| #!/usr/bin/python  | 
| # -*- coding: GBK -*-  | 
| #-------------------------------------------------------------------------------  | 
| #  | 
| ##@package NPCAI.AIType_21  | 
| #  | 
| # @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  | 
| #  @return None  | 
| #  @remarks º¯ÊýÏêϸ˵Ã÷.  | 
| def DoInit(curNPC):  | 
|     curNPC.GetNPCAngry().Init(ChConfig.Def_SuperFBBossAngryCount)  | 
|     return  | 
|   | 
| 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():  | 
|         return  | 
|       | 
|     #Ë¢ÐÂ×Ô¼ºµÄbuff  | 
|     npcControl.RefreshBuffState(tick)  | 
|     if GameObj.GetHP(curNPC) == 0:  | 
|         # BUFFË¢ÐÂÖпÉÄܻᵼÖÂNPCËÀÍö  | 
|         return  | 
|       | 
|     #Ë¢ÐÂ×Ô¼º³ðºÞ¶ÈÁÐ±í  | 
|     npcControl.RefreshAngryList(tick)  | 
|     curNPCAngry = npcControl.GetMaxAngryTag()  | 
|       | 
|     #³ðºÞ¶ÈÁбíÖеÄÈËΪ¿Õ  | 
|     if curNPCAngry == None:  | 
|         if curNPC.GetSpeed() != 0:  | 
|             __RobotMove(curNPC)  | 
|         return  | 
|       | 
|     #³ðºÞ¶ÔÏóÀàÐÍ,³ðºÞ¶ÔÏóID  | 
|     curNPCAngryType = curNPCAngry.GetObjType()  | 
|     curNPCAngryID = curNPCAngry.GetObjID()  | 
|       | 
|     #Ö´Ðй¥»÷Âß¼  | 
|     __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):  | 
|     ## »ñȡijÌõ·¾¶ÉϵÄÏàÁÚµãË÷ÒýÐÅÏ¢  | 
|     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¹¥»÷Âß¼  | 
| #  @param curNPC µ±Ç°npc  | 
| #  @param tagID curNPCAngryID  | 
| #  @param tagType curNPCAngryType   | 
| #  @param tick µ±Ç°Ê±¼ä  | 
| #  @return None  | 
| #  @remarks º¯ÊýÏêϸ˵Ã÷.  | 
| def __NPCFight(curNPC, tagID, tagType, tick):  | 
|     #ÉèÖýøÈëÕ½¶·×´Ì¬  | 
|     NPCCommon.SetNPCInBattleState(curNPC)  | 
|     npcControl = NPCCommon.NPCControl(curNPC)  | 
|       | 
|     #¿ªÊ¼¹¥»÷  | 
|     curTag = GameWorld.GetObj(tagID, tagType)  | 
|       | 
|     if curTag == None or GameObj.GetHP(curTag) <= 0:  | 
|         return  | 
|       | 
|     tagDist = GameWorld.GetDist(curNPC.GetPosX(), curNPC.GetPosY(), curTag.GetPosX(), curTag.GetPosY())  | 
|       | 
|     #---ÓÅÏÈÊͷż¼ÄÜ---  | 
|     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  | 
|       | 
|     if npcControl.FixTagPos(curTag.GetPosX(), curTag.GetPosY()):  | 
|         #ÐÞÕýÕâ¸öNPCµÄÕ¾Á¢Î»Öà  | 
|         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  | 
|   |