ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py
@@ -30,6 +30,7 @@
import GameWorld
import GameObj
import PetControl
import SkillShell
(
FightState_Start,
@@ -38,6 +39,10 @@
FightState_Fail,
FightState_Over,
) = range(5)
(
RebornType_PetSkill,
) = range(1, 1 + 1)
def GetObjName(gameObj):
    objName = gameObj.GetName()
@@ -121,10 +126,14 @@
    factionListB = fightPetObjListB + [tagObj]
    atkFactionList = [factionListA, factionListB]
    
    # 设置战斗主体
    curPlayer.SetDict(ChConfig.Def_Obj_Dict_TurnFightMainRole, 1)
    tagObj.SetDict(ChConfig.Def_Obj_Dict_TurnFightMainRole, 1)
    # 战斗前初始化,可能会改变攻速,所以先初始化
    for faction, factionObjList in enumerate(atkFactionList, 1):
        for gameObj in factionObjList:
            TurnFightObjStartInit(gameObj, faction, tick)
            TurnFightObjStartInit(playerID, gameObj, faction, tick)
            
    #一个回合攻击顺序,为了后续逻辑统一,都是先确定好顺序
    sortType = 2 # 攻击顺序排序方式
@@ -150,13 +159,29 @@
        for gameObj in fightObjList:
            TurnFightObjPerTurnStart(gameObj, turnNum, tick)
            
        isWin = CheckIswin(curPlayer, tagObj)
        if isWin != None:
            break
        # 回合战斗: 轮流依次攻击
        for gameObj in fightObjList:
            if not gameObj or GameObj.GetHP(gameObj) <= 0:
        for actionNum, gameObj in enumerate(fightObjList, 1):
            if not gameObj:
                # 没有对象可视为没有该节点
                continue
            faction = GameObj.GetFaction(gameObj)
            for obj in fightObjList:
                TurnFightObjPerTurnActionnum(turnNum, actionNum, obj, tick)
            objType = gameObj.GetGameObjType()
            objID = gameObj.GetID()
            SyncTurnFightObjAction(curPlayer, turnNum, objType, objID)
            if GameObj.GetHP(gameObj) <= 0:
                # 复活时机在自己行动节点
                if not DoReborn(gameObj):
                    continue
            faction = GameObj.GetFaction(gameObj)
            objName = GetObjName(gameObj)
            curHP = GameObj.GetHP(gameObj)
            
@@ -165,28 +190,16 @@
            tagObjID = tagGameObj.GetID()
            tagHP = GameObj.GetHP(tagGameObj)
            
            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)
            GameWorld.DebugLog("    ★回合%s.%s %s 行动 : objType-ID-HP(%s-%s-%s),curAtk=%s, tagType-ID-HP(%s-%s-%s)"
                               % (turnNum, actionNum, objName, objType, objID, curHP, gameObj.GetMaxAtk(), tagObjType, tagObjID, tagHP))
            
            DoAttack(gameObj, tagGameObj, tick)
            playerDead = GameObj.GetHP(curPlayer) <= 0
            tagObjDead = (not tagObj or GameObj.GetHP(tagObj) <= 0)
            if not playerDead and not tagObjDead:
            if not DoAttack(gameObj, tagGameObj, tick):
                continue
            
            if playerDead and tagObjDead:
                isWin = False # 平局算失败
                GameWorld.DebugLog("        双方被击杀,平局算失败: isWin=%s" % isWin)
            elif playerDead:
                isWin = False
                GameWorld.DebugLog("        玩家被击杀,失败: isWin=%s" % isWin)
            elif tagObjDead:
                isWin = True # 胜利
                GameWorld.DebugLog("        对手被击杀,胜利: isWin=%s" % isWin)
            break
            isWin = CheckIswin(curPlayer, tagObj)
            if isWin != None:
                break
        if isWin != None:
            break
        
@@ -200,11 +213,154 @@
                       % (mapID, funcLineID, tagPlayerID, isWin, overState), playerID)
    return
def TurnFightObjStartInit(gameObj, faction, tick):
def CheckIswin(curPlayer, tagObj):
    ## 检查是否结束
    # @return: None-未结束;True-获胜;False-失败
    playerDead = GameObj.GetHP(curPlayer) <= 0 and GetRebornTypeInfo(curPlayer) == None
    tagObjDead = (not tagObj or GameObj.GetHP(tagObj) <= 0) and GetRebornTypeInfo(tagObj) == None
    if not playerDead and not tagObjDead:
        return
    isWin = None
    if playerDead and tagObjDead:
        isWin = False # 平局算失败
        GameWorld.DebugLog("        双方被击杀,平局算失败: isWin=%s" % isWin)
    elif playerDead:
        isWin = False
        GameWorld.DebugLog("        玩家被击杀,失败: isWin=%s" % isWin)
    elif tagObjDead:
        isWin = True # 胜利
        GameWorld.DebugLog("        对手被击杀,胜利: isWin=%s" % isWin)
    return isWin
def SetKilled(gameObj, killer=None):
    if not gameObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnFightMainRole):
        #GameWorld.DebugLog("非回合战斗主体被击杀: curID=%s" % gameObj.GetID())
        return
    GameWorld.DebugLog("        %s 回合战斗主体被击杀: curID=%s" % (GetObjName(gameObj), gameObj.GetID()))
    GameObj.SetHP(gameObj, 0)
    playerID = gameObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnFightID)
    if not playerID:
        return
    curPlayer = GameWorld.GetMapCopyPlayerManager().FindPlayerByID(playerID)
    if not curPlayer:
        return
    # 通知前端
    clientPack = ChPyNetSendPack.tagMCTurnFightObjDead()
    clientPack.ObjID = gameObj.GetID()
    clientPack.ObjType = gameObj.GetGameObjType()
    NetPackCommon.SendFakePack(curPlayer, clientPack)
    return True
def GetRebornTypeInfo(gameObj):
    ''' 获取可复活的方式信息
    @return: None-代表不可复活
    '''
    if not gameObj:
        return
    if not gameObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnFightMainRole):
        # 仅主体可复活
        return
    rebornCountMax = 1
    curRebornCount = gameObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnRebornCount)
    if curRebornCount >= rebornCountMax:
        GameWorld.DebugLog("%s 已经超过复活次数,不能再复活! curID=%s,curRebornCount=%s" % (GetObjName(gameObj), gameObj.GetID(), curRebornCount))
        return
    # 检查是否有灵宠复活技能
    for index in range(gameObj.GetSummonCount()):
        curSummonNPC = gameObj.GetSummonNPCAt(index)
        if not curSummonNPC:
            continue
        if not PetControl.IsPetNPC(curSummonNPC):
            continue
        skillManager = curSummonNPC.GetSkillManager()
        for skillIndex in range(skillManager.GetSkillCount()):
            skill = skillManager.GetSkillByIndex(skillIndex)
            if skill.GetSkillType() != ChConfig.Def_SkillType_Revive:
                continue
            if not skill.GetRemainTime():
                return RebornType_PetSkill, curSummonNPC, skill
    # 检查其他功能复活,待扩展...
    #GameWorld.DebugLog("    没有可以复活的方式!")
    return
def DoReborn(gameObj, hpPer=ChConfig.Def_MaxRateValue):
    ## 执行复活
    rebornTypeInfo = GetRebornTypeInfo(gameObj)
    if rebornTypeInfo == None:
        return
    objName = GetObjName(gameObj)
    objID = gameObj.GetID()
    objType = gameObj.GetGameObjType()
    rebornType = rebornTypeInfo[0]
    rebornValue1, rebornValue2 = 0, 0
    if rebornType == RebornType_PetSkill:
        petNPC, skill = rebornTypeInfo[1:]
        skill.SetRemainTime(skill.GetCoolDownTime())
        hpPer = skill.GetEffect(0).GetEffectValue(0)
        rebornValue1 = petNPC.GetID()
        rebornValue2 = skill.GetSkillID()
    rebornCount = gameObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnRebornCount) + 1
    gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnRebornCount, rebornCount)
    setHP = int(GameObj.GetMaxHP(gameObj) * hpPer / float(ChConfig.Def_MaxRateValue))
    GameObj.SetHP(gameObj, setHP)
    if objType == IPY_GameWorld.gotPlayer:
        gameObj.ChangeAction(IPY_GameWorld.paNull)
    else:
        gameObj.ChangeAction(IPY_GameWorld.laNPCNull)
    curHP = GameObj.GetHP(gameObj)
    GameWorld.DebugLog("复活 %s: rebornType=%s,objID=%s,hpPer=%s,curHP=%s,rebornCount=%s" % (objName, rebornType, objID, hpPer, curHP, rebornCount))
    playerID = gameObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnFightID)
    if not playerID:
        return
    curPlayer = GameWorld.GetMapCopyPlayerManager().FindPlayerByID(playerID)
    if not curPlayer:
        return
    # 通知前端
    clientPack = ChPyNetSendPack.tagMCTurnFightObjReborn()
    clientPack.ObjID = gameObj.GetID()
    clientPack.ObjType = gameObj.GetGameObjType()
    clientPack.HP = curHP % ChConfig.Def_PerPointValue
    clientPack.HPEx = curHP / ChConfig.Def_PerPointValue
    clientPack.RebornType = rebornType
    clientPack.RebornValue1 = rebornValue1
    clientPack.RebornValue2 = rebornValue2
    NetPackCommon.SendFakePack(curPlayer, clientPack)
    return True
def SetTimeline(gameObj, turnNum, actionNum):
    '''设置回合制战斗所在时间节点
    @param turnNum: 第几回合,如果在回合制战斗中,则回合数一定大于0,
    @param actionNum: 第几个行动节点,每回合的行动节点会重置,也就是说行动节点0可视为每回合的起始节点,1位第一个行动目标节点,以此类推
    '''
    gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnFightTimeline, turnNum * 100 + actionNum)
    return
def TurnFightObjStartInit(playerID, gameObj, faction, tick):
    ## 回合制战斗实例初始化
    if not gameObj:
        return
    gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnFightNum, 1)
    isMainRole = gameObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnFightMainRole)
    gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnFightID, playerID)
    gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnRebornCount, 0)
    SetTimeline(gameObj, 1, 0)
    GameObj.SetFaction(gameObj, faction)
    GameObj.SetHPFull(gameObj)
    gameObj.RefreshView()
@@ -214,9 +370,9 @@
    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 】 objID=%s,npcID=%s,atkSpeed=%s,HP=%s,Atk=%s,Def=%s,isMainRole=%s"
                       % (objName, BaseAttack.GetObjAttackName(gameObj), gameObj.GetID(), npcID,
                          GameObj.GetAtkSpeed(gameObj), GameObj.GetHP(gameObj), gameObj.GetMaxAtk(), gameObj.GetDef(), isMainRole))
    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),
@@ -242,9 +398,10 @@
                continue
            skillIDList.append(curSkill.GetSkillID())
            if fightPlaceNum:
                # 灵宠技能开始时直接进入CD
                curSkill.SetLastUseTick(tick)
                curSkill.SetRemainTime(curSkill.GetCoolDownTime())
                if curSkill.GetSkillType() != ChConfig.Def_SkillType_Revive:
                    # 灵宠技能开始时直接进入CD
                    curSkill.SetLastUseTick(tick)
                    curSkill.SetRemainTime(curSkill.GetCoolDownTime())
        GameWorld.DebugLog("    NPC技能: npcID=%s,skillIDList=%s" % (npcID, skillIDList))
        
    return
@@ -254,7 +411,7 @@
    if not gameObj:
        return
    
    gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnFightNum, turnNum)
    SetTimeline(gameObj, turnNum, 0)
    # 重置连击、反击数
    gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnComboNum, 0)
    gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnAtkBackNum, 0)
@@ -277,14 +434,23 @@
        skill.SetRemainTime(updRemainTime)
        GameWorld.DebugLog("    skillID=%s,remainTime=%s,updRemainTime=%s" % (skillID, remainTime, updRemainTime))
        
    # 刷新定时处理的buff效果
    SkillShell.ProcessPersistBuff(gameObj, tick)
    return
def TurnFightObjPerTurnActionnum(turnNum, actionNum, gameObj, tick):
    ## 回合制战斗实例 - 每个行动节点处理
    if not gameObj:
        return
    SetTimeline(gameObj, turnNum, actionNum)
    objType = gameObj.GetGameObjType()
    if objType == IPY_GameWorld.gotPlayer:
        #刷新玩家Buff时长
        gameObj.SetTickByType(ChConfig.TYPE_Player_Tick_Buff, 0)
        gameObj.SetPersistBuffTick(0)
        #刷新玩家Buff
        reFlashBuff = PlayerState.ProcessRefreshBuffState(gameObj, tick)
        #刷新玩家场景buff效果
        PlayerState.ProcessPlayerBuffEffect(gameObj, tick)
        #SkillShell.ProcessPersistBuff(gameObj, tick) # 定时处理的在每个时间节点有需要再开启,目前默认回合开始处理
        
        attrBuffResult, actBuffResult = PlayerState.ProcessRefreshActionBuffState(gameObj, tick)
        playerControl = PlayerControl.PlayerControl(gameObj)
@@ -311,7 +477,7 @@
    ## 回合制战斗实例结束重置
    if not gameObj:
        return
    gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnFightNum, 0)
    SetTimeline(gameObj, 0, 0)
    gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnBattleType, 0)
    GameObj.SetFaction(gameObj, 0)
    
@@ -324,6 +490,9 @@
    return
def RecycleObj(gameObj):
    ## 释放回合制战斗对象
    #灵宠跟召唤兽由主人回收时触发回收,不然会导致报错
    npcObjType = gameObj.GetGameNPCObjType()
    if npcObjType == IPY_GameWorld.gnotPet:
        #GameWorld.DebugLog("RecycleObj 灵宠不回收 objID=%s,npcObjType=%s,%s" % (gameObj.GetID(), npcObjType, gameObj.GetNPCID()))
@@ -333,9 +502,7 @@
        if curOwner and curOwner.GetGameObjType() == IPY_GameWorld.gotNPC:
            #GameWorld.DebugLog("RecycleObj 召唤兽主人是NPC不回收 objID=%s,npcObjType=%s,%s,ownerID=%s" % (gameObj.GetID(), npcObjType, gameObj.GetNPCID(), curOwner.GetID()))
            return
    if GameObj.GetHP(gameObj) <= 0:
        #GameWorld.DebugLog("RecycleObj 已死亡,不用重复回收 objID=%s,npcObjType=%s,%s" % (gameObj.GetID(), npcObjType, gameObj.GetNPCID()))
        return
    #GameWorld.DebugLog("RecycleObj: objID=%s,npcObjType=%s,%s" % (gameObj.GetID(), npcObjType, gameObj.GetNPCID()))
    NPCCommon.SetDeadEx(gameObj)
    return
@@ -370,18 +537,18 @@
    tagHP = GameObj.GetHP(tagObj)
    GameWorld.DebugLog("            curID-HP=(%s-%s),tagID-HP=(%s-%s)" % (curID, curHP, tagID, tagHP))
    if tagHP <= 0 or curHP <= 0:
        return
        return True
    
    # 反击,反击可打断连击,所以优先判断
    if CanAtkBack(curObj, tagObj):
        DoAttack(tagObj, curObj, tick)
        return
        return True
    
    # 连击
    if CanCombo(curObj, tagObj):
        DoAttack(curObj, tagObj, tick)
        
    return
    return True
def CanAtkBack(atkObj, defObj):
    ## 可否反击