using System; using System.Collections.Generic; using System.Linq; using System.Threading.Tasks; using asap.core; using cfg; using Event1v1Battle.Panel; using Event1v1Battle.Panel.MainPanel; using Event1v1Battle.Panel.RewardPanel; using game; using GameCore; using Newtonsoft.Json.Linq; using SideGameFromFishing; using UI.Home.Event; using UI.PackPanel; using UniRx; using UnityEngine; using IEventData = Activity.IEventData; using Random = UnityEngine.Random; using Activity; namespace Event1v1Battle.Data { /// /// 1v1扇耳光大赛活动管理器 /// public class Event1v1BattleSlapManager : Activity.AEventDataManager, IActivityEventRedPoint, ISideGameBombRaidProgress, ISideGameFishRaidProgress { #region 常量 private const int SOURCE_BOMB = 0; // 轰炸 private const int SOURCE_SHOOT = 1; // 射鱼 private const int SOURCE_FISHING = 2; // 钓鱼 #endregion #region 字段 private Event1v1BattleSlapPresentationData _presentationData = new(); /// /// 获取表现数据 /// public Event1v1BattleSlapPresentationData PresentationData => _presentationData; #endregion #region 构造函数 public Event1v1BattleSlapManager() { GContext.OnEvent().Subscribe(OnFishingEnd).AddTo(CompositeDisposable); GContext.OnEvent().Subscribe(OnHomeStart).AddTo(CompositeDisposable); } private void OnFishingEnd(FishingEndEvent e) { var data = LoadData(); #if UNITY_EDITOR if ((!data.IsActive || !data.IsOnGoing) && Tables.TbEventSlapSpinach.TryGetByItemID(e.ItemId, out _)) { Debug.LogError($"有人作弊触发了菠菜,需要匹配对少才能触发正确流程"); } #endif if (!data.IsActive || !data.IsOnGoing) return; Tables.TbEventSlapSpinach.TryGetByItemID(e.ItemId, out var spinachConfig); if (spinachConfig == null) return; OnSpinachCaught(data); } private void OnHomeStart(HomeStartEvent e) { var data = LoadData(); if (CheckAndHandleBattleTimeout(data)) return; var needShowNpcAttackTv = CheckAndSimulatePendingAttacks(data, needClear: !_presentationData.IsPlayAttacking); if (needShowNpcAttackTv) ShowFaceTv(data); } #endregion #region 初始化 #region 业务方法(从DataEx移入) /// /// 活动激活时初始化 /// public void InitOnActive(Event1v1BattleSlapData data) { InitRound(data); } /// /// 初始化当前轮次 /// public void InitRound(Event1v1BattleSlapData data) { data.CurrentStageID = data.InitConfig.InitialStage; data.StageHistory?.Clear(); data.PlayerLifeCount = 3; data.SlapPaidReviveCount = 0; InitializeStageHp(data); } /// /// 初始化当前关卡的HP /// public void InitializeStageHp(Event1v1BattleSlapData data) { var stageConfig = data.StageConfig; if (stageConfig == null) { Debug.LogError($"[EventSlap] Stage config not found for ID: {data.CurrentStageID}"); return; } RandomNpcData(data); int maxHp = GetPlayerMaxHp(data); data.NpcHp = maxHp; data.MaxHp = maxHp; data.PlayerHp = maxHp; } /// /// 获取玩家最大HP(关卡表 StageHP 经 与体力一致的膨胀系数处理) /// public int GetPlayerMaxHp(Event1v1BattleSlapData data) { var stageConfig = data.StageConfig; if (stageConfig == null) { Debug.LogError($"[EventSlap] Stage config not found for ID: {data.CurrentStageID}"); return 0; } return GContext.container.Resolve().IntInflation(stageConfig.StageHP, data.InflationRate); } /// /// 随机NPC数据 /// private void RandomNpcData(Event1v1BattleSlapData data) { var robotList = data.Tables.TbRobot.DataList; var index = Random.Range(0, robotList.Count); var npcConfig = robotList[index]; while (npcConfig == null) { Debug.LogError($"npcConfig 配置错误 id {index}"); index = Random.Range(0, robotList.Count); npcConfig = robotList[index]; } data.NpcIcon = npcConfig.Avatar; data.NpcName = npcConfig.Name; } /// /// Buff是否有效 /// public bool BuffIsValid(Event1v1BattleSlapData data) { var center = GContext.container?.Resolve(); return center != null && center.GetWeelyBuffTimeData() != null; } /// /// 获取Buff加成 /// public float GetBuffBenefit(Event1v1BattleSlapData data) { if (!BuffIsValid(data)) return 0; var buff = GContext.container?.Resolve()?.GetWeelyBuffTimeData(); return buff?.Param ?? 0; } /// /// 从 中取扇耳光伤害加成(),命中第一条配置即可。 /// private float GetEventSlapDamageBuffParamFromTable() { foreach (var fishBuff in Tables.TbFishBuff.DataList) { if (fishBuff.BuffParam is EventSlapDamageBuff slapDamageBuff) return slapDamageBuff.Param; } return 0f; } #endregion protected override void OnDataInitialized(IEventData data, FishingEvent eventConfig) { base.OnDataInitialized(data, eventConfig); // 新一期活动(EventID 变化)时重置 Slap01,配合主面板 TriggerGuide(..., false) 实现每期仅可触发一次 GContext.container.Resolve().ClearGuide(GroupName.Slap01.ToString()); var slapData = (Event1v1BattleSlapData)data; InitOnActive(slapData); ShowFacePanel(slapData); SaveData(slapData); } #endregion #region 玩家攻击 /// /// 玩家执行攻击 /// public void ExecutePlayerAttack(int multiplier, int sourceIndex, Event1v1BattleSlapData data) { if (!data.IsActive || !data.IsOnGoing) return; if (CheckAndHandleBattleTimeout(data, simulateNpcAttacks: false)) return; _presentationData.Clear(); _presentationData.Multiplier = multiplier; var damage = CalculateDamageBySource(data, multiplier, sourceIndex, out _presentationData.CanQuality); var qualityForAgg = _presentationData.CanQuality; damage = (int)(damage * (1 + GetBuffBenefit(data))); Agg_event_slap(GetSpinachSourceAggType(sourceIndex), multiplier, qualityForAgg, data.PlayerHp, BuffIsValid(data), data.NpcHp); _presentationData.IsPlayAttacking = true; _presentationData.SyncFromRealData(data); data.NpcHp -= damage; _presentationData.NpcHpAfterPlayerAttack = data.NpcHp; if (data.NpcHp <= 0) { _presentationData.KilledNpc = true; _presentationData.NextStageId = data.IsFinalStage ? data.InitConfig.InitialStage : data.StageConfig.NextStage; HandleStageHpDepleted(data); } else { CheckAndSimulatePendingAttacks(data, false); } SaveData(data); ShowFaceTv(data); } private void ShowFaceTv(Event1v1BattleSlapData data) { if (data == null || !data.IsActive) return; if (string.IsNullOrEmpty(data.InitConfig?.TvPopUpPanel)) return; UITypes.Event1v1BattleSlapTvPopupPanel.SetType(data.InitConfig.TvPopUpPanel); GContext.container.Resolve().AddPostFaceUI(UITypes.Event1v1BattleSlapTvPopupPanel); } #region 伤害计算 /// /// 用Weight随机选择倍率 /// private int SelectDamageByWeight(Event1v1BattleSlapData data) { var stageConfig = data.StageConfig; var damageList = stageConfig.DamageList; var weightList = stageConfig.Weight; if (damageList == null || damageList.Count == 0) return 1; if (weightList == null || weightList.Count != damageList.Count) return damageList[0]; int totalWeight = weightList.Sum(); if (totalWeight <= 0) return damageList[0]; int randomValue = Random.Range(0, totalWeight); int currentWeight = 0; for (int i = 0; i < damageList.Count; i++) { currentWeight += weightList[i]; if (randomValue < currentWeight) return damageList[i]; } return damageList[0]; } /// /// 根据来源计算最终伤害 /// public int CalculateDamageBySource(Event1v1BattleSlapData data, int multiplier, int sourceIndex, out int quality) { var spinachID = Tables.TbEventSlapMag.GetSpinachIDFromMag(multiplier); var config = data.GetSpinachConfig(spinachID); quality = config?.Quality ?? 0; switch (sourceIndex) { case SOURCE_FISHING: return CalculateFishingDamage(config, multiplier); case SOURCE_BOMB: return CalculateBombDamage(multiplier); case SOURCE_SHOOT: return CalculateRaidDamage(multiplier); default: return 0; } } private int CalculateFishingDamage(EventSlapSpinach config,int multiplier) { return multiplier; } private int CalculateBombDamage(int multiplier) { return multiplier * Tables.TbGlobalConfig.EventSlapBombPoint; } private int CalculateRaidDamage(int multiplier) { return multiplier * Tables.TbGlobalConfig.EventSlapRaidPoint; } #endregion #endregion #region NPC攻击 /// /// 模拟单次NPC攻击(不修改真实数据,用于判断是否致命) /// public bool SimulateStageAttack(Event1v1BattleSlapData data, int currentHp, out int damage, out int attackQuality, out int attackMultiplier, out bool npcBuffApplied) { damage = CalculateStageDamage(data, out attackQuality, out attackMultiplier, out npcBuffApplied); int newHp = currentHp - damage; return newHp <= 0; } /// /// 计算NPC对玩家的伤害(完整流程) /// public int CalculateStageDamage(Event1v1BattleSlapData data, out int attackQuality, out int attackMultiplier, out bool npcBuffApplied) { attackMultiplier = 0; npcBuffApplied = false; var stageConfig = data.StageConfig; if (stageConfig == null) { Debug.LogError($"[EventSlap] Stage config not found for ID: {data.CurrentStageID}"); attackQuality = 0; return -1; } attackMultiplier = SelectDamageByWeight(data); int finalDamage = CalculateDamageBySource(data, attackMultiplier, SOURCE_FISHING, out attackQuality); float coverage = Mathf.Clamp01(stageConfig.BuffCoverage); if (finalDamage > 0 && coverage > 0f && Random.value < coverage) { float buffParam = GetEventSlapDamageBuffParamFromTable(); if (buffParam > 0f) { npcBuffApplied = true; finalDamage = Mathf.Max(1, Mathf.RoundToInt(finalDamage * (1f + buffParam))); } } #if UNITY_EDITOR Debug.Log($"[EventSlap] Stage Damage: multiplier={attackMultiplier}, final={finalDamage}, quality={attackQuality}, buffCoverage={stageConfig.BuffCoverage}"); #endif return finalDamage; } /// /// 检查并结算所有已到时的 NPC 攻击(while (now >= NextAttackTime) 可在一帧内连续多段)。 /// TV 只播一次敌方扇耳光:表现层仅展示最后一击—— /// 为最后一击前血量, /// 为最后一击配置伤害; /// 飘字/血条动画用表现前血量与真实结算后 的差值,故未死时等价于只展示最后一击的扣血(例:20 血连挨 5、8,表现为从 15 扣 8)。 /// public bool CheckAndSimulatePendingAttacks(Event1v1BattleSlapData data, bool needClear = true) { var nowSeconds = new DateTimeOffset(ZZTimeHelper.UtcNow()).ToUnixTimeSeconds(); if (!data.IsActive || !data.IsOnGoing) return false; // 超时由 HandleBattleTimeout 内 ShowFaceTv 入待播;此处勿返回 true,否则 OnHomeStart 会再走立刻弹 TV 重复一次 if (CheckAndHandleBattleTimeout(data)) return false; if (nowSeconds < data.NextAttackTime) return false; if (needClear) { _presentationData.Clear(); _presentationData.SyncFromRealData(data); } int lastDamage = 0; int lastAttackQuality = 0; int hpBeforeLastAttack = data.PlayerHp; bool hasLethalAttack = false; while (nowSeconds >= data.NextAttackTime) { hpBeforeLastAttack = data.PlayerHp; bool isLethal = SimulateStageAttack(data, data.PlayerHp, out int damage, out int attackQuality, out int attackMultiplier, out bool npcBuffApplied); lastDamage = damage; lastAttackQuality = attackQuality; PresentationData.IsNpcBuffValid = npcBuffApplied; if (damage >= 0) Agg_event_slap_attacked(data.CurrentStageID, data.CurrentRoundForm1, attackMultiplier, npcBuffApplied, isLethal); if (isLethal) { hasLethalAttack = true; data.PlayerHp = 0; break; } data.PlayerHp -= damage; int intervalSeconds = data.GetNextAttackInterval(); data.NextAttackTime += intervalSeconds; } if (!hasLethalAttack && nowSeconds >= data.NextAttackTime) { RefreshNextAttackTime(data); } _presentationData.IsNpcAttacking = true; _presentationData.AttackDamage = lastDamage; _presentationData.NpcAttackCanQuality = lastAttackQuality; _presentationData.PlayerHp = hpBeforeLastAttack; if (data.PlayerHp <= 0) { _presentationData.KilledPlayer = true; data.PlayerHp = 0; HandlePlayerHpDepleted(data); } SaveData(data); return true; } #endregion #region 菠菜系统 /// /// 钓到菠菜后直接攻击NPC /// public void OnSpinachCaught(Event1v1BattleSlapData data) { if (!data.IsActive || !data.IsOnGoing) return; var mag = GContext.container.Resolve().GetMagnification(); ExecutePlayerAttack(mag, SOURCE_FISHING, data); } public void OnSpinachFromBomb(int mag, Event1v1BattleSlapData data) { if (!data.IsActive || !data.IsOnGoing) return; ExecutePlayerAttack(mag, SOURCE_BOMB, data); } public void OnSpinachFromShoot(Event1v1BattleSlapData data, int mag) { if (!data.IsActive || !data.IsOnGoing) return; ExecutePlayerAttack(mag, SOURCE_SHOOT, data); } #endregion #region 关卡管理 public void StartBattle(Event1v1BattleSlapData data) { data.IsOnGoing = true; data.BattleStartTime = new DateTimeOffset(ZZTimeHelper.UtcNow()).ToUnixTimeSeconds(); RefreshNextAttackTime(data); SaveData(data); } /// /// 刷新下次NPC攻击时间 /// public void RefreshNextAttackTime(Event1v1BattleSlapData data) { var now = ZZTimeHelper.UtcNow(); int intervalSeconds = data.GetNextAttackInterval(); Debug.Log($" slap NPC攻击时间刷新 {now} + {intervalSeconds}秒"); data.NextAttackTime = new DateTimeOffset(now).ToUnixTimeSeconds() + intervalSeconds; } /// /// 处理玩家HP归零 /// public void HandlePlayerHpDepleted(Event1v1BattleSlapData data) { data.NextAttackTime = 0; data.PlayerLifeCount--; data.IsOnGoing = false; data.BattleStartTime = 0; if (data.HasLifeRemaining) { InitializeStageHp(data); } else if (TryEnterPaidRevivePendingState(data)) { // 三命耗尽:有配置则停留当前进度,主界面下方走付费复活 } else if (data.ShouldStartNewRound()) { HandleStartNewRound(data); } } /// /// 当前付费复活应使用的 TbIAPItemList 配置 id(来自 GlobalConfig.EventSlapIapList,下标封顶为最后一项) /// public int GetPaidReviveIapTableId(Event1v1BattleSlapData data) { var list = data.Tables.TbGlobalConfig.EventSlapIapList; if (list == null || list.Count == 0) return 0; int idx = Math.Min(data.SlapPaidReviveCount, list.Count - 1); return list[idx]; } /// /// 三命为 0、活动仍有效、且配置了可用 IAP 时,等待玩家付费复活(不自动开新轮) /// public bool IsAwaitingPaidRevive(Event1v1BattleSlapData data) { if (data == null || !data.IsActive || data.PlayerLifeCount > 0) { return false; } var iapId = GetPaidReviveIapTableId(data); if (iapId <= 0) { Debug.LogError($"[EventSlap] IsAwaitingPaidRevive, return false"); return false; } var iapItem = data.Tables.TbIAPItemList?.GetOrDefault(iapId); if (iapItem == null) { Debug.LogError($"[EventSlap] IsAwaitingPaidRevive, iapItem not found"); return false; } return true; } bool TryEnterPaidRevivePendingState(Event1v1BattleSlapData data) { if (!data.IsActive) return false; var iapId = GetPaidReviveIapTableId(data); if (iapId <= 0) return false; if (data.Tables.TbIAPItemList?.GetOrDefault(iapId) == null) { Debug.LogError($"[EventSlap] EventSlapIapList id {iapId} not found in TbIAPItemList, fallback to new round."); return false; } return true; } /// /// 付费成功后:满血(当前关 MaxHp)并恢复 3 条命,保持关卡进度 /// private void ApplyPaidRevive(Event1v1BattleSlapData data) { PresentationData.Clear(); data.SlapPaidReviveCount++; data.PlayerLifeCount = 3; InitializeStageHp(data); } /// /// 发起付费复活(无额外掉落展示) /// public async Task TryPurchasePaidReviveAsync(Event1v1BattleSlapData data) { if (!IsAwaitingPaidRevive(data)) return false; int iapTableId = GetPaidReviveIapTableId(data); GContext.container.Resolve().ResolveIapId(iapTableId, out var iapItem, out _); if (iapItem == null) return false; var emptyGift = new List(); var buyType = new ShopBuyTypeData { type = ShopBuyType.None, ID = data.EventID, IsHide = true, NoShow = true, extraPurcheData = new JObject { ["event_slap_paid_revive"] = true, ["slap_paid_revive_index"] = data.SlapPaidReviveCount } }; bool ok = await GContext.container.Resolve() .OnBuy(0, buyType, iapItem, emptyGift); if (ok) { ApplyPaidRevive(data); SaveData(data); } return ok; } /// /// 处理关卡HP归零 /// public void HandleStageHpDepleted(Event1v1BattleSlapData data) { Agg_event_slap_stage(data.CurrentRoundForm1, data.CurrentStageID); data.needSendRewardStageID = data.CurrentStageID; data.StageHistory.Add(data.CurrentStageID, true); data.IsOnGoing = false; if (data.IsFinalStage) HandleStartNewRound(data); else ProceedToNextStage(data); } /// /// 进入下一关 /// public void ProceedToNextStage(Event1v1BattleSlapData data) { data.CurrentStageID = data.GetNextStageID(); InitializeStageHp(data); } /// /// 开始新轮次 /// public void HandleStartNewRound(Event1v1BattleSlapData data) { data.CurrentRoundForm1++; InitRound(data); Debug.Log($"[EventSlap] Starting new round: {data.CurrentRoundForm1}"); } #endregion #region 倒计时超时 /// /// 检查战斗是否已超时(30分钟倒计时结束) /// public bool IsBattleTimeout(Event1v1BattleSlapData data) { if (!data.IsOnGoing || data.BattleStartTime <= 0) return false; var nowSeconds = new DateTimeOffset(ZZTimeHelper.UtcNow()).ToUnixTimeSeconds(); return nowSeconds - data.BattleStartTime >= Tables.TbGlobalConfig.EventBattleDuration*60; } /// /// 处理战斗超时。 为 true 时先模拟超时期间 NPC 待定攻击, /// 若能打死玩家则按 NPC 攻击致死结算;否则(或 为 false 时)直接判超时负。 /// public void HandleBattleTimeout(Event1v1BattleSlapData data, bool simulateNpcAttacks = true) { if (!data.IsOnGoing) return; if (simulateNpcAttacks) { Debug.Log($"[EventSlap] Battle timeout! 30min elapsed, simulating NPC attacks during timeout period..."); long battleEndTime = data.BattleStartTime + Tables.TbGlobalConfig.EventBattleDuration * 60; if (SimulateNpcAttacksDuringTimeout(data, battleEndTime)) return; } Debug.Log($"[EventSlap] Battle timeout, settling as timeout defeat."); Agg_event_slap_timeout(data.PlayerHp, data.NpcHp, data.CurrentRoundForm1, data.CurrentStageID); _presentationData.Clear(); _presentationData.SyncFromRealData(data); _presentationData.IsTimeoutDefeat = true; _presentationData.KilledPlayer = true; data.PlayerHp = 0; HandlePlayerHpDepleted(data); SaveData(data); ShowFaceTv(data); } /// /// 模拟超时期间 NPC 的攻击:从 到 battleEndTime 逐次模拟。 /// 若 NPC 在此期间打死玩家,填充表现数据为 NPC 攻击致死(TV 播 NPC 攻击动画),并完成结算。 /// /// true 表示 NPC 在超时期间打死了玩家,已完成结算;false 表示玩家存活,调用方应走超时判负 private bool SimulateNpcAttacksDuringTimeout(Event1v1BattleSlapData data, long battleEndTime) { if (data.NextAttackTime <= 0 || data.NextAttackTime > battleEndTime) return false; _presentationData.Clear(); _presentationData.SyncFromRealData(data); int lastDamage = 0; int lastAttackQuality = 0; int hpBeforeLastAttack = data.PlayerHp; long simTime = data.NextAttackTime; while (simTime <= battleEndTime) { hpBeforeLastAttack = data.PlayerHp; bool isLethal = SimulateStageAttack(data, data.PlayerHp, out int damage, out int attackQuality, out int attackMultiplier, out bool npcBuffApplied); lastDamage = damage; lastAttackQuality = attackQuality; _presentationData.IsNpcBuffValid = npcBuffApplied; if (damage >= 0) Agg_event_slap_attacked(data.CurrentStageID, data.CurrentRoundForm1, attackMultiplier, npcBuffApplied, isLethal); if (isLethal) { Debug.Log($"[EventSlap] NPC killed player during timeout period at simTime={simTime}."); data.PlayerHp = 0; _presentationData.IsNpcAttacking = true; _presentationData.AttackDamage = lastDamage; _presentationData.NpcAttackCanQuality = lastAttackQuality; _presentationData.PlayerHp = hpBeforeLastAttack; _presentationData.KilledPlayer = true; HandlePlayerHpDepleted(data); SaveData(data); ShowFaceTv(data); return true; } data.PlayerHp -= damage; int intervalSeconds = data.GetNextAttackInterval(); simTime += intervalSeconds; } return false; } /// /// 在各业务入口调用,检查超时并自动处理 /// /// true 表示已触发超时处理,调用方应终止后续逻辑 public bool CheckAndHandleBattleTimeout(Event1v1BattleSlapData data, bool simulateNpcAttacks = true) { if (!IsBattleTimeout(data)) return false; HandleBattleTimeout(data, simulateNpcAttacks); return true; } #endregion #region 奖励 public void SendStageReward(Event1v1BattleSlapData data) { var change = new ChangeSource(data.EventID, "Event_Minigame4", "Event_Minigame4_1V1Slap", "StageReward"); var config = Tables.TbEventSlapStage.GetOrDefault(data.needSendRewardStageID); GContext.container.Resolve() .AddItemByDropLureInflation(data.InflationRate, config.DropId, change); GContext.Publish(new ShowData()); data.needSendRewardStageID = 0; SetRedPoint(data); SaveData(data); } #endregion #region 主面板 public async Task ShowSlapPanel(Event1v1BattleSlapData data = null) { try { if (data == null) data = LoadData(); var panel = await GetBattleSlapContainer(data); panel.SetData(this).ShowBattleSlapPanel(); } catch (Exception e) { Debug.LogError(e); } } private async Task GetBattleSlapContainer(Event1v1BattleSlapData data) { if (data?.InitConfig == null) return null; UITypes.Event1v1BattleSlapPanel.SetType(data.InitConfig.UIPanel); GameObject obj; if (!UIManager.Instance.ContainsUI(UITypes.Event1v1BattleSlapPanel)) obj = await UIManager.Instance.ShowUILoad(UITypes.Event1v1BattleSlapPanel); else obj = UIManager.Instance.GetContainedUI(UITypes.Event1v1BattleSlapPanel); var panel = obj.GetComponent(); if (panel) return panel; Debug.LogError("[EventSlap] Failed to get Event1v1BattleSlapPanel"); return null; } public async Task ShowSlapMatchPanelAndRandom(Event1v1BattleSlapData data) { try { var panel = await GetBattleSlapContainer(data); panel.SetData(this).PlayRandomRpcAni(); } catch (Exception e) { Debug.LogError(e); } } #endregion #region 弹窗面板 public async Task ShowTvPanel(Event1v1BattleSlapData data) { try { if (data?.InitConfig == null) return null; UITypes.Event1v1BattleSlapTvPopupPanel.SetType(data.InitConfig.TvPopUpPanel); GameObject obj = await UIManager.Instance.ShowUILoad(UITypes.Event1v1BattleSlapTvPopupPanel); return obj.GetComponent(); } catch (Exception e) { Debug.LogError(e); return null; } } public async void ShowLoadingPanel(Event1v1BattleSlapData data) { try { if (data?.InitConfig == null) return; UITypes.Event1v1BattleSlapLoadingPanel.SetType(data.InitConfig.LoadingPanel); var obj = await UIManager.Instance.ShowUILoad(UITypes.Event1v1BattleSlapLoadingPanel); obj.GetComponent()?.SetData(this, data); } catch (Exception e) { Debug.LogError(e); } } public async void ShowStagePanel(Event1v1BattleSlapData data) { try { if (data?.InitConfig == null) return; UITypes.Event1v1BattleSlapPreviewPopupPanel.SetType(data.InitConfig.EventPreviewPanel); await UIManager.Instance.ShowUILoad(UITypes.Event1v1BattleSlapPreviewPopupPanel); } catch (Exception e) { Debug.LogError(e); } } public async void ShowAllStageRewardPanel(Event1v1BattleSlapData data) { try { if (data?.InitConfig == null) return; UITypes.Event1v1BattleSlapRewardPopupPanel.SetType(data.InitConfig.RewardPanel); var panelObj = await UIManager.Instance.ShowUILoad(UITypes.Event1v1BattleSlapRewardPopupPanel); var panel = panelObj.GetComponent(); panel.SetData(data); } catch (Exception e) { Debug.LogError(e); } } public void ShowFacePanel(Event1v1BattleSlapData data) { if (data == null) return; UITypes.Event1v1BattleSlapFacePopupPanel.SetType(data.InitConfig.StageReviewPanel); GContext.container.Resolve() .AddGiftFaceUI(data.EventID, UITypes.Event1v1BattleSlapFacePopupPanel, 0); } #endregion #region 礼包 public async void ShowFestPackPanel() { try { var data = LoadData(); if (data?.InitConfig == null) return; var packConfig = Tables.TbEventPackManager.GetOrDefault(data.InitConfig.PackID); if (packConfig == null) { Debug.LogError($"[EventSlap] PackID {data.InitConfig.PackID} not found"); return; } var panelObj = await UIManager.Instance.ShowUILoad(new UIType(data.InitConfig.PackPanel)); var panel = panelObj.GetComponent(); panel.ShowUI(packConfig, data.EventID, data.IsClaimedFreePack, data.RemainingTime, () => { data.IsClaimedFreePack = true; SetRedPoint(data); SaveData(data); }, null); } catch (Exception e) { Debug.LogError(e); } } #endregion #region 红点 private string GetRedPointKey() { return "eventBattleSlap.red"; } private bool GetRedPointState(Event1v1BattleSlapData data) { if (!data.IsActive) return false; return !data.IsClaimedFreePack || data.IsNeedSendReward; } public void SetRedPoint(Event1v1BattleSlapData data) { RedPointManager.Instance?.SetRedPointState(GetRedPointKey(), GetRedPointState(data)); } #endregion #region 外部接口 public int GetActivateItemId(Event1v1BattleSlapData data = null) { if (data == null) data = LoadData(); if (!data.IsActive || !data.IsOnGoing) return 0; float basicProb = Random.Range(0, 1f); if (!(basicProb <= data.Tables.TbGlobalConfig.EventSlapProb)) return 0; try { var mag = GContext.container.Resolve().GetMagnification(); var spinachID = data.Tables.TbEventSlapMag.GetSpinachIDFromMag(mag); return data.GetSpinachConfig(spinachID).FishItemID; } catch (Exception e) { Debug.LogError($"GetActivateItemId Error: {e.Message}"); return 0; } } #endregion #region 接口实现 public List AddBombRaidProgress(int multiple) { var data = LoadData(); if(!data.IsActive || !data.IsOnGoing) return null; OnSpinachFromBomb(multiple, data); var config = data.GetSpinachConfig(Tables.TbEventSlapMag.GetSpinachIDFromMag(multiple)); return config == null ? null : new List { new TargetAddData(config.FishItemID, 0, multiple) }; } public List AddFishRaidProgress(int multiple) { var data = LoadData(); if(!data.IsActive || !data.IsOnGoing) return null; OnSpinachFromShoot(data, multiple); var config = data.GetSpinachConfig(Tables.TbEventSlapMag.GetSpinachIDFromMag(multiple)); return config == null ? null : new List { new TargetAddData(config.FishItemID, 0, multiple) }; } #endregion #region Agg private static string GetSpinachSourceAggType(int sourceIndex) { return sourceIndex switch { SOURCE_BOMB => "bomb", SOURCE_SHOOT => "raid", SOURCE_FISHING => "fish", _ => "unknown" }; } /// /// event_slap 获得辣椒罐头(发起攻击)时上报 /// public void Agg_event_slap(string type, int multiple, int quality, int player_hp, bool is_buff, int enemy_hp) { #if AGG using (var e = GEvent.GameEvent("event_slap")) { e.AddContent(nameof(type), type) .AddContent(nameof(multiple), multiple) .AddContent(nameof(quality), quality) .AddContent(nameof(player_hp), player_hp) .AddContent(nameof(is_buff), is_buff) .AddContent(nameof(enemy_hp), enemy_hp); } #endif } /// /// event_slap_stage 击败对手时上报 /// public void Agg_event_slap_stage(int round, int stage_id) { #if AGG using (var e = GEvent.GameEvent("event_slap_stage")) { e.AddContent(nameof(round), round) .AddContent(nameof(stage_id), stage_id); } #endif } /// /// event_slap_attacked 被对手攻击时上报 /// public void Agg_event_slap_attacked(int stage_id, int round, int multiple, bool is_buff, bool is_defeat) { #if AGG using (var e = GEvent.GameEvent("event_slap_attacked")) { e.AddContent(nameof(stage_id), stage_id) .AddContent(nameof(round), round) .AddContent(nameof(multiple), multiple) .AddContent(nameof(is_buff), is_buff) .AddContent(nameof(is_defeat), is_defeat); } #endif } /// /// event_slap_timeout 战斗超时时上报 /// public void Agg_event_slap_timeout(int player_hp, int enemy_hp, int round, int stage_id) { #if AGG using (var e = GEvent.GameEvent("event_slap_timeout")) { e.AddContent(nameof(player_hp), player_hp) .AddContent(nameof(enemy_hp), enemy_hp) .AddContent(nameof(round), round) .AddContent(nameof(stage_id), stage_id); } #endif } #endregion #if UNITY_EDITOR #region 调试 public void Debug_SetStage(int stageID) { var data = LoadData(); data.CurrentStageID = stageID; data.StageHistory = new Dictionary(); var index = data.GetStageIndex(Tables.TbEventSlapStage.GetOrDefault(stageID)); for (int i = 0; i < index; i++) { data.StageHistory.Add(data.GetAllStage()[i].ID, true); } InitializeStageHp(data); SaveData(data); } public void Debug_SetLife(int lifeCount) { var data = LoadData(); data.PlayerLifeCount = lifeCount; SaveData(data); } #endregion #endif } }