using LitJson;
|
using vnxbqy.UI;
|
using System;
|
using System.Collections.Generic;
|
using UnityEngine;
|
|
public class TurnFightModel : SingletonMonobehaviour<TurnFightModel>
|
{
|
E_TurnFightStep turnFightStep; //接收封包时的战场状态,并非执行的时候
|
// 回合战斗开始后对封包进行管理,需要按时间线播放(加速或者跳过),先存储起来不处理,然后再播放
|
List<GameNetPackBasic> turnFightPacks = new List<GameNetPackBasic>();
|
int packIndex; //队列执行点
|
bool isDoUpdatePack = false; //是否对存储队列进行封包处理
|
float lastChallengeTick = 0; // 上次挑战时间 用于限制挑战频率
|
float lastAttackTick = 0; // 上次攻击时间 用于加速控制
|
float lastAttackInterval = 1f; // 上次攻击间隔 用于加速控制
|
public int speedMul = 1; // 播放速度倍数
|
float waitCameraTick = 0; // 等待镜头时间
|
|
public bool isSkip = false; //是否跳过战斗
|
public int canJumpTurnNum = 0; //第几个回合后可跳过战斗
|
public Dictionary<int, int> speedMulOpenTask = new Dictionary<int, int>(); //任务开启的加速倍数
|
int[][] enemyPosArr; //敌人位置
|
int[][] friendPosArr; //友方位置
|
public int distance = 5; //敌人与友方的距离
|
|
public const int AdventureMapID = 5000; //冒险地图ID
|
public event Action OnTurnFightEvent;
|
public int m_MapID; // 自定义地图ID,可用于绑定战斗场景功能(如野外关卡,爬塔功能,竞技场等)
|
public int m_FuncLineID;
|
public int m_PlayerID; // 对应玩家ID,可为0,某些功能可能有用,如竞技场
|
public int m_State; // 0-开始;1-战斗中;2-胜利;3-失败;4-结束
|
public int m_TurnNum = 1; // 当前轮次
|
public int m_TurnMax = 15; // 最大轮次
|
public string m_Msg; //自定义信息,准备是npc信息,结算是奖励信息
|
|
FactionObjInfo[] factionInfo; // 回合战斗双方信息
|
Dictionary<int, int> factionPlayerData = new Dictionary<int, int>(); // 回合战斗玩家的模型(后续可扩展更多数据,或者组队)
|
public FightResult fightResult; // 回合战斗结果
|
|
List<GActor> enemyActors = new List<GActor>();
|
List<GActor> friendActors = new List<GActor>();
|
//与人的回合战斗坐标, 其他按功能各自表配置 如天星塔表,冒险回合表
|
public Dictionary<string, int[]> turnFightPosEx = new Dictionary<string, int[]>();
|
|
//RoleParticularModel roleParticularModel { get { return ModelCenter.Instance.GetModel<RoleParticularModel>(); } }
|
VipModel vipModel { get { return ModelCenter.Instance.GetModel<VipModel>(); } }
|
CutTreeModel cutTreeModel { get { return ModelCenter.Instance.GetModel<CutTreeModel>(); } }
|
DungeonModel dungeonModel { get { return ModelCenter.Instance.GetModel<DungeonModel>(); } }
|
ChallengeDemonKingModel challengeDemonKingModel { get { return ModelCenter.Instance.GetModel<ChallengeDemonKingModel>(); } }
|
SkyTowerModel skyTowerModel { get { return ModelCenter.Instance.GetModel<SkyTowerModel>(); } }
|
RuneTowerModel runeTowerModel { get { return ModelCenter.Instance.GetModel<RuneTowerModel>(); } }
|
|
public void Init()
|
{
|
DTC0102_tagCDBPlayer.afterPlayerDataInitializeEvent += OnAfterPlayerDataInitialize;
|
ParseConfig();
|
}
|
|
void OnAfterPlayerDataInitialize()
|
{
|
lastChallengeTick = 0;
|
m_MapID = 0;
|
m_FuncLineID = 0;
|
m_PlayerID = 0;
|
m_State = 0;
|
m_TurnNum = 1;
|
|
speedMul = LocalSave.GetInt("TurnFightSpeed" + PlayerDatas.Instance.baseData.PlayerID , 1);
|
|
EndTurnFight(); //如果是重连 立即结束战斗
|
}
|
|
void ParseConfig()
|
{
|
var config = FuncConfigConfig.Get("TurnFight2");
|
canJumpTurnNum = int.Parse(config.Numerical1);
|
JsonData json = JsonMapper.ToObject(config.Numerical2);
|
foreach (var key in json.Keys)
|
{
|
speedMulOpenTask.Add(int.Parse(key), int.Parse(json[key].ToString()));
|
}
|
|
enemyPosArr = JsonMapper.ToObject<int[][]>(config.Numerical3);
|
friendPosArr = JsonMapper.ToObject<int[][]>(config.Numerical4);
|
distance = Math.Abs(enemyPosArr[0][0]);
|
turnFightPosEx = JsonMapper.ToObject<Dictionary<string, int[]>>(config.Numerical5);
|
}
|
|
|
protected void LateUpdate()
|
{
|
if (!isDoUpdatePack) return;
|
|
if (Time.realtimeSinceStartup - waitCameraTick < 0.1)
|
{
|
return;
|
}
|
|
if (packIndex >= turnFightPacks.Count) return;
|
var curPack = turnFightPacks[packIndex];
|
|
if (isSkip)
|
{
|
for (int i = packIndex; i < turnFightPacks.Count; i++)
|
{
|
curPack = turnFightPacks[i];
|
//后续优化:反向过滤 明确不需要执行的封包(如战斗表现包),其他封包立即执行
|
if (curPack.cmd == 0xB420 || curPack.cmd == 0x0608 || curPack.cmd == 0xA320)
|
{
|
PackageRegedit.Distribute(curPack);
|
}
|
}
|
return;
|
}
|
|
if (curPack.cmd == 0xB421 || curPack.cmd == 0xB422 || curPack.cmd == 0xB423 || curPack.cmd == 0x0614 || curPack.cmd == 0x0602)
|
{
|
|
//攻击和分割封包按间隔执行,其他包立即执行
|
if(Time.realtimeSinceStartup - lastAttackTick < lastAttackInterval)
|
{
|
return;
|
}
|
if (curPack.cmd != 0xB421)
|
{
|
lastAttackTick = Time.realtimeSinceStartup;
|
}
|
|
}
|
|
packIndex++;
|
PackageRegedit.Distribute(curPack);
|
}
|
|
|
// 改变播放速度, 任务开启 或者 首充开启
|
public void ChangePlaySpeed()
|
{
|
int maxSpeed = 1;
|
int speed2TaskCount = cutTreeModel.GetTaskCountToFinish(speedMulOpenTask[2]);
|
//2倍速度
|
if (vipModel.FirstGoldServerDay == 0 && speed2TaskCount > 0)
|
{
|
SysNotifyMgr.Instance.ShowTip("TurnFight1", speed2TaskCount);
|
return;
|
}
|
maxSpeed = 2;
|
|
int speed3TaskCount = cutTreeModel.GetTaskCountToFinish(speedMulOpenTask[3]);
|
//3倍速度
|
if (speed3TaskCount > 0)
|
{
|
if (speedMul == 2)
|
SysNotifyMgr.Instance.ShowTip("TurnFight2", speed3TaskCount);
|
}
|
else
|
{
|
maxSpeed = 3;
|
}
|
|
speedMul = speedMul % maxSpeed + 1;
|
LocalSave.SetInt("TurnFightSpeed" + PlayerDatas.Instance.baseData.PlayerID, speedMul);
|
lastAttackInterval = Math.Min(1f / speedMul + 0.1f, 1f);
|
}
|
|
//动作的速度变化
|
public float GetPlaySpeed()
|
{
|
return speedMul*1.2f;
|
}
|
|
/// <summary>
|
/// 向服务端请求回合战斗,服务端一次性结算下发,客户端进行表现
|
/// </summary>
|
/// <param name="mapID"> mapid 和lineid 共同决定是哪个功能的回合战,并不是字面意思的地图和线路</param>
|
/// <param name="lineID"></param>
|
/// <param name="playerID">向玩家进行离线挑战时 如竞技场</param>
|
/// tagType 战斗目标类型,0-NPC,1-玩家,2-队伍
|
/// valueList 附加值列表,可选,具体含义由MapID决定
|
//玩家间的战斗需先用AddPlayerAInfo和AddPlayerBInfo
|
public void StartTurnFight(int mapID, int lineID, int tagType, int tagID, uint[] valueList = null)
|
{
|
if (Time.realtimeSinceStartup - lastChallengeTick < 1)
|
{
|
return;
|
}
|
|
lastChallengeTick = Time.realtimeSinceStartup;
|
var pack = new CB410_tagCMTurnFight();
|
pack.MapID = (uint)mapID;
|
pack.FuncLineID = (ushort)lineID;
|
pack.TagType = (byte)tagType;
|
pack.TagID = (uint)tagID;
|
pack.ValueCount = valueList == null ? (byte)0 : (byte)valueList.Length;
|
pack.ValueList = valueList == null ? new uint[0] : valueList;
|
GameNetSystem.Instance.SendInfo(pack);
|
}
|
|
public void OnTurnFightResult(HB420_tagMCTurnFightState pack)
|
{
|
var state = (E_TurnFightStep)(pack.State + 1);
|
if (!isDoUpdatePack)
|
{
|
//存储队列和战场状态的处理
|
if (state == E_TurnFightStep.Start)
|
{
|
isSkip = false;
|
turnFightPacks.Clear();
|
if (turnFightPacks.IsNullOrEmpty())
|
turnFightPacks.Add(pack);
|
}
|
turnFightStep = state;
|
if (pack.TurnMax != 0)
|
m_TurnMax = pack.TurnMax;
|
|
if (turnFightStep == E_TurnFightStep.Over)
|
{
|
isDoUpdatePack = true;
|
|
}
|
}
|
else
|
{
|
m_MapID = (int)pack.MapID;
|
m_FuncLineID = pack.FuncLineID;
|
if (pack.TagType == 1)
|
m_PlayerID = (int)pack.TagID;
|
m_State = pack.State;
|
|
|
m_Msg = pack.Msg;
|
if (state == E_TurnFightStep.Start)
|
{
|
InitTurnFight();
|
|
}
|
else if (state == E_TurnFightStep.PrepareOK)
|
{
|
PrepareTurnFight();
|
}
|
else if (state == E_TurnFightStep.Fighting)
|
{
|
if (pack.TurnNum == 1)
|
{
|
//插入时间用于表现
|
lastAttackTick = Time.realtimeSinceStartup - 0.1f * speedMul;
|
}
|
}
|
else if (state == E_TurnFightStep.Result)
|
{
|
OnFightResult();
|
}
|
else if (state == E_TurnFightStep.Over)
|
{
|
ClearTurnFight();
|
}
|
}
|
}
|
|
//跳过直接结束战斗
|
public void EndTurnFight()
|
{
|
//立即处理剩余所有封包和逻辑
|
isSkip = true;
|
}
|
|
void InitTurnFight()
|
{
|
isSkip = false;
|
factionInfo = null;
|
PlayerDatas.Instance.hero.Behaviour.StopKillUntilDieAI();
|
PlayerDatas.Instance.hero.Behaviour.StopHandupAI();
|
WindowCenter.Instance.CloseAll();
|
WindowCenter.Instance.Close<MainInterfaceWin>();
|
WindowCenter.Instance.Open<TurnFightWin>();
|
}
|
|
void PrepareTurnFight()
|
{
|
factionInfo = JsonMapper.ToObject<FactionObjInfo[]>(m_Msg);
|
|
//创建友方
|
AddFriend(GAMgr.Instance.GetBySID((uint)factionInfo[0].objID));
|
for (int i = 0; i < factionInfo[0].petObjIDList.Length; i++)
|
{
|
AddFriend(GAMgr.Instance.GetBySID((uint)factionInfo[0].petObjIDList[i]));
|
}
|
|
//创建敌人
|
AddEnemy(GAMgr.Instance.GetBySID((uint)factionInfo[1].objID));
|
for (int i = 0; i < factionInfo[1].petObjIDList.Length; i++)
|
{
|
AddEnemy(GAMgr.Instance.GetBySID((uint)factionInfo[1].petObjIDList[i]));
|
}
|
|
//设置面向
|
for (int i = 0; i < friendActors.Count; i++)
|
{
|
friendActors[i].Forward = MathUtility.ForwardXZ(enemyActors[0].Pos, friendActors[i].Pos);
|
}
|
|
for (int i = 0; i < enemyActors.Count; i++)
|
{
|
enemyActors[i].Forward = MathUtility.ForwardXZ(friendActors[0].Pos, enemyActors[i].Pos);
|
}
|
|
//设置头顶信息
|
enemyActors[0].RequestLifeBar();
|
|
//设置玩家外观
|
int playerID = factionInfo[0].playerID;
|
factionPlayerData[playerID] = factionInfo[0].ModelMark;
|
if (playerID != 0)
|
{
|
var player = GAMgr.Instance.GetBySID((uint)playerID);
|
if (player != null)
|
{
|
//玩家是自己
|
friendActors[0].ActorInfo.modelMark = player.ActorInfo.modelMark;
|
}
|
else
|
{
|
//从缓存信息中获取 暂不考虑组队情况
|
friendActors[0].ActorInfo.modelMark = factionPlayerData[playerID];
|
}
|
(friendActors[0] as GActorFight).ChangeModelByModelMark();
|
}
|
|
playerID = factionInfo[1].playerID;
|
factionPlayerData[playerID] = factionInfo[1].ModelMark;
|
if (playerID != 0)
|
{
|
enemyActors[0].ActorInfo.modelMark = factionPlayerData[playerID];
|
(enemyActors[0] as GActorFight).ChangeModelByModelMark();
|
}
|
|
//拉镜头
|
CameraController.Instance.StartTurnFightCamera(friendActors[0]);
|
waitCameraTick = Time.realtimeSinceStartup;
|
}
|
|
void ClearTurnFight()
|
{
|
waitCameraTick = 0;
|
turnFightPacks.Clear();
|
packIndex = 0;
|
turnFightStep = E_TurnFightStep.None;
|
isDoUpdatePack = false;
|
isSkip = false;
|
enemyActors.Clear();
|
friendActors.Clear();
|
factionPlayerData.Clear();
|
m_TurnNum = 1;
|
CameraController.Instance.StopTurnFightCamera();
|
WindowCenter.Instance.Open<MainInterfaceWin>();
|
WindowCenter.Instance.Close<TurnFightWin>();
|
}
|
|
//收集回合制战斗封包
|
public bool AddNetPack(GameNetPackBasic pack)
|
{
|
if (turnFightStep == E_TurnFightStep.None || turnFightStep == E_TurnFightStep.Over)
|
return false;
|
|
turnFightPacks.Add(pack);
|
if (pack.cmd == 0xB420)
|
return false;
|
|
return true;
|
}
|
|
|
public void OnTurnFighting(HB421_tagMCTurnFightObjAction pack)
|
{
|
m_TurnNum = pack.TurnNum;
|
//只是用于分割时间线,不做处理
|
OnTurnFightEvent?.Invoke();
|
}
|
|
//是否回合制成员
|
public bool IsTurnFightMember(GActor actor)
|
{
|
if (friendActors.Contains(actor) || enemyActors.Contains(actor))
|
return true;
|
|
return false;
|
}
|
|
//是否在执行回合制
|
public bool IsTurnFight()
|
{
|
return isDoUpdatePack;
|
}
|
|
|
//是否在执行回合制的战斗中流程
|
public bool IsTurnFighting()
|
{
|
if (!IsTurnFight())
|
return false;
|
|
if ((E_TurnFightStep)m_State + 1 != E_TurnFightStep.Fighting)
|
return false;
|
|
return true;
|
}
|
|
|
|
public void AddEnemy(GActor actor)
|
{
|
if (m_MapID == AdventureMapID)
|
{
|
var config = AdventureConfig.Get(m_FuncLineID);
|
enemyActors.Add(actor);
|
actor.Pos = GetEnemyPos(actor, config.Pos[0], config.Pos[1]);
|
}
|
else if (m_MapID == ChallengeDemonKingModel.PERSONALBOSS_MAPID)
|
{
|
var config = PersonalBossConfig.Get(challengeDemonKingModel.showNpcID);
|
enemyActors.Add(actor);
|
actor.Pos = GetEnemyPos(actor, config.Pos[0], config.Pos[1]);
|
}
|
else if (m_MapID == SkyTowerModel.DATA_MAPID)
|
{
|
var config = SkyTowerConfig.Get(skyTowerModel.currentFloor);
|
enemyActors.Add(actor);
|
actor.Pos = GetEnemyPos(actor, config.Pos[0], config.Pos[1]);
|
}
|
else if (m_MapID == RuneTowerModel.RUNETOWER_MAPID)
|
{
|
var config = RuneTowerFloorConfig.Get(runeTowerModel.currentFloor);
|
enemyActors.Add(actor);
|
actor.Pos = GetEnemyPos(actor, config.Pos[0], config.Pos[1]);
|
}
|
else
|
{
|
enemyActors.Add(actor);
|
int[] pos;
|
if (!turnFightPosEx.ContainsKey(StringUtility.Contact(m_MapID, "_", m_FuncLineID)))
|
{
|
if (m_FuncLineID == 0)
|
{
|
Debug.LogError("没有配置回合制坐标 turnFightPosEx");
|
return;
|
}
|
else if (!turnFightPosEx.ContainsKey(StringUtility.Contact(m_MapID, "_", 0)))
|
{
|
Debug.LogError("没有配置回合制坐标 turnFightPosEx");
|
return;
|
}
|
pos = turnFightPosEx[StringUtility.Contact(m_MapID, "_", 0)];
|
}
|
else
|
{
|
pos = turnFightPosEx[StringUtility.Contact(m_MapID, "_", m_FuncLineID)];
|
}
|
|
actor.Pos = new Vector3((pos[0] + enemyPosArr[enemyActors.Count - 1][0]) * .5f, actor.Pos.y, (pos[1] + enemyPosArr[enemyActors.Count - 1][1]) * .5f);
|
}
|
}
|
|
public void AddFriend(GActor actor)
|
{
|
if (m_MapID == AdventureMapID)
|
{
|
var config = AdventureConfig.Get(m_FuncLineID);
|
friendActors.Add(actor);
|
actor.Pos = GetFriendPos(actor, config.Pos[0], config.Pos[1]);
|
}
|
else if (m_MapID == ChallengeDemonKingModel.PERSONALBOSS_MAPID)
|
{
|
var config = PersonalBossConfig.Get(challengeDemonKingModel.showNpcID);
|
friendActors.Add(actor);
|
actor.Pos = GetFriendPos(actor, config.Pos[0], config.Pos[1]);
|
}
|
else if (m_MapID == SkyTowerModel.DATA_MAPID)
|
{
|
var config = SkyTowerConfig.Get(skyTowerModel.currentFloor);
|
friendActors.Add(actor);
|
actor.Pos = GetFriendPos(actor, config.Pos[0], config.Pos[1]);
|
}
|
else if (m_MapID == RuneTowerModel.RUNETOWER_MAPID)
|
{
|
var config = RuneTowerFloorConfig.Get(runeTowerModel.currentFloor);
|
friendActors.Add(actor);
|
actor.Pos = GetFriendPos(actor, config.Pos[0], config.Pos[1]);
|
}
|
else
|
{
|
friendActors.Add(actor);
|
int[] pos;
|
if (!turnFightPosEx.ContainsKey(StringUtility.Contact(m_MapID, "_", m_FuncLineID)))
|
{
|
if (m_FuncLineID == 0)
|
{
|
Debug.LogError("没有配置回合制坐标 turnFightPosEx");
|
return;
|
}
|
else if (!turnFightPosEx.ContainsKey(StringUtility.Contact(m_MapID, "_", 0)))
|
{
|
Debug.LogError("没有配置回合制坐标 turnFightPosEx");
|
return;
|
}
|
pos = turnFightPosEx[StringUtility.Contact(m_MapID, "_", 0)];
|
}
|
else
|
{
|
pos = turnFightPosEx[StringUtility.Contact(m_MapID, "_", m_FuncLineID)];
|
}
|
actor.Pos = new Vector3((pos[0] + friendPosArr[friendActors.Count - 1][0]) * .5f, actor.Pos.y, (pos[1] + friendPosArr[friendActors.Count - 1][1]) * .5f);
|
}
|
}
|
|
Vector3 GetFriendPos(GActor actor, int x, int z)
|
{
|
return new Vector3((x + friendPosArr[friendActors.Count - 1][0]) * .5f, actor.Pos.y, (z + friendPosArr[friendActors.Count - 1][1]) * .5f);
|
}
|
|
Vector3 GetEnemyPos(GActor actor, int x, int z)
|
{
|
return new Vector3((x + enemyPosArr[enemyActors.Count - 1][0]) * .5f, actor.Pos.y, (z + enemyPosArr[enemyActors.Count - 1][1]) * .5f);
|
}
|
|
//复活
|
public void Reborn(HB423_tagMCTurnFightObjReborn netPack)
|
{
|
GActorFight _attacker = GAMgr.Instance.GetBySID(netPack.ObjID) as GActorFight;
|
_attacker.ActorInfo.SyncServerHp = netPack.HP + netPack.HPEx * Constants.ExpPointValue;
|
_attacker.ActorInfo.IncreaseHp(_attacker.ActorInfo.SyncServerHp);
|
_attacker.Play(GAStaticDefine.State_IdleHash);
|
|
if (netPack.RebornType == 1)
|
{
|
//灵宠的技能复活
|
var actor = GAMgr.Instance.GetBySID(netPack.RebornValue1);
|
actor.Play(GAStaticDefine.State_Attack1Hash);
|
}
|
}
|
|
|
//回合战斗结束
|
void OnFightResult()
|
{
|
fightResult = JsonMapper.ToObject<FightResult>(m_Msg);
|
|
if (m_MapID == ArenaManager.MapID)
|
{
|
WindowCenter.Instance.OpenIL<ArenaSettlementWin>();
|
//更新排名
|
ArenaRankModel.Instance.SetMyRank(ArenaModel.Instance.RankType, dungeonModel.dungeonResult.updOrder);
|
}
|
else if (fightResult.isWin == 0)
|
{
|
WindowCenter.Instance.Open<TurnFightDefeatedWin>();
|
}
|
else
|
{
|
WindowCenter.Instance.Open<TurnFightVictoryWin>();
|
}
|
}
|
|
|
public enum E_TurnFightStep
|
{
|
None,
|
Start,
|
PrepareOK,
|
Fighting,
|
FightOver,
|
Result,
|
Over,
|
}
|
|
|
// [{'playerID': 424045, 'objID': 41, 'petObjIDList': []
|
//},
|
//{ 'npcID': 60403010, 'objID': 42, 'petObjIDList': [43, 44, 45]}]
|
public struct FactionObjInfo
|
{
|
public int playerID;
|
public int npcID;
|
public int objID;
|
public int ModelMark;
|
public int[] petObjIDList;
|
}
|
|
public struct FightResult
|
{
|
public AwardInfo[] itemInfo;
|
public ulong totalHurt;
|
public int isWin;
|
}
|
|
public struct AwardInfo
|
{
|
public int ItemID;
|
public int Count;
|
public int IsAuctionItem;
|
}
|
}
|