local ____lualib = require("lualib_bundle") local Map = ____lualib.Map local __TS__New = ____lualib.__TS__New local Set = ____lualib.Set local __TS__Number = ____lualib.__TS__Number local __TS__ArrayIsArray = ____lualib.__TS__ArrayIsArray local __TS__ObjectAssign = ____lualib.__TS__ObjectAssign local __TS__NumberIsFinite = ____lualib.__TS__NumberIsFinite local __TS__ObjectEntries = ____lualib.__TS__ObjectEntries local __TS__ArrayFilter = ____lualib.__TS__ArrayFilter local __TS__ArrayIncludes = ____lualib.__TS__ArrayIncludes local __TS__ArrayEvery = ____lualib.__TS__ArrayEvery local ____exports = {} local getPurchasableCardPool, getPurchasablePoolByQuality, pickCardExactQuality, purchasableCardPoolCache, purchasablePoolByQualityCache, ARCADE_PACK_QUALITY_PICK_ATTEMPTS local ____card_catalog = require("card_catalog") local ALL_CARD_CATALOG_DEFS = ____card_catalog.ALL_CARD_CATALOG_DEFS local ____CardSystem = require("cards.CardSystem") local CardQuality = ____CardSystem.CardQuality local CardSystem = ____CardSystem.CardSystem local ____custom_game_events = require("custom_game_events") local ensurePlayerCardSystem = ____custom_game_events.ensurePlayerCardSystem local ____api_helper = require("api_helper") local encodeApiBody = ____api_helper.encodeApiBody local setApiHeaders = ____api_helper.setApiHeaders local ____player_info = require("player_info") local PlayerInfo = ____player_info.PlayerInfo local ____server_config = require("server_config") local SERVER_CONFIG = ____server_config.SERVER_CONFIG local ____store_manager = require("store_manager") local StoreManager = ____store_manager.StoreManager function getPurchasableCardPool(self) if purchasableCardPoolCache and #purchasableCardPoolCache > 0 then return purchasableCardPoolCache end local pool = {} for ____, def in ipairs(ALL_CARD_CATALOG_DEFS) do do local id = math.floor(__TS__Number(def.id)) if not __TS__NumberIsFinite(id) or id <= 0 or id == 404 then goto __continue46 end if def.defaultCard == true or def.purchasable == false then goto __continue46 end local runtimeData = CardSystem.cardData[id] if (runtimeData and runtimeData.disabled) == true then goto __continue46 end pool[#pool + 1] = id end ::__continue46:: end if #pool == 0 then for ____, ____value in ipairs(__TS__ObjectEntries(CardSystem.cardData)) do local idKey = ____value[1] local data = ____value[2] do local id = math.floor(__TS__Number(idKey)) if not __TS__NumberIsFinite(id) or id <= 0 or data.disabled == true or data.default == true or data.purchasable == false then goto __continue52 end pool[#pool + 1] = id end ::__continue52:: end end purchasableCardPoolCache = pool purchasablePoolByQualityCache = nil return pool end function getPurchasablePoolByQuality(self) if purchasablePoolByQualityCache then return purchasablePoolByQualityCache end local byQuality = {} for ____, cardId in ipairs(getPurchasableCardPool(nil)) do local cardData = CardSystem.cardData[cardId] local quality = math.max( CardQuality.COMMON, math.min( CardQuality.MYTHIC, math.floor(__TS__Number(cardData and cardData.quality or CardQuality.COMMON)) ) ) if not byQuality[quality] then byQuality[quality] = {} end local ____byQuality_quality_11 = byQuality[quality] ____byQuality_quality_11[#____byQuality_quality_11 + 1] = cardId end purchasablePoolByQualityCache = byQuality return byQuality end function pickCardExactQuality(self, quality, excludeIds) local pool = getPurchasablePoolByQuality(nil)[quality] if not pool or #pool == 0 then return nil end local exclude = __TS__New(Set, excludeIds) local available = __TS__ArrayFilter( pool, function(____, id) return not exclude:has(id) end ) local pickFrom = #available > 0 and available or pool return pickFrom[RandomInt(0, #pickFrom - 1) + 1] end ____exports.ARCADE_PACK_DEFINITIONS = {arcade_pack_standard = {id = "arcade_pack_standard", cardsCount = 3, price_free = 25000, allowed_currencies = {"free_currency"}}, arcade_pack_premium = {id = "arcade_pack_premium", cardsCount = 3, price_donate = 80, allowed_currencies = {"donate_currency"}}} --- Пороги pity: паков подряд без редкости → гарантия в следующем паке. local ARCADE_PITY_STANDARD_MYTHIC_PACKS = 100 local ARCADE_PITY_STANDARD_LEGENDARY_PACKS = 50 local ARCADE_PITY_PREMIUM_MYTHIC_PACKS = 10 local ARCADE_SESSION_TTL_SECONDS = 600 local sessionsByPlayerId = __TS__New(Map) local arcadePityByPlayerId = __TS__New(Map) local arcadePityLoadedFromBackend = __TS__New(Set) local function defaultArcadePityState(self) return {standardPacksWithoutMythic = 0, standardPacksWithoutLegendary = 0, premiumPacksWithoutMythic = 0} end local function normalizeArcadePityState(self, raw) local state = defaultArcadePityState(nil) if not raw or type(raw) ~= "table" then return state end local obj = raw state.standardPacksWithoutMythic = math.max( 0, math.floor(__TS__Number(obj.standardPacksWithoutMythic) or 0) ) local ____math_max_2 = math.max local ____math_floor_1 = math.floor local ____obj_standardPacksWithoutLegendary_0 = obj.standardPacksWithoutLegendary if ____obj_standardPacksWithoutLegendary_0 == nil then ____obj_standardPacksWithoutLegendary_0 = obj.standardPacksWithoutEpic end state.standardPacksWithoutLegendary = ____math_max_2( 0, ____math_floor_1(__TS__Number(____obj_standardPacksWithoutLegendary_0) or 0) ) state.premiumPacksWithoutMythic = math.max( 0, math.floor(__TS__Number(obj.premiumPacksWithoutMythic) or 0) ) return state end local function decodeJsonBody(self, body) do local function ____catch() return true, nil end local ____try, ____hasReturned, ____returnValue = pcall(function() return true, {json.decode(body)} end) if not ____try then ____hasReturned, ____returnValue = ____catch() end if ____hasReturned then return ____returnValue end end end local function unwrapApiJsonObject(self, decoded) if __TS__ArrayIsArray(decoded) and #decoded > 0 then return decoded[1] end return decoded end local function parseArcadePityPayload(self, raw) if not raw or type(raw) ~= "table" then return nil end local root = raw local pityRaw = root.arcade_pity if pityRaw == nil or pityRaw == nil then return normalizeArcadePityState(nil, nil) end return normalizeArcadePityState(nil, pityRaw) end local function applyArcadePityState(self, playerId, state) arcadePityByPlayerId:set(playerId, state) local info = PlayerInfo:GetPlayerInfo(playerId) or ({}) PlayerInfo:UpdatePlayerInfo( playerId, __TS__ObjectAssign({}, info, {arcade_pity = state}) ) end local function saveArcadePityToBackend(self, playerId, state) local steamId = PlayerResource:GetSteamAccountID(playerId) if not steamId then return end local request = CreateHTTPRequestScriptVM( "PUT", ((SERVER_CONFIG.API_URL .. "/player/") .. tostring(steamId)) .. "/arcade_pity" ) setApiHeaders(nil, request) request:SetHTTPRequestRawPostBody( "application/json", encodeApiBody(nil, {arcade_pity = state}) ) request:Send(function(result) if result.StatusCode < 200 or result.StatusCode >= 300 then print((((("[ARCADE_PITY] PUT fail player=" .. tostring(playerId)) .. " steam=") .. tostring(steamId)) .. " code=") .. tostring(result.StatusCode)) end end) end --- Загрузить pity с бэка при входе в игру / реконнект. function ____exports.loadArcadePityForPlayer(self, playerId) local steamId = PlayerResource:GetSteamAccountID(playerId) if not steamId then return end local request = CreateHTTPRequestScriptVM( "GET", ((SERVER_CONFIG.API_URL .. "/player/") .. tostring(steamId)) .. "/arcade_pity" ) setApiHeaders(nil, request) request:Send(function(result) if result.StatusCode < 200 or result.StatusCode >= 300 then print((((("[ARCADE_PITY] GET fail player=" .. tostring(playerId)) .. " steam=") .. tostring(steamId)) .. " code=") .. tostring(result.StatusCode)) return end local bodyStr = result.Body ~= nil and tostring(result.Body) or "" if #bodyStr == 0 then return end local decoded = decodeJsonBody(nil, bodyStr) local obj = unwrapApiJsonObject(nil, decoded) local state = parseArcadePityPayload(nil, obj) if state == nil then print((("[ARCADE_PITY] GET parse invalid player=" .. tostring(playerId)) .. " steam=") .. tostring(steamId)) return end arcadePityLoadedFromBackend:add(playerId) applyArcadePityState(nil, playerId, state) print((((((("[ARCADE_PITY] GET ok player=" .. tostring(playerId)) .. " stdM=") .. tostring(state.standardPacksWithoutMythic)) .. " stdL=") .. tostring(state.standardPacksWithoutLegendary)) .. " premM=") .. tostring(state.premiumPacksWithoutMythic)) end) end local function getArcadePityState(self, playerId) local state = arcadePityByPlayerId:get(playerId) if not state then local info = PlayerInfo:GetPlayerInfo(playerId) state = normalizeArcadePityState(nil, info and info.arcade_pity) arcadePityByPlayerId:set(playerId, state) end return state end local function saveArcadePityState(self, playerId, state) applyArcadePityState(nil, playerId, state) saveArcadePityToBackend(nil, playerId, state) end local function getCardQualityForPity(self, cardId) local cardData = CardSystem.cardData[cardId] return math.max( CardQuality.COMMON, math.min( CardQuality.MYTHIC, math.floor(__TS__Number(cardData and cardData.quality or CardQuality.COMMON)) ) ) end local function packHasMythic(self, cardIds) for ____, cardId in ipairs(cardIds) do if getCardQualityForPity(nil, cardId) == CardQuality.MYTHIC then return true end end return false end local function packHasLegendaryOrBetter(self, cardIds) for ____, cardId in ipairs(cardIds) do if getCardQualityForPity(nil, cardId) >= CardQuality.LEGENDARY then return true end end return false end local function buildArcadePityPlan(self, packId, state) local plan = {} local slot = 0 if packId == "arcade_pack_premium" then if state.premiumPacksWithoutMythic >= ARCADE_PITY_PREMIUM_MYTHIC_PACKS then plan.mythicSlot = slot slot = slot + 1 end return plan end if state.standardPacksWithoutMythic >= ARCADE_PITY_STANDARD_MYTHIC_PACKS then plan.mythicSlot = slot slot = slot + 1 end if state.standardPacksWithoutLegendary >= ARCADE_PITY_STANDARD_LEGENDARY_PACKS then plan.legendarySlot = slot slot = slot + 1 end return plan end local function pickCardForcedQuality(self, quality, excludeIds) do local attempt = 0 while attempt < ARCADE_PACK_QUALITY_PICK_ATTEMPTS do local cardId = pickCardExactQuality(nil, quality, excludeIds) if cardId ~= nil then return cardId end attempt = attempt + 1 end end return nil end --- Шансы редкости карты в паке аркады (сумма = 100%, шкала 1..10000). local ARCADE_PACK_QUALITY_ROLL_MAX = 10000 local ARCADE_PACK_STANDARD_QUALITY_THRESHOLDS = { {quality = CardQuality.COMMON, cumulative = 5500}, {quality = CardQuality.RARE, cumulative = 8000}, {quality = CardQuality.EPIC, cumulative = 9500}, {quality = CardQuality.LEGENDARY, cumulative = 9980}, {quality = CardQuality.MYTHIC, cumulative = 10000} } --- Премиум-пак: только эпик / легендарка / мифик. local ARCADE_PACK_PREMIUM_QUALITY_THRESHOLDS = {{quality = CardQuality.EPIC, cumulative = 6000}, {quality = CardQuality.LEGENDARY, cumulative = 9800}, {quality = CardQuality.MYTHIC, cumulative = 10000}} ARCADE_PACK_QUALITY_PICK_ATTEMPTS = 64 local function getArcadePackQualityWeights(self, packId) local thresholds = packId == "arcade_pack_premium" and ARCADE_PACK_PREMIUM_QUALITY_THRESHOLDS or ARCADE_PACK_STANDARD_QUALITY_THRESHOLDS local weights = {} local prevCumulative = 0 for ____, entry in ipairs(thresholds) do weights[#weights + 1] = {quality = entry.quality, weight = entry.cumulative - prevCumulative} prevCumulative = entry.cumulative end return weights end local function rollArcadePackQualityFromWeights(self, weights) local total = 0 for ____, w in ipairs(weights) do total = total + w.weight end if total <= 0 then local ____opt_12 = weights[#weights] return ____opt_12 and ____opt_12.quality or CardQuality.COMMON end local roll = RandomInt(1, total) for ____, w in ipairs(weights) do if roll <= w.weight then return w.quality end roll = roll - w.weight end return weights[#weights].quality end --- Редкости, для которых в каталоге есть хотя бы одна карта. local function getStockedQualityWeights(self, packId) local minQuality = packId == "arcade_pack_premium" and CardQuality.EPIC or CardQuality.COMMON local byQuality = getPurchasablePoolByQuality(nil) return __TS__ArrayFilter( getArcadePackQualityWeights(nil, packId), function(____, entry) if entry.quality < minQuality then return false end local pool = byQuality[entry.quality] return pool ~= nil and #pool > 0 end ) end --- Сначала бросок по таблице шансов → карта строго этой редкости. -- Если пул пуст — повторный бросок (без понижения/повышения тира). local function pickRandomCardForPack(self, packId, excludeIds) local tableWeights = getArcadePackQualityWeights(nil, packId) do local attempt = 0 while attempt < ARCADE_PACK_QUALITY_PICK_ATTEMPTS do local rolledQuality = rollArcadePackQualityFromWeights(nil, tableWeights) local cardId = pickCardExactQuality(nil, rolledQuality, excludeIds) if cardId ~= nil then return cardId end attempt = attempt + 1 end end local stockedWeights = getStockedQualityWeights(nil, packId) if #stockedWeights == 0 then return nil end do local attempt = 0 while attempt < ARCADE_PACK_QUALITY_PICK_ATTEMPTS do local rolledQuality = rollArcadePackQualityFromWeights(nil, stockedWeights) local cardId = pickCardExactQuality(nil, rolledQuality, excludeIds) if cardId ~= nil then return cardId end attempt = attempt + 1 end end return nil end local function rollRandomCardIds(self, count, packId, pityPlan) if #getPurchasableCardPool(nil) == 0 then return {} end local forcedBySlot = __TS__New(Map) if (pityPlan and pityPlan.mythicSlot) ~= nil and pityPlan.mythicSlot < count then forcedBySlot:set(pityPlan.mythicSlot, CardQuality.MYTHIC) end if (pityPlan and pityPlan.legendarySlot) ~= nil and pityPlan.legendarySlot < count and not forcedBySlot:has(pityPlan.legendarySlot) then forcedBySlot:set(pityPlan.legendarySlot, CardQuality.LEGENDARY) end local result = {} do local slot = 0 while slot < count do local forcedQuality = forcedBySlot:get(slot) local cardId if forcedQuality ~= nil then cardId = pickCardForcedQuality(nil, forcedQuality, result) end if cardId == nil then cardId = pickRandomCardForPack(nil, packId, result) end if cardId ~= nil then result[#result + 1] = cardId end slot = slot + 1 end end return result end local function clearExpiredSession(self, playerId) local session = sessionsByPlayerId:get(playerId) if not session then return end if GameRules:GetGameTime() - session.createdAt > ARCADE_SESSION_TTL_SECONDS then sessionsByPlayerId:delete(playerId) end end local function updateArcadePityAfterPack(self, playerId, packId, cardIds) local state = getArcadePityState(nil, playerId) local gotMythic = packHasMythic(nil, cardIds) local gotLegendaryPlus = packHasLegendaryOrBetter(nil, cardIds) if packId == "arcade_pack_premium" then state.premiumPacksWithoutMythic = gotMythic and 0 or state.premiumPacksWithoutMythic + 1 else state.standardPacksWithoutMythic = gotMythic and 0 or state.standardPacksWithoutMythic + 1 state.standardPacksWithoutLegendary = gotLegendaryPlus and 0 or state.standardPacksWithoutLegendary + 1 end saveArcadePityState(nil, playerId, state) end local function sendArcadeEvent(self, playerId, eventName, payload) local player = PlayerResource:GetPlayer(playerId) if not player then return end CustomGameEventManager:Send_ServerToPlayer(player, eventName, payload) end local function resolvePackPrice(self, pack, currency) if currency == "dust_currency" and pack.price_dust ~= nil then return math.floor(pack.price_dust) end if currency == "donate_currency" and pack.price_donate ~= nil then return math.floor(pack.price_donate) end if currency == "free_currency" and pack.price_free ~= nil then return math.floor(pack.price_free) end return -1 end local function deductCurrency(self, store, playerId, currency, price) if price <= 0 then return true end if currency == "free_currency" then return store:removeFreeCurrency(playerId, price) end if currency == "donate_currency" then return store:removeDonateCurrency(playerId, price) end if currency == "dust_currency" then return store:removeDustCurrency(playerId, price) end return false end local function refundCurrency(self, store, playerId, currency, price) if price <= 0 then return end if currency == "free_currency" then store:addFreeCurrency(playerId, price) elseif currency == "donate_currency" then store:addDonateCurrency(playerId, price) elseif currency == "dust_currency" then store:addDustCurrency(playerId, price) end end local function defaultArcadePackCredits(self) return {standard = 0, premium = 0} end local function normalizeArcadePackCredits(self, raw) local state = defaultArcadePackCredits(nil) if not raw or type(raw) ~= "table" then return state end local obj = raw state.standard = math.max( 0, math.floor(__TS__Number(obj.standard) or 0) ) state.premium = math.max( 0, math.floor(__TS__Number(obj.premium) or 0) ) return state end local function applyArcadePackCredits(self, playerId, credits) local info = PlayerInfo:GetPlayerInfo(playerId) or ({}) PlayerInfo:UpdatePlayerInfo( playerId, __TS__ObjectAssign({}, info, {arcade_pack_credits = credits}) ) end local function getLocalArcadePackCredits(self, playerId) local info = PlayerInfo:GetPlayerInfo(playerId) return normalizeArcadePackCredits(nil, info and info.arcade_pack_credits) end local function getArcadePackCreditKey(self, packId) if packId == "arcade_pack_standard" then return "standard" end if packId == "arcade_pack_premium" then return "premium" end return nil end local function tryConsumeArcadePackCredit(self, playerId, packId, onDone) local creditKey = getArcadePackCreditKey(nil, packId) if not creditKey then onDone(nil, false) return end local ____local = getLocalArcadePackCredits(nil, playerId) if ____local[creditKey] <= 0 then onDone(nil, false) return end local steamId = PlayerResource:GetSteamAccountID(playerId) if not steamId then onDone(nil, false) return end local request = CreateHTTPRequestScriptVM( "POST", ((SERVER_CONFIG.API_URL .. "/player/") .. tostring(steamId)) .. "/arcade_pack_credits/consume" ) setApiHeaders(nil, request) request:SetHTTPRequestRawPostBody( "application/json", encodeApiBody(nil, {pack_id = packId}) ) request:Send(function(result) if result.StatusCode < 200 or result.StatusCode >= 300 then onDone(nil, false) return end do local ____try, ____hasReturned, ____returnValue = pcall(function() local decoded = decodeJsonBody(nil, result.Body) local data = unwrapApiJsonObject(nil, decoded) if (data and data.consumed) == true and data.arcade_pack_credits then local credits = normalizeArcadePackCredits(nil, data.arcade_pack_credits) applyArcadePackCredits(nil, playerId, credits) onDone(nil, true) return true end end) if ____try and ____hasReturned then return ____returnValue end end onDone(nil, false) end) end local function getCardLevelForPlayer(self, playerId, cardId) local cardSystem = ensurePlayerCardSystem(nil, playerId) if not cardSystem then return 1 end local level = cardSystem:GetCardLevel(cardId) return __TS__NumberIsFinite(level) and math.max( 1, math.floor(level) ) or 1 end local function buildFlipPayload(self, playerId, cardId, slotIndex) local cardData = CardSystem.cardData[cardId] local quality = math.max( 1, math.floor(__TS__Number(cardData and cardData.quality or CardQuality.COMMON)) ) local cardLevel = getCardLevelForPlayer(nil, playerId, cardId) local store = StoreManager:getInstance() local ownedBefore = store:getOwnedCardCopies(playerId, cardId) local maxCopies = store:getCardMaxCopies(cardId) local isDuplicate = ownedBefore >= maxCopies local dustGranted = 0 if isDuplicate then dustGranted = CardSystem:getDuplicateCardDustCompensation(quality, cardLevel) if dustGranted > 0 then store:addDustCurrency(playerId, dustGranted) store:saveCurrencyToServer(playerId) end else store:grantCardPurchaseWithoutPayment(playerId, cardId) end local rawIcon = cardData and cardData.icon local icon = rawIcon ~= nil and #tostring(rawIcon) > 0 and tostring(rawIcon) or ("file://{images}/custom_game/cards/card_" .. tostring(cardId)) .. ".png" local rawCardName = cardData and cardData.name local cardName = rawCardName ~= nil and #tostring(rawCardName) > 0 and tostring(rawCardName) or ("card_" .. tostring(cardId)) .. "_name" return { slot_index = slotIndex, card_id = cardId, duplicate = isDuplicate and 1 or 0, dust_granted = dustGranted, card_level = cardLevel, quality = quality, icon = icon, card_name = cardName } end --- Выдать все карты пака сразу (порядок слотов важен для дубликатов). local function grantArcadePackCards(self, playerId, cardIds) local payloads = {} do local i = 0 while i < #cardIds do payloads[#payloads + 1] = buildFlipPayload(nil, playerId, cardIds[i + 1], i) i = i + 1 end end return payloads end local function handleBuyArcadePack(self, playerId, packId, selectedCurrency) local pack = ____exports.ARCADE_PACK_DEFINITIONS[packId] local store = StoreManager:getInstance() if not pack then store:sendPurchaseResult(playerId, false, "Неизвестный пак") return end if not store:tryAcquireStorePurchaseLock(playerId) then store:sendPurchaseResult(playerId, false, "Подождите, предыдущая покупка обрабатывается") return end store:syncLatestCurrencyTotalsFromApi( playerId, function(____, currencyOk) do local function ____catch() store:releaseStorePurchaseLock(playerId) end local ____try, ____hasReturned, ____returnValue = pcall(function() if not currencyOk then store:sendPurchaseResult(playerId, false, "Не удалось проверить баланс") store:releaseStorePurchaseLock(playerId) return true end if not arcadePityLoadedFromBackend:has(playerId) then ____exports.loadArcadePityForPlayer(nil, playerId) end clearExpiredSession(nil, playerId) if sessionsByPlayerId:has(playerId) then store:sendPurchaseResult(playerId, false, "Сначала откройте карты из текущего пака") store:releaseStorePurchaseLock(playerId) return true end tryConsumeArcadePackCredit( nil, playerId, packId, function(____, usedCredit) do local ____try, ____hasReturned, ____returnValue = pcall(function() local currency = selectedCurrency or pack.allowed_currencies[1] or "dust_currency" if not usedCredit and not __TS__ArrayIncludes(pack.allowed_currencies, currency) then store:sendPurchaseResult(playerId, false, "Эта валюта недоступна для пака") return true end local price = usedCredit and 0 or resolvePackPrice(nil, pack, currency) if price < 0 then store:sendPurchaseResult(playerId, false, "Некорректная цена пака") return true end local pityState = getArcadePityState(nil, playerId) local pityPlan = buildArcadePityPlan(nil, pack.id, pityState) local cardIds = rollRandomCardIds(nil, pack.cardsCount, pack.id, pityPlan) if #cardIds < pack.cardsCount then store:sendPurchaseResult(playerId, false, "Нет доступных карт для пака") return true end if not usedCredit and not deductCurrency( nil, store, playerId, currency, price ) then store:sendPurchaseResult(playerId, false, "Недостаточно валюты") return true end if not usedCredit then store:advanceCurrencyLoadSeq(playerId) store:saveCurrencyToServer(playerId) else store:notifyArcadePackCredits(playerId) end store:updateCurrencyDisplay(playerId) local flipPayloads = grantArcadePackCards(nil, playerId, cardIds) updateArcadePityAfterPack(nil, playerId, pack.id, cardIds) store:updateCurrencyDisplay(playerId) local session = { packId = pack.id, flipPayloads = flipPayloads, revealed = {}, createdAt = GameRules:GetGameTime() } do local i = 0 while i < pack.cardsCount do local ____session_revealed_28 = session.revealed ____session_revealed_28[#____session_revealed_28 + 1] = false i = i + 1 end end sessionsByPlayerId:set(playerId, session) local successMessage = usedCredit and "Открыт бесплатный пак из бандла" or "Пак куплен" store:sendPurchaseResult(playerId, true, successMessage, pack.id) sendArcadeEvent(nil, playerId, "store_arcade_pack_opened", {pack_id = pack.id, slot_count = pack.cardsCount, cards = flipPayloads, used_bundle_credit = usedCredit and 1 or 0}) end) do store:releaseStorePurchaseLock(playerId) end if ____try and ____hasReturned then return ____returnValue end end end ) end) if not ____try then ____hasReturned, ____returnValue = ____catch() end if ____hasReturned then return ____returnValue end end end ) end local function handleFlipArcadeCard(self, playerId, slotIndexRaw) clearExpiredSession(nil, playerId) local session = sessionsByPlayerId:get(playerId) if not session then sendArcadeEvent(nil, playerId, "store_arcade_flip_result", {success = 0, message = "Нет активного пака"}) return end local slotIndex = math.floor(__TS__Number(slotIndexRaw)) if not __TS__NumberIsFinite(slotIndex) or slotIndex < 0 or slotIndex >= #session.flipPayloads then sendArcadeEvent(nil, playerId, "store_arcade_flip_result", {success = 0, message = "Некорректная карта"}) return end if session.revealed[slotIndex + 1] then sendArcadeEvent(nil, playerId, "store_arcade_flip_result", {success = 0, message = "Карта уже открыта"}) return end session.revealed[slotIndex + 1] = true local flipPayload = session.flipPayloads[slotIndex + 1] sendArcadeEvent( nil, playerId, "store_arcade_flip_result", __TS__ObjectAssign({success = 1}, flipPayload) ) local allRevealed = __TS__ArrayEvery( session.revealed, function(____, v) return v == true end ) if allRevealed then sessionsByPlayerId:delete(playerId) sendArcadeEvent(nil, playerId, "store_arcade_pack_complete", {pack_id = session.packId}) end end local function setupStoreArcadePackListeners(self) CustomGameEventManager:RegisterListener( "store_buy_arcade_pack", function(_source, event) local playerId = event.PlayerID local packId = tostring(event.pack_id or event.item_id or "") local selectedCurrency = event.selected_currency handleBuyArcadePack(nil, playerId, packId, selectedCurrency) end ) CustomGameEventManager:RegisterListener( "store_arcade_flip_card", function(_source, event) local playerId = event.PlayerID local ____event_slot_index_29 = event.slot_index if ____event_slot_index_29 == nil then ____event_slot_index_29 = event.slotIndex end local ____event_slot_index_29_30 = ____event_slot_index_29 if ____event_slot_index_29_30 == nil then ____event_slot_index_29_30 = -1 end local slotIndex = __TS__Number(____event_slot_index_29_30) handleFlipArcadeCard(nil, playerId, slotIndex) end ) end if IsServer() then setupStoreArcadePackListeners(nil) end return ____exports