xdh
2018-12-19 57a7f963e83329c191e135c8102b0614dea6d5b4
5368 【后端】【1.4】聚魂功能开发
16个文件已修改
2个文件已添加
1415 ■■■■■ 已修改文件
PySysDB/PySysDBPY.h 32 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini 20 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py 34 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventShell.py 6 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/MakeItemCount.py 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/PrintFightPower.py 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/FBCommon.py 3 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_GatherSoul.py 597 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py 84 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py 12 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/UseItem/ItemCommon.py 7 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py 28 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py 5 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py 3 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerGatherSoul.py 533 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py 2 ●●●●● 补丁 | 查看 | 原始文档 | blame | 历史
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py 22 ●●●● 补丁 | 查看 | 原始文档 | blame | 历史
PySysDB/PySysDBPY.h
@@ -1430,3 +1430,35 @@
    DWORD        FightPower;    //增加战力
    dict        Attr;    //属性加成
};
//聚魂表
struct tagGatherSoul
{
    DWORD        _ItemID;    //物品ID
    list        AttrType;    //属性类型
    BYTE        SoulGrade;    //魂阶段
};
//聚魂合成表
struct tagGatherSoulCompound
{
    DWORD        _TagItemID;    //合成的物品ID
    WORD        NeedLV;    //需要的玩家等级
    list        NeedItem; //需要的物品ID
    WORD        NeedSoulSplinters;    //需要的聚魂碎片
    WORD        NeedSoulCore;    //需要的核心环
};
//聚魂属性表
struct tagGatherSoulAttr
{
    WORD        _AttrType;    //属性类型
    char        AttrInfo1;    //基础属性-参数聚魂等级level
    dict        AttrInfo2;    //品质系数(品质_系数|…)
    dict        AttrInfo3;    //多属性系数
    dict        AttrInfo4;    //初始属性(品质_属性值|…)
    dict        AttrInfo5;    //阶段系数
};
ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py
@@ -312,7 +312,8 @@
    Def_mitRecycleAttrFruit,  # 回收魂石
    Def_mitDogzEquipPlus,     # 神兽装备强化
    Def_mitRuneCompound,      # 符印合成
) = range(1, 23)
    Def_mitGatherSoulCompound,# 聚魂合成
) = range(1, 24)
#---写死的技能ID---
Def_SkillID_AutoTruck = 62220   # 自动运镖buff
@@ -786,7 +787,10 @@
CDBPlayerRefresh_GodWeaponLV_2,         # 神兵等级 - 类型2 193
CDBPlayerRefresh_GodWeaponLV_3,         # 神兵等级 - 类型3 194
CDBPlayerRefresh_GodWeaponLV_4,         # 神兵等级 - 类型4 195
) = range(146, 196)
CDBPlayerRefresh_SoulDust,              # 魂尘 196
CDBPlayerRefresh_SoulSplinters,         # 聚魂碎片 197
CDBPlayerRefresh_SoulCore,              # 核心环 198
) = range(146, 199)
TYPE_Price_Gold_Paper_Money = 5    # 金钱类型,(先用礼券,再用金子)
TYPE_Price_Family_Contribution = 6 # 战盟贡献度(活跃度转换得来)
@@ -801,6 +805,9 @@
TYPE_Price_TreasureScore = 25    # 寻宝积分
TYPE_Price_BourseMoney = 26    # 交易所可购买额度
TYPE_Price_Danjing = 27    # 丹精(丹药回收)
TYPE_Price_SoulDust = 28    # 魂尘
TYPE_Price_SoulSplinters = 29    # 聚魂碎片
TYPE_Price_SoulCore = 30    # 核心环
#以下是旧的金钱类型
@@ -828,6 +835,9 @@
                           TYPE_Price_FamilyActivity:CDBPlayerRefresh_FamilyActivity,
                           TYPE_Price_XianyuanCoin:CDBPlayerRefresh_Xianyuancoin,
                           TYPE_Price_Danjing:CDBPlayerRefresh_Danjing,
                           TYPE_Price_SoulDust:CDBPlayerRefresh_SoulDust,
                           TYPE_Price_SoulSplinters:CDBPlayerRefresh_SoulSplinters,
                           TYPE_Price_SoulCore:CDBPlayerRefresh_SoulCore,
                           }
# 高效战斗状态
@@ -925,8 +935,9 @@
#虚拟背包类型, 从255递减
Def_VPack_TypeList = (
rptGatherSoul,      # 聚魂背包 254
rptRune,            # 符印背包 255
) = range(256 - 1, 256)
) = range(256 - 2, 256)
#武器的手持形式
@@ -1266,7 +1277,7 @@
Def_IudetRuneSource = 40  # 符印来源 老号0,默认1,合成2(主要用来区分是否合成获得)
Def_IudetWingProgressValue = 42 #羽翼精炼值
Def_IudetCreateTime = 44 # 时效物品的创建时间
Def_IudetGatherSoulLV = 46  # 聚魂等级
# 200~300 宠物数据用
Def_IudetPet_NPCID = 200  # npcID
Def_IudetPet_ClassLV = 202  # 阶级
@@ -1330,7 +1341,7 @@
)=range(5)
# 战斗力模块类型
Def_MFPType_Max = 25
Def_MFPType_Max = 26
ModuleFightPowerTypeList = (
Def_MFPType_Role, # 角色 0
Def_MFPType_Equip, # 装备(基本装备位) 1
@@ -1354,6 +1365,7 @@
Def_MFPType_HorseSoul, # 坐骑魂石 19
Def_MFPType_MagicWeaponSoul, # 法宝之魂 20
Def_MFPType_Dogz, # 神兽 21
Def_MFPType_GatherSoul, # 聚魂 22
Def_MFPType_Other, # 其他
#以下暂时没用到,改时再处理
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/PyNetPack.ini
@@ -1387,3 +1387,23 @@
PacketCMD_2=0xAA
PacketSubCMD_2=0x06
PacketCallFunc_2=OnActWishingDrag
;聚魂
[PlayerGatherSoul]
ScriptName = Player\PlayerGatherSoul.py
Writer = xdh
Releaser = xdh
RegType = 0
RegisterPackCount = 3
PacketCMD_1=0xA5
PacketSubCMD_1=0x18
PacketCallFunc_1=OnGatherSoulUp
PacketCMD_2=0xA5
PacketSubCMD_2=0x19
PacketCallFunc_2=OnGatherSoulDecompose
PacketCMD_3=0xA5
PacketSubCMD_3=0x1C
PacketCallFunc_3=OnGatherSoulCompound
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py
@@ -313,6 +313,9 @@
Def_ItemType_FamilyBossFood = 50       #仙盟兽粮
Def_ItemType_SuccessItem = 53     # 用于完成成就的物品,不存在背包
Def_ItemType_ResetAttrPoint = 59       #洗点卷轴 使用后将某个属性一定值变为未分配属性
Def_ItemType_GatherSoulExp = 61 #聚魂精华材料
Def_ItemType_GatherSoul = 62 #普通聚魂
Def_ItemType_GatherSoulCore = 63 #聚魂核心
Def_ItemType_DogzEquipExp = 70  # 神兽装备经验
@@ -354,6 +357,7 @@
#虚拟背包最大格子数 功能配置表对应的key
Def_VPackCnt_Dict = {
                     ShareDefine.rptRune:'RunePackageNum',
                     ShareDefine.rptGatherSoul:'GatherSoulPackCount',
                     }
#虚拟背包可以放入的物品字典
@@ -361,6 +365,7 @@
ShareDefine.rptRune:[Def_ItemType_Rune, Def_ItemType_RuneExp],
ShareDefine.rptDogzItem:[Def_ItemType_DogzEquipExp, Def_ItemType_DogzEquipHorn, Def_ItemType_DogzEquipEye, 
                         Def_ItemType_DogzEquipTooth, Def_ItemType_DogzEquipClaw, Def_ItemType_DogzEquipScute],
ShareDefine.rptGatherSoul:[Def_ItemType_GatherSoulExp, Def_ItemType_GatherSoul, Def_ItemType_GatherSoulCore],
                      }
def GetItemPackType(itemType, defaultPack=IPY_GameWorld.rptItem):
@@ -1774,6 +1779,8 @@
Def_FBMapID_XMZZ = 31010
#神兽副本
Def_FBMapID_Dogz = 21110
#聚魂副本
Def_FBMapID_GatherSoul = 31340
#副本关闭时未拾取的物品邮件发放给玩家
#这里只有需要的副本才配置,不做默认逻辑,防止某些副本实际不能给导致刷物品,如麒麟之府
Def_SendUnPickItemMailMapIDList = [Def_FBMapID_IceLode, Def_FBMapID_PersonalBoss, Def_FBMapID_MunekadoTrial, 
@@ -1799,13 +1806,13 @@
#                            + Def_FBMapID_ClearDevil
# 刷新标识点在无玩家的情况下也需要刷新的地图
Def_NoPlayerNeedProcessRefreshPointMap = [Def_FBMapID_SealDemon, Def_FBMapID_GodArea, Def_FBMapID_BossHome]
Def_NoPlayerNeedProcessRefreshPointMap = [Def_FBMapID_SealDemon, Def_FBMapID_GodArea, Def_FBMapID_BossHome, Def_FBMapID_GatherSoul]
# 可重复进的副本
Def_NoLimitEnterCntMap = [Def_FBMapID_FamilyParty, Def_FBMapID_FamilyWar, Def_FBMapID_FamilyInvade, Def_FBMapID_ElderBattlefield]
# 无玩家时不自动关闭的自伸缩副本
Def_NoPlayerNotCloseAutoSizeMap = [Def_FBMapID_FamilyInvade, Def_FBMapID_FamilyBossMap]
Def_NoPlayerNotCloseAutoSizeMap = [Def_FBMapID_FamilyInvade, Def_FBMapID_FamilyBossMap, Def_FBMapID_GatherSoul]
# 不可切换PK模式的地图
Def_CanNotChangeAtkModelMap = []
@@ -1861,6 +1868,7 @@
                'SealDemon':[Def_FBMapID_SealDemon, Def_FBMapID_SealDemonEx], #封魔坛
                'XMZZ':[Def_FBMapID_XMZZ], #仙魔之争
                'Dogz':[Def_FBMapID_Dogz], #神兽副本
                'GatherSoul':[Def_FBMapID_GatherSoul],#聚魂副本
                }
#特殊副本ID, 由系统分配, 进入时候不验证IsMapCopyFull
@@ -3718,6 +3726,9 @@
Def_PDict_Rune_HoleOpenState = "Rune_HoleOpenState"  # 符印解锁状态
Def_PDict_Rune_Data = "Rune_Data_%s"  # 符印镶嵌数据, 参数(第几孔)
# 聚魂
Def_PDict_GatherSoulHoleData = "GatherSoulHoleData_%s"  # 聚魂镶嵌数据, 参数(第几孔)
# 副本 Def_PDictType_FB
Def_PDict_FamilyBossFBAwardState = "FamilyBossFBAwardState_%s"  # 家族boss副本领奖状态%s副本id
Def_PDict_LastEnterFBPropertyID = "LastEnterFBPropertyID_%s"  # 上次进入副本的propertyID%s副本id
@@ -4301,7 +4312,8 @@
Def_CalcAttrFunc_DogzBattleSkill, # 助战神兽技能36
Def_CalcAttrFunc_DogzEquip, # 神兽装备37
Def_CalcAttrFunc_DogzEquipPlus, # 神兽装备强化38
) = range(39)
Def_CalcAttrFunc_GatherSoul, # 聚魂39
) = range(40)
# 在此列表中的功能属性,不享受百分比加成,--属性参与战力计算
@@ -4340,6 +4352,7 @@
                            ShareDefine.Def_MFPType_MagicWeapon3:[Def_CalcAttrFunc_MagicWeapon3, Def_CalcAttrFunc_Stove, Def_CalcAttrFunc_VIP],
                            ShareDefine.Def_MFPType_StoveYao:[Def_CalcAttrFunc_StoveYao],
                            ShareDefine.Def_MFPType_MagicWeaponSoul:[Def_CalcAttrFunc_MagicWeaponSoul],
                            ShareDefine.Def_MFPType_GatherSoul:[Def_CalcAttrFunc_GatherSoul],
                            # 神兽战力同装备模块战力一致,受评分影响,装备评分相关的战力另外算
                            ShareDefine.Def_MFPType_Dogz:[Def_CalcAttrFunc_Dogz, Def_CalcAttrFunc_DogzEquipPlus],
                            ShareDefine.Def_MFPType_Other:[Def_CalcAttrFunc_Success, Def_CalcAttrFunc_FamilyTech, Def_CalcAttrFunc_EquipDecompose],
@@ -4566,6 +4579,7 @@
Def_Cost_WishingWell, # 许愿池刷新
Def_Cost_GodWeapon, # 神兵
Def_Cost_FBHelpBattle, # 副本助战
Def_Cost_FBGatherSoulBoss, # 聚魂副本BOSS召唤 40
#-----------以下为暂时没用的,先不删除,如有新增消费点则放在这些之前------------
Def_Cost_RefreshArrestTask, # 刷新悬赏任务
Def_Cost_OffLineExp, # 兑换离线经验
@@ -4586,7 +4600,7 @@
Def_Cost_Trade, # 交易
Def_Cost_Rename, # 改名
Def_Cost_SkillLvUp, # 技能升级
) = range(2000, 2000 + 59)
) = range(2000, 2000 + 60)
Def_Cost_Reason_SonKey = "reason_name_son" # 消费点原因子类说明key
@@ -4673,6 +4687,7 @@
Def_Cost_WishingWell:"WishingWell",
Def_Cost_GodWeapon:"GodWeapon",
Def_Cost_FBHelpBattle:"FBHelpBattle",
Def_Cost_FBGatherSoulBoss:"FBGatherSoulBoss",
}
## -----------------------------------------------------
@@ -4704,7 +4719,8 @@
Def_GiveMoney_Truck, # 运镖
Def_GiveMoney_FreeGoods, # 极品白拿 25
Def_GiveMoney_BindJadeWheel, # 绑玉转盘
) = range(1000, 1000 + 26)
Def_GiveMoney_GatherSoulDecompose, #聚魂分解
) = range(1000, 1000 + 27)
Def_Give_Reason_SonKey = "reason_name_son" # 原因子类说明key
@@ -4736,6 +4752,7 @@
Def_GiveMoney_Truck:"Truck",
Def_GiveMoney_FreeGoods:"FreeGoods",
Def_GiveMoney_BindJadeWheel:"BindJadeWheel",
Def_GiveMoney_GatherSoulDecompose:"GatherSoulDecompose",
}
##==================================================================================================
@@ -4825,7 +4842,8 @@
ItemDel_AddKillBossCnt, # 增加BOSS可击杀次数 32
ItemDel_DogzEquipPlus, # 神兽装备强化
ItemDel_ChatBubbleBox, # 激活聊天气泡框
) = range(2000, 2000 + 35)
ItemDel_GatherSoul, # 聚魂分解
) = range(2000, 2000 + 36)
# 物品扣除类型对应信息 {类型:eventName, ...}
ItemDelTypeDict = {
@@ -5189,7 +5207,8 @@
PowerDownType_Dogz, #神兽召回
PowerDownType_ResetPoint, #洗点
PowerDownType_ResetTalent, #大师天赋重置
) = range(10)
PowerDownType_GatherSoul, #聚魂替换
) = range(11)
FightPowerDownRecordDict = {
    PowerDownType_Rune:'Rune',
    PowerDownType_LVUP:'LVUP',
@@ -5201,4 +5220,5 @@
    PowerDownType_Dogz:'DogzState',
    PowerDownType_ResetPoint:'ResetPoint',
    PowerDownType_ResetTalent:'ResetTalent',
    PowerDownType_GatherSoul:'GatherSoul',
    } 
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Event/EventShell.py
@@ -100,7 +100,7 @@
import PlayerExpandPackCfgMgr
import EventReport
import PlayerCoat
import PlayerSuccess
import PlayerGatherSoul
import PlayerArrestTask
import PlayerRune
import IpyGameDataPY
@@ -4378,7 +4378,9 @@
    # 符印交换
    if PlayerRune.SwitchRune(curPlayer, pack_SrcBackpack, pack_DesBackPack, pack_SrcIndex, pack_DestIndex):
        return
    # 聚魂交换
    if PlayerGatherSoul.SwitchGatherSoul(curPlayer, pack_SrcBackpack, pack_DesBackPack, pack_SrcIndex, pack_DestIndex):
        return
    
    #ʱװ
    if PlayerCoat.SwitchCoat(curPlayer, pack_SrcBackpack, pack_DesBackPack, pack_SrcIndex, pack_DestIndex):
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/MakeItemCount.py
@@ -66,7 +66,8 @@
    if curItem.GetType() == ChConfig.Def_ItemType_Rune and runeLV:
        curItem.SetUserAttr(ShareDefine.Def_IudetRuneLV, runeLV)
    if curItem.GetType() in [ChConfig.Def_ItemType_GatherSoul,ChConfig.Def_ItemType_GatherSoulCore] and runeLV:
        curItem.SetUserAttr(ShareDefine.Def_IudetGatherSoulLV, runeLV)
    #将物品放置玩家背包
    PlayerItemControler = ItemControler.PlayerItemControler(curPlayer)
    if not PlayerItemControler.PutInItem(IPY_GameWorld.rptItem, curItem, event=[ChConfig.ItemGive_GMMake, False, {"CMD":"MakeItemCount"}]):
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/PrintFightPower.py
@@ -42,6 +42,7 @@
                   ShareDefine.Def_MFPType_GodWeapon:"神兵",
                   ShareDefine.Def_MFPType_Dienstgrad:"称号",
                   ShareDefine.Def_MFPType_Rune:"符印",
                   ShareDefine.Def_MFPType_GatherSoul:"聚魂",
                   ShareDefine.Def_MFPType_Horcrux:"魂器",
                   ShareDefine.Def_MFPType_MagicWeapon1:"人族",
                   ShareDefine.Def_MFPType_StoveYao:"丹药",
@@ -72,6 +73,7 @@
                     ChConfig.Def_CalcAttrFunc_GodWeapon:"神兵",
                     ChConfig.Def_CalcAttrFunc_Dienstgrad:"称号",
                     ChConfig.Def_CalcAttrFunc_Rune:"符印",
                     ChConfig.Def_CalcAttrFunc_GatherSoul:"聚魂",
                     ChConfig.Def_CalcAttrFunc_Horcrux:"魂器",
                     ChConfig.Def_CalcAttrFunc_MagicWeapon1:"人族法宝属性",
                     ChConfig.Def_CalcAttrFunc_MagicWeapon2:"魔族法宝属性", 
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/FBCommon.py
@@ -67,6 +67,9 @@
Help_helpCount = 'helpCount' #该副本今日已助战次数
Help_relation = 'relation' #该副本关系加成信息 [优先关系, 总加成]
Help_robotJob = 'robotJob' #机器人职业 {"ObjID":job, ...}
Help_isAuto = 'isAuto' #是否自动召唤
Help_hasRefreshBoss = 'hasRefreshBoss' #是否已刷新boss
Help_gsItemInfo = 'gsItemInfo' #聚魂副本物品信息 {"波数":[[{"ItemID":101, "ItemCount":10}]]}
#副本结算信息通用key
Over_dataMapID = 'dataMapID' #数据地图ID
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorldLogic/FBProcess/GameLogic_GatherSoul.py
New file
@@ -0,0 +1,597 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
##@package GameWorldLogic.FBProcess.GameLogic_GatherSoul
#
# @todo:聚魂副本
# @author xdh
# @date 2018-12-12
# @version 1.0
#
# 详细描述: 聚魂副本
#
#-------------------------------------------------------------------------------
#"""Version = 2018-12-12 21:00"""
#-------------------------------------------------------------------------------
import FBCommon
import GameWorld
import ItemCommon
import IPY_GameWorld
import GameWorldProcess
import PyGameData
import NPCCustomRefresh
import ChConfig
import ShareDefine
import EventReport
import PlayerControl
import ItemControler
import ChNPC
#---副本配置对应key值---
(
Def_FightTime,  # 进行时间(秒)
Def_LeaveTime,  # 退出时间(秒)
Def_BuildNPCID,  # 建造点NPCID
Def_BuildCnt,  # 建造点数量
Def_BuildMark,  # 建造点标识点
Def_BuildTime,  # 建造时间毫秒
Def_GuardInfo,  #{守卫npcid:最大数量}
Def_BossID,  # 黄金BOSSID
Def_BossCostMoney,  # 召唤黄金BOSS需要金钱
Def_NPCRefreshMark,  # 怪物刷新标识点
Def_NPCRefreshCD,  # 小怪间隔时间毫秒
Def_WheelRefreshCD,  # 每波间隔时间毫秒
) = range(12)
#当前副本地图的状态
(
FB_Step_Open,  # 副本开启
FB_Step_Prepare,  # 建造守卫
FB_Step_Fighting,  # 刷怪中
FB_Step_Over,  # 副本结束
FB_Step_Close,  # 副本关闭
) = range(5)
FBPlayerDict_GuardNPCID = 'FBPlayerDict_GuardNPCID'  # 需刷新的守卫ID
FBPlayerDict_GuardNPCCnt = 'FBPlayerDict_GuardNPCCnt%s'  # 守卫已刷新数量
FBPlayerDict_CurWheel = 'FBPlayerDict_CurWheel'  # 当前第几波怪
FBPlayerDict_NPCIndex = 'FBPlayerDict_NPCIndex'  # 本波怪第几只
FBPlayerDict_LastWheelEndTime = 'FBPlayerDict_LastWheelEndTime'  # 上一波结束时间
FBPlayerDict_LastNPCRTime = 'FBPlayerDict_LastNPCRTime'  # 上一只怪物刷新时间
FBPlayerDict_HasRefreshBoss = 'FBPlayerDict_HasRefreshBoss'  # 本波是否已刷黄金BOSS
FBPlayerDict_AutoBoss = 'FBPlayerDict_AutoBoss'  # 是否自动刷黄金boss
FBPlayerDict_NPCRemainCnt = 'FBPlayerDict_NPCRemainCnt'  # NPC剩余数量
##---获得副本配置---
#  @param None
#  @return 配置信息
def GetGatherSoulFBCfg():
    return FBCommon.GetFBLineStepTime(ChConfig.Def_FBMapID_GatherSoul, 0)
def GetGatherSoulNPCCfg():
    return FBCommon.GetFBLineRefreshNPC(ChConfig.Def_FBMapID_GatherSoul)
## 是否能够通过活动查询进入
#  @param curPlayer 玩家实例
#  @param mapID 地图ID
#  @param lineID 线路id
#  @param tick 时间戳
#  @return 布尔值
def OnEnterFBEvent(curPlayer, mapID, lineID, tick):
    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:请求结构体(IPY_BMChangeMapAsk)
# @param tick:时间戳
# @return IPY_GameWorld.cme 枚举
def OnChangeMapAsk(ask, tick):
    return IPY_GameWorld.cmeAccept
##开启副本
# @param tick 时间戳
# @return 返回值无意义
# @remarks 开启副本
def OnOpenFB(tick):
    #刷建造点
    gatherSoulFBCfg = GetGatherSoulFBCfg()
    NPCCustomRefresh.SetNPCRefresh(gatherSoulFBCfg[Def_BuildMark], [(gatherSoulFBCfg[Def_BuildNPCID], 1)], 1, gatherSoulFBCfg[Def_BuildCnt])
    return
##关闭副本
# @param tick 时间戳
# @return 无意义
# @remarks
def OnCloseFB(tick):
    __DoGatherSoulOver()
    return
## 进副本
#  @param curPlayer
#  @param tick
#  @return None
def DoEnterFB(curPlayer, tick):
    PlayerControl.SetSight(curPlayer, ChConfig.Def_PlayerSight_Default * 3)
    playerID = curPlayer.GetPlayerID()
    playerLV = curPlayer.GetLV()
    mapID = GameWorld.GetMap().GetMapID()
    mapID = FBCommon.GetRecordMapID(mapID)
    gameFB = GameWorld.GetGameFB()
    lineID = curPlayer.NomalDictGetProperty(ChConfig.Def_Player_Dict_ReqFBFuncLine)
    GameWorld.DebugLog("DoEnterFB...lineID=%s,playerLV=%s" % (lineID, playerLV), playerID)
    hadDelTicket = FBCommon.GetHadDelTicket(curPlayer)
    if not hadDelTicket:
        FBCommon.SetHadDelTicket(curPlayer)
        FBCommon.SetFBPropertyMark(lineID)
        EventReport.WriteEvent_FB(curPlayer, ChConfig.Def_FBMapID_GatherSoul, 0, ChConfig.CME_Log_Start)
    fbStep = gameFB.GetFBStep()
    if fbStep < FB_Step_Prepare:
        FBCommon.SetFBStep(FB_Step_Prepare, tick)
    if fbStep < FB_Step_Over:
        notify_tick = GetGatherSoulFBCfg()[Def_FightTime] * 1000 - (tick - GameWorld.GetGameWorld().GetOpenFBTick())
        curPlayer.Sync_TimeTick(IPY_GameWorld.tttTowerTake, 0, max(notify_tick, 0), True)
    else:
        return
    DoFBHelp(curPlayer, tick)
    return
##玩家退出副本
# @param curPlayer 玩家实例
# @param tick 时间戳
# @return 无意义
def DoExitFB(curPlayer, tick):
    PlayerControl.SetSight(curPlayer, ChConfig.Def_PlayerSight_Default)
    fbStep = GameWorld.GetGameFB().GetFBStep()
    if fbStep >= FB_Step_Over:
        GameWorldProcess.CloseFB(tick)
    return
##玩家主动离开副本.
# @param curPlayer 玩家实例
# @param tick 时间戳
# @return 返回值无意义
def DoPlayerLeaveFB(curPlayer, tick):
    __DoGatherSoulOver()
    GameWorldProcess.CloseFB(tick)
    return
## 获得副本帮助信息
#  @param curPlayer 当前玩家(被通知对象)
#  @param tick 当前时间
#  @return None
def DoFBHelp(curPlayer, tick):
    gameFB = GameWorld.GetGameFB()
    fbStep = gameFB.GetFBStep()
    if fbStep > FB_Step_Fighting:
        return
    curWheel = gameFB.GetGameFBDictByKey(FBPlayerDict_CurWheel)
    maxWheel = len(GetGatherSoulNPCCfg())
    curWheel = 0 if fbStep == FB_Step_Prepare else min(curWheel+1, maxWheel)
    gatherSoulFBCfg = GetGatherSoulFBCfg()
    guardDict = {}
    for npcid in gatherSoulFBCfg[Def_GuardInfo]:
        guardDict[npcid] = gameFB.GetGameFBDictByKey(FBPlayerDict_GuardNPCCnt%npcid)
    hasRefreshBoss = gameFB.GetGameFBDictByKey(FBPlayerDict_HasRefreshBoss)
    isAutoBoss = gameFB.GetGameFBDictByKey(FBPlayerDict_AutoBoss)
    itemDict = PyGameData.g_gathersoulfbAwardDict.get(curPlayer.GetID(), {})
    helpItemInfo = {}
    for wheel, itemList in itemDict:
        helpItemInfo[str(wheel)] = FBCommon.GetJsonItemList(itemList)
    helpDict = {FBCommon.Help_wheel:curWheel,
                FBCommon.Help_step:fbStep,
                FBCommon.Help_npc:FBCommon.GetJsonNPCKillList(guardDict),
                FBCommon.Help_isAuto:isAutoBoss,
                FBCommon.Help_isAuto:hasRefreshBoss,
                FBCommon.Help_gsItemInfo:helpItemInfo,
                }
    #副本帮助
    GameWorld.DebugLog("DoFBHelp %s" % str(helpDict))
    FBCommon.Notify_FBHelp(curPlayer, helpDict)
    return
##---副本总逻辑计时器---
# @param tick:时间戳
# @return 无意义
# @remarks 副本总逻辑计时器
def OnProcess(tick):
    fbStep = GameWorld.GetGameFB().GetFBStep()
    # 副本进行中
    if fbStep == FB_Step_Fighting:
        __DoLogic_FB_Fighting(tick)
    # 副本结束
    elif fbStep == FB_Step_Over:
        __DoLogic_FB_Over(tick)
    return
def __CheckNPCRefresh(tick):
    gameFB = GameWorld.GetGameFB()
    gatherSoulFBCfg = GetGatherSoulFBCfg()
    lastWheelEndTime = gameFB.GetGameFBDictByKey(FBPlayerDict_LastWheelEndTime)
    if lastWheelEndTime and tick - lastWheelEndTime < gatherSoulFBCfg[Def_WheelRefreshCD]:
        return
    lastNPCRTime = gameFB.GetGameFBDictByKey(FBPlayerDict_LastNPCRTime)
    if lastNPCRTime and tick - lastNPCRTime < gatherSoulFBCfg[Def_NPCRefreshCD]:
        return
    curWheel = gameFB.GetGameFBDictByKey(FBPlayerDict_CurWheel)
    curNPCIndex = gameFB.GetGameFBDictByKey(FBPlayerDict_NPCIndex)
    npcRereshList = GetGatherSoulNPCCfg()  #[[npcid,npcid,],[],[]]
    if curWheel >= len(npcRereshList):
        return
    npcList = npcRereshList[curWheel]
    if curNPCIndex >= len(npcList):
        return
    GameWorld.DebugLog('    开始刷第%s波第%s只怪!' % (curWheel + 1, curNPCIndex + 1))
    refreshNPCid = npcList[curNPCIndex]  #本次要刷新的NPC
#    npcCntDict = {}  #标识点对应数量
#    gameNPC = GameWorld.GetNPCManager()
#    for i in xrange(gameNPC.GetCustomNPCRefreshCount()):
#        npcRefresh = gameNPC.GetCustomNPCRefreshAt(i)
#        rmark = npcRefresh.GetRefreshMark()
#        npcCntDict[rmark] = npcCntDict.get(rmark, npcRefresh.GetCount())
    __RefreshNPC(refreshNPCid)
    if curNPCIndex + 1 >= len(npcList):
        if curWheel + 1 >= len(npcRereshList):
            GameWorld.DebugLog('    全部小怪刷完!')
    gameFB.SetGameFBDict(FBPlayerDict_NPCIndex, curNPCIndex + 1)
    gameFB.SetGameFBDict(FBPlayerDict_LastNPCRTime, tick)
    curPlayer = FBCommon.GetCurSingleFBPlayer()
    if curPlayer:
        DoFBHelp(curPlayer, tick)
    return
def __RefreshNPC(refreshNPCid):
    #刷1只怪物
    gameFB = GameWorld.GetGameFB()
    curRemainCnt = gameFB.GetGameFBDictByKey(FBPlayerDict_NPCRemainCnt)
    curMaxCnt = curRemainCnt + 1
    gatherSoulFBCfg = GetGatherSoulFBCfg()
    refreshMark = gatherSoulFBCfg[Def_NPCRefreshMark]
    NPCCustomRefresh.SetNPCRefresh(refreshMark, [refreshNPCid], curMaxCnt, 1)
    gameFB.SetGameFBDict(FBPlayerDict_NPCRemainCnt, curMaxCnt)
    return
## 副本进行中
#  @param tick:时间戳
#  @return 无意义
def __DoLogic_FB_Fighting(tick):
    __CheckNPCRefresh(tick)
    __CheckAutoRefreshGoldBoss(tick)
    fbCfg = GetGatherSoulNPCCfg()
    # 间隔未到
    if tick - GameWorld.GetGameWorld().GetOpenFBTick() < fbCfg[Def_FightTime] * 1000:
        return
    __DoGatherSoulOver()
    return
##副本关闭中
# @param tick:时间戳
# @return 无意义
# @remarks 副本关闭中
def __DoLogic_FB_Over(tick):
    #gameFB = GameWorld.GetGameFB()
    fbCfg = GetGatherSoulNPCCfg()
    # 间隔未到
    if tick - GameWorld.GetGameFB().GetFBStepTick() < fbCfg[Def_LeaveTime] * 1000:
        return
    #副本关闭
    GameWorldProcess.CloseFB(tick)
    FBCommon.SetFBStep(FB_Step_Close, tick)
    return
def DoFB_NPCDead(curNPC):
    npcRereshList = GetGatherSoulNPCCfg()
    npcidlist = [GetGatherSoulFBCfg()[Def_BossID]]
    for nlist in npcRereshList:
        npcidlist += nlist
    if curNPC.GetNPCID() not in npcidlist:
        return
    gameFB = GameWorld.GetGameFB()
    curRemainCnt = gameFB.GetGameFBDictByKey(FBPlayerDict_NPCRemainCnt)
    newRemainCnt = max(0, curRemainCnt - 1)
    gameFB.SetGameFBDict(FBPlayerDict_NPCRemainCnt, newRemainCnt)
    curWheel = gameFB.GetGameFBDictByKey(FBPlayerDict_CurWheel)
    curNPCIndex = gameFB.GetGameFBDictByKey(FBPlayerDict_NPCIndex)
    if newRemainCnt <= 0 and curNPCIndex >= len(npcRereshList[curWheel]):
        #本波的怪都死掉了
        gameFB.SetGameFBDict(FBPlayerDict_CurWheel, curWheel + 1)
        gameFB.SetGameFBDict(FBPlayerDict_HasRefreshBoss, 0)
        curPlayer = FBCommon.GetCurSingleFBPlayer()
        if curPlayer:
            DoFBHelp(curPlayer, GameWorld.GetGameWorld().GetTick())
        if curWheel + 1>=len(npcRereshList):
            #所有波的怪都死了,结束
            __DoGatherSoulOver()
        else:
            #进入下一波
            gameFB.SetGameFBDict(FBPlayerDict_NPCIndex, 0)
            gameFB.SetGameFBDict(FBPlayerDict_LastWheelEndTime, GameWorld.GetGameWorld().GetTick())
            gameFB.SetGameFBDict(FBPlayerDict_LastNPCRTime, 0)
            if curPlayer:
                curPlayer.Sync_TimeTick(IPY_GameWorld.tttLeaveFamilyWar, 0, GetGatherSoulFBCfg()[Def_WheelRefreshCD], True)
    return
##是否可以夺旗
# @param curPlayer 玩家实例
# @param curNPC NPC实例
# @param tick 时间戳
# @return 无意义
# @remarks
def OnCanCollect(curPlayer, curNPC, tick):
    gameFB = GameWorld.GetGameFB()
    guardNPCID = gameFB.GetGameFBDictByKey(FBPlayerDict_GuardNPCID)
    gatherSoulFBCfg = GetGatherSoulFBCfg()
    guardMaxCntDict = gatherSoulFBCfg[Def_GuardInfo]
    if guardNPCID not in guardMaxCntDict:
        return False
    curCnt = gameFB.GetGameFBDictByKey(FBPlayerDict_GuardNPCCnt % guardNPCID)
    if curCnt >= guardMaxCntDict[guardNPCID]:
        GameWorld.Log('    该守卫已满,不可再建造 guardNPCID=%s,curCnt=%s' % (guardNPCID, curCnt))
        return False
    return True
##副本中,占领NPC的Loading时间.
# @param curPlayer 玩家实例
# @param curNPC NPC实例
# @return 返回值, Loading时间
# @remarks 副本中,占领NPC的Loading时间
def GetFBPrepareTime(curPlayer, curNPC):
    return GetGatherSoulFBCfg()[Def_BuildTime]
##玩家收集成功(塔, 旗)
# @param curPlayer 玩家实例
# @param tick 时间戳
# @return 无意义
# @remarks
def OnCollectOK(curPlayer, npcID, tick):
    tagObj = curPlayer.GetActionObj()
    if not tagObj:
        return
    if tagObj.GetGameObjType() != IPY_GameWorld.gotNPC:
        return
    curNPC = GameWorld.GetNPCManager().GetNPCByIndex(tagObj.GetIndex())
    if not curNPC:
        return
    gatherSoulFBCfg = GetGatherSoulFBCfg()
    if curNPC.GetNPCID() != gatherSoulFBCfg[Def_BuildNPCID]:
        return
    gameFB = GameWorld.GetGameFB()
    guardNPCID = gameFB.GetGameFBDictByKey(FBPlayerDict_GuardNPCID)
    if not guardNPCID:
        GameWorld.ErrLog('采集前未指定要建造NPCID', curPlayer.GetID())
        return
    ChNPC.OnCollectEnd(curPlayer, curNPC)
    #刷守卫
    NPCCustomRefresh.SetNPCRefresh(gatherSoulFBCfg[Def_BuildMark], [(guardNPCID, 1)], 1, 1)
    key = FBPlayerDict_GuardNPCCnt % guardNPCID
    gameFB.SetGameFBDict(key, gameFB.GetGameFBDictByKey(key) + 1)
    return
## 副本行为
#  @param curPlayer 玩家
#  @param actionType 行为类型
#  @param actionInfo 行为信息
#  @param tick 当前时间
#  @return None
def DoFBAction(curPlayer, actionType, actionInfo, tick):
    gameFB = GameWorld.GetGameFB()
    gatherSoulFBCfg = GetGatherSoulFBCfg()
    fbStep = gameFB.GetFBStep()
    if actionType == 0:  #建造守卫
        if actionInfo not in gatherSoulFBCfg[Def_GuardInfo]:
            return
        gameFB.SetGameFBDict(FBPlayerDict_GuardNPCID, actionInfo)
    elif actionType == 1:  #开始刷怪
        if fbStep != FB_Step_Prepare:
            return
        FBCommon.SetFBStep(FB_Step_Fighting, tick)
        FBCommon.AddEnterFBCount(curPlayer, ChConfig.Def_FBMapID_GatherSoul)
    elif actionType == 2:  #召唤黄金BOSS actionInfo 0-召唤1次 1-自动召唤 2-取消自动召唤
        if fbStep != FB_Step_Fighting:
            return
        if actionInfo == 0:
            if gameFB.GetGameFBDictByKey(FBPlayerDict_HasRefreshBoss):
                #本波已刷黄金BOSS
                PlayerControl.NotifyCode(curPlayer, 'JHCallForBoss1')
                return
            #判断钱
            costMoney = gatherSoulFBCfg[Def_BossCostMoney]
            costMoneyList = PlayerControl.HaveMoneyEx(curPlayer, ShareDefine.TYPE_Price_Gold_Paper_Money, costMoney)
            if not costMoneyList:
                return
            for moneyType, moneyCnt in costMoneyList:
                PlayerControl.PayMoney(curPlayer, moneyType, moneyCnt, ChConfig.Def_Cost_FBGatherSoulBoss)
            #立即刷
            __RefreshNPC(gatherSoulFBCfg[Def_BossID])
            gameFB.SetGameFBDict(FBPlayerDict_HasRefreshBoss, 1)
        elif actionInfo == 1:
            if gameFB.GetGameFBDictByKey(FBPlayerDict_AutoBoss):
                GameWorld.DebugLog('已经是自动召唤BOSS状态!')
                return
            gameFB.SetGameFBDict(FBPlayerDict_AutoBoss, 1)
        elif actionInfo == 2:
            if not gameFB.GetGameFBDictByKey(FBPlayerDict_AutoBoss):
                GameWorld.DebugLog('不是自动召唤BOSS状态,不需要取消!')
                return
            gameFB.SetGameFBDict(FBPlayerDict_AutoBoss, 0)
    DoFBHelp(curPlayer, tick)
    return
def __CheckAutoRefreshGoldBoss(tick):
    ##自动召唤黄金BOSS
    gameFB = GameWorld.GetGameFB()
    if not gameFB.GetGameFBDictByKey(FBPlayerDict_AutoBoss):
        return
    curPlayer = FBCommon.GetCurSingleFBPlayer()
    if not curPlayer:
        gameFB.SetGameFBDict(FBPlayerDict_AutoBoss, 0)
        return
    fbStep = gameFB.GetFBStep()
    if fbStep != FB_Step_Fighting:
        gameFB.SetGameFBDict(FBPlayerDict_AutoBoss, 0)
        return
    if gameFB.GetGameFBDictByKey(FBPlayerDict_HasRefreshBoss):
        #本波已刷黄金BOSS
        return
    gatherSoulFBCfg = GetGatherSoulFBCfg()
    costMoney = gatherSoulFBCfg[Def_BossCostMoney]
    costMoneyList = PlayerControl.HaveMoneyEx(curPlayer, ShareDefine.TYPE_Price_Gold_Paper_Money, costMoney, False)
    if not costMoneyList:
        PlayerControl.NotifyCode(curPlayer, 'JHCallForBoss2')
        gameFB.SetGameFBDict(FBPlayerDict_AutoBoss, 0)
    else:
        for moneyType, moneyCnt in costMoneyList:
            PlayerControl.PayMoney(curPlayer, moneyType, moneyCnt, ChConfig.Def_Cost_FBGatherSoulBoss)
        #立即刷
        __RefreshNPC(gatherSoulFBCfg[Def_BossID])
        gameFB.SetGameFBDict(FBPlayerDict_HasRefreshBoss, 1)
    DoFBHelp(curPlayer, tick)
    return
## 是否副本复活
#  @param None
#  @return 是否副本复活
def OnPlayerReborn():
    return True
##玩家死亡.
# @param curPlayer:死亡的玩家
# @param tick 时间戳
# @return 返回值无意义
# @remarks 玩家主动离开副本.
def DoPlayerDead(curPlayer):
    return
## 检查是否可攻击, 主判定不可攻击的情况,其他逻辑由外层决定
#  @param attacker 攻击方
#  @param defender 防守方
#  @return bool
def CheckCanAttackTagObjInFB(attacker, defender):
    gameFB = GameWorld.GetGameFB()
    if gameFB.GetFBStep() != FB_Step_Fighting:
        return False
    return True
def KillGatherSoulNPCDropAward(itemID, itemCnt, isBind):
    ##掉落奖励 {wheel:[[itemid,itemCnt,isBind]]}
    gameFB = GameWorld.GetGameFB()
    curWheel = gameFB.GetGameFBDictByKey(FBPlayerDict_CurWheel) + 1
    ownerID = gameFB.GetGameFBDictByKey(ChConfig.Def_FB_SingleFBPlayerID)
    if ownerID not in PyGameData.g_gathersoulfbAwardDict:
        PyGameData.g_gathersoulfbAwardDict[ownerID] = {}
    if curWheel not in PyGameData.g_gathersoulfbAwardDict[ownerID]:
        PyGameData.g_gathersoulfbAwardDict[ownerID][curWheel] = []
    PyGameData.g_gathersoulfbAwardDict[ownerID][curWheel].append([itemID, itemCnt, isBind])
    curPlayer = FBCommon.GetCurSingleFBPlayer()
    if curPlayer:
        DoFBHelp(curPlayer, 0)
    return
## 副本结束处理
def __DoGatherSoulOver():
    gameFB = GameWorld.GetGameFB()
    if gameFB.GetFBStep() == FB_Step_Over:
        return
    tick = GameWorld.GetGameWorld().GetTick()
    # 进入离开阶段
    FBCommon.SetFBStep(FB_Step_Over, tick)
    ownerID = gameFB.GetGameFBDictByKey(ChConfig.Def_FB_SingleFBPlayerID)
    itemDict = PyGameData.g_gathersoulfbAwardDict.pop(ownerID, {})
    totalItemList = []
    for itemList in itemDict.values():
        totalItemList += itemList
    GameWorld.Log('   副本结束处理  itemDict=%s'%itemDict, ownerID)
    curPlayer = FBCommon.GetCurSingleFBPlayer()
    if not curPlayer:
        #奖励直接发邮件
        PlayerControl.SendMailByKey('JHBagFull2', [ownerID], totalItemList)
        GameWorldProcess.CloseFB(tick)
        return
    needSpace = len(totalItemList)
    emptySpace = ItemCommon.GetItemPackSpace(curPlayer, ShareDefine.rptGatherSoul, needSpace)
    isSendMail = int(needSpace > emptySpace) # 是否发送邮件
    if isSendMail:
        PlayerControl.SendMailByKey('JHBagFull2', [curPlayer.GetPlayerID()], totalItemList)
        GameWorld.DebugLog("背包空间不够,发送邮件: mailItemList=%s" % str(totalItemList), curPlayer.GetPlayerID())
    else:
        for itemID, itemCnt, isBind in totalItemList:
            ItemControler.GivePlayerItem(curPlayer, itemID, itemCnt, isBind, [ShareDefine.rptGatherSoul],
                                            event=["GatherSoulFB", False, {}])
    fbCfg = GetGatherSoulFBCfg()
    costTime = tick - GameWorld.GetGameWorld().GetOpenFBTick()
    itemInfo = FBCommon.GetJsonItemList(totalItemList)
    __SendOverInfo(curPlayer, {FBCommon.Over_isPass:1, FBCommon.Over_costTime:costTime, FBCommon.Over_itemInfo:itemInfo})
    FBCommon.Sync_Player_TimeTick(IPY_GameWorld.tttLeaveMap, fbCfg[Def_LeaveTime] * 1000)
    return
## 发送挑战结果信息
def __SendOverInfo(curPlayer, overDict):
    overDict[FBCommon.Over_dataMapID] = ChConfig.Def_FBMapID_GatherSoul
    #overDict[FBCommon.Over_lineID] = FBCommon.GetFBPropertyMark()
    GameWorld.DebugLog("__SendOverInfo overDict=%s" % (str(overDict)), curPlayer.GetPlayerID())
    FBCommon.Notify_FB_Over(curPlayer, overDict)
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py
@@ -1130,6 +1130,29 @@
                        ("DWORD", "FightPower", 0),
                        ("dict", "Attr", 0),
                        ),
                "GatherSoul":(
                        ("DWORD", "ItemID", 1),
                        ("list", "AttrType", 0),
                        ("BYTE", "SoulGrade", 0),
                        ),
                "GatherSoulCompound":(
                        ("DWORD", "TagItemID", 1),
                        ("WORD", "NeedLV", 0),
                        ("list", "NeedItem", 0),
                        ("WORD", "NeedSoulSplinters", 0),
                        ("WORD", "NeedSoulCore", 0),
                        ),
                "GatherSoulAttr":(
                        ("WORD", "AttrType", 1),
                        ("char", "AttrInfo1", 0),
                        ("dict", "AttrInfo2", 0),
                        ("dict", "AttrInfo3", 0),
                        ("dict", "AttrInfo4", 0),
                        ("dict", "AttrInfo5", 0),
                        ),
                }
@@ -3436,6 +3459,55 @@
    def GetFightPower(self): return self.FightPower # 增加战力
    def GetAttr(self): return self.Attr # 属性加成
# 聚魂表
class IPY_GatherSoul():
    def __init__(self):
        self.ItemID = 0
        self.AttrType = []
        self.SoulGrade = 0
        return
    def GetItemID(self): return self.ItemID # 物品ID
    def GetAttrType(self): return self.AttrType # 属性类型
    def GetSoulGrade(self): return self.SoulGrade # 魂阶段
# 聚魂合成表
class IPY_GatherSoulCompound():
    def __init__(self):
        self.TagItemID = 0
        self.NeedLV = 0
        self.NeedItem = []
        self.NeedSoulSplinters = 0
        self.NeedSoulCore = 0
        return
    def GetTagItemID(self): return self.TagItemID # 合成的物品ID
    def GetNeedLV(self): return self.NeedLV # 需要的玩家等级
    def GetNeedItem(self): return self.NeedItem # 需要的物品ID
    def GetNeedSoulSplinters(self): return self.NeedSoulSplinters # 需要的聚魂碎片
    def GetNeedSoulCore(self): return self.NeedSoulCore # 需要的核心环
# 聚魂属性表
class IPY_GatherSoulAttr():
    def __init__(self):
        self.AttrType = 0
        self.AttrInfo1 = ""
        self.AttrInfo2 = {}
        self.AttrInfo3 = {}
        self.AttrInfo4 = {}
        self.AttrInfo5 = {}
        return
    def GetAttrType(self): return self.AttrType # 属性类型
    def GetAttrInfo1(self): return self.AttrInfo1 # 基础属性-参数聚魂等级level
    def GetAttrInfo2(self): return self.AttrInfo2 # 品质系数(品质_系数|…)
    def GetAttrInfo3(self): return self.AttrInfo3 # 多属性系数
    def GetAttrInfo4(self): return self.AttrInfo4 # 初始属性(品质_属性值|…)
    def GetAttrInfo5(self): return self.AttrInfo5 # 阶段系数
def Log(msg, playerID=0, par=0):
    LogUI.Msg("%s\t%s\t%s" % (par, playerID, msg))
@@ -3670,6 +3742,12 @@
        self.ipyIceLodeStarAwardLen = len(self.ipyIceLodeStarAwardCache)
        self.ipyGodWeaponEffectCache = self.__LoadFileData("GodWeaponEffect", IPY_GodWeaponEffect)
        self.ipyGodWeaponEffectLen = len(self.ipyGodWeaponEffectCache)
        self.ipyGatherSoulCache = self.__LoadFileData("GatherSoul", IPY_GatherSoul)
        self.ipyGatherSoulLen = len(self.ipyGatherSoulCache)
        self.ipyGatherSoulCompoundCache = self.__LoadFileData("GatherSoulCompound", IPY_GatherSoulCompound)
        self.ipyGatherSoulCompoundLen = len(self.ipyGatherSoulCompoundCache)
        self.ipyGatherSoulAttrCache = self.__LoadFileData("GatherSoulAttr", IPY_GatherSoulAttr)
        self.ipyGatherSoulAttrLen = len(self.ipyGatherSoulAttrCache)
        Log("IPY_FuncConfig count=%s" % len(self.ipyFuncConfigDict))
        Log("IPY_DataMgr InitOK!")
        return
@@ -4046,6 +4124,12 @@
    def GetIceLodeStarAwardByIndex(self, index): return self.ipyIceLodeStarAwardCache[index]
    def GetGodWeaponEffectCount(self): return self.ipyGodWeaponEffectLen
    def GetGodWeaponEffectByIndex(self, index): return self.ipyGodWeaponEffectCache[index]
    def GetGatherSoulCount(self): return self.ipyGatherSoulLen
    def GetGatherSoulByIndex(self, index): return self.ipyGatherSoulCache[index]
    def GetGatherSoulCompoundCount(self): return self.ipyGatherSoulCompoundLen
    def GetGatherSoulCompoundByIndex(self, index): return self.ipyGatherSoulCompoundCache[index]
    def GetGatherSoulAttrCount(self): return self.ipyGatherSoulAttrLen
    def GetGatherSoulAttrByIndex(self, index): return self.ipyGatherSoulAttrCache[index]
IPYData = IPY_DataMgr()
def IPY_Data(): return IPYData
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py
@@ -1029,6 +1029,8 @@
        if packIndex == ShareDefine.rptRune:
            runeSource = tagItem.GetUserAttr(ShareDefine.Def_IudetRuneSource) or 1
            setItemKeyData = GetRuneItemKeyData(tagItem.GetItemTypeID(), tagItem.GetUserAttr(ShareDefine.Def_IudetRuneLV), source=runeSource)
        elif packIndex == ShareDefine.rptGatherSoul:
            setItemKeyData = GetGatherSoulItemKeyData(tagItem.GetItemTypeID(), tagItem.GetUserAttr(ShareDefine.Def_IudetGatherSoulLV))
        refreshPlaceList = []
        for place in xrange(ItemCommon.GetVPackCnt(packIndex)):
@@ -1138,7 +1140,7 @@
        isBind = tagItem.GetIsBind()
        isNeedRecord = False
        # 目前暂只记录放入背包的
        if packIndex in [IPY_GameWorld.rptItem, ShareDefine.rptTreasure, ShareDefine.rptRune]:
        if packIndex in [IPY_GameWorld.rptItem, ShareDefine.rptTreasure, ShareDefine.rptRune, ShareDefine.rptGatherSoul]:
            isNeedRecord = ItemNeedRecord(tagItem) or isForceEvent
        putResult = False
        
@@ -1378,6 +1380,14 @@
def IsRuneItemNeedRecord(curItem, plusLV):
    return plusLV > 0 or curItem.GetItemColor() >= ChConfig.Def_Quality_Orange
# 聚魂物品存储字典数值数据结构: 前5位为物品ID, 6~8位为强化等级
def GetGatherSoulItemKeyData(itemID, GatherSoulLV):
    return min(GatherSoulLV, 999) * 100000 + itemID
def GetGatherSoulItemID(keyData): return keyData % 100000
def GetGatherSoulItemPlusLV(keyData): return keyData % 100000000 / 100000
def IsGatherSoulItemNeedRecord(curItem, plusLV):
    return plusLV > 0 or curItem.GetItemColor() >= ChConfig.Def_Quality_Orange
def SetVPackItemKeyData(curPlayer, packIndex, place, keyData, isSync=True):
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_VPackItem % (packIndex, place), keyData)
    if isSync:
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/UseItem/ItemCommon.py
@@ -1849,6 +1849,13 @@
            itemName = str(itemID) if not curItemData else  curItemData.GetName()
            itemName = "%s LV%s" % (itemName, plusLV + 1)
            isNeedRecord = curItemData and ItemControler.IsRuneItemNeedRecord(curItemData, plusLV)
        if packIndex == ShareDefine.rptGatherSoul:
            itemID = ItemControler.GetGatherSoulItemID(itemKeyData)
            plusLV = ItemControler.GetGatherSoulItemPlusLV(itemKeyData)
            curItemData = GameWorld.GetGameData().GetItemByTypeID(itemID)
            itemName = str(itemID) if not curItemData else  curItemData.GetName()
            itemName = "%s LV%s" % (itemName, plusLV + 1)
            isNeedRecord = curItemData and ItemControler.IsGatherSoulItemNeedRecord(curItemData, plusLV)
            
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_VPackItem % (packIndex, place), 0)
        if isNeedRecord:
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/NPC/NPCCommon.py
@@ -47,7 +47,7 @@
import BossHurtMng
import PlayerSuperMarket
import GameLogic_FamilyInvade
#import GameLogic_MunekadoTrial
import GameLogic_GatherSoul
import FormulaControl
import PlayerMagicWeapon
import PlayerBossReborn
@@ -4189,6 +4189,13 @@
            if not curItem:
                continue
            
            if mapID == ChConfig.Def_FBMapID_GatherSoul:#聚魂副本特殊处理
                GameLogic_GatherSoul.KillGatherSoulNPCDropAward(itemID, itemCnt, isBind)
                dropItemDataStr = ChItem.GetMapDropItemDataStr(curItem)
                self.SendVirtualItemDrop(ownerPlayer, itemID, resultX, resultY, dropItemDataStr)
                curItem.Clear()
                continue
            if isDropInItemPack:
                curItem.SetUserAttr(ShareDefine.Def_IudetSource, ShareDefine.Item_Source_VirtualItemDrop)
                dropItemDataStr = ChItem.GetMapDropItemDataStr(curItem)
@@ -4196,17 +4203,22 @@
                if ItemControler.DoLogic_PutItemInPack(ownerPlayer, curItem, True, True,
                                                       event=["NPCDrop", False, {"npcID":npcID}]):
                    #通知客户端
                    vItemDrop = ChPyNetSendPack.tagMCVirtualItemDrop()
                    vItemDrop.ItemTypeID = itemID
                    vItemDrop.PosX = resultX
                    vItemDrop.PosY = resultY
                    vItemDrop.UserData = dropItemDataStr
                    vItemDrop.UserDataLen = len(vItemDrop.UserData)
                    NetPackCommon.SendFakePack(ownerPlayer, vItemDrop)
                    self.SendVirtualItemDrop(ownerPlayer, itemID, resultX, resultY, dropItemDataStr)
            else:
                self.__MapCreateItem(curItem, resultX, resultY, ownerType, ownerID)
        return
    
    def SendVirtualItemDrop(self, player, itemID, posX, posY, userDataStr):
        #通知客户端
        vItemDrop = ChPyNetSendPack.tagMCVirtualItemDrop()
        vItemDrop.ItemTypeID = itemID
        vItemDrop.PosX = posX
        vItemDrop.PosY = posY
        vItemDrop.UserData = userDataStr
        vItemDrop.UserDataLen = len(vItemDrop.UserData)
        NetPackCommon.SendFakePack(player, vItemDrop)
        return
    #---------------------------------------------------------------------
    ## NPC被杀死逻辑处理
    #  @param self 类实例
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py
@@ -76,7 +76,7 @@
import PlayerEquipDecompose
import PlayerCoat
import PlayerGreatMaster
import PlayerCostVIP
import PlayerGatherSoul
import PlayerMergeKing
import PlayerMergePK
import GameFuncComm
@@ -564,7 +564,8 @@
    SyncChatBubbleBoxState(curPlayer)
    # 副本助战
    FBHelpBattle.DoPlayerLogin(curPlayer)
    # 聚魂
    PlayerGatherSoul.PlayerLogin(curPlayer)
    curPlayer.SetState(0)   # 脱机挂恢复为正常上线
    curPlayer.SetFacePic(0) # 通知数据库是否保存还是下线,做一次恢复,1为保存 0为正常下线
    tjgTime = PlayerTJG.GetTJGTime(curPlayer)
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerControl.py
@@ -64,7 +64,7 @@
import PlayerGameEvent
import EventReport
import PlayerTeHui
import GameLogic_XMZZ
import PlayerGatherSoul
import PlayerSuccess
import PlayerPet
import PlayerGreatMaster
@@ -4089,6 +4089,7 @@
        PlayerFamilyTech.CalcFamilyTechAttr(curPlayer)
        PlayerEquipDecompose.RefreshEDAttr(curPlayer)
        PlayerDogz.RefreshDogzAttr(curPlayer)
        PlayerGatherSoul.RefreshGatherSoulAttr(curPlayer)
        self.RefreshAllState(isForce=True)
        GameWorld.DebugLog("End ReCalcAllState!!!")
        return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerGatherSoul.py
New file
@@ -0,0 +1,533 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#-------------------------------------------------------------------------------
#
#-------------------------------------------------------------------------------
#
##@package Player.PlayerGatherSoul
#
# @todo:玩家聚魂
# @author xdh
# @date 2018-12-10
# @version 1.0
#
# 详细描述: 玩家聚魂
#---------------------------------------------------------------------
#"""Version = 2018-12-10 12:00"""
#---------------------------------------------------------------------
import GameWorld
import ShareDefine
import ChConfig
import ItemCommon
import ItemControler
import PlayerControl
import ChPyNetSendPack
import NetPackCommon
import IpyGameDataPY
import FormulaControl
import DataRecordPack
g_GatherSoulLVExpDict = {}  #经验缓存
g_gatherSoulLVAttrDict = {}  #属性缓存
##登录处理
# @param curPlayer 玩家
# @return None
def PlayerLogin(curPlayer):
    Sync_GatherSoulHoleInfo(curPlayer)
    return
## 获取聚魂ipy数据
def GetGatherSoulIpyData(itemID):return IpyGameDataPY.GetIpyGameData("GatherSoul", itemID)
## 获取聚魂升级需要经验
def GetGatherSoulNeedExp(itemID, lv):
    global g_GatherSoulLVExpDict
    #((升级经验 * 品质系数)* 神魂系数)*  多属性系数
    itemData = GameWorld.GetGameData().GetItemByTypeID(itemID)
    if not itemData:
        return 0
    ipyData = GetGatherSoulIpyData(itemID)
    if not ipyData:
        return 0
    itemColor = itemData.GetItemColor()
    if lv == 0:  #初始经验
        expDict = IpyGameDataPY.GetFuncEvalCfg('GatherSoulLevelUp', 4, {})
        exp = expDict.get(itemColor, 0)
    else:
        if lv in g_GatherSoulLVExpDict:
            exp = g_GatherSoulLVExpDict[lv]
        else:
            level = lv + 1  #公式从1开始
            exp = eval(IpyGameDataPY.GetFuncCompileCfg('GatherSoulLevelUp'))
            g_GatherSoulLVExpDict[lv] = exp
        qualityPerDict = IpyGameDataPY.GetFuncEvalCfg('GatherSoulLevelUp', 2, {})
        if itemColor in qualityPerDict:
            exp *= float(qualityPerDict[itemColor])
        soulGrade = ipyData.GetSoulGrade()
        exp *= float(IpyGameDataPY.GetFuncEvalCfg('GatherSoulLevelUp', 4, {}).get(soulGrade, 1))
        attrTypeCnt = len(ipyData.GetAttrType())
        specialPer = IpyGameDataPY.GetFuncEvalCfg('GatherSoulLevelUp', 3, {}).get(attrTypeCnt, 1)
        exp *= float(specialPer)
    return exp
## 获取聚魂属性数值
def GetGatherSoulAttrValue(itemID, lv):
    global g_gatherSoulLVAttrDict
    #((初始属性 + 升级属性 * 品质系数)* 神魂系数 ) * 多属性系数
    itemData = GameWorld.GetGameData().GetItemByTypeID(itemID)
    if not itemData:
        return {}
    ipyData = GetGatherSoulIpyData(itemID)
    if not ipyData:
        return {}
    level = lv + 1  #公式从1开始
    attrTypeList = ipyData.GetAttrType()
    attrTypeCnt = len(attrTypeList)  #属性条数
    soulGrade = ipyData.GetSoulGrade()
    itemColor = itemData.GetItemColor()
    attrDict = {}
    for attrType in attrTypeList:
        attrIpyData = IpyGameDataPY.GetIpyGameData('GatherSoulAttr', attrType)
        if not attrIpyData:
            GameWorld.ErrLog('    聚魂属性表未配置该属性 attrType=%s' % attrType)
            continue
        key = '%s_%s' % (attrType, level)
        if key in g_gatherSoulLVAttrDict:
            value = g_gatherSoulLVAttrDict[key]
        else:
            attrFormula = FormulaControl.GetCompileFormula('GatherSoulAttr%s' % attrType, attrIpyData.GetAttrInfo1())
            if not attrFormula:
                continue
            value = eval(attrFormula)
            g_gatherSoulLVAttrDict[key] = value
        qualityPerDict = attrIpyData.GetAttrInfo2()
        if itemColor in qualityPerDict:
            value *= float(qualityPerDict[itemColor])
        extraValueDict = attrIpyData.GetAttrInfo4()
        value += extraValueDict.get(itemColor, 0)
        #阶段系数
        value *= float(attrIpyData.GetAttrInfo5().get(soulGrade, 1))
        #属性条目系数
        specialPer = attrIpyData.GetAttrInfo3().get(attrTypeCnt, 1)
        value *= float(specialPer)
        attrDict[int(attrType)] = int(value)
    return attrDict
def GetGatherSoulMaxLV(itemID):
    # 获取聚魂最大等级
    itemData = GameWorld.GetGameData().GetItemByTypeID(itemID)
    if not itemData:
        return 0
    GatherSoulMaxLVDict = IpyGameDataPY.GetFuncEvalCfg('GatherSoulMaxLV', 1, {})
    itemColor = itemData.GetItemColor()
    GatherSoulMaxLV = GatherSoulMaxLVDict.get(itemColor, 0)
    return GatherSoulMaxLV
def SwitchGatherSoul(curPlayer, srcBackpack, desBackPack, srcIndex, destIndex):
    # 镶嵌/摘下聚魂
    if not ((desBackPack == ShareDefine.rptGatherSoul and srcBackpack == ShareDefine.rptTempSwap) \
            or (srcBackpack == ShareDefine.rptGatherSoul and desBackPack == ShareDefine.rptTempSwap)):
        return False
    playerID = curPlayer.GetPlayerID()
    GatherSoulUnlockDict = IpyGameDataPY.GetFuncEvalCfg("GatherSoulHole", 1, {})
    maxGatherSoulHole = len(GatherSoulUnlockDict)
    # 穿
    if desBackPack == ShareDefine.rptTempSwap:
        desGatherSoulNum = destIndex
        if desGatherSoulNum < 0 or desGatherSoulNum >= maxGatherSoulHole:
            GameWorld.DebugLog("不存在该聚魂孔! desGatherSoulNum=%s" % desGatherSoulNum, playerID)
            return True
        if curPlayer.GetLV() < GatherSoulUnlockDict.get(desGatherSoulNum, 0):
            GameWorld.DebugLog("该聚魂孔未解锁! desGatherSoulNum=%s,needlv=%s" % (desGatherSoulNum, GatherSoulUnlockDict.get(desGatherSoulNum, 0)), playerID)
            return True
        srcGatherSoulData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_VPackItem
                                                     % (ShareDefine.rptGatherSoul, srcIndex))  # 聚魂背包中的值
        if not srcGatherSoulData:
            GameWorld.DebugLog("聚魂背包该位置没有聚魂! srcIndex=%s" % srcIndex, playerID)
            return True
        srcGatherSoulItemID = ItemControler.GetGatherSoulItemID(srcGatherSoulData)
        srcItemData = GameWorld.GetGameData().GetItemByTypeID(srcGatherSoulItemID)
        if not srcItemData:
            return
        srcGatherSoulType = srcItemData.GetType()
        needItemType = IpyGameDataPY.GetFuncEvalCfg("GatherSoulHole", 2, {}).get(desGatherSoulNum, 0)
        if srcGatherSoulType != needItemType:
            GameWorld.DebugLog("该聚魂孔不能镶嵌该聚魂类型! desGatherSoulNum=%s,srcGatherSoulType=%s,needItemType=%s" % (desGatherSoulNum, srcGatherSoulType, needItemType), playerID)
            return
        srcIpyData = GetGatherSoulIpyData(srcGatherSoulItemID)
        if not srcIpyData:
            GameWorld.Log("该聚魂没有配置属性! 无法镶嵌! itemID=%s" % srcGatherSoulItemID, playerID)
            return True
        srcGatherSoulAttrTypeList = srcIpyData.GetAttrType()
        # 判断是否已有镶嵌该属性类型
        for GatherSoulNum in xrange(maxGatherSoulHole):
            if GatherSoulNum == desGatherSoulNum:  # 目标孔不判断
                continue
            GatherSoulData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_GatherSoulHoleData % GatherSoulNum, 0)
            if not GatherSoulData:
                continue
            GatherSoulItemID = ItemControler.GetGatherSoulItemID(GatherSoulData)
            ipyData = GetGatherSoulIpyData(GatherSoulItemID)
            if not ipyData:
                continue
            attrTypeList = ipyData.GetAttrType()
            if set(srcGatherSoulAttrTypeList) & set(attrTypeList):
                GameWorld.DebugLog("已有镶嵌该属性类型! 无法镶嵌! GatherSoulHoleNum=%s,attrTypeList=%s,srcGatherSoulAttrTypeList=%s" % (GatherSoulNum, attrTypeList, srcGatherSoulAttrTypeList), playerID)
                return True
        desGatherSoulData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_GatherSoulHoleData % desGatherSoulNum, 0)  # 孔上的值
        # 设置聚魂孔数据
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_GatherSoulHoleData % desGatherSoulNum, srcGatherSoulData)
        # 原来的孔数据,则放入聚魂背包中
        ItemControler.SetVPackItemKeyData(curPlayer, ShareDefine.rptGatherSoul, srcIndex, desGatherSoulData)
    else:  #脱
        srcGatherSoulNum = srcIndex
        srcGatherSoulData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_GatherSoulHoleData % srcGatherSoulNum, 0)
        if not srcGatherSoulData:
            GameWorld.DebugLog("该聚魂孔没有镶嵌聚魂! srcGatherSoulNum=%s, srcGatherSoulData=%s" % (srcGatherSoulNum, srcGatherSoulData), curPlayer.GetPlayerID())
            return True
        emptyIndex = ItemCommon.GetEmptyIndexInPack(curPlayer, ShareDefine.rptGatherSoul)
        if emptyIndex == -1:
            GameWorld.DebugLog("聚魂背包已满,无法摘下! ", curPlayer.GetPlayerID())
            return True
        desGatherSoulData = 0
        # 摘下设置孔数据为0
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_GatherSoulHoleData % srcGatherSoulNum, 0)
        ItemControler.SetVPackItemKeyData(curPlayer, ShareDefine.rptGatherSoul, emptyIndex, srcGatherSoulData)
    dataDict = {'desBackPack':desBackPack, 'srcGatherSoulData':srcGatherSoulData, 'desGatherSoulData':desGatherSoulData}
    DataRecordPack.Cache_FightPowerChangeInfo(curPlayer, ChConfig.PowerDownType_GatherSoul, dataDict)
    RefreshGatherSoulAttr(curPlayer)
    PlayerControl.PlayerControl(curPlayer).RefreshPlayerAttrState()
    Sync_GatherSoulHoleInfo(curPlayer)
    return True
#// A5 18 聚魂升级 #tagCMGatherSoulUp
#struct    tagCMGatherSoulUp
#{
#    tagHead        Head;
#    BYTE        PlaceType;    // 位置类型;0-背包,1-孔
#    WORD        PlaceIndex;    // 位置索引
#};
def OnGatherSoulUp(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    placeType = clientData.PlaceType
    placeIndex = clientData.PlaceIndex
    if placeType == 0:
        GatherSoulData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_VPackItem % (ShareDefine.rptGatherSoul, placeIndex))
    elif placeType == 1:
        GatherSoulData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_GatherSoulHoleData % (placeIndex), 0)
    else:
        return
    playerID = curPlayer.GetPlayerID()
    if not GatherSoulData:
        GameWorld.DebugLog("该位置不存在聚魂, 无法升级! placeType=%s,placeIndex=%s" % (placeType, placeIndex), playerID)
        return
    GatherSoulItemID = ItemControler.GetGatherSoulItemID(GatherSoulData)
    GatherSoulItemPlusLV = ItemControler.GetGatherSoulItemPlusLV(GatherSoulData)
    itemData = GameWorld.GetGameData().GetItemByTypeID(GatherSoulItemID)
    if not itemData:
        return
    GatherSoulMaxLV = GetGatherSoulMaxLV(GatherSoulItemID)
    if GatherSoulItemPlusLV + 1 >= GatherSoulMaxLV:
        GameWorld.DebugLog('该聚魂已满级,无法升级!GatherSoulMaxLV=%s' % GatherSoulMaxLV)
        return
    plusCost = GetGatherSoulNeedExp(GatherSoulItemID, GatherSoulItemPlusLV + 1)
    plusCost = int(plusCost)
    if not plusCost:
        GameWorld.DebugLog("该聚魂无法升级!  placeType=%s,placeIndex=%s,itemID=%s,plusLV=%s"
                           % (placeType, placeIndex, GatherSoulItemID, GatherSoulItemPlusLV), playerID)
        return
    updGatherSoulData = ItemControler.GetGatherSoulItemKeyData(GatherSoulItemID, GatherSoulItemPlusLV + 1)
    if not PlayerControl.PayMoney(curPlayer, ShareDefine.TYPE_Price_SoulDust, plusCost):
        curGatherSoulMoney = PlayerControl.GetMoney(curPlayer, ShareDefine.TYPE_Price_SoulDust)
        GameWorld.DebugLog("聚魂尘点不足,无法升级!placeType=%s,placeIndex=%s,itemID=%s,plusLV=%s,plusCost=%s,curGatherSoulMoney=%s"
                           % (placeType, placeIndex, GatherSoulItemID, GatherSoulItemPlusLV, plusCost, curGatherSoulMoney), playerID)
        return
    if placeType == 0:
        ItemControler.SetVPackItemKeyData(curPlayer, ShareDefine.rptGatherSoul, placeIndex, updGatherSoulData)
    elif placeType == 1:
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_GatherSoulHoleData % (placeIndex), updGatherSoulData)
        RefreshGatherSoulAttr(curPlayer)
        PlayerControl.PlayerControl(curPlayer).RefreshPlayerAttrState()
        Sync_GatherSoulHoleInfo(curPlayer)
    GameWorld.DebugLog("聚魂升级!placeType=%s,placeIndex=%s,GatherSoulData=%s,updGatherSoulData=%s"
                       % (placeType, placeIndex, GatherSoulData, updGatherSoulData), playerID)
    return
#// A5 19 聚魂分解 #tagCMGatherSoulDecompose
#
#struct    tagCMGatherSoulDecompose
#{
#    tagHead        Head;
#    BYTE        IsAuto;    // 是否自动分解
#    BYTE        Count;    // 指定批量分解数,最大不超过50个
#    WORD        PlaceIndexList[Count];    // 批量分解位置索引列表
#};
def OnGatherSoulDecompose(index, clientData, tick):
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    isAuto = clientData.IsAuto
    placeList = clientData.PlaceIndexList
    delPlaceDict = {}
    totalSoulDust = 0
    totalSoulSplinters = 0
    totalSoulCore = 0
    giveMaterialDict = {}
    needPackSpace = 0
    packIndex = ShareDefine.rptGatherSoul
    for place in placeList:
        GatherSoulData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_VPackItem % (packIndex, place))
        if not GatherSoulData:
            continue
        GatherSoulItemID = ItemControler.GetGatherSoulItemID(GatherSoulData)
        GatherSoulItemPlusLV = ItemControler.GetGatherSoulItemPlusLV(GatherSoulData)
        itemData = GameWorld.GetGameData().GetItemByTypeID(GatherSoulItemID)
        if not itemData:
            continue
        soulidList, soulSplinters, soulCore, soulDust = [], 0, 0, 0
        if itemData.GetType() == ChConfig.Def_ItemType_GatherSoulExp:  #精华物品读效果值
            curEff = itemData.GetEffectByIndex(0)
            soulDust = curEff.GetEffectValue(0)
        else:
            soulDust = 0
            for lv in xrange(GatherSoulItemPlusLV + 1):
                soulDust += GetGatherSoulNeedExp(GatherSoulItemID, lv)
            #多属性的先拆解成单属性的聚魂
            soulidList, soulSplinters, soulCore = __GetGatherSoulSplitMaterial(GatherSoulItemID)
            for itemID in soulidList:
                giveMaterialDict[itemID] = giveMaterialDict.get(itemID, 0) + 1
                needPackSpace += 1
        totalSoulSplinters += soulSplinters
        totalSoulCore += soulCore
        totalSoulDust += soulDust
        delPlaceDict[place] = [GatherSoulData, soulidList, int(soulDust), soulSplinters, soulCore]
    if delPlaceDict:
        ItemCommon.DelVPackItem(curPlayer, packIndex, delPlaceDict.keys(), ChConfig.ItemDel_GatherSoul)
    addDataDict = {"delPlaceDict":delPlaceDict, "isAuto":isAuto}
    if totalSoulDust:
        totalSoulDust = int(totalSoulDust)
        PlayerControl.GiveMoney(curPlayer, ShareDefine.TYPE_Price_SoulDust, totalSoulDust,
                                ChConfig.Def_GiveMoney_GatherSoulDecompose, addDataDict, False)
        PlayerControl.NotifyCode(curPlayer, 'hwj_20170807_1', [totalSoulDust, ShareDefine.TYPE_Price_SoulDust])
    if totalSoulSplinters:
        PlayerControl.GiveMoney(curPlayer, ShareDefine.TYPE_Price_SoulSplinters, totalSoulSplinters,
                                ChConfig.Def_GiveMoney_GatherSoulDecompose, addDataDict, False)
        PlayerControl.NotifyCode(curPlayer, 'hwj_20170807_1', [totalSoulSplinters, ShareDefine.TYPE_Price_SoulSplinters])
    if totalSoulCore:
        PlayerControl.GiveMoney(curPlayer, ShareDefine.TYPE_Price_SoulCore, totalSoulCore,
                                ChConfig.Def_GiveMoney_GatherSoulDecompose, addDataDict, False)
        PlayerControl.NotifyCode(curPlayer, 'hwj_20170807_1', [totalSoulCore, ShareDefine.TYPE_Price_SoulCore])
    if giveMaterialDict:
        emptySpace = ItemCommon.GetItemPackSpace(curPlayer, ShareDefine.rptGatherSoul, 1)
        if emptySpace < needPackSpace:
            giveMaterialList = [[itemID, itemCnt, 1] for itemID, itemCnt in giveMaterialDict.items()]
            PlayerControl.SendMailByKey('JHBagFull1', [curPlayer.GetID()], giveMaterialList)
        else:
            for itemID, itemCnt in giveMaterialDict.items:
                ItemControler.GivePlayerItem(curPlayer, itemID, itemCnt, 1, [ShareDefine.rptGatherSoul])
    GameWorld.DebugLog("聚魂分解: isAuto=%s,PlaceIndexList=%s, delPlaceDict=%s" % (isAuto, placeList, delPlaceDict))
    return
def __GetGatherSoulSplitMaterial(gathersoulID, soulidList=[], soulSplinters=0, soulCore=0):
    ##拆解多属性聚魂 返回单属性聚魂ID,材料
    compoundIpyData = IpyGameDataPY.GetIpyGameDataNotLog('GatherSoulCompound', gathersoulID)
    if compoundIpyData:
        materialList = compoundIpyData.GetNeedItem()
        soulSplinters += compoundIpyData.GetNeedSoulSplinters()
        soulCore += compoundIpyData.GetNeedSoulCore()
        for itemID in materialList:
            soulIpyData = GetGatherSoulIpyData(itemID)
            if soulIpyData and len(soulIpyData.GetAttrType()) > 1:
                __GetGatherSoulSplitMaterial(itemID, soulidList, soulSplinters, soulCore)
            else:
                soulidList.append(itemID)
    return soulidList, soulSplinters, soulCore
#// A5 1C 聚魂合成 #tagCMGatherSoulCompound
#
#struct    tagCMGatherSoulCompound
#{
#    tagHead        Head;
#    BYTE        Cnt;
#    BYTE        PackList[Cnt];    //所在位置 0-背包 1-孔
#    WORD        IndexList[Cnt];    //物品索引
#    DWORD        TagItemID;    //合成目标物品ID
#};
def OnGatherSoulCompound(index, clientData, tick):
    ##聚魂合成
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    tagItemID = clientData.TagItemID
    packList = clientData.PackList
    indexList = clientData.IndexList
    GameWorld.DebugLog('    聚魂合成 tagItemID=%s' % tagItemID)
    ipyData = IpyGameDataPY.GetIpyGameData('GatherSoulCompound', tagItemID)
    if not ipyData:
        return
    if curPlayer.GetLV() < ipyData.GetNeedLV():
        return
    materialsIDList = []
    materialsLVDict = {}
    indexList1 = []  #背包的聚魂索引
    indexList2 = []  #孔索引
    for i, placeType in enumerate(packList):
        index = indexList[i]
        if placeType == 0:
            GatherSoulData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_VPackItem % (ShareDefine.rptGatherSoul, index))  # 聚魂背包中的值
            indexList1.append(index)
        else:
            GatherSoulData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_GatherSoulHoleData % (index), 0)
            indexList2.append(index)
        if not GatherSoulData:
            continue
        GatherSoulItemID = ItemControler.GetGatherSoulItemID(GatherSoulData)
        GatherSoulItemPlusLV = ItemControler.GetGatherSoulItemPlusLV(GatherSoulData)
        materialsIDList.append(GatherSoulItemID)
        materialsLVDict[GatherSoulItemID] = GatherSoulItemPlusLV
    needItemIDList = ipyData.GetNeedItem()
    if sorted(materialsIDList) != sorted(needItemIDList):
        GameWorld.DebugLog('    聚魂合成 材料不对 tagItemID=%s, materialsIDList=%s, needItemIDList=%s' % (tagItemID, materialsIDList, needItemIDList))
        return
    if 0 not in packList:
        #如果没有背包的材料要判断格子数
        emptySpace = ItemCommon.GetItemPackSpace(curPlayer, ShareDefine.rptGatherSoul, 1)
        if emptySpace < 1:
            PlayerControl.NotifyCode(curPlayer, "GeRen_chenxin_676165", [ShareDefine.rptGatherSoul])
            GameWorld.DebugLog('    聚魂合成 背包格子数量不足1个')
            return
    costMoneyDict = {ShareDefine.TYPE_Price_SoulSplinters:ipyData.GeNeedSoulSplinters(),
                     ShareDefine.TYPE_Price_SoulCore:ipyData.GeNeedSoulSplinters(), }
    for moneyType, costMoney in costMoneyDict:
        if not PlayerControl.HaveMoney(curPlayer, moneyType, costMoney):
            return
    infoDict = {"TagItemID":tagItemID}
    for moneyType, costMoney in costMoneyDict:
        PlayerControl.PayMoney(curPlayer, moneyType, costMoney, ChConfig.Def_Cost_ItemProduce, infoDict)
    totalPoint = 0
    for itemID in materialsIDList:
        decompose = 0
        GatherSoulItemPlusLV = materialsLVDict.get(itemID, 0)
        for lv in range(1, GatherSoulItemPlusLV + 1):
            decompose += GetGatherSoulNeedExp(itemID, lv)
        totalPoint += decompose
    totalPoint = int(totalPoint)
    tagItemLV = 0
    GatherSoulMaxLV = GetGatherSoulMaxLV(tagItemID)
    for lv in xrange(1, GatherSoulMaxLV):
        needExp = GetGatherSoulNeedExp(tagItemID, lv)
        if totalPoint < needExp:
            break
        tagItemLV = lv
        totalPoint -= needExp
    #删除材料物品
    if indexList1:
        ItemCommon.DelVPackItem(curPlayer, ShareDefine.rptGatherSoul, indexList1, ChConfig.ItemDel_GatherSoul)
    if indexList2:
        for index in indexList2:
            srcGatherSoulData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_GatherSoulHoleData % index, 0)
            PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_GatherSoulHoleData % index, 0)
            dataDict = {'doType':'GatherSoulCompound', 'srcGatherSoulData':srcGatherSoulData, 'desGatherSoulData':0}
            DataRecordPack.Cache_FightPowerChangeInfo(curPlayer, ChConfig.PowerDownType_GatherSoul, dataDict)
        Sync_GatherSoulHoleInfo(curPlayer)
        RefreshGatherSoulAttr(curPlayer)
        PlayerControl.PlayerControl(curPlayer).RefreshPlayerAttrState()
    #返还多余魂尘
    if totalPoint > 0:
        PlayerControl.GiveMoney(curPlayer, ShareDefine.TYPE_Price_SoulDust, totalPoint)
    #给新物品
    curItem = ItemControler.GetOutPutItemObj(tagItemID)
    curItem.SetUserAttr(ShareDefine.Def_IudetGatherSoulLV, tagItemLV)
    PlayerItemControler = ItemControler.PlayerItemControler(curPlayer)
    PlayerItemControler.PutInItem(ShareDefine.rptGatherSoul, curItem, event=[ChConfig.ItemGive_ItemCompound, False, {'indexList1':indexList1, 'indexList2':indexList2, 'soulDust':totalPoint}])
    curPlayer.Sync_MakeItemAnswer(ShareDefine.Def_mitGatherSoulCompound, 1)
    return
def RefreshGatherSoulAttr(curPlayer):
    allAttrList = [{} for _ in range(4)]
    GatherSoulUnlockDict = IpyGameDataPY.GetFuncEvalCfg("GatherSoulHole", 1, {})
    maxGatherSoulHole = len(GatherSoulUnlockDict)
    for holeNum in xrange(maxGatherSoulHole):
        GatherSoulData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_GatherSoulHoleData % holeNum, 0)
        if not GatherSoulData:
            continue
        GatherSoulItemID = ItemControler.GetGatherSoulItemID(GatherSoulData)
        GatherSoulItemPlusLV = ItemControler.GetGatherSoulItemPlusLV(GatherSoulData)
        attrDict = GetGatherSoulAttrValue(GatherSoulItemID, GatherSoulItemPlusLV)
        if not attrDict:
            continue
        GameWorld.DebugLog('    刷聚魂属性 holeNum=%s, attrDict=%s' % (holeNum, attrDict))
        for attrID, attrValue in attrDict.items():
            PlayerControl.CalcAttrDict_Type(attrID, attrValue, allAttrList)
    # 保存计算值
    PlayerControl.SetCalcAttrListValue(curPlayer, ChConfig.Def_CalcAttrFunc_GatherSoul, allAttrList)
    return
def Sync_GatherSoulHoleInfo(curPlayer):
    ##通知聚魂孔信息
    GatherSoulUnlockDict = IpyGameDataPY.GetFuncEvalCfg("GatherSoulHole", 1, {})
    maxGatherSoulHole = len(GatherSoulUnlockDict)
    GatherSoulInfoPack = ChPyNetSendPack.tagMCGatherSoulHoleInfo()
    GatherSoulInfoPack.Clear()
    GatherSoulInfoPack.GatherSoulDataList = []
    for GatherSoulNum in xrange(maxGatherSoulHole):
        GatherSoulData = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_GatherSoulHoleData % GatherSoulNum, 0)
        GatherSoulInfoPack.GatherSoulDataList.append(GatherSoulData)
    GatherSoulInfoPack.Count = len(GatherSoulInfoPack.GatherSoulDataList)
    NetPackCommon.SendFakePack(curPlayer, GatherSoulInfoPack)
    return
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/PyGameData.py
@@ -78,3 +78,5 @@
g_fightpowerChangeDataRecordDict = {} #导致战力降低的各种行为记录
g_fbRobotJobDict = {} #副本机器人职业  {lineID:{objID:job, ...}, ...}
g_gathersoulfbAwardDict = {} #聚魂副本奖励记录{playerID:[[itemID,itemCnt]]}
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py
@@ -312,7 +312,8 @@
    Def_mitRecycleAttrFruit,  # 回收魂石
    Def_mitDogzEquipPlus,     # 神兽装备强化
    Def_mitRuneCompound,      # 符印合成
) = range(1, 23)
    Def_mitGatherSoulCompound,# 聚魂合成
) = range(1, 24)
#---写死的技能ID---
Def_SkillID_AutoTruck = 62220   # 自动运镖buff
@@ -786,7 +787,10 @@
CDBPlayerRefresh_GodWeaponLV_2,         # 神兵等级 - 类型2 193
CDBPlayerRefresh_GodWeaponLV_3,         # 神兵等级 - 类型3 194
CDBPlayerRefresh_GodWeaponLV_4,         # 神兵等级 - 类型4 195
) = range(146, 196)
CDBPlayerRefresh_SoulDust,              # 魂尘 196
CDBPlayerRefresh_SoulSplinters,         # 聚魂碎片 197
CDBPlayerRefresh_SoulCore,              # 核心环 198
) = range(146, 199)
TYPE_Price_Gold_Paper_Money = 5    # 金钱类型,(先用礼券,再用金子)
TYPE_Price_Family_Contribution = 6 # 战盟贡献度(活跃度转换得来)
@@ -801,6 +805,9 @@
TYPE_Price_TreasureScore = 25    # 寻宝积分
TYPE_Price_BourseMoney = 26    # 交易所可购买额度
TYPE_Price_Danjing = 27    # 丹精(丹药回收)
TYPE_Price_SoulDust = 28    # 魂尘
TYPE_Price_SoulSplinters = 29    # 聚魂碎片
TYPE_Price_SoulCore = 30    # 核心环
#以下是旧的金钱类型
@@ -828,6 +835,9 @@
                           TYPE_Price_FamilyActivity:CDBPlayerRefresh_FamilyActivity,
                           TYPE_Price_XianyuanCoin:CDBPlayerRefresh_Xianyuancoin,
                           TYPE_Price_Danjing:CDBPlayerRefresh_Danjing,
                           TYPE_Price_SoulDust:CDBPlayerRefresh_SoulDust,
                           TYPE_Price_SoulSplinters:CDBPlayerRefresh_SoulSplinters,
                           TYPE_Price_SoulCore:CDBPlayerRefresh_SoulCore,
                           }
# 高效战斗状态
@@ -925,8 +935,9 @@
#虚拟背包类型, 从255递减
Def_VPack_TypeList = (
rptGatherSoul,      # 聚魂背包 254
rptRune,            # 符印背包 255
) = range(256 - 1, 256)
) = range(256 - 2, 256)
#武器的手持形式
@@ -1266,7 +1277,7 @@
Def_IudetRuneSource = 40  # 符印来源 老号0,默认1,合成2(主要用来区分是否合成获得)
Def_IudetWingProgressValue = 42 #羽翼精炼值
Def_IudetCreateTime = 44 # 时效物品的创建时间
Def_IudetGatherSoulLV = 46  # 聚魂等级
# 200~300 宠物数据用
Def_IudetPet_NPCID = 200  # npcID
Def_IudetPet_ClassLV = 202  # 阶级
@@ -1330,7 +1341,7 @@
)=range(5)
# 战斗力模块类型
Def_MFPType_Max = 25
Def_MFPType_Max = 26
ModuleFightPowerTypeList = (
Def_MFPType_Role, # 角色 0
Def_MFPType_Equip, # 装备(基本装备位) 1
@@ -1354,6 +1365,7 @@
Def_MFPType_HorseSoul, # 坐骑魂石 19
Def_MFPType_MagicWeaponSoul, # 法宝之魂 20
Def_MFPType_Dogz, # 神兽 21
Def_MFPType_GatherSoul, # 聚魂 22
Def_MFPType_Other, # 其他
#以下暂时没用到,改时再处理