using BrewMonster.Network; using BrewMonster.Scripts.Player; using System.Collections.Generic; using System.IO; using System.Runtime.InteropServices; using BrewMonster.Scripts.Managers; using CSNetwork.GPDataType; using PerfectWorld.Scripts.Task; using UnityEngine; namespace BrewMonster.Scripts.Task { [StructLayout(LayoutKind.Sequential, Pack = 1)] public class Kill_Player_Requirements { public const uint MAX_OCCPU_MASK = ((uint)1 << TaskInterfaceConstants.MAX_OCCUPATIONS) - 1u; public uint m_ulOccupations; public int m_iMinLevel; public int m_iMaxLevel; public int m_iGender; public int m_iForce; public Kill_Player_Requirements() { m_iMinLevel = 10; m_iMaxLevel = 100; m_iGender = 0; m_iForce = 0; m_ulOccupations = MAX_OCCPU_MASK; } public bool IsMeetAllOccupation() { return m_ulOccupations == MAX_OCCPU_MASK; } public bool CheckRequirements(int iOccupation, int iLevel, bool bGender, int iForce) { bool bForce = false; // �༭����1Ϊ�У�2ΪŮ // In editor: 1 is male, 2 is female int iGender = bGender ? 2 : 1; // �༭����0����û������Ҫ�� // In editor: 0 means no force requirement if (m_iForce == 0) { bForce = true; } // �����ʾ������Ҫ�� // Otherwise indicates there is a force requirement else { // �༭���ﻪ�⡢�����ͻ�ҹ�ֱ��õ�һ����������������λ��ʾ // Map force ids to bit positions int iForceMask = 0; if (iForce == 0) { return false; } else if (iForce == 1004) { iForceMask = 1 << 0; } else if (iForce == 1005) { iForceMask = 1 << 1; } else if (iForce == 1006) { iForceMask = 1 << 2; } bForce = (m_iForce & iForceMask) != 0; } return ((m_ulOccupations & (1u << iOccupation)) != 0) && m_iMinLevel <= iLevel && m_iMaxLevel >= iLevel && (m_iGender != 0 ? m_iGender == iGender : true) && bForce; } } #if _TASK_CLIENT [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct Task_State_info { public uint m_ulTimeLimit; public uint m_ulTimePassed; public uint m_ulNPCToProtect; public uint m_ulProtectTime; public uint m_ulWaitTime; public uint m_ulErrCode; public uint m_ulGoldWanted; public uint m_ulReachLevel; public uint m_ulReachReincarnation; public uint m_ulReachRealm; public uint m_ulPremLevelMin; [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct m_MonsterWanted_s { public uint m_ulMonsterId; public uint m_ulMonstersToKill; public uint m_ulMonstersKilled; } [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.MAX_MONSTER_WANTED)] public m_MonsterWanted_s[] m_MonsterWanted; [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct m_ItemsWanted_s { public uint m_ulItemId; public uint m_ulItemsToGet; public uint m_ulItemsGained; public uint m_ulMonsterId; } [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.MAX_ITEM_WANTED)] public m_ItemsWanted_s[] m_ItemsWanted; [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct TASK_INFO_PLAYER { public uint m_ulPlayersToKill; public uint m_ulPlayersKilled; public Kill_Player_Requirements m_Requirements; } [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.MAX_PLAYER_WANTED)] public TASK_INFO_PLAYER[] m_PlayerWanted; // abase::vector m_TaskCharArr (assumed 3 pointers: start, finish, end_of_storage; 32-bit layout) [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct abase_vector_wchar_t_ptr { public uint _start; public uint _finish; public uint _end_of_storage; } public abase_vector_wchar_t_ptr m_TaskCharArr; } [StructLayout(LayoutKind.Sequential, Pack = 1)] public struct Task_Award_Preview { public uint m_ulGold; public uint m_ulExp; public uint m_ulRealmExp; public uint m_ulSP; public bool m_bHasItem; public bool m_bItemKnown; public uint m_ulItemTypes; [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.MAX_ITEM_AWARD)] public uint[] m_ItemsId; [MarshalAs(UnmanagedType.ByValArray, SizeConst = TaskInterfaceConstants.MAX_ITEM_AWARD)] public uint[] m_ItemsNum; public int m_iForceActivity; public int m_iForceContrib; public int m_iForceRepu; } #endif 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; public const int TASK_STORAGE_COUNT = 32; public const int TASK_STORAGE_LEN = 10; public const float TASK_STORAGE_WHELL_SCALE = 10000; 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; // µ±Ç°¼¤»îµÄÈÎÎñÁÐ±í»º³åÇø´óС public int TASK_ACTIVE_LIST_BUF_SIZE => (TASK_ACTIVE_LIST_MAX_LEN * TASK_DATA_BUF_MAX_LEN + TASK_ACTIVE_LIST_HEADER_LEN); CECHostPlayer m_pHost; ActiveTaskList m_pActiveListBuf; // Active task list buffer // private byte[] m_pActiveListRawBuf; // raw buffer backing for active list (converted from C++) byte[] m_pFinishedListBuf; // Finished task list buffer byte[] m_pFinishedTimeListBuf; // Finished time list buffer byte[] m_pFinishedCountListBuf;// Finished count list buffer byte[] m_pStorageTaskListBuf; // Storage tasks list buffer private Dictionary m_TasksToConfirm = new Dictionary(); private readonly System.Collections.Generic.Dictionary m_emotionTask = new System.Collections.Generic.Dictionary(); private bool m_bForceNavigateFinish; public CECTaskInterface() { } public CECTaskInterface(CECHostPlayer pHost) { m_pHost = pHost; m_pActiveListBuf = null; m_pFinishedListBuf = null; m_pFinishedTimeListBuf = null; m_pFinishedCountListBuf = null; m_pStorageTaskListBuf = null; } // Initialize object public bool Init(byte[] pActiveListBuf, int iActiveListLen, byte[] pFinishedListBuf, int iFinishedListLen, byte[] pFinishedTimeListBuf, int iFinishedTimeListLen, byte[] pFinishedCountListBuf, int iFinishedCountListLen, byte[] pStorageTaskListBuf, int iStorageTaskListLen) { // basic argument check (converted from ASSERT) if (pActiveListBuf == null || pFinishedListBuf == null || pFinishedTimeListBuf == null || pFinishedCountListBuf == null) { return false; } BMLogger.Log($"pActiveListBuf: {pActiveListBuf.Length} - {TaskInterfaceConstants.TASK_ACTIVE_LIST_BUF_SIZE}"); // allocate internal buffers and copy; remaining bytes are zero-initialized in C# // m_pActiveListRawBuf = new byte[TaskInterfaceConstants.TASK_ACTIVE_LIST_BUF_SIZE]; // { // int copy = Mathf.Min(iActiveListLen, TaskInterfaceConstants.TASK_ACTIVE_LIST_BUF_SIZE); // if (copy > 0) System.Buffer.BlockCopy(pActiveListBuf, 0, m_pActiveListRawBuf, 0, copy); // } m_pActiveListBuf = new ActiveTaskList(); m_pActiveListBuf.ReadFromBuffer(pActiveListBuf); m_pFinishedListBuf = new byte[TaskInterfaceConstants.TASK_FINISHED_LIST_BUF_SIZE]; { int copy = Mathf.Min(iFinishedListLen, TaskInterfaceConstants.TASK_FINISHED_LIST_BUF_SIZE); if (copy > 0) System.Buffer.BlockCopy(pFinishedListBuf, 0, m_pFinishedListBuf, 0, copy); } m_pFinishedTimeListBuf = new byte[TaskInterfaceConstants.TASK_FINISH_TIME_LIST_BUF_SIZE]; { int copy = Mathf.Min(iFinishedTimeListLen, TaskInterfaceConstants.TASK_FINISH_TIME_LIST_BUF_SIZE); if (copy > 0) System.Buffer.BlockCopy(pFinishedTimeListBuf, 0, m_pFinishedTimeListBuf, 0, copy); } m_pFinishedCountListBuf = new byte[TaskInterfaceConstants.TASK_FINISH_COUNT_LIST_BUF_SIZE]; { int copy = Mathf.Min(iFinishedCountListLen, TaskInterfaceConstants.TASK_FINISH_COUNT_LIST_BUF_SIZE); if (copy > 0) System.Buffer.BlockCopy(pFinishedCountListBuf, 0, m_pFinishedCountListBuf, 0, copy); } m_pStorageTaskListBuf = new byte[TaskInterfaceConstants.TASK_STORAGE_LIST_BUF_SIZE]; { int copy = Mathf.Min(iStorageTaskListLen, TaskInterfaceConstants.TASK_STORAGE_LIST_BUF_SIZE); if (copy > 0) System.Buffer.BlockCopy(pStorageTaskListBuf, 0, m_pStorageTaskListBuf, 0, copy); } // Clear rest buffer // 清理剩余缓冲区 // No-op in C# because arrays are zero-initialized. ATaskTemplMan pTaskMan = GetTaskTemplMan(); pTaskMan.Release(); string task_data_path = Path.Combine(Application.streamingAssetsPath, "data/tasks.data"); pTaskMan.LoadTasksFromPack(task_data_path, true); pTaskMan.LoadNPCInfoFromPack("data\\task_npc.data"); pTaskMan.VerifyDynTasksPack("userdata\\dyn_tasks.data"); InitActiveTaskList(); m_bForceNavigateFinish = false; return true; } public void CheckPQEnterWorldInit() { return; ActiveTaskList pList = GetActiveTaskList(); List aEntries = new List(pList.m_TaskEntries); for(var i = 0; i < pList.m_uTaskCount; i++) { var CurEntry = aEntries[i]; if (CurEntry.m_ulTemplAddr == 0) continue; ATaskTempl pTempl = CurEntry.GetTempl(); if (pTempl == null || !pTempl.m_FixedData.m_bPQTask) continue; pTempl.IncValidCount(); // _notify_svr(this, TASK_CLT_NOTIFY_PQ_CHECK_INIT, CurEntry.m_ID); } } public static void WriteLog(int nPlayerId, int nTaskId, int nType, string szLog) { //do something? } public bool IsDeliverLegal() { // return !m_pHost->IsTrading() && m_pHost->GetBoothState() == 0 && !m_pHost->IsDead(); return m_pHost.IsTrading() && m_pHost.GetBoothState() == 0 && !m_pHost.IsDead(); } public int GetCommonItemCount(uint ulCommonItem) { // CECInventory pPack = m_pHost.GetPack(); //EC_Inventory pPack = m_pHost.GetPack(); // return pPack != null ? EC_Inventory.GetItemTotalNum( 0, (int)ulCommonItem) : 0; // paramater 1 to get type inventory (0:inventoty, 1:equip,...) return EC_Inventory.GetItemTotalNum(EC_Inventory.IVTRTYPE_PACK, (int)ulCommonItem); } public int GetTaskItemCount(uint ulTaskItem) { // CECInventory* pPack = m_pHost->GetTaskPack(); // return pPack ? pPack->GetItemTotalNum((int)ulTaskItem) : 0; return EC_Inventory.GetItemTotalNum(EC_Inventory.IVTRTYPE_TASKPACK, (int)ulTaskItem); } private ATaskTemplMan GetTaskTemplMan() { return EC_Game.GetTaskTemplateMan(); } private ActiveTaskList GetActiveTaskList() { return m_pActiveListBuf; } private void InitActiveTaskList() { ActiveTaskList pLst = GetActiveTaskList(); if (pLst == null) return; ATaskTemplMan pMan = GetTaskTemplMan(); if (pMan == null) return; // reset counters pLst.m_uTopShowTaskCount = 0; pLst.m_uTopHideTaskCount = 0; pLst.m_uTitleTaskCount = 0; byte i = 0; while (i < pLst.m_uTaskCount) { ActiveTaskEntry entry = pLst.m_TaskEntries[i]; if (entry == null) { i++; continue; } // repair sibling linkage if (entry.m_NextSblIndex != (char)0xff) { ActiveTaskEntry entryNextSbl = pLst.m_TaskEntries[entry.m_NextSblIndex]; if (entryNextSbl == null || entryNextSbl.m_PrevSblIndex != (char)i) { entry.m_NextSblIndex = (char)0xff; } } // resolve template for top-level entries; children left unresolved in C# if (entry.m_ParentIndex == (char)0xff) { entry.m_ulTemplAddr = 0u; ATaskTempl topTempl = pMan.GetTopTaskByID(entry.m_ID); if (topTempl != null) { if (topTempl.m_FixedData.m_bHidden) pLst.m_uTopHideTaskCount++; else if (topTempl.m_FixedData.m_bDisplayInTitleTaskUI) pLst.m_uTitleTaskCount++; else pLst.m_uTopShowTaskCount++; } } else { entry.m_ulTemplAddr = 0u; } // cap template best-effort (no pointer in managed) if (entry.m_uCapTaskId != 0) { ATaskTempl cap = pMan.GetTopTaskByID(entry.m_uCapTaskId); entry.m_ulCapTemplAddr = 0u; if (cap == null) { entry.m_uCapTaskId = 0; } } else { entry.m_ulCapTemplAddr = 0u; } i++; } // approximate used count pLst.m_uUsedCount = pLst.m_uTaskCount; } public bool CheckTaskForbid(uint task_id){ return false; } public bool IsAtCrossServer() { // TODO: cross server // return CECCrossServer.Instance().IsOnSpecialServer(); return false; } public uint GetPlayerLevel() { return (uint)m_pHost.GetBasicProps().iLevel; } public uint GetGoldNum() { return (uint)m_pHost.GetMoneyAmount(); } public int GetGlobalValue(int lKey) { return EC_Game.GetGameRun().GetCommonData(lKey); } public byte GetShapeMask() { return m_pHost.GetShapeMask(); } public int GetPos(float[] pos) { A3DVECTOR3 vPos = m_pHost.GetPos(); if (pos != null && pos.Length >= 3) { pos[0] = vPos.x; pos[1] = vPos.y; pos[2] = vPos.z; } var world = World.CECWorld.Instance; return world != null ? world.GetInstanceID() : 0; } public bool CheckSimpleTaskFinshConditon(uint task_id) { ATaskTempl pTempl = GetTaskTemplMan().GetTaskTemplByID(task_id); if (pTempl == null) return false; if (pTempl.m_FixedData.m_enumMethod == (uint)TaskMethod.enumTMSimpleClientTask && pTempl.m_FixedData.m_uiEmotion != 0) { if (m_emotionTask != null && m_emotionTask.TryGetValue(task_id, out bool finished)) return finished; return false; } else if (pTempl.m_FixedData.m_enumMethod == (uint)TaskMethod.enumTMSimpleClientTaskForceNavi) { return GetForceNavigateFinishFlag(); } return true; } public int GetFactionConsumeContrib() { return m_pHost.GetContribInfo().consume_contrib; } public int GetFactionExpContrib() { return m_pHost.GetContribInfo().exp_contrib; } public bool HasTask(uint ulTaskId) { ActiveTaskList pLst = GetActiveTaskList(); if (pLst == null) return false; for (int i = 0; i < pLst.m_uTaskCount; i++) { ActiveTaskEntry entry = pLst.m_TaskEntries[i]; if ((uint)entry.m_ID == ulTaskId && entry.GetTempl() != null) return true; } return false; } #if _TASK_CLIENT // Prepare award preview based on task and state public void GetTaskAwardPreview(uint ulTaskId, ref Task_Award_Preview p, bool bActiveTask=true) { // Zero and init output p = default; if (p.m_ItemsId == null) p.m_ItemsId = new uint[TaskInterfaceConstants.MAX_ITEM_AWARD]; if (p.m_ItemsNum == null) p.m_ItemsNum = new uint[TaskInterfaceConstants.MAX_ITEM_AWARD]; // Gather context ActiveTaskList pLst = GetActiveTaskList(); uint ulCurTime = GetCurTime(); ATaskTempl pTempl = null; AWARD_DATA ad = default; uint ulMulti = 1u; // Resolve template and dynamic award when active if (bActiveTask && pLst != null) { for (int i = 0; i < pLst.m_uTaskCount; i++) { ActiveTaskEntry CurEntry = pLst.m_TaskEntries[i]; if (CurEntry.m_ID != ulTaskId || CurEntry.m_ulTemplAddr == 0) continue; pTempl = CurEntry.GetTempl(); // TODO: CalcAwardData/CalcAwardMulti not implemented yet in C#; use fixed success award and multiplier 1 if (pTempl != null) { ad = pTempl.m_FixedData.m_Award_S; ulMulti = 1u; } if (ulMulti == 0u) return; break; } } // Fallback to top template when inactive else { pTempl = GetTaskTemplMan().GetTopTaskByID(ulTaskId); if (pTempl == null) return; ad = pTempl.m_FixedData.m_Award_S; } // Fill basic award fields unchecked { p.m_ulGold = ad.m_ulGoldNum * ulMulti; p.m_ulExp = ad.m_ulExp * ulMulti; p.m_ulSP = ad.m_ulSP * ulMulti; } p.m_iForceActivity = ad.m_iForceActivity; p.m_iForceContrib = ad.m_iForceContribution; p.m_iForceRepu = ad.m_iForceReputation; p.m_ulRealmExp = ad.m_ulRealmExp; // Apply level coefficient if configured (coefficient table not available; skip scaling) if (ad.m_bUseLevCo) { uint ulLev = GetPlayerLevel(); if (ulLev == 0) ulLev = 1; uint ulUpper = 0; if (pTempl != null && pTempl.GetTopTask() != null) ulUpper = pTempl.GetTopTask().m_FixedData.m_ulPremise_Lev_Max; if (ulUpper != 0 && ulLev > ulUpper) ulLev = ulUpper; // NOTE: Original code multiplies by _lev_co[ulLev-1]. Not available here; keep as-is. } // Candidate items handling if (ad.m_ulCandItems == 1 && ad.m_CandItems != null && ad.m_CandItems.Length > 0) { p.m_bHasItem = true; p.m_bItemKnown = true; AWARD_ITEMS_CAND ic = ad.m_CandItems[0]; if (ic.m_bRandChoose) { p.m_bItemKnown = false; } else { for (int j = 0; j < ic.m_ulAwardItems; j++) { ITEM_WANTED wi = ic.m_AwardItems[j]; if (!wi.m_bCommonItem) continue; else if (wi.m_fProb != 1.0f) { p.m_bItemKnown = false; break; } else { // Period conversion not implemented; assume valid if (p.m_ulItemTypes < TaskInterfaceConstants.MAX_ITEM_AWARD) { p.m_ItemsId[p.m_ulItemTypes] = wi.m_ulItemTemplId; p.m_ItemsNum[p.m_ulItemTypes] = wi.m_ulItemNum; p.m_ulItemTypes++; } } } } } else if (ad.m_ulCandItems > 1) { p.m_bHasItem = true; } // Done return; } public uint GetTaskCount() { ActiveTaskList pLst = GetActiveTaskList(); uint ulCount = 0; if (pLst == null) return 0u; for (int i = 0; i < pLst.m_uTaskCount; i++) { ActiveTaskEntry CurEntry = pLst.m_TaskEntries[i]; ATaskTempl pTempl = CurEntry.GetTempl(); if (pTempl != null && !pTempl.m_FixedData.m_bDisplayInTitleTaskUI && CurEntry.m_ParentIndex == (char)0xff) { if (!pTempl.m_FixedData.m_bHidden || pTempl.m_FixedData.m_bShowPrompt) { ulCount++; } } } return ulCount; } public uint GetTaskId(uint ulIndex) { ActiveTaskList pLst = GetActiveTaskList(); byte uTopCount = 0; int uCount = 0; if (pLst == null) return 0u; while (uCount < pLst.m_uTaskCount) { ActiveTaskEntry CurEntry = pLst.m_TaskEntries[uCount]; ATaskTempl pTempl = CurEntry.GetTempl(); if (pTempl != null && !pTempl.m_FixedData.m_bDisplayInTitleTaskUI && CurEntry.m_ParentIndex == (char)0xff) { if (!pTempl.m_FixedData.m_bHidden || pTempl.m_FixedData.m_bShowPrompt) { if (ulIndex == uTopCount) return CurEntry.m_ID; else uTopCount++; } } uCount++; } return 0u; } #endif private bool GetForceNavigateFinishFlag() { return m_bForceNavigateFinish; } public void GetTaskStateInfo(uint ulTaskId, ref Task_State_info pInfo, bool bActiveTask=true) { // 清零并准备输出结构 // Zero and prepare output struct pInfo = default; if (pInfo.m_MonsterWanted == null) pInfo.m_MonsterWanted = new Task_State_info.m_MonsterWanted_s[TaskInterfaceConstants.MAX_MONSTER_WANTED]; if (pInfo.m_ItemsWanted == null) pInfo.m_ItemsWanted = new Task_State_info.m_ItemsWanted_s[TaskInterfaceConstants.MAX_ITEM_WANTED]; if (pInfo.m_PlayerWanted == null) pInfo.m_PlayerWanted = new Task_State_info.TASK_INFO_PLAYER[TaskInterfaceConstants.MAX_PLAYER_WANTED]; ActiveTaskList pLst = GetActiveTaskList(); uint ulCurTime = GetCurTime(); // 当前时间 // current time ATaskTempl pTempl = null; ActiveTaskEntry foundEntry = default; bool hasFoundEntry = false; if (bActiveTask) { // 在激活任务列表中查找 // Search in active task list for (int i = 0; i < pLst.m_uTaskCount; i++) { ActiveTaskEntry CurEntry = pLst.m_TaskEntries[i]; if (CurEntry.m_ID != ulTaskId || CurEntry.m_ulTemplAddr == 0) continue; pTempl = CurEntry.GetTempl(); foundEntry = CurEntry; hasFoundEntry = true; // 检查任务是否可以完成 // Check if task can be completed if (pTempl != null && pTempl.CanFinishTask(this, CurEntry, ulCurTime)) { pInfo.m_ulErrCode = pTempl.RecursiveCheckAward(this, pLst, CurEntry, ulCurTime, -1); if (pInfo.m_ulErrCode == TaskInterfaceConstants.TASK_AWARD_FAIL_LEVEL_CHECK) { ATaskTempl pParent = pTempl; while (pParent != null && pParent.m_FixedData.m_ulPremise_Lev_Min == 0) pParent = pParent.m_pParent; if (pParent != null) pInfo.m_ulPremLevelMin = pParent.m_FixedData.m_ulPremise_Lev_Min; } } pInfo.m_ulTimePassed = ulCurTime > CurEntry.m_ulTaskTime ? (ulCurTime - CurEntry.m_ulTaskTime) : 0; if (pTempl != null && pTempl.m_FixedData.m_ulPremise_Lev_Min != 0) { if (pTempl.m_FixedData.m_bPremCheckMaxHistoryLevel != 0 && GetPlayerLevel() < pTempl.m_FixedData.m_ulPremise_Lev_Min) { pInfo.m_ulErrCode = TaskInterfaceConstants.TASK_AWARD_FAIL_LEVEL_CHECK; pInfo.m_ulPremLevelMin = pTempl.m_FixedData.m_ulPremise_Lev_Min; } } break; } } else { pTempl = GetTaskTemplMan().GetTopTaskByID(ulTaskId); } if (pTempl == null) return; // 基本任务要求 // Basic task requirements if (pTempl.m_FixedData.m_ulTimeLimit != 0) pInfo.m_ulTimeLimit = pTempl.m_FixedData.m_ulTimeLimit; if (pTempl.m_FixedData.m_ulGoldWanted != 0) pInfo.m_ulGoldWanted = pTempl.m_FixedData.m_ulGoldWanted; // 任务类型分支 // Task method branches if (pTempl.m_FixedData.m_enumMethod == (uint)TaskMethod.enumTMCollectNumArticle) { for (int j = 0; j < pTempl.m_FixedData.m_ulItemsWanted; j++) { var iw = pTempl.m_FixedData.m_ItemsWanted[j]; pInfo.m_ItemsWanted[j].m_ulItemId = iw.m_ulItemTemplId; pInfo.m_ItemsWanted[j].m_ulItemsToGet = iw.m_ulItemNum; pInfo.m_ItemsWanted[j].m_ulItemsGained = ATaskTempl._get_item_count(this, iw.m_ulItemTemplId, iw.m_bCommonItem); } } else if (pTempl.m_FixedData.m_enumMethod == (uint)TaskMethod.enumTMKillNumMonster) { int ulItemCount = 0; int ulMonsterCount = 0; for (int j = 0; j < pTempl.m_FixedData.m_ulMonsterWanted; j++) { var mw = pTempl.m_FixedData.m_MonsterWanted[j]; if (mw.m_ulDropItemId != 0) { pInfo.m_ItemsWanted[ulItemCount].m_ulMonsterId = mw.m_ulMonsterTemplId; pInfo.m_ItemsWanted[ulItemCount].m_ulItemId = mw.m_ulDropItemId; pInfo.m_ItemsWanted[ulItemCount].m_ulItemsToGet = mw.m_ulDropItemCount; pInfo.m_ItemsWanted[ulItemCount].m_ulItemsGained = ATaskTempl._get_item_count(this, mw.m_ulDropItemId, mw.m_bDropCmnItem); ulItemCount++; } else { pInfo.m_MonsterWanted[ulMonsterCount].m_ulMonsterId = mw.m_ulMonsterTemplId; pInfo.m_MonsterWanted[ulMonsterCount].m_ulMonstersToKill = mw.m_ulMonsterNum; if (bActiveTask && hasFoundEntry) { pInfo.m_MonsterWanted[ulMonsterCount].m_ulMonstersKilled = foundEntry.m_wMonsterNum[j]; } ulMonsterCount++; } } } else if (pTempl.m_FixedData.m_enumMethod == (uint)TaskMethod.enumTMKillPlayer) { int ulItemCount = 0; int ulPlayerCount = 0; for (int j = 0; j < pTempl.m_FixedData.m_ulPlayerWanted; j++) { var pw = pTempl.m_FixedData.m_PlayerWanted[j]; if (pw.m_ulDropItemId != 0) { pInfo.m_ItemsWanted[ulItemCount].m_ulItemId = pw.m_ulDropItemId; pInfo.m_ItemsWanted[ulItemCount].m_ulItemsToGet = pw.m_ulDropItemCount; pInfo.m_ItemsWanted[ulItemCount].m_ulItemsGained = ATaskTempl._get_item_count(this, pw.m_ulDropItemId, pw.m_bDropCmnItem); ulItemCount++; } else { pInfo.m_PlayerWanted[ulPlayerCount].m_ulPlayersToKill = pw.m_ulPlayerNum; if (bActiveTask && hasFoundEntry) { pInfo.m_PlayerWanted[ulPlayerCount].m_ulPlayersKilled = foundEntry.m_wMonsterNum[j]; } pInfo.m_PlayerWanted[ulPlayerCount].m_Requirements = pw.m_Requirements; ulPlayerCount++; } } } else if (pTempl.m_FixedData.m_enumMethod == (uint)TaskMethod.enumTMProtectNPC) { pInfo.m_ulNPCToProtect = pTempl.m_FixedData.m_ulNPCToProtect; pInfo.m_ulProtectTime = pTempl.m_FixedData.m_ulProtectTimeLen; } else if (pTempl.m_FixedData.m_enumMethod == (uint)TaskMethod.enumTMWaitTime) { pInfo.m_ulWaitTime = pTempl.m_FixedData.m_ulWaitTime; } else if (pTempl.m_FixedData.m_enumMethod == (uint)TaskMethod.enumTMGlobalValOK) { pTempl.GetGlobalTaskChar(this, pInfo.m_TaskCharArr); } else if (pTempl.m_FixedData.m_enumMethod == (uint)TaskMethod.enumTMReachLevel) { pInfo.m_ulReachLevel = pTempl.m_FixedData.m_ulReachLevel; pInfo.m_ulReachReincarnation = pTempl.m_FixedData.m_ulReachReincarnationCount; pInfo.m_ulReachRealm = pTempl.m_FixedData.m_ulReachRealmLevel; } return; } private uint GetCurTime() { // use this to avoid task hack by changing the system time return (uint)EC_Game.GetServerAbsTime(); } } }