diff --git a/README.md b/README.md index 73e9504..0b3249f 100644 --- a/README.md +++ b/README.md @@ -7,7 +7,7 @@
-The are a total of 15 fusions added in the mod, with more coming in the future!
+There are a total of 17 fusions added in the mod, two of which are exclusive to [Six Suits](https://github.com/Aurelius7309/SixSuits)!
You can find a list of their abilities, as well as the jokers needed to make them, in this link: https://itayfeder.github.io/Fusion-Jokers/
## ⬇ How to Download
- The mod requires Steamodded. You can see info about how to use it [here](https://github.com/Steamopollys/Steamodded)
-- Download the latest release of Fusion Jokers
+- Download the latest release of Fusion Jokers from the [releases tab](https://github.com/wingedcatgirl/Fusion-Jokers/releases) (should be stable), or the latest commit from the green "Code" button up there (might include bugfixes for some dumb thing I overlooked earlier)
- Extract the downloaded mod to the Mods folder (at %appdata%/Balatro/Mods)
+## ⚙️ Config
+
+- **Block used components from reappearing**: Jokers used in a fusion cannot reappear if the fusion is present. Default true.
+ - These Jokers can reappear regardless if Showman or a Showman-like effect is active, if the fused Joker's `in_pool()` has `{allow_returning_components = true}` in its second return value, or if the component Joker's `in_pool()` has `{allow_duplicates = true}` in its second return value.
+- **Alt art for Club Wizard**: A lighter color to better match high-contrast Clubs.
+- **No price flickering**: Stop the fusion cost from flickering when multiple fusions are possible.
+
## ➕ Fusion API (For Developers)
The mod adds a way for other developers to create their own fusions!
-Developers can call the function `FusionJokers.fusions:add_fusion()` to register their own fusion to the game. The function also allows them to determine carried stats between the component jokers and the fusion joker.
+Developers can call the function `FusionJokers.fusions:register_fusion()` to register their own fusion to the game. The function also allows them to determine carried stats between the component jokers and the fusion joker.
+
+```lua
+FusionJokers.fusions:register_fusion{
+ jokers = {
+ --First component Joker; all values except "name" optional
+ { name = "j_modprefix_key", carry_stat = "stat_to_carry", merge_stat = "stat_to_merge" },
+ -- String, key of component 1 String, name of stat String, name of stat
+ -- to carry over to merge
+ { name = "j_modprefix_key", carry_stat = "stat_to_carry", merge_stat = "stat_to_merge" },
+ --Second component Joker; same values.
+ --This works for arbitrary numbers of additional Jokers
+ --if you want to do the Exodia thing.
+ },
+ result_joker = "j_modprefix_key", --String, key of result Joker
+ cost = number, --Number, cost in $ to fuse this recipe
+ requirement = func, --Optional function; fusion can only be carried out if this function returns `true`.
+ merged_stat = "stat", --Optional string, name of stat that contains "merge_stat"s above
+ aftermath = func, --Optional function; will be run after the fusion is complete.
+}
+```
+
+> [!NOTE]
+> Carried and merged stats _always_ go in the new Joker's `ability.extra` table now! You also no longer need to specify whether the component Jokers' abilities are in an `extra` table or not; this is now detected automatically.
+
+> [!NOTE]
+> The old `add_fusion` method is depreciated and kept only for compatibility; please switch to `register_fusion` at your earliest convenience! You should be able to use [this regex](https://regex101.com/r/msZHKS/2/substitution) to quickly swap everything in your codespace.
+
+When fusing, calculation is called with the following context:
+```lua
+context = {
+ fusing_jokers = true, --Boolean to flag this context
+ fusion_components = {
+ [1] = Card, --first Joker to be fused away
+ [2] = Card, --next Joker to be fused away
+ --and so forth
+ },
+ fusion_result = Card --resulting Joker
+}
+```
+
+Fusions can be discounted by indexing a number to the final joker's key in `G.GAME.fujo_fusion_discount` for a flat discount in dollars, or `G.GAME.fujo_fusion_discountpercent` for a percentage discount. Alternately, index at the `universal` key for a discount that applies to all fusions. (Decimals always round down; minimum $1 after all discounts.)
## 🎉 Credits
-- The mod was written by [**Itayfeder**](https://github.com/stars/itayfeder/lists/balatro-modding), with art created by [**Lyman**](https://github.com/spikeof2010)
+- The original mod was written by [**Itayfeder**](https://github.com/stars/itayfeder/lists/balatro-modding), with art created by [**Lyman**](https://github.com/spikeof2010)
+- [**elbe**](https://github.com/lshtech) maintained the mod for several months through breaking Steamodded changes, and added some features
+- [**wingedcatgirl**](https://github.com/wingedcatgirl) (hi!) is the current mod maintainer
diff --git a/mod/FusionJokers.json b/mod/FusionJokers.json
new file mode 100644
index 0000000..71c6d46
--- /dev/null
+++ b/mod/FusionJokers.json
@@ -0,0 +1,19 @@
+{
+ "id": "FusionJokers",
+ "name": "Fusion Jokers",
+ "display_name": "Fusion Jokers",
+ "author": ["itayfeder", "Lyman"],
+ "description": "Adds the ability to fuse jokers into special new jokers!",
+ "prefix": "fuse",
+ "main_file": "FusionJokers.lua",
+ "priority": -10000,
+ "badge_colour": "B26CBB",
+ "badge_text_colour": "FFFFFF",
+ "version": "1.2.2~BETA-20260715",
+ "dependencies": [
+ "Steamodded (>=1.0.0~BETA-0827a)",
+ ],
+ "conflicts": [
+ "Talisman (<=2.0)",
+ ],
+}
diff --git a/mod/FusionJokers.lua b/mod/FusionJokers.lua
index 4f95aff..ea18ac8 100644
--- a/mod/FusionJokers.lua
+++ b/mod/FusionJokers.lua
@@ -1,15 +1,3 @@
---- STEAMODDED HEADER
---- MOD_NAME: Fusion Jokers
---- MOD_ID: FusionJokers
---- MOD_AUTHOR: [itayfeder, Lyman]
---- MOD_DESCRIPTION: Adds the ability to fuse jokers into special new jokers!
---- BADGE_COLOUR: B26CBB
---- PRIORITY: -10000
---- PREFIX: fuse
-----------------------------------------------
-------------MOD CODE -------------------------
-
-
G.localization.misc.dictionary["k_fusion"] = "Fusion"
G.localization.misc.dictionary["k_flipped_ex"] = "Flipped!"
G.localization.misc.dictionary["k_copied_ex"] = "Cloned!"
@@ -20,75 +8,84 @@ FusionJokers.fusions = {
{ jokers = {
{ name = "j_greedy_joker", carry_stat = nil, extra_stat = false },
{ name = "j_rough_gem", carry_stat = nil, extra_stat = false }
- }, result_joker = "j_diamond_bard", cost = 12 },
+ }, result_joker = "j_fuse_diamond_bard", cost = 12 },
{ jokers = {
{ name = "j_lusty_joker", carry_stat = nil, extra_stat = false },
{ name = "j_bloodstone", carry_stat = nil, extra_stat = false }
- }, result_joker = "j_heart_paladin", cost = 12 },
+ }, result_joker = "j_fuse_heart_paladin", cost = 12 },
{ jokers = {
{ name = "j_wrathful_joker", carry_stat = nil, extra_stat = false },
{ name = "j_arrowhead", carry_stat = nil, extra_stat = false }
- }, result_joker = "j_spade_archer", cost = 12 },
+ }, result_joker = "j_fuse_spade_archer", cost = 12 },
{ jokers = {
{ name = "j_gluttenous_joker", carry_stat = nil, extra_stat = false },
{ name = "j_onyx_agate", carry_stat = nil, extra_stat = false }
- }, result_joker = "j_club_wizard", cost = 12 },
+ }, result_joker = "j_fuse_club_wizard", cost = 12 },
{ jokers = {
{ name = "j_supernova", carry_stat = nil, extra_stat = false },
{ name = "j_constellation", carry_stat = nil, extra_stat = false }
- }, result_joker = "j_big_bang", cost = 11 },
+ }, result_joker = "j_fuse_big_bang", cost = 11 },
{ jokers = {
{ name = "j_even_steven", carry_stat = nil, extra_stat = false },
{ name = "j_odd_todd", carry_stat = nil, extra_stat = false }
- }, result_joker = "j_dynamic_duo", cost = 8 },
+ }, result_joker = "j_fuse_dynamic_duo", cost = 8 },
{ jokers = {
{ name = "j_flash", carry_stat = "mult", extra_stat = false },
{ name = "j_chaos", carry_stat = nil, extra_stat = false }
- }, result_joker = "j_collectible_chaos_card", cost = 9 },
+ }, result_joker = "j_fuse_collectible_chaos_card", cost = 9 },
{ jokers = {
{ name = "j_juggler", carry_stat = nil, extra_stat = false },
{ name = "j_drunkard", carry_stat = nil, extra_stat = false }
- }, result_joker = "j_flip_flop", cost = 9 },
+ }, result_joker = "j_fuse_flip_flop", cost = 9 },
{ jokers = {
{ name = "j_business", carry_stat = nil, extra_stat = false },
{ name = "j_reserved_parking", carry_stat = nil, extra_stat = false }
- }, result_joker = "j_royal_decree", cost = 10 },
+ }, result_joker = "j_fuse_royal_decree", cost = 10 },
{ jokers = {
{ name = "j_abstract", carry_stat = nil, extra_stat = false },
{ name = "j_riff_raff", carry_stat = nil, extra_stat = false }
- }, result_joker = "j_dementia_joker", cost = 8 },
+ }, result_joker = "j_fuse_dementia_joker", cost = 8 },
{ jokers = {
{ name = "j_egg", carry_stat = "extra_value", extra_stat = false },
{ name = "j_golden", carry_stat = nil, extra_stat = false }
- }, result_joker = "j_golden_egg", cost = 10 },
+ }, result_joker = "j_fuse_golden_egg", cost = 10 },
{ jokers = {
{ name = "j_banner", carry_stat = nil, extra_stat = false },
{ name = "j_green_joker", carry_stat = "mult", extra_stat = false }
- }, result_joker = "j_flag_bearer", cost = 9 },
+ }, result_joker = "j_fuse_flag_bearer", cost = 9 },
{ jokers = {
{ name = "j_scary_face", carry_stat = nil, extra_stat = false },
{ name = "j_smiley", carry_stat = nil, extra_stat = false }
- }, result_joker = "j_uncanny_face", cost = 8 },
+ }, result_joker = "j_fuse_uncanny_face", cost = 8 },
{ jokers = {
{ name = "j_ride_the_bus", carry_stat = nil, extra_stat = false },
{ name = "j_drivers_license", carry_stat = nil, extra_stat = false }
- }, result_joker = "j_commercial_driver", cost = 8 },
+ }, result_joker = "j_fuse_commercial_driver", cost = 8 },
{ jokers = {
{ name = "j_hiker", carry_stat = nil, extra_stat = false },
{ name = "j_dusk", carry_stat = nil, extra_stat = false }
- }, result_joker = "j_camping_trip", cost = 10 },
+ }, result_joker = "j_fuse_camping_trip", cost = 10 },
}
-local rarity = SMODS.Rarity{
+FusionJokers.fusionconfig = SMODS.current_mod.config
+SMODS.load_file('configui.lua')()
+
+FusionJokers.fusions.ingredience = {}
+
+for _, fusion in ipairs(FusionJokers.fusions) do
+ local fused = fusion.result_joker
+
+ for _, component in ipairs(fusion.jokers) do
+ local component_name = component.name
+
+ FusionJokers.fusions.ingredience[component_name] = FusionJokers.fusions.ingredience[component_name] or {}
+ FusionJokers.fusions.ingredience[component_name][fused] = true
+ end
+end
+
+
+SMODS.Rarity{
key = "fusion",
- loc_txt = {
- name = "Fusion",
- text = {
- "Can only be obtained",
- "through {C:attention}Fusing{}",
- "two specific Jokers"
- }
- },
default_weight = 0,
badge_colour = HEX("F7D762"),
pools = {["Joker"] = false},
@@ -99,37 +96,145 @@ local rarity = SMODS.Rarity{
local SMODS_Joker_inject=SMODS.Joker.inject
SMODS.Joker.inject =function(self)
- if self.rarity == 5 then
- self.rarity = rarity.key
+ if self.rarity == 5 or self.rarity == "fusion" then
+ self.rarity = "fuse_fusion"
end
SMODS_Joker_inject(self)
end
-function FusionJokers.fusions:add_fusion(joker1, carry_stat1, extra1, joker2, carry_stat2, extra2, result_joker, cost, merged_stat, merge_stat1, merge_stat2, merge_extra)
- table.insert(self,
- { jokers = {
- { name = joker1, carry_stat = carry_stat1, extra_stat = extra1, merge_stat = merge_stat1 },
- { name = joker2, carry_stat = carry_stat2, extra_stat = extra2, merge_stat = merge_stat2 }
- }, result_joker = result_joker, cost = cost, merged_stat = merged_stat, merge_extra = merge_extra })
+function FusionJokers.fusions:register_fusion(t)
+ if type(t) ~= "table" then
+ sendErrorMessage("Invalid format for register_fusion; should be table, got "..type(t), "Fusion Jokers")
+ return
+ end
+ local jokers
+ if t.jokers then jokers = t.jokers
+ else
+ local i = 1
+ jokers = {}
+ while t["joker"..i] do
+ jokers[i] = {
+ name = t["joker"..i],
+ carry_stat = t["carry_stat"..i],
+ merge_stat = t["merge_stat"..i]
+ }
+ i = i+1
+ end
+ end
+
+ for i,v in ipairs(jokers) do
+ FusionJokers.fusions.ingredience[v.name] = FusionJokers.fusions.ingredience[v.name] or {}
+ FusionJokers.fusions.ingredience[v.name][t.result_joker] = true
+ end
+
+ table.insert(self,
+ {
+ jokers = jokers,
+ result_joker = t.result_joker,
+ cost = t.cost,
+ merged_stat = t.merged_stat,
+ requirement = t.requirement,
+ aftermath = t.aftermath,
+ })
+end
+
+function FusionJokers.fusions:add_fusion(joker1, carry_stat1, extra1, joker2, carry_stat2, extra2, result_joker, cost, merged_stat, merge_stat1, merge_stat2)
+ if type(joker1) == "table" then
+ sendWarnMessage("add_fusion expects a list of parameters, not a table; passing table to register_fusion", "Fusion Jokers")
+ FusionJokers.fusions:register_fusion(joker1)
+ else
+ sendWarnMessage("add_fusion is now deprecated, please switch to register_fusion at earliest convenience", "Fusion Jokers")
+
+ self:register_fusion{
+ jokers = {
+ {name = joker1, carry_stat = carry_stat1, merge_stat = merge_stat1 },
+ {name = joker2, carry_stat = carry_stat2, merge_stat = merge_stat2 },
+ },
+ merged_stat = merged_stat,
+ result_joker = result_joker,
+ cost = cost,
+ }
+ end
+end
+
+local atpref = SMODS.add_to_pool
+SMODS.add_to_pool = function (prototype_obj, args)
+ if SMODS.showman(prototype_obj.key) then return true end
+ args = args or {}
+ if FusionJokers.fusionconfig.block_components and FusionJokers.fusions.ingredience[prototype_obj.key] then
+ local flags1,flags2
+ if type(prototype_obj.in_pool) == "function" then
+ _,flags1 = prototype_obj:in_pool(args)
+ end
+ for k,v in pairs(FusionJokers.fusions.ingredience[prototype_obj.key]) do
+ --assert(G.P_CENTERS[k], "Registered fusion "..k.." wants to create an unregistered Joker!\nEnsure "..k.." is a registered Joker, or else don't register this fusion.")
+ if type(G.P_CENTERS[k].in_pool) == "function" then
+ _,flags2 = G.P_CENTERS[k]:in_pool(args)
+ end
+ if not ((flags1 or {}).allow_duplicates or (flags2 or {}).allow_returning_components) and next(SMODS.find_card(k)) then return false end
+ end
+ end
+
+ return atpref(prototype_obj, args)
+end
+
+SMODS.load_file('jokers/diamondbard.lua')()
+SMODS.load_file('jokers/heartpaladin.lua')()
+SMODS.load_file('jokers/spadearcher.lua')()
+SMODS.load_file('jokers/clubwizard.lua')()
+if (SMODS.Mods["SixSuits"] or {}).can_load then
+ SMODS.load_file('jokers/moonmarauder.lua')()
+ SMODS.load_file('jokers/staroracle.lua')()
+end
+SMODS.load_file('jokers/bigbang.lua')()
+SMODS.load_file('jokers/dynamicduo.lua')()
+SMODS.load_file('jokers/collectiblechaos.lua')()
+SMODS.load_file('jokers/flipflop.lua')()
+SMODS.load_file('jokers/royaldecree.lua')()
+SMODS.load_file('jokers/dementiajoker.lua')()
+SMODS.load_file('jokers/goldenegg.lua')()
+SMODS.load_file('jokers/flagbearer.lua')()
+SMODS.load_file('jokers/uncannyface.lua')()
+SMODS.load_file('jokers/commercialdriver.lua')()
+SMODS.load_file('jokers/campingtrip.lua')()
+SMODS.load_file('jokers/test.lua')()
+
+to_number = to_number or function(num)
+ return num
end
-local to_number = to_number or function(num)
+to_big = to_big or function(num)
return num
end
-local function has_joker(val, start_pos)
+local function has_joker(val, start_pos, highlight_only)
if not start_pos then
- start_pos = 0
+ start_pos = 1
end
- for i, v in ipairs(G.jokers.cards) do
- if v.ability.set == 'Joker' and v.config.center_key == val and i > start_pos then
- return i
+ for i,v in ipairs(G.jokers.highlighted) do
+ if v.ability.set == 'Joker' and v.config.center_key == val and i >= start_pos then
+
+ for ii, vv in ipairs(G.jokers.cards) do
+ if vv == v and ii >= start_pos then
+ return ii
+ end
+ end
+
+ end
+ end
+
+ if not highlight_only then
+ for i, v in ipairs(G.jokers.cards) do
+ if v.ability.set == 'Joker' and v.config.center_key == val and i >= start_pos then
+ return i
+ end
end
end
return -1
end
-function Card:can_fuse_card()
+function Card:can_fuse_card(juicing)
+ --[[
for _, fusion in ipairs(FusionJokers.fusions) do
if to_number(G.GAME.dollars) >= fusion.cost then
local found_me = false
@@ -153,23 +258,151 @@ function Card:can_fuse_card()
return true
end
end
- end
- return false
+ end
+ return false
+ --]]
+
+ if self.area ~= G.jokers then return false end --Figure out fusing from other areas later; for now just disable it
+
+ local fusion = self:get_card_fusion()
+ if fusion.cost == "??" then return false, fusion end
+ if fusion.blocked and not juicing then return false, fusion end
+ local reqcheck = true
+ if type(fusion.requirement) == "function" then
+ reqcheck = fusion.requirement()
+ end
+ return reqcheck and (to_big(fusion.cost) + to_big(G.GAME.bankrupt_at or 0)) <= to_big(G.GAME.dollars), fusion
end
-function Card:get_card_fusion()
+function Card:get_card_fusion(debug)
+ debug = debug or G.fusion_debug_flag --Set this with DebugPlus if you want to
+ local dprint = function(msg)
+ if debug then print(msg) end
+ end
+ local function deep_copy(tbl)
+ if type(tbl) ~= "table" then return tbl end
+ local copy = {}
+ for k, v in pairs(tbl) do
+ copy[k] = deep_copy(v)
+ end
+ return copy
+ end
+ local results = {}
+ local held = {}
+ local affordable = {}
+ local result = {
+ result_joker = "No fusions",
+ jokers = {
+ {name = self.config.center_key }
+ },
+ cost = "??"
+ }
+ local jokerspos = {}
for _, fusion in ipairs(FusionJokers.fusions) do
+ local valid = true
for _, joker in ipairs(fusion.jokers) do
if joker.name == self.config.center_key then
- return fusion
+ result.result_joker = "Cannot fuse"
+ local recipe = {}
+ for i,component in ipairs(fusion.jokers) do
+ recipe[component.name] = (recipe[component.name] or 0) + 1
+ dprint(component.name.."s needed: "..tostring(recipe[component.name]))
+ dprint(component.name.."s found: "..tostring(#SMODS.find_card(component.name)))
+ if #SMODS.find_card(component.name) >= recipe[component.name] then
+ valid = valid and true
+ else
+ valid = false
+ end
+ end
+ if valid then
+ results[#results+1] = deep_copy(fusion)
+ end
+ break
end
end
- end
- return nil
+ end
+ if #results > 1 then
+ for i,recipe in ipairs(results) do
+ dprint("Checking if components for "..recipe.result_joker.." are owned")
+ jokerspos = {}
+ local valid = true
+ local startpos = {}
+ for ii,component in ipairs(recipe.jokers) do
+ startpos[component.name] = (startpos[component.name] or 1)
+ if has_joker(component.name, startpos[component.name]) ~= -1 then
+ startpos[component.name] = has_joker(component.name, startpos[component.name])
+ dprint(component.name.." is owned")
+ jokerspos[#jokerspos+1] = startpos[component.name]
+ else
+ valid = false
+ dprint(component.name.." is not owned")
+ break
+ end
+ end
+ if valid then held[#held+1] = deep_copy(results[i]) end
+ end
+ if #held == 1 then return held[1] end
+ if #held == 0 then return result end
+ for i,recipe in ipairs(held) do
+ dprint("Checking if components for "..recipe.result_joker.." are highlighted")
+ local valid = true
+ local startpos = {}
+ for ii,component in ipairs(recipe.jokers) do
+ startpos[component.name] = (startpos[component.name] or 1)
+ if has_joker(component.name, startpos[component.name], true) ~= -1 then
+ startpos[component.name] = has_joker(component.name, startpos[component.name], true)
+ dprint(component.name.." is highlighted")
+ else
+ valid = false
+ dprint(component.name.." is not highlighted")
+ break
+ end
+ end
+ if (to_big(recipe.cost) + to_big(G.GAME.bankrupt_at or 0)) < to_big(G.GAME.dollars) then
+ affordable[#affordable+1] = deep_copy(held[i])
+ end
+ if valid then result = held[i] break end --don't overhighlight :v
+ end
+ elseif #results == 1 then
+ result = results[1]
+ end
+ if #held > 1 and result.cost == "??" then
+ dprint("Picking a random possible fusion...")
+ local possible = #affordable > 0 and affordable or held
+ local speedfac = 8
+ local time = math.floor(love.timer.getTime() * speedfac)
+ if FusionJokers.fusionconfig.no_price_flicker then time = 1 end
+ if G.fusion_debug_flag then print(tostring(time)) end
+ math.randomseed(time)
+ local pick = math.random(1, #possible)
+ result = possible[pick]
+ result.blocked = true
+ else
+ dprint(result.blocked and "Result is blocked when it shouldn't be??" or "Result is not blocked (this is correct)")
+ end
+ if type(result.cost) == type(0) then
+ if G.GAME.fujo_fusion_discount then
+ if G.GAME.fujo_fusion_discount[result.result_joker] then
+ result.cost = result.cost - G.GAME.fujo_fusion_discount[result.result_joker]
+ end
+ result.cost = result.cost - (G.GAME.fujo_fusion_discount.universal or 0)
+ end
+ if G.GAME.fujo_fusion_discountpercent then
+ if G.GAME.fujo_fusion_discountpercent[result.result_joker] then
+ result.cost = result.cost * (1 - G.GAME.fujo_fusion_discountpercent[result.result_joker])
+ end
+ result.cost = result.cost * (1 - (G.GAME.fujo_fusion_discountpercent.universal or 0))
+ end
+ result.cost = math.max(math.floor(result.cost), 1)
+ end
+ return result
end
-
-function Card:fuse_card()
+function Card:fuse_card(debug)
+ debug = debug or G.fusion_debug_flag --Set this with DebugPlus if you want to
+ local dprint = function(msg)
+ if debug then print(msg) end
+ end
G.CONTROLLER.locks.selling_card = true
stop_use()
local area = self.area
@@ -185,108 +418,154 @@ function Card:fuse_card()
edition = self.edition
end
- local chosen_fusion = nil
- local joker_pos = {}
- local found_me = false
- for _, fusion in ipairs(FusionJokers.fusions) do
- joker_pos = {}
- found_me = false
- for _, joker in ipairs(fusion.jokers) do
- if fusion.jokers[1].name == fusion.jokers[2].name then
- if #SMODS.find_card(joker.name) > 1 and #joker_pos == 0 then
- local first_pos = has_joker(joker.name)
- table.insert(joker_pos, {pos = first_pos, joker = joker})
- table.insert(joker_pos, {pos = has_joker(joker.name, first_pos), joker = joker})
- end
- elseif next(SMODS.find_card(joker.name)) then
- table.insert(joker_pos, {pos = has_joker(joker.name), joker = joker})
- end
- if joker.name == self.config.center_key then
+
+ local chosen_fusion = self:get_card_fusion()
+ local carried_stats = {}
+ local merged_stat = 0
+ local total_extra_cost = 0
+ local recipe = {}
+ local me
+ do
+ local fusion = chosen_fusion
+ local found_me = false
+ local list = {}
+ for i,component in ipairs(fusion.jokers) do
+ if component.name == self.config.center_key and not found_me then
+ recipe[#recipe+1] = self
found_me = true
+ self.fused = true
+ total_extra_cost = total_extra_cost + (self.ability.extra_value or 0)
+ if component.carry_stat then
+ carried_stats[component.carry_stat] = (carried_stats[component.carry_stat] or 0) + (type(self.ability.extra) == "table" and self.ability.extra[component.carry_stat] or self.ability[component.carry_stat] or 0)
+ end
+ if component.merge_stat then
+ merged_stat = merged_stat + (type(self.ability.extra) == "table" and self.ability.extra[component.merge_stat] or self.ability[component.merge_stat])
+ end
+ else
+ local found_it = false
+ for ii,vv in ipairs(G.jokers.highlighted) do
+ if vv.config.center_key == component.name and not vv.fused then
+ recipe[#recipe+1] = vv
+ vv.fused = true
+ found_it = true
+ total_extra_cost = total_extra_cost + (vv.ability.extra_value or 0)
+ if component.carry_stat then
+ carried_stats[component.carry_stat] = (carried_stats[component.carry_stat] or 0) + (type(vv.ability.extra) == "table" and vv.ability.extra[component.carry_stat] or vv.ability[component.carry_stat] or 0)
+ end
+ if component.merge_stat then
+ merged_stat = merged_stat + (type(vv.ability.extra) == "table" and vv.ability.extra[component.merge_stat] or vv.ability[component.merge_stat])
+ end
+ break
+ end
+ end
+ if not found_it then
+ for ii,vv in ipairs(G.jokers.cards) do
+ if vv.config.center_key == component.name and not vv.fused then
+ recipe[#recipe+1] = vv
+ vv.fused = true
+ found_it = true
+ if component.carry_stat then
+ carried_stats[component.carry_stat] = (carried_stats[component.carry_stat] or 0) + (type(vv.ability.extra) == "table" and vv.ability.extra[component.carry_stat] or vv.ability[component.carry_stat] or 0)
+ end
+ if component.merge_stat then
+ merged_stat = merged_stat + (type(vv.ability.extra) == "table" and vv.ability.extra[component.merge_stat] or vv.ability[component.merge_stat])
+ end
+ break
+ end
+ end
+ end
+ if not found_it then
+ dprint("Failed to find component Jokers when fusing?")
+ chosen_fusion = nil
+ end
end
end
- if #joker_pos == #fusion.jokers and found_me then
- chosen_fusion = fusion
- break
+ if not (#recipe == #fusion.jokers and found_me) then
+ dprint("Failed to find component Jokers when fusing?")
+ chosen_fusion = nil
end
end
if chosen_fusion ~= nil then
G.E_MANAGER:add_event(Event({trigger = 'after', delay = 0.2,func = function()
play_sound('whoosh1')
- for _, pos in ipairs(joker_pos) do
- if not edition and G.jokers.cards[pos.pos].edition then
- edition = G.jokers.cards[pos.pos].edition
+ for i,v in ipairs(recipe) do
+ if not edition and v.edition then
+ edition = v.edition
end
- G.jokers.cards[pos.pos]:juice_up(0.3, 0.4)
+ v:juice_up(0.3, 0.4)
end
return true
end}))
delay(0.2)
G.E_MANAGER:add_event(Event({trigger = 'immediate',func = function()
ease_dollars(-chosen_fusion.cost)
- local j_fusion = create_card('Joker', G.jokers, nil, nil, nil, nil, chosen_fusion.result_joker, nil)
- if edition and not j_fusion.edition then
- j_fusion.edition = edition
+ local j_fusion = self
+
+ self:set_ability(chosen_fusion.result_joker)
+ if edition and not self.edition then
+ self:set_edition(edition.key)
end
- table.sort(joker_pos, function (a, b)
- return a.pos > b.pos
- end)
- for index, pos in ipairs(joker_pos) do
- local isPrimary = false
- if G.jokers.cards[pos.pos] == self then
- isPrimary = true
- end
+ SMODS.calculate_context{fusing_jokers = true, fusion_components = recipe, fusion_result = j_fusion}
+ for index, ingredient in ipairs(recipe) do
+ local isPrimary = ingredient == self
for k,_ in pairs(SMODS.Stickers) do
- if G.jokers.cards[pos.pos].ability[k] then
- -- if string.find(k, "gemslot") then
- -- local gemExists = false
- -- for k1, _ in pairs(j_fusion.ability) do
- -- if string.find(k1, "gemslot") then
- -- gemExists = true
- -- end
- -- end
- -- if isPrimary then
- -- j_fusion.ability[k] = true
- -- end
- -- else
- j_fusion.ability[k] = true
+ if ingredient.ability[k] then
+ --[[
+ if string.find(k, "gemslot") then
+ local gemExists = false
+ for k1, _ in pairs(j_fusion.ability) do
+ if string.find(k1, "gemslot") then
+ gemExists = true
+ end
+ end
+ if isPrimary then
+ j_fusion.ability[k] = true
+ end
+ else
+ --]]
+ local perish_count = j_fusion.ability.perish_tally or 0
+ j_fusion:add_sticker(k, true)
+ if k == "perishable" then
+ j_fusion.ability.perish_tally = math.max(perish_count, ingredient.ability.perish_tally or 0)
+ end
--end
end
end
- local check_joker = pos.joker
- if check_joker.carry_stat then
- if check_joker.extra_stat then
- j_fusion.ability.extra[check_joker.carry_stat] = G.jokers.cards[pos.pos].ability.extra[check_joker.carry_stat]
- else
- j_fusion.ability[check_joker.carry_stat] = G.jokers.cards[pos.pos].ability[check_joker.carry_stat]
- end
+ --G.jokers.cards[pos]:start_dissolve({G.C.GOLD})
+
+ local flags = SMODS.calculate_context({joker_type_destroyed = true, card = ingredient})
+ if not (flags.no_destroy or isPrimary) then
+ ingredient:remove()
+ else
+ ingredient.fused = nil
end
- if check_joker.merge_stat then
- if chosen_fusion.merge_extra then
- if check_joker.extra_stat then
- j_fusion.ability.extra[chosen_fusion.merged_stat] = j_fusion.ability.extra[chosen_fusion.merged_stat] + G.jokers.cards[pos.pos].ability.extra[check_joker.merge_stat]
- else
- j_fusion.ability.extra[chosen_fusion.merged_stat] = j_fusion.ability.extra[chosen_fusion.merged_stat] + G.jokers.cards[pos.pos].ability[check_joker.merge_stat]
- end
- else
- if check_joker.extra_stat then
- j_fusion.ability[chosen_fusion.merged_stat] = j_fusion.ability[chosen_fusion.merged_stat] + G.jokers.cards[pos.pos].ability.extra[check_joker.merge_stat]
- else
- j_fusion.ability[chosen_fusion.merged_stat] = j_fusion.ability[chosen_fusion.merged_stat] + G.jokers.cards[pos.pos].ability[check_joker.merge_stat]
- end
- end
+ end
+
+ if next(carried_stats) then
+ if type(self.ability.extra) == "number" then
+ local num = self.ability.extra
+ self.ability.extra = {
+ extra = num
+ }
+ elseif type(self.ability.extra) ~= "table" then
+ self.ability.extra = {}
end
- --G.jokers.cards[pos]:start_dissolve({G.C.GOLD})
- G.jokers.cards[pos.pos]:remove()
+ for k,v in pairs(carried_stats) do
+ self.ability.extra[k] = v
+ end
+ end
+ if chosen_fusion.merged_stat then
+ self.ability.extra[chosen_fusion.merged_stat] = merged_stat
end
-
+
delay(0.3)
- j_fusion:add_to_deck()
- G.jokers:emplace(j_fusion)
play_sound('explosion_release1')
+ self.ability.extra_value = total_extra_cost
+ self:set_cost()
+ G.jokers:unhighlight_all()
delay(0.1)
G.E_MANAGER:add_event(Event({trigger = 'after',delay = 0.3, blocking = false,
@@ -305,6 +584,17 @@ function Card:fuse_card()
end}))
return true
end}))
+
+ if type(chosen_fusion.aftermath) == "function" then
+ G.E_MANAGER:add_event(Event({func = function ()
+ chosen_fusion.aftermath()
+ return true
+ end}))
+ end
+ else
+ for i,v in ipairs(recipe) do --Shouldn't happen, but don't leave the fused flag lying around if it does
+ v.fused = nil
+ end
end
G.CONTROLLER.locks.selling_card = nil
@@ -317,7 +607,7 @@ G.FUNCS.fuse_card = function(e)
end
G.FUNCS.can_fuse_card = function(e)
- if e.config.ref_table:can_fuse_card() then
+ if e.config.ref_table:can_fuse_card() then
e.config.colour = G.C.DARK_EDITION
e.config.button = 'fuse_card'
else
@@ -331,11 +621,11 @@ G.FUNCS.can_fuse_card = function(e)
local use_and_sell_buttonsref = G.UIDEF.use_and_sell_buttons
function G.UIDEF.use_and_sell_buttons(card)
local retval = use_and_sell_buttonsref(card)
-
+
if card.area and card.area.config.type == 'joker' and card.ability.set == 'Joker' and card.ability.fusion then
- local fuse =
+ local fuse =
{n=G.UIT.C, config={align = "cr"}, nodes={
-
+
{n=G.UIT.C, config={ref_table = card, align = "cr",maxw = 1.25, padding = 0.1, r=0.08, minw = 1.25, hover = true, shadow = true, colour = G.C.GOLD, one_press = true, button = 'sell_card', func = 'can_fuse_card'}, nodes={
{n=G.UIT.B, config = {w=0.1,h=0.6}},
{n=G.UIT.C, config={align = "tm"}, nodes={
@@ -357,135 +647,36 @@ function G.UIDEF.use_and_sell_buttons(card)
return retval
end
-
-local card_h_popupref = G.UIDEF.card_h_popup
-function G.UIDEF.card_h_popup(card)
- local retval = card_h_popupref(card)
- if not card.config.center or -- no center
- (card.config.center.unlocked == false and not card.bypass_lock) or -- locked card
- card.debuff or -- debuffed card
- (not card.config.center.discovered and ((card.area ~= G.jokers and card.area ~= G.consumeables and card.area) or not card.area)) -- undiscovered card
- then return retval end
-
- if card.config.center.rarity == 5 then
- retval.nodes[1].nodes[1].nodes[1].nodes[3].nodes[1].nodes[1].nodes[2].config.object:remove()
- retval.nodes[1].nodes[1].nodes[1].nodes[3].nodes[1] = create_badge(localize('k_fusion'), loc_colour("fusion", nil), nil, 1.2)
- end
-
- return retval
-end
-
local updateref = Card.update
function Card:update(dt)
updateref(self, dt)
if G.STAGE == G.STAGES.RUN then
+ local fuseable, my_fusion = self:can_fuse_card(true)
- if self.ability.name == "Flip-Flop" then
- if self.ability.extra.side == "mult" then
- if (self.config.center.atlas ~= "j_flip_flop" or G.localization.descriptions["Joker"]["j_flip_flop"] ~= G.localization.descriptions["Joker"]["j_flip_flop_mult"]) then
- G.localization.descriptions["Joker"]["j_flip_flop"] = G.localization.descriptions["Joker"]["j_flip_flop_mult"]
- self.config.center.atlas = "j_flip_flop"
- self:set_sprites(self.config.center)
- end
- else
- if (self.config.center.atlas ~= "j_flop_flip" or G.localization.descriptions["Joker"]["j_flip_flop"] ~= G.localization.descriptions["Joker"]["j_flip_flop_chips"]) then
- G.localization.descriptions["Joker"]["j_flip_flop"] = G.localization.descriptions["Joker"]["j_flip_flop_chips"]
- self.config.center.atlas = "j_flop_flip"
- self:set_sprites(self.config.center)
- end
- end
- end
-
-
- if self:get_card_fusion() ~= nil then
+ if my_fusion and my_fusion.result_joker ~= "No fusions" then
self.ability.fusion = self.ability.fusion or {}
-
- local my_fusion = self:get_card_fusion()
self.fusion_cost = my_fusion.cost
- if self:can_fuse_card() and not self.ability.fusion.jiggle then
- juice_card_until(self, function(card) return (card:can_fuse_card()) end, true)
+ if fuseable and not self.ability.fusion.jiggle then
+ juice_card_until(self,
+ function(card)
+ return (card:can_fuse_card(true))
+ end,
+ true)
self.ability.fusion.jiggle = true
end
-
- if not self:can_fuse_card() and self.ability.fusion.jiggle then
+
+ if not fuseable and self.ability.fusion.jiggle then
self.ability.fusion.jiggle = false
end
+ else
+ self.ability.fusion, self.fusion_cost = nil, nil
end
end
end
-
-local add_to_deckref = Card.add_to_deck
-function Card:add_to_deck(from_debuff)
- if not self.added_to_deck then
- if self.ability.name == 'Collectible Chaos Card' then
- G.GAME.current_round.free_rerolls = G.GAME.current_round.free_rerolls + 1
- calculate_reroll_cost(true)
- end
-
- if self.ability.name == 'Flip-Flop' then
- if self.ability.extra.side == "mult" then
- G.hand:change_size(self.ability.extra.hands)
- else
- G.GAME.round_resets.discards = G.GAME.round_resets.discards + self.ability.extra.discards
- ease_discard(self.ability.extra.discards)
- end
- end
-
- if self.ability.name == 'Star Oracle' then
- G.consumeables:change_size(self.ability.extra.slots)
- end
- end
- add_to_deckref(self, from_debuff)
-end
-
-local remove_from_deckref = Card.remove_from_deck
-function Card:remove_from_deck(from_debuff)
- if self.added_to_deck then
- if self.ability.name == 'Collectible Chaos Card' then
- G.GAME.current_round.free_rerolls = G.GAME.current_round.free_rerolls - 1
- calculate_reroll_cost(true)
- end
-
- if self.ability.name == 'Flip-Flop' then
- if self.ability.extra.side == "mult" then
- G.hand:change_size(-self.ability.extra.hands)
- else
- G.GAME.round_resets.discards = G.GAME.round_resets.discards - self.ability.extra.discards
- ease_discard(-self.ability.extra.discards)
- end
- end
-
- if self.ability.name == 'Star Oracle' then
- G.consumeables:change_size(-self.ability.extra.slots)
- end
- end
- remove_from_deckref(self, from_debuff)
-end
-
-local new_roundref = new_round
-function new_round()
- new_roundref()
- local chaos = find_joker('Collectible Chaos Card')
- G.GAME.current_round.free_rerolls = G.GAME.current_round.free_rerolls or 0
- G.GAME.current_round.free_rerolls = G.GAME.current_round.free_rerolls + #chaos
- calculate_reroll_cost(true)
-end
-
-
-local calculate_dollar_bonusref = Card.calculate_dollar_bonus
-function Card:calculate_dollar_bonus()
- if self.ability.set == "Joker" then
- if self.ability.name == 'Golden Egg' then
- return self.ability.extra.dollars
- end
- end
- return calculate_dollar_bonusref(self)
-end
-
-- local shatterref = Card.shatter
-- function Card:shatter()
-- G.E_MANAGER:add_event(Event({
@@ -499,905 +690,15 @@ end
-- end
-- return true end)
-- }))
-
+
-- shatterref(self)
-- end
-
-
-
-
-function SMODS.INIT.FusionJokers()
- local mod_id = "FusionJokers"
- local mod_obj = SMODS.findModByID(mod_id)
-
- table.insert(G.P_JOKER_RARITY_POOLS, {})
- table.insert(G.C.RARITY, HEX("F7D762"))
-
- loc_colour("mult", nil)
- G.ARGS.LOC_COLOURS["fusion"] = G.C.RARITY[5]
-
-
-
- local diamond_bard_def = {
- name = "Diamond Bard",
- text = {
- "Played cards with {C:diamonds}Diamond{} suit give",
- "{C:money}$#1#{}, as well as {C:mult}+#2#{} Mult for every ",
- "{C:money}$#3#{} you have when scored",
- "{C:inactive}(#4# + #5#)"
- }
- }
-
- local diamond_bard = SMODS.Joker:new("Diamond Bard", "diamond_bard", {extra = {
- money_threshold = 20, mult = 4, money = 1, joker1 = "j_greedy_joker", joker2 = "j_rough_gem"
- }}, { x = 0, y = 0 }, diamond_bard_def, rarity.key, 12, true, false, true, true)
- SMODS.Sprite:new("j_diamond_bard", mod_obj.path, "j_diamond_bard.png", 71, 95, "asset_atli"):register();
- diamond_bard:register()
-
- function SMODS.Jokers.j_diamond_bard.loc_def(card)
- return {card.ability.extra.money, card.ability.extra.mult, card.ability.extra.money_threshold,
- localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
- localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}}
- end
-
- function SMODS.Jokers.j_diamond_bard.calculate(card, context)
- if context.individual and context.cardarea == G.play and
- context.other_card:is_suit('Diamonds') then
- G.GAME.dollar_buffer = (G.GAME.dollar_buffer or 0) + card.ability.extra.money
- G.E_MANAGER:add_event(Event({func = (function() G.GAME.dollar_buffer = 0; return true end)}))
- return {
- dollars = card.ability.extra.money,
- mult = card.ability.extra.mult * (1 + math.floor(G.GAME.dollars / card.ability.extra.money_threshold)),
- card = card
- }
- end
- end
-
-
-
- local heart_paladin_def = {
- name = "Heart Paladin",
- text = {
- "Played cards with {C:hearts}Heart{} suit give",
- "{X:mult,C:white}X#1#{} Mult when scored.",
- "{C:green}#2# in #3#{} chance to re-trigger",
- "{C:inactive}(#4# + #5#)"
- }
- }
-
- local heart_paladin = SMODS.Joker:new("Heart Paladin", "heart_paladin", {extra = {
- odds = 3, Xmult = 1.5, joker1 = "j_lusty_joker", joker2 = "j_bloodstone"
- }}, { x = 0, y = 0 }, heart_paladin_def, rarity.key, 12, true, false, true, true)
- SMODS.Sprite:new("j_heart_paladin", mod_obj.path, "j_heart_paladin.png", 71, 95, "asset_atli"):register();
- heart_paladin:register()
-
- function SMODS.Jokers.j_heart_paladin.loc_def(card)
- return {card.ability.extra.Xmult, ''..(G.GAME and G.GAME.probabilities.normal or 1), card.ability.extra.odds,
- localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
- localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}}
- end
-
- function SMODS.Jokers.j_heart_paladin.calculate(card, context)
- if context.individual and context.cardarea == G.play and
- context.other_card:is_suit('Hearts') then
- return {
- x_mult = card.ability.extra.Xmult,
- card = card
- }
- end
-
- if context.repetition and context.cardarea == G.play and
- context.other_card:is_suit('Hearts') then
- if pseudorandom('heart_paladin') < G.GAME.probabilities.normal/card.ability.extra.odds then
- return {
- message = localize('k_again_ex'),
- repetitions = 1,
- card = card
- }
- end
- end
- end
-
-
-
- local spade_archer_def = {
- name = "Spade Archer",
- text = {
- "Played cards with {C:spades}Spade{} suit give",
- "{C:chips}+#1#{} Chips when scored. Gains {C:chips}+#2#{} ",
- "chips when 5 {C:spades}Spades{} are played",
- "{C:inactive}(#3# + #4#)"
- }
- }
-
- local spade_archer = SMODS.Joker:new("Spade Archer", "spade_archer", {extra = {
- chips = 50, chip_mod = 10, joker1 = "j_wrathful_joker", joker2 = "j_arrowhead"
- }}, { x = 0, y = 0 }, spade_archer_def, rarity.key, 12, true, false, true, true)
- SMODS.Sprite:new("j_spade_archer", mod_obj.path, "j_spade_archer.png", 71, 95, "asset_atli"):register();
- spade_archer:register()
-
- function SMODS.Jokers.j_spade_archer.loc_def(card)
- return {card.ability.extra.chips, card.ability.extra.chip_mod,
- localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
- localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}}
- end
-
- function SMODS.Jokers.j_spade_archer.calculate(card, context)
- if context.individual and context.cardarea == G.play and
- context.other_card:is_suit('Spades') then
- return {
- chips = card.ability.extra.chips,
- card = card
- }
- end
-
- if context.before and context.cardarea == G.jokers then
- local spades = 0
- for k, v in ipairs(context.scoring_hand) do
- if v:is_suit('Spades') then
- spades = spades + 1
- end
- end
- if spades == 5 then
- card.ability.extra.chips = card.ability.extra.chips + card.ability.extra.chip_mod
- return {
- message = localize('k_upgrade_ex'),
- colour = G.C.CHIPS,
- card = card
- }
- end
- end
- end
-
-
-
- local club_wizard_def = {
- name = "Club Wizard",
- text = {
- "Played cards with {C:clubs}Club{} suit",
- "give {C:mult}+#1#{} Mult when scored",
- "{C:inactive}(#2# + #3#)"
- }
- }
-
- local club_wizard = SMODS.Joker:new("Club Wizard", "club_wizard", {extra = {
- mult = 24, joker1 = "j_gluttenous_joker", joker2 = "j_onyx_agate"
- }}, { x = 0, y = 0 }, club_wizard_def, rarity.key, 12, true, false, true, true)
- SMODS.Sprite:new("j_club_wizard", mod_obj.path, "j_club_wizard.png", 71, 95, "asset_atli"):register();
- club_wizard:register()
-
- function SMODS.Jokers.j_club_wizard.loc_def(card)
- return {card.ability.extra.mult,
- localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
- localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}}
- end
-
- function SMODS.Jokers.j_club_wizard.calculate(card, context)
- if context.individual and context.cardarea == G.play and
- context.other_card:is_suit('Clubs') then
- return {
- mult = card.ability.extra.mult,
- card = card
- }
- end
- end
-
-
-
- local big_bang_def = {
- name = "Big Bang",
- text = {
- "{X:mult,C:white} X#1# {} Mult per the number",
- "of times {C:attention}poker hand{} has been played",
- "plus the level of the {C:attention}poker hand{}.",
- "{C:inactive}(#2# + #3#)"
-
- }
- }
-
- local big_bang = SMODS.Joker:new("Big Bang", "big_bang", {extra = {
- Xmult = 0.1, joker1 = "j_supernova", joker2 = "j_constellation"
- }}, { x = 0, y = 0 }, big_bang_def, rarity.key, 11, true, false, true, true)
- SMODS.Sprite:new("j_big_bang", mod_obj.path, "j_big_bang.png", 71, 95, "asset_atli"):register();
- big_bang:register()
-
- function SMODS.Jokers.j_big_bang.loc_def(card)
- return {card.ability.extra.Xmult,
- localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
- localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}}
- end
-
- function SMODS.Jokers.j_big_bang.calculate(card, context)
- if context.cardarea == G.jokers and not context.after and not context.before and context.scoring_name then
- local mult_val = 1 + card.ability.extra.Xmult * (G.GAME.hands[context.scoring_name].level + G.GAME.hands[context.scoring_name].played)
- return {
- message = localize{type='variable',key='a_xmult',vars={mult_val}},
- Xmult_mod = mult_val
- }
- end
- end
-
-
-
- local dynamic_duo_def = {
- name = "Dynamic Duo",
- text = {
- "Played {C:attention}number{} cards give {C:mult}+#1#{} Mult ",
- "and {C:chips}+#2#{} Chips when scored.",
- "{C:inactive}(#3# + #4#)"
-
- }
- }
-
- local dynamic_duo = SMODS.Joker:new("Dynamic Duo", "dynamic_duo", {extra = {
- mult = 4, chips = 30, joker1 = "j_even_steven", joker2 = "j_odd_todd"
- }}, { x = 0, y = 0 }, dynamic_duo_def, rarity.key, 8, true, false, true, true)
- SMODS.Sprite:new("j_dynamic_duo", mod_obj.path, "j_dynamic_duo.png", 71, 95, "asset_atli"):register();
- dynamic_duo:register()
-
- function SMODS.Jokers.j_dynamic_duo.loc_def(card)
- return {card.ability.extra.mult, card.ability.extra.chips,
- localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
- localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}}
- end
-
- function SMODS.Jokers.j_dynamic_duo.calculate(card, context)
- if context.individual and context.cardarea == G.play and
- not context.other_card:is_face() then
- return {
- mult = card.ability.extra.mult,
- chips = card.ability.extra.chips,
- card = card
- }
- end
- end
-
- local collectible_chaos_card_def = {
- name = "Collectible Chaos Card",
- text = {
- "{C:mult}+#1#{} Mult per {C:attention}reroll{} in the shop.",
- "{C:attention}#2#{} free {C:green}Reroll{} per shop",
- "{C:inactive}(Currently {C:mult}+#3#{C:inactive} Mult)",
- "{C:inactive}(#4# + #5#)"
-
- }
- }
-
- local collectible_chaos_card = SMODS.Joker:new("Collectible Chaos Card", "collectible_chaos_card", {extra = {
- per_reroll = 2, free = 1, joker1 = "j_chaos", joker2 = "j_flash"
- }, mult = 0}, { x = 0, y = 0 }, collectible_chaos_card_def, rarity.key, 9, true, false, true, true)
- SMODS.Sprite:new("j_collectible_chaos_card", mod_obj.path, "j_collectible_chaos_card.png", 71, 95, "asset_atli"):register();
- collectible_chaos_card:register()
-
- function SMODS.Jokers.j_collectible_chaos_card.loc_def(card)
- return {card.ability.extra.per_reroll, card.ability.extra.free, card.ability.mult,
- localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
- localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}}
- end
-
- function SMODS.Jokers.j_collectible_chaos_card.calculate(card, context)
- if context.reroll_shop and not context.blueprint then
- card.ability.mult = card.ability.mult + card.ability.extra.per_reroll
- G.E_MANAGER:add_event(Event({
- func = (function()
- card_eval_status_text(card, 'extra', nil, nil, nil, {message = localize{type = 'variable', key = 'a_mult', vars = {card.ability.mult}}, colour = G.C.MULT})
- return true
- end)}))
- end
-
- if context.cardarea == G.jokers and card.ability.mult > 0 and not context.after and not context.before then
- return {
- message = localize{type='variable',key='a_mult',vars={card.ability.mult}},
- mult_mod = card.ability.mult
- }
- end
- end
-
-
-
- local flip_flop_hand_def = {
- name = "Flip-Flop",
- text = {
- "{C:attention}+#1#{} hand size. {C:red}+#2#{} Mult",
- "{C:attention}Flips{} after each blind",
- "{C:inactive}(#3# + #4#)"
-
- }
- }
-
- local flip_flop_discard_def = {
- name = "Flip-Flop",
- text = {
- "{C:red}+#1#{} discard. {C:chips}+#2#{} Chips",
- "{C:attention}Flips{} after each blind",
- "{C:inactive}(#3# + #4#)"
-
- }
- }
-
- local flip_flop = SMODS.Joker:new("Flip-Flop", "flip_flop", {extra = {
- hands = 2, discards = 2, mult = 8, chips = 50, side = "mult", joker1 = "j_juggler", joker2 = "j_drunkard"
- }}, { x = 0, y = 0 }, flip_flop_hand_def, rarity.key, 9, true, false, false, true)
- SMODS.Sprite:new("j_flip_flop", mod_obj.path, "j_flip_flop.png", 71, 95, "asset_atli"):register();
- SMODS.Sprite:new("j_flop_flip", mod_obj.path, "j_flop_flip.png", 71, 95, "asset_atli"):register();
- flip_flop:register()
-
- G.localization.descriptions["Joker"]["j_flip_flop_chips"] = flip_flop_discard_def
- G.localization.descriptions["Joker"]["j_flip_flop_mult"] = flip_flop_hand_def
-
-
- function SMODS.Jokers.j_flip_flop.loc_def(card)
- if card.ability.extra.side == "mult" then
- return {card.ability.extra.hands, card.ability.extra.mult,
- localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
- localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}}
- else
- return {card.ability.extra.discards, card.ability.extra.chips,
- localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
- localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}}
- end
+SMODS.current_mod.reset_game_globals = function (init)
+ if init then
+ G.jokers.config.highlighted_limit = math.max(G.jokers.config.highlighted_limit, 1e300)
+ G.GAME.fujo_fusion_discount = {}
+ G.GAME.fujo_fusion_discountpercent = {}
end
-
- function SMODS.Jokers.j_flip_flop.calculate(card, context)
- if context.end_of_round and not context.blueprint and not context.repetition and not context.individual then
- if card.ability.extra.side == "mult" then
- G.E_MANAGER:add_event(Event({trigger = 'after', delay = 0.3, blockable = false,
- func = function()
- card.ability.extra.side = "chips"
- G.localization.descriptions["Joker"]["j_flip_flop"] = G.localization.descriptions["Joker"]["j_flip_flop_chips"]
- card:juice_up(1, 1)
- card.config.center.atlas = "j_flop_flip"
- card:set_sprites(card.config.center)
-
- return true; end}))
-
- G.hand:change_size(-card.ability.extra.hands)
- G.GAME.round_resets.discards = G.GAME.round_resets.discards + card.ability.extra.discards
- ease_discard(card.ability.extra.discards)
-
- return {
- message = localize('k_flipped_ex'),
- colour = G.C.CHIPS
- }
- else
- G.E_MANAGER:add_event(Event({trigger = 'after', delay = 0.3, blockable = false,
- func = function()
- card.ability.extra.side = "mult"
- G.localization.descriptions["Joker"]["j_flip_flop"] = G.localization.descriptions["Joker"]["j_flip_flop_mult"]
- card:juice_up(1, 1)
- card.config.center.atlas = "j_flip_flop"
- card:set_sprites(card.config.center)
-
- return true; end}))
-
- G.hand:change_size(card.ability.extra.hands)
- G.GAME.round_resets.discards = G.GAME.round_resets.discards - card.ability.extra.discards
- ease_discard(-card.ability.extra.discards)
-
- return {
- message = localize('k_flipped_ex'),
- colour = G.C.MULT
- }
- end
-
- end
-
- if context.cardarea == G.jokers and not context.after and not context.before then
- if card.ability.extra.side == "mult" then
- return {
- message = localize{type='variable',key='a_mult',vars={card.ability.extra.mult}},
- mult_mod = card.ability.extra.mult,
- colour = G.C.MULT
- }
- else
- return {
- message = localize{type='variable',key='a_chips',vars={card.ability.extra.chips}},
- chip_mod = card.ability.extra.chips,
- colour = G.C.CHIPS
- }
- end
-
- end
- end
-
-
-
- local royal_decree_def = {
- name = "Royal Decree",
- text = {
- "Played {C:attention}face{} cards give {C:money}$#1#{} when scored.",
- "Each {C:attention}face{} card held in hand",
- "at end of round gives {C:money}$#1#{}",
- "{C:inactive}(#2# + #3#)"
-
- }
- }
-
- local royal_decree = SMODS.Joker:new("Royal Decree", "royal_decree", {extra = {
- dollars = 2, joker1 = "j_business", joker2 = "j_reserved_parking"
- }, mult = 0}, { x = 0, y = 0 }, royal_decree_def, rarity.key, 10, true, false, true, true)
- SMODS.Sprite:new("j_royal_decree", mod_obj.path, "j_royal_decree.png", 71, 95, "asset_atli"):register();
- royal_decree:register()
-
- function SMODS.Jokers.j_royal_decree.loc_def(card)
- return {card.ability.extra.dollars,
- localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
- localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}}
- end
-
- function SMODS.Jokers.j_royal_decree.calculate(card, context)
- if context.end_of_round and context.individual then
- if context.cardarea == G.hand and context.other_card:is_face() then
- return {
- h_dollars = 2,
- card = card
- }
- end
- end
-
- if context.cardarea == G.play and context.individual and context.other_card:is_face() then
- G.GAME.dollar_buffer = (G.GAME.dollar_buffer or 0) + 2
- G.E_MANAGER:add_event(Event({func = (function() G.GAME.dollar_buffer = 0; return true end)}))
- return {
- dollars = 2,
- card = card
- }
-
- end
- end
-
-
-
- local dementia_joker_def = {
- name = "Dementia Joker",
- text = {
- "{C:mult}+#1#{} Mult for each {C:attention}Joker{} card.",
- "{C:green}#2# in #3#{} chance to {C:attention}clone{} if ",
- "not {C:dark_edition}Negative{} after you beat a blind",
- "{C:inactive}(Currently {C:mult}+#4#{C:inactive} Mult)",
- "{C:inactive}(#5# + #6#)"
-
- }
- }
-
- local dementia_joker = SMODS.Joker:new("Dementia Joker", "dementia_joker", {extra = {
- mult = 3, odds = 3, joker1 = "j_abstract", joker2 = "j_riff_raff"
- }, mult = 0}, { x = 0, y = 0 }, dementia_joker_def, rarity.key, 8, true, false, true, true)
- SMODS.Sprite:new("j_dementia_joker", mod_obj.path, "j_dementia_joker.png", 71, 95, "asset_atli"):register();
- dementia_joker:register()
-
- function SMODS.Jokers.j_dementia_joker.loc_def(card)
- return {card.ability.extra.mult, ''..(G.GAME and G.GAME.probabilities.normal or 1), card.ability.extra.odds,
- (G.jokers and G.jokers.cards and #G.jokers.cards or 0)*card.ability.extra.mult,
- localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
- localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}}
- end
-
- function SMODS.Jokers.j_dementia_joker.calculate(card, context)
- if context.end_of_round and not context.blueprint and not context.repetition and not context.individual then
- if pseudorandom('dementia_joker') < G.GAME.probabilities.normal/card.ability.extra.odds
- and not (card.edition and card.edition.negative) then
- local card = copy_card(card, nil, nil, nil, card.edition and card.edition.negative)
- card:set_edition({negative = true}, true)
- card:add_to_deck()
- G.jokers:emplace(card)
- return {
- message = localize('k_copied_ex'),
- colour = G.C.DARK_EDITION
- }
- end
- end
-
- if context.cardarea == G.jokers and not context.after and not context.before then
- local x = 0
- for i = 1, #G.jokers.cards do
- if G.jokers.cards[i].ability.set == 'Joker' then x = x + 1 end
- end
- return {
- message = localize{type='variable',key='a_mult',vars={x*card.ability.extra.mult}},
- mult_mod = x*card.ability.extra.mult
- }
- end
- end
-
-
-
- local golden_egg_def = {
- name = "Golden Egg",
- text = {
- "Gains {C:money}$#1#{} of {C:attention}sell value{}",
- " at end of round.",
- " Earn {C:money}$#1#{} at end of round",
- "{C:inactive}(#2# + #3#)"
-
- }
- }
-
- local golden_egg = SMODS.Joker:new("Golden Egg", "golden_egg", {extra = {
- dollars = 4, joker1 = "j_egg", joker2 = "j_golden"
- }, mult = 0}, { x = 0, y = 0 }, golden_egg_def, rarity.key, 10, true, false, false, true)
- SMODS.Sprite:new("j_golden_egg", mod_obj.path, "j_golden_egg.png", 71, 95, "asset_atli"):register();
- golden_egg:register()
-
- function SMODS.Jokers.j_golden_egg.loc_def(card)
- return {card.ability.extra.dollars,
- localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
- localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}}
- end
-
- function SMODS.Jokers.j_golden_egg.calculate(card, context)
- if context.end_of_round and not context.blueprint and not context.repetition and not context.individual then
- card.ability.extra_value = card.ability.extra_value + card.ability.extra.dollars
- card:set_cost()
- return {
- message = localize('k_val_up'),
- colour = G.C.MONEY
- }
- end
- end
-
-
-
- local flag_bearer_def = {
- name = "Flag Bearer",
- text = {
- "{C:mult}+#1#{} Mult per hand played, {C:mult}-#2#{} Mult",
- "per discard. Mult is multiplied by",
- " remaining {C:attention}discards{}",
- "{C:inactive}(Currently {C:mult}+#3#{C:inactive} Mult)",
- "{C:inactive}(#4# + #5#)"
-
- }
- }
-
- local flag_bearer = SMODS.Joker:new("Flag Bearer", "flag_bearer", {extra = {
- hand_add = 1, discard_sub = 1, joker1 = "j_banner", joker2 = "j_green_joker"
- }, mult = 0}, { x = 0, y = 0 }, flag_bearer_def, rarity.key, 9, true, false, false, true)
- SMODS.Sprite:new("j_flag_bearer", mod_obj.path, "j_flag_bearer.png", 71, 95, "asset_atli"):register();
- flag_bearer:register()
-
- function SMODS.Jokers.j_flag_bearer.loc_def(card)
- return {card.ability.extra.hand_add, card.ability.extra.discard_sub, card.ability.mult * (G.GAME.current_round.discards_left or 0),
- localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
- localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}}
- end
-
- function SMODS.Jokers.j_flag_bearer.calculate(card, context)
- if context.discard and not context.blueprint and context.other_card == context.full_hand[#context.full_hand] then
- local prev_mult = card.ability.mult
- card.ability.mult = math.max(0, card.ability.mult - card.ability.extra.discard_sub)
- if card.ability.mult ~= prev_mult then
- return {
- message = localize{type='variable',key='a_mult_minus',vars={card.ability.extra.discard_sub}},
- colour = G.C.RED,
- card = card
- }
- end
- end
-
- if context.cardarea == G.jokers and context.before then
- if not context.blueprint then
- card.ability.mult = card.ability.mult + card.ability.extra.hand_add
- return {
- card = card,
- message = localize{type='variable',key='a_mult',vars={card.ability.extra.hand_add}}
- }
- end
- end
-
- if context.cardarea == G.jokers and not context.after and not context.before then
- local mult = card.ability.mult * G.GAME.current_round.discards_left
- return {
- message = localize{type='variable',key='a_mult',vars={mult}},
- mult_mod = mult
- }
- end
- end
-
-
- local uncanny_face_def = {
- name = "Uncanny Face",
- text = {
- "Played {C:attention}face{} cards give {C:chips}+#1#{} Chips and",
- "{C:mult}+#2#{} Mult for every {C:attention}face{} card",
- " in the scoring hand",
- "{C:inactive}(#3# + #4#)"
-
- }
- }
-
- local uncanny_face = SMODS.Joker:new("Uncanny Face", "uncanny_face", {extra = {
- chips = 15, mult = 2, joker1 = "j_scary_face", joker2 = "j_smiley"
- }}, { x = 0, y = 0 }, uncanny_face_def, rarity.key, 8, true, false, true, true)
- SMODS.Sprite:new("j_uncanny_face", mod_obj.path, "j_uncanny_face.png", 71, 95, "asset_atli"):register();
- uncanny_face:register()
-
- function SMODS.Jokers.j_uncanny_face.loc_def(card)
- return {card.ability.extra.chips, card.ability.extra.mult,
- localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
- localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}}
- end
-
- function SMODS.Jokers.j_uncanny_face.calculate(card, context)
- if context.individual and context.cardarea == G.play and
- context.other_card:is_face() then
- local faces = 0
- for k, v in ipairs(context.scoring_hand) do
- if v:is_face() then
- faces = faces + 1
- end
- end
- return {
- mult = card.ability.extra.mult * faces,
- chips = card.ability.extra.chips * faces,
- card = card
- }
- end
- end
-
-
- local commercial_driver_def = {
- name = "Commercial Driver",
- text = {
- "{X:mult,C:white} X#1# {} Mult per consecutive hand",
- "played with a scoring {C:attention}enhanced{} card",
- "{C:inactive}(Currently {X:mult,C:white}X#2#{C:inactive} Mult)",
- "{C:inactive}(#3# + #4#)"
- }
- }
-
- local commercial_driver = SMODS.Joker:new("Commercial Driver", "commercial_driver", {extra = {
- bonus = 0.25, total = 1, joker1 = "j_ride_the_bus", joker2 = "j_drivers_license"
- }}, { x = 0, y = 0 }, commercial_driver_def, rarity.key, 8, true, false, true, true)
- SMODS.Sprite:new("j_commercial_driver", mod_obj.path, "j_commercial_driver.png", 71, 95, "asset_atli"):register();
- commercial_driver:register()
-
- function SMODS.Jokers.j_commercial_driver.loc_def(card)
- return {card.ability.extra.bonus, card.ability.extra.total,
- localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
- localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}}
- end
-
- function SMODS.Jokers.j_commercial_driver.calculate(card, context)
- if context.before and context.cardarea == G.jokers then
- local enhanced = false
- for i = 1, #context.scoring_hand do
- if context.scoring_hand[i].config.center ~= G.P_CENTERS.c_base then enhanced = true end
- end
- if not enhanced then
- local last_mult = card.ability.extra.total
- card.ability.extra.total = 1
- if last_mult > 0 then
- return {
- card = card,
- message = localize('k_reset')
- }
- end
- else
- card.ability.extra.total = card.ability.extra.total + card.ability.extra.bonus
- end
- end
-
- if context.cardarea == G.jokers and not context.before and not context.after then
- return {
- message = localize{type='variable',key='a_xmult',vars={card.ability.extra.total}},
- Xmult_mod = card.ability.extra.total
- }
- end
- end
-
-
- local camping_trip_def = {
- name = "Camping Trip",
- text = {
- "Played {C:attention}cards{} permanently gains",
- "{C:chips}+#1#{} Chips when scored",
- "({C:chips}+#2#{} on the final hand)",
- "Your final hand triggers twice",
- "{C:inactive}(#3# + #4#)"
- }
- }
-
- local camping_trip = SMODS.Joker:new("Camping Trip", "camping_trip", {extra = {
- bonus_base = 5, bonus_final = 10, joker1 = "j_hiker", joker2 = "j_dusk"
- }}, { x = 0, y = 0 }, camping_trip_def, rarity.key, 10, true, false, true, true)
- SMODS.Sprite:new("j_camping_trip", mod_obj.path, "j_camping_trip.png", 71, 95, "asset_atli"):register();
- camping_trip:register()
-
- function SMODS.Jokers.j_camping_trip.loc_def(card)
- return {card.ability.extra.bonus_base, card.ability.extra.bonus_final,
- localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
- localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}}
- end
-
- function SMODS.Jokers.j_camping_trip.calculate(card, context)
- if context.individual and context.cardarea == G.play then
- context.other_card.ability.perma_bonus = context.other_card.ability.perma_bonus or 0
- if G.GAME.current_round.hands_left == 0 then
- context.other_card.ability.perma_bonus = context.other_card.ability.perma_bonus + card.ability.extra.bonus_final
- else
- context.other_card.ability.perma_bonus = context.other_card.ability.perma_bonus + card.ability.extra.bonus_base
- end
-
- return {
- extra = {message = localize('k_upgrade_ex'), colour = G.C.CHIPS},
- colour = G.C.CHIPS,
- card = card
- }
- end
-
- if context.repetition and context.cardarea == G.play and G.GAME.current_round.hands_left == 0 then
- return {
- message = localize('k_again_ex'),
- repetitions = 1,
- card = card
- }
- end
- end
-
-
- ----- SixSuits collab !!!!! ------------------
- ----------------------------------------------
-
- if SMODS.INIT.SixSuit then
-
- local star_oracle_def = {
- name = "Star Oracle",
- text = {
- "{C:attention}+2{} consumable slots.",
- "{C:green}#1# in #2#{} chance for played cards",
- " with {C:stars}Star{} suit to create a",
- "random {C:spectral}Spectral{} card when scored",
- "{C:inactive}(#3# + #4#)"
-
- }
- }
-
- local star_oracle = SMODS.Joker:new("Star Oracle", "star_oracle", {extra = {
- odds = 10, slots = 2, joker1 = "j_envious_joker", joker2 = "j_star_ruby"
- }}, { x = 0, y = 0 }, star_oracle_def, rarity.key, 12, true, false, true, true)
- SMODS.Sprite:new("j_star_oracle", mod_obj.path, "j_star_oracle.png", 71, 95, "asset_atli"):register();
- star_oracle:register()
-
- function SMODS.Jokers.j_star_oracle.loc_def(card)
- return { '' .. (G.GAME and G.GAME.probabilities.normal or 1), card.ability.extra.odds,
- localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
- localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}}
- end
-
- function SMODS.Jokers.j_star_oracle.calculate(card, context)
- if context.individual and
- context.cardarea == G.play and
- context.other_card:is_suit('Stars') and
- #G.consumeables.cards + G.GAME.consumeable_buffer < G.consumeables.config.card_limit and
- pseudorandom('starruby') < G.GAME.probabilities.normal / card.ability.extra.odds then
- G.GAME.consumeable_buffer = G.GAME.consumeable_buffer + 1
- G.E_MANAGER:add_event(Event({
- trigger = 'before',
- delay = 0.0,
- func = (function()
- local _card = create_card('Spectral', G.consumeables, nil, nil, nil, nil, nil, 'ruby')
- _card:add_to_deck()
- G.consumeables:emplace(_card)
- G.GAME.consumeable_buffer = 0
- return true
- end)
- }))
- card_eval_status_text(context.blueprint_card or card, 'extra', nil, nil, nil,
- { message = localize('k_plus_spectral'), colour = G.C.SECONDARY_SET.Spectral })
- return {}
- end
- end
-
-
-
- local moon_marauder_def = {
- name = "Moon Marauder",
- text = {
- "{C:green}#1# in #2#{} chance for played cards with",
- "{C:moons}Moon{} suit to become {C:attention}Glass{} Cards.",
- "played {C:moons}Moon{} {C:attention}Glass{} cards never shatter",
- "{C:inactive}(#3# + #4#)"
-
- }
- }
-
- local moon_marauder = SMODS.Joker:new("Moon Marauder", "moon_marauder", {extra = {
- odds = 3, joker1 = "j_slothful_joker", joker2 = "j_rainbow_moonstone"
- }}, { x = 0, y = 0 }, moon_marauder_def, rarity.key, 12, true, false, true, true)
- SMODS.Sprite:new("j_moon_marauder", mod_obj.path, "j_moon_marauder.png", 71, 95, "asset_atli"):register();
- moon_marauder:register()
-
- function SMODS.Jokers.j_moon_marauder.loc_def(card)
- return { '' .. (G.GAME and G.GAME.probabilities.normal or 1), card.ability.extra.odds,
- localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
- localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}}
- end
-
- function SMODS.Jokers.j_moon_marauder.calculate(card, context)
- if context.before and (context.cardarea == G.jokers) then
- local moons = {}
- for _, v in ipairs(context.full_hand) do
- if v:is_suit('Moons') and not (v.ability.name == 'Glass Card') and pseudorandom('moon_marauder') < G.GAME.probabilities.normal / card.ability.extra.odds then
- moons[#moons + 1] = v
- v:set_ability(G.P_CENTERS.m_glass, nil, true)
- G.E_MANAGER:add_event(Event({
- func = function()
- v:juice_up()
- return true
- end
- }))
- end
- end
- if #moons > 0 then
- return {
- message = localize('k_glass'),
- colour = G.C.SECONDARY_SET.Enhanced,
- card = context.blueprint_card or card
- }
- end
- end
-
- if context.remove_playing_cards and not context.blueprint then
- -- G.E_MANAGER:add_event(Event({
- -- trigger = 'after',
- -- delay = 1,
- -- func = function()
- -- sendDebugMessage(tostring(#context.removed))
- -- for k, v in ipairs(context.removed) do
- -- sendDebugMessage(tostring(v.shattered))
- -- if v.shattered then
- -- local _card = Card(G.play.T.x, G.play.T.y, G.CARD_W, G.CARD_H, G.P_CARDS.empty, G.P_CENTERS.c_base, {playing_card = G.playing_card})
-
- -- _card = copy_card(v, _card, nil, G.playing_card)
- -- _card:start_materialize({G.C.SECONDARY_SET.Enhanced})
- -- G.deck:emplace(_card)
-
- -- G.E_MANAGER:add_event(Event({
- -- func = function()
- -- card_eval_status_text(context.blueprint_card or card, 'extra', nil, nil, nil,
- -- { message = localize('k_in_tact_ex'), colour = G.C.SECONDARY_SET.edition })
- -- return true
- -- end
- -- }))
- -- end
- -- end
- -- end
- -- }))
- sendDebugMessage(tostring(#context.removed))
- for k, v in ipairs(context.removed) do
- sendDebugMessage(tostring(v.shattered))
- if v.shattered then
- local _card = Card(G.play.T.x, G.play.T.y, G.CARD_W, G.CARD_H, G.P_CARDS.empty, G.P_CENTERS.c_base, {playing_card = G.playing_card})
-
- G.playing_card = (G.playing_card and G.playing_card + 1) or 1
- _card = copy_card(v, _card, nil, G.playing_card)
- _card:start_materialize({G.C.SECONDARY_SET.Enhanced})
- G.deck:emplace(_card)
- table.insert(G.playing_cards, _card)
-
- G.E_MANAGER:add_event(Event({
- func = function()
- card_eval_status_text(context.blueprint_card or card, 'extra', nil, nil, nil,
- { message = localize('k_in_tact_ex'), colour = G.C.SECONDARY_SET.edition })
- return true
- end
- }))
- end
- end
- end
- end
-
- FusionJokers.fusions:add_fusion("j_envious_joker", nil, false, "j_star_ruby", nil, false, "j_star_oracle", 12)
- FusionJokers.fusions:add_fusion("j_slothful_joker", nil, false, "j_rainbow_moonstone", nil, false, "j_moon_marauder", 12)
- end
-
- ----------------------------------------------
- ----------------------------------------------
-
-end
-
-----------------------------------------------
-------------MOD CODE END----------------------
+end
\ No newline at end of file
diff --git a/mod/assets/1x/j_club_wizard.png b/mod/assets/1x/j_club_wizard.png
index 83b6e40..58b26e0 100644
Binary files a/mod/assets/1x/j_club_wizard.png and b/mod/assets/1x/j_club_wizard.png differ
diff --git a/mod/assets/1x/j_flip_flop.png b/mod/assets/1x/j_flip_flop.png
index 2919b84..6515673 100644
Binary files a/mod/assets/1x/j_flip_flop.png and b/mod/assets/1x/j_flip_flop.png differ
diff --git a/mod/assets/1x/j_fuse_three_jimbos.png b/mod/assets/1x/j_fuse_three_jimbos.png
new file mode 100644
index 0000000..bcfa723
Binary files /dev/null and b/mod/assets/1x/j_fuse_three_jimbos.png differ
diff --git a/mod/assets/1x/j_spade_archer.png b/mod/assets/1x/j_spade_archer.png
index 39727f3..9593965 100644
Binary files a/mod/assets/1x/j_spade_archer.png and b/mod/assets/1x/j_spade_archer.png differ
diff --git a/mod/assets/2x/j_club_wizard.png b/mod/assets/2x/j_club_wizard.png
index 78ca4ea..90eb3f8 100644
Binary files a/mod/assets/2x/j_club_wizard.png and b/mod/assets/2x/j_club_wizard.png differ
diff --git a/mod/assets/2x/j_flip_flop.png b/mod/assets/2x/j_flip_flop.png
index 3933296..3d609a6 100644
Binary files a/mod/assets/2x/j_flip_flop.png and b/mod/assets/2x/j_flip_flop.png differ
diff --git a/mod/assets/2x/j_fuse_three_jimbos.png b/mod/assets/2x/j_fuse_three_jimbos.png
new file mode 100644
index 0000000..d50587a
Binary files /dev/null and b/mod/assets/2x/j_fuse_three_jimbos.png differ
diff --git a/mod/assets/2x/j_spade_archer.png b/mod/assets/2x/j_spade_archer.png
index 91dafd1..0b04a8a 100644
Binary files a/mod/assets/2x/j_spade_archer.png and b/mod/assets/2x/j_spade_archer.png differ
diff --git a/mod/config.lua b/mod/config.lua
new file mode 100644
index 0000000..baaa2df
--- /dev/null
+++ b/mod/config.lua
@@ -0,0 +1,8 @@
+local colorblind = G.SETTINGS.colourblind_option or false
+local nomotion = G.SETTINGS.reduced_motion or false
+
+return {
+ ["block_components"] = true,
+ ["cw_alt_art"] = colorblind,
+ ["no_price_flicker"] = nomotion
+}
diff --git a/mod/configui.lua b/mod/configui.lua
new file mode 100644
index 0000000..d5ed0b8
--- /dev/null
+++ b/mod/configui.lua
@@ -0,0 +1,21 @@
+SMODS.current_mod.config_tab = function()
+ return {n = G.UIT.ROOT, config = {r = 0.1, minw = 8, minh = 6, align = "tl", padding = 0.2, colour = G.C.BLACK}, nodes = {
+ {n = G.UIT.C, config = {minw=1, minh=1, align = "tl", colour = G.C.CLEAR, padding = 0.15}, nodes = {
+ create_toggle({
+ label = "Block used components from reappearing",
+ ref_table = FusionJokers.fusionconfig,
+ ref_value = 'block_components',
+ }),
+ create_toggle({
+ label = "Alt art for Club Wizard",
+ ref_table = FusionJokers.fusionconfig,
+ ref_value = 'cw_alt_art',
+ }),
+ create_toggle({
+ label = "No price flickering",
+ ref_table = FusionJokers.fusionconfig,
+ ref_value = 'no_price_flicker',
+ }),
+ }}
+ }}
+end
\ No newline at end of file
diff --git a/mod/jokers/bigbang.lua b/mod/jokers/bigbang.lua
new file mode 100644
index 0000000..3e2ff6d
--- /dev/null
+++ b/mod/jokers/bigbang.lua
@@ -0,0 +1,67 @@
+SMODS.Atlas {
+ key = 'big_bang',
+ path = "j_big_bang.png",
+ px = 71,
+ py = 95
+}
+
+SMODS.Joker {
+ key = "big_bang",
+ name = "Big Bang",
+ atlas = 'big_bang',
+ pos = {
+ x = 0,
+ y = 0
+ },
+ rarity = "fuse_fusion",
+ cost = 12,
+ unlocked = true,
+ discovered = false,
+ eternal_compat = true,
+ perishable_compat = true,
+ blueprint_compat = true,
+ config = {
+ extra = {
+ Xmult = 0.1,
+ joker1 = "j_supernova",
+ joker2 = "j_constellation"
+ }
+ },
+ loc_vars = function(self, info_queue, card)
+ return {
+ vars = {
+ card.ability.extra.Xmult,
+ localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
+ localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}
+ }
+ }
+ end,
+ calculate = function(self, card, context)
+ if context.cardarea == G.jokers and context.joker_main and context.scoring_name then
+ local mult_val = 1 + card.ability.extra.Xmult * (G.GAME.hands[context.scoring_name].level + G.GAME.hands[context.scoring_name].played)
+ return {
+ message = localize{type='variable',key='a_xmult',vars={mult_val}},
+ Xmult_mod = mult_val
+ }
+ end
+ end,
+ joker_display_def = function(JokerDisplay)
+ return {
+ text = {
+ {
+ border_nodes = {
+ { text = "X" },
+ { ref_table = "card.joker_display_values", ref_value = "Xmult", retrigger_type = "exp" }
+ }
+ }
+ },
+ calc_function = function(card)
+ local text, _, _ = JokerDisplay.evaluate_hand()
+ card.joker_display_values.Xmult = 1 + card.ability.extra.Xmult * ((text ~= 'Unknown' and G.GAME and G.GAME.hands[text] and G.GAME.hands[text].level + G.GAME.hands[text].played + (next(G.play.cards) and 0 or 1)) or
+ 0)
+ end
+ }
+ end
+}
+
+-- See localization/en-us.lua to create joker text
\ No newline at end of file
diff --git a/mod/jokers/campingtrip.lua b/mod/jokers/campingtrip.lua
new file mode 100644
index 0000000..22c28df
--- /dev/null
+++ b/mod/jokers/campingtrip.lua
@@ -0,0 +1,84 @@
+SMODS.Atlas {
+ key = 'camping_trip',
+ path = "j_camping_trip.png",
+ px = 71,
+ py = 95
+}
+
+SMODS.Joker {
+ key = "camping_trip",
+ name = "Camping Trip",
+ atlas = 'camping_trip',
+ pos = {
+ x = 0,
+ y = 0
+ },
+ rarity = "fuse_fusion",
+ cost = 12,
+ unlocked = true,
+ discovered = false,
+ eternal_compat = true,
+ perishable_compat = true,
+ blueprint_compat = true,
+ config = {
+ extra = {
+ bonus_base = 5,
+ bonus_final = 10,
+ joker1 = "j_hiker",
+ joker2 = "j_dusk"
+ }
+ },
+ loc_vars = function(self, info_queue, card)
+ return {
+ vars = {
+ card.ability.extra.bonus_base,
+ card.ability.extra.bonus_final,
+ localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
+ localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}
+ }
+ }
+ end,
+ calculate = function(self, card, context)
+ if context.individual and context.cardarea == G.play then
+ local buff = card.ability.extra.bonus_base
+ if G.GAME.current_round.hands_left == 0 then
+ buff = card.ability.extra.bonus_final
+ end
+ context.other_card.ability.perma_bonus = (context.other_card.ability.perma_bonus or 0) + buff
+
+ return {
+ extra = {message = localize('k_upgrade_ex'), colour = G.C.CHIPS},
+ colour = G.C.CHIPS,
+ card = card
+ }
+ end
+
+ if context.repetition and context.cardarea == G.play and G.GAME.current_round.hands_left == 0 then
+ return {
+ message = localize('k_again_ex'),
+ repetitions = 1,
+ card = card
+ }
+ end
+ end,
+ joker_display_def = function(JokerDisplay)
+ return {
+ reminder_text = {
+ { text = "(" },
+ { ref_table = "card.joker_display_values", ref_value = "active" },
+ { text = ")" },
+ },
+ calc_function = function(card)
+ card.joker_display_values.active = G.GAME and G.GAME.current_round.hands_left <= 1 and
+ localize("jdis_active") or localize("jdis_inactive")
+ end,
+ retrigger_function = function(playing_card, scoring_hand, held_in_hand, joker_card)
+ if held_in_hand then return 0 end
+ return G.GAME and G.GAME.current_round.hands_left <= 1 and
+ 1 * JokerDisplay.calculate_joker_triggers(joker_card) or 0
+ end
+ }
+ end
+}
+
+-- See localization/en-us.lua to create joker text
diff --git a/mod/jokers/clubwizard.lua b/mod/jokers/clubwizard.lua
new file mode 100644
index 0000000..ede034c
--- /dev/null
+++ b/mod/jokers/clubwizard.lua
@@ -0,0 +1,89 @@
+SMODS.Atlas {
+ key = 'club_wizard',
+ path = "j_club_wizard.png",
+ px = 71,
+ py = 95
+}
+
+SMODS.Joker {
+ key = "club_wizard",
+ name = "Club Wizard",
+ atlas = 'club_wizard',
+ pos = {
+ x = 0,
+ y = 0
+ },
+ rarity = "fuse_fusion",
+ cost = 12,
+ unlocked = true,
+ discovered = false,
+ eternal_compat = true,
+ perishable_compat = true,
+ blueprint_compat = true,
+ config = {
+ extra = {
+ mult = 24,
+ joker1 = "j_gluttenous_joker",
+ joker2 = "j_onyx_agate",
+ art = "standard"
+ }
+ },
+ loc_vars = function(self, info_queue, card)
+ return {
+ vars = {
+ card.ability.extra.mult,
+ localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
+ localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}
+ }
+ }
+ end,
+ calculate = function(self, card, context)
+ if context.individual and context.cardarea == G.play and
+ context.other_card:is_suit('Clubs') then
+ return {
+ mult = card.ability.extra.mult,
+ card = card
+ }
+ end
+ end,
+ joker_display_def = function(JokerDisplay)
+ return {
+ text = {
+ { text = "+" },
+ { ref_table = "card.joker_display_values", ref_value = "mult", retrigger_type = "mult" },
+ },
+ text_config = { colour = G.C.MULT },
+ reminder_text = {
+ { text = "(" },
+ { ref_table = "card.joker_display_values", ref_value = "localized_text", colour = lighten(G.C.SUITS["Clubs"], 0.35) },
+ { text = ")" }
+ },
+ calc_function = function(card)
+ local mult = 0
+ local text, _, scoring_hand = JokerDisplay.evaluate_hand()
+ if text ~= 'Unknown' then
+ for _, scoring_card in pairs(scoring_hand) do
+ if scoring_card:is_suit("Clubs") then
+ mult = mult +
+ card.ability.extra.mult * JokerDisplay.calculate_card_triggers(scoring_card, scoring_hand)
+ end
+ end
+ end
+ card.joker_display_values.mult = mult
+ card.joker_display_values.localized_text = localize("Clubs", 'suits_plural')
+ end
+ }
+ end,
+ update = function(self, card, dt)
+ if not self.discovered and not card.bypass_discovery_center then return end
+ if FusionJokers.fusionconfig.cw_alt_art and card.ability.extra.art ~= "alt" then
+ card.children.center:set_sprite_pos({ x = 1, y = 0})
+ card.ability.extra.art = "alt"
+ elseif not FusionJokers.fusionconfig.cw_alt_art and card.ability.extra.art ~= "standard" then
+ card.children.center:set_sprite_pos({ x = 0, y = 0})
+ card.ability.extra.art = "standard"
+ end
+ end
+}
+
+-- See localization/en-us.lua to create joker text
\ No newline at end of file
diff --git a/mod/jokers/collectiblechaos.lua b/mod/jokers/collectiblechaos.lua
new file mode 100644
index 0000000..d07ff7d
--- /dev/null
+++ b/mod/jokers/collectiblechaos.lua
@@ -0,0 +1,97 @@
+SMODS.Atlas {
+ key = 'collectible_chaos_card',
+ path = "j_collectible_chaos_card.png",
+ px = 71,
+ py = 95
+}
+
+SMODS.Joker {
+ key = "collectible_chaos_card",
+ name = "Collectible Chaos Card",
+ atlas = 'collectible_chaos_card',
+ pos = {
+ x = 0,
+ y = 0
+ },
+ rarity = "fuse_fusion",
+ cost = 12,
+ unlocked = true,
+ discovered = false,
+ eternal_compat = true,
+ perishable_compat = true,
+ blueprint_compat = true,
+ config = {
+ extra = {
+ per_reroll = 2,
+ free = 1,
+ mult = 0,
+ joker1 = "j_chaos",
+ joker2 = "j_flash"
+ }
+ },
+ loc_vars = function(self, info_queue, card)
+ return {
+ vars = {
+ card.ability.extra.per_reroll,
+ card.ability.extra.free,
+ card.ability.extra.mult,
+ localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
+ localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}
+ }
+ }
+ end,
+ add_to_deck = function(self, card, from_debuff)
+ if not from_debuff then -- no gameplan shenanigans for bunco enjoyers :p
+ G.GAME.current_round.free_rerolls = G.GAME.current_round.free_rerolls + card.ability.extra.free
+ calculate_reroll_cost(true)
+ end
+ end,
+ remove_from_deck = function(self, card, from_debuff)
+ G.GAME.current_round.free_rerolls = math.max(G.GAME.current_round.free_rerolls - card.ability.extra.free, 0)
+ calculate_reroll_cost(true)
+ end,
+ set_ability = function(self, card, initial, delay_sprites)
+ G.E_MANAGER:add_event(Event({trigger = 'after',delay = 0.3, blocking = false,
+ func = function()
+ if card.ability.mult and (card.ability.extra.mult == 0) then
+ card.ability.extra.mult = card.ability.mult or 0
+ card.ability.mult = nil
+ end
+ return true
+ end}))
+ end,
+ calculate = function(self, card, context)
+ if context.starting_shop and not context.blueprint then
+ G.GAME.current_round.free_rerolls = G.GAME.current_round.free_rerolls or 0
+ G.GAME.current_round.free_rerolls = G.GAME.current_round.free_rerolls + card.ability.extra.free
+ calculate_reroll_cost(true)
+ end
+
+ if context.reroll_shop and not context.blueprint then
+ card.ability.extra.mult = card.ability.extra.mult + card.ability.extra.per_reroll
+ G.E_MANAGER:add_event(Event({
+ func = (function()
+ card_eval_status_text(card, 'extra', nil, nil, nil, {message = localize{type = 'variable', key = 'a_mult', vars = {card.ability.extra.mult}}, colour = G.C.MULT})
+ return true
+ end)}))
+ end
+
+ if context.cardarea == G.jokers and card.ability.extra.mult > 0 and context.joker_main then
+ return {
+ message = localize{type='variable',key='a_mult',vars={card.ability.extra.mult}},
+ mult_mod = card.ability.extra.mult
+ }
+ end
+ end,
+ joker_display_def = function(JokerDisplay)
+ return {
+ text = {
+ { text = "+" },
+ { ref_table = "card.ability", ref_value = "mult", retrigger_type = "mult" }
+ },
+ text_config = { colour = G.C.MULT },
+ }
+ end
+}
+
+-- See localization/en-us.lua to create joker text
\ No newline at end of file
diff --git a/mod/jokers/commercialdriver.lua b/mod/jokers/commercialdriver.lua
new file mode 100644
index 0000000..20753f8
--- /dev/null
+++ b/mod/jokers/commercialdriver.lua
@@ -0,0 +1,82 @@
+SMODS.Atlas {
+ key = 'commercial_driver',
+ path = "j_commercial_driver.png",
+ px = 71,
+ py = 95
+}
+
+SMODS.Joker {
+ key = "commercial_driver",
+ name = "Commercial Driver",
+ atlas = 'commercial_driver',
+ pos = {
+ x = 0,
+ y = 0
+ },
+ rarity = "fuse_fusion",
+ cost = 12,
+ unlocked = true,
+ discovered = false,
+ eternal_compat = true,
+ perishable_compat = true,
+ blueprint_compat = true,
+ config = {
+ extra = {
+ bonus = 0.25,
+ total = 1,
+ joker1 = "j_ride_the_bus",
+ joker2 = "j_drivers_license"
+ }
+ },
+ loc_vars = function(self, info_queue, card)
+ return {
+ vars = {
+ card.ability.extra.bonus,
+ card.ability.extra.total,
+ localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
+ localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}
+ }
+ }
+ end,
+ calculate = function(self, card, context)
+ if context.before and context.cardarea == G.jokers then
+ local enhanced = false
+ for i = 1, #context.scoring_hand do
+ if context.scoring_hand[i].config.center ~= G.P_CENTERS.c_base then enhanced = true end
+ end
+ if not enhanced then
+ local last_mult = card.ability.extra.total
+ card.ability.extra.total = 1
+ if last_mult > 0 then
+ return {
+ card = card,
+ message = localize('k_reset')
+ }
+ end
+ else
+ card.ability.extra.total = card.ability.extra.total + card.ability.extra.bonus
+ end
+ end
+
+ if context.cardarea == G.jokers and context.joker_main then
+ return {
+ message = localize{type='variable',key='a_xmult',vars={card.ability.extra.total}},
+ Xmult_mod = card.ability.extra.total
+ }
+ end
+ end,
+ joker_display_def = function(JokerDisplay)
+ return {
+ text = {
+ {
+ border_nodes = {
+ { text = "X" },
+ { ref_table = "card.ability.extra", ref_value = "total" }
+ }
+ }
+ }
+ }
+ end
+}
+
+-- See localization/en-us.lua to create joker text
\ No newline at end of file
diff --git a/mod/jokers/dementiajoker.lua b/mod/jokers/dementiajoker.lua
new file mode 100644
index 0000000..26b6ee0
--- /dev/null
+++ b/mod/jokers/dementiajoker.lua
@@ -0,0 +1,95 @@
+SMODS.Atlas {
+ key = 'dementia_joker',
+ path = "j_dementia_joker.png",
+ px = 71,
+ py = 95
+}
+
+SMODS.Joker {
+ key = "dementia_joker",
+ name = "Dementia Joker",
+ atlas = 'dementia_joker',
+ pos = {
+ x = 0,
+ y = 0
+ },
+ rarity = "fuse_fusion",
+ cost = 12,
+ unlocked = true,
+ discovered = false,
+ eternal_compat = true,
+ perishable_compat = true,
+ blueprint_compat = true,
+ config = {
+ extra = {
+ mult = 3,
+ odds = 3,
+ joker1 = "j_abstract",
+ joker2 = "j_riff_raff",
+ }
+ },
+ loc_vars = function(self, info_queue, card)
+ local luck, odds = SMODS.get_probability_vars(card, 1, card.ability.extra.odds, "fusion_dementia_desc", false)
+ return {
+ vars = {
+ card.ability.extra.mult,
+ luck, odds,
+ (G.jokers and G.jokers.cards and #G.jokers.cards or 0)*card.ability.extra.mult,
+ localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
+ localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}
+ }
+ }
+ end,
+ calculate = function(self, card, context)
+ if context.end_of_round and not context.blueprint and not context.repetition and not context.individual then
+ if SMODS.pseudorandom_probability(card, 'dementia_joker', 1, card.ability.extra.odds, 'dementia_joker')
+ and not (card.edition and card.edition.negative) then
+ local card = copy_card(card, nil, nil, nil, card.edition and card.edition.negative)
+ card:set_edition({negative = true}, true)
+ card:add_to_deck()
+ G.jokers:emplace(card)
+ return {
+ message = localize('k_copied_ex'),
+ colour = G.C.DARK_EDITION
+ }
+ end
+ end
+
+ if context.cardarea == G.jokers and context.joker_main then
+ local x = 0
+ for i = 1, #G.jokers.cards do
+ if G.jokers.cards[i].ability.set == 'Joker' then x = x + 1 end
+ end
+ return {
+ message = localize{type='variable',key='a_mult',vars={x*card.ability.extra.mult}},
+ mult_mod = x*card.ability.extra.mult
+ }
+ end
+ end,
+ joker_display_def = function(JokerDisplay)
+ return {
+ text = {
+ { text = "+" },
+ { ref_table = "card.joker_display_values", ref_value = "mult", retrigger_type = "mult" }
+ },
+ extra = {
+ {
+ { ref_table = "card.joker_display_values", ref_value = "odds" },
+ }
+ },
+ extra_config = { colour = G.C.GREEN, scale = 0.3 },
+ text_config = { colour = G.C.MULT },
+ calc_function = function(card)
+ local luck, odds = SMODS.get_probability_vars(card, 1, card.ability.extra.odds, "fusion_dementia_desc", false)
+ card.joker_display_values.mult = (G.jokers and G.jokers.cards and #G.jokers.cards or 0) * card.ability.extra.mult
+ if card.edition and card.edition.negative then
+ card.joker_display_values.odds = ""
+ else
+ card.joker_display_values.odds = localize { type = 'variable', key = "jdis_odds", vars = { luck, odds } }
+ end
+ end
+ }
+ end
+}
+
+-- See localization/en-us.lua to create joker text
\ No newline at end of file
diff --git a/mod/jokers/diamondbard.lua b/mod/jokers/diamondbard.lua
new file mode 100644
index 0000000..10ab58c
--- /dev/null
+++ b/mod/jokers/diamondbard.lua
@@ -0,0 +1,91 @@
+SMODS.Atlas {
+ key = 'diamond_bard',
+ path = "j_diamond_bard.png",
+ px = 71,
+ py = 95
+}
+
+SMODS.Joker {
+ key = "diamond_bard",
+ name = "Diamond Bard",
+ atlas = 'diamond_bard',
+ pos = {
+ x = 0,
+ y = 0
+ },
+ rarity = "fuse_fusion",
+ cost = 12,
+ unlocked = true,
+ discovered = false,
+ eternal_compat = true,
+ perishable_compat = true,
+ blueprint_compat = true,
+ config = {
+ extra = {
+ money_threshold = 20,
+ mult = 4,
+ money = 1,
+ joker1 = "j_greedy_joker",
+ joker2 = "j_rough_gem",
+ }
+ },
+ loc_vars = function(self, info_queue, card)
+ return {
+ vars = {
+ card.ability.extra.money,
+ card.ability.extra.mult,
+ card.ability.extra.money_threshold,
+ localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
+ localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}
+ }
+ }
+ end,
+ calculate = function(self, card, context)
+ if context.individual and context.cardarea == G.play and
+ context.other_card:is_suit('Diamonds') then
+ G.GAME.dollar_buffer = (G.GAME.dollar_buffer or 0) + to_big(card.ability.extra.money)
+ G.E_MANAGER:add_event(Event({func = (function() G.GAME.dollar_buffer = 0; return true end)}))
+ return {
+ dollars = card.ability.extra.money,
+ mult = card.ability.extra.mult * (1 + math.floor(to_number(G.GAME.dollars) / card.ability.extra.money_threshold)),
+ card = card
+ }
+ end
+ end,
+ joker_display_def = function(JokerDisplay)
+ return {
+ text = {
+ { text = "+", colour = G.C.MULT },
+ { ref_table = "card.joker_display_values", ref_value = "mult", retrigger_type = "mult", colour = G.C.MULT },
+ { text = ", " },
+ { text = "+$", colour = G.C.GOLD },
+ { ref_table = "card.joker_display_values", ref_value = "dollars", retrigger_type = "mult", colour = G.C.GOLD },
+ },
+ reminder_text = {
+ { text = "(" },
+ { ref_table = "card.joker_display_values", ref_value = "localized_text", colour = lighten(G.C.SUITS["Diamonds"], 0.35) },
+ { text = ")" }
+ },
+ calc_function = function(card)
+ local mult = 0
+ local dollars = 0
+ local text, _, scoring_hand = JokerDisplay.evaluate_hand()
+ if text ~= 'Unknown' then
+ for _, scoring_card in pairs(scoring_hand) do
+ if scoring_card:is_suit("Diamonds") then
+ mult = mult +
+ card.ability.extra.mult * (1 + math.floor(to_number(G.GAME.dollars) / card.ability.extra.money_threshold)) * JokerDisplay.calculate_card_triggers(scoring_card, scoring_hand)
+ dollars = dollars +
+ card.ability.extra.money * JokerDisplay.calculate_card_triggers(scoring_card, scoring_hand)
+ end
+ end
+ end
+ card.joker_display_values.mult = mult
+ card.joker_display_values.dollars = dollars
+ card.joker_display_values.localized_text = localize("Diamonds", 'suits_plural')
+ end
+ }
+ end
+}
+
+-- See localization/en-us.lua to create joker text
\ No newline at end of file
diff --git a/mod/jokers/dynamicduo.lua b/mod/jokers/dynamicduo.lua
new file mode 100644
index 0000000..d397ce3
--- /dev/null
+++ b/mod/jokers/dynamicduo.lua
@@ -0,0 +1,82 @@
+SMODS.Atlas {
+ key = 'dynamic_duo',
+ path = "j_dynamic_duo.png",
+ px = 71,
+ py = 95
+}
+
+SMODS.Joker {
+ key = "dynamic_duo",
+ name = "Dynamic Duo",
+ atlas = 'dynamic_duo',
+ pos = {
+ x = 0,
+ y = 0
+ },
+ rarity = "fuse_fusion",
+ cost = 12,
+ unlocked = true,
+ discovered = false,
+ eternal_compat = true,
+ perishable_compat = true,
+ blueprint_compat = true,
+ config = {
+ extra = {
+ mult = 4,
+ chips = 31,
+ joker1 = "j_even_steven",
+ joker2 = "j_odd_todd"
+ }
+ },
+ loc_vars = function(self, info_queue, card)
+ return {
+ vars = {
+ card.ability.extra.mult,
+ card.ability.extra.chips,
+ localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
+ localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}
+ }
+ }
+ end,
+ calculate = function(self, card, context)
+ if context.individual and context.cardarea == G.play and
+ not context.other_card:is_face() and not SMODS.has_no_rank(context.other_card) then
+ return {
+ mult = card.ability.extra.mult,
+ chips = card.ability.extra.chips,
+ card = card
+ }
+ end
+ end,
+ joker_display_def = function(JokerDisplay)
+ return {
+ text = {
+ { text = "+", colour = G.C.CHIPS },
+ { ref_table = "card.joker_display_values", ref_value = "chips", colour = G.C.CHIPS, retrigger_type = "mult" },
+ { text = " +", colour = G.C.MULT },
+ { ref_table = "card.joker_display_values", ref_value = "mult", colour = G.C.MULT, retrigger_type = "mult" }
+ },
+ reminder_text = {
+ { ref_table = "card.joker_display_values", ref_value = "localized_text" }
+ },
+ calc_function = function(card)
+ local chips, mult = 0, 0
+ local text, _, scoring_hand = JokerDisplay.evaluate_hand()
+ if text ~= 'Unknown' then
+ for _, scoring_card in pairs(scoring_hand) do
+ if not scoring_card:is_face() then
+ local retriggers = JokerDisplay.calculate_card_triggers(scoring_card, scoring_hand)
+ chips = chips + card.ability.extra.chips * retriggers
+ mult = mult + card.ability.extra.mult * retriggers
+ end
+ end
+ end
+ card.joker_display_values.mult = mult
+ card.joker_display_values.chips = chips
+ card.joker_display_values.localized_text = localize("k_numbered_cards")
+ end
+ }
+ end
+}
+
+-- See localization/en-us.lua to create joker text
\ No newline at end of file
diff --git a/mod/jokers/flagbearer.lua b/mod/jokers/flagbearer.lua
new file mode 100644
index 0000000..2e165e0
--- /dev/null
+++ b/mod/jokers/flagbearer.lua
@@ -0,0 +1,98 @@
+SMODS.Atlas {
+ key = 'flag_bearer',
+ path = "j_flag_bearer.png",
+ px = 71,
+ py = 95
+}
+
+SMODS.Joker {
+ key = "flag_bearer",
+ name = "Flag Bearer",
+ atlas = 'flag_bearer',
+ pos = {
+ x = 0,
+ y = 0
+ },
+ rarity = "fuse_fusion",
+ cost = 12,
+ unlocked = true,
+ discovered = false,
+ eternal_compat = true,
+ perishable_compat = true,
+ blueprint_compat = true,
+ config = {
+ extra = {
+ hand_add = 1,
+ discard_sub = 1,
+ mult = 0,
+ joker1 = "j_banner",
+ joker2 = "j_green_joker"
+ }
+ },
+ loc_vars = function(self, info_queue, card)
+ return {
+ vars = {
+ card.ability.extra.hand_add,
+ card.ability.extra.discard_sub,
+ card.ability.extra.mult * (G.GAME.current_round.discards_left or 0),
+ localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
+ localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}
+ }
+ }
+ end,
+ set_ability = function(self, card, initial, delay_sprites)
+ G.E_MANAGER:add_event(Event({trigger = 'after',delay = 0.3, blocking = false,
+ func = function()
+ if card.ability.mult and (card.ability.extra.mult == 0) then
+ card.ability.extra.mult = card.ability.mult or 0
+ card.ability.mult = nil
+ end
+ return true
+ end}))
+ end,
+ calculate = function(self, card, context)
+ if context.discard and not context.blueprint and context.other_card == context.full_hand[#context.full_hand] then
+ local prev_mult = card.ability.extra.mult
+ card.ability.extra.mult = math.max(0, card.ability.extra.mult - card.ability.extra.discard_sub)
+ if card.ability.extra.mult ~= prev_mult then
+ return {
+ message = localize{type='variable',key='a_mult_minus',vars={card.ability.extra.discard_sub}},
+ colour = G.C.RED,
+ card = card
+ }
+ end
+ end
+
+ if context.cardarea == G.jokers and context.before then
+ if not context.blueprint then
+ card.ability.extra.mult = card.ability.extra.mult + card.ability.extra.hand_add
+ return {
+ card = card,
+ message = localize{type='variable',key='a_mult',vars={card.ability.extra.hand_add}}
+ }
+ end
+ end
+
+ if context.cardarea == G.jokers and context.joker_main then
+ local mult = card.ability.extra.mult * G.GAME.current_round.discards_left
+ return {
+ message = localize{type='variable',key='a_mult',vars={mult}},
+ mult_mod = mult
+ }
+ end
+ end,
+ joker_display_def = function(JokerDisplay)
+ return {
+ text = {
+ { text = "+" },
+ { ref_table = "card.joker_display_values", ref_value = "mult", retrigger_type = "mult" },
+ },
+ text_config = { colour = G.C.MULT },
+ calc_function = function(card)
+ card.joker_display_values.mult = card.ability.extra.mult * G.GAME.current_round.discards_left
+ end
+ }
+ end
+}
+
+-- See localization/en-us.lua to create joker text
\ No newline at end of file
diff --git a/mod/jokers/flipflop.lua b/mod/jokers/flipflop.lua
new file mode 100644
index 0000000..ccaafa5
--- /dev/null
+++ b/mod/jokers/flipflop.lua
@@ -0,0 +1,168 @@
+SMODS.Atlas {
+ key = 'flip_flop',
+ path = "j_flip_flop.png",
+ px = 71,
+ py = 95
+}
+
+local flip = {
+ x = 0,
+ y = 0
+}
+
+local flop = {
+ x = 1,
+ y = 0
+}
+
+SMODS.Joker {
+ key = "flip_flop",
+ name = "Flip-Flop",
+ atlas = "flip_flop",
+ pos = flip,
+ rarity = "fuse_fusion",
+ cost = 12,
+ unlocked = true,
+ discovered = false,
+ eternal_compat = true,
+ perishable_compat = true,
+ blueprint_compat = true,
+ config = {
+ extra = {
+ hands = 2,
+ discards = 2,
+ mult = 8,
+ chips = 50,
+ side = "mult",
+ joker1 = "j_juggler",
+ joker2 = "j_drunkard"
+ }
+ },
+ loc_vars = function(self, info_queue, card)
+ local result = {}
+ if card.ability.extra.side == "mult" then
+ result = {
+ card.ability.extra.hands,
+ card.ability.extra.mult,
+ localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
+ localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}
+ }
+ else
+ result = {
+ card.ability.extra.discards,
+ card.ability.extra.chips,
+ localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
+ localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}
+ }
+ end
+
+ return {
+ key = self.key.."_"..card.ability.extra.side,
+ vars = result
+ }
+ end,
+ set_ability = function(self, card, initial, delay_sprites)
+ local flipref = card.config.center
+ if card.ability.extra.side == "mult" then
+ flipref.pos = flip
+ card:set_sprites(flipref)
+ else
+ flipref.pos = flop
+ card:set_sprites(flipref)
+ end
+ end,
+ add_to_deck = function(self, card, from_debuff)
+ if card.ability.extra.side == "mult" then
+ G.hand:change_size(card.ability.extra.hands)
+ else
+ G.GAME.round_resets.discards = G.GAME.round_resets.discards + card.ability.extra.discards
+ ease_discard(card.ability.extra.discards)
+ end
+ end,
+ remove_from_deck = function(self, card, from_debuff)
+ if card.ability.extra.side == "mult" then
+ G.hand:change_size(-card.ability.extra.hands)
+ else
+ G.GAME.round_resets.discards = G.GAME.round_resets.discards - card.ability.extra.discards
+ ease_discard(-card.ability.extra.discards)
+ end
+ end,
+ calculate = function(self, card, context)
+ local flipref = card.config.center
+ if context.end_of_round and not context.blueprint and not context.repetition and not context.individual then
+ if card.ability.extra.side == "mult" then
+ G.E_MANAGER:add_event(Event({trigger = 'after', delay = 0.3, blockable = false,
+ func = function()
+ card.ability.extra.side = "chips"
+ card:juice_up(1, 1)
+ flipref.pos = flop
+ card:set_sprites(flipref)
+
+ return true; end}))
+
+ G.hand:change_size(-card.ability.extra.hands)
+ G.GAME.round_resets.discards = G.GAME.round_resets.discards + card.ability.extra.discards
+ ease_discard(card.ability.extra.discards)
+
+ return {
+ message = localize('k_flipped_ex'),
+ colour = G.C.CHIPS
+ }
+ else
+ G.E_MANAGER:add_event(Event({trigger = 'after', delay = 0.3, blockable = false,
+ func = function()
+ card.ability.extra.side = "mult"
+ card:juice_up(1, 1)
+ flipref.pos = flip
+ card:set_sprites(flipref)
+
+ return true; end}))
+
+ G.hand:change_size(card.ability.extra.hands)
+ G.GAME.round_resets.discards = G.GAME.round_resets.discards - card.ability.extra.discards
+ ease_discard(-card.ability.extra.discards)
+
+ return {
+ message = localize('k_flipped_ex'),
+ colour = G.C.MULT
+ }
+ end
+
+ end
+
+ if context.cardarea == G.jokers and context.joker_main then
+ if card.ability.extra.side == "mult" then
+ return {
+ message = localize{type='variable',key='a_mult',vars={card.ability.extra.mult}},
+ mult_mod = card.ability.extra.mult,
+ colour = G.C.MULT
+ }
+ else
+ return {
+ message = localize{type='variable',key='a_chips',vars={card.ability.extra.chips}},
+ chip_mod = card.ability.extra.chips,
+ colour = G.C.CHIPS
+ }
+ end
+ end
+ end,
+ joker_display_def = function(JokerDisplay)
+ return {
+ text = {
+ { ref_table = "card.joker_display_values", ref_value = "chips", retrigger_type = "mult", colour = G.C.CHIPS },
+ { ref_table = "card.joker_display_values", ref_value = "mult", retrigger_type = "mult", colour = G.C.MULT },
+ },
+ calc_function = function(card)
+ if card.ability.extra.side == "mult" then
+ card.joker_display_values.chips = ""
+ card.joker_display_values.mult = "+" .. card.ability.extra.mult
+ else
+ card.joker_display_values.chips = "+" .. card.ability.extra.chips
+ card.joker_display_values.mult = ""
+ end
+ end
+ }
+ end
+}
+
+-- See localization/en-us.lua to create joker text
\ No newline at end of file
diff --git a/mod/jokers/goldenegg.lua b/mod/jokers/goldenegg.lua
new file mode 100644
index 0000000..f85b6c8
--- /dev/null
+++ b/mod/jokers/goldenegg.lua
@@ -0,0 +1,78 @@
+SMODS.Atlas {
+ key = 'golden_egg',
+ path = "j_golden_egg.png",
+ px = 71,
+ py = 95
+}
+
+SMODS.Joker {
+ key = "golden_egg",
+ name = "Golden Egg",
+ atlas = 'golden_egg',
+ pos = {
+ x = 0,
+ y = 0
+ },
+ rarity = "fuse_fusion",
+ cost = 12,
+ unlocked = true,
+ discovered = false,
+ eternal_compat = true,
+ perishable_compat = true,
+ blueprint_compat = true,
+ config = {
+ extra = {
+ dollars = 4,
+ joker1 = "j_egg",
+ joker2 = "j_golden"
+ }
+ },
+ loc_vars = function(self, info_queue, card)
+ return {
+ vars = {
+ card.ability.extra.dollars,
+ localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
+ localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}
+ }
+ }
+ end,
+ calc_dollar_bonus = function(self, card)
+ return card.ability.extra.dollars
+ end,
+ calculate = function(self, card, context)
+ if context.end_of_round and not context.blueprint and not context.repetition and not context.individual then
+ card.ability.extra_value = card.ability.extra_value + card.ability.extra.dollars
+ card:set_cost()
+ return {
+ message = localize('k_val_up'),
+ colour = G.C.MONEY
+ }
+ end
+ end,
+ joker_display_def = function(JokerDisplay)
+ return {
+ text = {
+ { text = "+$" },
+ { ref_table = "card.ability.extra", ref_value = "dollars" },
+ { text = " /round" },
+ },
+ text_config = { colour = G.C.GOLD },
+ reminder_text = {
+ { ref_table = "card.joker_display_values", ref_value = "localized_text" },
+ },
+ calc_function = function(card)
+ card.joker_display_values.localized_text = "(" .. localize("k_round") .. ")"
+ end,
+ reminder_text = {
+ { text = "(" },
+ { text = "$", colour = G.C.GOLD },
+ { ref_table = "card", ref_value = "sell_cost", colour = G.C.GOLD },
+ { text = " Sell Value", colour = G.C.GOLD },
+ { text = ")" },
+ },
+ reminder_text_config = { scale = 0.35 }
+ }
+ end
+}
+
+-- See localization/en-us.lua to create joker text
\ No newline at end of file
diff --git a/mod/jokers/heartpaladin.lua b/mod/jokers/heartpaladin.lua
new file mode 100644
index 0000000..d30aace
--- /dev/null
+++ b/mod/jokers/heartpaladin.lua
@@ -0,0 +1,102 @@
+SMODS.Atlas {
+ key = 'heart_paladin',
+ path = "j_heart_paladin.png",
+ px = 71,
+ py = 95
+}
+
+SMODS.Joker {
+ key = "heart_paladin",
+ name = "Heart Paladin",
+ atlas = 'heart_paladin',
+ pos = {
+ x = 0,
+ y = 0
+ },
+ rarity = "fuse_fusion",
+ cost = 12,
+ unlocked = true,
+ discovered = false,
+ eternal_compat = true,
+ perishable_compat = true,
+ blueprint_compat = true,
+ config = {
+ extra = {
+ odds = 3,
+ Xmult = 1.5,
+ joker1 = "j_lusty_joker",
+ joker2 = "j_bloodstone"
+ }
+ },
+ loc_vars = function(self, info_queue, card)
+ local luck, odds = SMODS.get_probability_vars(card, 1, card.ability.extra.odds, "fusion_heartpaladin_desc", false)
+ return {
+ vars = {
+ card.ability.extra.Xmult,
+ luck,
+ odds,
+ localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
+ localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}
+ }
+ }
+ end,
+ calculate = function(self, card, context)
+ if context.individual and context.cardarea == G.play and
+ context.other_card:is_suit('Hearts') then
+ return {
+ x_mult = card.ability.extra.Xmult,
+ card = card
+ }
+ end
+
+ if context.repetition and context.cardarea == G.play and
+ context.other_card:is_suit('Hearts') then
+ if SMODS.pseudorandom_probability(card, 'heart_paladin', 1, card.ability.extra.odds, 'heart_paladin') then
+ return {
+ message = localize('k_again_ex'),
+ repetitions = 1,
+ card = card
+ }
+ end
+ end
+ end,
+ joker_display_def = function(JokerDisplay)
+ return {
+ text = {
+ {
+ border_nodes = {
+ { ref_table = "card.joker_display_values", ref_value = "prefix" },
+ { ref_table = "card.joker_display_values", ref_value = "Xmult", retrigger_type = "mult" }
+ }
+ }
+ },
+ reminder_text = {
+ { text = "(" },
+ { ref_table = "card.joker_display_values", ref_value = "localized_text", colour = lighten(G.C.SUITS["Hearts"], 0.35) },
+ { text = ")" }
+ },
+ calc_function = function(card)
+ local luck, odds = SMODS.get_probability_vars(card, 1, card.ability.extra.odds, "fusion_heartpaladin_desc", false)
+ local x_mult = 1
+ local text, _, scoring_hand = JokerDisplay.evaluate_hand()
+ local m = 1.5
+ card.joker_display_values.prefix = "X"
+ if luck < odds then
+ card.joker_display_values.prefix = "X ~"
+ m = 1.25
+ end
+ if text ~= 'Unknown' then
+ for _, scoring_card in pairs(scoring_hand) do
+ if scoring_card:is_suit("Hearts") then
+ x_mult = x_mult * m ^ JokerDisplay.calculate_card_triggers(scoring_card, scoring_hand)
+ end
+ end
+ end
+ card.joker_display_values.Xmult = x_mult
+ card.joker_display_values.localized_text = localize("Hearts", 'suits_plural')
+ end
+ }
+ end
+}
+
+-- See localization/en-us.lua to create joker text
\ No newline at end of file
diff --git a/mod/jokers/moonmarauder.lua b/mod/jokers/moonmarauder.lua
new file mode 100644
index 0000000..60cf0f6
--- /dev/null
+++ b/mod/jokers/moonmarauder.lua
@@ -0,0 +1,118 @@
+FusionJokers.fusions:add_fusion("j_six_slothful_joker", nil, false, "j_six_moonstone", nil, false, "j_fuse_moon_marauder", 12)
+
+SMODS.Atlas {
+ key = 'moon_marauder',
+ path = "j_moon_marauder.png",
+ px = 71,
+ py = 95
+}
+
+SMODS.Joker {
+ key = "moon_marauder",
+ name = "Moon Marauder",
+ atlas = 'moon_marauder',
+ pos = {
+ x = 0,
+ y = 0
+ },
+ rarity = "fuse_fusion",
+ cost = 12,
+ unlocked = true,
+ discovered = false,
+ eternal_compat = true,
+ perishable_compat = true,
+ blueprint_compat = true,
+ config = {
+ extra = {
+ odds = 3,
+ joker1 = "j_six_slothful_joker",
+ joker2 = "j_six_moonstone"
+ }
+ },
+ loc_vars = function(self, info_queue, card)
+ local luck, odds = SMODS.get_probability_vars(card, 1, card.ability.extra.odds, "fusion_moonmarauder_desc", false)
+ return {
+ vars = {
+ luck,
+ odds,
+ localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
+ localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}
+ }
+ }
+ end,
+ calculate = function(self, card, context)
+ if context.before and (context.cardarea == G.jokers) then
+ local moons = {}
+ for _, v in ipairs(context.full_hand) do
+ if v:is_suit('Moons') and not (v.ability.name == 'Glass Card') and SMODS.pseudorandom_probability(card, 'moon_marauder', 1, card.ability.extra.odds, 'moon_marauder') then
+ moons[#moons + 1] = v
+ v:set_ability(G.P_CENTERS.m_glass, nil, true)
+ G.E_MANAGER:add_event(Event({
+ func = function()
+ v:juice_up()
+ return true
+ end
+ }))
+ end
+ end
+ if #moons > 0 then
+ return {
+ message = localize('k_glass'),
+ colour = G.C.SECONDARY_SET.Enhanced,
+ card = context.blueprint_card or card
+ }
+ end
+ end
+
+ if context.remove_playing_cards and not context.blueprint then
+ -- G.E_MANAGER:add_event(Event({
+ -- trigger = 'after',
+ -- delay = 1,
+ -- func = function()
+ -- sendDebugMessage(tostring(#context.removed))
+ -- for k, v in ipairs(context.removed) do
+ -- sendDebugMessage(tostring(v.shattered))
+ -- if v.shattered then
+ -- local _card = Card(G.play.T.x, G.play.T.y, G.CARD_W, G.CARD_H, G.P_CARDS.empty, G.P_CENTERS.c_base, {playing_card = G.playing_card})
+
+ -- _card = copy_card(v, _card, nil, G.playing_card)
+ -- _card:start_materialize({G.C.SECONDARY_SET.Enhanced})
+ -- G.deck:emplace(_card)
+
+ -- G.E_MANAGER:add_event(Event({
+ -- func = function()
+ -- card_eval_status_text(context.blueprint_card or card, 'extra', nil, nil, nil,
+ -- { message = localize('k_in_tact_ex'), colour = G.C.SECONDARY_SET.edition })
+ -- return true
+ -- end
+ -- }))
+ -- end
+ -- end
+ -- end
+ -- }))
+ sendDebugMessage(tostring(#context.removed))
+ for k, v in ipairs(context.removed) do
+ sendDebugMessage(tostring(v.shattered))
+ if v.shattered then
+ local _card = Card(G.play.T.x, G.play.T.y, G.CARD_W, G.CARD_H, G.P_CARDS.empty, G.P_CENTERS.c_base, {playing_card = G.playing_card})
+
+ G.playing_card = (G.playing_card and G.playing_card + 1) or 1
+ _card = copy_card(v, _card, nil, G.playing_card)
+ _card:start_materialize({G.C.SECONDARY_SET.Enhanced})
+ G.deck:emplace(_card)
+ table.insert(G.playing_cards, _card)
+
+ G.E_MANAGER:add_event(Event({
+ func = function()
+ card_eval_status_text(context.blueprint_card or card, 'extra', nil, nil, nil,
+ { message = localize('k_in_tact_ex'), colour = G.C.SECONDARY_SET.edition })
+ return true
+ end
+ }))
+ end
+ end
+ end
+ end
+}
+
+-- See localization/en-us.lua to create joker text
\ No newline at end of file
diff --git a/mod/jokers/royaldecree.lua b/mod/jokers/royaldecree.lua
new file mode 100644
index 0000000..b77c369
--- /dev/null
+++ b/mod/jokers/royaldecree.lua
@@ -0,0 +1,99 @@
+SMODS.Atlas {
+ key = 'royal_decree',
+ path = "j_royal_decree.png",
+ px = 71,
+ py = 95
+}
+
+SMODS.Joker {
+ key = "royal_decree",
+ name = "Royal Decree",
+ atlas = 'royal_decree',
+ pos = {
+ x = 0,
+ y = 0
+ },
+ rarity = "fuse_fusion",
+ cost = 12,
+ unlocked = true,
+ discovered = false,
+ eternal_compat = true,
+ perishable_compat = true,
+ blueprint_compat = true,
+ config = {
+ extra = {
+ dollars = 2,
+ joker1 = "j_business",
+ joker2 = "j_reserved_parking",
+ }
+ },
+ loc_vars = function(self, info_queue, card)
+ return {
+ vars = {
+ card.ability.extra.dollars,
+ localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
+ localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}
+ }
+ }
+ end,
+ calculate = function(self, card, context)
+ if context.end_of_round and context.individual then
+ if context.cardarea == G.hand and context.other_card:is_face() then
+ return {
+ h_dollars = 2,
+ card = card
+ }
+ end
+ end
+
+ if context.cardarea == G.play and context.individual and context.other_card:is_face() then
+ G.GAME.dollar_buffer = (G.GAME.dollar_buffer or 0) + 2
+ G.E_MANAGER:add_event(Event({func = (function() G.GAME.dollar_buffer = 0; return true end)}))
+ return {
+ dollars = 2,
+ card = card
+ }
+
+ end
+ end,
+ joker_display_def = function(JokerDisplay)
+ return {
+ text = {
+ { text = "$", colour = G.C.GOLD },
+ { ref_table = "card.joker_display_values", ref_value = "count", retrigger_type = "mult", colour = G.C.GOLD },
+ { text = " (played)", colour = G.C.GOLD },
+ },
+ reminder_text = {
+ { text = "$", colour = G.C.GOLD },
+ { ref_table = "card.joker_display_values", ref_value = "count2", retrigger_type = "mult", colour = G.C.GOLD },
+ { text = " (held)", colour = G.C.GOLD },
+ },
+ reminder_text_config = { scale = 0.35 },
+ calc_function = function(card)
+ local count = 0
+ local text, _, scoring_hand = JokerDisplay.evaluate_hand()
+ if text ~= 'Unknown' then
+ for _, scoring_card in pairs(scoring_hand) do
+ if scoring_card:is_face() then
+ count = count + card.ability.extra.dollars *
+ JokerDisplay.calculate_card_triggers(scoring_card, scoring_hand)
+ end
+ end
+ end
+ card.joker_display_values.count = count
+ local playing_hand = next(G.play.cards)
+ local count = 0
+ for _, playing_card in ipairs(G.hand.cards) do
+ if playing_hand or not playing_card.highlighted then
+ if playing_card.facing and not (playing_card.facing == 'back') and playing_card:is_face() then
+ count = count + 2 * JokerDisplay.calculate_card_triggers(playing_card, nil, true)
+ end
+ end
+ end
+ card.joker_display_values.count2 = count
+ end
+ }
+ end
+}
+
+-- See localization/en-us.lua to create joker text
\ No newline at end of file
diff --git a/mod/jokers/spadearcher.lua b/mod/jokers/spadearcher.lua
new file mode 100644
index 0000000..c425897
--- /dev/null
+++ b/mod/jokers/spadearcher.lua
@@ -0,0 +1,97 @@
+SMODS.Atlas {
+ key = 'spade_archer',
+ path = "j_spade_archer.png",
+ px = 71,
+ py = 95
+}
+
+SMODS.Joker {
+ key = "spade_archer",
+ name = "Spade Archer",
+ atlas = 'spade_archer',
+ pos = {
+ x = 0,
+ y = 0
+ },
+ rarity = "fuse_fusion",
+ cost = 12,
+ unlocked = true,
+ discovered = false,
+ eternal_compat = true,
+ perishable_compat = true,
+ blueprint_compat = true,
+ config = {
+ extra = {
+ chips = 50,
+ chip_mod = 10,
+ joker1 = "j_wrathful_joker",
+ joker2 = "j_arrowhead"
+ }
+ },
+ loc_vars = function(self, info_queue, card)
+ return {
+ vars = {
+ card.ability.extra.chips,
+ card.ability.extra.chip_mod,
+ localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
+ localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}
+ }
+ }
+ end,
+ calculate = function(self, card, context)
+ if context.individual and context.cardarea == G.play and
+ context.other_card:is_suit('Spades') then
+ return {
+ chips = card.ability.extra.chips,
+ card = card
+ }
+ end
+
+ if context.before and context.cardarea == G.jokers and not context.blueprint then
+ local spades = 0
+ for k, v in ipairs(context.scoring_hand) do
+ if v:is_suit('Spades') then
+ spades = spades + 1
+ end
+ end
+ if spades >= 5 then
+ card.ability.extra.chips = card.ability.extra.chips + card.ability.extra.chip_mod
+ return {
+ message = localize('k_upgrade_ex'),
+ colour = G.C.CHIPS,
+ card = card
+ }
+ end
+ end
+ end,
+ joker_display_def = function(JokerDisplay)
+ return {
+ text = {
+ { text = "+" },
+ { ref_table = "card.joker_display_values", ref_value = "chips", retrigger_type = "mult" },
+ },
+ text_config = { colour = G.C.CHIPS },
+ reminder_text = {
+ { text = "(" },
+ { ref_table = "card.joker_display_values", ref_value = "localized_text", colour = lighten(G.C.SUITS["Spades"], 0.35) },
+ { text = ")" }
+ },
+ calc_function = function(card)
+ local chips = 0
+ local text, _, scoring_hand = JokerDisplay.evaluate_hand()
+ if text ~= 'Unknown' then
+ for _, scoring_card in pairs(scoring_hand) do
+ if scoring_card:is_suit("Spades") then
+ chips = chips +
+ card.ability.extra.chips * JokerDisplay.calculate_card_triggers(scoring_card, scoring_hand)
+ end
+ end
+ end
+ card.joker_display_values.chips = chips
+ card.joker_display_values.localized_text = localize("Spades", 'suits_plural')
+ end
+ }
+ end,
+}
+
+-- See localization/en-us.lua to create joker text
diff --git a/mod/jokers/staroracle.lua b/mod/jokers/staroracle.lua
new file mode 100644
index 0000000..3e62319
--- /dev/null
+++ b/mod/jokers/staroracle.lua
@@ -0,0 +1,75 @@
+FusionJokers.fusions:add_fusion("j_six_envious_joker", nil, false, "j_six_star_ruby", nil, false, "j_fuse_star_oracle", 12)
+
+SMODS.Atlas {
+ key = 'star_oracle',
+ path = "j_star_oracle.png",
+ px = 71,
+ py = 95
+}
+
+SMODS.Joker {
+ key = "star_oracle",
+ name = "Star Oracle",
+ atlas = 'star_oracle',
+ pos = {
+ x = 0,
+ y = 0
+ },
+ rarity = "fuse_fusion",
+ cost = 12,
+ unlocked = true,
+ discovered = false,
+ eternal_compat = true,
+ perishable_compat = true,
+ blueprint_compat = true,
+ config = {
+ extra = {
+ odds = 10,
+ slots = 2,
+ joker1 = "j_six_envious_joker",
+ joker2 = "j_six_star_ruby",
+ }
+ },
+ loc_vars = function(self, info_queue, card)
+ local luck, odds = SMODS.get_probability_vars(card, 1, card.ability.extra.odds, "fusion_staroracle_desc", false)
+ return {
+ vars = {
+ luck,
+ odds,
+ localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
+ localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}
+ }
+ }
+ end,
+ add_to_deck = function(self, card, from_debuff)
+ G.consumeables:change_size(card.ability.extra.slots)
+ end,
+ remove_from_deck = function(self, card, from_debuff)
+ G.consumeables:change_size(-card.ability.extra.slots)
+ end,
+ calculate = function(self, card, context)
+ if context.individual and
+ context.cardarea == G.play and
+ context.other_card:is_suit('Stars') and
+ #G.consumeables.cards + G.GAME.consumeable_buffer < G.consumeables.config.card_limit and
+ SMODS.pseudorandom_probability(card, 'starruby', 1, card.ability.extra.odds, 'starruby') then
+ G.GAME.consumeable_buffer = G.GAME.consumeable_buffer + 1
+ G.E_MANAGER:add_event(Event({
+ trigger = 'before',
+ delay = 0.0,
+ func = (function()
+ local _card = create_card('Spectral', G.consumeables, nil, nil, nil, nil, nil, 'ruby')
+ _card:add_to_deck()
+ G.consumeables:emplace(_card)
+ G.GAME.consumeable_buffer = 0
+ return true
+ end)
+ }))
+ card_eval_status_text(context.blueprint_card or card, 'extra', nil, nil, nil,
+ { message = localize('k_plus_spectral'), colour = G.C.SECONDARY_SET.Spectral })
+ return {}
+ end
+ end
+}
+
+-- See localization/en-us.lua to create joker text
\ No newline at end of file
diff --git a/mod/jokers/test.lua b/mod/jokers/test.lua
new file mode 100644
index 0000000..7f3e219
--- /dev/null
+++ b/mod/jokers/test.lua
@@ -0,0 +1,59 @@
+local dp = not not next(SMODS.find_mod("DebugPlus"))
+if not dp then return nil end
+
+FusionJokers.fusions:register_fusion{
+ jokers = {
+ { name = "j_joker", merge_stat = "mult" },
+ { name = "j_joker", merge_stat = "mult" },
+ { name = "j_joker", merge_stat = "mult" },
+ },
+ result_joker = "j_fuse_three_jimbos",
+ merged_stat = "mult",
+ cost = 2,
+}
+
+SMODS.Atlas{
+ key = "three",
+ path = "j_fuse_three_jimbos.png",
+ px = 71,
+ py = 95
+}
+
+SMODS.Joker{
+ key = "three_jimbos",
+ loc_txt = {
+ name = "Three Fucking Jimbos",
+ text = {
+ "{C:mult}+#1#{} Mult",
+ "{C:inactive,s:0.8}hoLY shit"
+ }
+ },
+ loc_vars = function (self, info_queue, card)
+ return {
+ vars = {
+ card.ability.extra.mult
+ }
+ }
+ end,
+ config = {
+ extra = {
+ mult = 69
+ }
+ },
+ rarity = "fuse_fusion",
+ atlas = "three",
+ pos = {x=0,y=0},
+ calculate = function (self, card, context)
+ if context.joker_main then
+ return {
+ mult = card.ability.extra.mult
+ }
+ end
+ end
+}
+
+SMODS.Joker:take_ownership("joker", {
+ in_pool = function (self, args)
+ return true, {allow_duplicates = true}
+ end
+})
\ No newline at end of file
diff --git a/mod/jokers/uncannyface.lua b/mod/jokers/uncannyface.lua
new file mode 100644
index 0000000..96913b5
--- /dev/null
+++ b/mod/jokers/uncannyface.lua
@@ -0,0 +1,90 @@
+SMODS.Atlas {
+ key = 'uncanny_face',
+ path = "j_uncanny_face.png",
+ px = 71,
+ py = 95
+}
+
+SMODS.Joker {
+ key = "uncanny_face",
+ name = "Uncanny Face",
+ atlas = 'uncanny_face',
+ pos = {
+ x = 0,
+ y = 0
+ },
+ rarity = "fuse_fusion",
+ cost = 12,
+ unlocked = true,
+ discovered = false,
+ eternal_compat = true,
+ perishable_compat = true,
+ blueprint_compat = true,
+ config = {
+ extra = {
+ chips = 15,
+ mult = 2,
+ joker1 = "j_scary_face",
+ joker2 = "j_smiley"
+ }
+ },
+ loc_vars = function(self, info_queue, card)
+ return {
+ vars = {
+ card.ability.extra.chips,
+ card.ability.extra.mult,
+ localize{type = 'name_text', key = card.ability.extra.joker1, set = 'Joker'},
+ localize{type = 'name_text', key = card.ability.extra.joker2, set = 'Joker'}
+ }
+ }
+ end,
+ calculate = function(self, card, context)
+ if context.individual and context.cardarea == G.play and
+ context.other_card:is_face() then
+ local faces = 0
+ for k, v in ipairs(context.scoring_hand) do
+ if v:is_face() then
+ faces = faces + 1
+ end
+ end
+ return {
+ mult = card.ability.extra.mult * faces,
+ chips = card.ability.extra.chips * faces,
+ card = card
+ }
+ end
+ end,
+ joker_display_def = function(JokerDisplay)
+ return {
+ text = {
+ { text = "+", colour = G.C.CHIPS },
+ { ref_table = "card.joker_display_values", ref_value = "chips", colour = G.C.CHIPS, retrigger_type = "mult" },
+ { text = " +", colour = G.C.MULT },
+ { ref_table = "card.joker_display_values", ref_value = "mult", colour = G.C.MULT, retrigger_type = "mult" }
+ },
+ reminder_text = {
+ { ref_table = "card.joker_display_values", ref_value = "localized_text" }
+ },
+ calc_function = function(card)
+ local chips, mult = 0, 0
+ local face = 0
+ local text, _, scoring_hand = JokerDisplay.evaluate_hand()
+ if text ~= 'Unknown' then
+ for _, scoring_card in pairs(scoring_hand) do
+ if scoring_card:is_face() then
+ local retriggers = JokerDisplay.calculate_card_triggers(scoring_card, scoring_hand)
+ face = face + 1
+ chips = chips + card.ability.extra.chips * retriggers
+ mult = mult + card.ability.extra.mult * retriggers
+ end
+ end
+ end
+ card.joker_display_values.mult = mult * face
+ card.joker_display_values.chips = chips * face
+ card.joker_display_values.localized_text = localize("k_face_cards")
+ end
+ }
+ end
+}
+
+-- See localization/en-us.lua to create joker text
\ No newline at end of file
diff --git a/mod/localization/en-us.lua b/mod/localization/en-us.lua
new file mode 100644
index 0000000..99ae859
--- /dev/null
+++ b/mod/localization/en-us.lua
@@ -0,0 +1,189 @@
+return {
+ ["misc"] = {
+ ["dictionary"] = {
+ ["k_fusion"] = "Fusion",
+ ["k_fuse_fusion"] = "Fusion",
+ ["k_flipped_ex"] = "Flipped!",
+ ["k_copied_ex"] = "Cloned!",
+ ["k_in_tact_ex"] = "In-Tact!",
+ ["b_fuse"] = "FUSE",
+ },
+ ["labels"] = {
+ ["k_fuse_fusion"] = "Fusion",
+ },
+ },
+ ["descriptions"] = {
+ ["Joker"] = {
+ ["j_fuse_diamond_bard"] = {
+ ["name"] = "Diamond Bard",
+ ["text"] = {
+ "Played cards with {C:diamonds}Diamond{} suit give",
+ "{C:money}$#1#{}, as well as {C:mult}+#2#{} Mult for every ",
+ "{C:money}$#3#{} you have when scored",
+ "{C:inactive}(#4# + #5#)",
+ },
+ },
+ ["j_fuse_heart_paladin"] = {
+ ["name"] = "Heart Paladin",
+ ["text"] = {
+ "Played cards with {C:hearts}Heart{} suit give",
+ "{X:mult,C:white}X#1#{} Mult when scored.",
+ "{C:green}#2# in #3#{} chance to re-trigger",
+ "{C:inactive}(#4# + #5#)",
+ },
+ },
+ ["j_fuse_spade_archer"] = {
+ ["name"] = "Spade Archer",
+ ["text"] = {
+ "Played cards with {C:spades}Spade{} suit give",
+ "{C:chips}+#1#{} Chips when scored. Gains {C:chips}+#2#{} ",
+ "chips when 5 or more {C:spades}Spades{} are played",
+ "{C:inactive}(#3# + #4#)",
+ },
+ },
+ ["j_fuse_club_wizard"] = {
+ ["name"] = "Club Wizard",
+ ["text"] = {
+ "Played cards with {C:clubs}Club{} suit",
+ "give {C:mult}+#1#{} Mult when scored",
+ "{C:inactive}(#2# + #3#)",
+ },
+ },
+ ["j_fuse_big_bang"] = {
+ ["name"] = "Big Bang",
+ ["text"] = {
+ "{X:mult,C:white} X#1# {} Mult per the number",
+ "of times {C:attention}poker hand{} has been played",
+ "plus the level of the {C:attention}poker hand{}.",
+ "{C:inactive}(#2# + #3#)",
+ },
+ },
+ ["j_fuse_dynamic_duo"] = {
+ ["name"] = "Dynamic Duo",
+ ["text"] = {
+ "Played {C:attention}number{} cards give {C:mult}+#1#{} Mult ",
+ "and {C:chips}+#2#{} Chips when scored.",
+ "{C:inactive}(#3# + #4#)",
+ },
+ },
+ ["j_fuse_collectible_chaos_card"] = {
+ ["name"] = "Collectible Chaos Card",
+ ["text"] = {
+ "{C:mult}+#1#{} Mult per {C:attention}reroll{} in the shop.",
+ "{C:attention}#2#{} free {C:green}Reroll{} per shop",
+ "{C:inactive}(Currently {C:mult}+#3#{C:inactive} Mult)",
+ "{C:inactive}(#4# + #5#)",
+ },
+ },
+ ["j_fuse_flip_flop"] = {
+ ["name"] = "Flip-Flop",
+ ["text"] = {
+ "{C:attention}+#1#{} hand size. {C:red}+#2#{} Mult",
+ "{C:attention}Flips{} after each blind",
+ "{C:inactive}(#3# + #4#)",
+ },
+ },
+ ["j_fuse_flip_flop_mult"] = {
+ ["name"] = "Flip-Flop",
+ ["text"] = {
+ "{C:attention}+#1#{} hand size. {C:red}+#2#{} Mult",
+ "{C:attention}Flips{} after each blind",
+ "{C:inactive}(#3# + #4#)",
+ },
+ },
+ ["j_fuse_flip_flop_chips"] = {
+ ["name"] = "Flip-Flop",
+ ["text"] = {
+ "{C:red}+#1#{} discard. {C:chips}+#2#{} Chips",
+ "{C:attention}Flips{} after each blind",
+ "{C:inactive}(#3# + #4#)",
+ },
+ },
+ ["j_fuse_royal_decree"] = {
+ ["name"] = "Royal Decree",
+ ["text"] = {
+ "Played {C:attention}face{} cards give {C:money}$#1#{} when scored.",
+ "Each {C:attention}face{} card held in hand",
+ "at end of round gives {C:money}$#1#{}",
+ "{C:inactive}(#2# + #3#)",
+ },
+ },
+ ["j_fuse_dementia_joker"] = {
+ ["name"] = "Dementia Joker",
+ ["text"] = {
+ "{C:mult}+#1#{} Mult for each {C:attention}Joker{} card.",
+ "{C:green}#2# in #3#{} chance to {C:attention}clone{} if ",
+ "not {C:dark_edition}Negative{} after you beat a blind",
+ "{C:inactive}(Currently {C:mult}+#4#{C:inactive} Mult)",
+ "{C:inactive}(#5# + #6#)",
+ },
+ },
+ ["j_fuse_golden_egg"] = {
+ ["name"] = "Golden Egg",
+ ["text"] = {
+ "Gains {C:money}$#1#{} of {C:attention}sell value{}",
+ " at end of round.",
+ " Earn {C:money}$#1#{} at end of round",
+ "{C:inactive}(#2# + #3#)",
+ },
+ },
+ ["j_fuse_flag_bearer"] = {
+ ["name"] = "Flag Bearer",
+ ["text"] = {
+ "{C:mult}+#1#{} Mult per hand played, {C:mult}-#2#{} Mult",
+ "per discard. Mult is multiplied by",
+ " remaining {C:attention}discards{}",
+ "{C:inactive}(Currently {C:mult}+#3#{C:inactive} Mult)",
+ "{C:inactive}(#4# + #5#)",
+ },
+ },
+ ["j_fuse_uncanny_face"] = {
+ ["name"] = "Uncanny Face",
+ ["text"] = {
+ "Played {C:attention}face{} cards give {C:chips}+#1#{} Chips and",
+ "{C:mult}+#2#{} Mult for every {C:attention}face{} card",
+ " in the scoring hand",
+ "{C:inactive}(#3# + #4#)",
+ },
+ },
+ ["j_fuse_commercial_driver"] = {
+ ["name"] = "Commercial Driver",
+ ["text"] = {
+ "{X:mult,C:white} X#1# {} Mult per consecutive hand",
+ "played with a scoring {C:attention}enhanced{} card",
+ "{C:inactive}(Currently {X:mult,C:white}X#2#{C:inactive} Mult)",
+ "{C:inactive}(#3# + #4#)",
+ },
+ },
+ ["j_fuse_camping_trip"] = {
+ ["name"] = "Camping Trip",
+ ["text"] = {
+ "Played {C:attention}cards{} permanently gains",
+ "{C:chips}+#1#{} Chips when scored",
+ "({C:chips}+#2#{} on the final hand)",
+ "Your final hand triggers twice",
+ "{C:inactive}(#3# + #4#)",
+ },
+ },
+ ["j_fuse_star_oracle"] = {
+ ["name"] = "Star Oracle",
+ ["text"] = {
+ "{C:attention}+2{} consumable slots.",
+ "{C:green}#1# in #2#{} chance for played cards",
+ " with {C:stars}Star{} suit to create a",
+ "random {C:spectral}Spectral{} card when scored",
+ "{C:inactive}(#3# + #4#)",
+ },
+ },
+ ["j_fuse_moon_marauder"] = {
+ ["name"] = "Moon Marauder",
+ ["text"] = {
+ "{C:green}#1# in #2#{} chance for played cards with",
+ "{C:moons}Moon{} suit to become {C:attention}Glass{} Cards.",
+ "played {C:moons}Moon{} {C:attention}Glass{} cards never shatter",
+ "{C:inactive}(#3# + #4#)",
+ },
+ },
+ },
+ },
+}
\ No newline at end of file
diff --git a/mod/lsp_defs.lua b/mod/lsp_defs.lua
new file mode 100644
index 0000000..b0c01bb
--- /dev/null
+++ b/mod/lsp_defs.lua
@@ -0,0 +1,35 @@
+---@meta
+
+---@class FusionIngredient
+---@field name string Key of the ingredient joker
+---@field carry_stat? string Name of the stat to be carried over (whether it is in an `extra` table will be detected automatically)
+---@field merge_stat? string Name of the stat to be merged (as `carry_stat`); all `merge_stat` are added together.
+
+---@class FusionRecipe
+---@field jokers FusionIngredient[]
+---@field result_joker string Key of the Joker to be produced
+---@field cost number Cost in dollars to perform this fusion
+---@field merged_stat? string Key of the stat in which to place any `merge_stat` values, if present
+---@field requirement? fun():boolean Must return `true` to perform this fusion (in addition to having the ingredients and money)
+---@field aftermath? fun():nil Will be run after the Jokers are fused
+
+---Register a fusion recipe
+---@param t FusionRecipe
+function FusionJokers.fusions:register_fusion(t)
+end
+
+---Original fusion registry function, now deprecated. You can use [this regex](https://regex101.com/r/msZHKS/2/substitution) to convert it and avoid warning messages.
+---@param joker1 string Key of the first Joker to fuse
+---@param carry_stat1 string|nil Name of the stat to carry, if any
+---@param extra1 nil No longer used
+---@param joker2 string Key of the second Joker to fuse
+---@param carry_stat2 string|nil Name of the stat to carry, if any
+---@param extra2 nil No longer used
+---@param result_joker string Key of the output Joker
+---@param cost number Cost in dollars to perform this fusion
+---@param merged_stat string|nil Name of the stat in which to place `merge_stat`s
+---@param merge_stat1 string|nil Name of the stat to merge from Joker 1
+---@param merge_stat2 string|nil ... and from Joker 2
+---@deprecated Please use `register_fusion` instead
+function FusionJokers.fusions:add_fusion(joker1, carry_stat1, extra1, joker2, carry_stat2, extra2, result_joker, cost, merged_stat, merge_stat1, merge_stat2)
+end
\ No newline at end of file