789 lines
33 KiB
C#
789 lines
33 KiB
C#
using System;
|
||
using BrewMonster.Assets.PerfectWorld.Scripts.UI.GamePlay;
|
||
using BrewMonster.Managers;
|
||
using BrewMonster.Scripts.Task;
|
||
using BrewMonster.Scripts.Task.UI;
|
||
using BrewMonster.Scripts.UI;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
using BrewMonster.Network;
|
||
using BrewMonster.Scripts;
|
||
using CSNetwork;
|
||
using CSNetwork.GPDataType;
|
||
using PerfectWorld.UI.MiniMap;
|
||
using UnityEngine;
|
||
using BrewMonster.PerfectWorld.Scripts.UI;
|
||
|
||
namespace BrewMonster.UI
|
||
{
|
||
public class CECGameUIMan : AUIManager
|
||
{
|
||
public const int LAYOUTDATA_VERSION = 15;
|
||
|
||
DlgNPC m_pDlgNPC;
|
||
CDlgPetList m_pDlgPetList;
|
||
public NPC_ESSENCE? m_pCurNPCEssence;
|
||
public int m_idCurFinishTask = -1;
|
||
private DlgTask m_pDlgTask;
|
||
private Dictionary<byte, (string, Sprite[])> m_IconMap;
|
||
|
||
private const string SKILL_ICONLIST_NAME = "iconlist_skill_multisprite";
|
||
private const string ACTION_ICONLIST_NAME = "ActionIcon/iconlist_action_multisprite";
|
||
private const string STATE_ICONLIST_NAME = "iconlist_state";
|
||
|
||
public CDlgMiniMap m_pDlgMiniMap;
|
||
|
||
// Layout/settings flags for GetUserLayout (saved to server)
|
||
// 布局/设置标志,用于 GetUserLayout(保存到服务器)
|
||
private bool m_bAutoReply;
|
||
private bool m_bOnlineNotify;
|
||
private bool m_bSaveHistory;
|
||
private bool m_bShowItemDescCompare = true;
|
||
private bool m_bShowLowHP = true;
|
||
private bool m_bShowTargetOfTarget = true;
|
||
|
||
// TODO: System module quick bar dialog – GetMiniMode() not yet wired in C#
|
||
private AUIDialog m_pDlgSysModuleQuickBar;
|
||
// TODO: System bar dialog – IsShow() for bMenuMode
|
||
private AUIDialog m_pDlgSystemb;
|
||
|
||
public static bool TALKPROC_IS_TERMINAL(uint id)
|
||
{
|
||
return ((id & 0x80000000u) != 0) && ((id & 0x40000000u) != 0);
|
||
}
|
||
|
||
public static bool TALKPROC_IS_FUNCTION(uint id)
|
||
{
|
||
return ((id) & 0x80000000) != 0;
|
||
}
|
||
|
||
public static uint TALKPROC_GET_FUNCTION_ID(uint id)
|
||
{
|
||
return ((id) & 0x7FFFFFFF);
|
||
}
|
||
|
||
public void PopupNPCDialog(NPC_ESSENCE pEssence)
|
||
{
|
||
var dialogueNpc = CECUIManager.Instance.ShowUI("DialogNPC");
|
||
if (m_pDlgNPC == null)
|
||
{
|
||
if (dialogueNpc == null)
|
||
{
|
||
BMLogger.LogError("can not get dialogue npc");
|
||
return;
|
||
}
|
||
m_pDlgNPC = dialogueNpc.GetComponent<DlgNPC>();
|
||
m_pDlgNPC.SetAUIManager(this);
|
||
}
|
||
m_pDlgNPC.PopupDialog(pEssence);
|
||
}
|
||
|
||
public void PopupNPCDialog(talk_proc pTalk)
|
||
{
|
||
var dialogueNpc = CECUIManager.Instance.ShowUI("DialogNPC");
|
||
if (m_pDlgNPC == null)
|
||
{
|
||
if (dialogueNpc == null)
|
||
{
|
||
BMLogger.LogError("can not get dialogue npc");
|
||
return;
|
||
}
|
||
m_pDlgNPC = dialogueNpc.GetComponent<DlgNPC>();
|
||
m_pDlgNPC.SetAUIManager(this);
|
||
}
|
||
m_pDlgNPC.PopupNPCDialog(pTalk);
|
||
}
|
||
public CECShortcutSet GetSCSByDlg(int indexPanel)
|
||
{
|
||
CECHostPlayer pHost = CECGameRun.Instance.GetHostPlayer();
|
||
CDlgQuickBar cDlgQuickBar = CECUIManager.Instance.GetCDlgQuickBar();
|
||
CECShortcutSet pSCS = null;
|
||
int index = (0);
|
||
if (indexPanel == 1)
|
||
{
|
||
int panel = (index < 0 ? cDlgQuickBar.GetCurPanel1() : index) - 1;
|
||
pSCS = pHost.GetShortcutSet1(0);
|
||
}
|
||
else
|
||
{
|
||
int panel = (index < 0 ? cDlgQuickBar.GetCurPanel2() : index) - 1;
|
||
pSCS = pHost.GetShortcutSet2(panel);
|
||
}
|
||
return pSCS;
|
||
}
|
||
// 弹出任务完成对话框(到达/离开地点等触发) // Popup task-finish dialog (reach/leave site, etc.)
|
||
// C++: pTask->PopupTaskFinishDialog(taskId, &awardTalk); then OnUIDialogEnd() notifies server.
|
||
public bool PopupTaskFinishDialog(uint taskId, talk_proc pTalk)
|
||
{
|
||
if (pTalk.num_window == 0) return false;
|
||
var dialogueNpc = CECUIManager.Instance.ShowUI("DialogNPC");
|
||
if (m_pDlgNPC == null)
|
||
{
|
||
if (dialogueNpc == null)
|
||
{
|
||
BMLogger.LogError("can not get dialogue npc");
|
||
return false;
|
||
}
|
||
m_pDlgNPC = dialogueNpc.GetComponent<DlgNPC>();
|
||
m_pDlgNPC.SetAUIManager(this);
|
||
}
|
||
|
||
m_idCurFinishTask = (int)taskId;
|
||
m_pDlgNPC.PopupNPCDialog(pTalk);
|
||
m_pDlgNPC.SetData(DlgNPC.NPC_DIALOG.NPC_DIALOG_TASK_TALK, "");
|
||
return true;
|
||
}
|
||
|
||
public void EndNPCService()
|
||
{
|
||
m_pCurNPCEssence = null;
|
||
//EC_Game.GetGameRun().GetHostPlayer().EndNPCService();
|
||
EC_ManMessageMono.Instance.EC_ManPlayer.GetHostPlayer().EndNPCService();
|
||
}
|
||
|
||
public bool UpdateTask(uint idTask, int reason)
|
||
{
|
||
Debug.Log($"[EC_GameUIMan] UpdateTask: idTask={idTask}, reason={reason}");
|
||
DlgTaskTrace pDlg = GetDialog("Win_QuestMinion").GetComponent<DlgTaskTrace>();
|
||
if (pDlg) {
|
||
//pDlg->SetBtnUnTraceY(-1, 0);
|
||
pDlg.UpdateContributionTask();
|
||
if (reason == TaskTemplConstants.TASK_SVR_NOTIFY_NEW)
|
||
pDlg.OnTaskNew(idTask);
|
||
}
|
||
|
||
// TODO
|
||
// ���´����������
|
||
// if (reason == TaskTemplConstants.TASK_SVR_NOTIFY_NEW)
|
||
// {
|
||
// m_pDlgQuestionTask.AddQuestionTask(idTask);
|
||
// }
|
||
// else if (reason == TaskTemplConstants.TASK_SVR_NOTIFY_COMPLETE || reason == TaskTemplConstants.TASK_SVR_NOTIFY_GIVE_UP)
|
||
// {
|
||
// m_pDlgQuestionTask.RemoveQuestionTask(idTask);
|
||
// }
|
||
|
||
if (reason == TaskTemplConstants.TASK_SVR_NOTIFY_STORAGE)
|
||
{
|
||
// TODO
|
||
// CDlgTaskList* pDlg = (CDlgTaskList*)GetDialog("Win_QuestList");
|
||
// if (pDlg && pDlg.IsShow())
|
||
// {
|
||
// // refresh data in OnShow()
|
||
// pDlg.RefreshTaskList();
|
||
// }
|
||
return true;
|
||
}
|
||
else
|
||
{
|
||
// zhangyitian 20140521
|
||
// �������ʱ���ɽ������б�ҲҪ���£������˿ɽ������б������µ�����
|
||
return m_pDlgTask.UpdateQuestView();
|
||
}
|
||
}
|
||
public DialogScriptTableObject GetDialogResource()
|
||
{
|
||
return m_dialogResouce;
|
||
}
|
||
public Canvas GetCanvas()
|
||
{
|
||
return m_canvas;
|
||
}
|
||
public void EnableUI(bool bEnable)
|
||
{
|
||
|
||
}
|
||
|
||
/// <summary>
|
||
/// Get user layout data for saving to server. Fills USER_LAYOUT and optionally writes to pData.
|
||
/// 获取用户布局数据用于保存到服务器。填充 USER_LAYOUT,并可选写入 pData。
|
||
/// </summary>
|
||
public void GetUserLayout(byte[] pData, int startIndex, ref uint dwUISize)
|
||
{
|
||
|
||
CECHostPlayer pHost = EC_Game.GetGameRun()?.GetHostPlayer();
|
||
if (pHost == null)
|
||
{
|
||
dwUISize = 0;
|
||
return;
|
||
}
|
||
|
||
// Build and fill USER_LAYOUT (ul)
|
||
USER_LAYOUT ul = new USER_LAYOUT();
|
||
|
||
// Initialize array fields (C# class does not auto-init these)
|
||
ul.bChecked1 = new byte[HostCfgConstants.NUM_HOSTSCSETS1];
|
||
ul.bChecked2 = new byte[HostCfgConstants.NUM_HOSTSCSETS2];
|
||
ul.a_Mark = new SAVE_MARK[EC_GameUIMan_Constants.CECGAMEUIMAN_MAX_MARKS];
|
||
ul.idGroup = new int[EC_GameUIMan_Constants.CECGAMEUIMAN_MAX_GROUPS];
|
||
ul.clrGroup = new uint[EC_GameUIMan_Constants.CECGAMEUIMAN_MAX_GROUPS];
|
||
ul.a_MarkMapID = new short[EC_GameUIMan_Constants.CECGAMEUIMAN_MAX_MARKS];
|
||
for (int k = 0; k < ul.a_Mark.Length; k++)
|
||
{
|
||
ul.a_Mark[k].szName = new ushort[EC_GameUIMan_Constants.CECGAMEUIMAN_MARK_NAME_LEN + 1];
|
||
ul.a_MarkMapID[k] = 1; // C++ inits to 1 per element
|
||
}
|
||
|
||
ul.nVersion = (sbyte)LAYOUTDATA_VERSION;
|
||
ul.nMapMode = (sbyte)(m_pDlgMiniMap != null ? m_pDlgMiniMap.GetMode() : 0);
|
||
|
||
// TODO: Win_QuickbarPetV dialog – bQuickbarPetMode not wired in C# yet
|
||
// TODO: 快捷栏宠物模式对话框尚未在 C# 中接入
|
||
ul.bQuickbarPetMode = false;
|
||
|
||
// TODO : check later – bQuickbar1Mode and bChecked1 from Win_Quickbar*Ha_* dialogs
|
||
// string dlgName = $"Win_Quickbar{HostCfgConstants.SIZE_HOSTSCSET1}Ha";
|
||
// AUIDialog dlgQuickbar1Ha = GetDialog(dlgName);
|
||
// ul.bQuickbar1Mode = dlgQuickbar1Ha != null && dlgQuickbar1Ha.IsShow();
|
||
ul.bQuickbar1Mode = false;
|
||
|
||
for (int i = 0; i < HostCfgConstants.NUM_HOSTSCSETS1; i++)
|
||
{
|
||
// TODO: check later – Chk_Normal checkbox per quickbar panel
|
||
// TODO: 后续核对 – 每个快捷栏面板的 Chk_Normal 勾选状态
|
||
ul.bChecked1[i] = 0;
|
||
}
|
||
|
||
// TODO: check later – bQuickbar2Mode and bChecked2 from Win_Quickbar*Hb_* dialogs
|
||
ul.bQuickbar2Mode = false;
|
||
for (int i = 0; i < HostCfgConstants.NUM_HOSTSCSETS2; i++)
|
||
ul.bChecked2[i] = 0;
|
||
|
||
if (m_pDlgTask != null)
|
||
m_pDlgTask.SyncTrace(ul, false);
|
||
|
||
CDlgQuickBar dlgQuickBar = CECUIManager.Instance?.GetCDlgQuickBar();
|
||
if (dlgQuickBar != null)
|
||
{
|
||
ul.bQuickbarShowAll1 = dlgQuickBar.m_bShowAll1;
|
||
ul.bQuickbarShowAll2 = dlgQuickBar.m_bShowAll2;
|
||
ul.nQuickbarCurPanel1 = dlgQuickBar.m_nCurPanel1;
|
||
ul.nQuickbarCurPanel2 = dlgQuickBar.m_nCurPanel2;
|
||
ul.nQuickbarDisplayPanels1 = dlgQuickBar.m_nDisplayPanels1;
|
||
ul.nQuickbarDisplayPanels2 = dlgQuickBar.m_nDisplayPanels2;
|
||
}
|
||
|
||
// TODO: chat window size/color – m_pDlgChat not wired in C#
|
||
ul.nChatWinSize = 1;
|
||
ul.nCurChatColor = 1;
|
||
|
||
// MiniMap marks
|
||
if (m_pDlgMiniMap != null)
|
||
{
|
||
var marks = m_pDlgMiniMap.GetMarks();
|
||
int markCount = Mathf.Min(marks.Count, EC_GameUIMan_Constants.CECGAMEUIMAN_MAX_MARKS);
|
||
for (int i = 0; i < markCount; i++)
|
||
{
|
||
var m = marks[i];
|
||
ul.a_Mark[i].nNPC = m.nNPC;
|
||
ul.a_Mark[i].vecPos = m.vecPos;
|
||
ul.a_MarkMapID[i] = (short)m.mapID;
|
||
CopyStringToUshortArray(ul.a_Mark[i].szName, m.strName ?? "", EC_GameUIMan_Constants.CECGAMEUIMAN_MARK_NAME_LEN);
|
||
}
|
||
}
|
||
|
||
// TODO: friend group layout – CECFriendMan / GetFriendMan() not available in C# yet
|
||
// TODO: 好友分组布局 – C# 中尚未提供 CECFriendMan / GetFriendMan()
|
||
// Placeholder: idGroup / clrGroup remain zeroed (already initialized)
|
||
|
||
ul.bAutoReply = m_bAutoReply;
|
||
ul.bOnlineNotify = m_bOnlineNotify;
|
||
ul.bSaveHistory = m_bSaveHistory;
|
||
|
||
// TODO: current system module shortcut set index – GetCurSysModShortcutSetIndex() not in C# host
|
||
// TODO: 当前使用的系统模块快捷栏索引 – C# 宿主中暂无 GetCurSysModShortcutSetIndex()
|
||
ul.ucCurSystemModuleSC = 0;
|
||
|
||
// TODO: m_pDlgSysModuleQuickBar – GetMiniMode() not wired
|
||
ul.bSystemModuleQuickBarMini = m_pDlgSysModuleQuickBar != null && GetDlgSysModuleQuickBarMiniMode();
|
||
|
||
// TODO: m_pDlgSystemb – system bar show state
|
||
ul.bMenuMode = m_pDlgSystemb != null && m_pDlgSystemb.IsShow();
|
||
|
||
ul.bShowCompareDesc = m_bShowItemDescCompare;
|
||
ul.bShowLowHP = m_bShowLowHP;
|
||
ul.bShowTargetOfTarget = m_bShowTargetOfTarget;
|
||
|
||
dwUISize = EC_GameUIMan_Constants.USER_LAYOUT_SIZE; // Match C++ sizeof(USER_LAYOUT)=344
|
||
|
||
if (pData != null)
|
||
{
|
||
// Serialize USER_LAYOUT to binary (344 bytes) and copy into pData (match C++ memcpy)
|
||
byte[] layoutBytes = ul.ToBytes();
|
||
Array.Copy(layoutBytes, 0, pData, startIndex, (int)dwUISize);
|
||
}
|
||
|
||
|
||
}
|
||
|
||
/// <summary>Copy string into fixed ushort[] (for SAVE_MARK.szName).</summary>
|
||
private static void CopyStringToUshortArray(ushort[] dest, string str, int maxLen)
|
||
{
|
||
if (dest == null || dest.Length < maxLen + 1) return;
|
||
int len = System.Math.Min(str?.Length ?? 0, maxLen);
|
||
for (int i = 0; i < len; i++)
|
||
dest[i] = (ushort)str[i];
|
||
for (int i = len; i < dest.Length; i++)
|
||
dest[i] = 0;
|
||
}
|
||
|
||
/// <summary>TODO: Wire to system module quick bar mini mode when dialog is available.</summary>
|
||
private bool GetDlgSysModuleQuickBarMiniMode()
|
||
{
|
||
return false;
|
||
}
|
||
|
||
public override void Init()
|
||
{
|
||
base.Init();
|
||
m_IconMap = new Dictionary<byte, (string, Sprite[])>();
|
||
m_pDlgTask = GetDialog(CECUIHelper.DlgTaskName).GetComponent<DlgTask>();
|
||
m_pDlgTask.Show(false);
|
||
|
||
m_pDlgMiniMap = GameObject.FindObjectsByType<CDlgMiniMap>( FindObjectsSortMode.None).FirstOrDefault();
|
||
|
||
m_IconMap[(byte)EC_GAMEUI_ICONS.ICONS_SKILL] = (SKILL_ICONLIST_NAME, Resources.LoadAll<Sprite>(SKILL_ICONLIST_NAME));
|
||
m_IconMap[(byte)EC_GAMEUI_ICONS.ICONS_ACTION] = (ACTION_ICONLIST_NAME, Resources.LoadAll<Sprite>(ACTION_ICONLIST_NAME));
|
||
m_IconMap[(byte)EC_GAMEUI_ICONS.ICONS_STATE] = (STATE_ICONLIST_NAME, Resources.LoadAll<Sprite>(STATE_ICONLIST_NAME));
|
||
foreach(var icon in m_IconMap[(byte)EC_GAMEUI_ICONS.ICONS_STATE].Item2)
|
||
{
|
||
Debug.Log($"Init: icon: {icon.name}");
|
||
}
|
||
}
|
||
public void SetCover(AUIImagePictureBase pImgPic, string nameImage, EC_GAMEUI_ICONS iCONS_TYPE)
|
||
{
|
||
pImgPic.SetImage(m_IconMap[(byte)iCONS_TYPE].Item2.FirstOrDefault(s => s.name == nameImage));
|
||
}
|
||
|
||
/// <summary>Refresh team UI (Arrange Team dialog). Called after team join/leave/member data.</summary>
|
||
public bool UpdateTeam(bool bUpdateNear = false)
|
||
{
|
||
var dlg = GetDialog("Win_ArrangeTeam");
|
||
if (dlg is DlgArrangeTeam arr)
|
||
{
|
||
return arr.UpdateTeam(bUpdateNear);
|
||
}
|
||
return true;
|
||
}
|
||
public string GetRealmName(int realmLevel)
|
||
{
|
||
string strRealm = string.Empty;
|
||
if (realmLevel > 0){
|
||
int layer = CECHostPlayer.GetRealmLayer(realmLevel);
|
||
int subLevel = CECHostPlayer.GetRealmSubLevel(realmLevel);
|
||
strRealm = string.Format(GetStringFromTable(11100), GetStringFromTable(11100+layer), GetStringFromTable(11120+subLevel));
|
||
}
|
||
return strRealm;
|
||
}
|
||
|
||
public void PopupPetListDialog()
|
||
{
|
||
var dlg = CECUIManager.Instance.ShowUI("DlgPetList") as CDlgPetList;
|
||
dlg?.OnInitDialog();
|
||
}
|
||
|
||
public void PopupFriendListDialog()
|
||
{
|
||
var dlg = CECUIManager.Instance.ShowUI("Win_FriendList") as CDlgFriendList;
|
||
dlg?.OnInitDialog();
|
||
|
||
}
|
||
|
||
public void TraceTask(uint ulTaskId)
|
||
{
|
||
if (m_pDlgTask != null)
|
||
{
|
||
m_pDlgTask.TraceTask(ulTaskId);
|
||
}
|
||
}
|
||
|
||
|
||
public void ShowErrorMsg(string pszMsg, string pszName)
|
||
{
|
||
CECUIManager.Instance.ShowMessageBoxYes(pszName, pszMsg, null,null);
|
||
}
|
||
|
||
/*CDlgPopMsg m_pDlgPopMsg;
|
||
void AddHeartBeatHint(string pszMsg)
|
||
{
|
||
m_pDlgPopMsg->Add(pszMsg);
|
||
}*/
|
||
|
||
/// <summary>
|
||
/// Adds a message to the chat system.
|
||
/// Mirrors CECGameUIMan::AddChatMessage in C++ (EC_GameUIMan.cpp).
|
||
/// </summary>
|
||
/// <param name="pszMsg">Message text.</param>
|
||
/// <param name="cChannel">Chat channel.</param>
|
||
/// <param name="idPlayer">Sender role ID (-1 = system).</param>
|
||
/// <param name="szName">Sender name (optional).</param>
|
||
/// <param name="byFlag">Message flag byte (CHANNEL_FRIEND, CHANNEL_GAMETALK, etc.).</param>
|
||
/// <param name="cEmotion">Emotion set ID; high-bit indicates king speaker on GP_CHAT_COUNTRY.</param>
|
||
/// <param name="pItem">Linked item (not fully supported yet).</param>
|
||
/// <param name="pszMsgOrigion">Original unformatted message (for logging/history).</param>
|
||
public void AddChatMessage(string pszMsg, ChatChannel cChannel, int idPlayer = -1, string szName = null,
|
||
byte byFlag = 0, int cEmotion = 0, object pItem = null, string pszMsgOrigion = null)
|
||
{
|
||
// C++:
|
||
// bool bIsKing = false;
|
||
// if( cChannel == GP_CHAT_COUNTRY && (cEmotion & 0x80) ) { cEmotion &= ~0x80; bIsKing = true; }
|
||
bool bIsKing = false;
|
||
if (cChannel == ChatChannel.GP_CHAT_COUNTRY && (cEmotion & 0x80) != 0)
|
||
{
|
||
cEmotion &= ~0x80;
|
||
bIsKing = true;
|
||
}
|
||
|
||
// C++: ACString strModified = FilterEmotionSet(pszMsg, cEmotion);
|
||
string strModified = pszMsg;
|
||
|
||
// C++: 修正给GM的额外信息 (Fix extra info for GM)
|
||
// (Skipped in Unity for now)
|
||
|
||
// C++: 考虑本地化对某些内容不显示的要求 ... (Hide if empty)
|
||
if (string.IsNullOrEmpty(strModified))
|
||
return;
|
||
|
||
// C++: 标明来自GT频道的消息 (Mark GT channel message)
|
||
// if (byFlag == CHANNEL_GAMETALK) strModified += GetStringFromTable(9312);
|
||
|
||
pszMsg = strModified;
|
||
|
||
// C++: if( PlayerIsBlack(idPlayer) ) return;
|
||
// (Blacklist check skipped)
|
||
|
||
// C++: if( cChannel == GP_CHAT_SYSTEM && a_stricmp(pszMsg, GetStringFromTable(809)) == 0 ) return;
|
||
// (System message filter skipped)
|
||
|
||
// C++: if( byFlag == CHANNEL_FRIEND || byFlag == CHANNEL_FRIEND_RE || byFlag == CHANNEL_GAMETALK)
|
||
// AddFriendMessage(...)
|
||
|
||
// C++: else if( byFlag == CHANNEL_USERINFO ) ... (Refresh friend info)
|
||
|
||
// C++: FilterBadWords for Player messages
|
||
// if( cChannel == GP_CHAT_LOCAL || cChannel == GP_CHAT_FARCRY || ... )
|
||
// if (ISPLAYERID(idPlayer)) g_pGame->GetGameRun()->GetUIManager()->FilterBadWords(msg.strMsg);
|
||
bool isPlayerChannel = cChannel == ChatChannel.GP_CHAT_LOCAL
|
||
|| cChannel == ChatChannel.GP_CHAT_FARCRY
|
||
|| cChannel == ChatChannel.GP_CHAT_TEAM
|
||
|| cChannel == ChatChannel.GP_CHAT_FACTION
|
||
|| cChannel == ChatChannel.GP_CHAT_WHISPER
|
||
|| cChannel == ChatChannel.GP_CHAT_TRADE
|
||
|| cChannel == ChatChannel.GP_CHAT_SUPERFARCRY
|
||
|| cChannel == ChatChannel.GP_CHAT_BATTLE
|
||
|| cChannel == ChatChannel.GP_CHAT_COUNTRY;
|
||
|
||
if (isPlayerChannel && idPlayer > 0) // idPlayer > 0 is equivalent to C++ ISPLAYERID(id)
|
||
{
|
||
CECUIManager.Instance.FilterBadWords(ref pszMsg);
|
||
}
|
||
|
||
// C++: Booth Message check (cChannel == GP_CHAT_WHISPER && pszMsg ends with "!#")
|
||
// (Skipped)
|
||
|
||
// C++: TransformNameColor(pItem, strName, clrName);
|
||
|
||
// C++: msgWithColor += ... Color assignments ...
|
||
/*if( ISNPCID(idPlayer) ) msgWithColor += _AL("^C8FF64");
|
||
else if (cChannel == ChatChannel.GP_CHAT_COUNTRY && bIsKing)
|
||
{
|
||
msgWithColor += CDlgChat::m_pszKingColor;
|
||
}
|
||
else
|
||
{
|
||
msgWithColor += CDlgChat::GetChatColor(cChannel, idPlayer);
|
||
}*/
|
||
string colorHex;
|
||
if (GPDataTypeHelper.ISNPCID(idPlayer))
|
||
{
|
||
colorHex = DlgChat.NPC_COLOR;
|
||
}
|
||
else if (cChannel == ChatChannel.GP_CHAT_COUNTRY && bIsKing)
|
||
{
|
||
colorHex = DlgChat.KING_COLOR;
|
||
}
|
||
else
|
||
{
|
||
colorHex = DlgChat.GetChatColor(cChannel, idPlayer);
|
||
}
|
||
|
||
// C++: msgWithColor += GetChatChannelImage(cChannel);
|
||
string channelImage = DlgChat.GetChatChannelImage(cChannel);
|
||
|
||
// C++: if( cChannel == GP_CHAT_COUNTRY && bIsKing ) msgWithColor += GetStringFromTable(10310);
|
||
|
||
// Map the final string structure
|
||
// In C++, the FixedMsg adds &name& or ^&name^& formats to color player names.
|
||
// When building the string, C++ prefixes the color code (colorHex) before the message,
|
||
// which usually means the name is colored. But the content might have its own color reset.
|
||
// We use a regular expression to find `&...&` and wrap ONLY the name in reality.
|
||
string parsedMsg = pszMsg;
|
||
if (parsedMsg.Contains("&"))
|
||
{
|
||
// Convert &Cuong& into <color=#HexColor>Cuong</color>
|
||
parsedMsg = System.Text.RegularExpressions.Regex.Replace(
|
||
parsedMsg,
|
||
@"&([^&]+)&",
|
||
$"<color=#{colorHex}>$1</color>"
|
||
);
|
||
}
|
||
else
|
||
{
|
||
// If there's no &, we just colorize the whole string by default (e.g., system messages)
|
||
parsedMsg = $"<color=#{colorHex}>{parsedMsg}</color>";
|
||
}
|
||
|
||
// Channel icon prefix + message text
|
||
string formattedMsg = $"{channelImage}{parsedMsg}";
|
||
|
||
// C++: Write to m_pDlgChatWhisper, Chat1, Chat2, SuperFarCry
|
||
// Unity equivalent: Dispatch to EventBus for ChatPanelUI to handle
|
||
Debug.Log($"[Cuong][{cChannel}] {formattedMsg}");
|
||
EventBus.Publish(new GameSession.ChatMessageEvent(formattedMsg, (byte)cChannel));
|
||
|
||
// C++: AddChatMessage also handles head bubble via pPlayer->SetLastSaidWords
|
||
// Unity equivalent: Publish EventChatMessageOnTopPlayer
|
||
bool showsAboveHead = cChannel == ChatChannel.GP_CHAT_LOCAL
|
||
|| cChannel == ChatChannel.GP_CHAT_FARCRY
|
||
|| cChannel == ChatChannel.GP_CHAT_TEAM
|
||
|| cChannel == ChatChannel.GP_CHAT_SUPERFARCRY
|
||
|| cChannel == ChatChannel.GP_CHAT_BATTLE
|
||
|| cChannel == ChatChannel.GP_CHAT_COUNTRY;
|
||
|
||
if (showsAboveHead && idPlayer > 0)
|
||
{
|
||
// C++: pPlayer->SetLastSaidWords(strTemp, ...) — strTemp là nội dung chat thuần,
|
||
// KHÔNG bao gồm tên người chơi. Dùng pszMsgOrigion thay vì pszMsg.
|
||
string bubbleText = !string.IsNullOrEmpty(pszMsgOrigion) ? pszMsgOrigion : pszMsg;
|
||
EventBus.PublishChannel(idPlayer, new EventChatMessageOnTopPlayer(idPlayer, bubbleText));
|
||
}
|
||
|
||
// C++: if( cChannel == GP_CHAT_BROADCAST && byFlag == 0 ) SetMarqueeMsg(strConverted);
|
||
if (cChannel == ChatChannel.GP_CHAT_BROADCAST && byFlag == 0)
|
||
{
|
||
// TODO: SetMarqueeMsg(pszMsg); when marquee UI is available
|
||
}
|
||
|
||
// C++: AutoReply Logic
|
||
// else if( gs.bAutoReply && cChannel == GP_CHAT_WHISPER ... )
|
||
// (Skipped)
|
||
}
|
||
// bool LoadIconSet()
|
||
// {
|
||
// bool bval;
|
||
// int dwRead;
|
||
// AFileImage fi;
|
||
// int h, i, j, nIndex;
|
||
// A3DRECT *a_rc[ICONS_MAX];
|
||
// char szFile[MAX_PATH], szLine[AFILE_LINEMAXLEN];
|
||
// int W = 32, H = 32, a_nCountX[ICONS_MAX], a_nCountY[ICONS_MAX];
|
||
// GNET::RoleInfo Info = g_pGame->GetGameRun()->GetSelectedRoleInfo();
|
||
// char a_szIconFile[ICONS_MAX][40] = { "Action", "Skill", "Ivtr", "State", "SkillGrp", "Guild", "Pet", "ELF", "Suite", "Calendar", "PQ" };
|
||
|
||
// if( 0 == Info.gender )
|
||
// strcat(a_szIconFile[ICONS_INVENTORY], "M");
|
||
// else
|
||
// strcat(a_szIconFile[ICONS_INVENTORY], "F");
|
||
|
||
// for( h = 0; h < ICONS_MAX; h++ )
|
||
// {
|
||
// sprintf(szFile, "%s\\Surfaces\\IconSet\\IconList_%s.txt",
|
||
// af_GetBaseDir(), a_szIconFile[h]);
|
||
// bval = fi.Open(szFile, AFILE_OPENEXIST | AFILE_TEXT );
|
||
// if( !bval ) return AUI_ReportError(__LINE__, __FILE__);
|
||
|
||
// fi.ReadLine(szLine, sizeof(szLine), &dwRead);
|
||
// W = atoi(szLine);
|
||
|
||
// fi.ReadLine(szLine, sizeof(szLine), &dwRead);
|
||
// H = atoi(szLine);
|
||
|
||
// fi.ReadLine(szLine, sizeof(szLine), &dwRead);
|
||
// a_nCountY[h] = atoi(szLine);
|
||
|
||
// fi.ReadLine(szLine, sizeof(szLine), &dwRead);
|
||
// a_nCountX[h] = atoi(szLine);
|
||
|
||
// a_rc[h] = (A3DRECT*)a_malloc(sizeof(A3DRECT)*(a_nCountX[h] * a_nCountY[h]));
|
||
// if( !a_rc[h] ) return AUI_ReportError(__LINE__, __FILE__);
|
||
|
||
// for( i = 0; i < a_nCountY[h]; i++ )
|
||
// {
|
||
// for( j = 0; j < a_nCountX[h]; j++ )
|
||
// {
|
||
// nIndex = i * a_nCountX[h] + j;
|
||
// a_rc[h][nIndex].SetRect(j * W, i * H, j * W + W, i * H + H);
|
||
|
||
// bval = fi.ReadLine(szLine, sizeof(szLine), &dwRead);
|
||
// if( dwRead > 0 && strlen(szLine) > 0 )
|
||
// m_IconMap[h][AString(szLine)] = nIndex;
|
||
// }
|
||
// }
|
||
|
||
// fi.Close();
|
||
|
||
// m_pA2DSpriteIcons[h] = new A2DSprite;
|
||
// if( !m_pA2DSpriteIcons[h] )
|
||
// {
|
||
// a_free(a_rc[h]);
|
||
// return AUI_ReportError(__LINE__, __FILE__);
|
||
// }
|
||
|
||
// sprintf(szFile, "IconSet\\IconList_%s.dds", a_szIconFile[h]);
|
||
// bval = m_pA2DSpriteIcons[h]->Init(m_pA3DDevice, szFile, AUI_COLORKEY);
|
||
// if( !bval )
|
||
// {
|
||
// a_free(a_rc[h]);
|
||
// return AUI_ReportError(__LINE__, __FILE__);
|
||
// }
|
||
|
||
// m_vecIconList.push_back( m_pA2DSpriteIcons[h] ); // add for imaged hints
|
||
// }
|
||
|
||
// SetImageList(&m_vecIconList); // add for imaged hints
|
||
|
||
// for( h = 0; h < ICONS_MAX; h++ )
|
||
// {
|
||
// bval = m_pA2DSpriteIcons[h]->ResetItems(
|
||
// a_nCountX[h] * a_nCountY[h], a_rc[h]);
|
||
// a_free(a_rc[h]);
|
||
// if( !bval ) return AUI_ReportError(__LINE__, __FILE__);
|
||
// }
|
||
|
||
// m_pA2DSpriteMask = new A2DSprite;
|
||
// if( !m_pA2DSpriteMask ) return AUI_ReportError(__LINE__, __FILE__);
|
||
|
||
// bval = m_pA2DSpriteMask->Init(m_pA3DDevice,
|
||
// "InGame\\IconHighlight.dds", AUI_COLORKEY);
|
||
// if( !bval ) return AUI_ReportError(__LINE__, __FILE__);
|
||
|
||
// // load the expire icon cover
|
||
// m_pA2DSpriteItemExpire = new A2DSprite;
|
||
// if( !m_pA2DSpriteItemExpire ) return AUI_ReportError(__LINE__, __FILE__);
|
||
// bval = m_pA2DSpriteItemExpire->Init(m_pA3DDevice, "InGame\\IconItemExpire.dds", AUI_COLORKEY);
|
||
// if( !bval )
|
||
// {
|
||
// delete m_pA2DSpriteItemExpire;
|
||
// m_pA2DSpriteItemExpire = NULL;
|
||
// AUI_ReportError(__LINE__, "CECGameUIMan::LoadIconSet(), failed to load InGame\\IconItemExpire.dds");
|
||
// }
|
||
|
||
// // ���ذ���PVP���ͼ��
|
||
// const char *szFactionPVPMineBase[FACTION_PVP_ICON_NUM] = {
|
||
// "InGame\\����_С.tga",
|
||
// "InGame\\����_С_����.tga",
|
||
// "InGame\\����.tga",
|
||
// "InGame\\����_����.tga",
|
||
// "InGame\\����_�״�.tga",
|
||
// };
|
||
// for (i = 0; i < FACTION_PVP_ICON_NUM; ++ i){
|
||
// if (!LoadSprite(szFactionPVPMineBase[i], m_pFactionPVPMineBaseSprite[i])){
|
||
// AUI_ReportError(__LINE__, 1, "CECGameUIMan::LoadIconSet(), failed to load %s", szFactionPVPMineBase[i]);
|
||
// }
|
||
// }
|
||
// const char *szFactionPVPMine[FACTION_PVP_ICON_NUM] = {
|
||
// "InGame\\�����_С.tga",
|
||
// "InGame\\�����_С_����.tga",
|
||
// "InGame\\�����.tga",
|
||
// "InGame\\�����_����.tga",
|
||
// "InGame\\�����_�״�.tga",
|
||
// };
|
||
// for (i = 0; i < FACTION_PVP_ICON_NUM; ++ i){
|
||
// if (!LoadSprite(szFactionPVPMine[i], m_pFactionPVPMineSprite[i])){
|
||
// AUI_ReportError(__LINE__, 1, "CECGameUIMan::LoadIconSet(), failed to load %s", szFactionPVPMine[i]);
|
||
// }
|
||
// }
|
||
// const char *szFactionPVPHasMine = "InGame\\�п���ʾ.tga";
|
||
// if (!LoadSprite(szFactionPVPHasMine, m_pA2DSpriteFactionPVPHasMine)){
|
||
// AUI_ReportError(__LINE__, 1, "CECGameUIMan::LoadIconSet(), failed to load %s", szFactionPVPHasMine);
|
||
// }
|
||
|
||
// // Emotions.�����Ѽ���
|
||
|
||
// // Images
|
||
// char a_szImageFile[GP_CHAT_MAX][40] = { "��ͨ.tga", "����.tga", "���.tga", "����.tga", "����.tga", "", "", "����.tga", "", "ϵͳ.tga", "", "", "�Ž�.tga", "ս��.tga", "����.tga"};
|
||
// for (i = 0; i < GP_CHAT_MAX; ++ i)
|
||
// {
|
||
// AString strFile = AString("InGame\\") + a_szImageFile[i];
|
||
// AString strFullPath = AString("Surfaces\\") + strFile;
|
||
// if (af_IsFileExist(strFullPath))
|
||
// {
|
||
// A2DSprite *pSprite = new A2DSprite;
|
||
// if (!pSprite) return AUI_ReportError(__LINE__, __FILE__);
|
||
// if (pSprite->Init(m_pA3DDevice, strFile, AUI_COLORKEY))
|
||
// {
|
||
// m_pA2DSpriteImage.push_back(pSprite);
|
||
// continue;
|
||
// }
|
||
// else
|
||
// {
|
||
// A3DRELEASE(pSprite);
|
||
// }
|
||
// }
|
||
|
||
// // ����ռλ��
|
||
// m_pA2DSpriteImage.push_back(NULL);
|
||
// }
|
||
|
||
// PAUIDIALOG pShow = GetDialog("Win_Popface");
|
||
// pShow->SetData(AUIMANAGER_MAX_EMOTIONGROUPS);
|
||
// pShow = GetDialog("Win_Popface01");
|
||
// pShow->SetData(AUIMANAGER_MAX_EMOTIONGROUPS);
|
||
// pShow = GetDialog("Win_Popface02");
|
||
// pShow->SetData(AUIMANAGER_MAX_EMOTIONGROUPS);
|
||
|
||
// AScriptFile sf;
|
||
// if( sf.Open("Configs\\Iconsound.txt") )
|
||
// {
|
||
// int idSubType;
|
||
// AString strWave;
|
||
|
||
// while( sf.GetNextToken(true) )
|
||
// {
|
||
// idSubType = atoi(sf.m_szToken);
|
||
// sf.GetNextToken(true);
|
||
// strWave = sf.m_szToken;
|
||
// m_IconSound[idSubType] = strWave;
|
||
// }
|
||
|
||
// sf.Close();
|
||
// }
|
||
|
||
// for (i=0;i<CECSCSysModule::FM_NUM;i++)
|
||
// {
|
||
// const char* pIconFile = res_SysModuleIconFile(i);
|
||
// A2DSprite *pSprite = new A2DSprite;
|
||
// if (!pSprite) return AUI_ReportError(__LINE__, __FILE__);
|
||
// if (!pSprite->Init(m_pA3DDevice, pIconFile, AUI_COLORKEY))
|
||
// {
|
||
// A3DRELEASE(pSprite);
|
||
// a_LogOutput(1, "CECGameUIMan::LoadIconSet , %s",pIconFile);
|
||
// continue;
|
||
// }
|
||
// pSprite->SetLinearFilter(true);
|
||
|
||
// m_pSpriteIconSysModule.push_back(pSprite);
|
||
// }
|
||
|
||
// return true;
|
||
// }
|
||
|
||
}
|
||
|
||
public enum EC_GAMEUI_ICONS : byte
|
||
{
|
||
ICONS_ACTION = 0,
|
||
ICONS_SKILL,
|
||
ICONS_INVENTORY,
|
||
ICONS_STATE,
|
||
ICONS_SKILLGRP,
|
||
ICONS_GUILD,
|
||
ICONS_PET,
|
||
ICONS_ELF,
|
||
ICONS_SUITE,
|
||
ICONS_CALENDAR,
|
||
ICONS_PQ,
|
||
ICONS_MAX
|
||
};
|
||
}
|