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,7 +28,6 @@
import NPCCommon
import ItemCommon
import ReadChConfig
import PlayerGMOper
import BuffSkill
import PetControl
import OperControlManager
@@ -58,7 +54,6 @@
import PlayerActivity
import FBCommon
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
@@ -97,7 +91,6 @@
import PlayerCoat
import PlayerAssist
import PlayerState
import QuestCommon
import PlayerDogz
import PlayerFaQi
import PlayerLove
@@ -106,6 +99,7 @@
import PlayerCharm
import PlayerTask
import PlayerFace
import PlayerMail
import ChPlayer
import GMShell
import GameObj
@@ -345,189 +339,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 信息参数列表
@@ -619,35 +440,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:
@@ -807,6 +602,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
#---------------------------------------------------------------------
##设置玩家是否激活
@@ -1109,98 +911,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 检查的对象
@@ -1283,21 +993,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 返回值无意义
@@ -1318,29 +1013,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)
    #设置玩家的地图位置, 如果是副本, 离开副本
#    副本规则:
@@ -1500,8 +1181,6 @@
    __PlayerLeaveServerLogic(curPlayer, tick, True)
    #骑马玩家下线逻辑
    __RidingHorsePlayerDisconnect(curPlayer)
    #镖车下线逻辑
    __TruckPlayerDisconnect(curPlayer)
    #召唤兽死亡
    KillPlayerSummonNPC(curPlayer)
    #更新从本地图离线信息
@@ -1557,34 +1236,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 玩家实例
@@ -1593,22 +1244,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)
@@ -1623,25 +1258,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 之前更新
@@ -1679,18 +1295,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
#---------------------------------------------------------------------
@@ -1774,7 +1378,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():
@@ -1898,12 +1502,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()
    
@@ -1923,7 +1521,6 @@
            # 新手线路特殊处理,直接进入
            if lineID in newbielineList:
                GameWorld.DebugLog("封魔坛虚拟线路只能通过自定义场景进入挑战!")
                #PlayerResetWorldPosFB(curPlayer, mapID, posX, posY, False, fbID, funcLineID=lineID)
                return
            else:
                bossID = GameLogic_SealDemon.CurFBLineBOSSID(lineID)
@@ -1947,7 +1544,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请求进入副本
@@ -2054,21 +1651,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
@@ -2157,14 +1739,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:
@@ -2186,8 +1767,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)
@@ -2207,10 +1788,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))
    #获取副本传入副本需要携带的信息
@@ -2218,12 +1796,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))
    
@@ -2287,7 +1865,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
@@ -2298,13 +1876,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("死亡无法切换地图")
@@ -2328,7 +1905,7 @@
        return
    
    #---不同地图ID切换地图---
    PlayerResetWorldPosFB(curPlayer, mapID, posX, posY, takeTruck, shuntLineID, msg, canLock)
    PlayerResetWorldPosFB(curPlayer, mapID, posX, posY, shuntLineID, msg, canLock)
    
    #如果是服务器中最后一个人离开, 则关掉副本
    GameWorldProcess.OnPlayerLeaveMapCloseFB()
@@ -3300,8 +2877,6 @@
    elif type_Price == IPY_GameWorld.TYPE_Price_Silver_Paper:
        __PayMoneyAfterBySilverPaper(curPlayer, price)
    
    EventShell.EventRespons_OnMoneyChange(curPlayer, type_Price)
    #活跃度处理
    PlayerActivity.OnPayMoneyActivity(curPlayer, type_Price, price)
    #转盘活动
@@ -3534,7 +3109,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 +3131,6 @@
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] \
@@ -3737,8 +3310,6 @@
        #PK_wll_0: 您杀孽过重,在红名状态消失前您将不能继续而已攻击他人
        NotifyCode(curPlayer, "PK_lhs_202580")
        
    #玩家镖车身上记录玩家名字颜色信息(必须在设置红名以后)
    #PlayerTruck.ChangeTruckNoteInfo(curPlayer)
    return
def ChangePKValue(curPlayer, addValue, tick):
@@ -4137,36 +3708,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 类实例
@@ -4409,8 +3950,6 @@
                    needSyncTalentPoint = True
                    PlayerGreatMaster.AddGreatMasterSkillPointByLV(curPlayer, addTalentPoint)
            
            EventShell.EventResponse_LVUp(curPlayer)  # 升级触发事件
            PlayerTongTianLing.AddTongTianTaskValue(curPlayer, ChConfig.TTLTaskType_LVUp, 1)
            #---是否继续循环---
            curTotalExp = curTotalExp - lvUpNeedExp
@@ -4580,9 +4119,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 +4684,6 @@
        # 6.计算buff属性, buff层级的不算如战斗力
        #        算战斗力总值时该层影响的数值不统计,但刷属性时需计算
        SkillShell.CalcBuffers_Effect(curPlayer, allAttrListBuffs)
        # 渡劫副本护法属性加成
        GameLogic_DuJie.CalcDujieFBAttrAdd(curPlayer, allAttrListBuffs)
            
        #        层非线性战斗属性累加
        battleNolineAttrBuff = allAttrListBuffs[ChConfig.CalcAttr_BattleNoline]
@@ -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()
        
@@ -5966,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
#---------------------------------------------------------------------
##关于传送 验证玩家状态
@@ -6033,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)
    
@@ -6053,10 +5577,6 @@
        #执行下马逻辑
        PlayerHorse.PlayerRideHorseDown(curPlayer, False)
        
    #玩家镖车中, 下车
    elif curPlayerVehicle == IPY_GameWorld.pvTruck:
        PlayerTruck.PlayerTruckDown(curPlayer, curPlayer.GetTruck())
    #---其他系统处理---
    
    #中断战斗对峙
@@ -6644,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: