fixed cartomancer and bumped cryptid version

This commit is contained in:
Vomitblood 2025-11-28 19:23:32 +08:00
parent e449b45387
commit 2723c65a63
104 changed files with 3807 additions and 1642 deletions

57
Cartomancer/README.md Normal file
View file

@ -0,0 +1,57 @@
## Requirements
- [Lovely](https://github.com/ethangreen-dev/lovely-injector) - a Balatro injector.
## Installation
1. Install [Lovely](https://github.com/ethangreen-dev/lovely-injector?tab=readme-ov-file#manual-installation).
2. Download the [latest release](https://github.com/stupxd/Cartomancer/releases/) of this mod.
3. Unzip the folder, and move it into the `%appdata%/Balatro/Mods` folder.
4. Restart the game to load the mod.
## TL;DR
This mod is mainly aimed to improve your endless/heavily modded runs experience, providing quality of life & optimization features.
## Features
### 1. Limit amount of cards visible in your deck pile
![cards-pile-difference](git-assets/deck-pile.jpg)
### 2. Improved deck view
- Hide drawn cards
- Stack identical playing cards
![stackable-cards-difference](git-assets/stackable-cards.jpg)
### 4. Custom scoring flames intensity and SFX volume.
### 5. Extended Blinds info in Run Info
- Boss Blinds History
- Scoring requirements 8 ante ahead
![zoom-jokers-difference](git-assets/blinds-info.jpg)
### 6. Improved jokers management
- Option to hide all jokers (improves performance at 100+ jokers).
- Zoom into the jokers area for easier jokers management and navigation.
![zoom-jokers-difference](git-assets/zoom-jokers.jpg)
...and more!
Settings for this mod can be found under `Mods` tab, if you use Steamodded 1.0.0 - find `Cartomancer`, and open `Config` tab.
If you play vanilla, go to `Settings` and open ![cartomancer](assets/1x/modicon.png) tab.
## Credits
[Jen Walter](https://github.com/jenwalter666/) for the code for UI box on stacked cards.
[Mysthaps](https://github.com/Mysthaps/) for most of the initial mod config code.

View file

@ -5,16 +5,20 @@ Cartomancer.path = assert(
"Failed to find mod folder. Make sure that `Cartomancer` folder has `cartomancer.lua` file!"
)
Cartomancer.load_mod_file('internal/config.lua', 'internal.config')
Cartomancer.load_mod_file('internal/atlas.lua', 'internal.atlas')
Cartomancer.load_mod_file('internal/ui.lua', 'internal.ui')
Cartomancer.load_mod_file('internal/keybinds.lua', 'internal.keybinds')
Cartomancer.load_mod_file('internal/config.lua', 'cartomancer.config')
Cartomancer.load_mod_file('internal/atlas.lua', 'cartomancer.atlas')
Cartomancer.load_mod_file('internal/ui.lua', 'cartomancer.ui')
Cartomancer.load_mod_file('internal/keybinds.lua', 'cartomancer.keybinds')
Cartomancer.load_mod_file('core/view-deck.lua', 'core.view-deck')
Cartomancer.load_mod_file('core/flames.lua', 'core.flames')
Cartomancer.load_mod_file('core/optimizations.lua', 'core.optimizations')
Cartomancer.load_mod_file('core/jokers.lua', 'core.jokers')
Cartomancer.load_mod_file('core/hand.lua', 'core.hand')
Cartomancer.load_mod_file('core/view-deck.lua', 'cartomancer.view-deck')
Cartomancer.load_mod_file('core/flames.lua', 'cartomancer.flames')
Cartomancer.load_mod_file('core/optimizations.lua', 'cartomancer.optimizations')
Cartomancer.load_mod_file('core/jokers.lua', 'cartomancer.jokers')
Cartomancer.load_mod_file('core/hand.lua', 'cartomancer.hand')
Cartomancer.load_mod_file('core/blinds_info.lua', 'cartomancer.blinds_info')
if SMODS then
Cartomancer.load_mod_file('core/view-deck-steamodded.lua', 'cartomancer.view-deck-steamodded')
end
Cartomancer.load_config()

View file

@ -2,6 +2,7 @@
return {
compact_deck_enabled = true,
compact_deck_visible_cards = 100,
hide_deck = false,
deck_view_stack_enabled = true,
deck_view_stack_modifiers = false,
@ -18,18 +19,16 @@ return {
deck_view_hide_drawn_cards = false,
-- todo: maybe custom shader for drawn cards to adjust opacity
blinds_info = true,
improved_hand_sorting = false,
dynamic_hand_align = false,
draw_non_essential_shaders = true,
hide_tags = false,
hide_consumables = false,
hide_deck = false,
hide_jokers = false,
flames_intensity_min = 0.5,
flames_intensity_max = 10,
flames_relative_intensity = false,
flames_slower_speed = false,
flames_intensity_vanilla = false,
flames_volume = 100,
jokers_controls_buttons = true,

View file

@ -0,0 +1,200 @@
function Cartomancer.create_vert_tabs(args)
args = args or {}
args.colour = args.colour or G.C.CLEAR
args.tab_alignment = args.tab_alignment or 'cl'
args.opt_callback = args.opt_callback or nil
args.scale = args.scale or 1
args.tab_w = args.tab_w or 0
args.tab_h = args.tab_h or 0
args.text_scale = (args.text_scale or 0.5)
local tab_buttons = {}
for k, v in ipairs(args.tabs) do
if v.chosen then args.current = {k = k, v = v} end
local id = 'tab_but_'..(v.label or '')
tab_buttons[#tab_buttons+1] = {n=G.UIT.R, config={align = "cm"}, nodes={
UIBox_button({id = id, ref_table = v, button = 'cartomancer_settings_change_tab', label = {v.label}, colour = lighten(G.C.GREY, 0.115),
padding = 0.1, minh = 2.8*args.scale, minw = 0.8*args.scale, col = true, choice = true, scale = args.text_scale,
vert = true, chosen = v.chosen and 'vert', func = v.func, focus_args = {type = 'none'}})
}}
end
-- Tabs + Contents
return {n=G.UIT.R, config={padding = 0, align = "cl", colour = args.colour,},
nodes={
-- Tabs
{n=G.UIT.C, config={align = "cl", padding = 0.2, colour = G.C.CLEAR}, nodes=tab_buttons},
-- Tab contents
{n=G.UIT.C, config={align = args.tab_alignment, padding = args.padding or 0.1, no_fill = true, minh = args.tab_h, minw = args.tab_w}, nodes={
{n=G.UIT.O, config={id = 'cartomancer_settings_tab_contents',
old_chosen = tab_buttons[1].nodes[1].nodes[1],
object = UIBox{definition = args.current.v.tab_definition_function(args.current.v.tab_definition_function_args),
config = {offset = {x=0,y=0}}}}
}
}},
}
}
end
function Cartomancer.blinds_info_icon()
local icon = AnimatedSprite(0,0,0.75,0.75, G.ANIMATION_ATLAS['blind_chips'], {x=0, y=1})
icon.states.drag.can = false
return {n=G.UIT.C, config={align = "cm", padding = 0.05, r = 0.1, button = 'change_tab'}, nodes={
{n=G.UIT.O, config={object = icon}},
}}
end
local gnb = get_new_boss
function get_new_boss(...)
local ret = gnb(...)
G.GAME.cartomancer_bosses_list = G.GAME.cartomancer_bosses_list or {}
G.GAME.cartomancer_bosses_list[#G.GAME.cartomancer_bosses_list+1] = ret
return ret
end
function Cartomancer.view_blinds_info()
local blind_matrix = {
{},{},{}, {}, {}, {}
}
G.GAME.cartomancer_bosses_list = G.GAME.cartomancer_bosses_list or {}
local bosses_list_size = #G.GAME.cartomancer_bosses_list
local bosses_to_show = 25
local blind_tab = {}
-- Go from last generated boss blind until first
for i = bosses_list_size, (bosses_list_size - bosses_to_show), -1 do
local blind_key = G.GAME.cartomancer_bosses_list[i]
local blind = G.P_BLINDS[blind_key]
if blind then
blind_tab[#blind_tab+1] = blind
else
blind_tab[#blind_tab+1] = G.b_undiscovered
end
end
for k, v in ipairs(blind_tab) do
local discovered = v.discovered
local temp_blind = AnimatedSprite(0,0,0.9,0.9, G.ANIMATION_ATLAS[v.atlas or 'blind_chips'], v.pos)
temp_blind:define_draw_steps({
{shader = 'dissolve', shadow_height = 0.05},
{shader = 'dissolve'}
})
if k == 1 then
G.E_MANAGER:add_event(Event({
trigger = 'immediate',
func = (function()
G.CONTROLLER:snap_to{node = temp_blind}
return true
end)
}))
end
temp_blind.float = true
temp_blind.states.hover.can = true
temp_blind.states.drag.can = false
temp_blind.states.collide.can = true
temp_blind.config = {blind = v, force_focus = true}
if v ~= G.b_undiscovered then
temp_blind.hover = function()
if not G.CONTROLLER.dragging.target or G.CONTROLLER.using_touch then
if not temp_blind.hovering and temp_blind.states.visible then
temp_blind.hovering = true
temp_blind.hover_tilt = 3
temp_blind:juice_up(0.05, 0.02)
play_sound('chips1', math.random()*0.1 + 0.55, 0.12)
temp_blind.config.h_popup = create_UIBox_blind_popup(v, discovered)
temp_blind.config.h_popup_config ={align = 'cl', offset = {x=-0.1,y=0},parent = temp_blind}
Node.hover(temp_blind)
if temp_blind.children.alert then
temp_blind.children.alert:remove()
temp_blind.children.alert = nil
temp_blind.config.blind.alerted = true
G:save_progress()
end
end
end
temp_blind.stop_hover = function() temp_blind.hovering = false; Node.stop_hover(temp_blind); temp_blind.hover_tilt = 0 end
end
end
blind_matrix[math.ceil((k-1)/5+0.001)][1+((k-1)%5)] = {n=G.UIT.C, config={align = "cm", padding = 0.1}, nodes={
--(k==6 or k ==16 or k == 26) and {n=G.UIT.B, config={h=0.2,w=0.5}} or nil,
{n=G.UIT.O, config={object = temp_blind, focus_with_object = true}},
--(k==5 or k ==15 or k == 25) and {n=G.UIT.B, config={h=0.2,w=0.5}} or nil,
}}
end
local min_ante = 1
local max_ante = 9
local spacing = 0.07
local current_ante = G.GAME and G.GAME.round_resets and G.GAME.round_resets.ante or 1
local ante_scaling = G.GAME and G.GAME.starting_params and G.GAME.starting_params.ante_scaling or 1
if current_ante > 1 then
min_ante = current_ante - 1
max_ante = current_ante + 8
end
local ante_amounts = {}
for i = min_ante, max_ante do
if spacing > 0 and i > 1 then
ante_amounts[#ante_amounts+1] = {n=G.UIT.R, config={minh = spacing}, nodes={}}
end
local blind_chip = Sprite(0,0,0.2,0.2,G.ASSET_ATLAS["ui_"..(G.SETTINGS.colourblind_option and 2 or 1)], {x=0, y=0})
blind_chip.states.drag.can = false
ante_amounts[#ante_amounts+1] = {n=G.UIT.R, config={align = "cm", padding = 0.07, colour = i == current_ante and G.C.GREY}, nodes={
{n=G.UIT.C, config={align = "cm", minw = 0.7}, nodes={
{n=G.UIT.T, config={text = i, scale = 0.4, colour = G.C.FILTER, shadow = true}},
}},
{n=G.UIT.C, config={align = "cr", minw = 2.8}, nodes={
{n=G.UIT.O, config={object = blind_chip}},
{n=G.UIT.C, config={align = "cm", minw = 0.03, minh = 0.01}, nodes={}},
{n=G.UIT.T, config={text =number_format(get_blind_amount(i) * ante_scaling), scale = 0.4, colour = i <= G.PROFILES[G.SETTINGS.profile].high_scores.furthest_ante.amt and G.C.RED or G.C.JOKER_GREY, shadow = true}},
}}
}}
end
return {n=G.UIT.ROOT, config={align = "cm", colour = G.C.CLEAR, padding = 0, minh = 7.615, minw = 11.5}, nodes={
{n=G.UIT.C, config={align = "cm", r = 0.1, colour = G.C.BLACK, padding = 0.1, emboss = 0.05}, nodes={
{n=G.UIT.C, config={align = "cm", r = 0.1, colour = G.C.L_BLACK, padding = 0.15, force_focus = true, focus_args = {nav = 'tall'}}, nodes={
{n=G.UIT.R, config={align = "cm", padding = 0.05}, nodes={
{n=G.UIT.C, config={align = "cm", minw = 0.7}, nodes={
{n=G.UIT.T, config={text = localize('k_ante_cap'), scale = 0.4, colour = lighten(G.C.FILTER, 0.2), shadow = true}},
}},
{n=G.UIT.C, config={align = "cr", minw = 2.8}, nodes={
{n=G.UIT.T, config={text = localize('k_base_cap'), scale = 0.4, colour = lighten(G.C.RED, 0.2), shadow = true}},
}}
}},
{n=G.UIT.R, config={align = "cm"}, nodes=ante_amounts}
}},
{n=G.UIT.C, config={align = "cm", minw = 6.}, nodes={
{n=G.UIT.R, config={align = "cm"}, nodes={
{n=G.UIT.B, config={h=0.2,w=0.5}}
}},
{n=G.UIT.R, config={align = "cm"}, nodes={
{n=G.UIT.C, config={align = "cm", outline = 1, outline_colour = G.C.GREY, colour = darken(G.C.GREY, 0.3), minw = 5.2, r = 0.1, padding = 0.07, line_emboss = 1}, nodes={
{n=G.UIT.O, config={object = DynaText({string = localize('carto_blinds_info_title'), colours = {G.C.WHITE}, shadow = true, float = true, y_offset = -4, scale = 0.45, maxw =4.4})}},
}},
}},
{n=G.UIT.R, config={align = "cm"}, nodes={
{n=G.UIT.B, config={h=0.2,w=0.5}}
}},
{n=G.UIT.R, config={align = "cm"}, nodes={
{n=G.UIT.R, config={align = "cm"}, nodes=blind_matrix[1]},
{n=G.UIT.R, config={align = "cm"}, nodes=blind_matrix[2]},
{n=G.UIT.R, config={align = "cm"}, nodes=blind_matrix[3]},
{n=G.UIT.R, config={align = "cm"}, nodes=blind_matrix[4]},
{n=G.UIT.R, config={align = "cm"}, nodes=blind_matrix[5]},
}}
}},
}}
}}
end

View file

@ -1,15 +1,22 @@
local nan = math.huge/math.huge
local big_numbah = 1e308
function Cartomancer.get_flames_intensity()
function Cartomancer.get_flames_intensity(preview)
local value
if Cartomancer.SETTINGS.flames_relative_intensity then
if preview then
value = Cartomancer._INTERNAL_gasoline
elseif Cartomancer.SETTINGS.flames_relative_intensity then
-- Scale intensity relative to the required score
value = math.max(0., math.log(G.ARGS.score_intensity.earned_score/G.ARGS.score_intensity.required_score + 5, 5))
else
value = math.max(0., math.log(G.ARGS.score_intensity.earned_score, 5) - 2)
end
if Cartomancer.SETTINGS.flames_intensity_max >= Cartomancer._INTERNAL_max_flames_intensity then
if value == math.huge or not value or value == nan then
value = big_numbah
end
if Cartomancer.SETTINGS.flames_intensity_vanilla then
return value
end
@ -23,18 +30,18 @@ function Cartomancer.handle_flames_volume(value)
return Cartomancer.SETTINGS.flames_volume/100. * value
end
local function intensity_for_big_scores(real_intensity)
local power = 0.55
function Cartomancer.init_setting_flames()
G.ARGS.flame_handler.chips_cart = G.ARGS.flame_handler.chips_cart or {
id = 'flame_chips_cart',
arg_tab = 'chip_flames_cart',
colour = G.C.UI_CHIPS,
accent = G.C.UI_CHIPLICK or SMODS and SMODS.Scoring_Parameters and SMODS.Scoring_Parameters.chips and SMODS.Scoring_Parameters.chips.lick or {1, 1, 1, 1}
}
real_intensity = math.max(0, real_intensity)
return math.max(0, math.min(6, real_intensity) + math.max(1, math.log(real_intensity)) ^ power) - 1.
end
function Cartomancer.handle_flames_timer(timer, intensity)
if not Cartomancer.SETTINGS.flames_slower_speed then
return timer + G.real_dt*(1 + intensity*0.2)
end
return timer + G.real_dt*(1 + intensity_for_big_scores(intensity)*0.7)
G.ARGS.flame_handler.mult_cart = G.ARGS.flame_handler.mult_cart or {
id = 'flame_mult_cart',
arg_tab = 'mult_flames_cart',
colour = G.C.UI_MULT,
accent = G.C.UI_MULTLICK or SMODS and SMODS.Scoring_Parameters and SMODS.Scoring_Parameters.mult and SMODS.Scoring_Parameters.mult.lick or {1, 1, 1, 1}
}
end

View file

@ -1,35 +1,3 @@
-- ============================
-- Hide non-essential shaders
-- ============================
local essential_shaders = {
background = true,
CRT = true,
flame = true,
flash = true,
dissolve = true,
vortex = true,
voucher = true,
booster = true,
hologram = true,
debuff = true,
played = true,
skew = true,
splash = true,
}
local sprite_draw_shader = Sprite.draw_shader
function Sprite:draw_shader(_shader, _shadow_height, _send, _no_tilt, other_obj, ms, mr, mx, my, custom_shader, tilt_shadow)
if not Cartomancer.SETTINGS.draw_non_essential_shaders and _shader == 'negative' then
_shader = 'dissolve'
_send = nil
end
if Cartomancer.SETTINGS.draw_non_essential_shaders or essential_shaders[_shader] then
return sprite_draw_shader(self, _shader, _shadow_height, _send, _no_tilt, other_obj, ms, mr, mx, my, custom_shader, tilt_shadow)
end
end
-- ============================
-- Hide card areas
-- ============================

View file

@ -1,132 +1,38 @@
-- THIS IS NO LONGER BEING USED
-- Leaving this in for sentimental value :)
local Cartomancer_replacements = {
{
find = [[
for k, v in ipairs%(G%.playing_cards%) do
if v%.base%.suit then table%.insert%(SUITS%[v%.base%.suit%], v%) end]],
-- Steamodded<0917b
find_alt = [[
for k, v in ipairs%(G%.playing_cards%) do
table%.insert%(SUITS%[v%.base%.suit%], v%)]],
place = [[
local SUITS_SORTED = Cartomancer.tablecopy(SUITS)
for k, v in ipairs(G.playing_cards) do
if v.base.suit then
local greyed
if unplayed_only and not ((v.area and v.area == G.deck) or v.ability.wheel_flipped) then
greyed = true
end
local card_string = v:cart_to_string {deck_view = true}
if greyed then
card_string = card_string .. "Greyed" -- for some reason format doesn't work and final string is `sGreyed`
end
if greyed and Cartomancer.SETTINGS.deck_view_hide_drawn_cards then
-- Ignore this card.
elseif not SUITS[v.base.suit][card_string] then
-- Initiate stack
table.insert(SUITS_SORTED[v.base.suit], card_string)
local _scale = 0.7
local copy = copy_card(v, nil, _scale)
copy.greyed = greyed
copy.stacked_quantity = 1
SUITS[v.base.suit][card_string] = copy
else
-- Stack cards
local stacked_card = SUITS[v.base.suit][card_string]
stacked_card.stacked_quantity = stacked_card.stacked_quantity + 1
end
end]]
},
{
find = "card_limit = #SUITS%[suit_map%[j%]%],",
place = "card_limit = #SUITS_SORTED[suit_map[j]],"
},
{
find = [[
for i = 1%, %#SUITS%[suit_map%[j%]%] do
if SUITS%[suit_map%[j%]%]%[i%] then
local greyed%, _scale = nil%, 0%.7
if unplayed_only and not %(%(SUITS%[suit_map%[j%]%]%[i%]%.area and SUITS%[suit_map%[j%]%]%[i%]%.area == G%.deck%) or SUITS%[suit_map%[j%]%]%[i%]%.ability%.wheel_flipped%) then
greyed = true
end
local copy = copy_card%(SUITS%[suit_map%[j%]%]%[i%]%, nil%, _scale%)
copy%.greyed = greyed
copy%.T%.x = view_deck%.T%.x %+ view_deck%.T%.w %/ 2
copy%.T%.y = view_deck%.T%.y
copy:hard_set_T%(%)
view_deck:emplace%(copy%)
end
end]],
place = [[
for i = 1%, %#SUITS_SORTED%[suit_map%[j%]%] do
local card_string = SUITS_SORTED%[suit_map%[j%]%]%[i%]
local card = SUITS%[suit_map%[j%]%]%[card_string%]
card%.T%.x = view_deck%.T%.x %+ view_deck%.T%.w%/2
card%.T%.y = view_deck%.T%.y
card:create_quantity_display%(%)
card:hard_set_T%(%)
view_deck:emplace%(card%)
end]]
},
{
find = ' modded and {n = G.UIT.R, config = {align = "cm"}, nodes = {',
place = [=[
not unplayed_only and Cartomancer.add_unique_count() or nil,
modded and {n = G.UIT.R, config = {align = "cm"}, nodes = {]=]
},
}
-- Mom, can we have lovely patches for overrides.lua?
-- No, we have lovely patches at home
Cartomancer.get_visible_suits_smods = function (unplayed_only, page)
-- Lovely patches at home:
local SUITS = {}
-- Init all suits visible in deck
for _, v in ipairs(G.playing_cards) do
if v.base.suit then
local greyed = unplayed_only and not ((v.area and v.area == G.deck) or v.ability.wheel_flipped)
if greyed and Cartomancer.SETTINGS.deck_view_hide_drawn_cards then
-- Ignore this card.
elseif not SUITS[v.base.suit] then
SUITS[v.base.suit] = true
end
end
end
local Cartomancer_nfs_read
local Cartomancer_nfs_read_override = function (containerOrName, nameOrSize, sizeOrNil)
local data, size = Cartomancer_nfs_read(containerOrName, nameOrSize, sizeOrNil)
if type(containerOrName) ~= "string" then
return data, size
end
local overrides = '/overrides.lua'
if containerOrName:sub(-#overrides) ~= overrides then
return data, size
-- Now create a table with all visible suits
-- sorted in the same order as the deck view
local visible_suits = {}
for i = #SMODS.Suit.obj_buffer, 1, -1 do
if SUITS[SMODS.Suit.obj_buffer[i]] then
table.insert(visible_suits, SMODS.Suit.obj_buffer[i])
end
end
local replaced = 0
local total_replaced = 0
for _, v in ipairs(Cartomancer_replacements) do
data, replaced = string.gsub(data, v.find, v.place)
local deck_start_index = (page - 1) * 4 + 1
local deck_end_index = math.min(deck_start_index + 4 - 1, #visible_suits)
if replaced == 0 and v.find_alt then
data, replaced = string.gsub(data, v.find_alt, v.place)
end
if replaced == 0 then
print("Failed to replace " .. v.find .. " for overrides.lua")
else
total_replaced = total_replaced + 1
end
end
print("Totally applied " .. total_replaced .. " replacements to overrides.lua")
-- We no longer need this override
NFS.read = Cartomancer_nfs_read
return data, size
local result_suits = {}
for i = deck_start_index, deck_end_index do
result_suits[visible_suits[i]] = true
end
return result_suits
end

View file

@ -68,6 +68,55 @@ function Cartomancer.table_size(t)
return size
end
-- Compatibility with old settings ;-;
-- should have made this properly at the very beginning :(
local legacy_vertical = {
top = 1,
center = 2,
bottom = 3,
}
local legacy_horizontal = {
left = 1,
middle = 2,
right = 3,
}
local function fix_settings_values()
if type(Cartomancer.SETTINGS.deck_view_stack_pos_vertical) == "string" then
Cartomancer.SETTINGS.deck_view_stack_pos_vertical = legacy_vertical[Cartomancer.SETTINGS.deck_view_stack_pos_vertical]
end
if type(Cartomancer.SETTINGS.deck_view_stack_pos_vertical) ~= "number" then
Cartomancer.SETTINGS.deck_view_stack_pos_vertical = 1
end
if type(Cartomancer.SETTINGS.deck_view_stack_pos_horizontal) == "string" then
Cartomancer.SETTINGS.deck_view_stack_pos_horizontal = legacy_horizontal[Cartomancer.SETTINGS.deck_view_stack_pos_horizontal]
end
if type(Cartomancer.SETTINGS.deck_view_stack_pos_horizontal) ~= "number" then
Cartomancer.SETTINGS.deck_view_stack_pos_horizontal = 2
end
end
local vertical_options = {
"t", -- top
"c", -- center
"b" -- bottom
}
local horizontal_options = {
"l", -- left
"m", -- middle
"r" -- right
}
local function get_align_from_settings()
fix_settings_values()
local vertical = vertical_options[Cartomancer.SETTINGS.deck_view_stack_pos_vertical]
local horizontal = horizontal_options[Cartomancer.SETTINGS.deck_view_stack_pos_horizontal]
return vertical .. horizontal
end
function Cartomancer.add_unique_count()
local unique_count = 0
@ -92,21 +141,44 @@ end
-- Handle amount display
----- Copied from incantation
G.FUNCS.disable_quantity_display = function(e)
local preview_card = e.config.ref_table
e.states.visible = preview_card.stacked_quantity > 1
local function copy_values(to, from)
for k, v in pairs(from) do
to[k] = v
end
end
local old_opacity
local background_color = {}
local old_color
local x_color = {}
----- Copied from incantation
G.FUNCS.cartomancer_deck_view_quantity = function(e)
local preview_card = e.config.ref_table
e.states.visible = preview_card.stacked_quantity > 1
if Cartomancer.INTERNAL_in_config then
if old_opacity ~= Cartomancer.SETTINGS.deck_view_stack_background_opacity then
old_opacity = Cartomancer.SETTINGS.deck_view_stack_background_opacity
copy_values(background_color, adjust_alpha(darken(G.C.BLACK, 0.2), Cartomancer.SETTINGS.deck_view_stack_background_opacity / 100))
end
if old_color ~= Cartomancer.SETTINGS.deck_view_stack_x_color then
old_color = Cartomancer.SETTINGS.deck_view_stack_x_color
copy_values(x_color, Cartomancer.hex_to_color(Cartomancer.SETTINGS.deck_view_stack_x_color))
end
end
end
function Card:create_quantity_display()
if not Cartomancer.SETTINGS.deck_view_stack_enabled then
return
end
local X_COLOR = HEX(Cartomancer.SETTINGS.deck_view_stack_x_color)
if not self.children.stack_display and self.stacked_quantity > 1 then
copy_values(background_color, adjust_alpha(darken(G.C.BLACK, 0.2), Cartomancer.SETTINGS.deck_view_stack_background_opacity / 100))
copy_values(x_color, Cartomancer.hex_to_color(Cartomancer.SETTINGS.deck_view_stack_x_color))
self.children.stack_display = UIBox {
definition = {
n = G.UIT.ROOT,
@ -118,15 +190,15 @@ function Card:create_quantity_display()
r = 0.001,
padding = 0.1,
align = 'cm',
colour = adjust_alpha(darken(G.C.BLACK, 0.2), Cartomancer.SETTINGS.deck_view_stack_background_opacity / 100),
colour = background_color,
shadow = false,
func = 'disable_quantity_display',
func = 'cartomancer_deck_view_quantity',
ref_table = self
},
nodes = {
{
n = G.UIT.T, -- node type
config = { text = 'x', scale = 0.35, colour = X_COLOR }
config = { text = 'x', scale = 0.35, colour = x_color }
, padding = -1
},
{
@ -139,7 +211,7 @@ function Card:create_quantity_display()
}
},
config = {
align = (Cartomancer.SETTINGS.deck_view_stack_pos_vertical:sub(1, 1)) .. (Cartomancer.SETTINGS.deck_view_stack_pos_horizontal:sub(1, 1)),
align = get_align_from_settings(),
bond = 'Strong',
parent = self
},
@ -150,3 +222,38 @@ function Card:create_quantity_display()
}
end
end
function Cartomancer.get_view_deck_preview_area()
if not Cartomancer.view_deck_preview_area then
local preview = CardArea(
G.ROOM.T.x + 0.2*G.ROOM.T.w/2,G.ROOM.T.h,
G.CARD_W,
G.CARD_H,
{card_limit = 1, type = 'title', view_deck = true, highlight_limit = 0, card_w = G.CARD_W*0.7, draw_layers = {'card'}})
local card = Card(preview.T.x + preview.T.w/2, preview.T.y, G.CARD_W*0.7, G.CARD_H*0.7, G.P_CARDS.S_A, G.P_CENTERS.m_gold)
card.stacked_quantity = 69
card.no_ui = true
card:create_quantity_display()
card:hard_set_T()
preview:emplace(card)
Cartomancer.view_deck_preview_area = preview
end
return Cartomancer.view_deck_preview_area
end
Cartomancer.update_view_deck_preview = function ()
if not Cartomancer.view_deck_preview_area then
return
end
for _, card in pairs(Cartomancer.view_deck_preview_area.cards) do
if card.children.stack_display then
card.children.stack_display:remove()
card.children.stack_display = nil
end
card:create_quantity_display()
end
end

View file

@ -93,7 +93,89 @@ Cartomancer.table_join_keys = function (tab_, separator)
return inline or "[empty]"
end
Cartomancer.empty_table = {}
Cartomancer.remove_empty_tables = function (list)
local result = {}
for _, v in ipairs(list) do
if v ~= Cartomancer.empty_table then
result[#result+1] = v
end
end
return result
end
Cartomancer.do_nothing = function (...) end
Cartomancer.align_object = function (o)
o:align_to_major()
local x = (o.T.x)
local y = (o.T.y)
local w = (o.T.w)
local h = (o.T.h)
Moveable.hard_set_T(o,x, y, w, h)
o:hard_set_T(x, y, w, h)
end
function Cartomancer.basen(n,b)
n = math.floor(n)
if not b or b == 10 then return tostring(n) end
local digits = "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
local t = {}
local sign = ""
if n < 0 then
sign = "-"
n = -n
end
repeat
local d = (n % b) + 1
n = math.floor(n / b)
table.insert(t, 1, digits:sub(d,d))
until n == 0
return sign .. table.concat(t,"")
end
local function is_valid_hex(letter)
local byte_val = string.byte(string.upper(letter))
-- Between A-F or 0-9
return byte_val >= 65 and byte_val <= 70 or byte_val >= 48 and byte_val <= 57
end
function Cartomancer.hex_to_color(hex)
-- Make sure string length is always 8
while #hex < 8 do
hex = hex.."F"
end
hex = string.sub(hex, 1, 8)
-- Make sure string only contains
for i = 1, #hex do
if not is_valid_hex(hex:sub(i,i)) then
-- insane way to replace char at given index
hex = ("%sF%s"):format(hex:sub(1,i-1), hex:sub(i+1))
end
end
local _,_,r,g,b,a = hex:find('(%x%x)(%x%x)(%x%x)(%x%x)')
local color = {tonumber(r,16)/255,tonumber(g,16)/255,tonumber(b,16)/255,tonumber(a,16)/255 or 255}
return color
end
function Cartomancer.color_to_hex(color)
local hex = ""
for i = 1, 3 do
local base_16 = Cartomancer.basen(color[i] * 255, 16)
-- Numbers below 16 need 0 in front
if #base_16 == 1 then
base_16 = "0"..base_16
end
-- How would we ever get numbers above 255 :3c
base_16 = base_16:sub(#base_16 - 1, #base_16)
hex = hex .. base_16
end
return hex
end
return Cartomancer

View file

@ -1,8 +1,5 @@
if Cartomancer.use_smods() then return end
-- Vanilla will only support default loc cuz yes.
local loc_table = Cartomancer.load_mod_file('localization/en-us.lua', 'localization')
-- Credits: Steamodded
-- I was lazy and it's not like I'm going to code anything different from this anyways~
local function recurse(target, ref_table)
@ -15,14 +12,45 @@ local function recurse(target, ref_table)
end
end
end
recurse(loc_table, G.localization)
--local cas = CardArea.sort
--function CardArea:sort(method)
-- if method == 'sort_id' and self.cards[1] and self.cards[1].sort_id then
-- table.sort(self.cards, function (a, b) return a.sort_id > b.sort_id end )
-- return
-- end
--
-- return cas(self, method)
--end
local function add_defaults(default_table, target_table)
if type(default_table) ~= 'table' then return end
for k, v in pairs(default_table) do
if target_table[k] then
if type(v) == "table" then
add_defaults(v, target_table[k])
end
else
target_table[k] = v
end
end
end
local function load_localization()
local default_table = Cartomancer.load_mod_file('localization/en-us.lua', 'cartomancer.localization')
local loc_file = Cartomancer.path.."/localization/"..G.SETTINGS.language..".lua"
local loc_table
if Cartomancer.nfs.fileExists(loc_file) then
loc_table = load(Cartomancer.nfs.read(loc_file), "Cartomancer - Localization")()
-- Use english strings for missing localization strings
if G.SETTINGS.language ~= "en-us" then
add_defaults(default_table, loc_table)
end
else
loc_table = default_table
end
recurse(loc_table, G.localization)
end
load_localization()
local init_localization_ref = init_localization
function init_localization(...)
load_localization()
return init_localization_ref(...)
end

View file

@ -1,5 +1,8 @@
-- Setting max intensity to this value disables limit.
Cartomancer.C = {
HALF_GRAY = {G.C.GREY[1], G.C.GREY[2], G.C.GREY[3], 0.75},
}
Cartomancer._INTERNAL_max_flames_intensity = 40
local create_column_tabs,
@ -11,6 +14,8 @@ local create_column_tabs,
create_inline_options,
create_option_cycle_custom
local slider_callbacks = {}
local create_UIBox_generic_options_custom = function (args)
args = args or {}
@ -36,38 +41,35 @@ local function choose_tab(tab)
end
end
local tab_config = {r = 0.1, align = "t", padding = 0.0, colour = G.C.CLEAR, minw = 8.5, minh = 6}
local tab_config = {r = 0.1, align = "t", padding = 0.0, colour = G.C.CLEAR, minw = 8.5, minh = 6.6}
Cartomancer.config_tab = function()
Cartomancer.INTERNAL_in_config = true
Cartomancer.log "Opened cartomancer config"
local vertical_tabs = {}
choose_tab "compact_deck"
choose_tab "deck_view"
table.insert(vertical_tabs, {
label = localize('carto_settings_compact_deck'),
chosen = is_chosen("compact_deck"),
tab_definition_function = function (...)
choose_tab "compact_deck"
-- Yellow node. Align changes the position of modes inside
return {n = G.UIT.ROOT, config = tab_config, nodes = {
create_toggle_option {
ref_value = 'compact_deck_enabled',
localization = 'carto_compact_deck_enabled',
},
create_inline_slider({ref_value = 'compact_deck_visible_cards', localization = 'carto_compact_deck_visible_cards', max_value = 300}),
}}
end
})
table.insert(vertical_tabs, {
label = localize('carto_settings_deck_view'),
chosen = is_chosen("deck_view"),
tab_definition_function = function (...)
Cartomancer.view_deck_preview_area = nil
Cartomancer.deck_view_stack_x_color = Cartomancer.deck_view_stack_x_color or Cartomancer.hex_to_color(Cartomancer.SETTINGS.deck_view_stack_x_color)
local update_color = function ()
Cartomancer.SETTINGS.deck_view_stack_x_color = Cartomancer.color_to_hex(Cartomancer.deck_view_stack_x_color)
end
slider_callbacks['slider_red'] = update_color
slider_callbacks['slider_green'] = update_color
slider_callbacks['slider_blue'] = update_color
choose_tab "deck_view"
return {n = G.UIT.ROOT, config = tab_config, nodes = {
create_toggle_option {
ref_value = 'deck_view_hide_drawn_cards',
localization = 'carto_deck_view_hide_drawn_cards',
@ -75,6 +77,9 @@ Cartomancer.config_tab = function()
create_toggle_option {
ref_value = 'deck_view_stack_enabled',
localization = 'carto_deck_view_stack_enabled',
callback = function ()
Cartomancer.update_view_deck_preview()
end
},
create_toggle_option {
ref_value = 'deck_view_stack_modifiers',
@ -84,19 +89,103 @@ Cartomancer.config_tab = function()
ref_value = 'deck_view_stack_chips',
localization = 'carto_deck_view_stack_chips',
},
--create_toggle_option('deck_view_stack_suits', 'carto_deck_view_stack_suits'),
create_inline_slider({ref_value = 'deck_view_stack_background_opacity', localization = 'carto_deck_view_stack_background_opacity',}),
create_input_option('deck_view_stack_x_color', 'carto_deck_view_stack_x_color', 6),
-- inline this
{n = G.UIT.R, config = {align = "cl", padding = 0.05}, nodes = {
{n = G.UIT.R, config = {align = "cl", padding = 0.2, r = 0.1, colour = darken(G.C.L_BLACK, 0.1)}, nodes = {
{n = G.UIT.C, config = {align = "l", padding = 0}, nodes = {
create_option_cycle_custom('deck_view_stack_pos_vertical', 'carto_deck_view_stack_pos_vertical',
'cartomancer_deck_view_pos_vertical', 'carto_deck_view_stack_pos_vertical_options'),
create_inline_slider({
ref_value = 'deck_view_stack_background_opacity',
localization = 'carto_deck_view_stack_background_opacity',
}),
{n=G.UIT.R, config={align = "cl", minh = 0.9, padding = 0}, nodes={
{n=G.UIT.C, config={align = "cl", padding = 0}, nodes={
{n=G.UIT.T, config={text = localize('carto_deck_view_stack_x_color'),colour = G.C.UI.TEXT_LIGHT, scale = 0.36}},
}},
(create_slider({id = 'slider_red', colour = G.C.RED, label_scale = 0.36, w = 1.5, h = 0.3, padding = -0.05,
ref_table = Cartomancer.deck_view_stack_x_color, ref_value = 1, min = 0, max = 1,
decimal_places = 2, hide_value = true})),
(create_slider({id = 'slider_green', colour = G.C.GREEN, label_scale = 0.36, w = 1.5, h = 0.3, padding = -0.05,
ref_table = Cartomancer.deck_view_stack_x_color, ref_value = 2, min = 0, max = 1,
decimal_places = 2, hide_value = true})),
(create_slider({id = 'slider_blue', colour = G.C.BLUE, label_scale = 0.36, w = 1.5, h = 0.3, padding = -0.05,
ref_table = Cartomancer.deck_view_stack_x_color, ref_value = 3, min = 0, max = 1,
decimal_places = 2, hide_value = true})),
}},
-- inline this
{n = G.UIT.R, config = {align = "cl", padding = 0.05}, nodes = {
{n=G.UIT.C, config={align = "cl", padding = 0}, nodes={
{n=G.UIT.T, config={text = localize('carto_deck_view_stack_pos'),colour = G.C.UI.TEXT_LIGHT, scale = 0.36}},
}},
{n = G.UIT.C, config = {align = "l", padding = 0}, nodes = {
create_option_cycle_custom('deck_view_stack_pos_vertical', nil, --'carto_deck_view_stack_pos_vertical',
'cartomancer_deck_view_pos_vertical', 'carto_deck_view_stack_pos_vertical_options'),
}},
{n = G.UIT.C, config = {align = "r", padding = 0}, nodes = {
create_option_cycle_custom('deck_view_stack_pos_horizontal', nil, --'carto_deck_view_stack_pos_horizontal',
'cartomancer_deck_view_pos_horizontal', 'carto_deck_view_stack_pos_horizontal_options'),
}},
}}
}},
{n = G.UIT.C, config = {align = "r", padding = 0}, nodes = {
create_option_cycle_custom('deck_view_stack_pos_horizontal', 'carto_deck_view_stack_pos_horizontal',
'cartomancer_deck_view_pos_horizontal', 'carto_deck_view_stack_pos_horizontal_options'),
{n = G.UIT.C, config = {align = "l", padding = 0.1}, nodes = {
{n=G.UIT.R, config={align = "cm", padding = 0}, nodes={
{n=G.UIT.O, config={object = Cartomancer.get_view_deck_preview_area()}}
}}
}},
}},
}}
end
})
table.insert(vertical_tabs, {
label = localize('carto_settings_compact_deck'),
chosen = is_chosen("compact_deck"),
tab_definition_function = function (...)
if Cartomancer.INTERNAL_compact_deck_area then
Cartomancer.INTERNAL_compact_deck_area:remove()
Cartomancer.INTERNAL_compact_deck_area = nil
end
local area = CardArea(
G.ROOM.T.x + 0.2*G.ROOM.T.w/2,G.ROOM.T.h,
1.1*G.CARD_W,
1.1*G.CARD_H,
{card_limit = 300, type = 'deck'}
)
area.draw_uibox = true
for i = 1, 300 do
local card = Card(G.ROOM.T.x + 0.2*G.ROOM.T.w/2,G.ROOM.T.h, G.CARD_W, G.CARD_H, G.P_CARDS[1], G.P_CENTERS.c_base, {bypass_back = G.P_CENTERS['b_red'].pos, playing_card = i, viewed_back = true})
area:emplace(card)
card.b_red = true
card.sprite_facing = 'back'
card.facing = 'back'
end
Cartomancer.INTERNAL_compact_deck_area = area
choose_tab "compact_deck"
-- Yellow node. Align changes the position of modes inside
return {n = G.UIT.ROOT, config = tab_config, nodes = {
{n = G.UIT.R, config = {align = "cl", padding = 0.2, r = 0.1, colour = G.C.CLEAR}, nodes = {
{n = G.UIT.C, config = {align = "l", padding = 0}, nodes = {
create_toggle_option {
ref_value = 'compact_deck_enabled',
localization = 'carto_compact_deck_enabled',
},
create_inline_slider({ref_value = 'compact_deck_visible_cards', localization = 'carto_compact_deck_visible_cards', max_value = 300}),
create_toggle_option {
ref_value = 'hide_deck',
localization = 'carto_hide_deck',
},
}},
{n = G.UIT.C, config = {align = "r", minw = 2,padding = 0.1}, nodes = {
{n=G.UIT.R, config={align = "cr", padding = 0}, nodes={
}}
}},
{n = G.UIT.C, config = {align = "r", padding = 0.1}, nodes = {
{n=G.UIT.R, config={align = "cr", padding = 0}, nodes={
{n=G.UIT.O, config={object = area}}
}}
}},
}}
}}
@ -113,20 +202,49 @@ Cartomancer.config_tab = function()
label = localize('carto_settings_flames'),
chosen = is_chosen("flames"),
tab_definition_function = function (...)
local minw = 2
local minh = 1
local w = minw * 1.25
local h = minh * 2.5
Cartomancer._INTERNAL_gasoline = 5
local scale = 0.4
choose_tab "flames"
return {n = G.UIT.ROOT, config = tab_config, nodes = {
create_inline_slider({ref_value = 'flames_intensity_min', localization = 'carto_flames_intensity_min', max_value = Cartomancer._INTERNAL_max_flames_intensity, decimal_places = 1}),
create_inline_slider({ref_value = 'flames_intensity_max', localization = 'carto_flames_intensity_max', max_value = Cartomancer._INTERNAL_max_flames_intensity, decimal_places = 1}),
create_toggle_option {
ref_value = 'flames_relative_intensity',
localization = 'carto_flames_relative_intensity',
},
create_toggle_option {
ref_value = 'flames_slower_speed',
localization = 'carto_flames_slower_speed',
},
create_inline_slider({ref_value = 'flames_volume', localization = 'carto_flames_volume',}),
--
{n = G.UIT.R, config = {align = "cl", padding = 0.2, colour = darken(G.C.L_BLACK, 0.1), r = 0.1}, nodes = {
{n = G.UIT.C, config = {align = "cl", padding = 0}, nodes = {
create_inline_slider({ref_value = 'flames_intensity_min', localization = 'carto_flames_intensity_min', max_value = Cartomancer._INTERNAL_max_flames_intensity, decimal_places = 1}),
create_inline_slider({ref_value = 'flames_intensity_max', localization = 'carto_flames_intensity_max', max_value = Cartomancer._INTERNAL_max_flames_intensity, decimal_places = 1}),
create_toggle_option {
ref_value = 'flames_intensity_vanilla',
localization = 'carto_flames_intensity_vanilla',
},
}},
{n = G.UIT.C, config = {align = "cm", padding = 0}, nodes = {
{n=G.UIT.R, config={align = "cm", minh = 1, padding = 0.1}, nodes={
{n=G.UIT.C, config={align = "cr", minw = minw, minh =minh, r = 0.1,colour = G.C.UI_CHIPS, id = 'hand_chip_area_cart', emboss = 0.05}, nodes={
{n=G.UIT.O, config={func = 'flame_handler',no_role = true, id = 'flame_chips_cart', object = Moveable(0,0,0,0), w = 0, h = 0, _w = w, _h = h}},
{n=G.UIT.O, config={id = ':3_chips',object = DynaText({string = {{ref_table = {[":3"] = localize("carto_flames_chips") }, ref_value = ":3"}}, colours = {G.C.UI.TEXT_LIGHT}, font = G.LANGUAGES['en-us'].font, shadow = true, float = true, scale = scale*2})}},
{n=G.UIT.B, config={w=0.1,h=0.1}},
}},
{n=G.UIT.C, config={align = "cm"}, nodes={
{n=G.UIT.T, config={text = "X", lang = G.LANGUAGES['en-us'], scale = scale * 2, colour = G.C.UI_MULT, shadow = true}},
}},
{n=G.UIT.C, config={align = "cl", minw = minw, minh=minh, r = 0.1,colour = G.C.UI_MULT, id = 'hand_mult_area_cart', emboss = 0.05}, nodes={
{n=G.UIT.O, config={func = 'flame_handler',no_role = true, id = 'flame_mult_cart', object = Moveable(0,0,0,0), w = 0, h = 0, _w = w, _h = h}},
{n=G.UIT.B, config={w=0.1,h=0.1}},
{n=G.UIT.O, config={id = ':3_mult',object = DynaText({string = {{ref_table = {[":3"] = localize("carto_flames_mult") }, ref_value = ":3"}}, colours = {G.C.UI.TEXT_LIGHT}, font = G.LANGUAGES['en-us'].font, shadow = true, float = true, scale = scale*2})}},
}}
}},
create_inline_slider({align = 'cm', ref_table = Cartomancer, ref_value = '_INTERNAL_gasoline', localization = 'carto_flames_gasoline', max_value = Cartomancer._INTERNAL_max_flames_intensity, decimal_places = 1}),
}}
}},
}}
end
})
@ -139,17 +257,17 @@ Cartomancer.config_tab = function()
choose_tab "other"
return {n = G.UIT.ROOT, config = tab_config, nodes = {
create_toggle_option {
ref_value = 'improved_hand_sorting',
localization = 'carto_improved_hand_sorting',
callback = function () G.FUNCS.change_play_discard_position {to_key = G.SETTINGS.play_button_pos} end
ref_value = 'blinds_info',
localization = 'carto_blinds_info_setting',
},
create_toggle_option {
ref_value = 'dynamic_hand_align',
localization = 'carto_dynamic_hand_align',
},
create_toggle_option {
ref_value = 'draw_non_essential_shaders',
localization = 'carto_draw_non_essential_shaders',
ref_value = 'improved_hand_sorting',
localization = 'carto_improved_hand_sorting',
callback = function () G.FUNCS.change_play_discard_position {to_key = G.SETTINGS.play_button_pos} end
},
create_toggle_option {
ref_value = 'hide_tags',
@ -160,14 +278,6 @@ Cartomancer.config_tab = function()
ref_value = 'hide_consumables',
localization = 'carto_hide_consumables',
},
create_toggle_option {
ref_value = 'hide_deck',
localization = 'carto_hide_deck',
},
create_toggle_option {
ref_value = 'hide_jokers',
localization = 'carto_hide_jokers',
},
}}
end
})
@ -211,7 +321,7 @@ Cartomancer.config_tab = function()
nodes = {
create_column_tabs({
tab_alignment = 'tl',
tab_w = 8,
tab_w = 11.5,
tab_h = 4.3,-- this seems to not do shit?
text_scale = 0.4,
snap_to_nav = true,
@ -245,40 +355,34 @@ Cartomancer.jokers_visibility_menu = function ()
}}
end
create_inline_slider = function (args)
local args = args or {}
local slider = create_slider({label = localize(args.localization), label_scale = 0.36, w = 3, h = 0.3, padding = -0.05,
ref_table = Cartomancer.SETTINGS, ref_value = args.ref_value, min = args.min_value or 0, max = args.max_value or 100,
if type(args.callback) == "function" then
slider_callbacks[args.ref_value] = args.callback
end
local slider = create_slider({w = 3, h = 0.3, padding = -0.05,
ref_table = args.ref_table or Cartomancer.SETTINGS, ref_value = args.ref_value, min = args.min_value or 0, max = args.max_value or 100,
decimal_places = args.decimal_places})
slider.nodes[1].config.align = "cl"
for _, node in pairs(slider.nodes) do
node.n = G.UIT.C
if args.localization then
return {n=G.UIT.R, config={align = args.align or "cl", minh = 0.9, padding = 0.036}, nodes={
{n=G.UIT.C, config={align = "cl", padding = 0}, nodes={
{n=G.UIT.T, config={text = localize(args.localization),colour = G.C.UI.TEXT_LIGHT, scale = 0.36}},
}},
(slider)
}}
end
-- slider.nodes[2].nodes[1].n = G.UIT.R
return slider
end
local function starts_with(str, start)
return str:sub(1, #start) == start
end
local function find_option(options, value)
for i, str in pairs(options) do
if starts_with(str, value) then
return i
end
end
return (slider)
end
create_option_cycle_custom = function (ref_value, localization, change_function, options)
local options_loc = localize(options)
local cycle = create_option_cycle({w = 3, label = localize(localization),scale = 0.7, options = options_loc,
opt_callback = change_function, current_option = find_option(options_loc, Cartomancer.SETTINGS[ref_value])})
local cycle = create_option_cycle({w = 2.75, label = localization and localize(localization),scale = 0.7, options = options_loc,
opt_callback = change_function, current_option = tonumber(Cartomancer.SETTINGS[ref_value])})
cycle.config.padding = 0
@ -324,10 +428,13 @@ create_keybind = function (args)
}}
end
create_input_option = function (ref_value, localization, max_length)
create_input_option = function (args)
args = args or {}
args.ref_table = args.ref_table or Cartomancer.SETTINGS
return { n = G.UIT.R, config = {align = "cl", minw = 4, minh = 0.5, colour = G.C.CLEAR, padding = 0.05}, nodes = {
{ n = G.UIT.T, config = {text = localize(localization), scale = .36, minw = 4, minh = 0.5, colour = G.C.WHITE} },
create_text_input({ id = 'Input:'..ref_value, w = 2, max_length = max_length or 3, prompt_text = tostring(Cartomancer.SETTINGS[ref_value]), ref_table = Cartomancer.SETTINGS, ref_value = ref_value})
args.localization and { n = G.UIT.T, config = {text = localize(args.localization), scale = .36, minw = 4, minh = 0.5, colour = G.C.WHITE} } or nil,
create_text_input({ id = 'Input:'..args.ref_value, w = 2, max_length = args.max_length or 3, prompt_text = tostring(args.ref_table[args.ref_value]), ref_table = args.ref_table, ref_value = args.ref_value})
}}
end
@ -380,11 +487,32 @@ end
G.FUNCS.cartomancer_deck_view_pos_vertical = function(args)
Cartomancer.SETTINGS.deck_view_stack_pos_vertical = args.to_val
Cartomancer.SETTINGS.deck_view_stack_pos_vertical = args.to_key
Cartomancer.update_view_deck_preview()
end
G.FUNCS.cartomancer_deck_view_pos_horizontal = function(args)
Cartomancer.SETTINGS.deck_view_stack_pos_horizontal = args.to_val
Cartomancer.SETTINGS.deck_view_stack_pos_horizontal = args.to_key
Cartomancer.update_view_deck_preview()
end
-- This gets called every frame when you move the slider, which causes a lot of lag if you do heavy operations here
local g_funcs_slider = G.FUNCS.slider
G.FUNCS.slider = function(e)
if Cartomancer.INTERNAL_in_config then
local c = e.children[1]
local rt = c.config.ref_table
if G.CONTROLLER and G.CONTROLLER.dragging.target and
(G.CONTROLLER.dragging.target == e or
G.CONTROLLER.dragging.target == c) then
if slider_callbacks[rt.ref_value] then
slider_callbacks[rt.ref_value]()
elseif slider_callbacks[c.config.id] then
slider_callbacks[c.config.id]()
end
end
end
g_funcs_slider(e)
end
G.FUNCS.cartomancer_settings_change_keybind = function(e)
@ -507,5 +635,3 @@ end

View file

@ -252,6 +252,15 @@ function nativefs.unmount(archive)
return loveC.PHYSFS_unmount(archive) ~= 0
end
function nativefs.fileExists(name)
local file = nativefs.newFile(name)
local ok = file:open('r')
if not ok then return false end
file:close()
return true
end
function nativefs.read(containerOrName, nameOrSize, sizeOrNil)
local container, name, size
if sizeOrNil then

View file

@ -16,15 +16,14 @@ return {
carto_deck_view_stack_modifiers = "Stack all modifiers",
carto_deck_view_stack_chips = "Stack different chip values",
-- carto_deck_view_stack_suits = "Stack all suits", -- Do not think this is necessary if steamodded adds suit pages.
carto_deck_view_stack_x_color = "Stack display color (hex) ",
carto_deck_view_stack_background_opacity = "Stack display opacity ",
carto_deck_view_stack_pos_vertical = "Vertical stack alignment ",
carto_deck_view_stack_x_color = "Color ",
carto_deck_view_stack_background_opacity = "Opacity ",
carto_deck_view_stack_pos = "Alignment ",
carto_deck_view_stack_pos_vertical_options = {
"top",
"center",
"bottom"
},
carto_deck_view_stack_pos_horizontal = "Horizontal stack alignment ",
carto_deck_view_stack_pos_horizontal_options = {
"left",
"middle",
@ -32,18 +31,20 @@ return {
},
carto_deck_view_unique_cards = "Unique cards:",
carto_draw_non_essential_shaders = "Draw non-essential shaders",
carto_improved_hand_sorting = "Improved hand sorting",
carto_dynamic_hand_align = "Improved hand align for huge hand size",
carto_improved_hand_sorting = "More hand sorting options",
carto_dynamic_hand_align = "Better align for cards with huge hand size",
carto_hide_tags = "Hide tags",
carto_hide_consumables = "Hide consumables",
carto_hide_deck = "Hide deck",
carto_hide_jokers = "Hide jokers",
carto_flames_chips = "Chips",
carto_flames_mult = "Mult",
carto_flames_intensity_min = "Min intensity ",
carto_flames_intensity_max = "Max intensity ",
carto_flames_relative_intensity = "Relative score intensity",
carto_flames_slower_speed = "Slower flames on big scores",
carto_flames_relative_intensity = "Score intensity relative to current blind",
carto_flames_intensity_vanilla = "Ignore min/max intensity",
carto_flames_gasoline_title = "Preview",
carto_flames_gasoline = "",
carto_flames_volume = "Flames volume ",
carto_jokers_controls_buttons = "Show joker area buttons",
@ -59,6 +60,11 @@ return {
carto_kb_toggle_consumables = "Toggle consumables visibility",
carto_kb_toggle_jokers = "Toggle jokers visibility",
carto_kb_toggle_jokers_buttons = "Toggle jokers buttons",
carto_blinds_info_setting = "Show Blinds Info tab",
carto_blinds_info_current = "Current",
carto_blinds_info_extra = "History",
carto_blinds_info_title = "Boss Blinds History",
}
}
}

View file

@ -0,0 +1,66 @@
return {
misc = {
dictionary = {
carto_settings_compact_deck = "Baraja compacta",
carto_settings_deck_view = "Vista de la baraja",
carto_settings_jokers = "Comodines",
carto_settings_flames = "Llamas",
carto_settings_other = "Otros",
carto_settings_keybinds = "Teclas",
carto_compact_deck_enabled = "Limitar cartas en el baraja",
carto_compact_deck_visible_cards = "Límite de cartas ",
carto_deck_view_stack_enabled = "Apilar cartas en la vista de la baraja",
carto_deck_view_hide_drawn_cards = "Ocultar cartas robadas",
carto_deck_view_stack_modifiers = "Apilar todos los modificadores",
carto_deck_view_stack_chips = "Apilar diferentes valores de fichas",
carto_deck_view_stack_x_color = "Color ",
carto_deck_view_stack_background_opacity = "Opacidad ",
carto_deck_view_stack_pos = "Alineación ",
carto_deck_view_stack_pos_vertical_options = {
"arriba",
"centro",
"abajo"
},
carto_deck_view_stack_pos_horizontal_options = {
"izquierda",
"medio",
"derecha"
},
carto_deck_view_unique_cards = "Cartas únicas:",
carto_improved_hand_sorting = "Ordenación mejorada de la mano",
carto_dynamic_hand_align = "Alineación mejorada para manos grandes",
carto_hide_tags = "Ocultar etiquetas",
carto_hide_consumables = "Ocultar consumibles",
carto_hide_deck = "Ocultar baraja",
carto_flames_chips = "Fichas",
carto_flames_mult = "Multi",
carto_flames_intensity_min = "Intensidad mínima ",
carto_flames_intensity_max = "Intensidad máxima ",
carto_flames_relative_intensity = "Intensidad relativa a la ciega actual",
carto_flames_intensity_vanilla = "Ignorar intensidad mín/máx",
carto_flames_gasoline_title = "Vista previa",
carto_flames_gasoline = "",
carto_flames_volume = "Volumen de llamas ",
carto_jokers_controls_buttons = "Mostrar botones del área de comodines",
carto_jokers_controls_show_after = "Después de tener más de: ",
carto_jokers_hide = "Ocultar",
carto_jokers_show = "Mostrar",
carto_jokers_zoom = "Ampliar",
carto_waiting_keybind = "Esperando entrada...",
carto_kb_hide_joker = "Ocultar comodín",
carto_kb_toggle_tags = "Alternar visibilidad de etiquetas",
carto_kb_toggle_consumables = "Alternar visibilidad de consumibles",
carto_kb_toggle_jokers = "Alternar visibilidad de comodines",
carto_kb_toggle_jokers_buttons = "Alternar botones de comodines",
}
}
}

View file

@ -0,0 +1,70 @@
return {
misc = {
dictionary = {
carto_settings_compact_deck = "Ép gọn bộ bài",
carto_settings_deck_view = "Xem bộ bài",
carto_settings_jokers = "Joker",
carto_settings_flames = "Lửa",
carto_settings_other = "Khác",
carto_settings_keybinds = "Phím tắt",
carto_compact_deck_enabled = "Giới hạn lá bài trong bộ bài",
carto_compact_deck_visible_cards = "Giới hạn lá bài ",
carto_deck_view_stack_enabled = "Chồng lá bài trong phần xem bộ bài",
carto_deck_view_hide_drawn_cards = "Ẩn lá đã bốc",
carto_deck_view_stack_modifiers = "Chồng mọi sửa đổi",
carto_deck_view_stack_chips = "Chồng giá trị chip khác nhau",
-- carto_deck_view_stack_suits = "Stack all suits", -- Do not think this is necessary if steamodded adds suit pages.
carto_deck_view_stack_x_color = "Màu ",
carto_deck_view_stack_background_opacity = "Độ mờ ",
carto_deck_view_stack_pos = "Vị trí ",
carto_deck_view_stack_pos_vertical_options = {
"đỉnh",
"giữa",
"đáy"
},
carto_deck_view_stack_pos_horizontal_options = {
"trái",
"giữa",
"phải"
},
carto_deck_view_unique_cards = "Lá riêng biệt:",
carto_improved_hand_sorting = "Nhiều lựa chọn sắp xếp bài hơn",
carto_dynamic_hand_align = "Xếp bài đẹp hơn với số lá trong tay lớn",
carto_hide_tags = "Ẩn nhãn bỏ qua",
carto_hide_consumables = "Ẩn lá tiêu thụ",
carto_hide_deck = "Ẩn bộ bài",
carto_flames_chips = "Chip",
carto_flames_mult = "Nhân",
carto_flames_intensity_min = "Cường độ tối thiểu ",
carto_flames_intensity_max = "Cường độ tối đa ",
carto_flames_relative_intensity = "Cường độ tỉ lệ thuận với blind hiện tại",
carto_flames_intensity_vanilla = "Bỏ qua cường độ tối thiểu/tối đa",
carto_flames_gasoline_title = "Xem trước",
carto_flames_gasoline = "",
carto_flames_volume = "Thể tích lửa ",
carto_jokers_controls_buttons = "Hiện nút chỗ joker",
carto_jokers_controls_show_after = "sau khi số lượng joker vượt ",
--carto_jokers_hide_keybind = "Hide hovered joker with Alt + 1",
carto_jokers_hide = "Ẩn",
carto_jokers_show = "Hiện",
carto_jokers_zoom = "Phóng to",
carto_waiting_keybind = "Đang chờ nhập liệu...",
carto_kb_hide_joker = "Ẩn joker",
carto_kb_toggle_tags = "Ẩn/hiện nhãn bỏ qua",
carto_kb_toggle_consumables = "Ẩn/hiện lá tiêu thụ",
carto_kb_toggle_jokers = "Ẩn/hiện joker",
carto_kb_toggle_jokers_buttons = "Ẩn/hiện nút joker",
carto_blinds_info_setting = "Hiện tab thông tin Blind",
carto_blinds_info_current = "Hiện tại",
carto_blinds_info_extra = "Lịch sử",
carto_blinds_info_title = "Lịch sử Boss Blind",
}
}
}

View file

@ -0,0 +1,68 @@
return {
misc = {
dictionary = {
carto_settings_compact_deck = "紧凑牌堆",
carto_settings_deck_view = "牌堆视图",
carto_settings_jokers = "小丑牌区域",
carto_settings_flames = "火焰特效",
carto_settings_other = "其他设置",
carto_settings_keybinds = "键位设置",
carto_compact_deck_enabled = "限制牌堆卡牌显示数量",
carto_compact_deck_visible_cards = "卡牌数量限制:",
carto_deck_view_stack_enabled = "在牌堆视图中堆叠卡牌",
carto_deck_view_hide_drawn_cards = "隐藏已抽取卡牌",
carto_deck_view_stack_modifiers = "堆叠所有效果修饰卡",
carto_deck_view_stack_chips = "堆叠不同筹码值的卡牌",
-- carto_deck_view_stack_suits = "堆叠所有花色卡牌", -- 如果Steamodded已添加花色分页则无需此项
carto_deck_view_stack_x_color = "颜色:",
carto_deck_view_stack_background_opacity = "背景不透明度:",
carto_deck_view_stack_pos = "堆叠对齐方式:",
carto_deck_view_stack_pos_vertical_options = {
"顶部",
"居中",
"底部"
},
carto_deck_view_stack_pos_horizontal_options = {
"左侧",
"居中",
"右侧"
},
carto_deck_view_unique_cards = "唯一卡牌数量:",
carto_improved_hand_sorting = "优化手牌排序算法",
carto_dynamic_hand_align = "动态调整手牌对齐方式(适用于大量手牌)",
carto_hide_tags = "隐藏标签栏",
carto_hide_consumables = "隐藏消耗品栏",
carto_hide_deck = "隐藏牌堆区域",
carto_flames_intensity_min = "火焰最小强度:",
carto_flames_intensity_max = "火焰最大强度:",
carto_flames_relative_intensity = "根据当前盲注动态调整火焰强度",
carto_flames_intensity_vanilla = "使用原版火焰强度(忽略最小/最大值)",
carto_flames_gasoline_title = "汽油效果预览",
carto_flames_gasoline = "",
carto_flames_volume = "火焰音效音量:",
carto_jokers_controls_buttons = "显示小丑牌区域控制按钮",
carto_jokers_controls_show_after = "当小丑牌数量超过:",
--carto_jokers_hide_keybind = "使用 Alt + 1 隐藏当前悬停的小丑牌",
carto_jokers_hide = "隐藏",
carto_jokers_show = "显示",
carto_jokers_zoom = "缩放",
carto_waiting_keybind = "等待输入中...",
carto_kb_hide_joker = "隐藏小丑牌",
carto_kb_toggle_tags = "切换标签栏可见性",
carto_kb_toggle_consumables = "切换消耗品栏可见性",
carto_kb_toggle_jokers = "切换小丑牌区域可见性",
carto_kb_toggle_jokers_buttons = "切换小丑牌控制按钮",
carto_blinds_info_setting = "显示盲注信息",
carto_blinds_info_current = "当前",
carto_blinds_info_extra = "历史",
carto_blinds_info_title = "Boss盲注历史",
}
}
}

View file

@ -0,0 +1,52 @@
[manifest]
version = "1.0.0"
dump_lua = true
priority = 69
# Add blinds info button to Run info menu
[[patches]]
[patches.pattern]
target = "functions/UI_definitions.lua"
match_indent = true
position = "at"
pattern = '''
{
label = localize('b_blinds'),
tab_definition_function = G.UIDEF.current_blinds,
},'''
payload = '''
{
label = localize('b_blinds'),
tab_definition_function =
Cartomancer.SETTINGS.blinds_info and
function()
return
{n=G.UIT.ROOT, config={align = "cm", colour = G.C.CLEAR, padding = 0}, nodes={
Cartomancer.create_vert_tabs(
{tabs = {
{
chosen = true,
label = localize('carto_blinds_info_current'),
tab_definition_function = G.UIDEF.current_blinds,
},
{
label = localize('carto_blinds_info_extra'),
tab_definition_function = Cartomancer.view_blinds_info,
},
}})
}}
end
or
G.UIDEF.current_blinds,
},
'''
# Support vertical buttons
[[patches]]
[patches.regex]
target = "functions/UI_definitions.lua"
match_indent = true
position = "after"
pattern = "func = button_pip,"
payload = "vert = args.vert,"

View file

@ -16,13 +16,11 @@ payload = '''
local min_ante = 1
local max_ante = 16
local spacing = 1 - 15*0.06
if G.GAME and G.GAME.round_resets and G.GAME.round_resets.ante then
local current_ante = G.GAME.round_resets.ante
if current_ante > 8 then
min_ante = current_ante - 8 + 1
max_ante = current_ante + 8
end
local current_ante = G.GAME and G.GAME.round_resets and G.GAME.round_resets.ante or 1
local ante_scaling = G.GAME and G.GAME.starting_params and G.GAME.starting_params.ante_scaling or 1
if current_ante > 8 then
min_ante = current_ante - 8 + 1
max_ante = current_ante + 8
end
'''
match_indent = true
@ -37,6 +35,26 @@ for i = min_ante, max_ante do
'''
match_indent = true
[[patches]]
[patches.regex]
target = "functions/UI_definitions.lua"
pattern = '''number_format(get_blind_amount(i))'''
position = "at"
payload = '''
number_format(get_blind_amount(i) * ante_scaling)
'''
match_indent = true
[[patches]]
[patches.pattern]
target = "functions/UI_definitions.lua"
pattern = '''ante_amounts[#ante_amounts+1] = {n=G.UIT.R, config={align = "cm", padding = 0.03}, nodes={'''
position = "at"
payload = '''
ante_amounts[#ante_amounts+1] = {n=G.UIT.R, config={align = "cm", padding = 0.03, colour = i == current_ante and Cartomancer.C.HALF_GRAY}, nodes={
'''
match_indent = true
[[patches]]
[patches.pattern]
target = "functions/UI_definitions.lua"

View file

@ -21,6 +21,6 @@ if self\.config\.type == \'hand\' and [^\n]*then'''
position = "after"
payload = '''
local max_cards_override = (Cartomancer.SETTINGS.dynamic_hand_align and self.config.temp_limit - #self.cards > 5) and #self.cards
local max_cards_override = (Cartomancer.SETTINGS.dynamic_hand_align and self.config.temp_limit - #self.cards > 5) and math.max(#self.cards, math.min(10, self.config.temp_limit))
'''

View file

@ -23,8 +23,31 @@ payload = "Cartomancer.handle_flames_volume($value)"
[[patches]]
[patches.pattern]
target = 'functions/button_callbacks.lua'
pattern = '''_F.timer = _F.timer + G.real_dt*(1 + _F.intensity*0.2)'''
position = 'at'
pattern = '''for k, v in pairs(G.ARGS.flame_handler) do'''
position = 'before'
payload = '''
_F.timer = Cartomancer.handle_flames_timer(_F.timer, _F.intensity)'''
Cartomancer.init_setting_flames()
'''
match_indent = true
[[patches]]
[patches.pattern]
target = 'functions/button_callbacks.lua'
pattern = '''_F.timer = _F.timer + G.real_dt*(1 + _F.intensity*0.2)'''
position = 'before'
payload = '''
if v.id == 'flame_chips_cart' or v.id == 'flame_mult_cart' then
_F.intensity = Cartomancer.get_flames_intensity(true)
end
'''
match_indent = true
[[patches]]
[patches.pattern]
target = 'functions/button_callbacks.lua'
pattern = '''e.config.object:get_pos_pixel()'''
position = 'after'
payload = '''
Cartomancer.align_object(e.config.object)
'''
match_indent = true

View file

@ -8,7 +8,7 @@ priority = 69
[[patches]]
[patches.pattern]
target = "cardarea.lua"
pattern = "local stay_flipped = G.GAME and G.GAME.blind and G.GAME.blind:stay_flipped(self, card)"
pattern = "local stay_flipped = G.GAME and G.GAME.blind and G.GAME.blind:stay_flipped(self, card*)"
position = "before"
payload = '''
if self == G.hand and not card.states.visible then
@ -20,14 +20,24 @@ match_indent = true
[[patches]]
[patches.pattern]
target = "functions/common_events.lua"
pattern = "local stay_flipped = G.GAME and G.GAME.blind and G.GAME.blind:stay_flipped(to, card)"
position = "before"
pattern = "if card then drawn = true end"
position = "after"
payload = '''
if card and to == G.hand and not card.states.visible then
card.states.visible = true
end'''
match_indent = true
# Fix drawing specific card staying invisible
[[patches]]
[patches.pattern]
target = "cardarea.lua"
pattern = "(self.config.type == 'deck' and self ~= G.deck) or"
position = "at"
payload = '''
(self.config.type == 'deck' and self ~= G.deck and not self.draw_uibox) or'''
match_indent = true
# Replace drawing deck pile
[[patches]]
[patches.pattern]
@ -57,6 +67,8 @@ payload = '''
local total_cards = #self.cards <= display_limit and #self.cards or display_limit -- limit height
local fixedX, fixedY, fixedR = nil, nil, nil
local height_multiplier = total_cards/((self == G.deck or self.draw_uibox) and 1 or 2)
for k, card in ipairs(self.cards) do
if card.facing == 'front' then card:flip() end
@ -67,8 +79,8 @@ payload = '''
card.T.r = fixedR -- rotation
card.states.visible = false
else
card.T.x = self.T.x + 0.5*(self.T.w - card.T.w) + self.shadow_parrallax.x*deck_height*(total_cards/(self == G.deck and 1 or 2) - k) + 0.9*self.shuffle_amt*(1 - k*0.01)*(k%2 == 1 and 1 or -0)
card.T.y = self.T.y + 0.5*(self.T.h - card.T.h) + self.shadow_parrallax.y*deck_height*(total_cards/(self == G.deck and 1 or 2) - k)
card.T.x = self.T.x + 0.5*(self.T.w - card.T.w) + self.shadow_parrallax.x*deck_height*(height_multiplier - k) + 0.9*self.shuffle_amt*(1 - k*0.01)*(k%2 == 1 and 1 or -0)
card.T.y = self.T.y + 0.5*(self.T.h - card.T.h) + self.shadow_parrallax.y*deck_height*(height_multiplier - k)
card.T.r = 0 + 0.3*self.shuffle_amt*(1 + k*0.05)*(k%2 == 1 and 1 or -0)
card.T.x = card.T.x + card.shadow_parrallax.x/30
card.states.visible = true

View file

@ -13,14 +13,15 @@ target = '=[SMODS _ "src/overrides.lua"]'
match_indent = true
pattern = '''
for k, v in ipairs(G.playing_cards) do
if v.base.suit then table.insert(SUITS[v.base.suit], v) end'''
if v.base.suit* then table.insert(SUITS[v.base.suit], v) end'''
position = "at"
payload = '''
local visible_suits_carto = Cartomancer.get_visible_suits_smods((view_deck_unplayed_only or unplayed_only), args and args.cycle_config.current_option or 1)
local SUITS_SORTED = Cartomancer.tablecopy(SUITS)
for k, v in ipairs(G.playing_cards) do
if v.base.suit then
local greyed
if unplayed_only and not ((v.area and v.area == G.deck) or v.ability.wheel_flipped) then
if (view_deck_unplayed_only or unplayed_only) and not ((v.area and v.area == G.deck) or v.ability.wheel_flipped) then
greyed = true
end
local card_string = v:cart_to_string {deck_view = true, greyed = true}
@ -34,21 +35,29 @@ for k, v in ipairs(G.playing_cards) do
-- Initiate stack
table.insert(SUITS_SORTED[v.base.suit], card_string)
local _scale = 0.7
local copy = copy_card(v, nil, _scale)
if visible_suits_carto[v.base.suit] then
local _scale = 0.7
local copy = BALIATRO and copy_card(v, nil, _scale, nil, nil, true)
or copy_card(v, nil, _scale)
copy.greyed = greyed
copy.stacked_quantity = 1
copy.greyed = greyed
copy.stacked_quantity = 1
SUITS[v.base.suit][card_string] = copy
SUITS[v.base.suit][card_string] = copy
else
SUITS[v.base.suit][card_string] = "uhhh don't ever crash from this code pretty please?"
end
else
-- Stack cards
local stacked_card = SUITS[v.base.suit][card_string]
stacked_card.stacked_quantity = stacked_card.stacked_quantity + 1
if type(stacked_card) == 'table' then -- it crashed from that code above :(
stacked_card.stacked_quantity = stacked_card.stacked_quantity + 1
end
end
end
'''
# BACKWARDS COMPATIBILITY FOR OLDER STEAMODDED
[[patches]]
[patches.pattern]
target = '=[SMODS _ "src/overrides.lua"]'
@ -58,23 +67,23 @@ position = "at"
payload = 'card_limit = #SUITS_SORTED[suit_map[j]],'
[[patches]]
[patches.pattern]
[patches.regex]
target = '=[SMODS _ "src/overrides.lua"]'
match_indent = true
pattern = '''
for i = 1, #SUITS[suit_map[j]] do
if SUITS[suit_map[j]][i] then
local greyed, _scale = nil, 0.7
if unplayed_only and not ((SUITS[suit_map[j]][i].area and SUITS[suit_map[j]][i].area == G.deck) or SUITS[suit_map[j]][i].ability.wheel_flipped) then
for i = 1\, \#SUITS\[suit_map\[j\]\] do
if SUITS\[suit_map\[j\]\]\[i\] then
local greyed\, _scale = nil\, 0\.7
if unplayed_only and not \(\(SUITS\[suit_map\[j\]\]\[i\]\.area and SUITS\[suit_map\[j\]\]\[i\]\.area == G\.deck\) or SUITS\[suit_map\[j\]\]\[i\]\.ability\.wheel_flipped\) then
greyed = true
end
local copy = copy_card(SUITS[suit_map[j]][i], nil, _scale)
copy.greyed = greyed
copy.T.x = view_deck.T.x + view_deck.T.w / 2
copy.T.y = view_deck.T.y
local copy = copy_card\(SUITS\[suit_map\[j\]\]\[i\]\, nil\, _scale[^\)\n]*\)
copy\.greyed = greyed
copy\.T\.x = view_deck\.T\.x \+ view_deck\.T\.w \/ 2
copy\.T\.y = view_deck\.T\.y
copy:hard_set_T()
view_deck:emplace(copy)
copy:hard_set_T\(\)
view_deck:emplace\(copy\)
end
end'''
position = "at"
@ -92,6 +101,80 @@ for i = 1, #SUITS_SORTED[suit_map[j]] do
end
'''
# FOR LATEST STEAMODDED
[[patches]]
[patches.pattern]
target = '=[SMODS _ "src/overrides.lua"]'
match_indent = true
pattern = 'card_limit = #SUITS[visible_suit[j]],'
position = "at"
payload = 'card_limit = #SUITS_SORTED[visible_suit[j]],'
[[patches]]
[patches.regex]
target = '=[SMODS _ "src/overrides.lua"]'
match_indent = true
pattern = '''
for i = 1\, \#SUITS\[visible_suit\[j\]\] do
if SUITS\[visible_suit\[j\]\]\[i\] then
local greyed\, _scale = nil\, 0\.7[\s\S]*
copy:hard_set_T\(\)
view_deck:emplace\(copy\)
end
end'''
position = "at"
payload = '''
-- -- -- -- -- -- -- -- -- --
for i = 1, #SUITS_SORTED[visible_suit[j]] do
local card_string = SUITS_SORTED[visible_suit[j]][i]
local card = SUITS[visible_suit[j]][card_string]
card.T.x = view_deck.T.x + view_deck.T.w/2
card.T.y = view_deck.T.y
card:create_quantity_display()
card:hard_set_T()
view_deck:emplace(card)
end
-- -- -- -- -- -- -- -- -- --'''
# FOR MODDED SUITS PAGES
[[patches]]
[patches.pattern]
target = '=[SMODS _ "src/overrides.lua"]'
match_indent = true
pattern = 'card_limit = #SUITS[visible_suit[j]],'
position = "at"
payload = 'card_limit = #SUITS_SORTED[visible_suit[j]],'
[[patches]]
[patches.regex]
target = '=[SMODS _ "src/overrides.lua"]'
match_indent = true
pattern = '''
for i = 1\, \#SUITS\[visible_suit\[j\]\] do
if SUITS\[visible_suit\[j\]\]\[i\] then
local greyed\, _scale = nil\, 0\.7[\s\S]*
copy:hard_set_T\(\)
view_deck:emplace\(copy\)
end
end'''
position = "at"
payload = '''
-- -- -- -- -- -- -- -- -- --
for i = 1, #SUITS_SORTED[visible_suit[j]] do
local card_string = SUITS_SORTED[visible_suit[j]][i]
local card = SUITS[visible_suit[j]][card_string]
card.T.x = view_deck.T.x + view_deck.T.w/2
card.T.y = view_deck.T.y
card:create_quantity_display()
card:hard_set_T()
view_deck:emplace(card)
end
-- -- -- -- -- -- -- -- -- --'''
[[patches]]
[patches.pattern]
target = '=[SMODS _ "src/overrides.lua"]'
@ -99,5 +182,5 @@ match_indent = true
pattern = ' modded and {n = G.UIT.R, config = {align = "cm"}, nodes = {'
position = "at"
payload = '''
not unplayed_only and Cartomancer.add_unique_count() or nil,
not (view_deck_unplayed_only or unplayed_only) and Cartomancer.add_unique_count() or nil,
modded and {n = G.UIT.R, config = {align = "cm"}, nodes = {'''

View file

@ -10,7 +10,7 @@ priority = 69
target = "game.lua"
pattern = "boot_timer('prep stage', 'splash prep',1)"
position = "before"
payload = "Cartomancer.load_mod_file('internal/localization.lua', 'localization')"
payload = "Cartomancer.load_mod_file('internal/localization.lua', 'cartomancer.localization')"
match_indent = true
# Add tab button to settings menu
@ -72,6 +72,14 @@ position = "at"
pattern = "self.config.chosen = true"
payload = "self.config.chosen = chosen_temp or true"
[[patches]]
[patches.pattern]
target = "functions/UI_definitions.lua"
match_indent = true
position = "before"
pattern = '''{n=G.UIT.C, config={align = "cm", minh = args.h,r = 0.1, minw = 0.8, colour = args.colour,shadow = true}, nodes={'''
payload = "not args.hide_value and "
# Add dynamic label support to UIBox_button
[[patches]]
[patches.pattern]

View file

@ -6,7 +6,7 @@
--- PRIORITY: 69
--- BADGE_COLOR: FFD700
--- DISPLAY_NAME: Cartomancer
--- VERSION: 4.12
--- VERSION: 4.16-smods-fix
----------------------------------------------
------------MOD CODE -------------------------

View file

@ -1 +0,0 @@
4.12-fix

2
Cryptid/.gitignore vendored
View file

@ -4,3 +4,5 @@
.lovelyignore
.idea/*
*.diff
*.code-workspace
.DS_Store

View file

@ -9,10 +9,10 @@
"priority": 114,
"badge_colour": "708b91",
"badge_text_colour": "FFFFFF",
"version": "0.5.12a",
"version": "0.5.13",
"dependencies": [
"Talisman (>=2.2.0a)",
"Steamodded (>=1.0.0~BETA-0827)"
"Talisman (>=2.6)",
"Steamodded (>=1.0.0~BETA-1016c)"
],
"conflicts": [
"AntePreview (>= 2.0.0~0c16a) (<<3.0.0)",

View file

@ -42,7 +42,7 @@ end
local function process_items(f, mod)
local ret = f()
if not ret.disabled then
if ret.init then
if ret.init and type(ret.init) == "function" then
ret:init()
end
if ret.items then
@ -73,12 +73,6 @@ local function process_items(f, mod)
if item.init then
item:init()
end
--[[if not item.gameset_config then
-- by default, disable on modest
item.gameset_config = {
modest = {disabled = true},
}
end--]]
if not Cryptid.object_registry[item.object_type] then
Cryptid.object_registry[item.object_type] = {}
end
@ -187,6 +181,7 @@ function SMODS.injectItems(...)
end
end
if G.PROFILES[G.SETTINGS.profile].all_unlocked then
G.PROFILES[G.SETTINGS.profile].cry_none2 = true
G.PROFILES[G.SETTINGS.profile].cry_none = (Cryptid.enabled("set_cry_poker_hand_stuff") == true)
end
G.P_CENTERS.j_stencil.immutable = true

Binary file not shown.

Before

Width:  |  Height:  |  Size: 57 KiB

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 175 KiB

After

Width:  |  Height:  |  Size: 170 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 160 KiB

After

Width:  |  Height:  |  Size: 201 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 212 KiB

After

Width:  |  Height:  |  Size: 214 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 148 KiB

After

Width:  |  Height:  |  Size: 145 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 9.9 KiB

After

Width:  |  Height:  |  Size: 15 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 70 KiB

After

Width:  |  Height:  |  Size: 79 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 246 KiB

After

Width:  |  Height:  |  Size: 209 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 210 KiB

After

Width:  |  Height:  |  Size: 290 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 268 KiB

After

Width:  |  Height:  |  Size: 266 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 207 KiB

After

Width:  |  Height:  |  Size: 182 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 15 KiB

After

Width:  |  Height:  |  Size: 24 KiB

View file

@ -423,7 +423,6 @@ local joke = {
boss = {
min = 1,
max = 10,
yes_orb = true,
},
atlas = "blinds",
order = 15,
@ -448,14 +447,15 @@ local joke = {
collection_loc_vars = function(self)
return { vars = { "8", localize("cry_joke_placeholder") } }
end,
cry_calc_ante_gain = function(self)
if to_big(G.GAME.chips) > to_big(G.GAME.blind.chips) * 2 then
if G.GAME.round_resets.ante == 1 then
G.GAME.cry_ach_conditions.the_jokes_on_you_triggered = true
calculate = function(self, blind, context)
if context.modify_ante and context.ante_end and not blind.disabled then
if to_big(G.GAME.chips) > to_big(G.GAME.blind.chips) * 2 then
if G.GAME.round_resets.ante == 1 then
G.GAME.cry_ach_conditions.the_jokes_on_you_triggered = true
end
return { modify = G.GAME.win_ante - G.GAME.round_resets.ante % G.GAME.win_ante }
end
return G.GAME.win_ante - G.GAME.round_resets.ante % G.GAME.win_ante
end
return 1
end,
}
local hammer = {
@ -604,7 +604,7 @@ local shackle = {
if G.GAME.modifiers.cry_force_edition and G.GAME.modifiers.cry_force_edition == "negative" then
return false
end
return #Cryptid.advanced_find_joker(nil, nil, "e_negative", nil, true) ~= 0
return #Cryptid.advanced_find_joker(nil, nil, "e_negative", nil, true, "j") ~= 0
end,
recalc_debuff = function(self, card, from_blind)
if
@ -931,18 +931,33 @@ local chromatic = {
boss = {
min = 1,
max = 666666,
yes_orb = true,
},
atlas = "blinds_two",
order = 25,
boss_colour = HEX("a34f98"),
cry_modify_score = function(self, score)
if math.floor(G.GAME.current_round.hands_played + 1) % 2 == 1 then
return score * -1
else
return score
set_blind = function(self, reset, silent)
G.GAME.chromatic_mod = 0
SMODS.set_scoring_calculation("cry_chromatic")
end,
defeat = function(self, silent)
G.GAME.chromatic_mod = nil
SMODS.set_scoring_calculation("multiply")
end,
disable = function(self, silent)
G.GAME.chromatic_mod = nil
SMODS.set_scoring_calculation("multiply")
end,
press_play = function(self)
if not G.GAME.blind.disabled then
G.GAME.blind.prepped = true
end
end,
drawn_to_hand = function(self)
if G.GAME.blind.prepped and not G.GAME.blind.disabled then
G.GAME.chromatic_mod = G.GAME.chromatic_mod + 1
end
G.GAME.blind.prepped = nil
end,
}
local landlord = {

View file

@ -9,6 +9,8 @@ local code = {
default = "c_cry_crash",
can_stack = true,
can_divide = true,
select_card = "consumeables",
select_button_text = "b_pull",
}
local code_digital_hallucinations_compat = {
@ -2248,7 +2250,10 @@ local hooked = {
end
var = var or ("[no joker found - " .. (card.ability.cry_hook_id or "nil") .. "]")
end
return { vars = { var or "hooked Joker" } }
return {
vars = { var or "hooked Joker" },
key = Cryptid.gameset_loc(self, { madness = "2" }),
}
end,
key = "cry_hooked",
no_sticker_sheet = true,
@ -2276,6 +2281,10 @@ local hooked = {
end
end
end
if context.end_of_round and context.individual and Cryptid.gameset(G.P_CENTERS.c_cry_hook) ~= "madness" then
card.ability.cry_hooked = nil
end
end,
}
-- ://Off By One
@ -3068,13 +3077,29 @@ local declare = {
local localize_ref = localize
function localize(first, second, ...)
if second == "poker_hands" then
if G and G.GAME and G.GAME.hands[first] and G.GAME.hands[first].declare_name then
return G.GAME.hands[first].declare_name
if G then
if G.GAME then
if G.GAME.hands then
if G.GAME.hands[first] then
if G.GAME.hands[first].declare_name then
return G.GAME.hands[first].declare_name
end
end
end
end
end
end
if second == "poker_hand_descriptions" then
if G and G.GAME and G.GAME.hands[first] and G.GAME.hands[first].suitless then
return localize_ref(first .. "_suitless", second, ...)
if G then
if G.GAME then
if G.GAME.hands then
if G.GAME.hands[first] then
if G.GAME.hands[first].suitless then
return localize_ref(first .. "_suitless", second, ...)
end
end
end
end
end
end
return localize_ref(first, second, ...)
@ -4669,14 +4694,15 @@ local source = {
local cards = Cryptid.get_highlighted_cards({ G.hand }, card, 1, card.ability.max_highlighted)
return #cards > 0 and #cards <= to_number(card.ability.max_highlighted)
end,
use = function(self, card, area, copier) --Good enough
use = function(self, card, area, copier)
local used_consumable = copier or card
local cards = Cryptid.get_highlighted_cards({ G.hand }, {}, 1, 1)
for i = 1, #cards do
local highlighted = cards[i]
G.E_MANAGER:add_event(Event({
func = function()
play_sound("tarot1")
highlighted:juice_up(0.3, 0.5)
used_consumable:juice_up(0.3, 0.5)
return true
end,
}))
@ -4685,7 +4711,7 @@ local source = {
delay = 0.1,
func = function()
if highlighted then
highlighted:set_seal("cry_green")
highlighted:set_seal("cry_green", nil, true)
end
return true
end,
@ -5327,47 +5353,6 @@ local code_cards = {
return {
name = "Code Cards",
init = function()
--Code from Betmma's Vouchers
G.FUNCS.can_reserve_card = function(e)
local c1 = e.config.ref_table
if
#G.consumeables.cards
< G.consumeables.config.card_limit + (Cryptid.safe_get(c1, "edition", "negative") and 1 or 0)
then
e.config.colour = G.C.GREEN
e.config.button = "reserve_card"
else
e.config.colour = G.C.UI.BACKGROUND_INACTIVE
e.config.button = nil
end
end
G.FUNCS.reserve_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)
G.consumeables:emplace(c1)
SMODS.calculate_context({ pull_card = true, card = 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
--some code to make typing more characters better
G.FUNCS.text_input_key = function(args)
args = args or {}

View file

@ -680,8 +680,9 @@ local antimatter = {
"set_cry_deck",
},
},
extra_gamesets = { "Custom" },
loc_vars = function(self, info_queue, center)
return { key = Cryptid.gameset_loc(self, { mainline = "balanced", modest = "balanced" }) }
return { key = Cryptid.gameset_loc(self, { mainline = "balanced", modest = "balanced", Custom = "custom" }) }
end,
name = "cry-Antimatter",
order = 76,
@ -698,30 +699,40 @@ local antimatter = {
},
pos = { x = 2, y = 0 },
calculate = function(self, back, context)
if context.context ~= "final_scoring_step" then
Cryptid.antimatter_trigger(self, context, Cryptid.gameset(G.P_CENTERS.b_cry_antimatter) == "madness")
else
return Cryptid.antimatter_trigger_final_scoring(
self,
context,
Cryptid.gameset(G.P_CENTERS.b_cry_antimatter) == "madness"
)
end
return Cryptid.antimatter_trigger(
self,
context,
Cryptid.gameset(G.P_CENTERS.b_cry_antimatter) == "madness",
Cryptid.gameset(G.P_CENTERS.b_cry_antimatter) == "Custom"
)
end,
apply = function(self)
Cryptid.antimatter_apply(Cryptid.gameset(G.P_CENTERS.b_cry_antimatter) == "madness")
Cryptid.antimatter_apply(
Cryptid.gameset(G.P_CENTERS.b_cry_antimatter) == "madness",
Cryptid.gameset(G.P_CENTERS.b_cry_antimatter) == "Custom"
)
end,
atlas = "atlasdeck",
init = function(self)
function Cryptid.antimatter_apply(skip)
function Cryptid.antimatter_apply(skip, custom)
local function check(back)
-- Check if deck was won on Gold stake or if gameset is madness
if
(Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", back, "wins", 8) or 0 ~= 0) or skip
then
-- Check for custom Antimatter Deck gameset
if not custom or Cryptid.safe_get(G, "SETTINGS", "custom_antimatter_deck", back) then
return true
end
end
return false
end
--Blue Deck
if
(Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_blue", "wins", 8) or 0 ~= 0) or skip
then
if check("b_blue") then
G.GAME.starting_params.hands = G.GAME.starting_params.hands + 1
end
--All Consumables (see Cryptid.get_antimatter_consumables)
local querty = Cryptid.get_antimatter_consumables(nil, skip)
local querty = Cryptid.get_antimatter_consumables(nil, skip, custom)
if #querty > 0 then
delay(0.4)
G.E_MANAGER:add_event(Event({
@ -738,33 +749,23 @@ local antimatter = {
}))
end
--Yellow Deck
if
(Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_yellow", "wins", 8) or 0) ~= 0
or skip
then
if check("b_yellow") then
G.GAME.starting_params.dollars = G.GAME.starting_params.dollars + 10
end
--Abandoned Deck
if
(Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_abandoned", "wins", 8) or 0) ~= 0
or skip
then
if check("b_abandoned") then
G.GAME.starting_params.no_faces = true
end
--Ghost Deck
if
(Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_ghost", "wins", 8) or 0) ~= 0 or skip
then
if check("b_ghost") then
G.GAME.spectral_rate = 2
end
-- Red Deck
if
(Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_red", "wins", 8) or 0) ~= 0 or skip
then
if check("b_red") then
G.GAME.starting_params.discards = G.GAME.starting_params.discards + 1
end
-- All Decks with Vouchers (see Cryptid.get_antimatter_vouchers)
local vouchers = Cryptid.get_antimatter_vouchers(nil, skip)
local vouchers = Cryptid.get_antimatter_vouchers(nil, skip, custom)
if #vouchers > 0 then
for k, v in pairs(vouchers) do
if G.P_CENTERS[v] then
@ -780,10 +781,7 @@ local antimatter = {
end
end
-- Checkered Deck
if
(Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_checkered", "wins", 8) or 0) ~= 0
or skip
then
if check("b_checkered") then
G.E_MANAGER:add_event(Event({
func = function()
for k, v in pairs(G.playing_cards) do
@ -799,38 +797,24 @@ local antimatter = {
}))
end
-- Erratic Deck
if
(Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_erratic", "wins", 8) or 0) ~= 0
or skip
then
if check("b_erratic") then
G.GAME.starting_params.erratic_suits_and_ranks = true
end
-- Black Deck
if
(Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_black", "wins", 8) or 0) ~= 0 or skip
then
if check("b_black") then
G.GAME.starting_params.joker_slots = G.GAME.starting_params.joker_slots + 1
end
-- Painted Deck
if
(Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_painted", "wins", 8) or 0) ~= 0
or skip
then
if check("b_painted") then
G.GAME.starting_params.hand_size = G.GAME.starting_params.hand_size + 2
end
-- Green Deck
if
(Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_green", "wins", 8) or 0) ~= 0 or skip
then
if check("b_green") then
G.GAME.modifiers.money_per_hand = (G.GAME.modifiers.money_per_hand or 1) + 1
G.GAME.modifiers.money_per_discard = (G.GAME.modifiers.money_per_discard or 0) + 1
end
-- Spooky Deck
if
(Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_spooky", "wins", 8) or 0)
~= 0
or skip
then
if check("b_cry_spooky") then
G.GAME.modifiers.cry_spooky = true
G.GAME.modifiers.cry_curse_rate = 0
if Cryptid.enabled("j_cry_chocolate_dice") == true then
@ -848,31 +832,16 @@ local antimatter = {
end
end
-- Deck of Equilibrium
if
(
Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_equilibrium", "wins", 8)
or 0
)
~= 0
or skip
then
if check("b_cry_equilibrium") then
G.GAME.modifiers.cry_equilibrium = true
end
-- Misprint Deck
if
(Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_misprint", "wins", 8) or 0)
~= 0
or skip
then
if check("b_cry_misprint") then
G.GAME.modifiers.cry_misprint_min = 1
G.GAME.modifiers.cry_misprint_max = 10
end
-- Infinite Deck
if
(Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_infinite", "wins", 8) or 0)
~= 0
or skip
then
if check("b_cry_infinite") then
G.GAME.infinitedeck = true
G.E_MANAGER:add_event(Event({
trigger = "after",
@ -886,11 +855,7 @@ local antimatter = {
G.GAME.starting_params.hand_size = G.GAME.starting_params.hand_size + 1
end
-- Wormhole deck
if
(Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_wormhole", "wins", 8) or 0)
~= 0
or skip
then
if check("b_cry_wormhole") then
G.GAME.modifiers.cry_negative_rate = 20
if Cryptid.enabled("set_cry_exotic") == true then
@ -909,26 +874,11 @@ local antimatter = {
end
end
-- Redeemed deck
if
(Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_redeemed", "wins", 8) or 0)
~= 0
or skip
then
if check("b_cry_redeemed") then
G.GAME.modifiers.cry_redeemed = true
end
--[[
G.GAME.bosses_used["bl_goad"] = 1e308
G.GAME.bosses_used["bl_window"] = 1e308
G.GAME.bosses_used["bl_head"] = 1e308
G.GAME.bosses_used["bl_club"] = 1e308
]]
--
--Legendary Deck
if
(Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_legendary", "wins", 8) or 0)
~= 0
or skip
then
if check("b_cry_legendary") then
G.E_MANAGER:add_event(Event({
func = function()
if G.jokers then
@ -942,11 +892,7 @@ local antimatter = {
}))
end
--Encoded Deck
if
(Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_encoded", "wins", 8) or 0)
~= 0
or skip
then
if check("b_cry_encoded") then
G.E_MANAGER:add_event(Event({
func = function()
if G.jokers then
@ -976,25 +922,26 @@ local antimatter = {
}))
end
--Beige Deck
if
(Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_beige", "wins", 8) or 0) ~= 0
or skip
then
if check("b_cry_beige") then
G.GAME.modifiers.cry_common_value_quad = true
end
end
function Cryptid.antimatter_trigger_final_scoring(self, context, skip)
function Cryptid.antimatter_trigger(self, context, skip, custom)
local function check(back)
-- Check if deck was won on Gold stake or if gameset is madness
if
(Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", back, "wins", 8) or 0 ~= 0) or skip
then
-- Check for custom Antimatter Deck gameset
if not custom or Cryptid.safe_get(G, "SETTINGS", "custom_antimatter_deck", back) then
return true
end
end
return false
end
if context.context == "final_scoring_step" then
--Critical Deck
if
(
Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_critical", "wins", 8)
or 0
)
~= 0
or skip
then
if check("b_cry_critical") then
if
SMODS.pseudorandom_probability(
self,
@ -1025,11 +972,7 @@ local antimatter = {
end
--Plasma Deck
local tot = context.chips + context.mult
if
(Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_plasma", "wins", 8) or 0)
~= 0
or skip
then
if check("b_plasma") then
context.chips = math.floor(tot / 2)
context.mult = math.floor(tot / 2)
update_hand_text({ delay = 0 }, { mult = context.mult, chips = context.chips })
@ -1081,65 +1024,31 @@ local antimatter = {
delay(0.6)
end
return context.chips, context.mult
end
end
function Cryptid.antimatter_trigger(self, context, skip)
if context.context == "eval" and Cryptid.safe_get(G.GAME, "last_blind", "boss") then
--Glowing Deck
if
(
Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_glowing", "wins", 8)
or 0
)
~= 0
or skip
then
if check("b_cry_glowing") then
for i = 1, #G.jokers.cards do
Cryptid.manipulate(G.jokers.cards[i], { value = 1.25 })
end
end
--Legendary Deck
if G.jokers then
if
(
Cryptid.safe_get(
G.PROFILES,
G.SETTINGS.profile,
"deck_usage",
"b_cry_legendary",
"wins",
8
) or 0
if check("b_cry_legendary") then
if #G.jokers.cards < G.jokers.config.card_limit then
if
SMODS.pseudorandom_probability(
self,
"cry_legendary",
1,
self.config.cry_legendary_rate,
"Antimatter Deck"
)
~= 0
or skip
then
if #G.jokers.cards < G.jokers.config.card_limit then
if
SMODS.pseudorandom_probability(
self,
"cry_legendary",
1,
self.config.cry_legendary_rate,
"Antimatter Deck"
)
then
local card = create_card("Joker", G.jokers, true, 4, nil, nil, nil, "")
card:add_to_deck()
card:start_materialize()
G.jokers:emplace(card)
return true
else
card_eval_status_text(
G.jokers,
"jokers",
nil,
nil,
nil,
{ message = localize("k_nope_ex"), colour = G.C.RARITY[4] }
)
end
then
local card = create_card("Joker", G.jokers, true, 4, nil, nil, nil, "")
card:add_to_deck()
card:start_materialize()
G.jokers:emplace(card)
return true
else
card_eval_status_text(
G.jokers,
@ -1147,17 +1056,22 @@ local antimatter = {
nil,
nil,
nil,
{ message = localize("k_no_room_ex"), colour = G.C.RARITY[4] }
{ message = localize("k_nope_ex"), colour = G.C.RARITY[4] }
)
end
else
card_eval_status_text(
G.jokers,
"jokers",
nil,
nil,
nil,
{ message = localize("k_no_room_ex"), colour = G.C.RARITY[4] }
)
end
end
--Anaglyph Deck
if
(Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_anaglyph", "wins", 8) or 0)
~= 0
or skip
then
if check("b_anaglyph") then
G.E_MANAGER:add_event(Event({
func = function()
add_tag(Tag("tag_double"))
@ -1168,13 +1082,15 @@ local antimatter = {
}))
end
end
return context.chips, context.mult
end
function Cryptid.get_antimatter_vouchers(voucher_table, skip)
function Cryptid.get_antimatter_vouchers(voucher_table, skip, custom)
-- Create a table or use one that is passed into the function
if not voucher_table or type(voucher_table) ~= "table" then
voucher_table = {}
end
-- Add Vouchers into the table by key
-- Ignores duplicates
local function already_exists(t, voucher)
for _, v in ipairs(t) do
if v == voucher then
@ -1188,54 +1104,61 @@ local antimatter = {
table.insert(t, voucher)
end
end
local function check(back)
-- Check if deck was won on Gold stake or if gameset is madness
if
(Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", back, "wins", 8) or 0 ~= 0) or skip
then
-- Check for custom Antimatter Deck gameset
if not custom or Cryptid.safe_get(G, "SETTINGS", "custom_antimatter_deck", back) then
return true
end
end
return false
end
--Nebula Deck
if
(Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_nebula", "wins", 8) or 0 ~= 0)
or skip
then
if check("b_nebula") then
Add_voucher_to_the_table(voucher_table, "v_telescope")
end
-- Magic Deck
if
(Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_magic", "wins", 8) or 0 ~= 0) or skip
then
if check("b_magic") then
Add_voucher_to_the_table(voucher_table, "v_crystal_ball")
end
-- Zodiac Deck
if
(Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_zodiac", "wins", 8) or 0 ~= 0)
or skip
then
if check("b_zodiac") then
Add_voucher_to_the_table(voucher_table, "v_tarot_merchant")
Add_voucher_to_the_table(voucher_table, "v_planet_merchant")
Add_voucher_to_the_table(voucher_table, "v_overstock_norm")
end
-- Deck Of Equilibrium
if
(
Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_equilibrium", "wins", 8)
or 0 ~= 0
) or skip
then
if check("b_cry_equilibrium") then
Add_voucher_to_the_table(voucher_table, "v_overstock_norm")
Add_voucher_to_the_table(voucher_table, "v_overstock_plus")
end
return voucher_table
end
--Does this even need to be a function idk
function Cryptid.get_antimatter_consumables(consumable_table, skip)
function Cryptid.get_antimatter_consumables(consumable_table, skip, custom)
local function check(back)
-- Check if deck was won on Gold stake or if gameset is madness
if
(Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", back, "wins", 8) or 0 ~= 0) or skip
then
-- Check for custom Antimatter Deck gameset
if not custom or Cryptid.safe_get(G, "SETTINGS", "custom_antimatter_deck", back) then
return true
end
end
return false
end
if not consumable_table or type(consumable_table) ~= "table" then
consumable_table = {}
end
if
(Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_magic", "wins", 8) or 0 ~= 0) or skip
then
if check("b_magic") then
table.insert(consumable_table, "c_fool")
table.insert(consumable_table, "c_fool")
end
if
(Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_ghost", "wins", 8) or 0 ~= 0) or skip
then
if check("b_ghost") then
table.insert(consumable_table, "c_hex")
end
return consumable_table
@ -1257,8 +1180,29 @@ local antimatter = {
end,
}
--[[
Customize your Antimatter Deck here for the TRUE Sandbox experience!
How to use Custom Antimatter Deck:
1: Add decks to the antimatter_custom table with the format deck_key = true
2: Win a run on Gold Stake for each deck
3: Go to Mods > Cryptid > Thematic Sets > Decks > Antimatter Deck
4: Switch Gameset to "Custom"
]]
--
local antimatter_custom = {
["b_red"] = true,
["b_blue"] = true,
["b_yellow"] = true,
["b_green"] = true,
["b_black"] = true,
}
return {
name = "Misc. Decks",
init = function()
G.SETTINGS.custom_antimatter_deck = antimatter_custom
end,
items = {
very_fair,
equilibrium,

View file

@ -1009,7 +1009,6 @@ local number_blocks = {
-- Double Scale
-- Scaling jokers scale quadratically
-- Most of the code for this lies in Card:cry_double_scale_calc in lib/calculate.lua
local double_scale = {
object_type = "Joker",
name = "cry-Double Scale",
@ -1037,27 +1036,29 @@ local double_scale = {
immutable = true,
atlas = "atlasepic",
calc_scaling = function(self, card, other, current_scaling, current_scalar, args)
if not G.GAME.cryptid_base_scales then
G.GAME.cryptid_base_scales = {}
-- store original scaling rate
if not other.ability.cry_scaling_info then
other.ability.cry_scaling_info = {
[args.scalar_value] = current_scalar,
}
elseif not other.ability.cry_scaling_info[args.scalar_value] then
other.ability.cry_scaling_info[args.scalar_value] = current_scalar
end
if not G.GAME.cryptid_base_scales[other.config.center.key] then
G.GAME.cryptid_base_scales[other.config.center.key] = {}
end
if not G.GAME.cryptid_base_scales[other.config.center.key][args.scalar_value] then
G.GAME.cryptid_base_scales[other.config.center.key][args.scalar_value] = current_scalar
end
local true_base = G.GAME.cryptid_base_scales[other.config.center.key][args.scalar_value]
local orig_scale_scale = current_scaling
local original_scalar = other.ability.cry_scaling_info[args.scalar_value]
-- joker scaling stuff
if Cryptid.gameset(self) == "exp_modest" then
return {
scalar_value = lenient_bignum(to_big(true_base) * 2),
scalar_value = lenient_bignum(to_big(original_scalar) * 2),
message = localize("k_upgrade_ex"),
}
else
args.scalar_table[args.scalar_value] = current_scalar + original_scalar
return {
message = localize("k_upgrade_ex"),
}
end
args.scalar_table[args.scalar_value] = new_scale
return {
message = localize("k_upgrade_ex"),
}
end,
cry_credits = {
idea = {
@ -1572,7 +1573,7 @@ local bonusjoker = {
card.ability.immutable.check = lenient_bignum(card.ability.immutable.check + 1)
end
G.jokers.config.card_limit = lenient_bignum(
G.jokers.config.card_limit + cmath.min(card.ability.extra.add, card.ability.immutable.max)
G.jokers.config.card_limit + math.min(card.ability.extra.add, card.ability.immutable.max)
)
else
if not context.blueprint then

View file

@ -585,9 +585,21 @@ local effarcire = {
demicoloncompat = true,
calculate = function(self, card, context)
if not context.blueprint and not context.retrigger_joker or context.forcetrigger then
if context.first_hand_drawn or context.forcetrigger then
G.FUNCS.draw_from_deck_to_hand(#G.deck.cards)
return nil, true
if context.first_hand_drawn or context.forcetrigger and not G.GAME.effarcire_buffer then
G.GAME.effarcire_buffer = true
G.E_MANAGER:add_event(Event({
func = function()
G.FUNCS.draw_from_deck_to_hand(#G.deck.cards)
G.E_MANAGER:add_event(Event({
func = function()
G.GAME.effarcire_buffer = nil
save_run()
return true
end,
}))
return true
end,
}))
elseif G.hand.config.card_limit < 1 then
G.hand.config.card_limit = 1
end
@ -645,8 +657,7 @@ local crustulum = {
ref_table = card.ability.extra,
ref_value = "chips",
scalar_value = "chip_mod",
message_key = "a_chips",
colour = G.C.CHIPS,
message_colour = G.C.CHIPS,
})
return nil, true
end
@ -665,8 +676,7 @@ local crustulum = {
ref_table = card.ability.extra,
ref_value = "chips",
scalar_value = "chip_mod",
message_key = "a_chips",
colour = G.C.CHIPS,
message_colour = G.C.CHIPS,
})
return {
chip_mod = lenient_bignum(card.ability.extra.chips),
@ -819,41 +829,45 @@ local scalae = {
end
end,
calc_scaling = function(self, card, other, current_scaling, current_scalar, args)
if other.ability.name ~= "cry-Scalae" then
if not G.GAME.cryptid_base_scales then
G.GAME.cryptid_base_scales = {}
end
if not G.GAME.cryptid_base_scales[other.config.center.key] then
G.GAME.cryptid_base_scales[other.config.center.key] = {}
end
if not G.GAME.cryptid_base_scales[other.config.center.key][args.scalar_value] then
G.GAME.cryptid_base_scales[other.config.center.key][args.scalar_value] = current_scalar
end
local true_base = G.GAME.cryptid_base_scales[other.config.center.key][args.scalar_value]
local orig_scale_scale = current_scaling
local new_scale = lenient_bignum(
to_big(true_base)
* (
(
1
+ (
(to_big(orig_scale_scale) / to_big(true_base))
^ (to_big(1) / to_big(card.ability.extra.scale))
)
) ^ to_big(card.ability.extra.scale)
)
)
if not Cryptid.is_card_big(other) and to_big(new_scale) >= to_big(1e300) then
new_scale = 1e300
end
return {
scalar_value = new_scale,
message = localize("k_upgrade_ex"),
}
-- checks if the scaled joker is also a scalae
-- if so, return nothing
if other.config.center.key == self.key then
return
end
-- store original scaling rate
if not other.ability.cry_scaling_info then
other.ability.cry_scaling_info = {
[args.scalar_value] = current_scalar,
}
elseif not other.ability.cry_scaling_info[args.scalar_value] then
other.ability.cry_scaling_info[args.scalar_value] = current_scalar
end
-- joker scaling stuff
local original_scalar = other.ability.cry_scaling_info[args.scalar_value]
local new_scale = lenient_bignum(
to_big(original_scalar)
* (
(
1
+ (
(to_big(current_scaling) / to_big(original_scalar))
^ (to_big(1) / to_big(card.ability.extra.scale))
)
) ^ to_big(card.ability.extra.scale)
)
)
args.scalar_table[args.scalar_value] = new_scale
return {
message = localize("k_upgrade_ex"),
}
end,
loc_vars = function(self, info_queue, card)
local example = { 2, 3, 4 }
-- this is literally just straight up wrong atm, scalae doesn't work like this
for i = 1, #example do
example[i] = to_big(example[i]) ^ (card.ability.extra.scale + 1)
end
@ -1353,8 +1367,8 @@ local verisimile = {
object_type = "Joker",
name = "cry-verisimile",
key = "verisimile",
pos = { x = 0, y = 1 },
soul_pos = { x = 1, y = 1, extra = { x = 2, y = 1 } },
pos = { x = 6, y = 5 },
soul_pos = { x = 8, y = 5, extra = { x = 7, y = 5 } },
config = { extra = { xmult = 1 } },
rarity = "cry_exotic",
cost = 50,
@ -1365,12 +1379,12 @@ local verisimile = {
demicoloncompat = true,
blueprint_compat = true,
atlas = "placeholders",
atlas = "atlasexotic",
loc_vars = function(self, info_queue, center)
return { vars = { number_format(center.ability.extra.xmult) } }
end,
calculate = function(self, card, context)
if context.pseudorandom_result and context.result then
if context.pseudorandom_result and context.result and not context.blueprint then
-- implementation that doesn't use SMODS.scale_card; use if scale_card causes weird or unexpected behavior
--[[
card.ability.extra.xmult = lenient_bignum(card.ability.extra.xmult + context.denominator)
@ -1393,15 +1407,16 @@ local verisimile = {
ref_value = "xmult",
scalar_table = context,
scalar_value = "denominator",
scaling_message = {
message = localize({
type = "variable",
key = "a_xmult",
vars = { number_format(card.ability.extra.xmult) },
}),
},
scaling_message = {},
})
return {
message = localize({
type = "variable",
key = "a_xmult",
vars = { number_format(card.ability.extra.xmult) },
}),
}
-- forcetriggers won't scale non verisimile, because how much would you scale it by
elseif context.joker_main or context.forcetrigger then
return {
@ -1657,6 +1672,197 @@ local formidiulosus = {
code = { "Foegro" },
},
}
local caeruleum = {
dependencies = {
items = {
"c_cry_gateway",
"set_cry_exotic",
},
},
object_type = "Joker",
name = "cry-Caeruleum",
key = "caeruleum",
config = {},
init = function(self)
local scie = SMODS.calculate_individual_effect
function SMODS.calculate_individual_effect(effect, scored_card, key, amount, from_edition, ...)
local card = effect.card or scored_card
local caeruleum_messages = {}
if Cryptid.safe_get(card, "ability", "cry_caeruleum") then
for i = 1, #G.jokers.cards do
if G.jokers.cards[i] == card then
for _, b in ipairs(card.ability.cry_caeruleum) do
local caeruleum = G.jokers.cards[i + (b and 1 or -1)]
local was_key_changed, new_key, op = Cryptid.caeruleum_new_key(key)
-- change the key!
if was_key_changed then
key = new_key
-- no _mod returns because i hate them
effect.remove_default_message = (key:sub(-4) == "_mod")
-- create a new message for caeruleum to display
local chipsMessageKeys = {
"a_chips",
"a_xchips",
"a_powchips",
}
-- these get run through card_eval_status_text AFTER the normal calculate_individual_effect runs
caeruleum_messages[#caeruleum_messages + 1] = {
caeruleum,
"extra",
nil,
percent,
nil,
{
message = localize({
type = "variable",
key = chipsMessageKeys[op],
vars = {
number_format(amount),
},
}),
focus = caeruleum,
sound = "chips1",
},
}
end
end
end
end
end
-- run normal function
local ret = scie(effect, scored_card, key, amount, from_edition, ...)
-- display caeruleum messages
if #caeruleum_messages > 0 then
for _, msg in ipairs(caeruleum_messages) do
card_eval_status_text(unpack(msg))
end
end
-- return result
return ret
end
end,
pos = { x = 3, y = 6 },
rarity = "cry_exotic",
order = 519,
cost = 50,
blueprint_compat = false,
demicoloncompat = false,
atlas = "atlasexotic",
soul_pos = { x = 5, y = 6, extra = { x = 4, y = 6 } },
loc_vars = function(self, info_queue, center)
return {
vars = {},
}
end,
calculate = function(self, card, context)
-- used to "mark" jokers to be affected by caeruleum
if context.before and context.cardarea == G.jokers then
local left_joker = nil
local right_joker = nil
for i = 1, #G.jokers.cards do
if G.jokers.cards[i] == card then
left_joker = G.jokers.cards[i - 1]
right_joker = G.jokers.cards[i + 1]
end
end
-- allows caeruleum to stack
-- boolean value is true if the joker was to the left of caeruleum (so caeruleum is to the right of it)
if left_joker and left_joker.config.center.key ~= "j_cry_caeruleum" then
left_joker.ability.cry_caeruleum = left_joker.ability.cry_caeruleum or {}
left_joker.ability.cry_caeruleum[#left_joker.ability.cry_caeruleum + 1] = true
end
if right_joker and right_joker.config.center.key ~= "j_cry_caeruleum" then
right_joker.ability.cry_caeruleum = right_joker.ability.cry_caeruleum or {}
right_joker.ability.cry_caeruleum[#right_joker.ability.cry_caeruleum + 1] = false
end
end
if context.after and context.cardarea == G.jokers then
-- reset this on every joker just to avoid weird bugs
for i = 1, #G.jokers.cards do
G.jokers.cards[i].ability.cry_caeruleum = nil
end
end
end,
cry_credits = {
idea = { "HexaCryonic" },
art = { "Tatteredlurker" },
code = { "InvalidOS" },
},
}
local chipsOperators = {
{
keys = {
"eq_chips",
"Eqchips_mod",
"EQchips_mod",
-- TARGET: add =chips modifiers (or succession if you're silly)
},
operation = 0,
},
{
keys = {
"chips",
"h_chips",
"chip_mod",
},
operation = 1,
},
{
keys = {
"xchips",
"x_chips",
"Xchip_mod",
},
operation = 2,
},
}
local chipsReturnOperators = {
"chips",
"xchips",
"echips",
}
--- Handles Caeruleum's operator increase.
--- @param key string The key being checked.
--- @return boolean was_key_changed Whether the key was actually changed.
--- @return string new_key The new key if it was changed, or old one if it wasn't.
--- @return integer? op The new operator's position in the hyperoperation sequence. `nil` if the key wasn't changed.\n(1 is addition, 2 is multiplication, 3 is exponentiation)
function Cryptid.caeruleum_new_key(key)
if not SMODS.Calculation_Controls.chips or not key then
return false, key
end
for _, op in ipairs(chipsOperators) do
for _, key2 in pairs(op.keys) do
if key == key2 then
local op2 = math.max(1, math.min(op.operation + 1, 3))
local new_key = chipsReturnOperators[op2]
return true, new_key, op2
end
end
end
return false, key
end
local items = {
gateway,
iterum,
@ -1676,10 +1882,11 @@ local items = {
facile,
gemino,
energia,
--verisimile, WHY IS THIS AN EXOTIC????????????????????
verisimile, -- it's an exotic because it's fucking peak
--rescribere, [NEEDS REFACTOR]
duplicare,
formidiulosus, -- see tenebris
caeruleum,
}
return {
name = "Exotic Jokers",

View file

@ -1983,6 +1983,7 @@ local gold_edition = {
(
context.post_trigger -- for when on jonklers
and context.other_card == card
and Cryptid.isNonRollProbabilityContext(context.other_context)
)
or (
context.main_scoring -- for when on playing cards

View file

@ -80,7 +80,10 @@ local dropshot = {
ref_value = "x_mult",
scalar_value = "Xmult_mod",
message_key = "a_xmult",
message_colour = G.C.RED,
message_colour = G.C.MULT,
operation = function(ref_table, ref_value, initial, scaling)
ref_table[ref_value] = initial + scaling * cards
end,
})
return nil, true
end
@ -1875,11 +1878,11 @@ local sus = {
#king_of_hearts_cards > 0 and pseudorandom_element(king_of_hearts_cards, pseudoseed("cry_sus2"))
) or chosen_card
local _c = copy_card(to_copy, nil, nil, G.playing_card)
_c:start_materialize()
_c:add_to_deck()
G.deck.config.card_limit = G.deck.config.card_limit + 1
table.insert(G.playing_cards, _c)
G.hand:emplace(_c)
G.play:emplace(_c)
_c:start_materialize()
playing_card_joker_effects({ _c })
return true
end,
@ -1891,7 +1894,14 @@ local sus = {
G.GAME.sus_cards = destroyed_cards
end
-- SMODS.calculate_context({ remove_playing_cards = true, removed = G.GAME.sus_cards })
return { message = localize("cry_sus_ex") }
return {
message = localize("cry_sus_ex"),
func = function()
-- this was moved to here because of a timing issue (no bugs/odd behaviour, but looked weird)
draw_card(G.play, G.deck, 90, "up", nil)
playing_card_joker_effects({ _c })
end,
}
end
end,
cry_credits = {
@ -1939,16 +1949,20 @@ local fspinner = {
demicoloncompat = true,
calculate = function(self, card, context)
if context.before and not context.blueprint then
local play_more_than = (G.GAME.hands[context.scoring_name].played or 0)
local play_more_than, yes = (G.GAME.hands[context.scoring_name].played or 0), false
for k, v in pairs(G.GAME.hands) do
if k ~= context.scoring_name and v.played >= play_more_than and v.visible then
SMODS.scale_card(card, {
ref_table = card.ability.extra,
ref_value = "chips",
scalar_value = "chip_mod",
})
yes = true
end
end
if yes then
SMODS.scale_card(card, {
ref_table = card.ability.extra,
ref_value = "chips",
scalar_value = "chip_mod",
message_colour = G.C.CHIPS,
})
end
end
if context.joker_main and (to_big(card.ability.extra.chips) > to_big(0)) then
return {
@ -1966,7 +1980,7 @@ local fspinner = {
ref_value = "chips",
scalar_value = "chip_mod",
message_key = "a_chips",
message_colour = G.C.BLUE,
message_colour = G.C.CHIPS,
})
return {
chip_mod = lenient_bignum(card.ability.extra.chips),
@ -2927,7 +2941,8 @@ local unjust_dagger = {
end
if
context.setting_blind
and not (context.blueprint_card or self).getting_sliced
and not card.getting_sliced
and not context.blueprint
and my_pos
and G.jokers.cards[my_pos - 1]
and not SMODS.is_eternal(G.jokers.cards[my_pos - 1])
@ -2942,8 +2957,6 @@ local unjust_dagger = {
G.E_MANAGER:add_event(Event({
func = function()
G.GAME.joker_buffer = 0
card.ability.extra.x_mult =
lenient_bignum(to_big(card.ability.extra.x_mult) + sliced_card.sell_cost * 0.2)
card:juice_up(0.8, 0.8)
sliced_card:start_dissolve({ HEX("57ecab") }, nil, 1.6)
play_sound("slice1", 0.96 + math.random() * 0.08)
@ -2953,43 +2966,64 @@ local unjust_dagger = {
SMODS.scale_card(card, {
ref_table = card.ability.extra,
ref_value = "x_mult",
scalar_table = {
sell_cost = sliced_card.sell_cost * 0.2,
},
scalar_table = sliced_card,
scalar_value = "sell_cost",
message_key = "a_xmult",
message_colour = G.C.RED,
operation = function(ref_table, ref_value, initial, scaling)
ref_table[ref_value] = initial + 0.2 * scaling
end,
scaling_message = {
message = localize({
type = "variable",
key = "a_xmult",
vars = { card.ability.extra.x_mult + 0.2 * sliced_card.sell_cost },
}),
colour = G.C.MULT,
no_juice = true,
},
})
return nil, true
end
if context.forcetrigger and my_pos and G.jokers.cards[my_pos - 1] then
local sliced_card = G.jokers.cards[my_pos - 1]
sliced_card.getting_sliced = true
if sliced_card.config.center.rarity == "cry_exotic" then
check_for_unlock({ type = "what_have_you_done" })
if context.forcetrigger then
if
my_pos
and G.jokers.cards[my_pos - 1]
and not SMODS.is_eternal(G.jokers.cards[my_pos - 1])
and not G.jokers.cards[my_pos - 1].getting_sliced
then
local sliced_card = G.jokers.cards[my_pos - 1]
sliced_card.getting_sliced = true
if sliced_card.config.center.rarity == "cry_exotic" then
check_for_unlock({ type = "what_have_you_done" })
end
G.GAME.joker_buffer = G.GAME.joker_buffer - 1
G.E_MANAGER:add_event(Event({
func = function()
G.GAME.joker_buffer = 0
card:juice_up(0.8, 0.8)
sliced_card:start_dissolve({ HEX("57ecab") }, nil, 1.6)
play_sound("slice1", 0.96 + math.random() * 0.08)
return true
end,
}))
SMODS.scale_card(card, {
ref_table = card.ability.extra,
ref_value = "x_mult",
scalar_table = sliced_card,
scalar_value = "sell_cost",
operation = function(ref_table, ref_value, initial, scaling)
ref_table[ref_value] = initial + 0.2 * scaling
end,
scaling_message = {
message = localize({
type = "variable",
key = "a_xmult",
vars = { card.ability.extra.x_mult + 0.2 * sliced_card.sell_cost },
}),
colour = G.C.MULT,
no_juice = true,
},
})
end
G.GAME.joker_buffer = G.GAME.joker_buffer - 1
G.E_MANAGER:add_event(Event({
func = function()
G.GAME.joker_buffer = 0
card.ability.extra.x_mult =
lenient_bignum(to_big(card.ability.extra.x_mult) + sliced_card.sell_cost * 0.2)
card:juice_up(0.8, 0.8)
sliced_card:start_dissolve({ HEX("57ecab") }, nil, 1.6)
play_sound("slice1", 0.96 + math.random() * 0.08)
return true
end,
}))
SMODS.scale_card(card, {
ref_table = card.ability.extra,
ref_value = "x_mult",
scalar_table = {
sell_cost = sliced_card.sell_cost * 0.2,
},
scalar_value = "sell_cost",
message_key = "a_xmult",
message_colour = G.C.RED,
})
return {
Xmult_mod = lenient_bignum(card.ability.extra.x_mult),
}
@ -3048,7 +3082,8 @@ local monkey_dagger = {
end
if
context.setting_blind
and not (context.blueprint_card or self).getting_sliced
and not card.getting_sliced
and not context.blueprint
and my_pos
and G.jokers.cards[my_pos - 1]
and not SMODS.is_eternal(G.jokers.cards[my_pos - 1])
@ -3063,51 +3098,6 @@ local monkey_dagger = {
G.E_MANAGER:add_event(Event({
func = function()
G.GAME.joker_buffer = 0
card.ability.extra.chips =
lenient_bignum(to_big(card.ability.extra.chips) + sliced_card.sell_cost * 10)
card:juice_up(0.8, 0.8)
sliced_card:start_dissolve({ HEX("57ecab") }, nil, 1.6)
play_sound("slice1", 0.96 + math.random() * 0.08)
return true
end,
}))
local msg = SMODS.scale_card(card, {
ref_table = card.ability.extra,
ref_value = "x_mult",
scalar_table = {
sell_cost = sliced_card.sell_cost * 10,
},
scalar_value = "sell_cost",
})
if not msg or type(msg) == "string" then
card_eval_status_text(card, "extra", nil, nil, nil, {
message = msg or localize({
type = "variable",
key = "a_chips",
vars = {
number_format(
lenient_bignum(to_big(card.ability.extra.chips) + 10 * sliced_card.sell_cost)
),
},
}),
colour = G.C.CHIPS,
no_juice = true,
})
end
return nil, true
end
if context.forcetrigger and my_pos and G.jokers.cards[my_pos - 1] then
local sliced_card = G.jokers.cards[my_pos - 1]
sliced_card.getting_sliced = true
if sliced_card.config.center.rarity == "cry_exotic" then
check_for_unlock({ type = "what_have_you_done" })
end
G.GAME.joker_buffer = G.GAME.joker_buffer - 1
G.E_MANAGER:add_event(Event({
func = function()
G.GAME.joker_buffer = 0
card.ability.extra.chips =
lenient_bignum(to_big(card.ability.extra.chips) + sliced_card.sell_cost * 10)
card:juice_up(0.8, 0.8)
sliced_card:start_dissolve({ HEX("57ecab") }, nil, 1.6)
play_sound("slice1", 0.96 + math.random() * 0.08)
@ -3117,13 +3107,64 @@ local monkey_dagger = {
SMODS.scale_card(card, {
ref_table = card.ability.extra,
ref_value = "chips",
scalar_table = {
sell_cost = sliced_card.sell_cost * 10,
},
scalar_table = sliced_card,
scalar_value = "sell_cost",
message_key = "a_chips",
message_colour = G.C.BLUE,
operation = function(ref_table, ref_value, initial, scaling)
ref_table[ref_value] = initial + 10 * scaling
end,
scaling_message = {
message = localize({
type = "variable",
key = "a_chips",
vars = { card.ability.extra.chips + 10 * sliced_card.sell_cost },
}),
colour = G.C.CHIPS,
no_juice = true,
},
})
return nil, true
end
if context.forcetrigger then
if
my_pos
and G.jokers.cards[my_pos - 1]
and not SMODS.is_eternal(G.jokers.cards[my_pos - 1])
and not G.jokers.cards[my_pos - 1].getting_sliced
then
local sliced_card = G.jokers.cards[my_pos - 1]
sliced_card.getting_sliced = true
if sliced_card.config.center.rarity == "cry_exotic" then
check_for_unlock({ type = "what_have_you_done" })
end
G.GAME.joker_buffer = G.GAME.joker_buffer - 1
G.E_MANAGER:add_event(Event({
func = function()
G.GAME.joker_buffer = 0
card:juice_up(0.8, 0.8)
sliced_card:start_dissolve({ HEX("57ecab") }, nil, 1.6)
play_sound("slice1", 0.96 + math.random() * 0.08)
return true
end,
}))
SMODS.scale_card(card, {
ref_table = card.ability.extra,
ref_value = "chips",
scalar_table = sliced_card,
scalar_value = "sell_cost",
operation = function(ref_table, ref_value, initial, scaling)
ref_table[ref_value] = initial + 10 * scaling
end,
scaling_message = {
message = localize({
type = "variable",
key = "a_chips",
vars = { card.ability.extra.chips + 10 * sliced_card.sell_cost },
}),
colour = G.C.CHIPS,
no_juice = true,
},
})
end
return {
chip_mod = lenient_bignum(card.ability.extra.chips),
}
@ -3182,7 +3223,8 @@ local pirate_dagger = {
end
if
context.setting_blind
and not (context.blueprint_card or self).getting_sliced
and not card.getting_sliced
and not context.blueprint
and my_pos
and G.jokers.cards[my_pos + 1]
and not SMODS.is_eternal(G.jokers.cards[my_pos + 1])
@ -3197,8 +3239,6 @@ local pirate_dagger = {
G.E_MANAGER:add_event(Event({
func = function()
G.GAME.joker_buffer = 0
card.ability.extra.x_chips =
lenient_bignum(to_big(card.ability.extra.x_chips) + sliced_card.sell_cost * 0.25)
card:juice_up(0.8, 0.8)
sliced_card:start_dissolve({ HEX("57ecab") }, nil, 1.6)
play_sound("slice1", 0.96 + math.random() * 0.08)
@ -3208,45 +3248,71 @@ local pirate_dagger = {
SMODS.scale_card(card, {
ref_table = card.ability.extra,
ref_value = "x_chips",
scalar_table = {
sell_cost = sliced_card.sell_cost * 0.25,
},
scalar_table = sliced_card,
scalar_value = "sell_cost",
message_key = "a_xchips",
message_colour = G.C.BLUE,
operation = function(ref_table, ref_value, initial, scaling)
ref_table[ref_value] = initial + 0.25 * scaling
end,
scaling_message = {
message = localize({
type = "variable",
key = "a_xchips",
vars = { card.ability.extra.x_chips + 0.25 * sliced_card.sell_cost },
}),
colour = G.C.CHIPS,
no_juice = true,
},
})
return nil, true
end
if context.forcetrigger and my_pos and G.jokers.cards[my_pos + 1] then
local sliced_card = G.jokers.cards[my_pos + 1]
sliced_card.getting_sliced = true
if sliced_card.config.center.rarity == "cry_exotic" then
check_for_unlock({ type = "what_have_you_done" })
if context.forcetrigger then
if
my_pos
and G.jokers.cards[my_pos + 1]
and not SMODS.is_eternal(G.jokers.cards[my_pos + 1])
and not G.jokers.cards[my_pos + 1].getting_sliced
then
local sliced_card = G.jokers.cards[my_pos + 1]
sliced_card.getting_sliced = true
if sliced_card.config.center.rarity == "cry_exotic" then
check_for_unlock({ type = "what_have_you_done" })
end
G.GAME.joker_buffer = G.GAME.joker_buffer - 1
G.E_MANAGER:add_event(Event({
func = function()
G.GAME.joker_buffer = 0
card:juice_up(0.8, 0.8)
sliced_card:start_dissolve({ HEX("57ecab") }, nil, 1.6)
play_sound("slice1", 0.96 + math.random() * 0.08)
return true
end,
}))
SMODS.scale_card(card, {
ref_table = card.ability.extra,
ref_value = "x_chips",
scalar_table = sliced_card,
scalar_value = "sell_cost",
operation = function(ref_table, ref_value, initial, scaling)
ref_table[ref_value] = initial + 0.25 * scaling
end,
scaling_message = {
message = localize({
type = "variable",
key = "a_xchips",
vars = { card.ability.extra.x_chips + 0.25 * sliced_card.sell_cost },
}),
colour = G.C.CHIPS,
no_juice = true,
},
})
end
G.GAME.joker_buffer = G.GAME.joker_buffer - 1
G.E_MANAGER:add_event(Event({
func = function()
G.GAME.joker_buffer = 0
card.ability.extra.x_chips =
lenient_bignum(to_big(card.ability.extra.x_chips) + sliced_card.sell_cost * 0.25)
card:juice_up(0.8, 0.8)
sliced_card:start_dissolve({ HEX("57ecab") }, nil, 1.6)
play_sound("slice1", 0.96 + math.random() * 0.08)
return true
end,
}))
SMODS.scale_card(card, {
ref_table = card.ability.extra,
ref_value = "x_chips",
scalar_table = {
sell_cost = sliced_card.sell_cost * 0.25,
},
scalar_value = "sell_cost",
message_key = "a_xchips",
message_colour = G.C.BLUE,
})
return {
Xchip_mod = lenient_bignum(card.ability.extra.x_chips),
message = localize({
type = "variable",
key = "a_xchips",
vars = { number_format(card.ability.extra.x_chips) },
}),
}
end
end,
@ -3520,6 +3586,7 @@ local spaceglobe = {
ref_table = card.ability.extra,
ref_value = "x_chips",
scalar_value = "Xchipmod",
message_colour = G.C.CHIPS,
})
end
end
@ -3540,7 +3607,7 @@ local spaceglobe = {
ref_value = "x_chips",
scalar_value = "Xchipmod",
message_key = "a_xchips",
message_colour = G.C.BLUE,
message_colour = G.C.CHIPS,
})
return {
Xchip_mod = lenient_bignum(card.ability.extra.x_chips),
@ -9564,7 +9631,7 @@ local pity_prize = {
local tag_key
repeat
tag_key = get_next_tag_key("cry_pity_prize")
until tag_key ~= "tag_boss" --I saw pickle not generating boss tags because it apparently causes issues, so I did the same here
until tag_key ~= "tag_boss" and tag_key ~= "tag_cry_gambler" --I saw pickle not generating boss tags because it apparently causes issues, so I did the same here
local tag = Cryptid.get_next_tag()
if tag then
@ -9572,6 +9639,7 @@ local pity_prize = {
end
-- this is my first time seeing repeat... wtf
-- ^^ using repeat...until in this economy? absurd!
local tag = Tag(tag_key)
tag.ability.shiny = Cryptid.is_shiny()
if tag.name == "Orbital Tag" then
@ -9886,6 +9954,9 @@ local zooble = {
ref_table = card.ability.extra,
ref_value = "mult",
scalar_value = "a_mult",
operation = function(ref_table, ref_value, initial, scaling)
ref_table[ref_value] = initial + scaling * #unique_ranks
end,
})
end
end
@ -9977,6 +10048,14 @@ local lebaron_james = {
}
end
end
elseif
context.end_of_round
and not context.repetition
and not context.individual
and not context.blueprint
and not context.retrigger_joker
then
card.ability.immutable.added_h = 0
end
end,
cry_credits = {
@ -10604,7 +10683,6 @@ local pizza_slice = {
dependencies = {
items = {
"set_cry_misc_joker",
"j_cry_pizza",
},
},
name = "cry-pizza_slice",
@ -10817,6 +10895,165 @@ local poor_joker = { -- +1 to all listed probabilities for the highest cat tag l
end,
}
-- Broken Sync Catalyst
-- Swaps 10% of chips with 10% of mult
local broken_sync = {
cry_credits = {
idea = {
"arnideus",
},
art = {
"Tatteredlurker",
},
code = {
"InvalidOS",
},
},
object_type = "Joker",
dependencies = {
items = {
"set_cry_misc_joker",
},
},
name = "cry-broken_sync_catalyst",
key = "broken_sync_catalyst",
atlas = "atlastwo",
pos = { x = 6, y = 3 },
rarity = 3,
cost = 8,
order = 145,
demicoloncompat = true,
blueprint_compat = true,
config = { extra = { portion = 0.1 } },
loc_vars = function(self, info_queue, card)
return { vars = { number_format(Cryptid.clamp(card.ability.extra.portion * 100, 0, 100)) } }
end,
calculate = function(self, card, context)
if context.joker_main or context.forcetrigger then
return {
cry_broken_swap = card.ability.extra.portion,
}
end
end,
}
local thal = {
cry_credits = {
idea = {
"ODanK8604",
},
art = {
"Pangaea",
},
code = {
"candycanearter",
},
},
object_type = "Joker",
name = "cry-thalia",
key = "thalia",
atlas = "atlasthree",
pos = { x = 0, y = 8 },
soul_pos = { x = 1, y = 8 },
config = { extra = { xmgain = 1 } },
rarity = 4,
cost = 20,
order = 145,
demicoloncompat = true,
blueprint_compat = true,
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.xmgain, self:calc_xmult(card) } }
end,
calc_xmult = function(self, card)
if not (G.jokers and G.jokers.cards) then
return 1
end
local seen = {}
for _, c in ipairs(G.jokers.cards) do
local rarity = c.config.center.rarity
if not seen[rarity] then
seen[rarity] = 1
end
end
-- because lua generates keys automatically we ahve to do this
local n = 0
for _, r in pairs(seen) do
if r then
n = n + 1
end
end
-- n pick 2, or n!/(n-2)!, simplified bc of how lua is
local bonus = (n * (n - 1)) / 2
if bonus < 1 then
return 1
end
return bonus * card.ability.extra.xmgain
end,
calculate = function(self, card, context)
if context.joker_main or context.force_trigger then
return { xmult = self:calc_xmult(card) }
end
end,
}
local keychange = {
cry_credits = {
idea = {
"arnideus",
},
art = {
"Tatteredlurker",
},
code = {
"candycanearter",
},
},
object_type = "Joker",
name = "cry-keychange",
key = "keychange",
atlas = "placeholders",
pos = { x = 1, y = 1 },
config = { extra = { xm = 1, xmgain = 0.25 } },
rarity = 2,
cost = 5,
order = 145,
demicoloncompat = true,
blueprint_compat = true,
loc_vars = function(self, info_queue, card)
return { vars = { card.ability.extra.xmgain, card.ability.extra.xm } }
end,
calculate = function(self, card, context)
if
context.before
and G.GAME.hands[context.scoring_name]
and G.GAME.hands[context.scoring_name].played_this_round < 2
then
SMODS.scale_card(card, {
ref_table = card.ability.extra,
ref_value = "xm",
scalar_value = "mgain",
})
end
if context.joker_main or context.force_trigger then
return { xmult = card.ability.extra.xm }
end
if context.end_of_round and context.main_eval and not context.blueprint then
card.ability.extra.xm = 1
return { message = localize("k_reset") }
end
end,
}
local miscitems = {
jimball_sprite,
dropshot,
@ -10948,6 +11185,9 @@ local miscitems = {
paved_joker,
fading_joker,
poor_joker,
broken_sync,
thal,
keychange,
}
return {

View file

@ -261,6 +261,17 @@ local universe = {
badges[1] = create_badge(localize("k_planet_universe"), get_type_colour(self or card.config, card), nil, 1.2)
end,
loc_vars = function(self, info_queue, center)
--[[if Cryptid.safe_get(G, "GAME", "used_vouchers", "v_observatory") then
-- won't show up for some fucking reason
info_queue[#info_queue + 1] = {
key = "o_cry_universe",
set = "Other",
specific_vars = {
G.P_CENTERS.v_observatory.config.extra,
localize("cry_WholeDeck"),
}
}
end]]
return {
vars = {
localize("cry_WholeDeck"),
@ -277,6 +288,30 @@ local universe = {
}
end,
generate_ui = 0,
-- give emult instead of xmult
calculate = function(self, card, context)
if context.cry_observatory and card.ability.consumeable.hand_type == context.scoring_name then
local value = context.cry_observatory.ability.extra
-- because it's ((n^a)^a)^a
if Overflow then
value = value ^ to_big(card:getQty())
end
return {
message = localize({
type = "variable",
key = "a_powmult",
vars = {
number_format(context.cry_observatory.ability.extra),
},
}),
Emult_mod = lenient_bignum(context.cry_observatory.ability.extra),
colour = G.C.DARK_EDITION,
}
end
end,
demicoloncompat = true,
force_use = function(self, card, area)
card:use_consumeable(area)
@ -635,9 +670,9 @@ local planetlua = {
end
end
end,
calculate = function(self, card, context) --Observatory effect: Variable XMult
if G.GAME.used_vouchers.v_observatory and context.joker_main then
pseudorandom("cry_googol_play")
calculate = function(self, card, context)
if context.cry_observatory then
-- pseudorandom("cry_googol_play")
local aaa = pseudorandom("mstar")
local limit = Card.get_gameset(card) == "modest" and 2 or 1e100
local formula = aaa + (0.07 * (aaa ^ 5 / (1 - aaa ^ 2)))
@ -653,8 +688,7 @@ local planetlua = {
end
]]
return {
message = localize({ type = "variable", key = "a_xmult", vars = { value } }),
Xmult_mod = value,
xmult = value,
}
end
end,
@ -760,8 +794,8 @@ local nstar = {
end,
}))
end,
calculate = function(self, card, context) --Observatory effect: X0.1 mult for each neutron star used this run
if G.GAME.used_vouchers.v_observatory and G.GAME.neutronstarsusedinthisrun > 0 and context.joker_main then
calculate = function(self, card, context)
if context.cry_observatory and G.GAME.neutronstarsusedinthisrun > 0 then
local value = G.GAME.neutronstarsusedinthisrun
if Overflow then
value = value ^ to_big(card:getQty())
@ -847,94 +881,10 @@ local sunplanet = {
return true
end,
use = function(self, card, area, copier)
local used_consumable = copier or card
G.GAME.sunlevel = G.GAME.sunlevel + 1
G.GAME.sunnumber.modest = G.GAME.sunnumber.modest + card.ability.extra.modest
G.GAME.sunnumber.not_modest = G.GAME.sunnumber.not_modest + card.ability.extra.not_modest
delay(0.4)
update_hand_text(
{ sound = "button", volume = 0.7, pitch = 0.8, delay = 0.3 },
{ handname = localize("cry_asc_hands"), chips = "...", mult = "...", level = to_big(G.GAME.sunlevel - 1) }
)
delay(1.0)
G.E_MANAGER:add_event(Event({
trigger = "after",
delay = 0.2,
func = function()
play_sound("tarot1")
ease_colour(G.C.UI_CHIPS, copy_table(G.C.GOLD), 0.1)
ease_colour(G.C.UI_MULT, copy_table(G.C.GOLD), 0.1)
Cryptid.pulse_flame(0.01, G.GAME.sunlevel)
used_consumable:juice_up(0.8, 0.5)
G.E_MANAGER:add_event(Event({
trigger = "after",
blockable = false,
blocking = false,
delay = 1.2,
func = function()
ease_colour(G.C.UI_CHIPS, G.C.BLUE, 1)
ease_colour(G.C.UI_MULT, G.C.RED, 1)
return true
end,
}))
return true
end,
}))
update_hand_text(
{ sound = "button", volume = 0.7, pitch = 0.9, delay = 0 },
{ level = to_big(G.GAME.sunlevel) }
)
delay(2.6)
update_hand_text(
{ sound = "button", volume = 0.7, pitch = 1.1, delay = 0 },
{ mult = 0, chips = 0, handname = "", level = "" }
)
Cryptid.asc_level_up(card, copier, 1)
end,
bulk_use = function(self, card, area, copier, number)
local used_consumable = copier or card
G.GAME.sunlevel = G.GAME.sunlevel + number
G.GAME.sunnumber.modest = G.GAME.sunnumber.modest + number * card.ability.extra.modest
G.GAME.sunnumber.not_modest = G.GAME.sunnumber.not_modest + number * card.ability.extra.not_modest
delay(0.4)
update_hand_text({ sound = "button", volume = 0.7, pitch = 0.8, delay = 0.3 }, {
handname = localize("cry_asc_hands"),
chips = "...",
mult = "...",
level = to_big(G.GAME.sunlevel - number),
})
delay(1.0)
G.E_MANAGER:add_event(Event({
trigger = "after",
delay = 0.2,
func = function()
play_sound("tarot1")
ease_colour(G.C.UI_CHIPS, copy_table(G.C.GOLD), 0.1)
ease_colour(G.C.UI_MULT, copy_table(G.C.GOLD), 0.1)
Cryptid.pulse_flame(0.01, G.GAME.sunlevel)
used_consumable:juice_up(0.8, 0.5)
G.E_MANAGER:add_event(Event({
trigger = "after",
blockable = false,
blocking = false,
delay = 1.2,
func = function()
ease_colour(G.C.UI_CHIPS, G.C.BLUE, 1)
ease_colour(G.C.UI_MULT, G.C.RED, 1)
return true
end,
}))
return true
end,
}))
update_hand_text(
{ sound = "button", volume = 0.7, pitch = 0.9, delay = 0 },
{ level = to_big(G.GAME.sunlevel) }
)
delay(2.6)
update_hand_text(
{ sound = "button", volume = 0.7, pitch = 1.1, delay = 0 },
{ mult = 0, chips = 0, handname = "", level = "" }
)
Cryptid.asc_level_up(card, copier, number)
end,
loc_vars = function(self, info_queue, center)
local levelone = Cryptid.safe_get(G, "GAME", "sunlevel") or 1
@ -962,11 +912,15 @@ local sunplanet = {
}
end
if Cryptid.safe_get(G, "GAME", "used_vouchers", "v_observatory") then
local super_entropic_local_variable_that_stores_the_amount_of_suns = #find_joker("cry-sunplanet")
+ #find_joker("cry-Perkele")
local observatory_power = 0
if #find_joker("cry-sunplanet") == 1 then
if super_entropic_local_variable_that_stores_the_amount_of_suns == 1 then
observatory_power = 1
elseif #find_joker("cry-sunplanet") > 1 then
observatory_power = Cryptid.funny_log(2, #find_joker("cry-sunplanet") + 1)
elseif super_entropic_local_variable_that_stores_the_amount_of_suns > 1 then
observatory_power =
Cryptid.funny_log(2, super_entropic_local_variable_that_stores_the_amount_of_suns + 1)
end
info_queue[#info_queue + 1] = { key = "o_sunplanet", set = "Other", specific_vars = { observatory_power } }
end
@ -1071,22 +1025,18 @@ local ruutu = {
end,
calculate = function(self, card, context)
if
G.GAME.used_vouchers.v_observatory
and context.joker_main
context.cry_observatory
and (
context.scoring_name == "High Card"
or context.scoring_name == "Pair"
or context.scoring_name == "Two Pair"
)
then
local value = G.P_CENTERS.v_observatory.config.extra
local value = context.cry_observatory.ability.extra
if Overflow then
value = value ^ to_big(card:getQty())
end
return {
message = localize({ type = "variable", key = "a_xmult", vars = { value } }),
Xmult_mod = value,
}
return { xmult = value }
end
end,
demicoloncompat = true,
@ -1160,22 +1110,18 @@ local risti = {
end,
calculate = function(self, card, context)
if
G.GAME.used_vouchers.v_observatory
and context.joker_main
context.cry_observatory
and (
context.scoring_name == "Three of a Kind"
or context.scoring_name == "Straight"
or context.scoring_name == "Flush"
)
then
local value = G.P_CENTERS.v_observatory.config.extra
local value = context.cry_observatory.ability.extra
if Overflow then
value = value ^ to_big(card:getQty())
end
return {
message = localize({ type = "variable", key = "a_xmult", vars = { value } }),
Xmult_mod = value,
}
return { xmult = value }
end
end,
demicoloncompat = true,
@ -1249,22 +1195,18 @@ local hertta = {
end,
calculate = function(self, card, context)
if
G.GAME.used_vouchers.v_observatory
and context.joker_main
context.cry_observatory
and (
context.scoring_name == "Full House"
or context.scoring_name == "Four of a Kind"
or context.scoring_name == "Straight Flush"
)
then
local value = G.P_CENTERS.v_observatory.config.extra
local value = context.cry_observatory.ability.extra
if Overflow then
value = value ^ to_big(card:getQty())
end
return {
message = localize({ type = "variable", key = "a_xmult", vars = { value } }),
Xmult_mod = value,
}
return { xmult = value }
end
end,
demicoloncompat = true,
@ -1338,22 +1280,18 @@ local pata = {
end,
calculate = function(self, card, context)
if
G.GAME.used_vouchers.v_observatory
and context.joker_main
context.cry_observatory
and (
context.scoring_name == "Five of a Kind"
or context.scoring_name == "Flush House"
or context.scoring_name == "Flush Five"
)
then
local value = G.P_CENTERS.v_observatory.config.extra
local value = context.cry_observatory.ability.extra
if Overflow then
value = value ^ to_big(card:getQty())
end
return {
message = localize({ type = "variable", key = "a_xmult", vars = { value } }),
Xmult_mod = value,
}
return { xmult = value }
end
end,
demicoloncompat = true,
@ -1435,22 +1373,18 @@ local kaikki = {
end,
calculate = function(self, card, context)
if
G.GAME.used_vouchers.v_observatory
and context.joker_main
context.cry_observatory
and (
context.scoring_name == "cry_Bulwark"
or context.scoring_name == "cry_Clusterfuck"
or context.scoring_name == "cry_UltPair"
)
then
local value = G.P_CENTERS.v_observatory.config.extra
local value = context.cry_observatory.ability.extra
if Overflow then
value = value ^ to_big(card:getQty())
end
return {
message = localize({ type = "variable", key = "a_xmult", vars = { value } }),
Xmult_mod = value,
}
return { xmult = value }
end
end,
demicoloncompat = true,
@ -1458,7 +1392,164 @@ local kaikki = {
card:use_consumeable(area)
end,
}
-- order 166 reserved for suit planet of TEFD, None and Sol
-- Perkele
-- Upgrades None, TEFD, and Ascended Hands
local perkele = {
cry_credits = {
idea = {
"cassknows",
},
art = {
"cassknows",
"Lil Mr. Slipstream",
},
code = {
"InvalidOS",
},
},
dependencies = {
items = {
"set_cry_planet",
"set_cry_poker_hand_stuff",
},
},
object_type = "Consumable",
set = "Planet",
name = "cry-Perkele",
key = "perkele",
pos = { x = 2, y = 6 },
config = {
-- avoids having to mirror tweaks to sol on perkele
extra = sunplanet.config.extra,
-- "cry_asc_hands" is not a hand so don't include it here
hand_types = { "cry_None", "cry_WholeDeck" },
level_types = { "cry_None", "cry_WholeDeck", "cry_asc_hands" },
softlock = true,
},
cost = 4,
-- idk if this even matters
aurinko = true,
atlas = "atlasnotjokers",
order = 166,
can_use = function(self, card)
return true
end,
loc_vars = function(self, info_queue, center)
local levels = {
G.GAME.hands["cry_None"].level or 1,
G.GAME.hands["cry_WholeDeck"].level or 1,
Cryptid.safe_get(G, "GAME", "sunlevel") or 1,
}
local colours = {}
for i, lvl in ipairs(levels) do
colours[i] = to_big(lvl) == to_big(1) and G.C.UI.TEXT_DARK or G.C.HAND_LEVELS[to_number(math.min(7, lvl))]
end
-- don't want to entirely rework ascension power just for one consumable
local modest = Cryptid.gameset(G.P_CENTERS.c_cry_sunplanet) == "modest"
if G.STAGE == G.STAGES.RUN then
local current_power = Cryptid.safe_get(G, "GAME", "current_round", "current_hand", "cry_asc_num")
or Cryptid.calculate_ascension_power(
nil,
nil,
nil,
G.GAME.used_vouchers.v_cry_hyperspacetether,
G.GAME.bonus_asc_power
)
local multiplier = modest and 1 + ((0.25 + G.GAME.sunnumber.modest) * current_power)
or (1.25 + G.GAME.sunnumber.not_modest) ^ current_power
info_queue[#info_queue + 1] = {
key = "asc_misc" .. (modest and 2 or ""),
set = "Other",
specific_vars = {
current_power,
multiplier,
modest and (G.GAME.sunnumber.modest + 0.25) or (G.GAME.sunnumber.not_modest + 1.25),
},
}
end
if Cryptid.safe_get(G, "GAME", "used_vouchers", "v_observatory") then
local super_entropic_local_variable_that_stores_the_amount_of_suns = #find_joker("cry-sunplanet")
+ #find_joker("cry-Perkele")
local observatory_power = 0
if super_entropic_local_variable_that_stores_the_amount_of_suns == 1 then
observatory_power = 1
elseif super_entropic_local_variable_that_stores_the_amount_of_suns > 1 then
observatory_power =
Cryptid.funny_log(2, super_entropic_local_variable_that_stores_the_amount_of_suns + 1)
end
info_queue[#info_queue + 1] = {
key = "o_perkele",
set = "Other",
specific_vars = {
observatory_power,
G.P_CENTERS.v_observatory.config.extra,
localize("cry_None", "poker_hands"),
localize("cry_WholeDeck", "poker_hands"),
},
}
end
return {
vars = {
localize("cry_None", "poker_hands"),
localize("cry_WholeDeck", "poker_hands"),
localize("cry_asc_hands"),
levels[1],
levels[2],
levels[3],
(Cryptid.safe_get(G, "GAME", "sunnumber", modest == "modest" and "modest" or "not_modest") or 0) + 0.25,
colours = colours,
},
}
end,
use = function(self, card, area, copier)
Cryptid.suit_level_up(card, copier, 1, card.config.center.config.level_types)
end,
bulk_use = function(self, card, area, copier, number)
Cryptid.suit_level_up(card, copier, number, card.config.center.config.level_types)
end,
calculate = function(self, card, context)
if context.cry_observatory then
local value = context.cry_observatory.ability.extra
if Overflow then
value = value ^ to_big(card:getQty())
end
if context.scoring_name == "cry_None" then
return { xmult = value }
elseif context.scoring_name == "cry_WholeDeck" then
return {
message = localize({
type = "variable",
key = "a_powmult",
vars = {
number_format(context.cry_observatory.ability.extra),
},
}),
Emult_mod = lenient_bignum(context.cry_observatory.ability.extra),
colour = G.C.DARK_EDITION,
}
end
end
end,
demicoloncompat = true,
force_use = function(self, card, area)
card:use_consumeable(area)
end,
in_pool = function(self)
return (G.GAME.cry_asc_played and G.GAME.cry_asc_played > 0)
or SMODS.is_poker_hand_visible("cry_WholeDeck")
or SMODS.is_poker_hand_visible("cry_None")
end,
}
local voxel = {
cry_credits = {
idea = {
@ -1564,22 +1655,18 @@ local voxel = {
end,
calculate = function(self, card, context)
if
G.GAME.used_vouchers.v_observatory
and context.joker_main
context.cry_observatory
and (
context.scoring_name == "cry_Declare0"
or context.scoring_name == "cry_Declare1"
or context.scoring_name == "cry_Declare2"
)
then
local value = G.P_CENTERS.v_observatory.config.extra
local value = context.cry_observatory.ability.extra
if Overflow then
value = value ^ to_big(card:getQty())
end
return {
message = localize({ type = "variable", key = "a_xmult", vars = { value } }),
Xmult_mod = value,
}
return { xmult = value }
end
end,
demicoloncompat = true,
@ -1588,6 +1675,63 @@ local voxel = {
end,
}
function Cryptid.asc_level_up(card, copier, number, message)
local number = number or 1
local used_consumable = copier or card
G.GAME.sunlevel = G.GAME.sunlevel + number
G.GAME.sunnumber.modest = G.GAME.sunnumber.modest + number * card.ability.extra.modest
G.GAME.sunnumber.not_modest = G.GAME.sunnumber.not_modest + number * card.ability.extra.not_modest
if message then
SMODS.calculate_effect({
message = localize("k_level_up_ex"),
}, card)
end
if not Cryptid.safe_get(Talisman, "config_file", "disable_anims") then
delay(0.4)
update_hand_text({ sound = "button", volume = 0.7, pitch = 0.8, delay = 0.3 }, {
handname = localize("cry_asc_hands"),
chips = "...",
mult = "...",
level = to_big(G.GAME.sunlevel - number),
})
delay(1.0)
G.E_MANAGER:add_event(Event({
trigger = "after",
delay = 0.2,
func = function()
play_sound("tarot1")
ease_colour(G.C.UI_CHIPS, copy_table(G.C.GOLD), 0.1)
ease_colour(G.C.UI_MULT, copy_table(G.C.GOLD), 0.1)
Cryptid.pulse_flame(0.01, G.GAME.sunlevel)
used_consumable:juice_up(0.8, 0.5)
G.E_MANAGER:add_event(Event({
trigger = "after",
blockable = false,
blocking = false,
delay = 1.2,
func = function()
ease_colour(G.C.UI_CHIPS, G.C.BLUE, 1)
ease_colour(G.C.UI_MULT, G.C.RED, 1)
return true
end,
}))
return true
end,
}))
update_hand_text(
{ sound = "button", volume = 0.7, pitch = 0.9, delay = 0 },
{ level = to_big(G.GAME.sunlevel) }
)
delay(2.6)
update_hand_text(
{ sound = "button", volume = 0.7, pitch = 1.1, delay = 0 },
{ mult = 0, chips = 0, handname = "", level = "" }
)
end
end
function Cryptid.suit_level_up(card, copier, number, poker_hands, message)
local used_consumable = copier or card
if not number then
@ -1597,23 +1741,16 @@ function Cryptid.suit_level_up(card, copier, number, poker_hands, message)
poker_hands = { "Two Pair", "Straight Flush" }
end
if message then
card_eval_status_text(
card,
"extra",
nil,
nil,
nil,
{ message = localize("k_level_up_ex"), colour = G.C.FILTER }
)
SMODS.calculate_effect({
message = localize("k_level_up_ex"),
}, card)
end
for _, v in pairs(poker_hands) do
update_hand_text({ sound = "button", volume = 0.7, pitch = 0.8, delay = 0.3 }, {
handname = localize(v, "poker_hands"),
chips = G.GAME.hands[v].chips,
mult = G.GAME.hands[v].mult,
level = G.GAME.hands[v].level,
})
level_up_hand(used_consumable, v, nil, number)
if v == "cry_asc_hands" then
Cryptid.asc_level_up(card, copier, number, message)
else
SMODS.smart_level_up_hand(used_consumable, v, nil, number)
end
end
update_hand_text(
{ sound = "button", volume = 0.7, pitch = 1.1, delay = 0 },
@ -1637,7 +1774,7 @@ local planet_cards = {
hertta,
pata,
kaikki,
-- reserved for tefd/none/sol suit planet
perkele,
voxel,
}
return {

View file

@ -33,7 +33,8 @@ local lock = {
use = function(self, card, area, copier)
local used_consumable = copier or card
check_for_unlock({ cry_used_consumable = "c_cry_lock" })
local target = #G.jokers.cards == 1 and G.jokers.cards[1] or G.jokers.cards[math.random(#G.jokers.cards)]
local target = #G.jokers.cards == 1 and G.jokers.cards[1]
or pseudorandom_element(G.jokers.cards, pseudoseed("Dudeman"))
G.E_MANAGER:add_event(Event({
trigger = "after",
delay = 0.4,
@ -1176,7 +1177,7 @@ local typhoon = {
cost = 4,
atlas = "atlasnotjokers",
pos = { x = 0, y = 4 },
use = function(self, card, area, copier) --Good enough
use = function(self, card, area, copier)
local used_consumable = copier or card
check_for_unlock({ cry_used_consumable = "c_cry_typhoon" })
local cards = Cryptid.get_highlighted_cards({ G.hand }, card, 1, card.ability.max_highlighted)
@ -1185,7 +1186,7 @@ local typhoon = {
G.E_MANAGER:add_event(Event({
func = function()
play_sound("tarot1")
highlighted:juice_up(0.3, 0.5)
used_consumable:juice_up(0.3, 0.5)
return true
end,
}))
@ -1194,7 +1195,7 @@ local typhoon = {
delay = 0.1,
func = function()
if highlighted then
highlighted:set_seal("cry_azure")
highlighted:set_seal("cry_azure", nil, true)
end
return true
end,

View file

@ -861,7 +861,7 @@ local trick_or_treat = {
SMODS.pseudorandom_probability(
card,
"cry_trick_or_treat",
1,
3,
card and card.ability.extra.odds or self.config.extra.odds
)
then
@ -891,7 +891,7 @@ local trick_or_treat = {
end,
loc_vars = function(self, info_queue, center)
local num, denom =
SMODS.get_probability_vars(card, 1, card and card.ability.extra.odds or self.config.extra.odds)
SMODS.get_probability_vars(card, 3, card and card.ability.extra.odds or self.config.extra.odds)
return {
vars = {
num,

View file

@ -229,84 +229,4 @@ local test4 = {
end
end,
}
local kidnap2 = {
object_type = "Joker",
name = "cry-kidnap2",
key = "kidnap2",
pos = { x = 1, y = 2 },
config = {
extra = 1,
},
rarity = 1,
cost = 4,
loc_txt = {
name = "asd",
text = {
"Earn {C:money}$#1#{} at end of round",
"per unique {C:attention}Type Mult{} or",
"{C:attention}Type Chips{} Joker sold this run",
"{C:inactive}(Currently {C:money}$#2#{C:inactive})",
},
},
blueprint_compat = false,
loc_vars = function(self, info_queue, center)
local value = 0
if G.GAME and G.GAME.jokers_sold then
for _, v in ipairs(G.GAME.jokers_sold) do
if
G.P_CENTERS[v].effect == "Type Mult"
or G.P_CENTERS[v].effect == "Cry Type Mult"
or G.P_CENTERS[v].effect == "Cry Type Chips"
or G.P_CENTERS[v].effect == "Boost Kidnapping"
or (
G.P_CENTERS[v].name == "Sly Joker"
or G.P_CENTERS[v].name == "Wily Joker"
or G.P_CENTERS[v].name == "Clever Joker"
or G.P_CENTERS[v].name == "Devious Joker"
or G.P_CENTERS[v].name == "Crafty Joker"
)
then
value = value + 1
end
end
end
return { vars = { center.ability.extra, center.ability.extra * value } }
end,
atlas = "atlasone",
calc_dollar_bonus = function(self, card)
local value = 0
for _, v in ipairs(G.GAME.jokers_sold) do
if
G.P_CENTERS[v].effect == "Type Mult"
or G.P_CENTERS[v].effect == "Cry Type Mult"
or G.P_CENTERS[v].effect == "Cry Type Chips"
or G.P_CENTERS[v].effect == "Boost Kidnapping"
or (
G.P_CENTERS[v].name == "Sly Joker"
or G.P_CENTERS[v].name == "Wily Joker"
or G.P_CENTERS[v].name == "Clever Joker"
or G.P_CENTERS[v].name == "Devious Joker"
or G.P_CENTERS[v].name == "Crafty Joker"
)
then
value = value + 1
end
end
if value == 0 then
return
end
return card.ability.extra * value
end,
cry_credits = {
idea = {
"Jevonn",
},
art = {
"Jevonn",
},
code = {
"Jevonn",
},
},
}
return { items = { test, test2, test3, test4, kidnap2 }, disabled = true }
return { items = { test, test2, test3, test4 }, disabled = true }

View file

@ -366,6 +366,32 @@ local satellite_uplink = { -- Code T2; Code cards may appear in any of the Celes
requires = { "v_cry_command_prompt" },
}
--i removed the patch as it didnt do anything and its not needed
--mainly just took from vanillaremade
SMODS.Booster:take_ownership_by_kind("Celestial", {
create_card = function(self, card, i)
local _card
if G.GAME.used_vouchers.v_cry_satellite_uplink and pseudorandom("satellite_uplink") > 0.8 then
_card = {
set = "Code",
area = G.pack_cards,
skip_materialize = true,
soulable = true,
key_append = "pl2",
}
else
_card = {
set = "Planet",
area = G.pack_cards,
skip_materialize = true,
soulable = true,
key_append = "pl1",
}
end
return _card
end,
}, true)
-- Tier 3 Vouchers
local overstock_multi = { -- Overstock T3; +1 card slot, +1 booster pack slot and +1 voucher slot available in the shop
cry_credits = {

View file

@ -221,12 +221,22 @@ function Cryptid.calculate_ascension_power(hand_name, hand_cards, hand_scoring_c
if G.GAME.cry_exploit_override then
bonus = bonus + 1
end
-- Get Ascension Power From Sol (Observatory effect)
if G.GAME.used_vouchers.v_observatory and next(find_joker("cry-sunplanet")) then
if #find_joker("cry-sunplanet") == 1 then
-- Get Ascension Power From Sol/Perkele (Observatory effect)
if
G.GAME.used_vouchers.v_observatory and (next(find_joker("cry-sunplanet")) or next(find_joker("cry-Perkele")))
then
-- switch this to not use find_joker eventually please for the love of god
local super_entropic_local_variable_that_stores_the_amount_of_suns = #find_joker("cry-sunplanet")
+ #find_joker("cry-Perkele")
if super_entropic_local_variable_that_stores_the_amount_of_suns == 1 then
bonus = bonus + 1
else
bonus = bonus + Cryptid.nuke_decimals(Cryptid.funny_log(2, #find_joker("cry-sunplanet") + 1), 2)
bonus = bonus
+ Cryptid.nuke_decimals(
Cryptid.funny_log(2, super_entropic_local_variable_that_stores_the_amount_of_suns + 1),
2
)
end
end
local final = math.max(0, starting + bonus)

View file

@ -343,7 +343,7 @@ SMODS.Rarity({
pools = { ["Joker"] = true },
get_weight = function(self, weight, object_type)
-- The game shouldn't try generating Epic Jokers when they are disabled
if Cryptid_config["Epic Jokers"] then
if Cryptid.enabled("set_cry_epic") then
return 0.003
else
return 0
@ -540,23 +540,28 @@ SMODS.Sound({
and Cryptid_config.Cryptid
and Cryptid_config.Cryptid.jimball_music
-- Lowering priority for edition Jimballs later
and 7
and 200
end,
})
SMODS.Sound({
key = "music_code",
path = "music_code.ogg",
select_music_track = function()
return Cryptid_config.Cryptid
return (
Cryptid_config.Cryptid
and Cryptid_config.Cryptid.code_music
and (
(
G.pack_cards
and G.pack_cards.cards
and G.pack_cards.cards[1]
and G.pack_cards.cards[1].ability.set == "Code"
) or (G.GAME and G.GAME.USING_CODE)
-- in a code pack
(
G.booster_pack
and not G.booster_pack.REMOVED
and SMODS.OPENED_BOOSTER
and SMODS.OPENED_BOOSTER.config.center.kind == "Code"
)
-- using a code card
or (G.GAME and G.GAME.USING_CODE)
)
) and 100
end,
})
SMODS.Sound({
@ -565,14 +570,13 @@ SMODS.Sound({
select_music_track = function()
if G.GAME.cry_music_big then
return G.GAME.cry_music_big
end
if
elseif
Cryptid_config.Cryptid
and Cryptid_config.Cryptid.big_music
and to_big(G.GAME.round_scores["hand"].amt) > to_big(10) ^ 1000000
then
G.GAME.cry_music_big = true
return true
G.GAME.cry_music_big = 6
return 100.001
end
end,
})
@ -581,9 +585,11 @@ SMODS.Sound({
path = "music_exotic.ogg",
volume = 0.4,
select_music_track = function()
return Cryptid_config.Cryptid
return (
Cryptid_config.Cryptid
and Cryptid_config.Cryptid.exotic_music
and #Cryptid.advanced_find_joker(nil, "cry_exotic", nil, nil, true) ~= 0
) and 100.002
end,
})
SMODS.Sound({
@ -864,3 +870,23 @@ SMODS.Scoring_Calculation({
}
end,
})
-- Scoring Calculation for The Chromatic
SMODS.Scoring_Calculation({
key = "chromatic",
func = function(self, chips, mult, flames)
if Cryptid.safe_get(G, "GAME", "chromatic_mod") then
if G.GAME.chromatic_mod % 2 == 1 then
return chips * mult * -1
end
end
return chips * mult
end,
update_ui = function(self, container, chip_display, mult_display, operator)
local aaa = Cryptid.safe_get(G, "GAME", "chromatic_mod") or -1
if aaa > 0 and aaa % 2 == 1 then
ease_colour(G.C.UI_CHIPS, HEX("a34f98"), 0.3)
ease_colour(G.C.UI_MULT, HEX("a34f98"), 0.3)
end
end,
})

View file

@ -861,7 +861,7 @@ function Cryptid.forcetrigger(card, context)
-- if card.ability.name == "Blueprint" then results = { jokers = { } } end
if card.ability.name == "Wee Joker" then
SMODS.scale_card(card, {
ref_table = card.ability,
ref_table = card.ability.extra,
ref_value = "chips",
scalar_value = "chip_mod",
no_message = true,
@ -1011,7 +1011,8 @@ function Cryptid.forcetrigger(card, context)
SMODS.scale_card(card, {
ref_table = card.ability,
ref_value = "x_mult",
scalar_value = "extra",
scalar_table = card.ability.extra,
scalar_value = "xmult",
no_message = true,
})
results = { jokers = { Xmult_mod = card.ability.x_mult, card = card } }

View file

@ -330,6 +330,8 @@ G.FUNCS.cry_gameset_confirm = function(e)
if G.selectedGameset == "madness" then
--Unlock All by default in madness
G.PROFILES[G.SETTINGS.profile].all_unlocked = true
G.PROFILES[G.SETTINGS.profile].cry_none2 = true
G.PROFILES[G.SETTINGS.profile].cry_none = (Cryptid.enabled("set_cry_poker_hand_stuff") == true)
for k, v in pairs(G.P_CENTERS) do
if not v.demo and not v.wip then
v.alerted = true
@ -1129,8 +1131,7 @@ function Cryptid.update_obj_registry(m, force_enable)
G.PROFILES,
G.SETTINGS.profile,
"cry_none2"
) or nil
G.PROFILES[G.SETTINGS.profile].cry_none2 = nil
) and true or nil
end
end
else
@ -1138,8 +1139,6 @@ function Cryptid.update_obj_registry(m, force_enable)
v:_disable(en)
if v.key == "set_cry_poker_hand_stuff" and G.PROFILES[G.SETTINGS.profile].cry_none then
--Remove the none flag if poker hands are disabled because leaving it on can leave to softlocks
G.PROFILES[G.SETTINGS.profile].cry_none2 =
Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "cry_none")
G.PROFILES[G.SETTINGS.profile].cry_none = nil
end
end

View file

@ -1,5 +1,5 @@
-- Update the Cryptid member count using HTTPS
local member_fallback = 29332
local member_fallback = 38598
local succ, https = pcall(require, "SMODS.https")
local last_update_time = 0
local initial = true

View file

@ -528,6 +528,7 @@ Cryptid.big_num_blacklist = {
["j_cry_wonka_bar"] = true,
["j_cry_oldcandy"] = true,
["j_cry_negative"] = true,
["j_cry_energia"] = true,
["c_magician"] = true,
["c_empress"] = true,
@ -1453,6 +1454,11 @@ function Cryptid.funny_log(x, y)
return math.log(y) / math.log(x)
end
-- Clamps n between min and max
function Cryptid.clamp(n, min, max)
return math.min(math.max(n, min), max)
end
local say_stuff_ref = Card_Character.say_stuff
function Card_Character:say_stuff(n, not_first, quip_key)
local quip = SMODS.JimboQuips[quip_key]

View file

@ -18,12 +18,20 @@ Cryptid.misprintize_value_blacklist = {
colour = false,
suit_nominal_original = false,
times_played = false,
extra_slots_used = false,
card_limit = false,
-- TARGET: Misprintize Value Blacklist (format: key = false, )
}
Cryptid.misprintize_bignum_blacklist = {
odds = false,
cry_prob = false,
--nominal = false,
perma_repetitions = false,
repetitions = false,
nominal = false, --keep here, please.
}
Cryptid.misprintize_value_cap = {
perma_repetitions = 40,
repetitions = 40,
}
function Cryptid.calculate_misprint(initial, min, max, grow_type, pow_level)
@ -496,12 +504,19 @@ function Cryptid.manipulate_table(card, ref_table, ref_value, args, tblkey)
or Cryptid.base_values[card.config.center.key][i .. "consumeable"]
end
end
if args.big ~= nil then
ref_table[ref_value][i] = Cryptid.manipulate_value(num, args, args.big, i)
else
ref_table[ref_value][i] = Cryptid.manipulate_value(num, args, Cryptid.is_card_big(card), i)
local new_val = Cryptid.manipulate_value(num, args, args.big or Cryptid.is_card_big(card), i)
ref_table[ref_value][i] = new_val
-- take double scale / scalae into account
if ref_value == "ability" and ref_table.ability.cry_scaling_info then
ref_table.ability.cry_scaling_info[i] = new_val
end
elseif i ~= "immutable" and type(v) == "table" and Cryptid.misprintize_value_blacklist[i] ~= false then
elseif
i ~= "immutable"
and not (ref_value == "ability" and i == "cry_scaling_info")
and type(v) == "table"
and Cryptid.misprintize_value_blacklist[i] ~= false
then
Cryptid.manipulate_table(card, ref_table[ref_value], i, args)
end
end
@ -555,6 +570,9 @@ function Cryptid.manipulate_value(num, args, is_big, name)
end
end
end
if Cryptid.misprintize_value_cap[name] then
num = math.min(num, Cryptid.misprintize_value_cap[name])
end
if Cryptid.misprintize_bignum_blacklist[name] == false then
num = to_number(num)
return to_number(Cryptid.sanity_check(num, false))

View file

@ -198,6 +198,7 @@ function Blind:defeat(s)
end
if
--Stop impossible blind combinations from happening
--Needs a better system than this, needs a lovely patch for other mods to add to this list currently (TODO)
(self.name ~= "cry-oldarm" or not G.GAME.defeated_blinds["bl_psychic"])
and (self.name ~= "The Psychic" or not G.GAME.defeated_blinds["bl_cry_oldarm"])
and (self.name ~= "cry-oldarm" or not G.GAME.defeated_blinds["bl_cry_scorch"])
@ -208,6 +209,10 @@ function Blind:defeat(s)
and (self.name ~= "cry-Tax" or not G.GAME.defeated_blinds["bl_cry_lavender_loop"])
and (self.name ~= "The Needle" or not G.GAME.defeated_blinds["bl_cry_tax"])
and (self.name ~= "cry-Tax" or not G.GAME.defeated_blinds["bl_needle"])
and (self.name ~= "The Needle" or not G.GAME.defeated_blinds["bl_cry_chromatic"])
and (self.name ~= "cry-chromatic" or not G.GAME.defeated_blinds["bl_needle"])
and (self.name ~= "cry-Tax" or not G.GAME.defeated_blinds["bl_cry_chromatic"])
and (self.name ~= "cry-chromatic" or not G.GAME.defeated_blinds["bl_cry_tax"])
then
G.GAME.defeated_blinds[self.config.blind.key or ""] = true
end
@ -222,6 +227,8 @@ function Game:start_run(args)
if not G.GAME.defeated_blinds then
G.GAME.defeated_blinds = {}
end
G.consumeables.config.highlighted_limit = 1e100
G.jokers.config.highlighted_limit = 1e100
end
--patch for multiple Clocks to tick separately and load separately
@ -738,7 +745,7 @@ function SMODS.create_mod_badges(obj, badges)
}
local function eq_col(x, y)
for i = 1, 4 do
if x[1] ~= y[1] then
if x[i] ~= y[i] then
return false
end
end
@ -1832,6 +1839,7 @@ function end_round()
Cryptid.enabled("set_cry_poker_hand_stuff") == true
and not Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "cry_none")
then
G.PROFILES[G.SETTINGS.profile].cry_none2 = true
G.PROFILES[G.SETTINGS.profile].cry_none = true
end
if not Cryptid.enabled("set_cry_poker_hand_stuff") then
@ -1968,6 +1976,7 @@ G.FUNCS.play_cards_from_highlighted = function(e)
-- None Stuff
if G.GAME.stamp_mod and not G.PROFILES[G.SETTINGS.profile].cry_none and #G.hand.highlighted == 1 then
G.PROFILES[G.SETTINGS.profile].cry_none = true
G.PROFILES[G.SETTINGS.profile].cry_none2 = true
print("nonelock stuff here")
G.GAME.hands["cry_None"].visible = true
end
@ -2158,20 +2167,20 @@ function get_straight(hand, min_length, skip, wrap)
end
local get_prob_vars_ref = SMODS.get_probability_vars
function SMODS.get_probability_vars(trigger_obj, base_numerator, base_denominator, identifier, from_roll)
function SMODS.get_probability_vars(trigger_obj, base_numerator, base_denominator, identifier, from_roll, no_mod, ...)
local mod = trigger_obj and trigger_obj.ability and trigger_obj.ability.cry_prob or 1
local numerator = base_numerator * mod
if trigger_obj and trigger_obj.ability and trigger_obj.ability.cry_rigged then
if trigger_obj and trigger_obj.ability and trigger_obj.ability.cry_rigged and not no_mod then
numerator = base_denominator
end
return get_prob_vars_ref(trigger_obj, numerator, base_denominator, identifier, from_roll)
return get_prob_vars_ref(trigger_obj, numerator, base_denominator, identifier, from_roll, no_mod, ...)
end
local pseudorandom_probability_ref = SMODS.pseudorandom_probability
function SMODS.pseudorandom_probability(trigger_obj, seed, base_numerator, base_denominator, identifier)
function SMODS.pseudorandom_probability(trigger_obj, seed, base_numerator, base_denominator, identifier, no_mod, ...)
local mod = trigger_obj and trigger_obj.ability and trigger_obj.ability.cry_prob or 1
local numerator = base_numerator * mod
if trigger_obj and trigger_obj.ability and trigger_obj.ability.cry_rigged then
if trigger_obj and trigger_obj.ability and trigger_obj.ability.cry_rigged and not no_mod then
SMODS.post_prob = SMODS.post_prob or {}
SMODS.post_prob[#SMODS.post_prob + 1] = {
pseudorandom_result = true,
@ -2183,7 +2192,7 @@ function SMODS.pseudorandom_probability(trigger_obj, seed, base_numerator, base_
}
return true
end
return pseudorandom_probability_ref(trigger_obj, seed, numerator, base_denominator, identifier)
return pseudorandom_probability_ref(trigger_obj, seed, numerator, base_denominator, identifier, no_mod, ...)
end
local is_eternalref = SMODS.is_eternal
@ -2197,17 +2206,98 @@ end
local unlock_allref = G.FUNCS.unlock_all
G.FUNCS.unlock_all = function(e)
unlock_allref(e)
G.PROFILES[G.SETTINGS.profile].cry_none2 = true
G.PROFILES[G.SETTINGS.profile].cry_none = (Cryptid.enabled("set_cry_poker_hand_stuff") == true)
end
-- Calc ante gain for The Joke (Scuffed)
local smods_calc = SMODS.calculate_context
function SMODS.calculate_context(context, return_table, no_resolve)
local aaa = smods_calc(context, return_table, no_resolve)
if context.modify_ante and context.ante_end then
if G.GAME.blind then
aaa.modify = G.GAME.blind:cry_calc_ante_gain() - 1
end
local scie = SMODS.calculate_individual_effect
function SMODS.calculate_individual_effect(effect, scored_card, key, amount, from_edition, ...)
local ret = scie(effect, scored_card, key, amount, from_edition, ...)
if ret then
return ret
end
if key == "cry_broken_swap" and amount > 0 then
if effect.card and effect.card ~= scored_card then
juice_card(effect.card)
end
-- only need math.min due to amount being required to be greater than 0
amount = math.min(amount, 1)
local chips = SMODS.Scoring_Parameters.chips
local mult = SMODS.Scoring_Parameters.mult
local chip_mod = chips.current * amount
local mult_mod = mult.current * amount
chips:modify(mult_mod - chip_mod)
mult:modify(chip_mod - mult_mod)
if not Cryptid.safe_get(Talisman, "config_file", "disable_anims") then
G.E_MANAGER:add_event(Event({
func = function()
-- scored_card:juice_up()
local pitch_mod = pseudorandom("cry_broken_sync") * 0.05 + 0.85
-- wolf fifth as opposed to plasma deck's just-intonated fifth
-- yes i'm putting music theory nerd stuff in here no you cannot stop me
play_sound("gong", pitch_mod, 0.3)
play_sound("gong", pitch_mod * 1.4814814, 0.2)
play_sound("tarot1", 1.5)
ease_colour(G.C.UI_CHIPS, mix_colours(G.C.BLUE, G.C.RED, amount))
ease_colour(G.C.UI_MULT, mix_colours(G.C.RED, G.C.BLUE, amount))
G.E_MANAGER:add_event(Event({
trigger = "after",
blockable = false,
blocking = false,
delay = 0.8,
func = function()
ease_colour(G.C.UI_CHIPS, G.C.BLUE, 0.8)
ease_colour(G.C.UI_MULT, G.C.RED, 0.8)
return true
end,
}))
G.E_MANAGER:add_event(Event({
trigger = "after",
blockable = false,
blocking = false,
no_delete = true,
delay = 1.3,
func = function()
G.C.UI_CHIPS[1], G.C.UI_CHIPS[2], G.C.UI_CHIPS[3], G.C.UI_CHIPS[4] =
G.C.BLUE[1], G.C.BLUE[2], G.C.BLUE[3], G.C.BLUE[4]
G.C.UI_MULT[1], G.C.UI_MULT[2], G.C.UI_MULT[3], G.C.UI_MULT[4] =
G.C.RED[1], G.C.RED[2], G.C.RED[3], G.C.RED[4]
return true
end,
}))
return true
end,
}))
if not effect.remove_default_message then
if effect.balance_message then
card_eval_status_text(
effect.message_card or effect.juice_card or scored_card or effect.card or effect.focus,
"extra",
nil,
percent,
nil,
effect.balance_message
)
else
card_eval_status_text(
effect.message_card or effect.juice_card or scored_card or effect.card or effect.focus,
"extra",
nil,
percent,
nil,
{ message = localize("cry_balanced_q"), colour = { 0.8, 0.45, 0.85, 1 } }
)
end
end
delay(0.6)
end
return true
end
return aaa
end
SMODS.scoring_parameter_keys[#SMODS.scoring_parameter_keys + 1] = "cry_broken_swap"

View file

@ -321,80 +321,6 @@ end
local G_UIDEF_use_and_sell_buttons_ref = G.UIDEF.use_and_sell_buttons
function G.UIDEF.use_and_sell_buttons(card)
local abc = G_UIDEF_use_and_sell_buttons_ref(card)
-- Allow code cards to be reserved
if (card.area == G.pack_cards and G.pack_cards) and card.ability.consumeable then --Add a use button
if card.ability.set == "Code" 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_reserve_card",
},
nodes = {
{
n = G.UIT.T,
config = {
text = localize("b_pull"),
colour = G.C.UI.TEXT_LIGHT,
scale = 0.55,
shadow = true,
},
},
},
},
{
n = G.UIT.R,
config = {
ref_table = card,
r = 0.08,
padding = 0.1,
align = "bm",
minw = 0.5 * card.T.w - 0.15,
maxw = 0.9 * card.T.w - 0.15,
minh = 0.1 * card.T.h,
hover = true,
shadow = true,
colour = G.C.UI.BACKGROUND_INACTIVE,
one_press = true,
button = "Do you know that this parameter does nothing?",
func = "can_use_consumeable",
},
nodes = {
{
n = G.UIT.T,
config = {
text = localize("b_use"),
colour = G.C.UI.TEXT_LIGHT,
scale = 0.45,
shadow = true,
},
},
},
},
{ n = G.UIT.R, config = { align = "bm", w = 7.7 * card.T.w } },
{ n = G.UIT.R, config = { align = "bm", w = 7.7 * card.T.w } },
{ n = G.UIT.R, config = { align = "bm", w = 7.7 * card.T.w } },
{ n = G.UIT.R, config = { align = "bm", w = 7.7 * card.T.w } },
-- Betmma can't explain it, neither can I
},
}
end
end
-- Remove sell button from cursed jokers
if
card.area

View file

@ -5,7 +5,7 @@ return {
name = "Antimatter Deck",
text = {
"Applies the {C:legendary,E:1}upsides{}",
"of {C:attention}every{} deck",
"of {C:attention}almost every{} deck",
},
unlock = {
"Win a run",
@ -17,9 +17,27 @@ return {
name = "Antimatter Deck",
text = {
"Applies the {C:legendary,E:1}upsides{}",
"of {C:attention}every{} deck won",
"of {C:attention}almost every{} deck won",
"with {C:gold}Gold Stake{}",
},
unlock = {
"Win a run",
"with {C:attention}Blank Deck",
"on {C:attention}Gold Stake",
},
},
b_cry_antimatter_custom = {
name = "Antimatter Deck",
text = {
"Applies the {C:legendary,E:1}upsides{}",
"of {C:attention}some{} decks won",
"with {C:gold}Gold Stake{}",
},
unlock = {
"Win a run",
"with {C:attention}Blank Deck",
"on {C:attention}Gold Stake",
},
},
b_cry_beige = {
name = "Beige Deck",
@ -1214,6 +1232,31 @@ return {
"{C:attention}10 minutes",
},
},
j_cry_broken_sync_catalyst = {
name = "Broken Sync Catalyst",
text = {
"Swaps {C:attention}#1#%{} of {C:chips}Chips{} with {C:attention}#1#%{} of {C:mult}Mult{}",
"{C:inactive,s:0.8}I've seen this one before...",
"{C:inactive,s:0.8}...it's seen better days.",
},
},
j_cry_thalia = {
name = "Thalia and Melpomeme",
text = {
"{C:white,X:mult}X#1#{} Mult for every",
"pair of unique rarities",
"{C:inactive}(Currently {C:white,X:mult}X#2#{C:inactive}){}",
},
},
j_cry_keychange = {
name = "Key Change",
text = {
"Gains {C:white,X:mult}X#1#{} if {C:attention}poker hand{} has",
"not been played this round",
"Resets at {C:attention}end of round{}",
"{C:inactive}(Currently {C:white,X:mult}X#2#{C:inactive{}){}",
},
},
j_cry_brittle = {
name = "Brittle Candy",
text = {
@ -1248,6 +1291,14 @@ return {
"to the next shop",
},
},
j_cry_caeruleum = {
name = "Caeruleum",
text = {
"Adjacent {C:chips}chips{}-modifying jokers",
"use the next highest {C:attention}operator{} for scoring",
"{C:inactive}(Caps at exponentiation)",
},
},
j_cry_candy_basket = {
name = "Candy Basket",
text = {
@ -1593,8 +1644,9 @@ return {
["j_cry_Double Scale"] = { -- ?????????????
name = "Double Scale",
text = {
"Scaling {C:attention}Jokers{}",
"scale {C:attention}quadratically",
"Whenever a {C:attention}Joker scales{}",
"The {C:attention}scaling rate{} is increased by its {C:attention}original scale rate{}",
"{C:inactive,s:0.8}(Does not stack with copies of this Joker){}",
"{C:inactive,s:0.8}(ex. +1, +3, +6, +10)",
"{C:inactive,s:0.8}(grows by +1, +2, +3)",
},
@ -3276,6 +3328,18 @@ return {
"and {C:attention}#3#{}",
},
},
c_cry_perkele = {
name = "Perkele",
text = {
"({V:1}lvl.#4#{})({V:2}lvl.#5#{})({V:3}lvl.#6#{})",
"Level up",
"{C:attention}#1#{},",
"{C:attention}#2#{},",
"and {C:attention}#3#{}",
"{C:inactive}(Currently {X:gold,C:white}X#7#{C:inactive} {C:chips}C{}+{C:mult}M{C:inactive} Multiplier",
"{C:inactive}Per {C:attention}1{C:inactive} Ascension power)",
},
},
c_cry_voxel = {
name = "Voxel",
text = {
@ -4420,6 +4484,16 @@ return {
},
},
cry_hooked = {
name = "Hooked",
text = {
"When this Joker is {C:cry_code}triggered{},",
"trigger {C:cry_code}#1#",
"{C:inactive}Not all cards can be triggered this way{}",
"{C:inactive}but all Jokers can trigger the other{}",
"Removed at end of round",
},
},
cry_hooked_2 = {
name = "Hooked",
text = {
"When this Joker is {C:cry_code}triggered{},",
@ -4716,8 +4790,19 @@ return {
o_sunplanet = {
name = "Observatory Effect",
text = {
"Held {C:attention}Sol{} Cards increase",
"{C:attention}Ascension power",
"Held {C:attention}Sol{} and {C:attention}Perkele{} Cards",
"increase {C:attention}Ascension power",
"{C:inactive}(Currently {X:gold,C:white}+#1#{C:inactive})",
},
},
o_perkele = {
name = "Observatory Effect",
text = {
"{X:dark_edition,C:white}^#2#{} mult if played hand is a",
"{C:attention}#4#{}",
"{X:mult,C:white}X#2#{} mult if played hand is a {C:attention}#3#{}",
"Held {C:attention}Sol{} and {C:attention}Perkele{} Cards",
"increase {C:attention}Ascension power",
"{C:inactive}(Currently {X:gold,C:white}+#1#{C:inactive})",
},
},
@ -5136,6 +5221,7 @@ return {
cry_p_star = "Star",
cry_again_q = "Again?",
cry_balanced_q = "Balanced...?",
cry_curse = "Curse",
cry_curse_ex = "Curse!",
cry_demicolon = "Demitrigger!",
@ -5189,6 +5275,7 @@ return {
cry_gameset_mainline = "Mainline",
cry_gameset_madness = "Madness",
cry_gameset_custom = "Modified",
cry_gameset_Custom = "Custom",
cry_gameset_exp = "Experimental",
cry_gameset_exp_modest = "Experimental (Modest)",
cry_gameset_exp_mainline = "Experimental (Mainline)",

View file

@ -409,39 +409,6 @@ payload = '''if not G.shop then return true end
G.shop.alignment.offset.y = -5.3'''
match_indent = true
# Increase highlight limit for consumables
[[patches]]
[patches.pattern]
target = "game.lua"
pattern = "{card_limit = self.GAME.starting_params.consumable_slots, type = 'joker', highlight_limit = 1, negative_info = 'consumable'})"
position = "at"
payload = "{card_limit = self.GAME.starting_params.consumable_slots, type = 'joker', highlight_limit = 1e100, negative_info = 'consumable'})"
match_indent = true
# Increase highlight limit for jokers
[[patches]]
[patches.pattern]
target = "game.lua"
pattern = "{card_limit = self.GAME.starting_params.joker_slots, type = 'joker', highlight_limit = 1, negative_info = 'joker'})"
position = "at"
payload = "{card_limit = self.GAME.starting_params.joker_slots, type = 'joker', highlight_limit = 1e100, negative_info = 'joker'})"
match_indent = true
# Satellite Uplink
[[patches]]
[patches.pattern]
target = "card.lua"
pattern = '''card = create_card("Planet", G.pack_cards, nil, nil, true, true, nil, 'pl1')'''
position = "at"
payload = '''
if G.GAME.used_vouchers.v_cry_satellite_uplink and pseudorandom('cry_satellite_uplink') > 0.8 then
card = create_card("Code", G.pack_cards, nil, nil, true, true, nil, 'pl2')
else
card = create_card("Planet", G.pack_cards, nil, nil, true, true, nil, 'pl1')
end
'''
match_indent = true
# Exploit - reset variables
[[patches]]
[patches.pattern]

View file

@ -24,13 +24,18 @@ end
match_indent = true
# Packs
# changed this patch to fix certain shop booster stuff
# the function used was kinda problematic though
# so consider this a quickfix, as i feel as if the function itself could be changed
[[patches]]
[patches.pattern]
target = "game.lua"
pattern = "create_shop_card_ui(card, 'Booster', G.shop_booster)"
position = "before"
payload = '''
Cryptid.manipulate(card)
if G.GAME.modifiers.cry_misprint_min then
Cryptid.manipulate(card)
end
'''
match_indent = true

View file

@ -303,3 +303,29 @@ payload = '''
else
'''
match_indent = true
# Fix a crash with Cerlulean bell if there are no cards in hand 1/2
[[patches]]
[patches.pattern]
target = "blind.lua"
pattern = '''
forced_card.ability.forced_selection = true
'''
position = "before"
payload = '''
if forced_card then
'''
match_indent = true
# Fix a crash with Cerlulean bell if there are no cards in hand 2/2
[[patches]]
[patches.pattern]
target = "blind.lua"
pattern = '''
G.hand:add_to_highlighted(forced_card)
'''
position = "after"
payload = '''
end
'''
match_indent = true

View file

@ -24,4 +24,23 @@ elseif v.config.hand_types then
end
if not softlocked then
'''
match_indent = true
match_indent = true
# context.cry_observatory
[[patches]]
[patches.pattern]
target = '=[SMODS _ "src/game_object.lua"]'
pattern = '''if
context.other_consumeable and'''
position = "at"
payload = '''
if context.other_consumeable then
local ctx = SMODS.shallow_copy(context)
ctx.cry_observatory = card
ctx.other_consumeable = nil
local ret = context.other_consumeable:calculate_joker(ctx)
if ret then SMODS.calculate_effect(ret, context.other_consumeable) end
elseif context.other_consumeable and
not ret and
'''
match_indent = true

Binary file not shown.

Before

Width:  |  Height:  |  Size: 54 KiB

After

Width:  |  Height:  |  Size: 32 KiB

View file

@ -1,236 +1,290 @@
return {
descriptions = {
Other = {
load_success = {
text = {
'Mod caricata',
'{C:green}con successo!'
}
},
load_failure_d = {
text = {
'{C:attention}Dipendenze mancanti!',
'#1#',
}
},
load_failure_c = {
text = {
'{C:attention}Conflitti rilevati!',
'#1#'
}
},
load_failure_d_c = {
text = {
'{C:attention}Dipendenze mancanti!',
'#1#',
'{C:attention}Conflitti rilevati!',
'#2#'
}
},
load_failure_o = {
text = {
'{C:attention}Obsoleta!{} le versioni',
'di Steamodded {C:money}0.9.8{} ed inferiori',
'non sono più supportate.'
}
},
load_failure_i = {
text = {
'{C:attention}Incompatibile!{} Richiede la versione',
'#1# di Steamodded,',
'ma la #2# è installata.'
}
},
load_failure_p = {
text = {
'{C:attention}Conflitto fra i prefissi!{}',
'Il prefisso di questa mod è',
'lo stesso di quest\'altra mod',
'({C:attention}#1#{})'
}
},
load_failure_m = {
text = {
'{C:attention}File principale non trovato!{}',
'Il file principale di questa mod',
'non è stato trovato.',
'({C:attention}#1#{})'
}
},
load_disabled = {
text = {
'Questa mod è stata',
'{C:attention}disattivata!{}'
}
},
descriptions = {
Other = {
load_success = {
text = {
'Mod caricata',
'{C:green}con successo!'
}
},
load_failure_d = {
text = {
'{C:attention}Dipendenze mancanti!',
'#1#',
}
},
load_failure_c = {
text = {
'{C:attention}Conflitti rilevati!',
'#1#'
}
},
load_failure_d_c = {
text = {
'{C:attention}Dipendenze mancanti!',
'#1#',
'{C:attention}Conflitti rilevati!',
'#2#'
}
},
load_failure_o = {
text = {
'{C:attention}Obsoleta!{} le versioni',
'di Steamodded {C:money}0.9.8{} ed inferiori',
'non sono più supportate.'
}
},
load_failure_i = {
text = {
'{C:attention}Incompatibile!{} Richiede la versione',
'#1# di Steamodded,',
'ma la #2# è installata.'
}
},
load_failure_p = {
text = {
'{C:attention}Conflitto fra i prefissi!{}',
'Il prefisso di questa mod è',
'lo stesso di quest\'altra mod',
'({C:attention}#1#{})'
}
},
load_failure_m = {
text = {
'{C:attention}File principale non trovato!{}',
'Il file principale di questa mod',
'non è stato trovato.',
'({C:attention}#1#{})'
}
},
load_disabled = {
text = {
'Questa mod è stata',
'{C:attention}disattivata!{}'
}
},
-- card perma bonuses
card_extra_chips={
text={
"{C:chips}#1#{} fiche extra",
},
},
card_x_chips = {
text = {
"{X:chips,C:white}X#1#{} fiche"
}
},
card_extra_x_chips = {
text = {
"{X:chips,C:white}X#1#{} fiche extra"
}
},
card_extra_mult = {
text = {
"{C:mult}#1#{} Molt extra"
}
},
card_x_mult = {
text = {
"{X:mult,C:white}X#1#{} Molt"
}
},
card_extra_x_mult = {
text = {
"{X:mult,C:white}X#1#{} Molt extra"
}
},
card_extra_p_dollars = {
text = {
"{C:money}#1#{} quando assegna punti",
}
},
card_extra_h_chips = {
text = {
"{C:chips}#1#{} fiche se tenuta in mano",
}
},
card_h_x_chips = {
text = {
"{X:chips,C:white}X#1#{} fiche se tenuta in mano",
}
},
card_extra_h_x_chips = {
text = {
"{X:chips,C:white}X#1#{} fiche extra se tenuta in mano",
}
},
card_extra_h_mult = {
text = {
"{C:mult}#1#{} Molt extra se tenuta in mano",
}
},
card_h_x_mult = {
text = {
"{X:mult,C:white}X#1#{} Molt se tenuta in mano",
}
},
card_extra_h_x_mult = {
text = {
"{X:mult,C:white}X#1#{} Molt extra se tenuta in mano",
}
},
card_extra_h_dollars = {
text = {
"{C:money}#1#{} se hai in mano questa carta alla fine del round",
},
},
},
Edition = {
e_negative_playing_card = {
name = "Negativo",
text = {
"{C:dark_edition}+#1#{} carte della mano"
},
},
},
Enhanced = {
m_gold={
name="Carta dorata",
text={
"{C:money}$#1#{} se hai",
"in mano questa carta",
"alla fine del round",
},
},
m_stone={
name="Carta di pietra",
text={
"{C:chips}+#1#{} fiche",
"nessun valore o seme",
},
},
m_mult={
name="Carta Molt",
text={
"{C:mult}+#1#{} Molt",
},
},
}
},
misc = {
achievement_names = {
hidden_achievement = "???",
},
achievement_descriptions = {
hidden_achievement = "Gioca per scoprirlo!",
},
dictionary = {
b_mods = 'Mod',
b_mods_cap = 'MOD',
b_modded_version = 'Versione Modificata!',
b_steamodded = 'Steamodded',
b_credits = 'Crediti',
b_open_mods_dir = 'Apri cartella Mods',
b_no_mods = 'Nessuna mod rilevata...',
b_mod_list = 'Lista di mod attivate',
b_mod_loader = 'Mod Loader',
b_developed_by = 'sviluppato da ',
b_rewrite_by = 'Riscritto da by ',
b_github_project = 'Progetto Github',
b_github_bugs_1 = 'Puoi segnalare bug e',
b_github_bugs_2 = 'contribuire qui.',
b_disable_mod_badges = 'Disattiva etichette mod',
b_author = 'Autore',
b_authors = 'Autori',
b_unknown = 'Sconosciuto',
b_lovely_mod = '(Lovely Mod) ',
b_by = ' Di: ',
-- card perma bonuses
card_extra_chips={
text={
"{C:chips}#1#{} fiche extra",
},
},
card_x_chips = {
text = {
"{X:chips,C:white}X#1#{} fiche"
}
},
card_extra_x_chips = {
text = {
"{X:chips,C:white}X#1#{} fiche extra"
}
},
card_extra_mult = {
text = {
"{C:mult}#1#{} Molt extra"
}
},
card_x_mult = {
text = {
"{X:mult,C:white}X#1#{} Molt"
}
},
card_extra_x_mult = {
text = {
"{X:mult,C:white}X#1#{} Molt extra"
}
},
card_extra_p_dollars = {
text = {
"{C:money}#1#{} quando assegna punti",
}
},
card_extra_h_chips = {
text = {
"{C:chips}#1#{} fiche se tenuta in mano",
}
},
card_h_x_chips = {
text = {
"{X:chips,C:white}X#1#{} fiche se tenuta in mano",
}
},
card_extra_h_x_chips = {
text = {
"{X:chips,C:white}X#1#{} fiche extra se tenuta in mano",
}
},
card_extra_h_mult = {
text = {
"{C:mult}#1#{} Molt extra se tenuta in mano",
}
},
card_h_x_mult = {
text = {
"{X:mult,C:white}X#1#{} Molt se tenuta in mano",
}
},
card_extra_h_x_mult = {
text = {
"{X:mult,C:white}X#1#{} Molt extra se tenuta in mano",
}
},
card_extra_h_dollars = {
text = {
"{C:money}#1#{} se hai in mano questa carta alla fine del round",
},
},
card_extra_repetitions = {
text = {
"Riattiva questa",
"carta {C:attention}#1#{} #2#",
},
},
artist = {
text = {
"{C:inactive}Artista",
},
},
artist_credit = {
name = "Artista",
text = {
"{E:1}#1#{}"
},
},
generic_card_limit = {
name = "Card limite",
text = {
'{C:dark_edition}#1#{} slot'
}
},
generic_card_limit_plural = {
name = "Carte limite",
text = {
'{C:dark_edition}#1#{} slots'
}
},
generic_extra_slots = {
name = "Slot usati",
text = {
'Riempie {C:dark_edition}#1#{} slot'
},
},
},
Edition = {
e_negative_playing_card = {
name = "Negativo",
text = {
"{C:dark_edition}+#1#{} carte della mano"
},
},
e_negative_generic = {
name = "Negativa",
text = {
"{C:dark_edition}+#1#{} slot"
},
}
},
Enhanced = {
m_gold={
name="Carta dorata",
text={
"{C:money}$#1#{} se hai",
"in mano questa carta",
"alla fine del round",
},
},
m_stone={
name="Carta di pietra",
text={
"{C:chips}+#1#{} fiche",
"nessun valore o seme",
},
},
m_mult={
name="Carta Molt",
text={
"{C:mult}+#1#{} Molt",
},
},
m_lucky={
name="Carta fortunata",
text={
"{C:green}#1# probabilità su #3#{}",
"di {C:mult}+#2#{} Molt",
"{C:green}#6# probabilità su #5#{}",
"di vincere {C:money}$#4#",
},
},
}
},
misc = {
achievement_names = {
hidden_achievement = "???",
},
achievement_descriptions = {
hidden_achievement = "Gioca per scoprirlo!",
},
dictionary = {
b_mods = 'Mod',
b_mods_cap = 'MOD',
b_modded_version = 'Versione Modificata!',
b_steamodded = 'Steamodded',
b_credits = 'Crediti',
b_open_mods_dir = 'Apri cartella Mods',
b_no_mods = 'Nessuna mod rilevata...',
b_mod_list = 'Lista di mod attivate',
b_mod_loader = 'Mod Loader',
b_developed_by = 'sviluppato da ',
b_rewrite_by = 'Riscritto da by ',
b_github_project = 'Progetto Github',
b_github_bugs_1 = 'Puoi segnalare bug e',
b_github_bugs_2 = 'contribuire qui.',
b_disable_mod_badges = 'Disattiva etichette mod',
b_author = 'Autore',
b_authors = 'Autori',
b_unknown = 'Sconosciuto',
b_lovely_mod = '(Lovely Mod) ',
b_by = ' Di: ',
b_priority = 'Priorità: ',
b_config = "Configurazione",
b_additions = 'Aggiunte',
b_stickers = 'Adesivi',
b_stickers = 'Adesivi',
b_achievements = "Obiettivi",
b_applies_stakes_1 = 'Applica ',
b_applies_stakes_1 = 'Applica ',
b_applies_stakes_2 = '',
b_graphics_mipmap_level = "Livello mipmap",
b_browse = 'Sfoglia',
b_search_prompt = 'Cerca mod',
b_search_button = 'Cerca',
b_seeded_unlocks = 'Sblocchi con seed scelto',
b_seeded_unlocks_info = 'Attiva sblocchi e scoperte in sessioni con seed scelto',
ml_achievement_settings = {
'Disattivato',
'Attivato',
'Aggira restrizioni'
},
b_deckskins_lc = 'Colori a basso contrasto',
b_deckskins_hc = 'Colori ad alto contrasto',
b_deckskins_def = 'Colori predefiniti',
b_seeded_unlocks = 'Sblocchi con seed scelto',
b_seeded_unlocks_info = 'Attiva sblocchi e scoperte in sessioni con seed scelto',
ml_achievement_settings = {
'Disattivato',
'Attivato',
'Aggira restrizioni'
},
b_deckskins_lc = 'Colori a basso contrasto',
b_deckskins_hc = 'Colori ad alto contrasto',
b_deckskins_def = 'Colori predefiniti',
b_limit = 'Fino a ',
b_retrigger_single = 'volta',
b_retrigger_plural = 'volte'
},
v_dictionary = {
c_types = '#1# Tipi',
cashout_hidden = '...e #1# in più',
a_xchips = "X#1# fiche",
a_xchips_minus = "-X#1# fiche",
smods_version_mismatch = {
"La versione di Steamodded è cambiata",
"dall'inizio di questa sessione!",
"Continuare potrebbe causare",
"comportamenti anomali e crash.",
"Versione di partenza: #1#",
"Versione attuale: #2#",
}
a_xchips = "X#1# fiche",
a_xchips_minus = "-X#1# fiche",
smods_version_mismatch = {
"La versione di Steamodded è cambiata",
"dall'inizio di questa sessione!",
"Continuare potrebbe causare",
"comportamenti anomali e crash.",
"Versione di partenza: #1#",
"Versione attuale: #2#",
}
},
}
}

View file

@ -98,7 +98,7 @@ return {
},
card_extra_p_dollars = {
text = {
"打出并计分时获得{C:money}$#1#{}",
"打出并计分时获得{C:money}#1#{}",
}
},
card_extra_h_chips = {
@ -136,14 +136,55 @@ return {
"回合结束时还在手牌中则获得{C:money}#1#{}",
},
},
card_extra_repetitions = {
text = {
"重新触发",
"此卡牌{C:attention}#1#{} #2#",
},
},
artist = {
text = {
"{C:inactive}艺术家",
},
},
artist_credit = {
name = "艺术家",
text = {
"{E:1}#1#{}"
},
},
generic_card_limit = {
name = "卡限额",
text = {
'{C:dark_edition}#1#{}个区域槽位'
}
},
generic_card_limit_plural = {
name = "卡限额",
text = {
'{C:dark_edition}#1#{}个区域槽位'
}
},
generic_extra_slots = {
name = "已使用槽位",
text = {
'填充{C:dark_edition}#1#{}个槽位'
}
}
},
Edition = {
e_negative_playing_card = {
name = "负片",
text = {
"手牌上限{C:dark_edition}+#1#"
"手牌上限{C:dark_edition}+#1#{}"
},
},
e_negative_generic = {
name = "负片",
text = {
"{C:dark_edition}+#1#{}个区域槽位"
},
}
},
Enhanced = {
m_gold={
@ -151,7 +192,7 @@ return {
text={
"如果这张卡牌",
"在回合结束时还在手牌中",
"你获得{C:money}$#1#{}",
"你获得{C:money}#1#{}",
},
},
m_stone={
@ -167,6 +208,15 @@ return {
"{C:mult}#1#{}倍率",
},
},
m_lucky={
name="幸运牌",
text={
"{C:green}#1#/#3#{}几率",
"{C:mult}+#2#{}倍率",
"{C:green}#1#/#5#{}几率",
"获得{C:money}$#4#",
},
},
},
},
misc = {
@ -218,6 +268,7 @@ return {
b_deckskins_lc = '低对比度配色',
b_deckskins_hc = '高对比度配色',
b_deckskins_def = '默认配色',
b_limit = '最多',
},
v_dictionary = {
c_types = '共有#1#种',

View file

@ -70,7 +70,9 @@ pattern = '''
local X, Y, W, H = self.T.x, self.T.y, self.T.w, self.T.h
'''
payload = '''
for key, _ in pairs(self.T) do
self.T[key] = self.original_T[key]
if delay_sprites ~= 'quantum' then
for key, _ in pairs(self.T) do
self.T[key] = self.original_T[key]
end
end
'''

View file

@ -288,7 +288,7 @@ if card.area and area_set[card.area] then
if type(jokers) ~= 'table' then jokers = nil end
if jokers or triggered then
ret.jokers = jokers
if not (context.retrigger_joker_check or context.retrigger_joker) and not (jokers and jokers.no_retrigger) and not context.mod_probability and not context.fix_probability then
if not (context.retrigger_joker_check or context.retrigger_joker) and not (jokers and jokers.no_retrigger) and not SMODS.is_getter_context(context) then
local retriggers = SMODS.calculate_retriggers(card, context, ret)
if next(retriggers) then
ret.retriggers = retriggers
@ -1019,6 +1019,7 @@ for i=1, hand_space do --draw cards from deckL
end
'''
payload = '''
SMODS.cards_to_draw = (SMODS.cards_to_draw or 0) + math.max(hand_space, 0)
SMODS.drawn_cards = {}
'''
[[patches]]
@ -1036,6 +1037,13 @@ for i=1, hand_space do --draw cards from deckL
end
'''
payload = '''
G.E_MANAGER:add_event(Event({
trigger = 'immediate',
func = function()
SMODS.cards_to_draw = SMODS.cards_to_draw - math.max(hand_space, 0)
return true
end
}))
G.E_MANAGER:add_event(Event({
trigger = 'before',
delay = 0.4,
@ -1080,7 +1088,7 @@ end
'''
payload = '''
local flags = SMODS.calculate_context({drawing_cards = true, amount = hand_space})
hand_space = math.min(#G.deck.cards, flags.cards_to_draw or hand_space)
hand_space = math.min(#G.deck.cards, flags.cards_to_draw or flags.modify or hand_space)
'''
# Used to identify first hand of round
@ -1969,5 +1977,5 @@ delay(0.4); ease_ante(1); delay(0.4); check_for_unlock({type = 'ante_up', ante =
'''
position = 'at'
payload = '''
delay(0.4); ease_ante(1, true); delay(0.4); check_for_unlock({type = 'ante_up', ante = G.GAME.round_resets.ante + 1})
delay(0.4); SMODS.ante_end = true; ease_ante(1); SMODS.ante_end = nil; delay(0.4); check_for_unlock({type = 'ante_up', ante = G.GAME.round_resets.ante + 1})
'''

View file

@ -393,21 +393,39 @@ local loc_target = localize(target)'''
[[patches]]
[patches.pattern]
target = 'functions/common_events.lua'
pattern = 'elseif not v.boss.showdown*'
pattern = '''
if not v.boss then
elseif not v.boss.showdown and (v.boss.min <= math.max(1, G.GAME.round_resets.ante) and ((math.max(1, G.GAME.round_resets.ante))%G.GAME.win_ante ~= 0 or G.GAME.round_resets.ante < 2)) then
eligible_bosses[k] = true
elseif v.boss.showdown and (G.GAME.round_resets.ante)%G.GAME.win_ante == 0 and G.GAME.round_resets.ante >= 2 then
eligible_bosses[k] = true
end
'''
match_indent = true
position = 'before'
position = 'at'
payload = '''
local res, options = SMODS.add_to_pool(v)
options = options or {}
if not v.boss then
elseif options.ignore_showdown_check then
eligible_bosses[k] = res and true or nil
elseif v.in_pool and type(v.in_pool) == 'function' then
local res, options = SMODS.add_to_pool(v)
if
(
((G.GAME.round_resets.ante)%G.GAME.win_ante == 0 and G.GAME.round_resets.ante >= 2) ==
(v.boss.showdown or false)
) or
(options or {}).ignore_showdown_check
)
then
eligible_bosses[k] = res and true or nil
end'''
end
elseif not v.boss.showdown and (v.boss.min <= math.max(1, G.GAME.round_resets.ante) and ((math.max(1, G.GAME.round_resets.ante))%G.GAME.win_ante ~= 0 or G.GAME.round_resets.ante < 2)) then
eligible_bosses[k] = res and true or nil
elseif v.boss.showdown and (G.GAME.round_resets.ante)%G.GAME.win_ante == 0 and G.GAME.round_resets.ante >= 2 then
eligible_bosses[k] = res and true or nil
end
'''
# G.UIDEF.challenge_description_tab
[[patches]]

View file

@ -260,11 +260,12 @@ if card.ability.consumeable then
if (card.area == G.pack_cards and G.pack_cards) then
'''
payload = '''
if card.ability.consumeable and card.area == G.pack_cards and booster_obj and booster_obj.select_card and card:selectable_from_pack(booster_obj) then
if card.ability.consumeable and card.area == G.pack_cards and G.pack_cards and booster_obj and SMODS.card_select_area(card, booster_obj) and card:selectable_from_pack(booster_obj) then
if (card.area == G.pack_cards and G.pack_cards) then
local select_button_text = SMODS.get_select_text(card, booster_obj) or localize('b_select')
return {n=G.UIT.ROOT, config = {padding = 0, 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, maxw = 0.9*card.T.w - 0.15, minh = 0.3*card.T.h, hover = true, shadow = true, colour = G.C.UI.BACKGROUND_INACTIVE, one_press = true, button = 'use_card', func = 'can_select_from_booster'}, nodes={
{n=G.UIT.T, config={text = localize('b_select'),colour = G.C.UI.TEXT_LIGHT, scale = 0.45, shadow = true}}
{n=G.UIT.T, config={text = select_button_text, colour = G.C.UI.TEXT_LIGHT, scale = 0.45, shadow = true}}
}},
}}
end
@ -337,7 +338,7 @@ match_indent = true
position = 'at'
pattern = "if e.config.ref_table.ability.set ~= 'Joker' or (e.config.ref_table.edition and e.config.ref_table.edition.negative) or #G.jokers.cards < G.jokers.config.card_limit then"
payload = '''local card = e.config.ref_table
local card_limit = card.ability.card_limit
local card_limit = card.ability.card_limit - card.ability.extra_slots_used
if card.ability.set ~= 'Joker' or #G.jokers.cards < G.jokers.config.card_limit + card_limit then'''
# Card:redeem()

View file

@ -292,7 +292,7 @@ position = "at"
payload = """local hand_space = e
local cards_to_draw = {}
if not hand_space then
local limit = G.hand.config.card_limit - #G.hand.cards
local limit = G.hand.config.card_limit - #G.hand.cards - (SMODS.cards_to_draw or 0)
local unfixed = not G.hand.config.fixed_limit
local n = 0
while n < #G.deck.cards do
@ -307,5 +307,6 @@ if not hand_space then
n = n + 1
end
hand_space = #cards_to_draw
end"""
end
"""
match_indent = true

View file

@ -103,10 +103,12 @@ match_indent = true
payload = '''
elseif _c.generate_ui and type(_c.generate_ui) == 'function' then
local specific_vars = specific_vars or {}
if is_info_queue then specific_vars.is_info_queue = true end
_c:generate_ui(info_queue, card, desc_nodes, specific_vars, full_UI_table)
if is_info_queue then
desc_nodes.loc_name = {}
if desc_nodes ~= full_UI_table.main then
-- TODO should be moved into generate_ui;
-- also the multiple generate_ui cases should be refactored
-- to work off a base implementation
desc_nodes.name_styled = {}
local set = name_override and "Other" or _c.set
local key = name_override or _c.key
if set == "Seal" then
@ -115,9 +117,9 @@ elseif _c.generate_ui and type(_c.generate_ui) == 'function' then
if not G.localization.descriptions[set] or not G.localization.descriptions[set][_c.key] then set = "Other" end
end
--localize{type = 'name', key = key, set = set, nodes = desc_nodes.loc_name, fixed_scale = 0.63, no_pop_in = true, no_shadow = true, y_offset = 0, no_spacing = true, no_bump = true, vars = (_c.create_fake_card and _c.loc_vars and (_c:loc_vars({}, _c:create_fake_card()) or {}).vars) or {colours = {}}}
--desc_nodes.loc_name = SMODS.info_queue_desc_from_rows(desc_nodes.loc_name, true)
--desc_nodes.loc_name.config.align = "cm"
localize{type = 'name', key = key, set = set, nodes = desc_nodes.name_styled, fixed_scale = 0.63, no_pop_in = true, no_shadow = true, y_offset = 0, no_spacing = true, no_bump = true, vars = (_c.create_fake_card and _c.loc_vars and (_c:loc_vars({}, _c:create_fake_card()) or {}).vars) or {colours = {}}}
desc_nodes.name_styled = SMODS.info_queue_desc_from_rows(desc_nodes.name_styled, true)
desc_nodes.name_styled.config.align = "cm"
end
if specific_vars and specific_vars.pinned then info_queue[#info_queue+1] = {key = 'pinned_left', set = 'Other'} end
if specific_vars and specific_vars.sticker then info_queue[#info_queue+1] = {key = string.lower(specific_vars.sticker)..'_sticker', set = 'Other'} end'''
@ -491,18 +493,33 @@ end'''
[[patches]]
[patches.pattern]
target = 'functions/button_callbacks.lua'
pattern = "if card.area then card.area:remove_card(card) end"
match_indent = true
position = 'at'
pattern = '''
if G.booster_pack and not G.booster_pack.alignment.offset.py and (card.ability.consumeable or not (G.GAME.pack_choices and G.GAME.pack_choices > 1)) then
'''
payload = '''
local nc
local select_to = card.area == G.pack_cards and booster_obj and booster_obj.select_card and card:selectable_from_pack(booster_obj)
local select_to = card.area == G.pack_cards and G.pack_cards and booster_obj and SMODS.card_select_area(card, booster_obj) and card:selectable_from_pack(booster_obj)
if card.ability.consumeable and not select_to then
local obj = card.config.center
if obj.keep_on_use and type(obj.keep_on_use) == 'function' then
nc = obj:keep_on_use(card)
end
end
if G.booster_pack and not G.booster_pack.alignment.offset.py and ((not select_to and card.ability.consumeable) or not (G.GAME.pack_choices and G.GAME.pack_choices > 1)) then
'''
# G.FUNCS.use_card()
[[patches]]
[patches.pattern]
target = 'functions/button_callbacks.lua'
pattern = "if card.area then card.area:remove_card(card) end"
match_indent = true
position = 'at'
payload = '''
if not card.from_area then card.from_area = card.area end
if card.area and (not nc or card.area == G.pack_cards) then card.area:remove_card(card) end'''
[[patches]]

View file

@ -8,15 +8,26 @@ priority = -5
[patches.pattern]
target = "functions/UI_definitions.lua"
pattern = "local challenge_unlocked = G.PROFILES[G.SETTINGS.profile].challenges_unlocked and (G.PROFILES[G.SETTINGS.profile].challenges_unlocked >= k)"
position = 'after'
payload = """
if v.unlocked and type(v.unlocked) == 'function' then
challenge_unlocked = v:unlocked()
elseif type(v.unlocked) == 'boolean' then
challenge_unlocked = v.unlocked
end
challenge_unlocked = challenge_unlocked or G.PROFILES[G.SETTINGS.profile].all_unlocked
position = 'at'
payload = "local challenge_unlocked = SMODS.challenge_is_unlocked(v, k)"
match_indent = true
# function G.UIDEF.challenges() - fix challenge unlock count
[[patches]]
[patches.pattern]
target = "functions/UI_definitions.lua"
pattern = """
local _ch_tab = {comp = _ch_comp, unlocked = G.PROFILES[G.SETTINGS.profile].challenges_unlocked}
"""
position = 'at'
payload = """
local unlock_count = 0
for k, v in ipairs(G.CHALLENGES) do
if SMODS.challenge_is_unlocked(v, k) then
unlock_count = unlock_count + 1
end
end
local _ch_tab = {comp = _ch_comp, unlocked = unlock_count}
"""
match_indent = true

View file

@ -301,9 +301,9 @@ payload = '''
SMODS.enh_cache:write(self, nil)
if self.ability and not initial then
self.ability.card_limit = self.ability.card_limit - (self.config.center.card_limit or 0)
self.ability.extra_slots_used = self.ability.extra_slots_used - (self.config.center.extra_slots_used or 0)
if self.area then self.area:handle_card_limit(-1 * (self.config.center.card_limit or 0), -1 * (self.config.center.extra_slots_used or 0)) end
self.ability.card_limit = self.ability.card_limit - (self.config.center.config.card_limit or 0)
self.ability.extra_slots_used = self.ability.extra_slots_used - (self.config.center.config.extra_slots_used or 0)
if self.area then self.area:handle_card_limit(-1 * (self.config.center.config.card_limit or 0), -1 * (self.config.center.config.extra_slots_used or 0)) end
end
if self.ability and not initial then

View file

@ -99,7 +99,7 @@ pattern = "bypass_lock = self.bypass_lock,"
position = "after"
payload = """
unique_val = self.unique_val,
unique_val__saved_ID = self.ID,
unique_val__saved_ID = self.unique_val__saved_ID or self.ID,
ignore_base_shader = self.ignore_base_shader,
ignore_shadow = self.ignore_shadow,"""
match_indent = true
@ -112,6 +112,7 @@ pattern = "self.bypass_lock = cardTable.bypass_lock"
position = "after"
payload = """
self.unique_val = cardTable.unique_val or self.unique_val
self.unique_val__saved_ID = cardTable.unique_val__saved_ID or self.unique_val__saved_ID
if cardTable.unique_val__saved_ID and G.ID <= cardTable.unique_val__saved_ID then
G.ID = cardTable.unique_val__saved_ID + 1
end
@ -131,11 +132,6 @@ position = 'at'
match_indent = true
payload = '''function generate_card_ui(_c, full_UI_table, specific_vars, card_type, badges, hide_desc, main_start, main_end, card)
if _c.specific_vars then specific_vars = _c.specific_vars end
local is_info_queue = false
if specific_vars and specific_vars.is_info_queue then
is_info_queue = true
specific_vars = nil
end
'''
[[patches]]
@ -638,13 +634,13 @@ if success then st = _st else sendWarnMessage(_st, "LuaSteam"); st = {} end"""
overwrite = true
match_indent = true
# copy_card edition config
# copy_card: Subtract from .ability.card_limit
[[patches]]
[patches.pattern]
target = 'functions/common_events.lua'
position = 'at'
position = 'before'
match_indent = true
pattern = 'new_card:set_edition(other.edition or {}, nil, true)'
pattern = 'if not strip_edition then'
payload = '''
if other.edition then
new_card.ability.card_limit = new_card.ability.card_limit - (other.edition.card_limit or 0)
@ -653,8 +649,16 @@ end
if other.seal then
new_card.ability.card_limit = new_card.ability.card_limit - (other.ability.seal.card_limit or 0)
new_card.ability.extra_slots_used = new_card.ability.extra_slots_used - (other.ability.seal.extra_slots_used or 0)
end
new_card:set_edition(other.edition or {}, nil, true)
end'''
# copy_card edition config
[[patches]]
[patches.pattern]
target = 'functions/common_events.lua'
position = 'after'
match_indent = true
pattern = 'new_card:set_edition(other.edition or {}, nil, true)'
payload = '''
for k,v in pairs(other.edition or {}) do
if type(v) == 'table' then
new_card.edition[k] = copy_table(v)

View file

@ -16,9 +16,7 @@ payload = '''
args.AUT = args.AUT or {}
args.AUT.box_colours = {}
if (args.type == 'descriptions' or args.type == 'other') and type(loc_target.text) == 'table' and type(loc_target.text[1]) == 'table' then
if not args.is_info_queue then
args.AUT.multi_box = {}
end
args.AUT.multi_box = args.AUT.multi_box or {}
for i, box in ipairs(loc_target.text_parsed) do
for j, line in ipairs(box) do
local final_line = SMODS.localize_box(line, args)

View file

@ -12,7 +12,7 @@ priority = -5
target = "functions/common_events.lua"
pattern = "if _c.effect == 'Mult Card' then loc_vars = {cfg.mult}"
position = "at"
payload = "if _c.effect == 'Mult Card' then loc_vars = {SMODS.signed(cfg.mult + (specific_vars and specific_vars.bonus_mult or 0))}"
payload = "if _c.effect == 'Mult Card' then loc_vars = {SMODS.signed(cfg.mult)}"
match_indent = true
# generate_card_ui(): gold card special case
@ -21,7 +21,7 @@ match_indent = true
target = "functions/common_events.lua"
pattern = "elseif _c.effect == 'Gold Card' then loc_vars = {cfg.h_dollars}"
position = "at"
payload = "elseif _c.effect == 'Gold Card' then loc_vars = {specific_vars and SMODS.signed_dollars(specific_vars.total_h_dollars) or cfg.h_dollars and SMODS.signed_dollars(cfg.h_dollars) or 0}"
payload = "elseif _c.effect == 'Gold Card' then loc_vars = {SMODS.signed_dollars(cfg.h_dollars)}"
match_indent = true
# generate_card_ui(): stone card special case

View file

@ -143,9 +143,7 @@ pattern = "if add and not G.GAME.banned_keys[v.key] then"
match_indent = true
position = 'before'
payload = '''
if v.in_pool and type(v.in_pool) == 'function' then
add = in_pool and (add or pool_opts.override_base_checks)
end
add = in_pool and (add or pool_opts.override_base_checks)
'''
[[patches]]

View file

@ -327,8 +327,12 @@ SMODS.scale_card(self, {
ref_table = self.ability,
ref_value = "x_mult",
scalar_value = "extra",
message_colour = G.C.MULT
no_message = true
})
return {
extra = {focus = self, message = localize('k_upgrade_ex'), colour = G.C.MULT},
card = self
}
'''
# Obelisk
[[patches]]

View file

@ -92,13 +92,12 @@ end
# Add Scoring_Parameters to update_hand_text
[[patches]]
[patches.pattern]
[patches.regex]
target = 'functions/common_events.lua'
match_indent = true
position = 'before'
pattern = '''
if vals.handname and G.GAME.current_round.current_hand.handname ~= vals.handname then
'''
position = 'at'
line_prepend = '$indent'
pattern = '''(?<indent>[\t ]*)if vals\.[A-z0-9\n\t .~=()'\-+,<;>:{}]+mult:juice_up\(\) end\n[\t ]+end'''
payload = '''
for name, parameter in pairs(SMODS.Scoring_Parameters) do
if vals[name] and G.GAME.current_round.current_hand[name] ~= vals[name] then
@ -109,7 +108,7 @@ for name, parameter in pairs(SMODS.Scoring_Parameters) do
end
if type(vals[name]) == 'string' then delta = vals[name] end
G.GAME.current_round.current_hand[name] = vals[name]
G.hand_text_area[name] = G.hand_text_area[name] or G.HUD:get_UIE_by_ID('hand_'..name..'_area') or nil
G.hand_text_area[name] = G.hand_text_area[name] or G.HUD:get_UIE_by_ID('hand_'..name) or nil
if G.hand_text_area[name] then
G.hand_text_area[name]:update(0)
if vals.StatusText then
@ -121,9 +120,10 @@ for name, parameter in pairs(SMODS.Scoring_Parameters) do
cover_colour = mix_colours(parameter.colour, col, 0.1),
emboss = 0.05,
align = 'cm',
cover_align = 'cm'
cover_align = G.hand_text_area[name].parent.config.align
})
end
if (vals[name.."_juice"] or parameter.juice_on_update) and not G.TAROT_INTERRUPT then G.hand_text_area[name]:juice_up() end
end
end
end

View file

@ -0,0 +1,126 @@
[manifest]
version = "1.0.0"
dump_lua = true
priority = -10
[[patches]]
[patches.pattern]
target = 'engine/text.lua'
pattern = "if self.config.bump then letter.offset.y = (G.SETTINGS.reduced_motion and 0 or 1)*self.bump_amount*math.sqrt(self.scale)*7*math.max(0, (5+self.bump_rate)*math.sin(self.bump_rate*G.TIMERS.REAL+200*k) - 3 - self.bump_rate) end"
position = "after"
payload = '''if self.config.text_effect and SMODS.DynaTextEffects[self.config.text_effect] and type(SMODS.DynaTextEffects[self.config.text_effect].func) == "function" then
SMODS.DynaTextEffects[self.config.text_effect].func(self, k, letter) -- k is index
end'''
match_indent = true
[[patches]]
[patches.pattern]
target = 'functions/misc_functions.lua'
pattern = " local _float, _silent, _pop_in, _bump, _spacing = nil, true, nil, nil, nil"
position = "after"
payload = '''local text_effects'''
match_indent = true
[[patches]]
[patches.pattern]
target = 'functions/misc_functions.lua'
pattern = " _bump = true; _spacing = 1"
position = "after"
payload = '''elseif SMODS.DynaTextEffects[part.control.E] then
text_effects = part.control.E'''
match_indent = true
[[patches]]
[patches.pattern]
target = 'functions/misc_functions.lua'
pattern = " spacing = _spacing,"
position = "after"
payload = '''text_effect = text_effects,'''
match_indent = true
[[patches]]
[patches.pattern]
target = 'engine/text.lua'
pattern = """ love.graphics.draw(
letter.letter,
0.5*(letter.dims.x - letter.offset.x)*self.font.FONTSCALE/G.TILESIZE + _shadow_norm.x,
0.5*(letter.dims.y - letter.offset.y)*self.font.FONTSCALE/G.TILESIZE + _shadow_norm.y,
letter.r or 0,
real_pop_in*letter.scale*self.scale*self.font.FONTSCALE/G.TILESIZE,
real_pop_in*letter.scale*self.scale*self.font.FONTSCALE/G.TILESIZE,
0.5*letter.dims.x/(self.scale),
0.5*letter.dims.y/(self.scale)
)"""
position = "before"
payload = '''if self.config.text_effect and SMODS.DynaTextEffects[self.config.text_effect] and type(SMODS.DynaTextEffects[self.config.text_effect].draw_letter) == "function" then
SMODS.DynaTextEffects[self.config.text_effect].draw_letter(self, k, letter, false) -- actual text
else'''
match_indent = true
[[patches]]
[patches.pattern]
target = 'engine/text.lua'
pattern = """ love.graphics.draw(
letter.letter,
0.5*(letter.dims.x - letter.offset.x)*self.font.FONTSCALE/G.TILESIZE + _shadow_norm.x,
0.5*(letter.dims.y - letter.offset.y)*self.font.FONTSCALE/G.TILESIZE + _shadow_norm.y,
letter.r or 0,
real_pop_in*letter.scale*self.scale*self.font.FONTSCALE/G.TILESIZE,
real_pop_in*letter.scale*self.scale*self.font.FONTSCALE/G.TILESIZE,
0.5*letter.dims.x/(self.scale),
0.5*letter.dims.y/(self.scale)
)"""
position = "after"
payload = '''end'''
match_indent = true
[[patches]]
[patches.pattern]
target = 'engine/text.lua'
pattern = """ love.graphics.draw(
letter.letter,
0.5*(letter.dims.x - letter.offset.x)*self.font.FONTSCALE/G.TILESIZE -self.shadow_parrallax.x*self.scale/(G.TILESIZE),
0.5*(letter.dims.y)*self.font.FONTSCALE/G.TILESIZE -self.shadow_parrallax.y*self.scale/(G.TILESIZE),
letter.r or 0,
real_pop_in*self.scale*self.font.FONTSCALE/G.TILESIZE,
real_pop_in*self.scale*self.font.FONTSCALE/G.TILESIZE,
0.5*letter.dims.x/self.scale,
0.5*letter.dims.y/self.scale
)
love.graphics.translate(letter.dims.x*self.font.FONTSCALE/G.TILESIZE, 0)"""
position = "before"
payload = '''if self.config.text_effect and SMODS.DynaTextEffects[self.config.text_effect] and type(SMODS.DynaTextEffects[self.config.text_effect].draw_shadow) == "function" then
SMODS.DynaTextEffects[self.config.text_effect].draw_shadow(self, k, letter) -- shadow
else'''
match_indent = true
[[patches]]
[patches.pattern]
target = 'engine/text.lua'
pattern = """ love.graphics.draw(
letter.letter,
0.5*(letter.dims.x - letter.offset.x)*self.font.FONTSCALE/G.TILESIZE -self.shadow_parrallax.x*self.scale/(G.TILESIZE),
0.5*(letter.dims.y)*self.font.FONTSCALE/G.TILESIZE -self.shadow_parrallax.y*self.scale/(G.TILESIZE),
letter.r or 0,
real_pop_in*self.scale*self.font.FONTSCALE/G.TILESIZE,
real_pop_in*self.scale*self.font.FONTSCALE/G.TILESIZE,
0.5*letter.dims.x/self.scale,
0.5*letter.dims.y/self.scale
)
love.graphics.translate(letter.dims.x*self.font.FONTSCALE/G.TILESIZE, 0)"""
position = "after"
payload = '''end'''
match_indent = true
[[patches]]
[patches.pattern]
target = 'engine/text.lua'
pattern = """ if self.children.particle_effect then self.children.particle_effect:draw() end"""
position = "before"
payload = '''if self.config.text_effect and SMODS.DynaTextEffects[self.config.text_effect] and type(SMODS.DynaTextEffects[self.config.text_effect].draw_override) == "function" then
SMODS.DynaTextEffects[self.config.text_effect].draw_override(self)
return
end'''
match_indent = true

View file

@ -308,19 +308,6 @@ payload = "badges[#badges + 1] = create_badge(((card.ability.name == 'Pluto' or
# Fixing description error when info_queue has multi-box descriptions.
[[patches]]
[patches.pattern]
target = 'functions/common_events.lua'
pattern = '''
generate_card_ui(v, full_UI_table)
'''
position = "at"
payload = '''
generate_card_ui(v, full_UI_table, {is_info_queue = true})
'''
match_indent = true
[[patches]]
[patches.pattern]
target = 'functions/misc_functions.lua'
@ -336,6 +323,7 @@ y_offset = -0.6,
position = "at"
payload = '''
bump = not args.no_bump,
text_effect = SMODS.DynaTextEffects[part.control.E] and part.control.E,
silent = not args.no_silent,
pop_in = (not args.no_pop_in and (args.pop_in or 0)) or nil,
pop_in_rate = (not args.no_pop_in and (args.pop_in_rate or 4)) or nil,
@ -352,17 +340,22 @@ desc_nodes.name = localize{type = 'name_text', key = name_override or _c.key, se
'''
position = "after"
payload = '''
local set = name_override and "Other" or _c.set
local key = name_override or _c.key
if set == "Seal" then
if G.localization.descriptions["Other"][_c.key.."_seal"] then set = "Other"; key = key.."_seal" end
else
if not G.localization.descriptions[set][_c.key] then set = "Other" end
-- If statement guards against setting `name_styled` twice. This apparently happens
-- when generating ui for Lucky Cards: smods takes ownership of vanilla, so
-- this code is reached in both places it appears
if not desc_nodes.name_styled then
local set = name_override and "Other" or _c.set
local key = name_override or _c.key
if set == "Seal" then
if G.localization.descriptions["Other"][_c.key.."_seal"] then set = "Other"; key = key.."_seal" end
else
if not G.localization.descriptions[set][_c.key] then set = "Other" end
end
desc_nodes.name_styled = {}
localize{type = 'name', key = key, set = set, nodes = desc_nodes.name_styled, fixed_scale = 0.63, no_pop_in = true, no_shadow = true, y_offset = 0, no_spacing = true, no_bump = true, vars = (_c.create_fake_card and _c.loc_vars and (_c:loc_vars({}, _c:create_fake_card()) or {}).vars) or {colours = {}}}
desc_nodes.name_styled = SMODS.info_queue_desc_from_rows(desc_nodes.name_styled, true)
desc_nodes.name_styled.config.align = "cm"
end
desc_nodes.loc_name = {}
localize{type = 'name', key = key, set = set, nodes = desc_nodes.loc_name, fixed_scale = 0.63, no_pop_in = true, no_shadow = true, y_offset = 0, no_spacing = true, no_bump = true, vars = (_c.create_fake_card and _c.loc_vars and (_c:loc_vars({}, _c:create_fake_card()) or {}).vars) or {colours = {}}}
desc_nodes.loc_name = SMODS.info_queue_desc_from_rows(desc_nodes.loc_name, true)
desc_nodes.loc_name.config.align = "cm"
'''
match_indent = true
@ -374,25 +367,31 @@ function info_tip_from_rows(desc_nodes, name)
'''
position = "after"
payload = '''
local name_nodes = {}
local function deep_find(t, index)
if t[index] then return true end
for i,v in pairs(t) do
if i == index then return true end
if type(v) == "table" then
return deep_find(v, index)
end
end
return false
end
if not desc_nodes.loc_name or not deep_find(desc_nodes.loc_name, "object") then
local name_nodes
if not desc_nodes.name_styled then
name_nodes = {{n=G.UIT.T, config={text = name, scale = 0.32, colour = G.C.UI.TEXT_LIGHT}}}
else
name_nodes = {desc_nodes.loc_name}
name_nodes = {desc_nodes.name_styled}
end
'''
match_indent = true
[[patches]]
[patches.pattern]
target = 'engine/node.lua'
pattern = '''
self.children.h_popup.states.drag.can = true
'''
position = "after"
payload = '''
-- Fixes styled info_queue names
-- This ensures show_infotip runs just after the main hover box is created instead of being able to fall one frame after
if ((self.children.h_popup.UIRoot.children[1] or {}).config or {}).func == "show_infotip" then
G.FUNCS.show_infotip(self.children.h_popup.UIRoot.children[1])
end
'''
match_indent = true
[[patches]]
[patches.pattern]
target = 'functions/UI_definitions.lua'

View file

@ -24,7 +24,7 @@
---@field inject? fun(self: SMODS.Challenge|table, i?: number) Called during `inject_class`. Injects the object into the game.
---@field take_ownership? fun(self: SMODS.Challenge|table, key: string, obj: SMODS.Challenge|table, silent?: boolean): nil|table|SMODS.Challenge Takes control of vanilla objects. Child class must have get_obj for this to function
---@field get_obj? fun(self: SMODS.Challenge|table, key: string): SMODS.Challenge|table? Returns an object if one matches the `key`.
---@field unlocked? fun(self: SMODS.Challenge|table): boolean
---@field unlocked? fun(self: SMODS.Challenge|table): boolean | boolean
---@field button_colour? table HEX color of the button on the challenge list.
---@field calculate? fun(self: SMODS.Challenge|table, context: CalcContext|table): table?, boolean? Calculates effects based on parameters in `context`. See [SMODS calculation](https://github.com/Steamodded/smods/wiki/calculate_functions) docs for details.
---@field apply? fun(self: SMODS.Challenge|table) Applied modifiers at the start of a run.

View file

@ -0,0 +1,42 @@
---@meta
---@class SMODS.DynaTextEffect: SMODS.GameObject
---@field obj_table? table<string, SMODS.DynaTextEffect|table> Table of objects registered to this class.
---@field super? SMODS.GameObject|table Parent class.
---@field extend? fun(self: SMODS.DynaTextEffect|table, o: SMODS.DynaTextEffect|table): table Primary method of creating a class.
---@field __call? fun(self: SMODS.DynaTextEffect|table, o: SMODS.DynaTextEffect|table): nil|table|SMODS.DynaTextEffect
---@field check_duplicate_register? fun(self: SMODS.DynaTextEffect|table): boolean? Ensures objects already registered will not register.
---@field check_duplicate_key? fun(self: SMODS.DynaTextEffect|table): boolean? Ensures objects with duplicate keys will not register. Checked on `__call` but not `take_ownership`. For take_ownership, the key must exist.
---@field register? fun(self: SMODS.DynaTextEffect|table) Registers the object.
---@field check_dependencies? fun(self: SMODS.DynaTextEffect|table): boolean? Returns `true` if there's no failed dependencies.
---@field process_loc_text? fun(self: SMODS.DynaTextEffect|table) Called during `inject_class`. Handles injecting loc_text.
---@field send_to_subclasses? fun(self: SMODS.DynaTextEffect|table, func: string, ...: any) Starting from this class, recusively searches for functions with the given key on all subordinate classes and run all found functions with the given arguments.
---@field pre_inject_class? fun(self: SMODS.DynaTextEffect|table) Called before `inject_class`. Injects and manages class information before object injection.
---@field post_inject_class? fun(self: SMODS.DynaTextEffect|table) Called after `inject_class`. Injects and manages class information after object injection.
---@field inject_class? fun(self: SMODS.DynaTextEffect|table) Injects all direct instances of class objects by calling `obj:inject` and `obj:process_loc_text`. Also injects anything necessary for the class itself. Only called if class has defined both `obj_table` and `obj_buffer`.
---@field inject? fun(self: SMODS.DynaTextEffect|table, i?: number) Called during `inject_class`. Injects the object into the game.
---@field take_ownership? fun(self: SMODS.DynaTextEffect|table, key: string, obj: SMODS.DynaTextEffect|table, silent?: boolean): nil|table|SMODS.DynaTextEffect Takes control of vanilla objects. Child class must have get_obj for this to function
---@field get_obj? fun(self: SMODS.DynaTextEffect|table, key: string): SMODS.DynaTextEffect|table? Returns an object if one matches the `key`.
---@field func fun(dynatext: DynaText, index: number, letter: DynaTextLetter|table) function to modify each letter. DynaText being the main object itself. Index is the index of current letter in the dynatext
---@field draw_letter fun(dynatext: DynaText, index: number, letter: DynaTextLetter|table) function to draw each letter. DynaText being the main object itself. Index is the index of current letter in the dynatext
---@field draw_shadow fun(dynatext: DynaText, index: number, letter: DynaTextLetter|table) function to draw each letter's shadow. DynaText being the main object itself. Index is the index of current letter in the dynatext
---@field draw_override fun(dynatext: DynaText) wholly overrides the draw function for the dynatext. you will have to align everything yourselves (advanced)
---@overload fun(self: SMODS.DynaTextEffect): SMODS.DynaTextEffect
SMODS.DynaTextEffect = setmetatable({}, {
__call = function(self)
return self
end
})
---@type table<string, SMODS.DynaTextEffect|table>
SMODS.DynaTextEffects = {}
---@class DynaTextLetter
---@field pop_in number Determines how the letter gradually pops in
---@field r number Rotation of the letter in radians, defaults to 0
---@field scale number Scale of the letter with the normal size being 1
---@field dims table|{x: integer, y: integer} a hashtable with x and y as letter's dimension. in this case it does NOT modify the size that it is drawn. it instead modifies how far apart each letter are
---@field offset table|{x: integer, y: integer} a hashtable with x and y to specify the letter's offset from the main dynatext alignment
---@field letter love.graphics.Text a replaceable text object that will get drawn
---@class love.graphics.Text

View file

@ -256,7 +256,7 @@ function create_UIBox_your_collection_stickers() end
---@param table
---@field scale? number Set scale of text
---@field colour? table HEX colour of the container
---@field type? string Type of scoring component - defaults to `'mult'`
---@field type string Type of scoring component, ex. 'mult'. Can take the key of a Scoring_Parameter
---@field align? string Must be two letters, first indicates vertical alignment, second indicates horizontal alignment
---@field func? string Reference to function in `G.FUNCS` that controls changing the text - defaults to `'hand_'..type..'_UI_set'`
---@field text? string Key of value in `G.GAME.current_round.current_hand` - defaults to `type..'_text'`

View file

@ -73,7 +73,7 @@
---@field from_area? CardArea|table CardArea the card is being drawn from.
---@field modify_hand? true Check if `true` for modifying the chips and mult of the played hand.
---@field drawing_cards? true `true` when cards are being drawn
---@field amount? number Used for in some contexts to specify a numerical amount.
---@field amount? number Used for in some contexts to specify a numerical amount.
---@field evaluate_poker_hand? integer Check if `true` for modifying the name, display name or contained poker hands when evaluating a hand.
---@field display_name? PokerHands|'Royal Flush'|string Display name of the scoring poker hand.
---@field mod_probability? true Check if `true` for effects that make additive or multiplicative modifications to probabilities.
@ -104,6 +104,13 @@
---@field from_shop? true Check if `true` if money changed during the shop.
---@field from_consumeable? true Check if `true` if money changed by a consumable.
---@field from_scoring? true Check if `true` if money changed during scoring.
---@field modify_ante? number The amount the ante changes by, check for effects before the ante changes.
---@field ante_change? true Check if `true` for effects when the ante changes.
---@field ante_end? true Check if `true` for when the ante change is for reaching the end of the ante.
---@field setting_ability? true Check if `true` for effects after a card has had it's ability set.
---@field old? string Key of the old center after a card's ability is set.
---@field new? string Key of the new center after a card's ability is set.
---@field unchanged? boolean `true` if the key of the old center is the same as the new one after a card's ability is set.
--- Util Functions
@ -196,6 +203,7 @@ function SMODS.calculate_effect_table_key(effect_table, key, card, ret) end
---@param effects table
---@param card Card|table
---@return table
--- Used to calculate a table of effects generated in evaluate_play
function SMODS.trigger_effects(effects, card) end
@ -692,7 +700,6 @@ function SMODS.is_eternal(card, trigger) end
--- Args must contain `ref_table`, `ref_value`, and `scalar_value`. It may optionally contain `scalar_table`, used in place of `ref_table` for the `scalar_value`, and `operation` to designate the scaling operation, which defaults to `"+"`
function SMODS.scale_card(card, args) end
---@param prototype_obj SMODS.GameObject|table
---@param args table?
---@return boolean?, table?
@ -700,7 +707,6 @@ function SMODS.scale_card(card, args) end
--- i.e. the in_pool method doesn't exist or it returns `true`
function SMODS.add_to_pool(prototype_obj, args) end
---@param context CalcContext|table The context being pushed
---@param func string|nil The function/file from which the call originates
--- Pushes a context to the SMODS.context_stack. (Form: {context=context, count=[number of consecutive pushes]})
@ -712,7 +718,32 @@ function SMODS.push_to_context_stack(context, func) end
function SMODS.pop_from_context_stack(context, func) end
---@return CalcContext|table|nil
--- Returns the second to last context from the SMODS.context_stack.
--- Returns the second to last context from the SMODS.context_stack.
--- Useful for Seals/Enhancements determining whether a playing card was being individually evaluated,
--- when a Joker called (e.g.) SMODS.pseudorandom_probability().
function SMODS.get_previous_context() end
---@param context CalcContext|table The context to be updated
---@param flags table The flags with which to update it (e.g. flags.numerator, flags.denominator, etc.)
function SMODS.update_context_flags(context, flags) end
---@param context CalcContext|table The context checked
---@return string|false
--- Either returns a getter context identifier string
--- (e.g. "enhancement" for context.check_enhancement)
--- or false if the [context] isn't a getter context.
function SMODS.is_getter_context(context) end
---@param eval_object SMODS.GameObject|table The object that will be evaluated next if this returns false
---@return boolean
--- This functions checks whether a previous getter context of the same type
--- as the current context (last SMODS.context_stack context) has caused the
--- [eval_object] to incite any getter context, if yes returns false,
--- skipping the evaluation of the object and preventing an infinite loop.
function SMODS.check_looping_context(eval_object) end
---Check if `challenge` is unlocked.
---@param challenge SMODS.Challenge
---@param k? number Index of challenge in G.CHALLENGES. Only relevant for challenges defined outside SMODS
---@return boolean
function SMODS.challenge_is_unlocked(challenge, k) end

View file

@ -244,12 +244,15 @@ function get_straight(hand, min_length, skip, wrap) end
--- Creates tally sprite UI.
function tally_sprite(pos, value, tooltip, suit) end
---@param _t table[]
---@param _t table
---@param seed string
---@param args table|{starting_deck?: boolean, in_pool?: fun(center: SMODS.GameObject|table, args: table)}
---@return table
---@return string key
--- Sets the seed to `seed` and randomly selects a table within `_t`.
---@param args table|{starting_deck?: boolean, in_pool?: fun(v: any, args: table)}
---@return any
---@return string|number key
--- Sets the seed to `seed` and randomly selects an element within `_t`.
---
--- First filters the elements of `_t` using `args.in_pool`,
--- or else each element `v`'s `v.in_pool` field, if given.
function pseudorandom_element(_t, seed, args) end
--- Vanilla Pools

View file

@ -1 +1 @@
return "1.0.0~BETA-0827c-STEAMODDED"
return "1.0.0~BETA-1016c-STEAMODDED"

View file

@ -316,6 +316,34 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj.
process_loc_text = function() end,
}
-------------------------------------------------------------------------------------------------
----- API CODE GameObject.DynaTextEffect
-------------------------------------------------------------------------------------------------
SMODS.DynaTextEffects = {}
SMODS.DynaTextEffect = SMODS.GameObject:extend {
obj_table = SMODS.DynaTextEffects,
set = 'DynaTextEffects',
obj_buffer = {},
disable_mipmap = false,
required_params = {
'key',
},
func = function(dynatext, index, letter)
end,
register = function(self)
if self.registered then
sendWarnMessage(('Detected duplicate register call on object %s'):format(self.key), self.set)
return
end
self.name = self.key
SMODS.DynaTextEffect.super.register(self)
end,
inject = function(self)
end,
process_loc_text = function() end,
}
-------------------------------------------------------------------------------------------------
----- API CODE GameObject.Language
@ -1124,7 +1152,6 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj.
vars =
specific_vars or {}
}
if target.vars.is_info_queue then target.is_info_queue = true; target.vars.is_info_queue = nil end
local res = {}
if self.loc_vars and type(self.loc_vars) == 'function' then
res = self:loc_vars(info_queue, card) or {}
@ -1365,7 +1392,6 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj.
AUT = full_UI_table,
vars = {}
}
if target.vars.is_info_queue then target.is_info_queue = true; target.vars.is_info_queue = nil end
local res = {}
if self.loc_vars and type(self.loc_vars) == 'function' then
res = self:loc_vars(info_queue, card) or {}
@ -1767,7 +1793,6 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj.
AUT = full_UI_table,
vars = specific_vars or {},
}
if target.vars.is_info_queue then target.is_info_queue = true; target.vars.is_info_queue = nil end
local res = {}
if self.loc_vars and type(self.loc_vars) == 'function' then
res = self:loc_vars(info_queue, card) or {}
@ -2885,7 +2910,6 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj.
AUT = full_UI_table,
vars = specific_vars
}
if target.vars.is_info_queue then target.is_info_queue = true; target.vars.is_info_queue = nil end
local res = {}
if self.loc_vars and type(self.loc_vars) == 'function' then
-- card is actually a `Tag` here
@ -3646,6 +3670,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj.
SMODS.Scoring_Parameter({
key = 'mult',
default_value = 0,
juice_on_update = true,
colour = G.C.UI_MULT,
calculation_keys = {'mult', 'h_mult', 'mult_mod','x_mult', 'Xmult', 'xmult', 'x_mult_mod', 'Xmult_mod'},
calc_effect = function(self, effect, scored_card, key, amount, from_edition)

View file

@ -564,8 +564,7 @@ function SMODS.check_applied_stakes(stake, deck)
end
function G.UIDEF.stake_option(_type)
G.viewed_stake = G.viewed_stake or 1
local middle = {n=G.UIT.R, config={align = "cm", minh = 1.7, minw = 7.3}, nodes={
{n=G.UIT.O, config={id = nil, func = 'RUN_SETUP_check_stake2', object = Moveable()}},
}}
@ -573,6 +572,7 @@ function G.UIDEF.stake_option(_type)
local stake_options = {}
local curr_options = {}
local deck_usage = G.PROFILES[G.SETTINGS.profile].deck_usage[G.GAME.viewed_back.effect.center.key]
G.viewed_stake = deck_usage and ((deck_usage.wins_by_key[SMODS.stake_from_index(G.viewed_stake)] or G.PROFILES[G.SETTINGS.profile].all_unlocked) and G.viewed_stake or (get_deck_win_stake(G.GAME.viewed_back.effect.center.key) + 1)) or 1
for i=1, #G.P_CENTER_POOLS.Stake do
if G.PROFILES[G.SETTINGS.profile].all_unlocked or SMODS.check_applied_stakes(G.P_CENTER_POOLS.Stake[i], deck_usage or {wins_by_key = {}}) then
stake_options[#stake_options + 1] = i
@ -588,8 +588,8 @@ function G.UIDEF.stake_option(_type)
end
G.FUNCS.change_stake = function(args)
G.viewed_stake = args.to_val
G.PROFILES[G.SETTINGS.profile].MEMORY.stake = args.to_val
G.viewed_stake = args.to_val or args.to_key
G.PROFILES[G.SETTINGS.profile].MEMORY.stake = args.to_val or args.to_key
end
--#endregion
@ -1538,17 +1538,6 @@ end
function create_UIBox_current_hands(simple)
G.current_hands = {}
local index = 0
for _, v in ipairs(G.handlist) do
local ui_element = create_UIBox_current_hand_row(v, simple)
G.current_hands[index + 1] = ui_element
if ui_element then
index = index + 1
end
if index >= 10 then
break
end
end
local visible_hands = {}
for _, v in ipairs(G.handlist) do
@ -1557,6 +1546,19 @@ function create_UIBox_current_hands(simple)
end
end
local index = 0
for _, v in ipairs(G.handlist) do
local ui_element = create_UIBox_current_hand_row(v, simple)
G.current_hands[index + 1] = ui_element
if ui_element then
index = index + 1
end
if index >= 10 and #visible_hands > 12 then -- keep pagination off until there's more than the vanilla max of 12 hands
break
end
end
local hand_options = {}
for i = 1, math.ceil(#visible_hands / 10) do
table.insert(hand_options,
@ -1566,7 +1568,8 @@ function create_UIBox_current_hands(simple)
local object = {n = G.UIT.ROOT, config = {align = "cm", colour = G.C.CLEAR}, nodes = {
{n = G.UIT.R, config = {align = "cm", padding = 0.04}, nodes =
G.current_hands},
{n = G.UIT.R, config = {align = "cm", padding = 0}, nodes = {
-- UI consistency with vanilla
#visible_hands > 12 and {n = G.UIT.R, config = {align = "cm", padding = 0}, nodes = {
create_option_cycle({
options = hand_options,
w = 4.5,
@ -1576,7 +1579,8 @@ function create_UIBox_current_hands(simple)
current_option = 1,
colour = G.C.RED,
no_pips = true
})}}}}
})}} or nil,
}}
local t = {n = G.UIT.ROOT, config = {align = "cm", minw = 3, padding = 0.1, r = 0.1, colour = G.C.CLEAR}, nodes = {
{n = G.UIT.O, config = {
@ -1711,7 +1715,7 @@ function Card:set_sprites(_center, _front)
G.j_undiscovered.pos
self.children.center = Sprite(self.T.x, self.T.y, self.T.w, self.T.h, atlas, pos)
elseif _center.set == 'Joker' or _center.consumeable or _center.set == 'Voucher' then
self.children.center = Sprite(self.T.x, self.T.y, self.T.w, self.T.h, G.ASSET_ATLAS[_center[G.SETTINGS.colourblind_option and 'hc_atlas' or 'lc_atlas'] or _center.atlas or _center.set], self.config.center.pos)
self.children.center = Sprite(self.T.x, self.T.y, self.T.w, self.T.h, G.ASSET_ATLAS[_center[G.SETTINGS.colourblind_option and 'hc_atlas' or 'lc_atlas'] or _center.atlas or _center.set], _center.pos or {x=0, y=0})
else
self.children.center = Sprite(self.T.x, self.T.y, self.T.w, self.T.h, G.ASSET_ATLAS[_center.atlas or 'centers'], _center.pos)
end
@ -2184,11 +2188,9 @@ function get_pack(_key, _type)
local add
v.current_weight = v.get_weight and v:get_weight() or v.weight or 1
if (not _type or _type == v.kind) then add = true end
if v.in_pool and type(v.in_pool) == 'function' then
local res, pool_opts = SMODS.add_to_pool(v)
pool_opts = pool_opts or {}
add = res and (add or pool_opts.override_base_checks)
end
local res, pool_opts = SMODS.add_to_pool(v)
pool_opts = pool_opts or {}
add = res and (add or pool_opts.override_base_checks)
if add and not G.GAME.banned_keys[v.key] then cume = cume + (v.current_weight or 1); temp_in_pool[v.key] = true end
end
local poll = pseudorandom(pseudoseed((_key or 'pack_generic')..G.GAME.round_resets.ante))*cume
@ -2300,7 +2302,7 @@ function Blind:debuff_hand(cards, hand, handname, check)
local flags = SMODS.trigger_effects(effects, cards[i])
if flags.add_to_hand then splashed = true end
if flags.remove_from_hand then unsplashed = true end
if splashed and not unsplashed then table.insert(final_scoring_hand, G.play.cards[i]) end
if splashed and not unsplashed then table.insert(final_scoring_hand, cards[i]) end
end
local flags = SMODS.calculate_context({ debuff_hand = true, full_hand = cards, scoring_hand = final_scoring_hand, poker_hands = hand, scoring_name = handname, check = check })
if flags.prevent_debuff then return false end
@ -2370,11 +2372,11 @@ function Card:use_consumeable(area, copier)
end
local ease_ante_ref = ease_ante
function ease_ante(mod, ante_end)
local flags = SMODS.calculate_context({modify_ante = mod, ante_end = ante_end})
if flags.modify then mod = mod + flags.modify end
function ease_ante(mod)
local flags = SMODS.calculate_context({modify_ante = mod, ante_end = SMODS.ante_end})
if flags.modify then mod = flags.modify end
ease_ante_ref(mod)
SMODS.calculate_context({ante_change = mod, ante_end = ante_end})
SMODS.calculate_context({ante_change = mod, ante_end = SMODS.ante_end})
end
local eval_card_ref = eval_card

View file

@ -894,7 +894,7 @@ function buildModtag(mod)
local tag_atlas, tag_pos, tag_message, specific_vars = getModtagInfo(mod)
local tag_sprite_tab = nil
local units = SMODS.pixels_to_unit(34) * 2
local units = 1
local animated = G.ANIMATION_ATLAS[tag_atlas] or nil
local tag_sprite
if animated then
@ -2145,7 +2145,7 @@ end
function SMODS.GUI.score_container(args)
local scale = args.scale or 0.4
local type = args.type or 'mult'
local type = args.type
local colour = args.colour or SMODS.Scoring_Parameters[type].colour
local align = args.align or 'cl'
local func = args.func or 'hand_type_UI_set'
@ -2155,6 +2155,7 @@ function SMODS.GUI.score_container(args)
return
{n=G.UIT.R, config={align = align, minw = w, minh = h, r = 0.1, colour = colour, id = 'hand_'..type..'_area', emboss = 0.05}, nodes={
{n=G.UIT.O, config={func = 'flame_handler', no_role = true, id = 'flame_'..type, object = Moveable(0,0,0,0), w = 0, h = 0, _w = w * 1.25, _h = h * 2.5}},
-- TODO padding should depend only on 2nd letter of alignment?
align == 'cl' and {n=G.UIT.B, config={w = 0.1, h = 0.1}} or nil,
{n=G.UIT.O, config={id = 'hand_'..type, func = func, text = text, type = type, scale = scale*2.3, object = DynaText({
string = {{ref_table = G.GAME.current_round.current_hand, ref_value = text}},
@ -2173,4 +2174,4 @@ G.FUNCS.hand_type_UI_set = function(e)
e.config.object:update_text()
if not G.TAROT_INTERRUPT_PULSE then G.FUNCS.text_super_juice(e, math.max(0,math.floor(math.log10(type(G.GAME.current_round.current_hand[e.config.type]) == 'number' and G.GAME.current_round.current_hand[e.config.type] or 1)))) end
end
end
end

View file

@ -703,6 +703,10 @@ end
--#endregion
function SMODS.poll_edition(args)
args = args or {}
return poll_edition(args.key or 'editiongeneric', args.mod, args.no_negative, args.guaranteed, args.options)
end
function SMODS.poll_seal(args)
args = args or {}
@ -1221,7 +1225,7 @@ SMODS.smart_level_up_hand = function(card, hand, instant, amount)
if not (instant or SMODS.displayed_hand == hand) then
update_hand_text({sound = 'button', volume = 0.7, pitch = 0.8, delay = 0.3}, {handname=localize(hand, 'poker_hands'),chips = G.GAME.hands[hand].chips, mult = G.GAME.hands[hand].mult, level=G.GAME.hands[hand].level})
end
level_up_hand(card, hand, instant, type(amount) == 'number' and amount or 1)
level_up_hand(card, hand, instant, (type(amount) == 'number' or type(amount) == 'table') and amount or 1)
if not (instant or SMODS.displayed_hand == hand) then
update_hand_text({sound = 'button', volume = 0.7, pitch = 1.1, delay = 0}, vals_after_level or {mult = 0, chips = 0, handname = '', level = ''})
end
@ -1236,6 +1240,9 @@ SMODS.calculate_individual_effect = function(effect, scored_card, key, amount, f
if (key == 'p_dollars' or key == 'dollars' or key == 'h_dollars') and amount then
if effect.card and effect.card ~= scored_card then juice_card(effect.card) end
SMODS.ease_dollars_calc = true
ease_dollars(amount)
SMODS.ease_dollars_calc = nil
if not effect.remove_default_message then
if effect.dollar_message then
card_eval_status_text(effect.message_card or effect.juice_card or scored_card or effect.card or effect.focus, 'extra', nil, percent, nil, effect.dollar_message)
@ -1243,7 +1250,13 @@ SMODS.calculate_individual_effect = function(effect, scored_card, key, amount, f
card_eval_status_text(effect.message_card or effect.juice_card or scored_card or effect.card or effect.focus, 'dollars', amount, percent)
end
end
ease_dollars(amount)
SMODS.calculate_context({
money_altered = true,
amount = amount,
from_shop = (G.STATE == G.STATES.SHOP or G.STATE == G.STATES.SMODS_BOOSTER_OPENED or G.STATE == G.STATES.SMODS_REDEEM_VOUCHER) or nil,
from_consumeable = (G.STATE == G.STATES.PLAY_TAROT) or nil,
from_scoring = (G.STATE == G.STATES.HAND_PLAYED) or nil,
})
return true
end
@ -1335,7 +1348,7 @@ SMODS.calculate_individual_effect = function(effect, scored_card, key, amount, f
if key == 'saved' then
SMODS.saved = amount
G.GAME.saved_text = amount
return true
return key
end
if key == 'effect' then
@ -1639,6 +1652,10 @@ function SMODS.calculate_card_areas(_type, context, return_table, args)
if args and args.joker_area and not args.has_area then context.cardarea = area end
for _, _card in ipairs(area.cards) do
--calculate the joker effects
if SMODS.check_looping_context(_card) then
goto skip
end
SMODS.current_evaluated_object = _card
local eval, post = eval_card(_card, context)
if args and args.main_scoring and eval.jokers then
eval.jokers.juice_card = eval.jokers.juice_card or eval.jokers.card or _card
@ -1681,10 +1698,9 @@ function SMODS.calculate_card_areas(_type, context, return_table, args)
else
local f = SMODS.trigger_effects(effects, _card)
for k,v in pairs(f) do flags[k] = v end
if flags.numerator then context.numerator = flags.numerator end
if flags.denominator then context.denominator = flags.denominator end
if flags.cards_to_draw then context.amount = flags.cards_to_draw end
SMODS.update_context_flags(context, flags)
end
::skip::
end
end
end
@ -1701,18 +1717,25 @@ function SMODS.calculate_card_areas(_type, context, return_table, args)
-- For example; A seal can double the probability of Blood Stone hitting for the playing card it is applied to.
if context.mod_probability or context.fix_probability then
for _, card in ipairs(area.cards) do
if SMODS.check_looping_context(card) then
goto skip
end
SMODS.current_evaluated_object = card
local effects = {eval_card(card, context)}
local f = SMODS.trigger_effects(effects, card)
for k,v in pairs(f) do flags[k] = v end
if flags.numerator then context.numerator = flags.numerator end
if flags.denominator then context.denominator = flags.denominator end
if flags.cards_to_draw then context.amount = flags.cards_to_draw end
SMODS.update_context_flags(context, flags)
::skip::
end
end
goto continue
end
if not args or not args.has_area then context.cardarea = area end
for _, card in ipairs(area.cards) do
if SMODS.check_looping_context(card) then
goto skip
end
if not args or not args.has_area then
if area == G.play then
context.cardarea = SMODS.in_scoring(card, context.scoring_hand) and G.play or 'unscored'
@ -1722,19 +1745,20 @@ function SMODS.calculate_card_areas(_type, context, return_table, args)
context.cardarea = area
end
end
--calculate the played card effects
--calculate the played card effects
if return_table then
SMODS.current_evaluated_object = card
return_table[#return_table+1] = eval_card(card, context)
SMODS.calculate_quantum_enhancements(card, return_table, context)
else
SMODS.current_evaluated_object = card
local effects = {eval_card(card, context)}
SMODS.calculate_quantum_enhancements(card, effects, context)
local f = SMODS.trigger_effects(effects, card)
for k,v in pairs(f) do flags[k] = v end
if flags.numerator then context.numerator = flags.numerator end
if flags.denominator then context.denominator = flags.denominator end
if flags.cards_to_draw then context.amount = flags.cards_to_draw end
SMODS.update_context_flags(context, flags)
end
::skip::
end
::continue::
end
@ -1742,6 +1766,10 @@ function SMODS.calculate_card_areas(_type, context, return_table, args)
if _type == 'individual' then
for _, area in ipairs(SMODS.get_card_areas('individual')) do
if SMODS.check_looping_context(area.object) then
goto skip
end
SMODS.current_evaluated_object = area.object
local eval, post = SMODS.eval_individual(area, context)
if args and args.main_scoring and eval.individual then
eval.individual.juice_card = eval.individual.juice_card or eval.individual.card or area.scored_card
@ -1769,16 +1797,63 @@ function SMODS.calculate_card_areas(_type, context, return_table, args)
else
local f = SMODS.trigger_effects(effects, area.scored_card)
for k,v in pairs(f) do flags[k] = v end
if flags.numerator then context.numerator = flags.numerator end
if flags.denominator then context.denominator = flags.denominator end
SMODS.update_context_flags(context, flags)
end
::skip::
end
end
SMODS.current_evaluated_object = nil
return flags
end
-- Updates a [context] with all compatible [flags]
function SMODS.update_context_flags(context, flags)
if flags.numerator then context.numerator = flags.numerator end
if flags.denominator then context.denominator = flags.denominator end
if flags.cards_to_draw then context.amount = flags.cards_to_draw end
if flags.saved then context.game_over = false end
if flags.modify then
-- insert general modified value updating here
if context.modify_ante then context.modify_ante = flags.modify end
if context.drawing_cards then context.amount = flags.modify end
end
end
SMODS.current_evaluated_object = nil
-- Used to avoid looping getter context calls. Example;
-- Joker A: Doubles lucky card probabilities
-- Joker B: 1 in 3 chance that a card counts as a lucky card
-- Joker A calls SMODS.has_enhancement() during a probability context to check whether it should double the numerator
-- Joker B calls SMODS.pseudorandom_probability() to check whether it should trigger
-- A loop is caused (ignore the fact that Joker B would be the trigger_obj and not a playing card) (I'd write a Quantum Ranks example, If I had any!!)
-- To avoid this; Check before evaluating any object, whether the current getter context type (if it's a getter context) has previously caused said object to create a getter context,
-- if yes, don't evaluate the object.
function SMODS.is_getter_context(context)
if context.mod_probability or context.fix_probability then return "probability" end
if context.check_enhancement then return "enhancement" end
return false
end
function SMODS.check_looping_context(eval_object)
if #SMODS.context_stack < 2 then return false end
local getter_type = SMODS.is_getter_context(SMODS.context_stack[#SMODS.context_stack].context)
if not getter_type then return end
for i, t in ipairs(SMODS.context_stack) do
local other_type = SMODS.is_getter_context(t.context)
local next_context = SMODS.context_stack[i+1]
-- If the current kind of getter context has caused the eval_object to incite a getter context before, dont evaluate the object again
if other_type == getter_type and next_context and SMODS.is_getter_context(next_context.context) and next_context.caller == eval_object then
return true
end
end
return false
end
-- The context stack list, structured like so;
-- SMODS.context_stack = {1: {context = [unique context 1], count = [number of times it was added consecutively]}, ...}
-- SMODS.context_stack = {1: {context = [unique context 1], count = [number of times it was added consecutively], caller = [the SMODS.current_evaluated_object when the context was added]}, ...}
-- (Contexts may repeat non-consecutively, though I don't think they ever should..)
-- Allows some advanced effects, like:
-- Individual playing cards modifying probabilities checked during individual scoring, only when they're the context.other_card
@ -1791,7 +1866,7 @@ function SMODS.push_to_context_stack(context, func)
end
local len = #SMODS.context_stack
if len <= 0 or SMODS.context_stack[len].context ~= context then
SMODS.context_stack[len+1] = {context = context, count = 1}
SMODS.context_stack[len+1] = {context = context, count = 1, caller = SMODS.current_evaluated_object}
else
SMODS.context_stack[len].count = SMODS.context_stack[len].count + 1
end
@ -2021,7 +2096,6 @@ function SMODS.blueprint_effect(copier, copied_card, context)
context.blueprint_card = old_context_blueprint_card
if other_joker_ret then
other_joker_ret.card = eff_card
other_joker_ret.colour = G.C.BLUE
return other_joker_ret
end
end
@ -2235,16 +2309,18 @@ G.FUNCS.can_select_from_booster = function(e)
end
function Card.selectable_from_pack(card, pack)
if pack.select_exclusions then
if card.config.center.select_card then return card.config.center.select_card end
if pack and pack.select_exclusions then
for _, key in ipairs(pack.select_exclusions) do
if key == card.config.center_key then return false end
end
end
if pack.select_card then
if type(pack.select_card) == 'table' then
if pack.select_card[card.ability.set] then return pack.select_card[card.ability.set] else return false end
local select_area = SMODS.card_select_area(card, pack)
if select_area then
if type(select_area) == 'table' then
if select_area[card.ability.set] then return select_area[card.ability.set] else return false end
end
return pack.select_card
return select_area
end
end
@ -2403,10 +2479,13 @@ function SMODS.localize_box(lines, args)
if G.F_MOBILE_UI then desc_scale = desc_scale*1.5 end
if part.control.E then
local _float, _silent, _pop_in, _bump, _spacing = nil, true, nil, nil, nil
local text_effects
if part.control.E == '1' then
_float = true; _silent = true; _pop_in = 0
elseif part.control.E == '2' then
_bump = true; _spacing = 1
elseif SMODS.DynaTextEffects[part.control.E] then
text_effects = part.control.E
end
final_line[#final_line+1] = {n=G.UIT.C, config={align = "m", colour = part.control.B and args.vars.colours[tonumber(part.control.B)] or part.control.X and loc_colour(part.control.X) or nil, r = 0.05, padding = 0.03, res = 0.15}, nodes={}}
final_line[#final_line].nodes[1] = {n=G.UIT.O, config={
@ -2416,6 +2495,7 @@ function SMODS.localize_box(lines, args)
silent = _silent,
pop_in = _pop_in,
bump = _bump,
text_effect = text_effects,
spacing = _spacing,
font = SMODS.Fonts[part.control.f] or (tonumber(part.control.f) and G.FONTS[tonumber(part.control.f)]),
scale = 0.32*(part.control.s and tonumber(part.control.s) or args.scale or 1)*desc_scale})
@ -2468,7 +2548,11 @@ end
function SMODS.destroy_cards(cards, bypass_eternal, immediate, skip_anim)
if not cards[1] then
cards = {cards}
if Object.is(cards, Card) then
cards = {cards}
else
return
end
end
local glass_shattered = {}
local playing_cards = {}
@ -2493,7 +2577,7 @@ function SMODS.destroy_cards(cards, bypass_eternal, immediate, skip_anim)
if next(playing_cards) then SMODS.calculate_context({scoring_hand = cards, remove_playing_cards = true, removed = playing_cards}) end
for i = 1, #cards do
if immediate then
if immediate or skip_anim then
if cards[i].shattered then
cards[i]:shatter()
elseif cards[i].destroyed then
@ -2547,7 +2631,7 @@ function SMODS.draw_cards(hand_space)
end
local flags = SMODS.calculate_context({drawing_cards = true, amount = hand_space})
hand_space = math.min(#G.deck.cards, flags.cards_to_draw or hand_space)
hand_space = math.min(#G.deck.cards, flags.cards_to_draw or flags.modify or hand_space)
delay(0.3)
SMODS.drawn_cards = {}
for i=1, hand_space do --draw cards from deckL
@ -2687,6 +2771,21 @@ end
-- Scoring Calculation API
function SMODS.set_scoring_calculation(key)
G.GAME.current_scoring_calculation = SMODS.Scoring_Calculations[key]:new()
G.FUNCS.SMODS_scoring_calculation_function(G.HUD:get_UIE_by_ID('hand_text_area'))
G.HUD:get_UIE_by_ID('hand_operator_container').UIBox:recalculate()
SMODS.refresh_score_UI_list()
end
local game_start_run = Game.start_run
function Game:start_run(args)
game_start_run(self, args)
G.E_MANAGER:add_event(Event({
trigger = 'immediate',
func = function()
SMODS.refresh_score_UI_list()
return true
end
}))
end
G.FUNCS.SMODS_scoring_calculation_function = function(e)
@ -2732,6 +2831,11 @@ function SMODS.get_scoring_parameter(key, flames)
return SMODS.Scoring_Parameters[key].current or SMODS.Scoring_Parameters[key].default_value
end
function SMODS.refresh_score_UI_list()
for name, _ in pairs(SMODS.Scoring_Parameters) do
G.hand_text_area[name] = G.HUD:get_UIE_by_ID('hand_'..name)
end
end
-- Adds tag_triggered context
local tag_apply = Tag.apply_to_run
@ -2876,6 +2980,21 @@ function G.UIDEF.challenge_description_tab(args)
return ref_challenge_desc(args)
end
function SMODS.challenge_is_unlocked(challenge, k)
local challenge_unlocked
if type(challenge.unlocked) == 'function' then
challenge_unlocked = challenge:unlocked()
elseif type(challenge.unlocked) == 'boolean' then
challenge_unlocked = challenge.unlocked
else
-- vanilla condition, only for non-smods challenges
challenge_unlocked = G.PROFILES[G.SETTINGS.profile].challenges_unlocked and (G.PROFILES[G.SETTINGS.profile].challenges_unlocked >= (k or 0))
end
challenge_unlocked = challenge_unlocked or G.PROFILES[G.SETTINGS.profile].all_unlocked
return challenge_unlocked
end
function SMODS.localize_perma_bonuses(specific_vars, desc_nodes)
if specific_vars and specific_vars.bonus_x_chips then
localize{type = 'other', key = 'card_x_chips', nodes = desc_nodes, vars = {specific_vars.bonus_x_chips}}
@ -2889,7 +3008,7 @@ function SMODS.localize_perma_bonuses(specific_vars, desc_nodes)
if specific_vars and specific_vars.bonus_h_chips then
localize{type = 'other', key = 'card_extra_h_chips', nodes = desc_nodes, vars = {SMODS.signed(specific_vars.bonus_h_chips)}}
end
if specific_vars and specific_vars.bonus_x_chips then
if specific_vars and specific_vars.bonus_h_x_chips then
localize{type = 'other', key = 'card_h_x_chips', nodes = desc_nodes, vars = {specific_vars.bonus_h_x_chips}}
end
if specific_vars and specific_vars.bonus_h_mult then
@ -2912,6 +3031,7 @@ end
local ease_dollar_ref = ease_dollars
function ease_dollars(mod, instant)
ease_dollar_ref(mod, instant)
if SMODS.ease_dollars_calc then return end
SMODS.calculate_context({
money_altered = true,
amount = mod,
@ -2936,6 +3056,7 @@ function Card:is_rarity(rarity)
return own_rarity == rarity or SMODS.Rarities[own_rarity] == rarity
end
function UIElement:draw_pixellated_under(_type, _parallax, _emboss, _progress)
if not self.pixellated_rect or
#self.pixellated_rect[_type].vertices < 1 or
@ -2991,7 +3112,54 @@ function UIElement:draw_pixellated_under(_type, _parallax, _emboss, _progress)
end
end
love.graphics.polygon("fill", self.pixellated_rect.fill.vertices)
end
function SMODS.card_select_area(card, pack)
local select_area
if card.config.center.select_card then
if type(card.config.center.select_card) == "function" then -- Card's value takes first priority
select_area = card.config.center:select_card(card, pack)
else
select_area = card.config.center.select_card
end
elseif SMODS.ConsumableTypes[card.ability.set] and SMODS.ConsumableTypes[card.ability.set].select_card then -- ConsumableType is second priority
if type(SMODS.ConsumableTypes[card.ability.set].select_card) == "function" then
select_area = SMODS.ConsumableTypes[card.ability.set]:select_card(card, pack)
else
select_area = SMODS.ConsumableTypes[card.ability.set].select_card
end
elseif pack.select_card then -- Pack is third priority
if type(pack.select_card) == "function" then
select_area = pack:select_card(card, pack)
else
select_area = pack.select_card
end
end
return select_area
end
function SMODS.get_select_text(card, pack)
local select_text
if card.config.center.select_button_text then -- Card's value takes first priority
if type(card.config.center.select_button_text) == "function" then
select_text = card.config.center:select_button_text(card, pack)
else
select_text = localize(card.config.center.select_button_text)
end
elseif SMODS.ConsumableTypes[card.ability.set] and SMODS.ConsumableTypes[card.ability.set].select_button_text then -- ConsumableType is second priority
if type(SMODS.ConsumableTypes[card.ability.set].select_button_text) == "function" then
select_text = SMODS.ConsumableTypes[card.ability.set]:select_button_text(card, pack)
else
select_text = localize(SMODS.ConsumableTypes[card.ability.set].select_button_text)
end
elseif pack.select_button_text then -- Pack is third priority
if type(pack.select_button_text) == "function" then
select_text = pack:select_button_text(card, pack)
else
select_text = localize(pack.select_button_text)
end
end
return select_text
end
function CardArea:count_extra_slots_used(cards)
@ -3035,8 +3203,29 @@ function CardArea:handle_card_limit(card_limit, card_slots)
}))
end
if G.hand and self == G.hand and card_limit - card_slots > 0 then
if G.STATE == G.STATES.SELECTING_HAND then G.FUNCS.draw_from_deck_to_hand(math.min(card_limit - card_slots, (self.config.card_limit + card_limit - card_slots) - #self.cards)) end
if G.hand and self == G.hand and card_limit - card_slots > 0 then
if G.STATE == G.STATES.DRAW_TO_HAND and math.min(card_limit - card_slots, (self.config.card_limit + card_limit - card_slots) - #self.cards - (SMODS.cards_to_draw or 0)) > 0 then
G.E_MANAGER:add_event(Event({
trigger = 'immediate',
func = function()
G.E_MANAGER:add_event(Event({
trigger = 'immediate',
func = function()
G.FUNCS.draw_from_deck_to_hand()
return true
end
}))
return true
end
}))
elseif G.STATE == G.STATES.SELECTING_HAND then G.FUNCS.draw_from_deck_to_hand(math.min(card_limit - card_slots, (self.config.card_limit + card_limit - card_slots) - #self.cards)) end
G.E_MANAGER:add_event(Event({
trigger = 'immediate',
func = function()
save_run()
return true
end
}))
check_for_unlock({type = 'min_hand_size'})
end
end

View file

@ -1 +1 @@
return "1.0.0~BETA-0827c-STEAMODDED"
return "1.0.0~BETA-1016c-STEAMODDED"

2
Talisman/.gitattributes vendored Normal file
View file

@ -0,0 +1,2 @@
# Auto detect text files and perform LF normalization
* text=auto

3
Talisman/.gitignore vendored Normal file
View file

@ -0,0 +1,3 @@
config.lua
.vscode
.lovelyignore

View file

@ -1,5 +1,5 @@
# Talisman
A mod for Balatro that increases the score cap from ~10^308 to ~10{1000}10, allowing for endless runs to go past "naneinf" and Ante 39, and removes the long animations that come with these scores.
A mod for Balatro that increases the score cap from ~10^308 to ~10{1000}10, allowing for endless runs to go past "naneinf" and Ante 39, and additionally adds the option to remove the long animations that come with these scores.
The "BigNum" representation used by Talisman is a modified version of [this](https://github.com/veprogames/lua-big-number) library by veprogames.
The "OmegaNum" representation used by Talisman is a port of [OmegaNum.js](https://github.com/Naruyoko/OmegaNum.js/blob/master/OmegaNum.js) by [Mathguy23](https://github.com/Mathguy23)

View file

@ -1210,6 +1210,12 @@ function Big:arrow(arrows, other)
if (other:eq(B.ONE)) then
return t:clone()
end
if self:eq(2) and other:eq(2) then
-- handle infinite arrows
if arrows:isInfinite() then return Big:create(R.POSITIVE_INFINITY) end
return Big:create(4)
end
--[[if (arrows:gte(maxArrow)) then
return Big:create(B.POSITIVE_INFINITY)
end--]]

Some files were not shown because too many files have changed in this diff Show more