--- Divvy's Simulation for Balatro - _Vanilla.lua -- -- The simulation functions for all of the vanilla Balatro jokers. local FNSJ = FN.SIM.JOKERS FNSJ.simulate_joker = function(joker_obj, context) if context.cardarea == G.jokers and context.global then FN.SIM.add_mult(joker_obj.ability.mult) end end FNSJ.simulate_greedy_joker = function(joker_obj, context) FN.SIM.JOKERS.add_suit_mult(joker_obj, context) end FNSJ.simulate_lusty_joker = function(joker_obj, context) FN.SIM.JOKERS.add_suit_mult(joker_obj, context) end FNSJ.simulate_wrathful_joker = function(joker_obj, context) FN.SIM.JOKERS.add_suit_mult(joker_obj, context) end FNSJ.simulate_gluttenous_joker = function(joker_obj, context) FN.SIM.JOKERS.add_suit_mult(joker_obj, context) end FNSJ.simulate_jolly = function(joker_obj, context) FN.SIM.JOKERS.add_type_mult(joker_obj, context) end FNSJ.simulate_zany = function(joker_obj, context) FN.SIM.JOKERS.add_type_mult(joker_obj, context) end FNSJ.simulate_mad = function(joker_obj, context) FN.SIM.JOKERS.add_type_mult(joker_obj, context) end FNSJ.simulate_crazy = function(joker_obj, context) FN.SIM.JOKERS.add_type_mult(joker_obj, context) end FNSJ.simulate_droll = function(joker_obj, context) FN.SIM.JOKERS.add_type_mult(joker_obj, context) end FNSJ.simulate_sly = function(joker_obj, context) FN.SIM.JOKERS.add_type_chips(joker_obj, context) end FNSJ.simulate_wily = function(joker_obj, context) FN.SIM.JOKERS.add_type_chips(joker_obj, context) end FNSJ.simulate_clever = function(joker_obj, context) FN.SIM.JOKERS.add_type_chips(joker_obj, context) end FNSJ.simulate_devious = function(joker_obj, context) FN.SIM.JOKERS.add_type_chips(joker_obj, context) end FNSJ.simulate_crafty = function(joker_obj, context) FN.SIM.JOKERS.add_type_chips(joker_obj, context) end FNSJ.simulate_half = function(joker_obj, context) if context.cardarea == G.jokers and context.global then if #context.full_hand <= joker_obj.ability.extra.size then FN.SIM.add_mult(joker_obj.ability.extra.mult) end end end FNSJ.simulate_stencil = function(joker_obj, context) if context.cardarea == G.jokers and context.global then local xmult = G.jokers.config.card_limit - #FN.SIM.env.jokers for _, joker in ipairs(FN.SIM.env.jokers) do if joker.ability.name == "Joker Stencil" then xmult = xmult + 1 end end if joker_obj.ability.x_mult > 1 then FN.SIM.x_mult(joker_obj.ability.x_mult) end end end FNSJ.simulate_four_fingers = function(joker_obj, context) -- Effect not relevant (Meta) end FNSJ.simulate_mime = function(joker_obj, context) if context.cardarea == G.hand and context.repetition then FN.SIM.add_reps(joker_obj.ability.extra) end end FNSJ.simulate_credit_card = function(joker_obj, context) -- Effect not relevant (Meta) end FNSJ.simulate_ceremonial = function(joker_obj, context) if context.cardarea == G.jokers and context.global then FN.SIM.add_mult(joker_obj.ability.mult) end end FNSJ.simulate_banner = function(joker_obj, context) if context.cardarea == G.jokers and context.global then if G.GAME.current_round.discards_left > 0 then local chips = G.GAME.current_round.discards_left * joker_obj.ability.extra FN.SIM.add_chips(chips) end end end FNSJ.simulate_mystic_summit = function(joker_obj, context) if context.cardarea == G.jokers and context.global then if G.GAME.current_round.discards_left == joker_obj.ability.extra.d_remaining then FN.SIM.add_mult(joker_obj.ability.extra.mult) end end end FNSJ.simulate_marble = function(joker_obj, context) -- Effect not relevant (Blind) end FNSJ.simulate_loyalty_card = function(joker_obj, context) if context.cardarea == G.jokers and context.global then local loyalty_diff = G.GAME.hands_played - joker_obj.ability.hands_played_at_create local loyalty_remaining = ((joker_obj.ability.extra.every-1) - loyalty_diff) % (joker_obj.ability.extra.every+1) if loyalty_remaining == joker_obj.ability.extra.every then FN.SIM.x_mult(joker_obj.ability.extra.Xmult) end end end FNSJ.simulate_8_ball = function(joker_obj, context) -- Effect might be relevant? end FNSJ.simulate_misprint = function(joker_obj, context) if context.cardarea == G.jokers and context.global then local exact_mult = pseudorandom("nope", joker_obj.ability.extra.min, joker_obj.ability.extra.max) FN.SIM.add_mult(exact_mult, joker_obj.ability.extra.min, joker_obj.ability.extra.max) end end FNSJ.simulate_dusk = function(joker_obj, context) if context.cardarea == G.play and context.repetition then -- Note: Checking against 1 is needed as hands_left is not decremented as part of simulation if G.GAME.current_round.hands_left == 1 then FN.SIM.add_reps(joker_obj.ability.extra) end end end FNSJ.simulate_raised_fist = function(joker_obj, context) if context.cardarea == G.hand and context.individual then local cur_mult, cur_rank = 15, 15 local raised_card = nil for _, card in ipairs(FN.SIM.env.held_cards) do if cur_rank >= card.rank and card.ability.effect ~= 'Stone Card' then cur_mult = card.base_chips cur_rank = card.rank raised_card = card end end if raised_card == context.other_card and not context.other_card.debuff then FN.SIM.add_mult(2 * cur_mult) end end end FNSJ.simulate_chaos = function(joker_obj, context) -- Effect not relevant (Free Reroll) end FNSJ.simulate_fibonacci = function(joker_obj, context) if context.cardarea == G.play and context.individual then if FN.SIM.is_rank(context.other_card, {2, 3, 5, 8, 14}) and not context.other_card.debuff then FN.SIM.add_mult(joker_obj.ability.extra) end end end FNSJ.simulate_steel_joker = function(joker_obj, context) if context.cardarea == G.jokers and context.global then FN.SIM.x_mult(1 + joker_obj.ability.extra * joker_obj.ability.steel_tally) end end FNSJ.simulate_scary_face = function(joker_obj, context) if context.cardarea == G.play and context.individual then if FN.SIM.is_face(context.other_card) and not context.other_card.debuff then FN.SIM.add_chips(joker_obj.ability.extra) end end end FNSJ.simulate_abstract = function(joker_obj, context) if context.cardarea == G.jokers and context.global then FN.SIM.add_mult(#FN.SIM.env.jokers * joker_obj.ability.extra) end end FNSJ.simulate_delayed_grat = function(joker_obj, context) -- Effect not relevant (End of Round) end FNSJ.simulate_hack = function(joker_obj, context) if context.cardarea == G.play and context.repetition then if not context.other_card.debuff and FN.SIM.is_rank(context.other_card, {2, 3, 4, 5}) then FN.SIM.add_reps(joker_obj.ability.extra) end end end FNSJ.simulate_pareidolia = function(joker_obj, context) -- Effect not relevant (Meta) end FNSJ.simulate_gros_michel = function(joker_obj, context) if context.cardarea == G.jokers and context.global then FN.SIM.add_mult(joker_obj.ability.extra.mult) end end FNSJ.simulate_even_steven = function(joker_obj, context) if context.cardarea == G.play and context.individual then if not context.other_card.debuff and FN.SIM.check_rank_parity(context.other_card, true) then FN.SIM.add_mult(joker_obj.ability.extra) end end end FNSJ.simulate_odd_todd = function(joker_obj, context) if context.cardarea == G.play and context.individual then if not context.other_card.debuff and FN.SIM.check_rank_parity(context.other_card, false) then FN.SIM.add_chips(joker_obj.ability.extra) end end end FNSJ.simulate_scholar = function(joker_obj, context) if context.cardarea == G.play and context.individual then if FN.SIM.is_rank(context.other_card, 14) and not context.other_card.debuff then FN.SIM.add_chips(joker_obj.ability.extra.chips) FN.SIM.add_mult(joker_obj.ability.extra.mult) end end end FNSJ.simulate_business = function(joker_obj, context) if context.cardarea == G.play and context.individual then if FN.SIM.is_face(context.other_card) and not context.other_card.debuff then local exact_dollars, min_dollars, max_dollars = FN.SIM.get_probabilistic_extremes(pseudorandom("false"), joker_obj.ability.extra, 2, 0) FN.SIM.add_dollars(exact_dollars, min_dollars, max_dollars) end end end FNSJ.simulate_supernova = function(joker_obj, context) if context.cardarea == G.jokers and context.global then FN.SIM.add_mult(G.GAME.hands[context.scoring_name].played) end end FNSJ.simulate_ride_the_bus = function(joker_obj, context) if context.cardarea == G.jokers and context.before and not context.blueprint then local faces = false for _, scoring_card in ipairs(context.scoring_hand) do if FN.SIM.is_face(scoring_card) then faces = true end end if faces then joker_obj.ability.mult = 0 else joker_obj.ability.mult = joker_obj.ability.mult + joker_obj.ability.extra end end if context.cardarea == G.jokers and context.global then FN.SIM.add_mult(joker_obj.ability.mult) end end FNSJ.simulate_space = function(joker_obj, context) -- TODO: Verify if context.cardarea == G.jokers and context.before then local hand_data = G.GAME.hands[FN.SIM.env.scoring_name] local rand = pseudorandom("bad") -- Must reuse same pseudorandom value: local exact_chips, min_chips, max_chips = FN.SIM.get_probabilistic_extremes(rand, joker_obj.ability.extra, hand_data.l_chips, 0) local exact_mult, min_mult, max_mult = FN.SIM.get_probabilistic_extremes(rand, joker_obj.ability.extra, hand_data.l_mult, 0) FN.SIM.add_chips(exact_chips, min_chips, max_chips) FN.SIM.add_mult(exact_mult, min_mult, max_mult) end end FNSJ.simulate_egg = function(joker_obj, context) -- Effect not relevant (Meta) end FNSJ.simulate_burglar = function(joker_obj, context) -- Effect not relevant (Meta) end FNSJ.simulate_blackboard = function(joker_obj, context) if context.cardarea == G.jokers and context.global then local black_suits, all_cards = 0, 0 for _, card in ipairs(FN.SIM.env.held_cards) do all_cards = all_cards + 1 if FN.SIM.is_suit(card, "Clubs", true) or FN.SIM.is_suit(card, "Spades", true) then black_suits = black_suits + 1 end end if black_suits == all_cards then FN.SIM.x_mult(joker_obj.ability.extra) end end end FNSJ.simulate_runner = function(joker_obj, context) if context.cardarea == G.jokers and context.before and not context.blueprint then if next(context.poker_hands["Straight"]) then joker_obj.ability.extra.chips = joker_obj.ability.extra.chips + joker_obj.ability.extra.chip_mod end end if context.cardarea == G.jokers and context.global then FN.SIM.add_chips(joker_obj.ability.extra.chips) end end FNSJ.simulate_ice_cream = function(joker_obj, context) if context.cardarea == G.jokers and context.global then FN.SIM.add_chips(joker_obj.ability.extra.chips) end end FNSJ.simulate_dna = function(joker_obj, context) if context.cardarea == G.jokers and context.before then if G.GAME.current_round.hands_played == 0 and #context.full_hand == 1 then local new_card = copy_table(context.full_hand[1]) table.insert(FN.SIM.env.held_cards, new_card) end end end FNSJ.simulate_splash = function(joker_obj, context) -- Effect not relevant (Meta) end FNSJ.simulate_blue_joker = function(joker_obj, context) if context.cardarea == G.jokers and context.global then FN.SIM.add_chips(joker_obj.ability.extra * #G.deck.cards) end end FNSJ.simulate_sixth_sense = function(joker_obj, context) -- Effect might be relevant? end FNSJ.simulate_constellation = function(joker_obj, context) FN.SIM.JOKERS.x_mult_if_global(joker_obj, context) end FNSJ.simulate_hiker = function(joker_obj, context) if context.cardarea == G.play and context.individual then if not context.other_card.debuff then context.other_card.ability.perma_bonus = (context.other_card.ability.perma_bonus or 0) + joker_obj.ability.extra end end end FNSJ.simulate_faceless = function(joker_obj, context) -- Effect not relevant (Discard) end FNSJ.simulate_green_joker = function(joker_obj, context) if context.cardarea == G.jokers and context.before and not context.blueprint then joker_obj.ability.mult = joker_obj.ability.mult + joker_obj.ability.extra.hand_add end if context.cardarea == G.jokers and context.global then FN.SIM.add_mult(joker_obj.ability.mult) end end FNSJ.simulate_superposition = function(joker_obj, context) -- Effect might be relevant? end FNSJ.simulate_todo_list = function(joker_obj, context) if context.cardarea == G.jokers and context.before then if context.scoring_name == joker_obj.ability.to_do_poker_hand then FN.SIM.add_dollars(joker_obj.ability.extra.dollars) end end end FNSJ.simulate_cavendish = function(joker_obj, context) if context.cardarea == G.jokers and context.global then FN.SIM.x_mult(joker_obj.ability.extra.Xmult) end end FNSJ.simulate_card_sharp = function(joker_obj, context) if context.cardarea == G.jokers and context.global then if (G.GAME.hands[context.scoring_name] and G.GAME.hands[context.scoring_name].played_this_round > 1) then FN.SIM.x_mult(joker_obj.ability.extra.Xmult) end end end FNSJ.simulate_red_card = function(joker_obj, context) if context.cardarea == G.jokers and context.global then FN.SIM.add_mult(joker_obj.ability.mult) end end FNSJ.simulate_madness = function(joker_obj, context) FN.SIM.JOKERS.x_mult_if_global(joker_obj, context) end FNSJ.simulate_square = function(joker_obj, context) if context.cardarea == G.jokers and context.before and not context.blueprint then if #context.full_hand == 4 then joker_obj.ability.extra.chips = joker_obj.ability.extra.chips + joker_obj.ability.extra.chip_mod end end if context.cardarea == G.jokers and context.global then FN.SIM.add_chips(joker_obj.ability.extra.chips) end end FNSJ.simulate_seance = function(joker_obj, context) -- Effect might be relevant? (Consumable) end FNSJ.simulate_riff_raff = function(joker_obj, context) -- Effect not relevant (Blind) end FNSJ.simulate_vampire = function(joker_obj, context) if context.cardarea == G.jokers and context.before and not context.blueprint then local num_enhanced = 0 for _, card in ipairs(context.scoring_hand) do if card.ability.name ~= "Default Base" and not card.debuff then num_enhanced = num_enhanced + 1 FN.SIM.set_ability(card, G.P_CENTERS.c_base) end end if num_enhanced > 0 then joker_obj.ability.x_mult = joker_obj.ability.x_mult + (joker_obj.ability.extra * num_enhanced) end end FN.SIM.JOKERS.x_mult_if_global(joker_obj, context) end FNSJ.simulate_shortcut = function(joker_obj, context) -- Effect not relevant (Meta) end FNSJ.simulate_hologram = function(joker_obj, context) FN.SIM.JOKERS.x_mult_if_global(joker_obj, context) end FNSJ.simulate_vagabond = function(joker_obj, context) -- Effect might be relevant? (Consumable) end FNSJ.simulate_baron = function(joker_obj, context) if context.cardarea == G.hand and context.individual then if FN.SIM.is_rank(context.other_card, 13) and not context.other_card.debuff then FN.SIM.x_mult(joker_obj.ability.extra) end end end FNSJ.simulate_cloud_9 = function(joker_obj, context) -- Effect not relevant (End of Round) end FNSJ.simulate_rocket = function(joker_obj, context) -- Effect not relevant (End of Round) end FNSJ.simulate_obelisk = function(joker_obj, context) if context.cardarea == G.jokers and context.before and not context.blueprint then local reset = true local play_more_than = (G.GAME.hands[context.scoring_name].played or 0) for hand_name, hand in pairs(G.GAME.hands) do if hand_name ~= context.scoring_name and hand.played >= play_more_than and hand.visible then reset = false end end if reset then joker_obj.ability.x_mult = 1 else joker_obj.ability.x_mult = joker_obj.ability.x_mult + joker_obj.ability.extra end end FN.SIM.JOKERS.x_mult_if_global(joker_obj, context) end FNSJ.simulate_midas_mask = function(joker_obj, context) if context.cardarea == G.jokers and context.before and not context.blueprint then for _, card in ipairs(context.scoring_hand) do if FN.SIM.is_face(card) then FN.SIM.set_ability(card, G.P_CENTERS.m_gold) end end end end FNSJ.simulate_luchador = function(joker_obj, context) -- Effect not relevant (Meta) end FNSJ.simulate_photograph = function(joker_obj, context) if context.cardarea == G.play and context.individual then local first_face = nil for i = 1, #context.scoring_hand do if FN.SIM.is_face(context.scoring_hand[i]) then first_face = context.scoring_hand[i]; break end end if context.other_card == first_face and not context.other_card.debuff then FN.SIM.x_mult(joker_obj.ability.extra) end end end FNSJ.simulate_gift = function(joker_obj, context) -- Effect not relevant (Meta) end FNSJ.simulate_turtle_bean = function(joker_obj, context) -- Effect not relevant (Meta) end FNSJ.simulate_erosion = function(joker_obj, context) if context.cardarea == G.jokers and context.global then local diff = G.GAME.starting_deck_size - #G.playing_cards if (diff) > 0 then FN.SIM.add_mult(joker_obj.ability.extra * diff) end end end FNSJ.simulate_reserved_parking = function(joker_obj, context) if context.cardarea == G.hand and context.individual then if FN.SIM.is_face(context.other_card) and not context.other_card.debuff then local exact_dollars, min_dollars, max_dollars = FN.SIM.get_probabilistic_extremes(pseudorandom("notthistime"), joker_obj.ability.extra.odds, joker_obj.ability.extra.dollars, 0) FN.SIM.add_dollars(exact_dollars, min_dollars, max_dollars) end end end FNSJ.simulate_mail = function(joker_obj, context) if context.cardarea == G.hand and context.discard then if context.other_card.id == G.GAME.current_round.mail_card.id and not context.other_card.debuff then FN.SIM.add_dollars(joker_obj.ability.extra) end end end FNSJ.simulate_to_the_moon = function(joker_obj, context) -- Effect not relevant (End of Round) end FNSJ.simulate_hallucination = function(joker_obj, context) -- Effect not relevant (Outside of Play) end FNSJ.simulate_fortune_teller = function(joker_obj, context) if context.cardarea == G.jokers and context.global then if G.GAME.consumeable_usage_total and G.GAME.consumeable_usage_total.tarot then FN.SIM.add_mult(G.GAME.consumeable_usage_total.tarot) end end end FNSJ.simulate_juggler = function(joker_obj, context) -- Effect not relevant (Meta) end FNSJ.simulate_drunkard = function(joker_obj, context) -- Effect not relevant (Meta) end FNSJ.simulate_stone = function(joker_obj, context) if context.cardarea == G.jokers and context.global then FN.SIM.add_chips(joker_obj.ability.extra * joker_obj.ability.stone_tally) end end FNSJ.simulate_golden = function(joker_obj, context) -- Effect not relevant (End of Round) end FNSJ.simulate_lucky_cat = function(joker_obj, context) if not joker_obj.ability.x_mult_range then joker_obj.ability.x_mult_range = { min = joker_obj.ability.x_mult, exact = joker_obj.ability.x_mult, max = joker_obj.ability.x_mult, } end if context.cardarea == G.play and context.individual and not context.blueprint then local function lucky_cat(field) if context.other_card.lucky_trigger and context.other_card.lucky_trigger[field] then joker_obj.ability.x_mult_range[field] = joker_obj.ability.x_mult_range[field] + joker_obj.ability.extra if joker_obj.ability.x_mult_range[field] < 1 then joker_obj.ability.x_mult_range[field] = 1 end -- Precaution end end lucky_cat("min") lucky_cat("exact") lucky_cat("max") end if context.cardarea == G.jokers and context.global then FN.SIM.x_mult(joker_obj.ability.x_mult_range.exact, joker_obj.ability.x_mult_range.min, joker_obj.ability.x_mult_range.max) end end FNSJ.simulate_baseball = function(joker_obj, context) if context.cardarea == G.jokers and context.other_joker then if context.other_joker.rarity == 2 and context.other_joker ~= joker_obj then FN.SIM.x_mult(joker_obj.ability.extra) end end end FNSJ.simulate_bull = function(joker_obj, context) if context.cardarea == G.jokers and context.global then local function bull(data) return joker_obj.ability.extra * math.max(0, G.GAME.dollars + data.dollars) end local min_chips = bull(FN.SIM.running.min) local exact_chips = bull(FN.SIM.running.exact) local max_chips = bull(FN.SIM.running.max) FN.SIM.add_chips(exact_chips, min_chips, max_chips) end end FNSJ.simulate_diet_cola = function(joker_obj, context) -- Effect not relevant (Meta) end FNSJ.simulate_trading = function(joker_obj, context) -- Effect not relevant (Discard) end FNSJ.simulate_flash = function(joker_obj, context) if context.cardarea == G.jokers and context.global then FN.SIM.add_mult(joker_obj.ability.mult) end end FNSJ.simulate_popcorn = function(joker_obj, context) if context.cardarea == G.jokers and context.global then FN.SIM.add_mult(joker_obj.ability.mult) end end FNSJ.simulate_trousers = function(joker_obj, context) if context.cardarea == G.jokers and context.before and not context.blueprint then if (next(context.poker_hands["Two Pair"]) or next(context.poker_hands["Full House"])) then joker_obj.ability.mult = joker_obj.ability.mult + joker_obj.ability.extra end end if context.cardarea == G.jokers and context.global then FN.SIM.add_mult(joker_obj.ability.mult) end end FNSJ.simulate_ancient = function(joker_obj, context) if context.cardarea == G.play and context.individual then if FN.SIM.is_suit(context.other_card, G.GAME.current_round.ancient_card.suit) and not context.other_card.debuff then FN.SIM.x_mult(joker_obj.ability.extra) end end end FNSJ.simulate_ramen = function(joker_obj, context) if context.cardarea == G.hand and context.discard then joker_obj.ability.x_mult = math.max(1, joker_obj.ability.x_mult - joker_obj.ability.extra) end FN.SIM.JOKERS.x_mult_if_global(joker_obj, context) end FNSJ.simulate_walkie_talkie = function(joker_obj, context) if context.cardarea == G.play and context.individual then if FN.SIM.is_rank(context.other_card, {10, 4}) and not context.other_card.debuff then FN.SIM.add_chips(joker_obj.ability.extra.chips) FN.SIM.add_mult(joker_obj.ability.extra.mult) end end end FNSJ.simulate_selzer = function(joker_obj, context) if context.cardarea == G.play and context.repetition then FN.SIM.add_reps(1) end end FNSJ.simulate_castle = function(joker_obj, context) if context.cardarea == G.hand and context.discard and not context.blueprint then if FN.SIM.is_suit(context.other_card, G.GAME.current_round.castle_card.suit) and not context.other_card.debuff then joker_obj.ability.extra.chips = joker_obj.ability.extra.chips + joker_obj.ability.extra.chip_mod end end if context.cardarea == G.jokers and context.global then FN.SIM.add_chips(joker_obj.ability.extra.chips) end end FNSJ.simulate_smiley = function(joker_obj, context) if context.cardarea == G.play and context.individual then if FN.SIM.is_face(context.other_card) and not context.other_card.debuff then FN.SIM.add_mult(joker_obj.ability.extra) end end end FNSJ.simulate_campfire = function(joker_obj, context) FN.SIM.JOKERS.x_mult_if_global(joker_obj, context) end FNSJ.simulate_ticket = function(joker_obj, context) if context.cardarea == G.play and context.individual then if context.other_card.ability.effect == "Gold Card" and not context.other_card.debuff then FN.SIM.add_dollars(joker_obj.ability.extra) end end end FNSJ.simulate_mr_bones = function(joker_obj, context) -- Effect not relevant (Meta) end FNSJ.simulate_acrobat = function(joker_obj, context) if context.cardarea == G.jokers and context.global then -- Note: Checking against 1 is needed as hands_left is not decremented as part of simulation if G.GAME.current_round.hands_left == 1 then FN.SIM.x_mult(joker_obj.ability.extra) end end end FNSJ.simulate_sock_and_buskin = function(joker_obj, context) if context.cardarea == G.play and context.repetition then if FN.SIM.is_face(context.other_card) and not context.other_card.debuff then FN.SIM.add_reps(joker_obj.ability.extra) end end end FNSJ.simulate_swashbuckler = function(joker_obj, context) if context.cardarea == G.jokers and context.global then FN.SIM.add_mult(joker_obj.ability.mult) end end FNSJ.simulate_troubadour = function(joker_obj, context) -- Effect not relevant (Meta) end FNSJ.simulate_certificate = function(joker_obj, context) -- Effect not relevant (Meta) end FNSJ.simulate_smeared = function(joker_obj, context) -- Effect not relevant (Meta) end FNSJ.simulate_throwback = function(joker_obj, context) FN.SIM.JOKERS.x_mult_if_global(joker_obj, context) end FNSJ.simulate_hanging_chad = function(joker_obj, context) if context.cardarea == G.play and context.repetition then if context.other_card == context.scoring_hand[1] and not context.other_card.debuff then FN.SIM.add_reps(joker_obj.ability.extra) end end end FNSJ.simulate_rough_gem = function(joker_obj, context) if context.cardarea == G.play and context.individual then if FN.SIM.is_suit(context.other_card, "Diamonds") and not context.other_card.debuff then FN.SIM.add_dollars(joker_obj.ability.extra) end end end FNSJ.simulate_bloodstone = function(joker_obj, context) if context.cardarea == G.play and context.individual then if FN.SIM.is_suit(context.other_card, "Hearts") and not context.other_card.debuff then local exact_xmult, min_xmult, max_xmult = FN.SIM.get_probabilistic_extremes(pseudorandom("nopeagain"), joker_obj.ability.extra.odds, joker_obj.ability.extra.Xmult, 1) FN.SIM.x_mult(exact_xmult, min_xmult, max_xmult) end end end FNSJ.simulate_arrowhead = function(joker_obj, context) if context.cardarea == G.play and context.individual then if FN.SIM.is_suit(context.other_card, "Spades") and not context.other_card.debuff then FN.SIM.add_chips(joker_obj.ability.extra) end end end FNSJ.simulate_onyx_agate = function(joker_obj, context) if context.cardarea == G.play and context.individual then if FN.SIM.is_suit(context.other_card, "Clubs") and not context.other_card.debuff then FN.SIM.add_mult(joker_obj.ability.extra) end end end FNSJ.simulate_glass = function(joker_obj, context) FN.SIM.JOKERS.x_mult_if_global(joker_obj, context) end FNSJ.simulate_ring_master = function(joker_obj, context) -- Effect not relevant (Note: this is actually Showman) end FNSJ.simulate_flower_pot = function(joker_obj, context) if context.cardarea == G.jokers and context.global then local suit_count = { ["Hearts"] = 0, ["Diamonds"] = 0, ["Spades"] = 0, ["Clubs"] = 0 } function inc_suit(suit) suit_count[suit] = suit_count[suit] + 1 end -- Account for all 'real' suits. -- NOTE: Debuffed (non-wild) cards are still counted for their suits for _, card in ipairs(context.scoring_hand) do if card.ability.effect ~= "Wild Card" then if FN.SIM.is_suit(card, "Hearts", true) and suit_count["Hearts"] == 0 then inc_suit("Hearts") elseif FN.SIM.is_suit(card, "Diamonds", true) and suit_count["Diamonds"] == 0 then inc_suit("Diamonds") elseif FN.SIM.is_suit(card, "Spades", true) and suit_count["Spades"] == 0 then inc_suit("Spades") elseif FN.SIM.is_suit(card, "Clubs", true) and suit_count["Clubs"] == 0 then inc_suit("Clubs") end end end -- Let Wild Cards fill in the gaps. -- NOTE: Debuffed wild cards are completely ignored for _, card in ipairs(context.scoring_hand) do if card.ability.effect == "Wild Card" then if FN.SIM.is_suit(card, "Hearts") and suit_count["Hearts"] == 0 then inc_suit("Hearts") elseif FN.SIM.is_suit(card, "Diamonds") and suit_count["Diamonds"] == 0 then inc_suit("Diamonds") elseif FN.SIM.is_suit(card, "Spades") and suit_count["Spades"] == 0 then inc_suit("Spades") elseif FN.SIM.is_suit(card, "Clubs") and suit_count["Clubs"] == 0 then inc_suit("Clubs") end end end if suit_count["Hearts"] > 0 and suit_count["Diamonds"] > 0 and suit_count["Spades"] > 0 and suit_count["Clubs"] > 0 then FN.SIM.x_mult(joker_obj.ability.extra) end end end FNSJ.simulate_blueprint = function(joker_obj, context) local joker_to_mimic = nil for idx, joker in ipairs(FN.SIM.env.jokers) do if joker == joker_obj then joker_to_mimic = FN.SIM.env.jokers[idx+1] end end if joker_to_mimic then context.blueprint = (context.blueprint and (context.blueprint + 1)) or 1 if context.blueprint > #FN.SIM.env.jokers + 1 then return end FN.SIM.simulate_joker(joker_to_mimic, context) end end FNSJ.simulate_wee = function(joker_obj, context) if context.cardarea == G.play and context.individual and not context.blueprint then if FN.SIM.is_rank(context.other_card, 2) and not context.other_card.debuff then joker_obj.ability.extra.chips = joker_obj.ability.extra.chips + joker_obj.ability.extra.chip_mod end end if context.cardarea == G.jokers and context.global then FN.SIM.add_chips(joker_obj.ability.extra.chips) end end FNSJ.simulate_merry_andy = function(joker_obj, context) -- Effect not relevant (Meta) end FNSJ.simulate_oops = function(joker_obj, context) -- Effect not relevant (Meta) end FNSJ.simulate_idol = function(joker_obj, context) if context.cardarea == G.play and context.individual then if FN.SIM.is_rank(context.other_card, G.GAME.current_round.idol_card.id) and FN.SIM.is_suit(context.other_card, G.GAME.current_round.idol_card.suit) and not context.other_card.debuff then FN.SIM.x_mult(joker_obj.ability.extra) end end end FNSJ.simulate_seeing_double = function(joker_obj, context) if context.cardarea == G.jokers and context.global then local suit_count = { ["Hearts"] = 0, ["Diamonds"] = 0, ["Spades"] = 0, ["Clubs"] = 0 } function inc_suit(suit) suit_count[suit] = suit_count[suit] + 1 end -- Account for all 'real' suits: for _, card in ipairs(context.scoring_hand) do if card.ability.effect ~= "Wild Card" then if FN.SIM.is_suit(card, "Hearts") then inc_suit("Hearts") end if FN.SIM.is_suit(card, "Diamonds") then inc_suit("Diamonds") end if FN.SIM.is_suit(card, "Spades") then inc_suit("Spades") end if FN.SIM.is_suit(card, "Clubs") then inc_suit("Clubs") end end end -- Let Wild Cards fill in the gaps: for _, card in ipairs(context.scoring_hand) do if card.ability.effect == "Wild Card" then if suit_count["Clubs"] == 0 then inc_suit("Clubs") elseif FN.SIM.is_suit(card, "Diamonds") and suit_count["Diamonds"] == 0 then inc_suit("Diamonds") elseif FN.SIM.is_suit(card, "Spades") and suit_count["Spades"] == 0 then inc_suit("Spades") elseif FN.SIM.is_suit(card, "Hearts") and suit_count["Hearts"] == 0 then inc_suit("Hearts") end end end if suit_count["Clubs"] > 0 and (suit_count["Hearts"] > 0 or suit_count["Diamonds"] > 0 or suit_count["Spades"] > 0) then FN.SIM.x_mult(joker_obj.ability.extra) end end end FNSJ.simulate_matador = function(joker_obj, context) if context.cardarea == G.jokers and context.debuffed_hand then if G.GAME.blind.triggered then FN.SIM.add_dollars(joker_obj.ability.extra) end end end FNSJ.simulate_hit_the_road = function(joker_obj, context) if context.cardarea == G.hand and context.discard and not context.blueprint then if context.other_card.id == 11 and not context.other_card.debuff then joker_obj.ability.x_mult = joker_obj.ability.x_mult + joker_obj.ability.extra end end FN.SIM.JOKERS.x_mult_if_global(joker_obj, context) end FNSJ.simulate_duo = function(joker_obj, context) FN.SIM.JOKERS.x_mult_if_global(joker_obj, context) end FNSJ.simulate_trio = function(joker_obj, context) FN.SIM.JOKERS.x_mult_if_global(joker_obj, context) end FNSJ.simulate_family = function(joker_obj, context) FN.SIM.JOKERS.x_mult_if_global(joker_obj, context) end FNSJ.simulate_order = function(joker_obj, context) FN.SIM.JOKERS.x_mult_if_global(joker_obj, context) end FNSJ.simulate_tribe = function(joker_obj, context) FN.SIM.JOKERS.x_mult_if_global(joker_obj, context) end FNSJ.simulate_stuntman = function(joker_obj, context) if context.cardarea == G.jokers and context.global then FN.SIM.add_chips(joker_obj.ability.extra.chip_mod) end end FNSJ.simulate_invisible = function(joker_obj, context) -- Effect not relevant (Meta) end FNSJ.simulate_brainstorm = function(joker_obj, context) local joker_to_mimic = FN.SIM.env.jokers[1] if joker_to_mimic and joker_to_mimic ~= joker_obj then context.blueprint = (context.blueprint and (context.blueprint + 1)) or 1 if context.blueprint > #FN.SIM.env.jokers + 1 then return end FN.SIM.simulate_joker(joker_to_mimic, context) end end FNSJ.simulate_satellite = function(joker_obj, context) -- Effect not relevant (End of Round) end FNSJ.simulate_shoot_the_moon = function(joker_obj, context) if context.cardarea == G.hand and context.individual then if FN.SIM.is_rank(context.other_card, 12) and not context.other_card.debuff then FN.SIM.add_mult(13) end end end FNSJ.simulate_drivers_license = function(joker_obj, context) if context.cardarea == G.jokers and context.global then if (joker_obj.ability.driver_tally or 0) >= 16 then FN.SIM.x_mult(joker_obj.ability.extra) end end end FNSJ.simulate_cartomancer = function(joker_obj, context) -- Effect not relevant (Blind) end FNSJ.simulate_astronomer = function(joker_obj, context) -- Effect not relevant (Meta) end FNSJ.simulate_burnt = function(joker_obj, context) -- Effect not relevant (Discard) end FNSJ.simulate_bootstraps = function(joker_obj, context) if context.cardarea == G.jokers and context.global then local function bootstraps(data) return joker_obj.ability.extra.mult * math.floor((G.GAME.dollars + data.dollars) / joker_obj.ability.extra.dollars) end local min_mult = bootstraps(FN.SIM.running.min) local exact_mult = bootstraps(FN.SIM.running.exact) local max_mult = bootstraps(FN.SIM.running.max) FN.SIM.add_mult(exact_mult, min_mult, max_mult) end end FNSJ.simulate_caino = function(joker_obj, context) if context.cardarea == G.jokers and context.global then if joker_obj.ability.caino_xmult > 1 then FN.SIM.x_mult(joker_obj.ability.caino_xmult) end end end FNSJ.simulate_triboulet = function(joker_obj, context) if context.cardarea == G.play and context.individual then if FN.SIM.is_rank(context.other_card, {12, 13}) and not context.other_card.debuff then FN.SIM.x_mult(joker_obj.ability.extra) end end end FNSJ.simulate_yorick = function(joker_obj, context) if context.cardarea == G.hand and context.discard and not context.blueprint then -- This is only necessary for 'The Hook' blind. if joker_obj.ability.yorick_discards > 1 then joker_obj.ability.yorick_discards = joker_obj.ability.yorick_discards - 1 else joker_obj.ability.yorick_discards = joker_obj.ability.extra.discards joker_obj.ability.x_mult = joker_obj.ability.x_mult + joker_obj.ability.extra.xmult end end FN.SIM.JOKERS.x_mult_if_global(joker_obj, context) end FNSJ.simulate_chicot = function(joker_obj, context) -- Effect not relevant (Meta) end FNSJ.simulate_perkeo = function(joker_obj, context) -- Effect not relevant (Blind) end