--- 白龙boss战 local XLevel0015 = XDlcScriptManager.RegLevelScript(0015, "XLevel0015") local FuncSet = CS.StatusSyncFight.XFightScriptFuncs local Config = require("XDLCFight/Level/LevelConfig/Hunt01BossFightConfig") -- 读取场景物体的配置数据,作为实例存在本地 local Tool = require("XDLCFight/Level/Common/XLevelTools") local XPlayerNpcContainer = require("XDLCFight/Level/Common/XPlayerNpcContainer") local Timer = require("XDLCFight/Level/Common/XTaskScheduler") local _cameraResRefTable = { } function XLevel0015.GetCameraResRefTable() return _cameraResRefTable end ---@param proxy StatusSyncFight.XScriptLuaProxy function XLevel0015:Ctor(proxy) self._proxy = proxy self._timer = Timer.New() self._worldId = FuncSet.GetWorldId() if Config.Boss[self._worldId] == nil then self._worldId = 2 end self._wightDragonRespawnId = Config.Boss[self._worldId].WightDragon self._wightDragonBossRefId = 2 self._spearFatalitySoundFx = 8002105 self._bossHidePos = { x = 60, y = -200, z = 60 } self._bossBornPos = { x = 60, y = 1.95, z = 60 } self._bossBornRot = { x = 0, y = 180, z = 0 } self._wightDragonNpcId = nil ---boss的id self._playerNpcContainer = XPlayerNpcContainer.New() self._playerRescueDict = {} --[[ self._switches = { { placeId = 1, agent = nil, object = self, func = self.PlaySceneAnim, param = nil, times = 1, defaultEnable = true }, }]] self._deathZonePlaceId = 9999 self._outwardsDeathZonePlaceId = 9998 ---暂时用来应对玩家挤出空气墙的处理 self._debug = false end function XLevel0015:Init() self:InitPhase() self:InitWightDragon() self:InitPlayer() --self:InitSwitch() self:InitListen() end ---@param dt number @ delta time function XLevel0015:Update(dt) self._timer:Update(dt) self:OnUpdatePhase(dt) self:PlayerInteract() self:OnInteractButton() end function XLevel0015:OnInteractButton() if self._debug then if FuncSet.IsKeyDown(ENpcOperationKey.Ball11) then elseif FuncSet.IsKeyDown(ENpcOperationKey.Ball12) then self:SpearFatality() elseif FuncSet.IsKeyDown(ENpcOperationKey.Ball10) then elseif FuncSet.IsKeyDown(ENpcOperationKey.Ball9) then end end end ---@param eventType number ---@param eventArgs userdata function XLevel0015:HandleEvent(eventType, eventArgs) self.Super.HandleEvent(self, eventType, eventArgs) self:HandlePhaseEvent(eventType, eventArgs) self._playerNpcContainer:HandleEvent(eventType, eventArgs) if eventType == EScriptEvent.SceneObjectTrigger then --[[ XLog.Debug("XLevelBossFight1 SceneObjectTriggerEvent:" .. " TouchType " .. tostring(eventArgs.TouchType) .. " SourceActorId " .. tostring(eventArgs.SourceActorId) .. " SceneObjectId " .. tostring(eventArgs.SceneObjectId) .. " TriggerId " .. tostring(eventArgs.TriggerId) .. " TriggerState " .. tostring(eventArgs.TriggerState) .. " Log自关卡" )]] if eventArgs.SceneObjectId == self._deathZonePlaceId and FuncSet.IsPlayerNpc(eventArgs.SourceActorId) then FuncSet.ResetNpcToSafePoint(eventArgs.SourceActorId) end if eventArgs.SceneObjectId == self._outwardsDeathZonePlaceId and FuncSet.IsPlayerNpc(eventArgs.SourceActorId) and eventArgs.TriggerState == ESceneObjectTriggerState.Exit then FuncSet.ResetNpcToCheckPoint(eventArgs.SourceActorId) XLog.Warning("注意!npc ".. tostring(eventArgs.SourceActorId).."穿到战斗场景外了") end elseif eventType == EScriptEvent.NpcInteractComplete then --交互完成 self:OnNpcInteractComplete(eventArgs) end if eventType == EScriptEvent.Behavior2ScriptMsg then if eventArgs.MsgType == 1001 and FuncSet.CheckNpc(self._wightDragonNpcId) then --天基 self:SpearFatality() elseif eventArgs.MsgType == 100 then --设置空气墙碰撞 self:EnableAirWallToNpc(eventArgs.Int[1], eventArgs.Int[2] == 0) end end end function XLevel0015:GainControl() end function XLevel0015:InitPhase() --初始化关卡各个阶段的相关变量 self._currentPhase = 0 self._lastPhase = 0 self._phaseStartedDelayTranslate = false ---阶段延迟跳转需要设置为true self._phaseTimeCount = 0 XLog.Debug("[SceneHunt01]初始化关卡阶段参数完成") end function XLevel0015:InitWightDragon() --生成怪物 local id = FuncSet.GetGeneratedNpc(self._wightDragonBossRefId) if id <= 0 then --防止断线重连时重复创建怪物 self._wightDragonNpcId = FuncSet.GenerateNpc(self._wightDragonBossRefId, self._wightDragonRespawnId, ENpcCampType.Camp2, self._bossBornPos, self._bossBornRot) else self._wightDragonNpcId = id end self._proxy:RegisterBehavior2ScriptMsgEvent(self._wightDragonNpcId) XLog.Debug("[SceneHunt01]召唤npc白龙完成") end function XLevel0015:InitPlayer() self._playerNpcContainer:Init( function(npc) self:OnPlayerNpcCreate(npc) end, function(npc) self:OnPlayerNpcDestroy(npc) end ) self._playerNpcList = self._playerNpcContainer:GetPlayerNpcList() self._playerCount = #self._playerNpcList XLog.Debug("[SceneHunt01]初始化关卡用玩家参数完成") end function XLevel0015:InitSwitch() self._switches = Tool.InitSwitch(self._switches) XLog.Debug("[SceneHunt01]初始化场景中开关完成") end function XLevel0015:InitListen() self._proxy:RegisterSceneObjectTriggerEvent(self._deathZonePlaceId, 1) --死区 self._proxy:RegisterSceneObjectTriggerEvent(self._outwardsDeathZonePlaceId, 1) --外部死区,一个临时解决方案 XLog.Debug("[SceneHunt01]初始化其他监听内容完成") end function XLevel0015:OnPlayerNpcCreate(npc) self._proxy:RegisterNpcEvent(EScriptEvent.NpcCastSkill, npc) self._proxy:RegisterNpcEvent(EScriptEvent.NpcExitSkill, npc) self._playerNpcList = self._playerNpcContainer:GetPlayerNpcList() self._playerCount = #self._playerNpcList FuncSet.SetSceneColliderIgnoreCollision(npc, "MonsterAirWall", -1, true) --用于限制boss在场边活动的空气墙 XLog.Debug("[SceneHunt01]注册角色技能监听:" .. npc) end function XLevel0015:OnPlayerNpcDestroy(npc) self._proxy:UnregisterNpcEvent(EScriptEvent.NpcCastSkill, npc) self._proxy:UnregisterNpcEvent(EScriptEvent.NpcExitSkill, npc) self._playerNpcList = self._playerNpcContainer:GetPlayerNpcList() self._playerCount = #self._playerNpcList XLog.Debug("[SceneHunt01]注销角色技能监听:" .. npc) end ---玩家之间的交互 function XLevel0015:PlayerInteract() --玩家救援复活交互检测 for i = 1, #self._playerNpcList do local npcA = self._playerNpcList[i] for j = 1, #self._playerNpcList do local npcB = self._playerNpcList[j] self:CheckPlayerRescueInteract(npcA, npcB, 3.5) end end end ---玩家救援交互 ---@param launcher number ---@param target number ---@param dist number @distance function XLevel0015:CheckPlayerRescueInteract(launcher, target, dist) if target == launcher then --不能对自己交互 return end local curTarget = self._playerRescueDict[launcher] if curTarget ~= nil then local isInRange = FuncSet.CheckNpcDistance(launcher, curTarget, dist) if not isInRange or self:IsNpcDead(launcher) or not self:IsNpcDying(curTarget) then self._playerRescueDict[launcher] = nil FuncSet.CloseInteraction(launcher) XLog.Debug(string.format("Level CloseInteraction Rescue, launcher:%d target:%d ", launcher, curTarget, dist)) end else local isInRange = FuncSet.CheckNpcDistance(launcher, target, dist) if isInRange and not self:IsNpcDead(launcher) and self:IsNpcDying(target) then self._playerRescueDict[launcher] = target FuncSet.ShowInteraction(launcher, target, FuncSet.GetRescueTime(), EInteractType.Rescue) XLog.Debug(string.format("Level ShowInteraction Rescue, launcher:%d target:%d ", launcher, target, dist)) end end end ---@param eventArgs StatusSyncFight.NpcEventArgs function XLevel0015:OnNpcInteractComplete(eventArgs) local npc = eventArgs.NpcId local target = self._playerRescueDict[npc] if target then FuncSet.RebornNpc(npc, target) --复活救援对象 self._playerRescueDict[npc] = nil --清除救援对象记录 end FuncSet.CloseInteraction(npc, false) --关闭救援者的交互按钮 end ---Npc是否处在濒死状态 function XLevel0015:IsNpcDying(npcId) return FuncSet.CheckNpcAction(npcId, ENpcAction.Dying) end ---Npc是否死亡 function XLevel0015:IsNpcDead(npcId) return FuncSet.CheckNpcAction(npcId, ENpcAction.Dying) or FuncSet.CheckNpcAction(npcId, ENpcAction.Death) end ---跳转关卡阶段 function XLevel0015:SetPhase(phase) if phase == self._currentPhase then return end self:OnExitPhase(self._currentPhase) self:OnEnterPhase(phase) self:OnPhaseChanged(self._currentPhase, self.phase) self._lastPhase = self._currentPhase self._currentPhase = phase self._phaseTimeCount = 0 end ---当前关卡阶段需要一直执行的逻辑在这里实现。一般用作执行判断、执行持续性的功能、跳转阶段 function XLevel0015:OnUpdatePhase(dt) if self._phaseTimeCount == nil then self._phaseTimeCount = 0 end self._phaseTimeCount = self._phaseTimeCount + dt if self._currentPhase == 0 then if not FuncSet.CheckNpc(self._wightDragonNpcId) then XLog.Debug("[SceneHunt01]检测到boss死亡") FuncSet.FinishFight(true) end elseif self._currentPhase == 1 then end end ---进入一个关卡阶段时需要做的事情在这里实现。一般用作设置阶段所需的环境 function XLevel0015:OnEnterPhase(phase) if phase == 1 then elseif phase == 2 then end end ---关卡阶段改变时需要执行的逻辑,一般用于通知外部 function XLevel0015:OnPhaseChanged(lastPhase, nextPhase) end ---处理阶段相关的事件响应、状态检测、信息获取 function XLevel0015:HandlePhaseEvent(eventType, eventArgs) if self._currentPhase == 1 then elseif self._currentPhase == 2 then end end ---天基演出流程 function XLevel0015:SpearFatality() for _, npc in pairs(self._playerNpcList) do FuncSet.ApplyMagic(npc, npc, 5000003, 1) self._timer:Schedule(0.5, self, self.RemoveBlackScreen, npc) end self:SetFightUiActive(false) self._timer:Schedule(11, self, self.SetFightUiActive, true) self._timer:Schedule(0.5, self, self.PlaySpearFatality) end function XLevel0015:RemoveBlackScreen(npc) FuncSet.ApplyMagic(npc, npc, 5000006, 1) end function XLevel0015:PlaySpearFatality() if FuncSet.CheckNpc(self._wightDragonNpcId) then FuncSet.PlayCameraTimeline("SprearFatality01", self._wightDragonNpcId, 0, 0, 0) self._timer:Schedule(10.5, "SprearFatality01", FuncSet.StopCameraTimeline, self._wightDragonNpcId) FuncSet.ApplyMagic(self._wightDragonNpcId, self._wightDragonNpcId, self._spearFatalitySoundFx, 1) end end function XLevel0015:EnableAirWallToNpc(enable, npc) FuncSet.SetSceneColliderIgnoreCollision(npc, "AirWalls", -1, enable) FuncSet.SetSceneColliderIgnoreCollision(npc, "OuterAirWall", -1, enable) FuncSet.SetSceneColliderIgnoreCollision(npc, "MonsterAirWall", -1, enable) end function XLevel0015:SetFightUiActive(active) for _, npc in pairs(self._playerNpcList) do if active then FuncSet.ApplyMagic(npc, npc, 5000008) else FuncSet.ApplyMagic(npc, npc, 5000007) end end end function XLevel0015:Terminate() end return XLevel0015