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:
@@ -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)
|
||||
{
|
||||
// id��1��ʼ
|
||||
// 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);
|
||||
}
|
||||
}
|
||||
@@ -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
|
||||
|
||||
// ��ΪPQ�����PQ��������Ҫ��ʱ�����¼��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(¬ify, 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
|
||||
@@ -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)
|
||||
|
||||
+104
-86
@@ -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);
|
||||
}
|
||||
@@ -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");
|
||||
|
||||
@@ -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);
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@@ -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;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user