xdh
2019-05-09 02f8c83ffab335d63d18bdde30e61bd2233f1f87
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCAI/AIType_196.py
@@ -1,70 +1,38 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#---------------------------------------------------------------------
#-------------------------------------------------------------------------------
#
#---------------------------------------------------------------------
##@package AIType_196
# @todo: 盗宝哥布林AI
##@package NPCAI.AIType_196
#
# @author: hxp
# @date 2013-11-05
# @version 1.9
# @todo:盗宝哥布林/宝箱怪
# @author hxp
# @date 2019-04-18
# @version 1.0
#
# @note:
# @change: "2013-11-08 18:00" hxp 修改逻辑
# @change: "2013-11-12 14:50" hxp 掉落矩阵改为按掉落个数掉落
# @change: "2013-12-27 12:40" hxp 增加地精夺宝地图不广播
# @change: "2014-01-17 11:00" hxp 修改不掉落物品由NPC是否掉落决定,增加指定可掉落配置
# @change: "2015-03-05 11:30" hxp 修复可能会停在无法攻击区域的问题
# @change: "2015-03-30 19:30" hxp 增加击杀流向; 击杀广播可配置特殊NPCID对应广播
# @change: "2015-04-21 16:00" hxp 检查纠正哥布林位置(防止处于安全区或障碍点)
# @change: "2015-04-22 11:20" xmnathan NPC死亡时防范取到NPCID为0的情况
# @change: "2015-07-13 11:30" ljd 非一线隐藏哥布林
#---------------------------------------------------------------------
"""Version = 2015-07-13 11:30"""
#---------------------------------------------------------------------
import IPY_GameWorld
# 详细描述: 盗宝哥布林/宝箱怪
#
#-------------------------------------------------------------------------------
#"""Version = 2019-04-18 15:00"""
#-------------------------------------------------------------------------------
import GameMap
import ChConfig
import GameWorld
import NPCCommon
import ChConfig
import ReadChConfig
import PetControl
import GameMap
import DataRecordPack
import IPY_GameWorld
import PlayerControl
import IpyGameDataPY
import AttackCommon
import ItemCommon
import GameObj
import ChItem
import random
#---------------------------------------------------------------------
#---SetDict NPC字典KEY,不存于数据库---
Def_NPCKey_Goblin_AttackedTick = 'Goblin_AttackedTick'  # 哥布林被攻击时间
Def_NPCKey_Goblin_MoveDir = 'Goblin_MoveDir'  # 哥布林移动方向
(
Def_DropItemType_Money, # 掉落物品类型 - 金钱
Def_DropItemType_Goods, # 掉落物品类型 - 道具
Def_DropItemType_Equip, # 掉落物品类型 - 装备
) = range(3)
(
Def_StopTime, # 多长时间未被攻击则进入呆滞状态,毫秒
Def_AttackedDropItemCountRate, # 每次被攻击掉落的物品个数饼图概率
Def_AttackedDropItemTypeRate, # 每次被攻击掉落的物品类型饼图概率
Def_DieDropGoodsCountRate, # 死亡掉落的道具个数饼图概率
Def_DieDropEquipCountRate, # 死亡掉落的装备个数饼图概率
Def_DieDropCountRate, # 死亡掉落物品总个数饼图概率
Def_DropGoodsRate, # 移动/死亡掉落的道具掉落饼图概率及道具id
Def_DropEquipModelNum, # 移动/死亡掉落装备规则模板编号,模板文件GoblinDropEquip_模板文件编号.txt
) = range(8)
g_filterEquipDict = {} # 装备掉落过滤字典缓存
(
Def_EquipModel_EquipType, # 掉落装备类型
Def_EquipModel_LVLimit, # 掉落装备等级限制
Def_EquipModel_QualityRate, # 掉落装备品质概率
Def_EquipModel_DropItemList, # NPC不掉落,但这里可掉落的物品id列表
) = range(4)
# 移动方向
MoveDirList = (
@@ -87,9 +55,7 @@
#  @remarks 函数详细说明.
def DoInit(curNPC):
    curNPC.GetNPCAngry().Init(ChConfig.Def_NormalNPCAngryCount)
    curNPC.SetDict(Def_NPCKey_Goblin_AttackedTick, 0) # 设置被攻击时间
    DoHideGoblin(curNPC)
    #curNPC.SetDict(Def_NPCKey_Goblin_AttackedTick, 0) # 设置被攻击时间
    return
@@ -99,15 +65,13 @@
#  @return None
#  @remarks 函数详细说明.
def ProcessAI(curNPC, tick):
    if DoHideGoblin(curNPC):
        return
    
    npcControl = NPCCommon.NPCControl(curNPC)
    if curNPC.GetCurAction() == IPY_GameWorld.laNPCDie or not curNPC.IsAlive():
        #NPC死亡, 进入死亡倒计时
        if npcControl.DieTick(tick) == 0:
            return
    # 上一次被攻击时间
    attackedTick = curNPC.GetDictByKey(Def_NPCKey_Goblin_AttackedTick)
    
@@ -116,10 +80,8 @@
        __CheckCorrectGoblinPos(curNPC)
        return
    
    aiConfig = __GetGoblinConfig(curNPC.GetNPCID())
    # 一定时间内未被攻击,则停止
    if tick - attackedTick >= aiConfig[Def_StopTime]:
    if tick - attackedTick >= 3000:
        __GoblinStop(curNPC)
        return
    
@@ -127,7 +89,7 @@
    # 如果不是移动状态,则执行移动
    if curNPCAction != IPY_GameWorld.laNPCMove:
        __Runaway(curNPC, npcControl, tick)
    return
@@ -157,7 +119,7 @@
    
    dist = ChConfig.Def_Screen_Area * 2
    cPosX, cPosY = 0, 0
    for i in range(0, dist * dist):
    for _ in xrange(0, dist * dist):
        cPosX = random.randint(posX - dist, posX + dist)
        cPosY = random.randint(posY - dist, posY + dist)
        
@@ -176,11 +138,7 @@
    return
## 哥布林移动走开
#  @param curNPC 当前npc
#  @param npcControl
#  @param tick
#  @return None
## 移动走开
def __Runaway(curNPC, npcControl, tick):
    posX = curNPC.GetPosX()
    posY = curNPC.GetPosY()
@@ -189,7 +147,7 @@
    tagPosX, tagPosY = 0, 0
    
    # 寻找目标坐标点
    for i in range(len(MoveDirList)):
    for _ in range(len(MoveDirList)):
        tagPosX, tagPosY = __GetRandomPos(posX, posY, moveArea, moveDir)
        # 如果返回0,0点,或者位置不变,则改变移动方向
        if (tagPosX == 0 and tagPosY == 0) or (tagPosX == posX and tagPosY == posY):
@@ -247,7 +205,7 @@
        GameWorld.ErrLog("moveDir=%s not in MoveDirList" % moveDir)
        return (0, 0)
     
    for i in range(0, dist * dist):
    for _ in range(0, dist * dist):
        if moveDir == Def_MoveDir_Up: # 上
            resultX = posX
            resultY = posY + dist
@@ -288,210 +246,78 @@
#  @param tick 
#  @return 具体伤害值
def OnAttacked(atkObj, curNPC, skill, tick):
    npcControl = NPCCommon.NPCControl(curNPC)
    if GameObj.GetHP(curNPC) < GameObj.GetMaxHP(curNPC) / 2:
        GameObj.SetHP(curNPC, GameObj.GetMaxHP(curNPC))
        GameWorld.DebugLog("半血回满血!")
    curNPC.SetDict(Def_NPCKey_Goblin_AttackedTick, tick) # 设置被攻击时间
    
    # 每次被攻击掉落物品
    __OnAttackedDropItem(atkObj, curNPC)
    __OnAttackedDropItem(atkObj, curNPC, npcControl)
    return
def OnCheckCanDie(atkObj, curNPC, skill, tick):
    ## 检查NPC是否可死亡
    GameObj.SetHP(curNPC, GameObj.GetMaxHP(curNPC))
    GameWorld.DebugLog("死亡回满血!")
    return False
## 每次被攻击掉落物品
#  @param atkObj 攻击发起者
#  @param curNPC 被攻击NPC
#  @return None
def __OnAttackedDropItem(atkObj, curNPC):
    npcControl = NPCCommon.NPCControl(curNPC)
    dropType = ChConfig.Def_NPCHurtTypeAll
    ownerID = 0
    atkObjType = atkObj.GetGameObjType()
    # 如果是玩家,则物品拥有者属于该玩家
    if atkObjType == IPY_GameWorld.gotPlayer:
        dropType = ChConfig.Def_NPCHurtTypePlayer
        ownerID = atkObj.GetPlayerID()
    # 如果是召唤兽或宠物,则物品拥有者属于对应主人
    elif atkObjType == IPY_GameWorld.gotNPC:
        npcObjType = atkObj.GetGameNPCObjType()
        # 判断召唤兽主人
        if npcObjType == IPY_GameWorld.gnotSummon:
            curNPCDetail = GameWorld.GetObjDetail(atkObj)
            if curNPCDetail != None:
                curNPCOwner = curNPCDetail.GetOwner()
                summonOwner = GameWorld.GetObjDetail(curNPCOwner)
                if summonOwner != None:
                    # 召唤兽主人为玩家
                    if summonOwner.GetGameObjType() == IPY_GameWorld.gotPlayer:
                        dropType = ChConfig.Def_NPCHurtTypePlayer
                        ownerID = summonOwner.GetPlayerID()
        # 判断宠物主人
        elif npcObjType == IPY_GameWorld.gnotPet:
            curPlayer = PetControl.GetPetOwner(atkObj)
            if curPlayer != None:
                dropType = ChConfig.Def_NPCHurtTypePlayer
                ownerID = curPlayer.GetPlayerID()
    aiConfig = __GetGoblinConfig(curNPC.GetNPCID())
    # 掉落个数
    dropCount = GameWorld.GetResultByRandomList(aiConfig[Def_AttackedDropItemCountRate])
## 掉落规则修改,暂屏蔽,之后有用到该AI再做修改
#    # 循环掉落
#    for i in range(dropCount):
#        dropItemType = GameWorld.GetResultByRandomList(aiConfig[Def_AttackedDropItemTypeRate])
#
#        # 金钱
#        if dropItemType == Def_DropItemType_Money:
#            npcControl.DropMoney(ChConfig.Def_NPCMapDropRate, dropType, ownerID)
#        # 道具
#        elif dropItemType == Def_DropItemType_Goods:
#            goodsID = GameWorld.GetResultByRandomList(aiConfig[Def_DropGoodsRate])
#            npcControl.DropItem(goodsID, dropType, ownerID)
#        # 装备
#        elif dropItemType == Def_DropItemType_Equip:
#            equipID = __GetRadomDropEquipID(aiConfig[Def_DropEquipModelNum])
#            npcControl.DropItem(equipID, dropType, ownerID)
    return
## NPC死亡处理
#  @param curNPC 死亡NPC
#  @param HurtType 掉落类型
#  @param HurtID 对应拥有者id
#  @param modulus 掉落系数
#  @return None
def OnDie(curNPC, HurtType, HurtID):
    #GameWorld.DebugLog("OnDieDropItem...dropType=%s, ownerID=%s" % (dropType, ownerID))
    # 该死亡掉落无物品保护
    dropType = ChConfig.Def_NPCHurtTypeAll
    ownerID = 0
    npcControl = NPCCommon.NPCControl(curNPC)
    if curNPC.GetNPCID() == 0:
        GameWorld.ErrLog("AIType_196 OnDie NPCID=0")
def __OnAttackedDropItem(atkObj, curNPC, npcControl):
    attackPlayer, npcObjType = AttackCommon.GetAttackPlayer(atkObj)
    if npcObjType:
        return
    aiConfig = __GetGoblinConfig(curNPC.GetNPCID())
    dropItemIDList = [] # [[itemID, count],...]
    if not attackPlayer:
        return
    npcID = curNPC.GetNPCID()
    ipyData = IpyGameDataPY.GetIpyGameDataNotLog("TreasureNPC", npcID)
    if not ipyData:
        return
    attackCountDropWeightInfo = ipyData.GetAttackCountDropWeightInfo()
    attackDropWeightList = ipyData.GetAttackDropWeightList()
    attackDropWeightListEx = ipyData.GetAttackDropWeightListEx()
    dropCountEx = ipyData.GetDropCountEx()
    alchemyDiffLV = ipyData.GetAlchemyDiffLV()
    
    # 道具掉落个数
    dropGoodsCount = GameWorld.GetResultByRandomList(aiConfig[Def_DieDropGoodsCountRate])
    for i in range(dropGoodsCount):
        goodsID = GameWorld.GetResultByRandomList(aiConfig[Def_DropGoodsRate])
        dropItemIDList.append([goodsID, 1]) # 增加一个掉落道具
    mainItemWeightList = []
    if attackCountDropWeightInfo:
        maxCount = max(attackCountDropWeightInfo)
        attackCount = attackPlayer.NomalDictGetProperty(ChConfig.Def_PDict_NPCAttackCount % npcID) + 1
        if attackCount <= maxCount:
            if attackCount in attackCountDropWeightInfo:
                mainItemWeightList = attackCountDropWeightInfo[attackCount]
            NPCCommon.UpdateNPCAttackCount(attackPlayer, npcID, attackCount, maxCount)
    if not mainItemWeightList and attackDropWeightList:
        mainItemWeightList = ItemCommon.GetWeightItemListByAlchemyDiffLV(attackPlayer, attackDropWeightList, alchemyDiffLV)
        
    # 装备掉落个数
    dropEquipCount = GameWorld.GetResultByRandomList(aiConfig[Def_DieDropEquipCountRate])
    for i in range(dropEquipCount):
        equipID = __GetRadomDropEquipID(aiConfig[Def_DropEquipModelNum])
        dropItemIDList.append([equipID, 1]) # 增加一个掉落装备
    mainItemInfo = GameWorld.GetResultByWeightList(mainItemWeightList)
    
    # 掉落总个数
    dropCount = GameWorld.GetResultByRandomList(aiConfig[Def_DieDropCountRate])
    # npc超爆
    #npcControl.NPCSuperDropByItemIDExMoney(dropItemIDList, dropType, ownerID, dropCount)
    # 全服广播
    mapID = GameWorld.GetMap().GetMapID()
    if mapID not in []:
        notifyMarkDict = ReadChConfig.GetEvalChConfig("GoblinNotify")
        notifyMark = notifyMarkDict.get(curNPC.GetNPCID())
        if notifyMark:
            PlayerControl.WorldNotify(0, notifyMark, [GameWorld.GetMap().GetMapID()])
    if not mainItemInfo:
        notDropNotify = ipyData.GetNotDropNotify()
        if notDropNotify:
            PlayerControl.NotifyCode(attackPlayer, notDropNotify)
        return
    dropItemList = []
    if mainItemInfo:
        dropItemList.append(mainItemInfo)
    if attackDropWeightListEx and dropCountEx:
        weightListEx = ItemCommon.GetWeightItemListByAlchemyDiffLV(attackPlayer, attackDropWeightListEx, alchemyDiffLV)
        for _ in xrange(dropCountEx):
            itemInfo = GameWorld.GetResultByWeightList(weightListEx)
            if itemInfo:
                dropItemList.append(itemInfo)
    if not dropItemList:
        return
    dropPosX, dropPosY = curNPC.GetPosX(), curNPC.GetPosY()
    ChItem.DoMapDropItem(attackPlayer, dropItemList, npcID, dropPosX, dropPosY, isOnlySelfSee=False)
    return
## 玩家击杀哥布林
#  @param curNPC
#  @param curPlayer
#  @param skill
#  @return
def OnAttackDieByPlayer(curNPC, curPlayer, skill):
    DataRecordPack.DR_KillNPC(curPlayer, "Goblin", curNPC.GetNPCID())
    return
## 获取对应哥布林配置
#  @param npcID
#  @return 配置信息
def __GetGoblinConfig(npcID):
    return ReadChConfig.GetEvalChConfig('Goblin_%s' % npcID)
## 获取随机掉落装备id
#  @param dropEquipModelNum 装备掉落规则模板编号
#  @return >0掉落装备id,返回0表示无法获取掉落装备id
def __GetRadomDropEquipID(dropEquipModelNum):
    global g_filterEquipDict
    dropEquipModel = ReadChConfig.GetEvalChConfig('GoblinDropEquip_%s' % dropEquipModelNum)
    filterItemList = g_filterEquipDict.get(dropEquipModelNum)
    # 如果没有,则加载
    if not filterItemList:
        GameWorld.DebugLog("加载哥布林掉落装备模板GoblinDropEquip_%s.txt" % dropEquipModelNum)
        itemTypeList = dropEquipModel[Def_EquipModel_EquipType]
        itemMinLV = dropEquipModel[Def_EquipModel_LVLimit][0]
        itemMaxLV = dropEquipModel[Def_EquipModel_LVLimit][1]
        dropIDList = dropEquipModel[Def_EquipModel_DropItemList]
        filterItemList = __FilterItemFromDB(itemTypeList, itemMinLV, itemMaxLV, dropIDList)
        g_filterEquipDict[dropEquipModelNum] = filterItemList
    # 随机是否卓越
    quality = GameWorld.GetResultByRandomList(dropEquipModel[Def_EquipModel_QualityRate])
    dropEquipIdList = filterItemList[quality]
    if not dropEquipIdList:
        GameWorld.ErrLog("__GetRadomDropEquipID() can not find filter equip," + \
                         "please check GoblinDropEquip_%s.txt!!!" % dropEquipModelNum)
        return 0
    return random.choice(dropEquipIdList)
## 从数据库中查找满足要求的物品ID
#  @param itemTypeList: 获得的物品类型列表
#  @param itemMinLV: 获得的物品最低等级
#  @param itemMaxLV: 获得的物品最高等级
#  @param dropIDList: NPC不掉落,但这里可掉落的物品id列表
#  @return 找到的物品ID列表:[[非卓越装id列表], [卓越装id列表]]
def __FilterItemFromDB(itemTypeList, itemMinLV, itemMaxLV, dropIDList):
    findItemIdList = [[], []] # [[非卓越装], [卓越装]]
    for itemType in itemTypeList:
        gameData = GameWorld.GetGameData()
        gameData.FilterItemByType(itemType) # 过滤物品类型
        for i in range(0, gameData.GetFilterItemCount()):
            curFindItem = gameData.GetFilterItem(i)
            itemID = curFindItem.GetItemTypeID()
            # NPC不掉落的,且不在特定掉落id列表里的不掉落
            if not curFindItem.GetCanNPCDrop() and itemID not in dropIDList:
                continue
            # 不在过滤等级内,跳过
            if curFindItem.GetLV() < itemMinLV or curFindItem.GetLV() > itemMaxLV:
                continue
            findItemIdList[1 if curFindItem.GetItemQuality() else 0].append(curFindItem.GetItemTypeID())
    GameWorld.DebugLog("哥布林掉落装备id列表=%s,卓越装备id列表=%s" % (str(findItemIdList[0]), str(findItemIdList[1])))
    return findItemIdList
## 隐藏NPC
def DoHideGoblin(curNPC):
    # 只在一线刷, 非一线设置该NPC隐身
    lineID = GameWorld.GetGameWorld().GetLineID()
    if lineID != 0:
        goblinNPCIDList = [30000,30001,30002,30003,30004,30005,30006,30007,30008,30009]
        npcID = curNPC.GetNPCID()
        if npcID in goblinNPCIDList and curNPC.GetVisible():
            curNPC.SetVisible(False)
            GameWorld.Log("非一线,隐藏该NPCID=%s!" % npcID)
            return True
    return False