hxhhxhz
22-03-16, 10:11 PM
tính năng này hot lắm, không ai share đâu, giờ có mỗi con kiemthemoira làm được
local tb	= Task:GetTarget("ProtectNpc");
tb.szTargetName		= "ProtectNpc";
tb.REFRESH_FRAME 	= 18;
--tb.CHIEFSKILLID		= 100; -- Escort phụ trách Id kỹ năng con người, đóng cửa khi các mục tiêu được đóng vào đầu tải
-- Tham số Mô tả
-- Id đối thoại NPC mẫu, đối thoại bàn chải NPC khoảng thời gian, lựa chọn đối thoại, trò chuyện, đi bộ Id mẫu NPC, đi bộ NPC lớp, Id bản đồ, người chơi có thể để lại các điểm mục tiêu xa nhất phối x, y tọa độ của mục tiêu, mục tiêu bán kính, các tuyến đường, hoàn thành trước khi bong bóng, sau khi hoàn thành các bong bóng
function tb:Init(nDialogNpcTempId, nMapPosX, nMapPosY, nInterval, szOption, szMsg, nMoveNpcTempId, nMoveNpcLevel, nMapId, nMaxDistance, nLimitTime, nAimX, nAimY, nAimR, szTrack, szBeforePop, strRszLaterPop, nAttartRate)
	self.nDialogNpcTempId	= nDialogNpcTempId;
	self.nMapPosX			= nMapPosX;
	self.nMapPosY			= nMapPosY;
	self.nInterval			= nInterval;
	self.szDialogNpcName	= KNpc.GetNameByTemplateId(nDialogNpcTempId);
	self.szOption			= szOption;
	self.szMsg				= szMsg;
	self.nMoveNpcTempId		= nMoveNpcTempId;
	self.szMoveNpcName		= KNpc.GetNameByTemplateId(nMoveNpcTempId)
	self.nMoveNpcLevel		= nMoveNpcLevel;
	self.nMapId				= nMapId;
	self.szMapName			= Task:GetMapName(nMapId);
	self.nMaxDistance		= nMaxDistance;
	self.nLimitTime			= nLimitTime;
	self.nAimX				= nAimX;
	self.nAimY				= nAimY;
	self.nAimR				= nAimR;
	self.tbTrack			= self:ParseTrack(szTrack);
	self.szBeforePop		= szBeforePop;
	self.szLaterPop			= szLaterPop;
	self.nAttartRate 		= tonumber(nAttartRate) or 20;
	self:IniTarget();
end;
--Đi bộ chuỗi phân tích cú pháp
function tb:ParseTrack(szTrack)
	if (not szTrack or szTrack == "") then
		return;
	end
	local tbRet = {};
	local tbTrack = Lib:SplitStr(szTrack, "\n")
	for i=1, #tbTrack do
		if (tbTrack[i] and tbTrack[i] ~= "") then
			local tbPos = Lib:SplitStr(tbTrack[i]);
			table.insert(tbRet, tbPos);
		end
	end
	
	return tbRet;
end
function tb:IniTarget()
	if (MODULE_GAMESERVER) then
		if (not self.bStart) then
			local pDialogNpc = KNpc.Add2(self.nDialogNpcTempId, 1, -1, self.nMapId, self.nMapPosX, self.nMapPosY);
			if (not pDialogNpc) then
				return;
			end
			self.nDialogNpcId = pDialogNpc.dwId;
			Timer:Register(Env.GAME_FPS * 60, self.OnCheckNpcExist, self);
			self.bStart = true;
		end
	end
end;
-- Để ngăn chặn mất mát vô tình gây ra NPC
function tb:OnCheckNpcExist()
	if (Task:IsNpcExist(self.nDialogNpcId, self) == 1) then
		return;
	end
	
	if (self.nReviveDurationTimeId) then
		return;
	end
	
	self.nDialogNpcId = nil;
	self.nReviveDurationTimeId = nil;
	
	self:AddDialogNpc();
end
-- Bắt đầu
function tb:Start()
	self.bDone = 0;
	self:RegisterTalk();
end;
function tb:Save(nGroupId, nStartTaskId)
	self.tbSaveTask	= {	--Dưới đây bảo tồn, bất cứ lúc nào sau khi khách hàng có thể đồng bộ hóa tự
		nGroupId		= nGroupId,
		nStartTaskId	= nStartTaskId,
	};
	self.me.SetTask(nGroupId, nStartTaskId, self.bDone);
	return 1;
end;
function tb:Load(nGroupId, nStartTaskId)
	self.tbSaveTask	= {	-- Dưới đây bảo tồn, bất cứ lúc nào sau khi khách hàng có thể đồng bộ hóa tự
		nGroupId		= nGroupId,
		nStartTaskId	= nStartTaskId,
	};
	self.bDone	= self.me.GetTask(nGroupId, nStartTaskId);
	
	if (not self:IsDone()) then	-- Một khi mục tiêu này đạt được sẽ không thất bại
		self:RegisterTalk();
	end;
	
	return 1;
end;
function tb:IsDone()
	return self.bDone == 1;
end;
function tb:GetDesc()
	return self:GetStaticDesc();
end;
function tb:GetStaticDesc()
	return "Hộ tống "..self.szMoveNpcName;
end;
function tb:Close(szReason)
	self:UnReg_Npc_RunTimer();
	self:UnRegisterTalk();
	
	if (self.nMoveNpcId) then
		local pFightNpc = KNpc.GetById(self.nMoveNpcId);
		if (pFightNpc) then
			pFightNpc.Delete();
		end
	end
end;
-- Đăng ký và NPC đối thoại
function tb:RegisterTalk()
	self.tbTask:AddNpcMenu(self.nDialogNpcTempId, self.nMapId, self.szOption, self.OnTalkNpc, self);
end;
function tb:UnRegisterTalk()
	self.tbTask:RemoveNpcMenu(self.nDialogNpcTempId);
end;
function tb:OnTalkNpc()
	if (not him) then
		return;
	end;
	
	if (self.nMapId ~= 0 and self.nMapId ~= self.me.GetMapId()) then
		TaskAct:Talk("Thứ cần tìm "..self.szDialogNpcName.." không có trong bản đồ, hãy đi về phía trước"..self.szMapName)
		return;
	end;
	local oldPlayer = me;
	me = self.me;
	TaskAct:Talk(self.szMsg, self.OnTalkFinish, self);
	me = oldPlayer;
	
	self.nMyDialogNpcId = him.dwId;
end;
-- Sau khi đối thoại sẽ xóa các cuộc đối thoại hiện NPC, ở một nơi được chỉ định để đi bộ NPC bàn chải, và để cho anh ta đi bộ, và đăng ký hẹn giờ quy định thời gian và sau đó chải một cuộc đối thoại NPC
function tb:OnTalkFinish()
	if (self.nMyDialogNpcId ~= self._tbBase.nDialogNpcId) then
		return;
	end
	
	-- Trận chiến đối thoại lần lượt
	self:Dialog2Fight();	 
	
	--Đăng ký hẹn giờ để xóa NPC thời gian, để xem các cầu thủ từ NPC khoảng cách mỗi giây, nếu khoảng cách bị xóa
	self:Reg_Npc_RunTimer();
	
	-- Sau khi đăng ký thời gian quy định để đánh đối thoại NPC
	self._tbBase:RiseDialogNpc();
end;
function tb:Dialog2Fight()
	assert(MODULE_GAMESERVER);
	local pDialogNpc = KNpc.GetById(self._tbBase.nDialogNpcId);
	assert(pDialogNpc);
	local nCurMapId, nCurPosX, nCurPosY = pDialogNpc.GetWorldPos();
	
	pDialogNpc.Delete(); 
	self._tbBase.nDialogNpcId = nil;
	
	-- Di chuyển cổ áo trước
	if (self.nMoveNpcId) then
		local pFightNpc = KNpc.GetById(self.nMoveNpcId);
		
		if (pFightNpc) then
			pFightNpc.Delete();
			self.nMoveNpcId = nil;
		end
	end
	
	local pFightNpc	= KNpc.Add2(self.nMoveNpcTempId, self.nMoveNpcLevel, -1, self.nMapId, nCurPosX, nCurPosY, 0, 0, 1);
	assert(pFightNpc); 
	pFightNpc.SetCurCamp(0);
	local szTitle = " Do đội <color=yellow>"..self.me.szName.."<color> hộ tống";
	pFightNpc.SetTitle(szTitle);
	Npc:RegPNpcOnDeath(pFightNpc, self.OnDeath, self);
	self.nMoveNpcId = pFightNpc.dwId;
	
	pFightNpc.AI_ClearPath();
	for _,Pos in ipairs(self.tbTrack) do
		if (Pos[1] and Pos[2]) then
			pFightNpc.AI_AddMovePos(tonumber(Pos[1])*32, tonumber(Pos[2])*32)
		end
	end 
	
	pFightNpc.AI_AddMovePos(tonumber(self.nAimX)*32, tonumber(self.nAimY)*32);-- 終點為目標
	pFightNpc.SetNpcAI(9, self.nAttartRate, 1,-1, 25, 25, 25, 0, 0, 0, self.me.GetNpc().nIndex);	
end
function tb:RiseDialogNpc()
	assert(self._tbBase)
	assert(not self._tbBase._tbBase)
	if (MODULE_GAMESERVER) then
		self.nReviveDurationTimeId = Timer:Register(Env.GAME_FPS * self.nInterval, self.AddDialogNpc, self);
	end;
end
-- Thêm một cuộc đối thoại NPC
function tb:AddDialogNpc()
	assert(self._tbBase);
	assert(not self._tbBase._tbBase);
	assert(not self.nDialogNpcId);
	local pDialogNpc = KNpc.Add2(self.nDialogNpcTempId, 1, -1, self.nMapId, self.nMapPosX, self.nMapPosY);
	assert(pDialogNpc)
	
	self.nDialogNpcId = pDialogNpc.dwId;
	self.nReviveDurationTimeId = nil;
	return 0;
end
function tb:Reg_Npc_RunTimer()
	self.nRunElapseTime = 0;
	if (MODULE_GAMESERVER and not self.nRegisterRunTimerId) then
		self.nRegisterRunTimerId = Timer:Register(self.REFRESH_FRAME, self.OnRunTimer, self);
	end;
end;
function tb:UnReg_Npc_RunTimer()
	if (MODULE_GAMESERVER and self.nRegisterRunTimerId) then
		Timer:Close(self.nRegisterRunTimerId);
		self.nRegisterRunTimerId	= nil;
	end;
end;
-- 1. để xóa thời gian quy định chống NPC
-- 2 phụ thuộc vào người chơi NPC khoảng cách từ con thứ hai, nếu khoảng cách thường được xóa
--3. Mục tiêu là hoàn thành (và các cầu thủ đi))
function tb:OnRunTimer()
	if (not self.nMoveNpcId) then
		self.nRegisterRunTimerId	= nil;
		return 0;
	end
	
	local pFightNpc = KNpc.GetById(self.nMoveNpcId);
	if (not pFightNpc) then
		self.nRegisterRunTimerId	= nil;
		return 0;
	end
	self.nRunElapseTime = self.nRunElapseTime + 1;
	if (self.nRunElapseTime > self.nLimitTime) then -- Để thời gian quy định, các hộ tống thất bại
		pFightNpc.Delete();
		self.me.Msg("Không hộ tống thành công trong thời gian chỉ định"..self.szMoveNpcName..", quay về khởi điểm đối thoại lại để mở nhiệm vụ Hộ tống.")
		self.nMoveNpcId = nil;
		self.nRegisterRunTimerId	= nil;
		return 0;
	else
		local nHimCurMapId, nHimCurPosX, nHimCurPosY = pFightNpc.GetWorldPos();
		local oldme = me;
		me = self.me;
		local bAtPos, szMsg	= TaskCond:IsAtPos(self.nMapId, nHimCurPosX, nHimCurPosY, self.nMaxDistance);
		me = oldme;
		if (not bAtPos) then
			pFightNpc.Delete();
			self.me.Msg("Khoảng cách hộ tống "..self.szMoveNpcName.."quá xa, nhiệm vụ thất bại, quay về đối thoại để mở nhiệm vụ Hộ tống.")
			self.nMoveNpcId = nil;
			self.nRegisterRunTimerId	= nil;
			return 0;
		end;
		local oldme = me;
		me = self.me;
		-- Phân tích điểm đến
		if (TaskCond:IsNpcAtPos(pFightNpc.dwId, self.nMapId, self.nAimX, self.nAimY, self.nAimR) or pFightNpc.AI_IsArrival() == 1) then
			self.bDone	=  1;
			self:ShareProtectNpc();
			local tbSaveTask	= self.tbSaveTask;
			if (MODULE_GAMESERVER and tbSaveTask) then	-- Đồng bộ tự cho khách hàng, yêu cầu khách hàng để làm mới
				self.me.SetTask(tbSaveTask.nGroupId, tbSaveTask.nStartTaskId, self.bDone, 1);
				KTask.SendRefresh(self.me, self.tbTask.nTaskId, self.tbTask.nReferId, tbSaveTask.nGroupId);
			end;
			pFightNpc.Delete();
			self.nMoveNpcId = nil;
			self:UnReg_Npc_RunTimer();
			self.nRunElapseTime = 0;
		end;
		me = oldme;
		
		if (self:IsDone()) then	-- Một khi mục tiêu này đạt được sẽ không thất bại
			self.me.Msg("Mục tiêu:"..self:GetStaticDesc());
			self:UnReg_Npc_RunTimer();
			self:UnRegisterTalk();
			self.tbTask:OnFinishOneTag();
			self.nRunElapseTime = 0;
			self.nRegisterRunTimerId	= nil;
			return 0
		end;
	end;
	
	return self.REFRESH_FRAME;
end;
function tb:ShareProtectNpc()
--Qua tất cả các đồng đội của mình cho tất cả các nhiệm vụ bước mục tiêu hiện tại, và nếu mục tiêu này cũng giống như gọi OnTeamMateKillNpc
	local tbTeamMembers, nMemberCount	= self.me.GetTeamMemberList();
	if (not tbTeamMembers) then --Không thể chia sẻ: không có đội
		return;
	end
	if (nMemberCount <= 0) then-- Không thể chia sẻ: không có thành viên trong nhóm
		return;
	end
	
	local nOldPlayerIndex = self.me.nPlayerIndex;
	for i = 1, nMemberCount do
		local pPlayer	= tbTeamMembers[i];
		if (pPlayer.nPlayerIndex ~= nOldPlayerIndex) then
			if (Task:AtNearDistance(pPlayer, self.me) == 1) then
				for _, tbTask in pairs(Task:GetPlayerTask(pPlayer).tbTasks) do
					
					for _, tbCurTag in pairs(tbTask.tbCurTags) do
						
						if (tbCurTag.szTargetName == self.szTargetName) then
							if (tbCurTag.nMoveNpcTempId == self.nMoveNpcTempId and
								(tbCurTag.nMapId == 0 or tbCurTag.nMapId == self.nMapId)) then
								tbCurTag:OnTeamMateProtectNpc();
							end
						end
					end
				end
			end
		end
	end
end;
function tb:OnTeamMateProtectNpc()
	self.bDone  = 1;
	local tbSaveTask	= self.tbSaveTask;
	if (MODULE_GAMESERVER and tbSaveTask) then	-- Đồng bộ tự cho khách hàng, yêu cầu khách hàng để làm mới
		self.me.SetTask(tbSaveTask.nGroupId, tbSaveTask.nStartTaskId, self.bDone, 1);
		KTask.SendRefresh(self.me, self.tbTask.nTaskId, self.tbTask.nReferId, tbSaveTask.nGroupId);
	end;
	if (self:IsDone()) then	-- Một khi mục tiêu này đạt được sẽ không thất bại
		self.me.Msg("Mục tiêu:"..self:GetStaticDesc());
		self:UnReg_Npc_RunTimer();
		self:UnRegisterTalk();
		self.tbTask:OnFinishOneTag();
	end;
end;
function tb:OnDeath()
	if (self:IsDone()) then
		return;
	end
	self.nMoveNpcId = nil;
	self.me.Msg(self.szMoveNpcName.." đã chết, nhiệm vụ thất bại, quay về đối thoại để mở nhiệm vụ Hộ tống.");
end
em tìm dc code này nhưng e k học về hàm nên e k bjt.. mấy pro giúp với .. e đã dịch 1 số thứ ra tiếng việc rồi nè
--- Chế độ gộp bài viết ---
local tb	= Task:GetTarget("test3");
tb.szTargetName		= "test3";
tb.REFRESH_FRAME 	= 18;
--tb.CHIEFSKILLID		= 100; -- Escort phụ trách Id kỹ năng con người, đóng cửa khi các mục tiêu được đóng vào đầu tải
-- Tham số Mô tả
-- Id đối thoại NPC mẫu, đối thoại bàn chải NPC khoảng thời gian, lựa chọn đối thoại, trò chuyện, đi bộ Id mẫu NPC, đi bộ NPC lớp, Id bản đồ, người chơi có thể để lại các điểm mục tiêu xa nhất phối x, y tọa độ của mục tiêu, mục tiêu bán kính, các tuyến đường, hoàn thành trước khi bong bóng, sau khi hoàn thành các bong bóng
function tb:Init(nDialogNpcTempId, nMapPosX, nMapPosY, nInterval, szOption, szMsg, nMoveNpcTempId, nMoveNpcLevel, nMapId, nMaxDistance, nLimitTime, nAimX, nAimY, nAimR, szTrack, szBeforePop, strRszLaterPop, nAttartRate)
	self.nDialogNpcTempId	= nDialogNpcTempId;
	self.nMapPosX			= nMapPosX;
	self.nMapPosY			= nMapPosY;
	self.nInterval			= nInterval;
	self.szDialogNpcName	= KNpc.GetNameByTemplateId(nDialogNpcTempId);
	self.szOption			= szOption;
	self.szMsg				= szMsg;
	self.nMoveNpcTempId		= nMoveNpcTempId;
	self.szMoveNpcName		= KNpc.GetNameByTemplateId(nMoveNpcTempId)
	self.nMoveNpcLevel		= nMoveNpcLevel;
	self.nMapId				= nMapId;
	self.szMapName			= Task:GetMapName(nMapId);
	self.nMaxDistance		= nMaxDistance;
	self.nLimitTime			= nLimitTime;
	self.nAimX				= nAimX;
	self.nAimY				= nAimY;
	self.nAimR				= nAimR;
	self.tbTrack			= self:ParseTrack(szTrack);
	self.szBeforePop		= szBeforePop;
	self.szLaterPop			= szLaterPop;
	self.nAttartRate 		= tonumber(nAttartRate) or 20;
	self:IniTarget();
end;
--Đi bộ chuỗi phân tích cú pháp
function tb:ParseTrack(szTrack)
	if (not szTrack or szTrack == "") then
		return;
	end
	local tbRet = {};
	local tbTrack = Lib:SplitStr(szTrack, "\n")
	for i=1, #tbTrack do
		if (tbTrack[i] and tbTrack[i] ~= "") then
			local tbPos = Lib:SplitStr(tbTrack[i]);
			table.insert(tbRet, tbPos);
		end
	end
	
	return tbRet;
end
function tb:IniTarget()
	if (MODULE_GAMESERVER) then
		if (not self.bStart) then
			local pDialogNpc = KNpc.Add2(self.nDialogNpcTempId, 1, -1, self.nMapId, self.nMapPosX, self.nMapPosY);
			if (not pDialogNpc) then
				return;
			end
			self.nDialogNpcId = pDialogNpc.dwId;
			Timer:Register(Env.GAME_FPS * 60, self.OnCheckNpcExist, self);
			self.bStart = true;
		end
	end
end;
-- Để ngăn chặn mất mát vô tình gây ra NPC
function tb:OnCheckNpcExist()
	if (Task:IsNpcExist(self.nDialogNpcId, self) == 1) then
		return;
	end
	
	if (self.nReviveDurationTimeId) then
		return;
	end
	
	self.nDialogNpcId = nil;
	self.nReviveDurationTimeId = nil;
	
	self:AddDialogNpc();
end
-- Bắt đầu
function tb:Start()
	self.bDone = 0;
	self:RegisterTalk();
end;
function tb:Save(nGroupId, nStartTaskId)
	self.tbSaveTask	= {	--Dưới đây bảo tồn, bất cứ lúc nào sau khi khách hàng có thể đồng bộ hóa tự
		nGroupId		= nGroupId,
		nStartTaskId	= nStartTaskId,
	};
	self.me.SetTask(nGroupId, nStartTaskId, self.bDone);
	return 1;
end;
function tb:IsDone()
	return self.bDone == 1;
end;
function tb:GetDesc()
	return self:GetStaticDesc();
end;
function tb:GetStaticDesc()
	return "Hộ tống "..self.szMoveNpcName;
end;
function tb:Close(szReason)
	self:UnReg_Npc_RunTimer();
	self:UnRegisterTalk();
	
	if (self.nMoveNpcId) then
		local pFightNpc = KNpc.GetById(self.nMoveNpcId);
		if (pFightNpc) then
			pFightNpc.Delete();
		end
	end
end;
-- Đăng ký và NPC đối thoại
function tb:RegisterTalk()
	self.tbTask:AddNpcMenu(self.nDialogNpcTempId, self.nMapId, self.szOption, self.OnTalkNpc, self);
end;
function tb:UnRegisterTalk()
	self.tbTask:RemoveNpcMenu(self.nDialogNpcTempId);
end;
function tb:OnTalkNpc()
	if (not him) then
		return;
	end;
	
	if (self.nMapId ~= 0 and self.nMapId ~= self.me.GetMapId()) then
		TaskAct:Talk("Thứ cần tìm "..self.szDialogNpcName.." không có trong bản đồ, hãy đi về phía trước"..self.szMapName)
		return;
	end;
	local oldPlayer = me;
	me = self.me;
	TaskAct:Talk(self.szMsg, self.OnTalkFinish, self);
	me = oldPlayer;
	
	self.nMyDialogNpcId = him.dwId;
end;
-- Sau khi đối thoại sẽ xóa các cuộc đối thoại hiện NPC, ở một nơi được chỉ định để đi bộ NPC bàn chải, và để cho anh ta đi bộ, và đăng ký hẹn giờ quy định thời gian và sau đó chải một cuộc đối thoại NPC
function tb:OnTalkFinish()
	if (self.nMyDialogNpcId ~= self._tbBase.nDialogNpcId) then
		return;
	end
	
	-- Trận chiến đối thoại lần lượt
	self:Dialog2Fight();	 
	
	--Đăng ký hẹn giờ để xóa NPC thời gian, để xem các cầu thủ từ NPC khoảng cách mỗi giây, nếu khoảng cách bị xóa
	self:Reg_Npc_RunTimer();
	
	-- Sau khi đăng ký thời gian quy định để đánh đối thoại NPC
	self._tbBase:RiseDialogNpc();
end;
function tb:Dialog2Fight()
	assert(MODULE_GAMESERVER);
	local pDialogNpc = KNpc.GetById(self._tbBase.nDialogNpcId);
	assert(pDialogNpc);
	local nCurMapId, nCurPosX, nCurPosY = pDialogNpc.GetWorldPos();
	
	pDialogNpc.Delete(); 
	self._tbBase.nDialogNpcId = nil;
	
	-- Di chuyển cổ áo trước
	if (self.nMoveNpcId) then
		local pFightNpc = KNpc.GetById(self.nMoveNpcId);
		
		if (pFightNpc) then
			pFightNpc.Delete();
			self.nMoveNpcId = nil;
		end
	end
	
	local pFightNpc	= KNpc.Add2(9669, 90, -1, 8, 55304, 108000, 0, 0, 1);
	assert(pFightNpc); 
	pFightNpc.SetCurCamp(0);
	local szTitle = " Do đội <color=yellow>"..self.me.szName.."<color> hộ tống";
	pFightNpc.SetTitle(szTitle);
	Npc:RegPNpcOnDeath(pFightNpc, self.OnDeath, self);
	self.nMoveNpcId = pFightNpc.dwId;
	
	pFightNpc.AI_ClearPath();
	for _,Pos in ipairs(self.tbTrack) do
		if (Pos[1] and Pos[2]) then
			pFightNpc.AI_AddMovePos(tonumber(Pos[1])*32, tonumber(Pos[2])*32)
		end
	end 
	
	pFightNpc.AI_AddMovePos(tonumber(self.nAimX)*32, tonumber(self.nAimY)*32);-- 終點為目標
	pFightNpc.SetNpcAI(9, self.nAttartRate, 1,-1, 25, 25, 25, 0, 0, 0, self.me.GetNpc().nIndex);	
end
function tb:RiseDialogNpc()
	assert(self._tbBase)
	assert(not self._tbBase._tbBase)
	if (MODULE_GAMESERVER) then
		self.nReviveDurationTimeId = Timer:Register(Env.GAME_FPS * self.nInterval, self.AddDialogNpc, self);
	end;
end
-- Thêm một cuộc đối thoại NPC
function tb:AddDialogNpc()
	assert(self._tbBase);
	assert(not self._tbBase._tbBase);
	assert(not self.nDialogNpcId);
	local pDialogNpc = KNpc.Add2(9669, 90, -1, 8, 55304, 108000, 0, 0, 1);
	assert(pDialogNpc)
	
	self.nDialogNpcId = pDialogNpc.dwId;
	self.nReviveDurationTimeId = nil;
	return 0;
end
function tb:Reg_Npc_RunTimer()
	self.nRunElapseTime = 0;
	if (MODULE_GAMESERVER and not self.nRegisterRunTimerId) then
		self.nRegisterRunTimerId = Timer:Register(self.REFRESH_FRAME, self.OnRunTimer, self);
	end;
end;
function tb:UnReg_Npc_RunTimer()
	if (MODULE_GAMESERVER and self.nRegisterRunTimerId) then
		Timer:Close(self.nRegisterRunTimerId);
		self.nRegisterRunTimerId	= nil;
	end;
end;
-- 1. để xóa thời gian quy định chống NPC
-- 2 phụ thuộc vào người chơi NPC khoảng cách từ con thứ hai, nếu khoảng cách thường được xóa
--3. Mục tiêu là hoàn thành (và các cầu thủ đi))
function tb:OnRunTimer()
	if (not self.nMoveNpcId) then
		self.nRegisterRunTimerId	= nil;
		return 0;
	end
	
	local pFightNpc = KNpc.GetById(self.nMoveNpcId);
	if (not pFightNpc) then
		self.nRegisterRunTimerId	= nil;
		return 0;
	end
	self.nRunElapseTime = self.nRunElapseTime + 1;
	if (self.nRunElapseTime > self.nLimitTime) then -- Để thời gian quy định, các hộ tống thất bại
		pFightNpc.Delete();
		self.me.Msg("Không hộ tống thành công trong thời gian chỉ định"..self.szMoveNpcName..", quay về khởi điểm đối thoại lại để mở nhiệm vụ Hộ tống.")
		self.nMoveNpcId = nil;
		self.nRegisterRunTimerId	= nil;
		return 0;
	else
		local nHimCurMapId, nHimCurPosX, nHimCurPosY = pFightNpc.GetWorldPos();
		local oldme = me;
		me = self.me;
		local bAtPos, szMsg	= TaskCond:IsAtPos(self.nMapId, nHimCurPosX, nHimCurPosY, self.nMaxDistance);
		me = oldme;
		if (not bAtPos) then
			pFightNpc.Delete();
			self.me.Msg("Khoảng cách hộ tống "..self.szMoveNpcName.."quá xa, nhiệm vụ thất bại, quay về đối thoại để mở nhiệm vụ Hộ tống.")
			self.nMoveNpcId = nil;
			self.nRegisterRunTimerId	= nil;
			return 0;
		end;
		local oldme = me;
		me = self.me;
		-- Phân tích điểm đến
		if (TaskCond:IsNpcAtPos(3571, 8, 56288, 109792, 1) or pFightNpc.AI_IsArrival() == 1) then
			self.bDone	=  1;
			self:ShareProtectNpc();
			local tbSaveTask	= self.tbSaveTask;
			if (MODULE_GAMESERVER and tbSaveTask) then	-- Đồng bộ tự cho khách hàng, yêu cầu khách hàng để làm mới
				self.me.SetTask(tbSaveTask.nGroupId, tbSaveTask.nStartTaskId, self.bDone, 1);
				KTask.SendRefresh(self.me, self.tbTask.nTaskId, self.tbTask.nReferId, tbSaveTask.nGroupId);
			end;
			pFightNpc.Delete();
			self.nMoveNpcId = nil;
			self:UnReg_Npc_RunTimer();
			self.nRunElapseTime = 0;
		end;
		me = oldme;
		
		if (self:IsDone()) then	-- Một khi mục tiêu này đạt được sẽ không thất bại
			self.me.Msg("Mục tiêu:"..self:GetStaticDesc());
			self:UnReg_Npc_RunTimer();
			self:UnRegisterTalk();
			self.tbTask:OnFinishOneTag();
			self.nRunElapseTime = 0;
			self.nRegisterRunTimerId	= nil;
			return 0
		end;
	end;
	
	return self.REFRESH_FRAME;
end;
function tb:ShareProtectNpc()
--Qua tất cả các đồng đội của mình cho tất cả các nhiệm vụ bước mục tiêu hiện tại, và nếu mục tiêu này cũng giống như gọi OnTeamMateKillNpc
	local tbTeamMembers, nMemberCount	= self.me.GetTeamMemberList();
	if (not tbTeamMembers) then --Không thể chia sẻ: không có đội
		return;
	end
	if (nMemberCount <= 0) then-- Không thể chia sẻ: không có thành viên trong nhóm
		return;
	end
	
	local nOldPlayerIndex = self.me.nPlayerIndex;
	for i = 1, nMemberCount do
		local pPlayer	= tbTeamMembers[i];
		if (pPlayer.nPlayerIndex ~= nOldPlayerIndex) then
			if (Task:AtNearDistance(pPlayer, self.me) == 1) then
				for _, tbTask in pairs(Task:GetPlayerTask(pPlayer).tbTasks) do
					
					for _, tbCurTag in pairs(tbTask.tbCurTags) do
						
						if (tbCurTag.szTargetName == self.szTargetName) then
							if (tbCurTag.nMoveNpcTempId == self.nMoveNpcTempId and
								(tbCurTag.nMapId == 0 or tbCurTag.nMapId == self.nMapId)) then
								tbCurTag:OnTeamMateProtectNpc();
							end
						end
					end
				end
			end
		end
	end
end;
function tb:OnTeamMateProtectNpc()
	self.bDone  = 1;
	local tbSaveTask	= self.tbSaveTask;
	if (MODULE_GAMESERVER and tbSaveTask) then	-- Đồng bộ tự cho khách hàng, yêu cầu khách hàng để làm mới
		self.me.SetTask(tbSaveTask.nGroupId, tbSaveTask.nStartTaskId, self.bDone, 1);
		KTask.SendRefresh(self.me, self.tbTask.nTaskId, self.tbTask.nReferId, tbSaveTask.nGroupId);
	end;
	if (self:IsDone()) then	-- Một khi mục tiêu này đạt được sẽ không thất bại
		self.me.Msg("Mục tiêu:"..self:GetStaticDesc());
		self:UnReg_Npc_RunTimer();
		self:UnRegisterTalk();
		self.tbTask:OnFinishOneTag();
	end;
end;
function tb:OnDeath()
	if (self:IsDone()) then
		return;
	end
	self.nMoveNpcId = nil;
	self.me.Msg(self.szMoveNpcName.." đã chết, nhiệm vụ thất bại, quay về đối thoại để mở nhiệm vụ Hộ tống.");
end
 và đây là hàm e đang test nhưng vẫn chưa hoàn chinh
e bị kẹt mấy cái id + tọa độ NPC hộ tống và địa điểm hoàn thành hộ tống
nó kêu cái gì mà ''''''người chơi có thể để lại các điểm mục tiêu xa nhất phối x, y tọa độ của mục tiêu, mục tiêu bán kính, các tuyến đường'''''''''''
e k học nên e k bit .. pro nào vào giúp đỡ đi ạ
Powered by vBulletin® Version 4.2.0 Copyright © 2025 vBulletin Solutions, Inc. All rights reserved.