| #!/usr/bin/python  | 
| # -*- coding: GBK -*-  | 
| #-------------------------------------------------------------------------------  | 
| #  | 
| #-------------------------------------------------------------------------------  | 
| #  | 
| ##@package Player.PlayerAttrFruit  | 
| #  | 
| # @todo:Íæ¼Ò¸÷¹¦ÄÜÊôÐÔ¹ûʵ/»êʯ  | 
| # @author hxp  | 
| # @date 2014-11-04  | 
| # @version 1.9  | 
| #  | 
| # @change: "2014-11-25 18:00" hxp ÐÞ¸ÄÈ¡×øÆï½×¼¶´íÎóbug  | 
| # @change: "2014-11-26 17:30" hxp Ôö¼Ó»ñÈ¡ÊôÐÔ¹ûʵÒÑʹÓøöÊý×Öµä  | 
| # @change: "2014-12-04 15:30" hxp ÊôÐÔ¹ûʵ֧³Ö°´¸öÊý»ò°´ÊôÐÔµã¿ØÖÆÉÏÏÞ£»Ð޸İٷֱÈÊôÐÔÖ»Ëã»ù´¡ÊôÐÔ  | 
| # @change: "2014-12-05 19:30" hxp Ôö¼ÓÖ§³Ö°´±ýÍ¼Ëæ»úÊôÐ﵋  | 
| # @change: "2015-01-04 21:00" hxp Ôö¼ÓͼÌÚÊôÐÔ¹ûʵ  | 
| # @change: "2015-05-28 14:00" hxp Ë¢ÊôÐÔÓÅ»¯  | 
| # @change: "2016-05-17 11:00" xdh Ôö¼ÓÿÈÕ×î´óʹÓÃÉÏÏÞ£¬Ôö¼ÓÒ»¼üʹÓà  | 
| # @change: "2016-10-17 16:00" hxp ¹ó×åÌØÈ¨ÅжϷ½Ê½ÐÞ¸Ä  | 
| # @change: "2017-08-07 20:30" xdh ÊÖÓΰ汾ÐÞ¸Ä  | 
| #  | 
| # ÏêϸÃèÊö: Íæ¼Ò¸÷¹¦ÄÜÊôÐÔ¹ûʵ(°´µÈ¼¶»ò½×¼¶ÓÐʹÓøöÊýÉÏÏÞ)  | 
| #  | 
| #---------------------------------------------------------------------  | 
| #"""Version = 2017-08-07 20:30"""  | 
| #---------------------------------------------------------------------  | 
| import NetPackCommon  | 
| import ChPyNetSendPack  | 
| import PlayerControl  | 
| import ShareDefine  | 
| import ItemCommon  | 
| import PlayerHorse  | 
| import GameWorld  | 
| import ChConfig  | 
| import IPY_GameWorld  | 
| import IpyGameDataPY  | 
| import PlayerPet  | 
| import PlayerRefineStove  | 
| import PlayerSuccess  | 
| import SkillShell  | 
|   | 
| (  | 
| Def_LimitType_Cnt, # °´¸öÊýÏÞÖÆ  | 
| Def_LimitType_Attr, # °´ÊôÐÔÏÞÖÆ  | 
| ) = range(2)  | 
|   | 
|   | 
|   | 
|   | 
| ## ÊôÐÔ¹ûʵµÇ¼´¦Àí  | 
| # @param curPlayer  | 
| # @return None  | 
| def AttrFruitOnLogin(curPlayer):  | 
|     Sync_AttrFruitEatCnt(curPlayer)  | 
|     return  | 
|   | 
| ## »ñÈ¡¹ûʵipyÊý¾Ý  | 
| def GetAttrFruitIpyData(itemID, isShowLog=True):  | 
|     if isShowLog:  | 
|         return IpyGameDataPY.GetIpyGameData("AttrFruit", itemID)  | 
|     else:  | 
|         return IpyGameDataPY.GetIpyGameDataNotLog("AttrFruit", itemID)  | 
|       | 
|   | 
| #// A3 2A »ØÊÕ»êʯ #tagCMRecycleAttrFruit  | 
| #  | 
| #struct    tagCMRecycleAttrFruit  | 
| #{  | 
| #    tagHead        Head;  | 
| #    BYTE        IndexCount;    //Ë÷Òý¸öÊý  | 
| #    BYTE        IndexList[IndexCount];    //ÎïÆ·ÔÚ±³°üÖÐË÷ÒýÁÐ±í  | 
| #    WORD        RecycleCountList[IndexCount];    //Ë÷Òý¶ÔÓ¦»ØÊÕ¸öÊýÁÐ±í  | 
| #};  | 
| def OnRecycleAttrFruit(index, packData, tick):  | 
|     curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)  | 
|       | 
|     indexList = packData.IndexList  | 
|     recycleCountList = packData.RecycleCountList  | 
|     if not indexList or len(indexList) != len(recycleCountList):  | 
|         return  | 
|       | 
|     totalMoney = 0  | 
|     recycleItemList = []  | 
|     backPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptItem)  | 
|     for i, itemIndex in enumerate(indexList):  | 
|         recycleCount = recycleCountList[i]  | 
|         curItem = backPack.GetAt(itemIndex)  | 
|         if not ItemCommon.CheckItemCanUse(curItem):  | 
|             continue  | 
|           | 
|         recycleCount = min(recycleCount, curItem.GetCount())  | 
|         if recycleCount <= 0:  | 
|             continue  | 
|           | 
|         itemID = curItem.GetItemTypeID()  | 
|         ipyData = GetAttrFruitIpyData(itemID)  | 
|         if not ipyData:  | 
|             continue  | 
|           | 
|         maxEatCnt = GetMaxEatCnt(curPlayer, itemID)  | 
|         eatCntKey = ChConfig.Def_PDict_AttrFruitEatCnt % itemID  | 
|         limitType = Def_LimitType_Cnt  | 
|         if limitType == Def_LimitType_Attr:  | 
|             eatCntKey = ChConfig.Def_PDict_AttrFruitAddValue % itemID  | 
|         eatCnt = curPlayer.NomalDictGetProperty(eatCntKey) # ÒѳԴÎÊý/ÊôÐÔÖµ  | 
|         if eatCnt < maxEatCnt:  | 
|             GameWorld.DebugLog("δ´ïµ½Ê¹ÓøöÊýÉÏÏÞ£¬²»¿É»ØÊÕ£¡eatCnt=%s,maxEatCnt=%s" % (eatCnt, maxEatCnt), curPlayer.GetPlayerID())  | 
|             continue  | 
|           | 
|         recycleMoney = ipyData.GetRecycleMoney()  | 
|         if not recycleMoney:  | 
|             continue  | 
|           | 
|         totalMoney += recycleMoney * recycleCount  | 
|         recycleItemList.append({"GUID":curItem.GetGUID(), "ItemID":itemID, "ItemCount":recycleCount, "Index":itemIndex})  | 
|         ItemCommon.DelItem(curPlayer, curItem, recycleCount, True, ChConfig.ItemDel_AttrFruit)    | 
|         GameWorld.DebugLog("»ØÊÕ»êʯ itemID=%s,maxEatCnt=%s,eatCnt=%s,recycleCount=%s,recycleMoney=%s,totalMoney=%s"   | 
|                            % (itemID, maxEatCnt, eatCnt, recycleCount, recycleMoney, totalMoney), curPlayer.GetPlayerID())  | 
|                   | 
|     if totalMoney:  | 
|         addDataDict = {"recycleItemList":recycleItemList}  | 
|         PlayerControl.GiveMoney(curPlayer, ShareDefine.TYPE_Price_Danjing, totalMoney, ChConfig.Def_GiveMoney_UseItem, addDataDict)  | 
|         curPlayer.Sync_MakeItemAnswer(ShareDefine.Def_mitRecycleAttrFruit, 1)  | 
|     return  | 
|   | 
|   | 
| #// A3 2B Ò»¼üʹÓÃÊôÐÔ¹ûʵ #tagCMUseAllAttrFruit  | 
| #  | 
| #struct    tagCMUseAllAttrFruit  | 
| #{  | 
| #    tagHead        Head;  | 
| #    BYTE        FuncIndex;        //¹¦ÄÜË÷Òý  | 
| #};  | 
| ## Ò»¼üʹÓÃÊôÐÔ¹ûʵ  | 
| # @param index  | 
| # @return None  | 
| def OnEatAllFruitItem(index, packData, tick):  | 
|     curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)  | 
|     funcIndex = packData.FuncIndex  | 
|       | 
|     if funcIndex not in ShareDefine.Def_AttrFruitFuncList:  | 
|         GameWorld.ErrLog("¸ÃÊôÐÔ¹ûʵ¹¦ÄÜ먦·Å£¡")  | 
|         return  | 
|       | 
|     addValueDict = {}  | 
|     curPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptItem)  | 
|     for i in range(curPack.GetCount()):  | 
|         item = curPack.GetAt(i)  | 
|         if item == None or item.IsEmpty():  | 
|             continue  | 
|         itemID = item.GetItemTypeID()  | 
|       | 
|         addValue, hasUseCnt = __DoEatFruitItem(curPlayer, item, item.GetCount(), False)  | 
|         if addValue <= 0:  | 
|             continue  | 
|           | 
|         addValueDict[itemID] = addValueDict.get(itemID, 0) + addValue  | 
|           | 
|     GameWorld.DebugLog("OnEatAllFruitItem addValueDict=%s!" % addValueDict)  | 
|     if not addValueDict:  | 
|         return  | 
|       | 
|     Sync_AttrFruitEatCnt(curPlayer, addValueDict.keys())  | 
|       | 
|     # Ôö¼ÓÊôÐÔ  | 
|     for itemid, addValue in addValueDict.items():  | 
|         ipyData = GetAttrFruitIpyData(itemid)  | 
|         funcIndex = ipyData.GetFuncID()  | 
|         __AddFruitAttr(curPlayer, itemid, funcIndex, addValue)  | 
|       | 
|     # Ë¢ÐÂÊôÐÔ  | 
|     __RefreshAttr(curPlayer, funcIndex)  | 
|     return  | 
|   | 
|   | 
|   | 
| ## Íæ¼ÒʹÓÃÊôÐÔ¹ûʵ  | 
| # @param curPlayer  | 
| # @param useCnt Ê¹ÓÃÊýÁ¿  | 
| # @return -1´ú±í·ÇÊôÐÔ¹ûʵ£»True or False´ú±íʹÓóɹ¦Óë·ñ  | 
| def DoPlayerEatFruitItem(curPlayer, curItem, useCnt=1):  | 
|     itemID = curItem.GetItemTypeID()  | 
|     useCnt = max(1, useCnt)  | 
|     ipyData = GetAttrFruitIpyData(itemID, False)  | 
|     # ²»ÊǹûʵÎïÆ·  | 
|     if not ipyData:  | 
|         return -1  | 
|       | 
|     funcIndex = ipyData.GetFuncID()  | 
|     addValue, hasUseCnt = __DoEatFruitItem(curPlayer, curItem, useCnt)  | 
|       | 
|     if not addValue:  | 
|         return False, hasUseCnt  | 
|     Sync_AttrFruitEatCnt(curPlayer, [itemID])  | 
|       | 
|     # Ôö¼ÓÊôÐÔ  | 
|     __AddFruitAttr(curPlayer, itemID, funcIndex, addValue)  | 
|       | 
|     # Ë¢ÐÂÊôÐÔ  | 
|     __RefreshAttr(curPlayer, funcIndex)  | 
|     return True, hasUseCnt  | 
|   | 
| ## Íæ¼ÒʹÓÃÊôÐÔ¹ûʵ  | 
| # @param curPlayer  | 
| # @param useCnt Ê¹ÓÃÊýÁ¿  | 
| # @return Ôö¼ÓÊýÁ¿/ÊôÐÔ,ʵ¼ÊʹÓÃÊýÁ¿  | 
| def __DoEatFruitItem(curPlayer, item, useCnt, isShowMsg=True):  | 
|     itemID = item.GetItemTypeID()  | 
|     DefaultReturn = 0, 0  | 
|     ipyData = GetAttrFruitIpyData(itemID)  | 
|     # ²»ÊǹûʵÎïÆ·  | 
|     if not ipyData:  | 
|         return DefaultReturn  | 
|   | 
|     funcIndex = ipyData.GetFuncID()  | 
|     limitType = Def_LimitType_Cnt  | 
|     maxEatCnt = GetMaxEatCnt(curPlayer, itemID)  | 
|       | 
|     if funcIndex not in ShareDefine.Def_AttrFruitFuncList:  | 
|         GameWorld.ErrLog("¸ÃÊôÐÔ¹ûʵ¹¦ÄÜ먦·Å£¡funcIndex=%s"%funcIndex)  | 
|         return DefaultReturn  | 
|        | 
|     eatCntKey = ChConfig.Def_PDict_AttrFruitEatCnt % itemID  | 
|       | 
|     if limitType == Def_LimitType_Attr:  | 
|         eatCntKey = ChConfig.Def_PDict_AttrFruitAddValue % itemID  | 
|           | 
|           | 
|     eatCnt = curPlayer.NomalDictGetProperty(eatCntKey) # ÒѳԴÎÊý/ÊôÐÔÖµ  | 
|       | 
|     GameWorld.DebugLog("ʹÓÃÊôÐÔ¹ûʵ itemID=%s,limitType=%s,maxEatCnt=%s,eatCnt=%s"   | 
|                        % (itemID, limitType, maxEatCnt, eatCnt))  | 
|       | 
|     hasUseCnt = 0 #ʵ¼ÊʹÓøöÊý  | 
|     addValue = 0  | 
|     for _ in range(useCnt):  | 
|         if eatCnt >= maxEatCnt:  | 
|             GameWorld.DebugLog("    ÒÑ´ïµ½¸ÃµÈ¼¶¶Î×î´ó¸öÊý/ÊôÐÔ£¬²»¿ÉʹÓã¡")  | 
|             break  | 
|           | 
|         # ¸üÐÂʹÓøöÊý  | 
|         curValue = 1 # °´¸öÊýµÄĬÈÏʹÓÃÒ»¸ö  | 
| #        if limitType == Def_LimitType_Attr:  | 
| #            attrFruitRandom = ReadChConfig.GetEvalChConfig("AttrFruitRandom")  | 
| #            if itemID in attrFruitRandom:  | 
| #                randomList = attrFruitRandom[itemID]  | 
| #                curValue = GameWorld.GetResultByRandomList(randomList, 1) # ÖÁÉÙΪ1  | 
| #                GameWorld.DebugLog("    ±ýÍ¼Ëæ»úÊôÐÔµãaddValue=%s" % curValue)  | 
| #            else:  | 
| #                curEff = item.GetEffectByIndex(0) # °´ÊôÐÔµÄĬÈÏȡЧ¹û1µÄABÖµËæ»ú  | 
| #                minValue = curEff.GetEffectValue(0)  | 
| #                maxValue = max(curEff.GetEffectValue(1), minValue)  | 
| #                curValue = random.randint(minValue, maxValue)  | 
| #                GameWorld.DebugLog("    Ð§¹ûÖµAB·¶Î§Ëæ»úÊôÐÔµãaddValue=%s" % curValue)  | 
| #                  | 
| #            curValue = min(curValue, maxEatCnt - eatCnt)  | 
|         eatCnt += curValue  | 
|         hasUseCnt += 1  | 
|         addValue += curValue  | 
|           | 
|     if hasUseCnt <= 0:  | 
|         return DefaultReturn  | 
|     PlayerControl.NomalDictSetProperty(curPlayer, eatCntKey, eatCnt)  | 
|     if funcIndex == ShareDefine.Def_AttrFruitFunc_Stove:  | 
|         PlayerSuccess.DoAddSuccessProgress(curPlayer, ShareDefine.SuccType_UseStoveBylv, hasUseCnt, [item.GetLV()])  | 
|           | 
|     alchemyIpyData = IpyGameDataPY.GetIpyGameDataByCondition("Alchemy", {"AlchemItemID":itemID}, False, True)  | 
|     if alchemyIpyData:  | 
|         PlayerSuccess.DoAddSuccessProgress(curPlayer, ShareDefine.SuccType_UseStoveByType, hasUseCnt, [alchemyIpyData.GetAlchemType()])  | 
|           | 
|     effect = item.GetEffectByIndex(0)  | 
|     effID = effect.GetEffectID()  | 
|     ## ÌØÊâÊôÐÔID´¦Àí£¬´ËÊôÐÔID×öÒ»´ÎÐÔ´¦Àí£¬²»×öÊôÐÔ¼ÆËã  | 
|     if effID == ShareDefine.Def_Effect_FreePoint:  | 
|         effValue = effect.GetEffectValue(0)  | 
|         addFreePoint = effValue * hasUseCnt  | 
|         freePoint = curPlayer.GetFreePoint()  | 
|         updFreePoint = freePoint + addFreePoint  | 
|         curPlayer.SetFreePoint(updFreePoint)  | 
|         GameWorld.DebugLog("µ¤Ò©Ôö¼Ó×ÔÓÉÊôÐÔµã: freePoint=%s,addFreePoint=%s(%s*%s),updFreePoint=%s"   | 
|                            % (freePoint, addFreePoint, effValue, hasUseCnt, updFreePoint))  | 
|           | 
|     ItemCommon.DelItem(curPlayer, item, hasUseCnt, True, ChConfig.ItemDel_AttrFruit)  | 
|     return addValue, hasUseCnt  | 
|   | 
| ## Ë¢Ð¶ÔÓ¦Ë÷ÒýÊôÐÔ  | 
| # @param funcIndex  | 
| # @return None  | 
| def __RefreshAttr(curPlayer, funcIndex):  | 
|     if funcIndex == ShareDefine.Def_AttrFruitFunc_Pet:  | 
|         PlayerPet.RefreshPetItemAddAttr(curPlayer, True)  | 
|     elif funcIndex == ShareDefine.Def_AttrFruitFunc_Horse:  | 
|         PlayerHorse.RefreshHorseAttr(curPlayer)  | 
|     elif funcIndex == ShareDefine.Def_AttrFruitFunc_Stove:  | 
|         PlayerRefineStove.CalcStoveAttr(curPlayer)  | 
|         PlayerControl.PlayerControl(curPlayer).RefreshPlayerAttrState()  | 
|   | 
|     return  | 
|   | 
| ## Ôö¼Ó¹ûʵÔö¼ÓµÄÊôÐÔ»º´æ  | 
| # @param curPlayer  | 
| # @return None  | 
| def __AddFruitAttr(curPlayer, fruitItemID, funcIndex, addValue):  | 
|       | 
|     if addValue < 1:  | 
|         return []  | 
|       | 
|     itemData = GameWorld.GetGameData().GetItemByTypeID(fruitItemID)  | 
|     if not itemData:  | 
|         return []  | 
|       | 
|       | 
|     limitType = Def_LimitType_Cnt #ĬÈϰ´¸öÊý  | 
|       | 
|     # Ôö¼Ó¸½¼ÓÕ½Á¦£¬½ö°´¸öÊýʱÓÐЧ  | 
|     fightPowerExfigKey = ChConfig.Def_PlayerKey_FruitFightPowerEx % (funcIndex)  | 
|     fightPowerEx = curPlayer.GetDictByKey(fightPowerExfigKey)  | 
|     fruitIpyData = GetAttrFruitIpyData(fruitItemID)  | 
|     addFightPowerEx = 0 if not fruitIpyData else fruitIpyData.GetFightPowerEx()  | 
|     fightPowerEx = fightPowerEx + addFightPowerEx * addValue  | 
|     curPlayer.SetDict(fightPowerExfigKey, fightPowerEx)  | 
|     GameWorld.DebugLog("    Add funcIndex=%s,addFightPowerEx=%s,addValue=%s,fightPowerEx=%s" % (funcIndex, addFightPowerEx, addValue, fightPowerEx))  | 
|     attrIDList = []  | 
|     for i in range(itemData.GetEffectCount()):  | 
|         curEffect = itemData.GetEffectByIndex(i)  | 
|         effectID = curEffect.GetEffectID()  | 
|           | 
|         if not effectID or effectID not in ChConfig.ItemEffect_AttrDict or effectID == ShareDefine.Def_Effect_FreePoint:  | 
|             continue  | 
|         attrIDList.append(effectID)  | 
|         attrKey = ChConfig.Def_PlayerKey_FruitAttr % (funcIndex, effectID)  | 
|         curValue = curPlayer.GetDictByKey(attrKey)  | 
|         effValueA = curEffect.GetEffectValue(0)  | 
|         effValueB = curEffect.GetEffectValue(1)  | 
|         if limitType == Def_LimitType_Cnt:  | 
|             updValue = curValue + effValueA * addValue # °´¸öÊýµÄ£¬ÒÔÿ¸öÊôÐÔ*¸öÊý  | 
|         else:  | 
|             updValue = curValue + addValue # ¼ÓÊôÐÔµÄÖ±½Ó¼Ó  | 
|               | 
|         curPlayer.SetDict(attrKey, updValue)  | 
|         GameWorld.DebugLog("    Add funcIndex=%s,effID=%s,curValue=%s,effA=%s,effB=%s,count=%s,updV=%s"   | 
|                            % (funcIndex, effectID, curValue, effValueA, effValueB, addValue, updValue))  | 
|     return attrIDList  | 
|   | 
| ## ¼ÓÔØ¹ûʵÔö¼ÓµÄÊôÐÔ»º´æ£¬Ò»°ãÊǵǼ»òÇеØÍ¼ºó  | 
| # @param curPlayer  | 
| # @return None  | 
| def __InitPlayerAttrFruit(curPlayer):  | 
|     hadInit = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_HadInitFruitAttr)  | 
|     if hadInit:  | 
|         return  | 
|     GameWorld.DebugLog("__InitPlayerAttrFruit")  | 
|       | 
|     ipyDataMgr = IpyGameDataPY.IPY_Data()  | 
|     maxCnt = ipyDataMgr.GetAttrFruitCount()  | 
|     for i in xrange(maxCnt):  | 
|         ipyData = ipyDataMgr.GetAttrFruitByIndex(i)  | 
|         fruitItemID = ipyData.GetID()  | 
|         funcIndex = ipyData.GetFuncID() # ËùÊô¹¦ÄÜ  | 
|         limitType = Def_LimitType_Cnt # ÏÞÖÆÀàÐÍ  | 
|         eatCntKey = ChConfig.Def_PDict_AttrFruitEatCnt % fruitItemID  | 
|         if limitType == Def_LimitType_Attr:  | 
|             eatCntKey = ChConfig.Def_PDict_AttrFruitAddValue % fruitItemID  | 
|               | 
|         eatCnt = curPlayer.NomalDictGetProperty(eatCntKey)  | 
|         __AddFruitAttr(curPlayer, fruitItemID, funcIndex, eatCnt)  | 
|       | 
|     # ÉèÖñ¾µØÍ¼ÒѾˢйý  | 
|     curPlayer.SetDict(ChConfig.Def_PlayerKey_HadInitFruitAttr, 1)  | 
|     return  | 
|   | 
| ## ¼ÆËãÊôÐÔ¹ûʵÔö¼ÓµÄÊôÐÔ  | 
| # @param curPlayer  | 
| # @param allAttrList  | 
| # @param funcIndex ¶ÔÓ¦¹¦ÄÜË÷Òý  | 
| # @return None  | 
| def CalcAttrFruitAddAtrr(curPlayer, allAttrList, funcIndex):  | 
|     #GameWorld.DebugLog("CalcAttrFruitAddAtrr...funcIndex=%s" % (funcIndex))  | 
|     #GameWorld.DebugLog("    ÎÞ¹ûʵÊôÐÔ allAttrList=%s" % str(allAttrList))  | 
|     __InitPlayerAttrFruit(curPlayer)  | 
|   | 
|     for effectID in ChConfig.ItemEffect_AttrDict:  | 
|           | 
|         if not isinstance(effectID, int):  | 
|             continue  | 
|           | 
|         attrKey = ChConfig.Def_PlayerKey_FruitAttr % (funcIndex, effectID)  | 
|         addValue = curPlayer.GetDictByKey(attrKey)  | 
|         if not addValue:  | 
|             continue  | 
|           | 
|         #GameWorld.DebugLog("    effectID=%s,addValue=%s" % (effectID, addValue))  | 
|         PlayerControl.CalcAttrDict_Type(effectID, addValue, allAttrList)  | 
|   | 
|     fightPowerEx = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_FruitFightPowerEx % (funcIndex))  | 
|     #GameWorld.DebugLog("    ÓйûʵÊôÐÔfuncIndex=%s,fightPowerEx=%s,allAttrList=%s" % (funcIndex, fightPowerEx, allAttrList))  | 
|     return fightPowerEx  | 
|       | 
|   | 
| ## Í³¼Æ°Ù·Ö±ÈÊôÐÔ¶Ô¹¦ÄÜÄÚ²ãµÄÊôÐÔÔö¼Ó  | 
| #  @param curPlayer   | 
| #  @param funcIndex   | 
| #  @return None  | 
| def AddFuncPerValue(curPlayer, funcIndex, effPerID, allAttrList):  | 
|     attrPerKey = ChConfig.Def_PlayerKey_FruitAttr % (funcIndex, effPerID)  | 
|     addPer = curPlayer.GetDictByKey(attrPerKey)  | 
|       | 
|     if addPer <= 0:  | 
|         return  | 
|       | 
|     #[ÊôÐÔË÷Òý, ÊÇ·ñ»ù´¡ÊôÐÔ£¬(·Ç)ÏßÐÔ]  | 
|     attrInfo = ChConfig.ItemEffect_AttrDict.get(effPerID, [])  | 
|     if attrInfo is []:  | 
|         return  | 
|       | 
|     addAttrList = attrInfo[0]  | 
|     for attrDict in allAttrList:  | 
|         for attrIndex, attrValue in attrDict.items():  | 
|             # ·Ç°Ù·Ö±ÈÔö¼ÓµÄÊôÐÔ  | 
|             if attrIndex not in addAttrList:  | 
|                 continue  | 
|               | 
|             addPerValue = int(attrValue * addPer / ShareDefine.Def_MaxRateValue) # °Ù·Ö±ÈÔö¼ÓÊôÐÔ  | 
|               | 
|             updValue = attrValue + addPerValue  | 
|             attrDict[attrIndex] = updValue  | 
|   | 
|             #GameWorld.DebugLog("    effPerID=%s,attrValue=%s,addPer=%s,addPerValue=%s,updValue=%s"   | 
|             #                   % (effPerID, attrValue, addPer, addPerValue, updValue))  | 
|   | 
|     return True  | 
|   | 
|           | 
| ## Í¬²½ÊôÐÔ¹ûʵʹÓÃÇé¿ö  | 
| #  @param curPlayer   | 
| #  @param fruitItemID   | 
| #  @return None  | 
| def Sync_AttrFruitEatCnt(curPlayer, fruitItemIDList=None):  | 
|       | 
|     eatPack = ChPyNetSendPack.tagMCAttrFruitEatCntList()  | 
|     eatPack.Clear()  | 
|     eatPack.EatCntList = []  | 
|     if fruitItemIDList is None:  | 
|         itemidList = []  | 
|         ipyDataMgr = IpyGameDataPY.IPY_Data()  | 
|         maxCnt = ipyDataMgr.GetAttrFruitCount()  | 
|         for i in xrange(maxCnt):  | 
|             ipyData = ipyDataMgr.GetAttrFruitByIndex(i)  | 
|             itemID = ipyData.GetID()  | 
|             itemidList.append(itemID)  | 
|           | 
|     else:  | 
|         itemidList = fruitItemIDList  | 
|           | 
|       | 
|     for fruitItemID in itemidList:  | 
|         eatCntKey = ChConfig.Def_PDict_AttrFruitEatCnt % fruitItemID  | 
|         #addValueKey = ChConfig.Def_PDict_AttrFruitAddValue % fruitItemID  | 
|         eatCntPack = ChPyNetSendPack.tagMCAttrFruitEatCnt()  | 
|         eatCntPack.Clear()  | 
|         eatCntPack.ItemID = fruitItemID  | 
|         eatCntPack.EatCnt = curPlayer.NomalDictGetProperty(eatCntKey)  | 
|         eatCntPack.ItemAddCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AttrFruitAddItemCnt % fruitItemID)  | 
|         eatCntPack.ItemBreakCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AttrFruitItemBreakCnt % fruitItemID)  | 
|         eatPack.EatCntList.append(eatCntPack)  | 
|       | 
|     eatPack.count = len(eatPack.EatCntList)  | 
|     NetPackCommon.SendFakePack(curPlayer, eatPack)  | 
|     return  | 
|   | 
| ## ÊôÐÔ¹ûʵÒѳԸöÊý×Öµä  | 
| #  @param curPlayer   | 
| #  @param fruitItemID   | 
| #  @return {id:¸öÊý,...}  | 
| def GetAttrFruitEatCntDict(curPlayer):  | 
|     eatCntDict = {}  | 
|       | 
|     ipyDataMgr = IpyGameDataPY.IPY_Data()  | 
|     maxCnt = ipyDataMgr.GetAttrFruitCount()  | 
|     for i in xrange(maxCnt):  | 
|         ipyData = ipyDataMgr.GetAttrFruitByIndex(i)  | 
|         fruitItemID = ipyData.GetID()  | 
|         eatCntKey = ChConfig.Def_PDict_AttrFruitEatCnt % fruitItemID  | 
| #        if fruitInfo[Def_LimitType] == Def_LimitType_Attr:  | 
| #            eatCntKey = ChConfig.Def_PDict_AttrFruitAddValue % fruitItemID  | 
| #            dayEatCntKey = ChConfig.Def_PDict_AttrFruitDayAddValue % fruitItemID  | 
|               | 
|         eatCnt = curPlayer.NomalDictGetProperty(eatCntKey) # ÒѳԴÎÊý/ÊôÐÔÖµ  | 
|         if eatCnt <= 0:  | 
|             continue  | 
|           | 
|         eatCntDict[fruitItemID] = eatCnt  | 
|           | 
|     return eatCntDict  | 
|   | 
| def IsFruitEatFull(curPlayer, itemID):  | 
|     #ʹÓôÎÊýÊÇ·ñÒÑÂú  | 
|     maxEatCnt = GetMaxEatCnt(curPlayer, itemID)  | 
|     eatCntKey = ChConfig.Def_PDict_AttrFruitEatCnt % itemID  | 
|     limitType = Def_LimitType_Cnt  | 
|     if limitType == Def_LimitType_Attr:  | 
|         eatCntKey = ChConfig.Def_PDict_AttrFruitAddValue % itemID  | 
|     eatCnt = curPlayer.NomalDictGetProperty(eatCntKey) # ÒѳԴÎÊý/ÊôÐÔÖµ  | 
|     if eatCnt >= maxEatCnt:  | 
|         return True  | 
|     return  | 
|   | 
| def GetMaxEatCnt(curPlayer, itemID):  | 
|     ##»ñÈ¡¹ûʵ×î´ó¿ÉÓøöÊý  | 
|     ipyData = GetAttrFruitIpyData(itemID)  | 
|     if not ipyData:  | 
|         return 0  | 
|     maxEatCntDict = ipyData.GetMaxUseCnt()  | 
|     realmLV = curPlayer.GetOfficialRank()  | 
|     orderList = sorted(maxEatCntDict.keys(), reverse=True)  | 
|     maxEatCnt = 0  | 
|     for order in orderList:  | 
|         if realmLV >= order:  | 
|             maxEatCnt = maxEatCntDict[order]  | 
|             break  | 
|     addItemUseCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AttrFruitAddItemCnt % itemID)  | 
|     maxEatCnt += addItemUseCnt  | 
|     return maxEatCnt  | 
|   | 
|   | 
| #// A3 17 Ôö¼Ó¹ûʵʹÓÃÉÏÏÞ #tagCMAddFruitUseLimit  | 
| #  | 
| #struct    tagCMAddFruitUseLimit  | 
| #{  | 
| #    tagHead        Head;  | 
| #    DWORD        ItemID;        //¹ûʵÎïÆ·ID  | 
| #};  | 
| def OnAddFruitUseLimit(index, packData, tick):  | 
|     curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)  | 
|     itemID = packData.ItemID  | 
|     ipyData = GetAttrFruitIpyData(itemID)  | 
|     if not ipyData:  | 
|         return  | 
|     addItemInfoList = ipyData.GetAddItemInfo()  | 
|     if not addItemInfoList:  | 
|         return  | 
|     itemBreakCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AttrFruitItemBreakCnt % itemID)  | 
|     itemAddUseCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AttrFruitAddItemCnt % itemID)  | 
|     needUseCnt = canUpCnt = 0  | 
|     for breakCnt, useCnt, upCnt in addItemInfoList:  | 
|         if itemBreakCnt >= breakCnt:  | 
|             continue  | 
|         needUseCnt, canUpCnt = useCnt, upCnt  | 
|         break  | 
|     if not needUseCnt:  | 
|         return  | 
|   | 
|     needItemID = IpyGameDataPY.GetFuncCfg('AlchemyOverLimit')  | 
|     if itemAddUseCnt + canUpCnt> ChConfig.Def_UpperLimit_DWord:  | 
|         return  | 
|     itemPack = curPlayer.GetItemManager().GetPack(IPY_GameWorld.rptItem)  | 
|     enough, indexList, hasBind, lackCnt = ItemCommon.GetItem_FromPack_ByID_ExEx(needItemID, itemPack, needUseCnt)  | 
|     if not enough:  | 
|         return  | 
|     ItemCommon.ReduceItem(curPlayer, itemPack, indexList, needUseCnt, False, "AddFruitUseLimit")  | 
|     PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_AttrFruitAddItemCnt % itemID, itemAddUseCnt+canUpCnt)  | 
|     PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_AttrFruitItemBreakCnt % itemID,  | 
|                                        itemBreakCnt + 1)  | 
|     Sync_AttrFruitEatCnt(curPlayer, [itemID])  | 
|     return  |