package shop import ( "fmt" "math/rand" "regexp" "strings" "github.com/ectrc/snow/aid" "github.com/ectrc/snow/fortnite" ) func GetShop() *StorefrontCatalog { aid.SetRandom(rand.New(rand.NewSource(int64(aid.Config.Fortnite.ShopSeed) + aid.CurrentDayUnix()))) shop := NewStorefrontCatalog() dailySection := NewStorefrontCatalogSection("BRDailyStorefront", StorefrontCatalogOfferEnumItem) weeklySection := NewStorefrontCatalogSection("BRWeeklyStorefront", StorefrontCatalogOfferEnumItem) moneySection := NewStorefrontCatalogSection("CurrencyStorefront", StorefrontCatalogOfferEnumCurrency) kitSection := NewStorefrontCatalogSection("BRStarterKits", StorefrontCatalogOfferEnumStarterKit) bookSection := NewStorefrontCatalogSection(fmt.Sprintf("BRSeason%d", aid.Config.Fortnite.Season), StorefrontCatalogOfferEnumBattlePass) shop.AddSections(bookSection, dailySection, weeklySection, moneySection, kitSection) bookDefaultOffer := newBookOffer(aid.Ternary[string](fortnite.DataClient.SnowSeason.DefaultOfferID != "", fortnite.DataClient.SnowSeason.DefaultOfferID, "book://"+ aid.Hash([]byte(aid.RandomString(32)))), 950, 0, &StorefrontCatalogOfferGrant{TemplateID: "Snow:BattlePass", Quantity: 1, ProfileType: "athena"}) bookDefaultOffer.Diplay.Title = "Battle Pass" bookDefaultOffer.Diplay.ShortDescription = "Claim your Season 8 Battle Pass!" bookDefaultOffer.Diplay.Description = "Fortnite Season 8\n\nInstantly get these items valued at over 3,500 V-Bucks.\n • Blackheart Progressive Outfit\n • Hybrid Progressive Outfit\n • 50% Bonus Season Match XP\n • 10% Bonus Season Friend Match XP\n • Extra Weekly Challenges\n\nPlay to level up your Battle Pass, unlocking over 100 rewards (typically takes 75 to 150 hours of play).\n • Sidewinder and 4 more Outfits\n • 1,300 V-Bucks\n • 7 Emotes\n • 6 Wraps\n • 2 Pets\n • 5 Harvesting Tools\n • 4 Gliders\n • 4 Back Blings\n • 5 Contrails\n • 14 Sprays\n • 3 Music Tracks\n • 1 Toy\n • 20 Loading Screens\n • and so much more!\nWant it all faster? You can use V-Bucks to buy tiers any time!" bookDefaultOffer.Meta.DisplayAssetPath = fmt.Sprintf("/Game/Catalog/DisplayAssets/DA_BR_Season%d_BattlePass.DA_BR_Season%d_BattlePass", aid.Config.Fortnite.Season, aid.Config.Fortnite.Season) bookDefaultOffer.Meta.Priority = 1 bookSection.AddOffer(bookDefaultOffer) bookBundleOffer := newBookOffer(aid.Ternary[string](fortnite.DataClient.SnowSeason.BundleOfferID != "", fortnite.DataClient.SnowSeason.BundleOfferID, "book://"+ aid.Hash([]byte(aid.RandomString(32)))), 4700, 1850, []*StorefrontCatalogOfferGrant{ {TemplateID: "Snow:BattlePass", Quantity: 1, ProfileType: "athena"}, {TemplateID: "AccountResource:AthenaBattleStar", Quantity: 250, ProfileType: "athena"}, }...) bookBundleOffer.Diplay.Title = "Battle Bundle" bookBundleOffer.Diplay.ShortDescription = "Claim your Season 8 Battle Pass + 25 Tiers!" bookBundleOffer.Diplay.Description = "Fortnite Season 8\n\nInstantly get these items valued at over 10,000 V-Bucks.\n • Blackheart Progressive Outfit\n • Hybrid Progressive Outfit\n • Sidewinder Outfit\n • Tropical Camo Wrap\n • Woodsy Pet\n • Sky Serpents Glider\n • Cobra Back Bling\n • Flying Standard Contrail\n • 300 V-Bucks\n • 1 Music Track\n • 70% Bonus Season Match XP\n • 20% Bonus Season Friend Match XP\n • Extra Weekly Challenges\n • and more!\n\nPlay to level up your Battle Pass, unlocking over 75 rewards (typically takes 75 to 150 hours of play).\n • 4 more Outfits\n • 1,000 V-Bucks\n • 6 Emotes\n • 5 Wraps\n • 3 Gliders\n • 3 Back Blings\n • 4 Harvesting Tools\n • 4 Contrails\n • 1 Pet\n • 12 Sprays\n • 2 Music Tracks\n • and so much more!\nWant it all faster? You can use V-Bucks to buy tiers any time!" bookBundleOffer.Meta.DisplayAssetPath = fmt.Sprintf("/Game/Catalog/DisplayAssets/DA_BR_Season%d_BattlePassWithLevels.DA_BR_Season%d_BattlePassWithLevels", aid.Config.Fortnite.Season, aid.Config.Fortnite.Season) bookBundleOffer.Meta.Priority = 0 bookSection.AddOffer(bookBundleOffer) bookLevelOffer := newBookOffer(aid.Ternary[string](fortnite.DataClient.SnowSeason.TierOfferID != "", fortnite.DataClient.SnowSeason.TierOfferID, "book://"+ aid.Hash([]byte(aid.RandomString(32)))), 150, 150, &StorefrontCatalogOfferGrant{TemplateID: "AccountResource:AthenaBattleStar", Quantity: 10, ProfileType: "athena"}) bookSection.AddOffer(bookLevelOffer) for len(dailySection.Offers) <= fortnite.DataClient.GetStorefrontDailyItemCount(aid.Config.Fortnite.Season) { offer := newItemOffer(fortnite.GetRandomItemWithDisplayAssetOfNotType("AthenaCharacter"), true, true) offer.Meta.SectionID = "Daily" dailySection.AddOffer(offer) } for weeklySection.GetGroupedOffersLength() < fortnite.DataClient.GetStorefrontWeeklySetCount(aid.Config.Fortnite.Season) { set := fortnite.GetRandomSet() for _, item := range set.Items { offer := newItemOffer(item, true, true) offer.Meta.SectionID = "Featured" offer.Categories = append(offer.Categories, set.BackendName) weeklySection.AddOffer(offer) } } // xp := NewItemCatalogOffer() // xp.OfferID = "item://AthenaSeasonalXP" // xp.Meta.TileSize = "Small" // xp.Meta.Giftable = false // xp.Meta.Refundable = false // xp.Meta.DisplayAssetPath = "/Game/Catalog/DisplayAssets/DA_FoundersPack_4_5.DA_FoundersPack_4_5" // xp.Rewards = append(xp.Rewards, &StorefrontCatalogOfferGrant{ // TemplateID: "AccountResource:AthenaSeasonalXP", // Quantity: 100000, // ProfileType: "athena", // }) // xp.Price.PriceType = StorefrontCatalogOfferPriceTypeMtxCurrency // xp.Price.SaleType = StorefrontCatalogOfferPriceSaleTypeNone // xp.Price.OriginalPrice = 1000 // xp.Price.FinalPrice = 1000 // weeklySection.AddOffer(xp) moneySection.AddOffer(newMoneyOffer(1000, 0, "https://cdn1.epicgames.com/offer/fn/EGS_VBucks_1000_1200x1600-c8a13f66ba88744d5216f884855e2a4d", 3)) moneySection.AddOffer(newMoneyOffer(2800, 300, "https://cdn1.epicgames.com/offer/fn/EGS_VBucks_2800_1200x1600-055112a56c0fb d65989470ece7c653f", 2)) moneySection.AddOffer(newMoneyOffer(7500, 1500, "https://cdn1.epicgames.com/offer/fn/EGS_VBucks_5000_1200x1600-8ea53bb4ea3d75821153075df8e3ca95", 1)) moneySection.AddOffer(newMoneyOffer(13500, 3500, "https://cdn1.epicgames.com/offer/fn/EGS_VBucks_13500_1200x1600-39489a289769bc6c1d14f4a8b53b48f4", 0)) lagunaKit := newKitOffer("The Laguna Pack", 499, 8, []*StorefrontCatalogOfferGrant{ {TemplateID: "AthenaCharacter:CID_367_Athena_Commando_F_Tropical", Quantity: 1, ProfileType: "athena"}, {TemplateID: "AthenaBackpack:BID_231_TropicalFemale", Quantity: 1, ProfileType: "athena"}, {TemplateID: "AthenaItemWrap:Wrap_033_TropicalGirl", Quantity: 1, ProfileType: "athena"}, {TemplateID: "Currency:MtxPurchased", Quantity: 600, ProfileType: "common_core"}, }...) lagunaKit.Meta.DisplayAssetPath = "/Game/Catalog/DisplayAssets/DA_Featured_CID_367_Athena_Commando_F_Tropical.DA_Featured_CID_367_Athena_Commando_F_Tropical" lagunaKit.Meta.FeaturedImageURL = "https://fortnite-api.com/images/cosmetics/br/CID_367_Athena_Commando_F_Tropical/icon.png" kitSection.AddOffer(lagunaKit) ikonikKit := newKitOffer("Ikonik Pack", 3999, 8, []*StorefrontCatalogOfferGrant{ {TemplateID: "AthenaCharacter:CID_313_Athena_Commando_M_KpopFashion", Quantity: 1, ProfileType: "athena"}, {TemplateID: "AthenaDance:EID_KPopDance03", Quantity: 1, ProfileType: "athena"}, {TemplateID: "Currency:MtxPurchased", Quantity: 600, ProfileType: "common_core"}, }...) ikonikKit.Meta.DisplayAssetPath = "/Game/Catalog/DisplayAssets/DA_Featured_CID_313_Athena_Commando_M_KpopFashion.DA_Featured_CID_313_Athena_Commando_M_KpopFashion" ikonikKit.Meta.FeaturedImageURL = "https://fortnite-api.com/images/cosmetics/br/CID_313_Athena_Commando_M_KpopFashion/icon.png" kitSection.AddOffer(ikonikKit) return shop } func newItemOffer(item *fortnite.APICosmeticDefinition, addAssets, giftable bool) *StorefrontCatalogOfferTypeItem { displayAsset := regexp.MustCompile(`[^/]+$`).FindString(item.DisplayAssetPath) offer := NewItemCatalogOffer() offer.Meta.TileSize = aid.Ternary[string](item.Type.BackendValue == "AthenaCharacter", "Small", "Normal") offer.Meta.Giftable = giftable offer.Meta.Refundable = true if addAssets { offer.Meta.DisplayAssetPath = aid.Ternary[string](displayAsset != "", "/Game/Catalog/DisplayAssets/" + displayAsset + "." + displayAsset, "") offer.Meta.NewDisplayAssetPath = aid.Ternary[string](item.NewDisplayAssetPath != "", "/Game/Catalog/NewDisplayAssets/" + item.NewDisplayAssetPath + "." + item.NewDisplayAssetPath, "") } offer.Rewards = append(offer.Rewards, &StorefrontCatalogOfferGrant{ TemplateID: item.Type.BackendValue + ":" + item.ID, Quantity: 1, ProfileType: "athena", }) offer.Price.PriceType = StorefrontCatalogOfferPriceTypeMtxCurrency offer.Price.SaleType = StorefrontCatalogOfferPriceSaleTypeNone offer.Price.OriginalPrice = fortnite.DataClient.GetStorefrontCosmeticOfferPrice(item.Rarity.BackendValue, item.Type.BackendValue) offer.Price.FinalPrice = offer.Price.OriginalPrice offer.OfferID = fmt.Sprintf("item://%s", aid.Hash([]byte(offer.OfferID))) return offer } func newMoneyOffer(real, bonus int, imgUrl string, position int) *StorefrontCatalogOfferTypeCurrency { format := aid.FormatNumber(real) offer := NewCurrencyCatalogOffer() offer.Meta.IconSize = "Small" offer.Meta.CurrencyAnalyticsName = fmt.Sprintf("MtxPack%d", real) offer.Meta.OriginalOffer = real offer.Meta.ExtraBonus = bonus offer.Meta.DisplayAssetPath = fmt.Sprintf("/Game/Catalog/DisplayAssets/DA_MtxPack%d.DA_MtxPack%d", real, real) offer.Meta.FeaturedImageURL = imgUrl offer.Meta.Priority = position offer.Diplay.Title = fmt.Sprintf("%s V-Bucks", format) offer.Diplay.Description = fmt.Sprintf("Buy %s Fortnite V-Bucks, the in-game currency that can be spent in Fortnite Battle Royale and Creative modes. You can purchase new customization items like Outfits, Gliders, Pickaxes, Emotes, Wraps and the latest season's Battle Pass! Gliders and Contrails may not be used in Save the World mode.", format) offer.Diplay.LongDescription = fmt.Sprintf("Buy %s Fortnite V-Bucks, the in-game currency that can be spent in Fortnite Battle Royale and Creative modes. You can purchase new customization items like Outfits, Gliders, Pickaxes, Emotes, Wraps and the latest season's Battle Pass! Gliders and Contrails may not be used in Save the World mode.\n\nAll V-Bucks purchased on the Epic Games Store are not redeemable or usable on Nintendo Switch™.", format) offer.Price.PriceType = StorefrontCatalogOfferPriceTypeRealMoney offer.Price.BasePrice = float64(fortnite.DataClient.GetStorefrontCurrencyOfferPrice("GBP", real)) offer.Price.LocalPrice = float64(fortnite.DataClient.GetStorefrontCurrencyOfferPrice("USD", real)) offer.Rewards = append(offer.Rewards, &StorefrontCatalogOfferGrant{ TemplateID: "Currency:MtxPurchased", Quantity: real, ProfileType: "common_core", }) return offer } func newKitOffer(title string, basePrice, season int, rewards ...*StorefrontCatalogOfferGrant) *StorefrontCatalogOfferTypeStarterKit { description := fmt.Sprintf("Jump into Fortnite Battle Royale with the %s. Includes:\n\n- 600 V-Bucks", strings.ReplaceAll(title, "The ", "")) for _, reward := range rewards { item := fortnite.DataClient.FortniteItems[strings.Split(reward.TemplateID, ":")[1]] if item != nil { description += fmt.Sprintf("\n- %s %s", item.Name, item.Type.DisplayValue) } } offer := NewStarterKitCatalogOffer() offer.Meta.ReleaseSeason = season offer.Meta.OriginalOffer = 600 offer.Meta.ExtraBonus = 100 offer.Diplay.Title = title offer.Diplay.Description = description offer.Diplay.LongDescription = fmt.Sprintf("%s\n\nV-Bucks are an in-game currency that can be spent in both the Battle Royale PvP mode and the Save the World PvE campaign. In Battle Royale, you can use V-bucks to purchase new customization items like outfits, emotes, pickaxes, gliders, and more! In Save the World you can purchase Llama Pinata card packs that contain weapon, trap and gadget schematics as well as new Heroes and more! \n\nNote: Items do not transfer between the Battle Royale mode and the Save the World campaign.", description) offer.Price.PriceType = StorefrontCatalogOfferPriceTypeRealMoney offer.Price.BasePrice = float64(fortnite.DataClient.GetStorefrontLocalizedOfferPrice("GBP", basePrice)) offer.Price.LocalPrice = float64(fortnite.DataClient.GetStorefrontLocalizedOfferPrice("USD", basePrice)) offer.Rewards = rewards return offer } func newBookOffer(customId string, ogPrice, finalprice int, rewards ...*StorefrontCatalogOfferGrant) *StorefrontCatalogOfferTypeBattlePass { offer := NewBattlePassCatalogOffer() offer.OfferID = customId offer.Meta.TileSize = "Normal" offer.Meta.SectionID = "BattlePass" offer.Price.PriceType = StorefrontCatalogOfferPriceTypeMtxCurrency offer.Price.SaleType = StorefrontCatalogOfferPriceSaleTypeStrikethrough offer.Price.OriginalPrice = ogPrice offer.Price.FinalPrice = finalprice offer.Rewards = rewards return offer }