hxp
2024-01-06 776cf3759b9801f3795ee975cd77078f505b90d6
10071 【后端】灵宠改版
15个文件已修改
1418 ■■■■■ 已修改文件
PySysDB/PySysDBPY.h 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/AttackLogic/AttackCommon.py 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py 176 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCAI/AICommon.py 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py 35 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py 16 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PetControl.py 582 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerFB.py 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerPet.py 490 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerState.py 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerViewCacheTube.py 60 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/SkillShell.py 28 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
PySysDB/PySysDBPY.h
@@ -882,7 +882,7 @@
    DWORD        _DataMapID;    //数据地图ID
    WORD        _LineID;    //功能线路ID
    DWORD        NPCID;    //NPCID
    DWORD        SummerNPCID;    //召唤兽ID
    list        PetNPCIDList;    //灵宠NPCID列表
    list        AwardItemListFirst;    //首次过关奖励列表[[物品ID,个数,是否拍品], ...]
    list        AwardItemList;    //再次过关奖励列表[[物品ID,个数,是否拍品], ...]
};
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/AttackLogic/AttackCommon.py
@@ -2114,6 +2114,8 @@
        fbFightPower = GameWorld.GetGameFB().GetGameFBDictByKey(ChConfig.FBPD_HelpBattleFBFightPower)
        fbBaseHurt = GameWorld.GetGameFB().GetGameFBDictByKey(ChConfig.FBPD_HelpBattleFBBaseHurt)
        helpBattleFormatKey = "HelpRobot_Def"
    if atkObjType == IPY_GameWorld.gotNPC and PetControl.IsPetNPC(atkObj):
        mustHit = True
        
    #命中公式 攻击方类型不同,公式不同
    hitFormula = ReadChConfig.GetChConfig('CalcCanHit')
@@ -2465,6 +2467,8 @@
            return "HelpRobot"
        if obj.GetType() in ChConfig.PVPNPCTypeList:
            return "P"
        if obj.GetType() == IPY_GameWorld.ntPet:
            return "Pet"
        
    objType = obj.GetGameNPCObjType()
    if objType == IPY_GameWorld.gnotPet:
@@ -2476,7 +2480,7 @@
# @param None
# @return 攻击形式字符串
def GetAtkState(atkObj, defObj):
    isPet = PetControl.IsPet(atkObj)
    isPet = PetControl.IsPetNPC(atkObj)
    if IsPVENPCObj(atkObj) or IsPVENPCObj(defObj):
        return 'PVE_%s' if not isPet else 'PetVE_%s'
    
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py
@@ -29,6 +29,7 @@
import NPCCommon
import GameWorld
import GameObj
import PetControl
(
FightState_Start,
@@ -37,6 +38,12 @@
FightState_Fail,
FightState_Over,
) = range(5)
def GetObjName(gameObj):
    objName = gameObj.GetName()
    faction = GameObj.GetFaction(gameObj)
    fightPlaceNum = gameObj.GetDictByKey(ChConfig.Def_Obj_Dict_FightPetPlaceNum)
    return "%s%s %s" % ("A" if faction == 1 else "B", fightPlaceNum, objName)
#// B4 10 回合制战斗 #tagCMTurnFight
#
@@ -59,7 +66,7 @@
    SyncTurnFightState(curPlayer, mapID, funcLineID, tagPlayerID, FightState_Start)
    
    if tagPlayerID:
        PlayerViewCacheTube.GetPlayerPropDataCall(curPlayer, tagPlayerID, DoTrunFightVSPlayer, [mapID, funcLineID])
        PlayerViewCacheTube.GetPlayerPropDataCall(curPlayer, tagPlayerID, DoTrunFightVSPlayer, [mapID, funcLineID], True)
        return
    
    DoTrunFight(curPlayer, mapID, funcLineID, tagPlayerID, tick)
@@ -78,28 +85,16 @@
def DoTrunFight(curPlayer, mapID, funcLineID, tagPlayerID, tick):
    playerID = curPlayer.GetPlayerID()
    posX, posY = curPlayer.GetPosX(), curPlayer.GetPosY()
    factionListA, factionListB = [], []
    factionListA.append(curPlayer)
    curPet = curPlayer.GetPetMgr().GetFightPet()
    curPet and factionListA.append(curPet)
    # 玩家阵营的其他战斗实例,可扩展...
    assistNPCID = 0 # 协助召唤兽
    if assistNPCID:
        assistNPC = NPCCommon.SummonNPC(curPlayer, assistNPCID, posX, posY)
        assistNPC and factionListA.append(assistNPC)
    GameWorld.DebugLog("===== 执行回合制战斗: mapID=%s,funcLineID=%s,tagPlayerID=%s" % (mapID, funcLineID, tagPlayerID), playerID)
    tagObj = None
    if tagPlayerID:
        npcID = ChConfig.Def_NPCID_PVP
        tagObj = NPCCommon.SummonMapNpc(npcID, posX, posY, sightLevel=playerID, pvpPlayerID=tagPlayerID)
        if not tagObj:
            return
        factionListB.append(tagObj)
        # 对手玩家镜像的其他战斗实例...
        PlusData = PlayerViewCacheTube.GetPlayerPropPlusDictByID(playerID)[1] # 从缓存中获取
        petCacheInfo = PlusData.get("Pet")
        fightPetObjListB = PetControl.CalloutFightPet(tagObj, petCacheInfo)
    else:
        ipyData = IpyGameDataPY.GetIpyGameData("FBTurn", mapID, funcLineID)
        if not ipyData:
@@ -110,34 +105,42 @@
        tagObj = NPCCommon.SummonMapNpc(npcID, posX, posY, sightLevel=playerID)
        if not tagObj:
            return
        factionListB.append(tagObj)
        summerNPCID = ipyData.GetSummerNPCID()
        if summerNPCID:
            summerNPC = NPCCommon.SummonNPC(tagObj, summerNPCID, posX, posY)
            summerNPC and factionListB.append(summerNPC)
    if not factionListB:
        return
    for gameObj in factionListA:
        GameObj.SetFaction(gameObj, 1)
    for gameObj in factionListB:
        GameObj.SetFaction(gameObj, 2)
    #一个回合攻击顺序,由攻击速度决定,攻速相同下阵营1先攻击,还相同则由ID决定
    fightObjList = factionListA + factionListB
    fightObjList.sort(key=lambda o: (GameObj.GetAtkSpeed(o), (10 - GameObj.GetFaction(o)), o.GetID()), reverse=True)
        petNPCIDList = ipyData.GetPetNPCIDList()
        petCacheInfo = [] # 从配表中读取组合,技能默认取NPC表配置的
        for state, petNPCID in enumerate(petNPCIDList, 1):
            petCacheInfo.append({"npcID":petNPCID, "state":state, "quality":0})
        fightPetObjListB = PetControl.CalloutFightPet(tagObj, petCacheInfo)
    
    turnMax = IpyGameDataPY.GetFuncCfg("TurnFight", 1)
    GameWorld.DebugLog("===== 执行回合制战斗: mapID=%s,funcLineID=%s,tagPlayerID=%s,tagObjID=%s"
                       % (mapID, funcLineID, tagPlayerID, tagObj.GetID()), playerID)
    # 战斗前初始化
    for gameObj in fightObjList:
        TurnFightObjStartInit(gameObj)
    # 宠物先攻击
    fightPetObjListA = PetControl.CalloutFightPet(curPlayer)
    factionListA = fightPetObjListA + [curPlayer]
    factionListB = fightPetObjListB + [tagObj]
    atkFactionList = [factionListA, factionListB]
    # 战斗前初始化,可能会改变攻速,所以先初始化
    for faction, factionObjList in enumerate(atkFactionList, 1):
        for gameObj in factionObjList:
            TurnFightObjStartInit(gameObj, faction, tick)
    #一个回合攻击顺序,为了后续逻辑统一,都是先确定好顺序
    sortType = 2 # 攻击顺序排序方式
    fightObjList = []
    #方式1: 纯由攻击速度决定,攻速相同下阵营1先攻击,还相同则由ID决定
    if sortType == 1:
        fightObjList = factionListA + factionListB
        fightObjList.sort(key=lambda o: (GameObj.GetAtkSpeed(o), (10 - GameObj.GetFaction(o)), o.GetID()), reverse=True)
    #方式2:根据阵营主角攻速决定先手,然后每个阵营轮流固定位置攻击
    elif sortType == 2:
        if GameObj.GetAtkSpeed(curPlayer) < GameObj.GetAtkSpeed(tagObj):
            atkFactionList = [factionListB, factionListA]
        for i in range(len(factionListA)):
            for factionObjList in atkFactionList:
                fightObjList.append(factionObjList[i])
        
    isWin = None
    for turnNum in range(1, turnMax + 1):
        GameWorld.DebugLog("----- 回合制战斗轮次: %s -----" % turnNum, playerID)
        GameWorld.DebugLog("【----- 回合制战斗轮次: %s -----】" % turnNum)
        SyncTurnFightState(curPlayer, mapID, funcLineID, tagPlayerID, FightState_Fighting, turnNum, turnMax)
        
        # 回合开始: 做一些每回合重置逻辑或者某些根据回合触发的效果等
@@ -145,18 +148,22 @@
            TurnFightObjPerTurnStart(gameObj, turnNum, tick)
            
        # 回合战斗: 轮流依次攻击
        for actNum, gameObj in enumerate(fightObjList, 1):
            if not gameObj:
        for gameObj in fightObjList:
            if not gameObj or GameObj.GetHP(gameObj) <= 0:
                continue
            faction = GameObj.GetFaction(gameObj)
            tagGameObj = tagObj if faction == 1 else curPlayer
            objType = gameObj.GetGameObjType()
            objID = gameObj.GetID()
            objName = GetObjName(gameObj)
            curHP = GameObj.GetHP(gameObj)
            tagGameObj = tagObj if faction == 1 else curPlayer
            tagObjType = tagGameObj.GetGameObjType()
            tagObjID = tagGameObj.GetID()
            tagHP = GameObj.GetHP(tagGameObj)
            
            GameWorld.DebugLog("    行动: turnNum=%s,actNum=%s,faction=%s,objType=%s,objID=%s,tagObjType=%s,tagObjID=%s"
                               % (turnNum, actNum, faction, objType, objID, tagObjType, tagObjID))
            GameWorld.DebugLog("    ★回合%s %s 行动 : objType-ID-HP(%s-%s-%s), tagType-ID-HP(%s-%s-%s)"
                               % (turnNum, objName, objType, objID, curHP, tagObjType, tagObjID, tagHP))
            SyncTurnFightObjAction(curPlayer, turnNum, objType, objID)
            
            DoAttack(gameObj, tagGameObj, tick)
@@ -190,22 +197,25 @@
                       % (mapID, funcLineID, tagPlayerID, isWin, overState), playerID)
    return
def TurnFightObjStartInit(gameObj):
def TurnFightObjStartInit(gameObj, faction, tick):
    ## 回合制战斗实例初始化
    if not gameObj:
        return
    gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnFightNum, 1)
    GameObj.SetFaction(gameObj, faction)
    GameObj.SetHPFull(gameObj)
    gameObj.RefreshView()
    
    objType = gameObj.GetGameObjType()
    npcID = gameObj.GetNPCID() if objType == IPY_GameWorld.gotNPC else 0
    GameWorld.DebugLog("初始化实例: objID=%s,npcID=%s,faction=%s,atkSpeed=%s,HP=%s,Atk=%s,Def=%s"
                       % (gameObj.GetID(), npcID, GameObj.GetFaction(gameObj), GameObj.GetAtkSpeed(gameObj), GameObj.GetHP(gameObj), gameObj.GetMaxAtk(), gameObj.GetDef()))
    GameWorld.DebugLog("    闪命(%s,%s),闪避(%s,%s),暴击(%s,%s),击晕(%s,%s),连击(%s,%s),反击(%s,%s),吸血(%s,%s)"
                       % (gameObj.GetMiss(), gameObj.GetHit(),
                          GameObj.GetMissRate(gameObj), GameObj.GetMissDefRate(gameObj),
    objName = GetObjName(gameObj)
    fightPlaceNum = gameObj.GetDictByKey(ChConfig.Def_Obj_Dict_FightPetPlaceNum)
    GameWorld.DebugLog("【 %s 初始化 %s 】 objID=%s,npcID=%s,atkSpeed=%s,HP=%s,Atk=%s,Def=%s"
                       % (objName, BaseAttack.GetObjAttackName(gameObj), gameObj.GetID(), npcID,
                          GameObj.GetAtkSpeed(gameObj), GameObj.GetHP(gameObj), gameObj.GetMaxAtk(), gameObj.GetDef()))
    GameWorld.DebugLog("    闪避(%s,%s),暴击(%s,%s),击晕(%s,%s),连击(%s,%s),反击(%s,%s),吸血(%s,%s)"
                       % (GameObj.GetMissRate(gameObj), GameObj.GetMissDefRate(gameObj),
                          GameObj.GetSuperHitRate(gameObj), GameObj.GetSuperHitRateReduce(gameObj),
                          GameObj.GetFaintRate(gameObj), GameObj.GetFaintDefRate(gameObj),
                          GameObj.GetComboRate(gameObj), GameObj.GetComboDefRate(gameObj),
@@ -217,11 +227,23 @@
    if objType == IPY_GameWorld.gotPlayer:            
        skillManager = gameObj.GetSkillManager()
        for i in range(skillManager.GetSkillCount()):
            skill = skillManager.GetSkillByIndex(i)
            skill.SetRemainTime(0)
            curSkill = skillManager.GetSkillByIndex(i)
            curSkill.SetRemainTime(0)
            
    elif objType == IPY_GameWorld.gotNPC:
        pass
        skillIDList = []
        skillManager = gameObj.GetSkillManager()
        for i in range(skillManager.GetSkillCount()):
            curSkill = skillManager.GetSkillByIndex(i)
            if not curSkill:
                continue
            skillIDList.append(curSkill.GetSkillID())
            if fightPlaceNum:
                # 灵宠技能开始时直接进入CD
                curSkill.SetLastUseTick(tick)
                curSkill.SetRemainTime(curSkill.GetCoolDownTime())
        GameWorld.DebugLog("    NPC技能: npcID=%s,skillIDList=%s" % (npcID, skillIDList))
    return
def TurnFightObjPerTurnStart(gameObj, turnNum, tick):
@@ -237,7 +259,8 @@
    
    objType = gameObj.GetGameObjType()
    objID = gameObj.GetID()
    GameWorld.DebugLog("ObjPerTurnStart: faction=%s,objType=%s,objID=%s,turnNum=%s,HP=%s" % (GameObj.GetFaction(gameObj), objType, objID, turnNum, GameObj.GetHP(gameObj)))
    objName = GetObjName(gameObj)
    GameWorld.DebugLog("ObjPerTurnStart: 回合%s, %s objType-ID-HP(%s-%s-%s)" % (turnNum, objName, objType, objID, GameObj.GetHP(gameObj)))
    
    # 每回合开始减技能CD
    skillManager = gameObj.GetSkillManager()
@@ -357,7 +380,9 @@
def CanAtkBack(atkObj, defObj):
    ## 可否反击
    if atkObj.GetDictByKey(ChConfig.Def_Obj_Dict_FightPetPlaceNum) > 0:
        #GameWorld.DebugLog("            被灵宠攻击时无法触发反击")
        return False
    defAtkBackRate = GameObj.GetAtkBackRate(defObj) # 防方反击率
    atkBackNum = defObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnAtkBackNum) # 已反击次数
    if atkBackNum > 10:
@@ -407,18 +432,40 @@
    ## NPC攻击
    if not curObj:
        return
    objName = "● %s" % GetObjName(curObj)
    #有值代表灵宠上阵位置,判断是否有概率攻击
    fightPlaceNum = curObj.GetDictByKey(ChConfig.Def_Obj_Dict_FightPetPlaceNum)
    if fightPlaceNum > 0:
        fightRateList = IpyGameDataPY.GetFuncEvalCfg("PetGoOutFight", 2)
        if fightPlaceNum > len(fightRateList):
            return
        fightRatePer = fightRateList[fightPlaceNum - 1]
        qualityAddRateInfo = IpyGameDataPY.GetFuncEvalCfg("PetGoOutFight", 3, {})
        petQuality = curObj.GetDictByKey(ChConfig.Def_Obj_Dict_FightPetQuality)
        qualityAddPer = qualityAddRateInfo.get(str(petQuality), 0)
        fightRatePer += qualityAddPer
        if fightRatePer < 100 and not GameWorld.CanHappen(fightRatePer, 100):
            GameWorld.DebugLog("        灵宠概率不攻击: curID=%s,fightPlaceNum=%s,petQuality=%s,fightRatePer=%s"
                               % (curObj.GetID(), fightPlaceNum, petQuality, fightRatePer))
            return
    tagDist = 0
    atkOK = AICommon.DoAutoUseSkill(curObj, tagObj, tagDist, tick)
    #---优先释放技能---
    if not atkOK:
        if fightPlaceNum:
            GameWorld.DebugLog("        灵宠不可普通攻击: curID=%s,fightPlaceNum=%s" % (curObj.GetID(), fightPlaceNum))
        else:
        #普通攻击
        atkOK = BaseAttack.Attack(curObj, tagObj, None, tick)
        if atkOK:
            GameWorld.DebugLog("        NPC普通攻击: curID=%s,tagID=%s,atkOK=%s" % (curObj.GetID(), tagObj.GetID(), atkOK))
                GameWorld.DebugLog("        %s 普通攻击: curID=%s,tagID=%s,atkOK=%s" % (objName, curObj.GetID(), tagObj.GetID(), atkOK))
        else:
            GameWorld.DebugLog("        NPC攻击失败: curID=%s,tagID=%s,atkOK=%s" % (curObj.GetID(), tagObj.GetID(), atkOK))
                GameWorld.DebugLog("        %s 攻击失败: curID=%s,tagID=%s,atkOK=%s" % (objName, curObj.GetID(), tagObj.GetID(), atkOK))
    else:
        GameWorld.DebugLog("        NPC技能攻击: curID=%s,tagID=%s,atkOK=%s" % (curObj.GetID(), tagObj.GetID(), atkOK))
        GameWorld.DebugLog("        %s 技能攻击: curID=%s,tagID=%s,atkOK=%s" % (objName, curObj.GetID(), tagObj.GetID(), atkOK))
    return atkOK
def PlayerAttack(curPlayer, tagObj, tick):
@@ -433,6 +480,7 @@
    posX, posY = tagPosX, tagPosY = curPlayer.GetPosX(), curPlayer.GetPosY()
    tagObjType, tagObjID = tagObj.GetGameObjType(), tagObj.GetID()
    
    objName = "● %s" % GetObjName(curPlayer)
    curPlayer.ClearUseSkillRec()
    curPlayer.SetAttackTargetPos(posX, posY)
    curPlayer.SetUseSkillPosX(tagPosX)
@@ -461,10 +509,10 @@
        curPlayer.SetUseSkill(curSkill.GetSkillData())
        useSkillData = curPlayer.GetUseSkill()
        if not PlayerState.__DoClientUseSkillEx(curPlayer, useSkillData, tick):
            GameWorld.DebugLog("        玩家技能攻击失败: playerID=%s,tagID=%s,skillID=%s" % (playerID, tagObjID, skillID))
            GameWorld.DebugLog("        %s 技能攻击失败: playerID=%s,tagID=%s,skillID=%s" % (objName, playerID, tagObjID, skillID))
            continue
        useSkillResult = True
        GameWorld.DebugLog("        玩家技能攻击成功: playerID=%s,tagID=%s,skillID=%s" % (playerID, tagObjID, skillID))
        GameWorld.DebugLog("        %s 技能攻击成功: playerID=%s,tagID=%s,skillID=%s" % (objName, playerID, tagObjID, skillID))
        
        break
    
@@ -475,9 +523,9 @@
        atkOK = BaseAttack.Attack(curPlayer, tagObj, None, tick)
        if atkOK:
            useSkillResult = True
            GameWorld.DebugLog("        玩家普通攻击: curID=%s,tagID=%s,atkOK=%s" % (playerID, tagObjID, atkOK))
            GameWorld.DebugLog("        %s 普通攻击: curID=%s,tagID=%s,atkOK=%s" % (objName, playerID, tagObjID, atkOK))
        else:
            GameWorld.DebugLog("        玩家攻击失败: curID=%s,tagID=%s,atkOK=%s" % (playerID, tagObjID, atkOK))
            GameWorld.DebugLog("        %s 攻击失败: curID=%s,tagID=%s,atkOK=%s" % (objName, playerID, tagObjID, atkOK))
    return useSkillResult
def SyncTurnFightState(curPlayer, mapID, funcLineID, tagPlayerID, state, turnNum=0, turnMax=0):
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
@@ -3070,6 +3070,8 @@
Def_Obj_Dict_TurnComboNum = 'TurnComboNum' # 本回合已累计连击次数
Def_Obj_Dict_TurnAtkBackNum = 'TurnAtkBackNum' # 本回合已累计反击次数
Def_Obj_Dict_TurnBattleType = 'TurnBattleType' # 本次攻击战斗类型:TurnBattleType_xxx
Def_Obj_Dict_FightPetPlaceNum = 'FightPetPlaceNum' # 出战灵宠上阵位置,1~n
Def_Obj_Dict_FightPetQuality = 'FightPetQuality' # 出战灵宠品质
#---NPC字典-------
#每道龙卷风最终坐标
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
@@ -725,7 +725,7 @@
                        ("DWORD", "DataMapID", 1),
                        ("WORD", "LineID", 1),
                        ("DWORD", "NPCID", 0),
                        ("DWORD", "SummerNPCID", 0),
                        ("list", "PetNPCIDList", 0),
                        ("list", "AwardItemListFirst", 0),
                        ("list", "AwardItemList", 0),
                        ),
@@ -3709,7 +3709,7 @@
        self.DataMapID = 0
        self.LineID = 0
        self.NPCID = 0
        self.SummerNPCID = 0
        self.PetNPCIDList = []
        self.AwardItemListFirst = []
        self.AwardItemList = []
        return
@@ -3717,7 +3717,7 @@
    def GetDataMapID(self): return self.DataMapID # 数据地图ID
    def GetLineID(self): return self.LineID # 功能线路ID
    def GetNPCID(self): return self.NPCID # NPCID
    def GetSummerNPCID(self): return self.SummerNPCID # 召唤兽ID
    def GetPetNPCIDList(self): return self.PetNPCIDList # 灵宠NPCID列表
    def GetAwardItemListFirst(self): return self.AwardItemListFirst # 首次过关奖励列表[[物品ID,个数,是否拍品], ...]
    def GetAwardItemList(self): return self.AwardItemList # 再次过关奖励列表[[物品ID,个数,是否拍品], ...]
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCAI/AICommon.py
@@ -306,6 +306,11 @@
        return False
    #CD时间
    if curNPC.GetDictByKey(ChConfig.Def_Obj_Dict_TurnFightNum):
        if useSkill.GetRemainTime():
            #GameWorld.Log('技能回合CD中 = %s, %s'%(useSkill.GetSkillName(), useSkill.GetRemainTime()))
            return False
    else:
    if tick - useSkill.GetLastUseTick() < useSkill.GetCoolDownTime():
        #GameWorld.Log('检查CD时间触发失败 = %s'%(useSkill.GetSkillName()))
        return False
@@ -360,11 +365,11 @@
    
    #---对宠物主人释放---
    if skillTag == ChConfig.Def_UseSkillTag_PetMaster:
        if not PetControl.IsPet(curNPC):
        if not PetControl.IsPetNPC(curNPC):
            GameWorld.ErrLog("该NPC非宠物,无法获得主人释放技能")
            return False
        
        petOwner = PetControl.GetPetOwner(curNPC)
        petOwner = PetControl.GetPetNPCOwner(curNPC)
        
        if petOwner == None:
            GameWorld.ErrLog("宠物(%s)对主人释放技能,找不到主人"%curNPC.GetRolePet().PetID)
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py
@@ -2310,7 +2310,7 @@
    #__NotifyMapPlayerSummonMapNPC(npcId, rebornX, rebornY)
    return curSummon
def SummonNPC(gameObj, npcID, rebornX, rebornY):
def SummonNPC(gameObj, npcID, rebornX, rebornY, skillIDList=None):
    ''' 某个实例进行召唤,有从属关系
    '''
    npcData = GameWorld.GetGameData().FindNPCDataByID(npcID)
@@ -2343,6 +2343,13 @@
    curSummon.SetSightLevel(gameObj.GetSightLevel())
    
    curSummon.Reborn(rebornX, rebornY, False)
    #有指定的技能,重新学习
    if skillIDList:
        #GameWorld.DebugLog("指定召唤兽技能: npcID=%s,skillIDList=%s" % (npcID, skillIDList))
        skillManger = curSummon.GetSkillManager()
        skillManger.ResetSkill()
        for skillID in skillIDList:
            skillManger.LVUPSkillByID(skillID)
    NPCControl(curSummon).DoNPCRebornCommLogic(tick)
    #curSummon.RefreshView()
    return curSummon
@@ -3723,7 +3730,7 @@
        #范围校验
        if not posMap:
            GameWorld.ErrLog("__Func_GetRandPosInRefreshArea GetRefreshPosAt error: return None! npcID=%s" % curNPC.GetNPCID())
            return
            return curNPC.GetPosX(), curNPC.GetPosY()
        posMapX = posMap.GetPosX()
        posMapY = posMap.GetPosY()
        
@@ -4115,8 +4122,7 @@
#        curNPC.ForbiddenSkillTypeList_Clear()
    
        #宠物特殊处理
        if curNPC.GetGameNPCObjType() == IPY_GameWorld.gnotPet:
            PetControl.RefurbishPetAttr(curNPC, canSyncClient)
        if PetControl.RefurbishPetAttr(curNPC):
            return
        
        pvpPlayerID = curNPC.GetDictByKey(ChConfig.Def_NPC_Dict_PVPPlayerID)
@@ -4137,7 +4143,7 @@
        return
    
    def SetPVPNPCPlayerAttr(self, pvpPlayerID):
        PropDict = PlayerViewCacheTube.GetPlayerPropData(pvpPlayerID)
        PropDict, PlusDict = PlayerViewCacheTube.GetPlayerPropPlusDictByID(pvpPlayerID)
        if not PropDict:
            return
        curNPC = self.__Instance
@@ -4161,8 +4167,17 @@
        GameObj.SetSuckHPPer(curNPC, PropDict.get("SuckHPPer", 0))
        GameObj.SetSuckHPDefPer(curNPC, PropDict.get("SuckHPDefPer", 0))
        
        GameWorld.DebugLog("SetPVPNPCPlayerAttr: objID=%s,NPCID=%s,pvpPlayerID=%s,maxHP=%s"
                           % (curNPC.GetID(), curNPC.GetNPCID(), pvpPlayerID, GameObj.GetMaxHP(curNPC)))
        skillManager = curNPC.GetSkillManager()
        SkillInfo = PlusDict.get("SkillInfo", {})
        for _, skillLVDict in SkillInfo.items():
            for skillID, _ in skillLVDict.items():
                skillManager.LearnSkillByID(skillID)
        GameWorld.DebugLog("SetPVPNPCPlayerAttr: objID=%s,NPCID=%s,pvpPlayerID=%s,maxHP=%s,SkillInfo=%s"
                           % (curNPC.GetID(), curNPC.GetNPCID(), pvpPlayerID, GameObj.GetMaxHP(curNPC), SkillInfo))
        for index in range(0, skillManager.GetSkillCount()):
            useSkill = skillManager.GetSkillByIndex(index)
            GameWorld.DebugLog("    NPC SkillID=%s" % useSkill.GetSkillID())
        return
    
    def SetHelpBattleRobotRebornAttr(self, fightPower):
@@ -4603,9 +4618,9 @@
            return
        
        #宠物死亡调用独立接口
        if curNPC_GameNPCObjType == IPY_GameWorld.gnotPet:
            PetControl.SetPetDead(curNPC)
            return
        #if curNPC_GameNPCObjType == IPY_GameWorld.gnotPet:
        #    PetControl.SetPetDead(curNPC)
        #    return
        
        #---通用死亡逻辑---
        
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
@@ -344,7 +344,7 @@
    if curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomScene):
        PlayerFB.DoExitCustomScene(curPlayer)
        
    PetControl.DoLogic_PetLoadMapOK(curPlayer)
    #PetControl.DoLogic_PetLoadMapOK(curPlayer)
    
    # 恢复视野,刷新自己的视野
    curPlayer.SetVisible(True)
@@ -566,7 +566,7 @@
        DataRecordPack.DR_PlayerLogin(curPlayer)
        EventReport.WriteEvent_login(curPlayer)
        #---玩家上线, 宠物逻辑处理---
        PetControl.DoLogic_PetInfo_OnLogin(curPlayer, tick)
        #PetControl.DoLogic_PetInfo_OnLogin(curPlayer, tick)
        
        PlayerFamily.FamilyPlayerOnLoginCross(curPlayer)
        
@@ -652,7 +652,7 @@
    PlayerRefineStove.DoOnLogin(curPlayer, tick)
    
    #---玩家上线, 宠物逻辑处理---
    PetControl.DoLogic_PetInfo_OnLogin(curPlayer, tick)
    #PetControl.DoLogic_PetInfo_OnLogin(curPlayer, tick)
    PlayerPet.OnPlayerPetLogin(curPlayer)
    
    #要在SetCanMove之后做这个事情, 否则OnEnter不会卡住玩家
@@ -1483,7 +1483,7 @@
    #===========================================================================
    
    #初始化宠物 通知客户端
    PetControl.Sync_PetInfo_ChangeMap(curPlayer, tick)
    #PetControl.Sync_PetInfo_ChangeMap(curPlayer, tick)
    #通知GameServer自己现在的地图
    curPlayer.Sync_GameServer_MapID()
@@ -1742,7 +1742,7 @@
    EventShell.EventResponse_OnMapEx(curPlayer)
    
    #触发切换地图宠物逻辑
    PetControl.DoLogic_PetLoadMapOK(curPlayer)
    #PetControl.DoLogic_PetLoadMapOK(curPlayer)
    #---检查是否卡障碍---
    curMap = GameWorld.GetMap()
@@ -2249,7 +2249,7 @@
        return
    #出战宠物同时移动
    PetControl.FightPetFollowMove(curPlayer, sendPack_StartX, sendPack_StartY)
    #PetControl.FightPetFollowMove(curPlayer, sendPack_StartX, sendPack_StartY)
    
    
    return
@@ -4510,7 +4510,7 @@
        #直接取db中配置的复活点
        PlayerControl.PlayerResetWorldPos(curPlayer, gameMap.GetRebornMapID(), gameMap.GetRebornMapX(), gameMap.GetRebornMapY(), False)
    #重新召唤宠物
    PlayerPet.AutoSummonPet(curPlayer)
    #PlayerPet.AutoSummonPet(curPlayer)
    
    #复活成功,重置状态
    PlayerControl.ChangePlayerAction(curPlayer, IPY_GameWorld.paNull)
@@ -6160,7 +6160,7 @@
        #出战宠物同时移动
        if moveType == 0 or tick - fightPet.GetActionTick() > 300:
    
            PetControl.FightPetFollowMove(curPlayer,sendPack_SeverPosX, sendPack_SeverPosY)
            #PetControl.FightPetFollowMove(curPlayer,sendPack_SeverPosX, sendPack_SeverPosY)
            fightPet.SetCurAction(IPY_GameWorld.laNPCNull)
            
    return True
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PetControl.py
@@ -22,150 +22,17 @@
#IPY_RolePetMgr.PetList_Find\GetFightPet\PetList_At -> IPY_RolePet;
#IPY_RolePet.GetRolePet -> tagIPY_RolePet(结构体); 
#IPY_RolePet.GetPetData -> IPY_Pet;
#
#
#---------------------------------------------------------------------
import IPY_GameWorld
import ChConfig
import GameWorld
import BuffSkill
import SkillShell
import PlayerPet
import PlayerControl
import NPCCommon
import SkillCommon
import GameMap
import OperControlManager
import ShareDefine
import random
import copy
import math
import GameObj
import AICommon
import BaseAttack
import PassiveBuffEffMng
import ChNetSendPack
import IpyGameDataPY
#---------------------------------------------------------------------
DefPetRebornHPRate = 100  # 宠物死亡复活血量百分比
#---------------------------------------------------------------------
## 检查宠物是否出战中
#  @param curPlayer 玩家对象
#  @param curPetID 宠物ID
#  @return True or False 是否出战中
#  @remarks 检查宠物是否出战中
def CheckPetIsFight(curPlayer, curPetID):
    petMgr = curPlayer.GetPetMgr()
    #出战的宠物对象
    fightPetObj = petMgr.GetFightPet()
    if fightPetObj == None:
        return False
    if fightPetObj.GetRolePet().PetID == curPetID:
        return True
    return False
# 宠物跟随人物同时攻击
def PetFight(curPlayer, tick):
    rolePet = curPlayer.GetPetMgr().GetFightPet()
    #无出战宠物
    if rolePet == None:
        return
    rolePetControl = NPCCommon.NPCControl(rolePet)
    useSkillTagID = curPlayer.GetUseSkillTagID()
    useSkillTagType = curPlayer.GetUseSkillTagType()
    curTag = GameWorld.GetObj(useSkillTagID, useSkillTagType)
    if not curTag or GameObj.GetHP(curTag) <= 0:
        # 没有主目标就从仇恨中找
        for i in range(curPlayer.GetAngryNPCCount()):
            curTag = curPlayer.GetAngryNPCByIndex(i)
            if not curTag or GameObj.GetHP(curTag) <= 0:
                continue
    if not curTag or GameObj.GetHP(curTag) <= 0:
        return
    #tagDist = GameWorld.GetDist(rolePet.GetPosX(), rolePet.GetPosY(), curTag.GetPosX(), curTag.GetPosY())
    tagDist = 0
    #---优先释放技能---
    if AICommon.DoAutoUseSkill(rolePet, curTag, tagDist, tick):
        return
    #---释放普通攻击--- 边走边攻击纠正一次位置
    #if tagDist > rolePet.GetAtkDist():
    #    rolePetControl.MoveToObj_Detel(curTag)
    #普通攻击
    BaseAttack.Attack(rolePet, curTag, None, tick)
    return
#---------------------------------------------------------------------
##出战宠物跟随移动
# @param curPlayer 玩家实例
# @param destPosX 移动目标X点
# @param destPosY 移动目标Y点
# @return 返回值无意义
# @remarks 出战宠物跟随移动
def FightPetFollowMove(curPlayer, destPosX, destPosY):
    #主人在战斗中, 宠物不跟随移动
    fightPet = curPlayer.GetPetMgr().GetFightPet()
    #无出战宠物
    if fightPet == None:
        return
    petControl = NPCCommon.NPCControl(fightPet)
    movePosX, movePosY = petControl.GetMoveNearPos(destPosX, destPosY, 2)
    # 执行一次重置位置,避免快速发包导致无法移动
    fightPet.ChangePos(movePosX, movePosY)
    #movePosX, movePosY = petControl.GetMoveNearPos(destPosX, destPosY, 1)
    PetMove(fightPet, movePosX, movePosY)
    return
def PetMove(fightPet, posX, posY):
    sendPack = ChNetSendPack.tagObjMove()
    sendPack.Clear()
    sendPack.ObjID = fightPet.GetID()
    sendPack.ObjType = IPY_GameWorld.gotNPC
    sendPack.MoveType = IPY_GameWorld.mtNormal
    sendPack.DestPosX = posX
    sendPack.DestPosY = posY
    sendPack.Speed = fightPet.GetSpeed()
    sendPack.StartPosX = fightPet.GetPosX()
    sendPack.StartPosY = fightPet.GetPosY()
    fightPet.NotifyAll(sendPack.GetBuffer(), sendPack.GetLength())
    return
#---------------------------------------------------------------------
##清除出战宠物仇恨.
# @param curPlayer 玩家实例
# @return 返回值无意义
# @remarks 清除出战宠物仇恨
def ClearFightPetAngry(curPlayer):
    fightPet = curPlayer.GetPetMgr().GetFightPet()
    #无出战宠物
    if fightPet == None:
        return
    petControl = NPCCommon.NPCControl(fightPet)
    petControl.ClearNPCAngry()
    return
import ChConfig
#---------------------------------------------------------------------
##获得宠物的拥有者
@@ -206,6 +73,44 @@
    
    return False
#---------------------------------------------------------------------    
def IsPetNPC(curObj):
    ''' 是否灵宠NPC,召唤兽类型,玩家、玩家镜像、NPC通用,均可有灵宠召唤兽
            区别于 IsPet 为旧版的 PY_GameWorld.gnotPet 实例对象,仅玩家实例有
    '''
    curObjType = curObj.GetGameObjType()
    if curObjType != IPY_GameWorld.gotNPC:
        return False
    npcObjType = curObj.GetGameNPCObjType()
    if npcObjType != IPY_GameWorld.gnotSummon:
        return False
    return curObj.GetType() == IPY_GameWorld.ntPet
def GetPetNPCOwner(curPet):
    ''' 获得宠物的拥有者,可能为玩家、玩家镜像、NPC
        区别于 GetPetOwner 为旧版的 PY_GameWorld.gnotPet 归属者仅支持玩家
    '''
    if curPet == None:
        return
    atkObjType = curPet.GetGameObjType()
    if atkObjType != IPY_GameWorld.gotNPC:
        return
    summonOwner = None
    npcObjType = curPet.GetGameNPCObjType()
    # 判断召唤兽主人
    if npcObjType == IPY_GameWorld.gnotSummon:
        curNPCDetail = GameWorld.GetObjDetail(curPet)
        if curNPCDetail:
            curNPCOwner = curNPCDetail.GetOwner()
            if curNPCOwner:
                summonOwner = GameWorld.GetObjDetail(curNPCOwner)
                # 召唤兽主人为玩家
                #if summonOwner and summonOwner.GetGameObjType() == IPY_GameWorld.gotPlayer:
                #    return summonOwner, npcObjType
    return summonOwner
##清空宠物身上所有buff
# @param curPet 宠物对象
# @return None
@@ -217,225 +122,92 @@
        buffState.Clear()
    
    return
#---------------------------------------------------------------------    
##召唤宠物
# @param curPet 宠物对象
# @param curPosX 宠物出身点位置
# @param curPosY 宠物出身点位置
# @return None
# @remarks 召唤宠物,初始化宠物所有属性(C++处理)
def SummonPet(curPet, curPosX, curPosY):
    #出现(出战逻辑在C++, 将清空宠物的相关信息)
    curPet.Summon(curPosX, curPosY)
    #记录该宠物被召回
    curPet.SetIsBattle(True)
    #初始化宠物
    InitRolePet(curPet)
    PassiveBuffEffMng.GetPassiveEffManager().RegistPassiveEff(curPet)
    return
#---------------------------------------------------------------------
##初始化宠物属性
# @param rolePet 宠物实例
# @param canSyncClient 是否通知客户端
# @return 返回值无意义
# @remarks 初始化宠物属性
def InitRolePet(rolePet, canSyncClient=True):
    #---初始化时钟---
    NPCCommon.InitNPC(rolePet)
def CalloutFightPet(curObj, petCacheInfo=None):
    ## 出战上阵的灵宠
    # @param petCacheInfo: 玩家灵宠功能缓存信息
    # @return: [第1位置实例, 第2, ...]  按位置顺序,实例可能为None
    
    #---初始化仇恨列表---
    npcAngry = rolePet.GetNPCAngry()
    if npcAngry.GetAngryCount() == 0:
        npcAngry.Init(ChConfig.Def_Pet_Angry_Count)
    else:
        npcAngry.Clear()
    fightPlaceCount = len(IpyGameDataPY.GetFuncEvalCfg("PetGoOutFight", 1)) # 战斗位置数
    fightPetObjList = [None] * fightPlaceCount
    if petCacheInfo == None and curObj.GetGameObjType() == IPY_GameWorld.gotPlayer:
        petCacheInfo = PlayerPet.GetPetCacheInfo(curObj)
    if not petCacheInfo: # 没有灵宠
        return fightPetObjList
    #---初始化宠物属性---
    petControl = NPCCommon.NPCControl(rolePet)
    petControl.RefreshNPCState(canSyncClient)
    fightPetDict = {} # 上阵的灵宠
    for cacheInfo in petCacheInfo:
        state = cacheInfo.get("state", 0)
        if not state:
            continue
        fightPetDict[state] = cacheInfo
    #加一个防御措施, 如果宠物血为0, 不可召唤出来, 默认为宠物召回时候的血量
    if GameObj.GetHP(rolePet) <= 0:
        PetDead_ReStoreHP(rolePet, GameObj.GetMaxHP(rolePet))
        GameWorld.ErrLog('宠物重生血量为0, PetID = %s' % (rolePet.GetRolePet().PetID))
    if not fightPetDict: # 没有上阵的
        return fightPetObjList
    return
#---------------------------------------------------------------------
    posX, posY = curObj.GetPosX(), curObj.GetPosY()
    for index in range(fightPlaceCount):
        placeNum = index + 1
        if placeNum not in fightPetDict:
            continue
        petInfo = fightPetDict[placeNum]
        petNPCID = petInfo.get("npcID", 0)
        if not petNPCID:
            continue
        quality = petInfo.get("quality", 0)
        skillIDList = petInfo.get("skills", [])
        petObj = NPCCommon.SummonNPC(curObj, petNPCID, posX, posY, skillIDList)
        if not petObj:
            continue
        petObj.SetDict(ChConfig.Def_Obj_Dict_FightPetPlaceNum, placeNum)
        petObj.SetDict(ChConfig.Def_Obj_Dict_FightPetQuality, quality)
        fightPetObjList[index] = petObj
    return fightPetObjList
##召回出战的宠物
# @param curPlayer 玩家实例
# @return 布尔值
# @remarks 召回出战的宠物
def ReCallFightPet(curPlayer):
    rolePetMgr = curPlayer.GetPetMgr()
    #获得战斗的宠物
    fightPet = rolePetMgr.GetFightPet()
    if fightPet == None:
        return False
    #清空宠物身上附加的buff
    ClearPetBuff(fightPet)
    #记录该宠物被召回
    fightPet.SetIsBattle(False)
    #此死亡接口(C++将重置所有战斗属性, 要在刷一次)
    NPCCommon.SetDeadEx(fightPet)
    #刷新宠物属性
    petControl = NPCCommon.NPCControl(fightPet)
    petControl.RefreshNPCState(canSyncClient=True)
    #宠物数据物品状态变更
    petItemIndex = PlayerPet.GetPetObjItemIndex(fightPet)
    petItem = PlayerPet.GetPetDataItemByIndex(curPlayer, petItemIndex)
    if petItem:
        petItem.SetUserAttr(ShareDefine.Def_IudetPet_State, ShareDefine.Def_PetState_Null)
    petID = fightPet.GetRolePet().PetID
    npcID = fightPet.GetRolePet().NPCID
    rolePetMgr.PetList_SetFree(petID) # 永恒召回后默认放生, 最多只存在一个出战宠物实例
    GameWorld.DebugLog("随从召回后默认放生, petID=%s, npcID=%s" % (petID, npcID))
    return True
#---------------------------------------------------------------------
## 设置宠物死亡
#  @param curPet 宠物对象
#  @return None
#  @remarks 设置宠物死亡
def SetPetDead(curPet):
    #---执行死亡惩罚逻辑---
    
    #宠物主人
    curPetOwner = GetPetOwner(curPet)
    if not curPetOwner:
        return
    ReCallFightPet(curPetOwner)
    return
#---------------------------------------------------------------------
##宠物死亡恢复血量
# @param index 玩家索引
# @param tick 时间戳
# @return 返回值无意义
# @remarks 宠物死亡恢复血量
def PetDead_ReStoreHP(curPet, maxHP):
    #设置宠物当前血量为其上限的30%
    SetPetHP(curPet, int(maxHP * DefPetRebornHPRate / 100))
    return
#---------------------------------------------------------------------
#---------------------------------------------------------------------
##设置宠物HP
# @param rolePet 玩家宠物
# @param ֵ
# @param canSyncClient是否通知客户端
# @return 返回值无意义
# @remarks 设置宠物HP
def SetPetHP(rolePet, value, canSyncClient=True):
    ##设置宠物HP
    GameObj.SetHP(rolePet, value, canSyncClient)
    if not canSyncClient:
        return
    #rolePet.Sync_RefreshProp(IPY_GameWorld.PetInfoRefresh_HP, value, True)
    return
#---------------------------------------------------------------------
##增加宠物HP
# @param rolePet 玩家宠物
# @param ֵ
# @return 返回值无意义
# @remarks 加宠物HP
def AddPetHP(rolePet, value):
    remainValue = min(GameObj.GetHP(rolePet) + value, GameObj.GetMaxHP(rolePet))
    SetPetHP(rolePet, remainValue)
    ##增加宠物HP
    #remainValue = min(GameObj.GetHP(rolePet) + value, GameObj.GetMaxHP(rolePet))
    #SetPetHP(rolePet, remainValue)
    return
#---------------------------------------------------------------------
##刷新宠物的属性
# @param rolePet 玩家宠物
# @param canSyncClient 是否通知客户端(默认为True)
# @return 返回值无意义
# @remarks 刷新宠物的属性
def RefurbishPetAttr(rolePet, canSyncClient=True):
    curPlayer = GetPetOwner(rolePet)
    if not curPlayer:
def RefurbishPetAttr(curPet):
    ##刷新宠物的属性,仅支持召唤兽,废弃原 IPY_GameWorld.gnotPet
    if not IsPetNPC(curPet):
        return
    petOwner = GetPetNPCOwner(curPet)
    if not petOwner:
        return
    
    petDataItem = PlayerPet.GetPetDataItem(curPlayer, rolePet)
    if not petDataItem:
    #宠物不可被攻击, 灵宠继承人物的 百分百攻击和攻速
    curPet.SetMinAtk(petOwner.GetMinAtk())
    curPet.SetMaxAtk(petOwner.GetMaxAtk())
    GameObj.SetAtkSpeed(curPet, GameObj.GetAtkSpeed(petOwner))
    #allAttrList = [{} for i in range(4)]
    ##计算技能对战斗属性的影响
    #PlayerPet.CalcSkill_PetBattleEffect(curPlayer, rolePet, allAttrList)
    ##计算Buff对战斗属性的影响
    #PlayerPet.CalcBuffer_PetBattleEffect(rolePet, allAttrList)
    GameWorld.DebugLog("RefurbishPetAttr ID=%s,npcID=%s,maxAtk=%s,atkSpeed=%s"
                       % (curPet.GetID(), curPet.GetNPCID(), curPet.GetMaxAtk(), curPet.GetMaxAtk()))
        return
    # 变更需要同步的信息配置, 客户端取宠物信息全部以宠物物品数据为准
    syncList = [
                [lambda petObj:petObj.GetMaxAtk(), IPY_GameWorld.PetInfoRefresh_PhysicAtk], #攻击
                #[lambda petObj:petObj.GetQualityLV(), IPY_GameWorld.PetInfoRefresh_QualityLV], #品质
                ]
    beforeValueList = []
    for syncInfo in syncList:
        beforeValueList.append(syncInfo[0](rolePet))
    #添加Buff到宠物身上
    #AddPlayerPetSkillBuff(rolePet)
    #计算Buff对基础属性的影响
    #SkillShell.CalcBuffer_NPCBaseEffect(rolePet)
    #宠物不可被攻击, 命中与攻速直接继承主人攻击属性,攻击取等级阶级加成
    rolePet.SetMinAtk(PlayerControl.GetPetMinAtk(curPlayer))
    rolePet.SetMaxAtk(PlayerControl.GetPetMaxAtk(curPlayer))
    rolePet.SetSkillAtkRate(PlayerControl.GetPetSkillAtkRate(curPlayer))
    GameObj.SetPetDamPer(rolePet, GameObj.GetPetDamPer(curPlayer))
    #rolePet.SetMAtkMin(curPlayer.GetMAtkMin())
    #rolePet.SetMAtkMax(curPlayer.GetMAtkMax())
    rolePet.SetHit(curPlayer.GetHit())
    rolePet.SetSpeed(curPlayer.GetSpeed())
    allAttrList = [{} for i in range(4)]
    #计算技能对战斗属性的影响
    PlayerPet.CalcSkill_PetBattleEffect(curPlayer, rolePet, allAttrList)
    #计算Buff对战斗属性的影响
    PlayerPet.CalcBuffer_PetBattleEffect(rolePet, allAttrList)
    GameWorld.DebugLog("RefurbishPetAttr ID=%s,npcID=%s,atk=%s,hit=%s,skillAtkRate=%s"
                       % (rolePet.GetID(), rolePet.GetNPCID(), rolePet.GetMaxAtk(), rolePet.GetHit(), rolePet.GetSkillAtkRate()))
    #是否需要通知客户端属性刷新
    if not canSyncClient:
        return
    #===========================================================================
    # for i, syncInfo in enumerate(syncList):
    #    nowValue = syncInfo[0](rolePet)
    #    if beforeValueList[i] != nowValue:
    #        rolePet.Sync_RefreshProp(syncInfo[1], nowValue, True)
    #        #GameWorld.DebugLog("Sync_RefreshProp i=%s,befValue=%s,nowValue=%s,type=%s" % (i, beforeValueList[i], nowValue, syncInfo[1]))
    #===========================================================================
    return
#---------------------------------------------------------------------
##添加宠物技能Buff
# @param rolePet 宠物实例
# @return 返回值无意义
# @remarks 添加宠物技能Buff
#===============================================================================
# def AddPlayerPetSkillBuff(rolePet):
#    tick = GameWorld.GetGameWorld().GetTick()
#
#    #---先清掉---
#    passiveBuffManager = rolePet.GetPassiveBuf()
#    passiveBuffManager.Clear()
#
#    #---在加上---
#    rolePetSkillManager = rolePet.GetSkillManager()
#
#    for i in range(0, rolePetSkillManager.GetSkillCount()):
#        learnSkill = rolePetSkillManager.GetSkillByIndex(i)
#        #只添加被动技能
#        if not SkillCommon.isPassiveBuffSkill(learnSkill):
#            continue
#
#        #加上buff不刷新状态
#        BuffSkill.AddBuffNoRefreshState(rolePet, IPY_GameWorld.btPassiveBuf, learnSkill, tick)
#
#    return
#===============================================================================
#---------------------------------------------------------------------
def DoLogic_PlayerPetLearnSkillList(rolePet, learnSkillList):
    #GameWorld.DebugLog("DoLogic_PlayerPetLearnSkillList----%s"%learnSkillList)
@@ -454,144 +226,6 @@
    #rolePet.Sync_SkillList()     
    return
#---------------------------------------------------------------------
##检查当前指定宠物是否可出战
# @param curPlayer 玩家实例
# @param curPetObj 指定宠物实例
# @return BOOL 是否可出战
# @remarks 检查当前指定宠物是否可出战
def CheckPetCanFight(curPlayer, curPetObj):
    if not GetMapCanOutPet(curPlayer):
        #Pet_liubo_314885 此地图禁止宠物
        #PlayerControl.NotifyCode(curPlayer, "Pet_liubo_314885")
        return False
    petData = curPetObj.GetPetData()
    #防沉迷
    if curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_Wallow_LV) > ChConfig.Def_GameWallow_LV_First:
        PlayerControl.NotifyCode(curPlayer, "AvoidSink09")
        return False
    if GameObj.GetHP(curPlayer) <= 0:
        #死亡状态无法出战宠物
        return False
#    if curPlayer.GetLV() < petData.GetBringLV():
#        #Pet_hgg_442426 对不起,您尚未到达该宠物的携带等级.
#        PlayerControl.NotifyCode(curPlayer, "Pet_hgg_442426")
#        return False
#
#    if curPetObj.GetLV() - curPlayer.GetLV() > ChConfig.Def_PetRoleGapLVMax:
#        #Pet_liubo_570355 对不起,您不能出战超过人物5级的宠物!
#        PlayerControl.NotifyCode(curPlayer, "Pet_liubo_570355", [ChConfig.Def_PetRoleGapLVMax])
#        return False
    #---是否已有宠物出战---
    #fightPetObj = curPlayer.GetPetMgr().GetFightPet()  # 出战的宠物对象
    #if fightPetObj != None:
    #    #Pet_hgg_892377 对不起,您只能同时出战一只宠物,请先召回出战的宠物!
    #    PlayerControl.NotifyCode(curPlayer, "Pet_hgg_892377")
    #    return False
    #GameWorld.Log('宠物血量:%s,宠物ID:%s'%(curPetStruct.HP,curPetStruct.PetID))
    return True
#---------------------------------------------------------------------
#---------------------------------------------------------------------
##玩家离开服务器通知宠物信息
# @param curPlayer 玩家实例
# @param tick 时间戳
# @return 返回值无意义
# @remarks 玩家离开服务器通知宠物信息
def DoLogic_PetInfo_OnLeaveServer(curPlayer, tick):
    return
#---------------------------------------------------------------------
##玩家登陆通知宠物信息
# @param curPlayer 玩家实例
# @param tick 时间戳
# @return 返回值无意义
# @remarks 玩家登陆通知宠物信息
def DoLogic_PetInfo_OnLogin(curPlayer, tick):
    petMgr = curPlayer.GetPetMgr()
    if GameWorld.IsCrossServer():
        ''' 0435宠物出现包同步的ID是根据宠物的列表位置来的,比如在第2位发的就是2,而地图的可能是1,会导致ID不一致
                            所以跨服服务器登录时先清除出战宠物列表,确保登录地图成功后都是从1开始的即可
        '''
        petList = []
        for index in range(0, petMgr.PetList_Cnt()):
            rolePet = petMgr.PetList_At(index)
            petList.append(rolePet)
        for rolePet in petList:
            petMgr.PetList_SetFree(rolePet.GetRolePet().PetID)
    else:
        for index in range(0, petMgr.PetList_Cnt()):
            rolePet = petMgr.PetList_At(index)
            #刷新宠物信息并通知客户端
            __RefreshAndSyncPetInfo(rolePet)
            #自动出战宠物
            __AutoSummonPet_OnLogin(curPlayer, rolePet)
    return
#---------------------------------------------------------------------
##玩家上线, 自动出战宠物
# @param curPlayer 玩家实例
# @param tick 时间戳
# @return 返回值无意义
# @remarks 玩家上线, 自动出战宠物
def __AutoSummonPet_OnLogin(curPlayer, rolePet):
    #是否有出战标志
    if not rolePet.GetIsBattle():
        return
    if not GetMapCanOutPet(curPlayer):
        #此地图禁止宠物
        return
    #召唤宠物出战
    resultPos = GameMap.GetEmptyPlaceInArea(curPlayer.GetPosX(), curPlayer.GetPosY(), ChConfig.Def_SummonAppearDist)
    SummonPet(rolePet, resultPos.GetPosX(), resultPos.GetPosY())
    return
#---------------------------------------------------------------------
##玩家切换地图通知宠物信息.
# @param curPlayer 玩家实例
# @param tick 时间戳
# @return 返回值无意义
# @remarks 玩家切换地图通知宠物信息.
def Sync_PetInfo_ChangeMap(curPlayer, tick):
    petMgr = curPlayer.GetPetMgr()
    for index in range(0, petMgr.PetList_Cnt()):
        rolePet = petMgr.PetList_At(index)
        #刷新宠物信息并通知客户端
        __RefreshAndSyncPetInfo(rolePet)
    return
#---------------------------------------------------------------------
##玩家携带宠物登陆地图
# @param curPlayer 玩家实例
# @return 返回值无意义
# @remarks
def DoLogic_PetLoadMapOK(curPlayer):
    if GetMapCanOutPet(curPlayer):
        #此地图宠物可以上
        PlayerPet.AutoSummonPet(curPlayer)
        return
    #此地图禁止宠物, 召回出战的宠物
    if not ReCallFightPet(curPlayer):
        return
    #Pet_liubo_314885 此地图禁止宠物
    #PlayerControl.NotifyCode(curPlayer, "Pet_liubo_314885")
    return
def GetMapCanOutPet(curPlayer):
    ## 检查本地图可否出战宠物,支持前端自定义场景
    customMapID = PlayerControl.GetCustomMapID(curPlayer)
@@ -601,18 +235,4 @@
    else:
        canOutPet = GameWorld.GetMap().GetMapCanOutPet()
    return canOutPet
#---------------------------------------------------------------------
## 刷新宠物信息并通知客户端
#  @param rolePet 宠物实例
#  @return 无返回值
#  @remarks 刷新宠物信息并通知客户端
def __RefreshAndSyncPetInfo(rolePet):
    #---刷新宠物信息(不通知客户端)---
    InitRolePet(rolePet, False)
    return
#---------------------------------------------------------------------
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
@@ -1431,7 +1431,7 @@
# @remarks 玩家离开服务器
def PlayerLeaveServer(curPlayer, tick):
    #宠物下线逻辑, 这里要进行排行榜, 优先做, 避免玩家光环等属性影响宠物属性失效
    PetControl.DoLogic_PetInfo_OnLeaveServer(curPlayer, tick)
    #PetControl.DoLogic_PetInfo_OnLeaveServer(curPlayer, tick)
    
    #清除下线消失的buff, 在更新排行榜之前
    __DisconnectClearBuff(curPlayer, tick)
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerFB.py
@@ -514,7 +514,7 @@
    NPCCommon.ClearPriWoodPile(curPlayer)
    GameWorld.Log("玩家开始自定义场景!mapID=%s,lineID=%s" % (mapID, lineID), playerID)
    if mapID:
        PetControl.DoLogic_PetLoadMapOK(curPlayer)
        #PetControl.DoLogic_PetLoadMapOK(curPlayer)
        FBLogic.OnEnterCustomScene(curPlayer, mapID, lineID)
        
    #默认回满血
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerPet.py
@@ -34,57 +34,36 @@
import GameWorld
import IpyGameDataPY
import PlayerAttrFruit
import GameMap
import OpenServerCampaign
import PlayerMagicWeapon
import PlayerWeekParty
import CalcNoLineEffect
import PassiveBuffEffMng
import CrossPlayerData
import CalcLineEffect
import PlayerActivity
import ChPyNetSendPack
import NetPackCommon
import PlayerHorse
import GameObj
import random
import math
#---------------------------------------------------------------------
def DoLogic_PetInfo_OnDay(curPlayer):
    return
#---------------------------------------------------------------------
## 宠物功能开启
#  @return: 是否激活成功
def OnPlayerPetLogin(curPlayer):
    ## 登录处理
    if not GameFuncComm.GetFuncCanUse(curPlayer, ShareDefine.GameFuncID_Pet):
        return
    # 培养是后面加的功能,每次登录补检查一下功能开始时设置为培养1级
    for trainType in xrange(1, GetPetTrainTypes() + 1):
        if curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_PetTrainLV % trainType) == 0:
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_PetTrainLV % trainType, 1)
    Sync_PetTrainData(curPlayer)
    return
def DoPetOpen(curPlayer):
    GameWorld.DebugLog("DoPetOpen...", curPlayer.GetPlayerID())
#    firstPetData = ReadChConfig.GetEvalChConfig("FirstPet")
#    petNPCID = firstPetData[0]
#    isAutoFight = firstPetData[1]
#    if petNPCID <= 0:
#        return
#
#    # 如果已经有该宠物, 不再给
#    if GetPetDataItemIndexByNPCID(curPlayer, petNPCID) < 0:
#        newPetItem = GetNewPetDataItem(curPlayer, petNPCID)
#        if not newPetItem:
#            return
#
#        if not ItemControler.PlayerItemControler(curPlayer).PutInItem(ShareDefine.rptPet, newPetItem):
#            return
#
#        petData = newPetItem.GetUserData()
#        DataRecordPack.DR_UsePetEgg(curPlayer, 0, petNPCID, petData)
#
#    if isAutoFight and not curPlayer.GetPetMgr().GetFightPet():
#        petItemIndex = GetPetDataItemIndexByNPCID(curPlayer, petNPCID)
#        GameWorld.DebugLog("自动出战新手宠!petNPCID=%s,petItemIndex=%s" % (petNPCID, petItemIndex))
#        DoChangePetState(curPlayer, petItemIndex, ShareDefine.Def_PetState_Fight)
    
    for trainType in xrange(1, GetPetTrainTypes() + 1):
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_PetTrainLV % trainType, 1)
@@ -116,62 +95,28 @@
        return
    
    newPetItem.SetUserAttr(ShareDefine.Def_IudetPet_NPCID, petNPCID)
    newPetItem.SetUserAttr(ShareDefine.Def_IudetPet_State, ShareDefine.Def_PetState_Null)
    newPetItem.SetUserAttr(ShareDefine.Def_IudetPet_State, 0)
    
    initClass = petIpyData.GetInitRank() if classlv == -1 else classlv#初始阶级
    newPetItem.SetUserAttr(ShareDefine.Def_IudetPet_ClassLV, max(0, initClass - 1)) #代码里从0开始
    newPetItem.SetUserAttr(ShareDefine.Def_IudetPet_QualityLV, petIpyData.GetQuality()) # 宠物品质
    
    petSkillList = petIpyData.GetSkillID()
    petSkillUnLockList = petIpyData.GetSkillUnLock()
    for i, skillid in enumerate(petSkillList):
        limitPetClassLV = petSkillUnLockList[i] # 学习此技能所需宠物阶级
        if initClass < limitPetClassLV:
            continue
        curSkilData = GameWorld.GetGameData().GetSkillBySkillID(skillid)
        if not curSkilData:
            continue
        if curSkilData.GetFuncType() == ChConfig.Def_SkillFuncType_PetOwnerSkill:
            __GiveOwnerSkill(curPlayer, skillid)
            continue
        newPetItem.AddUserAttr(ShareDefine.Def_IudetPet_Skill, skillid)
    __UpdPetItemSkillByClass(curPlayer, newPetItem, False)
    return newPetItem
# 从称号获得技能
def __GiveOwnerSkill(curPlayer, skillResID):
    GameWorld.DebugLog("给灵宠主人技能: skillResID=%s" % skillResID)
    skillData = GameWorld.GetGameData().FindSkillByType(skillResID, 1)
    if skillData == None:
        GameWorld.DebugLog("    not find skill(%s)" % skillResID)
        return
    if not SkillCommon.CheckSkillJob(curPlayer, skillData):
        return
    if not SkillShell.CheckLearnSkillCondition(curPlayer, skillData):
        GameWorld.DebugLog("    learn skill condition isn't enough! skillResID=%s" % skillResID)
        return
    skillManager = curPlayer.GetSkillManager()
    if skillManager.FindSkillBySkillTypeID(skillResID):
        GameWorld.DebugLog("    have learned skill(%s)" % skillResID)
        return
    skillManager.LVUpSkillBySkillTypeID(skillResID)
    PassiveBuffEffMng.GetPassiveEffManager().RegistPassiveEff(curPlayer, skillResID)
    PlayerControl.PlayerControl(curPlayer).RefreshSkillFightPowerEx(skillResID, 0)
    return
## 获取宠物实例对应的宠物数据物品
def GetPetDataItem(curPetOwner, rolePet):
    if not curPetOwner:
        return
    packItemIndex = GetPetObjItemIndex(rolePet)
    packItemIndex = GetPetDataItemByNPCID(curPetOwner, rolePet.GetNPCID())
    return GetPetDataItemByIndex(curPetOwner, packItemIndex)
## 获取宠物数据物品
def GetPetDataItemByIndex(curPlayer, petItemIndex):
    
    petDataPack = curPlayer.GetItemManager().GetPack(ShareDefine.rptPet)
    if petItemIndex < 0 or petItemIndex >= petDataPack.GetCount():
        return
    petDataItem = petDataPack.GetAt(petItemIndex)
    if not ItemCommon.CheckItemCanUse(petDataItem):
        GameWorld.DebugLog("PetDataItem is none! PetItemIndex=%s" % petItemIndex, curPlayer.GetPlayerID())
@@ -190,10 +135,6 @@
            return petItem
    return
## 永恒暂用友好度来存储该宠物所属的宠物背包物品索引
def GetPetObjItemIndex(rolePet): return rolePet.GetRolePet().Friendliness
def SetPetObjItemIndex(petStruct, petItemIndex): petStruct.Friendliness = petItemIndex
## 根据宠物NPCID获取宠物数据物品在背包中的索引
def GetPetDataItemIndexByNPCID(curPlayer, petNPCID):
    petDataPack = curPlayer.GetItemManager().GetPack(ShareDefine.rptPet)
@@ -206,8 +147,33 @@
        
    return -1
#===================================================================================================
# //////////////////////////////////////////////////////////////
def GetPetItemCacheDict(petItem):
    ## 单个灵宠物品缓存信息
    npcID = petItem.GetUserAttr(ShareDefine.Def_IudetPet_NPCID)
    state = petItem.GetUserAttr(ShareDefine.Def_IudetPet_State)
    classLV = petItem.GetUserAttr(ShareDefine.Def_IudetPet_ClassLV)
    quality = petItem.GetUserAttr(ShareDefine.Def_IudetPet_QualityLV)
    star = petItem.GetUserAttr(ShareDefine.Def_IudetPet_Star)
    skills = [petItem.GetUserAttrByIndex(ShareDefine.Def_IudetPet_Skill, i) for i in xrange(petItem.GetUserAttrCount(ShareDefine.Def_IudetPet_Skill))]
    cacheDict = {"npcID":npcID}
    state and cacheDict.update({"state":state})
    classLV and cacheDict.update({"classLV":classLV})
    quality and cacheDict.update({"quality":quality})
    star and cacheDict.update({"star":star})
    skills and cacheDict.update({"skills":skills})
    return cacheDict
def GetPetCacheInfo(curPlayer):
    ## 获取灵宠功能缓存信息,暂时缓存全部,如果有需要改为仅缓存上阵的
    itemCacheList = []
    petDataPack = curPlayer.GetItemManager().GetPack(ShareDefine.rptPet)
    for petDataIndex in range(petDataPack.GetCount()):
        petItem = petDataPack.GetAt(petDataIndex)
        if petItem.IsEmpty():
            continue
        itemCacheList.append(GetPetItemCacheDict(petItem))
    return itemCacheList
# //16 03 宠物出战/召回#tagCPetStateChange
# tagCPetStateChange       *   GettagCPetStateChange();
@@ -219,203 +185,77 @@
#    // 状态.0-召回;1-出战;2xx-守护(守护+目标守护位)
#    int      GetState(); 0~255
# };
#===================================================================================================
##客户端封包响应
#@param index 玩家索引
#@param tick 时间戳
#@return 返回值无意义
#@remarks 客户端封包响应 //16 03 宠物出战/召回#tagCPetStateChange
def PetStateChange(index, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    pack = IPY_GameWorld.IPY_CPetStateChange()
    petItemIndex = pack.GetPetID()
    state = pack.GetState()
    #时间间隔未到,不处理(2010-06-23 16:20 策划刘鸿生说无须系统提示)
    if tick - curPlayer.GetTickByType(ChConfig.TYPE_Player_Tick_ChangePetState) \
       < ChConfig.TYPE_Player_Tick_Time[ChConfig.TYPE_Player_Tick_ChangePetState]:
        #没有到刷新间隔
        return
    curPlayer.SetTickByType(ChConfig.TYPE_Player_Tick_ChangePetState, tick)
    DoChangePetState(curPlayer, petItemIndex, state)
    return
## 宠物战斗状态变更; 0-收回;1-出战  (手游版本只能出战)
def DoChangePetState(curPlayer, petItemIndex, tagState, isRefresh=True):
    if petItemIndex < 0:
        return
    if tagState not in ShareDefine.Def_PetStateList:
        return
def DoChangePetState(curPlayer, petItemIndex, tagState):
    # @param tagState: 0-收回;>=1-出战在第几个位置
        
    petItem = GetPetDataItemByIndex(curPlayer, petItemIndex)
    if not petItem:
        return
    
    playerID = curPlayer.GetPlayerID()
    petNPCID = petItem.GetUserAttr(ShareDefine.Def_IudetPet_NPCID)
    curState = petItem.GetUserAttr(ShareDefine.Def_IudetPet_State)
    GameWorld.DebugLog("宠物状态变更! petItemIndex=%s,petNPCID=%s,curState=%s,tagState=%s"
                       % (petItemIndex, petNPCID, curState, tagState), playerID)
    # 收回
    if tagState <= 0:
        SetPetState(curPlayer, petItem, tagState)
        return
    gooutFightRealmList = IpyGameDataPY.GetFuncEvalCfg("PetGoOutFight", 1)
    if tagState > len(gooutFightRealmList):
        GameWorld.DebugLog("    不存在该灵宠上阵位置! tagState=%s" % tagState, playerID)
        return
    needRealmLV = gooutFightRealmList[tagState - 1]
    curRealmLV = curPlayer.GetOfficialRank()
    if curRealmLV < needRealmLV:
        GameWorld.DebugLog("    境界不足,无法上阵灵兽! curRealmLV=%s < %s, tagState=%s" % (curRealmLV, curRealmLV, tagState), playerID)
        return
    #判断是否达到可切换的阶数
    curClasslv = petItem.GetUserAttr(ShareDefine.Def_IudetPet_ClassLV)
    petNPCID = petItem.GetUserAttr(ShareDefine.Def_IudetPet_NPCID)
    ipyData = GetPetIpydata(petNPCID)
    if not ipyData:
        return
    needClasslv = ipyData.GetUseNeedRank()
    if curClasslv < needClasslv - 1: #配置的阶级从1开始
        GameWorld.DebugLog('    灵兽切换外观,阶级不足%s,不可切换!' % needClasslv)
        GameWorld.DebugLog('    灵兽切换外观,阶级不足%s,不可切换!' % needClasslv, playerID)
        return
    SetPetState(curPlayer, petItem, tagState)
        return
    
    curState = petItem.GetUserAttr(ShareDefine.Def_IudetPet_State) # 当前状态
    GameWorld.DebugLog("宠物状态变更!petItemIndex=%s,curState=%s,tagState=%s"
                       % (petItemIndex, curState, tagState))
    # 当前状态处理
    if curState == ShareDefine.Def_PetState_Fight:
#        curPet = curPlayer.GetPetMgr().GetFightPet()
#        if curPet:
#            #已是出战状态, C++召唤坐标和人重叠
#            resultPos = GameMap.GetEmptyPlaceInArea(curPlayer.GetPosX(), curPlayer.GetPosY(), ChConfig.Def_SummonAppearDist)
#            curPet.ResetPos(resultPos.GetPosX(), resultPos.GetPosY())
#            PassiveBuffEffMng.GetPassiveEffManager().RegistPassiveEff(curPet)
#            PassiveBuffEffMng.GetPassiveEffManager().RegistPassiveBuff(curPet)
#        return
        #18/10/15 因为某种未知原因宠物物品的状态是出战(实际场景中未出战),导致该宠物无法出战,故再次发包出战时,此处不拦!
        PetControl.ReCallFightPet(curPlayer)
def SetPetState(curPlayer, petItem, tagState):
    ## 设置灵宠出战状态
    # @param tagState: 0-收回;>=1-出战在第几个位置
    npcID = petItem.GetUserAttr(ShareDefine.Def_IudetPet_NPCID)
    if tagState <= 0:
        GameWorld.DebugLog("    灵宠下阵: npcID=%s" % npcID, curPlayer.GetPlayerID())
    else:
        pass
    # 目标状态处理
    if tagState == ShareDefine.Def_PetState_Null:
        #这里可不再宠物设置Null状态
        #petItem.SetUserAttr(ShareDefine.Def_IudetPet_State, ShareDefine.Def_PetState_Null)
        pass
    elif tagState == ShareDefine.Def_PetState_Fight:
        __DoPetGoOutToFight(curPlayer, petItem)
    if isRefresh:
        RefreshPetItemAddAttr(curPlayer, True) # 不刷排行榜
#    if petItem.GetUserAttr(ShareDefine.Def_IudetPet_State) != tagState:
#        petItem.SetUserAttr(ShareDefine.Def_IudetPet_State, tagState)
#        GameWorld.DebugLog("切换宠物状态异常防范! curState=%s,tagState=%s" % (curState, tagState))
    if not GameWorld.IsCrossServer():
        dataList = [petNPCID, curClasslv, tagState]
        CrossPlayerData.SendDataToCrossServer(curPlayer, CrossPlayerData.CrossData_PetState, dataList)
        petDataPack = curPlayer.GetItemManager().GetPack(ShareDefine.rptPet)
        for index in range(petDataPack.GetCount()):
            item = petDataPack.GetAt(index)
            if item.IsEmpty():
                continue
            if item.GetUserAttr(ShareDefine.Def_IudetPet_State) == tagState:
                SetPetState(curPlayer, item, 0)
        GameWorld.DebugLog("    灵宠上阵: npcID=%s,tagState=%s" % (npcID, tagState), curPlayer.GetPlayerID())
    petItem.SetUserAttr(ShareDefine.Def_IudetPet_State, tagState)
    return
def CrossServer_DoChangePetState(curPlayer, dataList):
    ## 跨服处理 宠物战斗状态变更
    petNPCID, curClasslv, tagState = dataList
    petItem = GetPetDataItemByNPCID(curPlayer, petNPCID)
    if not petItem:
        newPetItem = GetNewPetDataItem(curPlayer, petNPCID)
        if not newPetItem:
            return
        if not ItemControler.PlayerItemControler(curPlayer).PutInItem(ShareDefine.rptPet, newPetItem):
            return
        petItem = GetPetDataItemByNPCID(curPlayer, petNPCID)
    if not petItem:
        return
    curItemClasslv = petItem.GetUserAttr(ShareDefine.Def_IudetPet_ClassLV)
    # 处理技能问题,暂不处理
    if curClasslv > curItemClasslv:
        pass
    curState = petItem.GetUserAttr(ShareDefine.Def_IudetPet_State) # 当前状态
    if curState == ShareDefine.Def_PetState_Fight:
        PetControl.ReCallFightPet(curPlayer)
    if tagState == ShareDefine.Def_PetState_Fight:
        __DoPetGoOutToFight(curPlayer, petItem)
    return
## 执行宠物出战逻辑
def __DoPetGoOutToFight(curPlayer, petItem):
    npcID = petItem.GetUserAttr(ShareDefine.Def_IudetPet_NPCID)
    petNpcData = GameWorld.GetGameData().FindNPCDataByID(npcID)
    if not petNpcData:
        GameWorld.Log("PetStateChange FindNPCDataByID, pet npcID = %s" % (npcID))
        return
    petMgr = curPlayer.GetPetMgr()
    rolePet = petMgr.PetList_Add(npcID)
    if rolePet == None:
        GameWorld.ErrLog("PetStateChange PetList_Add, 添加宠物 = %s失败" % (npcID))
        return
    #---初始化宠物属性---
    petStruct = rolePet.GetRolePet()
    petID = petStruct.PetID
    petStruct.BindType = petItem.GetIsBind()
    petStruct.Name = str(petStruct.PetID)#petNpcData.GetName() 配表不是UTF8会导致报错,默认用ID当名字
    petStruct.DailyTrainCnt = PlayerHorse.GetHorsePetSkinIndex(curPlayer, 2, npcID)
    # 宠物lv 改为 阶级 用于客户端显示名字颜色用
#    classLV = petItem.GetUserAttr(ShareDefine.Def_IudetPet_ClassLV)
#    rolePet.SetLV(classLV)
    #位置.1, 在宠物列表; 2, 在物品背包
    petStruct.Pos = 1
    petItemIndex = petItem.GetItemPlaceIndex()
    SetPetObjItemIndex(petStruct, petItemIndex)
    rolePet.SetRolePet(petStruct)
    learnSkillList, passiveSkillList = GetPetLearnSkill(curPlayer)
    PetControl.DoLogic_PlayerPetLearnSkillList(rolePet, learnSkillList)
    #---刷新属性(不通知)---
    #GameWorld.DebugLog("ˢǰ: petID=%s,playerID=%s,npcID=%s,BindType=%s,AIMode=%s,PetIndex=%s,grade=%s,qualLV=%s,"
    #                   % (petStruct.PetID, petStruct.PlayerID, petStruct.NPCID, petStruct.BindType, petStruct.AIMode, petStruct.PetIndex,
    #                      rolePet.GetGrade(), rolePet.GetQualityLV()))
    petControl = NPCCommon.NPCControl(rolePet)
    petControl.RefreshNPCState(canSyncClient=False)
    #GameWorld.DebugLog("刷后: petID=%s,playerID=%s,npcID=%s,BindType=%s,AIMode=%s,PetIndex=%s,grade=%s,qualLV=%s,"
    #                   % (petStruct.PetID, petStruct.PlayerID, petStruct.NPCID, petStruct.BindType, petStruct.AIMode, petStruct.PetIndex,
    #                      rolePet.GetGrade(), rolePet.GetQualityLV()))
    #当前血量(不通知)
    PetControl.SetPetHP(rolePet, GameObj.GetMaxHP(rolePet), False)
    #---通知客户端---
    #rolePet.Sync_PetInfo()
    #刷新技能栏
    #rolePet.Sync_SkillList()
    #---收到"宠物出战"请求---
    #检查是否可出战
    if not PetControl.CheckPetCanFight(curPlayer, rolePet):
        GameWorld.DebugLog("不可出战!PetList_SetFree petID=%s" % petID)
        petMgr.PetList_SetFree(petID)
        return
    # 先招回出战中的宠物
    PetControl.ReCallFightPet(curPlayer)
    #召唤宠物出战
    resultPos = GameMap.GetEmptyPlaceInArea(curPlayer.GetPosX(), curPlayer.GetPosY(), ChConfig.Def_SummonAppearDist)
    PetControl.SummonPet(rolePet, resultPos.GetPosX(), resultPos.GetPosY())
    petItem.SetUserAttr(ShareDefine.Def_IudetPet_State, ShareDefine.Def_PetState_Fight)
    #记录出战的宠物索引 默认+1 0则代表没有
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_FightPetIndex, petItemIndex + 1)
    rolePet.SetSightLevel(curPlayer.GetSightLevel())
    return True
def AutoSummonPet(curPlayer):
    #重新召唤之前的宠物,复活、切换地图时调用
    fightPetIndex = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FightPetIndex)
    if not fightPetIndex:
        return
    DoChangePetState(curPlayer, fightPetIndex - 1, ShareDefine.Def_PetState_Fight)
    return
## 获取出战宠物要学的技能
@@ -508,16 +348,7 @@
    EventShell.EventRespons_OnActivatePet(curPlayer, petNPCID)
    sysMark = ipyData.GetUnlockSys() or 'GetPet'
    PlayerControl.WorldNotify(0, sysMark, [curPlayer.GetName(), petNPCID])
    rolePet = curPlayer.GetPetMgr().GetFightPet()
    if not rolePet:
        petItemIndex = GetPetDataItemIndexByNPCID(curPlayer, petNPCID)
        GameWorld.DebugLog("没有宠物出战,获得新宠物,默认出战该宠物!petNPCID=%s,petItemIndex=%s" % (petNPCID, petItemIndex))
        DoChangePetState(curPlayer, petItemIndex, ShareDefine.Def_PetState_Fight)
    else:
        
        if rolePet:
            learnSkillList, passiveSkillList = GetPetLearnSkill(curPlayer)
            PetControl.DoLogic_PlayerPetLearnSkillList(rolePet, learnSkillList)
    RefreshPetItemAddAttr(curPlayer, True)
    
    # 开服活动数据
@@ -550,6 +381,7 @@
                packItem.SetUserAttr(ShareDefine.Def_IudetPet_ClassLV, max(0, min(classlv, maxClassLV) - 1))
            packItem.SetUserAttr(ShareDefine.Def_IudetPet_QualityLV, quality) # 宠物品质
            GameWorld.DebugLog("已经拥有该宠物! i=%s,petItemNPCID=%s,petNPCID=%s" % (i, petItemNPCID, petNPCID))
            __UpdPetItemSkillByClass(curPlayer, packItem, True)
            return True
        
    if classlv == None:
@@ -564,25 +396,8 @@
        return
    if not refresh:
        return True
    petItemIndex = GetPetDataItemIndexByNPCID(curPlayer, petNPCID)
    DoChangePetState(curPlayer, petItemIndex, ShareDefine.Def_PetState_Fight)
    RefreshPetItemAddAttr(curPlayer, True)
    return True
#===============================================================================
## 获取已激活的灵兽ID
def GetActivePetID(curPlayer):
    petIDList = []
    petPackIndex = ShareDefine.rptPet
    petPack = curPlayer.GetItemManager().GetPack(petPackIndex)
    for i in range(petPack.GetCount()):
        packItem = petPack.GetAt(i)
        if packItem.IsEmpty():
            continue
        petItemNPCID = packItem.GetUserAttr(ShareDefine.Def_IudetPet_NPCID)
        petIDList.append(petItemNPCID)
    return petIDList
#// A7 04 宠物升阶 #tagCMPetClassUP
#
@@ -676,19 +491,6 @@
    
    if lackCnt > 0:
        return
        #===========================================================================================
        # if not isAutoBuy:
        #    return
        # lackCost = ItemCommon.GetAutoBuyItemNeedGold({autoBuyItemID:lackCnt})
        # if lackCost <= 0:
        #    return
        # itemData = GameWorld.GetGameData().GetItemByTypeID(autoBuyItemID)
        # itemName = autoBuyItemID if not itemData else itemData.GetName()
        # infoDict = {ChConfig.Def_Cost_Reason_SonKey:itemName}
        # if not PlayerControl.PayMoney(curPlayer, IPY_GameWorld.TYPE_Price_Gold_Money, lackCost,
        #                              ChConfig.Def_Cost_PetClassUP, infoDict, lackCnt):
        #    return
        #===========================================================================================
       
    playerName = curPlayer.GetName()
   
@@ -719,35 +521,7 @@
    if updClassLV > classLV:
        petDataItem.SetUserAttr(ShareDefine.Def_IudetPet_ClassLV, updClassLV)
        
        # 升阶开启技能
        petIpyData = GetPetIpydata(petNPCID)
        petSkillList = petIpyData.GetSkillID()
        petSkillUnLockList = petIpyData.GetSkillUnLock()
        sysMarkList = petIpyData.GetSkillUnLockSys()
        learnSkillList = []
        for i, skillid in enumerate(petSkillList):
            limitPetClassLV = petSkillUnLockList[i] # 学习此技能所需宠物阶级
            #上一阶已经处理过的技能不再处理
            if updClassLV >= limitPetClassLV:
                continue
            # 未达到所需阶级
            if updClassLV + 1 < limitPetClassLV:
                continue
            curSkilData = GameWorld.GetGameData().GetSkillBySkillID(skillid)
            if not curSkilData:
                continue
            if curSkilData.GetFuncType() == ChConfig.Def_SkillFuncType_PetOwnerSkill:
                __GiveOwnerSkill(curPlayer, skillid)
                continue
            petDataItem.AddUserAttr(ShareDefine.Def_IudetPet_Skill, skillid)
            if not SkillCommon.isPassiveAttr(curSkilData):
                #被动技能不学
                learnSkillList.append(skillid)
            #广播
            sysMark = sysMarkList[i] if i < len(sysMarkList) else 'PetUpLv'
            PlayerControl.WorldNotify(0, sysMark, [playerName, petNPCID, limitPetClassLV, skillid])
            #增加升级活跃点效果
            PlayerActivity.AddActivityByLVOnLearnSkill(curPlayer, skillid)
        learnSkillList = __UpdPetItemSkillByClass(curPlayer, petDataItem, True)
            
        if not learnSkillList and updClassLV + 1 == maxClassLV:
            PlayerControl.WorldNotify(0, 'PetUpLvMax', [playerName, petNPCID])
@@ -769,6 +543,65 @@
    #EventReport.WriteEvent_pet_class(curPlayer, petNpcData.GetName(), classLV, petClassExp, updClassLV, newClassExp)
    
    return
def __UpdPetItemSkillByClass(curPlayer, petDataItem, isNotify=False):
    # 升阶更新灵宠技能,支持同skillTypeID技能升级
    playerName = curPlayer.GetName()
    petNPCID = petDataItem.GetUserAttr(ShareDefine.Def_IudetPet_NPCID)
    classLV = petDataItem.GetUserAttr(ShareDefine.Def_IudetPet_ClassLV) + 1
    alreadyLearnSkillInfo = {}
    for i in xrange(petDataItem.GetUserAttrCount(ShareDefine.Def_IudetPet_Skill)):
        skillID = petDataItem.GetUserAttrByIndex(ShareDefine.Def_IudetPet_Skill, i)
        skillData = GameWorld.GetGameData().GetSkillBySkillID(skillID)
        if not skillData:
            continue
        skillTypeID = skillData.GetSkillTypeID()
        alreadyLearnSkillInfo[skillTypeID] = [skillID, i]
    #GameWorld.DebugLog("开始更新灵宠技能: petNPCID=%s,classLV=%s,alreadyLearnSkillInfo=%s" % (petNPCID, classLV, alreadyLearnSkillInfo))
    petIpyData = GetPetIpydata(petNPCID)
    petSkillList = petIpyData.GetSkillID()
    petSkillUnLockList = petIpyData.GetSkillUnLock()
    sysMarkList = petIpyData.GetSkillUnLockSys()
    learnSkillList = []
    for i, skillID in enumerate(petSkillList):
        limitPetClassLV = petSkillUnLockList[i] # 学习此技能所需宠物阶级
        if classLV < limitPetClassLV:
            #GameWorld.DebugLog("    未满足学习阶级: i=%s,skillID=%s,limitPetClassLV=%s" % (i, skillID, limitPetClassLV))
            break
        skillData = GameWorld.GetGameData().GetSkillBySkillID(skillID)
        if not skillData:
            continue
        skillTypeID = skillData.GetSkillTypeID()
        alreadyLearnSkillID, skillIndex = alreadyLearnSkillInfo.get(skillTypeID, [0, -1])
        if skillID <= alreadyLearnSkillID:
            #GameWorld.DebugLog("    技能已经学习过: i=%s,skillID=%s <= alreadyLearnSkillID=%s" % (i, skillID, alreadyLearnSkillID))
            continue
        if skillData.GetFuncType() == ChConfig.Def_SkillFuncType_PetOwnerSkill:
            #GameWorld.DebugLog("    主人学习技能: i=%s,skillID=%s" % (i, skillID))
            SkillCommon.GivePlayerSkillByJobSkill(curPlayer, [skillID])
            continue
        if not alreadyLearnSkillID:
            #GameWorld.DebugLog("    学习新的技能: i=%s,skillID=%s" % (i, skillID))
            petDataItem.AddUserAttr(ShareDefine.Def_IudetPet_Skill, skillID)
        else:
            #GameWorld.DebugLog("    学习升级技能: i=%s,skillID=%s,skillIndex=%s" % (i, skillID, skillIndex))
            petDataItem.UpdataUserAttrByIndex(ShareDefine.Def_IudetPet_Skill, skillIndex, skillID)
        if not SkillCommon.isPassiveAttr(skillData):
            #被动技能不学
            learnSkillList.append(skillID)
        #广播
        sysMark = sysMarkList[i] if i < len(sysMarkList) else 'PetUpLv'
        if isNotify and sysMark:
            PlayerControl.WorldNotify(0, sysMark, [playerName, petNPCID, limitPetClassLV, skillID])
        #增加升级活跃点效果
        PlayerActivity.AddActivityByLVOnLearnSkill(curPlayer, skillID)
    nowSkillIDList = []
    for i in xrange(petDataItem.GetUserAttrCount(ShareDefine.Def_IudetPet_Skill)):
        nowSkillIDList.append(petDataItem.GetUserAttrByIndex(ShareDefine.Def_IudetPet_Skill, i))
    GameWorld.DebugLog("灵宠最新技能: nowSkillIDList=%s" % nowSkillIDList)
    return learnSkillList
def GetTotalPetLV(curPlayer):
    totalPetLV = 0
@@ -801,18 +634,6 @@
        totalPetCount += 1
    return totalPetCount
def IsPetMaxLV(curPlayer, petNPCID):
    petItem = GetPetDataItemByNPCID(curPlayer, petNPCID)
    if not petItem:
        return
    petNPCID = petItem.GetUserAttr(ShareDefine.Def_IudetPet_NPCID)
    classLV = petItem.GetUserAttr(ShareDefine.Def_IudetPet_ClassLV)
    petIpyData = GetPetIpydata(petNPCID)
    if not petIpyData:
        return
    maxClassLV = petIpyData.GetMaxRank()
    return classLV + 2 > maxClassLV
## 刷新宠物数据物品增加的属性
def RefreshPetItemAddAttr(curPlayer, isUpdBillboard):
    CalcPetItemAddPlayerAttr(curPlayer)
@@ -823,9 +644,9 @@
    else:
        PlayerControl.PlayerControl(curPlayer).RefreshPlayerAttrState(isForce=True)
        
    fightPet = curPlayer.GetPetMgr().GetFightPet()
    if fightPet:
        PetControl.RefurbishPetAttr(fightPet)
    #fightPet = curPlayer.GetPetMgr().GetFightPet()
    #if fightPet:
    #    PetControl.RefurbishPetAttr(fightPet)
    return
def CalcSkill_PetBattleEffect(curPlayer, rolePet, allAttrListPet):
@@ -1020,19 +841,6 @@
    totalMinAtk = classAddAtk
    totalMaxAtk = classAddAtk
    return totalMinAtk, totalMaxAtk, qualityAttrInfo
def OnPlayerPetLogin(curPlayer):
    ## 登录处理
    if not GameFuncComm.GetFuncCanUse(curPlayer, ShareDefine.GameFuncID_Pet):
        return
    # 培养是后面加的功能,每次登录补检查一下功能开始时设置为培养1级
    for trainType in xrange(1, GetPetTrainTypes() + 1):
        if curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_PetTrainLV % trainType) == 0:
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_PetTrainLV % trainType, 1)
    Sync_PetTrainData(curPlayer)
    return
def GetPetTrainTypes():
    return len(IpyGameDataPY.GetFuncEvalCfg("PetUpItem", 3))
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerState.py
@@ -141,7 +141,7 @@
        
    if useSkillData and useSkillData.GetSkillID() != ChConfig.Def_SkillID_Somersault:
        # 跟随玩家同频率攻击
        PetControl.PetFight(curPlayer, tick)
        #PetControl.PetFight(curPlayer, tick)
        SummonFollowAtk(curPlayer, tick)
    #===========================================================================
    # if not result:
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerViewCacheTube.py
@@ -35,6 +35,7 @@
import PyGameData
import PlayerTJG
import SkillShell
import PlayerPet
import GameObj
import time
@@ -161,6 +162,8 @@
    return json.dumps(classItemDataDict, ensure_ascii=False).replace(" ", "")
def UpdPlayerPropPlusCache(curPlayer):
    if not curPlayer:
        return
    curPlayerPropDict = {}
    curPlayerPropDict["AccID"] = curPlayer.GetAccID()
    curPlayerPropDict["LV"] = curPlayer.GetLV()
@@ -247,9 +250,12 @@
    curPlayerPlusDict["TotalStoneLV"] = Operate_EquipStone.GetTotalStoneLV(curPlayer)
    curPlayerPlusDict["TotalEquipWashLV"] = Operate_EquipWash.GetTotalEquipWashLV(curPlayer)
    #主动技能总等级
    curPlayerPlusDict["TotalSkillLV"] = SkillShell.GetAllSkillLV(curPlayer, ChConfig.Def_SkillFuncType_FbSkill)
    skillInfo = SkillShell.GetAllSkillInfo(curPlayer, [ChConfig.Def_SkillFuncType_FbSkill, ChConfig.Def_SkillFuncType_NormalAttack])
    curPlayerPlusDict["SkillInfo"] = skillInfo
    curPlayerPlusDict["TotalSkillLV"] = sum(skillInfo.get(ChConfig.Def_SkillFuncType_FbSkill, {}).values())
    #灵宠数据
    curPlayerPlusDict["Pet"] = __GetPetInfo(curPlayer)
    curPlayerPlusDict["Pet"] = PlayerPet.GetPetCacheInfo(curPlayer)
    
    #坐骑数据
    curPlayerPlusDict["Horse"] = __GetHorseInfo(curPlayer)
@@ -273,16 +279,23 @@
def GetPlayerPropPlusCache(curPlayer):
    #玩家属性缓存
    UpdPlayerPropPlusCache(curPlayer)
    return GetPlayerPropPlusCacheByID(curPlayer.GetPlayerID())
    return GetPlayerPropPlusCacheByID(curPlayer.GetPlayerID(), False)
def GetPlayerPropPlusCacheByID(playerID):
def GetPlayerPropPlusCacheByID(playerID, checkUpd=False):
    #玩家属性缓存
    viewCache = PyGameData.g_playerViewCache.get(playerID, {})
    curPlayerPropDict = viewCache.get("PropData", {})
    curPlayerPlusDict = viewCache.get("PlusData", {})
    PropData = json.dumps(curPlayerPropDict, ensure_ascii=False).replace(" ", "")
    PlusData = json.dumps(curPlayerPlusDict, ensure_ascii=False).replace(" ", "")
    PropDict, PlusDict = GetPlayerPropPlusDictByID(playerID, checkUpd)
    PropData = json.dumps(PropDict, ensure_ascii=False).replace(" ", "")
    PlusData = json.dumps(PlusDict, ensure_ascii=False).replace(" ", "")
    return PropData, PlusData
def GetPlayerPropPlusDictByID(playerID, checkUpd=False):
    #玩家属性字典
    if checkUpd:
        UpdPlayerPropPlusCache(GameWorld.GetPlayerManager().FindPlayerByID(playerID))
    viewCache = PyGameData.g_playerViewCache.get(playerID, {})
    PropDict = viewCache.get("PropData", {})
    PlusDict = viewCache.get("PlusData", {})
    return PropDict, PlusDict
def __GetEquipShowIDList(curPlayer):
    ## 获取外观装备ID列表
@@ -295,23 +308,6 @@
            continue
        equipShowIDList.append(curEquip.GetItemTypeID())
    return equipShowIDList
## 灵宠信息
def __GetPetInfo(curPlayer):
    petInfo = {}
    petClassLVList = []
    equipPack = curPlayer.GetItemManager().GetPack(ShareDefine.rptPet)
    for index in xrange(equipPack.GetCount()):
        packItem = equipPack.GetAt(index)
        if not packItem or packItem.IsEmpty():
            continue
        petNPCID = packItem.GetUserAttr(ShareDefine.Def_IudetPet_NPCID)
        classLV = packItem.GetUserAttr(ShareDefine.Def_IudetPet_ClassLV)
        petClassLVList.append({"id":petNPCID, 'lv':classLV})
    petInfo["PetLV"] = petClassLVList
    petInfo["AtkSpeed"] = GameObj.GetAtkSpeed(curPlayer)
    return petInfo
## 坐骑信息
def __GetHorseInfo(curPlayer):
@@ -414,16 +410,14 @@
    NetPackCommon.SendPyPackToGameServer(sendPack)  
    return
def GetPlayerPropData(findPlayerID):
    ## 获取玩家战斗属性数据  UpdPlayerPropPlusCache
    viewCache = PyGameData.g_playerViewCache.get(findPlayerID, {})
    return viewCache.get("PropData", {})
def GetPlayerPropDataCall(curPlayer, findPlayerID, callFunc, callData=None, syncClient=True):
def GetPlayerPropDataCall(curPlayer, findPlayerID, callFunc, callData=None, syncClient=False):
    ## 获取玩家战斗属性数据 - 支持callback,因为地图可能暂时没有离线玩家缓存数据
    # @param callFunc: 获取到玩家数据后回调函数,可能地图没有数据,会等向GameServer同步过后再回调
    # @param callData: 回调函数扩展参数,透传参数
    # @param syncClient: 是否附带通知前端该玩家数据,一般如果有需要前端配合展示的,需要直接传给前端,如镜像PK类功能
    
    playerID = curPlayer.GetPlayerID()
    dataDict = GetPlayerPropData(findPlayerID)
    dataDict = GetPlayerPropPlusDictByID(findPlayerID, True)[0]
    if dataDict:
        if syncClient:
            Sync_PlayerCache(curPlayer, findPlayerID)
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Skill/SkillShell.py
@@ -624,11 +624,11 @@
    if skillTag != ChConfig.Def_UseSkillTag_PetMaster:
        return False
    if not PetControl.IsPet(curNPC):
    if not PetControl.IsPetNPC(curNPC):
        GameWorld.ErrLog("NPCID %s AI %s 非宠物,无法获得主人释放技能"%(curNPC.GetNPCID(), curNPC.GetAIType()))
        return False
    
    petOwner = PetControl.GetPetOwner(curNPC)
    petOwner = PetControl.GetPetNPCOwner(curNPC)
    
    if petOwner == None:
        GameWorld.ErrLog("宠物(%s)对主人释放技能,找不到主人"%curNPC.GetRolePet().PetID)
@@ -1757,11 +1757,11 @@
                  
        # 宠物对主人释放技能
        elif skillAffectTag == ChConfig.Def_UseSkillTag_PetMaster:
            if not PetControl.IsPet(attacker):
            if not PetControl.IsPetNPC(attacker):
                GameWorld.ErrLog("该NPC非宠物,无法获得主人释放技能")
                return False
            
            petOwner = PetControl.GetPetOwner(attacker)
            petOwner = PetControl.GetPetNPCOwner(attacker)
            
            if petOwner == None:
                GameWorld.ErrLog("宠物(%s)对主人释放技能,找不到主人"%attacker.GetRolePet().PetID)
@@ -3844,10 +3844,10 @@
    
    else:
        if affectTag == ChConfig.Def_UseSkillTag_PetMaster:
            if not PetControl.IsPet(attacker):
            if not PetControl.IsPetNPC(attacker):
                return False
            
            petOwner = PetControl.GetPetOwner(attacker)
            petOwner = PetControl.GetPetNPCOwner(attacker)
            if petOwner == None:
                return False
            
@@ -3898,15 +3898,19 @@
## 获取技能总等级
#  @param curPlayer
#  @return allSkillLV:总技能等级
def GetAllSkillLV(curPlayer, funcType):
    allSkillLV = 0
def GetAllSkillInfo(curPlayer, funcTypeList):
    # @return: {funcType:{skillID:skillLV, ...}, ...}
    skillDict = {}
    skillManager = curPlayer.GetSkillManager()
    for i in xrange(skillManager.GetSkillCount()):
        curPlayerSkill = skillManager.GetSkillByIndex(i)
        if curPlayerSkill == None:
            continue
        if curPlayerSkill.GetFuncType() != funcType:
        funcType = curPlayerSkill.GetFuncType()
        if funcType not in funcTypeList:
            continue
        skillLV = curPlayerSkill.GetSkillLV()
        allSkillLV += skillLV
    return allSkillLV
        if funcType not in skillDict:
            skillDict[funcType] = {}
        skillLVDict = skillDict[funcType]
        skillLVDict[curPlayerSkill.GetSkillID()] = curPlayerSkill.GetSkillLV()
    return skillDict