6843 【后端】【2.0】缥缈仙域优化 6897 【后端】【2.0】缥缈仙域产出类型修改 6805 【后端】【2.0】副本前端化(缥缈宝藏、妖王、草园、VIPboss)
22个文件已修改
1 文件已重命名
1733 ■■■■ 已修改文件
PySysDB/PySysDBPY.h 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini 12 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/AttackLogic/AttackCommon.py 4 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/AttackLogic/Player_Attack_SummonNPC.py 13 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/BaseAttack.py 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py 10 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChNetSendPack.py 208 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/SummonNPC.py 17 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBLogic.py 42 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/FBCommon.py 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_CrossDemonKing.py 81 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_CrossGrassland.py 119 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_FairyTreasure.py 358 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_PersonalBoss.py 330 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/ChNPC.py 9 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCAI/AIType_196.py 71 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCAI/AIType_PriWood.py 8 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py 309 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py 1 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerFB.py 69 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerFairyDomain.py 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
PySysDB/PySysDBPY.h
@@ -896,8 +896,8 @@
struct tagPersonalBoss
{
    DWORD        _NPCID;    //ID
    DWORD        ChanllengeLv;    //可挑战等级
    DWORD        NPCID;    //ID
    DWORD        _FuncLineID;    //可挑战等级
};
//仙盟活跃表
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
@@ -349,13 +349,13 @@
PacketSubCMD_8=0x04
PacketCallFunc_8=OnClientStartFB
PacketCMD_9=0xB1
PacketSubCMD_9=0x08
PacketCallFunc_9=OnRefreshCustomFBPrize
PacketCMD_9=
PacketSubCMD_9=
PacketCallFunc_9=
PacketCMD_10=0xB1
PacketSubCMD_10=0x09
PacketCallFunc_10=OnGiveCustomFBPrize
PacketCMD_10=
PacketSubCMD_10=
PacketCallFunc_10=
PacketCMD_11=0xB1
PacketSubCMD_11=0x0A
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/AttackLogic/AttackCommon.py
@@ -1033,8 +1033,8 @@
        #对象已经死亡
        return False
    
    #添加(系统)隐身者不可攻击,证明家族战非隐身
    if not attacker.GetVisible():
    #添加(系统)隐身者不可攻击,证明家族战非隐身;自定义场景中是隐身的不做限制
    if not attacker.GetVisible() and not attacker.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomScene):
        return False
    
    if not defender.GetVisible():
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/AttackLogic/Player_Attack_SummonNPC.py
@@ -21,18 +21,16 @@
# @change: "2015-04-11 15:30" hxp 增加最终伤害逻辑
# @change: "2016-02-26 17:00" hxp 增加PVP伤害统计
#------------------------------------------------------------------------------ 
"""Version = 2016-02-26 17:00"""
#"""Version = 2016-02-26 17:00"""
#---------------------------------------------------------------------
import NPCCommon
import GameWorld
import AttackCommon
import IPY_GameWorld
import PlayerControl
import SkillCommon
import ChConfig
import ChEquip
import SkillShell
import FBLogic
import GameObj
import ChNPC
#---------------------------------------------------------------------
#---------------------------------------------------------------------
@@ -146,8 +144,11 @@
    #召唤兽死亡
    if GameObj.GetHP(curTagSummon) <=  0:
        NPCCommon.OnPlayerAttackNPCDie(curTagSummon, curPlayer, skill)
        FBLogic.DoFB_Player_KillNPC(curPlayer , curTagSummon , tick)
        #获得控制器
        curTagNormalNPCControl = NPCCommon.NPCControl(curTagSummon)
        curTagNormalNPCControl.SetKilled()
    else:
        ChNPC.OnNPCAttacked(curPlayer, curTagSummon, skill, tick)
    return True
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Attack/BaseAttack.py
@@ -974,16 +974,18 @@
        if not curTag:
            continue
        
        if curSkillUseTag == ChConfig.Def_UseSkillTag_CanAttackNPC:
            if NPCCommon.GetNpcObjOwnerIsPlayer(curTag):
                #npc主人是玩家不能攻击
        #非自定义场景才需要判断
        if not attacker.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomScene):
            if curSkillUseTag == ChConfig.Def_UseSkillTag_CanAttackNPC:
                if NPCCommon.GetNpcObjOwnerIsPlayer(curTag):
                    #npc主人是玩家不能攻击
                    continue
            if GameWorld.GetDist(curTag.GetPosX(), curTag.GetPosY(), attacker.GetPosX(), attacker.GetPosY()) > attacker.GetSight():
                # 最远距离防范
                GameWorld.DebugLog("#--- 最远距离防范[%s-%s]"%(attacker.GetID(), curTag.GetID()))
                continue
        if GameWorld.GetDist(curTag.GetPosX(), curTag.GetPosY(), attacker.GetPosX(), attacker.GetPosY()) > attacker.GetSight():
            # 最远距离防范
            GameWorld.DebugLog("#--- 最远距离防范[%s-%s]"%(attacker.GetID(), curTag.GetID()))
            continue
        if CheckFunc != None:
            #检查是否受影响
            if not CheckFunc(attacker, curTag, curSkill, tick):
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
@@ -3377,6 +3377,7 @@
Def_Player_Dict_ReqFBMissionID = "ReqFBMissionID" # 请求进入副本的任务ID
Def_Player_Dict_ReqFBMissionType = "ReqFBMissionType" # 请求进入副本的任务类型
Def_Player_Dict_PlayerFBStar_MapId = "FBStar_%s_%s"  # 副本星级星级信息, 参数为[mapID, key编号], 按位存储每个lineID对应的星级
Def_Player_Dict_CustomSceneStartTime = "ClientFBStartTime_%s_%s"  # 前端自定义场景开始time, 参数(mapID, lineID), 0-无,2-已结束,其他-time值
Def_Player_Dict_EnterFbCntDay = "EnterFbCntDay_%s"  # 今日进入副本次数, 参数为副本ID
Def_Player_Dict_BuyFbCntDay = "BuyFbCntDay_%s" # 今日购买副本进入次数, 参数为副本ID
Def_Player_Dict_RecoverFbCnt = "RecoverFbCnt_%s"  # 今日找回的副本次数, 参数为副本ID
@@ -3932,6 +3933,10 @@
Def_PDict_FairyDomainVisitCnt = "FairyDomainVisitCnt" #寻访总次数
Def_PDict_FairyAdventuresData = "FairyAdventuresData_%s" #奇遇数值 唯一ID*100+档位 参数事件ID
Def_PDict_FairyDomainEventAppearCnt = "FDEventAppearCnt%s" #事件出现次数 参数事件ID  AAABBB BBB:小时段出现次数 AAA:今日出现次数
#草园
Def_PDict_GrasslandNPCCount = "GrasslandNPCCount_%s" #草园NPCID个数,参数NPCID
Def_PDict_GrasslandDropCount = "GrasslandDropCount_%s" #草园掉落统计,参数编号,记录格式 itemID*100+dropCount
#五行专精
Def_PDict_SkillElementID = "SkillElementID%s" #主技能选择的专精技能 参数主技能ID
@@ -4901,6 +4906,11 @@
##==================================================================================================
# 前端自定义场景状态
CustomSceneState_None = 0 # 无
CustomSceneState_Fight = 1 # 战斗进行中
CustomSceneState_Over = 2 # 已结束
# 副本参与类型
FB_JoinType = (
FB_JoinType_None, # 默认无
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChNetSendPack.py
@@ -828,3 +828,211 @@
m_NAtagObjInfoRefresh=tagObjInfoRefresh()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagObjInfoRefresh.Cmd,m_NAtagObjInfoRefresh.SubCmd))] = m_NAtagObjInfoRefresh
#04 08 玩家召唤NPC出现#tagPlayerSummonNPCAppear
class  tagPlayerSummonNPCAppear(Structure):
    Head = tagHead()
    PlayerID = 0    #(DWORD PlayerID)
    Country = 0    #(BYTE Country)
    ObjID = 0    #(DWORD ObjID)//召唤出来的NPCID
    NPCID = 0    #(DWORD NPCID)
    PosX = 0    #(WORD PosX)
    PosY = 0    #(WORD PosY)
    HP = 0    #(DWORD HP)
    HPEx = 0    #(DWORD HPEx)
    MaxHP = 0    #(DWORD MaxHP)
    MaxHPEx = 0    #(DWORD MaxHPEx)
    Speed = 0    #(WORD Speed)
    LV = 0    #(BYTE LV)
    OwnerNameLen = 0    #(BYTE OwnerNameLen)
    OwnerName = ""    #(String OwnerName)//size = OwnerNameLen
    data = None
    def __init__(self):
        self.Clear()
        self.Head.Cmd = 0x04
        self.Head.SubCmd = 0x08
        return
    def ReadData(self, _lpData, _pos=0, _Len=0):
        self.Clear()
        _pos = self.Head.ReadData(_lpData, _pos)
        self.PlayerID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.Country,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.ObjID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.NPCID,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.PosX,_pos = CommFunc.ReadWORD(_lpData, _pos)
        self.PosY,_pos = CommFunc.ReadWORD(_lpData, _pos)
        self.HP,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.HPEx,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.MaxHP,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.MaxHPEx,_pos = CommFunc.ReadDWORD(_lpData, _pos)
        self.Speed,_pos = CommFunc.ReadWORD(_lpData, _pos)
        self.LV,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.OwnerNameLen,_pos = CommFunc.ReadBYTE(_lpData, _pos)
        self.OwnerName,_pos = CommFunc.ReadString(_lpData, _pos,self.OwnerNameLen)
        return _pos
    def Clear(self):
        self.Head = tagHead()
        self.Head.Clear()
        self.Head.Cmd = 0x04
        self.Head.SubCmd = 0x08
        self.PlayerID = 0
        self.Country = 0
        self.ObjID = 0
        self.NPCID = 0
        self.PosX = 0
        self.PosY = 0
        self.HP = 0
        self.HPEx = 0
        self.MaxHP = 0
        self.MaxHPEx = 0
        self.Speed = 0
        self.LV = 0
        self.OwnerNameLen = 0
        self.OwnerName = ""
        return
    def GetLength(self):
        length = 0
        length += self.Head.GetLength()
        length += 4
        length += 1
        length += 4
        length += 4
        length += 2
        length += 2
        length += 4
        length += 4
        length += 4
        length += 4
        length += 2
        length += 1
        length += 1
        length += len(self.OwnerName)
        return length
    def GetBuffer(self):
        data = ''
        data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer())
        data = CommFunc.WriteDWORD(data, self.PlayerID)
        data = CommFunc.WriteBYTE(data, self.Country)
        data = CommFunc.WriteDWORD(data, self.ObjID)
        data = CommFunc.WriteDWORD(data, self.NPCID)
        data = CommFunc.WriteWORD(data, self.PosX)
        data = CommFunc.WriteWORD(data, self.PosY)
        data = CommFunc.WriteDWORD(data, self.HP)
        data = CommFunc.WriteDWORD(data, self.HPEx)
        data = CommFunc.WriteDWORD(data, self.MaxHP)
        data = CommFunc.WriteDWORD(data, self.MaxHPEx)
        data = CommFunc.WriteWORD(data, self.Speed)
        data = CommFunc.WriteBYTE(data, self.LV)
        data = CommFunc.WriteBYTE(data, self.OwnerNameLen)
        data = CommFunc.WriteString(data, self.OwnerNameLen, self.OwnerName)
        return data
    def OutputString(self):
        DumpString = '''
                                Head:%s,
                                PlayerID:%d,
                                Country:%d,
                                ObjID:%d,
                                NPCID:%d,
                                PosX:%d,
                                PosY:%d,
                                HP:%d,
                                HPEx:%d,
                                MaxHP:%d,
                                MaxHPEx:%d,
                                Speed:%d,
                                LV:%d,
                                OwnerNameLen:%d,
                                OwnerName:%s
                                '''\
                                %(
                                self.Head.OutputString(),
                                self.PlayerID,
                                self.Country,
                                self.ObjID,
                                self.NPCID,
                                self.PosX,
                                self.PosY,
                                self.HP,
                                self.HPEx,
                                self.MaxHP,
                                self.MaxHPEx,
                                self.Speed,
                                self.LV,
                                self.OwnerNameLen,
                                self.OwnerName
                                )
        return DumpString
m_NAtagPlayerSummonNPCAppear=tagPlayerSummonNPCAppear()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagPlayerSummonNPCAppear.Head.Cmd,m_NAtagPlayerSummonNPCAppear.Head.SubCmd))] = m_NAtagPlayerSummonNPCAppear
#06 08 NPC死亡#tagNPCDie
class  tagNPCDie(Structure):
    _pack_ = 1
    _fields_ = [
                  ("Cmd", c_ubyte),
                  ("SubCmd", c_ubyte),
                  ("ObjID", c_int),
                  ("Reason", c_int),
                  ("KillerType", c_ubyte),
                  ("KillerID", c_int),
                  ]
    def __init__(self):
        self.Clear()
        self.Cmd = 0x06
        self.SubCmd = 0x08
        return
    def ReadData(self, stringData, _pos=0, _len=0):
        self.Clear()
        memmove(addressof(self), stringData[_pos:], self.GetLength())
        return _pos + self.GetLength()
    def Clear(self):
        self.Cmd = 0x06
        self.SubCmd = 0x08
        self.ObjID = 0
        self.Reason = 0
        self.KillerType = 0
        self.KillerID = 0
        return
    def GetLength(self):
        return sizeof(tagNPCDie)
    def GetBuffer(self):
        return string_at(addressof(self), self.GetLength())
    def OutputString(self):
        DumpString = '''//06 08 NPC死亡//tagNPCDie:
                                Cmd:%s,
                                SubCmd:%s,
                                ObjID:%d,
                                Reason:%d,
                                KillerType:%d,
                                KillerID:%d
                                '''\
                                %(
                                self.Cmd,
                                self.SubCmd,
                                self.ObjID,
                                self.Reason,
                                self.KillerType,
                                self.KillerID
                                )
        return DumpString
m_NAtagNPCDie=tagNPCDie()
ChNetPackDict[eval("0x%02x%02x"%(m_NAtagNPCDie.Cmd,m_NAtagNPCDie.SubCmd))] = m_NAtagNPCDie
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/SummonNPC.py
@@ -16,6 +16,7 @@
import ChConfig
import GameWorld
import NPCCommon
import PlayerFB
#
#逻辑实现
@@ -26,8 +27,9 @@
#  @remarks 函数详细说明.
def OnExec(curPlayer, paramList):
    #输入命令格式错误
    if not paramList or len(paramList) > 2:
    if not paramList:
        GameWorld.DebugAnswer(curPlayer, "SummonNPC npcID 个数")
        GameWorld.DebugAnswer(curPlayer, "SummonNPC npcID 个数 前端场景ID lineID")
        return
    
    #NPC对象ID
@@ -40,6 +42,19 @@
    
    npcType = npcData.GetType()
    if npcType in [ChConfig.ntPriWoodPilePVE, ChConfig.ntPriWoodPilePVP]:
        mapID = paramList[2] if len(paramList) > 2 else 0
        lineID = paramList[3] if len(paramList) > 3 else 0
        if not mapID:
            GameWorld.DebugAnswer(curPlayer, "木桩怪必须指定地图ID才能召唤!")
            return
        sceneMapID = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomSceneMapID)
        sceneLineID = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomSceneLineID)
        if mapID != sceneMapID or lineID != sceneLineID:
            if sceneMapID:
                PlayerFB.DoExitCustomScene(curPlayer)
            tick = GameWorld.GetGameWorld().GetTick()
            PlayerFB.DoEnterCustomScene(curPlayer, mapID, lineID, tick)
        NPCCommon.SummonPriWoodPile(curPlayer, npcID, npcCount)
        return
    
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBLogic.py
@@ -272,6 +272,12 @@
#  @return None
#  @remarks 函数详细说明.
def DoFB_Player_KillNPC(curPlayer , curNPC , tick):
    mapID = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomSceneMapID)
    lineID = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomSceneLineID)
    if mapID:
        DoCustomScene_Player_KillNPC(curPlayer, curNPC, mapID, lineID)
        return
    do_FBLogic_ID = __GetFBLogic_MapID(GameWorld.GetMap().GetMapID())
    
    callFunc = GameWorld.GetExecFunc(FBProcess, "GameLogic_%s.%s" % (do_FBLogic_ID, "DoFB_Player_KillNPC"))
@@ -1564,7 +1570,7 @@
    callFunc = GameWorld.GetExecFunc(FBProcess, "GameLogic_%s.%s" % (do_FBLogic_ID, "OnEnterFBEvent"))
    
    if callFunc == None:
        return False
        return True
    
    return callFunc(curPlayer, mapID, lineID, tick)
@@ -2180,28 +2186,38 @@
    
    return callFunc(curPlayer, mapID, lineID)
## 客户端发送刷新自定义副本奖励
def OnRefreshCustomFBPrize(curPlayer, mapID, lineID):
## 判断可否召唤木桩怪
def OnCanSummonPriWoodPile(curPlayer, mapID, lineID, npcID, count):
    do_FBLogic_ID = __GetFBLogic_MapID(mapID)
    
    callFunc = GameWorld.GetExecFunc(FBProcess, "GameLogic_%s.%s" % (do_FBLogic_ID, "OnRefreshCustomFBPrize"))
    callFunc = GameWorld.GetExecFunc(FBProcess, "GameLogic_%s.%s" % (do_FBLogic_ID, "OnCanSummonPriWoodPile"))
    
    if callFunc == None:
        return []
        return True
    
    return callFunc(curPlayer, mapID, lineID)
    return callFunc(curPlayer, mapID, lineID, npcID, count)
## 给自定义副本奖励后续处理
## @return: 返回结算副本over信息字典,不含jsonItem信息
def OnGiveCustomFBPrizeOK(curPlayer, mapID, lineID):
## 自定义场景副本击杀NPC
def DoCustomScene_Player_KillNPC(curPlayer, curNPC, mapID, lineID):
    do_FBLogic_ID = __GetFBLogic_MapID(mapID)
    
    callFunc = GameWorld.GetExecFunc(FBProcess, "GameLogic_%s.%s" % (do_FBLogic_ID, "OnGiveCustomFBPrizeOK"))
    callFunc = GameWorld.GetExecFunc(FBProcess, "GameLogic_%s.%s" % (do_FBLogic_ID, "DoCustomScene_Player_KillNPC"))
    
    if callFunc == None:
        return {}
    if callFunc:
        callFunc(curPlayer, curNPC, mapID, lineID)
    return
## 自定义场景采集OK
def OnCustomSceneCollectOK(curPlayer, mapID, lineID, npcID):
    do_FBLogic_ID = __GetFBLogic_MapID(mapID)
    
    return callFunc(curPlayer, mapID, lineID)
    callFunc = GameWorld.GetExecFunc(FBProcess, "GameLogic_%s.%s" % (do_FBLogic_ID, "OnCustomSceneCollectOK"))
    if callFunc:
        callFunc(curPlayer, mapID, lineID, npcID)
    return
## 进入跨服副本注册数据前逻辑
## @return: 是否可以注册前往跨服副本,次函数中可以写一些扣除消耗逻辑等
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/FBCommon.py
@@ -473,6 +473,38 @@
    GameWorld.GetGameFB().SetPlayerGameFBDict(curPlayer.GetID(), ChConfig.FBPlayerDict_IsDelTicket, delSign)
    return
def SetCustomSceneStart(curPlayer, mapID, lineID):
    ''' 设置前端自定义场景副本开始时间
            某些自定义场景进入可能需要处理某些逻辑,比如扣门票、设置某些状态、完成成就等,这些逻辑在单次进入只能触发一次
            需要记录一个开始状态,只在设置成功的时候进行处理这些逻辑,防止断线重连或重登重新进入自定义场景时,重复执行逻辑
            该状态设置了一个有效期,暂时设定为15分钟,未完成场景有效期内重复进入不会重复触发
            做超时是为了防止玩家没有正常结束场景导致未来的某个时间再次进入场景时无法正常触发进入需要额外处理的逻辑
            需根据副本结束时机配置函数 SetCustomSceneOver 设置结束状态
    @return: 设置成功返回True
    '''
    if GetCustomSceneState(curPlayer, mapID, lineID) == ChConfig.CustomSceneState_Fight:
        return
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_CustomSceneStartTime % (mapID, lineID), int(time.time()))
    return True
def GetCustomSceneState(curPlayer, mapID, lineID):
    '''获取前端自定义场景状态
    @return: 0-无,1-进行中,2-已结束
    '''
    startTime = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_CustomSceneStartTime % (mapID, lineID))
    if not startTime:
        return ChConfig.CustomSceneState_None
    if startTime == ChConfig.CustomSceneState_Over:
        return ChConfig.CustomSceneState_Over
    # 保留15分钟
    curTime = int(time.time())
    return ChConfig.CustomSceneState_Fight if curTime - startTime < 15 * 60 else ChConfig.CustomSceneState_None
def SetCustomSceneOver(curPlayer, mapID, lineID):
    ## 设置前端自定义场景副本结束
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_CustomSceneStartTime % (mapID, lineID), ChConfig.CustomSceneState_Over)
    return
def GetCurSingleFBPlayer():
    ''' 获取当前单人副本玩家 '''
    curPlayer = None
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_CrossDemonKing.py
@@ -25,6 +25,7 @@
import PlayerControl
import ShareDefine
import PyGameData
import NPCCommon
import ChConfig
import ChItem
@@ -273,31 +274,41 @@
    PlayerFairyDomain.SetFairyDomainFBEventState(curPlayer, mapID, lineID, PlayerFairyDomain.FDEventState_Visiting)
    return
## 客户端发送刷新自定义副本奖励
def OnRefreshCustomFBPrize(curPlayer, mapID, lineID):
    visitCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FairyDomainVisitCnt)
    fakeImmortalCount = IpyGameDataPY.GetFuncCfg("FakeImmortalCount", 1)
    if visitCount > fakeImmortalCount:
        GameWorld.DebugLog("当前寻访次数不能获取自定义副本奖励!visitCount=%s" % visitCount)
        return []
    if not PlayerFairyDomain.SetFairyDomainFBEventState(curPlayer, mapID, lineID, PlayerFairyDomain.FDEventState_Visiting):
        GameWorld.DebugLog("寻访状态异常不能获取自定义副本奖励!")
        return []
    ipyData = IpyGameDataPY.GetIpyGameDataByCondition("FairyDomain", {"MapID":mapID, "LineID":lineID})
## 自定义场景副本击杀NPC
def DoCustomScene_Player_KillNPC(curPlayer, curNPC, mapID, lineID):
    bossID = curNPC.GetNPCID()
    funcLineID = lineID
    curBossID = GetCurFBLineBOSSID(lineID=funcLineID)
    curState = PlayerFairyDomain.GetFairyDomainFBEventState(curPlayer, mapID, lineID)
    GameWorld.DebugLog("自定义场景击杀NPC: mapID=%s,lineID=%s,bossID=%s,curBossID=%s,eventState=%s"
                       % (mapID, lineID, bossID, curBossID, curState))
    if bossID != curBossID:
        return
    playerID = curPlayer.GetPlayerID()
    ipyData = IpyGameDataPY.GetIpyGameDataByCondition("FairyDomain", {"MapID":mapID, "LineID":funcLineID})
    if not ipyData:
        return []
        return
    eventID = ipyData.GetID()
    eventFBType = ipyData.GetEventFBType()
    if eventFBType != PlayerFairyDomain.FDEventFBType_Client:
        GameWorld.DebugLog("    非前端本,不能掉落!", playerID)
        return
    if curState != PlayerFairyDomain.FDEventState_Visiting:
        GameWorld.DebugLog("    非寻访中,不能掉落!", playerID)
        return
    PlayerFairyDomain.SetFairyDomainFBEventState(curPlayer, mapID, funcLineID, PlayerFairyDomain.FDEventState_Visited)
    isOwner = True
    giveItemList = __GetDemonKingPrizeItemList(curPlayer, mapID, lineID, eventID, isOwner)
    return giveItemList
## 给自定义副本奖励后续处理
## @return: 返回结算副本over信息字典,不含jsonItem信息
def OnGiveCustomFBPrizeOK(curPlayer, mapID, lineID):
    PlayerFairyDomain.SetFairyDomainFBEventState(curPlayer, mapID, lineID, PlayerFairyDomain.FDEventState_Visited)
    ownerID, ownerName = curPlayer.GetPlayerID(), curPlayer.GetPlayerName()
    overDict = {FBCommon.Over_ownerID:ownerID, FBCommon.Over_ownerName:ownerName}
    return overDict
    giveItemList = __GetDemonKingPrizeItemList(curPlayer, mapID, funcLineID, eventID, isOwner)
    NPCCommon.DoGiveItemByVirtualDrop(curPlayer, giveItemList, bossID)
    isPass = 1
    overDict = {FBCommon.Over_ownerID:playerID, FBCommon.Over_ownerName:curPlayer.GetPlayerName(),
                FBCommon.Over_itemInfo:FBCommon.GetJsonItemList(giveItemList)}
    FBCommon.NotifyFBOver(curPlayer, mapID, lineID, isPass, overDict)
    return
def __GetDemonKingPrizeItemList(curPlayer, mapID, lineID, eventID, isOwner):
    giveItemList = PlayerFairyDomain.GetFairyAppointAward(curPlayer, eventID)
@@ -305,19 +316,29 @@
        return giveItemList
    
    # 没有定制奖励则取常规奖励
    # {物品ID:[归属者获得个数饼图[[概率, 个数], ...], 非归属者获得个数饼图[[概率, 个数], ...], 是否拍品], ...}
    # [[归属者随机次数, 非归属随机次数, [[权重,[物品ID,个数,是否拍品]], ...]], ...]
    giveItemList = []
    awardDict = FBCommon.GetFBLineReward(mapID, lineID)
    for itemID, itemInfo in awardDict.items():
        ownerCountRateList, notOwnerCountRateList, isAuctionItem = itemInfo
    awardList = FBCommon.GetFBLineReward(mapID, lineID)
    for awardInfo in awardList:
        ownerCount, otherCount, itemWeightList = awardInfo
        if isOwner:
            itemCount = GameWorld.GetResultByRandomList(ownerCountRateList)
            if not ownerCount:
                continue
            randCount = ownerCount
        else:
            itemCount = GameWorld.GetResultByRandomList(notOwnerCountRateList)
        if not itemCount:
            if not otherCount:
                continue
            randCount = otherCount
        realWeightList = ItemCommon.GetWeightItemListByAlchemyDiffLV(curPlayer, itemWeightList, 1)
        if not realWeightList:
            continue
        giveItemList.append([itemID, itemCount, isAuctionItem])
        
        for _ in xrange(randCount):
            itemInfo = GameWorld.GetResultByWeightList(realWeightList)
            itemID, itemCount, isAuctionItem = itemInfo
            giveItemList.append([itemID, itemCount, isAuctionItem])
    return giveItemList
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_CrossGrassland.py
@@ -39,7 +39,8 @@
        npcID = IpyGameDataPY.GetFuncCfg("CrossGrasslandCfg", 1)
        if npcID:
            NPCCommon.UpdateNPCAttackCount(curPlayer, npcID, 0)
    ResetGrasslandAwardRecord(curPlayer)
    return
## 是否需要做进入副本通用检查条件逻辑,默认需要检查
@@ -127,12 +128,100 @@
## 客户端进入自定义场景
def OnEnterCustomScene(curPlayer, mapID, lineID):
    curState = PlayerFairyDomain.GetFairyDomainFBEventState(curPlayer, mapID, lineID)
    PlayerFairyDomain.SetFairyDomainFBEventState(curPlayer, mapID, lineID, PlayerFairyDomain.FDEventState_Visiting)
    boxNPCID = IpyGameDataPY.GetFuncCfg("CrossGrasslandCfg", 1)
    refreshMapNPCDict = IpyGameDataPY.GetFuncEvalCfg("CrossGrasslandCfg", 2)
    refreshCount, npcIDRateList = refreshMapNPCDict.get(mapID, [0, []])
    npcIDList = [rate[1] for rate in npcIDRateList]
    if curState == PlayerFairyDomain.FDEventState_CanVisit:
        # 随机采集物数量
        for npcID in npcIDList:
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_GrasslandNPCCount % npcID, 0)
        npcCountDict = {}
        for _ in xrange(refreshCount):
            npcID = GameWorld.GetResultByRandomList(npcIDRateList)
            if npcID:
                npcCount = npcCountDict.get(npcID, 0) + 1
                npcCountDict[npcID] = npcCount
                PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_GrasslandNPCCount % npcID, npcCount)
        if mapID == ChConfig.Def_FBMapID_CrossGrasslandXian:
            FBCommon.DelFBEnterTicket(curPlayer, mapID, lineID)
    SyncCustomSceneNPCCount(curPlayer, mapID)
    if mapID == ChConfig.Def_FBMapID_CrossGrasslandXian:
        boxNPCID = IpyGameDataPY.GetFuncCfg("CrossGrasslandCfg", 1)
        if boxNPCID:
            NPCCommon.SyncNPCAttackCount(curPlayer, [boxNPCID])
    return
def DoCheckUpdateGrasslandEnd(curPlayer):
    ## 检查更新草园已拜访完成
def DecCustomSceneNPCCount(curPlayer, npcID):
    ## 减少草园自定义场景NPC,默认减少一个
    mapID = GetGrasslandMapID(curPlayer)[0]
    if not mapID:
        return
    curCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_GrasslandNPCCount % npcID)
    updCount = max(0, curCount - 1)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_GrasslandNPCCount % npcID, updCount)
    SyncCustomSceneNPCCount(curPlayer, mapID)
    return
def SyncCustomSceneNPCCount(curPlayer, mapID):
    ## 通知自定义场景NPC数
    refreshMapNPCDict = IpyGameDataPY.GetFuncEvalCfg("CrossGrasslandCfg", 2)
    npcIDRateList = refreshMapNPCDict.get(mapID, [0, []])[1]
    npcCountDict = {}
    for npcRate in npcIDRateList:
        npcID = npcRate[1]
        npcCountDict[npcID] = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_GrasslandNPCCount % npcID)
    if mapID == ChConfig.Def_FBMapID_CrossGrasslandXian:
        boxNPCID = IpyGameDataPY.GetFuncCfg("CrossGrasslandCfg", 1)
        npcCountDict[boxNPCID] = 1
    NPCCommon.SyncNPCCntInfo(curPlayer, mapID, npcCountDict)
    return
def RecordGrasslandAward(curPlayer, addItemList):
    ## 记录草园奖励信息
    mapID = GetGrasslandMapID(curPlayer)[0]
    if not mapID:
        return
    
    for itemInfo in addItemList:
        if not isinstance(itemInfo, list):
            continue
        itemID, itemCount = itemInfo[:2]
        newIndex = None
        for i in xrange(20):
            itemCountInfo = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_GrasslandDropCount % i)
            if not itemCountInfo:
                newIndex = i
                break
            recItemID = itemCountInfo/100
            if recItemID == itemID:
                updRecValue = itemCountInfo + itemCount
                PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_GrasslandDropCount % i, updRecValue)
                break
        if newIndex != None:
            newRecValue = itemID*100 + itemCount
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_GrasslandDropCount % newIndex, newRecValue)
    return
def ResetGrasslandAwardRecord(curPlayer):
    ## 重置草园奖励信息记录
    for i in xrange(20):
        itemCountInfo = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_GrasslandDropCount % i)
        if not itemCountInfo:
            break
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_GrasslandDropCount % i, 0)
    return
def GetGrasslandMapID(curPlayer):
    grasslandMapIDList = [ChConfig.Def_FBMapID_CrossGrasslandLing, ChConfig.Def_FBMapID_CrossGrasslandXian]
    crossMapID = PlayerControl.GetCrossMapID(curPlayer)
    clientCustomSceneMapID = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomSceneMapID)
@@ -143,6 +232,14 @@
        mapID = clientCustomSceneMapID
        lineID = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomSceneLineID)
    else:
        return 0, 0
    return mapID, lineID
def DoCheckUpdateGrasslandEnd(curPlayer):
    ## 检查更新草园已拜访完成
    mapID, lineID = GetGrasslandMapID(curPlayer)
    if not mapID:
        return
    
    # 采集次数是否已用完
@@ -179,6 +276,19 @@
        
    PlayerFairyDomain.SetFairyDomainFBEventState(curPlayer, mapID, lineID, PlayerFairyDomain.FDEventState_Visited)
    GameWorld.DebugLog("设置草园已完成!mapID=%s, lineID=%s" % (mapID, lineID))
    # 通知结算
    awardItemList = []
    for i in xrange(20):
        itemCountInfo = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_GrasslandDropCount % i)
        if not itemCountInfo:
            break
        isAuctionItem = 0
        itemID, itemCount = itemCountInfo/100, itemCountInfo%100
        awardItemList.append([itemID, itemCount, isAuctionItem])
    overDict = {FBCommon.Over_itemInfo:FBCommon.GetJsonItemList(awardItemList)}
    FBCommon.NotifyFBOver(curPlayer, mapID, lineID, 1, overDict)
    ResetGrasslandAwardRecord(curPlayer)
    return
def DoFB_NPCDead(curNPC):
@@ -191,3 +301,6 @@
    GameWorld.GetGameFB().SetGameFBDict(FBDict_SyncFBNPC, 1)
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_FairyTreasure.py
@@ -11,6 +11,7 @@
# @date 2019-04-09
# @version 1.0
# 详细描述: 缥缈宝藏
# 本副本做前端自定义场景处理,后端无实际地图
#
#---------------------------------------------------------------------
#"""Version = 2019-04-09 11:00"""
@@ -18,56 +19,14 @@
import FBCommon
import GameWorld
import IPY_GameWorld
import NPCCustomRefresh
import IpyGameDataPY
import PlayerControl
import PlayerFairyDomain
import GameWorldProcess
import ItemControler
import ItemCommon
import NPCCommon
import ChConfig
import ChPlayer
import EventReport
import ChNPC
import ItemCommon
FBPlayerDict_CurStep = 'FBPlayerDict_CurStep'   # 当前阶段
FBPlayerDict_StepState = 'FBPlayerDict_StepState'   # 阶段状态
# 副本通用配置
(
Def_PrepareTime, # 准备时间,秒
Def_FightTime, # 战斗时间,秒
Def_LeaveTime, # 退出时间, 秒
Def_CollectTime, # 采集时间, 秒
Def_RefreshBossMark, # 刷怪标识点
Def_RefreshBossMark1, # 刷怪标识点
) = range(6)
#当前副本地图的状态
(
FB_Step_Open,  # 副本开启
FB_Step_Prepare,  # 副本等待
FB_Step_Fighting,  # 副本进行中
#FB_Step_Collect,  # 副本采集中
#FB_Step_PickItem, # 拾取物品中
FB_Step_Over,  # 副本结束
FB_Step_Close,  # 副本关闭
) = range(5)
def __GetFBTimeCfg(lineID=0):
    if not lineID:
        lineID = FBCommon.GetFBPropertyMark()
    return FBCommon.GetFBLineStepTime(ChConfig.Def_FBMapID_FairyTreasure, lineID)
## 是否可进入
#  @param curPlayer
#  @param mapID 地图ID
#  @param lineId 分线ID
#  @param tick
#  @return 是否可进入
def OnEnterFBEvent(curPlayer, mapID, lineId, tick):
    ipyData = IpyGameDataPY.GetIpyGameDataByCondition('FairyDomain', {'MapID':mapID, 'LineID':lineId})
    if not ipyData:
@@ -77,284 +36,18 @@
        return
    return True
##副本玩家进入点
# @param curPlayer 玩家实例
# @param mapID 地图ID
# @param lineId 分线ID
# @param ipyEnterPosInfo 功能线路IPY配置坐标信息
# @param tick 时间戳
# @return posX, posY, 随机半径(可选)
def OnGetFBEnterPos(curPlayer, mapID, lineId, ipyEnterPosInfo, tick):
    return ipyEnterPosInfo
## 是否可以进入
#  @param ask 请求信息
#  @param tick
#  @return 回复是否通过请求
def OnChangeMapAsk(ask, tick):
    return IPY_GameWorld.cmeAccept
## 进副本
#  @param curPlayer
#  @param tick
#  @return None
def DoEnterFB(curPlayer, tick):
    PlayerControl.SetSight(curPlayer, ChConfig.Def_PlayerSight_Default * 3)
    mapID = GameWorld.GetMap().GetMapID()
    mapID = FBCommon.GetRecordMapID(mapID)
    gameFB = GameWorld.GetGameFB()
    lineID = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_ReqFBFuncLine)
    playerID = curPlayer.GetID()
    hadDelTicket = FBCommon.GetHadDelTicket(curPlayer)
    if not hadDelTicket:
        FBCommon.SetHadDelTicket(curPlayer)
        FBCommon.SetFBPropertyMark(lineID)
        boxIDList = FBCommon.GetFBLineRefreshNPC(mapID, lineID)[1:]
        npcCnt = len(boxIDList)
        NPCCustomRefresh.SetNPCRefresh(__GetFBTimeCfg()[Def_RefreshBossMark1], [[npcID,1] for npcID in boxIDList], npcCnt, npcCnt)
    if gameFB.GetGameFBDictByKey(FBPlayerDict_CurStep) == 0:
        FBCommon.SyncDynamicBarrierState(IpyGameDataPY.GetFuncEvalCfg('HazyTreasure'), 1, curPlayer) # 准备期间有动态障碍点
    if not hadDelTicket \
        and IpyGameDataPY.GetIpyGameDataByCondition("NPCShow", {"MapID":mapID, "LineID":lineID}, isLogNone=False):
        GameWorld.DebugLog("刚进入时不直接开始,需等前端通知开始才开始!", playerID)  # 掉线重上强制开始
## 自定义场景采集OK
def OnCustomSceneCollectOK(curPlayer, mapID, lineID, npcID):
    curState = PlayerFairyDomain.GetFairyDomainFBEventState(curPlayer, mapID, lineID)
    if curState != PlayerFairyDomain.FDEventState_Visiting:
        GameWorld.DebugLog("非寻访中,不能结算缥缈宝藏采集!", curPlayer.GetPlayerID())
        return
    fbStep = gameFB.GetFBStep()
    if fbStep < FB_Step_Prepare:
        FBCommon.SetFBStep(FB_Step_Prepare, tick)
    if fbStep <= FB_Step_Prepare:
        notify_tick = __GetFBTimeCfg(lineID)[Def_PrepareTime] * 1000 - (tick - GameWorld.GetGameFB().GetFBStepTick())
        curPlayer.Sync_TimeTick(IPY_GameWorld.tttWaitStart, 0, max(notify_tick, 0), True)
    elif fbStep == FB_Step_Fighting:
        notify_tick = __GetFBTimeCfg(lineID)[Def_FightTime] * 1000 - (tick - GameWorld.GetGameFB().GetFBStepTick())
        curPlayer.Sync_TimeTick(IPY_GameWorld.tttTowerTake, 0, max(notify_tick, 0), True)
    else:
        PlayerControl.PlayerLeaveFB(curPlayer)
        return
    DoFBHelp(curPlayer, tick)
    return
## 客户端发送开始副本
def OnClientStartFB(curPlayer, tick):
    gameFB = GameWorld.GetGameFB()
    fbStep = gameFB.GetFBStep()
    if fbStep >= FB_Step_Prepare:
        GameWorld.ErrLog("前端请求正式开始副本, 但副本已经开始了,不可重复开始!", curPlayer.GetPlayerID())
        return
    lineID = FBCommon.GetFBPropertyMark()
    GameWorld.DebugLog("前端场景秀已播放完毕,请求正式开始副本!lineID=%s" % lineID, curPlayer.GetPlayerID())
    FBCommon.SetFBStep(FB_Step_Prepare, tick)
    notify_tick = __GetFBTimeCfg(lineID)[Def_PrepareTime] * 1000 - (tick - GameWorld.GetGameFB().GetFBStepTick())
    curPlayer.Sync_TimeTick(IPY_GameWorld.tttWaitStart, 0, max(notify_tick, 0), True)
    DoFBHelp(curPlayer, tick)
    return
## 副本时间到关闭
#  @param tick 当前时间
#  @return None
#  @remarks 函数详细说明.
def OnCloseFB(tick):
    return
## 获得副本帮助信息
#  @param curPlayer 当前玩家(被通知对象)
#  @param tick 当前时间
#  @return None
def DoFBHelp(curPlayer, tick):
    gameFB = GameWorld.GetGameFB()
    curStep = gameFB.GetGameFBDictByKey(FBPlayerDict_CurStep) + 1
    helpDict = {FBCommon.Help_step:curStep, FBCommon.Help_npcTotal:gameFB.GetGameFBDictByKey(FBPlayerDict_StepState)}
    GameWorld.DebugLog("DoFBHelp %s" % str(helpDict))
    FBCommon.Notify_FBHelp(curPlayer, helpDict)
    return
##玩家退出副本.
# @param curPlayer 玩家实例
# @param tick 时间戳
# @return 返回值无意义
# @remarks 玩家主动离开副本.
def DoExitFB(curPlayer, tick):
    PlayerControl.SetSight(curPlayer, ChConfig.Def_PlayerSight_Default)
    # 玩家退出默认关闭副本
    #GameWorldProcess.CloseFB(tick)
    return
##副本总逻辑计时器
# @param tick 时间戳
# @return 无意义
# @remarks 副本总逻辑计时器
def OnProcess(tick):
    gameFB = GameWorld.GetGameFB()
    fbStep = gameFB.GetFBStep()
    # 副本准备
    if fbStep == FB_Step_Prepare:
        __DoLogic_FB_Prepare(tick)
    # 副本进行中
    elif fbStep == FB_Step_Fighting:
        __DoLogic_FB_Fighting(tick)
#    # 副本拾取中
#    elif fbStep == FB_Step_PickItem:
#        __DoLogic_FB_PickItem(tick)
    # 副本结束
    elif fbStep == FB_Step_Over:
        __DoLogic_FB_Over(tick)
    return
##战斗准备时间
# @param tick  时钟
# @return 无意义
def __DoLogic_FB_Prepare(tick):
    gameFB = GameWorld.GetGameFB()
    mapID = GameWorld.GetMap().GetMapID()
    lineID = FBCommon.GetFBPropertyMark()
    trialCfg = __GetFBTimeCfg(lineID)
    if tick - gameFB.GetFBStepTick() < trialCfg[Def_PrepareTime] * 1000:
        return
    FBCommon.Sync_Player_TimeTick(IPY_GameWorld.tttTowerTake, trialCfg[Def_FightTime] * 1000)
    bossID = FBCommon.GetFBLineRefreshNPC(mapID, lineID)[0]
    NPCCustomRefresh.SetNPCRefresh(trialCfg[Def_RefreshBossMark], [bossID])
    #转入战斗
    FBCommon.SetFBStep(FB_Step_Fighting, tick)
    return
##战斗时间
# @param tick  时钟
# @return 无意义
def __DoLogic_FB_Fighting(tick):
    gameFB = GameWorld.GetGameFB()
    #判断时间结束
    if tick - gameFB.GetFBStepTick() < __GetFBTimeCfg()[Def_FightTime] * 1000:
        return
    #游戏结束
    FBCommon.SetFBStep(FB_Step_Over, tick)
    return
##副本关闭中
# @param tick:时间戳
# @return 无意义
# @remarks 副本关闭中
def __DoLogic_FB_Over(tick):
    # 间隔未到
    if tick - GameWorld.GetGameFB().GetFBStepTick() < __GetFBTimeCfg()[Def_LeaveTime] * 1000:
        return
    #副本关闭
    GameWorldProcess.CloseFB(tick)
    FBCommon.SetFBStep(FB_Step_Close, tick)
    return
## 杀怪
#  @param curPlayer
#  @param curNPC 被杀的怪
#  @param tick
#  @return None
def DoFB_Player_KillNPC(curPlayer, curNPC, tick):
    mapID = GameWorld.GetMap().GetMapID()
    lineID = FBCommon.GetFBPropertyMark()
    bossID = FBCommon.GetFBLineRefreshNPC(mapID, lineID)[0]
    if bossID != curNPC.GetNPCID():
        return
    #刷宝箱进入采集阶段
    GameWorld.GetGameFB().SetGameFBDict(FBPlayerDict_CurStep, 1)
    DoFBHelp(curPlayer, tick)
    FBCommon.SyncDynamicBarrierState(IpyGameDataPY.GetFuncEvalCfg('HazyTreasure'), 0, curPlayer)
    #特效NPC消失
    FBCommon.ClearFBNPCEx(FBCommon.GetFBLineRefreshNPC(mapID, lineID)[2:])
    #FBCommon.SetFBStep(FB_Step_Collect, tick)
    #NPCCustomRefresh.SetNPCRefresh(__GetFBTimeCfg()[Def_RefreshBossMark], [boxID])
    return
## 检查是否可攻击, 主判定不可攻击的情况,其他逻辑由外层决定
#  @param attacker 攻击方
#  @param defender 防守方
#  @return bool
def CheckCanAttackTagObjInFB(attacker, defender):
    gameFB = GameWorld.GetGameFB()
    if gameFB.GetFBStep() != FB_Step_Fighting:
        return False
    return True
##是否可以采集
# @param curPlayer 玩家实例
# @param curNPC NPC实例
# @param tick 时间戳
# @return 无意义
# @remarks
def OnCanCollect(curPlayer, curNPC, tick):
    gameFB = GameWorld.GetGameFB()
    curStep = gameFB.GetGameFBDictByKey(FBPlayerDict_CurStep)
    return curStep == 1
##副本中,采集物需要Loading时间.
# @param curPlayer 玩家实例
# @param curNPC NPC实例
# @return 返回值, Loading时间
# @remarks 副本中,采集物需要Loading时间
def GetFBPrepareTime(curPlayer, curNPC):
    return __GetFBTimeCfg()[Def_CollectTime] * 1000
##玩家收集成功(塔, 旗)
# @param curPlayer 玩家实例
# @param tick 时间戳
# @return 无意义
# @remarks
def OnCollectOK(curPlayer, npcID, tick):
    playerID = curPlayer.GetID()
    tagObj = curPlayer.GetActionObj()
    if not tagObj:
        return
    if tagObj.GetGameObjType() != IPY_GameWorld.gotNPC:
        return
    curNPC = GameWorld.GetNPCManager().GetNPCByIndex(tagObj.GetIndex())
    if not curNPC:
        return
    dropPosX, dropPosY = curNPC.GetPosX(), curNPC.GetPosY()
    ChNPC.OnCollectEnd(curPlayer, curNPC)
    GameWorld.DebugLog('    采集成功!', playerID)
    GameWorld.GetGameFB().SetGameFBDict(FBPlayerDict_StepState, 1)
    DoFBHelp(curPlayer, 0)
    #掉落给奖励
    DoFairyTreasureOver(curPlayer, tick, dropPosX, dropPosY)
    return
def DoFairyTreasureOver(curPlayer, tick, dropPosX, dropPosY):
    #[[(4000,[141,1,1])],[(4000,[141,1,1])]]
    FBCommon.SetFBStep(FB_Step_Over, tick)
    lineID = FBCommon.GetFBPropertyMark()
    ipyData = IpyGameDataPY.GetIpyGameDataByCondition('FairyDomain', {'MapID':ChConfig.Def_FBMapID_FairyTreasure, 'LineID':lineID})
    fdeventID = ipyData.GetID()
    PlayerFairyDomain.SetFairyDomainEventState(curPlayer, fdeventID, PlayerFairyDomain.FDEventState_Visited)
    giveItemList = PlayerFairyDomain.GetFairyAppointAward(curPlayer, fdeventID)
    dropItemList = []
    if not giveItemList:
        awardCfg = FBCommon.GetFBLineReward(ChConfig.Def_FBMapID_FairyTreasure, lineID)
        curAlchemyLV = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_AlchemyLV)
@@ -376,34 +69,11 @@
            randomitem = GameWorld.GetResultByWeightList(newItemInfoList)
            giveItemList.append(randomitem)
            
    if giveItemList:
        for randomitem in giveItemList:
            for _ in xrange(randomitem[1]):
                dropItemList.append([randomitem[0],1,randomitem[2]])
        NPCCommon.DoVirtualItemDrop(curPlayer, dropItemList, dropPosX, dropPosY)
        ItemControler.GivePlayerItemOrMail(curPlayer, giveItemList)
        leaveTick = __GetFBTimeCfg(lineID)[Def_LeaveTime] * 1000
        curPlayer.Sync_TimeTick(IPY_GameWorld.tttLeaveMap, 0, leaveTick, True)
        overDict = {FBCommon.Over_itemInfo:FBCommon.GetJsonItemList(giveItemList)}
        FBCommon.NotifyFBOver(curPlayer, ChConfig.Def_FBMapID_FairyTreasure, lineID, 1, overDict)
    PlayerFairyDomain.SetFairyDomainEventState(curPlayer, fdeventID, PlayerFairyDomain.FDEventState_Visited)
        NPCCommon.DoGiveItemByVirtualDrop(curPlayer, giveItemList, npcID)
    overDict = {FBCommon.Over_itemInfo:FBCommon.GetJsonItemList(giveItemList)}
    FBCommon.NotifyFBOver(curPlayer, ChConfig.Def_FBMapID_FairyTreasure, lineID, 1, overDict)
    return
## 是否副本复活
#  @param None
#  @return 是否副本复活
def OnPlayerReborn():
    return True
## 副本行为
#  @param curPlayer 玩家
#  @param actionType 行为类型
#  @param actionInfo 行为信息
#  @param tick 当前时间
#  @return None
def DoFBAction(curPlayer, actionType, actionInfo, tick):
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_PersonalBoss.py
@@ -2,287 +2,79 @@
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
#-------------------------------------------------------------------------------
#
##@package GameWorldLogic.FBProcess.GameLogic_PersonalBoss
#
# @todo:个人BOSS
# @author xdh
# @date 2017-05-05
# @todo:个人Boss、VIPBoss
# @author hxp
# @date 2019-05-23
# @version 1.0
# 详细描述: 个人BOSS
#
#---------------------------------------------------------------------
#"""Version = 2017-05-05 11:00"""
#---------------------------------------------------------------------
# 详细描述: 个人Boss、VIPBoss
# 本副本做前端自定义场景处理,后端无实际地图
#
#-------------------------------------------------------------------------------
#"""Version = 2019-05-23 17:30"""
#-------------------------------------------------------------------------------
import FBCommon
import GameWorld
import IPY_GameWorld
import NPCCustomRefresh
import IpyGameDataPY
import PlayerBossReborn
import PlayerFairyCeremony
import PlayerNewFairyCeremony
import ChConfig
import ChPlayer
import EventReport
import PlayerBossReborn
import PlayerNewFairyCeremony
import PlayerFairyCeremony
import IpyGameDataPY
import NPCCommon
import ChConfig
# 副本通用配置
(
Def_PrepareTime, # 准备时间,秒
Def_FightTime, # 战斗时间,秒
Def_ExitTime, # 退出时间, 秒
Def_RefreshBossMark, # 刷怪标识点
) = range(4)
# 副本状态
(
FB_State_Open, # 副本开启
FB_State_FightPrepare, # 战斗准备时间
FB_State_Fighting, # 战斗
FB_State_FreeTime, # 活动结束准备(胜利/失败)
FB_State_Close, # 关闭副本
) = range(5)
## 是否可进入
#  @param curPlayer
#  @param mapID 地图ID
#  @param lineId 分线ID
#  @param tick
#  @return 是否可进入
def OnEnterFBEvent(curPlayer, mapID, lineId, tick):
## 是否需要做进入副本通用检查条件逻辑,默认需要检查
def OnNeedCheckCanEnterFBComm(curPlayer, mapID, lineID):
    ## 进行中的不需要重复检查,防止断线重连被禁止进入
    if FBCommon.GetCustomSceneState(curPlayer, mapID, lineID) == ChConfig.CustomSceneState_Fight:
        GameWorld.DebugLog("VIPBoss已经在进行中,本次进入不需要重新检查!")
        return False
    return True
## 检查可否进行挑战
def __CheckCanChallenge(curPlayer, bossID):
    ipyData = IpyGameDataPY.GetIpyGameData('PersonalBoss', bossID)
## 客户端进入自定义场景
def OnEnterCustomScene(curPlayer, mapID, lineID):
    
    if FBCommon.SetCustomSceneStart(curPlayer, mapID, lineID):
        FBCommon.DelFBEnterTicket(curPlayer, ChConfig.Def_FBMapID_PersonalBoss)
        #增加进入次数
        FBCommon.AddEnterFBCount(curPlayer, ChConfig.Def_FBMapID_PersonalBoss)
        EventReport.WriteEvent_FB(curPlayer, ChConfig.Def_FBMapID_PersonalBoss, 0, ChConfig.CME_Log_Start)
        PlayerBossReborn.AddBossRebornActionCnt(curPlayer, ChConfig.Def_BRAct_VIPBOSS, 1)
        PlayerFairyCeremony.AddFCPartyActionCnt(curPlayer, ChConfig.Def_PPAct_VIPBoss, 1)
        PlayerNewFairyCeremony.AddFCPartyActionCnt(curPlayer, ChConfig.Def_PPAct_VIPBoss, 1)
    return
## 自定义场景副本击杀NPC
def DoCustomScene_Player_KillNPC(curPlayer, curNPC, mapID, lineID):
    npcID = curNPC.GetNPCID()
    bossID = __GetPersonalBossID(lineID)
    GameWorld.DebugLog("个人boss场景击杀NPC: npcID=%s,bossID=%s" % (npcID, bossID), curPlayer.GetPlayerID())
    if npcID != bossID:
        return
    if FBCommon.GetCustomSceneState(curPlayer, mapID, lineID) != ChConfig.CustomSceneState_Fight:
        return
    FBCommon.SetCustomSceneOver(curPlayer, mapID, lineID)
    npcCountDict = {bossID:1}
    dropItemMapInfo = [0, 0]
    jsonItemList = NPCCommon.GiveKillNPCDropPrize(curPlayer, mapID, npcCountDict, dropItemMapInfo=dropItemMapInfo, isVirtualDrop=True)[0]
    isPass = 1
    overDict = {FBCommon.Over_itemInfo:jsonItemList}
    FBCommon.NotifyFBOver(curPlayer, mapID, lineID, isPass, overDict)
    return
def __GetPersonalBossID(lineID):
    ## VIPbossID
    ipyData = IpyGameDataPY.GetIpyGameData('PersonalBoss', lineID)
    if not ipyData:
        return False
    needLV = ipyData.GetChanllengeLv()
    if curPlayer.GetLV() < needLV:
        GameWorld.DebugLog('    检查可否进行挑战 bossID-%s  等级不足 %s'%(bossID, needLV))
        return False
    delResult = FBCommon.DelFBEnterTicket(curPlayer, ChConfig.Def_FBMapID_PersonalBoss)
    isOK = delResult[0]
    if not isOK:
        return False
    return True
        return 0
    return ipyData.GetNPCID()
##副本玩家进入点
# @param curPlayer 玩家实例
# @param mapID 地图ID
# @param lineId 分线ID
# @param ipyEnterPosInfo 功能线路IPY配置坐标信息
# @param tick 时间戳
# @return posX, posY, 随机半径(可选)
def OnGetFBEnterPos(curPlayer, mapID, lineId, ipyEnterPosInfo, tick):
    return ipyEnterPosInfo
## 是否可以进入
#  @param ask 请求信息
#  @param tick
#  @return 回复是否通过请求
def OnChangeMapAsk(ask, tick):
    return IPY_GameWorld.cmeAccept
## 进副本
#  @param curPlayer
#  @param tick
#  @return None
def DoEnterFB(curPlayer, tick):
    # 不做处理,有副本行为客户端发包选择挑战关卡
    return
## 副本时间到关闭
#  @param tick 当前时间
#  @return None
#  @remarks 函数详细说明.
def OnCloseFB(tick):
    return
##玩家退出副本.
# @param curPlayer 玩家实例
# @param tick 时间戳
# @return 返回值无意义
# @remarks 玩家主动离开副本.
def DoExitFB(curPlayer, tick):
    # 玩家退出默认关闭副本
    #GameWorldProcess.CloseFB(tick)
    return
##副本总逻辑计时器
# @param tick 时间戳
# @return 无意义
# @remarks 副本总逻辑计时器
def OnProcess(tick):
    gameFB = GameWorld.GetGameFB()
    fbStep = gameFB.GetFBStep()
    if fbStep == FB_State_FightPrepare:
        __DoLogic_FightPrepare(tick)
    elif fbStep == FB_State_Fighting:
        __DoLogic_Fighting(tick)
    elif fbStep == FB_State_FreeTime:
        __DoLogic_FreeTime(tick)
    elif fbStep == FB_State_Close:
        pass
    return
##战斗准备时间
# @param tick  时钟
# @return 无意义
def __DoLogic_FightPrepare(tick):
    gameFB = GameWorld.GetGameFB()
    mapID = GameWorld.GetMap().GetMapID()
    trialCfg = FBCommon.GetFBLineStepTime(mapID)
    if tick - gameFB.GetFBStepTick() < trialCfg[Def_PrepareTime] * 1000:
        return
    bossID = FBCommon.GetFBPropertyMark()
    if not bossID:
        FBCommon.DoLogic_FBKickAllPlayer()
        return
    FBCommon.Sync_Player_TimeTick(IPY_GameWorld.tttTowerTake, trialCfg[Def_FightTime] * 1000)
    NPCCustomRefresh.SetNPCRefresh(FBCommon.GetFBLineStepTime(mapID)[Def_RefreshBossMark], [bossID])
    #转入战斗
    FBCommon.SetFBStep(FB_State_Fighting, tick)
    return
## 开始副本关卡
def StartFBLevel(curPlayer, bossID, tick):
    FBCommon.SetFBPropertyMark(bossID)
    if curPlayer.GetPlayerAction() == IPY_GameWorld.paDie:
        GameWorld.DebugLog("复活玩家...", curPlayer.GetPlayerID())
        ChPlayer.PlayerRebornByType(curPlayer, ChConfig.rebornType_City, tick)
    #增加进入次数
    FBCommon.AddEnterFBCount(curPlayer, ChConfig.Def_FBMapID_PersonalBoss)
    EventReport.WriteEvent_FB(curPlayer, ChConfig.Def_FBMapID_PersonalBoss, 0, ChConfig.CME_Log_Start)
    PlayerBossReborn.AddBossRebornActionCnt(curPlayer, ChConfig.Def_BRAct_VIPBOSS, 1)
    PlayerFairyCeremony.AddFCPartyActionCnt(curPlayer, ChConfig.Def_PPAct_VIPBoss, 1)
    PlayerNewFairyCeremony.AddFCPartyActionCnt(curPlayer, ChConfig.Def_PPAct_VIPBoss, 1)
    FBCommon.ClearFBNPC()
    #gameFB = GameWorld.GetGameFB()
    mapID = GameWorld.GetMap().GetMapID()
    prepareTick = FBCommon.GetFBLineStepTime(mapID)[Def_PrepareTime] * 1000
    FBCommon.Sync_Player_TimeTick(IPY_GameWorld.tttAddUpTime, prepareTick)
    FBCommon.Sync_Player_TimeTick(IPY_GameWorld.tttWaitStart, prepareTick)
    FBCommon.SetFBStep(FB_State_FightPrepare, tick)
    helpDict = {FBCommon.Help_npcTotal:0}
    FBCommon.Notify_FBHelp(curPlayer, helpDict)
    GameWorld.DebugLog("StartFBLevel, fbLevel=%s, helpDict=%s"
                       % (bossID, str(helpDict)), curPlayer.GetPlayerID())
    return
##战斗时间
# @param tick  时钟
# @return 无意义
def __DoLogic_Fighting(tick):
    gameFB = GameWorld.GetGameFB()
    mapID = GameWorld.GetMap().GetMapID()
    #判断时间结束
    if tick - gameFB.GetFBStepTick() < FBCommon.GetFBLineStepTime(mapID)[Def_FightTime] * 1000:
        return
    #游戏结束
    __SetFBToFreeTime(tick)
    return
##设置副本进入离开状态
# @param tick  时钟
# @return 无意义
def __SetFBToFreeTime(tick):
    mapID = GameWorld.GetMap().GetMapID()
    FBCommon.Sync_Player_TimeTick(IPY_GameWorld.tttLeaveMap, FBCommon.GetFBLineStepTime(mapID)[Def_ExitTime] * 1000)
    FBCommon.SetFBStep(FB_State_FreeTime, tick)
    return
##比赛结束的空闲时间
# @param tick  时钟
# @return 无意义
# @remarks 比赛结束的空闲时间
def __DoLogic_FreeTime(tick):
    mapID = GameWorld.GetMap().GetMapID()
    if tick - GameWorld.GetGameFB().GetFBStepTick() < FBCommon.GetFBLineStepTime(mapID)[Def_ExitTime] * 1000:
        return
    FBCommon.DoLogic_FBKickAllPlayer()
    return
## 杀怪
#  @param curPlayer
#  @param curNPC 被杀的怪
#  @param tick
#  @return None
def DoFB_Player_KillNPC(curPlayer, curNPC, tick):
    bossID = FBCommon.GetFBPropertyMark()
    if bossID != curNPC.GetNPCID():
        return
    helpDict = {FBCommon.Help_npcTotal:1}
    FBCommon.Notify_FBHelp(curPlayer, helpDict)
    __SetFBToFreeTime(tick)
    return
## 检查是否可攻击, 主判定不可攻击的情况,其他逻辑由外层决定
#  @param attacker 攻击方
#  @param defender 防守方
#  @return bool
def CheckCanAttackTagObjInFB(attacker, defender):
    gameFB = GameWorld.GetGameFB()
    if gameFB.GetFBStep() != FB_State_Fighting:
        return False
    return True
## 是否副本复活
#  @param None
#  @return 是否副本复活
def OnPlayerReborn():
    return True
## 副本行为
#  @param curPlayer 玩家
#  @param actionType 行为类型
#  @param actionInfo 行为信息
#  @param tick 当前时间
#  @return None
def DoFBAction(curPlayer, actionType, actionInfo, tick):
    # 默认为选择关卡,由客户端决定,进场及副本选关通用此行为
    if actionInfo <= 0:
        return
    gameFB = GameWorld.GetGameFB()
    fbStep = gameFB.GetFBStep()
    if fbStep in [FB_State_FightPrepare, FB_State_Fighting]:
        GameWorld.DebugLog("准备或战斗中, 无法变更关卡!")
        return
    bossid = actionInfo
    if not __CheckCanChallenge(curPlayer, bossid):
        FBCommon.DoLogic_FBKickAllPlayer()
        return
    StartFBLevel(curPlayer, bossid, tick)
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
@@ -731,8 +731,8 @@
                        ),
                "PersonalBoss":(
                        ("DWORD", "NPCID", 1),
                        ("DWORD", "ChanllengeLv", 0),
                        ("DWORD", "NPCID", 0),
                        ("DWORD", "FuncLineID", 1),
                        ),
                "FamilyActivity":(
@@ -2923,11 +2923,11 @@
    
    def __init__(self):
        self.NPCID = 0
        self.ChanllengeLv = 0
        self.FuncLineID = 0
        return
        
    def GetNPCID(self): return self.NPCID # ID
    def GetChanllengeLv(self): return self.ChanllengeLv # 可挑战等级
    def GetFuncLineID(self): return self.FuncLineID # 可挑战等级
# 仙盟活跃表
class IPY_FamilyActivity():
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/ChNPC.py
@@ -127,6 +127,7 @@
#  @return None
#  @remarks 函数详细说明.
def OnNPCAttacked(atkObj, curNPC, skill, tick):
    NPCCommon.OnNPCAttacked(atkObj, curNPC, skill, tick)
    callFunc = GameWorld.GetExecFunc(NPCAI, "AIType_%d.%s"%(curNPC.GetAIType(), "OnAttacked"))
    if callFunc == None:
        return None
@@ -134,6 +135,7 @@
    callFunc(atkObj, curNPC, skill, tick)
    
    PlayerActivity.OnAttackNPCActivity(atkObj, curNPC)
    return
def OnCheckCanDie(atkObj, curNPC, skill, tick):
    callFunc = GameWorld.GetExecFunc(NPCAI, "AIType_%d.%s"%(curNPC.GetAIType(), "OnCheckCanDie"))
@@ -437,7 +439,7 @@
        GameWorld.GetGameFB().SetGameFBDict(ChConfig.Def_FBDict_NPCShowEndTick % npcID, 0)
        GameWorld.DebugLog("NPC秀结束,开始处理AI!npcID=%s,tick=%s,endTick=%s" % (npcID, tick, endTick))
        
    callFunc = GameWorld.GetExecFunc(NPCAI, "AIType_%d.%s"%(curNPC.GetAIType(), "ProcessAI"))
    callFunc = GameWorld.GetExecFunc(NPCAI, "AIType_%s.%s"%(GetAIName(curNPC), "ProcessAI"))
    if callFunc == None:
        #NPCAI不可使用
#        #默认call类型1的AI
@@ -447,7 +449,12 @@
        return
    
    callFunc(curNPC, tick)
    return
def GetAIName(curNPC):
    if curNPC.GetType() in [ChConfig.ntPriWoodPilePVE, ChConfig.ntPriWoodPilePVP]:
        return "PriWood"
    return curNPC.GetAIType()
##################################################logic
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCAI/AIType_196.py
@@ -20,12 +20,8 @@
import GameWorld
import NPCCommon
import IPY_GameWorld
import PlayerControl
import IpyGameDataPY
import AttackCommon
import ItemCommon
import AICommon
import GameObj
import ChItem
import random
@@ -246,14 +242,10 @@
#  @param tick 
#  @return 具体伤害值
def OnAttacked(atkObj, curNPC, skill, tick):
    npcControl = NPCCommon.NPCControl(curNPC)
    if GameObj.GetHP(curNPC) < GameObj.GetMaxHP(curNPC) / 2:
        GameObj.SetHP(curNPC, GameObj.GetMaxHP(curNPC))
        GameWorld.DebugLog("半血回满血!")
    curNPC.SetDict(Def_NPCKey_Goblin_AttackedTick, tick) # 设置被攻击时间
    # 每次被攻击掉落物品
    __OnAttackedDropItem(atkObj, curNPC, npcControl)
    return
def OnCheckCanDie(atkObj, curNPC, skill, tick):
@@ -261,65 +253,4 @@
    GameObj.SetHP(curNPC, GameObj.GetMaxHP(curNPC))
    GameWorld.DebugLog("死亡回满血!")
    return False
## 每次被攻击掉落物品
#  @param atkObj 攻击发起者
#  @param curNPC 被攻击NPC
#  @return None
def __OnAttackedDropItem(atkObj, curNPC, npcControl):
    attackPlayer, npcObjType = AttackCommon.GetAttackPlayer(atkObj)
    if npcObjType:
        return
    if not attackPlayer:
        return
    npcID = curNPC.GetNPCID()
    ipyData = IpyGameDataPY.GetIpyGameDataNotLog("TreasureNPC", npcID)
    if not ipyData:
        return
    attackCountDropWeightInfo = ipyData.GetAttackCountDropWeightInfo()
    attackDropWeightList = ipyData.GetAttackDropWeightList()
    attackDropWeightListEx = ipyData.GetAttackDropWeightListEx()
    dropCountEx = ipyData.GetDropCountEx()
    alchemyDiffLV = ipyData.GetAlchemyDiffLV()
    mainItemWeightList = []
    if attackCountDropWeightInfo:
        maxCount = max(attackCountDropWeightInfo)
        attackCount = attackPlayer.NomalDictGetProperty(ChConfig.Def_PDict_NPCAttackCount % npcID) + 1
        if attackCount <= maxCount:
            if attackCount in attackCountDropWeightInfo:
                mainItemWeightList = attackCountDropWeightInfo[attackCount]
            NPCCommon.UpdateNPCAttackCount(attackPlayer, npcID, attackCount, maxCount)
    if mainItemWeightList:
        mainItemWeightList = ItemCommon.GetWeightItemListByAlchemyDiffLV(attackPlayer, mainItemWeightList, alchemyDiffLV)
    elif attackDropWeightList:
        mainItemWeightList = ItemCommon.GetWeightItemListByAlchemyDiffLV(attackPlayer, attackDropWeightList, alchemyDiffLV)
    mainItemInfo = GameWorld.GetResultByWeightList(mainItemWeightList)
    if not mainItemInfo:
        notDropNotify = ipyData.GetNotDropNotify()
        if notDropNotify:
            PlayerControl.NotifyCode(attackPlayer, notDropNotify)
        return
    dropItemList = []
    if mainItemInfo:
        dropItemList.append(mainItemInfo)
    if attackDropWeightListEx and dropCountEx:
        weightListEx = ItemCommon.GetWeightItemListByAlchemyDiffLV(attackPlayer, attackDropWeightListEx, alchemyDiffLV)
        for _ in xrange(dropCountEx):
            itemInfo = GameWorld.GetResultByWeightList(weightListEx)
            if itemInfo:
                dropItemList.append(itemInfo)
    if not dropItemList:
        return
    dropPosX, dropPosY = curNPC.GetPosX(), curNPC.GetPosY()
    ChItem.DoMapDropItem(attackPlayer, dropItemList, npcID, dropPosX, dropPosY, isOnlySelfSee=False)
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCAI/AIType_PriWood.py
File was renamed from ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCAI/AIType_202.py
@@ -2,17 +2,17 @@
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package NPCAI.AIType_202
##@package NPCAI.AIType_PriWood
#
# @todo:专属木桩
# @author hxp
# @date 2019-04-29
# @date 2019-05-23
# @version 1.0
#
# 详细描述: 跟随主人
#
#-------------------------------------------------------------------------------
#"""Version = 2019-04-29 17:00"""
#"""Version = 2019-05-23 17:30"""
#-------------------------------------------------------------------------------
import IPY_GameWorld
@@ -37,7 +37,7 @@
    npcControl.RefreshBuffState(tick)
    
    owner = NPCCommon.GetNpcObjOwnerDetail(curNPC)
    if GameWorld.GetDist(curNPC.GetPosX(), curNPC.GetPosY(), owner.GetPosX(), owner.GetPosY()) > 5:
    if GameWorld.GetDist(curNPC.GetPosX(), curNPC.GetPosY(), owner.GetPosX(), owner.GetPosY()) > 3:
        resetPos = GameMap.GetEmptyPlaceInArea(owner.GetPosX(), owner.GetPosY(), 2)
        curNPC.ResetPos(resetPos.GetPosX(), resetPos.GetPosY())
        
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py
@@ -397,7 +397,7 @@
    return attrDict
def GiveKillNPCDropPrize(curPlayer, mapID, npcCountDict, exp_rate=None, mailTypeKey=None, isMail=False, 
                         extraItemList=[], prizeMultiple=1, dropItemMapInfo=[], curGrade=0):
                         extraItemList=[], prizeMultiple=1, dropItemMapInfo=[], curGrade=0, isVirtualDrop=False):
    '''给玩家击杀NPC掉落奖励
    @param mapID: 击杀的NPC所在地图ID,注意次地图并不一定是玩家当前地图
    @param npcCountDict: 执行单次时所击杀的npc数量字典 {npcID:count, ...}
@@ -406,6 +406,9 @@
    @param isMail: 是否强制发送邮件,若是则不考虑背包空间,否的话只在背包空间不足时才发送邮件
    @param extraItemList: 固定附加物品列表,如果需执行多次,则此固定产出列表需在外层处理好,内层不做多次执行处理。[[itemID, itemCount, isAuctionItem], ...]
    @param prizeMultiple: 奖励倍值, 对所有奖励有效,等于击杀多次NPC,多倍附加物品
    @param dropItemMapInfo: 掉落地板信息 [dropPosX, dropPosY, 是否仅自己可见, 堆叠物品是否散开]
    @param curGrade: 评级
    @param isVirtualDrop: 是否给物品虚拟掉落表现
    '''
    if not exp_rate:
        exp_rate = PlayerControl.GetPlayerExpRate(curPlayer)
@@ -508,45 +511,15 @@
        
    ## 直接掉地板上
    if dropItemMapInfo:
        dropPosX, dropPosY, isOnlySelfSee = dropItemMapInfo[:3]
        dropPosX, dropPosY = dropItemMapInfo[:2]
        isOnlySelfSee = dropItemMapInfo[2] if len(dropItemMapInfo) > 2 else False # 是否仅自己可见
        isDropDisperse = dropItemMapInfo[3] if len(dropItemMapInfo) > 3 else False # 堆叠的物品是否散开掉落
        if isDropDisperse:
            dropItemList = []
            for itemInfo in prizeItemList:
                if isinstance(itemInfo, list):
                    itemID, itemCount, isAuctionItem = itemInfo
                    for _ in xrange(itemCount):
                        dropItemList.append([itemID, 1, isAuctionItem])
                else:
                    dropItemList.append(itemInfo)
        ## 虚拟掉落表现
        if isVirtualDrop:
            DoGiveItemByVirtualDrop(curPlayer, prizeItemList, npcID, dropPosX, dropPosY, isDropDisperse, mailTypeKey)
        else:
            dropItemList = prizeItemList
        index = 0
        playerID = curPlayer.GetPlayerID()
        gameMap = GameWorld.GetMap()
        for posX, posY in ChConfig.Def_DropItemAreaMatrix:
            resultX = dropPosX + posX
            resultY = dropPosY + posY
            DoMapDropPrizeItem(curPlayer, prizeItemList, npcID, dropPosX, dropPosY, isDropDisperse, isOnlySelfSee)
            
            if not gameMap.CanMove(resultX, resultY):
                #玩家不可移动这个点
                continue
            if index > len(dropItemList) - 1:
                break
            curItem = dropItemList[index]
            index += 1
            if isinstance(curItem, list):
                itemID, itemCount, isAuctionItem = curItem
                curItem = ItemControler.GetOutPutItemObj(itemID, itemCount, isAuctionItem)
            if not curItem:
                continue
            ChItem.AddMapDropItem(resultX, resultY, curItem, ownerInfo=[ChConfig.Def_NPCHurtTypePlayer, playerID],
                                  dropNPCID=npcID, isOnlySelfSee=isOnlySelfSee)
    ## 发邮件 或 背包空间不足
    elif isMail or needSpace > ItemCommon.GetItemPackSpace(curPlayer, IPY_GameWorld.rptItem, needSpace):
        mailItemList = []
@@ -602,6 +575,110 @@
        dropItemDataStr = ChItem.GetMapDropItemDataStr(curItem)
        SendVirtualItemDrop(curPlayer, itemID, resultX, resultY, dropItemDataStr)
        curItem.Clear()
    return
def DoMapDropPrizeItem(curPlayer, prizeItemList, npcID, dropPosX, dropPosY, isDropDisperse=True, isOnlySelfSee=True):
    ## 奖励物品真实掉落地图,先拆开分散再掉落
    if isDropDisperse:
        dropItemList = []
        for itemInfo in prizeItemList:
            if isinstance(itemInfo, list):
                itemID, itemCount, isAuctionItem = itemInfo
                for _ in xrange(itemCount):
                    dropItemList.append([itemID, 1, isAuctionItem])
            else:
                dropItemList.append(itemInfo)
    else:
        dropItemList = prizeItemList
    index = 0
    playerID = curPlayer.GetPlayerID()
    gameMap = GameWorld.GetMap()
    for posX, posY in ChConfig.Def_DropItemAreaMatrix:
        resultX = dropPosX + posX
        resultY = dropPosY + posY
        if not gameMap.CanMove(resultX, resultY):
            #玩家不可移动这个点
            continue
        if index > len(dropItemList) - 1:
            break
        curItem = dropItemList[index]
        index += 1
        if isinstance(curItem, list):
            itemID, itemCount, isAuctionItem = curItem
            curItem = ItemControler.GetOutPutItemObj(itemID, itemCount, isAuctionItem)
        if not curItem:
            continue
        ChItem.AddMapDropItem(resultX, resultY, curItem, ownerInfo=[ChConfig.Def_NPCHurtTypePlayer, playerID],
                              dropNPCID=npcID, isOnlySelfSee=isOnlySelfSee)
    return
def DoGiveItemByVirtualDrop(curPlayer, giveItemList, npcID, dropPosX=0, dropPosY=0, isDropDisperse=True, mailTypeKey="ItemNoPickUp"):
    ## 给物品并且做假掉落表现,直接先堆叠给物品,再拆开做虚假掉落表现
    mapID = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomSceneMapID)
    #lineID = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomSceneLineID)
    if not mapID:
        mapID = GameWorld.GetGameWorld().GetMapID()
    playerID = curPlayer.GetPlayerID()
    mailItemList = []
    virtualItemDropList = []
    itemControl = ItemControler.PlayerItemControler(curPlayer)
    for itemInfo in giveItemList:
        if isinstance(itemInfo, list):
            itemID, itemCount, isAuctionItem = itemInfo
            curItem = ItemControler.GetOutPutItemObj(itemID, itemCount, isAuctionItem, curPlayer=curPlayer)
            if not curItem:
                continue
        else:
            curItem = itemInfo
            itemID = curItem.GetItemTypeID()
            itemCount = curItem.GetCount()
            isAuctionItem = ItemControler.GetIsAuctionItem(curItem)
        jsonItem = ItemCommon.GetJsonItem(curItem)
        dropItemDataStr = ChItem.GetMapDropItemDataStr(curItem)
        equipInfo = [curItem.GetEquipPlace(), ItemCommon.GetItemClassLV(curItem), curItem.GetItemColor(),
                     curItem.GetItemQuality(), curItem.GetUserData()]
        packIndex = ChConfig.GetItemPackType(curItem.GetType())
        if not itemControl.PutInItem(packIndex, curItem, event=[ChConfig.ItemGive_Pickup, False, {"NPCID":npcID}]):
            mailItemList.append(jsonItem)
        if npcID:
            serverGroupID = PlayerControl.GetPlayerServerGroupID(curPlayer)
            SendGameServerGoodItemRecord(mapID, npcID, curPlayer.GetName(), playerID, itemID, equipInfo, serverGroupID)
        # 散开掉落
        if isDropDisperse:
            for _ in xrange(itemCount):
                virtualItemDropList.append([itemID, dropItemDataStr])
        else:
            virtualItemDropList.append([itemID, dropItemDataStr])
    if mailItemList:
        PlayerControl.SendMailByKey(mailTypeKey, [playerID], mailItemList, [mapID])
    gameMap = GameWorld.GetMap()
    index = 0
    for posX, posY in ChConfig.Def_DropItemAreaMatrix:
        if dropPosX or dropPosY:
            resultX = dropPosX + posX
            resultY = dropPosY + posY
            if not gameMap.CanMove(resultX, resultY):
                #玩家不可移动这个点
                continue
        else:
            resultX, resultY = 0, 0
        if index > len(virtualItemDropList) - 1:
            break
        itemID, dropItemDataStr = virtualItemDropList[index]
        index += 1
        SendVirtualItemDrop(curPlayer, itemID, resultX, resultY, dropItemDataStr)
    return
################################### NPC掉落 ###################################
@@ -1959,6 +2036,17 @@
    ''' 召唤私有专属木桩怪
    '''
    
    if not curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomScene):
        GameWorld.DebugLog("玩家当前不是在自定义场景中,不允许招木桩!")
        return
    mapID = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomSceneMapID)
    lineID = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomSceneLineID)
    if mapID:
        if not FBLogic.OnCanSummonPriWoodPile(curPlayer, mapID, lineID, npcID, count):
            GameWorld.ErrLog("无法召唤木桩怪!mapID=%s,lineID=%s,npcID=%s,count=%s" % (mapID, lineID, npcID, count))
            return
    maxCount = 10
    nowCount = 0
    # 只允许存在一个私有木桩
@@ -1999,6 +2087,37 @@
        summonPos = GameMap.GetEmptyPlaceInArea(curPlayer.GetPosX(), curPlayer.GetPosY(), 3)
        summonNPC.Reborn(summonPos.GetPosX(), summonPos.GetPosY())
        
        if not curPlayer.GetSight():
            summonNPCAppear = ChNetSendPack.tagPlayerSummonNPCAppear()
            summonNPCAppear.Clear()
            summonNPCAppear.PlayerID = curPlayer.GetPlayerID()
            summonNPCAppear.ObjID = summonNPC.GetID()
            summonNPCAppear.NPCID = summonNPC.GetNPCID()
            summonNPCAppear.PosX = summonNPC.GetPosX()
            summonNPCAppear.PosY = summonNPC.GetPosY()
            summonNPCAppear.HP = summonNPC.GetHP()
            summonNPCAppear.HPEx = summonNPC.GetHPEx()
            summonNPCAppear.MaxHP = summonNPC.GetMaxHP()
            summonNPCAppear.MaxHPEx = summonNPC.GetMaxHPEx()
            summonNPCAppear.Speed = summonNPC.GetSpeed()
            summonNPCAppear.LV = GetNPCLV(summonNPC)
            summonNPCAppear.OwnerName = curPlayer.GetPlayerName()
            summonNPCAppear.OwnerNameLen = len(summonNPCAppear.OwnerName)
            NetPackCommon.SendFakePack(curPlayer, summonNPCAppear)
    return
def ClearPriWoodPile(curPlayer):
    ## 清除私有木桩
    indexList = range(curPlayer.GetSummonCount())
    for index in indexList[::-1]:
        summonNPC = curPlayer.GetSummonNPCAt(index)
        if not summonNPC:
            continue
        npcType = summonNPC.GetType()
        if npcType not in [ChConfig.ntPriWoodPilePVE, ChConfig.ntPriWoodPilePVP]:
            continue
        SetDeadEx(summonNPC)
    return
## 设置npc死亡及自身处理(请不要将游戏逻辑加在此函数中)
@@ -2019,8 +2138,10 @@
    if curNPC.GetGameObjType() == IPY_GameWorld.gotNPC:
        FBLogic.DoFB_NPCDead(curNPC)
    
    ownerPlayer = None
    summonPlayerID = curNPC.GetDictByKey(ChConfig.Def_NPC_Dict_SummonMapNPCPlayerID)
    if summonPlayerID > 0:
        ownerPlayer = GameWorld.GetObj(summonPlayerID, IPY_GameWorld.gotPlayer)
        curNPC.SetDict(ChConfig.Def_NPC_Dict_SummonMapNPCPlayerID, 0)
    
    # 暗金boss
@@ -2047,6 +2168,14 @@
        lineRobotJobDict = PyGameData.g_fbRobotJobDict.get(lineID, {})
        lineRobotJobDict.pop(curNPC.GetID(), 0)
        PyGameData.g_fbRobotJobDict[lineID] = lineRobotJobDict
    if ownerPlayer and not ownerPlayer.GetSight():
        npcDie = ChNetSendPack.tagNPCDie()
        npcDie.ObjID = curNPC.GetID()
        npcDie.Reason = curNPC.GetDictByKey(ChConfig.Def_NPCDead_Reason)
        npcDie.KillerType = curNPC.GetDictByKey(ChConfig.Def_NPCDead_KillerType)
        npcDie.KillerID = curNPC.GetDictByKey(ChConfig.Def_NPCDead_KillerID)
        NetPackCommon.SendFakePack(ownerPlayer, npcDie)
        
    # C++设置npc死亡
    curNPC.SetDead(curNPC.GetDictByKey(ChConfig.Def_NPCDead_Reason),
@@ -3344,7 +3473,8 @@
        
        #得到范围内随机一个点, 普通小怪走法
        PosMap = curNPC.GetRefreshPosAt(curNPC.GetCurRefreshPointIndex())
        if not PosMap:
            return
        moveArea = min(curNPC.GetMoveArea(), 2)
        posX = curNPC.GetPosX()
@@ -4152,6 +4282,9 @@
    #  @return 返回值无意义
    def __NPCDropItem(self, dropPlayer, hurtType, hurtID, ownerPlayerList=[]):
        if not dropPlayer:
            return
        if dropPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomScene):
            GameWorld.DebugLog("前端自定义场景中,不掉落物品!")
            return
        curNPC = self.__Instance
        npcID = curNPC.GetNPCID()
@@ -5729,6 +5862,15 @@
    if not curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomScene):
        GameWorld.DebugLog("非自定义场景中,无法获取定义采集奖励!")
        return
    mapID = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomSceneMapID)
    lineID = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomSceneLineID)
    GameWorld.DebugLog("前端场景采集: mapID=%s,lineID=%s,npcID=%s" % (mapID, lineID, npcID))
    if mapID:
        #if FBCommon.GetCustomSceneState(curPlayer, mapID, lineID) != ChConfig.CustomSceneState_Fight:
        #    return
        FBLogic.OnCustomSceneCollectOK(curPlayer, mapID, lineID, npcID)
    collectNPCIpyData = IpyGameDataPY.GetIpyGameData("CollectNPC", npcID)
    if collectNPCIpyData:
        DoGiveCollectNPCAward(curPlayer, npcID, collectNPCIpyData)
@@ -5764,11 +5906,20 @@
    collectAwardCfg = collectNPCIpyData.GetCollectAward()
    collectAppointAwardCfg = collectNPCIpyData.GetCollectAppointAward()
    if collectAppointAwardCfg:
        collTotalTime = min(curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CollNpcIDCollTimeTotal % npcID) + 1, ChConfig.Def_UpperLimit_DWord)
        if collTotalTime in collectAppointAwardCfg:
            awardItemList.append(collectAppointAwardCfg[collTotalTime])
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_CollNpcIDCollTimeTotal % npcID, collTotalTime)
        GameWorld.DebugLog("    采集次数定制奖励: collTotalTime=%s,awardItemList=%s" % (collTotalTime, awardItemList))
        #缥缈草园的采集定制由缥缈寻访次数决定
        if collectNPCIpyData.GetCollectResetType() in [12, 14]:
            fairyDomainVisitCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_FairyDomainVisitCnt)
            grasslandCollectAppointCfg = collectAppointAwardCfg.get(fairyDomainVisitCnt, {})
            curCollTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CollNpcIDCollTime % npcID)
            if curCollTime in grasslandCollectAppointCfg:
                awardItemList.append(grasslandCollectAppointCfg[curCollTime])
            GameWorld.DebugLog("    草园采集定制奖励: fairyDomainVisitCnt=%s,curCollTime=%s,awardItemList=%s" % (fairyDomainVisitCnt, curCollTime, awardItemList))
        else:
            collTotalTime = min(curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_CollNpcIDCollTimeTotal % npcID) + 1, ChConfig.Def_UpperLimit_DWord)
            if collTotalTime in collectAppointAwardCfg:
                awardItemList.append(collectAppointAwardCfg[collTotalTime])
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_CollNpcIDCollTimeTotal % npcID, collTotalTime)
            GameWorld.DebugLog("    采集次数定制奖励: collTotalTime=%s,awardItemList=%s" % (collTotalTime, awardItemList))
        
    if not awardItemList:
        alchemyDiffLV = collectNPCIpyData.GetAlchemyDiffLV()
@@ -5806,6 +5957,7 @@
                awardPack.AwardItemList.append(awardItem)
            awardPack.Count = len(awardPack.AwardItemList)
            NetPackCommon.SendFakePack(curPlayer, awardPack)
        GameLogic_CrossGrassland.RecordGrasslandAward(curPlayer, awardItemList)
    else:
        GameWorld.ErrLog("采集物品没有奖励!npcID=%s" % (npcID))
        
@@ -5813,6 +5965,7 @@
    PlayerSuccess.DoAddSuccessProgress(curPlayer, ShareDefine.SuccType_Collect, collectCnt, [npcID])
    #SyncCollectionItemInfo(curPlayer, addExp, addMoney, addZhenQi, giveItemInfoList, npcID)
    
    GameLogic_CrossGrassland.DecCustomSceneNPCCount(curPlayer, npcID)
    if isMaxTime:
        GameLogic_CrossGrassland.DoCheckUpdateGrasslandEnd(curPlayer)
        
@@ -6218,4 +6371,74 @@
    return
def OnNPCAttacked(atkObj, curNPC, skill, tick):
    ## NPC被攻击
    __OnAttackedDropItem(atkObj, curNPC)
    return
## 每次被攻击掉落物品
#  @param atkObj 攻击发起者
#  @param curNPC 被攻击NPC
#  @return None
def __OnAttackedDropItem(atkObj, curNPC):
    attackPlayer, npcObjType = AttackCommon.GetAttackPlayer(atkObj)
    if npcObjType:
        return
    if not attackPlayer:
        return
    npcID = curNPC.GetNPCID()
    ipyData = IpyGameDataPY.GetIpyGameDataNotLog("TreasureNPC", npcID)
    if not ipyData:
        return
    attackCountDropWeightInfo = ipyData.GetAttackCountDropWeightInfo()
    attackDropWeightList = ipyData.GetAttackDropWeightList()
    attackDropWeightListEx = ipyData.GetAttackDropWeightListEx()
    dropCountEx = ipyData.GetDropCountEx()
    alchemyDiffLV = ipyData.GetAlchemyDiffLV()
    mainItemWeightList = []
    if attackCountDropWeightInfo:
        maxCount = max(attackCountDropWeightInfo)
        attackCount = attackPlayer.NomalDictGetProperty(ChConfig.Def_PDict_NPCAttackCount % npcID) + 1
        if attackCount <= maxCount:
            if attackCount in attackCountDropWeightInfo:
                mainItemWeightList = attackCountDropWeightInfo[attackCount]
            UpdateNPCAttackCount(attackPlayer, npcID, attackCount, maxCount)
    if mainItemWeightList:
        mainItemWeightList = ItemCommon.GetWeightItemListByAlchemyDiffLV(attackPlayer, mainItemWeightList, alchemyDiffLV)
    elif attackDropWeightList:
        mainItemWeightList = ItemCommon.GetWeightItemListByAlchemyDiffLV(attackPlayer, attackDropWeightList, alchemyDiffLV)
    mainItemInfo = GameWorld.GetResultByWeightList(mainItemWeightList)
    if not mainItemInfo:
        notDropNotify = ipyData.GetNotDropNotify()
        if notDropNotify:
            PlayerControl.NotifyCode(attackPlayer, notDropNotify)
        return
    dropItemList = []
    if mainItemInfo:
        dropItemList.append(mainItemInfo)
    if attackDropWeightListEx and dropCountEx:
        weightListEx = ItemCommon.GetWeightItemListByAlchemyDiffLV(attackPlayer, attackDropWeightListEx, alchemyDiffLV)
        for _ in xrange(dropCountEx):
            itemInfo = GameWorld.GetResultByWeightList(weightListEx)
            if itemInfo:
                dropItemList.append(itemInfo)
    if not dropItemList:
        return
    mapID = attackPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomSceneMapID)
    if mapID:
        DoGiveItemByVirtualDrop(attackPlayer, dropItemList, npcID)
        GameLogic_CrossGrassland.RecordGrasslandAward(attackPlayer, dropItemList)
    else:
        dropPosX, dropPosY = curNPC.GetPosX(), curNPC.GetPosY()
        ChItem.DoMapDropItem(attackPlayer, dropItemList, npcID, dropPosX, dropPosY, isOnlySelfSee=False)
    return
                
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
@@ -439,7 +439,6 @@
        # 离线过久恢复为非跨服状态
        if PlayerControl.GetCrossMapID(curPlayer):
            PlayerControl.SetCrossMapID(curPlayer, 0)
        PyGameData.g_customFBPrizeInfo.pop(curPlayer.GetPlayerID(), None)
        
    SyncGuideState(curPlayer)
    
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerFB.py
@@ -38,9 +38,9 @@
import ShareDefine
import GameFuncComm
import FBHelpBattle
import ItemControler
import SkillShell
import PyGameData
import NPCCommon
import time
import math
@@ -525,73 +525,16 @@
    curPet = curPlayer.GetPetMgr().GetFightPet()
    if curPet:
        curPet.SetVisible(True)
    mapID = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomSceneMapID)
    lineID = curPlayer.GetDictByKey(ChConfig.Def_PlayerKey_ClientCustomSceneLineID)
    curPlayer.SetDict(ChConfig.Def_PlayerKey_ClientCustomScene, 0)
    curPlayer.SetDict(ChConfig.Def_PlayerKey_ClientCustomSceneMapID, 0)
    curPlayer.SetDict(ChConfig.Def_PlayerKey_ClientCustomSceneLineID, 0)
    if mapID and curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_CustomSceneStartTime % (mapID, lineID)) == ChConfig.CustomSceneState_Over:
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_Player_Dict_CustomSceneStartTime % (mapID, lineID), ChConfig.CustomSceneState_None)
    NPCCommon.ClearPriWoodPile(curPlayer)
    GameWorld.Log("玩家退出自定义场景!", curPlayer.GetPlayerID())
    return
#// B1 08 刷新自定义副本奖励 #tagCMRefreshCustomFBPrize
#
#struct    tagCMRefreshCustomFBPrize
#{
#    tagHead         Head;
#    DWORD        MapID;
#    WORD        FuncLineID;
#};
def OnRefreshCustomFBPrize(playerIndex, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(playerIndex)
    playerID = curPlayer.GetPlayerID()
    mapID = clientData.MapID
    funcLineID = clientData.FuncLineID
    prizeItemList = FBLogic.OnRefreshCustomFBPrize(curPlayer, mapID, funcLineID)
    PyGameData.g_customFBPrizeInfo[playerID] = prizeItemList
    prizePack = ChPyNetSendPack.tagMCCuntomFBPrizeInfo()
    prizePack.MapID = mapID
    prizePack.FuncLineID = funcLineID
    prizePack.PrizeItemIDList = [prizeItemInfo[0] for prizeItemInfo in prizeItemList]
    prizePack.PrizeItemCount = len(prizePack.PrizeItemIDList)
    NetPackCommon.SendFakePack(curPlayer, prizePack)
    return
#// B1 09 结算自定义副本奖励 #tagCMGiveCustomFBPrize
#
#struct    tagCMGiveCustomFBPrize
#{
#    tagHead         Head;
#    DWORD        MapID;
#    WORD        FuncLineID;
#};
def OnGiveCustomFBPrize(playerIndex, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(playerIndex)
    playerID = curPlayer.GetPlayerID()
    mapID = clientData.MapID
    lineID = clientData.FuncLineID
    prizeItemList = PyGameData.g_customFBPrizeInfo.pop(playerID, [])
    mailItemList = []
    jsonItemList = []
    playerItemControl = ItemControler.PlayerItemControler(curPlayer)
    for itemID, itemCount, isAuctionItem in prizeItemList:
        curItem = ItemControler.GetOutPutItemObj(itemID, itemCount, isAuctionItem, curPlayer=curPlayer)
        if not curItem:
            continue
        jsonItem = ItemCommon.GetJsonItem(curItem)
        jsonItemList.append(jsonItem)
        #放入玩家背包
        if not playerItemControl.PutInItem(IPY_GameWorld.rptItem, curItem):
            mailItemList.append(jsonItem)
    if mailItemList:
        PlayerControl.SendMailByKey("ItemNoPickUp", [playerID], mailItemList, [mapID])
    overDict = FBLogic.OnGiveCustomFBPrizeOK(curPlayer, mapID, lineID)
    isPass = 1
    overDict.update({FBCommon.Over_itemInfo:jsonItemList})
    FBCommon.NotifyFBOver(curPlayer, mapID, lineID, isPass, overDict)
    return
#// B1 0A 副本购买buff #tagCMFBBuyBuff
#struct    tagCMFBBuyBuff
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerFairyDomain.py
@@ -59,6 +59,12 @@
AdventuresType4,
) = range(1, 5)
#事件副本类型
(
FDEventFBType_Client, #前端本0
FDEventFBType_Server, #本服本1
FDEventFBType_CrossServer, #跨服本2
) = range(3)
def OnLogin(curPlayer):
    NotifyVisitFairyDomainInfo(curPlayer)
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py
@@ -101,8 +101,6 @@
g_allfamilyBossDict = {} # 多仙盟boss信息 {familyID:[familyName, 伤害, [playerID], ...}
g_horsePetBossPlayerHurtDict = {} #骑宠boss信息 {lineID:{playerID:[playerName,hurt]}}
g_customFBPrizeInfo = {} #自定义副本奖励 {playerID:[mapID, funcLineID, [奖励物品列表], ...}
g_crossFuncLineDataCache = {} # 动态分配的跨服虚拟分线数据缓存 {(mapID, copyMapID):funcLineDataCache, ...}
g_crossPlayerServerGroupIDInfo = {} #跨服玩家服务器组ID缓存,副本线路关闭时才释放,所以支持离线跨服玩家 {copyMapID:{playerID:serverGroupID, ...}, ...}
g_fbBuyBuffTimeDict = {} # 副本购买buff时间缓存{playerID:{moneyCnt:time}}