Merge branch 'develop' into feature/hp_interact_npc

# Conflicts:
#	Assets/PerfectWorld/Scripts/Network/CSNetwork/C2SCommand/C2SCommandFactory.cs
#	Assets/PerfectWorld/Scripts/Task/CECTaskInterface.cs
#	Assets/PerfectWorld/Scripts/Task/TaskInterface.cs
#	Assets/PerfectWorld/Scripts/Task/TaskProcess.cs
This commit is contained in:
Tungdv
2025-11-21 11:45:16 +07:00
21 changed files with 2349 additions and 213 deletions
@@ -6483,7 +6483,7 @@ MonoBehaviour:
m_TargetGraphic: {fileID: 7392889747821849613}
m_HandleRect: {fileID: 2343337405992641122}
m_Direction: 2
m_Value: 0
m_Value: 1
m_Size: 1
m_NumberOfSteps: 0
m_OnValueChanged:
@@ -7284,6 +7284,7 @@ MonoBehaviour:
m_Script: {fileID: 11500000, guid: 101488732bfd4d2fab4ea07f7ac6731f, type: 3}
m_Name:
m_EditorClassIdentifier:
_nameTaskText: {fileID: 502589151962525598}
m_pTxt_QuestNO: {fileID: 9151364455187038631}
m_pTv_Quest: {fileID: 6916443525973237579}
m_pTxt_Content: {fileID: 392616940935835323}
@@ -1,5 +1,6 @@
using UnityEngine;
using System;
using CSNetwork;
namespace BrewMonster.Network
{
@@ -57,11 +58,7 @@ namespace BrewMonster.Network
return m_AbsTimeStart + (int)sec;
}
}
public float timeGetTime()
{
return Time.time;
}
}
}
@@ -4,7 +4,7 @@ using UnityEngine;
using UnityEngine.UI;
using System.Reflection;
using System.Text;
using System.Text.RegularExpressions;
using CSNetwork.GPDataType;
using BrewMonster.Network;
using BrewMonster;
using BrewMonster.Common;
@@ -80,95 +80,7 @@ namespace BrewMonster.Scripts.Managers
/// <returns>Formatted text for TextMeshPro</returns>
private static string FormatForTextMeshPro(string text)
{
if (string.IsNullOrEmpty(text))
return string.Empty;
StringBuilder result = new StringBuilder(text);
// Handle line breaks (\r)
result.Replace("\\r", "\n");
// Handle color codes (^RRGGBB format)
string processedText = ProcessColorCodes(result);
return processedText;
}
/// <summary>
/// Format text for legacy Text components (limited rich text support)
/// </summary>
/// <param name="text">Raw text with formatting codes</param>
/// <returns>Formatted text for legacy Text</returns>
private static string FormatForLegacyText(string text)
{
if (string.IsNullOrEmpty(text))
return string.Empty;
StringBuilder result = new StringBuilder(text);
// Handle line breaks (\r)
result.Replace("\\r", "\n");
// Handle color codes (^RRGGBB format) - convert to Unity's rich text format
string processedText = ProcessColorCodesForLegacy(result);
return processedText;
}
/// <summary>
/// Process color codes for TextMeshPro (supports hex colors directly)
/// </summary>
private static string ProcessColorCodes(StringBuilder text)
{
// Pattern to match color codes: ^ followed by 6 hex characters
string pattern = @"\^([0-9A-Fa-f]{6})";
return Regex.Replace(text.ToString(), pattern, match =>
{
string hexColor = match.Groups[1].Value;
return $"<color=#{hexColor}>";
}, RegexOptions.None);
}
/// <summary>
/// Process color codes for legacy Text (convert to Unity rich text format)
/// </summary>
private static string ProcessColorCodesForLegacy(StringBuilder text)
{
// Pattern to match color codes: ^ followed by 6 hex characters
string pattern = @"\^([0-9A-Fa-f]{6})";
return Regex.Replace(text.ToString(), pattern, match =>
{
string hexColor = match.Groups[1].Value;
// Convert hex to Unity color format
Color color = HexToColor(hexColor);
return $"<color=#{ColorUtility.ToHtmlStringRGB(color)}>";
}, RegexOptions.None);
}
/// <summary>
/// Convert hex color string to Unity Color
/// </summary>
/// <param name="hex">Hex color string (e.g., "ffcb4a")</param>
/// <returns>Unity Color object</returns>
private static Color HexToColor(string hex)
{
if (hex.Length != 6)
return Color.white;
try
{
int r = Convert.ToInt32(hex.Substring(0, 2), 16);
int g = Convert.ToInt32(hex.Substring(2, 2), 16);
int b = Convert.ToInt32(hex.Substring(4, 2), 16);
return new Color(r / 255f, g / 255f, b / 255f, 1f);
}
catch
{
return Color.white;
}
return EC_Utility.FormatForTextMeshPro(text);
}
// Current selected item for equip/unequip operations
@@ -739,7 +651,7 @@ namespace BrewMonster.Scripts.Managers
{
if (legacy != null)
{
legacy.text = FormatForLegacyText(value ?? string.Empty);
legacy.text = EC_Utility.FormatForLegacyText(value ?? string.Empty);
}
if (tmp != null)
{
@@ -756,7 +668,7 @@ namespace BrewMonster.Scripts.Managers
{
string formattedText = preferTextMeshPro ?
FormatForTextMeshPro(value ?? string.Empty) :
FormatForLegacyText(value ?? string.Empty);
EC_Utility.FormatForLegacyText(value ?? string.Empty);
if (legacy != null)
{
@@ -578,5 +578,14 @@ namespace CSNetwork.C2SCommand
};
return SerializeCommand(CommandID.SEVNPC_SERVE, cmd, content);
}
public static Octets CreateTaskNotifyCmd()
{
var cmd = new cmd_header
{
cmd = (ushort)CommandID.TASK_NOTIFY
};
return SerializeCommand(CommandID.TASK_NOTIFY, cmd);
}
}
}
@@ -18,6 +18,7 @@ using System.Runtime.InteropServices;
using System.Text;
using System.Text;
using System.Threading.Tasks;
using BrewMonster.Scripts.Task;
using CommandID = CSNetwork.GPDataType.CommandID;
namespace CSNetwork
@@ -1175,5 +1176,12 @@ namespace CSNetwork
iCount += iNumSend;
}
}
public void c2s_SendCmdTaskNotify(ref task_notify_base pBuf, uint sz)
{
gamedatasend gamedatasend = new gamedatasend();
gamedatasend.Data = C2SCommandFactory.CreateTaskNotifyCmd();
SendProtocol(gamedatasend);
}
}
}
@@ -12,6 +12,7 @@ using System.Collections.Generic;
using System.IO;
using System.Text;
using System.Threading.Tasks;
using BrewMonster.Scripts.Task;
using UnityEngine;
using UnityEngine.SceneManagement;
@@ -298,6 +299,12 @@ namespace BrewMonster.Network
//Debug.Log("[Dat]- SendCmdGetAllData");
Instance._gameSession.c2s_SendCmdGetAllData(byPack, byEquip, byTask);
}
public static void c2s_CmdTaskNotify(ref task_notify_base pBuf, uint sz)
{
Instance._gameSession.c2s_SendCmdTaskNotify(ref pBuf, sz);
}
#endregion
public static void GetRoleBaseInfo(int iNumRole, List<int> aRoleIDs)
@@ -1,3 +1,4 @@
using System;
using BrewMonster;
using ModelRenderer.Scripts.GameData;
using System.Collections.Generic;
@@ -157,7 +158,7 @@ namespace BrewMonster.Scripts.Task
public ATaskTempl GetTaskTemplByID(uint ulID)
{
if (m_TaskTemplMap.TryGetValue((uint)ulID, out ATaskTempl task))
if (m_AllTemplMap.TryGetValue((uint)ulID, out ATaskTempl task))
{
return task;
}
@@ -349,6 +350,41 @@ namespace BrewMonster.Scripts.Task
}
public uint GetTaskStorageId(uint id)
{
// id1ʼ
// abase::hash_map<int, int>::iterator it = m_StorageTaskMap.find(id);
// return it == m_StorageTaskMap.end() ? 0 : it->second;
return m_StorageTaskMap.ContainsKey((int)id) ? (uint)m_StorageTaskMap[(int)id] : 0;
}
public void RemoveActiveStorageTask( StorageTaskList pLst, uint id)
{
// unsigned int set_id = GetTaskTemplMan()->GetTaskStorageId(id);
uint set_id = GetTaskStorageId(id);
if (set_id > 0)
{
// unsigned short* arr = pLst->m_Storages[set_id-1];
int start = ((int)set_id - 1) * TaskTemplConstants.TASK_STORAGE_LEN;
ushort[] arr = new ushort[TaskTemplConstants.TASK_STORAGE_LEN];
Array.Copy(pLst.m_Storages, start, arr, 0, TaskTemplConstants.TASK_STORAGE_LEN);
// int i;
for (int i = 0; i < TaskTemplConstants.TASK_STORAGE_LEN; i++)
{
if (arr[i] == (ushort)id)
{
arr[i] = 0;
break;
}
}
}
}
// 占位:可接返回0,不可接返回非0 // Placeholder: return 0 if deliverable, non-zero otherwise
// private int CanDeliverTask(TaskInterface pPlayer, uint templId)
@@ -973,6 +973,46 @@ namespace BrewMonster.Scripts.Task
return 0u;
}
public void ShowPunchBagMessage(bool bSucced,bool bMax,uint MonsterTemplID,int dps,int dph)
{
// TODO : implement UI message box
// CECGameUIMan* pGameUI = g_pGame->GetGameRun()->GetUIManager()->GetInGameUIMan();
//
// if (pGameUI == NULL) return;
//
// elementdataman *pDataMan = g_pGame->GetElementDataMan();
//
// DATA_TYPE dt;
// MONSTER_ESSENCE *pMonster = (MONSTER_ESSENCE *)pDataMan->get_data_ptr(MonsterTemplID, ID_SPACE_ESSENCE, dt);
//
// ACString strNpcName;
// if( dt == DT_MONSTER_ESSENCE )
// {
// if( pMonster)
// strNpcName = pMonster->name;
// }
//
// ACString str;
// if (!bSucced)
// {
// str.Format(pGameUI->GetStringFromTable(303),strNpcName);
// pGameUI->MessageBox("",str,MB_OK,A3DCOLORRGBA(255, 255, 255, 160));
// }
//
// else if (bMax)
// {
// str.Format(pGameUI->GetStringFromTable(304),dph);
// pGameUI->MessageBox("",str,MB_OK,A3DCOLORRGBA(255, 255, 255, 160));
// }
// else
// {
// str.Format(pGameUI->GetStringFromTable(305),dph);
// pGameUI->MessageBox("",str,MB_OK,A3DCOLORRGBA(255, 255, 255, 160));
// }
}
#endif
@@ -1249,6 +1289,109 @@ namespace BrewMonster.Scripts.Task
{
}
public bool IsTaskReadyToConfirm(int iTaskID)
{
if (m_TasksToConfirm == null) return false;
bool ret;
if (m_TasksToConfirm.TryGetValue(iTaskID, out ret)) return ret;
return false;
}
public void NotifyServer(ref task_notify_base pBuf, uint sz)
{
UnityGameSession.c2s_CmdTaskNotify(ref pBuf, sz);
}
public bool CheckVersion()
{
// return static_cast<ActiveTaskList*>(GetActiveTaskList())->m_Version == TASK_ENTRY_DATA_CUR_VER;
return GetActiveTaskList().m_Version == TaskTemplConstants.TASK_ENTRY_DATA_CUR_VER;
}
public StorageTaskList GetStorageTaskList()
{
StorageTaskList ret = new StorageTaskList();
ret.ReadByte(m_pStorageTaskListBuf);
return ret;
}
public uint GetTaskMask()
{
return 0;
}
public byte[] GetFinishedTimeList()
{
return m_pFinishedTimeListBuf;
}
void SetForceNavigateFinishFlag(bool bFinish) { m_bForceNavigateFinish = bFinish;} //
public void OnNewTask(int iTaskID)
{
ATaskTempl pTempl = GetTaskTemplMan().GetTaskTemplByID((uint)iTaskID);
if (pTempl != null
&& pTempl.m_FixedData.m_enumMethod== (uint)TaskCompletionMethod.enumTMSimpleClientTaskForceNavi)
{
SetForceNavigateFinishFlag(false);
// TODO: trigger navigation event
// m_pHost.OnNaviageEvent(iTaskID,CECNavigateCtrl::EM_PREPARE);
}
}
public void OnTaskConfirmUpdate()
{
// TODO: update task confirm UI
// CECGameUIMan* pGameUI = g_pGame->GetGameRun()->GetUIManager()->GetInGameUIMan();
// if (pGameUI) pGameUI->UpdateTaskConfirm();
}
public void UpdateConfirmTasksMap()
{
m_TasksToConfirm.Clear();
TaskClient.OnTaskCheckStatus(this);
OnTaskConfirmUpdate();
}
public void OnCompleteTask(int iTaskID)
{
ATaskTempl pTempl = GetTaskTemplMan().GetTaskTemplByID((uint)iTaskID);
if (pTempl != null &&
pTempl.m_FixedData.m_enumMethod == (uint)TaskCompletionMethod.enumTMSimpleClientTaskForceNavi)
{
//TODO: trigger navigation end event
// m_pHost.OnNaviageEvent(iTaskID,CECNavigateCtrl::EM_END);
SetForceNavigateFinishFlag(false);
}
}
public void TakeAwayCommonItem(uint ulTemplId, uint ulNum) {}
public void TakeAwayTaskItem(uint ulTemplId, uint ulNum) {}
public void TakeAwayGold(uint ulNum) {}
public void TakeAwayFactionConsumeContrib(int ulNum){}
public void OnGiveupTask(int iTaskID)
{
ATaskTempl pTempl = GetTaskTemplMan().GetTaskTemplByID((uint)iTaskID);
if (pTempl != null &&
pTempl.m_FixedData.m_enumMethod == (uint)TaskCompletionMethod.enumTMSimpleClientTaskForceNavi)
{
// TODO: trigger navigation end event
// m_pHost.OnNaviageEvent(iTaskID,CECNavigateCtrl::EM_END);
SetForceNavigateFinishFlag(false);
}
}
public void UpdateTaskUI(uint idTask, int reason)
{
// TODO: update task UI
// CECGameUIMan* pGameUI = g_pGame->GetGameRun()->GetUIManager()->GetInGameUIMan();
// if (pGameUI)
// {
// pGameUI->UpdateTask(idTask, reason);
// }
}
}
@@ -0,0 +1,515 @@
using System;
using System.Reflection;
using System.Runtime.InteropServices;
using BrewMonster.Network;
using BrewMonster.Scripts.Task;
using PerfectWorld.Scripts.Task;
using UnityEngine;
namespace BrewMonster.Scripts.Task
{
// provide some global methods
public class TaskClient
{
#if _TASK_CLIENT
private const uint FINISH_DLG_SHOWN_TIME = 3000; // TODO: Confirm correct value
private static uint s_finishDlgShownTime = 0;
public static void OnTaskCheckStatus(TaskInterface pTask)
{
// 版本与交付合法性检查 // Version and deliver legality check
if (pTask == null || !pTask.IsDeliverLegal())
return;
// TODO: CheckVersion not exposed on TaskInterface; skipping version check
// 读取激活任务列表 // Read active task list
ActiveTaskList pLst = TryGetActiveList(pTask);
if (pLst == null) return;
ActiveTaskEntry[] aEntries = pLst.m_TaskEntries;
uint ulCurTime = GetCurTime();
// 遍历所有激活任务 // Iterate active tasks
for (int i = 0; i < pLst.m_uTaskCount; i++)
{
ActiveTaskEntry CurEntry = aEntries[i];
if (CurEntry == null) continue;
if (CurEntry.m_ulTemplAddr == 0)
{
// assert(false) // English: unexpected empty template
continue;
}
ATaskTempl pTempl = CurEntry.GetTempl();
if (pTempl == null) continue;
// TODO: IsValidState from C++ not found in managed port; skip validity-state check
// PQ子任务 // PQ subtask
if (pTempl.m_FixedData.m_bPQSubTask)
{
// TODO: CheckGlobalPQKeyValue(true) not ported; if implemented and returns 0, notify server then continue
// if (pTempl.CheckGlobalPQKeyValue(true) == 0) { ... }
}
// 超时判断 // Timeout check
if (pTempl.m_FixedData.m_ulTimeLimit != 0
&& CurEntry.m_ulTaskTime + pTempl.m_FixedData.m_ulTimeLimit < ulCurTime)
{
pTempl.IncValidCount();
_notify_svr(pTask, (int)ClientNotificationConstants.TASK_CLT_NOTIFY_CHECK_FINISH, CurEntry.m_ID);
continue;
}
// 绝对失效时间判断 // Absolute fail time check
if (pTempl.m_FixedData.m_bAbsFail)
{
// TODO: Time zone bias and 'task_tm.before' not ported; skipping precise comparison
}
// 进入或离开区域导致失败 // Entering or leaving region causes failure
{
float[] pos = new float[3];
uint ulWorldId = (uint)pTask.GetPos(pos);
// 进入区域失败 // Enter region fail
if (pTempl.m_FixedData.m_bEnterRegionFail && ulWorldId == pTempl.m_FixedData.m_ulEnterRegionWorld)
{
for (uint iRegion = 0; iRegion < pTempl.m_FixedData.m_ulEnterRegionCnt; iRegion++)
{
Task_Region t = pTempl.m_FixedData.m_pEnterRegion[(int)iRegion];
if (IsInZone(t.zvMin, t.zvMax, pos))
{
pTempl.IncValidCount();
_notify_svr(pTask, (int)ClientNotificationConstants.TASK_CLT_NOTIFY_CHECK_FINISH, CurEntry.m_ID);
break;
}
}
}
// 离开区域失败 // Leave region fail
if (pTempl.m_FixedData.m_bLeaveRegionFail)
{
bool bLeaveRegion = false;
if (ulWorldId != pTempl.m_FixedData.m_ulLeaveRegionWorld) bLeaveRegion = true;
else
{
uint iRegion = 0;
for (; iRegion < pTempl.m_FixedData.m_ulLeaveRegionCnt; iRegion++)
{
Task_Region t = pTempl.m_FixedData.m_pLeaveRegion[(int)iRegion];
if (IsInZone(t.zvMin, t.zvMax, pos))
break;
}
if (iRegion >= pTempl.m_FixedData.m_ulLeaveRegionCnt) bLeaveRegion = true;
}
if (bLeaveRegion)
{
pTempl.IncValidCount();
_notify_svr(pTask, (int)ClientNotificationConstants.TASK_CLT_NOTIFY_CHECK_FINISH, CurEntry.m_ID);
}
}
}
// 离开家族失败 // Leave faction fail
if (!pTask.IsAtCrossServer() && pTempl.m_FixedData.m_bLeaveFactionFail && !pTask.IsInFaction(1))
{
pTempl.IncValidCount();
_notify_svr(pTask, (int)ClientNotificationConstants.TASK_CLT_NOTIFY_CHECK_FINISH, CurEntry.m_ID);
continue;
}
// 对话/NPC完成类任务跳过本轮 // Skip talk-to-NPC or NPC-finish tasks here
if ((TaskCompletionMethod)pTempl.m_FixedData.m_enumMethod == TaskCompletionMethod.enumTMTalkToNPC
|| pTempl.m_FixedData.m_bMarriage
|| (TaskFinishType)pTempl.m_FixedData.m_enumFinishType == TaskFinishType.enumTFTNPC)
continue;
// 判断未完成的直接完成判定 // Check direct-finish for unfinished tasks
if (!CurEntry.IsFinished())
{
// 到达地点直接完成 // Reach-site direct finish
if ((TaskCompletionMethod)pTempl.m_FixedData.m_enumMethod == TaskCompletionMethod.enumTMReachSite
&& (TaskFinishType)pTempl.m_FixedData.m_enumFinishType == TaskFinishType.enumTFTDirect)
{
if (ulCurTime - s_finishDlgShownTime < FINISH_DLG_SHOWN_TIME)
continue;
float[] pos = new float[3];
uint ulWorldId = (uint)pTask.GetPos(pos);
if (ulWorldId == pTempl.m_FixedData.m_ulReachSiteId)
{
for (uint iRegion = 0; iRegion < pTempl.m_FixedData.m_ulReachSiteCnt; iRegion++)
{
Task_Region t = pTempl.m_FixedData.m_pReachSite[(int)iRegion];
if (IsInZone(t.zvMin, t.zvMax, pos))
{
var pTalk = pTempl.m_AwardTalk;
if (pTalk.num_window == 0 || (pTalk.num_window == 1 && pTalk.windows != null && pTalk.windows.Length > 0 && pTalk.windows[0].num_option == 0))
{
pTempl.IncValidCount();
_notify_svr(pTask, ClientNotificationConstants.TASK_CLT_NOTIFY_REACH_SITE, (ushort)pTempl.GetID());
}
else
{
// TODO: PopupTaskFinishDialog not exposed; implement UI as needed
s_finishDlgShownTime = ulCurTime;
}
break;
}
}
}
continue;
}
// 离开地点直接完成 // Leave-site direct finish
if ((TaskCompletionMethod)pTempl.m_FixedData.m_enumMethod == TaskCompletionMethod.enumTMLeaveSite
&& (TaskFinishType)pTempl.m_FixedData.m_enumFinishType == TaskFinishType.enumTFTDirect)
{
if (ulCurTime - s_finishDlgShownTime < FINISH_DLG_SHOWN_TIME)
continue;
float[] pos = new float[3];
uint ulWorldId = (uint)pTask.GetPos(pos);
bool regRet = false;
if (ulWorldId == pTempl.m_FixedData.m_ulLeaveSiteId)
{
for (uint iRegion = 0; iRegion < pTempl.m_FixedData.m_ulLeaveSiteCnt; iRegion++)
{
Task_Region t = pTempl.m_FixedData.m_pLeaveSite[(int)iRegion];
if (IsInZone(t.zvMin, t.zvMax, pos))
{
regRet = true;
break;
}
}
}
if (!regRet)
{
var pTalk = pTempl.m_AwardTalk;
if (pTalk.num_window == 0 || (pTalk.num_window == 1 && pTalk.windows != null && pTalk.windows.Length > 0 && pTalk.windows[0].num_option == 0))
{
pTempl.IncValidCount();
_notify_svr(pTask, ClientNotificationConstants.TASK_CLT_NOTIFY_LEAVE_SITE, (ushort)pTempl.GetID());
}
else
{
// TODO: PopupTaskFinishDialog not exposed; implement UI as needed
s_finishDlgShownTime = ulCurTime;
}
}
continue;
}
}
// 非子任务:检查奖励条件并按需标记/通知 // If no children, check award conditions and update
if (pTempl != null && pTempl.m_pFirstChild == null)
{
bool bNeedServerCheck =
pTempl.RecursiveCheckAward(pTask, pLst, CurEntry, ulCurTime, -1) == 0
&& pTempl.CanFinishTask(pTask, CurEntry, ulCurTime);
if (pTempl.m_FixedData.m_bDisplayInExclusiveUI && pTempl.m_FixedData.m_bAutoDeliver
&& (TaskFinishType)pTempl.m_FixedData.m_enumFinishType == TaskFinishType.enumTFTDirect)
{
// TODO: Hook game UI and update auto-deliver countdown; no UI manager available here
uint ulRemainTime = 0;
if ((TaskCompletionMethod)pTempl.m_FixedData.m_enumMethod == TaskCompletionMethod.enumTMWaitTime)
{
uint ultime = CurEntry.m_ulTaskTime + pTempl.m_FixedData.m_ulWaitTime;
if (ultime > ulCurTime) ulRemainTime = ultime - ulCurTime;
}
// TODO: pTempl.m_bReadyToNotifyServer/ResetAutoDelTask workflow may need UI support
if (pTempl.m_FixedData.m_bReadyToNotifyServer && bNeedServerCheck)
{
pTempl.IncValidCount();
// TODO: pTempl.ResetAutoDelTask() not exposed; skip
_notify_svr(pTask, (int)ClientNotificationConstants.TASK_CLT_NOTIFY_CHECK_FINISH, (ushort)CurEntry.m_ID);
}
}
else
{
// TODO: UpdateTaskToConfirm not ported; implement confirmation UI/state if needed
UpdateTaskToConfirm(pTask, pTempl, bNeedServerCheck);
}
}
}
// TODO: ATaskTemplMan.UpdateStatus(pTask) not found in C# port; skipping
}
// ===== Helpers =====
// 取当前时间(服务器绝对时间) // Get current time (server absolute)
private static uint GetCurTime()
{
return (uint)EC_Game.GetServerAbsTime();
}
// 反射读取激活任务列表 // Read active task list via reflection
private static ActiveTaskList TryGetActiveList(TaskInterface pTask)
{
// Try to get private method GetActiveTaskList on CECTaskInterface
MethodInfo mi = pTask.GetType().GetMethod("GetActiveTaskList", BindingFlags.Instance | BindingFlags.NonPublic);
if (mi != null)
{
try { return mi.Invoke(pTask, null) as ActiveTaskList; } catch { }
}
// Fallback to private field m_pActiveListBuf
FieldInfo fi = pTask.GetType().GetField("m_pActiveListBuf", BindingFlags.Instance | BindingFlags.NonPublic);
if (fi != null)
{
try { return fi.GetValue(pTask) as ActiveTaskList; } catch { }
}
return null;
}
// 区域内检测(AABB // In-zone check (AABB)
private static bool IsInZone(ZONE_VERT min, ZONE_VERT max, float[] pos)
{
if (pos == null || pos.Length < 3) return false;
return pos[0] >= min.x && pos[0] <= max.x
&& pos[1] >= min.y && pos[1] <= max.y
&& pos[2] >= min.z && pos[2] <= max.z;
}
private static void _notify_svr(TaskInterface pTask, byte uReason, ushort uTaskID)
{
task_notify_base notify = new task_notify_base();
notify.reason = uReason;
notify.task = uTaskID;
pTask.NotifyServer( ref notify, (uint)Marshal.SizeOf<task_notify_base>());
}
// 更新“待确认任务” // Update task to confirm
private static void UpdateTaskToConfirm(TaskInterface pTask, ATaskTempl pTempl, bool needServerCheck)
{
// TODO: Implement confirmation queue/UI if required by design
}
// Handle server notification for task updates
public static void OnServerNotify(TaskInterface pTask, byte[] pBuf, uint sz)
{
// Check version validity
// TODO: CheckVersion not exposed on TaskInterface; skipping version check
if (!pTask.CheckVersion())
return;
// Validate buffer size for base notification structure
if (sz < (uint)Marshal.SizeOf<task_notify_base>()) return;
// Marshal base notification structure from buffer
GCHandle handle = GCHandle.Alloc(pBuf, GCHandleType.Pinned);
task_notify_base pNotify;
try
{
pNotify = Marshal.PtrToStructure<task_notify_base>(handle.AddrOfPinnedObject());
}
finally
{
handle.Free();
}
ATaskTempl pTempl = null;
ActiveTaskEntry pEntry = null;
// Handle error code notification
if (pNotify.reason == TaskTemplConstants.TASK_SVR_NOTIFY_ERROR_CODE)
{
// TODO: svr_task_err_code struct not defined; need to define or use alternative approach
// if (sz != Marshal.SizeOf<svr_task_err_code>()) return;
#if _ELEMENTCLIENT
// TODO: GetEntry method not implemented in ActiveTaskList; need to implement or use alternative
// ActiveTaskList pLst = TryGetActiveList(pTask);
// if (pLst != null)
// {
// pEntry = GetEntry(pLst, pNotify.task);
// if (pEntry != null) pEntry.SetErrReported();
// }
// TODO: TaskShowErrMessage not found; implement error message display
// TaskShowErrMessage(...);
#endif
return;
}
// Handle forget skill notification
else if (pNotify.reason == TaskTemplConstants.TASK_SVR_NOTIFY_FORGET_SKILL)
{
// TODO: OnForgetLivingSkill method not found in ATaskTemplMan; implement if needed
// ATaskTemplMan pMan = GetTaskTemplMan(pTask);
// if (pMan != null) pMan.OnForgetLivingSkill(pTask);
return;
}
// Handle new task notification
else if (pNotify.reason == TaskTemplConstants.TASK_SVR_NOTIFY_NEW)
{
ATaskTemplMan pMan = GetTaskTemplMan(pTask);
if (pMan != null) pTempl = pMan.GetTopTaskByID(pNotify.task);
}
// Handle dynamic task time mark notification
else if (pNotify.reason == TaskTemplConstants.TASK_SVR_NOTIFY_DYN_TIME_MARK)
{
// TODO: svr_task_dyn_time_mark struct not defined; need to define or use alternative
// if (sz != Marshal.SizeOf<svr_task_dyn_time_mark>()) return;
// TODO: OnDynTasksTimeMark method not found in ATaskTemplMan; implement if needed
// ATaskTemplMan pMan = GetTaskTemplMan(pTask);
// if (pMan != null)
// {
// svr_task_dyn_time_mark dynMark = Marshal.PtrToStructure<svr_task_dyn_time_mark>(handle.AddrOfPinnedObject());
// pMan.OnDynTasksTimeMark(pTask, dynMark.time_mark, dynMark.version);
// }
return;
}
// Handle dynamic task data notification
else if (pNotify.reason == TaskTemplConstants.TASK_SVR_NOTIFY_DYN_DATA)
{
if (sz <= (uint)Marshal.SizeOf<task_notify_base>()) return;
// TODO: OnDynTasksData method not found in ATaskTemplMan; implement if needed
// ATaskTemplMan pMan = GetTaskTemplMan(pTask);
// if (pMan != null)
// {
// byte[] dynData = new byte[sz - Marshal.SizeOf<task_notify_base>()];
// Array.Copy(pBuf, Marshal.SizeOf<task_notify_base>(), dynData, 0, dynData.Length);
// pMan.OnDynTasksData(pTask, dynData, (uint)dynData.Length, pNotify.task != 0);
// }
return;
}
// Handle storage data notification
else if (pNotify.reason == TaskTemplConstants.TASK_SVR_NOTIFY_STORAGE)
{
// TODO: StorageTaskList struct not defined; need to define or use alternative
// if (sz != Marshal.SizeOf<task_notify_base>() + Marshal.SizeOf<StorageTaskList>()) return;
// TODO: OnStorageData method not found in ATaskTemplMan; implement if needed
// ATaskTemplMan pMan = GetTaskTemplMan(pTask);
// if (pMan != null)
// {
// byte[] storageData = new byte[Marshal.SizeOf<StorageTaskList>()];
// Array.Copy(pBuf, Marshal.SizeOf<task_notify_base>(), storageData, 0, storageData.Length);
// pMan.OnStorageData(pTask, storageData);
// }
// TODO: UpdateTaskUI static method not found; implement UI update if needed
// TaskInterface.UpdateTaskUI(pNotify.task, pNotify.reason);
return;
}
// Handle special award notification
else if (pNotify.reason == TaskTemplConstants.TASK_SVR_NOTIFY_SPECIAL_AWARD)
{
// TODO: svr_task_special_award and special_award structs not defined; need to define
// if (sz != Marshal.SizeOf<svr_task_special_award>()) return;
// TODO: OnSpecialAward method not found in ATaskTemplMan; implement if needed
// ATaskTemplMan pMan = GetTaskTemplMan(pTask);
// if (pMan != null)
// {
// svr_task_special_award awardNotify = Marshal.PtrToStructure<svr_task_special_award>(handle.AddrOfPinnedObject());
// pMan.OnSpecialAward(ref awardNotify.sa, pTask);
// if (awardNotify.sa.id1 == 0)
// {
// // ID is 0 means no storage space, show newbie gift reminder
// // TODO: CECGameUIMan and PopupNewbieGiftRemind not found; implement UI if needed
// }
// }
return;
}
// Handle task limit increase notification
else if (pNotify.reason == TaskTemplConstants.TASK_SVR_NOTIFY_SET_TASK_LIMIT)
{
ActiveTaskList pLst = TryGetActiveList(pTask);
if (pLst != null)
{
// TODO: ExpandMaxSimultaneousCount method not implemented; implement if needed
// pLst.ExpandMaxSimultaneousCount();
}
// TODO: PopChatMessage static method and FIXMSG_TASK_LIMIT_INCREASED constant not found
// TaskInterface.PopChatMessage(FIXMSG_TASK_LIMIT_INCREASED);
return;
}
// Search for task entry in active task list
else
{
ActiveTaskList pLst = TryGetActiveList(pTask);
if (pLst != null)
{
for (byte i = 0; i < pLst.m_uTaskCount; i++)
{
ActiveTaskEntry CurEntry = pLst.m_TaskEntries[i];
if (CurEntry == null) continue;
if (CurEntry.m_ID != pNotify.task || CurEntry.m_ulTemplAddr == 0)
continue;
pTempl = CurEntry.GetTempl();
pEntry = CurEntry;
break;
}
}
}
// Handle player killed notification
if (pNotify.reason == TaskTemplConstants.TASK_SVR_NOTIFY_PLAYER_KILLED)
{
// TODO: CECUIHelper.OnTaskProcessUpdated not found; implement UI update if needed
// CECUIHelper.OnTaskProcessUpdated(pNotify.task);
}
// Handle monster killed notification
if (pNotify.reason == TaskTemplConstants.TASK_SVR_NOTIFY_MONSTER_KILLED)
{
// Monster kill count >= 2 triggers auto team
// TODO: svr_monster_killed struct not defined; need to define or use alternative
// if (sz == Marshal.SizeOf<svr_monster_killed>())
// {
// svr_monster_killed pKilled = Marshal.PtrToStructure<svr_monster_killed>(handle.AddrOfPinnedObject());
// if (pKilled.monster_num >= 2)
// {
// // TODO: CECAutoTeam and DoAutoTeam not found; implement auto team if needed
// // CECAutoTeam pAutoTeam = g_pGame.GetGameRun().GetHostPlayer().GetAutoTeam();
// // pAutoTeam.DoAutoTeam(CECAutoTeam.TYPE_TASK, pNotify.task);
// }
// }
// TODO: CECUIHelper.OnTaskProcessUpdated not found; implement UI update if needed
// CECUIHelper.OnTaskProcessUpdated(pNotify.task);
}
// Handle task completion or give up notification
else if (pNotify.reason == TaskTemplConstants.TASK_SVR_NOTIFY_COMPLETE || pNotify.reason == TaskTemplConstants.TASK_SVR_NOTIFY_GIVE_UP)
{
// TODO: CECUIHelper.OnTaskCompleted not found; implement UI update if needed
// CECUIHelper.OnTaskCompleted(pNotify.task);
}
// Validate template was found
if (pTempl == null)
{
// TODO: Replace assert with appropriate error handling
Debug.Assert(false, "Task template not found");
return;
}
// Clear valid count and process server notification
pTempl.ClearValidCount();
// TODO: OnServerNotify method signature may need adjustment for C# (ref/out parameters)
pTempl.OnServerNotify(pTask, pEntry, ref pNotify, sz);
}
// Helper method to get task template manager
private static ATaskTemplMan GetTaskTemplMan(TaskInterface pTask)
{
if (pTask is CECTaskInterface cecTask)
{
// Use reflection to access private GetTaskTemplMan method
MethodInfo mi = cecTask.GetType().GetMethod("GetTaskTemplMan", BindingFlags.Instance | BindingFlags.NonPublic);
if (mi != null)
{
try { return mi.Invoke(cecTask, null) as ATaskTemplMan; } catch { }
}
}
// Fallback to global access if available
// TODO: Check if EC_Game.GetTaskTemplateMan() is accessible
return EC_Game.GetTaskTemplateMan();
}
#endif
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: eb05c492df834a7da959d4d32b56057e
timeCreated: 1763461796
@@ -49,6 +49,7 @@ namespace BrewMonster.Scripts.Task
uint GetTaskId(uint ulIndex);
uint CanDeliverTask(uint ulTaskId);
void UpdateTaskUI(uint idTask, int reason);
#endif
// bool HasTask(uint taskId);
// bool CheckTaskForbid(uint taskId);
@@ -82,7 +83,23 @@ namespace BrewMonster.Scripts.Task
bool IsInTeam();
uint GetAccountTotalCash();
uint GetCurTime();
ActiveTaskList GetActiveTaskList();
void SetFinishDlgShowTime(int t);
void NotifyServer(ref task_notify_base pBuf, uint sz);
bool CheckVersion();
StorageTaskList GetStorageTaskList();
void ShowPunchBagMessage(bool bSucced,bool bMax,uint MonsterTemplID,int dps,int dph);
ActiveTaskList GetActiveTaskList();
uint GetTaskMask();
byte[] GetFinishedTimeList();
void OnNewTask(int iTaskID);
void UpdateConfirmTasksMap();
void OnCompleteTask(int iTaskID);
void TakeAwayCommonItem(uint ulTemplId, uint ulNum);
void TakeAwayTaskItem(uint ulTemplId, uint ulNum);
void TakeAwayGold(uint ulNum) ;
void TakeAwayFactionConsumeContrib(int ulNum);
void TakeAwayFactionExpContrib(int ulNum){}
void OnGiveupTask(int iTaskID);
}
}
+190 -14
View File
@@ -105,7 +105,7 @@ namespace PerfectWorld.Scripts.Task
public bool IsAwardNotifyTeam() => (m_uState & (byte)TaskState.TASK_STATE_AWARD_NOTIFY_TEAM) != 0;
public bool IsContributionFinish() => (m_uState & (byte)TaskState.TASK_STATE_CONTRIBUTION_FINISH) != 0;
// void SetFinished() { m_uState |= TASK_STATE_FINISHED; }
public void SetFinished() { m_uState |= (char)TaskState.TASK_STATE_FINISHED; }
// void ClearFinished() { m_uState &= ~TASK_STATE_FINISHED; }
// void SetSuccess() { m_uState |= TASK_STATE_SUCCESS; }
// void ClearSuccess() { m_uState &= ~TASK_STATE_SUCCESS; }
@@ -184,6 +184,7 @@ namespace PerfectWorld.Scripts.Task
public class ActiveTaskList
{
// --- Header Fields ---
// NOTE: union
public byte[] header = new byte[CECTaskInterface.TASK_ACTIVE_LIST_HEADER_LEN];
public byte m_uTaskCount; // number of tasks
@@ -241,11 +242,194 @@ namespace PerfectWorld.Scripts.Task
}
}
// void UpdateTaskMask(unsigned long& ulMask) const;
// void UpdateUsedCount();
// void RealignTask(ActiveTaskEntry* pEntry, unsigned char uReserve);
// void ClearTask(TaskInterface* pTask, ActiveTaskEntry* pEntry, bool bRemoveItem);
// void RecursiveClearTask(TaskInterface* pTask, ActiveTaskEntry* pEntry, bool bRemoveItem, bool bRemoveAcquired, bool bClearTask);
// void UpdateTaskMask(unsigned long& ulMask) const;
// void UpdateUsedCount();
void RealignTask(ActiveTaskEntry pEntry, byte uReserve)
{
// TODO: implement RealignTask logic
// // unsigned char uCurIndex = static_cast<unsigned char>(pEntry - m_TaskEntries);
// byte uCurIndex = (byte)Array.IndexOf(m_TaskEntries, pEntry);
//
// uint ulCount = (uint)m_uTaskCount - uCurIndex; // ʣ
//
// if (ulCount == 0) return; // һ
//
// byte uEmptyCount = 0;
// for (int uEmpty = uCurIndex; uEmpty < TaskInterfaceConstants.TASK_ACTIVE_LIST_MAX_LEN; uEmpty++)
// {
// if (m_TaskEntries[uEmpty].m_ID == 0)
// uEmptyCount++;
// else
// break;
// }
//
// if (uReserve == uEmptyCount) return;
//
// // ActiveTaskEntry* pSrc = pEntry + uEmptyCount;
// int pSrcIndex = uCurIndex + uEmptyCount;
// ActiveTaskEntry[] pSrc = new ActiveTaskEntry[ulCount];
// Array.Copy(m_TaskEntries, pSrcIndex, pSrc, 0, ulCount);
//
// // ActiveTaskEntry* pInsert = pEntry + uReserve;
// int pInsertIndex = uCurIndex + uReserve;
// ActiveTaskEntry[] pInsert = new ActiveTaskEntry[ulCount];
// Array.Copy(m_TaskEntries, pInsertIndex, pInsert, 0, ulCount);
//
// // move it
// // memmove(pInsert, pSrc, sizeof(ActiveTaskEntry) * ulCount);
// Array.Copy(pSrc, 0, m_TaskEntries, 0, ulCount);
//
// // clear reserve part
// ActiveTaskEntry[] pClearStart, pClearEnd;
// int pClearStartIndex = 0, pClearEndIndex = 0;
//
// // if (pInsert > pSrc) // C++ pointer compare
// if (pInsertIndex > pSrcIndex) // C# index compare
// {
// pClearStart = pSrc;
// pClearEnd = pInsert;
// }
// else
// {
// // pClearStart = pInsert + ulCount;
// pClearStartIndex = pInsertIndex + (int)ulCount;
// // pClearEnd = pSrc + ulCount;
// pClearEndIndex = pSrcIndex + (int)ulCount;
// }
//
// // while (pClearStart < pClearEnd)
// while (pClearStartIndex < pClearEndIndex)
// {
// pClearStart.m_ulTemplAddr = 0;
// pClearStart.m_ID = 0;
// pClearStart++;
// }
//
// // calc gap
// unsigned char uGap = static_cast<unsigned char>(pInsert - pSrc);
// unsigned long i = 0;
//
// for (; i < static_cast<unsigned long>(uCurIndex); i++)
// {
// // Parent, PrevСuCurIndex
// ActiveTaskEntry& CurEntry = m_TaskEntries[i];
//
// if(!CurEntry.m_ID)
// continue;
//
// if (CurEntry.m_ChildIndex != 0xff && CurEntry.m_ChildIndex >= uCurIndex)
// CurEntry.m_ChildIndex += uGap;
// if (CurEntry.m_NextSblIndex != 0xff && CurEntry.m_NextSblIndex >= uCurIndex)
// CurEntry.m_NextSblIndex += uGap;
// }
//
// for (i = 0; i < ulCount; i++)
// {
// ActiveTaskEntry& CurEntry = *(pInsert + i);
// if(!CurEntry.m_ID)
// continue;
//
// if (CurEntry.m_ParentIndex != 0xff && CurEntry.m_ParentIndex >= uCurIndex)
// CurEntry.m_ParentIndex += uGap;
// if (CurEntry.m_PrevSblIndex != 0xff && CurEntry.m_PrevSblIndex >= uCurIndex)
// CurEntry.m_PrevSblIndex += uGap;
// if (CurEntry.m_ChildIndex != 0xff)
// CurEntry.m_ChildIndex += uGap;
// if (CurEntry.m_NextSblIndex != 0xff)
// CurEntry.m_NextSblIndex += uGap;
// }
}
public void ClearTask(TaskInterface pTask, ActiveTaskEntry pEntry, bool bRemoveItem)
{
RecursiveClearTask(pTask, pEntry, bRemoveItem, true, true);
RealignTask(pEntry, 0);
}
void RecursiveClearTask(
TaskInterface pTask,
ActiveTaskEntry pEntry,
bool bRemoveItem,
bool bRemoveAcquired,
bool bClearTask)
{
while (pEntry.m_ChildIndex != 0xff)
{
RecursiveClearTask(
pTask,
m_TaskEntries[pEntry.m_ChildIndex],
bRemoveItem,
bRemoveAcquired,
bClearTask);
}
ATaskTempl pTempl = pEntry.GetTempl();
// ȥõƷ
#if _TASK_CLIENT
if (bRemoveItem && pTempl != null)
{
if (bRemoveAcquired || pTempl.m_FixedData.m_bClearAcquired) pTempl.RemoveAcquiredItem(pTask, bClearTask, false);
pTempl.TakeAwayGivenItems(pTask);
}
#endif
ushort uTaskId = pEntry.m_ID;
pEntry.m_ulTemplAddr = 0;
pEntry.m_ID = 0;
if (m_uTaskCount > 0)
m_uTaskCount--;
else
// TaskInterface::WriteLog(pTask->GetPlayerId(), uTaskId, 0, "ClearTask, TaskCount == 0");
if (pEntry.m_ParentIndex != 0xff)
{
if (pEntry.m_PrevSblIndex != 0xff)
m_TaskEntries[pEntry.m_PrevSblIndex].m_NextSblIndex = pEntry.m_NextSblIndex;
else
m_TaskEntries[pEntry.m_ParentIndex].m_ChildIndex = pEntry.m_NextSblIndex;
if (pEntry.m_NextSblIndex != 0xff) m_TaskEntries[pEntry.m_NextSblIndex].m_PrevSblIndex = pEntry.m_PrevSblIndex;
}
else
{
if (pTempl != null)
{
if (pTempl.m_FixedData.m_bHidden)
{
if (m_uTopHideTaskCount > 0)
m_uTopHideTaskCount--;
}
else if(pTempl.m_FixedData.m_bDisplayInTitleTaskUI)
{
if (m_uTitleTaskCount > 0)
m_uTitleTaskCount--;
}
else
{
if (m_uTopShowTaskCount > 0)
m_uTopShowTaskCount--;
}
if (m_uUsedCount >= pTempl.m_uDepth)
m_uUsedCount -= pTempl.m_uDepth;
else
{
// TaskInterface::WriteLog(pTask->GetPlayerId(), uTaskId, 0, "ClearTask, No Enough Used Count");
m_uUsedCount = 0;
}
}
}
}
public ActiveTaskEntry GetEntry(uint ulId)
{
for (int i = 0; i < m_uTaskCount; i++)
if (m_TaskEntries[i].m_ID == ulId)
return m_TaskEntries[i];
return null;
}
// void ClearChildrenOf(TaskInterface* pTask, ActiveTaskEntry* pParent, bool bRemoveItem = true);
// ActiveTaskEntry* GetEntry(unsigned long ulId)
// {
@@ -267,13 +451,5 @@ namespace PerfectWorld.Scripts.Task
// void ClearTimeMarkUpdate() { m_uListState &= ~TLIST_STATE_UPDATE_TIME_MARK; }
// int GetMaxSimultaneousCount() {return m_uMaxSimultaneousCount ? TASK_MAX_SIMULTANEOUS_COUT : TASK_DEFAULT_MAX_SIMULTANEOUS_COUT;}
// void ExpandMaxSimultaneousCount() {m_uMaxSimultaneousCount = 1;}
public ActiveTaskEntry GetEntry(uint ulId)
{
for (int i = 0; i < m_uTaskCount; i++)
if (m_TaskEntries[i].m_ID == ulId)
return m_TaskEntries[i];
return null;
}
};
}
@@ -1,3 +1,6 @@
using System;
using System.Runtime.InteropServices;
using BrewMonster.Network;
using BrewMonster.Scripts.Task;
using PerfectWorld.Scripts.Task;
@@ -381,6 +384,203 @@ namespace BrewMonster.Scripts.Task
}
}
// bool CanShowInExclusiveUI (TaskInterface* pTask, unsigned long ulCurTime) const;
public void OnServerNotify(
TaskInterface pTask,
ActiveTaskEntry pEntry,
ref task_notify_base pNotify,
uint sz)
{
uint ulTime = 0, ulCaptainTask = 0;
ActiveTaskList pLst = null;
ATaskTempl pSub = new ATaskTempl();
task_sub_tags sub_tags = new task_sub_tags();
// memset(&sub_tags, 0, sizeof(sub_tags));
uint i=0;
svr_monster_killed pKilled = null;
svr_player_killed pKilledPlayer = null;
StorageTaskList pStorage = pTask.GetStorageTaskList();
svr_treasure_map pTreasure = null;
var m_enumMethod = m_FixedData.m_enumMethod;
switch (pNotify.reason)
{
case TaskTemplConstants.TASK_SVR_NOTIFY_PLAYER_KILLED:
{
if (sz != Marshal.SizeOf<svr_player_killed>()) break;
if (m_enumMethod != (uint)TaskCompletionMethod.enumTMKillPlayer) break;
pKilledPlayer = pNotify as svr_player_killed;
int iIndex = pKilledPlayer.index;
if (iIndex < TaskInterfaceConstants.MAX_MONSTER_WANTED)
{
pEntry.m_wMonsterNum[iIndex] = pKilledPlayer.player_num;
}
}
break;
case TaskTemplConstants.TASK_SVR_NOTIFY_TREASURE_MAP:
if (m_enumMethod == (uint)TaskCompletionMethod.enumTMReachTreasureZone)
{
pTreasure = pNotify as svr_treasure_map;
pEntry.m_iUsefulData1 = pTreasure.treasure_index;
}
break;
case TaskTemplConstants.TASK_SVR_NOTIFY_MONSTER_KILLED:
if (sz != Marshal.SizeOf<svr_monster_killed>()) break;
if (m_enumMethod != (uint)TaskCompletionMethod.enumTMKillNumMonster) break;
pKilled = pNotify as svr_monster_killed;
for (i = 0; i < m_FixedData.m_ulMonsterWanted; i++)
{
MONSTER_WANTED mw = m_FixedData.m_MonsterWanted[i];
if (mw.m_ulMonsterTemplId == pKilled.monster_id)
{
pEntry.m_wMonsterNum[i] = pKilled.monster_num;
if (pKilled.dps > 0 && pKilled.dph > 0)
{
pTask.ShowPunchBagMessage(true,pKilled.dps >= mw.m_iDPS && pKilled.dph >= mw.m_iDPH,pKilled.monster_id,pKilled.dps,pKilled.dph);
}
break;
}
}
break;
case TaskTemplConstants.TASK_SVR_NOTIFY_NEW:
var svr_new_task = pNotify as svr_new_task;
if (svr_new_task.valid_size((int)sz) ) break;
pLst = pTask.GetActiveTaskList();
svr_new_task.get_data(
ref ulTime,
ref ulCaptainTask,
ref sub_tags
);
GetTaskTemplMan().RemoveActiveStorageTask(pStorage, m_FixedData.m_ID);
if (sub_tags.sub_task > 0)
{
pSub = GetConstSubById(sub_tags.sub_task);
if (pSub == null) break;
}
else
pSub = null;
if (CheckBudget(pLst) > 0) break;
DeliverTask(
pTask,
pLst,
null,
ulCaptainTask,
pTask.GetTaskMask(),
ulTime,
pSub,
ref sub_tags,
new TaskGlobalData(),
0);
if (m_FixedData.m_lAvailFrequency != (int)TaskAwardFreq.enumTAFNormal &&
!m_FixedData.m_bAccountTaskLimit && !m_FixedData.m_bRoleTaskLimit)
{
// static_cast<TaskFinishTimeList*>(pTask->GetFinishedTimeList())->AddOrUpdate(
// m_ID,
// ulTime);
var TaskFinishTimeList = new TaskFinishTimeList();
TaskFinishTimeList.ReadFromBuffer(pTask.GetFinishedTimeList());
TaskFinishTimeList.AddOrUpdate(m_FixedData.m_ID, ulTime);
}
// TODO: Log new task acceptance
// if (CanShowPrompt() && !m_bDisplayInTitleTaskUI) TaskInterface::ShowTaskMessage(m_ID, TASK_MSG_NEW);
// ׷ٷʱ
if (!m_FixedData.m_bHidden && !m_FixedData.m_bDisplayInTitleTaskUI)
// TaskInterface::TraceTask(m_ID);
// TODO: Log task trace
// pTask.TraceTask(m_FixedData.m_ID);
if (m_FixedData.m_bDisplayInTitleTaskUI)
// TODO: Update title UI
// TaskInterface::UpdateTitleUI(m_ID);
if ((m_enumMethod == (uint)TaskCompletionMethod.enumTMSimpleClientTask) && m_FixedData.m_uiEmotion > 0)
// TODO: Pop emotion UI
// TaskInterface::PopEmotionUI(m_ID,m_uiEmotion,true);
pTask.OnNewTask((int)m_FixedData.m_ID);
break;
case TaskTemplConstants.TASK_SVR_NOTIFY_COMPLETE:
var svr_task_complete = pNotify as svr_task_complete;
if (svr_task_complete.valid_size((int)sz)) break;
svr_task_complete.get_data(
ref ulTime,
ref sub_tags
);
pEntry.m_uState = (char)svr_task_complete.sub_tags.state;
if (!pEntry.IsSuccess())
{
#if TASK_TEMPL_EDITOR
RecursiveCheckPunchMonster(this);
#endif
}
// TODO: Log task completion
// if (CanShowPrompt() && !m_bDisplayInTitleTaskUI) TaskInterface::ShowTaskMessage(
// m_ID,
// (pEntry->IsSuccess() && !pEntry->IsGiveUp()) ? TASK_MSG_SUCCESS : TASK_MSG_FAIL);
RecursiveAward(
pTask,
pTask.GetActiveTaskList(),
pEntry,
ulTime,
-1,
ref sub_tags);
pTask.UpdateConfirmTasksMap();
// TODO: Show task completion trace
// pTask.UpdateTaskEmotionAction(m_FixedData.m_ID);
if ((m_enumMethod == (uint)TaskCompletionMethod.enumTMSimpleClientTask)
&& m_FixedData.m_uiEmotion > 0)
// TODO: Pop emotion UI
// PopEmotionUI(m_ID,m_uiEmotion,false);
if (m_FixedData.m_bDisplayInTitleTaskUI)
// TODO: Update title UI
// UpdateTitleUI(m_ID);
pTask.OnCompleteTask((int)m_FixedData.m_ID);
break;
case TaskTemplConstants.TASK_SVR_NOTIFY_GIVE_UP:
pLst = pTask.GetActiveTaskList();
pLst.ClearTask(pTask, pEntry, false);
// TODO: Log task give up
// if (m_bDisplayInTitleTaskUI) TaskInterface::UpdateTitleUI(m_ID);
// if ((m_enumMethod == enumTMSimpleClientTask) && m_uiEmotion)
// TaskInterface::PopEmotionUI(m_ID,m_uiEmotion,false);
pTask.OnGiveupTask((int)m_FixedData.m_ID);
break;
case TaskTemplConstants.TASK_SVR_NOTIFY_FINISHED:
pEntry.SetFinished();
break;
case TaskTemplConstants.TASK_SVR_NOTIFY_DIS_GLOBAL_VAL:
// DisplayTaskCharInfo(pTask, pEntry);
break;
default:
// assert(false);
break;
}
// Update task UI after processing server notification
pTask.UpdateTaskUI(pNotify.task, pNotify.reason);
}
#else
// void NotifyClient (TaskInterface* pTask, const ActiveTaskEntry* pEntry, unsigned char uReason, unsigned long ulCurTime, unsigned long ulParam = 0, int dps = 0, int dph = 0) const;
// bool CheckGlobalRequired (TaskInterface* pTask, unsigned long ulSubTaskId, const TaskPreservedData* pPreserve, const TaskGlobalData* pGlobal, unsigned short reason) const;
@@ -1047,5 +1247,576 @@ namespace BrewMonster.Scripts.Task
// 受限于当前 TaskInterface 未暴露获取接口,暂时视为通过 // English: Interface lacks API; treat as pass for now
return 0u;
}
public void ClearValidCount() { m_uValidCount = 0; }
public ATaskTemplMan GetTaskTemplMan()
{
return EC_Game.GetTaskTemplateMan();
}
public ATaskTempl GetConstSubById(uint ulId)
{
ATaskTempl pChild = m_pFirstChild;
while (pChild != null)
{
if (pChild.m_FixedData.m_ID == ulId) return pChild;
pChild = pChild.m_pNextSibling;
}
return null;
}
public ActiveTaskEntry DeliverTask(
TaskInterface pTask,
ActiveTaskList pList,
ActiveTaskEntry pEntry,
uint ulCaptainTask,
uint ulMask,
uint ulCurTime,
ATaskTempl pSubTempl,
ref task_sub_tags pSubTag,
TaskGlobalData pGlobal,
byte uParentIndex)
{
// TODO: implement full logic when ActiveTaskList/ActiveTaskEntry and TaskInterface APIs are available
return null;
/*ActiveTaskEntry* aEntries = pList->m_TaskEntries;
if (!pEntry) pEntry = aEntries + pList->m_uTaskCount;
else if (pEntry->m_ID != 0) // entryռãҪŲһλ;
pList->RealignTask(pEntry, 1);
unsigned char uIndex = static_cast<unsigned char>(pEntry - aEntries);
pEntry->m_ID = static_cast<unsigned short>(m_ID);
pEntry->m_ulTemplAddr = reinterpret_cast<unsigned long>(this);
pEntry->m_ParentIndex = uParentIndex;
pEntry->m_PrevSblIndex = 0xff;
pEntry->m_NextSblIndex = 0xff;
pEntry->m_ChildIndex = 0xff;
pEntry->m_uState = 0;
pEntry->m_ulTaskTime = ulCurTime;
#ifndef _TASK_CLIENT
// ΪPQҪʱ¼m_ulTaskTime
if (m_bPQTask)
{
pEntry->m_ulTaskTime = PublicQuestInterface::GetCurTaskStamp(m_ID);
}
#endif
if (ulCaptainTask)
{
pEntry->m_ulCapTemplAddr = reinterpret_cast<unsigned long>(GetTaskTemplMan()->GetTopTaskByID(ulCaptainTask));
if (pEntry->m_ulCapTemplAddr) pEntry->m_uCapTaskId = static_cast<unsigned short>(ulCaptainTask);
else
{
pEntry->m_uCapTaskId = 0;
char log[1024];
sprintf(log, "DeliverTask, Cant Find CapTask = %d", ulCaptainTask);
TaskInterface::WriteLog(pTask->GetPlayerId(), m_ID, 0, log);
}
}
else
{
pEntry->m_uCapTaskId = 0;
pEntry->m_ulCapTemplAddr = 0;
}
pEntry->SetSuccess(); // Later will check whether truly succeed
memset(pEntry->m_BufData, 0, sizeof(pEntry->m_BufData));
#ifndef _TASK_CLIENT
// ΪPQPQҪʱ¼m_ulTaskTime
if (m_bPQTask)
{
ulCurTime = PublicQuestInterface::GetCurTaskStamp(m_ID);
}
else if (m_enumMethod == enumTMReachTreasureZone)
{
// رλúͲرͼ½λõindex
unsigned short uZonesSum = m_ucZonesNumX * m_ucZonesNumZ;
unsigned short uTreasureLocIndex = pTask->RandNormal(1,uZonesSum);
char sTreasureLocMinX = (uTreasureLocIndex % m_ucZonesNumX - 1);
char sTreasureLocMinZ = (uTreasureLocIndex / m_ucZonesNumX);
// IJرͼλãʹرλòܴڲرͼıԵ
int sMapMinX = pTask->RandNormal(sTreasureLocMinX,sTreasureLocMinX + TASK_TREASURE_MAP_SIDE_MULTIPLE - 3) - TASK_TREASURE_MAP_SIDE_MULTIPLE + 2;
int sMapMinZ = pTask->RandNormal(sTreasureLocMinZ,sTreasureLocMinZ + TASK_TREASURE_MAP_SIDE_MULTIPLE - 3) - TASK_TREASURE_MAP_SIDE_MULTIPLE + 2;
// ѽб
pEntry->m_iUsefulData1 = uTreasureLocIndex;
pEntry->m_iUsefulData1 |= (sMapMinX << 16) & 0x00FF0000;
pEntry->m_iUsefulData1 |= (sMapMinZ << 24) & 0xFF000000;
}
ulMask |= m_ulMask;
#else
if (m_enumMethod == enumTMReachTreasureZone)
{
task_notify_base notify;
notify.reason = TASK_CLT_NOTIFY_REQUEST_TREASURE_INDEX;
notify.task = static_cast<unsigned short>(m_ID);
pTask->NotifyServer(&notify, sizeof(notify));
}
#endif
pList->m_uTaskCount++;
if (!m_pParent)
{
if (m_bHidden) pList->m_uTopHideTaskCount++;
else if (m_bDisplayInTitleTaskUI) pList->m_uTitleTaskCount++;
else pList->m_uTopShowTaskCount++;
pList->m_uUsedCount += m_uDepth;
#ifndef _TASK_CLIENT
if (pGlobal)
{
pGlobal->AddRevNum();
pGlobal->m_ulRcvUpdateTime = ulCurTime;
TaskUpdateGlobalData(m_ID, pGlobal->buf);
}
#endif
}
if (uParentIndex != 0xff)
{
ActiveTaskEntry& ParentEntry = aEntries[uParentIndex];
if (ParentEntry.m_ChildIndex == 0xff) ParentEntry.m_ChildIndex = uIndex;
else
{
unsigned char uChildEntry = ParentEntry.m_ChildIndex;
while (aEntries[uChildEntry].m_NextSblIndex != 0xff)
uChildEntry = aEntries[uChildEntry].m_NextSblIndex;
aEntries[uChildEntry].m_NextSblIndex = uIndex;
pEntry->m_PrevSblIndex = uChildEntry;
}
}
#ifndef _TASK_CLIENT
if (!m_pParent)
DeliverGivenItems(pTask);
#endif
pEntry++;
if (pSubTempl)
{
return pSubTempl->DeliverTask(
pTask,
pList,
pEntry,
0,
ulMask,
ulCurTime,
NULL,
pSubTag,
NULL,
uIndex);
}
else if (m_bRandOne)
{
#ifdef _TASK_CLIENT
if (pSubTag->cur_index < pSubTag->sz)
{
pSubTempl = GetSubByIndex(pSubTag->tags[pSubTag->cur_index]);
pSubTag->cur_index++;
if (pSubTempl)
{
return pSubTempl->DeliverTask(
pTask,
pList,
pEntry,
0,
ulMask,
ulCurTime,
NULL,
pSubTag,
NULL,
uIndex);
}
}
#else
int nSel;
pSubTempl = RandOneChild(pTask, nSel);
if (pSubTempl)
{
if (pSubTag->sz < MAX_SUB_TAGS)
pSubTag->tags[pSubTag->sz++] = static_cast<unsigned char>(nSel);
return pSubTempl->DeliverTask(
pTask,
pList,
pEntry,
0,
ulMask,
ulCurTime,
NULL,
pSubTag,
NULL,
uIndex);
}
#endif
}
else
{
const ATaskTempl* pChild = m_pFirstChild;
while (pChild)
{
pEntry = pChild->DeliverTask(
pTask,
pList,
pEntry,
0,
ulMask,
ulCurTime,
NULL,
pSubTag,
NULL,
uIndex);
if (m_bExeChildInOrder) return pEntry;
pChild = pChild->m_pNextSibling;
}
}
return pEntry;*/
}
void RecursiveAward(
TaskInterface pTask,
ActiveTaskList pList,
ActiveTaskEntry pEntry,
uint ulCurtime,
int nChoice,
ref task_sub_tags pSubTag)
{
// TODO : implement full logic when ActiveTaskList/ActiveTaskEntry and TaskInterface APIs are available
/*{
char log[1024];
sprintf(log, "RecursiveAward: state = 0x%x", pEntry->m_uState);
TaskInterface::WriteLog(pTask->GetPlayerId(), m_ID, 1, log);
}
ActiveTaskEntry* aEntries = pList->m_TaskEntries;
// ʧܲȡƷ
bool bFailedTaskDoNotTakeItem = !pEntry->IsSuccess() && m_bNotClearItemWhenFailed && m_bClearAcquired;
//
pList->ClearChildrenOf(pTask, pEntry, !bFailedTaskDoNotTakeItem);
if (!pEntry->m_ulTemplAddr) return; // must check it
if (!m_pParent && m_bNeedRecord)
{
static_cast<FinishedTaskList*>(pTask->GetFinishedTaskList())->AddOneTask(
m_ID,
pEntry->IsSuccess());
}
// ˺޴ɴ
if (!m_pParent && m_bAccountTaskLimit)
{
// ʱжǷɴ
CheckDeliverTime(pTask, ulCurtime);
// ûйѡʧܵʱ򲻼¼ɴ߹ѡʧܵʱ򲻼¼ɴɹʱ
if (!m_bNotIncCntWhenFailed || (m_bNotIncCntWhenFailed && pEntry->IsSuccess()))
static_cast<TaskFinishCountList*>(pTask->GetFinishedCntList())->AddOrUpdate(m_ID,ulCurtime);
}
// ɫ޴ɴ
else if (!m_pParent && m_bRoleTaskLimit)
{
// ʱжǷɴ
CheckDeliverTime(pTask, ulCurtime);
// ûйѡʧܵʱ򲻼¼ɴ߹ѡʧܵʱ򲻼¼ɴɹʱ
if (!m_bNotIncCntWhenFailed || (m_bNotIncCntWhenFailed && pEntry->IsSuccess())) {
// FinishedTaskListɴ
static_cast<FinishedTaskList*>(pTask->GetFinishedTaskList())->AddForFinishCount(m_ID,pEntry->IsSuccess());
// TaskFinishTimeListʱ
static_cast<TaskFinishTimeList*>(pTask->GetFinishedTimeList())->AddOrUpdate(m_ID, ulCurtime);
}
}
#ifndef _TASK_CLIENT
// Ʒ
AWARD_DATA ad;
CalcAwardData(
pTask,
&ad,
pEntry,
pEntry->m_ulTaskTime,
ulCurtime);
unsigned long ulRet = DeliverByAwardData(pTask, pList, pEntry, &ad, ulCurtime, nChoice);
if (ulRet)
{
char log[1024];
sprintf(log, "RecursiveAward, ret = %d", ulRet);
TaskInterface::WriteLog(pTask->GetPlayerId(), m_ID, 0, log);
}
// ȥõĻԤȸƷڷƷִ
if (m_bClearAcquired)
{
if (!bFailedTaskDoNotTakeItem)
RemoveAcquiredItem(pTask, false, pEntry->IsSuccess());
}
else if (!pEntry->IsSuccess())
TakeAwayGivenItems(pTask);
#endif
pEntry->m_ulTemplAddr = 0;
pEntry->m_ID = 0;
if (pList->m_uTaskCount)
pList->m_uTaskCount--;
else
TaskInterface::WriteLog(pTask->GetPlayerId(), m_ID, 0, "Award, TaskCount == 0");
if (pEntry->m_ParentIndex != 0xff)
{
ActiveTaskEntry& ParentEntry = aEntries[pEntry->m_ParentIndex];
if (pEntry->m_PrevSblIndex != 0xff)
aEntries[pEntry->m_PrevSblIndex].m_NextSblIndex = pEntry->m_NextSblIndex;
else
ParentEntry.m_ChildIndex = pEntry->m_NextSblIndex;
if (pEntry->m_NextSblIndex != 0xff)
aEntries[pEntry->m_NextSblIndex].m_PrevSblIndex = pEntry->m_PrevSblIndex;
if (!pEntry->IsSuccess() && m_bParentAlsoFail)
{
pList->RealignTask(pEntry, 0);
ParentEntry.ClearSuccess();
ParentEntry.SetFinished();
m_pParent->RecursiveAward(pTask, pList, &ParentEntry, ulCurtime, -1, pSubTag);
}
else if (pEntry->IsSuccess() && m_bParentAlsoSucc)
{
pList->RealignTask(pEntry, 0);
ParentEntry.SetFinished();
pList->ClearChildrenOf(pTask, &ParentEntry);
if (m_pParent->m_enumFinishType == enumTFTDirect)
m_pParent->RecursiveAward(pTask, pList, &ParentEntry, ulCurtime, -1, pSubTag);
#ifdef _TASK_CLIENT
else if (!m_pParent->m_bHidden && !m_pParent->m_bDisplayInTitleTaskUI)
TaskInterface::TraceTask(m_pParent->m_ID);
#endif
}
else if (m_pParent->m_bExeChildInOrder && m_pNextSibling)
{
if (ParentEntry.m_ChildIndex != 0xff || pList->GetEntry(m_pNextSibling->m_ID)) // Ϊ0xff
pList->RealignTask(pEntry, 0);
else
{
m_pNextSibling->DeliverTask(
pTask,
pList,
pEntry,
0,
*pTask->GetTaskMask(),
ulCurtime,
NULL,
pSubTag,
NULL,
pEntry->m_ParentIndex);
#ifdef _TASK_CLIENT
// ѡһһ˳ִ
// ǰ׷ٸʱѾ
// ڵڶԺ˳ִе
if (!m_pParent->m_bHidden && !m_pParent->m_bDisplayInTitleTaskUI)
TaskInterface::TraceTask(m_pNextSibling->m_ID);
#endif
}
}
else if (ParentEntry.m_ChildIndex == 0xff) // ʱΪ
{
pList->RealignTask(pEntry, 0);
ParentEntry.SetFinished();
if (m_pParent->m_enumFinishType == enumTFTDirect)
m_pParent->RecursiveAward(pTask, pList, &ParentEntry, ulCurtime, -1, pSubTag);
#ifdef _TASK_CLIENT
else if (!m_pParent->m_bHidden && !m_pParent->m_bDisplayInTitleTaskUI)
TaskInterface::TraceTask(m_pParent->m_ID);
#endif
}
else
pList->RealignTask(pEntry, 0);
}
else // Root Node
{
pList->RealignTask(pEntry, 0);
if (pList->m_uUsedCount >= m_uDepth)
pList->m_uUsedCount -= m_uDepth;
else
{
char log[1024];
sprintf(log, "Award, Used = %d", pList->m_uUsedCount);
TaskInterface::WriteLog(pTask->GetPlayerId(), m_ID, 0, log);
pList->m_uUsedCount = 0;
}
if (m_bHidden)
{
if (pList->m_uTopHideTaskCount)
pList->m_uTopHideTaskCount--;
}
else if(m_bDisplayInTitleTaskUI)
{
if (pList->m_uTitleTaskCount)
pList->m_uTitleTaskCount--;
}
else
{
if (pList->m_uTopShowTaskCount)
pList->m_uTopShowTaskCount--;
}
}*/
}
public void TakeAwayGivenItems(TaskInterface pTask)
{
uint ulCount;
for (int i = 0; i < m_FixedData.m_ulGivenItems; i++)
{
ITEM_WANTED wi = m_FixedData.m_GivenItems[i];
if (wi.m_bCommonItem)
{
ulCount = (uint)pTask.GetCommonItemCount(wi.m_ulItemTemplId);
if (ulCount > wi.m_ulItemNum) ulCount = wi.m_ulItemNum;
if (ulCount > 0) pTask.TakeAwayCommonItem(wi.m_ulItemTemplId, ulCount);
}
else
{
ulCount = (uint)pTask.GetTaskItemCount(wi.m_ulItemTemplId);
if (ulCount > 0) pTask.TakeAwayTaskItem(wi.m_ulItemTemplId, ulCount);
}
}
}
public void RemoveAcquiredItem(TaskInterface pTask, bool bClearTask, bool bSuccess)
{
var m_enumMethod = m_FixedData.m_enumMethod;
var m_ulItemsWanted = m_FixedData.m_ulItemsWanted;
var m_ItemsWanted = m_FixedData.m_ItemsWanted;
var m_ulGoldWanted = m_FixedData.m_ulGoldWanted;
var m_iFactionContribWanted = m_FixedData.m_iFactionContribWanted;
var m_iFactionExpContribWanted = m_FixedData.m_iFactionExpContribWanted;
var m_ulMonsterWanted = m_FixedData.m_ulMonsterWanted;
var m_MonsterWanted = m_FixedData.m_MonsterWanted;
var m_ulPlayerWanted = m_FixedData.m_ulPlayerWanted;
var m_PlayerWanted = m_FixedData.m_PlayerWanted;
if (m_enumMethod == (uint)TaskCompletionMethod.enumTMCollectNumArticle)
{
for (int i = 0; i < m_ulItemsWanted; i++)
{
ITEM_WANTED wi = m_ItemsWanted[i];
uint ulCount;
if (wi.m_bCommonItem)
{
if (bClearTask) continue;
ulCount = (uint)pTask.GetCommonItemCount(wi.m_ulItemTemplId);
if (ulCount == 0) continue;
if (wi.m_ulItemNum > 0 && ulCount > wi.m_ulItemNum) ulCount = wi.m_ulItemNum;
pTask.TakeAwayCommonItem(wi.m_ulItemTemplId, ulCount);
}
else
{
ulCount = (uint)pTask.GetTaskItemCount(wi.m_ulItemTemplId);
if (ulCount > 0) pTask.TakeAwayTaskItem(wi.m_ulItemTemplId, ulCount);
}
}
// ɹǮ
if (m_ulGoldWanted > 0 && !bClearTask && bSuccess)
{
uint ulGold = pTask.GetGoldNum();
if (ulGold > m_ulGoldWanted) ulGold = m_ulGoldWanted;
pTask.TakeAwayGold(ulGold);
}
//ɹѰɹ׶
if (m_iFactionContribWanted > 0 && !bClearTask && bSuccess)
{
int iContrib = pTask.GetFactionConsumeContrib();
if (iContrib > m_iFactionContribWanted) iContrib = m_iFactionContribWanted;
pTask.TakeAwayFactionConsumeContrib(iContrib);
}
//ɹѰɾ
if (m_iFactionExpContribWanted > 0 && !bClearTask && bSuccess)
{
int iContrib = pTask.GetFactionExpContrib();
if (iContrib > m_iFactionExpContribWanted) iContrib = m_iFactionExpContribWanted;
pTask.TakeAwayFactionExpContrib(iContrib);
}
}
else if (m_enumMethod == (uint)TaskCompletionMethod.enumTMKillNumMonster)
{
for (int i = 0; i < m_ulMonsterWanted; i++)
{
// const MONSTER_WANTED& mw = m_MonsterWanted[i];
MONSTER_WANTED mw = m_MonsterWanted[i];
if (mw.m_ulDropItemId == 0) continue;
uint ulCount;
if (mw.m_bDropCmnItem)
{
ulCount = (uint)pTask.GetCommonItemCount(mw.m_ulDropItemId);
if (mw.m_ulDropItemCount > 0 && ulCount > mw.m_ulDropItemCount) ulCount = mw.m_ulDropItemCount;
if (ulCount > 0) pTask.TakeAwayCommonItem(mw.m_ulDropItemId, ulCount);
}
else
{
ulCount = (uint)pTask.GetTaskItemCount(mw.m_ulDropItemId);
if (ulCount > 0) pTask.TakeAwayTaskItem(mw.m_ulDropItemId, ulCount);
}
}
}
else if (m_enumMethod == (uint)TaskCompletionMethod.enumTMKillPlayer)
{
for (uint i = 0; i < m_ulPlayerWanted; ++i)
{
// const PLAYER_WANTED& pw = m_PlayerWanted[i];
var pw = m_PlayerWanted[i];
if (pw.m_ulDropItemId == 0) continue;
uint ulCount;
if (pw.m_bDropCmnItem)
{
ulCount = (uint)pTask.GetCommonItemCount(pw.m_ulDropItemId);
if (pw.m_ulDropItemCount > 0 && ulCount > pw.m_ulDropItemCount) ulCount = pw.m_ulDropItemCount;
if (ulCount > 0) pTask.TakeAwayCommonItem(pw.m_ulDropItemId, ulCount);
}
else
{
ulCount = (uint)pTask.GetTaskItemCount(pw.m_ulDropItemId);
if (ulCount>0) pTask.TakeAwayTaskItem(pw.m_ulDropItemId, ulCount);
}
}
}
}
}
}
@@ -0,0 +1,274 @@
using System;
using System.Runtime.InteropServices;
namespace BrewMonster.Scripts.Task
{
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct task_sub_tags
{
// private const int MAX_SUB_TAGS = 32;
// union
// {
// unsigned short sub_task;
// unsigned char state;
// };
// IMPORTANT: union
public ushort sub_task;
public byte state;
public byte sz;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.MAX_SUB_TAGS)]
public byte[] tags;
public byte cur_index; // for temporary use, dont take into account
public int get_size() { return sz + 3; }
public bool valid_size(int _sz)
{
if (_sz < 3) return false;
return get_size() == _sz;
}
};
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class task_notify_base
{
public byte reason;
public ushort task;
};
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct cmd_task_notify
{
public uint size;
public byte placeholder; // Task data ...
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class svr_monster_killed : task_notify_base
{
public uint monster_id;
public ushort monster_num;
public int dps;
public int dph;
};
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public class svr_player_killed : task_notify_base
{
public ushort index;
public ushort player_num;
};
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct StorageTaskList
{
// unsigned short m_Storages[TASK_STORAGE_COUNT][TASK_STORAGE_LEN];
// NOTE: 2D array flattened
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.TASK_STORAGE_COUNT * TaskTemplConstants.TASK_STORAGE_LEN)]
public ushort[] m_Storages;
// union {
// unsigned short m_StoragesTaskSetCount[TASK_STORAGE_COUNT];
// unsigned short m_StoragesRefreshCount[TASK_STORAGE_COUNT];
// };
// NOTE: union
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.TASK_STORAGE_COUNT)]
public ushort[] m_StoragesTaskSetCount;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.TASK_STORAGE_COUNT)]
public ushort[] m_StoragesRefreshCount;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.TASK_STORAGE_COUNT)]
public uint[] m_StoragesRefreshTime;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.TASK_STORAGE_COUNT)]
public byte[] m_StoragesReceivePerDay;
public void RemoveAll()
{
for (int i = 0; i < TaskTemplConstants.TASK_STORAGE_COUNT; i++)
{
for (int j = 0; j < TaskTemplConstants.TASK_STORAGE_LEN; j++)
{
m_Storages[i * TaskTemplConstants.TASK_STORAGE_LEN + j] = 0;
}
m_StoragesTaskSetCount[i] = 0;
m_StoragesRefreshCount[i] = 0;
m_StoragesRefreshTime[i] = 0;
m_StoragesReceivePerDay[i] = 0;
}
}
public void ReadByte(byte[] data)
{
int offset = 0;
for (int i=0; i < TaskTemplConstants.TASK_STORAGE_COUNT; i++)
{
for (int j=0; j < TaskTemplConstants.TASK_STORAGE_LEN; j++)
{
m_Storages[i * TaskTemplConstants.TASK_STORAGE_LEN + j] = BitConverter.ToUInt16(data, (i * TaskTemplConstants.TASK_STORAGE_LEN + j) * 2);
}
}
offset += TaskTemplConstants.TASK_STORAGE_COUNT * TaskTemplConstants.TASK_STORAGE_LEN * 2;
// union
for (int i=0; i < TaskTemplConstants.TASK_STORAGE_COUNT; i++)
{
m_StoragesTaskSetCount[i] = BitConverter.ToUInt16(data, offset + i * 2);
m_StoragesRefreshCount[i] = BitConverter.ToUInt16(data, offset + i * 2);
}
offset += TaskTemplConstants.TASK_STORAGE_COUNT * 2;
for (int i=0; i < TaskTemplConstants.TASK_STORAGE_COUNT; i++)
{
m_StoragesRefreshTime[i] = BitConverter.ToUInt32(data, offset + i * 4);
}
offset += TaskTemplConstants.TASK_STORAGE_COUNT * 4;
for (int i=0; i < TaskTemplConstants.TASK_STORAGE_COUNT; i++)
{
m_StoragesReceivePerDay[i] = data[offset + i];
}
}
}
public class svr_new_task : task_notify_base
{
public uint cur_time;
public uint cap_task;
public task_sub_tags sub_tags;
public void set_data(
uint _cur_time,
uint _cap_task,
task_sub_tags _sub_tags)
{
cur_time = _cur_time;
cap_task = _cap_task;
// memcpy(&sub_tags, &_sub_tags, _sub_tags.get_size());
sub_tags = _sub_tags;
}
public void get_data(
ref uint _cur_time,
ref uint _cap_task,
ref task_sub_tags _sub_tags)
{
_cur_time = cur_time;
_cap_task = cap_task;
// memcpy(&_sub_tags, &sub_tags, sub_tags.get_size());
_sub_tags = sub_tags;
}
// inline size_t get_size() const { return sizeof(task_notify_base) + 8 + sub_tags.get_size(); }
public int get_size() { return Marshal.SizeOf<task_notify_base>() + 8 + sub_tags.get_size(); }
public bool valid_size(int sz)
{
int base_sz = Marshal.SizeOf<task_notify_base>() + 8;
if (sz <= base_sz) return false;
return sub_tags.valid_size(sz - base_sz);
}
}
public class svr_treasure_map : task_notify_base
{
public int treasure_index;
}
struct tm {
int tm_sec; /* seconds after the minute [0-60] */
int tm_min; /* minutes after the hour [0-59] */
int tm_hour; /* hours since midnight [0-23] */
int tm_mday; /* day of the month [1-31] */
int tm_mon; /* months since January [0-11] */
int tm_year; /* years since 1900 */
int tm_wday; /* days since Sunday [0-6] */
int tm_yday; /* days since January 1 [0-365] */
int tm_isdst; /* Daylight Savings Time flag */
long tm_gmtoff; /* offset from UTC in seconds */
byte tm_zone; /* timezone abbreviation */
};
[StructLayout(LayoutKind.Explicit)]
public struct TaskGlobalData
{
[FieldOffset(0)]
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.TASK_GLOBAL_DATA_SIZE)]
public byte[] buf;
[FieldOffset(0)]
public ulong m_ulReceiverNum;
[FieldOffset(8)]
public ulong m_ulRcvUpdateTime;
void AddRevNum() { m_ulReceiverNum++; }
void CheckRcvUpdateTime(uint ulCurTime, int nFrequency)
{
// TODO: implement time-based receiver number reset logic
// if (nFrequency == TaskCompletionMethod.enumTAFNormal || m_ulRcvUpdateTime == 0)
// return;
//
// tm tmCur = *localtime((time_t*)&ulCurTime);
// tm tmRcv = *localtime((time_t*)&m_ulRcvUpdateTime);
//
// if (nFrequency == enumTAFEachDay)
// {
// if (tmCur.tm_year != tmRcv.tm_year || tmCur.tm_yday != tmRcv.tm_yday)
// m_ulReceiverNum = 0;
// }
// else if (nFrequency == enumTAFEachWeek)
// {
// if (!_is_same_week(&tmCur, &tmRcv, ulCurTime, m_ulRcvUpdateTime))
// m_ulReceiverNum = 0;
// }
// else if (nFrequency == enumTAFEachMonth)
// {
// if (tmCur.tm_year != tmRcv.tm_year || tmCur.tm_mon != tmRcv.tm_mon)
// m_ulReceiverNum = 0;
// }
// else if (nFrequency == enumTAFEachYear)
// {
// if (tmCur.tm_year != tmRcv.tm_year)
// m_ulReceiverNum = 0;
// }
}
}
public class svr_task_complete : task_notify_base
{
public uint cur_time;
public task_sub_tags sub_tags;
public void set_data(
uint _cur_time,
task_sub_tags _sub_tags
)
{
cur_time = _cur_time;
// memcpy(&sub_tags, &_sub_tags, _sub_tags.get_size());
sub_tags = _sub_tags;
}
public void get_data(
ref uint _cur_time,
ref task_sub_tags _sub_tags)
{
_cur_time = cur_time;
// memcpy(&_sub_tags, &sub_tags, sub_tags.get_size());
_sub_tags = sub_tags;
}
public int get_size() { return Marshal.SizeOf<task_notify_base>() + 4 + sub_tags.get_size(); }
public bool valid_size(int sz)
{
int base_sz = Marshal.SizeOf<task_notify_base>() + 4;
if (sz <= base_sz) return false;
return sub_tags.valid_size(sz - base_sz);
}
}
}
@@ -0,0 +1,3 @@
fileFormatVersion: 2
guid: a70b3653041c46daa32cee68efb8bfec
timeCreated: 1763639774
+131 -2
View File
@@ -3,6 +3,7 @@ using System.IO;
using System.Runtime.InteropServices;
using System;
using BrewMonster;
using CSNetwork.GPDataType;
using ModelRenderer.Scripts.Common;
using PerfectWorld.Scripts.Task;
using UnityEngine.UIElements;
@@ -52,6 +53,63 @@ namespace BrewMonster.Scripts.Task
// Race-occupation mapping array
public static readonly uint[] _race_occ_map = new uint[MAX_OCCUPATIONS];
/*
* Server Notifications
*/
// 新任务发放 // New task issued
public const int TASK_SVR_NOTIFY_NEW = 1;
// 任务完毕 // Task completed
public const int TASK_SVR_NOTIFY_COMPLETE = 2;
// 任务放弃 // Task abandoned
public const int TASK_SVR_NOTIFY_GIVE_UP = 3;
// 杀怪数量 // Monster kill count
public const int TASK_SVR_NOTIFY_MONSTER_KILLED = 4;
// 处于得到奖励状态 // In reward receiving state
public const int TASK_SVR_NOTIFY_FINISHED = 5;
// 错误码 // Error code
public const int TASK_SVR_NOTIFY_ERROR_CODE = 6;
// 遗忘生活技能 // Forget life skill
public const int TASK_SVR_NOTIFY_FORGET_SKILL = 7;
// 动态任务时间标记 // Dynamic task time mark
public const int TASK_SVR_NOTIFY_DYN_TIME_MARK = 8;
// 动态任务数据 // Dynamic task data
public const int TASK_SVR_NOTIFY_DYN_DATA = 9;
// 特殊奖励信息 // Special reward info
public const int TASK_SVR_NOTIFY_SPECIAL_AWARD = 10;
// 仓库数据 // Storage data
public const int TASK_SVR_NOTIFY_STORAGE = 11;
// 显示全局变量 // Display global variables
public const int TASK_SVR_NOTIFY_DIS_GLOBAL_VAL = 12;
// 藏宝位置 // Treasure location
public const int TASK_SVR_NOTIFY_TREASURE_MAP = 13;
// 设置任务列表上限 // Set task list limit
public const int TASK_SVR_NOTIFY_SET_TASK_LIMIT = 14;
// 杀人数量 // Player kill count
public const int TASK_SVR_NOTIFY_PLAYER_KILLED = 15;
public const int TASK_ENTRY_DATA_CUR_VER = 1;
public const int MAX_SUB_TAGS = 32;
public const int TASK_STORAGE_COUNT = 32;
public const int TASK_STORAGE_LEN = 10;
}
public enum DynTaskType
@@ -1228,6 +1286,77 @@ namespace BrewMonster.Scripts.Task
return $"Min({zvMin.x}, {zvMin.y}, {zvMin.z}) - Max({zvMax.x}, {zvMax.y}, {zvMax.z})";
}
}
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct TaskFinishTimeEntry
{
public ushort m_uTaskId;
public uint m_ulTimeMark;
};
[StructLayout(LayoutKind.Sequential, Pack = 1)]
public struct TaskFinishTimeList
{
public ushort m_uCount;
[MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.TASK_FINISH_TIME_MAX_LEN)]
public TaskFinishTimeEntry[] m_aList;
public void ReadFromBuffer(byte[] data)
{
int offset = 0;
m_uCount = BitConverter.ToUInt16(data, offset);
offset += sizeof(ushort);
m_aList = new TaskFinishTimeEntry[TaskInterfaceConstants.TASK_FINISH_TIME_MAX_LEN];
for (int i = 0; i < TaskInterfaceConstants.TASK_FINISH_TIME_MAX_LEN; i++)
{
m_aList[i].m_uTaskId = BitConverter.ToUInt16(data, offset);
offset += sizeof(ushort);
m_aList[i].m_ulTimeMark = BitConverter.ToUInt32(data, offset);
offset += sizeof(uint);
}
}
public uint Search(uint ulID)
{
for (int i = 0; i < m_uCount; i++)
if (m_aList[i].m_uTaskId == (ushort)ulID)
return m_aList[i].m_ulTimeMark;
return 0;
}
public void AddOrUpdate(uint ulID, uint ulTime){
for (int i = 0; i < m_uCount; i++)
{
if (m_aList[i].m_uTaskId == (ushort)ulID)
{
m_aList[i].m_ulTimeMark = ulTime;
return;
}
}
if (m_uCount >= TaskInterfaceConstants.TASK_FINISH_TIME_MAX_LEN)
return;
m_aList[m_uCount].m_uTaskId = (ushort)ulID;
m_aList[m_uCount].m_ulTimeMark = ulTime;
m_uCount++;
}
void RemoveAll()
{
m_uCount = 0;
for (int i = 0; i < TaskInterfaceConstants.TASK_FINISH_TIME_MAX_LEN; i++)
{
m_aList[i].m_uTaskId = 0;
m_aList[i].m_ulTimeMark = 0;
}
}
bool IsValid() { return m_uCount <= TaskInterfaceConstants.TASK_FINISH_TIME_MAX_LEN; }
};
/// <summary>
@@ -1243,7 +1372,7 @@ namespace BrewMonster.Scripts.Task
public ATaskTempl m_pPrevSibling;
public ATaskTempl m_pNextSibling;
public ATaskTempl m_pFirstChild;
private byte m_uDepth; // 深度 // Depth
public byte m_uDepth; // 深度 // Depth
const int MAX_TASK_NAME_LEN = 30;
const int TASK_AWARD_MAX_CHANGE_VALUE = 255;
@@ -1291,7 +1420,7 @@ namespace BrewMonster.Scripts.Task
public string GetDescription()
{
return ByteToStringUtils.UshortArrayToUnicodeString(m_pwstrDescript);
return ByteToStringUtils.UshortArrayToUnicodeString(m_pwstrDescript);
}
public bool CanFinishTask(TaskInterface pTask, ActiveTaskEntry pEntry, uint ulCurTime)
@@ -5,6 +5,7 @@ using BrewMonster.Managers;
using BrewMonster.Scripts.Managers;
using BrewMonster.Network;
using BrewMonster.Scripts.Task;
using BrewMonster.UI;
using CSNetwork.GPDataType;
using ModelRenderer.Scripts.GameData;
using NUnit.Framework;
@@ -18,7 +19,7 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
/// <summary>
/// This is DlgTask.cpp
/// </summary>
public class TaskWindow : MonoBehaviour
public class DlgTask : AUIDialog
{
#if UNITY_EDITOR
[ContextMenu("Generate Tasks")]
@@ -84,6 +85,7 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
protected int m_iType;
[SerializeField] protected TMP_Text _nameTaskText;
[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
@@ -244,20 +246,22 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
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;
if (idType < (int)ENUM_TASK_TYPE.enumTTDaily || idType >= (int)ENUM_TASK_TYPE.enumTTEnd) {
// ASSERT(false && "wrong task type");
return Color.white;
}
Color result;
if (!EC_Utility.STRING_TO_A3DCOLOR(GetStringFromTable(idType - (int)ENUM_TASK_TYPE.enumTTDaily + 3121), out result))
{
// 解析颜色失败,返回白色
// [English] Failed to parse color, return white
result = Color.white;
}
return result;
}
// static A3DCOLOR GetTaskColor(const ATaskTempl *pTempl);
// static ACString FormatTime(int nSec, const ACString& desc, int timeLimit);
private static string GetTaskNameWithColor(ATaskTempl pTempl)
private string GetTaskNameWithColor(ATaskTempl pTempl)
{
if (pTempl == null) return string.Empty;
var type = (ENUM_TASK_TYPE)pTempl.m_FixedData.m_ulType;
@@ -285,10 +289,21 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
return name;
}
private static UnityEngine.Color GetTaskColor(ATaskTempl pTempl)
private Color GetTaskColor(ATaskTempl pTempl)
{
// TODO: Map task type/flags to color. Default white.
return UnityEngine.Color.white;
// [English] Map task type/flags to color. Default white.
if (pTempl == null) return UnityEngine.Color.white;
int idType = (int)(ENUM_TASK_TYPE)pTempl.m_FixedData.m_ulType;
if (idType < (int)ENUM_TASK_TYPE.enumTTDaily || idType >= (int)ENUM_TASK_TYPE.enumTTEnd) {
// ASSERT(false && "wrong task type")
// [English] wrong task type
return UnityEngine.Color.white;
}
Color result;
EC_Utility.STRING_TO_A3DCOLOR(GetStringFromTable(idType - (int)ENUM_TASK_TYPE.enumTTDaily + 3121), out result);
return result;
// return UnityEngine.Color.white;
}
private static string A3DColorToString(UnityEngine.Color c)
@@ -327,6 +342,7 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
m_idLastTask = -2;
m_pTxt_Content.SetText("");
m_pTxt_QuestItem.SetText("");
_nameTaskText.SetText("");
m_pBtn_Abandon.interactable = false;
UpdateTaskConfirm(0, false);
Btn_TreasureMap.interactable = false;
@@ -383,8 +399,10 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
{
if( idTask != m_idLastTask )
{
_nameTaskText.SetText(EC_Utility.FormatForTextMeshPro(GetTaskNameWithColor(pTemp)));
//pTextDesc->SetText(FormatTaskText(pTemp->GetDescription(), pTextDesc->GetColor()));
pTextDesc.SetText(pTemp.GetDescription());
pTextDesc.SetText(EC_Utility.FormatForTextMeshPro(pTemp.GetDescription()));
m_idLastTask = idTask;
bLastTaskChanged = true;
}
@@ -493,7 +511,7 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
// Update description when the selected task changes
if (idTask != m_idLastTask)
{
if (pTextDesc != null) pTextDesc.SetText(pTemp.GetDescription());
if (pTextDesc != null) pTextDesc.SetText(EC_Utility.FormatForTextMeshPro(pTemp.GetDescription()));
m_idLastTask = idTask;
bLastTaskChanged = true;
}
@@ -714,9 +732,10 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
// UnityEngine.UI.ScrollRect scrollRect = pTextItem.GetComponentInParent<UnityEngine.UI.ScrollRect>();
// float oldNormPos = scrollRect != null ? scrollRect.verticalNormalizedPosition : 0f;
if (!string.Equals(strNewTextItem, pTextItem.text))
string formatted = EC_Utility.FormatForTextMeshPro(strNewTextItem ?? string.Empty);
if (!string.Equals(formatted, pTextItem.text))
{
pTextItem.text = strNewTextItem ?? string.Empty;
pTextItem.text = formatted;
// TODO: apply hint to a tooltip UI if available (strNewHintItem)
}
@@ -742,43 +761,41 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
var sb = new System.Text.StringBuilder();
int colCount = 0;
const int col = 3;
int cellSpace = 30;
int cellSpace = 50; // adjust as needed for spacing
void AppendWithSpacing(int stringId, string value)
{
var title = EC_Utility.FormatForTextMeshPro(GetStringFromTable(stringId));
var text = $"{title} {value}";
sb.Append( EC_Utility.FormatForTextMeshPro(text));
sb.Append(' ', Mathf.Abs(cellSpace - text.Length));
if ((++colCount) % col == 0) sb.Append("\n");
}
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");
AppendWithSpacing(3201 , award.m_ulGold.ToString());
}
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");
AppendWithSpacing(3202 , award.m_ulExp.ToString());
}
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");
AppendWithSpacing(3203 , award.m_ulSP.ToString());
}
if (award.m_ulRealmExp > 0)
{
sb.Append($"{GetStringFromTable(3207)} {award.m_ulRealmExp}");
if ((++colCount) % col == 0) sb.Append("\n");
AppendWithSpacing( 3207, award.m_ulRealmExp.ToString());
}
if (award.m_iForceContrib > 0)
{
sb.Append($"{GetStringFromTable(3205)} {award.m_iForceContrib}");
if ((++colCount) % col == 0) sb.Append("\n");
AppendWithSpacing(3205, award.m_iForceContrib.ToString());
}
if (award.m_iForceRepu > 0)
{
sb.Append($"{GetStringFromTable(3206)} {award.m_iForceRepu}");
if ((++colCount) % col == 0) sb.Append("\n");
AppendWithSpacing(3206, award.m_iForceRepu.ToString());
}
if (sb.Length > 0 && m_pTxt_BaseAward != null)
@@ -798,11 +815,11 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
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;
m_pTxt_BaseAward.text = EC_Utility.FormatForTextMeshPro(strAward);
}
else if (m_pTxt_BaseAward != null)
{
m_pTxt_BaseAward.text = GetStringFromTable(3204) ?? string.Empty;
m_pTxt_BaseAward.text = EC_Utility.FormatForTextMeshPro(GetStringFromTable(3204) ?? string.Empty);
m_pTxt_BaseAward.gameObject.SetActive(true);
}
}
@@ -910,53 +927,53 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
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(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)
private string GetStringFromTable(uint id)
{
// return AUIManager.GetStringFromTable(id);
return GetStringFromTable((int)id);
@@ -1242,7 +1259,8 @@ namespace BrewMonster.PerfectWorld.Scripts.Task.UI
m_pBtn_FinishTask.gameObject.SetActive(true);
// TODO: Enable/disable based on task readiness
// m_pBtn_FinishTask->Enable(pTask->IsTaskReadyToConfirm(idTask));
m_pBtn_FinishTask.interactable = pTask.IsTaskReadyToConfirm(idTask);
}
else m_pBtn_FinishTask.gameObject.SetActive(false);
}
+6 -6
View File
@@ -172,18 +172,18 @@ namespace BrewMonster.UI
//}
//s.Close();
//if (a_stricmp(GetStringFromTable(1), _AL("")) == 0) //1 默认字体
// m_StringTable[1] = _AL("方正细黑一简体");
//if (a_stricmp(GetStringFromTable(1), _AL("")) == 0) //1 Ĭ
// m_StringTable[1] = _AL("ϸһ");
//m_strDefaultFontName = GetStringFromTable(1);
//if (a_stricmp(GetStringFromTable(2), _AL("")) == 0) //2 默认字体大小
//if (a_stricmp(GetStringFromTable(2), _AL("")) == 0) //2 ĬС
// m_StringTable[2] = _AL("10");
//m_nDefaultFontSize = a_atoi(GetStringFromTable(2));
//if (a_stricmp(GetStringFromTable(3), _AL("")) == 0) //3 符号 '\t' 相当于多少个 'W'的宽度
//if (a_stricmp(GetStringFromTable(3), _AL("")) == 0) //3 '\t' ڶٸ 'W'Ŀ
// m_StringTable[3] = _AL("30");
//_tab_char = a_atoi(GetStringFromTable(3));
//if (a_stricmp(GetStringFromTable(4), _AL("")) == 0) //4 m_FontImagePicture 字体大小
//if (a_stricmp(GetStringFromTable(4), _AL("")) == 0) //4 m_FontImagePicture С
// m_StringTable[4] = m_StringTable[2];
//if (a_stricmp(GetStringFromTable(5), _AL("")) == 0) //5 MessageBox 字体大小
//if (a_stricmp(GetStringFromTable(5), _AL("")) == 0) //5 MessageBox С
// m_StringTable[5] = m_StringTable[2];
//if (a_stricmp(GetStringFromTable(6), _AL("")) == 0) //6 MessageBox shadow
// m_StringTable[6] = _AL("0");
+7 -4
View File
@@ -66,9 +66,9 @@ public partial class CECHostPlayer
if (header == CommandID.TASK_DATA)
{
#if !LOAD_TASK_TEMPL
return; // Task templates loading not implemented in C#
#endif
#if LOAD_TASK_TEMPL // only load on developer project
// Parse aggregated task buffers
cmd_task_data pCmd = cmd_task_data.FromBuffer(pDataBuf);
// cmd_task_data pCmd = GPDataTypeHelper.FromBytes<cmd_task_data>(pDataBuf);
@@ -89,6 +89,8 @@ public partial class CECHostPlayer
}
m_pTaskInterface.CheckPQEnterWorldInit();
#endif
// check if player has equipped goblin (not yet implemented in C#)
// TODO: implement goblin initialization when equipment system is ready
@@ -114,7 +116,8 @@ public partial class CECHostPlayer
private void OnServerNotify(CECTaskInterface pInterface, byte[] data, int size)
{
// TODO: Implement server notify handling for task var data
TaskClient.OnServerNotify(pInterface, data, (uint)size);
}
}
+114
View File
@@ -4,6 +4,7 @@ using System;
using System.Collections;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;
using UnityEngine;
using static CECPlayer;
@@ -157,4 +158,117 @@ public static class EC_Utility
{
return (y.CompareTo(x) < 0) ? y : x;
}
public static bool STRING_TO_A3DCOLOR(string str, out Color clr)
{
// A3DCOLOR_TO_STRING ת
// [English] Parse according to A3DCOLOR_TO_STRING conversion format
bool ret = false;
clr = Color.white;
byte[] rgb = new byte[6];
int nLen = str != null ? str.Length : 0;
while (nLen == 7)
{
// ĸתСд
// [English] Convert uppercase letters to lowercase
str = str.ToLowerInvariant();
if (str[0] != '^')
break;
char c;
int i;
for (i = 1; i < nLen; ++i)
{
c = str[i];
if (c >= '0' && c <= '9')
{
rgb[i - 1] = (byte)(c - '0');
}
else if (c >= 'a' && c <= 'f')
{
rgb[i - 1] = (byte)(10 + (c - 'a'));
}
else
{
break;
}
}
if (i < nLen)
break;
byte r = (byte)((rgb[0] << 4) + rgb[1]);
byte g = (byte)((rgb[2] << 4) + rgb[3]);
byte b = (byte)((rgb[4] << 4) + rgb[5]);
clr = new Color(r / 255f, g / 255f, b / 255f, 1f);
ret = true;
break;
}
return ret;
}
// ===== Text/Color helpers moved from EC_InventoryUI =====
public static string FormatForLegacyText(string text)
{
if (string.IsNullOrEmpty(text))
return string.Empty;
StringBuilder result = new StringBuilder(text);
result.Replace("\\r", "\n");
return ProcessColorCodesForLegacy(result);
}
public static string FormatForTextMeshPro(string text)
{
if (string.IsNullOrEmpty(text))
return string.Empty;
StringBuilder result = new StringBuilder(text);
result.Replace("\\r", "\n");
return ProcessColorCodes(result);
}
public static string ProcessColorCodes(StringBuilder text)
{
string pattern = @"\^([0-9A-Fa-f]{6})";
return Regex.Replace(text.ToString(), pattern, match =>
{
string hexColor = match.Groups[1].Value;
return $"<color=#{hexColor}>";
}, RegexOptions.None);
}
public static string ProcessColorCodesForLegacy(StringBuilder text)
{
string pattern = @"\^([0-9A-Fa-f]{6})";
return Regex.Replace(text.ToString(), pattern, match =>
{
string hexColor = match.Groups[1].Value;
Color color = HexToColor(hexColor);
return $"<color=#{ColorUtility.ToHtmlStringRGB(color)}>";
}, RegexOptions.None);
}
private static Color HexToColor(string hex)
{
if (hex == null || hex.Length != 6)
return Color.white;
try
{
int r = Convert.ToInt32(hex.Substring(0, 2), 16);
int g = Convert.ToInt32(hex.Substring(2, 2), 16);
int b = Convert.ToInt32(hex.Substring(4, 2), 16);
return new Color(r / 255f, g / 255f, b / 255f, 1f);
}
catch
{
return Color.white;
}
}
}