diff --git a/Cartomancer/README.md b/Cartomancer/README.md new file mode 100644 index 0000000..fd302fd --- /dev/null +++ b/Cartomancer/README.md @@ -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. + diff --git a/Cartomancer/cartomancer.lua b/Cartomancer/cartomancer.lua index a982536..1c1dfac 100644 --- a/Cartomancer/cartomancer.lua +++ b/Cartomancer/cartomancer.lua @@ -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() diff --git a/Cartomancer/config.lua b/Cartomancer/config.lua index e63fc55..541c143 100644 --- a/Cartomancer/config.lua +++ b/Cartomancer/config.lua @@ -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, diff --git a/Cartomancer/core/blinds_info.lua b/Cartomancer/core/blinds_info.lua new file mode 100644 index 0000000..9614ecc --- /dev/null +++ b/Cartomancer/core/blinds_info.lua @@ -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 diff --git a/Cartomancer/core/flames.lua b/Cartomancer/core/flames.lua index 773203e..df65d47 100644 --- a/Cartomancer/core/flames.lua +++ b/Cartomancer/core/flames.lua @@ -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 diff --git a/Cartomancer/core/optimizations.lua b/Cartomancer/core/optimizations.lua index 29768c2..539edc0 100644 --- a/Cartomancer/core/optimizations.lua +++ b/Cartomancer/core/optimizations.lua @@ -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 -- ============================ diff --git a/Cartomancer/core/view-deck-steamodded.lua b/Cartomancer/core/view-deck-steamodded.lua index 935fafa..26f8f0c 100644 --- a/Cartomancer/core/view-deck-steamodded.lua +++ b/Cartomancer/core/view-deck-steamodded.lua @@ -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 + + diff --git a/Cartomancer/core/view-deck.lua b/Cartomancer/core/view-deck.lua index a2e2579..915feb5 100644 --- a/Cartomancer/core/view-deck.lua +++ b/Cartomancer/core/view-deck.lua @@ -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 \ No newline at end of file diff --git a/Cartomancer/internal/init.lua b/Cartomancer/internal/init.lua index c4d75a2..bd6afc9 100644 --- a/Cartomancer/internal/init.lua +++ b/Cartomancer/internal/init.lua @@ -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 \ No newline at end of file diff --git a/Cartomancer/internal/localization.lua b/Cartomancer/internal/localization.lua index 6423f49..ab2748e 100644 --- a/Cartomancer/internal/localization.lua +++ b/Cartomancer/internal/localization.lua @@ -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 + diff --git a/Cartomancer/internal/ui.lua b/Cartomancer/internal/ui.lua index f0377e6..11cd85b 100644 --- a/Cartomancer/internal/ui.lua +++ b/Cartomancer/internal/ui.lua @@ -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 - - diff --git a/Cartomancer/libs/nativefs.lua b/Cartomancer/libs/nativefs.lua index 7fde4fa..50b7f1f 100644 --- a/Cartomancer/libs/nativefs.lua +++ b/Cartomancer/libs/nativefs.lua @@ -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 diff --git a/Cartomancer/localization/en-us.lua b/Cartomancer/localization/en-us.lua index c45a66e..75e52be 100644 --- a/Cartomancer/localization/en-us.lua +++ b/Cartomancer/localization/en-us.lua @@ -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", } } } \ No newline at end of file diff --git a/Cartomancer/localization/es_ES.lua b/Cartomancer/localization/es_ES.lua new file mode 100644 index 0000000..df0cb15 --- /dev/null +++ b/Cartomancer/localization/es_ES.lua @@ -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", + } + } + } + \ No newline at end of file diff --git a/Cartomancer/localization/vi.lua b/Cartomancer/localization/vi.lua new file mode 100644 index 0000000..3d6c905 --- /dev/null +++ b/Cartomancer/localization/vi.lua @@ -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", + } + } +} \ No newline at end of file diff --git a/Cartomancer/localization/zh_CN.lua b/Cartomancer/localization/zh_CN.lua new file mode 100644 index 0000000..66716f8 --- /dev/null +++ b/Cartomancer/localization/zh_CN.lua @@ -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盲注历史", + } + } +} diff --git a/Cartomancer/lovely/blinds-info.toml b/Cartomancer/lovely/blinds-info.toml new file mode 100644 index 0000000..7711fac --- /dev/null +++ b/Cartomancer/lovely/blinds-info.toml @@ -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," \ No newline at end of file diff --git a/Cartomancer/lovely/dynamic-ante-display.toml b/Cartomancer/lovely/dynamic-ante-display.disabled similarity index 52% rename from Cartomancer/lovely/dynamic-ante-display.toml rename to Cartomancer/lovely/dynamic-ante-display.disabled index b2ecac9..357c481 100644 --- a/Cartomancer/lovely/dynamic-ante-display.toml +++ b/Cartomancer/lovely/dynamic-ante-display.disabled @@ -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" diff --git a/Cartomancer/lovely/dynamic-hand-align.toml b/Cartomancer/lovely/dynamic-hand-align.toml index e1fa646..be4bc2d 100644 --- a/Cartomancer/lovely/dynamic-hand-align.toml +++ b/Cartomancer/lovely/dynamic-hand-align.toml @@ -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)) ''' diff --git a/Cartomancer/lovely/fixed-flames.toml b/Cartomancer/lovely/fixed-flames.toml index 90904f1..10be7af 100644 --- a/Cartomancer/lovely/fixed-flames.toml +++ b/Cartomancer/lovely/fixed-flames.toml @@ -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 diff --git a/Cartomancer/lovely/limit-deck-size.toml b/Cartomancer/lovely/limit-deck-size.toml index e55774f..6f0694f 100644 --- a/Cartomancer/lovely/limit-deck-size.toml +++ b/Cartomancer/lovely/limit-deck-size.toml @@ -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 diff --git a/Cartomancer/lovely/stackable-deck-steamodded.toml b/Cartomancer/lovely/stackable-deck-steamodded.toml index bbcf456..7a73241 100644 --- a/Cartomancer/lovely/stackable-deck-steamodded.toml +++ b/Cartomancer/lovely/stackable-deck-steamodded.toml @@ -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 = {''' diff --git a/Cartomancer/lovely/vanilla-ui.toml b/Cartomancer/lovely/vanilla-ui.toml index 7aad247..cbea24b 100644 --- a/Cartomancer/lovely/vanilla-ui.toml +++ b/Cartomancer/lovely/vanilla-ui.toml @@ -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] diff --git a/Cartomancer/mod.lua b/Cartomancer/mod.lua index f2bb117..aa46f4d 100644 --- a/Cartomancer/mod.lua +++ b/Cartomancer/mod.lua @@ -6,7 +6,7 @@ --- PRIORITY: 69 --- BADGE_COLOR: FFD700 --- DISPLAY_NAME: Cartomancer ---- VERSION: 4.12 +--- VERSION: 4.16-smods-fix ---------------------------------------------- ------------MOD CODE ------------------------- diff --git a/Cartomancer/version b/Cartomancer/version deleted file mode 100755 index 8fc491d..0000000 --- a/Cartomancer/version +++ /dev/null @@ -1 +0,0 @@ -4.12-fix \ No newline at end of file diff --git a/Cryptid/.gitignore b/Cryptid/.gitignore index 4b6dff9..2e79320 100644 --- a/Cryptid/.gitignore +++ b/Cryptid/.gitignore @@ -4,3 +4,5 @@ .lovelyignore .idea/* *.diff +*.code-workspace +.DS_Store diff --git a/Cryptid/Cryptid.json b/Cryptid/Cryptid.json index b53982b..3e07ecc 100644 --- a/Cryptid/Cryptid.json +++ b/Cryptid/Cryptid.json @@ -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)", diff --git a/Cryptid/Cryptid.lua b/Cryptid/Cryptid.lua index d58ccce..ac63fe9 100644 --- a/Cryptid/Cryptid.lua +++ b/Cryptid/Cryptid.lua @@ -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 diff --git a/Cryptid/assets/1x/atlaseditiondeck.png b/Cryptid/assets/1x/atlaseditiondeck.png index a81d699..dea24ef 100644 Binary files a/Cryptid/assets/1x/atlaseditiondeck.png and b/Cryptid/assets/1x/atlaseditiondeck.png differ diff --git a/Cryptid/assets/1x/atlasexotic.png b/Cryptid/assets/1x/atlasexotic.png index 94866c6..f5eee31 100644 Binary files a/Cryptid/assets/1x/atlasexotic.png and b/Cryptid/assets/1x/atlasexotic.png differ diff --git a/Cryptid/assets/1x/atlasnotjokers.png b/Cryptid/assets/1x/atlasnotjokers.png index 60d9cfd..f581c43 100644 Binary files a/Cryptid/assets/1x/atlasnotjokers.png and b/Cryptid/assets/1x/atlasnotjokers.png differ diff --git a/Cryptid/assets/1x/atlasthree.png b/Cryptid/assets/1x/atlasthree.png index 5ce3db3..0a85048 100644 Binary files a/Cryptid/assets/1x/atlasthree.png and b/Cryptid/assets/1x/atlasthree.png differ diff --git a/Cryptid/assets/1x/atlastwo.png b/Cryptid/assets/1x/atlastwo.png index 56283d7..faca277 100644 Binary files a/Cryptid/assets/1x/atlastwo.png and b/Cryptid/assets/1x/atlastwo.png differ diff --git a/Cryptid/assets/1x/tag_cry.png b/Cryptid/assets/1x/tag_cry.png index 6ae3ea5..7467d8b 100644 Binary files a/Cryptid/assets/1x/tag_cry.png and b/Cryptid/assets/1x/tag_cry.png differ diff --git a/Cryptid/assets/2x/atlaseditiondeck.png b/Cryptid/assets/2x/atlaseditiondeck.png index 425faff..0341da7 100644 Binary files a/Cryptid/assets/2x/atlaseditiondeck.png and b/Cryptid/assets/2x/atlaseditiondeck.png differ diff --git a/Cryptid/assets/2x/atlasexotic.png b/Cryptid/assets/2x/atlasexotic.png index 501f13e..e363f71 100644 Binary files a/Cryptid/assets/2x/atlasexotic.png and b/Cryptid/assets/2x/atlasexotic.png differ diff --git a/Cryptid/assets/2x/atlasnotjokers.png b/Cryptid/assets/2x/atlasnotjokers.png index 7277fb8..4fe160b 100644 Binary files a/Cryptid/assets/2x/atlasnotjokers.png and b/Cryptid/assets/2x/atlasnotjokers.png differ diff --git a/Cryptid/assets/2x/atlasthree.png b/Cryptid/assets/2x/atlasthree.png index 1656c70..bbb3111 100644 Binary files a/Cryptid/assets/2x/atlasthree.png and b/Cryptid/assets/2x/atlasthree.png differ diff --git a/Cryptid/assets/2x/atlastwo.png b/Cryptid/assets/2x/atlastwo.png index b4be434..4e4175e 100644 Binary files a/Cryptid/assets/2x/atlastwo.png and b/Cryptid/assets/2x/atlastwo.png differ diff --git a/Cryptid/assets/2x/tag_cry.png b/Cryptid/assets/2x/tag_cry.png index a3fa98b..0d982e4 100644 Binary files a/Cryptid/assets/2x/tag_cry.png and b/Cryptid/assets/2x/tag_cry.png differ diff --git a/Cryptid/items/blind.lua b/Cryptid/items/blind.lua index 983cd75..299541e 100644 --- a/Cryptid/items/blind.lua +++ b/Cryptid/items/blind.lua @@ -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 = { diff --git a/Cryptid/items/code.lua b/Cryptid/items/code.lua index a8b70e1..1092170 100644 --- a/Cryptid/items/code.lua +++ b/Cryptid/items/code.lua @@ -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 {} diff --git a/Cryptid/items/deck.lua b/Cryptid/items/deck.lua index cfc49f7..332863c 100644 --- a/Cryptid/items/deck.lua +++ b/Cryptid/items/deck.lua @@ -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, diff --git a/Cryptid/items/epic.lua b/Cryptid/items/epic.lua index 04e46c8..64485d0 100644 --- a/Cryptid/items/epic.lua +++ b/Cryptid/items/epic.lua @@ -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 diff --git a/Cryptid/items/exotic.lua b/Cryptid/items/exotic.lua index 7c78ac4..a447186 100644 --- a/Cryptid/items/exotic.lua +++ b/Cryptid/items/exotic.lua @@ -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", diff --git a/Cryptid/items/misc.lua b/Cryptid/items/misc.lua index 53957f8..e787583 100644 --- a/Cryptid/items/misc.lua +++ b/Cryptid/items/misc.lua @@ -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 diff --git a/Cryptid/items/misc_joker.lua b/Cryptid/items/misc_joker.lua index 831c37a..0ce8859 100644 --- a/Cryptid/items/misc_joker.lua +++ b/Cryptid/items/misc_joker.lua @@ -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 { diff --git a/Cryptid/items/planet.lua b/Cryptid/items/planet.lua index a24231c..3561863 100644 --- a/Cryptid/items/planet.lua +++ b/Cryptid/items/planet.lua @@ -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 { diff --git a/Cryptid/items/spectral.lua b/Cryptid/items/spectral.lua index cfabb0d..83bc51f 100644 --- a/Cryptid/items/spectral.lua +++ b/Cryptid/items/spectral.lua @@ -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, diff --git a/Cryptid/items/spooky.lua b/Cryptid/items/spooky.lua index 2d2c51e..1fb1bf0 100644 --- a/Cryptid/items/spooky.lua +++ b/Cryptid/items/spooky.lua @@ -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, diff --git a/Cryptid/items/test.lua b/Cryptid/items/test.lua index 44a238a..6627f71 100644 --- a/Cryptid/items/test.lua +++ b/Cryptid/items/test.lua @@ -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 } diff --git a/Cryptid/items/voucher.lua b/Cryptid/items/voucher.lua index 366fc7b..351a54d 100644 --- a/Cryptid/items/voucher.lua +++ b/Cryptid/items/voucher.lua @@ -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 = { diff --git a/Cryptid/lib/ascended.lua b/Cryptid/lib/ascended.lua index 734f1bf..5ceacde 100644 --- a/Cryptid/lib/ascended.lua +++ b/Cryptid/lib/ascended.lua @@ -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) diff --git a/Cryptid/lib/content.lua b/Cryptid/lib/content.lua index b691479..a688486 100644 --- a/Cryptid/lib/content.lua +++ b/Cryptid/lib/content.lua @@ -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, +}) diff --git a/Cryptid/lib/forcetrigger.lua b/Cryptid/lib/forcetrigger.lua index 622df8a..c45e709 100644 --- a/Cryptid/lib/forcetrigger.lua +++ b/Cryptid/lib/forcetrigger.lua @@ -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 } } diff --git a/Cryptid/lib/gameset.lua b/Cryptid/lib/gameset.lua index 6ec4009..aacc5f5 100644 --- a/Cryptid/lib/gameset.lua +++ b/Cryptid/lib/gameset.lua @@ -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 diff --git a/Cryptid/lib/https.lua b/Cryptid/lib/https.lua index d037208..cae50f4 100644 --- a/Cryptid/lib/https.lua +++ b/Cryptid/lib/https.lua @@ -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 diff --git a/Cryptid/lib/misc.lua b/Cryptid/lib/misc.lua index 33050e6..c46a397 100644 --- a/Cryptid/lib/misc.lua +++ b/Cryptid/lib/misc.lua @@ -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] diff --git a/Cryptid/lib/misprintize.lua b/Cryptid/lib/misprintize.lua index b3aa39a..7c52e70 100644 --- a/Cryptid/lib/misprintize.lua +++ b/Cryptid/lib/misprintize.lua @@ -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)) diff --git a/Cryptid/lib/overrides.lua b/Cryptid/lib/overrides.lua index d27325e..24c274a 100644 --- a/Cryptid/lib/overrides.lua +++ b/Cryptid/lib/overrides.lua @@ -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" diff --git a/Cryptid/lib/ui.lua b/Cryptid/lib/ui.lua index a896066..d0ad4e1 100644 --- a/Cryptid/lib/ui.lua +++ b/Cryptid/lib/ui.lua @@ -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 diff --git a/Cryptid/localization/en-us.lua b/Cryptid/localization/en-us.lua index 43fe226..39da6d0 100644 --- a/Cryptid/localization/en-us.lua +++ b/Cryptid/localization/en-us.lua @@ -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)", diff --git a/Cryptid/lovely/code.toml b/Cryptid/lovely/code.toml index eac6113..a0dd0ba 100644 --- a/Cryptid/lovely/code.toml +++ b/Cryptid/lovely/code.toml @@ -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] diff --git a/Cryptid/lovely/misprint.toml b/Cryptid/lovely/misprint.toml index 6766215..c8196b8 100644 --- a/Cryptid/lovely/misprint.toml +++ b/Cryptid/lovely/misprint.toml @@ -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 diff --git a/Cryptid/lovely/none.toml b/Cryptid/lovely/none.toml index 430083e..2e744dc 100644 --- a/Cryptid/lovely/none.toml +++ b/Cryptid/lovely/none.toml @@ -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 diff --git a/Cryptid/lovely/planet.toml b/Cryptid/lovely/planet.toml index 0a790d0..e3e2514 100644 --- a/Cryptid/lovely/planet.toml +++ b/Cryptid/lovely/planet.toml @@ -24,4 +24,23 @@ elseif v.config.hand_types then end if not softlocked then ''' -match_indent = true \ No newline at end of file +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 diff --git a/Steamodded/icon.png b/Steamodded/icon.png index fcddcf9..a30fc65 100644 Binary files a/Steamodded/icon.png and b/Steamodded/icon.png differ diff --git a/Steamodded/localization/it.lua b/Steamodded/localization/it.lua index 326c164..5424af8 100644 --- a/Steamodded/localization/it.lua +++ b/Steamodded/localization/it.lua @@ -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#", + } }, } } diff --git a/Steamodded/localization/zh_CN.lua b/Steamodded/localization/zh_CN.lua index 1423301..bea844c 100644 --- a/Steamodded/localization/zh_CN.lua +++ b/Steamodded/localization/zh_CN.lua @@ -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#种', diff --git a/Steamodded/lovely/atlas.toml b/Steamodded/lovely/atlas.toml index dd4c2ee..641cb0a 100644 --- a/Steamodded/lovely/atlas.toml +++ b/Steamodded/lovely/atlas.toml @@ -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 ''' \ No newline at end of file diff --git a/Steamodded/lovely/better_calc.toml b/Steamodded/lovely/better_calc.toml index b3e095d..2536890 100644 --- a/Steamodded/lovely/better_calc.toml +++ b/Steamodded/lovely/better_calc.toml @@ -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}) ''' diff --git a/Steamodded/lovely/blind.toml b/Steamodded/lovely/blind.toml index 65cf8f7..3155aa1 100644 --- a/Steamodded/lovely/blind.toml +++ b/Steamodded/lovely/blind.toml @@ -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]] diff --git a/Steamodded/lovely/booster.toml b/Steamodded/lovely/booster.toml index 3a681e0..9db51b8 100644 --- a/Steamodded/lovely/booster.toml +++ b/Steamodded/lovely/booster.toml @@ -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() diff --git a/Steamodded/lovely/card_limit.toml b/Steamodded/lovely/card_limit.toml index c9ffee7..c1fef15 100644 --- a/Steamodded/lovely/card_limit.toml +++ b/Steamodded/lovely/card_limit.toml @@ -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 \ No newline at end of file diff --git a/Steamodded/lovely/center.toml b/Steamodded/lovely/center.toml index e9b6a1f..358d783 100644 --- a/Steamodded/lovely/center.toml +++ b/Steamodded/lovely/center.toml @@ -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]] diff --git a/Steamodded/lovely/challenge.toml b/Steamodded/lovely/challenge.toml index 40a521d..a6ee99e 100644 --- a/Steamodded/lovely/challenge.toml +++ b/Steamodded/lovely/challenge.toml @@ -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 diff --git a/Steamodded/lovely/enhancement.toml b/Steamodded/lovely/enhancement.toml index 12e6f7e..d184ffc 100644 --- a/Steamodded/lovely/enhancement.toml +++ b/Steamodded/lovely/enhancement.toml @@ -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 diff --git a/Steamodded/lovely/fixes.toml b/Steamodded/lovely/fixes.toml index e4e1a59..59340d5 100644 --- a/Steamodded/lovely/fixes.toml +++ b/Steamodded/lovely/fixes.toml @@ -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) diff --git a/Steamodded/lovely/multi_box_descriptions.toml b/Steamodded/lovely/multi_box_descriptions.toml index af23ca8..b60194f 100644 --- a/Steamodded/lovely/multi_box_descriptions.toml +++ b/Steamodded/lovely/multi_box_descriptions.toml @@ -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) diff --git a/Steamodded/lovely/perma_bonus.toml b/Steamodded/lovely/perma_bonus.toml index fc888fc..8a87adf 100644 --- a/Steamodded/lovely/perma_bonus.toml +++ b/Steamodded/lovely/perma_bonus.toml @@ -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 diff --git a/Steamodded/lovely/pool.toml b/Steamodded/lovely/pool.toml index 16b7c18..bfd0884 100644 --- a/Steamodded/lovely/pool.toml +++ b/Steamodded/lovely/pool.toml @@ -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]] diff --git a/Steamodded/lovely/scaling.toml b/Steamodded/lovely/scaling.toml index b6635c2..1cc6274 100644 --- a/Steamodded/lovely/scaling.toml +++ b/Steamodded/lovely/scaling.toml @@ -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]] diff --git a/Steamodded/lovely/scoring_calculation.toml b/Steamodded/lovely/scoring_calculation.toml index cf5175f..a818c2e 100644 --- a/Steamodded/lovely/scoring_calculation.toml +++ b/Steamodded/lovely/scoring_calculation.toml @@ -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 = '''(?[\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 diff --git a/Steamodded/lovely/text_effect.toml b/Steamodded/lovely/text_effect.toml new file mode 100644 index 0000000..d5a6514 --- /dev/null +++ b/Steamodded/lovely/text_effect.toml @@ -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 diff --git a/Steamodded/lovely/ui.toml b/Steamodded/lovely/ui.toml index 48591f8..17427bb 100644 --- a/Steamodded/lovely/ui.toml +++ b/Steamodded/lovely/ui.toml @@ -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' diff --git a/Steamodded/lsp_def/classes/challenge.lua b/Steamodded/lsp_def/classes/challenge.lua index a7cb6a4..55db587 100644 --- a/Steamodded/lsp_def/classes/challenge.lua +++ b/Steamodded/lsp_def/classes/challenge.lua @@ -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. diff --git a/Steamodded/lsp_def/classes/dynatexteffect.lua b/Steamodded/lsp_def/classes/dynatexteffect.lua new file mode 100644 index 0000000..7495867 --- /dev/null +++ b/Steamodded/lsp_def/classes/dynatexteffect.lua @@ -0,0 +1,42 @@ +---@meta + +---@class SMODS.DynaTextEffect: SMODS.GameObject +---@field obj_table? 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 +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 \ No newline at end of file diff --git a/Steamodded/lsp_def/ui.lua b/Steamodded/lsp_def/ui.lua index f30e438..8b83760 100644 --- a/Steamodded/lsp_def/ui.lua +++ b/Steamodded/lsp_def/ui.lua @@ -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'` diff --git a/Steamodded/lsp_def/utils.lua b/Steamodded/lsp_def/utils.lua index 6e8c716..b6e328b 100644 --- a/Steamodded/lsp_def/utils.lua +++ b/Steamodded/lsp_def/utils.lua @@ -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 diff --git a/Steamodded/lsp_def/vanilla.lua b/Steamodded/lsp_def/vanilla.lua index 21418a1..cb6c02a 100644 --- a/Steamodded/lsp_def/vanilla.lua +++ b/Steamodded/lsp_def/vanilla.lua @@ -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 diff --git a/Steamodded/release.lua b/Steamodded/release.lua index 238bf80..eecbdbd 100644 --- a/Steamodded/release.lua +++ b/Steamodded/release.lua @@ -1 +1 @@ -return "1.0.0~BETA-0827c-STEAMODDED" \ No newline at end of file +return "1.0.0~BETA-1016c-STEAMODDED" \ No newline at end of file diff --git a/Steamodded/src/game_object.lua b/Steamodded/src/game_object.lua index 0354e0a..bb3f900 100644 --- a/Steamodded/src/game_object.lua +++ b/Steamodded/src/game_object.lua @@ -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) diff --git a/Steamodded/src/overrides.lua b/Steamodded/src/overrides.lua index 86400fc..0eede9c 100644 --- a/Steamodded/src/overrides.lua +++ b/Steamodded/src/overrides.lua @@ -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 diff --git a/Steamodded/src/ui.lua b/Steamodded/src/ui.lua index 36be30e..18c0102 100644 --- a/Steamodded/src/ui.lua +++ b/Steamodded/src/ui.lua @@ -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 \ No newline at end of file +end diff --git a/Steamodded/src/utils.lua b/Steamodded/src/utils.lua index 4e35224..138a147 100644 --- a/Steamodded/src/utils.lua +++ b/Steamodded/src/utils.lua @@ -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 diff --git a/Steamodded/version.lua b/Steamodded/version.lua index 238bf80..fe449c2 100644 --- a/Steamodded/version.lua +++ b/Steamodded/version.lua @@ -1 +1 @@ -return "1.0.0~BETA-0827c-STEAMODDED" \ No newline at end of file +return "1.0.0~BETA-1016c-STEAMODDED" diff --git a/Talisman/.gitattributes b/Talisman/.gitattributes new file mode 100644 index 0000000..dfe0770 --- /dev/null +++ b/Talisman/.gitattributes @@ -0,0 +1,2 @@ +# Auto detect text files and perform LF normalization +* text=auto diff --git a/Talisman/.gitignore b/Talisman/.gitignore new file mode 100644 index 0000000..6a7b5fd --- /dev/null +++ b/Talisman/.gitignore @@ -0,0 +1,3 @@ +config.lua +.vscode +.lovelyignore diff --git a/Talisman/README.md b/Talisman/README.md index fd39717..25490f6 100644 --- a/Talisman/README.md +++ b/Talisman/README.md @@ -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) diff --git a/Talisman/big-num/omeganum.lua b/Talisman/big-num/omeganum.lua index 21124bf..4d1ea82 100644 --- a/Talisman/big-num/omeganum.lua +++ b/Talisman/big-num/omeganum.lua @@ -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--]] diff --git a/Talisman/config.lua b/Talisman/config.lua deleted file mode 100644 index 0f706ea..0000000 --- a/Talisman/config.lua +++ /dev/null @@ -1 +0,0 @@ -return {["disable_anims"]=false,["score_opt_id"]=3,["break_infinity"]="omeganum",} \ No newline at end of file diff --git a/Talisman/lovely.toml b/Talisman/lovely.toml index 00359e2..453c9ee 100644 --- a/Talisman/lovely.toml +++ b/Talisman/lovely.toml @@ -214,6 +214,14 @@ position = "at" payload = "if not is_number(G.GAME.current_round.current_hand.chips) or not is_number(G.GAME.current_round.current_hand.mult) then" match_indent = true +[[patches]] +[patches.pattern] +target = "functions/common_events.lua" +pattern = "local delta = (type(vals[name]) == 'number' and type(G.GAME.current_round.current_hand[name]) == 'number') and (vals[name] - G.GAME.current_round.current_hand[name]) or 0" +position = "at" +payload = "local delta = (is_number(vals[name]) and is_number(G.GAME.current_round.current_hand[name])) and (vals[name] - G.GAME.current_round.current_hand[name]) or 0" +match_indent = true + [[patches]] [patches.pattern] target = "functions/common_events.lua" diff --git a/Talisman/steamodded_metadata.lua b/Talisman/steamodded_metadata.lua index 8fc4cc1..f2043ff 100644 --- a/Talisman/steamodded_metadata.lua +++ b/Talisman/steamodded_metadata.lua @@ -4,7 +4,7 @@ --- MOD_AUTHOR: [MathIsFun_, Mathguy24, jenwalter666, cg-223, lord.ruby] --- MOD_DESCRIPTION: A mod that increases Balatro's score limit and skips scoring animations. --- PREFIX: talisman ---- VERSION: 2.5 +--- VERSION: 2.6 ---------------------------------------------- ------------MOD CODE ------------------------- @@ -53,10 +53,18 @@ end if SMODS.current_mod then function SMODS.current_mod.load_mod_config() end function SMODS.current_mod.save_mod_config() end - SMODS.current_mod.config_tab = Talisman.config_tab - SMODS.current_mod.debug_info = { - ["Break Infinity"] = Talisman.config_file.break_infinity - } + SMODS.current_mod.config_tab = function() + if Talisman and Talisman.config_tab then + return Talisman.config_tab() + end + return nil + end + SMODS.current_mod.debug_info = function() + if Talisman and Talisman.config_file then + return {["Break Infinity"] = Talisman.config_file.break_infinity} + end + return {} + end SMODS.current_mod.description_loc_vars = function() return { background_colour = G.C.CLEAR, text_colour = G.C.WHITE, scale = 1.2 } end diff --git a/Talisman/talisman.lua b/Talisman/talisman.lua index 0d4ed52..f356790 100644 --- a/Talisman/talisman.lua +++ b/Talisman/talisman.lua @@ -40,7 +40,7 @@ function init_localization() talismanloc() end -Talisman = {config_file = {disable_anims = false, break_infinity = "omeganum", score_opt_id = 3}, mod_path = talisman_path} +Talisman = {config_file = {disable_anims = false, break_infinity = "omeganum", score_opt_id = 2}, mod_path = talisman_path} if nativefs.read(talisman_path.."/config.lua") then Talisman.config_file = STR_UNPACK(nativefs.read(talisman_path.."/config.lua")) if Talisman.config_file.break_infinity == "bignumber" then @@ -779,11 +779,13 @@ function Card:set_seal(a,b,immediate) return ss(self,a,b,Talisman.config_file.disable_anims and (Talisman.calculating_joker or Talisman.calculating_score or Talisman.calculating_card) or immediate) end -function Card:get_chip_x_bonus() - if self.debuff then return 0 end - if self.ability.set == 'Joker' then return 0 end - if (SMODS.multiplicative_stacking(self.ability.x_chips or 1, self.ability.perma_x_chips or 0) or 0) <= 1 then return 0 end - return SMODS.multiplicative_stacking(self.ability.x_chips or 1, self.ability.perma_x_chips or 0) +if not SMODS then + function Card:get_chip_x_bonus() + if self.debuff then return 0 end + if self.ability.set == 'Joker' then return 0 end + if (self.ability.x_chips or 0) <= 1 then return 0 end + return self.ability.x_chips + end end function Card:get_chip_e_bonus() @@ -850,7 +852,7 @@ local edo = ease_dollars function ease_dollars(mod, instant) if Talisman.config_file.disable_anims then--and (Talisman.calculating_joker or Talisman.calculating_score or Talisman.calculating_card) then mod = mod or 0 - if to_big(mod) < to_big(0) then inc_career_stat('c_dollars_earned', mod) end + if to_big(mod) > to_big(0) then inc_career_stat('c_dollars_earned', mod) end G.GAME.dollars = G.GAME.dollars + mod Talisman.dollar_update = true else return edo(mod, instant) end @@ -935,9 +937,9 @@ if SMODS and SMODS.calculate_individual_effect then card_eval_status_text(scored_card, 'jokers', nil, percent, nil, {message = "^"..amount, colour = G.C.EDITION, edition = true}) elseif key ~= 'Echip_mod' then if effect.echip_message then - card_eval_status_text(scored_card or effect.card or effect.focus, 'extra', nil, percent, nil, effect.echip_message) + 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.echip_message) else - card_eval_status_text(scored_card or effect.card or effect.focus, 'e_chips', amount, percent) + card_eval_status_text(effect.message_card or effect.juice_card or scored_card or effect.card or effect.focus, 'e_chips', amount, percent) end end end @@ -958,9 +960,9 @@ if SMODS and SMODS.calculate_individual_effect then card_eval_status_text(scored_card, 'jokers', nil, percent, nil, {message = "^^"..amount, colour = G.C.EDITION, edition = true}) elseif key ~= 'EEchip_mod' then if effect.eechip_message then - card_eval_status_text(scored_card or effect.card or effect.focus, 'extra', nil, percent, nil, effect.eechip_message) + 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.eechip_message) else - card_eval_status_text(scored_card or effect.card or effect.focus, 'ee_chips', amount, percent) + card_eval_status_text(effect.message_card or effect.juice_card or scored_card or effect.card or effect.focus, 'ee_chips', amount, percent) end end end @@ -981,9 +983,9 @@ if SMODS and SMODS.calculate_individual_effect then card_eval_status_text(scored_card, 'jokers', nil, percent, nil, {message = "^^^"..amount, colour = G.C.EDITION, edition = true}) elseif key ~= 'EEEchip_mod' then if effect.eeechip_message then - card_eval_status_text(scored_card or effect.card or effect.focus, 'extra', nil, percent, nil, effect.eeechip_message) + 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.eeechip_message) else - card_eval_status_text(scored_card or effect.card or effect.focus, 'eee_chips', amount, percent) + card_eval_status_text(effect.message_card or effect.juice_card or scored_card or effect.card or effect.focus, 'eee_chips', amount, percent) end end end @@ -1004,9 +1006,9 @@ if SMODS and SMODS.calculate_individual_effect then card_eval_status_text(scored_card, 'jokers', nil, percent, nil, {message = (amount[1] > 5 and ('{' .. amount[1] .. '}') or string.rep('^', amount[1])) .. amount[2], colour = G.C.EDITION, edition = true}) elseif key ~= 'hyperchip_mod' then if effect.hyperchip_message then - card_eval_status_text(scored_card or effect.card or effect.focus, 'extra', nil, percent, nil, effect.hyperchip_message) + 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.hyperchip_message) else - card_eval_status_text(scored_card or effect.card or effect.focus, 'hyper_chips', amount, percent) + card_eval_status_text(effect.message_card or effect.juice_card or scored_card or effect.card or effect.focus, 'hyper_chips', amount, percent) end end end @@ -1027,9 +1029,9 @@ if SMODS and SMODS.calculate_individual_effect then card_eval_status_text(scored_card, 'jokers', nil, percent, nil, {message = "^"..amount.." "..localize("k_mult"), colour = G.C.EDITION, edition = true}) elseif key ~= 'Emult_mod' then if effect.emult_message then - card_eval_status_text(scored_card or effect.card or effect.focus, 'extra', nil, percent, nil, effect.emult_message) + 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.emult_message) else - card_eval_status_text(scored_card or effect.card or effect.focus, 'e_mult', amount, percent) + card_eval_status_text(effect.message_card or effect.juice_card or scored_card or effect.card or effect.focus, 'e_mult', amount, percent) end end end @@ -1050,9 +1052,9 @@ if SMODS and SMODS.calculate_individual_effect then card_eval_status_text(scored_card, 'jokers', nil, percent, nil, {message = "^^"..amount.." "..localize("k_mult"), colour = G.C.EDITION, edition = true}) elseif key ~= 'EEmult_mod' then if effect.eemult_message then - card_eval_status_text(scored_card or effect.card or effect.focus, 'extra', nil, percent, nil, effect.eemult_message) + 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.eemult_message) else - card_eval_status_text(scored_card or effect.card or effect.focus, 'ee_mult', amount, percent) + card_eval_status_text(effect.message_card or effect.juice_card or scored_card or effect.card or effect.focus, 'ee_mult', amount, percent) end end end @@ -1073,9 +1075,9 @@ if SMODS and SMODS.calculate_individual_effect then card_eval_status_text(scored_card, 'jokers', nil, percent, nil, {message = "^^^"..amount.." "..localize("k_mult"), colour = G.C.EDITION, edition = true}) elseif key ~= 'EEEmult_mod' then if effect.eeemult_message then - card_eval_status_text(scored_card or effect.card or effect.focus, 'extra', nil, percent, nil, effect.eeemult_message) + 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.eeemult_message) else - card_eval_status_text(scored_card or effect.card or effect.focus, 'eee_mult', amount, percent) + card_eval_status_text(effect.message_card or effect.juice_card or scored_card or effect.card or effect.focus, 'eee_mult', amount, percent) end end end @@ -1096,9 +1098,9 @@ if SMODS and SMODS.calculate_individual_effect then card_eval_status_text(scored_card, 'jokers', nil, percent, nil, {message = ((amount[1] > 5 and ('{' .. amount[1] .. '}') or string.rep('^', amount[1])) .. amount[2]).." "..localize("k_mult"), colour = G.C.EDITION, edition = true}) elseif key ~= 'hypermult_mod' then if effect.hypermult_message then - card_eval_status_text(scored_card or effect.card or effect.focus, 'extra', nil, percent, nil, effect.hypermult_message) + 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.hypermult_message) else - card_eval_status_text(scored_card or effect.card or effect.focus, 'hyper_mult', amount, percent) + card_eval_status_text(effect.message_card or effect.juice_card or scored_card or effect.card or effect.focus, 'hyper_mult', amount, percent) end end end