Files
test/Assets/PerfectWorld/Scripts/Task/UI/TaskWindow.cs
T
2025-11-20 02:18:48 +07:00

1371 lines
47 KiB
C#
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using BrewMonster.Managers;
using BrewMonster.Scripts.Managers;
using BrewMonster.Network;
using BrewMonster.Scripts.Task;
using CSNetwork.GPDataType;
using ModelRenderer.Scripts.GameData;
using NUnit.Framework;
using PerfectWorld.Scripts.Task;
using UnityEngine;
using UnityEngine.UI;
using TMPro;
namespace BrewMonster.PerfectWorld.Scripts.Task.UI
{
/// <summary>
/// This is DlgTask.cpp
/// </summary>
public class TaskWindow : MonoBehaviour
{
#if UNITY_EDITOR
[ContextMenu("Generate Tasks")]
public void TestUpdateTask()
{
UpdateTask(-1);
}
#endif
// Keep original macro as constant for array sizing
public const int CDLGTASK_AWARDITEM_MAX = 8;
// ===== Nested structs (converted from C++), keep naming, public with explicit layout =====
// [中文] 任务目标位置
// [English] Task object position
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct TASK_OBJECT_POS
{
public int x;
public int y;
public int z;
public int mapid;
}
// [中文] 任务完成时间
// [English] Task finished time
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct TASK_FINISHED_TIME
{
public int iTaskID;
public uint dwTime; // DWORD -> uint
}
// [中文]
// [English] Type grouping node
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct TypeNode
{
public uint type; // DWORD -> uint
public GameObject item; // P_AUITREEVIEW_ITEM -> GameObject
}
// [中文] ȼ
// [English] Level priority node
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct LevelNode
{
public int level;
public GameObject item; // P_AUITREEVIEW_ITEM -> GameObject
}
// ===== Converted member variables (keep original naming) =====
// protected:
protected int m_idLastTask;
protected int m_idSelTask;
protected bool m_bTraceNew;
protected bool m_bShowTrace;
protected int m_iType;
[SerializeField] protected TMP_Text m_pTxt_QuestNO; // PAUILABEL -> TMP_Text
[SerializeField] protected TaskTreeView m_pTv_Quest; // PAUITREEVIEW -> GameObject container
[SerializeField] protected TMP_Text m_pTxt_Content; // PAUITEXTAREA -> TMP_Text
[SerializeField] protected TMP_Text m_pTxt_QuestItem; // PAUITEXTAREA -> TMP_Text
[SerializeField] protected Button m_pBtn_Abandon; // PAUISTILLIMAGEBUTTON -> Button
[SerializeField] protected Button m_pBtn_MainQuest; // PAUISTILLIMAGEBUTTON -> Button
[SerializeField] protected Button m_pBtn_NormalQuest; // PAUISTILLIMAGEBUTTON -> Button
[SerializeField] protected Button m_pBtn_SearchQuest; // PAUISTILLIMAGEBUTTON -> Button
[SerializeField] protected Button m_pBtn_HaveQuest; // PAUISTILLIMAGEBUTTON -> Button
[SerializeField] protected Button m_pBtn_bShowTrace; // PAUISTILLIMAGEBUTTON -> Button
[SerializeField] protected Button m_pBtn_FinishTask; // PAUISTILLIMAGEBUTTON -> Button
[SerializeField] protected TMP_Text m_pTxt_BaseAward; // PAUILABEL -> TMP_Text
[Space(10)]
[SerializeField] protected Button Btn_TreasureMap;
[SerializeField] protected Button Btn_Focus;
[SerializeField] protected GameObject Lab_QuestNO; // the title label of m_pTxt_QuestNO
// PAUIIMAGEPICTURE m_pImg_Item[CDLGTASK_AWARDITEM_MAX];
// Use fixed-size array semantics via initialization length
// [中文] 奖励物品图片数组
// [English] Award item images array
[MarshalAs(UnmanagedType.ByValArray, SizeConst = CDLGTASK_AWARDITEM_MAX)]
[SerializeField] protected Image[] m_pImg_Item = new Image[CDLGTASK_AWARDITEM_MAX];
protected uint m_ImgCount => (uint)m_pImg_Item.Length; // unsigned int -> uint
[SerializeField] protected Button m_pBtn_GotoNPC; // PAUISTILLIMAGEBUTTON -> Button
[SerializeField] protected GameObject m_pQuickBuyTrigger; // CECQuickBuyPopActivityTrigger* -> GameObject
// private:
private static List<int> m_vecTasksUnFinish = new List<int>();
private static List<int> m_vecTasksCanFinish = new List<int>();
// [中文] 目标坐标集合
// [English] Target coordinates collection
private static List<Vector3> m_TargetCoord = new List<Vector3>();
private static string m_strTraceName = string.Empty; // ACString -> string
// [中文] 任务相关矿点映射
// [English] Mine map related to tasks
private static Dictionary<int, object> m_TaskMines = new Dictionary<int, object>(); // MINE_ESSENCE* -> object
// [中文] 任务跟踪计时器
// [English] Task trace counter
private CECCounter m_TaskTraceCounter = new (); // CECCounter -> object placeholder
#region Unity METHODS
private void OnEnable()
{
OnShowDialog();
}
private void Awake()
{
EventBus.Subscribe<TaskItemClickEvent>(evt =>
{
OnEventLButtonDown_Tv_Quest(evt.Data);
});
m_pBtn_HaveQuest.onClick.AddListener(OnCommand_havequest);
m_pBtn_SearchQuest.onClick.AddListener(OnCommand_searchquest);
OnInitDialog();
}
private void Update()
{
Tick();
}
#endregion
#region PUBLIC METHODS
public void OnCommand_searchquest()
{
// if (m_szName != "Win_Quest") return;
m_iType = 1;
// TODO
// PAUIOBJECT pObj = GetDlgItem("Img_New");
// if (pObj && IsShow()) pObj->Show(false);
// if(GetDlgItem("Lab_Trace")) GetDlgItem("Lab_Trace")->Show(false);
if(m_pBtn_bShowTrace) m_pBtn_bShowTrace.gameObject.SetActive(false);
m_pBtn_Abandon.gameObject.SetActive(false);
Btn_Focus.gameObject.SetActive(false);
Lab_QuestNO.gameObject.SetActive(false);
m_pTxt_QuestNO.gameObject.SetActive(false);
m_pBtn_SearchQuest.interactable = false;
m_pBtn_HaveQuest.interactable = true;
SearchForTask();
}
public void OnCommand_havequest()
{
m_iType = 0;
// TODO: if(GetDlgItem("Lab_Trace")) GetDlgItem("Lab_Trace")->Show(true);
if(m_pBtn_bShowTrace) m_pBtn_bShowTrace.gameObject.SetActive(true);
m_pBtn_Abandon.gameObject.SetActive(true);
Btn_Focus.gameObject.SetActive(true);
Lab_QuestNO.gameObject.SetActive(true);
m_pTxt_QuestNO.gameObject.SetActive(true);
m_pBtn_SearchQuest.interactable = true;
m_pBtn_HaveQuest.interactable = false;
UpdateTask();
}
public void OnCommand_showtrace(string szCommand) {}
public void OnCommand_focus(string szCommand) {}
public void OnCommand_abandon(string szCommand) {}
public void OnCommand_CANCEL(string szCommand) {}
public void OnCommand_TreasureMap(string szCommand) {}
public void OnCommand_FinishTask(string szCommand) {}
public void OnCommand_GotoNPC(string szCommand) {}
public void OnEventLButtonDown_Tv_Quest(uint itemData)
{
// UpdateTask((int)itemData);
// POINT ptPos = pObj->GetPos();
// A3DVIEWPORTPARAM *p = m_pA3DEngine->GetActiveViewport()->GetParam();
// int x = GET_X_LPARAM(lParam) - ptPos.x - p->X;
// int y = GET_Y_LPARAM(lParam) - ptPos.y - p->Y;
// PAUITREEVIEW pTree = (PAUITREEVIEW)pObj;
//
// if( AUI_PRESS(VK_SHIFT) && m_iType == 0)
// {
// P_AUITREEVIEW_ITEM pItem = pTree->HitTest(x, y);
//
// if( pItem ) OnCommand_focus("focus");
// }
// P_AUITREEVIEW_ITEM pItem = pTree->GetSelectedItem();
// var pItem = m_pTv_Quest.GetItemByData(itemData);
int idTask = (int)itemData;
// int idTask(0);
// if( pItem && pTree->GetParentItem(pItem) != pTree->GetRootItem())
// idTask = pTree->GetItemData(pItem);
//
if (idTask == 0) return;
//
// if (m_szName == "Win_Quest" && CDlgAutoHelp::IsAutoHelp())
// {
// if(pTree->GetHitArea(x,y) == AUITREEVIEW_RECT_FRAME)
// CDlgWikiShortcut::PopQuestWiki(GetGameUIMan(),idTask);
// }
m_idSelTask = idTask;
}
// void OnEventMouseMove_Txt_QuestItem(WPARAM wParam, LPARAM lParam, AUIObject *pObj);
// void OnEventLButtonDown_Txt_QuestItem(WPARAM wParam, LPARAM lParam, AUIObject *pObj);
// void OnEventLButtonDown_Award_Item(WPARAM wParam, LPARAM lParam, AUIObject *pObj);
//
// void GetItemLinkItemOn(int x, int y, PAUIOBJECT pObj, AUITEXTAREA_EDITBOX_ITEM *pLink);
//
// // get formatted data
// static ACString FormatTaskText(const ACHAR* szText, A3DCOLOR background);
Color GetTaskColor(int idType)
{
// TODO: Map task type to color. Default white.
// if (idType < enumTTDaily || idType >= enumTTEnd) {
// ASSERT(false && "wrong task type");
// return A3DCOLORRGB(255,255,255);
// }
// A3DCOLOR result;
// STRING_TO_A3DCOLOR(CECUIHelper::GetGameUIMan()->GetStringFromTable(idType - enumTTDaily + 3121), result);
// return result;
return Color.white;
}
// static A3DCOLOR GetTaskColor(const ATaskTempl *pTempl);
// static ACString FormatTime(int nSec, const ACString& desc, int timeLimit);
private static string GetTaskNameWithColor(ATaskTempl pTempl)
{
if (pTempl == null) return string.Empty;
var type = (ENUM_TASK_TYPE)pTempl.m_FixedData.m_ulType;
string rawName = ModelRenderer.Scripts.Common.ByteToStringUtils.UshortArrayToUnicodeString(pTempl.m_FixedData.m_szName);
if (type == ENUM_TASK_TYPE.enumTTQiShaList && !string.IsNullOrEmpty(rawName) && rawName[0] == '^')
{
// 如果是七杀榜任务且已经加了颜色,则颜色不变 // If QiShaList task already has color, keep it
return rawName;
}
string strTaskName = GetTaskNameWithOutColor(pTempl);
string strColorPreFix = A3DColorToString(GetTaskColor(pTempl));
return strColorPreFix + strTaskName;
}
// static ACString GetTaskNameWithOutColor(const ATaskTempl* pTempl);
private static string GetTaskNameWithOutColor(ATaskTempl pTempl)
{
if (pTempl == null) return string.Empty;
string name = ModelRenderer.Scripts.Common.ByteToStringUtils.UshortArrayToUnicodeString(pTempl.m_FixedData.m_szName);
if (!string.IsNullOrEmpty(name) && name[0] == '^')
{
// 去掉颜色前缀(假设格式为 ^RRGGBB // Strip color prefix (assume ^RRGGBB)
if (name.Length > 7) return name.Substring(7);
return string.Empty;
}
return name;
}
private static UnityEngine.Color GetTaskColor(ATaskTempl pTempl)
{
// TODO: Map task type/flags to color. Default white.
return UnityEngine.Color.white;
}
private static string A3DColorToString(UnityEngine.Color c)
{
// 原代码将颜色转换为字符串前缀,这里返回空前缀以保持UI简洁 // Return empty prefix for TMP rich text compatibility
return string.Empty;
}
//
private bool Tick()
{
// if( m_szName == "Win_Quest" && IsShow() )
{
var pTree = m_pTv_Quest;
var pItem = pTree.GetSelectedItem();
if( pItem )
{
for( int i = 0; i < m_ImgCount; i++ )
m_pImg_Item[i].gameObject.SetActive(false);
m_pTxt_BaseAward.gameObject.SetActive(false);
// if( pTree->GetParentItem(pItem) != pTree->GetRootItem() )
if( pTree.transform != pItem.transform.parent )
{
if (m_iType == 0)
{
UpdateTask((int)pTree.GetItemData(pItem));
}
else if (m_iType == 1)
{
SearchForTask((int)pTree.GetItemData(pItem));
}
}
else
{
m_idLastTask = -2;
m_pTxt_Content.SetText("");
m_pTxt_QuestItem.SetText("");
m_pBtn_Abandon.interactable = false;
UpdateTaskConfirm(0, false);
Btn_TreasureMap.interactable = false;
}
}
// TODO
// UpdateGotoNPC();
}
// return CDlgBase::Tick();
return true;
}
//
// void RefreshTaskTrace();
public bool UpdateTask(int idTask = -1)
{
// if( m_szName != "Win_Quest" || m_iType != 0)
// {
// return true;
// }
// ATaskTemplMan *pMan = GetGame()->GetTaskTemplateMan();
ATaskTemplMan pMan = EC_Game.GetTaskTemplateMan();
CECTaskInterface pTask = GetHostPlayer().GetTaskInterface();
if (pTask == null)
{
BMLogger.LogError("No CECTaskInterface found !!!");
return false;
}
// PAUITEXTAREA pTextDesc = m_pTxt_Content;
var pTextDesc = m_pTxt_Content;
// PAUITEXTAREA pTextItem = m_pTxt_QuestItem;
var pTextItem = m_pTxt_QuestItem;
string strNewTextItem = "";
string strNewHintItem = "";
bool bLastTaskChanged = false;
// PAUIOBJECT pObj = GetDlgItem("Txt_Contribution");
// if (pObj) {
// ACString strText;
// strText.Format(_AL("%d"), GetHostPlayer()->GetWorldContribution());
// pObj->SetText(strText);
// }
if ( idTask >= 0)
{
ATaskTempl pTemp = pMan.GetTaskTemplByID((uint)idTask);
if (pTemp != null)
{
if( idTask != m_idLastTask )
{
//pTextDesc->SetText(FormatTaskText(pTemp->GetDescription(), pTextDesc->GetColor()));
pTextDesc.SetText(pTemp.GetDescription());
m_idLastTask = idTask;
bLastTaskChanged = true;
}
m_pBtn_Abandon.interactable = pMan.CanGiveUpTask((uint)idTask);
// Get info
Task_State_info tsi = new Task_State_info();
pTask.GetTaskStateInfo((uint)idTask, ref tsi, false);
// Clear first
strNewTextItem = "";
// Base desc
UpdateTaskBaseDesc(ref strNewTextItem, tsi);
// Award NPC
int nANPC = (int)pTemp.GetAwardNPC();
UpdateAwardNPC(ref strNewTextItem, nANPC);
// Complete condition
UpdateCompleteCondition(ref strNewTextItem, ref strNewHintItem, tsi);
// Wanted Item
UpdateItemWanted(ref strNewTextItem, tsi, idTask);
// Treasure Map
UpdateTreasureMap(ref strNewTextItem);
// Task Confirm
UpdateTaskConfirm(idTask, pTemp.m_FixedData.m_enumFinishType == (uint)TaskFinishType.enumTFTConfirm);
// Award
Task_Award_Preview award = default;
pTask.GetTaskAwardPreview((uint)idTask, ref award);
UpdateBaseAward(award);
UpdateItemAward(award);
// GameObject pObj = GetDlgItem<GameObject>("Btn_TreasureMap");
if (Btn_TreasureMap != null)
{
Btn_TreasureMap.gameObject.
SetActive(pTemp.m_FixedData.m_enumMethod == (uint)TaskCompletionMethod.enumTMReachTreasureZone);
}
}
else
{
Debug.LogError($"Task {idTask} not found ATaskTempl !!!");
}
}
else
{
ClearContent(true);
if (m_pBtn_FinishTask)
m_pBtn_FinishTask.gameObject.SetActive(false);
for (int i = 0; i < pTask.GetTaskCount(); i++)
{
int id = (int)pTask.GetTaskId((uint)i);
AddTaskNode(id);
}
SortTaskNodeByType();
string strTemp;
int iMaxTaskCount = CECTaskInterface.TASK_ACTIVE_LIST_MAX_LEN;
strTemp = $"{pTask.GetTaskCount()}/{iMaxTaskCount}";
if (m_pTxt_QuestNO != null) m_pTxt_QuestNO.text = strTemp;
}
// GetGameUIMan()->ReplaceColor(&strNewTextItem, A3DCOLORRGB(255, 255, 255), pTextItem->GetColor());
SetTextItemText(strNewTextItem, pMan.GetTaskTemplByID((uint)idTask) != null && !bLastTaskChanged, strNewHintItem);
return true;
}
//
// Guard: only handle search list when current UI type is 1 (search)
public bool SearchForTask(int idTask = -1)
{
if (m_iType != 1)
{
return true;
}
// Setup managers and UI references
ATaskTemplMan pMan = EC_Game.GetTaskTemplateMan();
CECTaskInterface pTask = GetHostPlayer().GetTaskInterface();
var pTextDesc = m_pTxt_Content;
var pTextItem = m_pTxt_QuestItem;
// Track composed text buffers and change flag
string strNewTextItem = "";
string strNewHintItem = "";
bool bLastTaskChanged = false;
// Simplified: assume we are in quest UI context if tree exists
bool bQuestUI = m_pTv_Quest != null;
// When a concrete task id is provided
if (idTask >= 0)
{
ATaskTempl pTemp = pMan != null ? pMan.GetTaskTemplByID((uint)idTask) : null;
if (pTemp != null)
{
// Update description when the selected task changes
if (idTask != m_idLastTask)
{
if (pTextDesc != null) pTextDesc.SetText(pTemp.GetDescription());
m_idLastTask = idTask;
bLastTaskChanged = true;
}
// Optional: update tree item text if needed (skip if API not available)
if (bQuestUI)
{
var pItem = m_pTv_Quest.GetSelectedItem();
if (pItem != null)
{
uint id = m_pTv_Quest.GetItemData(pItem);
// NOTE: ATaskTemplMan.IsTaskToPush may be conditionally compiled; avoid hard dependency
// If needed, uncomment when method is available:
// if (pMan.IsTaskToPush((int)id)) m_pTv_Quest.SetItemText(pItem, GetTaskNameWithColor(pTemp));
}
}
// Get task state info
Task_State_info tsi = default;
if (pTask != null) pTask.GetTaskStateInfo((uint)idTask, ref tsi, false);
// Reset composed text buffer
strNewTextItem = "";
// Append: base description
UpdateTaskBaseDesc(ref strNewTextItem, tsi);
// Append: deliver NPC
UpdateDeliverNPC(ref strNewTextItem, (int)pTemp.GetDeliverNPC());
// Append: award NPC
int nANPC = (int)pTemp.GetAwardNPC();
UpdateAwardNPC(ref strNewTextItem, nANPC);
// Append: completion conditions
UpdateCompleteCondition(ref strNewTextItem, ref strNewHintItem, tsi);
// Append: wanted items
UpdateItemWanted(ref strNewTextItem, tsi, idTask);
// Preview and show awards
Task_Award_Preview award = default;
if (pTask != null) pTask.GetTaskAwardPreview((uint)idTask, ref award);
UpdateBaseAward(award);
UpdateItemAward(award);
}
else
{
// No template found for id: clear content
m_idLastTask = -2;
if (m_pTxt_Content != null) m_pTxt_Content.SetText("");
if (m_pTxt_QuestItem != null) m_pTxt_QuestItem.SetText("");
}
}
else
{
// zhangyitian 20140521 先将可接任务列表清空,再判断是否有可接任务
// zhangyitian 20140521 First clear the available tasks list, then check if there are available tasks
// 修正了原先没有可接任务时,可接任务列表显示已接任务的问题
// Fix: prevent accepted tasks from showing when there are no available tasks
ClearContent(false);
// TaskTemplLst ttl;
List<ATaskTempl> ttl = new List<ATaskTempl>(); // TaskTemplLst -> List<ATaskTempl>
pMan.GetAvailableTasks(pTask, ttl);
if( ttl.Count <= 0 ) return true;
for(int i = 0; i < ttl.Count; i++ )
{
int id = (int)ttl[i].GetID();
AddTaskNode(id);
}
SortTaskNodeByType();
// string strTemp;
// ActiveTaskList pLst = (ActiveTaskList)pTask.GetActiveTaskList();
// int iMaxTaskCount = pLst->GetMaxSimultaneousCount();
// strTemp.Format(_AL("%d/%d"), pTask->GetTaskCount(), iMaxTaskCount);
// m_pTxt_QuestNO->SetText(strTemp);
}
// Apply colors and set composed text into UI
bool hasTempl = idTask >= 0 && pMan != null && pMan.GetTaskTemplByID((uint)idTask) != null;
SetTextItemText(strNewTextItem, hasTempl && !bLastTaskChanged, strNewHintItem);
// Done
return true;
}
//
// //бɽѽ zhangyitian
// bool UpdateQuestView();
//
// bool IsPQTaskOrSubTask(int idTask);
// bool IsTreasureMapTask(int idTask);
//
// bool TraceTask(int idTask);
// void SyncTrace(void* pData, bool fromServer);
// bool IsShowTrace(){return m_bShowTrace;}
//
// typedef CECGame::ObjectCoords ObjectCoords;
// static const ObjectCoords& GetObjectCoords() { return m_TargetCoord; }
// static const ACString& GetTraceName() { return m_strTraceName; }
// static void SetTraceObjects(const ObjectCoords& objs, const ACString& name);
// static const MINE_ESSENCE* SearchTaskMine(int idTask);
//
// ACString GetKillPlayerRequirements(const Task_State_info& tsi,int iIndex);
//
// void SwitchTaskTrace(int idTask);
// void OnTaskPush(); // µĿɽ
// void OnTaskProcessUpdated(int idTask); // ѽҪǰʾ
// void OnTaskItemGained(int idItem);
#endregion
#region PRIVATE METHODS
private bool OnInitDialog()
{
// m_pTxt_QuestNO = (PAUILABEL)GetDlgItem("Txt_QuestNO");
// m_pTv_Quest = (PAUITREEVIEW)GetDlgItem("Tv_Quest");
// m_pTxt_Content = dynamic_cast<PAUITEXTAREA>(GetDlgItem("Txt_Content"));
// m_pTxt_QuestItem = dynamic_cast<PAUITEXTAREA>(GetDlgItem("Txt_QuestItem"));
// m_pBtn_Abandon = (PAUISTILLIMAGEBUTTON)GetDlgItem("Btn_Abandon");
// m_pTxt_BaseAward = (PAUILABEL)GetDlgItem("Txt_BaseAward");
// m_pBtn_SearchQuest = (PAUISTILLIMAGEBUTTON)GetDlgItem("Btn_SearchQuest");
// m_pBtn_HaveQuest = (PAUISTILLIMAGEBUTTON)GetDlgItem("Btn_HaveQuest");
// m_pBtn_bShowTrace = (PAUISTILLIMAGEBUTTON)GetDlgItem("Btn_ShowTrace");
// m_pBtn_FinishTask = (PAUISTILLIMAGEBUTTON)GetDlgItem("Btn_FinishTask");
// m_pBtn_GotoNPC = (PAUISTILLIMAGEBUTTON)GetDlgItem("Btn_GotoNPC");
if (m_pBtn_FinishTask) m_pBtn_FinishTask.gameObject.SetActive(false);
if (m_pBtn_GotoNPC) m_pBtn_GotoNPC.gameObject.SetActive(false);
// TODO: Set button pushed state
// if (m_pBtn_HaveQuest != null) { /* set pushed state if needed */ }
GameObject pObj = GetDlgItem<GameObject>("Btn_TreasureMap");
if (pObj != null)
{
pObj.SetActive(false);
}
pObj = GetDlgItem<GameObject>("Img_New");
if (pObj != null)
{
pObj.SetActive(false);
}
if (m_pTxt_QuestNO != null)
{
m_pTxt_QuestNO.text = "0";
}
m_TaskTraceCounter.SetPeriod(950);
return true;
}
private T GetDlgItem<T>(string name)
{
var t = transform.Find(name);
if (t != null) return t.GetComponent<T>();
return default(T);
}
public CECHostPlayer GetHostPlayer()
{
return EC_Game.GetGameRun().GetHostPlayer();
}
//
// virtual bool OnInitDialog();
void OnShowDialog()
{
if (m_idSelTask != 0)
UpdateTask();
}
// virtual void OnHideDialog();
// virtual bool OnChangeLayout(PAUIOBJECT pMine, PAUIOBJECT pTheir);
// virtual void OnChangeLayoutEnd(bool bAllDone);
//
private void InsertTaskChildren(TaskTreeViewItem pRoot, uint idTask, bool bExpand, bool bKey)
{
var pTreeTask = m_pTv_Quest;
var pMan = EC_Game.GetTaskTemplateMan();
var pTask = GetHostPlayer().GetTaskInterface();
if (pTreeTask == null || pMan == null || pTask == null) return;
ATaskTempl parentTempl = pMan.GetTaskTemplByID(idTask);
if (parentTempl == null) return;
ATaskTempl child = parentTempl.m_pFirstChild;
while (child != null)
{
uint id = child.m_FixedData.m_ID;
string text = GetTaskNameWithColor(child);
var pItem = pTreeTask.InsertItem(text, pRoot, null);
if (pItem != null)
{
pTreeTask.SetItemData(pItem, id);
if ((int)id == m_idSelTask)
{
if (m_pBtn_Abandon != null) m_pBtn_Abandon.interactable = true;
UpdateTask((int)id);
}
// Optional: colorize key tasks if UI supports it
}
InsertTaskChildren(pItem, id, bExpand, bKey);
child = child.m_pNextSibling;
}
}
private void SetTextItemText(string strNewTextItem, bool keepScrollPos, string strNewHintItem)
{
var pTextItem = m_pTxt_QuestItem;
if (pTextItem == null) return;
// Preserve scroll position if inside a ScrollRect
// UnityEngine.UI.ScrollRect scrollRect = pTextItem.GetComponentInParent<UnityEngine.UI.ScrollRect>();
// float oldNormPos = scrollRect != null ? scrollRect.verticalNormalizedPosition : 0f;
if (!string.Equals(strNewTextItem, pTextItem.text))
{
pTextItem.text = strNewTextItem ?? string.Empty;
// TODO: apply hint to a tooltip UI if available (strNewHintItem)
}
// if (keepScrollPos && scrollRect != null)
// {
// // Restore previous scroll position
// scrollRect.verticalNormalizedPosition = oldNormPos;
// }
}
// void SetTaskText(PAUIOBJECT pObj, ACString* pStr);
// int GetTaskIndex(int idTask);
//
// bool IsQuest()const;
// bool IsShowHaveQuest()const;
// int GetSelectedTaskFromUI();
// bool IsTreasureMapSelected();
//
// // update task content in dialog
// update task content in dialog (converted from C++)
private void UpdateBaseAward(Task_Award_Preview award)
{
var sb = new System.Text.StringBuilder();
int colCount = 0;
const int col = 3;
int cellSpace = 30;
if (award.m_ulGold > 0)
{
var text = $"{GetStringFromTable(3201)} {award.m_ulGold}";
sb.Append(text);
sb.Append(' ', cellSpace - text.Length);
if ((++colCount) % col == 0) sb.Append("\n");
}
if (award.m_ulExp > 0)
{
var text = $"{GetStringFromTable(3201)} {award.m_ulExp}";
sb.Append(text);
sb.Append(' ', cellSpace - text.Length);
if ((++colCount) % col == 0) sb.Append("\n");
}
if (award.m_ulSP > 0)
{
var text = $"{GetStringFromTable(3201)} {award.m_ulSP}";
sb.Append(text);
sb.Append(' ', cellSpace - text.Length);
if ((++colCount) % col == 0) sb.Append("\n");
}
if (award.m_ulRealmExp > 0)
{
sb.Append($"{GetStringFromTable(3207)} {award.m_ulRealmExp}");
if ((++colCount) % col == 0) sb.Append("\n");
}
if (award.m_iForceContrib > 0)
{
sb.Append($"{GetStringFromTable(3205)} {award.m_iForceContrib}");
if ((++colCount) % col == 0) sb.Append("\n");
}
if (award.m_iForceRepu > 0)
{
sb.Append($"{GetStringFromTable(3206)} {award.m_iForceRepu}");
if ((++colCount) % col == 0) sb.Append("\n");
}
if (sb.Length > 0 && m_pTxt_BaseAward != null)
{
m_pTxt_BaseAward.text = sb.ToString();
m_pTxt_BaseAward.gameObject.SetActive(true);
}
}
private void UpdateItemAward(Task_Award_Preview award)
{
bool bShowItem = false;
if (award.m_bHasItem)
{
if (!award.m_bItemKnown)
{
if (m_pTxt_BaseAward != null && m_pTxt_BaseAward.gameObject.activeSelf)
{
string strAward = (GetStringFromTable(3204) ?? string.Empty) + "\n" + (m_pTxt_BaseAward.text ?? string.Empty);
m_pTxt_BaseAward.text = strAward;
}
else if (m_pTxt_BaseAward != null)
{
m_pTxt_BaseAward.text = GetStringFromTable(3204) ?? string.Empty;
m_pTxt_BaseAward.gameObject.SetActive(true);
}
}
else
{
int max = m_pImg_Item != null ? m_pImg_Item.Length : 0;
for (int i = 0; i < max; i++)
{
if (i < award.m_ulItemTypes)
{
var img = m_pImg_Item[i];
if (img == null) continue;
var sprite = EC_IvtrItemUtils.Instance.ResolveItemIconSprite((int)award.m_ItemsId[i]);
if (sprite != null) img.sprite = sprite;
img.color = Color.white;
img.gameObject.SetActive(true);
var countLabel = img.GetComponentInChildren<TMP_Text>(true);
if (countLabel != null) countLabel.text = award.m_ItemsNum[i].ToString();
bShowItem = true;
}
else if (m_pImg_Item[i] != null)
{
m_pImg_Item[i].gameObject.SetActive(false);
}
}
}
}
// adjust the label position relative to item icons (approximate)
if (m_pTxt_BaseAward != null && m_pImg_Item != null && m_pImg_Item.Length > 0 && m_pImg_Item[0] != null)
{
var txtRT = m_pTxt_BaseAward.rectTransform;
var imgRT = m_pImg_Item[0].rectTransform;
var pos = imgRT.anchoredPosition;
var sz = imgRT.sizeDelta;
float margin = 2f;
if (bShowItem) txtRT.anchoredPosition = new Vector2(pos.x, pos.y - (sz.y + margin));
else txtRT.anchoredPosition = pos;
}
}
private void UpdateTaskBaseDesc(ref string strText, Task_State_info tsi)
{
// Build the base description text from task state
var sb = new System.Text.StringBuilder();
// NOTE: Original appended each entry in tsi.m_TaskCharArr (vector<wchar_t*>)
// In C#, this array is not directly available; content is already localized elsewhere.
// Append error message if any
if (tsi.m_ulErrCode != 0)
{
string szMsg = GetFixedMsg(tsi.m_ulErrCode);
if (!string.IsNullOrEmpty(szMsg))
{
sb.Append("<color=#ff0000>");
sb.Append(szMsg);
string strTemp;
if (tsi.m_ulErrCode == TaskInterfaceConstants.TASK_AWARD_FAIL_LEVEL_CHECK)
strTemp = string.Format(GetStringFromTable(7637), tsi.m_ulPremLevelMin);
else
strTemp = GetStringFromTable(807);
sb.Append(strTemp);
sb.AppendLine("</color>");
}
}
// Time limit and remaining time
if (tsi.m_ulTimeLimit > 0)
{
int nSec = (int)tsi.m_ulTimeLimit;
sb.Append(FormatTime(nSec, GetStringFromTable(245), 0));
int remain = System.Math.Max(0, (int)tsi.m_ulTimeLimit - (int)tsi.m_ulTimePassed);
sb.Append(FormatTime(remain, GetStringFromTable(246), 0));
}
// Wait time
if (tsi.m_ulWaitTime > 0)
{
int nSec = System.Math.Max(0, (int)tsi.m_ulWaitTime - (int)tsi.m_ulTimePassed);
sb.Append(FormatTime(nSec, GetStringFromTable(199), 0));
}
// Protect NPC info and timers
if (tsi.m_ulNPCToProtect > 0)
{
// Fallback text with NPC id; detailed name lookup omitted
sb.Append(string.Format(GetStringFromTable(257) ?? "Protect NPC: {0}", tsi.m_ulNPCToProtect));
sb.Append(FormatTime((int)tsi.m_ulProtectTime, GetStringFromTable(258), 0));
int remain = System.Math.Max(0, (int)tsi.m_ulProtectTime - (int)tsi.m_ulTimePassed);
sb.Append(FormatTime(remain, GetStringFromTable(259), 0));
}
// Apply to content text
// if (m_pTxt_Content != null)
// {
// m_pTxt_Content.text += sb.ToString();
// }
strText += sb.ToString();
}
private static string FormatTime(int nSec, string desc, int timeLimit)
{
var ts = System.TimeSpan.FromSeconds(System.Math.Max(0, nSec));
string label = string.IsNullOrEmpty(desc) ? string.Empty : desc;
return $"{label}{ts:hh\\:mm\\:ss}\n";
}
private static string GetStringFromTable(int id)
{
// TODO: return AUIManager.GetStringFromTable(id);
// HARD CODED STRINGS
switch (id)
{
case 3101:
return "Hàng ngày";
case 3102:
return "Tu chân";
case 3103:
return "Chủ tuyến";
case 3104:
return "Phụ tuyến";
case 3105:
return "Event";
case 3106:
return "7 Killer List";
case 3107:
return "Bang hội";
case 3108:
return "Management";
case 3109:
return "Huyền thoại";
case 3110:
return "Câu hỏi";
case 3201:
return "Gold:";
case 3202:
return "EXP:";
case 3203:
return "SP:";
case 3207:
return "Realm EXP:";
case 3205:
return "Contribution:";
case 3206:
return "Reputation:";
case 7621:
return "NPC giao nhiệm vụ: ";
default:
return $"UnKnown_{id} ";
}
}
private static string GetStringFromTable(uint id)
{
// return AUIManager.GetStringFromTable(id);
return GetStringFromTable((int)id);
}
private static string GetFixedMsg(uint id)
{
return BrewMonster.Network.EC_Game.GetFixedMsgs()?.GetWideString((int)id) ?? string.Empty;
}
private void UpdateDeliverNPC(ref string strText, int nDNPC)
{
// [中文] 交付NPC
// [English] Deliver NPC
if (nDNPC == 0)
{
return;
}
// [中文] 从元素数据中查找NPC
// [English] Lookup NPC from element data
string npcName = string.Empty;
var edm = BrewMonster.ElementDataManProvider.GetElementDataMan();
if (edm != null)
{
if (edm.essence_id_data_type_map.TryGetValue((uint)nDNPC, out var dtype)
&& dtype == DATA_TYPE.DT_NPC_ESSENCE
&& edm.essence_id_data_map.TryGetValue((uint)nDNPC, out var obj)
&& obj is NPC_ESSENCE npc)
{
npcName = npc.Name;
}
}
if (string.IsNullOrEmpty(npcName)) npcName = nDNPC.ToString();
// [中文] 追加到内容文本
// [English] Append to content text
var sb = new System.Text.StringBuilder();
sb.Append(GetStringFromTable(7620));
sb.Append(npcName);
sb.Append("\n");
// if (m_pTxt_QuestItem != null)
// {
// Debug.Log($"UpdateDeliverNPC: {sb.ToString()}");
// m_pTxt_QuestItem.text += sb.ToString();
// }
strText += sb.ToString();
}
private A3DVECTOR3 UpdateAwardNPC(ref string strText, int nANPC)
{
A3DVECTOR3 ret = new A3DVECTOR3(0f);
// Award NPC
if (nANPC == 0)
{
return ret;
}
// Lookup NPC name from element data
string npcName = string.Empty;
var edm = BrewMonster.ElementDataManProvider.GetElementDataMan();
if (edm != null)
{
if (edm.essence_id_data_type_map.TryGetValue((uint)nANPC, out var dtype)
&& dtype == DATA_TYPE.DT_NPC_ESSENCE
&& edm.essence_id_data_map.TryGetValue((uint)nANPC, out var obj)
&& obj is NPC_ESSENCE npc)
{
npcName = npc.Name;
}
}
if (string.IsNullOrEmpty(npcName)) npcName = nANPC.ToString();
// Append to content
var sb = new System.Text.StringBuilder();
sb.Append(GetStringFromTable(7621));
sb.Append(npcName);
sb.Append("\n");
// if (m_pTxt_Content != null)
// {
// Debug.Log($"Award NPC: {sb.ToString()}");
// m_pTxt_QuestItem.text += sb.ToString();
// }
strText += sb.ToString();
return ret;
}
// Update completion conditions (monsters, players, gold, level/reincarnation/realm)
private void UpdateCompleteCondition(ref string strText, ref string strHint, Task_State_info tsi)
{
// Setup host reference
// 设置宿主引用
var pHost = GetHostPlayer();
// Monster kill requirements
// 怪物击杀条件
for (int i = 0; i < TaskInterfaceConstants.MAX_MONSTER_WANTED; i++)
{
if (tsi.m_MonsterWanted[i].m_ulMonsterId == 0) break;
uint id = tsi.m_MonsterWanted[i].m_ulMonsterId;
if (tsi.m_MonsterWanted[i].m_ulMonstersKilled > 0 || tsi.m_MonsterWanted[i].m_ulMonstersToKill > 0)
{
// Resolve monster name
// 解析怪物名称
string strName = "^00FF00????^FFFFFF";
var edm = BrewMonster.ElementDataManProvider.GetElementDataMan();
if (edm != null && edm.essence_id_data_type_map.TryGetValue(id, out var dtype)
&& dtype == DATA_TYPE.DT_MONSTER_ESSENCE
&& edm.essence_id_data_map.TryGetValue(id, out var obj)
&& obj is MONSTER_ESSENCE me)
{
strName = ModelRenderer.Scripts.Common.ByteToStringUtils.UshortArrayToUnicodeString(me.name);
}
// Build description for this monster requirement
// 构建该怪物需求描述
string strTemp;
if (tsi.m_MonsterWanted[i].m_ulMonstersToKill > 0)
{
strTemp = string.Format(GetStringFromTable(7624), strName,
tsi.m_MonsterWanted[i].m_ulMonstersKilled, tsi.m_MonsterWanted[i].m_ulMonstersToKill);
}
else
{
strTemp = string.Format(GetStringFromTable(256), tsi.m_MonsterWanted[i].m_ulMonstersKilled);
}
// Prefix label for first/next item
// 首项/后续项的前缀标签
strText += (i == 0) ? GetStringFromTable(7622) : GetStringFromTable(7626);
strText += strTemp;
}
}
// Player kill requirements
// 击杀玩家条件
for (int i = 0; i < TaskInterfaceConstants.MAX_PLAYER_WANTED; i++)
{
if (tsi.m_PlayerWanted[i].m_ulPlayersToKill == 0) break;
if (tsi.m_ItemsWanted[i].m_ulItemId > 0) continue;
strText += (i == 0) ? GetStringFromTable(7630) : GetStringFromTable(7626);
strText += GetKillPlayerRequirements(tsi, i);
}
// Gold requirement
// 金币需求
if (tsi.m_ulGoldWanted != 0)
{
string strTemp = string.Format(GetStringFromTable(7636), tsi.m_ulGoldWanted);
strText += strTemp;
}
// Reincarnation requirement
// 转生次数需求
if (tsi.m_ulReachReincarnation != 0)
{
int iLevel = GetReincarnationCount(pHost);
string strColor = (iLevel < (int)tsi.m_ulReachReincarnation) ? "^ff0000" : "^00ff00";
if (iLevel < (int)tsi.m_ulReachReincarnation)
{
strHint += string.Format(GetStringFromTable(11144), iLevel);
}
strText += strColor;
strText += string.Format(GetStringFromTable(11141), tsi.m_ulReachReincarnation);
}
// Level requirement
// 等级需求
if (tsi.m_ulReachLevel != 0 && pHost != null)
{
int iLevel = pHost.GetBasicProps().iLevel;
string strColor = (iLevel < (int)tsi.m_ulReachLevel) ? "^ff0000" : "^00ff00";
if (iLevel < (int)tsi.m_ulReachLevel)
{
strHint += string.Format(GetStringFromTable(11143), iLevel);
}
strText += strColor;
strText += string.Format(GetStringFromTable(11140), tsi.m_ulReachLevel);
}
// Realm requirement
// 境界等级需求
if (tsi.m_ulReachRealm != 0 && pHost != null)
{
int iLevel = GetRealmLevel(pHost);
string strColor = (iLevel < (int)tsi.m_ulReachRealm) ? "^ff0000" : "^00ff00";
if (iLevel < (int)tsi.m_ulReachRealm)
{
strHint += string.Format(GetStringFromTable(11145), iLevel);
}
strText += strColor;
strText += string.Format(GetStringFromTable(11142), (int)tsi.m_ulReachRealm);
}
}
// Build text for player kill requirements
// 构建击杀玩家需求的文本
private string GetKillPlayerRequirements(Task_State_info tsi, int index)
{
uint killed = tsi.m_PlayerWanted[index].m_ulPlayersKilled;
uint toKill = tsi.m_PlayerWanted[index].m_ulPlayersToKill;
return $" {killed}/{toKill}\n";
}
// Get host reincarnation count (fallback implementation)
// 获取宿主转生次数(回退实现)
private int GetReincarnationCount(CECHostPlayer host)
{
return 0; // TODO: Replace with actual value when available
}
// Get host realm level via basic props level2
// 通过二级等级获取宿主境界等级
private int GetRealmLevel(CECHostPlayer host)
{
return host.GetBasicProps().iLevel2;
}
// Update wanted items section
// 更新需要的物品部分
private void UpdateItemWanted(ref string strText, Task_State_info tsi, int idTask)
{
// Resolve task template
// 获取任务模板
var pMan = EC_Game.GetTaskTemplateMan();
var pTempl = pMan != null ? pMan.GetTaskTemplByID((uint)idTask) : null;
if (pTempl == null) return;
// Iterate wanted items
// 遍历需要的物品
for (int i = 0; i < TaskInterfaceConstants.MAX_ITEM_WANTED; i++)
{
if (tsi.m_ItemsWanted[i].m_ulItemId == 0) break;
// Resolve item name
// 解析物品名称
int itemTid = unchecked((int)tsi.m_ItemsWanted[i].m_ulItemId);
string itemName = EC_IvtrItemUtils.Instance.ResolveItemName(itemTid);
if (string.IsNullOrEmpty(itemName)) itemName = $"Item {itemTid}";
// Compose line: name and progress (gained/toGet)
// 组合文本:名称与进度(已获得/所需)
string strTemp = string.Format(GetStringFromTable(7625), itemName,
tsi.m_ItemsWanted[i].m_ulItemsGained,
tsi.m_ItemsWanted[i].m_ulItemsToGet);
// Prefix for first or subsequent entries
// 首项或后续项前缀
strText += (i == 0) ? GetStringFromTable(7623) : GetStringFromTable(7626);
strText += strTemp;
// If task is KillPlayer, also add player requirements line
// 若为击杀玩家任务,同时追加玩家需求行
if (pTempl.m_FixedData.m_enumMethod == (uint)TaskCompletionMethod.enumTMKillPlayer && i < TaskInterfaceConstants.MAX_PLAYER_WANTED)
{
strText += GetKillPlayerRequirements(tsi, i);
}
}
}
private void UpdateTreasureMap(ref string strText)
{
// if (IsTreasureMapSelected())
// {
// EditBoxItemBase item(enumEICoord);
// item.SetName(GetStringFromTable(7629));
// item.SetInfo(GetStringFromTable(7629));
// item.SetColor(A3DCOLORRGB(0, 255, 0));
//
// strText += (ACHAR)AUICOMMON_ITEM_CODE_START + item.Serialize();
// }
}
private void UpdateTaskConfirm(int idTask, bool bFinishType)
{
CECTaskInterface pTask = GetHostPlayer().GetTaskInterface();
if (m_pBtn_FinishTask != null && pTask != null && bFinishType)
{
m_pBtn_FinishTask.gameObject.SetActive(true);
// TODO: Enable/disable based on task readiness
// m_pBtn_FinishTask->Enable(pTask->IsTaskReadyToConfirm(idTask));
}
else m_pBtn_FinishTask.gameObject.SetActive(false);
}
// void UpdateGotoNPC();
// void ClearGotoNPC();
//
// clear the task content in dialog
void ClearContent(bool clearNPC)
{
m_idLastTask = -2;
m_pTxt_Content.SetText("");
m_pTxt_BaseAward.gameObject.SetActive(false);
for( int j = 0; j < m_ImgCount; j++ )
{
m_pImg_Item[j].gameObject.SetActive(false);
// TODO: Clear image data
// m_pImg_Item[j]->SetData(0);
}
// TODO: Clear Tree quest view
m_pTv_Quest.DeleteAllItems();
}
// // add node to task tree
void AddTaskNode(int id)
{
var pTreeTask = m_pTv_Quest;
ATaskTemplMan pMan = EC_Game.GetTaskTemplateMan();
ATaskTempl pTemp = pMan.GetTaskTemplByID((uint)id);
if( pTemp == null )
{
return;
}
uint nTaskType = pTemp.m_FixedData.m_ulType;
if (pTemp.m_FixedData.m_DynTaskType != 0) nTaskType = (uint)ENUM_TASK_TYPE.enumTTEvent;
uint nAfterType = 0;
TaskTreeViewItem pAfter = null, pParent = null;
// P_AUITREEVIEW_ITEM pItem = pTreeTask->GetFirstChildItem(pTreeTask->GetRootItem());
// var pItem = pTreeTask.transform.parent.GetChild(0).GetComponent<TaskTreeViewItem>();
var pItem = pTreeTask.GetFirstChild();
while( pItem )
{
uint nType = pItem.GetItemData();
if( nType == nTaskType ){
pParent = pItem;
break;
}
else if (nType < nTaskType && nType > nAfterType){
nAfterType = nType;
pAfter = pItem;
}
pItem = pTreeTask.GetNextSiblingItem(pItem);
}
// add Biggest node if not exist
if(pParent ==null)
{
pParent = pTreeTask.InsertItem(GetStringFromTable(3101 + nTaskType - 100), null, pAfter);
// TODO: Expand tree node
// pTreeTask.Expand(pParent, AUITREEVIEW_EXPAND_EXPAND);
pTreeTask.SetItemData(pParent, nTaskType);
//if(nTaskType == enumTTLevel2)
// pTreeTask.SetItemTextColor(pParent, GetTaskColor(pTemp));
}
CECTaskInterface pTask = GetHostPlayer().GetTaskInterface();
string strItem = GetTaskNameWithColor(pTemp);
bool bTaskPushed = pMan.IsTaskToPush(id) && !pTask.HasTask((uint)id);
if (bTaskPushed) {
strItem += GetStringFromTable(3100);
}
pItem = pTreeTask.InsertItem(strItem, pParent, null);
if( pTemp.IsKeyTask() )
// pTreeTask.SetItemTextColor(pItem, GetTaskColor((int)ENUM_TASK_TYPE.enumTTLevel2));
pItem.SetItemTextColor(GetTaskColor((int)ENUM_TASK_TYPE.enumTTLevel2));
// pTreeTask.SetItemHint(pItem, pTemp->GetSignature()); // TODO
pTreeTask.SetItemData(pItem, (uint)id);
InsertTaskChildren(pItem, (uint)id, true, pTemp.IsKeyTask());
if( (int)id == m_idSelTask )
{
// TODO : select the item in UI
// pTreeTask.SelectItem(pItem);
// m_pBtn_Abandon->Enable(true);
UpdateTask(id);
}
}
private void SortTaskNodeByType()
{
var pTreeTask = m_pTv_Quest;
if (pTreeTask == null) return;
// Collect direct children under the tree root (this component's transform)
int childCount = pTreeTask.transform.childCount;
var items = new List<(uint type, TaskTreeViewItem item)>(childCount);
for (int i = 0; i < childCount; i++)
{
var child = pTreeTask.transform.GetChild(i).GetComponent<TaskTreeViewItem>();
if (child == null) continue;
uint nType = pTreeTask.GetItemData(child);
items.Add((nType, child));
}
// Sort by type ascending
items.Sort((a, b) => a.type.CompareTo(b.type));
// Reorder siblings to match sorted order
for (int i = 0; i < items.Count; i++)
{
items[i].item.transform.SetSiblingIndex(i);
}
}
// // whether the task can be traced
// bool IsTaskTraceable(int idTask);
#endregion
}
}