| #!/usr/bin/python  | 
| # -*- coding: GBK -*-  | 
| #-------------------------------------------------------------------------------  | 
| #  | 
| #-------------------------------------------------------------------------------  | 
| #  | 
| ##@package Player.PlayerRune  | 
| #  | 
| # @todo:Íæ¼Ò·ûÓ¡  | 
| # @author xdh  | 
| # @date 2017-08-04  | 
| # @version 1.0  | 
| #  | 
| # ÏêϸÃèÊö: Íæ¼Ò·ûÓ¡  | 
| #---------------------------------------------------------------------  | 
| #"""Version = 2017-08-04 12:00"""  | 
| #---------------------------------------------------------------------  | 
|   | 
| import GameWorld  | 
| import ShareDefine  | 
| import ChConfig  | 
| import ItemCommon  | 
| import ItemControler  | 
| import PlayerControl  | 
| import ChPyNetSendPack  | 
| import NetPackCommon  | 
| import IpyGameDataPY  | 
| import PlayerSuccess  | 
| import PlayerMagicWeapon  | 
| import IPY_GameWorld  | 
| import OpenServerCampaign  | 
|   | 
| g_runeLVExpDict = {}  | 
|   | 
| ##µÇ¼´¦Àí  | 
| # @param curPlayer Íæ¼Ò  | 
| # @return None  | 
| def PlayerRuneLogin(curPlayer):  | 
|     if not GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_Player_Dict_VersionFix, ChConfig.Def_VerFix_RuneSource):  | 
|         GameWorld.SetDictValueByBit(curPlayer, ChConfig.Def_Player_Dict_VersionFix, ChConfig.Def_VerFix_RuneSource, 1)  | 
|         runeHoleCnt = IpyGameDataPY.GetFuncCfg("RuneUnlock", 4)  | 
|         for RuneNum in xrange(1, runeHoleCnt + 1):  | 
|             RuneData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_Rune_Data % RuneNum, 0)  | 
|             if not RuneData:  | 
|                 continue  | 
|             RuneItemID = ItemControler.GetRuneItemID(RuneData)  | 
|             ipyData = IpyGameDataPY.GetIpyGameDataNotLog('RuneCompound', RuneItemID)  | 
|             if not ipyData:  | 
|                 continue  | 
|             RuneSource = ItemControler.GetRuneItemSource(RuneData)  | 
|             if RuneSource != ChConfig.Item_Source_Compound:  | 
|                 RuneItemPlusLV = ItemControler.GetRuneItemPlusLV(RuneData)  | 
|                 RuneIsLock = ItemControler.GetRuneItemIsLock(RuneData)  | 
|                 updRuneData = ItemControler.GetRuneItemKeyData(RuneItemID, RuneItemPlusLV, RuneIsLock, ChConfig.Item_Source_Compound)  | 
|                 PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_Rune_Data % RuneNum, updRuneData)  | 
|                 GameWorld.Log('ÉÏÏßÐÞ¸´Ë«ÊôÐÔ·ûÓ¡À´Ô´ RuneNum=%s,oldRuneData=%s,updRuneData=%s'%(RuneNum, RuneData, updRuneData))  | 
|         packIndex = ShareDefine.rptRune  | 
|         for place in xrange(ItemCommon.GetVPackCnt(packIndex)):  | 
|             RuneData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_VPackItem % (packIndex, place))  | 
|             if not RuneData:  | 
|                 continue  | 
|             RuneItemID = ItemControler.GetRuneItemID(RuneData)  | 
|             ipyData = IpyGameDataPY.GetIpyGameDataNotLog('RuneCompound', RuneItemID)  | 
|             if not ipyData:  | 
|                 continue  | 
|             RuneSource = ItemControler.GetRuneItemSource(RuneData)  | 
|             if RuneSource != ChConfig.Item_Source_Compound:  | 
|                 RuneItemPlusLV = ItemControler.GetRuneItemPlusLV(RuneData)  | 
|                 RuneIsLock = ItemControler.GetRuneItemIsLock(RuneData)  | 
|                 updRuneData = ItemControler.GetRuneItemKeyData(RuneItemID, RuneItemPlusLV, RuneIsLock, ChConfig.Item_Source_Compound)  | 
|                 ItemControler.SetVPackItemKeyData(curPlayer, ShareDefine.rptRune, place, updRuneData)  | 
|                 GameWorld.Log('ÉÏÏßÐÞ¸´Ë«ÊôÐÔ·ûÓ¡À´Ô´ place=%s,oldRuneData=%s,updRuneData=%s'%(place, RuneData, updRuneData))  | 
|       | 
|       | 
|     DoUnlockRuneHole(curPlayer, False)  | 
|     Sync_RuneInfo(curPlayer)  | 
|     return  | 
|   | 
|   | 
| ## »ñÈ¡·ûÓ¡ipyÊý¾Ý  | 
| def GetRuneIpyData(itemID):return IpyGameDataPY.GetIpyGameData("Rune", itemID)  | 
|   | 
| ## »ñÈ¡·ûÓ¡Éý¼¶ÐèÒª¾Ñé  | 
| def GetRuneNeedExp(itemID, lv):  | 
|     global g_runeLVExpDict  | 
|     itemData = GameWorld.GetGameData().GetItemByTypeID(itemID)  | 
|     if not itemData:  | 
|         return 0  | 
|     ipyData = GetRuneIpyData(itemID)  | 
|     if not ipyData:  | 
|         return 0  | 
|     itemColor = itemData.GetItemColor()  | 
|     if lv == 0: #³õʼ¾Ñé  | 
|         expDict = IpyGameDataPY.GetFuncEvalCfg('RuneExp', 4, {})  | 
|         exp = expDict.get(itemColor, 0)  | 
|     else:  | 
|         if lv in g_runeLVExpDict:  | 
|             exp = g_runeLVExpDict[lv]  | 
|         else:  | 
|             level = lv + 1 #¹«Ê½´Ó1¿ªÊ¼  | 
|             exp = eval(IpyGameDataPY.GetFuncCompileCfg('RuneExp'))  | 
|             g_runeLVExpDict[lv] = exp  | 
|               | 
|         qualityPerDict = IpyGameDataPY.GetFuncEvalCfg('RuneExp', 2, {})  | 
|         if itemColor in qualityPerDict:  | 
|             exp *= float(qualityPerDict[itemColor])  | 
|         if len(ipyData.GetAttrType()) > 1: #¶àÊôÐÔ  | 
|             specialPer = IpyGameDataPY.GetFuncCfg('RuneExp', 3)  | 
|             exp *= specialPer  | 
|     return exp  | 
|   | 
| ## »ñÈ¡·ûÓ¡ÊôÐÔÊýÖµ  | 
| def GetRuneAttrValue(itemID, lv):  | 
|     itemData = GameWorld.GetGameData().GetItemByTypeID(itemID)  | 
|     if not itemData:  | 
|         return {}  | 
|     ipyData = GetRuneIpyData(itemID)  | 
|     if not ipyData:  | 
|         return {}  | 
|     level = lv + 1 #¹«Ê½´Ó1¿ªÊ¼  | 
|       | 
|     attrTypeList = ipyData.GetAttrType()  | 
|     isSpecial = len(attrTypeList) > 1 #ÊÇ·ñ¶àÊôÐÔ  | 
|     itemColor = itemData.GetItemColor()  | 
|     attrDict = {}  | 
|     for attrType in attrTypeList:  | 
|         keyStr = 'RuneAttr%s' % attrType  | 
|         attrFormula = IpyGameDataPY.GetFuncCompileCfg(keyStr)  | 
|         if not attrFormula:  | 
|             continue  | 
|           | 
|         value = eval(attrFormula)  | 
|         qualityPerDict = IpyGameDataPY.GetFuncEvalCfg(keyStr, 2, {})  | 
|         if itemColor in qualityPerDict:  | 
|             value *= float(qualityPerDict[itemColor])  | 
|         if isSpecial:  | 
|             specialPer = IpyGameDataPY.GetFuncCfg(keyStr, 3)  | 
|             if specialPer:  | 
|                 value *= specialPer  | 
|             else:  | 
|                 GameWorld.ErrLog(' itemID=%s   ¹¦ÄÜÅäÖñíkeyStr=%s, ÊýÖµ3δÅäÖÃ' % (itemID, keyStr))  | 
|         attrDict[int(attrType)] = int(value)  | 
|     return attrDict  | 
|   | 
| def GetRuneMaxLV(itemID):  | 
|     # »ñÈ¡·ûÓ¡×î´óµÈ¼¶  | 
|     itemData = GameWorld.GetGameData().GetItemByTypeID(itemID)  | 
|     if not itemData:  | 
|         return 0  | 
|     runeMaxLVDict = IpyGameDataPY.GetFuncEvalCfg('RuneMaxLV', 1, {})  | 
|     itemColor = itemData.GetItemColor()  | 
|     runeMaxLV = runeMaxLVDict.get(itemColor, 0)  | 
|     return runeMaxLV  | 
|   | 
| #// A5 13 ½âËø·ûÓ¡¿× #tagCMUnlockRuneHole  | 
| #  | 
| #struct    tagCMUnlockRuneHole  | 
| #{  | 
| #    tagHead        Head;  | 
| #    BYTE        HoleIndex; // ¿×Ë÷Òý  | 
| #};  | 
| def OnUnlockRuneHole(index, clientData, tick):  | 
|     curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)  | 
|     holeIndex = clientData.HoleIndex  | 
|     runeUnlockDict = IpyGameDataPY.GetFuncEvalCfg("RuneUnlock", 2, {})  | 
|     if holeIndex not in runeUnlockDict:  | 
|         return  | 
|     runeOpenState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_Rune_HoleOpenState, 0)  | 
|     if runeOpenState & pow(2, holeIndex):  | 
|         return  | 
|     if curPlayer.GetLV() < IpyGameDataPY.GetFuncEvalCfg("RuneUnlock", 3, {}).get(holeIndex, 0):  | 
|         return  | 
|     costMoney = runeUnlockDict[holeIndex]  | 
|     if not PlayerControl.PayMoney(curPlayer, IPY_GameWorld.TYPE_Price_Gold_Money, costMoney, ChConfig.Def_Cost_RuneHole, {'holeIndex':holeIndex}):  | 
|         return  | 
|     PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_Rune_HoleOpenState, runeOpenState |pow(2, holeIndex))  | 
|     Sync_RuneInfo(curPlayer)  | 
|     PlayerControl.WorldNotify(0, 'RuneSpecialHoleGet', [curPlayer.GetName(), costMoney])  | 
|     return  | 
|   | 
| def DoUnlockRuneHole(curPlayer, isSycn=True):  | 
|     # ½âËø·ûÓ¡¿×, ·ûÓ¡Ëþ¹ý¹ØÊ±µ÷Óà  | 
|     runeUnlockList = IpyGameDataPY.GetFuncEvalCfg("RuneUnlock")  | 
|       | 
|     runeOpenState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_Rune_HoleOpenState, 0)  | 
|     trialTowerPassLV = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_TrialTower_PassLV) # ·ûÓ¡ËþÒѹý¹Ø²ãÊý  | 
|     updOpenState = runeOpenState  | 
|     for holeNum, needTowerPassLV in enumerate(runeUnlockList):  | 
|         if runeOpenState & pow(2, holeNum):  | 
|             continue  | 
|           | 
|         if trialTowerPassLV < needTowerPassLV:  | 
|             continue  | 
|         updOpenState |= pow(2, holeNum)  | 
|         GameWorld.DebugLog('    ½âËø·ûÓ¡¿× holeNum=%s,trialTowerPassLV=%s' % (holeNum, trialTowerPassLV))  | 
|     if updOpenState != runeOpenState:  | 
|         PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_Rune_HoleOpenState, updOpenState)  | 
|         if isSycn:  | 
|             Sync_RuneInfo(curPlayer)  | 
|     return  | 
|   | 
| ## »ñÈ¡·ûÓ¡ÊÇ·ñÒѽâËø  | 
| def GetIsOpenByRuneID(curPlayer, itemid):  | 
|     itemData = GameWorld.GetGameData().GetItemByTypeID(itemid)  | 
|     if not itemData:  | 
|         return  | 
|     curPassLV = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_TrialTower_PassLV)  | 
|     curEff = itemData.GetEffectByIndex(0)  | 
|     curRuneType = curEff.GetEffectID()  | 
|     floorCnt = IpyGameDataPY.GetFuncCfg('TowerRuneType', 2)  | 
|     towerRuneTypeDict = IpyGameDataPY.GetFuncEvalCfg('TowerRuneType')  | 
|     for floor, typeList in towerRuneTypeDict.items():  | 
|         if curRuneType in typeList:  | 
|             floorkey = (int(floor) - 1)*100+ floorCnt if int(floor) > 1 else 0  | 
|             return curPassLV >= floorkey  | 
|     # Ã»ÅäÖÃÏÞÖÆ²ãÊý½âËøµÄĬÈϽâËø  | 
|     return True  | 
|   | 
| def SwitchRune(curPlayer, srcBackpack, desBackPack, srcIndex, destIndex):  | 
|     # ÏâǶ/ժϷûÓ¡  | 
|     if not ((desBackPack == ShareDefine.rptRune and srcBackpack == ShareDefine.rptTempSwap) \  | 
|             or (srcBackpack == ShareDefine.rptRune and desBackPack == ShareDefine.rptTempSwap)):  | 
|         return False  | 
|       | 
|   | 
|     maxRuneHole = IpyGameDataPY.GetFuncCfg("RuneUnlock", 4)  | 
|     # ´©  | 
|     if desBackPack == ShareDefine.rptTempSwap:  | 
|         desRuneNum = destIndex + 1  | 
|         if desRuneNum < 1 or desRuneNum > maxRuneHole:  | 
|             GameWorld.DebugLog("²»´æÔڸ÷ûÓ¡¿×! desRuneNum=%s" % desRuneNum, curPlayer.GetPlayerID())  | 
|             return True  | 
|           | 
|         runeOpenState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_Rune_HoleOpenState, 0)  | 
|         if not runeOpenState & pow(2, destIndex):  | 
|             GameWorld.DebugLog("¸Ã·ûÓ¡¿×δ½âËø! desRuneNum=%s,state=%s" % (desRuneNum, runeOpenState), curPlayer.GetPlayerID())  | 
|             return True  | 
|           | 
|         srcRuneData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_VPackItem   | 
|                                                      % (ShareDefine.rptRune, srcIndex)) # ·ûÓ¡±³°üÖеÄÖµ  | 
|         if not srcRuneData:  | 
|             GameWorld.DebugLog("·ûÓ¡±³°ü¸ÃλÖÃûÓзûÓ¡! srcIndex=%s" % srcIndex, curPlayer.GetPlayerID())  | 
|             return True  | 
|         srcRuneItemID = ItemControler.GetRuneItemID(srcRuneData)  | 
|           | 
|         srcIpyData = GetRuneIpyData(srcRuneItemID)  | 
|           | 
|         if not srcIpyData:  | 
|             GameWorld.DebugLog("¸Ã·ûӡûÓÐÅäÖÃÊôÐÔ! ÎÞ·¨ÏâǶ! itemID=%s" % srcRuneItemID, curPlayer.GetPlayerID())  | 
|             return True  | 
|         srcRuneAttrType = srcIpyData.GetAttrType()  | 
|         # ÅжÏÊÇ·ñÒÑÓÐÏâǶ¸ÃÊôÐÔÀàÐÍ  | 
|         doubleCnt = 0 #Ë«ÊôÐÔ·ûÓ¡¸öÊý  | 
|         for RuneNum in xrange(1, maxRuneHole + 1):  | 
|             if RuneNum == desRuneNum: # Ä¿±ê¿×²»ÅÐ¶Ï  | 
|                 continue  | 
|             RuneData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_Rune_Data % RuneNum, 0)  | 
|             if not RuneData:  | 
|                 continue  | 
|             RuneItemID = ItemControler.GetRuneItemID(RuneData)  | 
|             ipyData = GetRuneIpyData(RuneItemID)  | 
|             if not ipyData:  | 
|                 continue  | 
|             attrTypeList = ipyData.GetAttrType()  | 
|             if srcRuneAttrType == attrTypeList:  | 
|                 GameWorld.DebugLog("ÒÑÓÐÏâǶ¸ÃÊôÐÔÀàÐÍ! ÎÞ·¨ÏâǶ! RuneHoleNum=%s,srcRuneAttrType=%s" % (RuneNum, srcRuneAttrType), curPlayer.GetPlayerID())  | 
|                 return True  | 
|             if len(attrTypeList) > 1:  | 
|                 doubleCnt +=1  | 
|           | 
|         if len(srcRuneAttrType) > 1 and doubleCnt >= __GetCanInlayDoubleAttrRuneCnt(curPlayer):  | 
|             GameWorld.DebugLog("µ±Ç°¿ÉÏâǶ˫ÊôÐÔ·ûÓ¡¸öÊýÒÑ´ïÉÏÏÞ%s! ÎÞ·¨ÏâǶ! itemID=%s" % (doubleCnt, srcRuneItemID), curPlayer.GetPlayerID())  | 
|             return True  | 
|           | 
|         desRuneData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_Rune_Data % desRuneNum, 0) # ¿×ÉϵÄÖµ  | 
|           | 
|         # ÉèÖ÷ûÓ¡¿×Êý¾Ý  | 
|         PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_Rune_Data % desRuneNum, srcRuneData)  | 
|         # ÔÀ´µÄ¿×Êý¾Ý£¬Ôò·ÅÈë·ûÓ¡±³°üÖÐ  | 
|         ItemControler.SetVPackItemKeyData(curPlayer, ShareDefine.rptRune, srcIndex, desRuneData)  | 
|         #·ûÓ¡³É¾Í  | 
|         DoRuneSuccessLogic(curPlayer)  | 
|     else:  | 
|         srcRuneNum = srcIndex + 1  | 
|         srcRuneData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_Rune_Data % srcRuneNum, 0)  | 
|         if not srcRuneData:  | 
|             GameWorld.DebugLog("¸Ã·ûÓ¡¿×ûÓÐÏâǶ·ûÓ¡! srcRuneNum=%s, srcRuneData=%s" % (srcRuneNum, srcRuneData), curPlayer.GetPlayerID())  | 
|             return True  | 
|           | 
|         emptyIndex = ItemCommon.GetEmptyIndexInPack(curPlayer, ShareDefine.rptRune)  | 
|         if emptyIndex == -1:  | 
|             GameWorld.DebugLog("·ûÓ¡±³°üÒÑÂú£¬ÎÞ·¨ÕªÏÂ! ", curPlayer.GetPlayerID())  | 
|             return True  | 
|           | 
|         # ÕªÏÂÉèÖÿ×Êý¾ÝΪ0  | 
|         PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_Rune_Data % srcRuneNum, 0)  | 
|         ItemControler.SetVPackItemKeyData(curPlayer, ShareDefine.rptRune, emptyIndex, srcRuneData)  | 
|       | 
|     RefreshRuneAttr(curPlayer)  | 
|     PlayerControl.PlayerControl(curPlayer).RefreshPlayerAttrState()  | 
|     Sync_RuneInfo(curPlayer)  | 
|     return True  | 
|   | 
| def __GetCanInlayDoubleAttrRuneCnt(curPlayer):  | 
|     ##µ±Ç°¿ÉÏâǶ¼¸¸öË«ÊôÐÔ·ûÓ¡  | 
|     runeDoubleInlayCntDict = IpyGameDataPY.GetFuncEvalCfg('RuneDoubleInlayCnt', 1, {})  | 
|     trialTowerPassLV = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_TrialTower_PassLV) # ·ûÓ¡ËþÒѹý¹Ø²ãÊý  | 
|     sortLVList = sorted(runeDoubleInlayCntDict.keys())  | 
|     findLV = 0  | 
|     for plv in sortLVList:  | 
|         if trialTowerPassLV < plv:  | 
|             break  | 
|         findLV = plv  | 
|     return runeDoubleInlayCntDict.get(findLV, 0)  | 
|   | 
| #// A5 65 ·ûÓ¡Éý¼¶ #tagCMRuneUp  | 
| #  | 
| #struct    tagCMRuneUp  | 
| #{  | 
| #    tagHead        Head;  | 
| #    BYTE        PlaceType;    // Î»ÖÃÀàÐÍ£»0-·ûÓ¡±³°ü£¬1-·ûÓ¡¿×  | 
| #    WORD        PlaceIndex;    // Î»ÖÃË÷Òý  | 
| #};  | 
| def OnRuneUp(index, clientData, tick):  | 
|     curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)  | 
|     placeType = clientData.PlaceType  | 
|     placeIndex = clientData.PlaceIndex  | 
|       | 
|     if placeType == 0:  | 
|         RuneData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_VPackItem % (ShareDefine.rptRune, placeIndex))  | 
|     elif placeType == 1:  | 
|         RuneData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_Rune_Data % (placeIndex + 1), 0)  | 
|     else:  | 
|         return  | 
|       | 
|     playerID = curPlayer.GetPlayerID()  | 
|     if not RuneData:  | 
|         GameWorld.DebugLog("¸ÃλÖò»´æÔÚ·ûÓ¡, ÎÞ·¨Éý¼¶! placeType=%s,placeIndex=%s" % (placeType, placeIndex), playerID)  | 
|         return  | 
|       | 
|     RuneItemID = ItemControler.GetRuneItemID(RuneData)  | 
|     RuneItemPlusLV = ItemControler.GetRuneItemPlusLV(RuneData)  | 
|     RuneIsLock = ItemControler.GetRuneItemIsLock(RuneData)  | 
|     RuneSource = ItemControler.GetRuneItemSource(RuneData)  | 
|     itemData = GameWorld.GetGameData().GetItemByTypeID(RuneItemID)  | 
|     if not itemData:  | 
|         return  | 
|       | 
|     runeMaxLV = GetRuneMaxLV(RuneItemID)  | 
|     if RuneItemPlusLV + 1 >= runeMaxLV:  | 
|         GameWorld.DebugLog('¸Ã·ûÓ¡ÒÑÂú¼¶£¬ÎÞ·¨Éý¼¶£¡runeMaxLV=%s' % runeMaxLV)  | 
|         return  | 
|       | 
|     plusCost = GetRuneNeedExp(RuneItemID, RuneItemPlusLV + 1)  | 
|     plusCost = int(plusCost)  | 
|     if not plusCost:  | 
|         GameWorld.DebugLog("¸Ã·ûÓ¡ÎÞ·¨Éý¼¶!  placeType=%s,placeIndex=%s,itemID=%s,plusLV=%s"   | 
|                            % (placeType, placeIndex, RuneItemID, RuneItemPlusLV), playerID)  | 
|         return  | 
|   | 
|       | 
|     updRuneData = ItemControler.GetRuneItemKeyData(RuneItemID, RuneItemPlusLV + 1, RuneIsLock, RuneSource)  | 
|     if not PlayerControl.PayMoney(curPlayer, ShareDefine.TYPE_Price_Rune, plusCost):  | 
|         curRuneMoney = PlayerControl.GetMoney(curPlayer, ShareDefine.TYPE_Price_Rune)  | 
|         GameWorld.DebugLog("·ûÓ¡¾«»ªµã²»×㣬ÎÞ·¨Éý¼¶!placeType=%s,placeIndex=%s,itemID=%s,plusLV=%s,plusCost=%s,curRuneMoney=%s"   | 
|                            % (placeType, placeIndex, RuneItemID, RuneItemPlusLV, plusCost, curRuneMoney), playerID)  | 
|         return  | 
|       | 
|     if placeType == 0:  | 
|         ItemControler.SetVPackItemKeyData(curPlayer, ShareDefine.rptRune, placeIndex, updRuneData)  | 
|     elif placeType == 1:  | 
|         PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_Rune_Data % (placeIndex + 1), updRuneData)  | 
|         RefreshRuneAttr(curPlayer)  | 
|         PlayerControl.PlayerControl(curPlayer).RefreshPlayerAttrState()  | 
|         Sync_RuneInfo(curPlayer)  | 
|         DoRuneSuccessLogic(curPlayer)  | 
|           | 
|     #itemData = GameWorld.GetGameData().GetItemByTypeID(RuneItemID)  | 
|     #RuneName = RuneItemID if not itemData else "%s(%s)" % (itemData.GetName(), RuneItemID)  | 
|     #aftRuneMoney = PlayerControl.GetMoney(curPlayer, ShareDefine.TYPE_Price_Rune)  | 
|     #EventReport.WriteEvent_rune_lv(curPlayer, RuneName, plusCost, RuneItemPlusLV + 1, aftRuneMoney)  | 
|     GameWorld.DebugLog("·ûÓ¡Éý¼¶!placeType=%s,placeIndex=%s,RuneData=%s,updRuneData=%s"   | 
|                        % (placeType, placeIndex, RuneData, updRuneData), playerID)  | 
|     return  | 
|   | 
|   | 
| def DoRuneSuccessLogic(curPlayer):  | 
|     #·ûÓ¡³É¾Í´¦Àí  | 
|     #Çåµô#ÏâǶXöXÆ·ÖÊ·ûÓ¡µÄ³É¾ÍÐÅÏ¢  | 
|     PlayerSuccess.ResetSuccessByType(curPlayer, ShareDefine.SuccType_InlayRune)  | 
|     totalLV = 0  | 
|     runeHoleCnt = IpyGameDataPY.GetFuncCfg("RuneUnlock", 4)  | 
|     for holeNum in xrange(1, runeHoleCnt + 1):  | 
|         runeData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_Rune_Data % holeNum, 0)  | 
|         if not runeData:  | 
|             continue  | 
|         runeItemID = ItemControler.GetRuneItemID(runeData)  | 
|         itemData = GameWorld.GetGameData().GetItemByTypeID(runeItemID)  | 
|         if not itemData:  | 
|             continue  | 
|         itemColor = itemData.GetItemColor()  | 
|         runeItemPlusLV = ItemControler.GetRuneItemPlusLV(runeData) + 1 #¿Í»§¶Ë1¿ªÊ¼  | 
|         totalLV += runeItemPlusLV  | 
|         PlayerSuccess.DoAddSuccessProgress(curPlayer, ShareDefine.SuccType_InlayRune, 1, [itemColor])  | 
|     PlayerSuccess.UptateSuccessProgress(curPlayer, ShareDefine.SuccType_RuneLvUp, totalLV)  | 
|     # ¿ª·þ»î¶¯Êý¾Ý  | 
|     OpenServerCampaign.UpdOpenServerCampaignRecordData(curPlayer, ShareDefine.Def_Campaign_Type_RuneLV, totalLV)  | 
|     return  | 
|   | 
| #// A5 66 ·ûÓ¡·Ö½â #tagCMRuneDecompose  | 
| #  | 
| #struct    tagCMRuneDecompose  | 
| #{  | 
| #    tagHead        Head;  | 
| #    BYTE        IsAll;    // ÊÇ·ñÈ«²¿·Ö½â£¬ÓÅÏȼ¶×î¸ß£¬Ëø¶¨³ýÍâ  | 
| #    BYTE        QualityCnt;    // °´È«²¿·Ö½âÆ·ÖÊÊý  | 
| #    BYTE        QualityList[QualityCnt];    // È«²¿·Ö½âµÄÆ·ÖÊÁÐ±í£¬·¢ËÍµÄÆ·ÖÊ»áÈ«²¿·Ö½â£¬Ëø¶¨³ýÍâ  | 
| #    BYTE        Count;    // Ö¸¶¨ÅúÁ¿·Ö½âÊý£¬×î´ó²»³¬¹ý50¸ö  | 
| #    WORD        PlaceIndexList[Count];    // ÅúÁ¿·Ö½âλÖÃË÷ÒýÁÐ±í  | 
| #};  | 
| def OnRuneDecompose(index, clientData, tick):  | 
|     curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)  | 
|     isAll = clientData.IsAll  | 
|     qualityList = clientData.QualityList  | 
|     GameWorld.DebugLog("·ûÓ¡·Ö½â: isAll=%s,qualityList=%s,PlaceIndexList=%s" % (isAll, qualityList, clientData.PlaceIndexList))  | 
|       | 
|     delPlaceDict = {}  | 
|     totalDecompose = 0  | 
|     totalMJ = 0  | 
|     packIndex = ShareDefine.rptRune  | 
|     placeList = xrange(ItemCommon.GetVPackCnt(packIndex)) if (isAll or clientData.QualityCnt > 0) else clientData.PlaceIndexList  | 
|     wmpIpyData = PlayerMagicWeapon.GetMagicWeaponPrivilege(curPlayer, ChConfig.MWPrivilege_RuneDecompose)  | 
|     addPer = int(wmpIpyData.GetEffectValue()) if wmpIpyData else 0  | 
|     for place in placeList:  | 
|         RuneData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_VPackItem % (packIndex, place))  | 
|         if not RuneData:  | 
|             continue  | 
|         # Ëø¶¨µÄ²»¿É·Ö½â  | 
|         RuneIsLock = ItemControler.GetRuneItemIsLock(RuneData)  | 
|         if RuneIsLock:  | 
|             continue  | 
|         RuneItemID = ItemControler.GetRuneItemID(RuneData)  | 
|         RuneItemPlusLV = ItemControler.GetRuneItemPlusLV(RuneData)  | 
|         itemData = GameWorld.GetGameData().GetItemByTypeID(RuneItemID)  | 
|         if not itemData:  | 
|             continue  | 
|           | 
|         quality = itemData.GetItemColor()  | 
|           | 
|         if not (isAll or quality in qualityList or place in clientData.PlaceIndexList):  | 
|             continue  | 
|           | 
|         if itemData.GetType() == ChConfig.Def_ItemType_RuneExp: #¾«»ªÎïÆ·¶ÁЧ¹ûÖµ  | 
|             curEff = itemData.GetEffectByIndex(0)  | 
|             decompose = curEff.GetEffectValue(0)  | 
|             decompose += decompose * addPer / ShareDefine.Def_MaxRateValue  | 
|         else:  | 
|             decompose = 0  | 
|             for lv in range(RuneItemPlusLV + 1):  | 
|                 decompose += GetRuneNeedExp(RuneItemID, lv)  | 
|                 if lv == 0:  | 
|                     decompose += decompose * addPer / ShareDefine.Def_MaxRateValue  | 
|                       | 
|             ipyData = IpyGameDataPY.GetIpyGameDataNotLog('RuneCompound', RuneItemID)  | 
|             if ipyData and ItemControler.GetRuneItemSource(RuneData) in [ChConfig.Rune_Source_Unkown,ChConfig.Item_Source_Compound]:  | 
|                 totalMJ += ipyData.GetNeedMJ()  | 
|               | 
|   | 
|         totalDecompose += decompose  | 
|         delPlaceDict[place] = [RuneData, int(decompose)]  | 
|           | 
|     if delPlaceDict:  | 
|         ItemCommon.DelVPackItem(curPlayer, packIndex, delPlaceDict.keys(), ChConfig.ItemDel_Rune)  | 
|       | 
|     totalDecompose = int(totalDecompose)  | 
|     if totalDecompose:  | 
|         addDataDict = {"delPlaceDict":delPlaceDict, "totalDecompose":totalDecompose}  | 
|         PlayerControl.GiveMoney(curPlayer, ShareDefine.TYPE_Price_Rune, totalDecompose,   | 
|                                 ChConfig.Def_GiveMoney_RuneDecompose, addDataDict, False)  | 
|         PlayerControl.NotifyCode(curPlayer, 'hwj_20170807_1', [totalDecompose, ShareDefine.TYPE_Price_Rune])  | 
|     if totalMJ:  | 
|         addDataDict = {"delPlaceDict":delPlaceDict, "totalMJ":totalMJ}  | 
|         PlayerControl.GiveMoney(curPlayer, ShareDefine.TYPE_Price_Ysog, totalMJ,   | 
|                                 ChConfig.Def_GiveMoney_RuneDecompose, addDataDict, False)  | 
|         PlayerControl.NotifyCode(curPlayer, 'hwj_20170807_1', [totalMJ, ShareDefine.TYPE_Price_Ysog])  | 
|     return  | 
|   | 
| #// A5 67 ·ûÓ¡Ëø¶¨×´Ì¬±ä¸ü #tagCMRuneLock  | 
| #  | 
| #struct    tagCMRuneLock  | 
| #{  | 
| #    tagHead        Head;  | 
| #    BYTE        LockState;    // Ëø¶¨×´Ì¬£¬ 0-Ëø¶¨£¬1-½âËø  | 
| #    BYTE        Count;    // ÅúÁ¿²Ù×÷Êý£¬×î´ó²»³¬¹ý50¸ö  | 
| #    WORD        PlaceIndexList[Count];    // ÅúÁ¿²Ù×÷λÖÃË÷ÒýÁÐ±í  | 
| #};  | 
| def OnRuneLock(index, clientData, tick):  | 
|     curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)  | 
|     packIndex = ShareDefine.rptRune  | 
|     changeLockState = clientData.LockState # Ëø¶¨×´Ì¬£¬ 1-Ëø¶¨£¬0-½âËø  | 
|       | 
|     changePlaceList = []  | 
|     for place in clientData.PlaceIndexList:  | 
|         RuneData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_VPackItem % (packIndex, place))  | 
|         if not RuneData:  | 
|             continue  | 
|         RuneIsLock = ItemControler.GetRuneItemIsLock(RuneData)  | 
|         if changeLockState == RuneIsLock:  | 
|             continue  | 
|         RuneItemID = ItemControler.GetRuneItemID(RuneData)  | 
|         RuneItemPlusLV = ItemControler.GetRuneItemPlusLV(RuneData)  | 
|         updRuneData = ItemControler.GetRuneItemKeyData(RuneItemID, RuneItemPlusLV, changeLockState)  | 
|         ItemControler.SetVPackItemKeyData(curPlayer, packIndex, place, updRuneData, False)  | 
|         changePlaceList.append(place)  | 
|           | 
|     if changePlaceList:  | 
|         ItemControler.Sync_VPackItem_Refresh(curPlayer, packIndex, changePlaceList)  | 
|         GameWorld.DebugLog("Ð޸ķûÓ¡Ëø¶¨×´Ì¬: changeLockState=%s, %s" % (changeLockState, changePlaceList))  | 
|     return  | 
|   | 
| #// A5 78 ·ûÓ¡ºÏ³É #tagCMRuneCompound  | 
| #  | 
| #struct    tagCMRuneCompound  | 
| #  | 
| #{  | 
| #    tagHead        Head;  | 
| #    BYTE        Cnt;  | 
| #    BYTE        PackList[Cnt];    //ËùÔÚλÖà0-±³°ü 1-·ûÓ¡¿×  | 
| #    BYTE        IndexList[Cnt];    //ÎïÆ·Ë÷Òý  | 
| #    DWORD        TagItemID;    //ºÏ³ÉÄ¿±êÎïÆ·ID  | 
| #};  | 
| def OnRuneCompound(index, clientData, tick):  | 
|     ##·ûÓ¡ºÏ³É  | 
|     curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)  | 
|     tagItemID = clientData.TagItemID  | 
|     packList = clientData.PackList  | 
|     indexList = clientData.IndexList  | 
|     GameWorld.DebugLog('    ·ûÓ¡ºÏ³É tagItemID=%s'%tagItemID)  | 
|     ipyData = IpyGameDataPY.GetIpyGameData('RuneCompound', tagItemID)  | 
|     if not ipyData:  | 
|         return  | 
|     materialsIDList = []  | 
|     materialsLVDict = {}  | 
|     indexList1 = [] #±³°üµÄ·ûÓ¡Ë÷Òý  | 
|     indexList2 = [] #¿×Ë÷Òý  | 
|     for i, placeType in enumerate(packList):  | 
|         index = indexList[i]  | 
|         if placeType == 0:  | 
|             runeData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_VPackItem % (ShareDefine.rptRune, index)) # ·ûÓ¡±³°üÖеÄÖµ  | 
|             indexList1.append(index)  | 
|         else:  | 
|             runeData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_Rune_Data % (index+1), 0)  | 
|             indexList2.append(index+1)  | 
|         if not runeData:  | 
|             continue  | 
|         runeItemID = ItemControler.GetRuneItemID(runeData)  | 
|         runeItemPlusLV = ItemControler.GetRuneItemPlusLV(runeData)  | 
|         materialsIDList.append(runeItemID)   | 
|         materialsLVDict[runeItemID] = runeItemPlusLV  | 
|           | 
|       | 
|     needItemIDList = ipyData.GetNeedItem()  | 
|     if sorted(materialsIDList) != sorted(needItemIDList):  | 
|         GameWorld.DebugLog('    ·ûÓ¡ºÏ³É ²ÄÁϲ»¶Ô tagItemID=%s, materialsIDList=%s, needItemIDList=%s'%(tagItemID,materialsIDList,needItemIDList))  | 
|         return  | 
|       | 
|     if 0 not in packList:  | 
|         #Èç¹ûûÓб³°üµÄ²ÄÁÏÒªÅжϸñ×ÓÊý  | 
|         emptySpace = ItemCommon.GetItemPackSpace(curPlayer, ShareDefine.rptRune, 1)  | 
|         if emptySpace < 1:  | 
|             PlayerControl.NotifyCode(curPlayer, "GeRen_chenxin_676165", [ShareDefine.rptRune])  | 
|             GameWorld.DebugLog('    ·ûÓ¡ºÏ³É ±³°ü¸ñ×ÓÊýÁ¿²»×ã1¸ö')  | 
|             return   | 
|           | 
|     needMJ = ipyData.GetNeedMJ()  | 
|     infoDict = {"TagItemID":tagItemID}  | 
|     if not PlayerControl.PayMoney(curPlayer, ShareDefine.TYPE_Price_Ysog, needMJ, ChConfig.Def_Cost_ItemProduce, infoDict):  | 
|         return  | 
|        | 
|     totalPoint = 0  | 
|     for itemID in materialsIDList:  | 
|         decompose = 0  | 
|         RuneItemPlusLV = materialsLVDict.get(itemID,0)  | 
|         for lv in range(1, RuneItemPlusLV + 1):  | 
|             decompose += GetRuneNeedExp(itemID, lv)  | 
|         totalPoint += decompose  | 
|     totalPoint = int(totalPoint)  | 
|     tagItemLV = 0  | 
|   | 
|     runeMaxLV = GetRuneMaxLV(tagItemID)  | 
|     for lv in xrange(1, runeMaxLV):  | 
|         needExp = GetRuneNeedExp(tagItemID, lv)  | 
|         if totalPoint < needExp:  | 
|             break  | 
|         tagItemLV = lv  | 
|         totalPoint -= needExp  | 
|       | 
|     #ɾ³ý²ÄÁÏÎïÆ·  | 
|     if indexList1:  | 
|         ItemCommon.DelVPackItem(curPlayer, ShareDefine.rptRune, indexList1, ChConfig.ItemDel_Rune)  | 
|     if indexList2:  | 
|         for index in indexList2:  | 
|             PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_Rune_Data % index, 0)  | 
|         Sync_RuneInfo(curPlayer)  | 
|         RefreshRuneAttr(curPlayer)  | 
|         PlayerControl.PlayerControl(curPlayer).RefreshPlayerAttrState()  | 
|           | 
|     #¸øÐÂÎïÆ·  | 
|     curItem = ItemControler.GetOutPutItemObj(tagItemID)  | 
|     curItem.SetUserAttr(ShareDefine.Def_IudetRuneLV, tagItemLV)  | 
|     curItem.SetUserAttr(ShareDefine.Def_IudetRuneSource, ChConfig.Item_Source_Compound)  | 
|     PlayerItemControler = ItemControler.PlayerItemControler(curPlayer)  | 
|     PlayerItemControler.PutInItem(ShareDefine.rptRune, curItem, event=[ChConfig.ItemGive_RuneCompound, False, {'indexList1':indexList1,'indexList2':indexList2}])  | 
|     curPlayer.Sync_MakeItemAnswer(ShareDefine.Def_mitRuneCompound, 1)  | 
|     return  | 
|   | 
|   | 
| ## Ë¢·ûÓ¡ÊôÐÔ  | 
| def RefreshRuneAttr(curPlayer):  | 
|     allAttrList = [{} for _ in range(4)]  | 
|     runeHoleCnt = IpyGameDataPY.GetFuncCfg("RuneUnlock", 4)  | 
|     for holeNum in xrange(1, runeHoleCnt + 1):  | 
|         runeData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_Rune_Data % holeNum, 0)  | 
|         if not runeData:  | 
|             continue  | 
|         runeItemID = ItemControler.GetRuneItemID(runeData)  | 
|         runeItemPlusLV = ItemControler.GetRuneItemPlusLV(runeData)  | 
|           | 
|         attrDict = GetRuneAttrValue(runeItemID, runeItemPlusLV)  | 
|           | 
|         if not attrDict:  | 
|             continue  | 
|         GameWorld.DebugLog('    Ë¢·ûÓ¡ÊôÐÔ holeNum=%s, attrDict=%s' % (holeNum, attrDict))  | 
|         for attrID, attrValue in attrDict.items():  | 
|             PlayerControl.CalcAttrDict_Type(attrID, attrValue, allAttrList)  | 
|           | 
|     # ±£´æ¼ÆËãÖµ  | 
|     PlayerControl.SetCalcAttrListValue(curPlayer, ChConfig.Def_CalcAttrFunc_Rune, allAttrList)  | 
|     return  | 
|   | 
|   | 
|   | 
| ## Í¬²½¿Í»§¶Ë  | 
| def Sync_RuneInfo(curPlayer):  | 
|     runeHoleCnt = IpyGameDataPY.GetFuncCfg("RuneUnlock", 4)  | 
|     if not runeHoleCnt:  | 
|         return  | 
|     RuneInfoPack = ChPyNetSendPack.tagMCRuneInfo()  | 
|     RuneInfoPack.Clear()  | 
|     RuneInfoPack.RuneHoleOpenState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_Rune_HoleOpenState, 0)  | 
|     RuneInfoPack.RuneDataList = []  | 
|     for RuneNum in xrange(1, runeHoleCnt + 1):  | 
|         RuneData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_Rune_Data % RuneNum, 0)  | 
|         RuneInfoPack.RuneDataList.append(RuneData)  | 
|     RuneInfoPack.Count = len(RuneInfoPack.RuneDataList)  | 
|     NetPackCommon.SendFakePack(curPlayer, RuneInfoPack)  | 
|     return  |