local SkillBaseSystem = require "Battle/Logic/Entity/System/SkillBaseSystem" local Base = require("Battle/Logic/AI/Decision/Decision_Base") local Decision_TeamPVPAutoFight = class("Decision_TeamPVPAutoFight", Base) local DODGE_KEYPOS = LuaConst.ESkillKeyPosition.Dodge local STRONGHOLD_KEY = "strongHold" --据点对象 local STRONGHOLD_CENTER_KEY = "strongHoldCenter" --据点中心 local STRONGHOLD_RADIUS_KEY = "strongHoldRadius" --据点区域半径 local STRONGHOLD_RADIUS_SQR_KEY = "strongHoldRadiusSqr" --据点区域半径的平方 local TO_P2_DIS_SQR_KEY = "toP2DisSqr" --1阶段转2阶段的距离阈值平方 local PHASE_KEY = "phase" --当前阶段 local P2_OUT_OF_STRONGHOLD_CHECK_TIMESTAMP_KEY = "outOfStrongholdCheckTime" --2阶段出圈检测时间戳 local MAX_ENEMY_2_CENTER_DIS_SQR_KEY = "maxEnemy2CenterDisSqr" --2阶段会被攻击的敌人距离据点的最大距离 local RUN_TO_BUFF_HERO_ID_CAMP1_KEY = "runToBuffHeroID_1" --阵营1跑向Buff的英雄的ID的记录key local RUN_TO_BUFF_HERO_ID_CAMP2_KEY = "runToBuffHeroID_2" --阵营2跑向Buff的英雄的ID的记录key local TARGET_BUFF_ID_CAMP1_KEY = "targetBuffID_1" --阵营1跑向的Buff怪的EntityID的记录的key local TARGET_BUFF_ID_CAMP2_KEY = "targetBuffID_2" --阵营2跑向的Buff怪的EntityID的记录的key local RUN_TO_BUFF_CHOOSE_FRAME_CAMP1_KEY = "runToBuffChooseFrame_1" --阵营1需要刷新的时间戳 local RUN_TO_BUFF_CHOOSE_FRAME_CAMP2_KEY = "runToBuffChooseFrame_2" --阵营2需要刷新的时间戳 local FairPlay3V3AIWaitTeammateTimeMs = DataSheetManager.ConstData:GetDataByID("FairPlay3V3AIWaitTeammateTime").IntValue * 1000 local BUFF_MONSTER_TYPE = 43 --Buff怪的MonsterType local IMPOSSIBLE_FRAME = 999999 --第2版AI参数,by HYW local LuaConst=LuaConst local FP_Const_Zero=FP.Const.Zero local FP=FP local FP_Half = FP.Const.Half local FP_Point8 = FP.newV1(0.8) local FP_Point9 = FP.newV1(0.9) local LEAVE_REVIVE_AREA_FINISH_DISTSQR = FP.newV1(1.414) local P1_2_P2_LIFE_RATIO = FP.newV1(0.7) --阶段1转阶段2血量阈值 local P1_SEARCH_ENEMY_DIS_SQR = FP.newV1(100) --阶段1索敌距离平方 --local P2_SEARCH_ENEMY_DIS_SQR = FP.newV1(1600) --阶段2索敌距离平方 --old 已改为在台子上这个正方形区域索敌了 local MIDDLE_SQUARE_SIDE_LENGTH = DataSheetManager.ConstData:GetDataByID("TVTSquareSideLength").IntValue --中间台子的边长 local MAX_ENEMY_DIS_PLUS = FP.newV1(20) --阶段2圈外多远之内的敌人会被攻击,比如10,就是圈外10m范围内的敌人才会被攻击。 local UNATTACK_2_MOVE_FRAME_COUNT = 100 --阶段1未受攻击跳转移动行为的时间(帧数,20帧是1秒) local OUT_OF_STRONGHOLD_CHECK_FRAME_COUNT = 120 --阶段2检测出圈的间隔 local P1_2_P2_DISTANCE_RATIO_SQR = FP.newV1(0.25) --阶段1转阶段2距离系数阈值的平方 local P2_2_P1_MIN_DISTANCE_SQR = FP.newV1(900) --阶段2转阶段1的最小距离的平方 local SEARCH_TARGET_POSSIBILITY = FP.newV1(0.05) -- 5/100概率寻找目标,相当于平均100/5*AI刷新间隔,通常AI刷新间隔为1帧,因此平均时间=100帧(5秒)索敌一次 local START_POSSIBILITY = FP.newV1(0.1) -- 1/10概率开始,AI刷新间隔为1帧的情况下相当于平均延迟0.25秒开始 local P3_FINDPATH_POSSIBILITY = FP.newV1(0.05) -- 阶段3 5/100概率重新寻路,AI刷新间隔为1帧的情况下相当于平均5秒重新寻路一次,减少寻路开销 local NEW_WANDER_POS_POSSIBILITY = FP.newV1(0.02)-- 1/50概率寻找新点,相当于平均50*AI刷新间隔,AI刷新间隔为1帧的情况下相当于50帧(2.5秒)寻找1次新点--注意如果_randomPool太小,会出现只有几个点在循环随机的情况。比如100个元素的_randomPool,则只会有两三个点在随机。 local PHASE1_TARGET_POS_RANDOM_INNDER_RADIUS = FP.newV1(19) --1阶段时会在 以据点为中心,PHASE1_TARGET_POS_RANDOM_INNDER_RADIUS为半径的圆内随机一个点作为目标位置跑过去 local PHASE1_TARGET_POS_RANDOM_OUTTER_RADIUS = FP.newV1(21) local PHASE1_DODGE_MIN_FRAME_INTERVAL = FP.newV1(60) --1阶段闪避最低间隔 local PHASE1_DODGE_MAX_FRAME_INTERVAL = FP.newV1(100) --1阶段闪避最大间隔 local USE_ADJUTANT_SKILL_DELAY_LIST = DataSheetManager.ConstData:GetDataByID("TVTRobotViceMusouDelay").IntListValue local USE_ADJUTANT_SKILL_POSSIBILITY = FP.newV1(1 / ((USE_ADJUTANT_SKILL_DELAY_LIST[1] + USE_ADJUTANT_SKILL_DELAY_LIST[2]) / 2 * LuaConst.LogicFrameRate)) local FIND_BUFF_DELAY_LIST = DataSheetManager.ConstData:GetDataByID("TVTRobotFindBuffDelay").IntListValue local FIND_BUFF_MIN_DELAY = FIND_BUFF_DELAY_LIST[1] * 3 --因为是3v3,而且每个entity的Check都相当全体都Check,所以delay*3来降低频率 local FIND_BUFF_MAX_DELAY = FIND_BUFF_DELAY_LIST[2] * 3 ---因为是3v3,而且每个entity的Check都相当全体都Check,所以delay*3来降低频率 local RUN_TO_BUFF_DODGE_DISTANCE_SQR = FP.newV1(169) --如果在跑向Buff阶段,距离Buff的距离的屏方大于这个值,就会试图释放闪避技能来快速接近buff local GO_OUT_HP_LESS = DataSheetManager.ConstData:GetDataByID("TVTRobotHPlessthanEnemyAction").FloatValue local IMMORTAL_BUFFID = 500001 local ESCAPE_WALK_FRAME = 20 --逃跑阶段一开始会步行几帧,最后以闪避结束。这个值指定要步行多少帧 local ESCAPE_FRAME_CD_MIN = 200 + ESCAPE_WALK_FRAME --逃跑Phase的最小CD local ESCAPE_FRAME_CD_MAX = 300 + ESCAPE_WALK_FRAME --逃跑Phase的最大CD local DODGE_DIST = FP.newV1(10) --闪避技能位移距离(闪避现在是做在动作里,由策划跟美术口头约定的,没走配表,所以只能在这里写死一个定值,会有误差) local DODGE_DIST_SQR = DODGE_DIST * DODGE_DIST local CAMP1_PATH_ID_MIN = 4001 local CAMP1_PATH_ID_MAX = 4006 local CAMP2_PATH_ID_MIN = 4021 local CAMP2_PATH_ID_MAX = 4026 --↑ local EPhase = { PREPARING = 0, LEAVE_REVIVE_AREA = 1, --离开复活点阶段1 RUN_TO_ENTRANCE = 2, --跑向高台的入口 FAR_TO_STRONGHOLD_MOVING = 3, --距离据点很远时,向着据点附近跑的阶段,距离的平方大于P2_2_P1_MIN_DISTANCE_SQR代表距离很远 NEAR_TO_STRONGHOLD_FIGHTING = 4, --距离据点较近时,在据点内战斗的阶段 NEAR_TO_STRINGHOLD_MOVING = 5, --距离据点较近时,向据点内部移动的阶段 RUN_TO_BUFF = 6, --去吃Buff ESCAPE = 7, --逃跑 } local ELeaveReviveAreaPosType = { MIDDLE = 0, LEFT = 1, RIGHT = 2, } local REVIVE_AREA_CAMP1_LEFTPOS = FP.newV2(107, 183) local REVIVE_AREA_CAMP1_RIGHTPOS = FP.newV2(150, 183) local REVIVE_AREA_CAMP2_LEFTPOS = FP.newV2(107, 74) local REVIVE_AREA_CAMP2_RIGHTPOS = FP.newV2(150, 74) local ENTRANCE_CAMP1_LEFTPOS = FP.newV2(111, 145) local ENTRANCE_CAMP1_RIGHTPOS = FP.newV2(145, 145) local ENTRANCE_CAMP2_LEFTPOS = FP.newV2(109, 110) local ENTRANCE_CAMP2_RIGHTPOS = FP.newV2(147, 107) local ENTRANCE_CAMP1_MIDDLEPOS = FP.newV2(128, 141) local ENTRANCE_CAMP2_MIDDLEPOS = FP.newV2(128, 112) local KEY_POS_SKILL1 = LuaConst.ESkillKeyPosition.Skill1 local KEY_POS_SKILL2 = LuaConst.ESkillKeyPosition.Skill2 local KEY_POS_SKILL3 = LuaConst.ESkillKeyPosition.Skill3 local KEY_POS_MUSOU = LuaConst.ESkillKeyPosition.MusouNormal local _tempV1 = FP.newV1(0) local _tempV1_2 = FP.newV1(0) local _tempDisSqr = FP.newV1(400) -- 20米范围 local temp_back = FP.newV2(0,0) -- 判断是否面向用 --3v3 自动战斗 --[[ 初始化 --]] function Decision_TeamPVPAutoFight:initialize(entity) Base.initialize(self,entity) --类型 self.Type = LuaConst.DecisionType.AutoFight3v3 --瞬时 self.IsOnce = false --初始化最小和最大技能DecisionCD self:InitSkillCDInfo() end function Decision_TeamPVPAutoFight:GetPosListByItemID(itemID) return LevelItemManager.GetItemByID(itemID).ItemData.PathPoints end --计算所需的各种路径的posList function Decision_TeamPVPAutoFight:CalcPathPosList(entity, decisionRecordDic) --计算 local levelID = LevelManager.GetCurLevelID() if entity:GetCampID() == 1 then decisionRecordDic.enterPosItemIDList = DataSheetManager.ConstData:GetDataByID("SyncLevel_3V3_Camp1Attack_" .. levelID).IntListValue else decisionRecordDic.enterPosItemIDList = DataSheetManager.ConstData:GetDataByID("SyncLevel_3V3_Camp2Attack_" .. levelID).IntListValue end decisionRecordDic.leaveReviveAreaPosListArray = {} for i,itemID in ipairs(decisionRecordDic.enterPosItemIDList) do table.insert(decisionRecordDic.leaveReviveAreaPosListArray, self:GetPosListByItemID(itemID)) end decisionRecordDic.buffPathItemIDList_2002 = DataSheetManager.ConstData:GetDataByID("SyncLevel_3V3_AttackToBuff1_" .. levelID).IntListValue decisionRecordDic.buffPosListArray_2002 = {} for i,itemID in ipairs(decisionRecordDic.buffPathItemIDList_2002) do table.insert(decisionRecordDic.buffPosListArray_2002, self:GetPosListByItemID(itemID)) end decisionRecordDic.buffPathItemIDList_2003 = DataSheetManager.ConstData:GetDataByID("SyncLevel_3V3_AttackToBuff2_" .. levelID).IntListValue decisionRecordDic.buffPosListArray_2003 = {} for i,itemID in ipairs(decisionRecordDic.buffPathItemIDList_2003) do table.insert(decisionRecordDic.buffPosListArray_2003, self:GetPosListByItemID(itemID)) end end --[[ 进入该Decision --]] function Decision_TeamPVPAutoFight:DecisionIn(entity, decisionData) local aiBaseComponent = entity.components.aiBase local decisionRecordDic = aiBaseComponent:GetDecisionRecordDic(decisionData) self:CalcPathPosList(entity, decisionRecordDic) --初始化据点数据,并做记录 local strongHoldList = LevelItemManager.GetItemListByType(LuaConst.LevelItemType.StrongHold) if strongHoldList then local strongHold = strongHoldList[1] --支持实验室测试pvp ai↓ if strongHold == nil then if LevelManager.IsMonsterTest() then logging.error(LTAG.ERROR, "HYW : 正在进行虚拟pvp测试") strongHold = {} strongHold.ItemData = {} strongHold.ItemData.ItemPos = FP.newV2(222,270) strongHold.ItemData.Radius = FP.newV1(12) else logging.error(LTAG.ERROR, "HYW : 没有据点,无法运行Pvp Ai") return end end --支持实验室测试pvp ai↑ if strongHold ~= decisionRecordDic[STRONGHOLD_KEY] then --存到Record里,方便以后做多据点AI decisionRecordDic[STRONGHOLD_KEY] = strongHold decisionRecordDic[PHASE_KEY] = EPhase.PREPARING if strongHold then decisionRecordDic[STRONGHOLD_CENTER_KEY] = strongHold.ItemData.ItemPos:cloneV2() decisionRecordDic[STRONGHOLD_RADIUS_KEY] = strongHold.ItemData.Radius local strongHoldRadiusSqr = strongHold.ItemData.Radius * strongHold.ItemData.Radius decisionRecordDic[STRONGHOLD_RADIUS_SQR_KEY] = strongHoldRadiusSqr decisionRecordDic[TO_P2_DIS_SQR_KEY] = strongHoldRadiusSqr * P1_2_P2_DISTANCE_RATIO_SQR PHASE1_TARGET_POS_RANDOM_INNDER_RADIUS:Reset(strongHold.ItemData.Radius):Sub(1) PHASE1_TARGET_POS_RANDOM_OUTTER_RADIUS:Reset(PHASE1_TARGET_POS_RANDOM_INNDER_RADIUS):Add(1) local maxEnemy2CenterDisSqr = (strongHold.ItemData.Radius + MAX_ENEMY_DIS_PLUS) * (strongHold.ItemData.Radius + MAX_ENEMY_DIS_PLUS) decisionRecordDic[MAX_ENEMY_2_CENTER_DIS_SQR_KEY] = maxEnemy2CenterDisSqr end end if strongHold then decisionRecordDic[PHASE_KEY] = 0 SystemManager.FindPath(entity, strongHold.ItemData.ItemPos, true) end end self:SetSkillCDByElo(entity, decisionRecordDic) decisionRecordDic.dontAutoRide = true decisionRecordDic.phaseFrameEla = 0 decisionRecordDic.aiUpdateFrameInterval = entity.components.aiBase:GetAiUpdateInterval() self:TryUpdateDodgeSkillIndex(entity, decisionRecordDic) decisionRecordDic.enemeyCampID = entity.CampID == 1 and 2 or 1 decisionRecordDic.dodgeFrame = IMPOSSIBLE_FRAME --自身下次释放闪避的帧数 end function Decision_TeamPVPAutoFight:TryUpdateDodgeSkillIndex(entity, decisionRecordDic) if decisionRecordDic.dodgeSkillIndex2HeroID ~= entity:GetCurCharacterID() then decisionRecordDic.dodgeSkillIndex = entity.components.skillBase:GetSkillIndexByKeyPosition(DODGE_KEYPOS) decisionRecordDic.dodgeSkillIndex2HeroID = entity:GetCurCharacterID() end end function Decision_TeamPVPAutoFight:GetSkillCDDataSheet() return DataSheetManager.ThreeBattleLevelData end --[[ 退出该Decision --]] function Decision_TeamPVPAutoFight:DecisionOut(entity, decisionData) local aiBaseComponent = entity.components.aiBase aiBaseComponent:ClearDecisionRecord(decisionData) end --[[ 能否进入 --]] function Decision_TeamPVPAutoFight:CanEnter(entity, decisionData, command) local autoFightComponent = entity.components.autoFight return autoFightComponent.IsSyncAuto end --[[ 能否退出 --]] function Decision_TeamPVPAutoFight:CanExit(entity, decisionData, command) local autoFightComponent = entity.components.autoFight return not autoFightComponent.IsSyncAuto end local CHOOSE_HERO_RUN_TO_BUFF_INTERVAL_FRAME = 40 --隔多少帧选一次人去吃buff local _tempBuffListEntity = {} function Decision_TeamPVPAutoFight:TryChooseHeroRunToBuff(entity, decisionRecordDic, aiBaseComponent, runToBuffHeroKey) local campId = entity:GetCampID() local frameKey = campId == 1 and RUN_TO_BUFF_CHOOSE_FRAME_CAMP1_KEY or RUN_TO_BUFF_CHOOSE_FRAME_CAMP2_KEY local needChooseFrame = aiBaseComponent:GetGlobalRecord(frameKey) if needChooseFrame == nil or LogicUpdateManager._clientHandleFrame >= needChooseFrame then aiBaseComponent:SetGlobalRecord(frameKey, LogicUpdateManager._clientHandleFrame + CHOOSE_HERO_RUN_TO_BUFF_INTERVAL_FRAME) --获取场上的所有buff if #_tempBuffListEntity > 0 then table.clear(_tempBuffListEntity) end for i,entity in ipairs(LogicUpdateManager.EntityList_Normal) do if entity._logicInitData._characterData.MonsterType == BUFF_MONSTER_TYPE then table.insert(_tempBuffListEntity, entity) end end if #_tempBuffListEntity > 0 then --场上有buff才选人去吃 local targetBuffEntity = nil local minDistSqr = FP.newV1(9999999) local entityList = CampManager.GetEntityListOfCampId(campId) local runnerHero = nil for i,entity in ipairs(entityList) do if entity:IsActive() and entity:IsHero() and entity:IsAlive() and entity.components.autoFight:IsAutoFight() then for _,buffEntity in ipairs(_tempBuffListEntity) do if buffEntity:IsAlive() then local distSqr = FP.V2.DistanceSqr(entity:GetLogicPos(), buffEntity:GetLogicPos()) if distSqr < minDistSqr then targetBuffEntity = buffEntity minDistSqr = distSqr runnerHero = entity end end end end end if targetBuffEntity then aiBaseComponent:SetGlobalRecord(runToBuffHeroKey, runnerHero.EntityID) local targetBuffRecordKey = campId == 1 and TARGET_BUFF_ID_CAMP1_KEY or TARGET_BUFF_ID_CAMP2_KEY aiBaseComponent:SetGlobalRecord(targetBuffRecordKey, targetBuffEntity.EntityID) return runnerHero.EntityID end end end end function Decision_TeamPVPAutoFight:ShouldRunToBuff(entity, decisionRecordDic, aiBaseComponent, selfPos) if LogicUpdateManager._clientHandleFrame >= decisionRecordDic.runToBuffCheckFrame then if entity:IsAlive() then local campId = entity:GetCampID() local runToBuffHeroKey = campId == 1 and RUN_TO_BUFF_HERO_ID_CAMP1_KEY or RUN_TO_BUFF_HERO_ID_CAMP2_KEY local runToBuffHeroID = aiBaseComponent:GetGlobalRecord(runToBuffHeroKey) -- old↓ 每个阵营都派一个人去吃 -- if not runToBuffHeroID then -- --如果当前阵营没有人跑向Buff -- runToBuffHeroID = self:TryChooseHeroRunToBuff(entity, decisionRecordDic, aiBaseComponent, runToBuffHeroKey) -- end -- old↑ -- new↓ 只有最近的人去吃 local runToBuffHeroID1 = aiBaseComponent:GetGlobalRecord(RUN_TO_BUFF_HERO_ID_CAMP1_KEY) local runToBuffHeroID2 = aiBaseComponent:GetGlobalRecord(RUN_TO_BUFF_HERO_ID_CAMP2_KEY) if not runToBuffHeroID1 and not runToBuffHeroID2 then runToBuffHeroID = self:TryChooseHeroRunToBuff(entity, decisionRecordDic, aiBaseComponent, runToBuffHeroKey) end -- new↑ 只有最近的人去吃 return runToBuffHeroID == entity.EntityID else return false end else return false end end function Decision_TeamPVPAutoFight:ShouldEscape(entity, decisionRecordDic) local should = false local target = entity.components.target.Target if target then if decisionRecordDic.escapeReadyFrame == nil or LogicUpdateManager._clientHandleFrame >= decisionRecordDic.escapeReadyFrame then local myHpPercent = entity.components.attr:HitPointPercents() --如果自己血量小于半血,且小于目标的血量,就逃跑 if myHpPercent < target.components.attr:HitPointPercents() and myHpPercent < FP_Half then should = true end end end return should end function Decision_TeamPVPAutoFight:ResetRunToBuffCheckFrame(decisionRecordDic) decisionRecordDic.runToBuffCheckFrame = LogicUpdateManager._clientHandleFrame + LogicRandom.GetIntegerValue(entity, FIND_BUFF_MIN_DELAY, FIND_BUFF_MAX_DELAY, 888885) end function Decision_TeamPVPAutoFight:ChangePhase(phase, entity, decisionData, decisionRecordDic, command, aiBaseComponent) if decisionRecordDic[PHASE_KEY] ~= phase then decisionRecordDic[PHASE_KEY] = phase decisionRecordDic.teamPvpRunByPathIndex = nil if phase == EPhase.LEAVE_REVIVE_AREA then -- old↓ 使用固定数量的几个点引导移动 -- local rand = LogicRandom.GetRandom01(entity, 6542894) -- local leftPos,rightPos -- if entity.CampID == 1 then -- leftPos = REVIVE_AREA_CAMP1_LEFTPOS -- rightPos = REVIVE_AREA_CAMP1_RIGHTPOS -- else -- leftPos = REVIVE_AREA_CAMP2_LEFTPOS -- rightPos = REVIVE_AREA_CAMP2_RIGHTPOS -- end -- if rand >= FP_Point8 then -- if rand >= FP_Point9 then -- decisionRecordDic.phaseTargetPos = rightPos -- decisionRecordDic.leaveReviveAreaPosType = ELeaveReviveAreaPosType.RIGHT -- else -- decisionRecordDic.phaseTargetPos = leftPos -- decisionRecordDic.leaveReviveAreaPosType = ELeaveReviveAreaPosType.LEFT -- end -- else -- decisionRecordDic.phaseTargetPos = entity:GetLogicPos() -- decisionRecordDic.leaveReviveAreaPosType = ELeaveReviveAreaPosType.MIDDLE -- end -- old↑ -- new↓ 使用不定数量的路点数组指定的路径进行移动 decisionRecordDic.posList = decisionRecordDic.leaveReviveAreaPosListArray[LogicRandom.GetIntegerValue(entity, 1, #decisionRecordDic.leaveReviveAreaPosListArray, 58345843)] -- new↑ decisionRecordDic.waitInLeaveAreaUntilFrame = LogicUpdateManager._clientHandleFrame if self:GetOutOfReviveAreaAliveHeroCountOfCamp(entity.CampID) == 0 then local campEntityList = CampManager.GetEntityListOfCampId(entity.CampID) for i,v in ipairs(campEntityList) do if v.isHero and v ~= entity and v.components.revive.ReviveTimer <= FairPlay3V3AIWaitTeammateTimeMs then local reviveFrame = FP.newV1(v.components.revive.ReviveTimer) reviveFrame:Div(LuaConst.TimeSpanMs) reviveFrame = FP.tonumberV1(reviveFrame) + LogicUpdateManager._clientHandleFrame if decisionRecordDic.waitInLeaveAreaUntilFrame == LogicUpdateManager._clientHandleFrame or decisionRecordDic.waitInLeaveAreaUntilFrame > reviveFrame then decisionRecordDic.waitInLeaveAreaUntilFrame = reviveFrame end end end end elseif phase == EPhase.RUN_TO_ENTRANCE then -- if decisionRecordDic.leaveReviveAreaPosType == ELeaveReviveAreaPosType.LEFT then -- if entity.CampID == 1 then -- decisionRecordDic.phaseTargetPos = ENTRANCE_CAMP1_LEFTPOS -- else -- decisionRecordDic.phaseTargetPos = ENTRANCE_CAMP2_LEFTPOS -- end -- elseif decisionRecordDic.leaveReviveAreaPosType == ELeaveReviveAreaPosType.RIGHT then -- if entity.CampID == 1 then -- decisionRecordDic.phaseTargetPos = ENTRANCE_CAMP1_RIGHTPOS -- else -- decisionRecordDic.phaseTargetPos = ENTRANCE_CAMP2_RIGHTPOS -- end -- else -- if entity.CampID == 1 then -- decisionRecordDic.phaseTargetPos = ENTRANCE_CAMP1_MIDDLEPOS -- else -- decisionRecordDic.phaseTargetPos = ENTRANCE_CAMP2_MIDDLEPOS -- end -- end elseif phase == EPhase.FAR_TO_STRONGHOLD_MOVING then decisionRecordDic.phaseTargetPos = LogicRandom.GetRandomPointInRing(entity, PHASE1_TARGET_POS_RANDOM_INNDER_RADIUS, PHASE1_TARGET_POS_RANDOM_OUTTER_RADIUS, 888888):Add(decisionRecordDic[STRONGHOLD_CENTER_KEY]) decisionRecordDic.phaseDodgeFrame = LogicRandom.GetRangeValue(entity, PHASE1_DODGE_MIN_FRAME_INTERVAL, PHASE1_DODGE_MAX_FRAME_INTERVAL, 3431423):Add(LogicUpdateManager._clientHandleFrame) --logging.error(LTAG.ERROR, "HYW : decisionRecordDic.phaseTargetPos : ", decisionRecordDic.phaseTargetPos) -- 路径(现在用随机点的方式效果跟路径差不多,所以注掉路径的方式)↓ -- local idMin -- local idMax -- if entity:GetCampID() == 1 then -- idMin = CAMP1_PATH_ID_MIN -- idMax = CAMP1_PATH_ID_MAX -- else -- idMin = CAMP2_PATH_ID_MIN -- idMax = CAMP2_PATH_ID_MAX -- end -- decisionRecordDic.runToCenterPathId = LogicRandom.GetIntegerValue(entity, idMin, idMax, 888886) -- entity.components.patrol:ResetPathIndex() -- 路径 ↑ elseif phase == EPhase.NEAR_TO_STRONGHOLD_FIGHTING then self:ResetRunToBuffCheckFrame(decisionRecordDic) elseif phase == EPhase.NEAR_TO_STRINGHOLD_MOVING then self:ResetRunToBuffCheckFrame(decisionRecordDic) if decisionRecordDic.runToBuffExitFrame and LogicUpdateManager._clientHandleFrame - decisionRecordDic.runToBuffExitFrame < 20 then decisionRecordDic.posList = decisionRecordDic.runToBuffPosList else decisionRecordDic.posList = nil command = self:CommandFindPathAndRunTo(entity, decisionRecordDic[STRONGHOLD_CENTER_KEY], command, true, decisionData) end elseif phase == EPhase.RUN_TO_BUFF then self:ResetRunToBuffCheckFrame(decisionRecordDic) local targetBuffRecordKey = entity:GetCampID() == 1 and TARGET_BUFF_ID_CAMP1_KEY or TARGET_BUFF_ID_CAMP2_KEY local buffEntityID = aiBaseComponent:GetGlobalRecord(targetBuffRecordKey) if LogicUpdateManager._entityDic[buffEntityID] then -- new↓ decisionRecordDic.targetBuffEntity = LogicUpdateManager._entityDic[buffEntityID] local buffPosListArray = decisionRecordDic["buffPosListArray_" .. decisionRecordDic.targetBuffEntity._logicInitData.BornItemID] decisionRecordDic.posList = buffPosListArray[LogicRandom.GetIntegerValue(entity, 1, #buffPosListArray, 58345844)] decisionRecordDic.runToBuffPosList = decisionRecordDic.posList -- new↑ -- old↓ --command = self:CommandFindPathAndRunTo(entity, decisionRecordDic.targetBuffEntity:GetLogicPos(), command, true, decisionData) -- old↑ --else --正常情况,此时可能buff已经没了 end elseif phase == EPhase.ESCAPE then decisionRecordDic.escapeReadyFrame = LogicUpdateManager._clientHandleFrame + LogicRandom.GetIntegerValue(entity, ESCAPE_FRAME_CD_MIN, ESCAPE_FRAME_CD_MAX, 888887) end decisionRecordDic.phaseFrameEla = 0 end end --在台子上索敌 function Decision_TeamPVPAutoFight:SearchTargetInSquare(entity, decisionRecordDic) SystemManager.SearchTargetInRect(entity, decisionRecordDic[STRONGHOLD_CENTER_KEY], MIDDLE_SQUARE_SIDE_LENGTH, MIDDLE_SQUARE_SIDE_LENGTH, FP.Const.Vector2_Right, false, true, false) end function Decision_TeamPVPAutoFight:SetCommandPhase_Preparing(entity, phase, command, decisionData, decisionRecordDic) --每帧有一定概率转为下一阶段 if LogicRandom.GetRandom01(entity , 1001) <= START_POSSIBILITY then phase = EPhase.LEAVE_REVIVE_AREA --logging.log(LTAG.HYW,"HYW : phase 0 to 1") end return phase end function Decision_TeamPVPAutoFight:GetAliveHeroCountOfCamp(campId) local count = 0 for i,_entity in ipairs(LogicUpdateManager.EntityList_Sync) do if _entity.isHero and _entity.CampID == campId and _entity:IsAlive() then count = count + 1 end end return count end function Decision_TeamPVPAutoFight:GetOutOfReviveAreaAliveHeroCountOfCamp(campId) local count = 0 for i,_entity in ipairs(LogicUpdateManager.EntityList_Sync) do if _entity.isHero and _entity.CampID == campId and _entity:IsAlive() and not _entity.components.buff:HasBuff(IMMORTAL_BUFFID) then count = count + 1 end end return count end function Decision_TeamPVPAutoFight:GetInReviveAreaAliveHeroCountOfCamp(campId) local count = 0 for i,_entity in ipairs(LogicUpdateManager.EntityList_Sync) do if _entity.isHero and _entity.CampID == campId and _entity:IsAlive() and _entity.components.buff:HasBuff(IMMORTAL_BUFFID) then count = count + 1 end end return count end function Decision_TeamPVPAutoFight:GetNearestPosIndexInList(entity, posList) local nearestDist = _tempV1 local dist = _tempV1_2 local index = 1 local entityPos = entity:GetLogicPos() entityPos:DistanceSqr(posList[1], nearestDist) for i=2,#posList do local pos = posList[i] entityPos:DistanceSqr(pos, dist) if dist < nearestDist then index = i nearestDist:Reset(dist) end end return index end function Decision_TeamPVPAutoFight:RunByPosList(entity, phase, command, decisionData, decisionRecordDic, posList, isBackward) local isArrived = true if decisionRecordDic.teamPvpRunByPathIndex == nil then decisionRecordDic.teamPvpRunByPathIndex = self:GetNearestPosIndexInList(entity, posList) end local isControlledBefore = decisionRecordDic.controlledFrame if entity.components.buff:HasHardControlBuff() then decisionRecordDic.controlledFrame = LogicUpdateManager._clientHandleFrame else decisionRecordDic.controlledFrame = nil end if isControlledBefore and decisionRecordDic.controlledFrame == nil then decisionRecordDic.teamPvpRunByPathIndex = self:GetNearestPosIndexInList(entity, posList) end if decisionRecordDic.teamPvpRunByPathIndex then local targetPos = posList[decisionRecordDic.teamPvpRunByPathIndex] if targetPos then entity:GetLogicPos():DistanceSqr(targetPos, _tempV1) if _tempV1 <= FP.Const.One then if (isBackward and decisionRecordDic.teamPvpRunByPathIndex == 1) or (not isBackward and decisionRecordDic.teamPvpRunByPathIndex == #posList) then isArrived = true else isArrived = false decisionRecordDic.teamPvpRunByPathIndex = decisionRecordDic.teamPvpRunByPathIndex + (isBackward and -1 or 1) targetPos = posList[decisionRecordDic.teamPvpRunByPathIndex] self:CommandFindPathAndRunTo(entity, targetPos, command, true, decisionData, 1000) end else isArrived = false self:CommandFindPathAndRunTo(entity, targetPos, command, false, decisionData, 1000) end else isArrived = true end else isArrived = true end return isArrived -- 可能需要的额外功能: -- --根据不同phase处理好abort -- if phase == EPhase.LEAVE_REVIVE_AREA then -- elseif phase == EPhase.RUN_TO_BUFF then -- end end function Decision_TeamPVPAutoFight:SetCommandPhase_LeaveReviveArea(entity, phase, command, decisionData, decisionRecordDic, selfPos) local aliveHeroCount = self:GetAliveHeroCountOfCamp(entity.CampID) local inReviveAreaHeroCount = self:GetInReviveAreaAliveHeroCountOfCamp(entity.CampID) --old↓ -- if LevelManager.CurLevelFunc:GetProgressOfCamp(decisionRecordDic.enemeyCampID) >= 1800 or aliveHeroCount == 3 or inReviveAreaHeroCount ~= aliveHeroCount then -- command = self:CommandFindPathAndRunTo(entity, decisionRecordDic.phaseTargetPos, command, false, decisionData, 1000) -- local toTargetDistSqr = FP.V2.DistanceSqr(selfPos, decisionRecordDic.phaseTargetPos) -- if toTargetDistSqr <= LEAVE_REVIVE_AREA_FINISH_DISTSQR then -- phase = EPhase.FAR_TO_STRONGHOLD_MOVING -- end -- --else -- --do nothing 等待队友复活 -- end --old↑ --new↓ if LevelManager.CurLevelFunc:GetProgressOfCamp(decisionRecordDic.enemeyCampID) >= 1800 or aliveHeroCount == 3 or inReviveAreaHeroCount ~= aliveHeroCount then if decisionRecordDic.waitInLeaveAreaUntilFrame == nil or decisionRecordDic.waitInLeaveAreaUntilFrame <= LogicUpdateManager._clientHandleFrame or LevelManager.CurLevelFunc:GetProgressOfCamp(decisionRecordDic.enemeyCampID) >= 1800 then if decisionRecordDic.teamPvpRunByPathIndex == 3 and entity.components.buff:HasBuff(IMMORTAL_BUFFID) then decisionRecordDic.teamPvpRunByPathIndex = 1 end if self:RunByPosList(entity, phase, command, decisionData, decisionRecordDic, decisionRecordDic.posList, false) then phase = EPhase.RUN_TO_ENTRANCE end end end --new↑ return phase end function Decision_TeamPVPAutoFight:SetCommandPhase_RunToEntrance(entity, phase, command, decisionData, decisionRecordDic, selfPos) -- command = self:CommandFindPathAndRunTo(entity, decisionRecordDic.phaseTargetPos, command, false, decisionData, 1000) -- local toTargetDistSqr = FP.V2.DistanceSqr(selfPos, decisionRecordDic.phaseTargetPos) -- if toTargetDistSqr <= LEAVE_REVIVE_AREA_FINISH_DISTSQR then -- phase = EPhase.FAR_TO_STRONGHOLD_MOVING -- end -- return phase return EPhase.FAR_TO_STRONGHOLD_MOVING end function Decision_TeamPVPAutoFight:SetCommandPhase_RunToSH(entity, phase, command, decisionData, decisionRecordDic, selfPos, toCenterDistSqr, strongHoldRadiusSqr, attr) --距离据点很远时,向着据点附近跑的阶段,距离的平方大于P2_2_P1_MIN_DISTANCE_SQR代表距离很远 local toP2DisSqr = decisionRecordDic[TO_P2_DIS_SQR_KEY] local p1ToTargetDistSqr = FP.V2.DistanceSqr(selfPos, decisionRecordDic.phaseTargetPos) if p1ToTargetDistSqr > toP2DisSqr and toCenterDistSqr > strongHoldRadiusSqr then if attr:HitPointPercents() >= P1_2_P2_LIFE_RATIO then command = self:CommandFindPathAndRunTo(entity, decisionRecordDic.phaseTargetPos, command, false, decisionData, 1000) --self:PatrolOnPath(entity, command, false, decisionRecordDic.runToCenterPathId)-- 路径(现在用随机点的方式效果跟路径差不多,所以注掉路径的方式) self:RunToSHIntervalDodge(entity, command, decisionRecordDic) else local hpSubTimeStamp = entity.components.record.hpSubTimeStamp or -999999 if LogicUpdateManager._clientHandleFrame - hpSubTimeStamp > UNATTACK_2_MOVE_FRAME_COUNT then command = self:CommandFindPathAndRunTo(entity, decisionRecordDic.phaseTargetPos, command, false, decisionData, 1000) --self:PatrolOnPath(entity, command, false, decisionRecordDic.runToCenterPathId)-- 路径(现在用随机点的方式效果跟路径差不多,所以注掉路径的方式) self:RunToSHIntervalDodge(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, decisionRecordDic.phaseTargetPos, command, false, decisionData, 1000) --self:PatrolOnPath(entity, command, false, decisionRecordDic.runToCenterPathId)-- 路径(现在用随机点的方式效果跟路径差不多,所以注掉路径的方式) end else -- 没有目标继续向阶段目标点跑 command = self:CommandFindPathAndRunTo(entity, decisionRecordDic.phaseTargetPos, command, false, decisionData, 1000) --self:PatrolOnPath(entity, command, false, decisionRecordDic.runToCenterPathId)-- 路径(现在用随机点的方式效果跟路径差不多,所以注掉路径的方式) end end end else --logging.error(LTAG.ERROR, "HYW : 1 Change To Phase2") phase = EPhase.NEAR_TO_STRONGHOLD_FIGHTING --状态切换的时候索1次敌 --SystemManager.OnSearchTarget(entity, 1, P2_SEARCH_ENEMY_DIS_SQR, 1, 0) self:SearchTargetInSquare(entity, decisionRecordDic) decisionRecordDic[P2_OUT_OF_STRONGHOLD_CHECK_TIMESTAMP_KEY] = LogicUpdateManager._clientHandleFrame end return phase end function Decision_TeamPVPAutoFight:RunToSHIntervalDodge(entity, command, decisionRecordDic) if self:CanUseDodgeSkill(entity) then if decisionRecordDic.phaseDodgeFrame == nil then decisionRecordDic.phaseDodgeFrame = LogicRandom.GetRangeValue(entity, PHASE1_DODGE_MIN_FRAME_INTERVAL, PHASE1_DODGE_MAX_FRAME_INTERVAL, 3431424):Add(LogicUpdateManager._clientHandleFrame) end if FP.Less(decisionRecordDic.phaseDodgeFrame, LogicUpdateManager._clientHandleFrame) then self:TryUpdateDodgeSkillIndex(entity, decisionRecordDic) command.SkillIndex = decisionRecordDic.dodgeSkillIndex decisionRecordDic.phaseDodgeFrame = nil end end end function Decision_TeamPVPAutoFight:CanUseAdjutantSkill(entity, decisionRecordDic) return entity.components.adjutant.AdjutantEntity and entity.components.adjutant.AdjutantCD <= 0 and LogicRandom.GetRandom01(entity , 5435330) <= USE_ADJUTANT_SKILL_POSSIBILITY and SkillBaseSystem.GetUsingMusouOrAdjutantSkillEntityCount() < 2 --策划需求 场上有2单位同时放无双/副将技能时,机器人会将原有释放无双/副将技行为延后 end function Decision_TeamPVPAutoFight:SetCommandPhase_FightingInSH(entity, phase, command, decisionData, decisionRecordDic, selfPos, aiBaseComponent, toCenterDistSqr, strongHoldRadiusSqr, strongHoldCenter) if self:ShouldRunToBuff(entity, decisionRecordDic, aiBaseComponent, selfPos) then phase = EPhase.RUN_TO_BUFF elseif self:ShouldEscape(entity, decisionRecordDic) then phase = EPhase.ESCAPE else --检查20米内有敌人向我释放技能,则闪避 local dodgeSuccess = self:CheckAndTryUseDodgeSkill(entity, command, decisionRecordDic) if not dodgeSuccess then ----距离据点较近时,在据点内战斗的阶段 local targetEntity = entity.components.target.Target if not targetEntity then --SystemManager.OnSearchTarget(entity, 1, P2_SEARCH_ENEMY_DIS_SQR, 1, 0) self:SearchTargetInSquare(entity, decisionRecordDic) targetEntity = entity.components.target.Target end local canGoOut = false --是否可出圈攻击 if targetEntity then local needWander = true local targetPos = targetEntity.components.move.LogicPos local maxEnemy2CenterDisSqr = decisionRecordDic[MAX_ENEMY_2_CENTER_DIS_SQR_KEY] --这个值表示在据点外沿MAX_ENEMY_DIS_PLUS米的圈内 local target2centerDistSqr = FP.V2.DistanceSqr(targetPos, strongHoldCenter) if target2centerDistSqr < maxEnemy2CenterDisSqr then if target2centerDistSqr < maxEnemy2CenterDisSqr or targetEntity.components.attr:HitPointPercents() <= entity.components.attr:HitPointPercents() then command = self:CommandChaseUseSkill(entity, command, decisionData, decisionRecordDic) needWander = false if targetEntity.components.attr:HitPointPercents() <= (entity.components.attr:HitPointPercents() - GO_OUT_HP_LESS) then canGoOut = true end --如果没有释放技能,且距离目标的距离大于闪避的位移距离,就释放闪避进行追击 if command.SkillIndex <= 0 then local toTargetDistSqr = FP.V2.DistanceSqr(targetPos, strongHoldCenter) if toTargetDistSqr >= DODGE_DIST_SQR then self:TryUpdateDodgeSkillIndex(entity, decisionRecordDic) command.SkillIndex = decisionRecordDic.dodgeSkillIndex end end else needWander = true end else --目标不在距离内就一定概率寻找新目标 if LogicRandom.GetRandom01(entity , 1002) <= SEARCH_TARGET_POSSIBILITY then --SystemManager.OnSearchTarget(entity, 1, P2_SEARCH_ENEMY_DIS_SQR, 1, 0) self:SearchTargetInSquare(entity, decisionRecordDic) end end if not needWander then local dir = targetPos - selfPos command.RotateDir:Reset(dir) FP.releaseV2(dir) else command = self:CommandRandomWander(entity, aiBaseComponent, decisionData, selfPos, strongHoldCenter, aiBaseComponent:GetDecisionRecord(decisionData,STRONGHOLD_RADIUS_KEY), command, NEW_WANDER_POS_POSSIBILITY) end else --没有目标就随机走动 command = self:CommandRandomWander(entity, aiBaseComponent, decisionData, selfPos, strongHoldCenter, aiBaseComponent:GetDecisionRecord(decisionData,STRONGHOLD_RADIUS_KEY), command, NEW_WANDER_POS_POSSIBILITY) self:ReleaseHoldingSkill(entity, command) end end --每OUT_OF_STRONGHOLD_CHECK_FRAME_COUNT帧判断一次是否出圈 local outOfStrongholdCheckTime = decisionRecordDic[P2_OUT_OF_STRONGHOLD_CHECK_TIMESTAMP_KEY] if not canGoOut and LogicUpdateManager._clientHandleFrame - outOfStrongholdCheckTime > OUT_OF_STRONGHOLD_CHECK_FRAME_COUNT then if toCenterDistSqr > strongHoldRadiusSqr then decisionRecordDic[P2_OUT_OF_STRONGHOLD_CHECK_TIMESTAMP_KEY] = LogicUpdateManager._clientHandleFrame if toCenterDistSqr > P2_2_P1_MIN_DISTANCE_SQR then phase = EPhase.FAR_TO_STRONGHOLD_MOVING --阶段2如果出圈了很远,就去阶段1 --logging.error(LTAG.ERROR, "HYW : 2 Change To Phase 1") else phase = EPhase.NEAR_TO_STRINGHOLD_MOVING --阶段2如果没出圈很远,就去阶段3 --logging.error(LTAG.ERROR, "HYW : 2 Change To Phase3") end end end end return phase end function Decision_TeamPVPAutoFight:SetCommandPhase_BackToSH(entity, phase, command, decisionData, decisionRecordDic, selfPos, aiBaseComponent, toCenterDistSqr, strongHoldCenter) if decisionRecordDic.posList then if self:RunByPosList(entity, phase, command, decisionData, decisionRecordDic, decisionRecordDic.posList, true) then phase = EPhase.NEAR_TO_STRONGHOLD_FIGHTING end else if self:ShouldRunToBuff(entity, decisionRecordDic, aiBaseComponent, selfPos) then phase = EPhase.RUN_TO_BUFF else local toP2DisSqr = decisionRecordDic[TO_P2_DIS_SQR_KEY] if toCenterDistSqr < toP2DisSqr then phase = EPhase.NEAR_TO_STRONGHOLD_FIGHTING else command = self:CommandFindPathAndRunTo(entity, strongHoldCenter, command, LogicRandom.GetRandom01(entity , 1002) <= P3_FINDPATH_POSSIBILITY, decisionData, 6000) end end end return phase end function Decision_TeamPVPAutoFight:SetCommandPhase_RunToBuff(entity, phase, command, decisionData, decisionRecordDic, aiBaseComponent) if entity:IsAlive() and decisionRecordDic.targetBuffEntity and decisionRecordDic.targetBuffEntity:IsAlive() and decisionRecordDic.targetBuffEntity:IsActive() then -- old↓ --↓ 如果距离buff比较远,就尝试释放闪避技能 -- if FP.V2.DistanceSqr(decisionRecordDic.targetBuffEntity:GetLogicPos(), entity:GetLogicPos()) > RUN_TO_BUFF_DODGE_DISTANCE_SQR then -- local skillBase = entity.components.skillBase -- if self:CanUseDodgeSkill(entity) then -- self:TryUpdateDodgeSkillIndex(entity, decisionRecordDic) -- command.SkillIndex = decisionRecordDic.dodgeSkillIndex -- end -- end -- command = self:CommandRunToPathPoint(entity, command, decisionData) --↑ -- old↑ -- new↓ if self:RunByPosList(entity, phase, command, decisionData, decisionRecordDic, decisionRecordDic.posList, false) then phase = EPhase.NEAR_TO_STRINGHOLD_MOVING decisionRecordDic.runToBuffExitFrame = LogicUpdateManager._clientHandleFrame end -- new↑ else decisionRecordDic.targetBuffEntity = nil phase = EPhase.NEAR_TO_STRINGHOLD_MOVING aiBaseComponent:SetGlobalRecord(entity:GetCampID() == 1 and RUN_TO_BUFF_HERO_ID_CAMP1_KEY or RUN_TO_BUFF_HERO_ID_CAMP2_KEY, nil) decisionRecordDic.runToBuffExitFrame = LogicUpdateManager._clientHandleFrame end return phase end function Decision_TeamPVPAutoFight:SetCommandPhase_Escape(entity, phase, command, decisionData, decisionRecordDic) local target = entity.components.target.Target if target then if decisionRecordDic.phaseFrameEla < ESCAPE_WALK_FRAME then self:CommandEscapeFromTarget(entity, command, target) else local skillBase = entity.components.skillBase if self:CanUseDodgeSkill(entity) then self:TryUpdateDodgeSkillIndex(entity, decisionRecordDic) command.SkillIndex = decisionRecordDic.dodgeSkillIndex else phase = EPhase.NEAR_TO_STRONGHOLD_FIGHTING end end else phase = EPhase.NEAR_TO_STRONGHOLD_FIGHTING end return phase end local debugFlag = true --[[ 输出指令 --]] local PAUSE_FRAME_AFTER_USER_INPUT = 10 --有玩家输入后,该Decision暂停几帧 function Decision_TeamPVPAutoFight:SetCommand(entity, decisionData, command) repeat 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 if decisionRecordDic.lastUserInputFrame and LogicUpdateManager._clientHandleFrame - decisionRecordDic.lastUserInputFrame < PAUSE_FRAME_AFTER_USER_INPUT then --策划需求:如果玩家有输入,就得暂停AI运行一段时间 command.DontHandle = true break end decisionRecordDic.phaseFrameEla = decisionRecordDic.phaseFrameEla + decisionRecordDic.aiUpdateFrameInterval local attr = entity.components.attr local strongHold = decisionRecordDic[STRONGHOLD_KEY] if strongHold then local strongHoldCenter = decisionRecordDic[STRONGHOLD_CENTER_KEY] local strongHoldRadiusSqr = decisionRecordDic[STRONGHOLD_RADIUS_SQR_KEY] local phase = decisionRecordDic[PHASE_KEY] or EPhase.PREPARING local selfPos = entity.components.move.LogicPos local toCenterDistSqr = FP.V2.DistanceSqr(selfPos,strongHoldCenter) if phase == EPhase.PREPARING then phase = self:SetCommandPhase_Preparing(entity, phase) elseif phase == EPhase.LEAVE_REVIVE_AREA then phase = self:SetCommandPhase_LeaveReviveArea(entity, phase, command, decisionData, decisionRecordDic, selfPos) elseif phase == EPhase.RUN_TO_ENTRANCE then if entity.components.buff:HasBuff(IMMORTAL_BUFFID) then --如果有了无敌buff,表示复活了 phase = EPhase.LEAVE_REVIVE_AREA else phase = self:SetCommandPhase_RunToEntrance(entity, phase, command, decisionData, decisionRecordDic, selfPos) end else if entity.components.buff:HasBuff(IMMORTAL_BUFFID) then --如果有了无敌buff,表示复活了 phase = EPhase.LEAVE_REVIVE_AREA else if phase == EPhase.FAR_TO_STRONGHOLD_MOVING then --移动、释放技能 phase = self:SetCommandPhase_RunToSH(entity, phase, command, decisionData, decisionRecordDic, selfPos, toCenterDistSqr, strongHoldRadiusSqr, attr) elseif phase == EPhase.NEAR_TO_STRONGHOLD_FIGHTING then --移动、释放技能 phase = self:SetCommandPhase_FightingInSH(entity, phase, command, decisionData, decisionRecordDic, selfPos, aiBaseComponent, toCenterDistSqr, strongHoldRadiusSqr, strongHoldCenter) 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 end end self:ChangePhase(phase, entity, decisionData, decisionRecordDic, command, aiBaseComponent) else logging.error(LTAG.ERROR, "HYW : 没有据点,无法运行Pvp Ai") end until true return command end --region 当敌人打我时,我释放闪避技能( 参考的1v1 Decision_SoloFight,区别是删掉了切将逻辑) -- 当周围20米内有任意敌人朝我释放技能时,我释放闪避技能(此方法未抄1v1) function Decision_TeamPVPAutoFight:CheckAndTryUseDodgeSkill(entity, command, decisionRecordDic) local useSuccess = false if decisionRecordDic.dodgeFrame == IMPOSSIBLE_FRAME then if self:CanUseDodgeSkill(entity) then -- 为了稍微优化点性能,从几个判断能否释放闪避技能的地方提前到这里 local myPos = entity:GetLogicPos() for i, enemy in ipairs(LogicUpdateManager.EntityList_Sync) do if enemy.CampID == decisionRecordDic.enemeyCampID then local enemyCurSkillData = enemy.components.skillBase.CurSkillData if enemyCurSkillData then FP.V2.DistanceSqr(myPos, enemy:GetLogicPos(), _tempDisSqr) -- 获取距离 _tempV1:Reset(enemyCurSkillData.CastRadius):Mul(enemyCurSkillData.CastRadius) -- 释放距离 if _tempDisSqr <= _tempV1 then -- 在范围内 local aDir = temp_back:Reset(myPos):Sub(enemy.components.move.LogicPos) local cosA = FP.V2.Dot(aDir,enemy.components.move.LogicRotateDir) if cosA > FP_Const_Zero then -- 且敌人是面向我的 if self:IsTriggerDodgeTargetSkill(enemyCurSkillData) then if self:TryRefreshTriggerDodgeTargetSkill(entity, decisionRecordDic) then break end end end end end if decisionRecordDic.dodgeFrame == IMPOSSIBLE_FRAME then -- 或者这个敌人副将已放出 if self:TryRefreshAdjutantDodge(entity, decisionRecordDic, enemy) then break end end end end end end if decisionRecordDic.dodgeFrame == IMPOSSIBLE_FRAME then -- 或者最近1秒内被无双或副将技子弹打过 self:TryRefreshTriggerDodgeMissile(entity, decisionRecordDic) end if decisionRecordDic.dodgeFrame <= LogicUpdateManager._clientHandleFrame then --释放闪避 if self:CanUseDodgeSkill(entity) then self:TryUpdateDodgeSkillIndex(entity, decisionRecordDic) command.SkillIndex = decisionRecordDic.dodgeSkillIndex local theta = LogicRandom.GetRangeValue(entity, FP.Const.Zero, FP.Const.PI2 ,202405167) --极坐标θ local sin = FP.Math.Sin(theta) local cos = FP.Math.Cos(theta) command.SkillJoystickPosX:Reset(sin) command.SkillJoystickPosZ:Reset(cos) -- 随机朝向释放 useSuccess = true else decisionRecordDic.dodgeFrame = IMPOSSIBLE_FRAME end end return useSuccess end function Decision_TeamPVPAutoFight:IsTriggerDodgeTargetSkill(skillData) if skillData then local keyPos = skillData.KeyPosition return keyPos == KEY_POS_SKILL1 or keyPos == KEY_POS_SKILL2 or keyPos == KEY_POS_SKILL3 or keyPos == KEY_POS_MUSOU end return false end function Decision_TeamPVPAutoFight:TryRefreshTriggerDodgeTargetSkill(entity, decisionRecordDic) if not entity.components.buff:HasBuff(IMMORTAL_BUFFID) then local rand = LogicRandom.GetRandom01(entity, 202405162) if rand <= decisionRecordDic.dodgeReactionChance then decisionRecordDic.dodgeFrame = LogicUpdateManager._clientHandleFrame + FP.tonumberV1(LogicRandom.GetRangeValue(entity, decisionRecordDic.dodgeReactionTimeLow, decisionRecordDic.dodgeReactionTimeHigh, 202405163):Div(LuaConst.TimeSpanMs)) return true end end return false end function Decision_TeamPVPAutoFight:TryRefreshTriggerDodgeMissile(entity, decisionRecordDic) local frame = entity.components.record.lastHitByMusouOrAdjutantFrame if frame <= LogicUpdateManager._clientHandleFrame and entity.components.record.lastHitByMusouOrAdjutantFrame + 20 >= LogicUpdateManager._clientHandleFrame then -- 如果最近1秒内被无双或副将技子弹打过(策划没配置,写死1秒) if self:CanUseDodgeSkill(entity) then decisionRecordDic.dodgeFrame = LogicUpdateManager._clientHandleFrame + FP.tonumberV1(LogicRandom.GetRangeValue(entity, decisionRecordDic.dodgeReactionTimeLow, decisionRecordDic.dodgeReactionTimeHigh, 202405164):Div(LuaConst.TimeSpanMs)) end end end function Decision_TeamPVPAutoFight:TryRefreshAdjutantDodge(entity, decisionRecordDic, target) if decisionRecordDic.nextCheckAdjutantDodgeFrame == nil or decisionRecordDic.nextCheckAdjutantDodgeFrame <= LogicUpdateManager._clientHandleFrame then if target.components.adjutant and target.components.adjutant.AdjutantEntity and target.components.adjutant.AdjutantEntity:IsActive() then --if self:CanUseDodgeSkill(entity) then -- 已提到外面判断 decisionRecordDic.nextCheckAdjutantDodgeFrame = LogicUpdateManager._clientHandleFrame + 120 local rand = LogicRandom.GetRandom01(entity, 202405165) if rand <= decisionRecordDic.dodgeReactionChance then decisionRecordDic.dodgeFrame = LogicUpdateManager._clientHandleFrame + FP.tonumberV1(LogicRandom.GetRangeValue(entity, decisionRecordDic.dodgeReactionTimeLow, decisionRecordDic.dodgeReactionTimeHigh, 202405166):Div(LuaConst.TimeSpanMs)) return true end --end end end return false end --endregion 当敌人打我时,我释放闪避技能 return Decision_TeamPVPAutoFight