hxp
2024-01-06 776cf3759b9801f3795ee975cd77078f505b90d6
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
def DoChangePetState(curPlayer, petItemIndex, tagState):
    # @param tagState: 0-收回;>=1-出战在第几个位置
    
    if tagState not in ShareDefine.Def_PetStateList:
        return
    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
    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)
    SetPetState(curPlayer, petItem, tagState)
    return
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,35 +491,22 @@
    
    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()
   
    curEff = curItem.GetEffectByIndex(0)
    addExp = curEff.GetEffectValue(0) * costItemCount
    updExp = curPetClassExp + addExp
    updClassLV = classLV
    for lv in xrange(classLV, maxClassLV-1):
        ipyData = IpyGameDataPY.GetIpyGameData("PetClassCost", petNPCID, lv+1)
    for lv in xrange(classLV, maxClassLV - 1):
        ipyData = IpyGameDataPY.GetIpyGameData("PetClassCost", petNPCID, lv + 1)
        if not ipyData:
            break
        upNeedExp = ipyData.GetUpNeedExp()
        if updExp < upNeedExp:
            break
        updExp -= upNeedExp
        updClassLV +=1
        updClassLV += 1
        
    
    #扣除物品
@@ -713,42 +515,14 @@
        ItemCommon.ReduceItem(curPlayer, curItemPack, itemIndexList, delCnt, True, ChConfig.ItemDel_Pet)
        
    # 更新经验值
    if updClassLV+1 >=maxClassLV:
        updExp =0
    if updClassLV + 1 >= maxClassLV:
        updExp = 0
    petDataItem.SetUserAttr(ShareDefine.Def_IudetPet_Exp, updExp)
    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):
@@ -968,7 +789,7 @@
        fpExTotal += petIpyData.GetInitFightPower() # 初始战力
        #觉醒战力
        skinData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_HorsePetSkinData % (2, petItemNPCID), 0)
        skinIpyData = IpyGameDataPY.GetIpyGameDataNotLog('HorsePetSkin', 2, petItemNPCID, skinData/100)
        skinIpyData = IpyGameDataPY.GetIpyGameDataNotLog('HorsePetSkin', 2, petItemNPCID, skinData / 100)
        if skinIpyData:
            for attrID, attrValue in skinIpyData.GetAttrInfo().items():
                PlayerControl.CalcAttrDict_Type(attrID, attrValue, allAttrListPetSkin)
@@ -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))