9550 lines
265 KiB
Lua
9550 lines
265 KiB
Lua
local unstb = SMODS.current_mod
|
|
local filesystem = NFS or love.filesystem
|
|
local path = unstb.path
|
|
local unstb_config = unstb.config
|
|
|
|
--Global Table
|
|
unstb_global = {}
|
|
unstb_global.config = unstb.config
|
|
|
|
-- Debug message
|
|
local function print(message)
|
|
sendDebugMessage('[UnStable] - '..(tostring(message) or '???'))
|
|
end
|
|
|
|
print("Starting Unstable")
|
|
|
|
--Initialize All Colors
|
|
G.C.UNSTB_AUX = HEX('00a669')
|
|
|
|
--Localization Colors
|
|
--Properly hook into the function, so it does not error
|
|
local ref_loc_colour = loc_colour
|
|
|
|
function loc_colour(_c, default)
|
|
if not G.ARGS.LOC_COLOURS then
|
|
ref_loc_colour(_c, default)
|
|
elseif not G.ARGS.LOC_COLOURS.unstb_colour then --Init UNSTB's exclusive color
|
|
G.ARGS.LOC_COLOURS.unstb_colour = true
|
|
|
|
G.ARGS.LOC_COLOURS['auxiliary'] = G.C.UNSTB_AUX
|
|
end
|
|
|
|
return ref_loc_colour(_c, default)
|
|
end
|
|
|
|
--Description page formatting
|
|
unstb.description_loc_vars = function()
|
|
return { background_colour = G.C.CLEAR, text_colour = G.C.WHITE, scale = 1.2 }
|
|
end
|
|
|
|
--Config Stuff
|
|
|
|
function unstb.save_config(self)
|
|
SMODS.save_mod_config(self)
|
|
end
|
|
|
|
local unstb_config_tab = function()
|
|
return{
|
|
{
|
|
label = localize("unstb_config_header_mech_setting"),
|
|
chosen = true,
|
|
tab_definition_function = function()
|
|
return {
|
|
n = G.UIT.ROOT,
|
|
config = {
|
|
emboss = 0.05,
|
|
minh = 6,
|
|
r = 0.1,
|
|
minw = 10,
|
|
align = "cm",
|
|
padding = 0.2,
|
|
colour = G.C.BLACK,
|
|
},
|
|
nodes = {
|
|
|
|
{n=G.UIT.R, config={align = "cm"}, nodes={
|
|
|
|
{n=G.UIT.R, config={align = "cm"}, nodes={{n = G.UIT.T, config = {text = localize("unstb_config_requires_restart"), colour = G.C.RED, scale = 0.4}}}},
|
|
}},
|
|
|
|
{n=G.UIT.R, config={align = "cm"}, nodes={ --Base Box containing everything
|
|
|
|
-- Left Side Column
|
|
{n=G.UIT.C, config={align = "cl", padding = 0.2}, nodes={
|
|
{n=G.UIT.R, config={align = "cl"}, nodes={
|
|
|
|
{n=G.UIT.R, config={align = "cm"}, nodes={{n = G.UIT.T, config = {text = localize("unstb_config_header_rank"), colour = G.C.ORANGE, scale = 0.5}}}},
|
|
create_toggle({label = localize("unstb_config_rank21"), ref_table = unstb.config.rank, ref_value = 'rank_21', callback = function() unstb:save_config() end}),
|
|
create_toggle({label = localize("unstb_config_rank_bi"), ref_table = unstb.config.rank, ref_value = 'rank_binary', callback = function() unstb:save_config() end}),
|
|
create_toggle({label = localize("unstb_config_rank_decimal"), ref_table = unstb.config.rank, ref_value = 'rank_decimal', callback = function() unstb:save_config() end}),
|
|
|
|
}},
|
|
|
|
{n=G.UIT.R, config={align = "cl"}, nodes={
|
|
|
|
{n=G.UIT.R, config={align = "cm"}, nodes={{n = G.UIT.T, config = {text = localize("unstb_config_header_enh"), colour = G.C.ORANGE, scale = 0.5}}}},
|
|
create_toggle({label = localize("unstb_config_enh_custom"), ref_table = unstb.config.enh, ref_value = 'enh_custom', callback = function() unstb:save_config() end}),
|
|
create_toggle({label = localize("unstb_config_enh_disenh"), ref_table = unstb.config.enh, ref_value = 'enh_disenh', callback = function() unstb:save_config() end}),
|
|
|
|
}}
|
|
}},
|
|
|
|
-- Right Side Column
|
|
{n=G.UIT.C, config={align = "cl"}, nodes={
|
|
|
|
{n=G.UIT.R, config={align = "cl"}, nodes={
|
|
|
|
{n=G.UIT.R, config={align = "cm"}, nodes={{n = G.UIT.T, config = {text = localize("unstb_config_header_mechanics"), colour = G.C.ORANGE, scale = 0.5}}}},
|
|
create_toggle({label = localize("unstb_config_mech_upgrade"), ref_table = unstb.config.gameplay, ref_value = 'edition_upgrade', callback = function() unstb:save_config() end}),
|
|
create_toggle({label = localize("unstb_config_mech_suitseal"), ref_table = unstb.config.gameplay, ref_value = 'seal_suit', callback = function() unstb:save_config() end}),
|
|
create_toggle({label = localize("unstb_config_mech_aux"), ref_table = unstb.config.gameplay, ref_value = 'c_aux', callback = function() unstb:save_config() end}),
|
|
create_toggle({label = localize("unstb_config_mech_music"), ref_table = unstb.config.gameplay, ref_value = 'music', callback = function() unstb:save_config() end}),
|
|
create_toggle({label = localize("unstb_config_mech_fallback"), info = localize("unstb_config_mech_fallback_desc"), ref_table = unstb.config.gameplay, ref_value = 'c_rebundant', callback = function() unstb:save_config() end}),
|
|
create_toggle({label = localize("unstb_config_mech_new_spectral"), ref_table = unstb.config.gameplay, ref_value = 'new_spectrals', callback = function() unstb:save_config() end}),
|
|
|
|
}},
|
|
}},
|
|
|
|
}}
|
|
},
|
|
}
|
|
end
|
|
},
|
|
|
|
{ --Reserved Tab, in case the settings are expended in the future
|
|
label = localize("unstb_config_header_joker_settings"),
|
|
tab_definition_function = function()
|
|
return {
|
|
n = G.UIT.ROOT,
|
|
config = {
|
|
emboss = 0.05,
|
|
minh = 6,
|
|
r = 0.1,
|
|
minw = 10,
|
|
align = "cm",
|
|
padding = 0.2,
|
|
colour = G.C.BLACK,
|
|
},
|
|
nodes = {
|
|
|
|
{n=G.UIT.R, config={align = "cm"}, nodes={
|
|
|
|
{n=G.UIT.R, config={align = "cm"}, nodes={{n = G.UIT.T, config = {text = localize("unstb_config_requires_restart"), colour = G.C.RED, scale = 0.4}}}},
|
|
}},
|
|
|
|
{n=G.UIT.R, config={align = "cm"}, nodes={ --Base Box containing everything
|
|
|
|
-- Right Side Column
|
|
{n=G.UIT.C, config={align = "cl"}, nodes={
|
|
|
|
{n=G.UIT.R, config={align = "cl"}, nodes={
|
|
|
|
{n=G.UIT.R, config={align = "cm"}, nodes={{n = G.UIT.T, config = {text = "Joker", colour = G.C.ORANGE, scale = 0.5}}}},
|
|
create_toggle({label = 'Vanilla Joker Overrides', info = {'Re-coded Vanilla Jokers to work with new features'}, ref_table = unstb.config.joker, ref_value = 'vanilla', callback = function() unstb:save_config() end}),
|
|
create_toggle({label = 'Shitpost Jokers', ref_table = unstb.config.joker, ref_value = 'shitpost', callback = function() unstb:save_config() end}),
|
|
create_toggle({label = 'Major Gameplay-Altering Jokers', info = {'Jokers that may alters the playstyle drastically'}, ref_table = unstb.config.joker, ref_value = 'alter', callback = function() unstb:save_config() end}),
|
|
create_toggle({label = 'Powerful Jokers', info = {'Jokers that is significantly powerful than base game'}, ref_table = unstb.config.joker, ref_value = 'powerful', callback = function() unstb:save_config() end}),
|
|
}}
|
|
}},
|
|
|
|
}}
|
|
|
|
},
|
|
|
|
|
|
}
|
|
end
|
|
}
|
|
}
|
|
end
|
|
|
|
unstb.extra_tabs = unstb_config_tab
|
|
|
|
--Just so the gear icon shows up
|
|
unstb.config_tab = true
|
|
|
|
--Map config value with a single string keyword
|
|
local config_value = {
|
|
["rank_21"] = unstb_config.rank.rank_21,
|
|
["rank_binary"] = unstb_config.rank.rank_binary,
|
|
["rank_decimal"] = unstb_config.rank.rank_decimal,
|
|
|
|
["enh_custom"] = unstb_config.enh.enh_custom,
|
|
["enh_disenh"] = unstb_config.enh.enh_disenh,
|
|
|
|
["edition_upgrade"] = unstb_config.gameplay.edition_upgrade,
|
|
["seal_suit"] = unstb_config.gameplay.seal_suit,
|
|
["c_aux"] = unstb_config.gameplay.c_aux,
|
|
["music"] = unstb_config.gameplay.music,
|
|
["c_rebundant"] = unstb_config.gameplay.c_rebundant,
|
|
["new_spectrals"] = unstb_config.gameplay.new_spectrals,
|
|
|
|
["j_vanilla"] = unstb_config.joker.vanilla,
|
|
["j_shitpost"] = unstb_config.joker.shitpost,
|
|
["j_alter"] = unstb_config.joker.alter,
|
|
["j_powerful"] = unstb_config.joker.powerful,
|
|
}
|
|
|
|
--Inclusion Check by a list of keyword
|
|
local function check_enable_taglist(taglist)
|
|
local isAdded = true
|
|
for _, v in ipairs(taglist) do
|
|
isAdded = isAdded and config_value[v]
|
|
end
|
|
return isAdded
|
|
end
|
|
|
|
--Talisman Compatibility
|
|
to_big = to_big or function(num)
|
|
return num
|
|
end
|
|
|
|
-- Index-based coordinates generation
|
|
|
|
local function get_coordinates(position, width)
|
|
if width == nil then width = 10 end -- 10 is default for Jokers
|
|
return {x = (position) % width, y = math.floor((position) / width)}
|
|
end
|
|
|
|
--Mod Icon
|
|
SMODS.Atlas {
|
|
-- Key for code to find it with
|
|
key = "modicon",
|
|
-- The name of the file, for the code to pull the atlas from
|
|
path = "modicon.png",
|
|
-- Width of each sprite in 1x size
|
|
px = 32,
|
|
-- Height of each sprite in 1x size
|
|
py = 32
|
|
}
|
|
|
|
--Creates an atlas for Jokers to use
|
|
SMODS.Atlas {
|
|
-- Key for code to find it with
|
|
key = "unstb_jokers",
|
|
-- The name of the file, for the code to pull the atlas from
|
|
path = "jokers.png",
|
|
-- Width of each sprite in 1x size
|
|
px = 71,
|
|
-- Height of each sprite in 1x size
|
|
py = 95
|
|
}
|
|
|
|
--Atlas for special Jokers (multi-face, dynamic graphic, etc)
|
|
SMODS.Atlas {
|
|
-- Key for code to find it with
|
|
key = "unstb_jokers_ex",
|
|
-- The name of the file, for the code to pull the atlas from
|
|
path = "jokers_ex.png",
|
|
-- Width of each sprite in 1x size
|
|
px = 71,
|
|
-- Height of each sprite in 1x size
|
|
py = 95
|
|
}
|
|
|
|
SMODS.Atlas {
|
|
-- Key for code to find it with
|
|
key = "unstb_jokers_wip",
|
|
-- The name of the file, for the code to pull the atlas from
|
|
path = "jokers_wip.png",
|
|
-- Width of each sprite in 1x size
|
|
px = 71,
|
|
-- Height of each sprite in 1x size
|
|
py = 95
|
|
}
|
|
|
|
--Atlas for new enhancements
|
|
|
|
SMODS.Atlas {
|
|
-- Key for code to find it with
|
|
key = "unstb_back",
|
|
-- The name of the file, for the code to pull the atlas from
|
|
path = "back.png",
|
|
-- Width of each sprite in 1x size
|
|
px = 71,
|
|
-- Height of each sprite in 1x size
|
|
py = 95
|
|
}
|
|
|
|
SMODS.Atlas {
|
|
-- Key for code to find it with
|
|
key = "enh_slop",
|
|
-- The name of the file, for the code to pull the atlas from
|
|
path = "enh_slop.png",
|
|
-- Width of each sprite in 1x size
|
|
px = 71,
|
|
-- Height of each sprite in 1x size
|
|
py = 95
|
|
}
|
|
|
|
SMODS.Atlas {
|
|
-- Key for code to find it with
|
|
key = "enh_slop_hc",
|
|
-- The name of the file, for the code to pull the atlas from
|
|
path = "enh_slop_hc.png",
|
|
-- Width of each sprite in 1x size
|
|
px = 71,
|
|
-- Height of each sprite in 1x size
|
|
py = 95
|
|
}
|
|
|
|
SMODS.Atlas {
|
|
-- Key for code to find it with
|
|
key = "enh_resource",
|
|
-- The name of the file, for the code to pull the atlas from
|
|
path = "enh_res.png",
|
|
-- Width of each sprite in 1x size
|
|
px = 71,
|
|
-- Height of each sprite in 1x size
|
|
py = 95
|
|
}
|
|
|
|
--Atlas for Suit Seals
|
|
SMODS.Atlas {
|
|
-- Key for code to find it with
|
|
key = "suit_seal",
|
|
-- The name of the file, for the code to pull the atlas from
|
|
path = "suit_seal.png",
|
|
-- Width of each sprite in 1x size
|
|
px = 71,
|
|
-- Height of each sprite in 1x size
|
|
py = 95
|
|
}
|
|
|
|
--Atlas for Booster Pack
|
|
SMODS.Atlas {
|
|
-- Key for code to find it with
|
|
key = "booster",
|
|
-- The name of the file, for the code to pull the atlas from
|
|
path = "booster.png",
|
|
-- Width of each sprite in 1x size
|
|
px = 71,
|
|
-- Height of each sprite in 1x size
|
|
py = 95
|
|
}
|
|
|
|
--Atlas for Auxiliary Cards
|
|
|
|
SMODS.Atlas {
|
|
-- Key for code to find it with
|
|
key = "auxiliary_undiscovered",
|
|
-- The name of the file, for the code to pull the atlas from
|
|
path = "auxiliary_undiscovered.png",
|
|
-- Width of each sprite in 1x size
|
|
px = 71,
|
|
-- Height of each sprite in 1x size
|
|
py = 95
|
|
}
|
|
|
|
SMODS.Atlas {
|
|
-- Key for code to find it with
|
|
key = "auxiliary",
|
|
-- The name of the file, for the code to pull the atlas from
|
|
path = "auxiliary.png",
|
|
-- Width of each sprite in 1x size
|
|
px = 71,
|
|
-- Height of each sprite in 1x size
|
|
py = 95
|
|
}
|
|
|
|
--Atlas for Other Consumable Cards
|
|
|
|
--Tarot
|
|
SMODS.Atlas {
|
|
-- Key for code to find it with
|
|
key = "tarot",
|
|
-- The name of the file, for the code to pull the atlas from
|
|
path = "tarot.png",
|
|
-- Width of each sprite in 1x size
|
|
px = 71,
|
|
-- Height of each sprite in 1x size
|
|
py = 95
|
|
}
|
|
|
|
|
|
--Spectral
|
|
SMODS.Atlas {
|
|
-- Key for code to find it with
|
|
key = "spectral",
|
|
-- The name of the file, for the code to pull the atlas from
|
|
path = "spectral.png",
|
|
-- Width of each sprite in 1x size
|
|
px = 71,
|
|
-- Height of each sprite in 1x size
|
|
py = 95
|
|
}
|
|
|
|
--Atlas for Vouchers
|
|
SMODS.Atlas {
|
|
-- Key for code to find it with
|
|
key = "voucher",
|
|
-- The name of the file, for the code to pull the atlas from
|
|
path = "voucher.png",
|
|
-- Width of each sprite in 1x size
|
|
px = 71,
|
|
-- Height of each sprite in 1x size
|
|
py = 95
|
|
}
|
|
|
|
--Atlas for Decks
|
|
SMODS.Atlas {
|
|
-- Key for code to find it with
|
|
key = "deck",
|
|
-- The name of the file, for the code to pull the atlas from
|
|
path = "deck.png",
|
|
-- Width of each sprite in 1x size
|
|
px = 71,
|
|
-- Height of each sprite in 1x size
|
|
py = 95
|
|
}
|
|
|
|
--Atlas for extra ranks
|
|
SMODS.Atlas {
|
|
-- Key for code to find it with
|
|
key = "rank_ex",
|
|
-- The name of the file, for the code to pull the atlas from
|
|
path = "rank_ex.png",
|
|
-- Width of each sprite in 1x size
|
|
px = 71,
|
|
-- Height of each sprite in 1x size
|
|
py = 95
|
|
}
|
|
|
|
SMODS.Atlas {
|
|
-- Key for code to find it with
|
|
key = "rank_ex2",
|
|
-- The name of the file, for the code to pull the atlas from
|
|
path = "rank_ex2.png",
|
|
-- Width of each sprite in 1x size
|
|
px = 71,
|
|
-- Height of each sprite in 1x size
|
|
py = 95
|
|
}
|
|
|
|
SMODS.Atlas {
|
|
-- Key for code to find it with
|
|
key = "rank_ex_hc",
|
|
-- The name of the file, for the code to pull the atlas from
|
|
path = "rank_ex_hc.png",
|
|
-- Width of each sprite in 1x size
|
|
px = 71,
|
|
-- Height of each sprite in 1x size
|
|
py = 95
|
|
}
|
|
|
|
SMODS.Atlas {
|
|
-- Key for code to find it with
|
|
key = "rank_ex2_hc",
|
|
-- The name of the file, for the code to pull the atlas from
|
|
path = "rank_ex2_hc.png",
|
|
-- Width of each sprite in 1x size
|
|
px = 71,
|
|
-- Height of each sprite in 1x size
|
|
py = 95
|
|
}
|
|
|
|
|
|
--Music
|
|
|
|
local aux_music_enable = unstb_config.gameplay.music
|
|
|
|
SMODS.Sound({
|
|
key = "music_aux",
|
|
path = "music_aux.ogg",
|
|
select_music_track = function()
|
|
return aux_music_enable
|
|
and ( G.pack_cards and G.pack_cards.cards and G.pack_cards.cards[1] and G.pack_cards.cards[1].ability.set == "Auxiliary")
|
|
end,
|
|
})
|
|
|
|
--SFXs
|
|
|
|
SMODS.Sound({key = 'heal', path = 'heal.ogg'})
|
|
SMODS.Sound({key = 'poison', path = 'poison.ogg'})
|
|
|
|
|
|
--Jokers
|
|
--filesystem.load(unstb.path..'joker\\joker.lua')()
|
|
|
|
--Utility
|
|
|
|
--Check if table value already exists in the List
|
|
local function table_has_value(list, value)
|
|
for i, v in ipairs(list) do
|
|
if v==value then
|
|
return true
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
|
|
--Expose this function so I can use this in global scope
|
|
unstb_global.table_has_value = table_has_value
|
|
|
|
--Auto event scheduler, based on Bunco
|
|
local function event(config)
|
|
local e = Event(config)
|
|
G.E_MANAGER:add_event(e)
|
|
return e
|
|
end
|
|
|
|
local function big_juice(card)
|
|
card:juice_up(0.7)
|
|
end
|
|
|
|
local function extra_juice(card)
|
|
card:juice_up(0.6, 0.1)
|
|
end
|
|
|
|
local function play_nope_sound()
|
|
--Copied from Wheel of Fortune lol
|
|
event({trigger = 'after', delay = 0.06*G.SETTINGS.GAMESPEED, blockable = false, blocking = false, func = function()
|
|
play_sound('tarot2', 0.76, 0.4);return true end})
|
|
play_sound('tarot2', 1, 0.4)
|
|
end
|
|
|
|
local function forced_message(message, card, color, delay, juice)
|
|
if delay == true then
|
|
delay = 0.7 * 1.25
|
|
elseif delay == nil then
|
|
delay = 0
|
|
end
|
|
|
|
event({trigger = 'before', delay = delay, func = function()
|
|
|
|
if juice then big_juice(juice) end
|
|
|
|
card_eval_status_text(
|
|
card,
|
|
'extra',
|
|
nil, nil, nil,
|
|
{message = message, colour = color, instant = true}
|
|
)
|
|
return true
|
|
end})
|
|
end
|
|
|
|
--Joker creation wrapper, based on Bunco
|
|
local function create_joker(joker)
|
|
|
|
--Check Joker's keyword tag, if the setting is turned off then don't add anything
|
|
local isAdded = true
|
|
if joker.gameplay_tag and type(joker.gameplay_tag) == 'table' then
|
|
for _, v in ipairs(joker.gameplay_tag) do
|
|
isAdded = check_enable_taglist(joker.gameplay_tag)
|
|
end
|
|
end
|
|
if not isAdded then return end
|
|
|
|
-- Sprite position
|
|
|
|
local width = 10 -- Width of the spritesheet (in Jokers)
|
|
|
|
-- Soul sprite
|
|
|
|
if joker.rarity == 'Legendary' then
|
|
joker.soul = get_coordinates(joker.id) -- Calculates coordinates based on the position variable
|
|
end
|
|
|
|
joker.position = get_coordinates(joker.id)
|
|
|
|
-- Sprite atlas
|
|
|
|
if joker.type == nil then
|
|
joker.atlas = 'unstb_jokers'
|
|
elseif joker.type == 'Banned' then
|
|
joker.atlas = 'unstb_jokers_banned'
|
|
end
|
|
|
|
if joker.rarity == 'Legendary' then
|
|
joker.atlas = 'unstb_jokers_legend'
|
|
end
|
|
|
|
--If the joker has ex property, used extra sheet
|
|
if joker.ex_art then
|
|
joker.atlas = 'unstb_jokers_ex'
|
|
end
|
|
|
|
--If the joker has no art, fallback to WIP sheet
|
|
if joker.no_art then
|
|
joker.atlas = 'unstb_jokers_wip'
|
|
end
|
|
|
|
-- Key generation from name
|
|
|
|
local key = string.gsub(string.lower(joker.name), '%s', '_') -- Removes spaces and uppercase letters
|
|
|
|
-- Rarity conversion
|
|
|
|
if joker.rarity == 'Common' then
|
|
joker.rarity = 1
|
|
elseif joker.rarity == 'Uncommon' then
|
|
joker.rarity = 2
|
|
elseif joker.rarity == 'Rare' then
|
|
joker.rarity = 3
|
|
elseif joker.rarity == 'Legendary' then
|
|
joker.rarity = 4
|
|
end
|
|
|
|
-- Config values
|
|
|
|
if joker.vars == nil then joker.vars = {} end
|
|
|
|
joker.config = {extra = {}}
|
|
|
|
for _, kv_pair in ipairs(joker.vars) do
|
|
-- kv_pair is {a = 1}
|
|
local k, v = next(kv_pair)
|
|
joker.config.extra[k] = v
|
|
end
|
|
|
|
-- Joker creation
|
|
SMODS.Joker{
|
|
name = joker.name,
|
|
key = key,
|
|
|
|
atlas = joker.atlas,
|
|
pos = joker.position,
|
|
soul_pos = joker.soul,
|
|
|
|
rarity = joker.rarity,
|
|
cost = joker.cost,
|
|
|
|
unlocked = true,
|
|
--check_for_unlock = joker.check_for_unlock,
|
|
--unlock_condition = joker.unlock_condition,
|
|
--discovered = true, --false,
|
|
|
|
blueprint_compat = joker.blueprint or false,
|
|
|
|
eternal_compat = (joker.eternal == nil) or joker.eternal,
|
|
|
|
perishable_compat = (joker.perishable == nil) or joker.perishable,
|
|
|
|
|
|
process_loc_text = joker.process_loc_text,
|
|
|
|
config = joker.custom_config or joker.config,
|
|
loc_vars = joker.custom_vars or function(self, info_queue, card)
|
|
|
|
-- Localization values
|
|
|
|
local vars = {}
|
|
|
|
for _, kv_pair in ipairs(joker.vars) do
|
|
-- kv_pair is {a = 1}
|
|
local k, v = next(kv_pair)
|
|
-- k is `a`, v is `1`
|
|
table.insert(vars, card.ability.extra[k])
|
|
end
|
|
|
|
return {vars = vars}
|
|
end,
|
|
|
|
calculate = joker.calculate,
|
|
update = joker.update,
|
|
remove_from_deck = joker.remove_from_deck,
|
|
add_to_deck = joker.add_to_deck,
|
|
|
|
set_ability = joker.set_ability,
|
|
set_sprites = joker.set_sprites,
|
|
load = joker.load,
|
|
|
|
calc_dollar_bonus = joker.calc_dollar_bonus,
|
|
|
|
in_pool = joker.custom_in_pool or pool,
|
|
|
|
effect = joker.effect
|
|
}
|
|
end
|
|
|
|
--New global function to get a random eligible suit and rank from the deck without rank-overrides enhancements getting in the way
|
|
--Code based on Castle from base game
|
|
function get_valid_card_from_deck(seed)
|
|
|
|
local res_suit = 'Spades'
|
|
local res_rank = '2'
|
|
|
|
local valid_cards = {}
|
|
for k, v in ipairs(G.playing_cards) do
|
|
if not v.config.center.replace_base_card then --Excludes all cards with replace_base_card enhancements
|
|
valid_cards[#valid_cards+1] = v
|
|
end
|
|
end
|
|
if valid_cards[1] then
|
|
local target_card = pseudorandom_element(valid_cards, pseudoseed(seed or 'validcard'..G.GAME.round_resets.ante))
|
|
|
|
res_suit = target_card.base.suit
|
|
res_rank = target_card.base.value
|
|
end
|
|
|
|
return {suit = res_suit, rank = res_rank}
|
|
end
|
|
|
|
--Black Jack Rank Calculation
|
|
local function blackJack_evalrank(hand, bustAmount)
|
|
--Black Jack-style total rank evaluation
|
|
|
|
bustAmount = bustAmount or 21
|
|
|
|
local aceCount = 0
|
|
local rank = 0
|
|
|
|
for i = 1, #hand do
|
|
local currentCard = hand[i]
|
|
if not (currentCard.config.center == G.P_CENTERS.m_stone or currentCard.config.center.no_rank) and not currentCard.debuff then
|
|
|
|
if currentCard.base.value ~= 'Ace' then
|
|
rank = rank + (SMODS.Ranks[currentCard.base.value].nominal or 0) --Supports modded ranks as well, just in case
|
|
else
|
|
aceCount = aceCount + 1
|
|
|
|
rank = rank + 11
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
--Handle Ace rank
|
|
while( aceCount > 0 )
|
|
do
|
|
|
|
if rank > bustAmount then
|
|
rank = rank - 10
|
|
end
|
|
|
|
aceCount = aceCount - 1
|
|
end
|
|
|
|
return rank
|
|
|
|
end
|
|
|
|
--"Upgrade" function, used on card
|
|
local function edition_upgrade(card)
|
|
local edition = (card.edition or {}).key
|
|
|
|
if not edition then
|
|
card:set_edition("e_foil", true, false)
|
|
elseif edition=="e_foil" then
|
|
card:set_edition("e_holo", true, false)
|
|
elseif edition=="e_holo" then
|
|
card:set_edition("e_polychrome", true, false)
|
|
end
|
|
end
|
|
|
|
--General Helper function for rank increment / decrement
|
|
|
|
--Insert "prev" property into SMODS.Ranks
|
|
function init_prev_rank_data()
|
|
print("Initialize Remaining Previous Rank Data")
|
|
for _, rank in pairs(SMODS.Ranks) do
|
|
|
|
--Initialize
|
|
--In case the rank table does not have prev existed
|
|
--Base rank and UNSTB one has them defined manually by default
|
|
if not rank.prev then
|
|
rank.prev = {}
|
|
end
|
|
|
|
next_rank_list = rank.next
|
|
|
|
for i=1, #next_rank_list do
|
|
local next_rank = SMODS.Ranks[next_rank_list[i]]
|
|
local prev = next_rank.prev or {}
|
|
|
|
if not table_has_value(prev, rank.key) then
|
|
table.insert(prev, rank.key)
|
|
next_rank.prev = prev
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
--Utility function to get the next rank by specified step, walked using the same algorithm as SMODS Implementation of Strength Tarot
|
|
--Negative Step is also ok
|
|
function get_next_x_rank(rank, step)
|
|
local currentRank = SMODS.Ranks[rank]
|
|
|
|
if not currentRank then
|
|
return 'unstb_???' --Fallback, if the rank is invalid then returning ??? rank card
|
|
end
|
|
|
|
local behavior
|
|
local new_rank
|
|
|
|
local mul = (step > 0 and 1) or -1
|
|
|
|
--Based on SMODS Current implementation of Strength
|
|
for i=mul, step, mul do
|
|
|
|
if mul > 0 then
|
|
behavior = currentRank.strength_effect or { fixed = 1, ignore = false, random = false }
|
|
else
|
|
behavior = currentRank.decrease_effect or { fixed = 1, ignore = false, random = false }
|
|
end
|
|
|
|
if behavior.ignore or not next(currentRank.next) then
|
|
return rank
|
|
elseif behavior.random then
|
|
-- TODO doesn't respect in_pool
|
|
if mul>0 then
|
|
new_rank = pseudorandom_element(currentRank.next, pseudoseed('nextrank'))
|
|
else
|
|
new_rank = pseudorandom_element(currentRank.prev, pseudoseed('prevrank'))
|
|
end
|
|
|
|
else
|
|
if mul>0 then
|
|
local ii = (behavior.fixed and currentRank.next[behavior.fixed]) and behavior.fixed or 1
|
|
new_rank = currentRank.next[ii]
|
|
else
|
|
local ii = (behavior.fixed and currentRank.prev[behavior.fixed]) and behavior.fixed or 1
|
|
new_rank = currentRank.prev and currentRank.prev[ii] or currentRank.key
|
|
end
|
|
|
|
end
|
|
|
|
currentRank = SMODS.Ranks[new_rank]
|
|
--print(SMODS.Ranks[new_rank].key)
|
|
end
|
|
|
|
return new_rank or rank
|
|
|
|
end
|
|
|
|
--Face Seal
|
|
|
|
if unstb_config.gameplay.seal_suit then
|
|
|
|
SMODS.Seal({
|
|
key = "face",
|
|
atlas = "suit_seal",
|
|
|
|
pos = { x = 4, y = 0 },
|
|
badge_colour = HEX "f59c00",
|
|
shiny = true,
|
|
|
|
weight = 0,
|
|
config = {extra = {}},
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
return {vars = {}}
|
|
end,
|
|
--[[calculate = function(self, card, context)
|
|
|
|
end]]
|
|
|
|
--This cannot spawn naturally at all
|
|
in_pool = function(self, args)
|
|
return false
|
|
end
|
|
})
|
|
|
|
end
|
|
|
|
--Hook into is_face to account for Face Seal
|
|
local card_isfaceref = Card.is_face
|
|
|
|
function Card:is_face(from_boss)
|
|
if self.debuff and not from_boss then return end
|
|
|
|
if self.seal == 'unstb_face' then
|
|
return true
|
|
end
|
|
|
|
return card_isfaceref(self, from_boss)
|
|
end
|
|
|
|
--Suit Seals
|
|
|
|
--Global table for Suit Seals-related stuff
|
|
SuitSeal = {}
|
|
|
|
SuitSeal.suit_seal_colors = {
|
|
Spades = HEX "603de8",
|
|
Hearts = HEX "e83d61",
|
|
Clubs = HEX "19b8a1",
|
|
Diamonds = HEX "e8793d",
|
|
}
|
|
|
|
--External function to supports register more suits (especially modded) if needed
|
|
function SuitSeal.registerSealColor(suit, color)
|
|
SuitSeal.suit_seal_colors[suit] = HEX(color)
|
|
end
|
|
|
|
--Creating an actual SMODS Seal object
|
|
function SuitSeal.initSeal(suit, atlas, posX)
|
|
SMODS.Seal({
|
|
key = string.lower(suit),
|
|
atlas = atlas or "suit_seal",
|
|
|
|
--Extra field for suit seal only,
|
|
suit_seal = suit,
|
|
|
|
pos = { x = posX or 0, y = 0 },
|
|
badge_colour = SuitSeal.suit_seal_colors[suit],
|
|
weight = 0,
|
|
config = {extra = {}},
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
return {vars = {localize(self.suit_seal, 'suits_plural'), colours = {G.C.SUITS[self.suit_seal]}}}
|
|
end,
|
|
|
|
--This cannot spawn naturally at all
|
|
in_pool = function(self, args)
|
|
return false
|
|
end
|
|
})
|
|
end
|
|
|
|
local suit_seal_list = {"Spades", "Hearts", "Clubs", "Diamonds"}
|
|
|
|
--Global Suit Seal map from suit
|
|
unstb_global.SUIT_SEAL = {}
|
|
|
|
--TODO: A function wrapper that registers extra suit seal, corresponding auxillary card at the same time
|
|
--Might be a part of UnStableEX
|
|
|
|
if unstb_config.gameplay.seal_suit then
|
|
|
|
for i = 1, #suit_seal_list do
|
|
SuitSeal.initSeal(suit_seal_list[i], "suit_seal", i-1 )
|
|
|
|
unstb_global.SUIT_SEAL[suit_seal_list[i]] = {}
|
|
|
|
unstb_global.SUIT_SEAL[suit_seal_list[i]].seal_key = 'unstb_'..string.lower(suit_seal_list[i])
|
|
unstb_global.SUIT_SEAL[suit_seal_list[i]].aux_key = 'c_unstb_aux_'..string.lower(suit_seal_list[i])
|
|
end
|
|
|
|
end
|
|
|
|
--Heal Seal
|
|
|
|
function Card:heal(initial, delay_sprites)
|
|
local prev_center = self.config.prev_center or G.P_CENTERS.c_base
|
|
|
|
--Nullify hand xmult just in case
|
|
if self.ability.h_x_mult then
|
|
self.ability.h_x_mult = 0
|
|
end
|
|
|
|
self:set_ability(prev_center, initial, delay_sprites)
|
|
end
|
|
|
|
if unstb_config.enh.enh_disenh then
|
|
|
|
SMODS.Seal({
|
|
key = "heal",
|
|
atlas = "suit_seal",
|
|
|
|
pos = { x = 5, y = 0 },
|
|
badge_colour = HEX "7ce83d",
|
|
|
|
weight = 0,
|
|
config = {extra = {}},
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
info_queue[#info_queue+1] = {set = 'Other', key = 'disenhancement'}
|
|
return {vars = {}}
|
|
end,
|
|
calculate = function(self, card, context)
|
|
if context.cardarea == G.play and context.main_scoring then
|
|
|
|
local valid_cards = {}
|
|
for i = 1, #G.hand.cards do
|
|
if G.hand.cards[i].config.center.disenhancement and not G.hand.cards[i].healed then
|
|
valid_cards[#valid_cards+1] = G.hand.cards[i]
|
|
end
|
|
end
|
|
|
|
if valid_cards[1] then
|
|
local target_card = pseudorandom_element(valid_cards, pseudoseed('heal'..G.GAME.round_resets.ante))
|
|
--Set variable in advance because events are delayed
|
|
target_card.healed = true
|
|
|
|
--Nullify hand xmult in advance
|
|
if target_card.config.center == G.P_CENTERS.m_unstb_radioactive then
|
|
target_card.ability.h_x_mult = 0
|
|
end
|
|
|
|
event({func = function()
|
|
target_card:heal()
|
|
play_sound('unstb_heal', 1, 0.3)
|
|
target_card:juice_up()
|
|
target_card.healed = nil
|
|
return true
|
|
end
|
|
})
|
|
|
|
forced_message("Healed!", target_card, G.C.GREEN, true)
|
|
end
|
|
end
|
|
end,
|
|
|
|
--This cannot spawn naturally at all
|
|
in_pool = function(self, args)
|
|
return false
|
|
end
|
|
})
|
|
|
|
end
|
|
|
|
|
|
--New Enhancements
|
|
|
|
function get_valid_card_from_deck(seed)
|
|
|
|
local res_suit = 'Spades'
|
|
local res_rank = '2'
|
|
|
|
local valid_cards = {}
|
|
for k, v in ipairs(G.playing_cards) do
|
|
if not v.config.center.replace_base_card then --Excludes all cards with replace_base_card enhancements
|
|
valid_cards[#valid_cards+1] = v
|
|
end
|
|
end
|
|
if valid_cards[1] then
|
|
local target_card = pseudorandom_element(valid_cards, pseudoseed(seed or 'validcard'..G.GAME.round_resets.ante))
|
|
|
|
res_suit = target_card.base.suit
|
|
res_rank = target_card.base.value
|
|
end
|
|
|
|
return {suit = res_suit, rank = res_rank}
|
|
end
|
|
|
|
--Patch get_chip_bonus to allow total chip override
|
|
local cardGetChipBonusPointer = Card.get_chip_bonus
|
|
|
|
function Card:get_chip_bonus()
|
|
|
|
if self.config.center.override_chip then
|
|
return self.config.center.override_chip
|
|
end
|
|
|
|
return cardGetChipBonusPointer(self)
|
|
end
|
|
|
|
if unstb_config.enh.enh_custom then
|
|
|
|
--Acorn
|
|
SMODS.Enhancement {
|
|
key = "acorn",
|
|
atlas = "unstb_back",
|
|
pos = {x=0, y = 0},
|
|
|
|
replace_base_card = false,
|
|
no_suit = false,
|
|
no_rank = false,
|
|
always_scores = false,
|
|
override_chip = 0,
|
|
|
|
|
|
config = {extra = { totalchips = 0, originalchips = 0}},
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
return {
|
|
vars = { (card and (card.base.nominal + (card.ability.perma_bonus or 0)) *2) or 0 }
|
|
}
|
|
end,
|
|
|
|
|
|
|
|
--Override genere_ui so it does not display any chips
|
|
generate_ui = function(self, info_queue, card, desc_nodes, specific_vars, full_UI_table)
|
|
SMODS.Enhancement.super.generate_ui(self, info_queue, card, desc_nodes, specific_vars, full_UI_table)
|
|
end,
|
|
|
|
|
|
calculate = function(self, card, context)
|
|
if context.cardarea == G.play and context.main_scoring then
|
|
local rulesJoker = SMODS.find_card('j_unstb_rules_errata')
|
|
|
|
if next(rulesJoker) then
|
|
|
|
--Makes the Joker bounce when this card score
|
|
event({trigger = 'after', func = function()
|
|
big_juice(rulesJoker[1])
|
|
return true end })
|
|
|
|
return {
|
|
mult = card.base.nominal * 0.5,
|
|
}
|
|
|
|
else
|
|
event({trigger = 'after', delay = 0.05, func = function()
|
|
play_sound('tarot2', 1, 0.4);
|
|
return true end })
|
|
|
|
forced_message("Not Allowed!", card, G.C.RED, true)
|
|
end
|
|
end
|
|
|
|
if context.cardarea == G.hand and context.main_scoring then
|
|
card.ability.extra.totalchips = (card.base.nominal + (card.ability.perma_bonus or 0)) * 2
|
|
|
|
if not card.debuff then
|
|
--ret.unstb_h_chips = card.ability.extra.totalchips
|
|
return {
|
|
h_chips = card.ability.extra.totalchips
|
|
}
|
|
end
|
|
|
|
end
|
|
end
|
|
}
|
|
|
|
--Vintage
|
|
SMODS.Enhancement {
|
|
key = "vintage",
|
|
atlas = "unstb_back",
|
|
pos = {x=1, y = 0},
|
|
|
|
|
|
config = {extra = { bonus_chip = 0, chip_gain_rate = 10, current_odd = 0, odd_destroy = 15, destroy_rate = 1}},
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
|
|
local odds_current = 0
|
|
local destroy_rate = 1
|
|
|
|
if card then
|
|
odds_current = card.ability.extra.current_odd or 0
|
|
destroy_rate = card.ability.extra.destroy_rate
|
|
end
|
|
|
|
if G.GAME and G.GAME.probabilities.normal then
|
|
odds_current = odds_current * G.GAME.probabilities.normal
|
|
destroy_rate = destroy_rate * G.GAME.probabilities.normal
|
|
end
|
|
|
|
return {
|
|
vars = { self.config.extra.chip_gain_rate, odds_current, self.config.extra.odd_destroy, destroy_rate}
|
|
}
|
|
end,
|
|
|
|
|
|
|
|
|
|
calculate = function(self, card, context)
|
|
if context.cardarea == G.play and context.main_scoring then
|
|
card.ability.perma_bonus = (card.ability.perma_bonus or 0) + card.ability.extra.chip_gain_rate
|
|
card.ability.extra.current_odd = (card.ability.extra.current_odd or 0) + card.ability.extra.destroy_rate
|
|
|
|
forced_message("Upgrade!", card, G.C.CHIPS, true)
|
|
end
|
|
end,
|
|
|
|
after_play = function(self, card, context)
|
|
local isDestroy = pseudorandom('vintage'..G.SEED) < card.ability.extra.current_odd * G.GAME.probabilities.normal / card.ability.extra.odd_destroy
|
|
|
|
if isDestroy then
|
|
event({trigger = 'after', delay = 0.05, func = function()
|
|
play_sound('tarot2', 1, 0.4);
|
|
return true end })
|
|
|
|
forced_message("Torn...", card, G.C.BLACK, true)
|
|
return {
|
|
to_destroy = true
|
|
}
|
|
end
|
|
end,
|
|
}
|
|
|
|
--Promo
|
|
SMODS.Enhancement {
|
|
key = "promo",
|
|
atlas = "unstb_back",
|
|
pos = {x=2, y = 0},
|
|
|
|
replace_base_card = false,
|
|
no_suit = false,
|
|
no_rank = false,
|
|
always_scores = false,
|
|
|
|
config = {extra = { gold = 0, gold_rate = 1, odds_destroy = 8}},
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
return {
|
|
vars = { (card and card.ability and card.ability.extra.gold) or 0, self.config.extra.gold_rate, (G.GAME and G.GAME.probabilities.normal or 1), self.config.extra.odds_destroy }
|
|
}
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
if context.cardarea == G.play and context.main_scoring then
|
|
card.ability.extra.gold = (card.ability.extra.gold or 0) + card.ability.extra.gold_rate
|
|
forced_message("Upgrade!", card, G.C.GOLD, true)
|
|
end
|
|
|
|
if context.cardarea == G.hand and context.main_scoring then
|
|
if not card.debuff and card.ability.extra.gold>0 then
|
|
--ret.dollars = card.ability.extra.gold
|
|
return {
|
|
dollars = card.ability.extra.gold
|
|
}
|
|
end
|
|
end
|
|
|
|
end,
|
|
|
|
after_play = function(self, card, context)
|
|
--print("Trigger afterplay")
|
|
|
|
local isDestroy = pseudorandom('promo'..G.SEED) < G.GAME.probabilities.normal / card.ability.extra.odds_destroy
|
|
|
|
if isDestroy then
|
|
event({trigger = 'after', delay = 0.05, func = function()
|
|
play_sound('tarot2', 1, 0.4);
|
|
return true end })
|
|
|
|
forced_message("Sold", card, G.C.ORANGE, true)
|
|
return {
|
|
to_destroy = true
|
|
}
|
|
end
|
|
end,
|
|
}
|
|
|
|
--Slop
|
|
SMODS.Enhancement {
|
|
key = "slop",
|
|
|
|
lc_atlas = "enh_slop",
|
|
hc_atlas = "enh_slop_hc",
|
|
|
|
atlas = "enh_slop",
|
|
is_hc = false,
|
|
|
|
pos = {x=0, y = 0},
|
|
|
|
replace_base_card = true,
|
|
no_suit = false,
|
|
no_rank = false,
|
|
always_scores = true,
|
|
|
|
config = {extra = { suit = 'Spades', rank = '2', chips = 0}},
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
|
|
local suit_text = '(Suit)'
|
|
local suit_text_color = G.C.ORANGE
|
|
|
|
if card and card.ability then
|
|
suit_text = localize(card.ability.extra.suit, 'suits_plural');
|
|
suit_text_color = G.C.SUITS[card.ability.extra.suit]
|
|
end
|
|
|
|
return {
|
|
vars = { card and card.ability.extra.chips or 2, suit_text, localize(card and card.ability.extra.rank or '2', 'ranks') ,
|
|
colours = {suit_text_color} }
|
|
}
|
|
end,
|
|
|
|
|
|
|
|
suit_map = {
|
|
Hearts = 0,
|
|
Clubs = 1,
|
|
Diamonds = 2,
|
|
Spades = 3,
|
|
},
|
|
|
|
set_sprites = function(self, card, front)
|
|
local isCollection = (card.area and card.area.config.collection) or false
|
|
|
|
if not isCollection and card.ability and card.ability.extra then
|
|
local suit = (card.base and card.base.suit) or 'Spades'
|
|
|
|
local pos = get_coordinates( (self.suit_map[suit] or -1) +1 )
|
|
|
|
card.children.center:set_sprite_pos(pos)
|
|
end
|
|
|
|
end,
|
|
|
|
set_ability = function(self, card, initial, delay_sprites)
|
|
if card.base then
|
|
card.ability.extra.suit = card.base.suit or 'Hearts'
|
|
card.ability.extra.rank = card.base.value or '2'
|
|
card.ability.extra.chips = SMODS.Ranks[card.ability.extra.rank].nominal
|
|
end
|
|
end,
|
|
|
|
update = function(self, card)
|
|
|
|
--Jank, supporting for high contrast texture change settings
|
|
if G.SETTINGS.colourblind_option ~= card.atlasmode then
|
|
|
|
if G.SETTINGS.colourblind_option then
|
|
self.atlas = self.hc_atlas
|
|
else
|
|
self.atlas = self.lc_atlas
|
|
end
|
|
card.children.center.atlas = G.ASSET_ATLAS[self.atlas]
|
|
card.atlasmode = G.SETTINGS.colourblind_option
|
|
|
|
end
|
|
|
|
--Update the value for the 'wise' player who tries to change card value using tarots
|
|
if (card.VT.w <= 0) and card.base.suit and card.base.value then
|
|
local isCollection = (card.area and card.area.config.collection) or false
|
|
|
|
if not isCollection then
|
|
card.ability.extra.suit = card.base.suit or 'Hearts'
|
|
card.ability.extra.rank = card.base.value or '2'
|
|
card.ability.extra.chips = SMODS.Ranks[card.ability.extra.rank].nominal
|
|
|
|
local suit = (card.base and card.base.suit) or 'Spades'
|
|
local pos = get_coordinates( (self.suit_map[suit] or -1) +1 )
|
|
card.children.center:set_sprite_pos(pos)
|
|
end
|
|
end
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
if context.cardarea == G.play and context.main_scoring then
|
|
local scoredAmount = card.ability.extra.chips + card.ability.perma_bonus
|
|
--Store the current scoring hand, for after_play
|
|
--Had to check to not include itself and other Slop Cards so it won't have cyclic references
|
|
if not card.ability.extra.prevhand and context.scoring_hand then
|
|
local hand = {}
|
|
|
|
for i=1, #context.scoring_hand do
|
|
if context.scoring_hand[i] ~= card and not context.scoring_hand[i].config.center.replace_base_card then
|
|
hand[#hand+1] = {suit = context.scoring_hand[i].base.suit, rank = context.scoring_hand[i].base.value}
|
|
end
|
|
end
|
|
|
|
card.ability.extra.prevhand = hand
|
|
|
|
--print(inspectDepth(card.ability.extra.prevhand))
|
|
end
|
|
|
|
return {
|
|
chips = scoredAmount,
|
|
}
|
|
|
|
end
|
|
end,
|
|
|
|
after_play = function(self, card, context)
|
|
|
|
forced_message("Randomize!", card, G.C.RED, true)
|
|
|
|
event({trigger = 'after', delay = 0.05, func = function()
|
|
card.ability.extra.suit = pseudorandom_element(SMODS.Suits, pseudoseed('slop_card')..G.SEED).key
|
|
card.ability.extra.rank = pseudorandom_element(SMODS.Ranks, pseudoseed('slop_card')..G.SEED).key
|
|
|
|
local prompt_joker = SMODS.find_card('j_unstb_prompt')
|
|
|
|
if next(prompt_joker) then
|
|
|
|
if #card.ability.extra.prevhand>0 then
|
|
card.ability.extra.suit = pseudorandom_element(card.ability.extra.prevhand, pseudoseed('slop_card')..G.SEED).suit
|
|
card.ability.extra.rank = pseudorandom_element(card.ability.extra.prevhand, pseudoseed('slop_card')..G.SEED).rank
|
|
|
|
--Bounce the Joker a lil bit for the feedback effect
|
|
big_juice(prompt_joker[1])
|
|
end
|
|
|
|
end
|
|
|
|
--Clear the variable, unsure why this caused the game to crash when hovering on the deck if left uncleared
|
|
card.ability.extra.prevhand = nil
|
|
|
|
card.ability.extra.chips = SMODS.Ranks[card.base.value].nominal
|
|
|
|
local suit_data = SMODS.Suits[card.ability.extra.suit]
|
|
local suit_prefix = suit_data.card_key
|
|
|
|
local targetCard = suit_prefix .. '_' ..SMODS.Ranks[card.ability.extra.rank].card_key
|
|
|
|
--print(targetCard)
|
|
|
|
card:set_base(G.P_CARDS[targetCard])
|
|
|
|
local suit = (card.base and card.base.suit) or 'Spades'
|
|
local pos = get_coordinates( (self.suit_map[suit] or -1) +1 )
|
|
card.children.center:set_sprite_pos(pos)
|
|
|
|
return true end })
|
|
end,
|
|
|
|
--This cannot spawn naturally at all
|
|
in_pool = function(self, args)
|
|
return false
|
|
end
|
|
}
|
|
|
|
--Resource
|
|
SMODS.Enhancement {
|
|
key = "resource",
|
|
atlas = "enh_resource",
|
|
pos = {x=0, y = 0},
|
|
|
|
replace_base_card = true,
|
|
--no_suit = false,
|
|
no_rank = true,
|
|
always_scores = true,
|
|
|
|
config = {extra = { xmult = 5, suit = "undefined"} },
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
|
|
local suit_text = 'undefined'
|
|
local suit_text_color = {}
|
|
|
|
if card.ability then
|
|
suit_text = card.ability.extra.suit;
|
|
|
|
if suit_text ~= '(Corresponding Suit)' then
|
|
suit_text = localize(card.ability.extra.suit, 'suits_singular');
|
|
suit_text_color = G.C.SUITS[card.ability.extra.suit]
|
|
else
|
|
suit_text_color = G.C.ORANGE
|
|
end
|
|
end
|
|
|
|
return {
|
|
vars = { (card.ability and card.ability.extra.xmult) or 5, suit_text,
|
|
colours = {suit_text_color} }
|
|
}
|
|
end,
|
|
|
|
suit_map = {
|
|
Hearts = 0,
|
|
Clubs = 1,
|
|
Diamonds = 2,
|
|
Spades = 3,
|
|
},
|
|
|
|
|
|
|
|
set_sprites = function(self, card, front)
|
|
|
|
local isCollection = (card.area and card.area.config.collection) or false
|
|
|
|
if not isCollection and card.ability and card.ability.extra then
|
|
local suit = (card.base and card.base.suit) or 'Spades'
|
|
|
|
card.ability.extra.suit = suit
|
|
|
|
local pos = get_coordinates( (self.suit_map[suit] or -1) +2 )
|
|
|
|
card.children.center:set_sprite_pos(pos)
|
|
end
|
|
|
|
end,
|
|
|
|
update = function(self, card)
|
|
if (card.VT.w <= 0 or card.ability.extra.suit == 'undefined') then
|
|
local isCollection = (card.area and card.area.config.collection) or false
|
|
|
|
if not isCollection then
|
|
card.ability.extra.suit = card.base.suit
|
|
card.children.center:set_sprite_pos( get_coordinates( (self.suit_map[card.base.suit] or -1) +2 ) )
|
|
else
|
|
card.ability.extra.suit = "(Corresponding Suit)"
|
|
end
|
|
end
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
|
|
if context.cardarea == G.play and context.main_scoring then
|
|
local has_suit = false
|
|
|
|
if context.scoring_hand then
|
|
for i = 1, #context.scoring_hand do
|
|
local currentCard = context.scoring_hand[i]
|
|
if currentCard ~= card and currentCard.config.center ~= G.P_CENTERS.m_unstb_resource and currentCard:is_suit(card.ability.extra.suit) then
|
|
has_suit = true
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
if has_suit then
|
|
--[[event({trigger = 'after', func = function()
|
|
play_sound('multhit1')
|
|
return true end })]]
|
|
|
|
card.ability.extra.to_destroy = true
|
|
|
|
return {
|
|
xmult = card.ability.extra.xmult,
|
|
}
|
|
|
|
else
|
|
event({trigger = 'after', delay = 0.05, func = function()
|
|
play_sound('tarot2', 1, 0.4);
|
|
return true end })
|
|
|
|
forced_message("Invalid", card, G.C.ORANGE, true)
|
|
end
|
|
|
|
return {
|
|
repetitions = -1,
|
|
card = context.other_card
|
|
}
|
|
end
|
|
end,
|
|
|
|
--Injected the trigger using lovely, can be used for any post-play enchantment stuff
|
|
after_play = function(self, card, context)
|
|
if card.ability.extra.to_destroy then
|
|
forced_message("Redeemed!", card, G.C.RED, true)
|
|
|
|
return {
|
|
to_destroy = true
|
|
}
|
|
end
|
|
end,
|
|
|
|
--Can spawn when Catan mode enabled
|
|
in_pool = function(self, args)
|
|
return G.GAME.pool_flags.catan_enabled
|
|
end
|
|
}
|
|
|
|
end
|
|
|
|
--"Negative" Enhancements
|
|
|
|
--Global function wrapper to set DisEnhancements
|
|
function Card:set_disenhancement(center, initial, delay_sprites)
|
|
|
|
--If the card has heal seal
|
|
if self.seal and self.seal == 'unstb_heal' then
|
|
|
|
if self.debuff then
|
|
--If debuff, remove the seal and proceed through the rest of the process
|
|
self.seal = nil
|
|
else
|
|
--If the card is on hand, show resisting animation
|
|
if self.area == G.hand then
|
|
event({func = function() play_sound('unstb_heal', 1, 0.3) return true end})
|
|
forced_message("Resist!", self, G.C.GREEN, true)
|
|
elseif self.area == G.play then
|
|
--Play healing sound effect if it's in play
|
|
event({func = function() play_sound('unstb_heal', 1, 0.3) return true end})
|
|
end
|
|
|
|
--Don't turn the card into DisEnhancements
|
|
return
|
|
end
|
|
|
|
end
|
|
|
|
--If the card is debuffed, removed the heal seal entirely
|
|
if self.seal and self.seal == 'unstb_heal' and self.debuff then
|
|
self.seal = nil
|
|
end
|
|
|
|
local old_center = self.config.center
|
|
|
|
--Set the previous enhancement to keep track
|
|
if not old_center.disenhancement then
|
|
self.config.prev_center = old_center
|
|
end
|
|
|
|
--Calling appropriate set_ability
|
|
self:set_ability(center, initial, delay_sprites)
|
|
end
|
|
|
|
if unstb_config.enh.enh_disenh then
|
|
|
|
--Global blacklist for card enhancements that cannot be converted by radioactive card
|
|
unstb_global.radioactive_blacklist = {
|
|
m_unstb_radioactive = true,
|
|
m_unstb_slop = true,
|
|
}
|
|
|
|
--Radioactive
|
|
SMODS.Enhancement {
|
|
key = "radioactive",
|
|
atlas = "unstb_back",
|
|
pos = {x=3, y = 0},
|
|
|
|
|
|
|
|
replace_base_card = true,
|
|
no_suit = true,
|
|
no_rank = true,
|
|
always_scores = true,
|
|
|
|
disenhancement = true, --exclusive property to check if it's disenhancement or not
|
|
|
|
config = {extra = { chips = 13, odds_conv = 2, odds_mult = 3, mult_good = 1.75, mult_bad = 0.5 }, h_x_mult = 1},
|
|
|
|
loc_vars = function(self)
|
|
return {
|
|
vars = { self.config.extra.chips, (G.GAME and G.GAME.probabilities.normal or 1), self.config.extra.odds_conv, self.config.extra.odds_mult, self.config.extra.mult_good, self.config.extra.mult_bad }
|
|
}
|
|
end,
|
|
|
|
|
|
|
|
set_ability = function(self, card, initial, delay_sprites)
|
|
--Set the hand multiplier the first time
|
|
if pseudorandom('radioactive'..G.SEED) < G.GAME.probabilities.normal / card.ability.extra.odds_mult then
|
|
card.ability.h_x_mult = card.ability.extra.mult_good
|
|
else
|
|
card.ability.h_x_mult = card.ability.extra.mult_bad
|
|
end
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
if context.cardarea == G.play and context.main_scoring then
|
|
if #context.scoring_hand > 1 then
|
|
|
|
--polling the eligible hand first
|
|
|
|
local eligible_hand = {}
|
|
|
|
for i=1, #context.scoring_hand do
|
|
--Exclude slop card because it interacts horribly with this
|
|
if not unstb_global.radioactive_blacklist[context.scoring_hand[i].config.center.key] and not context.scoring_hand[i].to_convert then
|
|
eligible_hand[#eligible_hand+1] = context.scoring_hand[i]
|
|
end
|
|
end
|
|
|
|
--Update: no longer show "Safe!" if the entire hand is not convertable
|
|
if #eligible_hand > 0 then
|
|
local target = pseudorandom_element(eligible_hand, pseudoseed('radioactive_conv'..G.SEED))
|
|
if pseudorandom('radioactive'..G.SEED) < G.GAME.probabilities.normal / card.ability.extra.odds_conv then
|
|
target.to_convert = true
|
|
--Flipping Animation
|
|
event({trigger = 'after', delay = 0.1, func = function() target:flip(); play_sound('card1', 1); target:juice_up(0.3, 0.3); return true end })
|
|
|
|
--Changing Card Property
|
|
|
|
event({trigger = 'after', delay = 0.05, func = function()
|
|
|
|
target:set_disenhancement(G.P_CENTERS.m_unstb_radioactive)
|
|
|
|
return true end })
|
|
|
|
--Unflipping Animation
|
|
event({trigger = 'after', delay = 0.1, func = function() target:flip(); play_sound('tarot2', 1, 0.6); big_juice(card); target:juice_up(0.3, 0.3); target.to_convert = nil; return true end })
|
|
|
|
forced_message("Decayed!", target, G.C.RED, true)
|
|
else
|
|
forced_message("Safe!", card, G.C.GREEN, true)
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
return {
|
|
chips = card.ability.extra.chips
|
|
}
|
|
|
|
|
|
end
|
|
|
|
if context.cardarea == G.hand and not card.healed and context.main_scoring then
|
|
--Xmult handling ability is built-in, so this one just checks for odds and alter it respectively.
|
|
if pseudorandom('radioactive'..G.SEED) < G.GAME.probabilities.normal / card.ability.extra.odds_mult then
|
|
card.ability.h_x_mult = card.ability.extra.mult_good
|
|
else
|
|
card.ability.h_x_mult = card.ability.extra.mult_bad
|
|
end
|
|
|
|
end
|
|
end,
|
|
|
|
--This cannot spawn naturally at all
|
|
in_pool = function(self, args)
|
|
return false
|
|
end
|
|
}
|
|
|
|
SMODS.Enhancement {
|
|
key = "biohazard",
|
|
atlas = "unstb_back",
|
|
pos = {x=4, y = 0},
|
|
|
|
replace_base_card = true,
|
|
no_suit = true,
|
|
no_rank = true,
|
|
always_scores = true,
|
|
|
|
disenhancement = true,
|
|
|
|
config = {extra = { xmult = 0.9, h_money = 1, odds_conv = 3}},
|
|
|
|
loc_vars = function(self)
|
|
return {
|
|
vars = { self.config.extra.xmult, self.config.extra.h_money, (G.GAME and G.GAME.probabilities.normal or 1), self.config.extra.odds_conv }
|
|
}
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
|
|
if context.cardarea == G.play and context.main_scoring then
|
|
return {
|
|
xmult = card.ability.extra.xmult,
|
|
}
|
|
end
|
|
|
|
if context.discard and context.other_card == card then
|
|
local is_neutralized = next(SMODS.find_card('j_unstb_vaccination_card'))
|
|
|
|
--check if it is activated
|
|
if pseudorandom('biohazard'..G.SEED) < G.GAME.probabilities.normal / card.ability.extra.odds_conv and not is_neutralized then
|
|
|
|
--check hand card
|
|
local hand_card = {}
|
|
for i = 1, #G.hand.cards do
|
|
hand_card[G.hand.cards[i]] = true
|
|
end
|
|
|
|
--populate valid cards
|
|
local valid_cards = {}
|
|
for k, v in ipairs(G.playing_cards) do
|
|
if v.config.center ~= G.P_CENTERS.m_unstb_biohazard and not hand_card[v] then --Exclude biohazard cards
|
|
valid_cards[#valid_cards+1] = v
|
|
end
|
|
end
|
|
|
|
if valid_cards[1] then
|
|
local target_card = pseudorandom_element(valid_cards, pseudoseed(seed or 'validcard'..G.GAME.round_resets.ante))
|
|
target_card:set_disenhancement(G.P_CENTERS.m_unstb_biohazard , nil, true)
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
|
|
if context.cardarea == G.hand and not card.healed and context.main_scoring then
|
|
|
|
local is_neutralized = next(SMODS.find_card('j_unstb_vaccination_card'))
|
|
|
|
if not card.debuff and not is_neutralized then
|
|
return {
|
|
dollars = -card.ability.extra.h_money
|
|
}
|
|
end
|
|
end
|
|
end,
|
|
|
|
--This cannot spawn naturally at all
|
|
in_pool = function(self, args)
|
|
return false
|
|
end
|
|
}
|
|
|
|
SMODS.Enhancement {
|
|
key = "poison",
|
|
atlas = "unstb_back",
|
|
pos = {x=5, y = 0},
|
|
|
|
replace_base_card = false,
|
|
no_suit = false,
|
|
no_rank = false,
|
|
always_scores = true,
|
|
|
|
disenhancement = true,
|
|
|
|
override_chip = 0,
|
|
|
|
config = {extra = { chip = 0.9, h_money = 1}},
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
|
|
local chip = 0
|
|
if card and card.base then
|
|
chip = card.base.nominal + (card.ability.perma_bonus or 0)
|
|
end
|
|
|
|
return {
|
|
vars = { chip , self.config.extra.h_money }
|
|
}
|
|
end,
|
|
|
|
--Override generate_ui so it does not display any chips
|
|
generate_ui = function(self, info_queue, card, desc_nodes, specific_vars, full_UI_table)
|
|
SMODS.Enhancement.super.generate_ui(self, info_queue, card, desc_nodes, specific_vars, full_UI_table)
|
|
end,
|
|
|
|
|
|
calculate = function(self, card, context)
|
|
|
|
if context.cardarea == G.play and context.main_scoring then
|
|
local totalChip = card.base.nominal + (card.ability.perma_bonus or 0) --Counted bonus chips too, go crying
|
|
return {
|
|
chips = -totalChip,
|
|
colour = G.C.RED
|
|
}
|
|
end
|
|
end,
|
|
|
|
discard_override = function(self, card, args) --Discard overridden function, injected by Lovely
|
|
card.ability.discarded = nil
|
|
|
|
draw_card(G.hand, G.deck, args.delay, 'down', false, card)
|
|
|
|
--Wrap shuffle in the event instead, so it should work now hopefully???
|
|
event({trigger = 'after', func = function()
|
|
G.deck:shuffle('poison'..G.GAME.round_resets.ante)
|
|
return true end})
|
|
end,
|
|
|
|
--This cannot spawn naturally at all
|
|
in_pool = function(self, args)
|
|
return false
|
|
end
|
|
}
|
|
|
|
end
|
|
|
|
--Add proper tag to stone cards, nothing should change gameplay-wise
|
|
SMODS.Enhancement:take_ownership('m_stone', {
|
|
replace_base_card = true,
|
|
no_suit = true,
|
|
no_rank = true,
|
|
always_scores = true,
|
|
}, true)
|
|
|
|
--New Ranks
|
|
|
|
--Hook for Card:get_id()
|
|
|
|
local decimal_rank_map = { ['unstb_0.5'] = 'unstb_1', unstb_r2 = '2', unstb_e = '3', unstb_Pi = '4'}
|
|
|
|
--Expose this part so other mods can register decimal rank used for Engineer
|
|
function unstb_global.register_decimal_rank_map(decimal_rank, integer_rank)
|
|
decimal_rank_map[decimal_rank] = integer_rank
|
|
end
|
|
|
|
local ref_getid = Card.get_id
|
|
function Card:get_id()
|
|
|
|
local engineer_joker = next(SMODS.find_card('j_unstb_engineer'))
|
|
|
|
--If 'Engineer' Joker exists, returns rounded up rank instead
|
|
if engineer_joker and SMODS.Ranks[self.base.value].is_decimal then
|
|
return SMODS.Ranks[decimal_rank_map[self.base.value]].id
|
|
end
|
|
|
|
return ref_getid(self)
|
|
end
|
|
|
|
--Function wrapper to check if a card has decimal rank
|
|
|
|
local function is_decimal(card)
|
|
return (SMODS.Ranks[card.base.value].is_decimal or SMODS.Ranks[card.base.value].decimal_compat) and not card.config.center.no_rank
|
|
end
|
|
|
|
--Hook for Poker Hand name
|
|
|
|
local ref_get_poker_hand_info = G.FUNCS.get_poker_hand_info
|
|
|
|
G.FUNCS.get_poker_hand_info = function(_cards)
|
|
local text, loc_disp_text, poker_hands, scoring_hand, disp_text = ref_get_poker_hand_info(_cards)
|
|
--print(disp_text)
|
|
|
|
if string.find(disp_text, 'Straight') then
|
|
for i=1, #scoring_hand do
|
|
if is_decimal(scoring_hand[i]) then
|
|
loc_disp_text = string.gsub(loc_disp_text, 'Straight', 'Gay')
|
|
break
|
|
end
|
|
end
|
|
end
|
|
|
|
return text, loc_disp_text, poker_hands, scoring_hand, disp_text
|
|
end
|
|
|
|
|
|
--Pool flag wrapper function to help assist managing ranks enable / disable
|
|
function setPoolRankFlagEnable(rank, isEnable)
|
|
if not G.GAME or G.GAME.pool_flags[rank] == isEnable then return end
|
|
|
|
G.GAME.pool_flags[rank] = isEnable
|
|
end
|
|
|
|
function getPoolRankFlagEnable(rank)
|
|
return (G.GAME and G.GAME.pool_flags[rank] or false)
|
|
end
|
|
|
|
--Shared pool rank checking function
|
|
local function unstb_rankCheck(self, args)
|
|
if args and args.initial_deck then
|
|
return false
|
|
end
|
|
|
|
return getPoolRankFlagEnable(self.key)
|
|
end
|
|
|
|
SMODS.Rank {
|
|
hc_atlas = 'rank_ex_hc',
|
|
lc_atlas = 'rank_ex',
|
|
|
|
|
|
hidden = true,
|
|
|
|
key = '0',
|
|
card_key = '0',
|
|
pos = { x = 6 },
|
|
nominal = 0,
|
|
|
|
strength_effect = {
|
|
fixed = 2,
|
|
random = false,
|
|
ignore = false
|
|
},
|
|
next = { 'unstb_0.5', 'unstb_1', 'unstb_r2' },
|
|
|
|
prev = { 'unstb_???' },
|
|
|
|
shorthand = '0',
|
|
|
|
straight_edge = true,
|
|
|
|
in_pool = unstb_rankCheck,
|
|
}
|
|
|
|
SMODS.Rank {
|
|
hc_atlas = 'rank_ex_hc',
|
|
lc_atlas = 'rank_ex',
|
|
|
|
|
|
hidden = true,
|
|
|
|
key = '0.5',
|
|
card_key = '0.5',
|
|
pos = { x = 2 },
|
|
nominal = 0.5,
|
|
|
|
next = {'unstb_1', 'unstb_r2', '2', 'unstb_e' },
|
|
|
|
prev = { 'unstb_0' },
|
|
|
|
shorthand = '0.5',
|
|
|
|
is_decimal = true,
|
|
rank_act = {'0', '0.5', '1'},
|
|
|
|
in_pool = unstb_rankCheck,
|
|
}
|
|
|
|
SMODS.Rank {
|
|
hc_atlas = 'rank_ex_hc',
|
|
lc_atlas = 'rank_ex',
|
|
|
|
|
|
hidden = true,
|
|
|
|
key = '1',
|
|
card_key = '1',
|
|
pos = { x = 5 },
|
|
nominal = 1,
|
|
strength_effect = {
|
|
fixed = 2,
|
|
random = false,
|
|
ignore = false
|
|
},
|
|
next = {'unstb_r2', '2', 'unstb_e' },
|
|
|
|
prev = { 'unstb_0' },
|
|
|
|
shorthand = '1',
|
|
|
|
in_pool = unstb_rankCheck,
|
|
}
|
|
|
|
SMODS.Rank {
|
|
hc_atlas = 'rank_ex_hc',
|
|
lc_atlas = 'rank_ex',
|
|
|
|
|
|
hidden = true,
|
|
|
|
key = 'r2',
|
|
card_key = 'R',
|
|
pos = { x = 7 },
|
|
nominal = 1.41,
|
|
|
|
next = {'2', 'unstb_e', '3', 'unstb_Pi' },
|
|
prev = { 'unstb_1' },
|
|
|
|
shorthand = '/2',
|
|
|
|
is_decimal = true,
|
|
rank_act = {'1', '1.41', '2'},
|
|
|
|
in_pool = unstb_rankCheck,
|
|
}
|
|
|
|
SMODS.Rank {
|
|
hc_atlas = 'rank_ex_hc',
|
|
lc_atlas = 'rank_ex',
|
|
|
|
|
|
hidden = true,
|
|
|
|
key = 'e',
|
|
card_key = 'E',
|
|
pos = { x = 3 },
|
|
nominal = 2.72,
|
|
|
|
next = { '3', 'unstb_Pi', '4' },
|
|
prev = { '2' },
|
|
|
|
shorthand = 'e',
|
|
|
|
is_decimal = true,
|
|
rank_act = {'2', '2.72', '3'},
|
|
|
|
in_pool = unstb_rankCheck,
|
|
}
|
|
|
|
SMODS.Rank {
|
|
hc_atlas = 'rank_ex_hc',
|
|
lc_atlas = 'rank_ex',
|
|
|
|
|
|
hidden = true,
|
|
|
|
key = 'Pi',
|
|
card_key = 'P',
|
|
pos = { x = 4 },
|
|
nominal = 3.14,
|
|
|
|
next = { '4', '5' },
|
|
prev = { '3' },
|
|
|
|
shorthand = 'Pi',
|
|
|
|
is_decimal = true,
|
|
rank_act = {'3', '3.14', '4'},
|
|
|
|
in_pool = unstb_rankCheck,
|
|
}
|
|
|
|
SMODS.Rank {
|
|
hc_atlas = 'rank_ex_hc',
|
|
lc_atlas = 'rank_ex',
|
|
|
|
|
|
hidden = true,
|
|
|
|
key = '???',
|
|
card_key = '?',
|
|
pos = { x = 1 },
|
|
nominal = 0,
|
|
next = { 'unstb_???' },
|
|
prev = { 'unstb_???' },
|
|
shorthand = '?',
|
|
|
|
in_pool = unstb_rankCheck,
|
|
}
|
|
|
|
SMODS.Rank {
|
|
hc_atlas = 'rank_ex_hc',
|
|
lc_atlas = 'rank_ex',
|
|
|
|
|
|
hidden = true,
|
|
|
|
key = '21', -- the number or name (ex. "Jack") of your rank if it has one
|
|
card_key = '21', -- the short key put after the suit when coding a card object (ex. for the card "H_5" the card_key is 5). this seems to usually match the shorthand
|
|
pos = { x = 0 }, -- x position on the card atlas
|
|
nominal = 21, -- the number of chips this card scores
|
|
next = { 'unstb_???' }, -- the next rank directly above it, used for Strength Tarot
|
|
prev = { 'unstb_???' }, -- UNSTB addition: the previous rank directly below it
|
|
shorthand = '21', -- used for deck preview
|
|
|
|
in_pool = unstb_rankCheck,
|
|
}
|
|
|
|
-- "Premium Pack" Ranks
|
|
SMODS.Rank {
|
|
hc_atlas = 'rank_ex2_hc',
|
|
lc_atlas = 'rank_ex2',
|
|
|
|
hidden = true,
|
|
|
|
key = '11',
|
|
card_key = '11',
|
|
pos = { x = 0 },
|
|
nominal = 11,
|
|
next = { 'unstb_12' },
|
|
prev = {'10'},
|
|
shorthand = '11',
|
|
|
|
in_pool = unstb_rankCheck,
|
|
}
|
|
|
|
SMODS.Rank {
|
|
hc_atlas = 'rank_ex2_hc',
|
|
lc_atlas = 'rank_ex2',
|
|
|
|
hidden = true,
|
|
|
|
key = '12',
|
|
card_key = '12',
|
|
pos = { x = 1 },
|
|
nominal = 12,
|
|
next = { 'unstb_13' },
|
|
prev = {'unstb_11'},
|
|
shorthand = '12',
|
|
|
|
in_pool = unstb_rankCheck,
|
|
}
|
|
|
|
SMODS.Rank {
|
|
hc_atlas = 'rank_ex2_hc',
|
|
lc_atlas = 'rank_ex2',
|
|
|
|
hidden = true,
|
|
|
|
key = '13',
|
|
card_key = '13',
|
|
pos = { x = 2 },
|
|
nominal = 13,
|
|
next = { 'Ace' },
|
|
prev = {'unstb_12'},
|
|
shorthand = '13',
|
|
|
|
in_pool = unstb_rankCheck,
|
|
}
|
|
|
|
SMODS.Rank {
|
|
hc_atlas = 'rank_ex2_hc',
|
|
lc_atlas = 'rank_ex2',
|
|
|
|
hidden = true,
|
|
|
|
key = '25',
|
|
card_key = '25',
|
|
pos = { x = 3 },
|
|
nominal = 25,
|
|
next = { 'unstb_???' },
|
|
prev = { 'unstb_???' },
|
|
shorthand = '25',
|
|
|
|
in_pool = unstb_rankCheck,
|
|
}
|
|
|
|
SMODS.Rank {
|
|
hc_atlas = 'rank_ex2_hc',
|
|
lc_atlas = 'rank_ex2',
|
|
|
|
hidden = true,
|
|
|
|
key = '161',
|
|
card_key = '161',
|
|
pos = { x = 4 },
|
|
nominal = 161,
|
|
next = { 'unstb_???' },
|
|
prev = { 'unstb_???' },
|
|
shorthand = '161',
|
|
|
|
in_pool = unstb_rankCheck,
|
|
}
|
|
--
|
|
|
|
SMODS.Ranks['2'].strength_effect = {
|
|
fixed = 2,
|
|
random = false,
|
|
ignore = false
|
|
}
|
|
SMODS.Ranks['2'].next = {'unstb_e', '3', 'unstb_Pi'}
|
|
|
|
SMODS.Ranks['3'].strength_effect = {
|
|
fixed = 2,
|
|
random = false,
|
|
ignore = false
|
|
}
|
|
SMODS.Ranks['3'].next = {'unstb_Pi', '4'}
|
|
|
|
--Change straight edge off from Ace, so it start to look at rank 0 instead
|
|
--SMODS.Ranks['Ace'].straight_edge = false
|
|
SMODS.Ranks['Ace'].strength_effect = {
|
|
fixed = 2,
|
|
random = false,
|
|
ignore = false
|
|
}
|
|
SMODS.Ranks['Ace'].next = {'unstb_r2', '2', 'unstb_e'}
|
|
|
|
--Vanilla Rank Alteration for Set 2
|
|
SMODS.Ranks['10'].next = {'Jack', 'unstb_11'}
|
|
|
|
--Add preliminary prev property into vanilla rank list, so the default behavior will always point to this one
|
|
local vanilla_rank_list = {'2', '3', '4', '5', '6', '7', '8', '9', '10', 'Jack', 'Queen', 'King', 'Ace'}
|
|
|
|
for i=#vanilla_rank_list, 2, -1 do
|
|
SMODS.Ranks[vanilla_rank_list[i]].prev = {vanilla_rank_list[i-1]}
|
|
end
|
|
SMODS.Ranks['2'].prev = {'Ace'}
|
|
|
|
--Add a custom in_pool for high vanilla ranks, so they can be hidden from appearing in Lowkey Combo Decks HUD
|
|
|
|
for i=#vanilla_rank_list, 5, -1 do
|
|
SMODS.Ranks[vanilla_rank_list[i]].in_pool = function()
|
|
return not G.GAME.prevent_high_rank
|
|
end
|
|
end
|
|
|
|
--Booster Pack for Premium Card
|
|
|
|
local premium_booster_rate = {0.75, 0.75, 0.5, 0.1}
|
|
local premium_booster_cost = {4, 4, 6, 8}
|
|
|
|
--Needs all three ranks setting to be on to start appearing
|
|
if check_enable_taglist({'rank_binary', 'rank_decimal', 'rank_21'}) then
|
|
|
|
for i = 1, 4 do
|
|
SMODS.Booster{
|
|
key = 'prem_'..(i <= 2 and i or i == 3 and 'jumbo' or 'mega'),
|
|
cost = premium_booster_cost[i],
|
|
|
|
config = {extra = i <= 2 and 3 or 5, choose = i <= 3 and 1 or 2},
|
|
draw_hand = false,
|
|
|
|
create_card = function(self, card)
|
|
local card = create_card("Base", G.pack_cards, nil, nil, nil, true, nil, 'prem')
|
|
local edition_rate = 3
|
|
local edition = poll_edition('premium_edition'..G.GAME.round_resets.ante, edition_rate, true)
|
|
|
|
local rank_set = {"unstb_0", "unstb_0.5", "unstb_1", "unstb_r2", "unstb_e", "unstb_Pi", "unstb_11", "unstb_12", "unstb_13", "unstb_21", "unstb_25", "unstb_161"}
|
|
|
|
--Lowkey Deck / Sleeve combo mode, prevent high rank from being spawned
|
|
if G.GAME.prevent_high_rank then
|
|
rank_set = {"unstb_0", "unstb_0.5", "unstb_1", "unstb_r2", "unstb_e", "unstb_Pi"}
|
|
end
|
|
|
|
SMODS.change_base(card, nil, pseudorandom_element(rank_set, pseudoseed('premium_rank'..G.GAME.round_resets.ante)))
|
|
|
|
--Pooling Enhancements
|
|
local cen_pool = {}
|
|
for k, v in pairs(G.P_CENTER_POOLS["Enhanced"]) do
|
|
if not v.replace_base_card and not v.disenhancement then
|
|
cen_pool[#cen_pool+1] = v
|
|
end
|
|
end
|
|
|
|
local enh = pseudorandom_element(cen_pool, pseudoseed('premium_enhance'))
|
|
|
|
card:set_ability(enh)
|
|
|
|
card:set_edition(edition)
|
|
card:set_seal(SMODS.poll_seal({mod = 10}))
|
|
|
|
return card
|
|
-- return {set = 'Polymino', area = G.pack_cards, skip_materialize = nil, soulable = nil, key_append = 'vir'}
|
|
end,
|
|
|
|
ease_background_colour = function(self) ease_background_colour{new_colour = HEX('62a1b4'), special_colour = HEX('fce1b6'), contrast = 2} end,
|
|
particles = function(self)
|
|
G.booster_pack_sparkles = Particles(1, 1, 0,0, {
|
|
timer = 0.015,
|
|
scale = 0.3,
|
|
initialize = true,
|
|
lifespan = 3,
|
|
speed = 0.2,
|
|
padding = -1,
|
|
attach = G.ROOM_ATTACH,
|
|
colours = {G.C.BLACK, G.C.GOLD},
|
|
fill = true
|
|
})
|
|
G.booster_pack_sparkles.fade_alpha = 1
|
|
G.booster_pack_sparkles:fade(1, 0)
|
|
end,
|
|
|
|
pos = get_coordinates(i+3),
|
|
atlas = 'booster',
|
|
|
|
weight = premium_booster_rate[i],
|
|
}
|
|
end
|
|
|
|
end
|
|
|
|
|
|
-- Poker Hand Rewrite to support new ranks probably?
|
|
-- Currently unused: Straights use SMODS Implementation perfectly fine
|
|
|
|
local function get_keys(t)
|
|
local keys={}
|
|
for key,_ in pairs(t) do
|
|
table.insert(keys, key)
|
|
end
|
|
return keys
|
|
end
|
|
|
|
local isAllowDecimal = true
|
|
|
|
local decimalHands = {['unstb_0.5'] = {0, 1}, ['unstb_e'] = {2, 3}, ['unstb_Pi'] = {3, 4}}
|
|
|
|
--Unused, redirect the entire straight calculation to ustb_get_straight instead due to straight_edge shenanigans
|
|
function ustb_get_straight_wrapper(hand)
|
|
|
|
local ret = {}
|
|
if #hand < (5 - (four_fingers and 1 or 0)) then return ret end
|
|
|
|
local hasDecimal = false
|
|
for i = 1, #hand do
|
|
if decimalHands[hand[i].base.value] then
|
|
hasDecimal = true
|
|
break
|
|
end
|
|
end
|
|
|
|
return ustb_straight_calculation(hand)
|
|
|
|
--[[if hasDecimal then
|
|
--print('Has decimal')
|
|
return ustb_straight_decimal(hand)
|
|
else
|
|
--print('do not has decimal')
|
|
return get_straight(hand)
|
|
end]]
|
|
end
|
|
|
|
function ustb_get_straight(hand)
|
|
--Basically SMOD's implementation of straight_edge
|
|
--But with a slightly different fix to make extra ranks work
|
|
|
|
local ret = {}
|
|
local four_fingers = next(SMODS.find_card('j_four_fingers'))
|
|
local can_skip = next(SMODS.find_card('j_shortcut'))
|
|
|
|
local can_loop = next(SMODS.find_card('j_unstb_portal'))
|
|
|
|
if #hand < (5 - (four_fingers and 1 or 0)) then return ret end
|
|
|
|
local t = {}
|
|
local RANKS = {}
|
|
for i = 1, #hand do
|
|
if hand[i]:get_id() > 0 then
|
|
local rank = hand[i].base.value
|
|
RANKS[rank] = RANKS[rank] or {}
|
|
RANKS[rank][#RANKS[rank] + 1] = hand[i]
|
|
end
|
|
end
|
|
|
|
local straight_length = 0
|
|
local straight = false
|
|
local skipped_rank = false
|
|
local vals = {}
|
|
for k, v in pairs(SMODS.Ranks) do
|
|
if v.straight_edge then
|
|
table.insert(vals, k)
|
|
end
|
|
end
|
|
|
|
local init_vals = {}
|
|
for _, v in ipairs(vals) do
|
|
init_vals[v] = true
|
|
end
|
|
if not next(vals) then table.insert(vals, 'Ace') end
|
|
|
|
local initial = true
|
|
local br = false
|
|
local end_iter = false
|
|
local i = 0
|
|
|
|
--print(inspect(vals))
|
|
|
|
--Manually swapping vals because it would not work properly if it starts at Ace
|
|
--However, Ace has to be kept otherwise it allows the loop back
|
|
|
|
--TODO: Honestly could figure out the proper logic so it can be converted to lovely patch instead
|
|
|
|
vals[1] = 'unstb_0'
|
|
--vals[2] = 'Ace'
|
|
|
|
if not can_loop then
|
|
vals[2] = 'Ace'
|
|
end
|
|
|
|
--If there is no possible RANKS, breaks the function early
|
|
if not next(RANKS) then return ret end
|
|
|
|
while 1 do
|
|
end_iter = false
|
|
if straight_length >= (5 - (four_fingers and 1 or 0)) then
|
|
straight = true
|
|
end
|
|
i = i + 1
|
|
if br or (i > #SMODS.Rank.obj_buffer + 1) then break end
|
|
if not next(vals) then break end
|
|
for _, val in ipairs(vals) do
|
|
--print(val)
|
|
--print('===')
|
|
if init_vals[val] and not initial and not can_loop then br = true end
|
|
if RANKS[val] then
|
|
straight_length = straight_length + 1
|
|
skipped_rank = false
|
|
for _, vv in ipairs(RANKS[val]) do
|
|
t[#t + 1] = vv
|
|
end
|
|
|
|
vals = SMODS.Ranks[val].next
|
|
|
|
--print(inspect(vals))
|
|
--print('---')
|
|
|
|
initial = false
|
|
end_iter = true
|
|
break
|
|
end
|
|
end
|
|
if not end_iter then
|
|
local new_vals = {}
|
|
for _, val in ipairs(vals) do
|
|
for _, r in ipairs(SMODS.Ranks[val].next) do
|
|
table.insert(new_vals, r)
|
|
end
|
|
end
|
|
vals = new_vals
|
|
if can_skip and not skipped_rank then
|
|
skipped_rank = true
|
|
else
|
|
straight_length = 0
|
|
skipped_rank = false
|
|
if not straight then t = {} end
|
|
if straight then break end
|
|
end
|
|
end
|
|
end
|
|
if not straight then return ret end
|
|
table.insert(ret, t)
|
|
|
|
return ret
|
|
end
|
|
|
|
SMODS.PokerHandPart:take_ownership('_straight', {
|
|
func = function(hand) return ustb_get_straight(hand) end
|
|
})
|
|
|
|
--Generic consumable selection check utility function
|
|
--Written this way for Cryptid compatibility
|
|
local function get_consumable_use_hand_count(card, hand)
|
|
local selected_cards = {}
|
|
for i = 1, #hand do
|
|
if hand[i] ~= card then selected_cards[#selected_cards+1] = hand[i] end
|
|
end
|
|
return #selected_cards
|
|
end
|
|
|
|
--Returns selected hands excluding itself (in case of Cryptid merged consumable cards)
|
|
local function get_selected_cards(card, hand)
|
|
local selected_cards = {}
|
|
for i = 1, #hand do
|
|
if hand[i] ~= card then selected_cards[#selected_cards+1] = hand[i] end
|
|
end
|
|
return selected_cards
|
|
end
|
|
|
|
--Auxiliary Card
|
|
|
|
if unstb_config.gameplay.c_aux then
|
|
|
|
SMODS.ConsumableType{
|
|
key = 'Auxiliary',
|
|
primary_colour = HEX('424e54'),
|
|
secondary_colour = G.C.UNSTB_AUX,
|
|
loc_txt = {},
|
|
default = 'c_unstb_aux_seal_move',
|
|
collection_rows = {5, 5}
|
|
}
|
|
|
|
SMODS.UndiscoveredSprite{
|
|
key = 'Auxiliary',
|
|
atlas = 'auxiliary_undiscovered',
|
|
pos = get_coordinates(0)
|
|
}
|
|
|
|
--Booster Pack for Auxiliary Cards
|
|
|
|
local aux_booster_rate = {1, 1, 1, 0.25}
|
|
local aux_booster_cost = {4, 4, 6, 8}
|
|
|
|
for i = 1, 4 do
|
|
SMODS.Booster{
|
|
key = 'aux_'..(i <= 2 and i or i == 3 and 'jumbo' or 'mega'),
|
|
cost = aux_booster_cost[i],
|
|
|
|
config = {extra = i <= 2 and 3 or 5, choose = i <= 3 and 1 or 2},
|
|
draw_hand = false,
|
|
|
|
create_card = function(self, card)
|
|
local card = create_card('Auxiliary', G.pack_cards, nil, nil, true, true, nil, 'aux')
|
|
local neg_chance = pseudorandom('aux_rng')
|
|
|
|
if neg_chance < 0.4 and G.GAME.used_vouchers.v_unstb_aux2 and card.config.center.key ~= 'c_unstb_aux_dark_matter' then
|
|
card:set_edition({negative = true}, true)
|
|
end
|
|
|
|
return card
|
|
end,
|
|
|
|
ease_background_colour = function(self)
|
|
ease_colour(G.C.DYN_UI.MAIN, G.C.UNSTB_AUX)
|
|
ease_background_colour{new_colour = HEX('477978'), special_colour = HEX('00a669'), contrast = 4}
|
|
end,
|
|
|
|
pos = get_coordinates(i-1),
|
|
atlas = 'booster',
|
|
|
|
weight = aux_booster_rate[i],
|
|
|
|
--in_pool = function() return (pseudorandom('aux'..G.SEED) < aux_booster_rate[i]) end
|
|
}
|
|
end
|
|
|
|
--Original Reserve Card Button Code from MoreFluff (which credits to Cryptid and Betmma)
|
|
G.FUNCS.can_take_card = function(e)
|
|
local card = e.config.ref_table
|
|
|
|
--If the edition is negative, adds one more buffer to check if you can take it or not
|
|
local neg_buffer = (card.edition or {}).key == 'e_negative' and 1 or 0
|
|
|
|
if #G.consumeables.cards < G.consumeables.config.card_limit + neg_buffer then
|
|
e.config.colour = G.C.GREEN
|
|
e.config.button = "take_card"
|
|
else
|
|
e.config.colour = G.C.UI.BACKGROUND_INACTIVE
|
|
e.config.button = nil
|
|
end
|
|
end
|
|
|
|
G.FUNCS.take_card = function(e)
|
|
local c1 = e.config.ref_table
|
|
G.E_MANAGER:add_event(Event({
|
|
trigger = "after",
|
|
delay = 0.1,
|
|
func = function()
|
|
c1.area:remove_card(c1)
|
|
c1:add_to_deck()
|
|
if c1.children.price then
|
|
c1.children.price:remove()
|
|
end
|
|
c1.children.price = nil
|
|
if c1.children.buy_button then
|
|
c1.children.buy_button:remove()
|
|
end
|
|
c1.children.buy_button = nil
|
|
remove_nils(c1.children)
|
|
|
|
play_sound('generic1')
|
|
|
|
G.consumeables:emplace(c1)
|
|
G.GAME.pack_choices = G.GAME.pack_choices - 1
|
|
if G.GAME.pack_choices <= 0 then
|
|
G.FUNCS.end_consumeable(nil, delay_fac)
|
|
end
|
|
return true
|
|
end,
|
|
}))
|
|
end
|
|
|
|
local G_UIDEF_card_focus_ui_ref = G.UIDEF.card_focus_ui
|
|
|
|
function G.UIDEF.card_focus_ui(card)
|
|
base_background = G_UIDEF_card_focus_ui_ref(card)
|
|
local card_width = card.T.w + (card.ability.consumeable and -0.1 or card.ability.set == 'Voucher' and -0.16 or 0)
|
|
local base_attach = base_background:get_UIE_by_ID('ATTACH_TO_ME')
|
|
|
|
if ((card.area == G.pack_cards and G.pack_cards)) and card.ability.consumeable and card.ability.set == "Auxiliary" then
|
|
base_attach.children.use = G.UIDEF.card_focus_button{
|
|
card = card, parent = base_attach, type = 'select',
|
|
func = 'can_take_card', button = 'use_card', card_width = card_width
|
|
}
|
|
end
|
|
|
|
return base_background
|
|
end
|
|
|
|
local G_UIDEF_use_and_sell_buttons_ref = G.UIDEF.use_and_sell_buttons
|
|
function G.UIDEF.use_and_sell_buttons(card)
|
|
if (card.area == G.pack_cards and G.pack_cards) and card.ability.consumeable then --Add a take button for Auxiliary pack
|
|
if card.ability.set == "Auxiliary" then
|
|
return {
|
|
n = G.UIT.ROOT,
|
|
config = { padding = -0.1, colour = G.C.CLEAR },
|
|
nodes = {
|
|
{
|
|
n = G.UIT.R,
|
|
config = {
|
|
ref_table = card,
|
|
r = 0.08,
|
|
padding = 0.1,
|
|
align = "bm",
|
|
minw = 0.5 * card.T.w - 0.15,
|
|
minh = 0.7 * card.T.h,
|
|
maxw = 0.7 * card.T.w - 0.15,
|
|
hover = true,
|
|
shadow = true,
|
|
colour = G.C.UI.BACKGROUND_INACTIVE,
|
|
one_press = true,
|
|
button = "use_card",
|
|
func = "can_take_card",
|
|
},
|
|
nodes = {
|
|
{
|
|
n = G.UIT.T,
|
|
config = {
|
|
text = 'SELECT',
|
|
colour = G.C.UI.TEXT_LIGHT,
|
|
scale = 0.55,
|
|
shadow = true,
|
|
},
|
|
},
|
|
},
|
|
},
|
|
},
|
|
}
|
|
end
|
|
end
|
|
return G_UIDEF_use_and_sell_buttons_ref(card)
|
|
end
|
|
|
|
--Auxiliary Cards Code Starts Here--
|
|
|
|
if unstb_config.gameplay.seal_suit then
|
|
|
|
--Suit Seals Addition Cards
|
|
for i = 1, #suit_seal_list do
|
|
SMODS.Consumable{
|
|
set = 'Auxiliary', atlas = 'auxiliary',
|
|
key = 'aux_'..string.lower(suit_seal_list[i]),
|
|
|
|
config = {extra = {count = 2, seal = 'unstb_'..string.lower(suit_seal_list[i])}},
|
|
--discovered = true,
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
local suit = localize(suit_seal_list[i], 'suits_singular') ..' Seal'
|
|
local suit_color = G.C.SUITS[suit_seal_list[i]]
|
|
|
|
info_queue[#info_queue+1] = {set = 'Other', key = 'suit_seal'}
|
|
|
|
return {vars = {card.ability.extra.count, suit, colours = {suit_color}}}
|
|
end,
|
|
|
|
can_use = function(self, card)
|
|
if G.hand and (get_consumable_use_hand_count(card, G.hand.highlighted) >= 1 and get_consumable_use_hand_count(card, G.hand.highlighted) <= card.ability.extra.count) then
|
|
return true
|
|
end
|
|
return false
|
|
end,
|
|
|
|
use = function(self, card)
|
|
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
play_sound('tarot1')
|
|
card:juice_up(0.3, 0.5)
|
|
return true end })
|
|
|
|
for i = 1, #G.hand.highlighted do
|
|
event({trigger = 'after', delay = 0.2,
|
|
func = function()
|
|
G.hand.highlighted[i]:set_seal(card.ability.extra.seal, nil, true)
|
|
return true end })
|
|
end
|
|
|
|
delay(0.5)
|
|
event({trigger = 'after', delay = 0.2,
|
|
func = function()
|
|
G.hand:unhighlight_all();
|
|
return true end })
|
|
|
|
|
|
end,
|
|
|
|
pos = get_coordinates(i+1),
|
|
}
|
|
end
|
|
|
|
--Face Seal Card
|
|
SMODS.Consumable{
|
|
set = 'Auxiliary', atlas = 'auxiliary',
|
|
key = 'aux_face',
|
|
|
|
config = {extra = {count = 2, seal = 'unstb_face'}},
|
|
--discovered = true,
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
info_queue[#info_queue+1] = {set = 'Other', key = 'unstb_face_seal'}
|
|
return {vars = {card.ability.extra.count}}
|
|
end,
|
|
|
|
can_use = function(self, card)
|
|
if G.hand and (get_consumable_use_hand_count(card, G.hand.highlighted) >= 1 and get_consumable_use_hand_count(card, G.hand.highlighted) <= card.ability.extra.count) then
|
|
return true
|
|
end
|
|
return false
|
|
end,
|
|
|
|
use = function(self, card)
|
|
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
play_sound('tarot1')
|
|
card:juice_up(0.3, 0.5)
|
|
return true end })
|
|
|
|
for i = 1, #G.hand.highlighted do
|
|
event({trigger = 'after', delay = 0.2,
|
|
func = function()
|
|
G.hand.highlighted[i]:set_seal(card.ability.extra.seal, nil, true)
|
|
return true end })
|
|
end
|
|
|
|
delay(0.5)
|
|
event({trigger = 'after', delay = 0.2,
|
|
func = function()
|
|
G.hand:unhighlight_all();
|
|
return true end })
|
|
|
|
|
|
end,
|
|
|
|
pos = get_coordinates(6),
|
|
}
|
|
|
|
end
|
|
|
|
-- +2
|
|
SMODS.Consumable{
|
|
set = 'Auxiliary', atlas = 'auxiliary',
|
|
key = 'aux_plus_two',
|
|
|
|
config = {extra = {count = 2}},
|
|
--discovered = true,
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
return {vars = {card.ability.extra.count}}
|
|
end,
|
|
|
|
can_use = function(self, card)
|
|
local selected_hands = get_selected_cards(card, G.hand.highlighted)
|
|
if G.hand and (#selected_hands == 1) and not selected_hands[1].config.center.no_suit then
|
|
return true
|
|
end
|
|
return false
|
|
end,
|
|
|
|
use = function(self, card)
|
|
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
play_sound('tarot1')
|
|
card:juice_up(0.3, 0.5)
|
|
return true end })
|
|
|
|
local targetCard = G.hand.highlighted[1]
|
|
|
|
event({
|
|
trigger = 'after',
|
|
delay = 0.7,
|
|
func = function()
|
|
local cards = {}
|
|
for i=1, card.ability.extra.count do
|
|
cards[i] = true
|
|
local _rank = pseudorandom_element(SMODS.Ranks, pseudoseed('aux_plus_two')) or SMODS.Ranks['2']
|
|
local _suit = SMODS.Suits[targetCard.base.suit]
|
|
|
|
create_playing_card({front = G.P_CARDS[(_suit.card_key)..'_'..(_rank.card_key)], center = G.P_CENTERS.c_base}, G.hand, nil, i ~= 1, {G.C.SECONDARY_SET.Spectral})
|
|
end
|
|
playing_card_joker_effects(cards)
|
|
return true end })
|
|
end,
|
|
|
|
pos = get_coordinates(7),
|
|
}
|
|
|
|
-- Wild +4
|
|
SMODS.Consumable{
|
|
set = 'Auxiliary', atlas = 'auxiliary',
|
|
key = 'aux_plus_four_wild',
|
|
|
|
config = {extra = {count = 4}},
|
|
--discovered = true,
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
return {vars = {card.ability.extra.count}}
|
|
end,
|
|
|
|
can_use = function(self, card)
|
|
local selected_hands = get_selected_cards(card, G.hand.highlighted)
|
|
if G.hand and (#selected_hands == 1) and not selected_hands[1].config.center.no_rank then
|
|
return true
|
|
end
|
|
return false
|
|
end,
|
|
|
|
use = function(self, card)
|
|
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
play_sound('tarot1')
|
|
card:juice_up(0.3, 0.5)
|
|
return true end })
|
|
|
|
local targetCard = G.hand.highlighted[1]
|
|
|
|
event({
|
|
trigger = 'after',
|
|
delay = 0.7,
|
|
func = function()
|
|
local cards = {}
|
|
for i=1, card.ability.extra.count do
|
|
cards[i] = true
|
|
local _rank = SMODS.Ranks[targetCard.base.value]
|
|
local _suit = pseudorandom_element(SMODS.Suits, pseudoseed('aux_wild_plus_four')) or SMODS.Suits['Spades']
|
|
|
|
create_playing_card({front = G.P_CARDS[(_suit.card_key)..'_'..(_rank.card_key)], center = G.P_CENTERS.c_base}, G.hand, nil, i ~= 1, {G.C.SECONDARY_SET.Spectral})
|
|
end
|
|
playing_card_joker_effects(cards)
|
|
return true end })
|
|
end,
|
|
|
|
pos = get_coordinates(8),
|
|
}
|
|
|
|
-- In-round Instants
|
|
local function get_instant_effect(id, amount)
|
|
if id == 3 then
|
|
ease_hands_played(amount)
|
|
elseif id == 1 then
|
|
ease_discard(amount)
|
|
elseif id == 2 then
|
|
--Base game has this for tags, so I utilize them here
|
|
G.hand:change_size(amount)
|
|
G.FUNCS.draw_from_deck_to_hand(amount)
|
|
|
|
G.GAME.round_resets.temp_handsize = (G.GAME.round_resets.temp_handsize or 0) + amount
|
|
else
|
|
forced_message("Nope!", currentCard, G.C.PURPLE, true)
|
|
end
|
|
end
|
|
|
|
local aux_instants = {'aux_inst_disc', 'aux_inst_hsize', 'aux_inst_hand'}
|
|
|
|
for i = 1, #aux_instants do
|
|
SMODS.Consumable{
|
|
set = 'Auxiliary', atlas = 'auxiliary',
|
|
key = aux_instants[i],
|
|
|
|
config = {extra = {amount = 3}},
|
|
--discovered = true,
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
return {vars = {card.ability.extra.amount}}
|
|
end,
|
|
|
|
can_use = function(self, card)
|
|
--Only usable in-round. I can't believe it had to be checked *this much*
|
|
return G.hand and not G.blind_select and G.STATE ~= G.STATES.ROUND_EVAL and not G.shop and not G.booster_pack
|
|
end,
|
|
|
|
use = function(self, card)
|
|
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
play_sound('tarot1')
|
|
card:juice_up(0.3, 0.5)
|
|
return true end })
|
|
|
|
event({
|
|
trigger = 'after',
|
|
delay = 0.2,
|
|
func = function()
|
|
play_sound('generic1')
|
|
|
|
get_instant_effect(i, card.ability.extra.amount)
|
|
return true end })
|
|
end,
|
|
|
|
pos = get_coordinates(8+i),
|
|
}
|
|
end
|
|
|
|
--Seal Swap
|
|
SMODS.Consumable{
|
|
set = 'Auxiliary', atlas = 'auxiliary',
|
|
key = 'aux_seal_move',
|
|
|
|
config = {extra = {}},
|
|
--discovered = true,
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
return {vars = {}}
|
|
end,
|
|
|
|
can_use = function(self, card)
|
|
if G.hand and (get_consumable_use_hand_count(card, G.hand.highlighted) == 2) then
|
|
return true
|
|
end
|
|
return false
|
|
end,
|
|
|
|
use = function(self, card)
|
|
local card_l_seal = G.hand.highlighted[1].seal
|
|
|
|
--Animation code mostly ported from basegame tarot
|
|
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
play_sound('tarot1')
|
|
card:juice_up(0.3, 0.5)
|
|
return true end })
|
|
|
|
for i=1, #G.hand.highlighted do
|
|
local percent = 1.15 - (i-0.999)/(#G.hand.highlighted-0.998)*0.3
|
|
event({trigger = 'after',delay = 0.15,func = function() G.hand.highlighted[i]:flip();play_sound('card1', percent);G.hand.highlighted[i]:juice_up(0.3, 0.3);return true end })
|
|
end
|
|
delay(0.2)
|
|
|
|
--Handle the conversion
|
|
event({trigger = 'after',delay = 0.1,func = function()
|
|
G.hand.highlighted[1]:set_seal(G.hand.highlighted[2].seal, true, true)
|
|
G.hand.highlighted[2]:set_seal(card_l_seal, true, true)
|
|
|
|
--If a heal seal is on disenhanced card, heal it
|
|
for i=1, #G.hand.highlighted do
|
|
if G.hand.highlighted[i].config.center.disenhancement and G.hand.highlighted[i].seal == 'unstb_heal' then
|
|
G.hand.highlighted[i]:heal()
|
|
end
|
|
end
|
|
|
|
|
|
return true end })
|
|
|
|
for i=1, #G.hand.highlighted do
|
|
local percent = 0.85 + (i-0.999)/(#G.hand.highlighted-0.998)*0.3
|
|
event({trigger = 'after',delay = 0.15,func = function() G.hand.highlighted[i]:flip();play_sound('tarot2', percent, 0.6);G.hand.highlighted[i]:juice_up(0.3, 0.3);return true end })
|
|
end
|
|
event({trigger = 'after', delay = 0.2,func = function() G.hand:unhighlight_all(); return true end })
|
|
delay(0.5)
|
|
end,
|
|
|
|
pos = get_coordinates(12),
|
|
}
|
|
|
|
if unstb_config.rank.rank_binary then
|
|
|
|
--All for One
|
|
SMODS.Consumable{
|
|
set = 'Auxiliary', atlas = 'auxiliary',
|
|
key = 'aux_conv_1',
|
|
|
|
config = {extra = {count = 3}},
|
|
--discovered = true,
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
return {vars = {card.ability.extra.count}}
|
|
end,
|
|
|
|
can_use = function(self, card)
|
|
if G.hand and (get_consumable_use_hand_count(card, G.hand.highlighted) >= 1) and (get_consumable_use_hand_count(card, G.hand.highlighted) <= card.ability.extra.count) then
|
|
return true
|
|
end
|
|
return false
|
|
end,
|
|
|
|
use = function(self, card)
|
|
--Enable Rank Flag
|
|
setPoolRankFlagEnable('unstb_1', true);
|
|
|
|
--Animation code mostly ported from basegame tarot
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
play_sound('tarot1')
|
|
card:juice_up(0.3, 0.5)
|
|
return true end })
|
|
|
|
for i=1, #G.hand.highlighted do
|
|
local percent = 1.15 - (i-0.999)/(#G.hand.highlighted-0.998)*0.3
|
|
event({trigger = 'after',delay = 0.15,func = function() G.hand.highlighted[i]:flip();play_sound('card1', percent);G.hand.highlighted[i]:juice_up(0.3, 0.3);return true end })
|
|
end
|
|
delay(0.2)
|
|
|
|
--Handle the conversion
|
|
for i=1, #G.hand.highlighted do
|
|
event({trigger = 'after',delay = 0.1,func = function()
|
|
SMODS.change_base(G.hand.highlighted[i], G.hand.highlighted[i].base.suit, 'unstb_1')
|
|
return true end })
|
|
end
|
|
|
|
for i=1, #G.hand.highlighted do
|
|
local percent = 0.85 + (i-0.999)/(#G.hand.highlighted-0.998)*0.3
|
|
event({trigger = 'after',delay = 0.15,func = function() G.hand.highlighted[i]:flip();play_sound('tarot2', percent, 0.6);G.hand.highlighted[i]:juice_up(0.3, 0.3);return true end })
|
|
end
|
|
event({trigger = 'after', delay = 0.2,func = function() G.hand:unhighlight_all(); return true end })
|
|
delay(0.5)
|
|
end,
|
|
|
|
pos = get_coordinates(13),
|
|
}
|
|
|
|
end
|
|
|
|
if unstb_config.rank.rank_21 then
|
|
|
|
--The Twenty-One
|
|
SMODS.Consumable{
|
|
set = 'Auxiliary', atlas = 'auxiliary',
|
|
key = 'aux_21',
|
|
|
|
config = {extra = {count = 5}},
|
|
--discovered = true,
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
return {vars = {card.ability.extra.count}}
|
|
end,
|
|
|
|
can_use = function(self, card)
|
|
local selected_hands = get_selected_cards(card, G.hand.highlighted)
|
|
if G.hand and (#selected_hands >= 1) and (#selected_hands <= card.ability.extra.count) and blackJack_evalrank(selected_hands, 21)>=21 then
|
|
return true
|
|
end
|
|
return false
|
|
end,
|
|
|
|
use = function(self, card)
|
|
--Enable Rank Flag
|
|
setPoolRankFlagEnable('unstb_21', true);
|
|
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
play_sound('tarot1')
|
|
card:juice_up(0.3, 0.5)
|
|
return true end })
|
|
|
|
--Populate removed cards
|
|
local destroyed_cards = {}
|
|
for i = 1, #G.hand.highlighted do destroyed_cards[#destroyed_cards+1] = G.hand.highlighted[i] end
|
|
|
|
--Destroy Selected Card
|
|
event({
|
|
trigger = 'after',
|
|
delay = 0.1,
|
|
func = function()
|
|
for i=#destroyed_cards, 1, -1 do
|
|
local c = destroyed_cards[i]
|
|
if c.ability.name == 'Glass Card' then
|
|
c:shatter()
|
|
else
|
|
c:start_dissolve(nil, i == #destroyed_cards)
|
|
end
|
|
end
|
|
return true end })
|
|
--Adds Card
|
|
event({
|
|
trigger = 'after',
|
|
delay = 0.7,
|
|
func = function()
|
|
local cards = {true}
|
|
local _rank = SMODS.Ranks['unstb_21']
|
|
local _suit = pseudorandom_element(SMODS.Suits, pseudoseed('aux_21')) or SMODS.Suits['Spades']
|
|
|
|
create_playing_card({front = G.P_CARDS[(_suit.card_key)..'_'..(_rank.card_key)], center = G.P_CENTERS.c_base}, G.hand, nil, i ~= 1, {G.C.SECONDARY_SET.Spectral})
|
|
playing_card_joker_effects(cards)
|
|
return true end })
|
|
|
|
--Call joker calculations for post-destroyed stuff
|
|
delay(0.3)
|
|
for i = 1, #G.jokers.cards do
|
|
G.jokers.cards[i]:calculate_joker({remove_playing_cards = true, removed = destroyed_cards})
|
|
end
|
|
end,
|
|
|
|
pos = get_coordinates(14),
|
|
}
|
|
|
|
end
|
|
|
|
if check_enable_taglist({'edition_upgrade', 'enh_disenh'}) then
|
|
|
|
--Monkey Paw
|
|
SMODS.Consumable{
|
|
set = 'Auxiliary', atlas = 'auxiliary',
|
|
key = 'aux_upgrade',
|
|
|
|
config = {extra = {}},
|
|
--discovered = true,
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
|
|
info_queue[#info_queue+1] = {set = 'Other', key = 'upgrade_edition'}
|
|
info_queue[#info_queue+1] = {set = 'Other', key = 'poison_tooltip'}
|
|
|
|
return {vars = {}}
|
|
end,
|
|
|
|
can_use = function(self, card)
|
|
if G.hand and (get_consumable_use_hand_count(card, G.hand.highlighted) == 1) then
|
|
return true
|
|
end
|
|
return false
|
|
end,
|
|
|
|
use = function(self, card)
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
play_sound('tarot1')
|
|
card:juice_up(0.3, 0.5)
|
|
return true end })
|
|
|
|
local selected_card = G.hand.highlighted[1]
|
|
local selected_index
|
|
|
|
local poisoned_card = {}
|
|
|
|
--look for two adjacent cards in hand
|
|
for i=1, #G.hand.cards do
|
|
if G.hand.cards[i] == selected_card then
|
|
selected_index = i
|
|
end
|
|
end
|
|
|
|
--print(selected_index)
|
|
|
|
--Cover edge cases
|
|
|
|
local handCount = #G.hand.cards
|
|
|
|
if handCount >=3 then --If the hand has 3 cards or more, pick two adjacent cards to poison
|
|
if selected_index>1 then
|
|
poisoned_card[1] = G.hand.cards[selected_index-1]
|
|
else
|
|
poisoned_card[1] = G.hand.cards[handCount]
|
|
end
|
|
|
|
if selected_index<handCount then
|
|
poisoned_card[2] = G.hand.cards[selected_index+1]
|
|
else
|
|
poisoned_card[2] = G.hand.cards[1]
|
|
end
|
|
elseif #G.hand.cards ==2 then --If the hand has only 2 cards, only one other card can be poisoned
|
|
if selected_index == 1 then
|
|
poisoned_card[1] = G.hand.cards[2]
|
|
else
|
|
poisoned_card[1] = G.hand.cards[1]
|
|
end
|
|
end
|
|
|
|
for i=1, #poisoned_card do
|
|
local percent = 1.15 - (i-0.999)/(#poisoned_card-0.998)*0.3
|
|
event({trigger = 'after',delay = 0.15,func = function() poisoned_card[i]:flip();play_sound('card1', percent);poisoned_card[i]:juice_up(0.3, 0.3);return true end })
|
|
end
|
|
delay(0.2)
|
|
|
|
--Handle the conversion
|
|
event({trigger = 'after',delay = 0.1,func = function()
|
|
edition_upgrade(selected_card)
|
|
return true end })
|
|
for i=1, #poisoned_card do
|
|
event({trigger = 'after',delay = 0.1,func = function()
|
|
poisoned_card[i]:set_disenhancement(G.P_CENTERS.m_unstb_poison)
|
|
return true end })
|
|
end
|
|
|
|
for i=1, #poisoned_card do
|
|
local percent = 0.85 + (i-0.999)/(#poisoned_card-0.998)*0.3
|
|
event({trigger = 'after',delay = 0.15,func = function() poisoned_card[i]:flip();play_sound('tarot2', percent, 0.6);poisoned_card[i]:juice_up(0.3, 0.3);return true end })
|
|
end
|
|
event({trigger = 'after', delay = 0.2,func = function() G.hand:unhighlight_all(); return true end })
|
|
delay(0.5)
|
|
|
|
|
|
end,
|
|
|
|
pos = get_coordinates(15),
|
|
}
|
|
|
|
end
|
|
|
|
if unstb_config.enh.enh_disenh then
|
|
|
|
--Heal Seal Card
|
|
SMODS.Consumable{
|
|
set = 'Auxiliary', atlas = 'auxiliary',
|
|
key = 'aux_heal',
|
|
|
|
config = {extra = {count = 1, seal = 'unstb_heal'}},
|
|
--discovered = true,
|
|
|
|
weight = 10, --Large chance to appear when it is needed
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
info_queue[#info_queue+1] = {set = 'Other', key = 'unstb_heal_seal'}
|
|
return {vars = {card.ability.extra.count}}
|
|
end,
|
|
|
|
can_use = function(self, card)
|
|
if G.hand and (get_consumable_use_hand_count(card, G.hand.highlighted) == card.ability.extra.count) then
|
|
return true
|
|
end
|
|
return false
|
|
end,
|
|
|
|
use = function(self, card)
|
|
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
play_sound('tarot1')
|
|
card:juice_up(0.3, 0.5)
|
|
return true end })
|
|
|
|
for i = 1, #G.hand.highlighted do
|
|
event({trigger = 'after', delay = 0.2,
|
|
func = function()
|
|
G.hand.highlighted[i]:set_seal(card.ability.extra.seal, nil, true)
|
|
|
|
--If the selected card has DisEnhancements, heal it
|
|
if G.hand.highlighted[i].config.center.disenhancement then
|
|
G.hand.highlighted[i]:heal()
|
|
play_sound('unstb_heal', 1, 0.3)
|
|
|
|
forced_message("Healed!", G.hand.highlighted[i], G.C.GREEN, true)
|
|
end
|
|
return true end })
|
|
end
|
|
|
|
delay(0.5)
|
|
event({trigger = 'after', delay = 0.2,
|
|
func = function()
|
|
G.hand:unhighlight_all();
|
|
return true end })
|
|
|
|
|
|
end,
|
|
|
|
pos = get_coordinates(16),
|
|
|
|
--Can spawn only when more than 10 cards the deck is Disenhanced
|
|
in_pool = function(self, args)
|
|
|
|
--For some reason, not checking this crash Cryptid on start up
|
|
if not G.playing_cards then return false end
|
|
|
|
local count = 0
|
|
|
|
for k, v in ipairs(G.playing_cards) do
|
|
if v.config.center.disenhancement then
|
|
count = count+1
|
|
end
|
|
end
|
|
|
|
return count > 10
|
|
end,
|
|
}
|
|
|
|
--Heal Hand
|
|
SMODS.Consumable{
|
|
set = 'Auxiliary', atlas = 'auxiliary',
|
|
key = 'aux_heal_hand',
|
|
|
|
config = {extra = {}},
|
|
--discovered = true,
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
info_queue[#info_queue+1] = {set = 'Other', key = 'disenhancement'}
|
|
|
|
return {vars = {card.ability.extra.count}}
|
|
end,
|
|
|
|
weight = 10, --Large chance to appear when it is needed
|
|
|
|
can_use = function(self, card)
|
|
--Usable only in-game
|
|
if G.hand and not G.blind_select and G.STATE ~= G.STATES.ROUND_EVAL and not G.shop and not G.booster_pack then
|
|
|
|
--Check if the hand contains at least one DisEnhancements
|
|
for i = 1, #G.hand.cards do
|
|
if G.hand.cards[i].config.center.disenhancement then
|
|
return true
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
return false
|
|
end,
|
|
|
|
use = function(self, card)
|
|
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
play_sound('tarot1')
|
|
card:juice_up(0.3, 0.5)
|
|
return true end })
|
|
|
|
--Populate List of cards to heal
|
|
local heal_cards = {}
|
|
for i = 1, #G.hand.cards do
|
|
if G.hand.cards[i].config.center.disenhancement then
|
|
heal_cards[#heal_cards+1] = G.hand.cards[i]
|
|
end
|
|
end
|
|
|
|
if #heal_cards>0 then
|
|
play_sound('unstb_heal', 1, 0.3)
|
|
end
|
|
|
|
for i = 1, #heal_cards do
|
|
event({trigger = 'after', delay = 0.1, func = function()
|
|
heal_cards[i]:heal()
|
|
play_sound('tarot2', 1, 0.4)
|
|
heal_cards[i]:juice_up()
|
|
return true
|
|
end
|
|
})
|
|
end
|
|
|
|
end,
|
|
|
|
pos = get_coordinates(17),
|
|
|
|
--Can spawn only when more than 1/4 of deck is Disenhanced
|
|
in_pool = function(self, args)
|
|
|
|
--For some reason, not checking this crash Cryptid on start up
|
|
if not G.playing_cards then return false end
|
|
|
|
local count = 0
|
|
|
|
for k, v in ipairs(G.playing_cards) do
|
|
if v.config.center.disenhancement then
|
|
count = count+1
|
|
end
|
|
end
|
|
|
|
return count > #G.playing_cards * 0.25
|
|
end,
|
|
}
|
|
|
|
end
|
|
|
|
--Lottery
|
|
SMODS.Consumable{
|
|
set = 'Auxiliary', atlas = 'auxiliary',
|
|
key = 'aux_lottery',
|
|
|
|
config = {extra = {odds_win = 4, prize = 20}},
|
|
--discovered = true,
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
return {vars = {G.GAME and G.GAME.probabilities.normal or 1, card.ability.extra.odds_win, card.ability.extra.prize }}
|
|
end,
|
|
|
|
can_use = function(self, card)
|
|
return true
|
|
end,
|
|
|
|
use = function(self, card)
|
|
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
play_sound('tarot1')
|
|
card:juice_up(0.3, 0.5)
|
|
return true end })
|
|
|
|
event({trigger = 'after', func = function()
|
|
if pseudorandom('aux_lottery'..G.SEED) < G.GAME.probabilities.normal / card.ability.extra.odds_win then
|
|
ease_dollars(20, true)
|
|
else
|
|
--Port from Wheel of Fortune
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
attention_text({
|
|
text = localize('k_nope_ex'),
|
|
scale = 1.3,
|
|
hold = 1.4,
|
|
major = card,
|
|
backdrop_colour = G.C.UNSTB_AUX,
|
|
align = (G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.SPECTRAL_PACK or G.STATE == G.STATES.SMODS_BOOSTER_OPENED) and 'tm' or 'cm',
|
|
offset = {x = 0, y = (G.STATE == G.STATES.TAROT_PACK or G.STATE == G.STATES.SPECTRAL_PACK or G.STATE == G.STATES.SMODS_BOOSTER_OPENED) and -0.2 or 0},
|
|
silent = true
|
|
})
|
|
event({trigger = 'after', delay = 0.06*G.SETTINGS.GAMESPEED, blockable = false, blocking = false, func = function()
|
|
play_sound('tarot2', 0.76, 0.4);return true end})
|
|
play_sound('tarot2', 1, 0.4)
|
|
card:juice_up(0.3, 0.5)
|
|
return true end })
|
|
end
|
|
return true
|
|
end
|
|
})
|
|
end,
|
|
|
|
pos = get_coordinates(18),
|
|
}
|
|
|
|
--Blank
|
|
SMODS.Consumable{
|
|
set = 'Auxiliary', atlas = 'auxiliary',
|
|
key = 'aux_blank',
|
|
|
|
config = {extra = {}},
|
|
--discovered = true,
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
return {vars = {}}
|
|
end,
|
|
|
|
can_use = function(self, card)
|
|
return true
|
|
end,
|
|
|
|
use = function(self, card)
|
|
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
play_sound('tarot1')
|
|
card:juice_up(0.3, 0.5)
|
|
return true end })
|
|
|
|
event({trigger = 'after', func = function()
|
|
G.GAME.aux_blank_count = (G.GAME.aux_blank_count or 0) + 1
|
|
return true
|
|
end
|
|
})
|
|
end,
|
|
|
|
pos = get_coordinates(0),
|
|
|
|
in_pool = function(self, args)
|
|
if not G.GAME then return false end
|
|
|
|
return G.booster_pack and (G.GAME.aux_blank_count or 0) < (G.GAME.aux_blank_max_count or 2)
|
|
end,
|
|
}
|
|
|
|
--Dark Matter
|
|
SMODS.Consumable{
|
|
set = 'Auxiliary', atlas = 'auxiliary',
|
|
key = 'aux_dark_matter',
|
|
|
|
config = {extra = {slot = 1}},
|
|
--discovered = true,
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
|
|
local key = self.key
|
|
if (card.edition or {}).key == 'e_negative' then
|
|
key = self.key..'_n'
|
|
end
|
|
|
|
return {key = key, vars = {card.ability.extra.slot}}
|
|
end,
|
|
|
|
can_use = function(self, card)
|
|
return G.jokers.config.card_limit > 0
|
|
end,
|
|
|
|
use = function(self, card)
|
|
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
play_sound('tarot1')
|
|
card:juice_up(0.3, 0.5)
|
|
return true end })
|
|
|
|
G.GAME.aux_blank_count = 0
|
|
|
|
--Increase the count for the next Dark Matter
|
|
G.GAME.aux_blank_max_count = (G.GAME.aux_blank_max_count or 2)+1
|
|
|
|
event({trigger = 'after', func = function()
|
|
if (card.edition or {}).key == 'e_negative' then
|
|
G.jokers.config.card_limit = G.jokers.config.card_limit - card.ability.extra.slot
|
|
else
|
|
G.jokers.config.card_limit = G.jokers.config.card_limit + card.ability.extra.slot
|
|
end
|
|
return true
|
|
end
|
|
})
|
|
end,
|
|
|
|
pos = get_coordinates(20),
|
|
|
|
--Can spawn only when redeemed Blank Auxiliary Card enough time
|
|
in_pool = function(self, args)
|
|
if not G.GAME then return false end
|
|
|
|
return G.booster_pack and (G.GAME.aux_blank_count or 0) >= (G.GAME.aux_blank_max_count or 2)
|
|
end,
|
|
}
|
|
|
|
--Random
|
|
SMODS.Consumable{
|
|
set = 'Auxiliary', atlas = 'auxiliary',
|
|
key = 'aux_random',
|
|
|
|
config = {extra = {count = 2}},
|
|
--discovered = true,
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
return {vars = {card.ability.extra.count}}
|
|
end,
|
|
|
|
can_use = function(self, card)
|
|
return true
|
|
end,
|
|
|
|
use = function(self, card)
|
|
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
play_sound('tarot1')
|
|
card:juice_up(0.3, 0.5)
|
|
return true end })
|
|
|
|
for i = 1, math.min(card.ability.extra.count, G.consumeables.config.card_limit - #G.consumeables.cards) do
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
if G.consumeables.config.card_limit > #G.consumeables.cards then
|
|
play_sound('timpani')
|
|
local c = create_card('Auxiliary', G.consumeables, nil, nil, nil, nil, nil, 'aux_random')
|
|
c:add_to_deck()
|
|
G.consumeables:emplace(c)
|
|
card:juice_up(0.3, 0.5)
|
|
end
|
|
return true end })
|
|
end
|
|
delay(0.6)
|
|
end,
|
|
|
|
pos = get_coordinates(19),
|
|
}
|
|
|
|
end
|
|
|
|
--Other Basegame Consumable Supports for new features
|
|
|
|
--Tarots
|
|
|
|
--main function for all three tarots
|
|
local function conversionTarot(hand, newcenter)
|
|
--Animation ported from basegame Tarot
|
|
|
|
for i=1, #hand do
|
|
local percent = 1.15 - (i-0.999)/(#hand-0.998)*0.3
|
|
event({trigger = 'after',delay = 0.15,func = function() hand[i]:flip();play_sound('card1', percent);hand[i]:juice_up(0.3, 0.3);return true end })
|
|
end
|
|
delay(0.2)
|
|
|
|
--Handle the conversion
|
|
for i=1, #hand do
|
|
event({trigger = 'after',delay = 0.1,func = function()
|
|
hand[i]:set_ability(G.P_CENTERS[newcenter])
|
|
return true end })
|
|
end
|
|
|
|
for i=1, #hand do
|
|
local percent = 0.85 + (i-0.999)/(#hand-0.998)*0.3
|
|
event({trigger = 'after',delay = 0.15,func = function() hand[i]:flip();play_sound('tarot2', percent, 0.6);hand[i]:juice_up(0.3, 0.3);return true end })
|
|
end
|
|
event({trigger = 'after', delay = 0.2,func = function() G.hand:unhighlight_all(); return true end })
|
|
delay(0.5)
|
|
end
|
|
|
|
if unstb_config.enh.enh_custom then
|
|
|
|
--The Time
|
|
SMODS.Consumable{
|
|
set = 'Tarot', atlas = 'tarot',
|
|
key = 'trt_time',
|
|
set_card_type_badge = function(self, card, badges)
|
|
badges[1] = create_badge(localize("k_tarot_exclaim"), get_type_colour(self or card.config, card), nil, 1.2)
|
|
end,
|
|
|
|
config = {extra = {count = 2}},
|
|
--discovered = true,
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
|
|
info_queue[#info_queue+1] = G.P_CENTERS['m_unstb_vintage']
|
|
|
|
return {vars = {card and card.ability.extra.count or self.config.extra.count}}
|
|
end,
|
|
|
|
can_use = function(self, card)
|
|
if G.hand and (get_consumable_use_hand_count(card, G.hand.highlighted) >= 1) and (get_consumable_use_hand_count(card, G.hand.highlighted) <= card.ability.extra.count) then
|
|
return true
|
|
end
|
|
return false
|
|
end,
|
|
|
|
use = function(self, card)
|
|
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
play_sound('tarot1')
|
|
card:juice_up(0.3, 0.5)
|
|
return true end })
|
|
|
|
--Special Interaction: If it is a Vintage Card already, reset the breakdown chance
|
|
if G.hand.highlighted[1].config.center.key == 'm_unstb_vintage' then
|
|
G.hand.highlighted[1].ability.extra.current_odd = 0
|
|
end
|
|
|
|
conversionTarot(G.hand.highlighted, 'm_unstb_vintage')
|
|
end,
|
|
|
|
pos = get_coordinates(0),
|
|
}
|
|
|
|
--The Acorn
|
|
SMODS.Consumable{
|
|
set = 'Tarot', atlas = 'tarot',
|
|
key = 'trt_acorn',
|
|
set_card_type_badge = function(self, card, badges)
|
|
badges[1] = create_badge(localize("k_tarot_exclaim"), get_type_colour(self or card.config, card), nil, 1.2)
|
|
end,
|
|
|
|
config = {extra = {count = 1}},
|
|
--discovered = true,
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
|
|
info_queue[#info_queue+1] = {set = 'Other', key = 'acorn_tooltip'}
|
|
|
|
return {vars = {card and card.ability.extra.count or self.config.extra.count}}
|
|
end,
|
|
|
|
can_use = function(self, card)
|
|
if G.hand and (get_consumable_use_hand_count(card, G.hand.highlighted) >= 1) and (get_consumable_use_hand_count(card, G.hand.highlighted) <= card.ability.extra.count) then
|
|
return true
|
|
end
|
|
return false
|
|
end,
|
|
|
|
use = function(self, card)
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
play_sound('tarot1')
|
|
card:juice_up(0.3, 0.5)
|
|
return true end })
|
|
conversionTarot(G.hand.highlighted, 'm_unstb_acorn')
|
|
end,
|
|
|
|
pos = get_coordinates(1),
|
|
}
|
|
|
|
--The Greed
|
|
SMODS.Consumable{
|
|
set = 'Tarot', atlas = 'tarot',
|
|
key = 'trt_greed',
|
|
set_card_type_badge = function(self, card, badges)
|
|
badges[1] = create_badge(localize("k_tarot_exclaim"), get_type_colour(self or card.config, card), nil, 1.2)
|
|
end,
|
|
|
|
config = {extra = {count = 2}},
|
|
--discovered = true,
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
|
|
info_queue[#info_queue+1] = G.P_CENTERS['m_unstb_promo']
|
|
|
|
return {vars = {card and card.ability.extra.count or self.config.extra.count}}
|
|
end,
|
|
|
|
can_use = function(self, card)
|
|
if G.hand and (get_consumable_use_hand_count(card, G.hand.highlighted) >= 1) and (get_consumable_use_hand_count(card, G.hand.highlighted) <= card.ability.extra.count) then
|
|
return true
|
|
end
|
|
return false
|
|
end,
|
|
|
|
use = function(self, card)
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
play_sound('tarot1')
|
|
card:juice_up(0.3, 0.5)
|
|
return true end })
|
|
conversionTarot(G.hand.highlighted, 'm_unstb_promo')
|
|
end,
|
|
|
|
pos = get_coordinates(2),
|
|
}
|
|
|
|
end
|
|
|
|
--New Rank-based Tarot
|
|
|
|
local tarot_half_rankList = {['unstb_0'] = 'unstb_0',
|
|
['unstb_1'] = 'unstb_0',
|
|
['2'] = 'unstb_1',
|
|
['3'] = 'unstb_1',
|
|
['4'] = '2',
|
|
['5'] = '2',
|
|
['6'] = '3',
|
|
['7'] = '3',
|
|
['8'] = '4',
|
|
['9'] = '4',
|
|
['10'] = '5',
|
|
['Ace'] = '5',
|
|
['unstb_11'] = '5',
|
|
['unstb_12'] = '6',
|
|
['unstb_13'] = '6',
|
|
['unstb_21'] = '10',
|
|
['unstb_25'] = 'unstb_12',}
|
|
|
|
if check_enable_taglist({'rank_binary', 'rank_decimal'}) then
|
|
|
|
SMODS.Consumable{
|
|
set = 'Tarot', atlas = 'tarot',
|
|
key = 'trt_half',
|
|
set_card_type_badge = function(self, card, badges)
|
|
badges[1] = create_badge(localize("k_tarot_exclaim"), get_type_colour(self or card.config, card), nil, 1.2)
|
|
end,
|
|
|
|
config = {extra = {count = 2}},
|
|
--discovered = true,
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
|
|
return {vars = {}}
|
|
end,
|
|
|
|
can_use = function(self, card)
|
|
local selected_hands = get_selected_cards(card, G.hand.highlighted)
|
|
if G.hand and (#selected_hands == 1) and not selected_hands[1].config.center.replace_base_card and tarot_half_rankList[selected_hands[1].base.value] then
|
|
return true
|
|
end
|
|
return false
|
|
end,
|
|
|
|
use = function(self, card)
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
play_sound('tarot1')
|
|
card:juice_up(0.3, 0.5)
|
|
return true end })
|
|
|
|
local target_card = G.hand.highlighted[1]
|
|
|
|
--Create two copies of the card, with half rank
|
|
--Create one additional rank 0.5 card if applicable, copy the enhancement only, no other bonus property
|
|
|
|
local new_rank = tarot_half_rankList[target_card.base.value]
|
|
|
|
local extra_card = 0
|
|
|
|
if target_card.base.nominal%2 ==1 then
|
|
extra_card = 1
|
|
|
|
--Enable Rank Flag
|
|
setPoolRankFlagEnable('unstb_0.5', true);
|
|
end
|
|
|
|
event({
|
|
trigger = 'after',
|
|
delay = 0.7,
|
|
func = function()
|
|
local _first_dissolve = nil
|
|
local new_cards = {}
|
|
for i = 1, card.ability.extra.count + extra_card do
|
|
G.playing_card = (G.playing_card and G.playing_card + 1) or 1
|
|
local _card = copy_card(target_card, nil, nil, G.playing_card)
|
|
|
|
if extra_card>0 and i==card.ability.extra.count + extra_card then
|
|
--Remove special ability
|
|
--_card.set_ability(G.P_CENTERS.c_base)
|
|
_card:set_edition(nil, true, true)
|
|
_card:set_seal(nil, true, true)
|
|
_card.ability.perma_bonus = 0
|
|
|
|
SMODS.change_base(_card, nil, 'unstb_0.5')
|
|
else
|
|
SMODS.change_base(_card, nil, new_rank)
|
|
end
|
|
|
|
_card:add_to_deck()
|
|
G.deck.config.card_limit = G.deck.config.card_limit + 1
|
|
table.insert(G.playing_cards, _card)
|
|
G.hand:emplace(_card)
|
|
_card:start_materialize(nil, _first_dissolve)
|
|
_first_dissolve = true
|
|
new_cards[#new_cards+1] = _card
|
|
end
|
|
playing_card_joker_effects(new_cards)
|
|
return true end })
|
|
|
|
|
|
--Destroy the original card
|
|
local destroyed_cards = {target_card}
|
|
event({
|
|
trigger = 'after',
|
|
delay = 0.1,
|
|
func = function()
|
|
for i=#destroyed_cards, 1, -1 do
|
|
local c = destroyed_cards[i]
|
|
if c.ability.name == 'Glass Card' then
|
|
c:shatter()
|
|
else
|
|
c:start_dissolve(nil, i == #destroyed_cards)
|
|
end
|
|
end
|
|
return true end })
|
|
|
|
--Calling Jokers to process the card destroying
|
|
--Edit: Disable this part for now, technically it should not be counted as destroying card because the new card is considered a split
|
|
|
|
--[[delay(0.3)
|
|
for i = 1, #G.jokers.cards do
|
|
G.jokers.cards[i]:calculate_joker({remove_playing_cards = true, removed = destroyed_cards})
|
|
end]]
|
|
|
|
end,
|
|
|
|
pos = get_coordinates(3),
|
|
}
|
|
|
|
end
|
|
|
|
if unstb_config.rank.rank_decimal then
|
|
|
|
SMODS.Consumable{
|
|
set = 'Tarot', atlas = 'tarot',
|
|
key = 'trt_knowledge',
|
|
set_card_type_badge = function(self, card, badges)
|
|
badges[1] = create_badge(localize("k_tarot_exclaim"), get_type_colour(self or card.config, card), nil, 1.2)
|
|
end,
|
|
|
|
config = {extra = {count = 1}},
|
|
--discovered = true,
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
|
|
return {vars = {}}
|
|
end,
|
|
|
|
can_use = function(self, card)
|
|
local selected_hands = get_selected_cards(card, G.hand.highlighted)
|
|
if G.hand and (#selected_hands == 1) and not selected_hands[1].config.center.replace_base_card then
|
|
return true
|
|
end
|
|
return false
|
|
end,
|
|
|
|
use = function(self, card)
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
play_sound('tarot1')
|
|
card:juice_up(0.3, 0.5)
|
|
return true end })
|
|
|
|
local targetCard = G.hand.highlighted[1]
|
|
|
|
event({
|
|
trigger = 'after',
|
|
delay = 0.7,
|
|
func = function()
|
|
local cards = {}
|
|
for i=1, card.ability.extra.count do
|
|
cards[i] = true
|
|
local created_rank = pseudorandom_element({'unstb_0.5', 'unstb_r2', 'unstb_e', 'unstb_Pi'}, pseudoseed('trt_knowledge'))
|
|
setPoolRankFlagEnable(created_rank, true)
|
|
|
|
local _rank = SMODS.Ranks[created_rank]
|
|
local _suit = SMODS.Suits[targetCard.base.suit]
|
|
|
|
create_playing_card({front = G.P_CARDS[(_suit.card_key)..'_'..(_rank.card_key)], center = G.P_CENTERS.c_base}, G.hand, nil, i ~= 1, {G.C.SECONDARY_SET.Spectral})
|
|
end
|
|
playing_card_joker_effects(cards)
|
|
return true end })
|
|
event({trigger = 'after', delay = 0.2,func = function() G.hand:unhighlight_all(); return true end })
|
|
|
|
end,
|
|
|
|
pos = get_coordinates(4),
|
|
}
|
|
end
|
|
|
|
--"Rebundant" Spectral (Same ability set as some Auxiliary exclusives, but worse)
|
|
|
|
if unstb_config.gameplay.c_rebundant then
|
|
|
|
if unstb_config.enh.enh_disenh then
|
|
|
|
--Elixir of Life
|
|
SMODS.Consumable{
|
|
set = 'Spectral', atlas = 'spectral',
|
|
key = 'spc_elixir',
|
|
|
|
config = {extra = {}},
|
|
--discovered = true,
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
info_queue[#info_queue+1] = {set = 'Other', key = 'disenhancement'}
|
|
|
|
return {vars = {card.ability.extra.count}}
|
|
end,
|
|
|
|
can_use = function(self, card)
|
|
--Check the entire deck
|
|
for k, v in ipairs(G.playing_cards) do
|
|
if v.config.center.disenhancement then
|
|
return true
|
|
end
|
|
end
|
|
|
|
return false
|
|
end,
|
|
|
|
use = function(self, card)
|
|
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
play_sound('tarot1')
|
|
card:juice_up(0.3, 0.5)
|
|
return true end })
|
|
|
|
--Populate List of cards to heal
|
|
local heal_cards = {}
|
|
|
|
for k, v in ipairs(G.playing_cards) do
|
|
if v.config.center.disenhancement then
|
|
heal_cards[#heal_cards+1] = v
|
|
end
|
|
end
|
|
|
|
if #heal_cards>0 then
|
|
play_sound('unstb_heal', 1, 0.3)
|
|
end
|
|
|
|
for i = 1, #heal_cards do
|
|
if heal_cards[i].area == G.hand then --If card is in hand, play animation
|
|
event({trigger = 'after', delay = 0.1, func = function()
|
|
heal_cards[i]:heal()
|
|
play_sound('tarot2', 1, 0.4)
|
|
heal_cards[i]:juice_up()
|
|
return true
|
|
end
|
|
})
|
|
else --Otherwise, just heal
|
|
heal_cards[i]:heal()
|
|
end
|
|
|
|
end
|
|
|
|
--Reduce Money if it's greater than 0, otherwise do nothing
|
|
if G.GAME.dollars > 0 then
|
|
ease_dollars(-math.ceil(G.GAME.dollars*0.5), true)
|
|
end
|
|
end,
|
|
|
|
weight = 10, --Large chance to appear when it is needed
|
|
|
|
pos = get_coordinates(0),
|
|
|
|
--Can spawn only when more than 1/3 of deck is Disenhanced
|
|
in_pool = function(self, args)
|
|
|
|
--For some reason, not checking this crash Cryptid on start up
|
|
if not G.playing_cards then return false end
|
|
|
|
local count = 0
|
|
|
|
for k, v in ipairs(G.playing_cards) do
|
|
if v.config.center.disenhancement then
|
|
count = count+1
|
|
end
|
|
end
|
|
|
|
return count > #G.playing_cards * 0.3
|
|
end,
|
|
}
|
|
|
|
end
|
|
|
|
if unstb_config.gameplay.seal_suit then
|
|
|
|
--Vessel
|
|
SMODS.Consumable{
|
|
set = 'Spectral', atlas = 'spectral',
|
|
key = 'spc_vessel',
|
|
|
|
config = {extra = {count = 4}},
|
|
--discovered = true,
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
info_queue[#info_queue+1] = {set = 'Other', key = 'suit_seal'}
|
|
return {vars = {card.ability.extra.count}}
|
|
end,
|
|
|
|
can_use = function(self, card)
|
|
local selected_hands = get_selected_cards(card, G.hand.highlighted)
|
|
|
|
if G.hand and (#selected_hands > 1 and #selected_hands <= card.ability.extra.count) then
|
|
|
|
local targetCard = selected_hands[1]
|
|
--Sort to get the actual target card
|
|
for i=1, #selected_hands do if selected_hands[i].T.x < targetCard.T.x then targetCard = selected_hands[i] end end
|
|
|
|
return not targetCard.config.center.no_suit and (unstb_global.SUIT_SEAL[targetCard.base.suit] or {}).seal_key
|
|
end
|
|
return false
|
|
end,
|
|
|
|
use = function(self, card)
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
play_sound('tarot1')
|
|
card:juice_up(0.3, 0.5)
|
|
return true end })
|
|
|
|
--Figure out what is left card, what is the left card
|
|
local targetCard = G.hand.highlighted[1]
|
|
--Sort to get the actual target card
|
|
for i=1, #G.hand.highlighted do if G.hand.highlighted[i].T.x < targetCard.T.x then targetCard = G.hand.highlighted[i] end end
|
|
|
|
--Adds Suit Seal to the right card (or none, if there's no matching suit)
|
|
local suit_seal = (unstb_global.SUIT_SEAL[targetCard.base.suit] or {}).seal_key
|
|
|
|
for i=1, #G.hand.highlighted do
|
|
if G.hand.highlighted[i] ~= targetCard then
|
|
G.hand.highlighted[i]:set_seal(suit_seal, nil, true)
|
|
end
|
|
end
|
|
|
|
--Destroy the leftmost card
|
|
local destroyed_cards = {targetCard}
|
|
|
|
event({
|
|
trigger = 'after',
|
|
delay = 0.1,
|
|
func = function()
|
|
for i=#destroyed_cards, 1, -1 do
|
|
local c = destroyed_cards[i]
|
|
if c.ability.name == 'Glass Card' then
|
|
c:shatter()
|
|
else
|
|
c:start_dissolve(nil, i == #destroyed_cards)
|
|
end
|
|
end
|
|
return true end })
|
|
--Calling Jokers to process the card destroying
|
|
delay(0.3)
|
|
for i = 1, #G.jokers.cards do
|
|
G.jokers.cards[i]:calculate_joker({remove_playing_cards = true, removed = destroyed_cards})
|
|
end
|
|
end,
|
|
|
|
pos = get_coordinates(1),
|
|
}
|
|
|
|
--Conferment
|
|
SMODS.Consumable{
|
|
set = 'Spectral', atlas = 'spectral',
|
|
key = 'spc_conferment',
|
|
|
|
config = {extra = {count = 4, cost = 8}},
|
|
--discovered = true,
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
info_queue[#info_queue+1] = {set = 'Other', key = 'unstb_face_seal'}
|
|
return {vars = {card and card.ability.extra.count or self.config.extra.count, card and card.ability.extra.cost or self.config.extra.cost}}
|
|
end,
|
|
|
|
can_use = function(self, card)
|
|
if G.hand and #G.hand.cards > 1 then
|
|
|
|
--Check if the hand contains at least one non-face card
|
|
for i = 1, #G.hand.cards do
|
|
if not G.hand.cards[i]:is_face() then
|
|
return true
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
return false
|
|
end,
|
|
|
|
use = function(self, card)
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
play_sound('tarot1')
|
|
card:juice_up(0.3, 0.5)
|
|
return true end })
|
|
|
|
|
|
for i = 1, card.ability.extra.count do
|
|
|
|
event({
|
|
trigger = 'after',
|
|
delay = 0.2,
|
|
func = function()
|
|
local hand_card = {}
|
|
|
|
--Pool All eligible cards in hand, this has to be done each repetition
|
|
--Maybe there could be a prettier way for this?
|
|
for i = 1, #G.hand.cards do
|
|
if not G.hand.cards[i]:is_face() then
|
|
hand_card[#hand_card+1] = G.hand.cards[i]
|
|
end
|
|
end
|
|
|
|
local target_card = pseudorandom_element(hand_card, pseudoseed('conferment'))
|
|
|
|
if target_card then
|
|
target_card:set_seal('unstb_face', nil, true)
|
|
end
|
|
return true end
|
|
})
|
|
|
|
end
|
|
|
|
--Always decrease regardless of the current money
|
|
ease_dollars(-card.ability.extra.cost, true)
|
|
|
|
end,
|
|
|
|
pos = get_coordinates(2),
|
|
}
|
|
|
|
end
|
|
|
|
if unstb_config.rank.rank_binary then
|
|
|
|
--Amnesia
|
|
SMODS.Consumable{
|
|
set = 'Spectral', atlas = 'spectral',
|
|
key = 'spc_amnesia',
|
|
|
|
config = {extra = {count = 3}},
|
|
--discovered = true,
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
|
|
return {vars = {card and card.ability.extra.count or self.config.extra.count}}
|
|
end,
|
|
|
|
can_use = function(self, card)
|
|
if G.hand and #G.hand.cards > 1 then
|
|
|
|
--Check if the hand contains at least one non-face card
|
|
for i = 1, #G.hand.cards do
|
|
if not G.hand.cards[i]:is_face() then
|
|
return true
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
return false
|
|
end,
|
|
|
|
use = function(self, card)
|
|
--Enable Rank Flag
|
|
setPoolRankFlagEnable('unstb_0', true);
|
|
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
play_sound('tarot1')
|
|
card:juice_up(0.3, 0.5)
|
|
return true end })
|
|
|
|
--Based on Basegame's Immolate
|
|
local converted_card = {}
|
|
|
|
local temp_hand = {}
|
|
for k, v in ipairs(G.hand.cards) do temp_hand[#temp_hand+1] = v end
|
|
table.sort(temp_hand, function (a, b) return not a.playing_card or not b.playing_card or a.playing_card < b.playing_card end)
|
|
pseudoshuffle(temp_hand, pseudoseed('amnesia'))
|
|
|
|
for i = 1, card.ability.extra.count do converted_card[#converted_card+1] = temp_hand[i] end
|
|
|
|
if #converted_card > 0 then
|
|
--Animation from Basegame Tarot
|
|
for i=1, #converted_card do
|
|
local percent = 1.15 - (i-0.999)/(#converted_card-0.998)*0.3
|
|
event({trigger = 'after',delay = 0.15,func = function() converted_card[i]:flip();play_sound('card1', percent);converted_card[i]:juice_up(0.3, 0.3);return true end })
|
|
end
|
|
delay(0.2)
|
|
|
|
--Handle the conversion
|
|
for i=1, #converted_card do
|
|
event({trigger = 'after',delay = 0.1,func = function()
|
|
SMODS.change_base(converted_card[i], nil, 'unstb_0')
|
|
return true end })
|
|
end
|
|
|
|
for i=1, #converted_card do
|
|
local percent = 0.85 + (i-0.999)/(#converted_card-0.998)*0.3
|
|
event({trigger = 'after',delay = 0.15,func = function() converted_card[i]:flip();play_sound('tarot2', percent, 0.6);converted_card[i]:juice_up(0.3, 0.3);return true end })
|
|
end
|
|
delay(0.5)
|
|
end
|
|
end,
|
|
|
|
pos = get_coordinates(3),
|
|
}
|
|
|
|
end
|
|
|
|
if unstb_config.rank.rank_21 then
|
|
|
|
--Altar
|
|
SMODS.Consumable{
|
|
set = 'Spectral', atlas = 'spectral',
|
|
key = 'spc_altar',
|
|
|
|
config = {extra = {destroy_count = 4, create_count = 3}},
|
|
--discovered = true,
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
|
|
return {vars = {card and card.ability.extra.destroy_count or self.config.extra.destroy_count, card and card.ability.extra.create_count or self.config.extra.create_count}}
|
|
end,
|
|
|
|
can_use = function(self, card)
|
|
if G.hand and #G.hand.cards > 1 then
|
|
return true
|
|
end
|
|
return false
|
|
end,
|
|
|
|
use = function(self, card)
|
|
--Enable Rank Flag
|
|
setPoolRankFlagEnable('unstb_21', true);
|
|
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
play_sound('tarot1')
|
|
card:juice_up(0.3, 0.5)
|
|
return true end })
|
|
|
|
--Based on Basegame's Immolate
|
|
local destroyed_cards = {}
|
|
|
|
local temp_hand = {}
|
|
for k, v in ipairs(G.hand.cards) do temp_hand[#temp_hand+1] = v end
|
|
table.sort(temp_hand, function (a, b) return not a.playing_card or not b.playing_card or a.playing_card < b.playing_card end)
|
|
pseudoshuffle(temp_hand, pseudoseed('altar'))
|
|
|
|
for i = 1, card.ability.extra.destroy_count do destroyed_cards[#destroyed_cards+1] = temp_hand[i] end
|
|
|
|
--Destroy Cards
|
|
event({
|
|
trigger = 'after',
|
|
delay = 0.1,
|
|
func = function()
|
|
for i=#destroyed_cards, 1, -1 do
|
|
local c = destroyed_cards[i]
|
|
--print(c)
|
|
|
|
if c.ability.name == 'Glass Card' then
|
|
c:shatter()
|
|
else
|
|
c:start_dissolve(nil, i == #destroyed_cards)
|
|
end
|
|
end
|
|
return true end })
|
|
--Calling Jokers to process the card destroying
|
|
delay(0.3)
|
|
--print('joker')
|
|
for i = 1, #G.jokers.cards do
|
|
G.jokers.cards[i]:calculate_joker({remove_playing_cards = true, removed = destroyed_cards})
|
|
end
|
|
|
|
--Adding New Cards
|
|
event({
|
|
trigger = 'after',
|
|
delay = 0.7,
|
|
func = function()
|
|
local cards = {}
|
|
for i=1, card.ability.extra.create_count do
|
|
cards[i] = true
|
|
local _rank = SMODS.Ranks['unstb_21']
|
|
local _suit = pseudorandom_element(SMODS.Suits, pseudoseed('altar')) or SMODS.Suits['Spades']
|
|
|
|
--Pooling Enhancements
|
|
local cen_pool = {}
|
|
for k, v in pairs(G.P_CENTER_POOLS["Enhanced"]) do
|
|
if not v.replace_base_card and not v.disenhancement then
|
|
cen_pool[#cen_pool+1] = v
|
|
end
|
|
end
|
|
|
|
create_playing_card({front = G.P_CARDS[(_suit.card_key)..'_'..(_rank.card_key)], center = pseudorandom_element(cen_pool, pseudoseed('altar'))}, G.hand, nil, i ~= 1, {G.C.SECONDARY_SET.Spectral})
|
|
end
|
|
playing_card_joker_effects(cards)
|
|
return true end })
|
|
|
|
end,
|
|
|
|
pos = get_coordinates(4),
|
|
}
|
|
|
|
end
|
|
|
|
if check_enable_taglist({'edition_upgrade', 'enh_disenh'}) then
|
|
|
|
--Devil's Contract
|
|
SMODS.Consumable{
|
|
set = 'Spectral', atlas = 'spectral',
|
|
key = 'spc_contract',
|
|
|
|
config = {extra = {upgrade_count = 2, disenc_count = 2}},
|
|
--discovered = true,
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
|
|
info_queue[#info_queue+1] = {set = 'Other', key = 'upgrade_edition'}
|
|
info_queue[#info_queue+1] = {set = 'Other', key = 'disenhancement'}
|
|
|
|
return {vars = {card and card.ability.extra.upgrade_count or self.config.extra.upgrade_count, card and card.ability.extra.disenc_count or self.config.extra.disenc_count}}
|
|
end,
|
|
|
|
can_use = function(self, card)
|
|
if G.hand and #G.hand.cards > 1 then
|
|
return true
|
|
end
|
|
return false
|
|
end,
|
|
|
|
use = function(self, card)
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
play_sound('tarot1')
|
|
card:juice_up(0.3, 0.5)
|
|
return true end })
|
|
|
|
--Based on Basegame's Immolate
|
|
local upgrade_card = {}
|
|
local disenc_card = {}
|
|
|
|
local temp_hand = {}
|
|
for k, v in ipairs(G.hand.cards) do temp_hand[#temp_hand+1] = v end
|
|
table.sort(temp_hand, function (a, b) return not a.playing_card or not b.playing_card or a.playing_card < b.playing_card end)
|
|
pseudoshuffle(temp_hand, pseudoseed('dvcontract'))
|
|
|
|
for i = 1, card.ability.extra.upgrade_count do upgrade_card[#upgrade_card+1] = temp_hand[i] end
|
|
for i = card.ability.extra.upgrade_count+1, card.ability.extra.upgrade_count+card.ability.extra.disenc_count do disenc_card[#disenc_card+1] = temp_hand[i] end
|
|
|
|
--Upgrade the card
|
|
for i=1, #upgrade_card do
|
|
event({trigger = 'after',delay = 0.1,func = function()
|
|
edition_upgrade(upgrade_card[i])
|
|
return true end })
|
|
end
|
|
|
|
--Disenhanced the Remaining Cards
|
|
if #disenc_card > 0 then
|
|
--Animation from Basegame Tarot
|
|
for i=1, #disenc_card do
|
|
local percent = 1.15 - (i-0.999)/(#disenc_card-0.998)*0.3
|
|
event({trigger = 'after',delay = 0.15,func = function() disenc_card[i]:flip();play_sound('card1', percent);disenc_card[i]:juice_up(0.3, 0.3);return true end })
|
|
end
|
|
delay(0.2)
|
|
|
|
--Handle the conversion
|
|
for i=1, #disenc_card do
|
|
event({trigger = 'after',delay = 0.1,func = function()
|
|
disenc_card[i]:set_ability(G.P_CENTERS[pseudorandom_element({'m_unstb_radioactive', 'm_unstb_biohazard', 'm_unstb_poison'}, pseudoseed('dvcontract'))])
|
|
return true end })
|
|
end
|
|
|
|
for i=1, #disenc_card do
|
|
local percent = 0.85 + (i-0.999)/(#disenc_card-0.998)*0.3
|
|
event({trigger = 'after',delay = 0.15,func = function() disenc_card[i]:flip();play_sound('tarot2', percent, 0.6);disenc_card[i]:juice_up(0.3, 0.3);return true end })
|
|
end
|
|
delay(0.5)
|
|
end
|
|
end,
|
|
|
|
pos = get_coordinates(5),
|
|
}
|
|
|
|
end
|
|
|
|
end
|
|
|
|
--Other Spectrals
|
|
|
|
if unstb_config.gameplay.new_spectrals then
|
|
|
|
--Poltergeist
|
|
SMODS.Consumable{
|
|
set = 'Spectral', atlas = 'spectral',
|
|
key = 'spc_poltergeist',
|
|
|
|
config = {extra = {}},
|
|
--discovered = true,
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
|
|
return {vars = {}}
|
|
end,
|
|
|
|
can_use = function(self, card)
|
|
if G.hand and #G.jokers.cards > 1 then
|
|
|
|
--Check if there is at least one joker with edition
|
|
for i = 1, #G.jokers.cards do
|
|
if G.jokers.cards[i].edition then
|
|
return true
|
|
end
|
|
end
|
|
|
|
return false
|
|
end
|
|
return false
|
|
end,
|
|
|
|
use = function(self, card)
|
|
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
play_sound('tarot1')
|
|
card:juice_up(0.3, 0.5)
|
|
return true end })
|
|
|
|
local joker_list = G.jokers.cards
|
|
|
|
local temp_edition = {}
|
|
for k, v in ipairs(joker_list) do temp_edition[#temp_edition+1] = v.edition or 'none' end
|
|
pseudoshuffle(temp_edition, pseudoseed('poltergeist'))
|
|
|
|
--Give all joker new editions
|
|
--Animation from Basegame Tarot
|
|
for i=1, #joker_list do
|
|
local percent = 1.15 - (i-0.999)/(#joker_list-0.998)*0.3
|
|
event({trigger = 'after',delay = 0.15,func = function() joker_list[i]:flip();play_sound('card1', percent);joker_list[i]:juice_up(0.3, 0.3);return true end })
|
|
end
|
|
delay(0.2)
|
|
|
|
--Set the new edition
|
|
for i=1, #joker_list do
|
|
event({trigger = 'after',delay = 0.1,func = function()
|
|
|
|
local edition = temp_edition[i]
|
|
|
|
if edition == 'none' then
|
|
edition = nil
|
|
end
|
|
|
|
joker_list[i]:set_edition(edition, true, true)
|
|
return true end })
|
|
end
|
|
|
|
for i=1, #joker_list do
|
|
local percent = 0.85 + (i-0.999)/(#joker_list-0.998)*0.3
|
|
event({trigger = 'after',delay = 0.15,func = function() joker_list[i]:flip();play_sound('tarot2', percent, 0.6);joker_list[i]:juice_up(0.3, 0.3);return true end })
|
|
end
|
|
delay(0.5)
|
|
end,
|
|
|
|
pos = get_coordinates(6),
|
|
|
|
--Can spawn only if there is more than one joker, and at least one with edition
|
|
in_pool = function(self, args)
|
|
|
|
--For some reason, not checking this crash Cryptid on start up
|
|
if not G.jokers then return false end
|
|
|
|
if #G.jokers.cards > 1 then
|
|
for i=1, #G.jokers.cards do
|
|
if G.jokers.cards[i].edition then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
|
|
return false
|
|
end,
|
|
}
|
|
|
|
--Projection
|
|
SMODS.Consumable{
|
|
set = 'Spectral', atlas = 'spectral',
|
|
key = 'spc_projection',
|
|
|
|
config = {extra = {odds_break = 4}},
|
|
--discovered = true,
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
|
|
return {vars = {G.GAME and G.GAME.probabilities.normal or 1, card and card.ability.extra.odds_break or self.config.extra.odds_break}}
|
|
end,
|
|
|
|
can_use = function(self, card)
|
|
if G.hand and #G.jokers.cards > 1 and #G.jokers.highlighted ==1 and G.jokers.highlighted[1] then
|
|
|
|
--Check if there is at least one of the selected jokers have edition and is not the same
|
|
local joker = G.jokers.highlighted[1]
|
|
local position = nil
|
|
|
|
for i = 1, #G.jokers.cards do
|
|
if G.jokers.cards[i] == joker then position = i; break end
|
|
end
|
|
|
|
--Selected Joker is at the rightmost
|
|
if position==#G.jokers.cards then
|
|
return false
|
|
end
|
|
|
|
local nextjoker = G.jokers.cards[position+1]
|
|
|
|
--If both has edition, see if it's the same
|
|
if joker.edition and nextjoker.edition then
|
|
return joker.edition.key ~= nextjoker.edition.key
|
|
end
|
|
|
|
--Return true if at least one of them has edition
|
|
return joker.edition or nextjoker.edition
|
|
end
|
|
return false
|
|
end,
|
|
|
|
use = function(self, card)
|
|
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
play_sound('tarot1')
|
|
card:juice_up(0.3, 0.5)
|
|
return true end })
|
|
|
|
local joker = G.jokers.highlighted[1]
|
|
local position = nil
|
|
|
|
for i = 1, #G.jokers.cards do
|
|
if G.jokers.cards[i] == joker then position = i; break end
|
|
end
|
|
|
|
local nextjoker = G.jokers.cards[position+1]
|
|
|
|
local firstEdition = joker.edition
|
|
local nextEdition = nextjoker.edition
|
|
|
|
local joker_list = {joker, nextjoker}
|
|
|
|
--Animation from Basegame Tarot
|
|
for i=1, #joker_list do
|
|
local percent = 1.15 - (i-0.999)/(#joker_list-0.998)*0.3
|
|
event({trigger = 'after',delay = 0.15,func = function() joker_list[i]:flip();play_sound('card1', percent);joker_list[i]:juice_up(0.3, 0.3);return true end })
|
|
end
|
|
delay(0.2)
|
|
|
|
--Set the new edition
|
|
for i=1, #joker_list do
|
|
event({trigger = 'after',delay = 0.1,func = function()
|
|
joker:set_edition(nextEdition, true, true)
|
|
nextjoker:set_edition(firstEdition, true, true)
|
|
return true end })
|
|
end
|
|
|
|
for i=1, #joker_list do
|
|
local percent = 0.85 + (i-0.999)/(#joker_list-0.998)*0.3
|
|
event({trigger = 'after',delay = 0.15,func = function() joker_list[i]:flip();play_sound('tarot2', percent, 0.6);joker_list[i]:juice_up(0.3, 0.3);return true end })
|
|
end
|
|
delay(0.5)
|
|
|
|
--Destroy one of the joker
|
|
if pseudorandom('projection'..G.SEED) < G.GAME.probabilities.normal / card.ability.extra.odds_break then
|
|
local target = pseudorandom_element(joker_list, pseudoseed('projection'))
|
|
event({func = function()
|
|
target:start_dissolve({HEX("57ecab")}, nil, 1.6)
|
|
return true end })
|
|
forced_message("Failed...", target, G.C.BLACK, true)
|
|
end
|
|
|
|
|
|
end,
|
|
|
|
pos = get_coordinates(7),
|
|
|
|
--Can spawn only if there is at least more than 1 Joker with distinct edition
|
|
in_pool = function(self, args)
|
|
|
|
--For some reason, not checking this crash Cryptid on start up
|
|
if not G.jokers then return false end
|
|
|
|
local prev_edition = nil
|
|
|
|
if #G.jokers.cards > 1 then
|
|
--Set the first one as a pivot check
|
|
prev_edition = G.jokers.cards[1].edition
|
|
|
|
--Iterate through the rest
|
|
for i=2, #G.jokers.cards do
|
|
--If there is one Joker with different edition, breaks and return true
|
|
if prev_edition ~= G.jokers.cards[i].edition then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
|
|
return false
|
|
end,
|
|
}
|
|
|
|
unstb_global.siphon_blacklist = {}
|
|
unstb_global.siphon_blacklist['e_negative'] = true
|
|
|
|
--Global register function, just in case more modded edition can blackList them
|
|
function unstb_global.register_siphon_blacklist(edition_list)
|
|
for i=1, #edition_list do
|
|
unstb_global.siphon_blacklist[edition_list[i]] = true
|
|
end
|
|
end
|
|
|
|
--Siphon
|
|
SMODS.Consumable{
|
|
set = 'Spectral', atlas = 'spectral',
|
|
key = 'spc_siphon',
|
|
|
|
config = {extra = {count = 4}},
|
|
--discovered = true,
|
|
|
|
loc_vars = function(self, info_queue, card)
|
|
|
|
return {vars = {card and card.ability.extra.count or self.config.extra.count}}
|
|
end,
|
|
|
|
can_use = function(self, card)
|
|
if G.hand and #G.jokers.cards >= 1 and #G.jokers.highlighted ==1 and G.jokers.highlighted[1] then
|
|
return G.jokers.highlighted[1].edition and not unstb_global.siphon_blacklist[G.jokers.highlighted[1].edition.key]
|
|
end
|
|
return false
|
|
end,
|
|
|
|
use = function(self, card)
|
|
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
play_sound('tarot1')
|
|
card:juice_up(0.3, 0.5)
|
|
return true end })
|
|
|
|
local edition_card = {}
|
|
local temp_hand = {}
|
|
|
|
for k, v in ipairs(G.hand.cards) do temp_hand[#temp_hand+1] = v end
|
|
table.sort(temp_hand, function (a, b) return not a.playing_card or not b.playing_card or a.playing_card < b.playing_card end)
|
|
pseudoshuffle(temp_hand, pseudoseed('siphon'))
|
|
|
|
for i = 1, card.ability.extra.count do edition_card[#edition_card+1] = temp_hand[i] end
|
|
|
|
local joker = G.jokers.highlighted[1]
|
|
local edition = joker.edition
|
|
|
|
--Destroy the joker
|
|
|
|
event({func = function()
|
|
joker:start_dissolve({HEX("57ecab")}, nil, 1.6)
|
|
return true end })
|
|
delay(0.5)
|
|
|
|
--Upgrade the card
|
|
|
|
event({trigger = 'after',delay = 0.1,func = function()
|
|
for i=1, #edition_card do
|
|
edition_card[i]:set_edition(edition, true, i==1)
|
|
end
|
|
return true end })
|
|
|
|
|
|
end,
|
|
|
|
pos = get_coordinates(8),
|
|
|
|
--Can spawn only if there is one joker or more with edition
|
|
in_pool = function(self, args)
|
|
|
|
--For some reason, not checking this crash Cryptid on start up
|
|
if not G.jokers then return false end
|
|
|
|
if #G.jokers.cards >= 1 then
|
|
for i=1, #G.jokers.cards do
|
|
if G.jokers.cards[i].edition then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
|
|
return false
|
|
end,
|
|
}
|
|
|
|
end
|
|
|
|
--Vouchers
|
|
|
|
if unstb_config.gameplay.c_aux then
|
|
|
|
SMODS.Voucher({
|
|
object_type = "Voucher",
|
|
key = "aux1",
|
|
|
|
atlas = "voucher",
|
|
pos = { x = 0, y = 0 },
|
|
unlocked = true,
|
|
--discovered = true,
|
|
redeem = function(self)
|
|
event({
|
|
func = function()
|
|
G.GAME.auxiliary_rate = (G.GAME.auxiliary_rate or 0) + 2
|
|
return true
|
|
end,
|
|
})
|
|
end,
|
|
unredeem = function(self)
|
|
event({
|
|
func = function()
|
|
G.GAME.auxiliary_rate = (G.GAME.auxiliary_rate or 2) - 2
|
|
return true
|
|
end,
|
|
})
|
|
end
|
|
})
|
|
|
|
SMODS.Voucher({
|
|
object_type = "Voucher",
|
|
key = "aux2",
|
|
|
|
atlas = "voucher",
|
|
pos = { x = 1, y = 0 },
|
|
unlocked = true,
|
|
--discovered = true,
|
|
requires = { "v_unstb_aux1" },
|
|
})
|
|
|
|
end
|
|
|
|
-------- Joker Code Starts Here ------
|
|
|
|
--Basic Jokers
|
|
|
|
--Lunar Calendar
|
|
create_joker({
|
|
name = 'Lunar Calendar', id = 40,
|
|
rarity = 'Common', cost = 5,
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
vars = { {odds_spawn = 4} },
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
local suit = card and card.ability.extra and card.ability.extra.suit or 'Spades'
|
|
|
|
local suit_name = localize(suit, 'suits_singular')
|
|
local suit_color = G.C.SUITS[suit]
|
|
|
|
return {vars = {suit_name, G.GAME and G.GAME.probabilities.normal or 1, card.ability.extra.odds_spawn, colours = {suit_color}}}
|
|
end,
|
|
|
|
set_ability = function(self, card, initial, delay_sprites)
|
|
--Initialize variables
|
|
card.ability.extra.suit = pseudorandom_element(SMODS.Suits, pseudoseed('lunarcalendar')).key --All suits, not just strictly in the deck
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
if context.individual and context.cardarea == G.play then
|
|
--Main Context
|
|
if context.other_card:is_suit(card.ability.extra.suit) then
|
|
local isActivated = pseudorandom('lunarcalendar'..G.SEED) < G.GAME.probabilities.normal / card.ability.extra.odds_spawn
|
|
|
|
if isActivated then
|
|
if #G.consumeables.cards + G.GAME.consumeable_buffer < G.consumeables.config.card_limit then
|
|
|
|
G.GAME.consumeable_buffer = G.GAME.consumeable_buffer + 1
|
|
event({func = function()
|
|
local created_card = create_card('Planet', G.consumeables, nil, nil, nil, nil, nil, nil)
|
|
created_card:add_to_deck()
|
|
G.consumeables:emplace(created_card)
|
|
G.GAME.consumeable_buffer = 0
|
|
return true end
|
|
})
|
|
|
|
forced_message("Planet", context.blueprint_card or card, G.C.SECONDARY_SET.Planet, true)
|
|
end
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
--End-of-round Randomize
|
|
if context.end_of_round and not context.other_card and not context.repetition and not context.game_over and not context.blueprint then
|
|
card.ability.extra.suit = pseudorandom_element(SMODS.Suits, pseudoseed('lunarcalendar')).key
|
|
return{
|
|
message = localize(card.ability.extra.suit, 'suits_singular'),
|
|
}
|
|
end
|
|
end,
|
|
})
|
|
|
|
--Dragon Hoard
|
|
create_joker({
|
|
name = 'Dragon Hoard', id = 42,
|
|
rarity = 'Common', cost = 4,
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
vars = {{mult_rate = 15}, {held_amount = 2}, {mult_current = 0}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
|
|
local held_amount = G.consumeables and #G.consumeables.cards or 0
|
|
|
|
local mult_current = card.ability.extra.mult_rate * math.floor(held_amount/card.ability.extra.held_amount)
|
|
|
|
return { vars = {card.ability.extra.mult_rate, card.ability.extra.held_amount, mult_current}}
|
|
end,
|
|
|
|
|
|
calculate = function(self, card, context)
|
|
--Main context
|
|
if context.joker_main then
|
|
|
|
card.ability.extra.mult_current = card.ability.extra.mult_rate * math.floor(#G.consumeables.cards/card.ability.extra.held_amount)
|
|
|
|
if card.ability.extra.mult_current > 0 then
|
|
return {
|
|
mult_mod = card.ability.extra.mult_current,
|
|
message = localize { type = 'variable', key = 'a_mult', vars = { card.ability.extra.mult_current } }
|
|
}
|
|
end
|
|
end
|
|
|
|
end,
|
|
})
|
|
|
|
--Card Dealer
|
|
create_joker({
|
|
name = 'Card Dealer', id = 41,
|
|
rarity = 'Common', cost = 5,
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
vars = { {chip_rate = 15}, {chips = 0} },
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
|
|
return { vars = {card.ability.extra.chip_rate, card.ability.extra.chips}}
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
|
|
if context.joker_main then
|
|
return {
|
|
chip_mod = card.ability.extra.chips,
|
|
message = localize { type = 'variable', key = 'a_chips', vars = { card.ability.extra.chips } }
|
|
}
|
|
end
|
|
|
|
if context.before and context.full_hand and not context.blueprint then
|
|
card.ability.extra.chips = card.ability.extra.chips + #context.full_hand * card.ability.extra.chip_rate
|
|
|
|
return {
|
|
message = 'Upgraded!',
|
|
colour = G.C.CHIPS,
|
|
card = card
|
|
}
|
|
end
|
|
|
|
--End-of-round Resets
|
|
if context.end_of_round and not context.other_card and not context.repetition and not context.game_over and not context.blueprint then
|
|
card.ability.extra.chips = 0
|
|
return{
|
|
message = localize('k_reset'),
|
|
colour = G.C.RED
|
|
}
|
|
end
|
|
|
|
end,
|
|
})
|
|
|
|
--Match Three
|
|
create_joker({
|
|
name = 'Match Three', id = 67,
|
|
rarity = 'Common', cost = 6,
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
vars = { {mult = 15}, {count = 3} },
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
|
|
return { vars = {card.ability.extra.mult, card.ability.extra.count}}
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
|
|
if context.joker_main then
|
|
|
|
--Not enough card
|
|
if #context.scoring_hand < card.ability.extra.count then
|
|
return
|
|
end
|
|
|
|
local card_count = 1
|
|
local max_card_count = 0
|
|
local current_suit = context.scoring_hand[1].base.suit
|
|
|
|
for i=2, #context.scoring_hand do
|
|
if context.scoring_hand[i]:is_suit(current_suit) then
|
|
card_count = card_count + 1
|
|
else
|
|
--reset count
|
|
|
|
if card_count > max_card_count then
|
|
max_card_count = card_count
|
|
end
|
|
|
|
card_count = 1
|
|
current_suit = context.scoring_hand[i].base.suit
|
|
end
|
|
end
|
|
|
|
if card_count > max_card_count then
|
|
max_card_count = card_count
|
|
end
|
|
|
|
--print(max_card_count)
|
|
--print(card.ability.extra.count)
|
|
|
|
if max_card_count >= card.ability.extra.count then
|
|
return {
|
|
mult_mod = card.ability.extra.mult,
|
|
message = localize { type = 'variable', key = 'a_mult', vars = { card.ability.extra.mult } }
|
|
}
|
|
end
|
|
end
|
|
|
|
end,
|
|
})
|
|
|
|
create_joker({
|
|
name = 'Furry Joker', id = 44,
|
|
rarity = 'Uncommon', cost = 7,
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
vars = { {odds_poly = 8} },
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
info_queue[#info_queue+1] = G.P_CENTERS['m_wild']
|
|
info_queue[#info_queue+1] = G.P_CENTERS['e_polychrome']
|
|
|
|
return { vars = {G.GAME and G.GAME.probabilities.normal or 1, card.ability.extra.odds_poly}}
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
if context.after and context.scoring_hand then
|
|
local polyAmount = 0
|
|
for i=1, #context.scoring_hand do
|
|
local current_card = context.scoring_hand[i]
|
|
if current_card.config.center == G.P_CENTERS.m_wild and (current_card.edition or {}).key ~= 'e_polychrome' and not current_card.becoming_poly then
|
|
local isActivated = pseudorandom('furry'..G.SEED) < G.GAME.probabilities.normal / card.ability.extra.odds_poly
|
|
if isActivated then
|
|
current_card.becoming_poly = true
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
big_juice(context.blueprint_card or card)
|
|
current_card:set_edition("e_polychrome", true, false)
|
|
current_card.becoming_poly = nil
|
|
return true end
|
|
})
|
|
polyAmount = polyAmount+1
|
|
end
|
|
end
|
|
end
|
|
if polyAmount>0 then
|
|
delay(2.5)
|
|
end
|
|
end
|
|
end,
|
|
|
|
custom_in_pool = function(self, args)
|
|
|
|
--Spawns if there is at least one wild card in the deck
|
|
for _, v in pairs(G.playing_cards) do
|
|
if v.config.center == G.P_CENTERS.m_wild then return true end
|
|
end
|
|
return false
|
|
|
|
end
|
|
})
|
|
|
|
--Hook set_cost to allow messing with prices
|
|
local ref_set_cost = Card.set_cost
|
|
function Card.set_cost(self)
|
|
ref_set_cost(self)
|
|
for k,v in ipairs(SMODS.find_card("j_unstb_luxurious_handbag")) do
|
|
self.cost = self.cost + v.ability.extra.inflation
|
|
end
|
|
|
|
end
|
|
|
|
create_joker({
|
|
name = 'Luxurious Handbag', id = 43,
|
|
rarity = 'Uncommon', cost = 6,
|
|
|
|
blueprint = false, eternal = true, perishable = true,
|
|
|
|
vars = { {add_slot = 4}, {inflation = 2} },
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
return { vars = {card.ability.extra.add_slot, card.ability.extra.inflation}}
|
|
end,
|
|
|
|
add_to_deck = function(self, card, from_debuff)
|
|
|
|
G.consumeables:change_size(card.ability.extra.add_slot)
|
|
|
|
--Recalculate all prices in the shop
|
|
event({func = function()
|
|
for k, v in pairs(G.I.CARD) do
|
|
if v.set_cost then v:set_cost() end
|
|
end
|
|
return true end
|
|
})
|
|
|
|
end,
|
|
|
|
remove_from_deck = function(self, card, from_debuff)
|
|
G.consumeables:change_size(-card.ability.extra.add_slot)
|
|
|
|
--Recalculate all prices in the shop
|
|
event({func = function()
|
|
for k, v in pairs(G.I.CARD) do
|
|
if v.set_cost then v:set_cost() end
|
|
end
|
|
return true end
|
|
})
|
|
end,
|
|
|
|
--Actual functionality is in Card.set_cost hook mostly
|
|
--[[
|
|
calculate = function(self, card, context)
|
|
|
|
end,]]
|
|
})
|
|
|
|
--Portal
|
|
create_joker({
|
|
name = 'Portal', id = 39,
|
|
rarity = 'Uncommon', cost = 7,
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
--vars = { {times = 1}},
|
|
|
|
--Actual ability is in ustb_get_straight
|
|
--[[calculate = function(self, card, context)
|
|
|
|
end,]]
|
|
})
|
|
|
|
--Suit Seal Support Jokers
|
|
|
|
--Vainglorious Joker
|
|
create_joker({
|
|
name = 'Vainglorious Joker', id = 32,
|
|
rarity = 'Common', cost = 5,
|
|
|
|
gameplay_tag = {'seal_suit'},
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
vars = { {mult = 5} },
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
info_queue[#info_queue+1] = {set = 'Other', key = 'suit_seal'}
|
|
return {vars = {card.ability.extra.mult}}
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
if context.individual and context.cardarea == G.play then
|
|
if context.other_card.seal and SMODS.Seals[context.other_card.seal] and SMODS.Seals[context.other_card.seal].suit_seal then
|
|
--big_juice(context.blueprint_card or card)
|
|
return {
|
|
mult = card.ability.extra.mult,
|
|
card = card
|
|
}
|
|
end
|
|
end
|
|
end,
|
|
|
|
custom_in_pool = function(self, args)
|
|
|
|
--Spawns if there is at least one card with suit seal
|
|
for _, v in pairs(G.playing_cards) do
|
|
if v.seal and SMODS.Seals[v.seal] and SMODS.Seals[v.seal].suit_seal then return true end
|
|
end
|
|
return false
|
|
|
|
end
|
|
})
|
|
|
|
--Acedia Joker
|
|
create_joker({
|
|
name = 'Acedia Joker', id = 31,
|
|
rarity = 'Common', cost = 5,
|
|
|
|
gameplay_tag = {'seal_suit'},
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
vars = { {mult = 10} },
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
info_queue[#info_queue+1] = {set = 'Other', key = 'suit_seal'}
|
|
return {vars = {card.ability.extra.mult}}
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
if context.individual and context.cardarea == G.play then
|
|
if context.other_card.seal and SMODS.Seals[context.other_card.seal] and SMODS.Seals[context.other_card.seal].suit_seal then
|
|
local is_activate = false
|
|
|
|
--If same suit, returns true immediately. This should also handle Wild Card cases and other Joker-related calculation probably?
|
|
--I hope so, if there's a case that slips by I'll be crying
|
|
if context.other_card:is_suit(SMODS.Seals[context.other_card.seal].suit_seal, nil, nil, true) then
|
|
is_activate = true
|
|
|
|
--Otherwise, checks suit group
|
|
elseif get_suit_group(context.other_card.base.suit) == get_suit_group(SMODS.Seals[context.other_card.seal].suit_seal) then
|
|
is_activate = true
|
|
end
|
|
|
|
if is_activate then
|
|
return {
|
|
mult = card.ability.extra.mult,
|
|
card = card
|
|
}
|
|
end
|
|
end
|
|
end
|
|
end,
|
|
|
|
custom_in_pool = function(self, args)
|
|
|
|
--Spawns if there is at least one card with suit seal
|
|
for _, v in pairs(G.playing_cards) do
|
|
if v.seal and SMODS.Seals[v.seal] and SMODS.Seals[v.seal].suit_seal then return true end
|
|
end
|
|
return false
|
|
|
|
end
|
|
})
|
|
|
|
--Cinnabar
|
|
create_joker({
|
|
name = 'Cinnabar', id = 33,
|
|
rarity = 'Uncommon', cost = 7,
|
|
|
|
gameplay_tag = {'seal_suit', 'c_aux'},
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
vars = { {odds = 6} },
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
info_queue[#info_queue+1] = {set = 'Other', key = 'suit_seal'}
|
|
return {vars = {G.GAME and G.GAME.probabilities.normal or 1, card.ability.extra.odds}}
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
if context.individual and context.cardarea == G.play then
|
|
if context.other_card.seal and SMODS.Seals[context.other_card.seal] and SMODS.Seals[context.other_card.seal].suit_seal then
|
|
local isActivated = pseudorandom('cinnabar'..G.SEED) < G.GAME.probabilities.normal / card.ability.extra.odds
|
|
|
|
if isActivated then
|
|
local created_card = unstb_global.SUIT_SEAL[SMODS.Seals[context.other_card.seal].suit_seal].aux_key
|
|
if #G.consumeables.cards + G.GAME.consumeable_buffer < G.consumeables.config.card_limit then
|
|
|
|
G.GAME.consumeable_buffer = G.GAME.consumeable_buffer + 1
|
|
event({func = function()
|
|
local created_card = create_card('Auxiliary', G.consumeables, nil, nil, nil, nil, created_card, nil)
|
|
created_card:add_to_deck()
|
|
G.consumeables:emplace(created_card)
|
|
G.GAME.consumeable_buffer = 0
|
|
return true end
|
|
})
|
|
|
|
forced_message("Auxiliary", context.blueprint_card or card, G.C.UNSTB_AUX, true)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end,
|
|
|
|
custom_in_pool = function(self, args)
|
|
|
|
--Spawns if there is at least one card with suit seal
|
|
for _, v in pairs(G.playing_cards) do
|
|
if v.seal and SMODS.Seals[v.seal] and SMODS.Seals[v.seal].suit_seal then return true end
|
|
end
|
|
return false
|
|
|
|
end
|
|
})
|
|
|
|
--Auxiliary Support
|
|
|
|
--Free Trial
|
|
create_joker({
|
|
name = 'Free Trial', id = 54,
|
|
rarity = 'Uncommon', cost = 4,
|
|
|
|
gameplay_tag = {'c_aux'},
|
|
|
|
vars = {{odds = 4}},
|
|
custom_vars = function(self, info_queue, card)
|
|
info_queue[#info_queue+1] = {key = 'e_negative_consumable', set = 'Edition', config = {extra = 1}}
|
|
|
|
return {vars = {G.GAME and G.GAME.probabilities.normal or 1, card.ability.extra.odds}}
|
|
end,
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
calculate = function(self, card, context)
|
|
|
|
if context.using_consumeable then
|
|
if context.consumeable.ability.set == "Auxiliary" then
|
|
if pseudorandom('freetrial'..G.SEED) < G.GAME.probabilities.normal / card.ability.extra.odds then
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
if G.consumeables.config.card_limit >= #G.consumeables.cards then
|
|
play_sound('timpani')
|
|
local c = create_card('Auxiliary', G.consumeables, nil, nil, nil, nil, nil, 'freetrial')
|
|
c:set_edition({negative = true}, true)
|
|
c:add_to_deck()
|
|
G.consumeables:emplace(c)
|
|
|
|
big_juice(context.blueprint_card or card)
|
|
card_eval_status_text(context.blueprint_card or card,'extra',nil, nil, nil,{message = "Free Trial", colour = G.C.UNSTB_AUX, instant = true})
|
|
|
|
--forced_message("Free Trial!", context.blueprint_card or card, G.C.UNSTB_AUX, )
|
|
end
|
|
return true end })
|
|
|
|
end
|
|
end
|
|
end
|
|
end
|
|
})
|
|
|
|
--Extended Warranty
|
|
create_joker({
|
|
name = 'Extended Warranty', id = 55,
|
|
rarity = 'Rare', cost = 8,
|
|
|
|
gameplay_tag = {'c_aux'},
|
|
|
|
vars = {{xmult = 1.5}},
|
|
custom_vars = function(self, info_queue, card)
|
|
return {vars = {card.ability.extra.xmult}}
|
|
end,
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
calculate = function(self, card, context)
|
|
|
|
if context.joker_main then
|
|
for i=1, #G.consumeables.cards do
|
|
if G.consumeables.cards[i].ability.set == "Auxiliary" then
|
|
|
|
event({trigger = 'after', func = function()
|
|
(context.blueprint_card or card):juice_up(0.5, 0.5)
|
|
return true end
|
|
})
|
|
|
|
SMODS.calculate_effect({xmult = card.ability.extra.xmult}, G.consumeables.cards[i])
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
})
|
|
|
|
--Technician
|
|
create_joker({
|
|
name = 'Technician', id = 56,
|
|
rarity = 'Common', cost = 6,
|
|
|
|
gameplay_tag = {'c_aux'},
|
|
|
|
vars = {{chip_rate = 15}, {chips = 0}},
|
|
custom_vars = function(self, info_queue, card)
|
|
return {vars = {card.ability.extra.chip_rate, card.ability.extra.chips}}
|
|
end,
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
set_ability = function(self, card, initial, delay_sprites)
|
|
if G.GAME and G.GAME.consumeable_usage_total then
|
|
card.ability.extra.chips = (G.GAME.consumeable_usage_total.auxiliary or 0) * card.ability.extra.chip_rate
|
|
else
|
|
card.ability.extra.chips = 0
|
|
end
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
|
|
--Upgrades
|
|
if context.using_consumeable and not context.blueprint then
|
|
if context.consumeable.ability.set == "Auxiliary" then
|
|
card.ability.extra.chips = card.ability.extra.chips + card.ability.extra.chip_rate
|
|
event({
|
|
func = function()
|
|
big_juice(card)
|
|
forced_message("Upgraded!", card, G.C.CHIPS, true)
|
|
--card_eval_status_text(card,'extra',nil, nil, nil,{message = "Upgraded", colour = G.C.MULT, instant = true})
|
|
return true end})
|
|
end
|
|
end
|
|
|
|
--Main context
|
|
if context.joker_main then
|
|
if card.ability.extra.chips > 0 then
|
|
return {
|
|
chip_mod = card.ability.extra.chips,
|
|
message = localize { type = 'variable', key = 'a_chips', vars = { card.ability.extra.chips } }
|
|
}
|
|
end
|
|
end
|
|
|
|
end
|
|
})
|
|
|
|
--Season Pass
|
|
create_joker({
|
|
name = 'Season Pass', id = 57,
|
|
rarity = 'Uncommon', cost = 5,
|
|
|
|
gameplay_tag = {'c_aux'},
|
|
|
|
vars = {{odds = 4}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
|
|
return {vars = {G.GAME and G.GAME.probabilities.normal or 1, card.ability.extra.odds}}
|
|
end,
|
|
|
|
blueprint = true, eternal = true,
|
|
|
|
calculate = function(self, card, context)
|
|
if context.discard then
|
|
if not context.other_card.debuff and context.other_card:is_face() and pseudorandom('season_pass'..G.SEED) < G.GAME.probabilities.normal / card.ability.extra.odds then
|
|
--Create consumable
|
|
if #G.consumeables.cards + G.GAME.consumeable_buffer < G.consumeables.config.card_limit then
|
|
|
|
G.GAME.consumeable_buffer = G.GAME.consumeable_buffer + 1
|
|
event({func = function()
|
|
local created_card = create_card('Auxiliary', G.consumeables, nil, nil, nil, nil, nil, 'season_pass')
|
|
created_card:add_to_deck()
|
|
G.consumeables:emplace(created_card)
|
|
G.GAME.consumeable_buffer = 0
|
|
return true end
|
|
})
|
|
|
|
forced_message("Auxiliary", context.blueprint_card or card, G.C.UNSTB_AUX, 0.5)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
})
|
|
|
|
--BlackJack + Question Mark Line Jokers
|
|
|
|
--Black Jack
|
|
create_joker({
|
|
name = 'Black Jack', id = 15,
|
|
rarity = 'Common', cost = 5,
|
|
|
|
gameplay_tag = {'rank_21', 'j_alter'},
|
|
|
|
blueprint = true, eternal = true, perishable = false,
|
|
|
|
vars = {{maxRank = 21}, {chips = 0}},
|
|
|
|
calculate = function(self, card, context)
|
|
--This part handles the chip reward
|
|
if context.joker_main then
|
|
return {
|
|
chip_mod = card.ability.extra.chips,
|
|
message = localize { type = 'variable', key = 'a_chips', vars = { card.ability.extra.chips } }
|
|
}
|
|
end
|
|
|
|
--This part handles the scaling
|
|
if context.before and context.scoring_hand and not context.blueprint then
|
|
|
|
local totalRank = blackJack_evalrank(context.scoring_hand, card.ability.extra.maxRank)
|
|
|
|
if totalRank < card.ability.extra.maxRank then
|
|
card.ability.extra.chips = card.ability.extra.chips + totalRank
|
|
|
|
return {
|
|
message = 'Upgraded!',
|
|
colour = G.C.CHIPS,
|
|
card = card
|
|
}
|
|
elseif totalRank == card.ability.extra.maxRank then
|
|
card.ability.extra.chips = (card.ability.extra.chips + totalRank) * 2
|
|
|
|
local popup_msg = 'Black Jack!'
|
|
if card.ability.extra.maxRank ~= 21 then
|
|
popup_msg = 'Black Jack...?'
|
|
else
|
|
|
|
end
|
|
|
|
event({ trigger = 'after', delay = 0.2, func = function()
|
|
play_sound('multhit1')
|
|
return true end })
|
|
|
|
return {
|
|
message = popup_msg,
|
|
colour = G.C.RED,
|
|
card = card
|
|
}
|
|
else
|
|
card.ability.extra.chips = 0
|
|
|
|
event({ trigger = 'after', delay = 0.2, func = function()
|
|
play_sound('tarot1')
|
|
return true end })
|
|
|
|
return {
|
|
message = 'Busted...',
|
|
colour = G.C.BLACK,
|
|
card = card
|
|
}
|
|
end
|
|
|
|
|
|
end
|
|
end
|
|
})
|
|
|
|
--What
|
|
create_joker({
|
|
name = 'What', id = 14,
|
|
rarity = 'Rare', cost = 6,
|
|
|
|
gameplay_tag = {'rank_21'},
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
vars = { {chips = 420}, {mult = 69} },
|
|
|
|
calculate = function(self, card, context)
|
|
if context.individual and context.cardarea == G.play then
|
|
if context.other_card.base.value == 'unstb_???' then
|
|
return {
|
|
chips = card.ability.extra.chips,
|
|
mult = card.ability.extra.mult,
|
|
card = card
|
|
}
|
|
end
|
|
end
|
|
end,
|
|
|
|
custom_in_pool = function(self, args)
|
|
|
|
--Spawns if there is at least one rank ??? card
|
|
for _, v in pairs(G.playing_cards) do
|
|
if v.base.value == 'unstb_???' then return true end
|
|
end
|
|
return false
|
|
|
|
end
|
|
})
|
|
|
|
--Decimal-line Jokers
|
|
|
|
create_joker({
|
|
name = 'Floating Point Error', id = 34,
|
|
rarity = 'Uncommon', cost = 4,
|
|
|
|
gameplay_tag = {'rank_decimal'},
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
--vars = { {bonus = 10}},
|
|
|
|
calculate = function(self, card, context)
|
|
if context.individual and context.cardarea == G.play then
|
|
local currentCard = context.other_card
|
|
if is_decimal(currentCard) then
|
|
--big_juice(card)
|
|
|
|
currentCard.ability.perma_bonus = (currentCard.ability.perma_bonus or 0) + SMODS.Ranks[currentCard.base.value].nominal
|
|
|
|
event({ trigger = 'after', func = function()
|
|
big_juice(card)
|
|
return true end })
|
|
|
|
return {
|
|
extra = {message = "Upgrade!", colour = G.C.CHIPS},
|
|
colour = G.C.CHIPS,
|
|
card = currentCard
|
|
}
|
|
end
|
|
end
|
|
end,
|
|
|
|
custom_in_pool = function(self, args)
|
|
|
|
--Spawns if there is at least one decimal card
|
|
for _, v in pairs(G.playing_cards) do
|
|
if is_decimal(v) then return true end
|
|
end
|
|
return false
|
|
|
|
end
|
|
})
|
|
|
|
--Academic Journal
|
|
create_joker({
|
|
name = 'Academic Journal', id = 35,
|
|
rarity = 'Uncommon', cost = 6,
|
|
|
|
gameplay_tag = {'rank_decimal'},
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
vars = { {times_max = 5}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
return {vars = {card.ability.extra.times_max, card.ability.extra.times_max - card.ability.extra.times_current}}
|
|
end,
|
|
|
|
add_to_deck = function(self, card, from_debuff)
|
|
--Enable all decimal ranks card in pools
|
|
if not from_debuff then
|
|
setPoolRankFlagEnable('unstb_0.5', true);
|
|
setPoolRankFlagEnable('unstb_r2', true);
|
|
setPoolRankFlagEnable('unstb_e', true);
|
|
setPoolRankFlagEnable('unstb_Pi', true);
|
|
end
|
|
end,
|
|
|
|
set_ability = function(self, card, initial, delay_sprites)
|
|
--Initialize variables
|
|
card.ability.extra.times_current = 0
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
if context.before and not context.blueprint then
|
|
local is_active = true
|
|
|
|
if card.ability.extra.times_current < card.ability.extra.times_max then
|
|
for i=1, #context.scoring_hand do
|
|
if context.scoring_hand[i]:is_face() then
|
|
is_active = false
|
|
break
|
|
end
|
|
end
|
|
|
|
if is_active then
|
|
card.ability.extra.times_current = (card.ability.extra.times_current or 0) + 1
|
|
end
|
|
else
|
|
is_active = false
|
|
end
|
|
|
|
card.ability.extra.is_active = is_active
|
|
end
|
|
|
|
if context.after then
|
|
--Create Card if it activates
|
|
if card.ability.extra.is_active then
|
|
--Adds a card
|
|
event({trigger = 'after', func = function()
|
|
local rank = SMODS.Ranks[pseudorandom_element({'unstb_0.5', 'unstb_r2', 'unstb_e', 'unstb_Pi'}, pseudoseed('researchpaper')..G.SEED)].card_key
|
|
local suit = pseudorandom_element(SMODS.Suits, pseudoseed('researchpaper')..G.SEED).card_key
|
|
|
|
--Pooling Enhancements
|
|
local cen_pool = {}
|
|
for k, v in pairs(G.P_CENTER_POOLS["Enhanced"]) do
|
|
if not v.replace_base_card and not v.disenhancement then
|
|
cen_pool[#cen_pool+1] = v
|
|
end
|
|
end
|
|
|
|
local _card = Card(G.play.T.x + G.play.T.w/2, G.play.T.y, G.CARD_W, G.CARD_H, G.P_CARDS[suit..'_'..rank], pseudorandom_element(cen_pool, pseudoseed('researchpaper')..G.SEED), {playing_card = G.playing_card})
|
|
|
|
_card:start_materialize({G.C.SECONDARY_SET.Enhanced})
|
|
G.play:emplace(_card)
|
|
table.insert(G.playing_cards, _card)
|
|
|
|
big_juice(context.blueprint_card or card)
|
|
|
|
return true end
|
|
})
|
|
delay(1.5)
|
|
|
|
event({trigger = 'after', func = function()
|
|
G.deck.config.card_limit = G.deck.config.card_limit + 1
|
|
draw_card(G.play,G.deck, 90,'up', nil)
|
|
return true end
|
|
})
|
|
|
|
playing_card_joker_effects({true})
|
|
end
|
|
end
|
|
|
|
--End of round check, make sure it's checked absolutely once per round
|
|
if context.end_of_round and not context.other_card and not context.repetition and not context.game_over and not context.blueprint then
|
|
if card.ability.extra.times_current > 0 then
|
|
card.ability.extra.times_current = 0
|
|
return {
|
|
message = 'Reset!'
|
|
}
|
|
end
|
|
end
|
|
end,
|
|
})
|
|
|
|
--Engineer
|
|
create_joker({
|
|
name = 'Engineer', id = 37,
|
|
rarity = 'Common', cost = 5,
|
|
|
|
gameplay_tag = {'rank_decimal'},
|
|
|
|
blueprint = false, eternal = true, perishable = true,
|
|
|
|
--vars = { {times = 1}},
|
|
|
|
--Engineer's actual ability is in Card:get_id hook above
|
|
--[[calculate = function(self, card, context)
|
|
|
|
end,]]
|
|
|
|
custom_in_pool = function(self, args)
|
|
|
|
--Spawns if there is at least one decimal card
|
|
for _, v in pairs(G.playing_cards) do
|
|
if is_decimal(v) then return true end
|
|
end
|
|
return false
|
|
|
|
end
|
|
})
|
|
|
|
--Thesis Proposal
|
|
create_joker({
|
|
name = 'Thesis Proposal', id = 36,
|
|
rarity = 'Common', cost = 6,
|
|
|
|
gameplay_tag = {'rank_decimal'},
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
vars = {{ repetitions = 2 }},
|
|
|
|
calculate = function(self, card, context)
|
|
if context.cardarea == G.play and context.repetition and not context.repetition_only then
|
|
if is_decimal(context.other_card) then
|
|
return {
|
|
message = 'Again!',
|
|
repetitions = card.ability.extra.repetitions,
|
|
card = context.blueprint_card or card
|
|
}
|
|
end
|
|
end
|
|
end,
|
|
|
|
custom_in_pool = function(self, args)
|
|
|
|
--Spawns if there is at least one decimal card
|
|
for _, v in pairs(G.playing_cards) do
|
|
if is_decimal(v) then return true end
|
|
end
|
|
return false
|
|
|
|
end
|
|
})
|
|
|
|
--Rainbow Flag
|
|
create_joker({
|
|
name = 'Rainbow Flag', id = 38,
|
|
rarity = 'Uncommon', cost = 5,
|
|
|
|
gameplay_tag = {'rank_decimal'},
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
vars = { {odds_poly = 6} },
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
info_queue[#info_queue+1] = G.P_CENTERS['e_polychrome']
|
|
|
|
return { vars = {G.GAME and G.GAME.probabilities.normal or 1, card.ability.extra.odds_poly}}
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
if context.after and next(context.poker_hands['Straight']) and context.scoring_hand then
|
|
|
|
--Check if the Joker should be activated or not
|
|
local is_activate = false
|
|
for i=1, #context.scoring_hand do
|
|
if is_decimal(context.scoring_hand[i]) then
|
|
is_activate = true
|
|
break
|
|
end
|
|
end
|
|
|
|
if is_activate then
|
|
local eligible_card = {}
|
|
|
|
--Populate the list of eligible card
|
|
for i=1, #context.scoring_hand do
|
|
if (context.scoring_hand[i].edition or {}).key ~= 'e_polychrome' and not context.scoring_hand[i].becoming_poly then
|
|
eligible_card[#eligible_card+1] = context.scoring_hand[i]
|
|
end
|
|
end
|
|
|
|
--If there is eligible card, and the random chance hits
|
|
if #eligible_card > 0 and pseudorandom('rainbowflag'..G.SEED) < G.GAME.probabilities.normal / card.ability.extra.odds_poly then
|
|
local targetCard = pseudorandom_element(eligible_card, pseudoseed('rainbowflag')..G.SEED)
|
|
|
|
targetCard.becoming_poly = true
|
|
event({trigger = 'after', delay = 0.4, func = function()
|
|
big_juice(context.blueprint_card or card)
|
|
targetCard:set_edition("e_polychrome", true, false)
|
|
targetCard.becoming_poly = nil
|
|
return true end
|
|
})
|
|
delay(2.5)
|
|
end
|
|
end
|
|
end
|
|
end,
|
|
|
|
custom_in_pool = function(self, args)
|
|
|
|
--Spawns if there is at least one decimal card
|
|
for _, v in pairs(G.playing_cards) do
|
|
if is_decimal(v) then return true end
|
|
end
|
|
return false
|
|
|
|
end
|
|
})
|
|
|
|
--Binary-line Jokers
|
|
|
|
local chipsAbilityMatch = {
|
|
m_stone = 50,
|
|
m_unstb_resource = 0,
|
|
m_unstb_radioactive = 13,
|
|
m_unstb_biohazard = 0
|
|
}
|
|
|
|
create_joker({
|
|
name = 'Dummy Data', id = 6,
|
|
rarity = 'Uncommon', cost = 6,
|
|
|
|
gameplay_tag = {'rank_binary'},
|
|
|
|
vars = {{odds = 2}, {unscored_card = {}}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
return {vars = {G.GAME and G.GAME.probabilities.normal or 1, card.ability.extra.odds}}
|
|
end,
|
|
|
|
blueprint = false, eternal = true, perishable = true,
|
|
|
|
add_to_deck = function(self, card, from_debuff)
|
|
--Enable rank 0 card in pools
|
|
if not from_debuff then
|
|
setPoolRankFlagEnable('unstb_0', true);
|
|
setPoolRankFlagEnable('unstb_1', true);
|
|
end
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
if context.before and context.scoring_hand and not context.blueprint then
|
|
card.ability.extra.unscored_card = {}
|
|
for k, v in pairs(context.full_hand) do
|
|
local unscoring = true
|
|
for _k,_v in pairs(context.scoring_hand) do
|
|
if v == _v then
|
|
unscoring = false
|
|
break
|
|
end
|
|
end
|
|
|
|
if unscoring and not v.debuff then
|
|
card.ability.extra.unscored_card[#card.ability.extra.unscored_card+1] = v
|
|
end
|
|
end
|
|
end
|
|
|
|
if context.after and not context.blueprint then
|
|
for i = 1, #card.ability.extra.unscored_card do
|
|
|
|
local isTurning = pseudorandom('dummy'..G.SEED) < G.GAME.probabilities.normal / card.ability.extra.odds
|
|
if isTurning then
|
|
local currentCard = card.ability.extra.unscored_card[i]
|
|
|
|
currentCard.ability.perma_bonus = (currentCard.ability.perma_bonus or 0) + SMODS.Ranks[currentCard.base.value].nominal
|
|
|
|
--Flipping Animation
|
|
event({trigger = 'after', delay = 0.1, func = function() currentCard:flip(); play_sound('card1', 1); currentCard:juice_up(0.3, 0.3); return true end })
|
|
|
|
--Changing Card Property
|
|
|
|
event({trigger = 'after', delay = 0.05, func = function()
|
|
|
|
local suit_data = SMODS.Suits[currentCard.base.suit]
|
|
local suit_prefix = suit_data.card_key
|
|
|
|
currentCard:set_base(G.P_CARDS[suit_prefix .. '_unstb_0' ])
|
|
|
|
--Un-stoned the stone card
|
|
if currentCard.config.center.key == 'm_unstb_slop' or chipsAbilityMatch[currentCard.config.center.key] then
|
|
currentCard:set_ability(G.P_CENTERS.c_base)
|
|
end
|
|
|
|
return true end })
|
|
|
|
--Unflipping Animation
|
|
event({trigger = 'after', delay = 0.1, func = function() currentCard:flip(); play_sound('tarot2', 1, 0.6); big_juice(card); currentCard:juice_up(0.3, 0.3); return true end })
|
|
forced_message("Zero!", currentCard, G.C.GREY, true)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
})
|
|
|
|
create_joker({
|
|
name = 'Micro SD Card', id = 4,
|
|
rarity = 'Uncommon', cost = 7,
|
|
|
|
gameplay_tag = {'rank_binary', 'j_alter', 'j_powerful'},
|
|
|
|
vars = {{odds_current = 0}, {odds_destroy = 512}, {stored_chips = 0}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
|
|
local activate_text = 'Inactive'
|
|
local activate_color = G.C.RED
|
|
if G.jokers and G.jokers.cards[1] == card then
|
|
activate_text = 'Active'
|
|
activate_color = G.C.GREEN
|
|
end
|
|
|
|
return {vars = {G.GAME and G.GAME.probabilities.normal * card.ability.extra.odds_current or 0, card.ability.extra.odds_destroy, G.GAME and G.GAME.probabilities.normal or 1, card.ability.extra.stored_chips, activate_text,
|
|
colours = {activate_color} }}
|
|
end,
|
|
|
|
blueprint = true, eternal = false, perishable = false,
|
|
|
|
--Set sprites and hitbox
|
|
|
|
set_sprites = function(self, card, front)
|
|
local w_scale, h_scale = 41/71, 59/95
|
|
card.children.center.scale.y = card.children.center.scale.y * h_scale
|
|
card.children.center.scale.x = card.children.center.scale.x * w_scale
|
|
end,
|
|
|
|
set_ability = function(self, card, initial, delay_sprites)
|
|
local w_scale, h_scale = 41/71, 59/95
|
|
card.T.h = card.T.h * h_scale
|
|
card.T.w = card.T.w * w_scale
|
|
end,
|
|
|
|
load = function(self, card, initial, delay_sprites)
|
|
local w_scale, h_scale = 41/71, 59/95
|
|
card.T.h = card.T.h * h_scale
|
|
card.T.w = card.T.w * w_scale
|
|
end,
|
|
|
|
add_to_deck = function(self, card, from_debuff)
|
|
--Enable rank 0 card in pools
|
|
setPoolRankFlagEnable('unstb_0', true);
|
|
setPoolRankFlagEnable('unstb_1', true);
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
--This part handles the chip reward
|
|
if context.joker_main then
|
|
return {
|
|
chip_mod = card.ability.extra.stored_chips,
|
|
message = localize { type = 'variable', key = 'a_chips', vars = { card.ability.extra.stored_chips } }
|
|
}
|
|
end
|
|
|
|
--The scaling part is not copyable by Blueprint
|
|
if context.discard and not context.blueprint then
|
|
|
|
--Check if the joker is on the leftmost slot
|
|
if G.jokers.cards[1] == card then
|
|
local currentCard = context.other_card
|
|
|
|
--Not debuffed, and isn't face card, and is base card
|
|
if not currentCard:is_face() and not currentCard.debuff and currentCard.config.center == G.P_CENTERS.c_base then
|
|
|
|
local bonusChip = currentCard.ability.perma_bonus or 0
|
|
local baseChip = SMODS.Ranks[currentCard.base.value].nominal
|
|
|
|
local totalChip = baseChip + bonusChip
|
|
|
|
if totalChip>0 then
|
|
card.ability.extra.stored_chips = (card.ability.extra.stored_chips or 0) + totalChip
|
|
|
|
card.ability.extra.odds_current = (card.ability.extra.odds_current or 0) + totalChip
|
|
|
|
--Change card
|
|
event({trigger = 'after', delay = 0.02, func = function()
|
|
|
|
local suit_data = SMODS.Suits[currentCard.base.suit]
|
|
local suit_prefix = suit_data.card_key
|
|
|
|
currentCard:juice_up(0.3, 0.3);
|
|
currentCard:set_base(G.P_CARDS[suit_prefix .. '_unstb_0' ])
|
|
|
|
return true end })
|
|
|
|
return {
|
|
message = localize { type = 'variable', key = 'a_chips', vars = { totalChip } },
|
|
colour = G.C.CHIPS,
|
|
card = card
|
|
}
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
--End of round check, make sure it's checked absolutely once per round
|
|
if context.end_of_round and not context.other_card and not context.repetition and not context.game_over and not context.blueprint then
|
|
if pseudorandom('sdcard'..G.SEED) < G.GAME.probabilities.normal * card.ability.extra.odds_current / card.ability.extra.odds_destroy then
|
|
event({func = function()
|
|
|
|
play_sound('tarot1')
|
|
card.T.r = -0.2
|
|
card:juice_up(0.3, 0.4)
|
|
card.states.drag.is = true
|
|
card.children.center.pinch.x = true
|
|
|
|
--Destroy Card
|
|
event({trigger = 'after', delay = 0.3, func = function()
|
|
|
|
G.jokers:remove_card(card)
|
|
card:remove()
|
|
card = nil
|
|
return true end })
|
|
|
|
return true end })
|
|
return {
|
|
message = 'Corrupted...',
|
|
colour = G.C.BLACK
|
|
}
|
|
else
|
|
return {
|
|
message = 'Safe!'
|
|
}
|
|
end
|
|
end
|
|
end
|
|
})
|
|
|
|
create_joker({
|
|
name = 'Social Experiment', id = 65,
|
|
rarity = 'Rare', cost = 9,
|
|
|
|
gameplay_tag = {'rank_binary', 'j_powerful'},
|
|
|
|
blueprint = false, eternal = true, perishable = true,
|
|
|
|
add_to_deck = function(self, card, from_debuff)
|
|
--Enable rank 0 card in pools
|
|
setPoolRankFlagEnable('unstb_0', true);
|
|
setPoolRankFlagEnable('unstb_1', true);
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
|
|
if context.after and context.scoring_hand and #context.scoring_hand > 1 and not context.blueprint then
|
|
local totalChipCount = 0
|
|
|
|
for i = 1, #context.scoring_hand do
|
|
if i<#context.scoring_hand and not (context.scoring_hand[i]:is_face() and not (context.scoring_hand[i].config.center.key == 'm_unstb_slop' or context.scoring_hand[i].config.center.no_rank)) then --context.scoring_hand[i].config.center ~= G.P_CENTERS.m_stone then --Check if it is not a Stone card
|
|
local currentCard = context.scoring_hand[i]
|
|
|
|
local bonusChip = currentCard.ability.perma_bonus or 0
|
|
|
|
|
|
local baseChip = SMODS.Ranks[currentCard.base.value].nominal
|
|
|
|
if currentCard.config.center.key == 'm_unstb_slop' then
|
|
baseChip = 0
|
|
bonusChip = bonusChip + currentCard.ability.extra.chips
|
|
elseif chipsAbilityMatch[currentCard.config.center.key] then
|
|
baseChip = 0
|
|
bonusChip = bonusChip + chipsAbilityMatch[currentCard.config.center.key]
|
|
end
|
|
|
|
if bonusChip + baseChip > 0 then
|
|
|
|
context.scoring_hand[i+1].ability.perma_bonus = (context.scoring_hand[i+1].ability.perma_bonus or 0) + (bonusChip + baseChip)*2
|
|
|
|
totalChipCount = totalChipCount + bonusChip + baseChip
|
|
|
|
currentCard.ability.perma_bonus = 0
|
|
|
|
--Flipping Animation
|
|
event({trigger = 'after', delay = 0.1, func = function() currentCard:flip(); play_sound('card1', 1); currentCard:juice_up(0.3, 0.3); return true end })
|
|
|
|
--Changing Card Property
|
|
|
|
event({trigger = 'after', delay = 0.05, func = function()
|
|
|
|
local suit_data = SMODS.Suits[currentCard.base.suit]
|
|
local suit_prefix = suit_data.card_key
|
|
|
|
currentCard:set_base(G.P_CARDS[suit_prefix .. '_unstb_0' ])
|
|
|
|
--Un-stoned the stone card
|
|
--print(currentCard.config.center.key)
|
|
--print(chipsAbilityMatch[currentCard.config.center.key])
|
|
if currentCard.config.center.key == 'm_unstb_slop' or chipsAbilityMatch[currentCard.config.center.key] then
|
|
currentCard:set_ability(G.P_CENTERS.c_base)
|
|
end
|
|
|
|
return true end })
|
|
|
|
--Unflipping Animation
|
|
event({trigger = 'after', delay = 0.1, func = function() currentCard:flip(); play_sound('tarot2', 1, 0.6); big_juice(card); currentCard:juice_up(0.3, 0.3); return true end })
|
|
forced_message("Double It!", currentCard, G.C.CHIPS, true)
|
|
end
|
|
|
|
else
|
|
if totalChipCount > 0 then
|
|
local currentCard = context.scoring_hand[i]
|
|
|
|
event({ trigger = 'after', delay = 0.2, func = function()
|
|
big_juice(currentCard)
|
|
play_sound('multhit1')
|
|
return true end })
|
|
|
|
forced_message("Take!", currentCard, G.C.CHIPS, true)
|
|
|
|
totalChipCount = 0
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
})
|
|
|
|
create_joker({
|
|
name = 'Power of One', id = 13,
|
|
rarity = 'Uncommon', cost = 7,
|
|
|
|
gameplay_tag = {'rank_binary'},
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
vars = {{mult_rate = '4'}, {mult = '0'}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
|
|
--Check the number of 1 in the deck
|
|
local one_count=0
|
|
if (G.playing_cards) then
|
|
for _, v in pairs(G.playing_cards) do
|
|
if v.base.value == 'unstb_1' then one_count = one_count + 1 end
|
|
end
|
|
return { vars = {card.ability.extra.mult_rate, one_count*card.ability.extra.mult_rate}}
|
|
else
|
|
return { vars = {card.ability.extra.mult_rate, 0}}
|
|
end
|
|
end,
|
|
|
|
|
|
calculate = function(self, card, context)
|
|
--Main context
|
|
if context.joker_main then
|
|
local one_count=0
|
|
for _, v in pairs(G.playing_cards) do
|
|
if v.base.value == 'unstb_1' then one_count = one_count + 1 end
|
|
end
|
|
|
|
card.ability.extra.mult = one_count*card.ability.extra.mult_rate
|
|
|
|
return {
|
|
mult_mod = card.ability.extra.mult,
|
|
message = localize { type = 'variable', key = 'a_mult', vars = { card.ability.extra.mult } }
|
|
}
|
|
end
|
|
|
|
end,
|
|
|
|
custom_in_pool = function(self, args)
|
|
|
|
--Spawns if there is at least one rank 1 card
|
|
for _, v in pairs(G.playing_cards) do
|
|
if v.base.value == 'unstb_1' then return true end
|
|
end
|
|
return false
|
|
|
|
end
|
|
})
|
|
|
|
local binary_rank = {'unstb_0', 'unstb_1', '2', '3', '4', '5', '6', '7', '8', '9', '10', 'Jack', 'Queen', 'King', 'Ace', 'unstb_???'}
|
|
|
|
create_joker({
|
|
name = 'Binary Number', id = 5,
|
|
rarity = 'Uncommon', cost = 7,
|
|
|
|
gameplay_tag = {'rank_binary'},
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
vars = {},
|
|
|
|
|
|
calculate = function(self, card, context)
|
|
--Main context
|
|
if context.after then
|
|
local hand = context.full_hand
|
|
|
|
--Parse the hand and check if it's eligible in one go
|
|
|
|
--Ineligible hand
|
|
if #hand > 4 then return end
|
|
|
|
local is_binary = true
|
|
local final_rank = 0
|
|
local suit_list = {}
|
|
|
|
for i=1, #hand do
|
|
local rank = hand[i].base.value
|
|
|
|
if rank == 'unstb_1' then
|
|
final_rank = final_rank + 2 ^ (#hand-i)
|
|
suit_list[#suit_list+1] = hand[1].base.suit
|
|
elseif rank == 'unstb_0' then
|
|
--Do nothing, really
|
|
suit_list[#suit_list+1] = hand[1].base.suit
|
|
else
|
|
is_binary = false
|
|
break
|
|
end
|
|
end
|
|
|
|
--If the hand is binary number, create card accordingly
|
|
if is_binary then
|
|
|
|
local target_rank = binary_rank[final_rank+1] or 'unstb_???'
|
|
|
|
--print(final_rank)
|
|
--print(target_rank)
|
|
|
|
--Create Card
|
|
event({func = function()
|
|
local rank = SMODS.Ranks[target_rank].card_key
|
|
local suit = SMODS.Suits[pseudorandom_element(suit_list, pseudoseed('binary')..G.SEED)].card_key
|
|
|
|
local _card = Card(G.play.T.x + G.play.T.w/2, G.play.T.y, G.CARD_W, G.CARD_H, G.P_CARDS[suit..'_'..rank], G.P_CENTERS.c_base, {playing_card = G.playing_card})
|
|
|
|
|
|
--Juice up the Joker
|
|
card:juice_up(0.3, 0.3)
|
|
|
|
_card:start_materialize({G.C.SECONDARY_SET.Enhanced})
|
|
G.play:emplace(_card)
|
|
table.insert(G.playing_cards, _card)
|
|
|
|
return true end
|
|
})
|
|
|
|
event({func = function()
|
|
G.deck.config.card_limit = G.deck.config.card_limit + 1
|
|
return true end
|
|
})
|
|
|
|
delay(1)
|
|
|
|
event({func = function()
|
|
draw_card(G.play,G.deck, 90,'up', nil)
|
|
return true end
|
|
})
|
|
|
|
playing_card_joker_effects({true})
|
|
end
|
|
|
|
end
|
|
|
|
end,
|
|
|
|
custom_in_pool = function(self, args)
|
|
--If rank 0 and 1 is unlocked this run
|
|
return getPoolRankFlagEnable('unstb_0') and getPoolRankFlagEnable('unstb_1')
|
|
|
|
end
|
|
})
|
|
|
|
--Enhancement-line Jokers
|
|
|
|
--Quintuplets
|
|
create_joker({
|
|
name = 'Quintuplets', id = 2,
|
|
rarity = 'Uncommon', cost = 6,
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
vars = {{scoring_name = ''}, {scoring_hand = {}}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
info_queue[#info_queue+1] = G.P_TAGS.tag_negative
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
--Keep track of scoring hand
|
|
--[[if context.after and context.scoring_name ~= nil and context.scoring_hand and not context.blueprint then
|
|
card.ability.extra.scoring_name = context.scoring_name
|
|
card.ability.extra.scoring_hand = context.scoring_hand
|
|
end
|
|
|
|
if context.end_of_round and not context.other_card and not context.repetition and not context.game_over and card.ability.extra.scoring_name == 'Flush Five' then
|
|
|
|
local isActivated = true
|
|
|
|
for i = 1, #card.ability.extra.scoring_hand do
|
|
if card.ability.extra.scoring_hand[i].config.center == G.P_CENTERS.c_base then
|
|
isActivated = false
|
|
break
|
|
end
|
|
end
|
|
|
|
if isActivated then
|
|
if not context.blueprint then
|
|
card.ability.extra.scoring_name = ''
|
|
end
|
|
|
|
event({ trigger = 'after', delay = 0.5, func = function()
|
|
card:juice_up(0.3, 0.3)
|
|
|
|
add_tag(Tag('tag_negative'))
|
|
play_sound('generic1', 0.9 + math.random()*0.1, 0.8)
|
|
play_sound('holo1', 1.2 + math.random()*0.1, 0.4)
|
|
|
|
return true end
|
|
}
|
|
)
|
|
end
|
|
end]]
|
|
|
|
if context.after and next(context.poker_hands['Five of a Kind']) then
|
|
event({ trigger = 'after', delay = 0.5, func = function()
|
|
(context.blueprint_card or card):juice_up(0.3, 0.3)
|
|
|
|
add_tag(Tag('tag_negative'))
|
|
play_sound('generic1', 0.9 + math.random()*0.1, 0.8)
|
|
play_sound('holo1', 1.2 + math.random()*0.1, 0.4)
|
|
|
|
return true end
|
|
}
|
|
)
|
|
end
|
|
end
|
|
})
|
|
|
|
--Edition-line Jokers
|
|
|
|
--Graphic Card
|
|
create_joker({
|
|
name = 'Graphic Card', id = 69,
|
|
rarity = 'Rare', cost = 8,
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
vars = {{ count = 5 }, {current_count = 0}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
info_queue[#info_queue+1] = G.P_TAGS.tag_double
|
|
return {vars = {card.ability.extra.count, card.ability.extra.current_count}}
|
|
end,
|
|
|
|
--Set sprites and hitbox
|
|
|
|
set_sprites = function(self, card, front)
|
|
local w_scale, h_scale = 48/71, 95/95
|
|
card.children.center.scale.y = card.children.center.scale.y * h_scale
|
|
card.children.center.scale.x = card.children.center.scale.x * w_scale
|
|
end,
|
|
|
|
set_ability = function(self, card, initial, delay_sprites)
|
|
local w_scale, h_scale = 48/71, 95/95
|
|
card.T.h = card.T.h * h_scale
|
|
card.T.w = card.T.w * w_scale
|
|
end,
|
|
|
|
load = function(self, card, initial, delay_sprites)
|
|
local w_scale, h_scale = 48/71, 95/95
|
|
card.T.h = card.T.h * h_scale
|
|
card.T.w = card.T.w * w_scale
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
|
|
if context.individual and context.cardarea == G.play and not context.repetition then
|
|
if context.other_card.edition then
|
|
card.ability.extra.current_count = card.ability.extra.current_count + 1
|
|
end
|
|
end
|
|
|
|
if context.end_of_round and not context.other_card and not context.repetition and not context.game_over and not context.blueprint then
|
|
|
|
if card.ability.extra.current_count > 0 then
|
|
|
|
if card.ability.extra.current_count >= card.ability.extra.count then
|
|
event({ trigger = 'after', delay = 0.5, func = function()
|
|
|
|
add_tag(Tag('tag_double'))
|
|
play_sound('generic1', 0.9 + math.random()*0.1, 0.8)
|
|
play_sound('holo1', 1.2 + math.random()*0.1, 0.4)
|
|
|
|
return true end
|
|
}
|
|
)
|
|
forced_message("Tag!", card, G.C.SECONDARY_SET.Enhanced, true, false)
|
|
else
|
|
forced_message("Reset", card, G.C.SECONDARY_SET.Enhanced, true, false)
|
|
end
|
|
|
|
end
|
|
card.ability.extra.current_count = 0
|
|
end
|
|
end,
|
|
|
|
custom_in_pool = function(self, args)
|
|
|
|
--Spawns if there is at least one card with edition
|
|
for _, v in pairs(G.playing_cards) do
|
|
if v.edition then return true end
|
|
end
|
|
return false
|
|
|
|
end
|
|
})
|
|
|
|
--Connoiseur
|
|
create_joker({
|
|
name = 'Connoiseur', id = 45,
|
|
rarity = 'Rare', cost = 8,
|
|
|
|
gameplay_tag = {'j_powerful'},
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
vars = {{ repetitions = 1 }},
|
|
|
|
calculate = function(self, card, context)
|
|
if context.cardarea == G.play and context.repetition and not context.repetition_only then
|
|
if context.other_card.edition then
|
|
return {
|
|
message = 'Again!',
|
|
repetitions = card.ability.extra.repetitions,
|
|
card = context.blueprint_card or card
|
|
}
|
|
end
|
|
end
|
|
end,
|
|
|
|
custom_in_pool = function(self, args)
|
|
|
|
--Spawns if there is at least one card with edition
|
|
for _, v in pairs(G.playing_cards) do
|
|
if v.edition then return true end
|
|
end
|
|
return false
|
|
|
|
end
|
|
})
|
|
|
|
--Jeweler
|
|
create_joker({
|
|
name = 'Jeweler', id = 0,
|
|
rarity = 'Uncommon', cost = 8,
|
|
|
|
gameplay_tag = {'edition_upgrade'},
|
|
|
|
vars = {{odds = 4}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
info_queue[#info_queue+1] = {set = 'Other', key = 'upgrade_edition'}
|
|
|
|
local vars
|
|
if G.GAME and G.GAME.probabilities.normal then
|
|
vars = {G.GAME.probabilities.normal, card.ability.extra.odds}
|
|
else
|
|
vars = {1, card.ability.extra.odds}
|
|
end
|
|
return {vars = vars}
|
|
end,
|
|
|
|
blueprint = false, eternal = true, perishable = true,
|
|
|
|
calculate = function(self, card, context)
|
|
|
|
if context.before and not context.blueprint then
|
|
|
|
if pseudorandom('jeweler'..G.SEED) < G.GAME.probabilities.normal / card.ability.extra.odds then
|
|
|
|
forced_message("Upgrade!", card, G.C.PURPLE, true, false)
|
|
|
|
local hand_name = context.scoring_name
|
|
|
|
if to_big(G.GAME.hands[hand_name].level) > to_big(0) then
|
|
level_up_hand(card, hand_name, false, -1)
|
|
end
|
|
|
|
|
|
|
|
for i = 1, #context.scoring_hand do
|
|
local current_card = context.scoring_hand[i]
|
|
edition_upgrade(context.scoring_hand[i])
|
|
|
|
--[[event({delay = 0, trigger = 'before',
|
|
func = function()
|
|
edition_upgrade(current_card)
|
|
|
|
return true end}
|
|
)]]
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
})
|
|
|
|
--New Enhancements Support Stuff
|
|
|
|
--Slop Card Lines
|
|
|
|
--Joker Diffusion
|
|
create_joker({
|
|
name = 'Joker Diffusion', id = 26,
|
|
rarity = 'Uncommon', cost = 6,
|
|
|
|
gameplay_tag = {'enh_custom'},
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
vars = {{count = '3'}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
|
|
info_queue[#info_queue+1] = G.P_CENTERS['m_unstb_slop']
|
|
|
|
return { vars = {card.ability.extra.count}}
|
|
end,
|
|
|
|
|
|
calculate = function(self, card, context)
|
|
if context.after then
|
|
local is_activate = #context.scoring_hand ~= #context.full_hand
|
|
|
|
--Terminate if the condition does not met
|
|
if not is_activate then return end
|
|
|
|
--Populate Candidate Card
|
|
local eligible_card = {}
|
|
local converted_card = {}
|
|
|
|
for i=1, #G.hand.cards do
|
|
if G.hand.cards[i].config.center == G.P_CENTERS.c_base and not G.hand.cards[i].to_convert then eligible_card[#eligible_card+1] = G.hand.cards[i] end
|
|
end
|
|
|
|
table.sort(eligible_card, function (a, b) return not a.playing_card or not b.playing_card or a.playing_card < b.playing_card end)
|
|
pseudoshuffle(eligible_card, pseudoseed('jokerdiffusion'..G.SEED))
|
|
|
|
|
|
for i = 1, card.ability.extra.count do converted_card[#converted_card+1] = eligible_card[i] end
|
|
|
|
if #converted_card > 0 then
|
|
--Animation from Basegame Tarot
|
|
for i=1, #converted_card do
|
|
converted_card[i].to_convert = true
|
|
|
|
local percent = 1.15 - (i-0.999)/(#converted_card-0.998)*0.3
|
|
event({trigger = 'after',delay = 0.15,func = function() big_juice(context.blueprint_card or card); converted_card[i]:flip();play_sound('card1', percent);converted_card[i]:juice_up(0.3, 0.3);return true end })
|
|
end
|
|
delay(0.2)
|
|
|
|
--Handle the conversion
|
|
for i=1, #converted_card do
|
|
event({trigger = 'after',delay = 0.1,func = function()
|
|
converted_card[i]:set_ability(G.P_CENTERS.m_unstb_slop)
|
|
return true end })
|
|
end
|
|
|
|
for i=1, #converted_card do
|
|
local percent = 0.85 + (i-0.999)/(#converted_card-0.998)*0.3
|
|
event({trigger = 'after',delay = 0.15,func = function() converted_card[i]:flip();play_sound('tarot2', percent, 0.6);converted_card[i]:juice_up(0.3, 0.3); converted_card[i].to_convert = nil; return true end })
|
|
end
|
|
delay(0.5)
|
|
end
|
|
end
|
|
|
|
end,
|
|
})
|
|
|
|
--Non-Fungible Joker
|
|
create_joker({
|
|
name = 'NonFungible Joker', id = 27,
|
|
rarity = 'Uncommon', cost = 6,
|
|
|
|
gameplay_tag = {'enh_custom'},
|
|
|
|
blueprint = false, eternal = false, perishable = true,
|
|
|
|
vars = {{count = '1'}, {max_payout = 10}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
|
|
info_queue[#info_queue+1] = G.P_CENTERS['m_unstb_slop']
|
|
|
|
return { vars = {card.ability.extra.count, card.ability.extra.max_payout}}
|
|
end,
|
|
|
|
|
|
calculate = function(self, card, context)
|
|
if context.pre_discard and not context.blueprint then
|
|
local slop_count = 0
|
|
for i=1, #context.full_hand do
|
|
if context.full_hand[i].config.center == G.P_CENTERS.m_unstb_slop then slop_count = slop_count + 1 end
|
|
end
|
|
|
|
card.ability.extra.is_activate = slop_count==1
|
|
end
|
|
|
|
if context.discard and not context.other_card.debuff and not context.blueprint then
|
|
if card.ability.extra.is_activate and context.other_card.config.center == G.P_CENTERS.m_unstb_slop then
|
|
ease_dollars(pseudorandom('nfj'..G.SEED, 0, card.ability.extra.max_payout), true)
|
|
|
|
return {
|
|
--play_sound('whoosh1', math.random()*0.1 + 0.6,0.3),
|
|
message = 'Sold!',
|
|
colour = G.C.GOLD,
|
|
remove = true,
|
|
card = card
|
|
}
|
|
end
|
|
end
|
|
|
|
if context.end_of_round and not context.other_card and not context.repetition and not context.game_over and not context.blueprint then
|
|
if card.ability.extra.max_payout > 0 or card.sell_cost > 0 then
|
|
if card.ability.extra.max_payout>0 then
|
|
card.ability.extra.max_payout = card.ability.extra.max_payout - 1
|
|
end
|
|
|
|
--Reduce its own selling price too, for the funny
|
|
|
|
if card.sell_cost > 0 then
|
|
card.ability.extra_value = (card.ability.extra_value or 0) - 1
|
|
card:set_cost()
|
|
end
|
|
|
|
return{
|
|
message = "Price Dropped",
|
|
colour = G.C.RED,
|
|
}
|
|
end
|
|
end
|
|
|
|
end,
|
|
|
|
custom_in_pool = function(self, args)
|
|
|
|
--Spawns if there is at least one slop card
|
|
for _, v in pairs(G.playing_cards) do
|
|
if v.config.center == G.P_CENTERS.m_unstb_slop then return true end
|
|
end
|
|
return false
|
|
|
|
end
|
|
})
|
|
|
|
--Prompt
|
|
create_joker({
|
|
name = 'Prompt', id = 28,
|
|
rarity = 'Common', cost = 7,
|
|
|
|
gameplay_tag = {'enh_custom'},
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
--vars = { {times = 1}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
|
|
info_queue[#info_queue+1] = G.P_CENTERS['m_unstb_slop']
|
|
|
|
return { vars = {}}
|
|
end,
|
|
|
|
--Prompt's actual ability is in Slop Card's after_play function
|
|
--[[calculate = function(self, card, context)
|
|
|
|
end,]]
|
|
|
|
custom_in_pool = function(self, args)
|
|
|
|
--Spawns if there is at least one slop card
|
|
for _, v in pairs(G.playing_cards) do
|
|
if v.config.center == G.P_CENTERS.m_unstb_slop then return true end
|
|
end
|
|
return false
|
|
|
|
end
|
|
})
|
|
|
|
--Uninterested Primate
|
|
create_joker({
|
|
name = 'Uninterested Primate', id = 29,
|
|
rarity = 'Common', cost = 5,
|
|
|
|
gameplay_tag = {'enh_custom'},
|
|
|
|
blueprint = true, eternal = false, perishable = false,
|
|
|
|
vars = { {chips = 50}, {chips_rate = 10}, {slop_scored = 0}, {slop_cycle = 3}, {chance_destroy = 8}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
|
|
info_queue[#info_queue+1] = G.P_CENTERS['m_unstb_slop']
|
|
|
|
return { vars = {card.ability.extra.chips_rate, card.ability.extra.slop_cycle, G.GAME and G.GAME.probabilities.normal or 1, card.ability.extra.chance_destroy, card.ability.extra.chips, card.ability.extra.slop_cycle - card.ability.extra.slop_scored}}
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
--Main Context
|
|
if context.joker_main then
|
|
return {
|
|
chip_mod = card.ability.extra.chips,
|
|
message = localize { type = 'variable', key = 'a_chips', vars = { card.ability.extra.chips } }
|
|
}
|
|
end
|
|
|
|
--Scaling, cannot copy via blueprint
|
|
if context.individual and context.cardarea == G.play and not context.blueprint then
|
|
if context.other_card.config.center == G.P_CENTERS.m_unstb_slop then
|
|
card.ability.extra.slop_scored = card.ability.extra.slop_scored + 1
|
|
|
|
if card.ability.extra.slop_scored >= card.ability.extra.slop_cycle then
|
|
card.ability.extra.slop_scored = 0
|
|
|
|
card.ability.extra.chips = card.ability.extra.chips + card.ability.extra.chips_rate
|
|
|
|
forced_message("+"..card.ability.extra.chips_rate, card, G.C.CHIPS, true)
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
--End of round check, make sure it's checked absolutely once per round
|
|
if context.end_of_round and not context.other_card and not context.repetition and not context.game_over and not context.blueprint then
|
|
|
|
--Reduce its own selling price, for the funny
|
|
|
|
if card.sell_cost > 0 then
|
|
card.ability.extra_value = (card.ability.extra_value or 0) - 1
|
|
card:set_cost()
|
|
end
|
|
|
|
if pseudorandom('primate'..G.SEED) < G.GAME.probabilities.normal / card.ability.extra.chance_destroy then
|
|
event({func = function()
|
|
|
|
play_sound('tarot1')
|
|
card.T.r = -0.2
|
|
card:juice_up(0.3, 0.4)
|
|
card.states.drag.is = true
|
|
card.children.center.pinch.x = true
|
|
|
|
--Destroy Card
|
|
event({trigger = 'after', delay = 0.3, func = function()
|
|
|
|
G.jokers:remove_card(card)
|
|
card:remove()
|
|
card = nil
|
|
return true end })
|
|
|
|
return true end })
|
|
|
|
G.GAME.pool_flags.primate_gone = true
|
|
return {
|
|
message = 'My Primates Gone'
|
|
}
|
|
else
|
|
return {
|
|
message = 'Safe!'
|
|
}
|
|
end
|
|
end
|
|
end,
|
|
|
|
custom_in_pool = function(self, args)
|
|
|
|
--Spawns if there is at least one slop card + primate is not gone yet
|
|
for _, v in pairs(G.playing_cards) do
|
|
if v.config.center == G.P_CENTERS.m_unstb_slop then return not G.GAME.pool_flags.primate_gone end
|
|
end
|
|
return false
|
|
|
|
end
|
|
})
|
|
|
|
--Lethargic Lion
|
|
create_joker({
|
|
name = 'Lethargic Lion', id = 30,
|
|
rarity = 'Common', cost = 5,
|
|
|
|
gameplay_tag = {'enh_custom'},
|
|
|
|
blueprint = true, eternal = false, perishable = false,
|
|
|
|
vars = { {xmult = 2}, {xmult_rate = 0.02}, {slop_scored = 0}, {slop_cycle = 3}, {chance_destroy = 8}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
|
|
info_queue[#info_queue+1] = G.P_CENTERS['m_unstb_slop']
|
|
|
|
return { vars = {card.ability.extra.xmult_rate, card.ability.extra.slop_cycle, G.GAME and G.GAME.probabilities.normal or 1, card.ability.extra.chance_destroy, card.ability.extra.xmult, card.ability.extra.slop_cycle - card.ability.extra.slop_scored}}
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
--Main Context
|
|
if context.joker_main then
|
|
return {
|
|
Xmult_mod = card.ability.extra.xmult,
|
|
message = localize { type = 'variable', key = 'a_xmult', vars = { card.ability.extra.xmult } }
|
|
}
|
|
end
|
|
|
|
--Scaling, cannot copy via blueprint
|
|
if context.individual and context.cardarea == G.play and not context.blueprint then
|
|
if context.other_card.config.center == G.P_CENTERS.m_unstb_slop then
|
|
card.ability.extra.slop_scored = card.ability.extra.slop_scored + 1
|
|
|
|
if card.ability.extra.slop_scored >= card.ability.extra.slop_cycle then
|
|
card.ability.extra.slop_scored = 0
|
|
|
|
card.ability.extra.xmult = card.ability.extra.xmult + card.ability.extra.xmult_rate
|
|
|
|
forced_message("+"..card.ability.extra.xmult_rate, card, G.C.MULT, true)
|
|
end
|
|
|
|
end
|
|
end
|
|
|
|
--End of round check, make sure it's checked absolutely once per round
|
|
if context.end_of_round and not context.other_card and not context.repetition and not context.game_over and not context.blueprint then
|
|
|
|
--Reduce its own selling price, for the funny
|
|
|
|
if card.sell_cost > 0 then
|
|
card.ability.extra_value = (card.ability.extra_value or 0) - 1
|
|
card:set_cost()
|
|
end
|
|
|
|
if pseudorandom('primate'..G.SEED) < G.GAME.probabilities.normal / card.ability.extra.chance_destroy then
|
|
event({func = function()
|
|
|
|
play_sound('tarot1')
|
|
card.T.r = -0.2
|
|
card:juice_up(0.3, 0.4)
|
|
card.states.drag.is = true
|
|
card.children.center.pinch.x = true
|
|
|
|
--Destroy Card
|
|
event({trigger = 'after', delay = 0.3, func = function()
|
|
|
|
G.jokers:remove_card(card)
|
|
card:remove()
|
|
card = nil
|
|
return true end })
|
|
|
|
return true end })
|
|
return {
|
|
message = 'My Lions Gone'
|
|
}
|
|
else
|
|
return {
|
|
message = 'Safe!'
|
|
}
|
|
end
|
|
end
|
|
end,
|
|
|
|
custom_in_pool = function(self, args)
|
|
|
|
--Spawns if there is at least one slop card + primate is gone
|
|
for _, v in pairs(G.playing_cards) do
|
|
if v.config.center == G.P_CENTERS.m_unstb_slop then return G.GAME.pool_flags.primate_gone end
|
|
end
|
|
return false
|
|
|
|
end
|
|
})
|
|
|
|
|
|
--Vintage Joker
|
|
create_joker({
|
|
name = 'Vintage Joker', id = 23,
|
|
rarity = 'Uncommon', cost = 6,
|
|
|
|
gameplay_tag = {'enh_custom'},
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
vars = {{chance_fix = '4'}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
|
|
info_queue[#info_queue+1] = G.P_CENTERS['m_unstb_vintage']
|
|
|
|
return { vars = {G.GAME and G.GAME.probabilities.normal or 1, card.ability.extra.chance_fix}}
|
|
end,
|
|
|
|
|
|
calculate = function(self, card, context)
|
|
if context.individual and context.cardarea == G.play then
|
|
if context.other_card.config.center == G.P_CENTERS.m_unstb_vintage then
|
|
if pseudorandom('vintagejoker'..G.SEED) < G.GAME.probabilities.normal / card.ability.extra.chance_fix then
|
|
context.other_card.ability.extra.current_odd = 0 --math.ceil(context.other_card.ability.extra.current_odd * 0.5)
|
|
|
|
event({trigger = 'after', func = function()
|
|
play_sound('tarot2', 1, 0.6);
|
|
big_juice(context.blueprint_card or card)
|
|
return true end })
|
|
forced_message("Restored!", context.other_card, G.C.GREEN, true)
|
|
end
|
|
end
|
|
end
|
|
|
|
end,
|
|
|
|
custom_in_pool = function(self, args)
|
|
|
|
--Spawns if there is at least one vintage card
|
|
for _, v in pairs(G.playing_cards) do
|
|
if v.config.center == G.P_CENTERS.m_unstb_vintage then return true end
|
|
end
|
|
return false
|
|
|
|
end
|
|
})
|
|
|
|
--Rules Errata
|
|
create_joker({
|
|
name = 'Rules Errata', id = 24,
|
|
rarity = 'Uncommon', cost = 5,
|
|
|
|
gameplay_tag = {'enh_custom'},
|
|
|
|
blueprint = false, eternal = true, perishable = true,
|
|
|
|
--vars = {{}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
|
|
info_queue[#info_queue+1] = {set = 'Other', key = 'acorn_tooltip'}
|
|
|
|
return { vars = {}}
|
|
end,
|
|
|
|
--This Joker's effect is in Acorn Mark Card's code itself
|
|
--[[calculate = function(self, card, context)
|
|
|
|
if context.individual and context.cardarea == G.play then
|
|
|
|
end
|
|
|
|
end,]]
|
|
|
|
custom_in_pool = function(self, args)
|
|
|
|
--Spawns if there is at least one acorn card
|
|
for _, v in pairs(G.playing_cards) do
|
|
if v.config.center == G.P_CENTERS.m_unstb_acorn then return true end
|
|
end
|
|
return false
|
|
|
|
end
|
|
})
|
|
|
|
--Auction Winner
|
|
create_joker({
|
|
name = 'Auction Winner', id = 25,
|
|
rarity = 'Common', cost = 6,
|
|
|
|
gameplay_tag = {'enh_custom'},
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
--vars = {{}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
|
|
info_queue[#info_queue+1] = G.P_CENTERS['m_unstb_promo']
|
|
|
|
return { vars = {}}
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
|
|
if context.remove_playing_cards then
|
|
|
|
local money = 0
|
|
|
|
for _, v in pairs(context.removed) do
|
|
if v.config.center == G.P_CENTERS.m_unstb_promo then
|
|
money = money + v.ability.extra.gold
|
|
end
|
|
end
|
|
|
|
if money>0 then
|
|
event({trigger = 'after', func = function()
|
|
ease_dollars(money, true)
|
|
big_juice(context.blueprint_card or card)
|
|
return true end })
|
|
forced_message('$'..money, context.blueprint_card or card, G.C.GOLD, true)
|
|
end
|
|
|
|
end
|
|
|
|
end,
|
|
|
|
custom_in_pool = function(self, args)
|
|
|
|
--Spawns if there is at least one promo card
|
|
for _, v in pairs(G.playing_cards) do
|
|
if v.config.center == G.P_CENTERS.m_unstb_promo then return true end
|
|
end
|
|
return false
|
|
|
|
end
|
|
})
|
|
|
|
create_joker({
|
|
name = 'Joker Island', id = 7,
|
|
rarity = 'Uncommon', cost = 6,
|
|
|
|
gameplay_tag = {'enh_custom'},
|
|
|
|
vars = {{target_rank = 2}, {odds_ticket = 6}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
info_queue[#info_queue+1] = {set = 'Other', key = 'resource_tooltip'}
|
|
return {vars = {localize(card.ability.extra.target_rank, 'ranks'), G.GAME and G.GAME.probabilities.normal or 1, card.ability.extra.odds_ticket}}
|
|
end,
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
set_ability = function(self, card, initial, delay_sprites)
|
|
--Random possible rank
|
|
local rank = '2'
|
|
if G.playing_cards then
|
|
rank = get_valid_card_from_deck('jokerisland'..G.SEED).rank --pseudorandom_element(G.playing_cards, pseudoseed('jokerisland')..G.SEED).base.value
|
|
end
|
|
|
|
card.ability.extra.target_rank = rank
|
|
end,
|
|
|
|
add_to_deck = function(self, card, from_debuff)
|
|
if not G.GAME.pool_flags.catan_enabled then
|
|
G.GAME.pool_flags.catan_enabled = true
|
|
end
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
if context.individual and context.cardarea == G.play then
|
|
local currentCard = context.other_card
|
|
if currentCard.base.value == card.ability.extra.target_rank and not currentCard.config.center.no_rank then
|
|
|
|
local isActivated = pseudorandom('jokerisland'..G.SEED) < G.GAME.probabilities.normal / card.ability.extra.odds_ticket
|
|
|
|
if isActivated then
|
|
event({func = function()
|
|
local rank = pseudorandom_element(SMODS.Ranks, pseudoseed('jokerisland')..G.SEED).card_key
|
|
local suit = SMODS.Suits[currentCard.base.suit].card_key
|
|
|
|
local _card = Card(G.play.T.x + G.play.T.w/2, G.play.T.y, G.CARD_W, G.CARD_H, G.P_CARDS[suit..'_'..rank], G.P_CENTERS.m_unstb_resource, {playing_card = G.playing_card})
|
|
|
|
_card:start_materialize({G.C.SECONDARY_SET.Enhanced})
|
|
G.play:emplace(_card)
|
|
table.insert(G.playing_cards, _card)
|
|
|
|
return true end
|
|
})
|
|
|
|
event({func = function()
|
|
G.deck.config.card_limit = G.deck.config.card_limit + 1
|
|
draw_card(G.play,G.deck, 90,'up', nil)
|
|
return true end
|
|
})
|
|
|
|
playing_card_joker_effects({true})
|
|
end
|
|
end
|
|
end
|
|
|
|
if context.end_of_round and not context.other_card and not context.repetition and not context.game_over and not context.blueprint then
|
|
card.ability.extra.target_rank = get_valid_card_from_deck('jokerisland'..G.SEED).rank --pseudorandom_element(G.playing_cards, pseudoseed('jokerisland')..G.SEED).base.value --pseudorandom_element(SMODS.Ranks, pseudoseed('jokerisland')..G.SEED).key
|
|
return{
|
|
message = "Randomize"
|
|
}
|
|
end
|
|
end
|
|
})
|
|
|
|
--New Anti-Enhancement Stuff
|
|
|
|
create_joker({
|
|
name = 'Kaiju', id = 17,
|
|
rarity = 'Uncommon', cost = 8,
|
|
|
|
gameplay_tag = {'enh_disenh'},
|
|
|
|
vars = {{add_slot = 4}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
|
|
info_queue[#info_queue+1] = G.P_CENTERS['m_unstb_radioactive']
|
|
|
|
return {vars = {card.ability.extra.add_slot}}
|
|
end,
|
|
|
|
blueprint = false, eternal = true, perishable = true,
|
|
|
|
add_to_deck = function(self, card, from_debuff)
|
|
if not G.GAME.pool_flags.radioactive_enabled then
|
|
G.GAME.pool_flags.radioactive_enabled = true
|
|
end
|
|
|
|
G.jokers.config.card_limit = G.jokers.config.card_limit + card.ability.extra.add_slot
|
|
end,
|
|
|
|
remove_from_deck = function(self, card, from_debuff)
|
|
G.jokers.config.card_limit = G.jokers.config.card_limit - card.ability.extra.add_slot
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
if context.first_hand_drawn then
|
|
event({delay = 0.4, trigger = 'after',
|
|
func = function()
|
|
local eligible_list={}
|
|
for i=1, #G.hand.cards do
|
|
if G.hand.cards[i].config.center ~= G.P_CENTERS.m_unstb_radioactive then table.insert(eligible_list,G.hand.cards[i]) end
|
|
end
|
|
if #eligible_list>0 then
|
|
local enhanced_card = pseudorandom_element(eligible_list, pseudoseed('kaiju'..G.SEED))
|
|
enhanced_card:set_disenhancement(G.P_CENTERS.m_unstb_radioactive , nil, true)
|
|
play_sound('tarot1')
|
|
enhanced_card:juice_up()
|
|
end
|
|
|
|
return true end}
|
|
)
|
|
end
|
|
end
|
|
})
|
|
|
|
create_joker({
|
|
name = 'Poison the Well', id = 18,
|
|
rarity = 'Uncommon', cost = 8,
|
|
|
|
gameplay_tag = {'enh_disenh'},
|
|
|
|
vars = {{discard_size = 4}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
|
|
info_queue[#info_queue+1] = {set = 'Other', key = 'poison_tooltip'}
|
|
|
|
return {vars = {card.ability.extra.discard_size}}
|
|
end,
|
|
|
|
blueprint = false, eternal = true, perishable = true,
|
|
|
|
add_to_deck = function(self, card, from_debuff)
|
|
if not G.GAME.pool_flags.poison_enabled then
|
|
G.GAME.pool_flags.poison_enabled = true
|
|
end
|
|
|
|
G.GAME.round_resets.discards = G.GAME.round_resets.discards + card.ability.extra.discard_size
|
|
ease_discard(3)
|
|
end,
|
|
|
|
remove_from_deck = function(self, card, from_debuff)
|
|
G.GAME.round_resets.discards = G.GAME.round_resets.discards - card.ability.extra.discard_size
|
|
ease_discard(-3)
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
if context.pre_discard and not context.blueprint then
|
|
local target_card = pseudorandom_element(G.hand.highlighted, pseudoseed(seed or 'poisonwell'..G.GAME.round_resets.ante))
|
|
|
|
event({trigger = 'after', func = function()
|
|
play_sound('generic1')
|
|
target_card:juice_up(0.3, 0.3);
|
|
target_card:set_disenhancement(G.P_CENTERS.m_unstb_poison , nil, true)
|
|
|
|
return true end })
|
|
end
|
|
end
|
|
})
|
|
|
|
create_joker({
|
|
name = 'Petri Dish', id = 19,
|
|
rarity = 'Uncommon', cost = 8,
|
|
|
|
gameplay_tag = {'enh_disenh'},
|
|
|
|
vars = {{adds_hand = 4}, {odds = 4}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
|
|
info_queue[#info_queue+1] = G.P_CENTERS['m_unstb_biohazard']
|
|
|
|
return {vars = {card.ability.extra.adds_hand, G.GAME and G.GAME.probabilities.normal or 1, card.ability.extra.odds}}
|
|
end,
|
|
|
|
blueprint = false, eternal = true, perishable = true,
|
|
|
|
add_to_deck = function(self, card, from_debuff)
|
|
if not G.GAME.pool_flags.biohazard_enabled then
|
|
G.GAME.pool_flags.biohazard_enabled = true
|
|
end
|
|
|
|
G.GAME.round_resets.hands = G.GAME.round_resets.hands + card.ability.extra.adds_hand
|
|
ease_hands_played(3)
|
|
end,
|
|
|
|
remove_from_deck = function(self, card, from_debuff)
|
|
G.GAME.round_resets.hands = G.GAME.round_resets.hands - card.ability.extra.adds_hand
|
|
ease_hands_played(-3)
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
if context.after and not context.blueprint then
|
|
if pseudorandom('petridish'..G.SEED) < G.GAME.probabilities.normal / card.ability.extra.odds then
|
|
local target_card = pseudorandom_element(context.full_hand, pseudoseed(seed or 'petridishtarget'..G.SEED))
|
|
|
|
event({trigger = 'after', func = function()
|
|
play_sound('generic1')
|
|
target_card:juice_up(0.3, 0.3);
|
|
target_card:set_disenhancement(G.P_CENTERS.m_unstb_biohazard)
|
|
|
|
return true end })
|
|
|
|
forced_message("Infected", target_card, G.C.RED, true)
|
|
end
|
|
end
|
|
end
|
|
})
|
|
|
|
--Anti-Enhancement Supports
|
|
create_joker({
|
|
name = 'Geiger Counter', id = 20,
|
|
rarity = 'Uncommon', cost = 6,
|
|
|
|
gameplay_tag = {'enh_disenh'},
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
vars = {{mult_rate = '6'}, {mult = '0'}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
|
|
info_queue[#info_queue+1] = G.P_CENTERS['m_unstb_radioactive']
|
|
|
|
--Check the number of radioactive card in the deck
|
|
local count =0
|
|
if (G.playing_cards) then
|
|
for _, v in pairs(G.playing_cards) do
|
|
if v.config.center == G.P_CENTERS.m_unstb_radioactive then count = count + 1 end
|
|
end
|
|
return { vars = {card.ability.extra.mult_rate, count*card.ability.extra.mult_rate}}
|
|
else
|
|
return { vars = {card.ability.extra.mult_rate, 0}}
|
|
end
|
|
end,
|
|
|
|
--Set sprites and hitbox
|
|
|
|
set_sprites = function(self, card, front)
|
|
local w_scale, h_scale = 53/71, 95/95
|
|
card.children.center.scale.y = card.children.center.scale.y * h_scale
|
|
card.children.center.scale.x = card.children.center.scale.x * w_scale
|
|
end,
|
|
|
|
set_ability = function(self, card, initial, delay_sprites)
|
|
local w_scale, h_scale = 53/71, 95/95
|
|
card.T.h = card.T.h * h_scale
|
|
card.T.w = card.T.w * w_scale
|
|
end,
|
|
|
|
load = function(self, card, initial, delay_sprites)
|
|
local w_scale, h_scale = 53/71, 95/95
|
|
card.T.h = card.T.h * h_scale
|
|
card.T.w = card.T.w * w_scale
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
--Main context
|
|
if context.joker_main then
|
|
local count=0
|
|
for _, v in pairs(G.playing_cards) do
|
|
if v.config.center == G.P_CENTERS.m_unstb_radioactive then count = count + 1 end
|
|
end
|
|
|
|
card.ability.extra.mult = count*card.ability.extra.mult_rate
|
|
|
|
return {
|
|
mult_mod = card.ability.extra.mult,
|
|
message = localize { type = 'variable', key = 'a_mult', vars = { card.ability.extra.mult } }
|
|
}
|
|
end
|
|
|
|
end,
|
|
|
|
custom_in_pool = function(self, args)
|
|
|
|
--Spawns if there is at least one radioactive card
|
|
for _, v in pairs(G.playing_cards) do
|
|
if v.config.center == G.P_CENTERS.m_unstb_radioactive then return true end
|
|
end
|
|
return false
|
|
|
|
end
|
|
})
|
|
|
|
create_joker({
|
|
name = 'Strych Nine', id = 21,
|
|
rarity = 'Uncommon', cost = 5,
|
|
|
|
gameplay_tag = {'enh_disenh'},
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
vars = {{chip_rate = '9'}, {chip = '0'}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
|
|
info_queue[#info_queue+1] = {set = 'Other', key = 'poison_tooltip'}
|
|
|
|
--Check the number of poison card in the deck
|
|
local count =0
|
|
if (G.playing_cards) then
|
|
for _, v in pairs(G.playing_cards) do
|
|
if v.config.center == G.P_CENTERS.m_unstb_poison then count = count + 1 end
|
|
end
|
|
return { vars = {card.ability.extra.chip_rate, count*card.ability.extra.chip_rate}}
|
|
else
|
|
return { vars = {card.ability.extra.chip_rate, 0}}
|
|
end
|
|
end,
|
|
|
|
|
|
calculate = function(self, card, context)
|
|
--Main context
|
|
if context.joker_main then
|
|
local count=0
|
|
for _, v in pairs(G.playing_cards) do
|
|
if v.config.center == G.P_CENTERS.m_unstb_poison then count = count + 1 end
|
|
end
|
|
|
|
card.ability.extra.chip = count*card.ability.extra.chip_rate
|
|
|
|
return {
|
|
chip_mod = card.ability.extra.chip,
|
|
message = localize { type = 'variable', key = 'a_chips', vars = { card.ability.extra.chip } }
|
|
}
|
|
end
|
|
|
|
end,
|
|
|
|
custom_in_pool = function(self, args)
|
|
|
|
--Spawns if there is at least one poison card
|
|
for _, v in pairs(G.playing_cards) do
|
|
if v.config.center == G.P_CENTERS.m_unstb_poison then return true end
|
|
end
|
|
return false
|
|
|
|
end
|
|
})
|
|
|
|
create_joker({
|
|
name = 'Vaccination Card', id = 22,
|
|
rarity = 'Uncommon', cost = 7,
|
|
|
|
gameplay_tag = {'enh_disenh'},
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
vars = {{xmult_rate = '0.5'}, {xmult = '1'}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
|
|
info_queue[#info_queue+1] = G.P_CENTERS['m_unstb_biohazard']
|
|
|
|
--Check the number of biohazard card on hand
|
|
local count = 0
|
|
if (G.hand) then
|
|
for i = 1, #G.hand.cards do
|
|
if G.hand.cards[i].config.center == G.P_CENTERS.m_unstb_biohazard and not G.hand.cards[i].healed then
|
|
count = count+1
|
|
end
|
|
end
|
|
return { vars = {card.ability.extra.xmult_rate, 1+count*card.ability.extra.xmult_rate}}
|
|
else
|
|
return { vars = {card.ability.extra.xmult_rate, 1}}
|
|
end
|
|
end,
|
|
|
|
|
|
calculate = function(self, card, context)
|
|
--Main context
|
|
if context.joker_main then
|
|
local count=0
|
|
|
|
for i = 1, #G.hand.cards do
|
|
if G.hand.cards[i].config.center == G.P_CENTERS.m_unstb_biohazard and not G.hand.cards[i].healed then
|
|
count = count+1
|
|
end
|
|
end
|
|
|
|
card.ability.extra.xmult = 1+count*card.ability.extra.xmult_rate
|
|
|
|
return {
|
|
Xmult_mod = card.ability.extra.xmult,
|
|
message = localize { type = 'variable', key = 'a_xmult', vars = { card.ability.extra.xmult } }
|
|
}
|
|
end
|
|
|
|
end,
|
|
|
|
custom_in_pool = function(self, args)
|
|
|
|
--Spawns if there is at least one biohazard card
|
|
for _, v in pairs(G.playing_cards) do
|
|
if v.config.center == G.P_CENTERS.m_unstb_biohazard then return true end
|
|
end
|
|
return false
|
|
|
|
end
|
|
})
|
|
|
|
--Miscellaneous
|
|
|
|
-- Joker 2
|
|
|
|
create_joker({
|
|
name = 'Joker2', id = 11,
|
|
rarity = 'Common', cost = 4,
|
|
|
|
gameplay_tag = {'j_shitpost'},
|
|
|
|
vars = {{mult = 4}, {xmult = 2}, {odds_destroy = 4}},
|
|
custom_vars = function(self, info_queue, card)
|
|
return {vars = {card.ability.extra.mult, card.ability.extra.xmult, G.GAME and G.GAME.probabilities.normal or 1, card.ability.extra.odds_destroy}}
|
|
end,
|
|
|
|
blueprint = true, eternal = false, perishable = true,
|
|
|
|
calculate = function(self, card, context)
|
|
|
|
--Main context
|
|
if context.joker_main then
|
|
return {
|
|
mult = card.ability.extra.mult,
|
|
xmult = card.ability.extra.xmult,
|
|
--message = localize { type = 'variable', key = 'a_xmult', vars = { card.ability.extra.xmult } }
|
|
}
|
|
end
|
|
|
|
--End of round check, make sure it's checked absolutely once per round
|
|
if context.end_of_round and not context.other_card and not context.repetition and not context.game_over and not context.blueprint then
|
|
if pseudorandom('joker2'..G.SEED) < G.GAME.probabilities.normal / card.ability.extra.odds_destroy then
|
|
event({func = function()
|
|
|
|
play_sound('tarot1')
|
|
card.T.r = -0.2
|
|
card:juice_up(0.3, 0.4)
|
|
card.states.drag.is = true
|
|
card.children.center.pinch.x = true
|
|
|
|
--Destroy Card
|
|
event({trigger = 'after', delay = 0.3, func = function()
|
|
|
|
G.jokers:remove_card(card)
|
|
card:remove()
|
|
card = nil
|
|
return true end })
|
|
|
|
return true end })
|
|
return {
|
|
message = 'Flopped',
|
|
colour = G.C.ORANGE
|
|
}
|
|
else
|
|
return {
|
|
message = 'Safe!',
|
|
colour = G.C.GREEN
|
|
}
|
|
end
|
|
end
|
|
end
|
|
})
|
|
|
|
-- Joker Stairs
|
|
create_joker({
|
|
name = 'Joker Stairs', id = 12,
|
|
rarity = 'Uncommon', cost = 8,
|
|
|
|
gameplay_tag = {'j_shitpost'},
|
|
|
|
vars = {{mult_rate = 4}, {mult = 0}},
|
|
custom_vars = function(self, info_queue, card)
|
|
return {vars = {card.ability.extra.mult_rate, card.ability.extra.mult}}
|
|
end,
|
|
|
|
blueprint = true, eternal = true, perishable = false,
|
|
|
|
calculate = function(self, card, context)
|
|
--Shop
|
|
if context.buying_card and context.card ~= card then
|
|
if unstb_global.name_joker[context.card.config.center.key] then
|
|
--print("Joker Stair Triggered!")
|
|
card.ability.extra.mult = card.ability.extra.mult + card.ability.extra.mult_rate
|
|
event({
|
|
func = function()
|
|
big_juice(card)
|
|
forced_message("Upgraded!", card, G.C.MULT, true)
|
|
--card_eval_status_text(card,'extra',nil, nil, nil,{message = "Upgraded", colour = G.C.MULT, instant = true})
|
|
return true end})
|
|
end
|
|
end
|
|
|
|
--Main context
|
|
if context.joker_main then
|
|
if card.ability.extra.mult > 0 then
|
|
return {
|
|
mult_mod = card.ability.extra.mult,
|
|
message = localize { type = 'variable', key = 'a_mult', vars = { card.ability.extra.mult } }
|
|
}
|
|
end
|
|
end
|
|
|
|
end
|
|
})
|
|
|
|
--A special function to check for blueprint compat for both sides
|
|
G.FUNCS.blueprint_compat_dside_l = function(e)
|
|
if e.config.ref_table.ability.blueprint_compat_l ~= e.config.ref_table.ability.blueprint_compat_check_l then
|
|
if e.config.ref_table.ability.blueprint_compat_l == 'compatible' then
|
|
e.config.colour = mix_colours(G.C.GREEN, G.C.JOKER_GREY, 0.8)
|
|
elseif e.config.ref_table.ability.blueprint_compat_l == 'incompatible' then
|
|
e.config.colour = mix_colours(G.C.RED, G.C.JOKER_GREY, 0.8)
|
|
end
|
|
e.config.ref_table.ability.blueprint_compat_ui_l = ' '..localize('k_blueprint_l_'..e.config.ref_table.ability.blueprint_compat_l)..' '
|
|
e.config.ref_table.ability.blueprint_compat_check_l = e.config.ref_table.ability.blueprint_compat_l
|
|
end
|
|
end
|
|
|
|
G.FUNCS.blueprint_compat_dside_r = function(e)
|
|
if e.config.ref_table.ability.blueprint_compat_r ~= e.config.ref_table.ability.blueprint_compat_check_r then
|
|
if e.config.ref_table.ability.blueprint_compat_r == 'compatible' then
|
|
e.config.colour = mix_colours(G.C.GREEN, G.C.JOKER_GREY, 0.8)
|
|
elseif e.config.ref_table.ability.blueprint_compat_r == 'incompatible' then
|
|
e.config.colour = mix_colours(G.C.RED, G.C.JOKER_GREY, 0.8)
|
|
end
|
|
e.config.ref_table.ability.blueprint_compat_ui_r = ' '..localize('k_blueprint_r_'..e.config.ref_table.ability.blueprint_compat_r)..' '
|
|
e.config.ref_table.ability.blueprint_compat_check_r = e.config.ref_table.ability.blueprint_compat_r
|
|
end
|
|
end
|
|
|
|
--Plagiarism
|
|
create_joker({
|
|
name = 'Plagiarism', id = 46,
|
|
rarity = 'Uncommon', cost = 10,
|
|
|
|
gameplay_tag = {'j_shitpost'},
|
|
|
|
vars = {{dir = 0}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
return {vars = {card.ability.extra.dir==0 and 'Left' or 'Right'}}
|
|
end,
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
set_ability = function(self, card, initial, delay_sprites)
|
|
--Random direction
|
|
card.ability.extra.dir = 0
|
|
if pseudorandom('plagiarism'..G.SEED) > 0.5 then
|
|
card.ability.extra.dir = 1
|
|
end
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
--Code based on Familiar's Crimsonotype
|
|
|
|
--This bit of code runs before hand played, cannot copyable by other blueprint
|
|
if context.before and not context.blueprint and not context.repetition and not context.repetition_only then
|
|
card.ability.extra.dir = 0
|
|
|
|
if pseudorandom('plagiarism'..G.SEED) > 0.5 then
|
|
card.ability.extra.dir = 1
|
|
end
|
|
|
|
forced_message(card.ability.extra.dir==0 and 'Left' or 'Right', card, G.C.ORANGE, true)
|
|
end
|
|
|
|
local other_joker = nil
|
|
for i = 1, #G.jokers.cards do
|
|
if G.jokers.cards[i] == card then
|
|
if card.ability.extra.dir==0 then
|
|
other_joker = G.jokers.cards[i - 1]
|
|
else
|
|
other_joker = G.jokers.cards[i + 1]
|
|
end
|
|
end
|
|
end
|
|
if other_joker and other_joker ~= self then
|
|
|
|
--local newcontext = context
|
|
context.blueprint = (context.blueprint and (context.blueprint + 1)) or 1
|
|
context.blueprint_card = context.blueprint_card or card
|
|
|
|
if context.blueprint > #G.jokers.cards + 1 then
|
|
return
|
|
end
|
|
|
|
local other_joker_ret, trig = other_joker:calculate_joker(context)
|
|
|
|
--Context needs resetting afterwards, otherwise this value keeps persisting
|
|
context.blueprint = nil
|
|
|
|
local eff_card = context.blueprint_card or card
|
|
context.blueprint_card = nil
|
|
|
|
if other_joker_ret or trig then
|
|
if not other_joker_ret then
|
|
other_joker_ret = {}
|
|
end
|
|
|
|
other_joker_ret.card = eff_card
|
|
other_joker_ret.colour = G.C.GREEN
|
|
other_joker_ret.no_callback = true
|
|
|
|
--IDK why these are not applied to the return value, it even worked fine when I commented return line out when it shouldn't
|
|
|
|
return other_joker_ret
|
|
end
|
|
end
|
|
end
|
|
})
|
|
|
|
--Joker Throwing Card
|
|
create_joker({
|
|
name = 'Joker Throwing Card', id = 47,
|
|
rarity = 'Rare', cost = 8,
|
|
|
|
vars = {{rate = 2}, {reduce = 10}, {odds_destroy = 4}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
return {vars = {card.ability.extra.reduce, G.GAME and G.GAME.probabilities.normal or 1, card.ability.extra.odds_destroy, card.ability.extra.rate}}
|
|
end,
|
|
|
|
blueprint = false, eternal = true, perishable = false,
|
|
|
|
calculate = function(self, card, context)
|
|
--Reduce Blind Size
|
|
if context.setting_blind and not context.blueprint then
|
|
local decrease = math.min(card.ability.extra.reduce, 70) --Failsafe, just in case other value-altering joker did the funnies
|
|
|
|
G.GAME.blind.chips = G.GAME.blind.chips * (1 - decrease * 0.01)
|
|
G.GAME.blind.chip_text = number_format(G.GAME.blind.chips)
|
|
end
|
|
|
|
--Check before hand is played
|
|
if context.before and context.scoring_hand and not context.blueprint then
|
|
|
|
local isActivated = pseudorandom('throwingcard'..G.SEED) < G.GAME.probabilities.normal / card.ability.extra.odds_destroy
|
|
|
|
if isActivated and card.ability.extra.reduce < 70 then --Won't activate if the reduction reach the hardcoded limit (to prevent other value-altering joker)
|
|
local target_card = pseudorandom_element(context.scoring_hand, pseudoseed('throwingcard'..G.SEED))
|
|
target_card.is_destroying = true
|
|
end
|
|
end
|
|
|
|
--Handle Card Destroy
|
|
if context.destroying_card and not context.blueprint then
|
|
if context.destroying_card.is_destroying then
|
|
if card.ability.extra.reduce < 70 then
|
|
card.ability.extra.reduce = card.ability.extra.reduce + card.ability.extra.rate
|
|
card.ability.extra.reduce = math.min(card.ability.extra.reduce, 70)
|
|
|
|
forced_message("Upgraded!", card, G.C.PURPLE, true)
|
|
end
|
|
|
|
return true --Destroy the card
|
|
end
|
|
end
|
|
end
|
|
})
|
|
|
|
--Jackhammer
|
|
create_joker({
|
|
name = 'Jackhammer', id = 16,
|
|
rarity = 'Uncommon', cost = 7,
|
|
|
|
gameplay_tag = {'j_powerful'},
|
|
|
|
vars = {{retrigger_times = 5}, {is_activate = false}},
|
|
custom_vars = function(self, info_queue, card)
|
|
return {vars = {card.ability.extra.retrigger_times}}
|
|
end,
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
calculate = function(self, card, context)
|
|
|
|
--Pre-hand check
|
|
if context.before and not context.blueprint then
|
|
card.ability.extra.is_activate = false
|
|
|
|
local jack_count = 0
|
|
for i=1, #context.scoring_hand do
|
|
if context.scoring_hand[i].base.value == 'Jack' then
|
|
jack_count = jack_count + 1
|
|
end
|
|
end
|
|
|
|
if jack_count==1 then
|
|
card.ability.extra.is_activate = true
|
|
end
|
|
|
|
end
|
|
|
|
--Main context
|
|
if context.cardarea == G.play and context.repetition and not context.repetition_only and card.ability.extra.is_activate then
|
|
if context.other_card.base.value == 'Jack' then
|
|
card.ability.extra.target_jack = context.other_card
|
|
|
|
return {
|
|
message = 'Again!',
|
|
repetitions = card.ability.extra.retrigger_times,
|
|
card = context.blueprint_card or card
|
|
}
|
|
end
|
|
end
|
|
|
|
if context.destroying_card and not context.blueprint then
|
|
--This context is called on every single card in the scoring hand
|
|
--Check if the card called is the same as target card
|
|
if context.destroying_card == card.ability.extra.target_jack then
|
|
card.ability.extra.target_jack = nil
|
|
return true --Destroy the card
|
|
end
|
|
end
|
|
|
|
end
|
|
})
|
|
|
|
--Jack of All Trades
|
|
create_joker({
|
|
name = 'Jack of All Trades', id = 60,
|
|
rarity = 'Uncommon', cost = 6,
|
|
|
|
vars = {{chips = 20}, {mult = 3}, {xmult = 1.25}, {money = 1}},
|
|
custom_vars = function(self, info_queue, card)
|
|
return {vars = {card.ability.extra.chips, card.ability.extra.mult, card.ability.extra.xmult, card.ability.extra.money}}
|
|
end,
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
|
|
calculate = function(self, card, context)
|
|
if context.individual and context.cardarea == G.play then
|
|
if context.other_card.base.value == 'Jack' then
|
|
ease_dollars(card.ability.extra.money)
|
|
return {
|
|
chips = card.ability.extra.chips,
|
|
mult = card.ability.extra.mult,
|
|
x_mult = card.ability.extra.xmult,
|
|
card = card
|
|
}
|
|
end
|
|
end
|
|
end
|
|
})
|
|
|
|
--Magic Trick Card
|
|
create_joker({
|
|
name = 'Magic Trick Card', id = 0, ex_art = true,
|
|
rarity = 'Uncommon', cost = 4,
|
|
|
|
vars = {{side = 0}},
|
|
custom_vars = function(self, info_queue, card)
|
|
|
|
local rank1 = localize(card.ability.extra.source_rank, 'ranks')
|
|
local suit1 = localize(card.ability.extra.source_suit, 'suits_plural')
|
|
|
|
local rank2 = localize(card.ability.extra.target_rank, 'ranks')
|
|
local suit2 = localize(card.ability.extra.target_suit, 'suits_plural')
|
|
|
|
local colour1 = G.C.SUITS[card.ability.extra.source_suit]
|
|
local colour2 = G.C.SUITS[card.ability.extra.target_suit]
|
|
|
|
return {vars = {rank1..' of '..suit1, rank2..' of '..suit2, colours = {colour1, colour2}}}
|
|
end,
|
|
|
|
blueprint = false, eternal = true, perishable = true,
|
|
|
|
set_ability = function(self, card, initial, delay_sprites)
|
|
if card.ability.extra.side == 0 then
|
|
card.ability.extra.source_suit = 'Hearts'
|
|
card.ability.extra.source_rank = 'Queen'
|
|
|
|
card.ability.extra.target_suit = 'Clubs'
|
|
card.ability.extra.target_rank = '7'
|
|
else
|
|
card.ability.extra.source_suit = 'Clubs'
|
|
card.ability.extra.source_rank = '7'
|
|
|
|
card.ability.extra.target_suit = 'Hearts'
|
|
card.ability.extra.target_rank = 'Queen'
|
|
end
|
|
card.children.center:set_sprite_pos({x = card.ability.extra.side, y = 0})
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
|
|
if context.pre_discard and not context.blueprint then
|
|
event({trigger = 'after', delay = 0.3, blockable = false,
|
|
func = function()
|
|
|
|
card:juice_up(1, 1)
|
|
|
|
if card.ability.extra.side == 0 then
|
|
card.ability.extra.side = 1
|
|
|
|
card.ability.extra.source_suit = 'Clubs'
|
|
card.ability.extra.source_rank = '7'
|
|
|
|
card.ability.extra.target_suit = 'Hearts'
|
|
card.ability.extra.target_rank = 'Queen'
|
|
else
|
|
card.ability.extra.side = 0
|
|
|
|
card.ability.extra.source_suit = 'Hearts'
|
|
card.ability.extra.source_rank = 'Queen'
|
|
|
|
card.ability.extra.target_suit = 'Clubs'
|
|
card.ability.extra.target_rank = '7'
|
|
end
|
|
card.children.center:set_sprite_pos({x = card.ability.extra.side, y = 0})
|
|
|
|
return true end})
|
|
|
|
card_eval_status_text(
|
|
card,
|
|
'extra',
|
|
nil, nil, nil,
|
|
{message = 'Flipped!', colour = G.C.ORANGE, instant = true}
|
|
)
|
|
end
|
|
|
|
if context.after and not context.blueprint then
|
|
for i = 1, #context.scoring_hand do
|
|
local currentCard = context.scoring_hand[i]
|
|
|
|
local is_activate = currentCard:is_suit(card.ability.extra.source_suit) and currentCard.base.value == card.ability.extra.source_rank
|
|
|
|
if is_activate then
|
|
--Flipping Animation
|
|
event({trigger = 'after', delay = 0.1, func = function() big_juice(card); currentCard:flip(); play_sound('card1', 1); currentCard:juice_up(0.3, 0.3); return true end })
|
|
|
|
--Changing Card Property
|
|
|
|
event({trigger = 'after', delay = 0.05, func = function()
|
|
SMODS.change_base(currentCard, card.ability.extra.target_suit, card.ability.extra.target_rank)
|
|
return true end })
|
|
|
|
--Unflipping Animation
|
|
event({trigger = 'after', delay = 0.1, func = function() currentCard:flip(); play_sound('tarot2', 1, 0.6); big_juice(card); currentCard:juice_up(0.3, 0.3); return true end })
|
|
forced_message("Changed!", currentCard, G.C.ORANGE, true)
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
})
|
|
|
|
--Queensland
|
|
create_joker({
|
|
name = 'Queensland', id = 61,
|
|
rarity = 'Rare', cost = 7,
|
|
|
|
gameplay_tag = {'enh_custom'},
|
|
|
|
vars = {{count_max = 5}, {count = 0}},
|
|
custom_vars = function(self, info_queue, card)
|
|
info_queue[#info_queue+1] = {set = 'Other', key = 'resource_tooltip'}
|
|
return {vars = {card.ability.extra.count_max, card.ability.extra.count_max - card.ability.extra.count}}
|
|
end,
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
|
|
calculate = function(self, card, context)
|
|
if context.individual and context.cardarea == G.play then
|
|
if context.other_card.base.value == 'Queen' then
|
|
if card.ability.extra.count < card.ability.extra.count_max then
|
|
if not context.blueprint then
|
|
card.ability.extra.count = card.ability.extra.count + 1
|
|
end
|
|
|
|
local other_card = context.other_card
|
|
|
|
event({func = function()
|
|
local rank = pseudorandom_element(SMODS.Ranks, pseudoseed('queensland')..G.SEED).card_key
|
|
local suit = SMODS.Suits[other_card.base.suit].card_key
|
|
|
|
local _card = Card(G.play.T.x + G.play.T.w/2, G.play.T.y, G.CARD_W, G.CARD_H, G.P_CARDS[suit..'_'..rank], G.P_CENTERS.m_unstb_resource, {playing_card = G.playing_card})
|
|
|
|
big_juice(context.blueprint_card or card)
|
|
|
|
_card:start_materialize({G.C.SECONDARY_SET.Enhanced})
|
|
G.play:emplace(_card)
|
|
table.insert(G.playing_cards, _card)
|
|
|
|
return true end
|
|
})
|
|
|
|
event({func = function()
|
|
G.deck.config.card_limit = G.deck.config.card_limit + 1
|
|
draw_card(G.play,G.deck, 90,'up', nil)
|
|
return true end
|
|
})
|
|
|
|
playing_card_joker_effects({true})
|
|
|
|
end
|
|
end
|
|
end
|
|
|
|
if context.end_of_round and not context.other_card and not context.repetition and not context.game_over and not context.blueprint then
|
|
if card.ability.extra.count > 0 then
|
|
card.ability.extra.count = 0
|
|
return {
|
|
message = 'Reset!'
|
|
}
|
|
end
|
|
end
|
|
end
|
|
})
|
|
|
|
--King of Pop
|
|
create_joker({
|
|
name = 'King of Pop', id = 62,
|
|
rarity = 'Rare', cost = 8,
|
|
|
|
gameplay_tag = {'j_powerful'},
|
|
|
|
vars = {{odds_destroy = 4}},
|
|
custom_vars = function(self, info_queue, card)
|
|
info_queue[#info_queue+1] = G.P_TAGS.tag_double
|
|
return {vars = {G.GAME and G.GAME.probabilities.normal or 1, card.ability.extra.odds_destroy}}
|
|
end,
|
|
|
|
blueprint = false, eternal = true, perishable = true,
|
|
|
|
calculate = function(self, card, context)
|
|
--Pre-hand check
|
|
if context.before and not context.blueprint then
|
|
for i=1, #context.scoring_hand do
|
|
if context.scoring_hand[i].base.value == 'King' and context.scoring_hand[i].config.center ~= G.P_CENTERS.c_base and not context.scoring_hand[i].config.center.disenhancement then
|
|
if pseudorandom('kingofpop'..G.SEED) < G.GAME.probabilities.normal / card.ability.extra.odds_destroy then
|
|
context.scoring_hand[i].to_destroy = true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
if context.destroying_card and not context.blueprint then
|
|
if context.destroying_card.to_destroy then
|
|
event({ trigger = 'after', delay = 0.5, func = function()
|
|
|
|
add_tag(Tag('tag_double'))
|
|
play_sound('generic1', 0.9 + math.random()*0.1, 0.8)
|
|
play_sound('holo1', 1.2 + math.random()*0.1, 0.4)
|
|
|
|
return true end
|
|
}
|
|
)
|
|
forced_message("Tag!", card, G.C.SECONDARY_SET.Enhanced)
|
|
|
|
return true --Destroy the card
|
|
end
|
|
end
|
|
end
|
|
})
|
|
|
|
--Polychrome Red Seal Steel Joker
|
|
create_joker({
|
|
name = 'prssj', id = 63,
|
|
rarity = 'Rare', cost = 10,
|
|
|
|
gameplay_tag = {'j_shitpost', 'j_powerful', 'edition_upgrade'},
|
|
|
|
vars = {{odds_upgrade = 8}, {odds_retrigger = 4}, {odds_hand = 2}, {hand_xmult = 2}},
|
|
custom_vars = function(self, info_queue, card)
|
|
info_queue[#info_queue+1] = {set = 'Other', key = 'upgrade_edition'}
|
|
|
|
return {vars = {G.GAME and G.GAME.probabilities.normal or 1, card.ability.extra.odds_upgrade, card.ability.extra.odds_retrigger, card.ability.extra.odds_hand, card.ability.extra.hand_xmult}}
|
|
end,
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
calculate = function(self, card, context)
|
|
|
|
--Upgrade Part
|
|
if context.before then
|
|
|
|
local upgrade_count = 0
|
|
for i = 1, #context.scoring_hand do
|
|
local current_card = context.scoring_hand[i]
|
|
|
|
if not current_card.debuff and current_card.base.value == 'King' and pseudorandom('prssj1'..G.SEED) < G.GAME.probabilities.normal / card.ability.extra.odds_upgrade then
|
|
upgrade_count = upgrade_count+1
|
|
edition_upgrade(current_card)
|
|
end
|
|
end
|
|
|
|
if upgrade_count > 0 then
|
|
--forced_message("Upgrade!", context.blueprint_card or card, G.C.SECONDARY_SET.Enhanced, true)
|
|
return {
|
|
message = 'Upgrade!',
|
|
colour = G.C.SECONDARY_SET.Enhanced,
|
|
card = context.blueprint_card or card,
|
|
}
|
|
end
|
|
|
|
end
|
|
|
|
if context.cardarea == G.play and context.repetition and not context.repetition_only and not context.other_card.debuff and context.other_card.base.value == 'King' then
|
|
if pseudorandom('prssj2'..G.SEED) < G.GAME.probabilities.normal / card.ability.extra.odds_retrigger then
|
|
return {
|
|
message = 'Again!',
|
|
repetitions = 1,
|
|
card = context.blueprint_card or card
|
|
}
|
|
end
|
|
end
|
|
|
|
if context.individual and context.cardarea == G.hand and not context.end_of_round and context.other_card.base.value == 'King' then
|
|
if pseudorandom('prssj3'..G.SEED) < G.GAME.probabilities.normal / card.ability.extra.odds_hand then
|
|
if context.other_card.debuff then
|
|
return {
|
|
message = localize('k_debuffed'),
|
|
colour = G.C.RED,
|
|
card = context.blueprint_card or card,
|
|
}
|
|
else
|
|
return {
|
|
x_mult = card.ability.extra.hand_xmult,
|
|
card = context.blueprint_card or card
|
|
}
|
|
end
|
|
end
|
|
end
|
|
end
|
|
})
|
|
|
|
--Master of One
|
|
create_joker({
|
|
name = 'Master of One', id = 64,
|
|
rarity = 'Uncommon', cost = 7,
|
|
|
|
gameplay_tag = {'rank_binary', 'j_alter'},
|
|
|
|
--vars = {},
|
|
custom_vars = function(self, info_queue, card)
|
|
return {vars = {}}
|
|
end,
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
add_to_deck = function(self, card, from_debuff)
|
|
--Enable rank 1 card in pools
|
|
if not from_debuff then
|
|
setPoolRankFlagEnable('unstb_1', true);
|
|
end
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
|
|
if context.setting_blind then
|
|
--Adds a card
|
|
event({trigger = 'after', func = function()
|
|
local rank = 'unstb_1'
|
|
local suit = pseudorandom_element(SMODS.Suits, pseudoseed('masterofone')..G.SEED).card_key
|
|
|
|
--Pooling Enhancements
|
|
local cen_pool = {}
|
|
for k, v in pairs(G.P_CENTER_POOLS["Enhanced"]) do
|
|
if not v.replace_base_card and not v.disenhancement then
|
|
cen_pool[#cen_pool+1] = v
|
|
end
|
|
end
|
|
|
|
local _card = Card(G.play.T.x + G.play.T.w/2, G.play.T.y, G.CARD_W, G.CARD_H, G.P_CARDS[suit..'_'..rank], pseudorandom_element(cen_pool, pseudoseed('masterofone')..G.SEED), {playing_card = G.playing_card})
|
|
|
|
_card:start_materialize({G.C.SECONDARY_SET.Enhanced})
|
|
G.play:emplace(_card)
|
|
table.insert(G.playing_cards, _card)
|
|
|
|
big_juice(context.blueprint_card or card)
|
|
card_eval_status_text(context.blueprint_card or card, 'extra', nil, nil, nil, {message = 'One!', colour = G.C.SECONDARY_SET.Enhanced})
|
|
|
|
return true end
|
|
})
|
|
|
|
event({trigger = 'after', func = function()
|
|
G.deck.config.card_limit = G.deck.config.card_limit + 1
|
|
draw_card(G.play,G.deck, 90,'up', nil)
|
|
return true end
|
|
})
|
|
|
|
playing_card_joker_effects({true})
|
|
end
|
|
|
|
end
|
|
})
|
|
|
|
--Spectre
|
|
create_joker({
|
|
name = 'Spectre', id = 9,
|
|
rarity = 'Uncommon', cost = 7,
|
|
|
|
vars = {{xmult_rate = 0.25}, {xmult = 1}},
|
|
custom_vars = function(self, info_queue, card)
|
|
return {vars = {card.ability.extra.xmult_rate, card.ability.extra.xmult}}
|
|
end,
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
set_ability = function(self, card, initial, delay_sprites)
|
|
if G.GAME and G.GAME.consumeable_usage_total then
|
|
card.ability.extra.xmult = 1 + G.GAME.consumeable_usage_total.spectral * card.ability.extra.xmult_rate
|
|
else
|
|
card.ability.extra.xmult = 1
|
|
end
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
|
|
--Upgrades
|
|
if context.using_consumeable and not context.blueprint then
|
|
if context.consumeable.ability.set == "Spectral" then
|
|
card.ability.extra.xmult = card.ability.extra.xmult + card.ability.extra.xmult_rate
|
|
event({
|
|
func = function()
|
|
big_juice(card)
|
|
forced_message("Upgraded!", card, G.C.MULT, true)
|
|
--card_eval_status_text(card,'extra',nil, nil, nil,{message = "Upgraded", colour = G.C.MULT, instant = true})
|
|
return true end})
|
|
end
|
|
end
|
|
|
|
--Main context
|
|
if context.joker_main then
|
|
return {
|
|
Xmult_mod = card.ability.extra.xmult,
|
|
message = localize { type = 'variable', key = 'a_xmult', vars = { card.ability.extra.xmult } }
|
|
}
|
|
end
|
|
|
|
end
|
|
})
|
|
|
|
--Library Card
|
|
create_joker({
|
|
name = 'Library Card', id = 52,
|
|
rarity = 'Uncommon', cost = 8,
|
|
|
|
vars = {{chips_rate = 5}, {mult_rate = 2}},
|
|
custom_vars = function(self, info_queue, card)
|
|
return {vars = {card.ability.extra.chips_rate, card.ability.extra.mult_rate}}
|
|
end,
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
|
|
calculate = function(self, card, context)
|
|
if context.individual and context.cardarea == G.play then
|
|
if not context.other_card.config.center.no_suit and unstb_global.name_suit[context.other_card.base.suit] then
|
|
local suit_info = unstb_global.name_suit[context.other_card.base.suit]
|
|
|
|
local totalChips = card.ability.extra.chips_rate * suit_info.count_consonant
|
|
local totalMult = card.ability.extra.mult_rate * suit_info.count_vowel
|
|
|
|
return {
|
|
chips = totalChips,
|
|
mult = totalMult,
|
|
card = card
|
|
}
|
|
end
|
|
end
|
|
end
|
|
})
|
|
|
|
--Collector's Album
|
|
create_joker({
|
|
name = 'Collector Album', id = 53,
|
|
rarity = 'Uncommon', cost = 8,
|
|
|
|
vars = {{chips_rate = 120}},
|
|
custom_vars = function(self, info_queue, card)
|
|
return {vars = {card.ability.extra.chips_rate, card.ability.extra.mult_rate}}
|
|
end,
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
|
|
calculate = function(self, card, context)
|
|
|
|
if context.other_joker then
|
|
--trigger on only joker with "Card" in the name
|
|
if unstb_global.name_card[context.other_joker.config.center.key] then
|
|
event({
|
|
func = function()
|
|
context.other_joker:juice_up(0.5, 0.5)
|
|
return true
|
|
end
|
|
})
|
|
return {
|
|
message = localize{type='variable',key='a_chips',vars={card.ability.extra.chips_rate}},
|
|
chip_mod = card.ability.extra.chips_rate
|
|
}
|
|
end
|
|
end
|
|
end
|
|
})
|
|
|
|
local function get_random_hand(current_hand, seed)
|
|
local _poker_hands = {}
|
|
|
|
--Populate list
|
|
for k, v in pairs(G.GAME.hands) do
|
|
if v.visible then _poker_hands[#_poker_hands+1] = k end
|
|
end
|
|
|
|
local new_hand = nil
|
|
while not new_hand do
|
|
new_hand = pseudorandom_element(_poker_hands, pseudoseed(seed or 'rand_hand'))
|
|
if new_hand == current_hand then new_hand = nil end
|
|
end
|
|
|
|
return new_hand
|
|
end
|
|
|
|
--Throwing Hands
|
|
create_joker({
|
|
name = 'Throwing Hands', id = 8,
|
|
rarity = 'Common', cost = 5,
|
|
|
|
vars = {{target_hand = 'High Card'}, {odds_base = 2}, {odds_destroy = 3}, {xmult = 4}},
|
|
custom_vars = function(self, info_queue, card)
|
|
return {vars = {card.ability.extra.xmult, card.ability.extra.odds_base * (G.GAME and G.GAME.probabilities.normal or 1), card.ability.extra.odds_destroy, localize(card.ability.extra.target_hand, 'poker_hands')}}
|
|
end,
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
set_ability = function(self,card, initial, delay_sprites)
|
|
|
|
--Random Poker Hand
|
|
card.ability.extra.target_hand = get_random_hand(card.ability.extra.target_hand, 'throwinghands'..G.SEED)
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
|
|
if context.joker_main and context.scoring_name ~= nil and context.scoring_hand then
|
|
local is_destroyed = false;
|
|
|
|
if context.scoring_name ~= card.ability.extra.target_hand then
|
|
if pseudorandom('throwinghands'..G.SEED) < G.GAME.probabilities.normal * card.ability.extra.odds_base / card.ability.extra.odds_destroy then
|
|
is_destroyed = true
|
|
end
|
|
end
|
|
|
|
if not is_destroyed then
|
|
return {
|
|
xmult = card.ability.extra.xmult,
|
|
}
|
|
else
|
|
if not context.blueprint then
|
|
event({func = function()
|
|
|
|
play_sound('tarot1')
|
|
card.T.r = -0.2
|
|
card:juice_up(0.3, 0.4)
|
|
card.states.drag.is = true
|
|
card.children.center.pinch.x = true
|
|
|
|
--Destroy Card
|
|
event({trigger = 'after', delay = 0.3, func = function()
|
|
|
|
G.jokers:remove_card(card)
|
|
card:remove()
|
|
card = nil
|
|
return true end })
|
|
|
|
return true end })
|
|
return {
|
|
message = 'Bye',
|
|
}
|
|
end
|
|
end
|
|
|
|
|
|
end
|
|
|
|
if context.end_of_round and not (context.individual or context.repetition or context.blueprint) then
|
|
card.ability.extra.target_hand = get_random_hand(card.ability.extra.target_hand, 'throwinghands'..G.SEED)
|
|
|
|
return {
|
|
message = card.ability.extra.target_hand
|
|
}
|
|
end
|
|
end
|
|
})
|
|
|
|
--Imperial Bower
|
|
create_joker({
|
|
name = 'Imperial Bower', id = 58,
|
|
rarity = 'Common', cost = 7,
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
vars = { {xmult = 3}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
|
|
return { vars = {card.ability.extra.xmult}}
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
|
|
if context.joker_main and next(context.poker_hands['Straight']) then
|
|
|
|
local face_count = 0
|
|
|
|
for i=1, #context.scoring_hand do
|
|
if context.scoring_hand[i]:is_face() then
|
|
face_count = face_count+1
|
|
end
|
|
end
|
|
|
|
if face_count > 0 then
|
|
return {
|
|
Xmult_mod = card.ability.extra.xmult,
|
|
message = localize { type = 'variable', key = 'a_xmult', vars = { card.ability.extra.xmult } }
|
|
}
|
|
end
|
|
|
|
end
|
|
|
|
end,
|
|
})
|
|
|
|
--The Jolly Joker
|
|
create_joker({
|
|
name = 'The Jolly Joker', id = 59,
|
|
rarity = 'Uncommon', cost = 6,
|
|
|
|
blueprint = true, eternal = true, perishable = false,
|
|
|
|
vars = { {mult_rate = 8}, {mult = 0}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
|
|
return { vars = {card.ability.extra.mult_rate, card.ability.extra.mult}}
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
|
|
if context.before and context.scoring_hand and not context.blueprint then
|
|
if next(context.poker_hands['Pair']) then
|
|
|
|
card.ability.extra.mult = card.ability.extra.mult + card.ability.extra.mult_rate
|
|
|
|
return {
|
|
message = 'Upgraded!',
|
|
colour = G.C.MULT,
|
|
card = card
|
|
}
|
|
|
|
elseif card.ability.extra.mult > 0 then
|
|
card.ability.extra.mult = 0
|
|
|
|
event({ trigger = 'after', delay = 0.2, func = function()
|
|
play_sound('tarot1')
|
|
return true end })
|
|
|
|
return {
|
|
message = 'Reset',
|
|
card = card
|
|
}
|
|
end
|
|
end
|
|
|
|
if context.joker_main then
|
|
if card.ability.extra.mult > 0 then
|
|
return {
|
|
mult_mod = card.ability.extra.mult,
|
|
message = localize { type = 'variable', key = 'a_mult', vars = { card.ability.extra.mult } }
|
|
}
|
|
end
|
|
|
|
end
|
|
|
|
end,
|
|
})
|
|
|
|
--Get Out of Jail Free Card
|
|
create_joker({
|
|
name = 'Get Out of Jail Free Card', id = 48,
|
|
rarity = 'Rare', cost = 10,
|
|
|
|
blueprint = false, eternal = false, perishable = true,
|
|
|
|
--vars = { {times = 1}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
|
|
local activate_text = 'Inactive'
|
|
local activate_color = G.C.RED
|
|
if G.STATE == G.STATES.SELECTING_HAND then
|
|
activate_text = 'Active'
|
|
activate_color = G.C.GREEN
|
|
end
|
|
|
|
return {vars = {activate_text,
|
|
colours = {activate_color} }}
|
|
end,
|
|
|
|
--Set sprites and hitbox
|
|
|
|
set_sprites = function(self, card, front)
|
|
local w_scale, h_scale = 64/71, 93/95
|
|
card.children.center.scale.y = card.children.center.scale.y * h_scale
|
|
card.children.center.scale.x = card.children.center.scale.x * w_scale
|
|
end,
|
|
|
|
set_ability = function(self, card, initial, delay_sprites)
|
|
local w_scale, h_scale = 64/71, 93/95
|
|
card.T.h = card.T.h * h_scale
|
|
card.T.w = card.T.w * w_scale
|
|
end,
|
|
|
|
load = function(self, card, initial, delay_sprites)
|
|
local w_scale, h_scale = 64/71, 93/95
|
|
card.T.h = card.T.h * h_scale
|
|
card.T.w = card.T.w * w_scale
|
|
end,
|
|
|
|
add_to_deck = function(self, card, from_debuff)
|
|
--Set the flag to true immediately once this joker has been picked up, it can't spawn again for the rest of the session
|
|
G.GAME.pool_flags.jailfree_get = true
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
--Referenced from DebugPlus's "Win Blind" function
|
|
if context.selling_self and not context.blueprint then
|
|
if G.STATE ~= G.STATES.SELECTING_HAND then
|
|
return
|
|
end
|
|
G.GAME.chips = G.GAME.blind.chips
|
|
G.STATE = G.STATES.HAND_PLAYED
|
|
G.STATE_COMPLETE = true
|
|
end_round()
|
|
end
|
|
end,
|
|
|
|
custom_in_pool = function(self, args)
|
|
|
|
--Spawns if this card has not been picked before
|
|
return not G.GAME.pool_flags.jailfree_get
|
|
|
|
end
|
|
|
|
})
|
|
|
|
--Tanzaku
|
|
create_joker({
|
|
name = 'Tanzaku', id = 70,
|
|
rarity = 'Rare', cost = 8,
|
|
|
|
gameplay_tag = {'j_powerful'},
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
vars = {{ repetitions = 0 }, { repetition_rate = 1 } },
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
return {vars = {card.ability.extra.repetitions, card.ability.extra.repetition_rate}}
|
|
end,
|
|
|
|
--Set sprites and hitbox
|
|
|
|
set_sprites = function(self, card, front)
|
|
local w_scale, h_scale = 50/71, 80/95
|
|
card.children.center.scale.y = card.children.center.scale.y * h_scale
|
|
card.children.center.scale.x = card.children.center.scale.x * w_scale
|
|
end,
|
|
|
|
set_ability = function(self, card, initial, delay_sprites)
|
|
local w_scale, h_scale = 50/71, 80/95
|
|
card.T.h = card.T.h * h_scale
|
|
card.T.w = card.T.w * w_scale
|
|
end,
|
|
|
|
load = function(self, card, initial, delay_sprites)
|
|
local w_scale, h_scale = 50/71, 80/95
|
|
card.T.h = card.T.h * h_scale
|
|
card.T.w = card.T.w * w_scale
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
if context.cardarea == G.play and context.repetition and not context.repetition_only then
|
|
if context.other_card.seal then
|
|
return {
|
|
message = 'Again!',
|
|
repetitions = card.ability.extra.repetitions,
|
|
card = context.blueprint_card or card
|
|
}
|
|
end
|
|
end
|
|
|
|
--The scaling part is not copyable by Blueprint
|
|
if context.discard and not context.blueprint then
|
|
|
|
local currentCard = context.other_card
|
|
|
|
--Not debuffed, and has seal
|
|
if not currentCard.debuff and currentCard.seal then
|
|
card.ability.extra.repetitions = card.ability.extra.repetitions + card.ability.extra.repetition_rate
|
|
|
|
--forced_message('+'..card.ability.extra.repetition_rate, card, G.C.ORANGE, true)
|
|
return {
|
|
message = '+'..card.ability.extra.repetition_rate,
|
|
card = card
|
|
}
|
|
end
|
|
|
|
end
|
|
|
|
--End of round check, make sure it's checked absolutely once per round
|
|
if context.end_of_round and not context.other_card and not context.repetition and not context.game_over and not context.blueprint then
|
|
if card.ability.extra.repetitions > 0 then
|
|
card.ability.extra.repetitions = 0
|
|
return {
|
|
message = 'Reset!'
|
|
}
|
|
end
|
|
end
|
|
end
|
|
})
|
|
|
|
--Glass Cannon
|
|
create_joker({
|
|
name = 'Glass Cannon', id = 68,
|
|
rarity = 'Rare', cost = 8,
|
|
|
|
gameplay_tag = {'j_powerful'},
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
vars = {{ repetitions = 1 }},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
info_queue[#info_queue+1] = G.P_CENTERS.m_glass
|
|
return {vars = {card.ability.extra.repetitions}}
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
if context.cardarea == G.play and context.repetition and not context.repetition_only then
|
|
if context.other_card.config.center == G.P_CENTERS.m_glass then
|
|
return {
|
|
message = 'Again!',
|
|
repetitions = card.ability.extra.repetitions,
|
|
card = context.blueprint_card or card
|
|
}
|
|
end
|
|
end
|
|
|
|
if context.destroying_card and not context.blueprint then
|
|
if context.destroying_card.config.center == G.P_CENTERS.m_glass then
|
|
return true --Destroy the card
|
|
end
|
|
end
|
|
end
|
|
})
|
|
|
|
--Pity Rate Drop
|
|
create_joker({
|
|
name = 'Pity Rate Drop', id = 71,
|
|
rarity = 'Rare', cost = 8,
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
vars = {{ odds = 8 }, {odds_rate = 1}, {odds_current = 1}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
return {vars = {card.ability.extra.odds_current * (G.GAME and G.GAME.probabilities.normal or 1), card.ability.extra.odds, card.ability.extra.odds_rate * (G.GAME and G.GAME.probabilities.normal or 1), G.GAME and G.GAME.probabilities.normal or 1}}
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
|
|
if context.setting_blind and #G.jokers.cards + G.GAME.joker_buffer < G.jokers.config.card_limit then
|
|
if pseudorandom('pity_rate_drop'..G.SEED) < G.GAME.probabilities.normal * card.ability.extra.odds_current / card.ability.extra.odds then
|
|
|
|
if context.blueprint then
|
|
card.ability.extra.blueprint_created = true
|
|
end
|
|
card.ability.extra.odds_current = 1
|
|
|
|
local jokers_to_create = math.min(1, G.jokers.config.card_limit - (#G.jokers.cards + G.GAME.joker_buffer))
|
|
G.GAME.joker_buffer = G.GAME.joker_buffer + jokers_to_create
|
|
event({
|
|
func = function()
|
|
for i = 1, jokers_to_create do
|
|
local card = create_card('Joker', G.jokers, nil, 1, nil, nil, nil, 'pity_rate_drop')
|
|
card:add_to_deck()
|
|
G.jokers:emplace(card)
|
|
card:start_materialize()
|
|
end
|
|
G.GAME.joker_buffer = 0
|
|
return true
|
|
end})
|
|
card_eval_status_text(context.blueprint_card or card, 'extra', nil, nil, nil, {message = 'Create!', colour = G.C.RED})
|
|
else
|
|
--Odds increments part are not copyable by Blueprint
|
|
if not context.blueprint then
|
|
--Increase odds, only if a card has not been created by blueprint prior
|
|
|
|
if not card.ability.extra.blueprint_created then
|
|
card.ability.extra.odds_current = card.ability.extra.odds_current + card.ability.extra.odds_rate
|
|
else
|
|
card.ability.extra.blueprint_created = nil
|
|
end
|
|
|
|
play_nope_sound()
|
|
card_eval_status_text(card, 'extra', nil, nil, nil, {message = 'Nope', colour = G.C.RED})
|
|
end
|
|
end
|
|
end
|
|
end
|
|
})
|
|
|
|
--Salmon Run
|
|
create_joker({
|
|
name = 'Salmon Run', id = 10,
|
|
rarity = 'Uncommon', cost = 7,
|
|
|
|
vars = {{odds = 7}},
|
|
custom_vars = function(self, info_queue, card)
|
|
return {vars = {G.GAME and G.GAME.probabilities.normal or 1, card.ability.extra.odds}}
|
|
end,
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
calculate = function(self, card, context)
|
|
if context.individual and context.cardarea == G.play then
|
|
local currentCard = context.other_card
|
|
|
|
if not currentCard.config.center.no_rank and currentCard.base.value == '7' then
|
|
local isActivated = pseudorandom('salmonrun'..G.SEED) < G.GAME.probabilities.normal / card.ability.extra.odds
|
|
|
|
if isActivated then
|
|
event({func = function()
|
|
--Copy Card
|
|
local _card = copy_card(currentCard, nil, nil, G.playing_card)
|
|
_card:start_materialize({G.C.SECONDARY_SET.Enhanced})
|
|
G.play:emplace(_card)
|
|
table.insert(G.playing_cards, _card)
|
|
|
|
return true end
|
|
})
|
|
|
|
event({func = function()
|
|
G.deck.config.card_limit = G.deck.config.card_limit + 1
|
|
draw_card(G.play,G.deck, 90,'up', nil)
|
|
return true end
|
|
})
|
|
|
|
playing_card_joker_effects({true})
|
|
end
|
|
end
|
|
end
|
|
end
|
|
})
|
|
|
|
--Cool S
|
|
create_joker({
|
|
name = 'Cool S', id = 66,
|
|
rarity = 'Common', cost = 8,
|
|
|
|
vars = {},
|
|
custom_vars = function(self, info_queue, card)
|
|
return {vars = {}}
|
|
end,
|
|
|
|
blueprint = false, eternal = true, perishable = true,
|
|
|
|
calculate = function(self, card, context)
|
|
if context.after and not context.blueprint then
|
|
for i = 1, #context.scoring_hand do
|
|
local currentCard = context.scoring_hand[i]
|
|
|
|
if currentCard.base.value == '8' then
|
|
--Pooling Enhancements
|
|
local cen_pool = {}
|
|
for k, v in pairs(G.P_CENTER_POOLS["Enhanced"]) do
|
|
if not v.replace_base_card and not v.disenhancement then
|
|
cen_pool[#cen_pool+1] = v
|
|
end
|
|
end
|
|
|
|
--Flipping Animation
|
|
event({trigger = 'after', delay = 0.1, func = function() currentCard:flip(); play_sound('card1', 1); currentCard:juice_up(0.3, 0.3); return true end })
|
|
|
|
--Changing Card Property
|
|
|
|
event({trigger = 'after', delay = 0.05, func = function()
|
|
|
|
currentCard:set_ability(pseudorandom_element(cen_pool, pseudoseed('cool_s'..G.SEED)))
|
|
|
|
return true end })
|
|
|
|
--Unflipping Animation
|
|
event({trigger = 'after', delay = 0.1, func = function() currentCard:flip(); play_sound('tarot2', 1, 0.6); big_juice(card); currentCard:juice_up(0.3, 0.3); return true end })
|
|
|
|
delay(0.1)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
})
|
|
|
|
--Memoriam Photo
|
|
create_joker({
|
|
name = 'Memoriam Photo', id = 72,
|
|
rarity = 'Uncommon', cost = 6,
|
|
|
|
vars = {{chips = 0}},
|
|
custom_vars = function(self, info_queue, card)
|
|
return {vars = {card.ability.extra.chips}}
|
|
end,
|
|
|
|
blueprint = true, eternal = true, perishable = false,
|
|
|
|
calculate = function(self, card, context)
|
|
--Upgrades
|
|
if context.remove_playing_cards and not context.blueprint then
|
|
local added_total = 0
|
|
for i=1, #context.removed do
|
|
if not context.removed[i].config.center.no_rank then
|
|
added_total = added_total + context.removed[i].base.nominal
|
|
end
|
|
end
|
|
|
|
if added_total>0 then
|
|
card.ability.extra.chips = card.ability.extra.chips + (2 * added_total)
|
|
event({
|
|
func = function()
|
|
big_juice(card)
|
|
forced_message("Upgraded!", card, G.C.CHIPS, true)
|
|
--card_eval_status_text(card,'extra',nil, nil, nil,{message = "Upgraded", colour = G.C.MULT, instant = true})
|
|
return true end
|
|
})
|
|
end
|
|
end
|
|
|
|
--Main context
|
|
if context.joker_main then
|
|
if card.ability.extra.chips > 0 then
|
|
return {
|
|
chip_mod = card.ability.extra.chips,
|
|
message = localize { type = 'variable', key = 'a_chips', vars = { card.ability.extra.chips } }
|
|
}
|
|
end
|
|
end
|
|
end,
|
|
})
|
|
|
|
--Schrodinger Cat
|
|
create_joker({
|
|
name = 'Schrodinger Cat', id = 73,
|
|
rarity = 'Uncommon', cost = 8,
|
|
|
|
vars = {{odds = 3}},
|
|
custom_vars = function(self, info_queue, card)
|
|
return {vars = {G.GAME and G.GAME.probabilities.normal or 1, card.ability.extra.odds}}
|
|
end,
|
|
|
|
blueprint = true, eternal = true, perishable = true,
|
|
|
|
calculate = function(self, card, context)
|
|
--Upgrades
|
|
if context.remove_playing_cards then
|
|
for i=1, #context.removed do
|
|
local isActivated = pseudorandom('schrodingercat'..G.SEED) < G.GAME.probabilities.normal / card.ability.extra.odds
|
|
|
|
if isActivated then
|
|
event({func = function()
|
|
--Copy Card
|
|
G.playing_card = (G.playing_card and G.playing_card + 1) or 1
|
|
local _card = copy_card(context.removed[i], nil, nil, G.playing_card)
|
|
|
|
--Special interaction: if it is a vintage card, resets the odds
|
|
if _card.config.center.key == 'm_unstb_vintage' then
|
|
_card.ability.extra.current_odd = 0
|
|
end
|
|
|
|
_card:start_materialize({G.C.SECONDARY_SET.Enhanced})
|
|
_card:add_to_deck()
|
|
G.deck:emplace(_card)
|
|
table.insert(G.playing_cards, _card)
|
|
return true end
|
|
})
|
|
|
|
event({func = function()
|
|
G.deck.config.card_limit = G.deck.config.card_limit + 1
|
|
return true end
|
|
})
|
|
|
|
playing_card_joker_effects({true})
|
|
|
|
forced_message(localize('k_copied_ex'), context.blueprint_card or card, G.C.ORANGE, 0.25)
|
|
end
|
|
end
|
|
end
|
|
end,
|
|
})
|
|
|
|
--Cashback Card
|
|
create_joker({
|
|
name = 'Cashback Card', id = 51,
|
|
rarity = 'Rare', cost = 9,
|
|
|
|
vars = {{payout = 0}},
|
|
custom_vars = function(self, info_queue, card)
|
|
return {vars = {card.ability.extra.payout}}
|
|
end,
|
|
|
|
blueprint = false, eternal = true, perishable = true,
|
|
|
|
calculate = function(self, card, context)
|
|
if context.using_consumeable and not context.blueprint then
|
|
card.ability.extra.payout = card.ability.extra.payout + 1
|
|
event({
|
|
func = function()
|
|
big_juice(card)
|
|
forced_message("Upgrade!", card, G.C.GOLD, true)
|
|
--card_eval_status_text(card,'extra',nil, nil, nil,{message = "Upgraded", colour = G.C.MULT, instant = true})
|
|
return true end})
|
|
end
|
|
end,
|
|
calc_dollar_bonus = function(self, card)
|
|
if G.GAME.blind.boss then
|
|
local bonus = card.ability.extra.payout
|
|
|
|
card.ability.extra.payout = 0
|
|
|
|
if bonus > 0 then return bonus end
|
|
end
|
|
end
|
|
})
|
|
|
|
--Raffle
|
|
create_joker({
|
|
name = 'Raffle', id = 50,
|
|
rarity = 'Common', cost = 8,
|
|
|
|
vars = {{odds = 20}, {prize = 20}, {current_odds = 0}},
|
|
custom_vars = function(self, info_queue, card)
|
|
return {vars = {(G.GAME and G.GAME.probabilities.normal or 1)*card.ability.extra.current_odds, card.ability.extra.odds, card.ability.extra.prize, G.GAME and G.GAME.probabilities.normal or 1, }}
|
|
end,
|
|
|
|
blueprint = false, eternal = true, perishable = true,
|
|
|
|
calculate = function(self, card, context)
|
|
--All upgraded part
|
|
if context.buying_card and not context.blueprint then
|
|
card.ability.extra.current_odds = card.ability.extra.current_odds + 1
|
|
forced_message('Upgrade!', card, G.C.ORANGE, true)
|
|
end
|
|
|
|
if context.reroll_shop and not context.blueprint then
|
|
card.ability.extra.current_odds = card.ability.extra.current_odds + 1
|
|
forced_message('Upgrade!', card, G.C.ORANGE, true)
|
|
end
|
|
|
|
if context.open_booster and not context.blueprint then
|
|
card.ability.extra.current_odds = card.ability.extra.current_odds + 1
|
|
forced_message('Upgrade!', card, G.C.ORANGE, true)
|
|
end
|
|
|
|
--Payout
|
|
if context.ending_shop and not context.blueprint then
|
|
if pseudorandom('raffle'..G.SEED) < G.GAME.probabilities.normal * card.ability.extra.current_odds / card.ability.extra.odds then
|
|
event({trigger = 'after', func = function()
|
|
ease_dollars(card.ability.extra.prize, true)
|
|
big_juice(context.blueprint_card or card)
|
|
return true end })
|
|
forced_message('$'..card.ability.extra.prize, card, G.C.GOLD, true)
|
|
else
|
|
play_nope_sound()
|
|
forced_message('Nope', card, G.C.RED, true)
|
|
end
|
|
|
|
card.ability.extra.current_odds = 0
|
|
end
|
|
|
|
--Make sure the chance resets again when round ends, cause booster opening from tags currently still trigger it and idk how to prevent that
|
|
if context.end_of_round and not context.other_card and not context.repetition and not context.game_over and not context.blueprint then
|
|
card.ability.extra.current_odds = 0
|
|
end
|
|
end
|
|
})
|
|
|
|
--ease_dollars hook, for IC Card
|
|
local ref_ease_dollars = ease_dollars
|
|
function ease_dollars(mod, instant)
|
|
|
|
if to_big(mod) < to_big(0) then
|
|
|
|
local iccard_list = SMODS.find_card('j_unstb_ic_card')
|
|
|
|
if next(iccard_list) then
|
|
for i=1, #iccard_list do
|
|
if iccard_list[i].ability.extra.balance > 0 then
|
|
|
|
--Note: Spend amount is negative
|
|
local spendamount = math.max(mod, -iccard_list[i].ability.extra.balance)
|
|
|
|
mod = mod - spendamount
|
|
iccard_list[i].ability.extra.balance = iccard_list[i].ability.extra.balance + spendamount
|
|
G.GAME.virtual_dollars = G.GAME.virtual_dollars + spendamount
|
|
|
|
if not instant then
|
|
forced_message("-$"..math.abs(spendamount), iccard_list[i], G.C.red, 0.5)
|
|
end
|
|
|
|
if mod >= 0 then
|
|
return
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
ref_ease_dollars(mod, instant)
|
|
end
|
|
|
|
--IC Card
|
|
create_joker({
|
|
name = 'IC Card', id = 49,
|
|
rarity = 'Uncommon', cost = 6,
|
|
|
|
vars = {{money_rate = 3},{balance = 0}, {round_max = 9}},
|
|
custom_vars = function(self, info_queue, card)
|
|
return {vars = {card.ability.extra.money_rate, card.ability.extra.round_max, card.ability.extra.balance, card.ability.extra.round_left}}
|
|
end,
|
|
|
|
blueprint = false, eternal = false, perishable = false,
|
|
|
|
set_ability = function(self, card, initial, delay_sprites)
|
|
card.ability.extra.round_left = card.ability.extra.round_max
|
|
|
|
if G.STATE ~= G.STATES.SHOP then --Joker obtained not during the shop
|
|
card.ability.extra.start_counting = true
|
|
end
|
|
end,
|
|
|
|
add_to_deck = function(self, card, from_debuff)
|
|
G.GAME.virtual_dollars = (G.GAME.virtual_dollars or 0) + card.ability.extra.balance
|
|
end,
|
|
|
|
remove_from_deck = function(self, card, from_debuff)
|
|
G.GAME.virtual_dollars = (G.GAME.virtual_dollars or 0) - card.ability.extra.balance
|
|
end,
|
|
|
|
calculate = function(self, card, context)
|
|
|
|
--When entering the round, start counting the round remaining
|
|
--(If the Joker is bought in the shop, the first shop leave will not be counted down)
|
|
if context.first_hand_drawn then
|
|
card.ability.extra.start_counting = true
|
|
end
|
|
|
|
if context.before and context.scoring_hand and not context.blueprint then
|
|
card.ability.extra.balance = card.ability.extra.balance + card.ability.extra.money_rate
|
|
|
|
--Update the game's global virtual money at the same time
|
|
G.GAME.virtual_dollars = (G.GAME.virtual_dollars or 0) + card.ability.extra.money_rate
|
|
|
|
forced_message("$"..card.ability.extra.money_rate, card, G.C.GOLD, true)
|
|
end
|
|
|
|
if context.ending_shop and not context.blueprint then
|
|
|
|
if card.ability.extra.start_counting then
|
|
card.ability.extra.round_left = card.ability.extra.round_left - 1
|
|
|
|
if card.ability.extra.round_left <= 0 then
|
|
event({func = function()
|
|
|
|
play_sound('tarot1')
|
|
card.T.r = -0.2
|
|
card:juice_up(0.3, 0.4)
|
|
card.states.drag.is = true
|
|
card.children.center.pinch.x = true
|
|
|
|
--Destroy Card
|
|
event({trigger = 'after', delay = 0.3, func = function()
|
|
|
|
G.jokers:remove_card(card)
|
|
card:remove()
|
|
card = nil
|
|
return true end })
|
|
|
|
return true end })
|
|
card_eval_status_text(card,'extra',nil, nil, nil,{message = 'Expired', colour = G.C.ORANGE, instant = true})
|
|
else
|
|
forced_message(card.ability.extra.round_left..' Round', card, G.C.ORANGE, true)
|
|
end
|
|
|
|
end
|
|
|
|
card.ability.extra.start_counting = false
|
|
end
|
|
end
|
|
})
|
|
|
|
|
|
|
|
--local rank_2048 = { unstb_0 = true, unstb_1 = true, ['2'] = true, ['4'] = true, ['8'] = true}
|
|
|
|
--2048
|
|
create_joker({
|
|
name = 'j2048', id = 3,
|
|
rarity = 'Uncommon', cost = 7,
|
|
|
|
gameplay_tag = {'j_alter'},
|
|
|
|
vars = {{card_to_destroy = {}}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
|
|
--[[local key = self.key
|
|
if getPoolRankFlagEnable('unstb_0') or getPoolRankFlagEnable('unstb_1') then
|
|
key = self.key..'_ex'
|
|
end]]
|
|
|
|
return { vars = {} }
|
|
end,
|
|
|
|
blueprint = false, eternal = true, perishable = true,
|
|
|
|
calculate = function(self, card, context)
|
|
if context.before and context.scoring_hand and not context.blueprint then
|
|
local card_list = {}
|
|
local card_to_destroy = {}
|
|
|
|
for i = 1, #context.scoring_hand do
|
|
local c = context.scoring_hand[i]
|
|
local key = c.base.value
|
|
|
|
--print(rank_2048[c.base.value])
|
|
|
|
|
|
if card_list[key] then
|
|
--print('found the card list: '..c.base.value)
|
|
|
|
local prev_card = card_list[key]
|
|
card_to_destroy[#card_to_destroy+1] = prev_card
|
|
|
|
--Transfer chips
|
|
local bonusChip = prev_card.ability.perma_bonus or 0
|
|
local baseChip = SMODS.Ranks[prev_card.base.value].nominal
|
|
|
|
--Delay the chip adding, so it does not get evaluated
|
|
event({delay = 0.1, func = function()
|
|
c.ability.perma_bonus = (c.ability.perma_bonus or 0) + baseChip + bonusChip
|
|
return true end
|
|
})
|
|
|
|
--Erase the slot, if there's the next one then it counts as a new pair
|
|
card_list[key] = nil
|
|
else
|
|
--print('adding to card list: '..c.base.value)
|
|
card_list[key] = c
|
|
end
|
|
|
|
end
|
|
|
|
--print('done')
|
|
--print(inspectDepth(card_to_destroy, nil, 1))
|
|
|
|
card.ability.extra.card_to_destroy = card_to_destroy
|
|
end
|
|
|
|
if context.destroying_card and not context.blueprint then
|
|
--print('check card to destroy main')
|
|
for i = 1, #card.ability.extra.card_to_destroy do
|
|
--print('check card to destroy')
|
|
--print(context.destroying_card == card.ability.extra.card_to_destroy[i])
|
|
if context.destroying_card == card.ability.extra.card_to_destroy[i] then
|
|
return true
|
|
end
|
|
end
|
|
end
|
|
end
|
|
})
|
|
|
|
--Inductor
|
|
create_joker({
|
|
name = 'Inductor', id = 1,
|
|
rarity = 'Rare', cost = 8,
|
|
|
|
gameplay_tag = {'j_powerful'},
|
|
|
|
vars = {{odds_en = 2}, {odds_ed = 4}, {odds_s = 8}},
|
|
|
|
custom_vars = function(self, info_queue, card)
|
|
local vars
|
|
if G.GAME and G.GAME.probabilities.normal then
|
|
vars = {G.GAME.probabilities.normal, card.ability.extra.odds_en, card.ability.extra.odds_ed, card.ability.extra.odds_s}
|
|
else
|
|
vars = {1, card.ability.extra.odds_en, card.ability.extra.odds_ed, card.ability.extra.odds_s}
|
|
end
|
|
return {vars = vars}
|
|
end,
|
|
|
|
blueprint = false, eternal = true, perishable = true,
|
|
|
|
calculate = function(self, card, context)
|
|
|
|
if context.after and context.scoring_hand and #context.scoring_hand > 1 and not context.blueprint then
|
|
local sourceCard = {}
|
|
|
|
for i = 1, #context.scoring_hand do
|
|
if not (context.scoring_hand[i].config.center == G.P_CENTERS.m_stone or context.scoring_hand[i].config.center.replace_base_card) then --Check if it is not a Stone card or have any weird enhancement
|
|
if sourceCard[context.scoring_hand[i].base.value..context.scoring_hand[i].base.suit] then --targetCard exists
|
|
|
|
local currentCard = context.scoring_hand[i]
|
|
local targetCard = sourceCard[context.scoring_hand[i].base.value..context.scoring_hand[i].base.suit]
|
|
|
|
|
|
local isCopyEnhancement = pseudorandom('prop_enh'..G.SEED) < G.GAME.probabilities.normal / card.ability.extra.odds_en
|
|
local isCopyEdition = pseudorandom('prop_ed'..G.SEED) < G.GAME.probabilities.normal / card.ability.extra.odds_ed
|
|
local isCopySeal = pseudorandom('prop_s'..G.SEED) < G.GAME.probabilities.normal / card.ability.extra.odds_s
|
|
|
|
--Extra check, if the current card and target card have the same status, don't play animation
|
|
|
|
if currentCard.config.center == targetCard.config.center then
|
|
isCopyEnhancement = false
|
|
|
|
end
|
|
if (currentCard.edition or {}).key == (targetCard.edition or {}).key then
|
|
isCopyEdition = false
|
|
|
|
end
|
|
if currentCard.seal == targetCard.seal then
|
|
isCopySeal = false
|
|
end
|
|
|
|
local isPlayingAnimation = isCopyEnhancement or isCopyEdition or isCopySeal
|
|
|
|
if isPlayingAnimation then
|
|
--Flipping Animation
|
|
event({trigger = 'after', delay = 0.1, func = function() currentCard:flip(); play_sound('card1', 1); currentCard:juice_up(0.3, 0.3); return true end })
|
|
|
|
--Changing Card Property
|
|
event({trigger = 'after', delay = 0.05, func = function()
|
|
|
|
--Copy enhancement
|
|
if isCopyEnhancement then
|
|
currentCard:set_ability(targetCard.config.center)
|
|
end
|
|
|
|
--Copy edition
|
|
if isCopyEdition then
|
|
currentCard:set_edition(targetCard.edition, true, true)
|
|
end
|
|
|
|
--Copy seal
|
|
if isCopySeal then
|
|
currentCard:set_seal(targetCard.seal, true, true)
|
|
end
|
|
|
|
return true end })
|
|
|
|
--Unflipping Animation
|
|
event({trigger = 'after', delay = 0.1, func = function() currentCard:flip(); play_sound('tarot2', 1, 0.6); big_juice(card); currentCard:juice_up(0.3, 0.3); return true end })
|
|
forced_message("Copied!", currentCard, G.C.RED, true)
|
|
end
|
|
else --set the target card to the following
|
|
sourceCard[context.scoring_hand[i].base.value..context.scoring_hand[i].base.suit] = context.scoring_hand[i]
|
|
end
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
end
|
|
})
|
|
|
|
--Decks
|
|
|
|
if unstb_config.gameplay.c_aux then
|
|
|
|
SMODS.Back{ -- Utility Deck
|
|
key = "utility",
|
|
pos = {x = 0, y = 0},
|
|
|
|
unlocked = true,
|
|
|
|
config = {vouchers = {'v_unstb_aux1'}, aux_amount = 1, aux_chance = 2},
|
|
loc_vars = function(self)
|
|
return {vars = {}}
|
|
end,
|
|
|
|
apply = function(self)
|
|
G.GAME.auxiliary_rate = (G.GAME.auxiliary_rate or 0) + self.config.aux_chance
|
|
event({
|
|
func = function()
|
|
for i = 1, self.config.aux_amount do
|
|
local card = create_card('Auxiliary', G.consumeables, nil, nil, nil, nil, 'c_unstb_aux_random', 'utildeck')
|
|
card:add_to_deck()
|
|
G.consumeables:emplace(card)
|
|
end
|
|
return true
|
|
end
|
|
})
|
|
end,
|
|
|
|
atlas = 'unstb_deck'
|
|
}
|
|
|
|
end
|
|
|
|
if check_enable_taglist({'rank_binary', 'rank_decimal'}) then
|
|
|
|
unstb.lowkey_rankList = {'2', '3', '4', '5', 'unstb_0', 'unstb_0.5', 'unstb_1', 'unstb_r2', 'unstb_e', 'unstb_Pi'}
|
|
|
|
unstb.lowkey_blacklisted = {}
|
|
unstb.lowkey_ranklist = {}
|
|
|
|
--Populate the Lowkey Deck rank blacklist, called at the Splash Screen to support modded ranks as well
|
|
function init_lowkey_blacklist()
|
|
for k, v in pairs(SMODS.Ranks) do
|
|
if not table_has_value(unstb.lowkey_rankList, k) then
|
|
unstb.lowkey_blacklisted[k] = true
|
|
end
|
|
end
|
|
end
|
|
|
|
SMODS.Back{ -- Lowkey Deck
|
|
key = "lowkey",
|
|
pos = {x = 1, y = 0},
|
|
|
|
unlocked = true,
|
|
|
|
config = {},
|
|
loc_vars = function(self)
|
|
return {vars = {}}
|
|
end,
|
|
|
|
apply = function(self)
|
|
|
|
--Enable all the pool flags
|
|
setPoolRankFlagEnable('unstb_0', true);
|
|
setPoolRankFlagEnable('unstb_0.5', true);
|
|
setPoolRankFlagEnable('unstb_1', true);
|
|
setPoolRankFlagEnable('unstb_r2', true);
|
|
setPoolRankFlagEnable('unstb_e', true);
|
|
setPoolRankFlagEnable('unstb_Pi', true);
|
|
|
|
--Notice: used card_key version and not standard key
|
|
local added_rank = {'unstb_0', 'unstb_0.5', 'unstb_1', 'unstb_R', 'unstb_E', 'unstb_P'}
|
|
|
|
local all_suit = {}
|
|
|
|
for k, v in pairs(SMODS.Suits) do
|
|
--If has in_pool, check in_pool
|
|
if type(v) == 'table' and type(v.in_pool) == 'function' and v.in_pool then
|
|
if v:in_pool({initial_deck = true}) then
|
|
all_suit[#all_suit+1] = v.card_key
|
|
end
|
|
else --Otherwise, added by default
|
|
all_suit[#all_suit+1] = v.card_key
|
|
end
|
|
|
|
end
|
|
|
|
--print(inspect(all_suit))
|
|
|
|
local extra_cards = {}
|
|
|
|
for i=1, #all_suit do
|
|
for j=1, #added_rank do
|
|
extra_cards[#extra_cards+1] = {s = all_suit[i], r = added_rank[j]}
|
|
end
|
|
end
|
|
|
|
G.GAME.starting_params.extra_cards = extra_cards
|
|
|
|
G.GAME.starting_params.blacklisted_ranks = unstb.lowkey_blacklisted
|
|
|
|
end,
|
|
|
|
atlas = 'unstb_deck'
|
|
}
|
|
end
|
|
|
|
|
|
--Compatibility / Tweaks / Rework Stuff
|
|
|
|
--CardSleeves Support
|
|
if CardSleeves then
|
|
|
|
--Sleeves
|
|
SMODS.Atlas {
|
|
-- Key for code to find it with
|
|
key = "sleeve",
|
|
path = "sleeve.png",
|
|
px = 73,
|
|
py = 95
|
|
}
|
|
|
|
if unstb_config.gameplay.c_aux then
|
|
|
|
--Utility Sleeve
|
|
CardSleeves.Sleeve({
|
|
name = "Utility Sleeve",
|
|
key="utility",
|
|
atlas="sleeve",
|
|
pos = { x = 0, y = 0 },
|
|
unlocked = true,
|
|
loc_vars = function(self)
|
|
local key
|
|
|
|
if self.get_current_deck_key() ~= "b_unstb_utility" then
|
|
key = self.key
|
|
self.config = { voucher = 'v_unstb_aux1', aux_chance = 1}
|
|
else
|
|
key = self.key .. "_alt"
|
|
self.config = { voucher = 'v_unstb_aux2', aux_chance = 1}
|
|
end
|
|
return { key = key }
|
|
end,
|
|
apply = function(self)
|
|
--Call main apply function from CardSleeve first to apply vouchers
|
|
CardSleeves.Sleeve.apply(self)
|
|
|
|
G.GAME.auxiliary_rate = (G.GAME.auxiliary_rate or 0) + self.config.aux_chance
|
|
|
|
event({
|
|
func = function()
|
|
|
|
if self.get_current_deck_key() ~= "b_unstb_utility" then
|
|
local card = create_card('Auxiliary', G.consumeables, nil, nil, nil, nil, 'c_unstb_aux_random', 'utildeck')
|
|
card:add_to_deck()
|
|
G.consumeables:emplace(card)
|
|
else
|
|
local card = create_card('Joker', G.jokers, nil, nil, nil, nil, 'j_unstb_free_trial', nil)
|
|
card:set_edition({negative = true}, true)
|
|
card:add_to_deck()
|
|
G.jokers:emplace(card)
|
|
end
|
|
|
|
return true
|
|
end
|
|
})
|
|
end
|
|
})
|
|
|
|
end
|
|
|
|
if check_enable_taglist({'rank_binary', 'rank_decimal'}) then
|
|
|
|
--Lowkey Sleeve
|
|
CardSleeves.Sleeve({
|
|
name = "Lowkey Sleeve",
|
|
key="lowkey",
|
|
atlas="sleeve",
|
|
pos = { x = 1, y = 0 },
|
|
unlocked = true,
|
|
loc_vars = function(self)
|
|
local key
|
|
|
|
if self.get_current_deck_key() ~= "b_unstb_lowkey" then
|
|
key = self.key
|
|
self.config = { remove_ranks = true }
|
|
else
|
|
key = self.key .. "_alt"
|
|
self.config = { prevent_ranks = true }
|
|
end
|
|
return { key = key }
|
|
end,
|
|
apply = function(self)
|
|
--Call main apply function from CardSleeve first to apply vouchers
|
|
CardSleeves.Sleeve.apply(self)
|
|
|
|
--Regular sleeve effects
|
|
|
|
if self.config.remove_ranks then
|
|
--Enable all the pool flags
|
|
setPoolRankFlagEnable('unstb_0', true);
|
|
setPoolRankFlagEnable('unstb_0.5', true);
|
|
setPoolRankFlagEnable('unstb_1', true);
|
|
setPoolRankFlagEnable('unstb_r2', true);
|
|
setPoolRankFlagEnable('unstb_e', true);
|
|
setPoolRankFlagEnable('unstb_Pi', true);
|
|
|
|
--Notice: used card_key version and not standard key
|
|
local added_rank = {'unstb_0', 'unstb_0.5', 'unstb_1', 'unstb_R', 'unstb_E', 'unstb_P'}
|
|
|
|
local all_suit = {}
|
|
|
|
for k, v in pairs(SMODS.Suits) do
|
|
--If has in_pool, check in_pool
|
|
if type(v) == 'table' and type(v.in_pool) == 'function' and v.in_pool then
|
|
if v:in_pool({initial_deck = true}) then
|
|
all_suit[#all_suit+1] = v.card_key
|
|
end
|
|
else --Otherwise, added by default
|
|
all_suit[#all_suit+1] = v.card_key
|
|
end
|
|
|
|
end
|
|
|
|
--print(inspect(all_suit))
|
|
|
|
local extra_cards = {}
|
|
|
|
for i=1, #all_suit do
|
|
for j=1, #added_rank do
|
|
extra_cards[#extra_cards+1] = {s = all_suit[i], r = added_rank[j]}
|
|
end
|
|
end
|
|
|
|
G.GAME.starting_params.extra_cards = extra_cards
|
|
|
|
G.GAME.starting_params.blacklisted_ranks = unstb.lowkey_blacklisted
|
|
end
|
|
|
|
--Set the game flags to prevent high rank, this affact premium booster
|
|
if self.config.prevent_ranks then
|
|
G.GAME.prevent_high_rank = true
|
|
end
|
|
|
|
--Code based on Abandoned Sleeve from CardSleeve itself, for special effect
|
|
if self.config.prevent_ranks and self.allowed_card_centers == nil then
|
|
self.allowed_card_centers = {}
|
|
self.skip_trigger_effect = true
|
|
|
|
for _, card_center in pairs(G.P_CARDS) do
|
|
local card_instance = Card(0, 0, 0, 0, card_center, G.P_CENTERS.c_base)
|
|
|
|
if not unstb.lowkey_blacklisted[card_instance.base.value] then
|
|
self.allowed_card_centers[#self.allowed_card_centers+1] = card_center
|
|
end
|
|
card_instance:remove()
|
|
end
|
|
|
|
-- Make it loops around to 0 immediately after using strength on 5
|
|
self.get_rank_after_5 = function() return "unstb_0" end
|
|
self.skip_trigger_effect = false
|
|
end
|
|
end,
|
|
trigger_effect = function(self, args)
|
|
|
|
--Code based on Abandoned Sleeve from CardSleeve itself
|
|
if not self.config.prevent_ranks then
|
|
return
|
|
end
|
|
if self.skip_trigger_effect then
|
|
return
|
|
end
|
|
if self.allowed_card_centers == nil then
|
|
self:apply()
|
|
end
|
|
|
|
-- handle Strength, Ouija, Grim, Familiar
|
|
local card = args.context and args.context.card
|
|
local is_playing_card = card and (card.ability.set == "Default" or card.ability.set == "Enhanced") and card.config.card_key
|
|
if args.context and args.context.before_use_consumable and card then
|
|
if card.ability.name == 'Strength' then
|
|
self.in_strength = true
|
|
elseif card.ability.name == "Ouija" then
|
|
self.in_ouija = true
|
|
elseif card.ability.name == "Grim" then
|
|
self.in_grim = true
|
|
elseif card.ability.name == "Familiar" then
|
|
self.in_familiar = true
|
|
end
|
|
|
|
elseif args.context and args.context.after_use_consumable then
|
|
self.in_strength = nil
|
|
self.in_ouija = nil
|
|
self.ouija_rank = nil
|
|
|
|
self.in_grim = nil
|
|
self.in_familiar = nil
|
|
elseif G.GAME and G.GAME.blind and args.context and (args.context.create_card or args.context.modify_playing_card) and card and is_playing_card then
|
|
if unstb.lowkey_blacklisted[card.base.value] then
|
|
local initial = G.GAME.blind == nil or args.context.create_card
|
|
|
|
if self.in_strength then
|
|
local base_key = SMODS.Suits[card.base.suit].card_key .. "_" .. self.get_rank_after_5()
|
|
card:set_base(G.P_CARDS[base_key], initial)
|
|
elseif self.in_grim then --Grim will always create 1 (because Ace)
|
|
local base_key = SMODS.Suits[card.base.suit].card_key .. "_unstb_1"
|
|
card:set_base(G.P_CARDS[base_key], initial)
|
|
elseif self.in_ouija then
|
|
if self.ouija_rank == nil then
|
|
local random_base = pseudorandom_element(self.allowed_card_centers, pseudoseed("slv"))
|
|
local card_instance = Card(0, 0, 0, 0, random_base, G.P_CENTERS.c_base)
|
|
self.ouija_rank = SMODS.Ranks[card_instance.base.value]
|
|
card_instance:remove()
|
|
end
|
|
local base_key = SMODS.Suits[card.base.suit].card_key .. "_" .. self.ouija_rank.card_key
|
|
card:set_base(G.P_CARDS[base_key], initial)
|
|
else
|
|
local new_rank = pseudorandom_element(unstb.lowkey_rankList, pseudoseed("slv"))
|
|
--Use smods change_base so we can still keep the suit
|
|
SMODS.change_base(card, nil, new_rank)
|
|
|
|
if self.in_familiar and unstb_config.gameplay.seal_suit then --For Familiar, adds face seal to the created card (if the mechanic is enabled)
|
|
card:set_seal('unstb_face', true, true)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end,
|
|
})
|
|
|
|
end
|
|
|
|
end
|
|
|
|
--Reworked Vanilla Joker to support new features
|
|
if unstb_config.joker.vanilla then
|
|
|
|
filesystem.load(unstb.path..'/override/vanilla_joker.lua')()
|
|
|
|
end
|
|
|
|
--Suits, supports for Suit Seals, a lot of suit-based Joker, and modded suits support for Smeared
|
|
filesystem.load(unstb.path..'/override/suits.lua')()
|
|
|
|
--JokerDisplay (Partial) Support
|
|
if JokerDisplay then
|
|
SMODS.load_file("/override/jokerdisplay.lua")()
|
|
end
|
|
|
|
--Manually load localizations and populate necessary info needed for the mod
|
|
|
|
--Global table entry to handle trigger for name-related stuff
|
|
unstb_global.name_joker = {}
|
|
unstb_global.name_card = {}
|
|
unstb_global.name_suit = {}
|
|
|
|
function unstb_process_english_loc()
|
|
local function populateList(temp_loc)
|
|
if not temp_loc or not temp_loc.descriptions then return end
|
|
|
|
local jokers = temp_loc.descriptions.Joker or {}
|
|
for k,v in pairs(jokers) do
|
|
if not unstb_global.name_joker[k] and not unstb_global.name_card[k] then
|
|
if v.name and string.match(string.lower(v.name), "joker") then
|
|
unstb_global.name_joker[k] = v.name
|
|
end
|
|
|
|
if v.name and string.match(string.lower(v.name), "card") then
|
|
unstb_global.name_card[k] = v.name
|
|
end
|
|
end
|
|
end
|
|
|
|
--Process suit loc if exists
|
|
local suit = (temp_loc.misc and temp_loc.misc.suits_singular) or {}
|
|
|
|
for k,v in pairs(suit) do
|
|
if not unstb_global.name_suit[k] and v then
|
|
local suit_name = string.lower(v)
|
|
|
|
local vowel = suit_name:gsub("[^aeiou]","")
|
|
local consonant = suit_name:gsub("[^bcdfghjklmnpqrstvwxyz]","") --To be safe, list alphabet only, no symbol, space, or numbers
|
|
|
|
unstb_global.name_suit[k] = {
|
|
name = v,
|
|
count_vowel = string.len(vowel),
|
|
count_consonant = string.len(consonant)
|
|
}
|
|
end
|
|
end
|
|
|
|
end
|
|
|
|
local function loc_fallback()
|
|
--print("Called loc fallback")
|
|
return {}
|
|
end
|
|
|
|
print("Start initializing localization-independent info")
|
|
--Basegame Jokers
|
|
local temp_loc = assert(loadstring(love.filesystem.read('localization/en-us.lua')))()
|
|
populateList(temp_loc)
|
|
|
|
--Modded Jokers
|
|
for k, _ in pairs(SMODS.Mods) do
|
|
if SMODS.Mods[k].can_load and SMODS.Mods[k].path then
|
|
temp_loc = (SMODS.load_file('/localization/en-us.lua', k) or loc_fallback)()
|
|
if temp_loc then
|
|
populateList(temp_loc)
|
|
end
|
|
end
|
|
end
|
|
|
|
--Fallback, handle the rest of the mod without proper localization (eg. uses loc_txt)
|
|
--these mods tend to not have proper localization so it should be fine to look at the game's raw table
|
|
populateList(G.localization)
|
|
|
|
print("Finished initializing localization-independent info")
|
|
|
|
end
|
|
|
|
--Hook for the game's splash screen, to initialize any data that is sensitive to the mod's order (mainly rank stuff)
|
|
|
|
local ref_gamesplashscreen = Game.splash_screen
|
|
|
|
function Game:splash_screen()
|
|
ref_gamesplashscreen(self)
|
|
|
|
--set_consumeable_usage hook to keep track of UnStable's own consumable count
|
|
--Certain mod like Aurinko made this hook doesn't work fsr
|
|
local set_consumeable_usage_ref = set_consumeable_usage
|
|
|
|
function set_consumeable_usage(card)
|
|
if card.config.center_key and card.ability.consumeable then
|
|
if card.config.center.set == 'Auxiliary' then
|
|
--Initialize it if not, basically what basegame does but have to put here bc it runs before basegame's
|
|
G.GAME.consumeable_usage_total = G.GAME.consumeable_usage_total or {tarot = 0, planet = 0, spectral = 0, tarot_planet = 0, all = 0}
|
|
|
|
G.GAME.consumeable_usage_total.auxiliary = (G.GAME.consumeable_usage_total.auxiliary or 0) + 1
|
|
end
|
|
end
|
|
|
|
return set_consumeable_usage_ref(card)
|
|
end
|
|
|
|
init_prev_rank_data()
|
|
|
|
if init_lowkey_blacklist then
|
|
init_lowkey_blacklist()
|
|
end
|
|
|
|
unstb_process_english_loc()
|
|
end |