hxp
2025-10-09 dae842ad6e4a43d66255251e3ca60880af8d08bb
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerSignDay.py
@@ -1,277 +1,160 @@
#!/usr/bin/python
# -*- coding: GBK -*-
#
#
##@package PlayerSignDay
#
# @todo: 每日签到
#
# @author jiang
# @date 2012-03-23
# @version 1.8
# @note:
# @change: "2013-03-13 17:00" wdb 删除封包
# @change: "2013-10-31 11:00" hxp 修改每日签到逻辑
# @change: "2013-11-05 20:20" hxp 增加过天通知签到记录情况
# @change: "2014-04-03 22:00" xmnathan 每日签到逻辑修改,增加VIP补签
# @change: "2015-06-16 15:40" ljd 修改成类登陆奖励,补登
# @change: "2015-08-03 16:40" ljd 补签次数从VIP 挪到 贵族
# @change: "2015-08-24 14:40" zqx 增加签到成就
# @change: "2016-10-26 11:00" hxp 签到逻辑修改
#-------------------------------------------------------------------------------
#"""Version = 2016-10-26 11:00"""
#
##@package Player.PlayerSignDay
#
# @todo:签到
# @author hxp
# @date 2025-10-09
# @version 1.0
#
# 详细描述: 签到
#
#-------------------------------------------------------------------------------
#"""Version = 2025-10-09 16:30"""
#-------------------------------------------------------------------------------
import ObjPool
import DBDataMgr
import PlayerMail
import ShareDefine
import NetPackCommon
import IPY_GameWorld
import ItemControler
import DataRecordPack
import ChPyNetSendPack
import PlayerTongTianLing
import PlayerActTask
import PlayerPet
import PlayerControl
import IpyGameDataPY
import GameWorld
import ChConfig
import GameFuncComm
import IpyGameDataPY
import ItemCommon
import time
#===============================================================================
#//A5 09 玩家签到 #tagCMDaySign
# struct    tagCMDaySign
SignInState_None = 0
SignInState_Sign = 1 # 已签到
SignInState_Supplement = 2 # 可补签
SignInState_Got = 3 # 已领取
#//A5 09 玩家签到领奖 #tagCSDaySign
#
#struct    tagCSDaySign
#{
#    tagHead        Head;
#    BYTE        Day;    //默认0表示当日签到,从1表示补签。
# };
#===============================================================================
## 玩家签到封包入口
#  @param index: 玩家索引
#  @param clientData: 封包结构体
#  @param tick: 时间戳
#  @return: None
#    tagHead         Head;
#    BYTE        Day;    // 第x天,从1开始
#};
def OnSignDay(index, clientData, tick):
    # 跨服服务器功能限制
    if GameWorld.IsCrossServer():
        return
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    #功能开启判断
    if not GameFuncComm.GetFuncCanUse(curPlayer, ShareDefine.GameFuncID_SignDay):
        GameWorld.DebugLog("玩家等级不足,未开启签到功能 PlayerLv=%s" % curPlayer.GetLV())
        return
    curPlayer = GameWorld.GetPlayerManager().GetPlayerByIndex(index)
    signDay = clientData.Day # 0-正常签到;1-补签
    isAddLogin = 1 if signDay else 0 # 是否补签
    signDay = clientData.Day
    
    if not isAddLogin:
        #是否今天已经签到
        signState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_DayLoginSignState)
        if signState:
            GameWorld.DebugLog("今日已签到过!")
            return
        signCost = 0
    else:
        #本轮累计可补签次数
        canAddSignNum = GetCanAddSignNum(curPlayer)
        #是否有剩余补签次数
        if canAddSignNum <= 0:
            GameWorld.DebugLog("已经没有补签次数,补签失败!canAddSignNum=%s" % canAddSignNum)
            return
        #获取需要消耗玩家仙玉
        signCost = IpyGameDataPY.GetFuncCfg("SignConsumption")
        if not PlayerControl.HaveMoney(curPlayer, IPY_GameWorld.TYPE_Price_Gold_Money, signCost, True):
            GameWorld.DebugLog("补签所需货币不足! signCost=%s" % signCost)
            return
    #获得签到天数
    curSignNum = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_DayLoginSignNum) + 1
    totalSignNum = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TotalSignNum) + 1
    #获得签到累计奖励表某日信息
    awardInfo = IpyGameDataPY.GetIpyGameData("SignAward", curSignNum)
    if not awardInfo:
        GameWorld.DebugLog("找不到签到奖励! 签到第(%s)次" % curSignNum)
    bit = signDay - 1
    state = GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_SignInState, bit, False)
    if state == SignInState_Got:
        GameWorld.DebugLog("该天已签到领奖过了! signDay=%s" % signDay)
        return
    #获得列信息
    itemIDList = awardInfo.GetItemID()
    ordinaryNumList = awardInfo.GetOrdinaryNum()
    isBind = awardInfo.GetIsBind()
    vipLv = awardInfo.GetVipLv()
    vipMultiple = awardInfo.GetVipMultiple()
    #判断是否是第二月以后
    isMulti = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_DayLoginSignIsMulti)
    if not isMulti:
        itemID = itemIDList[0]
        ordinaryNum = ordinaryNumList[0]
    else:
        itemID = itemIDList[1]
        ordinaryNum = ordinaryNumList[1]
    #判断是否需要Vip多倍
    curVipLV = curPlayer.GetVIPLv()
    if curVipLV >= vipLv:
        ordinaryNum *= vipMultiple
    #记录签到信息
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_DayLoginSignNum, curSignNum)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TotalSignNum, totalSignNum)
    if not isAddLogin:
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_DayLoginSignState, 1)
    #支付仙玉
    if signCost > 0:
        PlayerControl.PayMoney(curPlayer, IPY_GameWorld.TYPE_Price_Gold_Money, signCost, ChConfig.Def_Cost_AddSignDay)
    #签到奖励信息
    awardInfoList = [[itemID, ordinaryNum, isBind]]
    
    #给予签到奖励物品
    __GivePlayerItemByItemInfoList(curPlayer, awardInfoList, "SignToPlayer")
    ipyData = IpyGameDataPY.GetIpyGameData("SignIn", signDay)
    if not ipyData:
        return
    awardItemList = ipyData.GetAwardItemList()
    if not awardItemList:
        return
    
    #累计签到奖励信息
    contineAwardInfoList = []
    moneyType, moneyValue = 0, 0
    # 补签
    if state == SignInState_Supplement:
        moneyType, moneyValue = IpyGameDataPY.GetFuncEvalCfg("SignInSet", 1)
        if not PlayerControl.HaveMoney(curPlayer, moneyType, moneyValue):
            return
    elif state != SignInState_Sign:
        GameWorld.DebugLog("当前天签到状态不可领取签到奖励! signDay=%s,state=%s" % (signDay, state))
        return
    
    #获得连续签到奖励表信息
    contineAwardInfo = IpyGameDataPY.GetIpyGameData("ContineSignAward", curSignNum)
    if not contineAwardInfo:
        GameWorld.DebugLog("找不到连续签到奖励! 签到第(%s)次" % curSignNum)
    else:
        jobItemList = contineAwardInfo.GetJobItemList()
        itemIDList = contineAwardInfo.GetItemID()
        itemNumList = contineAwardInfo.GetItemNum()
        awardIndex = 1 if (len(itemIDList) > 1 and isMulti) else 0
        itemID = itemIDList[awardIndex]
        itemCount = itemNumList[awardIndex]
        if itemID in jobItemList and curPlayer.GetJob() <= len(jobItemList):
            itemID = jobItemList[curPlayer.GetJob() - 1]
        contineAwardInfoList = [[itemID, itemCount, contineAwardInfo.GetIsBind()]]
        #for index in xrange(len(itemIDList)):
        #    contineAwardInfoList.append([itemIDList[index], itemNumList[index], itemIsBind])
    #给予累计奖励物品
    __GivePlayerItemByItemInfoList(curPlayer, contineAwardInfoList, "ContineSignToPlayer")
    PlayerControl.NotifyCode(curPlayer, 'SignInText')
    #同步客户端
    if moneyType and moneyValue:
        PlayerControl.PayMoney(curPlayer, moneyType, moneyValue, ChConfig.Def_Cost_AddSignDay)
    befValue, updValue = GameWorld.SetDictValueByBit(curPlayer, ChConfig.Def_PDict_SignInState, bit, SignInState_Got, False)
    GameWorld.DebugLog("签到领奖: signDay=%s,state=%s,befValue=%s,updValue=%s" % (signDay, state, befValue, updValue))
    ItemControler.GivePlayerItemOrMail(curPlayer, awardItemList, event=["SignDay", False, {}])
    Sync_SignDayInfo(curPlayer)
    addDataDict = {"signNum":curSignNum, "vipLV":curVipLV, "itemInfo":str(awardInfoList + contineAwardInfoList),
                   "isAddSign":isAddLogin, "CostMoney":str([IPY_GameWorld.TYPE_Price_Gold_Money, signCost])}
    DataRecordPack.DR_FuncGiveItem(curPlayer, "DayLoginSignAward", addDataDict)
    GameWorld.DebugLog("%s: %s" % ("补签" if isAddLogin else "签到", addDataDict), curPlayer.GetPlayerID())
    ItemControler.NotifyGiveAwardInfo(curPlayer, awardInfoList + contineAwardInfoList, "SignDay")
    # 刷签到附加功能属性
    PlayerPet.CalcPetItemAddPlayerAttr(curPlayer)
    PlayerControl.PlayerControl(curPlayer).RefreshPlayerAttrState()
    petLearnSkillList, petPassiveSkillList = PlayerPet.GetPetLearnSkill(curPlayer)
    if ChConfig.Def_SkillID_PetSignDay in petPassiveSkillList:
        signDayAttrSkill = GameWorld.GetGameData().GetSkillBySkillID(ChConfig.Def_SkillID_PetSignDay)
        if signDayAttrSkill:
            curEffect = signDayAttrSkill.GetEffect(0)
            PlayerControl.NotifyCode(curPlayer, "SignInText2", [ChConfig.Def_SkillID_PetSignDay, curEffect.GetEffectID(), curEffect.GetEffectValue(0)])
    PlayerTongTianLing.AddTongTianTaskValue(curPlayer, ChConfig.TTLTaskType_Sign, 1)
    PlayerActTask.AddActTaskValue(curPlayer, ChConfig.ActTaskType_Sign)
    return
## 签到总奖励天数
def GetSignAwardCountMax(): return IpyGameDataPY.IPY_Data().GetSignAwardCount()
def DoSignDayOpen(curPlayer):
    ResetDaySign(curPlayer)
    return
def GetSignAwardCountMax(): return IpyGameDataPY.IPY_Data().GetSignInCount()
def SignDayOnLogin(curPlayer):
    ''' 玩家上线 '''
    #功能开启判断
    if not GameFuncComm.GetFuncCanUse(curPlayer, ShareDefine.GameFuncID_SignDay):
        #GameWorld.DebugLog("玩家未开启签到功能 PlayerLv=%s" % curPlayer.GetLV())
        return
    Sync_SignDayInfo(curPlayer)
    __doAutoSingIn(curPlayer)
    return
def SignDayOnDay(curPlayer):
    ''' 玩家过天 '''
    #功能开启判断
    if not GameFuncComm.GetFuncCanUse(curPlayer, ShareDefine.GameFuncID_SignDay):
        GameWorld.DebugLog("玩家攻击不足,未开启签到功能 PlayerLv=%s" % curPlayer.GetLV())
        return
    curSignNum = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_DayLoginSignNum)
    #签到天数已满最大值,刷新榜单
    if curSignNum >= GetSignAwardCountMax():
        GameWorld.DebugLog("累计签到天数满重置! curSignNum=%s" % curSignNum)
        ResetDaySign(curPlayer, 1)
        return
    #刷新是否签到记录
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_DayLoginSignState, 0)
    Sync_SignDayInfo(curPlayer)
    __doAutoSingIn(curPlayer)
    return
def ResetDaySign(curPlayer, isMulti=0):
    ''' 重置签到
    @param isMulti: 是否次月起
    '''
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_DayLoginSignIsMulti, isMulti)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_DayLoginSignNum, 0)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_DayLoginSignState, 0)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_DayLoginSignStartTime, int(time.time()))
    if isMulti:
        Sync_SignDayInfo(curPlayer)
def ResetDaySign(curPlayer):
    ## 重置签到
    signInMax = GetSignAwardCountMax()
    GameWorld.DebugLog("重置签到: signInMax=%s" % (signInMax), curPlayer.GetPlayerID())
    #补发未领取奖励
    mailItemDict = {}
    for day in range(1, 1 + signInMax):
        state = GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_SignInState, day - 1, False)
        if state != SignInState_Sign: # 已签到未领取的
            continue
        ipyData = IpyGameDataPY.GetIpyGameData("SignIn", day)
        if not ipyData:
            break
        awardItemList = ipyData.GetAwardItemList()
        for itemInfo in awardItemList:
            itemID, itemCount = itemInfo[:2]
            mailItemDict[itemID] = mailItemDict.get(itemID, 0) + itemCount
        GameWorld.DebugLog("签到未领取奖励补发: day=%s,awardItemList=%s,%s" % (day, awardItemList, mailItemDict), curPlayer.GetPlayerID())
    if mailItemDict:
        PlayerMail.SendMailByKey("SignDay", curPlayer.GetPlayerID(), mailItemDict)
    keyNumMax = signInMax / 9 + 1 # 每个可以记录9天的状态
    for num in range(keyNumMax):
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_SignInState % num, 0)
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_SignInLastDay, 0)
    __doAutoSingIn(curPlayer)
    return
def __doAutoSingIn(curPlayer):
    ## 执行自动签到,仅做签到标记,非领奖
    signInMax = GetSignAwardCountMax()
    lastDay = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_SignInLastDay)
    isMixServer = DBDataMgr.GetEventTrigMgr().GetValue(ShareDefine.Def_IsMixServer)
    if isMixServer:
        serverDay = DBDataMgr.GetEventTrigMgr().GetValue(ShareDefine.Def_MixServerDay) + 1
    else:
        PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_TotalSignNum, 0)
    return
        serverDay = DBDataMgr.GetEventTrigMgr().GetValue(ShareDefine.Def_ServerDay) + 1
    if lastDay:
        signInRound = (serverDay - 1) / signInMax
        signInRoundLast = (lastDay - 1) / signInMax
        if signInRound != signInRoundLast:
            ResetDaySign(curPlayer)
            return
    canSignInMax = (serverDay - 1) % signInMax + 1
    for day in range(1, 1 + canSignInMax):
        bit = day - 1
        if GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_SignInState, bit, False):
            continue
        state = SignInState_Sign if day == canSignInMax else SignInState_Supplement
        GameWorld.SetDictValueByBit(curPlayer, ChConfig.Def_PDict_SignInState, bit, state, False)
        GameWorld.DebugLog("更新签到状态: day=%s/%s,state=%s,isMixServer=%s,serverDay=%s" % (day, signInMax, state, isMixServer, serverDay))
    PlayerControl.NomalDictSetProperty(curPlayer, ChConfig.Def_PDict_SignInLastDay, serverDay)
    Sync_SignDayInfo(curPlayer)
    return True
def GetCanAddSignNum(curPlayer):
    ## 获取可补签天数
    curTime = int(time.time())
    startTime = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_DayLoginSignStartTime) # 开始时间
    if not startTime:
        return 0
    if curTime < startTime:
        return 0
    signNumMax = GetSignAwardCountMax()
    signNumMax = min(GameWorld.GetDiff_Day(curTime, startTime) + 1, signNumMax) # 最大可签到次数
    signState = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_DayLoginSignState) # 今日是否已签到
    signCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_DayLoginSignNum) # 已签到次数
    signNumRemain = signNumMax - signCount # 剩余可签到次数
    if not signState:
        signNumRemain -= 1
    signNumRemain = max(0, signNumRemain)
    #GameWorld.DebugLog("最大可签到次数=%s,已签到次数=%s,今天是否已签到=%s,可补签次数=%s"
    #                   % (signNumMax, signCount, signState, signNumRemain), curPlayer.GetPlayerID())
    return signNumRemain
## 通知签到次数奖励领取情况
#  @param curPlayer: 玩家实例
#  @return: None
def Sync_SignDayInfo(curPlayer):
    signInfo = ChPyNetSendPack.tagMCDaySignInfo()
    signInfo.Clear()
    signInfo.DaySignCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_DayLoginSignNum)
    signInfo.ReplenishSignCount = GetCanAddSignNum(curPlayer)
    signInfo.IsSign = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_DayLoginSignState)
    isFrist = 0 if curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_DayLoginSignIsMulti) else 1
    signInfo.IsFrist = isFrist
    signInfo.TotalSignCount = curPlayer.NomalDictGetProperty(ChConfig.Def_PDict_TotalSignNum)
    NetPackCommon.SendFakePack(curPlayer, signInfo)
    signInMax = GetSignAwardCountMax()
    clientPack = ObjPool.GetPoolMgr().acquire(ChPyNetSendPack.tagSCDaySignInfo)
    clientPack.SignStateList = []
    for bit in range(signInMax):
        state = GameWorld.GetDictValueByBit(curPlayer, ChConfig.Def_PDict_SignInState, bit, False)
        clientPack.SignStateList.append(state)
    clientPack.Count = len(clientPack.SignStateList)
    NetPackCommon.SendFakePack(curPlayer, clientPack)
    return
##给予玩家物品
def __GivePlayerItemByItemInfoList(curPlayer, awardInfoList, mailTypeKey):
    signCount = len(awardInfoList)
    packSpace = ItemCommon.GetItemPackSpace(curPlayer, IPY_GameWorld.rptItem, signCount)
    if packSpace >= signCount:
        for awardInfo in awardInfoList:
            ItemControler.GivePlayerItem(curPlayer, awardInfo[0], awardInfo[1], 0, [IPY_GameWorld.rptItem])
    else:
        GameWorld.DebugLog("背包已满 邮件发送物品")
        PlayerControl.SendMailByKey(mailTypeKey, [curPlayer.GetPlayerID()], awardInfoList)
    return