| #!/usr/bin/python  | 
| # -*- coding: GBK -*-  | 
| #---------------------------------------------------------------------  | 
| #  | 
| #---------------------------------------------------------------------  | 
| ##@package FBDefenseCommon  | 
| # @todo: ÊØ»¤Å®ÉñËùÓйÖÎïAIµÄ¹«¹²Êý¾ÝºÍº¯Êý  | 
| #  | 
| # @author adaws  | 
| # @date 2009-11-17 19:00  | 
| # @version 2.2  | 
| #  | 
| # @note:   | 
| #   | 
| # @change: "2010-11-18 11:00" adaws ¼ÓNPC´æ»îʱ¼äÈ¡½Ó¿Ú½è ²»ÊÇÿ¸öNPC¶¼ÓÐ  | 
| # @change: "2010-11-18 18:00" adaws AIѰ·Ð޸ĠÔÚ¹¥»÷ÖеĶàÓàRefreshAllStateÈ¥µô  | 
| # @change: "2010-11-19 12:00" adaws ÓÐÄ¿±êµÄ·Å¼¼ÄÜÔö¼Ó »Øµ÷ÐÞ¸Ä  | 
| # @change: "2010-11-20 17:40" adaws AI×ß·Ð޸ĠNormalCheck¼ì²é¼ÓÈëÊÇ·ñÔÚ¿ìËÙÒÆ¶¯Ïà¹Ø ¿ìËÙÒÆ¶¯µ«ÊDz»»ØË¢ÐµãÐÞ¸Ä  | 
| # @change: "2010-11-22 12:15" Alee NPC¿ØÖÆÐÞ¸Ä  | 
| # @change: "2010-11-22 17:30" adaws NPC·Å¼¼ÄܵÄʱºò¸ù¾Ý¼¼ÄܵÄÄ¿±êÊÇ·ñÊǶÔ×Ô¼º·ÅµÄÑ¡²»Í¬µÄÄ¿±ê  | 
| # @change: "2010-11-26 10:00" adaws É¾³ýÉÏÒ»´ÎµÄÍ·¶¥BUFF ÑéÖ¤ È¥µôÕ½¶·»ØÑª ¼ÓBUFF²»Ë¢×´Ì¬  | 
| # @change: "2010-12-16 20:50" Alee Ð޸ĺ¯ÊýÃû  | 
| # @change: "2010-12-31 17:43" Alee ÐÞ¸ÄBUFF¹ÜÀíÆ÷ÑéÖ¤  | 
| # @change: "2011-06-15 11:40" chenxuewei Ôö¼ÓÊØ»¤Å®Éñ¶¯Ì¬°æµÄbossµÄkey  | 
| #  | 
| # @change: "2011-06-16 16:40" chenxuewei AIÔö¼ÓÒì×åÎ×Ò½µÄÌØÊâ¼¼ÄÜÊÍ·Å  | 
| # @change: "2015-03-30 12:00" hxp ÐÞ¸ÄΪ֧³ÖͨÓÃTDË¢¹ÖÐÐ×ß·Ïß  | 
| #  | 
| #---------------------------------------------------------------------  | 
| """Version = 2015-03-30 12:00"""  | 
| #---------------------------------------------------------------------  | 
| import SkillShell  | 
| import GameWorld  | 
| import NPCCommon  | 
| import IPY_GameWorld  | 
| import OperControlManager  | 
| import BaseAttack  | 
| import ChConfig  | 
| import ReadChConfig  | 
| import AICommon  | 
| import GameObj  | 
|   | 
| import random  | 
|   | 
| #---ÏÂÃæ¶¼ÊÇNPCµÄ×ÖµäKEY---  | 
| NPCKey_PassedPointCount = 'PassedCount'          # NPC×ß¹ýµÄµãµÄ¸öÊý ²Èµã×ß·¨  | 
| NPCKey_CurLvUp_Step = 'LvUpStep'                 # µ±Ç°Í·¶¥BUFFµÄµÚ¼¸¸ö Í·¶¥BUFFµÈ¼¶  | 
| NPCKey_UseSkillHpPercent = 'UseSkillPercent'     # Ê¹Óü¼ÄÜÉúÃü°Ù·Ö±È·§Öµ  | 
| SingleMoveArea = 5  # NPCµ¥´ÎÒÆ¶¯¾àÀë  | 
| Dis_Differ = 3  # ÔÚÑ¡µãÒÆ¶¯µÄʱºò Ñ¡µãµÄ·¶Î§ ±ÜÃâÖØµþ  | 
| #MovePointList = [(53, 125), (73, 125), (93, 125), (113, 125), (133, 125), (146,125)]  | 
| #MovePointList = ReadChConfig.GetEvalChConfig('TDMovePointList')  | 
| Def_MaxDis = 999999  | 
|   | 
|   | 
| ## ¸±±¾ÖеÄNPCµÄÒÆ¶¯Âß¼ ²ÈµãÒÆ¶¯  | 
| #  @param curNpc: µ±Ç°NPC  | 
| #  @param movePointList: ²ÈµãÁÐ±í£¨×ø±êX£¬×ø±êY£¬¾àÀëÄ¿±êµãµÄÒÆ¶¯¾àÀ룩  | 
| #  @param tick: µ±Ç°tick  | 
| #  @return: ÎÞ  | 
| #  @remarks: ¸±±¾ÖÐNPC²ÈµãÒÆ¶¯  | 
| def NpcMoveByMovePointList(curNPC, movePointList, tick):  | 
|     npcControl = NPCCommon.NPCControl(curNPC)  | 
|     curNPCAction = curNPC.GetCurAction()  | 
|       | 
|     #ÎÞ³ðºÞ,µ«ÊÇÓÐÉ˺¦Ä¿±ê  | 
|     if curNPC.GetPlayerHurtList().GetHurtCount() != 0:  | 
|         npcControl.ResetNPC_Init()  | 
|           | 
|     elif curNPCAction == IPY_GameWorld.laNPCAttack:  | 
|         curNPC.SetCurAction(IPY_GameWorld.laNPCNull)  | 
|         #ÖØÖÃÉÏ´ÎÒÆ¶¯Ê±¼ä,ÈÃ×·»÷Íæ¼ÒµÄNPC¿ÉÒÔÉ¢¿ª  | 
|         curNPC.SetActionTick(0)  | 
|           | 
|     elif curNPCAction == IPY_GameWorld.laNPCNull:  | 
|         #¿ÕÏÐ״̬»ØÑª  | 
|         npcControl.ProcessHPRestore(tick)  | 
|       | 
|     curPassedPointCount = curNPC.GetDictByKey(NPCKey_PassedPointCount)  | 
|     needMoveToPointIndex = min(curPassedPointCount, len(movePointList) - 1)  | 
|   | 
|     #µ±Ç°×ø±ê Ä¿  | 
|     curPosX, curPosY = curNPC.GetPosX(), curNPC.GetPosY()  | 
|     destPosX, destPosY = movePointList[needMoveToPointIndex]  | 
|     curDis = GameWorld.GetDist(curPosX, curPosY, destPosX, destPosY)  | 
|   | 
|     #Èç¹ûÀëÄ¿±êµã±È½Ï½üµÄ»° È¡ÏÂÒ»¸öÄ¿±êµã  | 
|     if curDis <= Dis_Differ*2:  | 
|         nextIndex = min(needMoveToPointIndex + 1, len(movePointList) - 1)  | 
|         #Èç¹û»¹²»ÊÇ×îºóÒ»¸öÄ¿±êµã ÔòÈ¡ÏÂÒ»¸öÄ¿±êµãÐèÒªÒÆµÄλÖà  | 
|         if nextIndex != needMoveToPointIndex:  | 
|             curNPC.SetDict(NPCKey_PassedPointCount, needMoveToPointIndex + 1)  | 
|             destPosX, destPosY = movePointList[nextIndex]  | 
|             curDis = GameWorld.GetDist(curPosX, curPosY, destPosX, destPosY)  | 
|           | 
|     #---Èç¹ûÀëÄ¿±êµã±È½Ï½ü»òÕß ÒѾȥ¹ýÄ¿±êµãÔòѡĿ±êµãÖÜΧµÄÒ»µã×ß  | 
|     moveDestX, moveDestY = npcControl.GetMoveNearPos(destPosX, destPosY, 1)  | 
|     npcControl.MoveToPosStepByStep(moveDestX, moveDestY, SingleMoveArea)  | 
|      | 
|      | 
|   | 
| ## Å®Éñ¸±±¾ÖеÄNPCÒÆ¶¯  | 
| #  @param curNpc: µ±Ç°NPC  | 
| #  @param tick: µ±Ç°tick  | 
| #  @return: ÎÞ  | 
| #  @remarks: Å®Éñ¸±±¾ÖÐNPC²ÈµãÒÆ¶¯ µ÷¸±±¾²ÈµãÒÆ¶¯º¯Êý ¸ø¶¨²ÈµãÁÐ±í  | 
| def FBDefenceMove(curNPC, tick):  | 
|     #GameWorld.DebugLog("FBDefenceMove isboss=%s" % curNPC.GetIsBoss())  | 
|     fromRefreshValue = curNPC.GetDictByKey(ChConfig.Def_NPC_Dict_FromRefreshValue)  | 
|     fromRefreshMark = curNPC.GetDictByKey(ChConfig.Def_NPC_Dict_FromRefreshMark)  | 
|       | 
|     MovePointList = ReadChConfig.GetEvalChConfig('TDMovePointList')  | 
|     if fromRefreshValue > 0:  | 
|         movePointDict = ReadChConfig.GetEvalChConfig('TD_%s_Move' % fromRefreshValue)  | 
|         if fromRefreshMark in movePointDict:  | 
|             MovePointList = movePointDict[fromRefreshMark]  | 
|               | 
|     #NpcMoveByMovePointList(curNPC, MovePointList, tick)  | 
|     AICommon.NPCMoveByPointList(curNPC, MovePointList)  | 
|     return  | 
|   | 
| ## Å®Éñ¸±±¾µÄÆÕͨ¼ì²é  | 
| # @param curNPC: µ±Ç°NPC  | 
| # @param tick: µ±Ç°Tick  | 
| # @return: ÊÇ·ñ¿ÉÒÔ¹¥»÷»òÖ´ÐÐÆäËüµÄ¶¯×÷  | 
| # @remarks:  ¼ì²éNPCËÀÍö ÊÇ·ñÓÐÒ쳣״̬²»Äܶ¯µÄ ÊÇ·ñÐèÒªËÀÍöµÈ  | 
| def NormalCheck(curNPC, tick):  | 
|     if curNPC.GetCurAction() == IPY_GameWorld.laNPCDie or not curNPC.IsAlive():  | 
|         #NPCËÀÍö, ½øÈëËÀÍöµ¹¼ÆÊ±  | 
|         return False  | 
|       | 
|     npcControl = NPCCommon.NPCControl(curNPC)  | 
|     npcControl.RefreshBuffState(tick)  | 
|     if GameObj.GetHP(curNPC) == 0 :  | 
|         # BUFFË¢ÐÂÖпÉÄܻᵼÖÂNPCËÀÍö  | 
|         return  | 
|       | 
|     npcLastTime = 0  | 
|     npcObjType = curNPC.GetGameNPCObjType()  | 
|     if npcObjType == IPY_GameWorld.gnotSummon:  | 
|         npcLastTime = curNPC.GetLastTime()  | 
|           | 
|     #ÕÙ»½ÊÞ³¬¹ý´æ»îʱ¼ä, ÉèÖÃËÀÍö  | 
|     if npcLastTime != 0 and tick - curNPC.GetBornTime() >= npcLastTime:  | 
|         npcControl.SetKilled()  | 
|         return False  | 
|       | 
|     #ÅжÏÒ쳣״̬  | 
| #    if curNPC.GetAbnormalState() == IPY_GameWorld.sctFaint:  | 
| #        return False  | 
|   | 
|     curNPCAction = curNPC.GetCurAction()  | 
|     #NPC¿ìËÙ±¼ÅÜÖÐ, ²»´¦Àí   | 
|     if curNPCAction == IPY_GameWorld.laNPCMove and curNPC.GetCurMoveType() == IPY_GameWorld.mtRun:  | 
|         FastMoveNotMoveBack(curNPC, tick)  | 
|         return False  | 
|       | 
|     return True  | 
|   | 
|   | 
| ##¿ìËÙÒÆ¶¯µ«ÊDz»»ØË¢Ð嵋  | 
| # @param curNPC: µ±Ç°NPC  | 
| # @param tick: µ±Ç°Tick  | 
| # @return: ÎÞ  | 
| # @remarks:  NPC¿ìËÙÒÆ¶¯ µ«ÊDz»»ØË¢Ð嵋  | 
| def FastMoveNotMoveBack(curNPC, tick):  | 
|     npcControl = NPCCommon.NPCControl(curNPC)  | 
|     if curNPC.GetPlayerHurtList().GetHurtCount() == 0:  | 
|         npcControl.ProcessHPRestore(tick)  | 
|     else:  | 
|         npcControl.ProcessBattleHPRestore(tick)  | 
|     return  | 
|           | 
| ## Å®Éñ¸±±¾µÄAIͨÓù¥»÷  | 
| # @param curNPC: µ±Ç°NPC  | 
| # @param tick: µ±Ç°Tick  | 
| # @param canMove: NPCÊÇ·ñ¿ÉÒÔÒÆ¶¯  | 
| # @param callbackList: ·Å¼¼Äܵļì²é»Øµ÷  | 
| # @param isWuYi: µ±Ç°NPCÊÇ·ñÊÇÒì×åÎ×Ò½£¬Ä¬Èϲ»ÊÇ  | 
| # @return: ÎÞ  | 
| # @remarks:  Å®Éñ¸±±¾µÄAIͨÓù¥»÷ °üÀ¨·Å¼¼ÄÜ Èç¹ûʲô¼¼ÄÜÒ²²»·Å²»¸ø¼ì²é»Øµ÷¼´¿É Èç¹û²»·ÅµÚ¼¸¸ö¼¼ÄÜÐèҪдһ¸ö»Øµ÷ÓÀ²»µ÷Óà  | 
| def NormalFight(curNPC, tick, canMove=True, refreshInterval=ChConfig.Def_NPCRefreshAngryValueInterval, isUpdAngry=False):  | 
|     npcControl = NPCCommon.NPCControl(curNPC)  | 
|   | 
|     #Ë¢ÐÂ×Ô¼º³ðºÞ¶ÈÁÐ±í  | 
|     if not isUpdAngry:  | 
|         angryObj = None  | 
|         curNPCAngry = npcControl.GetMaxAngryTag()  | 
|         if curNPCAngry:  | 
|             angryObj = GameWorld.GetObj(curNPCAngry.GetObjID(), curNPCAngry.GetObjType())  | 
|         if not angryObj or (angryObj and GameObj.GetHP(angryObj) <= 0):  | 
|             npcControl.RefreshAngryList(tick, refreshInterval, isUpdAngry)  | 
|             curNPCAngry = npcControl.GetMaxAngryTag()  | 
|     else:  | 
|         npcControl.RefreshAngryList(tick, refreshInterval, isUpdAngry)  | 
|         curNPCAngry = npcControl.GetMaxAngryTag()  | 
|       | 
|     #³ðºÞ¶ÈÁбíÖеÄÈËΪ¿Õ  | 
|     if curNPCAngry == None:  | 
|         if not canMove:  | 
|             return  | 
|         FBDefenceMove(curNPC, tick)  | 
|         return  | 
|       | 
|     #³ðºÞ¶ÔÏóÀàÐÍ,³ðºÞ¶ÔÏóID  | 
|     curNPCAngryType = curNPCAngry.GetObjType()  | 
|     curNPCAngryID = curNPCAngry.GetObjID()  | 
|     #Õ½¶·ÖлØÑª  | 
| #    npcControl.ProcessBattleHPRestore(tick)  | 
|       | 
|     #Ö´Ðй¥»÷Âß¼  | 
|     __NPCFight(curNPC, curNPCAngryID, curNPCAngryType, tick, canMove)  | 
|     return  | 
|   | 
|   | 
| ## npc¹¥»÷Âß¼ ¸ù¾ÝNPCÊÇ·ñ¿ÉÒÔÒÆ¶¯ ¼¼Äܼì²é»Øµ÷Áбí·Å¼¼ÄÜ  | 
| #  @param curNPC µ±Ç°npc  | 
| #  @param tagID curNPCAngryID  | 
| #  @param tagType curNPCAngryType   | 
| #  @param tick µ±Ç°Ê±¼ä  | 
| #  @param canMove£º NPCÊÇ·ñÒªÒÔÒÆ¶¯   | 
| #  @param callbackList£º ·Å¼¼Äܵļì²é»Øµ÷ÁÐ±í  | 
| #  @param isWuYi: µ±Ç°NPCÊÇ·ñÊÇÒì×åÎ×Ò½£¬Ä¬Èϲ»ÊÇ  | 
| #  @return None  | 
| #  @remarks º¯ÊýÏêϸ˵Ã÷.  | 
| def __NPCFight(curNPC, tagID, tagType, tick, canMove):  | 
|     #ÉèÖýøÈëÕ½¶·×´Ì¬  | 
|     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 tagDist > curNPC.GetAtkDist():  | 
|         if not canMove:  | 
|             return  | 
|           | 
|         npcControl.MoveToObj_Detel(curTag)  | 
|         return  | 
|       | 
|     #¹¥»÷¼ä¸ôûÓе½, ·µ»Ø  | 
|     if tick - curNPC.GetAttackTick() < curNPC.GetAtkInterval():  | 
|         return  | 
|       | 
|     #ÐÞÕýÕâ¸öNPCµÄÕ¾Á¢Î»ÖàÈç¹û¿ÉÒÔ¶¯µÄ»°  | 
|     if canMove:  | 
|         if npcControl.FixTagPos(curTag.GetPosX(), curTag.GetPosY()):  | 
|             return  | 
|       | 
|     #if SeriesSkillByCallBackList(curNPC, curTag, tick, callbackList):  | 
|     #    return  | 
|       | 
|     #ÆÕͨ¹¥»÷  | 
|     BaseAttack.Attack(curNPC, curTag, None, tick)  | 
|     return  | 
|   | 
| ## ¸ù¾Ýindex ·ÅNPCÖеĵÚindex¸ö¼¼ÄÜ  | 
| #  @param curNPC£º µ±Ç°NPC   | 
| #  @param index£º ·ÅµÚ¼¸¸ö¼¼ÄÜ  | 
| #  @return ÎÞ  | 
| #  @remarks º¯ÊýÏêϸ˵Ã÷.¸ù¾Ýindex ·ÅNPCÖеĵÚindex¸ö¼¼ÄÜ  | 
| def UseSkillByIndex(curNPC, index):  | 
|     if index < 0:  | 
|         return  | 
|       | 
|     skillManager = curNPC.GetSkillManager()  | 
|     if skillManager.GetSkillCount() <= index:  | 
|         return  | 
|       | 
|     curSkill = skillManager.GetSkillByIndex(index)  | 
|     if not curSkill:  | 
|         return  | 
|       | 
|     tick = GameWorld.GetGameWorld().GetTick()  | 
|     SkillShell.NPCUseSkill(curNPC, curSkill, tick)  | 
|   | 
|   | 
| ## ËÀÍöµÄʱºò·Å¼¼ÄÜ ÒòΪNPCËÀÁËËùÒÔÐèÒªÏÈÉèHP 1 Èƹý¼ì²é È»ºóÔÙÉè³É0  | 
| # @param curNPC: µ±Ç°NPC  | 
| # @param index: Òª·ÅµÄ¼¼ÄÜindex  | 
| # @return: ÎÞ  | 
| # @remarks:  ËÀÍöµÄʱºò·Å¼¼ÄÜ ÒòΪNPCËÀÁËËùÒÔÐèÒªÏÈÉèHP 1 Èƹý¼ì²é È»ºóÔÙÉè³É0  | 
| def DeadUseSkillByIndex(curNPC, index):  | 
|     GameObj.SetHP(curNPC, 1)  | 
|     UseSkillByIndex(curNPC, index)  | 
|     GameObj.SetHP(curNPC, 0)  | 
|       | 
|       | 
| ## »Øµ÷¼ì²é NPC ÊÇ·ñµ½ÁËNPC×ÖµäÖеÄÏàӦѪÁ¿°Ù·Ö±È  | 
| # @param curNPC: µ±Ç°NPC  | 
| # @return: ÊÇ·ñµ½ÁËNPC×ÖµäÖеÄÏàӦѪÁ¿°Ù·Ö±È£¨NPC ÑªÁ¿µ½·§ÖµÊ±ºò ÐèÒª·Å¼¼Äܵġ££©  | 
| # @remarks:  »Øµ÷¼ì²é ÊÇ·ñµ½ÁËNPC×ÖµäÖеÄÏàӦѪÁ¿°Ù·Ö±È  | 
| def CallbackCheckHpPercent(curNPC):  | 
|     curHp = GameObj.GetHP(curNPC)  | 
|     maxHp = GameObj.GetMaxHP(curNPC)  | 
|     npcUseSkillHpPercent = curNPC.GetDictByKey(NPCKey_UseSkillHpPercent)  | 
|     realPercent = float(npcUseSkillHpPercent)/ChConfig.Def_MaxRateValue  | 
|       | 
|     #ѪÁ¿²»¹»°Ù·Ö±ÈÐèÒª·Å¼¼ÄÜ  | 
|     if curHp < maxHp*realPercent:  | 
|         return True  | 
|     else:  | 
|         return False  | 
|   | 
| ## ¸ù¾Ý¼ì²é»Øµ÷ ÊͷŶÔÓ¦NPCµÄ¼¼ÄÜ Èç¹û²»³É¹¦·µ»ØFalse  | 
| # @param curNPC: µ±Ç°NPC  | 
| # @param skillIndex: Òª·ÅµÄ¼¼ÄÜindex  | 
| # @param tick: µ±Ç°Tick  | 
| # @param skillIndex: ¼ì²é»Øµ÷  | 
| # @return: ·Å¼¼ÄÜÊÇ·ñÊͷųɹ¦  | 
| # @remarks: ¸ù¾Ý¼ì²é»Øµ÷ ÊͷŶÔÓ¦NPCµÄ¼¼ÄÜ Èç¹û²»³É¹¦·µ»ØFalse  | 
| def SkillCheckCallback(curNPC, curTag, skillIndex, tick, callback=None):  | 
|     #---¹¥»÷¼ä¸ô²»µ½ »òÕ߻ص÷ûÓв»´¦Àí---  | 
|     if tick - curNPC.GetAttackTick() < curNPC.GetAtkInterval():  | 
|         return False  | 
|       | 
|     skillManager = curNPC.GetSkillManager()  | 
|     skillTotalCount = skillManager.GetSkillCount()  | 
|     if skillTotalCount <= skillIndex:  | 
|         return False  | 
|       | 
|     #Èç¹ûÊǸºµÄÔò´Ó×îºóÒ»¸ö¼¼ÄÜÍùǰÊý ×îСΪ0¼´µÚÒ»¸ö  | 
|     if skillIndex < 0:  | 
|         skillIndex = min(0, skillTotalCount + skillIndex)  | 
|           | 
|     curSkill = skillManager.GetSkillByIndex(skillIndex)  | 
|       | 
|     if not curSkill:  | 
|         return False  | 
|       | 
|     #CDδµ½²»´¦Àí  curSkill.GetCoolDownTime()  | 
|     if tick - curSkill.GetLastUseTick() < curSkill.GetCoolDownTime():  | 
|         return False  | 
|    | 
|     #¼ì²é»Øµ÷²»Í¨¹ý  | 
|     if callback != None and not callback(curNPC):  | 
|         return False  | 
|       | 
|     #¶Ô×ÔÒѷŵļ¼ÄÜ  | 
|     if SkillShell.GetSkillAffectTag(curSkill) in ChConfig.Def_ST_CanNPCUseSkill:  | 
|         curTag = curNPC  | 
|           | 
|     #ÉÏÃæµÄÌõ¼þ¶¼Âú×ã·Å¼¼ÄÜ  | 
|     SkillShell.DoLogic_UseSkill(curNPC, curTag, curSkill, tick)  | 
|     return True  | 
|   | 
|   | 
| ## ¸ù¾Ý¼ì²é»Øµ÷Áбí ÊͷŶÔÓ¦NPCµÄ¼¼ÄÜ »Øµ÷ÁбíÓÃÓÚÅж¨µ±Öеļ¼ÄÜÊÇ·ñÄÜ·Å  | 
| # @param curNPC: µ±Ç°NPC  | 
| # @param tick: µ±Ç°Tick  | 
| # @param callbackList: ¼ì²é»Øµ÷ÁÐ±í  | 
| # @return: ·Å¼¼ÄÜÊÇ·ñÊͷųɹ¦  | 
| # @remarks: ¸ù¾Ý¼ì²é»Øµ÷Áбí ÊͷŶÔÓ¦NPCµÄ¼¼ÄÜ »Øµ÷ÁбíÓÃÓÚÅж¨µ±Öеļ¼ÄÜÊÇ·ñÄÜ·Å »Øµ÷¼ì²éº¯Êý¿ÉÒÔÊÇ×Ô¼ºµÄPYµÄ  | 
| def SeriesSkillByCallBackList(curNPC, curTag, tick, callbackList):  | 
|     if callbackList == []:  | 
|         return False  | 
|       | 
|     skillManager = curNPC.GetSkillManager()  | 
|       | 
|     #---×î¶à¿ÉÒÔ·ÅNPC¼¼ÄܹÜÀíÆ÷ÖÐÓеļ¼ÄÜ---  | 
|     skillTotalCount = skillManager.GetSkillCount()  | 
|     callBackList = callbackList[:skillTotalCount]  | 
|       | 
|     for index, curCallback in enumerate(callBackList):  | 
|         if SkillCheckCallback(curNPC, curTag, index, tick, curCallback):  | 
|             return True  | 
|       | 
|     return False  | 
|   | 
|       | 
|      |