hxp
5 天以前 a7ab0247c7b8eff06ad104bee39bc035384ca43e
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
@@ -14,14 +14,9 @@
#"""Version = 2017-07-17 15:00"""
#---------------------------------------------------------------------
import GameWorld
import ChEquip
import SkillShell
import ChConfig
import EventShell
import EffGetSet
import PlayerHorse
import PlayerTruck
import PlayerTrade
import PlayerTeam
import SkillCommon
import MirrorAttack
@@ -31,12 +26,12 @@
import NPCCommon
import ItemCommon
import ReadChConfig
import PlayerGMOper
import BuffSkill
import PetControl
import OperControlManager
import PlayerFamily
import ShareDefine
import PlayerViewCache
import PlayerBillboard
import GameServerRefresh
import IPY_GameWorld
@@ -44,32 +39,15 @@
import ChPyNetSendPack
import NetPackCommon
import DataRecordPack
import CalcNoLineEffect
import CalcLineEffect
import PlayerEquipDecompose
import FormulaControl
import PlayerDienstgrad
import PlayerPrestigeSys
import OpenServerCampaign
import PlayerGodWeapon
import PlayerExpandPackCfgMgr
import PlayerWorldAverageLv
import PlayerActivity
import FBCommon
import PlayerViewCacheTube
import PassiveBuffEffMng
import PlayerGameEvent
import EventReport
import PlayerGatherSoul
import PlayerGatherTheSoul
import PlayerSuccess
import PlayerPet
import PlayerGreatMaster
import ItemControler
import GameFuncComm
import IpyGameDataPY
import PlayerRune
import GameLogic_DuJie
import PyGameData
import PlayerMagicWeapon
import PlayerFeastTravel
@@ -77,38 +55,24 @@
import GameLogic_SealDemon
import GameLogic_ZhuXianBoss
import GameLogic_CrossDemonKing
import PlayerTJG
import PlayerVip
import PlayerRefineStove
import PlayerFamilyTech
import PlayerFamilyZhenfa
import PlayerCostRebate
import PlayerActLunhuidian
import PlayerActGarbageSorting
import GY_Query_CrossRealmReg
import PlayerTongTianLing
import PlayerCrossRealmPK
import FunctionNPCCommon
import PlayerGoldInvest
import IPY_PlayerDefine
import CrossRealmPlayer
import CrossPlayerData
import NPCHurtManager
import ChNetSendPack
import PlayerLianTi
import PlayerCoat
import PlayerAssist
import PlayerState
import QuestCommon
import PlayerDogz
import PlayerFaQi
import PlayerLove
import PlayerGubao
import PlayerShentong
import PlayerCharm
import PlayerFace
import PlayerOnline
import PlayerTask
import PlayerMail
import ChPlayer
import GMShell
import GameObj
import random
@@ -250,7 +214,13 @@
#  @param mergeMapInfo 该提示所属的跨服活动地图信息, 主要用于不同子服对应所跨的活动地图ID
#  @return 无返回值
def WorldNotify(country, msgMark, msgParamList=[], lineID=0, mergeMinOSD=-1, mergeMaxOSD=-1, mergeMapInfo=[]):
    GameWorld.GetPlayerManager().BroadcastCountry_NotifyCode(country, 0, msgMark, __GetNotifyCodeList(msgParamList), lineID)
    #GameWorld.GetPlayerManager().BroadcastCountry_NotifyCode(country, 0, msgMark, __GetNotifyCodeList(msgParamList), lineID)
    playerManager = GameWorld.GetPlayerManager()
    for i in xrange(playerManager.OnlineCount()):
        curPlayer = playerManager.OnlineAt(i)
        if not GameWorld.IsNormalPlayer(curPlayer):
            continue
        NotifyCode(curPlayer, msgMark, msgParamList)
    return
def GetCrossWorldNotifyInfo(country, msgMark, msgParamList=[]):
@@ -276,7 +246,8 @@
#  @return 无返回值
#  @remarks 
def FamilyNotify(familyID, msgMark, msgParamList=[]):
    GameWorld.GetPlayerManager().BroadcastCountry_NotifyCode(0, familyID, msgMark, __GetNotifyCodeList(msgParamList))
    #GameWorld.GetPlayerManager().BroadcastCountry_NotifyCode(0, familyID, msgMark, __GetNotifyCodeList(msgParamList))
    PlayerFamily.NotifyAllFamilyMemberMsg(familyID, msgMark, msgParamList)
    return
#---------------------------------------------------------------------
@@ -339,189 +310,16 @@
#---------------------------------------------------------------------
def SendMailBatch(mailTypeKey, batchPlayerIDList, batchAddItemList=[], batchParamList=[], batchGold=[], batchGoldPaper=[], batchSilver=[], batchDetail=[], moneySource=ChConfig.Def_GiveMoney_Mail, crossMail=False):
    '''批量发送邮件, 用于瞬间需要发送多封(大量)邮件的,比如一些公共副本活动等结算时
    @param mailTypeKey: 邮件模板key
    @param batchPlayerIDList: [playerIDList, playerIDList, ...]
    @param batchAddItemList: [addItemList, addItemList, ...]
    @param batchParamList: [paramList, paramList, ...]
    @param batchGold: [batchGold, batchGold, ...]
    @param batchGoldPaper: [batchGoldPaper, batchGoldPaper, ...]
    @param batchSilver: [batchSilver, batchSilver, ...]
    @param batchDetail: [记录邮件流向用, ...]
    @param moneySource: 货币来源
    '''
    copyMapPlayerManager = GameWorld.GetMapCopyPlayerManager()
    for i, playerIDList in enumerate(batchPlayerIDList):
        for playerID in playerIDList[::-1]:
            curPlayer = copyMapPlayerManager.FindPlayerByID(playerID)
            if curPlayer and not curPlayer.GetGameServerInitOK():
                bAddItemList = [batchAddItemList[i]] if len(batchAddItemList) > i else []
                bParamList = [batchParamList[i]] if len(batchParamList) > i else []
                bGold = [batchGold[i]] if len(batchGold) > i else []
                bGoldPaper = [batchGoldPaper[i]] if len(batchGoldPaper) > i else []
                bSilver = [batchSilver[i]] if len(batchSilver) > i else []
                bDetail = [batchDetail[i]] if len(batchDetail) > i else []
                AddUnLoginOKPlayerMailCache(playerID, "ByMailTemplate", [mailTypeKey, bAddItemList, bParamList, bGold, bGoldPaper, bSilver, bDetail, moneySource, crossMail])
                playerIDList.pop(playerIDList.index(playerID))
                continue
    msgInfo = str([mailTypeKey, batchPlayerIDList, batchAddItemList, batchParamList, batchGold, batchGoldPaper, batchSilver, batchDetail, moneySource, crossMail])
    GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(0, 0, 0, "SendMailBatch", msgInfo, len(msgInfo))
    GameWorld.Log("SendMailBatch %s, batchPlayerIDList=%s, batchAddItemList=%s, batchParamList=%s, batchGold=%s, batchGoldPaper=%s, batchSilver=%s"
                  % (mailTypeKey, batchPlayerIDList, batchAddItemList, batchParamList, batchGold, batchGoldPaper, batchSilver))
    ## 删除旧版发送邮件,如果功能还有需要,可使用新版本发送邮件 PlayerMail
    ## 批量发送邮件的一般是活动类型功能,一般都需要用到GameServer
    ## 所以暂时不兼容使用新版本发送邮件,等相应功能有需要时再同步修改
    return
def SendMailByKey(mailTypeKey, playerIDList, addItemList, paramList=[], gold=0, goldPaper=0, silver=0, detail="", moneySource=ChConfig.Def_GiveMoney_Mail, crossMail=False):
    '''
    @param detail: 记录邮件流向用
    '''
    if not mailTypeKey:
        mailTypeKey = ShareDefine.DefaultLackSpaceMailType
    content = "<MailTemplate>%s</MailTemplate>%s" % (mailTypeKey, json.dumps(paramList, ensure_ascii=False))
    SendMail("", content, 30, playerIDList, addItemList, gold, goldPaper, silver, detail, moneySource, crossMail)
    return
def SendCrossMail(serverGroupID, mailTypeKey, playerIDList, addItemList, paramList=[]):
    ## 发送跨服邮件
    if not serverGroupID:
        return
    dataMsg = {"MailTypeKey":mailTypeKey, "Player":playerIDList}
    if addItemList:
        dataMsg["Item"] = CombineMailItem(addItemList)
    if paramList:
        dataMsg["Param"] = paramList
    GameWorld.SendMsgToClientServer(ShareDefine.CrossServerMsg_SendMail, dataMsg, [serverGroupID])
    return
def SendEntireMail(mailTypeKey, getDays, limitLV, limitLVType, addItemList=[], paramList=[], \
                   gold=0, goldPaper=0, silver=0, detail="", moneySource=ChConfig.Def_GiveMoney_Mail):
    ''' 发送全服邮件
    @param mailTypeKey: 邮件模板key
    @param getDays: 有效天数
    @param limitLV: 领取最低等级限制
    @param limitLVType: 等级不足的升级后是否可领 0-不可,1-可以
    '''
    # 有效天数限制
    if not mailTypeKey or getDays <= 0:
        return
    # 跨服服务器不允许发送邮件
    if GameWorld.IsCrossServer():
        return
    combineItemList = CombineMailItem(addItemList)
    cmdList = [mailTypeKey, getDays, limitLV, limitLVType, combineItemList, paramList, gold, goldPaper, silver, detail, moneySource]
    GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(0, 0, 0, "SendEntireMail", '%s' % (cmdList), len(str(cmdList)))
    GameWorld.Log("发送全服邮件: %s,getDays=%s,limitLV=%s,limitLVType=%s,combineItemList=%s,paramList=%s,gold=%s,goldPaper=%s,silver=%s,detail=%s,moneySource=%s" %
                  (mailTypeKey, getDays, limitLV, limitLVType, combineItemList, paramList, gold, goldPaper, silver, detail, moneySource))
    return
## 功能发放物品补偿/奖励邮件
#  @param addItemList [(itemID, itemCnt, 是否拍品), {或物品信息字典}, ...]
#  @return
def SendMail(title, content, getDays, playerIDList, addItemList, gold=0, goldPaper=0, silver=0, detail="", moneySource=ChConfig.Def_GiveMoney_Mail, crossMail=False):
    if not playerIDList:
        return
#    if not addItemList:
#        return
    # 有效天数限制
    if getDays <= 0:
        return
    # 跨服服务器不允许发送邮件
    if GameWorld.IsCrossServer() and not crossMail:
        return
    sendPlayerIDList = []
    copyMapPlayerManager = GameWorld.GetMapCopyPlayerManager()
    ## 函数先保留,之后功能直接使用 PlayerMail.SendMailByKey
    for playerID in playerIDList:
        curPlayer = copyMapPlayerManager.FindPlayerByID(playerID)
        if curPlayer and not curPlayer.GetGameServerInitOK():
            AddUnLoginOKPlayerMailCache(playerID, "ByMailContent", [title, content, getDays, addItemList, gold, goldPaper, silver, detail, moneySource])
            continue
        sendPlayerIDList.append(playerID)
    combineItemList = CombineMailItem(addItemList)
    cmdList = [title, content, getDays, sendPlayerIDList, combineItemList, gold, goldPaper, silver, detail, moneySource, crossMail]
    GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(0, 0, 0, "SendMail", '%s' % (cmdList), len(str(cmdList)))
    return True
def AddUnLoginOKPlayerMailCache(playerID, cacheType, mailInfo):
    ''' 添加未登录成功的玩家个人邮件发送缓存
    '''
    if playerID not in PyGameData.g_unLoginOKPlayerMailInfo:
        PyGameData.g_unLoginOKPlayerMailInfo[playerID] = []
    mailList = PyGameData.g_unLoginOKPlayerMailInfo[playerID]
    if [cacheType, mailInfo] in mailList:
        GameWorld.Log("###重复添加GetGameServerInitOK未登录成功的玩家个人邮件发送缓存! 不添加! mailCount=%s, mailInfo=%s"
                      % (len(mailList), str(mailInfo)), playerID)
        return
    if len(mailList) >= 30: # 做个限制,防止出问题刷邮件
        GameWorld.Log("###限制添加GetGameServerInitOK未登录成功的玩家个人邮件发送缓存! 超出最大可添加数,不添加! mailCount=%s, mailInfo=%s"
                      % (len(mailList), str(mailInfo)), playerID)
        return
    mailList.append([cacheType, mailInfo])
    # curPlayer.GetGameServerInitOK()
    GameWorld.Log("添加GetGameServerInitOK未登录成功的玩家个人邮件发送缓存! 等待发送! mailCount=%s, mailInfo=%s"
                  % (len(mailList), str(mailInfo)), playerID)
        PlayerMail.SendMailByKey(mailTypeKey, playerID, addItemList, paramList)
    return
def SendUnLoginOKPlayerMailCache(curPlayer):
    ## 未登录成功的玩家个人邮件发送缓存  - 登录成功后处理
    if not curPlayer.GetGameServerInitOK():
        return
    playerID = curPlayer.GetPlayerID()
    if playerID not in PyGameData.g_unLoginOKPlayerMailInfo:
        return
    mailList = PyGameData.g_unLoginOKPlayerMailInfo.pop(playerID)
    for cacheType, mailInfo in mailList:
        playerIDList = [playerID]
        GameWorld.Log("发送未登录成功时缓存的待发送邮件! cacheType=%s, mailInfo=%s" % (cacheType, str(mailInfo)), playerID)
        if cacheType == "ByMailContent":
            title, content, getDays, addItemList, gold, goldPaper, silver, detail, moneySource = mailInfo
            SendMail(title, content, getDays, playerIDList, addItemList, gold, goldPaper, silver, detail, moneySource)
        elif cacheType == "ByMailTemplate":
            mailTypeKey, bAddItemList, bParamList, bGold, bGoldPaper, bSilver, bDetail, moneySource, crossMail = mailInfo
            SendMailBatch(mailTypeKey, [playerIDList], bAddItemList, bParamList, bGold, bGoldPaper, bSilver, bDetail, moneySource, crossMail)
    return
def CombineMailItem(addItemList):
    ## 合并邮件物品
    itemCountDict = {}
    combineItemList = [] # 合并后的物品列表
    for mailItem in addItemList:
        if isinstance(mailItem, dict):
            combineItemList.append(mailItem)
            continue
        if len(mailItem) != 3:
            continue
        itemID, itemCnt, isAuctionItem = mailItem
        if ItemControler.GetAppointItemRealID(itemID):
            # 定制物品转化为物品信息字典
            appointItemObj = ItemControler.GetItemByData(ItemControler.GetAppointItemDictData(itemID, isAuctionItem))
            if not appointItemObj:
                GameWorld.ErrLog("邮件定制物品转化失败!itemID, itemCnt, isAuctionItem" % (itemID, itemCnt, isAuctionItem))
                continue
            combineItemList.append(ItemCommon.GetMailItemDict(appointItemObj))
            appointItemObj.Clear()
        elif isAuctionItem:
            combineItemList.append((itemID, itemCnt, isAuctionItem))
        else:
            key = (itemID, isAuctionItem)
            itemCountDict[key] = itemCountDict.get(key, 0) + itemCnt
    for key, itemCnt in itemCountDict.items():
        itemID, isAuctionItem = key
        combineItemList.append((itemID, itemCnt, isAuctionItem))
    return combineItemList
## 构建系统提示参数列表
#  @param msgParamList 信息参数列表
@@ -613,35 +411,9 @@
    if GameObj.GetHP(curPlayer) <= 0:
        return False
    
#    if curPlayer.GetPKValue() > 0:
#        #PK_lhs_161795
#        NotifyCode(curPlayer, "PK_lhs_161795")
#        return False
    #检查玩家状态
    if not CheckTransState(curPlayer):
        return False
#    #眩晕时,不可传送
#    if curPlayer.GetAbnormalState() == IPY_GameWorld.sctFaint:
#        return False
    #=========================================================================================================
    # #拉镖车中,人不在镖车中也不能传送
    # if curPlayer.GetTruck() != None:
    #    NotifyCode(curPlayer, "HaveTruck_No_Trans")
    #    return False
    #=========================================================================================================
#    #被攻击时候, 无法使用
#    if curPlayer.IsBattleState():
#        NotifyCode(curPlayer, "CannotAtk09")
#        return False
#
#    #对峙中, 无法使用
#    if curPlayer.GetIsConfronting():
#        NotifyCode(curPlayer, "CannotAtk09")
#        return False
    
    #检查玩家是否在普通地图
    if GameWorld.GetMap().GetMapFBType() != IPY_GameWorld.fbtNull:
@@ -801,6 +573,13 @@
    #GameWorld.DebugLog("receiveState = %s, state = %s" % (receiveState, state))
    return state != 0
## 清除py自定义状态
#  @param curPlayer 玩家实例
#  @return 返回值无意义
def ClearPyPlayerAction(curPlayer):
    #清除py自定义状态
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_PyPlayerAction, 0)
    return
#---------------------------------------------------------------------
##设置玩家是否激活
@@ -972,21 +751,6 @@
    
    
    return
#---------------------------------------------------------------------
##玩家播放表情
# @param curPlayer 玩家实例
# @return 返回值无意义
# @remarks 玩家播放表情
def DoPlayerShowPlayerFace(curPlayer, faceType):
    #清空玩家点击
    curPlayer.SetActionObj(None)
    #通知中断战斗对峙
    ExitPlayerConfronting(curPlayer)
    #通知停止移动
    curPlayer.StopMove()
    #通知客户端播放表情
    curPlayer.View_ShowPlayerFace(faceType)
    return
#---------------------------------------------------------------------
##玩家死亡
@@ -1103,98 +867,6 @@
    __FixPlayerPos(checkObj, posX, posY, needResetPos, canChangeClientPos)
    return True
#    curPlayer.SetMoveCount(curPlayer.GetMoveCount() + 1)
#
#    #Def_PlayerMoveCheckClearCount:
#    #玩家移动多少次清空这个累计错误
#    if curPlayer.GetMoveCount() >= ReadChConfig.GetEvalChConfig('Def_PlayerMoveCheckClearCount'):
#        curPlayer.SetMoveCount(0)
#        curPlayer.SetMoveDistDiff(0)
#
#    #距离(起点-客户端位置-服务器端位置-终点)
#    severDist = GameWorld.GetDist(objPosX, objPosY, objDestPosX, objDestPosY)
#    severTotalDist = GameWorld.GetDist(objStartX, objStartY, objDestPosX, objDestPosY)
#    clientDist = GameWorld.GetDist(posX, posY, objDestPosX, objDestPosY)
#
#    clientSlow = False
#
#    if clientDist >= severDist and clientDist <= severTotalDist:
#        #方向
#        severDir = GameWorld.GetAngle(objStartX, objStartY, objDestPosX, objDestPosY)
#        clientDir = GameWorld.GetAngle(posX, posY, objDestPosX, objDestPosY)
#
#        clientSlow = True
##===============================================================================
##        #2011-1-19 此种情况也要计算误差
##        #如果角度差别10度, 则认为可以接受
##        dirDiff = 10
##        dirDiffValue = abs(severDir - clientDir)
##
##        if dirDiffValue <= dirDiff:
##            #第二种情况:服务器比客户端快
##            #可以接受
##            __FixPlayerPos(checkObj, posX, posY, needResetPos, canChangeClientPos)
##            return True
##===============================================================================
#    #服务器比客户端慢#ChConfig.Def_AcceptPlayerStopPlaceDist:
#    if dist > ReadChConfig.GetEvalChConfig('Def_AcceptPlayerStopPlaceDist'):
#        return False
#        #踢玩家下线
#        if clientSlow:
#            GameWorld.ErrLog("超大误差, 客户端比服务器慢 %d" % dist, curPlayer.GetPlayerID())
#        else:
#            GameWorld.ErrLog("超大误差, 服务器比客户端慢 %d" % dist, curPlayer.GetPlayerID())
#            #服务器端比客户端慢可以接受
#            return False
#
#        #GameWorld.GodLog(curPlayer, '超大误差, 暂不处理, clientSlow = %s, dist = %s'%(clientSlow, dist))
#
#        #超大误差封停账号时间
#        closeAccIDTime = ReadChConfig.GetEvalChConfig('Def_BigErrorDistCloseAccTime')
#
#        if closeAccIDTime > 0:
#            #超大误差封停玩家
#            PlayerGMOper.ClosePlayerByAccID(curPlayer, closeAccIDTime, 'BigErrorDist = %s Kick' % (dist))
#        else:
#            #超大误差踢出玩家
#            curPlayer.Kick(IPY_GameWorld.disPlayerMoveToFar)
#
#        return False
#
#    #停止位置可接受,当需记录
#    curMoveDistDiff = curPlayer.GetMoveDistDiff() + dist
#    curPlayer.SetMoveDistDiff(curMoveDistDiff)
#
#    #新增移动坐标差值Debug提示信息,方便客户端查询
#    GameWorld.GodLog(curPlayer, 'Client=(%s,%s), Server=(%s,%s), 累加距离=%s, 累加总值=%s' \
#                     % (posX, posY, objPosX, objPosY, dist, curPlayer.GetMoveDistDiff()))
#
#    #玩家移动100次检查一次
#    if curPlayer.GetMoveCount() >= ReadChConfig.GetEvalChConfig('Def_PlayerMoveCheckCount'):
#        maxMoveDistDiff = ReadChConfig.GetEvalChConfig('Def_PlayerMoveCheckDist')
#        #2009/07/15 因副本拉人瞬间距离过大,副本判定距离双倍
#        if GameWorld.GetMap().GetMapFBType() != IPY_GameWorld.fbtNull:
#            maxMoveDistDiff = maxMoveDistDiff * 2
#
#        if curMoveDistDiff >= maxMoveDistDiff:
#            return False
#            GameWorld.Log("玩家移动错误次数 = %s, 移动累计距离 = %s, 踢玩家下线" \
#                          % (curPlayer.GetMoveCount(), curMoveDistDiff), curPlayer.GetPlayerID())
#
#            closeAccIDTime = ReadChConfig.GetEvalChConfig('Def_MoveDistErrorCloseAccTime')
#
#            if closeAccIDTime > 0:
#                PlayerGMOper.ClosePlayerByAccID(curPlayer, closeAccIDTime, 'MoveCheckKick, ErrDist = %s' \
#                                                % (curMoveDistDiff))
#            else:
#                curPlayer.Kick(IPY_GameWorld.disPlayerMoveAddUpError)
#
#            return False
#
#    #第3种情况:记录并矫正坐标
#    __FixPlayerPos(checkObj, posX, posY, needResetPos, canChangeClientPos)
#    return True
#---------------------------------------------------------------------
##矫正玩家坐标
# @param checkObj 检查的对象
@@ -1277,21 +949,6 @@
#------------------------------玩家离开服务器的逻辑------------------------------------
#---------------------------------------------------------------------
##镖车下线逻辑
# @param curPlayer 玩家实例
# @return 返回值无意义
# @remarks 镖车下线逻辑
def __TruckPlayerDisconnect(curPlayer):
    return
    #在镖车
    if PlayerTruck.GetHaveAutoTruck(curPlayer):
        curPlayerTruck = curPlayer.GetTruck()
        curPlayerTruck.SetOwner(None)
        PlayerTruck.PlayerTruckDown(curPlayer, curPlayerTruck)
    return
#---------------------------------------------------------------------
##骑马下线逻辑
# @param curPlayer 玩家实例
# @return 返回值无意义
@@ -1312,29 +969,15 @@
def __PlayerLeaveServerLogic(curPlayer, tick, isDisconnect):
    #给予玩家补偿
    #PlayerExpiation.GivePlayerExpiation(curPlayer, tick)
    #运行离线xml
    EventShell.EventResponse_OnLeaveMap(curPlayer)
    #如果玩家有骠车, 把骠车的主人设置为None
    curPlayerTruck = curPlayer.GetTruck()
    if curPlayerTruck != None:
        curPlayerTruck.SetOwner(None)
    #刷新技能剩余时间
    SkillCommon.RefreshAllSkillRemainTime(curPlayer, tick)
    #如果在交易状态,取消交易双方的交易状态并解除交易栏中物品锁定状态
    PlayerTrade.LeaveTrade(curPlayer, 0)
    
    #队伍玩家退出地图
    PlayerTeam.TeamPlayerLeaveMap(curPlayer, tick, isDisconnect)
    #退出采集
    NPCCommon.ClearCollectNPC(curPlayer)
    #结束事件
    EventShell.DoExitEvent(curPlayer)
    #设置玩家的地图位置, 如果是副本, 离开副本
#    副本规则:
@@ -1372,9 +1015,6 @@
        CrossPlayerData.ClearCrossSyncDataCache(curPlayer)
        PyGameData.g_fbBuyBuffTimeDict.pop(playerID, None)
    #清除地图玩家缓存
    PyGameData.g_playerFuncAttrDict.pop(playerID, None)
    PyGameData.g_playerEquipPartAttrDict.pop(playerID, None)
    PyGameData.g_equipChangeClassLVInfo.pop(playerID, None)
    PyGameData.g_playerReqEnterFBEx.pop(playerID, None)
    NPCCommon.ClearPriWoodPile(curPlayer)
    #移除地图缓存的境界难度玩家ID信息
@@ -1487,14 +1127,13 @@
    PlayerBillboard.UpdatePlayerBillboardOnLeaveServer(curPlayer) #排行榜已实时更新,故下线不再同步
    
    #玩家下线通知gameserver记录缓存(放在下线更新排行榜之后,方便Gameserver判断是否需要存入数据库中)
    PlayerViewCacheTube.OnPlayerLogOut(curPlayer, tick)
    PlayerViewCache.OnPlayerLogout(curPlayer)
    PlayerFamily.OnPlayerLogout(curPlayer)
    
    #玩家下线/玩家切换地图公用逻辑
    __PlayerLeaveServerLogic(curPlayer, tick, True)
    #骑马玩家下线逻辑
    __RidingHorsePlayerDisconnect(curPlayer)
    #镖车下线逻辑
    __TruckPlayerDisconnect(curPlayer)
    #召唤兽死亡
    KillPlayerSummonNPC(curPlayer)
    #更新从本地图离线信息
@@ -1550,34 +1189,6 @@
    NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_DelPackIndex, 0)
    return
##切换地图镖车设定
# @param curPlayer 玩家实例
# @return 返回值真,可以带上镖车切换地图
# @remarks 切换地图镖车设定
def __GetCanChangeMapSetTruck(curPlayer):
    curTruck = curPlayer.GetTruck()
    #GameWorld.Log("玩家 骠车 切换地图逻辑")
    if curTruck == None:
        #GameWorld.Log("玩家 没有 骠车")
        return False
    dist = GameWorld.GetDist(curTruck.GetPosX(), curTruck.GetPosY(),
                             curPlayer.GetPosX(), curPlayer.GetPosY())
    if dist > ChConfig.Def_PlayerTruckEventDist:
        #GameWorld.Log("玩家和骠车距离过远, 骠车不切换  %d" %dist)
        return False
#    #玩家下骠车
#    if curPlayer.GetPlayerVehicle() == IPY_GameWorld.pvTruck :
#        PlayerTruck.PlayerTruckDown(curPlayer,curTruck)
    #GameWorld.Log("玩家和骠车一起切换地图")
    #1. 在对方地图创建骠车
    #curTruck.ResetWorldPos(mapID, targetPosX, targetPosY)
    #2. 消失本地图骠车
    return True
#---------------------------------------------------------------------
##玩家开始切换地图
# @param curPlayer 玩家实例
@@ -1586,22 +1197,6 @@
# @remarks 玩家开始切换地图
def DoPlayerResetWorldPos(curPlayer, tick):
    NotifyStartChangeMap(curPlayer) # 通知开始切换地图
    #在此函数中不可中断, 一定要调用DoResetWorldPosAndClear函数
    #否则, 会在BalanceServer中卡住
    takeTruck = curPlayer.GetChangeMapTakeTruck()
    #如果有骠车, 带上骠车
    if takeTruck == True:
        if not __GetCanChangeMapSetTruck(curPlayer):
            takeTruck = False
    #如果不让带骠车, 并且玩家在人镖合一状态, 那么让玩家下车
    if takeTruck == False and curPlayer.GetPlayerVehicle() == IPY_GameWorld.pvTruck:
        curTruck = curPlayer.GetTruck()
        if curTruck:
            PlayerTruck.PlayerTruckDown(curPlayer, curTruck)
    curPlayer.SetChangeMapTakeTruck(takeTruck)
    
    #离开地图服务器
    __PlayerLeaveServerLogic(curPlayer, tick, False)
@@ -1616,25 +1211,6 @@
    while curPlayer.GetSummonCount():
        summonNPC = curPlayer.GetSummonNPCAt(0)
        NPCCommon.SetDeadEx(summonNPC)
#    summonIndex = 0
#    while summonIndex < curPlayer.GetSummonCount():
#        summonNPC = curPlayer.GetSummonNPCAt(summonIndex)
#
#        #2009.4.21, 如果召唤兽的速度为0, 代表这个召唤兽为杖子
#        #切换地图不可带过去
#        #之前用硬判定的
#        if summonNPC.GetSpeed() == 0:
#            #切换地图不能带过去
#            NPCCommon.SetDeadEx(summonNPC)
#            continue
#
#        #切换地图可以带过去 , 清空召唤兽仇恨,伤血列表
#        summonNPCControl = NPCCommon.NPCControl(summonNPC)
#        summonNPCControl.ClearNPCAngry()
#        summonNPCControl.ClearNPCHurtList()
#        summonList.append(summonNPC)
#        summonIndex += 1
        
    changeMapID = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ChangeMapID)
    # 更新最后一次离开的非中立常规地图, 从中立地图退出时需要回到该地方,必须在 DoResetWorldPosAndClear 之前更新
@@ -1672,18 +1248,6 @@
            
    #2. 调用切换地图接口
    curPlayer.DoResetWorldPosAndClear()
    #3. 玩家已经传送过去了, 删除这个玩家的附加召唤兽(骠车, 或者黄泉使者)
    #for curSummon in summonList:
    #    NPCCommon.SetDeadEx(curSummon)
    if takeTruck == True:
        curTruck = curPlayer.GetTruck()
        if curTruck != None:
            curPlayer.SetTruck(None)
            curTruck.Disappear()
    return
#---------------------------------------------------------------------
@@ -1767,7 +1331,7 @@
    #    ChangePlayerAction(curPlayer, IPY_GameWorld.paNull)
    #===============================================================================================
    
    PlayerResetWorldPosFB(curPlayer, mapID, posX, posY, False, lineID, funcLineID=funcLineID, enterFBFree=enterFBFree)
    PlayerResetWorldPosFB(curPlayer, mapID, posX, posY, lineID, funcLineID=funcLineID, enterFBFree=enterFBFree)
    
    #在空闲或者移动状态下,才能锁死玩家
    if curPlayer.GetPlayerAction() in [IPY_GameWorld.paNull] or curPlayer.IsMoving():
@@ -1891,12 +1455,6 @@
        
        posX, posY = retPos
        
    #===============================================================================================
    # if not EventShell.DoLogic_EnterFbGameEvent(curPlayer, mapID, tick):
    #    GameWorld.Log("DoLogic_EnterFbGameEvent False!mapID=%s,lineID=%s" % (mapID, lineID))
    #    return
    #===============================================================================================
    if curPlayer.IsMoving():
        curPlayer.StopMove()
    
@@ -1916,7 +1474,6 @@
            # 新手线路特殊处理,直接进入
            if lineID in newbielineList:
                GameWorld.DebugLog("封魔坛虚拟线路只能通过自定义场景进入挑战!")
                #PlayerResetWorldPosFB(curPlayer, mapID, posX, posY, False, fbID, funcLineID=lineID)
                return
            else:
                bossID = GameLogic_SealDemon.CurFBLineBOSSID(lineID)
@@ -1940,7 +1497,7 @@
        SendToGameServerEnterFB(curPlayer, mapID, lineID, tick, extendParamList)
        return
    
    PlayerResetWorldPosFB(curPlayer, mapID, posX, posY, False, fbID, funcLineID=lineID)
    PlayerResetWorldPosFB(curPlayer, mapID, posX, posY, fbID, funcLineID=lineID)
    return
##发送到GameServer请求进入副本
@@ -1982,11 +1539,6 @@
    if GameObj.GetHP(curPlayer) <= 0:
        GameWorld.Log("玩家已经死亡, 无法进入副本!")
        return ShareDefine.EntFBAskRet_Dead
    if PlayerTJG.GetIsTJG(curPlayer):
        if isNotify:
            NotifyCode(curPlayer, "SingleEnterDefaul", [mapID])
        return ShareDefine.EntFBAskRet_TJG
    
    ## 队伍检查的情况,队长不处理,只处理队员
    if isTeamAsk and curPlayer.GetTeamLV() != IPY_GameWorld.tmlLeader:
@@ -2052,21 +1604,6 @@
                NotifyCode(curPlayer, "Carry_lhs_697674")
            return ShareDefine.EntFBAskRet_Other
        
    #移动中不执行此操作
#    if curPlayer.IsMoving():
#        #NotifyCode(curPlayer, "GeRen_lhs_0")
#        return False
#    #拉镖中无法传送到副本
#    if curPlayer.GetTruck():
#        #NotifyCode(curPlayer, "Convey_Duplicate_Lost01")
#        return False
    #战斗状态中无法传送到副本
    #if curPlayer.IsBattleState():
    #    NotifyCode(curPlayer, "Carry_lhs_202580")
    #    return False
    #当前地图不是普通地图
    if GameWorld.GetMap().GetMapFBType() != IPY_GameWorld.fbtNull:
        canFBMoveToOther = False
@@ -2155,14 +1692,13 @@
# @param mapID 地图ID
# @param posX 坐标X
# @param posY 坐标Y
# @param takeTruck 是否带镖车
# @param FBID 副本ID, 虚拟线路ID
# @param msg 携待信息
# @param canLock 是否锁定玩家
# @param funcLineID 副本功能线路ID,由前端请求
# @return 返回值无意义
# @remarks 玩家切换到指定副本ID
def PlayerResetWorldPosFB(curPlayer, mapID, posX, posY, takeTruck, fbID=0, msg='', canLock=True, funcLineID=0, enterFBFree=False):
def PlayerResetWorldPosFB(curPlayer, mapID, posX, posY, fbID=0, msg='', canLock=True, funcLineID=0, enterFBFree=False):
    '''
    参数说明:
        @param fbID:
@@ -2184,8 +1720,8 @@
    lastTransTick = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_TransTick)
    #暂定1秒
    if tick - lastTransTick < 1000:
        GameWorld.Log("玩家切图CD中: mapID=%s,posX=%s,posY=%s,takeTruck=%s,fbID=%s,msg=%s,funcLineID=%s,tick=%s,lastTransTick=%s"
                      % (mapID, posX, posY, takeTruck, fbID, msg, funcLineID, tick, lastTransTick), curPlayer.GetPlayerID())
        GameWorld.Log("玩家切图CD中: mapID=%s,posX=%s,posY=%s,fbID=%s,msg=%s,funcLineID=%s,tick=%s,lastTransTick=%s"
                      % (mapID, posX, posY, fbID, msg, funcLineID, tick, lastTransTick), curPlayer.GetPlayerID())
        NotifyCode(curPlayer, "MapMoveCD")
        return
    curPlayer.SetDict(ChConfig.Def_PlayerKey_TransTick, tick)
@@ -2205,10 +1741,7 @@
    #传送时, 锁定玩家, 传送成功, 在目标地图解锁, 传送失败, 在传送回调函数PlayerChangeMapFailCallback中解锁
    if canLock:
        curPlayer.BeginEvent()
    if not takeTruck:
        #取消自动运镖
        PlayerTruck.SetAutoTruckState(curPlayer, ShareDefine.Def_Out_Truck)
    #GameWorld.Log(1, "SetXP=%s"%(curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_RecordXPValue)))
    #curPlayer.SetXP(curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_RecordXPValue))
    #获取副本传入副本需要携带的信息
@@ -2216,12 +1749,12 @@
    
    NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_ReqFBMapID, mapID)
    NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_ReqFBFuncLine, funcLineID)
    GameWorld.Log("玩家请求开始切图: sceneMapID=%s,posX=%s,posY=%s,takeTruck=%s,fbID=%s,msg=%s,funcLineID=%s,tick=%s,lastTransTick=%s"
                  % (sceneMapID, posX, posY, takeTruck, fbID, msg, funcLineID, tick, lastTransTick), curPlayer.GetPlayerID())
    GameWorld.Log("玩家请求开始切图: sceneMapID=%s,posX=%s,posY=%s,fbID=%s,msg=%s,funcLineID=%s,tick=%s,lastTransTick=%s"
                  % (sceneMapID, posX, posY, fbID, msg, funcLineID, tick, lastTransTick), curPlayer.GetPlayerID())
    if enterFBFree:
        NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_EnterFBFree, 1)
        GameWorld.DebugLog("    本次免费进入副本!")
    curPlayer.ResetWorldPosReq(sceneMapID, posX, posY, takeTruck, fbID, msg)
    curPlayer.ResetWorldPosReq(sceneMapID, posX, posY, False, fbID, msg)
    curPlayer.SetDict(ChConfig.Def_PlayerKey_ChangeMapID, sceneMapID)
    curPlayer.SetDict(ChConfig.Def_PlayerKey_ChangeLineID, max(0, fbID))
    
@@ -2285,7 +1818,7 @@
    NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_HighChangeLineID, 0)
    
    #---开始切换线路---
    PlayerResetWorldPosFB(curPlayer, curPlayer.GetMapID(), curPlayer.GetPosX(), curPlayer.GetPosY(), False, changLineID)
    PlayerResetWorldPosFB(curPlayer, curPlayer.GetMapID(), curPlayer.GetPosX(), curPlayer.GetPosY(), changLineID)
    
    GameWorld.Log('玩家 = %s 切换分线 = %s, 锁住' % (curPlayer.GetName(), changLineID), curPlayer.GetID())
    return
@@ -2296,13 +1829,12 @@
# @param mapID 地图ID
# @param posX 坐标X
# @param posY 坐标Y
# @param takeTruck 是否携带镖车
# @param lineID 线路ID -1代表当前线
# @param msg 切换地图携带的信息
# @param canLock 是否可以锁定玩家(传送点不可锁定, 因为要跨地图寻路)
# @return 返回值无意义
# @remarks 玩家切换地图
def PlayerResetWorldPos(curPlayer, mapID, posX, posY, takeTruck, lineID=-1, msg='', canLock=True, exData1=0):
def PlayerResetWorldPos(curPlayer, mapID, posX, posY, lineID=-1, msg='', canLock=True, exData1=0):
    #更改: 死亡允许切换地图, 在副本中被怪打死, 副本时间到, 回收副本
#    if GameObj.GetHP(curPlayer) <= 0 :
#        GameWorld.Log("死亡无法切换地图")
@@ -2326,7 +1858,7 @@
        return
    
    #---不同地图ID切换地图---
    PlayerResetWorldPosFB(curPlayer, mapID, posX, posY, takeTruck, shuntLineID, msg, canLock)
    PlayerResetWorldPosFB(curPlayer, mapID, posX, posY, shuntLineID, msg, canLock)
    
    #如果是服务器中最后一个人离开, 则关掉副本
    GameWorldProcess.OnPlayerLeaveMapCloseFB()
@@ -2349,9 +1881,6 @@
        特殊boss分流: 
        @param bossID: 分流bossID
    '''
    if PlayerTJG.GetIsTJG(curPlayer):
        GameWorld.DebugLog("脱机的玩家不处理分流!", curPlayer.GetPlayerID())
        return tagLineID
    if GameWorld.IsCrossServer():
        return tagLineID
    # 非常规地图之间的切换不处理
@@ -3251,7 +2780,7 @@
                GameWorld.Log("等价货币补足扣除: type_Price%s, price=%s, curCurrency=%s, lackPrice=%s, tagMoneyType=%s, tagMoneyValue=%s" 
                                   % (type_Price, price, curCurrency, lackPrice, tagMoneyType, tagMoneyValue), curPlayer.GetPlayerID())
            else:
                #GameWorld.Log("没有等价货币,无法扣除")
                GameWorld.DebugLog("货币不足! type_Price=%s,curCurrency=%s < %s" % (type_Price, curCurrency, price))
                return False
        #有足够的钱支付
        SetPlayerCurrency(curPlayer, type_Price, curCurrency - lostMoney)
@@ -3301,15 +2830,18 @@
    elif type_Price == IPY_GameWorld.TYPE_Price_Silver_Paper:
        __PayMoneyAfterBySilverPaper(curPlayer, price)
    
    EventShell.EventRespons_OnMoneyChange(curPlayer, type_Price)
    #活跃度处理
    PlayerActivity.OnPayMoneyActivity(curPlayer, type_Price, price)
    #转盘活动
    PlayerActTurntable.OnPlayerUseGold(curPlayer, type_Price, price)
    #轮回殿
    PlayerActLunhuidian.AddLunhuidianValue(curPlayer, PlayerActLunhuidian.AwardType_PayMoney, type_Price, price)
    if type_Price == ShareDefine.TYPE_Price_Xiantao:
        unXiantaoCntExp = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_UnXiantaoCntExp)
        NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_UnXiantaoCntExp, unXiantaoCntExp + price)
        unXiantaoCntEquip = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_UnXiantaoCntEquip)
        NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_UnXiantaoCntEquip, unXiantaoCntEquip + price)
        PlayerPrestigeSys.AddRealmTaskValue(curPlayer, PlayerPrestigeSys.RealmTaskType_UseXiantao, price)
    unitPrice = price if quantity == 1 else int(math.ceil(price * 1.0 / quantity)) # 单价
    #reason_name = "Unknown" if not costType else costType
    reason_name = costType
@@ -3484,7 +3016,8 @@
        msgInfo = {"PlayerID":curPlayer.GetPlayerID(), "MoneyType":priceType, "Value":value, "GiveType":giveType, "AddDataDict":addDataDict}
        GameWorld.SendMsgToClientServer(ShareDefine.CrossServerMsg_GiveMoney, msgInfo, [serverGroupID])
        return True
    befMoney = GetMoney(curPlayer, priceType)
    if priceType == IPY_GameWorld.TYPE_Price_Gold_Money:
        updPlayerGold = GetMoneyReal(curPlayer, priceType) + value
        if updPlayerGold > ChConfig.Def_PlayerTotalMoney_Gold:
@@ -3534,7 +3067,6 @@
        SetPlayerCurrency(curPlayer, priceType, updValue)
        if priceType == ShareDefine.TYPE_Price_RealmPoint:
            PlayerSuccess.DoAddSuccessProgress(curPlayer, ShareDefine.SuccType_GetRealmPoint, value)
            EventShell.EventRespons_GetRealmPoint(curPlayer)
    else:
        GameWorld.ErrLog("金钱类型错误, priceType=%s,value=%s,giveType=%s" % (priceType, value, giveType), curPlayer.GetPlayerID())
        DataRecordPack.DR_GiveMoneyError(curPlayer, priceType, value, giveType, addDataDict)
@@ -3552,12 +3084,17 @@
            NotifyCode(curPlayer, "GetMoney", [priceType, value])
    __GiveMoneyAfter(curPlayer, priceType, value, giveType, addDataDict)
    
    if befMoney == 0:
        aftMoney = GetMoney(curPlayer, priceType)
        if aftMoney > 0:
            ItemControler.CheckGiveBindMoneyTypeItem(curPlayer, priceType)
    return True
def __GiveMoneyAfter(curPlayer, priceType, value, giveType, addDataDict):
    # 除钻石及绑钻外,未指定操作类型的不记录
    
    EventShell.EventRespons_OnMoneyChange(curPlayer, priceType)
    PlayerTask.AddTaskValue(curPlayer, ChConfig.TaskType_GetMoney, value, [priceType])
    
    if priceType not in [IPY_GameWorld.TYPE_Price_Gold_Money, IPY_GameWorld.TYPE_Price_Gold_Paper, ShareDefine.TYPE_Price_PayCoin] \
        and giveType == ChConfig.Def_GiveMoney_Unknown:
@@ -3704,16 +3241,11 @@
# @return 返回值, 参考经验
# @remarks 获得当前玩家的参考经验
def GetPlayerReExp(curPlayer):
    lvIpyData = GetPlayerLVIpyData(curPlayer.GetLV())
    if not lvIpyData:
        return 0
    return lvIpyData.GetReExp()
## 获得当前玩家的参考金钱
#  @param curPlayer 玩家实例
#  @return
def GetPlayerReMoney(curPlayer):
    return 0
    #lvIpyData = GetPlayerLVIpyData(curPlayer.GetLV())
    #if not lvIpyData:
    #    return 0
    #return lvIpyData.GetReExp()
#---------------------------------------------------------------------
##增加玩家的PK值
@@ -3736,8 +3268,6 @@
        #PK_wll_0: 您杀孽过重,在红名状态消失前您将不能继续而已攻击他人
        NotifyCode(curPlayer, "PK_lhs_202580")
        
    #玩家镖车身上记录玩家名字颜色信息(必须在设置红名以后)
    #PlayerTruck.ChangeTruckNoteInfo(curPlayer)
    return
def ChangePKValue(curPlayer, addValue, tick):
@@ -3789,8 +3319,6 @@
    ## 刷新红名对应PKValue
    curPKValue = curPlayer.GetPKValue()
    if not curPKValue:
        return
    if PlayerTJG.GetIsTJG(curPlayer):
        return
    redBuff = SkillCommon.FindBuffByID(curPlayer, ChConfig.Def_SkillID_Red)[0]
    if not redBuff:
@@ -3883,204 +3411,6 @@
    
#---------------------------------------------------------------------
## 功能模块战斗力类
#
#  分模块计算战斗力
class ModuleFightPower():
    __AttrName = "%s" # 参数为ChConfig.Def_Calc_AllAttrType_MAX对应所有属性列表索引
    __AttrNameNoline = "Noline_%s" # 参数为ChConfig.Def_Calc_AllAttrType_MAX对应所有属性列表索引
    __NolineAttrList = [ChConfig.TYPE_Calc_AttrSpeed] # 需要记录的非线性战斗属性
    ## 初始化
    #  @param self 类实例
    #  @return 返回值无意义
    #  @remarks 初始化
    def __init__(self, mfpType):
        self.mfpType = mfpType
        self.ClearAttr()
        return
    ## 重置所有属性
    #  @param self 类实例
    #  @return 返回值无意义
    def ClearAttr(self):
        for attrIndex in xrange(1, ChConfig.Def_Calc_AllAttrType_MAX):
            value = 0
            setattr(self, self.__AttrName % attrIndex, value)
        for attrIndex in self.__NolineAttrList:
            setattr(self, self.__AttrNameNoline % attrIndex, 0)
        return
    ## 根据战斗属性列表设置计算战斗力属性
    #  @param self 类实例
    #  @return 返回值无意义
    def SetCalcMFPBattleAttr(self, allAttrList):
        battleAttrDict = allAttrList[ChConfig.CalcAttr_Battle]
        # 设置本模块增加的线性战斗属性,非线性战斗属性增加的在刷属性时累加上去
        for attrIndex, value in battleAttrDict.items():
            self.AddCalcMFPAttr(attrIndex, value)
        # 非线性战斗属性仅设置时记录即可
        battleNolineAttrDict = allAttrList[ChConfig.CalcAttr_BattleNoline]
        for attrIndex, value in battleNolineAttrDict.items():
            if attrIndex in self.__NolineAttrList:
                setattr(self, self.__AttrNameNoline % attrIndex, value)
        return
    ## 设置计算战斗力属性值
    def SetCalcMFPAttr(self, attrIndex, value):
        if 1 <= attrIndex < ChConfig.Def_Calc_AllAttrType_MAX:
            attrName = self.__AttrName % attrIndex
            setattr(self, attrName, value)
        return
    ## 增加计算战斗力属性
    #  @param self 类实例
    #  @param key 计算属性类型
    #  @param value 计算属性数值
    #  @return 返回值无意义
    def AddCalcMFPAttr(self, attrIndex, value):
        # 如果有存在计算战斗力所需的参数key值,则增加上去
        if 1 <= attrIndex < ChConfig.Def_Calc_AllAttrType_MAX:
            attrName = self.__AttrName % attrIndex
            setattr(self, attrName, getattr(self, attrName) + value)
    def GetModuleFightPower(self, fpParam, curPlayer):
        MaxHP = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_AttrMaxHP) # 最大血量
        MinAtk = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_AttrATKMin) # 最小攻击
        MaxAtk = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_AttrATKMax) # 最大攻击
        Def = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_AttrDEF) # 物防
        Hit = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_AttrHit) * fpParam.GetCftHit() # 命中值
        Miss = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_AttrMiss) * fpParam.GetCftMiss() # 闪避值
        AtkSpeed = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_AttrAtkSpeed) # 攻击速度(数值非攻击间隔)
        SuperHitRate = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_SuperHitRate) * fpParam.GetCftSuperHitRate() # 暴击率
        SuperHitRateReduce = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_SuperHitRateReduce) * fpParam.GetCftSuperHitRateReduce() # 暴击概率抗性
        SuperHit = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_SuperHit) # 暴击伤害固定值
        SuperHitReduce = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_SuperHitReduce) # 暴击固定减伤
        LuckyHitRate = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_LuckyHitRate) * fpParam.GetCftLuckyHitRate() # 会心一击
        LuckyHitRateReduce = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_LuckyHitRateReduce) * fpParam.GetCftLuckyHitRateReduce() # 会心一击概率抗性
        LuckyHit = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_LuckyHit) # 会心一击伤害固定值
        LuckyHitReduce = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_LuckyHitReduce) # 会心一击伤害固定减伤
        SkillAtkRate = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_SkillAtkRate) * fpParam.GetCftSkillAtkRate() # 技能攻击比例加成
        SkillAtkRateReduce = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_SkillAtkRateReduce) * fpParam.GetCftSkillAtkRateReduce() # 技能攻击比例减少
        DamagePVP = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_DamagePVP)  # PVP固定伤害
        DamagePVPReduce = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_DamagePVPReduce)  # PVP固定减伤
        DamagePVE = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_DamagePVE)  # PVE固定伤害
        HPRestore = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_HPRestorePer) # 自动回复血量,固定值
        DamBackPer = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_DamBackPer) * fpParam.GetCftDamBackPer() # 反伤百分比
        SpeedValue = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_AttrSpeed) # 移动速度值
        SpeedPer = 0#getattr(self, self.__AttrNameNoline % ChConfig.TYPE_Calc_AttrSpeed) * fpParam.GetCftSpeedPer() # 移动速度百分比系数
        PetMinAtk = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_PetMinAtk) # 宠物最小攻击
        PetMaxAtk = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_PetMaxAtk) # 宠物最大攻击
        PetDamPer = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_PetDamPer) # 宠物伤害百分比提升
        IceAtk = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_AttrIceAtk) # 冰攻, 元素攻击
        IceDef = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_AttrIceDef) # 冰防, 元素防御
        IgnoreDefRate = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_IgnoreDefRate) * fpParam.GetCftIgnoreDefRate() # 无视防御几率
        IgnoreDefRateReduce = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_IgnoreDefRateReduce) * fpParam.GetCftIgnoreDefRateReduce() # 无视防御概率抗性
        DamChanceDef = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_DamChanceDef) * fpParam.GetCftDamChanceDef() # 20%的概率抵御伤害比率
        BleedDamage = 0#getattr(self, self.__AttrName % ChConfig.TYPE_Calc_BleedDamage) * fpParam.GetCftBleedDamage() # 流血伤害
        AtkBackHP = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_AtkBackHPPer) # 攻击回复血量
        FaintRate = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_FaintRate) * fpParam.GetCftFaintRate() # 触发击晕
        FaintDefRate = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_FaintDefRate) * fpParam.GetCftFaintDefRate() # 击晕抵抗
        FinalHurt = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_FinalHurt) # 最终固定伤害增加
        FinalHurtReduce = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_FinalHurtReduce) # 最终固定伤害减少
        BossFinalHurtPer = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_BossFinalHurtPer) * fpParam.GetCftBossFinalHurtPer() # Boss最终伤害万分率
        FinalHurtPer = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_FinalHurtPer) * fpParam.GetCftFinalHurtPer() # 最终伤害万分率
        FinalHurtReducePer = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_FinalHurtReducePer) * fpParam.GetCftFinalHurtReducePer() # 最终伤害减少万分率
        DamagePerPVP = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_DamagePerPVP) * fpParam.GetCftDamagePerPVP() # 伤害输出计算百分比PVP
        DamagePerPVPReduce = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_DamagePerPVPReduce) * fpParam.GetCftDamagePerPVPReduce() # 伤害输出计算百分比PVP减少
        JobAHurtAddPer = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_JobAHurtAddPer) * fpParam.GetCftJobAHurtAddPer() # 对目标战士伤害加成
        JobBHurtAddPer = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_JobBHurtAddPer) * fpParam.GetCftJobBHurtAddPer() # 对目标法师伤害加成
        JobCHurtAddPer = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_JobCHurtAddPer) * fpParam.GetCftJobCHurtAddPer() # 对目标弓箭伤害加成
        JobAAtkReducePer = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_JobAAtkReducePer) * fpParam.GetCftJobAAtkReducePer() # 战士攻击伤害减免
        JobBAtkReducePer = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_JobBAtkReducePer) * fpParam.GetCftJobBAtkReducePer() # 法师攻击伤害减免
        JobCAtkReducePer = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_JobCAtkReducePer) * fpParam.GetCftJobCAtkReducePer() # 弓箭攻击伤害减免
        AffairSpeedPer = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_AffairSpeedPer) * fpParam.GetCftAffairSpeedPer() # 仙盟事务速度加成
        FamilyBossHurtPer = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_FamilyBossHurtPer) * fpParam.GetCftFamilyBossHurtPer() # 仙盟BOSS伤害加成
        FamilyWarHPPer = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_FamilyWarHPPer) * fpParam.GetCftFamilyWarHPPer() # 仙盟联赛生命加成
        FamilyWarAtkPer = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_FamilyWarAtkPer) * fpParam.GetCftFamilyWarAtkPer() # 仙盟联赛攻击加成
        FamilySitExpPer = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_FamilySitExpPer) * fpParam.GetCftFamilySitExpPer() # 仙盟打坐经验加成
        NormalHurt = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_NormalHurt)
        NormalHurtPer = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_NormalHurtPer) * fpParam.GetCftNormalHurtPer() # 普通附加伤害加成
        FabaoHurt = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_FabaoHurt)
        FabaoHurtPer = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_FabaoHurtPer) * fpParam.GetCftFabaoHurtPer() # 法宝附加伤害加成
        Luck = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_Luck)
        ComboRate = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_ComboRate) # 连击几率
        ComboDamPer = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_ComboDamPer) # 连击伤害
        #MaxProDef = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_MaxProDef) # 最大防护值
        #ProDefAbsorb = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_ProDefAbsorb) # 防护值吸收伤害比率
        ProDefPer = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_ProDefHPPer) # 防护转化百分比
        OnlyFinalHurt = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_OnlyFinalHurt) # 额外输出伤害
        PVPAtkBackHP = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_PVPAtkBackHP) # PVP攻击回血
        NPCHurtAddPer = getattr(self, self.__AttrName % ChConfig.TYPE_Calc_NPCHurtAddPer) * fpParam.GetCftNPCHurtAddPer() # 对怪物伤害加成
        #其他需作为公式参数的系数
        AtkSpeedParameter = fpParam.GetCftAtkSpeed()
        LuckyHitParameter = 0#fpParam.GetCftLuckyHit()
        #取总属性的
        SuperHitRateTotal = curPlayer.GetSuperHitRate()
        LuckyHitRateTotal = curPlayer.GetLuckyHitRate()
        job = curPlayer.GetJob()
        diffAttrDict = self.__GetAttrFightPowerParamDiff(job)
        for paramName, diffValue in diffAttrDict.items():
            exec("%s = max(0, %s - %s)" % (paramName, paramName, diffValue))
        #获取策划配置的表格
        FightpowerFormula = IpyGameDataPY.GetFuncCfg("FightpowerFormula")
        totalFightPower = eval(FormulaControl.GetCompileFormula("FightpowerFormula", FightpowerFormula))
        #GameWorld.DebugLog("MfpType=%s,FightPower=%s, %s" % (self.mfpType, totalFightPower, self.GetMFPAttrStr()))
        if totalFightPower > ShareDefine.Def_UpperLimit_DWord:
            GameWorld.ErrLog("模块战力超过数值上限, MfpType=%s,fightPower=%s, %s" % (self.mfpType, totalFightPower, self.GetMFPAttrStr()))
            #totalFightPower = ShareDefine.Def_UpperLimit_DWord 模块战力支持超20亿,日志暂保留用于输出提醒
        return totalFightPower
    def __GetAttrFightPowerParamDiff(self, job):
        ## 战力计算属性参数与实际属性差值
        #角色基础模块某些属性不计算战力
        if self.mfpType != ShareDefine.Def_MFPType_Role:
            return {}
        roleBaseAttrDict = IpyGameDataPY.GetFuncEvalCfg("CreatRoleBaseAttr", 1)
        notFightPowerEffIDNameDict = IpyGameDataPY.GetFuncEvalCfg("CreatRoleBaseAttr", 2)
        if job not in roleBaseAttrDict:
            return {}
        diffAttrDict = {}
        jobBaseAttrDict = roleBaseAttrDict[job]
        for attrID, paramName in notFightPowerEffIDNameDict.items():
            if attrID not in jobBaseAttrDict:
                continue
            diffAttrDict[paramName] = jobBaseAttrDict[attrID]
        return diffAttrDict
    def GetMFPAttrStr(self):
        attrStr = ""
        for attrIndex in xrange(1, ChConfig.Def_Calc_AllAttrType_MAX):
            attrName = self.__AttrName % attrIndex
            attrValue = getattr(self, attrName)
            if attrValue <= 0:
                continue
            attrStr += "%s=%s," % (attrName, attrValue)
        for attrIndex in self.__NolineAttrList:
            attrName = self.__AttrNameNoline % attrIndex
            attrValue = getattr(self, attrName)
            if attrValue <= 0:
                continue
            attrStr += "%s=%s," % (attrName, attrValue)
        return attrStr
###############################################################
#人物控制类
@@ -4089,7 +3419,7 @@
#  人物死亡等逻辑处理
class PlayerControl:
    __Player = None
    __fpTypeObjDict = {}
    #---------------------------------------------------------------------
    ## 初始化
    #  @param self 类实例
@@ -4098,76 +3428,6 @@
    #  @remarks 初始化
    def __init__(self, iPlayer):
        self.__Player = iPlayer
    ## 获取模块战斗力对象
    #  @param self 类实例
    #  @param fpType 战斗力类型
    #  @return 返回战斗力对象
    def GetModuleFightPowerObj(self, fpType):
        fpObj = self.__fpTypeObjDict.get(fpType)
        if not fpObj:
            fpObj = ModuleFightPower(fpType)
            self.__fpTypeObjDict[fpType] = fpObj
        return fpObj
    ## 获取模块战斗力对象
    #  @param self 类实例
    #  @return 返回战斗力对象
    def ResetFightPowerObj(self):
        for obj in self.__fpTypeObjDict.values():
            obj.ClearAttr()
    #---------------------------------------------------------------------
    ## 玩家升级加点加技能 前20级自动加点 20级后 以前是加技能点现改成直接升级后读表加技能
    #  @param self 类实例
    #  @return None
    #  @remarks 玩家升级 加点 2010-05-26 adaws修改 原来有加技能点 现将升级加技能提出
    def __DoLVUPAddPoint(self):
        curPlayer = self.__Player
        if not GameFuncComm.GetFuncCanUse(curPlayer, ShareDefine.GameFuncID_AddPoint):
            # 未开启前不可加点,因为DoAddPointOpen会一次性补齐,避免意外情况多加了点数
            return
        curFreePoint = curPlayer.GetFreePoint()
        addPoint = GetLvUp_AddPoint(curPlayer)
        if addPoint != 0:
            setFreePoint = curFreePoint + addPoint
            #NotifyCode(curPlayer, "ObtainAttributeDot", [addPoint])
            DataRecordPack.DR_Freepoint(curPlayer, "LvUP", addPoint)
            curPlayer.SetFreePoint(setFreePoint)
        return
    #---------------------------------------------------------------------
    ## 检查玩家是否需要封爵
    #  @param self 类实例
    #  @param curPlayer 玩家实例
    #  @param curLV 当前等级
    #  @return 返回值真, 需要
    #  @remarks 检查玩家是否需要封爵
    def __LVUpDoInvestiture(self, curPlayer, curLV):
#===============================================================================
#        此逻辑不能用 GetTotalExp,
#        改动请慎重!
#===============================================================================
        #1. 检查玩家是否在封爵等级
        if curLV < 20 or curLV % 10 != 0:
            return False
        curMission = curPlayer.FindMission(curLV * 100)
        if curMission != None and curMission.GetState() == ChConfig.Def_Mission_State_Over:
            #任务完成
            return False
        if curMission == None:
            #2. 如果在封爵等级, 并且即将升到下一级, 触发封爵任务
            if EventShell.EventResponse_LVFull(curPlayer) != True:
                GameWorld.Log("触发封爵任务失败", curPlayer.GetPlayerID())
                return False
        return True
    #---------------------------------------------------------------------
    
    ## 加经验值 
    #  @param self 类实例
@@ -4189,31 +3449,25 @@
            NetPackCommon.SendFakePack(curPlayer, sendPack)
            
        #副本获得经验, 无论获得多少经验均需通知, 有些副本逻辑需要通过获得经验时机处理
        if GameWorld.GetMap().GetMapFBType() != IPY_GameWorld.fbtNull:
            FBLogic.OnGetExp(curPlayer, finalAddExp, expViewType)
        #if GameWorld.GetMap().GetMapFBType() != IPY_GameWorld.fbtNull:
        #    FBLogic.OnGetExp(curPlayer, finalAddExp, expViewType)
        return finalAddExp
    
    # 参数 addSkillID 表示因什么技能杀死NPC获得经验
    def __AddExp(self, curPlayer, addExp, expViewType, isSysHint, addSkillID=0, expRateEx=0):
        if addExp == 0:
        if addExp <= 0:
            # 不进入计算
            return addExp, expViewType
        
        #取得人物当前经验
        #curTotalExp = GetPlayerTotalExp(curPlayer)
        curTotalExp = curPlayer.GetExpPoint() * ChConfig.Def_PerPointValue + curPlayer.GetTotalExp()
        maxLV = GetPlayerMaxLV(curPlayer)
        maxLVExpStore = IpyGameDataPY.GetFuncCfg("MaxLVExpStore", 1)
        curTotalExp = GetPlayerTotalExp(curPlayer)
        
        curLV = curPlayer.GetLV()
#        # 检查转生等级
#        if curLV >= nextReinLV and curTotalExp >= maxLVExpStore:
#            self.__NotifyExpFull(curPlayer, "GeRen_liubo_260986")
#            GameWorld.DebugLog("经验已满!需先转生!curLV=%s,reinLV=%s" % (curLV, nextReinLV), curPlayer.GetPlayerID())
#            return 0
        maxLV = GetPlayerMaxLV(curPlayer)
        maxLVExpStore = IpyGameDataPY.GetFuncCfg("PlayerMaxLV", 2)
        curLV = curPlayer.GetLV()
        # 检查最大等级,maxLVExpStore -1时不限累计经验上限
        if curLV >= maxLV and curTotalExp >= maxLVExpStore and maxLVExpStore != -1:
            self.__NotifyExpFull(curPlayer, "GeRen_admin_825676")
@@ -4223,90 +3477,26 @@
        # 杀怪
        if expViewType == ShareDefine.Def_ViewExpType_KillNPC:
            exp_rate = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_TotalExpRate)
            superRate = PassiveBuffEffMng.GetPassiveSkillValueByTriggerType(curPlayer, None, None, ChConfig.TriggerType_AddExpRate)
            if superRate:
                # 龙凤镯 经验
                expViewType = ShareDefine.Def_ViewExpType_KillNPCSuper
            if addSkillID == ChConfig.Def_SkillID_LXHY_AddExpRate:
                addSkill = GameWorld.GetGameData().GetSkillBySkillID(addSkillID)
                hasEffect = SkillCommon.GetSkillEffectByEffectID(addSkill, ChConfig.Def_Skill_Effect_AddExpRate)
                if hasEffect:
                    #烈焰战神 经验
                    superRate += hasEffect.GetEffectValue(0)
                    expViewType = ShareDefine.Def_ViewExpType_LYZS
            exp_rate += superRate
        elif expViewType in [ShareDefine.Def_ViewExpType_GameEvent, ShareDefine.Def_ViewExpType_Sit]:
            exp_rate = curPlayer.GetGameEventExpRate()
            exp_rate += GetFamilySitExpPer(curPlayer)
            #exp_rate += GetFamilySitExpPer(curPlayer)
        else:
            exp_rate = max(GameWorld.GetGameWorld().GetExpRate(), ChConfig.Def_MaxRateValue)
        exp_rate += expRateEx
        #输入的经验有可能为long型
        addExp = int(addExp * exp_rate / float(ChConfig.Def_MaxRateValue))
        
        #防沉迷计算
        addExp = PlayerGameWallow.ChangeExpByWallow(curPlayer, addExp)
        #===========================================================================================
        # #特殊地图杀怪经验外层加成
        # if expViewType == ShareDefine.Def_ViewExpType_KillNPC:
        #    #mapID = GameWorld.GetMap().GetMapID()
        #    #if mapID in ChConfig.Def_FBMapID_BZZDAll:
        #    #    nobleVIPOuterRate = ...
        #    #    #nobleVIPAddExp += 0 if not nobleVIPOuterRate else int(addExp * nobleVIPOuterRate / float(ChConfig.Def_MaxRateValue))
        #    #    nobleVIPAddExp += nobleVIPOuterRate
        #
        #    outerExpRate = FBLogic.OnGetOuterExpRate(curPlayer)
        #    if outerExpRate > 0:
        #        addExp = int(addExp * outerExpRate / float(ChConfig.Def_MaxRateValue))
        #===========================================================================================
        # 不可再升级时,增加后的经验不可超过最大可存储经验
        #if curLV >= nextReinLV or curLV >= maxLV:
        if curLV >= maxLV and maxLVExpStore > 0:
            addExp = min(addExp, max(0, maxLVExpStore - curTotalExp))
        if addExp <= 0:
            #无法获得经验
            GameWorld.DebugLog("无法获得经验")
            return 0, expViewType
        
        #addExp = min(addExp, ChConfig.Def_UpperLimit_DWord) # 单次加经验不超过20亿
        #缓存获取的经验值, 用于兑换家族荣誉
        #if curPlayer.GetFamilyID() != 0:
        #    curPlayer.SetPerExp(min(curPlayer.GetPerExp() + addExp, ChConfig.Def_UpperLimit_DWord))
        #人物头顶提示
        #=======================================================================
        # viewExpCnt = min(2, addExp / ChConfig.Def_UpperLimit_DWord) # 最多飘两次20亿的
        # viewExp = addExp % ChConfig.Def_UpperLimit_DWord
        # for _ in range(viewExpCnt):
        #    curPlayer.Notify_GetExpView(ChConfig.Def_UpperLimit_DWord, expViewType)
        # if viewExp:
        #    curPlayer.Notify_GetExpView(viewExp, expViewType)
        #
        # if isSysHint:
        #    # 杀怪附加加成显示
        #    if expViewType == ShareDefine.Def_ViewExpType_KillNPC:
        #        nobleVIPAddExp = int(nobleVIPAddExp / 100.0)
        #        #NotifyCode(curPlayer, "GeRen_liubo_74717", [addExp, nobleVIPAddExp])
        #    elif expViewType in [ShareDefine.Def_ViewExpType_GameEvent,
        #                         ShareDefine.Def_ViewExpType_Sit]:
        #        #小游戏事件特殊提示,打坐获取经验
        #        NotifyCode(curPlayer, "ObtainExperience", [addExp])
        #    elif expViewType == ShareDefine.Def_ViewExpType_MousePos:
        #        #鼠标位置提示获得经验
        #        NotifyCode(curPlayer, "GeRen_admin_887936", [addExp])
        #    else:
        #        #正常信息提示
        #        NotifyCode(curPlayer, "GeRen_lhs_0", [addExp])
        #=======================================================================
        #给人物经验 先设经验后升级
        #SetPlayerTotalExp(curPlayer, curTotalExp + addExp)
        totalExp = curTotalExp + addExp
        curExp = totalExp % ChConfig.Def_PerPointValue
        expPoint = totalExp / ChConfig.Def_PerPointValue
@@ -4315,13 +3505,10 @@
            curPlayer.SetExpPoint(expPoint)
        if curPlayer.GetTotalExp() != curExp:
            curPlayer.SetTotalExp(curExp)
        #GameWorld.Log("玩家 = %s 得到经验 = %s ,当前经验倍率 = %s"%(curPlayer.GetName(), addExp,expRate ))
        #小于转生等级才可升级
        #if curLV < nextReinLV and curLV < maxLV:
        if curLV < maxLV:
            self.PlayerLvUp()
        #添加经验成功
        return addExp, expViewType
    
@@ -4341,29 +3528,22 @@
    def PlayerLvUp(self, handLvUp=False):
        curPlayer = self.__Player
        
        if GameObj.GetHP(curPlayer) <= 0:
            #玩家死亡不可升级
            return
        #if GameObj.GetHP(curPlayer) <= 0:
        #    #玩家死亡不可升级
        #    return
        
        #lvIpyData = GetPlayerLVIpyData(curPlayer.GetLV())
        lvIpyData = IpyGameDataPY.GetIpyGameData("PlayerLV", curPlayer.GetLV())
        lvIpyData = GetPlayerLVIpyData(curPlayer.GetLV())
        if not lvIpyData:
            GameWorld.ErrLog("经验表异常  lv= %s" % curPlayer.GetLV())
            return
        #lvUpNeedExp = GetLVUPTotalExpNeed(lvIpyData)
        lvUpNeedExp = lvIpyData.GetExpPoint() * ChConfig.Def_PerPointValue + lvIpyData.GetExp()
        lvUpNeedExp = GetLVUPTotalExpNeed(lvIpyData)
        if lvUpNeedExp <= 0:
            return
        
        #增加经验
        #curTotalExp = GetPlayerTotalExp(curPlayer)
        curTotalExp = curPlayer.GetExpPoint() * ChConfig.Def_PerPointValue + curPlayer.GetTotalExp()
        curTotalExp = GetPlayerTotalExp(curPlayer)
        #未达到升级经验
        if curTotalExp < lvUpNeedExp:
            return
        needSyncTalentPoint = False
        playerNeedDoLVUp = False
        curLV = curPlayer.GetLV()
        maxLV = GetPlayerMaxLV(curPlayer)
@@ -4371,14 +3551,7 @@
        curPlayer.BeginRefreshState()
        #befXP = curPlayer.GetXP()
        befLV = curPlayer.GetLV()
        befFreePoint = curPlayer.GetFreePoint()
        befBaseSTR = curPlayer.GetBaseSTR()
        befBasePNE = curPlayer.GetBasePNE()
        befBasePHY = curPlayer.GetBasePHY()
        befBaseCON = curPlayer.GetBaseCON()
        #升级前的世界等级经验
        #beforeExpRate = PlayerWorldAverageLv.GetWorldAverageLvExpRate(curPlayer)
        #befFreePoint = curPlayer.GetFreePoint()
        
        while curTotalExp >= lvUpNeedExp and curLV < maxLV:
            
@@ -4393,26 +3566,17 @@
                isNotifyServer = False
            
            curPlayer.SetLV(curLV, isNotifyServer)
            EventReport.WriteEvent_level_up(curPlayer)
            #EventReport.WriteEvent_level_up(curPlayer)
                       
            # 记录玩家升级
            DataRecordPack.DR_PlayerUpgrade(curPlayer, curPlayer.GetLV(), GetPlayerTotalExp(curPlayer), lvUpNeedExp)
            DataRecordPack.Cache_FightPowerChangeInfo(curPlayer, ChConfig.PowerDownType_LVUP, {'lv':curLV})
            self.__GiveLVMailAward(curLV)
            self.__DoLVUPAddPoint()  # 升级加点
            #self.__DoLVUPAddPoint()  # 升级加点
            #self.__DoLvUpAddSkill()  # 升级加技能
            
            lvIpyData = GetPlayerLVIpyData(curPlayer.GetLV())
            # 大师天赋点
            if lvIpyData:
                addTalentPoint = lvIpyData.GetTalentPoint()
                if addTalentPoint:
                    needSyncTalentPoint = True
                    PlayerGreatMaster.AddGreatMasterSkillPointByLV(curPlayer, addTalentPoint)
            
            EventShell.EventResponse_LVUp(curPlayer)  # 升级触发事件
            PlayerTongTianLing.AddTongTianTaskValue(curPlayer, ChConfig.TTLTaskType_LVUp, 1)
            #---是否继续循环---
            curTotalExp = curTotalExp - lvUpNeedExp
            
@@ -4427,57 +3591,28 @@
        #有升级, 转生时刚好是转生等级会默认+1级
        if playerNeedDoLVUp:
            aftLV = curPlayer.GetLV()
            aftFreePoint = curPlayer.GetFreePoint()
            aftBaseSTR = curPlayer.GetBaseSTR()
            aftBasePNE = curPlayer.GetBasePNE()
            aftBasePHY = curPlayer.GetBasePHY()
            aftBaseCON = curPlayer.GetBaseCON()
            #aftFreePoint = curPlayer.GetFreePoint()
            if aftLV > befLV:
                curPlayer.SetLV(aftLV, False) # 这里不再通知GameServer
                PlayerTongTianLing.AddTongTianTaskValue(curPlayer, ChConfig.TTLTaskType_LVUp, aftLV - befLV)
                PlayerTask.UpdTaskValue(curPlayer, ChConfig.TaskType_LV)
                PlayerSuccess.UptateSuccessProgress(curPlayer, ShareDefine.SuccType_HeroLV, aftLV)
                PlayerActivity.DoAddActivityByLV(curPlayer, befLV, aftLV)
                
            if aftFreePoint > befFreePoint:
                curPlayer.SetFreePoint(aftFreePoint)
                #NotifyCode(curPlayer, "ObtainAttributeDot", [aftFreePoint - befFreePoint])
            if aftBaseSTR > befBaseSTR:
                curPlayer.SetBaseSTR(aftBaseSTR)
            if aftBasePNE > befBasePNE:
                curPlayer.SetBasePNE(aftBasePNE)
            if aftBasePHY > befBasePHY:
                curPlayer.SetBasePHY(aftBasePHY)
            if aftBaseCON > befBaseCON:
                curPlayer.SetBaseCON(aftBaseCON)
            #if aftFreePoint > befFreePoint:
            #    curPlayer.SetFreePoint(aftFreePoint)
            PlayerGubao.DoGubaoAddFreePoint(curPlayer)
            #===================================================================
            # if curPlayer.GetXP() != befXP:
            #    curPlayer.SetXP(curPlayer.GetXP())
            #===================================================================
            #享受世界等级
            #===================================================================
            #curExpRate = PlayerWorldAverageLv.GetWorldAverageLvExpRate(curPlayer)
            #if beforeExpRate <= 0 and curExpRate > 0:
            #    NotifyCode(curPlayer, "GeRen_liubo_127574")
            
            #===================================================================
            # 天赋点通知
            if needSyncTalentPoint:
                PlayerGreatMaster.Sync_GreatMasterFreeSkillPoint(curPlayer)
            # 升级需要执行的游戏功能处理
            GameFuncComm.DoFuncOpenLogic(curPlayer)
            ChEquip.RefreshPlayerLingQiEquipAttr(curPlayer) # 灵器属性会随等级成长
            if aftLV%10 == 0:
                # 控制下刷新次数
                PlayerPet.CalcPetItemAddPlayerAttr(curPlayer)   # 宠物有随等级变化的技能
            
            self.RefreshPlayerAttrState(billboardFunc=PlayerBillboard.UpdatePlayerLVBillboard)
            #放在功能开启后面
            PlayerWorldAverageLv.UpdatePlayerWorldAverageLv(curPlayer)
            PlayerOnline.CalcRoleBase(curPlayer)
            PlayerOnline.GetOnlinePlayer(curPlayer).RefreshRoleAttr()
            #将血设置为最大
            GameObj.SetHPFull(curPlayer)
            if curPlayer.GetMaxMP() > 0:
                curPlayer.SetMP(curPlayer.GetMaxMP())
            #GameObj.SetHPFull(curPlayer)
            #if curPlayer.GetMaxMP() > 0:
            #    curPlayer.SetMP(curPlayer.GetMaxMP())
            
            FBLogic.OnPlayerLVUp(curPlayer)
            # 记录开服活动冲级数据
@@ -4500,152 +3635,6 @@
        return
    
    #---------------------------------------------------------------------
    def CalcRoleBaseAttr(self, curPlayer):
        # 计算玩家角色基础属性值
        curPlayerID = curPlayer.GetID()
        job = curPlayer.GetJob()
        lvAttrDict = IpyGameDataPY.GetFuncEvalCfg("LVUPAttr%s" % job, 1)
        if not lvAttrDict:
            GameWorld.ErrLog('无此职业等级刷属性配置!job=%s' % (job), curPlayerID)
            return
        allAttrList = [{} for _ in range(4)]
        # 职业初始属性
        roleBaseAttrDict = IpyGameDataPY.GetFuncEvalCfg("CreatRoleBaseAttr", 1)
        if job in roleBaseAttrDict:
            for roleBaseAttrID, value in roleBaseAttrDict[job].items():
                CalcAttrDict_Type(roleBaseAttrID, value, allAttrList)
        #GameWorld.DebugLog("初始加属性: %s" % allAttrList)
        # 等级成长属性
        LV = curPlayer.GetLV()
        for lvAttrID, formula in lvAttrDict.items():
            calcValue = eval(FormulaControl.GetCompileFormula("LVUPAttr%s_%s" % (job, lvAttrID), formula))
            CalcAttrDict_Type(lvAttrID, calcValue, allAttrList)
            #GameWorld.DebugLog("    lvAttrID=%s,calcValue=%s" % (lvAttrID, calcValue))
        #GameWorld.DebugLog("等级加属性: %s" % allAttrList)
        # 属性点属性
        hadRefreshAttr = curPlayer.GetDictByKey(ChConfig.Def_Player_HadRefreshAttr) # 本地图是否刷新过属性
        pointFightPowerEx = 0
        pointValueInfo = {ShareDefine.Def_Effect_Metal:[lambda curObj:GetMetal(curObj), lambda curObj, value:SetMetalQualityLV(curObj, value), lambda curObj:GetMetalQualityLV(curObj)],
                          ShareDefine.Def_Effect_Wood:[lambda curObj:GetWood(curObj), lambda curObj, value:SetWoodQualityLV(curObj, value), lambda curObj:GetWoodQualityLV(curObj)],
                          ShareDefine.Def_Effect_Water:[lambda curObj:GetWater(curObj), lambda curObj, value:SetWaterQualityLV(curObj, value), lambda curObj:GetWaterQualityLV(curObj)],
                          ShareDefine.Def_Effect_Fire:[lambda curObj:GetFire(curObj), lambda curObj, value:SetFireQualityLV(curObj, value), lambda curObj:GetFireQualityLV(curObj)],
                          ShareDefine.Def_Effect_Earth:[lambda curObj:GetEarth(curObj), lambda curObj, value:SetEarthQualityLV(curObj, value), lambda curObj:GetEarthQualityLV(curObj)],
                          }
        hasChange_Qualitylv = False #灵根品级是否有变更
        lingGenQualityAttrList = [{} for _ in range(4)]
        for pointAttrID, pointFuncInfo in pointValueInfo.items():
            pointValue = pointFuncInfo[0](curPlayer)
            befPQLV = pointFuncInfo[2](curPlayer)
            pointFuncInfo[1](curPlayer, 0)
            if not pointValue:
                if 0 != befPQLV:
                    hasChange_Qualitylv = True
                continue
            ipyData = IpyGameDataPY.GetIpyGameData("RolePoint", pointAttrID)
            if not ipyData:
                continue
            # 每点属性
            perPointAddAttrDict = ipyData.GetAddAttrInfoPerPoint() # {"职业":[[每X点,属性ID,值], ...], ..}
            addAttrList = perPointAddAttrDict.get(str(job), [])
            for needPoint, pointAddAttrID, pointAddAttrValue in addAttrList:
                pointAddValueTotal = pointAddAttrValue * (pointValue / needPoint)
                CalcAttrDict_Type(pointAddAttrID, pointAddValueTotal, allAttrList)
                #GameWorld.DebugLog("    属性点(%s)加属性: pointValue=%s,pointAddAttrID=%s,pointAddValueTotal=%s" % (pointAttrID, pointValue, pointAddAttrID, pointAddValueTotal))
            pointFightPowerEx += (ipyData.GetFightPowerPerPoint() * pointValue)
            # 点数品质属性
            curPQLV = 0
            pqIntervalList = ipyData.GetPointQualityIntervalList()
            for pqLV, pqValue in enumerate(pqIntervalList, 1): # 灵根品级从1开始
                if pointValue >= pqValue:
                    curPQLV = pqLV
                else:
                    break
            pointFuncInfo[1](curPlayer, curPQLV)
            if curPQLV != befPQLV:
                hasChange_Qualitylv = True
            if not curPQLV:
                continue
            pqAttrInfoDict = ipyData.GetPointQualityAttrDict().get(str(curPlayer.GetJob()), {})
            for pqAttrID, pqAttrValueList in pqAttrInfoDict.items():
                pqAttrValue = 0 if curPQLV > len(pqAttrValueList) else pqAttrValueList[curPQLV - 1]
                CalcAttrDict_Type(int(pqAttrID), pqAttrValue, lingGenQualityAttrList)
            #GameWorld.DebugLog("        属性点(%s)品阶等级属性: befPQLV=%s,curPQLV=%s,pqAttrInfoDict=%s" % (pointAttrID, befPQLV, curPQLV, pqAttrInfoDict))
            if hadRefreshAttr and befPQLV < curPQLV:
                for pqlv in xrange(befPQLV+1, curPQLV+1):
                    EventShell.EventRespons_LingGenQualityUP(curPlayer, pointAttrID, pqlv)
        #GameWorld.DebugLog("等级属性点加属性: %s" % allAttrList)
        #GameWorld.DebugLog("灵根品阶等级属性: %s" % lingGenQualityAttrList)
        #GameWorld.DebugLog("灵根点数附加战力: %s" % pointFightPowerEx)
        SetMFPExFightPower(curPlayer, ShareDefine.Def_MFPType_Role, pointFightPowerEx)
        SetCalcAttrListValue(curPlayer, ChConfig.Def_CalcAttrFunc_RoleBase, allAttrList)
        SetCalcAttrListValue(curPlayer, ChConfig.Def_CalcAttrFunc_LingGenQuailty, lingGenQualityAttrList)
        return hasChange_Qualitylv
    #---------------------------------------------------------------------
    def NotifyAllState(self, playerStateDict):
        curPlayer = self.__Player
        notifySelfList = []
        notifyAllList = []
        notifyAllAttrState = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_NotifyAllAttrState)
        #在此处把所有属性的不同通知给客户端
        for index, value in playerStateDict.items():
            curPlayerState, attrType, notifySelf, notifyAll = EffGetSet.GetValueByEffIndexEx(curPlayer, index)
            if not attrType:
                continue
            if notifyAllAttrState and curPlayerState == value:
                #GameWorld.Log("第%d个,原值%d等于现值%d,不发给客户端"%( index, value, curPlayerState ) )
                continue
            notifyStruct = ChPyNetSendPack.tagRefreshType()
            notifyStruct.RefreshType = attrType
            if attrType in [IPY_PlayerDefine.CDBPlayerRefresh_HP, IPY_PlayerDefine.CDBPlayerRefresh_MaxHP]:
                notifyStruct.Value = curPlayerState % ShareDefine.Def_PerPointValue
                notifyStruct.ValueEx = curPlayerState / ShareDefine.Def_PerPointValue
            else:
                notifyStruct.Value = curPlayerState
            if notifySelf:
                notifySelfList.append(notifyStruct)
            if notifyAll:
                notifyAllList.append(notifyStruct)
        #属性组合包
        #通知自己
        if notifySelfList:
            sendPack = ChPyNetSendPack.tagObjInfoListRefresh()
            sendPack.Clear()
            sendPack.ObjID = curPlayer.GetID()
            sendPack.ObjType = curPlayer.GetGameObjType()
            sendPack.Count = len(notifySelfList)
            sendPack.RefreshType = notifySelfList
            NetPackCommon.SendFakePack(curPlayer, sendPack)
        if len(notifyAllList) != 0:
            #广播周围玩家
            sendPack = ChPyNetSendPack.tagObjInfoListRefresh()
            sendPack.Clear()
            sendPack.ObjID = curPlayer.GetID()
            sendPack.ObjType = curPlayer.GetGameObjType()
            sendPack.Count = len(notifyAllList)
            sendPack.RefreshType = notifyAllList
            PyNotifyAll(curPlayer, sendPack, False, -1)
        if not notifyAllAttrState:
            curPlayer.SetDict(ChConfig.Def_PlayerKey_NotifyAllAttrState, 1)
        return
    
    ## 刷新玩家所有状态
    #  @param self 类实例
@@ -4653,58 +3642,13 @@
    #  @return 返回值无意义
    #  @remarks 刷新玩家所有状态
    def RefreshAllState(self, isSyncBuff=False, billboardFunc=None, isForce=False):
        curPlayer = self.__Player
        playerID = curPlayer.GetPlayerID()
        GameWorld.DebugLog("Start RefreshAllState!!!", playerID)
        self.RefreshPlayerActionState()
        self.RefreshPlayerAttrState(billboardFunc, isForce)
        return
    
    ## 重计算并刷新玩家所有状态, 目前只用与切换地图
    #  @param self 类实例
    #  @return 返回值无意义
    #  @remarks 刷新玩家所有状态
    def ReCalcAllState(self):
        curPlayer = self.__Player
        playerID = curPlayer.GetPlayerID()
        GameWorld.DebugLog("Start ReCalcAllState!!!", playerID)
        for funcIndex in ChConfig.CalcAttrFuncList:
            ClearCalcAttrListValue(curPlayer, funcIndex)
        #先压入BUFF的效果值及技能战斗力
        self.RefreshAllSkill()
        ChEquip.RefreshPlayerEquipAttribute(curPlayer)
        ChEquip.RefreshPlayerLingQiEquipAttr(curPlayer)
        #SkillShell.RefreshPlayerBuffOnAttrAddEffect(curPlayer)
        PlayerHorse.CalcHorseAttrEx(curPlayer)
        PlayerPrestigeSys.CalcOfficialRankAttr(curPlayer)
        PlayerGodWeapon.CalcGodWeaponAttr(curPlayer)
        PlayerDienstgrad.CalcAllDienstgradAttr(curPlayer)
        PlayerPet.CalcPetItemAddPlayerAttr(curPlayer)
        PlayerRune.RefreshRuneAttr(curPlayer)
        PlayerMagicWeapon.CalcMagicWeaponAttr(curPlayer)
        PlayerSuccess.CalcSuccessAttr(curPlayer)
        PlayerVip.CalcVIPAttr(curPlayer)
        PlayerRefineStove.CalcStoveAttr(curPlayer)
        PlayerFamilyTech.CalcFamilyTechAttr(curPlayer)
        PlayerEquipDecompose.RefreshEDAttr(curPlayer)
        PlayerDogz.RefreshDogzAttr(curPlayer)
        PlayerGatherSoul.RefreshGatherSoulAttr(curPlayer)
        PlayerGatherTheSoul.CalcSoulAttr(curPlayer)
        PlayerCoat.CalcClothesCoatSkinAttr(curPlayer)
        PlayerFaQi.CalcFaQiAttr(curPlayer)
        PlayerLove.CalcLoveAttr(curPlayer)
        PlayerCharm.CalcCharmAttr(curPlayer)
        PlayerLianTi.CalcLianTiAttr(curPlayer)
        PlayerShentong.CalcShentongAttr(curPlayer)
        PlayerFamilyZhenfa.CalcZhenfaAttr(curPlayer)
        PlayerFace.CalcFaceAttr(curPlayer)
        PlayerFace.CalcFacePicAttr(curPlayer)
        self.RefreshAllState(isForce=True)
        GameWorld.DebugLog("End ReCalcAllState!!!", playerID)
        return
    
    
@@ -4719,36 +3663,7 @@
    
    # BUFF层单独刷新属性
    def RefreshPlayerAttrByBuffEx(self):
        curPlayer = self.__Player
        if curPlayer.GetDictByKey(ChConfig.Def_Player_RefreshAttrByBuff) != 1:
            return
        playerID = curPlayer.GetPlayerID()
        GameWorld.DebugLog("Start RefreshPlayerAttrByBuffEx!!!", playerID)
        beforeMaxHP = GameObj.GetMaxHP(curPlayer)
        beforeMoveSpeedValue = GetSpeedValue(curPlayer)
        #构建玩家刷新通知客户端字典, 缓存[索引, 数值]
        playerStateDict = {}
        for index in xrange(1, ChConfig.Def_Calc_AllAttrType_MAX):
            playerStateDict.update({index:EffGetSet.GetValueByEffIndex(curPlayer, index)})
        #GameWorld.DebugLog("刷属性前=%s" % playerStateDict, playerID)
        #self.PrintAttr(curPlayer, "ˢ֮ǰ")
        #---------------------------开始计算-------------------------------------
        curPlayer.BeginRefreshState()
        # 恢复功能数值  不能调用函数self.InitPlayerState()
        EffGetSet.RestorePlayerFuncAttr(curPlayer)
        # 6.计算buff属性, buff层级的不算如战斗力
        self.__RefreshBuffAttr()
        # 7.刷完属性后需要处理的逻辑
        self.__DoRefreshAttrAfterLogic(beforeMaxHP, beforeMoveSpeedValue, playerStateDict)
        curPlayer.SetDict(ChConfig.Def_Player_RefreshAttrByBuff, 0)
        GameWorld.DebugLog("End RefreshPlayerAttrByBuffEx!!!", playerID)
        return
    
    #===========================================================================
    # #装备和BUFF 效果的计算移到外层
@@ -4769,15 +3684,6 @@
        if isForce:
            self.RefreshPlayerAttrStateEx()
            
        return
    def PrintAttr(self, curPlayer, mark):
        attrInfo = ""
        for index in xrange(1, ChConfig.Def_Calc_AllAttrType_MAX):
            value = EffGetSet.GetValueByEffIndex(curPlayer, index)
            if value:
                attrInfo = "%s,%s=%s" % (attrInfo, index, value)
        GameWorld.DebugLog("%s AttrInfo=%s" % (mark, attrInfo))
        return
    
    def RefreshPlayerAttrStateEx(self):
@@ -4811,812 +3717,33 @@
                        无buff总属性  = 固定总属性 + 内部百分比加成值 + 交叉百分比加成  + 固定总属性百分比加成   + 技能百分比对固定属性加成  + 技能固定值
                        含buff总属性  = 无buff总属性 * buff百分比加成  +  buff固定值
        '''
        curPlayer = self.__Player
        if curPlayer.GetDictByKey(ChConfig.Def_Player_RefreshAttr) != 1:
            return False
        PlayerGubao.CalcGubaoAttr(curPlayer) # 古宝定位为对贯通所有游戏功能系统的属性玩法,所以每次都重新刷新
        playerID = curPlayer.GetPlayerID()
        GameWorld.DebugLog("Start RefreshPlayerAttrStateEx!!!", playerID)
        #beforeAtkInterval = curPlayer.GetAtkInterval()
        beforeMaxHP = GameObj.GetMaxHP(curPlayer)
        beforeMoveSpeedValue = GetSpeedValue(curPlayer)
        beforeMaxProDef = GetMaxProDef(curPlayer)
        #[金木水火土]
        beforePointList = [GetMetal(curPlayer), GetWood(curPlayer), GetWater(curPlayer), GetFire(curPlayer), GetEarth(curPlayer)]
        #构建玩家刷新通知客户端字典, 缓存[索引, 数值]
        playerStateDict = {}
        for index in xrange(1, ChConfig.Def_Calc_AllAttrType_MAX):
            playerStateDict.update({index:EffGetSet.GetValueByEffIndex(curPlayer, index)})
        #GameWorld.DebugLog("刷属性前=%s" % playerStateDict, playerID)
        #self.PrintAttr(curPlayer, "ˢ֮ǰ")
        #---------------------------开始计算-------------------------------------
        curPlayer.BeginRefreshState()
        self.ResetFightPowerObj()
        #self.PrintAttr(curPlayer, "重置后")
        notAttrList = [{} for _ in range(4)]
        # 1.初始化人物各项状态及属性
        self.InitPlayerState()
        #self.PrintAttr(curPlayer, "初始化")
        # 功能属性层级一...
        # 2.计算基础属性
        #    2.1 获取所有功能计算点计算的属性值, 统计基础属性累加
        baseAttrDict = {}
        baseAttrNolineDict = {}
        funcAttrLen = len(ChConfig.CalcAttrFuncList)
        funcAttrInfoList = [[{} for _ in range(4)]] * funcAttrLen
        funcInsidePerAttrList = [{}] * funcAttrLen # 功能内部百分比附加属性
        for funcIndex in ChConfig.CalcAttrFuncList:
            # 基础属性等功能汇总完后统一刷新,因为各功能可能会加属性点数
            if funcIndex in [ChConfig.Def_CalcAttrFunc_RoleBase, ChConfig.Def_CalcAttrFunc_LingGenQuailty]:
                continue
            attrInfo, insidePerAttrDict = GetCalcAttrListValue(curPlayer, funcIndex)[:2]
            if attrInfo == notAttrList and not insidePerAttrDict:
                continue
            GameWorld.DebugLog("功能点属性: %s(%s), %s, 内层百分比附加: %s" % (funcIndex, ChConfig.FuncIndexName.get(funcIndex, ""), attrInfo, insidePerAttrDict), playerID)
            funcAttrInfoList[funcIndex] = attrInfo
            funcInsidePerAttrList[funcIndex] = insidePerAttrDict
            # 不同功能点间的数值累加,需使用支持衰减递增的计算方式
            AddAttrDictValue(baseAttrDict, attrInfo[ChConfig.CalcAttr_Base])
            AddAttrDictValue(baseAttrNolineDict, attrInfo[ChConfig.CalcAttr_BaseNoline])
        #    2.2 将基础属性累加到玩家身上
        if baseAttrDict or baseAttrNolineDict:
            # 因为基础属性会影响战斗属性计算,所以先统计增加基础属性
            GameWorld.DebugLog("功能附加点: baseAttrDict=%s,baseAttrNolineDict=%s" % (baseAttrDict, baseAttrNolineDict), playerID)
            CalcLineEffect.ChangePlayerAttrInLineEffectList(curPlayer, baseAttrDict)
            CalcNoLineEffect.ChangePlayerAttrInNoLineEffectList(curPlayer, baseAttrNolineDict)
        # 功能有加基础属性值,这里再重新刷新一下基础属性, 基础属性会影响战斗属性, 每次都刷新角色基础属性
        hasChange_Qualitylv = self.CalcRoleBaseAttr(curPlayer)
        roleBaseAttrInfo, roleInsidePerAttrDict = GetCalcAttrListValue(curPlayer, ChConfig.Def_CalcAttrFunc_RoleBase)[:2]
        lingGenQualityAttrList, lingGenQualityInsidePerAttrDict = GetCalcAttrListValue(curPlayer, ChConfig.Def_CalcAttrFunc_LingGenQuailty)[:2]
        funcAttrInfoList[ChConfig.Def_CalcAttrFunc_RoleBase] = roleBaseAttrInfo
        funcInsidePerAttrList[ChConfig.Def_CalcAttrFunc_RoleBase] = roleInsidePerAttrDict
        funcAttrInfoList[ChConfig.Def_CalcAttrFunc_LingGenQuailty] =  lingGenQualityAttrList
        funcInsidePerAttrList[ChConfig.Def_CalcAttrFunc_LingGenQuailty] =  lingGenQualityInsidePerAttrDict
        GameWorld.DebugLog("功能点属性: %s(%s), %s, 内层百分比附加: %s"
                           % (ChConfig.Def_CalcAttrFunc_RoleBase, ChConfig.FuncIndexName.get(ChConfig.Def_CalcAttrFunc_RoleBase, ""), roleBaseAttrInfo, roleInsidePerAttrDict), playerID)
        GameWorld.DebugLog("功能点属性: %s(%s), %s, 内层百分比附加: %s"
                           % (ChConfig.Def_CalcAttrFunc_LingGenQuailty, ChConfig.FuncIndexName.get(ChConfig.Def_CalcAttrFunc_LingGenQuailty, ""), lingGenQualityAttrList, lingGenQualityInsidePerAttrDict), playerID)
        #self.PrintAttr(curPlayer, "基础后", playerID)
        # 3.计算战斗属性
        #    3.1 战斗属性层级交叉影响基值数值汇总
        #        基础层级(角色基础属性)
        baseAttrList = AddAttrListValue([funcAttrInfoList[ChConfig.Def_CalcAttrFunc_RoleBase],
                                         funcAttrInfoList[ChConfig.Def_CalcAttrFunc_LingGen],
                                         funcAttrInfoList[ChConfig.Def_CalcAttrFunc_LingGenQuailty],
                                         ])
        #GameWorld.DebugLog("基础层级: %s" % baseAttrList, playerID)
        #        功能点交叉影响非线性层对应属性基值列表
        funcAttrPerInfo = {ChConfig.TYPE_Calc_BaseAtkAddPer:[baseAttrList],
                           ChConfig.TYPE_Calc_BaseMaxHPAddPer:[baseAttrList],
                           ChConfig.TYPE_Calc_BaseDefAddPer:[baseAttrList],
                           ChConfig.TYPE_Calc_BaseHitAddPer:[baseAttrList],
                           ChConfig.TYPE_Calc_BaseMissAddPer:[baseAttrList],
                           ChConfig.TYPE_Calc_FaQiMaxHPPer:[funcAttrInfoList[ChConfig.Def_CalcAttrFunc_FaQi]],
                           ChConfig.TYPE_Calc_FaQiAtkPer:[funcAttrInfoList[ChConfig.Def_CalcAttrFunc_FaQi]],
                           ChConfig.TYPE_Calc_FaQiDefPer:[funcAttrInfoList[ChConfig.Def_CalcAttrFunc_FaQi]],
                           ChConfig.TYPE_Calc_GodWeaponMaxHPPer:[funcAttrInfoList[ChConfig.Def_CalcAttrFunc_GodWeapon]],
                           ChConfig.TYPE_Calc_GodWeaponAtkPer:[funcAttrInfoList[ChConfig.Def_CalcAttrFunc_GodWeapon]],
                           ChConfig.TYPE_Calc_StoneMaxHPPer:[funcAttrInfoList[ChConfig.Def_CalcAttrFunc_Stone]],
                           ChConfig.TYPE_Calc_StoneAtkPer:[funcAttrInfoList[ChConfig.Def_CalcAttrFunc_Stone]],
                           ChConfig.TYPE_Calc_StoneBasePer:[funcAttrInfoList[ChConfig.Def_CalcAttrFunc_Stone]],
                           ChConfig.TYPE_Calc_RealmBasePer:[funcAttrInfoList[ChConfig.Def_CalcAttrFunc_Prestige]],
                           ChConfig.TYPE_Calc_HorseAtkPer:[funcAttrInfoList[ChConfig.Def_CalcAttrFunc_Horse]],
                           ChConfig.TYPE_Calc_HorseMaxHPPer:[funcAttrInfoList[ChConfig.Def_CalcAttrFunc_Horse]],
                           ChConfig.TYPE_Calc_HorseTrainAttrPer:[funcAttrInfoList[ChConfig.Def_CalcAttrFunc_HorseTarin]],
                           ChConfig.TYPE_Calc_PetTrainAttrPer:[funcAttrInfoList[ChConfig.Def_CalcAttrFunc_PetTarin]],
                           ChConfig.TYPE_Calc_GuardTrainAttrPer:[funcAttrInfoList[ChConfig.Def_CalcAttrFunc_GuardTarin]],
                           ChConfig.TYPE_Calc_WingTrainAttrPer:[funcAttrInfoList[ChConfig.Def_CalcAttrFunc_WingTarin]],
                           ChConfig.TYPE_Calc_PeerlessWeaponTrainAttrPer:[funcAttrInfoList[ChConfig.Def_CalcAttrFunc_PeerlessWeaponTrain]],
                           ChConfig.TYPE_Calc_PeerlessWeapon2TrainAttrPer:[funcAttrInfoList[ChConfig.Def_CalcAttrFunc_PeerlessWeapon2Train]],
                           ChConfig.TYPE_Calc_LianTiAttrPer:[funcAttrInfoList[ChConfig.Def_CalcAttrFunc_LianTi]],
                           ChConfig.TYPE_Calc_HorseSkinMaxHPPer:[funcAttrInfoList[ChConfig.Def_CalcAttrFunc_HorseSkin], funcAttrInfoList[ChConfig.Def_CalcAttrFunc_HorseStar]],
                           ChConfig.TYPE_Calc_HorseSkinAtkPer:[funcAttrInfoList[ChConfig.Def_CalcAttrFunc_HorseSkin], funcAttrInfoList[ChConfig.Def_CalcAttrFunc_HorseStar]],
                           ChConfig.TYPE_Calc_HorseSkinDefPer:[funcAttrInfoList[ChConfig.Def_CalcAttrFunc_HorseSkin], funcAttrInfoList[ChConfig.Def_CalcAttrFunc_HorseStar]],
                           ChConfig.TYPE_Calc_TitleMaxHPPer:[funcAttrInfoList[ChConfig.Def_CalcAttrFunc_Dienstgrad], funcAttrInfoList[ChConfig.Def_CalcAttrFunc_TitleStar]],
                           ChConfig.TYPE_Calc_TitleAtkPer:[funcAttrInfoList[ChConfig.Def_CalcAttrFunc_Dienstgrad], funcAttrInfoList[ChConfig.Def_CalcAttrFunc_TitleStar]],
                           ChConfig.TYPE_Calc_TitleDefPer:[funcAttrInfoList[ChConfig.Def_CalcAttrFunc_Dienstgrad], funcAttrInfoList[ChConfig.Def_CalcAttrFunc_TitleStar]],
                           ChConfig.TYPE_Calc_FaceMaxHPPer:[funcAttrInfoList[ChConfig.Def_CalcAttrFunc_Face]],
                           ChConfig.TYPE_Calc_FaceAtkPer:[funcAttrInfoList[ChConfig.Def_CalcAttrFunc_Face]],
                           ChConfig.TYPE_Calc_FaceDefPer:[funcAttrInfoList[ChConfig.Def_CalcAttrFunc_Face]],
                           ChConfig.TYPE_Calc_FacePicMaxHPPer:[funcAttrInfoList[ChConfig.Def_CalcAttrFunc_FacePic]],
                           ChConfig.TYPE_Calc_FacePicAtkPer:[funcAttrInfoList[ChConfig.Def_CalcAttrFunc_FacePic]],
                           ChConfig.TYPE_Calc_FacePicDefPer:[funcAttrInfoList[ChConfig.Def_CalcAttrFunc_FacePic]],
                           }
        #    3.2 统计各功能之间非线性属性交叉影响累加
        funcCrossAttrPerInfoDict = {} # 百分比交叉影响所提升的属性值 {功能属性编号:{提升的属性类型:数值, ...}, ...}
        for i, funcAttrList in enumerate(funcAttrInfoList):
            battleNoLineAttrDict = funcAttrList[ChConfig.CalcAttr_BattleNoline] # 暂写死只取战斗非线性的
            if not battleNoLineAttrDict:
                continue
            addAttrDict = {}
            #GameWorld.DebugLog("交叉功能点: i=%s,%s" % (i,battleNoLineAttrDict), playerID)
            for noLineAttrType, addAttrPer in battleNoLineAttrDict.items():
                if noLineAttrType not in funcAttrPerInfo or noLineAttrType not in ChConfig.FuncNoLinearAttrDict:
                    continue
                # 使用的基值目标功能索引
                attrRate = addAttrPer / float(ChConfig.Def_MaxRateValue)
                addAttrTypeList = ChConfig.FuncNoLinearAttrDict[noLineAttrType]
                useFuncAttrList = funcAttrPerInfo[noLineAttrType]
                for attrType in addAttrTypeList:
                    addValue = 0
                    for useAttrList in useFuncAttrList:
                        useAttrDict = useAttrList[ChConfig.CalcAttr_Battle] # 默认增加的是战斗线性
                        # 默认提升的属性在线性战斗属性里
                        if attrType not in useAttrDict:
                            continue
                        baseValue = useAttrDict[attrType] # 只是用到目标功能的基值
                        addValue += int(baseValue * attrRate)
                        #GameWorld.DebugLog("    i=%s,calcID=%s,per=%s,rate=%s,baseValue=%s,attrType=%s,addValue=%s" % (i, noLineAttrType, addAttrPer, attrRate, baseValue, attrType, addValue), playerID)
                    if addValue <= 0:
                        continue
                    addAttrDict[attrType] = addAttrDict.get(attrType, 0) + addValue
            if addAttrDict:
                # 增加的数值统计到百分比属性所属功能点
                # 如符文有个武器攻击百分比增加属性,增加的数值属于符文功能,不属于武器功能点的,只是基值使用了武器攻击
                funcCrossAttrPerInfoDict[i] = addAttrDict # 先都统计完后再累加到对应功能属性里,不然可能会导致功能基值变更
        GameWorld.DebugLog("交叉影响属性: %s" % funcCrossAttrPerInfoDict, playerID)
        #    3.3 统计所有功能固定属性影响累加
        allFixAttrDict = {} # 固定属性层级总属性基值
        for funcIndex, funcAttrList in enumerate(funcAttrInfoList):
            # 技能模块不计入功能固定属性、不计战力
            if funcIndex in ChConfig.CalcAttrFuncSkillList:
                continue
            AddAttrDictValue(allFixAttrDict, funcAttrList[ChConfig.CalcAttr_Battle])
        fixAttrPerAddExDict = {} # 固定总属性百分比影响所提升的属性值 {功能属性编号:{提升的属性类型:数值, ...}, ...}
        for funcIndex, funcAttrList in enumerate(funcAttrInfoList):
            fixAddPerDict = funcAttrList[ChConfig.CalcAttr_BattleNoline]
            if not fixAddPerDict:
                continue
            addValueExDict = {}
            for fixAttrType, addPer in fixAddPerDict.items():
                if fixAttrType not in allFixAttrDict:
                    continue
                curFixValue = allFixAttrDict[fixAttrType]
                addValueEx = int(curFixValue * addPer / 10000.0)
                addValueExDict[fixAttrType] = addValueEx
            fixAttrPerAddExDict[funcIndex] = addValueExDict
        GameWorld.DebugLog("固定属性总和: %s" % allFixAttrDict, playerID)
        GameWorld.DebugLog("固定百分比附加属性: %s" % fixAttrPerAddExDict, playerID)
        # 4. 计算属性及战力, 需在计算buff层之前计算
        curLV = curPlayer.GetLV()
        fpParam = IpyGameDataPY.GetIpyGameData("FightPowerParam", curLV)
        mfpDict = {} # 模块战斗力
        mfpObjDict = {}
        for mfpType, attrFuncIndexList in ChConfig.MFPTypeAttrFuncIndexDict.items():
            mfpAttrList = [{} for _ in range(4)]
            mfpAttrExDict = {}
            for funcIndex in attrFuncIndexList:
                if funcIndex in ChConfig.CalcAttrFuncSkillList:
                    # 技能模块不计入功能固定属性、不计战力
                    continue
                funcAttrList = funcAttrInfoList[funcIndex]
                funcInsidePerAttrDict = funcInsidePerAttrList[funcIndex] # 功能点内部百分比加成属性
                funcCrossPerAttrDict = funcCrossAttrPerInfoDict.get(funcIndex, {}) # 功能点交叉百分比加成属性
                fixPerAttrDict = fixAttrPerAddExDict.get(funcIndex, {}) # 功能总固定属性百分比加成属性
                CalcLineEffect.ChangePlayerAttrInLineEffectList(curPlayer, funcAttrList[ChConfig.CalcAttr_Battle])
                CalcLineEffect.ChangePlayerAttrInLineEffectList(curPlayer, funcInsidePerAttrDict)
                CalcLineEffect.ChangePlayerAttrInLineEffectList(curPlayer, funcCrossPerAttrDict)
                CalcLineEffect.ChangePlayerAttrInLineEffectList(curPlayer, fixPerAttrDict)
                # 不算战力的
                if funcIndex in ChConfig.CalcAttrFuncNoFightPowerList:
                    continue
                mfpAttrList = AddAttrListValue([mfpAttrList, funcAttrList])
                AddAttrDictValue(mfpAttrExDict, funcInsidePerAttrDict)
                AddAttrDictValue(mfpAttrExDict, funcCrossPerAttrDict)
                AddAttrDictValue(mfpAttrExDict, fixPerAttrDict)
            mfpObj = self.GetModuleFightPowerObj(mfpType)
            mfpObj.SetCalcMFPBattleAttr(mfpAttrList)
            for attrIndex, value in mfpAttrExDict.items():
                mfpObj.AddCalcMFPAttr(attrIndex, value)
            mfpObjDict[mfpType] = mfpObj
        # 因为计算战力需要取到总属性,所以等各功能点属性累加完后再计算
        for mfpType, mfpObj in mfpObjDict.items():
            mfpValue = 0 if not fpParam else mfpObj.GetModuleFightPower(fpParam, curPlayer)
            mfpSkill = GetMFPSkillFightPower(curPlayer, mfpObj.mfpType)
            mfpEx = GetMFPExFightPower(curPlayer, mfpType)
            mfpTotal = mfpValue + mfpSkill + mfpEx
            mfpDict[mfpObj.mfpType] = mfpTotal
            if mfpType == ShareDefine.Def_MFPType_Plus:
                OpenServerCampaign.UpdOpenServerCampaignRecordData(curPlayer, ShareDefine.Def_Campaign_Type_Plus, mfpTotal)
            elif mfpType == ShareDefine.Def_MFPType_Horse:
                OpenServerCampaign.UpdOpenServerCampaignRecordData(curPlayer, ShareDefine.Def_Campaign_Type_Horse, mfpTotal)
            elif mfpType == ShareDefine.Def_MFPType_Wash:
                OpenServerCampaign.UpdOpenServerCampaignRecordData(curPlayer, ShareDefine.Def_Campaign_Type_Wash, mfpTotal)
        #GameWorld.DebugLog("整体层级线性属性: %s" % allAttrList, playerID)
        # 5.被动技能附加属性,不算战力
        passiveSkillAttrList = [{} for _ in range(4)]
        SkillShell.CalcPassiveAttr_Effect(curPlayer, passiveSkillAttrList)  # 属性类技能与buff同层
        for funcIndex in ChConfig.CalcAttrFuncSkillList:
            passiveSkillAttrList = AddAttrListValue([passiveSkillAttrList, funcAttrInfoList[funcIndex]])
        GameWorld.DebugLog("无战力被动属性: %s" % passiveSkillAttrList, playerID)
        skillFixAttrExDict = {}
        skillFixAddPerDict = passiveSkillAttrList[ChConfig.CalcAttr_BattleNoline]
        for fixAttrType, addPer in skillFixAddPerDict.items():
            if fixAttrType not in allFixAttrDict:
                continue
            curFixValue = allFixAttrDict[fixAttrType]
            addValueEx = int(curFixValue * addPer / 10000.0)
            skillFixAttrExDict[fixAttrType] = addValueEx
        CalcLineEffect.ChangePlayerAttrInLineEffectList(curPlayer, passiveSkillAttrList[ChConfig.CalcAttr_Battle])
        CalcLineEffect.ChangePlayerAttrInLineEffectList(curPlayer, skillFixAttrExDict)
        #特殊指定属性公式
        GameMap.SpecialMapSetAttrValueByFormat(curPlayer)
        #护盾值刷新
        self.__RefreshMaxProDef(beforeMaxProDef)
        # 【到此所有功能属性都已刷新处理完毕,复制一份 功能属性的刷新结果,用于BUFF属性单独刷新】
        EffGetSet.CopyPlayerFuncAttr(curPlayer)
        # 6.计算buff属性, buff层级的不算如战斗力
        self.__RefreshBuffAttr()
        # 7.刷完属性后需要处理的逻辑
        self.__DoRefreshAttrAfterLogic(beforeMaxHP, beforeMoveSpeedValue, playerStateDict)
        #通知基础属性
        self.__SyncBaseAttr(curPlayer, baseAttrList)
        #五行灵根变更需要处理的逻辑
        afterPointList = [GetMetal(curPlayer), GetWood(curPlayer), GetWater(curPlayer), GetFire(curPlayer), GetEarth(curPlayer)]
        if beforePointList != afterPointList:
            diffPointAttrList = []
            for i, attrID in enumerate([ShareDefine.Def_Effect_Metal, ShareDefine.Def_Effect_Wood, ShareDefine.Def_Effect_Water,
                           ShareDefine.Def_Effect_Fire, ShareDefine.Def_Effect_Earth]):
                if beforePointList[i] != afterPointList[i]:
                    diffPointAttrList.append(attrID)
            SkillShell.RefreshElementSkillByAttr(curPlayer, diffPointAttrList)
#        if hasChange_Qualitylv:
#            #灵根品级变化处理
#            ChEquip.ChangeEquipfacadeByLingGen(curPlayer)
        # 更新开服活动灵根数据
        OpenServerCampaign.UpdOpenServerCampaignLingGenData(curPlayer)
        # 同步前端战力,因为有 SetFightPower 所以累加战力放在这里所有刷新及计算处理完后才处理,才能正常触发set同步前端
        self.SendModuleFightPowerPack(curPlayer, mfpDict)
        billFuncCnt = len(PyGameData.g_refreshAttrBillboardFunc) # 只处理固定次数,防止死循环
        while billFuncCnt > 0 and PyGameData.g_refreshAttrBillboardFunc:
            billFuncCnt -= 1
            billboardFunc = PyGameData.g_refreshAttrBillboardFunc.pop(0)
            GameWorld.DebugLog("回调排行榜: %s" % billboardFunc, playerID)
            billboardFunc(curPlayer, isForceUpdate=True)
        # 暂停刷新属性标志,必须被调用
        curPlayer.SetDict(ChConfig.Def_Player_RefreshAttr, 0)
        curPlayer.SetDict(ChConfig.Def_Player_RefreshAttrByBuff, 0)
        curPlayer.SetDict(ChConfig.Def_Player_HadRefreshAttr, 1)
        GameWorld.DebugLog("End RefreshPlayerAttrStateEx!!!", playerID)
        return True
    # 生命转化为防护值
    def __RefreshMaxProDef(self, beforeMaxProDef):
        curPlayer = self.__Player
        if GetProDefHPPer(curPlayer) == 0:
            return
        maxHP = GameObj.GetMaxHP(curPlayer)
        proDefPer = GetProDefHPPer(curPlayer)
        #获取策划配置的表格
        GodWeapon4 = IpyGameDataPY.GetFuncCfg("GodWeapon4", 2)
        maxProDef = eval(FormulaControl.GetCompileFormula("GodWeapon4", GodWeapon4))
        SetMaxProDef(curPlayer, int(maxProDef))
        afterMaxProDef = GetMaxProDef(curPlayer)
        addValue = max(0, afterMaxProDef - beforeMaxProDef)
        curProDef = GetProDef(curPlayer)
        if beforeMaxProDef > 0 and addValue > 0 and curPlayer.GetPlayerAction() != IPY_GameWorld.paDie:
            # 同步增加 (死亡状态下不刷)
            SetProDef(curPlayer, min(curProDef + addValue, afterMaxProDef))
        elif curProDef > afterMaxProDef:
            # 做一次防范纠正
            SetProDef(curPlayer, min(curProDef, afterMaxProDef))
        return
    def __RefreshBuffAttr(self):
        ## 刷新buff层属性,该层属性只会改变玩家最终属性,不会影响战力等
        curPlayer = self.__Player
        playerID = curPlayer.GetPlayerID()
        allAttrListBuffs = [{} for _ in range(4)]
        # 6.计算buff属性, buff层级的不算如战斗力
        #        算战斗力总值时该层影响的数值不统计,但刷属性时需计算
        SkillShell.CalcBuffers_Effect(curPlayer, allAttrListBuffs)
        # 渡劫副本护法属性加成
        GameLogic_DuJie.CalcDujieFBAttrAdd(curPlayer, allAttrListBuffs)
        #        层非线性战斗属性累加
        battleNolineAttrBuff = allAttrListBuffs[ChConfig.CalcAttr_BattleNoline]
        CalcNoLineEffect.AddPlayerMapAttrNolineEffect(curPlayer, battleNolineAttrBuff)
        CalcNoLineEffect.ChangePlayerAttrInNoLineEffectList(curPlayer, battleNolineAttrBuff, isBuffAttr=True)
        battleAttrBuff = allAttrListBuffs[ChConfig.CalcAttr_Battle]
        CalcLineEffect.ChangePlayerAttrInLineEffectList(curPlayer, battleAttrBuff, isBuffAttr=True)
        #        速度特殊处理 计算一次
        self.__RefreshMoveSpeed(allAttrListBuffs)
        # GM测试属性特殊逻辑
        self.__DoRefreshGMAttr()
        #        刷新攻击速度
        self.__SetAtkInterval()
        GameWorld.DebugLog("Buff层属性: %s" % allAttrListBuffs, playerID)
        return
    def __DoRefreshGMAttr(self):
        ## 刷新GM测试属性
        curPlayer = self.__Player
        platform = GameWorld.GetPlatform()
        if platform not in GMShell.TestPlatformList:
            return
        if curPlayer.GetGMLevel() != ChConfig.Def_GM_LV_God:
            return
        ipyDataMgr = IpyGameDataPY.IPY_Data()
        if not ipyDataMgr.GetGMAttrCount():
            return
        playerAccID = GameWorld.GetPlatformAccID(curPlayer.GetAccID())
        gmIpyData = None
        commIpyData = None
        for i in xrange(ipyDataMgr.GetGMAttrCount()):
            ipyData = ipyDataMgr.GetGMAttrByIndex(i)
            if not ipyData.GetIsValid():
                continue
            gmMaxLV = ipyData.GetGMMaxLV()
            if curPlayer.GetLV() > gmMaxLV:
                continue
            gmAccID = ipyData.GetGMAccID()
            if gmAccID == playerAccID:
                gmIpyData = ipyData
                break
            if not gmAccID and not commIpyData:
                commIpyData = ipyData
        if not gmIpyData:
            if not commIpyData:
                return
            gmIpyData = commIpyData
        setAttrDict = {}
        specAttrDict = gmIpyData.GetAttrSpecDict()
        attrLV = gmIpyData.GetAttrLV()
        attrPer = gmIpyData.GetAttrPer()
        if attrLV:
            if attrLV == 1:
                attrLV = curPlayer.GetLV()
            lvIpyData = GetPlayerLVIpyData(attrLV)
            if lvIpyData:
                setAttrDict[ChConfig.AttrName_MaxHP] = int(lvIpyData.GetReMaxHP() * attrPer) # 最大生命值
                setAttrDict[ChConfig.AttrName_Atk] = int(lvIpyData.GetReAtk() * attrPer) # 攻击(最小、最大攻击)
                setAttrDict[ChConfig.AttrName_Def] = int(lvIpyData.GetReDef() * attrPer) # 防御
                setAttrDict[ChConfig.AttrName_Hit] = int(lvIpyData.GetReHit() * attrPer) # 命中
                setAttrDict[ChConfig.AttrName_DefRate] = int(lvIpyData.GetReMiss() * attrPer) # 闪避
                setAttrDict[ChConfig.AttrName_AtkSpeed] = int((lvIpyData.GetReAtkSpeed() + 10000) * attrPer) # 攻击速度, 策划等级表配置的是附加值,所以这里要加
                setAttrDict[ChConfig.AttrName_SkillAtkRate] = int(max(0, lvIpyData.GetReSkillAtkRate() - 10000) * attrPer) # 技能伤害比例, 策划等级表配置的是最终值,初始值是0,所以这里要减
                setAttrDict[ChConfig.AttrName_DamagePVP] = int(lvIpyData.GetReDamagePer() * attrPer) # PVP固定伤害
                setAttrDict[ChConfig.AttrName_DamagePVPReduce] = int(lvIpyData.GetReDamReduce() * attrPer) # PVP固定减伤
                setAttrDict[ChConfig.AttrName_IgnoreDefRate] = int(lvIpyData.GetReIgnoreDefRate() * attrPer) # 无视防御比例
                setAttrDict[ChConfig.AttrName_LuckyHitRate] = int(lvIpyData.GetReLuckyHitRate() * attrPer) # 会心一击率
                setAttrDict[ChConfig.AttrName_LuckyHit] = int(lvIpyData.GetReLuckyHit() * attrPer) # 会心一击伤害
                setAttrDict[ChConfig.AttrName_BleedDamage] = int(lvIpyData.GetReBleedDamage() * attrPer) # 流血伤害增加
                setAttrDict[ChConfig.AttrName_IceAtk] = int(lvIpyData.GetReIceAtk() * attrPer) # 真实伤害
                setAttrDict[ChConfig.AttrName_IceDef] = int(lvIpyData.GetReIceDef() * attrPer) # 真实抵御
                setAttrDict[ChConfig.AttrName_PetAtk] = int(lvIpyData.GetRePetAtk() * attrPer) # 灵宠攻击
                setAttrDict[ChConfig.AttrName_PetSkillAtkRate] = int(max(0, lvIpyData.GetRePetSkillAtkRate() - 10000) * attrPer) # 灵宠技能, 策划等级表配置的是最终值,初始值是0,所以这里要减
                setAttrDict[ChConfig.AttrName_PetDamPer] = int(lvIpyData.GetRePetDamPer() * attrPer) # 灵宠伤害增加
                setAttrDict[ChConfig.AttrName_FinalHurt] = int(lvIpyData.GetReFinalHurt() * attrPer) # 固定伤害增加
                setAttrDict[ChConfig.AttrName_FinalHurtReduce] = int(lvIpyData.GetReFinalHurtReduce() * attrPer) # 固定伤害减少
        # 特殊属性的直接优先级最高,直接覆盖
        for attrType, attrValue in specAttrDict.items():
            setAttrDict[attrType] = attrValue
        gmAttrSetInfo = [{} for _ in range(4)]
        for attrType, attrValue in setAttrDict.items():
            if not attrValue:
                setAttrDict.pop(attrType)
                continue
            CalcAttrDict_Type(attrType, attrValue, gmAttrSetInfo)
        # 直接设置的属性
        if gmAttrSetInfo:
            for key, value in gmAttrSetInfo[ChConfig.CalcAttr_Battle].items():
                EffGetSet.SetValueByEffIndex(curPlayer, key, value)
        # 附加属性
        attrExDict = gmIpyData.GetAttrExDict()
        gmAttrExInfo = [{} for _ in range(4)]
        for attrType, attrValue in attrExDict.items():
            CalcAttrDict_Type(attrType, attrValue, gmAttrExInfo)
        CalcLineEffect.ChangePlayerAttrInLineEffectList(curPlayer, gmAttrExInfo[ChConfig.CalcAttr_Battle])
        GameWorld.DebugLog("GM测试设置属性: GMAttrID=%s,playerAccID=%s" % (gmIpyData.GetGMAttrID(), playerAccID))
        GameWorld.DebugLog("    GM等级属性: GMAttrLV=%s,attrPer=%s,setAttrDict=%s,specAttrDict=%s,%s"
                           % (attrLV, attrPer, setAttrDict, specAttrDict, gmAttrSetInfo))
        GameWorld.DebugLog("    GM附加属性: attrExDict=%s,%s" % (attrExDict, gmAttrExInfo))
        return
    def __DoRefreshAttrAfterLogic(self, beforeMaxHP, beforeMoveSpeedValue, playerStateDict):
        '''刷完总属性(功能属性 + buff属性) 后需要处理的逻辑
            包含一些数值纠正、属性变更通知等
            @attention: 此函数为刷 功能属性 及 buff属性 通用逻辑,所以不是受buff影响的相关处理请不要放这里,比如战斗力等
        '''
        curPlayer = self.__Player
        #------------------------------计算完毕--------------------------------
        afterMaxHP = GameObj.GetMaxHP(curPlayer)
        addMaxHP = max(0, afterMaxHP - beforeMaxHP)
        if beforeMaxHP > 0 and addMaxHP > 0 and curPlayer.GetPlayerAction() != IPY_GameWorld.paDie:
            # 最大血量增加时,同步增加等量的当前血量 (死亡状态下不刷当前血量)
            GameObj.SetHP(curPlayer, min(GameObj.GetHP(curPlayer) + addMaxHP, afterMaxHP))
        #self.PrintAttr(curPlayer, "最终的")
        curPlayer.EndRefreshState() # 统一在刷属性结束逻辑中调用
        #---------------------------------------------------------------------
        #把属性合并通知
        self.NotifyAllState(playerStateDict)
        #移动速度不同则通知给客户端, 功能层处理的是 SpeedNotBuff , 通知客户端的需要是最终的 SpeedValue
        if beforeMoveSpeedValue != GetSpeedValue(curPlayer):
            SetSpeedValue(curPlayer, GetSpeedValue(curPlayer))
        #纠正当前血魔量不超过最大值
        self.__RestoreHPMP()
        #通知客户端玩家当前经验倍率
        Sync_ExpRateChange(curPlayer)
        return
    def __SyncBaseAttr(self, curPlayer, baseAttrList):
        baseBattleAttrDict = baseAttrList[ChConfig.CalcAttr_Battle]
        attrTypeKeyDict = {ChConfig.TYPE_Calc_AttrATKMin:[ChConfig.Def_PlayerKey_BaseAtkMin, ShareDefine.CDBPlayerRefresh_BaseAtkMin],
                           ChConfig.TYPE_Calc_AttrATKMax:[ChConfig.Def_PlayerKey_BaseAtkMax, ShareDefine.CDBPlayerRefresh_BaseAtkMax],
                           ChConfig.TYPE_Calc_AttrMaxHP:[ChConfig.Def_PlayerKey_BaseMaxHP, ShareDefine.CDBPlayerRefresh_BaseMaxHP],
                           ChConfig.TYPE_Calc_AttrDEF:[ChConfig.Def_PlayerKey_BaseDef, ShareDefine.CDBPlayerRefresh_BaseDef],
                           ChConfig.TYPE_Calc_AttrHit:[ChConfig.Def_PlayerKey_BaseHit, ShareDefine.CDBPlayerRefresh_BaseHit],
                           ChConfig.TYPE_Calc_AttrMiss:[ChConfig.Def_PlayerKey_BaseMiss, ShareDefine.CDBPlayerRefresh_BaseMiss],
                           }
        notifySList = []
        for attrType, attrInfo in attrTypeKeyDict.items():
            attrKey, refreshType = attrInfo
            baseValue = baseBattleAttrDict.get(attrType, 0)
            curBaseValue = curPlayer.GetDictByKey(attrKey)
            if baseValue != curBaseValue:
                curPlayer.SetDict(attrKey, baseValue)
                notifyStruct = ChPyNetSendPack.tagRefreshType()
                notifyStruct.RefreshType = refreshType
                notifyStruct.Value = baseValue
                notifySList.append(notifyStruct)
        # 通知基础属性
        if notifySList:
            sendPack = ChPyNetSendPack.tagObjInfoListRefresh()
            sendPack.Clear()
            sendPack.ObjID = curPlayer.GetID()
            sendPack.ObjType = curPlayer.GetGameObjType()
            sendPack.Count = len(notifySList)
            sendPack.RefreshType = notifySList
            NetPackCommon.SendFakePack(curPlayer, sendPack)
        return
    #---------------------------------------------------------------------
    
    ## 刷新玩家技能战斗力
    #  @param self 类实例
    #  @return 返回值无意义
    #  @remarks 刷新玩家被动技能Buff
    def RefreshAllSkill(self):
        curPlayer = self.__Player
        skillManager = curPlayer.GetSkillManager()
        # 重置模块技能战斗力
        for mfpType in ShareDefine.ModuleFightPowerTypeList:
            SetMFPSkillFightPower(curPlayer, mfpType, 0)
        for i in range(0, skillManager.GetSkillCount()):
            curSkill = skillManager.GetSkillByIndex(i)
            mfpType = ChConfig.Def_SkillFuncType_MFPType.get(curSkill.GetFuncType(), ShareDefine.Def_MFPType_Role)
            skillMFP = GetMFPSkillFightPower(curPlayer, mfpType)
            SetMFPSkillFightPower(curPlayer, mfpType, skillMFP + curSkill.GetFightPower())
        return
    
    ## 技能升级刷属性战斗力处理
    def RefreshSkillFightPowerEx(self, skillID, beforeFightPower, isRefreshState=True):
        curPlayer = self.__Player
        # 新技能战力-旧技能战力为增加的技能战力
        curSkill = GameWorld.GetGameData().GetSkillBySkillID(skillID)
        if not curSkill:
            return
        mfpType = ChConfig.Def_SkillFuncType_MFPType.get(curSkill.GetFuncType(), ShareDefine.Def_MFPType_Role)
        addFightPower = curSkill.GetFightPower() - beforeFightPower
        skillMFP = GetMFPSkillFightPower(curPlayer, mfpType)
        SetMFPSkillFightPower(curPlayer, mfpType, max(0, skillMFP + addFightPower))
        GameWorld.DebugLog("刷新技能附加战斗力: skillID=%s,beforeFightPower=%s,mfpType=%s,skillMFP=%s,updMFP=%s"
                           % (skillID, beforeFightPower, mfpType, skillMFP, skillMFP + addFightPower), curPlayer.GetPlayerID())
        if isRefreshState:
            # 如果需要同步排行榜的话先强制刷属性
            self.RefreshPlayerAttrState()
        return
    
    def RefreshSkillFightPowerByDel(self, delSkillID, isRefreshState=True):
        curPlayer = self.__Player
        # 新技能战力-旧技能战力为增加的技能战力
        curSkill = GameWorld.GetGameData().GetSkillBySkillID(delSkillID)
        if not curSkill:
            return
        delFightPower = curSkill.GetFightPower()
        mfpType = ChConfig.Def_SkillFuncType_MFPType.get(curSkill.GetFuncType(), ShareDefine.Def_MFPType_Role)
        skillMFP = GetMFPSkillFightPower(curPlayer, mfpType)
        SetMFPSkillFightPower(curPlayer, mfpType, max(0, skillMFP - delFightPower))
        GameWorld.DebugLog("刷新技能附加战斗力: delSkillID=%s,mfpType=%s,skillMFP=%s,delFightPower=%s"
                           % (delSkillID, mfpType, skillMFP, delFightPower), curPlayer.GetPlayerID())
        if isRefreshState:
            # 如果需要同步排行榜的话先强制刷属性
            self.RefreshPlayerAttrState()
        return
    
    ## 计算被动buff属性加成
    #  @param self 类实例
    #  @return 
    def CalcPassiveBuffAttr(self):
        #=======================================================================
        # curPlayer = self.__Player
        # allAttrListPassive = [{} for i in range(4)]
        # SkillShell.CalcCurBuffer_Effect(curPlayer.GetPassiveBuf(), curPlayer, allAttrListPassive)
        # SetCalcAttrListValue(curPlayer, ChConfig.Def_CalcAttrFunc_PassiveBuf, allAttrListPassive)
        #=======================================================================
        return
    ## //A3 A1 各功能模块战斗力信息 #tagMCModuleFightPowerInfo
    #  @param curPlayer 玩家
    #  @return None
    def SendModuleFightPowerPack(self, curPlayer, mfpDict):
        mfpDataList = []
        totalFightPower = 0
        playerID = curPlayer.GetPlayerID()
        GameWorld.DebugLog("战力功能点: %s" % ChConfig.MFPTypeAttrFuncIndexDict, playerID)
        GameWorld.DebugLog("模块战力: %s" % mfpDict, playerID)
        for mfpType, fightPower in mfpDict.items():
            SetMFPFightPower(curPlayer, mfpType, fightPower)
            mfpData = ChPyNetSendPack.tagMCModuleFightPower()
            mfpData.Clear()
            mfpData.MfpType = mfpType
            mfpData.FightPower = fightPower % ChConfig.Def_PerPointValue # 当前模块战斗力数值
            mfpData.FightPowerEx = fightPower / ChConfig.Def_PerPointValue # 当前模块战斗力数值
            mfpDataList.append(mfpData)
            totalFightPower += fightPower # 累加总战斗力
        # //A3 A1 各功能模块战斗力信息 #tagMCModuleFightPowerInfo
        mfpInfo = ChPyNetSendPack.tagMCModuleFightPowerInfo()
        mfpInfo.Clear()
        mfpInfo.TotalFightPower = totalFightPower % ChConfig.Def_PerPointValue
        mfpInfo.TotalFightPoweEx = totalFightPower / ChConfig.Def_PerPointValue
        mfpInfo.MFPCnt = len(mfpDataList)
        mfpInfo.MFPList = mfpDataList
        NetPackCommon.SendFakePack(curPlayer, mfpInfo)
        beforeFightPower = GetFightPower(curPlayer)
        SetFightPower(curPlayer, totalFightPower)
        if totalFightPower < beforeFightPower:
            DataRecordPack.DR_FightPowerChangeInfo(curPlayer, beforeFightPower)
        highestFightPower = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FightPower_Highest, 0,
                                                           ChConfig.Def_PDictType_FightPower)
        highestFightPower += curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FightPower_HighestEx, 0,
                                                            ChConfig.Def_PDictType_FightPower) * ChConfig.Def_PerPointValue
        if totalFightPower > highestFightPower:
            highestFightPower = totalFightPower
            NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FightPower_Highest, highestFightPower % ChConfig.Def_PerPointValue,
                                 ChConfig.Def_PDictType_FightPower)
            NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FightPower_HighestEx, highestFightPower / ChConfig.Def_PerPointValue,
                                 ChConfig.Def_PDictType_FightPower)
        GameWorld.DebugLog("总战力: %s, 历史最高战力: %s, beforeFightPower=%s" % (totalFightPower, highestFightPower, beforeFightPower), playerID)
        PlayerBillboard.UpdatePlayerFPTotalBillboard(curPlayer)
        # 记录开服活动数据
        OpenServerCampaign.UpdOpenServerCampaignRecordData(curPlayer, ShareDefine.Def_Campaign_Type_FightPower, totalFightPower)
        if beforeFightPower != totalFightPower:
            CrossPlayerData.OnPlayerFightPowerChange(curPlayer)
        return
    def __RefreshMoveSpeed(self, allAttrListBuffs):
        ## 刷新移动速度
        curPlayer = self.__Player
        playerID = curPlayer.GetPlayerID()
        moveSpeedFormat = IpyGameDataPY.GetFuncCfg("MoveSpeed")
        if PlayerTruck.GetHaveAutoTruck(curPlayer):
            speed = IpyGameDataPY.GetFuncCfg("MoveSpeed", 3)
            GameWorld.DebugLog("运镖固定速度值: speed=%s" % speed, playerID)
        else:
            speed = GetSpeedNotBuff(curPlayer)
            GameWorld.DebugLog("功能移动速度值: speed=%s" % speed, playerID)
            # 骑乘状态加上骑乘附加速度
            if curPlayer.GetPlayerVehicle() == IPY_GameWorld.pvHorse:
                speedHorse = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_SpeedHorse)
                speed += speedHorse
                GameWorld.DebugLog("    骑乘状态附加值: %s, speed=%s" % (speedHorse, speed), playerID)
            buffBattleAttr = allAttrListBuffs[ChConfig.CalcAttr_Battle]
            buffBattleNolineAttr = allAttrListBuffs[ChConfig.CalcAttr_BattleNoline]
            #buff速度加成
            buffSpeed = buffBattleAttr.get(ChConfig.TYPE_Calc_AttrSpeed, 0)
            buffSpeedPer = buffBattleNolineAttr.get(ChConfig.TYPE_Calc_AttrSpeed, 0)
            if buffSpeed or buffSpeedPer:
                speed = int(speed * (ShareDefine.Def_MaxRateValue + buffSpeedPer) / float(ShareDefine.Def_MaxRateValue) + buffSpeed)
                GameWorld.DebugLog("    buff影响后速度值: speed=%s,buffSpeedPer=%s,buffSpeed=%s" % (speed, buffSpeedPer, buffSpeed), playerID)
            speed = max(speed, 0)   #防小于0错误
        if GetSpeedValue(curPlayer) != speed:
            SetSpeedValue(curPlayer, speed)
            moveSpeed = eval(FormulaControl.GetCompileFormula("MoveSpeed", moveSpeedFormat))
            curPlayer.SetSpeed(moveSpeed)
            GameWorld.DebugLog("公式计算后移动频率: moveSpeed=%s 毫秒/格" % moveSpeed, playerID)
            fightPet = curPlayer.GetPetMgr().GetFightPet()
            #无出战宠物
            if fightPet:
                fightPet.SetSpeed(moveSpeed)
        return
    ##刷新攻击间隔
    # @param self 类实例
    # @return None
    def __SetAtkInterval(self):
        curPlayer = self.__Player
        atkSpeed = GetAtkSpeed(curPlayer)
        formula = IpyGameDataPY.GetFuncCfg("AtkInterval")
        atkInterval = 0 if not formula else eval(FormulaControl.GetCompileFormula("AtkInterval", formula))
        curPlayer.SetAtkInterval(atkInterval)
        return
    
    ## 刷新玩家所有行为BUFF状态
    #  @param self 类实例
    #  @return 返回值无意义
    #  @remarks 刷新玩家所有行为BUFF状态
    def RefreshPlayerActionState(self):
        curPlayer = self.__Player
        playerID = curPlayer.GetPlayerID()
        GameWorld.DebugLog("Start RefreshPlayerActionState!!!", playerID)
        #curTime = time.clock()
        #先清除所有状态
        OperControlManager.ClearObjActionState(curPlayer)
        #再根据BUFF 加上状态
        SkillShell.CalcBuffer_ActionState(curPlayer)
    #---------------------------------------------------------------------
    ## 刷新血量和魔
    #  @param self 类实例
    #  @return 返回值无意义
    #  @remarks 刷新血量和魔
    def __RestoreHPMP(self):
        curPlayer = self.__Player
        if not curPlayer.GetInitOK():
            #玩家未初始化成功, 不修正血量和魔法值, 因此时有可能因为某些影响主角的物品未初始化完毕(如宠物装备)
            return
        curPlayerHP = GameObj.GetHP(curPlayer)
        curPlayerMaxHP = GameObj.GetMaxHP(curPlayer)
        #=======================================================================
        # curPlayerMP = curPlayer.GetMP()
        # curPlayerMaxMP = curPlayer.GetMaxMP()
        #=======================================================================
        if curPlayerHP > curPlayerMaxHP:
            GameObj.SetHPFull(curPlayer)
        #=======================================================================
        # if curPlayerMP > curPlayerMaxMP:
        #    curPlayer.SetMP(curPlayerMaxMP)
        #=======================================================================
        return
    #---------------------------------------------------------------------
    ## 初始化玩家基本状态 这里不对( 计算现有战斗属性中的元素进行处理 )
    #  @param self 类实例
    #  @return 返回值无意义
    #  @remarks 初始化玩家基本状态 这里不对( 计算现有战斗属性中的元素进行处理 )
    def InitPlayerState(self):
        curPlayer = self.__Player
        #清空战斗属性 //战斗属性设置数值为0的, 由C++处理 如元素属性,命中等
        curPlayer.ClearBattleEffect()
        initAttrDict = {
                        #ChConfig.TYPE_Calc_AttrCurSTR:curPlayer.GetBaseSTR(),
                        #ChConfig.TYPE_Calc_AttrCurPNE:curPlayer.GetBasePNE(),
                        #ChConfig.TYPE_Calc_AttrCurPHY:curPlayer.GetBasePHY(),
                        #ChConfig.TYPE_Calc_AttrCurCON:curPlayer.GetBaseCON(),
                        #ChConfig.TYPE_Calc_AttrSpeed:curPlayer.GetBaseSpeed(),
                        ChConfig.TYPE_Calc_AttrAtkSpeed:ChConfig.Def_BaseAtkSpeed,
                        ChConfig.TYPE_Calc_AttrFightExpRate:GameWorld.GetGameWorld().GetExpRate(),
                        ChConfig.TYPE_Calc_AttrGameExpRate:GameWorld.GetGameWorld().GetExpRate(),
                        ChConfig.TYPE_Calc_AttrPetExpRate:GameWorld.GetGameWorld().GetExpRate(),
                        ChConfig.TYPE_Calc_HitSucessRate:ChConfig.Def_MaxRateValue,
                        ChConfig.TYPE_Calc_CurePer:ChConfig.Def_MaxRateValue,
                        ChConfig.TYPE_Calc_YinjiTime:IpyGameDataPY.GetFuncCfg('Yinji', 1),  # 每X秒自动消失一个印记
                        }
        for i in xrange(1, ChConfig.Def_Calc_AllAttrType_MAX):
            if i in [ChConfig.TYPE_Calc_AttrHP, ChConfig.TYPE_Calc_AttrMP, ChConfig.TYPE_Calc_ProDef]:
                continue
            value = 0 if i not in initAttrDict else initAttrDict[i]
            EffGetSet.SetValueByEffIndex(curPlayer, i, value)
        #初始化拾取距离
        if curPlayer.GetPickupDist() != ChConfig.Def_RolePickupItemDist:
            curPlayer.SetPickupDist(ChConfig.Def_RolePickupItemDist)
        #玩家初始化可攻击
        if not curPlayer.GetCanAttack():
            curPlayer.SetCanAttack(True)
        #初始化灵根
        SetMetal(curPlayer, curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AddPointValue % ShareDefine.Def_Effect_Metal))
        SetWood(curPlayer, curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AddPointValue % ShareDefine.Def_Effect_Wood))
        SetWater(curPlayer, curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AddPointValue % ShareDefine.Def_Effect_Water))
        SetFire(curPlayer, curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AddPointValue % ShareDefine.Def_Effect_Fire))
        SetEarth(curPlayer, curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AddPointValue % ShareDefine.Def_Effect_Earth))
        return True
    #---------------------------------------------------------------------
    ## 初始化场景buff
    #  @param self 类实例
    #  @return 返回值无意义
    #  @remarks 初始化场景buff
    def InitMapBuffState(self):
        curPlayer = self.__Player
        #初始化区域, 默认为普通区域
        if GameMap.GetAreaTypeByMapPos(curPlayer.GetPosX(), curPlayer.GetPosY()) != IPY_GameWorld.gatNormal:
            curPlayer.SetAreaType(IPY_GameWorld.gatNormal)
        return
    
    #---------------------------------------------------------------------
@@ -5665,7 +3792,7 @@
            return
        
        #把人物设置回重生点
        PlayerResetWorldPos(curPlayer, rebornMapID, rebornPosX, rebornPosY, False)
        PlayerResetWorldPos(curPlayer, rebornMapID, rebornPosX, rebornPosY)
        return
    
    #---------------------------------------------------------------------
@@ -5692,8 +3819,6 @@
        #召唤回出战的宠物
        PetControl.ReCallFightPet(curPlayer)
        
        #拉镖玩家死亡处理
        PlayerTruck.DoPlayerDead(curPlayer)
        #清空使用技能记录
        curPlayer.ClearUseSkillRec()
        
@@ -5718,7 +3843,6 @@
        #通知死亡
        DoPlayerDead(curPlayer)
        
        #PlayerTJG.PlayerTJGReborn(curPlayer, tick)
        GameObj.ClearPyPlayerState(curPlayer)
        
        MirrorAttack.OnPlayerDead(curPlayer)
@@ -5967,12 +4091,7 @@
def IsMapOpen(curPlayer, openMapStep):
    # 主线任务完成时会设置标志可进地图标志
    mission_1 = QuestCommon.GetCommonMission(curPlayer)
    if not mission_1:
        return False
    if openMapStep > mission_1.GetProperty("OpenMap"):
        return False
    return True
    return False
#---------------------------------------------------------------------
##关于传送 验证玩家状态
@@ -6034,15 +4153,15 @@
    
    #玩家交易中, 离开交易
    if curPlayerAction == IPY_GameWorld.paTrade:
        PlayerTrade.LeaveTrade(curPlayer, 0)
        pass
    #玩家事件状态中, 退出事件
    elif curPlayerAction == IPY_GameWorld.paEvent:
        EventShell.DoExitEvent(curPlayer)
        pass
        
    elif curPlayerAction == IPY_GameWorld.paGameEvent:
        PlayerGameEvent.StopGameEvent(curPlayer, tick)
        pass
    if curPlayerAction == IPY_GameWorld.paPreparing:
        DoExitPreparing(curPlayer)
    
@@ -6054,10 +4173,6 @@
        #执行下马逻辑
        PlayerHorse.PlayerRideHorseDown(curPlayer, False)
        
    #玩家镖车中, 下车
    elif curPlayerVehicle == IPY_GameWorld.pvTruck:
        PlayerTruck.PlayerTruckDown(curPlayer, curPlayer.GetTruck())
    #---其他系统处理---
    
    #中断战斗对峙
@@ -6107,92 +4222,22 @@
#        return False
    
    return True
#------------------------------------------------------------------------------------
##初始化玩家背包.
# @param curPlayer 玩家实例
# @return 返回值无意义
# @remarks 初始化玩家背包
def Init_ItemPack(curPlayer):
    packType = IPY_GameWorld.rptItem
    #初始化玩家背包
    if packType not in ChConfig.Def_Type_CanBuyPack_PlayerDict.keys():
        return
    #获取玩家背包
    curPack = curPlayer.GetItemManager().GetPack(packType)
    #默认14格子 + 开启的
    keyName = ChConfig.Def_Type_CanBuyPack_PlayerDict.get(packType)[ChConfig.Def_PlayerPackDict_Index_Key]
    count = ItemCommon.GetPackInitCount(packType) + curPlayer.NomalDictGetProperty(keyName)
    curPack.SetCount(count)
    #通知客户端背包格子数目
#    curPlayer.Sync_ItemCount(curPack.GetCount())
    curPack.Sync_PackCanUseCount()
    return
#------------------------------------------------------------------------------------
##初始化玩家仓库.
# @param curPlayer 玩家实例
# @return 返回值无意义
# @remarks 初始化玩家仓库
def Init_Warehouse(curPlayer):
    packType = IPY_GameWorld.rptWarehouse
    #初始化玩家背包
    if packType not in ChConfig.Def_Type_CanBuyPack_PlayerDict.keys():
        return
    #获取玩家背包
def Init_PackCount(curPlayer, packType, defaultMax=False, isSync=True):
    ## 初始化刷新玩家某个背包格子数
    curPack = curPlayer.GetItemManager().GetPack(packType)
    #默认42格子 + 开启的
    keyName = ChConfig.Def_Type_CanBuyPack_PlayerDict.get(packType)[ChConfig.Def_PlayerPackDict_Index_Key]
    count = ItemCommon.GetPackInitCount(packType) + curPlayer.NomalDictGetProperty(keyName)
    curPack.SetCount(count)
    #通知客户端
    curPack.Sync_PackCanUseCount()
    return
##初始化寻宝背包
# @param curPlayer 玩家实例
# @return None
def Init_TreasurePack(curPlayer):
    curPack = curPlayer.GetItemManager().GetPack(ShareDefine.rptTreasure)
    curPack.SetCount(ItemCommon.GetPackInitCount(ShareDefine.rptTreasure))
    #通知客户端
    curPack.Sync_PackCanUseCount()
    maxCount = curPack.GetMaxCount()
    if defaultMax:
        curPack.SetCount(maxCount)
    else:
        count = ItemCommon.GetPackInitCount(packType) + ItemCommon.GetPackOpenItemCnt(curPlayer, packType)
        curPack.SetCount(min(count, maxCount))
    if isSync:
        curPack.Sync_PackCanUseCount()
    return
##初始化玩家收纳柜
# @param curPlayer 玩家实例
# @param packType 背包类型
# @return 返回值无意义
def Init_CabinetCountByType(curPlayer, packType):
    keyName = ChConfig.Def_Type_CanBuyPack_PlayerDict.get(packType)[ChConfig.Def_PlayerPackDict_Index_Key]
    if keyName == None:
        GameWorld.ErrLog("Init_Pack Error type=%s" % packType)
        return
    #初始化时装武器背包
    curPack = curPlayer.GetItemManager().GetPack(packType)
    #默认14格子 + 开启的
    count = ChConfig.Def_PackCnt_WeaponCoat + curPlayer.NomalDictGetProperty(keyName)
    curPack.SetCount(count)
    #通知客户端
    curPack.Sync_PackCanUseCount()
    return
#---------------------------------------------------------------------
def IsInOperationAction(curPlayer, actName, actIDKey, crossActName="", crossActIDKey=""):
    ## 玩家是否有正在进行中运营活动,不含参与结束阶段
    
@@ -6237,12 +4282,11 @@
def Sync_ExpRateChange(curPlayer):
    totalExpRate = GetPlayerExpRate(curPlayer)
    fightExpRate = curPlayer.GetFightExpRate() # 系统及功能累加
    fightExpRate += PlayerWorldAverageLv.GetWorldAverageLvExpRate(curPlayer) # 世界等级
    fightExpRate += PlayerVip.GetPrivilegeValue(curPlayer, ChConfig.VIPPrivilege_FightExpRate) # VIP加成
    fightExpRate += PlayerGoldInvest.GetAddFightExpRate(curPlayer)
    
    actExpRateInfo = PyGameData.g_operationActionDict.get(ShareDefine.OperationActionName_ExpRate, {})# 多倍经验活动加成
    if not PlayerTJG.GetIsTJG(curPlayer) and actExpRateInfo.get(ShareDefine.ActKey_State):
    if actExpRateInfo.get(ShareDefine.ActKey_State):
        actExpIpyData = IpyGameDataPY.GetIpyGameData("ActExpRate", actExpRateInfo.get(ShareDefine.ActKey_CfgID))
        if actExpIpyData and curPlayer.GetLV() >= actExpIpyData.GetLVLimit():
            fightExpRate += actExpIpyData.GetAddExpRate()
@@ -6294,17 +4338,6 @@
                totalExpRate -= effExpRate
                
    return totalExpRate
##记录玩家失去金钱的流向记录,消息中会记录玩家拥有的金钱信息
# @param curPlayer 玩家实例
# @param moneyType 金钱类型
# @param logIndex 流向记录索引
# @param tagID 在此用于记录特别标识(物品ID)
# @param par 在此用于记录金额
# @param msg 记录特别的信息
# @return None
def DataServerMoneyLog(curPlayer, moneyType, logIndex, tagID=0, par=0, msg=""):
    return
#===============================================================================
#---玩家扩展字段---
@@ -6399,18 +4432,58 @@
        SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_ForbidenTalk, 0)
    return
def IsMainLevelPass(curPlayer, lvID):
    ## 判断玩家是否过关某个主线关卡ID
    # @param lvID: 关卡唯一ID,与策划约定好 = 章节*100+关卡编号
    passChapterID, passLevelNum, _ = GetMainLevelPassInfo(curPlayer)
    passValue = passChapterID * 100 + passLevelNum # 因为pass的记录是带波数的,即当前关卡boss还没过关,所以只有大于该记录值的才算过关
    return passValue > lvID
## 主线关卡过关进度值 = 章节*10000+关卡编号*100+第x波
def GetMainLevelPassValue(curPlayer): return curPlayer.GetExAttr1()
def SetMainLevelPassValue(curPlayer, value): curPlayer.SetExAttr1(value, False, False) # 不通知GameServer
def SetMainLevelPassInfo(curPlayer, chapterID, levelNum, wave=0):
    ## 设置主线关卡过关进度
    # @param chapterID: 章节ID
    # @param levelNum: 关卡编号
    # @param wave: 第x波
    value = ComMainLevelValue(chapterID, levelNum, wave)
    SetMainLevelPassValue(curPlayer, value)
    return value
def GetMainLevelPassInfo(curPlayer):
    ## 获取主线关卡过关进度信息
    # @return: chapterID, levelNum, wave
    return GetMainLevelValue(GetMainLevelPassValue(curPlayer))
## 主线关卡当前进度值 = 章节*10000+关卡编号*100+第x波
def GetMainLevelNowValue(curPlayer): return curPlayer.GetExAttr2()
def SetMainLevelNowValue(curPlayer, value): curPlayer.SetExAttr2(value, False, False) # 不通知GameServer
def SetMainLevelNowInfo(curPlayer, chapterID=1, levelNum=1, wave=1):
    ## 设置主线关卡当前进度
    # @param chapterID: 章节ID
    # @param levelNum: 关卡编号
    # @param wave: 第x波
    value = ComMainLevelValue(chapterID, levelNum, wave)
    SetMainLevelNowValue(curPlayer, value)
    return value
def GetMainLevelNowInfo(curPlayer):
    ## 获取主线关卡当前进度信息
    # @return: chapterID, levelNum, wave
    return GetMainLevelValue(GetMainLevelNowValue(curPlayer))
def ComMainLevelValue(chapterID, levelNum, wave=0): return chapterID * 10000 + levelNum * 100 + wave
def GetMainLevelValue(value):
    chapterID = value / 10000
    levelNum = value % 10000 / 100
    wave = value % 100
    return chapterID, levelNum, wave
## 协助目标玩家ID
def SetAssistTagPlayerID(curPlayer, value):
    curPlayer.SetExAttr1(value, True, False) # 不通知GameServer
    NPCHurtManager.OnSetAssistTagPlayerID(curPlayer, value)
    return
def GetAssistTagPlayerID(curPlayer): return curPlayer.GetExAttr1()
def GetAssistTagPlayerID(curPlayer): return 0
## 队伍相关审核开关状态, joinReqCheck-入队申请是否需要审核; inviteCheck-组队邀请是否需要审核;
def SetTeamCheckStateEx(curPlayer, joinReqCheck, inviteCheck): return SetTeamCheckState(curPlayer, joinReqCheck * 10 + inviteCheck)
def SetTeamCheckState(curPlayer, checkState): return curPlayer.SetExAttr2(checkState, False, True)
def GetTeamCheckState(curPlayer): return curPlayer.GetExAttr2()
def SetTeamCheckState(curPlayer, checkState): return
## 副本功能线路ID, 这里做db存储,防止在合并地图副本中掉线重上时前端无法加载正确的场景资源,登录加载场景时机为0102包
def SetFBFuncLineID(curPlayer, mapID, funcLineID):
    value = mapID * 1000 + funcLineID
@@ -6454,8 +4527,8 @@
def SetVIPExpireTime(curPlayer, expireTime): return
##最近一次提升VIP等级时间
def GetVIPLVUpTime(curPlayer): return curPlayer.GetExAttr9()
def SetVIPLVUpTime(curPlayer, lvUpTime): return curPlayer.SetExAttr9(lvUpTime, False, True)
def GetVIPLVUpTime(curPlayer): return 0
def SetVIPLVUpTime(curPlayer, lvUpTime): return
##聊天气泡框
def GetChatBubbleBox(curPlayer): return curPlayer.GetExAttr10()
@@ -6516,120 +4589,61 @@
        GameWorld.DebugLog("更新玩家所属服务器组ID: serverGroupID=%s" % serverGroupID)
    return
##影响外观的3部位索引记录 123456789  123:武器格子索引 456:副手  789:衣服
def GetFaceEquipIndexList(curPlayer):
    attr15 = curPlayer.GetExAttr15()
    return [attr15%1000, attr15/1000%1000, attr15/1000000]
def SetFaceEquipIndex(curPlayer, value): return curPlayer.SetExAttr15(value)
def SetLingGenMaxIndex(curPlayer):
    return
# 境界难度等级
def GetRealmDifficulty(curPlayer): return curPlayer.GetExAttr18()
def GetRealmDifficulty(curPlayer): return 0
def SetRealmDifficulty(curPlayer, realmDifficulty):
    ''' 设置境界难度等级,任何地图均可选择
    '''
    playerID = curPlayer.GetPlayerID()
    if realmDifficulty:
        needRealmLV = GetDifficultyRealmLV(realmDifficulty)
        curRealmLV = curPlayer.GetOfficialRank()
        if curRealmLV < needRealmLV:
            GameWorld.DebugLog("当前境界低于境界难度,无法选择! curRealmLV(%s) < %s" % (curRealmLV, needRealmLV), playerID)
            return
        difficultyRealmList = IpyGameDataPY.GetFuncEvalCfg("RealmDifficulty", 2)
        if needRealmLV not in difficultyRealmList:
            GameWorld.ErrLog("realmDifficulty(%s) needRealmLV(%s) not in difficultyRealmList(%s)"
                             % (realmDifficulty, needRealmLV, difficultyRealmList), playerID)
            return
    GameWorld.DebugLog("SetRealmDifficulty: realmDifficulty=%s" % realmDifficulty, playerID)
    realmMapIDList = IpyGameDataPY.GetFuncEvalCfg("RealmDifficulty", 1)
    mapID = curPlayer.GetMapID()
    if mapID in realmMapIDList:
        # 先移除之前选的难度
        for playerIDList in PyGameData.g_realmDiffPlayerDict.values():
            if playerID in playerIDList:
                playerIDList.remove(playerID)
        # 加入新难度,0难度不处理
        if realmDifficulty:
            if realmDifficulty not in PyGameData.g_realmDiffPlayerDict:
                PyGameData.g_realmDiffPlayerDict[realmDifficulty] = []
            playerIDList = PyGameData.g_realmDiffPlayerDict[realmDifficulty]
            if playerID not in playerIDList:
                playerIDList.append(playerID)
        SetPlayerSightLevel(curPlayer, realmDifficulty)
    if curPlayer.GetExAttr18() != realmDifficulty:
        curPlayer.SetExAttr18(realmDifficulty)
        SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_ExAttr18, realmDifficulty)
    return
def GetDifficultyRealmLV(realmDifficulty): return realmDifficulty % 1000
def GetDifficultyRealmLV(realmDifficulty): return 0
def GetMapRealmDifficulty(curPlayer):
    ## 获取玩家在本地图中的境界难度层级,必须在境界地图且有选择境界难度才算,否则为默认0;该难度值同时也是视野层级
    realmDifficulty = GetRealmDifficulty(curPlayer)
    if not realmDifficulty:
        return 0
    mapID = curPlayer.GetMapID()
    realmMapIDList = IpyGameDataPY.GetFuncEvalCfg("RealmDifficulty", 1)
    if mapID not in realmMapIDList:
        return 0
    return realmDifficulty
    return 0
##玩家离开仙盟时间(主动或被踢都算)
def GetLeaveFamilyTimeEx(curPlayer):return curPlayer.GetExAttr19()
def SetLeaveFamilyTimeEx(curPlayer, value):
    curPlayer.SetExAttr19(value)
    curPlayer.SendGameServerRefreshState(ShareDefine.CDBPlayerRefresh_ExAttr19, value, 0)
    #curPlayer.SendGameServerRefreshState(ShareDefine.CDBPlayerRefresh_ExAttr19, value, 0)
    curPlayer.SendPropertyRefresh(ShareDefine.CDBPlayerRefresh_ExAttr19, value, 0, False)
    return
##获得玩家威望值
def GetPrestige(curPlayer): return 0
def SetPrestige(curPlayer, value): return
##总战斗力,支持超过20E = 各模块战力总和
def GetFightPower(curPlayer): return curPlayer.GetFightPowerEx() * ChConfig.Def_PerPointValue + curPlayer.GetFightPower()
def SetFightPower(curPlayer, value):
    beforeFightPower = GetFightPower(curPlayer)
    curPlayer.SetFightPower(value % ChConfig.Def_PerPointValue, value / ChConfig.Def_PerPointValue, False) # 不通知GameServer bNotifyGameServer False
    if value < beforeFightPower:
        DataRecordPack.DR_FightPowerChangeInfo(curPlayer, beforeFightPower)
    highestFightPower = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FightPower_Highest)
    highestFightPower += curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FightPower_HighestEx) * ChConfig.Def_PerPointValue
    if value > highestFightPower:
        highestFightPower = value
        NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FightPower_Highest, highestFightPower % ChConfig.Def_PerPointValue)
        NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FightPower_HighestEx, highestFightPower / ChConfig.Def_PerPointValue)
    GameWorld.DebugLog("总战力: %s, 历史最高战力: %s, beforeFightPower=%s" % (value, highestFightPower, beforeFightPower), curPlayer.GetPlayerID())
    PlayerBillboard.UpdatePlayerFPTotalBillboard(curPlayer)
    # 记录开服活动数据
    #OpenServerCampaign.UpdOpenServerCampaignRecordData(curPlayer, ShareDefine.Def_Campaign_Type_FightPower, totalFightPower)
    #if beforeFightPower != totalFightPower:
    #    CrossPlayerData.OnPlayerFightPowerChange(curPlayer)
    return
## 设置模块战斗力,支持超过20E = 模块公式战力 + 技能附加战力 + 其他附加战力
def SetMFPFightPower(curPlayer, mfpType, fightPower):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_MFPFightPower % mfpType, fightPower % ChConfig.Def_PerPointValue)
    curPlayer.SetDict(ChConfig.Def_PlayerKey_MFPFightPowerPoint % mfpType, fightPower / ChConfig.Def_PerPointValue)
    return
def SetMFPFightPower(curPlayer, mfpType, fightPower): return
## 获取模块战斗力
def GetMFPFightPower(curPlayer, mfpType):
    return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_MFPFightPowerPoint % mfpType) * ChConfig.Def_PerPointValue + \
        curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_MFPFightPower % mfpType)
def GetMFPFightPower(curPlayer, mfpType): return 0
## 设置模块附加战斗力,支持超过20E
def SetMFPExFightPower(curPlayer, mfpType, fightPower):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_MFPEx % mfpType, fightPower % ChConfig.Def_PerPointValue)
    curPlayer.SetDict(ChConfig.Def_PlayerKey_MFPExPoint % mfpType, fightPower / ChConfig.Def_PerPointValue)
    return
def SetMFPExFightPower(curPlayer, mfpType, fightPower): return
## 获取模块附加战斗力
def GetMFPExFightPower(curPlayer, mfpType):
    return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_MFPExPoint % mfpType) * ChConfig.Def_PerPointValue + \
        curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_MFPEx % mfpType)
def GetMFPExFightPower(curPlayer, mfpType): return 0
        
## 设置模块技能附加战斗力,支持超过20E
def SetMFPSkillFightPower(curPlayer, mfpType, fightPower):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_MFPSkill % mfpType, fightPower % ChConfig.Def_PerPointValue)
    curPlayer.SetDict(ChConfig.Def_PlayerKey_MFPSkillEx % mfpType, fightPower / ChConfig.Def_PerPointValue)
    return
def SetMFPSkillFightPower(curPlayer, mfpType, fightPower): return
## 获取模块技能附加战斗力
def GetMFPSkillFightPower(curPlayer, mfpType):
    return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_MFPSkillEx % mfpType) * ChConfig.Def_PerPointValue + \
        curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_MFPSkill % mfpType)
def GetMFPSkillFightPower(curPlayer, mfpType): return 0
        
#===============================================================================
##获取玩家分线信息
@@ -6645,12 +4659,6 @@
# @param sight 视野范围
# @return 无意义
def SetSight(curPlayer, sight):
    import QuestCommon
    firstMission = QuestCommon.GetCommonMission(curPlayer)
    if firstMission and firstMission.GetProperty(QuestCommon.Def_NewGuyNoSight) == 1:
        curPlayer.SetSight(0)
        return
    #外挂号 视野验证
    if curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_AutoCheckHack_State) \
                                      == ChConfig.Def_AutoCheck_State_Danger:
@@ -6674,19 +4682,6 @@
        atkInterval *= 100
    
    return atkInterval
def AddZhenQiByKillNPC(curPlayer, npcSP, killCount=1):
    ## 杀怪加真气
    if not npcSP:
        return
    addSPValue = npcSP * killCount
    npcSPRate = PlayerVip.GetPrivilegeValue(curPlayer, ChConfig.VIPPrivilege_NPCSPRate)
    if npcSPRate:
        npcHPRate = ChConfig.Def_MaxRateValue + npcSPRate
        addSPValue = int(addSPValue * npcHPRate / float(ChConfig.Def_MaxRateValue))
    PlayerAddZhenQi(curPlayer, addSPValue)
    return
##玩家增加真气
# @param curPlayer 玩家
@@ -6741,107 +4736,19 @@
    return True
## SP真气值 - 暂废弃 ExAttr7、ExAttr8 改为专精选择通知,用于前端表现其他玩家的不同专精特效
def GetZhenQi(curPlayer): return 0 #curPlayer.GetExAttr8() * ChConfig.Def_PerPointValue + curPlayer.GetExAttr7()
def SetZhenQi(curPlayer, totalZhenQi):
#    zhenQi = totalZhenQi % ChConfig.Def_PerPointValue
#    zhenQiPoint = min(totalZhenQi / ChConfig.Def_PerPointValue, ChConfig.Def_UpperLimit_DWord)
#    # 玩家单独通知,不广播; c++接口默认广播,故这里设置False
#    if zhenQi != curPlayer.GetExAttr7():
#        curPlayer.SetExAttr7(zhenQi)
#    if zhenQiPoint != curPlayer.GetExAttr8():
#        curPlayer.SetExAttr8(zhenQiPoint)
    return
def GetZhenQi(curPlayer): return 0
def SetZhenQi(curPlayer, totalZhenQi): return
#===============================================================================
# #@warning: ExAttr6~ExAttr10, 新增2个布尔默认参数, 是否通知客户端, 是否通知GameServer, 默认值为False
#===============================================================================
#---------------------------------------------------------------------------
##获取可免费开启的格子数
# @param curPlayer 玩家对象
# @param packType 背包类型
# @param openCnt 实际要开启的格子数
# @return 获取可免费开启的格子数
def GetCanAutoOpenPackCount(curPlayer, packType, openCnt, tick):
    if packType not in [IPY_GameWorld.rptItem, IPY_GameWorld.rptWarehouse]:
        return 0
    cfgObj = PlayerExpandPackCfgMgr.GetExpandPackCfg(curPlayer, packType)
    #找不到这种背包的配置信息对象
    if not cfgObj:
        return 0
    #已购买或自动开启的格子数
    keyName = ChConfig.Def_Type_CanBuyPack_PlayerDict[packType][ChConfig.Def_PlayerPackDict_Index_Key]
    curCount = curPlayer.NomalDictGetProperty(keyName)
#    nextCountIndex = curCount + 1
#    infoObj = cfgObj.GetAttrInfoByInex(nextCountIndex)
#    if None == infoObj:
#        return 0
#    #更新下玩家的在线时间
#    UpdateOnLineTime(curPlayer, tick)
#    onlineTime = curPlayer.GetOnlineTime()
#    #需要的时间
#    needOnlineTime = infoObj["OnlineTime"]
#    #最后一次自动开启背包的在线时间tick
#    lastAutoOpenPackTick = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_LastAutoOpenPackTick)
#    if onlineTime - lastAutoOpenPackTick > needOnlineTime:
#        return 1
#    return 0
    #最大可增加的背包数
    maxCanAddCount = cfgObj.GetCanAddCount()
    forCount = min(openCnt, maxCanAddCount - curCount)
    #可以再增加的格子数
    count = 0
    #遍历可增加的背包格子数
    UpdateOnLineTime(curPlayer, tick)
    onlineTime = curPlayer.GetOnlineTime()
    lastAutoOpenPackTick = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_LastAutoOpenPackTick % packType)
    lastInfoObj = cfgObj.GetTotalAddAttrInfoByCount(curCount)
    notOnlineTime = 0
    if lastInfoObj:
        notOnlineTime = lastInfoObj["OnlineTime"]
#    GameWorld.Log("get online time = %s"%onlineTime)
    for i in range(forCount):
        nextCount = curCount + i + 1
        infoObj = cfgObj.GetTotalAddAttrInfoByCount(nextCount)
        if None == infoObj:
            break
        # (小于0的不具有免费开启功能)
        if infoObj["OnlineTime"] < 0:
            continue
        needOnlineTime = infoObj["OnlineTime"] - notOnlineTime
#        GameWorld.Log("get need online time = %s"%needOnlineTime)
        #要求的在线时间,大于当前的在线时间,没办法加背包格子
        if needOnlineTime > onlineTime - lastAutoOpenPackTick:
            break
        count += 1
    return count
## 获取节假日经验加成
#  @param curPlayer: 玩家实例
#  @return: 节假日经验加成
def GetHolidayExpRate(curPlayer):
    return 0
## 获取世界boss经验加成
#  @param curPlayer: 玩家实例
#  @return: 世界boss经验加成
def GetWorldBossExpRate(curPlayer):
    return 0
## 获取玩家当前等级升级所需总经验
#  @param playerLv 玩家等级
#  @return 返回值, 升级需要的总经验
def GetLVUPTotalNeedExp(curPlayer):
    curLV = curPlayer.GetLV()
    #if curLV >= IpyGameDataPY.GetFuncCfg("PlayerMaxLV") and PlayerGreatMaster.IsGreatMasterOpen(curPlayer):
    #    return PlayerGreatMaster.GetTotalExpByGreatMasterLV(curPlayer.GetLV2())
    return GetTotalExpByPlayerLv(curLV)
## 根据等级获得升级需要的总经验
@@ -6863,7 +4770,7 @@
def GetLVUPTotalExpNeed(lvIpyData):
    if not lvIpyData:
        return 0
    return lvIpyData.GetExpPoint() * ChConfig.Def_PerPointValue + lvIpyData.GetExp()
    return lvIpyData.GetExp()
def GetPlayerMaxLV(curPlayer):
    ## 获取玩家实际可升的最大等级
@@ -6946,64 +4853,8 @@
#  @param allAttrList 属性列表
#  @return None
def CalcAttrDict_Type(attrType, value, allAttrList):
    if value == 0:
        return
    #[属性索引, 是否基础属性,(非)线性]
    attrInfo = ChConfig.ItemEffect_AttrDict.get(attrType, [])
    if attrInfo == []:
        return
    index = ChConfig.Def_CalcAttrIndexDict[(attrInfo[1], attrInfo[2])]
    attrDict = allAttrList[index]
    for i in attrInfo[0]:
        GameWorld.AddDictValue(attrDict, {i:value})
    return
def CalcAttrDict_TypeEx(attrType, value, allAttrDict):
    ## 统计玩家属性,累加
    if value == 0:
        return
    #[属性索引, 是否基础属性,(非)线性]
    attrInfo = ChConfig.ItemEffect_AttrDict.get(attrType, [])
    if attrInfo == []:
        return
    for i in attrInfo[0]:
        GameWorld.AddDictValue(allAttrDict, {i:value})
    return
#===============================================================================
# CalcAttr_Base,
# CalcAttr_BaseNoline,
# CalcAttr_Battle,
# CalcAttr_BattleNoline,
#===============================================================================
# 从srcAttrList计算出addAttrList带来的固定属性,用于后续计算使用
#===============================================================================
# def CalcAddFuncAttrByAttrList(srcAttrList, addAttrList):
#    for addKey, addValue in addAttrList[ChConfig.CalcAttr_BaseNoline].items():
#        value = srcAttrList[ChConfig.CalcAttr_Base].get(addKey, 0)
#        if value == 0:
#            continue
#
#        addAttrList[ChConfig.CalcAttr_Base][addKey]  = addAttrList[ChConfig.CalcAttr_Base].get(addKey, 0)\
#                                                         + value*addValue / ChConfig.Def_MaxRateValue
#
#    addAttrList[ChConfig.CalcAttr_BaseNoline] = {}
#    for addKey, addValue in addAttrList[ChConfig.CalcAttr_BattleNoline].items():
#        value = srcAttrList[ChConfig.CalcAttr_Battle].get(addKey, 0)
#        if value == 0:
#            continue
#
#        addAttrList[ChConfig.CalcAttr_Battle][addKey]  = addAttrList[ChConfig.CalcAttr_Battle].get(addKey, 0)\
#                                                         + value*addValue / ChConfig.Def_MaxRateValue
#
#    addAttrList[ChConfig.CalcAttr_BattleNoline] = {}
#    return addAttrList
#===============================================================================
## 培养境界等级
def GetTrainRealmLVReal(curPlayer, funcType):
    trainRealmLV = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TrainRealmLV % funcType)
@@ -7043,710 +4894,69 @@
def GetTotalLingGenPoint(curPlayer):
    # 总灵根点数(金木水火土+自由点数)
    attrIDList = [ShareDefine.Def_Effect_Metal, ShareDefine.Def_Effect_Wood, ShareDefine.Def_Effect_Water, ShareDefine.Def_Effect_Fire, ShareDefine.Def_Effect_Earth]
    curTotalPoint = 0
    for attrID in attrIDList:
        curTotalPoint += curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AddPointValue % attrID)
    curTotalPoint += curPlayer.GetFreePoint()
    return curTotalPoint
    return 0
# 灵根 - 金木水火土
def GetMetal(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_Metal)
def SetMetal(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_Metal, value)
def GetWood(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_Wood)
def SetWood(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_Wood, value)
def GetWater(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_Water)
def SetWater(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_Water, value)
def GetFire(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_Fire)
def SetFire(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_Fire, value)
def GetEarth(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_Earth)
def SetEarth(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_Earth, value)
# 灵根品级 - 金木水火土
def GetMetalQualityLV(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_MetalQualityLV)
def SetMetalQualityLV(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_MetalQualityLV, value)
def GetWoodQualityLV(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_WoodQualityLV)
def SetWoodQualityLV(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_WoodQualityLV, value)
def GetWaterQualityLV(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_WaterQualityLV)
def SetWaterQualityLV(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_WaterQualityLV, value)
def GetFireQualityLV(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_FireQualityLV)
def SetFireQualityLV(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_FireQualityLV, value)
def GetEarthQualityLV(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_EarthQualityLV)
def SetEarthQualityLV(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_EarthQualityLV, value)
def GetMetal(curPlayer): return 0
def GetWood(curPlayer): return 0
def GetWater(curPlayer): return 0
def GetFire(curPlayer): return 0
def GetEarth(curPlayer): return 0
#---玩家扩展接口, 战斗属性,不存数据库,只通知本人---
##玩家移动速度值, 不含buff对速度的影响; 功能等对速度的影响直接改变此值
def GetSpeedNotBuff(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_SpeedValueNotBuff)
def SetSpeedNotBuff(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_SpeedValueNotBuff, value)
##玩家移动速度值, 含buff对速度的影响; 此数值不是真正的移动速度,只是用于计算移动速度的参数值
def GetSpeedValue(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_SpeedValue)
def SetSpeedValue(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_SpeedValue, value)
    SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_SpeedValue, value, True) # 移动速度值暂定广播周围玩家
##获取玩家攻击速度,用于计算攻击间隔
# @param curPlayer 玩家实例
# @return 玩家攻击速度
def GetAtkSpeed(curPlayer):
    return curPlayer.GetBattleValEx1()
##设置玩家攻击速度,用于计算攻击间隔
# @param curPlayer 玩家实例
# @return None
def SetAtkSpeed(curPlayer, value):
    curPlayer.SetBattleValEx1(value, True)
#---攻击回复血量比率----
## 获取玩家攻击回复血量比率
#  @param curPlayer 玩家实例
#  @return
def GetAtkBackHPPer(curPlayer):
    return curPlayer.GetBattleValEx2()
## 设置玩家攻击回复血量比率
#  @param curPlayer 玩家实例
#  @return None
def SetAtkBackHPPer(curPlayer, value):
    curPlayer.SetBattleValEx2(value)
## 获取玩家攻击回复蓝量比率
def GetAtkBackMPPer(curPlayer): return 0
def SetAtkBackMPPer(curPlayer, value): return
## 玩家减技能CD比例
def GetReduceSkillCDPer(curPlayer): return curPlayer.GetBattleValEx3()
def SetReduceSkillCDPer(curPlayer, reducePer): return curPlayer.SetBattleValEx3(reducePer)
def GetReduceSkillCDPer(curPlayer): return 0
def SetReduceSkillCDPer(curPlayer, reducePer): return
## 常规地图经验倍率加成
def GetCommMapExpRate(curPlayer):
    if GameWorld.GetMap().GetMapFBType() == IPY_GameWorld.fbtNull:
        return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_CommMapExpRate)
    return 0
def SetCommMapExpRate(curPlayer, expRate): return curPlayer.SetDict(ChConfig.Def_PlayerKey_CommMapExpRate, expRate)
## 对怪物伤害加成
def GetNPCHurtAddPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_NPCHurtAddPer)
def SetNPCHurtAddPer(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_NPCHurtAddPer, value)
    SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_NPCHurtAddPer, value)
#---职业伤害加成---
## 目标战士伤害加成
def GetJobAHurtAddPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_JobAHurtAddPer)
def SetJobAHurtAddPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_JobAHurtAddPer, value)
## 目标法师伤害加成
def GetJobBHurtAddPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_JobBHurtAddPer)
def SetJobBHurtAddPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_JobBHurtAddPer, value)
## 目标弓手伤害加成
def GetJobCHurtAddPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_JobCHurtAddPer)
def SetJobCHurtAddPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_JobCHurtAddPer, value)
#---伤害减免---
## NPC攻击伤害减免
def GetNPCAtkReducePer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_NPCAtkReducePer)
def SetNPCAtkReducePer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_NPCAtkReducePer, value)
## 战士攻击伤害减免
def GetJobAAtkReducePer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_JobAAtkReducePer)
def SetJobAAtkReducePer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_JobAAtkReducePer, value)
## 法师攻击伤害减免
def GetJobBAtkReducePer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_JobBAtkReducePer)
def SetJobBAtkReducePer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_JobBAtkReducePer, value)
## 弓手攻击伤害减免
def GetJobCAtkReducePer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_JobCAtkReducePer)
def SetJobCAtkReducePer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_JobCAtkReducePer, value)
#---特殊伤害减免---
## 会心一击伤害减免固定值
def GetLuckyHitReduce(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_LuckyHitReduce)
def SetLuckyHitReduce(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_LuckyHitReduce, value)
    SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_LuckyHitReduce, value)
## 卓越一击伤害减免
def GetGreatHitReducePer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_GreatHitReducePer)
def SetGreatHitReducePer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_GreatHitReducePer, value)
## 暴击伤害减免
def GetSuperHitReduce(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_SuperHitReduce)
def SetSuperHitReduce(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_SuperHitReduce, value)
    SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_SuperHitReduce, value)
## 无视防御伤害减免
def GetIgnoreDefReducePer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_IgnoreDefReducePer)
def SetIgnoreDefReducePer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_IgnoreDefReducePer, value)
#---抗特殊伤害概率---
## 抗会心一击概率
def GetLuckyHitRateReduce(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_LuckyHitRateReduce)
def SetLuckyHitRateReduce(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_LuckyHitRateReduce, value)
    SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_LuckyHitRateReduce, value)
## 抗卓越一击概率
def GetGreatHitRateReduce(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_GreatHitRateReduce)
def SetGreatHitRateReduce(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_GreatHitRateReduce, value)
## 抗暴击概率
def GetSuperHitRateReduce(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_SuperHitRateReduce)
def SetSuperHitRateReduce(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_SuperHitRateReduce, value)
    SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_SuperHitRateReduce, value)
## 抗无视防御概率
def GetIgnoreDefRateReduce(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_IgnoreDefRateReduce)
def SetIgnoreDefRateReduce(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_IgnoreDefRateReduce, value)
    SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_IgnoreDefRateReduce, value)
#---特殊伤害概率---
## 富豪一击概率
def GetFuhaoHitRate(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_FuhaoHitRate)
def SetFuhaoHitRate(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_FuhaoHitRate, value)
## 流血伤害
def GetBleedDamage(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_BleedDamage)
def SetBleedDamage(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_BleedDamage, value)
    SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_BleedDamage, value)
## Boss最终伤害百分比
def GetBossFinalHurtPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_BossFinalHurtPer)
def SetBossFinalHurtPer(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_BossFinalHurtPer, value)
    SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_BossFinalHurtPer, value)
## 最终伤害百分比
def GetFinalHurtPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_FinalHurtPer)
def SetFinalHurtPer(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_FinalHurtPer, value)
    SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_FinalHurtPer, value)
## 最终伤害减免百分比
def GetFinalHurtReducePer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_FinalHurtReducePer)
def SetFinalHurtReducePer(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_FinalHurtReducePer, value)
    SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_FinalHurtReducePer, value)
## 最终固定伤害增加
def GetFinalHurt(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_FinalHurt)
def SetFinalHurt(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_FinalHurt, value)
    SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_FinalHurt, value)
## 最终固定伤害减少
def GetFinalHurtReduce(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_FinalHurtReduce)
def SetFinalHurtReduce(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_FinalHurtReduce, value)
    SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_FinalHurtReduce, value)
## 对指定boss伤害加成固定值
def GetBossIDHurt(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_BossIDHurt)
def SetBossIDHurt(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_BossIDHurt, value)
## 对指定boss伤害加成倍率
def GetBossIDHurtAddPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_BossIDHurtAddPer)
def SetBossIDHurtAddPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_BossIDHurtAddPer, value)
## 装备掉落执行次数加成万分率
def GetDropEquipDoCount(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_DropEquipDoCount)
def SetDropEquipDoCount(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_DropEquipDoCount, value)
# 基础攻击百分比
def GetBaseAtkAddPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_BaseAtkAddPer)
def SetBaseAtkAddPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_BaseAtkAddPer, value)
# 基础生命百分比
def GetBaseMaxHPAddPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_BaseMaxHPAddPer)
def SetBaseMaxHPAddPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_BaseMaxHPAddPer, value)
# 基础防御百分比
def GetBaseDefAddPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_BaseDefAddPer)
def SetBaseDefAddPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_BaseDefAddPer, value)
# 基础命中百分比
def GetBaseHitAddPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_BaseHitAddPer)
def SetBaseHitAddPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_BaseHitAddPer, value)
# 基础闪避百分比
def GetBaseMissAddPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_BaseMissAddPer)
def SetBaseMissAddPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_BaseMissAddPer, value)
# 法器生命百分比
def GetFaQiMaxHPPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_FaQiMaxHPPer)
def SetFaQiMaxHPPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_FaQiMaxHPPer, value)
# 法器攻击百分比
def GetFaQiAtkPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_FaQiAtkPer)
def SetFaQiAtkPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_FaQiAtkPer, value)
# 法器防御百分比
def GetFaQiDefPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_FaQiDefPer)
def SetFaQiDefPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_FaQiDefPer, value)
# 神兵生命百分比
def GetGodWeaponMaxHPPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_GodWeaponMaxHPPer)
def SetGodWeaponMaxHPPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_GodWeaponMaxHPPer, value)
# 神兵攻击百分比
def GetGodWeaponAtkPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_GodWeaponAtkPer)
def SetGodWeaponAtkPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_GodWeaponAtkPer, value)
# 宝石生命百分比
def GetStoneMaxHPPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_StoneMaxHPPer)
def SetStoneMaxHPPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_StoneMaxHPPer, value)
# 宝石攻击百分比
def GetStoneAtkPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_StoneAtkPer)
def SetStoneAtkPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_StoneAtkPer, value)
# 血瓶恢复效果
def GetHPCureEnhance(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_HPCureEnhance)
def SetHPCureEnhance(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_HPCureEnhance, value)
# 额外输出伤害
def GetOnlyFinalHurt(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_OnlyFinalHurt)
def SetOnlyFinalHurt(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_OnlyFinalHurt, value)
    SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_OnlyFinalHurt, value)
    return
# PVP攻击回血
def GetPVPAtkBackHP(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_PVPAtkBackHP)
def SetPVPAtkBackHP(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_PVPAtkBackHP, value)
# 命中成功率
def GetHitSucessRate(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_HitSucessRate)
def SetHitSucessRate(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_HitSucessRate, value)
# 闪避成功率
def GetMissSucessRate(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_MissSucessRate)
def SetMissSucessRate(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_MissSucessRate, value)
# 治疗加成 默认百分百
def GetCurePer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_CurePer)
def SetCurePer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_CurePer, value)
# 加深受到伤害百分比
def GetBeHurtPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_BeHurtPer)
def SetBeHurtPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_BeHurtPer, value)
# 称号生命加成
def GetTitleMaxHPPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_TitleMaxHPPer)
def SetTitleMaxHPPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_TitleMaxHPPer, value)
# 称号攻击加成
def GetTitleAtkPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_TitleAtkPer)
def SetTitleAtkPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_TitleAtkPer, value)
# 称号防御加成
def GetTitleDefPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_TitleDefPer)
def SetTitleDefPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_TitleDefPer, value)
# 头像生命加成
def GetFaceMaxHPPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_FaceMaxHPPer)
def SetFaceMaxHPPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_FaceMaxHPPer, value)
# 头像攻击加成
def GetFaceAtkPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_FaceAtkPer)
def SetFaceAtkPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_FaceAtkPer, value)
# 头像防御加成
def GetFaceDefPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_FaceDefPer)
def SetFaceDefPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_FaceDefPer, value)
# 头像框生命加成
def GetFacePicMaxHPPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_FacePicMaxHPPer)
def SetFacePicMaxHPPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_FacePicMaxHPPer, value)
# 头像框攻击加成
def GetFacePicAtkPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_FacePicAtkPer)
def SetFacePicAtkPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_FacePicAtkPer, value)
# 头像框防御加成
def GetFacePicDefPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_FacePicDefPer)
def SetFacePicDefPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_FacePicDefPer, value)
# 坐骑幻化生命加成
def GetHorseSkinMaxHPPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_HorseSkinMaxHPPer)
def SetHorseSkinMaxHPPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_HorseSkinMaxHPPer, value)
# 坐骑幻化攻击加成
def GetHorseSkinAtkPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_HorseSkinAtkPer)
def SetHorseSkinAtkPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_HorseSkinAtkPer, value)
# 坐骑幻化防御加成
def GetHorseSkinDefPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_HorseSkinDefPer)
def SetHorseSkinDefPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_HorseSkinDefPer, value)
# 坐骑攻击百分比
def GetHorseAtkPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_HorseAtkPer)
def SetHorseAtkPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_HorseAtkPer, value)
# 坐骑生命加成
def GetHorseMaxHPPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_HorseMaxHPPer)
def SetHorseMaxHPPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_HorseMaxHPPer, value)
# 灵宠攻击加成
def GetPetAtkPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_PetAtkPer)
def SetPetAtkPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_PetAtkPer, value)
# 坐骑培养属性加成
def GetHorseTrainAttrPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_HorseTrainAttrPer)
def SetHorseTrainAttrPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_HorseTrainAttrPer, value)
# 灵宠培养属性加成
def GetPetTrainAttrPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_PetTrainAttrPer)
def SetPetTrainAttrPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_PetTrainAttrPer, value)
# 守护培养属性加成
def GetGuardTrainAttrPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_GuardTrainAttrPer)
def SetGuardTrainAttrPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_GuardTrainAttrPer, value)
# 翅膀培养属性加成
def GetWingTrainAttrPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_WingTrainAttrPer)
def SetWingTrainAttrPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_WingTrainAttrPer, value)
# 灭世培养属性加成
def GetPeerlessWeaponTrainAttrPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_PeerlessWeaponTrainAttrPer)
def SetPeerlessWeaponTrainAttrPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_PeerlessWeaponTrainAttrPer, value)
# 弑神培养属性加成
def GetPeerlessWeapon2TrainAttrPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_PeerlessWeapon2TrainAttrPer)
def SetPeerlessWeapon2TrainAttrPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_PeerlessWeapon2TrainAttrPer, value)
# 炼体属性属性加成
def GetLianTiAttrPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_LianTiAttrPer)
def SetLianTiAttrPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_LianTiAttrPer, value)
def GetAttr160(curPlayer): return 0
def SetAttr160(curPlayer, value): pass
def GetHPCureEnhance(curPlayer): return 0
# 仙盟徽章ID
def GetFamilyEmblemID(curPlayer): return curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FamilyEmblemID)
def SetFamilyEmblemID(curPlayer, emblemID): NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_FamilyEmblemID, emblemID)
# 仙盟事务速度加成
def GetAffairSpeedPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_AffairSpeedPer)
def SetAffairSpeedPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_AffairSpeedPer, value)
# 仙盟BOSS伤害加成
def GetFamilyBossHurtPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_FamilyBossHurtPer)
def SetFamilyBossHurtPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_FamilyBossHurtPer, value)
# 仙盟联赛生命加成
def GetFamilyWarHPPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_FamilyWarHPPer)
def SetFamilyWarHPPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_FamilyWarHPPer, value)
# 仙盟联赛攻击加成
def GetFamilyWarAtkPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_FamilyWarAtkPer)
def SetFamilyWarAtkPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_FamilyWarAtkPer, value)
# 仙盟打坐经验加成
def GetFamilySitExpPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_FamilySitExpPer)
def SetFamilySitExpPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_FamilySitExpPer, value)
# 宝石基础属性百分比
def GetStoneBasePer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_StoneBasePer)
def SetStoneBasePer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_StoneBasePer, value)
# 境界基础属性百分比
def GetRealmBasePer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_RealmBasePer)
def SetRealmBasePer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_RealmBasePer, value)
# 翅膀生命百分比
def GetWingHPPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_WingHPPer)
def SetWingHPPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_WingHPPer, value)
# 套装基础属性百分比
def GetSuiteBasePer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_SuiteBasePer)
def SetSuiteBasePer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_SuiteBasePer, value)
# 强化基础攻击百分比
def GetPlusBaseAtkPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_PlusBaseAtkPer)
def SetPlusBaseAtkPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_PlusBaseAtkPer, value)
## 暂无用
#  @param curPlayer 玩家实例
#  @return
def GetAddBackHPPer(curPlayer):
    return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_AddBackHPPer)
## 暂无用
#  @param curPlayer 玩家实例
#  @return None
def SetAddBackHPPer(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_AddBackHPPer, value)
#---降低生命恢复效果----
## 获取降低生命恢复效果万分率
#  @param curPlayer 玩家实例
#  @return
def GetReduceBackHPPer(curPlayer):
    return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ReduceBackHPPer)
## 设置降低生命恢复效果万分率
#  @param curPlayer 玩家实例
#  @return None
def SetReduceBackHPPer(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_ReduceBackHPPer, value)
#---触发击晕----
def GetFaintRate(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_AttrFaintRate)
def SetFaintRate(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_AttrFaintRate, value)
    SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_FaintRate, value)
#---击晕抵抗----
def GetFaintDefRate(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_AttrFaintDefRate)
def SetFaintDefRate(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_AttrFaintDefRate, value)
    SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_FaintDefRate, value)
#---触发定身----
def GetAtkerFreezed(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_AttrAtkerFreezed)
def SetAtkerFreezed(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_AttrAtkerFreezed, value)
#---增加仇恨----
def GetAddAngry(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_AttrAddAngry)
def SetAddAngry(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_AttrAddAngry, value)
#---连击几率----
def GetComboRate(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_AttrComboRate)
def SetComboRate(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_AttrComboRate, value)
    SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_ComboRate, value)
#---连击伤害----
def GetComboDamPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_AttrComboDamPer)
def SetComboDamPer(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_AttrComboDamPer, value)
    SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_ComboDamPer, value)
#---技能攻击比例减少----
def GetSkillAtkRateReduce(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_SkillAtkRateReduce)
def SetSkillAtkRateReduce(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_SkillAtkRateReduce, value)
    SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_SkillAtkRateReduce, value)
#---PVP固定伤害----
def GetDamagePVP(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_AttrDamagePVP)
def SetDamagePVP(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_AttrDamagePVP, value)
    SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_DamagePVP, value)
#---PVP固定伤害减少----
def GetDamagePVPReduce(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_AttrDamagePVPReduce)
def SetDamagePVPReduce(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_AttrDamagePVPReduce, value)
    SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_DamagePVPReduce, value)
#---伤害输出固定值计算对NPC附加----
def GetDamagePVE(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_AttrDamagePVE)
def SetDamagePVE(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_AttrDamagePVE, value)
    SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_DamagePVE, value)
#---伤害输出计算百分比对玩家附加----
def GetDamagePerPVP(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_AttrDamagePerPVP)
def SetDamagePerPVP(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_AttrDamagePerPVP, value)
    SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_DamagePerPVP, value)
def GetDamagePerPVPReduce(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_AttrDamagePerPVPReduce)
def SetDamagePerPVPReduce(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_AttrDamagePerPVPReduce, value)
    SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_DamagePerPVPReduce, value)
#---受伤计算百分比----
def GetHurtPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_AttrHurtPer)
def SetHurtPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_AttrHurtPer, value)
#---自动恢复XP值比率----
def GetXPRestorePer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_AttrXPRestorePer)
def SetXPRestorePer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_AttrXPRestorePer, value)
#---魔法盾伤害吸收蓝耗比率----
def GetShieldMPCostRate(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_AttrShieldMPCostRate)
def SetShieldMPCostRate(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_AttrShieldMPCostRate, value)
#---20%的概率抵御伤害比率----
def GetDamChanceDef(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_AttrDamChanceDef)
def SetDamChanceDef(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_AttrDamChanceDef, value)
    SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_DamChanceDef, value)
#---当前防护值,需存DB----
def GetProDef(curPlayer): return curPlayer.GetExAttr4()
def SetProDef(curPlayer, value):
    curPlayer.SetExAttr4(value, True)
# 仙盟职位,使用 GetReceivedSalary,因为FamilyMemberLV没有入库
def GetFamilyMemberLV(curPlayer): return curPlayer.GetReceivedSalary()
def SetFamilyMemberLV(curPlayer, fmLV):
    #因为仙盟职位没有存DBPlayer,而跨服后又没有Family信息,所以这里做个存储,用于跨服用
    curPlayer.SetReceivedSalary(fmLV)
    curPlayer.SetFamilyMemberLV(fmLV) # 也同步设置该值,防止有些地方直接调用 curPlayer.GetFamilyMemberLV()
    return
#---当前防护值,需存DB----
def GetProDef(curPlayer): return 0
def SetProDef(curPlayer, value): return
#---最大防护值----
def GetMaxProDef(curPlayer): return curPlayer.GetExAttr16()
def SetMaxProDef(curPlayer, value):
    value = min(value, ChConfig.Def_UpperLimit_DWord)
    curPlayer.SetExAttr16(value)
    curPlayer.SendPropertyRefresh(ShareDefine.CDBPlayerRefresh_MaxProDef, value, 0, True) # 周围玩家需要通知
    return
#---生命上限换算为防护值的百分比----
def GetProDefHPPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_AttrProDefHPPer)
def SetProDefHPPer(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_AttrProDefHPPer, value)
    #SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_ProDefHPPer, value)
#---防护值吸收伤害比率----
def GetProDefAbsorb(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_AttrProDefAbsorb)
def SetProDefAbsorb(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_AttrProDefAbsorb, value)
    #SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_ProDefAbsorb, value)
#---宠物攻击提升值----
def GetPetMinAtk(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_AttrPetMinAtk)
def SetPetMinAtk(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_AttrPetMinAtk, value)
def GetPetMaxAtk(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_AttrPetMaxAtk)
def SetPetMaxAtk(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_AttrPetMaxAtk, value)
#---宠物伤害百分比提升----移到GameObj下
#===============================================================================
# def GetPetDamPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_AttrPetDamPer)
# def SetPetDamPer(curPlayer, value):
#    curPlayer.SetDict(ChConfig.Def_PlayerKey_AttrPetDamPer, value)
#    SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_PetDamPer, value)
#===============================================================================
#---宠物技能伤害百分比提升----
def GetPetSkillAtkRate(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_PetSkillAtkRate)
def SetPetSkillAtkRate(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_PetSkillAtkRate, value)
#---每1级+%s攻击, 数值取万分率,支持小数算法----
def GetPerLVAtk(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_AttrPerLVAtk)
def SetPerLVAtk(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_AttrPerLVAtk, value)
#---每1级+%s生命, 数值为固定值----
def GetPerLVMaxHP(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_AttrPerLVMaxHP)
def SetPerLVMaxHP(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_AttrPerLVMaxHP, value)
#---装备掉率----
def GetDropEquipPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_AttrDropEquipPer)
def SetDropEquipPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_AttrDropEquipPer, value)
#---功能层防御值----
def GetFuncDef(curPlayer): return EffGetSet.GetCopyFuncAttrValue(curPlayer, ChConfig.TYPE_Calc_AttrDEF)
def SetFuncDef(curPlayer, value): EffGetSet.SetCopyFuncAttrValue(curPlayer, ChConfig.TYPE_Calc_AttrDEF, value)
#普通攻击增伤:普通攻击附加的固定值伤害
def GetNormalHurt(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_NormalHurt)
def SetNormalHurt(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_NormalHurt, value)
#普通攻击加成:普通攻击附加的伤害百分比
def GetNormalHurtPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_NormalHurtPer)
def SetNormalHurtPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_NormalHurtPer, value)
#法宝技能增伤:法宝技能攻击附加的固定值伤害
def GetFabaoHurt(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_FabaoHurt)
def SetFabaoHurt(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_FabaoHurt, value)
#法宝技能加成:法宝技能攻击附加的伤害百分比
def GetFabaoHurtPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_FabaoHurtPer)
def SetFabaoHurtPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_FabaoHurtPer, value)
def GetMaxProDef(curPlayer): return 0
def SetMaxProDef(curPlayer, value): return
# 每X秒自动消失一个印记, 毫秒记录
def GetLostYinjiTime(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_LostYinjiTime)
def SetLostYinjiTime(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_LostYinjiTime, value)
    SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_YinjiTime, value)
def GetLostYinjiTime(curPlayer): return 0
def SetLostYinjiTime(curPlayer, value): return
# 当前印记数
def GetYinjiCnt(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_YinjiCnt)
def SetYinjiCnt(curPlayer, value):
    curPlayer.SetDict(ChConfig.Def_PlayerKey_YinjiCnt, value)
    SendPropertyRefresh(curPlayer, ShareDefine.CDBPlayerRefresh_YinjiCnt, value)
def GetYinjiCnt(curPlayer): return 0
def SetYinjiCnt(curPlayer, value): return
# 减少指定技能组CD XX%
def GetTheFBSkillsCD(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_TheFBSkillsCD)
def SetTheFBSkillsCD(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_TheFBSkillsCD, value)
def GetTheFBSkillsCD(curPlayer): return 0
def SetTheFBSkillsCD(curPlayer, value): return
# 灼烧固定伤害
def GetBurnValue(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_BurnValue)
def SetBurnValue(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_BurnValue, value)
def GetBurnValue(curPlayer): return 0
def SetBurnValue(curPlayer, value): return
# 延长灼烧时间百分比
def GetBurnTimePer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_BurnTimePer)
def SetBurnTimePer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_BurnTimePer, value)
def GetBurnTimePer(curPlayer): return 0
def SetBurnTimePer(curPlayer, value): return
# 减移动速度百分比
def GetSubSpeedPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_SubSpeedPer)
def SetSubSpeedPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_SubSpeedPer, value)
# 技能伤害增强
def GetSkillAddPer1(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_SkillAddPer1)
def SetSkillAddPer1(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_SkillAddPer1, value)
def GetSkillAddPer2(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_SkillAddPer2)
def SetSkillAddPer2(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_SkillAddPer2, value)
def GetSkillAddPer3(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_SkillAddPer3)
def SetSkillAddPer3(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_SkillAddPer3, value)
def GetSkillAddPer4(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_SkillAddPer4)
def SetSkillAddPer4(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_SkillAddPer4, value)
def GetSkillAddPer5(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_SkillAddPer5)
def SetSkillAddPer5(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_SkillAddPer5, value)
def GetSkillAddPer6(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_SkillAddPer6)
def SetSkillAddPer6(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_SkillAddPer6, value)
def GetSkillAddPer7(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_SkillAddPer7)
def SetSkillAddPer7(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_SkillAddPer7, value)
# 受到技能伤害减少
def GetSkillReducePer1(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_SkillReducePer1)
def SetSkillReducePer1(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_SkillReducePer1, value)
def GetSkillReducePer2(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_SkillReducePer2)
def SetSkillReducePer2(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_SkillReducePer2, value)
def GetSkillReducePer3(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_SkillReducePer3)
def SetSkillReducePer3(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_SkillReducePer3, value)
def GetSkillReducePer4(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_SkillReducePer4)
def SetSkillReducePer4(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_SkillReducePer4, value)
def GetSkillReducePer5(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_SkillReducePer5)
def SetSkillReducePer5(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_SkillReducePer5, value)
def GetSkillReducePer6(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_SkillReducePer6)
def SetSkillReducePer6(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_SkillReducePer6, value)
def GetSkillReducePer7(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_SkillReducePer7)
def SetSkillReducePer7(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_SkillReducePer7, value)
#---诛仙一击概率---
def GetZhuXianRate(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ZhuxianRate)
def SetZhuXianRate(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_ZhuxianRate, value)
#---诛仙护体减伤---
def GetZhuXianReducePer(curPlayer): return 0#curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ZhuXianReducePer)
def SetZhuXianReducePer(curPlayer, value): return #curPlayer.SetDict(ChConfig.Def_PlayerKey_ZhuXianReducePer, value)
## 计算功能背包物品属性
#  @param curPlayer 当前玩家
#  @param packType 背包类型
#  @param allAttrListEquip 属性列表
#  @return None
def CalcFuncPackItem(curPlayer, packType, allAttrListEquip):
    #===========================================================================
    # funcPack = curPlayer.GetItemManager().GetPack(packType)
    # equipPartIndexList = ChConfig.Pack_EquipPart_CanPlusStar.get(packType, [])
    #
    # #玩家当前可装备的装备类型
    # for equipIndex in range(0, funcPack.GetCount()):
    #
    #    curEquip = funcPack.GetAt(equipIndex)
    #    if curEquip.IsEmpty():
    #        continue
    #
    #    #计算效果
    #    for i in range(0, curEquip.GetEffectCount()):
    #        curEffect = curEquip.GetEffectByIndex(i)
    #        if not curEffect:
    #            break
    #
    #        effectID = curEffect.GetEffectID()
    #        if effectID == 0:
    #            #最后一个
    #            break
    #
    #        effectValue = curEffect.GetEffectValue(0)
    #        if not effectValue:
    #            continue
    #
    #        #添加物品效果的属性值
    #        CalcAttrDict_Type(effectID, effectValue, allAttrListEquip)
    #
    #
    #===========================================================================
    return
def GetSubSpeedPer(curPlayer): return 0
def SetSubSpeedPer(curPlayer, value): return
#-------------------------------------------------------------------------------
## 设置保存功能事先计算好的属性值
def SetCalcAttrListValue(curPlayer, funcIndex, allAttrList, insidePerAttrDict=None, customAttrDict=None):
    # 设置值之前先清空重置
    # @param customAttrDict: 自定义的属性信息,必须是格式 {"自定义属性描述名key":属性信息, ...}  自定义属性描述名key - 建议不同功能点之间不要重复
    ClearCalcAttrListValue(curPlayer, funcIndex)
    if insidePerAttrDict == None:
        insidePerAttrDict = {}
    if customAttrDict == None:
        customAttrDict = {}
    battleAttrDict = allAttrList[ChConfig.CalcAttr_Battle]
    if ChConfig.TYPE_Calc_PerLVAtk in battleAttrDict:
        # 每1级加的攻击力不一定满1点,所以这里按万分率来算,支持小数算法
        addAtk = int(curPlayer.GetLV() * battleAttrDict[ChConfig.TYPE_Calc_PerLVAtk] / float(ShareDefine.Def_MaxRateValue))
        battleAttrDict[ChConfig.TYPE_Calc_AttrATKMin] = battleAttrDict.get(ChConfig.TYPE_Calc_AttrATKMin, 0) + addAtk
        battleAttrDict[ChConfig.TYPE_Calc_AttrATKMax] = battleAttrDict.get(ChConfig.TYPE_Calc_AttrATKMax, 0) + addAtk
    if ChConfig.TYPE_Calc_PerLVMaxHP in battleAttrDict:
        # 每1级加的生命值不会少于1点,所以直接乘
        addMaxHP = curPlayer.GetLV() * battleAttrDict[ChConfig.TYPE_Calc_PerLVMaxHP]
        battleAttrDict[ChConfig.TYPE_Calc_AttrMaxHP] = battleAttrDict.get(ChConfig.TYPE_Calc_AttrMaxHP, 0) + addMaxHP
    playerID = curPlayer.GetPlayerID()
    if playerID not in PyGameData.g_playerFuncAttrDict:
        PyGameData.g_playerFuncAttrDict[playerID] = {}
    funcAttrDict = PyGameData.g_playerFuncAttrDict[playerID]
    funcAttrDict[funcIndex] = [allAttrList, insidePerAttrDict, customAttrDict]
    #GameWorld.DebugLog("保存功能点属性: funcIndex=%s, %s, %s" % (funcIndex, allAttrList, insidePerAttrDict))
    return
def GetCalcAttrListValue(curPlayer, funcIndex):
@@ -7754,57 +4964,13 @@
    attrList = [{} for _ in range(4)]
    insidePerAttrDict = {}
    customAttrDict = {}
    if isinstance(funcIndex, int):
        funcIndexList = [funcIndex]
    elif isinstance(funcIndex, list):
        funcIndexList = funcIndex
    else:
        return attrList, insidePerAttrDict, customAttrDict
    playerID = curPlayer.GetPlayerID()
    if playerID not in PyGameData.g_playerFuncAttrDict:
        return attrList, insidePerAttrDict, customAttrDict
    funcAttrDict = PyGameData.g_playerFuncAttrDict[playerID]
    for funcIndex in funcIndexList:
        if funcIndex not in funcAttrDict:
            continue
        funcAttrList, funcInsidePerAttrDict, funcCustomAttrDict = funcAttrDict[funcIndex]
        for i, attrDict in enumerate(attrList):
            curAttrDict = funcAttrList[i]
            AddAttrDictValue(attrDict, curAttrDict)
        customAttrDict.update(funcCustomAttrDict)
        AddAttrDictValue(insidePerAttrDict, funcInsidePerAttrDict)
    return attrList, insidePerAttrDict, customAttrDict
## 重置缓存
def ClearCalcAttrListValue(curPlayer, funcIndex):
    playerID = curPlayer.GetPlayerID()
    if playerID not in PyGameData.g_playerFuncAttrDict:
        return
    funcAttrDict = PyGameData.g_playerFuncAttrDict[playerID]
    funcAttrDict.pop(funcIndex, None)
    return
def AddAttrListValue(attrList):
    addAttrList = [{} for _ in range(4)]
    for aList in attrList:
        for i in ChConfig.CalcAttrIndexList:
            AddAttrDictValue(addAttrList[i], aList[i])
    return addAttrList
## 属性值字典累加
def AddAttrDictValue(dict1, dict2):
    for key, value in dict2.items():
        if key not in dict1:
            dict1[key] = value
        else:
            aValue = dict1[key]
            if key in ChConfig.TYPE_Calc_DeclineList:
                # 这种算法的属性一般是万分率的,最大不超过百分百,故暂默认万分率, 若有不是万分率的属性再做处理
                dict1[key] = 10000 - (10000 - aValue) * (10000 - value)
            else:
                dict1[key] = aValue + value
    return
def GetLordAttr(curPlayer):
    ## 获取主公属性汇总
    lordAttrDict = {"Atk":curPlayer.GetMaxAtk(), "Def":curPlayer.GetDef(), "MaxHP":GameObj.GetMaxHP(curPlayer),
                    "Hit":curPlayer.GetHit(), "Miss":curPlayer.GetMiss()}
    return lordAttrDict
#-------------------------------------------------------------------------------
## 设置玩家字典值, 存库