local EventSystem = require('Event/EventSystem') local Base = require("Battle/Logic/Level/LevelItemFactory/LevelItem") local LevelItem_Global = class("LevelItem_Global", Base) local ConditionType = LuaConst.LevelConditionType local ActionType = LuaConst.LevelActionType local ActionFunc = {} local ActionCacheFunc = {} local SLOW_MOTION_DURATION = 4 local SLOW_MOTION_SCALE = 0.2 local COUNT_CEIL_NUM = 1 local COMBO_REMAIN_DURATION = 4 -- 这个值要和界面上的动画时长统一 local LogicUpdateManager = LogicUpdateManager local SystemManager = SystemManager local LuaConst = LuaConst local EventID = EventID local EFFECT_PATH = ConstAssetPathConfig.EFFECT_PATH2 local SearchEntityType = { ["None"] = 0, ["ID"] = 1, ["ItemID"] = 2, ["ItemGroupID"] = 3, } local MatchIter = {} local function ExecutorIPair(ids,i) if not ids then return end while true do i = i + 1 local id = ids[i] if id then local entity = LogicUpdateManager._entityDic[id] if entity and entity:IsValid() then return i, entity end else break end end end local function CoveredKillerIPair(id,i) if not id then return end while true do i = i + 1 if i <= 1 then local entity = LogicUpdateManager._entityDic[id] if entity and entity:IsValid() then return i, entity end else break end end end MatchIter[LuaConst.MatchRangeType.All] = LogicUpdateManager.ValidAllEntityIter MatchIter[LuaConst.MatchRangeType.Player] = LogicUpdateManager.ValidSyncEntityIter MatchIter[LuaConst.MatchRangeType.Monster] = LogicUpdateManager.ValidMonsterEntityIter MatchIter[LuaConst.MatchRangeType.Executor] = function(context) return ExecutorIPair, context.ExecutorIDs, 0 end MatchIter[LuaConst.MatchRangeType.CoveredKiller] = function(context) return CoveredKillerIPair, context.CoveredKillerID, 0 end --region --***************生命周期***************-- function LevelItem_Global:initialize(data) Base.initialize(self,data) self._playingTimelineCount = 0 self._isLevelFinished = true self._levelRemainTimer = FP.newV1(-1) --关卡剩余时间 self._levelPassTimer = FP.newV1(-1) --关卡运行时间 --self._heroDeadTimes = 0 --统计玩家死亡次数 self._heroDeadTimesOfPlayer = {} --统计玩家死亡次数 self._monsterDeadNums = 0 --统计怪物死亡数量 self._monsterRemainNums = 0 --统计怪物剩余数量 self._monsterIDRemainNums = {} --统计不同ID怪物剩余数量 self._levelWave = 0 --统计关卡波次 self._selfKillNums = 0 --统计本端玩家的杀怪数(不同步) self._syncKillNums = 0 --统计全部玩家的击杀数(同步) self._frameHitNum = 0 --统计玩家一帧的连击数 self._comboHitNum = 0 --统计玩家的连击数 self._comboRemainTimer = 0 --统计玩家连击数的持续计时 self._curVisitedEntity = nil --当前访问的实体 self._interactNpc = nil --当前游戏中只会一个正在交互的npc,如后面有需要再改结构 self._interactNpcDir = FP.newV2(0,0) --当前交互的npc交互前的朝向 self._pathGuideTimer = nil --路径显示计数 self._guideMissionID = nil --当前的路径显示任务ID,为nil时默认主线 self._curMainMissionItem = nil --当前需要寻路的主线任务 self._curSelectMissionItem = nil --当前需要寻路的选中任务 self._selectMissionID = nil --缓存需要寻论的任务 self._notifyPosMonsters = {} --需要同步位置的怪物表 self._notifyPosMonstersOfItem = nil--需要同步元素里的所有怪物的位置 self._curSlowMotionID = nil --当前的慢镜头ID self._cacheSlowMotionID = nil --缓存的慢镜头ID self._slowMotionTimer = nil --当前的慢镜头计时 self._needHPPctMonsterIDs = {} --(优化字段)需要发送血量事件的ID列表 self._confrontationTimer = nil --对峙冷却计时 self._showProgressTimer = nil --关卡进度条计时 self._showProgressName = nil --关卡进度条名称 self._showProgressIsGrowMode = nil --关卡进度条是否为增涨形式 self._showProgressFrameCount = 0 --关卡进度条同步事件记帧数 self._confrontations = {} --需要对峙的实体参数表 self._notifySAList = {} --需要同步无双值的出生点元素ID列表 self._isLevelTimeFreezing = false --是否冻结关卡时间(只是冻结时间统计,不是冻结逻辑运行,不是时间静止) self._randomCacheList = { } --用于计算随机的缓存数组 self._mapItemIDList = { } --缓存需要显示在小地图上的元素ID self._dialogueMessageIDsQueue ={} --用于缓存每条对话的分支对应参数信息的队列 self._coveredKillerID = nil --可覆盖的击杀者ID self._context = --用于传递的上下文 { GetCoveredKillerID = function() return self._coveredKillerID end } self:InitActionCache() --[[ ******** callback of expression ******** ]]-- --timeline callback self._callback_Timeline = function(timelineID,level,requestReward, isSkipTime) ExpLevelManager.OnTimelineEnd(timelineID, requestReward) self._playingTimelineCount = self._playingTimelineCount - 1 self:Dispatch(ConditionType.Global_TimeLineEnd, isSkipTime, timelineID) end --dialogue callback self._callback_Dialogue = function(dialogueID) local dialogueData = DataSheetManager.DialogueData:GetDataByFirstKeyAndIndex(dialogueID,1) if dialogueData.DialogueType == LuaConst.EDialogueType.Normal then self.isShowingDialogue = false end self:Dispatch(ConditionType.Global_DialogueEnd,nil,dialogueID) end --movie callback self._callback_Movie = function(movieID) self.isShowingMovie = false self:Dispatch(ConditionType.Global_MovieEnd,nil,movieID) end --guide callback self._callback_Guide = function(guideID) self:Dispatch(ConditionType.Global_GuideEnd,nil,guideID) end end function LevelItem_Global:OnActive() if Base.OnActive(self) then self._levelRemainTimer:Reset(self.ItemData.LevelInfo.Timer) self._levelPassTimer:Reset(0) self._isLevelFinished = false self:Dispatch(ConditionType.Global_LevelStart) self:Dispatch(ConditionType.Global_PackageType, nil, GameAppInfo.Global_PackageType) EventSystem.Dispatch(EventID.Level_Start) EventSystem.Regist(EventID.Level_HitEnemy, self.OnHitEnemy, self) return true end end function LevelItem_Global:OnDeactive() if Base.OnDeactive(self) then --self._levelRemainTimer:Reset(-1) --不能置空,因为这个信息要保留给之后的代码模块使用 EventSystem.UnRegist(EventID.Level_HitEnemy,self.OnHitEnemy,self) for i = 1, #self._notifySAList do local eventID = self._notifySAList[i]..EventID._EntitySAChanged EventSystem.UnRegist(eventID, self.OnEntitySAChange, self) self._notifySAList[i] = nil end return true end end function LevelItem_Global:FreezeLevelTime() self._isLevelTimeFreezing = true end function LevelItem_Global:CancelFreezeLevelTime() self._isLevelTimeFreezing = false end function LevelItem_Global:OnUpdate() Base.OnUpdate(self) if self._levelRemainTimer >= FP.Const.Zero then if not self._isLevelTimeFreezing then self._levelRemainTimer:Sub(LuaConst.TimeSpan) self._levelPassTimer:Add(LuaConst.TimeSpan) self:Dispatch(ConditionType.Global_TimeRemain,nil, self._levelRemainTimer) self:Dispatch(ConditionType.Global_TimeRun,nil, self._levelPassTimer) if self._levelRemainTimer <= FP.Const.Zero then self:Dispatch(ConditionType.Global_TimeOver) end end end for i, entity in LogicUpdateManager.ValidSyncEntityIter() do self:Dispatch(ConditionType.Global_PlayerReachArea,nil, entity.components.move.LogicPos) end for monsterID, entityList in pairs(self._notifyPosMonsters) do for _, entity in ipairs(entityList) do if entity.components.attr:IsAlive() then self:Dispatch(ConditionType.Global_GivenMonsterReachArea,nil,monsterID,entity.components.move.LogicPos) end end end if self._notifyPosMonstersOfItem then for type, itemList in pairs(self._notifyPosMonstersOfItem) do self:Dispatch(type,nil, nil, itemList) end end if self._slowMotionTimer then self._slowMotionTimer:Sub(LuaConst.TimeSpan) if self._slowMotionTimer <= FP.Const.Zero then for entityID ,entity in pairs(LogicUpdateManager._entityDic) do SystemManager.OnDeleteTimeScale(entity,"slowMotion",SLOW_MOTION_SCALE) end self:Dispatch(ConditionType.Global_SlowMotionEnd,nil,self._curSlowMotionID) self._curSlowMotionID = nil self._slowMotionTimer = nil end end if self._confrontationTimer then self._confrontationTimer = self._confrontationTimer - LuaConst.TimeSpanMs if self._confrontationTimer < 0 then self._confrontationTimer = nil end end if self._showProgressTimer then self._showProgressTimer:Sub(LuaConst.TimeSpan) self._showProgressFrameCount = self._showProgressFrameCount + 1 if self._showProgressFrameCount >= 100 then EventSystem.Dispatch(EventID.UIBattle_Level_UpdateProgressBar, FP.tonumberV1(self._showProgressTimer)) self._showProgressFrameCount = 0 end if FP.LessEquals(self._showProgressTimer,0) then self._showProgressTimer = nil end end if self._cacheSlowMotionID and not LevelManager.IsLevelPause() then self:HandleSlowMotion(self._cacheSlowMotionID) self._cacheSlowMotionID = nil end self:HandleComboNumber() self:HandleMission() self:HandleMissionGuide() self:HandleNPCInteracted() end function LevelItem_Global:OnDestroy() Base.OnDestroy(self) --self._heroDeadTimes = nil self._heroDeadTimesOfPlayer = nil self._monsterDeadNums = nil self._monsterRemainNums = nil self._levelWave = nil self._selfKillNums = nil self._syncKillNums = nil self._comboRemainTimer = nil self._curVisitedEntity = nil self._interactNpc = nil self._interactNpcDir = nil self._pathGuideTimer = nil self._guideMissionID = nil self._curMainMissionItem = nil self._curSelectMissionItem = nil self._selectMissionID = nil self._curSlowMotionID = nil self._cacheSlowMotionID = nil self._slowMotionTimer = nil self._needHPPctMonsterIDs = nil self._notifyPosMonsters = nil self._notifyPosMonstersOfItem = nil self._confrontationTimer = nil self._confrontations = nil self._showProgressTimer = nil self._showProgressName = nil self._showProgressIsGrowMode = nil self._showProgressFrameCount = nil self._callback_Timeline = nil self._callback_Dialogue = nil self._callback_Movie = nil self._callback_Guide = nil self._notifySAList = nil self._randomCacheList = nil self._mapItemIDList = nil self._dialogueMessageIDsQueue = nil self:ClearActionCache() end --endregion 生命周期 --region--***************事件相关***************-- function LevelItem_Global:HandleCondition(conditionType, paramID, param1, param2, param3) Base.HandleCondition(conditionType, paramID,param1) if conditionType == ConditionType.Global_GivenMonsterReachArea then local entityList = self._notifyPosMonsters[paramID] if not entityList then entityList = {} end for _, entity in pairs(LogicUpdateManager._entityDic) do if entity._logicInitData.CharacterID == paramID then table.insert(entityList,entity) end end self._notifyPosMonsters[paramID] = entityList elseif conditionType == ConditionType.Global_GivenMonsterAllReachArea or conditionType == ConditionType.Global_GivenMonsterAnyReachArea then if self._notifyPosMonstersOfItem == nil then self._notifyPosMonstersOfItem = {} end self._notifyPosMonstersOfItem[conditionType] = param3 elseif conditionType == ConditionType.Global_GivenMonsterRemainHPPct then self._needHPPctMonsterIDs[paramID] = true elseif conditionType == ConditionType.Global_PlayerSAIncrease then for id, value in pairs(param1) do if not table.containValue(self._notifySAList, id) then table.insert(self._notifySAList, id) local eventID = id..EventID._EntitySAChanged EventSystem.Regist(eventID, self.OnEntitySAChange, self) end end end end --这个元素可做的事情 ,执行action [事件执行的不受到自身条件限制] function LevelItem_Global:DoAction(actionType, match, param1, param2, context, param3) Base.DoAction(self,actionType,param1) local func = ActionFunc[actionType] if func then func(self,param1, param2, match, context, param3) end end function LevelItem_Global:OnHitEnemy() self._frameHitNum = self._frameHitNum + 1 end function LevelItem_Global:OnEntitySAChange(entity, delta, value) local bornItemID = entity._logicInitData.OriginBornItemID if bornItemID then self:Dispatch(ConditionType.Global_PlayerSAIncrease,nil, bornItemID, delta) end end function LevelItem_Global:GetCurMainMission() return self._curMainMissionItem end --endregion 事件相关 --region--***************全局通知***************-- function LevelItem_Global:Notify_WaitOtherPlayer_WaitStart() --self:Dispatch(ConditionType.Global_WaitOtherPlayer_Start)--这个条件不同步,怕被误用,直接废弃了 LevelItemManager.Global:FreezeLevelTime() end function LevelItem_Global:Notify_WaitOtherPlayer_CountdownStart() self:Dispatch(ConditionType.Global_WaitOtherPlayer_AllPlayerOnline) end function LevelItem_Global:Notify_WaitOtherPlayer_WaitFinished() LevelItemManager.Global:CancelFreezeLevelTime() self:Dispatch(ConditionType.Global_WaitOtherPlayer_CountdownFinish) end function LevelItem_Global:Notify_PlayerDead(entity, levelItemID) --self._heroDeadTimes = self._heroDeadTimes + 1 self._heroDeadTimesOfPlayer[levelItemID] = self._heroDeadTimesOfPlayer[levelItemID] or 0 self._heroDeadTimesOfPlayer[levelItemID] = self._heroDeadTimesOfPlayer[levelItemID] + 1 self:Dispatch(ConditionType.Global_PlayerDeadTimes,nil, self._heroDeadTimesOfPlayer[levelItemID], levelItemID) local heroEntities = LevelPlayerManager.GetHeroEntities() if not heroEntities then return end for k,list in pairs(heroEntities) do for i,entity in ipairs(list) do if entity.components.attr:IsAlive() then return end end end self:Dispatch(ConditionType.Global_PlayerDead) end function LevelItem_Global:Notify_MonsterBorn(entity) local monsterID = entity._logicInitData.CharacterID local entityID = entity.EntityID self._monsterRemainNums = self._monsterRemainNums + COUNT_CEIL_NUM local remainNum = self._monsterIDRemainNums[monsterID] or 0 remainNum = remainNum + COUNT_CEIL_NUM self._monsterIDRemainNums[monsterID] = remainNum local pctArray = entity.components.base.CurMonsterFeature.ConfrontationPctHP if pctArray and #pctArray> 0 then local confrontation = { entity = entity, hpChecker = 1 } self:UpdateConfrontationChecker(confrontation) self._confrontations[entityID] = confrontation end self:HandleEntityActionCache(entity) local entityList = self._notifyPosMonsters[monsterID] if entityList then table.insert(entityList, entity) end EventSystem.Dispatch(EventID.Level_MonsterBorn, monsterID, entityID) self:Dispatch(ConditionType.Global_AllMonsterAliveNum,nil, COUNT_CEIL_NUM) self:Dispatch(ConditionType.Global_GivenMonsterAliveNum,nil, monsterID, COUNT_CEIL_NUM) if self._needHPPctMonsterIDs[monsterID] then local comp_Attr = entity.components.attr self:Dispatch(ConditionType.Global_GivenMonsterRemainHPPct,nil,monsterID, entity,FP.tonumberV1(comp_Attr:MaxHP()),FP.tonumberV1(comp_Attr.hp)) end end function LevelItem_Global:Notify_MonsterDead(entity) local killer = entity.components.record.KillerEntity self._coveredKillerID = killer and killer:GetEntityID() or nil local monsterID = entity._logicInitData.CharacterID local entityID = entity.EntityID self._monsterDeadNums = self._monsterDeadNums + COUNT_CEIL_NUM self._monsterRemainNums = self._monsterRemainNums - COUNT_CEIL_NUM local remainNum = self._monsterIDRemainNums[monsterID] or COUNT_CEIL_NUM remainNum = remainNum - COUNT_CEIL_NUM self._monsterIDRemainNums[monsterID] = remainNum local pctArray = entity.components.base.CurMonsterFeature.ConfrontationPctHP if pctArray and #pctArray> 0 then self._confrontations[entityID] = nil end local entityList = self._notifyPosMonsters[monsterID] if entityList then for i = 1, #entityList do if entityList[i] == entity then table.remove(entityList, i) break end end end EventSystem.Dispatch(EventID.Level_MonsterDead, monsterID, entityID) self:Dispatch(ConditionType.Global_AllMonsterAliveNum,nil, -COUNT_CEIL_NUM) self:Dispatch(ConditionType.Global_GivenMonsterAliveNum,nil, monsterID, -COUNT_CEIL_NUM) self:Dispatch(ConditionType.DeadNumber, self._context, monsterID, COUNT_CEIL_NUM) if self._needHPPctMonsterIDs[monsterID] then local comp_Attr = entity.components.attr self:Dispatch(ConditionType.Global_GivenMonsterRemainHPPct, nil, monsterID, entity,nil,-FP.tonumberV1(comp_Attr.hp)) end if killer then local originKiller = killer:GetOriginEntity() if originKiller:IsMainEntityOfPlayer() then --不同步 不可用于同步方法 if originKiller:IsPlayerSelf() then self._selfKillNums = self._selfKillNums + COUNT_CEIL_NUM EventSystem.Dispatch(EventID.Level_UpdateKillNum, self._selfKillNums) end --同步 可用于同步方法 if originKiller:IsHero() then self._syncKillNums = self._syncKillNums + COUNT_CEIL_NUM self:Dispatch(ConditionType.Global_HeroKillNums, nil, self._syncKillNums) end end end self._coveredKillerID = nil end function LevelItem_Global:Notify_MonsterHPChanged(entity, realDelta) local monsterID = entity._logicInitData.CharacterID if self._needHPPctMonsterIDs[monsterID] then self:Dispatch(ConditionType.Global_GivenMonsterRemainHPPct,nil,monsterID, entity,nil,FP.tonumberV1(realDelta)) end end function LevelItem_Global:Notify_MonsterItemDeadAll(entity) if LevelItemManager.CheckMonsterItemDeadAll() then local killer = entity.components.record.KillerEntity self._coveredKillerID = killer and killer:GetEntityID() or nil self:Dispatch(ConditionType.Global_MonsterDeadAll, self._context) self._coveredKillerID = nil end end function LevelItem_Global:Notify_MonsterAIMessage(entity,aiID) local monsterID = entity._logicInitData.CharacterID self:Dispatch(ConditionType.ReceiveAI,nil,monsterID,aiID) end function LevelItem_Global:Notify_AddItemOnMap(itemID) if not table.containValue(self._mapItemIDList, itemID) then table.insert(self._mapItemIDList, itemID) end end function LevelItem_Global:Notify_DeleteItemOnMap(itemID) table.removebyvalue(self._mapItemIDList, itemID) end function LevelItem_Global:Notify_NpcVisited(entity) self._curVisitedEntity = entity end function LevelItem_Global:Notify_MonsterInteracted(entity, interactData) local monsterID = entity._logicInitData.CharacterID self:Dispatch(ConditionType.InteractNumber,nil, monsterID, COUNT_CEIL_NUM) end function LevelItem_Global:Notify_NpcInteracted(entity) local comp_Move = entity.components.move if self._interactNpc then if self._interactNpc ~= entity then SystemManager.RotateToDir(self._interactNpc, self._interactNpcDir) end else self._interactNpcDir:Reset(comp_Move.LogicRotateDir) end self._interactNpc = entity local characterData = entity.components.base.CurCharacterData --主视角调用 if not characterData.NotFacePlayer then SystemManager.RotateToEntity(entity, LogicUpdateManager._curEntity) end end function LevelItem_Global:GetEntityMissionAim(entity) local mission = self._curSelectMissionItem or self._curMainMissionItem if mission then local playerID = entity:GetPlayerID() return mission:GetMissionAimByPlayerID(playerID) end end function LevelItem_Global:Notify_MissionStart(missionItem) if missionItem:CheckMainMission() then self._curMainMissionItem = missionItem end if missionItem.LevelItemID == self._selectMissionID then self._curSelectMissionItem = missionItem self._selectMissionID = nil end end function LevelItem_Global:Notify_MissionEnd(missionItem) if self._curMainMissionItem == missionItem then self._curMainMissionItem = nil end if self._curSelectMissionItem == missionItem then self._curSelectMissionItem = nil end end function LevelItem_Global:Notify_DialogueCommand(branch) local msgIDs = table.remove(self._dialogueMessageIDsQueue, 1) if msgIDs then local id = msgIDs[branch] if id then self:Dispatch(ConditionType.Global_ReceiveLevelMessage,nil, id) end else logging.error(LTAG.ERROR, "不正常情况:执行对话的选择框指令时,对话信息缓存队列为空") end end function LevelItem_Global:Notify_ServerMessage(msgID) self:Dispatch(ConditionType.Global_ReceiveServerMessage,nil,msgID) end function LevelItem_Global:Notify_ServerHasNextLevel(hasNext) self:Dispatch(ConditionType.Global_HasNextLevel,nil,hasNext) end function LevelItem_Global:Notify_ConfrontationOccured(confrontation) self._confrontationTimer = LuaConst.ConfrontationCoolDown self:UpdateConfrontationChecker(confrontation) end function LevelItem_Global:Notify_CollectionDone(collectionID) self:Dispatch(ConditionType.CollectNumber,nil, collectionID, COUNT_CEIL_NUM) end function LevelItem_Global:Notify_LoadingOver() self:Dispatch(ConditionType.Global_LoadingOver) end --endregion 全局通知 --region--***************内部方法***************-- function LevelItem_Global:IsLevelFinished() return self._isLevelFinished end function LevelItem_Global:HandelEntityAction(match, context, func, ...) local checkFunc = LevelItemManager.MatchCheckFunc for i,v in MatchIter[match.Range](context) do if checkFunc[match.Check](v,match.Param) then func(v,...) end end end function LevelItem_Global:HandleEndLevel(isWin, withShow, persist, dontDeadQuitMonster) --if FP.GreaterEquals(self._levelRemainTimer,0) then if not self._isLevelFinished and FP.Greater(self.ItemData.LevelInfo.Timer,0) then LevelManager.CurLevelFunc:BeforeEndLevel() self._isLevelFinished = true LevelManager.AddSummaryTime(self._levelPassTimer, persist) self:Dispatch(ConditionType.Global_LevelEnd,nil, isWin) EventSystem.Dispatch(EventID.Level_Score) LevelItemManager.OnEndLevel() LevelEvaluationManager.StopEvaluations() if not dontDeadQuitMonster then for i,entity in LogicUpdateManager.ValidMonsterEntityIter() do SystemManager.DeadQuit(entity) end end self:ResetAllEntityState() MissileManager.Clear() LogicUpdateManager.StopElementTick() if isWin then LevelManager.CurLevelFunc:OnLevelSucceed(withShow) else LevelManager.CurLevelFunc:OnLevelFail() end end end --重置所有战斗单位为Idle状态 function LevelItem_Global:ResetAllEntityState() for i,v in ipairs(LogicUpdateManager.EntityList_Normal) do if v:IsAlive() then SystemManager.BreakState(v) end end for i,v in ipairs(LogicUpdateManager.EntityList_Sync) do if v:IsAlive() then SystemManager.BreakState(v) end end end function LevelItem_Global:HandleComboNumber() if self._frameHitNum > 0 then self._comboHitNum = self._comboHitNum + self._frameHitNum self._frameHitNum = 0 self._comboRemainTimer = COMBO_REMAIN_DURATION EventSystem.Dispatch(EventID.Level_UpdateComboNum, self._comboHitNum) end if self._comboRemainTimer > 0 then self._comboRemainTimer = self._comboRemainTimer - LuaConst.TimeSpan if self._comboRemainTimer <= 0 then self._comboHitNum = 0 EventSystem.Dispatch(EventID.Level_UpdateComboNum, self._comboHitNum) end end end function LevelItem_Global:ResetComboNumber() self._comboHitNum = 0 end function LevelItem_Global:HandleMission() --刷新任务路点信息 for i, entity in LogicUpdateManager.ValidSyncEntityIter() do if entity:IsHero() then local missionAim = self:GetEntityMissionAim(entity) if missionAim then missionAim:RefreshPathIndex(entity.components.move.LogicPos) end end end end function LevelItem_Global:HandleMissionGuide() local mission = self._curSelectMissionItem or self._curMainMissionItem if not self._pathGuideTimer or not mission then ExpLevelManager.HidePathGuide() return end if FP.Greater(self._pathGuideTimer, 0) then self._pathGuideTimer:Sub(LuaConst.TimeSpan) for i, entity in LogicUpdateManager.ValidSyncEntityIter() do local missionAim = self:GetEntityMissionAim(entity) missionAim:RefreshCurrentGuidePosition(entity.components.move.LogicPos) end else self._pathGuideTimer:Reset(LuaConst.GUIDE_POINT_FREQUENCY) for i, entity in LogicUpdateManager.ValidSyncEntityIter() do local pathFind = false local missionAim = self:GetEntityMissionAim(entity) if missionAim then local position = missionAim:RefreshCurrentGuidePosition(entity.components.move.LogicPos) if position then SystemManager.FindPath2(entity, position, true) pathFind = true end end if entity == LogicUpdateManager._curEntity then if pathFind then ExpLevelManager.ShowPathGuide(entity.components.move.LogicPos, entity) else ExpLevelManager.HidePathGuide() end end end end end function LevelItem_Global:HandleNPCInteracted() if not self._interactNpc then return end local mainEntityMove = LogicUpdateManager._curEntity.components.move local comp_Move = self._interactNpc.components.move if FP.V2.IsDistanceSqrGreater(mainEntityMove.LogicPos, comp_Move.LogicPos, LogicUpdateManager.NPCTurnSqrDistance) then SystemManager.RotateToDir(self._interactNpc, self._interactNpcDir) self._interactNpc = nil self._interactNpcDir:Reset() end end function LevelItem_Global:HandleShowDialogue(param1, param2, entity) if param2 then table.insert(self._dialogueMessageIDsQueue, param2.LevelMessageIDs) end if LogicUpdateManager.IsInReconnectFastPlay() then return end EventSystem.Dispatch(EventID.UI_MainShowDialogue ,param1,self._callback_Dialogue,param2, entity) end function LevelItem_Global:HandleSlowMotion(slowMotionID) if self._curSlowMotionID then self:Dispatch(ConditionType.Global_SlowMotionEnd,nil,self._curSlowMotionID) end self._curSlowMotionID = slowMotionID self._slowMotionTimer = FP.newV1(SLOW_MOTION_DURATION) for entityID ,entity in pairs(LogicUpdateManager._entityDic) do SystemManager.OnAddTimeScale(entity,"slowMotion",SLOW_MOTION_SCALE,-1,LuaConst.TimeScaleBreakType.LevelPauseBreak) end SystemManager.PlayPsEffect(EFFECT_PATH) end function LevelItem_Global:UpdateConfrontationChecker(confrontation) local entity = confrontation.entity local pctArray = entity.components.base.CurMonsterFeature.ConfrontationPctHP local hpPct = entity.components.attr:HitPointPercents() local checker = 0 for i = #pctArray,1,-1 do--hp percent array are in inverted order,such as {80,40} local compare = pctArray[i]/100 if FP.Greater(hpPct,compare) then checker = compare else break end end if confrontation.hpChecker > checker then confrontation.hpChecker = checker end end function LevelItem_Global:HandleConveyPlayRandom(entity, total, list, aiID) local random = LogicRandom.GetRangeValue(nil, 0, total, 76802) local value = 0 local itemID for i,v in ipairs(list) do value = value + v.Weight if not FP.Greater(random, value) then itemID = v.ID break end end if itemID then local targetItem = LevelItemManager.GetItemByID(itemID,LuaConst.LevelItemType.TargetPoint) local itemData = targetItem.ItemData SystemManager.OnConvey(entity, itemData.ItemPos, itemData.ItemDir) self:HandleStartSystemLevelAuto(entity, aiID) end end function LevelItem_Global:HandleStartSystemLevelAuto(entity, aiID) if aiID > 0 then SystemManager.SetAIByID(entity, aiID) SystemManager.StartAutoFight(entity, true) end end --endregion 内部方法 --region --***************外部方法***************-- function LevelItem_Global:IsShowingTimeline() return self._playingTimelineCount > 0 end --是否在显示打断性对话(DialogueType == LuaConst.EDialogueType.Normal的) function LevelItem_Global:IsShowingDialogue() return self.isShowingDialogue end function LevelItem_Global:IsShowingMovie() return self.isShowingMovie end function LevelItem_Global:GetRemainTime() return self._levelRemainTimer end function LevelItem_Global:AddRemainTime(delta) self._levelRemainTimer:Add(delta) end function LevelItem_Global:SetRemainTime(value) self._levelRemainTimer:Reset(value) end function LevelItem_Global:GetPassTime() return self._levelPassTimer end function LevelItem_Global:GetLevelWave() return self._levelWave end function LevelItem_Global:GetCurVisitedEntity() return self._curVisitedEntity end function LevelItem_Global:GetConfrontations() if not self._confrontationTimer then return self._confrontations end end function LevelItem_Global:GetShowProgressTimer() return self._showProgressTimer end function LevelItem_Global:GetShowProgressInfo() return self._showProgressName, self._showProgressIsGrowMode end function LevelItem_Global:GetMapItemIDIter() return ipairs(self._mapItemIDList) end function LevelItem_Global:LookForMissionAimEntity(missionAim) local monsterID = missionAim.Data.ParamID local itemIDList = missionAim.Data.ItemIDList local entity if monsterID then entity = LevelItemManager.GetMonsterByID(monsterID) elseif itemIDList then entity = LevelItemManager.GetMonsterByItemIDs(itemIDList) end if entity then missionAim:ReceiveAimEntity(entity) end end --endregion 外部方法 --region --***************行为方法***************-- ActionFunc[ActionType.Global_LevelSucceed] = function(self) self:HandleEndLevel(true,true) end ActionFunc[ActionType.Global_LevelFail] = function(self) self:HandleEndLevel(false) end ActionFunc[ActionType.Global_PlayTimeLine] = function(self,param1,param2,match,context,param3) local cutsceneAutoPassTime = LevelManager.GetCutsceneAutoPassTime() for i,v in ipairs(param1) do self._playingTimelineCount = self._playingTimelineCount + 1 --timeline配置成连续跳过,并且上一个连续的上一个timeline跳过了 if context and context.IsSkipTimeLine and v.SkipContinue then --下一个监听上一个的播放结束,如果上一下是跳过,这个也配置了跳过,则直接跳过 cutsceneAutoPassTime=0 elseif v.SkipContinue then --同时进队列n个timeline,将配置跳过设置到timeline参数中 cutsceneAutoPassTime=-99 end SystemManager.PlayTimeline(v.Path, param2, cutsceneAutoPassTime, self._callback_Timeline, LuaConst.ETimelinePlayReqSourceFlag.LEVEL_ITEM_GLOBAL, v.Time, nil, v.AdsorbType, v.AdsorbParam) end end --TODO: 为了可以热更临时添加的行为,仅限播放timeline时候使用 ActionFunc[ActionType.Global_SetTimelineCameraOrthographic] = function(self) if LogicUpdateManager.IsInReconnectFastPlay() then return end if LevelManager.IsNeedCheckNotSyncLevel() then return end if LevelManager.GetCutsceneAutoPassTime() ~= 0 then ExpSystemManager.ChangeCameraOrthographic() end end ActionFunc[ActionType.Global_PlayDialogue] = function(self,param1,param2,match,context) local data = DataSheetManager.DialogueData:GetDataByFirstKeyAndIndex(param1,1) self.isShowingDialogue = data.DialogueType == LuaConst.EDialogueType.Normal if not match then self:HandleShowDialogue(param1, param2) else local iter = MatchIter[match.Range] if iter then for i, entity in iter(context) do if LevelItemManager.MatchCheckFunc[match.Check](entity, match.Param) then self:HandleShowDialogue(param1, param2, entity) end end else if LevelItemManager.MatchCheckFunc[match.Check](LogicUpdateManager._curEntity, match.Param) then self:HandleShowDialogue(param1, param2, LogicUpdateManager._curEntity) end end end end ActionFunc[ActionType.Global_PlayMovie] = function(self,param1,param2) self.isShowingMovie = true local isDebugSkip= USE_LUA_STANDALONE or LevelManager.IsNeedCheckNotSyncLevel() or MDL.Cheat.Get_IsDebugSkipTimeline() -- 由于自动跑关卡也需要跳过,故加上了USE_LUA_STANDALONE for i,v in ipairs(param1) do if isDebugSkip then self._callback_Movie(v) else local context = { movieID = v, banSkipTime = param2 and param2[i] or nil, autoPassTime = -1, callback = self._callback_Movie} if UIManager.IsViewOpened(Const_UI_Lua.UIEnum.UIMoviePanel) then EventSystem.Dispatch(EventID.UI_MoviePanel_OpenInit, context) else UIManager.OpenView(Const_UI_Lua.UIEnum.UIMoviePanel, context) end end end end ActionFunc[ActionType.Global_ConveyPlayer] = function(self, param1, param2, match, context) local playerConveyType local aiID = -1 if type(param1) == "number" then playerConveyType = param1 else playerConveyType = param1[1] aiID = param1[2] end if playerConveyType == LuaConst.PlayerConveyType.InLevel_ByIndex then --代表关卡内部传送 for i,v in ipairs(param2) do local entities = LevelPlayerManager.GetPlayerEntitysByPlayerIDInRoom(i) if entities then local entity = entities[1] local targetItem = LevelItemManager.GetItemByID(v,LuaConst.LevelItemType.TargetPoint) local itemData = targetItem.ItemData SystemManager.OnConvey(entity, itemData.ItemPos, itemData.ItemDir, nil, itemData.CamAngle) self:HandleStartSystemLevelAuto(entity, aiID) end end elseif playerConveyType == LuaConst.PlayerConveyType.OverLevel_ByIndex then --代表跨关卡传送 LevelManager.CurLevelFunc:OnLevelConvey(param2) self:HandleEndLevel(true,false) elseif playerConveyType == LuaConst.PlayerConveyType.InLevel_All_Random then local totalWeight = 0 for i, v in ipairs(param2) do totalWeight = totalWeight + v.Weight end for i, entity in MatchIter[LuaConst.MatchRangeType.Player] do self:HandleConveyPlayRandom(entity,totalWeight,param2, aiID) end elseif playerConveyType == LuaConst.PlayerConveyType.InLevel_Executor_Random then local totalWeight = 0 for i, v in ipairs(param2) do totalWeight = totalWeight + v.Weight end for i, entity in MatchIter[LuaConst.MatchRangeType.Executor](context) do if entity:IsHero() then self:HandleConveyPlayRandom(entity,totalWeight,param2, aiID) end end end end ActionFunc[ActionType.Global_SetLevelWave] = function(self,param1,param2) self._levelWave = param1 self:Dispatch(ConditionType.Global_LevelWaveReach, nil, param1) EventSystem.Dispatch(EventID.UIBattle_Level_UpdateWave, param1, param2) end ActionFunc[ActionType.Global_ShowPathGuide] = function(self,param1) self._pathGuideTimer = FP.newV1(0) self._selectMissionID = nil self._curSelectMissionItem = nil if param1 then local missionItem = LevelItemManager.GetItemByID(param1,LuaConst.LevelItemType.Mission) if missionItem.IsActive then self._curSelectMissionItem = missionItem else self._selectMissionID = param1 end end end ActionFunc[ActionType.Global_HidePathGuide] = function(self) self._pathGuideTimer = nil self._selectMissionID = nil self._curSelectMissionItem = nil ExpLevelManager.HidePathGuide() end ActionFunc[ActionType.Global_ShowTimerProgress] = function(self,param1,param2, match, context, param3) self._showProgressTimer = param1 and FP.newV1(param1) or nil self._showProgressName = param2 if param3 == nil then -- 为了适配之前的数据进行的特殊处理 self._showProgressIsGrowMode = true --关卡进度条是否为增涨形式 else self._showProgressIsGrowMode = param3 --关卡进度条是否为增涨形式 end self._showProgressFrameCount = 0 EventSystem.Dispatch(EventID.UIBattle_Level_SetProgressBar, param1, param2) end ActionFunc[ActionType.Global_PlaySound] = function(self,param1) EventSystem.Dispatch(EventID.PlayGameSound ,param1,true) end ActionFunc[ActionType.Global_StopSound] = function(self,param1) EventSystem.Dispatch(EventID.StopGameSound ,param1) end ActionFunc[ActionType.Global_ResetEvent] = function(self,param1) LevelItemManager.ResetEvent(param1) end ActionFunc[ActionType.Global_ActiveEvent] = function(self,param1) LevelItemManager.ActiveEvent(param1) end ActionFunc[ActionType.Global_DeactiveEvent] = function(self,param1) LevelItemManager.DeactiveEvent(param1) end ActionFunc[ActionType.Global_SwitchCamera] = function(self,param1,param2, match, context, param3) local camera1ID = param1[1] local camera2ID = param1[2] or 0 if camera1ID and camera1ID > 0 then CameraController.Instance:StartPatternSystem(camera1ID, camera2ID, param2) end if param3 == 1 then -- 对于当前处于索敌状态的处理 0- 不变化 1-去掉索敌 2-尝试恢复之前的索敌状态 ExpSystemManager.OnEscapeCameraLock(nil, true) elseif param3 == 2 then ExpSystemManager.TryRecoverMyBeforeCameraLock() end end ActionFunc[ActionType.Global_CameraLookLevelItem] = function(self,param1) local item = LevelItemManager.GetItemByID(param1, LuaConst.LevelItemType.SceneActor) if item._renderEntity then AuxUtil.SetCurRenderEntity(item._renderEntity) ExpSystemManager.SetForceLookRenderEntity(item._renderEntity) item:SetIsCameraLook(true) end end ActionFunc[ActionType.Global_FreezeLevelTime] = function(self,param1) if param1 then LevelItemManager.Global:FreezeLevelTime() else LevelItemManager.Global:CancelFreezeLevelTime() end end ActionFunc[ActionType.Global_SetFightModeOfAllPlayer] = function(self, param1) SystemManager.SetFightModeOfAllPlayer(param1) end ActionFunc[ActionType.Global_MonsterItemRestock] = function(self, param1, param2) local list = LevelItemManager.GetItemIDListByGroup(param2, LuaConst.LevelItemType.Monster) if list then local emptyList = {} local notEmptyCount = 0 local levelItem for i,levelItemID in ipairs(list) do levelItem = LevelItemManager.GetItemByID(levelItemID) if levelItem._monsterRemainNums == 0 then table.insert(emptyList, levelItem) else notEmptyCount = notEmptyCount + 1 end end local emptyCount = #emptyList local restockCount = param1 - notEmptyCount if restockCount < emptyCount then --shuffle local rand local temp for i=#emptyList,1,-1 do rand = LogicRandom.GetIntegerValue(nil, 1, i) temp = emptyList[i] emptyList[i] = emptyList[rand] emptyList[rand] = temp end end for i=1,restockCount do if i <= emptyCount then emptyList[i]:OnActive() else break end end end end ActionFunc[ActionType.Global_ShowMapInfo] = function(self,param1) EventSystem.Dispatch(EventID.Level_OpenUIView, "Town/UIMapInfoView", { text = param1 }) end ActionFunc[ActionType.Global_SlowMotion] = function(self,param1) if LevelManager.IsLevelPause() then self._cacheSlowMotionID = param1 else self:HandleSlowMotion(param1) end end ActionFunc[ActionType.Global_SwitchWeather] = function(self, param1, param2) if type(param1) == "number" then EventSystem.Dispatch(EventID.LevelWeather_GlobalSwitchWeather, param1, param2) else local switchType = param1[1] local switchTime if switchType == LuaConst.SwitchWeatherType.FixedID_FixedTime or switchType == LuaConst.SwitchWeatherType.RandomID_FixedTime then switchTime = param1[2] else switchTime = FP.tonumberV1(LogicRandom.GetRangeValue(nil, param1[2], param1[3], 76502)) end local weatherId if switchType == LuaConst.SwitchWeatherType.RandomID_FixedTime or switchType == LuaConst.SwitchWeatherType.RandomID_RandomTime then local value = 0 for i, v in ipairs(param2) do value = value + v.Weight end local random = LogicRandom.GetRangeValue(nil, 0, value, 75502) value = 0 for i, v in ipairs(param2) do value = value + v.Weight if not FP.Greater(random, value) then weatherId = v.ID break end end else weatherId = param2 end EventSystem.Dispatch(EventID.LevelWeather_GlobalSwitchWeather, weatherId, tonumber(switchTime)) end end ActionFunc[ActionType.Global_EndGuideLevel] = function(self, param1) if param1 then EventSystem.Dispatch(EventID.Guide_SetGuideStep, param1) self:HandleEndLevel(true, not LevelManager.InGuideLevel) else self:HandleEndLevel(false) end end ActionFunc[ActionType.Global_ResetForceTarget] = function(self,param1,param2) --主视角调用 if not LogicUpdateManager._curEntity then return end local entity if param1 == SearchEntityType.None then entity = nil elseif param1 == SearchEntityType.ID then entity = LevelItemManager.GetMonsterByID(param2) elseif param1 == SearchEntityType.ItemID then entity = LevelItemManager.GetMonsterByItemID(param2) elseif param1 == SearchEntityType.ItemGroupID then entity = LevelItemManager.GetMonsterByItemIDs(param2) end --主视角调用 LogicUpdateManager._curEntity.components.target:SetForceTarget(entity) end ActionFunc[ActionType.Global_ReloadLevel] = function(self) if USE_LUA_STANDALONE then-- 校验服不能触发这个,会导致无限循环了 logging.error(LTAG.ERROR, "【gws】:校验服发现需要重新开关关卡,强制失败!") self:HandleEndLevel(false) return end local levelID = LevelManager.GetCurLevelID() LevelManager.SwitchLevel(levelID) end ActionFunc[ActionType.Global_PlayerOffDrive] = function(self) --主视角调用 local curEntity = LogicUpdateManager._curEntity if curEntity.components.drive.DriveEntity then SystemManager.OffDrive(curEntity) end end ActionFunc[ActionType.Global_ShowLevelTimer] = function(self,param1) --param1: 0为正计时,1为倒计时,nil为关闭计时 local timer = param1 and FP.tonumberV1(self._levelRemainTimer) or nil EventSystem.Dispatch(EventID.UIBattle_Level_SetLevelTimer,timer,param1 == 0) end ActionFunc[ActionType.Global_SwitchArmy] = function(self,param1, param2) local pos,dir,attr_sa,itemData,timeScales --主视角调用 if LogicUpdateManager._curEntity then local component = LogicUpdateManager._curEntity.components pos = component.move.LogicPos dir = component.move.LogicRotateDir attr_sa = component.attr.sa:cloneV1() local bornItemID = LogicUpdateManager._curEntity._logicInitData.OriginBornItemID itemData = LevelItemManager.GetItemDataByID(bornItemID) timeScales = component.timeScale.AddTimeScaleList else local bornPoint = LevelItemManager.GetBornItem(LuaConst.PlayerDefaultBornIndex) itemData = bornPoint.ItemData pos = LogicRandom.GetRandomPointInLevelItem(nil, itemData, 8238237) -- new 支持 固定/范围随机 位置出生 dir = itemData.ItemDir attr_sa = FP.newV1(0) end if param1 == 0 then LevelPlayerManager.ClearPlayerEntity(LuaConst.STANDALONE_PLAYER_PlayID) LevelPlayerManager.CreatePlayers(pos,dir) LevelManager.CurLevelFunc:SetIsAllHeroJoinBattle(nil) --主视角调用 LogicUpdateManager._curEntity:SetAttrBaseValue("sa",attr_sa) for i, entity in ipairs(LevelPlayerManager.GetPlayerEntitysByPlayerIDInRoom(LuaConst.STANDALONE_PLAYER_PlayID)) do entity.components.timeScale:SetAddTimeScales(timeScales) end EventSystem.Dispatch(EventID.Level_SwitchHero,LuaConst.SwitchHeroType.LevelAction,LogicUpdateManager._curEntity) else local armyData = DataSheetManager.LevelBattleArmy:GetDataByID(param1) if armyData then LevelPlayerManager.RecordHeroAttr(LuaConst.STANDALONE_PLAYER_PlayID) LevelPlayerManager.ClearPlayerEntity(LuaConst.STANDALONE_PLAYER_PlayID) LevelPlayerManager.CreatePlayers_ByArmyData(armyData,itemData.LevelItemID,pos,dir, param2==false) -- 当param2==false 全部出战 ,param2为nil或者true时 一个接一个出战。 LevelManager.CurLevelFunc:SetIsAllHeroJoinBattle(param2==false) --主视角调用 LogicUpdateManager._curEntity:SetAttrBaseValue("sa",attr_sa) for i, entity in ipairs(LevelPlayerManager.GetPlayerEntitysByPlayerIDInRoom(LuaConst.STANDALONE_PLAYER_PlayID)) do entity.components.timeScale:SetAddTimeScales(timeScales) end EventSystem.Dispatch(EventID.Level_SwitchHero,LuaConst.SwitchHeroType.LevelAction,LogicUpdateManager._curEntity) end end CameraController.Instance:ReactiveCamera() end ActionFunc[ActionType.Global_SetWeatherAnim] = function(self,param1,param2) if param1 then AuxUtil.StartWeatherAnim(param1,param2[1],param2[2],param2[3]) else AuxUtil.StopWeatherAnim() end end ActionFunc[ActionType.Global_PlayGuide] = function(self,param1) EventSystem.Dispatch(EventID.PlayerGuide_StartGuideByLevelAction,tonumber(param1),self._callback_Guide) --Play Guide By ID -- guideID : param1, callback :self._callback_Guide end ActionFunc[ActionType.Global_NotifyBuff] = function(self,param1) SystemManager.OnNotifyBuff(param1) end ActionFunc[ActionType.Global_PlayerHandleHorse] = function(self, param1, param2) if param1 then for i, entity in LogicUpdateManager.ValidSyncEntityIter() do SystemManager.ExecuteRideHorse(entity) end -- handle ui by param2 EventSystem.Dispatch(EventID.Level_HideSkillInput, true, param2.HideSkillMode) if param2.HideHorseBtn then EventSystem.Dispatch(EventID.Level_HideHorseInput, true) end else for i, entity in LogicUpdateManager.ValidSyncEntityIter() do SystemManager.OffHorse(entity) end --revert ui EventSystem.Dispatch(EventID.Level_HideSkillInput, false) EventSystem.Dispatch(EventID.Level_HideHorseInput, false) end end ActionFunc[ActionType.Global_SetBornItem] = function(self, param1, param2) local splits = string.split(param2, ",") local i = 1 local pairsList = {} if #splits == 1 then table.insert(pairsList, {key = tonumber(splits[1]), value = 1}) else while i < #splits do table.insert(pairsList, {key = tonumber(splits[i]), value = tonumber(splits[i + 1])}) i = i + 2 end end LevelManager.CurLevelFunc:AddBornItemID2WeightList(param1, pairsList) end --给外部的接口,主要是接给BattleEffect,最终是调用关卡行为 全局_设置出生点|复活点 --param1是一个至少有2个元素的数组,param1[1]是设置类型,param[2]是类型参数 --类型1=阵营 --类型2=出生点元素 --类型3=玩家 --param2是一个字符串,表示一组关卡元素和权重,用逗号分隔,比如:"1001,1,1002,2" 这个字符串表示的是:随机出生点时,关卡元素1001的权重是1,1002的权重是2 function LevelItem_Global:SetBornItem(param1, param2) ActionFunc[ActionType.Global_SetBornItem](self, param1, param2) end ActionFunc[ActionType.Global_SetRemainTime] = function(self, param1) self._levelRemainTimer:Reset(param1) -- 秒 --self._levelPassTimer -- 策划说了:不用设置 end ActionFunc[ActionType.Global_ShowBattleReport] = function(self, param1, param2) local str = UIUtils.GetLocalizedTxt(param1) EventSystem.Dispatch(EventID.UI_MainShowBattleReport, str) end ActionFunc[ActionType.Global_ActiveEvaluation] = function(self, param1) LevelEvaluationManager.ActiveEvaluation(param1) end ActionFunc[ActionType.DigTreasure_RewardBoxBorn] = function(self, param1, param2) EventSystem.Dispatch(EventID.DigTreasure_RewardBoxBorn) end ActionFunc[ActionType.HandleBuff] = function(self, param1, param2, match, context) if param1 then self:HandelEntityAction(match, context, SystemManager.AddBuff, param2, nil, nil, nil) self:AddEntityActionCache(match, ActionType.HandleBuff, param2, false) else self:HandelEntityAction(match, context, SystemManager.DeleteBuff, param2, nil) self:RemoveEntityActionCache(match, ActionType.HandleBuff, param2, false) end end -- param1 : dialogueID , param2 : random number ActionFunc[ActionType.ShowBubble] = function(self, param1, param2, match, context) if param2 <= 0 then return end local list = self._randomCacheList local func = SystemManager.ShowBubbleDialogue local checkFunc = LevelItemManager.MatchCheckFunc for i,v in MatchIter[match.Range](context) do if checkFunc[match.Check](v,match.Param) then table.insert(list, v) end end local leftTimes = param2 local count = #list while count > 0 do local index = math.random(1, count) --气泡是纯表现,先使用非定点数随机 func(list[index], param1) list[index] = list[count] count = count - 1 leftTimes = leftTimes - 1 if leftTimes == 0 then break end end table.clearArray(list) end ActionFunc[ActionType.NotifyAI] = function(self, param1, param2, match, context) self:HandelEntityAction(match, context, SystemManager.OnNotifyAI, param1) self:AddEntityActionCache(match, ActionType.NotifyAI, param1, false) end ActionFunc[ActionType.LockAI] = function(self, param1, param2, match, context) self:HandelEntityAction(match, context, SystemManager.OnLockAI, param1) if param1 then self:AddEntityActionCache(match,ActionType.LockAI,param1,true) else self:RemoveEntityActionCache(match,ActionType.LockAI,nil,true) end end local function DeadQuitIgnoreCount(entity) SystemManager.DeadQuit(entity, true) end ActionFunc[ActionType.Delete] = function(self, param1, param2, match, context) --TODO 这个是遗留的逻辑,感觉有些别扭,想下如何改造 if match.Range == LuaConst.MatchRangeType.All or match.Range == LuaConst.MatchRangeType.Monster then if match.Check == LuaConst.MatchCheckType.CharacterID then EventSystem.Dispatch(EventID.Level_DeleteMonster, match.Param) elseif match.Check == LuaConst.MatchCheckType.All then LevelItemManager.ClearMonsterItem() end end if param1 == false then -- 不要用 not param1 self:HandelEntityAction(match, context, DeadQuitIgnoreCount) else self:HandelEntityAction(match, context, SystemManager.DeadQuit) end end ActionFunc[ActionType.Rout] = function(self, param1, param2, match, context) --TODO 这个是遗留的逻辑,感觉有些别扭,想下如何改造 if match.Range == LuaConst.MatchRangeType.All or match.Range == LuaConst.MatchRangeType.Monster then if match.Check == LuaConst.MatchCheckType.CharacterID then EventSystem.Dispatch(EventID.Level_DeleteMonster, match.Param) elseif match.Check == LuaConst.MatchCheckType.All then LevelItemManager.ClearMonsterItem() end end self:HandelEntityAction(match, context, SystemManager.OnNotifyAI, LuaConst.LevelRoutAIID) end ActionFunc[ActionType.ShowObject] = function(self, param1, param2, match, context) self:HandelEntityAction(match, context, SystemManager.OnShowObject, param1, param2) end --endregion 行为方法 --region --***************缓存行为方法***************-- function LevelItem_Global:InitActionCache() self._allMonsterCacheList = {} self._monsterIDActionCache = {} self._monsterBornIDActionCache = {} self._monsterCampIDActionCache = {} end function LevelItem_Global:ClearActionCache() self._allMonsterCacheList = nil self._monsterIDActionCache = nil self._monsterBornIDActionCache = nil self._monsterCampIDActionCache = nil end function LevelItem_Global:AddEntityActionCache(match, type, param1, cover) --只针对存在怪物的匹配范围进行缓存 if match.Range == LuaConst.MatchRangeType.All or match.Range == LuaConst.MatchRangeType.Monster then if match.Check == LuaConst.MatchCheckType.CharacterID then self._monsterIDActionCache[match.Param] = self:AddCacheList(self._monsterIDActionCache[match.Param],type,param1,cover) elseif match.Check == LuaConst.MatchCheckType.BornItemID then for i, v in pairs(match.Param) do self._monsterBornIDActionCache[i] = self:AddCacheList(self._monsterBornIDActionCache[i],type,param1,cover) end elseif match.Check == LuaConst.MatchCheckType.CampID then for i, v in pairs(match.Param) do self._monsterCampIDActionCache[i] = self:AddCacheList(self._monsterCampIDActionCache[i],type,param1,cover) end else self._allMonsterCacheList = self:AddCacheList(self._allMonsterCacheList,type,param1,cover) end end end function LevelItem_Global:RemoveEntityActionCache(match,type,param1,cover) --只针对存在怪物的匹配范围进行缓存 if match.Range == LuaConst.MatchRangeType.All or match.Range == LuaConst.MatchRangeType.Monster then if match.Check == LuaConst.MatchCheckType.CharacterID then self:RemoveCacheList(self._monsterIDActionCache[match.Param],type,param1,cover) elseif match.Check == LuaConst.MatchCheckType.BornItemID then for i, v in pairs(match.Param) do self:RemoveCacheList(self._monsterBornIDActionCache[i],type,param1,cover) end elseif match.Check == LuaConst.MatchCheckType.CampID then for i, v in pairs(match.Param) do self:RemoveCacheList(self._monsterCampIDActionCache[i],type,param1,cover) end else self:RemoveCacheList(self._allMonsterCacheList,type,param1,cover) end end end function LevelItem_Global:HandleEntityActionCache(entity) self:ExecuteCacheList(self._allMonsterCacheList, entity) self:ExecuteCacheList(self._monsterIDActionCache[entity._logicInitData.CharacterID], entity) self:ExecuteCacheList(self._monsterBornIDActionCache[entity._logicInitData.BornItemID], entity) self:ExecuteCacheList(self._monsterCampIDActionCache[entity:GetCampID()], entity) end function LevelItem_Global:AddCacheList(list, type, param1, cover) list = list or {} if cover then for i = #list, 1, -1 do local value =list[i] if value[1] == type and value[2] == param1 then table.remove(list,i) break end end end table.insert(list, {type, param1}) return list end function LevelItem_Global:RemoveCacheList(list, type, param1, cover) if list then if cover then for i = #list, 1, -1 do local value = list[i] if value[1] == type then table.remove(list,i) end end else for i = #list, 1, -1 do local value = list[i] if value[1] == type and value[2] == param1 then table.remove(list,i) break end end end end end function LevelItem_Global:ExecuteCacheList(list, entity) if not list then return end for i,v in ipairs(list) do ActionCacheFunc[v[1]](entity,v[2]) end end ActionCacheFunc[ActionType.LockAI] = SystemManager.OnLockAI ActionCacheFunc[ActionType.NotifyAI] = SystemManager.OnNotifyAI ActionCacheFunc[ActionType.HandleBuff] = function(entity, buffID) SystemManager.AddBuff(entity, buffID, nil, nil, nil) end --endregion 缓存行为方法 return LevelItem_Global