ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py
@@ -397,7 +397,7 @@
    return attrDict
def GiveKillNPCDropPrize(curPlayer, mapID, npcCountDict, exp_rate=None, mailTypeKey=None, isMail=False, 
                         extraItemList=[], prizeMultiple=1, dropItemMapInfo=[], curGrade=0):
                         extraItemList=[], prizeMultiple=1, dropItemMapInfo=[], curGrade=0, isVirtualDrop=False):
    '''给玩家击杀NPC掉落奖励
    @param mapID: 击杀的NPC所在地图ID,注意次地图并不一定是玩家当前地图
    @param npcCountDict: 执行单次时所击杀的npc数量字典 {npcID:count, ...}
@@ -406,6 +406,9 @@
    @param isMail: 是否强制发送邮件,若是则不考虑背包空间,否的话只在背包空间不足时才发送邮件
    @param extraItemList: 固定附加物品列表,如果需执行多次,则此固定产出列表需在外层处理好,内层不做多次执行处理。[[itemID, itemCount, isAuctionItem], ...]
    @param prizeMultiple: 奖励倍值, 对所有奖励有效,等于击杀多次NPC,多倍附加物品
    @param dropItemMapInfo: 掉落地板信息 [dropPosX, dropPosY, 是否仅自己可见, 堆叠物品是否散开]
    @param curGrade: 评级
    @param isVirtualDrop: 是否给物品虚拟掉落表现
    '''
    if not exp_rate:
        exp_rate = PlayerControl.GetPlayerExpRate(curPlayer)
@@ -508,45 +511,15 @@
        
    ## 直接掉地板上
    if dropItemMapInfo:
        dropPosX, dropPosY, isOnlySelfSee = dropItemMapInfo[:3]
        dropPosX, dropPosY = dropItemMapInfo[:2]
        isOnlySelfSee = dropItemMapInfo[2] if len(dropItemMapInfo) > 2 else False # 是否仅自己可见
        isDropDisperse = dropItemMapInfo[3] if len(dropItemMapInfo) > 3 else False # 堆叠的物品是否散开掉落
        if isDropDisperse:
            dropItemList = []
            for itemInfo in prizeItemList:
                if isinstance(itemInfo, list):
                    itemID, itemCount, isAuctionItem = itemInfo
                    for _ in xrange(itemCount):
                        dropItemList.append([itemID, 1, isAuctionItem])
                else:
                    dropItemList.append(itemInfo)
        ## 虚拟掉落表现
        if isVirtualDrop:
            DoGiveItemByVirtualDrop(curPlayer, prizeItemList, npcID, dropPosX, dropPosY, isDropDisperse, mailTypeKey)
        else:
            dropItemList = prizeItemList
        index = 0
        playerID = curPlayer.GetPlayerID()
        gameMap = GameWorld.GetMap()
        for posX, posY in ChConfig.Def_DropItemAreaMatrix:
            resultX = dropPosX + posX
            resultY = dropPosY + posY
            DoMapDropPrizeItem(curPlayer, prizeItemList, npcID, dropPosX, dropPosY, isDropDisperse, isOnlySelfSee)
            
            if not gameMap.CanMove(resultX, resultY):
                #玩家不可移动这个点
                continue
            if index > len(dropItemList) - 1:
                break
            curItem = dropItemList[index]
            index += 1
            if isinstance(curItem, list):
                itemID, itemCount, isAuctionItem = curItem
                curItem = ItemControler.GetOutPutItemObj(itemID, itemCount, isAuctionItem)
            if not curItem:
                continue
            ChItem.AddMapDropItem(resultX, resultY, curItem, ownerInfo=[ChConfig.Def_NPCHurtTypePlayer, playerID],
                                  dropNPCID=npcID, isOnlySelfSee=isOnlySelfSee)
    ## 发邮件 或 背包空间不足
    elif isMail or needSpace > ItemCommon.GetItemPackSpace(curPlayer, IPY_GameWorld.rptItem, needSpace):
        mailItemList = []
@@ -602,6 +575,110 @@
        dropItemDataStr = ChItem.GetMapDropItemDataStr(curItem)
        SendVirtualItemDrop(curPlayer, itemID, resultX, resultY, dropItemDataStr)
        curItem.Clear()
    return
def DoMapDropPrizeItem(curPlayer, prizeItemList, npcID, dropPosX, dropPosY, isDropDisperse=True, isOnlySelfSee=True):
    ## 奖励物品真实掉落地图,先拆开分散再掉落
    if isDropDisperse:
        dropItemList = []
        for itemInfo in prizeItemList:
            if isinstance(itemInfo, list):
                itemID, itemCount, isAuctionItem = itemInfo
                for _ in xrange(itemCount):
                    dropItemList.append([itemID, 1, isAuctionItem])
            else:
                dropItemList.append(itemInfo)
    else:
        dropItemList = prizeItemList
    index = 0
    playerID = curPlayer.GetPlayerID()
    gameMap = GameWorld.GetMap()
    for posX, posY in ChConfig.Def_DropItemAreaMatrix:
        resultX = dropPosX + posX
        resultY = dropPosY + posY
        if not gameMap.CanMove(resultX, resultY):
            #玩家不可移动这个点
            continue
        if index > len(dropItemList) - 1:
            break
        curItem = dropItemList[index]
        index += 1
        if isinstance(curItem, list):
            itemID, itemCount, isAuctionItem = curItem
            curItem = ItemControler.GetOutPutItemObj(itemID, itemCount, isAuctionItem)
        if not curItem:
            continue
        ChItem.AddMapDropItem(resultX, resultY, curItem, ownerInfo=[ChConfig.Def_NPCHurtTypePlayer, playerID],
                              dropNPCID=npcID, isOnlySelfSee=isOnlySelfSee)
    return
def DoGiveItemByVirtualDrop(curPlayer, giveItemList, npcID, dropPosX=0, dropPosY=0, isDropDisperse=True, mailTypeKey="ItemNoPickUp"):
    ## 给物品并且做假掉落表现,直接先堆叠给物品,再拆开做虚假掉落表现
    mapID = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomSceneMapID)
    #lineID = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomSceneLineID)
    if not mapID:
        mapID = GameWorld.GetGameWorld().GetMapID()
    playerID = curPlayer.GetPlayerID()
    mailItemList = []
    virtualItemDropList = []
    itemControl = ItemControler.PlayerItemControler(curPlayer)
    for itemInfo in giveItemList:
        if isinstance(itemInfo, list):
            itemID, itemCount, isAuctionItem = itemInfo
            curItem = ItemControler.GetOutPutItemObj(itemID, itemCount, isAuctionItem, curPlayer=curPlayer)
            if not curItem:
                continue
        else:
            curItem = itemInfo
            itemID = curItem.GetItemTypeID()
            itemCount = curItem.GetCount()
            isAuctionItem = ItemControler.GetIsAuctionItem(curItem)
        jsonItem = ItemCommon.GetJsonItem(curItem)
        dropItemDataStr = ChItem.GetMapDropItemDataStr(curItem)
        equipInfo = [curItem.GetEquipPlace(), ItemCommon.GetItemClassLV(curItem), curItem.GetItemColor(),
                     curItem.GetItemQuality(), curItem.GetUserData()]
        packIndex = ChConfig.GetItemPackType(curItem.GetType())
        if not itemControl.PutInItem(packIndex, curItem, event=[ChConfig.ItemGive_Pickup, False, {"NPCID":npcID}]):
            mailItemList.append(jsonItem)
        if npcID:
            serverGroupID = PlayerControl.GetPlayerServerGroupID(curPlayer)
            SendGameServerGoodItemRecord(mapID, npcID, curPlayer.GetName(), playerID, itemID, equipInfo, serverGroupID)
        # 散开掉落
        if isDropDisperse:
            for _ in xrange(itemCount):
                virtualItemDropList.append([itemID, dropItemDataStr])
        else:
            virtualItemDropList.append([itemID, dropItemDataStr])
    if mailItemList:
        PlayerControl.SendMailByKey(mailTypeKey, [playerID], mailItemList, [mapID])
    gameMap = GameWorld.GetMap()
    index = 0
    for posX, posY in ChConfig.Def_DropItemAreaMatrix:
        if dropPosX or dropPosY:
            resultX = dropPosX + posX
            resultY = dropPosY + posY
            if not gameMap.CanMove(resultX, resultY):
                #玩家不可移动这个点
                continue
        else:
            resultX, resultY = 0, 0
        if index > len(virtualItemDropList) - 1:
            break
        itemID, dropItemDataStr = virtualItemDropList[index]
        index += 1
        SendVirtualItemDrop(curPlayer, itemID, resultX, resultY, dropItemDataStr)
    return
################################### NPC掉落 ###################################
@@ -1959,6 +2036,17 @@
    ''' 召唤私有专属木桩怪
    '''
    
    if not curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomScene):
        GameWorld.DebugLog("玩家当前不是在自定义场景中,不允许招木桩!")
        return
    mapID = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomSceneMapID)
    lineID = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomSceneLineID)
    if mapID:
        if not FBLogic.OnCanSummonPriWoodPile(curPlayer, mapID, lineID, npcID, count):
            GameWorld.ErrLog("无法召唤木桩怪!mapID=%s,lineID=%s,npcID=%s,count=%s" % (mapID, lineID, npcID, count))
            return
    maxCount = 10
    nowCount = 0
    # 只允许存在一个私有木桩
@@ -1999,6 +2087,37 @@
        summonPos = GameMap.GetEmptyPlaceInArea(curPlayer.GetPosX(), curPlayer.GetPosY(), 3)
        summonNPC.Reborn(summonPos.GetPosX(), summonPos.GetPosY())
        
        if not curPlayer.GetSight():
            summonNPCAppear = ChNetSendPack.tagPlayerSummonNPCAppear()
            summonNPCAppear.Clear()
            summonNPCAppear.PlayerID = curPlayer.GetPlayerID()
            summonNPCAppear.ObjID = summonNPC.GetID()
            summonNPCAppear.NPCID = summonNPC.GetNPCID()
            summonNPCAppear.PosX = summonNPC.GetPosX()
            summonNPCAppear.PosY = summonNPC.GetPosY()
            summonNPCAppear.HP = summonNPC.GetHP()
            summonNPCAppear.HPEx = summonNPC.GetHPEx()
            summonNPCAppear.MaxHP = summonNPC.GetMaxHP()
            summonNPCAppear.MaxHPEx = summonNPC.GetMaxHPEx()
            summonNPCAppear.Speed = summonNPC.GetSpeed()
            summonNPCAppear.LV = GetNPCLV(summonNPC)
            summonNPCAppear.OwnerName = curPlayer.GetPlayerName()
            summonNPCAppear.OwnerNameLen = len(summonNPCAppear.OwnerName)
            NetPackCommon.SendFakePack(curPlayer, summonNPCAppear)
    return
def ClearPriWoodPile(curPlayer):
    ## 清除私有木桩
    indexList = range(curPlayer.GetSummonCount())
    for index in indexList[::-1]:
        summonNPC = curPlayer.GetSummonNPCAt(index)
        if not summonNPC:
            continue
        npcType = summonNPC.GetType()
        if npcType not in [ChConfig.ntPriWoodPilePVE, ChConfig.ntPriWoodPilePVP]:
            continue
        SetDeadEx(summonNPC)
    return
## 设置npc死亡及自身处理(请不要将游戏逻辑加在此函数中)
@@ -2019,8 +2138,10 @@
    if curNPC.GetGameObjType() == IPY_GameWorld.gotNPC:
        FBLogic.DoFB_NPCDead(curNPC)
    
    ownerPlayer = None
    summonPlayerID = curNPC.GetDictByKey(ChConfig.Def_NPC_Dict_SummonMapNPCPlayerID)
    if summonPlayerID > 0:
        ownerPlayer = GameWorld.GetObj(summonPlayerID, IPY_GameWorld.gotPlayer)
        curNPC.SetDict(ChConfig.Def_NPC_Dict_SummonMapNPCPlayerID, 0)
    
    # 暗金boss
@@ -2047,6 +2168,14 @@
        lineRobotJobDict = PyGameData.g_fbRobotJobDict.get(lineID, {})
        lineRobotJobDict.pop(curNPC.GetID(), 0)
        PyGameData.g_fbRobotJobDict[lineID] = lineRobotJobDict
    if ownerPlayer and not ownerPlayer.GetSight():
        npcDie = ChNetSendPack.tagNPCDie()
        npcDie.ObjID = curNPC.GetID()
        npcDie.Reason = curNPC.GetDictByKey(ChConfig.Def_NPCDead_Reason)
        npcDie.KillerType = curNPC.GetDictByKey(ChConfig.Def_NPCDead_KillerType)
        npcDie.KillerID = curNPC.GetDictByKey(ChConfig.Def_NPCDead_KillerID)
        NetPackCommon.SendFakePack(ownerPlayer, npcDie)
        
    # C++设置npc死亡
    curNPC.SetDead(curNPC.GetDictByKey(ChConfig.Def_NPCDead_Reason),
@@ -3344,7 +3473,8 @@
        
        #得到范围内随机一个点, 普通小怪走法
        PosMap = curNPC.GetRefreshPosAt(curNPC.GetCurRefreshPointIndex())
        if not PosMap:
            return
        moveArea = min(curNPC.GetMoveArea(), 2)
        posX = curNPC.GetPosX()
@@ -4152,6 +4282,9 @@
    #  @return 返回值无意义
    def __NPCDropItem(self, dropPlayer, hurtType, hurtID, ownerPlayerList=[]):
        if not dropPlayer:
            return
        if dropPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomScene):
            GameWorld.DebugLog("前端自定义场景中,不掉落物品!")
            return
        curNPC = self.__Instance
        npcID = curNPC.GetNPCID()
@@ -5729,6 +5862,15 @@
    if not curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomScene):
        GameWorld.DebugLog("非自定义场景中,无法获取定义采集奖励!")
        return
    mapID = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomSceneMapID)
    lineID = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomSceneLineID)
    GameWorld.DebugLog("前端场景采集: mapID=%s,lineID=%s,npcID=%s" % (mapID, lineID, npcID))
    if mapID:
        #if FBCommon.GetCustomSceneState(curPlayer, mapID, lineID) != ChConfig.CustomSceneState_Fight:
        #    return
        FBLogic.OnCustomSceneCollectOK(curPlayer, mapID, lineID, npcID)
    collectNPCIpyData = IpyGameDataPY.GetIpyGameData("CollectNPC", npcID)
    if collectNPCIpyData:
        DoGiveCollectNPCAward(curPlayer, npcID, collectNPCIpyData)
@@ -5764,11 +5906,20 @@
    collectAwardCfg = collectNPCIpyData.GetCollectAward()
    collectAppointAwardCfg = collectNPCIpyData.GetCollectAppointAward()
    if collectAppointAwardCfg:
        collTotalTime = min(curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CollNpcIDCollTimeTotal % npcID) + 1, ChConfig.Def_UpperLimit_DWord)
        if collTotalTime in collectAppointAwardCfg:
            awardItemList.append(collectAppointAwardCfg[collTotalTime])
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_CollNpcIDCollTimeTotal % npcID, collTotalTime)
        GameWorld.DebugLog("    采集次数定制奖励: collTotalTime=%s,awardItemList=%s" % (collTotalTime, awardItemList))
        #缥缈草园的采集定制由缥缈寻访次数决定
        if collectNPCIpyData.GetCollectResetType() in [12, 14]:
            fairyDomainVisitCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FairyDomainVisitCnt)
            grasslandCollectAppointCfg = collectAppointAwardCfg.get(fairyDomainVisitCnt, {})
            curCollTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CollNpcIDCollTime % npcID)
            if curCollTime in grasslandCollectAppointCfg:
                awardItemList.append(grasslandCollectAppointCfg[curCollTime])
            GameWorld.DebugLog("    草园采集定制奖励: fairyDomainVisitCnt=%s,curCollTime=%s,awardItemList=%s" % (fairyDomainVisitCnt, curCollTime, awardItemList))
        else:
            collTotalTime = min(curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CollNpcIDCollTimeTotal % npcID) + 1, ChConfig.Def_UpperLimit_DWord)
            if collTotalTime in collectAppointAwardCfg:
                awardItemList.append(collectAppointAwardCfg[collTotalTime])
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_CollNpcIDCollTimeTotal % npcID, collTotalTime)
            GameWorld.DebugLog("    采集次数定制奖励: collTotalTime=%s,awardItemList=%s" % (collTotalTime, awardItemList))
        
    if not awardItemList:
        alchemyDiffLV = collectNPCIpyData.GetAlchemyDiffLV()
@@ -5806,6 +5957,7 @@
                awardPack.AwardItemList.append(awardItem)
            awardPack.Count = len(awardPack.AwardItemList)
            NetPackCommon.SendFakePack(curPlayer, awardPack)
        GameLogic_CrossGrassland.RecordGrasslandAward(curPlayer, awardItemList)
    else:
        GameWorld.ErrLog("采集物品没有奖励!npcID=%s" % (npcID))
        
@@ -5813,6 +5965,7 @@
    PlayerSuccess.DoAddSuccessProgress(curPlayer, ShareDefine.SuccType_Collect, collectCnt, [npcID])
    #SyncCollectionItemInfo(curPlayer, addExp, addMoney, addZhenQi, giveItemInfoList, npcID)
    
    GameLogic_CrossGrassland.DecCustomSceneNPCCount(curPlayer, npcID)
    if isMaxTime:
        GameLogic_CrossGrassland.DoCheckUpdateGrasslandEnd(curPlayer)
        
@@ -6218,4 +6371,74 @@
    return
def OnNPCAttacked(atkObj, curNPC, skill, tick):
    ## NPC被攻击
    __OnAttackedDropItem(atkObj, curNPC)
    return
## 每次被攻击掉落物品
#  @param atkObj 攻击发起者
#  @param curNPC 被攻击NPC
#  @return None
def __OnAttackedDropItem(atkObj, curNPC):
    attackPlayer, npcObjType = AttackCommon.GetAttackPlayer(atkObj)
    if npcObjType:
        return
    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()
    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]
            UpdateNPCAttackCount(attackPlayer, npcID, attackCount, maxCount)
    if mainItemWeightList:
        mainItemWeightList = ItemCommon.GetWeightItemListByAlchemyDiffLV(attackPlayer, mainItemWeightList, alchemyDiffLV)
    elif attackDropWeightList:
        mainItemWeightList = ItemCommon.GetWeightItemListByAlchemyDiffLV(attackPlayer, attackDropWeightList, alchemyDiffLV)
    mainItemInfo = GameWorld.GetResultByWeightList(mainItemWeightList)
    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
    mapID = attackPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomSceneMapID)
    if mapID:
        DoGiveItemByVirtualDrop(attackPlayer, dropItemList, npcID)
        GameLogic_CrossGrassland.RecordGrasslandAward(attackPlayer, dropItemList)
    else:
        dropPosX, dropPosY = curNPC.GetPosX(), curNPC.GetPosY()
        ChItem.DoMapDropItem(attackPlayer, dropItemList, npcID, dropPosX, dropPosY, isOnlySelfSee=False)
    return