hxp
2024-01-06 776cf3759b9801f3795ee975cd77078f505b90d6
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)
        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)
        
    #一个回合攻击顺序,由攻击速度决定,攻速相同下阵营1先攻击,还相同则由ID决定
    fightObjList = factionListA + factionListB
    fightObjList.sort(key=lambda o: (GameObj.GetAtkSpeed(o), (10 - GameObj.GetFaction(o)), o.GetID()), reverse=True)
    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:
        #普通攻击
        atkOK = BaseAttack.Attack(curObj, tagObj, None, tick)
        if atkOK:
            GameWorld.DebugLog("        NPC普通攻击: curID=%s,tagID=%s,atkOK=%s" % (curObj.GetID(), tagObj.GetID(), atkOK))
        if fightPlaceNum:
            GameWorld.DebugLog("        灵宠不可普通攻击: curID=%s,fightPlaceNum=%s" % (curObj.GetID(), fightPlaceNum))
        else:
            GameWorld.DebugLog("        NPC攻击失败: curID=%s,tagID=%s,atkOK=%s" % (curObj.GetID(), tagObj.GetID(), atkOK))
            #普通攻击
            atkOK = BaseAttack.Attack(curObj, tagObj, None, tick)
            if atkOK:
                GameWorld.DebugLog("        %s 普通攻击: curID=%s,tagID=%s,atkOK=%s" % (objName, curObj.GetID(), tagObj.GetID(), atkOK))
            else:
                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):