From ac4f3139e69d4671a46a299df51159f018a5da13 Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期二, 26 十一月 2019 11:35:00 +0800
Subject: [PATCH] 8346 【恺英】【后端】协助系统(封包、表)

---
 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/AuctionHouse.py |  466 ++++++++++++++++++++++++++++++++++++++++++++++++++--------
 1 files changed, 402 insertions(+), 64 deletions(-)

diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/AuctionHouse.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/AuctionHouse.py
index adc2ff1..dc1dabf 100644
--- a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/AuctionHouse.py
+++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/AuctionHouse.py
@@ -20,6 +20,7 @@
 import DataRecordPack
 import PyGameDataStruct
 import PlayerCompensation
+import IPY_PlayerDefine
 import ChPyNetSendPack
 import PlayerDBGSEvent
 import IpyGameDataPY
@@ -52,7 +53,8 @@
 AuctionRecordResult_BidOK, # 竞价成功
 AuctionRecordResult_BidFail, # 竞价失败
 AuctionRecordResult_MoveToWorld, # 仙盟拍品转移到全服拍品
-) = range(6)
+AuctionRecordResult_Unsell, # 下架
+) = range(7)
 
 # 当前拍品归类 0-全服拍品 1-仙盟私有拍品
 AuctionType_World = 0
@@ -247,6 +249,7 @@
     
     if dbData.AuctionType == AuctionType_World:
         pyAuctionItemMgr.worldAuctionItemList.append(dbData)
+        __OnCalcWorldAuctionItemCount(dbData, 1)
         
     if familyID:
         familyItemList = pyAuctionItemMgr.familyAuctionItemDict.get(familyID, [])
@@ -406,6 +409,37 @@
             return True
     return False
 
+def __OnCalcWorldAuctionItemCount(auctionItem, changeCount):
+    ## 世界拍品数量变更统计处理
+    
+    if auctionItem.AuctionType != AuctionType_World:
+        return
+    
+    auctionItemMgr = PyDataManager.GetAuctionItemManager()
+    itemID = auctionItem.ItemID
+    #GameWorld.DebugLog("世界拍品数量变更统计: itemID=%s,changeCount=%s" % (itemID, changeCount))
+    
+    itemIDStr = str(itemID)
+    classLV = auctionItem.ItemClassLV
+    jobLimit = auctionItem.ItemJobLimit
+    # 统计有职业限制的境界装备
+    if jobLimit and classLV and len(itemIDStr) == 7:
+        color = int(itemIDStr[3:4])
+        isSuit = int(itemIDStr[-1])
+        jobEquipKey = (jobLimit, classLV, color, isSuit) # 职业,阶,颜色,是否套装
+        befCount = auctionItemMgr.worldAuctionJobEquipCountDict.get(jobEquipKey, 0)
+        updCount = max(befCount + changeCount, 0)
+        auctionItemMgr.worldAuctionJobEquipCountDict[jobEquipKey] = updCount
+        #GameWorld.DebugLog("    职业境界装备数量变更: jobLimit=%s,classLV=%s,color=%s,isSuit=%s,befCount=%s,updCount=%s" 
+        #                   % (jobLimit, classLV, color, isSuit, befCount, updCount))
+    # 其他的直接用itemID统计
+    else:
+        befCount = auctionItemMgr.worldAuctionItemCountDict.get(itemID, 0)
+        updCount = max(befCount + changeCount, 0)
+        auctionItemMgr.worldAuctionItemCountDict[itemID] = updCount
+        #GameWorld.DebugLog("    物品ID数量变更: itemID=%s,befCount=%s,updCount=%s" % (itemID, befCount, updCount))
+        
+    return
 
 def __GetAuctionSystemItemInfo():
     key = "AuctionSystemItem"
@@ -434,9 +468,10 @@
         endTimeStr = ipyData.GetEndTime()
         auctionCount = ipyData.GetAuctionCount()
         randMinuteRange = ipyData.GetRandMinuteRange()
+        replenishAuctionCount = ipyData.GetReplenishAuctionCount()
         
-        GameWorld.DebugLog("cfgID=%s,startDateStr=%s,endDateStr=%s,startTimeStr=%s,endTimeStr=%s,auctionCount=%s,randMinuteRange=%s" 
-                           % (cfgID, startDateStr, endDateStr, startTimeStr, endTimeStr, auctionCount, randMinuteRange))
+        GameWorld.DebugLog("cfgID=%s,startDateStr=%s,endDateStr=%s,startTimeStr=%s,endTimeStr=%s,auctionCount=%s,randMinuteRange=%s,replenishAuctionCount=%s" 
+                           % (cfgID, startDateStr, endDateStr, startTimeStr, endTimeStr, auctionCount, randMinuteRange, replenishAuctionCount))
         
         if not startDateStr:
             startDateStr = curDateStr
@@ -485,10 +520,15 @@
             GameWorld.DebugLog("    添加上架系统拍品时间: nextAddMinutes=%s %s" % (nextAddMinutes, nextAddAuctionItemDatetime))
             addAuctionItemDatetimeList.append(nextAddAuctionItemDatetime)
             
-        if not addAuctionItemDatetimeList:
+        # 动态补充拍品模式
+        if replenishAuctionCount:
+            GameWorld.DebugLog("    添加动态补充系统拍品计划: %s" % replenishAuctionCount)
+        # 指定上架拍品模式
+        elif addAuctionItemDatetimeList:
+            GameWorld.DebugLog("    添加上架系统拍品时间计划: %s" % addAuctionItemDatetimeList)
+        else:
             continue
-        GameWorld.DebugLog("    添加上架系统拍品时间: %s" % addAuctionItemDatetimeList)
-        addSystemAuctionItemInfo.append([cfgID, ipyData, addAuctionItemDatetimeList])
+        addSystemAuctionItemInfo.append([cfgID, ipyData, startDatetime, endDatetime, addAuctionItemDatetimeList])
         
     AuctionSystemItem = IpyGameDataPY.SetConfigEx(key, [reloadSign, addSystemAuctionItemInfo])
     GameWorld.Log("本日系统拍品信息加载完毕!reloadSign=%s" % (reloadSign))
@@ -505,39 +545,98 @@
                                                                     curDateTime.hour, curDateTime.minute), ChConfig.TYPE_Time_Format)
     
     randMailKey = ""
-    addItemTick = tick
-    sysAuctionItemList = IpyGameDataPY.GetConfigEx("SysWaitAuctionItemList") # 系统等待上架的拍品列表
-    if not sysAuctionItemList:
-        sysAuctionItemList = []
-    addSystemAuctionItemInfo = __GetAuctionSystemItemInfo()
-    for cfgID, ipyData, addAuctionItemDatetimeList in addSystemAuctionItemInfo:
-        if curDateTime not in addAuctionItemDatetimeList:
-            continue
-        #cfgID = ipyData.GetCfgID()
-        addCountWeightList = ipyData.GetItemCountWeightList()
-        auctionItemWeightList = ipyData.GetAuctionItemWeightList()
-        randSecondRange = ipyData.GetAddRandSecondRange()
+    sysAuctionItemListDict = IpyGameDataPY.GetConfigEx("SysWaitAuctionItemListDict") # 系统等待上架的拍品列表字典 {cfgID:[待上架拍品列表], ...}
+    if not sysAuctionItemListDict:
+        sysAuctionItemListDict = {}
         
-        addCount = GameWorld.GetResultByWeightList(addCountWeightList)
-        GameWorld.Log("增加等待上架的系统拍品信息: cfgID=%s,addCount=%s,addItemTick=%s" % (cfgID, addCount, addItemTick))
-        for _ in xrange(addCount):
-            itemInfo = GameWorld.GetResultByWeightList(auctionItemWeightList)
-            if itemInfo != None:
-                randSeconds = 0
-                if len(randSecondRange) == 2:
-                    randSeconds = random.randint(randSecondRange[0], randSecondRange[1])
-                elif len(randSecondRange) == 1:
-                    randSeconds = randSecondRange[0]
-                addItemTick = addItemTick + randSeconds * 1000
-                sysAuctionItemList.append([addItemTick, itemInfo])
-                GameWorld.Log("    增加等待上架的系统拍品: randSeconds=%s,addItemTick=%s,itemInfo=%s" % (randSeconds, addItemTick, itemInfo))
-                
-        randMailKeyList = ipyData.GetRandMailKeyList()
-        if randMailKeyList:
-            randMailKey = random.choice(randMailKeyList)
+    curTime = int(time.time())
+    addItemTime = curTime
+    openJobList = IpyGameDataPY.GetFuncEvalCfg("OpenJob", 1)
+    auctionItemMgr = PyDataManager.GetAuctionItemManager()
+    curWorldLV = PlayerDBGSEvent.GetDBGSTrig_ByKey(ShareDefine.Def_Notify_WorldKey_WorldAverageLv)
+    addSystemAuctionItemInfo = __GetAuctionSystemItemInfo()
+    for cfgID, ipyData, startDatetime, endDatetime, addAuctionItemDatetimeList in addSystemAuctionItemInfo:
+        #cfgID = ipyData.GetCfgID()
+        if cfgID in sysAuctionItemListDict:
+            #GameWorld.DebugLog("    队列中还有未处理的拍品时不处理,防止重复添加!cfgID=%s" % (cfgID))
+            continue
+        worldLVRange = ipyData.GetWorldLVRange()
+        if worldLVRange and len(worldLVRange) == 2:
+            worldLVMin, worldLVMax = worldLVRange
+            if curWorldLV < worldLVMin or curWorldLV > worldLVMax:
+                #GameWorld.DebugLog("    不满足当前世界等级范围条件,不处理该系统上架拍品计划!cfgID=%s,curWorldLV=%s" % (cfgID, curWorldLV))
+                continue
             
-    IpyGameDataPY.SetConfigEx("SysWaitAuctionItemList", sysAuctionItemList)
-    #GameWorld.DebugLog("等待系统上架的拍品列表: %s" % sysAuctionItemList)
+        if curDateTime < startDatetime or curDateTime > endDatetime:
+            #GameWorld.DebugLog("    不在规定的时间内,不处理该系统上架拍品计划!cfgID=%s" % (cfgID))
+            continue
+        
+        randSecondRange = ipyData.GetAddRandSecondRange()
+        if len(randSecondRange) != 2:
+            #GameWorld.DebugLog("    随机上架秒数格式错误,不处理该系统上架拍品计划!cfgID=%s" % (cfgID))
+            continue
+        
+        addItemInfoList = []
+        replenishAuctionCount = ipyData.GetReplenishAuctionCount()
+        # 动态模式
+        if replenishAuctionCount:
+            replenishCDSeconds = ipyData.GetReplenishCDMinutes() * 60
+            lastReplenishTime = auctionItemMgr.worldAuctionReplenishTimeDict.get(cfgID, 0)
+            if curTime - lastReplenishTime < replenishCDSeconds:
+                continue
+            auctionItemMgr.worldAuctionReplenishTimeDict[cfgID] = curTime
+            
+            replenishItemID = ipyData.GetReplenishItemID()
+            if replenishItemID:
+                curItemIDCount = auctionItemMgr.worldAuctionItemCountDict.get(replenishItemID, 0)
+                if curItemIDCount >= replenishAuctionCount:
+                    continue
+                addItemIDCount = replenishAuctionCount - curItemIDCount
+                GameWorld.DebugLog("    动态补充拍品队列: cfgID=%s,replenishItemID=%s,addItemIDCount=%s" % (cfgID, replenishItemID, addItemIDCount))
+                for _ in xrange(addItemIDCount):
+                    addItemInfoList.append(replenishItemID)
+            else:
+                replenishEquipPlaces = ipyData.GetReplenishEquipPlaces()
+                rpClassLV, rpColor, rpIsSuit = ipyData.GetReplenishEquipInfo()
+                rpStar = 0
+                for job in openJobList:
+                    jobEquipKey = (job, rpClassLV, rpColor, rpIsSuit)
+                    curJobEquipCount = auctionItemMgr.worldAuctionJobEquipCountDict.get(jobEquipKey, 0)
+                    if curJobEquipCount >= replenishAuctionCount:
+                        continue
+                    addEquipCount = replenishAuctionCount - curJobEquipCount
+                    GameWorld.DebugLog("    动态补充拍品队列: cfgID=%s,addEquipCount=%s,job=%s" % (cfgID, addEquipCount, job))
+                    for _ in xrange(addEquipCount):
+                        addItemInfoList.append([rpClassLV, rpColor, replenishEquipPlaces, rpIsSuit, rpStar, [job]])
+                        
+            random.shuffle(addItemInfoList) # 动态模式待添加拍品打乱下顺序,防止批量添加同一职业物品
+            
+        # 指定模式
+        elif curDateTime in addAuctionItemDatetimeList:
+            
+            addCountWeightList = ipyData.GetItemCountWeightList()
+            auctionItemWeightList = ipyData.GetAuctionItemWeightList()
+            
+            addCount = GameWorld.GetResultByWeightList(addCountWeightList)
+            GameWorld.DebugLog("    指定补充拍品队列: cfgID=%s,addCount=%s" % (cfgID, addCount))
+            for _ in xrange(addCount):
+                itemInfo = GameWorld.GetResultByWeightList(auctionItemWeightList)
+                if itemInfo != None:
+                    addItemInfoList.append(itemInfo)
+                    
+            randMailKeyList = ipyData.GetRandMailKeyList()
+            if randMailKeyList:
+                randMailKey = random.choice(randMailKeyList)
+            
+        sysWaitAuctionItemList = []
+        for itemInfo in addItemInfoList:
+            randSeconds = random.randint(randSecondRange[0], randSecondRange[1])
+            addItemTime = addItemTime + randSeconds
+            sysWaitAuctionItemList.append([addItemTime, itemInfo])
+        sysAuctionItemListDict[cfgID] = sysWaitAuctionItemList
+        
+    IpyGameDataPY.SetConfigEx("SysWaitAuctionItemListDict", sysAuctionItemListDict)
+    #GameWorld.DebugLog("等待系统上架的拍品列表: %s" % sysAuctionItemListDict)
     
     # 随机邮件通知 
     if randMailKey:
@@ -556,21 +655,26 @@
     return
 
 def __DoSysWaitAddAuctionItem(tick):
-    sysAuctionItemList = IpyGameDataPY.GetConfigEx("SysWaitAuctionItemList") # 系统等待上架的拍品列表
-    if not sysAuctionItemList:
+    SysWaitAuctionItemListDict = IpyGameDataPY.GetConfigEx("SysWaitAuctionItemListDict") # 系统等待上架的拍品列表
+    if not SysWaitAuctionItemListDict:
         return
     
-    doCount = len(sysAuctionItemList)
-    while doCount > 0 and sysAuctionItemList:
-        doCount -= 1
-        addItemTick, itemInfo = sysAuctionItemList[0]
-        if tick < addItemTick:
-            #GameWorld.DebugLog("未到系统等待上架的拍品tick,不处理! tick=%s,sysAuctionItemList=%s" % (tick, sysAuctionItemList))
-            break
-        sysAuctionItemList.pop(0)
-        GameWorld.DebugLog("系统等待上架的拍品tick已到,可上架! tick=%s >= addItemTick=%s,itemInfo=%s,sysAuctionItemList=%s" % (tick, addItemTick, itemInfo, sysAuctionItemList))
-        DoAddSystemAuctionItem([itemInfo])
-        
+    curTime = int(time.time())
+    for cfgID, sysAuctionItemList in SysWaitAuctionItemListDict.items():
+        doCount = len(sysAuctionItemList)
+        while doCount > 0 and sysAuctionItemList:
+            doCount -= 1
+            addItemTime, itemInfo = sysAuctionItemList[0]
+            if curTime < addItemTime:
+                #GameWorld.DebugLog("未到系统等待上架的拍品时间,不处理! curTime=%s,sysAuctionItemList=%s" % (curTime, sysAuctionItemList))
+                break
+            sysAuctionItemList.pop(0)
+            GameWorld.DebugLog("系统等待上架的拍品时间已到,可上架! curTime=%s >= addItemTime=%s,itemInfo=%s,sysAuctionItemList=%s" % (curTime, addItemTime, itemInfo, sysAuctionItemList))
+            DoAddSystemAuctionItem([itemInfo])
+            
+        if not sysAuctionItemList:
+            SysWaitAuctionItemListDict.pop(cfgID)
+            
     return
 
 def OnAuctionItemTimeProcess(curTime, tick):
@@ -661,6 +765,7 @@
         openJobList = IpyGameDataPY.GetFuncEvalCfg("OpenJob", 1)
         for job in openJobList:
             jobPlayerCount = len(PyGameData.g_onedayJobPlayerLoginoffTimeDict.get(job, {}))
+            jobPlayerCount = max(1, jobPlayerCount) # 人数默认至少1个
             totalPlayerCount += jobPlayerCount
             jobWeightList.append([jobPlayerCount, job])
             GameWorld.DebugLog("职业人数: job=%s,count=%s" % (job, jobPlayerCount))
@@ -714,6 +819,7 @@
         
         auctionItemMgr.allAuctionItemByEndTimeList.append(auctionItem)
         auctionItemMgr.worldAuctionItemList.append(auctionItem)
+        __OnCalcWorldAuctionItemCount(auctionItem, 1)
         notifyWorldAddItemList.append([itemGUID, itemID, playerID])
         
         AddAuctionRecord(auctionItem, AuctionRecordResult_MoveToWorld)
@@ -764,7 +870,7 @@
         auctionItemMgr.sysBuyoutItemByTimeList.sort(key=operator.attrgetter("SysBuyTime"))
     return
 
-def __EndAuctionItem(endItemList, endEvent):
+def __EndAuctionItem(endItemList, endEvent, funcAutoBuyout=False, buyPlayer=None):
     ''' 结束拍品竞拍
     @param delItemStateDict: 删除的拍品竞拍状态
     '''
@@ -791,10 +897,20 @@
             
             # 竞拍成功邮件,发放物品
             if bidderID:
+                mailTypeKey = "PaimaiMail3"
                 paramList = [bidderPrice]
                 detail = {"ItemGUID":itemGUID}
                 addItemList = [{"ItemID":itemID, "Count":itemCount, "IsAuctionItem":False, "UserData":auctionItem.UserData}]
-                PlayerCompensation.SendMailByKey("PaimaiMail3", [bidderID], addItemList, paramList, detail=detail)
+                if funcAutoBuyout:
+                    # 功能自动购买的不给物品,由功能根据功能需求处理
+                    pass
+                ## 如果有玩家的,直接给到背包
+                elif buyPlayer and buyPlayer.GetPlayerID() == bidderID:
+                    mailInfo = [mailTypeKey, addItemList, paramList, detail]
+                    resultMsg = str([itemGUID, itemID, itemCount, auctionItem.UserData, mailInfo])
+                    buyPlayer.MapServer_QueryPlayerResult(0, 0, "AuctionHouseGiveItem", resultMsg, len(resultMsg))
+                else:
+                    PlayerCompensation.SendMailByKey(mailTypeKey, [bidderID], addItemList, paramList, detail=detail)
                 AddAuctionRecord(auctionItem, AuctionRecordResult_BidOK)
             
             # 拍卖成功收益,都以玩家收益向上取整
@@ -812,7 +928,7 @@
                     # 仙盟拍品收益邮件
                     detail = {"ItemGUID":itemGUID, "ItemID":itemID, "Count":itemCount, "BidderPrice":bidderPrice, "FamilyPlayerIDList":familyPlayerIDList}
                     paramList = [itemID, itemID, bidderPrice, taxRate, giveGoldAverage, personMaxRate]
-                    PlayerCompensation.SendMailByKey("PaimaiMail8", familyPlayerIDList, [], paramList, gold=giveGoldAverage, 
+                    PlayerCompensation.SendMailByKey("PaimaiMail8", familyPlayerIDList, [], paramList, goldPaper=giveGoldAverage, 
                                                      detail=detail, moneySource=ChConfig.Def_GiveMoney_AuctionGain)
                 else:
                     GameWorld.ErrLog("仙盟拍品没有人获得收益!familyID=%s,itemID=%s,itemGUID=%s" % (familyID, itemID, itemGUID))
@@ -825,7 +941,7 @@
                 # 个人拍卖收益邮件
                 detail = {"ItemGUID":itemGUID, "ItemID":itemID, "Count":itemCount, "BidderPrice":bidderPrice}
                 paramList = [itemID, itemID, bidderPrice, taxRate, givePlayerGold]
-                PlayerCompensation.SendMailByKey("PaimaiMail7", [playerID], [], paramList, gold=givePlayerGold, 
+                PlayerCompensation.SendMailByKey("PaimaiMail7", [playerID], [], paramList, goldPaper=givePlayerGold, 
                                                  detail=detail, moneySource=ChConfig.Def_GiveMoney_AuctionGain)
                 
             else:
@@ -846,13 +962,17 @@
             elif playerID:
                 endType = "Return"
                 
-                # 流拍返还物品邮件
+                # 返还物品邮件
                 paramList = []
                 detail = {"ItemGUID":itemGUID}
                 addItemList = [{"ItemID":itemID, "Count":itemCount, "IsAuctionItem":True, "UserData":auctionItem.UserData}]
-                PlayerCompensation.SendMailByKey("PaimaiMail4", [playerID], addItemList, paramList, detail=detail)
-                
-                AddAuctionRecord(auctionItem, AuctionRecordResult_SellFail)
+                # 下架
+                if endEvent == "Unsell":
+                    PlayerCompensation.SendMailByKey("PaimaiMail9", [playerID], addItemList, paramList, detail=detail)
+                    AddAuctionRecord(auctionItem, AuctionRecordResult_Unsell)
+                else:
+                    PlayerCompensation.SendMailByKey("PaimaiMail4", [playerID], addItemList, paramList, detail=detail)
+                    AddAuctionRecord(auctionItem, AuctionRecordResult_SellFail)
             else:
                 endType = "SystemDelete"
                 GameWorld.Log("系统拍品流拍: itemGUID=%s,itemID=%s" % (itemGUID, itemID))
@@ -870,6 +990,7 @@
             
         if auctionItem in auctionItemMgr.worldAuctionItemList:
             auctionItemMgr.worldAuctionItemList.remove(auctionItem)
+            __OnCalcWorldAuctionItemCount(auctionItem, -1)
             
         for queryItemList in auctionItemMgr.worldAuctionItemQueryDict.values():
             if auctionItem in queryItemList:
@@ -971,6 +1092,19 @@
             
         return
     
+    # 下架拍品
+    elif queryType == "UnsellAuctionItem":
+        itemGUID = queryData[0]
+        __DoUnsellAuctionItem(curPlayer, itemGUID)
+        return
+        
+    # 升星自动购买
+    elif queryType == "EquipStarAutoBuy":
+        buyResult = __DoEquipStarAutoBuyEquip(curPlayer, queryData,  tick)
+        if buyResult == None:
+            return
+        result = buyResult
+        
     elif queryType == "ClearAuctionItem":
         __DoGMClearAuctionItem(curPlayer)
         return
@@ -1073,6 +1207,7 @@
         auctionItemMgr.familyAuctionItemDict[familyID] = familyItemList
     else:
         auctionItemMgr.worldAuctionItemList.append(auctionItem)
+        __OnCalcWorldAuctionItemCount(auctionItem, 1)
         
         # 添加进我的拍卖
         if playerID:
@@ -1133,12 +1268,38 @@
             NetPackCommon.SendFakePack(player, infoPack)
     return
 
-def __DoPlayerBidAuctionItem(curPlayer, itemGUID, biddingPrice, tick, isOnlyCheck):
+def __DoUnsellAuctionItem(curPlayer, itemGUID):
+    ## 下架拍品
+    auctionItem = GetAuctionItem(itemGUID)
+    if not auctionItem:
+        # 拍品不存在
+        PlayerControl.NotifyCode(curPlayer, "Paimai3")
+        return
+    playerID = curPlayer.GetPlayerID()
+    itemID = auctionItem.ItemID
+    if auctionItem.FamilyID:
+        GameWorld.ErrLog("仙盟拍品无法下架!itemGUID=%s,itemID=%s,itemFamilyID=%s" 
+                         % (itemGUID, itemID, auctionItem.FamilyID), playerID)
+        return
+    if auctionItem.PlayerID != playerID:
+        GameWorld.ErrLog("不是玩家自己的拍品无法下架!itemGUID=%s,itemID=%s,itemPlayerID=%s" 
+                         % (itemGUID, itemID, auctionItem.PlayerID), playerID)
+        return
+    if auctionItem.BidderPrice:
+        # 竞价中的拍品不能下架
+        PlayerControl.NotifyCode(curPlayer, "Paimai9")
+        return
+    
+    __EndAuctionItem([auctionItem], "Unsell")
+    return
+
+def __DoPlayerBidAuctionItem(curPlayer, itemGUID, biddingPrice, tick, isOnlyCheck, funcAutoBuyout=False):
     ''' 玩家竞价物品
     @param curPlayer: 竞价的玩家
     @param itemGUID: 拍品GUID
     @param biddingPrice: 竞价
     @param isOnlyCheck: 是否仅检查可否竞价
+    @param funcAutoBuyout: 是否功能自动购买
     '''
     
     errInfo = ""
@@ -1199,7 +1360,7 @@
         auctionItem.BiddingQueryTick = tick
         return itemID, errInfo
     
-    if auctionItem.BiddingQueryID != playerID:
+    if not funcAutoBuyout and auctionItem.BiddingQueryID != playerID:
         PlayerControl.NotifyCode(curPlayer, "Paimai2")
         errInfo = "bidding player error"
         return itemID, errInfo
@@ -1220,12 +1381,12 @@
         if isBuyout:
             # 竞拍失败,仅通知
             paramList = [itemID, itemID, lastBidderPrice]
-            PlayerCompensation.SendMailByKey("PaimaiMail2", [lastBidderID], [], paramList, gold=lastBidderPrice, 
+            PlayerCompensation.SendMailByKey("PaimaiMail2", [lastBidderID], [], paramList, goldPaper=lastBidderPrice, 
                                              detail=detail, moneySource=ChConfig.Def_GiveMoney_AuctionBidReturn)
         else:
             # 竞拍失败,可继续竞价邮件
             paramList = [itemID, itemID, lastBidderPrice, itemGUID]
-            PlayerCompensation.SendMailByKey("PaimaiMail1", [lastBidderID], [], paramList, gold=lastBidderPrice, 
+            PlayerCompensation.SendMailByKey("PaimaiMail1", [lastBidderID], [], paramList, goldPaper=lastBidderPrice, 
                                              detail=detail, moneySource=ChConfig.Def_GiveMoney_AuctionBidReturn)
         AddAuctionRecord(auctionItem, AuctionRecordResult_BidFail)
         
@@ -1278,8 +1439,8 @@
         auctionItemMgr.sysBuyoutItemByTimeList.remove(auctionItem)
         #GameWorld.DebugLog("拍品有人竞价了,移除系统一口价拍品列表!")
         
-    if isBuyout:        
-        __EndAuctionItem([auctionItem], "Buyout")
+    if isBuyout:
+        __EndAuctionItem([auctionItem], "Buyout", funcAutoBuyout, buyPlayer=curPlayer)
     else:
         if __AddAuctionItemEndTimeByBid(auctionItem):
             __SortAuctionitem(isSortWorldItem=False)
@@ -1291,6 +1452,183 @@
         
     return itemID, errInfo
 
+def __DoEquipStarAutoBuyEquip(curPlayer, queryData, tick):
+    ## 升星自动购买
+    classLV, equipPlace, curPartStar, equipPackIndex, isAutoBuyPreview, curRate, delEquipIndexList, delItemInfoList, lackItemCostMoney, playerGoldPaper = queryData
+    GameWorld.DebugLog("升星自动购买装备: classLV=%s, equipPlace=%s, curPartStar=%s, equipPackIndex=%s" % (classLV, equipPlace, curPartStar, equipPackIndex))
+    GameWorld.DebugLog("    是否预览 %s, curRate=%s,lackItemCostMoney=%s, playerGoldPaper=%s" % (isAutoBuyPreview, curRate, lackItemCostMoney, playerGoldPaper))
+    nextStar = curPartStar + 1
+    ipyData = IpyGameDataPY.GetIpyGameData("EquipStarUp", classLV, equipPlace, nextStar)
+    if not ipyData:
+        return
+    costEquipPlaceList = ipyData.GetCostEquipPlace()
+    costEquipColorList = ipyData.GetCostEquipColor()
+    isJobLimit = ipyData.GetIsJobLimit()
+    unSuitRate = ipyData.GetUnSuitRate()
+    
+    curTime = int(time.time())
+    fullRate = IpyGameDataPY.GetFuncCfg("EquipStarRate", 4)
+    autoBuyOtherClassItemDict = {}
+    buyEquipCostMoney = 0
+    autoBuyItemList = []
+    auctionItemMgr = PyDataManager.GetAuctionItemManager()
+    #GameWorld.DebugLog("世界拍品个数: %s" % len(auctionItemMgr.worldAuctionItemList))
+    for i, worldAuctionItem in enumerate(auctionItemMgr.worldAuctionItemList):
+                
+        itemID = worldAuctionItem.ItemID
+        aucItemJob = worldAuctionItem.ItemJobLimit
+        if not aucItemJob:
+            #GameWorld.DebugLog("    %s 职业通用的, 不购买!itemID=%s" % (i, itemID))
+            continue
+        if isJobLimit and aucItemJob != curPlayer.GetJob():
+            #GameWorld.DebugLog("    %s 职业不可用, 不购买!itemID=%s,aucItemJob=%s != %s" % (i, itemID, aucItemJob, curPlayer.GetJob()))
+            continue
+        
+        itemIDStr = str(itemID)
+        aucItemColor = int(itemIDStr[3:4])
+        aucItemPlace = int(itemIDStr[4:6])
+        aucItemIsSuit = int(itemIDStr[-1])
+        
+        if aucItemColor not in costEquipColorList:
+            #GameWorld.DebugLog("    %s 颜色限制, 不购买!itemID=%s,aucItemColor=%s not in %s" % (i, itemID, aucItemColor, costEquipColorList))
+            continue
+        if aucItemPlace not in costEquipPlaceList:
+            #GameWorld.DebugLog("    %s 装备位限制, 不购买!itemID=%s,aucItemPlace=%s not in %s" % (i, itemID, aucItemPlace, costEquipPlaceList))
+            continue
+        if aucItemIsSuit:
+            #套装不允许自动购买
+            #GameWorld.DebugLog("    %s 套装, 不购买!itemID=%s" % (i, itemID))
+            continue
+        
+        aucIpyData = IpyGameDataPY.GetIpyGameData("AuctionItem", itemID)
+        if not aucIpyData:
+            continue
+        buyoutPrice = aucIpyData.GetBuyoutPrice()
+        if not buyoutPrice:
+            #GameWorld.DebugLog("    %s 没有一口价, 不购买!itemID=%s,buyoutPrice=%s" % (i, itemID, buyoutPrice))
+            continue
+                
+        if curTime > worldAuctionItem.EndTime:
+            #GameWorld.DebugLog("    %s 拍品已结束竞价, 不购买!itemID=%s" % (i, itemID))
+            continue
+        
+        noticeMinutes = aucIpyData.GetNoticeSaleMinutes()
+        if noticeMinutes:
+            addTimeStr = worldAuctionItem.AddTime
+            addTime = GameWorld.ChangeTimeStrToNum(addTimeStr)
+            passMinutes = (curTime - addTime) / 60
+            if passMinutes < noticeMinutes:
+                #GameWorld.DebugLog("    %s 拍品尚未开放竞价, 不购买!itemID=%s" % (i, itemID))
+                continue
+            
+        aucItemClassLV = worldAuctionItem.ItemClassLV
+        # 本阶的直接处理
+        if aucItemClassLV == classLV:
+            autoBuyItemList.append([worldAuctionItem, buyoutPrice])
+            curRate += unSuitRate
+            buyEquipCostMoney += buyoutPrice
+            GameWorld.DebugLog("    %s 本阶优先购买!itemID=%s,classLV=%s,curRate=%s,buyoutPrice=%s,buyEquipCostMoney=%s" 
+                               % (i, itemID, classLV, curRate, buyoutPrice, buyEquipCostMoney))
+            if curRate >= fullRate:
+                curRate = 100
+                GameWorld.DebugLog("        自动购买本阶概率已满足!curRate=%s" % (curRate))
+                break
+            
+        # 其他阶的需要按阶的优先级进行处理
+        else:
+            if aucItemClassLV not in autoBuyOtherClassItemDict:
+                autoBuyOtherClassItemDict[aucItemClassLV] = []
+            classItemList = autoBuyOtherClassItemDict[aucItemClassLV]
+            classItemList.append([worldAuctionItem, buyoutPrice])
+            GameWorld.DebugLog("    %s 非本阶, 暂不处理! itemID=%s,aucItemClassLV=%s" % (i, itemID, aucItemClassLV))
+          
+    # 未满概率时再购买其他阶
+    if curRate < 100:
+        lowClassList, highClassList = [], []
+        for othClassLV in autoBuyOtherClassItemDict.keys():
+            if othClassLV <= classLV:
+                lowClassList.append(othClassLV)
+            else:
+                highClassList.append(othClassLV)
+        lowClassList.sort(reverse=True)
+        highClassList.sort()
+        buyClassLVList = lowClassList + highClassList
+        GameWorld.DebugLog("本阶概率未满,检查购买其他阶! curRate=%s,buyClassLVList=%s" % (curRate, buyClassLVList))
+        
+        diffClassChangeRatePerInfo = IpyGameDataPY.GetFuncEvalCfg("EquipStarRate", 1)
+        unSuitRateRange = IpyGameDataPY.GetFuncEvalCfg("EquipStarRate", 2)
+        for othClassLV in buyClassLVList:
+            classItemList = autoBuyOtherClassItemDict[othClassLV]
+            for worldAuctionItem, buyoutPrice in classItemList:
+                baseRate = unSuitRate
+                minRate, maxRate = unSuitRateRange
+                
+                costClassLV = worldAuctionItem.ItemClassLV
+                itemID = worldAuctionItem.ItemID
+                
+                #吞高阶
+                if costClassLV > classLV:
+                    diffClassChangeRatePer = diffClassChangeRatePerInfo[0] * (costClassLV - classLV)
+                    addRate = int(math.ceil(round(baseRate * (100 + diffClassChangeRatePer) /100.0, 2)))
+                    GameWorld.DebugLog("    吞高阶 itemID=%s,costClassLV=%s,classLV=%s,baseRate=%s,diffClassChangeRatePer=%s,addRate=%s" 
+                                       % (itemID, costClassLV, classLV, baseRate, diffClassChangeRatePer, addRate))
+                #吞低阶
+                elif costClassLV < classLV:
+                    diffClassChangeRatePer = diffClassChangeRatePerInfo[1] * (classLV - costClassLV)
+                    addRate = int(math.ceil(round(baseRate * (100 - diffClassChangeRatePer) /100.0, 2)))
+                    GameWorld.DebugLog("    吞低阶 itemID=%s,costClassLV=%s,classLV=%s,baseRate=%s,diffClassChangeRatePer=%s,addRate=%s" 
+                                       % (itemID, costClassLV, classLV, baseRate, diffClassChangeRatePer, addRate))
+                else:
+                    addRate = baseRate
+                addRate = max(minRate, min(addRate, maxRate))
+                
+                autoBuyItemList.append([worldAuctionItem, buyoutPrice])
+                curRate += addRate
+                buyEquipCostMoney += buyoutPrice
+                GameWorld.DebugLog("        curRate=%s,buyoutPrice=%s,buyEquipCostMoney=%s" % (curRate, buyoutPrice, buyEquipCostMoney))
+                if curRate >= fullRate:
+                    GameWorld.DebugLog("        自动购买补充其他阶概率已满足!curRate=%s" % (curRate))
+                    curRate = 100
+                    break
+            if curRate >= fullRate:
+                break
+            
+    totalCostMoney = lackItemCostMoney + buyEquipCostMoney
+    GameWorld.DebugLog("    lackItemCostMoney=%s,buyEquipCostMoney=%s,totalCostMoney=%s,curRate=%s" % (lackItemCostMoney, buyEquipCostMoney, totalCostMoney, curRate))
+    if isAutoBuyPreview:
+        __SyncEquipStarAutoBuyCostInfo(curPlayer, classLV, equipPlace, curPartStar, curRate, totalCostMoney)
+        return
+    
+    if curRate < 100:
+        # 自动购买必须满概率
+        # 因为确认购买不是实时的,所以存在拍卖行预览消耗装备可能被其他玩家买走导致无法满赶驴,所以这里需要补同步一次
+        __SyncEquipStarAutoBuyCostInfo(curPlayer, classLV, equipPlace, curPartStar, curRate, totalCostMoney)
+        PlayerControl.NotifyCode(curPlayer, "AutoBuyEquipLackEquip")
+        return
+    
+    if playerGoldPaper < totalCostMoney:
+        # 因为确认购买不是实时的,所以存在拍卖行预览消耗的价格与实际购买可能出现消耗价格不一致的情况,所以这里需要补同步一次
+        __SyncEquipStarAutoBuyCostInfo(curPlayer, classLV, equipPlace, curPartStar, curRate, totalCostMoney)
+        PlayerControl.NotifyCode(curPlayer, "AutoBuyEquipLackMoney", [IPY_PlayerDefine.TYPE_Price_Gold_Paper])
+        return
+    
+    for worldAuctionItem, buyoutPrice in autoBuyItemList:
+        # 这里认为一定可以购买成功,不对返回值做处理,即使无法购买也认为购买成功,玩家的消耗照常扣除
+        __DoPlayerBidAuctionItem(curPlayer, worldAuctionItem.ItemGUID, buyoutPrice, tick, False, funcAutoBuyout=True)
+        
+    return classLV, equipPlace, curPartStar, equipPackIndex, curRate, delEquipIndexList, delItemInfoList, lackItemCostMoney, buyEquipCostMoney
+
+def __SyncEquipStarAutoBuyCostInfo(curPlayer, classLV, equipPlace, curPartStar, curRate, totalCostMoney):
+    ## 通知自动购买预览结果
+    costInfo = ChPyNetSendPack.tagGCEquipStarAutoBuyCostInfo()
+    costInfo.ClassLV = classLV
+    costInfo.EquipPlace = equipPlace
+    costInfo.CurStar = curPartStar
+    costInfo.CurRate = curRate
+    costInfo.AutoBuyCostMoney = totalCostMoney
+    NetPackCommon.SendFakePack(curPlayer, costInfo)
+    return
+
 def __SyncRefreshAuctionItem(auctionItemList):
     ''' // B5 08 拍卖行刷新拍品 #tagGCRefreshAuctionItemInfo
         1-仙盟拍品转移到全服时通知; 2-拍品有人竞价时刷新

--
Gitblit v1.8.0