From dc526260c284ced0e4283fbd233c9bf76aa58b17 Mon Sep 17 00:00:00 2001 From: KyleBastien Date: Sat, 13 Dec 2025 21:01:52 -0800 Subject: [PATCH 1/6] First attempt at simple joker search --- Brainstorm_UI.lua | 162 ++++++++++++++++++++++++++++++++++++++++++ Brainstorm_reroll.lua | 58 +++++++++++++++ 2 files changed, 220 insertions(+) diff --git a/Brainstorm_UI.lua b/Brainstorm_UI.lua index e3b9a4d..e69abda 100644 --- a/Brainstorm_UI.lua +++ b/Brainstorm_UI.lua @@ -45,6 +45,159 @@ Brainstorm.SearchPackList = { ["Jumbo Spectral"] = {"p_spectral_jumbo_1"}, ["Mega Spectral"] = {"p_spectral_mega_1"}, } + +Brainstorm.SearchJokerList = { + ["None"] = "", + ["8 Ball"] = "j_8_ball", + ["Abstract Joker"] = "j_abstract", + ["Acrobat"] = "j_acrobat", + ["Ancient Joker"] = "j_ancient", + ["Arrowhead"] = "j_arrowhead", + ["Astronomer"] = "j_astronomer", + ["Banner"] = "j_banner", + ["Baron"] = "j_baron", + ["Baseball Card"] = "j_baseball", + ["Blackboard"] = "j_blackboard", + ["Bloodstone"] = "j_bloodstone", + ["Blue Joker"] = "j_blue_joker", + ["Blueprint"] = "j_blueprint", + ["Bootstraps"] = "j_bootstraps", + ["Brainstorm"] = "j_brainstorm", + ["Bull"] = "j_bull", + ["Burglar"] = "j_burglar", + ["Burnt Joker"] = "j_burnt", + ["Business Card"] = "j_business", + ["Caino"] = "j_caino", + ["Campfire"] = "j_campfire", + ["Card Sharp"] = "j_card_sharp", + ["Cartomancer"] = "j_cartomancer", + ["Castle"] = "j_castle", + ["Cavendish"] = "j_cavendish", + ["Ceremonial Dagger"] = "j_ceremonial", + ["Certificate"] = "j_certificate", + ["Chaos the Clown"] = "j_chaos", + ["Chicot"] = "j_chicot", + ["Clever Joker"] = "j_clever", + ["Cloud 9"] = "j_cloud_9", + ["Constellation"] = "j_constellation", + ["Crafty Joker"] = "j_crafty", + ["Crazy Joker"] = "j_crazy", + ["Credit Card"] = "j_credit_card", + ["Delayed Gratification"] = "j_delayed_grat", + ["Devious Joker"] = "j_devious", + ["Diet Cola"] = "j_diet_cola", + ["DNA"] = "j_dna", + ["Driver's License"] = "j_drivers_license", + ["Droll Joker"] = "j_droll", + ["Drunkard"] = "j_drunkard", + ["Dusk"] = "j_dusk", + ["Egg"] = "j_egg", + ["Erosion"] = "j_erosion", + ["Even Steven"] = "j_even_steven", + ["Faceless Joker"] = "j_faceless", + ["Fibonacci"] = "j_fibonacci", + ["Flash Card"] = "j_flash", + ["Flower Pot"] = "j_flower_pot", + ["Fortune Teller"] = "j_fortune_teller", + ["Four Fingers"] = "j_four_fingers", + ["Gift Card"] = "j_gift", + ["Glass Joker"] = "j_glass", + ["Gluttonous Joker"] = "j_gluttenous_joker", + ["Golden Joker"] = "j_golden", + ["Golden Ticket"] = "j_ticket", + ["Green Joker"] = "j_green_joker", + ["Greedy Joker"] = "j_greedy_joker", + ["Gros Michel"] = "j_gros_michel", + ["Hack"] = "j_hack", + ["Half Joker"] = "j_half", + ["Hallucination"] = "j_hallucination", + ["Hanging Chad"] = "j_hanging_chad", + ["Hiker"] = "j_hiker", + ["Hit the Road"] = "j_hit_the_road", + ["Hologram"] = "j_hologram", + ["Ice Cream"] = "j_ice_cream", + ["Invisible Joker"] = "j_invisible", + ["Joker"] = "j_joker", + ["Joker Stencil"] = "j_stencil", + ["Jolly Joker"] = "j_jolly", + ["Juggler"] = "j_juggler", + ["Luchador"] = "j_luchador", + ["Lucky Cat"] = "j_lucky_cat", + ["Lusty Joker"] = "j_lusty_joker", + ["Mad Joker"] = "j_mad", + ["Madness"] = "j_madness", + ["Mail-In Rebate"] = "j_mail", + ["Marble Joker"] = "j_marble", + ["Matador"] = "j_matador", + ["Merry Andy"] = "j_merry_andy", + ["Midas Mask"] = "j_midas_mask", + ["Mime"] = "j_mime", + ["Misprint"] = "j_misprint", + ["Mr. Bones"] = "j_mr_bones", + ["Mystic Summit"] = "j_mystic_summit", + ["Obelisk"] = "j_obelisk", + ["Odd Todd"] = "j_odd_todd", + ["Onyx Agate"] = "j_onyx_agate", + ["Oops! All 6s"] = "j_oops", + ["Pareidolia"] = "j_pareidolia", + ["Perkeo"] = "j_perkeo", + ["Photograph"] = "j_photograph", + ["Popcorn"] = "j_popcorn", + ["Raised Fist"] = "j_raised_fist", + ["Ramen"] = "j_ramen", + ["Red Card"] = "j_red_card", + ["Reserved Parking"] = "j_reserved_parking", + ["Ride the Bus"] = "j_ride_the_bus", + ["Riff-raff"] = "j_riff_raff", + ["Rocket"] = "j_rocket", + ["Rough Gem"] = "j_rough_gem", + ["Runner"] = "j_runner", + ["Satellite"] = "j_satellite", + ["Scary Face"] = "j_scary_face", + ["Scholar"] = "j_scholar", + ["Seance"] = "j_seance", + ["Seeing Double"] = "j_seeing_double", + ["Seltzer"] = "j_selzer", + ["Shoot the Moon"] = "j_shoot_the_moon", + ["Shortcut"] = "j_shortcut", + ["Showman"] = "j_ring_master", + ["Sixth Sense"] = "j_sixth_sense", + ["Sly Joker"] = "j_sly", + ["Smeared Joker"] = "j_smeared", + ["Smiley Face"] = "j_smiley", + ["Sock and Buskin"] = "j_sock_and_buskin", + ["Space Joker"] = "j_space", + ["Spare Trousers"] = "j_trousers", + ["Splash"] = "j_splash", + ["Square Joker"] = "j_square", + ["Steel Joker"] = "j_steel_joker", + ["Stone Joker"] = "j_stone", + ["Stuntman"] = "j_stuntman", + ["Supernova"] = "j_supernova", + ["Superposition"] = "j_superposition", + ["Swashbuckler"] = "j_swashbuckler", + ["The Duo"] = "j_duo", + ["The Family"] = "j_family", + ["The Idol"] = "j_idol", + ["The Order"] = "j_order", + ["The Tribe"] = "j_tribe", + ["The Trio"] = "j_trio", + ["Throwback"] = "j_throwback", + ["To Do List"] = "j_todo_list", + ["To the Moon"] = "j_to_the_moon", + ["Trading Card"] = "j_trading", + ["Triboulet"] = "j_triboulet", + ["Troubadour"] = "j_troubadour", + ["Turtle Bean"] = "j_turtle_bean", + ["Vagabond"] = "j_vagabond", + ["Vampire"] = "j_vampire", + ["Walkie Talkie"] = "j_walkie_talkie", + ["Wee Joker"] = "j_wee", + ["Wily Joker"] = "j_wily", + ["Wrathful Joker"] = "j_wrathful_joker", + ["Yorick"] = "j_yorick", + ["Zany Joker"] = "j_zany", +} Brainstorm.seedsPerFrame = { ["500"] = 500, ["750"] = 750, @@ -53,6 +206,7 @@ Brainstorm.seedsPerFrame = { local searchTagKeys = {"None", "Charm Tag", "Double Tag", "Uncommon Tag", "Rare Tag", "Holographic Tag", "Foil Tag", "Polychrome Tag", "Investment Tag", "Voucher Tag", "Boss Tag", "Juggle Tag", "Coupon Tag", "Economy Tag", "Skip Tag", "D6 Tag"} local searchPackKeys = {"None", "Arcana", "Celestial", "Standard", "Buffoon", "Spectral", "Normal Arcana", "Jumbo Arcana", "Mega Arcana", "Normal Celestial", "Jumbo Celestial", "Mega Celestial", "Normal Standard", "Jumbo Standard", "Mega Standard", "Normal Buffoon", "Jumbo Buffoon", "Mega Buffoon", "Normal Spectral", "Jumbo Spectral", "Mega Spectral"} +local searchJokerKeys = {"None", "8 Ball", "Abstract Joker", "Acrobat", "Ancient Joker", "Arrowhead", "Astronomer", "Banner", "Baron", "Baseball Card", "Blackboard", "Bloodstone", "Blue Joker", "Blueprint", "Bootstraps", "Brainstorm", "Bull", "Burglar", "Burnt Joker", "Business Card", "Caino", "Campfire", "Card Sharp", "Cartomancer", "Castle", "Cavendish", "Ceremonial Dagger", "Certificate", "Chaos the Clown", "Chicot", "Clever Joker", "Cloud 9", "Constellation", "Crafty Joker", "Crazy Joker", "Credit Card", "Delayed Gratification", "Devious Joker", "Diet Cola", "DNA", "Driver's License", "Droll Joker", "Drunkard", "Dusk", "Egg", "Erosion", "Even Steven", "Faceless Joker", "Fibonacci", "Flash Card", "Flower Pot", "Fortune Teller", "Four Fingers", "Gift Card", "Glass Joker", "Gluttonous Joker", "Golden Joker", "Golden Ticket", "Green Joker", "Greedy Joker", "Gros Michel", "Hack", "Half Joker", "Hallucination", "Hanging Chad", "Hiker", "Hit the Road", "Hologram", "Ice Cream", "Invisible Joker", "Joker", "Joker Stencil", "Jolly Joker", "Juggler", "Luchador", "Lucky Cat", "Lusty Joker", "Mad Joker", "Madness", "Mail-In Rebate", "Marble Joker", "Matador", "Merry Andy", "Midas Mask", "Mime", "Misprint", "Mr. Bones", "Mystic Summit", "Obelisk", "Odd Todd", "Onyx Agate", "Oops! All 6s", "Pareidolia", "Perkeo", "Photograph", "Popcorn", "Raised Fist", "Ramen", "Red Card", "Reserved Parking", "Ride the Bus", "Riff-raff", "Rocket", "Rough Gem", "Runner", "Satellite", "Scary Face", "Scholar", "Seance", "Seeing Double", "Seltzer", "Shoot the Moon", "Shortcut", "Showman", "Sixth Sense", "Sly Joker", "Smeared Joker", "Smiley Face", "Sock and Buskin", "Space Joker", "Spare Trousers", "Splash", "Square Joker", "Steel Joker", "Stone Joker", "Stuntman", "Supernova", "Superposition", "Swashbuckler", "The Duo", "The Family", "The Idol", "The Order", "The Tribe", "The Trio", "Throwback", "To Do List", "To the Moon", "Trading Card", "Triboulet", "Troubadour", "Turtle Bean", "Vagabond", "Vampire", "Walkie Talkie", "Wee Joker", "Wily Joker", "Wrathful Joker", "Yorick", "Zany Joker"} local seedsPerFrame = {"500", "750", "1000"} -- print(Brainstorm.FUNCS.inspect(searchTagKeys)) @@ -99,6 +253,14 @@ function create_tabs(args) opt_callback = "change_search_pack", current_option = Brainstorm.SETTINGS.autoreroll.searchPackID or 1, }), + create_option_cycle({ + label = "AutoReroll Search Joker", + scale = 0.8, + w = 4, + options = searchJokerKeys, + opt_callback = "change_search_joker", + current_option = Brainstorm.SETTINGS.autoreroll.searchJokerID or 1, + }), create_option_cycle({ label = "Charm Tag/Arcana Pack: Number of Souls", scale = 0.8, diff --git a/Brainstorm_reroll.lua b/Brainstorm_reroll.lua index b2e7d6e..62254c0 100644 --- a/Brainstorm_reroll.lua +++ b/Brainstorm_reroll.lua @@ -12,6 +12,17 @@ end G.FUNCS.change_search_pack = function(x) Brainstorm.SETTINGS.autoreroll.searchPackID = x.to_key Brainstorm.SETTINGS.autoreroll.searchPack = Brainstorm.SearchPackList[x.to_val] + -- Reset joker search when switching away from buffoon packs + if not string.find(x.to_val, "Buffoon") then + Brainstorm.SETTINGS.autoreroll.searchJokerID = 1 + Brainstorm.SETTINGS.autoreroll.searchJoker = "" + end + nativefs.write(lovely.mod_dir .. "/Brainstorm/settings.lua", STR_PACK(Brainstorm.SETTINGS)) +end + +G.FUNCS.change_search_joker = function(x) + Brainstorm.SETTINGS.autoreroll.searchJokerID = x.to_key + Brainstorm.SETTINGS.autoreroll.searchJoker = Brainstorm.SearchJokerList[x.to_val] nativefs.write(lovely.mod_dir .. "/Brainstorm/settings.lua", STR_PACK(Brainstorm.SETTINGS)) end @@ -109,6 +120,16 @@ break end end if not pack_found then seed_found = nil + else + -- If searching for a specific joker in buffoon packs + if seed_found and Brainstorm.SETTINGS.autoreroll.searchJoker and Brainstorm.SETTINGS.autoreroll.searchJoker ~= "" then + if string.find(center.key, "buffoon") then + -- Simulate joker generation for the buffoon pack + if not simulate_buffoon_pack_jokers(seed_found, center.key) then + seed_found = nil + end + end + end end end --[[ @@ -177,6 +198,43 @@ function wait(seconds) end end +function simulate_buffoon_pack_jokers(seed_found, pack_key) + -- Determine joker count based on pack type + local joker_count = 2 -- Default for Normal Buffoon + if string.find(pack_key, "jumbo") then + joker_count = 4 -- Jumbo Buffoon: 4 jokers, pick 1 + elseif string.find(pack_key, "mega") then + joker_count = 4 -- Mega Buffoon: 4 jokers, pick 2 + end + + -- Simulate each joker slot in the pack + for i = 1, joker_count do + -- Determine rarity using Balatro's algorithm + local rarity_roll = pseudorandom(Brainstorm.pseudoseed("rarity" .. i .. "sho" .. seed_found)) + local rarity = 1 -- Common + if rarity_roll > 0.95 then + rarity = 3 -- Rare + elseif rarity_roll > 0.7 then + rarity = 2 -- Uncommon + end + + -- Select joker from the rarity pool + -- Note: G.P_JOKER_RARITY_POOLS[rarity] contains all jokers of that rarity + -- pseudorandom_element uses the seed to deterministically pick from the pool + local joker_center = pseudorandom_element( + G.P_JOKER_RARITY_POOLS[rarity], + Brainstorm.pseudoseed("Joker" .. rarity .. i .. "sho" .. seed_found) + ) + + -- Check if this is the joker we're searching for + if joker_center and joker_center.key == Brainstorm.SETTINGS.autoreroll.searchJoker then + return true + end + end + + return false +end + function Brainstorm.pseudoseed(key, predict_seed) if key == "seed" then return math.random() From 5616d1f35427a7652ea51dacaf245343e7b0c5b5 Mon Sep 17 00:00:00 2001 From: KyleBastien Date: Sat, 13 Dec 2025 21:33:58 -0800 Subject: [PATCH 2/6] Search more packs --- Brainstorm_reroll.lua | 47 ++++++++++++++++++++++++++++++++++--------- 1 file changed, 37 insertions(+), 10 deletions(-) diff --git a/Brainstorm_reroll.lua b/Brainstorm_reroll.lua index 62254c0..a7b0ccc 100644 --- a/Brainstorm_reroll.lua +++ b/Brainstorm_reroll.lua @@ -121,13 +121,33 @@ break end if not pack_found then seed_found = nil else - -- If searching for a specific joker in buffoon packs + -- If searching for a specific joker, check all buffoon packs in both shop slots if seed_found and Brainstorm.SETTINGS.autoreroll.searchJoker and Brainstorm.SETTINGS.autoreroll.searchJoker ~= "" then - if string.find(center.key, "buffoon") then - -- Simulate joker generation for the buffoon pack - if not simulate_buffoon_pack_jokers(seed_found, center.key) then - seed_found = nil + local joker_found = false + -- Check both shop pack slots for buffoon packs + for slot = 1, 2 do + local slot_cume, slot_it, slot_center = 0, 0, nil + for k, v in ipairs(G.P_CENTER_POOLS['Booster']) do + if (not _type or _type == v.kind) then slot_cume = slot_cume + (v.weight or 1) end end + local slot_poll = pseudorandom(Brainstorm.pseudoseed("shop_pack"..slot..seed_found))*slot_cume + for k, v in ipairs(G.P_CENTER_POOLS['Booster']) do + if not _type or _type == v.kind then slot_it = slot_it + (v.weight or 1) end + if slot_it >= slot_poll and slot_it - (v.weight or 1) <= slot_poll then + slot_center = v + break + end + end + -- If this slot has a buffoon pack, check for the joker + if slot_center and string.find(slot_center.key, "buffoon") then + if simulate_buffoon_pack_jokers(slot_center.key) then + joker_found = true + break -- Early exit once joker is found + end + end + end + if not joker_found then + seed_found = nil end end end @@ -198,7 +218,7 @@ function wait(seconds) end end -function simulate_buffoon_pack_jokers(seed_found, pack_key) +function simulate_buffoon_pack_jokers(pack_key) -- Determine joker count based on pack type local joker_count = 2 -- Default for Normal Buffoon if string.find(pack_key, "jumbo") then @@ -208,9 +228,11 @@ function simulate_buffoon_pack_jokers(seed_found, pack_key) end -- Simulate each joker slot in the pack + -- Note: Jokers within packs use 'buf' as key_append, with ante 1 for first shop for i = 1, joker_count do -- Determine rarity using Balatro's algorithm - local rarity_roll = pseudorandom(Brainstorm.pseudoseed("rarity" .. i .. "sho" .. seed_found)) + -- Seed pattern: 'rarity' + ante + 'buf' (ante = 1 for first shop) + local rarity_roll = pseudorandom(Brainstorm.pseudoseed("rarity1buf")) local rarity = 1 -- Common if rarity_roll > 0.95 then rarity = 3 -- Rare @@ -219,11 +241,10 @@ function simulate_buffoon_pack_jokers(seed_found, pack_key) end -- Select joker from the rarity pool - -- Note: G.P_JOKER_RARITY_POOLS[rarity] contains all jokers of that rarity - -- pseudorandom_element uses the seed to deterministically pick from the pool + -- Seed pattern: 'Joker' + rarity + 'buf' + ante local joker_center = pseudorandom_element( G.P_JOKER_RARITY_POOLS[rarity], - Brainstorm.pseudoseed("Joker" .. rarity .. i .. "sho" .. seed_found) + Brainstorm.pseudoseed("Joker" .. rarity .. "buf1") ) -- Check if this is the joker we're searching for @@ -232,6 +253,12 @@ function simulate_buffoon_pack_jokers(seed_found, pack_key) end end + return false +end + return true + end + end + return false end From 19d6d958d7b2a8c23b92ec824335fc8c7b7a8709 Mon Sep 17 00:00:00 2001 From: KyleBastien Date: Sat, 13 Dec 2025 21:46:24 -0800 Subject: [PATCH 3/6] Fix bad syntax --- Brainstorm_reroll.lua | 6 ------ 1 file changed, 6 deletions(-) diff --git a/Brainstorm_reroll.lua b/Brainstorm_reroll.lua index a7b0ccc..7fb2bc4 100644 --- a/Brainstorm_reroll.lua +++ b/Brainstorm_reroll.lua @@ -253,12 +253,6 @@ function simulate_buffoon_pack_jokers(pack_key) end end - return false -end - return true - end - end - return false end From 8631fb650e35ff231d19b051e4372da190f1e8ca Mon Sep 17 00:00:00 2001 From: KyleBastien Date: Sun, 14 Dec 2025 21:03:33 -0800 Subject: [PATCH 4/6] Final fixes to get it working --- Brainstorm.lua | 7 ++ Brainstorm_reroll.lua | 156 +++++++++++++++++++++++++++++++----------- 2 files changed, 124 insertions(+), 39 deletions(-) diff --git a/Brainstorm.lua b/Brainstorm.lua index 1072050..7a54821 100644 --- a/Brainstorm.lua +++ b/Brainstorm.lua @@ -10,6 +10,13 @@ function initBrainstorm() local settings_file = STR_UNPACK(nativefs.read((lovely.mod_dir .. "/Brainstorm/settings.lua"))) if settings_file ~= nil then Brainstorm.SETTINGS = settings_file + -- Ensure new fields have defaults + if not Brainstorm.SETTINGS.autoreroll.searchJoker then + Brainstorm.SETTINGS.autoreroll.searchJoker = "" + end + if not Brainstorm.SETTINGS.autoreroll.searchJokerID then + Brainstorm.SETTINGS.autoreroll.searchJokerID = 1 + end end end _RELEASE_MODE = not Brainstorm.SETTINGS.debug_mode diff --git a/Brainstorm_reroll.lua b/Brainstorm_reroll.lua index 7fb2bc4..f83d4dc 100644 --- a/Brainstorm_reroll.lua +++ b/Brainstorm_reroll.lua @@ -66,6 +66,11 @@ function Brainstorm.auto_reroll() -- This part is meant to mimic how Balatro rerolls for Gold Stake local extra_num = -0.561892350821 local seed_found = nil + + -- Debug: Show what we're searching for + if Brainstorm.SETTINGS.debug_mode and Brainstorm.SETTINGS.autoreroll.searchJoker and Brainstorm.SETTINGS.autoreroll.searchJoker ~= "" then + sendDebugMessage("[Brainstorm] AUTO-REROLL ACTIVE - Searching for joker: " .. Brainstorm.SETTINGS.autoreroll.searchJoker) + end while not seed_found and rerollsThisFrame < Brainstorm.SETTINGS.autoreroll.seedsPerFrame do rerollsThisFrame = rerollsThisFrame + 1 extra_num = extra_num + 0.561892350821 @@ -100,7 +105,68 @@ function Brainstorm.auto_reroll() end end end - if seed_found and Brainstorm.SETTINGS.autoreroll.searchPack and #Brainstorm.SETTINGS.autoreroll.searchPack > 0 then + -- Check for joker search (works independently or with pack search) + if seed_found and Brainstorm.SETTINGS.autoreroll.searchJoker and Brainstorm.SETTINGS.autoreroll.searchJoker ~= "" then + if Brainstorm.SETTINGS.debug_mode then + sendDebugMessage("[Brainstorm] Checking seed: " .. seed_found .. " for joker: " .. Brainstorm.SETTINGS.autoreroll.searchJoker) + end + local joker_found = false + -- Check both shop pack slots for buffoon packs + for slot = 1, 2 do + local slot_cume, slot_it, slot_center = 0, 0, nil + for k, v in ipairs(G.P_CENTER_POOLS['Booster']) do + if (not _type or _type == v.kind) then slot_cume = slot_cume + (v.weight or 1) end + end + local slot_poll = pseudorandom(Brainstorm.pseudoseed("shop_pack"..slot..seed_found))*slot_cume + for k, v in ipairs(G.P_CENTER_POOLS['Booster']) do + if not _type or _type == v.kind then slot_it = slot_it + (v.weight or 1) end + if slot_it >= slot_poll and slot_it - (v.weight or 1) <= slot_poll then + slot_center = v + break + end + end + -- If this slot has a buffoon pack, check for the joker + if slot_center then + if Brainstorm.SETTINGS.debug_mode then + sendDebugMessage("[Brainstorm] Slot " .. slot .. " pack: " .. slot_center.key) + end + if string.find(slot_center.key, "buffoon") then + -- If pack search is active, verify this is the right pack type + local pack_type_matches = true + if Brainstorm.SETTINGS.autoreroll.searchPack and #Brainstorm.SETTINGS.autoreroll.searchPack > 0 then + pack_type_matches = false + for i = 1, #Brainstorm.SETTINGS.autoreroll.searchPack do + if Brainstorm.SETTINGS.autoreroll.searchPack[i] == slot_center.key then + pack_type_matches = true + break + end + end + end + + if pack_type_matches then + if Brainstorm.SETTINGS.debug_mode then + sendDebugMessage("[Brainstorm] Found buffoon pack, simulating...") + end + if simulate_buffoon_pack_jokers(slot_center.key, seed_found) then + if Brainstorm.SETTINGS.debug_mode then + sendDebugMessage("[Brainstorm] *** JOKER FOUND! ***") + end + joker_found = true + break -- Early exit once joker is found + else + if Brainstorm.SETTINGS.debug_mode then + sendDebugMessage("[Brainstorm] Joker not in this pack") + end + end + end + end + end + end + if not joker_found then + seed_found = nil + end + elseif seed_found and Brainstorm.SETTINGS.autoreroll.searchPack and #Brainstorm.SETTINGS.autoreroll.searchPack > 0 then + -- Pack-only search (no joker specified) local cume, it, center = 0, 0, nil for k, v in ipairs(G.P_CENTER_POOLS['Booster']) do if (not _type or _type == v.kind) then cume = cume + (v.weight or 1 ) end @@ -120,36 +186,6 @@ break end end if not pack_found then seed_found = nil - else - -- If searching for a specific joker, check all buffoon packs in both shop slots - if seed_found and Brainstorm.SETTINGS.autoreroll.searchJoker and Brainstorm.SETTINGS.autoreroll.searchJoker ~= "" then - local joker_found = false - -- Check both shop pack slots for buffoon packs - for slot = 1, 2 do - local slot_cume, slot_it, slot_center = 0, 0, nil - for k, v in ipairs(G.P_CENTER_POOLS['Booster']) do - if (not _type or _type == v.kind) then slot_cume = slot_cume + (v.weight or 1) end - end - local slot_poll = pseudorandom(Brainstorm.pseudoseed("shop_pack"..slot..seed_found))*slot_cume - for k, v in ipairs(G.P_CENTER_POOLS['Booster']) do - if not _type or _type == v.kind then slot_it = slot_it + (v.weight or 1) end - if slot_it >= slot_poll and slot_it - (v.weight or 1) <= slot_poll then - slot_center = v - break - end - end - -- If this slot has a buffoon pack, check for the joker - if slot_center and string.find(slot_center.key, "buffoon") then - if simulate_buffoon_pack_jokers(slot_center.key) then - joker_found = true - break -- Early exit once joker is found - end - end - end - if not joker_found then - seed_found = nil - end - end end end --[[ @@ -218,7 +254,11 @@ function wait(seconds) end end -function simulate_buffoon_pack_jokers(pack_key) +function simulate_buffoon_pack_jokers(pack_key, predict_seed) + if Brainstorm.SETTINGS.debug_mode then + sendDebugMessage("[Brainstorm] simulate_buffoon_pack_jokers called with pack: " .. pack_key .. ", seed: " .. (predict_seed or "nil")) + end + -- Determine joker count based on pack type local joker_count = 2 -- Default for Normal Buffoon if string.find(pack_key, "jumbo") then @@ -226,30 +266,68 @@ function simulate_buffoon_pack_jokers(pack_key) elseif string.find(pack_key, "mega") then joker_count = 4 -- Mega Buffoon: 4 jokers, pick 2 end + if Brainstorm.SETTINGS.debug_mode then + sendDebugMessage("[Brainstorm] Simulating " .. joker_count .. " jokers") + end + -- Initialize a temporary RNG state for this simulation + -- This mimics how Balatro's G.GAME.pseudorandom works but for prediction + local temp_random_state = {} + -- Simulate each joker slot in the pack -- Note: Jokers within packs use 'buf' as key_append, with ante 1 for first shop + -- IMPORTANT: In Balatro, calling pseudoseed with the same key multiple times + -- returns different values because it maintains and advances state for each key for i = 1, joker_count do -- Determine rarity using Balatro's algorithm -- Seed pattern: 'rarity' + ante + 'buf' (ante = 1 for first shop) - local rarity_roll = pseudorandom(Brainstorm.pseudoseed("rarity1buf")) + -- We need to simulate state advancement, so we'll use a helper that tracks calls + local rarity_key = "rarity1buf" + if not temp_random_state[rarity_key] then + temp_random_state[rarity_key] = pseudohash(rarity_key .. (predict_seed or '')) + end + temp_random_state[rarity_key] = math.abs(tonumber(string.format("%.13f", (2.134453429141 + temp_random_state[rarity_key] * 1.72431234) % 1))) + local rarity_seed_value = (temp_random_state[rarity_key] + (pseudohash(predict_seed) or 0)) / 2 + local rarity_roll = pseudorandom(rarity_seed_value) + local rarity = 1 -- Common + local rarity_name = "Common" if rarity_roll > 0.95 then rarity = 3 -- Rare + rarity_name = "Rare" elseif rarity_roll > 0.7 then rarity = 2 -- Uncommon + rarity_name = "Uncommon" + end + if Brainstorm.SETTINGS.debug_mode then + sendDebugMessage("[Brainstorm] Joker #" .. i .. " rarity roll: " .. rarity_roll .. " -> " .. rarity_name) end -- Select joker from the rarity pool -- Seed pattern: 'Joker' + rarity + 'buf' + ante - local joker_center = pseudorandom_element( - G.P_JOKER_RARITY_POOLS[rarity], - Brainstorm.pseudoseed("Joker" .. rarity .. "buf1") - ) + local joker_key = "Joker" .. rarity .. "buf1" + if not temp_random_state[joker_key] then + temp_random_state[joker_key] = pseudohash(joker_key .. (predict_seed or '')) + end + temp_random_state[joker_key] = math.abs(tonumber(string.format("%.13f", (2.134453429141 + temp_random_state[joker_key] * 1.72431234) % 1))) + local joker_seed_value = (temp_random_state[joker_key] + (pseudohash(predict_seed) or 0)) / 2 + local joker_center = pseudorandom_element(G.P_JOKER_RARITY_POOLS[rarity], joker_seed_value) -- Check if this is the joker we're searching for - if joker_center and joker_center.key == Brainstorm.SETTINGS.autoreroll.searchJoker then - return true + if joker_center then + if Brainstorm.SETTINGS.debug_mode then + sendDebugMessage("[Brainstorm] Generated: " .. joker_center.key .. " (" .. (joker_center.name or "unknown") .. ")") + end + if joker_center.key == Brainstorm.SETTINGS.autoreroll.searchJoker then + if Brainstorm.SETTINGS.debug_mode then + sendDebugMessage("[Brainstorm] *** MATCH! ***") + end + return true + end + else + if Brainstorm.SETTINGS.debug_mode then + sendDebugMessage("[Brainstorm] ERROR: Failed to generate joker") + end end end From 6e94aee44fded486f9a21133cddce0959abfcdac Mon Sep 17 00:00:00 2001 From: KyleBastien Date: Sun, 14 Dec 2025 21:22:18 -0800 Subject: [PATCH 5/6] Nits --- Brainstorm.lua | 1 - Brainstorm_reroll.lua | 6 ------ 2 files changed, 7 deletions(-) diff --git a/Brainstorm.lua b/Brainstorm.lua index 7a54821..0a3b89c 100644 --- a/Brainstorm.lua +++ b/Brainstorm.lua @@ -10,7 +10,6 @@ function initBrainstorm() local settings_file = STR_UNPACK(nativefs.read((lovely.mod_dir .. "/Brainstorm/settings.lua"))) if settings_file ~= nil then Brainstorm.SETTINGS = settings_file - -- Ensure new fields have defaults if not Brainstorm.SETTINGS.autoreroll.searchJoker then Brainstorm.SETTINGS.autoreroll.searchJoker = "" end diff --git a/Brainstorm_reroll.lua b/Brainstorm_reroll.lua index f83d4dc..200f3bf 100644 --- a/Brainstorm_reroll.lua +++ b/Brainstorm_reroll.lua @@ -12,11 +12,6 @@ end G.FUNCS.change_search_pack = function(x) Brainstorm.SETTINGS.autoreroll.searchPackID = x.to_key Brainstorm.SETTINGS.autoreroll.searchPack = Brainstorm.SearchPackList[x.to_val] - -- Reset joker search when switching away from buffoon packs - if not string.find(x.to_val, "Buffoon") then - Brainstorm.SETTINGS.autoreroll.searchJokerID = 1 - Brainstorm.SETTINGS.autoreroll.searchJoker = "" - end nativefs.write(lovely.mod_dir .. "/Brainstorm/settings.lua", STR_PACK(Brainstorm.SETTINGS)) end @@ -67,7 +62,6 @@ function Brainstorm.auto_reroll() local extra_num = -0.561892350821 local seed_found = nil - -- Debug: Show what we're searching for if Brainstorm.SETTINGS.debug_mode and Brainstorm.SETTINGS.autoreroll.searchJoker and Brainstorm.SETTINGS.autoreroll.searchJoker ~= "" then sendDebugMessage("[Brainstorm] AUTO-REROLL ACTIVE - Searching for joker: " .. Brainstorm.SETTINGS.autoreroll.searchJoker) end From d327f1f4faf3db9b275e706bbf917327fdb6fd75 Mon Sep 17 00:00:00 2001 From: KyleBastien Date: Mon, 15 Dec 2025 19:59:08 -0800 Subject: [PATCH 6/6] Add shop Joker search --- Brainstorm.lua | 6 ++ Brainstorm_UI.lua | 15 ++++ Brainstorm_reroll.lua | 199 ++++++++++++++++++++++++++++++++++-------- 3 files changed, 182 insertions(+), 38 deletions(-) diff --git a/Brainstorm.lua b/Brainstorm.lua index 0a3b89c..d048208 100644 --- a/Brainstorm.lua +++ b/Brainstorm.lua @@ -16,6 +16,12 @@ function initBrainstorm() if not Brainstorm.SETTINGS.autoreroll.searchJokerID then Brainstorm.SETTINGS.autoreroll.searchJokerID = 1 end + if not Brainstorm.SETTINGS.autoreroll.searchJokerLocation then + Brainstorm.SETTINGS.autoreroll.searchJokerLocation = "any" + end + if not Brainstorm.SETTINGS.autoreroll.searchJokerLocationID then + Brainstorm.SETTINGS.autoreroll.searchJokerLocationID = 1 + end end end _RELEASE_MODE = not Brainstorm.SETTINGS.debug_mode diff --git a/Brainstorm_UI.lua b/Brainstorm_UI.lua index e69abda..1458bba 100644 --- a/Brainstorm_UI.lua +++ b/Brainstorm_UI.lua @@ -204,9 +204,16 @@ Brainstorm.seedsPerFrame = { ["1000"] = 1000, } +Brainstorm.SearchJokerLocationList = { + ["In Any Location"] = "any", + ["In Any Buffoon Pack"] = "pack", + ["In Shop Slots"] = "shop", +} + local searchTagKeys = {"None", "Charm Tag", "Double Tag", "Uncommon Tag", "Rare Tag", "Holographic Tag", "Foil Tag", "Polychrome Tag", "Investment Tag", "Voucher Tag", "Boss Tag", "Juggle Tag", "Coupon Tag", "Economy Tag", "Skip Tag", "D6 Tag"} local searchPackKeys = {"None", "Arcana", "Celestial", "Standard", "Buffoon", "Spectral", "Normal Arcana", "Jumbo Arcana", "Mega Arcana", "Normal Celestial", "Jumbo Celestial", "Mega Celestial", "Normal Standard", "Jumbo Standard", "Mega Standard", "Normal Buffoon", "Jumbo Buffoon", "Mega Buffoon", "Normal Spectral", "Jumbo Spectral", "Mega Spectral"} local searchJokerKeys = {"None", "8 Ball", "Abstract Joker", "Acrobat", "Ancient Joker", "Arrowhead", "Astronomer", "Banner", "Baron", "Baseball Card", "Blackboard", "Bloodstone", "Blue Joker", "Blueprint", "Bootstraps", "Brainstorm", "Bull", "Burglar", "Burnt Joker", "Business Card", "Caino", "Campfire", "Card Sharp", "Cartomancer", "Castle", "Cavendish", "Ceremonial Dagger", "Certificate", "Chaos the Clown", "Chicot", "Clever Joker", "Cloud 9", "Constellation", "Crafty Joker", "Crazy Joker", "Credit Card", "Delayed Gratification", "Devious Joker", "Diet Cola", "DNA", "Driver's License", "Droll Joker", "Drunkard", "Dusk", "Egg", "Erosion", "Even Steven", "Faceless Joker", "Fibonacci", "Flash Card", "Flower Pot", "Fortune Teller", "Four Fingers", "Gift Card", "Glass Joker", "Gluttonous Joker", "Golden Joker", "Golden Ticket", "Green Joker", "Greedy Joker", "Gros Michel", "Hack", "Half Joker", "Hallucination", "Hanging Chad", "Hiker", "Hit the Road", "Hologram", "Ice Cream", "Invisible Joker", "Joker", "Joker Stencil", "Jolly Joker", "Juggler", "Luchador", "Lucky Cat", "Lusty Joker", "Mad Joker", "Madness", "Mail-In Rebate", "Marble Joker", "Matador", "Merry Andy", "Midas Mask", "Mime", "Misprint", "Mr. Bones", "Mystic Summit", "Obelisk", "Odd Todd", "Onyx Agate", "Oops! All 6s", "Pareidolia", "Perkeo", "Photograph", "Popcorn", "Raised Fist", "Ramen", "Red Card", "Reserved Parking", "Ride the Bus", "Riff-raff", "Rocket", "Rough Gem", "Runner", "Satellite", "Scary Face", "Scholar", "Seance", "Seeing Double", "Seltzer", "Shoot the Moon", "Shortcut", "Showman", "Sixth Sense", "Sly Joker", "Smeared Joker", "Smiley Face", "Sock and Buskin", "Space Joker", "Spare Trousers", "Splash", "Square Joker", "Steel Joker", "Stone Joker", "Stuntman", "Supernova", "Superposition", "Swashbuckler", "The Duo", "The Family", "The Idol", "The Order", "The Tribe", "The Trio", "Throwback", "To Do List", "To the Moon", "Trading Card", "Triboulet", "Troubadour", "Turtle Bean", "Vagabond", "Vampire", "Walkie Talkie", "Wee Joker", "Wily Joker", "Wrathful Joker", "Yorick", "Zany Joker"} +local searchJokerLocationKeys = {"In Any Location", "In Any Buffoon Pack", "In Shop Slots"} local seedsPerFrame = {"500", "750", "1000"} -- print(Brainstorm.FUNCS.inspect(searchTagKeys)) @@ -261,6 +268,14 @@ function create_tabs(args) opt_callback = "change_search_joker", current_option = Brainstorm.SETTINGS.autoreroll.searchJokerID or 1, }), + create_option_cycle({ + label = "Search Joker Location", + scale = 0.8, + w = 4, + options = searchJokerLocationKeys, + opt_callback = "change_search_joker_location", + current_option = Brainstorm.SETTINGS.autoreroll.searchJokerLocationID or 1, + }), create_option_cycle({ label = "Charm Tag/Arcana Pack: Number of Souls", scale = 0.8, diff --git a/Brainstorm_reroll.lua b/Brainstorm_reroll.lua index 200f3bf..a871019 100644 --- a/Brainstorm_reroll.lua +++ b/Brainstorm_reroll.lua @@ -21,6 +21,12 @@ G.FUNCS.change_search_joker = function(x) nativefs.write(lovely.mod_dir .. "/Brainstorm/settings.lua", STR_PACK(Brainstorm.SETTINGS)) end +G.FUNCS.change_search_joker_location = function(x) + Brainstorm.SETTINGS.autoreroll.searchJokerLocationID = x.to_key + Brainstorm.SETTINGS.autoreroll.searchJokerLocation = Brainstorm.SearchJokerLocationList[x.to_val] + nativefs.write(lovely.mod_dir .. "/Brainstorm/settings.lua", STR_PACK(Brainstorm.SETTINGS)) +end + G.FUNCS.change_search_soul_count = function(x) Brainstorm.SETTINGS.autoreroll.searchForSoul = x.to_val nativefs.write(lovely.mod_dir .. "/Brainstorm/settings.lua", STR_PACK(Brainstorm.SETTINGS)) @@ -105,57 +111,76 @@ function Brainstorm.auto_reroll() sendDebugMessage("[Brainstorm] Checking seed: " .. seed_found .. " for joker: " .. Brainstorm.SETTINGS.autoreroll.searchJoker) end local joker_found = false - -- Check both shop pack slots for buffoon packs - for slot = 1, 2 do - local slot_cume, slot_it, slot_center = 0, 0, nil - for k, v in ipairs(G.P_CENTER_POOLS['Booster']) do - if (not _type or _type == v.kind) then slot_cume = slot_cume + (v.weight or 1) end + local location = Brainstorm.SETTINGS.autoreroll.searchJokerLocation or "any" + + -- Check shop slots if location is "shop" or "any" + if location == "shop" or location == "any" then + if Brainstorm.SETTINGS.debug_mode then + sendDebugMessage("[Brainstorm] Checking shop slots...") end - local slot_poll = pseudorandom(Brainstorm.pseudoseed("shop_pack"..slot..seed_found))*slot_cume - for k, v in ipairs(G.P_CENTER_POOLS['Booster']) do - if not _type or _type == v.kind then slot_it = slot_it + (v.weight or 1) end - if slot_it >= slot_poll and slot_it - (v.weight or 1) <= slot_poll then - slot_center = v - break - end + if simulate_shop_jokers(seed_found) then + joker_found = true end - -- If this slot has a buffoon pack, check for the joker - if slot_center then - if Brainstorm.SETTINGS.debug_mode then - sendDebugMessage("[Brainstorm] Slot " .. slot .. " pack: " .. slot_center.key) + end + + -- Check buffoon packs if location is "pack" or "any" (and not already found) + if not joker_found and (location == "pack" or location == "any") then + if Brainstorm.SETTINGS.debug_mode then + sendDebugMessage("[Brainstorm] Checking buffoon packs...") + end + -- Check both shop pack slots for buffoon packs + for slot = 1, 2 do + local slot_cume, slot_it, slot_center = 0, 0, nil + for k, v in ipairs(G.P_CENTER_POOLS['Booster']) do + if (not _type or _type == v.kind) then slot_cume = slot_cume + (v.weight or 1) end end - if string.find(slot_center.key, "buffoon") then - -- If pack search is active, verify this is the right pack type - local pack_type_matches = true - if Brainstorm.SETTINGS.autoreroll.searchPack and #Brainstorm.SETTINGS.autoreroll.searchPack > 0 then - pack_type_matches = false - for i = 1, #Brainstorm.SETTINGS.autoreroll.searchPack do - if Brainstorm.SETTINGS.autoreroll.searchPack[i] == slot_center.key then - pack_type_matches = true - break - end - end + local slot_poll = pseudorandom(Brainstorm.pseudoseed("shop_pack"..slot..seed_found))*slot_cume + for k, v in ipairs(G.P_CENTER_POOLS['Booster']) do + if not _type or _type == v.kind then slot_it = slot_it + (v.weight or 1) end + if slot_it >= slot_poll and slot_it - (v.weight or 1) <= slot_poll then + slot_center = v + break + end + end + -- If this slot has a buffoon pack, check for the joker + if slot_center then + if Brainstorm.SETTINGS.debug_mode then + sendDebugMessage("[Brainstorm] Slot " .. slot .. " pack: " .. slot_center.key) end - - if pack_type_matches then - if Brainstorm.SETTINGS.debug_mode then - sendDebugMessage("[Brainstorm] Found buffoon pack, simulating...") + if string.find(slot_center.key, "buffoon") then + -- If pack search is active, verify this is the right pack type + local pack_type_matches = true + if Brainstorm.SETTINGS.autoreroll.searchPack and #Brainstorm.SETTINGS.autoreroll.searchPack > 0 then + pack_type_matches = false + for i = 1, #Brainstorm.SETTINGS.autoreroll.searchPack do + if Brainstorm.SETTINGS.autoreroll.searchPack[i] == slot_center.key then + pack_type_matches = true + break + end + end end - if simulate_buffoon_pack_jokers(slot_center.key, seed_found) then + + if pack_type_matches then if Brainstorm.SETTINGS.debug_mode then - sendDebugMessage("[Brainstorm] *** JOKER FOUND! ***") + sendDebugMessage("[Brainstorm] Found buffoon pack, simulating...") end - joker_found = true - break -- Early exit once joker is found - else - if Brainstorm.SETTINGS.debug_mode then - sendDebugMessage("[Brainstorm] Joker not in this pack") + if simulate_buffoon_pack_jokers(slot_center.key, seed_found) then + if Brainstorm.SETTINGS.debug_mode then + sendDebugMessage("[Brainstorm] *** JOKER FOUND! ***") + end + joker_found = true + break -- Early exit once joker is found + else + if Brainstorm.SETTINGS.debug_mode then + sendDebugMessage("[Brainstorm] Joker not in this pack") + end end end end end end end + if not joker_found then seed_found = nil end @@ -328,6 +353,104 @@ function simulate_buffoon_pack_jokers(pack_key, predict_seed) return false end +function simulate_shop_jokers(predict_seed) + if Brainstorm.SETTINGS.debug_mode then + sendDebugMessage("[Brainstorm] simulate_shop_jokers called with seed: " .. (predict_seed or "nil")) + end + + -- Shop has exactly 2 joker slots (joker_max = 2) + local shop_slots = 2 + + -- Initialize a temporary RNG state for this simulation + local temp_random_state = {} + + -- Simulate each shop slot + for i = 1, shop_slots do + -- First, determine what type of card this slot gets (Joker, Tarot, Planet, etc.) + -- Seed pattern: 'cdt' + ante + local type_key = "cdt1" + if not temp_random_state[type_key] then + temp_random_state[type_key] = pseudohash(type_key .. (predict_seed or '')) + end + temp_random_state[type_key] = math.abs(tonumber(string.format("%.13f", (2.134453429141 + temp_random_state[type_key] * 1.72431234) % 1))) + local type_seed_value = (temp_random_state[type_key] + (pseudohash(predict_seed) or 0)) / 2 + local type_poll = pseudorandom(type_seed_value) + + -- Determine rates (default values from base game) + local joker_rate = 20 + local tarot_rate = 4 + local planet_rate = 4 + local playing_card_rate = 4 + local spectral_rate = 0 + local total_rate = joker_rate + tarot_rate + planet_rate + playing_card_rate + spectral_rate + + -- Check if this slot generates a Joker + local polled_rate = type_poll * total_rate + if polled_rate <= joker_rate then + -- This slot generates a Joker! Now determine which one + if Brainstorm.SETTINGS.debug_mode then + sendDebugMessage("[Brainstorm] Shop slot #" .. i .. " generates a Joker") + end + + -- Determine rarity using 'sho' key_append + -- Seed pattern: 'rarity' + ante + 'sho' + local rarity_key = "rarity1sho" + if not temp_random_state[rarity_key] then + temp_random_state[rarity_key] = pseudohash(rarity_key .. (predict_seed or '')) + end + temp_random_state[rarity_key] = math.abs(tonumber(string.format("%.13f", (2.134453429141 + temp_random_state[rarity_key] * 1.72431234) % 1))) + local rarity_seed_value = (temp_random_state[rarity_key] + (pseudohash(predict_seed) or 0)) / 2 + local rarity_roll = pseudorandom(rarity_seed_value) + + local rarity = 1 -- Common + local rarity_name = "Common" + if rarity_roll > 0.95 then + rarity = 3 -- Rare + rarity_name = "Rare" + elseif rarity_roll > 0.7 then + rarity = 2 -- Uncommon + rarity_name = "Uncommon" + end + if Brainstorm.SETTINGS.debug_mode then + sendDebugMessage("[Brainstorm] Rarity roll: " .. rarity_roll .. " -> " .. rarity_name) + end + + -- Select joker from the rarity pool + -- Seed pattern: 'Joker' + rarity + 'sho' + ante + local joker_key = "Joker" .. rarity .. "sho1" + if not temp_random_state[joker_key] then + temp_random_state[joker_key] = pseudohash(joker_key .. (predict_seed or '')) + end + temp_random_state[joker_key] = math.abs(tonumber(string.format("%.13f", (2.134453429141 + temp_random_state[joker_key] * 1.72431234) % 1))) + local joker_seed_value = (temp_random_state[joker_key] + (pseudohash(predict_seed) or 0)) / 2 + local joker_center = pseudorandom_element(G.P_JOKER_RARITY_POOLS[rarity], joker_seed_value) + + -- Check if this is the joker we're searching for + if joker_center then + if Brainstorm.SETTINGS.debug_mode then + sendDebugMessage("[Brainstorm] Generated: " .. joker_center.key .. " (" .. (joker_center.name or "unknown") .. ")") + end + if joker_center.key == Brainstorm.SETTINGS.autoreroll.searchJoker then + if Brainstorm.SETTINGS.debug_mode then + sendDebugMessage("[Brainstorm] *** MATCH! ***") + end + return true + end + else + if Brainstorm.SETTINGS.debug_mode then + sendDebugMessage("[Brainstorm] ERROR: Failed to generate joker") + end + end + else + if Brainstorm.SETTINGS.debug_mode then + sendDebugMessage("[Brainstorm] Shop slot #" .. i .. " generates non-Joker (type_poll: " .. polled_rate .. ")") + end + end + end + + return false +end + function Brainstorm.pseudoseed(key, predict_seed) if key == "seed" then return math.random()