hxp
2025-06-03 4cdd576855c6e22d986ece4b18f7c80d82cefe38
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
@@ -17,11 +17,8 @@
import ChEquip
import SkillShell
import ChConfig
import EventShell
import EffGetSet
import PlayerHorse
import PlayerTruck
import PlayerTrade
import PlayerTeam
import SkillCommon
import MirrorAttack
@@ -31,12 +28,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
@@ -56,9 +53,7 @@
import PlayerWorldAverageLv
import PlayerActivity
import FBCommon
import PlayerViewCacheTube
import PassiveBuffEffMng
import PlayerGameEvent
import EventReport
import PlayerGatherSoul
import PlayerGatherTheSoul
@@ -69,7 +64,6 @@
import GameFuncComm
import IpyGameDataPY
import PlayerRune
import GameLogic_DuJie
import PyGameData
import PlayerMagicWeapon
import PlayerFeastTravel
@@ -77,7 +71,6 @@
import GameLogic_SealDemon
import GameLogic_ZhuXianBoss
import GameLogic_CrossDemonKing
import PlayerTJG
import PlayerVip
import PlayerRefineStove
import PlayerFamilyTech
@@ -87,7 +80,6 @@
import PlayerActGarbageSorting
import GY_Query_CrossRealmReg
import PlayerTongTianLing
import PlayerCrossRealmPK
import FunctionNPCCommon
import PlayerGoldInvest
import IPY_PlayerDefine
@@ -99,16 +91,16 @@
import PlayerCoat
import PlayerAssist
import PlayerState
import QuestCommon
import PlayerDogz
import PlayerFaQi
import PlayerLove
import PlayerGubao
import PlayerShentong
import PlayerCharm
import PlayerTask
import PlayerFace
import PlayerMail
import ChPlayer
import GMShell
import GameObj
import random
@@ -250,7 +242,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 +274,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 +338,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 +439,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 +601,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
#---------------------------------------------------------------------
##设置玩家是否激活
@@ -1103,98 +910,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 +992,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 +1012,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)
    #设置玩家的地图位置, 如果是副本, 离开副本
#    副本规则:
@@ -1487,14 +1173,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 +1235,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 +1243,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 +1257,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 +1294,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 +1377,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 +1501,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 +1520,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 +1543,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 +1585,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 +1650,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 +1738,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 +1766,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 +1787,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 +1795,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 +1864,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 +1875,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 +1904,7 @@
        return
    
    #---不同地图ID切换地图---
    PlayerResetWorldPosFB(curPlayer, mapID, posX, posY, takeTruck, shuntLineID, msg, canLock)
    PlayerResetWorldPosFB(curPlayer, mapID, posX, posY, shuntLineID, msg, canLock)
    
    #如果是服务器中最后一个人离开, 则关掉副本
    GameWorldProcess.OnPlayerLeaveMapCloseFB()
@@ -2349,9 +1927,6 @@
        特殊boss分流: 
        @param bossID: 分流bossID
    '''
    if PlayerTJG.GetIsTJG(curPlayer):
        GameWorld.DebugLog("脱机的玩家不处理分流!", curPlayer.GetPlayerID())
        return tagLineID
    if GameWorld.IsCrossServer():
        return tagLineID
    # 非常规地图之间的切换不处理
@@ -3251,7 +2826,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 +2876,14 @@
    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:
        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
@@ -3534,7 +3108,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)
@@ -3557,7 +3130,7 @@
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:
@@ -3736,8 +3309,6 @@
        #PK_wll_0: 您杀孽过重,在红名状态消失前您将不能继续而已攻击他人
        NotifyCode(curPlayer, "PK_lhs_202580")
        
    #玩家镖车身上记录玩家名字颜色信息(必须在设置红名以后)
    #PlayerTruck.ChangeTruckNoteInfo(curPlayer)
    return
def ChangePKValue(curPlayer, addValue, tick):
@@ -3789,8 +3360,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:
@@ -4138,36 +3707,6 @@
            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 类实例
@@ -4410,8 +3949,6 @@
                    needSyncTalentPoint = True
                    PlayerGreatMaster.AddGreatMasterSkillPointByLV(curPlayer, addTalentPoint)
            
            EventShell.EventResponse_LVUp(curPlayer)  # 升级触发事件
            PlayerTongTianLing.AddTongTianTaskValue(curPlayer, ChConfig.TTLTaskType_LVUp, 1)
            #---是否继续循环---
            curTotalExp = curTotalExp - lvUpNeedExp
@@ -4434,6 +3971,7 @@
            aftBaseCON = curPlayer.GetBaseCON()
            if aftLV > befLV:
                curPlayer.SetLV(aftLV, False) # 这里不再通知GameServer
                PlayerTask.UpdTaskValue(curPlayer, ChConfig.TaskType_LV, aftLV)
                PlayerSuccess.UptateSuccessProgress(curPlayer, ShareDefine.SuccType_HeroLV, aftLV)
                PlayerActivity.DoAddActivityByLV(curPlayer, befLV, aftLV)
                
@@ -4580,9 +4118,6 @@
                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)
@@ -5148,8 +4683,6 @@
        # 6.计算buff属性, buff层级的不算如战斗力
        #        算战斗力总值时该层影响的数值不统计,但刷属性时需计算
        SkillShell.CalcBuffers_Effect(curPlayer, allAttrListBuffs)
        # 渡劫副本护法属性加成
        GameLogic_DuJie.CalcDujieFBAttrAdd(curPlayer, allAttrListBuffs)
            
        #        层非线性战斗属性累加
        battleNolineAttrBuff = allAttrListBuffs[ChConfig.CalcAttr_BattleNoline]
@@ -5173,10 +4706,11 @@
    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
        platform = GameWorld.GetPlatform()
        if not GameWorld.IsTestPlatform(platform):
            return
        
        ipyDataMgr = IpyGameDataPY.IPY_Data()
@@ -5462,31 +4996,28 @@
        
        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)
        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)
            
            # 骑乘状态加上骑乘附加速度
            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)
            
            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错误
        speed = max(speed, 0)   #防小于0错误
        if GetSpeedValue(curPlayer) != speed:
            SetSpeedValue(curPlayer, speed)
            moveSpeed = eval(FormulaControl.GetCompileFormula("MoveSpeed", moveSpeedFormat))
@@ -5665,7 +5196,7 @@
            return
        
        #把人物设置回重生点
        PlayerResetWorldPos(curPlayer, rebornMapID, rebornPosX, rebornPosY, False)
        PlayerResetWorldPos(curPlayer, rebornMapID, rebornPosX, rebornPosY)
        return
    
    #---------------------------------------------------------------------
@@ -5692,8 +5223,6 @@
        #召唤回出战的宠物
        PetControl.ReCallFightPet(curPlayer)
        
        #拉镖玩家死亡处理
        PlayerTruck.DoPlayerDead(curPlayer)
        #清空使用技能记录
        curPlayer.ClearUseSkillRec()
        
@@ -5718,7 +5247,6 @@
        #通知死亡
        DoPlayerDead(curPlayer)
        
        #PlayerTJG.PlayerTJGReborn(curPlayer, tick)
        GameObj.ClearPyPlayerState(curPlayer)
        
        MirrorAttack.OnPlayerDead(curPlayer)
@@ -5967,12 +5495,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 +5557,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 +5577,6 @@
        #执行下马逻辑
        PlayerHorse.PlayerRideHorseDown(curPlayer, False)
        
    #玩家镖车中, 下车
    elif curPlayerVehicle == IPY_GameWorld.pvTruck:
        PlayerTruck.PlayerTruckDown(curPlayer, curPlayer.GetTruck())
    #---其他系统处理---
    
    #中断战斗对峙
@@ -6242,7 +5761,7 @@
    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()
@@ -6584,7 +6103,7 @@
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
@@ -6645,12 +6164,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:
@@ -7398,6 +6911,14 @@
def GetFamilyEmblemID(curPlayer): return curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FamilyEmblemID)
def SetFamilyEmblemID(curPlayer, emblemID): NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_FamilyEmblemID, emblemID)
# 仙盟职位,使用 GetReceivedSalary,因为FamilyMemberLV没有入库
def GetFamilyMemberLV(curPlayer): return curPlayer.GetReceivedSalary()
def SetFamilyMemberLV(curPlayer, fmLV):
    #因为仙盟职位没有存DBPlayer,而跨服后又没有Family信息,所以这里做个存储,用于跨服用
    curPlayer.SetReceivedSalary(fmLV)
    curPlayer.SetFamilyMemberLV(fmLV) # 也同步设置该值,防止有些地方直接调用 curPlayer.GetFamilyMemberLV()
    return
# 仙盟事务速度加成
def GetAffairSpeedPer(curPlayer): return curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_AffairSpeedPer)
def SetAffairSpeedPer(curPlayer, value): curPlayer.SetDict(ChConfig.Def_PlayerKey_AffairSpeedPer, value)