hxp
2024-05-16 2bca56e5df150d46e0f218a4e1af5e3dd81a0bcb
10159 [新增]异兽入侵
12个文件已修改
2个文件已添加
573 ■■■■ 已修改文件
PySysDB/PySysDBPY.h 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/BillboardData.py 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldAlineInvade.py 65 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py 214 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBLogic.py 40 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_AlineInvade.py 168 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py 27 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py 15 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerBillboard.py 9 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
PySysDB/PySysDBPY.h
@@ -2949,3 +2949,13 @@
    list        EquipColorRateList;    //产出装备品质概率列表,[0品质万分率, 1品质万分率, ...]
    list        ExAwardItemRateList;    //每次砍树概率额外产出道具饼图,[[万分率,[物品ID,个数]], ...]
};
//异兽入侵
struct tagAlineInvade
{
    BYTE        _BoxNum;    //奖励盒子编号
    DWORD        NeedHurtValue;    //下个盒子所需伤血
    list        BoxAwardWeightList;    //本盒子奖励权重饼图[[权重, [物品ID,个数,是否拍品]], ...]
    dict        BossAttrPlusInfo;    //Boss在该盒子情况下属性强化
};
ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py
@@ -597,6 +597,7 @@
            ShareDefine.Def_BT_CharmWeek                : 100,           #魅力周榜
            ShareDefine.Def_BT_CharmDay                 : 100,           #魅力日榜
            ShareDefine.Def_BT_BossTrialSubmit          : 1000,          #boss凭证 (boss历练活动)
            ShareDefine.Def_BT_AlineInvade              : 1000,          #异兽入侵
            }
#排行榜保存类型(和BillboardType匹配), 默认保存, 如果不保存,可配置进去
ServerPython/CoreServerGroup/GameServer/Script/GM/Commands/BillboardData.py
@@ -25,7 +25,7 @@
        GameWorld.DebugAnswer(curPlayer, errInfo)
    GameWorld.DebugAnswer(curPlayer, "新增榜单假数据: BillboardData 类型 条数 比较值1 可选参数(比较值2 常规值1 常规值2)")
    GameWorld.DebugAnswer(curPlayer, "删除榜单假数据: BillboardData 类型")
    GameWorld.DebugAnswer(curPlayer, "榜单类型:0-战力,1-龙魂,2-灵瑶,4-等级,5-坐骑,6-灵宠,7-符印,8-脱机,9-境界,19-助战")
    GameWorld.DebugAnswer(curPlayer, "榜单类型:0-战力,1-龙魂,2-灵瑶,4-等级,5-坐骑,6-灵宠,7-符印,8-脱机,9-境界,19-助战,34-异兽")
    GameWorld.DebugAnswer(curPlayer, "开服活动榜类型:11-强化,12-坐骑,13-宝石,14-冲级,15-境界,16-战力,18-符印,20-神兵,21-充值,22-灵宠,24-灵根,25-升星")
    GameWorld.DebugAnswer(curPlayer, "运营活动榜类型:17-仙界盛典,23-仙界盛典2,33-boss凭证")
    GameWorld.DebugAnswer(curPlayer, "魅力榜单类型:30-总榜,31-周榜,32-日榜")
@@ -83,7 +83,7 @@
    for i in xrange(count):
        dataPlayerID = curDataCount + 1 + i
        dataPlayerName = "%s%s" % (FakeName, i)
        dataCmpValue1 = max(0, cmpValue1 - i)
        dataCmpValue1 = max(0, cmpValue1 - i) if not cmpValue2 else cmpValue1
        dataCmpValue2 = max(0, cmpValue2 - i)
        PlayerBillboard.UpdatePlayerBillboard(dataPlayerID, dataPlayerName, curPlayerOpInfo, billboardIndex, bType2, value1, value2, dataCmpValue1, autoSort, dataCmpValue2)
        
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldAlineInvade.py
New file
@@ -0,0 +1,65 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package GameWorldAlineInvade
#
# @todo:异兽入侵
# @author hxp
# @date 2024-05-16
# @version 1.0
#
# 详细描述: 异兽入侵
#
#-------------------------------------------------------------------------------
#"""Version = 2024-05-16 16:00"""
#-------------------------------------------------------------------------------
import GameWorld
import ShareDefine
import PlayerCompensation
import IpyGameDataPY
def DoOnDay():
    GiveDayHurtAward()
    return
def GiveDayHurtAward():
    GameWorld.Log("异兽入侵每日结算奖励")
    billBoard = GameWorld.GetBillboard().FindBillboard(ShareDefine.Def_BT_AlineInvade)
    if not billBoard:
        return
    billboradAwardDict = IpyGameDataPY.GetFuncEvalCfg("AlineInvade", 2, {})
    orderList = []
    for orderStr in billboradAwardDict.keys():
        orderList.append(int(orderStr))
    orderList.sort()
    GameWorld.Log("    奖励名次列表: %s" % orderList)
    awardOrder = orderList[0]
    billboardCount, billboardMaxCount = billBoard.GetCount(), billBoard.GetMaxCount()
    GameWorld.Log("    榜单数据数! billboardCount=%s,billboardMaxCount=%s" % (billboardCount, billboardMaxCount))
    for index in xrange(billboardCount):
        billBoardData = billBoard.At(index)
        if not billBoardData:
            continue
        order = index + 1
        if order > awardOrder:
            nextOrderIndex = orderList.index(awardOrder) + 1
            if nextOrderIndex >= len(orderList):
                break
            awardOrder = orderList[nextOrderIndex]
        playerID = billBoardData.GetID()
        #GameWorld.DebugLog("order=%s,playerID=%s,awardOrder=%s" % (order, playerID, awardOrder))
        if playerID < 10000:
            continue
        awardList = billboradAwardDict[str(awardOrder)]
        PlayerCompensation.SendMailByKey("AlineInvadeHurtRank", [playerID], awardList, [order])
    billBoard.Clear()
    return
ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldProcess.py
@@ -112,6 +112,7 @@
import CrossBillboard
import CrossChampionship
import GameWorldMineArea
import GameWorldAlineInvade
#---------------------------------------------------------------------
#---------------------------------------------------------------------
@@ -184,6 +185,8 @@
    PlayerLove.DoOnDay()
    # 云购
    CrossLuckyCloudBuy.DoOnDay()
    # 异兽入侵
    GameWorldAlineInvade.DoOnDay()
    return
def OnDayEx(tick):
ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py
@@ -809,9 +809,10 @@
    Def_BT_CharmWeek, #魅力周榜
    Def_BT_CharmDay, #魅力日榜
    Def_BT_BossTrialSubmit,                   #提交boss凭证榜 (boss历练活动)
    Def_BT_AlineInvade,                       #异兽入侵
    
    Def_BT_Max, #排行榜最大类型
) = range(0, 33 + 2)
) = range(0, 34 + 2)
''' 跨服排行榜类型, 从 150 开始
与本服榜单存储的是不一样的数据库表格,理论上类型可以和本服榜单类型重复,为了做下区分防误导,跨服榜单从 150 开始
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/TurnAttack.py
@@ -54,6 +54,72 @@
RebornType_ShentongSkill, # 神通复活 - 由主角自己触发,灵宠触发的神通技能归为灵宠复活
) = range(1, 1 + 3)
Def_FactionA = 1
Def_FactionB = 2
class TurnFightBattle():
    def __init__(self):
        self.CleaerBat()
        return
    def CleaerBat(self):
        self.curPlayer = None
        self.mapID = 0
        self.funcLineID = 0
        self.tagType = 0
        self.tagID = 0
        self.valueList = []
        self.factionObjListDict = {} # 阵营所有战斗实例,包含主体、灵宠 {阵营:[obj, ...], ...}
        self.factionMainObjListDict = {} # 阵营所有战斗主体, {阵营:[obj, ...], ...}
        self.objTotalHurtDict = {} # 战斗实例累计输出 {objID:totalHurtValue, ...}
        self.factionTotalHurtDict = {} # 阵营累计输出 {faction:totalHurtValue, ...}
        self.fbData = {} # 战斗关联副本自定义相关数据 {key:value, ...}
        return
    def SetBattle(self, curPlayer, mapID, funcLineID, tagType, tagID, valueList):
        self.curPlayer = curPlayer
        self.mapID = mapID
        self.funcLineID = funcLineID
        self.tagType = tagType
        self.tagID = tagID
        self.valueList = valueList
        return
    def SetFactionObj(self, faction, objList, mainObjList):
        self.factionObjListDict[faction] = objList
        self.factionMainObjListDict[faction] = mainObjList
        return
    def GetTagMainObj(self):
        ## 获取对方战斗主体
        if Def_FactionB not in self.factionMainObjListDict:
            return
        mainObjList = self.factionMainObjListDict[Def_FactionB]
        if not mainObjList:
            return
        return mainObjList[0]
    def AddObjHurtValue(self, curObj, hurtValue):
        objID = curObj.GetID()
        faction = GameObj.GetFaction(curObj)
        updHurtValue = self.objTotalHurtDict.get(objID, 0) + hurtValue
        self.objTotalHurtDict[objID] = updHurtValue
        factionHurtValue = self.factionTotalHurtDict.get(faction, 0) + hurtValue
        self.factionTotalHurtDict[faction] = factionHurtValue
        # 玩家阵营
        if faction == Def_FactionA:
            FBLogic.OnTurnFightPlayerFactionHurt(self.curPlayer, self.mapID, self.funcLineID, curObj, hurtValue, factionHurtValue)
        return updHurtValue
g_turnFightBattle = TurnFightBattle()
def GetTurnFightBattle():
    global g_turnFightBattle
    return g_turnFightBattle
def GetObjName(gameObj):
    objName = gameObj.GetName()
    faction = GameObj.GetFaction(gameObj)
@@ -61,7 +127,7 @@
    curID = gameObj.GetDictByKey(ChConfig.Def_NPC_Dict_MirrorPlayerID)
    if not curID and gameObj.GetGameObjType() == IPY_GameWorld.gotNPC:
        curID = gameObj.GetNPCID()
    return "%s%s %s[%s-%s]" % ("A" if faction == 1 else "B", fightPlaceNum, objName, gameObj.GetID(), curID)
    return "%s%s %s[%s-%s]" % ("A" if faction == Def_FactionA else "B", fightPlaceNum, objName, gameObj.GetID(), curID)
#// B4 10 回合制战斗 #tagCMTurnFight
#
@@ -178,62 +244,12 @@
        factionInfoB = {"npcID":npcID, "pet":petCacheInfo, "skillIDExList":skillIDExList}
    else:
        return
    fightRet = ProcessAutoTurnFight(mapID, funcLineID, tagType, tagID, factionInfoA, factionInfoB, tick, curPlayer)
    if not fightRet:
        return
    isWin, turnNum, turnMax, factionTotalHurtDict, playbackID = fightRet
    
    needSendGameServer, awardItemList, overInfoEx = False, [], {}
    overRet = FBLogic.OnTurnFightOver(curPlayer, mapID, funcLineID, tagType, tagID, valueList, fightRet)
    if overRet != None:
        needSendGameServer, awardItemList, overInfoEx = overRet
    if needSendGameServer or mapID in ChConfig.Def_TFMapID_SendToGameServer:
        SendToGameServer_TurnFight(curPlayer, "TurnFightOver", [mapID, funcLineID, tagType, tagID, valueList, fightRet, awardItemList])
    overMsg = {"isWin":isWin, FBCommon.Over_itemInfo:FBCommon.GetJsonItemList(awardItemList), "totalHurt":factionTotalHurtDict.get(1, 0)}
    playbackID and overMsg.update({"playbackID":playbackID})
    overInfoEx and overMsg.update(overInfoEx)
    SyncTurnFightState(curPlayer, mapID, funcLineID, tagType, tagID, FightState_Award, turnNum, turnMax, overMsg)
    return
def GetPlayerFactionInfoByCache(playerID):
    ## 根据玩家缓存数据获取对阵玩家阵营信息字典
    PropDict, PlusDict = PlayerViewCacheTube.GetPlayerPropPlusDictByID(playerID, True) # 从缓存中获取,强刷一次最新属性
    skillIDList = []
    SkillInfo = PlusDict.get("SkillInfo", {})
    for _, skillLVDict in SkillInfo.items():
        for skillID, _ in skillLVDict.items():
            skillID = GameWorld.ToIntDef(skillID)
            skillData = GameWorld.GetGameData().GetSkillBySkillID(skillID)
            if not skillData:
                continue
            skillIDList.append(skillID)
    return {"playerID":playerID, "pet":PlusDict.get("Pet"), "skillIDList":skillIDList, "ModelMark":PropDict.get("ModelMark", 0)}
def ProcessAutoTurnFight(mapID, funcLineID, tagType, tagID, factionInfoA, factionInfoB, tick, syncPlayer=None, isSavePlayback=False):
    ''' 处理自动回合战斗过程,仅做战斗流程处理,不做及其他功能逻辑
    @param mapID: 可视为功能ID
    @param funcLineID: 对功能ID的扩展
    @param factionInfoA: A方阵营信息,playerID 和 npcID 二选一 {"playerID":主体玩家镜像ID, "npcID":主体NPCID, "pet":[{出战灵宠信息兼容玩家缓存的灵宠信息k:v, ...}, ...]}
    @param factionInfoB: B方阵营信息
    @param syncPlayer: 需要通知的玩家,可能为None,注意仅做通知用,该玩家可能和AB阵营无任何关系
    @param isSavePlayback: 是否保存战斗回放
    @return: None-无结果;或 (isWin, turnNum, turnMax, factionTotalHurtDict)
                        isWin: 是否获胜
                        turnNum: 打了几回合
                        factionTotalHurtDict: 双方伤血统计
    '''
    if syncPlayer:
        syncPlayer.SetCanAttack(False) # 该玩家设置为不可被攻击
        playerID = syncPlayer.GetPlayerID()
        sightLevel, posX, posY = playerID, syncPlayer.GetPosX(), syncPlayer.GetPosY()
    else:
        playerID = 0
        sightLevel, posX, posY = 99, 192, 109 # 系统默认处理的层级及坐标
    factionA, factionB, mainRolePlace = 1, 2, 1
    curPlayer.SetCanAttack(False) # 该玩家设置为不可被攻击
    playerID = curPlayer.GetPlayerID()
    sightLevel, posX, posY = playerID, curPlayer.GetPosX(), curPlayer.GetPosY()
    factionA, factionB, mainRolePlace = Def_FactionA, Def_FactionB, 1
    objRetA = __SummonFactionObjs(factionA, mainRolePlace, factionInfoA, sightLevel, posX, posY)
    objRetB = __SummonFactionObjs(factionB, mainRolePlace, factionInfoB, sightLevel, posX, posY)
    objA, petObjListA, factionSyncInfoA = objRetA if objRetA else (None, [], {})
@@ -243,6 +259,11 @@
        for gameObj in fightObjList:
            TurnFightObjOverReset(gameObj, tick)
        return
    tfBattle = GetTurnFightBattle()
    tfBattle.CleaerBat()
    tfBattle.SetBattle(curPlayer, mapID, funcLineID, tagType, tagID, valueList)
    playerIDA = objA.GetDictByKey(ChConfig.Def_NPC_Dict_MirrorPlayerID) # 可能为0,非玩家镜像时为0
    playerIDB = objB.GetDictByKey(ChConfig.Def_NPC_Dict_MirrorPlayerID) # 可能为0,非玩家镜像时为0
    
@@ -255,6 +276,8 @@
    factionListA = petObjListA + [objA]
    factionListB = petObjListB + [objB]
    atkFactionList = [factionListA, factionListB]
    tfBattle.SetFactionObj(factionA, factionListA, [objA])
    tfBattle.SetFactionObj(factionB, factionListB, [objB])
    
    # 设置战斗主体
    objA.SetDict(ChConfig.Def_Obj_Dict_TurnEnemyID, objB.GetID())
@@ -266,8 +289,8 @@
            if not gameObj:
                continue
            faction = GameObj.GetFaction(gameObj)
            tagGameObj = objB if faction == 1 else objA
            TurnFightObjStartInit(playerID, gameObj, tagGameObj, tick)
            tagGameObj = objB if faction == Def_FactionA else objA
            TurnFightObjStartInit(mapID, playerID, gameObj, tagGameObj, tick)
            
    #一个回合攻击顺序,为了后续逻辑统一,都是先确定好顺序
    sortType = 2 # 攻击顺序排序方式
@@ -284,19 +307,19 @@
            for factionObjList in atkFactionList:
                fightObjList.append(factionObjList[i])
                
    SyncTurnFightState(syncPlayer, mapID, funcLineID, tagType, tagID, FightState_PrepareOK, msg=[factionSyncInfoA, factionSyncInfoB])
    SyncTurnFightState(curPlayer, mapID, funcLineID, tagType, tagID, FightState_PrepareOK, msg=[factionSyncInfoA, factionSyncInfoB])
    
    isWin = None
    for turnNum in range(1, turnMax + 1):
        GameWorld.DebugLog("【----- 回合制战斗轮次: %s -----】" % turnNum)
        SyncTurnFightState(syncPlayer, mapID, funcLineID, tagType, tagID, FightState_Fighting, turnNum, turnMax)
        SyncTurnFightState(curPlayer, mapID, funcLineID, tagType, tagID, FightState_Fighting, turnNum, turnMax)
        
        # 回合开始: 做一些每回合重置逻辑或者某些根据回合触发的效果等
        for gameObj in fightObjList:
            if not gameObj:
                continue
            faction = GameObj.GetFaction(gameObj)
            tagGameObj = objB if faction == 1 else objA
            tagGameObj = objB if faction == Def_FactionA else objA
            TurnFightObjPerTurnStart(gameObj, tagGameObj, turnNum, tick)
            
        isWin = CheckIswin(objA, objB)
@@ -314,7 +337,7 @@
                
            objType = gameObj.GetGameObjType()
            objID = gameObj.GetID()
            SyncTurnFightObjAction(syncPlayer, turnNum, objType, objID)
            SyncTurnFightObjAction(curPlayer, turnNum, objType, objID)
            
            if GameObj.GetHP(gameObj) <= 0:
                # 复活时机在自己行动节点
@@ -325,7 +348,7 @@
            objName = GetObjName(gameObj)
            curHP = GameObj.GetHP(gameObj)
            
            tagGameObj = objB if faction == 1 else objA
            tagGameObj = objB if faction == Def_FactionA else objA
            tagObjType = tagGameObj.GetGameObjType()
            tagObjID = tagGameObj.GetID()
            tagHP = GameObj.GetHP(tagGameObj)
@@ -343,20 +366,19 @@
        if isWin != None:
            break
        
    isWin = FBLogic.OnTurnFightIsWin(curPlayer, mapID, funcLineID, tagType, tagID, valueList, isWin)
    GameWorld.DebugLog("--- 战斗结束处理 --- isWin=%s" % isWin)
    isWin = 1 if isWin else 0
    
    # 统计总伤害
    factionTotalHurtDict = {}
    factionTotalHurtDict = tfBattle.factionTotalHurtDict
    for gameObj in fightObjList:
        if not gameObj:
            continue
        faction = GameObj.GetFaction(gameObj)
        objName = GetObjName(gameObj)
        objID = gameObj.GetID()
        totalHurtEx = gameObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnTotalHurtEx) * ChConfig.Def_PerPointValue
        totalHurt = gameObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnTotalHurt) + totalHurtEx
        factionTotalHurtDict[faction] = factionTotalHurtDict.get(faction, 0) + totalHurt
        totalHurt = tfBattle.objTotalHurtDict.get(objID, 0)
        GameWorld.DebugLog("%s objID=%s,faction=%s, 总输出: %s" % (objName, objID, faction, totalHurt))
    for faction, totalHurt in factionTotalHurtDict.items():
        GameWorld.DebugLog("faction=%s, 阵营总输出: %s" % (faction, totalHurt))
@@ -364,19 +386,51 @@
    GameWorld.DebugLog("A剩余血量: %s / %s" % (GameObj.GetHP(objA), GameObj.GetMaxHP(objA)))
    GameWorld.DebugLog("B剩余血量: %s / %s" % (GameObj.GetHP(objB), GameObj.GetMaxHP(objB)))
    
    SyncTurnFightState(syncPlayer, mapID, funcLineID, tagType, tagID, FightState_FightEnd, turnNum, turnMax)
    for gameObj in fightObjList:
        TurnFightObjOverReset(gameObj, tick)
    SyncTurnFightState(curPlayer, mapID, funcLineID, tagType, tagID, FightState_FightEnd, turnNum, turnMax)
        
    playbackID = 0 # 战斗回放ID,可根据该ID查看回放
    #playbackInfo = "" # 战斗回放信息
    if isSavePlayback:
        pass
    #if isSavePlayback:
    #    pass
    
    GameWorld.DebugLog("===== 回合制战斗结束: mapID=%s,funcLineID=%s,playerIDA=%s,playerIDB=%s,isWin=%s" 
                       % (mapID, funcLineID, playerIDA, playerIDB, isWin))
    return isWin, turnNum, turnMax, factionTotalHurtDict, playbackID
    # 战斗结束后处理
    fightRet = [isWin, turnNum, turnMax, factionTotalHurtDict, playbackID]
    needSendGameServer, awardItemList, overInfoEx = False, [], {}
    overRet = FBLogic.OnTurnFightOver(curPlayer, mapID, funcLineID, tagType, tagID, valueList, fightRet)
    if overRet != None:
        needSendGameServer, awardItemList, overInfoEx = overRet
    if needSendGameServer or mapID in ChConfig.Def_TFMapID_SendToGameServer:
        SendToGameServer_TurnFight(curPlayer, "TurnFightOver", [mapID, funcLineID, tagType, tagID, valueList, fightRet, awardItemList])
    overMsg = {"isWin":isWin, FBCommon.Over_itemInfo:FBCommon.GetJsonItemList(awardItemList), "totalHurt":factionTotalHurtDict.get(Def_FactionA, 0)}
    playbackID and overMsg.update({"playbackID":playbackID})
    overInfoEx and overMsg.update(overInfoEx)
    SyncTurnFightState(curPlayer, mapID, funcLineID, tagType, tagID, FightState_Award, turnNum, turnMax, overMsg)
    # 都处理完毕了,回收对象,重置数据
    for gameObj in fightObjList:
        TurnFightObjOverReset(gameObj, tick)
    tfBattle.CleaerBat()
    return
def GetPlayerFactionInfoByCache(playerID):
    ## 根据玩家缓存数据获取对阵玩家阵营信息字典
    PropDict, PlusDict = PlayerViewCacheTube.GetPlayerPropPlusDictByID(playerID, True) # 从缓存中获取,强刷一次最新属性
    skillIDList = []
    SkillInfo = PlusDict.get("SkillInfo", {})
    for _, skillLVDict in SkillInfo.items():
        for skillID, _ in skillLVDict.items():
            skillID = GameWorld.ToIntDef(skillID)
            skillData = GameWorld.GetGameData().GetSkillBySkillID(skillID)
            if not skillData:
                continue
            skillIDList.append(skillID)
    return {"playerID":playerID, "pet":PlusDict.get("Pet"), "skillIDList":skillIDList, "ModelMark":PropDict.get("ModelMark", 0)}
def __SummonFactionObjs(faction, mainRolePlace, objInfo, sightLevel, posX, posY):
    '''召唤阵营战斗实例
@@ -608,15 +662,14 @@
    gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnFightTimeline, turnNum * 100 + actionNum)
    return
def TurnFightObjStartInit(playerID, gameObj, tagObj, tick):
def TurnFightObjStartInit(mapID, playerID, gameObj, tagObj, tick):
    ## 回合制战斗实例初始化
    if not gameObj:
        return
    mainRolePlace = gameObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnFightMainRolePlace)
    gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnFightMapID, mapID)
    gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnFightID, playerID)
    gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnRebornCount, 0)
    gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnTotalHurt, 0)
    gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnTotalHurtEx, 0)
    gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnSkillSuccessPetState, 0)
    gameObj.SetDict(ChConfig.Def_Obj_Dict_TurnAttackOverPetState, 0)
    SetTimeline(gameObj, 1, 0)
@@ -839,15 +892,12 @@
def AddTurnObjHurtValue(curObj, tagObj, hurtType, hurtValue, lostHP, curSkill=None):
    if not curObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnFightTimeline):
        return
    tfBattle = GetTurnFightBattle()
    curID = curObj.GetID()
    tagID = tagObj.GetID()
    skillID = curSkill.GetSkillID() if curSkill else 0
    totalHurtEx = curObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnTotalHurtEx) * ChConfig.Def_PerPointValue
    totalHurt = curObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnTotalHurt) + totalHurtEx
    if curID != tagID:
        totalHurt += hurtValue
        curObj.SetDict(ChConfig.Def_Obj_Dict_TurnTotalHurt, totalHurt % ChConfig.Def_PerPointValue)
        curObj.SetDict(ChConfig.Def_Obj_Dict_TurnTotalHurtEx, totalHurt / ChConfig.Def_PerPointValue)
        totalHurt = tfBattle.AddObjHurtValue(curObj, hurtValue)
        GameWorld.DebugLog("        伤血: curTD=%s,tagID=%s,skillID=%s,hurtType=%s,hurtValue=%s,totalHurt=%s,lostHP=%s,tagHP=%s" 
                           % (curID, tagID, skillID, hurtType, hurtValue, totalHurt, lostHP, GameObj.GetHP(tagObj)))
    else:
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
@@ -1883,6 +1883,7 @@
#回合战斗自定义地图ID
Def_TFMapID_MineArea = 1 # 福地 1
Def_TFMapID_Adventure = 5000 # 冒险
Def_TFMapID_AlineInvade = 5010 # 异兽入侵
#回合战斗自定义地图需要发送GameServer的列表
Def_TFMapID_SendToGameServer = [Def_TFMapID_MineArea, Def_FBMapID_ArenaBattle]
@@ -2018,6 +2019,7 @@
                'Love':[Def_FBMapID_Love],#情缘副本
                'CrossBattlefield':[Def_FBMapID_CrossBattlefield], #跨服战场
                'MineArea':[Def_TFMapID_MineArea], #福地
                'AlineInvade':[Def_TFMapID_AlineInvade], #异兽入侵
                'Adventure':[Def_TFMapID_Adventure], #冒险
                }
@@ -3101,14 +3103,13 @@
#---Obj字典-------
Def_Obj_Dict_Faction = 'Faction' # 所属阵营
Def_Obj_Dict_TurnFightID = 'TurnFightID' # 回合制战斗所属玩家ID
Def_Obj_Dict_TurnFightMapID = 'TurnFightMapID' # 回合制战斗所属MapID
Def_Obj_Dict_TurnFightTimeline = 'TurnFightTimeline' # 回合制战斗时间线: 回合数*100+行动编号节点
Def_Obj_Dict_TurnFightMainRolePlace = 'TurnFightMainRolePlace' # 回合制战斗主体位置,可用于支持单阵营多主体,最终胜负由主体存活状态决定
Def_Obj_Dict_TurnRebornCount = 'TurnRebornCount' # 回合战斗已复活次数
Def_Obj_Dict_TurnComboNum = 'TurnComboNum' # 本回合已累计连击次数
Def_Obj_Dict_TurnAtkBackNum = 'TurnAtkBackNum' # 本回合已累计反击次数
Def_Obj_Dict_TurnBattleType = 'TurnBattleType' # 本次攻击战斗类型:TurnBattleType_xxx
Def_Obj_Dict_TurnTotalHurt = 'TurnTotalHurt' # 本回合制战斗总伤害,求余亿部分
Def_Obj_Dict_TurnTotalHurtEx = 'TurnTotalHurtEx' # 本回合制战斗总伤害,整除亿部分
Def_Obj_Dict_FightPetPlaceNum = 'FightPetPlaceNum' # 出战灵宠上阵位置,1~n
Def_Obj_Dict_FightPetQuality = 'FightPetQuality' # 出战灵宠品质
Def_Obj_Dict_TurnEnemyID = 'TurnEnemyID' # 回合制战斗对手实例ID
@@ -4453,6 +4454,10 @@
Def_PDict_MineTreasureState = "MineTreasureState" # 聚宝盆激活状态,按类型位运算记录是否已激活
Def_PDict_MineTreasureAward = "MineTreasureAward" # 聚宝盆奖励状态,按类型位运算记录是否已领取
Def_PDict_MineTreasureProgess = "MineTreasureProgess_%s" # 聚宝盆进度值,参数(聚宝盆类型)
#异兽入侵
Def_PDict_AlineInvadeHurtTotalEx = "AlineInvadeHurtTotalEx" #本日累计伤害,整除亿部分
Def_PDict_AlineInvadeHurtTotal = "AlineInvadeHurtTotal" #本日累计伤害,求余亿部分
#-------------------------------------------------------------------------------
#可以从07 41封包购买的背包类型,和对应字典{背包类型:[字典key, 默认格子数]}
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBLogic.py
@@ -1263,6 +1263,22 @@
        return {}
    return ret
def GetLogicMapID(curObj=None):
    if curObj:
        tfMapID = curObj.GetDictByKey(ChConfig.Def_Obj_Dict_TurnFightMapID)
        if tfMapID:
            return tfMapID
    return GameWorld.GetMap().GetMapID()
def CalcFBNPCPlusAttr(curNPC):
    ## 副本NPC增加属性
    # @return: 增加的属性信息 {attrID:value, ...}
    do_FBLogic_ID = __GetFBLogic_MapID(GetLogicMapID(curNPC))
    callFunc = GameWorld.GetExecFunc(FBProcess, "GameLogic_%s.%s" % (do_FBLogic_ID, "CalcFBNPCPlusAttr"))
    if not callFunc:
        return {}
    return callFunc(curNPC)
## 获得副本LoadIng时间
#  @param 占领人
#  @param 被占领的NPC
@@ -2437,6 +2453,18 @@
    
    return callFunc(curPlayer, mapID, funcLineID, tagType, tagID, valueList)
def OnTurnFightIsWin(curPlayer, mapID, funcLineID, tagType, tagID, valueList, isWin):
    ## 回合战斗副本是否获胜
    do_FBLogic_ID = __GetFBLogic_MapID(mapID)
    callFunc = GameWorld.GetExecFunc(FBProcess, "GameLogic_%s.%s" % (do_FBLogic_ID, "OnTurnFightIsWin"))
    if callFunc == None:
        return isWin
    return callFunc(curPlayer, mapID, funcLineID, tagType, tagID, valueList, isWin)
def OnTurnFightOver(curPlayer, mapID, funcLineID, tagType, tagID, valueList, fightRet):
    ## 回合战斗结束
    # @return: 是否需要同步GameServer, 奖励列表, 同步结果信息
@@ -2462,4 +2490,16 @@
    
    return callFunc(curPlayer, mapID, funcLineID, tagType, tagID, valueList, fightRet, awardItemList, ret)
def OnTurnFightPlayerFactionHurt(curPlayer, mapID, funcLineID, hurtObj, hurtValue, factionHurtValue):
    ## 回合战斗玩家阵营伤害变更
    do_FBLogic_ID = __GetFBLogic_MapID(mapID)
    callFunc = GameWorld.GetExecFunc(FBProcess, "GameLogic_%s.%s" % (do_FBLogic_ID, "OnTurnFightPlayerFactionHurt"))
    if callFunc == None:
        return
    return callFunc(curPlayer, mapID, funcLineID, hurtObj, hurtValue, factionHurtValue)
    
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_AlineInvade.py
New file
@@ -0,0 +1,168 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package GameWorldLogic.FBProcess.GameLogic_AlineInvade
#
# @todo:异兽入侵
# @author hxp
# @date 2024-05-16
# @version 1.0
#
# 详细描述: 异兽入侵
#
#-------------------------------------------------------------------------------
#"""Version = 2024-05-16 16:00"""
#-------------------------------------------------------------------------------
import ChConfig
import NPCCommon
import TurnAttack
import IpyGameDataPY
import PlayerBillboard
import ItemControler
import PlayerControl
import GameWorld
import FBCommon
def OnFBPlayerOnDay(curPlayer):
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_AlineInvadeHurtTotalEx, 0)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_AlineInvadeHurtTotal, 0)
    return
def OnTurnFightRequest(curPlayer, mapID, funcLineID, tagType, tagID, valueList):
    ## 回合战斗请求 - 地图验证
    weekNPCIDList = IpyGameDataPY.GetFuncEvalCfg("AlineInvade", 1)
    curTime = GameWorld.GetCurrentTime()
    curWeekday = curTime.weekday()
    bossID = weekNPCIDList[curWeekday % len(weekNPCIDList)]
    if tagType != ChConfig.TurnBattle_TagType_NPC or tagID != bossID:
        GameWorld.ErrLog("异兽入侵目标bossID错误,无法挑战! curWeekday=%s,bossID=%s,tagType=%s,tagID=%s"
                         % (curWeekday, bossID, tagType, tagID), curPlayer.GetPlayerID())
        return False
    return True
def OnTurnFightPlayerFactionHurt(curPlayer, mapID, funcLineID, hurtObj, hurtValue, factionHurtValue):
    ## 回合战斗玩家阵营伤害变更
    tfBattle = TurnAttack.GetTurnFightBattle()
    fbData = tfBattle.fbData
    boxNum = fbData.get("boxNum", 0) # 当前盒子数
    fbData["boxHurt"] = boxHurt = fbData.get("boxHurt", 0) + hurtValue # 当前盒子已累计伤害
    ipyData = IpyGameDataPY.GetIpyGameData("AlineInvade", boxNum)
    if not ipyData:
        return
    needHurtValue = ipyData.GetNeedHurtValue()
    isBoxNumChange = False
    if boxHurt >= needHurtValue:
        isBoxNumChange = True
        boxHurt = factionHurtValue
        ipyDataMgr = IpyGameDataPY.IPY_Data()
        for index in range(ipyDataMgr.GetAlineInvadeCount()):
            ipyData = ipyDataMgr.GetAlineInvadeByIndex(index)
            boxNum = ipyData.GetBoxNum()
            needHurtValue = ipyData.GetNeedHurtValue()
            if boxHurt >= needHurtValue:
                boxHurt -= needHurtValue
            else:
                break
    fbData["boxNum"] = boxNum
    fbData["boxHurt"] = boxHurt
    fbData["totalHurt"] = factionHurtValue
    helpDict = {FBCommon.Over_dataMapID:tfBattle.mapID, FBCommon.Over_dataMapID:tfBattle.funcLineID}
    helpDict.update(fbData)
    FBCommon.Notify_FBHelp(curPlayer, helpDict)
    if not isBoxNumChange:
        return
    tagNPC = tfBattle.GetTagMainObj()
    if tagNPC:
        GameWorld.DebugLog("boxNum变更: %s" % (boxNum))
        NPCCommon.NPCControl(tagNPC).RefreshNPCAttrState()
    return
def CalcFBNPCPlusAttr(curNPC):
    ## 副本NPC增加属性
    # @return: 增加的属性信息 {attrID:value, ...}
    plusAttrDict = {}
    tfBattle = TurnAttack.GetTurnFightBattle()
    boxNum = tfBattle.fbData.get("boxNum", 0)
    ipyData = IpyGameDataPY.GetIpyGameData("AlineInvade", boxNum)
    if ipyData:
        plusAttrDict = ipyData.GetBossAttrPlusInfo()
    return plusAttrDict
def OnTurnFightIsWin(curPlayer, mapID, funcLineID, tagType, tagID, valueList, isWin):
    ## 回合战斗副本是否获胜
    if isWin == False:
        return isWin
    # 只要不被击败就算赢
    return True
def OnTurnFightOver(curPlayer, mapID, funcLineID, tagType, tagID, valueList, fightRet):
    ## 回合战斗结束
    # @return: 是否需要同步GameServer, 奖励列表, 同步结果信息
    needSendGameServer = False
    isWin = fightRet[0]
    # 无论胜利与否都算参与,扣次数
    FBCommon.OnFBJoin(curPlayer, mapID, funcLineID)
    FBCommon.AddEnterFBCount(curPlayer, ChConfig.Def_TFMapID_AlineInvade)
    tfBattle = TurnAttack.GetTurnFightBattle()
    fbData = tfBattle.fbData
    playerID = curPlayer.GetPlayerID()
    GameWorld.DebugLog("异兽入侵结算: isWin=%s,fbData=%s" % (isWin, fbData), playerID)
    boxNum = fbData.get("boxNum", 0) # 当前盒子数
    totalHurt = fbData.get("totalHurt", 0) # 总伤害
    awardItemDict = {}
    ipyDataMgr = IpyGameDataPY.IPY_Data()
    for index in range(ipyDataMgr.GetAlineInvadeCount()):
        ipyData = ipyDataMgr.GetAlineInvadeByIndex(index)
        if boxNum < ipyData.GetBoxNum():
            break
        awardWeightList = ipyData.GetBoxAwardWeightList()
        if not awardWeightList:
            continue
        awardItem = GameWorld.GetResultByWeightList(awardWeightList)
        if not awardItem:
            continue
        itemID = awardItem[0]
        itemCount = awardItem[1]
        awardItemDict[itemID] = awardItemDict.get(itemID, 0) + itemCount
    isAuctionItem = 0
    awardItemList = []
    for itemID, itemCount in awardItemDict.items():
        awardItemList.append([itemID, itemCount, isAuctionItem])
    ItemControler.GivePlayerItemOrMail(curPlayer, awardItemList, event=["AlineInvade", False, {"boxNum":boxNum, "totalHurt":totalHurt}])
    # 同步本日累计伤害榜单
    totalHurtTodayEx = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AlineInvadeHurtTotalEx)
    totalHurtToday = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AlineInvadeHurtTotal)
    totalHurtToday += totalHurtTodayEx * ChConfig.Def_PerPointValue
    updTotalHurtToday = totalHurtToday + totalHurt
    updTotalHurtTodayEx = updTotalHurtToday / ChConfig.Def_PerPointValue
    updTotalHurtToday = updTotalHurtToday % ChConfig.Def_PerPointValue
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_AlineInvadeHurtTotalEx, updTotalHurtTodayEx)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_AlineInvadeHurtTotal, updTotalHurtToday)
    GameWorld.DebugLog("更新今日累伤: totalHurtToday=%s,addHurt=%s,updTotalHurtTodayEx=%s,updTotalHurtToday=%s"
                       % (totalHurtToday, totalHurt, updTotalHurtTodayEx, updTotalHurtToday), playerID)
    PlayerBillboard.UpdateAlineInvadeBillboard(curPlayer)
    overInfoEx = fbData
    return needSendGameServer, awardItemList, overInfoEx
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
@@ -2286,6 +2286,13 @@
                        ("list", "EquipColorRateList", 0),
                        ("list", "ExAwardItemRateList", 0),
                        ),
                "AlineInvade":(
                        ("BYTE", "BoxNum", 1),
                        ("DWORD", "NeedHurtValue", 0),
                        ("list", "BoxAwardWeightList", 0),
                        ("dict", "BossAttrPlusInfo", 0),
                        ),
                }
@@ -5682,6 +5689,18 @@
    def GetLVUPNeedTime(self): return self.attrTuple[2] # 升级下一级所需所需秒 DWORD
    def GetEquipColorRateList(self): return self.attrTuple[3] # 产出装备品质概率列表,[0品质万分率, 1品质万分率, ...] list
    def GetExAwardItemRateList(self): return self.attrTuple[4] # 每次砍树概率额外产出道具饼图,[[万分率,[物品ID,个数]], ...] list
# 异兽入侵
class IPY_AlineInvade():
    def __init__(self):
        self.attrTuple = None
        return
    def GetBoxNum(self): return self.attrTuple[0] # 奖励盒子编号 BYTE
    def GetNeedHurtValue(self): return self.attrTuple[1] # 下个盒子所需伤血 DWORD
    def GetBoxAwardWeightList(self): return self.attrTuple[2] # 本盒子奖励权重饼图[[权重, [物品ID,个数,是否拍品]], ...] list
    def GetBossAttrPlusInfo(self): return self.attrTuple[3] # Boss在该盒子情况下属性强化 dict
def Log(msg, playerID=0, par=0):
@@ -5966,6 +5985,7 @@
        self.__LoadFileData("CustomAward", onlyCheck)
        self.__LoadFileData("Zhanling", onlyCheck)
        self.__LoadFileData("TreeLV", onlyCheck)
        self.__LoadFileData("AlineInvade", onlyCheck)
        Log("IPY_DataMgr ReloadOK! onlyCheck=%s" % onlyCheck)
        return
    
@@ -7766,6 +7786,13 @@
    def GetTreeLVByIndex(self, index):
        self.CheckLoadData("TreeLV")
        return self.ipyTreeLVCache[index]
    def GetAlineInvadeCount(self):
        self.CheckLoadData("AlineInvade")
        return self.ipyAlineInvadeLen
    def GetAlineInvadeByIndex(self, index):
        self.CheckLoadData("AlineInvade")
        return self.ipyAlineInvadeCache[index]
IPYData = IPY_DataMgr()
def IPY_Data(): return IPYData
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py
@@ -77,6 +77,8 @@
import GameObj
import ChNPC
import PassiveBuffEffMng
import CalcNoLineEffect
import CalcLineEffect
import random
import math
@@ -4157,6 +4159,19 @@
        else:
            DoNPCAttrStrengthen(curNPC, isReborn)
            
        #其他功能属性
        otherAttrList = [{} for _ in range(4)]
        #副本增加属性
        plusAttrDict = FBLogic.CalcFBNPCPlusAttr(curNPC)
        for attrID, attrValue in plusAttrDict.items():
            if not attrValue or not attrID:
                continue
            PlayerControl.CalcAttrDict_Type(attrID, attrValue, otherAttrList)
        #GameWorld.DebugLog("NPC plusAttrDict=%s" % plusAttrDict)
        #GameWorld.DebugLog("NPC otherAttrList=%s" % otherAttrList)
        CalcNoLineEffect.ChangeNPCAttrInNoLineEffectList(curNPC, otherAttrList[ChConfig.CalcAttr_BattleNoline])
        CalcLineEffect.ChangeNPCAttrInLineEffectList(curNPC, otherAttrList[ChConfig.CalcAttr_Battle])
        #计算buf对战斗属性的改变
        allAttrList = SkillShell.CalcBuffer_NPCBattleEffect(curNPC)
        
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerBillboard.py
@@ -52,6 +52,7 @@
    
    if isAll:
        UpdateRuneTowerBillboard(curPlayer)
        UpdateAlineInvadeBillboard(curPlayer)
        
        #UpdateTJGBillboard(curPlayer, minuteExp) 脱机效率可不更新
        
@@ -221,6 +222,14 @@
    UpdatePlayerBillboard(curPlayer, ShareDefine.Def_BT_TrialTower, passLV) 
    return
def UpdateAlineInvadeBillboard(curPlayer):
    ##更新异兽入侵排行榜
    totalHurtTodayEx = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AlineInvadeHurtTotalEx)
    totalHurtToday = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AlineInvadeHurtTotal)
    if not totalHurtToday and not totalHurtTodayEx:
        return
    UpdatePlayerBillboard(curPlayer, ShareDefine.Def_BT_AlineInvade, totalHurtTodayEx, totalHurtToday)
    return
def UpdateTJGBillboard(curPlayer, minuteExp):
    ##脱机效率榜
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
@@ -809,9 +809,10 @@
    Def_BT_CharmWeek, #魅力周榜
    Def_BT_CharmDay, #魅力日榜
    Def_BT_BossTrialSubmit,                   #提交boss凭证榜 (boss历练活动)
    Def_BT_AlineInvade,                       #异兽入侵
    
    Def_BT_Max, #排行榜最大类型
) = range(0, 33 + 2)
) = range(0, 34 + 2)
''' 跨服排行榜类型, 从 150 开始
与本服榜单存储的是不一样的数据库表格,理论上类型可以和本服榜单类型重复,为了做下区分防误导,跨服榜单从 150 开始
@@ -1207,7 +1208,7 @@
GameFuncID_FaQi = 199           # 法器
GameFuncID_LianTi = 207         # 炼体
GameFuncID_Championship = 210   # 排位
GameFuncID_MineArea = 223       # 福地
GameFuncID_MineArea = 223       # 福地
# 以下为暂时无用的
GameFuncID_Truck = 33           # 运镖
GameFuncID_RunDaily = 34        # 日常跑环