Merge branch 'develop' into feature/skill-set-shortcut
# Conflicts: # Assets/PerfectWorld/Scripts/Addressable/AddressableManager.cs # Assets/PerfectWorld/Scripts/DebugCommandMenu.meta
This commit is contained in:
@@ -205,6 +205,13 @@ public partial class CECGameRun
|
||||
CECPlayer.InitStaticRes();
|
||||
hostPlayer = ObjectSpawner.Instance.InstantiateObject(_playerPrefab, setThisAsParent: true).AddComponent<CECHostPlayer>();
|
||||
hostPlayer.InitCharacter(info);
|
||||
|
||||
if (hostPlayer != null)
|
||||
{
|
||||
var t = Type.GetType("BrewMonster.UI.SelectedTargetHUDController, Assembly-CSharp");
|
||||
if (t != null && hostPlayer.GetComponent(t) == null)
|
||||
hostPlayer.gameObject.AddComponent(t);
|
||||
}
|
||||
}
|
||||
public CECMonster GetMonster()
|
||||
{
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
using BrewMonster.Managers;
|
||||
using BrewMonster.Managers;
|
||||
using BrewMonster.Network;
|
||||
using BrewMonster.Scripts;
|
||||
using BrewMonster.Scripts.World;
|
||||
@@ -828,75 +828,16 @@ namespace BrewMonster
|
||||
}
|
||||
}
|
||||
}
|
||||
// TO DO: fix later
|
||||
//else if (GPDataTypeHelper.ISPLAYERID(idTarget))
|
||||
//{
|
||||
// // Check duel at first
|
||||
// if (m_pvp.iDuelState == Duel_state.DUEL_ST_INDUEL && m_pvp.idDuelOpp == idTarget)
|
||||
// return 1;
|
||||
// else if (m_pvp.iDuelState == Duel_state.DUEL_ST_STOPPING && m_pvp.idDuelOpp == idTarget)
|
||||
// return 0;
|
||||
|
||||
// // In sanctuary we cannot attack other players
|
||||
// if (m_bInSanctuary)
|
||||
// return 0;
|
||||
|
||||
// //ASSERT(pObject.GetClassID() == CECObject::OCID_ELSEPLAYER);
|
||||
// EC_ElsePlayer pPlayer = (EC_ElsePlayer)pObject;
|
||||
// ROLEBASICPROP bp = pPlayer.GetBasicProps();
|
||||
// EC_GAME_SETTING gs = g_pGame.GetConfigs().GetGameSettings();
|
||||
|
||||
// if (m_pvp.bFreePVP)
|
||||
// {
|
||||
// if (IsTeamMember(idTarget))
|
||||
// return 0;
|
||||
|
||||
// // In free pvp mode, for example, host is in arena.
|
||||
// if (bForceAttack)
|
||||
// iRet = 1;
|
||||
// else if (gs.bAtk_NoMafia && IsFactionMember(pPlayer.GetFactionID()))
|
||||
// iRet = 0;
|
||||
// else if (gs.bAtk_NoWhite && !pPlayer.IsInvader() && !pPlayer.IsPariah())
|
||||
// iRet = 0;
|
||||
// else if (gs.bAtk_NoAlliance && g_pGame.GetFactionMan().IsFactionAlliance(pPlayer.GetFactionID()))
|
||||
// iRet = 0;
|
||||
// else if (gs.bAtk_NoForce && GetForce() > 0 && GetForce() == pPlayer.GetForce())
|
||||
// iRet = 0;
|
||||
// else
|
||||
// iRet = 1;
|
||||
// }
|
||||
// else if (m_iBattleCamp != GP_BATTLE_CAMP_NONE)
|
||||
// {
|
||||
// // Host is in battle
|
||||
// int iCamp = pPlayer.GetBattleCamp();
|
||||
// if (iCamp != GP_BATTLE_CAMP_NONE && iCamp != m_iBattleCamp)
|
||||
// iRet = 1;
|
||||
// else
|
||||
// iRet = 0;
|
||||
// }
|
||||
// else // Normal mode
|
||||
// {
|
||||
// if (IsTeamMember(idTarget))
|
||||
// return 0;
|
||||
|
||||
// if (!IsPVPOpen() || !pPlayer.IsPVPOpen() || m_BasicProps.iLevel < EC_MAXNOPKLEVEL || bp.iLevel < EC_MAXNOPKLEVEL)
|
||||
// iRet = 0;
|
||||
// else if (bForceAttack)
|
||||
// iRet = 1;
|
||||
// else if (!gs.bAtk_Player)
|
||||
// iRet = 0;
|
||||
// else if (gs.bAtk_NoMafia && IsFactionMember(pPlayer.GetFactionID()))
|
||||
// iRet = 0;
|
||||
// else if (gs.bAtk_NoWhite && !pPlayer.IsInvader() && !pPlayer.IsPariah())
|
||||
// iRet = 0;
|
||||
// else if (gs.bAtk_NoAlliance && g_pGame.GetFactionMan().IsFactionAlliance(pPlayer.GetFactionID()))
|
||||
// iRet = 0;
|
||||
// else if (gs.bAtk_NoForce && GetForce() > 0 && GetForce() == pPlayer.GetForce())
|
||||
// iRet = 0;
|
||||
// else
|
||||
// iRet = 1;
|
||||
// }
|
||||
//}
|
||||
else if (GPDataTypeHelper.ISPLAYERID(idTarget))
|
||||
{
|
||||
// Duel: allow attack only on duel opponent while in duel
|
||||
if (IsInDuel() && m_pvp.idDuelOpp == idTarget)
|
||||
return 1;
|
||||
if (m_pvp.iDuelState == Duel_state.DUEL_ST_STOPPING && m_pvp.idDuelOpp == idTarget)
|
||||
return 0;
|
||||
// Other player PVP not implemented here; treat as not attackable
|
||||
return 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
return -1;
|
||||
@@ -952,6 +893,10 @@ namespace BrewMonster
|
||||
else
|
||||
bForceAttack = iForceAtk > 0 ? true : false;
|
||||
|
||||
// Duel: server accepts attack on opponent only with PVP/force mask
|
||||
if (IsInDuel() && idTarget == m_pvp.idDuelOpp)
|
||||
bForceAttack = true;
|
||||
|
||||
if (AttackableJudge(idTarget, bForceAttack) != 1)
|
||||
return false;
|
||||
|
||||
|
||||
@@ -705,6 +705,20 @@ namespace BrewMonster
|
||||
PlayAttackEffect(pCmd.target, pCmd.skill, pCmd.level, nDamage,
|
||||
dwModifier & mask, 0, ref attackTime, pCmd.section);
|
||||
}
|
||||
|
||||
public void OnMsgHstClearTessera(ECMSG Msg)
|
||||
{
|
||||
cmd_clear_tessera pCmd = GPDataTypeHelper.FromBytes<cmd_clear_tessera>((byte[])Msg.dwParam1);
|
||||
AddMoneyAmount(-(int)pCmd.cost);
|
||||
// Refresh equip's data
|
||||
UnityGameSession.c2s_CmdGetItemInfo(Inventory_type.IVTRTYPE_PACK, (byte)pCmd.equip_idx);
|
||||
}
|
||||
// Add money amount
|
||||
private int AddMoneyAmount(int iAmount)
|
||||
{
|
||||
m_iMoneyCnt += (uint)iAmount;
|
||||
return (int)m_iMoneyCnt;
|
||||
}
|
||||
|
||||
public bool HaveHealthStones()
|
||||
{
|
||||
|
||||
+139
-25
@@ -19,6 +19,7 @@ using System;
|
||||
using System.Collections;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Runtime.InteropServices;
|
||||
using System.Text;
|
||||
using UnityEngine;
|
||||
using UnityEngine.UI;
|
||||
@@ -579,7 +580,6 @@ namespace BrewMonster
|
||||
case EC_MsgDef.MSG_HST_SELTARGET:
|
||||
OnMsgHstSelTarget(Msg); break;
|
||||
case EC_MsgDef.MSG_HST_USEITEM:
|
||||
OnMsgHstUseItem(Msg);
|
||||
break;
|
||||
case EC_MsgDef.MSG_HST_ATKRESULT: OnMsgHstAttackResult(Msg); break;
|
||||
case EC_MsgDef.MSG_HST_ATTACKED: OnMsgHstAttacked(Msg); break;
|
||||
@@ -600,10 +600,7 @@ namespace BrewMonster
|
||||
case EC_MsgDef.MSG_HST_TARGETISFAR: OnMsgHstTargetIsFar(Msg); break;
|
||||
case EC_MsgDef.MSG_PM_PLAYERGATHER: OnMsgPlayerGather(Msg); break;
|
||||
case EC_MsgDef.MSG_HST_COOLTIMEDATA: OnMsgHstCoolTimeData(Msg); break;
|
||||
case EC_MsgDef.MSG_HST_SETCOOLTIME: OnMsgHstSetCoolTime(Msg); break;
|
||||
case EC_MsgDef.MSG_HST_PRESSCANCEL: OnMsgHstPressCancel(Msg); break;
|
||||
case EC_MsgDef.MSG_HST_LEARNSKILL: OnMsgHstLearnSkill(Msg); break;
|
||||
case EC_MsgDef.MSG_HST_COMBO_SKILL_PREPARE: OnMsgComboSkillPrepare(Msg); break;
|
||||
case EC_MsgDef.MSG_PM_PLAYERFLY: OnMsgPlayerFly(Msg); break;
|
||||
case EC_MsgDef.MSG_HST_PETOPT: OnMsgHstPetOpt(Msg); break;
|
||||
case EC_MsgDef.MSG_HST_SETPLAYERLIMIT: OnMsgHstSetPlayerLimit(Msg); break;
|
||||
@@ -613,7 +610,8 @@ namespace BrewMonster
|
||||
case EC_MsgDef.MSG_HST_LEAVETEAM: OnMsgHstLeaveTeam(Msg); break;
|
||||
case EC_MsgDef.MSG_HST_NEWTEAMMEM: OnMsgHstNewTeamMem(Msg); break;
|
||||
case EC_MsgDef.MSG_HST_TEAMMEMBERDATA: OnMsgHstTeamMemberData(Msg); break;
|
||||
case EC_MsgDef.MSG_HST_CONTINUECOMBOSKILL: OnMsgContinueComboSkill(Msg); break;
|
||||
case EC_MsgDef.MSG_PM_DUELOPT: OnMsgHstDuelOpt(Msg); break;
|
||||
case EC_MsgDef.MSG_HST_CLEARTESSERA: OnMsgHstClearTessera(Msg); break;
|
||||
}
|
||||
|
||||
/*if (bActionStartSkill)
|
||||
@@ -645,6 +643,85 @@ namespace BrewMonster
|
||||
}
|
||||
catch { }
|
||||
}
|
||||
|
||||
/// <summary>Update host duel state from S2C duel commands (MSG_PM_DUELOPT).</summary>
|
||||
private void OnMsgHstDuelOpt(ECMSG Msg)
|
||||
{
|
||||
int cmdId = Convert.ToInt32(Msg.dwParam2);
|
||||
byte[] data = Msg.dwParam1 as byte[];
|
||||
int idOpp = 0;
|
||||
if (data != null && data.Length >= 4)
|
||||
idOpp = BitConverter.ToInt32(data, 0);
|
||||
switch (cmdId)
|
||||
{
|
||||
case CommandID.DUEL_PREPARE:
|
||||
m_pvp.iDuelState = Duel_state.DUEL_ST_PREPARE;
|
||||
m_pvp.idDuelOpp = idOpp;
|
||||
m_pvp.iDuelTimeCnt = data != null && data.Length >= 8 ? BitConverter.ToInt32(data, 4) : 3000;
|
||||
break;
|
||||
case CommandID.HOST_DUEL_START:
|
||||
m_pvp.iDuelState = Duel_state.DUEL_ST_INDUEL;
|
||||
m_pvp.idDuelOpp = idOpp;
|
||||
m_pvp.iDuelTimeCnt = 0;
|
||||
// Origin: server must be notified of force-attack (PVP) so it accepts attacks on the duel opponent
|
||||
NotifyServerForceAttack(true);
|
||||
break;
|
||||
case CommandID.DUEL_STOP:
|
||||
case CommandID.DUEL_RESULT:
|
||||
m_pvp.iDuelState = Duel_state.DUEL_ST_STOPPING;
|
||||
m_pvp.iDuelTimeCnt = data != null && data.Length >= 8 ? BitConverter.ToInt32(data, 4) : 3000;
|
||||
if (data != null && data.Length >= 12)
|
||||
m_pvp.iDuelRlt = BitConverter.ToInt32(data, 8);
|
||||
NotifyServerForceAttack(false);
|
||||
break;
|
||||
case CommandID.DUEL_CANCEL:
|
||||
case CommandID.DUEL_REJECT_REQUEST:
|
||||
m_pvp.iDuelState = Duel_state.DUEL_ST_NONE;
|
||||
m_pvp.idDuelOpp = 0;
|
||||
m_pvp.iDuelTimeCnt = 0;
|
||||
NotifyServerForceAttack(false);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Called when MSG_PM_PLAYERDUELOPT (229) is received; server may send duel start to both participants. If host is one of the two ids, set duel state.</summary>
|
||||
public void OnMsgPlayerDuelStart(byte[] data)
|
||||
{
|
||||
if (data == null || data.Length < 8) return;
|
||||
int id1 = BitConverter.ToInt32(data, 0);
|
||||
int id2 = BitConverter.ToInt32(data, 4);
|
||||
int cid = m_PlayerInfo.cid;
|
||||
if (cid == id1)
|
||||
{
|
||||
m_pvp.iDuelState = Duel_state.DUEL_ST_INDUEL;
|
||||
m_pvp.idDuelOpp = id2;
|
||||
m_pvp.iDuelTimeCnt = 0;
|
||||
NotifyServerForceAttack(true);
|
||||
}
|
||||
else if (cid == id2)
|
||||
{
|
||||
m_pvp.iDuelState = Duel_state.DUEL_ST_INDUEL;
|
||||
m_pvp.idDuelOpp = id1;
|
||||
m_pvp.iDuelTimeCnt = 0;
|
||||
NotifyServerForceAttack(true);
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>Origin: notify server of force-attack (PVP) state so it accepts/rejects attacks on players. Call when duel starts (true) or ends (false).</summary>
|
||||
private void NotifyServerForceAttack(bool bForceAttack)
|
||||
{
|
||||
byte refuseBless = EC_Utility.glb_BuildRefuseBLSMask();
|
||||
UnityGameSession.c2s_SendCmdNotifyForceAttack(glb_BuildPVPMask(bForceAttack), refuseBless);
|
||||
}
|
||||
|
||||
#if UNITY_EDITOR
|
||||
/// <summary>
|
||||
/// Cycles through learned skills by removing all shortcuts and adding 2 new skills to slots 0 and 1.
|
||||
/// If m_startingSkillID is set (>0), uses that specific skill ID and the next one (ID+1).
|
||||
/// Otherwise, cycles through all learned skills in pairs.
|
||||
/// </summary>
|
||||
#endif
|
||||
|
||||
public bool HostIsReady()
|
||||
{
|
||||
return m_bEnterGame;
|
||||
@@ -1029,6 +1106,9 @@ namespace BrewMonster
|
||||
{
|
||||
var data = (byte[])Msg.dwParam1;
|
||||
cmd_select_target pCmd = GPDataTypeHelper.FromBytes<cmd_select_target>(data);
|
||||
// In duel: don't let server force selection back to duel opponent when player chose another target
|
||||
if (IsInDuel() && pCmd.idTarget == m_pvp.idDuelOpp && m_idSelTarget != 0 && m_idSelTarget != m_pvp.idDuelOpp)
|
||||
return;
|
||||
m_idSelTarget = pCmd.idTarget;
|
||||
m_idUCSelTarget = 0;
|
||||
}
|
||||
@@ -1041,6 +1121,7 @@ namespace BrewMonster
|
||||
public override void SetUpPlayer()
|
||||
{
|
||||
base.SetUpPlayer();
|
||||
m_iCID = (int)CECObject.Class_ID.OCID_HOSTPLAYER;
|
||||
|
||||
m_IncantCnt = new CECCounter();
|
||||
m_IncantCnt.SetPeriod(1000);
|
||||
@@ -1256,6 +1337,12 @@ namespace BrewMonster
|
||||
// SetPlayerModel();
|
||||
//Debug.LogError("Pos Character = " + pos);
|
||||
}
|
||||
|
||||
/// <summary>Use host's m_pvp (we update it from S2C duel packets). Base IsInDuel() reads CECPlayer.m_pvp which is never set.</summary>
|
||||
public new bool IsInDuel() { return m_pvp.iDuelState == Duel_state.DUEL_ST_INDUEL; }
|
||||
|
||||
/// <summary>Duel opponent character id when in duel; 0 otherwise. Used by HPWork so trace/melee send correct PVP mask.</summary>
|
||||
public int GetDuelOpponentId() { return m_pvp.idDuelOpp; }
|
||||
|
||||
public void ClearAnimation()
|
||||
{
|
||||
@@ -1527,6 +1614,7 @@ namespace BrewMonster
|
||||
|
||||
return fSpeedSev;
|
||||
}
|
||||
|
||||
|
||||
public void PrepareNPCService(int idSev)
|
||||
{
|
||||
@@ -1706,7 +1794,6 @@ namespace BrewMonster
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
public A3DVECTOR3 GetDir()
|
||||
{
|
||||
// Return forward direction from transform
|
||||
@@ -1811,7 +1898,6 @@ namespace BrewMonster
|
||||
|
||||
public bool SelectTarget(int idTarget)
|
||||
{
|
||||
//BMLogger.LogError("HoangDev: HostPlayer SelectTarget");
|
||||
bool bRet = false;
|
||||
bool canDo = CanDo(ActionCanDo.CANDO_CHANGESELECT);
|
||||
bool canselect = CanSelectTarget(idTarget);
|
||||
@@ -1822,11 +1908,15 @@ namespace BrewMonster
|
||||
{
|
||||
//BMLogger.LogError("HoangDev: HostPlayer Unsetlect npc");
|
||||
UnityGameSession.c2s_CmdUnselect();
|
||||
m_idSelTarget = 0;
|
||||
m_idUCSelTarget = 0;
|
||||
}
|
||||
else
|
||||
{
|
||||
//BMLogger.LogError("HoangDev: HostPlayer setlect npc");
|
||||
UnityGameSession.c2s_CmdSelectTarget(idTarget);
|
||||
m_idSelTarget = idTarget;
|
||||
m_idUCSelTarget = idTarget;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1864,6 +1954,10 @@ namespace BrewMonster
|
||||
return true;
|
||||
}
|
||||
|
||||
// Duel: always allow selecting the duel opponent so we can attack/cast (distance checked when trace runs)
|
||||
if (IsInDuel() && idTarget == m_pvp.idDuelOpp)
|
||||
return true;
|
||||
|
||||
CECObject pTarget = null;
|
||||
if (GPDataTypeHelper.ISPLAYERID(idTarget))
|
||||
{
|
||||
@@ -2282,7 +2376,23 @@ namespace BrewMonster
|
||||
}
|
||||
public void SetSelectedTarget(int id)
|
||||
{
|
||||
if (m_idSelTarget != id)
|
||||
EventBus.Publish(new CECHostPlayer.TargetHUDClearEvent());
|
||||
m_idSelTarget = id;
|
||||
// In duel, when player selects a different target, cancel trace work so it doesn't overwrite selection on touch
|
||||
if (IsInDuel() && id != 0 && id != m_pvp.idDuelOpp)
|
||||
m_pWorkMan?.FinishRunningWork(CECHPWork.Host_work_ID.WORK_TRACEOBJECT);
|
||||
// When selecting another player, publish NPCINFO so target HUD shows (server doesn't resend base info on select)
|
||||
if (id != 0 && id != GetCharacterID() && GPDataTypeHelper.ISPLAYERID(id))
|
||||
{
|
||||
var elsePlayer = EC_ManMessageMono.Instance?.GetECManPlayer?.GetPlayer(id) as EC_ElsePlayer;
|
||||
if (elsePlayer != null && elsePlayer.m_bBaseInfoReady)
|
||||
{
|
||||
string name = elsePlayer.GetName();
|
||||
if (!string.IsNullOrEmpty(name))
|
||||
EventBus.Publish(new CECHostPlayer.NPCINFO(name, 100, 100, id));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public new int GetSelectedTarget()
|
||||
@@ -3209,7 +3319,10 @@ namespace BrewMonster
|
||||
MaxHealth = maxHealth;
|
||||
IDNPC = idnpc;
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
/// <summary>Fired when selected target HUD should be hidden (deselect or switch).</summary>
|
||||
public struct TargetHUDClearEvent { }
|
||||
|
||||
public struct GNDINFO
|
||||
{
|
||||
@@ -3540,21 +3653,19 @@ namespace BrewMonster
|
||||
public CECCounter GetIncantCnt() { return m_IncantCnt; }
|
||||
|
||||
// Get key object(NPC..) coordinates
|
||||
public A3DVECTOR3 GetObjectCoordinates(int idTarget, ref ObjectCoords TargetCoord, ref bool bInTable)
|
||||
public A3DVECTOR3 GetObjectCoordinates(int idTarget, out List<OBJECT_COORD> TargetCoord, ref bool bInTable)
|
||||
{
|
||||
if (TargetCoord == null)
|
||||
{
|
||||
TargetCoord = new ObjectCoords();
|
||||
}
|
||||
TargetCoord.Clear();
|
||||
|
||||
TargetCoord = new List<OBJECT_COORD>();
|
||||
|
||||
A3DVECTOR3 vDestPos = new A3DVECTOR3(0, 0, 0);
|
||||
|
||||
bInTable = false;
|
||||
// Get object coordinates from CECGame::m_CoordTab
|
||||
string szText = idTarget.ToString();
|
||||
List<OBJECT_COORD> tempCoord = new List<OBJECT_COORD>();
|
||||
int iCount = EC_Game.GetObjectCoord(szText, ref tempCoord);
|
||||
List<OBJECT_COORD> originalCoords = new List<OBJECT_COORD>();
|
||||
int iCount = EC_Game.GetObjectCoord(szText, out originalCoords);
|
||||
|
||||
if (iCount == 0)
|
||||
{
|
||||
return vDestPos;
|
||||
@@ -3567,11 +3678,12 @@ namespace BrewMonster
|
||||
CECInstance pInstance = CECGameRun.Instance.GetInstance(idInstance);
|
||||
string strCurMap = pInstance.GetPath();
|
||||
// �ȼ��ͬһ��ͼ���Ƿ���Ҫ���ҵ���Ʒ
|
||||
bool bHasObjectInCurrentInstance = tempCoord.Any(coord => coord.strMap == strCurMap);
|
||||
bool bHasObjectInCurrentInstance = originalCoords.Any(coord => coord.strMap == strCurMap);
|
||||
|
||||
// Iterate over original list and build filtered TargetCoord list
|
||||
for (int i = 0; i < iCount; i++)
|
||||
{
|
||||
OBJECT_COORD objCoord = tempCoord[i];
|
||||
|
||||
OBJECT_COORD objCoord = originalCoords[i];
|
||||
if (strCurMap == objCoord.strMap)
|
||||
{
|
||||
TargetCoord.Add(objCoord);
|
||||
@@ -3583,22 +3695,24 @@ namespace BrewMonster
|
||||
fMinDist = tempDist;
|
||||
bInTable = true;
|
||||
vDestPos = objCoord.vPos;
|
||||
}
|
||||
}
|
||||
}
|
||||
// ��ǰ��ͼ��û��Ŀ��Ļ�����Ŀ�����ڵ�ͼ�ڵ�ǰ��ͼ�����
|
||||
else if (!bHasObjectInCurrentInstance)
|
||||
{
|
||||
|
||||
// find the entrance of instance
|
||||
List<OBJECT_COORD> instCoord = new List<OBJECT_COORD>();
|
||||
int iCount2 = EC_Game.GetObjectCoord(objCoord.strMap, ref instCoord);
|
||||
for (int j = 0; j < iCount2; ++j)
|
||||
int iCount2 = EC_Game.GetObjectCoord(objCoord.strMap, out instCoord);
|
||||
for (int j = 0; j < iCount2; ++j)
|
||||
{
|
||||
if (instCoord[j].strMap == strCurMap)
|
||||
{
|
||||
TargetCoord.Add(instCoord[j]);
|
||||
|
||||
|
||||
// Check if this is the nearest target
|
||||
float tempDist = (instCoord[i].vPos - GetPos()).Magnitude();
|
||||
float tempDist = (instCoord[j].vPos - GetPos()).Magnitude();
|
||||
|
||||
if (tempDist < fMinDist)
|
||||
{
|
||||
fMinDist = tempDist;
|
||||
@@ -3616,7 +3730,7 @@ namespace BrewMonster
|
||||
public int GetRealmSubLevel() { return m_RealmLevel % 100; }
|
||||
public static int GetRealmLayer(int realmLevel) { return realmLevel > 0 ? (realmLevel + 9) / 10 : 0; }
|
||||
public static int GetRealmSubLevel(int realmLevel) { return realmLevel > 0 ? (realmLevel % 10 > 0 ? realmLevel % 10 : 10) : 0; }
|
||||
|
||||
|
||||
// <summary>
|
||||
// Calculate distance to an object and optionally retrieve the object reference
|
||||
// 计算到对象的距离,并可选地获取对象引用
|
||||
|
||||
@@ -22,6 +22,7 @@ public class CECUIManager : MonoSingleton<CECUIManager>
|
||||
[SerializeField] private int currentTargetNPCID;
|
||||
CECGameUIMan gameUI;
|
||||
AUIManager aUIManager;
|
||||
AUIDialog _dlgPlayerOptions;
|
||||
[SerializeField] private DialogScriptTableObject dialogResouce;
|
||||
[SerializeField] private Canvas canvasDlg;
|
||||
|
||||
@@ -33,11 +34,16 @@ public class CECUIManager : MonoSingleton<CECUIManager>
|
||||
Sprite[] m_iconlistIvtr;
|
||||
private CDlgInfoTooltip m_pDlgSkillTooltip;
|
||||
|
||||
// Task update timer / 任务更新计时器
|
||||
private float _nextTaskUpdateTime = 0f;
|
||||
private const float TASK_UPDATE_INTERVAL = .1f;
|
||||
|
||||
protected override void Awake()
|
||||
{
|
||||
base.Awake();
|
||||
|
||||
EventBus.Subscribe<CECHostPlayer.NPCINFO>(ShowUINPC);
|
||||
EventBus.Subscribe<CECHostPlayer.TargetHUDClearEvent>(OnTargetHUDClear);
|
||||
EventBus.Subscribe<NPCDiedEvent>(TryHideUINPC);
|
||||
EventBus.Subscribe<MessageBoxEvent>(OnMessageBox);
|
||||
|
||||
@@ -58,22 +64,69 @@ public class CECUIManager : MonoSingleton<CECUIManager>
|
||||
// _fpsText.text = $"{Mathf.RoundToInt(1f / Time.deltaTime)}";
|
||||
if (m_pDlgQuickBar1 != null)
|
||||
{ m_pDlgQuickBar1.UpdateShortcuts(); }
|
||||
|
||||
// Periodically update task UI (DlgTask and DlgTaskTrace) / 定期更新任务UI(DlgTask和DlgTaskTrace)
|
||||
if (Time.unscaledTime >= _nextTaskUpdateTime)
|
||||
{
|
||||
_nextTaskUpdateTime = Time.unscaledTime + TASK_UPDATE_INTERVAL;
|
||||
UpdateTaskUI();
|
||||
}
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Update task UI from DlgTask and DlgTaskTrace / 从DlgTask和DlgTaskTrace更新任务UI
|
||||
/// </summary>
|
||||
private void UpdateTaskUI()
|
||||
{
|
||||
try
|
||||
{
|
||||
var inGameUIMan = GetInGameUIMan();
|
||||
if (inGameUIMan == null) return;
|
||||
|
||||
var dlgTaskDialog = inGameUIMan.GetDialog("Win_Quest");
|
||||
var dlgTaskTraceDialog = inGameUIMan.GetDialog("Win_QuestMinion");
|
||||
if (dlgTaskDialog != null && dlgTaskDialog is BrewMonster.Scripts.Task.UI.DlgTask dlgTaskForTrace)
|
||||
{
|
||||
if (dlgTaskTraceDialog != null && dlgTaskTraceDialog.IsShow())
|
||||
{
|
||||
dlgTaskForTrace.RefreshTaskTrace();
|
||||
}
|
||||
dlgTaskForTrace.Tick();
|
||||
}
|
||||
|
||||
}
|
||||
catch (System.Exception)
|
||||
{
|
||||
// Silently handle errors to avoid spamming logs / 静默处理错误以避免日志刷屏
|
||||
// Task UI update errors are handled silently / 任务UI更新错误被静默处理
|
||||
}
|
||||
}
|
||||
|
||||
private void OnDestroy()
|
||||
{
|
||||
EventBus.Unsubscribe<CECHostPlayer.NPCINFO>(ShowUINPC);
|
||||
EventBus.Unsubscribe<CECHostPlayer.TargetHUDClearEvent>(OnTargetHUDClear);
|
||||
EventBus.Unsubscribe<NPCDiedEvent>(TryHideUINPC);
|
||||
EventBus.Unsubscribe<MessageBoxEvent>(OnMessageBox);
|
||||
}
|
||||
|
||||
private void ShowUINPC(CECHostPlayer.NPCINFO obj)
|
||||
{
|
||||
var host = EC_Game.GetGameRun()?.GetHostPlayer();
|
||||
if (host != null && host.GetSelectedTarget() != obj.IDNPC)
|
||||
return;
|
||||
npsUI.gameObject.SetActive(true);
|
||||
npsUI.SetText($"{obj.CurrentHealth}/{obj.MaxHealth}", obj.Name, "");
|
||||
npsUI.SetHealthImage((float)obj.CurrentHealth / (float)obj.MaxHealth);
|
||||
string hpText = obj.MaxHealth > 0 ? $"{obj.CurrentHealth}/{obj.MaxHealth}" : "-/-";
|
||||
npsUI.SetText(hpText, obj.Name ?? "", "");
|
||||
float fill = obj.MaxHealth > 0 ? (float)obj.CurrentHealth / (float)obj.MaxHealth : 1f;
|
||||
npsUI.SetHealthImage(fill);
|
||||
currentTargetNPCID = obj.IDNPC;
|
||||
}
|
||||
|
||||
private void OnTargetHUDClear(CECHostPlayer.TargetHUDClearEvent _)
|
||||
{
|
||||
npsUI.gameObject.SetActive(false);
|
||||
}
|
||||
public CDlgQuickBar GetCDlgQuickBar()
|
||||
{
|
||||
return m_pDlgQuickBar1;
|
||||
@@ -408,6 +461,16 @@ public class CECUIManager : MonoSingleton<CECUIManager>
|
||||
return gameUI;
|
||||
}
|
||||
|
||||
/// <summary>Shows the player options menu for the given character. Requires a prefab with id "DlgPlayerOptions" in DialogScriptTableObject.</summary>
|
||||
public void ShowPlayerOptionsDialog(int characterId)
|
||||
{
|
||||
if (characterId == 0 || canvasDlg == null) return;
|
||||
var gui = GetInGameUIMan();
|
||||
if (_dlgPlayerOptions == null)
|
||||
_dlgPlayerOptions = gui.GetDialog("DlgPlayerOptions");
|
||||
_dlgPlayerOptions?.ShowForPlayer(characterId);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Get the current target NPC ID (same as stored from NPCINFO event)
|
||||
/// </summary>
|
||||
|
||||
Reference in New Issue
Block a user