hxp
2025-10-21 ec19547ca0985de3f1c4045411ee6c171204e535
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventSrc/FunctionNPCCommon.py
@@ -46,480 +46,98 @@
#---------------------------------------------------------------------
#"""Version = 2016-08-04 18:00"""
#---------------------------------------------------------------------
import ChPyNetSendPack
import NetPackCommon
import GameWorld
import IPY_GameWorld
import ItemControler
import ChConfig
import GameWorld
import NetPackCommon
import ItemControler
import ChPyNetSendPack
import PlayerControl
import ItemCommon
import ShareDefine
import PlayerFlashSale
#import EventSrc
import ChItem
import IpyGameDataPY
import PlayerRune
import GameFuncComm
import PlayerSpringSale
import PyGameData
import ItemCommon
import ObjPool
import random
import math
import time
# 重置类型
ResetType_Day = 1
ResetType_Week = 2
g_mysticalShopDict = {} #神秘商店{等级范围:[等级段,{金钱类型:库}]}
#---------------------------------------------------------------------
##开始交易
# @param curPlayer 玩家实例
# @param tick 时间戳
# @return 返回值真, 逻辑运行成功
# @remarks 开始交易
def StartTrade(curPlayer, tick):
# 解锁类型
UnlockType_FamilyLV = 1 # 公会等级
UnlockType_RandRefresh = 2 # 随机刷新解锁
    curActionObj = curPlayer.GetActionObj()
    if curActionObj == None:
        return
    if curActionObj.GetGameObjType() != IPY_GameWorld.gotNPC:
        return
    curActionNPC = GameWorld.GetNPCManager().GetNPCByIndex(curActionObj.GetIndex())
    curActionNPCID = curActionNPC.GetNPCID()
    # 设置当前商店的npcid
    curPlayer.SetDict(ChConfig.Def_PlayerKey_TradeTagNPC, curActionNPCID)
    #设定为禁止整理背包
    curPlayer.SetForbiddenResetItem(1)
    curPlayer.BeginSpecialEvent(ShareDefine.TYPE_Event_Shop)
    return True
# 部分商店类型
ShopType_HeroSoul = 3 # 将魂
#------------------------------------------------------------------------------
## 获取远程商店的npc
# @param curPlayer 玩家实例
# @return 远程商店的npc
def GetDirectNpcID():
    return 0
RefreshShopTypeList = [ShopType_HeroSoul]
#---------------------------------------------------------------------
##请求商店物品列表
# @param curPlayer 玩家实例
# @param tick 时间戳
# @return 返回值真, 逻辑运行成功
def QueryNPCShopItem(playerIndex, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(playerIndex)
    #时间间隔未到
    if tick - curPlayer.GetTickByType(ChConfig.TYPE_Player_Tick_QueryFuncData) \
       < ChConfig.TYPE_Player_Tick_Time[ChConfig.TYPE_Player_Tick_QueryFuncData]:
        return
    curPlayer.SetTickByType(ChConfig.TYPE_Player_Tick_QueryFuncData, tick)
    #直接查询,存在该NPCID就发包
    tradeTagNPC = clientData.NPCShopID
    GameWorld.GetGameData().FilterShopItemByShopType(tradeTagNPC)
    shopItemCount = GameWorld.GetGameData().GetFilterShopItemCount()
    if shopItemCount <= 0:
        return
#    # 商店npcid与当前对话npc对应,0为远程商店
#    tradeTagNPC = clientData.NPCShopID
#    if tradeTagNPC != 0 and not CheckTradeTagNPC(curPlayer, tradeTagNPC):
#        return
    # 发送商品今日已购买次数
    #SyncShopItemTodayBuyCount(curPlayer)
    # 发送商店物品列表
    curPlayer.BeginShopEx(tradeTagNPC)
def DoShopOpen(curPlayer):
    for shopType in RefreshShopTypeList:
        DoRandRefreshShopItem(curPlayer, shopType, sysRefresh=True)
    return
##同步商店NPC物品今日购买次数
# @param curPlayer 玩家实例
# @param npcID
# @param itemIndex -1时同步该NPC所有物品
# @return
def SyncShopItemTodayBuyCount(curPlayer, itemIndexList=[], isReset=False):
    dayBuyCntInfo = ChPyNetSendPack.tagMCShopItemDayBuyCntInfo()
    dayBuyCntInfo.DayBuyCntList = []
    if itemIndexList:
        for itemIndex in itemIndexList:
            __AppendShopItemDayBuyCntInfo(curPlayer, itemIndex, dayBuyCntInfo.DayBuyCntList, isReset)
    else:
        ipyDataMgr = IpyGameDataPY.IPY_Data()
        for i in xrange(ipyDataMgr.GetStoreCount()):
            shopItem = ipyDataMgr.GetStoreByIndex(i)
            if not shopItem.GetLimitCnt():
                continue
            dayBuyCntKey = ChConfig.Def_PDict_ShopItemDayBuyCnt % shopItem.GetID()
            curDayBuyCnt = curPlayer.NomalDictGetProperty(dayBuyCntKey)
            if curDayBuyCnt <= 0:
                continue
            __AppendShopItemDayBuyCntInfo(curPlayer, shopItem.GetID(), dayBuyCntInfo.DayBuyCntList, isReset)
    dayBuyCntInfo.Count = len(dayBuyCntInfo.DayBuyCntList)
    NetPackCommon.SendFakePack(curPlayer, dayBuyCntInfo)
def ShopItemOnLogin(curPlayer):
    SyncShopItemBuyCntInfo(curPlayer)
    for shopType in RefreshShopTypeList:
        SyncShopRefreshItemInfo(curPlayer, shopType)
    return
##增加商店物品今日购买次数信息
# @param curPlayer 玩家实例
# @param npcID
# @param itemIndex
# @return
def __AppendShopItemDayBuyCntInfo(curPlayer, itemIndex, dayBuyCntList, isReset):
    itemDayBuyCnt = ChPyNetSendPack.tagMCShopItemDayBuyCnt()
    itemDayBuyCnt.ItemIndex = itemIndex
    dayBuyCntKey = ChConfig.Def_PDict_ShopItemDayBuyCnt % itemIndex
    curDayBuyCnt = curPlayer.NomalDictGetProperty(dayBuyCntKey)
    itemDayBuyCnt.BuyCnt = curDayBuyCnt
    itemDayBuyCnt.IsReset = int(isReset)
    dayBuyCntList.append(itemDayBuyCnt)
    return
## 登录
def ShopItemOnLogin(curPlayer):
    SyncMysticalLimitShopInfo(curPlayer)
    SyncShopItemTodayBuyCount(curPlayer)
    if not curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_MysticalShopGoods % 0):
        __DoMysticalShopRefresh(curPlayer, True, GameWorld.GetGameWorld().GetTick())
    SyncMysticalShopInfo(curPlayer)
    return
##商店物品OnDay
# @param curPlayer 玩家实例
# @return
def ShopItemOnDay(curPlayer, onEventType):
    if onEventType == ShareDefine.Def_OnEventType:
        OSSaleOpenMail(curPlayer)
        refreshType = [3]
        #神秘商店刷新次数重置
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_MysticalShopRefreshCnt, 0)
        SyncMysticalShopInfo(curPlayer)
def ShopItemOnDay(curPlayer):
    for shopType in RefreshShopTypeList:
        if not curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ShopRefreshCnt % shopType):
            continue
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ShopRefreshCnt % shopType, 0)
        SyncShopRefreshItemInfo(curPlayer, shopType)
        
    elif onEventType == ShareDefine.Def_OnEventTypeEx:
        refreshType = [4]
        openServerDay = GameWorld.GetGameWorld().GetGameWorldDictByKey(ShareDefine.Def_Notify_WorldKey_ServerDay)
        isMixServer = GameWorld.GetGameWorld().GetGameWorldDictByKey(ShareDefine.Def_Notify_WorldKey_IsMixServer)
        if isMixServer:
            mixServerDay = GameWorld.GetGameWorld().GetGameWorldDictByKey(ShareDefine.Def_Notify_WorldKey_MixServerDay)
            if mixServerDay % 3 == 0:
                refreshType.append(7)
        elif openServerDay % 3 == 0:
            refreshType.append(7)
    else:
        return
    ResetShopItemBuyCount(curPlayer, refreshType)
    ResetShopItemBuyCount(curPlayer, [ResetType_Day])
    return
##商店物品OnWeek
# @param curPlayer 玩家实例
# @return
def ShopItemOnWeek(curPlayer, onEventType):
    if onEventType == ShareDefine.Def_OnEventType:
        refreshType = [1]
    elif onEventType == ShareDefine.Def_OnEventTypeEx:
        refreshType = [2]
    else:
        return
    ResetShopItemBuyCount(curPlayer, refreshType)
    return
##商店物品OnMonth
# @param curPlayer 玩家实例
# @return
def ShopItemOnMonth(curPlayer, onEventType):
    if onEventType == ShareDefine.Def_OnEventType:
        refreshType = 5
    elif onEventType == ShareDefine.Def_OnEventTypeEx:
        refreshType = 6
    else:
        return
    ResetShopItemBuyCount(curPlayer, [refreshType])
    return
def ShopItemOnCrossPKSeasonChange(curPlayer):
    ## 按跨服PK赛季重置
    refreshType = 8
    ResetShopItemBuyCount(curPlayer, [refreshType])
def ShopItemOnWeek(curPlayer):
    ResetShopItemBuyCount(curPlayer, [ResetType_Week])
    return
def ResetShopItemBuyCount(curPlayer, resetTypeList):
    #@param resetTypeList: 需要重置的类型列表
    #重置商店物品购买次数  1:周一0点刷新    2:周一5点刷新    3:每日0点刷新    4:每日5点刷新    5每月0点    6每月5点   7每3天5点  8每赛季
    if not resetTypeList:
        # 暂定必须指定类型列表,防止终身限购的误被重置
        return
    syncIndexList = []
    syncIDList = []
    ipyDataMgr = IpyGameDataPY.IPY_Data()
    for i in xrange(ipyDataMgr.GetStoreCount()):
        shopItem = ipyDataMgr.GetStoreByIndex(i)
        if not shopItem.GetLimitCnt():
            continue
        if shopItem.GetRefreshLimit():
        if shopItem.GetResetType() not in resetTypeList:
            continue
        if shopItem.GetRefreshType() not in resetTypeList:
        shopID = shopItem.GetID()
        curBuyCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ShopBuyCnt % shopID)
        if curBuyCnt <= 0:
            continue
        dayBuyCntKey = ChConfig.Def_PDict_ShopItemDayBuyCnt % shopItem.GetID()
        curDayBuyCnt = curPlayer.NomalDictGetProperty(dayBuyCntKey)
        if curDayBuyCnt <= 0:
            continue
        PlayerControl.NomalDictSetProperty(curPlayer, dayBuyCntKey, 0)
        syncIndexList.append(shopItem.GetID())
    if syncIndexList:
        SyncShopItemTodayBuyCount(curPlayer, syncIndexList, True)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ShopBuyCnt % shopID, 0)
        syncIDList.append(shopID)
    if syncIDList:
        SyncShopItemBuyCntInfo(curPlayer, syncIDList)
    return
def ResetShopItemBuyCountByShopType(curPlayer, shopTypeList):
    ##根据商店类型重置商店限购物品次数
    if not shopTypeList:
        return
    syncIndexList = []
    ipyDataMgr = IpyGameDataPY.IPY_Data()
    for i in xrange(ipyDataMgr.GetStoreCount()):
        shopItem = ipyDataMgr.GetStoreByIndex(i)
        if not shopItem.GetLimitCnt():
    syncIDList = []
    for shopType in shopTypeList:
        ipyDataList = IpyGameDataPY.GetIpyGameDataByCondition("Store", {"ShopType":shopType}, True, True)
        if not ipyDataList:
            continue
        if shopItem.GetRefreshLimit():
            continue
        if shopItem.GetShopType() not in shopTypeList:
            continue
        dayBuyCntKey = ChConfig.Def_PDict_ShopItemDayBuyCnt % shopItem.GetID()
        curDayBuyCnt = curPlayer.NomalDictGetProperty(dayBuyCntKey)
        if curDayBuyCnt <= 0:
            continue
        PlayerControl.NomalDictSetProperty(curPlayer, dayBuyCntKey, 0)
        syncIndexList.append(shopItem.GetID())
    if syncIndexList:
        SyncShopItemTodayBuyCount(curPlayer, syncIndexList, True)
    return
def MysticalLimitShopOpen(curPlayer, befLV, aftLV):
    ##神秘限购开启
    ipyDataList = IpyGameDataPY.GetIpyGameDataByCondition('Store', {'ShopType':16}, True)
    if not ipyDataList:
        return
    curTime = int(time.time())
    syncGoodsList = []
    for ipyData in ipyDataList:
        limitLV = ipyData.GetLimitLV()
        if befLV < limitLV and aftLV >= limitLV:
            goodsID = ipyData.GetID()
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ShopItemStartTime % goodsID, curTime)
            syncGoodsList.append(goodsID)
            GameWorld.DebugLog('神秘限购商品%s 开卖'%goodsID, curPlayer.GetID())
    if syncGoodsList:
        SyncMysticalLimitShopInfo(curPlayer)
    return
def SyncMysticalLimitShopInfo(curPlayer):
    ##神秘限购通知
    packData = ChPyNetSendPack.tagMCMysticalShopTimeInfo()
    packData.ShopTimeList = []
    ipyDataList = IpyGameDataPY.GetIpyGameDataByCondition('Store', {'ShopType':16}, True)
    curTime = int(time.time())
    for ipyData in ipyDataList:
        goodsID = ipyData.GetID()
        startTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ShopItemStartTime % goodsID)
        if not startTime:
            continue
        if curTime - startTime >= ipyData.GetLimitValue():
            #超时的重置
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ShopItemStartTime % goodsID, 0)
        else:
            goodsTime = ChPyNetSendPack.tagMCMysticalShopTime()
            goodsTime.GoodsID = goodsID
            goodsTime.StartTime = startTime
            packData.ShopTimeList.append(goodsTime)
    if not packData.ShopTimeList:
        return
    packData.Count = len(packData.ShopTimeList)
    NetPackCommon.SendFakePack(curPlayer, packData)
    return
def CheckMysticalShopRefresh(curPlayer, tick):
    ##神秘商店刷新
    createRoleTime = curPlayer.GetCreateRoleTime()
    if not createRoleTime:
        return
    diffTime = GameWorld.GetCurrentTime() - GameWorld.GetDateTimeByStr(createRoleTime, ChConfig.TYPE_Time_Format)
    pastSeconds = diffTime.days*24*60*60 + diffTime.seconds
    refreshTime = IpyGameDataPY.GetFuncCfg('MysteryShopRefresh', 4)
    if refreshTime and pastSeconds % refreshTime == 0:
        __DoMysticalShopRefresh(curPlayer, True, tick)
    return
#// A2 32 神秘商店刷新 #tagCMRefreshMysticalShop
#struct    tagCMRefreshMysticalShop
#{
#    tagHead        Head;
#};
def OnMysticalShopRefresh(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    __DoMysticalShopRefresh(curPlayer, False, tick)
    return
def __DoMysticalShopRefresh(curPlayer, isFree, tick):
    global g_mysticalShopDict #{等级范围:[等级段,{金钱类型:库}]}
    refreshTime = IpyGameDataPY.GetFuncCfg('MysteryShopRefresh', 4)
    if not refreshTime:
        return
    lastTime = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_MysticalShopLastTime)
    if lastTime and tick - lastTime < 1000:
        #GameWorld.DebugLog('神秘商店刷新,过于频繁!')
        return
    curPlayer.SetDict(ChConfig.Def_PlayerKey_MysticalShopLastTime, tick)
    if not g_mysticalShopDict:
        ipyMgr= IpyGameDataPY.IPY_Data()
        for i in xrange(ipyMgr.GetMysteryShopCount()):
            ipyData = ipyMgr.GetMysteryShopByIndex(i)
            lvRange = ipyData.GetLVRange()
            goodsID = ipyData.GetGoodsID()
            goodsIpyData = IpyGameDataPY.GetIpyGameData('Store', goodsID)
            if not goodsIpyData:
        for ipyData in ipyDataList:
            if not ipyData.GetLimitCnt():
                continue
            moneyType = goodsIpyData.GetMoneyType()
            weight = goodsIpyData.GetLimitValue()
            lvkey = tuple(lvRange)
            if lvkey not in g_mysticalShopDict:
                g_mysticalShopDict[lvkey] = [lvkey[0], {}]
                weightDict = {}
            if moneyType not in g_mysticalShopDict[lvkey][1]:
                g_mysticalShopDict[lvkey][1][moneyType] = []
            weightDict[moneyType] = weightDict.get(moneyType, 0) + weight
            g_mysticalShopDict[lvkey][1][moneyType].append([weightDict[moneyType], goodsID])
    if not g_mysticalShopDict:
        return
    playerLV = curPlayer.GetLV()
    curLVDan, shopDict = GameWorld.GetDictValueByRangeKey(g_mysticalShopDict, playerLV)
    if not shopDict:
        return
    maxCnt = IpyGameDataPY.GetFuncCfg('MysteryShopGoods', 1)
    goldGoodsCnt =GameWorld.GetResultByRandomList(IpyGameDataPY.GetFuncEvalCfg('MysteryShopGoods', 2))
    if not goldGoodsCnt:
        return
    specialGoodsID = 0 #必出的商品ID
    if not isFree:
        #优先道具,再仙玉
        itemPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptItem)
        costItemID = IpyGameDataPY.GetFuncCfg('MysteryShopRefresh', 1)
        costItemCntDict = IpyGameDataPY.GetFuncEvalCfg('MysteryShopRefresh', 2)
        curRefreshCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_MysticalShopRefreshCnt)
        cntList = [int(cnt) for cnt in costItemCntDict.keys()]
        cntList.sort()
        costItemCnt = costItemCntDict[str(cntList[-1])]
        for cnt in cntList:
            if curRefreshCnt < cnt:
                costItemCnt = costItemCntDict[str(cnt)]
                break
        enough, indexList, hasBind, lackCnt = ItemCommon.GetItem_FromPack_ByID_ExEx(costItemID, itemPack, costItemCnt)
        costGold = 0
        if not enough:
            costGold = lackCnt * IpyGameDataPY.GetFuncCfg('MysteryShopRefresh', 3)
            if not PlayerControl.PayMoney(curPlayer, IPY_GameWorld.TYPE_Price_Gold_Money, costGold, ChConfig.Def_Cost_MysteryShopRefresh):
                return
        ItemCommon.ReduceItem(curPlayer, itemPack, indexList, costItemCnt, False, "MysteryShopRefresh")
        curLVRefreshData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_MysticalShopLVRefreshCnt)
        curLVRefreshCnt, lvDan = curLVRefreshData / 10000, curLVRefreshData % 10000
        updLVRefreshCnt = 1 if curLVDan != lvDan else curLVRefreshCnt + 1 #等级段变更,重置该等级段的刷新次数
        updLVRefreshData = min(updLVRefreshCnt * 10000+curLVDan, ChConfig.Def_UpperLimit_DWord)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_MysticalShopLVRefreshCnt, updLVRefreshData)
        specialRefreshCfg = IpyGameDataPY.GetFuncEvalCfg('MysteryShopRefresh', 5)
        if curLVDan in specialRefreshCfg and updLVRefreshCnt == specialRefreshCfg[curLVDan][0]:
            specialGoodsID = specialRefreshCfg[curLVDan][1]
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_MysticalShopRefreshCnt, curRefreshCnt+1)
    goldGoodsCnt = min(goldGoodsCnt, maxCnt)
    sliverGoodsCnt = maxCnt - goldGoodsCnt
    goodsResultList = []
    if goldGoodsCnt:
        goodsResultList += GameWorld.GetResultByRandomListEx(shopDict.get(IPY_GameWorld.TYPE_Price_Gold_Money, []), goldGoodsCnt, [])
    if sliverGoodsCnt:
        goodsResultList += GameWorld.GetResultByRandomListEx(shopDict.get(IPY_GameWorld.TYPE_Price_Silver_Money, []), sliverGoodsCnt, [])
    if specialGoodsID and specialGoodsID not in goodsResultList:
        goodsResultList[0] = specialGoodsID
        GameWorld.DebugLog('神秘商店刷新特殊规则,等级段:%s,updLVRefreshCnt=%s,specialGoodsID=%s'%(curLVDan, updLVRefreshCnt, specialGoodsID))
    GameWorld.DebugLog('神秘商店刷新isFree=%s,goldGoodsCnt=%s,sliverGoodsCnt=%s,goodsResultList=%s'%(isFree, goldGoodsCnt, sliverGoodsCnt, goodsResultList))
    syncIndexList = []
    for i in xrange(maxCnt):
        goodsID = goodsResultList[i] if i < len(goodsResultList) else 0
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_MysticalShopGoods % i, goodsID)
        dayBuyCntKey = ChConfig.Def_PDict_ShopItemDayBuyCnt % goodsID
        curDayBuyCnt = curPlayer.NomalDictGetProperty(dayBuyCntKey)
        if curDayBuyCnt:
            PlayerControl.NomalDictSetProperty(curPlayer, dayBuyCntKey, 0)
            syncIndexList.append(goodsID)
    if syncIndexList:
        SyncShopItemTodayBuyCount(curPlayer, syncIndexList, True)
    #֪ͨ
    SyncMysticalShopInfo(curPlayer)
    return
def SyncMysticalShopInfo(curPlayer):
    ##神秘商店通知
    packData = ChPyNetSendPack.tagMCMysticalShopInfo()
    packData.RefreshCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_MysticalShopRefreshCnt)
    packData.GoodsList = []
    maxCnt = IpyGameDataPY.GetFuncCfg('MysteryShopGoods', 1)
    for i in xrange(maxCnt):
        goodsID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_MysticalShopGoods % i)
        goodsInfo = ChPyNetSendPack.tagMCMysticalShopGoods()
        goodsInfo.GoodsID = goodsID
        packData.GoodsList.append(goodsInfo)
    packData.Count = len(packData.GoodsList)
    NetPackCommon.SendFakePack(curPlayer, packData)
    return
## 回购物品
#  @param None
#  @return None
def BuyItemBack(curPlayer, clientPack, tick):
    index = clientPack.Index
    backPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptRecycle)
    if index >= backPack.GetCount():
        #假包退出
        return
    curItem = backPack.GetAt(index)
    if not curItem or curItem.IsEmpty():
        #没有物品退出
        return
    realPutCount = curItem.GetCount()
    itemControl = ItemControler.PlayerItemControler(curPlayer)
    if not itemControl.CanPutInItem(IPY_GameWorld.rptItem,
                                    curItem.GetItemTypeID(),
                                    realPutCount,
                                    curItem.GetIsBind()):
        #物品不能放入退出
        PlayerControl.NotifyCode(curPlayer, "GeRen_chenxin_676165", [IPY_GameWorld.rptItem])
        return
    itemPrice, priceType = __GetItemSellPrice(curPlayer, curItem)
    itemPrice = int(itemPrice) * realPutCount
    if not priceType or not itemPrice:
        return
    #付钱
    infoDict = {ChConfig.Def_Cost_Reason_SonKey:curItem.GetItemTypeID()}
    if not PlayerControl.PayMoney(curPlayer, priceType, itemPrice, ChConfig.Def_Cost_BuyItemBack, infoDict):
        return
    itemControl.PutInItem(IPY_GameWorld.rptItem, curItem, event=["BuyItemBack", False, {}])
    itemIndexs = str(curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_DelPackIndex))
    itemIndexs = itemIndexs.replace(str(index + 1), '')
    if itemIndexs == '':
        #没有物品保留 0
        itemIndexs = '0'
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_DelPackIndex, int(itemIndexs))
            shopID = ipyData.GetID()
            curBuyCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ShopBuyCnt % shopID)
            if curBuyCnt <= 0:
                continue
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ShopBuyCnt % shopID, 0)
            syncIDList.append(shopID)
    if syncIDList:
        SyncShopItemBuyCntInfo(curPlayer, syncIDList)
    return
def PayAutoBuyItem(curPlayer, lackItemDict, priceType, costType=ChConfig.Def_Cost_Unknown, infoDict={}, isCheck=False, shopItemIndexDict=None):
@@ -541,27 +159,26 @@
            return
        
        if shopItemIndexDict and itemID in shopItemIndexDict:
            itemIndex = shopItemIndexDict[itemID]
            ipyData = IpyGameDataPY.GetIpyGameData("Store", itemIndex)
            shopID = shopItemIndexDict[itemID]
            ipyData = IpyGameDataPY.GetIpyGameData("Store", shopID)
        else:
            ipyData = ItemCommon.GetShopItemPriceIpyData(itemID, priceType)
        if not ipyData:
            return
        
        itemIndex = ipyData.GetID()
        shopID = ipyData.GetID()
        shopType = ipyData.GetShopType()
        priceType = ipyData.GetMoneyType()
        itemMoney = ipyData.GetMoneyNum()
        limitCntList = ipyData.GetLimitCnt()
        if limitCntList:
            limitBuyCnt = limitCntList[0]
            curDayBuyCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ShopItemDayBuyCnt % itemIndex)
            canBuyCnt = max(0, limitBuyCnt - curDayBuyCnt)
        limitBuyCnt = ipyData.GetLimitCnt()
        if limitBuyCnt:
            curBuyCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ShopBuyCnt % shopID)
            canBuyCnt = max(0, limitBuyCnt - curBuyCnt)
            if canBuyCnt < lackCnt:
                GameWorld.Log("自动购买次数不足!shopType=%s,itemIndex=%s,itemID=%s,limitBuyCnt=%s,curDayBuyCnt=%s,canBuyCnt=%s < %s"
                              % (shopType, itemIndex, itemID, limitBuyCnt, curDayBuyCnt, canBuyCnt, lackCnt), curPlayer.GetPlayerID())
                GameWorld.Log("自动购买次数不足!shopType=%s,shopID=%s,itemID=%s,limitBuyCnt=%s,curBuyCnt=%s,canBuyCnt=%s < %s"
                              % (shopType, shopID, itemID, limitBuyCnt, curBuyCnt, canBuyCnt, lackCnt), curPlayer.GetPlayerID())
                return
            addLimitCountInfo[itemIndex] = lackCnt
            addLimitCountInfo[shopID] = lackCnt
            
        totalMoney += (lackCnt * itemMoney)
        
@@ -578,679 +195,254 @@
        return
    
    if addLimitCountInfo:
        syncIndexList = []
        for itemIndex, lackCnt in addLimitCountInfo.items():
            curDayBuyCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ShopItemDayBuyCnt % itemIndex)
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ShopItemDayBuyCnt % itemIndex, curDayBuyCnt + lackCnt)
            syncIndexList.append(itemIndex)
        SyncShopItemTodayBuyCount(curPlayer, syncIndexList)
        syncIDList = []
        for shopID, lackCnt in addLimitCountInfo.items():
            curBuyCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ShopBuyCnt % shopID)
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ShopBuyCnt % shopID, curBuyCnt + lackCnt)
            syncIDList.append(shopID)
        SyncShopItemBuyCntInfo(curPlayer, syncIDList)
        
    return True
#// A3 10 购买商城物品 #tagCMBuyItem
#// A3 10 购买商城物品 #tagCSBuyItem
#
#struct    tagCMBuyItem
#struct    tagCSBuyItem
#{
#    tagHead        Head;
#    WORD        BuyItemIndex;        //购买的物品索引
#    DWORD        BuyCount;        //购买数量
#    DWORD        ShopID;        //商品ID
#    DWORD        BuyCount;    //购买数量
#};
def PyBuyItem(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    itemIndex = clientData.BuyItemIndex
    shopID = clientData.ShopID
    buyCount = clientData.BuyCount
    OnBuyItem(curPlayer, itemIndex, buyCount)
    OnBuyItem(curPlayer, shopID, buyCount)
    return
##购买物品
# @param curPlayer 玩家实例
# @param tick 时间戳
# @return 返回值真, 逻辑运行成功
def BuyItem(curPlayer, tick):
    buyItemList = IPY_GameWorld.IPY_CBuyItemList()
    itemIndex = buyItemList.GetBuyItemIndex()
    clientBuyCount = buyItemList.GetBuyCount()
    OnBuyItem(curPlayer, itemIndex, clientBuyCount)
    return
def OnBuyItem(curPlayer, itemIndex, clientBuyCount):
    GameWorld.DebugLog("购买商城物品: itemIndex=%s,clientBuyCount=%s" % (itemIndex, clientBuyCount), curPlayer.GetPlayerID())
def OnBuyItem(curPlayer, shopID, clientBuyCount):
    GameWorld.DebugLog("购买商城物品: shopID=%s,clientBuyCount=%s" % (shopID, clientBuyCount))
    if GameWorld.IsCrossServer():
        return
    if itemIndex < 0 or clientBuyCount <= 0:
    if shopID <= 0 or clientBuyCount <= 0:
        return
    ipyData = IpyGameDataPY.GetIpyGameData("Store", itemIndex)
    ipyData = IpyGameDataPY.GetIpyGameData("Store", shopID)
    if not ipyData:
        return
    shopType = ipyData.GetShopType()
    operationActionShopType = ipyData.GetOperationActionShop()
    if operationActionShopType == 1:
        if not PlayerSpringSale.IsSpringSaleShopType(shopType):
            return
    elif operationActionShopType == 2:
        if not PlayerFlashSale.IsFlashSaleShopType(shopType):
            return
    # 物品信息
    limitLV = ipyData.GetLimitLV()
    if limitLV and curPlayer.GetLV() < limitLV:
        return
    LimitVIPLVList = ipyData.GetLimitVIPLV()
    LimitCntList = ipyData.GetLimitCnt()
    limitBuyCnt = 0
    if LimitVIPLVList or LimitCntList:
        if not LimitVIPLVList:
            LimitVIPLVList = [0]
        if not LimitCntList:
            LimitCntList = [0]
        if len(LimitVIPLVList) != len(LimitCntList):
            GameWorld.Log("    购买物品LimitVIPLV  LimitCnt 长度不同")
            return
        curVIPlv = curPlayer.GetVIPLv()
        limitBuyCnt = -1
        for i, viplv in enumerate(LimitVIPLVList):
            if curVIPlv < viplv:
                break
            limitBuyCnt = LimitCntList[i]
        if limitBuyCnt == -1:
            GameWorld.DebugLog("    vip%s才能购买"%viplv)
            return
    curDayBuyCnt = 0
    dayBuyCntKey = ChConfig.Def_PDict_ShopItemDayBuyCnt % itemIndex
    limitBuyCnt = ipyData.GetLimitCnt()
    if limitBuyCnt > 0:
        curDayBuyCnt = curPlayer.NomalDictGetProperty(dayBuyCntKey)
        canBuyCnt = max(0, limitBuyCnt - curDayBuyCnt)
        curBuyCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ShopBuyCnt % shopID)
        canBuyCnt = max(0, limitBuyCnt - curBuyCnt)
        if canBuyCnt <= 0:
            GameWorld.DebugLog("BuyShopItem 今日购买次数已满!shopType=%s,itemIndex=%s" % (shopType, itemIndex))
            GameWorld.DebugLog("商品限购次数已满 ! shopType=%s,shopID=%s,curBuyCnt=%s < %s" % (shopType, shopID, curBuyCnt, limitBuyCnt))
            return
        if clientBuyCount > canBuyCnt:
            GameWorld.DebugLog("BuyShopItem 修正购买次数!shopType=%s,itemIndex=%s,clientBuyCount=%s,canBuyCnt=%s"
                               % (shopType, itemIndex, clientBuyCount, canBuyCnt))
            clientBuyCount = canBuyCnt
    serverLimitCnt = ipyData.GetServerLimitCnt()
    if serverLimitCnt > 0:
        clientBuyCount = min(serverLimitCnt, clientBuyCount)
    itemID, itemCount, isBind = ipyData.GetItemID(), ipyData.GetItemCnt(), ipyData.GetIsBind()
    itemID, itemCount, isBind = ipyData.GetItemID(), ipyData.GetItemCnt(), 0
    itemListEx = ipyData.GetItemListEx()
    priceType, itemPrice = ipyData.GetMoneyType(), ipyData.GetMoneyNum()
    itemPrice *= clientBuyCount
    job = curPlayer.GetJob()
    jobItemList = ipyData.GetJobItem()
    totalItemList = []
    if itemID:
        jobItemID = GetShopJobItem(job, itemID, jobItemList)
        totalItemList.append([jobItemID, itemCount * clientBuyCount, isBind])
        totalItemList.append([itemID, itemCount * clientBuyCount, isBind])
    for itemIDEx, itemCountEx, isBindEx in itemListEx:
        jobItemID = GetShopJobItem(job, itemIDEx, jobItemList)
        totalItemList.append([jobItemID, itemCountEx * clientBuyCount, isBindEx])
    #允许价钱配置0,用来免费购买
        totalItemList.append([itemIDEx, itemCountEx * clientBuyCount, isBindEx])
    if not totalItemList:
        GameWorld.ErrLog("Store shop item error! shopType=%s,totalItemList=%s,itemPrice=%s" % (shopType, totalItemList, itemPrice))
        GameWorld.ErrLog("Store shop item error! shopType=%s,shopID=%s" % (shopType, shopID), curPlayer.GetPlayerID())
        return
    mainItemID = totalItemList[0][0]
    GameWorld.DebugLog("shopType=%s,shopID=%s,totalItemList=%s" % (shopType, shopID, totalItemList))
    # 检查是否解锁商品购买
    if not CheckBuyItemUnlock(curPlayer, shopType, shopID, mainItemID, ipyData):
        GameWorld.Log("Store shop item lock! shopID=%s,shopID=%s" % (shopType, shopID), curPlayer.GetPlayerID())
        return
    
    mainItemID = 0
    needPackSpaceDict = {}
    for i, itemInfo in enumerate(totalItemList):
        itemID = itemInfo[0]
        itemCnt = itemInfo[1]
        curItem = GameWorld.GetGameData().GetItemByTypeID(itemID)
        if not curItem:
            GameWorld.ErrLog("Store shop item error! shopType=%s,itemID=%s" % (shopType, itemID))
            return
        packType = ChConfig.GetItemPackType(curItem)
        needSpace = ItemControler.GetItemNeedPackCount(packType, curItem, itemCnt)
        needPackSpaceDict[packType] = needPackSpaceDict.get(packType, 0) + needSpace
        if i == 0:
            mainItemID = itemID
    if not mainItemID:
        return
    GameWorld.DebugLog("购买物品: shopType=%s,itemIndex=%s,clientBuyCount=%s,totalItemList=%s,mainItemID=%s,needPackSpaceDict=%s"
                       % (shopType, itemIndex, clientBuyCount, totalItemList, mainItemID, needPackSpaceDict), curPlayer.GetPlayerID())
    mailKey = ipyData.GetMailKey()
    isLackPack = False #是否背包不足
    for packType, needSpace in needPackSpaceDict.items():
        if needSpace > ItemCommon.GetItemPackSpace(curPlayer, packType, needSpace):
            isLackPack = True
            if mailKey:
                break
            else:
                curPlayer.ShopResult(itemIndex, IPY_GameWorld.tsrNoPlace)
                PlayerControl.NotifyCode(curPlayer, "GeRen_chenxin_676165", [packType])
                return
    sendMailKey = mailKey if isLackPack and mailKey else '' #背包不足且配置了mailKey的才发邮件
    # 购买限制条件扩展
    if CheckBuyItemLimitEx(curPlayer, shopType, itemIndex, mainItemID, ipyData.GetLimitValue(), clientBuyCount):
        GameWorld.Log("Store shop item buy limit! shopType=%s,itemIndex=%s,limitValue=%s"
                      % (shopType, itemIndex, ipyData.GetLimitValue()), curPlayer.GetPlayerID())
        return
    if not PlayerControl.HaveMoney(curPlayer, priceType, itemPrice):
        curPlayer.ShopResult(itemIndex, IPY_GameWorld.tsrNoMoney)
        return
    if serverLimitCnt > 0: #全服限购判断放到最后面,GameServer直接加次数
        if curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_StoreQueryState) == 1:
            #已经在查询中, 不重复查询
            GameWorld.DebugLog("全服购买次数已经在查询中, 不重复查询 itemIndex=%s" % itemIndex)
            return
        cmdStr = '%s' % ([itemIndex, serverLimitCnt, clientBuyCount, totalItemList, mainItemID, limitBuyCnt, sendMailKey])
        GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(curPlayer.GetID(), 0, 0,
                                        "GetStoreServerBuyCnt", cmdStr, len(cmdStr))
        #设置状态查询中
        curPlayer.SetDict(ChConfig.Def_PlayerKey_StoreQueryState, 1)
        return
    #-------------------------开始购买物品-----------------------------
    DoBuyStoreItem(curPlayer, itemIndex, clientBuyCount, totalItemList, mainItemID, limitBuyCnt, sendMailKey, ipyData)
    return
def DoBuyStoreItem(curPlayer, itemIndex, clientBuyCount, totalItemList, mainItemID, limitBuyCnt, sendMailKey, ipyData=None):
    if not ipyData:
        ipyData = IpyGameDataPY.GetIpyGameData("Store", itemIndex)
    priceType, itemPrice = ipyData.GetMoneyType(), ipyData.GetMoneyNum()
    itemPrice *= clientBuyCount
    shopType = ipyData.GetShopType()
    #if not PlayerControl.HaveMoney(curPlayer, priceType, itemPrice):
    #    return
    
    beforeMoney = PlayerControl.GetMoney(curPlayer, priceType)
    infoDict = {"TotalItemList":totalItemList, "ClientBuyCount":clientBuyCount, "ShopType":shopType,
                "ShopItemIndex":itemIndex, ChConfig.Def_Cost_Reason_SonKey:mainItemID}
    if not PlayerControl.PayMoney(curPlayer, priceType, itemPrice, ChConfig.Def_Cost_BuyStoreItem, infoDict, clientBuyCount):
        GameWorld.ErrLog("购买商城物品实际扣除货币时失败: itemIndex=%s,clientBuyCount=%s,priceType=%s,itemPrice=%s"
                         % (itemIndex, clientBuyCount, priceType, itemPrice))
                "ShopID":shopID, ChConfig.Def_Cost_Reason_SonKey:mainItemID}
    if priceType and itemPrice and not PlayerControl.PayMoney(curPlayer, priceType, itemPrice, ChConfig.Def_Cost_BuyStoreItem, infoDict, clientBuyCount):
        return
    afterMoney = PlayerControl.GetMoney(curPlayer, priceType)
    
    # 今日购买次数+1
    if limitBuyCnt > 0:
        dayBuyCntKey = ChConfig.Def_PDict_ShopItemDayBuyCnt % itemIndex
        curDayBuyCnt = curPlayer.NomalDictGetProperty(dayBuyCntKey)
        updDayBuyCnt = min(curDayBuyCnt + clientBuyCount, ChConfig.Def_UpperLimit_DWord)
        PlayerControl.NomalDictSetProperty(curPlayer, dayBuyCntKey, updDayBuyCnt)
        GameWorld.DebugLog("更新商城物品限购次数: itemIndex=%s,curDayBuyCnt=%s,clientBuyCount=%s,updDayBuyCnt=%s/%s"
                           % (itemIndex, curDayBuyCnt, clientBuyCount, updDayBuyCnt, limitBuyCnt), curPlayer.GetPlayerID())
        SyncShopItemTodayBuyCount(curPlayer, [itemIndex])
        updBuyCnt = min(curBuyCnt + clientBuyCount, ChConfig.Def_UpperLimit_DWord)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ShopBuyCnt % shopID, updBuyCnt)
        GameWorld.DebugLog("更新商城物品限购次数: shopID=%s,curBuyCnt=%s,clientBuyCount=%s,updBuyCnt=%s/%s"
                           % (shopID, curBuyCnt, clientBuyCount, updBuyCnt, limitBuyCnt))
        SyncShopItemBuyCntInfo(curPlayer, [shopID])
        
    dataDict = {"ShopType":shopType, "ShopItemIndex":itemIndex, "ClientBuyCount":clientBuyCount,
                "ItemPrice":itemPrice, "MoneyType":priceType,
                "BeforeMoney":beforeMoney, "AfterMoney":afterMoney}
    isForceEvent = priceType not in [IPY_GameWorld.TYPE_Price_Silver_Money]
    ItemControler.GivePlayerItemOrMail(curPlayer, totalItemList, event=["BuyItem", False, {}], notifyDataEx=shopID)
    return
def CheckBuyItemUnlock(curPlayer, shopType, shopID, mainItemID, ipyData):
    ## 检查是否解锁商品购买
    # @return: 是否已解锁购买
    
    for itemID, itemCount, isBind in totalItemList:
        curItemObj = ItemControler.GetOutPutItemObj(itemID, itemCount, False, curPlayer=curPlayer)
        if not curItemObj:
            continue
        userData = curItemObj.GetUserData()
        curItemObj.Clear()
        if not sendMailKey:
            if not ItemControler.GivePlayerItem(curPlayer, itemID, itemCount, isBind, event=[ChConfig.ItemGive_BuyItem, isForceEvent, dataDict]):
                GameWorld.ErrLog("购买商城物品放入背包失败! itemID=%s, itemCount=%s" % (itemID, itemCount), curPlayer.GetPlayerID())
        if ipyData.GetNotifyMark() and itemID == mainItemID:
            PlayerControl.WorldNotify(0, ipyData.GetNotifyMark(), [curPlayer.GetName(), mainItemID, userData])
        # 购买永久守护时删除限时守护
        if itemID == 4101:
            delGuardItem = ItemCommon.FindItemInPackByItemID(curPlayer, 4105, IPY_GameWorld.rptItem)
            if delGuardItem:
                ItemCommon.DelItem(curPlayer, delGuardItem, 1)
    if sendMailKey:
        PlayerControl.SendMailByKey(sendMailKey, [curPlayer.GetID()], totalItemList, detail=dataDict)
    else:
        ItemControler.NotifyGiveAwardInfo(curPlayer, totalItemList, ChConfig.ItemGive_BuyItem, dataEx=shopType)
    SyncShoppingResult(curPlayer, itemIndex, clientBuyCount)
    return
def GetShopJobItem(job, itemID, jobItemList):
    ## 获取商城物品对应的职业物品, 职业从1开始
    for jobItemIDList in jobItemList:
        if type(jobItemIDList) not in [list, tuple]:
            GameWorld.ErrLog("商城职业物品组格式错误!shopItemID=%s,jobItemList=%s" % (itemID, jobItemList))
            return itemID
        if itemID in jobItemIDList:
            if job <= 0 or job > len(jobItemIDList):
                GameWorld.ErrLog("商城职业物品配置错误,没有该职业对应物品ID!shopItemID=%s,job=%s" % (itemID, job))
                return itemID
            return jobItemIDList[job - 1]
    return itemID
def SyncShoppingResult(curPlayer, itemIndex, itemCnt):
    #通知购买结果
    resultInfo = ChPyNetSendPack.tagMCShoppingResult()
    resultInfo.ItemIndex = itemIndex
    resultInfo.ItemCnt = itemCnt
    NetPackCommon.SendFakePack(curPlayer, resultInfo)
    return
## 商店购买物品限制条件扩展
#  @param curPlayer 玩家实例
#  @return
def CheckBuyItemLimitEx(curPlayer, shopNPCID, itemIndex, curItemID, limitValue, clientBuyCount):
    if shopNPCID == 7: #符印商店
        return not PlayerRune.GetIsOpenByRuneID(curPlayer, curItemID)
    if shopNPCID in [8, 9, 10]: #仙盟商店
        if curPlayer.GetFamilyID() == 0:
            #无家族
            return True
    unlockType = ipyData.GetUnlockType()
    unlockValue = ipyData.GetUnlockValue()
    # 公会等级解锁
    if unlockType == UnlockType_FamilyLV:
        if not curPlayer.GetFamilyID():
            GameWorld.DebugLog("无公会无法购买! shopID=%s" % shopID)
            return
        curFamilyLV = curPlayer.GetFamilyLV()
        if curFamilyLV <= 0:
            curFamilyLV = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FamilyLV)
        return curFamilyLV < limitValue
    if shopNPCID in [15]: # 开服特惠商店
        #playerCreateRoleDays = GameWorld.GetCreateRoleDays(curPlayer)
        openServerDay = GameWorld.GetGameWorld().GetGameWorldDictByKey(ShareDefine.Def_Notify_WorldKey_ServerDay)+1
        return openServerDay != limitValue
    if shopNPCID == 16:#神秘限购
        startTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ShopItemStartTime % itemIndex)
        curTime = int(time.time())
        return not startTime or curTime - startTime >= limitValue
        if curFamilyLV < unlockValue:
            GameWorld.DebugLog("公会等级不足无法购买! shopID=%s,curFamilyLV=%s < %s" % (shopID, curFamilyLV, unlockValue))
            return
        
#
#    limitPlusDict = {shopItem.GetLimitPlusType1():shopItem.GetLimitPlusValue1(),
#                     shopItem.GetLimitPlusType2():shopItem.GetLimitPlusValue2(),
#                     shopItem.GetLimitPlusType3():shopItem.GetLimitPlusValue3(),
#                     }
#
#    for limitType, limitValue in limitPlusDict.items():
#        if limitType <= 0:
#            continue
#
#        # 优先判断NPC独有的
#        callFunc = GameWorld.GetExecFunc(EventSrc, "FunctionNPCShopBuyCheck.CheckByNPC_%s_%s"
#                                         % (shopNPCID, limitType))
#
#        if callFunc:
#            return callFunc(curPlayer, shopItem.GetItemID(), limitValue)
#
#        # 公共限制条件判断
#        callFunc = GameWorld.GetExecFunc(EventSrc, "FunctionNPCShopBuyCheck.CheckPublic_%s" % limitType)
#
#        if callFunc:
#            return callFunc(curPlayer, shopItem.GetItemID(), limitValue)
    # 默认不限制
    return False
def OSSaleOpenMail(curPlayer):
    #开服特惠开启邮件
    if not GameFuncComm.GetFuncCanUse(curPlayer, ShareDefine.GameFuncID_OSSail):
        return
    openServerDay = GameWorld.GetGameWorld().GetGameWorldDictByKey(ShareDefine.Def_Notify_WorldKey_ServerDay)+1
    if openServerDay not in IpyGameDataPY.GetFuncEvalCfg('OSSaleOpenMail'):
        return
    addItemList = IpyGameDataPY.GetFuncEvalCfg('OSSaleOpenMail', 2)
    PlayerControl.SendMailByKey('SellMail1', [curPlayer.GetID()], addItemList)
    return
## 商店npcid
#  @param curPlayer 玩家实例
#  @return
def GetCurTradeTagNPC(curPlayer):
    curActionNPCID = -1
    # 当前商店的npcid
    tradeTagNPC = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_TradeTagNPC)
    # 远程商店
    if not tradeTagNPC:
        return GetDirectNpcID()
    # 商店npcid与当前对话npc对应
    elif CheckTradeTagNPC(curPlayer, tradeTagNPC):
        return tradeTagNPC
    else:
        GameWorld.ErrLog("GetCurStoreItemList:trade tag NPC not match:%s"%tradeTagNPC,
                          curPlayer.GetPlayerID())
    return curActionNPCID
## 判断记录的商店npcid是否正确
#  @param curPlayer 玩家实例
#  @param tradeTagNPC
#  @return
def CheckTradeTagNPC(curPlayer, tradeTagNPC):
    curActionObj = curPlayer.GetActionObj()
    if not curActionObj:
        return False
    if curActionObj.GetGameObjType() != IPY_GameWorld.gotNPC:
        return False
    curActionNPC = GameWorld.GetNPCManager().GetNPCByIndex(curActionObj.GetIndex())
    if curActionNPC.GetNPCID() != tradeTagNPC:
        return False
    # 随机刷新解锁
    elif unlockType == UnlockType_RandRefresh:
        if not GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_ShopRandUnlock, shopID):
            GameWorld.DebugLog("该商品没有随机解锁无法购买! shopID=%s" % shopID)
            return
    return True
#--------------------出售物品
##出售物品
# @param curPlayer 玩家实例
# @param tick 时间戳
# @return 返回值真, 逻辑运行成功
# @remarks 出售物品
def SellItem(curPlayer, tick):
    #1检查事件发生的顺序
    sendData = IPY_GameWorld.IPY_CPlayerSellItem()
    packType = sendData.GetPackType()
    itemIndex = sendData.GetItemIndex()
    shopType = ChConfig.Def_ShopType_NpcShop
    return SellPackItem(curPlayer, packType, [itemIndex], shopType)
#// A3 11 批量出售物品 #tagCMSellItem
#// A2 32 刷新商店 #tagCSRefreshShop
#
#struct    tagCMSellItem
#struct    tagCSRefreshShop
#{
#    tagHead        Head;
#    BYTE        PackType;        //背包类型
#    BYTE        Count;            //索引数量
#    BYTE        ItemIndex[Count];        //物品索引
#    WORD        ShopType;
#};
def OnSellManyItem(index, clientData, tick):
def OnRefreshShop(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    packType = clientData.PackType
    ItemIndexList = clientData.ItemIndex
    if not ItemIndexList:
        return
    shopType = ChConfig.Def_ShopType_NpcShop
    isOk = SellPackItem(curPlayer, packType, ItemIndexList, shopType)
    if isOk:
        curPlayer.Sync_MakeItemAnswer(ShareDefine.Def_mitKeySell, 1)
    return
#---------------------------------------------------------------------
##出售指定背包物品
# @param curPlayer 玩家实例
# @param packType 背包类型
# @param itemIndex 物品索引
# @param shopType 商店类型,1NPC商店,2远程贩售
# @return 返回值真, 检查通过
# @remarks 出售指定背包物品
def SellPackItem(curPlayer, packType, itemIndexList, shopType):
    backPack = curPlayer.GetItemManager().GetPack(packType)
    if backPack == None:
        return False
    shopType = clientData.ShopType
    DoRandRefreshShopItem(curPlayer, shopType)
    return
def DoRandRefreshShopItem(curPlayer, shopType, randCnt=0, sysRefresh=False):
    ## 随机刷新商店物品,ID不重复
    # @param randCnt: 指定要随机解锁的个数
    
    totalSellPriceDict = {}
    hasSellOK = False
    notForceRecordEquipTypeList = range(ChConfig.Def_ItemType_retWeapon, ChConfig.Def_ItemType_retNeck)
    for itemIndex in itemIndexList:
        curItem = backPack.GetAt(itemIndex)
        if not __CheckItemSell(curPlayer, curItem):
    ipyDataList = IpyGameDataPY.GetIpyGameDataByCondition("Store", {"ShopType":shopType}, True, True)
    if not ipyDataList:
        return
    shopIDWeightDict = {}
    randWeightList = []
    for ipyData in ipyDataList:
        if ipyData.GetUnlockType() != UnlockType_RandRefresh:
            continue
        hasSellOK = True
        #当前物品数量
        curItemCount = curItem.GetCount()
        #itemName = curItem.GetName()
        #获得单个物品销售价格
        curItemSellPrice, curItemSellType = __GetItemSellPrice(curPlayer, curItem)
        #获得整组销售价格
        curAllItemSellPrice = int(curItemSellPrice) * curItemCount
        totalSellPriceDict[curItemSellType] = totalSellPriceDict.get(curItemSellType, 0) + curAllItemSellPrice
        #GameWorld.Log('curItemSellPrice=%s,curAllItemSellPrice=%s,curItemCount=%s'%(curItemSellPrice,curAllItemSellPrice,curItemCount))
        shopID = ipyData.GetID()
        randWeight = ipyData.GetUnlockValue()
        randWeightList.append([randWeight, shopID])
        shopIDWeightDict[shopID] = randWeight
        
        #===========================================================================================
        # #因日记记录过大, 添加记录筛选条件
        # if ItemControler.ItemNeedRecord(curItem):
        #    #详细记录装备信息
        #    DataRecordPack.DR_GetMoneyBySellPackItem(curPlayer, curItemSellType, curAllItemSellPrice)
        #===========================================================================================
    if not randWeightList:
        GameWorld.ErrLog("该商店没有可随机刷新解锁的商品! shopType=%s" % shopType)
        return
    refreshCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ShopRefreshCnt % shopType)
    moneyType, moneyValue = 0, 0
    if shopType == ShopType_HeroSoul:
        randCnt = IpyGameDataPY.GetFuncCfg("StoreHeroSoul", 1)
        freeCnt = IpyGameDataPY.GetFuncCfg("StoreHeroSoul", 3)
        if not sysRefresh and refreshCnt >= freeCnt:
            moneyType, moneyValue = IpyGameDataPY.GetFuncEvalCfg("StoreHeroSoul", 2)
    GameWorld.DebugLog("随机刷新商店商品: shopType=%s,randCnt=%s/%s,refreshCnt=%s,moneyType=%s,moneyValue=%s,sysRefresh=%s"
                       % (shopType, randCnt, len(randWeightList), refreshCnt, moneyType, moneyValue, sysRefresh))
    if randCnt <= 0:
        return
    if moneyType and moneyValue and not PlayerControl.PayMoney(curPlayer, moneyType, moneyValue, "RefreshShopItem"):
        return
    doCnt = randCnt * 10
    randShopIDList = []
    syncBuyCntIDList = []
    while randWeightList and len(randShopIDList) < randCnt and doCnt > 0:
        doCnt -= 1
        shopID = GameWorld.GetResultByWeightList(randWeightList)
        if not shopID:
            continue
        randShopIDList.append(shopID)
        randWeight = shopIDWeightDict.get(shopID, 0)
        if [randWeight, shopID] in randWeightList:
            randWeightList.remove([randWeight, shopID])
        GameWorld.SetDictValueByBit(curPlayer, ChConfig.Def_PDict_ShopRandUnlock, shopID, 1)
        if curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ShopBuyCnt % shopID):
            syncBuyCntIDList.append(shopID)
    GameWorld.DebugLog("随机刷新商品数: %s,%s" % (len(randShopIDList), randShopIDList))
    GameWorld.DebugLog("剩余锁定商品数: %s,%s" % (len(randWeightList), randWeightList))
    # 其他的设置未解锁
    for _, shopID in randWeightList:
        GameWorld.SetDictValueByBit(curPlayer, ChConfig.Def_PDict_ShopRandUnlock, shopID, 0)
    if not sysRefresh:
        refreshCnt += 1
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ShopRefreshCnt % shopType, refreshCnt)
        GameWorld.DebugLog("更新刷新商店次数=%s" % refreshCnt)
        
        isForceDR = curItem.GetType() not in notForceRecordEquipTypeList and not ItemControler.ItemNotNeedRecord(curItem)
        #物品消失
        ItemCommon.DelItem(curPlayer, curItem, curItemCount, False, ChConfig.ItemDel_SellPackItem, isForceDR=isForceDR)
        #PutItemInBuyBackPack(curPlayer, curItem)
    if not hasSellOK:
        return False
    for priceType, priceMoney in totalSellPriceDict.items():
        #玩家钱增加
        addDataDict = {}
        PlayerControl.GiveMoney(curPlayer, priceType, priceMoney, ChConfig.Def_GiveMoney_SellPackItem, addDataDict, False)
        PlayerControl.NotifyCode(curPlayer, "GetMoney01", [priceType, priceMoney])
    return True
## 售卖物品回购背包的处理, 放入空位不叠加(本项目没有回购,先屏蔽)
#  @param None
#  @return None
def PutItemInBuyBackPack(curPlayer, curItem):
    if syncBuyCntIDList:
        SyncShopItemBuyCntInfo(curPlayer, syncBuyCntIDList)
    SyncShopRefreshItemInfo(curPlayer, shopType, randShopIDList)
    return
    itemIndexs = str(curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_DelPackIndex))
    backPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptRecycle)
    emptyIndex = ItemCommon.GetEmptyIndexInPack(curPlayer, IPY_GameWorld.rptRecycle)
    if emptyIndex == -1:
        #清除旧物品
        emptyIndex = int(itemIndexs[0]) - 1
        item = backPack.GetAt(emptyIndex)
        item.Clear()
        itemIndexs = itemIndexs[1:]
def SyncShopRefreshItemInfo(curPlayer, shopType, syncIDList=[]):
    ##同步刷新解锁的商品信息
    if not syncIDList:
        syncIDList = []
        ipyDataList = IpyGameDataPY.GetIpyGameDataByCondition("Store", {"ShopType":shopType}, True, True)
        if not ipyDataList:
            return
        for ipyData in ipyDataList:
            shopID = ipyData.GetID()
            if not GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_ShopRandUnlock, shopID):
                continue
            syncIDList.append(shopID)
    if not syncIDList:
        return
    clientPack = ObjPool.GetPoolMgr().acquire(ChPyNetSendPack.tagSCShopRefreshItemInfo)
    clientPack.ShopType = shopType
    clientPack.RefreshCnt = min(curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ShopRefreshCnt % shopType), 250)
    clientPack.ShopIDList = syncIDList
    clientPack.Count = len(clientPack.ShopIDList)
    NetPackCommon.SendFakePack(curPlayer, clientPack)
    return
def SyncShopItemBuyCntInfo(curPlayer, syncIDList=[]):
    ##同步商品购买次数
    objPool = ObjPool.GetPoolMgr()
    buyCntList = []
    if syncIDList:
        for shopID in syncIDList:
            buyInfo = objPool.acquire(ChPyNetSendPack.tagSCShopItemBuyCnt)
            buyInfo.ShopID = shopID
            buyInfo.BuyCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ShopBuyCnt % shopID)
            buyCntList.append(buyInfo)
    else:
        # 清空空格位防范, 防止异常情况物品消失而没有重置标记位导致数值越界
        itemIndexs = itemIndexs.replace(str(emptyIndex + 1), '')
        item = backPack.GetAt(emptyIndex)
    itemIndexs = "%s%s"%(itemIndexs, emptyIndex + 1)
        ipyDataMgr = IpyGameDataPY.IPY_Data()
        for i in xrange(ipyDataMgr.GetStoreCount()):
            shopItem = ipyDataMgr.GetStoreByIndex(i)
            if not shopItem.GetLimitCnt():
                continue
            shopID = shopItem.GetID()
            buyCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ShopBuyCnt % shopID)
            if buyCnt <= 0:
                continue
            buyInfo = objPool.acquire(ChPyNetSendPack.tagSCShopItemBuyCnt)
            buyInfo.ShopID = shopID
            buyInfo.BuyCnt = buyCnt
            buyCntList.append(buyInfo)
    if not buyCntList:
        return
    
    #放入新物品
    item.PutIn(curItem)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_DelPackIndex, int(itemIndexs))
    clientPack = objPool.acquire(ChPyNetSendPack.tagSCShopItemBuyCntInfo)
    clientPack.BuyCntList = buyCntList
    clientPack.Count = len(clientPack.BuyCntList)
    NetPackCommon.SendFakePack(curPlayer, clientPack)
    return
##检查物品是否可以出售
# @param curPlayer 玩家实例
# @param curItem 物品实例
# @return 返回值真, 检查通过
# @remarks 检查物品是否可以出售
def __CheckItemSell(curPlayer, curItem) :
    if not ItemCommon.CheckItemCanUse(curItem):# or ItemControler.GetIsAuctionItem(curItem):
        PlayerControl.NotifyCode(curPlayer, "GeRen_chenxin_644055")
        return
    #if ItemControler.IsEventItem(curItem):
    #    PlayerControl.NotifyCode(curPlayer, "itemuse_chenxin_31379")
    #    return
    if curItem.GetCanSell() == 0:
        #不能出售的物品,无法出售
        PlayerControl.NotifyCode(curPlayer, "GeRen_lhs_272921")
        return
    #获得单个物品销售价格
    itemPrice , priceType = __GetItemSellPrice(curPlayer, curItem)
    itemPrice = int(itemPrice) * curItem.GetCount()
    if not itemPrice or not priceType:
        PlayerControl.NotifyCode(curPlayer, "GeRen_lhs_272921")
        return
    if not PlayerControl.CanGiveMoney(curPlayer, priceType, itemPrice):
        # 对不起,您携带的金钱已经达上限,操作无效
        #PlayerControl.NotifyCode(curPlayer, "GeRen_chenxin_609765")
        return
    return True
#---------------------------------------------------------------------
##获得物品的出售价格
# @param curPlayer 玩家实例
# @param curItem 物品实例
# @return 返回值, 物品的出售价格
# @remarks 获得物品的出售价格
def __GetItemSellPrice(curPlayer, curItem):
    #为配合客户端,进行以下逻辑(向上取整)
    #2012-03-26 jiang 耐久这里不进行除ChConfig.Def_EndureRepairParameter的转换该有公式自己计算
    #curItemEndure = curItem.GetCurDurg()
    #curItemMaxEndure = curItem.GetMaxEndure()
    # 修改此函数请同时修改 脱机挂出售
    #当前物品价格 原价出售
    priceType = curItem.GetGoldPaperPrice()
    if not priceType:
        priceType = IPY_GameWorld.TYPE_Price_Silver_Money
    curItemPrice = curItem.GetSilverPrice()
    return curItemPrice, priceType
##检查玩家可否开始NPC事件
# @param curPlayer 玩家实例
# @return 返回值真, 检查通过
# @remarks 检查玩家可否开始NPC事件
def CheckPlayerCanStateEvent(curPlayer):
    if curPlayer.GetPlayerAction() not in ChConfig.Def_Player_DoEvent_State :
        #CannotDoing 对不起,您当前状态无法进行此操作,操作无效
        PlayerControl.NotifyCode(curPlayer, "GeRen_chenxin_740826")
        return False
    return True
#---------------------------------------------------------------------
##检查物品是否可以放入合成背包.
# @param curItem 物品实例
# @return 布尔值
# @remarks 检查物品是否可以放入合成背包
def __CheckItemCanPutInComposePack(curItem):
    return curItem.GetType() in ChConfig.Def_Compose_Can_Put_List
#---------------------------------------------------------------------
##通用背包放入操作
# @param curPlayer 玩家实例
# @param srcBackpack 起点背包
# @param desBackPack 目标背包
# @param srcIndex 起点索引
# @param destIndex 目标索引
# @param putItemCount 放入数量
# @param tick 时间戳
# @return 返回值无意义
# @remarks 通用背包放入操作
def BackpackOperate(curPlayer, srcBackpack, desBackPack, srcIndex, destIndex, putItemCount, tick):
    #获得需要操作的物品的物品
    scrItem = __GetBackPackOperateItem(curPlayer, srcBackpack, desBackPack, srcIndex)
    if scrItem == None:
        return
    itemControl = ItemControler.PlayerItemControler(curPlayer)
    if not itemControl.CanPutInItem(desBackPack, scrItem.GetItemTypeID(), putItemCount, scrItem.GetIsBind()):
        PlayerControl.NotifyCode(curPlayer, "GeRen_chenxin_676165", [desBackPack])
        return
    #拖拽物品
    ItemControler.DragItem(curPlayer, srcBackpack, srcIndex, desBackPack, destIndex, putItemCount)
    return
#---------------------------------------------------------------------
##通用背包操作检查
# @param scrItem 放入物品
# @param desBackPack 目标背包
# @return 布尔值
# @remarks 通用背包操作检查
def __CheckBackPackOperate(scrItem, desBackPack):
    #特殊检查
    if desBackPack in ChConfig.Def_ComposePack_List:
        if not __CheckItemCanPutInComposePack(scrItem):
            GameWorld.ErrLog('BackpackOperate ItemErr = %s, ItemType = %s'%(scrItem.GetItemTypeID(), scrItem.GetType()))
            return False
    return True
#---------------------------------------------------------------------
##获得背包当前操作的物品
# @param curPlayer 玩家实例
# @param srcBackpack 起始背包
# @param desBackPack 目的背包
# @param srcIndex 起始物品索引
# @return 操作物品实例或者None
# @remarks 获得背包当前操作的物品
def __GetBackPackOperateItem(curPlayer, srcBackpack, desBackPack, srcIndex):
    #操作背包检查
    if srcBackpack not in ChConfig.Def_BackpackOperate_List or desBackPack not in ChConfig.Def_BackpackOperate_List:
        GameWorld.ErrLog('PackItemExchange packErr, srcBackpack = %s, \
            desBackPack = %s'%(srcBackpack, desBackPack), curPlayer.GetID())
        return
    #获得放入的物品
    scrItem = curPlayer.GetItemManager().GetPack(srcBackpack).GetAt(srcIndex)
    #---物品检查---
    if not ItemCommon.CheckItemCanUse(scrItem):
        return
    #特殊检查
    if not __CheckBackPackOperate(scrItem, desBackPack):
        return
    return scrItem
#---------------------------------------------------------------------
##通用背包交换操作
# @param curPlayer 玩家实例
# @param srcBackpack 起点背包
# @param destBackPack 目标背包
# @param srcIndex 起点索引
# @param destIndex 目标索引
# @param tick 时间戳
# @return 返回值无意义
# @remarks 通用背包交换操作
def PackItemExchange(curPlayer, srcBackpack, destBackPack, srcIndex, destIndex, tick):
    #获得需要操作的物品的物品
    scrItem = __GetBackPackOperateItem(curPlayer, srcBackpack, destBackPack, srcIndex)
    if scrItem == None:
        return
    #---验证目标背包格子--
    destItem = curPlayer.GetItemManager().GetPack(destBackPack).GetAt(destIndex)
    #目标格子只验证锁定, 可以允许空位
    if destItem == None or destItem.GetIsLocked():
        return
    ItemCommon.DoLogicSwitchItem(curPlayer, scrItem, destItem, destBackPack)
    return
## 获得金钱付费字典
#  @param moneyList 金钱列表 [金钱类型, 金钱数量,。。。]
#  @param payMoneyDict 金钱累加字典
#  @return 金钱累加字典
#  @remarks 获得金钱付费字典
def GetPayMoneyDict(moneyList, payMoneyDict={}):
    length = len(moneyList)
    for index in range(0, length, 2):
        moneyType = moneyList[index]
        money = moneyList[index + 1]
        payMoney = payMoneyDict.get(moneyType)
        if payMoney == None:
            payMoneyDict[moneyType] = money
        else:
            payMoneyDict[moneyType] += money
    return payMoneyDict
## 检查金钱
#  @param curPlayer 玩家
#  @param payMoneyDict 付钱字典
#  @return BOOL是否足够
#  @remarks 检查金钱
def CheckPayMoney(curPlayer, payMoneyDict):
    for moneyType, money in payMoneyDict.items():
        #验证手续费
        if not PlayerControl.HaveMoney(curPlayer, moneyType, money):
            return False
    return True