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
}
}