hxp
2025-10-24 3432541b467d53ffe4ed3872c734e76638e30df8
ServerPython/ZoneServerGroup/map1_8G/MapServer/MapServerData/Script/Player/PlayerSignDay.py
@@ -1,286 +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 PlayerMagicWeapon
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")
    # 刷签到附加功能属性
    PlayerMagicWeapon.CalcMagicWeaponAttr(curPlayer)
    PlayerPet.CalcPetItemAddPlayerAttr(curPlayer)
    PlayerControl.PlayerControl(curPlayer).RefreshPlayerAttrState()
    mwID = IpyGameDataPY.GetFuncCfg('MWSignDayAttr', 2)
    if mwID:
        effDict = IpyGameDataPY.GetFuncEvalCfg('MWSignDayAttr', 1, {})
        if PlayerMagicWeapon.GetIsActiveMagicWeapon(curPlayer, mwID) and effDict:
            PlayerControl.NotifyCode(curPlayer, "SignInText1", [mwID, effDict.keys()[0], effDict.values()[0]])
    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