From ea1ec0723d36ee1f493505ccdb81906bd009b27e Mon Sep 17 00:00:00 2001
From: hxp <ale99527@vip.qq.com>
Date: 星期二, 29 十月 2019 16:57:41 +0800
Subject: [PATCH] 8315 【恺英】【后端】一键自动购买材料及拍品满概率升星

---
 ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/AuctionHouse.py |  208 +++++++++++++++++++++++++++++++++++++++++++++++++--
 1 files changed, 199 insertions(+), 9 deletions(-)

diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/AuctionHouse.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/AuctionHouse.py
index c1a2563..f668b8b 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
@@ -869,7 +870,7 @@
         auctionItemMgr.sysBuyoutItemByTimeList.sort(key=operator.attrgetter("SysBuyTime"))
     return
 
-def __EndAuctionItem(endItemList, endEvent):
+def __EndAuctionItem(endItemList, endEvent, funcAutoBuyout=False):
     ''' 结束拍品竞拍
     @param delItemStateDict: 删除的拍品竞拍状态
     '''
@@ -896,10 +897,14 @@
             
             # 竞拍成功邮件,发放物品
             if bidderID:
-                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
+                else:
+                    paramList = [bidderPrice]
+                    detail = {"ItemGUID":itemGUID}
+                    addItemList = [{"ItemID":itemID, "Count":itemCount, "IsAuctionItem":False, "UserData":auctionItem.UserData}]
+                    PlayerCompensation.SendMailByKey("PaimaiMail3", [bidderID], addItemList, paramList, detail=detail)
                 AddAuctionRecord(auctionItem, AuctionRecordResult_BidOK)
             
             # 拍卖成功收益,都以玩家收益向上取整
@@ -1086,6 +1091,13 @@
         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)
@@ -1275,12 +1287,13 @@
     __EndAuctionItem([auctionItem], "Unsell")
     return
 
-def __DoPlayerBidAuctionItem(curPlayer, itemGUID, biddingPrice, tick, isOnlyCheck):
+def __DoPlayerBidAuctionItem(curPlayer, itemGUID, biddingPrice, tick, isOnlyCheck, funcAutoBuyout=False):
     ''' 玩家竞价物品
     @param curPlayer: 竞价的玩家
     @param itemGUID: 拍品GUID
     @param biddingPrice: 竞价
     @param isOnlyCheck: 是否仅检查可否竞价
+    @param funcAutoBuyout: 是否功能自动购买
     '''
     
     errInfo = ""
@@ -1341,7 +1354,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
@@ -1420,8 +1433,8 @@
         auctionItemMgr.sysBuyoutItemByTimeList.remove(auctionItem)
         #GameWorld.DebugLog("拍品有人竞价了,移除系统一口价拍品列表!")
         
-    if isBuyout:        
-        __EndAuctionItem([auctionItem], "Buyout")
+    if isBuyout:
+        __EndAuctionItem([auctionItem], "Buyout", funcAutoBuyout)
     else:
         if __AddAuctionItemEndTimeByBid(auctionItem):
             __SortAuctionitem(isSortWorldItem=False)
@@ -1433,6 +1446,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