lcy
21 小时以前 484239463e0802b47070d5df8d7b6931a64b0a67
492 武将返场
19个文件已修改
91个文件已添加
6107 ■■■■■ 已修改文件
Main/Config/ConfigManager.cs 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/Configs/ActHeroAppearConfig.cs 37 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/Configs/ActHeroAppearSkinArtConfig.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/Configs/ActHeroReturnArtConfig.cs 107 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/Configs/ActHeroReturnArtConfig.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/Configs/ActHeroReturnSkinArtConfig.cs 56 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/Configs/ActHeroReturnSkinArtConfig.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/PartialConfigs/ActHeroAppearConfig.cs 36 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/PartialConfigs/ActHeroAppearStarConfig.cs 34 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/DTCFile/ServerPack/HA0_Sys/DTCA009_tagSCGameRecInfo.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Core/NetworkPackage/DTCFile/ServerPack/HAA_SaleActivity/DTCAA22_tagSCActHeroAppearPlayerInfo.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Main.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Manager/UIManager.cs 37 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HappyXB/HappyXBModel.cs 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroDebut/HeroDebutCallWin.cs 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroDebut/HeroDebutManager.cs 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroDebut/HeroDebutStarUpWin.cs 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroDebut/HeroDebutWin.cs 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn.meta 8 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallBubbleCell.cs 23 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallBubbleCell.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallButton.cs 95 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallButton.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallChangeCell.cs 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallChangeCell.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallChangeItem.cs 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallChangeItem.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallChangeWin.cs 100 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallChangeWin.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallChooseCell.cs 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallChooseCell.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallChooseItem.cs 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallChooseItem.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallChooseWin.cs 95 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallChooseWin.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallHistoryCell.cs 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallHistoryCell.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallHistoryOutCell.cs 21 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallHistoryOutCell.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallHistoryWin.cs 57 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallHistoryWin.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallRateCell.cs 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallRateCell.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallRateHeroCell.cs 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallRateHeroCell.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallRateHeroWin.cs 119 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallRateHeroWin.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallRateItem.cs 123 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallRateItem.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallRateWin.cs 83 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallRateWin.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallResultCell.cs 104 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallResultCell.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallResultWin.cs 370 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallResultWin.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallWin.cs 417 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCallWin.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCell.cs 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCell.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCheckInCell.cs 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCheckInCell.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCheckInWin.cs 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnCheckInWin.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnGiftCell.cs 165 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnGiftCell.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnGiftWin.cs 86 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnGiftWin.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnManager.cs 1152 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnManager.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnPopWin.cs 96 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnPopWin.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnRankAwardCell.cs 45 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnRankAwardCell.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnRankCell.cs 76 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnRankCell.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnRankTop3Cell.cs 47 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnRankTop3Cell.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnRankWin.cs 175 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnRankWin.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnShopCell.cs 134 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnShopCell.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnShopLineCell.cs 30 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnShopLineCell.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnShopWin.cs 80 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnShopWin.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnSkinAwardCell.cs 18 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnSkinAwardCell.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnSkinTabCell.cs 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnSkinTabCell.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnSkinWin.cs 229 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnSkinWin.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnStarUpCell.cs 126 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnStarUpCell.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnStarUpChangeCell.cs 33 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnStarUpChangeCell.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnStarUpChangeItem.cs 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnStarUpChangeItem.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnStarUpChangeWin.cs 100 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnStarUpChangeWin.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnStarUpPaidItemCell.cs 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnStarUpPaidItemCell.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnStarUpWin.cs 159 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnStarUpWin.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnWin.cs 268 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/HeroReturn/HeroReturnWin.cs.meta 11 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Main/HomeWin.cs 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/OpenServerActivity/OperationTimeHepler.cs 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/Redpoint/MainRedDot.cs 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/System/UIBase/UIJumpManager.cs 41 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Utility/EnumHelper.cs 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
Main/Config/ConfigManager.cs
@@ -43,6 +43,8 @@
            typeof(ActHeroAppearConfig),
            typeof(ActHeroAppearSkinArtConfig),
            typeof(ActHeroAppearStarConfig),
            typeof(ActHeroReturnArtConfig),
            typeof(ActHeroReturnSkinArtConfig),
            typeof(ActLunhuidianTypeConfig),
            typeof(ActSignAwardConfig),
            typeof(ADAwardConfig),
@@ -278,6 +280,10 @@
        ClearConfigDictionary<ActHeroAppearSkinArtConfig>();
        // 清空 ActHeroAppearStarConfig 字典
        ClearConfigDictionary<ActHeroAppearStarConfig>();
        // 清空 ActHeroReturnArtConfig 字典
        ClearConfigDictionary<ActHeroReturnArtConfig>();
        // 清空 ActHeroReturnSkinArtConfig 字典
        ClearConfigDictionary<ActHeroReturnSkinArtConfig>();
        // 清空 ActLunhuidianTypeConfig 字典
        ClearConfigDictionary<ActLunhuidianTypeConfig>();
        // 清空 ActSignAwardConfig 字典
Main/Config/Configs/ActHeroAppearConfig.cs
@@ -1,6 +1,6 @@
//--------------------------------------------------------
//    [Author]:           YYL
//    [  Date ]:           2026年3月9日
//    [  Date ]:           Thursday, March 26, 2026
//--------------------------------------------------------
using System.Collections.Generic;
@@ -17,6 +17,7 @@
    }
    public int CfgID;
    public int ActNum;
    public int[] ActHeroIDList;
    public int ActTreasureType;
    public int StarGiftTempID;
@@ -40,13 +41,15 @@
        string[] tables = input.Split('\t');
        int.TryParse(tables[0],out CfgID); 
            if (tables[1].Contains("["))
            int.TryParse(tables[1],out ActNum);
            if (tables[2].Contains("["))
            {
                ActHeroIDList = JsonMapper.ToObject<int[]>(tables[1]);
                ActHeroIDList = JsonMapper.ToObject<int[]>(tables[2]);
            }
            else
            {
                string[] ActHeroIDListStringArray = tables[1].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
                string[] ActHeroIDListStringArray = tables[2].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
                ActHeroIDList = new int[ActHeroIDListStringArray.Length];
                for (int i=0;i<ActHeroIDListStringArray.Length;i++)
                {
@@ -54,17 +57,17 @@
                }
            }
            int.TryParse(tables[2],out ActTreasureType);
            int.TryParse(tables[3],out ActTreasureType);
            int.TryParse(tables[3],out StarGiftTempID);
            int.TryParse(tables[4],out StarGiftTempID);
            if (tables[4].Contains("["))
            if (tables[5].Contains("["))
            {
                SkinCTGIDList = JsonMapper.ToObject<int[]>(tables[4]);
                SkinCTGIDList = JsonMapper.ToObject<int[]>(tables[5]);
            }
            else
            {
                string[] SkinCTGIDListStringArray = tables[4].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
                string[] SkinCTGIDListStringArray = tables[5].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
                SkinCTGIDList = new int[SkinCTGIDListStringArray.Length];
                for (int i=0;i<SkinCTGIDListStringArray.Length;i++)
                {
@@ -72,13 +75,13 @@
                }
            }
            if (tables[5].Contains("["))
            if (tables[6].Contains("["))
            {
                GiftCTGIDList = JsonMapper.ToObject<int[]>(tables[5]);
                GiftCTGIDList = JsonMapper.ToObject<int[]>(tables[6]);
            }
            else
            {
                string[] GiftCTGIDListStringArray = tables[5].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
                string[] GiftCTGIDListStringArray = tables[6].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
                GiftCTGIDList = new int[GiftCTGIDListStringArray.Length];
                for (int i=0;i<GiftCTGIDListStringArray.Length;i++)
                {
@@ -86,15 +89,15 @@
                }
            }
            int.TryParse(tables[6],out GiftShopType);
            int.TryParse(tables[7],out GiftShopType);
            int.TryParse(tables[7],out ExShopType);
            int.TryParse(tables[8],out ExShopType);
            int.TryParse(tables[8],out ExShopCostItemID);
            int.TryParse(tables[9],out ExShopCostItemID);
            int.TryParse(tables[9],out SignTempID);
            int.TryParse(tables[10],out SignTempID);
            int.TryParse(tables[10],out BillTempID);
            int.TryParse(tables[11],out BillTempID);
        }
        catch (Exception exception)
        {
Main/Config/Configs/ActHeroAppearSkinArtConfig.cs
@@ -1,6 +1,6 @@
//--------------------------------------------------------
//    [Author]:           YYL
//    [  Date ]:           2026年3月11日
//    [  Date ]:           2026年3月26日
//--------------------------------------------------------
using System.Collections.Generic;
Main/Config/Configs/ActHeroReturnArtConfig.cs
New file
@@ -0,0 +1,107 @@
//--------------------------------------------------------
//    [Author]:           YYL
//    [  Date ]:           2026年3月26日
//--------------------------------------------------------
using System.Collections.Generic;
using System;
using UnityEngine;
using LitJson;
public partial class ActHeroReturnArtConfig : ConfigBase<int, ActHeroReturnArtConfig>
{
    static ActHeroReturnArtConfig()
    {
        // 访问过静态构造函数
        visit = true;
    }
    public int HeroID;
    public int[][] HeroNameColor;
    public int[][] CallBubbleItems;
    public string EntryBgImage;
    public string EntryTitleText;
    public string PopBgImage;
    public string PopTitleBgImage;
    public string PopTitleImage;
    public string PopInfoBgImage;
    public int PopInfoBgUIEffectId;
    public string PopInfoText;
    public int[] PopInfoColor;
    public string MainBgImage;
    public string MainTitleImage;
    public int MainSkinID;
    public string StarUpHeroImage;
    public string GiftBgImage;
    public string GiftHeroImage;
    public string RankAwardHeroImage;
    public string CheckInBgImage;
    public override int LoadKey(string _key)
    {
        int key = GetKey(_key);
        return key;
    }
    public override void LoadConfig(string input)
    {
        try {
        string[] tables = input.Split('\t');
        int.TryParse(tables[0],out HeroID);
            HeroNameColor = JsonMapper.ToObject<int[][]>(tables[1].Replace("(", "[").Replace(")", "]"));
            CallBubbleItems = JsonMapper.ToObject<int[][]>(tables[2].Replace("(", "[").Replace(")", "]"));
            EntryBgImage = tables[3];
            EntryTitleText = tables[4];
            PopBgImage = tables[5];
            PopTitleBgImage = tables[6];
            PopTitleImage = tables[7];
            PopInfoBgImage = tables[8];
            int.TryParse(tables[9],out PopInfoBgUIEffectId);
            PopInfoText = tables[10];
            if (tables[11].Contains("["))
            {
                PopInfoColor = JsonMapper.ToObject<int[]>(tables[11]);
            }
            else
            {
                string[] PopInfoColorStringArray = tables[11].Trim().Split(StringUtility.splitSeparator,StringSplitOptions.RemoveEmptyEntries);
                PopInfoColor = new int[PopInfoColorStringArray.Length];
                for (int i=0;i<PopInfoColorStringArray.Length;i++)
                {
                     int.TryParse(PopInfoColorStringArray[i],out PopInfoColor[i]);
                }
            }
            MainBgImage = tables[12];
            MainTitleImage = tables[13];
            int.TryParse(tables[14],out MainSkinID);
            StarUpHeroImage = tables[15];
            GiftBgImage = tables[16];
            GiftHeroImage = tables[17];
            RankAwardHeroImage = tables[18];
            CheckInBgImage = tables[19];
        }
        catch (Exception exception)
        {
            Debug.LogError(exception);
        }
    }
}
Main/Config/Configs/ActHeroReturnArtConfig.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 010dfd3e7d7da104f8daef3fb34fd922
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/Config/Configs/ActHeroReturnSkinArtConfig.cs
New file
@@ -0,0 +1,56 @@
//--------------------------------------------------------
//    [Author]:           YYL
//    [  Date ]:           Thursday, March 26, 2026
//--------------------------------------------------------
using System.Collections.Generic;
using System;
using UnityEngine;
using LitJson;
public partial class ActHeroReturnSkinArtConfig : ConfigBase<int, ActHeroReturnSkinArtConfig>
{
    static ActHeroReturnSkinArtConfig()
    {
        // 访问过静态构造函数
        visit = true;
    }
    public int SkinID;
    public string MainSkinBuyBgImage;
    public string BGImage;
    public string HeroNameImage;
    public string SkinInfoImage;
    public string AwardBGImage;
    public string TabInfoImage;
    public override int LoadKey(string _key)
    {
        int key = GetKey(_key);
        return key;
    }
    public override void LoadConfig(string input)
    {
        try {
        string[] tables = input.Split('\t');
        int.TryParse(tables[0],out SkinID);
            MainSkinBuyBgImage = tables[1];
            BGImage = tables[2];
            HeroNameImage = tables[3];
            SkinInfoImage = tables[4];
            AwardBGImage = tables[5];
            TabInfoImage = tables[6];
        }
        catch (Exception exception)
        {
            Debug.LogError(exception);
        }
    }
}
Main/Config/Configs/ActHeroReturnSkinArtConfig.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 5a29cc75b87652c4d9357b05ef1853f5
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/Config/PartialConfigs/ActHeroAppearConfig.cs
@@ -1,18 +1,40 @@
using System.Collections.Generic;
using System.Linq;
public partial class ActHeroAppearConfig : ConfigBase<int, ActHeroAppearConfig>
{
    private static List<int> actTreasureTypeList;
    public static List<int> GetActTreasureTypeList()
    /// <summary>
    /// 武将登场的所有招募寻宝类型
    /// </summary>
    private static HashSet<int> heroDebutActTreasureTypeList = new();
    public static List<int> GetHeroDebutActTreasureTypeList()
    {
        if (actTreasureTypeList == null)
        if (heroDebutActTreasureTypeList.Count == 0)
        {
            actTreasureTypeList = new();
            foreach (var item in GetValues())
            {
                if (!actTreasureTypeList.Contains(item.ActTreasureType))
                    actTreasureTypeList.Add(item.ActTreasureType);
                if (item.ActNum != 10)
                    continue;
                heroDebutActTreasureTypeList.Add(item.ActTreasureType);
            }
        }
        return actTreasureTypeList;
        return heroDebutActTreasureTypeList.ToList();
    }
    /// <summary>
    /// 武将返场的所有招募寻宝类型
    /// </summary>
    private static HashSet<int> heroReturnActTreasureTypeList = new();
    public static List<int> GetHeroReturnActTreasureTypeList()
    {
        if (heroReturnActTreasureTypeList.Count == 0)
        {
            foreach (var item in GetValues())
            {
                if (item.ActNum != 11)
                    continue;
                heroReturnActTreasureTypeList.Add(item.ActTreasureType);
            }
        }
        return heroReturnActTreasureTypeList.ToList();
    }
}
Main/Config/PartialConfigs/ActHeroAppearStarConfig.cs
@@ -26,8 +26,40 @@
            sortDict[starTempID] = list;
        }
    }
    public static List<int> GetHeroReturnAwardIndexSortList(int starTempID)
    {
        LoadSortList();
        sortDict.TryGetValue(starTempID, out var list);
    public static List<int> GetAwardIndexSortList(int starTempID)
        List<int> res = new List<int>();
        int heroId = HeroReturnManager.Instance.GetCurrentDisplayStarUpHeroId();
        int nowStar = HeroReturnManager.Instance.GetNowHeroMaxStarCnt(heroId);
        for (int i = HeroReturnManager.Instance.seeArr.Length - 1; i >= 0; i--)
        {
            int[] info = HeroReturnManager.Instance.seeArr[i];
            int needStar = info[0];
            int seeStar = info[1];
            if (nowStar >= needStar)
            {
                for (int j = 0; j < seeStar; j++)
                {
                    if (j >= list.Count) continue;
                    var config = GetConfig(starTempID, list[j]);
                    if (config == null) continue;
                    int tempStar = config.NeedStar;
                    if (tempStar > seeStar) continue;
                    res.Add(list[j]);
                }
                return res;
            }
        }
        return null;
    }
    public static List<int> GetHeroDebutAwardIndexSortList(int starTempID)
    {
        LoadSortList();
        sortDict.TryGetValue(starTempID, out var list);
Main/Core/NetworkPackage/DTCFile/ServerPack/HA0_Sys/DTCA009_tagSCGameRecInfo.cs
@@ -10,5 +10,6 @@
        ArenaManager.Instance.UpdateGameRecInfo(vNetData);
        HeroDebutManager.Instance.UpdateGameRecInfo(vNetData);
        QunyingManager.Instance.UpdateGameRecInfo(vNetData);
        HeroReturnManager.Instance.UpdateGameRecInfo(vNetData);
    }
}
Main/Core/NetworkPackage/DTCFile/ServerPack/HAA_SaleActivity/DTCAA22_tagSCActHeroAppearPlayerInfo.cs
@@ -10,5 +10,6 @@
        base.Done(vNetPack);
        HAA22_tagSCActHeroAppearPlayerInfo vNetData = vNetPack as HAA22_tagSCActHeroAppearPlayerInfo;
        HeroDebutManager.Instance.UpdateHeroAppearPlayerInfo(vNetData);
        HeroReturnManager.Instance.UpdateHeroAppearPlayerInfo(vNetData);
    }
}
Main/Main.cs
@@ -112,6 +112,7 @@
        managers.Add(GeneralActInfoManager.Instance);
        managers.Add(QunyingManager.Instance);
        managers.Add(ViewBuffManager.Instance);
        managers.Add(HeroReturnManager.Instance);
        foreach (var manager in managers)
        {
Main/Manager/UIManager.cs
@@ -381,6 +381,43 @@
        return false;
    }
    // 检查是否存在任何同层级sortingOrde大于我的窗口
    public bool ExistAnySameLevelWinHigherSortingOrder(UILayer uiLayer, string excludeUIName)
    {
        int mySortingOrder = 0;
        if (uiDict.TryGetValue(excludeUIName, out List<UIBase> excludeList) && excludeList.Count > 0)
        {
            foreach (var ui in excludeList)
            {
                if (ui.IsActive())
                {
                    mySortingOrder = ui.GetSortingOrder();
                    break;
                }
            }
        }
        if (mySortingOrder == 0)
            return false;
        foreach (var uiList in uiDict.Values)
        {
            foreach (var ui in uiList)
            {
                if (!ui.IsActive())
                    continue;
                if (ui.uiName == excludeUIName)
                    continue;
                if (ui.uiLayer != uiLayer)
                    continue;
                if (ui.GetSortingOrder() > mySortingOrder)
                    return true;
            }
        }
        return false;
    }
    
    // 获取指定类型的所有UI实例
    public List<T> GetAllUI<T>() where T : UIBase
Main/System/HappyXB/HappyXBModel.cs
@@ -182,14 +182,24 @@
            {
                UIManager.Instance.OpenWindow<HeroCallResultWin>();
            }
            return;
        }
        if (ActHeroAppearConfig.GetActTreasureTypeList().Contains(type))
        if (ActHeroAppearConfig.GetHeroDebutActTreasureTypeList().Contains(type))
        {
            if (!UIManager.Instance.IsOpened<HeroDebutCallResultWin>())
            {
                UIManager.Instance.OpenWindow<HeroDebutCallResultWin>();
            }
            return;
        }
        if (ActHeroAppearConfig.GetHeroReturnActTreasureTypeList().Contains(type))
        {
            if (!UIManager.Instance.IsOpened<HeroReturnCallResultWin>())
            {
                UIManager.Instance.OpenWindow<HeroReturnCallResultWin>();
            }
        }
    }
Main/System/HeroDebut/HeroDebutCallWin.cs
@@ -78,6 +78,7 @@
        PackManager.Instance.RefreshItemEvent += RefreshItemEvent;
        scroller.OnRefreshCell += OnRefreshCell;
        manager.OnUpdateGameRecInfo += OnUpdateGameRecInfo;
        manager.OnUpdateHeroAppearPlayerInfoEvent += OnUpdateHeroAppearPlayerInfoEvent;
        if (manager.isSendFirst)
        {
@@ -113,7 +114,7 @@
    // 1. 在类中声明一个全局的 Sequence 变量,用于统一管控动画
    private Sequence heroAnimSeq;
    private void OnUpdateHeroAppearPlayerInfoEvent(int actNum)
    private void OnUpdateHeroAppearPlayerInfoEvent()
    {
        changeRect.SetActive(false);
Main/System/HeroDebut/HeroDebutManager.cs
@@ -77,9 +77,9 @@
    private void OnBeforePlayerDataInitializeEventOnRelogin()
    {
        isSendFirst = true;
        starHeroIndexDict.Clear();
        starHeroIndex = 0;
        callHeroIndex = 0;
        starFreeAwardDict.Clear();
        callHeroIndexDict.Clear();
    }
    private void OnPlayerLoginOk()
@@ -243,22 +243,23 @@
            OnNowCallChooseHeroIDChangeEvent?.Invoke();
        }
    }
    public event Action<int> OnUpdateHeroAppearPlayerInfoEvent;
    public int starHeroIndex = 0;
    public int callHeroIndex = 0;
    //<升星计划选择的武将ID索引,升星计划免费奖励记录>
    Dictionary<int, uint> starFreeAwardDict = new();
    public event Action OnUpdateHeroAppearPlayerInfoEvent;
    public void UpdateHeroAppearPlayerInfo(HAA22_tagSCActHeroAppearPlayerInfo vNetData)
    {
        if (vNetData == null) return;
        int actNum = vNetData.ActNum;
        starHeroIndexDict[actNum] = vNetData.StarHeroIndex;
        callHeroIndexDict[actNum] = vNetData.CallHeroIndex;
        if (vNetData.ActNum != this.actNum) return;
        if (!starFreeAwardDict.TryGetValue(actNum, out var dict))
        {
            dict = new Dictionary<int, uint>();
            starFreeAwardDict[actNum] = dict;
        }
        dict[vNetData.StarHeroIndex] = vNetData.StarFreeAward;
        int actNum = vNetData.ActNum;
        starHeroIndex = vNetData.StarHeroIndex;
        callHeroIndex = vNetData.CallHeroIndex;
        starFreeAwardDict[starHeroIndex] = vNetData.StarFreeAward;
        UpdateRedpoint();
        OnUpdateHeroAppearPlayerInfoEvent?.Invoke(actNum);
        OnUpdateHeroAppearPlayerInfoEvent?.Invoke();
    }
    public void SendHeroAppearStarHeroSelect(int actNum, int starHeroIndex)
@@ -432,12 +433,6 @@
    #region 升星计划
    //<活动编号,升星计划选择的武将ID索引>
    public Dictionary<int, int> starHeroIndexDict = new();
    //<活动编号,<升星计划选择的武将ID索引,升星计划免费奖励记录>>
    public Dictionary<int, Dictionary<int, uint>> starFreeAwardDict = new();
    /// <summary>
    /// 当前升星计划选中的武将ID
    /// </summary>
@@ -445,12 +440,11 @@
    {
        var act = GetOperationHeroAppearInfo();
        if (act == null) return 0;
        if (!starHeroIndexDict.TryGetValue(actNum, out int index)) return 0;
        var config = ActHeroAppearConfig.Get(act.CfgID);
        if (config == null || config.ActHeroIDList?.Length <= index) return 0;
        if (config == null || config.ActHeroIDList?.Length <= starHeroIndex) return 0;
        return config.ActHeroIDList[index];
        return config.ActHeroIDList[starHeroIndex];
    }
    private Dictionary<int, Dictionary<int, int[][]>> showHeroGiftItemInfoDict = new();
@@ -508,16 +502,14 @@
        // 没获得武将本体不可领取
        if (!HeroManager.Instance.HasHero(heroId))return 0;
        
        if (!starHeroIndexDict.TryGetValue(actNum, out int index)) return 0;
        if (IsStarUpFreeHave(index, config.AwardIndex)) return 2;
        if (IsStarUpFreeHave(starHeroIndex, config.AwardIndex)) return 2;
        if (IsHeroStarCntOk(heroConfig.HeroID, config.NeedStar)) return 1;
        return 0;
    }
    private bool IsStarUpFreeHave(int starHeroIndex, int awardIndex)
    {
        if (!starFreeAwardDict.TryGetValue(actNum, out var dict)) return false;
        if (!dict.TryGetValue(starHeroIndex, out uint freeAward)) return false;
        if (!starFreeAwardDict.TryGetValue(starHeroIndex, out uint freeAward)) return false;
        return ((freeAward >> awardIndex) & 1u) == 1u;
    }
@@ -544,7 +536,7 @@
    public bool TryGetStarUpStateIndex(int starGiftTempID, int tarState, out int index)
    {
        index = 0;
        var list = ActHeroAppearStarConfig.GetAwardIndexSortList(starGiftTempID);
        var list = ActHeroAppearStarConfig.GetHeroDebutAwardIndexSortList(starGiftTempID);
        if (list == null) return false;
        for (int i = 0; i < list.Count; i++)
@@ -733,7 +725,7 @@
    }
    private string GetCallSkipKey(int cfgID, OperationDate startDate, OperationDate endDate)
    {
        return string.Concat("HeroDebutManager_CallSkip_", cfgID, ToInt(startDate), ToInt(endDate), PlayerDatas.Instance.PlayerId);
        return string.Concat("HeroDebutManager_CallSkip_", cfgID, "_", ToInt(startDate), "_", ToInt(endDate), "_", PlayerDatas.Instance.PlayerId);
    }
    public bool LoadCallSkipData(int cfgID, OperationDate startDate, OperationDate endDate)
@@ -746,9 +738,6 @@
        LocalSave.SetBool(GetCallSkipKey(cfgID, startDate, endDate), value);
    }
    //<活动编号,招募选择的武将ID索引>
    public Dictionary<int, int> callHeroIndexDict = new();
    /// <summary>
    /// 当前招募选中的武将ID
    /// </summary>
@@ -756,12 +745,11 @@
    {
        var act = GetOperationHeroAppearInfo();
        if (act == null) return 0;
        if (!callHeroIndexDict.TryGetValue(actNum, out int index)) return 0;
        var config = ActHeroAppearConfig.Get(act.CfgID);
        if (config == null || config.ActHeroIDList?.Length <= index) return 0;
        if (config == null || config.ActHeroIDList?.Length <= callHeroIndex) return 0;
        return config.ActHeroIDList[index];
        return config.ActHeroIDList[callHeroIndex];
    }
@@ -960,19 +948,10 @@
    {
        return gameRecDict;
    }
    public List<HeroDebutGameRec> GetLastFourRecords()
    {
        if (gameRecDict == null || gameRecDict.Count == 0) return new List<HeroDebutGameRec>();
        int count = gameRecDict.Count;
        int takeCount = Math.Min(4, count);
        return gameRecDict.GetRange(count - takeCount, takeCount);
    }
    public event Action OnUpdateGameRecInfo;
    public void UpdateGameRecInfo(HA009_tagSCGameRecInfo vNetData)
    {
        var act = GetOperationHeroAppearInfo();
        if (act == null) return;
Main/System/HeroDebut/HeroDebutStarUpWin.cs
@@ -44,7 +44,7 @@
        manager.OnUpdateHeroAppearPlayerInfoEvent -= OnUpdateHeroAppearPlayerInfoEvent;
    }
    private void OnUpdateHeroAppearPlayerInfoEvent(int obj)
    private void OnUpdateHeroAppearPlayerInfoEvent()
    {
        scroller.m_Scorller.RefreshActiveCellViews();
    }
@@ -96,7 +96,7 @@
        if (appearConfig == null || heroConfig == null) return;
        int starGiftTempID = appearConfig.StarGiftTempID;
        var list = ActHeroAppearStarConfig.GetAwardIndexSortList(starGiftTempID);
        var list = ActHeroAppearStarConfig.GetHeroDebutAwardIndexSortList(starGiftTempID);
        if (list == null) return;
        scroller.Refresh();
Main/System/HeroDebut/HeroDebutWin.cs
@@ -60,7 +60,7 @@
        manager.OnUpdateHeroAppearPlayerInfoEvent -= OnUpdateHeroAppearPlayerInfoEvent;
    }
    private void OnUpdateHeroAppearPlayerInfoEvent(int obj)
    private void OnUpdateHeroAppearPlayerInfoEvent()
    {
        Display();
    }
Main/System/HeroReturn.meta
New file
@@ -0,0 +1,8 @@
fileFormatVersion: 2
guid: ad40f79e4689d234fac9fc2f4d8be9a7
folderAsset: yes
DefaultImporter:
  externalObjects: {}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnCallBubbleCell.cs
New file
@@ -0,0 +1,23 @@
using UnityEngine;
public class HeroReturnCallBubbleCell : MonoBehaviour
{
    [SerializeField] ButtonEx clickButton;
    [SerializeField] ImageEx bgImage;
    [SerializeField] ImageEx iconImage;
    [SerializeField] TextEx countText;
    public void Display(int itemID, int count)
    {
        var config = ItemConfig.Get(itemID);
        if (config == null) return;
        bgImage.SetSprite($"HeroDebutCallBubbleBG{config.ItemColor}");
        iconImage.SetItemSprite(itemID);
        iconImage.SetNativeSize();
        countText.text = count.ToString();
        clickButton.SetListener(() => ItemTipUtility.Show(itemID));
    }
}
Main/System/HeroReturn/HeroReturnCallBubbleCell.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 10ed3265b0279984dbb79382f829567a
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnCallButton.cs
New file
@@ -0,0 +1,95 @@
using UnityEngine;
public class HeroReturnCallButton : MonoBehaviour
{
    [SerializeField] ButtonEx clickButton;
    [SerializeField] TextEx callText;
    [SerializeField] TextEx needText;
    [SerializeField] ImageEx needImage;
    HeroReturnManager manager => HeroReturnManager.Instance;
    HappyXBModel xbManager => HappyXBModel.Instance;
    int index;
    int type;
    int needCostItemCnt;
    long hasItemCnt;
    int needCostMoneyCnt;
    long moneyCount;
    public void Display(int treasureType, int index)
    {
        this.index = index;
        type = treasureType;
        var treasureSetConfig = TreasureSetConfig.Get(treasureType);
        if (treasureSetConfig == null) return;
        if (treasureSetConfig.TreasureCountList == null || treasureSetConfig.TreasureCountList.Length <= index) return;
        if (treasureSetConfig.CostItemCountList == null || treasureSetConfig.CostItemCountList.Length <= index) return;
        if (treasureSetConfig.CostMoneyList == null || treasureSetConfig.CostMoneyList.Length <= index) return;
        XBTypeInfo info = xbManager.GetXBInfoByType(treasureType);
        if (info == null) return;
        int treasureCnt = treasureSetConfig.TreasureCountList[index];
        callText.text = Language.Get("HeroDebut23", treasureCnt);
        int dailyMaxCountMoney = treasureSetConfig.DailyMaxCountMoney;
        int nowMoneyCnt = info.treasureCountTodayGold;
        needCostMoneyCnt = treasureSetConfig.CostMoneyList[index];
        moneyCount = UIHelper.GetMoneyCnt(treasureSetConfig.CostMoneyType);
        needCostItemCnt = treasureSetConfig.CostItemCountList[index];
        hasItemCnt = PackManager.Instance.GetItemCountByID(PackType.Item, treasureSetConfig.CostItemID);
        // 物品不足 && 没超货币招募次数上限
        if (hasItemCnt < needCostItemCnt &&
            nowMoneyCnt + treasureCnt <= dailyMaxCountMoney)
        {
            DisplayByMoney(treasureSetConfig.CostMoneyType, needCostMoneyCnt, moneyCount);
            return;
        }
        DisplayByItem(treasureSetConfig.CostItemID, treasureCnt);
    }
    void DisplayByMoney(int moneyType, long needCostMoneyCnt, long moneyCount)
    {
        bool isEnough = moneyCount >= needCostMoneyCnt;
        needText.text = Language.Get("L1100", RichTextMsgReplaceConfig.GetRichReplace("MONEY", moneyType), UIHelper.AppendColor(!isEnough ? TextColType.Red : TextColType.LightGreen, needCostMoneyCnt.ToString()));
        needImage.SetIconWithMoneyType(moneyType);
        clickButton.SetListener(() =>
        {
            if (!isEnough)
            {
                ItemTipUtility.ShowMoneyTip(moneyType, true);
                return;
            }
            HeroUIManager.Instance.selectCallType = (HappXBTitle)type;
            HeroUIManager.Instance.selectCallIndex = index;
            HappyXBModel.Instance.SendXBQuest(type, index, 0);
        });
    }
    void DisplayByItem(int itemID, int count)
    {
        ItemConfig itemConfig = ItemConfig.Get(itemID);
        if (itemConfig == null) return;
        bool isEnough = hasItemCnt >= needCostItemCnt;
        needText.text = Language.Get("L1100", itemConfig.ItemName, UIHelper.AppendColor(!isEnough ? TextColType.Red : TextColType.LightGreen, count.ToString()));
        needImage.SetItemSprite(itemID);
        clickButton.SetListener(() =>
        {
            if (!isEnough)
            {
                ItemTipUtility.Show(itemID, true);
                return;
            }
            HeroUIManager.Instance.selectCallType = (HappXBTitle)type;
            HeroUIManager.Instance.selectCallIndex = index;
            HappyXBModel.Instance.SendXBQuest(type, index, 2);
        });
    }
}
Main/System/HeroReturn/HeroReturnCallButton.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d55190ecb673d464f88f4ec0a5425732
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnCallChangeCell.cs
New file
@@ -0,0 +1,33 @@
using UnityEngine;
public class HeroReturnCallChangeCell : CellView
{
    [SerializeField] HeroReturnCallChangeItem[] items;
    HeroReturnManager manager => HeroReturnManager.Instance;
    public void Display(int rowIndex)
    {
        var act = manager.GetOperationHeroAppearInfo();
        if (act == null) return;
        var config = ActHeroAppearConfig.Get(act.CfgID);
        if (config == null) return;
        var heroArr = config.ActHeroIDList;
        if (heroArr.IsNullOrEmpty()) return;
        for (int i = 0; i < items.Length; i++)
        {
            int index = rowIndex * HeroReturnCallChangeWin.rowCountMax + i;
            if (index < heroArr.Length)
            {
                items[i].SetActive(true);
                items[i].Display(index, heroArr, act.CfgID);
            }
            else
            {
                items[i].SetActive(false);
            }
        }
    }
}
Main/System/HeroReturn/HeroReturnCallChangeCell.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e0d034734cb56844cb0216e77c5b3440
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnCallChangeItem.cs
New file
@@ -0,0 +1,41 @@
using UnityEngine;
using UnityEngine.UI;
public class HeroReturnCallChangeItem : MonoBehaviour
{
    [SerializeField] HeroHeadBaseCell heroHeadBaseCell;
    [SerializeField] Image jobImg;
    [SerializeField] Text nameText;
    [SerializeField] Transform select;
    HeroReturnManager manager => HeroReturnManager.Instance;
    HeroConfig heroConfig;
    int index;
    public void Display(int index, int[] heroIds, int cfgId)
    {
        this.index = index;
        if (heroIds?.Length <= index) return;
        int heroId = heroIds[index];
        heroConfig = HeroConfig.Get(heroId);
        if (heroConfig == null) return;
        int skinID = manager.GetDefaultSkinID(heroId);
        var heroSkinConfig = HeroSkinConfig.Get(skinID);
        if (heroSkinConfig == null) return;
        heroHeadBaseCell.Init(heroConfig.HeroID, skinID, 0, 0, 0, OnClick);
        nameText.text = heroConfig.Name;
        jobImg.SetSprite(HeroUIManager.Instance.GetJobIconName(heroConfig.Class));
        bool isChoose = manager.nowCallChooseHeroID == heroId;
        select?.SetActive(isChoose);
    }
    public void OnClick()
    {
        if (heroConfig == null) return;
        manager.nowCallChooseHeroID = heroConfig.HeroID;
    }
}
Main/System/HeroReturn/HeroReturnCallChangeItem.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0720ebe725ea61345a7c09406a98e96e
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnCallChangeWin.cs
New file
@@ -0,0 +1,100 @@
using UnityEngine;
public class HeroReturnCallChangeWin : UIBase
{
    [SerializeField] ScrollerController scroller;
    [SerializeField] ButtonEx closeButton;
    [SerializeField] ButtonEx okButton;
    [SerializeField] ButtonEx previewButton;
    [SerializeField] UIHeroController uiHeroController;
    public const int rowCountMax = 4;
    HeroReturnManager manager => HeroReturnManager.Instance;
    protected override void InitComponent()
    {
        closeButton.SetListener(CloseWindow);
        okButton.SetListener(() =>
        {
            var act = manager.GetOperationHeroAppearInfo();
            if (act == null) return;
            int index = manager.GetHeroIdIndex(act.CfgID, manager.nowCallChooseHeroID);
            if (index < 0) return;
            if (manager.GetCurrentDisplayCallHeroId() == manager.nowCallChooseHeroID)
            {
                SysNotifyMgr.Instance.ShowTip("HeroDebut01");
                return;
            }
            manager.SnedHeroAppearCallHeroSelect(manager.actNum, index);
            CloseWindow();
        });
        previewButton.SetListener(() =>
        {
            HeroUIManager.Instance.selectForPreviewHeroID = manager.nowCallChooseHeroID;
            UIManager.Instance.OpenWindow<HeroBestBaseWin>();
        });
    }
    protected override void OnPreOpen()
    {
        scroller.OnRefreshCell += OnRefreshCell;
        manager.OnNowCallChooseHeroIDChangeEvent += OnNowCallChooseHeroIDChangeEvent;
        manager.nowCallChooseHeroID = manager.GetCurrentDisplayCallHeroId();
        Display();
        CreateScroller();
    }
    protected override void OnPreClose()
    {
        scroller.OnRefreshCell -= OnRefreshCell;
        manager.OnNowCallChooseHeroIDChangeEvent -= OnNowCallChooseHeroIDChangeEvent;
    }
    private void OnNowCallChooseHeroIDChangeEvent()
    {
        Display();
        scroller.m_Scorller.RefreshActiveCellViews();
    }
    void OnRefreshCell(ScrollerDataType type, CellView cell)
    {
        var _cell = cell as HeroReturnCallChangeCell;
        _cell.Display(cell.index);
    }
    void CreateScroller()
    {
        var act = manager.GetOperationHeroAppearInfo();
        if (act == null) return;
        var config = ActHeroAppearConfig.Get(act.CfgID);
        if (config == null) return;
        var arr = config.ActHeroIDList;
        if (arr.IsNullOrEmpty()) return;
        scroller.Refresh();
        int rowCount = (int)Mathf.Ceil((float)arr.Length / rowCountMax);
        for (int i = 0; i < rowCount; i++)
        {
            scroller.AddCell(ScrollerDataType.Header, i);
        }
        scroller.Restart();
    }
    void Display()
    {
        var act = manager.GetOperationHeroAppearInfo();
        if (act == null) return;
        int skinID = manager.GetDefaultSkinID(manager.nowCallChooseHeroID);
        var skinConfig = HeroSkinConfig.Get(skinID);
        if (skinConfig == null) return;
        uiHeroController.Create(skinID, 1);
    }
}
Main/System/HeroReturn/HeroReturnCallChangeWin.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8aa8fd53cfed7704f8a1b6b0b8d75407
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnCallChooseCell.cs
New file
@@ -0,0 +1,33 @@
using UnityEngine;
public class HeroReturnCallChooseCell : CellView
{
    [SerializeField] HeroReturnCallChooseItem[] items;
    HeroReturnManager manager => HeroReturnManager.Instance;
    public void Display(int rowIndex)
    {
        var act = manager.GetOperationHeroAppearInfo();
        if (act == null) return;
        var config = ActHeroAppearConfig.Get(act.CfgID);
        if (config == null) return;
        var heroArr = config.ActHeroIDList;
        if (heroArr.IsNullOrEmpty()) return;
        for (int i = 0; i < items.Length; i++)
        {
            int index = rowIndex * HeroReturnCallChangeWin.rowCountMax + i;
            if (index < heroArr.Length)
            {
                items[i].SetActive(true);
                items[i].Display(index, heroArr, act.CfgID);
            }
            else
            {
                items[i].SetActive(false);
            }
        }
    }
}
Main/System/HeroReturn/HeroReturnCallChooseCell.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0f45542ad2c6a5a4a9b16dacda70e468
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnCallChooseItem.cs
New file
@@ -0,0 +1,41 @@
using UnityEngine;
using UnityEngine.UI;
public class HeroReturnCallChooseItem : MonoBehaviour
{
    [SerializeField] HeroHeadBaseCell heroHeadBaseCell;
    [SerializeField] Image jobImg;
    [SerializeField] Text nameText;
    [SerializeField] Transform select;
    HeroReturnManager manager => HeroReturnManager.Instance;
    HeroConfig heroConfig;
    int index;
    public void Display(int index, int[] heroIds, int cfgId)
    {
        this.index = index;
        if (heroIds?.Length <= index) return;
        int heroId = heroIds[index];
        heroConfig = HeroConfig.Get(heroId);
        if (heroConfig == null) return;
        int skinID = manager.GetDefaultSkinID(heroId);
        var heroSkinConfig = HeroSkinConfig.Get(skinID);
        if (heroSkinConfig == null) return;
        heroHeadBaseCell.Init(heroConfig.HeroID, skinID, 0, 0, 0, OnClick);
        nameText.text = heroConfig.Name;
        jobImg.SetSprite(HeroUIManager.Instance.GetJobIconName(heroConfig.Class));
        bool isChoose = manager.nowCallChooseHeroID == heroId;
        select?.SetActive(isChoose);
    }
    public void OnClick()
    {
        if (heroConfig == null) return;
        manager.nowCallChooseHeroID = heroConfig.HeroID;
    }
}
Main/System/HeroReturn/HeroReturnCallChooseItem.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 05796103e33a5c44b9ab102ee2fde400
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnCallChooseWin.cs
New file
@@ -0,0 +1,95 @@
using UnityEngine;
public class HeroReturnCallChooseWin : UIBase
{
    [SerializeField] ScrollerController scroller;
    [SerializeField] ButtonEx closeButton;
    [SerializeField] ButtonEx okButton;
    [SerializeField] ButtonEx previewButton;
    [SerializeField] UIHeroController uiHeroController;
    public const int rowCountMax = 4;
    HeroReturnManager manager => HeroReturnManager.Instance;
    protected override void InitComponent()
    {
        closeButton.SetListener(CloseWindow);
        okButton.SetListener(() =>
        {
            var act = manager.GetOperationHeroAppearInfo();
            if (act == null) return;
            int index = manager.GetHeroIdIndex(act.CfgID, manager.nowCallChooseHeroID);
            if (index < 0) return;
            manager.SnedHeroAppearCallHeroSelect(manager.actNum, index);
            manager.SaveCallChooseHeroStateKey(act);
            CloseWindow();
        });
        previewButton.SetListener(() =>
        {
            HeroUIManager.Instance.selectForPreviewHeroID = manager.nowCallChooseHeroID;
            UIManager.Instance.OpenWindow<HeroBestBaseWin>();
        });
    }
    protected override void OnPreOpen()
    {
        scroller.OnRefreshCell += OnRefreshCell;
        manager.OnNowCallChooseHeroIDChangeEvent += OnNowCallChooseHeroIDChangeEvent;
        manager.nowCallChooseHeroID = manager.GetCurrentDisplayCallHeroId();
        Display();
        CreateScroller();
    }
    protected override void OnPreClose()
    {
        scroller.OnRefreshCell -= OnRefreshCell;
        manager.OnNowCallChooseHeroIDChangeEvent -= OnNowCallChooseHeroIDChangeEvent;
    }
    private void OnNowCallChooseHeroIDChangeEvent()
    {
        Display();
        scroller.m_Scorller.RefreshActiveCellViews();
    }
    void OnRefreshCell(ScrollerDataType type, CellView cell)
    {
        var _cell = cell as HeroReturnCallChooseCell;
        _cell.Display(cell.index);
    }
    void CreateScroller()
    {
        var act = manager.GetOperationHeroAppearInfo();
        if (act == null) return;
        var config = ActHeroAppearConfig.Get(act.CfgID);
        if (config == null) return;
        var arr = config.ActHeroIDList;
        if (arr.IsNullOrEmpty()) return;
        scroller.Refresh();
        int rowCount = (int)Mathf.Ceil((float)arr.Length / rowCountMax);
        for (int i = 0; i < rowCount; i++)
        {
            scroller.AddCell(ScrollerDataType.Header, i);
        }
        scroller.Restart();
    }
    void Display()
    {
        var act = manager.GetOperationHeroAppearInfo();
        if (act == null) return;
        int skinID = manager.GetDefaultSkinID(manager.nowCallChooseHeroID);
        var skinConfig = HeroSkinConfig.Get(skinID);
        if (skinConfig == null) return;
        uiHeroController.Create(skinID, 1);
    }
}
Main/System/HeroReturn/HeroReturnCallChooseWin.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: df583e8bc2fc9ab47ab8db4a977622bc
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnCallHistoryCell.cs
New file
@@ -0,0 +1,42 @@
using System.Collections.Generic;
using UnityEngine;
public class HeroReturnCallHistoryCell : CellView
{
    [SerializeField] Color nameColor;
    [SerializeField] TextEx infoText;
    public virtual void Display(int index, List<HeroReturnGameRec> list)
    {
        if (list?.Count <= index) return;
        var rec = list[index];
        var itemconfig = ItemConfig.Get(rec.ItemID);
        if (itemconfig == null) return;
        //150 整个武将
        if (itemconfig.Type == 150)
        {
            HeroConfig heroConfig = HeroConfig.Get(rec.ItemID);
            if (heroConfig == null) return;
            int quality = heroConfig.Quality;
            infoText.text = Language.Get("HeroDebut29",
                UIHelper.AppendColor(nameColor, rec.PlayerName),
                UIHelper.AppendColor(UIHelper.GetUIColorByFunc(quality), Language.Get(StringUtility.Concat("CommonQuality", quality.ToString()))),
                UIHelper.AppendColor(UIHelper.GetUIColorByFunc(quality), heroConfig.Name.ToString())
            );
        }
        else
        {
            int quality = itemconfig.ItemColor;
            infoText.text = Language.Get("HeroDebut30",
                UIHelper.AppendColor(nameColor, rec.PlayerName),
                UIHelper.AppendColor(UIHelper.GetUIColorByFunc(quality), itemconfig.ItemName.ToString()),
                rec.ItemCount.ToString()
            );
        }
    }
}
Main/System/HeroReturn/HeroReturnCallHistoryCell.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 38c9c575a3a11064597472dbd5e95a43
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnCallHistoryOutCell.cs
New file
@@ -0,0 +1,21 @@
using System.Collections.Generic;
using UnityEngine;
public class HeroReturnCallHistoryOutCell : HeroReturnCallHistoryCell
{
    [SerializeField] CanvasGroup canvasGroup;
    public override void Display(int index, List<HeroReturnGameRec> list)
    {
        base.Display(index, list);
    }
    // 提供给外部设置透明度的方法
    public void SetAlpha(float alpha)
    {
        if (canvasGroup != null)
        {
            canvasGroup.alpha = alpha;
        }
    }
}
Main/System/HeroReturn/HeroReturnCallHistoryOutCell.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 8239f369fcc315847a4e250422c234d6
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnCallHistoryWin.cs
New file
@@ -0,0 +1,57 @@
using System.Collections.Generic;
using UnityEngine;
public class HeroReturnCallHistoryWin : UIBase
{
    [SerializeField] ScrollerController scroller;
    [SerializeField] RectTransform noRect;
    HeroReturnManager manager => HeroReturnManager.Instance;
    protected override void OnPreOpen()
    {
        scroller.lockType = EnhanceLockType.LockVerticalBottom;
        scroller.OnRefreshCell += OnRefreshCell;
        manager.OnUpdateGameRecInfo += OnUpdateGameRecInfo;
        CreateScroller();
    }
    protected override void OnPreClose()
    {
        scroller.OnRefreshCell -= OnRefreshCell;
        manager.OnUpdateGameRecInfo -= OnUpdateGameRecInfo;
    }
    private void OnUpdateGameRecInfo()
    {
        scroller.m_Scorller.RefreshActiveCellViews();
    }
    void OnRefreshCell(ScrollerDataType type, CellView cell)
    {
        var _cell = cell as HeroReturnCallHistoryCell;
        _cell.Display(cell.index, list);
    }
    public List<HeroReturnGameRec> list;
    void CreateScroller()
    {
        list = manager.GetGameRecList();
        if (list == null)
        {
            noRect.SetActive(true);
            scroller.SetActive(false);
            return;
        }
        noRect.SetActive(false);
        scroller.SetActive(true);
        scroller.Refresh();
        for (int i = 0; i < list.Count; i++)
        {
            scroller.AddCell(ScrollerDataType.Header, i);
        }
        scroller.Restart();
    }
}
Main/System/HeroReturn/HeroReturnCallHistoryWin.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 10151abcb0caf394aa8caa2c00f25bbe
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnCallRateCell.cs
New file
@@ -0,0 +1,28 @@
using System.Collections.Generic;
using UnityEngine;
public class HeroReturnCallRateCell : CellView
{
    [SerializeField] HeroReturnCallRateItem[] items;
    HeroReturnManager manager => HeroReturnManager.Instance;
    public void Display(int rowIndex, Dictionary<int, int> gridRateDict, List<int> gridList, XBGetItemConfig xbConfig)
    {
        if (gridList == null) return;
        for (int i = 0; i < items.Length; i++)
        {
            int index = rowIndex * HeroReturnCallChangeWin.rowCountMax + i;
            if (index < gridList.Count)
            {
                items[i].SetActive(true);
                items[i].Display(index, gridRateDict, gridList, xbConfig);
            }
            else
            {
                items[i].SetActive(false);
            }
        }
    }
}
Main/System/HeroReturn/HeroReturnCallRateCell.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: cc363b85a77d3ce4b92b8f4ce95f524f
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnCallRateHeroCell.cs
New file
@@ -0,0 +1,28 @@
using System.Collections.Generic;
using UnityEngine;
public class HeroReturnCallRateHeroCell : CellView
{
    [SerializeField] ItemCell[] itemCells;
    public void Display(int rowIndex, List<Item> dataList)
    {
        if (dataList == null) return;
        for (int i = 0; i < itemCells.Length; i++)
        {
            int dataIndex = rowIndex * HeroReturnCallRateHeroWin.rowCountMax + i;
            if (dataIndex < dataList.Count)
            {
                itemCells[i].SetActive(true);
                itemCells[i].Init(new ItemCellModel(dataList[dataIndex].id, true, dataList[dataIndex].countEx));
                itemCells[i].button.SetListener(() => ItemTipUtility.Show(dataList[dataIndex].id));
            }
            else
            {
                itemCells[i].SetActive(false);
            }
        }
    }
}
Main/System/HeroReturn/HeroReturnCallRateHeroCell.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 75a05dc1b9031fa40b0fea8347aceca7
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnCallRateHeroWin.cs
New file
@@ -0,0 +1,119 @@
using System.Collections.Generic;
using Cysharp.Threading.Tasks;
using UnityEngine;
public class HeroReturnCallRateHeroWin : UIBase
{
    [SerializeField] RectTransform rectTransform;
    [SerializeField] RectTransform arrowImage;
    [SerializeField] RectTransform arrowUpImage;
    [SerializeField] ScrollerController scroller;
    public static Vector3 worldPos; //世界坐标系位置
    public static bool isDownShow = false;  // 是否向下显示
    public static List<Item> dataList;
    public const int rowCountMax = 4;
    protected override void OnPreOpen()
    {
        scroller.OnRefreshCell += OnRefreshCell;
        rectTransform.position = new Vector3(100, 100, 100);   //初始化时,屏幕范围外
        arrowImage.SetActive(!isDownShow);
        arrowUpImage.SetActive(isDownShow);
        CreateScroller();
    }
    protected override void OnPreClose()
    {
        isDownShow = false;
        scroller.OnRefreshCell -= OnRefreshCell;
    }
    void OnRefreshCell(ScrollerDataType type, CellView cell)
    {
        var _cell = cell as HeroReturnCallRateHeroCell;
        _cell.Display(cell.index, dataList);
    }
    void CreateScroller()
    {
        if (dataList == null || dataList.Count == 0) return;
        scroller.Refresh();
        int rowCount = Mathf.CeilToInt((float)dataList.Count / rowCountMax);
        for (int i = 0; i < rowCount; i++)
        {
            scroller.AddCell(ScrollerDataType.Header, i);
        }
        scroller.Restart();
    }
    protected override void OnOpen()
    {
        UpdatePos().Forget();
    }
    async UniTask UpdatePos()
    {
        await UniTask.DelayFrame(3);
        // 限制在屏幕范围内
        Vector3[] corners = new Vector3[4];
        rectTransform.GetWorldCorners(corners);
        float minY = corners[0].y;
        float maxY = corners[0].y;
        for (int i = 1; i < corners.Length; i++)
        {
            if (corners[i].y < minY) minY = corners[i].y;
            if (corners[i].y > maxY) maxY = corners[i].y;
        }
        float screenHeight = maxY - minY;
        Vector2 adjustedPos = new Vector2(worldPos.x, worldPos.y + (!isDownShow ? screenHeight * 0.5f : -screenHeight * 0.5f));
        Vector2 screenAdjustedPos = CameraManager.uiCamera.WorldToScreenPoint(adjustedPos);
        var rectWidth = rectTransform.rect.width * Screen.width / canvasScaler.referenceResolution.x;
        screenAdjustedPos.x = Mathf.Clamp(screenAdjustedPos.x, rectWidth * 0.5f, Screen.width - rectWidth * 0.5f);
        screenAdjustedPos.y = Mathf.Clamp(screenAdjustedPos.y, rectTransform.rect.height * 0.5f, Screen.height - rectTransform.rect.height * 0.5f - 15);
        adjustedPos = CameraManager.uiCamera.ScreenToWorldPoint(screenAdjustedPos);
        rectTransform.position = adjustedPos;
        if (!isDownShow)
        {
            rectTransform.localPosition = new Vector3(rectTransform.localPosition.x, rectTransform.localPosition.y + 15, rectTransform.localPosition.z);
        }
        else
        {
            rectTransform.localPosition = new Vector3(rectTransform.localPosition.x, rectTransform.localPosition.y - 15, rectTransform.localPosition.z);
        }
        rectTransform.GetWorldCorners(corners);
        float minX = corners[0].x;
        float maxX = corners[0].x;
        for (int i = 1; i < corners.Length; i++)
        {
            if (corners[i].x < minX) minX = corners[i].x;
            if (corners[i].x > maxX) maxX = corners[i].x;
        }
        //显示arrowImage 的x轴上的位置,和worldPos同步,但不超过minX 和 maxX范围
        if (!isDownShow)
        {
            Vector3 arrowImagePosition = arrowImage.position;
            arrowImagePosition.x = Mathf.Clamp(worldPos.x, minX, maxX);
            arrowImage.position = arrowImagePosition;
        }
        else
        {
            Vector3 arrowUpImagePosition = arrowUpImage.position;
            arrowUpImagePosition.x = Mathf.Clamp(worldPos.x, minX, maxX);
            arrowUpImage.position = arrowUpImagePosition;
        }
    }
}
Main/System/HeroReturn/HeroReturnCallRateHeroWin.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4488cbc55bbabcf43b390ebb827ec1f8
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnCallRateItem.cs
New file
@@ -0,0 +1,123 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class HeroReturnCallRateItem : MonoBehaviour
{
    [SerializeField] ButtonEx libButton;
    [SerializeField] ItemCell itemCell;
    [SerializeField] Text rateText;
    HeroReturnManager manager => HeroReturnManager.Instance;
    public void Display(int index, Dictionary<int, int> gridRateDict, List<int> gridList, XBGetItemConfig xbConfig)
    {
        if (gridList?.Count <= index || gridRateDict?.Count != gridList?.Count || xbConfig == null) return;
        if (xbConfig?.GridItemInfo == null || xbConfig?.GridLibInfo == null) return;
        if (manager.xbGridArr == null) return;
        int grid = gridList[index];
        int rate = gridRateDict[grid];
        rateText.text = Language.Get("TimingGift02", (double)rate / (double)100.0);
        SetItemCell(grid, xbConfig.GridItemInfo, xbConfig.GridLibInfo, manager.xbGridArr);
    }
    public void SetCountActive(ItemCell itemCell, long count)
    {
        itemCell.countText.SetActive(count > 1);
    }
    private void SetItemCell(int grid, Dictionary<int, int[]> gridItemInfo, Dictionary<int, int> gridLibInfo, int[] xbGridArr)
    {
        libButton.SetActive(false);
        itemCell.SetActive(false);
        if (gridItemInfo.TryGetValue(grid, out var itemInfo))
        {
            itemCell.SetActive(true);
            itemCell.Init(new ItemCellModel(itemInfo[0], true, itemInfo[1]));
            SetCountActive(itemCell, itemInfo[1]);
            itemCell.button.SetListener(() => ItemTipUtility.Show(itemInfo[0]));
            return;
        }
        if (!gridLibInfo.TryGetValue(grid, out var libID)) return;
        var list = TreasureItemLibConfig.GetItemIDList(libID);
        if (list == null) return;
        if (xbGridArr == null) return;
        if (xbGridArr.Contains(grid))
        {
            int heroID = manager.GetCurrentDisplayCallHeroId();
            if (!TryGetHeroItemInfo(heroID, libID, list, out int itemID, out int itemCount)) return;
            itemCell.SetActive(true);
            itemCell.Init(new ItemCellModel(itemID, true, itemCount));
            SetCountActive(itemCell, itemCount);
            itemCell.button.SetListener(() => ItemTipUtility.Show(itemID));
        }
        else
        {
            libButton.SetActive(true);
            libButton.SetListener(() =>
            {
                HeroReturnCallRateHeroWin.worldPos = libButton.transform.position;
                HeroReturnCallRateHeroWin.dataList = GetLibItemList(libID, list);
                HeroReturnCallRateHeroWin.isDownShow = true;
                UIManager.Instance.OpenWindow<HeroReturnCallRateHeroWin>();
            });
        }
    }
    public List<Item> GetLibItemList(int libID, List<int> itemList)
    {
        List<Item> res = new();
        for (int i = 0; i < itemList.Count; i++)
        {
            int itemID = itemList[i];
            var config = ItemConfig.Get(itemID);
            if (config == null) continue;
            if (!TreasureItemLibConfig.TryGetID(libID, itemID, out int id)) continue;
            var treasureItemLibConfig = TreasureItemLibConfig.Get(id);
            if (treasureItemLibConfig == null) continue;
            res.Add(new Item(itemID, treasureItemLibConfig.ItemCount));
        }
        return res;
    }
    public bool TryGetHeroItemInfo(int heroID, int libID, List<int> itemList, out int itemID, out int itemCount)
    {
        itemID = 0;
        itemCount = 0;
        if (itemList == null) return false;
        for (int i = 0; i < itemList.Count; i++)
        {
            itemID = itemList[i];
            var config = ItemConfig.Get(itemID);
            if (config == null) continue;
            if (!TreasureItemLibConfig.TryGetID(libID, itemID, out int id)) continue;
            var treasureItemLibConfig = TreasureItemLibConfig.Get(id);
            if (treasureItemLibConfig == null) continue;
            //本体
            if (config.Type == 150)
            {
                if (heroID == itemID)
                {
                    itemCount = treasureItemLibConfig.ItemCount;
                    return true;
                }
            }
            else if (config.Type == 151)
            {
                if (heroID == config.EffectValueA1)
                {
                    itemCount = treasureItemLibConfig.ItemCount;
                    return true;
                }
            }
        }
        return false;
    }
}
Main/System/HeroReturn/HeroReturnCallRateItem.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e8caa7644bce7414d9ada3cef9ee1eff
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnCallRateWin.cs
New file
@@ -0,0 +1,83 @@
using System.Collections.Generic;
using UnityEngine;
public class HeroReturnCallRateWin : UIBase
{
    [SerializeField] ScrollerController scroller;
    public const int rowCountMax = 4;
    HeroReturnManager manager => HeroReturnManager.Instance;
    protected override void OnPreOpen()
    {
        scroller.OnRefreshCell += OnRefreshCell;
        CreateScroller();
    }
    protected override void OnPreClose()
    {
        scroller.OnRefreshCell -= OnRefreshCell;
    }
    void OnRefreshCell(ScrollerDataType type, CellView cell)
    {
        var _cell = cell as HeroReturnCallRateCell;
        _cell.Display(cell.index, gridRateDict, gridList, xbConfig);
    }
    Dictionary<int, int> gridRateDict;
    List<int> gridList;
    XBGetItemConfig xbConfig;
    void CreateScroller()
    {
        var act = manager.GetOperationHeroAppearInfo();
        if (act == null) return;
        var config = ActHeroAppearConfig.Get(act.CfgID);
        if (config == null) return;
        xbConfig = HappyXBModel.Instance.GetXBItemConfigByType(config.ActTreasureType);
        if (xbConfig == null || xbConfig.GridItemRateList1 == null) return;
        gridRateDict = GetGridRateDict(xbConfig.GridItemRateList1);
        if (gridRateDict == null) return;
        gridList = GetSortedGridList();
        if (gridList == null) return;
        scroller.Refresh();
        int rowCount = (int)Mathf.Ceil((float)gridList.Count / rowCountMax);
        for (int i = 0; i < rowCount; i++)
        {
            scroller.AddCell(ScrollerDataType.Header, i);
        }
        scroller.Restart();
    }
    //<格子,万分率>
    public Dictionary<int, int> GetGridRateDict(int[][] gridItemRateList1)
    {
        Dictionary<int, int> res = new();
        for (int i = 0; i < gridItemRateList1.Length; i++)
        {
            res[gridItemRateList1[i][1]] = i == 0 ?
                gridItemRateList1[i][0] :
                gridItemRateList1[i][0] - gridItemRateList1[i - 1][0];
        }
        return res;
    }
    public List<int> GetSortedGridList()
    {
        if (gridRateDict == null || gridRateDict.Count == 0) return null;
        List<int> sortedGrids = new List<int>(gridRateDict.Keys);
        sortedGrids.Sort();
        // sortedGrids.Sort((a, b) =>
        // {
        //     int rateA = gridRateDict[a];
        //     int rateB = gridRateDict[b];
        //     return rateA.CompareTo(rateB);
        // });
        return sortedGrids;
    }
}
Main/System/HeroReturn/HeroReturnCallRateWin.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 3dc8fff9b1f118d4682a6541f30741a0
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnCallResultCell.cs
New file
@@ -0,0 +1,104 @@
using UnityEngine;
using DG.Tweening;
public class HeroReturnCallResultCell : MonoBehaviour
{
    [SerializeField] public ItemCell itemCell;
    [SerializeField] UIEffectPlayer orbBaseEffect;    // 初始状态特效
    [SerializeField] UIEffectPlayer orbBoomEffect;    // 爆发瞬间特效
    [SerializeField] UIEffectPlayer orbQualityEffect; // 品质底色特效
    [SerializeField] UIEffectPlayer flowEffect;       // 最终流光特效
    [HideInInspector] public Vector3 originalLocalPos;
    void Awake()
    {
        // 记录初始本地坐标,用于发牌动画的归位
        originalLocalPos = transform.localPosition;
    }
    /// <summary>
    /// 初始化格子数据
    /// </summary>
    public void DisplayItemCell(int itemID, int count)
    {
        itemCell.Init(new ItemCellModel(itemID, true, count));
        itemCell.button.SetListener(() => ItemTipUtility.Show(itemID));
    }
    /// <summary>
    /// 重置所有 UI 元素和特效至初始状态
    /// </summary>
    public void ResetState()
    {
        itemCell.gameObject.SetActive(false);
        orbBaseEffect.SetActive(false);
        orbBoomEffect.SetActive(false);
        orbQualityEffect.SetActive(false);
        flowEffect.SetActive(false);
    }
    /// <summary>
    /// 阶段 1:播放初始引导光点(飞行阶段)
    /// </summary>
    public void PlayInitialOrb()
    {
        orbBaseEffect.SetActive(true);
        orbBoomEffect.SetActive(false);
        orbQualityEffect.SetActive(false);
        orbBaseEffect.Play(4); // 播放索引为4的通用飞行效
    }
    /// <summary>
    /// 阶段 2 & 3:执行爆开、显色、翻牌、展示流光的组合序列
    /// </summary>
    /// <param name="qualityIndex">品质底色特效索引</param>
    /// <param name="flowQualityIndex">最终流光特效索引</param>
    /// <returns>返回 Sequence 方便外部进行 Stagger(交错)排列</returns>
    public Tween PlayExplosionFadeAndFlipReveal(int qualityIndex, int flowQualityIndex)
    {
        Sequence seq = DOTween.Sequence();
        // [0.0s] 切换特效:关闭飞行态,触发爆发态
        seq.InsertCallback(0f, () =>
        {
            orbBaseEffect.SetActive(false);
            orbBoomEffect.SetActive(true);
            orbBoomEffect.Play(3);
        });
        // [0.2s] 展示品质基色
        seq.InsertCallback(0.2f, () =>
        {
            orbQualityEffect.transform.localScale = Vector3.zero;
            orbQualityEffect.SetActive(true);
            orbQualityEffect.Play(qualityIndex);
        });
        // 品质光团由小变大的回弹动画
        seq.Insert(0.2f, orbQualityEffect.transform.DOScale(Vector3.one, 0.2f).SetEase(Ease.OutBack));
        // [0.8s] 准备翻牌:激活 ItemCell 并设置 90 度侧向,准备旋转
        seq.InsertCallback(0.8f, () =>
        {
            itemCell.gameObject.SetActive(true);
            itemCell.transform.localEulerAngles = new Vector3(0, 90f, 0);
        });
        // [0.8s] 翻转动作(耗时 0.3s):从 90 度旋转回 0 度
        seq.Insert(0.8f, itemCell.transform.DOLocalRotate(Vector3.zero, 0.3f, RotateMode.Fast).SetEase(Ease.OutSine));
        // [1.1s] 序列完结:清理临时特效,激活持久流光
        seq.InsertCallback(1.1f, () =>
        {
            orbBoomEffect.SetActive(false);
            orbQualityEffect.SetActive(false);
            flowEffect.SetActive(true);
            flowEffect.Play(flowQualityIndex);
        });
        return seq;
    }
}
Main/System/HeroReturn/HeroReturnCallResultCell.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: aa9f5a1a80f17304b84d946832fe6381
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnCallResultWin.cs
New file
@@ -0,0 +1,370 @@
using UnityEngine;
using DG.Tweening;
using System.Collections.Generic;
public class HeroReturnCallResultWin : UIBase
{
    [SerializeField] Transform moneyRect;
    [SerializeField] OwnItemCell ownItemCell;
    [SerializeField] ItemCell presentItemCell;         // 抽卡获得的赠送道具
    [SerializeField] RectTransform oneRect;             // 单抽容器中心点
    [SerializeField] HeroReturnCallResultCell oneCell;   // 单抽单元格
    [SerializeField] RectTransform tenRect;             // 十连容器
    [SerializeField] HeroReturnCallResultCell[] tenCell; // 十连单元格数组
    [SerializeField] UIEffectPlayer firstEffect;        // 开屏初始特效
    [SerializeField] HeroReturnCallButton callButton;    // 再次抽取按钮
    [SerializeField] ButtonEx okButton;                 // 确定返回按钮
    HeroReturnManager manager => HeroReturnManager.Instance;
    HappyXBModel xbManager => HappyXBModel.Instance;
    bool isSkip;            // 是否跳过动画
    int treasureType;       // 抽卡宝库类型
    bool isOne = false;     // 是否为单抽模式
    private Sequence animSeq; // 主动画序列
    protected override void InitComponent()
    {
        okButton.SetListener(CloseWindow);
    }
    protected override void OnPreOpen()
    {
        animSeq?.Kill();
        var act = manager.GetOperationHeroAppearInfo();
        if (act == null) return;
        var config = ActHeroAppearConfig.Get(act.CfgID);
        if (config == null) return;
        treasureType = config.ActTreasureType;
        // 根据配置和时间戳加载用户的是否跳过动画设置
        isSkip = manager.LoadCallSkipData(config.CfgID, act.startDate, act.endDate);
        // 绑定数据刷新回调
        HappyXBModel.Instance.RefreshXBResultAct += RefreshXBResultAct;
        HappyXBModel.Instance.RefreshXBTypeInfoAct += OnRefreshXBTypeInfoAct;
        var treasureSetConfig = TreasureSetConfig.Get(config.ActTreasureType);
        if (treasureSetConfig == null) return;
        ownItemCell.itemID = treasureSetConfig.CostItemID;
        RefreshXBResultAct();
    }
    protected override void OnPreClose()
    {
        animSeq?.Kill();
        // 解绑回调,防止内存泄漏
        HappyXBModel.Instance.RefreshXBResultAct -= RefreshXBResultAct;
        HappyXBModel.Instance.RefreshXBTypeInfoAct -= OnRefreshXBTypeInfoAct;
    }
    /// <summary>
    /// 刷新抽卡结果界面
    /// </summary>
    void RefreshXBResultAct()
    {
        isOne = HeroUIManager.Instance.selectCallIndex == 0;
        // 初始化顶部赠送物品
        int itemId = xbManager.addXBAddItemID;
        long count = xbManager.addXBItemCount;
        presentItemCell.Init(new ItemCellModel(itemId, true, count));
        presentItemCell.button.SetListener(() => ItemTipUtility.Show(itemId));
        // 根据单抽或十连填充物品数据
        if (isOne)
        {
            if (!xbManager.xbResultDict.IsNullOrEmpty())
            {
                oneCell.DisplayItemCell(xbManager.xbResultDict[0].itemId, xbManager.xbResultDict[0].count);
            }
        }
        else
        {
            for (int i = 0; i < tenCell.Length; i++)
            {
                if (i < xbManager.xbResultDict?.Count)
                {
                    tenCell[i].DisplayItemCell(xbManager.xbResultDict[i].itemId, xbManager.xbResultDict[i].count);
                }
            }
        }
        callButton.Display(treasureType, HeroUIManager.Instance.selectCallIndex);
        if (isSkip)
        {
            // 模式:跳过动画,直接显示最终状态
            firstEffect.SetActive(false);
            ShowImmediate();
        }
        else
        {
            // 模式:播放完整展示动画
            PrepareAnimation();
            firstEffect.SetActive(true);
            firstEffect.Play(0);
            // 预留 1.1s 的开屏动效时间后,开始播放发牌/翻牌序列
            PlayResultAnimation(1.1f);
        }
    }
    private void OnRefreshXBTypeInfoAct() { RefreshXBResultAct(); }
    /// <summary>
    /// 静态显示(无动画直接展示结果)
    /// </summary>
    private void ShowImmediate()
    {
        animSeq?.Kill();
        oneRect.SetActive(isOne);
        tenRect.SetActive(!isOne);
        ownItemCell.SetActive(true);
        moneyRect.SetActive(true);
        presentItemCell.SetActive(true);
        callButton.SetActive(true);
        okButton.SetActive(true);
        if (isOne)
        {
            oneCell.SetActive(true);
            oneCell.ResetState();
            oneCell.itemCell.SetActive(true);
        }
        else
        {
            for (int i = 0; i < tenCell.Length; i++)
            {
                if (i < xbManager.xbResultDict?.Count)
                {
                    tenCell[i].SetActive(true);
                    tenCell[i].transform.localPosition = tenCell[i].originalLocalPos;
                    tenCell[i].ResetState();
                    tenCell[i].itemCell.SetActive(true);
                }
                else
                {
                    tenCell[i].SetActive(false);
                }
            }
        }
    }
    /// <summary>
    /// 动画前置准备(隐藏元素并重置坐标)
    /// </summary>
    private void PrepareAnimation()
    {
        oneRect.SetActive(isOne);
        tenRect.SetActive(!isOne);
        ownItemCell.SetActive(false);
        moneyRect.SetActive(false);
        presentItemCell.SetActive(false);
        callButton.SetActive(false);
        okButton.SetActive(false);
        if (isOne)
        {
            oneCell.SetActive(true);
            oneCell.ResetState();
        }
        else
        {
            for (int i = 0; i < tenCell.Length; i++)
            {
                if (i < xbManager.xbResultDict?.Count)
                {
                    tenCell[i].SetActive(true);
                    tenCell[i].ResetState();
                    tenCell[i].transform.localPosition = tenCell[i].originalLocalPos;
                }
                else
                {
                    tenCell[i].SetActive(false);
                }
            }
        }
    }
    /// <summary>
    /// 核心逻辑:编排结果展示动画时间轴
    /// </summary>
    private void PlayResultAnimation(float startDelay = 0f)
    {
        animSeq?.Kill();
        animSeq = DOTween.Sequence();
        if (isOne)
        {
            // ==================== 单抽动画逻辑 ====================
            float timelineCursor = startDelay;
            // 1. 播放中心光团
            animSeq.InsertCallback(timelineCursor, () => oneCell.PlayInitialOrb());
            // 预留短暂的展示时间
            float finishShowTime = 0.12f;
            timelineCursor += finishShowTime;
            // 2. 触发爆开与翻牌组合动画
            int itemId = xbManager.xbResultDict[0].itemId;
            int quality = GetOrbQuality(itemId);
            int flowQuality = GetFlowQuality(itemId);
            animSeq.Insert(timelineCursor, oneCell.PlayExplosionFadeAndFlipReveal(quality, flowQuality));
            // 推进游标至组合动画结束(1.1s基础时长 + 0.3s缓冲)
            timelineCursor += 1.4f;
            // 3. 弹出底部 UI
            animSeq.InsertCallback(timelineCursor, ShowBottomUI);
        }
        else
        {
            // ==================== 十连动画逻辑 ====================
            int count = xbManager.xbResultDict.Count;
            float staggerInterval = 0.1f; // 发牌间隔
            float moveDuration = 0.12f;    // 飞行时间
            float timelineCursor = startDelay;
            // 1. 依次从中心点向目标位置发射光团(发牌阶段)
            for (int i = 0; i < count; i++)
            {
                var cell = tenCell[i];
                cell.transform.position = oneRect.position; // 起始于中心
                float delay = timelineCursor + i * staggerInterval;
                animSeq.InsertCallback(delay, () => cell.PlayInitialOrb());
                animSeq.Insert(delay, cell.transform.DOLocalMove(cell.originalLocalPos, moveDuration).SetEase(Ease.OutCubic));
            }
            // 计算所有卡牌完成飞行的时刻
            float finishFlyingTime = ((count - 1) * staggerInterval) + moveDuration;
            timelineCursor += finishFlyingTime;
            // 2. 依次触发爆开翻牌动画(展示阶段)
            for (int i = 0; i < count; i++)
            {
                int itemId = xbManager.xbResultDict[i].itemId;
                int quality = GetOrbQuality(itemId);
                int flowQuality = GetFlowQuality(itemId);
                animSeq.Insert(timelineCursor + i * staggerInterval, tenCell[i].PlayExplosionFadeAndFlipReveal(quality, flowQuality));
            }
            // 计算全部卡牌翻转完成的时间点并加入缓冲
            float finalFlipDuration = 1.1f + ((count - 1) * staggerInterval) + 0.3f;
            timelineCursor += finalFlipDuration;
            // 3. 弹出底部 UI
            animSeq.InsertCallback(timelineCursor, ShowBottomUI);
        }
    }
    /// <summary>
    /// 展示底部操作按钮,并检查是否触发武将立绘
    /// </summary>
    private void ShowBottomUI()
    {
        ownItemCell.SetActive(true);
        moneyRect.SetActive(true);
        presentItemCell.SetActive(true);
        callButton.SetActive(true);
        okButton.SetActive(true);
        presentItemCell.transform.localScale = Vector3.zero;
        callButton.transform.localScale = Vector3.zero;
        okButton.transform.localScale = Vector3.zero;
        Sequence bottomSeq = DOTween.Sequence();
        bottomSeq.Append(presentItemCell.transform.DOScale(Vector3.one, 0.3f).SetEase(Ease.OutBack));
        bottomSeq.Join(callButton.transform.DOScale(Vector3.one, 0.3f).SetEase(Ease.OutBack));
        bottomSeq.Join(okButton.transform.DOScale(Vector3.one, 0.3f).SetEase(Ease.OutBack));
        bottomSeq.OnComplete(() =>
        {
            if (!isSkip)
            {
                CheckAndShowHeroLH();
            }
        });
        animSeq.Append(bottomSeq);
    }
    /// <summary>
    /// 检测并展示高品质武将立绘(弹窗展示)
    /// </summary>
    private void CheckAndShowHeroLH()
    {
        // 清理缓存列表
        ItemLogicUtility.Instance.poplhHeroIdList.Clear();
        List<int> uniqueHeroIds = new List<int>();
        int count = xbManager.xbResultDict.Count;
        for (int i = 0; i < count; i++)
        {
            int itemId = xbManager.xbResultDict[i].itemId;
            // 仅对 HeroConfig 中存在的完整武将进行处理
            if (HeroConfig.HasKey(itemId))
            {
                // 仅展示高于设定品质的武将
                if (HeroConfig.Get(itemId).Quality < HappyXBModel.Instance.lhQuality) continue;
                if (!uniqueHeroIds.Contains(itemId))
                {
                    uniqueHeroIds.Add(itemId);
                }
            }
        }
        // 如果存在符合条件的武将,打开大图展示界面
        if (uniqueHeroIds.Count > 0)
        {
            ItemLogicUtility.Instance.poplhHeroIdList = uniqueHeroIds;
            if (!UIManager.Instance.IsOpenedInList<HeroShowLHWin>())
            {
                UIManager.Instance.OpenWindow<HeroShowLHWin>();
            }
        }
    }
    // --- 辅助方法:映射配置品质到特效索引 ---
    private int GetOrbQuality(int itemId)
    {
        int qualityLevel = ItemConfig.Get(itemId).ItemColor;
        switch (qualityLevel)
        {
            case 2: return 5; // 紫色
            case 3: return 2; // 黄色
            case 4: return 0; // 橙色
            case 5: return 1; // 红色
            default: return 0;
        }
    }
    private int GetFlowQuality(int itemId)
    {
        int qualityLevel = ItemConfig.Get(itemId).ItemColor;
        switch (qualityLevel)
        {
            case 2: return 3; // 紫色
            case 3: return 2; // 黄色
            case 4: return 0; // 橙色
            case 5: return 1; // 红色
            default: return 0;
        }
    }
}
Main/System/HeroReturn/HeroReturnCallResultWin.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fafde75987e7b864ea3c2faa42578100
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnCallWin.cs
New file
@@ -0,0 +1,417 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;
using System.Linq;
using EnhancedUI.EnhancedScroller;
public class HeroReturnCallWin : UIBase
{
    [SerializeField] RawImage chooseHeroBgImage;
    [SerializeField] ButtonEx chooseHeroButton;
    [SerializeField] ImageEx chooseHeroImage1;
    [SerializeField] ImageEx chooseHeroImage2;
    [SerializeField] Transform lhTransform;
    [SerializeField] Transform heroCallTransform;
    [SerializeField] Transform topTransform;
    [SerializeField] Transform heroInfoTransform;
    [SerializeField] ImageEx bgImage;
    [SerializeField] RectTransform changeRect;
    [SerializeField] UIEffectPlayer changeUIEffect;
    [SerializeField] OwnItemCell ownItemCell;
    [SerializeField] ButtonEx closeBtn;
    [SerializeField] Toggle skipToggle;
    [SerializeField] HeroReturnCallButton xbButton1;
    [SerializeField] HeroReturnCallButton xbButton10;
    [SerializeField] TextEx resMoneyCallCntText;
    [SerializeField] TextEx nextBigAwardCntText;
    [SerializeField] GradientText heroQualityText;
    [SerializeField] GradientText heroNameText;
    [SerializeField] TextEx timeText;
    [SerializeField] TextEx nameText;
    [SerializeField] TextEx descText;
    [SerializeField] ImageEx countryImage;
    [SerializeField] ImageEx jobImage;
    [SerializeField] ButtonEx changeHeroButton;//更换英雄
    [SerializeField] ButtonEx previewButton;//满级预览
    [SerializeField] ButtonEx closeButton;
    [SerializeField] ButtonEx shopButton; // 兑换商店
    [SerializeField] RedpointBehaviour shopRedpoint;
    [SerializeField] ButtonEx giftButton; // 皇权礼包
    [SerializeField] RedpointBehaviour giftRedpoint;
    [SerializeField] ButtonEx rankButton;
    [SerializeField] TextEx[] top3NameText;
    [SerializeField] TextEx rankTipText;
    [SerializeField] ButtonEx rateButton;
    [SerializeField] ScrollerController scroller;
    [SerializeField] ButtonEx historyButton;
    [SerializeField] UIHeroController lhController;
    [SerializeField] UIHeroController uiHeroController;
    [SerializeField] HeroReturnCallBubbleCell[] bubbleCell;
    [SerializeField] float modleSize = 1f;
    HeroReturnManager manager => HeroReturnManager.Instance;
    protected override void InitComponent()
    {
        closeButton.SetListener(CloseWindow);
        shopButton.SetListener(() => UIManager.Instance.OpenWindow<HeroReturnShopWin>());
        giftButton.SetListener(() => UIManager.Instance.OpenWindow<HeroReturnGiftWin>());
        changeHeroButton.SetListener(() => UIManager.Instance.OpenWindow<HeroReturnCallChangeWin>());
        rankButton.SetListener(() => UIManager.Instance.OpenWindow<HeroReturnRankWin>());
        rateButton.SetListener(() => UIManager.Instance.OpenWindow<HeroReturnCallRateWin>());
        historyButton.SetListener(() => UIManager.Instance.OpenWindow<HeroReturnCallHistoryWin>());
        chooseHeroButton.SetListener(() => UIManager.Instance.OpenWindow<HeroReturnCallChooseWin>());
        previewButton.SetListener(OnClickPreview);
        skipToggle.AddListener((value) =>
        {
            manager.SaveCallSkipData(config.CfgID, act.startDate, act.endDate, value);
        });
    }
    protected override void OnPreOpen()
    {
        scroller.lockType = EnhanceLockType.LockVerticalBottom;
        RankModel.Instance.ResetQueryParam();
        RankModel.Instance.QueryRankByPage(manager.sendRankType, watchID: (int)PlayerDatas.Instance.baseData.PlayerID, groupValue1: manager.actNum);
        HappyXBModel.Instance.RefreshXBTypeInfoAct += OnRefreshXBTypeInfoAct;
        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
        RankModel.Instance.onRankRefresh += OnRankRefresh;
        PlayerDatas.Instance.playerDataRefreshEvent += PlayerDataRefresh;
        PackManager.Instance.RefreshItemEvent += RefreshItemEvent;
        scroller.OnRefreshCell += OnRefreshCell;
        manager.OnUpdateGameRecInfo += OnUpdateGameRecInfo;
        manager.OnUpdateHeroAppearPlayerInfoEvent += OnUpdateHeroAppearPlayerInfoEvent;
        if (manager.isSendFirst)
        {
            act = manager.GetOperationHeroAppearInfo();
            if (act == null) return;
            config = ActHeroAppearConfig.Get(act.CfgID);
            if (config == null) return;
            int treasureType = config.ActTreasureType;
            manager.SendViewGameRecPack(treasureType);
        }
        InitRedpoint();
        CreateScroller();
        Display();
    }
    protected override void OnPreClose()
    {
        HappyXBModel.Instance.RefreshXBTypeInfoAct -= OnRefreshXBTypeInfoAct;
        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
        RankModel.Instance.onRankRefresh -= OnRankRefresh;
        PlayerDatas.Instance.playerDataRefreshEvent -= PlayerDataRefresh;
        PackManager.Instance.RefreshItemEvent -= RefreshItemEvent;
        scroller.OnRefreshCell -= OnRefreshCell;
        manager.OnUpdateGameRecInfo -= OnUpdateGameRecInfo;
        manager.OnUpdateHeroAppearPlayerInfoEvent -= OnUpdateHeroAppearPlayerInfoEvent;
    }
    private Sequence heroAnimSeq;
    private void OnUpdateHeroAppearPlayerInfoEvent()
    {
        changeRect.SetActive(false);
        if (heroAnimSeq != null)
        {
            heroAnimSeq.Kill();
            heroAnimSeq = null;
        }
        Display();
        Transform targetTrans = lhController.transform;
        // 停止 Transform 上可能残留的单独动画
        targetTrans.DOKill();
        int heroID = manager.GetCurrentDisplayCallHeroId();
        int skinID = manager.GetDefaultSkinID(heroID);
        var skinConfig = HeroSkinConfig.Get(skinID);
        float baseScaleValue = 1f; // 默认缩放
        if (skinConfig != null && skinConfig.TachieParam != null && skinConfig.TachieParam.Length == 4)
        {
            baseScaleValue = skinConfig.TachieParam[2];
        }
        Vector3 baseScale = Vector3.one * baseScaleValue;
        targetTrans.localScale = baseScale;
        CanvasGroup cg = lhController.GetComponent<CanvasGroup>();
        if (cg == null) cg = lhController.gameObject.AddComponent<CanvasGroup>();
        cg.DOKill();
        cg.alpha = 0.8f;
        changeUIEffect.Play();
        heroAnimSeq = DOTween.Sequence();
        heroAnimSeq.Append(targetTrans.DOScale(baseScale * 1.1f, 0.3f).SetEase(Ease.OutQuad));
        heroAnimSeq.Append(targetTrans.DOScale(baseScale, 0.3f).SetEase(Ease.InQuad));
        heroAnimSeq.Join(cg.DOFade(1f, 0.3f).SetEase(Ease.Linear));
        heroAnimSeq.OnComplete(() =>
        {
            changeRect.SetActive(true);
            heroAnimSeq = null;
        });
    }
    private void OnUpdateGameRecInfo()
    {
        CreateScroller();
    }
    public void RefreshItemEvent(PackType packType, int index, int itemID)
    {
        if (packType != PackType.Item && treasureSetConfig?.CostItemID != itemID) return;
        Display();
    }
    private void PlayerDataRefresh(PlayerDataType type)
    {
        if (type != PlayerDataType.Gold) return;
        Display();
    }
    private void OnRankRefresh(int type)
    {
        if (type != manager.sendRankType) return;
        ShowTop3();
    }
    private void OnSecondEvent()
    {
        manager.GetActTimeStr(timeText);
    }
    private void OnRefreshXBTypeInfoAct()
    {
        Display();
    }
    public void InitRedpoint()
    {
        shopRedpoint.redpointId = manager.GetRedPointId(HeroReturnRedPointType.Shop);
        giftRedpoint.redpointId = manager.GetRedPointId(HeroReturnRedPointType.Gift);
    }
    private void OnClickPreview()
    {
        if (heroConfig == null) return;
        HeroUIManager.Instance.selectForPreviewHeroID = heroConfig.HeroID;
        UIManager.Instance.OpenWindow<HeroBestBaseWin>();
    }
    OperationHeroAppearInfo act;
    ActHeroAppearConfig config;
    HeroConfig heroConfig;
    TreasureSetConfig treasureSetConfig;
    XBTypeInfo xbTypeInfo;
    private void Display()
    {
        act = manager.GetOperationHeroAppearInfo();
        if (act == null) return;
        config = ActHeroAppearConfig.Get(act.CfgID);
        if (config == null) return;
        int heroID = manager.GetCurrentDisplayCallHeroId();
        heroConfig = HeroConfig.Get(heroID);
        if (heroConfig == null) return;
        int skinID = manager.GetDefaultSkinID(heroID);
        var skinConfig = HeroSkinConfig.Get(skinID);
        if (skinConfig == null) return;
        var artConfig = ActHeroReturnArtConfig.Get(heroID);
        if (artConfig == null || artConfig.CallBubbleItems == null) return;
        int treasureType = config.ActTreasureType;
        treasureSetConfig = TreasureSetConfig.Get(treasureType);
        if (treasureSetConfig == null) return;
        xbTypeInfo = HappyXBModel.Instance.GetXBInfoByType(treasureType);
        if (xbTypeInfo == null) return;
        bool canChooseHero = !manager.IsSingleHero(act);
        bool isChooseHero = manager.LoadCallChooseHeroStateKey(act);
        chooseHeroBgImage.SetActive(canChooseHero && !isChooseHero);
        chooseHeroButton.SetActive(canChooseHero && !isChooseHero);
        chooseHeroImage1.SetActive(canChooseHero && !isChooseHero);
        chooseHeroImage2.SetActive(canChooseHero && !isChooseHero);
        lhTransform.SetActive(!canChooseHero || isChooseHero);
        heroCallTransform.SetActive(!canChooseHero || isChooseHero);
        topTransform.SetActive(!canChooseHero || isChooseHero);
        heroInfoTransform.SetActive(!canChooseHero || isChooseHero);
        bgImage.SetSprite(artConfig.MainBgImage);
        lhController.Create(skinID, 1, motionName: "", isLh: true);
        uiHeroController.Create(skinID, modleSize);
        uiHeroController.transform.localScale = new Vector3(modleSize, modleSize, modleSize);
        ownItemCell.itemID = treasureSetConfig.CostItemID;
        skipToggle.isOn = manager.LoadCallSkipData(config.CfgID, act.startDate, act.endDate);
        xbButton1.Display(config.ActTreasureType, 0);
        xbButton10.Display(config.ActTreasureType, 1);
        resMoneyCallCntText.text = Language.Get("HeroDebut24", Mathf.Max(treasureSetConfig.DailyMaxCountMoney - xbTypeInfo.treasureCountTodayGold, 0));
        var needCount = GetNextXBCountForBigAward(treasureType);
        nextBigAwardCntText.text = Language.Get("HeroDebut08", needCount.ToString());
        heroQualityText.text = Language.Get($"heroCallQaulity{heroConfig.Quality}");
        manager.SetheroQaulityColor(heroQualityText, heroConfig.Quality);
        nameText.text = heroConfig.Name;
        nameText.color = UIHelper.GetUIColorByFunc(heroConfig.Quality);
        descText.text = heroConfig.Desc;
        countryImage.SetSprite(HeroUIManager.Instance.GetCountryIconName(heroConfig.Country));
        jobImage.SetSprite(HeroUIManager.Instance.GetJobIconName(heroConfig.Class));
        heroNameText.text = heroConfig.Name;
        manager.SetGradientTextColor(heroNameText, artConfig.HeroNameColor);
        for (int i = 0; i < bubbleCell.Length; i++)
        {
            if (i < artConfig.CallBubbleItems.Length)
            {
                bubbleCell[i].SetActive(true);
                bubbleCell[i].Display(artConfig.CallBubbleItems[i][0], artConfig.CallBubbleItems[i][1]);
            }
            else
            {
                bubbleCell[i].SetActive(false);
            }
        }
        ShowTop3();
        OnSecondEvent();
    }
    public int GetNextXBCountForBigAward(int type)
    {
        XBTypeInfo typeInfo = HappyXBModel.Instance.GetXBInfoByType(type);
        if (typeInfo == null) return 0;
        var xbConfig = HappyXBModel.Instance.GetXBItemConfigByType(type);
        var luckList = xbConfig.LuckyItemRateInfo.Keys.ToList();
        luckList.Sort();
        for (int i = 0; i < luckList.Count; i++)
        {
            var luckyValue = typeInfo.luckValue;
            if (luckyValue < luckList[i])
            {
                return luckList[i] - luckyValue;
            }
        }
        return 0;
    }
    void ShowTop3()
    {
        for (int i = 0; i < top3NameText.Length; i++)
        {
            var rankData = RankModel.Instance.GetRankDataByRank(manager.loadRankType, i + 1);
            top3NameText[i].text = rankData == null ? Language.Get("L1124") : rankData.name1;
        }
        int billTempID = config.BillTempID;
        rankTipText.text = Language.Get("HeroDebut27", ActBillboardAwardConfig.GetTop3MinCalNeedValue(billTempID));
    }
    public List<HeroReturnGameRec> list;
    void OnRefreshCell(ScrollerDataType type, CellView cell)
    {
        var _cell = cell as HeroReturnCallHistoryOutCell;
        _cell.Display(cell.index, list);
    }
    float autoScrollInterval = 2f;
    private float autoScrollTimer = 0f;
    private int currentScrollerIndex = 0;
    private bool isScrollerReady = false; // 判定标志
    void CreateScroller()
    {
        list = manager.GetGameRecList();
        scroller.Refresh();
        int listCount = list?.Count ?? 0;
        if (list != null)
        {
            for (int i = 0; i < listCount; i++)
            {
                scroller.AddCell(ScrollerDataType.Header, i);
            }
        }
        bool canScroll = listCount > 4;// 只有数量 > 4 时才开启 Loop 和计时器
        scroller.m_Scorller.Loop = canScroll;
        isScrollerReady = canScroll;
        scroller.vertical = false;
        scroller.horizontal = false;
        scroller.Restart();
        // 如果是循环模式,确保初始位置正确
        if (canScroll)
        {
            scroller.m_Scorller.JumpToDataIndex(0,
            tweenType: EnhancedScroller.TweenType.immediate);
        }
        autoScrollTimer = 0f;
        currentScrollerIndex = 0;
    }
    private void LateUpdate()
    {
        // 只有在数据就绪且超过 4 个时,才执行计时逻辑
        if (isScrollerReady)
        {
            autoScrollTimer += Time.deltaTime;
            if (autoScrollTimer >= autoScrollInterval)
            {
                autoScrollTimer = 0f;
                AutoScrollNext();
            }
        }
    }
    private void AutoScrollNext()
    {
        if (list?.Count <= 4)
        {
            isScrollerReady = false;
            return;
        }
        // 检查 scroller 的 GameObject 是否处于激活状态
        if (scroller == null || scroller.m_Scorller == null || !scroller.m_Scorller.gameObject.activeInHierarchy)
        {
            return;
        }
        currentScrollerIndex++;
        // 在 Loop 模式下进行平滑跳转
        scroller.m_Scorller.JumpToDataIndex(
            currentScrollerIndex % list.Count,
            tweenType: EnhancedScroller.TweenType.easeInOutQuad,
            tweenTime: 0.5f);
    }
}
Main/System/HeroReturn/HeroReturnCallWin.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 0774834d6226ea848adedc229e82552f
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnCell.cs
New file
@@ -0,0 +1,30 @@
using UnityEngine;
public class HeroReturnCell : MonoBehaviour
{
    [SerializeField] ButtonEx clickButton;
    [SerializeField] ImageEx bgImage;
    [SerializeField] ImageEx heroImage;
    [SerializeField] GradientText titleText;
    HeroReturnManager manager => HeroReturnManager.Instance;
    public void Display()
    {
        clickButton.SetListener(() =>
        {
            UIManager.Instance.OpenWindow<HeroReturnWin>();
        });
        int heroID = manager.GetFirstHeroId();
        var artConfig = ActHeroReturnArtConfig.Get(heroID);
        if (artConfig == null) return;
        int skinID = manager.GetDefaultSkinID(heroID);
        var skinConfig = HeroSkinConfig.Get(skinID);
        if (skinConfig == null) return;
        bgImage.SetSprite(artConfig.EntryBgImage);
        manager.SetHeroSquareIcon(heroImage, skinConfig.SquareIcon);
        titleText.text = artConfig.EntryTitleText;
    }
}
Main/System/HeroReturn/HeroReturnCell.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dc2b313f9675a0644bd1a684fe9bad47
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnCheckInCell.cs
New file
@@ -0,0 +1,60 @@
using UnityEngine;
public class HeroReturnCheckInCell : MonoBehaviour
{
    [SerializeField] ButtonEx clickButton;
    [SerializeField] ImageEx bgImage;
    [SerializeField] TextEx dayText;
    [SerializeField] TextEx itemNameText;
    [SerializeField] ItemCell itemCell;
    [SerializeField] UIEffectPlayer uiEffectPlayer;
    [SerializeField] Transform imgMask;
    HeroReturnManager manager => HeroReturnManager.Instance;
    private int currentItemId;
    private int currentState;
    public void Display(int templateID, int dayNum)
    {
        uiEffectPlayer.Stop();
        var config = ActSignAwardConfig.GetConfig(templateID, dayNum);
        if (config == null) return;
        if (config.SignAwardItemList.IsNullOrEmpty()) return;
        currentItemId = config.SignAwardItemList[0][0];
        int count = config.SignAwardItemList[0][1];
        var itemConfig = ItemConfig.Get(currentItemId);
        if (itemConfig == null) return;
        currentState = manager.GetCheckInState(dayNum);
        imgMask.SetActive(currentState == 2);
        bgImage.SetSprite(currentState == 1 ? "HeroDebutCheckInDayBG1" : "HeroDebutCheckInDayBG2");
        if (currentState == 1)
        {
            uiEffectPlayer.Play();
        }
        dayText.text = Language.Get($"SignDay{dayNum}");
        itemNameText.text = itemConfig.ItemName;
        itemCell.Init(new ItemCellModel(currentItemId, false, count));
        itemCell.button.AddListener(OnItemClicked);
        clickButton.SetListener(() => manager.SendGetCheckInReward());
    }
    private void OnItemClicked()
    {
        if (currentState == 1)
        {
            manager.SendGetCheckInReward();
        }
        else
        {
            ItemTipUtility.Show(currentItemId);
        }
    }
}
Main/System/HeroReturn/HeroReturnCheckInCell.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7dc473ad41cdeb049b5ff9072138f709
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnCheckInWin.cs
New file
@@ -0,0 +1,81 @@
using UnityEngine;
public class HeroReturnCheckInWin : UIBase
{
    [SerializeField] ImageEx bgImage;
    [SerializeField] UIHeroController rolelhShow;
    [SerializeField] TextEx timeText;
    [SerializeField] ButtonEx closeButton;
    [SerializeField] HeroReturnCheckInCell[] cells;
    HeroReturnManager manager => HeroReturnManager.Instance;
    protected override void InitComponent()
    {
        closeButton.SetListener(CloseWindow);
    }
    protected override void OnPreOpen()
    {
        GeneralActInfoManager.Instance.OnUpdateActSignInfosEvent += OnUpdateActSignInfosEvent;
        TimeMgr.Instance.OnDayEvent += OnDayEvent;
        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
        Display();
    }
    protected override void OnPreClose()
    {
        GeneralActInfoManager.Instance.OnUpdateActSignInfosEvent -= OnUpdateActSignInfosEvent;
        TimeMgr.Instance.OnDayEvent -= OnDayEvent;
        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
    }
    private void OnDayEvent()
    {
        Display();
    }
    private void OnUpdateActSignInfosEvent(int arg1, int arg2)
    {
        Display();
    }
    private void OnSecondEvent()
    {
        manager.GetActTimeStr(timeText);
    }
    private void Display()
    {
        int heroID = manager.GetFirstHeroId();
        var artConfig = ActHeroReturnArtConfig.Get(heroID);
        if (artConfig == null) return;
        var heroConfig = HeroConfig.Get(heroID);
        if (heroConfig == null) return;
        int skinID = manager.GetDefaultSkinID(heroID);
        var act = manager.GetOperationHeroAppearInfo();
        if (act == null) return;
        var config = ActHeroAppearConfig.Get(act.CfgID);
        if (config == null) return;
        int templateID = config.SignTempID;
        var list = ActSignAwardConfig.GetDayNumSortList(templateID);
        if (list == null) return;
        bgImage.SetSprite(artConfig.CheckInBgImage);
        for (int i = 0; i < cells.Length; i++)
        {
            if (i < list.Count)
            {
                cells[i].SetActive(true);
                cells[i].Display(templateID, list[i]);
            }
            else
            {
                cells[i].SetActive(false);
            }
        }
        rolelhShow.Create(skinID, 1, motionName: "", isLh: true);
        OnSecondEvent();
    }
}
Main/System/HeroReturn/HeroReturnCheckInWin.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: d4ec9226f50edd6408ce3f2bdb9821ca
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnGiftCell.cs
New file
@@ -0,0 +1,165 @@
using System.Collections.Generic;
using UnityEngine;
public class HeroReturnGiftCell : MonoBehaviour
{
    [SerializeField] ImageEx vipImage;
    [SerializeField] TextEx vipText;
    [SerializeField] OutlineEx vipTextOutline;
    [SerializeField] ImageEx rateImage;
    [SerializeField] TextEx rateText;
    [SerializeField] ItemCell[] itemCells;
    [SerializeField] TextEx titleText;
    [SerializeField] ButtonEx buyButton;
    [SerializeField] ImageEx buyImage;
    [SerializeField] TextEx buyText;
    [SerializeField] TextEx buyText1;
    [SerializeField] ImageEx moneyIconImage;
    [SerializeField] TextEx limitCountText;
    [SerializeField] ImageEx redImage;
    HeroReturnManager manager => HeroReturnManager.Instance;
    StoreModel storeModel => StoreModel.Instance;
    public void Display(int index, List<HeroReturnGiftItem> giftItems)
    {
        if (giftItems.IsNullOrEmpty() || index < 0 || index >= giftItems.Count) return;
        HeroReturnGiftItem item = giftItems[index];
        if (item.type == 0)
        {
            DisplayStore(item.id);
            return;
        }
        DisplayCTG(item.id);
    }
    private void DisplayCTG(int ctgId)
    {
        redImage.SetActive(false);
        buyText.SetActive(true);
        buyText1.SetActive(false);
        moneyIconImage.SetActive(false);
        rateImage.SetActive(true);
        if (!RechargeManager.Instance.TryGetOrderInfo(ctgId, out var orderConfig)) return;
        if (!RechargeManager.Instance.TryGetRechargeCount(ctgId, out var rechargeCount)) return;
        if (!CTGConfig.HasKey(ctgId)) return;
        if (!RechargeManager.Instance.TryGetRechargeItem(ctgId, out var rechargeItemList)) return;
        CTGConfig config = CTGConfig.Get(ctgId);
        vipImage.SetActive(config.VipLevel > 0);
        if (config.VipLevel > 0)
        {
            vipImage.SetSprite($"VipLevel{config.VipLevel}");
            vipText.text = Language.Get($"VipLevelInfo{config.VipLevel}");
            vipText.color = InvestModel.Instance.GetTextColor(config.VipLevel);
            vipTextOutline.OutlineColor = InvestModel.Instance.GetOutlineColor(config.VipLevel);
        }
        rateImage.SetActive(true);
        rateText.text = Language.Get("DailySpecials07", config.Percentage);
        bool isCanBuy = manager.IsCanBuyToday(ctgId);
        titleText.text = config.Title;
        buyImage.SetSprite(isCanBuy ? "DailySpecialsBuy1" : "DailySpecialsBuy2");
        buyText.text = !isCanBuy ? Language.Get("storename11") : Language.Get("PayMoneyNum", UIHelper.GetMoneyFormat(orderConfig.PayRMBNumOnSale));
        limitCountText.SetActive(config.DailyBuyCount > 0);
        limitCountText.text = Language.Get("HeroDebut39", UIHelper.AppendColor(rechargeCount.todayCount >= config.DailyBuyCount ? TextColType.Red : TextColType.LightGreen, Mathf.Max(0, config.DailyBuyCount - rechargeCount.todayCount).ToString()));
        buyButton.interactable = isCanBuy;
        buyButton.SetListener(() =>
        {
            if (config.VipLevel > 0 && !FuncOpen.Instance.IsFuncOpen((int)FuncOpenEnum.PrivilegeCard))
            {
                SysNotifyMgr.Instance.ShowTip("MinggeAuto8");
                return;
            }
            if (config.VipLevel == 1 && !InvestModel.Instance.IsInvested(InvestModel.monthCardType))
            {
                SysNotifyMgr.Instance.ShowTip("MinggeAuto5");
                UIManager.Instance.OpenWindow<PrivilegeCardWin>();
                return;
            }
            if (config.VipLevel == 2 && !InvestModel.Instance.IsInvested(InvestModel.foreverCardType))
            {
                SysNotifyMgr.Instance.ShowTip("MinggeAuto7");
                UIManager.Instance.OpenWindow<PrivilegeCardWin>();
                return;
            }
            RechargeManager.Instance.CTG(ctgId);
        });
        for (int i = 0; i < itemCells.Length; i++)
        {
            var itemBaisc = itemCells[i];
            if (i < rechargeItemList.Count)
            {
                var itemInfo = rechargeItemList[i];
                itemBaisc.SetActive(true);
                itemBaisc.Init(new ItemCellModel((int)itemInfo.id, false, itemInfo.countEx));
                itemBaisc.button.AddListener(() =>
                {
                    ItemTipUtility.Show((int)itemInfo.id);
                });
            }
            else
            {
                itemBaisc.SetActive(false);
            }
        }
    }
    private void DisplayStore(int id)
    {
        rateImage.SetActive(false);
        vipImage.SetActive(false);
        if (!StoreConfig.HasKey(id)) return;
        StoreConfig storeConfig = StoreConfig.Get(id);
        int remainNum;
        storeModel.TryGetIsSellOut(storeConfig, out remainNum);
        bool isFree = manager.IsFreeShop(id);
        titleText.text = storeConfig.Name;
        limitCountText.SetActive(!isFree);
        limitCountText.text = Language.Get("TimeRush08", UIHelper.AppendColor(remainNum == 0 ? TextColType.Red : TextColType.LightGreen, Mathf.Max(0, remainNum).ToString(), true));
        bool isCanBuy = manager.IsNoSellOutShopID(id);
        redImage.SetActive(isFree && isCanBuy);
        buyText.SetActive(isFree || !isCanBuy);
        buyText.text = isFree ? Language.Get("L1127") : Language.Get("storename11");
        buyText1.SetActive(!isFree && isCanBuy);
        buyText1.text = UIHelper.GetMoneyFormat(storeConfig.MoneyNum);
        moneyIconImage.SetActive(!isFree && isCanBuy);
        moneyIconImage.SetIconWithMoneyType(1);
        buyImage.SetSprite(isCanBuy ? "DailySpecialsBuy1" : "DailySpecialsBuy2");
        buyButton.interactable = isCanBuy;
        buyButton.SetListener(() =>
        {
            storeModel.SendBuyShopItemWithPopCheck(storeConfig, 1, (int)BuyStoreItemCheckType.ActGift);
        });
        var items = storeModel.GetShopItemlistByIndex(storeConfig);
        for (int i = 0; i < itemCells.Length; i++)
        {
            var itemBaisc = itemCells[i];
            if (i < items.Count)
            {
                var itemInfo = items[i];
                itemBaisc.SetActive(true);
                itemBaisc.Init(new ItemCellModel(itemInfo.itemId, false, itemInfo.count));
                itemBaisc.button.AddListener(() =>
                {
                    ItemTipUtility.Show(itemInfo.itemId);
                });
            }
            else
            {
                itemBaisc.SetActive(false);
            }
        }
    }
}
Main/System/HeroReturn/HeroReturnGiftCell.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4a5a9f2a5a389d24b8e9b1847cf53d35
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnGiftWin.cs
New file
@@ -0,0 +1,86 @@
using System.Collections.Generic;
using UnityEngine;
public class HeroReturnGiftWin : UIBase
{
    [SerializeField] ButtonEx closeButton;
    [SerializeField] ImageEx bgImage;
    [SerializeField] ImageEx heroImage;
    [SerializeField] ScrollerController scroller;
    [SerializeField] TextEx timeText;
    HeroReturnManager manager => HeroReturnManager.Instance;
    StoreModel storeModel => StoreModel.Instance;
    protected override void InitComponent()
    {
        closeButton.SetListener(CloseWindow);
    }
    protected override void OnPreOpen()
    {
        scroller.OnRefreshCell += OnRefreshCell;
        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
        RechargeManager.Instance.rechargeCountEvent += OnRechargeCountEvent;
        storeModel.RefreshBuyShopLimitEvent += RefreshBuyShopLimitEvent;
        int heroID = manager.GetFirstHeroId();
        var artConfig = ActHeroReturnArtConfig.Get(heroID);
        if (artConfig == null) return;
        bgImage.SetSprite(artConfig.GiftBgImage);
        heroImage.SetNativeSize();
        heroImage.SetSprite(artConfig.GiftHeroImage);
        heroImage.SetNativeSize();
        OnSecondEvent();
        CreateGiftScroller();
    }
    protected override void OnPreClose()
    {
        scroller.OnRefreshCell -= OnRefreshCell;
        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
        RechargeManager.Instance.rechargeCountEvent -= OnRechargeCountEvent;
        storeModel.RefreshBuyShopLimitEvent -= RefreshBuyShopLimitEvent;
    }
    private void OnRefreshCell(ScrollerDataType type, CellView cell)
    {
        var _cell = cell.GetComponent<HeroReturnGiftCell>();
        _cell?.Display(cell.index, giftItems);
    }
    private void OnSecondEvent()
    {
        manager.GetActTimeStr(timeText);
    }
    private void OnRechargeCountEvent(int obj)
    {
        RefreshAll();
    }
    private void RefreshBuyShopLimitEvent()
    {
        RefreshAll();
    }
    List<HeroReturnGiftItem> giftItems;
    private void CreateGiftScroller()
    {
        giftItems = manager.GetGiftItemList(true);
        scroller.Refresh();
        if (!giftItems.IsNullOrEmpty())
        {
            for (int i = 0; i < giftItems.Count; i++)
            {
                scroller.AddCell(ScrollerDataType.Header, i);
            }
        }
        scroller.Restart();
    }
    void RefreshAll()
    {
        scroller.m_Scorller.RefreshActiveCellViews();
    }
}
Main/System/HeroReturn/HeroReturnGiftWin.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7cc0cd7de844ca946be560af29b6a17c
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnManager.cs
New file
@@ -0,0 +1,1152 @@
using System;
using System.Collections.Generic;
using System.Linq;
using LitJson;
using UnityEngine;
public class HeroReturnManager : GameSystemManager<HeroReturnManager>, IOpenServerActivity
{
    public int[] xbGridArr;
    public Dictionary<int, int[][]> heroQaulityColor;
    public int[][] seeArr;
    public override void Init()
    {
        DTC0102_tagCDBPlayer.beforePlayerDataInitializeEventOnRelogin += OnBeforePlayerDataInitializeEventOnRelogin;
        DTC0403_tagPlayerLoginLoadOK.playerLoginOkEvent += OnPlayerLoginOk;
        FuncOpen.Instance.OnFuncStateChangeEvent += OnFuncStateChangeEvent;
        OperationTimeHepler.Instance.operationTimeUpdateEvent += OperationTimeUpdateEvent;
        OperationTimeHepler.Instance.operationStartEvent += OperationStartEvent;
        OperationTimeHepler.Instance.operationEndEvent += OperationEndEvent;
        OperationTimeHepler.Instance.operationAdvanceEvent += OperationAdvanceEvent;
        StoreModel.Instance.RefreshBuyShopLimitEvent += RefreshBuyShopLimitEvent;
        GeneralActInfoManager.Instance.OnUpdateActSignInfosEvent += OnUpdateActSignInfosEvent;
        HeroManager.Instance.onHeroChangeEvent += OnHeroChangeEvent;
        TimeMgr.Instance.OnDayEvent += OnDayEvent;
        var config = FuncConfigConfig.Get("HeroAppear");
        xbGridArr = JsonMapper.ToObject<int[]>(config.Numerical1);
        config = FuncConfigConfig.Get("HeroReturn");
        heroQaulityColor = ConfigParse.ParseIntArray2Dict(config.Numerical1);
        seeArr = JsonMapper.ToObject<int[][]>(config.Numerical2);
        InitRedPointId();
    }
    public void SetheroQaulityColor(GradientText text, int qaulity)
    {
        if (!heroQaulityColor.TryGetValue(qaulity, out var colors)) return;
        if (colors?.Length < 2) return;
        text.SetVerticalGradient(ParseColor32(colors[0]), ParseColor32(colors[1]));
    }
    public override void Release()
    {
        DTC0102_tagCDBPlayer.beforePlayerDataInitializeEventOnRelogin -= OnBeforePlayerDataInitializeEventOnRelogin;
        DTC0403_tagPlayerLoginLoadOK.playerLoginOkEvent -= OnPlayerLoginOk;
        FuncOpen.Instance.OnFuncStateChangeEvent -= OnFuncStateChangeEvent;
        OperationTimeHepler.Instance.operationTimeUpdateEvent -= OperationTimeUpdateEvent;
        OperationTimeHepler.Instance.operationStartEvent -= OperationStartEvent;
        OperationTimeHepler.Instance.operationEndEvent -= OperationEndEvent;
        OperationTimeHepler.Instance.operationAdvanceEvent -= OperationAdvanceEvent;
        StoreModel.Instance.RefreshBuyShopLimitEvent -= RefreshBuyShopLimitEvent;
        GeneralActInfoManager.Instance.OnUpdateActSignInfosEvent -= OnUpdateActSignInfosEvent;
        HeroManager.Instance.onHeroChangeEvent -= OnHeroChangeEvent;
        TimeMgr.Instance.OnDayEvent -= OnDayEvent;
    }
    private void OnDayEvent()
    {
        UpdateRedpoint();
    }
    private void OnHeroChangeEvent(HeroInfo info)
    {
        UpdateRedpoint();
    }
    private void OnUpdateActSignInfosEvent(int arg1, int arg2)
    {
        UpdateRedpoint();
    }
    private void RefreshBuyShopLimitEvent()
    {
        UpdateRedpoint();
    }
    private void OnBeforePlayerDataInitializeEventOnRelogin()
    {
        isSendFirst = true;
        starHeroIndex = 0;
        callHeroIndex = 0;
        starFreeAwardDict.Clear();
    }
    private void OnPlayerLoginOk()
    {
        TryPopWin();
    }
    private void OnFuncStateChangeEvent(int obj)
    {
        if (obj != (int)FuncOpenEnum.HeroReturn)
            return;
        TryPopWin();
    }
    public readonly int sendRankType = 6;
    public int loadRankType => actNum * 1000 + sendRankType;
    public const int activityType = (int)OpenServerActivityCenter.ActivityType.AT_DateActivity;
    public const int activityID = (int)NewDayActivityID.HeroReturnAct;
    public static OperationType operaType = OperationType.HeroReturn;
    public Redpoint redPoint = new Redpoint(MainRedDot.HeroReturnRepoint);
    public bool IsOpen => OperationTimeHepler.Instance.SatisfyOpenCondition(operaType);
    public bool IsAdvance => OperationTimeHepler.Instance.SatisfyAdvanceCondition(operaType);
    public bool priorityOpen => redPoint.state == RedPointState.Simple;
    public readonly int actNum = 11;
    public event Action<int> onStateUpdate;
    private void OperationTimeUpdateEvent(OperationType type)
    {
        if (type == operaType)
        {
            if (UIManager.Instance.IsOpened<HeroReturnPopWin>())
                UIManager.Instance.CloseWindow<HeroReturnPopWin>();
            if (UIManager.Instance.IsOpened<HeroReturnWin>())
                UIManager.Instance.CloseWindow<HeroReturnWin>();
            UpdateRedpoint();
        }
    }
    private void OperationStartEvent(OperationType type, int state)
    {
        if (type == operaType && state == 0)
        {
            onStateUpdate?.Invoke(activityID);
            TryPopWin();
            UpdateRedpoint();
        }
    }
    private void OperationEndEvent(OperationType type, int state)
    {
        if (type == operaType)
        {
            onStateUpdate?.Invoke(activityID);
            if (UIManager.Instance.IsOpened<HeroReturnPopWin>())
                UIManager.Instance.CloseWindow<HeroReturnPopWin>();
            if (UIManager.Instance.IsOpened<HeroReturnWin>())
                UIManager.Instance.CloseWindow<HeroReturnWin>();
            UpdateRedpoint();
        }
    }
    private void OperationAdvanceEvent(OperationType type)
    {
        if (type == operaType)
        {
            onStateUpdate?.Invoke(activityID);
            UpdateRedpoint();
        }
    }
    public OperationHeroAppearInfo GetOperationHeroAppearInfo()
    {
        OperationTimeHepler.Instance.TryGetOperation(operaType, out OperationHeroAppearInfo act);
        return act;
    }
    public void SetHeroSquareIcon(ImageEx image, string name)
    {
        var sprite = UILoader.LoadSprite("HeroHead", name);
        if (sprite != null)
        {
            image.overrideSprite = sprite;
            return;
        }
        image.SetSprite("herohead_default");
    }
    public void GetActTimeStr(TextEx timeText, string key = "TimeRush05")
    {
        var act = GetOperationHeroAppearInfo();
        if (act == null)
        {
            timeText.text = Language.Get("OSActivity6");
            return;
        }
        timeText.text = Language.Get(key, TimeUtility.SecondsToShortDHMS(act.GetResetSurplusTime()));
    }
    public void SetGradientTextColor(GradientText text, int[][] colors)
    {
        if (colors?.Length < 4) return;
        text.topLeftColor = ParseColor32(colors[0]);
        text.topRightColor = ParseColor32(colors[1]);
        text.bottomLeftColor = ParseColor32(colors[2]);
        text.bottomRightColor = ParseColor32(colors[3]);
        text.SetVerticesDirty();
    }
    public Color32 ParseColor32(int[] colorArr)
    {
        return new Color32()
        {
            r = (byte)(colorArr.Length > 0 ? colorArr[0] : 0),
            g = (byte)(colorArr.Length > 1 ? colorArr[1] : 0),
            b = (byte)(colorArr.Length > 2 ? colorArr[2] : 0),
            a = (byte)(colorArr.Length > 3 ? colorArr[3] : 255),
        };
    }
    public int GetDefaultSkinID(int heroID)
    {
        HeroConfig heroConfig = HeroConfig.Get(heroID);
        if (heroConfig == null || heroConfig.SkinIDList.IsNullOrEmpty()) return 0;
        return heroConfig.SkinIDList[0];
    }
    public bool IsHeroReturnOpen()
    {
        if (!IsOpen) return false;
        if (!FuncOpen.Instance.IsFuncOpen((int)FuncOpenEnum.HeroReturn)) return false;
        return true;
    }
    public int GetHeroIdIndex(int cfgID, int heroID)
    {
        var config = ActHeroAppearConfig.Get(cfgID);
        if (config == null) return 0;
        var heroArr = config.ActHeroIDList;
        if (heroArr.IsNullOrEmpty()) return 0;
        int index = Array.IndexOf(heroArr, heroID);
        return index;
    }
    public event Action OnNowCallChooseHeroIDChangeEvent;
    private int m_heroAppearActNum = 0;
    public int nowCallChooseHeroID
    {
        get { return m_heroAppearActNum; }
        set
        {
            if (m_heroAppearActNum == value) return;
            m_heroAppearActNum = value;
            OnNowCallChooseHeroIDChangeEvent?.Invoke();
        }
    }
    public event Action OnNowStarUpChooseHeroIDChangeEvent;
    private int m_nowStarUpChooseHeroID = 0;
    public int nowStarUpChooseHeroID
    {
        get { return m_nowStarUpChooseHeroID; }
        set
        {
            if (m_nowStarUpChooseHeroID == value) return;
            m_nowStarUpChooseHeroID = value;
            OnNowStarUpChooseHeroIDChangeEvent?.Invoke();
        }
    }
    public int starHeroIndex = 0;
    public int callHeroIndex = 0;
    //<升星计划选择的武将ID索引,升星计划免费奖励记录>
    Dictionary<int, uint> starFreeAwardDict = new();
    public event Action OnUpdateHeroAppearPlayerInfoEvent;
    public void UpdateHeroAppearPlayerInfo(HAA22_tagSCActHeroAppearPlayerInfo vNetData)
    {
        if (vNetData == null) return;
        if (vNetData.ActNum != this.actNum) return;
        int actNum = vNetData.ActNum;
        starHeroIndex = vNetData.StarHeroIndex;
        callHeroIndex = vNetData.CallHeroIndex;
        starFreeAwardDict[starHeroIndex] = vNetData.StarFreeAward;
        UpdateRedpoint();
        OnUpdateHeroAppearPlayerInfoEvent?.Invoke();
    }
    public void SendHeroAppearStarHeroSelect(int actNum, int starHeroIndex)
    {
        var pack = new CAA01_tagCSActHeroAppearStarHeroSelect();
        pack.ActNum = (byte)actNum;                 // 活动编号
        pack.StarHeroIndex = (byte)starHeroIndex;   // 升星计划选择的武将ID索引
        GameNetSystem.Instance.SendInfo(pack);
    }
    public void SnedHeroAppearCallHeroSelect(int actNum, int callHeroIndex)
    {
        var pack = new CAA02_tagCSActHeroAppearCallHeroSelect();
        pack.ActNum = (byte)actNum;                 // 活动编号
        pack.CallHeroIndex = (byte)callHeroIndex;   // 招募选择的武将ID索引
        GameNetSystem.Instance.SendInfo(pack);
    }
    public void SendGetStarReward()
    {
        var pack = new CA504_tagCMPlayerGetReward();
        pack.RewardType = 10;
        pack.DataEx = (uint)actNum;
        GameNetSystem.Instance.SendInfo(pack);
    }
    #region 红点
    public int GetRedPointId(HeroReturnRedPointType type)
    {
        return MainRedDot.HeroReturnRepoint * 10 + (int)type;
    }
    public Redpoint checkInRedpoint;
    public Redpoint starUpRedpoint;
    public Redpoint shopRedpoint;
    public Redpoint giftRedpoint;
    public void InitRedPointId()
    {
        checkInRedpoint ??= new Redpoint(MainRedDot.HeroReturnRepoint, GetRedPointId(HeroReturnRedPointType.CheckIn));
        starUpRedpoint ??= new Redpoint(MainRedDot.HeroReturnRepoint, GetRedPointId(HeroReturnRedPointType.StarUp));
        shopRedpoint ??= new Redpoint(MainRedDot.HeroReturnRepoint, GetRedPointId(HeroReturnRedPointType.Shop));
        giftRedpoint ??= new Redpoint(MainRedDot.HeroReturnRepoint, GetRedPointId(HeroReturnRedPointType.Gift));
    }
    public void UpdateRedpoint()
    {
        redPoint.state = RedPointState.None;
        checkInRedpoint.state = RedPointState.None;
        starUpRedpoint.state = RedPointState.None;
        shopRedpoint.state = RedPointState.None;
        giftRedpoint.state = RedPointState.None;
        if (!IsHeroReturnOpen()) return;
        if (HasCheckInCanHave()) //签到赠礼
        {
            checkInRedpoint.state = RedPointState.Simple;
        }
        if (HasStarUpCanHave())//星级提升
        {
            starUpRedpoint.state = RedPointState.Simple;
        }
        //兑换商店每天0点显示红点,点击进入一次界面后消失
        if (!IsShopVisitedToday) //兑换商店
        {
            shopRedpoint.state = RedPointState.Simple;
        }
        if (HasGiftCanHave())//皇权礼包
        {
            giftRedpoint.state = RedPointState.Simple;
        }
    }
    #endregion
    #region 拍脸界面
    public bool IsTodayPop
    {
        get
        {
            int lastPopTime = LoadPopTimeData();
            int todayStartTime = TimeUtility.GetTodayStartTick();
            return lastPopTime < todayStartTime;
        }
    }
    private string PopTimeDataKey { get { return $"HeroReturnManager_PopTimeData_{PlayerDatas.Instance.PlayerId}"; } }
    private int LoadPopTimeData()
    {
        return LocalSave.GetInt(PopTimeDataKey);
    }
    public void SavePopTimeData()
    {
        LocalSave.SetInt(PopTimeDataKey, TimeUtility.AllSeconds);
    }
    private void TryPopWin()
    {
        if (!IsHeroReturnOpen()) return;
        if (!IsTodayPop) return;
        if (UIManager.Instance.IsOpened<HeroReturnPopWin>()) return;
        if (UIManager.Instance.IsOpened<HeroReturnWin>()) return;
        PopupWindowsProcessor.Instance.Add("HeroReturnPopWin");
    }
    #endregion
    #region 签到
    private int GetNowDayNum()
    {
        var act = GetOperationHeroAppearInfo();
        if (act == null) return 0;
        int dayNum = act.IndexOfDays(TimeUtility.ServerNow);
        return dayNum < 0 ? 0 : dayNum + 1;
    }
    private bool IsCheckInGridUnlock(int gridDayNum)
    {
        int nowDayNum = GetNowDayNum();
        if (nowDayNum <= 0) return false;
        return nowDayNum >= gridDayNum;
    }
    /// <summary>
    /// 0-未解锁 1-可签 2-已签
    /// </summary>
    public int GetCheckInState(int gridDayNum)
    {
        var act = GetOperationHeroAppearInfo();
        if (act == null) return 0;
        int actType = act.ActType;
        if (GeneralActInfoManager.Instance.IsDaySigned(actType, actNum, gridDayNum)) return 2;
        if (IsCheckInGridUnlock(gridDayNum)) return 1;
        return 0;
    }
    public void SendGetCheckInReward()
    {
        var act = GetOperationHeroAppearInfo();
        if (act == null) return;
        int actType = act.ActType;
        GeneralActInfoManager.Instance.SendGetSignReward(actType, actNum);
    }
    public bool HasCheckInCanHave()
    {
        var act = GetOperationHeroAppearInfo();
        if (act == null) return false;
        var config = ActHeroAppearConfig.Get(act.CfgID);
        if (config == null) return false;
        int templateID = config.SignTempID;
        var list = ActSignAwardConfig.GetDayNumSortList(templateID);
        if (list == null) return false;
        for (int i = 0; i < list.Count; i++)
        {
            int dayNum = list[i];
            int state = GetCheckInState(dayNum);
            if (state == 1) return true;
        }
        return false;
    }
    #endregion
    #region 升星计划
    public bool IsSingleHero(OperationHeroAppearInfo act)
    {
        var appearConfig = ActHeroAppearConfig.Get(act.CfgID);
        return appearConfig?.ActHeroIDList?.Length == 1;
    }
    public bool IsLockStarHero(OperationHeroAppearInfo act)
    {
        // 如果只有一个可选武将,视为锁定
        if (IsSingleHero(act)) return true;
        if (!starFreeAwardDict.TryGetValue(starHeroIndex, out uint freeAward)) return false;
        //领取了任意一档免费奖励视为锁定
        if (freeAward > 0) return true;
        //购买了任意一档礼包视为锁定
        if (IsAnyStarGiftPurchased(act)) return true;
        return LoadStarUpLockState(act);
    }
    /// <summary>
    /// 检查是否购买了任意一档升星礼包
    /// </summary>
    private bool IsAnyStarGiftPurchased(OperationHeroAppearInfo act)
    {
        var appearConfig = ActHeroAppearConfig.Get(act.CfgID);
        if (appearConfig == null) return false;
        int starGiftTempID = appearConfig.StarGiftTempID;
        var list = ActHeroAppearStarConfig.GetHeroReturnAwardIndexSortList(starGiftTempID);
        if (list.IsNullOrEmpty()) return false;
        for (int i = 0; i < list.Count; i++)
        {
            var config = ActHeroAppearStarConfig.GetConfig(starGiftTempID, list[i]);
            if (config == null) continue;
            if (RechargeManager.Instance.TryGetRechargeCount(config.StarGiftCTGID, out var rechargeCount))
            {
                if (rechargeCount.totalCount > 0)
                {
                    return true;
                }
            }
        }
        return false;
    }
    private string GetStarUpChooseHeroStateKey(OperationHeroAppearInfo act)
    {
        if (act == null) return string.Empty;
        return string.Concat("HeroReturnManager_StarUpChooseHero_", act.CfgID, "_", ToInt(act.startDate), "_", ToInt(act.startDate), "_", PlayerDatas.Instance.PlayerId);
    }
    public bool LoadStarUpChooseHeroStateKey(OperationHeroAppearInfo act)
    {
        return LocalSave.GetBool(GetStarUpChooseHeroStateKey(act));
    }
    public void SaveStarUpChooseHeroStateKey(OperationHeroAppearInfo act)
    {
        LocalSave.SetBool(GetStarUpChooseHeroStateKey(act), true);
    }
    private string GetStarUpLockStateKey(OperationHeroAppearInfo act)
    {
        if (act == null) return string.Empty;
        return string.Concat("HeroReturnManager_StarUpLockState_", act.CfgID, "_", ToInt(act.startDate), "_", ToInt(act.startDate), "_", PlayerDatas.Instance.PlayerId);
    }
    public bool LoadStarUpLockState(OperationHeroAppearInfo act)
    {
        return LocalSave.GetBool(GetStarUpLockStateKey(act));
    }
    public void SaveStarUpLockState(OperationHeroAppearInfo act)
    {
        LocalSave.SetBool(GetStarUpLockStateKey(act), true);
    }
    /// <summary>
    /// 当前升星计划选中的武将ID
    /// </summary>
    public int GetCurrentDisplayStarUpHeroId()
    {
        var act = GetOperationHeroAppearInfo();
        if (act == null) return 0;
        var config = ActHeroAppearConfig.Get(act.CfgID);
        if (config == null || config.ActHeroIDList?.Length <= starHeroIndex) return 0;
        return config.ActHeroIDList[starHeroIndex];
    }
    private Dictionary<int, Dictionary<int, int[][]>> showHeroGiftItemInfoDict = new();
    public bool TryGetStarUpAwardArr(int id, int heroID, out int[][] arr)
    {
        arr = null;
        var config = ActHeroAppearStarConfig.Get(id);
        if (config == null) return false;
        var ctgConfig = CTGConfig.Get(config.StarGiftCTGID);
        if (ctgConfig == null) return false;
        if (!showHeroGiftItemInfoDict.TryGetValue(id, out var dict))
        {
            dict = new Dictionary<int, int[][]>();
            showHeroGiftItemInfoDict[id] = dict;
        }
        if (!dict.TryGetValue(heroID, out arr))
        {
            // 如果缓存里没有当前武将的数据,才进行解析
            var giftdict = ConfigParse.ParseIntArray2Dict(config.HeroGiftItemInfo);
            int[][] ctgArray = ctgConfig.GainItemList;
            foreach (var kvp in giftdict)
            {
                int hId = kvp.Key;
                int[][] hGift = kvp.Value ?? Array.Empty<int[]>();
                dict[hId] = hGift.Concat(ctgArray).ToArray();
            }
            // 如果遍历完发现配表里根本没有这个 heroID
            if (!dict.TryGetValue(heroID, out arr))
            {
                arr = ctgArray;
                dict[heroID] = arr;
            }
        }
        return true;
    }
    /// <summary>
    /// 0 - 未解锁 1 - 可领取 2 - 已领取
    /// </summary>
    public int GetStarUpFreeState(int id)
    {
        var config = ActHeroAppearStarConfig.Get(id);
        if (config == null) return 0;
        int heroId = GetCurrentDisplayStarUpHeroId();
        var heroConfig = HeroConfig.Get(heroId);
        if (heroConfig == null) return 0;
        // 没锁定的武将视为未解锁
        if (!IsLockStarHero(GetOperationHeroAppearInfo())) return 0;
        // 没获得武将本体不可领取
        if (!HeroManager.Instance.HasHero(heroId)) return 0;
        if (IsStarUpFreeHave(starHeroIndex, config.AwardIndex)) return 2;
        if (IsHeroStarCntOk(heroConfig.HeroID, config.NeedStar)) return 1;
        return 0;
    }
    private bool IsStarUpFreeHave(int starHeroIndex, int awardIndex)
    {
        if (!starFreeAwardDict.TryGetValue(starHeroIndex, out uint freeAward)) return false;
        return ((freeAward >> awardIndex) & 1u) == 1u;
    }
    public bool IsHeroStarCntOk(int heroId, int needStar)
    {
        return GetNowHeroMaxStarCnt(heroId) >= needStar;
    }
    public int GetNowHeroMaxStarCnt(int heroId)
    {
        int res = 0;
        foreach (var item in HeroManager.Instance.GetHeroList())
        {
            if (item == null) continue;
            if (item.heroId == heroId)
            {
                if (res < item.heroStar)
                    res = item.heroStar;
            }
        }
        return res;
    }
    public bool TryGetStarUpStateIndex(int starGiftTempID, int tarState, out int index)
    {
        index = 0;
        var list = ActHeroAppearStarConfig.GetHeroReturnAwardIndexSortList(starGiftTempID);
        if (list == null) return false;
        for (int i = 0; i < list.Count; i++)
        {
            var awardIndex = list[i];
            var config = ActHeroAppearStarConfig.GetConfig(starGiftTempID, awardIndex);
            if (config == null) continue;
            int state = GetStarUpFreeState(config.ID);
            if (state == tarState)
            {
                index = i;
                return true;
            }
        }
        return false;
    }
    public int GetStarUpJumpIndex(int starGiftTempID)
    {
        // 优先查找可领取的奖励
        if (TryGetStarUpStateIndex(starGiftTempID, 1, out int index)) return index;
        // 若没有可领取的,则查找未达到条件的奖励
        if (TryGetStarUpStateIndex(starGiftTempID, 0, out index)) return index;
        // 都没有
        return 0;
    }
    public bool HasStarUpCanHave()
    {
        var act = GetOperationHeroAppearInfo();
        if (act == null) return false;
        var config = ActHeroAppearConfig.Get(act.CfgID);
        if (config == null) return false;
        int starGiftTempID = config.StarGiftTempID;
        return TryGetStarUpStateIndex(starGiftTempID, 1, out _);
    }
    #endregion
    #region 兑换商店
    private string ShopVisitTimeDataKey { get { return $"HeroReturnManager_ShopVisitTime_{PlayerDatas.Instance.PlayerId}"; } }
    private int LoadShopVisitTimeData()
    {
        return LocalSave.GetInt(ShopVisitTimeDataKey);
    }
    public void SaveShopVisitTimeData()
    {
        LocalSave.SetInt(ShopVisitTimeDataKey, TimeUtility.AllSeconds);
    }
    public bool IsShopVisitedToday
    {
        get
        {
            int lastVisitTime = LoadShopVisitTimeData();
            int todayStartTime = TimeUtility.GetTodayStartTick();
            return lastVisitTime >= todayStartTime;
        }
    }
    #endregion
    #region 皇权礼包
    //没售罄
    public bool IsCanBuyToday(int ctgID)
    {
        CTGConfig config = CTGConfig.Get(ctgID);
        if (config == null) return false;
        if (!RechargeManager.Instance.TryGetRechargeCount(ctgID, out var rechargeCount)) return false;
        if (config.DailyBuyCount == 0) return true;
        return rechargeCount.todayCount < config.DailyBuyCount;
    }
    public bool IsNoSellOutCTGID(int ctgID)
    {
        CTGConfig config = CTGConfig.Get(ctgID);
        if (config == null) return false;
        if (!RechargeManager.Instance.TryGetRechargeCount(ctgID, out var rechargeCount)) return false;
        return rechargeCount.totalCount < config.TotalBuyCount;
    }
    // 免费商品
    public bool IsFreeShop(int shopID)
    {
        StoreConfig config = StoreConfig.Get(shopID);
        if (config == null) return false;
        return config.MoneyNum == 0;
    }
    //没售罄
    public bool IsNoSellOutShopID(int shopID)
    {
        StoreConfig config = StoreConfig.Get(shopID);
        if (config == null) return false;
        StoreModel.Instance.TryGetIsSellOut(config, out int remainNum);
        return remainNum > 0;
    }
    public List<HeroReturnGiftItem> GetGiftItemList(bool isSort = false)
    {
        var act = GetOperationHeroAppearInfo();
        if (act == null) return null;
        var config = ActHeroAppearConfig.Get(act.CfgID);
        if (config == null) return null;
        List<HeroReturnGiftItem> res = new List<HeroReturnGiftItem>();
        var list = StoreModel.Instance.storeTypeDict[config.GiftShopType];
        if (!list.IsNullOrEmpty())
        {
            for (int i = 0; i < list.Count; i++)
            {
                var item = list[i];
                if (item.storeConfig == null)
                    continue;
                res.Add(new HeroReturnGiftItem
                {
                    type = 0,
                    id = item.storeConfig.ID,
                });
            }
        }
        if (config.GiftCTGIDList != null)
        {
            for (int i = 0; i < config.GiftCTGIDList.Length; i++)
            {
                var item = config.GiftCTGIDList[i];
                res.Add(new HeroReturnGiftItem
                {
                    type = 1,
                    id = item,
                });
            }
        }
        if (isSort)
        {
            res = res.OrderBy(item =>
            {
                bool isCanBuy = item.type == 0 ? IsNoSellOutShopID(item.id) : IsCanBuyToday(item.id);
                return !isCanBuy;
            })
            .ThenBy(item => item.type)
            .ThenBy(item => item.id)
            .ToList();
        }
        return res;
    }
    public bool HasGiftCanHave()
    {
        var list = GetGiftItemList(false);
        if (list.IsNullOrEmpty())
            return false;
        for (int i = 0; i < list.Count; i++)
        {
            var item = list[i];
            if (item.type == 0)
            {
                bool isFree = IsFreeShop(item.id);
                bool isCanBuy = IsNoSellOutShopID(item.id);
                if (isFree && isCanBuy)
                    return true;
            }
        }
        return false;
    }
    #endregion
    #region 招募
    public int ToInt(OperationDate date)
    {
        return date.year * 10000 + date.month * 100 + date.day;
    }
    private string GetCallSkipKey(int cfgID, OperationDate startDate, OperationDate endDate)
    {
        return string.Concat("HeroReturnManager_CallSkip_", cfgID, "_", ToInt(startDate), "_", ToInt(endDate), "_", PlayerDatas.Instance.PlayerId);
    }
    public bool LoadCallSkipData(int cfgID, OperationDate startDate, OperationDate endDate)
    {
        return LocalSave.GetBool(GetCallSkipKey(cfgID, startDate, endDate));
    }
    public void SaveCallSkipData(int cfgID, OperationDate startDate, OperationDate endDate, bool value)
    {
        LocalSave.SetBool(GetCallSkipKey(cfgID, startDate, endDate), value);
    }
    /// <summary>
    /// 当前招募选中的武将ID
    /// </summary>
    public int GetCurrentDisplayCallHeroId()
    {
        var act = GetOperationHeroAppearInfo();
        if (act == null) return 0;
        var config = ActHeroAppearConfig.Get(act.CfgID);
        if (config == null || config.ActHeroIDList?.Length <= callHeroIndex) return 0;
        return config.ActHeroIDList[callHeroIndex];
    }
    public int GetFirstHeroId()
    {
        var act = GetOperationHeroAppearInfo();
        if (act == null) return 0;
        var config = ActHeroAppearConfig.Get(act.CfgID);
        if (config == null || config.ActHeroIDList.IsNullOrEmpty()) return 0;
        return config.ActHeroIDList.First();
    }
    private string GetCallChooseHeroStateKey(OperationHeroAppearInfo act)
    {
        if (act == null) return string.Empty;
        return string.Concat("HeroReturnManager_CallChooseHero_", act.CfgID, "_", ToInt(act.startDate), "_", ToInt(act.startDate), "_", PlayerDatas.Instance.PlayerId);
    }
    public bool LoadCallChooseHeroStateKey(OperationHeroAppearInfo act)
    {
        return LocalSave.GetBool(GetCallChooseHeroStateKey(act));
    }
    public void SaveCallChooseHeroStateKey(OperationHeroAppearInfo act)
    {
        LocalSave.SetBool(GetCallChooseHeroStateKey(act), true);
    }
    #endregion
    #region 时装特卖
    public event Action OnCurrentChooseSkinIDChangeEevent;
    private int m_currentChooseSkinID = 0;
    public int currentChooseSkinID
    {
        get
        {
            return m_currentChooseSkinID;
        }
        set
        {
            if (m_currentChooseSkinID == value) return;
            m_currentChooseSkinID = value;
            OnCurrentChooseSkinIDChangeEevent?.Invoke();
        }
    }
    /// <summary>
    /// 通过skinID获取对应的heroID
    /// </summary>
    public int GetHeroIDBySkinID(int skinID)
    {
        foreach (var heroConfig in HeroConfig.GetValues())
        {
            if (heroConfig.SkinIDList != null && heroConfig.SkinIDList.Contains(skinID))
            {
                return heroConfig.HeroID;
            }
        }
        return 0;
    }
    /// <summary>
    /// 获取skinID在HeroConfig.SkinIDList中的索引
    /// </summary>
    public int GetSkinIndexInHeroConfig(int heroID, int skinID)
    {
        var heroConfig = HeroConfig.Get(heroID);
        if (heroConfig?.SkinIDList == null) return int.MaxValue;
        for (int i = 0; i < heroConfig.SkinIDList.Length; i++)
        {
            if (heroConfig.SkinIDList[i] == skinID)
                return i;
        }
        return int.MaxValue;
    }
    //<skinID,ctgID>
    Dictionary<int, int> ctgDict = new();
    public int GetCtgIDBySkinID(int skinID)
    {
        if (ctgDict.IsNullOrEmpty())
        {
            GetSkinIDToCtgIDDict();
        }
        int ctgID;
        ctgDict.TryGetValue(skinID, out ctgID);
        return ctgID;
    }
    Dictionary<int, int> GetSkinIDToCtgIDDict()
    {
        if (!ctgDict.IsNullOrEmpty())
        {
            return ctgDict;
        }
        foreach (var config in ActHeroAppearConfig.GetValues())
        {
            if (config == null || config.SkinCTGIDList == null) return null;
            for (int i = 0; i < config.SkinCTGIDList.Length; i++)
            {
                var ctgID = config.SkinCTGIDList[i];
                var ctgConfig = CTGConfig.Get(ctgID);
                if (ctgConfig == null || ctgConfig.GainItemList == null) continue;
                for (int j = 0; j < ctgConfig.GainItemList.Length; j++)
                {
                    var itemID = ctgConfig.GainItemList[j][0];
                    var itemConfig = ItemConfig.Get(itemID);
                    if (itemConfig == null) continue;
                    if (!HeroSkinAttrConfig.TryGetSkinIDByItemID(itemID, out var skinID)) continue;
                    if (ctgDict.ContainsKey(skinID)) continue;
                    ctgDict[skinID] = ctgID;
                }
            }
        }
        return ctgDict;
    }
    public bool HasItemInSkinCTGIDList(int cfgID, int findItemID)
    {
        var config = ActHeroAppearConfig.Get(cfgID);
        if (config == null || config.SkinCTGIDList == null) return false;
        for (int i = 0; i < config.SkinCTGIDList.Length; i++)
        {
            var ctgID = config.SkinCTGIDList[i];
            var ctgConfig = CTGConfig.Get(ctgID);
            if (ctgConfig == null || ctgConfig.GainItemList == null) continue;
            for (int j = 0; j < ctgConfig.GainItemList.Length; j++)
            {
                var itemID = ctgConfig.GainItemList[j][0];
                if (itemID == findItemID) return true;
            }
        }
        return false;
    }
    public List<int> GetSkinIDList(int cfgID, int heroID, int mainSkinID)
    {
        var config = ActHeroAppearConfig.Get(cfgID);
        if (config == null || config.SkinCTGIDList == null) return null;
        var res = new List<int>();
        for (int i = 0; i < config.SkinCTGIDList.Length; i++)
        {
            var ctgID = config.SkinCTGIDList[i];
            var ctgConfig = CTGConfig.Get(ctgID);
            if (ctgConfig == null || ctgConfig.GainItemList == null) continue;
            for (int j = 0; j < ctgConfig.GainItemList.Length; j++)
            {
                var itemID = ctgConfig.GainItemList[j][0];
                var itemConfig = ItemConfig.Get(itemID);
                if (itemConfig == null) continue;
                if (!HeroSkinAttrConfig.TryGetSkinIDByItemID(itemID, out var skinID)) continue;
                if (res.Contains(skinID)) continue;
                res.Add(skinID);
            }
        }
        // 自定义排序
        res.Sort((a, b) =>
        {
            // 1. 判断是否是传入heroID的皮肤,优先排前面
            int heroIDA = GetHeroIDBySkinID(a);
            int heroIDB = GetHeroIDBySkinID(b);
            bool isPriorityA = (heroIDA == heroID);
            bool isPriorityB = (heroIDB == heroID);
            if (isPriorityA != isPriorityB)
                return isPriorityA ? -1 : 1;
            // 2. 相同武将的多个皮肤连续挨在一起
            if (heroIDA != heroIDB)
                return heroIDA.CompareTo(heroIDB);
            // 3. 如果heroid相同,和MainSkinID相同的排在最前面
            if (a == mainSkinID) return -1;
            if (b == mainSkinID) return 1;
            // 4. 其他按SkinIDList索引排序
            int indexA = GetSkinIndexInHeroConfig(heroIDA, a);
            int indexB = GetSkinIndexInHeroConfig(heroIDB, b);
            return indexA.CompareTo(indexB);
        });
        return res;
    }
    #endregion
    #region 获奖记录
    public static readonly int RecordType = 311;
    public void SendViewGameRecPack(int treasureType)
    {
        CA008_tagCSViewGameRec pack = new CA008_tagCSViewGameRec();
        pack.RecType = (ushort)RecordType;
        pack.RecID = (uint)treasureType;
        GameNetSystem.Instance.SendInfo(pack);
    }
    public bool isSendFirst = true;
    List<HeroReturnGameRec> gameRecDict = new();
    public List<HeroReturnGameRec> GetGameRecList()
    {
        return gameRecDict;
    }
    public event Action OnUpdateGameRecInfo;
    public void UpdateGameRecInfo(HA009_tagSCGameRecInfo vNetData)
    {
        var act = GetOperationHeroAppearInfo();
        if (act == null) return;
        var config = ActHeroAppearConfig.Get(act.CfgID);
        if (config == null) return;
        int treasureType = config.ActTreasureType;
        if (vNetData.RecType != RecordType || treasureType != (int)vNetData.RecID) return;
        if (vNetData.RecList.IsNullOrEmpty()) return;
        if (isSendFirst)
        {
            gameRecDict.Clear();
        }
        foreach (var rec in vNetData.RecList)
        {
            try
            {
                var playerName = JsonMapper.ToObject(rec.UserData)["Name"].ToString();
                var arenaGameRec = new HeroReturnGameRec
                {
                    Time = (int)rec.Time,
                    ItemID = (int)rec.Value1,
                    ItemCount = rec.Value2,
                    PlayerID = (int)rec.Value3,
                    ServerID = (int)rec.Value4,
                    PlayerName = playerName,
                };
                gameRecDict.Add(arenaGameRec);
            }
            catch (Exception ex)
            {
                Debug.LogError($"JSON解析错误: {ex.Message}, UserData: {rec.UserData}");
                continue;
            }
        }
        if (isSendFirst)
        {
            isSendFirst = !isSendFirst;
            gameRecDict.Sort((x, y) => x.Time.CompareTo(y.Time));
        }
        OnUpdateGameRecInfo?.Invoke();
    }
    #endregion
}
public class HeroReturnGiftItem
{
    public int type;//0 商店id 1 充值id
    public int id;
}
public enum HeroReturnRedPointType
{
    CheckIn = 1,
    StarUp = 2,
    Shop = 3,
    Gift = 4,
}
public class HeroReturnGameRec
{
    public int Time;
    public int ItemID;
    public long ItemCount;
    public int PlayerID;
    public int ServerID;
    public string PlayerName;
}
Main/System/HeroReturn/HeroReturnManager.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: b509add974a70944ea78b2739e505c32
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnPopWin.cs
New file
@@ -0,0 +1,96 @@
using UnityEngine;
using UnityEngine.UI;
public class HeroReturnPopWin : UIBase
{
    [SerializeField] ImageEx bgImage;
    [SerializeField] UIHeroController rolelhShow;
    [SerializeField] ImageEx qaulityBgImage;
    [SerializeField] ImageEx qaulityImage;
    [SerializeField] ButtonEx goButton;
    [SerializeField] ImageEx titleBgImage;
    [SerializeField] ImageEx titleImage;
    [SerializeField] ImageEx infoBgImage;
    [SerializeField] UIEffectPlayer uiEffectPlayer;
    [SerializeField] TextEx infoText;
    [SerializeField] TextEx timeText;
    [SerializeField] Toggle todayPopToggle;
    [SerializeField] ButtonEx closeButton;
    HeroReturnManager manager => HeroReturnManager.Instance;
    protected override void InitComponent()
    {
        closeButton.SetListener(CloseWindow);
        goButton.SetListener(() =>
        {
            UIManager.Instance.CloseWindow<HeroReturnPopWin>();
            if (!UIManager.Instance.IsOpened<HeroReturnWin>())
                UIManager.Instance.OpenWindow<HeroReturnWin>();
        });
        todayPopToggle.AddListener((bool value) =>
        {
            if (value)
                manager.SavePopTimeData();
        });
    }
    protected override void OnPreOpen()
    {
        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
        Display();
    }
    protected override void OnPreClose()
    {
        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
    }
    private void OnSecondEvent()
    {
        manager.GetActTimeStr(timeText, "HeroDebutPop02");
    }
    private void Display()
    {
        uiEffectPlayer.Stop();
        todayPopToggle.isOn = !manager.IsTodayPop;
        int heroID = manager.GetFirstHeroId();
        var artConfig = ActHeroReturnArtConfig.Get(heroID);
        if (artConfig == null) return;
        var heroConfig = HeroConfig.Get(heroID);
        if (heroConfig == null) return;
        int skinID = manager.GetDefaultSkinID(heroID);
        var skinConfig = HeroSkinConfig.Get(skinID);
        if (skinConfig == null) return;
        uiEffectPlayer.effectId = artConfig.PopInfoBgUIEffectId;
        uiEffectPlayer.Play();
        bgImage.SetSprite(artConfig.PopBgImage);
        bgImage.SetNativeSize();
        qaulityBgImage.SetSprite($"HeroDebutPopQaulityBG{heroConfig.Quality}");
        qaulityBgImage.SetNativeSize();
        qaulityImage.SetSprite($"HeroDebutPopQaulity{heroConfig.Quality}");
        qaulityImage.SetNativeSize();
        titleBgImage.SetSprite(artConfig.PopTitleBgImage);
        titleBgImage.SetNativeSize();
        titleImage.SetSprite(artConfig.PopTitleImage);
        titleImage.SetNativeSize();
        infoBgImage.SetSprite(artConfig.PopInfoBgImage);
        infoBgImage.SetNativeSize();
        infoText.text = artConfig.PopInfoText;
        infoText.color = manager.ParseColor32(artConfig.PopInfoColor);
        rolelhShow.Create(skinID, 1, motionName: "", isLh: true);
        OnSecondEvent();
    }
}
Main/System/HeroReturn/HeroReturnPopWin.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 2ec133afd45ed6548bf892a3179cba58
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnRankAwardCell.cs
New file
@@ -0,0 +1,45 @@
using UnityEngine;
public class HeroReturnRankAwardCell : CellView
{
    [SerializeField] ImageEx imgRank;
    [SerializeField] TextEx txtRank;
    [SerializeField] ItemCell[] itemCells;
    public void Display(int rankA, int templateID)
    {
        var config = ActBillboardAwardConfig.GetConfig(templateID, rankA);
        if (config == null) return;
        if (rankA <= 3)
        {
            imgRank.SetActive(true);
            txtRank.SetActive(false);
            imgRank.SetSprite(StringUtility.Concat("Rank", rankA.ToString()));
            txtRank.text = rankA.ToString();
        }
        else
        {
            imgRank.SetActive(false);
            txtRank.SetActive(true);
            txtRank.text = Language.Get("Arena15", rankA, config.RankB);
        }
        int[][] rewardArr = config.AwardItemList;
        for (int i = 0; i < itemCells.Length; i++)
        {
            var itemCell = itemCells[i];
            if (!rewardArr.IsNullOrEmpty() && i < rewardArr.Length)
            {
                int itemCellIndex = i;
                itemCell.SetActive(true);
                itemCell.Init(new ItemCellModel(rewardArr[i][0], true, rewardArr[i][1]));
                itemCell.button.SetListener(() => ItemTipUtility.Show(rewardArr[itemCellIndex][0], true));
            }
            else
            {
                itemCell.SetActive(false);
            }
        }
    }
}
Main/System/HeroReturn/HeroReturnRankAwardCell.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 31c2c107b8558ce4db4c8208a7019236
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnRankCell.cs
New file
@@ -0,0 +1,76 @@
using UnityEngine;
using UnityEngine.UI;
public class HeroReturnRankCell : MonoBehaviour
{
    [SerializeField] AvatarCell avatarCell;
    [SerializeField] Text rankText;
    [SerializeField] Text rankValueText;    //排名比较内容
    [SerializeField] Text nameText;
    [SerializeField] OfficialTitleCell officialTitleCell;
    [SerializeField] Button queryPlayerBtn; //后续添加点击查看玩家详情
    HeroReturnManager manager => HeroReturnManager.Instance;
    // rank 为0 代表玩家自己
    public void Display(int rankType, int rank, string valueFormat)
    {
        var act = manager.GetOperationHeroAppearInfo();
        if (act == null) return;
        var config = ActHeroAppearConfig.Get(act.CfgID);
        if (config == null) return;
        int billTempID = config.BillTempID;
        var awardConfig = ActBillboardAwardConfig.GetConfig(billTempID, rank);
        RankData rankData = null;
        int viewPlayerId = (int)PlayerDatas.Instance.baseData.PlayerID;
        if (rank != 0)
        {
            rankData = RankModel.Instance.GetRankDataByRank(rankType, rank);
        }
        else
        {
            rankData = RankModel.Instance.GetMyRank(rankType);
            if (rankData == null)
            {
                //取玩家自己的数据
                avatarCell.InitUI(AvatarHelper.GetAvatarModel((int)PlayerDatas.Instance.baseData.PlayerID,
                                                PlayerDatas.Instance.baseData.face,
                                                PlayerDatas.Instance.baseData.facePic));
                rankText.text = Language.Get("L1045");
                rankValueText.text = awardConfig == null || awardConfig.NeedValue == 0 ? "0" : Language.Get("HeroDebut27", awardConfig.NeedValue);
                nameText.text = PlayerDatas.Instance.baseData.PlayerName;
                officialTitleCell.InitUI(PlayerDatas.Instance.baseData.realmLevel, PlayerDatas.Instance.baseData.TitleID);
                return;
            }
            rank = rankData.rank;
        }
        if (rankData == null)
        {
            officialTitleCell.SetActive(false);
            avatarCell.SetActive(false);
            nameText.text = Language.Get("L1124");
            rankValueText.text = awardConfig == null || awardConfig.NeedValue == 0 ? "0" : Language.Get("HeroDebut27", awardConfig.NeedValue);
        }
        else
        {
            officialTitleCell.SetActive(true);
            officialTitleCell.InitUI((int)rankData.value1, (int)rankData.value2);
            avatarCell.SetActive(true);
            avatarCell.InitUI(AvatarHelper.GetAvatarModel((int)rankData.id, (int)rankData.value3, (int)rankData.value4));
            viewPlayerId = (int)rankData.id;
            nameText.text = rankData.name1;
            rankValueText.text = string.Format(valueFormat, UIHelper.ReplaceLargeNum(rankData.cmpValue));
        }
        rankText.text = rank.ToString();
        if (queryPlayerBtn != null)
        {
            queryPlayerBtn.AddListener(() =>
            {
                AvatarHelper.TryViewOtherPlayerInfo(viewPlayerId);
            });
        }
    }
}
Main/System/HeroReturn/HeroReturnRankCell.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a9a73b5eecf896f46a562a01b9102ba6
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnRankTop3Cell.cs
New file
@@ -0,0 +1,47 @@
using UnityEngine;
using UnityEngine.UI;
public class HeroReturnRankTop3Cell : MonoBehaviour
{
    //[SerializeField] Model 显示NPC 武将模型
    [SerializeField] Text rankValueText;    //排名比较内容
    [SerializeField] Text nameText;
    [SerializeField] OfficialTitleCell officialTitleCell;
    [SerializeField] Button queryPlayerBtn; //后续添加点击查看玩家详情
    [SerializeField] HorseController model;
    HeroReturnManager manager => HeroReturnManager.Instance;
    public void Display(int rankType, int rank, string valueFormat = "{0}")
    {
        var act = manager.GetOperationHeroAppearInfo();
        if (act == null) return;
        var config = ActHeroAppearConfig.Get(act.CfgID);
        if (config == null) return;
        int billTempID = config.BillTempID;
        var awardConfig = ActBillboardAwardConfig.GetConfig(billTempID, rank);
        var rankData = RankModel.Instance.GetRankDataByRank(rankType, rank);
        if (rankData == null)
        {
            rankValueText.text = awardConfig == null || awardConfig.NeedValue == 0 ? "0" : Language.Get("HeroDebut40", awardConfig.NeedValue);
            nameText.text = Language.Get("L1124");
            officialTitleCell.SetActive(false);
            model.SetActive(false);
            return;
        }
        officialTitleCell.SetActive(true);
        rankValueText.text = string.Format(valueFormat, UIHelper.ReplaceLargeNum(rankData.cmpValue));
        nameText.text = rankData.name1;
        officialTitleCell.InitUI((int)rankData.value1, (int)rankData.value2);
        model.SetActive(true);
        model.Create(HorseManager.Instance.GetOtherPlayerHorseSkinID((int)rankData.value6), (int)rankData.value5, rank == 1 ? 1f : 0.8f);
        queryPlayerBtn.SetListener(() =>
        {
            AvatarHelper.TryViewOtherPlayerInfo((int)rankData.id);
        });
    }
}
Main/System/HeroReturn/HeroReturnRankTop3Cell.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: e3f3dcdd709d3ab4e918517695fb715a
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnRankWin.cs
New file
@@ -0,0 +1,175 @@
using System.Collections.Generic;
using UnityEngine;
public class HeroReturnRankWin : FunctionsBaseWin
{
    [SerializeField] ButtonEx btnClose;
    [SerializeField] RectTransform rankRect;
    [SerializeField] RectTransform awardRect;
    [SerializeField] TextEx timeText;
    [Header("排行")]
    [SerializeField] ScrollerController rankScroller;
    [SerializeField] List<HeroReturnRankTop3Cell> playerTop3Cells;
    [SerializeField] HeroReturnRankCell myRankCell;
    [HideInInspector] public string valueFormat = "{0}";
    [Header("奖励")]
    // [SerializeField] TextEx txtCountdown;
    [SerializeField] ScrollerController awardScroller;
    [SerializeField] ImageEx heroImage;
    [SerializeField] TextEx myRankNumText;
    [SerializeField] TextEx myCallCntText;
    [SerializeField] TextEx timeText1;
    HeroReturnManager manager => HeroReturnManager.Instance;
    protected override void InitComponent()
    {
        base.InitComponent();
        btnClose.SetListener(CloseWindow);
    }
    protected override void OnPreOpen()
    {
        base.OnPreOpen();
        RankModel.Instance.ResetQueryParam();
        RankModel.Instance.QueryRankByPage(manager.sendRankType, watchID: (int)PlayerDatas.Instance.baseData.PlayerID, groupValue1: manager.actNum);
        RankModel.Instance.onRankRefresh += OnRankRefresh;
        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
        rankScroller.OnRefreshCell += OnRefreshCell;
        awardScroller.OnRefreshCell += OnRefreshAwardCell;
        Display();
    }
    protected override void OnPreClose()
    {
        base.OnPreClose();
        RankModel.Instance.onRankRefresh -= OnRankRefresh;
        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
        rankScroller.OnRefreshCell -= OnRefreshCell;
        awardScroller.OnRefreshCell -= OnRefreshAwardCell;
    }
    void OnRankRefresh(int type)
    {
        RankRefresh();
    }
    void RankRefresh()
    {
        ShowTop3();
        rankScroller.m_Scorller.RefreshActiveCellViews();
        DisplayMyRank();
        DisplayAwardMyRank();
    }
    void CreateRankScroller()
    {
        rankScroller.Refresh();
        var cnt = RankModel.Instance.GetRankShowMaxCnt(manager.sendRankType);
        for (int i = 3; i < cnt; i++)
        {
            rankScroller.AddCell(ScrollerDataType.Header, i);
        }
        rankScroller.Restart();
    }
    void OnRefreshCell(ScrollerDataType type, CellView cell)
    {
        var _cell = cell.GetComponent<HeroReturnRankCell>();
        _cell.Display(manager.loadRankType, cell.index + 1, valueFormat);
        RankModel.Instance.ListenRankPage(manager.sendRankType, cell.index, groupValue1: manager.actNum);
    }
    private void OnSecondEvent()
    {
        manager.GetActTimeStr(timeText);
        manager.GetActTimeStr(timeText1);
    }
    protected override void OpenSubUIByTabIndex()
    {
        rankRect.SetActive(functionOrder == 0);
        awardRect.SetActive(functionOrder == 1);
        Display();
    }
    public void Display()
    {
        int heroID = manager.GetFirstHeroId();
        var artConfig = ActHeroReturnArtConfig.Get(heroID);
        if (artConfig == null) return;
        if (functionOrder == 0)
        {
            ShowTop3();
            CreateRankScroller();
            DisplayMyRank();
        }
        else
        {
            CreateAwardScroller();
            heroImage.SetSprite(artConfig.RankAwardHeroImage);
            heroImage.SetNativeSize();
            DisplayAwardMyRank();
        }
        OnSecondEvent();
    }
    private void DisplayMyRank()
    {
        myRankCell.Display(manager.loadRankType, 0, valueFormat);
    }
    void ShowTop3()
    {
        for (int i = 0; i < playerTop3Cells.Count; i++)
        {
            playerTop3Cells[i].Display(manager.loadRankType, i + 1);
        }
    }
    void DisplayAwardMyRank()
    {
        RankData rankData = RankModel.Instance.GetMyRank(manager.loadRankType);
        if (rankData == null)
        {
            myRankNumText.text = Language.Get("L1045");
            myCallCntText.text = "0";
            return;
        }
        myRankNumText.text = Language.Get("WarlordPavilion12", rankData.rank);
        myCallCntText.text = string.Format(valueFormat, UIHelper.ReplaceLargeNum(rankData.cmpValue));
    }
    int billTempID;
    private void CreateAwardScroller()
    {
        var act = manager.GetOperationHeroAppearInfo();
        if (act == null) return;
        var config = ActHeroAppearConfig.Get(act.CfgID);
        if (config == null) return;
        billTempID = config.BillTempID;
        var list = ActBillboardAwardConfig.GetRankASortList(billTempID);
        if (list == null) return;
        awardScroller.Refresh();
        for (int i = 0; i < list.Count; i++)
        {
            awardScroller.AddCell(ScrollerDataType.Header, list[i]);
        }
        awardScroller.Restart();
    }
    private void OnRefreshAwardCell(ScrollerDataType type, CellView cell)
    {
        var _cell = cell.GetComponent<HeroReturnRankAwardCell>();
        _cell?.Display(cell.index, billTempID);
    }
}
Main/System/HeroReturn/HeroReturnRankWin.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 564897474a653594fbb6f294779e17c1
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnShopCell.cs
New file
@@ -0,0 +1,134 @@
using UnityEngine;
using UnityEngine.UI;
public class HeroReturnShopCell : MonoBehaviour
{
    [SerializeField] Transform saleRect;
    [SerializeField] Text saleText;
    [SerializeField] Text itemName;
    [SerializeField] ItemCell itemCell;
    [SerializeField] Text limitText;
    [SerializeField] Text lockTip;
    [SerializeField] Transform priceRect;
    [SerializeField] Image priceIcon;
    [SerializeField] Text priceText;
    [SerializeField] Transform priceRect1;//居中位置的价格
    [SerializeField] Image priceIcon1;
    [SerializeField] Text priceText1;
    [SerializeField] Transform salePriceRect;
    [SerializeField] Text salePriceText;
    [SerializeField] Button buyButton;
    [SerializeField] Image freeRedPoint;
    [SerializeField] Text freeText;
    [SerializeField] Image exclusiveImage;//专属
    [SerializeField] Image sellOutImage;//售罄
    HeroReturnManager manager => HeroReturnManager.Instance;
    public void Display(int index)
    {
        var act = manager.GetOperationHeroAppearInfo();
        if (act == null) return;
        var config = ActHeroAppearConfig.Get(act.CfgID);
        if (config == null) return;
        if (!StoreModel.Instance.storeTypeDict.TryGetValue(config.ExShopType, out var list)) return;
        var storeData = list[index];
        int shopID = storeData.shopId;
        var itemID = storeData.storeConfig.ItemID;
        var itemCount = storeData.storeConfig.ItemCnt;
        exclusiveImage.SetActive(storeData.storeConfig.IsExclusive == 1);
        itemCell.Init(new ItemCellModel(itemID, false, itemCount));
        itemCell.button.AddListener(() =>
        {
            ItemTipUtility.Show(itemID);
        });
        var itemConfig = ItemConfig.Get(itemID);
        itemName.text = itemConfig.ItemName;
        //折扣
        if (storeData.storeConfig.MoneyOriginal != 0)
        {
            saleRect.SetActive(true);
            saleText.text = Language.Get("storename5", (storeData.storeConfig.MoneyNum * 10 / (float)storeData.storeConfig.MoneyOriginal).ToString("0.#"));
        }
        else
        {
            saleRect.SetActive(false);
        }
        var buyCnt = StoreModel.Instance.GetShopLimitBuyCount(shopID);
        string limitStr = "";
        if (storeData.storeConfig.MoneyNum == 0)
        {
            //免费
            limitStr = "";
        }
        else if (storeData.storeConfig.ResetType == 0)
        {
            //限购
            limitStr = storeData.storeConfig.LimitCnt > 0 ? Language.Get("storename8", storeData.storeConfig.LimitCnt - buyCnt, storeData.storeConfig.LimitCnt) : "";
        }
        else if (storeData.storeConfig.ResetType == 1)
        {
            //每日限购
            limitStr = Language.Get("storename6", storeData.storeConfig.LimitCnt - buyCnt, storeData.storeConfig.LimitCnt);
        }
        else if (storeData.storeConfig.ResetType == 2)
        {
            //每周限购
            limitStr = Language.Get("storename7", storeData.storeConfig.LimitCnt - buyCnt, storeData.storeConfig.LimitCnt);
        }
        limitText.text = buyCnt >= storeData.storeConfig.LimitCnt ? UIHelper.AppendColor(TextColType.Gray, limitStr) : limitStr;
        buyButton.AddListener(() => { BuyGoods(shopID); });
        //0可购买 1已售罄 2免费 3未解锁
        var state = StoreModel.Instance.GetShopIDState(shopID);
        sellOutImage.SetActive(state == 1);
        freeRedPoint.SetActive(state == 2);
        lockTip.text = state == 2 ? Language.Get("storename10", storeData.storeConfig.UnlockValue) : string.Empty;
        priceRect.SetActive(state != 2 && storeData.storeConfig.MoneyOriginal != 0);
        priceRect1.SetActive(state != 2 && storeData.storeConfig.MoneyOriginal == 0);
        freeText.SetActive(state == 2);
        salePriceRect.SetActive(state != 2 && storeData.storeConfig.MoneyOriginal != 0);
        priceText.text = storeData.storeConfig.MoneyNum.ToString();
        priceText1.text = storeData.storeConfig.MoneyNum.ToString();
        if (storeData.storeConfig.MoneyType <= 0)
        {
            priceIcon.SetItemSprite(storeData.storeConfig.CostItemID);
            priceIcon1.SetItemSprite(storeData.storeConfig.CostItemID);
        }
        else
        {
            priceIcon.SetIconWithMoneyType(storeData.storeConfig.MoneyType);
            priceIcon1.SetIconWithMoneyType(storeData.storeConfig.MoneyType);
        }
        salePriceText.text = storeData.storeConfig.MoneyOriginal.ToString();
    }
    void BuyGoods(int shopID)
    {
        var state = StoreModel.Instance.GetShopIDState(shopID);
        if (state == 1) return;
        if (state == 2)
        {
            StoreModel.Instance.SendBuyShopItem(StoreConfig.Get(shopID), 1);
        }
        else
        {
            StoreModel.Instance.buyShopID = shopID;
            UIManager.Instance.OpenWindow<BuyItemWin>();
        }
    }
}
Main/System/HeroReturn/HeroReturnShopCell.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 9f3fa1a06f369cd43bfeed05c9fc78da
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnShopLineCell.cs
New file
@@ -0,0 +1,30 @@
using UnityEngine;
public class HeroReturnShopLineCell : CellView
{
    [SerializeField] HeroReturnShopCell[] storeCells;
    HeroReturnManager manager => HeroReturnManager.Instance;
    public void Display(int index)
    {
        var act = manager.GetOperationHeroAppearInfo();
        if (act == null) return;
        var config = ActHeroAppearConfig.Get(act.CfgID);
        if (config == null) return;
        if (!StoreModel.Instance.storeTypeDict.TryGetValue(config.ExShopType, out var list)) return;
        for (int i = 0; i < storeCells.Length; i++)
        {
            if (index + i < list.Count)
            {
                storeCells[i].SetActive(true);
                storeCells[i].Display(index + i);
            }
            else
            {
                storeCells[i].SetActive(false);
            }
        }
    }
}
Main/System/HeroReturn/HeroReturnShopLineCell.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 7dbf46352446602458ece7d5acde3f20
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnShopWin.cs
New file
@@ -0,0 +1,80 @@
using UnityEngine;
public class HeroReturnShopWin : UIBase
{
    [SerializeField] OwnItemCell ownItemCell;
    [SerializeField] ButtonEx closeButton;
    [SerializeField] TextEx timeText;
    [SerializeField] ScrollerController scroller;
    HeroReturnManager manager => HeroReturnManager.Instance;
    protected override void InitComponent()
    {
        closeButton.SetListener(CloseWindow);
    }
    protected override void OnPreOpen()
    {
        scroller.OnRefreshCell += OnRefreshCell;
        StoreModel.Instance.RefreshShopEvent += CreateScroller;
        StoreModel.Instance.RefreshBuyShopLimitEvent += CreateScroller;
        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
        if (!manager.IsShopVisitedToday)
        {
            HeroReturnManager.Instance.SaveShopVisitTimeData();
            manager.UpdateRedpoint();
        }
        var act = manager.GetOperationHeroAppearInfo();
        if (act == null) return;
        var config = ActHeroAppearConfig.Get(act.CfgID);
        if (config == null) return;
        ownItemCell.itemID = config.ExShopCostItemID;
        CreateScroller();
        OnSecondEvent();
    }
    protected override void OnPreClose()
    {
        scroller.OnRefreshCell -= OnRefreshCell;
        StoreModel.Instance.RefreshShopEvent -= CreateScroller;
        StoreModel.Instance.RefreshBuyShopLimitEvent -= CreateScroller;
        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
        StoreModel.Instance.selectStoreFuncType = StoreFunc.Normal;
    }
    void OnRefreshCell(ScrollerDataType type, CellView cell)
    {
        var _cell = cell as HeroReturnShopLineCell;
        _cell.Display(cell.index);
    }
    private void OnSecondEvent()
    {
        manager.GetActTimeStr(timeText);
    }
    void CreateScroller()
    {
        var act = manager.GetOperationHeroAppearInfo();
        if (act == null) return;
        var config = ActHeroAppearConfig.Get(act.CfgID);
        if (config == null) return;
        if (!StoreModel.Instance.storeTypeDict.TryGetValue(config.ExShopType, out var list)) return;
        scroller.Refresh();
        for (int i = 0; i < list.Count; i++)
        {
            if (i % 3 == 0)
            {
                scroller.AddCell(ScrollerDataType.Header, i);
            }
        }
        scroller.Restart();
        scroller.lockType = EnhanceLockType.KeepVertical;
    }
}
Main/System/HeroReturn/HeroReturnShopWin.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: fceb72924bf0d6c418f2128afc294a52
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnSkinAwardCell.cs
New file
@@ -0,0 +1,18 @@
using UnityEngine;
public class HeroReturnSkinAwardCell : CellView
{
    [SerializeField] ItemCell itemCell;
    public void Display(int index, int[][] arr)
    {
        if (arr == null || arr.Length <= index) return;
        int itemID = arr[index][0];
        long itemCount = arr[index][1];
        itemCell.Init(new ItemCellModel(itemID, false, itemCount));
        itemCell.button.AddListener(() =>
        {
            ItemTipUtility.Show(itemID);
        });
    }
}
Main/System/HeroReturn/HeroReturnSkinAwardCell.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f6b0d10c152793d4f81f3b5fe4182937
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnSkinTabCell.cs
New file
@@ -0,0 +1,28 @@
using System.Collections.Generic;
using UnityEngine;
public class HeroReturnSkinTabCell : CellView
{
    [SerializeField] ImageEx tabBgImage;
    [SerializeField] ButtonEx tabButton;
    [SerializeField] RectTransform chooseRect;
    [SerializeField] RectTransform maskRect;
    HeroReturnManager manager => HeroReturnManager.Instance;
    public void Display(int index, List<int> list)
    {
        if (list?.Count <= index) return;
        var skinID = list[index];
        var skinArtConfig = ActHeroReturnSkinArtConfig.Get(skinID);
        if (skinArtConfig == null) return;
        tabBgImage.SetSprite(skinArtConfig.TabInfoImage);
        tabBgImage.SetNativeSize();
        maskRect.SetActive(manager.currentChooseSkinID != skinID);
        chooseRect.SetActive(manager.currentChooseSkinID == skinID);
        tabButton.SetListener(() =>
        {
            manager.currentChooseSkinID = skinID;
        });
    }
}
Main/System/HeroReturn/HeroReturnSkinTabCell.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 4f356ffc491c15044879e4d6601e5726
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnSkinWin.cs
New file
@@ -0,0 +1,229 @@
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.UI;
public class HeroReturnSkinWin : UIBase
{
    [SerializeField] float modelScale = 1f;
    [SerializeField] RawImage bgImage;
    [SerializeField] ImageEx heroNameImage;
    [SerializeField] ImageEx skinInfoImage;
    [SerializeField] ImageEx awardBgImage;
    [SerializeField] TextEx timeText;
    [SerializeField] ButtonEx buyButton;
    [SerializeField] ImageEx buyImage;
    [SerializeField] ImageEx countryImage;
    [SerializeField] TextEx buyText;
    [SerializeField] ButtonEx closeButton;
    [SerializeField] UIHeroController uiHeroController;
    [SerializeField] UIHeroController lhController;
    [SerializeField] ScrollerController awardScroller;
    [SerializeField] ScrollerController tabScroller;
    [SerializeField] Color numColor;
    [SerializeField] TextEx[] wearAttrText;
    [SerializeField] TextEx[] roleAttrText;
    [SerializeField] ButtonEx infoButton;
    HeroReturnManager manager => HeroReturnManager.Instance;
    protected override void InitComponent()
    {
        closeButton.SetListener(CloseWindow);
        infoButton.SetListener(() =>
        {
            int heroID = manager.GetHeroIDBySkinID(manager.currentChooseSkinID);
            HeroUIManager.Instance.selectForPreviewHeroID = heroID;
            HeroUIManager.Instance.selectSkinIndex = manager.GetSkinIndexInHeroConfig(heroID, manager.currentChooseSkinID);
            UIManager.Instance.OpenWindow<HeroBestBaseWin>(1);
        });
    }
    protected override void OnPreOpen()
    {
        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
        RechargeManager.Instance.rechargeCountEvent += OnRechargeCountEvent;
        awardScroller.OnRefreshCell += OnRefreshAwardCell;
        tabScroller.OnRefreshCell += OnRefreshTabCell;
        manager.OnCurrentChooseSkinIDChangeEevent += OnCurrentChooseSkinIDChange;
        CreateTabScroller();
        Display();
    }
    protected override void OnPreClose()
    {
        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
        RechargeManager.Instance.rechargeCountEvent -= OnRechargeCountEvent;
        awardScroller.OnRefreshCell -= OnRefreshAwardCell;
        tabScroller.OnRefreshCell -= OnRefreshTabCell;
        manager.OnCurrentChooseSkinIDChangeEevent -= OnCurrentChooseSkinIDChange;
    }
    private void OnCurrentChooseSkinIDChange()
    {
        tabScroller.m_Scorller.RefreshActiveCellViews();
        Display();
    }
    void OnRefreshTabCell(ScrollerDataType type, CellView cell)
    {
        var _cell = cell as HeroReturnSkinTabCell;
        _cell.Display(cell.index, skinIDList);
    }
    List<int> skinIDList;
    void CreateTabScroller()
    {
        var act = manager.GetOperationHeroAppearInfo();
        if (act == null) return;
        var config = ActHeroAppearConfig.Get(act.CfgID);
        if (config == null) return;
        int heroID = manager.GetFirstHeroId();
        var artConfig = ActHeroReturnArtConfig.Get(heroID);
        if (artConfig == null) return;
        skinIDList = manager.GetSkinIDList(act.CfgID, heroID, artConfig.MainSkinID);
        if (skinIDList.IsNullOrEmpty()) return;
        manager.currentChooseSkinID = skinIDList[0];
        tabScroller.Refresh();
        for (int i = 0; i < skinIDList.Count; i++)
        {
            tabScroller.AddCell(ScrollerDataType.Header, i);
        }
        tabScroller.Restart();
    }
    int[][] arr = null;
    void OnRefreshAwardCell(ScrollerDataType type, CellView cell)
    {
        var _cell = cell as HeroReturnSkinAwardCell;
        _cell.Display(cell.index, arr);
    }
    void CreateAwardScroller(int[][] sourceArr)
    {
        if (sourceArr == null) return;
        // 1. 获取已拥有的 ID 集合 (使用 LINQ 简洁明了)
        var ownedItems = HeroSkinAttrConfig.GetItemList();
        var itemIds = ownedItems != null ? new HashSet<int>(ownedItems) : new HashSet<int>();
        // 2. 过滤掉 items 中已有的项,并直接赋值给成员变量
        // arr[i][0] 假设为判断是否存在于 items 中的 ID
        this.arr = System.Array.FindAll(sourceArr, row => !itemIds.Contains(row[0]));
        // 3. 刷新 UI
        awardScroller.Refresh();
        for (int i = 0; i < this.arr.Length; i++)
        {
            awardScroller.AddCell(ScrollerDataType.Header, i);
        }
        awardScroller.Restart();
    }
    private void OnSecondEvent()
    {
        manager.GetActTimeStr(timeText);
    }
    private void OnRechargeCountEvent(int obj)
    {
        Display();
    }
    public void Display()
    {
        var act = manager.GetOperationHeroAppearInfo();
        if (act == null) return;
        var config = ActHeroAppearConfig.Get(act.CfgID);
        if (config == null) return;
        int heroID = manager.GetFirstHeroId();
        var artConfig = ActHeroReturnArtConfig.Get(heroID);
        if (artConfig == null) return;
        var heroConfig = HeroConfig.Get(heroID);
        if (heroConfig == null) return;
        int skinID = manager.currentChooseSkinID;
        var skinArtConfig = ActHeroReturnSkinArtConfig.Get(skinID);
        if (skinArtConfig == null) return;
        var heroSkinAttrConfig = HeroSkinAttrConfig.Get(skinID);
        if (heroSkinAttrConfig == null) return;
        if (heroSkinAttrConfig.WearAttrIDList == null) return;
        if (heroSkinAttrConfig.WearAttrValueList == null) return;
        if (heroSkinAttrConfig.RoleAttrIDList == null) return;
        if (heroSkinAttrConfig.RoleAttrValueList == null) return;
        var skinIDList = manager.GetSkinIDList(act.CfgID, heroID, skinID);
        if (skinIDList.IsNullOrEmpty()) return;
        int ctgId = manager.GetCtgIDBySkinID(skinID);
        var ctgConfig = CTGConfig.Get(ctgId);
        if (ctgConfig == null) return;
        if (!RechargeManager.Instance.TryGetOrderInfo(ctgId, out var orderConfig)) return;
        if (!RechargeManager.Instance.TryGetRechargeCount(ctgId, out var rechargeCount)) return;
        if (!RechargeManager.Instance.TryGetRechargeItem(ctgId, out var rechargeItemList)) return;
        bgImage.SetTexture2D(skinArtConfig.BGImage);
        heroNameImage.SetSprite(skinArtConfig.HeroNameImage);
        heroNameImage.SetNativeSize();
        skinInfoImage.SetSprite(skinArtConfig.SkinInfoImage);
        skinInfoImage.SetNativeSize();
        awardBgImage.SetSprite(skinArtConfig.AwardBGImage);
        awardBgImage.SetNativeSize();
        uiHeroController.Create(skinID, modelScale);
        lhController.Create(skinID, 1, motionName: "", isLh: true);
        countryImage.SetSprite(HeroUIManager.Instance.GetCountryIconName(heroConfig.Country));
        OnSecondEvent();
        CreateAwardScroller(ctgConfig.GainItemList);
        bool isCanBuy = manager.IsNoSellOutCTGID(ctgId);
        //buyImage.gray = !isCanBuy;
        buyText.text = !isCanBuy ? Language.Get("storename11") : Language.Get("PayMoneyNum", UIHelper.GetMoneyFormat(orderConfig.PayRMBNumOnSale));
        buyButton.interactable = isCanBuy;
        buyButton.SetListener(() =>
        {
            RechargeManager.Instance.CTG(ctgId);
        });
        for (int i = 0; i < wearAttrText.Length; i++)
            SetAttrInfo(0, i, heroSkinAttrConfig, wearAttrText[i]);
        for (int i = 0; i < roleAttrText.Length; i++)
            SetAttrInfo(1, i, heroSkinAttrConfig, roleAttrText[i]);
    }
    // type 0 穿戴属性值 1 主公属性
    public void SetAttrInfo(int type, int index, HeroSkinAttrConfig heroSkinAttrConfig, TextEx info)
    {
        if (heroSkinAttrConfig == null) return;
        int[] arrID = type == 0 ? heroSkinAttrConfig.WearAttrIDList : heroSkinAttrConfig.RoleAttrIDList;
        int[] arrValue = type == 0 ? heroSkinAttrConfig.WearAttrValueList : heroSkinAttrConfig.RoleAttrValueList;
        if (arrID?.Length <= index || arrValue?.Length <= index)
        {
            info.text = string.Empty;
            return;
        }
        info.text = GetFullDescription(arrID[index], arrValue[index]);
    }
    string GetFullDescription(int id, long value)
    {
        var config = PlayerPropertyConfig.Get(id);
        if (config == null) return string.Empty;
        return Language.Get("HeroDebut33", config.ShowName, PlayerPropertyConfig.GetValueDescription(id, value));
    }
}
Main/System/HeroReturn/HeroReturnSkinWin.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: a583b7b333d69584792f6aef8834bfcd
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnStarUpCell.cs
New file
@@ -0,0 +1,126 @@
using System.Linq;
using UnityEngine;
public class HeroReturnStarUpCell : CellView
{
    [SerializeField] ItemCell freeAwardItemCell;
    [SerializeField] Transform freeAwardHaveTransform;//已领取
    [SerializeField] Transform freeAwardCanHaveTransform;//可领取
    [SerializeField] Transform upProcssBGTransform;
    [SerializeField] Transform upProcessTransform;
    [SerializeField] Transform downProcssBGTransform;
    [SerializeField] Transform downProcessTransform;
    [SerializeField] TextEx starCntText;
    [SerializeField] TextEx limitText;
    [SerializeField] ButtonEx buyButton;
    [SerializeField] ImageEx buyImage;
    [SerializeField] TextEx buyText;
    [SerializeField] ImageEx rateImage;
    [SerializeField] TextEx rateText;
    [SerializeField] ScrollerController scroller;
    HeroReturnManager manager => HeroReturnManager.Instance;
    int id;
    public void Display(int id, CellView cell)
    {
        this.id = id;
        int heroID = cell.info.Value.infoInt1;
        bool isFrist = cell.info.Value.infoInt2 == 1;
        bool isEnd = cell.info.Value.infoInt3 == 1;
        var config = ActHeroAppearStarConfig.Get(id);
        if (config == null) return;
        var heroConfig = HeroConfig.Get(heroID);
        if (heroConfig == null) return;
        if (config.FreeAwardItemList.IsNullOrEmpty()) return;
        int ctgId = config.StarGiftCTGID;
        int awardIndex = config.AwardIndex;
        if (!manager.TryGetStarUpAwardArr(id, heroID, out int[][] list)) return;
        if (!RechargeManager.Instance.TryGetOrderInfo(ctgId, out var orderConfig)) return;
        if (!RechargeManager.Instance.TryGetRechargeCount(ctgId, out var rechargeCount)) return;
        if (!RechargeManager.Instance.TryGetRechargeItem(ctgId, out var rechargeItemList)) return;
        CTGConfig ctgConfig = CTGConfig.Get(ctgId);
        if (ctgConfig == null) return;
        rateImage.SetActive(true);
        rateText.text = Language.Get("DailySpecials07", ctgConfig.Percentage);
        int state = manager.GetStarUpFreeState(id);//0 - 未解锁 1 - 可领取 2 - 已领取
        freeAwardHaveTransform.SetActive(state == 2);
        freeAwardCanHaveTransform.SetActive(state == 1);
        bool isNoSellOut = manager.IsNoSellOutCTGID(ctgId);
        buyButton.interactable = state != 0 && isNoSellOut;
        buyButton.SetListener(() =>
        {
            if (isNoSellOut && state != 0)
            {
                RechargeManager.Instance.CTG(ctgId);
            }
        });
        //buyImage.gray = state == 0 || !isNoSellOut;
        buyText.text = !isNoSellOut ? Language.Get("storename11") : Language.Get("PayMoneyNum", UIHelper.GetMoneyFormat(orderConfig.PayRMBNumOnSale));
        limitText.text = Language.Get("TimeRush08", UIHelper.AppendColor(rechargeCount.totalCount >= ctgConfig.TotalBuyCount ? TextColType.Red : TextColType.DarkGreen, $"{rechargeCount.totalCount}/{ctgConfig.TotalBuyCount}"));
        bool isHeroStarOk = manager.IsHeroStarCntOk(heroConfig.HeroID, config.NeedStar) && HeroManager.Instance.HasHero(heroConfig.HeroID) && manager.IsLockStarHero(manager.GetOperationHeroAppearInfo());
        upProcssBGTransform.SetActive(!isFrist);
        downProcssBGTransform.SetActive(!isEnd);
        upProcessTransform.SetActive(isHeroStarOk);
        downProcessTransform.SetActive(isHeroStarOk);
        CreateScroller(list);
        int[] arr = config.FreeAwardItemList.First();
        int itemID = arr[0];
        int itemCount = arr[1];
        freeAwardItemCell.SetActive(true);
        freeAwardItemCell.Init(new ItemCellModel(itemID, false, itemCount));
        freeAwardItemCell.button.AddListener(() =>
        {
            if (state == 1)
            {
                manager.SendGetStarReward();
            }
            else
            {
                ItemTipUtility.Show(itemID);
            }
        });
        starCntText.text = Language.Get("HeroDebut20", config.NeedStar);
    }
    private void CreateScroller(int[][] list)
    {
        if (list == null) return;
        var config = ActHeroAppearStarConfig.Get(id);
        if (config == null) return;
        scroller.OnRefreshCell += OnRefreshCell;
        scroller.Refresh();
        for (int i = 0; i < list.Length; i++)
        {
            var item = list[i];
            var itemID = item[0];
            var itemCount = item[1];
            CellInfo cellInfo = new()
            {
                infoInt1 = itemID,
                infoInt2 = itemCount,
                infoInt3 = manager.IsNoSellOutCTGID(config.StarGiftCTGID) ? 1 : 0,
            };
            scroller.AddCell(ScrollerDataType.Header, i, cellInfo);
        }
        scroller.Restart();
        scroller.OnRefreshCell -= OnRefreshCell;
    }
    private void OnRefreshCell(ScrollerDataType type, CellView cell)
    {
        var _cell = cell.GetComponent<HeroReturnStarUpPaidItemCell>();
        _cell?.Display(cell.index, cell);
    }
}
Main/System/HeroReturn/HeroReturnStarUpCell.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 98c3340ec72bd5b46935ede657bae2b3
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnStarUpChangeCell.cs
New file
@@ -0,0 +1,33 @@
using UnityEngine;
public class HeroReturnStarUpChangeCell : CellView
{
    [SerializeField] HeroReturnStarUpChangeItem[] items;
    HeroReturnManager manager => HeroReturnManager.Instance;
    public void Display(int rowIndex)
    {
        var act = manager.GetOperationHeroAppearInfo();
        if (act == null) return;
        var config = ActHeroAppearConfig.Get(act.CfgID);
        if (config == null) return;
        var heroArr = config.ActHeroIDList;
        if (heroArr.IsNullOrEmpty()) return;
        for (int i = 0; i < items.Length; i++)
        {
            int index = rowIndex * HeroReturnCallChangeWin.rowCountMax + i;
            if (index < heroArr.Length)
            {
                items[i].SetActive(true);
                items[i].Display(index, heroArr);
            }
            else
            {
                items[i].SetActive(false);
            }
        }
    }
}
Main/System/HeroReturn/HeroReturnStarUpChangeCell.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 24e8dba4fdfc18547bd908c4906c29bc
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnStarUpChangeItem.cs
New file
@@ -0,0 +1,41 @@
using UnityEngine;
using UnityEngine.UI;
public class HeroReturnStarUpChangeItem : MonoBehaviour
{
    [SerializeField] HeroHeadBaseCell heroHeadBaseCell;
    [SerializeField] Image jobImg;
    [SerializeField] Text nameText;
    [SerializeField] Transform select;
    HeroReturnManager manager => HeroReturnManager.Instance;
    HeroConfig heroConfig;
    int index;
    public void Display(int index, int[] heroIds)
    {
        this.index = index;
        if (heroIds?.Length <= index) return;
        int heroId = heroIds[index];
        heroConfig = HeroConfig.Get(heroId);
        if (heroConfig == null) return;
        int skinID = manager.GetDefaultSkinID(heroId);
        var heroSkinConfig = HeroSkinConfig.Get(skinID);
        if (heroSkinConfig == null) return;
        heroHeadBaseCell.Init(heroConfig.HeroID, skinID, 0, 0, 0, OnClick);
        nameText.text = heroConfig.Name;
        jobImg.SetSprite(HeroUIManager.Instance.GetJobIconName(heroConfig.Class));
        bool isChoose = manager.nowStarUpChooseHeroID == heroId;
        select?.SetActive(isChoose);
    }
    public void OnClick()
    {
        if (heroConfig == null) return;
        manager.nowStarUpChooseHeroID = heroConfig.HeroID;
    }
}
Main/System/HeroReturn/HeroReturnStarUpChangeItem.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: f8d8ae1944679f64abb94301a00e6938
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnStarUpChangeWin.cs
New file
@@ -0,0 +1,100 @@
using UnityEngine;
public class HeroReturnStarUpChangeWin : UIBase
{
    [SerializeField] ScrollerController scroller;
    [SerializeField] ButtonEx closeButton;
    [SerializeField] ButtonEx okButton;
    [SerializeField] ButtonEx previewButton;
    [SerializeField] UIHeroController uiHeroController;
    public const int rowCountMax = 4;
    HeroReturnManager manager => HeroReturnManager.Instance;
    protected override void InitComponent()
    {
        closeButton.SetListener(CloseWindow);
        okButton.SetListener(() =>
        {
            var act = manager.GetOperationHeroAppearInfo();
            if (act == null) return;
            int index = manager.GetHeroIdIndex(act.CfgID, manager.nowStarUpChooseHeroID);
            if (index < 0) return;
            manager.SendHeroAppearStarHeroSelect(manager.actNum, index);
            manager.SaveStarUpChooseHeroStateKey(act);
            CloseWindow();
        });
        previewButton.SetListener(() =>
        {
            HeroUIManager.Instance.selectForPreviewHeroID = manager.nowStarUpChooseHeroID;
            UIManager.Instance.OpenWindow<HeroBestBaseWin>();
        });
    }
    protected override void OnPreOpen()
    {
        scroller.OnRefreshCell += OnRefreshCell;
        manager.OnNowStarUpChooseHeroIDChangeEvent += OnNowStarUpChooseHeroIDChangeEvent;
        manager.nowStarUpChooseHeroID = manager.GetCurrentDisplayStarUpHeroId();
        Display();
        CreateScroller();
    }
    protected override void OnPreClose()
    {
        scroller.OnRefreshCell -= OnRefreshCell;
        manager.OnNowStarUpChooseHeroIDChangeEvent -= OnNowStarUpChooseHeroIDChangeEvent;
        if (!UIManager.Instance.IsOpened<HeroReturnStarUpWin>() && manager.LoadStarUpChooseHeroStateKey(manager.GetOperationHeroAppearInfo()))
        {
            UIManager.Instance.OpenWindow<HeroReturnStarUpWin>();
        }
    }
    private void OnNowStarUpChooseHeroIDChangeEvent()
    {
        Display();
        scroller.m_Scorller.RefreshActiveCellViews();
    }
    void OnRefreshCell(ScrollerDataType type, CellView cell)
    {
        var _cell = cell as HeroReturnStarUpChangeCell;
        _cell.Display(cell.index);
    }
    void CreateScroller()
    {
        var act = manager.GetOperationHeroAppearInfo();
        if (act == null) return;
        var config = ActHeroAppearConfig.Get(act.CfgID);
        if (config == null) return;
        var arr = config.ActHeroIDList;
        if (arr.IsNullOrEmpty()) return;
        scroller.Refresh();
        int rowCount = (int)Mathf.Ceil((float)arr.Length / rowCountMax);
        for (int i = 0; i < rowCount; i++)
        {
            scroller.AddCell(ScrollerDataType.Header, i);
        }
        scroller.Restart();
    }
    void Display()
    {
        var act = manager.GetOperationHeroAppearInfo();
        if (act == null) return;
        int skinID = manager.GetDefaultSkinID(manager.nowStarUpChooseHeroID);
        var skinConfig = HeroSkinConfig.Get(skinID);
        if (skinConfig == null) return;
        uiHeroController.Create(skinID, 1);
    }
}
Main/System/HeroReturn/HeroReturnStarUpChangeWin.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 509bac132ac2a424fbed7f0aa2ef09de
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnStarUpPaidItemCell.cs
New file
@@ -0,0 +1,17 @@
using UnityEngine;
public class HeroReturnStarUpPaidItemCell : CellView
{
    [SerializeField] ItemCell itemCell;
    [SerializeField] Transform soldOutTransform;
    public void Display(int index, CellView cell)
    {
        int itemID = cell.info.Value.infoInt1;
        int count = cell.info.Value.infoInt2;
        bool isSoldOut = cell.info.Value.infoInt3 == 0;
        soldOutTransform.SetActive(isSoldOut);
        itemCell.SetActive(true);
        itemCell.Init(new ItemCellModel((int)itemID, false, count));
        itemCell.button.AddListener(() => ItemTipUtility.Show(itemID));
    }
}
Main/System/HeroReturn/HeroReturnStarUpPaidItemCell.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dd781838fa949c54cafb8db9df042715
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnStarUpWin.cs
New file
@@ -0,0 +1,159 @@
using UnityEngine;
public class HeroReturnStarUpWin : UIBase
{
    [SerializeField] HeroHeadBaseCell heroHeadBaseCell;
    [SerializeField] ImageEx jobImg;
    [SerializeField] TextEx nameText;
    [SerializeField] ButtonEx changeButton;
    [SerializeField] ButtonEx lockButton;
    [SerializeField] GradientText heroNameText;
    [SerializeField] TextEx timeText;
    [SerializeField] ImageEx heroImage;
    [SerializeField] ButtonEx goCallButton;
    [SerializeField] ButtonEx goInfoButton;
    [SerializeField] ButtonEx closeButton;
    [SerializeField] ScrollerController scroller;
    HeroReturnManager manager => HeroReturnManager.Instance;
    protected override void InitComponent()
    {
        closeButton.SetListener(CloseWindow);
        goCallButton.SetListener(() =>
        {
            UIManager.Instance.CloseWindow<HeroReturnStarUpWin>();
            UIManager.Instance.OpenWindow<HeroReturnCallWin>();
        });
        goInfoButton.SetListener(() =>
        {
            if (heroConfig == null) return;
            UIManager.Instance.CloseWindow<HeroReturnStarUpWin>();
            HeroUIManager.Instance.selectForPreviewHeroID = heroConfig.HeroID;
            UIManager.Instance.OpenWindow<HeroBestBaseWin>();
        });
        changeButton.SetListener(() =>
        {
            UIManager.Instance.OpenWindow<HeroReturnStarUpChangeWin>();
        });
        lockButton.SetListener(() =>
        {
            manager.SaveStarUpLockState(manager.GetOperationHeroAppearInfo());
            Display();
            manager.UpdateRedpoint();
        });
    }
    protected override void OnPreOpen()
    {
        scroller.OnRefreshCell += OnRefreshCell;
        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
        RechargeManager.Instance.rechargeCountEvent += OnRechargeCountEvent;
        manager.OnUpdateHeroAppearPlayerInfoEvent += OnUpdateHeroAppearPlayerInfoEvent;
        Display();
    }
    protected override void OnPreClose()
    {
        scroller.OnRefreshCell -= OnRefreshCell;
        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
        RechargeManager.Instance.rechargeCountEvent -= OnRechargeCountEvent;
        manager.OnUpdateHeroAppearPlayerInfoEvent -= OnUpdateHeroAppearPlayerInfoEvent;
    }
    private void OnUpdateHeroAppearPlayerInfoEvent()
    {
        scroller.m_Scorller.RefreshActiveCellViews();
        Display();
    }
    private void OnRefreshCell(ScrollerDataType type, CellView cell)
    {
        var _cell = cell.GetComponent<HeroReturnStarUpCell>();
        _cell?.Display(cell.index, cell);
    }
    private void OnSecondEvent()
    {
        manager.GetActTimeStr(timeText);
    }
    private void OnRechargeCountEvent(int obj)
    {
        scroller.m_Scorller.RefreshActiveCellViews();
    }
    HeroConfig heroConfig;
    private void Display()
    {
        int heroID = manager.GetCurrentDisplayStarUpHeroId();
        heroConfig = HeroConfig.Get(heroID);
        if (heroConfig == null) return;
        var artConfig = ActHeroReturnArtConfig.Get(heroID);
        if (artConfig == null) return;
        var act = manager.GetOperationHeroAppearInfo();
        if (act == null) return;
        var config = ActHeroAppearConfig.Get(act.CfgID);
        if (config == null) return;
        var heroArr = config.ActHeroIDList;
        if (heroArr.Length <= manager.starHeroIndex) return;
        int heroId = heroArr[manager.starHeroIndex];
        heroConfig = HeroConfig.Get(heroId);
        if (heroConfig == null) return;
        int skinID = manager.GetDefaultSkinID(heroId);
        var heroSkinConfig = HeroSkinConfig.Get(skinID);
        if (heroSkinConfig == null) return;
        bool isLockStarHero = manager.IsLockStarHero(act);
        changeButton.SetActive(!isLockStarHero);
        lockButton.interactable = !isLockStarHero;
        heroHeadBaseCell.Init(heroConfig.HeroID, skinID, 0, 0, 0, () =>
        {
            if (isLockStarHero) return;
            UIManager.Instance.OpenWindow<HeroReturnStarUpChangeWin>();
        });
        nameText.text = heroConfig.Name;
        jobImg.SetSprite(HeroUIManager.Instance.GetJobIconName(heroConfig.Class));
        heroNameText.text = heroConfig.Name;
        manager.SetGradientTextColor(heroNameText, artConfig.HeroNameColor);
        heroImage.SetSprite(artConfig.StarUpHeroImage);
        heroImage.SetNativeSize();
        CreateScroller(config, heroConfig);
    }
    private void CreateScroller(ActHeroAppearConfig appearConfig, HeroConfig heroConfig)
    {
        if (appearConfig == null || heroConfig == null) return;
        int starGiftTempID = appearConfig.StarGiftTempID;
        var list = ActHeroAppearStarConfig.GetHeroReturnAwardIndexSortList(starGiftTempID);
        if (list == null) return;
        scroller.Refresh();
        for (int i = 0; i < list.Count; i++)
        {
            var awardIndex = list[i];
            var config = ActHeroAppearStarConfig.GetConfig(starGiftTempID, awardIndex);
            if (config == null) continue;
            CellInfo cellInfo = new()
            {
                infoInt1 = heroConfig.HeroID,
                infoInt2 = i == 0 ? 1 : 0,
                infoInt3 = i == list.Count - 1 ? 1 : 0
            };
            scroller.AddCell(ScrollerDataType.Header, config.ID, cellInfo);
        }
        scroller.Restart();
        scroller.JumpIndex(manager.GetStarUpJumpIndex(starGiftTempID));
    }
}
Main/System/HeroReturn/HeroReturnStarUpWin.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: dae38759f25f7eb4ab53165ca393cd2e
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/HeroReturn/HeroReturnWin.cs
New file
@@ -0,0 +1,268 @@
using System;
using UnityEngine;
using UnityEngine.UI;
using DG.Tweening;
public class HeroReturnWin : UIBase
{
    [SerializeField] RectTransform activeRect;
    [SerializeField] RectTransform moveRect;
    [SerializeField] RectTransform startRect;
    [SerializeField] RectTransform endRect;
    [SerializeField] ImageEx bgImage;
    [SerializeField] ImageEx titleImage;
    [SerializeField] TextEx timeText;
    [SerializeField] ButtonEx animationButton;
    [SerializeField] ButtonEx checkInButton; // 签到赠礼
    [SerializeField] RedpointBehaviour checkInRedpoint;
    [SerializeField] ButtonEx starUpButton; // 升星计划
    [SerializeField] RedpointBehaviour starUpRedpoint;
    [SerializeField] ButtonEx shopButton; // 兑换商店
    [SerializeField] RedpointBehaviour shopRedpoint;
    [SerializeField] ImageEx skinImage;
    [SerializeField] ButtonEx skinButton; // 时装特卖
    [SerializeField] ButtonEx giftButton; // 皇权礼包
    [SerializeField] RedpointBehaviour giftRedpoint;
    [SerializeField] ButtonEx callButton; // 皇权招募
    [SerializeField] UIHeroController uiHeroController;
    [SerializeField] UIHeroController lhController;
    [SerializeField] Image callRedImage;
    [SerializeField] ButtonEx closeButton;
    [SerializeField] float modleSize = 0.8f;
    // 轮播相关
    private const float CarouselInterval = 5f;       // 轮播间隔5秒
    private const float FadeDuration = 0.4f;          // 渐变时长
    private int[] heroIdList;                         // 武将ID列表
    private int currentHeroIndex;                      // 当前武将索引
    private bool isCarouselActive;                    // 是否正在轮播
    private Tween carouselTween;                       // 轮播淡入淡出tween
    private float carouselTimer;                       // 轮播计时器
    HeroReturnManager manager => HeroReturnManager.Instance;
    protected override void InitComponent()
    {
        closeButton.SetListener(() => UIManager.Instance.CloseWindow<HeroReturnWin>());
        checkInButton.SetListener(() => UIManager.Instance.OpenWindow<HeroReturnCheckInWin>());
        starUpButton.SetListener(() =>
        {
            if (manager.IsLockStarHero(manager.GetOperationHeroAppearInfo()))
            {
                UIManager.Instance.OpenWindow<HeroReturnStarUpWin>();
                return;
            }
            if (!manager.LoadStarUpChooseHeroStateKey(manager.GetOperationHeroAppearInfo()))
            {
                UIManager.Instance.OpenWindow<HeroReturnStarUpChangeWin>();
                return;
            }
            UIManager.Instance.OpenWindow<HeroReturnStarUpWin>();
        });
        shopButton.SetListener(() => UIManager.Instance.OpenWindow<HeroReturnShopWin>());
        skinButton.SetListener(() => UIManager.Instance.OpenWindow<HeroReturnSkinWin>());
        giftButton.SetListener(() => UIManager.Instance.OpenWindow<HeroReturnGiftWin>());
        callButton.SetListener(() => UIManager.Instance.OpenWindow<HeroReturnCallWin>());
    }
    protected override void OnPreOpen()
    {
        InitRedpoint();
        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
        RechargeManager.Instance.rechargeCountEvent += OnRechargeCountEvent;
        StoreModel.Instance.RefreshBuyShopLimitEvent += Display;
        manager.OnUpdateHeroAppearPlayerInfoEvent += OnUpdateHeroAppearPlayerInfoEvent;
        Display();
    }
    protected override void OnPreClose()
    {
        StopCarousel();
        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
        RechargeManager.Instance.rechargeCountEvent -= OnRechargeCountEvent;
        StoreModel.Instance.RefreshBuyShopLimitEvent -= Display;
        manager.OnUpdateHeroAppearPlayerInfoEvent -= OnUpdateHeroAppearPlayerInfoEvent;
    }
    private void OnUpdateHeroAppearPlayerInfoEvent()
    {
        Display();
    }
    private void OnRechargeCountEvent(int obj)
    {
        Display();
    }
    public void InitRedpoint()
    {
        checkInRedpoint.redpointId = manager.GetRedPointId(HeroReturnRedPointType.CheckIn);
        starUpRedpoint.redpointId = manager.GetRedPointId(HeroReturnRedPointType.StarUp);
        shopRedpoint.redpointId = manager.GetRedPointId(HeroReturnRedPointType.Shop);
        giftRedpoint.redpointId = manager.GetRedPointId(HeroReturnRedPointType.Gift);
    }
    private void Display()
    {
        var act = manager.GetOperationHeroAppearInfo();
        if (act == null) return;
        var config = ActHeroAppearConfig.Get(act.CfgID);
        if (config == null || config.ActHeroIDList.IsNullOrEmpty()) return;
        // 获取武将列表
        heroIdList = config.ActHeroIDList;
        currentHeroIndex = 0;
        // 如果只有一个武将,不轮播,直接显示
        if (heroIdList.Length <= 1)
        {
            StopCarousel();
            DisplayHero(heroIdList[0], false);
        }
        else
        {
            // 多个武将,开启轮播
            carouselTimer = 0f;
            DisplayHero(heroIdList[currentHeroIndex], false);
            StartCarousel();
        }
        callRedImage.SetActive(!manager.IsShopVisitedToday || manager.HasGiftCanHave());
        OnSecondEvent();
    }
    private void LateUpdate()
    {
        if (!isCarouselActive) return;
        if (heroIdList == null || heroIdList.Length <= 1) return;
        // 检查是否存在更高层级的窗口,如果有则不播放轮播
        if (UIManager.Instance.ExistAnySameLevelWinHigherSortingOrder(uiLayer, uiName))
        {
            return;
        }
        carouselTimer += Time.deltaTime;
        if (carouselTimer >= CarouselInterval)
        {
            carouselTimer = 0f;
            // 切换到下一个武将
            currentHeroIndex = (currentHeroIndex + 1) % heroIdList.Length;
            int nextHeroID = heroIdList[currentHeroIndex];
            // 带动画切换
            DisplayHero(nextHeroID, true);
        }
    }
    /// <summary>
    /// 显示指定武将的背景和立绘
    /// </summary>
    private void DisplayHero(int heroID, bool withAnimation)
    {
        var artConfig = ActHeroReturnArtConfig.Get(heroID);
        if (artConfig == null) return;
        int skinID = manager.GetDefaultSkinID(heroID);
        var skinConfig = HeroSkinConfig.Get(skinID);
        if (skinConfig == null) return;
        var skinArtConfig = ActHeroReturnSkinArtConfig.Get(artConfig.MainSkinID);
        if (skinArtConfig == null) return;
        if (withAnimation)
        {
            carouselTween?.Kill();
            Sequence seq = DOTween.Sequence();
            seq.Append(bgImage.DOFade(0.7f, FadeDuration));
            CanvasGroup lhCanvasGroup = lhController.GetComponent<CanvasGroup>();
            if (lhCanvasGroup == null)
            {
                lhCanvasGroup = lhController.gameObject.AddComponent<CanvasGroup>();
            }
            seq.Join(lhCanvasGroup.DOFade(0f, FadeDuration));
            seq.OnComplete(() =>
            {
                UpdateHeroDisplay(heroID, skinID, artConfig, skinArtConfig);
                // 淡入
                bgImage.DOFade(1f, FadeDuration);
                lhCanvasGroup.DOFade(1f, FadeDuration);
            });
            carouselTween = seq;
        }
        else
        {
            UpdateHeroDisplay(heroID, skinID, artConfig, skinArtConfig);
            CanvasGroup lhCanvasGroup = lhController.GetComponent<CanvasGroup>();
            if (lhCanvasGroup != null)
            {
                lhCanvasGroup.alpha = 1f;
            }
        }
    }
    /// <summary>
    /// 更新武将显示资源
    /// </summary>
    private void UpdateHeroDisplay(int heroID, int skinID, ActHeroReturnArtConfig artConfig, ActHeroReturnSkinArtConfig skinArtConfig)
    {
        int chosenHeroSkinID = manager.GetDefaultSkinID(
            manager.LoadCallChooseHeroStateKey(manager.GetOperationHeroAppearInfo()) ?
            manager.GetCurrentDisplayCallHeroId() :
            manager.GetFirstHeroId());
        uiHeroController.Create(chosenHeroSkinID, modleSize);
        uiHeroController.transform.localScale = new Vector3(-modleSize, modleSize, modleSize);
        lhController.Create(skinID, 1, motionName: "", isLh: true);
        // 更新背景
        bgImage.SetSprite(artConfig.MainBgImage);
        bgImage.SetNativeSize();
        // 更新标题
        titleImage.SetSprite(artConfig.MainTitleImage);
        titleImage.SetNativeSize();
        // 更新皮肤图片
        int firstHeroID = manager.GetFirstHeroId();
        var firstHeroIDArtConfig = ActHeroReturnArtConfig.Get(firstHeroID);
        if (firstHeroIDArtConfig == null) return;
        var firstSkinArtConfig = ActHeroReturnSkinArtConfig.Get(firstHeroIDArtConfig.MainSkinID);
        if (firstSkinArtConfig == null) return;
        skinImage.SetSprite(firstSkinArtConfig.MainSkinBuyBgImage);
    }
    /// <summary>
    /// 开始轮播
    /// </summary>
    private void StartCarousel()
    {
        if (isCarouselActive) return;
        isCarouselActive = true;
        carouselTimer = 0f;
    }
    /// <summary>
    /// 停止轮播
    /// </summary>
    private void StopCarousel()
    {
        isCarouselActive = false;
        carouselTimer = 0f;
        carouselTween?.Kill();
        carouselTween = null;
    }
    private void OnSecondEvent()
    {
        manager.GetActTimeStr(timeText);
    }
}
Main/System/HeroReturn/HeroReturnWin.cs.meta
New file
@@ -0,0 +1,11 @@
fileFormatVersion: 2
guid: 264e7ec58915d6243902eadabc46eee9
MonoImporter:
  externalObjects: {}
  serializedVersion: 2
  defaultReferences: []
  executionOrder: 0
  icon: {instanceID: 0}
  userData:
  assetBundleName:
  assetBundleVariant:
Main/System/Main/HomeWin.cs
@@ -73,6 +73,7 @@
    [SerializeField] Button osMinggeBtn;
    [SerializeField] TimeRushCell timeRushCell;
    [SerializeField] HeroDebutCell heroDebutCell;
    [SerializeField] HeroReturnCell heroReturnCell;
    //坐骑
    [SerializeField] Image horseBGImg;
@@ -296,6 +297,7 @@
        DisplayTimeRush();
        DisplayHeroDebut();
        DisplayHeroReturn();
        DelayPlayMusic().Forget();
    }
@@ -336,6 +338,10 @@
        {
            DisplayHeroDebut();
        }
        else if (type == OperationType.HeroReturn)
        {
            DisplayHeroReturn();
        }
    }
@@ -343,6 +349,7 @@
    {
        DisplayTimeRush();
        DisplayHeroDebut();
        DisplayHeroReturn();
    }
    private void OnShowGiftIdListAddEvent()
@@ -841,6 +848,10 @@
        {
            DisplayHeroDebut();
        }
        else if (funcId == (int)FuncOpenEnum.HeroReturn)
        {
            DisplayHeroReturn();
        }
    }
    private void OnUpdateFirstChargeInfo()
@@ -917,6 +928,15 @@
            return;
        heroDebutCell.Display();
    }
    void DisplayHeroReturn()
    {
        bool isOpen = HeroReturnManager.Instance.IsHeroReturnOpen();
        heroReturnCell.SetActive(isOpen);
        if (!isOpen)
            return;
        heroReturnCell.Display();
    }
}
Main/System/OpenServerActivity/OperationTimeHepler.cs
@@ -469,9 +469,9 @@
            case 10:
                opreationType = OperationType.HeroDebut;
                break;
            // case 11:
            //     opreationType = OperationType.HeroBack;
            //     break;
            case 11:
                opreationType = OperationType.HeroReturn;
                break;
        }
        if (string.IsNullOrEmpty(package.StartDate) || string.IsNullOrEmpty(package.EndtDate))
@@ -1084,5 +1084,6 @@
{
    TimeRush = 1,  //日期型活动 - 轮回殿
    HeroDebut = 2,  //日期型活动 - 武将登场
    HeroReturn = 3, //日期型活动 - 武将返场
    max,
}
Main/System/Redpoint/MainRedDot.cs
@@ -155,6 +155,7 @@
    public const int RedPoint_OSHeroTrain = 481;
    public const int RedPoint_OSBeautyMM = 482;
    public const int RedPoint_OSMingge = 483;
    public const int HeroReturnRepoint = 484; //武将返场
    public void Register()
    {
Main/System/UIBase/UIJumpManager.cs
@@ -61,10 +61,9 @@
                }
            }
        }
        else if (config.WinName == "HeroDebutCallWin" ||
                config.WinName == "HeroDebutSkinWin" ||
                config.WinName == "HeroDebutCheckInWin" ||
                config.WinName == "HeroDebutGiftWin" ||
        //武将登场相关
        else if (config.WinName == "HeroDebutCallWin" || config.WinName == "HeroDebutSkinWin" ||
                config.WinName == "HeroDebutCheckInWin" || config.WinName == "HeroDebutGiftWin" ||
                config.WinName == "HeroDebutShopWin")
        {
            var heroDebutAct = HeroDebutManager.Instance.GetOperationHeroAppearInfo();
@@ -96,6 +95,40 @@
                UIManager.Instance.OpenWindow(config.WinName);
            }
        }
        //武将返场相关
        else if (config.WinName == "HeroReturnCallWin" || config.WinName == "HeroReturnSkinWin" ||
                config.WinName == "HeroReturnCheckInWin" || config.WinName == "HeroReturnGiftWin" ||
                config.WinName == "HeroReturnShopWin")
        {
            var heroDebutAct = HeroReturnManager.Instance.GetOperationHeroAppearInfo();
            if (heroDebutAct == null)
            {
                SysNotifyMgr.Instance.ShowTip("ActivityNoOpen");
                return;
            }
            var actHeroAppearConfig = ActHeroAppearConfig.Get(heroDebutAct.CfgID);
            if (actHeroAppearConfig == null)
            {
                SysNotifyMgr.Instance.ShowTip("ActivityNoOpen");
                return;
            }
            // 皮肤商店需要判断物品ID
            if (config.WinName == "HeroReturnSkinWin")
            {
                if (!HeroReturnManager.Instance.HasItemInSkinCTGIDList(heroDebutAct.CfgID, int.Parse(config.Extra)))
                {
                    SysNotifyMgr.Instance.ShowTip("ActivityNoOpen");
                    return;
                }
            }
            if (UIManager.Instance.IsOpened(config.WinName))
            {
                UIManager.Instance.CloseWindow(config.WinName);
                UIManager.Instance.OpenWindow(config.WinName);
            }
        }
        if (!UIManager.Instance.IsOpened(config.WinName))
        {
Main/Utility/EnumHelper.cs
@@ -858,6 +858,7 @@
    OSMingge = 61, //开服命格培养榜活动
    Qunying = 62, //群英榜
    HeroDebut = 63,//武将登场
    HeroReturn = 64,  //武将返场
}
@@ -1813,6 +1814,7 @@
{
    TimeRushAct = 200,  //轮回殿(武将冲刺)
    HeroDebutAct = 201,  //英雄登场活动
    HeroReturnAct = 202,  //英雄返场活动
}
//仙玉购买的二次确认框类型