local ShopData = class("ShopData", BaseData) function ShopData:ctor() self.data.isDirty = true self.data.isThirdPayGiftDirty = false end function ShopData:clear() self.firstRechargePoped = nil DataManager:unregisterCrossDayFunc("ShopData") end function ShopData:setDirty() self.data.isDirty = not self.data.isDirty end function ShopData:init() -- 章节礼包 self.chapterInfo = {} -- 魂芯商店 self.coreSoulAdTimes = 0 self.coreSoulNormalRewardTimes = 0 self.coreSoulEliteRewardTimes = 0 -- 每日商店 self.dailyInfo = {} -- 金币商店 self.goldInfo = {} --@TODO 2025-09-24 15:12:35 self.goldInfo.count = 0 DataManager:registerCrossDayFunc("ShopData", function() self.coreSoulAdTimes = 0 if self.dailyInfo then self.dailyInfo.refresh_count = 0 self.dailyInfo.ad_refresh_count = 0 end if self.goldInfo then self.goldInfo.count = 0 end if self.emblemInfo then self.emblemInfo.today_count = {} end self.vitAdCount = 0 self.vitGemCount = 0 self:setDirty() end) end function ShopData:isOpen(showToast) if not ModuleManager:getIsOpen(ModuleManager.MODULE_KEY.MALL, not showToast) then return false end return true end function ShopData:isCoreSoulOpen(showToast) if not self:isOpen(showToast) then return false end if not ModuleManager:getIsOpen(ModuleManager.MODULE_KEY.CORE_BOX, not showToast) then return false end return true end function ShopData:hasCoreSoulRedPoint() if not self:isCoreSoulOpen() then return false end -- 广告次数 local adCount = self:getCoreSoulAdRemainTimes() if adCount > 0 then return true end -- 普通道具次数 local normalItemId = self:getCoreSoulCostItemId( GConst.ShopConst.CORE_SOUL_TYPE.NORMAL) if GFunc.checkCost(normalItemId, 1, false) then return true end -- 史诗道具次数 local eliteItemId = self:getCoreSoulCostItemId( GConst.ShopConst.CORE_SOUL_TYPE.ELITE) if GFunc.checkCost(eliteItemId, 1, false) then return true end return false end function ShopData:isDailyOpen(showToast) if not self:isOpen(showToast) then return false end if not ModuleManager:getIsOpen(ModuleManager.MODULE_KEY.MALL_DAILY, not showToast) then return false end return true end function ShopData:showRedPoint() if not self:isOpen() then return false end -- return self:hasCoreSoulRedPoint() or self:hasDailyRedPoint() or self:hasGoldRedPoint(true) or DataManager.CollectionData:hasSummonRedPoint() return self:hasDailyRedPoint() or self:hasGoldRedPoint(true) end function ShopData:hasDailyRedPoint() if not self:isDailyOpen() then return false end if not self:getLoginDailyRp() then return false end for id, cfg in ipairs(self:getDailyConfig()) do if not cfg.cost then local remainCount = self:getDailyRemainFreeCount(id) if remainCount > 0 then return true end end end return false end --是否只包含免费,不包含广告 function ShopData:hasGoldRedPoint(isOnlyFree) if not SDKManager:isAdLoaded() then return false end if not self:getLoginGoldRp() then return false end for id, info in ipairs(self:getGoldConfig()) do if self:getGoldBuyRemainCountByFree(id) > 0 then return true end if not isOnlyFree then if self:getGoldBuyRemainCountByAd(id) > 0 then return true end end end return false end function ShopData:getActGiftConfig(id) if id then return ConfigManager:getConfig("act_gift")[id] else return ConfigManager:getConfig("act_gift") end end function ShopData:getActGiftIdsByType(giftType) local ids = {} for id, info in pairs(self:getActGiftConfig()) do if info.type == giftType then table.insert(ids, id) end end table.sort(ids, function(a, b) return a < b end) return ids end -- 章节礼包 ---------------------------------------------------------------------------------------------------------------------------------------- function ShopData:refreshChapterShop(data) if not data then return end if EDITOR_MODE then Logger.logHighlight("ShopData 章节礼包") Logger.printTable(data) end self.chapterInfo = data.bought self:setDirty() end function ShopData:getChapterGiftConfig(id) if id then return ConfigManager:getConfig("mall_chapter")[id] else return ConfigManager:getConfig("mall_chapter") end end -- 获取要展示的章节礼包id function ShopData:getShowChapterGiftIds() local ids = {} for id, info in ipairs(self:getChapterGiftConfig()) do if DataManager.ChapterData:getChapterPassed(info.chapter_id) and not self:isBoughtChapterGift(id) then table.insert(ids, id) end end table.sort(ids, function(a, b) return a < b end) return ids end -- 是否购买了章节礼包 function ShopData:isBoughtChapterGift(id) return self.chapterInfo[id] and self.chapterInfo[id] > 0 end -- 购买章节礼包成功 function ShopData:onBuyChapterGiftSuccess(id) self.chapterInfo[id] = (self.chapterInfo[id] or 0) + 1 self:setDirty() end -- 魂芯商店 ---------------------------------------------------------------------------------------------------------------------------------------- function ShopData:refreshCoreSoulShop(data) if not data then return end if not data.summons then return end if EDITOR_MODE then Logger.logHighlight("ShopData 魂芯商店") Logger.printTable(data.summons) end local coreSoulInfo = data.summons or {} local normalInfo = coreSoulInfo[GConst.ShopConst.CORE_SOUL_TYPE.NORMAL] or {} local eliteInfo = coreSoulInfo[GConst.ShopConst.CORE_SOUL_TYPE.ELITE] or {} self.coreSoulAdTimes = normalInfo.ad_count or 0 self.coreSoulNormalRewardTimes = normalInfo.trigger_count or 0 -- 普通宝箱大奖累计次数 self.coreSoulEliteRewardTimes = eliteInfo.trigger_count or 0 -- 史诗宝箱大奖累计次数 self:setDirty() end -- 魂芯广告使用次数 function ShopData:getCoreSoulAdTimes() return self.coreSoulAdTimes or 0 end -- 魂芯广告剩余次数 function ShopData:getCoreSoulAdRemainTimes() local remainTimes = self:getCoreSoulAdMaxTimes() - self:getCoreSoulAdTimes() if remainTimes < 0 then remainTimes = 0 end return remainTimes end -- 魂芯广告上限次数 function ShopData:getCoreSoulAdMaxTimes() return GFunc.getConstIntValue("summon_core_adtimes_1") end -- 魂芯大奖配置需要次数 function ShopData:getCoreSoulBigRewardConstTimes(idx) local cfg = ConfigManager:getConfig("summon_core") return cfg[idx].guarantee_times or 0 end -- 魂芯大奖需要次数 function ShopData:getCoreSoulBigRewardTimes(idx) local limit = self:getCoreSoulBigRewardConstTimes(idx) if limit == nil then limit = 66 end if idx == GConst.ShopConst.CORE_SOUL_TYPE.NORMAL then return limit - (self.coreSoulNormalRewardTimes or 0) else return limit - (self.coreSoulEliteRewardTimes or 0) end end --- 魂芯抽奖消耗道具id function ShopData:getCoreSoulCostItemId(idx) local cfgInfo = ConfigManager:getConfig("summon_core")[idx] local cost = cfgInfo.item_cost return cost and cost.id end --- 魂芯抽奖单抽消耗钻石数量 function ShopData:getCoreSoulSingleCostGemNum(idx) local cfgInfo = ConfigManager:getConfig("summon_core")[idx] local cost = cfgInfo.cost return cost and cost.num end --- 魂芯抽奖10连抽消耗钻石数量 function ShopData:getCoreSoulMultiCostGemNum(idx) local cfgInfo = ConfigManager:getConfig("summon_core")[idx] local cost = cfgInfo.cost_ten return cost and cost.num end function ShopData:onBuyCoreSoulBoxSuccess(idx, free, times, triggerCount) if idx == GConst.ShopConst.CORE_SOUL_TYPE.NORMAL then if free then self.coreSoulAdTimes = self.coreSoulAdTimes + times end self.coreSoulNormalRewardTimes = triggerCount else self.coreSoulEliteRewardTimes = triggerCount end self:setDirty() end -- 每日商店 ---------------------------------------------------------------------------------------------------------------------------------------- function ShopData:refreshDailyShop(data) if not data then return end if EDITOR_MODE then Logger.logHighlight("ShopData 每日商店") Logger.printTable(data) end self.dailyInfo = data self:setDirty() end function ShopData:getDailyConfig(id) if id then return ConfigManager:getConfig("mall_daily_store")[id] else return ConfigManager:getConfig("mall_daily_store") end end -- 获取每日免费刷新次数 function ShopData:getDailyRefreshFreeCount() return GFunc.getConstIntValue("mall_daily_free_refresh") or 0 end -- 获取每日广告刷新次数 function ShopData:getDailyRefreshAdCount() return GFunc.getConstIntValue("mall_daily_ad_refresh") or 0 end -- 获取每日道具刷新次数 function ShopData:getDailyRefreshCostCount() return GFunc.getConstIntValue("mall_daily_refresh") or 0 end -- 获取刷新道具 function ShopData:getDailyRefreshCost() return GFunc.getConstCost("mall_daily_refresh_cost") end -- 获取每日商店今日免费+钻石刷新次数 function ShopData:getDailyRefreshCount() return self.dailyInfo.refresh_count or 0 end -- 获取每日商店今日广告刷新次数 function ShopData:getDailyAdRefreshCount() return self.dailyInfo.ad_refresh_count or 0 end function ShopData:getDailyFreeRefreshRemainCount() return math.max(self:getDailyRefreshFreeCount() - self:getDailyRefreshCount(), 0) end function ShopData:getDailyAdRefreshRemainCount() return math.max(self:getDailyRefreshAdCount() - self:getDailyAdRefreshCount(), 0) end function ShopData:getDailyCostRefreshRemainCount() if self:getDailyFreeRefreshRemainCount() <= 0 then return math.max(self:getDailyRefreshCostCount() - (self:getDailyRefreshCount() - self:getDailyRefreshFreeCount()), 0) else return self:getDailyRefreshCostCount() end end -- 获取自动刷新倒计时 function ShopData:getDailyRefreshAutoTime() return Time:formatNumTimeStr(Time:getTodaySurplusTime()) end function ShopData:getDailyReward(id) if self.dailyInfo.grids then return self.dailyInfo.grids[id] end end function ShopData:getDailyCost(id) if self.dailyInfo.grids_cost then return self.dailyInfo.grids_cost[id] end end function ShopData:getDailyIdx(id) if self.dailyInfo.grids_index then return self.dailyInfo.grids_index[id] end end -- 剩余次数,包括免费与广告免费 function ShopData:getDailyRemainCount(id) local cfg = self:getDailyConfig(id) if not cfg then return 0 end local count = 0 if self.dailyInfo.daily_count then count = self.dailyInfo.daily_count[id] or 0 end return (cfg.limit or 0) + (cfg.limit_ad or 0) - count end function ShopData:getDailyCount(id) local cfg = self:getDailyConfig(id) if not cfg then return 0 end return (cfg.limit or 0) + (cfg.limit_ad or 0) end -- 剩余次数,只包括免费,不包括广告 function ShopData:getDailyRemainFreeCount(id) local cfg = self:getDailyConfig(id) if not cfg then return 0 end local count = 0 if self.dailyInfo.daily_count then count = self.dailyInfo.daily_count[id] or 0 end return (cfg.limit or 0) - count end function ShopData:getDailyLocked(id) local cfg = self:getDailyConfig(id) if not cfg or not cfg.unlock then return end if DataManager.ChapterData:getChapterPassed(cfg.unlock) then return end local str = DataManager.ChapterData:getChapterNameXYMode(cfg.unlock) return I18N:getGlobalText(I18N.GlobalConst.FUNC_OPEN_STAGE, str) end function ShopData:setLoginDailyRp() self.loginRpDaily = true end function ShopData:getLoginDailyRp() --@TODO 2025-09-24 15:10:19 -- if DataManager.PaymentData:getIsSkipAd() then -- return true -- end return not self.loginRpDaily end -- 钻石商店 ---------------------------------------------------------------------------------------------------------------------------------------- function ShopData:getGemConfig(id) if id then return ConfigManager:getConfig("mall_treasure")[id] else return ConfigManager:getConfig("mall_treasure") end end -- 金币商店 ---------------------------------------------------------------------------------------------------------------------------------------- function ShopData:refreshGoldShop(data) if not data then return end if EDITOR_MODE then Logger.logHighlight("ShopData 金币商店") Logger.printTable(data) end self.goldInfo = data self:setDirty() end function ShopData:getGoldConfig(id) if id then return ConfigManager:getConfig("mall_gold")[id] else return ConfigManager:getConfig("mall_gold") end end -- 广告次数 function ShopData:getBuyGoldAdCount(id) local cfg = self:getGoldConfig(id) return cfg and cfg.daily_ad or 0 end -- 获取剩余免费广告领取次数 function ShopData:getGoldBuyRemainCountByAd(id) local freeCount = self:getBuyGoldFreeCount(id) local adCount = self:getBuyGoldAdCount(id) return math.max(adCount + freeCount - self.goldInfo.count, 0) end -- 免费次数 function ShopData:getBuyGoldFreeCount(id) local cfg = self:getGoldConfig(id) return cfg and cfg.daily_free or 0 end -- 获取剩余免费领取次数 function ShopData:getGoldBuyRemainCountByFree(id) local freeCount = self:getBuyGoldFreeCount(id) return math.max(freeCount - self.goldInfo.count, 0) end function ShopData:onBuyGoldGiftSuccess(id) if id == 1 then -- 今日免费广告次数+1 self.goldInfo.count = self.goldInfo.count + 1 end self:setDirty() end function ShopData:setLoginGoldRp() self.loginRpGold = true end function ShopData:getLoginGoldRp() --@TODO 2025-09-24 15:10:19 -- if DataManager.PaymentData:getIsSkipAd() then -- return true -- end return not self.loginRpGold end -- 神话星辉 ---------------------------------------------------------------------------------------------------------------------------------------- function ShopData:refreshEmblemShop(data) if not data then return end if EDITOR_MODE then Logger.logHighlight("ShopData 星辉商店") Logger.printTable(data) end self.emblemInfo = data or {} self:setDirty() end function ShopData:getEmblemConfig(id) if id then return ConfigManager:getConfig("mall_mythic_emblem")[id] else return ConfigManager:getConfig("mall_mythic_emblem") end end function ShopData:isEmblemOpen(showToast) if not self:isOpen(showToast) then return false end if not ModuleManager:getIsOpen(ModuleManager.MODULE_KEY.MALL_EMBLEM, not showToast) then return false end return true end function ShopData:getEmblemLimitCount(id) local cfg = self:getEmblemConfig(id) if not cfg or not cfg.daily_limit then return 0 end return cfg.daily_limit end function ShopData:getEmblemBoughtCount(id) return self.emblemInfo.today_count[id] or 0 end function ShopData:getEmblemRemainCount(id) return self:getEmblemLimitCount(id) - self:getEmblemBoughtCount(id) end function ShopData:onBuyEmblemGiftSuccess(id) self.emblemInfo.total_count[id] = (self.emblemInfo.total_count[id] or 0) + 1 self.emblemInfo.today_count[id] = (self.emblemInfo.today_count[id] or 0) + 1 self:setDirty() end -- 首充礼包 ---------------------------------------------------------------------------------------------------------------------------------------- function ShopData:isFirstRechargeOpen(gear) if GFunc.isShenhe() then return false end if gear then local boughtLast = gear > 1 and self:getFirstRechargeRewardDays(gear - 1) > 0 -- 时间到了 & 没购买上一档 if not ModuleManager:getIsOpen(ModuleManager.MODULE_KEY["FIRST_CHARGE_" .. gear], true) and not boughtLast then return false end for day = 1, 3 do if not self:isBoughtFirstRecharge(gear, day) or self:getFirstRechargeRewardDays(gear) < 3 then -- 特殊处理一下首充3,正常逻辑如果购买了首充1,那么就开首充2,但是如果购买了首充2,首充3还要额外判断一下配置的等级条件是否达到了 if gear == 3 and not ModuleManager:getIsOpen(ModuleManager.MODULE_KEY.FIRST_CHARGE_3, true) and boughtLast then local cfg = ConfigManager:getConfig("func_open")[ModuleManager.MODULE_KEY.FIRST_CHARGE_3] if cfg.level then local isOpen = DataManager.PlayerData:getLv() >= cfg.level if not isOpen then return false end elseif cfg.stage then local isOpen = DataManager.ChapterData:getChapterPassed(cfg.stage) if not isOpen then return false end end end return true end end else for k, gear in pairs(GConst.ShopConst.FIRST_RECHARGE_GEARS) do if self:isFirstRechargeOpen(gear) then return true end end end return false end -- 开启了几个首冲档位 function ShopData:getFirstRechargeOpenCount() local count = 0 for k, gear in pairs(GConst.ShopConst.FIRST_RECHARGE_GEARS) do if self:isFirstRechargeOpen(gear) then count = count + 1 end end return count end -- 红点 function ShopData:hasFirstRechargeRedPoint() for k, gear in pairs(GConst.ShopConst.FIRST_RECHARGE_GEARS) do local boughtDay = self:getFirstRechargeBoughtDays(gear) local rewardDay = self:getFirstRechargeRewardDays(gear) if boughtDay > 0 and rewardDay < 3 and boughtDay > rewardDay then return true end end return false end function ShopData:getNeedShowFirstRechargePop() -- if not self:isFirstRechargeOpen() then -- return false -- end -- 如果可以领的奖励都领完了也不弹了 local openCount = 0 local canGetCount = 0 for k, gear in pairs(GConst.ShopConst.FIRST_RECHARGE_GEARS) do if self:isFirstRechargeOpen(gear) then openCount = openCount + 1 local boughtDay = self:getFirstRechargeBoughtDays(gear) local rewardDay = self:getFirstRechargeRewardDays(gear) if boughtDay > 0 and boughtDay <= rewardDay then -- 已经领取过了不用弹了 canGetCount = canGetCount + 1 end end end if openCount == canGetCount then -- 功能没开,或者开启了的首充都已经领取完了 return false end return not self.firstRechargePoped end function ShopData:setFirstrechargePoped() self.firstRechargePoped = true end -- 获取档位id function ShopData:getFirstRechargeGiftId(gear, day) return GConst.ShopConst.FIRST_RECHARGE_ID[gear][day or 1] end -- 获取档位购买状态 function ShopData:isBoughtFirstRecharge(gear, day) return DataManager.PaymentData:getGiftBoughtNum(PayManager.PURCHARSE_TYPE.ACT_GIFT, self:getFirstRechargeGiftId(gear, day)) > 0 end -- 档位奖励领取天数 function ShopData:getFirstRechargeRewardDays(gear) if not self:isBoughtFirstRecharge(gear) then return 0 end local getDay = 0 for day = 1, 3 do if DataManager.PaymentData:getGiftBoughtNum(PayManager.PURCHARSE_TYPE.ACT_GIFT, self:getFirstRechargeGiftId(gear, day)) > 0 then getDay = day end end return getDay end -- 购买天数 function ShopData:getFirstRechargeBoughtDays(gear) if not self:isBoughtFirstRecharge(gear) then return 0 end local time = DataManager.PaymentData:getGiftBoughtTime(PayManager.PURCHARSE_TYPE.ACT_GIFT, self:getFirstRechargeGiftId(gear)) if time == nil or time <= 0 then return 0 end local day = Time:getDayBeginTimeStamp(time) day = (Time:getBeginningOfServerToday() - day) // 86400 return day + 1 end -- 是否可领取 function ShopData:canGetFirstRechargeReward(gear, day) if not self:isBoughtFirstRecharge(gear) then return false end if self:isBoughtFirstRecharge(gear, day) then return false end local boughtDay = self:getFirstRechargeBoughtDays(gear) local rewardDay = self:getFirstRechargeRewardDays(gear) return boughtDay > rewardDay and rewardDay + 1 == day end -- 体力 ---------------------------------------------------------------------------------------------------------------------------------------- function ShopData:initVit(data) data = data or {} if EDITOR_MODE then Logger.logHighlight("体力数据") Logger.printTable(data) end self.vitAdCount = data.ad_count or 0 self.vitGemCount = data.diamond_count or 0 end -- 获取体力购买奖励 function ShopData:getVitBuyReward(buyType) if buyType == GConst.VIT_BUY_TYPE.AD then return GFunc.getConstCost("stamina_ad_buy") elseif buyType == GConst.VIT_BUY_TYPE.GEM then return GFunc.getConstCost("stamina_diamond_buy") end return nil end -- 获取体力购买消耗 function ShopData:getVitBuyCost(buyType) if buyType == GConst.VIT_BUY_TYPE.GEM then local cost = GFunc.getConstCost("stamina_diamond_cost") local costAdd = GFunc.getConstCost("stamina_diamond_costadd") if self._shopVitCost == nil then self._shopVitCost = { id = cost.id, type = cost.type, } end self._shopVitCost.num = cost.num + self.vitGemCount * costAdd.num return self._shopVitCost end return nil end -- 获取体力每日购买次数 function ShopData:getVitBuyLimit(buyType) if buyType == GConst.VIT_BUY_TYPE.AD then return GFunc.getConstIntValue("stamina_ad_times") elseif buyType == GConst.VIT_BUY_TYPE.GEM then return GFunc.getConstIntValue("stamina_diamond_times") end return 0 end -- 获取体力每日购买次数(月卡加成) function ShopData:getVitBuyPrivateLimit(buyType) if buyType == GConst.VIT_BUY_TYPE.GEM then return GFunc.getConstIntValue("stamina_dia_privilege") end return 0 end -- 获取体力今日已购买次数 function ShopData:getVitBoughtCount(buyType) if buyType == GConst.VIT_BUY_TYPE.AD then return self.vitAdCount or 0 elseif buyType == GConst.VIT_BUY_TYPE.GEM then return self.vitGemCount or 0 end return 0 end -- 获取剩余购买次数 function ShopData:getVitBuyRemainCount(buyType) if buyType == GConst.VIT_BUY_TYPE.AD then local total = self:getVitBuyLimit(buyType) -- if DataManager.MonthlyCardData:getIsCardActive(GConst.MonthlyCardConst.CARD_TYPE.CARD_2) then -- total = total + self:getVitBuyPrivateLimit(buyType) -- end return total - self:getVitBoughtCount(buyType) elseif buyType == GConst.VIT_BUY_TYPE.GEM then return 99999 end return 0 end function ShopData:onVitBuySuccess(data) self:initVit(data) self:setDirty() end -- region 三方直接购买礼包 function ShopData:onServerPushThirdPay(data) if data then self:initThirdPayOrder(data) self:initThirdPayGiftOrder(data) if data.third_pay_total then DataManager.PaymentData:setThirdPayTotal(data.third_pay_total) end end end function ShopData:initThirdPayGiftOrder(data) self.thirdPayGifts = data and data.gifts if self:getNeedShowGiftReceiveUI() then self.data.isThirdPayGiftDirty = not self.data.isThirdPayGiftDirty end end function ShopData:getNeedShowGiftReceiveUI() if self.thirdPayGifts == nil then return false end return #self.thirdPayGifts > 0 end function ShopData:getThirdPayGiftOrders() return self.thirdPayGifts or GConst.EMPTY_TABLE end function ShopData:getThirdPayGiftOrderInfo(order) if self.thirdPayGifts == nil then return end for k, v in ipairs(self.thirdPayGifts) do if v.order_id == order then return v end end end function ShopData:deleteThirdPayGiftOrders(orders) for i = #orders, 1, -1 do for j = #self.thirdPayGifts, 1, -1 do if orders[i] == self.thirdPayGifts[j].order_id then table.remove(self.thirdPayGifts, j) break end end end end --@endregion -- 代金券 ---------------------------------------------------------------------------------------------------------------------------------------- function ShopData:initThirdPayOrder(data) if EDITOR_MODE then Logger.logHighlight("ShopData 代金券") Logger.printTable(data) end self.thirdPayOrder = data and data.orders end function ShopData:getNeedShowVoucherReceiveUI() if self.thirdPayOrder == nil then return false end return #self.thirdPayOrder > 0 end function ShopData:getThirdPayOrders() return self.thirdPayOrder or GConst.EMPTY_TABLE end function ShopData:getThirdPayOrderInfo(order) if self.thirdPayOrder == nil then return end for k, v in ipairs(self.thirdPayOrder) do if v.order_id == order then return v end end end function ShopData:deleteThirdPayOrders(orders) for i = #orders, 1, -1 do for j = #self.thirdPayOrder, 1, -1 do if orders[i] == self.thirdPayOrder[j].order_id then table.remove(self.thirdPayOrder, j) break end end end end return ShopData