From 2e0dbebc2b1e2dbfea405ac4674c7c50bd92b73d Mon Sep 17 00:00:00 2001 From: hxp <ale99527@vip.qq.com> Date: 星期五, 08 十一月 2024 13:56:48 +0800 Subject: [PATCH] 10289 【越南】【英语】【砍树】【tqxbqy】运势-服务端 --- ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldActionControl.py | 145 +++++- ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py | 33 + ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py | 53 ++ ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py | 5 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py | 193 ++++++++ ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTreasure.py | 258 +++++++---- ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/SetXunbao.py | 21 ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py | 193 ++++++++ ServerPython/CoreServerGroup/GameServer/Script/GameWorld.py | 31 + ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActYunshi.py | 115 +++++ ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py | 94 +++ ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py | 6 PySysDB/PySysDBPY.h | 26 + ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorld.py | 31 + ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py | 5 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py | 4 PySysDB/PySysDBG.h | 13 ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py | 10 18 files changed, 1,048 insertions(+), 188 deletions(-) diff --git a/PySysDB/PySysDBG.h b/PySysDB/PySysDBG.h index 3efb7fa..23311ec 100644 --- a/PySysDB/PySysDBG.h +++ b/PySysDB/PySysDBG.h @@ -1179,6 +1179,19 @@ WORD LVLimit; //限制等级 }; +//运势活动时间表 + +struct tagActYunshi +{ + DWORD _CfgID; //配置ID + list PlatformList; //活动平台列表["平台A", "平台A", ...],配[]代表所有 + list ServerGroupIDList; //服务器ID列表 + BYTE ActNum; //活动分组编号, 活动类型 * 10 + 不同界面编号 + char StartDate; //开启日期 + char EndDate; //结束日期 + BYTE ResetType; //重置类型,0-0点重置;1-5点重置 +}; + //购买次数礼包活动时间表 struct tagActBuyCountGift diff --git a/PySysDB/PySysDBPY.h b/PySysDB/PySysDBPY.h index 9b8ef4f..823074e 100644 --- a/PySysDB/PySysDBPY.h +++ b/PySysDB/PySysDBPY.h @@ -1696,8 +1696,11 @@ { BYTE _TreasureType; //寻宝类型 BYTE PackType; //放入背包 + BYTE CheckPack; //是否检查背包 + BYTE IsActType; //是否活动寻宝 BYTE DailyFreeCount; //每日免费次数 list TreasureCountList; //抽奖次数列表 + char RecycleItemMail; //重置回收道具邮件,如果有配置回收邮件key,则重置时会回收多余的寻宝道具 DWORD CostItemID; //消耗道具ID list CostItemCountList; //消耗个数列表 BYTE CostMoneyType; //消耗货币类型 @@ -1707,6 +1710,7 @@ WORD FullLucky; //满幸运值 char LuckyRateFormat; //幸运格子概率公式 BYTE LuckyGridNum; //幸运格子编号 + dict GridNumMaxLimitInfo; //格子最大产出次数限制,{"格子":最大可产出次数, ...} list NotifyGridNumList; //需要额外广播的格子 BYTE AwardMoneyType; //额外奖励货币类型 WORD AwardMoneyValue; //单次奖励货币数 @@ -1736,6 +1740,16 @@ DWORD ItemID; //物品ID DWORD ItemCount; //物品个数 DWORD ItemWeight; //物品权重 +}; + +//寻宝累计次数奖励表 + +struct tagTreasureCntAward +{ + BYTE _TreasureType; //寻宝类型 + DWORD _NeedTreasureCnt; //所需寻宝次数 + BYTE AwardIndex; //奖励记录索引 0~30 + list AwardItemList; //奖励物品信息列表 [[物品ID,个数,是否拍品],...] }; //极品白拿表 @@ -2648,6 +2662,18 @@ WORD Point; //积分 }; +//运势活动时间表 + +struct tagActYunshi +{ + DWORD _CfgID; //配置ID + char StartDate; //开启日期 + char EndDate; //结束日期 + WORD LVLimit; //限制等级 + BYTE ResetType; //重置类型,0-0点重置;1-5点重置 + DWORD TreasureType; //商城类型 +}; + //购买次数礼包活动时间表 struct tagActBuyCountGift diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py b/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py index 0d1a270..e31fbc4 100644 --- a/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py +++ b/ServerPython/CoreServerGroup/GameServer/Script/ChPyNetSendPack.py @@ -28879,13 +28879,11 @@ #------------------------------------------------------ # A3 51 寻宝功能信息 #tagMCTreasureInfo -class tagMCTreasureTypeInfo(Structure): +class tagMCTreasureGridLimit(Structure): _pack_ = 1 _fields_ = [ - ("TreasureType", c_ubyte), #寻宝类型 - ("LuckValue", c_ushort), #当前幸运值 - ("TreasureCount", c_int), #已寻宝总次数 - ("FreeCountToday", c_ushort), #今日已免费寻宝次数 + ("GridNum", c_ubyte), # 有限制抽取次数的格子编号 + ("GridCnt", c_ushort), # 已抽到次数 ] def __init__(self): @@ -28898,30 +28896,109 @@ return _pos + self.GetLength() def Clear(self): - self.TreasureType = 0 - self.LuckValue = 0 - self.TreasureCount = 0 - self.FreeCountToday = 0 + self.GridNum = 0 + self.GridCnt = 0 return def GetLength(self): - return sizeof(tagMCTreasureTypeInfo) + return sizeof(tagMCTreasureGridLimit) def GetBuffer(self): return string_at(addressof(self), self.GetLength()) def OutputString(self): DumpString = '''// A3 51 寻宝功能信息 //tagMCTreasureInfo: + GridNum:%d, + GridCnt:%d + '''\ + %( + self.GridNum, + self.GridCnt + ) + return DumpString + + +class tagMCTreasureTypeInfo(Structure): + TreasureType = 0 #(BYTE TreasureType)//寻宝类型 + LuckValue = 0 #(WORD LuckValue)//当前幸运值 + TreasureCount = 0 #(DWORD TreasureCount)//已寻宝总次数 + FreeCountToday = 0 #(WORD FreeCountToday)//今日已免费寻宝次数 + TreasureCntAward = 0 #(DWORD TreasureCntAward)//累计寻宝次数对应奖励领奖状态,按奖励记录索引二进制记录是否已领取 + GridLimitCnt = 0 #(BYTE GridLimitCnt) + GridLimitCntList = list() #(vector<tagMCTreasureGridLimit> GridLimitCntList)//有限制抽取次数的格子次数信息 + data = None + + def __init__(self): + self.Clear() + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + self.TreasureType,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.LuckValue,_pos = CommFunc.ReadWORD(_lpData, _pos) + self.TreasureCount,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.FreeCountToday,_pos = CommFunc.ReadWORD(_lpData, _pos) + self.TreasureCntAward,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.GridLimitCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.GridLimitCnt): + temGridLimitCntList = tagMCTreasureGridLimit() + _pos = temGridLimitCntList.ReadData(_lpData, _pos) + self.GridLimitCntList.append(temGridLimitCntList) + return _pos + + def Clear(self): + self.TreasureType = 0 + self.LuckValue = 0 + self.TreasureCount = 0 + self.FreeCountToday = 0 + self.TreasureCntAward = 0 + self.GridLimitCnt = 0 + self.GridLimitCntList = list() + return + + def GetLength(self): + length = 0 + length += 1 + length += 2 + length += 4 + length += 2 + length += 4 + length += 1 + for i in range(self.GridLimitCnt): + length += self.GridLimitCntList[i].GetLength() + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteBYTE(data, self.TreasureType) + data = CommFunc.WriteWORD(data, self.LuckValue) + data = CommFunc.WriteDWORD(data, self.TreasureCount) + data = CommFunc.WriteWORD(data, self.FreeCountToday) + data = CommFunc.WriteDWORD(data, self.TreasureCntAward) + data = CommFunc.WriteBYTE(data, self.GridLimitCnt) + for i in range(self.GridLimitCnt): + data = CommFunc.WriteString(data, self.GridLimitCntList[i].GetLength(), self.GridLimitCntList[i].GetBuffer()) + return data + + def OutputString(self): + DumpString = ''' TreasureType:%d, LuckValue:%d, TreasureCount:%d, - FreeCountToday:%d + FreeCountToday:%d, + TreasureCntAward:%d, + GridLimitCnt:%d, + GridLimitCntList:%s '''\ %( self.TreasureType, self.LuckValue, self.TreasureCount, - self.FreeCountToday + self.FreeCountToday, + self.TreasureCntAward, + self.GridLimitCnt, + "..." ) return DumpString @@ -41595,6 +41672,98 @@ #------------------------------------------------------ +# AA 87 运势活动信息 #tagMCActYunshiInfo + +class tagMCActYunshiInfo(Structure): + Head = tagHead() + ActNum = 0 #(BYTE ActNum)// 活动编号 + StartDate = "" #(char StartDate[10])// 开始日期 y-m-d + EndtDate = "" #(char EndtDate[10])// 结束日期 y-m-d + ResetType = 0 #(BYTE ResetType)// 重置类型,0-0点重置;1-5点重置 + LimitLV = 0 #(WORD LimitLV)// 限制等级 + TreasureType = 0 #(BYTE TreasureType)// 活动寻宝类型 + data = None + + def __init__(self): + self.Clear() + self.Head.Cmd = 0xAA + self.Head.SubCmd = 0x87 + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + _pos = self.Head.ReadData(_lpData, _pos) + self.ActNum,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.StartDate,_pos = CommFunc.ReadString(_lpData, _pos,10) + self.EndtDate,_pos = CommFunc.ReadString(_lpData, _pos,10) + self.ResetType,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.LimitLV,_pos = CommFunc.ReadWORD(_lpData, _pos) + self.TreasureType,_pos = CommFunc.ReadBYTE(_lpData, _pos) + return _pos + + def Clear(self): + self.Head = tagHead() + self.Head.Clear() + self.Head.Cmd = 0xAA + self.Head.SubCmd = 0x87 + self.ActNum = 0 + self.StartDate = "" + self.EndtDate = "" + self.ResetType = 0 + self.LimitLV = 0 + self.TreasureType = 0 + return + + def GetLength(self): + length = 0 + length += self.Head.GetLength() + length += 1 + length += 10 + length += 10 + length += 1 + length += 2 + length += 1 + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer()) + data = CommFunc.WriteBYTE(data, self.ActNum) + data = CommFunc.WriteString(data, 10, self.StartDate) + data = CommFunc.WriteString(data, 10, self.EndtDate) + data = CommFunc.WriteBYTE(data, self.ResetType) + data = CommFunc.WriteWORD(data, self.LimitLV) + data = CommFunc.WriteBYTE(data, self.TreasureType) + return data + + def OutputString(self): + DumpString = ''' + Head:%s, + ActNum:%d, + StartDate:%s, + EndtDate:%s, + ResetType:%d, + LimitLV:%d, + TreasureType:%d + '''\ + %( + self.Head.OutputString(), + self.ActNum, + self.StartDate, + self.EndtDate, + self.ResetType, + self.LimitLV, + self.TreasureType + ) + return DumpString + + +m_NAtagMCActYunshiInfo=tagMCActYunshiInfo() +ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCActYunshiInfo.Head.Cmd,m_NAtagMCActYunshiInfo.Head.SubCmd))] = m_NAtagMCActYunshiInfo + + +#------------------------------------------------------ # AA 15 仙界盛典全民来嗨玩家信息 #tagMCAllPeoplePartyInfo class tagMCAllPeoplePartyCount(Structure): diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorld.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorld.py index c287f47..3edd9c9 100644 --- a/ServerPython/CoreServerGroup/GameServer/Script/GameWorld.py +++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorld.py @@ -599,6 +599,30 @@ templateID = templateIDList[-1] if dayIndex >= len(templateIDList) else templateIDList[dayIndex] return templateID +def GetOperationActionLoopDate(startDateStr, endDateStr, curDateTime): + ## 获取运营活动配置日期循环的具体活动时间 + # @return: 开始日期, 结束日期, 返回的日期是第x次循环 + startSplitList = startDateStr.split("_") + loopDays = int(startSplitList[0][1:]) + startLoopDateStr = startSplitList[1] + startLoopDateTime = ChangeStrToDatetime(startLoopDateStr, ChConfig.TYPE_Time_YmdFormat) + + endSplitList = endDateStr.split("_") # 可不配Lx_开头,防误配,做兼容 + endLoopDateStr = endSplitList[0] if len(endSplitList) == 1 else endSplitList[1] + endLoopDateTime = ChangeStrToDatetime(endLoopDateStr, ChConfig.TYPE_Time_YmdFormat) + + if curDateTime >= startLoopDateTime: + passDays = (curDateTime - startLoopDateTime).days + loopTimes = passDays / loopDays + 1 # 第x次循环 + loopTimeMax = (endLoopDateTime - startLoopDateTime).days / loopDays + 1 # 最大循环次数 + loopTimes = min(loopTimes, loopTimeMax) + else: + loopTimes = 1 # 还未开始取第一次 + + startDateTime = startLoopDateTime + datetime.timedelta((loopTimes - 1)*loopDays) + endDateTime = startDateTime + datetime.timedelta(days=(loopDays - 1)) + return startDateTime, endDateTime, loopTimes + def GetOperationActionDateStr(ipyData): ## 获取运营活动对应日期,存数字代表开服天配置,需要转化为对应的日期 curDateTime = datetime.datetime.today() @@ -610,7 +634,7 @@ endDateStr = "%d-%d-%d" % (curDateTime.year, curDateTime.month, curDateTime.day) # 日期直接返回 - if startDateStr.count("-") == 2 and "W" not in startDateStr: + if startDateStr.count("-") == 2 and "W" not in startDateStr and not startDateStr.startswith("L"): return startDateStr, endDateStr # 开服天 @@ -657,7 +681,10 @@ # 只配置结束日期的时候可能导致开始日期计算出来比结束日期还大,即当前时间超过结束日期,且 配置还存在的情况 if startDateTime > endDateTime: startDateTime = endDateTime # 反正都无法开启,随便给个日期,不超过结束日期即可 - + # 按日期循环 + elif startDateStr.startswith("L"): + startDateTime, endDateTime, _ = GetOperationActionLoopDate(startDateStr, endDateStr, curDateTime) + # 默认 else: startDateTime = curDateTime diff --git a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldActionControl.py b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldActionControl.py index 876a37b..bf08925 100644 --- a/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldActionControl.py +++ b/ServerPython/CoreServerGroup/GameServer/Script/GameWorldLogic/GameWorldActionControl.py @@ -247,8 +247,9 @@ GameWorld.Log("加载运营活动: actName=%s,platform=%s,serverGroupID=%s" % (actName, platform, serverGroupID)) curServerActIpyDataList = __GetOperationActionServerIpyDataList(ipyDataMgr, platform, serverGroupID, actName) GameWorld.Log(" 可处理条数=%s" % (len(curServerActIpyDataList))) - actNumDisableWeekIpyDataInfo, disableWeekCfgIDDict = __GetOperationActionDisableWeekIpyDataInfo(actName, curDateTime, curServerActIpyDataList) - + coverDisableLoopIpyDataInfo, disableLoopCfgIDDict, otherLoopCfgIDDict, coverDisableWeekIpyDataInfo, disableWeekCfgIDDict = \ + __GetOperationActionDisableIpyDataInfo(actName, curDateTime, curServerActIpyDataList) + for ipyData in curServerActIpyDataList: platformList = [] if not hasattr(ipyData, "GetPlatformList") else ipyData.GetPlatformList() @@ -280,10 +281,30 @@ endDateStr = "%d-%d-%d" % (serverTime.year, serverTime.month, serverTime.day) GameWorld.Log(" 结束日期为空,默认每天,今日为: endDateStr=%s" % endDateStr) - # 开服常规: 开服天 > 日期 > 周x (不受合服天影响,合服活动新增一套独立的活动,还是走运营活动配置) + actByLoopYmd = startDateStr.startswith("L") # 按日期循环 + # 根据日期循环的通用 + if actByLoopYmd: + if cfgID in coverDisableLoopIpyDataInfo: + loopStartDate, loopEndDate, ymdCfgID, ymdStartDate, ymdEndDate = coverDisableLoopIpyDataInfo[cfgID] + GameWorld.Log(" 按日期循环的在按日期开启的时间内,不处理! cfgID=%s,%s(%s) ~ %s(%s) in ymdCfgID=%s,%s ~ %s" + % (cfgID, loopStartDate, startDateStr, loopEndDate, endDateStr, ymdCfgID, ymdStartDate, ymdEndDate)) + continue + + if cfgID in disableLoopCfgIDDict: + GameWorld.Log(" 按日期循环的未到开启循环日期或已结束循环日期,不处理! cfgID=%s,startDateStr=%s,endDateStr=%s" % (cfgID, startDateStr, endDateStr)) + continue + + if cfgID in otherLoopCfgIDDict: + loopCfgIDList, startDateStr, endDateStr, loopIndex, loopTimes = otherLoopCfgIDDict[cfgID] + GameWorld.Log(" 按日期循环的还未循环到当前配置,不处理! cfgID=%s,startDateStr=%s,endDateStr=%s,loopCfgIDList=%s,loopIndex=%s,loopTimes=%s" + % (cfgID, startDateStr, endDateStr, loopCfgIDList, loopIndex, loopTimes)) + continue + startDateStr, endDateStr = GameWorld.GetOperationActionDateStr(ipyData) + + # 开服常规: 开服天 > 日期 > 周x=日期循环 (不受合服天影响,合服活动新增一套独立的活动,还是走运营活动配置) if actType == ShareDefine.ActType_OpenComm: actByWeek = (startDateStr.startswith("W") and endDateStr.startswith("W")) # 按周x开 - actByDate = (not actByWeek and startDateStr.count("-") == 2 and endDateStr.count("-") == 2) # 按日期开 + actByDate = (not actByLoopYmd and not actByWeek and startDateStr.count("-") == 2 and endDateStr.count("-") == 2) # 按日期开 # 开服天的 if startDateStr.isdigit() and endDateStr.isdigit(): @@ -299,21 +320,20 @@ GameWorld.Log(" 开服天转化为日期: %s ~ %s" % (startDateStr, endDateStr)) # 常规配置: 开服前X天不开,不受合服影响,功能配置表可配置 开服前X天后交叉可开,每日重置的活动默认可开 - elif actByWeek or actByDate: + elif actByWeek or actByDate or actByLoopYmd: if openServerDay <= customMaxServerDay: GameWorld.Log(" 按日期/周开的在开服定制限制天内,不处理! cfgID=%s,%s ~ %s,openServerDay=%s" % (cfgID, startDateStr, endDateStr, openServerDay)) continue - disableWeekIpyDataInfo = actNumDisableWeekIpyDataInfo.get(actNum, {}) - if cfgID in disableWeekIpyDataInfo: - startWeekDate, endWeekDate, ymdCfgID, ymdStartDate, ymdEndDate = disableWeekIpyDataInfo[cfgID] + if cfgID in coverDisableWeekIpyDataInfo: + startWeekDate, endWeekDate, ymdCfgID, ymdStartDate, ymdEndDate = coverDisableWeekIpyDataInfo[cfgID] GameWorld.Log(" 常规活动,按星期开启的在按日期开启的时间内,不处理! cfgID=%s,%s(%s) ~ %s(%s) in ymdCfgID=%s,%s ~ %s" % (cfgID, startWeekDate, startDateStr, endWeekDate, endDateStr, ymdCfgID, ymdStartDate, ymdEndDate)) continue if cfgID in disableWeekCfgIDDict: GameWorld.Log(" 常规活动,按星期开启的未到开启循环日期或已结束循环日期,不处理! cfgID=%s,startDateStr=%s,endDateStr=%s, %s" - % (cfgID, startDateStr, endDateStr, disableWeekCfgIDDict[cfgID])) + % (cfgID, startDateStr, endDateStr, str(disableWeekCfgIDDict[cfgID]))) continue if actByWeek: @@ -653,11 +673,16 @@ return curServerActIpyDataList -def __GetOperationActionDisableWeekIpyDataInfo(actName, curDateTime, curServerActIpyDataList): +def __GetOperationActionDisableIpyDataInfo(actName, curDateTime, curServerActIpyDataList): ## 获取不可用的按星期X开启的配置数据信息,按星期X开启的 活动优先级小于按日期的,当有重叠时以日期的为准 - #curWeekday = curDateTime.weekday() + 1 # 今天星期几, 1代表星期1 - actNumWeekYMDIpyDataInfo = {} # {actNum:[weekIpyDataList, ymdIpyDatList], ...} - disableWeekCfgIDDict = {} # {cfgID:[startDateStr, endDateStr], ...} + # 优先级 日期 > 按日期循环 > 按星期循环 + + actNumYMDIpyDataInfo = {} # {actNum:ymdIpyDataList, ...} # 配置日期的 + actNumLoopIpyDataInfo = {} # {actNum:{loopKey:[loopCfgIDList, loopDateInfo]}, ...} # 按日期循环的 + actNumWeekIpyDataInfo = {} # {actNum:weekIpyDataList, ...} # 按星期循环的 + + disableWeekCfgIDDict = {} # {cfgID:[startDateStr, endDateStr], ...} # 未开始循环的星期 + disableLoopCfgIDDict = {} # {cfgID:[startDateStr, endDateStr], ...} # 未开始循环的日期 curDateTimeYmdStr = "%d-%d-%d" % (curDateTime.year, curDateTime.month, curDateTime.day) curDateTimeYmd = GameWorld.ChangeStrToDatetime(curDateTimeYmdStr, ChConfig.TYPE_Time_YmdFormat) @@ -667,50 +692,90 @@ startDateStr = ipyData.GetStartDate() endDateStr = ipyData.GetEndDate() actNum = GetOperationActNum(actName, ipyData) - actType = GetOperationActType(actNum) - # 这里只处理常规运营活动,日期优先级大于周 - if actType != ShareDefine.ActType_OpenComm: - continue - - if actNum not in actNumWeekYMDIpyDataInfo: - weekIpyDataList, ymdIpyDatList = [], [] - actNumWeekYMDIpyDataInfo[actNum] = [weekIpyDataList, ymdIpyDatList] - weekIpyDataList, ymdIpyDatList = actNumWeekYMDIpyDataInfo[actNum] # 按星期X的 if startDateStr.startswith("W"): + if actNum not in actNumWeekIpyDataInfo: + actNumWeekIpyDataInfo[actNum] = [] + weekIpyDataList = actNumWeekIpyDataInfo[actNum] startDateStr, endDateStr = GameWorld.GetOperationActionDateStr(ipyData) startWeekDate = GameWorld.ChangeStrToDatetime(startDateStr, ChConfig.TYPE_Time_YmdFormat) endWeekDate = GameWorld.ChangeStrToDatetime(endDateStr, ChConfig.TYPE_Time_YmdFormat) if startWeekDate > curDateTimeYmd or curDateTimeYmd > endWeekDate: # 还未开始的循环 or 已经强制结束的循环 disableWeekCfgIDDict[cfgID] = [startDateStr, endDateStr] else: - weekIpyDataList.append([ipyData, startWeekDate, endWeekDate]) + weekIpyDataList.append([cfgID, startWeekDate, endWeekDate]) + # 按日期循环 + elif startDateStr.startswith("L"): + loopStartDate, loopEndDate, loopTimes = GameWorld.GetOperationActionLoopDate(startDateStr, endDateStr, curDateTime) + if loopStartDate > curDateTimeYmd or curDateTimeYmd > loopEndDate: # 还未开始的循环 or 已经强制结束的循环 + disableLoopCfgIDDict[cfgID] = [startDateStr, endDateStr] + else: + loopKey = (startDateStr, endDateStr) # 同个循环周期的视为同一组 + if actNum not in actNumLoopIpyDataInfo: + actNumLoopIpyDataInfo[actNum] = {} + loopIpyDataDict = actNumLoopIpyDataInfo[actNum] + if loopKey not in loopIpyDataDict: + loopCfgIDList, loopDateInfo = [], [loopStartDate, loopEndDate, loopTimes] + loopIpyDataDict[loopKey] = [loopCfgIDList, loopDateInfo] + loopCfgIDList, loopDateInfo = loopIpyDataDict[loopKey] + loopCfgIDList.append(cfgID) + # 按日期的 elif startDateStr.count("-") == 2: - ymdIpyData = ipyData - ymdStartDate = datetime.datetime.strptime("%s %02d:%02d:00" % (startDateStr, curDateTime.hour, curDateTime.minute), ChConfig.TYPE_Time_Format) - ymdEndDate = datetime.datetime.strptime("%s %02d:%02d:00" % (endDateStr, curDateTime.hour, curDateTime.minute), ChConfig.TYPE_Time_Format) - ymdIpyDatList.append([ymdIpyData, ymdStartDate, ymdEndDate]) + if actNum not in actNumYMDIpyDataInfo: + actNumYMDIpyDataInfo[actNum] = [] + ymdIpyDataList = actNumYMDIpyDataInfo[actNum] + ymdStartDate = GameWorld.ChangeStrToDatetime(startDateStr, ChConfig.TYPE_Time_YmdFormat) + ymdEndDate = GameWorld.ChangeStrToDatetime(endDateStr, ChConfig.TYPE_Time_YmdFormat) + ymdIpyDataList.append([cfgID, ymdStartDate, ymdEndDate]) else: - # 只处理按星期、按日期的,其他的不处理 + # 其他的不处理 pass - actNumDisableWeekIpyDataInfo = {} # {actNum:{cfgID:[info], ...}, ...} - for actNum, weekYMDIpyDataInfo in actNumWeekYMDIpyDataInfo.items(): - weekIpyDataList, ymdIpyDatList = weekYMDIpyDataInfo - for ipyData, startWeekDate, endWeekDate in weekIpyDataList: - cfgID = ipyData.GetCfgID() - for ymdIpyData, ymdStartDate, ymdEndDate in ymdIpyDatList: - if ymdStartDate <= startWeekDate <= ymdEndDate or ymdStartDate <= endWeekDate <= ymdEndDate: - if actNum not in actNumDisableWeekIpyDataInfo: - actNumDisableWeekIpyDataInfo[actNum] = {} - ymdCfgID = ymdIpyData.GetCfgID() - actNumDisableWeekIpyDataInfo[actNum][cfgID] = [startWeekDate, endWeekDate, ymdCfgID, ymdStartDate, ymdEndDate] + nowLoopYMDIpyDataInfo = {} # {actNum:loopIpyDataList, ...} # # 日期循环中当前在循环的 + otherLoopCfgIDDict = {} # {cfgID:[info], ...} # 日期循环中不是当前循环的其他循环 + coverDisableLoopIpyDataInfo = {} # {cfgID:[info], ...} # 被日期覆盖的日期循环 + for actNum, loopIpyDataDict in actNumLoopIpyDataInfo.items(): + ymdIpyDataList = actNumYMDIpyDataInfo.get(actNum, []) + if actNum not in nowLoopYMDIpyDataInfo: + nowLoopYMDIpyDataInfo[actNum] = [] + loopIpyDataList = nowLoopYMDIpyDataInfo[actNum] + for loopKey, loopInfo in loopIpyDataDict.items(): + startDateStr, endDateStr = loopKey + loopCfgIDList, loopDateInfo = loopInfo + loopStartDate, loopEndDate, loopTimes = loopDateInfo + loopIndex = (loopTimes - 1) % len(loopCfgIDList) # 当前循环次数对应的循环索引 + curLoopCfgID = 0 + for index, loopCfgID in enumerate(loopCfgIDList): + if index == loopIndex: # 当前循环的 + curLoopCfgID = loopCfgID + loopIpyDataList.append([loopCfgID, loopStartDate, loopEndDate]) + else: + otherLoopCfgIDDict[loopCfgID] = [loopCfgIDList, startDateStr, endDateStr, loopIndex, loopTimes] - return actNumDisableWeekIpyDataInfo, disableWeekCfgIDDict + for ymdCfgID, ymdStartDate, ymdEndDate in ymdIpyDataList: + if ymdStartDate <= loopStartDate <= ymdEndDate or ymdStartDate <= loopEndDate <= ymdEndDate: + coverDisableLoopIpyDataInfo[curLoopCfgID] = [loopStartDate, loopEndDate, ymdCfgID, ymdStartDate, ymdEndDate] + + coverDisableWeekIpyDataInfo = {} # {cfgID:[info], ...} # 被日期覆盖的星期循环 + for actNum, weekIpyDataList in actNumWeekIpyDataInfo.items(): + ymdIpyDataList = actNumYMDIpyDataInfo.get(actNum, []) + loopIpyDatList = nowLoopYMDIpyDataInfo.get(actNum, []) + for weekCfgID, startWeekDate, endWeekDate in weekIpyDataList: + # 被常规日期覆盖的 + for ymdCfgID, ymdStartDate, ymdEndDate in ymdIpyDataList: + if ymdStartDate <= startWeekDate <= ymdEndDate or ymdStartDate <= endWeekDate <= ymdEndDate: + coverDisableWeekIpyDataInfo[weekCfgID] = [startWeekDate, endWeekDate, ymdCfgID, ymdStartDate, ymdEndDate] + + # 被循环日期覆盖的 + for loopCfgID, loopStartDate, loopEndDate in loopIpyDatList: + if loopStartDate <= startWeekDate <= loopEndDate or loopStartDate <= endWeekDate <= loopEndDate: + coverDisableWeekIpyDataInfo[weekCfgID] = [startWeekDate, endWeekDate, loopCfgID, loopStartDate, loopEndDate] + + return coverDisableLoopIpyDataInfo, disableLoopCfgIDDict, otherLoopCfgIDDict, coverDisableWeekIpyDataInfo, disableWeekCfgIDDict def Dispose_OperationActionState(reloadRefresh=False): # 运营活动状态处理, 每天0点会强制同步当天的运营活动详情到地图服务器 diff --git a/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py b/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py index ff942d5..7e446ed 100644 --- a/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py +++ b/ServerPython/CoreServerGroup/GameServer/Script/IpyGameDataPY.py @@ -948,6 +948,16 @@ ("WORD", "LVLimit", 0), ), + "ActYunshi":( + ("DWORD", "CfgID", 1), + ("list", "PlatformList", 0), + ("list", "ServerGroupIDList", 0), + ("BYTE", "ActNum", 0), + ("char", "StartDate", 0), + ("char", "EndDate", 0), + ("BYTE", "ResetType", 0), + ), + "ActBuyCountGift":( ("DWORD", "CfgID", 1), ("list", "PlatformList", 0), @@ -2550,6 +2560,21 @@ def GetNotifyInfoEnd(self): return self.attrTuple[10] # 全服提示信息 - 相对结束时间 dict def GetLVLimit(self): return self.attrTuple[11] # 限制等级 WORD +# 运势活动时间表 +class IPY_ActYunshi(): + + def __init__(self): + self.attrTuple = None + return + + def GetCfgID(self): return self.attrTuple[0] # 配置ID DWORD + def GetPlatformList(self): return self.attrTuple[1] # 活动平台列表["平台A", "平台A", ...],配[]代表所有 list + def GetServerGroupIDList(self): return self.attrTuple[2] # 服务器ID列表 list + def GetActNum(self): return self.attrTuple[3] # 活动分组编号, 活动类型 * 10 + 不同界面编号 BYTE + def GetStartDate(self): return self.attrTuple[4] # 开启日期 char + def GetEndDate(self): return self.attrTuple[5] # 结束日期 char + def GetResetType(self): return self.attrTuple[6] # 重置类型,0-0点重置;1-5点重置 BYTE + # 购买次数礼包活动时间表 class IPY_ActBuyCountGift(): @@ -3053,6 +3078,7 @@ self.__LoadFileData("CrossDemonLandZoneMap", onlyCheck) self.__LoadFileData("CrossFamilyFlagwarZoneMap", onlyCheck) self.__LoadFileData("ActWeekParty", onlyCheck) + self.__LoadFileData("ActYunshi", onlyCheck) self.__LoadFileData("ActBuyCountGift", onlyCheck) self.__LoadFileData("ActTask", onlyCheck) self.__LoadFileData("ActLoginNew", onlyCheck) @@ -3897,6 +3923,13 @@ self.CheckLoadData("ActWeekParty") return self.ipyActWeekPartyCache[index] + def GetActYunshiCount(self): + self.CheckLoadData("ActYunshi") + return self.ipyActYunshiLen + def GetActYunshiByIndex(self, index): + self.CheckLoadData("ActYunshi") + return self.ipyActYunshiCache[index] + def GetActBuyCountGiftCount(self): self.CheckLoadData("ActBuyCountGift") return self.ipyActBuyCountGiftLen diff --git a/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py b/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py index 0b8f31d..2cc0d68 100644 --- a/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py +++ b/ServerPython/CoreServerGroup/GameServer/Script/ShareDefine.py @@ -296,6 +296,7 @@ OperationActionName_FamilyCTGAssist = "ActFamilyCTGAssist" # 仙盟充值协助 OperationActionName_Gubao = "ActGubao" # 古宝养成活动 OperationActionName_HorsePetTrain = "ActHorsePetTrain" # 骑宠养成活动 +OperationActionName_Yunshi = "ActYunshi" # 运势活动 #节日活动类型列表 - 该类型无视开服天,日期到了就开启 FeastOperationActionNameList = [OperationActionName_FeastWeekParty, OperationActionName_FeastRedPacket, OperationActionName_RechargeRebateGold, OperationActionName_GrowupBuy, @@ -318,7 +319,7 @@ OperationActionName_BuyOne, OperationActionName_BossTrial, OperationActionName_ActLoginNew, OperationActionName_ActTask, OperationActionName_BuyCountGift, OperationActionName_FamilyCTGAssist, - OperationActionName_Gubao, OperationActionName_HorsePetTrain, + OperationActionName_Gubao, OperationActionName_HorsePetTrain, OperationActionName_Yunshi, ] + FeastOperationActionNameList #需要记录开启活动时的世界等级的运营活动 NeedWorldLVOperationActNameList = [OperationActionName_FairyCeremony, OperationActionName_WishingWell, @@ -345,7 +346,7 @@ OperationActionName_BuyOne, OperationActionName_BossTrial, OperationActionName_ActLoginNew, OperationActionName_ActTask, OperationActionName_BuyCountGift, OperationActionName_FamilyCTGAssist, - OperationActionName_Gubao, OperationActionName_HorsePetTrain, + OperationActionName_Gubao, OperationActionName_HorsePetTrain, OperationActionName_Yunshi, ] #跨服运营活动表名定义 diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py index 26483bd..9105b74 100644 --- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py +++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChConfig.py @@ -528,6 +528,7 @@ Def_Effect_Face = 274 #头像物品;A值-头像ID Def_Effect_FacePic = 275 #头像框物品;A值-头像框ID Def_Effect_EmojiPack = 276 #表情包物品;A值-表情包ID +Def_Effect_RecycleItemMoney = 277 #回收物品转化为货币; A值-直接给货币物品ID;B值-货币数量 #----以下未使用或代码依然存在的--- Def_Effect_ItemGiveGongXun = 1920 #使用道具给予功勋 Def_Effect_ItemGiveRuneJH = 1925 #使用道具给予符印精华 @@ -3676,6 +3677,8 @@ Def_PDict_TreasureFreeCount = "TreasureFreeCount_%s" # 寻宝今日已使用免费次数, 参数(寻宝类型) Def_PDict_TreasureCount = "TreasureCount_%s" # 寻宝次数, 参数(寻宝类型) Def_PDict_TreasureLuck = "TreasureLuck_%s" # 寻宝当前幸运值, 参数(寻宝类型) +Def_PDict_TreasureCntAward = "TreasureCntAward_%s" # 累计寻宝次数对应物品奖励领奖状态, 参数(寻宝类型) +Def_PDict_TreasureGridCnt = "TreasureGridCnt_%s_%s" # 格子对应累计产出次数, 参数(寻宝类型, 格子编号) Def_Player_Dict_LastAutoOpenPackTick = "LastAutoOpenPackTick219_%s" #上一次自动购买的tick<背包类型> @@ -4193,6 +4196,10 @@ Def_PDict_ActTaskValue = "ActTaskValue_%s_%s" # 任务活动当前任务进度值,参数:(活动编号, 任务类型) Def_PDict_ActTaskAward = "ActTaskAward_%s_%s" # 任务活动奖励记录,按位记录任务ID是否已领取,参数:(活动编号,key编号) Def_PDict_ActTaskRound = "ActTaskRound_%s" # 任务轮次,参数:(活动编号) + +#运势活动 +Def_PDict_ActYunshiID = "ActYunshiID_%s" # 玩家身上的活动ID,唯一标识,取活动开始日期time值,参数:(活动编号) +Def_PDict_ActYunshiTreasureType = "ActYunshiTreasureType_%s" # 活动寻宝类型,参数:(活动编号) #购买次数礼包活动 Def_PDict_BuyCountGiftID = "BuyCountGiftID_%s" # 玩家身上的活动ID,唯一标识,取活动开始日期time,参数(活动编号) @@ -6032,7 +6039,8 @@ Def_RewardType_FamilyCTGAssist, # 仙盟充值互助奖励 74 Def_RewardType_TiandaoTree, # 仙宫天道树奖励 75 Def_RewardType_OpenServerDailyAward, # 开服每日奖励 76 -)= range(77) +Def_RewardType_TreasureCntAward, # 寻宝累计次数奖励 77 +)= range(78) #boss复活相关活动定义 BossRebornActIDList = ( diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py index 0d1a270..e31fbc4 100644 --- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py +++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ChPyNetSendPack.py @@ -28879,13 +28879,11 @@ #------------------------------------------------------ # A3 51 寻宝功能信息 #tagMCTreasureInfo -class tagMCTreasureTypeInfo(Structure): +class tagMCTreasureGridLimit(Structure): _pack_ = 1 _fields_ = [ - ("TreasureType", c_ubyte), #寻宝类型 - ("LuckValue", c_ushort), #当前幸运值 - ("TreasureCount", c_int), #已寻宝总次数 - ("FreeCountToday", c_ushort), #今日已免费寻宝次数 + ("GridNum", c_ubyte), # 有限制抽取次数的格子编号 + ("GridCnt", c_ushort), # 已抽到次数 ] def __init__(self): @@ -28898,30 +28896,109 @@ return _pos + self.GetLength() def Clear(self): - self.TreasureType = 0 - self.LuckValue = 0 - self.TreasureCount = 0 - self.FreeCountToday = 0 + self.GridNum = 0 + self.GridCnt = 0 return def GetLength(self): - return sizeof(tagMCTreasureTypeInfo) + return sizeof(tagMCTreasureGridLimit) def GetBuffer(self): return string_at(addressof(self), self.GetLength()) def OutputString(self): DumpString = '''// A3 51 寻宝功能信息 //tagMCTreasureInfo: + GridNum:%d, + GridCnt:%d + '''\ + %( + self.GridNum, + self.GridCnt + ) + return DumpString + + +class tagMCTreasureTypeInfo(Structure): + TreasureType = 0 #(BYTE TreasureType)//寻宝类型 + LuckValue = 0 #(WORD LuckValue)//当前幸运值 + TreasureCount = 0 #(DWORD TreasureCount)//已寻宝总次数 + FreeCountToday = 0 #(WORD FreeCountToday)//今日已免费寻宝次数 + TreasureCntAward = 0 #(DWORD TreasureCntAward)//累计寻宝次数对应奖励领奖状态,按奖励记录索引二进制记录是否已领取 + GridLimitCnt = 0 #(BYTE GridLimitCnt) + GridLimitCntList = list() #(vector<tagMCTreasureGridLimit> GridLimitCntList)//有限制抽取次数的格子次数信息 + data = None + + def __init__(self): + self.Clear() + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + self.TreasureType,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.LuckValue,_pos = CommFunc.ReadWORD(_lpData, _pos) + self.TreasureCount,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.FreeCountToday,_pos = CommFunc.ReadWORD(_lpData, _pos) + self.TreasureCntAward,_pos = CommFunc.ReadDWORD(_lpData, _pos) + self.GridLimitCnt,_pos = CommFunc.ReadBYTE(_lpData, _pos) + for i in range(self.GridLimitCnt): + temGridLimitCntList = tagMCTreasureGridLimit() + _pos = temGridLimitCntList.ReadData(_lpData, _pos) + self.GridLimitCntList.append(temGridLimitCntList) + return _pos + + def Clear(self): + self.TreasureType = 0 + self.LuckValue = 0 + self.TreasureCount = 0 + self.FreeCountToday = 0 + self.TreasureCntAward = 0 + self.GridLimitCnt = 0 + self.GridLimitCntList = list() + return + + def GetLength(self): + length = 0 + length += 1 + length += 2 + length += 4 + length += 2 + length += 4 + length += 1 + for i in range(self.GridLimitCnt): + length += self.GridLimitCntList[i].GetLength() + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteBYTE(data, self.TreasureType) + data = CommFunc.WriteWORD(data, self.LuckValue) + data = CommFunc.WriteDWORD(data, self.TreasureCount) + data = CommFunc.WriteWORD(data, self.FreeCountToday) + data = CommFunc.WriteDWORD(data, self.TreasureCntAward) + data = CommFunc.WriteBYTE(data, self.GridLimitCnt) + for i in range(self.GridLimitCnt): + data = CommFunc.WriteString(data, self.GridLimitCntList[i].GetLength(), self.GridLimitCntList[i].GetBuffer()) + return data + + def OutputString(self): + DumpString = ''' TreasureType:%d, LuckValue:%d, TreasureCount:%d, - FreeCountToday:%d + FreeCountToday:%d, + TreasureCntAward:%d, + GridLimitCnt:%d, + GridLimitCntList:%s '''\ %( self.TreasureType, self.LuckValue, self.TreasureCount, - self.FreeCountToday + self.FreeCountToday, + self.TreasureCntAward, + self.GridLimitCnt, + "..." ) return DumpString @@ -41595,6 +41672,98 @@ #------------------------------------------------------ +# AA 87 运势活动信息 #tagMCActYunshiInfo + +class tagMCActYunshiInfo(Structure): + Head = tagHead() + ActNum = 0 #(BYTE ActNum)// 活动编号 + StartDate = "" #(char StartDate[10])// 开始日期 y-m-d + EndtDate = "" #(char EndtDate[10])// 结束日期 y-m-d + ResetType = 0 #(BYTE ResetType)// 重置类型,0-0点重置;1-5点重置 + LimitLV = 0 #(WORD LimitLV)// 限制等级 + TreasureType = 0 #(BYTE TreasureType)// 活动寻宝类型 + data = None + + def __init__(self): + self.Clear() + self.Head.Cmd = 0xAA + self.Head.SubCmd = 0x87 + return + + def ReadData(self, _lpData, _pos=0, _Len=0): + self.Clear() + _pos = self.Head.ReadData(_lpData, _pos) + self.ActNum,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.StartDate,_pos = CommFunc.ReadString(_lpData, _pos,10) + self.EndtDate,_pos = CommFunc.ReadString(_lpData, _pos,10) + self.ResetType,_pos = CommFunc.ReadBYTE(_lpData, _pos) + self.LimitLV,_pos = CommFunc.ReadWORD(_lpData, _pos) + self.TreasureType,_pos = CommFunc.ReadBYTE(_lpData, _pos) + return _pos + + def Clear(self): + self.Head = tagHead() + self.Head.Clear() + self.Head.Cmd = 0xAA + self.Head.SubCmd = 0x87 + self.ActNum = 0 + self.StartDate = "" + self.EndtDate = "" + self.ResetType = 0 + self.LimitLV = 0 + self.TreasureType = 0 + return + + def GetLength(self): + length = 0 + length += self.Head.GetLength() + length += 1 + length += 10 + length += 10 + length += 1 + length += 2 + length += 1 + + return length + + def GetBuffer(self): + data = '' + data = CommFunc.WriteString(data, self.Head.GetLength(), self.Head.GetBuffer()) + data = CommFunc.WriteBYTE(data, self.ActNum) + data = CommFunc.WriteString(data, 10, self.StartDate) + data = CommFunc.WriteString(data, 10, self.EndtDate) + data = CommFunc.WriteBYTE(data, self.ResetType) + data = CommFunc.WriteWORD(data, self.LimitLV) + data = CommFunc.WriteBYTE(data, self.TreasureType) + return data + + def OutputString(self): + DumpString = ''' + Head:%s, + ActNum:%d, + StartDate:%s, + EndtDate:%s, + ResetType:%d, + LimitLV:%d, + TreasureType:%d + '''\ + %( + self.Head.OutputString(), + self.ActNum, + self.StartDate, + self.EndtDate, + self.ResetType, + self.LimitLV, + self.TreasureType + ) + return DumpString + + +m_NAtagMCActYunshiInfo=tagMCActYunshiInfo() +ChNetPackDict[eval("0x%02x%02x"%(m_NAtagMCActYunshiInfo.Head.Cmd,m_NAtagMCActYunshiInfo.Head.SubCmd))] = m_NAtagMCActYunshiInfo + + +#------------------------------------------------------ # AA 15 仙界盛典全民来嗨玩家信息 #tagMCAllPeoplePartyInfo class tagMCAllPeoplePartyCount(Structure): diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/SetXunbao.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/SetXunbao.py index 8d8cf68..fdb59c6 100644 --- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/SetXunbao.py +++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GM/Commands/SetXunbao.py @@ -30,7 +30,7 @@ # @remarks 函数详细说明. def OnExec(curPlayer, paramList): if not paramList: - GameWorld.DebugAnswer(curPlayer, "重置寻宝:SetXunbao 0") + GameWorld.DebugAnswer(curPlayer, "重置寻宝:SetXunbao 0 [指定类型]") GameWorld.DebugAnswer(curPlayer, "设置幸运:SetXunbao 寻宝类型 幸运值 已寻宝次数") return @@ -38,15 +38,16 @@ ClearPack.OnExec(curPlayer, [ShareDefine.rptTreasure]) ClearPack.OnExec(curPlayer, [ShareDefine.rptRune]) - ipyDataMgr = IpyGameDataPY.IPY_Data() - for i in xrange(ipyDataMgr.GetTreasureSetCount()): - ipyData = ipyDataMgr.GetTreasureSetByIndex(i) - treasureType = ipyData.GetTreasureType() - PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreasureCount % (treasureType), 0) - PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreasureLuck % (treasureType), 0) - PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreasureFreeCount % (treasureType), 0) - - GameWorld.DebugAnswer(curPlayer, "重置寻宝OK!") + treasureTypeList = paramList[1:] + if not treasureTypeList: + ipyDataMgr = IpyGameDataPY.IPY_Data() + for i in xrange(ipyDataMgr.GetTreasureSetCount()): + ipyData = ipyDataMgr.GetTreasureSetByIndex(i) + treasureTypeList.append(ipyData.GetTreasureType()) + PlayerTreasure.ResetTreasureType(curPlayer, treasureTypeList) + GameWorld.DebugAnswer(curPlayer, "重置寻宝OK!%s" % treasureTypeList) + return + else: treasureType = paramList[0] luck = paramList[1] if len(paramList) > 1 else None diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorld.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorld.py index fe37d50..8bf2cdc 100644 --- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorld.py +++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/GameWorld.py @@ -649,6 +649,30 @@ templateID = templateIDList[-1] if dayIndex >= len(templateIDList) else templateIDList[dayIndex] return templateID +def GetOperationActionLoopDate(startDateStr, endDateStr, curDateTime): + ## 获取运营活动配置日期循环的具体活动时间 + # @return: 开始日期, 结束日期, 返回的日期是第x次循环 + startSplitList = startDateStr.split("_") + loopDays = int(startSplitList[0][1:]) + startLoopDateStr = startSplitList[1] + startLoopDateTime = ChangeStrToDatetime(startLoopDateStr, ChConfig.TYPE_Time_Format_Day) + + endSplitList = endDateStr.split("_") # 可不配Lx_开头,防误配,做兼容 + endLoopDateStr = endSplitList[0] if len(endSplitList) == 1 else endSplitList[1] + endLoopDateTime = ChangeStrToDatetime(endLoopDateStr, ChConfig.TYPE_Time_Format_Day) + + if curDateTime >= startLoopDateTime: + passDays = (curDateTime - startLoopDateTime).days + loopTimes = passDays / loopDays + 1 # 第x次循环 + loopTimeMax = (endLoopDateTime - startLoopDateTime).days / loopDays + 1 # 最大循环次数 + loopTimes = min(loopTimes, loopTimeMax) + else: + loopTimes = 1 # 还未开始取第一次 + + startDateTime = startLoopDateTime + datetime.timedelta((loopTimes - 1)*loopDays) + endDateTime = startDateTime + datetime.timedelta(days=(loopDays - 1)) + return startDateTime, endDateTime, loopTimes + def GetOperationActionDateStr(ipyData): ## 获取运营活动对应日期,存数字代表开服天配置,需要转化为对应的日期 curDateTime = datetime.datetime.today() @@ -660,7 +684,7 @@ endDateStr = "%d-%d-%d" % (curDateTime.year, curDateTime.month, curDateTime.day) # 日期直接返回 - if startDateStr.count("-") == 2 and "W" not in startDateStr: + if startDateStr.count("-") == 2 and "W" not in startDateStr and not startDateStr.startswith("L"): return startDateStr, endDateStr # 开服天 @@ -707,7 +731,10 @@ # 只配置结束日期的时候可能导致开始日期计算出来比结束日期还大,即当前时间超过结束日期,且 配置还存在的情况 if startDateTime > endDateTime: startDateTime = endDateTime # 反正都无法开启,随便给个日期,不超过结束日期即可 - + # 按日期循环 + elif startDateStr.startswith("L"): + startDateTime, endDateTime, _ = GetOperationActionLoopDate(startDateStr, endDateStr, curDateTime) + # 默认 else: startDateTime = curDateTime diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py index 38f8cf0..6352007 100644 --- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py +++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/IpyGameDataPY.py @@ -1346,8 +1346,11 @@ "TreasureSet":( ("BYTE", "TreasureType", 1), ("BYTE", "PackType", 0), + ("BYTE", "CheckPack", 0), + ("BYTE", "IsActType", 0), ("BYTE", "DailyFreeCount", 0), ("list", "TreasureCountList", 0), + ("char", "RecycleItemMail", 0), ("DWORD", "CostItemID", 0), ("list", "CostItemCountList", 0), ("BYTE", "CostMoneyType", 0), @@ -1357,6 +1360,7 @@ ("WORD", "FullLucky", 0), ("char", "LuckyRateFormat", 0), ("BYTE", "LuckyGridNum", 0), + ("dict", "GridNumMaxLimitInfo", 0), ("list", "NotifyGridNumList", 0), ("BYTE", "AwardMoneyType", 0), ("WORD", "AwardMoneyValue", 0), @@ -1380,6 +1384,13 @@ ("DWORD", "ItemID", 0), ("DWORD", "ItemCount", 0), ("DWORD", "ItemWeight", 0), + ), + + "TreasureCntAward":( + ("BYTE", "TreasureType", 1), + ("DWORD", "NeedTreasureCnt", 1), + ("BYTE", "AwardIndex", 0), + ("list", "AwardItemList", 0), ), "FreeGoods":( @@ -2061,6 +2072,15 @@ ("WORD", "SingleTimes", 0), ("list", "Reward", 0), ("WORD", "Point", 0), + ), + + "ActYunshi":( + ("DWORD", "CfgID", 1), + ("char", "StartDate", 0), + ("char", "EndDate", 0), + ("WORD", "LVLimit", 0), + ("BYTE", "ResetType", 0), + ("DWORD", "TreasureType", 0), ), "ActBuyCountGift":( @@ -4443,20 +4463,24 @@ def GetTreasureType(self): return self.attrTuple[0] # 寻宝类型 BYTE def GetPackType(self): return self.attrTuple[1] # 放入背包 BYTE - def GetDailyFreeCount(self): return self.attrTuple[2] # 每日免费次数 BYTE - def GetTreasureCountList(self): return self.attrTuple[3] # 抽奖次数列表 list - def GetCostItemID(self): return self.attrTuple[4] # 消耗道具ID DWORD - def GetCostItemCountList(self): return self.attrTuple[5] # 消耗个数列表 list - def GetCostMoneyType(self): return self.attrTuple[6] # 消耗货币类型 BYTE - def GetCostMoneyList(self): return self.attrTuple[7] # 消耗货币列表 list - def GetEnsureCount(self): return self.attrTuple[8] # 每x次必出 WORD - def GetOnceLucky(self): return self.attrTuple[9] # 单次幸运值 BYTE - def GetFullLucky(self): return self.attrTuple[10] # 满幸运值 WORD - def GetLuckyRateFormat(self): return self.attrTuple[11] # 幸运格子概率公式 char - def GetLuckyGridNum(self): return self.attrTuple[12] # 幸运格子编号 BYTE - def GetNotifyGridNumList(self): return self.attrTuple[13] # 需要额外广播的格子 list - def GetAwardMoneyType(self): return self.attrTuple[14] # 额外奖励货币类型 BYTE - def GetAwardMoneyValue(self): return self.attrTuple[15] # 单次奖励货币数 WORD + def GetCheckPack(self): return self.attrTuple[2] # 是否检查背包 BYTE + def GetIsActType(self): return self.attrTuple[3] # 是否活动寻宝 BYTE + def GetDailyFreeCount(self): return self.attrTuple[4] # 每日免费次数 BYTE + def GetTreasureCountList(self): return self.attrTuple[5] # 抽奖次数列表 list + def GetRecycleItemMail(self): return self.attrTuple[6] # 重置回收道具邮件,如果有配置回收邮件key,则重置时会回收多余的寻宝道具 char + def GetCostItemID(self): return self.attrTuple[7] # 消耗道具ID DWORD + def GetCostItemCountList(self): return self.attrTuple[8] # 消耗个数列表 list + def GetCostMoneyType(self): return self.attrTuple[9] # 消耗货币类型 BYTE + def GetCostMoneyList(self): return self.attrTuple[10] # 消耗货币列表 list + def GetEnsureCount(self): return self.attrTuple[11] # 每x次必出 WORD + def GetOnceLucky(self): return self.attrTuple[12] # 单次幸运值 BYTE + def GetFullLucky(self): return self.attrTuple[13] # 满幸运值 WORD + def GetLuckyRateFormat(self): return self.attrTuple[14] # 幸运格子概率公式 char + def GetLuckyGridNum(self): return self.attrTuple[15] # 幸运格子编号 BYTE + def GetGridNumMaxLimitInfo(self): return self.attrTuple[16] # 格子最大产出次数限制,{"格子":最大可产出次数, ...} dict + def GetNotifyGridNumList(self): return self.attrTuple[17] # 需要额外广播的格子 list + def GetAwardMoneyType(self): return self.attrTuple[18] # 额外奖励货币类型 BYTE + def GetAwardMoneyValue(self): return self.attrTuple[19] # 单次奖励货币数 WORD # 寻宝产出库表 class IPY_TreasureHouse(): @@ -4487,6 +4511,18 @@ def GetItemID(self): return self.attrTuple[1] # 物品ID DWORD def GetItemCount(self): return self.attrTuple[2] # 物品个数 DWORD def GetItemWeight(self): return self.attrTuple[3] # 物品权重 DWORD + +# 寻宝累计次数奖励表 +class IPY_TreasureCntAward(): + + def __init__(self): + self.attrTuple = None + return + + def GetTreasureType(self): return self.attrTuple[0] # 寻宝类型 BYTE + def GetNeedTreasureCnt(self): return self.attrTuple[1] # 所需寻宝次数 DWORD + def GetAwardIndex(self): return self.attrTuple[2] # 奖励记录索引 0~30 BYTE + def GetAwardItemList(self): return self.attrTuple[3] # 奖励物品信息列表 [[物品ID,个数,是否拍品],...] list # 极品白拿表 class IPY_FreeGoods(): @@ -5549,6 +5585,20 @@ def GetReward(self): return self.attrTuple[4] # 奖励物品 list def GetPoint(self): return self.attrTuple[5] # 积分 WORD +# 运势活动时间表 +class IPY_ActYunshi(): + + def __init__(self): + self.attrTuple = None + return + + def GetCfgID(self): return self.attrTuple[0] # 配置ID DWORD + def GetStartDate(self): return self.attrTuple[1] # 开启日期 char + def GetEndDate(self): return self.attrTuple[2] # 结束日期 char + def GetLVLimit(self): return self.attrTuple[3] # 限制等级 WORD + def GetResetType(self): return self.attrTuple[4] # 重置类型,0-0点重置;1-5点重置 BYTE + def GetTreasureType(self): return self.attrTuple[5] # 商城类型 DWORD + # 购买次数礼包活动时间表 class IPY_ActBuyCountGift(): @@ -6449,6 +6499,7 @@ self.__LoadFileData("TreasureSet", onlyCheck) self.__LoadFileData("TreasureHouse", onlyCheck) self.__LoadFileData("TreasureItemLib", onlyCheck) + self.__LoadFileData("TreasureCntAward", onlyCheck) self.__LoadFileData("FreeGoods", onlyCheck) self.__LoadFileData("ActFlashGiftbag", onlyCheck) self.__LoadFileData("FlashGiftbag", onlyCheck) @@ -6525,6 +6576,7 @@ self.__LoadFileData("CoatChestUp", onlyCheck) self.__LoadFileData("ActWeekParty", onlyCheck) self.__LoadFileData("WeekParty", onlyCheck) + self.__LoadFileData("ActYunshi", onlyCheck) self.__LoadFileData("ActBuyCountGift", onlyCheck) self.__LoadFileData("ActTask", onlyCheck) self.__LoadFileData("ActTaskTemp", onlyCheck) @@ -7667,6 +7719,13 @@ self.CheckLoadData("TreasureItemLib") return self.ipyTreasureItemLibCache[index] + def GetTreasureCntAwardCount(self): + self.CheckLoadData("TreasureCntAward") + return self.ipyTreasureCntAwardLen + def GetTreasureCntAwardByIndex(self, index): + self.CheckLoadData("TreasureCntAward") + return self.ipyTreasureCntAwardCache[index] + def GetFreeGoodsCount(self): self.CheckLoadData("FreeGoods") return self.ipyFreeGoodsLen @@ -8199,6 +8258,13 @@ self.CheckLoadData("WeekParty") return self.ipyWeekPartyCache[index] + def GetActYunshiCount(self): + self.CheckLoadData("ActYunshi") + return self.ipyActYunshiLen + def GetActYunshiByIndex(self, index): + self.CheckLoadData("ActYunshi") + return self.ipyActYunshiCache[index] + def GetActBuyCountGiftCount(self): self.CheckLoadData("ActBuyCountGift") return self.ipyActBuyCountGiftLen diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py index c04f05e..39aa5d3 100644 --- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py +++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Item/ItemControler.py @@ -2913,3 +2913,56 @@ GivePlayerItem(curPlayer, itemID, itemCnt, isAuctionItem, [IPY_GameWorld.rptItem], event=event) return +def RecycleItem(curPlayer, itemID, notifyMailKey): + ## 回收物品,一般用于相关活动结束后回收活动道具 + if not itemID: + return + playerID = curPlayer.GetPlayerID() + + recycleCount = 0 # 回收总数 + moneyItemID, moneyCount = None, None + + # 背包、仓库 + for packType in [IPY_GameWorld.rptItem, IPY_GameWorld.rptWarehouse]: + backPack = curPlayer.GetItemManager().GetPack(packType) + for i in range(backPack.GetCount())[::-1]: # 会删除,倒序遍历 + curItem = backPack.GetAt(i) + if not curItem or curItem.IsEmpty(): + continue + if curItem.GetItemTypeID() != itemID: + continue + itemCount = GetItemCount(curItem) + equipNoteDict = ItemCommon.GetItemNoteDict(curItem, itemCount) + ItemCommon.DR_DelItem(curPlayer, packType, "RecycleItem", equipNoteDict) + + recycleCount += itemCount + if moneyItemID == None: + moneyItemID, moneyCount = 0, 0 + for i in range(curItem.GetEffectCount()): + effect = curItem.GetEffectByIndex(i) + if effect.GetEffectID() != ChConfig.Def_Effect_RecycleItemMoney: + continue + moneyItemID = effect.GetEffectValue(0) + moneyCount = effect.GetEffectValue(1) + break + + curItem.Clear() + + if not recycleCount: + return + + addItemList = [] + if moneyItemID and moneyCount: + moneyItemData = GameWorld.GetGameData().GetItemByTypeID(moneyItemID) + if moneyItemData: + addItemList.append([moneyItemID, moneyCount * recycleCount, 0]) + + if notifyMailKey: + paramList = [itemID, itemID, recycleCount] + PlayerControl.SendMailByKey(notifyMailKey, [playerID], addItemList, paramList) + elif addItemList: + GivePlayerItemOrMail(curPlayer, addItemList, event=["RecycleItem", False, {"RecycleItemID":itemID}]) + + return + + diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py index fb3624a..3cad6b4 100644 --- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py +++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/ChPlayer.py @@ -167,6 +167,7 @@ import PlayerMineArea import PlayerActLoginNew import PlayerActBuyCountGift +import PlayerActYunshi import PlayerActTask import datetime @@ -882,6 +883,8 @@ PlayerActBuyCountGift.OnPlayerLogin(curPlayer) # 任务活动 PlayerActTask.OnPlayerLogin(curPlayer) + # 运势活动 + PlayerActYunshi.OnPlayerLogin(curPlayer) # 登录活动 PlayerActLoginNew.OnPlayerLogin(curPlayer) # 节日巡礼活动 @@ -5690,6 +5693,9 @@ # 天道树奖励 elif rewardType == ChConfig.Def_RewardType_TiandaoTree: PlayerXiangong.GetTiandaoTreeAward(curPlayer, dataEx) + # 寻宝累计次数奖励 + elif rewardType == ChConfig.Def_RewardType_TreasureCntAward: + PlayerTreasure.GetTreasureCntAward(curPlayer, dataEx, dataExStr) #缥缈奇遇领取 elif rewardType == ChConfig.Def_RewardType_FairyAdventuresAward: PlayerFairyDomain.GetFairyAdventuresAward(curPlayer, dataEx, dataExStr) diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActYunshi.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActYunshi.py new file mode 100644 index 0000000..879c89a --- /dev/null +++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerActYunshi.py @@ -0,0 +1,115 @@ +#!/usr/bin/python +# -*- coding: GBK -*- +#------------------------------------------------------------------------------- +# +##@package Player.PlayerActYunshi +# +# @todo:运势活动 +# @author hxp +# @date 2024-11-08 +# @version 1.0 +# +# 详细描述: 运势活动 +# +#------------------------------------------------------------------------------- +#"""Version = 2024-11-08 15:00""" +#------------------------------------------------------------------------------- + +import PyGameData +import ShareDefine +import PlayerControl +import IpyGameDataPY +import ChPyNetSendPack +import PlayerTreasure +import NetPackCommon +import GameWorld +import ChConfig + +def OnPlayerLogin(curPlayer): + + for actInfo in PyGameData.g_operationActionDict.get(ShareDefine.OperationActionName_Yunshi, {}).values(): + actNum = actInfo.get(ShareDefine.ActKey_ActNum, 0) + isReset = __CheckPlayerActYunshiAction(curPlayer, actNum) + # 活动中同步活动信息 + if not isReset and actInfo.get(ShareDefine.ActKey_State): + Sync_ActYunshiActionInfo(curPlayer, actNum) + return + +def RefreshActYunshiActionInfo(actNum): + ## 收到GameServer同步的活动信息,刷新活动信息 + playerManager = GameWorld.GetPlayerManager() + for index in xrange(playerManager.GetPlayerCount()): + curPlayer = playerManager.GetPlayerByIndex(index) + if not GameWorld.IsNormalPlayer(curPlayer): + continue + __CheckPlayerActYunshiAction(curPlayer, actNum) + return + +def __CheckPlayerActYunshiAction(curPlayer, actNum): + ## 检查玩活动数据信息 + + playerID = curPlayer.GetPlayerID() + + actInfo = GameWorld.GetActInfo(ShareDefine.OperationActionName_Yunshi, actNum) + actID = actInfo.get(ShareDefine.ActKey_ID, 0) + state = actInfo.get(ShareDefine.ActKey_State, 0) + cfgID = actInfo.get(ShareDefine.ActKey_CfgID) + + playerActID = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ActYunshiID % actNum) # 玩家身上的活动ID + lastTreasureType = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ActYunshiTreasureType % actNum) + + # 活动ID 相同的话不处理 + if actID == playerActID: + GameWorld.DebugLog("运势活动ID不变,不处理! actNum=%s,cfgID=%s,actID=%s" % (actNum, cfgID, actID), playerID) + return + GameWorld.DebugLog("运势活动重置! actNum=%s,cfgID=%s,actID=%s,playerActID=%s,state=%s,lastTreasureType=%s" + % (actNum, cfgID, actID, playerActID, state, lastTreasureType), playerID) + if lastTreasureType: + PlayerTreasure.ResetTreasureType(curPlayer, [lastTreasureType]) + + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ActYunshiID % actNum, actID) + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ActYunshiTreasureType % actNum, 0) + + if state: + ipyData = IpyGameDataPY.GetIpyGameData("ActYunshi", cfgID) + if ipyData: + treasureType = ipyData.GetTreasureType() + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_ActYunshiTreasureType % actNum, treasureType) + PlayerTreasure.ResetTreasureType(curPlayer, [treasureType]) + + Sync_ActYunshiActionInfo(curPlayer, actNum) + return True + +def IsActTreasureType(curPlayer, treasureType): + ## 是否活动中的寻宝类型 + for actInfo in PyGameData.g_operationActionDict.get(ShareDefine.OperationActionName_Yunshi, {}).values(): + actNum = actInfo.get(ShareDefine.ActKey_ActNum, 0) + if not actInfo.get(ShareDefine.ActKey_State): + continue + if treasureType == curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_ActYunshiTreasureType % actNum): + return True + return False + +def Sync_ActYunshiActionInfo(curPlayer, actNum): + ## 通知活动信息 + actInfo = GameWorld.GetActInfo(ShareDefine.OperationActionName_Yunshi, actNum) + if not actInfo: + return + if not actInfo.get(ShareDefine.ActKey_State): + return + cfgID = actInfo.get(ShareDefine.ActKey_CfgID) + ipyData = IpyGameDataPY.GetIpyGameData("ActYunshi", cfgID) + if not ipyData: + return + + startDateStr, endDateStr = GameWorld.GetOperationActionDateStr(ipyData) + actPack = ChPyNetSendPack.tagMCActYunshiInfo() + actPack.Clear() + actPack.ActNum = actNum + actPack.StartDate = startDateStr + actPack.EndtDate = endDateStr + actPack.ResetType = ipyData.GetResetType() + actPack.LimitLV = ipyData.GetLVLimit() + actPack.TreasureType = ipyData.GetTreasureType() + NetPackCommon.SendFakePack(curPlayer, actPack) + return diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py index fa05a81..caa8ccc 100644 --- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py +++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerEventCounter.py @@ -102,6 +102,7 @@ import PlayerFeastLogin import PlayerFeastWish import PlayerActTask +import PlayerActYunshi import PlayerActBuyCountGift import PlayerActLoginNew import PlayerActLogin @@ -1497,6 +1498,9 @@ elif actionName == ShareDefine.OperationActionName_ActTask: PlayerActTask.RefreshActTaskActionInfo(actNum) + elif actionName == ShareDefine.OperationActionName_Yunshi: + PlayerActYunshi.RefreshActYunshiActionInfo(actNum) + elif actionName == ShareDefine.OperationActionName_LoginAward: PlayerActLogin.RefreshOperationAction_LoginAward() diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTreasure.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTreasure.py index e0bbb05..4220e01 100644 --- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTreasure.py +++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerTreasure.py @@ -30,6 +30,7 @@ import PlayerFeastTravel import PlayerFairyCeremony import PlayerNewFairyCeremony +import PlayerActYunshi import PlayerActTask import ItemCommon import ChConfig @@ -37,6 +38,7 @@ import random import time +# 寻宝类型: >=100的为策划自行配置的自定义寻宝类型,<100的用于指定系统寻宝功能 TreasureTypeList = ( TreasureType_Jipin, # 极品寻宝 1 TreasureType_Rune, # 符印寻宝 2 @@ -70,6 +72,34 @@ Sync_TreasureInfo(curPlayer, syncTypeList) return +def ResetTreasureType(curPlayer, treasureTypeList): + ## 重置寻宝类型数 + for treasureType in treasureTypeList: + setIpyData = IpyGameDataPY.GetIpyGameData("TreasureSet", treasureType) + if not setIpyData: + continue + recycleItemMail = setIpyData.GetRecycleItemMail() + costItemID = setIpyData.GetCostItemID() + if recycleItemMail and costItemID: + ItemControler.RecycleItem(curPlayer, costItemID, recycleItemMail) + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreasureFreeCount % (treasureType), 0) + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreasureCount % (treasureType), 0) + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreasureLuck % (treasureType), 0) + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreasureCntAward % (treasureType), 0) + + gridNumMaxLimitInfo = setIpyData.GetGridNumMaxLimitInfo() + for gridNumStr in gridNumMaxLimitInfo.keys(): + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreasureGridCnt % (treasureType, int(gridNumStr)), 0) + + Sync_TreasureInfo(curPlayer, treasureTypeList) + return + +def IsActTreasureType(curPlayer, treasureType): + ## 是否活动中的寻宝类型 + if PlayerActYunshi.IsActTreasureType(curPlayer, treasureType): + return True + return False + #// A5 68 请求寻宝 #tagCMRequestTreasure # #struct tagCMRequestTreasure @@ -93,6 +123,10 @@ setIpyData = IpyGameDataPY.GetIpyGameData("TreasureSet", treasureType) if not setIpyData: return + if setIpyData.GetIsActType(): + if not IsActTreasureType(curPlayer, treasureType): + GameWorld.ErrLog("该寻宝类型非活动中,无法寻宝! treasureType=%s" % (treasureType), playerID) + return treasureCountList = setIpyData.GetTreasureCountList() # 寻宝获得个数列表 if not treasureCountList: GameWorld.DebugLog("没有寻宝次数列表配置!", playerID) @@ -106,7 +140,7 @@ return packType = setIpyData.GetPackType() - if treasureType not in [TreasureType_GatherTheSoul, TreasureType_Gubao]: + if setIpyData.GetCheckPack(): if not ItemCommon.CheckPackHasSpace(curPlayer, packType, True): GameWorld.DebugLog("对应寻宝背包没有空格子!packType=%s" % packType, playerID) return @@ -177,113 +211,87 @@ luckyGridNumList = [setIpyData.GetLuckyGridNum()] GameWorld.DebugLog("luckyGridNumList=%s, %s" % (luckyGridNumList, luckyItemRateList), playerID) luckFormula = setIpyData.GetLuckyRateFormat() # 幸运物品概率公式 - addLuck = setIpyData.GetOnceLucky() * treasureCount # 增加幸运值 + addLuck = setIpyData.GetOnceLucky() # 增加幸运值 maxLuck = setIpyData.GetFullLucky() # 满幸运值 curLuck = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreasureLuck % (treasureType)) # 当前幸运值 - updLuck = curLuck + addLuck - - commItemRateList = GetUpdLuckyItemRateList(ipyData, luckyGridNumList, curLuck, luckFormula, costType) # 常规产出物品格子饼图,幸运物品概率已变更 + updLuck = curLuck curTreasureCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreasureCount % (treasureType)) # 当前已寻宝次数 - updTreasureCount = curTreasureCount + treasureCount - GameWorld.DebugLog("已经寻宝次数=%s,当前幸运=%s,commItemRateList=%s" % (curTreasureCount, curLuck, commItemRateList), playerID) + updTreasureCount = curTreasureCount beSureCountDict = ipyData.GetGridItemRateList3() # 第x次必出产出格子编号饼图 ensureCount = setIpyData.GetEnsureCount() # 每多少次触发保底产出库 ensureRateList = ipyData.GetGridItemRateList2() + GameWorld.DebugLog("beSureCountDict=%s" % beSureCountDict, playerID) + GameWorld.DebugLog("ensureCount=%s, %s" % (ensureCount, ensureRateList), playerID) notifyGridNumList = setIpyData.GetNotifyGridNumList() # 额外需要广播的格子,幸运必出、次数必出可不配置 + gridNumMaxLimitInfo = setIpyData.GetGridNumMaxLimitInfo() # {"格子":最大可产出次数, ...} + gridNumCountInfo = {} # 有限制产出次数的格子已经产出数 + for gridNumStr in gridNumMaxLimitInfo.keys(): + gridNumCountInfo[int(gridNumStr)] = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreasureGridCnt % (treasureType, gridNumStr)) + GameWorld.DebugLog("gridNumMaxLimitInfo=%s,gridNumCountInfo=%s" % (gridNumMaxLimitInfo, gridNumCountInfo), playerID) # 单抽产出优先级: 幸运物品 > 必出 > 保底 > 普通 # 连抽没有优先级限制,只要满足条件即可产出 getGridResult = [] - - # 1.满幸运必出 - if updLuck >= maxLuck and luckyGridNumList: - if luckyItemRateList: - luckyGridNum = GameWorld.GetResultByRandomList(luckyItemRateList) - else: - luckyGridNum = luckyGridNumList[0] - getGridResult.append(luckyGridNum) - GameWorld.DebugLog("满幸运必出幸运物品: luckyGridNum=%s" % luckyGridNum, playerID) + for tIndex in range(treasureCount): + updLuck = min(updLuck + addLuck, maxLuck) + updTreasureCount += 1 + GameWorld.DebugLog("%s,累计次数=%s,幸运=%s" % (tIndex + 1, updTreasureCount, updLuck), playerID) + if gridNumMaxLimitInfo: + GameWorld.DebugLog(" gridNumMaxLimitInfo=%s,gridNumCountInfo=%s" % (gridNumMaxLimitInfo, gridNumCountInfo), playerID) + baseRateList, commItemRateList = GetUpdLuckyItemRateList(ipyData, luckyGridNumList, updLuck, luckFormula, costType) # 常规产出物品格子饼图,幸运物品概率已变更 + commItemRateList = GetRemoveLimitGridRateList(commItemRateList, gridNumCountInfo, gridNumMaxLimitInfo) + GameWorld.DebugLog(" 基础饼图=%s" % baseRateList, playerID) + GameWorld.DebugLog(" 常规饼图=%s" % commItemRateList, playerID) - # 单抽 - if treasureCount == 1: - if not getGridResult: - if updTreasureCount in beSureCountDict: - gridNumRateList = beSureCountDict[updTreasureCount] - gridNum = GameWorld.GetResultByRandomList(gridNumRateList) - GameWorld.DebugLog("到达次数必出,updTreasureCount=%s,gridNumRateList=%s,gridNum=%s" % (updTreasureCount, gridNumRateList, gridNum), playerID) - elif ensureCount and updTreasureCount % ensureCount == 0 and ensureRateList: - gridNumRateList = ensureRateList - gridNum = GameWorld.GetResultByRandomList(gridNumRateList) - GameWorld.DebugLog("满次数保底出,updTreasureCount=%s,gridNumRateList=%s,gridNum=%s" % (updTreasureCount, gridNumRateList, gridNum), playerID) + curRateList = [] # 可能会改变饼图,每次抽奖使用新的饼图对象,不要改变配置的饼图概率 + + # 满幸运必出 + if updLuck >= maxLuck and luckyGridNumList: + if luckyItemRateList: + curRateList = GetRemoveLimitGridRateList(luckyItemRateList, gridNumCountInfo, gridNumMaxLimitInfo) else: - gridNumRateList = commItemRateList - gridNum = GameWorld.GetResultByRandomList(gridNumRateList) - GameWorld.DebugLog("常规产出,updTreasureCount=%s,gridNum=%s" % (updTreasureCount, gridNum), playerID) - getGridResult.append(gridNum) + curRateList = GetRemoveLimitGridRateList([(10000, luckyGridNumList[0])], gridNumCountInfo, gridNumMaxLimitInfo) + GameWorld.DebugLog(" 【满幸运饼图】: %s" % curRateList) - # 连抽 - elif treasureCount > 1: - # 2. 次数必出 - besureGridNumList = [] - for count, gridNumRateList in beSureCountDict.items(): - if curTreasureCount < count and updTreasureCount >= count: - for gridInfo in gridNumRateList: - besureGridNumList.append(gridInfo[1]) - gridNum = GameWorld.GetResultByRandomList(gridNumRateList) - getGridResult.append(gridNum) - GameWorld.DebugLog("到达次数必出,count=%s,updTreasureCount=%s,gridNumRateList=%s,gridNum=%s" % (count, updTreasureCount, gridNumRateList, gridNum), playerID) + # 次数必出 + if not curRateList and updTreasureCount in beSureCountDict: + besureGridRateList = beSureCountDict[updTreasureCount] + curRateList = GetRemoveLimitGridRateList(besureGridRateList, gridNumCountInfo, gridNumMaxLimitInfo) + GameWorld.DebugLog(" 【第%s次数必出饼图】: %s" % (updTreasureCount, curRateList)) + + # 满次数必出 + if not curRateList and ensureCount and updTreasureCount % ensureCount == 0 and ensureRateList: + curRateList = GetRemoveLimitGridRateList(ensureRateList, gridNumCountInfo, gridNumMaxLimitInfo) + GameWorld.DebugLog(" 【满%s次数必出饼图】: %s" % (ensureCount, curRateList)) + + doCount = 0 + while doCount <= 50: # 限制最大次数 + doCount += 1 + if doCount > 1 or not curRateList: # 重新随机的默认使用常规饼图 + curRateList = commItemRateList - # 3. 次数保底 - ensureGridNumList = [] - if ensureCount and updTreasureCount / ensureCount > curTreasureCount / ensureCount and ensureRateList: - for gridInfo in ensureRateList: - ensureGridNumList.append(gridInfo[1]) - gridNum = GameWorld.GetResultByRandomList(ensureRateList) - getGridResult.append(gridNum) - GameWorld.DebugLog("满次数保底出,updTreasureCount=%s,gridNumRateList=%s,gridNum=%s" % (updTreasureCount, ensureRateList, gridNum), playerID) - - # 4. 常规产出 - doCount = 200 - needCount = max(0, treasureCount - len(getGridResult)) - while needCount and doCount: - doCount -= 1 - gridNum = GameWorld.GetResultByRandomList(commItemRateList) - + gridNum = GameWorld.GetResultByRandomList(curRateList) if gridNum in luckyGridNumList and gridNum in getGridResult: - GameWorld.DebugLog("幸运物品已经出过,不再重复产出!") + GameWorld.DebugLog(" 幸运物品已经出过,不再重复产出! gridNum=%s in %s" % (gridNum, getGridResult)) continue - if gridNum in besureGridNumList: - canGive = True - for besureGridNum in besureGridNumList: - if besureGridNum in getGridResult: - canGive = False - GameWorld.DebugLog("次数必出物品已经出过,不再重复产出!gridNum=%s,besureGridNum=%s,besureGridNumList=%s" - % (gridNum, besureGridNum, besureGridNumList), playerID) - break - if not canGive: - continue - - if gridNum in ensureGridNumList: - canGive = True - for ensureGridNum in ensureGridNumList: - if ensureGridNum in getGridResult: - canGive = False - GameWorld.DebugLog("满次数保底物品已经出过,不再重复产出!gridNum=%s,ensureGridNum=%s,ensureGridNumList=%s" - % (gridNum, ensureGridNum, ensureGridNumList), playerID) - break - if not canGive: - continue - - needCount -= 1 - getGridResult.append(gridNum) - GameWorld.DebugLog("常规产出: gridNum=%s" % (gridNum), playerID) + # 其他产出限制... - else: - return - + if not gridNum: + continue + + getGridResult.append(gridNum) + GameWorld.DebugLog(" 本次产出: gridNum=%s, %s" % (gridNum, getGridResult), playerID) + if gridNum in luckyGridNumList: + updLuck = 0 + GameWorld.DebugLog(" 【产出幸运格子】: gridNum=%s" % (gridNum), playerID) + if gridNum in gridNumCountInfo: + gridNumCountInfo[gridNum] = gridNumCountInfo[gridNum] + 1 + GameWorld.DebugLog(" 【更新产出次数】: gridNum=%s, %s" % (gridNum, gridNumCountInfo), playerID) + break + GameWorld.DebugLog("寻宝格子结果: getGridResult=%s" % getGridResult, playerID) if len(getGridResult) != treasureCount: GameWorld.ErrLog("寻宝异常,实际获得数量与寻宝请求数不同!treasureType=%s,treasureIndex=%s" % (treasureType, treasureIndex), playerID) @@ -367,7 +375,9 @@ updLuck = 0 break PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreasureLuck % (treasureType), updLuck) - + for gridNum, updCount in gridNumCountInfo.items(): + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreasureGridCnt % (treasureType, gridNum), updCount) + addScoreType = setIpyData.GetAwardMoneyType() # 额外奖励货币类型 addScore = setIpyData.GetAwardMoneyValue() # 单次奖励货币数 if addScoreType and addScore: @@ -407,8 +417,8 @@ if mailItemList: PlayerControl.SendMailByKey("HappyXBUnEnough", [playerID], mailItemList) - GameWorld.DebugLog("寻宝成功: treasureType=%s,updTreasureCount=%s,updLuck=%s,addLuck=%s,addScoreType=%s,addScore=%s" - % (treasureType, updTreasureCount, updLuck, addLuck, addScoreType, addScore), playerID) + GameWorld.DebugLog("寻宝成功: treasureType=%s,updTreasureCount=%s,updLuck=%s,addScoreType=%s,addScore=%s,gridNumCountInfo=%s" + % (treasureType, updTreasureCount, updLuck, addScoreType, addScore, gridNumCountInfo), playerID) GameWorld.DebugLog(" treasureResult=%s" % (treasureResult), playerID) GameWorld.DebugLog(" mailItemList=%s" % (mailItemList), playerID) @@ -424,6 +434,26 @@ Sync_TreasureInfo(curPlayer, [treasureType]) return + +def GetRemoveLimitGridRateList(srcGridNumRateList, gridNumCountInfo, gridNumMaxLimitInfo): + ## 获取移除限制产出的格子后的饼图列表 + # @param srcGridNumRateList: 原始概率 [(概率, 格子编号), ...] + # @param gridNumCountInfo: 有限制产出数的格子已经产出数量信息 {gridNum:count, ...} + # @param gridNumMaxLimitInfo: 有限制产出数的格子最大产出数量信息 {"gridNum":countLimit, ...} + newRateList = [] + if not gridNumMaxLimitInfo: + return newRateList + srcGridNumRateList # 不使用原配置饼图,不然可能导致修改掉原始配置饼图导致bug + for i, rateInfo in enumerate(srcGridNumRateList): + rate, gridNum = rateInfo + if str(gridNum) in gridNumMaxLimitInfo: + limitCount = gridNumMaxLimitInfo[str(gridNum)] + if limitCount and gridNumCountInfo.get(gridNum, 0) >= limitCount: + # 已达到限制产出数,不再产出 + continue + srcRate = rate if i == 0 else (rate - srcGridNumRateList[i - 1][0]) # 原概率 + newRate = srcRate if not newRateList else (newRateList[-1][0] + srcRate) + newRateList.append((newRate, gridNum)) + return newRateList def GetUpdLuckyItemRateList(ipyData, luckyGridNumList, curLuck, luckFormula, costType): # 获取幸运物品提升概率后的饼图 @@ -445,7 +475,7 @@ specRate = newRate if not updRateList else (updRateList[-1][0] + newRate) # 提升后对应饼图概率 updRateList.append((specRate, gridNum)) - return updRateList + return srcPieList, updRateList def GetJobItem(job, itemID, jobItemList): ## 获取宝箱物品奖励对应的职业物品, 职业从1开始 @@ -460,6 +490,37 @@ return jobItemIDList[job - 1] return itemID +def GetTreasureCntAward(curPlayer, treasureType, needTreasureCnt): + ## 领取天道树奖励 + needTreasureCnt = GameWorld.ToIntDef(needTreasureCnt, 0) + playerID = curPlayer.GetPlayerID() + ipyData = IpyGameDataPY.GetIpyGameData("TreasureCntAward", treasureType, needTreasureCnt) + if not ipyData: + return + awardIndex = ipyData.GetAwardIndex() + awardItemList = ipyData.GetAwardItemList() + + awardState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreasureCntAward % (treasureType)) + if awardState&pow(2, awardIndex): + GameWorld.DebugLog("该寻宝次数奖励已领奖! treasureType=%s,needTreasureCnt=%s,awardIndex=%s" + % (treasureType, needTreasureCnt, awardIndex), playerID) + return + + treasureCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreasureCount % (treasureType)) + if treasureCount < needTreasureCnt: + GameWorld.DebugLog("该寻宝次数不足,无法领奖! treasureType=%s,treasureCount=%s < %s" + % (treasureType, treasureCount, needTreasureCnt), playerID) + return + + updState = awardState|pow(2, awardIndex) + PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TreasureCntAward % (treasureType), updState) + GameWorld.DebugLog("领取寻宝次数奖励! treasureType=%s,needTreasureCnt=%s,awardIndex=%s,awardState=%s,updState=%s" + % (treasureType, needTreasureCnt, awardIndex, awardState, updState), playerID) + + ItemControler.GivePlayerItemOrMail(curPlayer, awardItemList) + Sync_TreasureInfo(curPlayer, [treasureType]) + return + def Sync_TreasureInfo(curPlayer, syncTypeList=None): if syncTypeList == None: syncTypeList = [] @@ -472,12 +533,27 @@ treasureInfoPack.Clear() treasureInfoPack.TreasuerInfoList = [] for tType in syncTypeList: + setIpyData = IpyGameDataPY.GetIpyGameData("TreasureSet", tType) + if not setIpyData: + continue + if setIpyData.GetIsActType(): + if not IsActTreasureType(curPlayer, tType): + continue + gridNumMaxLimitInfo = setIpyData.GetGridNumMaxLimitInfo() tTypeInfo = ChPyNetSendPack.tagMCTreasureTypeInfo() tTypeInfo.Clear() tTypeInfo.TreasureType = tType tTypeInfo.LuckValue = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreasureLuck % (tType)) tTypeInfo.TreasureCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreasureCount % (tType)) tTypeInfo.FreeCountToday = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreasureFreeCount % (tType)) + tTypeInfo.TreasureCntAward = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreasureCntAward % (tType)) + for gridNumStr in gridNumMaxLimitInfo.keys(): + gridNum = int(gridNumStr) + gridLimit = ChPyNetSendPack.tagMCTreasureGridLimit() + gridLimit.GridNum = gridNum + gridLimit.GridCnt = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TreasureGridCnt % (tType, gridNum)) + tTypeInfo.GridLimitCntList.append(gridLimit) + tTypeInfo.GridLimitCnt = len(tTypeInfo.GridLimitCntList) treasureInfoPack.TreasuerInfoList.append(tTypeInfo) treasureInfoPack.InfoCount = len(treasureInfoPack.TreasuerInfoList) NetPackCommon.SendFakePack(curPlayer, treasureInfoPack) diff --git a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py index 0b8f31d..2cc0d68 100644 --- a/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py +++ b/ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/ShareDefine.py @@ -296,6 +296,7 @@ OperationActionName_FamilyCTGAssist = "ActFamilyCTGAssist" # 仙盟充值协助 OperationActionName_Gubao = "ActGubao" # 古宝养成活动 OperationActionName_HorsePetTrain = "ActHorsePetTrain" # 骑宠养成活动 +OperationActionName_Yunshi = "ActYunshi" # 运势活动 #节日活动类型列表 - 该类型无视开服天,日期到了就开启 FeastOperationActionNameList = [OperationActionName_FeastWeekParty, OperationActionName_FeastRedPacket, OperationActionName_RechargeRebateGold, OperationActionName_GrowupBuy, @@ -318,7 +319,7 @@ OperationActionName_BuyOne, OperationActionName_BossTrial, OperationActionName_ActLoginNew, OperationActionName_ActTask, OperationActionName_BuyCountGift, OperationActionName_FamilyCTGAssist, - OperationActionName_Gubao, OperationActionName_HorsePetTrain, + OperationActionName_Gubao, OperationActionName_HorsePetTrain, OperationActionName_Yunshi, ] + FeastOperationActionNameList #需要记录开启活动时的世界等级的运营活动 NeedWorldLVOperationActNameList = [OperationActionName_FairyCeremony, OperationActionName_WishingWell, @@ -345,7 +346,7 @@ OperationActionName_BuyOne, OperationActionName_BossTrial, OperationActionName_ActLoginNew, OperationActionName_ActTask, OperationActionName_BuyCountGift, OperationActionName_FamilyCTGAssist, - OperationActionName_Gubao, OperationActionName_HorsePetTrain, + OperationActionName_Gubao, OperationActionName_HorsePetTrain, OperationActionName_Yunshi, ] #跨服运营活动表名定义 -- Gitblit v1.8.0