| | |
| | | #!/usr/bin/python
|
| | | # -*- coding: GBK -*-
|
| | | #---------------------------------------------------------------------
|
| | | ##@package AIType_21
|
| | | #巡逻守卫AI,攻击非本国家玩家,和红名玩家
|
| | | #-------------------------------------------------------------------------------
|
| | | #
|
| | | # @author PanWei
|
| | | # @date 2010-4-28下午06:01:33
|
| | | # @version 1.4
|
| | | ##@package NPCAI.AIType_21
|
| | | #
|
| | | #模块详细说明.
|
| | | # @change: "2010-05-12 18:30" zhengyang 添加注释
|
| | | # @change: "2010-06-09 09:50" zhengyang 守卫npc加入异常状态眩晕判断 |
| | | # @change: 2010-06-14 16:00 zhengyang 修正普攻参数传错
|
| | | # @change: "2010-11-22 12:15" Alee 删除异常/沉默判定
|
| | | #---------------------------------------------------------------------
|
| | | """Version = 2010-11-22 12:15"""
|
| | | #---------------------------------------------------------------------
|
| | | import IPY_GameWorld
|
| | | import GameWorld
|
| | | import NPCCommon
|
| | | import BaseAttack
|
| | | # @todo:副本活动机器人
|
| | | # @author hxp
|
| | | # @date 2018-12-06
|
| | | # @version 1.0
|
| | | #
|
| | | # 详细描述: 副本活动机器人
|
| | | #
|
| | | #-------------------------------------------------------------------------------
|
| | | #"""Version = 2018-12-06 20:00"""
|
| | | #-------------------------------------------------------------------------------
|
| | |
|
| | | import ChConfig
|
| | | import AICommon
|
| | | import NPCCommon
|
| | | import BaseAttack
|
| | | import IpyGameDataPY
|
| | | import IPY_GameWorld
|
| | | import GameWorld
|
| | | import FBCommon
|
| | | import GameObj
|
| | |
|
| | | import random
|
| | | #---------------------------------------------------------------------
|
| | |
|
| | | #---------------------------------------------------------------------
|
| | | ## 初始化
|
| | | # @param curNPC NPC实例
|
| | | # @param curNPC 当前npc
|
| | | # @return None
|
| | | # @remarks 函数详细说明.
|
| | | def DoInit(curNPC):
|
| | | curNPC.GetNPCAngry().Init(ChConfig.Def_BossAngryCount)
|
| | | curNPC.GetNPCAngry().Init(ChConfig.Def_SuperFBBossAngryCount)
|
| | | return
|
| | |
|
| | | #---------------------------------------------------------------------
|
| | | ##正常AI逻辑处理
|
| | | #@param curNPC NPC实例
|
| | | #@param tick 时间戳
|
| | | #@return 返回值无意义
|
| | | #@remarks 正常AI逻辑处理
|
| | | def OnNPCReborn(curNPC):
|
| | | curNPC.SetIsNeedProcess(True)
|
| | | return
|
| | |
|
| | | ## 执行AI
|
| | | # @param curNPC 当前npc
|
| | | # @param tick 当前时间
|
| | | # @return None
|
| | | # @remarks 函数详细说明.
|
| | | def ProcessAI(curNPC, tick):
|
| | | npcControl = NPCCommon.NPCControl(curNPC)
|
| | | if curNPC.GetCurAction() == IPY_GameWorld.laNPCDie or not curNPC.IsAlive():
|
| | | #NPC死亡, 进入死亡倒计时
|
| | | if npcControl.DieTick(tick) == 0:
|
| | | return
|
| | | |
| | | #刷新自己的buff
|
| | | npcControl.RefreshBuffState(tick)
|
| | | if GameObj.GetHP(curNPC) == 0 :
|
| | | # BUFF刷新中可能会导致NPC死亡
|
| | | return
|
| | |
|
| | | # #判断异常状态
|
| | | # if curNPC.GetAbnormalState() == IPY_GameWorld.sctFaint:
|
| | | # return |
| | | |
| | | curNPCAction = curNPC.GetCurAction()
|
| | | #NPC快速奔跑中, 处理
|
| | | if curNPCAction == IPY_GameWorld.laNPCMove and curNPC.GetCurMoveType() == IPY_GameWorld.mtRun :
|
| | | AICommon.NormalNPCFast_Move(curNPC , tick)
|
| | | #刷新自己的buff
|
| | | npcControl.RefreshBuffState(tick)
|
| | | if GameObj.GetHP(curNPC) == 0:
|
| | | # BUFF刷新中可能会导致NPC死亡
|
| | | return
|
| | |
|
| | | #刷新自己仇恨度列表
|
| | |
| | | curNPCAngry = npcControl.GetMaxAngryTag()
|
| | |
|
| | | #仇恨度列表中的人为空
|
| | | if curNPCAngry == None :
|
| | | AICommon.NormalNPCFree_Move(curNPC , tick)
|
| | | if curNPCAngry == None:
|
| | | if curNPC.GetSpeed() != 0:
|
| | | __RobotMove(curNPC)
|
| | | return
|
| | |
|
| | | #仇恨对象类型,仇恨对象ID
|
| | | curNPCAngryType = curNPCAngry.GetObjType()
|
| | | curNPCAngryID = curNPCAngry.GetObjID()
|
| | | #战斗中回血
|
| | | npcControl.ProcessBattleHPRestore(tick)
|
| | | |
| | | #执行攻击逻辑
|
| | | __NPCFight(curNPC, curNPCAngryID, curNPCAngryType, tick)
|
| | | return
|
| | |
|
| | | def __RobotMove(curNPC):
|
| | | if curNPC.GetCurAction() == IPY_GameWorld.laNPCMove:
|
| | | #GameWorld.DebugLog("移动中不处理!(%s,%s)" % (curNPC.GetPosX(), curNPC.GetPosY()))
|
| | | return
|
| | | mapID = GameWorld.GetMap().GetMapID()
|
| | | lineID = FBCommon.GetFBPropertyMark()
|
| | | dataMapID = FBCommon.GetRecordMapID(mapID)
|
| | | fbRandMovePosDict = IpyGameDataPY.GetFuncEvalCfg("AI198Point", 2, {})
|
| | | if str(dataMapID) in fbRandMovePosDict:
|
| | | __RobotMove2(curNPC, fbRandMovePosDict[str(dataMapID)])
|
| | | return
|
| | | posKey = "%d%02d" % (mapID, lineID)
|
| | | fbMovePosDict = IpyGameDataPY.GetFuncCfg("AI198Point", 1)
|
| | | if posKey not in fbMovePosDict:
|
| | | posKey = "%d%02d" % (mapID, 0)
|
| | | if posKey not in fbMovePosDict:
|
| | | return
|
| | | |
| | | posList = fbMovePosDict[posKey]
|
| | | Key_PosIndex = "RobotMovePosIndex" # NPC上次移动的坐标索引,存值+1
|
| | | posIndex = curNPC.GetDictByKey(Key_PosIndex) - 1
|
| | | if posIndex < 0:
|
| | | # 还没有走过点的,寻找所有点中最近的点
|
| | | posIndex = random.randint(0, len(posList) - 1)
|
| | | else:
|
| | | tagPosX, tagPosY = posList[posIndex]
|
| | | tagDist = GameWorld.GetDist(curNPC.GetPosX(), curNPC.GetPosY(), tagPosX, tagPosY)
|
| | | if tagDist < 2:
|
| | | posIndex += 1
|
| | | |
| | | if posIndex < 0 or posIndex >= len(posList):
|
| | | posIndex = random.randint(0, len(posList) - 1)
|
| | | |
| | | curNPC.SetDict(Key_PosIndex, posIndex + 1)
|
| | | tagPosX, tagPosY = posList[posIndex]
|
| | | curNPC.Move(tagPosX, tagPosY)
|
| | | return
|
| | |
|
| | | def __RobotMove2(curNPC, randPosList):
|
| | | ''' 根据多条路径随机移动,不同路径间如果存在交叉点,那么可能随机改变路径
|
| | | @param randPosList: [[[路径A点1x,y],[路径A点2x,y],...], [[路径B点1x,y],[路径B点2x,y],...], ...]
|
| | | '''
|
| | | if not randPosList:
|
| | | return
|
| | | |
| | | #objID = curNPC.GetID()
|
| | | #npcID = curNPC.GetNPCID()
|
| | | RobotMoveIndexInfo = "RobotMoveIndexInfo" # 上次移动目标坐标点索引信息 i * 100 + j
|
| | | RobotMovePosInfo = "RobotMovePosInfo" # 上次移动目标坐标点 posX * 10000 + posY
|
| | | indexInfo = curNPC.GetDictByKey(RobotMoveIndexInfo)
|
| | | posInfo = curNPC.GetDictByKey(RobotMovePosInfo)
|
| | | tagI, tagJ = indexInfo / 100, indexInfo % 100
|
| | | tagPosX, tagPosY = posInfo / 10000, posInfo % 10000
|
| | | curPosX, curPosY = curNPC.GetPosX(), curNPC.GetPosY()
|
| | | |
| | | |
| | | resetPosPath = True # 重置坐标路径,为True时重新搜索路径
|
| | | # 已经有目标点
|
| | | if tagPosX and tagPosY:
|
| | | # 理论上配置没重读
|
| | | if tagI < len(randPosList) and type(randPosList[tagI]) in [list, tuple] and tagJ < len(randPosList[tagI]) \
|
| | | and randPosList[tagI][tagJ] == [tagPosX, tagPosY]:
|
| | | resetPosPath = False
|
| | | |
| | | #GameWorld.DebugLog("__RobotMove2: objID=%s,npcID=%s,curPos(%s,%s),tagPos(%s,%s),tagIndex(%s,%s)" |
| | | # % (objID, npcID, curPosX, curPosY, tagPosX, tagPosY, tagI, tagJ))
|
| | | #GameWorld.DebugLog(" resetPosPath=%s,randPosList=%s" % (resetPosPath, randPosList))
|
| | | |
| | | # 重置路径,先走向最近的点
|
| | | if resetPosPath:
|
| | | nearestDist = 99999999
|
| | | for i, pathList in enumerate(randPosList):
|
| | | for j, pos in enumerate(pathList):
|
| | | posX, posY = pos
|
| | | tagDist = GameWorld.GetDist(curPosX, curPosY, posX, posY)
|
| | | if tagDist < nearestDist:
|
| | | nearestDist = tagDist
|
| | | tagI, tagJ = i, j
|
| | | tagPosX, tagPosY = posX, posY
|
| | | #GameWorld.DebugLog(" nearestDist=%s" % nearestDist)
|
| | | else:
|
| | | tagDist = GameWorld.GetDist(curPosX, curPosY, tagPosX, tagPosY)
|
| | | #GameWorld.DebugLog(" tagDist=%s" % (tagDist))
|
| | | # 快到达目标点了,预先寻找下个点
|
| | | if tagDist < 2:
|
| | | nearPosIndexList = __getNearPosIndexList(randPosList, tagI, tagJ)
|
| | | #GameWorld.DebugLog(" nearPosIndexList=%s" % nearPosIndexList)
|
| | | if nearPosIndexList:
|
| | | tagI, tagJ = random.choice(nearPosIndexList)
|
| | | tagPosX, tagPosY = randPosList[tagI][tagJ]
|
| | | |
| | | #GameWorld.DebugLog(" tagPos(%s,%s),tagIndex(%s,%s)" % (tagPosX, tagPosY, tagI, tagJ))
|
| | | curNPC.SetDict(RobotMoveIndexInfo, tagI * 100 + tagJ)
|
| | | curNPC.SetDict(RobotMovePosInfo, tagPosX * 10000 + tagPosY)
|
| | | curNPC.Move(tagPosX, tagPosY)
|
| | | return
|
| | |
|
| | | def __getNearPosIndexList(randPosList, tagI, tagJ):
|
| | | ## 获取多条路径上相邻的点
|
| | | pathPosList = randPosList[tagI]
|
| | | if not pathPosList or len(pathPosList) <= 1:
|
| | | return
|
| | | |
| | | tagPosX, tagPosY = randPosList[tagI][tagJ]
|
| | | nearPosIndexList = __getNearIndexByPath(pathPosList, tagI, tagJ)
|
| | | # 检查其他路径交叉点
|
| | | for i, pathList in enumerate(randPosList):
|
| | | if i == tagI:
|
| | | # 本路径不处理
|
| | | continue
|
| | | for j, pos in enumerate(pathList):
|
| | | posX, posY = pos
|
| | | if posX == tagPosX and posY == tagPosY:
|
| | | for ni, nj in __getNearIndexByPath(pathList, i, j):
|
| | | if [ni, nj] not in nearPosIndexList:
|
| | | nearPosIndexList.append([ni, nj])
|
| | | return nearPosIndexList
|
| | |
|
| | | def __getNearIndexByPath(pathPosList, tagI, tagJ):
|
| | | ## 获取某条路径上的相邻点索引信息
|
| | | nearPosIndexList = []
|
| | | # 起始点 或 最终点
|
| | | if tagJ == 0 or tagJ == len(pathPosList) - 1:
|
| | | # 起点=终点
|
| | | if pathPosList[0] == pathPosList[-1]:
|
| | | nearPosIndexList.append([tagI, 1])
|
| | | nearPosIndexList.append([tagI, -2])
|
| | | # 起点
|
| | | elif tagJ == 0:
|
| | | nearPosIndexList.append([tagI, 1])
|
| | | else:
|
| | | nearPosIndexList.append([tagI, -2])
|
| | | |
| | | # 中间点,取前后两点
|
| | | else:
|
| | | nearPosIndexList.append([tagI, tagJ - 1])
|
| | | nearPosIndexList.append([tagI, tagJ + 1])
|
| | | return nearPosIndexList
|
| | |
|
| | | #---------------------------------------------------------------------
|
| | | ## npc攻击战斗
|
| | | ## npc攻击逻辑
|
| | | # @param curNPC 当前npc
|
| | | # @param tagID curNPCAngryID
|
| | | # @param tagType curNPCAngryType
|
| | | # @param tick 当前时间
|
| | | # @return None
|
| | | # @remarks 战斗逻辑实现
|
| | | # @remarks 函数详细说明.
|
| | | def __NPCFight(curNPC, tagID, tagType, tick):
|
| | | #设置进入战斗状态
|
| | | NPCCommon.SetNPCInBattleState(curNPC)
|
| | | npcControl = NPCCommon.NPCControl(curNPC)
|
| | | #NPC的打怪AI
|
| | | if not npcControl.IsInRefreshArea():
|
| | | #追击返回
|
| | | npcControl.MoveBack()
|
| | | return
|
| | |
|
| | | #开始攻击
|
| | | curTag = GameWorld.GetObj(tagID, tagType)
|
| | |
| | |
|
| | | tagDist = GameWorld.GetDist(curNPC.GetPosX(), curNPC.GetPosY(), curTag.GetPosX(), curTag.GetPosY())
|
| | |
|
| | | if tagDist > curNPC.GetAtkDist() :
|
| | | npcControl.MoveToObj_Detel(curTag)
|
| | | #---优先释放技能---
|
| | | if AICommon.DoAutoUseSkill(curNPC, curTag, tagDist, tick):
|
| | | return
|
| | |
|
| | | #---释放普通攻击---
|
| | | |
| | | if curNPC.GetSpeed() == 0:
|
| | | # 不可移动NPC
|
| | | if tagDist > curNPC.GetAtkDist():
|
| | | return
|
| | | |
| | | if tick - curNPC.GetAttackTick() < curNPC.GetAtkInterval():
|
| | | #攻击间隔没有到, 返回
|
| | | return
|
| | | |
| | | #普通攻击
|
| | | BaseAttack.Attack(curNPC, curTag, None, tick)
|
| | | return
|
| | | |
| | | #超过攻击距离,移动过去
|
| | | if tagDist > curNPC.GetAtkDist():
|
| | |
|
| | | destDist = GameWorld.GetDist(curNPC.GetDestPosX() , curNPC.GetDestPosY(), curTag.GetPosX(), curTag.GetPosY())
|
| | | if destDist <= curNPC.GetAtkDist() and curNPC.GetCurAction() == IPY_GameWorld.laNPCMove:
|
| | | # 目标在移动的攻击范围内,不改变目标点
|
| | | return
|
| | | npcControl.MoveToObj_Detel(curTag)
|
| | | return
|
| | | else:
|
| | | curNPC.StopMove()
|
| | | |
| | | if tick - curNPC.GetAttackTick() < curNPC.GetAtkInterval():
|
| | | #攻击间隔没有到, 返回
|
| | | return
|
| | |
| | | #普通攻击
|
| | | BaseAttack.Attack(curNPC, curTag, None, tick)
|
| | | return
|
| | | |
| | |
|
| | | ## NPC死亡
|
| | | # @param curNPC 当前npc
|
| | | # @param hurtType 伤害者的obj类型
|
| | | # @param hurtID 伤害者的objID
|
| | | # @return None
|
| | | def OnDie(curNPC, hurtType, hurtID):
|
| | | AICommon.DoNPCUseSkillOnDie(curNPC)
|
| | | return
|
| | |
|
| | | |