4762 【1.3】【后端】组队功能和助战积分优化;(初版,可测试基本流程)
24个文件已修改
5个文件已添加
1204 ■■■■■ 已修改文件
PyNetPack @ 7f19b0 2 ●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py 38 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py 7 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerControl.py 13 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFBHelpBattle.py 371 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFamily.py 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFriend.py 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerViewCache.py 26 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/AttackLogic/AttackCommon.py 6 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/AttackLogic/NormalNPC_Attack_NormalNPC.py 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/AttackLogic/Pet_Attack_NormalNPC.py 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/AttackLogic/Player_Attack_NormalNPC.py 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/AttackLogic/SummonNPC_Attack_NormalNPC.py 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py 19 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBLogic.py 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/FBHelpBattle.py 438 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_QueenRelics.py 67 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldProcess.py 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCAI/AIType_186.py 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCAI/AIType_20.py 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py 21 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_FBHelpBattle.py 50 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py 5 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
PyNetPack
New file
@@ -1 +1 @@
Subproject commit 0000000000000000000000000000000000000000
Subproject commit 7f19b08a9d54dfcd64e3858a5eebb3132db87fc9
ServerPython/CoreServerGroup/GameServer/Script/ChConfig.py
@@ -783,3 +783,41 @@
    fbtAll,             # 8所有
    fbtVsRoom,          # 9PK房间
) = range(10)
#VIP特权编号列表, 使用到具体特权时,修改下具体的命名
VIPPrivilegeList = (
VIPPrivilege_VIPKillNPCAddAtk, #1 vip法宝-加攻 - 废弃
VIPPrivilege_2, #2 vip宝石孔-废弃,读功能配置表 GemOpenVip
VIPPrivilege_TeamVIPBuff, #3 VIPbuff-攻守同盟, 组队属性加成
VIPPrivilege_BourseTax, #4 交易税减免额度(万分比)
VIPPrivilege_5, #5 私人秘书(消息推送)
VIPPrivilege_FreeTransport, #6 免费传送
VIPPrivilege_7, #7 自动仙盟任务 - 前端
VIPPrivilege_CollTimeReduceRate, #8 采集大师, 采旗时间减少万分比
VIPPrivilege_9, #9 百战不死 - 废弃
VIPPrivilege_FightExpRate,    #10 杀怪经验提升(万分比)
VIPPrivilege_EatItem,    #11 吞噬装备经验提升(万分比)
VIPPrivilege_NPCSPRate,    #12 杀怪SP值(万分比)
VIPPrivilege_MoneyPray,    #13 金币祈愿
VIPPrivilege_ExpPray, #14 经验祈愿
VIPPrivilege_15,    #15 个人boss额外次数 - 副本总表统一处理
VIPPrivilege_BossHome,    #16 boss之家层数权限
VIPPrivilege_17,    #17 灵宠副本购买次数 - 副本总表统一处理
VIPPrivilege_18,    #18 洗炼副本购买次数 - 副本总表统一处理
VIPPrivilege_19,    #19 虚无禁地额外次数 - 副本总表统一处理
VIPPrivilege_20,    #20 暮光神庙购买次数
VIPPrivilege_21,    #21 恶魔深渊购买次数 - 副本总表统一处理
VIPPrivilege_22,    #22 黑暗之门购买次数
VIPPrivilege_FamilyGoldPack,    #23 仙盟钻石红包
VIPPrivilege_BoursePwd,    #24 集市上架使用密码
VIPPrivilege_25,    #25 封魔坛购买次数 - 副本总表统一处理
VIPPrivilege_BoursePwd,    #26 VIP被动技能孔——VIP4专属被动技能孔
VIPPrivilege_BOSSHomeKillLimit,    #27 BOSS之家疲劳值上限
VIPPrivilege_FMTDouble,    #28 封魔坛双倍击杀
VIPPrivilege_29,    #29 娲皇遗迹购买次数 - 副本总表统一处理
VIPPrivilege_BindJadeWheel,    #30 绑玉转盘次数
VIPPrivilege_PrayElixir,    #31 丹药祈福次数
VIPPrivilege_32,    #32 封魔坛自动挑战
VIPPrivilege_XianyuanCoinUpperAdd,    #33 仙缘币上限加成
VIPPrivilege_XianyuanCoinAddPer,    #34 仙缘币获得倍率加成(万分比)
) = range(1, 35)
ServerPython/CoreServerGroup/GameServer/Script/Player/ChPlayer.py
@@ -65,6 +65,7 @@
import PlayerGeTui
import PlayerStore
import GameWorldActionControl
import PlayerFBHelpBattle
import GMT_CTG
import PyGameData
import GMShell
@@ -660,6 +661,9 @@
    elif packType == IPY_GameServer.CDBPlayerRefresh_ExAttr10:
        PlayerControl.SetChatBubbleBox(curPlayer, packValue)
        
    elif packType == IPY_GameServer.CDBPlayerRefresh_ExAttr11:
        PlayerControl.SetTodayXianyuanCoin(curPlayer, packValue)
    elif packType == IPY_GameServer.CDBPlayerRefresh_OperateInfo:
        curPlayer.SetOperateInfo(packValue);
    
@@ -673,7 +677,8 @@
    PlayerTeam.PlayerTeamMemberRefresh(curPlayer, packType, packValue, tick)
    #家族刷新
    PlayerFamily.PlayerRefresh(curPlayer, tick)
    #副本助战
    PlayerFBHelpBattle.UpdateCheckInPlayerInfoByRefresh(curPlayer, packType, packValue)
    return
## 玩家切换地图的响应(参数 -> 当前玩家,当前时间)
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerControl.py
@@ -202,10 +202,23 @@
#        return 0
    return curPlayer.GetVIPLv()
## 根据特权ID 和 VIP等级获得特权值
def GetPrivilegeValue(vipLV, privilegeID):
    if privilegeID not in ChConfig.VIPPrivilegeList:
        return 0
    vipMsg = IpyGameDataPY.GetIpyGameData('VipPrivilege', privilegeID)
    if not vipMsg:
        return 0
    return getattr(vipMsg, 'GetVIP%d' % vipLV)()
##聊天气泡框
def GetChatBubbleBox(curPlayer): return curPlayer.GetExAttr10()
def SetChatBubbleBox(curPlayer, value): return curPlayer.SetExAttr10(value)
##今日已获得仙缘币
def GetTodayXianyuanCoin(curPlayer): return curPlayer.GetExAttr11()
def SetTodayXianyuanCoin(curPlayer, value): return curPlayer.SetExAttr11(value)
## 是否脱机挂机状态
def GetIsTJG(curPlayer):
    if curPlayer.GetDictByKey(ChConfig.Def_OnlineType):
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFBHelpBattle.py
New file
@@ -0,0 +1,371 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package PlayerFBHelpBattle
#
# @todo:副本助战系统
# @author hxp
# @date 2018-11-24
# @version 1.0
#
# 详细描述: 副本助战系统
#
#-------------------------------------------------------------------------------
#"""Version = 2018-11-24 22:30"""
#-------------------------------------------------------------------------------
import PlayerFriend
import PlayerViewCache
import IpyGameDataPY
import PyGameData
import GameWorld
import random
import time
import IPY_GameServer
import PlayerControl
import ChConfig
import ChPyNetSendPack
import NetPackCommon
MaxRobotID = 100 # 最大机器人NPC定义ID
## 助战玩家简要信息
class HelpBattlePlayer():
    def __init__(self, playerID):
        self.playerID = playerID
        self.job = 0
        self.playerName = ""
        self.playerLV = 0
        self.realmLV = 0
        self.fightPower = 0
        self.familyID = 0
        self.vipLV = 0
        self.checkInCount = 0
        self.checkInTime = 0
        self.todayHelpCountDict = {} # 今天已助战次数 {(mapID, lineID):count, ...}, 通用次数时lineID默认为0
        self.todayXianyuanCoin = 0 # 今日已获得仙缘币
        return
## 助战记录 - 目前只记录未通知玩家的助战信息
class FBHelpBattleRecord():
    def __init__(self):
        self.callPlayerID = 0 # 召唤他的玩家ID
        self.callPlayerName = ""
        self.mapID = 0
        self.funcLineID = 0
        self.xianyuanCoinAdd = 0 # 0代表到达上限
        self.relation = 0 # 当时的关系
        self.vipLV = 0 # 当时的VIP等级
        self.recordTime = 0 # 记录的时间
        return
## 是否在助战登记列表里
def IsInHelpBattleCheckInList(playerID): return playerID in PyGameData.g_fbHelpBattleCheckInPlayerDict
def MapServer_FBHelpBattle(curPlayer, msgList):
    ## 地图玩家请求助战相关操作
    GameWorld.DebugLog("MapServer_FBHelpBattle %s" % str(msgList), curPlayer.GetPlayerID())
    if not msgList:
        return ""
    cmd = msgList[0]
    result = []
    # 登记
    if cmd == "CheckIn":
        result = __DoPlayerFBHelpBattleCheckIn(curPlayer, msgList)
    # 刷新助战列表
    elif cmd == "Refresh":
        result = __DoFBHelpBattleRefresh(curPlayer, msgList)
    # 召唤
    elif cmd == "Call":
        result = __DoFBHelpBattleCall(curPlayer, msgList)
    if result == None:
        return
    return msgList + result
def __DoPlayerFBHelpBattleCheckIn(curPlayer, msgList):
    ## 玩家登记
    checkInCount, fightPower = msgList[1:]
    curTime = int(time.time())
    playerID = curPlayer.GetPlayerID()
    curCache = PlayerViewCache.ViewCacheMgr.FindCache(playerID)
    haveViewCache = 1 if curCache else 0
    todayXianyuanCoin = PlayerControl.GetTodayXianyuanCoin(curPlayer)
    helpBattlePlayer = PyGameData.g_fbHelpBattleCheckInPlayerDict.get(playerID)
    if not helpBattlePlayer:
        helpBattlePlayer = HelpBattlePlayer(playerID)
        PyGameData.g_fbHelpBattleCheckInPlayerDict[playerID] = helpBattlePlayer
    helpBattlePlayer.playerName = curPlayer.GetName()
    helpBattlePlayer.playerLV = curPlayer.GetLV()
    helpBattlePlayer.job = curPlayer.GetJob()
    helpBattlePlayer.realmLV = curPlayer.GetOfficialRank()
    helpBattlePlayer.fightPower = fightPower
    helpBattlePlayer.familyID = curPlayer.GetFamilyID()
    helpBattlePlayer.vipLV = curPlayer.GetVIPLv()
    helpBattlePlayer.checkInCount = checkInCount + 1
    helpBattlePlayer.checkInTime = curTime
    helpBattlePlayer.todayXianyuanCoin = todayXianyuanCoin
    isOK = 1 # 默认成功
    GameWorld.Log("玩家助战登记: playerLV=%s,fightPower=%s,familyID=%s,vipLV=%s,todayXianyuanCoin=%s,checkInCount=%s,haveViewCache=%s"
                  % (curPlayer.GetLV(), fightPower, curPlayer.GetFamilyID(), curPlayer.GetVIPLv(), todayXianyuanCoin, checkInCount + 1, haveViewCache), playerID)
    return [isOK, haveViewCache]
def UpdateCheckInPlayerInfo(playerID, fightPower, familyID):
    ## 更新登记的助战玩家等级战力
    if playerID not in PyGameData.g_fbHelpBattleCheckInPlayerDict:
        return
    helpBattlePlayer = PyGameData.g_fbHelpBattleCheckInPlayerDict[playerID]
    helpBattlePlayer.fightPower = fightPower
    helpBattlePlayer.familyID = familyID
    GameWorld.DebugLog("更新助战玩家等级战力: fightPower=%s,familyID=%s" % (fightPower, familyID), playerID)
    return
def UpdateCheckInPlayerInfoByRefresh(curPlayer, refreshType, value):
    ## 更新登记的助战玩家仙盟ID
    playerID = curPlayer.GetPlayerID()
    if playerID not in PyGameData.g_fbHelpBattleCheckInPlayerDict:
        return
    helpBattlePlayer = PyGameData.g_fbHelpBattleCheckInPlayerDict[playerID]
    if refreshType == IPY_GameServer.CDBPlayerRefresh_LV:
        helpBattlePlayer.playerLV = value
    elif refreshType == IPY_GameServer.CDBPlayerRefresh_ExAttr11:
        helpBattlePlayer.todayXianyuanCoin = value
    elif refreshType == IPY_GameServer.CDBPlayerRefresh_VIPLv:
        helpBattlePlayer.vipLV = value
    else:
        return
    GameWorld.DebugLog("更新助战玩家信息: refreshType=%s,value=%s" % (refreshType, value), playerID)
    return
def __DoFBHelpBattleRefresh(curPlayer, msgList):
    ## 助战列表刷新
    mapID, funcLineID, isClientRefresh, costMoneyList, calledPlayerIDDict = msgList[1:]
    helpBattlePlayerDict = {} # 同步给地图服务器的待选助战玩家列表信息
    ipyData = IpyGameDataPY.GetIpyGameData("FBHelpBattle", mapID, funcLineID)
    if not ipyData:
        return [helpBattlePlayerDict]
    fightPowerMin = ipyData.GetFightPowerMin()
    fightPowerMax = ipyData.GetFightPowerMax()
    limitLV = ipyData.GetLVLimit()
    dayFreeHelpCountInfo = ipyData.GetDayFreeHelpCount() # 每日免费助战次数,[每日免费助战次数, 是否所有层通用]
    dayFreeHelpCount = 0 # 0为无限制次数
    helpCountLineID = funcLineID # 助战次数所属lineID,当所有层通用时,默认为0
    if dayFreeHelpCountInfo and len(dayFreeHelpCountInfo) == 2:
        dayFreeHelpCount, isAllLineCount = dayFreeHelpCountInfo
        if isAllLineCount:
            helpCountLineID = 0
    helpCountKey = (mapID, helpCountLineID)
    playerID = curPlayer.GetPlayerID()
    GameWorld.Log("刷新助战列表: mapID=%s,funcLineID=%s,helpCountLineID=%s,isClientRefresh=%s,costMoneyList=%s,calledPlayerIDDict=%s"
                  % (mapID, funcLineID, helpCountLineID, isClientRefresh, costMoneyList, calledPlayerIDDict), playerID)
    goldCallCount = 0
    #已经召唤的保留
    for calledPlayerID, callInfo in calledPlayerIDDict.items():
        needGoldCall, job, relation = callInfo
        # 玩家镜像
        if calledPlayerID in PyGameData.g_fbHelpBattleCheckInPlayerDict:
            helpBattlePlayer = PyGameData.g_fbHelpBattleCheckInPlayerDict[calledPlayerID]
            helpBattlePlayerDict[calledPlayerID] = __GetNotifyMapServerHelpPlayerInfoDict(helpBattlePlayer, needGoldCall, job, relation)
            if needGoldCall:
                goldCallCount += 1
        # 机器人NPC
        elif 1 <= calledPlayerID <= MaxRobotID:
            helpBattlePlayerDict[calledPlayerID] = __GetNotifyMapServerHelpPlayerInfoDict(None, False, job)
        else:
            GameWorld.ErrLog("已召唤的助战玩家找不到镜像缓存!理论上不存在该情况,镜像缓存释放会比登记有效时长多半小时!")
            continue
    if helpBattlePlayerDict:
        GameWorld.Log("已召唤的助战: %s" % str(helpBattlePlayerDict), playerID)
    curTime = int(time.time())
    maxHelpPlayerSelectCount =  IpyGameDataPY.GetFuncCfg("HelpBattleCall", 1) # 最大可以选择助战的玩家个数
    maxGoldHelpPlayerCount = IpyGameDataPY.GetFuncCfg("HelpBattleCall", 3) # 最大付费召唤人数
    checkInValidHours = IpyGameDataPY.GetFuncCfg("HelpBattleCheckIn", 1) # 登记有效时长,小时
    checkInValidSeconds = checkInValidHours * 3600
    checkInPlayerIDList = PyGameData.g_fbHelpBattleCheckInPlayerDict.keys()
    random.shuffle(checkInPlayerIDList) # 刷新纯随机
    GameWorld.Log("    登记助战人数=%s" % (len(checkInPlayerIDList)), playerID)
    for checkInPlayerID in checkInPlayerIDList:
        if checkInPlayerID == playerID:
            GameWorld.DebugLog("    自己不处理, checkInPlayerID=%s" % checkInPlayerID)
            continue
        if checkInPlayerID in helpBattlePlayerDict:
            GameWorld.DebugLog("    已经在助战里的不处理, checkInPlayerID=%s" % checkInPlayerID)
            continue
        if len(helpBattlePlayerDict) >= maxHelpPlayerSelectCount:
            GameWorld.DebugLog("    超过最大个数了不处理, checkInPlayerID=%s" % checkInPlayerID)
            break
        helpBattlePlayer = PyGameData.g_fbHelpBattleCheckInPlayerDict[checkInPlayerID]
        checkInPlayerLV = helpBattlePlayer.playerLV
        checkInPlayerFightPower = helpBattlePlayer.fightPower
        checkInTime = helpBattlePlayer.checkInTime
        if checkInPlayerLV < limitLV:
            GameWorld.DebugLog("    等级不足, checkInPlayerID=%s,checkInPlayerLV=%s < limitLV=%s" % (checkInPlayerID, checkInPlayerLV, limitLV))
            continue
        if fightPowerMin and checkInPlayerFightPower < fightPowerMin:
            GameWorld.DebugLog("    战力不足, checkInPlayerID=%s,checkInPlayerFightPower=%s < fightPowerMin=%s" % (checkInPlayerID, checkInPlayerFightPower, fightPowerMin))
            continue
        if fightPowerMax and checkInPlayerFightPower > fightPowerMax:
            GameWorld.DebugLog("    战力超出, checkInPlayerID=%s,checkInPlayerFightPower=%s > fightPowerMax=%s" % (checkInPlayerID, checkInPlayerFightPower, fightPowerMax))
            continue
        passTime = curTime - checkInTime
        if passTime > checkInValidSeconds:
            GameWorld.DebugLog("    登记超时, checkInPlayerID=%s,checkInTime=%s,passTime=%s > checkInValidSeconds=%s" % (checkInPlayerID, checkInTime, passTime, checkInValidSeconds))
            continue
        needGoldCall = False
        if dayFreeHelpCount:
            todayHelpCount = helpBattlePlayer.todayHelpCountDict.get(helpCountKey, 0)
            needGoldCall = todayHelpCount >= dayFreeHelpCount
            if needGoldCall and goldCallCount >= maxGoldHelpPlayerCount:
                GameWorld.DebugLog("    超过最大付费召唤人数, checkInPlayerID=%s,goldCallCount=%s > maxGoldHelpPlayerCount=%s" % (checkInPlayerID, goldCallCount, maxGoldHelpPlayerCount))
                continue
            goldCallCount += 1
        relation = __GetHelpBattleRelation(curPlayer, helpBattlePlayer)
        helpBattlePlayerDict[checkInPlayerID] = __GetNotifyMapServerHelpPlayerInfoDict(helpBattlePlayer, needGoldCall, helpBattlePlayer.job, relation)
    # 不足的机器人NPC补足
    openJobList = IpyGameDataPY.GetFuncEvalCfg("OpenJob", 1) # 开放的职业
    lackCount = maxHelpPlayerSelectCount - len(helpBattlePlayerDict)
    robotID = 0 # 机器人NPC定义ID从1开始
    while lackCount > 0 and robotID < MaxRobotID:
        robotID += 1
        if robotID in helpBattlePlayerDict:
            continue
        lackCount -= 1
        randJob = random.choice(openJobList)
        helpBattlePlayerDict[robotID] = __GetNotifyMapServerHelpPlayerInfoDict(None, False, randJob)
    GameWorld.Log("    helpBattlePlayerDict=%s" % (helpBattlePlayerDict), playerID)
    return [helpBattlePlayerDict]
def __GetHelpBattleRelation(curPlayer, helpBattlePlayer):
    ## 获取助战社交关系 0-无,1-好友,2-盟友
    if not helpBattlePlayer:
        return 0
    playerID = curPlayer.GetPlayerID()
    tagPlayerID = helpBattlePlayer.playerID
    tagFamilyID = helpBattlePlayer.familyID
    relationList = IpyGameDataPY.GetFuncEvalCfg("HelpBattlePoint", 3, []) # 社交关系优先级
    for checkRelation in relationList:
        if checkRelation == 1:
            if PlayerFriend.IsFriend(playerID, tagPlayerID):
                return checkRelation
        if checkRelation == 2:
            if curPlayer.GetFamilyID() == tagFamilyID:
                return checkRelation
    return 0
def __GetNotifyMapServerHelpPlayerInfoDict(helpBattlePlayer, needGoldCall, job, relation=0):
    ## 获取同步给地图的助战玩家简要信息
    helpPlayerDict = {"Job":job}
    if not helpBattlePlayer:
        return helpPlayerDict
    if needGoldCall:
        helpPlayerDict["NeedGoldCall"] = 1
    helpPlayerDict["Name"] = helpBattlePlayer.playerName
    helpPlayerDict["LV"] = helpBattlePlayer.playerLV
    #helpPlayerDict["Job"] = helpBattlePlayer.job
    helpPlayerDict["RealmLV"] = helpBattlePlayer.realmLV
    helpPlayerDict["FightPower"] = helpBattlePlayer.fightPower
    helpPlayerDict["Relation"] = relation
    return helpPlayerDict
def __DoFBHelpBattleCall(curPlayer, msgList):
    ''' 助战召唤,不管最终过关与否,被召唤方都直接算助战成功,这里处理被召唤的,主动方在地图直接处理
    '''
    mapID, funcLineID, calledPlayerDict = msgList[1:]
    fbFuncIpyData = IpyGameDataPY.GetIpyGameData("FBFunc", mapID)
    fbHelpIpyData = IpyGameDataPY.GetIpyGameData("FBHelpBattle", mapID, funcLineID)
    if not fbFuncIpyData or not fbHelpIpyData or not calledPlayerDict:
        return
    curTime = int(time.time())
    tagPlayerID = curPlayer.GetPlayerID()
    tagPlayerName = curPlayer.GetName()
    playerMgr = GameWorld.GetPlayerManager()
    xianyuanCoinUpper = IpyGameDataPY.GetFuncCfg("HelpBattlePoint", 1) # 每日仙缘币上限
    baseHelpPoint = fbFuncIpyData.GetHelpPoint() # 助战 - 基础仙缘币
    relationCoinAddDict = IpyGameDataPY.GetFuncEvalCfg("HelpBattlePoint", 2, {}) # 社交关系加成 {"社交关系":[过关加成, 助战加成], ...}
    GameWorld.DebugLog("召唤助战: mapID=%s, funcLineID=%s, calledPlayerDict=%s" % (mapID, funcLineID, calledPlayerDict), tagPlayerID)
    for calledPlayerID, relation in calledPlayerDict.items():
        if calledPlayerID not in PyGameData.g_fbHelpBattleCheckInPlayerDict:
            continue
        addCoinRate = 10000 # 基础倍率
        playerXianyuanCoinUpper = xianyuanCoinUpper
        relationAddList = relationCoinAddDict.get(str(relation), [])
        relationAdd = relationAddList[1] if len(relationAddList) == 2 else 0
        helpBattlePlayer = PyGameData.g_fbHelpBattleCheckInPlayerDict[calledPlayerID]
        todayXianyuanCoin = helpBattlePlayer.todayXianyuanCoin # 今日已获得仙缘币
        vipLV = helpBattlePlayer.vipLV
        if vipLV:
            xianyuanCoinUpperAdd = PlayerControl.GetPrivilegeValue(vipLV, ChConfig.VIPPrivilege_XianyuanCoinUpperAdd)
            xianyuanCoinAddPer = PlayerControl.GetPrivilegeValue(vipLV, ChConfig.VIPPrivilege_XianyuanCoinAddPer)
            playerXianyuanCoinUpper += xianyuanCoinUpperAdd
            addCoinRate += xianyuanCoinAddPer
        # 仙缘币公式=(通关仙缘币或助战仙缘币+社交关系加成)*VIP倍数
        coinAdd = int((baseHelpPoint + relationAdd) * addCoinRate / 10000.0)
        canAddMax = max(playerXianyuanCoinUpper - todayXianyuanCoin, 0)
        coinAddReal = min(coinAdd, canAddMax) # 实际加仙缘币
        GameWorld.DebugLog("    助战增加仙缘币: coinAddReal=%s" % (coinAddReal), calledPlayerID)
        # GameServer 直接先加
        helpBattlePlayer.todayXianyuanCoin += coinAddReal
        helpRecord = FBHelpBattleRecord()
        helpRecord.callPlayerID = tagPlayerID # 召唤他的玩家ID
        helpRecord.callPlayerName = tagPlayerName
        helpRecord.mapID = mapID
        helpRecord.funcLineID = funcLineID
        helpRecord.xianyuanCoinAdd = coinAddReal
        helpRecord.relation = relation
        helpRecord.vipLV = vipLV
        helpRecord.recordTime = curTime
        calledPlayer = playerMgr.FindPlayerByID(calledPlayerID)
        # 非脱机在线直接通知地图
        if calledPlayer and not PlayerControl.GetIsTJG(calledPlayer):
            SendMapServer_FBHelpBattleRecord(calledPlayer, [helpRecord])
        else:
            unNotifyRecordList = PyGameData.g_fbHelpBattleRecord.get(calledPlayerID, [])
            unNotifyRecordList.append(helpRecord)
            PyGameData.g_fbHelpBattleRecord[calledPlayerID] = unNotifyRecordList
    return
def SendMapServer_FBHelpBattleRecord(curPlayer, syncHelpRecordList):
    if not syncHelpRecordList:
        return
    helpRecordList = []
    for record in syncHelpRecordList:
        helpRecordList.append([record.callPlayerID, record.callPlayerName, record.mapID, record.funcLineID,
                               record.xianyuanCoinAdd, record.relation, record.vipLV, record.recordTime])
    addXianyuanCoinMsg = str(["HelpRecord", helpRecordList])
    curPlayer.MapServer_QueryPlayerResult(0, 0, 'FBHelpBattle', addXianyuanCoinMsg, len(addXianyuanCoinMsg))
    GameWorld.DebugLog("    MapServer_QueryPlayerResult %s" % addXianyuanCoinMsg, curPlayer.GetPlayerID())
    return
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFamily.py
@@ -348,7 +348,8 @@
    
    # 玩家战盟名变更处理
    __OnFamilyNameChange(jionPlayer.GetPlayerID(), curFamily.GetName())
    #玩家缓存
    PlayerViewCache.OnPlayerFamilyChange(jionPlayer.GetPlayerID(), curFamily.GetID(), curFamily.GetName())
    #加入仙盟联赛成员
    GameWorldFamilyWar.AddFamilyWarMem(jionPlayer.GetPlayerID(), curFamily.GetID())
    GameWorldFamilyWar.CheckPlayerJoinFamilyWarInfo(jionPlayer)
@@ -1524,7 +1525,7 @@
    # 玩家战盟名变更处理
    __OnFamilyNameChange(leavePlayerID, '')
    AddFamilyIDToFightPowerChangeList(curFamily.GetID())
    PlayerViewCache.OnPlayerLeaveFamily(leavePlayerID)
    PlayerViewCache.OnPlayerFamilyChange(leavePlayerID, 0, "")
    return
#//////////////////////////////////////////////////////////////
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerFriend.py
@@ -147,6 +147,13 @@
    
    return PyDataManager.GetFriendManager().AddFriends(playerID)
def IsFriend(playerID, tagPlayerID):
    ## 判断双方是否好友
    curFriends = PyDataManager.GetFriendManager().GetFriends(playerID)
    if not curFriends:
        return False
    return curFriends.Find(tagPlayerID) != None
#---------------------------------------------------------------------
##好友检查
# @param curPlayer 申请好友的玩家
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerQuery.py
@@ -60,6 +60,7 @@
#import PlayerFamilyTech
import MergeChildMsg
import PlayerFamilyRedPacket
import PlayerFBHelpBattle
import PlayerFamilyStore
import PlayerFamilySWRH
import GameWorldProcess
@@ -843,6 +844,17 @@
#        curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(srcPlayerID)
#        resultName = '%s' % PlayerFamilyTech.OnQuery_PlayerFamilyTechLVUP(curPlayer, eval(resultName))
    
    # 副本助战
    if callName =="FBHelpBattle":
        curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(srcPlayerID)
        if not curPlayer:
            return
        ret = PlayerFBHelpBattle.MapServer_FBHelpBattle(curPlayer, eval(resultName))
        if ret == None:
            return
        resultName = '%s' % ret
    # 战盟仓库
    if callName == "FamilyStore":
        curPlayer = GameWorld.GetPlayerManager().FindPlayerByID(srcPlayerID)
ServerPython/CoreServerGroup/GameServer/Script/Player/PlayerViewCache.py
@@ -26,6 +26,8 @@
import ReadChConfig
import PlayerFamily
import IPY_GameServer
import PlayerFBHelpBattle
import IpyGameDataPY
import ShareDefine
import ChConfig
@@ -81,6 +83,13 @@
        curCache.SetPlusDataNoSave(PlusData,len(PlusData))
    curCache.SetNeedSaveDB(isSaveDB) #设置需要保存到数据库
    
    # 同步更新助战信息
    if PlayerFBHelpBattle.IsInHelpBattleCheckInList(PlayerID):
        PropDataDict = eval(PropData)
        fightPower = PropDataDict.get("FightPower", 0)
        familyID = PropDataDict.get("FamilyID", 0)
        PlayerFBHelpBattle.UpdateCheckInPlayerInfo(PlayerID, fightPower, familyID)
    #暂时关闭
    #===========================================================================
    # FamilyIDKey = "FamilyID"
@@ -109,7 +118,10 @@
#  @param PlayerID, PlayerLV
#  @return None
def IsNeedSaveLogoutPlayer(PlayerID, PlayerLV):
    SaveDBLimitLV, NeedCheckBillBoardType, HighLadderLimitOrder = ReadChConfig.GetEvalChConfig("CacheSaveLimit")
    if PlayerFBHelpBattle.IsInHelpBattleCheckInList(PlayerID):
        return True
    SaveDBLimitLV = IpyGameDataPY.GetFuncCfg("PlayerViewCache", 1)
    #校验玩家等级
    if PlayerLV < SaveDBLimitLV:
        return False
@@ -118,7 +130,9 @@
# 上榜用户
def IsNeedSaveViewCacheAllInfo(PlayerID):
    SaveDBLimitLV, NeedCheckBillBoardType, HighLadderLimitOrder = ReadChConfig.GetEvalChConfig("CacheSaveLimit")
    if PlayerFBHelpBattle.IsInHelpBattleCheckInList(PlayerID):
        return True
    NeedCheckBillBoardType = IpyGameDataPY.GetFuncEvalCfg("PlayerViewCache", 2)
    #校验玩家是否上排行榜
    billboardMgr = GameWorld.GetBillboard()
    for BillBoardType in NeedCheckBillBoardType:
@@ -282,14 +296,14 @@
    NetPackCommon.SendFakePack(curPlayer, answerPack)
    return
def OnPlayerLeaveFamily(playerID):
    GameWorld.DebugLog("ViewCache->OnPlayerLeaveFamily", playerID)
def OnPlayerFamilyChange(playerID, familyID, familyName):
    GameWorld.DebugLog("ViewCache->OnPlayerFamilyChange", playerID)
    curCache = ViewCacheMgr.FindCache(playerID)
    if not curCache:
        return
    PropData = eval(curCache.GetPropData())
    PropData["FamilyID"] = 0
    PropData["FamilyName"] = ""
    PropData["FamilyID"] = familyID
    PropData["FamilyName"] = familyName
    playerLV = PropData["LV"]
    
    PropData = json.dumps(PropData, ensure_ascii=False)
ServerPython/CoreServerGroup/GameServer/Script/PyGameData.py
@@ -78,4 +78,8 @@
g_partyheroAnswerDict = {} #仙盟宴会玩家答题数量 {playerid:答题数量,..}
g_dogzNPCRefreshTimeDict = {} # 神兽副本NPC刷新时间{npcid:剩余刷新时间}
g_bourseItemTradingTimeDict = {} # 物品开始交易的时间记录 {guid:tick}
g_bourseItemTradingTimeDict = {} # 物品开始交易的时间记录 {guid:tick}
g_fbHelpBattleCheckInPlayerDict = {} # 副本助战玩家登记缓存
g_fbHelpBattleRecord = {} # 未同步的副本助战记录
ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py
@@ -759,7 +759,7 @@
CDBPlayerRefresh_RealmPoint,            # 境界修炼点
CDBPlayerRefresh_Ysog,                  # 魔精
CDBPlayerRefresh_FamilyActivity,        # 仙盟活跃令
CDBPlayerRefresh_FBHelpPoint,           # 副本助战积分
CDBPlayerRefresh_Xianyuancoin,          # 仙缘币
CDBPlayerRefresh_PKState,               # 战斗状态 175
CDBPlayerRefresh_BossState,             # boss״̬
CDBPlayerRefresh_BaseAtkMin,            # 基础最小攻击
@@ -789,7 +789,8 @@
TYPE_Price_RealmPoint = 13    # 境界修炼点
TYPE_Price_Ysog = 14    # 魔精
TYPE_Price_FamilyActivity = 15    # 仙盟活跃令
TYPE_Price_FBHelpPoint = 16    # 副本助战积分
TYPE_Price_FBHelpPoint = 16    # 副本助战积分, 废弃
TYPE_Price_XianyuanCoin = 17    # 仙缘币
TYPE_Price_Rune = 23    # 符印精华点
TYPE_Price_RuneSplinters = 24    # 符印碎片
TYPE_Price_TreasureScore = 25    # 寻宝积分
@@ -820,7 +821,7 @@
                           TYPE_Price_RealmPoint:CDBPlayerRefresh_RealmPoint,
                           TYPE_Price_Ysog:CDBPlayerRefresh_Ysog,
                           TYPE_Price_FamilyActivity:CDBPlayerRefresh_FamilyActivity,
                           TYPE_Price_FBHelpPoint:CDBPlayerRefresh_FBHelpPoint,
                           TYPE_Price_XianyuanCoin:CDBPlayerRefresh_Xianyuancoin,
                           TYPE_Price_Danjing:CDBPlayerRefresh_Danjing,
                           }
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
@@ -1131,6 +1131,26 @@
PacketSubCMD_1=0x75
PacketCallFunc_1=BuyFBEnterCount
;副本助战
[FBHelpBattle]
ScriptName = GameWorldLogic\FBProcess\FBHelpBattle.py
Writer = hxp
Releaser = hxp
RegType = 0
RegisterPackCount = 3
PacketCMD_1=0xB1
PacketSubCMD_1=0x5
PacketCallFunc_1=OnHelpBattleCheckIn
PacketCMD_2=0xB1
PacketSubCMD_2=0x6
PacketCallFunc_2=OnHelpBattleCall
PacketCMD_3=0xB1
PacketSubCMD_3=0x7
PacketCallFunc_3=OnHelpBattleRefresh
;组队
[PlayerTeam]
ScriptName = Player\PlayerTeam.py
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/AttackLogic/AttackCommon.py
@@ -1578,6 +1578,11 @@
        elif defObj.GetGameNPCObjType() == IPY_GameWorld.gnotTruck:
            remainHP = max(PlayerTruck.GetTruckDestroyMinHP(defObj), remainHP)
            GameObj.SetHP(defObj, remainHP)
        elif defObj.GetType() == ChConfig.ntHelpBattleRobot:
            remainHP = min(dHP, max(GameObj.GetMaxHP(defObj)/2, remainHP)) # 助战机器人剩余血量不能少于一半
            GameObj.SetHP(defObj, remainHP)
        else:
            #防守方是怪物NPC,只扣其血
            GameObj.SetHP(defObj, remainHP)
@@ -2470,7 +2475,6 @@
    
    #---NPC处理---
    if not ChNPC.OnCheckCanDie(atkObj, curObjDetel, curSkill, tick):
        GameObj.SetHP(curObjDetel, 1)
        return
    
    npcControl = NPCCommon.NPCControl(curObjDetel)
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/AttackLogic/NormalNPC_Attack_NormalNPC.py
@@ -100,7 +100,8 @@
    
    #普通NPC
    if GameObj.GetHP(defender) <= 0:
        if not ChNPC.OnCheckCanDie(attacker, defender, skill, tick):
            return
        #副本
        FBLogic.DoFB_Npc_KillNPC(attacker, defender, tick)
            
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/AttackLogic/Pet_Attack_NormalNPC.py
@@ -111,7 +111,6 @@
        curPlayer = PetControl.GetPetOwner(curPet)  # 宠物主人
        
        if not ChNPC.OnCheckCanDie(curPlayer, curTagNPC, skill, tick):
            GameObj.SetHP(curTagNPC, 1)
            return
        
        if curPlayer != None:
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/AttackLogic/Player_Attack_NormalNPC.py
@@ -111,7 +111,6 @@
    
    if GameObj.GetHP(curTagNormalNPC) <= 0:
        if not ChNPC.OnCheckCanDie(curPlayer, curTagNormalNPC, skill, tick):
            GameObj.SetHP(curTagNormalNPC, 1)
            return
        #执行击杀NPC逻辑
        FBLogic.DoFB_Player_KillNPC(curPlayer , curTagNormalNPC , tick)
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/AttackLogic/SummonNPC_Attack_NormalNPC.py
@@ -144,7 +144,6 @@
    curPlayer = NPCCommon.GetSummonNPCOwner(IPY_GameWorld.gotPlayer, curSummonNPC)
    
    if not ChNPC.OnCheckCanDie(curPlayer, curTagNPC, skill, tick):
        GameObj.SetHP(curTagNPC, 1)
        return
    
    #2011-05-12 chenxuewei 有没主人都只要通知一次即可,避免重复通知
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
@@ -1877,10 +1877,14 @@
Def_FB_DropDoCountRate = 'DropDoCountRate' # 怪物掉落执行次数万分率
Def_FB_DropDoCountAdd = 'DropDoCountAdd' # 怪物掉落执行次数加成固定值
Def_FB_SingleFBPlayerID = 'SingleFBPlayerID' # 个人副本玩家ID
Def_FB_HelpBattleFBObjID = 'HelpBattleFBObjID_%s' # 助战副本助战NPC机器人/玩家ID对应实例ID, 参数为玩家ID
Def_FB_HelpBattleGoldCall = 'HelpBattleGoldCall_%s' # 助战机器人是否花费召唤, 参数为玩家ID
FBPlayerDict_EncourageLV = 'FBPlayerDict_EncourageLV'   # 鼓舞等级
FBPlayerDict_IsDelTicket = 'FBPlayerDict_IsDelTicket'   # 是否已扣除入场券/进入次数
FBPlayerDict_IsHelpFight = 'FBPlayerDict_IsHelpFight' # 是否助战
FBPD_HelpBattleRefreshCount = 'FBPD_HelpBattleRefreshCount' # 助战已刷新次数
#领取奖励标识
(
@@ -3662,6 +3666,9 @@
Def_PDict_IceLodeLastCheckTime = "IceLodeLastCheckTime" #上次补发星级奖励时间
Def_PDict_IceLodeDayLV = "IceLodeDayLV" #今日等级
Def_PDict_IceLodeIsInFBOnDay = "IceLodeIsInFBOnDay" #在副本里过天
#助战
Def_PDict_HelpBattleCheckInCount = "HelpBattleCheckInCount" #助战登记次数, 登记次数*10+今日是否登记过
#-------------------------------------------------------------------------------
#类型 Def_PDictType_OnlinePrize
Def_PDict1_OnlinePrizeCnt = "OnlinePrizeCnt"  # 新手在线已领取奖励次数
@@ -4530,6 +4537,7 @@
Def_Cost_BindJadeWheel, # 绑玉转盘
Def_Cost_WishingWell, # 许愿池刷新
Def_Cost_GodWeapon, # 神兵
Def_Cost_FBHelpBattle, # 副本助战
#-----------以下为暂时没用的,先不删除,如有新增消费点则放在这些之前------------
Def_Cost_RefreshArrestTask, # 刷新悬赏任务
Def_Cost_OffLineExp, # 兑换离线经验
@@ -4550,7 +4558,7 @@
Def_Cost_Trade, # 交易
Def_Cost_Rename, # 改名
Def_Cost_SkillLvUp, # 技能升级
) = range(2000, 2000 + 58)
) = range(2000, 2000 + 59)
Def_Cost_Reason_SonKey = "reason_name_son" # 消费点原因子类说明key
@@ -4636,6 +4644,7 @@
Def_Cost_BindJadeWheel:"BindJadeWheel",
Def_Cost_WishingWell:"WishingWell",
Def_Cost_GodWeapon:"GodWeapon",
Def_Cost_FBHelpBattle:"FBHelpBattle",
}
## -----------------------------------------------------
@@ -4934,7 +4943,10 @@
VIPPrivilege_29,    #29 娲皇遗迹购买次数 - 副本总表统一处理
VIPPrivilege_BindJadeWheel,    #30 绑玉转盘次数
VIPPrivilege_PrayElixir,    #31 丹药祈福次数
) = range(1, 32)
VIPPrivilege_32,    #32 封魔坛自动挑战
VIPPrivilege_XianyuanCoinUpperAdd,    #33 仙缘币上限加成
VIPPrivilege_XianyuanCoinAddPer,    #34 仙缘币获得倍率加成(万分比)
) = range(1, 35)
(
@@ -4958,8 +4970,9 @@
ntTouchKill, #触碰后自杀类 17
ntUndeath, #不死类型 18
ntRobot, #上古战场机器人类型 19
ntHelpBattleRobot, #助战机器人 20
ntMax
) = range(21)
) = range(22)
(Def_SkillFuncType_Common, #0为通用技能
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBLogic.py
@@ -535,6 +535,18 @@
        callFunc(curPlayer, tick)
    return
def OnCallHelpBattleOK(curPlayer, tick):
    ## 召唤助战完成
    do_FBLogic_ID = __GetFBLogic_MapID(GameWorld.GetMap().GetMapID())
    callFunc = GameWorld.GetExecFunc(FBProcess, "GameLogic_%s.%s" % (do_FBLogic_ID, "OnCallHelpBattleOK"))
    if callFunc != None:
        GameWorld.Log("OnCallHelpBattleOK...", curPlayer.GetPlayerID())
        callFunc(curPlayer, tick)
    return
def InitFBNPCStrengthenData(curPlayer, gameMap):
    #副本NPC成长相关数据在 DoEnterFB 之前初始化
    gameFB = GameWorld.GetGameFB()
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/FBHelpBattle.py
New file
@@ -0,0 +1,438 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package GameWorldLogic.FBProcess.FBHelpBattle
#
# @todo:副本助战系统
# @author hxp
# @date 2018-11-24
# @version 1.0
#
# 详细描述: 副本助战系统
#
#-------------------------------------------------------------------------------
#"""Version = 2018-11-24 22:30"""
#-------------------------------------------------------------------------------
import GameWorld
import ChConfig
import PlayerControl
import ChPyNetSendPack
import NetPackCommon
import PlayerViewCacheTube
import FBCommon
import IpyGameDataPY
import ShareDefine
import PyGameData
import random
import GameMap
import NPCCommon
import FBLogic
import PlayerVip
def DoPlayerOnDay(curPlayer):
    checkInInfo = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_HelpBattleCheckInCount)
    checkInCount = checkInInfo / 10 # 累计登记
    checkInInfo = (checkInCount + 1) * 10 + 0
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_HelpBattleCheckInCount, checkInInfo)
    return
def GameServer_FBHelpBattleResult(curPlayer, msgList, tick):
    ## GameServer结果返回处理
    if not msgList:
        return
    cmd = msgList[0]
    # 登记
    if cmd == "CheckIn":
        __OnHelpBattleCheckInResult(curPlayer, msgList, tick)
    # 刷新
    if cmd == "Refresh":
        __OnHelpBattleRefreshResult(curPlayer, msgList, tick)
    # 助战记录
    if cmd == "HelpRecord":
        __OnHelpBattleRecord(curPlayer, msgList, tick)
    return
#// B1 05 助战登记 #tagCMHelpBattleCheckIn
#
#struct    tagCMHelpBattleCheckIn
#{
#    tagHead         Head;
#};
def OnHelpBattleCheckIn(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    checkInInfo = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_HelpBattleCheckInCount)
    checkInCount = checkInInfo / 10 # 累计登记
    todayIsCheckIn = checkInInfo % 10 # 今天是否已登记
    if todayIsCheckIn:
        GameWorld.DebugLog("当天已登记,不需要重复登记!", curPlayer.GetPlayerID())
        return
    fightPower = curPlayer.GetFightPower()
    msgInfo = str(["CheckIn", checkInCount, fightPower])
    GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(curPlayer.GetID(), 0, 0, "FBHelpBattle", msgInfo, len(msgInfo))
    return
def __OnHelpBattleCheckInResult(curPlayer, msgList, tick):
    ## 登记返回
    cmd, checkInCount, fightPower, isOK, haveViewCache = msgList
    if isOK:
        checkInInfo = (checkInCount + 1) * 10 + 1
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_HelpBattleCheckInCount, checkInInfo)
        # 没有数据缓存的话,马上同步一次
        if not haveViewCache:
            PlayerViewCacheTube.UpdateGameServerPlayerCache(curPlayer, tick, False)
    checkInPack = ChPyNetSendPack.tagMCHelpBattleCheckInResult()
    checkInPack.IsOK = isOK
    NetPackCommon.SendFakePack(curPlayer, checkInPack)
    GameWorld.DebugLog("FBHelpBattleResult: %s,checkInCount=%s,fightPower=%s,isOK=%s,haveViewCache=%s"
                       % (cmd, checkInCount, fightPower, isOK, haveViewCache), curPlayer.GetPlayerID())
    return
#// B1 06 助战召唤 #tagCMHelpBattleCall
#
#struct    tagCMHelpBattleCall
#{
#    tagHead         Head;
#    BYTE        IsOneKeyCall;    // 是否一键召唤
#    DWORD        PlayerID;        // 召唤的玩家ID,大于1小于100代表机器人
#    BYTE        IsGoldCall;    // 是否仙玉召唤
#};
def OnHelpBattleCall(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    isOneKeyCall = clientData.IsOneKeyCall
    calledPlayerID = clientData.PlayerID
    #isGoldCall = clientData.IsGoldCall
    playerID = curPlayer.GetPlayerID()
    gameFB = GameWorld.GetGameFB()
    mapID = FBCommon.GetRecordMapID(curPlayer.GetMapID())
    funcLineID = FBCommon.GetFBPropertyMark()
    ipyData = IpyGameDataPY.GetIpyGameData("FBHelpBattle", mapID, funcLineID)
    if not ipyData:
        return
    helpBattlePlayerDict = PyGameData.g_fbHelpBattlePlayerDict.get(playerID, {})
    maxHelpPlayerCount = IpyGameDataPY.GetFuncCfg("HelpBattleCall", 2) # 最大助战人数
    calledCount = 0
    freePlayerIDList = []
    helpNPCRobotIDList = []
    for helpPlayerID, helpPlayerInfoDict in helpBattlePlayerDict.items():
        objID = gameFB.GetGameFBDictByKey(ChConfig.Def_FB_HelpBattleFBObjID % helpPlayerID)
        if objID:
            calledCount += 1
        # 统计免费的未召唤的
        elif not helpPlayerInfoDict.get("NeedGoldCall", 0):
            if "Name" in helpPlayerInfoDict:
                freePlayerIDList.append(helpPlayerID)
            else:
                helpNPCRobotIDList.append(helpPlayerID)
    if calledCount >= maxHelpPlayerCount:
        GameWorld.Log("已经召唤满人数!无法再召唤!calledCount=%s" % calledCount, playerID)
        return
    calledPlayerDict = {} # {被召唤的玩家ID:关系, ...}
    # 优先召唤免费玩家镜像,不足才招NPC,暂不做战力排序
    if isOneKeyCall:
        lackCount = maxHelpPlayerCount - calledCount
        if freePlayerIDList:
            randIDList = random.sample(freePlayerIDList, min(lackCount, len(freePlayerIDList)))
            lackCount -= len(randIDList)
            for randID in randIDList:
                helpPlayerInfoDict = helpBattlePlayerDict[randID]
                calledPlayerDict[randID] = helpPlayerInfoDict.get("Relation", 0)
        if lackCount > 0 and helpNPCRobotIDList:
            for robotID in helpNPCRobotIDList[:lackCount]:
                calledPlayerDict[robotID] = 0
        if calledCount + len(calledPlayerDict) < maxHelpPlayerCount:
            GameWorld.ErrLog("无法一键召唤!人数不足! calledCount=%s,calledPlayerDict=%s,maxHelpPlayerCount=%s"
                             % (calledCount, calledPlayerDict, maxHelpPlayerCount), playerID)
            return
    else:
        if calledPlayerID not in helpBattlePlayerDict:
            GameWorld.ErrLog("不存在该助战玩家,无法召唤!calledPlayerID=%s" % (calledPlayerID), playerID)
            return
        helpPlayerInfoDict = helpBattlePlayerDict[calledPlayerID]
        if helpPlayerInfoDict.get("NeedGoldCall", 0):
            goldCallCost = IpyGameDataPY.GetFuncCfg("HelpBattleCall", 5) # 付费召唤消耗仙玉,优先消耗绑玉
            costMoneyList = PlayerControl.HaveMoneyEx(curPlayer, ShareDefine.TYPE_Price_Gold_Paper_Money, goldCallCost)
            if not costMoneyList:
                return
            infoDict = {"MapID":mapID, 'lineID':funcLineID, "Type":"Call"}
            for moneyType, moneyNum in costMoneyList:
                PlayerControl.PayMoney(curPlayer, moneyType, moneyNum, ChConfig.Def_Cost_FBHelpBattle, infoDict)
        calledPlayerDict[calledPlayerID] = helpPlayerInfoDict.get("Relation", 0)
    # 直接在地图召唤出来
    robotNPCID = IpyGameDataPY.GetFuncCfg("HelpBattleRobot", 1)
    posX, posY = curPlayer.GetPosX(), curPlayer.GetPosY()
    for calledPlayerID in calledPlayerDict.keys():
        if calledPlayerID not in helpBattlePlayerDict:
            continue
        helpPlayerInfoDict = helpBattlePlayerDict[calledPlayerID]
        job = helpPlayerInfoDict.get("Job", 1)
        if "FightPower" in helpPlayerInfoDict:
            fightPower = helpPlayerInfoDict["FightPower"]
            npcLV = helpPlayerInfoDict["LV"]
        else:
            fightPower = ipyData.GetRobotFightPower()
            npcLV = ipyData.GetRobotLV()
            calledPlayerDict.pop(calledPlayerID) # 招NPC不通知GameServer
        jobSkillDict = ipyData.GetRobotSkillsDict()
        position = GameMap.GetEmptyPlaceInAreaEx(posX, posY, 2, 6)
        npcPosX, npcPosY = position.GetPosX(), position.GetPosY()
        helpBattleNPC = NPCCommon.SummonMapNpc(robotNPCID, npcPosX, npcPosY)
        if not helpBattleNPC:
            continue
        objID = helpBattleNPC.GetID()
        GameWorld.Log("召唤助战成功: calledPlayerID=%s,objID=%s,fightPower=%s" % (calledPlayerID, objID, fightPower), playerID)
        gameFB.SetGameFBDict(ChConfig.Def_FB_HelpBattleFBObjID % calledPlayerID, objID)
        calledCount += 1
        __DoGiveHelpBattleRobotSkill(helpBattleNPC, jobSkillDict, job, npcLV)
        # 通知前端召唤成功
        callResultPack = ChPyNetSendPack.tagMCHelpBattleCallResult()
        callResultPack.ObjID = objID
        callResultPack.PlayerID = calledPlayerID
        NetPackCommon.SendFakePack(curPlayer, callResultPack)
    # 召唤满后
    if calledCount >= maxHelpPlayerCount:
        FBLogic.OnCallHelpBattleOK(curPlayer, tick)
    # ֪ͨGameServer
    if calledPlayerDict:
        msgInfo = str(["Call", mapID, funcLineID, calledPlayerDict])
        GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(curPlayer.GetID(), 0, 0, "FBHelpBattle", msgInfo, len(msgInfo))
        GameWorld.Log("GameServer_QueryPlayerResult: %s" % msgInfo, curPlayer.GetID())
    return
def __DoGiveHelpBattleRobotSkill(curNPC, jobSkillDict, job, npcLV):
    skillManager = curNPC.GetSkillManager()
    if job not in jobSkillDict:
        return
    skillInfoDict = jobSkillDict[job]
    #{职业:{(技能ID,...):所需等级, 技能ID:所需等级, ...}, ...}
    #{1:{(12000, 12001, 12002, 12003):1, 12011:7, 12012:15, 12013:30, 12014:80, 12015:140}, 2:{(12100, 12101, 12102, 12103):1, 12111:7, 12112:15, 12114:80, 12115:140}}
    skillIDList = []
    for skillInfo, needLV in skillInfoDict.items():
        if npcLV < needLV:
            continue
        if isinstance(skillInfo, int):
            skillIDList.append(skillInfo)
        else:
            skillIDList += list(skillInfo)
    GameWorld.DebugLog("    给助战机器人技能: job=%s,npcLV=%s, %s" % (job, npcLV, skillIDList))
    for skillID in skillIDList:
        skillManager.LearnSkillByID(skillID)
    return
#// B1 07 助战刷新 #tagCMHelpBattleRefresh
#
#struct    tagCMHelpBattleRefresh
#{
#    tagHead         Head;
#};
def OnHelpBattleRefresh(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    SendGameServer_RefreshHelpBattlePlayer(curPlayer, isClientRefresh=True)
    return
def SendGameServer_RefreshHelpBattlePlayer(curPlayer, mapID=0, funcLineID=0, isClientRefresh=True):
    ## 发送GameServer请求刷新助战玩家列表
    if not mapID:
        mapID = FBCommon.GetRecordMapID(curPlayer.GetMapID())
    if not funcLineID:
        funcLineID = FBCommon.GetFBPropertyMark()
    ipyData = IpyGameDataPY.GetIpyGameData("FBHelpBattle", mapID, funcLineID)
    if not ipyData:
        return
    playerID = curPlayer.GetPlayerID()
    gameFB = GameWorld.GetGameFB()
    costMoneyList = []
    calledPlayerIDDict = {} # 已经召唤的玩家ID字典 {playerID:[是否付费召唤, 职业], ...}
    if isClientRefresh:
        refreshCount = gameFB.GetPlayerGameFBDictByKey(playerID, ChConfig.FBPD_HelpBattleRefreshCount)
        freeRefreshCount = IpyGameDataPY.GetFuncCfg("HelpBattleRefresh", 1)
        goldRefreshCount = IpyGameDataPY.GetFuncCfg("HelpBattleRefresh", 2)
        if refreshCount >= (freeRefreshCount + goldRefreshCount):
            GameWorld.DebugLog("超过刷新助战列表次数!无法刷新!refreshCount=%s" % (refreshCount), playerID)
            return
        if refreshCount >= freeRefreshCount:
            costGold = IpyGameDataPY.GetFuncCfg("HelpBattleRefresh", 3)
            costMoneyList = PlayerControl.HaveMoneyEx(curPlayer, ShareDefine.TYPE_Price_Gold_Paper_Money, costGold)
            if not costMoneyList:
                GameWorld.DebugLog("货币不足!无法刷新助战!")
                return
        # 获取已经召唤的玩家镜像ID
        helpBattlePlayerDict = PyGameData.g_fbHelpBattlePlayerDict.get(playerID, {})
        for helpPlayerID, helpPlayerInfoDict in helpBattlePlayerDict.items():
            objID = gameFB.GetGameFBDictByKey(ChConfig.Def_FB_HelpBattleFBObjID % helpPlayerID)
            if not objID:
                continue
            needGoldCall = gameFB.GetGameFBDictByKey(ChConfig.Def_FB_HelpBattleGoldCall % helpPlayerID)
            job = helpPlayerInfoDict.get("Job", 1)
            relation = helpPlayerInfoDict.get("Relation", 0) # 关系需以刷新列表时的为准,如果已经召唤了,则已当时的为准
            calledPlayerIDDict[helpPlayerID] = [needGoldCall, job, relation]
    # 非客户端刷新的视为重新开始,重置刷新次数
    else:
        gameFB.SetPlayerGameFBDict(playerID, ChConfig.FBPD_HelpBattleRefreshCount, 0)
    msgInfo = str(["Refresh", mapID, funcLineID, isClientRefresh, costMoneyList, calledPlayerIDDict])
    GameWorld.GetPlayerManager().GameServer_QueryPlayerResult(curPlayer.GetID(), 0, 0, "FBHelpBattle", msgInfo, len(msgInfo))
    GameWorld.Log("SendGameServer_RefreshHelpBattlePlayer %s" % (msgInfo), playerID)
    return
def __OnHelpBattleRefreshResult(curPlayer, msgList, tick):
    ## 刷新返回
    cmd, mapID, funcLineID, isClientRefresh, costMoneyList, calledPlayerIDDict, helpBattlePlayerDict = msgList
    playerID = curPlayer.GetPlayerID()
    gameFB = GameWorld.GetGameFB()
    # 扣钱,加刷新次数
    infoDict = {"MapID":mapID, 'lineID':funcLineID, "Type":"Refresh"}
    for moneyType, moneyNum in costMoneyList:
        PlayerControl.PayMoney(curPlayer, moneyType, moneyNum, ChConfig.Def_Cost_FBHelpBattle, infoDict)
    refreshCount = gameFB.GetPlayerGameFBDictByKey(playerID, ChConfig.FBPD_HelpBattleRefreshCount)
    if isClientRefresh:
        refreshCount += 1
        gameFB.SetPlayerGameFBDict(playerID, ChConfig.FBPD_HelpBattleRefreshCount, refreshCount)
    GameWorld.Log("FBHelpBattleResult: %s,mapID=%s,funcLineID=%s,isClientRefresh=%s,costMoneyList=%s,calledPlayerIDDict=%s,refreshCount=%s"
                  % (cmd, mapID, funcLineID, isClientRefresh, costMoneyList, calledPlayerIDDict, refreshCount), playerID)
    GameWorld.Log("    helpBattlePlayerDict=%s" % (helpBattlePlayerDict), playerID)
    PyGameData.g_fbHelpBattlePlayerDict[playerID] = helpBattlePlayerDict
    # 通知前端
    helpPlayerListPack = ChPyNetSendPack.tagMCHelpBattleList()
    helpPlayerListPack.RefreshCount = refreshCount
    helpPlayerListPack.HelpPlayerList = []
    for helpPlayerID, helpPlayerInfoDict in helpBattlePlayerDict.items():
        helpPlayer = ChPyNetSendPack.tagMCHelpBattlePlayer()
        helpPlayer.ObjID = gameFB.GetGameFBDictByKey(ChConfig.Def_FB_HelpBattleFBObjID % helpPlayerID) # 获取已经召唤的对应objID
        helpPlayer.PlayerID = helpPlayerID
        helpPlayer.Job = helpPlayerInfoDict.get("Job", 1)
        # 玩家镜像才有名字,助战NPC名字前端处理
        if "Name" in helpPlayerInfoDict:
            helpPlayer.Name =  helpPlayerInfoDict["Name"]
            helpPlayer.NameLen =  len(helpPlayer.Name)
            helpPlayer.LV =  helpPlayerInfoDict["LV"]
            helpPlayer.RealmLV =  helpPlayerInfoDict["RealmLV"]
            helpPlayer.FightPower =  helpPlayerInfoDict["FightPower"]
            helpPlayer.Relation = helpPlayerInfoDict.get("Relation", 0)
            helpPlayer.IsNeedGold =  helpPlayerInfoDict.get("NeedGoldCall", 0)
        helpPlayerListPack.HelpPlayerList.append(helpPlayer)
    helpPlayerListPack.HelpCount = len(helpPlayerListPack.HelpPlayerList)
    NetPackCommon.SendFakePack(curPlayer, helpPlayerListPack)
    return
def __OnHelpBattleRecord(curPlayer, msgList, tick):
    cmd, helpRecordList = msgList
    playerID = curPlayer.GetPlayerID()
    GameWorld.DebugLog("__OnHelpBattleRecord %s,helpRecordList=%s" % (cmd, helpRecordList), playerID)
    addXianyuanCoinTotal = 0 # 累计需要增加的仙缘币
    addXianyuanCoinTotalTotay = 0 # 累计需要增加的今日仙缘币
    drList = []
    recordPack = ChPyNetSendPack.tagMCHelpBattleRecordList()
    recordPack.RecordList = []
    for recordInfo in helpRecordList:
        callPlayerID, callPlayerName, mapID, funcLineID, xianyuanCoinAdd, relation, vipLV, recordTime = recordInfo
        timeStr = GameWorld.ChangeTimeNumToStr(recordTime)
        isSameDay = GameWorld.CheckTimeIsSameServerDayEx(recordTime)
        record = ChPyNetSendPack.tagMCHelpBattleRecord()
        record.CallPlayerID = callPlayerID
        record.CallPlayerName = callPlayerName
        record.NameLen = len(record.CallPlayerName)
        record.MapID = mapID
        record.FuncLineID = funcLineID
        record.XianyuanCoinAdd = xianyuanCoinAdd
        record.Relation = relation
        record.VIPLV = vipLV
        record.HelpTime = timeStr
        recordPack.RecordList.append(record)
        drList.append({"CallPlayerID":callPlayerID, "MapID":mapID, "FuncLineID":funcLineID, "XianyuanCoinAdd":xianyuanCoinAdd,
                       "Relation":relation, "VIPLV":vipLV, "HelpTime":timeStr, "IsSameDay":isSameDay})
        addXianyuanCoinTotal += xianyuanCoinAdd
        if isSameDay:
            addXianyuanCoinTotalTotay += xianyuanCoinAdd
    recordPack.RecordCount = len(recordPack.RecordList)
    NetPackCommon.SendFakePack(curPlayer, recordPack)
    addDataDict = {"HelpList":drList}
    GameWorld.DebugLog("    addXianyuanCoinTotal=%s,addXianyuanCoinTotalTotay=%s" % (addXianyuanCoinTotal, addXianyuanCoinTotalTotay), playerID)
    PlayerControl.GiveMoney(curPlayer, ShareDefine.TYPE_Price_XianyuanCoin, addXianyuanCoinTotal, addDataDict=addDataDict, isSysHint=False)
    if addXianyuanCoinTotalTotay:
        PlayerControl.AddTodayXianyuanCoin(curPlayer, addXianyuanCoinTotalTotay)
    return
def DoSingleFBAddXianyuanCoin(curPlayer, mapID, lineID):
    ## 挑战单人副本增加仙缘币,仅适用于召唤镜像助战挑战的副本
    playerID = curPlayer.GetPlayerID()
    fbFuncIpyData = IpyGameDataPY.GetIpyGameData("FBFunc", mapID)
    fbHelpIpyData = IpyGameDataPY.GetIpyGameData("FBHelpBattle", mapID, lineID)
    if not fbFuncIpyData or not fbHelpIpyData:
        return
    addCoinRate = 10000 # 基础倍率
    baseFBPoint = fbFuncIpyData.GetFBPoint() # 过关 - 基础仙缘币
    xianyuanCoinUpper = IpyGameDataPY.GetFuncCfg("HelpBattlePoint", 1) # 每日仙缘币上限
    relationCoinAddDict = IpyGameDataPY.GetFuncEvalCfg("HelpBattlePoint", 2, {}) # 社交关系加成 {"社交关系":[过关加成, 助战加成], ...}
    todayXianyuanCoin = PlayerControl.GetTodayXianyuanCoin(curPlayer) # 今日已获得仙缘币
    playerXianyuanCoinUpper = xianyuanCoinUpper
    if curPlayer.GetVIPLv():
        playerXianyuanCoinUpper += PlayerVip.GetPrivilegeValue(curPlayer, ChConfig.VIPPrivilege_XianyuanCoinUpperAdd)
        addCoinRate += PlayerVip.GetPrivilegeValue(curPlayer, ChConfig.VIPPrivilege_XianyuanCoinAddPer)
    if todayXianyuanCoin >= playerXianyuanCoinUpper:
        GameWorld.DebugLog("玩家今日仙缘币已达上限!todayXianyuanCoin=%s,playerXianyuanCoinUpper=%s"
                           % (todayXianyuanCoin, playerXianyuanCoinUpper), playerID)
        return
    relationAdd = 0
    helpBattlePlayerDict = PyGameData.g_fbHelpBattlePlayerDict.get(playerID, {})
    for helpPlayerInfoDict in helpBattlePlayerDict.values():
        relation = helpPlayerInfoDict.get("Relation", 0)
        if not relation:
            continue
        relationAddList = relationCoinAddDict.get(str(relation), [])
        relationAdd += relationAddList[1] if len(relationAddList) == 2 else 0
    coinAdd = int((baseFBPoint + relationAdd) * addCoinRate / 10000.0)
    canAddMax = max(playerXianyuanCoinUpper - todayXianyuanCoin, 0)
    coinAddReal = min(coinAdd, canAddMax) # 实际加仙缘币
    GameWorld.DebugLog("挑战单人副本增加仙缘币: coinAdd=%s,canAddMax=%s,coinAddReal=%s" % (coinAdd, canAddMax, coinAddReal), playerID)
    addDataDict = {"MapID":mapID, "FuncLineID":lineID}
    PlayerControl.GiveMoney(curPlayer, ShareDefine.TYPE_Price_XianyuanCoin, coinAddReal, addDataDict=addDataDict)
    PlayerControl.AddTodayXianyuanCoin(curPlayer, coinAddReal)
    return
def DoTeamFBAddXianyuanCoin(curPlayer, mapID, lineID, callPlayerID, callPlayerName, relation):
    ## 挑战组队副本增加仙缘币
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_QueenRelics.py
@@ -31,6 +31,7 @@
import EventShell
import EventReport
import ChPlayer
import FBHelpBattle
#阶段时间
@@ -42,7 +43,7 @@
#当前副本地图的状态
(
FB_Step_Open, # 副本开启
FB_Step_CallHelp, # 助战召唤
FB_Step_Prepare, # 副本等待
FB_Step_Fighting, # 副本进行中
FB_Step_Over, # 副本结束
@@ -122,6 +123,12 @@
    curPlayer.ResetPos(enterX, enterY)
    return
## 召唤助战完成
def OnCallHelpBattleOK(curPlayer, tick):
    lineID = FBCommon.GetFBPropertyMark()
    DoQueenRelicsLinePrepare(curPlayer, lineID, tick)
    return
## 进副本
#  @param curPlayer
#  @param tick
@@ -130,7 +137,6 @@
    playerID = curPlayer.GetPlayerID()
    GameWorld.DebugLog("DoEnterFB...", playerID)
    
    isHelpFight = FBCommon.GetIsHelpFight(curPlayer)
    gameFB = GameWorld.GetGameFB()
    
    if not FBCommon.GetHadDelTicket(curPlayer):
@@ -139,33 +145,21 @@
            GameWorld.ErrLog("进入副本扣除门票失败!", curPlayer.GetPlayerID())
            return 0
        FBCommon.SetHadDelTicket(curPlayer)
        isHelpFight = FBCommon.SetIsHelpFight(curPlayer)
        GameWorld.DebugLog("    是否助战: %s" % isHelpFight, playerID)
        
    mapID = ChConfig.Def_FBMapID_QueenRelics
    lineID = FBCommon.GetFBPropertyMark()
    reqLineID = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_ReqFBFuncLine)
    joinType = FBCommon.GetFBJoinType(curPlayer, isHelpFight)
    
    if not FBCommon.GetHadSetFBPropertyMark() or reqLineID > lineID:
        FBCommon.SetFBPropertyMark(reqLineID, curPlayer)
        FBCommon.SetFBStep(FB_Step_Open, tick)
        lineID = reqLineID
        EventReport.WriteEvent_FB(curPlayer, ChConfig.Def_FBMapID_QueenRelics, lineID, ChConfig.CME_Log_Start, joinType)
    # 最后一次请求的功能线路ID比副本当前的还小,代表掉线期间队友已经打到其他层了,这时候,需要直接切换过去
    elif reqLineID < lineID:
        GameWorld.DebugLog("掉线期间队友已经打到其他层了,直接切换到目标功能线路ID!", playerID)
        toPosX, toPosY = __GetQueenRelicsLinePos(mapID, lineID)
        PlayerControl.PlayerResetWorldPosFBLineID(curPlayer, mapID, toPosX, toPosY, lineID)
        EventReport.WriteEvent_FB(curPlayer, ChConfig.Def_FBMapID_QueenRelics, lineID, ChConfig.CME_Log_Start, joinType)
        return
    else:
        EventReport.WriteEvent_FB(curPlayer, ChConfig.Def_FBMapID_QueenRelics, lineID, ChConfig.CME_Log_Start, joinType)
    #因为是组队副本,队员轮流进,所以只能设置一次
    fbStep = gameFB.GetFBStep()
    if fbStep < FB_Step_Prepare:
    if fbStep == FB_Step_CallHelp:
        FBCommon.SetFBPropertyMark(reqLineID, curPlayer)
        lineID = reqLineID
        FBHelpBattle.SendGameServer_RefreshHelpBattlePlayer(curPlayer, mapID, lineID)
        return
    if reqLineID > lineID:
        FBCommon.SetFBPropertyMark(reqLineID, curPlayer)
        lineID = reqLineID
        DoQueenRelicsLinePrepare(curPlayer, lineID, tick)
    else:
        fbLineTime = FBCommon.GetFBLineStepTime(ChConfig.Def_FBMapID_QueenRelics, lineID)
@@ -195,6 +189,7 @@
    __RefreshQueenRelicsNPC(True, False, tick, curPlayer)
    fbLineTime = FBCommon.GetFBLineStepTime(ChConfig.Def_FBMapID_QueenRelics, lineID)
    curPlayer.Sync_TimeTick(IPY_GameWorld.tttWaitStart, 0, fbLineTime[Def_PrepareTime] * 1000, True)
    EventReport.WriteEvent_FB(curPlayer, ChConfig.Def_FBMapID_QueenRelics, lineID, ChConfig.CME_Log_Start)
    return
##副本总逻辑计时器
@@ -473,30 +468,17 @@
            continue
        DoFBHelp(curPlayer, tick)
        
        isHelpFight = FBCommon.GetIsHelpFight(curPlayer)
        playerID = curPlayer.GetPlayerID()
        rewardLine = gameFB.GetPlayerGameFBDictByKey(playerID, FBPKey_RewardLine)
        needSyncFBData = False
        overDict = {}
        if isPass:
            overDict = {FBCommon.Over_costTime:costTime, FBCommon.Over_grade:grade}
            # 助战只算单次过关
            if isHelpFight:
                helpPoint = FBCommon.AddFBHelpPoint(curPlayer, dataMapID)
                overDict.update({FBCommon.Over_money:FBCommon.GetJsonMoneyList({ShareDefine.TYPE_Price_FBHelpPoint:helpPoint})})
                curGrade = GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_Player_Dict_PlayerFBStar_MapId, lineID, False, [dataMapID])
                if curGrade < grade:
                    GameWorld.DebugLog("    助战更新过关评级: dataMapID=%s,lineID=%s,curGrade=%s,grade=%s" % (dataMapID, lineID, curGrade, grade), curPlayer.GetPlayerID())
                    GameWorld.SetDictValueByBit(curPlayer, ChConfig.Def_Player_Dict_PlayerFBStar_MapId, lineID, grade, False, [dataMapID])
                    needSyncFBData = True
            else:
                rewardRet = __GivePlayerQueenRelicsReward(curPlayer, dataMapID, rewardLine - 1, lineID, grade, maxGrade, rewardRateList)
                if rewardRet:
                    needSyncFBData, startRewardLineID, totalSP, rewardItemList = rewardRet
                    overDict.update({FBCommon.Over_sp:totalSP, FBCommon.Over_itemInfo:FBCommon.GetJsonItemList(rewardItemList),
                                     "startRewardLineID":startRewardLineID})
            rewardRet = __GivePlayerQueenRelicsReward(curPlayer, dataMapID, rewardLine - 1, lineID, grade, maxGrade, rewardRateList)
            if rewardRet:
                needSyncFBData, startRewardLineID, totalSP, rewardItemList = rewardRet
                overDict.update({FBCommon.Over_sp:totalSP, FBCommon.Over_itemInfo:FBCommon.GetJsonItemList(rewardItemList),
                                 "startRewardLineID":startRewardLineID})
            if lineID+1 > curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_FBHistoryMaxLine % dataMapID):
                PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_FBHistoryMaxLine % dataMapID, lineID+1)
            #成就
@@ -512,12 +494,13 @@
        updRewardLine = lineID + 1
        gameFB.SetPlayerGameFBDict(playerID, FBPKey_RewardLine, updRewardLine)
        
        if isPass and not rewardLine and not isHelpFight:
        if isPass and not rewardLine:
            isInFBOnDay = gameFB.GetPlayerGameFBDictByKey(playerID, FBPKey_IsInFBOnDay)
            if not isInFBOnDay:
                GameWorld.DebugLog("首次结算奖励,增加挑战次数!", playerID)
                needSyncFBData = True
                FBCommon.AddEnterFBCount(curPlayer, dataMapID)
                FBHelpBattle.DoSingleFBAddXianyuanCoin(curPlayer, mapID, lineID)
            else:
                GameWorld.DebugLog("副本中过天,不增加挑战次数!", playerID)
            PlayerSuccess.DoAddSuccessProgress(curPlayer, ShareDefine.SuccType_QueenRelicsEx, 1)
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/GameWorldProcess.py
@@ -102,6 +102,11 @@
    if fbType == 0:
        return
    
    if fbType == IPY_GameWorld.fbtSingle:
        ownerID = gameFBMgr.GetGameFBDictByKey(ChConfig.Def_FB_SingleFBPlayerID)
        if ownerID in PyGameData.g_fbHelpBattlePlayerDict:
            PyGameData.g_fbHelpBattlePlayerDict.pop(ownerID)
    #副本关闭时统一清怪
    FBCommon.ClearFBNPC()
    
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCAI/AIType_186.py
@@ -388,6 +388,7 @@
        return True
    tagObj = __RefreshDropOwner(curNPC, tick, 0)
    if not atkObj or not tagObj:
        GameObj.SetHP(curNPC, 1)
        GameWorld.ErrLog("Boss当前状态下不可以死亡!npcID=%s" % curNPC.GetNPCID())
        return False
    return True
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCAI/AIType_20.py
New file
@@ -0,0 +1,50 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package NPCAI.AIType_20
#
# @todo:助战机器人
# @author hxp
# @date 2018-11-24
# @version 1.0
#
# 详细描述: 助战机器人
#     玩家正在攻击的目标(变相跟随玩家), 玩家无攻击目标时,机器人攻击自身视野中可攻击目标
#     如果都没有目标,跟随玩家
#     玩家掉线,机器人不再攻击
#     助战机器人永远不死,血量低于50%自动回血,后端自定
#-------------------------------------------------------------------------------
#"""Version = 2018-11-24 22:30"""
#-------------------------------------------------------------------------------
import NPCCommon
import ChConfig
import GameWorld
import GameObj
## 初始化
#  @param curNPC 当前npc
#  @return None
#  @remarks 函数详细说明.
def DoInit(curNPC):
    curNPC.GetNPCAngry().Init(ChConfig.Def_NormalNPCAngryCount)
    return
## 执行AI
#  @param curNPC 当前npc
#  @param tick 当前时间
#  @return None
#  @remarks 函数详细说明.
def ProcessAI(curNPC, tick):
    npcControl = NPCCommon.NPCControl(curNPC)
    return
def OnCheckCanDie(atkObj, curNPC, skill, tick):
    ## 检查NPC是否可死亡
    GameObj.SetHP(curNPC, GameObj.GetMaxHP(curNPC) / 2) # 回一半血
    GameWorld.ErrLog("该NPC不可以死亡!npcID=%s,curHP=%s" % (curNPC.GetNPCID(), GameObj.GetHP(curNPC)))
    return False
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
@@ -5678,6 +5678,10 @@
        curPlayer.SetExAttr6(silverPoint)
    return
## 玩家今日已获得仙缘币
def GetTodayXianyuanCoin(curPlayer): return curPlayer.GetExAttr11()
def AddTodayXianyuanCoin(curPlayer, addValue): return curPlayer.SetExAttr11(curPlayer.GetExAttr11() + addValue, False, True)
##VIP到期时间, 需要同步GameServer
def GetVIPExpireTime(curPlayer): return curPlayer.GetExAttr9()
def SetVIPExpireTime(curPlayer, expireTime): return curPlayer.SetExAttr9(expireTime, False, True)
@@ -5889,23 +5893,6 @@
#  @return: 威望值
def GetMergeWarRank(curPlayer):
    return 0
## 设置玩家官爵星级
#  @param curPlayer: 玩家实例
#  @param value: 星级
#  @return:
def SetOfficeStar(curPlayer, value):
    curPlayer.SetExAttr11(value)
    return
## 获取玩家玩家官爵星级
#  @param curPlayer: 玩家实例
#  @return: 星级
def GetOfficeStar(curPlayer):
    return curPlayer.GetExAttr11()
##获取可免费开启的格子数
# @param curPlayer 玩家对象
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py
@@ -98,6 +98,7 @@
import PlayerDiceEx
import IpyGameDataPY
import FamilyRobBoss
import FBHelpBattle
import QuestManager
import PyGameData
import PlayerTJG
@@ -545,6 +546,8 @@
        PlayerFreeGoods.OnDay(curPlayer)
        #采集次数重置
        NPCCommon.CollNPCTimeOnDay(curPlayer)
        #副本助战
        FBHelpBattle.DoPlayerOnDay(curPlayer)
        
    PlayerTJG.TJGOnDay(curPlayer, onEventType)
    # 以下为支持两种重置模式切换配置的
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/RemoteQuery/GY_Query_FBHelpBattle.py
New file
@@ -0,0 +1,50 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package Player.RemoteQuery.GY_Query_FBHelpBattle
#
# @todo:副本助战
# @author hxp
# @date 2018-11-24
# @version 1.0
#
# 详细描述: 副本助战
#
#-------------------------------------------------------------------------------
#"""Version = 2018-11-24 22:30"""
#-------------------------------------------------------------------------------
import GameWorld
import FBHelpBattle
#---------------------------------------------------------------------
#逻辑实现
## 请求逻辑
#  @param query_Type 请求类型
#  @param query_ID 请求的玩家ID
#  @param packCMDList 发包命令 [ ]
#  @param tick 当前时间
#  @return "True" or "False" or ""
#  @remarks 函数详细说明.
def DoLogic(query_Type, query_ID, packCMDList, tick):
    return ""
#---------------------------------------------------------------------
#执行结果
## 执行结果
#  @param curPlayer 发出请求的玩家
#  @param callFunName 功能名称
#  @param funResult 查询的结果
#  @param tick 当前时间
#  @return None
#  @remarks 函数详细说明.
def DoResult(curPlayer, callFunName, funResult, tick):
    GameWorld.DebugLog("GY_Query_FBHelpBattle funResult=%s" % str(funResult))
    if funResult == "":
        return
    FBHelpBattle.GameServer_FBHelpBattleResult(curPlayer, eval(funResult), tick)
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py
@@ -67,4 +67,7 @@
g_familyPartyInfo = {} #[ [[familyID, familyName, 答题数量]], top名字,top答题数量]
g_elderBattleRobotDieDict = {} #上古战场机器人死亡时间{lineid:[]}
g_elderBattleRobotDieDict = {} #上古战场机器人死亡时间{lineid:[]}
g_fbHelpBattlePlayerDict = {} # 助战玩家信息 {playerID:{助战玩家ID:{助战玩家简要信息字典} ...}, ...}
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
@@ -759,7 +759,7 @@
CDBPlayerRefresh_RealmPoint,            # 境界修炼点
CDBPlayerRefresh_Ysog,                  # 魔精
CDBPlayerRefresh_FamilyActivity,        # 仙盟活跃令
CDBPlayerRefresh_FBHelpPoint,           # 副本助战积分
CDBPlayerRefresh_Xianyuancoin,          # 仙缘币
CDBPlayerRefresh_PKState,               # 战斗状态 175
CDBPlayerRefresh_BossState,             # boss״̬
CDBPlayerRefresh_BaseAtkMin,            # 基础最小攻击
@@ -789,7 +789,8 @@
TYPE_Price_RealmPoint = 13    # 境界修炼点
TYPE_Price_Ysog = 14    # 魔精
TYPE_Price_FamilyActivity = 15    # 仙盟活跃令
TYPE_Price_FBHelpPoint = 16    # 副本助战积分
TYPE_Price_FBHelpPoint = 16    # 副本助战积分, 废弃
TYPE_Price_XianyuanCoin = 17    # 仙缘币
TYPE_Price_Rune = 23    # 符印精华点
TYPE_Price_RuneSplinters = 24    # 符印碎片
TYPE_Price_TreasureScore = 25    # 寻宝积分
@@ -820,7 +821,7 @@
                           TYPE_Price_RealmPoint:CDBPlayerRefresh_RealmPoint,
                           TYPE_Price_Ysog:CDBPlayerRefresh_Ysog,
                           TYPE_Price_FamilyActivity:CDBPlayerRefresh_FamilyActivity,
                           TYPE_Price_FBHelpPoint:CDBPlayerRefresh_FBHelpPoint,
                           TYPE_Price_XianyuanCoin:CDBPlayerRefresh_Xianyuancoin,
                           TYPE_Price_Danjing:CDBPlayerRefresh_Danjing,
                           }