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
{
///
/// This is DlgTask.cpp
///
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 m_vecTasksUnFinish = new List();
private static List m_vecTasksCanFinish = new List();
// [中文] 目标坐标集合
// [English] Target coordinates collection
private static List m_TargetCoord = new List();
private static string m_strTraceName = string.Empty; // ACString -> string
// [中文] 任务相关矿点映射
// [English] Mine map related to tasks
private static Dictionary m_TaskMines = new Dictionary(); // 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(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("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 ttl = new List(); // TaskTemplLst -> List
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(GetDlgItem("Txt_Content"));
// m_pTxt_QuestItem = dynamic_cast(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("Btn_TreasureMap");
if (pObj != null)
{
pObj.SetActive(false);
}
pObj = GetDlgItem("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(string name)
{
var t = transform.Find(name);
if (t != null) return t.GetComponent();
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();
// 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(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)
// 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("");
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("");
}
}
// 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();
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();
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
}
}