From e111d0483971bbd41719d7b083a5496ee8f433b9 Mon Sep 17 00:00:00 2001 From: Le Duc Anh Date: Thu, 2 Oct 2025 15:56:27 +0700 Subject: [PATCH] convert more structs --- Assets/Scripts/PlayerVisual.cs | 7 +- Assets/Scripts/Task/ATaskTemplMan.cs | 2 +- Assets/Scripts/Task/CECTaskInterface.cs | 153 ++ Assets/Scripts/Task/TaskExpAnalyser.cs | 24 +- Assets/Scripts/Task/TaskProcess.cs | 325 ++-- Assets/Scripts/Task/TaskTempl.cs | 1903 +++++++++++++++++++++-- 6 files changed, 2137 insertions(+), 277 deletions(-) diff --git a/Assets/Scripts/PlayerVisual.cs b/Assets/Scripts/PlayerVisual.cs index d4bb4c21e8..dec61d0dee 100644 --- a/Assets/Scripts/PlayerVisual.cs +++ b/Assets/Scripts/PlayerVisual.cs @@ -1,4 +1,5 @@ using Animancer; +using BrewMonster; using System; using UnityEngine; @@ -11,7 +12,7 @@ public class PlayerVisual : MonoBehaviour private void PlayActionEventHandler(PlayActionEvent @event) { - BrewMonster.BMLogger.Log("PlayActionEventHandler : "+@event.AnimationName); + BMLogger.Log("PlayActionEventHandler : "+@event.AnimationName); animancer.TryPlay(@event.AnimationName); } @@ -20,13 +21,13 @@ public class PlayerVisual : MonoBehaviour animancer = GetComponentInChildren(); if(animancer == null) { - BrewMonster.BMLogger.LogError("animancer == null"); + BMLogger.LogError("animancer == null"); return; } var player = GetComponentInParent(); if(player == null) { - BrewMonster.BMLogger.LogError("player == null"); + BMLogger.LogError("player == null"); return; } _playerInfo = player.GetPlayInfo(); diff --git a/Assets/Scripts/Task/ATaskTemplMan.cs b/Assets/Scripts/Task/ATaskTemplMan.cs index a7981b970f..95f2add267 100644 --- a/Assets/Scripts/Task/ATaskTemplMan.cs +++ b/Assets/Scripts/Task/ATaskTemplMan.cs @@ -153,7 +153,7 @@ namespace PerfectWorld.Scripts.Task if (pTask.m_FixedData.m_bSkillTask) m_SkillTaskLst.Add(pTask); //todo: recheck m_DynTaskType type - if (!string.IsNullOrEmpty(pTask.m_FixedData.m_DynTaskType)) + if (pTask.m_FixedData.m_DynTaskType != '\0') { if (m_DynTaskMap.TryGetValue(pTask.m_FixedData.m_ID, out ATaskTempl task)) { diff --git a/Assets/Scripts/Task/CECTaskInterface.cs b/Assets/Scripts/Task/CECTaskInterface.cs index 461bb9622a..162a5ec769 100644 --- a/Assets/Scripts/Task/CECTaskInterface.cs +++ b/Assets/Scripts/Task/CECTaskInterface.cs @@ -4,6 +4,159 @@ using UnityEngine; namespace PerfectWorld.Scripts.Task { + public class TaskInterfaceConstants + { + // Task Prerequisite Error Code + public const int TASK_PREREQU_FAIL_INDETERMINATE = 1; + public const int TASK_PREREQU_FAIL_NOT_ROOT = 2; + public const int TASK_PREREQU_FAIL_SAME_TASK = 3; + public const int TASK_PREREQU_FAIL_NO_SPACE = 4; + public const int TASK_PREREQU_FAIL_FULL = 5; + public const int TASK_PREREQU_FAIL_CANT_REDO = 6; + public const int TASK_PREREQU_FAIL_BELOW_LEVEL = 7; + public const int TASK_PREREQU_FAIL_ABOVE_LEVEL = 8; + public const int TASK_PREREQU_FAIL_NO_ITEM = 9; + public const int TASK_PREREQU_FAIL_BELOW_REPU = 10; + public const int TASK_PREREQU_FAIL_CLAN = 11; + public const int TASK_PREREQU_FAIL_WRONG_GENDER = 12; + public const int TASK_PREREQU_FAIL_NOT_IN_OCCU = 13; + public const int TASK_PREREQU_FAIL_WRONG_PERIOD = 14; + public const int TASK_PREREQU_FAIL_PREV_TASK = 15; + public const int TASK_PREREQU_FAIL_MAX_RCV = 16; + public const int TASK_PREREQU_FAIL_NO_DEPOSIT = 17; + public const int TASK_PREREQU_FAIL_NO_TASK = 18; + public const int TASK_PREREQU_FAIL_NOT_CAPTAIN = 19; + public const int TASK_PREREQU_FAIL_ILLEGAL_MEM = 20; + public const int TASK_PREREQU_FAIL_WRONG_TIME = 21; + public const int TASK_PREREQU_FAIL_NO_SUCH_SUB = 22; + public const int TASK_PREREQU_FAIL_MUTEX_TASK = 23; + public const int TASK_PREREQU_FAIL_NOT_IN_ZONE = 24; + public const int TASK_PREREQU_FAIL_WRONG_SUB = 25; + public const int TASK_PREREQU_FAIL_OUTOF_DIST = 26; + public const int TASK_PREREQU_FAIL_GIVEN_ITEM = 27; + public const int TASK_PREREQU_FAIL_LIVING_SKILL = 28; + public const int TASK_PREREQU_FAIL_SPECIAL_AWARD = 29; + public const int TASK_PREREQU_FAIL_GM = 30; + public const int TASK_PREREQU_FAIL_GLOBAL_KEYVAL = 31; + public const int TASK_PREREQU_FAIL_SHIELD_USER = 32; + public const int TASK_PREREQU_FAIL_ALREADY_HAS_PQ = 33; + public const int TASK_PREREQU_FAIL_MAX_ACC_CNT = 34; + public const int TASK_PREREQU_FAIL_RMB_NOT_ENOUGH = 35; + public const int TASK_PREREQU_FAIL_NOT_COUPLE = 36; + public const int TASK_PREREQU_FAIL_ERR_CHAR_TIME = 37; + public const int TASK_PREREQU_FAIL_NOT_IVTRSLOTNUM = 38; // version 81 + public const int TASK_PREREQU_FAIL_BELOW_FACTION_CONTRIB = 39; // version 87 + public const int TASK_PREREQU_FAIL_BELOW_RECORD_TASKS_NUM = 40; // version 91 + public const int TASK_PREREQU_FAIL_OVER_RECEIVE_PER_DAY = 41; + public const int TASK_PREREQU_FAIL_TRANSFORM_MASK = 42; + public const int TASK_PREREQU_FAIL_FORCE = 43; + public const int TASK_PREREQU_FAIL_FORCE_REPUTATION = 44; + public const int TASK_PREREQU_FAIL_FORCE_CONTRIBUTION = 45; + public const int TASK_PREREQU_FAIL_EXP = 46; + public const int TASK_PREREQU_FAIL_SP = 47; + public const int TASK_PREREQU_FAIL_FORCE_AL = 48; + public const int TASK_PREREQU_FAIL_WEDDING_OWNER = 49; + public const int TASK_PREREQU_FAIL_CROSSSERVER_NO_ACOUNT_LIMIT = 50; + public const int TASK_PREREQU_FAIL_CROSSSERVER_NO_MARRIAGE = 51; + public const int TASK_PREREQU_FAIL_CROSSSERVER_NO_FORCE = 52; + public const int TASK_PREREQU_FAIL_KING = 53; + public const int TASK_PREREQU_FAIL_IN_TEAM = 54; + public const int TASK_PREREQU_FAIL_TITLE = 55; + public const int TASK_PREREQU_FAIL_HISTORYSTAGE = 56; + public const int TASK_PREREQU_FAIL_NO_GIFTCARD_TASK = 57; + public const int TASK_PREREQU_FAIL_BELOW_REINCARNATION = 57; + public const int TASK_PREREQU_FAIL_ABOVE_REINCARNATION = 58; + public const int TASK_PREREQU_FAIL_BELOW_REALMLEVEL = 59; + public const int TASK_PREREQU_FAIL_ABOVE_REALMLEVEL = 60; + public const int TASK_PREREQU_FAIL_REALM_EXP_FULL = 61; + public const int TASK_PREREQU_FAIL_CARD_COUNT_COLLECTION = 62; + public const int TASK_PREREQU_FAIL_MAX_ROLE_CNT = 63; + public const int TASK_PREREQU_FAIL_CARD_COUNT_RANK = 64; + public const int TASK_PREREQU_FAIL_TASK_FORBID = 65; + public const int TASK_PREREQU_FAIL_NO_NAVIGATE_INSHPAED = 66; + + public const int TASK_AWARD_FAIL_GIVEN_ITEM = 150; + public const int TASK_AWARD_FAIL_NEW_TASK = 151; + public const int TASK_AWARD_FAIL_REPUTATION = 152; + public const int TASK_AWARD_FAIL_GLOBAL_KEYVAL = 153; + public const int TASK_AWARD_FAIL_CROSSSERVER_NO_ACOUNT_LIMIT = 154; + public const int TASK_AWARD_FAIL_CROSSSERVER_NO_ACOUNT_STORAGE = 155; + public const int TASK_AWARD_FAIL_CROSSSERVER_NO_DIVORCE = 156; + public const int TASK_AWARD_FAIL_CROSSSERVER_NO_FACTION_RALATED = 157; + public const int TASK_AWARD_FAIL_CROSSSERVER_NO_FORCE_RALATED = 158; + public const int TASK_AWARD_FAIL_CROSSSERVER_NO_DIVIEND = 159; + public const int TASK_AWARD_FAIL_LEVEL_CHECK = 160; + + + // Task messages + public const int TASK_MSG_NEW = 1; + public const int TASK_MSG_SUCCESS = 2; + public const int TASK_MSG_FAIL = 3; + + public const int TASK_ACTIVE_LIST_HEADER_LEN = 8; + public const int TASK_ACTIVE_LIST_MAX_LEN = 175; + public const int TASK_FINISHED_LIST_MAX_LEN = 2040; + public const int TASK_DATA_BUF_MAX_LEN = 32; + public const int TASK_FINISH_TIME_MAX_LEN = 1700; + public const int TASK_FINISH_COUNT_MAX_LEN = 730; + + // 库任务 // Library tasks + public const int TASK_MAX_DELIVER_COUNT = 5; + public const int TASK_STORAGE_COUNT = 32; + public const int TASK_STORAGE_LEN = 10; + public const int TASK_STORAGE_WHELL_SCALE = 10000; // 10000.f originally + + // 当前激活的任务列表缓冲区大小 // Current active task list buffer size + public const int TASK_ACTIVE_LIST_BUF_SIZE = (TASK_ACTIVE_LIST_MAX_LEN * TASK_DATA_BUF_MAX_LEN + TASK_ACTIVE_LIST_HEADER_LEN); + // 已完成的任务列表缓冲区大小 // Completed task list buffer size + public const int TASK_FINISHED_LIST_BUF_SIZE = 8192; + public const int TASK_FINISHED_LIST_BUF_SIZE_OLD = 4096; + // 任务全局数据大小 // Task global data size + public const int TASK_GLOBAL_DATA_SIZE = 256; + // 任务完成时间 // Task completion time + public const int TASK_FINISH_TIME_LIST_BUF_SIZE = 10240; + //任务完成次数 // Task completion count + public const int TASK_FINISH_COUNT_LIST_BUF_SIZE = 10240; + // 库任务 // Library tasks + public const int TASK_STORAGE_LIST_BUF_SIZE = 1024; + + + // Masks + public const int TASK_MASK_KILL_MONSTER = 0x00000001; + public const int TASK_MASK_COLLECT_ITEM = 0x00000002; + public const int TASK_MASK_TALK_TO_NPC = 0x00000004; + public const int TASK_MASK_REACH_SITE = 0x00000008; + public const int TASK_MASK_ANSWER_QUESTION = 0x00000010; + public const int TASK_MASK_TINY_GAME = 0x00000020; + public const int TASK_MASK_KILL_PQ_MONSTER = 0x00000040; + public const int TASK_MASK_KILL_PLAYER = 0x00000080; + + + public const int MAX_MONSTER_WANTED = 3; // 受ActiveTaskEntry大小限制,最大3 // Limited by ActiveTaskEntry size, max 3 + public const int MAX_PLAYER_WANTED = MAX_MONSTER_WANTED; + public const int MAX_ITEM_WANTED = 10; + public const int MAX_ITEM_AWARD = 64; + public const int MAX_MONSTER_SUMMONED = 32; // 最大召唤出的怪物数量 // Maximum number of summoned monsters + + public const int MAX_OCCUPATIONS = 12; // 职业 // Occupations + + public const int TASK_MSG_CHANNEL_LOCAL = 0; + public const int TASK_MSG_CHANNEL_WORLD = 1; + public const int TASK_MSG_CHANNEL_BROADCAST = 9; + + public const int TASK_TEAM_RELATION_MARRIAGE = 1; + + public const int TASK_AWARD_MAX_CHANGE_VALUE = 255; + public const int TASK_AWARD_MAX_DISPLAY_VALUE = 64; + + public const int TASK_AWARD_MAX_DISPLAY_EXP_CNT = 32; // 表达式的个数 // Number of expressions + public const int TASK_AWARD_MAX_DISPLAY_CHAR_LEN = 64; // 表达式的长度 // Length of expression + + public const int TASK_WORLD_CONTRIBUTION_SPEND_PER_DAY = 30; // 免费玩家每日消费贡献度上限 // Daily contribution spend cap for free players + + } + + public class CECTaskInterface : TaskInterface { public const int TASK_MAX_DELIVER_COUNT = 5; diff --git a/Assets/Scripts/Task/TaskExpAnalyser.cs b/Assets/Scripts/Task/TaskExpAnalyser.cs index fb05f704bf..383d122682 100644 --- a/Assets/Scripts/Task/TaskExpAnalyser.cs +++ b/Assets/Scripts/Task/TaskExpAnalyser.cs @@ -1,5 +1,8 @@ -namespace PerfectWorld.Scripts.Task +using System.Runtime.InteropServices; + +namespace PerfectWorld.Scripts.Task { + [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct TASK_EXPRESSION { public int type; @@ -9,5 +12,24 @@ { return (type == src.type && value == src.value); } + + public override bool Equals(object obj) + { + if (obj is TASK_EXPRESSION other) + { + return Equals(other); + } + return false; + } + + public static bool operator ==(TASK_EXPRESSION lhs, TASK_EXPRESSION rhs) + { + return lhs.Equals(rhs); + } + + public static bool operator !=(TASK_EXPRESSION lhs, TASK_EXPRESSION rhs) + { + return !lhs.Equals(rhs); + } } } \ No newline at end of file diff --git a/Assets/Scripts/Task/TaskProcess.cs b/Assets/Scripts/Task/TaskProcess.cs index 24230b2a9e..ab9dd8800d 100644 --- a/Assets/Scripts/Task/TaskProcess.cs +++ b/Assets/Scripts/Task/TaskProcess.cs @@ -3,174 +3,177 @@ using System.Runtime.InteropServices; using PerfectWorld.Scripts.Task; using UnityEngine; -public class TaskProcess +namespace PerfectWorld.Scripts.Task { - -} -[Flags] -public enum TaskState : byte -{ - TASK_STATE_FINISHED = 0x01, // Is finished - TASK_STATE_SUCCESS = 0x02, // Is successful - TASK_STATE_GIVEUP = 0x04, // Is given up - TASK_STATE_ERR_REPORTED = 0x08, // Error has been reported to client - TASK_STATE_AWARD_NOTIFY_TEAM = 0x10, // Award has been notified to team - TASK_STATE_CONTRIBUTION_FINISH = 0x20 // Contribution finished -} - -// Cur Size 21 bytes -public class TASK_ENTRY_FIXED_DATA -{ - public ushort m_ID; // ID - public char m_ParentIndex; // Parent node index - public char m_PrevSblIndex; // Previous sibling node index - public char m_NextSblIndex; // Next sibling node index - public char m_ChildIndex; // Child node index - public char m_uState; // Task state - public ulong m_ulTaskTime; // Timestamp - public ushort m_uCapTaskId; // Captain task ID - public ulong m_ulTemplAddr; // Template address - public ulong m_ulCapTemplAddr; // Captain task template address -}; - - // ´óСΪTASK_DATA_BUF_MAX_LEN -public class ActiveTaskEntry : TASK_ENTRY_FIXED_DATA -{ - // Buffer union simplified (C# does not support union directly) - public byte[] m_BufData; // Raw data buffer - public ushort[] m_wMonsterNum; // Monster numbers - public int m_iUsefulData1; - public char m_iUsefulData2; - - // bool IsFinished() const { return (m_uState & TASK_STATE_FINISHED) != 0; } - // bool IsSuccess() const { return (m_uState & TASK_STATE_SUCCESS) != 0; } - // bool IsGiveUp() const { return (m_uState & TASK_STATE_GIVEUP) != 0; } - // bool IsErrReported() const { return (m_uState & TASK_STATE_ERR_REPORTED) != 0; } - // bool IsAwardNotifyTeam() const { return (m_uState & TASK_STATE_AWARD_NOTIFY_TEAM) != 0; } - // bool IsContributionFinish() const { return (m_uState & TASK_STATE_CONTRIBUTION_FINISH) != 0; } - // --- State check methods --- - public bool IsFinished() => (m_uState & (byte)TaskState.TASK_STATE_FINISHED) != 0; - public bool IsSuccess() => (m_uState & (byte)TaskState.TASK_STATE_SUCCESS) != 0; - public bool IsGiveUp() => (m_uState & (byte)TaskState.TASK_STATE_GIVEUP) != 0; - public bool IsErrReported() => (m_uState & (byte)TaskState.TASK_STATE_ERR_REPORTED) != 0; - 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; } - // void ClearFinished() { m_uState &= ~TASK_STATE_FINISHED; } - // void SetSuccess() { m_uState |= TASK_STATE_SUCCESS; } - // void ClearSuccess() { m_uState &= ~TASK_STATE_SUCCESS; } - // void SetGiveUp() { m_uState |= TASK_STATE_GIVEUP; } - // void ClearGiveUp() { m_uState &= ~TASK_STATE_GIVEUP; } - // void SetErrReported() { m_uState |= TASK_STATE_ERR_REPORTED; } - // void ClearErrReported() { m_uState &= ~TASK_STATE_ERR_REPORTED; } - // void SetAwardNotifyTeam() { m_uState |= TASK_STATE_AWARD_NOTIFY_TEAM; } - // void ClearAwardNotifyTeam() { m_uState &= ~TASK_STATE_AWARD_NOTIFY_TEAM; } - // void SetContributionFinish() { m_uState |= TASK_STATE_CONTRIBUTION_FINISH; } - // void ClearContributionFinish() { m_uState &= ~TASK_STATE_CONTRIBUTION_FINISH; } - // - public ATaskTempl GetTempl() + public class TaskProcess { - if (m_ulTemplAddr == 0) return null; - return Marshal.PtrToStructure( - new IntPtr(unchecked((long)m_ulTemplAddr)) - ); - // return reinterpret_cast(m_ulTemplAddr); + } - // const ATaskTempl* GetCap() const { return reinterpret_cast(m_ulCapTemplAddr); } - // const ATaskTempl* GetCapOrSelf() const - // { - // if (m_ulCapTemplAddr) return GetCap(); - // else return GetTempl(); - // } - // bool HasParent() const { return m_ParentIndex != 0xff; } - // bool HasChildren() const { return m_ChildIndex != 0xff; } - // bool IsValid(unsigned char uIndex, unsigned char uMaxCount) const - // { - // if (m_ParentIndex != 0xff) - // { - // if (m_ParentIndex >= uIndex || m_ParentIndex >= uMaxCount) - // return false; - // } - // - // if (m_PrevSblIndex != 0xff) - // { - // if (m_PrevSblIndex >= uIndex || m_PrevSblIndex >= uMaxCount) - // return false; - // } - // - // if (m_NextSblIndex != 0xff) - // { - // if (m_NextSblIndex <= uIndex || m_NextSblIndex >= uMaxCount) - // return false; - // } - // - // if (m_ChildIndex != 0xff) - // { - // if (m_ChildIndex <= uIndex || m_ChildIndex >= uMaxCount) - // return false; - // } - // - // return true; - // } -}; - -public class ActiveTaskList -{ - // --- Header Fields --- - public byte[] header = new byte[CECTaskInterface.TASK_ACTIVE_LIST_HEADER_LEN]; - - public byte m_uTaskCount; // number of tasks - public byte m_uUsedCount; // used count - public ushort m_Version; // version - public byte m_uTopShowTaskCount; // top show task count - public byte m_uListState; // list state - public byte m_uTopHideTaskCount; // top hide task count - - private byte _flags; // simulate bitfield (1 bit + 7 bits) - - public bool m_uMaxSimultaneousCount + [Flags] + public enum TaskState : byte { - get => (_flags & 0x01) != 0; - set + TASK_STATE_FINISHED = 0x01, // Is finished + TASK_STATE_SUCCESS = 0x02, // Is successful + TASK_STATE_GIVEUP = 0x04, // Is given up + TASK_STATE_ERR_REPORTED = 0x08, // Error has been reported to client + TASK_STATE_AWARD_NOTIFY_TEAM = 0x10, // Award has been notified to team + TASK_STATE_CONTRIBUTION_FINISH = 0x20 // Contribution finished + } + + // Cur Size 21 bytes + public class TASK_ENTRY_FIXED_DATA + { + public ushort m_ID; // ID + public char m_ParentIndex; // Parent node index + public char m_PrevSblIndex; // Previous sibling node index + public char m_NextSblIndex; // Next sibling node index + public char m_ChildIndex; // Child node index + public char m_uState; // Task state + public ulong m_ulTaskTime; // Timestamp + public ushort m_uCapTaskId; // Captain task ID + public ulong m_ulTemplAddr; // Template address + public ulong m_ulCapTemplAddr; // Captain task template address + }; + + // ´óСΪTASK_DATA_BUF_MAX_LEN + public class ActiveTaskEntry : TASK_ENTRY_FIXED_DATA + { + // Buffer union simplified (C# does not support union directly) + public byte[] m_BufData; // Raw data buffer + public ushort[] m_wMonsterNum; // Monster numbers + public int m_iUsefulData1; + public char m_iUsefulData2; + + // bool IsFinished() const { return (m_uState & TASK_STATE_FINISHED) != 0; } + // bool IsSuccess() const { return (m_uState & TASK_STATE_SUCCESS) != 0; } + // bool IsGiveUp() const { return (m_uState & TASK_STATE_GIVEUP) != 0; } + // bool IsErrReported() const { return (m_uState & TASK_STATE_ERR_REPORTED) != 0; } + // bool IsAwardNotifyTeam() const { return (m_uState & TASK_STATE_AWARD_NOTIFY_TEAM) != 0; } + // bool IsContributionFinish() const { return (m_uState & TASK_STATE_CONTRIBUTION_FINISH) != 0; } + // --- State check methods --- + public bool IsFinished() => (m_uState & (byte)TaskState.TASK_STATE_FINISHED) != 0; + public bool IsSuccess() => (m_uState & (byte)TaskState.TASK_STATE_SUCCESS) != 0; + public bool IsGiveUp() => (m_uState & (byte)TaskState.TASK_STATE_GIVEUP) != 0; + public bool IsErrReported() => (m_uState & (byte)TaskState.TASK_STATE_ERR_REPORTED) != 0; + 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; } + // void ClearFinished() { m_uState &= ~TASK_STATE_FINISHED; } + // void SetSuccess() { m_uState |= TASK_STATE_SUCCESS; } + // void ClearSuccess() { m_uState &= ~TASK_STATE_SUCCESS; } + // void SetGiveUp() { m_uState |= TASK_STATE_GIVEUP; } + // void ClearGiveUp() { m_uState &= ~TASK_STATE_GIVEUP; } + // void SetErrReported() { m_uState |= TASK_STATE_ERR_REPORTED; } + // void ClearErrReported() { m_uState &= ~TASK_STATE_ERR_REPORTED; } + // void SetAwardNotifyTeam() { m_uState |= TASK_STATE_AWARD_NOTIFY_TEAM; } + // void ClearAwardNotifyTeam() { m_uState &= ~TASK_STATE_AWARD_NOTIFY_TEAM; } + // void SetContributionFinish() { m_uState |= TASK_STATE_CONTRIBUTION_FINISH; } + // void ClearContributionFinish() { m_uState &= ~TASK_STATE_CONTRIBUTION_FINISH; } + // + public ATaskTempl GetTempl() { - if (value) _flags |= 0x01; - else _flags &= unchecked((byte)~0x01); + if (m_ulTemplAddr == 0) return null; + return Marshal.PtrToStructure( + new IntPtr(unchecked((long)m_ulTemplAddr)) + ); + // return reinterpret_cast(m_ulTemplAddr); } - } + // const ATaskTempl* GetCap() const { return reinterpret_cast(m_ulCapTemplAddr); } + // const ATaskTempl* GetCapOrSelf() const + // { + // if (m_ulCapTemplAddr) return GetCap(); + // else return GetTempl(); + // } + // bool HasParent() const { return m_ParentIndex != 0xff; } + // bool HasChildren() const { return m_ChildIndex != 0xff; } + // bool IsValid(unsigned char uIndex, unsigned char uMaxCount) const + // { + // if (m_ParentIndex != 0xff) + // { + // if (m_ParentIndex >= uIndex || m_ParentIndex >= uMaxCount) + // return false; + // } + // + // if (m_PrevSblIndex != 0xff) + // { + // if (m_PrevSblIndex >= uIndex || m_PrevSblIndex >= uMaxCount) + // return false; + // } + // + // if (m_NextSblIndex != 0xff) + // { + // if (m_NextSblIndex <= uIndex || m_NextSblIndex >= uMaxCount) + // return false; + // } + // + // if (m_ChildIndex != 0xff) + // { + // if (m_ChildIndex <= uIndex || m_ChildIndex >= uMaxCount) + // return false; + // } + // + // return true; + // } + }; - public byte m_uTitleTaskCount + public class ActiveTaskList { - get => (byte)((_flags & 0xFE) >> 1); - set => _flags = (byte)((_flags & 0x01) | ((value & 0x7F) << 1)); - } + // --- Header Fields --- + public byte[] header = new byte[CECTaskInterface.TASK_ACTIVE_LIST_HEADER_LEN]; - public ActiveTaskEntry[] m_TaskEntries = new ActiveTaskEntry[CECTaskInterface.TASK_ACTIVE_LIST_MAX_LEN]; + public byte m_uTaskCount; // number of tasks + public byte m_uUsedCount; // used count + public ushort m_Version; // version + public byte m_uTopShowTaskCount; // top show task count + public byte m_uListState; // list state + public byte m_uTopHideTaskCount; // top hide task count - // 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 ClearChildrenOf(TaskInterface* pTask, ActiveTaskEntry* pParent, bool bRemoveItem = true); - // ActiveTaskEntry* GetEntry(unsigned long ulId) - // { - // for (unsigned char i = 0; i < m_uTaskCount; i++) - // if (m_TaskEntries[i].m_ID == ulId) - // return &m_TaskEntries[i]; - // - // return NULL; - // } - // void RemoveAll() - // { - // unsigned short ver = m_Version; - // memset(this, 0, sizeof(*this)); - // m_Version = ver; - // } - // bool IsValid() const { return m_uTaskCount <= TASK_ACTIVE_LIST_MAX_LEN; } - // bool IsTimeMarkUpdate() const { return (m_uListState & TLIST_STATE_UPDATE_TIME_MARK) != 0; } - // void SetTimeMarkUpdate() { m_uListState |= TLIST_STATE_UPDATE_TIME_MARK; } - // 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;} -}; \ No newline at end of file + private byte _flags; // simulate bitfield (1 bit + 7 bits) + + public bool m_uMaxSimultaneousCount + { + get => (_flags & 0x01) != 0; + set + { + if (value) _flags |= 0x01; + else _flags &= unchecked((byte)~0x01); + } + } + + public byte m_uTitleTaskCount + { + get => (byte)((_flags & 0xFE) >> 1); + set => _flags = (byte)((_flags & 0x01) | ((value & 0x7F) << 1)); + } + + public ActiveTaskEntry[] m_TaskEntries = new ActiveTaskEntry[CECTaskInterface.TASK_ACTIVE_LIST_MAX_LEN]; + + // 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 ClearChildrenOf(TaskInterface* pTask, ActiveTaskEntry* pParent, bool bRemoveItem = true); + // ActiveTaskEntry* GetEntry(unsigned long ulId) + // { + // for (unsigned char i = 0; i < m_uTaskCount; i++) + // if (m_TaskEntries[i].m_ID == ulId) + // return &m_TaskEntries[i]; + // + // return NULL; + // } + // void RemoveAll() + // { + // unsigned short ver = m_Version; + // memset(this, 0, sizeof(*this)); + // m_Version = ver; + // } + // bool IsValid() const { return m_uTaskCount <= TASK_ACTIVE_LIST_MAX_LEN; } + // bool IsTimeMarkUpdate() const { return (m_uListState & TLIST_STATE_UPDATE_TIME_MARK) != 0; } + // void SetTimeMarkUpdate() { m_uListState |= TLIST_STATE_UPDATE_TIME_MARK; } + // 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;} + }; +} \ No newline at end of file diff --git a/Assets/Scripts/Task/TaskTempl.cs b/Assets/Scripts/Task/TaskTempl.cs index 9c28eae2d6..8e43546304 100644 --- a/Assets/Scripts/Task/TaskTempl.cs +++ b/Assets/Scripts/Task/TaskTempl.cs @@ -1,59 +1,276 @@ using UnityEngine; using System.IO; using System.Runtime.InteropServices; +using System; namespace PerfectWorld.Scripts.Task { - public sealed class TaskConstant + public class TaskTemplConstants { - public const int MAX_OCCUPATIONS = 12; - public const int MAX_TASK_NAME_LEN = 30; public const int MAX_AWARD_NPC_NUM = 8; public const int MAX_PREM_TASK_COUNT = 20; public const int MAX_MUTEX_TASK_COUNT = 5; + public const int MAX_OCCUPATIONS = 12; // 职业 // Occupations public const int MAX_TEAM_MEM_WANTED = MAX_OCCUPATIONS; public const int MAX_TIMETABLE_SIZE = 24; + public const int MAX_AWARD_SCALES = 5; public const int MAX_AWARD_CANDIDATES = 12; public const int MAX_LIVING_SKILLS = 4; - public const int MAX_CONTRIB_MONSTERS = 100; - public const int MAX_AWARD_PQ_RANKING = 32; + public const int MAX_CONTRIB_MONSTERS = 100; // PQ子任务贡献度最大怪物种类 // Maximum monster types for PQ subtask contribution + public const int MAX_AWARD_PQ_RANKING = 32; // PQ子任务奖励最大排名数 // Maximum ranking count for PQ subtask rewards public const int MAX_TITLE_NUM = 10; - public const int MAX_TASKREGION = 8; + + public const int MAX_TASKREGION = 8; // 最大区域个数 // Maximum number of regions + public const int TASK_GENDER_NONE = 0; public const int TASK_GENDER_MALE = 1; public const int TASK_GENDER_FEMALE = 2; + public const int TASK_MAX_PATH = 260; - public const int INVALID_VAL = -1; + public const uint INVALID_VAL = uint.MaxValue; + public const int TASK_MAX_LINE_LEN = TASK_MAX_PATH; + public const int TASK_MAX_VALID_COUNT = 6; - public const int TASK_TREASURE_MAP_SIDE_MULTIPLE = 30; + public const int TASK_TREASURE_MAP_SIDE_MULTIPLE = 30; // 藏宝图边长与小区域边长的比 // Ratio of treasure map side length to small region side length + public const int NUM_SPECIAL_AWARD = 2; + public static readonly int[] TASK_SPECIAL_AWARD = new int[NUM_SPECIAL_AWARD] { 26969, 26970 }; - public readonly long[] task_week_map = - { - 7, - 1, - 2, - 3, - 4, - 5, - 6 - }; + public const uint TASK_PACK_MAGIC = 0x93858361; + + // Race-occupation mapping array + public static readonly uint[] _race_occ_map = new uint[MAX_OCCUPATIONS]; } - public struct task_tm + public enum DynTaskType { - public int year; - public int month; - public int day; - public int hour; - public int min; - public int wday; + enumDTTNone = 0, + enumDTTSpecialAward, + enumDTTNormal, + enumDTTGiftCard, + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct NPC_INFO + { + public uint id; + public short x; + public short y; + public short z; + } + + public class ServerNotificationConstants + { + // 新任务发放 // 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 class ClientNotificationConstants + { + // 检查完成 // Check completion + public const int TASK_CLT_NOTIFY_CHECK_FINISH = 1; + + // 检查放弃 // Check abandonment + public const int TASK_CLT_NOTIFY_CHECK_GIVEUP = 2; + + // 到达地点 // Reach location + public const int TASK_CLT_NOTIFY_REACH_SITE = 3; + + // 自动交付 // Auto delivery + public const int TASK_CLT_NOTIFY_AUTO_DELV = 4; + + // 手动触发 // Manual trigger + public const int TASK_CLT_NOTIFY_MANUAL_TRIG = 5; + + // 强制放弃 // Force abandon + public const int TASK_CLT_NOTIFY_FORCE_GIVEUP = 6; + + // 动态任务时间标记 // Dynamic task time mark + public const int TASK_CLT_NOTIFY_DYN_TIMEMARK = 7; + + // 动态任务数据 // Dynamic task data + public const int TASK_CLT_NOTIFY_DYN_DATA = 8; + + // 特殊奖励 // Special reward + public const int TASK_CLT_NOTIFY_SPECIAL_AWARD = 9; + + // 离开地点 // Leave location + public const int TASK_CLT_NOTIFY_LEAVE_SITE = 10; + + // PQ检查初始化 // PQ check initialization + public const int TASK_CLT_NOTIFY_PQ_CHECK_INIT = 11; + + // 仓库 // Storage + public const int TASK_CLT_NOTIFY_STORAGE = 12; + + // 请求宝藏索引 // Request treasure index + public const int TASK_CLT_NOTIFY_REQUEST_TREASURE_INDEX = 14; + + // 15天未登录 // 15 days no login + public const int TASK_CLT_NOTIFY_15DAYS_NOLOGIN = 15; + + // 特殊奖励掩码 // Special reward mask + public const int TASK_CLT_NOTIFY_SPECIAL_AWARD_MASK = 16; + + // 称号任务 // Title task + public const int TASK_CLT_NOTIFY_TITLE_TASK = 17; + + // 选择奖励 // Choose reward + public const int TASK_CLT_NOTIFY_CHOOSE_AWARD = 18; + + // 购买代币商店物品 // Buy token shop item + public const int TASK_CLT_NOTIFY_BUY_TOKENSHOP_ITEM = 20; + + // 通过世界贡献完成任务 // Complete task by world contribution + public const int TASK_CLT_NOTIFY_FINISH_TASK_BY_WORLD_CONTRIBUTION = 21; + + // 移除完成任务 // Remove completed task + public const int TASK_CLT_NOTIFY_RM_FINISH_TASK = 150; + } + + + public static class PlayerNotificationConstants + { + // Notify receiving team member task // 通知接收队员任务 + public const int TASK_PLY_NOTIFY_NEW_MEM_TASK = 1; + + // Whole team fails // 全队失败 + public const int TASK_PLY_NOTIFY_FORCE_FAIL = 2; + + // Whole team succeeds // 全队成功 + public const int TASK_PLY_NOTIFY_FORCE_SUCC = 3; + } + + public static class GlobalDataReasonConstants + { + public const int TASK_GLOBAL_CHECK_RCV_NUM = 1; + public const int TASK_GLOBAL_CHECK_COTASK = 2; + public const int TASK_GLOBAL_CHECK_ADD_MEM = 3; + public const int TASK_GLOBAL_NPC_KILLED_TIME = 4; + public const int TASK_GLOBAL_ADD_TIME_MARK = 5; + public const int TASK_GLOBAL_DEL_TIME_MARK = 6; + public const int TASK_GLOBAL_PROTECT_NPC = 7; + } + + public static class CotaskConditionConstants + { + public const int COTASK_CORRESPOND = 0; + public const int COTASK_ONCE = 1; + } + + // 任务类型 // Task types + public enum ENUM_TASK_TYPE + { + enumTTDaily = 100, // 每日 // Daily + enumTTLevel2, // 修真 // Cultivation + enumTTMajor, // 主线 // Main quest + enumTTBranch, // 支线 // Branch quest + enumTTEvent, // 活动 // Event + enumTTQiShaList, // 七杀榜 // Seven Killers List + enumTTFaction, // 帮派 // Faction + enumTTFunction, // 经营 // Management + enumTTLegend, // 传奇 // Legend + enumTTQuestion, // 答题 // Quiz + + enumTTEnd, + } + + // 完成方式 // Completion methods + public enum TaskCompletionMethod + { + enumTMNone = 0, // 无 // None + enumTMKillNumMonster, // 杀数量怪 // Kill specific number of monsters + enumTMCollectNumArticle, // 获得数量道具 // Collect specific number of items + enumTMTalkToNPC, // 与特定NPC对话 // Talk to specific NPC + enumTMReachSite, // 到达特定地点 // Reach specific location + enumTMWaitTime, // 等待特定时间 // Wait for specific time + enumTMAnswerQuestion, // 选择问答 // Answer questions + enumTMTinyGame, // 小游戏 // Mini game + enumTMProtectNPC, // 保护特定NPC // Protect specific NPC + enumTMNPCReachSite, // NPC到达特定地点 // NPC reaches specific location + enumTMGlobalValOK, // 全局变量满足条件 // Global variable meets condition + enumTMLeaveSite, // 离开特定地点 // Leave specific location + enumTMReachTreasureZone, // 达到藏宝区域 // Reach treasure zone + enumTMKillPlayer, // 杀死玩家 // Kill player + enumTMTransform, // 变身状态 // Transform state + enumTMReachLevel, // 检查等级:普通等级,转生次数,境界等级 // Check level: normal level, reincarnation count, realm level + enumTMSimpleClientTask, // 简单任务,只做客户端验证,目前只验证表情动作 // Simple task, client-side verification only, currently only verifies emote actions + enumTMSimpleClientTaskForceNavi, // 强制移动 // Force movement + } + + // 完成条件 // Completion conditions + public enum TaskFinishType + { + enumTFTDirect = 0, // 直接完成 // Direct completion + enumTFTNPC, // NPC完成 // NPC completion + enumTFTConfirm // 需要确认完成 // Need confirmation to complete + } + + // 奖励方式 // Reward methods + public enum TaskAwardType + { + enumTATNormal = 0, // 普通 // Normal + enumTATEach, // 按杀怪数目、获得物品乘 // Multiply by monster kills, items obtained + enumTATRatio, // 按时间比例 // By time ratio + enumTATItemCount // 按获得物品个数分不同档次 // Different tiers based on number of items obtained + } + + // 任务重复间隔 // Task repeat interval + public enum TaskAwardFreq + { + enumTAFNormal = 0, // 普通 // Normal + enumTAFEachDay, // 每天 // Daily + enumTAFEachWeek, // 每周 // Weekly + enumTAFEachMonth, // 每月 // Monthly + enumTAFEachYear // 每年 // Yearly } public struct TASK_PACK_HEADER @@ -63,12 +280,103 @@ namespace PerfectWorld.Scripts.Task public int item_count; } + public struct ZONE_VERT + { + public float x; + public float y; + public float z; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct PLAYER_WANTED + { + public uint m_ulTemplID; // Player Template ID + public uint m_ulCount; // Count + public uint m_ulLevel; // Level + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct MONSTER_WANTED + { + public uint m_ulMonsterTemplId; // Monster template ID + public uint m_ulMonsterNum; // Number of monsters + public uint m_ulDropItemId; // Drop item ID + public uint m_ulDropItemCount; // Drop item count + public bool m_bDropCmnItem; // Is common item drop + public float m_fDropProb; // Drop probability + public bool m_bKillerLev; // Killer level flag + public int m_iDPH; // Damage per hit + public int m_iDPS; // Damage per second + + public bool Equals(MONSTER_WANTED src) + { + return (m_ulMonsterTemplId == src.m_ulMonsterTemplId && + m_ulMonsterNum == src.m_ulMonsterNum && + m_ulDropItemId == src.m_ulDropItemId && + m_ulDropItemCount == src.m_ulDropItemCount && + m_bDropCmnItem == src.m_bDropCmnItem && + m_fDropProb == src.m_fDropProb && + m_bKillerLev == src.m_bKillerLev); + } + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct ITEM_WANTED + { + public uint m_ulItemTemplId; + public bool m_bCommonItem; + public uint m_ulItemNum; + public float m_fProb; + public int m_lPeriod; + + public bool Equals(ITEM_WANTED src) + { + return (m_ulItemTemplId == src.m_ulItemTemplId && + m_bCommonItem == src.m_bCommonItem && + m_ulItemNum == src.m_ulItemNum && + m_lPeriod == src.m_lPeriod); + } + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct TITLE_AWARD + { + public uint m_ulTitleID; + public int m_lPeriod; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct TEAM_MEM_ITEM_WANTED + { + public uint m_ulItemTemplId; + public bool m_bCommonItem; + public uint m_ulItemNum; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct MONSTERS_SUMMONED + { + public uint m_ulMonsterTemplId; + public uint m_ulMonsterNum; + public float m_fSummonProb; + public int m_lPeriod; + + public bool Equals(MONSTERS_SUMMONED src) + { + return (m_ulMonsterTemplId == src.m_ulMonsterTemplId && + m_ulMonsterNum == src.m_ulMonsterNum && + m_fSummonProb == src.m_fSummonProb && + m_lPeriod == src.m_lPeriod); + } + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct MONSTERS_CONTRIB { - public ulong m_ulMonsterTemplId; // Monster ID - public int m_iWholeContrib; // Team exclusive contribution - public int m_iShareContrib; // Team shared contribution - public int m_iPersonalWholeContrib; // Personal exclusive contribution + public uint m_ulMonsterTemplId; // Monster ID // 怪物ID + public int m_iWholeContrib; // Team exclusive contribution // 组队间独享贡献度 + public int m_iShareContrib; // Team shared contribution // 组队间共享贡献度 + public int m_iPersonalWholeContrib; // Personal exclusive contribution // 个人独享贡献度 public bool Equals(MONSTERS_CONTRIB src) { @@ -79,13 +387,1091 @@ namespace PerfectWorld.Scripts.Task } } - public struct ZONE_VERT + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct RANKING_AWARD { - public float x; - public float y; - public float z; + public uint m_iRankingStart; + public uint m_iRankingEnd; + public bool m_bCommonItem; + public ulong m_ulAwardItemId; + public ulong m_ulAwardItemNum; + public long m_lPeriod; + + public bool Equals(RANKING_AWARD src) + { + return (m_iRankingStart == src.m_iRankingStart && + m_iRankingEnd == src.m_iRankingEnd && + m_bCommonItem == src.m_bCommonItem && + m_ulAwardItemId == src.m_ulAwardItemId && + m_ulAwardItemNum == src.m_ulAwardItemNum && + m_lPeriod == src.m_lPeriod); + } } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct AWARD_MONSTERS_SUMMONED + { + public uint m_ulMonsterNum; + public bool m_bRandChoose; + public uint m_ulSummonRadius; + public bool m_bDeathDisappear; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.MAX_MONSTER_SUMMONED)] + public MONSTERS_SUMMONED[] m_Monsters; + + public int MarshalBasicData(byte[] pData) + { + int offset = 0; + + pData[offset] = m_bRandChoose ? (byte)1 : (byte)0; + offset++; + + pData[offset] = (byte)m_ulSummonRadius; + offset++; + + pData[offset] = (byte)m_ulMonsterNum; + offset++; + + pData[offset] = m_bDeathDisappear ? (byte)1 : (byte)0; + offset++; + + int sz = Marshal.SizeOf(typeof(MONSTERS_SUMMONED)) * (int)m_ulMonsterNum; + if (sz > 0) + { + // Copy MONSTERS_SUMMONED array to byte array + GCHandle handle = GCHandle.Alloc(m_Monsters, GCHandleType.Pinned); + try + { + IntPtr ptr = handle.AddrOfPinnedObject(); + Marshal.Copy(ptr, pData, offset, sz); + } + finally + { + handle.Free(); + } + offset += sz; + } + + return offset; + } + + public int UnmarshalBasicData(byte[] pData) + { + int offset = 0; + + m_bRandChoose = pData[offset] != 0; + offset++; + + m_ulSummonRadius = pData[offset]; + offset++; + + m_ulMonsterNum = pData[offset]; + offset++; + + m_bDeathDisappear = pData[offset] != 0; + offset++; + + if (m_ulMonsterNum > 0) + { + m_Monsters = new MONSTERS_SUMMONED[m_ulMonsterNum]; + + int sz = Marshal.SizeOf(typeof(MONSTERS_SUMMONED)) * (int)m_ulMonsterNum; + // Copy byte array to MONSTERS_SUMMONED array + for (uint i = 0; i < m_ulMonsterNum; i++) + { + IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(MONSTERS_SUMMONED))); + try + { + Marshal.Copy(pData, offset, ptr, Marshal.SizeOf(typeof(MONSTERS_SUMMONED))); + m_Monsters[i] = (MONSTERS_SUMMONED)Marshal.PtrToStructure(ptr, typeof(MONSTERS_SUMMONED)); + } + finally + { + Marshal.FreeHGlobal(ptr); + } + offset += Marshal.SizeOf(typeof(MONSTERS_SUMMONED)); + } + } + + return offset; + } + + public static bool operator ==(AWARD_MONSTERS_SUMMONED a, AWARD_MONSTERS_SUMMONED b) + { + if (a.m_ulMonsterNum != b.m_ulMonsterNum) + { + return false; + } + + for (uint i = 0; i < a.m_ulMonsterNum; ++i) + { + if (!(a.m_Monsters[i].Equals(b.m_Monsters[i]))) + { + return false; + } + } + + return (a.m_bRandChoose == b.m_bRandChoose && + a.m_ulSummonRadius == b.m_ulSummonRadius && + a.m_bDeathDisappear == b.m_bDeathDisappear); + } + + public static bool operator !=(AWARD_MONSTERS_SUMMONED a, AWARD_MONSTERS_SUMMONED b) + { + return !(a == b); + } + + public override bool Equals(object obj) + { + if (obj is AWARD_MONSTERS_SUMMONED) + return this == (AWARD_MONSTERS_SUMMONED)obj; + return false; + } + + public override int GetHashCode() + { + return m_ulMonsterNum.GetHashCode() ^ + m_bRandChoose.GetHashCode() ^ + m_ulSummonRadius.GetHashCode() ^ + m_bDeathDisappear.GetHashCode(); + } + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct AWARD_PQ_RANKING + { + public bool m_bAwardByProf; + public uint m_ulRankingAwardNum; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.MAX_AWARD_PQ_RANKING)] + public RANKING_AWARD[] m_RankingAward; + + public int MarshalBasicData(byte[] pData) + { + int offset = 0; + + pData[offset] = m_bAwardByProf ? (byte)1 : (byte)0; + offset++; + + pData[offset] = (byte)m_ulRankingAwardNum; + offset++; + + int sz = Marshal.SizeOf(typeof(RANKING_AWARD)) * (int)m_ulRankingAwardNum; + if (sz > 0) + { + // Copy RANKING_AWARD array to byte array + GCHandle handle = GCHandle.Alloc(m_RankingAward, GCHandleType.Pinned); + try + { + IntPtr ptr = handle.AddrOfPinnedObject(); + Marshal.Copy(ptr, pData, offset, sz); + } + finally + { + handle.Free(); + } + offset += sz; + } + + return offset; + } + + public int UnmarshalBasicData(byte[] pData) + { + int offset = 0; + + m_bAwardByProf = pData[offset] != 0; + offset++; + + m_ulRankingAwardNum = pData[offset]; + offset++; + + if (m_ulRankingAwardNum > 0) + { + m_RankingAward = new RANKING_AWARD[m_ulRankingAwardNum]; + + int sz = Marshal.SizeOf(typeof(RANKING_AWARD)) * (int)m_ulRankingAwardNum; + // Copy byte array to RANKING_AWARD array + for (uint i = 0; i < m_ulRankingAwardNum; i++) + { + IntPtr ptr = Marshal.AllocHGlobal(Marshal.SizeOf(typeof(RANKING_AWARD))); + try + { + Marshal.Copy(pData, offset, ptr, Marshal.SizeOf(typeof(RANKING_AWARD))); + m_RankingAward[i] = (RANKING_AWARD)Marshal.PtrToStructure(ptr, typeof(RANKING_AWARD)); + } + finally + { + Marshal.FreeHGlobal(ptr); + } + offset += Marshal.SizeOf(typeof(RANKING_AWARD)); + } + } + + return offset; + } + + public static bool operator ==(AWARD_PQ_RANKING a, AWARD_PQ_RANKING b) + { + if (a.m_bAwardByProf != b.m_bAwardByProf) + { + return false; + } + if (a.m_ulRankingAwardNum != b.m_ulRankingAwardNum) + { + return false; + } + + for (uint i = 0; i < a.m_ulRankingAwardNum; ++i) + { + if (!(a.m_RankingAward[i].Equals(b.m_RankingAward[i]))) + { + return false; + } + } + return true; + } + + public static bool operator !=(AWARD_PQ_RANKING a, AWARD_PQ_RANKING b) + { + return !(a == b); + } + + public override bool Equals(object obj) + { + if (obj is AWARD_PQ_RANKING) + return this == (AWARD_PQ_RANKING)obj; + return false; + } + + public override int GetHashCode() + { + return m_bAwardByProf.GetHashCode() ^ m_ulRankingAwardNum.GetHashCode(); + } + } + + public class TaskTemplUtils + { + /// + /// 必须定义operator == // Must define operator == + /// + /// The type of the objects to compare + /// First object to compare + /// Second object to compare + /// True if both objects are equal or both are null + public static bool CompareTwoPointer(T_NAME p1, T_NAME p2) + { + if (p1 == null && p2 == null) + { + return true; + } + else if (p1 != null && p2 != null) + { + return p1.Equals(p2); + } + else + return false; + } + } + + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct task_tm + { + public int year; + public int month; + public int day; + public int hour; + public int min; + public int wday; + } + + // Define task_team_member_info struct required by TEAM_MEM_WANTED + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct task_team_member_info + { + public uint m_ulLevel; + public uint m_ulOccupation; + public int m_iForce; + public bool m_bMale; + } + + // Race-occupation mapping array + public static class TaskTemplMapping + { + public static readonly uint[] _race_occ_map = new uint[TaskTemplConstants.MAX_OCCUPATIONS]; + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct TEAM_MEM_WANTED + { + public uint m_ulLevelMin; + public uint m_ulLevelMax; + public uint m_ulRace; + public uint m_ulOccupation; + public uint m_ulGender; + public uint m_ulMinCount; + public uint m_ulMaxCount; + public uint m_ulTask; + public int m_iForce; + // public uint m_ulTeamMemsItemWanted; + // public TEAM_MEM_ITEM_WANTED[] m_TeamMemItemWanted; //[MAX_ITEM_WANTED]; + // public bool m_bJustCheck; + + // Initialize fields with default values to avoid constructor issues + public static TEAM_MEM_WANTED Create() + { + TEAM_MEM_WANTED result = new TEAM_MEM_WANTED(); + result.Init(); + return result; + } + + public bool IsMeetBaseInfo(task_team_member_info pInfo) + { + if (m_ulLevelMin != 0 && pInfo.m_ulLevel < m_ulLevelMin) return false; + + if (m_ulLevelMax != 0 && pInfo.m_ulLevel > m_ulLevelMax) return false; + + if (m_ulRace != 0) + { + if (pInfo.m_ulOccupation >= TaskTemplConstants.MAX_OCCUPATIONS) return false; + if (TaskTemplMapping._race_occ_map[pInfo.m_ulOccupation] != m_ulRace) return false; + } + else if (m_ulOccupation != TaskTemplConstants.INVALID_VAL && pInfo.m_ulOccupation != m_ulOccupation) + return false; + + if (m_iForce != 0) + { + if (m_iForce == -1) + { + if (pInfo.m_iForce == 0) + return false; + } + else if (pInfo.m_iForce != m_iForce) return false; + } + +#if !_TASK_CLIENT + if (m_ulGender == TaskTemplConstants.TASK_GENDER_MALE && !pInfo.m_bMale + || m_ulGender == TaskTemplConstants.TASK_GENDER_FEMALE && pInfo.m_bMale) + return false; +#endif + + return true; + } + + public bool IsMeetCount(uint ulCount) + { + if (m_ulMinCount != 0 && ulCount < m_ulMinCount) return false; + + if (m_ulMaxCount != 0 && ulCount > m_ulMaxCount) return false; + + return true; + } + + public void Init() + { + m_ulLevelMin = 0; + m_ulLevelMax = 0; + m_ulRace = 0; + m_ulOccupation = TaskTemplConstants.INVALID_VAL; + m_ulGender = 0; + m_ulMinCount = 0; + m_ulMaxCount = 0; + m_ulTask = 0; + m_iForce = 0; + // m_ulTeamMemsItemWanted = 0; + // m_TeamMemItemWanted = null; + // m_bJustCheck = false; + } + + public bool IsValid() + { + return !( + m_ulLevelMin == 0 && + m_ulLevelMax == 0 && + m_ulRace == 0 && + m_ulOccupation == TaskTemplConstants.INVALID_VAL && + m_ulGender == 0 && + m_ulMinCount == 0 && + m_ulMaxCount == 0 && + m_ulTask == 0 // && + // m_ulTeamMemsItemWanted == 0 && + // m_TeamMemItemWanted == null && + // m_bJustCheck == false + ); + } + + public static bool operator ==(TEAM_MEM_WANTED a, TEAM_MEM_WANTED b) + { + return ( + a.m_ulLevelMin == b.m_ulLevelMin && + a.m_ulLevelMax == b.m_ulLevelMax && + a.m_ulRace == b.m_ulRace && + a.m_ulOccupation == b.m_ulOccupation && + a.m_ulGender == b.m_ulGender && + a.m_ulMinCount == b.m_ulMinCount && + a.m_ulMaxCount == b.m_ulMaxCount && + a.m_ulTask == b.m_ulTask // && + // a.m_ulTeamMemsItemWanted == b.m_ulTeamMemsItemWanted && + // *a.m_TeamMemItemWanted == *(b.m_TeamMemItemWanted) && + // a.m_bJustCheck == b.m_bJustCheck + ); + } + + public static bool operator !=(TEAM_MEM_WANTED a, TEAM_MEM_WANTED b) + { + return !(a == b); + } + + public override bool Equals(object obj) + { + if (obj is TEAM_MEM_WANTED) + return this == (TEAM_MEM_WANTED)obj; + return false; + } + + public override int GetHashCode() + { + return m_ulLevelMin.GetHashCode() ^ m_ulLevelMax.GetHashCode() ^ m_ulRace.GetHashCode() ^ m_ulOccupation.GetHashCode(); + } + } + + + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct AWARD_ITEMS_CAND + { + public uint m_ulAwardItems; + public uint m_ulAwardCmnItems; + public uint m_ulAwardTskItems; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.MAX_ITEM_AWARD)] + public ITEM_WANTED[] m_AwardItems; + public bool m_bRandChoose; + + public int MarshalBasicData(byte[] pData) + { + int offset = 0; + + pData[offset] = m_bRandChoose ? (byte)1 : (byte)0; + offset++; + + pData[offset] = (byte)m_ulAwardItems; + offset++; + + int sz = Marshal.SizeOf(typeof(ITEM_WANTED)) * (int)m_ulAwardItems; + if (sz > 0) + { + // Copy ITEM_WANTED array data + for (int i = 0; i < m_ulAwardItems; i++) + { + // Would need to implement proper marshaling here + // For now, just increase offset by appropriate size + offset += Marshal.SizeOf(typeof(ITEM_WANTED)); + } + } + + return offset; + } + + public int UnmarshalBasicData(byte[] pData) + { + int offset = 0; + + m_bRandChoose = pData[offset] != 0; + offset++; + + m_ulAwardItems = pData[offset]; + offset++; + + if (m_ulAwardItems > 0) + { + m_AwardItems = new ITEM_WANTED[m_ulAwardItems]; + + // Copy ITEM_WANTED array data + for (uint i = 0; i < m_ulAwardItems; i++) + { + // Would need to implement proper unmarshaling here + // For now, just increase offset by appropriate size + offset += Marshal.SizeOf(typeof(ITEM_WANTED)); + + if (m_AwardItems[i].m_bCommonItem) + m_ulAwardCmnItems++; + else + m_ulAwardTskItems++; + } + } + + return offset; + } + + public static bool operator ==(AWARD_ITEMS_CAND a, AWARD_ITEMS_CAND b) + { + if (a.m_ulAwardItems != b.m_ulAwardItems) + return false; + + for (uint i = 0; i < a.m_ulAwardItems; ++i) + { + if (!(a.m_AwardItems[i].Equals(b.m_AwardItems[i]))) + return false; + } + + return (a.m_ulAwardCmnItems == b.m_ulAwardCmnItems && + a.m_ulAwardTskItems == b.m_ulAwardTskItems && + a.m_bRandChoose == b.m_bRandChoose); + } + + public static bool operator !=(AWARD_ITEMS_CAND a, AWARD_ITEMS_CAND b) + { + return !(a == b); + } + + public override bool Equals(object obj) + { + if (obj is AWARD_ITEMS_CAND) + return this == (AWARD_ITEMS_CAND)obj; + return false; + } + + public override int GetHashCode() + { + return m_ulAwardItems.GetHashCode() ^ + m_ulAwardCmnItems.GetHashCode() ^ + m_ulAwardTskItems.GetHashCode() ^ + m_bRandChoose.GetHashCode(); + } + } + + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct AWARD_DATA + { + public AWARD_DATA(bool initialize = true) + { + m_ulGoldNum = 0; + m_ulExp = 0; + m_ulRealmExp = 0; + m_bExpandRealmLevelMax = false; + m_ulNewTask = 0; + m_ulSP = 0; + m_lReputation = 0; + m_ulNewPeriod = 0; + m_ulNewRelayStation = 0; + m_ulStorehouseSize = 0; + m_ulStorehouseSize2 = 0; + m_ulStorehouseSize3 = 0; + m_ulStorehouseSize4 = 0; + m_lInventorySize = 0; + m_ulPetInventorySize = 0; + m_ulFuryULimit = 0; + m_ulTransWldId = 0; + m_TransPt = new ZONE_VERT(); + m_lMonsCtrl = 0; + m_bTrigCtrl = false; + m_bUseLevCo = false; + m_bDivorce = false; + m_bSendMsg = false; + m_nMsgChannel = 0; + m_ulCandItems = 0; + m_CandItems = null; + m_ulSummonedMonsters = 0; + m_SummonedMonsters = new AWARD_MONSTERS_SUMMONED(); + m_bAwardDeath = false; + m_bAwardDeathWithLoss = false; + m_ulDividend = 0; + m_bAwardSkill = false; + m_iAwardSkillID = 0; + m_iAwardSkillLevel = 0; + m_ulSpecifyContribTaskID = 0; + m_ulSpecifyContribSubTaskID = 0; + m_ulSpecifyContrib = 0; + m_ulContrib = 0; + m_ulRandContrib = 0; + m_ulLowestcontrib = 0; + m_iFactionContrib = 0; + m_iFactionExpContrib = 0; + m_ulPQRankingAwardCnt = 0; + m_PQRankingAward = new AWARD_PQ_RANKING(); + m_bMulti = false; + m_nNumType = 0; + m_lNum = 0; + m_ulChangeKeyCnt = 0; + m_plChangeKey = null; + m_plChangeKeyValue = null; + m_pbChangeType = null; + m_ulHistoryChangeCnt = 0; + m_plHistoryChangeKey = null; + m_plHistoryChangeKeyValue = null; + m_pbHistoryChangeType = null; + m_ulDisplayKeyCnt = 0; + m_plDisplayKey = null; + m_ulExpCnt = 0; + m_pszExp = null; + m_pExpArr = null; + m_ulTaskCharCnt = 0; + m_pTaskChar = null; + m_iForceContribution = 0; + m_iForceReputation = 0; + m_iForceActivity = 0; + m_iForceSetRepu = 0; + m_iTaskLimit = 0; + m_ulTitleNum = 0; + m_pTitleAward = null; + m_iLeaderShip = 0; + m_iWorldContribution = 0; + +#if TASK_TEMPL_EDITOR + m_CandItems = new AWARD_ITEMS_CAND[TaskTemplConstants.MAX_AWARD_CANDIDATES]; + + m_SummonedMonsters = new AWARD_MONSTERS_SUMMONED(); + + m_PQRankingAward = new AWARD_PQ_RANKING(); + + m_pTitleAward = new TITLE_AWARD[TaskTemplConstants.MAX_TITLE_NUM]; +#endif + } + + public uint m_ulGoldNum; + public uint m_ulExp; + public uint m_ulRealmExp; // 境界经验 // Realm experience + public bool m_bExpandRealmLevelMax; // 境界等级10整级时提升境界等级上限 // Increase realm level upper limit when realm level is at level 10 + public uint m_ulNewTask; + public uint m_ulSP; + public int m_lReputation; + public uint m_ulNewPeriod; + public uint m_ulNewRelayStation; + public uint m_ulStorehouseSize; + public uint m_ulStorehouseSize2; + public uint m_ulStorehouseSize3; + public uint m_ulStorehouseSize4; // 账号仓库 // Account warehouse + public int m_lInventorySize; + public uint m_ulPetInventorySize; + public uint m_ulFuryULimit; + public uint m_ulTransWldId; + public ZONE_VERT m_TransPt; + public int m_lMonsCtrl; + public bool m_bTrigCtrl; + public bool m_bUseLevCo; + public bool m_bDivorce; + public bool m_bSendMsg; + public int m_nMsgChannel; + public uint m_ulCandItems; + public AWARD_ITEMS_CAND[] m_CandItems; //[MAX_AWARD_CANDIDATES]; + public uint m_ulSummonedMonsters; + public AWARD_MONSTERS_SUMMONED m_SummonedMonsters; + public bool m_bAwardDeath; + public bool m_bAwardDeathWithLoss; + public uint m_ulDividend; // 鸿利值 // Dividend value + + public bool m_bAwardSkill; // 是否奖励技能 // Whether to reward skill [Yongdong, 2010-1-6] + public int m_iAwardSkillID; // 技能ID // Skill ID + public int m_iAwardSkillLevel;// 技能等级 // Skill level + +//////////////////////////////////////////////////// PQ任务奖励 start // PQ task reward start + + public uint m_ulSpecifyContribTaskID; // 指定任务贡献度的任务id // Task ID for specified contribution + public uint m_ulSpecifyContribSubTaskID; // 指定任务贡献度的子任务ID // Subtask ID for specified contribution + public uint m_ulSpecifyContrib; // 指定任务贡献度 // Specified task contribution + + // 仅PQ子任务专用 // Only for PQ subtasks + public uint m_ulContrib; // 贡献度 // Contribution + public uint m_ulRandContrib; // 随机贡献度 // Random contribution + public uint m_ulLowestcontrib; // 最低贡献度 // Minimum contribution + + // 帮派贡献度 // Faction contribution + public int m_iFactionContrib; + public int m_iFactionExpContrib; + + public uint m_ulPQRankingAwardCnt; + public AWARD_PQ_RANKING m_PQRankingAward; + +//////////////////////////////////////////////////// PQ任务奖励 end // PQ task reward end + + // 改变全局key/value // Change global key/value + public uint m_ulChangeKeyCnt; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.TASK_AWARD_MAX_CHANGE_VALUE)] + public int[] m_plChangeKey; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.TASK_AWARD_MAX_CHANGE_VALUE)] + public int[] m_plChangeKeyValue; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.TASK_AWARD_MAX_CHANGE_VALUE)] + public bool[] m_pbChangeType; + + // 修改历史进度 // Modify historical progress + public uint m_ulHistoryChangeCnt; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.TASK_AWARD_MAX_CHANGE_VALUE)] + public int[] m_plHistoryChangeKey; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.TASK_AWARD_MAX_CHANGE_VALUE)] + public int[] m_plHistoryChangeKeyValue; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.TASK_AWARD_MAX_CHANGE_VALUE)] + public bool[] m_pbHistoryChangeType; + + // 倍率 // Multiplier + public bool m_bMulti; + public int m_nNumType; + public int m_lNum; + + // 显示全局key/value // Display global key/value + public uint m_ulDisplayKeyCnt; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.TASK_AWARD_MAX_DISPLAY_VALUE)] + public int[] m_plDisplayKey; + + // 显示全局变量表达式 // Display global variable expressions + public uint m_ulExpCnt; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.TASK_AWARD_MAX_DISPLAY_EXP_CNT)] + public string[] m_pszExp; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.TASK_AWARD_MAX_DISPLAY_EXP_CNT)] + public TASK_EXPRESSION[] m_pExpArr; + + // 显示全局变量表达式提示字符串 // Display global variable expression prompt strings + public uint m_ulTaskCharCnt; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.TASK_AWARD_MAX_DISPLAY_EXP_CNT)] + public ushort[] m_pTaskChar; + + // 势力相关 // Force-related + public int m_iForceContribution; + public int m_iForceReputation; + public int m_iForceActivity; + public int m_iForceSetRepu; + + public int m_iTaskLimit; + public uint m_ulTitleNum; + public TITLE_AWARD[] m_pTitleAward; + public int m_iLeaderShip; + + public int m_iWorldContribution; // 世界贡献度 // World contribution + + public bool HasAward() + { + return m_ulGoldNum != 0 + || m_ulExp != 0 + || m_ulNewTask != 0 + || m_ulSP != 0 + || m_lReputation != 0 + || m_ulNewPeriod != 0 + || m_ulNewRelayStation != 0 + || m_ulStorehouseSize != 0 + || m_ulStorehouseSize2 != 0 + || m_ulStorehouseSize3 != 0 + || m_ulStorehouseSize4 != 0 + || m_lInventorySize != 0 + || m_ulPetInventorySize != 0 + || m_ulFuryULimit != 0 + || m_bDivorce + || m_bSendMsg + || m_bAwardDeath + || m_ulCandItems != 0 + || m_ulSummonedMonsters != 0 + || m_ulSpecifyContrib != 0 + || m_ulSpecifyContribTaskID != 0 + || m_ulContrib != 0 + || m_ulRandContrib != 0 + || m_ulDividend != 0 + || m_ulPQRankingAwardCnt != 0 + || m_ulSpecifyContribSubTaskID != 0 + || m_bAwardSkill + || m_iFactionContrib != 0 + || m_iFactionExpContrib != 0 + || m_iForceActivity != 0 + || m_iForceContribution != 0 + || m_iForceReputation != 0 + || m_iForceSetRepu != 0 + || m_iTaskLimit != 0 + || m_ulRealmExp != 0 + || m_bExpandRealmLevelMax; + } + + public int MarshalBasicData(byte[] pData) + { + int offset = 0; + + int mask = 0; + BitConverter.GetBytes(mask).CopyTo(pData, offset); + offset += 4; + + if (m_ulGoldNum != 0) + { + mask |= 1; + BitConverter.GetBytes((int)m_ulGoldNum).CopyTo(pData, offset); + offset += sizeof(int); + } + + if (m_ulExp != 0) + { + mask |= 1 << 1; + BitConverter.GetBytes((int)m_ulExp).CopyTo(pData, offset); + offset += sizeof(int); + } + + if (m_ulSP != 0) + { + mask |= 1 << 2; + BitConverter.GetBytes((int)m_ulSP).CopyTo(pData, offset); + offset += sizeof(int); + } + + if (m_lReputation != 0) + { + mask |= 1 << 3; + BitConverter.GetBytes(m_lReputation).CopyTo(pData, offset); + offset += sizeof(int); + } + + if (m_ulCandItems != 0) + { + mask |= 1 << 4; + + pData[offset] = (byte)m_ulCandItems; + offset++; + + for (int i = 0; i < m_ulCandItems; i++) + { + offset += m_CandItems[i].MarshalBasicData(pData.AsSpan(offset).ToArray()); + } + } + + if (m_ulSummonedMonsters != 0) + { + mask |= 1 << 5; + + pData[offset] = (byte)m_ulSummonedMonsters; + offset++; + + offset += m_SummonedMonsters.MarshalBasicData(pData.AsSpan(offset).ToArray()); + } + + if (m_ulPQRankingAwardCnt != 0) + { + mask |= 1 << 6; + + pData[offset] = (byte)m_ulPQRankingAwardCnt; + offset++; + + offset += m_PQRankingAward.MarshalBasicData(pData.AsSpan(offset).ToArray()); + } + + // Update the mask + BitConverter.GetBytes(mask).CopyTo(pData, 0); + + return offset; + } + + public int UnmarshalBasicData(byte[] pData) + { + int offset = 0; + + int mask = BitConverter.ToInt32(pData, offset); + offset += sizeof(int); + + if ((mask & 1) != 0) + { + m_ulGoldNum = (uint)BitConverter.ToInt32(pData, offset); + offset += 4; + } + + if ((mask & (1 << 1)) != 0) + { + m_ulExp = (uint)BitConverter.ToInt32(pData, offset); + offset += 4; + } + + if ((mask & (1 << 2)) != 0) + { + m_ulSP = (uint)BitConverter.ToInt32(pData, offset); + offset += 4; + } + + if ((mask & (1 << 3)) != 0) + { + m_lReputation = BitConverter.ToInt32(pData, offset); + offset += 4; + } + + if ((mask & (1 << 4)) != 0) + { + m_ulCandItems = pData[offset]; + offset++; + + if (m_ulCandItems != 0) + { +#if !TASK_TEMPL_EDITOR + m_CandItems = new AWARD_ITEMS_CAND[m_ulCandItems]; +#endif + + for (uint i = 0; i < m_ulCandItems; i++) + { + offset += m_CandItems[i].UnmarshalBasicData(pData.AsSpan(offset).ToArray()); + } + } + } + + if ((mask & (1 << 5)) != 0) + { + m_ulSummonedMonsters = pData[offset]; + offset++; + + if (m_ulSummonedMonsters != 0) + { +#if !TASK_TEMPL_EDITOR + m_SummonedMonsters = new AWARD_MONSTERS_SUMMONED(); +#endif + + offset += m_SummonedMonsters.UnmarshalBasicData(pData.AsSpan(offset).ToArray()); + } + } + + if ((mask & (1 << 6)) != 0) + { + m_ulPQRankingAwardCnt = pData[offset]; + offset++; + + if (m_ulPQRankingAwardCnt != 0) + { +#if !TASK_TEMPL_EDITOR + m_PQRankingAward = new AWARD_PQ_RANKING(); +#endif + + offset += m_PQRankingAward.UnmarshalBasicData(pData.AsSpan(offset).ToArray()); + } + } + + return offset; + } + + public static bool CompareTwoPointer(T p1, T p2) where T : class + { + if (p1 == null && p2 == null) + { + return true; + } + else if (p1 != null && p2 != null) + { + return p1.Equals(p2); + } + else + return false; + } + + public static bool operator ==(AWARD_DATA a, AWARD_DATA b) + { + if (a.m_ulCandItems != b.m_ulCandItems || a.m_ulSummonedMonsters != b.m_ulSummonedMonsters || + a.m_ulChangeKeyCnt != b.m_ulChangeKeyCnt || a.m_ulDisplayKeyCnt != b.m_ulDisplayKeyCnt || + a.m_ulExpCnt != b.m_ulExpCnt || a.m_ulTaskCharCnt != b.m_ulTaskCharCnt || + a.m_ulHistoryChangeCnt != b.m_ulHistoryChangeCnt) + { + return false; + } + + for (uint i = 0; i < a.m_ulCandItems; ++i) + { + if (!(a.m_CandItems[i] == b.m_CandItems[i])) + { + return false; + } + } + + if (!TaskTemplUtils.CompareTwoPointer(a.m_SummonedMonsters, b.m_SummonedMonsters)) + { + return false; + } + + for (uint i = 0; i < a.m_ulChangeKeyCnt; ++i) + { + if (a.m_plChangeKey[i] != b.m_plChangeKey[i] || + a.m_plChangeKeyValue[i] != b.m_plChangeKeyValue[i] || + a.m_pbChangeType[i] != b.m_pbChangeType[i]) + { + return false; + } + } + + for (uint i = 0; i < a.m_ulHistoryChangeCnt; ++i) + { + if (a.m_plHistoryChangeKey[i] != b.m_plHistoryChangeKey[i] || + a.m_plHistoryChangeKeyValue[i] != b.m_plHistoryChangeKeyValue[i] || + a.m_pbHistoryChangeType[i] != b.m_pbHistoryChangeType[i]) + { + return false; + } + } + + for (uint i = 0; i < a.m_ulDisplayKeyCnt; ++i) + { + if (a.m_plDisplayKey[i] != b.m_plDisplayKey[i]) + { + return false; + } + } + + if (!TaskTemplUtils.CompareTwoPointer(a.m_PQRankingAward, b.m_PQRankingAward)) + { + return false; + } + + return (a.m_ulGoldNum == b.m_ulGoldNum && + a.m_ulExp == b.m_ulExp && + a.m_ulNewTask == b.m_ulNewTask && + a.m_ulSP == b.m_ulSP && + a.m_lReputation == b.m_lReputation && + a.m_ulNewPeriod == b.m_ulNewPeriod && + a.m_ulNewRelayStation == b.m_ulNewRelayStation && + a.m_ulStorehouseSize == b.m_ulStorehouseSize && + a.m_ulStorehouseSize2 == b.m_ulStorehouseSize2 && + a.m_ulStorehouseSize3 == b.m_ulStorehouseSize3 && + a.m_ulStorehouseSize4 == b.m_ulStorehouseSize4 && + a.m_lInventorySize == b.m_lInventorySize && + a.m_ulPetInventorySize == b.m_ulPetInventorySize && + a.m_ulFuryULimit == b.m_ulFuryULimit && + a.m_ulTransWldId == b.m_ulTransWldId && + a.m_TransPt.Equals(b.m_TransPt) && + a.m_lMonsCtrl == b.m_lMonsCtrl && + a.m_bTrigCtrl == b.m_bTrigCtrl && + a.m_bUseLevCo == b.m_bUseLevCo && + a.m_bDivorce == b.m_bDivorce && + a.m_bSendMsg == b.m_bSendMsg && + a.m_nMsgChannel == b.m_nMsgChannel && + a.m_bAwardDeath == b.m_bAwardDeath && + a.m_bAwardDeathWithLoss == b.m_bAwardDeathWithLoss && + a.m_ulDividend == b.m_ulDividend && + a.m_bAwardSkill == b.m_bAwardSkill && + a.m_iAwardSkillID == b.m_iAwardSkillID && + a.m_iAwardSkillLevel == b.m_iAwardSkillLevel && + a.m_ulSpecifyContribTaskID == b.m_ulSpecifyContribTaskID && + a.m_ulSpecifyContribSubTaskID == b.m_ulSpecifyContribSubTaskID && + a.m_ulSpecifyContrib == b.m_ulSpecifyContrib && + a.m_ulContrib == b.m_ulContrib && + a.m_ulRandContrib == b.m_ulRandContrib && + a.m_ulLowestcontrib == b.m_ulLowestcontrib && + a.m_iFactionContrib == b.m_iFactionContrib && + a.m_iFactionExpContrib == b.m_iFactionExpContrib && + a.m_ulPQRankingAwardCnt == b.m_ulPQRankingAwardCnt && + a.m_bMulti == b.m_bMulti && + a.m_nNumType == b.m_nNumType && + a.m_lNum == b.m_lNum + ); + } + + public static bool operator !=(AWARD_DATA a, AWARD_DATA b) + { + return !(a == b); + } + + public override bool Equals(object obj) + { + if (obj is AWARD_DATA) + { + return this == (AWARD_DATA)obj; + } + return false; + } + + public override int GetHashCode() + { + return m_ulGoldNum.GetHashCode() ^ + m_ulExp.GetHashCode() ^ + m_lReputation.GetHashCode() ^ + m_ulSP.GetHashCode(); + } + } + + + public enum task_tm_type { enumTaskTimeDate = 0, @@ -120,6 +1506,41 @@ namespace PerfectWorld.Scripts.Task enumTMSimpleClientTaskForceNavi // Force navigation } + [StructLayout(LayoutKind.Sequential, Pack = 1)] + public struct COMPARE_KEY_VALUE + { + public int nLeftType; + public long lLeftNum; + public int nCompOper; + public int nRightType; + public long lRightNum; + + public static bool operator ==(COMPARE_KEY_VALUE a, COMPARE_KEY_VALUE b) + { + return (a.nLeftType == b.nLeftType && a.lLeftNum == b.lLeftNum && + a.nCompOper == b.nCompOper && a.nRightType == b.nRightType && + a.lRightNum == b.lRightNum); + } + + public static bool operator !=(COMPARE_KEY_VALUE a, COMPARE_KEY_VALUE b) + { + return !(a == b); + } + + public override bool Equals(object obj) + { + if (obj is COMPARE_KEY_VALUE) + return this == (COMPARE_KEY_VALUE)obj; + return false; + } + + public override int GetHashCode() + { + return nLeftType.GetHashCode() ^ lLeftNum.GetHashCode() ^ nCompOper.GetHashCode() ^ + nRightType.GetHashCode() ^ lRightNum.GetHashCode(); + } + } + public struct Task_Region { public ZONE_VERT zvMin; @@ -156,102 +1577,111 @@ namespace PerfectWorld.Scripts.Task public struct ATaskTemplFixedData { - /* Task object properties */ - - // Task ID + // 任务id // Task ID public uint m_ID; - // Task name - [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskConstant.MAX_TASK_NAME_LEN)] - public ushort[] m_szName; - // Task signature + // 任务名称 // Task name + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.MAX_TASK_NAME_LEN)] + public char[] m_szName; + + // 任务署名 // Task signature public bool m_bHasSign; + public string m_pszSignature; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskConstant.MAX_TASK_NAME_LEN)] - public ushort[] m_pszSignature; - // Task type + // 任务类型 // Task type public uint m_ulType; - // Time limit + + // 时间限制 // Time limit public uint m_ulTimeLimit; - // Task fails when offline + // 下线任务失败 // Task fails when offline public bool m_bOfflineFail; - // Absolute failure time + // 任务失败时间 // Task failure time public bool m_bAbsFail; public task_tm m_tmAbsFailTime; - // Do not take items during task validation + // 任务开启物品检验不收取 // Don't take items when validating task start public bool m_bItemNotTakeOff; - // Whether using absolute time + // 是否绝对时间 // Whether absolute time public bool m_bAbsTime; - // Number of time periods - public ulong m_ulTimetable; - // Time method - [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskConstant.MAX_TIMETABLE_SIZE)] - public byte[] m_tmType; - // Start time for delivery - public task_tm[] m_tmStart; // [MAX_TIMETABLE_SIZE] - // End time for delivery - public task_tm[] m_tmEnd; // [MAX_TIMETABLE_SIZE] - // Delivery frequency - public long m_lAvailFrequency; - public long m_lPeriodLimit; - // Execute single subtask + + // 时间段个数 // Number of time periods + public uint m_ulTimetable; + + // 时间方式 // Time method + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.MAX_TIMETABLE_SIZE)] + public char[] m_tmType; + + // 发放起始时间 // Distribution start time + public task_tm[] m_tmStart; + + // 发放终止时间 // Distribution end time + public task_tm[] m_tmEnd; + + // 发放频率 // Distribution frequency + public int m_lAvailFrequency; + public int m_lPeriodLimit; + + // 选择单个子任务执行 // Execute single subtask public bool m_bChooseOne; - // Randomly rotate single subtask execution + + // 随机旋转单个子任务执行 // Randomly rotate single subtask execution public bool m_bRandOne; - // Whether subtasks have order + + // 子任务是否有顺序 // Whether subtasks have order public bool m_bExeChildInOrder; - // Whether parent task fails when subtask fails + + // 失败后是否认为父任务也失败 // Whether parent task fails when subtask fails public bool m_bParentAlsoFail; - // Whether parent task succeeds when subtask succeeds + + // 子任务成功后父任务成功 // Parent task succeeds when subtask succeeds public bool m_bParentAlsoSucc; - // Whether task can be abandoned + + // 能否放弃此任务 // Whether task can be abandoned public bool m_bCanGiveUp; - // Whether task can be repeated + + // 是否可重复完成 // Whether task can be repeated public bool m_bCanRedo; - // Whether task can be redone after failure + + // 失败后是否可重新完成 // Whether task can be redone after failure public bool m_bCanRedoAfterFailure; - // Clear task on abandonment + + // 放弃清空任务 // Clear task when abandoned public bool m_bClearAsGiveUp; - // Whether recording is needed + + // 是否需要记录 // Whether recording is needed public bool m_bNeedRecord; - // Whether task fails when player dies + + // 玩家被杀死是否认为失败 // Whether task fails when player dies public bool m_bFailAsPlayerDie; - // Maximum number of receivers + + // 接受者上限 // Maximum number of receivers public uint m_ulMaxReceiver; - // Delivery zone + + // 发放区域 // Distribution area public bool m_bDelvInZone; public uint m_ulDelvWorld; public uint m_ulDelvRegionCnt; - - [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskConstant.MAX_TASKREGION)] public Task_Region[] m_pDelvRegion; - // Enter region task failure + // 进入区域任务失败 // Task fails when entering region public bool m_bEnterRegionFail; public uint m_ulEnterRegionWorld; public uint m_ulEnterRegionCnt; - //public ZONE_VERT m_EnterRegionMinVert; - //public ZONE_VERT m_EnterRegionMaxVert; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskConstant.MAX_TASKREGION)] public Task_Region[] m_pEnterRegion; - - // Leave region task failure + + // 离开区域任务失败 // Task fails when leaving region public bool m_bLeaveRegionFail; public uint m_ulLeaveRegionWorld; public uint m_ulLeaveRegionCnt; - //public ZONE_VERT m_LeaveRegionMinVert; - //public ZONE_VERT m_LeaveRegionMaxVert; - [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskConstant.MAX_TASKREGION)] public Task_Region[] m_pLeaveRegion; - // Leave force failure + // 离开阵营失败 // Fails when leaving force public bool m_bLeaveForceFail; - // Transport to specific point + // 传送到特定点 // Teleport to specific point public bool m_bTransTo; public uint m_ulTransWldId; public ZONE_VERT m_TransPt; @@ -330,41 +1760,293 @@ namespace PerfectWorld.Scripts.Task public bool m_bCompareItemAndInventory; public uint m_ulInventorySlotNum; -/////////////////////////////////////////////// PQ Task start - // 是否是PQ任务 - public bool m_bPQTask; - // PQ任务全局变量显示 - public uint m_ulPQExpCnt; + // PQ Task related // PQ任务相关 + public bool m_bPQTask; // Whether it is a PQ task // 是否是PQ任务 + public uint m_ulPQExpCnt; // PQ task global variable display // PQ任务全局变量显示 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.TASK_AWARD_MAX_DISPLAY_EXP_CNT)] + public string[] m_pszPQExp; // PQ expressions + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.TASK_AWARD_MAX_DISPLAY_EXP_CNT)] + public TASK_EXPRESSION[] m_pPQExpArr; // PQ expression arrays + public bool m_bPQSubTask; // Whether it is a PQ subtask // 是否PQ子任务 + public bool m_bClearContrib; // Clear contribution when task starts // 任务开始时清空贡献度 + public uint m_ulMonsterContribCnt; // Number of monster types // 怪物种类数量 + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.MAX_CONTRIB_MONSTERS)] + public MONSTERS_CONTRIB[] m_MonstersContrib; // Monster contribution settings // 怪物贡献度设定 + // Account Task related // 账号任务相关 + public int m_iPremNeedRecordTasksNum; // Number of completed record tasks // 记录完成结果任务完成个数 + public bool m_bShowByNeedRecordTasksNum; // Show by number of needed record tasks + public int m_iPremiseFactionContrib; // Faction contribution // 帮派贡献度 + public bool m_bShowByFactionContrib; // Show by faction contribution + public bool m_bAccountTaskLimit; // Whether account limits completion times // 是否账号限制完成次数 + public bool m_bRoleTaskLimit; // Whether role limits completion times // 是否角色限制完成次数 + public uint m_ulAccountTaskLimitCnt; // Account task limit count (deprecated) // 账号限制完成次数,废弃使用了 + public bool m_bLeaveFactionFail; // Fail when leaving faction + public bool m_bNotIncCntWhenFailed; // Don't increase count when failed // 是否失败时不增加完成次数 + public bool m_bNotClearItemWhenFailed; // Don't clear items when failed // 任务失败时不收取任务要求的物品 + public bool m_bDisplayInTitleTaskUI; // Show in title task UI // 是否显示在称号任务界面里 + /* 开启条件 */ /* Opening conditions */ - public uint m_ulNPCToProtect; - public uint m_ulProtectTimeLen; - public uint m_enumMethod; - public uint m_enumFinishType; - - // Required items - public ulong m_ulPremItems; - // public ItemWanted[] m_PremItems; // [MAX_ITEM_WANTED] + // 变身状态 // Transformation state + public byte m_ucPremiseTransformedForm; + public bool m_bShowByTransformed; + // 等级条件 // Level conditions + public uint m_ulPremise_Lev_Min; + public uint m_ulPremise_Lev_Max; + public uint m_bPremCheckMaxHistoryLevel; + public bool m_bShowByLev; + // 转生次数 // Reincarnation times + public bool m_bPremCheckReincarnation; + public uint m_ulPremReincarnationMin; + public uint m_ulPremReincarnationMax; + public bool m_bShowByReincarnation; + // 境界 // Realm level + public bool m_bPremCheckRealmLevel; + public uint m_ulPremRealmLevelMin; + public uint m_ulPremRealmLevelMax; + public bool m_bPremCheckRealmExpFull; + public bool m_bShowByRealmLevel; + // 所需道具 // Required items + public uint m_ulPremItems; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.MAX_ITEM_WANTED)] + public ITEM_WANTED[] m_PremItems; //[MAX_ITEM_WANTED]; public bool m_bShowByItems; public bool m_bPremItemsAnyOne; + // 发放道具 // Given items + public uint m_ulGivenItems; + public uint m_ulGivenCmnCount; + public uint m_ulGivenTskCount; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.MAX_ITEM_WANTED)] + public ITEM_WANTED[] m_GivenItems; //[MAX_ITEM_WANTED]; + // 押金 // Deposit + public uint m_ulPremise_Deposit; + public bool m_bShowByDeposit; + // 声望 // Reputation + public long m_lPremise_Reputation; + public long m_lPremise_RepuMax; + public bool m_bShowByRepu; + // 完成特定任务(成功?失败?),Task ID最高位1表示条件为失败,0为成功 // Complete specific tasks (success? failure?), Task ID highest bit 1 means failure condition, 0 means success condition + public uint m_ulPremise_Task_Count; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.MAX_PREM_TASK_COUNT)] + public uint[] m_ulPremise_Tasks; + public bool m_bShowByPreTask; + public uint m_ulPremise_Task_Least_Num; // 多个前提任务需要完成若干个 // Multiple prerequisite tasks need to complete a certain number + // 达到特定时期 // Reach specific period + public uint m_ulPremise_Period; + public bool m_bShowByPeriod; + // 帮派 // Faction + public uint m_ulPremise_Faction; + public int m_iPremise_FactionRole; + public bool m_bShowByFaction; - // Level condition - public ulong m_ulPremise_Lev_Min; - public ulong m_ulPremise_Lev_Max; - public ulong m_bPremCheckMaxHistoryLevel; - public bool m_bShowByLev; + // 性别 // Gender + public uint m_ulGender; + public bool m_bShowByGender; + // 职业限制 // Occupation restrictions + public uint m_ulOccupations; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.MAX_OCCUPATIONS)] + public uint[] m_Occupations; + public bool m_bShowByOccup; + // 夫妻 // Spouse + public bool m_bPremise_Spouse; + public bool m_bShowBySpouse; + public bool m_bPremiseWeddingOwner; + public bool m_bShowByWeddingOwner; + // GM + public bool m_bGM; + // 完美神盾用户 // Perfect Shield user + public bool m_bShieldUser; - // Dynamic task type - public string m_DynTaskType; + // 账号累计充值金额(下限&上限) // Account accumulated recharge amount (lower & upper limit) + public bool m_bShowByRMB; + public uint m_ulPremRMBMin; + public uint m_ulPremRMBMax; + + // 角色相关时间 // Character-related time + public bool m_bCharTime; + public bool m_bShowByCharTime; + public int m_iCharStartTime; + public int m_iCharEndTime; // 为0则为当前时间;为1则为m_tmCharEndTime指定时间; // 0 means current time; 1 means the time specified by m_tmCharEndTime; + public task_tm m_tmCharEndTime; + public uint m_ulCharTimeGreaterThan; - // Special award ID, used for events - public ulong m_ulSpecialAward; - // Whether to display in the title task UI - public bool m_bDisplayInTitleTaskUI; + // 关联任务 // Related tasks + public uint m_ulPremise_Cotask; + public uint m_ulCoTaskCond; + // 互斥任务 // Mutually exclusive tasks + public uint m_ulMutexTaskCount; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.MAX_MUTEX_TASK_COUNT)] + public uint[] m_ulMutexTasks; + // 生活技能级别 // Life skill levels + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.MAX_LIVING_SKILLS)] + public long[] m_lSkillLev; + // 动态任务类型 // Dynamic task type + public char m_DynTaskType; + // 特殊奖励号,用于运营的活动 // Special award number, used for operational activities + public uint m_ulSpecialAward; + // 组队信息 // Team information + public bool m_bTeamwork; // 组队任务 // Team task + public bool m_bRcvByTeam; // 必须组队接收 // Must be in team to receive + public bool m_bSharedTask; // 新队员分享任务 // New team members share tasks + public bool m_bSharedAchieved; // 分享杀怪、物品数量 // Share kill counts and item counts + public bool m_bCheckTeammate; // 检查队友位置 // Check teammate positions + public float m_fTeammateDist; // 队友距离平方值 // Square of teammate distance + public bool m_bAllFail; // 任意队员失败则全部失败 // Any member fails, all fail + public bool m_bCapFail; // 队长失败则全部失败 // Leader fails, all fail + public bool m_bCapSucc; // 队长成功则全队成功 // Leader succeeds, all succeed + public float m_fSuccDist; // 成功时队员的距离 // Member distance for success + public bool m_bDismAsSelfFail; // 队员离队自身失败 // Member leaves team fails itself + public bool m_bRcvChckMem; // 接任务时检查队员位置 // Check member positions when receiving task + public float m_fRcvMemDist; // 接任务时队员距离平方值 // Square of member distance when receiving task + public bool m_bCntByMemPos; // 队员在有效范围内杀怪有效 // Members in valid range for kill counts + public float m_fCntMemDist; // 队员有效的范围 // Valid range for members + public bool m_bAllSucc; // 任意队员成功则全部成功 // Any member succeeds, all succeed + public bool m_bCoupleOnly; // 队长队员必须为夫妻 // Leader and member must be spouses + public bool m_bDistinguishedOcc; // 队伍中不允许有相同的职业 // No same occupations allowed in team + // 队伍成员需求 // Team member requirements + public uint m_ulTeamMemsWanted; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskTemplConstants.MAX_TEAM_MEM_WANTED)] + public TEAM_MEM_WANTED[] m_TeamMemsWanted; + public bool m_bShowByTeam; + + // 前提全局key/value // Premise global key/value + public bool m_bPremNeedComp; + public int m_nPremExp1AndOrExp2; + public COMPARE_KEY_VALUE m_Prem1KeyValue; + public COMPARE_KEY_VALUE m_Prem2KeyValue; + + public bool m_bPremCheckForce; + public int m_iPremForce; + public bool m_bShowByForce; + public int m_iPremForceReputation; + public bool m_bShowByForceReputation; + public int m_iPremForceContribution; // 扣除战功 // Deduct military merit + public bool m_bShowByForceContribution; + public int m_iPremForceExp; // 经验兑换 // Experience exchange + public bool m_bShowByForceExp; + public int m_iPremForceSP; // 元神兑换 // Spirit exchange + public bool m_bShowByForceSP; + public int m_iPremForceActivityLevel; + public bool m_bShowByForceActivityLevel; + + public bool m_bPremIsKing; + public bool m_bShowByKing; + public bool m_bPremNotInTeam; + public bool m_bShowByNotInTeam; + public uint m_iPremTitleNumTotal; + public uint m_iPremTitleNumRequired; + public int[] m_PremTitles; + public bool m_bShowByTitle; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 2)] + public int[] m_iPremHistoryStageIndex; // 历史阶段 // Historical stage + public bool m_bShowByHistoryStage; + + public uint m_ulPremGeneralCardCount; // 收集的卡牌数量 // Number of collected cards + public bool m_bShowByGeneralCard; + + public int m_iPremGeneralCardRank; // 要求某品阶的卡牌数量 // Required number of cards of a certain rank + public uint m_ulPremGeneralCardRankCount; + public bool m_bShowByGeneralCardRank; + + /* 任务完成的方式及条件 */ /* Task completion methods and conditions */ + + public uint m_enumMethod; + public uint m_enumFinishType; + + /* 任务方式 */ /* Task methods */ + + public uint m_ulPlayerWanted; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.MAX_PLAYER_WANTED)] + public PLAYER_WANTED[] m_PlayerWanted; + public uint m_ulMonsterWanted; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.MAX_MONSTER_WANTED)] + public MONSTER_WANTED[] m_MonsterWanted; + + public uint m_ulItemsWanted; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.MAX_ITEM_WANTED)] + public ITEM_WANTED[] m_ItemsWanted; + public uint m_ulGoldWanted; + + public int m_iFactionContribWanted; + public int m_iFactionExpContribWanted; + + public uint m_ulNPCToProtect; + public uint m_ulProtectTimeLen; + + public uint m_ulNPCMoving; + public uint m_ulNPCDestSite; + + //public ZONE_VERT m_ReachSiteMin; + //public ZONE_VERT m_ReachSiteMax; + public Task_Region[] m_pReachSite; + public uint m_ulReachSiteCnt; + public uint m_ulReachSiteId; + public uint m_ulWaitTime; + + //藏宝图 使用已接任务列表中的m_iUsefulData1存储 // Treasure map Use m_iUsefulData1 in the list of accepted tasks + public enum TREASURE_DISTANCE_LEVEL { + DISTANCE_FAR_FAR_AWAY, + DISTANCE_FAR, + DISTANCE_MEDIUM, + DISTANCE_NEAR, + DISTANCE_VERY_NEAR, + DISTANCE_NUM, + } + + // TREA section + public ZONE_VERT m_TreasureStartZone; + public byte m_ucZonesNumX; + public byte m_ucZonesNumZ; + public byte m_ucZoneSide; + + //public ZONE_VERT m_LeaveSiteMin; + //public ZONE_VERT m_LeaveSiteMax; + public Task_Region[] m_pLeaveSite; + public uint m_ulLeaveSiteCnt; + public uint m_ulLeaveSiteId; + + // 完成全局key/value // Complete global key/value + public bool m_bFinNeedComp; + public int m_nFinExp1AndOrExp2; + public COMPARE_KEY_VALUE m_Fin1KeyValue; + public COMPARE_KEY_VALUE m_Fin2KeyValue; + + // 需显示的全局变量表达式 // Global variable expressions to display + public uint m_ulExpCnt; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.TASK_AWARD_MAX_DISPLAY_CHAR_LEN * TaskInterfaceConstants.TASK_AWARD_MAX_DISPLAY_EXP_CNT)] + public char[] m_pszExp; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.TASK_AWARD_MAX_DISPLAY_CHAR_LEN * TaskInterfaceConstants.TASK_AWARD_MAX_DISPLAY_EXP_CNT)] + public TASK_EXPRESSION[] m_pExpArr; + + // 需显示的全局变量表达式提示字符串 // Global variable expression prompt strings + public uint m_ulTaskCharCnt; + [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.TASK_AWARD_MAX_DISPLAY_EXP_CNT * TaskInterfaceConstants.TASK_AWARD_MAX_DISPLAY_CHAR_LEN)] + public ushort[] m_pTaskChar; + + // 变身状态 // Transformation state + public byte m_ucTransformedForm; + // 等级 // Level + public uint m_ulReachLevel; + // 转生次数 // Reincarnation count + public uint m_ulReachReincarnationCount; + // 境界等级 // Realm level + public uint m_ulReachRealmLevel; + + public uint m_uiEmotion; // 表情动作 // Emotion action + + /* 任务结束后的奖励 */ /* Rewards after task completion */ + public uint m_ulAwardType_S; + public uint m_ulAwardType_F; + + /* 普通和按每个方式 */ /* Normal and per-method rewards */ + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] + public AWARD_DATA[] m_Award_S; /* 成功 */ /* Success */ + [MarshalAs(UnmanagedType.ByValArray, SizeConst = 1)] + public AWARD_DATA[] m_Award_F; /* 失败 */ /* Failure */ } public class ATaskTempl @@ -431,7 +2113,6 @@ namespace PerfectWorld.Scripts.Task private bool LoadFixedDataFromBinFile(FileStream fp) { - ulong i; long readBytes = 0; ATaskTemplFixedData fixedData = AAssit.ReadFromBinaryOf(fp, ref readBytes);