convert skill combo'

This commit is contained in:
VDH
2026-01-22 19:23:32 +07:00
parent 485488b804
commit ef366cfc32
12 changed files with 1144 additions and 452 deletions
@@ -1071,11 +1071,12 @@ namespace BrewMonster
{
try
{
BMLogger.LogError("LoadUserConfigData: Start loading user config data");
using (MemoryStream ms = new MemoryStream(pDataBuf, 0, iDataSize))
using (BinaryReader reader = new BinaryReader(ms))
{
uint dwVer = reader.ReadUInt32();
if (dwVer < 15)
{
DefaultUserConfigData();
@@ -1115,9 +1116,9 @@ namespace BrewMonster
// Note: Would need EC_Game reference
// g_pGame->GetA3DGFXExMan()->SetPriority(m_vs.nEffect);
// Send force attack to server
/* byte forceAttack = glb_BuildPVPMask(false);
byte refuseBless = glb_BuildRefuseBLSMask();
UnityGameSession.Instance.c2s_CmdNotifyForceAttack(forceAttack, refuseBless);*/
byte forceAttack = EC_Utility.glb_BuildPVPMask(false);
byte refuseBless = EC_Utility.glb_BuildRefuseBLSMask();
UnityGameSession.c2s_SendCmdNotifyForceAttack(forceAttack, refuseBless);
}
public void SetSceneLoadRadius(float fRadius)
@@ -807,7 +807,7 @@ namespace BrewMonster.Scripts.Managers
var pItem = new EC_IvtrItem(tid, expire_date);
DATA_TYPE DataType = DATA_TYPE.DT_INVALID;
object data = ElementDataManProvider.GetElementDataMan().get_data_ptr((uint)tid, ID_SPACE.ID_SPACE_ESSENCE, ref DataType);
Debug.Log("Create item data: DataType: " + DataType);
//Debug.Log("Create item data: DataType: " + DataType);
switch(DataType)
{
case DATA_TYPE.DT_WEAPON_ESSENCE:
@@ -331,6 +331,16 @@ namespace CSNetwork.C2SCommand
var cmdBuf = SerializeCommand(CommandID.CAST_POS_SKILL, cmd);
return cmdBuf;
}
public static Octets CreateNotifyForceAttack(int iForceAttack, byte refuseBless)
{
var cmd = new cmd_notify_force_attack
{
force_attack = (byte)iForceAttack,
refuse_bless = refuseBless
};
var cmdBuf = SerializeCommand(CommandID.NOTIFY_FORCE_ATTACK, cmd);
return cmdBuf;
}
public static short FloatToFix8(float x)
{
@@ -2194,19 +2194,20 @@ namespace CSNetwork.GPDataType
public int exp;
};
public _entry[] records;
public bool CheckValid(int buf_size, out int sz)
{ sz = 0;
if (count < 0)
return false;
sz = Marshal.SizeOf<cmd_reincarnation_tome_info>() - Marshal.SizeOf<_entry[]>();
sz += count * Marshal.SizeOf<_entry>();
return buf_size >= sz;
}
};
public bool CheckValid(int buf_size, out int sz)
{
sz = 0;
if (count < 0)
return false;
sz = Marshal.SizeOf<cmd_reincarnation_tome_info>() - Marshal.SizeOf<_entry[]>();
sz += count * Marshal.SizeOf<_entry>();
return buf_size >= sz;
}
};
// Pet type
public enum GP_PET_TYPE
{
{
GP_PET_CLASS_INVALID = -1,
GP_PET_CLASS_MOUNT = 0, //
GP_PET_CLASS_COMBAT, // ս
@@ -2216,13 +2217,13 @@ namespace CSNetwork.GPDataType
GP_PET_CLASS_EVOLUTION, //
GP_PET_CLASS_MAX,
};
public struct PetSkill
{
public int skill;
public int level;
}
}
public struct _evo_prop
{
public int r_attack;
@@ -2234,29 +2235,29 @@ namespace CSNetwork.GPDataType
}
public enum GP_PET_SKILL_NUM
{
GP_PET_SKILL_NUM = 8
GP_PET_SKILL_NUM = 8
};
public struct info_pet
{
public int honor_point; // øж
public int hunger; //
public int feed_time; // ϴιڵʱ
public int pet_tid; // ģID
public int pet_vis_tid; // ĿɼIDΪ0ʾɼID
public int pet_egg_tid; // ID
public int pet_class; // սͳ
public float hp_factor; // Ѫջʱʹã 0Ϊ
public short level; //
public ushort color; // ɫλΪ1ʾЧĿǰЧ
public int exp; // ﵱǰ
public int skill_point; // ʣܵ
public char is_bind; // Ƿ˺һһMask0x01 ˺һ0x02 Ѱɽ
public char unused; // ĿǰЧ
public ushort name_len; // ֳ ĿǰЧΪ߻
public char[] name; //
public PetSkill[] skills;
{
public int honor_point; // øж
public int hunger; //
public int feed_time; // ϴιڵʱ
public int pet_tid; // ģID
public int pet_vis_tid; // ĿɼIDΪ0ʾɼID
public int pet_egg_tid; // ID
public int pet_class; // սͳ
public float hp_factor; // Ѫջʱʹã 0Ϊ
public short level; //
public ushort color; // ɫλΪ1ʾЧĿǰЧ
public int exp; // ﵱǰ
public int skill_point; // ʣܵ
public char is_bind; // Ƿ˺һһMask0x01 ˺һ0x02 Ѱɽ
public char unused; // ĿǰЧ
public ushort name_len; // ֳ ĿǰЧΪ߻
public char[] name; //
public PetSkill[] skills;
public _evo_prop evo_prop;
public int[] reserved; // δ
public int[] reserved; // δ
public info_pet(bool isDefault = true)
{
honor_point = 0;
@@ -2276,7 +2277,8 @@ namespace CSNetwork.GPDataType
name_len = 0;
name = new char[16];
skills = new PetSkill[(int)GP_PET_SKILL_NUM.GP_PET_SKILL_NUM];
evo_prop = new _evo_prop{
evo_prop = new _evo_prop
{
r_attack = 0,
r_defense = 0,
r_hp = 0,
@@ -2286,6 +2288,17 @@ namespace CSNetwork.GPDataType
};
reserved = new int[10];
}
};
};
public enum REFUSE_BLESS_MASK : byte
{
REFUSE_NEUTRAL_BLESS = 0x0001, // ²»½ÓÊÜÖÐÐÔ×£¸£
REFUSE_NON_TEAMMATE_BLESS = 0x0002, // ²»½ÓÊܷǶÓÓÑ×£¸£
};
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct cmd_notify_force_attack
{
public byte force_attack;
public byte refuse_bless;
};
}
@@ -364,11 +364,11 @@ namespace CSNetwork
case ProtocolType.PROTOCOL_GETUICONFIG_RE: OnPrtcGetConfigRe(protocol); break;
case ProtocolType.PROTOCOL_AUTOTEAMSETGOAL_RE:
{
// CECAutoTeam pAutoTeam = CECGameRun.Instance.GetHostPlayer().GetAutoTeam();
// if( pAutoTeam !=null)
// pAutoTeam.OnPrtcAutoTeamSetGoalRe((AutoTeamSetGoal_Re)protocol);
}
{
// CECAutoTeam pAutoTeam = CECGameRun.Instance.GetHostPlayer().GetAutoTeam();
// if( pAutoTeam !=null)
// pAutoTeam.OnPrtcAutoTeamSetGoalRe((AutoTeamSetGoal_Re)protocol);
}
break;
default:
@@ -593,64 +593,64 @@ namespace CSNetwork
#if UNITY_EDITOR
BMLogger.LogError($"### GameDataSend: ERROR_MESSAGE: {errRaw}");
#endif
cmd_error_msg pCmd = GPDataTypeHelper.FromBytes<cmd_error_msg>(pDataBuf);
cmd_error_msg pCmd = GPDataTypeHelper.FromBytes<cmd_error_msg>(pDataBuf);
#if UNITY_EDITOR
BMLogger.LogError($"### GameDataSend: ERROR_MESSAGE parsed iMessage={pCmd.iMessage}");
#endif
if (pCmd.iMessage != 0)
{
// string szMsg = m_ErrorMsgs.GetWideString(pCmd.iMessage);
// if (string.IsNullOrEmpty(szMsg))
// BMLogger.LogError("SERVER - unknown error !");
//else if (pCmd.iMessage != 2)
//g_pGame.GetGameRun().AddChatMessage(szMsg, GP_CHAT_MISC);
}
if (pCmd.iMessage != 0)
{
// string szMsg = m_ErrorMsgs.GetWideString(pCmd.iMessage);
// if (string.IsNullOrEmpty(szMsg))
// BMLogger.LogError("SERVER - unknown error !");
//else if (pCmd.iMessage != 2)
//g_pGame.GetGameRun().AddChatMessage(szMsg, GP_CHAT_MISC);
}
if (pCmd.iMessage == 2)
{
// Attack target is too far
EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_TARGETISFAR, MANAGER_INDEX.MAN_PLAYER, 0, pDataBuf, pCmdHeader);
}
else if (pCmd.iMessage == 20)
{
// Failed to cast skill
//pGameRun.PostMessage(MSG_PM_CASTSKILL, MAN_PLAYER, 0, (DWORD)pDataBuf, pCmdHeader.cmd);
}
else if (pCmd.iMessage == 133 || pCmd.iMessage == 134)
{
// deal failed
//pGameRun.PostMessage(MSG_HST_BUY_SELL_FAIL, MAN_PLAYER, 0, (DWORD)pDataBuf, pCmdHeader.cmd);
}
else if (pCmd.iMessage == 158)
{
// µ±Ç°»ãÂʲ»¶Ô£¬ÖØÐÂÈ¡»ãÂÊ
//c2s_CmdGetCashMoneyRate();
}
else if (pCmd.iMessage == 108 /*&& pGameRun.GetHostPlayer().IsInKingService()*/)
{
/* CECGameUIMan* pGameUI = pGameRun.GetUIManager().GetInGameUIMan();
if (pGameUI)
pGameUI.EndNPCService();*/
}
else if
(pCmd.iMessage == 108 /*&& pGameRun.GetHostPlayer().GetOfflineShopCtrl().GetNPCSevFlag() != COfflineShopCtrl::NPCSEV_NULL*/
)
{
/* CECGameUIMan* pGameUI = pGameRun.GetUIManager().GetInGameUIMan();
if (pGameUI)
pGameUI.EndNPCService();*/
}
else if (pCmd.iMessage == 175)
{
//c2s_CmdQueryParallelWorld();
}
else if (pCmd.iMessage == 6)
{
//AP_ActionEvent(AP_EVENT_CANNOTPICKUP);
}
if (pCmd.iMessage == 2)
{
// Attack target is too far
EC_ManMessage.PostMessage(EC_MsgDef.MSG_HST_TARGETISFAR, MANAGER_INDEX.MAN_PLAYER, 0, pDataBuf, pCmdHeader);
}
else if (pCmd.iMessage == 20)
{
// Failed to cast skill
//pGameRun.PostMessage(MSG_PM_CASTSKILL, MAN_PLAYER, 0, (DWORD)pDataBuf, pCmdHeader.cmd);
}
else if (pCmd.iMessage == 133 || pCmd.iMessage == 134)
{
// deal failed
//pGameRun.PostMessage(MSG_HST_BUY_SELL_FAIL, MAN_PLAYER, 0, (DWORD)pDataBuf, pCmdHeader.cmd);
}
else if (pCmd.iMessage == 158)
{
// µ±Ç°»ãÂʲ»¶Ô£¬ÖØÐÂÈ¡»ãÂÊ
//c2s_CmdGetCashMoneyRate();
}
else if (pCmd.iMessage == 108 /*&& pGameRun.GetHostPlayer().IsInKingService()*/)
{
/* CECGameUIMan* pGameUI = pGameRun.GetUIManager().GetInGameUIMan();
if (pGameUI)
pGameUI.EndNPCService();*/
}
else if
(pCmd.iMessage == 108 /*&& pGameRun.GetHostPlayer().GetOfflineShopCtrl().GetNPCSevFlag() != COfflineShopCtrl::NPCSEV_NULL*/
)
{
/* CECGameUIMan* pGameUI = pGameRun.GetUIManager().GetInGameUIMan();
if (pGameUI)
pGameUI.EndNPCService();*/
}
else if (pCmd.iMessage == 175)
{
//c2s_CmdQueryParallelWorld();
}
else if (pCmd.iMessage == 6)
{
//AP_ActionEvent(AP_EVENT_CANNOTPICKUP);
}
break;
break;
}
case CommandID.SELECT_TARGET:
case CommandID.UNSELECT:
@@ -719,7 +719,7 @@ namespace CSNetwork
case CommandID.OBJECT_CAST_INSTANT_SKILL:
case CommandID.OBJECT_CAST_POS_SKILL:
{
cmd_object_cast_skill pCmd2 = GPDataTypeHelper.FromBytes<cmd_object_cast_skill>(pDataBuf,true);
cmd_object_cast_skill pCmd2 = GPDataTypeHelper.FromBytes<cmd_object_cast_skill>(pDataBuf, true);
if (ISPLAYERID(pCmd2.caster))
EC_ManMessage.PostMessage(EC_MsgDef.MSG_PM_CASTSKILL, MANAGER_INDEX.MAN_PLAYER, -1, pDataBuf, pCmdHeader);
else if (ISNPCID(pCmd2.caster))
@@ -1121,6 +1121,12 @@ namespace CSNetwork
SendProtocol(gamedatasend);
}
public void c2s_SendCmdNotifyForceAttack(int iForceAttack, byte refuseBless)
{
gamedatasend gamedatasend = new gamedatasend();
gamedatasend.Data = C2SCommandFactory.CreateNotifyForceAttack(iForceAttack, refuseBless);
SendProtocol(gamedatasend);
}
public void c2s_SendCmdContinueAction()
{
gamedatasend gamedatasend = new gamedatasend();
@@ -1210,24 +1216,24 @@ namespace CSNetwork
// Get referral name for adding friend or other display
//TODO: a Hung lam phan select role info di
/* RoleInfo info = EC_Game.GetGameRun().GetSelectedRoleInfo();
if (info.referrer_role > 0)
GetPlayerBriefInfo(1, info.referrer_role, 2);*/
/* RoleInfo info = EC_Game.GetGameRun().GetSelectedRoleInfo();
if (info.referrer_role > 0)
GetPlayerBriefInfo(1, info.referrer_role, 2);*/
}
CECHostPlayer pHost = EC_Game.GetGameRun().GetHostPlayer();
pHost.OnAllInitDataReady();
/* if (pHost.IsGM())
{
CDlgCountryMap pDlgCountryMap = (CDlgCountryMap)pGameUI.GetDialog("Win_CountryMap");
pDlgCountryMap.GetConfig();
}
/* if (pHost.IsGM())
{
CDlgCountryMap pDlgCountryMap = (CDlgCountryMap)pGameUI.GetDialog("Win_CountryMap");
pDlgCountryMap.GetConfig();
}
g_pGame.GetConfigs().ApplyOptimizeSetting();
g_pGame.GetConfigs().ApplyOptimizeSetting();
if (g_pGame.GetConfigs().IsMiniClient())
CECMCDownload::GetInstance().SendGetDownloadOK();*/
if (g_pGame.GetConfigs().IsMiniClient())
CECMCDownload::GetInstance().SendGetDownloadOK();*/
}
}
private void OnPrtcPlayerBaseInfoRe(Protocol pProtocol)
@@ -1434,7 +1440,7 @@ namespace CSNetwork
public void c2s_SendCmdTaskNotify(byte[] pData, uint dwDataSize)
{
gamedatasend gamedatasend = new gamedatasend();
gamedatasend.Data = C2SCommandFactory.CreateTaskNotifyCmd( pData, dwDataSize);
gamedatasend.Data = C2SCommandFactory.CreateTaskNotifyCmd(pData, dwDataSize);
BMLogger.Log($"[MH Task] c2s_SendCmdTaskNotify Command ID : {pData[0]} Size: {dwDataSize}");
SendProtocol(gamedatasend);
}
@@ -1445,24 +1451,24 @@ namespace CSNetwork
gamedatasend.Data = C2SCommandFactory.CreateNakeCmd(C2SCommand.CommandID.STAND_UP);
SendProtocol(gamedatasend);
}
public void c2s_SendCmdAutoTeamSetGoal(int type, int goal_id, int op)
{
gamedatasend gamedatasend = new gamedatasend();
gamedatasend.Data = C2SCommandFactory.CreateAutoTeamSetGoalCommand(type,goal_id, op);
gamedatasend.Data = C2SCommandFactory.CreateAutoTeamSetGoalCommand(type, goal_id, op);
SendProtocol(gamedatasend);
}
public void c2s_CmdGoto(float x, float y, float z)
{
c2s_SendCmdGoto(x, y, z);
c2s_SendCmdGoto(x, y, z);
}
// Send C2S::GOTO command data
void c2s_SendCmdGoto(float x, float y, float z)
{
gamedatasend gamedatasend = new gamedatasend();
gamedatasend.Data = C2SCommandFactory.CreateGoToCommed( x, y, z);
gamedatasend.Data = C2SCommandFactory.CreateGoToCommed(x, y, z);
SendProtocol(gamedatasend);
}
@@ -316,6 +316,10 @@ namespace BrewMonster.Network
public static void c2s_CmdNPCSevHeal()
{
}
public static void c2s_SendCmdNotifyForceAttack(int iForceAttack, byte refuseBless)
{
Instance._gameSession.c2s_SendCmdNotifyForceAttack(iForceAttack, refuseBless);
}
public static void c2s_CmdNPCSevAcceptTask(int idTask,int idStorage,int idRefreshItem)
{
@@ -636,100 +636,100 @@ namespace BrewMonster
break;
}
/* case CECShortcut.ShortcutType.SCT_ITEM:
{
int iPack = BitConverter.ToInt32(pDataBuf, offset);
offset += sizeof(int);
int iIvtrSlot = BitConverter.ToInt32(pDataBuf, offset);
offset += sizeof(int);
int idItem = BitConverter.ToInt32(pDataBuf, offset);
offset += sizeof(int);
/* case CECShortcut.ShortcutType.SCT_ITEM:
{
int iPack = BitConverter.ToInt32(pDataBuf, offset);
offset += sizeof(int);
int iIvtrSlot = BitConverter.ToInt32(pDataBuf, offset);
offset += sizeof(int);
int idItem = BitConverter.ToInt32(pDataBuf, offset);
offset += sizeof(int);
CECInventory pPack = pHost.GetPack(iPack);
if (pPack == null)
{
Debug.LogError("CECShortcutSet::LoadConfigData - Invalid inventory");
return false;
}
CECInventory pPack = pHost.GetPack(iPack);
if (pPack == null)
{
Debug.LogError("CECShortcutSet::LoadConfigData - Invalid inventory");
return false;
}
CECIvtrItem pItem = pPack.GetItem(iIvtrSlot);
if (pItem != null)
CreateItemShortcut(iSlot, iPack, iIvtrSlot, pItem);
CECIvtrItem pItem = pPack.GetItem(iIvtrSlot);
if (pItem != null)
CreateItemShortcut(iSlot, iPack, iIvtrSlot, pItem);
break;
}
break;
}*/
case CECShortcut.ShortcutType.SCT_SKILLGRP:
{
if (dwVer >= 3)
{
int iGroupIdx = BitConverter.ToInt32(pDataBuf, offset);
offset += sizeof(int);
case CECShortcut.ShortcutType.SCT_SKILLGRP:
{
if (dwVer >= 3)
{
int iGroupIdx = BitConverter.ToInt32(pDataBuf, offset);
offset += sizeof(int);
if (iGroupIdx >= 0)
CreateSkillGroupShortcut(iSlot, iGroupIdx);
}
else
{
Debug.LogError("CECShortcutSet::LoadConfigData - Invalid version for skill group");
return false;
}
break;
}
if (iGroupIdx >= 0)
CreateSkillGroupShortcut(iSlot, iGroupIdx);
}
else
{
Debug.LogError("CECShortcutSet::LoadConfigData - Invalid version for skill group");
return false;
}
break;
}
case CECShortcut.ShortcutType.SCT_PET:
{
if (dwVer >= 4)
{
int iPetIndex = BitConverter.ToInt32(pDataBuf, offset);
offset += sizeof(int);
/*case CECShortcut.ShortcutType.SCT_PET:
{
if (dwVer >= 4)
{
int iPetIndex = BitConverter.ToInt32(pDataBuf, offset);
offset += sizeof(int);
if (iPetIndex >= 0)
CreatePetShortcut(iSlot, iPetIndex);
}
else
{
Debug.LogError("CECShortcutSet::LoadConfigData - Invalid version for pet");
return false;
}
break;
}
if (iPetIndex >= 0)
CreatePetShortcut(iSlot, iPetIndex);
}
else
{
Debug.LogError("CECShortcutSet::LoadConfigData - Invalid version for pet");
return false;
}
break;
}
case CECShortcut.ShortcutType.SCT_AUTOFASHION:
{
if (dwVer >= 5)
{
int iAutoFashionIndex = BitConverter.ToInt32(pDataBuf, offset);
offset += sizeof(int);
case CECShortcut.ShortcutType.SCT_AUTOFASHION:
{
if (dwVer >= 5)
{
int iAutoFashionIndex = BitConverter.ToInt32(pDataBuf, offset);
offset += sizeof(int);
if (iAutoFashionIndex >= 0)
CreateAutoFashionShortcut(iSlot, iAutoFashionIndex);
}
else
{
Debug.LogError("CECShortcutSet::LoadConfigData - Invalid version for auto fashion");
return false;
}
break;
}
if (iAutoFashionIndex >= 0)
CreateAutoFashionShortcut(iSlot, iAutoFashionIndex);
}
else
{
Debug.LogError("CECShortcutSet::LoadConfigData - Invalid version for auto fashion");
return false;
}
break;
}
case CECShortcut.ShortcutType.SCT_SYSMODULE:
{
if (dwVer > 10)
{
int iSys = BitConverter.ToInt32(pDataBuf, offset);
offset += sizeof(int);
case CECShortcut.ShortcutType.SCT_SYSMODULE:
{
if (dwVer > 10)
{
int iSys = BitConverter.ToInt32(pDataBuf, offset);
offset += sizeof(int);
if (iSys >= 0)
CreateSystemModuleShortcut(iSlot, iSys);
}
else
{
Debug.LogError("CECShortcutSet::LoadConfigData - Invalid version for system module");
return false;
}
break;
}*/
if (iSys >= 0)
CreateSystemModuleShortcut(iSlot, iSys);
}
else
{
Debug.LogError("CECShortcutSet::LoadConfigData - Invalid version for system module");
return false;
}
break;
}*/
/* default:
//TODO: uncomment
@@ -0,0 +1,631 @@
# Flow: Player Clicks Shortcut to Use Combo Skill
## Overview
This document describes the complete flow from when a player clicks on a combo skill shortcut in the UI until the combo skill sequence is executed.
---
## Complete Flow Diagram
```
┌─────────────────────────────────────────────────────────────┐
│ 1. PLAYER CLICKS COMBO SKILL SHORTCUT │
│ (Mouse click on shortcut bar OR keyboard hotkey) │
└─────────────────┬───────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 2. UI EVENT HANDLER │
│ File: EC_GameUIEvent.cpp (line 173) │
│ OR EC_GameUIMan.cpp (line 1320, 1344) │
│ │
│ CECShortcut* pSC = GetShortcutFromUI(); │
│ pSC->Execute(); // ← Calls Execute() on shortcut │
└─────────────────┬───────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 3. CECSCSkillGrp::Execute() │
│ File: EC_Shortcut.cpp (line 712-716) │
│ │
│ bool CECSCSkillGrp::Execute() │
│ { │
│ CECHostPlayer* pHost = GetHostPlayer(); │
│ pHost->ApplyComboSkill(m_iGroupIdx); // ← Group ID │
│ return true; │
│ } │
└─────────────────┬───────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 4. CECHostPlayer::ApplyComboSkill() │
│ File: EC_HostPlayer.cpp (line 7696-7721) │
│ │
│ bool ApplyComboSkill(int iGroup, ...) │
│ { │
│ ClearComboSkill(); // Clear any existing combo │
│ │
│ m_pComboSkill = new CECComboSkill; │
│ │
│ // Initialize combo skill with group index │
│ m_pComboSkill->Init(this, iGroup, │
│ m_idSelTarget, │
│ bForceAttack, │
│ bIgnoreAtkLoop); │
│ │
│ // Start first skill in combo │
│ m_pComboSkill->Continue(m_bMelee); │
│ │
│ return true; │
│ } │
└─────────────────┬───────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 5. CECComboSkill::Init() │
│ File: EC_ComboSkill.cpp (line 74-123) │
│ │
│ bool Init(CECHostPlayer* pHost, int iGroup, ...) │
│ { │
│ // Load combo skill data from configs │
│ CECConfigs* pCfg = GetConfigs(); │
│ m_cs = pCfg->GetVideoSettings() │
│ .comboSkill[iGroup]; // ← Load combo │
│ │
│ // Find loop start flag (if any) │
│ // Move cursor to first valid skill │
│ StepCursor(true); │
│ │
│ return true; │
│ } │
└─────────────────┬───────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 6. CECComboSkill::Continue() - FIRST SKILL │
│ File: EC_ComboSkill.cpp (line 128-217) │
│ │
│ bool Continue(bool bMeleeing) │
│ { │
│ int idSkill = GetNextSkill(); // Get skill ID │
│ │
│ if (idSkill > 0) // Regular skill │
│ { │
│ // Execute skill │
│ bool bRet = m_pHost->ApplySkillShortcut( │
│ idSkill, true, m_idTarget, ...); │
│ │
│ if (bRet) │
│ { │
│ StepCursor(false); // Move to next skill │
│ return true; // Continue combo │
│ } │
│ } │
│ else if (idSkill == SID_ATTACK) // Normal attack │
│ { │
│ m_pHost->CmdNormalAttack(...); │
│ StepCursor(false); │
│ return true; │
│ } │
│ │
│ return false; // Combo stopped │
│ } │
└─────────────────┬───────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 7. SKILL EXECUTION │
│ File: EC_HostPlayer.cpp │
│ │
│ ApplySkillShortcut() executes the skill: │
│ - Checks if skill is ready │
│ - Sends command to server │
│ - Starts skill animation │
│ - Updates cooldown timers │
└─────────────────┬───────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 8. CONTINUE COMBO (After Skill Finishes) │
│ File: EC_HostPlayer.cpp (line 4129-4135, 6244-6252) │
│ │
│ When skill finishes or melee state changes: │
│ │
│ if (m_pComboSkill && !m_pComboSkill->IsStop()) │
│ { │
│ // Post message to continue combo │
│ PostMessage(MSG_HST_CONTINUECOMBOSKILL, │
│ MAN_PLAYER, 0, │
│ bMeleeing ? 1 : 0, │
│ m_pComboSkill->GetGroupIndex()); │
│ } │
└─────────────────┬───────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 9. OnMsgContinueComboSkill() │
│ File: EC_HostPlayer.cpp (line 6261-6268) │
│ │
│ void OnMsgContinueComboSkill(const ECMSG &Msg) │
│ { │
│ bool bMeleeing = (Msg.dwParam1 == 1); │
│ int iGroupID = (int)Msg.dwParam2; │
│ │
│ if (m_pComboSkill && │
│ m_pComboSkill->GetGroupIndex() == iGroupID && │
│ !m_pComboSkill->IsStop()) │
│ { │
│ m_pComboSkill->Continue(bMeleeing); // ← Loop │
│ } │
│ } │
└─────────────────┬───────────────────────────────────────────┘
┌─────────────────────────────────────────────────────────────┐
│ 10. REPEAT STEPS 6-9 │
│ Until combo skill sequence completes or stops │
│ │
│ - Continue() executes next skill in sequence │
│ - StepCursor() moves to next position │
│ - If loop flag found, cursor jumps back │
│ - If end reached, combo stops │
└─────────────────────────────────────────────────────────────┘
```
---
## Detailed Step-by-Step Flow
### **STEP 1: Player Clicks Shortcut**
**Trigger**:
- Mouse click on shortcut bar UI element
- OR Keyboard hotkey (1-9, Q, E, R, etc.)
**UI Elements**:
- `DlgQuickBar` - Main shortcut bar dialog
- `Item_01`, `Item_02`, ... - Shortcut slot UI controls
---
### **STEP 2: UI Event Handler**
**File**: `EC_GameUIEvent.cpp` (line 163-174)
```cpp
// Mouse click handler
if (abs(x - m_ptLButtonDown.x) < 3 && abs(y - m_ptLButtonDown.y) < 3)
{
if (strstr(pDlgSrc->GetName(), "Win_Quickbar") ||
0 == stricmp(pDlgSrc->GetName(), "Win_Action"))
{
CECShortcut* pSC = (CECShortcut*)pDlg->GetDataPtr();
if (pSC)
pSC->Execute(); // ← Execute shortcut
}
}
```
**OR Keyboard Handler**:
**File**: `EC_GameUIMan.cpp` (line 1316-1321)
```cpp
// Keyboard shortcut handler
int nCurPanel1 = CDlgQuickBar::GetCurPanel1();
CECShortcutSet* pSCS = pHost->GetShortcutSet1(nCurPanel1 - 1);
CECShortcut* pSC = pSCS->GetShortcut(iUsage - LKEY_UI_QUICK9_SC1);
if (pSC)
pSC->Execute(); // ← Execute shortcut
```
---
### **STEP 3: CECSCSkillGrp::Execute()**
**File**: `EC_Shortcut.cpp` (line 712-716)
```cpp
bool CECSCSkillGrp::Execute()
{
CECHostPlayer* pHost = g_pGame->GetGameRun()->GetHostPlayer();
pHost->ApplyComboSkill(m_iGroupIdx); // ← Group index (0-EC_COMBOSKILL_NUM-1)
return true;
}
```
**Key Points**:
- `m_iGroupIdx` is the combo skill group index (0, 1, 2, ...)
- This was set when the shortcut was created from config data
---
### **STEP 4: CECHostPlayer::ApplyComboSkill()**
**File**: `EC_HostPlayer.cpp` (line 7696-7721)
```cpp
bool CECHostPlayer::ApplyComboSkill(int iGroup, bool bIgnoreAtkLoop, int iForceAtk)
{
// Clear any existing combo skill
ClearComboSkill();
// Create new combo skill object
if (!(m_pComboSkill = new CECComboSkill))
return false;
// Determine force attack flag
bool bForceAttack;
if (iForceAtk < 0)
bForceAttack = glb_GetForceAttackFlag(NULL);
else
bForceAttack = iForceAtk > 0 ? true : false;
// Initialize combo skill
if (!(m_pComboSkill->Init(this, iGroup, m_idSelTarget, bForceAttack, bIgnoreAtkLoop)))
{
delete m_pComboSkill;
m_pComboSkill = NULL;
return false;
}
// Start the combo skill sequence
m_pComboSkill->Continue(m_bMelee);
return true;
}
```
**Key Points**:
- Clears any existing combo skill first
- Creates new `CECComboSkill` object
- Initializes with group index, target, force attack flag
- Immediately calls `Continue()` to start first skill
---
### **STEP 5: CECComboSkill::Init()**
**File**: `EC_ComboSkill.cpp` (line 74-123)
```cpp
bool CECComboSkill::Init(CECHostPlayer* pHost, int iGroup, int idTarget,
bool bForceAttack, bool bIgnoreAtkLoop)
{
if (iGroup < 0 || iGroup >= EC_COMBOSKILL_NUM)
return false;
m_pHost = pHost;
m_iGroup = iGroup;
m_iCursor = 0;
m_bStop = false;
m_idTarget = idTarget;
m_bForceAtk = bForceAttack;
m_bIgnoreAtkLoop = bIgnoreAtkLoop;
// ★ KEY: Load combo skill data from configs
CECConfigs* pCfg = g_pGame->GetConfigs();
m_cs = pCfg->GetVideoSettings().comboSkill[iGroup];
// m_cs contains:
// - m_cs.nIcon: Icon index
// - m_cs.idSkill[]: Array of skill IDs in sequence
// Find the last loop start flag (SID_LOOPSTART = -2)
m_iLoopStart = -1;
for (int i = 0; i < EC_COMBOSKILL_LEN; i++)
{
if (m_cs.idSkill[i] == SID_LOOPSTART)
m_iLoopStart = i;
}
// Validate loop start flag
if (m_iLoopStart >= 0)
{
// Check if there's a valid skill after loop start
// ... validation code ...
}
// Move cursor to first valid skill position
StepCursor(true);
return true;
}
```
**Key Points**:
- Loads combo skill data from `EC_Configs::m_vs.comboSkill[iGroup]`
- Finds loop start flag if present
- Moves cursor to first valid skill
---
### **STEP 6: CECComboSkill::Continue() - Execute Skills**
**File**: `EC_ComboSkill.cpp` (line 128-217)
```cpp
bool CECComboSkill::Continue(bool bMeleeing)
{
// Check if combo should stop
if (m_bStop || !m_cs.nIcon || !m_pHost ||
m_iCursor < 0 || m_iCursor >= EC_COMBOSKILL_LEN ||
(m_idTarget != m_pHost->GetSelectedTarget() && !m_bIgnoreAtkLoop))
return false;
int idSkill = GetNextSkill(); // Get skill ID at current cursor position
if (idSkill > 0) // Regular skill
{
// Execute the skill
bool bRet = m_pHost->ApplySkillShortcut(idSkill, true, m_idTarget,
m_bForceAtk ? 1 : 0);
if (!bRet)
{
// Skill failed, try next skill
StepCursor(false);
if (!IsStop())
{
// Post message to continue combo
g_pGame->GetGameRun()->PostMessage(MSG_HST_CONTINUECOMBOSKILL,
MAN_PLAYER, 0,
bMeleeing ? 1 : 0,
m_iGroup);
}
else
{
// Combo finished
AP_ActionEvent(AP_EVENT_COMBOFINISH);
}
return false;
}
else
{
// Skill executed successfully
AP_ActionEvent(AP_EVENT_COMBOCONTINUE);
}
}
else if (idSkill == SID_ATTACK) // Normal attack (-1)
{
if (!bMeleeing && !m_bIgnoreAtkLoop)
{
bool bRet = m_pHost->CmdNormalAttack(false, true, m_idTarget,
m_bForceAtk ? 1 : 0);
if (!bRet)
{
StepCursor(false);
if (!IsStop())
{
g_pGame->GetGameRun()->PostMessage(MSG_HST_CONTINUECOMBOSKILL,
MAN_PLAYER, 0,
bMeleeing ? 1 : 0,
m_iGroup);
}
return false;
}
}
}
// Move cursor to next skill
StepCursor(false);
return true;
}
```
**Key Points**:
- Gets next skill ID from `m_cs.idSkill[m_iCursor]`
- Executes skill via `ApplySkillShortcut()`
- Moves cursor forward with `StepCursor(false)`
- If skill fails, posts message to try next skill
---
### **STEP 7: StepCursor() - Move Through Sequence**
**File**: `EC_ComboSkill.cpp` (line 220-247)
```cpp
void CECComboSkill::StepCursor(bool bFirst)
{
if (bFirst)
m_iCursor = -1; // Start before first position
while (1)
{
m_iCursor++;
if (m_iCursor >= EC_COMBOSKILL_LEN) // Reached end
{
// If loop flag exists, jump back to loop start
if (m_iLoopStart >= 0 && !m_bIgnoreAtkLoop)
m_iCursor = m_iLoopStart;
else
{
m_bStop = true; // Combo finished
return;
}
}
else
{
int id = m_cs.idSkill[m_iCursor];
// Find next valid skill (id > 0) or attack (id == SID_ATTACK)
if (id > 0 || (id == SID_ATTACK && !m_bIgnoreAtkLoop))
break; // Found valid skill
}
}
}
```
**Key Points**:
- Moves cursor forward through skill array
- Skips empty slots (id == 0)
- If loop flag exists, jumps back to loop start
- Sets `m_bStop = true` when combo ends
---
### **STEP 8: Continue Combo After Skill Finishes**
**File**: `EC_HostPlayer.cpp` (line 4129-4135, 6244-6252)
When a skill finishes or melee state changes:
```cpp
// After melee attack finishes
if (m_bMelee && m_pComboSkill && !m_pComboSkill->IsStop())
{
if (CECAutoPolicy::GetInstance().IsAutoPolicyEnabled())
g_pGame->GetGameRun()->PostMessage(MSG_HST_CONTINUECOMBOSKILL,
MAN_PLAYER, 0, 1,
m_pComboSkill->GetGroupIndex());
else
m_pComboSkill->Continue(true);
}
// After other actions finish
if (bDoOtherThing)
{
if (m_pComboSkill && !m_pComboSkill->IsStop())
{
if (CECAutoPolicy::GetInstance().IsAutoPolicyEnabled())
g_pGame->GetGameRun()->PostMessage(MSG_HST_CONTINUECOMBOSKILL,
MAN_PLAYER, 0, 0,
m_pComboSkill->GetGroupIndex());
else
m_pComboSkill->Continue(false);
}
}
```
**Key Points**:
- Posts `MSG_HST_CONTINUECOMBOSKILL` message to continue combo
- Message includes melee state and group index
- Allows combo to continue asynchronously
---
### **STEP 9: OnMsgContinueComboSkill()**
**File**: `EC_HostPlayer.cpp` (line 6261-6268)
```cpp
void CECHostPlayer::OnMsgContinueComboSkill(const ECMSG &Msg)
{
bool bMeleeing = (Msg.dwParam1 == 1);
if (bMeleeing != m_bMelee)
bMeleeing = m_bMelee; // Use current melee state
int iGroupID = (int)Msg.dwParam2;
// Verify combo is still active and matches group
if (m_pComboSkill &&
m_pComboSkill->GetGroupIndex() == iGroupID &&
!m_pComboSkill->IsStop())
{
m_pComboSkill->Continue(bMeleeing); // Continue to next skill
}
}
```
**Key Points**:
- Handles message to continue combo
- Verifies combo is still active
- Calls `Continue()` again to execute next skill
---
### **STEP 10: Loop Until Complete**
Steps 6-9 repeat until:
- All skills in sequence are executed
- Combo reaches end (no loop flag)
- Combo is stopped (`m_bStop = true`)
- Target changes (unless `bIgnoreAtkLoop` is true)
---
## Key Data Structures
### **EC_COMBOSKILL**
```cpp
struct EC_COMBOSKILL
{
BYTE nIcon; // Icon index (0-N)
short idSkill[EC_COMBOSKILL_LEN]; // Array of skill IDs
};
```
**Special Skill IDs**:
- `SID_ATTACK = -1`: Normal attack
- `SID_LOOPSTART = -2`: Loop start flag
- `0`: Empty slot (skipped)
- `> 0`: Regular skill ID
### **CECComboSkill Member Variables**
```cpp
CECHostPlayer* m_pHost; // Host player
EC_COMBOSKILL m_cs; // Combo skill data
int m_iGroup; // Group index (0-EC_COMBOSKILL_NUM-1)
int m_iCursor; // Current position in sequence
bool m_bStop; // Stop flag
int m_iLoopStart; // Loop start index (-1 if no loop)
int m_idTarget; // Attack target
bool m_bForceAtk; // Force attack flag
bool m_bIgnoreAtkLoop; // Ignore attack loop flag
```
---
## Important Files
| File | Purpose |
|------|---------|
| `EC_GameUIEvent.cpp` | Handles mouse clicks on shortcuts |
| `EC_GameUIMan.cpp` | Handles keyboard shortcuts |
| `EC_Shortcut.cpp` | `CECSCSkillGrp::Execute()` - Entry point |
| `EC_HostPlayer.cpp` | `ApplyComboSkill()` - Creates and starts combo |
| `EC_ComboSkill.cpp` | `CECComboSkill` class - Manages combo sequence |
| `EC_Configs.cpp` | Stores combo skill data in `m_vs.comboSkill[]` |
---
## For Unity Port
To implement this in Unity:
1. **Shortcut Click Handler**:
```csharp
public void OnShortcutClicked(int slotIndex)
{
CECShortcut shortcut = GetShortcut(slotIndex);
if (shortcut != null && shortcut.GetType() == SCT_SKILLGRP)
{
CECSCSkillGrp skillGrp = (CECSCSkillGrp)shortcut;
GetHostPlayer().ApplyComboSkill(skillGrp.GetGroupIndex());
}
}
```
2. **ApplyComboSkill**:
```csharp
public bool ApplyComboSkill(int groupIndex)
{
ClearComboSkill();
m_comboSkill = new CECComboSkill();
if (!m_comboSkill.Init(this, groupIndex, m_selectedTarget,
forceAttack, ignoreAtkLoop))
return false;
m_comboSkill.Continue(m_isMeleeing);
return true;
}
```
3. **Continue Combo**:
```csharp
// After skill finishes
if (m_comboSkill != null && !m_comboSkill.IsStop())
{
StartCoroutine(ContinueComboAfterDelay());
}
```
---
## Summary
**Complete Flow**:
1. Player clicks shortcut → `pSC->Execute()`
2. `CECSCSkillGrp::Execute()` → `ApplyComboSkill(groupIndex)`
3. `ApplyComboSkill()` → Creates `CECComboSkill` and calls `Init()`
4. `Init()` → Loads combo data from configs
5. `Continue()` → Executes first skill
6. After skill finishes → Posts `MSG_HST_CONTINUECOMBOSKILL`
7. `OnMsgContinueComboSkill()` → Calls `Continue()` again
8. Repeat until combo completes
**Key**: The combo skill data (`EC_COMBOSKILL`) is loaded from `EC_Configs::m_vs.comboSkill[groupIndex]`, which was loaded from server in `LoadUserConfigData()`.
@@ -0,0 +1,7 @@
fileFormatVersion: 2
guid: 09b07dfdbdd8c094d9ded2ba81316847
TextScriptImporter:
externalObjects: {}
userData:
assetBundleName:
assetBundleVariant:
@@ -23,6 +23,213 @@ namespace BrewMonster
/// Apply for a license remove later
/// </summary>
/// <returns></returns>
//public bool UpdateShortcuts()
//{
// CECShortcut pSC;
// Image skillImage;
// CECSCSkill pSCSkill;
// int iIconFile, nMax;
// AUIImagePicture pCell;
// CECSkill pSkill = new CECSkill(-1, -1);
// AUIClockIcon pClock;
// int nCurPanel9 = GetCurPanel1();
// int nCurPanel8 = GetCurPanel2();
// CECHostPlayer pHost = EC_Game.GetGameRun().GetHostPlayer();
// if (pHost == null) return false;
// var a_pSCS = new List<CECShortcutSet>();
// var a_pszPanel = new List<string>();
// GetQuickBarNameAndSC(pHost, a_pszPanel, a_pSCS, nCurPanel9, nCurPanel8);
// for (int i = 0; i <= 1(int)a_pSCS.Count; i++)
// {
// if (a_pSCS[i] == null)
// continue;
// CDlgQuickBar* pQuickBar = dynamic_cast<CDlgQuickBar*>(GetGameUIMan()->GetDialog(a_pszPanel[i]));
// if (!pQuickBar || !pQuickBar->IsShow()) continue;
// int slotIndex = 0;
// for (int j = 0; j < a_pSCS.Count; j++)
// {
// pCell = AUIImagePictureList[slotIndex];
// pSC = a_pSCS[i].GetShortcut(j);
// pClock = pCell.GetClockIcon();
// pClock.SetProgressRange(0, 1);
// pClock.SetProgressPos(1);
// if (pSC != null)
// {
// if (pSC.GetType() == (int)CECShortcut.ShortcutType.SCT_SKILL)
// {
// iIconFile = (int)EC_GAMEUI_ICONS.ICONS_SKILL;
// pSCSkill = (CECSCSkill)pSC;
// pSkill = pSCSkill.GetSkill();
// if (falsem_bDelGoblinSkillSC && GNET::ElementSkill::IsGoblinSkill(pSkill->GetSkillID()))
// {
// a_pSCS[i]->SetShortcut(j, NULL);
// pSC = NULL;
// }
// else
// {
// if (pSkill != null && pSkill.ReadyToCast() && pHost.GetPrepSkill() != pSkill)
// {
// if (ElementSkill.IsGoblinSkill((uint)pSkill.GetSkillID()))
// {
// if (pHostGoblin && !pHostGoblin->CheckSkillCastCondition(pSkill))
// {
// pCell->SetColor(A3DCOLORRGB(255, 255, 255));
// }
// else
// {
// pCell->SetColor(A3DCOLORRGB(128, 128, 128));
// }
// }
// else
// {
// if (pHost.CheckSkillCastCondition(pSkill) == 0)
// {
// //pCell.SetColor(A3DCOLORRGB(255, 255, 255));
// }
// else
// {
// //pCell.SetColor(A3DCOLORRGB(128, 128, 128));
// }
// }
// }
// else
// pClock.SetColor(A3DCOLORRGBA(0, 0, 0, 128));
// if (pSkill != null && (pSkill.GetCoolingTime() > 0 ||
// pHost.GetPrepSkill() == pSkill))
// {
// pClock.SetProgressRange(0, pSkill.GetCoolingTime());
// if (pHost.GetPrepSkill() == pSkill)
// {
// pClock.SetProgressPos(0);
// }
// else
// {
// pClock.SetProgressPos(pSkill.GetCoolingTime() - pSkill.GetCoolingCnt());
// }
// }
// }
// }
// else if (pSC->GetType() == CECShortcut::SCT_ITEM)
// {
// iIconFile = CECGameUIMan::ICONS_INVENTORY;
// pCell->SetColor(A3DCOLORRGB(255, 255, 255));
// pSCItem = (CECSCItem*)pSC;
// pIvtr = GetHostPlayer()->GetPack(pSCItem->GetInventory());
// pItem = pIvtr->GetItem(pSCItem->GetIvtrSlot());
// if (pItem && pItem->GetCoolTime(&nMax) > 0)
// {
// pClock->SetProgressRange(0, nMax);
// pClock->SetProgressPos(nMax - pItem->GetCoolTime());
// pClock->SetColor(A3DCOLORRGBA(0, 0, 0, 128));
// }
// if (pSCItem->GetInventory() == IVTRTYPE_EQUIPPACK)
// pCell->SetColor(A3DCOLORRGBA(128, 128, 255, 128));
// }
// else if (pSC->GetType() == CECShortcut::SCT_PET)
// {
// pSCPet = (CECSCPet*)pSC;
// CECPetData* pPet = pPetCorral->GetPetData(pSCPet->GetPetIndex());
// iIconFile = CECGameUIMan::ICONS_INVENTORY;
// pCell->SetColor(A3DCOLORRGB(255, 255, 255));
// if (pPet)
// {
// // dead combat pet
// if ((pPet->GetClass() == GP_PET_CLASS_COMBAT || pPet->GetClass() == GP_PET_CLASS_EVOLUTION) && pPet->GetHPFactor() == 0.0f)
// {
// pCell->SetColor(A3DCOLORRGB(128, 128, 128));
// }
// // current active pet
// else if (pSCPet->IsActivePet())
// {
// pCell->SetColor(A3DCOLORRGB(255, 255, 0));
// }
// }
// }
// else if (pSC->GetType() == CECShortcut::SCT_AUTOFASHION)
// {
// iIconFile = CECGameUIMan::ICONS_SUITE;
// fashionCoolTime = pHost->GetCoolTime(GP_CT_EQUIP_FASHION_ITEM, &fashionCoolTimeMax);
// pCell->SetColor(A3DCOLORRGB(255, 255, 255));
// if (fashionCoolTimeMax > 0)
// {
// pClock->SetProgressRange(0, fashionCoolTimeMax);
// pClock->SetProgressPos(fashionCoolTimeMax - fashionCoolTime);
// pClock->SetColor(A3DCOLORRGBA(0, 0, 0, 175));
// }
// }
// else
// {
// iIconFile = CECGameUIMan::ICONS_ACTION;
// if (pSC->GetType() == CECShortcut::SCT_COMMAND)
// {
// CECSCCommand* pCommandSC = (CECSCCommand*)pSC;
// if (GetHostPlayer()->IsInvisible())
// {
// if (pCommandSC->GetCommandID() == CECSCCommand::CMD_STARTTRADE ||
// pCommandSC->GetCommandID() == CECSCCommand::CMD_SELLBOOTH ||
// pCommandSC->GetCommandID() == CECSCCommand::CMD_BINDBUDDY)
// {
// pCell->SetColor(A3DCOLORRGB(128, 128, 128));
// }
// else
// {
// pCell->SetColor(A3DCOLORRGB(255, 255, 255));
// }
// }
// else
// {
// pCell->SetColor(A3DCOLORRGB(255, 255, 255));
// }
// }
// if (pSC->GetCoolTime(&nMax) > 0)
// {
// pClock->SetProgressRange(0, nMax);
// pClock->SetProgressPos(nMax - pSC->GetCoolTime());
// pClock->SetColor(A3DCOLORRGBA(0, 0, 0, 128));
// }
// }
// if (pSC != null)
// {
// pCell.SetDataPtr(pSC, "ptr_CECShortcut");
// if (pSC.GetType() == (int)CECShortcut.ShortcutType.SCT_SKILLGRP)
// {
// EC_VIDEO_SETTING setting = GetGame()->GetConfigs()->GetVideoSettings();
// pCell->SetCover(GetGameUIMan()->m_pA2DSpriteIcons[CECGameUIMan::ICONS_SKILLGRP],
// setting.comboSkill[((CECSCSkillGrp*)pSC)->GetGroupIndex()].nIcon + 1);
// }
// else
// {
// if (pSkill != null)
// {
// slotIndex++;
// //BMLogger.Log("HoangDev: QuickBar Set Skill Icon: " + (uint)pSkill.GetSkillID() + " : " + ElementSkill.GetIcon((uint)pSkill.GetSkillID()));
// var nameskill = ElementSkill.GetIcon((uint)pSkill.GetSkillID());
// GetGameUIMan().SetCover(pCell, nameskill, EC_GAMEUI_ICONS.ICONS_SKILL);
// }
// af_GetFileTitle(pSC->GetIconFile(), strFile);
// strFile.MakeLower();
// pCell->SetCover(GetGameUIMan()->m_pA2DSpriteIcons[iIconFile],
// GetGameUIMan()->m_IconMap[iIconFile][strFile]);
// }
// }
// }
// else
// {
// pCell->SetCover(NULL, -1);
// pCell->SetText(_AL(""));
// pCell->SetDataPtr(NULL);
// pCell->SetColor(A3DCOLORRGB(255, 255, 255));
// }
// }
// }
// return true;
//}
public bool UpdateShortcuts()
{
CECShortcut pSC;
@@ -48,12 +255,12 @@ namespace BrewMonster
if (a_pSCS[i] == null)
continue;
/*CDlgQuickBar* pQuickBar = dynamic_cast<CDlgQuickBar*>(GetGameUIMan()->GetDialog(a_pszPanel[i]));
if (!pQuickBar || !pQuickBar->IsShow()) continue;*/
int slotIndex = 0;
for (int j = 0; j < a_pSCS.Count; j++)
//*//*CDlgQuickBar* pQuickBar = dynamic_cast<CDlgQuickBar*>(GetGameUIMan()->GetDialog(a_pszPanel[i]));
//if (!pQuickBar || !pQuickBar->IsShow()) continue;*//*
for (int j = 0; j < AUIImagePictureList.Count; j++)
{
pCell = AUIImagePictureList[slotIndex];
pCell = AUIImagePictureList[j];
pSC = a_pSCS[i].GetShortcut(j);
pClock = pCell.GetClockIcon();
pClock.SetProgressRange(0, 1);
@@ -67,8 +274,8 @@ namespace BrewMonster
pSkill = pSCSkill.GetSkill();
if (false/*m_bDelGoblinSkillSC && GNET::ElementSkill::IsGoblinSkill(pSkill->GetSkillID())*/)
{
/* a_pSCS[i]->SetShortcut(j, NULL);
pSC = NULL;*/
/* a_pSCS[i]->SetShortcut(j, NULL);
pSC = NULL;*/
}
else
{
@@ -76,14 +283,14 @@ namespace BrewMonster
{
if (ElementSkill.IsGoblinSkill((uint)pSkill.GetSkillID()))
{
/* if (pHostGoblin && !pHostGoblin->CheckSkillCastCondition(pSkill))
{
pCell->SetColor(A3DCOLORRGB(255, 255, 255));
}
else
{
pCell->SetColor(A3DCOLORRGB(128, 128, 128));
}*/
/* if (pHostGoblin && !pHostGoblin->CheckSkillCastCondition(pSkill))
{
pCell->SetColor(A3DCOLORRGB(255, 255, 255));
}
else
{
pCell->SetColor(A3DCOLORRGB(128, 128, 128));
}*/
}
else
{
@@ -97,8 +304,8 @@ namespace BrewMonster
}
}
}
/* else
pClock.SetColor(A3DCOLORRGBA(0, 0, 0, 128));*/
/*else
pClock.SetColor(A3DCOLORRGBA(0, 0, 0, 128));*/
if (pSkill != null && (pSkill.GetCoolingTime() > 0 ||
pHost.GetPrepSkill() == pSkill))
{
@@ -193,222 +400,20 @@ namespace BrewMonster
pClock->SetProgressPos(nMax - pSC->GetCoolTime());
pClock->SetColor(A3DCOLORRGBA(0, 0, 0, 128));
}
}*/
}*//**/
if (pSC != null)
{
BMLogger.LogError("HoangDev: QuickBar Set Skil");
pCell.SetDataPtr(pSC, "ptr_CECShortcut");
if (pSC.GetType() == (int)CECShortcut.ShortcutType.SCT_SKILLGRP)
{
/* EC_VIDEO_SETTING setting = GetGame()->GetConfigs()->GetVideoSettings();
pCell->SetCover(GetGameUIMan()->m_pA2DSpriteIcons[CECGameUIMan::ICONS_SKILLGRP],
setting.comboSkill[((CECSCSkillGrp*)pSC)->GetGroupIndex()].nIcon + 1);*/
}
else
{
if (pSkill != null)
{
slotIndex++;
//BMLogger.Log("HoangDev: QuickBar Set Skill Icon: " + (uint)pSkill.GetSkillID() + " : " + ElementSkill.GetIcon((uint)pSkill.GetSkillID()));
var nameskill = ElementSkill.GetIcon((uint)pSkill.GetSkillID());
GetGameUIMan().SetCover(pCell, nameskill, EC_GAMEUI_ICONS.ICONS_SKILL);
}
/*af_GetFileTitle(pSC->GetIconFile(), strFile);
strFile.MakeLower();
pCell->SetCover(GetGameUIMan()->m_pA2DSpriteIcons[iIconFile],
GetGameUIMan()->m_IconMap[iIconFile][strFile]);*/
}
}
}
else
{
/* pCell->SetCover(NULL, -1);
pCell->SetText(_AL(""));
pCell->SetDataPtr(NULL);
pCell->SetColor(A3DCOLORRGB(255, 255, 255));*/
}
}
}
return true;
}
/* public bool UpdateShortcuts()
{
CECShortcut pSC;
Image skillImage;
CECSCSkill pSCSkill;
int iIconFile, nMax;
AUIImagePicture pCell;
CECSkill pSkill = new CECSkill(-1, -1);
AUIClockIcon pClock;
int nCurPanel9 = GetCurPanel1();
int nCurPanel8 = GetCurPanel2();
CECHostPlayer pHost = EC_Game.GetGameRun().GetHostPlayer();
if (pHost == null) return false;
var a_pSCS = new List<CECShortcutSet>();
var a_pszPanel = new List<string>();
GetQuickBarNameAndSC(pHost, a_pszPanel, a_pSCS, nCurPanel9, nCurPanel8);
for (int i = 0; i <= 1*//*(int)a_pSCS.Count*//*; i++)
{
if (a_pSCS[i] == null)
continue;
*//*CDlgQuickBar* pQuickBar = dynamic_cast<CDlgQuickBar*>(GetGameUIMan()->GetDialog(a_pszPanel[i]));
if (!pQuickBar || !pQuickBar->IsShow()) continue;*//*
for (int j = 0; j < AUIImagePictureList.Count; j++)
{
pCell = AUIImagePictureList[j];
pSC = a_pSCS[i].GetShortcut(j);
pClock = pCell.GetClockIcon();
pClock.SetProgressRange(0, 1);
pClock.SetProgressPos(1);
if (pSC != null)
{
if (pSC.GetType() == (int)CECShortcut.ShortcutType.SCT_SKILL)
{
iIconFile = (int)EC_GAMEUI_ICONS.ICONS_SKILL;
pSCSkill = (CECSCSkill)pSC;
pSkill = pSCSkill.GetSkill();
if (false*//*m_bDelGoblinSkillSC && GNET::ElementSkill::IsGoblinSkill(pSkill->GetSkillID())*//*)
{
*//* a_pSCS[i]->SetShortcut(j, NULL);
pSC = NULL;*//*
}
else
{
if (pSkill != null && pSkill.ReadyToCast() && pHost.GetPrepSkill() != pSkill)
{
if (ElementSkill.IsGoblinSkill((uint)pSkill.GetSkillID()))
{
*//* if (pHostGoblin && !pHostGoblin->CheckSkillCastCondition(pSkill))
{
pCell->SetColor(A3DCOLORRGB(255, 255, 255));
}
else
{
pCell->SetColor(A3DCOLORRGB(128, 128, 128));
}*//*
}
else
{
if (pHost.CheckSkillCastCondition(pSkill) == 0)
{
//pCell.SetColor(A3DCOLORRGB(255, 255, 255));
}
else
{
//pCell.SetColor(A3DCOLORRGB(128, 128, 128));
}
}
}
*//* else
pClock.SetColor(A3DCOLORRGBA(0, 0, 0, 128));*//*
if (pSkill != null && (pSkill.GetCoolingTime() > 0 ||
pHost.GetPrepSkill() == pSkill))
{
pClock.SetProgressRange(0, pSkill.GetCoolingTime());
if (pHost.GetPrepSkill() == pSkill)
{
pClock.SetProgressPos(0);
}
else
{
pClock.SetProgressPos(pSkill.GetCoolingTime() - pSkill.GetCoolingCnt());
}
}
}
}
*//*else if (pSC->GetType() == CECShortcut::SCT_ITEM)
{
iIconFile = CECGameUIMan::ICONS_INVENTORY;
pCell->SetColor(A3DCOLORRGB(255, 255, 255));
pSCItem = (CECSCItem*)pSC;
pIvtr = GetHostPlayer()->GetPack(pSCItem->GetInventory());
pItem = pIvtr->GetItem(pSCItem->GetIvtrSlot());
if (pItem && pItem->GetCoolTime(&nMax) > 0)
{
pClock->SetProgressRange(0, nMax);
pClock->SetProgressPos(nMax - pItem->GetCoolTime());
pClock->SetColor(A3DCOLORRGBA(0, 0, 0, 128));
}
if (pSCItem->GetInventory() == IVTRTYPE_EQUIPPACK)
pCell->SetColor(A3DCOLORRGBA(128, 128, 255, 128));
}
else if (pSC->GetType() == CECShortcut::SCT_PET)
{
pSCPet = (CECSCPet*)pSC;
CECPetData* pPet = pPetCorral->GetPetData(pSCPet->GetPetIndex());
iIconFile = CECGameUIMan::ICONS_INVENTORY;
pCell->SetColor(A3DCOLORRGB(255, 255, 255));
if (pPet)
{
// dead combat pet
if ((pPet->GetClass() == GP_PET_CLASS_COMBAT || pPet->GetClass() == GP_PET_CLASS_EVOLUTION) && pPet->GetHPFactor() == 0.0f)
{
pCell->SetColor(A3DCOLORRGB(128, 128, 128));
}
// current active pet
else if (pSCPet->IsActivePet())
{
pCell->SetColor(A3DCOLORRGB(255, 255, 0));
}
}
}
else if (pSC->GetType() == CECShortcut::SCT_AUTOFASHION)
{
iIconFile = CECGameUIMan::ICONS_SUITE;
fashionCoolTime = pHost->GetCoolTime(GP_CT_EQUIP_FASHION_ITEM, &fashionCoolTimeMax);
pCell->SetColor(A3DCOLORRGB(255, 255, 255));
if (fashionCoolTimeMax > 0)
{
pClock->SetProgressRange(0, fashionCoolTimeMax);
pClock->SetProgressPos(fashionCoolTimeMax - fashionCoolTime);
pClock->SetColor(A3DCOLORRGBA(0, 0, 0, 175));
}
}
else
{
iIconFile = CECGameUIMan::ICONS_ACTION;
if (pSC->GetType() == CECShortcut::SCT_COMMAND)
{
CECSCCommand* pCommandSC = (CECSCCommand*)pSC;
if (GetHostPlayer()->IsInvisible())
{
if (pCommandSC->GetCommandID() == CECSCCommand::CMD_STARTTRADE ||
pCommandSC->GetCommandID() == CECSCCommand::CMD_SELLBOOTH ||
pCommandSC->GetCommandID() == CECSCCommand::CMD_BINDBUDDY)
{
pCell->SetColor(A3DCOLORRGB(128, 128, 128));
}
else
{
pCell->SetColor(A3DCOLORRGB(255, 255, 255));
}
}
else
{
pCell->SetColor(A3DCOLORRGB(255, 255, 255));
}
}
if (pSC->GetCoolTime(&nMax) > 0)
{
pClock->SetProgressRange(0, nMax);
pClock->SetProgressPos(nMax - pSC->GetCoolTime());
pClock->SetColor(A3DCOLORRGBA(0, 0, 0, 128));
}
}*//*
if (pSC != null)
{
pCell.SetDataPtr(pSC, "ptr_CECShortcut");
if (pSC.GetType() == (int)CECShortcut.ShortcutType.SCT_SKILLGRP)
{
*//* EC_VIDEO_SETTING setting = GetGame()->GetConfigs()->GetVideoSettings();
pCell->SetCover(GetGameUIMan()->m_pA2DSpriteIcons[CECGameUIMan::ICONS_SKILLGRP],
setting.comboSkill[((CECSCSkillGrp*)pSC)->GetGroupIndex()].nIcon + 1);*//*
BMLogger.LogError("HoangDev: QuickBar Set Skill Group Icon SCT_SKILLGRP");
EC_VIDEO_SETTING setting = EC_Game.GetConfigs().GetVideoSettings();
/* pCell.SetCover(GetGameUIMan()->m_pA2DSpriteIcons[CECGameUIMan::ICONS_SKILLGRP],
setting.comboSkill[((CECSCSkillGrp)pSC).GetGroupIndex()].nIcon + 1);
setting.comboSkill[((CECSCSkillGrp)pSC).GetGroupIndex()].nIcon + 1;*/
GetGameUIMan().SetCover(pCell, "unknown", EC_GAMEUI_ICONS.ICONS_SKILLGRP);
}
else
{
@@ -419,24 +424,24 @@ namespace BrewMonster
var nameskill = ElementSkill.GetIcon((uint)pSkill.GetSkillID());
GetGameUIMan().SetCover(pCell, nameskill, EC_GAMEUI_ICONS.ICONS_SKILL);
}
*//*af_GetFileTitle(pSC->GetIconFile(), strFile);
strFile.MakeLower();
pCell->SetCover(GetGameUIMan()->m_pA2DSpriteIcons[iIconFile],
GetGameUIMan()->m_IconMap[iIconFile][strFile]);*//*
/* af_GetFileTitle(pSC->GetIconFile(), strFile);
strFile.MakeLower();
pCell->SetCover(GetGameUIMan()->m_pA2DSpriteIcons[iIconFile],
GetGameUIMan()->m_IconMap[iIconFile][strFile]); */
}
}
}
else
{
*//* pCell->SetCover(NULL, -1);
pCell->SetText(_AL(""));
/* pCell->SetCover(NULL, -1);
pCell->SetText(_AL(""));
pCell->SetDataPtr(NULL);
pCell->SetColor(A3DCOLORRGB(255, 255, 255));*//*
pCell->SetColor(A3DCOLORRGB(255, 255, 255)); */
}
}
}
return true;
}*/
}
private void GetQuickBarNameAndSC(CECHostPlayer pHost, List<string> pszPanel, List<CECShortcutSet> pSCS, int panel9, int panel8)
{
string dlgName;
+19 -19
View File
@@ -6,8 +6,10 @@ using BrewMonster.UI;
using CSNetwork;
using CSNetwork.GPDataType;
using CSNetwork.Protocols.RPCData;
using System;
using System.Collections.Generic;
using System.Data;
using System.Linq;
using System.Threading.Tasks;
using Unity.Cinemachine;
using UnityEngine;
@@ -300,7 +302,6 @@ public partial class CECGameRun
dwRealLen = 0;
}
byte[] pData = pDataBuf;
int dataOffset = offset;
if (dwVer >= 3)
{
@@ -343,7 +344,7 @@ public partial class CECGameRun
}
}
//TODO: flow in update fix later
Task.Run(() =>
/* Task.Run(() =>
{
GameSession.Context.Post(_ =>
{
@@ -353,22 +354,21 @@ public partial class CECGameRun
}
m_pUIManager.GetCDlgQuickBar().UpdateShortcuts();
}, null);
});
});*/
// TODO: Uncomment when UI manager is available
// Load UI configs / 加载UI配置
CECGameUIMan pGameUI = m_pUIManager.GetInGameUIMan();
/* if (pGameUI != null)
{
int iSize = dr.ReadInt();
byte[] uiConfigData = dr.ReadData(iSize);
if (!pGameUI.SetUserLayout(uiConfigData, iSize))
{
BMLogger.LogError("CECGameRun::LoadConfigsFromServer, Failed to set user layout");
return false;
}
}*/
if (pGameUI != null)
{
int iSize = dr.ReadInt();
byte[] uiConfigData = dr.ReadData(iSize);
/*if (!pGameUI.SetUserLayout(uiConfigData, iSize))
{
BMLogger.LogError("CECGameRun::LoadConfigsFromServer, Failed to set user layout");
return false;
}*/
}
// Load user settings / 加载用户设置
if (dwVer >= 2)
@@ -376,11 +376,11 @@ public partial class CECGameRun
// TODO: Uncomment when game configs are available
int iSize = dr.ReadInt();
byte[] settingsData = dr.ReadData(iSize);
/* if (!EC_Game.GetConfigs().LoadUserConfigData(settingsData, iSize))
{
BMLogger.LogError("CECGameRun::LoadConfigsFromServer, Failed to load user config data");
return false;
}*/
if (!EC_Game.GetConfigs().LoadUserConfigData(settingsData, iSize))
{
BMLogger.LogError("CECGameRun::LoadConfigsFromServer, Failed to load user config data");
return false;
}
}
}
catch (System.Exception e)
+15
View File
@@ -85,6 +85,21 @@ public static class EC_Utility
{
return new System.Numerics.Vector3(v.x, v.y, v.z);
}
public static byte glb_BuildRefuseBLSMask()
{
byte byMask = 0;
// const EC_GAME_SETTING &gs = g_pGame->GetConfigs()->GetGameSettings();
var gs = EC_Game.GetConfigs().GetGameSettings();
if (gs.bBlsRefuse_Neutral)
byMask |= (byte)REFUSE_BLESS_MASK.REFUSE_NEUTRAL_BLESS;
if (gs.bBlsRefuse_NonTeammate)
byMask |= (byte)REFUSE_BLESS_MASK.REFUSE_NON_TEAMMATE_BLESS;
return byMask;
}
public static void Swap<T>(List<T> arr, int a, int b)
{
T tmp = arr[a];