local Base = require("Battle/Logic/AI/Decision/Decision_Base") local Decision_FourCountry = class("Decision_FourCountry", Base) local DODGE_KEYPOS = LuaConst.ESkillKeyPosition.Dodge local PHASE1_DODGE_MIN_FRAME_INTERVAL = FP.newV1(60) --1阶段闪避最低间隔 local PHASE1_DODGE_MAX_FRAME_INTERVAL = FP.newV1(100) --1阶段闪避最大间隔 local P1_SEARCH_ENEMY_DIS_SQR = FP.newV1(625) --阶段1索敌距离平方 local P2_SEARCH_ENEMY_DIS_SQR = FP.newV1(625) --阶段2索敌距离平方 local P3_SEARCH_ENEMY_DIS_SQR = FP.newV1(100) --阶段3索敌距离平方 local FP = FP local newV1 = FP.newV1 local newV2 = FP.newV2 local FIGHT_BACK_HP_PER = newV1(0.7) --血量低于这个百分比,就反击 local UNATTACK_TO_MOVE_FRAME_COUNT = 100 --阶段1、阶段3未受攻击跳转移动行为的时间(帧数,20帧是1秒) local P2_OUT_REGION_BACK_FRAME_COUNT = 40 --阶段2如果连续在圈外超过这个帧数,则转p1回圈内 local SyncFourCountryBlockDisappearTimeFrame = DataSheetManager.ConstData:GetDataByID("SyncFourCountryBlockDisappearTime").IntValue * LuaConst.LogicFrameRate local EPhase = { PREPARING = 0, RUN_TO_NORMAL_REGION = 1, STAY_IN_NORMAL_REGION = 2, RUN_TO_HIGH_REGION = 3, STAY_IN_HIGH_REGION = 4, } local p1PathPoints = { FP.newV2(0, 43.5), FP.newV2(0, -43.5), FP.newV2(43.5, 0), FP.newV2(-43.5, 0), } --[[ 初始化 --]] function Decision_FourCountry:initialize(entity) Base.initialize(self, entity) --类型 self.Type = LuaConst.DecisionType.FourCountry --瞬时 self.IsOnce = false end --[[ 能否进入 --]] function Decision_FourCountry:CanEnter(entity, decisionData, command) return true end --[[ 能否退出 --]] function Decision_FourCountry:CanExit(entity, decisionData, command) return false end function Decision_FourCountry:CanUseDodgeSkill(entity) local skillBase = entity.components.skillBase return self:CanAiUseSkill(entity, skillBase, skillBase:GetSkillDataByKeyPosition(DODGE_KEYPOS)) end function Decision_FourCountry:GetNearestYuanBaoPos(entity) return LevelManager.CurLevelFunc:GetNearestYuanBaoPos(entity) end function Decision_FourCountry:GetNearestP1PathPoint(entity, decisionRecordDic) decisionRecordDic._tempV1_b:Reset(99999999) local index = 1 local entityLogicPos = entity:GetLogicPos() for i,v in ipairs(p1PathPoints) do entityLogicPos:DistanceSqr(v, decisionRecordDic._tempV1) if decisionRecordDic._tempV1 < decisionRecordDic._tempV1_b then index = i decisionRecordDic._tempV1_b:Reset(decisionRecordDic._tempV1) end end return p1PathPoints[index], decisionRecordDic._tempV1_b:cloneV1() end function Decision_FourCountry:RefreshNearestHighRegionInfoToRecordDic(entity, decisionRecordDic) decisionRecordDic.highRegionCenter, decisionRecordDic.highRegionEntity = LevelManager.CurLevelFunc:GetNearestHighRegionCenter(entity) end function Decision_FourCountry:IsOutOfNormalRegion(decisionRecordDic, selfPos) selfPos:DistanceSqr(decisionRecordDic.center, decisionRecordDic._tempV1) return decisionRecordDic._tempV1 > decisionRecordDic.normalRegionRadiusSqr end function Decision_FourCountry:IsOutOfHighRegion(decisionRecordDic, selfPos) local result if decisionRecordDic.highRegionCenter then if decisionRecordDic.highRegionEntity:IsAlive() and decisionRecordDic.highRegionEntity:IsActive() then selfPos:DistanceSqr(decisionRecordDic.center, decisionRecordDic._tempV1) if decisionRecordDic._tempV1 > decisionRecordDic.lavaInnerRadiusSqr then result = true else local highRegionEntityLogicRotateDir = decisionRecordDic.highRegionEntity.components.move.LogicRotateDir if decisionRecordDic._tempV1_b:Reset(highRegionEntityLogicRotateDir.x):Mul(selfPos.x) < FP.Const.Zero then result = true elseif decisionRecordDic._tempV1_b:Reset(highRegionEntityLogicRotateDir.z):Mul(selfPos.z) < FP.Const.Zero then result = true else --在 decisionRecordDic.lavaInnerRadiusSqr 范围内, 且象限跟 highRegionEntity.components.move.LogicRotateDir 匹配,则表示没有 IsOutOfHighRegion result = false end end else result = true end else result = true end return result end --[[ 进入该Decision --]] function Decision_FourCountry:DecisionIn(entity, decisionData) local decisionRecordDic = entity.components.aiBase:GetDecisionRecordDic(decisionData) decisionRecordDic.center = newV2(0, 0) decisionRecordDic.lavaInnerRadius = newV1(30) decisionRecordDic.lavaInnerRadiusSqr = decisionRecordDic.lavaInnerRadius * decisionRecordDic.lavaInnerRadius decisionRecordDic.lavaOutterRadius = newV1(37) decisionRecordDic.lavaOutterRadiusSqr = decisionRecordDic.lavaOutterRadius * decisionRecordDic.lavaOutterRadius decisionRecordDic.normalRegionRadius = newV1(50) decisionRecordDic.normalRegionRadiusSqr = decisionRecordDic.normalRegionRadius * decisionRecordDic.normalRegionRadius decisionRecordDic.toP2DisSqr = newV1(100) --如果处于 RUN_TO_NORMAL_REGION 阶段,且到center的距离小于 toP2DisSqr ,则切换到下一阶段 decisionRecordDic.highRegionRadius = newV1(100) --未完成HYW now now now now now decisionRecordDic.toP4DisSqr = decisionRecordDic.highRegionRadius / 4 --如果处于 RUN_TO_HIGH_REGION 阶段,且到highRegionCenter的距离小于 toP4DisSqr ,则切换到下一阶段 decisionRecordDic.aiUpdateFrameInterval = entity.components.aiBase:GetAiUpdateInterval() decisionRecordDic.phase = EPhase.PREPARING decisionRecordDic.phaseFrameEla = 0 decisionRecordDic.dodgeSkillIndex = entity.components.skillBase:GetSkillIndexByKeyPosition(DODGE_KEYPOS) decisionRecordDic._tempV1 = FP.newV1(0) decisionRecordDic._tempV1_b = FP.newV1(0) decisionRecordDic.pathPointArrived = false decisionRecordDic.dontAutoRide = true end function Decision_FourCountry:ChangePhase(phase, entity, decisionData, decisionRecordDic, command, aiBaseComponent) if decisionRecordDic.phase ~= phase then decisionRecordDic.phase = phase -- local str -- if phase == 0 then -- str = "准备阶段-PREPARING" -- elseif phase == 1 then -- str = "跑向普通区域-RUN_TO_NORMAL_REGION" -- elseif phase == 2 then -- str = "待在普通区域-STAY_IN_NORMAL_REGION" -- elseif phase == 3 then -- str = "跑向高分区域-RUN_TO_HIGH_REGION" -- elseif phase == 4 then -- str = "待在高分区域-STAY_IN_HIGH_REGION" -- end -- logging.error(LTAG.ERROR, "HYW : Change To Phase : ", phase, str) --logging.error(LTAG.ERROR, "HYW : ChangePhase : ", phase) if phase == EPhase.RUN_TO_NORMAL_REGION then decisionRecordDic.pathPointArrived = false elseif phase == EPhase.STAY_IN_NORMAL_REGION then decisionRecordDic.p2OutRegionFrame = 0 elseif phase == EPhase.RUN_TO_HIGH_REGION then --elseif phase == EPhase.NEAR_TO_STRONGHOLD_FIGHTING then --end decisionRecordDic.phaseFrameEla = 0 end end end function Decision_FourCountry:RunToNRIntervalDodge(entity, command, decisionRecordDic) if self:CanUseDodgeSkill(entity) then if decisionRecordDic.phase1DodgeFrame == nil then decisionRecordDic.phase1DodgeFrame = LogicRandom.GetRangeValue(entity, PHASE1_DODGE_MIN_FRAME_INTERVAL, PHASE1_DODGE_MAX_FRAME_INTERVAL, 3431425):Add(LogicUpdateManager._clientHandleFrame) end if FP.Less(decisionRecordDic.phase1DodgeFrame, LogicUpdateManager._clientHandleFrame) then command.SkillIndex = decisionRecordDic.dodgeSkillIndex decisionRecordDic.phase1DodgeFrame = nil end end end local PAUSE_FRAME_AFTER_USER_INPUT = 10 --有玩家输入后,该Decision暂停几帧 --[[ 输出指令 --]] function Decision_FourCountry:SetCommand(entity, decisionData, command) repeat if LogicUpdateManager._clientHandleFrame < SyncFourCountryBlockDisappearTimeFrame then command.DontHandle = true break end local aiBaseComponent = entity.components.aiBase local decisionRecordDic = aiBaseComponent:GetDecisionRecordDic(decisionData) if command.MoveDir ~= FP.Const.Vector2_Zero or command.SkillIndex ~= 0 then --如果有玩家输入,记录这个输入的时间,并跳出AI运行 decisionRecordDic.lastUserInputFrame = LogicUpdateManager._clientHandleFrame entity.components.target:SetForceTarget(nil) command.DontHandle = true break end decisionRecordDic.phaseFrameEla = decisionRecordDic.phaseFrameEla + decisionRecordDic.aiUpdateFrameInterval if decisionRecordDic.lastUserInputFrame and LogicUpdateManager._clientHandleFrame - decisionRecordDic.lastUserInputFrame < PAUSE_FRAME_AFTER_USER_INPUT then --策划需求:如果玩家有输入,就得暂停AI运行一段时间 command.DontHandle = true break end local selfPos = entity.components.move.LogicPos local phase = decisionRecordDic.phase or EPhase.PREPARING local toCenterDistSqr = FP.V2.DistanceSqr(selfPos, decisionRecordDic.center) if phase == EPhase.PREPARING then phase = self:SetCommandPhase_Preparing() elseif phase == EPhase.RUN_TO_NORMAL_REGION then phase = self:SetCommandPhase_RunToNormalRegion(entity, phase, command, decisionData, decisionRecordDic, selfPos, toCenterDistSqr) elseif phase == EPhase.STAY_IN_NORMAL_REGION then phase = self:SetCommandPhase_StayInNormalRegion(entity, phase, command, decisionData, decisionRecordDic, selfPos, aiBaseComponent, toCenterDistSqr) elseif phase == EPhase.RUN_TO_HIGH_REGION then phase = self:SetCommandPhase_RunToHighRegion(entity, phase, command, decisionData, decisionRecordDic, selfPos) elseif phase == EPhase.STAY_IN_HIGH_REGION then phase = self:SetCommandPhase_StayInHighRegion(entity, phase, command, decisionData, decisionRecordDic, selfPos) -- elseif phase == EPhase.NEAR_TO_STRINGHOLD_MOVING then -- --移动 -- phase = self:SetCommandPhase_BackToSH(entity, phase, command, decisionData, decisionRecordDic, selfPos, aiBaseComponent, toCenterDistSqr, strongHoldCenter) -- elseif phase == EPhase.RUN_TO_BUFF then -- --去吃Buff -- phase = self:SetCommandPhase_RunToBuff(entity, phase, command, decisionData, decisionRecordDic, aiBaseComponent) -- elseif phase == EPhase.ESCAPE then -- phase = self:SetCommandPhase_Escape(entity, phase, command, decisionData, decisionRecordDic) end self:ChangePhase(phase, entity, decisionData, decisionRecordDic, command, aiBaseComponent) until true return command end function Decision_FourCountry:SetCommandPhase_StayInHighRegion(entity, phase, command, decisionData, decisionRecordDic, selfPos) SystemManager.OnSearchTarget(entity, 1, P3_SEARCH_ENEMY_DIS_SQR, 1, 0) if entity.components.target.Target then local isSkillUsed = false --有目标就打目标 command,isSkillUsed = self:CommandUseSkill(entity, command, decisionRecordDic) end if self:IsOutOfHighRegion(decisionRecordDic, selfPos) then phase = EPhase.RUN_TO_NORMAL_REGION end return phase end function Decision_FourCountry:SetCommandPhase_RunToHighRegion(entity, phase, command, decisionData, decisionRecordDic, selfPos) if decisionRecordDic.highRegionCenter == nil or not decisionRecordDic.highRegionEntity:IsAlive() or not decisionRecordDic.highRegionEntity:IsActive() then self:RefreshNearestHighRegionInfoToRecordDic(entity, decisionRecordDic) end local center = decisionRecordDic.highRegionCenter if center then local toCenterDistSqr = FP.V2.DistanceSqr(selfPos, center) if toCenterDistSqr > decisionRecordDic.toP4DisSqr then if entity.components.attr:HitPointPercents() >= FIGHT_BACK_HP_PER then command = self:CommandFindPathAndRunTo(entity, center, command, false, decisionData, 1000) else local hpSubTimeStamp = entity.components.record.hpSubTimeStamp or -999999 if LogicUpdateManager._clientHandleFrame - hpSubTimeStamp > UNATTACK_TO_MOVE_FRAME_COUNT then command = self:CommandFindPathAndRunTo(entity, center, command, false, decisionData, 1000) else --索敌 SystemManager.OnSearchTarget(entity, 1, P3_SEARCH_ENEMY_DIS_SQR, 1, 0) if entity.components.target.Target then local isSkillUsed = false --有目标就打目标 command,isSkillUsed = self:CommandUseSkill(entity, command, decisionRecordDic) if not isSkillUsed then --如果释放技能失败,就往阶段目标点跑 command = self:CommandFindPathAndRunTo(entity, center, command, false, decisionData, 1000) end else -- 没有目标继续向阶段目标点跑 command = self:CommandFindPathAndRunTo(entity, center, command, false, decisionData, 1000) end end end else phase = EPhase.STAY_IN_HIGH_REGION end else phase = EPhase.RUN_TO_NORMAL_REGION end return phase end function Decision_FourCountry:SetCommandPhase_StayInNormalRegion(entity, phase, command, decisionData, decisionRecordDic, selfPos, aiBaseComponent, toCenterDistSqr) self:RefreshNearestHighRegionInfoToRecordDic(entity, decisionRecordDic) if decisionRecordDic.highRegionCenter then phase = EPhase.RUN_TO_HIGH_REGION else SystemManager.OnSearchTarget(entity, 1, P2_SEARCH_ENEMY_DIS_SQR, 1, 0) if entity.components.target.Target then local isSkillUsed = false --有目标就打目标 command,isSkillUsed = self:CommandUseSkill(entity, command, decisionRecordDic) if not isSkillUsed then --如果释放技能失败,就往阶段目标点跑 command = self:CommandFindPathAndRunTo(entity, center, command, false, decisionData, 1000) end --else --没有目标就站立等待 --do nothing --old↓ -- -- 没有目标就找元宝 -- local yuanbaoPos = self:GetNearestYuanBaoPos(entity) -- if yuanbaoPos then -- command = self:CommandFindPathAndRunTo(entity, yuanbaoPos, command, false, decisionData, 1000) -- --else -- --do nothing 没有元宝则站立等待 -- end --old↑ end end if self:IsOutOfNormalRegion(decisionRecordDic, selfPos) then decisionRecordDic.p2OutRegionFrame = decisionRecordDic.p2OutRegionFrame + 1 if decisionRecordDic.p2OutRegionFrame > P2_OUT_REGION_BACK_FRAME_COUNT then phase = EPhase.RUN_TO_NORMAL_REGION end else decisionRecordDic.p2OutRegionFrame = 0 end return phase end function Decision_FourCountry:TryFightBack(entity, command, targetPos, decisionData, decisionRecordDic) local hpSubTimeStamp = entity.components.record.hpSubTimeStamp or -999999 if LogicUpdateManager._clientHandleFrame - hpSubTimeStamp > UNATTACK_TO_MOVE_FRAME_COUNT then command = self:CommandFindPathAndRunTo(entity, targetPos, command, false, decisionData, 1000) --self:RunToNRIntervalDodge(entity, command, decisionRecordDic) else --索敌 SystemManager.OnSearchTarget(entity, 1, P1_SEARCH_ENEMY_DIS_SQR, 1, 0) if entity.components.target.Target then local isSkillUsed = false --有目标就打目标 command,isSkillUsed = self:CommandUseSkill(entity, command, decisionRecordDic) if not isSkillUsed then --如果释放技能失败,就往阶段目标点跑 command = self:CommandFindPathAndRunTo(entity, targetPos, command, false, decisionData, 1000) end else -- 没有目标继续向阶段目标点跑 command = self:CommandFindPathAndRunTo(entity, targetPos, command, false, decisionData, 1000) end end end function Decision_FourCountry:SetCommandPhase_RunToNormalRegion(entity, phase, command, decisionData, decisionRecordDic, selfPos, toCenterDistSqr, strongHoldRadiusSqr) --距离据点很远时,向着据点附近跑的阶段,距离的平方大于P2_2_P1_MIN_DISTANCE_SQR代表距离很远 local center = decisionRecordDic.center local p1ToTargetDistSqr = FP.V2.DistanceSqr(selfPos, center) local nearesetPathPoint, toPathPointDistSqr if not decisionRecordDic.pathPointArrived then nearesetPathPoint, toPathPointDistSqr = self:GetNearestP1PathPoint(entity, decisionRecordDic) end if nearesetPathPoint and p1ToTargetDistSqr > decisionRecordDic.lavaOutterRadiusSqr then if entity.components.attr:HitPointPercents() >= FIGHT_BACK_HP_PER then if toPathPointDistSqr > FP.Const.One then decisionRecordDic.nearesetPathPoint = nearesetPathPoint command = self:CommandFindPathAndRunTo(entity, nearesetPathPoint, command, false, decisionData, 1000) end else self:TryFightBack(entity, command, decisionRecordDic.pathPointArrived and center or nearesetPathPoint, decisionData, decisionRecordDic) end if toPathPointDistSqr <= FP.Const.One then decisionRecordDic.pathPointArrived = true end else decisionRecordDic.pathPointArrived = p1ToTargetDistSqr > decisionRecordDic.lavaOutterRadiusSqr if p1ToTargetDistSqr > decisionRecordDic.toP2DisSqr and toCenterDistSqr > decisionRecordDic.normalRegionRadius then if entity.components.attr:HitPointPercents() >= FIGHT_BACK_HP_PER then command = self:CommandFindPathAndRunTo(entity, center, command, false, decisionData, 1000) --self:RunToNRIntervalDodge(entity, command, decisionRecordDic) else self:TryFightBack(entity, command, center, decisionData, decisionRecordDic) end else --logging.error(LTAG.ERROR, "HYW : 1 Change To Phase2") phase = EPhase.STAY_IN_NORMAL_REGION --状态切换的时候索1次敌 SystemManager.OnSearchTarget(entity, 1, P2_SEARCH_ENEMY_DIS_SQR, 1, 0) end end return phase end function Decision_FourCountry:SetCommandPhase_Preparing() return EPhase.RUN_TO_NORMAL_REGION end return Decision_FourCountry