From 09bc892c7283df8757a07b646d5af21ddaa263d1 Mon Sep 17 00:00:00 2001
From: lcy <1459594991@qq.com>
Date: 星期四, 06 十一月 2025 18:22:34 +0800
Subject: [PATCH] 164 天子的考验-客户端

---
 Main/Component/UI/Common/IntensifySmoothSlider.cs                                           |  183 +++
 Main/System/TianziBillborad/TianziBillboradBossHead.cs                                      |   79 +
 Main/Core/NetworkPackage/ServerPack/HB2_ActionMap/HB201_tagSCTianziKYInfo.cs                |   25 
 Main/System/BoneField/AdsManager.cs                                                         |   24 
 Main/System/ChallengeTab/TianziBillboradTabHandler.cs.meta                                  |   11 
 Main/Config/PartialConfigs/TianziConfig.cs                                                  |  136 ++
 Main/System/TianziBillborad/TianziBillboradBox.cs.meta                                      |   11 
 Main/System/TianziBillborad/TianziBillboradManager.cs.meta                                  |   11 
 Main/System/Redpoint/MainRedDot.cs                                                          |    1 
 Main/Core/NetworkPackage/ServerPack/HB2_ActionMap/HB201_tagSCTianziKYInfo.cs.meta           |   11 
 Main/Config/Configs/TianziConfig.cs.meta                                                    |   11 
 Main/Core/NetworkPackage/DTCFile/ServerPack/HB2_ActionMap/DTCB201_tagSCTianziKYInfo.cs      |   12 
 Main/System/Settlement/BattleSettlementManager.cs                                           |    7 
 Main/Config/Configs/TianziConfig.cs                                                         |   59 +
 Main/System/Battle/BattleObject/BattleObject.cs                                             |   30 
 Main/System/Battle/UIComp/BattleHeroInfoBar.cs                                              |    9 
 Main/System/TianziBillborad/TianziBillboradWin.cs                                           |  265 +++++
 Main/Core/NetworkPackage/DTCFile/ServerPack/HB2_ActionMap.meta                              |    8 
 Main/System/TianziBillborad/TianziBillboradRankWin.cs.meta                                  |   11 
 Main/System/TianziBillborad/TianziBillboradAwardCell.cs.meta                                |   11 
 Main/System/TianziBillborad/TianziBillboradSweepTipWin.cs.meta                              |   11 
 Main/System/ChallengeTab/TianziBillboradTabHandler.cs                                       |   75 +
 Main/System/Battle/BattleConst.cs                                                           |    2 
 Main/Config/ConfigManager.cs                                                                |    3 
 Main/System/TianziBillborad/TianziBillboradBossHead.cs.meta                                 |   11 
 Main/System/TianziBillborad/TianziBillboradAwardCell.cs                                     |   55 +
 Main/System/Battle/TianziBillboradBattleWin.cs                                              |  346 +++++++
 Main/Config/Configs/NPCConfig.cs                                                            |   13 
 Main/System/Battle/BattleFieldFactory.cs                                                    |    3 
 Main/System/Battle/TianziBillboradBattleWin.cs.meta                                         |   11 
 Main/Config/PartialConfigs/TianziConfig.cs.meta                                             |   11 
 Main/Core/NetworkPackage/ServerPack/HB2_ActionMap.meta                                      |    8 
 Main/Config/PartialConfigs/DungeonConfig.cs                                                 |    4 
 Main/System/Settlement/TianziBillboradVictoryWin.cs                                         |   96 ++
 Main/Core/NetworkPackage/DTCFile/ServerPack/HB2_ActionMap/DTCB201_tagSCTianziKYInfo.cs.meta |   11 
 Main/Main.cs                                                                                |    2 
 Main/System/TianziBillborad/TianziBillboradWin.cs.meta                                      |   11 
 Main/System/TianziBillborad/TianziDamageBar.cs                                              |  224 ++++
 Main/System/TianziBillborad/TianziDamageBar.cs.meta                                         |   11 
 Main/System/TianziBillborad/TianziBillboradBox.cs                                           |  247 +++++
 Main/System/Battle/BattleField/TianziBillboradBattleField.cs                                |  142 ++
 Main/System/Dungeon/DungeonManager.cs                                                       |    2 
 Main/Core/NetworkPackage/DTCFile/ServerPack/H03_MainCharacter/DTC0320_tagFBEnd.cs           |    1 
 Main/System/Battle/BattleField/TianziBillboradBattleField.cs.meta                           |   11 
 Main/System/Settlement/TianziBillboradVictoryWin.cs.meta                                    |   11 
 Main/System/TianziBillborad/TianziBillboradRankWin.cs                                       |  164 +++
 Main/System/TianziBillborad/TianziBillboradSweepTipWin.cs                                   |   48 +
 Main/Component/UI/Common/IntensifySmoothSlider.cs.meta                                      |    0 
 /dev/null                                                                                   |  115 --
 Main/Core/NetworkPackage/DataToCtl/PackageRegedit.cs                                        |    1 
 Main/System/TianziBillborad/TianziBillboradManager.cs                                       |  295 ++++++
 51 files changed, 2,720 insertions(+), 140 deletions(-)

diff --git a/Main/Component/UI/Common/IntensifySmoothSlider.cs b/Main/Component/UI/Common/IntensifySmoothSlider.cs
new file mode 100644
index 0000000..97cb452
--- /dev/null
+++ b/Main/Component/UI/Common/IntensifySmoothSlider.cs
@@ -0,0 +1,183 @@
+using System;
+using UnityEngine;
+using UnityEngine.UI;
+
+[DisallowMultipleComponent]
+public class IntensifySmoothSlider : MonoBehaviour
+{
+    [SerializeField]
+    Slider m_Slider;
+    public Slider slider
+    {
+        get { return m_Slider; }
+    }
+
+    [SerializeField]
+    [Range(0, 10)]
+    float m_Delay = 0.2f;
+    public float delay
+    {
+        get { return m_Delay; }
+        set
+        {
+            m_Delay = Mathf.Clamp(value, 0, 10);
+        }
+    }
+
+    [SerializeField]
+    [Range(0, 1)]
+    float m_Value = 0f;
+    public float value
+    {
+        get
+        {
+            return m_Value;
+        }
+        set
+        {
+            m_Value = Mathf.Clamp01(value);
+        }
+    }
+    
+
+    // 鍊兼洿鏂颁簨浠�(ValueChangeAction)鐨勮Е鍙戝垎娈垫暟銆�
+    // 鐢ㄤ簬闄嶄綆 ValueChangeAction 鐨勮Е鍙戦鐜囷紝闃叉UI鏂囨湰绛夌洃鍚粍浠堕绻佸埛鏂般��
+    // 
+    // 宸ヤ綔鍘熺悊:
+    // 灏嗘粦鍧楃殑 [0, 1] 鑼冨洿鍒掑垎涓� 'm_ValueUpdateSegments' 涓暟閲忕浉绛夌殑鍒嗘銆�
+    // ValueChangeAction 浜嬩欢浠呭湪 slider.value 璺ㄨ秺杩欎簺鍒嗘杈圭晫鏃舵墠浼氳瑙﹀彂銆�
+    //
+    // 绀轰緥:
+    // - 璁句负 10: 鍒欐粦鍧楀�兼瘡鍙樺寲 0.1 (10%) 瑙﹀彂涓�娆′簨浠� (濡備粠 0.19 璺ㄥ埌 0.21 鏃�)銆�
+    // - 璁句负 100: 鍒欐粦鍧楀�兼瘡鍙樺寲 0.01 (1%) 瑙﹀彂涓�娆′簨浠躲��
+    [SerializeField]
+    [Range(1, 1000)]
+    int m_ValueUpdateSegments = 10; 
+    public int ValueUpdateSegments
+    {
+        get { return m_ValueUpdateSegments; }
+        set { m_ValueUpdateSegments = Mathf.Max(1, value); } // 鑷冲皯涓�1
+    }
+
+    // 璺熻釜涓婁竴娆¤Е鍙戜簨浠舵椂锛屾粦鍧楀�兼墍澶勭殑鍒嗘绱㈠紩 (鑼冨洿浠� 0 鍒� m_ValueUpdateSegments-1)銆�
+    private int m_LastNotifiedSegment = -1;
+
+
+    int m_Stage = 0;
+    public int stage
+    {
+        get { return m_Stage; }
+        set { m_Stage = value; }
+    }
+
+    private int presentStage;
+    public int CurrentStage { get { return presentStage; } }
+
+    float refSpeed = 0f;
+    public event Action<int> StageUpAction;
+    public event Action<float, int> ValueChangeAction;
+    public event Action ChangeEndAction;
+    public void ResetStage()
+    {
+        presentStage = stage;
+    }
+
+    public void ResetValue(float _value)
+    {
+        value = _value;
+        if (slider != null)
+        {
+            slider.value = Mathf.Clamp01(_value);
+        }
+        // 閲嶇疆鍊兼椂锛屽悓姝ユ洿鏂版渶鍚庨�氱煡鐨勫垎娈电储寮�
+        m_LastNotifiedSegment = GetCurrentSegment(slider.value);
+    }
+
+    void OnEnable()
+    {
+        refSpeed = 0f;
+        // 鍚敤鏃讹紝鍒濆鍖栨渶鍚庨�氱煡鐨勫垎娈电储寮�
+        m_LastNotifiedSegment = GetCurrentSegment(slider != null ? slider.value : m_Value);
+    }
+
+    // 鏍规嵁褰撳墠婊戝潡鍊�(0-1)锛岃绠楀叾鎵�灞炵殑鍒嗘绱㈠紩(0 鍒� m_ValueUpdateSegments-1)
+    private int GetCurrentSegment(float currentValue)
+    {
+        // 灏� [0, 1] 鑼冨洿鐨勬诞鐐规暟鍊� 鏄犲皠鍒� [0, m_ValueUpdateSegments-1] 鑼冨洿鐨勬暣鏁扮储寮�
+        float preciseSegment = currentValue * m_ValueUpdateSegments;
+        
+        // 娉ㄦ剰锛氬綋鍊间负1.0f鏃讹紝鎴戜滑甯屾湜瀹冭惤鍦ㄦ渶鍚庝竴涓垎娈电储寮曚笂 (鍗� segments - 1)
+        if (currentValue >= 1.0f)
+        {
+            return m_ValueUpdateSegments - 1;
+        }
+        return Mathf.FloorToInt(preciseSegment);
+    }
+
+
+    // 鐢ㄤ簬璺熻釜婊戝潡鏄惁姝e湪缂撳姩
+    private bool isMoving = false;
+
+    void LateUpdate()
+    {
+        if (slider == null)
+        {
+            return;
+        }
+
+        if (presentStage < m_Stage)
+        {
+            slider.value = Mathf.SmoothDamp(slider.value, 1, ref refSpeed, delay / 2);
+
+            if (slider.value >= 0.99f)
+            {
+                slider.value = 0f;
+                presentStage++;
+                StageUpAction?.Invoke(presentStage);
+                m_LastNotifiedSegment = 0;// 褰撹鏉″惊鐜椂锛岄噸缃垎娈电储寮�
+            }
+
+            isMoving = true;
+            CheckForValueChangeNotification(slider.value);
+        }
+        else
+        {
+            if (Mathf.Abs(slider.value - value) > 0.001f)
+            {
+                slider.value = Mathf.SmoothDamp(slider.value, value, ref refSpeed, delay);
+                isMoving = true; 
+                CheckForValueChangeNotification(slider.value);
+            }
+            else
+            {
+                if (isMoving)
+                {
+                    // 纭繚鍊煎湪鍋滄鏃跺畬鍏ㄧ簿纭�
+                    if (slider.value != value)
+                    {
+                        slider.value = value;
+                        ValueChangeAction?.Invoke(slider.value, CurrentStage);
+                        m_LastNotifiedSegment = GetCurrentSegment(slider.value);
+                    }
+                    ChangeEndAction?.Invoke(); 
+                    isMoving = false;  
+                }
+            }
+        }
+    }
+
+    // 妫�鏌ユ槸鍚﹂渶瑕佽Е鍙慥alueChangeAction鐨勯�昏緫
+    private void CheckForValueChangeNotification(float currentSliderValue)
+    {
+        int currentSegment = GetCurrentSegment(currentSliderValue);
+        
+        // 濡傛灉褰撳墠鐨勫垎娈电储寮曚笌涓婃瑙﹀彂浜嬩欢鏃剁殑绱㈠紩涓嶅悓锛岃鏄庡凡璺ㄨ秺鍒嗘杈圭晫銆�
+        if (currentSegment != m_LastNotifiedSegment)
+        {
+            ValueChangeAction?.Invoke(currentSliderValue, CurrentStage);
+            // 鏇存柊鈥滀笂娆¤Е鍙戔�濈殑绱㈠紩涓哄綋鍓嶇储寮曪紝闃叉鏈垎娈靛唴閲嶅瑙﹀彂銆�
+            m_LastNotifiedSegment = currentSegment; 
+        }
+    }
+
+}
\ No newline at end of file
diff --git a/Main/System/TianziBillborad/IntensifySmoothSlider.cs.meta b/Main/Component/UI/Common/IntensifySmoothSlider.cs.meta
similarity index 100%
rename from Main/System/TianziBillborad/IntensifySmoothSlider.cs.meta
rename to Main/Component/UI/Common/IntensifySmoothSlider.cs.meta
diff --git a/Main/Config/ConfigManager.cs b/Main/Config/ConfigManager.cs
index 581039f..7e1430b 100644
--- a/Main/Config/ConfigManager.cs
+++ b/Main/Config/ConfigManager.cs
@@ -71,6 +71,7 @@
             typeof(StoreConfig),
             typeof(SuccessConfig),
             typeof(SysInfoConfig),
+            typeof(TianziConfig),
             typeof(TitleStarUpConfig),
             typeof(TreasureSetConfig),
             typeof(TreeLVConfig),
@@ -292,6 +293,8 @@
         ClearConfigDictionary<SuccessConfig>();
         // 娓呯┖ SysInfoConfig 瀛楀吀
         ClearConfigDictionary<SysInfoConfig>();
+        // 娓呯┖ TianziConfig 瀛楀吀
+        ClearConfigDictionary<TianziConfig>();
         // 娓呯┖ TitleStarUpConfig 瀛楀吀
         ClearConfigDictionary<TitleStarUpConfig>();
         // 娓呯┖ TreasureSetConfig 瀛楀吀
diff --git a/Main/Config/Configs/NPCConfig.cs b/Main/Config/Configs/NPCConfig.cs
index c67fc02..8681919 100644
--- a/Main/Config/Configs/NPCConfig.cs
+++ b/Main/Config/Configs/NPCConfig.cs
@@ -1,6 +1,6 @@
 锘�//--------------------------------------------------------
 //    [Author]:           YYL
-//    [  Date ]:           2025骞�10鏈�17鏃�
+//    [  Date ]:           2025骞�10鏈�24鏃�
 //--------------------------------------------------------
 
 using System.Collections.Generic;
@@ -18,6 +18,7 @@
 
     public int NPCID;
 	public string NPCName;
+	public int RelatedHeroID;
 	public int LV;
 	public int SkinID;
 	public float ModelScale;
@@ -37,13 +38,15 @@
 
 			NPCName = tables[1];
 
-			int.TryParse(tables[2],out LV); 
+			int.TryParse(tables[2],out RelatedHeroID); 
 
-			int.TryParse(tables[3],out SkinID); 
+			int.TryParse(tables[3],out LV); 
 
-			float.TryParse(tables[4],out ModelScale); 
+			int.TryParse(tables[4],out SkinID); 
 
-			int.TryParse(tables[5],out LifeBarCount); 
+			float.TryParse(tables[5],out ModelScale); 
+
+			int.TryParse(tables[6],out LifeBarCount); 
         }
         catch (Exception exception)
         {
diff --git a/Main/Config/Configs/TianziConfig.cs b/Main/Config/Configs/TianziConfig.cs
new file mode 100644
index 0000000..597fc23
--- /dev/null
+++ b/Main/Config/Configs/TianziConfig.cs
@@ -0,0 +1,59 @@
+锘�//--------------------------------------------------------
+//    [Author]:           YYL
+//    [  Date ]:           2025骞�10鏈�28鏃�
+//--------------------------------------------------------
+
+using System.Collections.Generic;
+using System;
+using UnityEngine;
+using LitJson;
+
+public partial class TianziConfig : ConfigBase<int, TianziConfig>
+{
+    static TianziConfig()
+    {
+        // 璁块棶杩囬潤鎬佹瀯閫犲嚱鏁�
+        visit = true; 
+    }
+
+    public int ID;
+	public int BossID;
+	public int HPNum;
+	public int Atk;
+	public int Def;
+	public long MaxHP;
+	public string OtherAttrDict;
+	public int[][] RandWeightItemList;
+
+    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 ID); 
+
+			int.TryParse(tables[1],out BossID); 
+
+			int.TryParse(tables[2],out HPNum); 
+
+			int.TryParse(tables[3],out Atk); 
+
+			int.TryParse(tables[4],out Def); 
+
+			long.TryParse(tables[5],out MaxHP); 
+
+			OtherAttrDict = tables[6];
+
+			RandWeightItemList = JsonMapper.ToObject<int[][]>(tables[7].Replace("(", "[").Replace(")", "]")); 
+        }
+        catch (Exception exception)
+        {
+            Debug.LogError(exception);
+        }
+    }
+}
diff --git a/Main/Config/Configs/TianziConfig.cs.meta b/Main/Config/Configs/TianziConfig.cs.meta
new file mode 100644
index 0000000..b1d12f0
--- /dev/null
+++ b/Main/Config/Configs/TianziConfig.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c157a3f99bdd3ca4a9311a1438687170
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Config/PartialConfigs/DungeonConfig.cs b/Main/Config/PartialConfigs/DungeonConfig.cs
index 2c1bab2..73a6e08 100644
--- a/Main/Config/PartialConfigs/DungeonConfig.cs
+++ b/Main/Config/PartialConfigs/DungeonConfig.cs
@@ -18,8 +18,8 @@
         return dungeonIndexDict.TryGetValue(mapID, out var dict) && dict.TryGetValue(lineID, out dungeonID);
     }
 
-    public static Dictionary<int, Dictionary<int, int>> GetDungeonIndexDict()
+    public static bool TryGetDictByMapID(int mapID, out Dictionary<int, int> dict)
     {
-        return dungeonIndexDict;
+        return dungeonIndexDict.TryGetValue(mapID, out dict);
     }
 }
diff --git a/Main/Config/PartialConfigs/TianziConfig.cs b/Main/Config/PartialConfigs/TianziConfig.cs
new file mode 100644
index 0000000..42a2d3c
--- /dev/null
+++ b/Main/Config/PartialConfigs/TianziConfig.cs
@@ -0,0 +1,136 @@
+
+
+using System.Collections.Generic;
+using System.Linq;
+
+public partial class TianziConfig : ConfigBase<int, TianziConfig>
+{
+    //<BossID<HPNum,TianziConfig>>
+    private static Dictionary<int, Dictionary<int, TianziConfig>> bossIDAllInfoDict = new Dictionary<int, Dictionary<int, TianziConfig>>();
+    protected override void OnConfigParseCompleted()
+    {
+        if (!bossIDAllInfoDict.ContainsKey(BossID))
+        {
+            bossIDAllInfoDict[BossID] = new Dictionary<int, TianziConfig>();
+        }
+        bossIDAllInfoDict[BossID][HPNum] = this;
+    }
+
+    public static bool TryGetAllInfoDictByBossID(int BossID, out Dictionary<int, TianziConfig> dict)
+    {
+        return bossIDAllInfoDict.TryGetValue(BossID, out dict);
+    }
+
+    public static bool TryGetTianziConfigByBossIDAndHPNum(int BossID, int HPNum, out TianziConfig tianziConfig)
+    {
+        tianziConfig = null;
+        if (bossIDAllInfoDict.TryGetValue(BossID, out var hpDict))
+        {
+            if (hpDict.TryGetValue(HPNum, out tianziConfig))
+            {
+                return true;
+            }
+        }
+        return false;
+    }
+
+    public static bool TryGetTianziConfigByBossIDAndMaxHP(int BossID, long MaxHP, out TianziConfig tianziConfig)
+    {
+        tianziConfig = null;
+        if (bossIDAllInfoDict.TryGetValue(BossID, out var hpDict))
+        {
+            foreach (var item in hpDict.Values)
+            {
+                if (item.MaxHP == MaxHP)
+                {
+                    tianziConfig = Get(item.ID);
+                    return true;
+                }
+            }
+        }
+        return false;
+    }
+
+    /// <summary>
+    /// 鏍规嵁浼犲叆鐨勪激瀹宠绠楀綋鍓嶆槸鍝釜琛�鏉★紝杩斿洖瀵瑰簲鐨凾ianziConfig
+    /// </summary>
+    /// <param name="BossID">Boss ID</param>
+    /// <param name="damage">绱浼ゅ鍊�</param>
+    /// <param name="tianziConfig">杩斿洖鐨凾ianziConfig</param>
+    /// <returns>鏄惁鎴愬姛鎵惧埌瀵瑰簲鐨勮鏉¢厤缃�</returns>
+    public static bool TryGetTianziConfigByBossIDAndDamage(int BossID, ulong damage, out TianziConfig tianziConfig)
+    {
+        tianziConfig = null;
+
+        if (!bossIDAllInfoDict.TryGetValue(BossID, out var hpDict))
+            return false;
+
+        // 鎸夎鏉$紪鍙锋帓搴忥紝浠庡皬鍒板ぇ璁$畻绱鐢熷懡鍊�
+        var sortedHPNums = hpDict.Keys.ToList();
+        sortedHPNums.Sort();
+
+        ulong accumulatedHP = 0;
+        foreach (int hpNum in sortedHPNums)
+        {
+            if (!hpDict.TryGetValue(hpNum, out var config))
+                continue;
+
+            // 绱鐢熷懡鍊�
+            accumulatedHP += (ulong)config.MaxHP;
+
+            // 濡傛灉浼ゅ <= 绱鐢熷懡鍊硷紝璇存槑褰撳墠琛�鏉″氨鏄繖涓�
+            if (damage <= accumulatedHP)
+            {
+                tianziConfig = Get(config.ID);
+                return true;
+            }
+        }
+
+        // 濡傛灉浼ゅ >= 鎵�鏈夎鏉$殑鎬荤敓鍛藉�硷紝杩斿洖鏈�鍚庝竴涓鏉�
+        if (sortedHPNums.Count > 0)
+        {
+            var lastHPNum = sortedHPNums[sortedHPNums.Count - 1];
+            if (hpDict.TryGetValue(lastHPNum, out var lastConfig))
+            {
+                tianziConfig = Get(lastConfig.ID);
+                return true;
+            }
+        }
+
+        return false;
+    }
+
+
+    public static ulong GetCurrentHPDamage(int BossID, ulong totalDamage)
+    {
+
+        if (!bossIDAllInfoDict.TryGetValue(BossID, out var hpDict))
+            return 0;
+
+        var sortedHPNums = hpDict.Keys.ToList();
+        sortedHPNums.Sort();
+
+        ulong accumulatedHP = 0;
+        ulong previousAccumulatedHP = 0;
+
+        foreach (int hpNum in sortedHPNums)
+        {
+            if (!hpDict.TryGetValue(hpNum, out var config))
+                continue;
+
+            // 绱鐢熷懡鍊�
+            previousAccumulatedHP = accumulatedHP;
+            accumulatedHP += (ulong)config.MaxHP;
+
+            // 濡傛灉鎬讳激瀹� <= 绱鐢熷懡鍊硷紝璇存槑褰撳墠琛�鏉″氨鏄繖涓�
+            if (totalDamage <= accumulatedHP)
+            {
+                // 瀵瑰綋鍓嶈鏉¢�犳垚鐨勪激瀹� = 鎬讳激瀹� - 涔嬪墠琛�鏉$殑鎬荤敓鍛藉��
+                ulong currentHPDamage = totalDamage - previousAccumulatedHP;
+                return currentHPDamage;
+            }
+        }
+        return totalDamage - accumulatedHP;
+    }
+
+}
diff --git a/Main/Config/PartialConfigs/TianziConfig.cs.meta b/Main/Config/PartialConfigs/TianziConfig.cs.meta
new file mode 100644
index 0000000..3c63bb3
--- /dev/null
+++ b/Main/Config/PartialConfigs/TianziConfig.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 78c01f83db1dcb54493c13af7086637f
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Core/NetworkPackage/DTCFile/ServerPack/H03_MainCharacter/DTC0320_tagFBEnd.cs b/Main/Core/NetworkPackage/DTCFile/ServerPack/H03_MainCharacter/DTC0320_tagFBEnd.cs
index 18410c3..ec94251 100644
--- a/Main/Core/NetworkPackage/DTCFile/ServerPack/H03_MainCharacter/DTC0320_tagFBEnd.cs
+++ b/Main/Core/NetworkPackage/DTCFile/ServerPack/H03_MainCharacter/DTC0320_tagFBEnd.cs
@@ -8,5 +8,6 @@
         base.Done(vNetPack);
         H0320_tagFBEnd vNetData = vNetPack as H0320_tagFBEnd;
         BoneFieldManager.Instance.UpdateFBEnd(vNetData);
+        TianziBillboradManager.Instance.UpdateFBEnd(vNetData);
     }
 }
diff --git a/Main/Core/NetworkPackage/DTCFile/ServerPack/HB2_ActionMap.meta b/Main/Core/NetworkPackage/DTCFile/ServerPack/HB2_ActionMap.meta
new file mode 100644
index 0000000..c18cfdb
--- /dev/null
+++ b/Main/Core/NetworkPackage/DTCFile/ServerPack/HB2_ActionMap.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: e956e1ea8a1bd304890b23f7228a9e4c
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Core/NetworkPackage/DTCFile/ServerPack/HB2_ActionMap/DTCB201_tagSCTianziKYInfo.cs b/Main/Core/NetworkPackage/DTCFile/ServerPack/HB2_ActionMap/DTCB201_tagSCTianziKYInfo.cs
new file mode 100644
index 0000000..751cc61
--- /dev/null
+++ b/Main/Core/NetworkPackage/DTCFile/ServerPack/HB2_ActionMap/DTCB201_tagSCTianziKYInfo.cs
@@ -0,0 +1,12 @@
+using UnityEngine;
+using System.Collections;
+
+// B2 01 澶╁瓙鑰冮獙淇℃伅 #tagSCTianziKYInfo
+
+public class DTCB201_tagSCTianziKYInfo : DtcBasic {
+    public override void Done(GameNetPackBasic vNetPack) {
+        base.Done(vNetPack);
+        HB201_tagSCTianziKYInfo vNetData = vNetPack as HB201_tagSCTianziKYInfo;
+        TianziBillboradManager.Instance.UpdateTianziKYInfo(vNetData);
+    }
+}
diff --git a/Main/Core/NetworkPackage/DTCFile/ServerPack/HB2_ActionMap/DTCB201_tagSCTianziKYInfo.cs.meta b/Main/Core/NetworkPackage/DTCFile/ServerPack/HB2_ActionMap/DTCB201_tagSCTianziKYInfo.cs.meta
new file mode 100644
index 0000000..a1fbb19
--- /dev/null
+++ b/Main/Core/NetworkPackage/DTCFile/ServerPack/HB2_ActionMap/DTCB201_tagSCTianziKYInfo.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8c47281476c6caf44994a8bbb384f2a7
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Core/NetworkPackage/DataToCtl/PackageRegedit.cs b/Main/Core/NetworkPackage/DataToCtl/PackageRegedit.cs
index c8e669b..81e9230 100644
--- a/Main/Core/NetworkPackage/DataToCtl/PackageRegedit.cs
+++ b/Main/Core/NetworkPackage/DataToCtl/PackageRegedit.cs
@@ -119,6 +119,7 @@
         Register(typeof(HA922_tagSCArenaMatchList), typeof(DTCA922_tagSCArenaMatchList));
         Register(typeof(HA923_tagSCArenaPlayerInfo), typeof(DTCA923_tagSCArenaPlayerInfo));
         Register(typeof(HB109_tagSCDailyTaskInfo), typeof(DTCB109_tagSCDailyTaskInfo));
+        Register(typeof(HB201_tagSCTianziKYInfo), typeof(DTCB201_tagSCTianziKYInfo));
     }
 
     //涓诲伐绋嬫敞鍐屽皝鍖�
diff --git a/Main/Core/NetworkPackage/ServerPack/HB2_ActionMap.meta b/Main/Core/NetworkPackage/ServerPack/HB2_ActionMap.meta
new file mode 100644
index 0000000..27424a1
--- /dev/null
+++ b/Main/Core/NetworkPackage/ServerPack/HB2_ActionMap.meta
@@ -0,0 +1,8 @@
+fileFormatVersion: 2
+guid: a0f8b16704633e541aef7538d8ca2e6b
+folderAsset: yes
+DefaultImporter:
+  externalObjects: {}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Core/NetworkPackage/ServerPack/HB2_ActionMap/HB201_tagSCTianziKYInfo.cs b/Main/Core/NetworkPackage/ServerPack/HB2_ActionMap/HB201_tagSCTianziKYInfo.cs
new file mode 100644
index 0000000..f6dbc58
--- /dev/null
+++ b/Main/Core/NetworkPackage/ServerPack/HB2_ActionMap/HB201_tagSCTianziKYInfo.cs
@@ -0,0 +1,25 @@
+using UnityEngine;
+using System.Collections;
+
+// B2 01 澶╁瓙鑰冮獙淇℃伅 #tagSCTianziKYInfo
+
+public class HB201_tagSCTianziKYInfo : GameNetPackBasic {
+    public byte LineID;    //浠婃棩鏄摢涓猯ineID锛屽搴斿壇鏈〃鐨勫姛鑳界嚎璺疘D
+    public uint HistoryHurt;    //鏈�冮獙鍘嗗彶鏈�澶т激瀹筹紝姹備綑浜块儴鍒�
+    public uint HistoryHurtEx;    //鏈�冮獙鍘嗗彶鏈�澶т激瀹筹紝鏁撮櫎浜块儴鍒�
+    public uint TodayHurt;    //鏈�冮獙浠婃棩鏈�澶т激瀹筹紝姹備綑浜块儴鍒�
+    public uint TodayHurtEx;    //鏈�冮獙浠婃棩鏈�澶т激瀹筹紝鏁撮櫎浜块儴鍒�
+
+    public HB201_tagSCTianziKYInfo () {
+        _cmd = (ushort)0xB201;
+    }
+
+    public override void ReadFromBytes (byte[] vBytes) {
+        TransBytes (out LineID, vBytes, NetDataType.BYTE);
+        TransBytes (out HistoryHurt, vBytes, NetDataType.DWORD);
+        TransBytes (out HistoryHurtEx, vBytes, NetDataType.DWORD);
+        TransBytes (out TodayHurt, vBytes, NetDataType.DWORD);
+        TransBytes (out TodayHurtEx, vBytes, NetDataType.DWORD);
+    }
+
+}
diff --git a/Main/Core/NetworkPackage/ServerPack/HB2_ActionMap/HB201_tagSCTianziKYInfo.cs.meta b/Main/Core/NetworkPackage/ServerPack/HB2_ActionMap/HB201_tagSCTianziKYInfo.cs.meta
new file mode 100644
index 0000000..5e06870
--- /dev/null
+++ b/Main/Core/NetworkPackage/ServerPack/HB2_ActionMap/HB201_tagSCTianziKYInfo.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: e11b3a9a5992d644db0e2626ac7dd9ca
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/Main.cs b/Main/Main.cs
index 88c6ada..98041ca 100644
--- a/Main/Main.cs
+++ b/Main/Main.cs
@@ -83,7 +83,7 @@
         managers.Add(ArenaManager.Instance);
         managers.Add(DayMissionManager.Instance);
         managers.Add(BattlePassManager.Instance);
-        
+        managers.Add(TianziBillboradManager.Instance);
         foreach (var manager in managers)
         {
             manager.Init();
diff --git a/Main/System/Battle/BattleConst.cs b/Main/System/Battle/BattleConst.cs
index 62c1b86..266ac7d 100644
--- a/Main/System/Battle/BattleConst.cs
+++ b/Main/System/Battle/BattleConst.cs
@@ -10,6 +10,7 @@
         typeof(StoryBossBattleWin),
         typeof(ArenaBattleWin),
         typeof(BoneFieldBattleWin),
+        typeof(TianziBillboradBattleWin),
     };
 
     public static Dictionary<string, string> battleNameToWinName = new Dictionary<string, string>()
@@ -18,6 +19,7 @@
         { "StoryBossBattleField", "StoryBossBattleWin" },
         { "ArenaBattleField", "ArenaBattleWin" },
         { "BoneBattleField", "BoneFieldBattleWin" },
+        { "TianziBillboradBattleField", "TianziBillboradBattleWin" },
     };
 
     public const int BattleStartEffectID = 1001; // Example effect ID for battle start
diff --git a/Main/System/Battle/BattleField/TianziBillboradBattleField.cs b/Main/System/Battle/BattleField/TianziBillboradBattleField.cs
new file mode 100644
index 0000000..2f39395
--- /dev/null
+++ b/Main/System/Battle/BattleField/TianziBillboradBattleField.cs
@@ -0,0 +1,142 @@
+using LitJson;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+
+public class TianziBillboradBattleField : BattleField
+{
+    protected JsonData extendData;
+    protected MainLevelConfig levelConfig;
+    public TianziBillboradBattleField(string _guid) : base(_guid)
+    {
+
+    }
+
+    public override void Init(int MapID, int FuncLineID, JsonData _extendData,
+        List<TeamBase> _redTeamList, List<TeamBase> _blueTeamList, byte turnMax)
+    {
+        base.Init(MapID, FuncLineID, extendData, _redTeamList, _blueTeamList, turnMax);
+
+        int level = FuncLineID;// 鍏冲崱
+        extendData = _extendData;
+        levelConfig = MainLevelConfig.Get(level);
+
+        SetBattleMode(BattleMode.Record);
+    }
+
+    public override void AutoSetBattleMode()
+    {
+        SetBattleMode(BattleMode.Record);
+    }
+
+    public override void TurnFightState(int TurnNum, int State,
+        uint FuncLineID, JsonData extendData)
+    {
+        base.TurnFightState(TurnNum, State, FuncLineID, extendData);
+
+        switch (State)
+        {
+            //  璧峰鐘舵�佹爣璁�
+            case 0:
+                break;
+            case 1://鍑嗗瀹屾瘯
+                break;
+            case 2://鎴樻枟涓�
+                break;
+            case 3://鎴樻枟缁撴潫
+                break;
+            case 4://缁撶畻濂栧姳
+                if (extendData != null && extendData.ContainsKey("totalHurt"))
+                {
+                    ulong totalHurt = ulong.Parse(extendData["totalHurt"].ToString());
+                    TianziBillboradBattleWin.TianziDamageBarEndDataAction?.Invoke(totalHurt);
+                }
+                break;
+            case 5://缁撴潫鐘舵�佹爣璁�
+                break;
+            default:
+                BattleDebug.LogError("recieve a unknown State");
+                break;
+        }
+    }
+
+    protected override void OnSettlement(JsonData turnFightStateData)
+    {
+        base.OnSettlement(turnFightStateData);
+    }
+
+    public override void WhaleFall()
+    {
+        AutoFightModel.Instance.isPause = false;
+        Destroy();
+
+        if (UIManager.Instance.IsOpened<TianziBillboradBattleWin>())
+        {
+            UIManager.Instance.CloseWindow<TianziBillboradBattleWin>();
+            UIManager.Instance.OpenWindow<TianziBillboradWin>();
+        }
+    }
+
+    public override void Run()
+    {
+        if (operationAgent == null)
+        {
+            //闃茶寖寮傚父
+            return;
+        }
+        base.Run();
+    }
+
+    public override void DistributeNextPackage()
+    {
+        if (IsBattleFinish)
+            return;
+
+        //  涓嶈璋冪敤base鐨勫嚱鏁�
+        BattleManager.Instance.DistributeNextReportPackage(guid);
+    }
+
+    public override void ShowWindow(HB424_tagSCTurnFightInit vNetData)
+    {
+        TianziBillboradBattleWin fsBattleWin = UIManager.Instance.GetUI<TianziBillboradBattleWin>();// as FullScreenBattleWin;
+        if (null == fsBattleWin)
+        {
+            fsBattleWin = UIManager.Instance.OpenWindow<TianziBillboradBattleWin>();
+        }
+        fsBattleWin.SetBattleField(this);
+
+        if (UIManager.Instance.IsOpened<TianziBillboradWin>())
+        {
+            UIManager.Instance.CloseWindow<TianziBillboradWin>();
+        }
+    }
+
+    public NPCLineupConfig GetBossLineupConfig()
+    {
+        if (!DungeonConfig.TryGetDungeonID(MapID, FuncLineID, out int dungeonID))
+            return null;
+        if (!DungeonConfig.HasKey(dungeonID))
+            return null;
+        int[] lineupIDList = DungeonConfig.Get(dungeonID).LineupIDList;
+        if (lineupIDList.IsNullOrEmpty())
+            return null;
+        int lineupID = lineupIDList[0];
+        if (!NPCLineupConfig.HasKey(lineupID))
+            return null;
+        NPCLineupConfig nPCLineupConfig = NPCLineupConfig.Get(lineupID);
+
+        return nPCLineupConfig;
+    }
+
+    public override BattleObject FindBoss()
+    {
+        var config = GetBossLineupConfig();
+        if (config != null)
+        {
+            int bossId = config.BossID;
+            BattleObject bo = battleObjMgr.allBattleObjDict.Values.FirstOrDefault(bo => bo.teamHero.NPCID == bossId);
+            return bo;
+        }
+        return null;
+    }
+}
\ No newline at end of file
diff --git a/Main/System/Battle/BattleField/TianziBillboradBattleField.cs.meta b/Main/System/Battle/BattleField/TianziBillboradBattleField.cs.meta
new file mode 100644
index 0000000..03344b5
--- /dev/null
+++ b/Main/System/Battle/BattleField/TianziBillboradBattleField.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c9799b3f52f4bd442b3952bdec14c779
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/Battle/BattleFieldFactory.cs b/Main/System/Battle/BattleFieldFactory.cs
index 35a7ad8..b12531c 100644
--- a/Main/System/Battle/BattleFieldFactory.cs
+++ b/Main/System/Battle/BattleFieldFactory.cs
@@ -26,6 +26,9 @@
             case 30010:
                 battleField = new BoneBattleField(guid);
                 break;
+            case 30020:
+                battleField = new TianziBillboradBattleField(guid);
+                break;
             default:
                 break;
         }
diff --git a/Main/System/Battle/BattleObject/BattleObject.cs b/Main/System/Battle/BattleObject/BattleObject.cs
index 9941d87..266ee05 100644
--- a/Main/System/Battle/BattleObject/BattleObject.cs
+++ b/Main/System/Battle/BattleObject/BattleObject.cs
@@ -162,6 +162,10 @@
 
     public void OnObjInfoRefresh(H0418_tagObjInfoRefresh _refreshInfo)
     {
+        // 澶╁瓙鐨勬寫鎴樻嫤鎴鏉¢�昏緫
+        BattleObject boss = battleField.FindBoss();
+        if (boss != null && battleField.MapID == 30020 && boss.ObjID == _refreshInfo.ObjID)
+            return;
         switch ((PlayerDataType)_refreshInfo.RefreshType)
         {
             case PlayerDataType.HP:
@@ -186,6 +190,10 @@
 
     public void ObjPropertyRefreshView(HB418_tagSCObjPropertyRefreshView vNetData)
     {
+        // 澶╁瓙鐨勬寫鎴樻嫤鎴鏉¢�昏緫
+        BattleObject boss = battleField.FindBoss();
+        if (boss != null && battleField.MapID == 30020 && boss.ObjID == vNetData.ObjID)
+            return;
         switch ((PlayerDataType)vNetData.RefreshType)
         {
             case PlayerDataType.HP:
@@ -324,7 +332,7 @@
                 PushDropItems(battleHurtParam.battleDrops);
             }
             battleField.OnObjsDead(new List<HB422_tagMCTurnFightObjDead>() { battleHurtParam.deadPack });
-            
+
         }
         else
         {
@@ -411,13 +419,23 @@
     protected virtual BattleDmgInfo PopDamage(BattleHurtParam battleHurtParam)
     {
         BattleDmgInfo battleDmgInfo = new BattleDmgInfo(battleField.guid, battleHurtParam);
+        // 澶╁瓙鐨勬寫鎴樻嫤鎴鏉¢�昏緫
+        BattleObject boss = battleField.FindBoss();
+        if (boss != null && battleField.MapID == 30020 && boss.ObjID == battleHurtParam.hurtObj.ObjID)
+        {
+            EventBroadcast.Instance.Broadcast(EventName.BATTLE_DAMAGE_TAKEN, battleDmgInfo);
+            return battleDmgInfo;
+        }
+        else
+        {
+            // 浣跨敤浼犲叆鐨� fromHp 鍜� toHp 鏇存柊琛�鏉℃樉绀�
+            heroInfoBar.UpdateHP(battleHurtParam.fromHp, battleHurtParam.toHp, teamHero.maxHp);
 
-        // 浣跨敤浼犲叆鐨� fromHp 鍜� toHp 鏇存柊琛�鏉℃樉绀�
-        heroInfoBar.UpdateHP(battleHurtParam.fromHp, battleHurtParam.toHp, teamHero.maxHp);
+            // YYL TODO 鏄惁闇�瑕佹寕鍦ㄥ湪鑷韩鐨刦ollow鐐逛笂
+            EventBroadcast.Instance.Broadcast(EventName.BATTLE_DAMAGE_TAKEN, battleDmgInfo);
+            return battleDmgInfo;
+        }
 
-        // YYL TODO 鏄惁闇�瑕佹寕鍦ㄥ湪鑷韩鐨刦ollow鐐逛笂
-        EventBroadcast.Instance.Broadcast(EventName.BATTLE_DAMAGE_TAKEN, battleDmgInfo);
-        return battleDmgInfo;
     }
 
     public RectTransform GetAliasTeamNode()
diff --git a/Main/System/Battle/TianziBillboradBattleWin.cs b/Main/System/Battle/TianziBillboradBattleWin.cs
new file mode 100644
index 0000000..dc5beea
--- /dev/null
+++ b/Main/System/Battle/TianziBillboradBattleWin.cs
@@ -0,0 +1,346 @@
+锘縰sing System;
+using System.Collections.Generic;
+using Cysharp.Threading.Tasks;
+using LitJson;
+using UnityEngine;
+using UnityEngine.UI;
+
+public class TianziBillboradBattleWin : BaseBattleWin
+{
+    [SerializeField] Transform transButtons;
+    [SerializeField] public TianziDamageBar tianziDamageBar;
+    [SerializeField] public SkillWordCell[] skillWordCells;
+    [SerializeField] public BossHeadCell bossHeadCell;
+    [SerializeField] public Text txtBossName;
+    [SerializeField] HeroCountryComponent myCountry;
+    [SerializeField] HeroCountryComponent enemyCountry;
+    private BattleObject bossBattleObject = null;
+    [SerializeField] public List<BattleBuffCell> buffCells;
+    [SerializeField] RectTransform rectBoxEnd;
+    [SerializeField] UIEffectPlayer uiEffectPlayer;
+
+    public static Action<ulong> TianziDamageBarEndDataAction;
+
+    protected override void OnPreOpen()
+    {
+        base.OnPreOpen();
+        tianziDamageBar.StageUp += OnStageUp;
+        tianziDamageBar.ValueChangeAction += OnValueChangeAction;
+        tianziDamageBar.ChangeEndAction += OnChangeEndAction;
+        //tianziDamageBar.IsLastHitUnLockEvent += OnIsLastHitUnLockEvent;
+        TianziDamageBarEndDataAction += OnTianziDamageBarEndData;
+        MainWin.TabChangeEvent += OnTabChangeEvent;
+        EventBroadcast.Instance.AddListener<string, JsonData>(EventName.BATTLE_END, OnSettlement);
+        EventBroadcast.Instance.AddListener<HB419_tagSCObjHPRefresh>(EventName.BATTLE_TIANZI_REFRESH_HP, OnUpdateHpNum);
+        bool isOpenBattleChangeTab = IsOpenBattleChangeTab();
+        transButtons.localPosition = new Vector3(0, isOpenBattleChangeTab ? 130 : 0, 0);
+        if (isOpenBattleChangeTab)
+        {
+            UIManager.Instance.GetUI<MainWin>()?.CloseSubUI();
+        }
+        else
+        {
+            UIManager.Instance.CloseWindow<MainWin>();
+        }
+    }
+
+    protected override void OnPreClose()
+    {
+        base.OnPreClose();
+        tianziDamageBar.StageUp -= OnStageUp;
+        tianziDamageBar.ValueChangeAction -= OnValueChangeAction;
+        tianziDamageBar.ChangeEndAction += OnChangeEndAction;
+        //tianziDamageBar.IsLastHitUnLockEvent += OnIsLastHitUnLockEvent;
+        TianziDamageBarEndDataAction -= OnTianziDamageBarEndData;
+        MainWin.TabChangeEvent -= OnTabChangeEvent;
+        EventBroadcast.Instance.RemoveListener<string, JsonData>(EventName.BATTLE_END, OnSettlement);
+        EventBroadcast.Instance.RemoveListener<HB419_tagSCObjHPRefresh>(EventName.BATTLE_TIANZI_REFRESH_HP, OnUpdateHpNum);
+        bool isOpenBattleChangeTab = IsOpenBattleChangeTab();
+        if (isOpenBattleChangeTab)
+        {
+            UIManager.Instance.GetUI<MainWin>()?.RestoreSubUI();
+        }
+        else
+        {
+            UIManager.Instance.OpenWindow<MainWin>();
+        }
+
+        if (bossBattleObject != null)
+        {
+            if (bossBattleObject.buffMgr != null)
+            {
+                bossBattleObject.buffMgr.onBuffChanged -= OnBuffChanged;
+            }
+            bossBattleObject = null;
+        }
+
+    }
+
+
+
+    private void OnTianziDamageBarEndData(ulong obj)
+    {
+        tianziDamageBar.Show(obj);
+    }
+
+    private void OnStageUp(int stage)
+    {
+        GameObject hero = bossBattleObject.heroGo;
+        if (hero == null || stage <= 1)
+            return;
+        uiEffectPlayer.Play();
+
+        GameObject prefab = UIUtility.CreateWidget("TianziBillboradBox", "TianziBillboradBox");
+        prefab.transform.SetParentEx(hero.transform, Vector3.zero, Quaternion.identity, Vector3.one);
+        TianziBillboradBox boxAnimator = prefab.GetComponent<TianziBillboradBox>();
+        if (boxAnimator != null)
+        {
+            Vector3 startPos = hero.transform.position;
+            Vector3 endPos = rectBoxEnd.position;
+            boxAnimator.StartAnimation(startPos, endPos);
+        }
+        else
+        {
+            Destroy(prefab);
+        }
+    }
+
+    private void OnTabChangeEvent()
+    {
+        CloseWindow();
+    }
+
+    protected override void OnCreateBattleField(string guid, BattleField field)
+    {
+        if (field is TianziBillboradBattleField)
+        {
+            SetBattleField(field);
+        }
+    }
+
+    protected override void RefreshSpecific()
+    {
+        DestroyExistingTianziBillboradBoxes();
+        TianziBillboradBattleField boneField = battleField as TianziBillboradBattleField;
+        if (boneField == null) return;
+
+        NPCLineupConfig lineupConfig = boneField.GetBossLineupConfig();
+
+        if (bossBattleObject != null)
+        {
+            if (bossBattleObject.buffMgr != null)
+            {
+                bossBattleObject.buffMgr.onBuffChanged -= OnBuffChanged;
+            }
+            bossBattleObject = null;
+        }
+
+        bossBattleObject = boneField.FindBoss();
+
+        DisplaySkillWordsList(lineupConfig);
+
+        hpB419 = 0;
+        maxHpB419 = 0;
+        tianziDamageBar.Init();
+
+        if (null != bossBattleObject)
+        {
+            TeamHero teamHero = bossBattleObject.teamHero;
+            bossHeadCell.SetTeamHero(teamHero);
+            txtBossName.text = teamHero.name;
+            NPCConfig npcConfig = NPCConfig.Get(teamHero.NPCID);
+            bossBattleObject.buffMgr.onBuffChanged -= OnBuffChanged;
+            bossBattleObject.buffMgr.onBuffChanged += OnBuffChanged;
+        }
+        else
+        {
+            bossHeadCell.SetTeamHero(null);
+            txtBossName.text = string.Empty;
+            Debug.LogError("鎵句笉鍒癰oss");
+        }
+
+        OnRoundChange(battleField.round, battleField.turnMax); // 纭繚鍥炲悎鏄剧ず琚皟鐢�
+        OnBuffChanged();
+
+        // 鑾峰彇鎴戞柟锛堢孩鏂癸級闃熶紞鏁版嵁
+        List<BattleObject> myTeam = battleField.battleObjMgr.GetBattleObjList(BattleCamp.Red);
+        // 鑾峰彇鏁屾柟锛堣摑鏂癸級闃熶紞鏁版嵁
+        List<BattleObject> enemyTeam = battleField.battleObjMgr.GetBattleObjList(BattleCamp.Blue);
+
+        myCountry.RefreshOnTeamCountry(GetTeamHeroList(myTeam), true);
+        enemyCountry.RefreshOnTeamCountry(GetTeamHeroList(enemyTeam), true);
+    }
+
+    private void DestroyExistingTianziBillboradBoxes()
+    {
+        // 鏌ユ壘鍦烘櫙涓墍鏈夊瓨鍦ㄧ殑TianziBillboradBox瀹炰緥
+        TianziBillboradBox[] existingBoxes = FindObjectsOfType<TianziBillboradBox>();
+        foreach (TianziBillboradBox box in existingBoxes)
+        {
+            if (box != null && box.gameObject != null)
+            {
+                Destroy(box.gameObject);
+            }
+        }
+    }
+
+    private void OnBuffChanged()
+    {
+        var buffList = new List<HB428_tagSCBuffRefresh>();
+        if (null != bossBattleObject)
+        {
+            buffList = bossBattleObject.buffMgr.GetBuffList();
+        }
+        RefreshBuff(buffList);
+    }
+
+    private void OnSettlement(string _guid, JsonData data)
+    {
+        if (string.Empty == _guid)
+            return;
+        var battle = BattleManager.Instance.GetBattleField(_guid);
+        if (battle == null)
+            return;
+        var battleName = battle.ToString();
+        if (battleName != "TianziBillboradBattleField")
+            return;
+
+        if (data != null && data.ContainsKey("totalHurt"))
+        {
+            ulong totalHurt = ulong.Parse(data["totalHurt"].ToString());
+            tianziDamageBar.Show(totalHurt);
+        }
+    }
+
+    private void OnIsLastHitUnLockEvent()
+    {
+        if (bossBattleObject == null)
+            return;
+
+        bossBattleObject.teamHero.curHp = (long)hpB419;
+        bossBattleObject.teamHero.maxHp = (long)maxHpB419;
+        Debug.Log($"TianziDamageBar OnIsLastHitUnLockEvent hpB419 {hpB419} maxHpB419 {maxHpB419}");
+    }
+
+    ulong hpB419;
+    ulong maxHpB419;
+    private void OnUpdateHpNum(HB419_tagSCObjHPRefresh info)
+    {
+        if (bossBattleObject == null || info.ObjID != bossBattleObject.ObjID)
+            return;
+        ulong curHp = (ulong)GeneralDefine.GetFactValue(info.HP, info.HPEx);
+        ulong maxHp = (ulong)GeneralDefine.GetFactValue(info.MaxHP, info.MaxHPEx);
+        hpB419 = curHp;
+        maxHpB419 = maxHp;
+        //tianziDamageBar.ShowByB419(curHp, maxHp);
+    }
+
+    protected override void OnDamageTaken(BattleDmgInfo info)
+    {
+        base.OnDamageTaken(info);
+
+        if (battleField == null || info.battleFieldGuid != battleField.guid)
+            return;
+
+        if (bossBattleObject != null && info.hurtObj.ObjID == bossBattleObject.ObjID)
+        {
+
+            TeamHero teamHero = bossBattleObject.teamHero;
+            tianziDamageBar.Show(info);
+            //tianziDamageBar.Show((ulong)teamHero.curHp, (ulong)teamHero.maxHp, info);
+        }
+
+    }
+
+    private void OnValueChangeAction(float nowValue, int CurrentStage)
+    {
+        if (bossBattleObject == null || bossBattleObject.heroInfoBar == null)
+            return;
+        bossBattleObject.heroInfoBar.UpdateHP(nowValue);
+        //Debug.Log($"TianziDamageBar nowValue {nowValue} 鏃堕棿: {DateTime.Now:HH:mm:ss}");
+    }
+
+    private void OnChangeEndAction(ulong nowHunt, ulong nowHpMax)
+    {
+        if (bossBattleObject == null || bossBattleObject.heroInfoBar == null)
+            return;
+        if (nowHpMax > 0)
+        {
+            float percentage = Mathf.Clamp(nowHunt, 0, nowHpMax) / (float)nowHpMax;
+            bossBattleObject.heroInfoBar.UpdateHP(percentage);
+            //Debug.Log($"TianziDamageBar nowValue {percentage} 鏃堕棿: {DateTime.Now:HH:mm:ss}");
+        }
+    }
+
+
+    public void DisplaySkillWordsList(NPCLineupConfig lineUPConfig)
+    {
+        if (skillWordCells.IsNullOrEmpty())
+            return;
+
+        if (null == lineUPConfig)
+            return;
+
+        for (int i = 0; i < skillWordCells.Length; i++)
+        {
+            if (i < lineUPConfig.SkillIDExList.Length)
+            {
+                skillWordCells[i].SetActive(true);
+                int skillID = lineUPConfig.SkillIDExList[i];
+                skillWordCells[i].Init(skillID, () =>
+                {
+                    SmallTipWin.showText = Language.Get("SmallTipFomat", SkillConfig.Get(skillID)?.SkillName, SkillConfig.Get(skillID)?.Description);
+                    SmallTipWin.worldPos = CameraManager.uiCamera.ScreenToWorldPoint(Input.mousePosition);
+                    SmallTipWin.isDownShow = true;
+                    UIManager.Instance.OpenWindow<SmallTipWin>();
+                });
+            }
+            else
+            {
+                skillWordCells[i].SetActive(false);
+            }
+        }
+    }
+
+    public void RefreshBuff(List<HB428_tagSCBuffRefresh> datas)
+    {
+        if (buffCells.IsNullOrEmpty())
+            return;
+
+
+        for (int i = 0; i < buffCells.Count; i++)
+        {
+            if (i < datas.Count)
+            {
+                buffCells[i].SetActive(true);
+                HB428_tagSCBuffRefresh buffData = datas[i];
+                buffCells[i].Init(buffData, () =>
+                {
+                    //  鐐瑰嚮buff鍥炬爣 鏄剧ずbuff鎻忚堪/褰撳墠韬笂鎵�鏈塨uff
+                });
+            }
+            else
+            {
+                buffCells[i].SetActive(false);
+            }
+        }
+    }
+
+    bool IsOpenBattleChangeTab()
+    {
+        return FuncOpen.Instance.IsFuncOpen(ArenaManager.Instance.BattleChangeTabFuncId);
+    }
+
+    List<TeamHero> GetTeamHeroList(List<BattleObject> teams)
+    {
+        List<TeamHero> teamHeroes = new List<TeamHero>();
+        if (teams.IsNullOrEmpty())
+            return teamHeroes;
+        foreach (var item in teams)
+        {
+            teamHeroes.Add(item.teamHero);
+        }
+        return teamHeroes;
+
+    }
+}
diff --git a/Main/System/Battle/TianziBillboradBattleWin.cs.meta b/Main/System/Battle/TianziBillboradBattleWin.cs.meta
new file mode 100644
index 0000000..55c7ee4
--- /dev/null
+++ b/Main/System/Battle/TianziBillboradBattleWin.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 7e1803332c96b3d40af8e8958c6c2296
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/Battle/UIComp/BattleHeroInfoBar.cs b/Main/System/Battle/UIComp/BattleHeroInfoBar.cs
index 78e01a9..766e9ab 100644
--- a/Main/System/Battle/UIComp/BattleHeroInfoBar.cs
+++ b/Main/System/Battle/UIComp/BattleHeroInfoBar.cs
@@ -167,6 +167,15 @@
     }
 
     /// <summary>
+    /// !!!涓存椂鐨勭敤浜庡ぉ瀛愭洿鏂拌閲忔樉绀�,绛夋帴鍙e畬鍠勫悗鍒犻櫎
+    /// </summary>
+    public void UpdateHP(float value)
+    {
+        sliderHp.value = value; 
+        //Debug.Log("TianziDamageBar UpdateHP value:" + value);
+    }
+
+    /// <summary>
     /// 鏇存柊鎬掓皵鏄剧ず
     /// </summary>
     public void UpdateXP(long fromXp, long toXp, long maxXp, bool tween = true)
diff --git a/Main/System/BoneField/AdsManager.cs b/Main/System/BoneField/AdsManager.cs
index b3974b9..5033fc5 100644
--- a/Main/System/BoneField/AdsManager.cs
+++ b/Main/System/BoneField/AdsManager.cs
@@ -4,7 +4,7 @@
 {
     //<骞垮憡ID,浠婃棩宸查鍙栧箍鍛婂鍔辨鏁�>
     private Dictionary<int, int> adsInfoDict = new Dictionary<int, int>();
-    public event Action<int,int> OnAdsInfoListUpdateEvent;//ADID ADMapID
+    public event Action<int, int> OnAdsInfoListUpdateEvent;//ADID ADMapID
     public override void Init()
     {
         DTC0102_tagCDBPlayer.beforePlayerDataInitializeEvent += OnBeforePlayerDataInitializeEvent;
@@ -30,16 +30,22 @@
 
     public void PlayAds(int ADID)
     {
-        if (ADID == 1)
+        switch (ADID)
         {
-
-            int dataMapID = BoneFieldManager.Instance.DataMapID;
-            if (!DungeonManager.Instance.TryGetFBInfoByMapID(dataMapID, out var fbInfo))
-                return;
-            SendGetReward(ADID);
-            BoneFieldManager.Instance.SendBBeginFBWipeOut(dataMapID, (int)fbInfo.PassLineID);
+            case 1:
+                if (!DungeonManager.Instance.TryGetFBInfoByMapID(BoneFieldManager.Instance.DataMapID, out var fbInfo1))
+                    return;
+                SendGetReward(ADID);
+                BoneFieldManager.Instance.SendBBeginFBWipeOut(BoneFieldManager.Instance.DataMapID, (int)fbInfo1.PassLineID);
+                break;
+            case 2:
+            
+                if (!DungeonManager.Instance.TryGetFBInfoByMapID(TianziBillboradManager.Instance.DataMapID, out var fbInfo2))
+                    return;
+                SendGetReward(ADID);
+                BoneFieldManager.Instance.SendBBeginFBWipeOut(TianziBillboradManager.Instance.DataMapID, (int)fbInfo2.PassLineID);
+                break;
         }
-
     }
 
     public int GetADCntByADID(int ADID)
diff --git a/Main/System/ChallengeTab/TianziBillboradTabHandler.cs b/Main/System/ChallengeTab/TianziBillboradTabHandler.cs
new file mode 100644
index 0000000..490547d
--- /dev/null
+++ b/Main/System/ChallengeTab/TianziBillboradTabHandler.cs
@@ -0,0 +1,75 @@
+using System;
+using UnityEngine;
+
+public class TianziBillboradTabHandler : BaseChallengeTabHandler
+{
+    protected override int GetIndex() => 3;
+    protected override int GetOpenState() => 0; // 0=FuncID
+    protected override int GetFuncId() => TianziBillboradManager.Instance.funcId;
+    protected override int GetRedpointId() => MainRedDot.TianziBillboradRepoint;
+
+    protected override string GetCountInfo()
+    {
+        int count = TianziBillboradManager.Instance.GetRemainChallageCount();
+        return UIHelper.AppendColor(count > 0 ? TextColType.Green : TextColType.Red, Language.Get("Challenge01", count));
+    }
+
+    protected override Action GetOnClickAction()
+    {
+        return HandleBoneFieldNavigation;
+    }
+
+    private void HandleBoneFieldNavigation()
+    {
+        if (!FuncOpen.Instance.IsFuncOpen(GetFuncId(), true))
+            return;
+        UIManager.Instance.CloseWindow<ChallengeTabWin>();
+
+        BattleField battleField = BattleManager.Instance.GetBattleFieldByMapID(TianziBillboradManager.Instance.DataMapID);
+        if (battleField != null)
+        {
+            TianziBillboradBattleWin battleWin;
+            if (!UIManager.Instance.IsOpened<TianziBillboradBattleWin>())
+            {
+                battleWin = UIManager.Instance.OpenWindow<TianziBillboradBattleWin>();
+            }
+            else
+            {
+                battleWin = UIManager.Instance.GetUI<TianziBillboradBattleWin>();
+            }
+            battleWin.SetBattleField(battleField as TianziBillboradBattleField);
+        }
+        else
+        {
+            UIManager.Instance.OpenWindow<TianziBillboradWin>();
+        }
+    }
+
+    protected override void SubscribeToSpecificEvents()
+    {
+        DungeonManager.Instance.UpdateFBInfoChangeEvent += OnUpdateFBInfoChange;
+        AdsManager.Instance.OnAdsInfoListUpdateEvent += OnAdsInfoListUpdate;
+    }
+
+    protected override void UnsubscribeFromSpecificEvents()
+    {
+        DungeonManager.Instance.UpdateFBInfoChangeEvent -= OnUpdateFBInfoChange;
+        AdsManager.Instance.OnAdsInfoListUpdateEvent -= OnAdsInfoListUpdate;
+    }
+
+    private void OnUpdateFBInfoChange(int mapID, bool isADAddCntChange, bool isBuyAddCntChange, bool isItemAddCntChange)
+    {
+        if (mapID == TianziBillboradManager.Instance.DataMapID)
+        {
+            Refresh();
+        }
+    }
+
+    private void OnAdsInfoListUpdate(int adID, int mapID)
+    {
+        if (mapID == TianziBillboradManager.Instance.DataMapID)
+        {
+            Refresh();
+        }
+    }
+}
\ No newline at end of file
diff --git a/Main/System/ChallengeTab/TianziBillboradTabHandler.cs.meta b/Main/System/ChallengeTab/TianziBillboradTabHandler.cs.meta
new file mode 100644
index 0000000..7ce9feb
--- /dev/null
+++ b/Main/System/ChallengeTab/TianziBillboradTabHandler.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c2c989a90e5f4d140a0ee55e2f47788c
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/Dungeon/DungeonManager.cs b/Main/System/Dungeon/DungeonManager.cs
index d696272..bbfbb11 100644
--- a/Main/System/Dungeon/DungeonManager.cs
+++ b/Main/System/Dungeon/DungeonManager.cs
@@ -10,8 +10,6 @@
     private Dictionary<int, FBInfo> fbInfoDict = new Dictionary<int, FBInfo>();
     public event Action<int> UpdateFBInfoListEvent;//int mapID
     public event Action<int, bool, bool, bool> UpdateFBInfoChangeEvent;
-    public event Action<int> UpdateFBInfoListEventByADAddCnt;//int mapID  骞垮憡澧炲姞娆℃暟鏈夋洿鏂�
-    public event Action<int> UpdateFBInfoListEventNotByADAddCnt;//int mapID  涓嶆槸骞垮憡澧炲姞娆℃暟瀵艰嚧鐨勬洿鏂�
     Dictionary<int, DungeonRecord> dungeonRecords = new Dictionary<int, DungeonRecord>();
     public event Action updateDungeonBuyCnt;
 
diff --git a/Main/System/Redpoint/MainRedDot.cs b/Main/System/Redpoint/MainRedDot.cs
index 57079f0..53b63cd 100644
--- a/Main/System/Redpoint/MainRedDot.cs
+++ b/Main/System/Redpoint/MainRedDot.cs
@@ -114,6 +114,7 @@
     public const int FirstChargeRepoint = 468; //棣栧厖
     public const int BoneFieldRepoint = 469; //鐧介鐩堥噹
     public const int ArenaRepoint = 470; //婕旀鍦�
+    public const int TianziBillboradRepoint= 471; //澶╁瓙鐨勮�冮獙
     public void Register()
     {
 
diff --git a/Main/System/Settlement/BattleSettlementManager.cs b/Main/System/Settlement/BattleSettlementManager.cs
index c55daaf..f172857 100644
--- a/Main/System/Settlement/BattleSettlementManager.cs
+++ b/Main/System/Settlement/BattleSettlementManager.cs
@@ -41,6 +41,9 @@
             case "BoneBattleField":
                 PopupWindowsProcessor.Instance.Add(isWin ? "BoneBattleVictoryWin" : "BoneBattleFailWin", false);
                 break;
+            case "TianziBillboradBattleField":
+                PopupWindowsProcessor.Instance.Add("TianziBillboradVictoryWin", false);
+                break;
             default:
                 PopupWindowsProcessor.Instance.Add(isWin ? "BattleVictoryWin" : "BattleFailWin", false);
                 break;
@@ -72,6 +75,10 @@
                     UIManager.Instance.OpenWindow<BoneBattleFailWin>();
                 }
                 break;
+            case "TianziBillboradBattleField":
+                TianziBillboradManager.Instance.isSweepVictory = false;
+                UIManager.Instance.OpenWindow<TianziBillboradVictoryWin>();
+                break;
             default:
                 if (isWin)
                 {
diff --git a/Main/System/Settlement/TianziBillboradVictoryWin.cs b/Main/System/Settlement/TianziBillboradVictoryWin.cs
new file mode 100644
index 0000000..7d27b83
--- /dev/null
+++ b/Main/System/Settlement/TianziBillboradVictoryWin.cs
@@ -0,0 +1,96 @@
+using System.Collections.Generic;
+using Cysharp.Threading.Tasks;
+using UnityEngine;
+
+public class TianziBillboradVictoryWin : UIBase
+{
+    [SerializeField] ScrollerController scroller;
+    [SerializeField] TextEx txtHunt;
+    bool isSweepVictory = false;
+    string battleName = "TianziBillboradBattleField";
+    protected override void OnPreOpen()
+    {
+        base.OnPreOpen();
+        isSweepVictory = TianziBillboradManager.Instance.isSweepVictory;
+        scroller.OnRefreshCell += OnRefreshCell;
+        CreateScroller();
+        Display();
+    }
+
+    protected override void OnPreClose()
+    {
+        base.OnPreClose();
+        scroller.OnRefreshCell -= OnRefreshCell;
+        TianziBillboradManager.Instance.isSweepVictory = false;
+        BattleSettlementManager.Instance.WinShowOver(battleName);
+    }
+
+    private void Display()
+    {
+        var jsonData = BattleSettlementManager.Instance.GetBattleSettlement(battleName);
+        if (isSweepVictory)
+        {
+            txtHunt.text = Language.Get("TianziBillborad04", UIHelper.ReplaceLargeNum(TianziBillboradManager.Instance.totalHurtSweep));
+        }
+        else
+        {
+            txtHunt.text = !jsonData.ContainsKey("totalHurt") ? string.Empty : Language.Get("TianziBillborad04", UIHelper.ReplaceLargeNum(ulong.Parse(jsonData["totalHurt"].ToString())));
+        }
+    }
+
+    List<Item> showItems = new List<Item>();
+    void CreateScroller()
+    {
+        if (isSweepVictory)
+        {
+            showItems = TianziBillboradManager.Instance.itemInfos;
+        }
+        else
+        {
+            var jsonData = BattleSettlementManager.Instance.GetBattleSettlement(battleName);
+            if (jsonData == null)
+            {
+                DelayCloseWindow().Forget();
+                return;
+            }
+
+            if (!jsonData.ContainsKey("itemInfo"))
+            {
+                return;
+            }
+            showItems.Clear();
+            var resultStr = jsonData["itemInfo"];
+            for (int i = 0; i < resultStr.Count; i++)
+            {
+                showItems.Add(new Item((int)resultStr[i]["ItemID"], (long)resultStr[i]["Count"]));
+            }
+        }
+
+        scroller.Refresh();
+        if (!showItems.IsNullOrEmpty())
+        {
+            showItems.Sort(SortItem);
+            for (int i = 0; i < showItems.Count; i++)
+            {
+                scroller.AddCell(ScrollerDataType.Header, i);
+            }
+        }
+        scroller.Restart();
+    }
+
+
+
+    int SortItem(Item itemA, Item itemB)
+    {
+        var itemConfigA = ItemConfig.Get(itemA.id);
+        var itemConfigB = ItemConfig.Get(itemB.id);
+        return itemConfigB.ItemColor - itemConfigA.ItemColor;
+    }
+
+    void OnRefreshCell(ScrollerDataType type, CellView cell)
+    {
+        var _cell = cell as SettlementAwardCell;
+        var item = showItems[cell.index];
+        _cell?.Display(item.id, item.countEx);
+    }
+}
\ No newline at end of file
diff --git a/Main/System/Settlement/TianziBillboradVictoryWin.cs.meta b/Main/System/Settlement/TianziBillboradVictoryWin.cs.meta
new file mode 100644
index 0000000..903df8e
--- /dev/null
+++ b/Main/System/Settlement/TianziBillboradVictoryWin.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 67d3b4a0c1a70064899aba53b673f291
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/TianziBillborad/IntensifySmoothSlider.cs b/Main/System/TianziBillborad/IntensifySmoothSlider.cs
deleted file mode 100644
index 41a5ff5..0000000
--- a/Main/System/TianziBillborad/IntensifySmoothSlider.cs
+++ /dev/null
@@ -1,115 +0,0 @@
-using UnityEngine;
-using UnityEngine.UI;
-
-[DisallowMultipleComponent]
-public class IntensifySmoothSlider : MonoBehaviour
-{
-    [SerializeField]
-    Slider m_Slider;
-    public Slider slider
-    {
-        get { return m_Slider; }
-    }
-
-    [SerializeField]
-    [Range(0, 10)]
-    float m_Delay = 0.2f;
-    public float delay
-    {
-        get { return m_Delay; }
-        set
-        {
-            m_Delay = Mathf.Clamp(value, 0, 10);
-        }
-    }
-
-    [SerializeField]
-    [Range(0, 1)]
-    float m_Value = 0f;
-    public float value
-    {
-        get
-        {
-            return m_Value;
-        }
-        set
-        {
-            m_Value = Mathf.Clamp01(value);
-        }
-    }
-    [SerializeField] Text m_LvText;
-    int m_Stage = 0;
-    public int stage
-    {
-        get
-        {
-            return m_Stage;
-        }
-        set
-        {
-            m_Stage = value;
-        }
-    }
-
-    private int presentStage;
-    public int CurrentStage { get { return presentStage; } }
-
-    float refSpeed = 0f;
-
-    public void ResetStage()
-    {
-        presentStage = stage;
-    }
-
-    public void ResetValue(float _value)
-    {
-        value = _value;
-        if (slider != null)
-        {
-            slider.value = Mathf.Clamp01(_value);
-        }
-    }
-
-    void OnEnable()
-    {
-        refSpeed = 0f;
-        if (m_LvText != null)
-        {
-            m_LvText.text = string.Format(Language.Get("TianziBillborad07"), presentStage);
-        }
-    }
-
-    void LateUpdate()
-    {
-        if (slider == null)
-        {
-            return;
-        }
-        if (presentStage < m_Stage)
-        {
-            slider.value = Mathf.SmoothDamp(slider.value, 1, ref refSpeed, delay / 2);
-            if (slider.value >= 0.999f)
-            {
-                slider.value = 0f;
-                presentStage++;
-                if (m_LvText != null)
-                {
-                    m_LvText.text = string.Format(Language.Get("TianziBillborad07"), presentStage);
-                }
-            }
-        }
-        else
-        {
-            if (Mathf.Abs(slider.value - value) > 0.001f)
-            {
-                slider.value = Mathf.SmoothDamp(slider.value, value, ref refSpeed, delay);
-            }
-        }
-
-    }
-
-
-}
-
-
-
diff --git a/Main/System/TianziBillborad/TianziBillboradAwardCell.cs b/Main/System/TianziBillborad/TianziBillboradAwardCell.cs
new file mode 100644
index 0000000..85fc3f5
--- /dev/null
+++ b/Main/System/TianziBillborad/TianziBillboradAwardCell.cs
@@ -0,0 +1,55 @@
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+
+public class TianziBillboradAwardCell : CellView
+{
+    [SerializeField] ImageEx imgRank;
+    [SerializeField] TextEx txtRank;
+    [SerializeField] ItemCell[] itemCells;
+    TianziBillboradManager model { get { return TianziBillboradManager.Instance; } }
+    public void Display(int index)
+    {
+        Dictionary<int, int[][]> rewardDict = model.rankAwards;
+        if (rewardDict.IsNullOrEmpty())
+            return;
+        var list = rewardDict.Keys.ToList();
+        list.Sort();
+
+
+        int rank = list[index];
+
+        if (rank <= 3)
+        {
+            imgRank.SetActive(true);
+            txtRank.SetActive(false);
+            imgRank.SetSprite(StringUtility.Contact("Rank", rank));
+            txtRank.text = rank.ToString();
+        }
+        else
+        {
+            imgRank.SetActive(false);
+            txtRank.SetActive(true);
+            int lastIndex = index - 1;
+            txtRank.text = lastIndex > 0 && lastIndex < list.Count ? Language.Get("Arena15", list[lastIndex] + 1, rank) : string.Empty;
+        }
+
+        int key = list[index];
+        int[][] rewardArr = rewardDict[key];
+        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);
+            }
+        }
+    }
+}
diff --git a/Main/System/TianziBillborad/TianziBillboradAwardCell.cs.meta b/Main/System/TianziBillborad/TianziBillboradAwardCell.cs.meta
new file mode 100644
index 0000000..b0ba456
--- /dev/null
+++ b/Main/System/TianziBillborad/TianziBillboradAwardCell.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 8bd24f1d85f3c204696199cade01645b
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/TianziBillborad/TianziBillboradBossHead.cs b/Main/System/TianziBillborad/TianziBillboradBossHead.cs
new file mode 100644
index 0000000..38c00ce
--- /dev/null
+++ b/Main/System/TianziBillborad/TianziBillboradBossHead.cs
@@ -0,0 +1,79 @@
+using System;
+using UnityEngine;
+
+public class TianziBillboradBossHead : MonoBehaviour
+{
+    [SerializeField] RectTransform rectTransform;
+    [SerializeField] ImageEx imgQuality;
+    [SerializeField] ImageEx imgHeadIcon;
+    [SerializeField] TextEx txtTime;
+
+    private bool isTodayBoss = false;
+    
+    TianziBillboradManager model { get { return TianziBillboradManager.Instance; } }
+    
+    public void Display(int bossId)
+    {
+        if (!NPCConfig.HasKey(bossId))
+            return;
+        NPCConfig npcConfig = NPCConfig.Get(bossId);
+        int heroID = npcConfig.RelatedHeroID;
+        if (!HeroConfig.HasKey(heroID))
+            return;
+        var heroConfig = HeroConfig.Get(heroID);
+        int skinID = heroConfig.SkinIDList[0];
+        if (!HeroSkinConfig.HasKey(skinID))
+            return;
+        if (!model.TryGetBossConfig(model.DataMapID, model.todayLineID, out DungeonConfig dungeonConfig, out NPCLineupConfig npcLineupConfig, out NPCConfig npcConfigToday))
+            return;
+
+        isTodayBoss = npcConfigToday.NPCID == bossId;
+
+        // --- 璁剧疆灏哄 ---
+        imgQuality.rectTransform.sizeDelta = isTodayBoss ? new Vector2(104, 104) : new Vector2(94, 94);
+        rectTransform.sizeDelta = isTodayBoss ? new Vector2(104, 104) : new Vector2(94, 94);
+
+        // --- 璁剧疆鍥惧儚鍜岀姸鎬� ---
+        var heroSkinConfig = HeroSkinConfig.Get(skinID);
+        imgQuality.SetSprite("heroheadBG" + heroConfig.Quality);
+        imgQuality.gray = !isTodayBoss;
+
+        var sprite = UILoader.LoadSprite("HeroHead", heroSkinConfig.SquareIcon);
+        if (sprite == null)
+        {
+            // 鍐呯綉鏈厤缃椂
+            imgHeadIcon.SetSprite("herohead_default");
+        }
+        else
+        {
+            imgHeadIcon.overrideSprite = sprite;
+        }
+        imgHeadIcon.gray = !isTodayBoss;
+
+        txtTime.SetActive(isTodayBoss);
+        if (isTodayBoss)
+        {
+            UpdateTimer();
+        }
+    }
+
+    public void UpdateTimer()
+    {
+        if (!isTodayBoss)
+            return;
+        DateTime endDay = TimeUtility.ServerNow.AddDays(1).Date;
+        TimeSpan remainingTime = endDay - TimeUtility.ServerNow;
+        int remainingSeconds = (int)remainingTime.TotalSeconds;
+
+        if (remainingSeconds > 0)
+        {
+            string countdownText = TimeUtility.SecondsToHMS(remainingSeconds);
+            txtTime.text = countdownText;
+        }
+        else
+        {
+            // 鍊掕鏃剁粨鏉燂紝闅愯棌鏂囨湰
+            txtTime.SetActive(false); 
+        }
+    }
+}
\ No newline at end of file
diff --git a/Main/System/TianziBillborad/TianziBillboradBossHead.cs.meta b/Main/System/TianziBillborad/TianziBillboradBossHead.cs.meta
new file mode 100644
index 0000000..f68d2eb
--- /dev/null
+++ b/Main/System/TianziBillborad/TianziBillboradBossHead.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 0e9e4bca577e25b4e8b2a684125f7d46
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/TianziBillborad/TianziBillboradBox.cs b/Main/System/TianziBillborad/TianziBillboradBox.cs
new file mode 100644
index 0000000..425c65e
--- /dev/null
+++ b/Main/System/TianziBillborad/TianziBillboradBox.cs
@@ -0,0 +1,247 @@
+using UnityEngine;
+using DG.Tweening;
+
+/// <summary>
+/// 鎺у埗澶╁瓙鐪嬫澘鎴樼瀛愶紙鍥炶鏃讹級鎺夎惤鍜屾敹闆嗗姩鐢荤殑缁勪欢銆�
+/// 鍔ㄧ敾搴忓垪: 鎶涘皠寮у舰 -> 澶氭寮硅烦 -> 绛夊緟 -> 椋炲悜鏀堕泦鐐� -> 閿�姣�
+/// </summary>
+[RequireComponent(typeof(RectTransform))]
+public class TianziBillboradBox : MonoBehaviour
+{
+    private RectTransform rectTransform;
+
+    [Header("1. 鎶涘皠闃舵 (浠嶣oss浣嶇疆)")]
+    [SerializeField]
+    [Tooltip("鍒濆浣嶇疆鐨刋/Y鍋忕Щ閲忥紙鍍忕礌鍗曚綅锛夈�傜瀛愬皢浠嶽Boss浣嶇疆 + 鍋忕Щ]寮�濮嬫姏灏勩��")]
+    Vector2 initialPositionOffset = Vector2.zero; // NEW: 鍒濆浣嶇疆鍋忕Щ
+
+    [SerializeField]
+    [Tooltip("绠卞瓙鎶涘皠鐨勬寔缁椂闂达紙绉掞級銆�")]
+    float throwDuration = 0.6f;
+
+    [SerializeField]
+    [Tooltip("鎶涘皠鐨勭紦鍔ㄥ姩鐢荤被鍨嬨�俓n" +
+             "Ease.OutQuad: 妯℃嫙鎶涚墿绾匡紝寮�濮嬪揩锛岃惤鍦版參銆�")]
+    Ease throwEase = Ease.OutQuad;
+
+    [SerializeField]
+    [Tooltip("鎶涘皠鐨勫熀纭�姘村钩璺濈锛堝儚绱犲崟浣嶏級銆�")]
+    float throwHorizontalDistance = 200f;
+
+    [SerializeField]
+    [Tooltip("鎶涘皠璺濈鐨勯殢鏈哄彉鍖栬寖鍥达紙鐧惧垎姣旓級銆�")]
+    [Range(0f, 1f)]
+    float throwDistanceRandomness = 0.3f;
+
+    [SerializeField]
+    [Tooltip("鎶涘皠鐨勫姬褰㈡渶楂樼偣锛岀浉瀵逛簬璧风偣鐨勯珮搴︼紙鍍忕礌鍗曚綅锛夈��")]
+    float throwArcHeight = 150f; 
+
+    [SerializeField]
+    [Tooltip("鎶涘皠钀藉湴鐨勬渶灏忓瀭鐩磋窛绂伙紙鍍忕礌鍗曚綅锛夛紝鍗虫瘮璧风偣浣庡灏戙��")]
+    float minThrowVerticalDrop = 120f; 
+
+    [SerializeField]
+    [Tooltip("鎶涘皠钀藉湴鐨勬渶澶у瀭鐩磋窛绂伙紙鍍忕礌鍗曚綅锛夛紝鍗虫瘮璧风偣浣庡灏戙��")]
+    float maxThrowVerticalDrop = 180f; 
+
+
+    [Header("2. 寮硅烦闃舵")]
+    [SerializeField]
+    [Tooltip("寮硅烦娆℃暟锛�1-3娆★級銆�")]
+    [Range(1, 3)]
+    int bounceCount = 2;
+
+    [SerializeField]
+    [Tooltip("绗竴娆″脊璺崇殑楂樺害锛堝儚绱犲崟浣嶏級銆�")]
+    float firstBounceHeight = 80f;
+
+    [SerializeField]
+    [Tooltip("绗簩娆″脊璺崇殑楂樺害锛堝儚绱犲崟浣嶏級銆�")]
+    float secondBounceHeight = 50f;
+
+    [SerializeField]
+    [Tooltip("绗笁娆″脊璺崇殑楂樺害锛堝儚绱犲崟浣嶏級銆�")]
+    float thirdBounceHeight = 30f;
+
+    [SerializeField]
+    [Tooltip("姣忔寮硅烦鐨勫熀纭�姘村钩璺濈锛堝儚绱犲崟浣嶏級銆�")]
+    float bounceHorizontalDistance = 100f;
+
+    [SerializeField]
+    [Tooltip("寮硅烦璺濈鐨勯殢鏈哄彉鍖栬寖鍥达紙鐧惧垎姣旓級銆�")]
+    [Range(0f, 1f)]
+    float bounceDistanceRandomness = 0.4f;
+
+    [SerializeField]
+    [Tooltip("姣忔寮硅烦鐨勬寔缁椂闂达紙绉掞級銆�")]
+    float bounceDuration = 0.3f;
+
+    [SerializeField]
+    [Tooltip("寮硅烦鐨勭紦鍔ㄥ姩鐢荤被鍨嬨��")]
+    Ease bounceEase = Ease.OutQuad;
+
+    [Header("3. 绛夊緟闃舵")]
+    [SerializeField]
+    [Tooltip("寮硅烦鍋滄鍚庣瓑寰呯殑鏃堕棿锛堢锛夈��")]
+    float waitAfterBounce = 0.5f;
+
+    [Header("4. 鏀堕泦绉诲姩闃舵 (椋炲悜缁堢偣)")]
+    [SerializeField]
+    [Tooltip("绠卞瓙浠庡湴闈㈢Щ鍔ㄥ埌鏈�缁堟敹闆嗕綅缃紙rectBoxEnd锛夋墍闇�鐨勬椂闂达紙绉掞級銆�")]
+    float moveDuration = 0.4f;
+
+    [SerializeField]
+    [Tooltip("绉诲姩鏃剁殑缂撳姩鍔ㄧ敾绫诲瀷銆俓n" +
+             "Ease.InSine: 瀹炵幇鍏堟參鍚庡揩鐨勫姞閫熸晥鏋溿��")]
+    Ease moveEase = Ease.InSine;
+
+    // ----------------------------------------------------------------------
+
+    private void Awake()
+    {
+        rectTransform = GetComponent<RectTransform>();
+    }
+
+    /// <summary>
+    /// 鍚姩绠卞瓙鍔ㄧ敾搴忓垪
+    /// </summary>
+    /// <param name="startWorldPos">鍔ㄧ敾寮�濮嬬殑涓栫晫鍧愭爣锛堜緥濡� Boss 澶村儚浣嶇疆锛�</param>
+    /// <param name="endWorldPos">鍔ㄧ敾缁撴潫鐨勪笘鐣屽潗鏍囷紙rectBoxEnd 鐨勪綅缃級</param>
+    public void StartAnimation(Vector3 startWorldPos, Vector3 endWorldPos)
+    {
+        /// Debug.Log($"TianziBillboradBox startWorldPos {startWorldPos} endWorldPos {endWorldPos}");
+        if (rectTransform == null)
+        {
+            rectTransform = GetComponent<RectTransform>();
+        }
+
+        // --- 0. 鍦ㄥ紑濮嬪姩鐢诲墠锛屽皢绠卞瓙绉诲姩鍒癰oss鐨勭埗鐗╀綋 ---
+        Transform currentParent = transform.parent;
+        if (currentParent != null)
+        {
+            Transform bossParent = currentParent.parent; // boss鐨勭埗鐗╀綋
+            if (bossParent != null)
+            {
+                transform.SetParent(bossParent);
+                transform.localScale = Vector3.one; // 灏唖cale璁剧疆涓�1
+            }
+        }
+
+        // --- 1. 璁$畻骞惰缃垵濮嬩綅缃� (搴旂敤鍋忕Щ) ---
+        Vector3 actualStartPos = new Vector3(
+            startWorldPos.x + initialPositionOffset.x / 100f,
+            startWorldPos.y + initialPositionOffset.y / 100f,
+            startWorldPos.z
+        );
+
+        rectTransform.position = actualStartPos; // MODIFIED: 浣跨敤鍋忕Щ鍚庣殑浣嶇疆
+        gameObject.SetActive(true);
+
+        // --- 2. 闅忔満閫夋嫨鎶涘皠鏂瑰悜锛堝乏鎴栧彸锛夊拰瑙掑害 ---
+        bool throwRight = Random.Range(0, 2) == 1;
+        float horizontalDirection = throwRight ? 1f : -1f;
+
+        // 娣诲姞闅忔満瑙掑害鍋忕Щ
+        float angleOffset = Random.Range(-45f, 45f);
+        float angleRad = angleOffset * Mathf.Deg2Rad;
+
+        // 璁$畻甯﹂殢鏈烘�х殑鎶涘皠璺濈
+        float randomThrowDistance = throwHorizontalDistance *
+            (1f + Random.Range(-throwDistanceRandomness, throwDistanceRandomness));
+
+        // --- 3. 璁$畻鎶涘皠缁堢偣浣嶇疆 ---
+        //璁$畻闅忔満鐨勫瀭鐩翠笅钀借窛绂�
+        float randomVerticalDrop = Random.Range(minThrowVerticalDrop, maxThrowVerticalDrop);
+
+        Vector3 throwEndPos = new Vector3(
+            actualStartPos.x + randomThrowDistance / 100 * Mathf.Cos(angleRad) * horizontalDirection, // MODIFIED
+            actualStartPos.y - randomVerticalDrop / 100, // MODIFIED
+            actualStartPos.z
+        );
+
+        // --- 4. 璁$畻鎶涘皠鎺у埗鐐癸紙鐢ㄤ簬寮у舰杞ㄨ抗锛�---
+        Vector3 controlPoint = new Vector3(
+            actualStartPos.x + randomThrowDistance / 100 * Mathf.Cos(angleRad) * horizontalDirection * 0.5f, // MODIFIED
+            actualStartPos.y + throwArcHeight / 100, // MODIFIED
+            actualStartPos.z
+        );
+
+        // --- 5. 鍒涘缓涓�涓姩鐢诲簭鍒� ---
+        Sequence animSequence = DOTween.Sequence();
+
+        // --- 6. 鎶涘皠闃舵锛堝姬褰㈣建杩癸級---
+        animSequence.Append(
+            rectTransform.DOPath(
+                new Vector3[] { actualStartPos, controlPoint, throwEndPos }, // MODIFIED
+                throwDuration,
+                PathType.CatmullRom
+            ).SetEase(throwEase)
+        );
+
+        // --- 7. 寮硅烦闃舵锛堝悜鎶涘皠鏂瑰悜缁х画璺�1-3娆★級---
+        Vector3 currentPos = throwEndPos;
+        int actualBounceCount = Random.Range(1, bounceCount + 1); // 闅忔満1-3娆�
+
+        for (int i = 0; i < actualBounceCount; i++)
+        {
+            // 璁$畻褰撳墠寮硅烦鐨勯珮搴�
+            float currentBounceHeight = i switch
+            {
+                0 => firstBounceHeight,
+                1 => secondBounceHeight,
+                _ => thirdBounceHeight
+            };
+
+            // 璁$畻甯﹂殢鏈烘�х殑寮硅烦璺濈
+            float randomBounceDistance = bounceHorizontalDistance *
+                (1f + Random.Range(-bounceDistanceRandomness, bounceDistanceRandomness));
+
+            // 璁$畻寮硅烦缁堢偣浣嶇疆锛堢户缁悜鎶涘皠鏂瑰悜绉诲姩锛�
+            Vector3 bounceEndPos = new Vector3(
+                currentPos.x + randomBounceDistance / 100 * horizontalDirection,
+                currentPos.y,
+                currentPos.z
+            );
+
+            // 寮硅烦鎺у埗鐐癸紙寮у舰杞ㄨ抗锛�
+            Vector3 bounceControlPoint = new Vector3(
+                currentPos.x + randomBounceDistance / 100 * horizontalDirection * 0.5f,
+                currentPos.y + currentBounceHeight / 100,
+                currentPos.z
+            );
+
+            // 娣诲姞寮硅烦鍔ㄧ敾锛堝姬褰㈣建杩癸級
+            animSequence.Append(
+                rectTransform.DOPath(
+                    new Vector3[] { currentPos, bounceControlPoint, bounceEndPos },
+                    bounceDuration,
+                    PathType.CatmullRom
+                ).SetEase(bounceEase)
+            );
+
+            currentPos = bounceEndPos; // 鏇存柊褰撳墠浣嶇疆
+        }
+
+        // --- 8. 绛夊緟闃舵 ---
+        animSequence.AppendInterval(waitAfterBounce);
+
+        // --- 9. 绉诲姩鍒扮粓鐐� ---
+        animSequence.Append(
+            rectTransform.DOMove(endWorldPos, moveDuration)
+                .SetEase(moveEase)
+        );
+
+        // --- 10. 鍔ㄧ敾鎾斁瀹屾瘯鍚庨攢姣� ---
+        animSequence.OnComplete(() =>
+        {
+            if (this != null && gameObject != null)
+            {
+                Destroy(gameObject);
+            }
+        });
+
+        // --- 11. 鍏宠仈鐢熷懡鍛ㄦ湡 ---
+        animSequence.SetTarget(this);
+    }
+}
\ No newline at end of file
diff --git a/Main/System/TianziBillborad/TianziBillboradBox.cs.meta b/Main/System/TianziBillborad/TianziBillboradBox.cs.meta
new file mode 100644
index 0000000..a4470a7
--- /dev/null
+++ b/Main/System/TianziBillborad/TianziBillboradBox.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: bf7cf077ef7274a4d998cf2909992027
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/TianziBillborad/TianziBillboradManager.cs b/Main/System/TianziBillborad/TianziBillboradManager.cs
new file mode 100644
index 0000000..37fe6d1
--- /dev/null
+++ b/Main/System/TianziBillborad/TianziBillboradManager.cs
@@ -0,0 +1,295 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using LitJson;
+public class TianziBillboradManager : GameSystemManager<TianziBillboradManager>
+{
+    public readonly int rankType = 2;    // 姒滃崟绫诲瀷
+    public readonly int funcId = 39;    // 鍔熻兘Id
+    public readonly int DataMapID = 30020;
+    public int nowTabIndex;     // 0 鎺掕姒� 1 濂栧姳
+    public byte todayLineID;    //浠婃棩鏄摢涓猯ineID锛屽搴斿壇鏈〃鐨勫姛鑳界嚎璺疘D
+    public ulong historyHurt;    //鏈�冮獙鍘嗗彶鏈�澶т激瀹�
+    public ulong todayHurt;    //鏈�冮獙浠婃棩鏈�澶т激瀹�
+    public bool isSkipSweepTip = false;
+    public event Action UpdateTianziKYInfoExent;
+    public Dictionary<int, int[][]> rankAwards;// 姣忔棩鎺掕濂栧姳 {"鍚嶆":[[鐗╁搧ID, 涓暟,鏄惁鎷嶅搧], ...], ...} 閰嶇疆鐨勫悕娆ey锛岃嚜鍔ㄦ寜灏忎簬绛変簬瀵瑰簲鍚嶆缁欏鍔�
+    public Redpoint parentRedpoint = new Redpoint(MainRedDot.MainChallengeRedpoint, MainRedDot.TianziBillboradRepoint);
+    public override void Init()
+    {
+        DTC0102_tagCDBPlayer.beforePlayerDataInitializeEvent += OnBeforePlayerDataInitializeEvent;
+        DungeonManager.Instance.UpdateFBInfoChangeEvent += OnUpdateFBInfoChangeEvent;
+        AdsManager.Instance.OnAdsInfoListUpdateEvent += OnAdsInfoListUpdateEvent;
+        FuncOpen.Instance.OnFuncStateChangeEvent += OnFuncStateChangeEvent;
+        TimeMgr.Instance.OnDayEvent += OnDayEvent;
+        UpdateTianziKYInfoExent += OnUpdateTianziKYInfoExent;
+
+        FuncConfigConfig config = FuncConfigConfig.Get("TianziBillboradAward");
+        rankAwards = ConfigParse.ParseIntArray2Dict(config.Numerical1);
+    }
+
+    public override void Release()
+    {
+        DTC0102_tagCDBPlayer.beforePlayerDataInitializeEvent -= OnBeforePlayerDataInitializeEvent;
+        DungeonManager.Instance.UpdateFBInfoChangeEvent -= OnUpdateFBInfoChangeEvent;
+        AdsManager.Instance.OnAdsInfoListUpdateEvent -= OnAdsInfoListUpdateEvent;
+        FuncOpen.Instance.OnFuncStateChangeEvent -= OnFuncStateChangeEvent;
+        TimeMgr.Instance.OnDayEvent -= OnDayEvent;
+        UpdateTianziKYInfoExent -= OnUpdateTianziKYInfoExent;
+    }
+
+    private void OnBeforePlayerDataInitializeEvent()
+    {
+        nowTabIndex = 0;
+        todayLineID = 0;
+        historyHurt = 0;
+        todayHurt = 0;
+
+        isSkipSweepTip = false;
+    }
+
+    private void OnUpdateTianziKYInfoExent()
+    {
+        UpdateRedPoint();
+    }
+
+    private void OnFuncStateChangeEvent(int obj)
+    {
+        if (obj != funcId)
+            return;
+        UpdateRedPoint();
+    }
+
+    private void OnDayEvent()
+    {
+        UpdateRedPoint();
+    }
+
+    private void OnUpdateFBInfoChangeEvent(int mapID, bool isADAddCntChange, bool isBuyAddCntChange, bool isItemAddCntChange)
+    {
+        int dataMapID = DataMapID;
+        if (mapID != dataMapID)
+            return;
+        if (isADAddCntChange)
+            return;
+        UpdateRedPoint();
+    }
+
+    private void OnAdsInfoListUpdateEvent(int id, int mapId)
+    {
+        if (mapId != DataMapID)
+            return;
+        UpdateRedPoint();
+    }
+
+    public void UpdateRedPoint()
+    {
+        parentRedpoint.state = RedPointState.None;
+        if (!FuncOpen.Instance.IsFuncOpen(funcId))
+            return;
+        int remainChallageCount = GetRemainChallageCount();
+        if (remainChallageCount > 0)
+        {
+            parentRedpoint.state = RedPointState.Simple;
+        }
+    }
+
+    public int GetRemainChallageCount()
+    {
+        if (!DungeonManager.Instance.TryGetFBInfoByMapID(DataMapID, out FBInfo fbInfo))
+            return 0;
+        if (!DungeonOpenTimeConfig.HasKey(DataMapID))
+            return 0;
+        DungeonOpenTimeConfig dungeonOpenTimeConfig = DungeonOpenTimeConfig.Get(DataMapID);
+        int baseCount = dungeonOpenTimeConfig.DayTimes + dungeonOpenTimeConfig.PayCntMax;
+        int realMaxCount = baseCount + fbInfo.ADAddCnt + fbInfo.BuyAddCnt + fbInfo.ItemAddCnt;
+        return realMaxCount - fbInfo.EnterCnt;
+    }
+
+    public List<int> GetBossIDList(int dataMapID)
+    {
+        if (!DungeonConfig.TryGetDictByMapID(dataMapID, out Dictionary<int, int> dict))
+            return new List<int>();
+        List<int> list = dict.Keys.ToList();
+        list.Sort();
+        List<int> res = new List<int>();
+        for (int i = 0; i < list.Count; i++)
+        {
+            int dungeonId = dict[list[i]];
+            int lineupID = DungeonConfig.Get(dungeonId).LineupIDList[0];
+            if (!NPCLineupConfig.HasKey(lineupID))
+                continue;
+            NPCLineupConfig npcLineupConfig = NPCLineupConfig.Get(lineupID);
+            int bossId = npcLineupConfig.BossID;
+            if (!res.Contains(bossId))
+                res.Add(bossId);
+        }
+        return res;
+    }
+    public bool TryGetADAwardConfigByMapId(int dataMapID, out ADAwardConfig adAwardConfig)
+    {
+        adAwardConfig = null;
+        if (!ADAwardConfig.TryGetADIDByADMapID(dataMapID, out int adID) || !ADAwardConfig.HasKey(adID))
+            return false;
+        adAwardConfig = ADAwardConfig.Get(adID);
+        return true;
+    }
+
+    public bool TryGetBossConfig(int dataMapID, int lineID, out DungeonConfig dungeonConfig, out NPCLineupConfig npcLineupConfig, out NPCConfig npcConfig)
+    {
+        dungeonConfig = null;
+        npcLineupConfig = null;
+        npcConfig = null;
+        if (!DungeonConfig.TryGetDungeonID(dataMapID, lineID, out int dungeonID) || !DungeonConfig.HasKey(dungeonID))
+            return false;
+        dungeonConfig = DungeonConfig.Get(dungeonID);
+        int lineupID = dungeonConfig.LineupIDList[0];
+        if (!NPCLineupConfig.HasKey(lineupID))
+            return false;
+        npcLineupConfig = NPCLineupConfig.Get(lineupID);
+        int bossId = npcLineupConfig.BossID;
+        if (!NPCConfig.HasKey(bossId))
+            return false;
+        npcConfig = NPCConfig.Get(bossId);
+        return true;
+    }
+
+    public int[][] GetPossibleRewards(int bossID)
+    {
+        if (!TianziConfig.TryGetAllInfoDictByBossID(bossID, out Dictionary<int, TianziConfig> dict))
+            return new int[0][];
+
+        List<int> itemIds = new List<int>();
+        foreach (var item in dict.Values)
+        {
+            int[][] award = item.RandWeightItemList;
+            for (int i = 0; i < award.Length; i++)
+            {
+                int itemId = award[i][1];
+                if (!itemIds.Contains(itemId))
+                {
+                    itemIds.Add(itemId);
+                }
+            }
+        }
+
+        // 鏍规嵁鐗╁搧鍝佽川鎺掑簭锛屽搧璐ㄩ珮鐨勬帓鍦ㄥ墠闈�
+        itemIds.Sort((itemId1, itemId2) =>
+        {
+            var itemConfig1 = ItemConfig.Get(itemId1);
+            var itemConfig2 = ItemConfig.Get(itemId2);
+
+            if (itemConfig1 == null && itemConfig2 == null) return 0;
+            if (itemConfig1 == null) return -1;
+            if (itemConfig2 == null) return 1;
+
+            return itemConfig2.ItemColor.CompareTo(itemConfig1.ItemColor);
+        });
+
+        // 杞崲涓� int[itemID][鏁伴噺(0)] 鏍煎紡
+        int[][] result = new int[itemIds.Count][];
+        for (int i = 0; i < itemIds.Count; i++)
+        {
+            result[i] = new int[] { itemIds[i], 0 };
+        }
+
+        return result;
+    }
+
+
+    /// <summary>
+    /// 璁$畻鎵崱鑳借幏寰楃瀛愭暟閲�
+    /// </summary>
+    /// <param name="damage">浼ゅ鍊�</param>
+    /// <returns>鑳借幏寰楃殑绠卞瓙鏁伴噺</returns>
+    public int CalculateSweepBoxCount(ulong damage)
+    {
+        if (!TryGetBossConfig(DataMapID, todayLineID, out DungeonConfig dungeonConfig, out NPCLineupConfig npcLineupConfig, out NPCConfig npcConfig))
+            return 0;
+        int bossID = npcLineupConfig.BossID;
+        if (!TianziConfig.TryGetAllInfoDictByBossID(bossID, out Dictionary<int, TianziConfig> hpDict))
+            return 0;
+        int boxCount = 0;
+        ulong accumulatedHP = 0;
+
+        // 鎸夎鏉$紪鍙锋帓搴忥紝浠庡皬鍒板ぇ璁$畻绱鐢熷懡鍊�
+        var sortedHPNums = hpDict.Keys.ToList();
+        sortedHPNums.Sort();
+
+        foreach (int hpNum in sortedHPNums)
+        {
+            if (hpDict.TryGetValue(hpNum, out TianziConfig tianziConfig))
+            {
+                // 绱鐢熷懡鍊�
+                accumulatedHP += (ulong)tianziConfig.MaxHP;
+
+                // 濡傛灉浼ゅ >= 绱鐢熷懡鍊硷紝鍒欒幏寰椾竴涓瀛�
+                if (damage >= accumulatedHP)
+                {
+                    boxCount++;
+                }
+                else
+                {
+                    // 濡傛灉浼ゅ涓嶈冻浠ヨ幏寰楀綋鍓嶈鏉$殑绠卞瓙锛屽垯鍋滄璁$畻
+                    break;
+                }
+            }
+        }
+
+        return boxCount;
+    }
+
+    public List<Item> itemInfos = new List<Item>();
+    public bool isSweepVictory = false;
+    public ulong totalHurtSweep;
+    public ulong todayHurtTotalSweep;
+    public void UpdateFBEnd(H0320_tagFBEnd vNetData)
+    {
+        if (vNetData.Msg == null)
+            return;
+        JsonData jsonData = JsonMapper.ToObject(vNetData.Msg);
+        int isSweep = int.Parse(jsonData["isSweep"].ToString());
+        int dataMapID = int.Parse(jsonData["dataMapID"].ToString());
+        totalHurtSweep = ulong.Parse(jsonData["totalHurt"].ToString());
+        int lineID = int.Parse(jsonData["lineID"].ToString());
+        todayHurtTotalSweep = ulong.Parse(jsonData["todayHurtTotal"].ToString());
+        int isPass = int.Parse(jsonData["isPass"].ToString());
+
+        if (dataMapID != DataMapID)
+            return;
+        isSweepVictory = true;
+
+        itemInfos.Clear();
+        if (jsonData["itemInfo"] != null && jsonData["itemInfo"].IsArray)
+        {
+            for (int i = 0; i < jsonData["itemInfo"].Count; i++)
+            {
+                JsonData itemData = jsonData["itemInfo"][i];
+                Item itemInfo = new Item((int)itemData["ItemID"], (long)itemData["ItemID"]);
+                itemInfos.Add(itemInfo);
+            }
+        }
+        isSweepVictory = true;
+        UIManager.Instance.OpenWindow<TianziBillboradVictoryWin>();
+    }
+
+    public void SendBBeginFBWipeOut()
+    {
+        CA505_tagCMBeginFBWipeOut pack = new CA505_tagCMBeginFBWipeOut();
+        pack.MapID = (uint)DataMapID;
+        pack.LineID = (ushort)todayLineID;
+        pack.Cnt = 1;
+        GameNetSystem.Instance.SendInfo(pack);
+    }
+
+    public void UpdateTianziKYInfo(HB201_tagSCTianziKYInfo vNetData)
+    {
+        if (vNetData == null)
+            return;
+        todayLineID = vNetData.LineID;
+        historyHurt = (ulong)vNetData.HistoryHurtEx * 100000000 + (ulong)vNetData.HistoryHurt;
+        todayHurt = (ulong)vNetData.TodayHurtEx * 100000000 + (ulong)vNetData.TodayHurt;
+        UpdateTianziKYInfoExent?.Invoke();
+    }
+}
+
diff --git a/Main/System/TianziBillborad/TianziBillboradManager.cs.meta b/Main/System/TianziBillborad/TianziBillboradManager.cs.meta
new file mode 100644
index 0000000..733cc8e
--- /dev/null
+++ b/Main/System/TianziBillborad/TianziBillboradManager.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: f142b2e5ad3e5494f97ad68a5ccb95cd
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/TianziBillborad/TianziBillboradRankWin.cs b/Main/System/TianziBillborad/TianziBillboradRankWin.cs
new file mode 100644
index 0000000..7562fa0
--- /dev/null
+++ b/Main/System/TianziBillborad/TianziBillboradRankWin.cs
@@ -0,0 +1,164 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using UnityEngine;
+public class TianziBillboradRankWin : FunctionsBaseWin
+{
+    [Header("閫氱敤閮ㄥ垎")]
+    [SerializeField] Transform transRank;
+    [SerializeField] Transform transAward;
+    [SerializeField] ButtonEx btnClose;
+    [SerializeField] TextEx txtTitle;
+    [SerializeField] PlayerRankCell myRankCell;
+    [HideInInspector] public string valueFormat = "{0}";
+
+    [Header("濂栧姳")]
+    [SerializeField] TextEx txtCountdown;
+    [SerializeField] ScrollerController scrAward;
+    [Header("鎺掕")]
+    [SerializeField] List<PlayerTop3Cell> playerTop3Cells;
+    [SerializeField] ScrollerController scrollerController;
+    [HideInInspector] public int groupValue1 = 0;   //涓�鑸敤浜庤法鏈�
+    [HideInInspector] public int groupValue2 = 0;   //涓�鑸敤浜庤法鏈�
+    TianziBillboradManager model { get { return TianziBillboradManager.Instance; } }
+    protected override void InitComponent()
+    {
+        base.InitComponent();
+        btnClose.SetListener(CloseWindow);
+    }
+
+    protected override void OnPreOpen()
+    {
+        base.OnPreOpen();
+        tabButtons[functionOrder].SelectBtn(true);
+        RankModel.Instance.ResetQueryParam();
+        RankModel.Instance.QueryRankByPage(model.rankType, watchID: (int)PlayerDatas.Instance.baseData.PlayerID);
+        RankModel.Instance.onRankRefresh += OnRankRefresh;
+        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
+        scrollerController.OnRefreshCell += OnRefreshCell;
+        scrAward.OnRefreshCell += OnRefreshAwardCell;
+        model.UpdateTianziKYInfoExent += OnUpdateTianziKYInfoExent;
+        Display();
+    }
+
+    protected override void OnPreClose()
+    {
+        base.OnPreClose();
+        model.UpdateTianziKYInfoExent -= OnUpdateTianziKYInfoExent;
+        RankModel.Instance.onRankRefresh -= OnRankRefresh;
+        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
+        scrollerController.OnRefreshCell -= OnRefreshCell;
+        scrAward.OnRefreshCell -= OnRefreshAwardCell;
+    }
+
+    private void OnUpdateTianziKYInfoExent()
+    {
+        Refresh();
+    }
+
+    private void OnSecondEvent()
+    {
+        DateTime endDay = TimeUtility.ServerNow.AddDays(1).Date;
+        TimeSpan remainingTime = endDay - TimeUtility.ServerNow;
+        int remainingSeconds = (int)remainingTime.TotalSeconds;
+        if (remainingSeconds > 0)
+        {
+            string countdownText = TimeUtility.SecondsToHMS(remainingSeconds);
+            txtCountdown.SetActive(true);
+            txtCountdown.text = Language.Get("Arena14", countdownText);
+        }
+        else
+        {
+            txtCountdown.SetActive(false);
+        }
+    }
+
+    void OnRankRefresh(int type)
+    {
+        Refresh();
+    }
+
+    protected override void OpenSubUIByTabIndex()
+    {
+        TianziBillboradManager.Instance.nowTabIndex = functionOrder;
+        transRank.SetActive(functionOrder == 0);
+        transAward.SetActive(functionOrder == 1);
+        Display();
+    }
+
+    private void OnRefreshAwardCell(ScrollerDataType type, CellView cell)
+    {
+        var _cell = cell.GetComponent<TianziBillboradAwardCell>();
+        _cell?.Display(cell.index);
+    }
+
+    void Refresh()
+    {
+        ShowTop3();
+        scrollerController.m_Scorller.RefreshActiveCellViews();
+        DisplayMyRank();
+    }
+
+    private void Display()
+    {
+        txtTitle.text = Language.Get(functionOrder == 0 ? "L1118" : "Arena04");
+        if (functionOrder == 0)
+        {
+            ShowTop3();
+            CreateScroller();
+        }
+        else
+        {
+            CreateAwardScroller();
+            OnSecondEvent();
+        }
+        DisplayMyRank();
+    }
+    void CreateScroller()
+    {
+        scrollerController.Refresh();
+        var cnt = RankModel.Instance.GetRankShowMaxCnt(model.rankType);
+        for (int i = 3; i < cnt; i++)
+        {
+            scrollerController.AddCell(ScrollerDataType.Header, i);
+        }
+        scrollerController.Restart();
+    }
+
+    void OnRefreshCell(ScrollerDataType type, CellView cell)
+    {
+        var _cell = cell.GetComponent<PlayerRankCell>();
+        _cell.Display(model.rankType, cell.index + 1, valueFormat);
+        RankModel.Instance.ListenRankPage(model.rankType, cell.index, groupValue1, groupValue2);
+    }
+
+    private void CreateAwardScroller()
+    {
+        scrAward.Refresh();
+        Dictionary<int, int[][]> rewardDict = model.rankAwards;
+        if (!rewardDict.IsNullOrEmpty())
+        {
+            var list = rewardDict.Keys.ToList();
+            list.Sort();
+            for (int i = 0; i < list.Count; i++)
+            {
+                CellInfo cellInfo = new CellInfo();
+                scrAward.AddCell(ScrollerDataType.Header, i, cellInfo);
+            }
+        }
+        scrAward.Restart();
+    }
+
+    private void DisplayMyRank()
+    {
+        myRankCell.Display(model.rankType, 0, valueFormat);
+    }
+
+    void ShowTop3()
+    {
+        for (int i = 0; i < playerTop3Cells.Count; i++)
+        {
+            playerTop3Cells[i].Display(model.rankType, i + 1);
+        }
+    }
+}
\ No newline at end of file
diff --git a/Main/System/TianziBillborad/TianziBillboradRankWin.cs.meta b/Main/System/TianziBillborad/TianziBillboradRankWin.cs.meta
new file mode 100644
index 0000000..fbab4cd
--- /dev/null
+++ b/Main/System/TianziBillborad/TianziBillboradRankWin.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 0cee596ea898c8d418ecf8baada9df12
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/TianziBillborad/TianziBillboradSweepTipWin.cs b/Main/System/TianziBillborad/TianziBillboradSweepTipWin.cs
new file mode 100644
index 0000000..be629e9
--- /dev/null
+++ b/Main/System/TianziBillborad/TianziBillboradSweepTipWin.cs
@@ -0,0 +1,48 @@
+using UnityEngine;
+using UnityEngine.UI;
+public class TianziBillboradSweepTipWin : UIBase
+{
+    [SerializeField] ButtonEx btnOK;
+    [SerializeField] ButtonEx btnClose;
+    [SerializeField] TextEx txtTodayHurt;
+    [SerializeField] TextEx txtBoxCount;
+    [SerializeField] Toggle toggle;
+    TianziBillboradManager model { get { return TianziBillboradManager.Instance; } }
+
+    protected override void InitComponent()
+    {
+        base.InitComponent();
+        btnClose.SetListener(CloseWindow);
+        btnOK.SetListener(() =>
+        {
+            int remainChallageCount = model.GetRemainChallageCount();
+            if (remainChallageCount <= 0)
+            {
+                SysNotifyMgr.Instance.ShowTip("TianziBillborad02");
+                return;
+            }
+            model.SendBBeginFBWipeOut();
+            CloseWindow();
+        });
+        toggle.onValueChanged.AddListener(OnValueChanged);
+    }
+    protected override void OnPreOpen()
+    {
+        base.OnPreOpen();
+        Display();
+    }
+
+    public void Display()
+    {
+        toggle.isOn = false;
+        txtTodayHurt.text = Language.Get("TianziBillborad05", UIHelper.ReplaceLargeNum(model.historyHurt));
+        int boxCount = model.CalculateSweepBoxCount(model.todayHurt);
+        txtBoxCount.text = UIHelper.AppendColor(boxCount > 0 ? TextColType.Green : TextColType.Red, Language.Get("TianziBillborad07", boxCount));
+    }
+
+    private void OnValueChanged(bool value)
+    {
+        model.isSkipSweepTip = value;
+    }
+
+}
\ No newline at end of file
diff --git a/Main/System/TianziBillborad/TianziBillboradSweepTipWin.cs.meta b/Main/System/TianziBillborad/TianziBillboradSweepTipWin.cs.meta
new file mode 100644
index 0000000..cc73080
--- /dev/null
+++ b/Main/System/TianziBillborad/TianziBillboradSweepTipWin.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: b393705c8be17b542b181b3ed5b0f0ce
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/TianziBillborad/TianziBillboradWin.cs b/Main/System/TianziBillborad/TianziBillboradWin.cs
new file mode 100644
index 0000000..e69ed39
--- /dev/null
+++ b/Main/System/TianziBillborad/TianziBillboradWin.cs
@@ -0,0 +1,265 @@
+using System.Collections.Generic;
+using UnityEngine;
+using UnityEngine.UI;
+public class TianziBillboradWin : UIBase
+{
+    [SerializeField] float modelSize;
+    [SerializeField] ButtonEx btnClose;
+    [SerializeField] ButtonEx btnRank;
+    [SerializeField] ButtonEx btnAds;
+    [SerializeField] ButtonEx btnChallenge1;
+    [SerializeField] ButtonEx btnChallenge2;
+    [SerializeField] ButtonEx btnSweep;
+
+    [SerializeField] ImageEx imgChallengeRed1;
+    [SerializeField] ImageEx imgChallengeRed2;
+    [SerializeField] ImageEx imgSweepRed;
+
+    [SerializeField] TextEx txtBossName;
+    [SerializeField] UIHeroController bossModel;
+    [SerializeField] UIEffectPlayer uiEffectPlayer;
+    [SerializeField] List<SkillWordCell> skillWords;
+    [SerializeField] List<ItemCell> possibleRewards;
+    [SerializeField] TextEx txtTodayChallengeCount;
+    [SerializeField] TextEx txtTodayAdsCount;
+    [SerializeField] TextEx txtHistoryHurt;
+    [SerializeField] TextEx txtTodayHurt;
+    [SerializeField] List<TianziBillboradBossHead> bossHeads;
+    [SerializeField] RectTransform layoutGroupRect;
+    TianziBillboradManager model { get { return TianziBillboradManager.Instance; } }
+    DungeonManager dungeonModel { get { return DungeonManager.Instance; } }
+    AdsManager adsModel { get { return AdsManager.Instance; } }
+    TimeMgr timeModel { get { return TimeMgr.Instance; } }
+
+    protected override void InitComponent()
+    {
+        base.InitComponent();
+        btnClose.SetListener(CloseWindow);
+        btnRank.SetListener(() => { UIManager.Instance.OpenWindow<TianziBillboradRankWin>(); });
+        btnAds.SetListener(() =>
+        {
+            if (!model.TryGetADAwardConfigByMapId(model.DataMapID, out ADAwardConfig adAwardConfig))
+                return;
+            adsModel.PlayAds(adAwardConfig.ADID);
+        });
+        btnChallenge1.SetListener(OnClickChallenge);
+        btnChallenge2.SetListener(OnClickChallenge);
+        btnSweep.SetListener(() =>
+        {
+            if (model.isSkipSweepTip)
+            {
+                int remainChallageCount = model.GetRemainChallageCount();
+                if (remainChallageCount <= 0)
+                {
+                    SysNotifyMgr.Instance.ShowTip("TianziBillborad02");
+                    return;
+                }
+                model.SendBBeginFBWipeOut();
+            }
+            else
+            {
+                UIManager.Instance.OpenWindow<TianziBillboradSweepTipWin>();
+            }
+        });
+    }
+
+    void OnClickChallenge()
+    {
+        int remainChallageCount = model.GetRemainChallageCount();
+        if (remainChallageCount <= 0)
+        {
+            SysNotifyMgr.Instance.ShowTip("TianziBillborad01");
+            return;
+        }
+        BattleManager.Instance.SendTurnFight((uint)model.DataMapID, model.todayLineID);
+    }
+
+    protected override void OnPreOpen()
+    {
+        base.OnPreOpen();
+        model.UpdateTianziKYInfoExent += OnUpdateTianziKYInfoExent;
+        dungeonModel.UpdateFBInfoListEvent += OnUpdateFBInfoListEvent;
+        adsModel.OnAdsInfoListUpdateEvent += OnAdsInfoListUpdateEvent;
+        timeModel.OnDayEvent += OnDayEvent;
+        GlobalTimeEvent.Instance.secondEvent += OnSecondEvent;
+        Display();
+    }
+
+    protected override void OnPreClose()
+    {
+        base.OnPreClose();
+        model.UpdateTianziKYInfoExent -= OnUpdateTianziKYInfoExent;
+        dungeonModel.UpdateFBInfoListEvent -= OnUpdateFBInfoListEvent;
+        adsModel.OnAdsInfoListUpdateEvent -= OnAdsInfoListUpdateEvent;
+        timeModel.OnDayEvent -= OnDayEvent;
+        GlobalTimeEvent.Instance.secondEvent -= OnSecondEvent;
+    }
+
+    private void OnUpdateTianziKYInfoExent()
+    {
+        Display();
+    }
+
+    private void OnSecondEvent()
+    {
+        if (bossHeads == null)
+            return;
+
+        foreach (var head in bossHeads)
+        {
+            if (head != null)
+            {
+                head.UpdateTimer();
+            }
+        }
+    }
+
+    private void OnUpdateFBInfoListEvent(int mapID)
+    {
+        if (mapID != model.DataMapID)
+            return;
+        if (!model.TryGetADAwardConfigByMapId(model.DataMapID, out ADAwardConfig adAwardConfig))
+            return;
+        Display();
+    }
+
+    private void OnAdsInfoListUpdateEvent(int id, int mapId)
+    {
+        if (mapId != model.DataMapID)
+            return;
+        if (!model.TryGetADAwardConfigByMapId(model.DataMapID, out ADAwardConfig adAwardConfig))
+            return;
+        Display();
+    }
+
+    private void OnDayEvent()
+    {
+        Display();
+    }
+
+    public void Display()
+    {
+        if (!model.TryGetBossConfig(model.DataMapID, model.todayLineID, out DungeonConfig dungeonConfig, out NPCLineupConfig npcLineupConfig, out NPCConfig npcConfig))
+            return;
+        if (!DungeonManager.Instance.TryGetFBInfoByMapID(model.DataMapID, out var fbInfo))
+            return;
+        if (!model.TryGetADAwardConfigByMapId(model.DataMapID, out ADAwardConfig adAwardConfig))
+            return;
+
+        DisplayFBInfo(npcConfig);
+        DisplayButton(adAwardConfig, fbInfo);
+        DisplaySkillWordsList(npcLineupConfig);
+        DisplayItemCellList(possibleRewards, model.GetPossibleRewards(npcConfig.NPCID));
+        DisplayBossHeadList(bossHeads, model.GetBossIDList(model.DataMapID));
+    }
+
+    private void DisplayButton(ADAwardConfig adAwardConfig, FBInfo fbInfo)
+    {
+        bool isTodayFirst = fbInfo.EnterCnt <= 0;
+        btnChallenge2.SetActive(isTodayFirst);
+        btnChallenge1.SetActive(!isTodayFirst);
+        btnSweep.SetActive(!isTodayFirst);
+        btnAds.SetActive(!isTodayFirst);
+
+        if (!DungeonOpenTimeConfig.HasKey(model.DataMapID))
+            return;
+        DungeonOpenTimeConfig dungeonOpenTimeConfig = DungeonOpenTimeConfig.Get(model.DataMapID);
+        int remainChallageCount = model.GetRemainChallageCount();
+        int maxCount = dungeonOpenTimeConfig.DayTimes;
+        txtTodayChallengeCount.text = UIHelper.AppendColor(remainChallageCount > 0 ? TextColType.Green : TextColType.Red, Language.Get("TianziBillborad03", remainChallageCount, maxCount));
+
+        imgChallengeRed1.SetActive(remainChallageCount > 0);
+        imgChallengeRed2.SetActive(remainChallageCount > 0);
+        imgSweepRed.SetActive(false);
+
+        int adsCnt = AdsManager.Instance.GetADCntByADID(adAwardConfig.ADID);
+        bool isShowAds = adsCnt < adAwardConfig.ADCntMax;
+        int remainAdsCount = adAwardConfig.ADCntMax - adsCnt;
+        btnAds.SetActive(!isTodayFirst && isShowAds);
+        txtTodayAdsCount.text = UIHelper.AppendColor(isShowAds ? TextColType.Green : TextColType.Red, Language.Get("BoneField09", remainAdsCount, adAwardConfig.ADCntMax)); ;
+    }
+
+    private void DisplayFBInfo(NPCConfig npcConfig)
+    {
+        txtBossName.text = npcConfig.NPCName;
+        uiEffectPlayer.Play();
+        bossModel.Create(npcConfig.SkinID, modelSize);
+        txtHistoryHurt.text = Language.Get("TianziBillborad01", UIHelper.ReplaceLargeNum(model.historyHurt));
+        txtTodayHurt.text = Language.Get("TianziBillborad02", UIHelper.ReplaceLargeNum(model.todayHurt));
+    }
+
+    public void DisplayItemCellList(List<ItemCell> itemCells, int[][] items)
+    {
+        if (itemCells.IsNullOrEmpty() || items.IsNullOrEmpty())
+            return;
+        for (int i = 0; i < itemCells.Count; i++)
+        {
+            if (i < items.Length)
+            {
+                int index = i;
+                itemCells[i].SetActive(true);
+                itemCells[i].Init(new ItemCellModel(items[i][0], true, items[i][1]));
+                itemCells[i].button.SetListener(() =>
+                {
+                    ItemTipUtility.Show(items[index][0], true);
+                });
+            }
+            else
+            {
+                itemCells[i].SetActive(false);
+            }
+        }
+    }
+
+    public void DisplaySkillWordsList(NPCLineupConfig npcLineupConfig)
+    {
+        if (skillWords.IsNullOrEmpty())
+            return;
+        for (int i = 0; i < skillWords.Count; i++)
+        {
+            if (i < npcLineupConfig.SkillIDExList.Length)
+            {
+                skillWords[i].SetActive(true);
+                int skillID = npcLineupConfig.SkillIDExList[i];
+                skillWords[i].Init(skillID, () =>
+                {
+                    SmallTipWin.showText = Language.Get("SmallTipFomat", SkillConfig.Get(skillID)?.SkillName, SkillConfig.Get(skillID)?.Description);
+                    SmallTipWin.worldPos = CameraManager.uiCamera.ScreenToWorldPoint(Input.mousePosition);
+                    SmallTipWin.isDownShow = true;
+                    UIManager.Instance.OpenWindow<SmallTipWin>();
+                });
+            }
+            else
+            {
+                skillWords[i].SetActive(false);
+            }
+        }
+    }
+
+    public void DisplayBossHeadList(List<TianziBillboradBossHead> heads, List<int> bossIds)
+    {
+        if (heads.IsNullOrEmpty() || bossIds.IsNullOrEmpty())
+            return;
+        for (int i = 0; i < heads.Count; i++)
+        {
+            if (i < bossIds.Count)
+            {
+                heads[i].SetActive(true);
+                heads[i].Display(bossIds[i]);
+            }
+            else
+            {
+                heads[i].SetActive(false);
+            }
+        }
+        ExecuteNextFrame(() =>
+        {
+            if (this != null && gameObject.activeInHierarchy && !isClosing && layoutGroupRect != null)
+            {
+                LayoutRebuilder.ForceRebuildLayoutImmediate(layoutGroupRect);
+            }
+        });
+
+    }
+
+}
\ No newline at end of file
diff --git a/Main/System/TianziBillborad/TianziBillboradWin.cs.meta b/Main/System/TianziBillborad/TianziBillboradWin.cs.meta
new file mode 100644
index 0000000..74d249b
--- /dev/null
+++ b/Main/System/TianziBillborad/TianziBillboradWin.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: 5506c1e2daa61a346bbf1eb95adc48b0
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 
diff --git a/Main/System/TianziBillborad/TianziDamageBar.cs b/Main/System/TianziBillborad/TianziDamageBar.cs
new file mode 100644
index 0000000..c418908
--- /dev/null
+++ b/Main/System/TianziBillborad/TianziDamageBar.cs
@@ -0,0 +1,224 @@
+using System;
+using UnityEngine;
+using UnityEngine.UI;
+
+public class TianziDamageBar : MonoBehaviour
+{
+    [SerializeField] IntensifySmoothSlider m_IntensifySlider;
+    [SerializeField] Text m_HurtInfo;
+    [SerializeField] Text m_BoxCount;
+
+    int bossId;
+    ulong nowHunt;    // 褰撳墠瀵笲oss鐨勪激瀹�
+    ulong nowHpMax; // 褰撳墠Boss鏈�澶ц閲�
+    int nowHpNum;   // 褰撳墠鏄疊oss绗嚑鏉¤
+    public event Action<int> StageUp;
+    public event Action<float, int> ValueChangeAction;
+    public event Action<ulong, ulong> ChangeEndAction;
+
+    public void Awake()
+    {
+        m_IntensifySlider.StageUpAction += OnStageUp;
+        m_IntensifySlider.ValueChangeAction += OnValueChange;
+        m_IntensifySlider.ChangeEndAction += OnChangeEndAction;
+
+    }
+    public void OnDestroy()
+    {
+        m_IntensifySlider.StageUpAction -= OnStageUp;
+        m_IntensifySlider.ValueChangeAction -= OnValueChange;
+        m_IntensifySlider.ChangeEndAction -= OnChangeEndAction;
+    }
+
+    private void OnChangeEndAction()
+    {
+        ChangeEndAction.Invoke(nowHunt, nowHpMax);
+        m_HurtInfo.text = Language.Get("BoneField09", nowHunt, UIHelper.ReplaceLargeNum(nowHpMax));
+    }
+
+    private void OnValueChange(float nowValue, int CurrentStage)
+    {
+        int hpNum = CurrentStage;
+        if (!TianziConfig.TryGetTianziConfigByBossIDAndHPNum(bossId, hpNum, out TianziConfig tianziConfig))
+            return;
+        ulong hpMax = (ulong)tianziConfig.MaxHP;
+        if (hpMax > 0)
+        {
+            m_HurtInfo.text = Language.Get("BoneField09", (int)(nowValue * hpMax), UIHelper.ReplaceLargeNum(hpMax));
+        }
+        //Debug.Log($"TianziDamageBar nowValue {nowValue} CurrentStage {CurrentStage} 鏃堕棿: {DateTime.Now:HH:mm:ss}");
+        ValueChangeAction?.Invoke(nowValue, CurrentStage);
+    }
+
+    private void OnStageUp(int stage)
+    {
+        m_BoxCount.text = Language.Get("TianziBillborad07", Mathf.Max(stage - 1, 0));
+        StageUp?.Invoke(stage);
+    }
+
+    public void Init()
+    {
+        int dataMapID = TianziBillboradManager.Instance.DataMapID;
+        int lineID = TianziBillboradManager.Instance.todayLineID;
+        if (!TianziBillboradManager.Instance.TryGetBossConfig(dataMapID, lineID, out DungeonConfig dungeonConfig, out NPCLineupConfig npcLineupConfig, out NPCConfig npcConfig))
+            return;
+        bossId = npcConfig.NPCID;
+        nowHpNum = 1; // 榛樿浠庣1鏉¤寮�濮�
+        if (!TianziConfig.TryGetTianziConfigByBossIDAndHPNum(bossId, nowHpNum, out TianziConfig tianziConfig))
+            return;
+        m_IntensifySlider.stage = 0;
+        m_IntensifySlider.ResetStage();
+        nowHunt = 0; // 鍒濆琛�閲忎负0
+        nowHpMax = (ulong)tianziConfig.MaxHP;
+        m_BoxCount.text = Language.Get("TianziBillborad07", 0);
+        // 闄ら浂淇濇姢
+        float percentage = 0f;
+        if (nowHpMax > 0)
+        {
+            percentage = Mathf.Clamp(nowHunt, 0, nowHpMax) / (float)nowHpMax;
+        }
+
+        m_IntensifySlider.value = percentage;
+        m_IntensifySlider.stage = nowHpNum; // 璁剧疆褰撳墠闃舵
+        m_HurtInfo.text = Language.Get("BoneField09", nowHunt, UIHelper.ReplaceLargeNum(nowHpMax));
+    }
+
+
+    // public event Action IsLastHitUnLockEvent;
+    // public void Show(ulong hp, ulong maxHp, BattleDmgInfo info)  // 鏄剧ず浼ゅ鏉�
+    // {
+    //     if (!TianziConfig.TryGetTianziConfigByBossIDAndMaxHP(bossId, (long)maxHp, out TianziConfig tianziConfig))
+    //         return;
+    //     if (info.isLastHit && isLock)
+    //     {
+    //         isLock = false;
+    //         IsLastHitUnLockEvent?.Invoke();
+    //     }
+
+    //     int hpNum = tianziConfig.HPNum;
+    //     ulong hunt = maxHp - hp;
+
+    //     if (maxHp < nowHpMax)
+    //     {
+    //         Debug.LogWarning($"TianziDamageBar SkillID  {info.skillConfig.SkillID} hp {hp} maxHp {maxHp} hunt {hunt} nowHpNum {nowHpNum} nowHunt {nowHunt} nowHpMax {nowHpMax} 鏃堕棿: {DateTime.Now:HH:mm:ss}");
+    //         return;
+    //     }
+
+    //     if (!isLock)
+    //     {
+    //         // 鏍规嵁maxHp鑾峰緱褰撳墠鏄鍑犳潯琛�
+    //         nowHpNum = hpNum;
+    //         nowHunt = hunt;
+    //         nowHpMax = maxHp;
+    //         // 闄ら浂淇濇姢
+    //         float percentage = 0f;
+    //         if (nowHpMax > 0)
+    //         {
+    //             percentage = Mathf.Clamp(nowHunt, 0, nowHpMax) / (float)nowHpMax;
+    //         }
+    //         m_IntensifySlider.value = percentage;
+    //         m_IntensifySlider.stage = nowHpNum; // 璁剧疆褰撳墠闃舵
+    //         Debug.Log($"TianziDamageBar SkillID  {info.skillConfig.SkillID} hp {hp} maxHp {maxHp} hunt {hunt} nowHpNum {nowHpNum} nowHunt {nowHunt} nowHpMax {nowHpMax} 鏃堕棿: {DateTime.Now:HH:mm:ss}");
+    //     }
+    // }
+
+    // bool isLock = false;
+    // public void ShowByB419(ulong hp, ulong maxHp)
+    // {
+    //     if (!TianziConfig.TryGetTianziConfigByBossIDAndMaxHP(bossId, (long)maxHp, out TianziConfig tianziConfig))
+    //         return;
+
+    //     isLock = true;
+
+    //     int hpNum = tianziConfig.HPNum;
+    //     ulong hunt = maxHp - hp;
+
+    //     if (maxHp < nowHpMax)
+    //     {
+    //         Debug.LogWarning($"TianziDamageBar  B419 hp {hp} maxHp {maxHp} hunt {hunt} nowHpNum {nowHpNum} nowHunt {nowHunt} nowHpMax {nowHpMax} 鏃堕棿: {DateTime.Now:HH:mm:ss}");
+    //         return;
+    //     }
+    //     nowHpNum = hpNum;
+    //     nowHunt = hunt;
+    //     nowHpMax = maxHp;
+    //     // 闄ら浂淇濇姢
+    //     float percentage = 0f;
+    //     if (nowHpMax > 0)
+    //     {
+    //         percentage = Mathf.Clamp(nowHunt, 0, nowHpMax) / (float)nowHpMax;
+    //     }
+    //     m_IntensifySlider.value = percentage;
+    //     m_IntensifySlider.stage = nowHpNum; // 璁剧疆褰撳墠闃舵
+    //     Debug.Log($"TianziDamageBar B419 hp {hp} maxHp {maxHp} hunt {hunt} nowHpNum {nowHpNum} nowHunt {nowHunt} nowHpMax{nowHpMax} 鏃堕棿: {DateTime.Now:HH:mm:ss}");
+    // }
+
+
+    public void Show(ulong totalHP)  // 鏄剧ず浼ゅ鏉�
+    {
+        if (!TianziConfig.TryGetTianziConfigByBossIDAndDamage(bossId, totalHP, out TianziConfig tianziConfig))
+            return;
+        ulong endMaxHp = (ulong)tianziConfig.MaxHP;
+        int endHpNum = tianziConfig.HPNum;
+        ulong endNowHunt = TianziConfig.GetCurrentHPDamage(bossId, totalHP);
+
+        nowHpNum = endHpNum;
+        nowHunt = endNowHunt;
+        nowHpMax = endMaxHp;
+
+        // 闄ら浂淇濇姢
+        float percentage = 0f;
+        if (nowHpMax > 0)
+        {
+            percentage = Mathf.Clamp(nowHunt, 0, nowHpMax) / (float)nowHpMax;
+        }
+        m_IntensifySlider.value = percentage;
+        m_IntensifySlider.stage = nowHpNum; // 璁剧疆褰撳墠闃舵
+        //Debug.Log($"TianziDamageBar end nowHpNum {nowHpNum} nowHunt {nowHunt} nowHpMax{nowHpMax} 鏃堕棿: {DateTime.Now:HH:mm:ss}");
+    }
+
+    ulong loaclNowHunt = 0;
+    ulong loaclAllHunt = 0;
+    ulong loaclMaxHp = 0;
+    int loaclHpNum = 0;
+    public void Show(BattleDmgInfo _damageInfo)
+    {
+        //闂伩鍜屽洖琛�绫讳笉绠椾激瀹�
+        if (_damageInfo.IsType(DamageType.Dodge) || _damageInfo.IsType(DamageType.Recovery))
+            return;
+        var damages = _damageInfo.damageList;
+        for (int i = 0; i < damages.Count; i++)
+        {
+            ulong hunt = (ulong)damages[i];
+            loaclAllHunt += hunt;
+            if (!TianziConfig.TryGetTianziConfigByBossIDAndDamage(bossId, loaclAllHunt, out TianziConfig tianziConfig))
+                return;
+            loaclMaxHp = (ulong)tianziConfig.MaxHP;
+            loaclHpNum = tianziConfig.HPNum;
+            loaclNowHunt = TianziConfig.GetCurrentHPDamage(bossId, loaclAllHunt);
+
+            // if (loaclMaxHp < nowHpMax || loaclHpNum < nowHpNum)
+            // {
+            //     Debug.LogWarning($"TianziDamageBar hunt {hunt} loaclAllHunt {loaclAllHunt} loaclHpNum {loaclHpNum} loaclNowHunt {loaclNowHunt} nowHpNum {nowHpNum} nowHunt {nowHunt} nowHpMax{nowHpMax} 鏃堕棿: {DateTime.Now:HH:mm:ss}");
+            //     return;
+            // }
+
+            // if (loaclNowHunt < nowHunt)
+            // {
+            //     Debug.LogWarning($"TianziDamageBar hunt {hunt} loaclAllHunt {loaclAllHunt} loaclHpNum {loaclHpNum} loaclNowHunt {loaclNowHunt} nowHpNum {nowHpNum} nowHunt {nowHunt} nowHpMax{nowHpMax} 鏃堕棿: {DateTime.Now:HH:mm:ss}");
+            //     return;
+            // }
+            nowHunt = loaclNowHunt;
+            nowHpMax = loaclMaxHp;
+            nowHpNum = loaclHpNum;
+            // 闄ら浂淇濇姢
+            float percentage = 0f;
+            if (nowHpMax > 0)
+            {
+                percentage = Mathf.Clamp(nowHunt, 0, nowHpMax) / (float)nowHpMax;
+            }
+            m_IntensifySlider.value = percentage;
+            m_IntensifySlider.stage = nowHpNum;
+            //Debug.Log($"TianziDamageBar hunt {hunt} loaclAllHunt {loaclAllHunt} loaclHpNum {loaclHpNum} loaclNowHunt {loaclNowHunt} nowHpNum {nowHpNum} nowHunt {nowHunt} nowHpMax{nowHpMax} 鏃堕棿: {DateTime.Now:HH:mm:ss}");
+        }
+    }
+}
\ No newline at end of file
diff --git a/Main/System/TianziBillborad/TianziDamageBar.cs.meta b/Main/System/TianziBillborad/TianziDamageBar.cs.meta
new file mode 100644
index 0000000..d931331
--- /dev/null
+++ b/Main/System/TianziBillborad/TianziDamageBar.cs.meta
@@ -0,0 +1,11 @@
+fileFormatVersion: 2
+guid: c0588389dd6e50a4ea91f1d5779482ff
+MonoImporter:
+  externalObjects: {}
+  serializedVersion: 2
+  defaultReferences: []
+  executionOrder: 0
+  icon: {instanceID: 0}
+  userData: 
+  assetBundleName: 
+  assetBundleVariant: 

--
Gitblit v1.8.0