hxp
5 天以前 256fb6df5072850105da4b381f8ce1896c168ac1
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerHero.py
@@ -22,15 +22,20 @@
import ItemControler
import PlayerSuccess
import ChPyNetSendPack
import OpenServerActivity
import PlayerActivity
import NetPackCommon
import PlayerControl
import PlayerOnline
import PlayerPreset
import PlayerBeauty
import PlayerTask
import PlayerHJG
import GameWorld
import ChConfig
import random
import math
    
def PlayerOnDay(curPlayer):
    if curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_HeroAwakeRebirthCnt):
@@ -93,10 +98,10 @@
        return
    GameWorld.DebugLog("初始化新手武将: %s" % defaultHeroInfo, curPlayer.GetPlayerID())
    
    lineupID = ShareDefine.Lineup_Main
    presetID = 1 # 默认预设1
    shapeType = 0
    for heroID, posNum in defaultHeroInfo.items():
        lineupValue = ComLineupValue(lineupID, shapeType, posNum)
        lineupValue = ComLineupValue(presetID, shapeType, posNum)
        setAttrDict = {ShareDefine.Def_IudetHeroLineup:[lineupValue]}
        ItemControler.GivePlayerItem(curPlayer, heroID, 1, False, [ShareDefine.rptHero], setAttrDict=setAttrDict)
        
@@ -113,6 +118,8 @@
        singleItem.SetUserAttr(ShareDefine.Def_IudetHeroAwakeLV, 0)
    if singleItem.GetUserAttr(ShareDefine.Def_IudetHeroSkin):
        singleItem.SetUserAttr(ShareDefine.Def_IudetHeroSkin, 0)
    if singleItem.GetUserAttr(ShareDefine.Def_IudetHeroSkinAttr):
        singleItem.SetUserAttr(ShareDefine.Def_IudetHeroSkinAttr, 0)
        
    if singleItem.GetUserAttrCount(ShareDefine.Def_IudetHeroTalentID):
        singleItem.ClearUserAttr(ShareDefine.Def_IudetHeroTalentID)
@@ -187,6 +194,7 @@
        #首次获得图鉴额外逻辑 ...
        Sync_HeroInfo(curPlayer, [heroID])
        PlayerOnline.GetOnlinePlayer(curPlayer).OnHeroItemUpate(heroItem) # 首次获得
        OpenServerActivity.UpdOSA_HeroTrainBillboard(curPlayer) # 首次获得
        
    return
@@ -228,55 +236,21 @@
    GameWorld.DebugLog("设置武将图鉴激活状态:%s,bookState=%s,updBookState=%s" % (isAct, bookState, updBookState), curPlayer.GetPlayerID())
    return
#def GetHeroBookStarLV(curPlayer, heroID):
#    ## 武将图鉴星级等级
#    bookState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_HeroBook % heroID)
#    return GameWorld.GetValue(bookState, 4, 3)
#def SetHeroBookStarLV(curPlayer, heroID, starLV):
#    ## 设置武将图鉴星级等级,支持三位数 0~999 级
#    bookState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_HeroBook % heroID)
#    updBookState = GameWorld.SetValue(bookState, 4, 3, starLV)
#    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_HeroBook % heroID, updBookState)
#    GameWorld.DebugLog("设置武将图鉴星级等级:%s,bookState=%s,updBookState=%s" % (starLV, bookState, updBookState), curPlayer.GetPlayerID())
#    return
#def GetHeroBookStarLVH(curPlayer, heroID):
#    ## 武将图鉴星级历史最高等级
#    bookStateH = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_HeroBookH % heroID)
#    return GameWorld.GetValue(bookStateH, 4, 3)
#def SetHeroBookStarLVH(curPlayer, heroID, starLVH):
#    ## 设置武将图鉴星级历史最高等级,支持三位数 0~999 级
#    bookStateH = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_HeroBookH % heroID)
#    updBookStateH = GameWorld.SetValue(bookStateH, 4, 3, starLVH)
#    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_HeroBookH % heroID, updBookStateH)
#    GameWorld.DebugLog("设置武将图鉴星级历史最高等级:%s,bookStateH=%s,updBookStateH=%s" % (starLVH, bookStateH, updBookStateH), curPlayer.GetPlayerID())
#    Sync_HeroInfo(curPlayer, [heroID])
#    return
#def GetHeroBookBreakLV(curPlayer, heroID):
#    ## 武将图鉴突破等级
#    bookState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_HeroBook % heroID)
#    return GameWorld.GetValue(bookState, 7, 3)
#def SetHeroBookBreakLV(curPlayer, heroID, breakLV):
#    ## 设置武将图鉴突破等级,支持三位数 0~999 级
#    bookState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_HeroBook % heroID)
#    updBookState = GameWorld.SetValue(bookState, 7, 3, breakLV)
#    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_HeroBook % heroID, updBookState)
#    GameWorld.DebugLog("设置武将图鉴突破等级:%s,bookState=%s,updBookState=%s" % (breakLV, bookState, updBookState), curPlayer.GetPlayerID())
#    return
#def GetHeroBookBreakLVH(curPlayer, heroID):
#    ## 武将图鉴突破历史最高等级
#    bookStateH = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_HeroBookH % heroID)
#    return GameWorld.GetValue(bookStateH, 7, 3)
#def SetHeroBookBreakLVH(curPlayer, heroID, breakLVH):
#    ## 设置武将图鉴突破历史最高等级,支持三位数 0~999 级
#    bookStateH = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_HeroBookH % heroID)
#    updBookStateH = GameWorld.SetValue(bookStateH, 7, 3, breakLVH)
#    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_HeroBookH % heroID, updBookStateH)
#    GameWorld.DebugLog("设置武将图鉴突破历史最高等级:%s,bookStateH=%s,updBookStateH=%s" % (breakLVH, bookStateH, updBookStateH), curPlayer.GetPlayerID())
#    Sync_HeroInfo(curPlayer, [heroID])
#    return
## Def_PDict_HeroSkinInfo 星级*10+是否已激活
def GetHeroSkinState(curPlayer, skinID):
    ## 武将时装激活状态
    return curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_HeroSkinInfo % skinID) % 10
def SetHeroSkinState(curPlayer, skinID, state):
    info = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_HeroSkinInfo % skinID)
    info = info / 10 * 10 + min(1, state)
    return PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_HeroSkinInfo % skinID, info)
def GetHeroSkinStar(curPlayer, skinID):
    ## 武将时装星级
    return curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_HeroSkinInfo % skinID) / 10
def SetHeroSkinStar(curPlayer, skinID, star):
    info = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_HeroSkinInfo % skinID)
    info = star * 10 + info % 10
    return PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_HeroSkinInfo % skinID, info)
def GetHeroItem(curPlayer, itemIndex):
    curPack = curPlayer.GetItemManager().GetPack(ShareDefine.rptHero)
@@ -289,28 +263,16 @@
        return
    return heroItem
def GetHeroLineupPosNum(heroItem, lineupID=ShareDefine.Lineup_Main):
    ## 获取英雄所在阵型站位
    # @param lineupID: 阵型ID,默认主阵型
    # @return: 0-没有在该阵型;>0-在该阵型中的站位编号
    lineupCount = heroItem.GetUserAttrCount(ShareDefine.Def_IudetHeroLineup)
    if not lineupCount:
        return 0
    for lpIndex in range(lineupCount)[::-1]:
        lineupValue = heroItem.GetUserAttrByIndex(ShareDefine.Def_IudetHeroLineup, lpIndex)
        lpID, _, posNum = GetLineupValue(lineupValue)
        if lpID != lineupID:
            continue
        return posNum
    return 0
def InMainLineup(heroItem):
    ## 是否在主阵容中
    for lpIndex in range(heroItem.GetUserAttrCount(ShareDefine.Def_IudetHeroLineup)):
        lineupValue = heroItem.GetUserAttrByIndex(ShareDefine.Def_IudetHeroLineup, lpIndex)
        if GetLineupValue(lineupValue)[0] == ShareDefine.Lineup_Main:
            return True
    return False
def GetHeroEffPresetIDList(heroItem):
    ## 获取英雄有生效的预设ID列表
    dataCount = heroItem.GetUserAttrCount(ShareDefine.Def_IudetHeroEffPresetID)
    if not dataCount:
        return []
    effPresetIDList = []
    for lpIndex in range(dataCount):
        presetID = heroItem.GetUserAttrByIndex(ShareDefine.Def_IudetHeroEffPresetID, lpIndex)
        effPresetIDList.append(presetID)
    return effPresetIDList
#// B2 30 武将升级 #tagCSHeroLVUP
#
@@ -364,6 +326,7 @@
    PlayerActivity.AddDailyTaskValue(curPlayer, ChConfig.DailyTask_HeroLVUP, 1)
    PlayerTask.AddTaskValue(curPlayer, ChConfig.TaskType_HeroLVUP)
    PlayerSuccess.DoAddSuccessProgress(curPlayer, ShareDefine.SuccType_OSAHeroLVUP, 1)
    OpenServerActivity.UpdOSA_HeroTrainBillboard(curPlayer) # 升级
    return
def GetHeroLVMax(heroItem):
@@ -429,7 +392,7 @@
    quality = heroIpyData.GetQuality()
    star = heroItem.GetUserAttr(ShareDefine.Def_IudetHeroStar)
    awakeLV = heroItem.GetUserAttr(ShareDefine.Def_IudetHeroAwakeLV)
    starMax = GetHeroStarMax(heroItem)
    starMax = GetHeroStarMax(heroID, heroItem)
    GameWorld.DebugLog("heroID=%s,star=%s,quality=%s,awakeLV=%s,starMax=%s" % (heroID, star, quality, awakeLV, starMax), playerID)
    if star >= starMax:
        GameWorld.DebugLog("该武将已满星!starMax=%s" % (starMax), playerID)
@@ -443,11 +406,31 @@
    DoHeroUpdStar(curPlayer, heroItem, updStar)
    
    PlayerOnline.GetOnlinePlayer(curPlayer).OnHeroItemUpate(heroItem) # 升星
    # 固定返还一个遣散本体材料
    qualityIpyData = IpyGameDataPY.GetIpyGameData("HeroQuality", quality)
    if qualityIpyData:
        ratio = IpyGameDataPY.GetFuncCfg("HeroRebirth", 5)
        returnItemList = []
        dismissReturnItems = qualityIpyData.GetDismissReturnItems()
        for itemID, itemCount in dismissReturnItems:
            returnCnt = max(1, int(itemCount * ratio / 100.0))
            returnItemList.append([itemID, returnCnt])
        returnItemExDict = {}
        __calcHeroQualityReturnItemEx(curPlayer, qualityIpyData, returnItemExDict)
        for key, itemCount in returnItemExDict.items():
            itemID, isBind = key
            returnItemList.append([itemID, itemCount, isBind])
        GameWorld.DebugLog("吞噬额外总返还: %s" % returnItemList)
        ItemControler.GivePlayerItemOrMail(curPlayer, returnItemList, event=["HeroStarUPReturn", False, {}])
    OpenServerActivity.UpdOSA_HeroTrainBillboard(curPlayer) # 升星
    return
def GetHeroStarMax(heroItem):
    ## 获取武将当前最大星级
    heroID = heroItem.GetItemTypeID()
def GetHeroStarMax(heroID, heroItem=None):
    ## 获取武将卡物品当前最大星级
    # @param heroItem: 传入武将物品时,则取本物品当前觉醒对应的最大星级
    heroIpyData = IpyGameDataPY.GetIpyGameData("Hero", heroID)
    if not heroIpyData:
        return 0
@@ -457,8 +440,10 @@
        return 0
    InitStarUpper = qualityIpyData.GetInitStarUpper()
    
    awakeLV = heroItem.GetUserAttr(ShareDefine.Def_IudetHeroAwakeLV)
    if not awakeLV:
    awakeLV = 99999
    if heroItem:
        awakeLV = heroItem.GetUserAttr(ShareDefine.Def_IudetHeroAwakeLV)
    if awakeLV <= 0:
        return InitStarUpper
    
    addStarUpper = 0
@@ -475,7 +460,11 @@
def DoHeroUpdStar(curPlayer, heroItem, updStar, isSync=True):
    ## 执行武将星级更新
    #heroID = heroItem.GetItemTypeID()
    heroID = heroItem.GetItemTypeID()
    versionStarMax = GetHeroStarMax(heroID) # 版本理论最大星级
    if updStar > versionStarMax:
        updStar = versionStarMax
        GameWorld.DebugLog("不超过版本最大武将星级: heroID=%s,versionStarMax=%s" % (heroID, versionStarMax))
    curStar = heroItem.GetUserAttr(ShareDefine.Def_IudetHeroStar)
    addStar = updStar - curStar
    item = heroItem.GetItem()
@@ -608,6 +597,19 @@
        singleItem.AddUserAttr(ShareDefine.Def_IudetHeroTalentIDLV, lvList[index])
    return
def GetHeroIDStar(curPlayer, heroID):
    ## 获取某个武将ID当前星级,同时存在多张卡时取最大的星级
    starMax = 0
    curPack = curPlayer.GetItemManager().GetPack(ShareDefine.rptHero)
    for index in range(curPack.GetCount()):
        heroItem = curPack.GetAt(index)
        if not heroItem or heroItem.IsEmpty():
            continue
        if heroID != heroItem.GetItemTypeID():
            continue
        starMax = max(heroItem.GetUserAttr(ShareDefine.Def_IudetHeroStar), starMax)
    return starMax
def GetHeroStarTotal(curPlayer):
    ## 武将总星级
    totalStar = 0
@@ -622,8 +624,6 @@
def __CheckOSAHeroStar(curPlayer):
    ## 线上bug临时处理
    osaHeroStar = PlayerSuccess.GetSuccValue(curPlayer, ShareDefine.SuccType_OSAHeroStarUP, [])
    if osaHeroStar != 5: # bug时卡在进度5了
        return
    starTotal = GetHeroStarTotal(curPlayer)
    addStar = starTotal - osaHeroStar
    if addStar <= 0:
@@ -680,6 +680,7 @@
    SetHeroBreakLV(curPlayer, heroItem, nextBreakLV)
    
    PlayerOnline.GetOnlinePlayer(curPlayer).OnHeroItemUpate(heroItem) # 突破
    OpenServerActivity.UpdOSA_HeroTrainBillboard(curPlayer) # 突破
    return
def SetHeroBreakLV(curPlayer, heroItem, breakLV, isSync=True):
@@ -746,6 +747,7 @@
    SetHeroAwakeLV(heroItem, nextAwakeLV)
    
    PlayerOnline.GetOnlinePlayer(curPlayer).OnHeroItemUpate(heroItem) # 觉醒
    OpenServerActivity.UpdOSA_HeroTrainBillboard(curPlayer) # 觉醒
    return
def SetHeroAwakeLV(heroItem, awakeLV, isSync=True):
@@ -857,21 +859,51 @@
        idList.append(talentID)
        lvList.append(talentLV)
        
    commTalentSlot = IpyGameDataPY.GetFuncCfg("HeroStarTalent", 1) # 常规天赋槽个数
    if idCount < commTalentSlot:
        idList += [0] * (commTalentSlot - idCount)
        lvList += [0] * (commTalentSlot - idCount)
    if selectTalentID in idList:
        GameWorld.ErrLog("选择天赋ID不能重复! heroID=%s,selectIndex=%s,selectTalentID=%s in %s" 
                         % (heroID, selectIndex, selectTalentID, idList), playerID)
        return
    commTalentSlot = IpyGameDataPY.GetFuncCfg("HeroStarTalent", 1) # 常规天赋槽个数
    talentMaxLV = IpyGameDataPY.GetFuncCfg("HeroStarTalent", 2) # 每个天赋最大等级
    idCount = len(idList)
    GameWorld.DebugLog("选择天赋: heroID=%s,selectTalentID=%s,idList=%s,lvList=%s" % (heroID, selectTalentID, idList, lvList))
    
    if idCount < commTalentSlot:
        idList += [0] * (commTalentSlot - idCount)
        lvList += [0] * (commTalentSlot - idCount)
        selectTalentLV = 1
        GameWorld.DebugLog("常规槽位未全部解锁,觉醒槽位默认1级天赋")
    else:
        heroIpyData = IpyGameDataPY.GetIpyGameData("Hero", heroID)
        if not heroIpyData:
            return
        quality = heroIpyData.GetQuality()
        qualityIpyData = IpyGameDataPY.GetIpyGameData("HeroQuality", quality)
        if not qualityIpyData:
            return
        InitStarUpper = qualityIpyData.GetInitStarUpper()
        heroAwakeIpyDataList = IpyGameDataPY.GetIpyGameDataListNotLog("HeroAwake", heroID)
        if not heroAwakeIpyDataList:
            return
        preSlotStarMax = 0 # 上一档槽位最大星级
        preSlotStarMax += InitStarUpper
        for ipyData in heroAwakeIpyDataList:
            if idCount < ipyData.GetUnlockTalentSlot():
                break
            preSlotStarMax += ipyData.GetAddStarUpper()
        curStar = heroItem.GetUserAttr(ShareDefine.Def_IudetHeroStar)
        GameWorld.DebugLog("常规槽位已全部解锁, idCount=%s,preSlotStarMax=%s,curStar=%s" % (idCount, preSlotStarMax, curStar))
        overflowStar = curStar - preSlotStarMax # 溢出星级 = 当前星级 - 上一档槽位最大星级
        selectTalentLV = max(1, min(overflowStar + 1, talentMaxLV)) # 保底1级 + 溢出星级
    idList.append(selectTalentID)
    lvList.append(1)
    lvList.append(selectTalentLV)
    singleItem.ClearUserAttr(ShareDefine.Def_IudetHeroTalentIDAwakeRand)
    
    GameWorld.DebugLog("更新选择天赋: selectTalentID=%s,idList=%s,lvList=%s" % (selectTalentID, idList, lvList))
    GameWorld.DebugLog("selectTalentID=%s,selectTalentLV=%s,idList=%s,lvList=%s" % (selectTalentID, selectTalentLV, idList, lvList))
    singleItem.ClearUserAttr(ShareDefine.Def_IudetHeroTalentID)
    singleItem.ClearUserAttr(ShareDefine.Def_IudetHeroTalentIDLV)
    for index, talentID in enumerate(idList):
@@ -993,6 +1025,8 @@
    heroItem.Sync_Item()
    GameWorld.DebugLog("武将洗炼结果! itemIndex=%s,heroID=%s,washIDList=%s,lockTalentIndexs=%s" 
                       % (itemIndex, heroID, washIDList, lockTalentIndexs))
    OpenServerActivity.AddOSAValue(curPlayer, ShareDefine.Def_BT_OSA_HeroTrain, washCostItemCount)
    OpenServerActivity.UpdOSA_HeroTrainBillboard(curPlayer) # 洗炼
    return
def HeroTalentWashReplace(curPlayer, itemIndex, heroItem):
@@ -1020,18 +1054,44 @@
    PlayerOnline.GetOnlinePlayer(curPlayer).OnHeroItemUpate(heroItem) # 替换洗炼天赋
    return
#// B2 36 武将换肤 #tagCSHeroWearSkin
#// B2 36 武将皮肤操作 #tagCSHeroSkinOP
#
#struct    tagCSHeroWearSkin
#struct    tagCSHeroSkinOP
#{
#    tagHead        Head;
#    WORD        ItemIndex;    //武将物品所在武将背包位置索引
#    BYTE        SkinIndex;    //皮肤索引
#    DWORD        HeroID;        //武将ID
#    DWORD        SkinID;        //ʱװID
#    BYTE        OPType;        //操作 1-激活;2-选择形象;3-升星;4-选择属性
#    WORD        ItemIndex;    //武将物品所在武将背包位置索引,仅佩戴时有效
#};
def OnHeroWearSkin(index, clientData, tick):
def OnHeroSkinOP(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    heroID = clientData.HeroID
    skinID = clientData.SkinID
    opType = clientData.OPType
    itemIndex = clientData.ItemIndex
    skinIndex = clientData.SkinIndex
    heroIpyData = IpyGameDataPY.GetIpyGameData("Hero", heroID)
    if not heroIpyData:
        return
    skinIDList = heroIpyData.GetSkinIDList()
    if skinID not in skinIDList:
        GameWorld.DebugLog("不存在该皮肤! heroID=%s,skinID=%s not in %s" % (heroID, skinID, skinIDList))
        return
    skinIndex = skinIDList.index(skinID)
    if opType == 1:
        ActiveHeroSkin(curPlayer, heroID, skinID)
    elif opType == 2:
        DoHeroWearSkin(curPlayer, itemIndex, skinIndex, False)
    elif opType == 3:
        DoHeroSkinStarUP(curPlayer, heroID, skinID)
    elif opType == 4:
        DoHeroWearSkin(curPlayer, itemIndex, skinIndex, True)
    return
def DoHeroWearSkin(curPlayer, itemIndex, skinIndex, isSkinAttr):
    # @param isSkinAttr: 是否是选择属性的,反之则为选择皮肤形象
    heroItem = GetHeroItem(curPlayer, itemIndex)
    if not heroItem:
        return
@@ -1044,30 +1104,146 @@
        if skinIndex >= len(skinIDList):
            GameWorld.DebugLog("该武将不存在该皮肤! heroID=%s,skinIndex=%s" % (heroID, skinIndex))
            return
        skinState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_HeroSkin % heroID)
        if not skinState & pow(2, skinIndex):
            GameWorld.DebugLog("该武将皮肤未解锁! heroID=%s,skinIndex=%s,skinState=%s" % (heroID, skinIndex, skinState))
        skinID = skinIDList[skinIndex]
        if not GetHeroSkinState(curPlayer, skinID):
            GameWorld.DebugLog("该武将皮肤未解锁! heroID=%s,skinIndex=%s" % (heroID, skinIndex))
            return
    heroItem.SetUserAttr(ShareDefine.Def_IudetHeroSkin, skinIndex)
    PlayerOnline.GetOnlinePlayer(curPlayer).OnHeroItemUpate(heroItem) # 切换皮肤
    GameWorld.DebugLog("切换武将皮肤! heroID=%s,skinIndex=%s,isSkinAttr=%s" % (heroID, skinIndex, isSkinAttr))
    item = heroItem.GetItem()
    if not isSkinAttr:
        item.SetUserAttr(ShareDefine.Def_IudetHeroSkin, skinIndex)
    else:
        # 选属性同步修改形象
        item.SetUserAttr(ShareDefine.Def_IudetHeroSkin, skinIndex)
        item.SetUserAttr(ShareDefine.Def_IudetHeroSkinAttr, skinIndex)
        PlayerOnline.GetOnlinePlayer(curPlayer).OnHeroItemUpate(heroItem) # 切换皮肤属性
    heroItem.Sync_Item()
    return True
def GMSetHeroSkin(curPlayer, heroID, skinIndex, isActive=1):
    heroIpyData = IpyGameDataPY.GetIpyGameData("Hero", heroID)
    if not heroIpyData:
        return
    skinIDList = heroIpyData.GetSkinIDList()
    if not skinIDList or skinIndex >= len(skinIDList):
        return
    skinID = skinIDList[skinIndex]
    __onHeroSkinActive(curPlayer, heroID, skinID, isActive)
    return
def ActiveHeroSkin(curPlayer, heroID, skinIndex, isActive=True):
    skinState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_HeroSkin % heroID)
    if isActive:
        updState = skinState | pow(2, skinIndex)
        GameWorld.DebugLog("激活武将皮肤: heroID=%s,skinIndex=%s,skinState=%s,updState=%s"
                           % (heroID, skinIndex, skinState, updState), curPlayer.GetPlayerID())
    else:
        updState = GameWorld.SetBitValue(skinState, skinIndex, 0)
        GameWorld.DebugLog("失效武将皮肤: heroID=%s,skinIndex=%s,skinState=%s,updState=%s"
                           % (heroID, skinIndex, skinState, updState), curPlayer.GetPlayerID())
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_HeroSkin % heroID, updState)
    Sync_HeroInfo(curPlayer, [heroID])
    #RefreshLordAttr(curPlayer)
def ActiveHeroSkin(curPlayer, heroID, skinID):
    skinIpyData = IpyGameDataPY.GetIpyGameData("HeroSkinAttr", skinID)
    if not skinIpyData:
        return
    if GetHeroSkinState(curPlayer, skinID):
        GameWorld.DebugLog("该武将皮肤已经激活了: heroID=%s,skinID=%s" % (heroID, skinID))
        return
    needItemID = skinIpyData.GetNeedItemID()
    needItemCnt = 1
    costItemIndexList, bindCnt, unBindCnt = ItemCommon.GetPackItemBindStateIndexInfo(curPlayer, needItemID, needItemCnt)
    lackCnt = needItemCnt - bindCnt - unBindCnt
    if lackCnt > 0:
        GameWorld.DebugLog("激活武将时装物品不足! heroID=%s,needItemID=%s,needItemCnt=%s,lackCnt=%s" % (heroID, needItemID, needItemCnt, lackCnt))
        return
    ItemCommon.DelCostItemByBind(curPlayer, costItemIndexList, bindCnt, unBindCnt, needItemCnt, "HeroSkin")
    GameWorld.DebugLog("激活武将皮肤: heroID=%s,skinID=%s" % (heroID, skinID), curPlayer.GetPlayerID())
    __onHeroSkinActive(curPlayer, heroID, skinID, 1)
    return
def __onHeroSkinActive(curPlayer, heroID, skinID, isActive):
    SetHeroSkinState(curPlayer, skinID, isActive)
    Sync_HeroInfo(curPlayer, [heroID])
    RefreshLordAttr(curPlayer) # 时装激活 - 全体属性
    return
def DoHeroSkinStarUP(curPlayer, heroID, skinID):
    playerID = curPlayer.GetPlayerID()
    if not GetHeroSkinState(curPlayer, skinID):
        GameWorld.DebugLog("该武将时装未激活! heroID=%s,skinID=%s" % (heroID, skinID), playerID)
        return
    skinIpyData = IpyGameDataPY.GetIpyGameData("HeroSkinAttr", skinID)
    if not skinIpyData:
        return
    starMax = skinIpyData.GetStarMax()
    curStar = GetHeroSkinStar(curPlayer, skinID)
    if curStar >= starMax:
        GameWorld.DebugLog("武将时装星级已满! heroID=%s,skinID=%s,curStar=%s >= %s" % (heroID, skinID, curStar, starMax), playerID)
        return
    needItemID = skinIpyData.GetNeedItemID()
    needItemCnt = 1
    if not needItemID or not needItemCnt:
        return
    costItemIndexList, bindCnt, unBindCnt = ItemCommon.GetPackItemBindStateIndexInfo(curPlayer, needItemID, needItemCnt)
    lackCnt = needItemCnt - bindCnt - unBindCnt
    if lackCnt > 0:
        GameWorld.DebugLog("武将时装升星物品不足! heroID=%s,skinID=%s,needItemID=%s,needItemCnt=%s,lackCnt=%s" % (heroID, skinID, needItemID, needItemCnt, lackCnt))
        return
    ItemCommon.DelCostItemByBind(curPlayer, costItemIndexList, bindCnt, unBindCnt, needItemCnt, "Hero")
    nextStar = curStar + 1
    GameWorld.DebugLog("武将时装升星! heroID=%s,skinID=%s,nextStar=%s" % (heroID, skinID, nextStar), playerID)
    SetHeroSkinStar(curPlayer, skinID, nextStar)
    Sync_HeroInfo(curPlayer, [heroID])
    RefreshLordAttr(curPlayer) # 时装升星 - 全体属性
    return
def AutoChangeToSkinPoint(curPlayer, curItem, eventName):
    ## 获得皮肤时自动转化为皮肤碎片
    # @return: 是否成功转化
    itemID = curItem.GetItemTypeID()
    itemIDSkinIDDict = GetItemHeroSkinIDDict()
    if itemID not in itemIDSkinIDDict:
        #GameWorld.DebugLog("非武将皮肤物品不处理! itemID=%s not in %s" % (itemID, itemIDSkinIDDict))
        return
    skinID = itemIDSkinIDDict[itemID]
    if not GetHeroSkinState(curPlayer, skinID):
        #GameWorld.DebugLog("该武将皮肤未激活不处理转化: itemID=%s,skinID=%s" % (itemID, skinID))
        return
    curStar = GetHeroSkinStar(curPlayer, skinID)
    ipyData = IpyGameDataPY.GetIpyGameData("HeroSkinAttr", skinID)
    if not ipyData:
        return
    starMax = ipyData.GetStarMax()
    if starMax and curStar < starMax:
        #GameWorld.DebugLog("武将皮肤未满星暂不转化! itemID=%s,skinID=%s,curStar=%s < %s" % (itemID, skinID, curStar, starMax))
        return
    skinQuality = ipyData.GetSkinQuality()
    skinQualityPointDict = IpyGameDataPY.GetFuncEvalCfg("HeroSkin", 1, {})
    if str(skinQuality) not in skinQualityPointDict:
        return
    changePoint = skinQualityPointDict[str(skinQuality)]
    itemCount = ItemControler.GetItemCount(curItem)
    addDataDict = {"ItemID":itemID, "ItemCount":itemCount, "SkinID":skinID}
    moneyType = ShareDefine.TYPE_Price_SkinPoint
    moneyValue = changePoint * itemCount
    GameWorld.DebugLog("武将皮肤不需要再升星了自动转化为皮肤碎片! itemID=%s,skinID=%s,skinQuality=%s,moneyValue=%s,itemCount=%s"
                       % (itemID, skinID, skinQuality, moneyValue, itemCount))
    if not PlayerControl.GiveMoney(curPlayer, moneyType, moneyValue, eventName, addDataDict, notifyAward=False):
        return
    curItem.Clear()
    if eventName:
        isBind = ItemControler.GetIsBindValue(srcSign=ChConfig.ItemSrcSign_HeroSkinChange)
        ItemControler.NotifyGiveAwardInfo(curPlayer, [], eventName, moneyInfo={moneyType:[moneyValue, isBind]}, dataEx=itemID)
    return True
def GetItemHeroSkinIDDict():
    ## 获取物品ID对应皮肤ID信息
    itemIDSkinIDDict = IpyGameDataPY.GetConfigEx("itemIDSkinIDDict")
    if not itemIDSkinIDDict:
        itemIDSkinIDDict = {}
        ipyDataMgr = IpyGameDataPY.IPY_Data()
        for index in range(ipyDataMgr.GetHeroSkinAttrCount()):
            ipyData = ipyDataMgr.GetHeroSkinAttrByIndex(index)
            skinID = ipyData.GetSkinID()
            skinItemID = ipyData.GetNeedItemID()
            itemIDSkinIDDict[skinItemID] = skinID
        IpyGameDataPY.SetConfigEx("itemIDSkinIDDict", itemIDSkinIDDict)
        GameWorld.DebugLog("加载物品ID对应武将皮肤ID: %s" % itemIDSkinIDDict)
    return itemIDSkinIDDict
#// B2 37 武将图鉴激活升级 #tagCSHeroBookUP
#
@@ -1132,48 +1308,10 @@
                    
    Sync_HeroInfo(curPlayer, [heroID])
    
    #RefreshLordAttr(curPlayer) 图鉴属性去除了
    bookCnt = GetHeroBookActCnt(curPlayer)
    PlayerTask.UpdTaskValue(curPlayer, ChConfig.TaskType_HeroBook)
    PlayerSuccess.UptateSuccessProgress(curPlayer, ShareDefine.SuccType_OSAHeroBook, bookCnt)
    return
#def __doHeroBookStarLVUP(curPlayer, heroID):
#    ## 图鉴星级升级,废弃
#    playerID = curPlayer.GetPlayerID()
#    if not GetHeroBookInitState(curPlayer, heroID):
#        GameWorld.DebugLog("该武将图鉴未激活! heroID=%s" % heroID, playerID)
#        return
#    bookStar = GetHeroBookStarLV(curPlayer, heroID)
#    bookStarH = GetHeroBookStarLVH(curPlayer, heroID)
#    if bookStar >= bookStarH:
#        GameWorld.DebugLog("该武将图鉴星级已达当前英雄最高星级! heroID=%s,bookStar=%s >= %s" % (heroID, bookStar, bookStarH), playerID)
#        return
#    GameWorld.DebugLog("武将图鉴星级升级! heroID=%s,bookStar=%s,bookStarH=%s" % (heroID, bookStar, bookStarH), playerID)
#    SetHeroBookStarLV(curPlayer, heroID, bookStar + 1)
#    Sync_HeroInfo(curPlayer, [heroID])
#
#    RefreshLordAttr(curPlayer)
#    return
#def __doHeroBookBreakLVUP(curPlayer, heroID):
#    ## 图鉴突破升级,废弃
#    playerID = curPlayer.GetPlayerID()
#    if not GetHeroBookInitState(curPlayer, heroID):
#        GameWorld.DebugLog("该武将图鉴未激活! heroID=%s" % heroID, playerID)
#        return
#    bookBreakLV = GetHeroBookBreakLV(curPlayer, heroID)
#    bookBreakLVH = GetHeroBookBreakLVH(curPlayer, heroID)
#    if bookBreakLV >= bookBreakLVH:
#        GameWorld.DebugLog("该武将图鉴突破等级已达当前英雄最高突破等级! heroID=%s,bookBreakLV=%s >= %s" % (heroID, bookBreakLV, bookBreakLVH), playerID)
#        return
#    GameWorld.DebugLog("武将图鉴突破升级! heroID=%s,bookBreakLV=%s,bookBreakLVH=%s" % (heroID, bookBreakLV, bookBreakLVH), playerID)
#    SetHeroBookBreakLV(curPlayer, heroID, bookBreakLV + 1)
#    Sync_HeroInfo(curPlayer, [heroID])
#
#    RefreshLordAttr(curPlayer)
#    return
#// B2 38 武将锁定 #tagCSHeroLock
#
@@ -1199,10 +1337,16 @@
#{
#    tagHead        Head;
#    WORD        ItemIndex;    //武将物品所在武将背包位置索引
#    BYTE        LVReset;        //重置等级
#    BYTE        BreakReset;    //重置突破
#    BYTE        AwakeReset;    //重置觉醒
#};
def OnHeroRebirth(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    itemIndex = clientData.ItemIndex
    lvReset =  clientData.LVReset
    breakReset = clientData.BreakReset or lvReset # 突破受等级限制,所以等级重置突破必重置
    awakeReset = clientData.AwakeReset
    heroItem = GetHeroItem(curPlayer, itemIndex)
    if not heroItem:
        return
@@ -1213,7 +1357,7 @@
        GameWorld.DebugLog("该武将未进行过等级突破觉醒培养,不需要重生! itemIndex=%s" % (itemIndex))
        return
    
    if awakeLV:
    if awakeReset and awakeLV:
        rebirthCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_HeroAwakeRebirthCnt)
        rebirthCntMax = IpyGameDataPY.GetFuncCfg("HeroRebirth", 2)
        if rebirthCntMax and rebirthCnt >= rebirthCntMax:
@@ -1225,38 +1369,55 @@
    if not heroIpyData:
        return
    quality = heroIpyData.GetQuality()
    qualityAwakeIpyData = IpyGameDataPY.GetIpyGameDataNotLog("HeroQualityAwake", quality, awakeLV)
    awakeCostMoney = qualityAwakeIpyData.GetRebirthCostMoney() if qualityAwakeIpyData else 0
    lvCostMoney = 0
    breakCostMoney = 0
    awakeCostMoney = 0
    moneyType = IpyGameDataPY.GetFuncCfg("HeroRebirth", 1)
    lvCostMoney = int(eval(IpyGameDataPY.GetFuncCompileCfg("HeroRebirth", 3)))
    costMoneyTotal = lvCostMoney + awakeCostMoney
    GameWorld.DebugLog("武将重生: itemIndex=%s,heroID=%s,quality=%s,heroLV=%s,breakLV=%s,awakeLV=%s,costMoneyTotal=%s(%s+%s)"
                       % (itemIndex, heroID, quality, heroLV, breakLV, awakeLV, costMoneyTotal, lvCostMoney, awakeCostMoney))
    if awakeReset and awakeLV:
        qualityAwakeIpyData = IpyGameDataPY.GetIpyGameDataNotLog("HeroQualityAwake", quality, awakeLV)
        awakeCostMoney = qualityAwakeIpyData.GetRebirthCostMoney() if qualityAwakeIpyData else 0
    if lvReset:
        lvCostMoney = int(max(0, eval(IpyGameDataPY.GetFuncCompileCfg("HeroRebirth", 3))))
    if breakReset:
        breakCostMoney = int(max(0, eval(IpyGameDataPY.GetFuncCompileCfg("HeroRebirth2", 1))))
    costMoneyTotal = lvCostMoney + awakeCostMoney + breakCostMoney
    GameWorld.DebugLog("武将重生: itemIndex=%s,heroID=%s,quality=%s,heroLV=%s,breakLV=%s,awakeLV=%s,costMoneyTotal=%s(lv:%s+b:%s+a:%s),lvReset=%s,breakReset=%s,awakeReset=%s"
                       % (itemIndex, heroID, quality, heroLV, breakLV, awakeLV, costMoneyTotal, lvCostMoney, breakCostMoney, awakeCostMoney, lvReset, breakReset, awakeReset))
    if moneyType and costMoneyTotal and not PlayerControl.HaveMoney(curPlayer, moneyType, costMoneyTotal):
        return
    
    # 验证通过,可以重生
    ratio = IpyGameDataPY.GetFuncCfg("HeroRebirth", 4)
    returnItemDict = {}
    __calcHeroLVReturnitem(quality, heroLV, returnItemDict, ratio)
    __calcHeroBreakReturnitem(quality, breakLV, returnItemDict, ratio)
    __calcHeroAwakeReturnitem(quality, awakeLV, returnItemDict, ratio)
    if lvReset:
        __calcHeroLVReturnitem(quality, heroLV, returnItemDict, ratio)
    if breakReset:
        __calcHeroBreakReturnitem(quality, breakLV, returnItemDict, ratio)
    if awakeReset:
        __calcHeroAwakeReturnitem(quality, awakeLV, returnItemDict, ratio)
    if moneyType and costMoneyTotal and not PlayerControl.PayMoney(curPlayer, moneyType, costMoneyTotal, "HeroRebirth"):
        return
    
    # 执行重生
    item = heroItem.GetItem()
    item.SetUserAttr(ShareDefine.Def_IudetHeroLV, 1)
    item.SetUserAttr(ShareDefine.Def_IudetHeroBreakLV, 0)
    item.SetUserAttr(ShareDefine.Def_IudetHeroAwakeLV, 0)
    if lvReset:
        item.SetUserAttr(ShareDefine.Def_IudetHeroLV, 1)
    if breakReset:
        item.SetUserAttr(ShareDefine.Def_IudetHeroBreakLV, 0)
    if awakeReset:
        item.SetUserAttr(ShareDefine.Def_IudetHeroAwakeLV, 0)
    heroItem.Sync_Item()
    
    if returnItemDict:
        returnItemList = [[k, v] for k, v in returnItemDict.items()]
        ItemControler.GivePlayerItemOrMail(curPlayer, returnItemList, event=["HeroRebirth", False, {}])
        
    if awakeLV:
    if awakeReset and awakeLV:
        rebirthCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_HeroAwakeRebirthCnt)
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_HeroAwakeRebirthCnt, rebirthCnt + 1)
        Sync_PlayerHeroInfo(curPlayer)
@@ -1331,7 +1492,7 @@
    ratio = IpyGameDataPY.GetFuncCfg("HeroRebirth", 5)
    dismissItemList = []
    returnItemDict = {}
    olPlayer = PlayerOnline.GetOnlinePlayer(curPlayer)
    returnItemExDict = {}
    curPack = curPlayer.GetItemManager().GetPack(ShareDefine.rptHero)
    for itemIndex in itemIndexList:
        if itemIndex < 0 or itemIndex >= curPack.GetCount():
@@ -1352,9 +1513,9 @@
            GameWorld.DebugLog("上阵中的武将无法遣散! itemIndex=%s,lineupValueList=%s" % (itemIndex, lineupValueList))
            continue
        heroID = heroItem.GetItemTypeID()
        _, effItemIndex, _ = olPlayer.GetHeroEffectiveCard(heroID)
        if itemIndex == effItemIndex:
            GameWorld.DebugLog("生效中的卡牌无法遣散! itemIndex=%s,heroID=%s,effItemIndex=%s" % (itemIndex, heroID, effItemIndex))
        effPresetIDList = GetHeroEffPresetIDList(heroItem)
        if effPresetIDList:
            GameWorld.DebugLog("生效中的卡牌无法遣散! itemIndex=%s,heroID=%s,effPresetIDList=%s" % (itemIndex, heroID, effPresetIDList))
            continue
        heroIpyData = IpyGameDataPY.GetIpyGameData("Hero", heroID)
        if not heroIpyData:
@@ -1374,6 +1535,7 @@
        GameWorld.DebugLog("    星级返还: quality=%s,heroStar=%s,ratio=%s,%s,总%s" % (quality, heroStar, ratio, dismissReturnItems, returnItemDict))
        __calcHeroLVReturnitem(quality, heroLV, returnItemDict, ratio)
        __calcHeroBreakReturnitem(quality, breakLV, returnItemDict, ratio)
        __calcHeroQualityReturnItemEx(curPlayer, qualityIpyData, returnItemExDict)
        dismissItemList.append([itemIndex, heroItem])
    
    if not dismissItemList:
@@ -1384,48 +1546,91 @@
        
    if returnItemDict:
        returnItemList = [[k, v] for k, v in returnItemDict.items()]
        for key, itemCount in returnItemExDict.items():
            itemID, isBind = key
            returnItemList.append([itemID, itemCount, isBind])
        GameWorld.DebugLog("遣散总返还: %s" % returnItemList)
        ItemControler.GivePlayerItemOrMail(curPlayer, returnItemList, event=["HeroDismiss", False, {}])
        
    return
#// B4 12 战斗阵容保存 #tagCSHeroLineupSave
def __calcHeroQualityReturnItemEx(curPlayer, qualityIpyData, returnItemExDict):
    ## 其他功能额外返还
    # 红颜特殊效果: 遣散/吞噬额外返还百分比
    beautyReturnItems = qualityIpyData.GetBeautyReturnItems()
    if beautyReturnItems:
        isBind = ItemControler.GetIsBindValue(srcSign=ChConfig.ItemSrcSign_BeautyEff)
        retPer = PlayerBeauty.GetBeautyEffInfo(curPlayer, PlayerBeauty.EffType_HeroItemExPer)[0]
        for itemID, itemCount in beautyReturnItems:
            if not retPer:
                break
            key = (itemID, isBind)
            retCnt = max(1, int(math.ceil(itemCount * retPer / 100.0)))
            returnItemExDict[key] = returnItemExDict.get(key, 0) + retCnt
        GameWorld.DebugLog("    红颜返还: retPer=%s,%s,总%s" % (retPer, beautyReturnItems, returnItemExDict))
    # 称号特殊效果: 遣散/吞噬额外返还百分比
    titleReturnItems = qualityIpyData.GetTitleReturnItems()
    if titleReturnItems:
        isBind = ItemControler.GetIsBindValue(srcSign=ChConfig.ItemSrcSign_TitleEff)
        retPer = PlayerHJG.GetTitleEffInfo(curPlayer, PlayerHJG.TitleEff_HeroItemExPer)[0]
        for itemID, itemCount in titleReturnItems:
            if not retPer:
                break
            key = (itemID, isBind)
            retCnt = max(1, int(math.ceil(itemCount * retPer / 100.0)))
            returnItemExDict[key] = returnItemExDict.get(key, 0) + retCnt
        GameWorld.DebugLog("    称号返还: retPer=%s,%s,总%s" % (retPer, titleReturnItems, returnItemExDict))
    return
#// B4 12 战斗阵容预设保存 #tagCSHeroPresetSave
#
#struct    tagCSHeroLineupPos
#struct    tagCSHeroPresetPos
#{
#    WORD        ItemIndex;    //武将物品所在武将背包位置索引
#    BYTE        PosNum;        //1~n上阵位置编号  
#};
#
#struct    tagCSHeroLineupSave
#struct    tagCSHeroPresetSave
#{
#    tagHead        Head;
#    BYTE        LineupID;        //阵容ID:1-主阵容;其他待扩展,如某个防守阵容
#    BYTE        ShapeType;    //本阵容阵型,0为默认阵型,可扩展不同的阵型
#    BYTE        PresetID;        //阵容方案预设ID
#    BYTE        PosCnt;
#    tagCSHeroLineupPos    HeroPosList[PosCnt];    // 保存的阵容,只发送最终的阵容武将位置即可
#    tagCSHeroPresetPos    HeroPosList[PosCnt];    // 保存的阵容,只发送最终的阵容武将位置即可
#};
def OnHeroLineupSave(index, clientData, tick):
def OnHeroPresetSave(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    lineupID = clientData.LineupID
    shapeType = clientData.ShapeType
    presetID = clientData.PresetID
    shapeType = 0#clientData.ShapeType
    heroPosList = clientData.HeroPosList
    
    heroPosDict = {}
    indexList = []
    itemIndexPosDict = {}
    for posInfo in heroPosList:
        posNum = posInfo.PosNum
        itemIndex = posInfo.ItemIndex
        itemIndexPosDict[itemIndex] = posNum
    DoSaveHeroPreset(curPlayer, presetID, itemIndexPosDict, shapeType)
    return
def DoSaveHeroPreset(curPlayer, presetID, itemIndexPosDict, shapeType=0):
    if not PlayerPreset.GetFuncPresetIDState(curPlayer, presetID, ShareDefine.FuncPreset_Hero):
        GameWorld.DebugLog("该武将阵容预设不可用! presetID=%s" % presetID)
        return
    heroPosDict = {}
    indexList = []
    for itemIndex, posNum in itemIndexPosDict.items():
        if itemIndex in indexList:
            # 单武将只能一个位置,一个位置只能对应唯一武将单位
            continue
        indexList.append(itemIndex)
        heroPosDict[posNum] = itemIndex
        
    if lineupID not in ShareDefine.LineupList:
        GameWorld.DebugLog("不存在该阵容,无法保存! lineupID=%s" % lineupID)
        return
    GameWorld.DebugLog("保存阵容: lineupID=%s, %s" % (lineupID, heroPosDict), curPlayer.GetPlayerID())
    GameWorld.DebugLog("保存武将预设阵容: presetID=%s, %s" % (presetID, heroPosDict), curPlayer.GetPlayerID())
    curPack = curPlayer.GetItemManager().GetPack(ShareDefine.rptHero)
    # 直接重置旧阵型
    delCount = 0
@@ -1440,7 +1645,7 @@
        item = heroItem.GetItem()
        for lpIndex in range(lineupCount)[::-1]:
            lineupValue = item.GetUserAttrByIndex(ShareDefine.Def_IudetHeroLineup, lpIndex)
            if GetLineupValue(lineupValue)[0] != lineupID:
            if GetLineupValue(lineupValue)[0] != presetID:
                continue
            item.DelUserAttr(ShareDefine.Def_IudetHeroLineup, lineupValue)
            delCount += 1
@@ -1463,26 +1668,17 @@
            continue
        heroIDList.append(itemID)
        item = heroItem.GetItem()
        lineupValue = ComLineupValue(lineupID, shapeType, posNum)
        lineupValue = ComLineupValue(presetID, shapeType, posNum)
        item.AddUserAttr(ShareDefine.Def_IudetHeroLineup, lineupValue)
        if itemIndex not in syncItemDict:
            syncItemDict[itemIndex] = heroItem
        heroItemDict[itemIndex] = posNum
        
    # 主阵容修改时重整背包,约定所有背包由前端自行排序
    #if lineupID == ShareDefine.Lineup_Main:
    #    ResetHeroPack(curPlayer)
    #else:
    # 约定所有背包由前端自行排序
    for syncItem in syncItemDict.values():
        syncItem.Sync_Item()
        
    olPlayer = PlayerOnline.GetOnlinePlayer(curPlayer)
    lineup = olPlayer.GetLineup(lineupID, False)
    lineup.UpdLineup(heroItemDict, shapeType)
    # 主阵容调整,重载生效的卡牌
    if lineupID == ShareDefine.Lineup_Main:
        PlayerOnline.reloadEffHeroCard(curPlayer, olPlayer)
    PlayerOnline.GetOnlinePlayer(curPlayer).UpdHeroItemPreset(presetID, heroItemDict, shapeType)
    return
def ComLineupValue(lineupID, shapeType, posNum): return lineupID * 10000 + shapeType * 100 + posNum
@@ -1609,6 +1805,7 @@
        return
    needStarTotal = qualityLVIpyData.GetNeedStarTotal()
    needHeroCnt = qualityLVIpyData.GetNeedHeroCnt()
    needQuality = qualityLVIpyData.GetNeedQuality()
    
    costItemList = []
    heroStarDict = {}
@@ -1622,7 +1819,7 @@
        
        # 材料卡
        if index in useIndexList:
            if __checkHeroFatesLVUPItem(olPlayer, fatesQuality, index, heroItem, heroID):
            if __checkHeroFatesLVUPItem(olPlayer, needQuality, index, heroItem, heroID):
                costItemList.append(heroItem)
                
        if heroID not in heroIDList:
@@ -1653,15 +1850,15 @@
    RefreshLordAttr(curPlayer) # 宿缘
    return
def __checkHeroFatesLVUPItem(olPlayer, fatesQuality, itemIndex, heroItem, heroID):
def __checkHeroFatesLVUPItem(olPlayer, needQuality, itemIndex, heroItem, heroID):
    ## 检查宿缘材料卡可否使用
    heroIpyData = IpyGameDataPY.GetIpyGameData("Hero", heroID)
    if not heroIpyData:
        return
    
    quality = heroIpyData.GetQuality()
    if quality != fatesQuality:
        GameWorld.DebugLog("    与宿缘品质不同的卡无法使用: itemIndex=%s,heroID=%s,quality=%s != %s" % (itemIndex, heroID, quality, fatesQuality))
    if quality != needQuality:
        GameWorld.DebugLog("    与宿缘所需品质不同的卡无法使用: itemIndex=%s,heroID=%s,quality=%s != %s" % (itemIndex, heroID, quality, needQuality))
        return
    
    #未生效、未上阵、未锁定、未进行过升级、突破、升星、觉醒
@@ -1684,9 +1881,9 @@
        return
    
    heroID = heroItem.GetItemTypeID()
    _, effItemIndex, _ = olPlayer.GetHeroEffectiveCard(heroID)
    if itemIndex == effItemIndex:
        GameWorld.DebugLog("    生效中的卡牌无法使用! itemIndex=%s,heroID=%s,effItemIndex=%s" % (itemIndex, heroID, effItemIndex))
    effPresetIDList = GetHeroEffPresetIDList(heroItem)
    if effPresetIDList:
        GameWorld.DebugLog("    生效中的卡牌无法使用! itemIndex=%s,heroID=%s,effPresetIDList=%s" % (itemIndex, heroID, effPresetIDList))
        return
    
    return True
@@ -1700,10 +1897,33 @@
def CalcHeroAddAttr(curPlayer):
    ## 计算武将对主公增加的属性
    
    skinAttrDict = {}
    fatesAttrDict = {}
    playerID = curPlayer.GetID()
    
    ipyDataMgr = IpyGameDataPY.IPY_Data()
    # 武将时装
    for index in range(ipyDataMgr.GetHeroSkinAttrCount()):
        ipyData = ipyDataMgr.GetHeroSkinAttrByIndex(index)
        skinID = ipyData.GetSkinID()
        if not GetHeroSkinState(curPlayer, skinID):
            continue
        skinStar = GetHeroSkinStar(curPlayer, skinID)
        attrIDList = ipyData.GetRoleAttrIDList()
        attrValueList = ipyData.GetRoleAttrValueList()
        perStarAddList = ipyData.GetRoleAttrPerStarAddList()
        for i in range(min(len(attrIDList), len(attrValueList))):
            attrID = attrIDList[i]
            attrValuePerStar = perStarAddList[i] if len(perStarAddList) > i else 0
            attrValue = attrValueList[i] + attrValuePerStar * skinStar
            skinAttrDict[attrID] = skinAttrDict.get(attrID, 0) + attrValue
    GameWorld.DebugLog("时装属性: %s" % skinAttrDict, playerID)
    PlayerOnline.GetOnlinePlayer(curPlayer).SetCalcAttr(ChConfig.Def_CalcAttr_HeroSkin, skinAttrDict)
    # 宿缘
    for index in range(ipyDataMgr.GetHeroFatesCount()):
        ipyData = ipyDataMgr.GetHeroFatesByIndex(index)
        fatesID = ipyData.GetFatesID()
@@ -1744,18 +1964,21 @@
        heroIpyData = IpyGameDataPY.GetIpyGameData("Hero", heroID)
        if not heroIpyData:
            continue
        if heroIDList == None and not curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_HeroBook % heroID) \
            and not curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_HeroBookH % heroID):
        if heroIDList == None and not curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_HeroBook % heroID):
            continue
        skinIDList = heroIpyData.GetSkinIDList()
        
        hero = ChPyNetSendPack.tagSCHero()
        hero.HeroID = heroID
        hero.SkinState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_HeroSkin % heroID)
        hero.BookInitState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_HeroBook % heroID) % 10
        #hero.BookStarLV = GetHeroBookStarLV(curPlayer, heroID)
        #hero.BookBreakLV = GetHeroBookBreakLV(curPlayer, heroID)
        #hero.BookStarLVH = GetHeroBookStarLVH(curPlayer, heroID)
        #hero.BookBreakLVH = GetHeroBookBreakLVH(curPlayer, heroID)
        hero.SkinList = []
        for skinID in skinIDList[1:]: # 第1个默认激活的不同步
            skin = ChPyNetSendPack.tagSCHeroSkin()
            skin.SkinID = skinID
            skin.State = GetHeroSkinState(curPlayer, skinID)
            skin.Star = GetHeroSkinStar(curPlayer, skinID)
            hero.SkinList.append(skin)
        hero.SkinCnt = len(hero.SkinList)
        syncInfoList.append(hero)
        
    if not syncInfoList:
@@ -1767,39 +1990,39 @@
    NetPackCommon.SendFakePack(curPlayer, clientPack)
    return
def Sync_Lineup(curPlayer, lineupID=None):
    if lineupID:
        syncIDList = [lineupID]
    else:
        syncIDList = ShareDefine.LineupList
    lineupList = []
def Sync_HeroPreset(curPlayer, heroPresetID=None):
    olPlayer = PlayerOnline.GetOnlinePlayer(curPlayer)
    for lineupID in syncIDList:
        lineup = olPlayer.GetLineup(lineupID, False)
        if not lineup:
    if heroPresetID:
        syncIDList = [heroPresetID]
    else:
        syncIDList = olPlayer.GetHeroPresetIDList()
    presetList = []
    for heroPresetID in syncIDList:
        heroPreset = olPlayer.GetHeroPreset(heroPresetID)
        if not heroPreset:
            continue
        
        posNumItemIndexDict = {v:k for k, v in lineup.heroItemDict.items()}
        posNumItemIndexDict = {v:k for k, v in heroPreset.heroItemDict.items()}
        heroItemIndexList = [] # 所在武将背包索引+1列表 [站位1物品索引+1, 站位2, ...],站位无武将时为0
        for posNum in range(1, 1 + ShareDefine.LineupObjMax):
            if posNum in posNumItemIndexDict:
                heroItemIndexList.append(posNumItemIndexDict[posNum] + 1)
            else:
                heroItemIndexList.append(0)
        packLineup = ChPyNetSendPack.tagSCLineup()
        packLineup.LineupID = lineup.lineupID
        packLineup.ShapeType = lineup.shapeType
        packLineup.HeroItemIndexList = heroItemIndexList
        packLineup.HeroCnt = len(packLineup.HeroItemIndexList)
        lineupList.append(packLineup)
        preset = ChPyNetSendPack.tagSCHeroPreset()
        preset.PresetID = heroPresetID
        #preset.ShapeType = heroPreset.shapeType
        preset.HeroItemIndexList = heroItemIndexList
        preset.HeroCnt = len(preset.HeroItemIndexList)
        presetList.append(preset)
        
    if not lineupList:
    if not presetList:
        return
    
    clientPack = ChPyNetSendPack.tagSCLineupInfo()
    clientPack.LineupList = lineupList
    clientPack.LineupCnt = len(clientPack.LineupList)
    clientPack = ChPyNetSendPack.tagSCHeroPresetInfo()
    clientPack.PresetList = presetList
    clientPack.PresetCnt = len(clientPack.PresetList)
    NetPackCommon.SendFakePack(curPlayer, clientPack)
    return