diff --git a/Cartomancer-v.4.10-fix-fix/README.md b/Cartomancer-v.4.10-fix-fix/README.md deleted file mode 100644 index d1c5fe5..0000000 --- a/Cartomancer-v.4.10-fix-fix/README.md +++ /dev/null @@ -1,46 +0,0 @@ -## 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. - -## Features -1. Limit amount of cards visible in your deck pile, to make it appear smaller. Default limit is 100 cards, which can be modified in mod config menu. - -![cards-pile-difference](git-assets/deck-pile.jpg) - - -2. Improved deck view - -- Stack identical playing cards, which looks much cleaner and improves performance. - -![stackable-cards-difference](git-assets/stackable-cards.jpg) - -- Optionally, stack cards regardless of modifier, if your deck has tons of unique cards. -- Hide drawn cards from deck view - -4. Custom scoring flames intensity and SFX volume. - -5. Hide non-essential (edition) shaders. - -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) - -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-v.4.10-fix-fix/lovely/apply-before-smods.toml b/Cartomancer-v.4.10-fix-fix/lovely/apply-before-smods.toml deleted file mode 100644 index 9763958..0000000 --- a/Cartomancer-v.4.10-fix-fix/lovely/apply-before-smods.toml +++ /dev/null @@ -1,14 +0,0 @@ -[manifest] -version = "1.0.0" -dump_lua = true -priority = 0 - -# Patches applied before steamodded. - -[[patches]] -[patches.copy] -target = "main.lua" -position = "prepend" -sources = [ - "core/view-deck-steamodded.lua", -] diff --git a/Cartomancer-v.4.10-fix-fix/lovely/dynamic-ante-display.toml b/Cartomancer-v.4.10-fix-fix/lovely/dynamic-ante-display.toml deleted file mode 100644 index b2ecac9..0000000 --- a/Cartomancer-v.4.10-fix-fix/lovely/dynamic-ante-display.toml +++ /dev/null @@ -1,49 +0,0 @@ -[manifest] -version = "1.0.0" -dump_lua = true -priority = 0 - -# Patch dynamic ante display into -# function create_UIBox_your_collection_blinds(exit) -# this will only work for vanilla, as steamodded overrides this - -[[patches]] -[patches.pattern] -target = "functions/UI_definitions.lua" -pattern = "local ante_amounts = {}" -position = "before" -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 -end -''' -match_indent = true - -[[patches]] -[patches.pattern] -target = "functions/UI_definitions.lua" -pattern = "for i = 1, math.min(16, math.max(16, G.PROFILES[G.SETTINGS.profile].high_scores.furthest_ante.amt)) do" -position = "at" -payload = ''' -for i = min_ante, max_ante do -''' -match_indent = true - -[[patches]] -[patches.pattern] -target = "functions/UI_definitions.lua" -pattern = "local spacing = 1 - math.min(20, math.max(15, G.PROFILES[G.SETTINGS.profile].high_scores.furthest_ante.amt))*0.06" -position = "at" -payload = ''' --- :3 -''' -match_indent = true - diff --git a/Cartomancer-v.4.10-fix-fix/lovely/fixed-flames.toml b/Cartomancer-v.4.10-fix-fix/lovely/fixed-flames.toml deleted file mode 100644 index 90904f1..0000000 --- a/Cartomancer-v.4.10-fix-fix/lovely/fixed-flames.toml +++ /dev/null @@ -1,30 +0,0 @@ -[manifest] -version = "1.0.0" -dump_lua = true -priority = 69 - - -[[patches]] -[patches.regex] -target = "functions/button_callbacks.lua" -position = "at" -pattern = ''' -(?math\.max\(0\., math\.log\(G\.ARGS\.score_intensity\.earned_score, 5\)-2\))''' -payload = "Cartomancer.get_flames_intensity()" - -[[patches]] -[patches.regex] -target = "functions/misc_functions.lua" -position = "at" -pattern = ''' -(?\(not G\.video_organ and G\.STATE == G\.STATES\.SPLASH\) and 0 or AC\[k\]\.vol and v\.volfunc\(AC\[k\]\.vol\) or 0)''' -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' -payload = ''' -_F.timer = Cartomancer.handle_flames_timer(_F.timer, _F.intensity)''' -match_indent = true diff --git a/Cartomancer-v.4.10-fix-fix/lovely/hand-sorting.toml b/Cartomancer-v.4.10-fix-fix/lovely/hand-sorting.toml deleted file mode 100644 index 7011b30..0000000 --- a/Cartomancer-v.4.10-fix-fix/lovely/hand-sorting.toml +++ /dev/null @@ -1,30 +0,0 @@ -[manifest] -version = "1.0.0" -dump_lua = true -priority = 0 - -# Add no sort button to -# create_UIBox_buttons -[[patches]] -[patches.pattern] -target = "functions/UI_definitions.lua" -pattern = ''' -{n=G.UIT.T, config={text = localize('b_sort_hand'), scale = text_scale*0.8, colour = G.C.UI.TEXT_LIGHT}}''' -position = "before" -payload = ''' -Cartomancer.SETTINGS.improved_hand_sorting and -create_toggle{ col = true, label = localize('b_sort_hand'), label_scale = text_scale*0.8, scale = 0.30, w = 0, shadow = true, ref_table = G.hand, ref_value = 'cart_sorting', callback = function () G.FUNCS.cartomancer_sort_hand_off() end } -or''' -match_indent = true - -# Set default value of G.hand.cart_sorting -[[patches]] -[patches.pattern] -target = "functions/UI_definitions.lua" -pattern = ''' -function create_UIBox_buttons()''' -position = "after" -payload = ''' - if G.hand and G.hand.cart_sorting == nil then G.hand.cart_sorting = true end -''' -match_indent = true diff --git a/Cartomancer-v.4.10-fix-fix/lovely/hidden-jokers.toml b/Cartomancer-v.4.10-fix-fix/lovely/hidden-jokers.toml deleted file mode 100644 index dfc920e..0000000 --- a/Cartomancer-v.4.10-fix-fix/lovely/hidden-jokers.toml +++ /dev/null @@ -1,28 +0,0 @@ -[manifest] -version = "1.0.0" -dump_lua = true -priority = 69 - -[[patches]] -[patches.pattern] -target = "cardarea.lua" -pattern = "self.children.area_uibox:draw()" -position = "after" -payload = ''' -if self == G.jokers then - Cartomancer.add_visibility_controls() -end -''' -match_indent = true - -[[patches]] -[patches.pattern] -target = "cardarea.lua" -pattern = "function CardArea:emplace(card, location, stay_flipped)" -position = "after" -payload = ''' -if self == G.jokers then - Cartomancer.handle_joker_added(card) -end -''' -match_indent = true diff --git a/Cartomancer-v.4.10-fix-fix/lovely/keybinds.toml b/Cartomancer-v.4.10-fix-fix/lovely/keybinds.toml deleted file mode 100644 index f82b968..0000000 --- a/Cartomancer-v.4.10-fix-fix/lovely/keybinds.toml +++ /dev/null @@ -1,20 +0,0 @@ -[manifest] -version = "1.0.0" -dump_lua = true -priority = 69 - - -[[patches]] -[patches.pattern] -target = 'engine/controller.lua' -pattern = "function Controller:key_press_update(key, dt)" -position = "after" -payload = ''' - if key == "escape" and Cartomancer.INTERNAL_in_config then - Cartomancer.INTERNAL_in_config = false - if not Cartomancer.use_smods() then - Cartomancer.save_config() - end - end -''' -match_indent = true diff --git a/Cartomancer-v.4.10-fix-fix/lovely/limit-deck-size.toml b/Cartomancer-v.4.10-fix-fix/lovely/limit-deck-size.toml deleted file mode 100644 index f4ef9b2..0000000 --- a/Cartomancer-v.4.10-fix-fix/lovely/limit-deck-size.toml +++ /dev/null @@ -1,86 +0,0 @@ -[manifest] -version = "1.0.0" -dump_lua = true -priority = 69 - -# Make all drawn cards visible - -[[patches]] -[patches.pattern] -target = "cardarea.lua" -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 - card.states.visible = true -end''' -match_indent = true - -# Fix drawing specific card staying invisible -[[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" -payload = ''' -if card and to == G.hand and not card.states.visible then - card.states.visible = true -end''' -match_indent = true - -# Replace drawing deck pile - -[[patches]] -[patches.regex] -target = "cardarea.lua" -pattern = ''' -(?[\t ]*)local deck_height \= \(self\.config\.deck_height or 0\.15\)\/52 -[\t ]*for k, card in ipairs\(self\.cards\) do -[\t ]* if card\.facing \=\= 'front' then card\:flip\(\) end -[\t ]* -[\t ]* if not card\.states\.drag\.is then -[\t ]* card\.T\.x \= self\.T\.x \+ 0\.5\*\(self\.T\.w \- card\.T\.w\) \+ self\.shadow_parrallax\.x\*deck_height\*\(\#self\.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\) -[\t ]* card\.T\.y \= self\.T\.y \+ 0\.5\*\(self\.T\.h \- card\.T\.h\) \+ self\.shadow_parrallax\.y\*deck_height\*\(\#self\.cards\/\(self \=\= G\.deck and 1 or 2\) \- k\) -[\t ]* card\.T\.r \= 0 \+ 0\.3\*self\.shuffle_amt\*\(1 \+ k\*0\.05\)\*\(k%2 \=\= 1 and 1 or \-0\) -[\t ]* card\.T\.x \= card\.T\.x \+ card\.shadow_parrallax\.x\/30 -[\t ]* end -[\t ]*end''' -position = "at" -payload = ''' -local display_limit -if not Cartomancer.SETTINGS.compact_deck_enabled then - display_limit = 999999 -else - display_limit = Cartomancer.SETTINGS.compact_deck_visible_cards -end - -local deck_height = (self.config.deck_height or 0.15)/52 -local total_cards = #self.cards <= display_limit and #self.cards or display_limit -- limit height -local fixedX, fixedY, fixedR = nil, nil, nil - -for k, card in ipairs(self.cards) do - if card.facing == 'front' then card:flip() end - - if not card.states.drag.is then - if fixedX then - card.T.x = fixedX - card.T.y = fixedY - 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.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 - - if k >= display_limit then - fixedX = card.T.x - fixedY = card.T.y - fixedR = card.T.r - end - end - end -end''' -line_prepend = '$indent' - diff --git a/Cartomancer-v.4.10-fix-fix/lovely/stackable-deck-steamodded-0.9.8.toml b/Cartomancer-v.4.10-fix-fix/lovely/stackable-deck-steamodded-0.9.8.toml deleted file mode 100644 index bc0b3bf..0000000 --- a/Cartomancer-v.4.10-fix-fix/lovely/stackable-deck-steamodded-0.9.8.toml +++ /dev/null @@ -1,15 +0,0 @@ -[manifest] -version = "1.0.0" -dump_lua = true -priority = 69 - -# Add unique count - -[[patches]] -[patches.pattern] -target = "main.lua" -match_indent = true -pattern = "modded and {" -position = "before" -payload = ''' -not unplayed_only and Cartomancer.add_unique_count() or nil, -- Cartomancer Steamodded 0.9.8 compatibility''' diff --git a/Cartomancer-v.4.10-fix-fix/lovely/stackable-deck-steamodded.toml b/Cartomancer-v.4.10-fix-fix/lovely/stackable-deck-steamodded.toml deleted file mode 100644 index bd0eac2..0000000 --- a/Cartomancer-v.4.10-fix-fix/lovely/stackable-deck-steamodded.toml +++ /dev/null @@ -1,31 +0,0 @@ -[manifest] -version = "1.0.0" -dump_lua = true -priority = 69 - -# Initialize upvalue from file above, and override NFS.read now. -[[patches]] -[patches.pattern] -target = "main.lua" -match_indent = true -pattern = "SMODS.path = find_self(SMODS.MODS_DIR, 'core.lua', '--- STEAMODDED CORE')" -position = "after" -payload = ''' - -Cartomancer_nfs_read = NFS.read -NFS.read = Cartomancer_nfs_read_override - -''' - -# todo : use lovely for view deck patches - -#[[patches]] -#[patches.pattern] -#target = "Steamodded - src/overrides.lua" -#match_indent = true -#pattern = "--- STEAMODDED CORE" -#position = "after" -#payload = ''' -#-- YO WHADDUP -#print"------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------" -#''' \ No newline at end of file diff --git a/Cartomancer-v.4.10-fix-fix/lovely/stackable-deck-vanilla.toml b/Cartomancer-v.4.10-fix-fix/lovely/stackable-deck-vanilla.toml deleted file mode 100644 index 855bb27..0000000 --- a/Cartomancer-v.4.10-fix-fix/lovely/stackable-deck-vanilla.toml +++ /dev/null @@ -1,118 +0,0 @@ -[manifest] -version = "1.0.0" -dump_lua = true -priority = 69 - -# -# Vanilla patches -# - -# Overwrite how suits are added - -[[patches]] -[patches.pattern] -target = "functions/UI_definitions.lua" -pattern = "table.insert(SUITS[v.base.suit], v)" -position = "at" -payload = ''' -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() -if greyed then - card_string = card_string .. "Greyed" -end -if greyed and Cartomancer.SETTINGS.deck_view_hide_drawn_cards then - -- Ignore this card. -elseif not SUITS[v.base.suit][card_string] then - 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 - local stacked_card = SUITS[v.base.suit][card_string] - stacked_card.stacked_quantity = stacked_card.stacked_quantity + 1 - end''' -match_indent = true - -[[patches]] -[patches.regex] -target = "functions/UI_definitions.lua" -pattern = ''' -if SUITS\[suit_map\[j\]\]\[1\] then -[\t ]*local view_deck = CardArea\(''' -position = "at" -payload = ''' -if SUITS_SORTED[suit_map[j]][1] then - local view_deck = CardArea(''' -line_prepend = '' - -[[patches]] -[patches.pattern] -target = "functions/UI_definitions.lua" -pattern = "local suit_map = {'Spades', 'Hearts', 'Clubs', 'Diamonds'}" -position = "after" -payload = "local SUITS_SORTED = Cartomancer.tablecopy(SUITS)" -match_indent = true - -[[patches]] -[patches.pattern] -target = "functions/UI_definitions.lua" -pattern = "{card_limit = #SUITS[suit_map[j]], type = 'title', view_deck = true, highlight_limit = 0, card_w = G.CARD_W*0.7, draw_layers = {'card'}})" -position = "at" -payload = "{card_limit = #SUITS_SORTED[suit_map[j]], type = 'title', view_deck = true, highlight_limit = 0, card_w = G.CARD_W*0.7, draw_layers = {'card'}})" -match_indent = true - -# Add unique count - -[[patches]] -[patches.pattern] -target = "functions/UI_definitions.lua" -pattern = '''modded and {n=G.UIT.R, config={align = "cm"}, nodes={''' -position = "before" -payload = "not unplayed_only and Cartomancer.add_unique_count() or nil," -match_indent = true - -# Overwrite cards copy and display code - -[[patches]] -[patches.regex] -target = "functions/UI_definitions.lua" -pattern = ''' -(?[\t ]*)for i = 1\, \#SUITS\[suit_map\[j\]\] do -[\t ]* if SUITS\[suit_map\[j\]\]\[i\] then -[\t ]* local greyed\, _scale = nil\, 0\.7 -[\t ]* 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 -[\t ]* greyed = true -[\t ]* end -[\t ]* local copy = copy_card\(SUITS\[suit_map\[j\]\]\[i\]\,nil\, _scale\) -[\t ]* copy\.greyed = greyed -[\t ]* copy\.T\.x = view_deck\.T\.x \+ view_deck\.T\.w\/2 -[\t ]* copy\.T\.y = view_deck\.T\.y -[\t ]* -[\t ]* copy:hard_set_T\(\) -[\t ]* view_deck:emplace\(copy\) -[\t ]* end -[\t ]*end''' -position = "at" -payload = ''' -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 -''' -line_prepend = '$indent' \ No newline at end of file diff --git a/Cartomancer-v.4.10-fix-fix/lovely/tags.toml b/Cartomancer-v.4.10-fix-fix/lovely/tags.toml deleted file mode 100644 index 13a8f7e..0000000 --- a/Cartomancer-v.4.10-fix-fix/lovely/tags.toml +++ /dev/null @@ -1,14 +0,0 @@ -[manifest] -version = "1.0.0" -dump_lua = true -priority = 69 - - -[[patches]] -[patches.pattern] -target = 'game.lua' -pattern = '''G.FUNCS.blind_chip_UI_scale(G.hand_text_area.blind_chips)''' -position = 'before' -payload = ''' -Cartomancer.update_tags_visibility()''' -match_indent = true diff --git a/Cartomancer-v.4.10-fix-fix/lovely/vanilla-ui.toml b/Cartomancer-v.4.10-fix-fix/lovely/vanilla-ui.toml deleted file mode 100644 index 7aad247..0000000 --- a/Cartomancer-v.4.10-fix-fix/lovely/vanilla-ui.toml +++ /dev/null @@ -1,90 +0,0 @@ -[manifest] -version = "1.0.0" -dump_lua = true -priority = 69 - - -# Localization -[[patches]] -[patches.pattern] -target = "game.lua" -pattern = "boot_timer('prep stage', 'splash prep',1)" -position = "before" -payload = "Cartomancer.load_mod_file('internal/localization.lua', 'localization')" -match_indent = true - -# Add tab button to settings menu -[[patches]] -[patches.pattern] -target = "functions/UI_definitions.lua" -match_indent = true -position = "before" -pattern = '''local t = create_UIBox_generic_options({back_func = 'options',contents = {create_tabs(''' -payload = ''' -local settings_icon = Cartomancer.add_settings_icon() -if settings_icon then - tabs[#tabs+1] = { - colour = G.C.MONEY, - custom_button = {settings_icon}, - tab_definition_function = Cartomancer.config_tab, - tab_definition_function_args = '' - } -end -''' - -# Use custom button -[[patches]] -[patches.pattern] -target = "functions/UI_definitions.lua" -match_indent = true -position = "at" -pattern = '''but_UI_label''' -payload = ''' -args.ref_table and args.ref_table.custom_button or but_UI_label -- Cartomancer''' - -# Use custom color -[[patches]] -[patches.pattern] -target = "functions/UI_definitions.lua" -match_indent = true -position = "at" -pattern = '''colour = args.colour,''' -payload = ''' -colour = args.ref_table and args.ref_table.colour or args.colour, -- Cartomancer''' - - -# From steamodded for vertical tabs support. -# Fix UIElement.config.chosen being overriden if choice=true is set -# UIElement:click() -[[patches]] -[patches.pattern] -target = "engine/ui.lua" -match_indent = true -position = "after" -pattern = "if self.config.choice then" -payload = " local chosen_temp = self.config.chosen" - -[[patches]] -[patches.pattern] -target = "engine/ui.lua" -match_indent = true -position = "at" -pattern = "self.config.chosen = true" -payload = "self.config.chosen = chosen_temp or true" - -# Add dynamic label support to UIBox_button -[[patches]] -[patches.pattern] -target = "functions/UI_definitions.lua" -match_indent = true -position = "before" -pattern = "for k, v in ipairs(args.label) do" -payload = ''' -if args.dynamic_label then - but_UI_label = {} - - table.insert(but_UI_label, {n=G.UIT.R, config={align = "cm", padding = 0, minw = args.minw, maxw = args.maxw}, nodes={ - {n=G.UIT.T, config={ref_table = args.dynamic_label, ref_value = 'text', scale = args.scale, colour = args.text_colour, shadow = args.shadow, focus_args = button_pip and args.focus_args or nil, func = button_pip,}} - }}) -end -''' \ No newline at end of file diff --git a/Cartomancer-v.4.10-fix-fix/lovely/zoom-jokers.toml b/Cartomancer-v.4.10-fix-fix/lovely/zoom-jokers.toml deleted file mode 100644 index dd92f4a..0000000 --- a/Cartomancer-v.4.10-fix-fix/lovely/zoom-jokers.toml +++ /dev/null @@ -1,58 +0,0 @@ -[manifest] -version = "1.0.0" -dump_lua = true -priority = 69 - -# Replace joker sorting. Needs better mod compat -[[patches]] -[patches.pattern] -target = "cardarea.lua" -pattern = "if self.config.type == 'joker' or self.config.type == 'title_2' then" -position = "at" -payload = ''' -if self == G.jokers and G.jokers.cart_jokers_expanded then - local align_cards = Cartomancer.expand_G_jokers() - - -- This should work fine without cryptid. But because cryptid's patch is priority=0, it has to be this way - if not G.GAME.modifiers.cry_conveyor then - table.sort(self.cards, function (a, b) return a.T.x + a.T.w/2 - 100*(a.pinned and a.sort_id or 0) < b.T.x + b.T.w/2 - 100*(b.pinned and b.sort_id or 0) end) - end - - if align_cards then - G.jokers:hard_set_cards() - end -elseif self.config.type == 'joker' or self.config.type == 'title_2' then''' -match_indent = true - -# Hide all cards that are off-screen -[[patches]] -[patches.pattern] -target = "card.lua" -pattern = "if not self.states.visible then return end" -position = "after" -payload = ''' -if self.VT.x < -3 or self.VT.x > G.TILE_W + 2.5 then return end''' -match_indent = true - -# Add slider ID -[[patches]] -[patches.pattern] -target = "functions/UI_definitions.lua" -pattern = '''{n=G.UIT.B, config={w=startval,h=args.h, r = 0.1, colour = args.colour, ref_table = args, refresh_movement = true}},''' -position = "at" -payload = ''' -{n=G.UIT.B, config={id = args.id, w=startval,h=args.h, r = 0.1, colour = args.colour, ref_table = args, refresh_movement = true}}, -''' -match_indent = true - -# Hide slider value -[[patches]] -[patches.regex] -target = "functions/UI_definitions.lua" -pattern = ''' -(?\{n=G\.UIT\.C\, config=\{align = "cm"\, minh = args\.h\,r = 0\.1\, minw = 0\.8\, colour = args\.colour\,shadow = true\}\, nodes=\{ -[\t ]*\{n=G\.UIT\.T\, config=\{ref_table = args\, ref_value = 'text'\, scale = args\.text_scale\, colour = G\.C\.UI\.TEXT_LIGHT\, decimal_places = args\.decimal_places\}\} -[\t ]*\}\})\,''' -position = "at" -payload = ''' -not args.hide_val and $content or nil''' diff --git a/Cartomancer-v.4.10-fix-fix/LICENSE b/Cartomancer/LICENSE similarity index 100% rename from Cartomancer-v.4.10-fix-fix/LICENSE rename to Cartomancer/LICENSE diff --git a/Cartomancer-v.4.10-fix-fix/assets/1x/modicon.png b/Cartomancer/assets/1x/modicon.png similarity index 100% rename from Cartomancer-v.4.10-fix-fix/assets/1x/modicon.png rename to Cartomancer/assets/1x/modicon.png diff --git a/Cartomancer-v.4.10-fix-fix/assets/1x/settings.png b/Cartomancer/assets/1x/settings.png similarity index 100% rename from Cartomancer-v.4.10-fix-fix/assets/1x/settings.png rename to Cartomancer/assets/1x/settings.png diff --git a/Cartomancer-v.4.10-fix-fix/assets/2x/modicon.png b/Cartomancer/assets/2x/modicon.png similarity index 100% rename from Cartomancer-v.4.10-fix-fix/assets/2x/modicon.png rename to Cartomancer/assets/2x/modicon.png diff --git a/Cartomancer-v.4.10-fix-fix/assets/2x/settings.png b/Cartomancer/assets/2x/settings.png similarity index 100% rename from Cartomancer-v.4.10-fix-fix/assets/2x/settings.png rename to Cartomancer/assets/2x/settings.png diff --git a/Cartomancer-v.4.10-fix-fix/cartomancer.lua b/Cartomancer/cartomancer.lua similarity index 100% rename from Cartomancer-v.4.10-fix-fix/cartomancer.lua rename to Cartomancer/cartomancer.lua diff --git a/Cartomancer-v.4.10-fix-fix/config.lua b/Cartomancer/config.lua similarity index 98% rename from Cartomancer-v.4.10-fix-fix/config.lua rename to Cartomancer/config.lua index 09171ef..e63fc55 100644 --- a/Cartomancer-v.4.10-fix-fix/config.lua +++ b/Cartomancer/config.lua @@ -19,6 +19,7 @@ return { -- todo: maybe custom shader for drawn cards to adjust opacity improved_hand_sorting = false, + dynamic_hand_align = false, draw_non_essential_shaders = true, hide_tags = false, hide_consumables = false, diff --git a/Cartomancer-v.4.10-fix-fix/core/flames.lua b/Cartomancer/core/flames.lua similarity index 100% rename from Cartomancer-v.4.10-fix-fix/core/flames.lua rename to Cartomancer/core/flames.lua diff --git a/Cartomancer-v.4.10-fix-fix/core/hand.lua b/Cartomancer/core/hand.lua similarity index 100% rename from Cartomancer-v.4.10-fix-fix/core/hand.lua rename to Cartomancer/core/hand.lua diff --git a/Cartomancer-v.4.10-fix-fix/core/jokers.lua b/Cartomancer/core/jokers.lua similarity index 100% rename from Cartomancer-v.4.10-fix-fix/core/jokers.lua rename to Cartomancer/core/jokers.lua diff --git a/Cartomancer-v.4.10-fix-fix/core/optimizations.lua b/Cartomancer/core/optimizations.lua similarity index 100% rename from Cartomancer-v.4.10-fix-fix/core/optimizations.lua rename to Cartomancer/core/optimizations.lua diff --git a/Cartomancer-v.4.10-fix-fix/core/view-deck-steamodded.lua b/Cartomancer/core/view-deck-steamodded.lua similarity index 87% rename from Cartomancer-v.4.10-fix-fix/core/view-deck-steamodded.lua rename to Cartomancer/core/view-deck-steamodded.lua index 1357ec4..935fafa 100644 --- a/Cartomancer-v.4.10-fix-fix/core/view-deck-steamodded.lua +++ b/Cartomancer/core/view-deck-steamodded.lua @@ -1,4 +1,7 @@ +-- THIS IS NO LONGER BEING USED +-- Leaving this in for sentimental value :) + local Cartomancer_replacements = { { find = [[ @@ -16,21 +19,12 @@ for k, v in ipairs(G.playing_cards) do 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() + 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 Cartomancer.SETTINGS.deck_view_stack_enabled then - -- Don't stack cards - local _scale = 0.7 - local copy = copy_card(v, nil, _scale) - - copy.greyed = greyed - copy.stacked_quantity = 1 - table.insert(SUITS_SORTED[v.base.suit], copy) - elseif not SUITS[v.base.suit][card_string] then -- Initiate stack table.insert(SUITS_SORTED[v.base.suit], card_string) @@ -74,13 +68,8 @@ for i = 1%, %#SUITS%[suit_map%[j%]%] do end]], place = [[ for i = 1%, %#SUITS_SORTED%[suit_map%[j%]%] do - local card - if not Cartomancer.SETTINGS.deck_view_stack_enabled then - card = SUITS_SORTED%[suit_map%[j%]%]%[i%] - else - local card_string = SUITS_SORTED%[suit_map%[j%]%]%[i%] - card = SUITS%[suit_map%[j%]%]%[card_string%] - end + 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 diff --git a/Cartomancer-v.4.10-fix-fix/core/view-deck.lua b/Cartomancer/core/view-deck.lua similarity index 93% rename from Cartomancer-v.4.10-fix-fix/core/view-deck.lua rename to Cartomancer/core/view-deck.lua index e32945f..a2e2579 100644 --- a/Cartomancer-v.4.10-fix-fix/core/view-deck.lua +++ b/Cartomancer/core/view-deck.lua @@ -2,6 +2,11 @@ function Card:cart_to_string(args) local args = args or {} + -- With deck stacking disabled, sort_id should make all cards unstacked in deck view. + if args.deck_view and not Cartomancer.SETTINGS.deck_view_stack_enabled then + return tostring(self.sort_id) + end + local suit = self.base and ( -- if has base, check for stone / no_suit -- only use NoSuit for unique_count, deck view displays every stone card in respective suit area @@ -19,7 +24,7 @@ function Card:cart_to_string(args) rank = rank .. tostring(self:get_chip_bonus()) end - if not args.unique_count and Cartomancer.SETTINGS.deck_view_stack_modifiers then + if args.deck_view and Cartomancer.SETTINGS.deck_view_stack_modifiers then return string.format( "%s%s", suit, diff --git a/Cartomancer-v.4.10-fix-fix/internal/atlas.lua b/Cartomancer/internal/atlas.lua similarity index 100% rename from Cartomancer-v.4.10-fix-fix/internal/atlas.lua rename to Cartomancer/internal/atlas.lua diff --git a/Cartomancer-v.4.10-fix-fix/internal/config.lua b/Cartomancer/internal/config.lua similarity index 100% rename from Cartomancer-v.4.10-fix-fix/internal/config.lua rename to Cartomancer/internal/config.lua diff --git a/Cartomancer-v.4.10-fix-fix/internal/init.lua b/Cartomancer/internal/init.lua similarity index 100% rename from Cartomancer-v.4.10-fix-fix/internal/init.lua rename to Cartomancer/internal/init.lua diff --git a/Cartomancer-v.4.10-fix-fix/internal/keybinds.lua b/Cartomancer/internal/keybinds.lua similarity index 100% rename from Cartomancer-v.4.10-fix-fix/internal/keybinds.lua rename to Cartomancer/internal/keybinds.lua diff --git a/Cartomancer-v.4.10-fix-fix/internal/localization.lua b/Cartomancer/internal/localization.lua similarity index 69% rename from Cartomancer-v.4.10-fix-fix/internal/localization.lua rename to Cartomancer/internal/localization.lua index c97851d..6423f49 100644 --- a/Cartomancer-v.4.10-fix-fix/internal/localization.lua +++ b/Cartomancer/internal/localization.lua @@ -16,3 +16,13 @@ local function recurse(target, ref_table) 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 diff --git a/Cartomancer-v.4.10-fix-fix/internal/ui.lua b/Cartomancer/internal/ui.lua similarity index 99% rename from Cartomancer-v.4.10-fix-fix/internal/ui.lua rename to Cartomancer/internal/ui.lua index 7b37017..f0377e6 100644 --- a/Cartomancer-v.4.10-fix-fix/internal/ui.lua +++ b/Cartomancer/internal/ui.lua @@ -143,6 +143,10 @@ Cartomancer.config_tab = function() 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 = 'dynamic_hand_align', + localization = 'carto_dynamic_hand_align', + }, create_toggle_option { ref_value = 'draw_non_essential_shaders', localization = 'carto_draw_non_essential_shaders', diff --git a/Cartomancer-v.4.10-fix-fix/libs/nativefs.lua b/Cartomancer/libs/nativefs.lua similarity index 100% rename from Cartomancer-v.4.10-fix-fix/libs/nativefs.lua rename to Cartomancer/libs/nativefs.lua diff --git a/Cartomancer-v.4.10-fix-fix/localization/en-us.lua b/Cartomancer/localization/en-us.lua similarity index 97% rename from Cartomancer-v.4.10-fix-fix/localization/en-us.lua rename to Cartomancer/localization/en-us.lua index 848128a..c45a66e 100644 --- a/Cartomancer-v.4.10-fix-fix/localization/en-us.lua +++ b/Cartomancer/localization/en-us.lua @@ -34,6 +34,7 @@ return { 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_hide_tags = "Hide tags", carto_hide_consumables = "Hide consumables", carto_hide_deck = "Hide deck", diff --git a/Cartomancer-v.4.10-fix-fix/lovely.toml b/Cartomancer/lovely.toml similarity index 100% rename from Cartomancer-v.4.10-fix-fix/lovely.toml rename to Cartomancer/lovely.toml diff --git a/Cartomancer-v.4.10-fix-fix/mod.lua b/Cartomancer/mod.lua similarity index 97% rename from Cartomancer-v.4.10-fix-fix/mod.lua rename to Cartomancer/mod.lua index 57f2351..f2bb117 100644 --- a/Cartomancer-v.4.10-fix-fix/mod.lua +++ b/Cartomancer/mod.lua @@ -6,7 +6,7 @@ --- PRIORITY: 69 --- BADGE_COLOR: FFD700 --- DISPLAY_NAME: Cartomancer ---- VERSION: 4.10 +--- VERSION: 4.12 ---------------------------------------------- ------------MOD CODE ------------------------- diff --git a/Cartomancer/version b/Cartomancer/version new file mode 100755 index 0000000..8fc491d --- /dev/null +++ b/Cartomancer/version @@ -0,0 +1 @@ +4.12-fix \ No newline at end of file diff --git a/Cryptid/Cryptid.json b/Cryptid/Cryptid.json new file mode 100644 index 0000000..b7cd620 --- /dev/null +++ b/Cryptid/Cryptid.json @@ -0,0 +1,17 @@ +{ + "id": "Cryptid", + "name": "Cryptid", + "display_name": "Cryptid", + "author": ["MathIsFun_, Cryptid and Balatro Discords"], + "description": "Adds unbalanced ideas to Balatro.", + "prefix": "cry", + "main_file": "Cryptid.lua", + "priority": 114, + "badge_colour": "708b91", + "badge_text_colour": "FFFFFF", + "version": "0.5.5", + "dependencies": [ + "Talisman (>=2.0.9)", + "Steamodded (>=1.0.0~BETA-0308a)" + ] +} diff --git a/Cryptid/Cryptid.lua b/Cryptid/Cryptid.lua index c297f2e..64ccdde 100644 --- a/Cryptid/Cryptid.lua +++ b/Cryptid/Cryptid.lua @@ -1,31 +1,14 @@ ---- STEAMODDED HEADER ---- MOD_NAME: Cryptid ---- MOD_ID: Cryptid ---- PREFIX: cry ---- MOD_AUTHOR: [MathIsFun_, Cryptid and Balatro Discords] ---- MOD_DESCRIPTION: Adds unbalanced ideas to Balatro. ---- BADGE_COLOUR: 708b91 ---- DEPENDENCIES: [Talisman>=2.0.9, Steamodded>=1.0.0~ALPHA-1312c] ---- VERSION: 0.5.4 ---- PRIORITY: 2147483647 - ----------------------------------------------- -------------MOD CODE ------------------------- - -- Welcome to the Cryptid source code! -- This is the main file for the mod, where everything is loaded and initialized. --- If you're looking for a specific feature, browse the Items folder to see how it is implemented. +-- If you're looking for a specific feature, browse the items folder to see how it is implemented. -- If you're looking for a specific function, check the lib folder to see if it is there. --- Initialize some important variables if not Cryptid then Cryptid = {} end local mod_path = "" .. SMODS.current_mod.path -- this path changes when each mod is loaded, but the local variable will retain Cryptid's path Cryptid.path = mod_path Cryptid_config = SMODS.current_mod.config --- This will save the current state even when settings are modified -Cryptid.enabled = copy_table(Cryptid_config) -- Enable optional features SMODS.current_mod.optional_features = { @@ -71,8 +54,13 @@ local function process_items(f, mod) key = false, atlas = false, } + item.mod_path = mod.path if item.key then - item.key = mod.prefix .. "_" .. item.key + if item.object_type and SMODS[item.object_type].class_prefix then + item.key = SMODS[item.object_type].class_prefix .. "_" .. mod.prefix .. "_" .. item.key + else + item.key = mod.prefix .. "_" .. item.key + end end if item.atlas then item.atlas = mod.prefix .. "_" .. item.atlas @@ -153,7 +141,7 @@ for _, mod in pairs(SMODS.Mods) do end process_items(f, mod) end - if file == "Cryptid" then + if file == "Cryptid" and path .. "Cryptid/" ~= Cryptid.path then local files = NFS.getDirectoryItems(path .. "Cryptid") for _, file in ipairs(files) do print("[CRYPTID] Loading file " .. file .. " from " .. mod.id) @@ -184,7 +172,7 @@ end local inj = SMODS.injectItems function SMODS.injectItems(...) inj(...) - cry_update_obj_registry() + Cryptid.update_obj_registry() for _, t in ipairs({ G.P_CENTERS, G.P_BLINDS, @@ -226,6 +214,7 @@ local cryptidConfigTab = function() config = { n = G.UIT.R, config = { align = "tm", padding = 0 }, nodes = { left_settings, right_settings } } cry_nodes[#cry_nodes + 1] = config cry_nodes[#cry_nodes + 1] = UIBox_button({ + colour = G.C.CRY_GREENGRADIENT, button = "your_collection_content_sets", label = { localize("b_content_sets") }, count = modsCollectionTally(G.P_CENTER_POOLS["Content Set"]), @@ -237,18 +226,31 @@ local cryptidConfigTab = function() --Add warning notifications later for family mode cry_nodes[#cry_nodes + 1] = create_toggle({ label = localize("cry_family"), - active_colour = G.C.MONEY, + active_colour = HEX("40c76d"), ref_table = Cryptid_config, ref_value = "family_mode", - callback = reload_cryptid_localization, + callback = Cryptid.reload_localization, }) cry_nodes[#cry_nodes + 1] = create_toggle({ label = localize("cry_experimental"), - active_colour = G.C.MONEY, + active_colour = HEX("1f8505"), ref_table = Cryptid_config, ref_value = "experimental", }) + cry_nodes[#cry_nodes + 1] = create_toggle({ + label = localize("cry_feat_https module"), + active_colour = HEX("b1c78d"), + ref_table = Cryptid_config, + ref_value = "HTTPS", + }) + cry_nodes[#cry_nodes + 1] = create_toggle({ + label = localize("cry_feat_menu"), + active_colour = HEX("1c5c23"), + ref_table = Cryptid_config, + ref_value = "menu", + }) cry_nodes[#cry_nodes + 1] = UIBox_button({ + colour = G.C.CRY_ALTGREENGRADIENT, button = "reset_gameset_config", label = { localize("b_reset_gameset_" .. (G.PROFILES[G.SETTINGS.profile].cry_gameset or "mainline")) }, minw = 5, @@ -292,26 +294,31 @@ local cryptidTabs = function() } settings = { n = G.UIT.C, config = { align = "tl", padding = 0.05 }, nodes = {} } settings.nodes[#settings.nodes + 1] = create_toggle({ + active_colour = G.C.CRY_JOLLY, label = localize("cry_mus_jimball"), ref_table = Cryptid_config.Cryptid, ref_value = "jimball_music", }) settings.nodes[#settings.nodes + 1] = create_toggle({ + active_colour = G.C.CRY_JOLLY, label = localize("cry_mus_code"), ref_table = Cryptid_config.Cryptid, ref_value = "code_music", }) settings.nodes[#settings.nodes + 1] = create_toggle({ + active_colour = G.C.CRY_JOLLY, label = localize("cry_mus_exotic"), ref_table = Cryptid_config.Cryptid, ref_value = "exotic_music", }) settings.nodes[#settings.nodes + 1] = create_toggle({ + active_colour = G.C.CRY_JOLLY, label = localize("cry_mus_high_score"), ref_table = Cryptid_config.Cryptid, ref_value = "big_music", }) settings.nodes[#settings.nodes + 1] = create_toggle({ + active_colour = G.C.CRY_JOLLY, label = localize("cry_mus_alt_bg"), ref_table = Cryptid_config.Cryptid, ref_value = "alt_bg_music", diff --git a/Cryptid/assets/1x/atlasSleeves.png b/Cryptid/assets/1x/atlasSleeves.png index a5fd82d..7732baf 100644 Binary files a/Cryptid/assets/1x/atlasSleeves.png and b/Cryptid/assets/1x/atlasSleeves.png differ diff --git a/Cryptid/assets/1x/atlasdeck.png b/Cryptid/assets/1x/atlasdeck.png index 43ab466..6719fed 100644 Binary files a/Cryptid/assets/1x/atlasdeck.png and b/Cryptid/assets/1x/atlasdeck.png differ diff --git a/Cryptid/assets/1x/atlaseditiondeck.png b/Cryptid/assets/1x/atlaseditiondeck.png index 32d3cea..a81d699 100644 Binary files a/Cryptid/assets/1x/atlaseditiondeck.png and b/Cryptid/assets/1x/atlaseditiondeck.png differ diff --git a/Cryptid/assets/1x/atlasepic.png b/Cryptid/assets/1x/atlasepic.png index fd9138b..2591a75 100644 Binary files a/Cryptid/assets/1x/atlasepic.png and b/Cryptid/assets/1x/atlasepic.png differ diff --git a/Cryptid/assets/1x/atlasexotic.png b/Cryptid/assets/1x/atlasexotic.png index e96113a..e4cac0d 100644 Binary files a/Cryptid/assets/1x/atlasexotic.png and b/Cryptid/assets/1x/atlasexotic.png differ diff --git a/Cryptid/assets/1x/atlasone.png b/Cryptid/assets/1x/atlasone.png index b782bbc..ec0fb2a 100644 Binary files a/Cryptid/assets/1x/atlasone.png and b/Cryptid/assets/1x/atlasone.png differ diff --git a/Cryptid/assets/1x/atlasthree.png b/Cryptid/assets/1x/atlasthree.png index 6513191..ae80eda 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 08d1bfc..0c49b8d 100644 Binary files a/Cryptid/assets/1x/atlastwo.png and b/Cryptid/assets/1x/atlastwo.png differ diff --git a/Cryptid/assets/1x/c_cry_code.png b/Cryptid/assets/1x/c_cry_code.png index 1a01d1a..100dd2c 100644 Binary files a/Cryptid/assets/1x/c_cry_code.png and b/Cryptid/assets/1x/c_cry_code.png differ diff --git a/Cryptid/assets/1x/cry_achievements.png b/Cryptid/assets/1x/cry_achievements.png index 929a4d6..9712b47 100644 Binary files a/Cryptid/assets/1x/cry_achievements.png and b/Cryptid/assets/1x/cry_achievements.png differ diff --git a/Cryptid/assets/1x/goofy.png b/Cryptid/assets/1x/goofy.png index f121446..ae07adb 100644 Binary files a/Cryptid/assets/1x/goofy.png and b/Cryptid/assets/1x/goofy.png differ diff --git a/Cryptid/assets/1x/shinyc.png b/Cryptid/assets/1x/shinyc.png new file mode 100644 index 0000000..79e0271 Binary files /dev/null and b/Cryptid/assets/1x/shinyc.png differ diff --git a/Cryptid/assets/1x/shinyv.png b/Cryptid/assets/1x/shinyv.png new file mode 100644 index 0000000..2e30729 Binary files /dev/null and b/Cryptid/assets/1x/shinyv.png differ diff --git a/Cryptid/assets/1x/sticker_cry.png b/Cryptid/assets/1x/sticker_cry.png index 61d1191..be0b290 100644 Binary files a/Cryptid/assets/1x/sticker_cry.png and b/Cryptid/assets/1x/sticker_cry.png differ diff --git a/Cryptid/assets/2x/atlasSleeves.png b/Cryptid/assets/2x/atlasSleeves.png index 45ded79..6327e3c 100644 Binary files a/Cryptid/assets/2x/atlasSleeves.png and b/Cryptid/assets/2x/atlasSleeves.png differ diff --git a/Cryptid/assets/2x/atlasdeck.png b/Cryptid/assets/2x/atlasdeck.png index 815eae1..733a085 100644 Binary files a/Cryptid/assets/2x/atlasdeck.png and b/Cryptid/assets/2x/atlasdeck.png differ diff --git a/Cryptid/assets/2x/atlaseditiondeck.png b/Cryptid/assets/2x/atlaseditiondeck.png index b3adaf7..425faff 100644 Binary files a/Cryptid/assets/2x/atlaseditiondeck.png and b/Cryptid/assets/2x/atlaseditiondeck.png differ diff --git a/Cryptid/assets/2x/atlasepic.png b/Cryptid/assets/2x/atlasepic.png index 878bffe..106806f 100644 Binary files a/Cryptid/assets/2x/atlasepic.png and b/Cryptid/assets/2x/atlasepic.png differ diff --git a/Cryptid/assets/2x/atlasexotic.png b/Cryptid/assets/2x/atlasexotic.png index c1afaea..1b72fbe 100644 Binary files a/Cryptid/assets/2x/atlasexotic.png and b/Cryptid/assets/2x/atlasexotic.png differ diff --git a/Cryptid/assets/2x/atlasone.png b/Cryptid/assets/2x/atlasone.png index 40a13c8..67f2256 100644 Binary files a/Cryptid/assets/2x/atlasone.png and b/Cryptid/assets/2x/atlasone.png differ diff --git a/Cryptid/assets/2x/atlasthree.png b/Cryptid/assets/2x/atlasthree.png index 3932388..961fdf7 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 7a7664e..ef74a6b 100644 Binary files a/Cryptid/assets/2x/atlastwo.png and b/Cryptid/assets/2x/atlastwo.png differ diff --git a/Cryptid/assets/2x/c_cry_code.png b/Cryptid/assets/2x/c_cry_code.png index 8ab62f3..11653cf 100644 Binary files a/Cryptid/assets/2x/c_cry_code.png and b/Cryptid/assets/2x/c_cry_code.png differ diff --git a/Cryptid/assets/2x/cry_achievements.png b/Cryptid/assets/2x/cry_achievements.png index 244dc2e..b2add8f 100644 Binary files a/Cryptid/assets/2x/cry_achievements.png and b/Cryptid/assets/2x/cry_achievements.png differ diff --git a/Cryptid/assets/2x/goofy.png b/Cryptid/assets/2x/goofy.png index 220317f..d53f7ec 100644 Binary files a/Cryptid/assets/2x/goofy.png and b/Cryptid/assets/2x/goofy.png differ diff --git a/Cryptid/assets/2x/shinyc.png b/Cryptid/assets/2x/shinyc.png new file mode 100644 index 0000000..2515d04 Binary files /dev/null and b/Cryptid/assets/2x/shinyc.png differ diff --git a/Cryptid/assets/2x/shinyv.png b/Cryptid/assets/2x/shinyv.png new file mode 100644 index 0000000..e13b22a Binary files /dev/null and b/Cryptid/assets/2x/shinyv.png differ diff --git a/Cryptid/assets/2x/sticker_cry.png b/Cryptid/assets/2x/sticker_cry.png index 50cc5c8..43cfd6e 100644 Binary files a/Cryptid/assets/2x/sticker_cry.png and b/Cryptid/assets/2x/sticker_cry.png differ diff --git a/Cryptid/config.lua b/Cryptid/config.lua index 2972677..8912a73 100644 --- a/Cryptid/config.lua +++ b/Cryptid/config.lua @@ -8,4 +8,6 @@ return { }, ["family_mode"] = false, ["experimental"] = false, + ["HTTPS"] = true, + ["menu"] = true, } diff --git a/Cryptid/https/linux-https.so b/Cryptid/https/linux-https.so deleted file mode 100644 index c1c0a6d..0000000 Binary files a/Cryptid/https/linux-https.so and /dev/null differ diff --git a/Cryptid/https/macos-https.so b/Cryptid/https/macos-https.so deleted file mode 100644 index a6e5c98..0000000 Binary files a/Cryptid/https/macos-https.so and /dev/null differ diff --git a/Cryptid/https/thread.lua b/Cryptid/https/thread.lua deleted file mode 100644 index b1cd796..0000000 --- a/Cryptid/https/thread.lua +++ /dev/null @@ -1,36 +0,0 @@ -require("love.system") - --- mac/linux support? - -local script_path = debug.getinfo(1, "S").source:sub(2) -local script_dir = script_path:match("(.*/)") - -package.path = script_dir .. "?.lua;" .. package.path -package.cpath = script_dir .. "?.so;" .. package.cpath - -local index_os = love.system.getOS() - -if index_os == "OS X" then - loc_https = require("macos-https") -elseif index_os == "Linux" then - loc_https = require("linux-https") -else - loc_https = require("https") -end - -local last_update_time = 0 -local initial = true -while true do - if (os.time() - last_update_time >= 60) or initial then - initial = nil - last_update_time = os.time() - local resp, txt = loc_https.request( - "https://discord.com/api/v10/invites/eUf9Ur6RyB?with_counts=true" .. "&v=" .. tostring(os.time()) - ) - if resp == 200 then - love.thread.getChannel("member_count"):push(txt) - else - love.thread.getChannel("member_error"):push("Failed to get count: " .. resp) - end - end -end diff --git a/Cryptid/items/achievement.lua b/Cryptid/items/achievement.lua index c0059ae..505e3f7 100644 --- a/Cryptid/items/achievement.lua +++ b/Cryptid/items/achievement.lua @@ -337,7 +337,7 @@ local home_realtor = { atlas = "cry_achievements", --reset_on_startup = true, unlock_condition = function(self, args) - --todo: check for doe/antimatter sleeves + --TODO: check for antimatter sleeve in the check_unlock when it's added if args.type == "home_realtor" then return true end @@ -394,6 +394,20 @@ local perfectly_balanced = { end end, } +local pin = { + object_type = "Achievement", + key = "pin", + order = 21, + hidden_text = true, + pos = { x = 3, y = 0 }, + atlas = "cry_achievements", + bypass_all_unlocked = true, + unlock_condition = function(self, args) + if args.type == "lose_to_specific_blind" and args.blind == "cry-pin" then + return true + end + end, +} -- TODO: Add new Achievements. -- Current Ideas (Normal): @@ -446,5 +460,6 @@ local achievement_objects = { home_realtor, traffic_jam, perfectly_balanced, + --pin, Needs to be screened } return { name = "Achievements", items = achievement_objects } diff --git a/Cryptid/items/blind.lua b/Cryptid/items/blind.lua index 53d59d8..ca64c82 100644 --- a/Cryptid/items/blind.lua +++ b/Cryptid/items/blind.lua @@ -546,10 +546,14 @@ local shackle = { if G.GAME.modifiers.cry_force_edition and G.GAME.modifiers.cry_force_edition == "negative" then return false end - return #advanced_find_joker(nil, nil, "e_negative", nil, true) ~= 0 + return #Cryptid.advanced_find_joker(nil, nil, "e_negative", nil, true) ~= 0 end, recalc_debuff = function(self, card, from_blind) - if (card.area == G.jokers) and not G.GAME.blind.disabled and safe_get(card, "edition", "negative") == true then + if + (card.area == G.jokers) + and not G.GAME.blind.disabled + and Cryptid.safe_get(card, "edition", "negative") == true + then return true end return false @@ -577,7 +581,7 @@ local pin = { if not G.jokers or not G.jokers.cards then return false end - return #advanced_find_joker(nil, { 1, 2, 3 }, nil, nil, true) < #G.jokers.cards + return #Cryptid.advanced_find_joker(nil, { 1, 2, 3 }, nil, nil, true) < #G.jokers.cards end, recalc_debuff = function(self, card, from_blind) if @@ -665,7 +669,7 @@ local tornado = { order = 94, boss_colour = HEX("3dd9ca"), loc_vars = function(self) - return { vars = { "" .. ((safe_get(G.GAME, "probabilities", "normal") or 1) * 2), 3 } } + return { vars = { "" .. ((Cryptid.safe_get(G.GAME, "probabilities", "normal") or 1) * 2), 3 } } end, set_blind = function(self, reset, silent) if not reset then @@ -673,10 +677,10 @@ local tornado = { end end, in_pool = function() - return #advanced_find_joker("Oops! All 6s", nil, nil, { "eternal" }, nil) == 0 + return #Cryptid.advanced_find_joker("Oops! All 6s", nil, nil, { "eternal" }, nil) == 0 end, collection_loc_vars = function(self) - return { vars = { "" .. ((safe_get(G.GAME, "probabilities", "normal") or 1) * 2), 3 } } + return { vars = { "" .. ((Cryptid.safe_get(G.GAME, "probabilities", "normal") or 1) * 2), 3 } } end, debuff_hand = function(self, cards, hand, handname, check) if @@ -1301,7 +1305,9 @@ local trophy = { order = 95, boss_colour = HEX("bbdb44"), set_blind = function(self, reset, silent) - G.GAME.trophymod = true + if not reset then + G.GAME.trophymod = true + end end, defeat = function(self, silent) if G.GAME.trophymod then diff --git a/Cryptid/items/challenge.lua b/Cryptid/items/challenge.lua index a4e05a6..764e35b 100644 --- a/Cryptid/items/challenge.lua +++ b/Cryptid/items/challenge.lua @@ -16,7 +16,9 @@ local sticker_sheet = { modifiers = {}, }, restrictions = { - banned_cards = {}, + banned_cards = { + { id = "c_cry_lock" }, + }, banned_other = {}, }, deck = { @@ -35,7 +37,9 @@ local sticker_sheet_plus = { modifiers = {}, }, restrictions = { - banned_cards = {}, + banned_cards = { + { id = "c_cry_lock" }, + }, banned_other = {}, }, deck = { @@ -74,6 +78,8 @@ local ballin = { { id = "c_familiar" }, { id = "c_grim" }, { id = "c_incantation" }, + { id = "c_cry_eclipse" }, + { id = "c_cry_class" }, }, banned_other = {}, }, @@ -122,6 +128,10 @@ local rush_hour_ii = { { id = "j_diet_cola" }, { id = "v_directors_cut" }, { id = "v_retcon" }, + { id = "j_cry_pickle" }, + { id = "v_cry_copies" }, + { id = "v_cry_tag_printer" }, + { id = "v_cry_clone_machine" }, }, banned_other = {}, }, @@ -212,6 +222,10 @@ local rush_hour_iii = { { id = "j_diet_cola" }, { id = "v_directors_cut" }, { id = "v_retcon" }, + { id = "j_cry_pickle" }, + { id = "v_cry_copies" }, + { id = "v_cry_tag_printer" }, + { id = "v_cry_clone_machine" }, }, banned_other = {}, }, @@ -241,6 +255,10 @@ local boss_rush = { { id = "j_diet_cola" }, { id = "v_directors_cut" }, { id = "v_retcon" }, + { id = "j_cry_pickle" }, + { id = "v_cry_copies" }, + { id = "v_cry_tag_printer" }, + { id = "v_cry_clone_machine" }, }, banned_other = {}, }, @@ -264,8 +282,13 @@ local rng = { { id = "tag_uncommon" }, { id = "tag_rare" }, { id = "tag_top_up" }, + { id = "tag_cry_epic" }, + }, + banned_cards = { + { id = "j_cry_equilib" }, + { id = "c_cry_delete" }, + { id = "p_cry_meme_1", ids = { "p_cry_meme_1", "p_cry_meme_two", "p_cry_meme_three" } }, }, - banned_cards = {}, banned_other = {}, }, } @@ -311,15 +334,22 @@ local onlycard = { { id = "tag_meteor" }, { id = "tag_buffoon" }, { id = "tag_ethereal" }, + { id = "tag_cry_bundle" }, + { id = "tag_cry_loss" }, + { id = "tag_cry_gambler" }, + { id = "tag_cry_empowered" }, + { id = "tag_cry_console" }, }, banned_cards = { { id = "j_marble" }, { id = "j_dna" }, { id = "j_certificate" }, + { id = "j_cry_multjoker" }, { id = "c_familiar" }, { id = "c_grim" }, { id = "c_incantation" }, { id = "c_cryptid" }, + { id = "c_cry_replica" }, { id = "p_celestial_normal_1", ids = { @@ -364,6 +394,19 @@ local onlycard = { "p_buffoon_mega_1", }, }, + { + id = "p_cry_meme_1", + ids = { + "p_cry_meme_1", + "p_cry_meme_two", + "p_cry_meme_three", + }, + }, + { id = "p_cry_empowered" }, + { + id = "p_cry_code_normal_1", + ids = { "p_cry_code_normal_1", "p_cry_code_normal_2", "p_cry_code_jumbo_1", "p_cry_code_mega_1" }, + }, }, banned_other = { { id = "bl_house", type = "blind" }, @@ -427,11 +470,25 @@ local joker_poker = { { id = "j_yorick" }, { id = "j_perkeo" }, { id = "j_constellation" }, + { id = "j_cry_booster" }, + { id = "j_cry_wheelhope" }, + { id = "j_cry_hunger" }, + { id = "j_cry_sacrifice" }, + { id = "j_cry_doodlem" }, + { id = "j_cry_multjoker" }, + { id = "j_cry_stella_mortis" }, + { id = "j_cry_crustulum" }, + { id = "j_cry_cut" }, + { id = "j_cry_CodeJoker" }, + { id = "j_cry_copypaste" }, + { id = "j_cry_blender" }, + { id = "j_cry_python" }, }, banned_other = { { id = "bl_hook", type = "blind" }, { id = "bl_arm", type = "blind" }, { id = "bl_water", type = "blind" }, + { id = "bl_cry_oldmanacle", type = "blind" }, }, }, } @@ -453,82 +510,6 @@ function Game:start_run(args) end --Add banned cards when specific features/mods are enabled here --TODO other mods -if Cryptid.enabled["Blinds"] then - joker_poker.restrictions.banned_other[#joker_poker.restrictions.banned_other + 1] = - { id = "bl_cry_oldmanacle", type = "blind" } -end -if Cryptid.enabled["Tags"] then - onlycard.restrictions.banned_tags[#onlycard.restrictions.banned_tags + 1] = { id = "tag_cry_bundle" } - onlycard.restrictions.banned_tags[#onlycard.restrictions.banned_tags + 1] = { id = "tag_cry_loss" } - onlycard.restrictions.banned_tags[#onlycard.restrictions.banned_tags + 1] = { id = "tag_cry_gambler" } - onlycard.restrictions.banned_tags[#onlycard.restrictions.banned_tags + 1] = { id = "tag_cry_empowered" } - onlycard.restrictions.banned_cards[#onlycard.restrictions.banned_cards + 1] = { id = "p_cry_empowered" } - if Cryptid.enabled["Epic Jokers"] then - rng.restrictions.banned_tags[#rng.restrictions.banned_tags + 1] = { id = "tag_cry_epic" } - end -end -if Cryptid.enabled["Misc."] then - ballin.restrictions.banned_cards[#ballin.restrictions.banned_cards + 1] = { id = "c_cry_eclipse" } - rng.restrictions.banned_cards[#rng.restrictions.banned_cards + 1] = - { id = "p_cry_meme_1", ids = { "p_cry_meme_1", "p_cry_meme_two", "p_cry_meme_three" } } - onlycard.restrictions.banned_cards[#onlycard.restrictions.banned_cards + 1] = - { id = "p_cry_meme_1", ids = { "p_cry_meme_1", "p_cry_meme_two", "p_cry_meme_three" } } -end -if Cryptid.enabled["Misc. Jokers"] then - rush_hour_ii.restrictions.banned_cards[#rush_hour_ii.restrictions.banned_cards + 1] = { id = "j_cry_pickle" } - rush_hour_iii.restrictions.banned_cards[#rush_hour_iii.restrictions.banned_cards + 1] = { id = "j_cry_pickle" } - boss_rush.restrictions.banned_cards[#boss_rush.restrictions.banned_cards + 1] = { id = "j_cry_pickle" } - joker_poker.restrictions.banned_cards[#joker_poker.restrictions.banned_cards + 1] = { id = "j_cry_booster" } - joker_poker.restrictions.banned_cards[#joker_poker.restrictions.banned_cards + 1] = { id = "j_cry_wheelhope" } - joker_poker.restrictions.banned_cards[#joker_poker.restrictions.banned_cards + 1] = { id = "j_cry_hunger" } -end -if Cryptid.enabled["M Jokers"] then - joker_poker.restrictions.banned_cards[#joker_poker.restrictions.banned_cards + 1] = { id = "j_cry_sacrifice" } - if Cryptid.enabled["Epic Jokers"] then - joker_poker.restrictions.banned_cards[#joker_poker.restrictions.banned_cards + 1] = { id = "j_cry_doodlem" } - end -end -if Cryptid.enabled["Epic Jokers"] then - onlycard.restrictions.banned_cards[#onlycard.restrictions.banned_cards + 1] = { id = "j_cry_multjoker" } - joker_poker.restrictions.banned_cards[#joker_poker.restrictions.banned_cards + 1] = { id = "j_cry_multjoker" } -end -if Cryptid.enabled["Exotic Jokers"] then - rng.restrictions.banned_cards[#rng.restrictions.banned_cards + 1] = { id = "j_cry_equilib" } - joker_poker.restrictions.banned_cards[#joker_poker.restrictions.banned_cards + 1] = { id = "j_cry_stella_mortis" } - joker_poker.restrictions.banned_cards[#joker_poker.restrictions.banned_cards + 1] = { id = "j_cry_crustulum" } -end -if Cryptid.enabled["Code Cards"] then - ballin.restrictions.banned_cards[#ballin.restrictions.banned_cards + 1] = { id = "c_cry_class" } - rng.restrictions.banned_cards[#rng.restrictions.banned_cards + 1] = { id = "c_cry_delete" } - onlycard.restrictions.banned_tags[#onlycard.restrictions.banned_tags + 1] = { id = "tag_cry_console" } - onlycard.restrictions.banned_cards[#onlycard.restrictions.banned_cards + 1] = { - id = "p_cry_code_normal_1", - ids = { "p_cry_code_normal_1", "p_cry_code_normal_2", "p_cry_code_jumbo_1", "p_cry_code_mega_1" }, - } - joker_poker.restrictions.banned_cards[#joker_poker.restrictions.banned_cards + 1] = { id = "j_cry_cut" } - joker_poker.restrictions.banned_cards[#joker_poker.restrictions.banned_cards + 1] = { id = "j_cry_CodeJoker" } - joker_poker.restrictions.banned_cards[#joker_poker.restrictions.banned_cards + 1] = { id = "j_cry_copypaste" } - joker_poker.restrictions.banned_cards[#joker_poker.restrictions.banned_cards + 1] = { id = "j_cry_blender" } - joker_poker.restrictions.banned_cards[#joker_poker.restrictions.banned_cards + 1] = { id = "j_cry_python" } -end -if Cryptid.enabled["Spectrals"] then - sticker_sheet.restrictions.banned_cards[#sticker_sheet.restrictions.banned_cards + 1] = { id = "c_cry_lock" } - sticker_sheet_plus.restrictions.banned_cards[#sticker_sheet_plus.restrictions.banned_cards + 1] = - { id = "c_cry_lock" } - onlycard.restrictions.banned_cards[#onlycard.restrictions.banned_cards + 1] = { id = "c_cry_replica" } -end -if Cryptid.enabled["Vouchers"] then - rush_hour_ii.restrictions.banned_cards[#rush_hour_ii.restrictions.banned_cards + 1] = { id = "v_cry_copies" } - rush_hour_iii.restrictions.banned_cards[#rush_hour_iii.restrictions.banned_cards + 1] = { id = "v_cry_copies" } - boss_rush.restrictions.banned_cards[#boss_rush.restrictions.banned_cards + 1] = { id = "v_cry_copies" } - rush_hour_ii.restrictions.banned_cards[#rush_hour_ii.restrictions.banned_cards + 1] = { id = "v_cry_tag_printer" } - rush_hour_iii.restrictions.banned_cards[#rush_hour_iii.restrictions.banned_cards + 1] = { id = "v_cry_tag_printer" } - boss_rush.restrictions.banned_cards[#boss_rush.restrictions.banned_cards + 1] = { id = "v_cry_tag_printer" } - rush_hour_ii.restrictions.banned_cards[#rush_hour_ii.restrictions.banned_cards + 1] = { id = "v_cry_clone_machine" } - rush_hour_iii.restrictions.banned_cards[#rush_hour_iii.restrictions.banned_cards + 1] = - { id = "v_cry_clone_machine" } - boss_rush.restrictions.banned_cards[#boss_rush.restrictions.banned_cards + 1] = { id = "v_cry_clone_machine" } -end if (SMODS.Mods["jen"] or {}).can_load then ballin.restrictions.banned_cards[#ballin.restrictions.banned_cards + 1] = { id = "c_jen_chance" } ballin.restrictions.banned_cards[#ballin.restrictions.banned_cards + 1] = { id = "c_jen_token_tag_cry_bundle" } @@ -581,21 +562,19 @@ if (SMODS.Mods["jen"] or {}).can_load then onlycard.restrictions.banned_cards[#onlycard.restrictions.banned_cards + 1] = { id = "c_jen_cryptid_ex" } end --end of banned cards -local challenges = { sticker_sheet, sticker_sheet_plus, onlycard } -if Cryptid.enabled["Misc. Jokers"] then - challenges[#challenges + 1] = ballin - challenges[#challenges + 1] = boss_rush - challenges[#challenges + 1] = rng - challenges[#challenges + 1] = dagger_war -end -if Cryptid.enabled["Blinds"] and Cryptid.enabled["Timer Mechanics"] then - challenges[#challenges + 1] = rush_hour - challenges[#challenges + 1] = rush_hour_ii - challenges[#challenges + 1] = rush_hour_iii -end -if Cryptid.enabled["Misc. Decks"] then --yoinking vfd code here - challenges[#challenges + 1] = joker_poker -end +local challenges = { + sticker_sheet, + sticker_sheet_plus, + onlycard, + ballin, + boss_rush, + rng, + dagger_war, + rush_hour, + rush_hour_ii, + rush_hour_iii, + joker_poker, +} for k, v in pairs(G.P_CENTERS) do if v.set == "Joker" then diff --git a/Cryptid/items/code.lua b/Cryptid/items/code.lua index e4c5235..b9606d1 100644 --- a/Cryptid/items/code.lua +++ b/Cryptid/items/code.lua @@ -1,14 +1,5 @@ --note to self: refer to https://docs.google.com/document/d/1LNaIouU3vrtWIuPBdFCqLyjYAjVtq7t64xjHnckEY50/edit for order of remaining consumables local code = { - --[[ - I'm assuming this won't work so it's commented out for now - Jevonn - dependencies = { - items = { - "set_cry_code", - }, - }, - ]] - -- object_type = "ConsumableType", key = "Code", primary_colour = HEX("14b341"), @@ -20,7 +11,28 @@ local code = { can_stack = true, can_divide = true, } +local code_digital_hallucinations_compat = { + colour = HEX("14b341"), + loc_key = "cry_plus_code", + create = function() + local ccard = create_card("Code", G.consumeables, nil, nil, nil, nil, nil, "diha") + ccard:set_edition({ negative = true }, true) + ccard:add_to_deck() + G.consumeables:emplace(ccard) + end, +} local pack1 = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "Math", + }, + }, dependencies = { items = { "set_cry_code", @@ -51,8 +63,20 @@ local pack1 = { } end, group_key = "k_cry_program_pack", + cry_digital_hallucinations = code_digital_hallucinations_compat, } local pack2 = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "Math", + }, + }, dependencies = { items = { "set_cry_code", @@ -83,8 +107,20 @@ local pack2 = { } end, group_key = "k_cry_program_pack", + cry_digital_hallucinations = code_digital_hallucinations_compat, } local packJ = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "Math", + }, + }, dependencies = { items = { "set_cry_code", @@ -115,8 +151,20 @@ local packJ = { } end, group_key = "k_cry_program_pack", + cry_digital_hallucinations = code_digital_hallucinations_compat, } local packM = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "Math", + }, + }, dependencies = { items = { "set_cry_code", @@ -147,8 +195,20 @@ local packM = { } end, group_key = "k_cry_program_pack", + cry_digital_hallucinations = code_digital_hallucinations_compat, } local console = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "Math", + }, + }, dependencies = { items = { "p_cry_code_normal_1", @@ -185,7 +245,7 @@ local console = { if G.GAME.modifiers.cry_force_edition and not G.GAME.modifiers.cry_force_random_edition then card:set_edition(nil, true, true) elseif G.GAME.modifiers.cry_force_random_edition then - local edition = cry_poll_random_edition() + local edition = Cryptid.poll_random_edition() card:set_edition(edition, true, true) end card:start_materialize() @@ -197,6 +257,17 @@ local console = { end, } local crash = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "Math", + }, + }, dependencies = { items = { "set_cry_code", @@ -764,6 +835,17 @@ local crash = { end, } local payload = { + cry_credits = { + idea = { + "Mjiojio", + }, + art = { + "HexaCryonic", + }, + code = { + "Math", + }, + }, dependencies = { items = { "set_cry_code", @@ -793,6 +875,17 @@ local payload = { end, } local reboot = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "Math", + }, + }, dependencies = { items = { "set_cry_code", @@ -835,6 +928,17 @@ local reboot = { end, } local revert = { + cry_credits = { + idea = { + "Mjiojio", + }, + art = { + "HexaCryonic", + }, + code = { + "Math", + }, + }, dependencies = { items = { "set_cry_code", @@ -882,6 +986,17 @@ local revert = { end, } local semicolon = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "Math", + }, + }, dependencies = { items = { "set_cry_code", @@ -943,6 +1058,17 @@ local semicolon = { end, } local malware = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "HexaCryonic", + }, + }, dependencies = { items = { "set_cry_code", @@ -1007,6 +1133,17 @@ local malware = { end, } local seed = { + cry_credits = { + idea = { + "Mjiojio", + }, + art = { + "HexaCryonic", + }, + code = { + "Math", + }, + }, dependencies = { items = { "set_cry_code", @@ -1051,7 +1188,7 @@ local seed = { if G.consumeables.highlighted[1] then G.consumeables.highlighted[1].ability.cry_rigged = true end - if safe_get(G, "pack_cards", "highlighted", 1) then + if Cryptid.safe_get(G, "pack_cards", "highlighted", 1) then G.pack_cards.highlighted[1].ability.cry_rigged = true end end, @@ -1070,6 +1207,10 @@ local rigged = { prefix_config = { key = false }, badge_colour = HEX("14b341"), draw = function(self, card) --don't draw shine + local notilt = nil + if card.area and card.area.config.type == "deck" then + notilt = true + end if not G.shared_stickers["cry_rigged2"] then G.shared_stickers["cry_rigged2"] = Sprite(0, 0, G.CARD_W, G.CARD_H, G.ASSET_ATLAS["cry_sticker"], { x = 5, y = 1 }) @@ -1078,21 +1219,32 @@ local rigged = { G.shared_stickers[self.key].role.draw_major = card G.shared_stickers["cry_rigged2"].role.draw_major = card - G.shared_stickers[self.key]:draw_shader("dissolve", nil, nil, nil, card.children.center) + G.shared_stickers[self.key]:draw_shader("dissolve", nil, nil, notilt, card.children.center) card.hover_tilt = card.hover_tilt / 2 -- call it spaghetti, but it's what hologram does so... - G.shared_stickers["cry_rigged2"]:draw_shader("dissolve", nil, nil, nil, card.children.center) + G.shared_stickers["cry_rigged2"]:draw_shader("dissolve", nil, nil, notilt, card.children.center) G.shared_stickers["cry_rigged2"]:draw_shader( "hologram", nil, card.ARGS.send_to_shader, - nil, + notilt, card.children.center ) -- this doesn't really do much tbh, but the slight effect is nice card.hover_tilt = card.hover_tilt * 2 end, } local hook = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "Math", + }, + }, dependencies = { items = { "set_cry_code", @@ -1189,7 +1341,7 @@ local hooked = { var = localize({ type = "name_text", set = "Joker", key = G.jokers.cards[i].config.center.key }) end end - var = var or "[no joker found - " .. (card.hook_id or "nil") .. "]" + var = var or ("[no joker found - " .. (card.hook_id or "nil") .. "]") end return { vars = { var or "hooked Joker" } } end, @@ -1203,6 +1355,17 @@ local hooked = { end, } local variable = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "AlexZGreat", + }, + }, dependencies = { items = { "set_cry_code", @@ -1221,7 +1384,7 @@ local variable = { order = 8, config = { max_highlighted = 2, extra = { enteredrank = "" } }, loc_vars = function(self, info_queue, card) - return { vars = { safe_get(card, "ability", "max_highlighted") or self.config.max_highlighted } } + return { vars = { Cryptid.safe_get(card, "ability", "max_highlighted") or self.config.max_highlighted } } end, use = function(self, card, area, copier) G.GAME.USING_CODE = true @@ -1491,6 +1654,17 @@ local variable = { end, } local class = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "Math", + }, + }, dependencies = { items = { "set_cry_code", @@ -1509,7 +1683,7 @@ local class = { order = 16, config = { max_highlighted = 1, extra = { enteredrank = "" } }, loc_vars = function(self, info_queue, card) - return { vars = { safe_get(card, "ability", "max_highlighted") or self.config.max_highlighted } } + return { vars = { Cryptid.safe_get(card, "ability", "max_highlighted") or self.config.max_highlighted } } end, use = function(self, card, area, copier) G.GAME.USING_CODE = true @@ -1667,7 +1841,7 @@ local class = { delay = 0.15, func = function() CARD:flip() - CARD:set_ability(get_random_consumable("cry_class"), true, nil) + CARD:set_ability(Cryptid.random_consumable("cry_class"), true, nil) play_sound("tarot2", percent) CARD:juice_up(0.3, 0.3) return true @@ -1765,6 +1939,17 @@ local class = { end, } local commit = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "Math", + }, + }, dependencies = { items = { "set_cry_code", @@ -1832,6 +2017,17 @@ local commit = { end, } local merge = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "Math", + }, + }, dependencies = { items = { "set_cry_code", @@ -1932,6 +2128,17 @@ local merge = { end, } local multiply = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "Math", + }, + }, dependencies = { items = { "set_cry_code", @@ -1958,8 +2165,8 @@ local multiply = { G.jokers.highlighted[1].config.cry_multiply = 1 end G.jokers.highlighted[1].config.cry_multiply = G.jokers.highlighted[1].config.cry_multiply * 2 - cry_with_deck_effects(G.jokers.highlighted[1], function(card) - cry_misprintize(card, { min = 2, max = 2 }, nil, true) + Cryptid.with_deck_effects(G.jokers.highlighted[1], function(card) + Cryptid.misprintize(card, { min = 2, max = 2 }, nil, true) end) end, init = function(self) @@ -1970,8 +2177,8 @@ local multiply = { for i = 1, #G.jokers.cards do if G.jokers.cards[i].config.cry_multiply then m = G.jokers.cards[i].config.cry_multiply - cry_with_deck_effects(G.jokers.cards[i], function(card) - cry_misprintize(card, { min = 1 / m, max = 1 / m }, nil, true) + Cryptid.with_deck_effects(G.jokers.cards[i], function(card) + Cryptid.misprintize(card, { min = 1 / m, max = 1 / m }, nil, true) end) G.jokers.cards[i].config.cry_multiply = nil end @@ -1980,6 +2187,17 @@ local multiply = { end, } local divide = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "Math", + }, + }, dependencies = { items = { "set_cry_code", @@ -2036,6 +2254,18 @@ local divide = { end, } local delete = { + cry_credits = { + idea = { + "Mjiojio", + }, + art = { + "HexaCryonic", + }, + code = { + "Math", + "Toneblock", + }, + }, dependencies = { items = { "set_cry_code", @@ -2054,7 +2284,7 @@ local delete = { cost = 4, config = { cry_multiuse = 3 }, loc_vars = function(self, info_queue, card) - return { vars = { safe_get(card, "ability", "cry_multiuse") or self.config.cry_multiuse } } + return { vars = { Cryptid.safe_get(card, "ability", "cry_multiuse") or self.config.cry_multiuse } } end, can_use = function(self, card) return G.STATE == G.STATES.SHOP @@ -2087,7 +2317,7 @@ local delete = { a = G.shop_vouchers c = G.shop_vouchers.highlighted[1] if c.shop_voucher then - G.GAME.current_round.voucher = nil + G.GAME.current_round.voucher.spawn[c.config.center.key] = nil G.GAME.current_round.cry_voucher_edition = nil G.GAME.current_round.cry_voucher_stickers = { eternal = false, perishable = false, rental = false, pinned = false, banana = false } @@ -2156,6 +2386,17 @@ local delete = { ]] } local spaghetti = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "Math", + }, + }, dependencies = { items = { "set_cry_code", @@ -2189,6 +2430,17 @@ local spaghetti = { end, } local machinecode = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "Math", + }, + }, dependencies = { items = { "set_cry_code", @@ -2209,24 +2461,24 @@ local machinecode = { loc_vars = function(self, info_queue, center) return { main_start = { - randomchar(codechars6), - randomchar(codechars6), - randomchar(codechars6), - randomchar(codechars6), - randomchar(codechars6), - randomchar(codechars6), + Cryptid.randomchar(codechars6), + Cryptid.randomchar(codechars6), + Cryptid.randomchar(codechars6), + Cryptid.randomchar(codechars6), + Cryptid.randomchar(codechars6), + Cryptid.randomchar(codechars6), }, } end, use = function(self, card, area, copier) local card = create_card( "Consumeables", - G.consumables, + G.consumeables, nil, nil, nil, nil, - get_random_consumable("cry_machinecode", nil, "c_cry_machinecode").key, + Cryptid.random_consumable("cry_machinecode", nil, "c_cry_machinecode").key, c_cry_machinecode ) card:set_edition({ cry_glitched = true }) @@ -2237,11 +2489,11 @@ local machinecode = { local a = {} local b for i = 1, number do - b = get_random_consumable("cry_machinecode", nil, "c_cry_machinecode") + b = Cryptid.random_consumable("cry_machinecode", nil, "c_cry_machinecode") a[b] = (a[b] or 0) + 1 end for k, v in pairs(a) do - local card = create_card("Consumeables", G.consumables, nil, nil, nil, nil, k.key) + local card = create_card("Consumeables", G.consumeables, nil, nil, nil, nil, k.key) card:set_edition({ cry_glitched = true }) card:add_to_deck() if Incantation then @@ -2428,7 +2680,7 @@ local machinecode = { codechars8 = { "M", "W", "m", "w", "¤", "¶", "Ø", "ø", "Ł" } codechars9 = { "&", "@", "©", "«", "®", "»" } codechars10 = { "Æ", "æ", "Œ", "œ" } - function randomchar(arr) + function Cryptid.randomchar(arr) return { n = G.UIT.O, config = { @@ -2448,6 +2700,17 @@ local machinecode = { end, } local run = { + cry_credits = { + idea = { + "Mjiojio", + }, + art = { + "HexaCryonic", + }, + code = { + "Math", + }, + }, dependencies = { items = { "set_cry_code", @@ -2462,7 +2725,7 @@ local run = { atlas = "code", order = 6, can_use = function(self, card) - return safe_get(G.GAME, "blind", "in_blind") + return Cryptid.safe_get(G.GAME, "blind", "in_blind") end, can_bulk_use = true, use = function(self, card, area, copier) @@ -2549,6 +2812,17 @@ local run = { end, } local exploit = { + cry_credits = { + idea = { + "Mjiojio", + }, + art = { + "HexaCryonic", + }, + code = { + "Toneblock", + }, + }, dependencies = { items = { "set_cry_code", @@ -2567,7 +2841,7 @@ local exploit = { order = 28, config = { cry_multiuse = 2, extra = { enteredhand = "" } }, -- i don't think this ever uses config...? loc_vars = function(self, info_queue, card) - return { vars = { safe_get(card, "ability", "cry_multiuse") or self.config.cry_multiuse } } + return { vars = { Cryptid.safe_get(card, "ability", "cry_multiuse") or self.config.cry_multiuse } } end, can_use = function(self, card) return true @@ -2754,6 +3028,17 @@ local exploit = { end, } local oboe = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "Math", + }, + }, dependencies = { items = { "set_cry_code", @@ -2774,9 +3059,9 @@ local oboe = { can_bulk_use = true, loc_vars = function(self, info_queue, card) if not card then - return { vars = { self.config.extra.choices, (safe_get(G.GAME, "cry_oboe") or 0) } } + return { vars = { self.config.extra.choices, (Cryptid.safe_get(G.GAME, "cry_oboe") or 0) } } end - return { vars = { card.ability.extra.choices, (safe_get(G.GAME, "cry_oboe") or 0) } } + return { vars = { card.ability.extra.choices, (Cryptid.safe_get(G.GAME, "cry_oboe") or 0) } } end, can_use = function(self, card) return true @@ -2789,6 +3074,17 @@ local oboe = { end, } local rework = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "Math", + }, + }, dependencies = { items = { "set_cry_code", @@ -2808,7 +3104,7 @@ local rework = { cost = 4, loc_vars = function(self, info_queue) info_queue[#info_queue + 1] = - { set = "Tag", key = "tag_cry_rework", specific_vars = { "[edition]", "[joker]" } } + { set = "Tag", key = "tag_cry_rework", specific_vars = { "[edition]", "[joker]", "n" } } return { vars = {} } end, can_use = function(self, card) @@ -2857,6 +3153,17 @@ local rework = { end, } local rework_tag = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "Math", + }, + }, dependencies = { items = { "c_cry_rework", @@ -2882,13 +3189,13 @@ local rework_tag = { end return r end - local ed = safe_get(tag, "ability", "rework_edition") + local ed = Cryptid.safe_get(tag, "ability", "rework_edition") and localize({ type = "name_text", set = "Edition", key = tag.ability.rework_edition }) or "[" .. string.lower(localize("k_edition")) .. "]" return { vars = { ed, - safe_get(tag, "ability", "rework_key") + Cryptid.safe_get(tag, "ability", "rework_key") and localize({ type = "name_text", set = "Joker", key = tag.ability.rework_key }) or "[" .. string.lower(localize("k_joker")) .. "]", string.sub(ed, 1, 1) ~= "[" and p(ed) or "n", @@ -2999,10 +3306,8 @@ local patch = { CARD:set_eternal(nil) end CARD.ability.banana = nil - if Cryptid.enabled["Spooky"] then - CARD.ability.cry_possessed = nil - SMODS.Stickers.cry_flickering:apply(CARD, nil) - end + CARD.ability.cry_possessed = nil + SMODS.Stickers.cry_flickering:apply(CARD, nil) play_sound("tarot2", percent) CARD:juice_up(0.3, 0.3) return true @@ -3025,11 +3330,9 @@ local patch = { if not CARD.sob then CARD:set_eternal(nil) end - CARD.ability.banana = nil - if Cryptid.enabled["Spooky"] then - CARD.ability.cry_possessed = nil - SMODS.Stickers.cry_flickering:apply(CARD, nil) - end + CARD.ability.banana = notify_alert + CARD.ability.cry_possessed = nil + SMODS.Stickers.cry_flickering:apply(CARD, nil) play_sound("card1", percent) CARD:juice_up(0.3, 0.3) return true @@ -3053,10 +3356,8 @@ local patch = { CARD:set_eternal(nil) end CARD.ability.banana = nil - if Cryptid.enabled["Spooky"] then - CARD.ability.cry_possessed = nil - SMODS.Stickers.cry_flickering:apply(CARD, nil) - end + CARD.ability.cry_possessed = nil + SMODS.Stickers.cry_flickering:apply(CARD, nil) play_sound("card1", percent) CARD:juice_up(0.3, 0.3) return true @@ -3066,6 +3367,17 @@ local patch = { end, } local ctrl_v = { + cry_credits = { + idea = { + "ItsFlowwey", + }, + art = { + "HexaCryonic", + }, + code = { + "Foegro", + }, + }, dependencies = { items = { "set_cry_code", @@ -3101,6 +3413,7 @@ local ctrl_v = { card:add_to_deck() table.insert(G.playing_cards, card) G.hand:emplace(card) + playing_card_joker_effects({ card }) return true end, })) @@ -3157,6 +3470,17 @@ local ctrl_v = { end, } local inst = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "Foegro", + }, + }, dependencies = { items = { "set_cry_code", @@ -3223,6 +3547,17 @@ local inst = { end, } local alttab = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "Toneblock", + }, + }, dependencies = { items = { "set_cry_code", @@ -3243,7 +3578,7 @@ local alttab = { can_bulk_use = true, loc_vars = function(self, info_queue, card) local ret = localize("k_none") - if safe_get(G.GAME, "blind", "in_blind") then + if Cryptid.safe_get(G.GAME, "blind", "in_blind") then if G.GAME.blind:get_type() == "Small" then ret = localize({ type = "name_text", key = G.GAME.round_resets.blind_tags.Small, set = "Tag" }) elseif G.GAME.blind:get_type() == "Big" then @@ -3255,7 +3590,7 @@ local alttab = { return { vars = { ret } } end, can_use = function(self, card) - return safe_get(G.GAME, "blind", "in_blind") + return Cryptid.safe_get(G.GAME, "blind", "in_blind") end, use = function(self, card, area, copier) local used_consumable = copier or card @@ -3306,6 +3641,17 @@ local alttab = { end, } local automaton = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "Math", + }, + }, dependencies = { items = { "set_cry_code", @@ -3320,7 +3666,7 @@ local automaton = { order = 5, atlas = "code", loc_vars = function(self, info_queue, card) - return { vars = { safe_get(card, "ability", "create") or self.config.create } } + return { vars = { Cryptid.safe_get(card, "ability", "create") or self.config.create } } end, can_use = function(self, card) return #G.consumeables.cards < G.consumeables.config.card_limit or card.area == G.consumeables @@ -3385,6 +3731,17 @@ local green_seal = { end, } local source = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "Math", + }, + }, dependencies = { items = { "cry_green", @@ -3442,6 +3799,17 @@ local source = { end, } local pointer = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "Math", + }, + }, dependencies = { items = { "set_cry_code", @@ -4291,6 +4659,17 @@ local pointer = { end, } local encoded = { + cry_credits = { + idea = { + "I forgot", + }, + art = { + "Kailen", + }, + code = { + "Kailen", + }, + }, dependencies = { items = { "set_cry_code", @@ -4348,16 +4727,22 @@ local CodeJoker = { pos = { x = 2, y = 4 }, loc_vars = function(self, info_queue, center) info_queue[#info_queue + 1] = { key = "e_negative_consumable", set = "Edition", config = { extra = 1 } } + return { key = Cryptid.gameset_loc(self, { exp_modest = "modest" }) } end, + extra_gamesets = { "exp_modest" }, rarity = "cry_epic", cost = 11, order = 109, blueprint_compat = true, atlas = "atlasepic", calculate = function(self, card, context) - if context.setting_blind and not (context.blueprint_card or self).getting_sliced then + if + context.setting_blind + and not (context.blueprint_card or self).getting_sliced + and (G.GAME.blind:get_type() == "Boss" or Cryptid.gameset(card) ~= "exp_modest") + then play_sound("timpani") - local card = create_card("Code", G.consumables, nil, nil, nil, nil) + local card = create_card("Code", G.consumeables, nil, nil, nil, nil) card:set_edition({ negative = true, }) @@ -4385,7 +4770,7 @@ local CodeJoker = { local count2 = 0 for k, v in pairs(G.P_CENTER_POOLS["Code"]) do count2 = count2 + 1 - if safe_get(v, "discovered") == true then + if Cryptid.safe_get(v, "discovered") == true then count = count + 1 end end @@ -4428,16 +4813,41 @@ local copypaste = { ) or 1, card and card.ability.extra.odds or 2, }, -- this effectively prevents a copypaste from ever initially misprinting at above 50% odds. still allows rigging/oops - key = Card.get_gameset(card) ~= "madness" and "j_cry_copypaste" or "j_cry_copypaste2", + key = Cryptid.gameset_loc(self, { madness = "madness", exp_modest = "modest" }), } end, atlas = "atlasepic", + extra_gamesets = { "exp_modest" }, + gameset_config = { + exp_modest = { cost = 8, center = { rarity = 3 } }, + }, calculate = function(self, card, context) + if context.pull_card and context.card.ability.set == "Code" and Cryptid.gameset(card) == "exp_modest" then + if #G.consumeables.cards + G.GAME.consumeable_buffer < G.consumeables.config.card_limit then + G.E_MANAGER:add_event(Event({ + func = function() + local cards = copy_card(context.card) + cards:add_to_deck() + G.consumeables:emplace(cards) + return true + end, + })) + card_eval_status_text( + context.blueprint_card or card, + "extra", + nil, + nil, + nil, + { message = localize("k_copied_ex") } + ) + end + end if context.using_consumeable and context.consumeable.ability.set == "Code" and not context.consumeable.beginning_end and not card.ability.extra.ckt + and Cryptid.gameset(card) ~= "exp_modest" then if #G.consumeables.cards + G.GAME.consumeable_buffer < G.consumeables.config.card_limit then if @@ -4603,7 +5013,7 @@ local blender = { and not context.consumeable.beginning_end then if #G.consumeables.cards + G.GAME.consumeable_buffer < G.consumeables.config.card_limit then - local card = create_card("Consumeables", G.consumables, nil, nil, nil, nil, nil, "cry_blender") + local card = create_card("Consumeables", G.consumeables, nil, nil, nil, nil, nil, "cry_blender") card:add_to_deck() G.consumeables:emplace(card) end @@ -4811,7 +5221,11 @@ return { end --Code from Betmma's Vouchers G.FUNCS.can_reserve_card = function(e) - if #G.consumeables.cards < G.consumeables.config.card_limit then + 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 @@ -4837,6 +5251,7 @@ return { 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) diff --git a/Cryptid/items/deck.lua b/Cryptid/items/deck.lua index d83b951..7b9aaea 100644 --- a/Cryptid/items/deck.lua +++ b/Cryptid/items/deck.lua @@ -16,6 +16,13 @@ local very_fair = { end, init = function(self) very_fair_quip = {} + local avts = SMODS.add_voucher_to_shop + function SMODS.add_voucher_to_shop(...) + if G.GAME.modifiers.cry_no_vouchers then + return + end + return avts(...) + end end, } local equilibrium = { @@ -43,13 +50,13 @@ local equilibrium = { local valid_pools = { "Joker", "Consumeables", "Voucher", "Booster" } for _, id in ipairs(valid_pools) do for k, v in pairs(G.P_CENTER_POOLS[id]) do - if not center_no(v, "doe", k) then + if not Cryptid.no(v, "doe", k) then P_CRY_ITEMS[#P_CRY_ITEMS + 1] = v.key end end end for k, v in pairs(G.P_CARDS) do - if not center_no(v, "doe", k) then + if not Cryptid.no(v, "doe", k) then P_CRY_ITEMS[#P_CRY_ITEMS + 1] = v.key end end @@ -213,6 +220,7 @@ local redeemed = { else area = G.play end + if not G.cry_redeemed_buffer then G.cry_redeemed_buffer = {} end if not G.cry_redeemed_buffer[v.key] and v.unlocked then local card = create_card("Voucher", area, nil, nil, nil, nil, v.key) G.cry_redeemed_buffer[v.key] = true @@ -253,8 +261,8 @@ local legendary = { pos = { x = 0, y = 6 }, atlas = "atlasdeck", order = 15, - trigger_effect = function(self, args) - if args.context == "eval" and safe_get(G.GAME, "last_blind", "boss") then + calculate = function(self, back, context) + if context.context == "eval" and Cryptid.safe_get(G.GAME, "last_blind", "boss") then if G.jokers then if #G.jokers.cards < G.jokers.config.card_limit then local legendary_poll = pseudorandom(pseudoseed("cry_legendary")) @@ -383,12 +391,12 @@ local glowing = { return { vars = { " " } } end, atlas = "glowing", - trigger_effect = function(self, args) - if args.context == "eval" and safe_get(G.GAME, "last_blind", "boss") then + calculate = function(self, back, context) + if context.context == "eval" and Cryptid.safe_get(G.GAME, "last_blind", "boss") then for i = 1, #G.jokers.cards do if not Card.no(G.jokers.cards[i], "immutable", true) then - cry_with_deck_effects(G.jokers.cards[i], function(card) - cry_misprintize(card, { min = 1.25, max = 1.25 }, nil, true) + Cryptid.with_deck_effects(G.jokers.cards[i], function(card) + Cryptid.misprintize(card, { min = 1.25, max = 1.25 }, nil, true) end) end end @@ -465,6 +473,9 @@ local antimatter = { "set_cry_deck", }, }, + loc_vars = function(self, info_queue, center) + return { key = Cryptid.gameset_loc(self, { mainline = "balanced", modest = "balanced" }) } + end, name = "cry-Antimatter", order = 76, key = "antimatter", @@ -479,44 +490,53 @@ local antimatter = { cry_forced_draw_amount = 5, }, pos = { x = 2, y = 0 }, - trigger_effect = function(self, args) - if args.context ~= "final_scoring_step" then - antimatter_trigger_effect(self, args) + calculate = function(self, back, context) + if context.context ~= "final_scoring_step" then + Cryptid.antimatter_trigger(self, context) else - return antimatter_trigger_effect_final_scoring_step(self, args) + return Cryptid.antimatter_trigger_final_scoring(self, context) end end, apply = function(self) - antimatter_apply() + Cryptid.antimatter_apply() end, atlas = "atlasdeck", init = function(self) - function antimatter_apply() - local bluecheck = safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_blue", "wins", 8) - local yellowcheck = safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_yellow", "wins", 8) - local abandonedcheck = safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_abandoned", "wins", 8) - local ghostcheck = safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_ghost", "wins", 8) - local redcheck = safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_red", "wins", 8) - local checkeredcheck = safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_checkered", "wins", 8) - local erraticcheck = safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_erratic", "wins", 8) - local blackcheck = safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_black", "wins", 8) - local paintedcheck = safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_painted", "wins", 8) - local greencheck = safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_green", "wins", 8) - local spookycheck = safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_spooky", "wins", 8) + function Cryptid.antimatter_apply() + local bluecheck = Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_blue", "wins", 8) + local yellowcheck = Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_yellow", "wins", 8) + local abandonedcheck = + Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_abandoned", "wins", 8) + local ghostcheck = Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_ghost", "wins", 8) + local redcheck = Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_red", "wins", 8) + local checkeredcheck = + Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_checkered", "wins", 8) + local erraticcheck = Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_erratic", "wins", 8) + local blackcheck = Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_black", "wins", 8) + local paintedcheck = Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_painted", "wins", 8) + local greencheck = Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_green", "wins", 8) + local spookycheck = + Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_spooky", "wins", 8) local equilibriumcheck = - safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_equilibrium", "wins", 8) - local misprintcheck = safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_misprint", "wins", 8) - local infinitecheck = safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_infinite", "wins", 8) - local wormholecheck = safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_wormhole", "wins", 8) - local redeemedcheck = safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_redeemed", "wins", 8) - local legendarycheck = safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_legendary", "wins", 8) - local encodedcheck = safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_encoded", "wins", 8) - local world = safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_world_deck", "wins", 8) - local sun = safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_sun_deck", "wins", 8) - local star = safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_star_deck", "wins", 8) - local moon = safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_moon_deck", "wins", 8) + Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_equilibrium", "wins", 8) + local misprintcheck = + Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_misprint", "wins", 8) + local infinitecheck = + Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_infinite", "wins", 8) + local wormholecheck = + Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_wormhole", "wins", 8) + local redeemedcheck = + Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_redeemed", "wins", 8) + local legendarycheck = + Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_legendary", "wins", 8) + local encodedcheck = + Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_encoded", "wins", 8) + local world = Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_world_deck", "wins", 8) + local sun = Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_sun_deck", "wins", 8) + local star = Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_star_deck", "wins", 8) + local moon = Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_moon_deck", "wins", 8) - if cry_get_gameset(G.P_CENTERS.b_cry_antimatter) == "madness" then + if Cryptid.gameset(G.P_CENTERS.b_cry_antimatter) == "madness" then bluecheck = 1 yellowcheck = 1 abandonedcheck = 1 @@ -545,8 +565,8 @@ local antimatter = { if (bluecheck or 0) ~= 0 then G.GAME.starting_params.hands = G.GAME.starting_params.hands + 1 end - --All Consumables (see get_antimatter_consumables) - local querty = get_antimatter_consumables() + --All Consumables (see Cryptid.get_antimatter_consumables) + local querty = Cryptid.get_antimatter_consumables() if #querty > 0 then delay(0.4) G.E_MANAGER:add_event(Event({ @@ -578,15 +598,19 @@ local antimatter = { if (redcheck or 0) ~= 0 then G.GAME.starting_params.discards = G.GAME.starting_params.discards + 1 end - -- All Decks with Vouchers (see get_antimatter_vouchers) - local vouchers = get_antimatter_vouchers() + -- All Decks with Vouchers (see Cryptid.get_antimatter_vouchers) + local vouchers = Cryptid.get_antimatter_vouchers() if #vouchers > 0 then for k, v in pairs(vouchers) do if G.P_CENTERS[v] then G.GAME.used_vouchers[v] = true - G.GAME.cry_owned_vouchers[v] = true G.GAME.starting_voucher_count = (G.GAME.starting_voucher_count or 0) + 1 - Card.apply_to_run(nil, G.P_CENTERS[v]) + G.E_MANAGER:add_event(Event({ + func = function() + Card.apply_to_run(nil, G.P_CENTERS[v]) + return true + end, + })) end end end @@ -659,24 +683,21 @@ local antimatter = { -- Wormhole deck if (wormholecheck or 0) ~= 0 then G.GAME.modifiers.cry_negative_rate = 20 - --[[ - Needs to check if exotic Jokers exist are enabled (whenever that happens) - - G.E_MANAGER:add_event(Event({ - func = function() - if G.jokers then - local card = create_card("Joker", G.jokers, nil, "cry_exotic", nil, nil, nil, "cry_wormhole") - card:add_to_deck() - card:start_materialize() - G.jokers:emplace(card) - return true - end - end, - })) - - ]] - -- + if Cryptid.enabled("set_cry_exotic") == true then + G.E_MANAGER:add_event(Event({ + func = function() + if G.jokers then + local card = + create_card("Joker", G.jokers, nil, "cry_exotic", nil, nil, nil, "cry_wormhole") + card:add_to_deck() + card:start_materialize() + G.jokers:emplace(card) + return true + end + end, + })) + end end -- Redeemed deck if (redeemedcheck or 0) ~= 0 then @@ -709,9 +730,8 @@ local antimatter = { end, })) end - --Encoded Deck (TBA) + --Encoded Deck if (encodedcheck or 0) ~= 0 then - --[[ G.E_MANAGER:add_event(Event({ func = function() if G.jokers then @@ -737,23 +757,27 @@ local antimatter = { end end, })) - ]] - -- end end - function antimatter_trigger_effect_final_scoring_step(self, args) - local critcheck = safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_critical", "wins", 8) - local plasmacheck = safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_plasma", "wins", 8) + function Cryptid.antimatter_trigger_final_scoring(self, context) + local critcheck = + Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_critical", "wins", 8) + local plasmacheck = Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_plasma", "wins", 8) - if args.context == "final_scoring_step" then + if Cryptid.gameset(G.P_CENTERS.b_cry_antimatter) == "madness" then + critcheck = 1 + plasmacheck = 1 + end + + if context.context == "final_scoring_step" then local crit_poll = pseudorandom(pseudoseed("cry_critical")) crit_poll = crit_poll / (G.GAME.probabilities.normal or 1) --Critical Deck if (critcheck or 0) ~= 0 then if crit_poll < self.config.cry_crit_rate then - args.mult = args.mult ^ 2 - update_hand_text({ delay = 0 }, { mult = args.mult, chips = args.chips }) + context.mult = context.mult ^ 2 + update_hand_text({ delay = 0 }, { mult = context.mult, chips = context.chips }) G.E_MANAGER:add_event(Event({ func = function() play_sound("talisman_emult", 1) @@ -772,11 +796,11 @@ local antimatter = { end end --Plasma Deck - local tot = args.chips + args.mult + local tot = context.chips + context.mult if (plasmacheck or 0) ~= 0 then - args.chips = math.floor(tot / 2) - args.mult = math.floor(tot / 2) - update_hand_text({ delay = 0 }, { mult = args.mult, chips = args.chips }) + context.chips = math.floor(tot / 2) + context.mult = math.floor(tot / 2) + update_hand_text({ delay = 0 }, { mult = context.mult, chips = context.chips }) G.E_MANAGER:add_event(Event({ func = function() @@ -825,21 +849,30 @@ local antimatter = { delay(0.6) end - return args.chips, args.mult + return context.chips, context.mult end end - function antimatter_trigger_effect(self, args) - local glowingcheck = safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_glowing", "wins", 8) - local legendarycheck = safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_legendary", "wins", 8) - local anaglyphcheck = safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_anaglyph", "wins", 8) + function Cryptid.antimatter_trigger(self, context) + local glowingcheck = + Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_glowing", "wins", 8) + local legendarycheck = + Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_legendary", "wins", 8) + local anaglyphcheck = + Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_anaglyph", "wins", 8) - if args.context == "eval" and safe_get(G.GAME, "last_blind", "boss") then + if Cryptid.gameset(G.P_CENTERS.b_cry_antimatter) == "madness" then + glowingcheck = 1 + legendarycheck = 1 + anaglyphcheck = 1 + end + + if context.context == "eval" and Cryptid.safe_get(G.GAME, "last_blind", "boss") then --Glowing Deck if (glowingcheck or 0) ~= 0 then for i = 1, #G.jokers.cards do - cry_with_deck_effects(G.jokers.cards[i], function(card) - cry_misprintize(card, { min = 1.25, max = 1.25 }, nil, true) + Cryptid.with_deck_effects(G.jokers.cards[i], function(card) + Cryptid.misprintize(card, { min = 1.25, max = 1.25 }, nil, true) end) end end @@ -889,11 +922,12 @@ local antimatter = { end end - function get_antimatter_vouchers(voucher_table) + function Cryptid.get_antimatter_vouchers(voucher_table) -- 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 + local skip = (Cryptid.gameset(G.P_CENTERS.b_cry_antimatter) == "madness") -- Add Vouchers into the table by key local function already_exists(t, voucher) @@ -911,77 +945,56 @@ local antimatter = { end end - --Checks for nils in the extremely nested thing i'm checking for - - local nebulacheck = safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_nebula", "wins", 8) - local magiccheck = safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_magic", "wins", 8) - local zodiaccheck = safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_zodiac", "wins", 8) + local nebulacheck = Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_nebula", "wins", 8) + local magiccheck = Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_magic", "wins", 8) + local zodiaccheck = Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_zodiac", "wins", 8) local equilibriumcheck = - safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_equilibrium", "wins", 8) + Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_cry_equilibrium", "wins", 8) --Nebula Deck - if (nebulacheck or 0) ~= 0 then + if (nebulacheck or 0) ~= 0 or skip then Add_voucher_to_the_table(voucher_table, "v_telescope") end -- Magic Deck - if (magiccheck or 0) ~= 0 then + if (magiccheck or 0) ~= 0 or skip then Add_voucher_to_the_table(voucher_table, "v_crystal_ball") end -- Zodiac Deck - if (zodiaccheck or 0) ~= 0 then + if (zodiaccheck or 0) ~= 0 or skip 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 (equilibriumcheck or 0) ~= 0 then + if (equilibriumcheck or 0) ~= 0 or skip 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 get_antimatter_consumables(consumable_table) - --Checks for nils in the extremely nested thing i'm checking for - -- Create a table or use one that is passed into the function + function Cryptid.get_antimatter_consumables(consumable_table) + local skip = (Cryptid.gameset(G.P_CENTERS.b_cry_antimatter) == "madness") if not consumable_table or type(consumable_table) ~= "table" then consumable_table = {} end -- Add Consumables into the table by key - local magiccheck = safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_magic", "wins", 8) - local ghostcheck = safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_ghost", "wins", 8) + local magiccheck = Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_magic", "wins", 8) + local ghostcheck = Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "deck_usage", "b_ghost", "wins", 8) - if (magiccheck or 0) ~= 0 then + if (magiccheck or 0) ~= 0 or skip then table.insert(consumable_table, "c_fool") table.insert(consumable_table, "c_fool") end - if (ghostcheck or 0) ~= 0 then + if (ghostcheck or 0) ~= 0 or skip then table.insert(consumable_table, "c_hex") end return consumable_table end - - --[[ - local test = antimatter_trigger_effect - function antimatter_trigger_effect(self, args) - test(self, args) - if args.context == "eval" then - ease_dollars(900) - end - end - local test2 = get_antimatter_consumables - function get_antimatter_consumables(consumable_table) - if not consumable_table or type(consumable_table) ~= "table" then consumable_table = {} end - table.insert(consumable_table, "c_soul") - table.insert(consumable_table, "c_soul") - return test2(consumable_table) - end - ]] - -- end, } diff --git a/Cryptid/items/enhanced.lua b/Cryptid/items/enhanced.lua index 07981d1..5da3108 100644 --- a/Cryptid/items/enhanced.lua +++ b/Cryptid/items/enhanced.lua @@ -1,10 +1,5 @@ -local atlasenhanced = { - object_type = "Atlas", - key = "atlasenhanced", - path = "atlasdeck.png", - px = 71, - py = 95, -} +--Move all the stuff in here into atlasdeck.png later +--Also a lot of the edition decks have wrong proportions so those also need to get fixed local atlasedition = { object_type = "Atlas", key = "atlaseditiondeck", @@ -16,11 +11,12 @@ local atlasedition = { Cryptid.edeck_sprites = { edition = { order = 1, - default = { atlas = "centers", pos = { x = 5, y = 2 } }, + default = { atlas = "cry_placeholders", pos = { x = 4, y = 2 } }, foil = { atlas = "cry_atlaseditiondeck", pos = { x = 0, y = 0 } }, holo = { atlas = "cry_atlaseditiondeck", pos = { x = 1, y = 0 } }, polychrome = { atlas = "cry_atlaseditiondeck", pos = { x = 2, y = 0 } }, negative = { atlas = "cry_atlaseditiondeck", pos = { x = 3, y = 0 } }, + cry_glitched = { atlas = "cry_atlaseditiondeck", pos = { x = 4, y = 0 } }, cry_mosaic = { atlas = "cry_atlaseditiondeck", pos = { x = 0, y = 1 } }, cry_oversat = { atlas = "cry_atlaseditiondeck", pos = { x = 1, y = 1 } }, cry_glass = { atlas = "cry_atlaseditiondeck", pos = { x = 2, y = 1 } }, @@ -32,53 +28,57 @@ Cryptid.edeck_sprites = { }, enhancement = { order = 2, - default = { atlas = "centers", pos = { x = 5, y = 2 } }, - m_bonus = { atlas = "cry_atlasenhanced", pos = { x = 3, y = 3 } }, - m_mult = { atlas = "cry_atlasenhanced", pos = { x = 2, y = 3 } }, - m_wild = { atlas = "cry_atlasenhanced", pos = { x = 5, y = 3 } }, - m_glass = { atlas = "cry_atlasenhanced", pos = { x = 4, y = 3 } }, - m_steel = { atlas = "centers", pos = { x = 6, y = 1 } }, - m_stone = { atlas = "centers", pos = { x = 5, y = 0 } }, - m_gold = { atlas = "centers", pos = { x = 6, y = 0 } }, - m_lucky = { atlas = "centers", pos = { x = 4, y = 1 } }, - m_cry_echo = { atlas = "cry_atlasenhanced", pos = { x = 1, y = 5 } }, - m_cry_light = { atlas = "cry_misc", pos = { x = 0, y = 3 } }, + default = { atlas = "cry_placeholders", pos = { x = 4, y = 2 } }, + m_bonus = { atlas = "cry_atlasdeck", pos = { x = 3, y = 3 } }, + m_mult = { atlas = "cry_atlasdeck", pos = { x = 2, y = 3 } }, + m_wild = { atlas = "cry_atlasdeck", pos = { x = 5, y = 3 } }, + m_glass = { atlas = "cry_atlasdeck", pos = { x = 4, y = 3 } }, + m_steel = { atlas = "cry_atlasdeck", pos = { x = 8, y = 4 } }, + m_stone = { atlas = "cry_atlasdeck", pos = { x = 6, y = 4 } }, + m_gold = { atlas = "cry_atlasdeck", pos = { x = 7, y = 4 } }, + m_lucky = { atlas = "cry_atlasdeck", pos = { x = 6, y = 3 } }, + m_cry_echo = { atlas = "cry_atlasdeck", pos = { x = 1, y = 5 } }, + m_cry_light = { atlas = "cry_atlasdeck", pos = { x = 7, y = 3 } }, }, sticker = { order = 3, - default = { atlas = "centers", pos = { x = 5, y = 2 } }, - eternal = { atlas = "cry_atlasenhanced", pos = { x = 5, y = 2 } }, - perishable = { atlas = "cry_atlasenhanced", pos = { x = 0, y = 3 } }, - rental = { atlas = "cry_atlasenhanced", pos = { x = 1, y = 3 } }, - pinned = { atlas = "cry_atlasenhanced", pos = { x = 0, y = 5 } }, - banana = { atlas = "cry_atlasenhanced", pos = { x = 5, y = 4 } }, + default = { atlas = "cry_placeholders", pos = { x = 4, y = 2 } }, + eternal = { atlas = "cry_atlasdeck", pos = { x = 6, y = 0 } }, + perishable = { atlas = "cry_atlasdeck", pos = { x = 7, y = 0 } }, + rental = { atlas = "cry_atlasdeck", pos = { x = 8, y = 0 } }, + pinned = { atlas = "cry_atlasdeck", pos = { x = 7, y = 1 } }, + banana = { atlas = "cry_atlasdeck", pos = { x = 6, y = 1 } }, + cry_rigged = { atlas = "cry_atlasdeck", pos = { x = 8, y = 1 } }, + cry_absolute = { atlas = "cry_atlasdeck", pos = { x = 8, y = 2 } }, + cry_possessed = { atlas = "cry_atlasdeck", pos = { x = 7, y = 2 } }, + cry_flickering = { atlas = "cry_atlasdeck", pos = { x = 6, y = 2 } }, }, suit = { order = 4, - default = { atlas = "centers", pos = { x = 5, y = 2 } }, - Diamonds = { atlas = "cry_atlasenhanced", pos = { x = 2, y = 1 } }, - Hearts = { atlas = "cry_atlasenhanced", pos = { x = 3, y = 1 } }, - Spades = { atlas = "cry_atlasenhanced", pos = { x = 4, y = 1 } }, - Clubs = { atlas = "cry_atlasenhanced", pos = { x = 5, y = 1 } }, + default = { atlas = "cry_placeholders", pos = { x = 4, y = 2 } }, + Diamonds = { atlas = "cry_atlasdeck", pos = { x = 2, y = 1 } }, + Hearts = { atlas = "cry_atlasdeck", pos = { x = 3, y = 1 } }, + Spades = { atlas = "cry_atlasdeck", pos = { x = 4, y = 1 } }, + Clubs = { atlas = "cry_atlasdeck", pos = { x = 5, y = 1 } }, }, seal = { order = 5, - default = { atlas = "centers", pos = { x = 5, y = 2 } }, - Gold = { atlas = "centers", pos = { x = 1, y = 2 } }, - Red = { atlas = "centers", pos = { x = 0, y = 0 } }, - Blue = { atlas = "cry_atlasenhanced", pos = { x = 2, y = 2 } }, - Purple = { atlas = "cry_atlasenhanced", pos = { x = 1, y = 2 } }, - cry_azure = { atlas = "centers", pos = { x = 0, y = 2 } }, - cry_green = { atlas = "cry_atlasenhanced", pos = { x = 3, y = 5 } }, + default = { atlas = "cry_placeholders", pos = { x = 4, y = 2 } }, + Gold = { atlas = "cry_atlasdeck", pos = { x = 3, y = 2 } }, + Red = { atlas = "cry_atlasdeck", pos = { x = 0, y = 2 } }, + Blue = { atlas = "cry_atlasdeck", pos = { x = 2, y = 2 } }, + Purple = { atlas = "cry_atlasdeck", pos = { x = 1, y = 2 } }, + cry_azure = { atlas = "cry_atlasdeck", pos = { x = 8, y = 3 } }, + cry_green = { atlas = "cry_atlasdeck", pos = { x = 3, y = 5 } }, }, } -cry_edeck_atlas_update = function(self) +Cryptid.edeck_atlas_update = function(self) local sprite = Cryptid.edeck_sprites[self.edeck_type] if not sprite then error(self.edeck_type) end - local enh_info = { cry_get_enchanced_deck_info(self) } + local enh_info = { Cryptid.enhanced_deck_info(self) } sprite = sprite[enh_info[sprite.order]] or sprite.default self.atlas, self.pos = sprite.atlas, sprite.pos return sprite @@ -96,13 +96,13 @@ local e_deck = { order = 17, pos = { x = 5, y = 2 }, loc_vars = function(self, info_queue, center) - local aaa = cry_get_enchanced_deck_info(self) + local aaa = Cryptid.enhanced_deck_info(self) return { vars = { localize({ type = "name_text", set = "Edition", key = "e_" .. aaa }) } } end, edeck_type = "edition", - config = {}, + config = { cry_no_edition_price = true }, apply = function(self) - local aaa = cry_get_enchanced_deck_info(self) + local aaa = Cryptid.enhanced_deck_info(self) G.GAME.modifiers.cry_force_edition = aaa --Ban Edition tags (They will never redeem) for k, v in pairs(G.P_TAGS) do @@ -134,11 +134,11 @@ local et_deck = { edeck_type = "enhancement", config = {}, loc_vars = function(self, info_queue, center) - local _, bbb = cry_get_enchanced_deck_info(self) + local _, bbb = Cryptid.enhanced_deck_info(self) return { vars = { localize({ type = "name_text", set = "Enhanced", key = bbb }) } } end, apply = function(self) - local aaa, bbb = cry_get_enchanced_deck_info(self) + local aaa, bbb = Cryptid.enhanced_deck_info(self) G.GAME.modifiers.cry_force_enhancement = bbb G.E_MANAGER:add_event(Event({ func = function() @@ -165,14 +165,14 @@ local sk_deck = { edeck_type = "sticker", config = {}, loc_vars = function(self, info_queue, center) - local _, _, ccc = cry_get_enchanced_deck_info(self) + local _, _, ccc = Cryptid.enhanced_deck_info(self) if ccc == "pinned" then ccc = "pinned_left" end return { vars = { localize({ type = "name_text", set = "Other", key = ccc }) } } end, apply = function(self) - local aaa, bbb, ccc = cry_get_enchanced_deck_info(self) + local aaa, bbb, ccc = Cryptid.enhanced_deck_info(self) G.GAME.modifiers.cry_force_sticker = ccc G.E_MANAGER:add_event(Event({ func = function() @@ -204,11 +204,11 @@ local st_deck = { pos = { x = 5, y = 2 }, edeck_type = "suit", loc_vars = function(self, info_queue, center) - local _, _, _, ddd = cry_get_enchanced_deck_info(self) + local _, _, _, ddd = Cryptid.enhanced_deck_info(self) return { vars = { localize(ddd, "suits_plural") } } end, apply = function(self) - local aaa, bbb, ccc, ddd = cry_get_enchanced_deck_info(self) + local aaa, bbb, ccc, ddd = Cryptid.enhanced_deck_info(self) if ddd == "Spades" then G.GAME.bosses_used["bl_goad"] = 1e308 elseif ddd == "Hearts" then @@ -243,11 +243,11 @@ local sl_deck = { config = {}, edeck_type = "seal", loc_vars = function(self, info_queue, center) - local _, _, _, _, eee = cry_get_enchanced_deck_info(self) + local _, _, _, _, eee = Cryptid.enhanced_deck_info(self) return { vars = { localize({ type = "name_text", set = "Other", key = eee:lower() .. "_seal" }) } } end, apply = function(self) - local aaa, bbb, ccc, ddd, eee = cry_get_enchanced_deck_info(self) + local aaa, bbb, ccc, ddd, eee = Cryptid.enhanced_deck_info(self) G.GAME.modifiers.cry_force_seal = eee G.E_MANAGER:add_event(Event({ func = function() @@ -312,7 +312,7 @@ return { then self.config.center.immutable = true end - if safe_get(center, "name") == "Default Base" then -- scuffed + if Cryptid.safe_get(center, "name") == "Default Base" then -- scuffed return sa( self, (not self.no_forced_enhancement and G.GAME.modifiers.cry_force_enhancement) @@ -347,40 +347,40 @@ return { function Card:change_suit(new_suit) return cs(self, not self.no_forced_suit and G.GAME.modifiers.cry_force_suit or new_suit) end - local sc = Card.set_cost - function Card:set_cost() - if self.edition and G.GAME.modifiers.cry_no_edition_price then - local m = cry_deep_copy(self.edition) - self.edition = nil - sc(self) - self.edition = m - else - sc(self) - end - end local ccl = Card.click function Card:click() ccl(self) if Galdur - and (self.edeck_select or (self.area == safe_get(Galdur, "run_setup", "selected_deck_area") and safe_get( + and Cryptid.safe_get(Galdur, "run_setup", "current_page") == 1 + and (self.edeck_select or (self.area == Cryptid.safe_get(Galdur, "run_setup", "selected_deck_area") and Cryptid.safe_get( self, "config", "center", "edeck_type" ))) - or ( - safe_get(G.GAME, "viewed_back", "effect", "center", "edeck_type") - and (self.back == "viewed_back" or self.edeck_select) - ) + or not Galdur + and (Cryptid.safe_get(G.GAME, "viewed_back", "effect", "center", "edeck_type") and (self.back == "viewed_back" or self.edeck_select)) then - if self.edeck_select then - G.PROFILES[G.SETTINGS.profile]["cry_edeck_" .. self.config.center.edeck_type] = self.edeck_select + if not G.cry_edeck_select then + Cryptid.enhancement_config_UI(Galdur and self.config.center or G.GAME.viewed_back.effect.center) + G.cry_edeck_select = true + else + if self.edeck_select then + G.PROFILES[G.SETTINGS.profile]["cry_edeck_" .. self.config.center.edeck_type] = + self.edeck_select + end + G.FUNCS.overlay_menu({ + definition = G.UIDEF.run_setup("main_menu_play"), + }) + G.cry_edeck_select = nil end - cry_enhancement_config_UI(Galdur and self.config.center or G.GAME.viewed_back.effect.center) end end - function cry_enhancement_config_UI(center) + function Cryptid.enhancement_config_UI(center) + if not center.edeck_type then + return + end G.SETTINGS.paused = true G.your_collection = {} G.your_collection[1] = CardArea( @@ -413,10 +413,10 @@ return { end for i = 1, #editions do - local _center = cry_deep_copy(center) + local _center = Cryptid.deep_copy(center) _center.config["cry_force_" .. center.edeck_type] = editions[i] - cry_edeck_atlas_update(_center) - local card = create_generic_card(_center) + Cryptid.edeck_atlas_update(_center) + local card = Cryptid.generic_card(_center) card.edeck_select = editions[i] G.your_collection[1]:emplace(card) end @@ -440,5 +440,5 @@ return { }) end end, - items = { e_deck, et_deck, sk_deck, st_deck, sl_deck, atlasenhanced, atlasedition }, + items = { e_deck, et_deck, sk_deck, st_deck, sl_deck, atlasedition }, } diff --git a/Cryptid/items/epic.lua b/Cryptid/items/epic.lua index 1cdddfb..5e35fbd 100644 --- a/Cryptid/items/epic.lua +++ b/Cryptid/items/epic.lua @@ -17,7 +17,6 @@ One For all -- Supercell -- +15 Chips, +15 Mult, X2 Chips, X2 Mult, earn $3 at end of round --- TODO: Modest description local supercell = { object_type = "Joker", name = "cry-supercell", @@ -35,7 +34,10 @@ local supercell = { blueprint_compat = true, atlas = "atlasepic", loc_vars = function(self, info_queue, center) - return { vars = { center.ability.extra.stat1, center.ability.extra.stat2, center.ability.extra.money } } + return { + key = Cryptid.gameset_loc(self, { modest = "balanced" }), + vars = { center.ability.extra.stat1, center.ability.extra.stat2, center.ability.extra.money }, + } end, calculate = function(self, card, context) if context.joker_main then @@ -108,7 +110,11 @@ local membershipcardtwo = { a = 8 end return { - vars = { card.ability.extra.chips, card.ability.extra.chips * math.floor(GLOBAL_cry_member_count / a) }, + key = Cryptid.gameset_loc(self, { modest = "balanced" }), + vars = { + card.ability.extra.chips, + card.ability.extra.chips * math.floor(Cryptid.member_count / a), + }, } end, calculate = function(self, card, context) @@ -121,9 +127,9 @@ local membershipcardtwo = { message = localize({ type = "variable", key = "a_chips", - vars = { card.ability.extra.chips * math.floor(GLOBAL_cry_member_count / a) }, + vars = { card.ability.extra.chips * math.floor(Cryptid.member_count / a) }, }), - chip_mod = card.ability.extra.chips * math.floor(GLOBAL_cry_member_count / a), + chip_mod = card.ability.extra.chips * math.floor(Cryptid.member_count / a), } end end, @@ -248,6 +254,17 @@ local sync_catalyst = { return { message = localize("k_balanced"), colour = { 0.8, 0.45, 0.85, 1 }, + func = function() + G.E_MANAGER:add_event(Event({ + trigger = "after", + func = function() + play_sound("gong", 0.94, 0.3) + play_sound("gong", 0.94 * 1.5, 0.2) + play_sound("tarot1", 1.5) + return true + end, + })) + end, } end end, @@ -262,25 +279,7 @@ local sync_catalyst = { "Math", }, }, - unlocked = false, - check_for_unlock = function(self, args) - if safe_get(G, "jokers") and safe_get(G.GAME, "round_resets", "ante") and G.GAME.round_resets.ante < 9 then - local rarities = {} - for i = 1, #G.jokers.cards do - local card = G.jokers.cards[i] - rarities[card.config.center.rarity .. "_rarity"] = true - end - if rarities["3_rarity"] and rarities["4_rarity"] and rarities["cry_epic_rarity"] then - unlock_card(self) - end - end - if args.type == "cry_lock_all" then - lock_card(self) - end - if args.type == "cry_unlock_all" then - unlock_card(self) - end - end, + unlocked = true, } -- Negative Joker @@ -344,6 +343,9 @@ local canvas = { cost = 18, blueprint_compat = true, atlas = "atlasepic", + loc_vars = function(self, info_queue, center) + return { key = Cryptid.gameset_loc(self, { modest = "balanced" }) } + end, calculate = function(self, card, context) if context.retrigger_joker_check and not context.retrigger_joker then local num_retriggers = 0 @@ -409,8 +411,9 @@ local error_joker = { eternal_compat = false, atlas = "atlasepic", loc_vars = function(self, info_queue, center) - if safe_get(G.GAME, "pseudorandom") and G.STAGE == G.STAGES.RUN then - cry_error_msgs[#cry_error_msgs].string = "%%" .. predict_card_for_shop() + local ok, ret = pcall(Cryptid.predict_card_for_shop) + if Cryptid.safe_get(G.GAME, "pseudorandom") and G.STAGE == G.STAGES.RUN and ok then + cry_error_msgs[#cry_error_msgs].string = "%%" .. ret else cry_error_msgs[#cry_error_msgs].string = "%%J6" end @@ -515,7 +518,7 @@ local error_joker = { and not context.blueprint then local eval = function(card) - return (safe_get(card, "ability", "loyalty_remaining") == 0) and not G.RESET_JIGGLES + return (Cryptid.safe_get(card, "ability", "loyalty_remaining") == 0) and not G.RESET_JIGGLES end juice_card_until(card, eval, true) local jokers = {} @@ -599,32 +602,33 @@ local error_joker = { { string = "%%ERROR", colour = G.C.CRY_ASCENDANT }, --temp string, this will be modified } - function predict_pseudoseed(key) + function Cryptid.predict_pseudoseed(key) local M = G.GAME.pseudorandom[key] or pseudohash(key .. (G.GAME.pseudorandom.seed or "")) local m = math.abs(tonumber(string.format("%.13f", (2.134453429141 + M * 1.72431234) % 1))) return (m + (G.GAME.pseudorandom.hashed_seed or 0)) / 2 end - function predict_card_for_shop() + function Cryptid.predict_card_for_shop() local total_rate = G.GAME.joker_rate + G.GAME.playing_card_rate for _, v in ipairs(SMODS.ConsumableType.obj_buffer) do total_rate = total_rate + (G.GAME[v:lower() .. "_rate"] or 0) end - local polled_rate = pseudorandom(predict_pseudoseed("cdt" .. G.GAME.round_resets.ante)) * total_rate + local polled_rate = pseudorandom(Cryptid.predict_pseudoseed("cdt" .. G.GAME.round_resets.ante)) * total_rate local check_rate = 0 -- need to preserve order to leave RNG unchanged - local rates = { - { type = "Joker", val = G.GAME.joker_rate }, - { type = "Tarot", val = G.GAME.tarot_rate }, - { type = "Planet", val = G.GAME.planet_rate }, + local rates = { - type = (G.GAME.used_vouchers["v_illusion"] and pseudorandom(predict_pseudoseed("illusion")) > 0.6) - and "Enhanced" - or "Base", - val = G.GAME.playing_card_rate, - }, - { type = "Spectral", val = G.GAME.spectral_rate }, - } + { type = "Joker", val = G.GAME.joker_rate }, + { type = "Tarot", val = G.GAME.tarot_rate }, + { type = "Planet", val = G.GAME.planet_rate }, + { + type = (G.GAME.used_vouchers["v_illusion"] and pseudorandom( + Cryptid.predict_pseudoseed("illusion") + ) > 0.6) and "Enhanced" or "Base", + val = G.GAME.playing_card_rate, + }, + { type = "Spectral", val = G.GAME.spectral_rate }, + } for _, v in ipairs(SMODS.ConsumableType.obj_buffer) do if not (v == "Tarot" or v == "Planet" or v == "Spectral") then table.insert(rates, { type = v, val = G.GAME[v:lower() .. "_rate"] }) @@ -862,7 +866,7 @@ local number_blocks = { vars = { center.ability.extra.money, center.ability.extra.money_mod, - localize(safe_get(G.GAME, "current_round", "cry_nb_card", "rank") or "Ace", "ranks"), + localize(Cryptid.safe_get(G.GAME, "current_round", "cry_nb_card", "rank") or "Ace", "ranks"), }, } end, @@ -922,7 +926,12 @@ local double_scale = { }, gameset_config = { modest = { cost = 20, center = { rarity = 4 } }, + exp_modest = { cost = 11 }, }, + extra_gamesets = { "exp_modest" }, + loc_vars = function(self, info_queue, center) + return { key = Cryptid.gameset_loc(self, { exp_modest = "modest" }) } + end, order = 6, rarity = "cry_epic", cost = 18, @@ -930,6 +939,10 @@ local double_scale = { atlas = "atlasepic", --todo: support jokers that scale multiple variables cry_scale_mod = function(self, card, joker, orig_scale_scale, true_base, orig_scale_base, new_scale_base) + print(orig_scale_scale, true_base, orig_scale_base, new_scale_base) + if Cryptid.gameset(self) == "exp_modest" then + return true_base * 2 + end return orig_scale_scale + true_base end, cry_credits = { @@ -1293,7 +1306,7 @@ local curse_sob = { }, unlocked = false, check_for_unlock = function(self, args) - if safe_get(G, "jokers") then + if Cryptid.safe_get(G, "jokers") then for i = 1, #G.jokers.cards do if G.jokers.cards[i].config.center.key == "j_obelisk" and G.jokers.cards[i].ability.eternal then unlock_card(self) @@ -1565,7 +1578,7 @@ local altgoogol = { madness = { center = { blueprint_compat = true }, copies = 2 }, }, loc_vars = function(self, info_queue, center) - return { vars = { center.ability.copies } } + return { key = Cryptid.gameset_loc(self, { modest = "balanced" }), vars = { center.ability.copies } } end, calculate = function(self, card, context) local gameset = Card.get_gameset(card) @@ -1588,7 +1601,11 @@ local altgoogol = { nil, nil, nil, - (gameset == "modest" and (safe_get(chosen_joker, "edition", "negative")) or nil) + ( + gameset == "modest" + and (Cryptid.safe_get(chosen_joker, "edition", "negative")) + or nil + ) ) card:add_to_deck() G.jokers:emplace(card) @@ -1650,36 +1667,31 @@ local soccer = { "set_cry_epic", }, }, - immutable = true, + immutable = true, -- i swear i changed this... whatever rarity = "cry_epic", order = 58, cost = 20, atlas = "atlasepic", loc_vars = function(self, info_queue, center) - return { vars = { center.ability.extra.holygrail } } + return { key = Cryptid.gameset_loc(self, { modest = "balanced" }), vars = { center.ability.extra.holygrail } } end, - add_to_deck = function(self, card, from_debuff) --TODO: Card in booster packs, Voucher slots + add_to_deck = function(self, card, from_debuff) card.ability.extra.holygrail = math.floor(card.ability.extra.holygrail) - G.jokers.config.card_limit = G.jokers.config.card_limit - + ((Card.get_gameset(card) == "modest") and 0 or card.ability.extra.holygrail) - G.consumeables.config.card_limit = G.consumeables.config.card_limit + card.ability.extra.holygrail - G.hand:change_size(card.ability.extra.holygrail) - if not G.GAME.modifiers.cry_booster_packs then - G.GAME.modifiers.cry_booster_packs = 2 - end - G.GAME.modifiers.cry_booster_packs = G.GAME.modifiers.cry_booster_packs + card.ability.extra.holygrail - change_shop_size(card.ability.extra.holygrail) + local mod = card.ability.extra.holygrail + G.jokers.config.card_limit = G.jokers.config.card_limit + ((Card.get_gameset(card) == "modest") and 0 or mod) + G.consumeables.config.card_limit = G.consumeables.config.card_limit + mod + G.hand:change_size(mod) + SMODS.change_booster_limit(mod) + SMODS.change_voucher_limit(mod) end, remove_from_deck = function(self, card, from_debuff) - G.jokers.config.card_limit = G.jokers.config.card_limit - - ((Card.get_gameset(card) == "modest") and 0 or card.ability.extra.holygrail) - G.consumeables.config.card_limit = G.consumeables.config.card_limit - card.ability.extra.holygrail - G.hand:change_size(-card.ability.extra.holygrail) - if not G.GAME.modifiers.cry_booster_packs then - G.GAME.modifiers.cry_booster_packs = 2 - end - G.GAME.modifiers.cry_booster_packs = G.GAME.modifiers.cry_booster_packs - card.ability.extra.holygrail - change_shop_size(card.ability.extra.holygrail * -1) + card.ability.extra.holygrail = math.floor(card.ability.extra.holygrail) + local mod = card.ability.extra.holygrail + G.jokers.config.card_limit = G.jokers.config.card_limit + ((Card.get_gameset(card) == "modest") and 0 or -mod) + G.consumeables.config.card_limit = G.consumeables.config.card_limit - mod + G.hand:change_size(-mod) + SMODS.change_booster_limit(-mod) + SMODS.change_voucher_limit(-mod) end, cry_credits = { idea = { @@ -1746,7 +1758,7 @@ local fleshpanopticon = { card.gone = false G.GAME.blind.chips = G.GAME.blind.chips * card.ability.extra.boss_size G.GAME.blind.chip_text = number_format(G.GAME.blind.chips) - G.HUD_blind:recalculate(true) + G.HUD_blind:recalculate() G.E_MANAGER:add_event(Event({ func = function() G.E_MANAGER:add_event(Event({ @@ -1780,7 +1792,7 @@ local fleshpanopticon = { nil, nil, nil, - Cryptid.enabled["Exotic Jokers"] and "c_cry_gateway" or "c_soul", + Cryptid.enabled("c_cry_gateway") and "c_cry_gateway" or "c_soul", "sup" ) card:set_edition({ negative = true }, true) @@ -1881,6 +1893,49 @@ local spectrogram = { }, }, } +local jtron = { + object_type = "Joker", + dependencies = { + items = { + "set_cry_epic", + }, + }, + name = "cry-jtron", + key = "jtron", + config = { extra = { bonus = 1, current = 0 } }, + rarity = "cry_epic", + cost = 14, + order = 64, + blueprint_compat = true, + atlas = "atlasepic", + pos = { x = 2, y = 5 }, + loc_vars = function(self, info_queue, center) + info_queue[#info_queue + 1] = G.P_CENTERS.j_joker + center.ability.extra.current = 1 + center.ability.extra.bonus * #SMODS.find_card("j_joker") + return { vars = { center.ability.extra.bonus, center.ability.extra.current } } + end, + calculate = function(self, card, context) + card.ability.extra.current = 1 + card.ability.extra.bonus * #SMODS.find_card("j_joker") + if context.cardarea == G.jokers and context.joker_main then + return { + message = localize({ + type = "variable", + key = "a_powmult", + vars = { + number_format(card.ability.extra.current), + }, + }), + Emult_mod = card.ability.extra.current, + colour = G.C.DARK_EDITION, + } + end + end, + cry_credits = { + idea = { "AlexZGreat" }, + art = { "Darren_The_Frog" }, + code = { "candycanearter" }, + }, +} return { name = "Epic Jokers", items = { @@ -1907,5 +1962,6 @@ return { soccer, fleshpanopticon, spectrogram, + jtron, }, } diff --git a/Cryptid/items/exotic.lua b/Cryptid/items/exotic.lua index 465f683..53d9e47 100644 --- a/Cryptid/items/exotic.lua +++ b/Cryptid/items/exotic.lua @@ -17,7 +17,12 @@ local gateway = { order = 90, hidden = true, --default soul_set and soul_rate of 0.3% in spectral packs is used can_use = function(self, card) - return true + if (#SMODS.find_card("j_jen_saint") + #SMODS.find_card("j_jen_saint_attuned")) > 0 then + return #G.jokers.cards < G.jokers.config.card_limit + else + --Don't allow use if everything is eternal and there is no room + return #Cryptid.advanced_find_joker(nil, nil, nil, { "eternal" }, true, "j") < G.jokers.config.card_limit + end end, use = function(self, card, area, copier) if (#SMODS.find_card("j_jen_saint") + #SMODS.find_card("j_jen_saint_attuned")) <= 0 then @@ -136,7 +141,7 @@ local universum = { end, cry_credits = { idea = { "Ein13" }, - art = { "Ein13/hydrogenperoxiide" }, + art = { "Ein13", "hydro" }, }, init = function(self) --Universum Patches @@ -315,7 +320,7 @@ local exponentia = { vars = { number_format(to_big(v.ability.extra.Emult)) }, }), }) - exponentia_scale_mod(v, v.ability.extra.Emult_mod, old, v.ability.extra.Emult) + Cryptid.exponentia_scale_mod(v, v.ability.extra.Emult_mod, old, v.ability.extra.Emult) end end return ret @@ -427,7 +432,7 @@ local redeo = { end, cry_credits = { idea = { "Enemui" }, - art = { "Jevonn" }, + art = { "Jevonn", "Darren_The_Frog" }, code = { "Math", "jenwalter666" }, }, init = function(self) @@ -505,7 +510,7 @@ local effarcire = { end, cry_credits = { idea = { "Frix" }, - art = { "AlexZGreat" }, + art = { "AlexZGreat", "Catformer" }, code = { "jenwalter666" }, }, } @@ -693,7 +698,7 @@ local scalae = { ) ^ card.ability.extra.scale ) ) - if (new_scale < to_big(1e100)) or not is_card_big(joker) then + if (new_scale < to_big(1e100)) or not Cryptid.is_card_big(joker) then if new_scale >= to_big(1e300) then new_scale = 1e300 else @@ -704,7 +709,19 @@ local scalae = { end end, loc_vars = function(self, info_queue, card) - return { vars = { number_format(card.ability.extra.scale + 1), number_format(card.ability.extra.scale_mod) } } + local example = { 2, 3, 4 } + for i = 1, #example do + example[i] = to_big(example[i]) ^ (card.ability.extra.scale + 1) + end + return { + vars = { + number_format(card.ability.extra.scale + 1), + number_format(card.ability.extra.scale_mod), + example[1], + example[2], + example[3], + }, + } end, cry_credits = { idea = { "Mathguy" }, @@ -794,7 +811,7 @@ local stella_mortis = { end, cry_credits = { idea = { "SMG9000" }, - art = { "SMG9000" }, + art = { "SMG9000", "George the Rat", "patchy", "lolxDdj" }, code = { "SMG9000" }, }, } @@ -819,7 +836,7 @@ local circulus_pistoris = { loc_vars = function(self, info_queue, center) return { vars = { - safe_get(center, "edition", "cry_oversat") and "tau" or "pi", + Cryptid.safe_get(center, "edition", "cry_oversat") and "tau" or "pi", center.ability.extra.hands_remaining, }, } @@ -833,7 +850,7 @@ local circulus_pistoris = { ) then local pi = math.pi - if safe_get(card, "edition", "cry_oversat") then + if Cryptid.safe_get(card, "edition", "cry_oversat") then pi = 2 * pi end return { @@ -842,7 +859,7 @@ local circulus_pistoris = { message = localize({ type = "variable", key = "a_powmultchips", - vars = { (safe_get(card, "edition", "cry_oversat") and "tau" or "pi") }, + vars = { (Cryptid.safe_get(card, "edition", "cry_oversat") and "tau" or "pi") }, }), colour = { 0.8, 0.45, 0.85, 1 }, --plasma colors } @@ -850,7 +867,7 @@ local circulus_pistoris = { end, cry_credits = { idea = { "SMG9000", "Math" }, --not sure if there's more ppl I'm missing - art = { "HexaCryonic" }, + art = { "HexaCryonic", "ori" }, code = { "SMG9000", "Math" }, }, } @@ -973,7 +990,7 @@ local aequilibrium = { -- cry_credits = { idea = { "Elial2" }, - art = { "Elial2" }, + art = { "Elial2", "unexian", "hydro" }, code = { "Elial2" }, }, } @@ -1025,7 +1042,7 @@ local facile = { end, cry_credits = { idea = { "Enemui" }, - art = { "Kailen" }, + art = { "Kailen", "hydro" }, code = { "Jevonn" }, }, } @@ -1047,7 +1064,7 @@ local gemino = { "Jolly Open Winner", "Requiacity", }, - art = { "Requiacity" }, + art = { "unexian" }, code = { "Math" }, }, rarity = "cry_exotic", @@ -1106,8 +1123,8 @@ local gemino = { local check = false local card = G.jokers.cards[1] if not Card.no(G.jokers.cards[1], "immutable", true) then - cry_with_deck_effects(G.jokers.cards[1], function(card) - cry_misprintize(card, { min = 2, max = 2 }, nil, true) + Cryptid.with_deck_effects(G.jokers.cards[1], function(card) + Cryptid.misprintize(card, { min = 2, max = 2 }, nil, true) end) check = true end @@ -1169,7 +1186,7 @@ local energia = { end, cry_credits = { idea = { "jenwalter666" }, - art = { "Kailen" }, + art = { "unexian" }, code = { "Math" }, }, } @@ -1417,7 +1434,7 @@ local formidiulosus = { no_dbl = true, update = function(self, card, front) card.ability.extra.Emult = 1 - + (card.ability.extra.Emult_mod * #advanced_find_joker(nil, "cry_candy", nil, nil, true)) + + (card.ability.extra.Emult_mod * #Cryptid.advanced_find_joker(nil, "cry_candy", nil, nil, true)) end, calculate = function(self, card, context) if @@ -1446,12 +1463,7 @@ local formidiulosus = { G.jokers:emplace(card) end end - if - context.cardarea == G.jokers - and (to_big(card.ability.extra.Emult) > to_big(1)) - and not context.before - and not context.after - then + if context.cardarea == G.jokers and (to_big(card.ability.extra.Emult) > to_big(1)) and context.joker_main then return { message = localize({ type = "variable", @@ -1467,7 +1479,7 @@ local formidiulosus = { end, cry_credits = { idea = { "HexaCryonic", "Kailen" }, - art = { "Foegro" }, + art = { "Foegro", "hydro" }, code = { "Foegro" }, }, } @@ -1493,7 +1505,7 @@ local items = { --verisimile, WHY IS THIS AN EXOTIC???????????????????? --rescribere, [NEEDS REFACTOR] duplicare, - --formidiulosus + formidiulosus, } return { name = "Exotic Jokers", diff --git a/Cryptid/items/joker_display.lua b/Cryptid/items/joker_display.lua index 7cb570d..e4882c3 100644 --- a/Cryptid/items/joker_display.lua +++ b/Cryptid/items/joker_display.lua @@ -449,7 +449,7 @@ if JokerDisplay then }, text_config = { colour = G.C.CHIPS }, calc_function = function(card) - card.joker_display_values.stat = card.ability.extra.chips * (GLOBAL_cry_member_count or 1) + card.joker_display_values.stat = card.ability.extra.chips * Cryptid.member_count end, } JokerDisplay.Definitions["j_cry_redeo"] = { @@ -578,7 +578,7 @@ if JokerDisplay then e_mult = ( card.ability.name == "Jolly Joker" or card.edition and card.edition.key == "e_cry_m" - or safe_get(card, "pools", "M") + or Cryptid.safe_get(card, "pools", "M") ) and mod_joker.ability.extra.mult * JokerDisplay.calculate_joker_triggers(mod_joker) or nil, @@ -1753,8 +1753,7 @@ if JokerDisplay then }, }, calc_function = function(card) - card.joker_display_values.stat = - math.max(1, (card.ability.extra.Xmult_mod * (GLOBAL_cry_member_count or 1))) + card.joker_display_values.stat = math.max(1, card.ability.extra.Xmult_mod * Cryptid.member_count) end, } JokerDisplay.Definitions["j_cry_cryptidmoment"] = { @@ -1806,7 +1805,7 @@ if JokerDisplay then { border_nodes = { { text = "X" }, - { ref_table = "card.ability.extra", ref_value = "mult", retrigger_type = "exp" }, + { ref_table = "card.ability.extra", ref_value = "monster", retrigger_type = "exp" }, }, }, }, diff --git a/Cryptid/items/m.lua b/Cryptid/items/m.lua index b61ab85..0ff9bcc 100644 --- a/Cryptid/items/m.lua +++ b/Cryptid/items/m.lua @@ -15,7 +15,7 @@ local jollysus = { }, immutable = true, loc_vars = function(self, info_queue, center) - if cry_card_enabled("e_cry_m") == true then + if Cryptid.enabled("e_cry_m") == true then info_queue[#info_queue + 1] = G.P_CENTERS.e_cry_m end return { vars = { center.ability.extra.active } } @@ -39,7 +39,7 @@ local jollysus = { card.ability.extra.spawn = false end local card = create_card("Joker", G.jokers, nil, nil, nil, nil, nil, "jollysus") - if cry_card_enabled("e_cry_m") == true then + if Cryptid.enabled("e_cry_m") == true then card:set_edition({ cry_m = true }) end card:add_to_deck() @@ -58,7 +58,7 @@ local jollysus = { card.ability.extra.spawn = false end local card = create_card("Joker", G.jokers, nil, nil, nil, nil, nil, "jollysus") - if cry_card_enabled("e_cry_m") == true then + if Cryptid.enabled("e_cry_m") == true then card:set_edition({ cry_m = true }) end card:add_to_deck() @@ -368,7 +368,7 @@ local mneon = { if context.end_of_round and not context.blueprint and not context.individual and not context.repetition then local jollycount = 0 for i = 1, #G.jokers.cards do - if G.jokers.cards[i]:is_jolly() or safe_get(G.jokers.cards[i], "pools", "M") then + if G.jokers.cards[i]:is_jolly() or Cryptid.safe_get(G.jokers.cards[i].config.center, "pools", "M") then jollycount = jollycount + 1 end end @@ -490,11 +490,10 @@ local bonk = { object_type = "Joker", name = "cry-bonk", key = "bonk", - pools = { ["M"] = true }, + pools = { ["M"] = true, ["Meme"] = true }, order = 256, pos = { x = 2, y = 2 }, config = { extra = { chips = 6, bonus = 1, xchips = 3, type = "Pair" } }, - pools = { ["Meme"] = true }, loc_vars = function(self, info_queue, center) info_queue[#info_queue + 1] = G.P_CENTERS.j_jolly return { @@ -649,7 +648,7 @@ local scrabble = { blueprint_compat = true, atlas = "atlasone", loc_vars = function(self, info_queue, card) - if cry_card_enabled("e_cry_m") == true then + if Cryptid.enabled("e_cry_m") == true then info_queue[#info_queue + 1] = G.P_CENTERS.e_cry_m end return { @@ -669,7 +668,7 @@ local scrabble = { then check = true local card = create_card("Joker", G.jokers, nil, 0.9, nil, nil, nil, "scrabbletile") - if cry_card_enabled("e_cry_m") == true then + if Cryptid.enabled("e_cry_m") == true then card:set_edition({ cry_m = true }) end card:add_to_deck() @@ -781,6 +780,7 @@ local sacrifice = { }, art = { "Jevonn", + "George the Rat", }, code = { "Jevonn", @@ -1060,7 +1060,9 @@ local smallestm = { if context.cardarea == G.jokers and context.before then --This isn't retrigger joker compatible for some reason if context.scoring_name == card.ability.extra.type then - add_tag(Tag("tag_cry_double_m")) + local tag = Tag("tag_cry_double_m") + tag.ability.shiny = cry_rollshinybool() + add_tag(tag) play_sound("generic1", 0.9 + math.random() * 0.1, 0.8) play_sound("holo1", 1.2 + math.random() * 0.1, 0.4) card_eval_status_text(context.blueprint_card or card, "extra", nil, nil, nil, { @@ -1218,7 +1220,9 @@ local mprime = { elseif context.other_joker then if context.other_joker - and (context.other_joker:is_jolly() or safe_get(context.other_joker, "pools", "M")) + and ( + context.other_joker:is_jolly() or Cryptid.safe_get(context.other_joker.config.center, "pools", "M") + ) then if not Talisman.config_file.disable_anims then G.E_MANAGER:add_event(Event({ @@ -1284,7 +1288,11 @@ local macabre = { v ~= card and not v:is_jolly() and v.config.center.key ~= "j_cry_mprime" - and not (v.ability.eternal or v.getting_sliced or safe_get(v, "pools", "M")) + and not ( + v.ability.eternal + or v.getting_sliced + or Cryptid.safe_get(v.config.center, "pools", "M") + ) then destroyed_jokers[#destroyed_jokers + 1] = v end @@ -1401,29 +1409,25 @@ local longboi = { name = "cry-longboi", key = "longboi", pos = { x = 5, y = 4 }, - config = { extra = { mult = nil, bonus = 0.75 } }, + config = { extra = { monster = 1, bonus = 0.75 } }, rarity = 1, cost = 5, order = 261, pools = { ["M"] = true }, - no_dbl = true, blueprint_compat = true, eternal_compat = false, loc_vars = function(self, info_queue, center) return { vars = { - math.max(0.75, math.floor(center.ability.extra.bonus)), - (center.ability.extra.mult ~= nil and center.ability.extra.mult or (G.GAME.monstermult or 1)), + math.max(0.75, center.ability.extra.bonus), + center.ability.extra.monster, }, } end, atlas = "atlasthree", calculate = function(self, card, context) if context.end_of_round and not context.individual and not context.repetition then - if not G.GAME.monstermult then - G.GAME.monstermult = 1 - end - G.GAME.monstermult = G.GAME.monstermult + math.max(0.75, math.floor(card.ability.extra.bonus)) + G.GAME.monstermult = G.GAME.monstermult + math.max(0.75, card.ability.extra.bonus) if not context.retrigger_joker then return { card_eval_status_text(context.blueprint_card or card, "extra", nil, nil, nil, { @@ -1432,21 +1436,19 @@ local longboi = { }), } end - elseif context.joker_main and ((card.ability.extra.mult or 1) > 1) then + elseif context.joker_main and card.ability.extra.monster > 1 then return { - message = localize({ type = "variable", key = "a_xmult", vars = { card.ability.extra.mult } }), - Xmult_mod = card.ability.extra.mult, + message = localize({ type = "variable", key = "a_xmult", vars = { card.ability.extra.monster } }), + Xmult_mod = card.ability.extra.monster, } end end, - add_to_deck = function(self, card, from_debuff) - if (not from_debuff and card.ability.extra.mult == nil) or card.checkmonster then - --Stops Things like Gemini from updating mult when it isn't supposed to - if card.checkmonster then - card.checkmonster = nil - end - - card.ability.extra.mult = G.GAME.monstermult or 1 + set_ability = function(self, card, from_debuff) + card.ability.extra.monster = G.GAME and G.GAME.monstermult or 1 + if card.ability.extra.monster >= 1234567654321 then + card.children.center:set_sprite_pos({ x = 7, y = 5 }) + elseif card.ability.extra.monster >= 12321 then + card.children.center:set_sprite_pos({ x = 7, y = 6 }) end end, cry_credits = { @@ -1462,6 +1464,7 @@ local longboi = { }, } local ret_items = { + jollysus, bubblem, foodm, mstack, @@ -1481,7 +1484,7 @@ local ret_items = { mprime, } --retriggering system for M Vouchers -function get_m_retriggers(self, card, context) +function Cryptid.get_m_retriggers(self, card, context) local text, disp_text, poker_hands, scoring_hand, non_loc_disp_text = G.FUNCS.get_poker_hand_info(G.play.cards) if G.GAME.used_vouchers.v_cry_pairamount_plus then local pairs = 0 diff --git a/Cryptid/items/misc.lua b/Cryptid/items/misc.lua index 10a630b..b6f7e67 100644 --- a/Cryptid/items/misc.lua +++ b/Cryptid/items/misc.lua @@ -1,5 +1,26 @@ -- Packs +local meme_digital_hallucinations_compat = { + colour = G.C.CRY_ASCENDANT, + loc_key = "k_plus_joker", + create = function() + local ccard = create_card("Meme", G.jokers, nil, nil, true, true, nil, "diha") + ccard:set_edition({ negative = true }, true) + ccard:add_to_deck() + G.jokers:emplace(ccard) --Note: Will break if any non-Joker gets added to the meme pool + end, +} local meme1 = { + cry_credits = { + idea = { + "Jevonn", + }, + art = { + "Jevonn", + }, + code = { + "Jevonn", + }, + }, object_type = "Booster", dependencies = { items = { @@ -16,7 +37,7 @@ local meme1 = { weight = 0.18 / 3, --0.18 base ÷ 3 since there are 3 identical packs create_card = function(self, card) if - Cryptid.enabled["Misc. Jokers"] + Cryptid.enabled("j_cry_waluigi") and not (G.GAME.used_jokers["j_cry_waluigi"] and not next(find_joker("Showman"))) then if pseudorandom("meme1_" .. G.GAME.round_resets.ante) > 0.997 then @@ -43,13 +64,24 @@ local meme1 = { SMODS.Booster.update_pack(self, dt) end, group_key = "k_cry_meme_pack", + cry_digital_hallucinations = meme_digital_hallucinations_compat, } local meme2 = { + cry_credits = { + idea = { + "Jevonn", + }, + art = { + "Jevonn", + }, + code = { + "Jevonn", + }, + }, object_type = "Booster", dependencies = { items = { "set_cry_misc", - "p_cry_meme_1", }, }, key = "meme_two", @@ -62,7 +94,7 @@ local meme2 = { weight = 0.18 / 3, --0.18 base ÷ 3 since there are 3 identical packs create_card = function(self, card) if - Cryptid.enabled["Misc. Jokers"] + Cryptid.enabled("j_cry_waluigi") and not (G.GAME.used_jokers["j_cry_waluigi"] and not next(find_joker("Showman"))) then if pseudorandom("memetwo_" .. G.GAME.round_resets.ante) > 0.997 then @@ -89,14 +121,24 @@ local meme2 = { SMODS.Booster.update_pack(self, dt) end, group_key = "k_cry_meme_pack", + cry_digital_hallucinations = meme_digital_hallucinations_compat, } local meme3 = { + cry_credits = { + idea = { + "Jevonn", + }, + art = { + "Jevonn", + }, + code = { + "Jevonn", + }, + }, object_type = "Booster", dependencies = { items = { "set_cry_misc", - "p_cry_meme_1", - "p_cry_meme_two", }, }, key = "meme_three", @@ -109,7 +151,7 @@ local meme3 = { weight = 0.18 / 3, --0.18 base ÷ 3 since there are 3 identical packs create_card = function(self, card) if - Cryptid.enabled["Misc. Jokers"] + Cryptid.enabled("j_cry_waluigi") and not (G.GAME.used_jokers["j_cry_waluigi"] and not next(find_joker("Showman"))) then if pseudorandom("memethree_" .. G.GAME.round_resets.ante) > 0.997 then @@ -136,6 +178,7 @@ local meme3 = { SMODS.Booster.update_pack(self, dt) end, group_key = "k_cry_meme_pack", + cry_digital_hallucinations = meme_digital_hallucinations_compat, } if not AurinkoAddons then @@ -149,6 +192,18 @@ local mosaic_shader = { path = "mosaic.fs", } local mosaic = { + cry_credits = { + idea = { + "Mystic Misclick", + }, + --Replace with Shader later + art = { + "Math", + }, + code = { + "Math", + }, + }, object_type = "Edition", dependencies = { items = { @@ -202,6 +257,17 @@ local oversat_shader = { path = "oversat.fs", } local oversat = { + cry_credits = { + idea = { + "Math", + }, + art = { + "Math", + }, + code = { + "Math", + }, + }, object_type = "Edition", dependencies = { items = { @@ -222,26 +288,32 @@ local oversat = { get_weight = function(self) return G.GAME.edition_rate * self.weight end, + -- Note: Duping playing cards resets the base chips for some reason on_apply = function(card) - cry_with_deck_effects(card, function(card) - cry_misprintize(card, { - min = 2, - max = 2, - }, nil, true) - end) - if card.config.center.apply_oversat then - card.config.center:apply_oversat(card, function(val) - return cry_misprintize_val(val, { + if not card.ability.cry_oversat then + Cryptid.with_deck_effects(card, function(card) + Cryptid.misprintize(card, { min = 2, max = 2, - }, is_card_big(card), true) + }, nil, true) end) + if card.config.center.apply_oversat then + card.config.center:apply_oversat(card, function(val) + return Cryptid.misprintize_val(val, { + min = 2 * (G.GAME.modifiers.cry_misprint_min or 1), + max = 2 * (G.GAME.modifiers.cry_misprint_max or 1), + }, Cryptid.is_card_big(card)) + end) + end end + card.ability.cry_oversat = true end, on_remove = function(card) - cry_with_deck_effects(card, function(card) - cry_misprintize(card, { min = 0.5, max = 0.5 }, nil, true) + Cryptid.with_deck_effects(card, function(card) + Cryptid.misprintize(card, { min = 1, max = 1 }, true) + Cryptid.misprintize(card) -- Correct me if i'm wrong but this is for misprint deck. or atleast it is after this patch end) + card.ability.cry_oversat = nil end, init = function(self) AurinkoAddons.cry_oversat = function(card, hand, instant, amount) @@ -300,6 +372,14 @@ local glitched_shader = { path = "glitched.fs", } local glitched = { + cry_credits = { + art = { + "Samario", + }, + code = { + "Math", + }, + }, object_type = "Edition", dependencies = { items = { @@ -320,29 +400,32 @@ local glitched = { get_weight = function(self) return G.GAME.edition_rate * self.weight end, - -- Note: This is happening even when it shouldn't (like in deck view) - -- Also messes with rank sort order a bit for some reason + -- Note: Duping playing cards resets the base chips for some reason on_apply = function(card) - cry_with_deck_effects(card, function(card) - cry_misprintize(card, { - min = 0.1, - max = 10, - }, nil, true) - end) - if card.config.center.apply_glitched then - card.config.center:apply_glitched(card, function(val) - return cry_misprintize_val(val, { - min = 0.1 * (G.GAME.modifiers.cry_misprint_min or 1), - max = 10 * (G.GAME.modifiers.cry_misprint_max or 1), - }, is_card_big(card), true) + if not card.ability.cry_glitched then + Cryptid.with_deck_effects(card, function(card) + Cryptid.misprintize(card, { + min = 0.1, + max = 10, + }, nil, true) end) + if card.config.center.apply_glitched then + card.config.center:apply_glitched(card, function(val) + return Cryptid.misprintize_val(val, { + min = 0.1 * (G.GAME.modifiers.cry_misprint_min or 1), + max = 10 * (G.GAME.modifiers.cry_misprint_max or 1), + }, Cryptid.is_card_big(card)) + end) + end end + card.ability.cry_glitched = true end, on_remove = function(card) - cry_with_deck_effects(card, function(card) - cry_misprintize(card, { min = 1, max = 1 }, true) - cry_misprintize(card) -- Correct me if i'm wrong but this is for misprint deck. or atleast it is after this patch + Cryptid.with_deck_effects(card, function(card) + Cryptid.misprintize(card, { min = 1, max = 1 }, true) + Cryptid.misprintize(card) -- Correct me if i'm wrong but this is for misprint deck. or atleast it is after this patch end) + card.ability.cry_glitched = nil end, init = function(self) local randtext = { @@ -431,14 +514,14 @@ local glitched = { AurinkoAddons.cry_glitched = function(card, hand, instant, amount) local modc = G.GAME.hands[hand].l_chips - * cry_log_random( + * Cryptid.log_random( pseudoseed("cry_aurinko_chips_misprint" .. G.GAME.round_resets.ante), (G.GAME.modifiers.cry_misprint_min or 1) / 10, (G.GAME.modifiers.cry_misprint_max or 1) * 10 ) * amount local modm = G.GAME.hands[hand].l_mult - * cry_log_random( + * Cryptid.log_random( pseudoseed("cry_aurinko_mult_misprint" .. G.GAME.round_resets.ante), (G.GAME.modifiers.cry_misprint_min or 1) / 10, (G.GAME.modifiers.cry_misprint_max or 1) * 10 @@ -525,6 +608,15 @@ local astral_shader = { path = "astral.fs", } local astral = { + cry_credits = { + --Don't remember who came up with this idea + art = { + "AlexZGreat", + }, + code = { + "Math", + }, + }, object_type = "Edition", dependencies = { items = { @@ -578,6 +670,17 @@ local blurred_shader = { path = "blur.fs", } local blurred = { + cry_credits = { + idea = { + "stupid", + }, + art = { + "stupid", + }, + code = { + "stupid", + }, + }, object_type = "Edition", dependencies = { items = { @@ -641,6 +744,17 @@ local noisy_stats = { }, } local noisy = { + cry_credits = { + idea = { + "Math", + }, + art = { + "jenwalter666", + }, + code = { + "Math", + }, + }, object_type = "Edition", dependencies = { items = { @@ -902,6 +1016,18 @@ local jollyeditionshader = { path = "m.fs", } local jollyedition = { + cry_credits = { + idea = { + "Jevonn", + }, + art = { + "stupid", + "Math", + }, + code = { + "Jevonn", + }, + }, object_type = "Edition", dependencies = { items = { @@ -1034,6 +1160,17 @@ local glass_shader = { end, } local glass_edition = { + cry_credits = { + idea = { + "Math", + }, + art = { + "stupid", + }, + code = { + "Math", + }, + }, object_type = "Edition", dependencies = { items = { @@ -1163,6 +1300,17 @@ local gold_shader = { end, } local gold_edition = { + cry_credits = { + idea = { + "Math", + }, + art = { + "stupid", + }, + code = { + "Math", + }, + }, object_type = "Edition", dependencies = { items = { @@ -1219,9 +1367,9 @@ local double_sided = { modest = { disabled = true }, mainline = { disabled = true }, madness = { disabled = true }, - experimental = {}, + exp = {}, }, - extra_gamesets = { "experimental" }, + extra_gamesets = { "exp" }, key = "double_sided", shader = false, order = 32, @@ -1235,6 +1383,9 @@ local double_sided = { vol = 0.3, }, cry_credits = { + code = { + "Math", + }, jolly = { "Jolly Open Winner", "Axolotolus", @@ -1282,7 +1433,7 @@ local double_sided = { local area = e.config.ref_table.area area:remove_card(e.config.ref_table) mergedcard:init_dbl_side() - copy_dbl_card(e.config.ref_table, mergedcard.dbl_side) + Cryptid.copy_dbl_card(e.config.ref_table, mergedcard.dbl_side) e.config.ref_table:remove() e.config.ref_table = nil return true @@ -1430,7 +1581,7 @@ local double_sided = { self.ability.eternal = true end end - function copy_dbl_card(C, c, deck_effects) + function Cryptid.copy_dbl_card(C, c, deck_effects) if not deck_effects then Cdeck = C.added_to_deck cdeck = c.added_to_deck @@ -1445,11 +1596,11 @@ local double_sided = { self:set_edition(nil, true) end if not self.dbl_side then - self.dbl_side = cry_deep_copy(self) + self.dbl_side = Cryptid.deep_copy(self) self.dbl_side:set_ability(G.P_CENTERS.j_joker) -- self.dbl_side:set_base(G.P_CARDS.empty) -- RIGHT HERE THIS RIGHT HERE THATS YOUR DAM CULPRIT if self.area == G.hand then - self.dbl_side = cry_deep_copy(self) + self.dbl_side = Cryptid.deep_copy(self) self.dbl_side:set_ability(G.P_CENTERS.c_base) end self.dbl_side.added_to_deck = false @@ -1458,7 +1609,7 @@ local double_sided = { end function Card:dbl_side_flip() local init_dbl_side = self:init_dbl_side() - local tmp_side = cry_deep_copy(self.dbl_side) + local tmp_side = Cryptid.deep_copy(self.dbl_side) self.children.center.scale = { x = self.children.center.atlas.px, y = self.children.center.atlas.py } self.T.w, self.T.h = G.CARD_W, G.CARD_H local active_side = self @@ -1468,8 +1619,8 @@ local double_sided = { if not init_dbl_side then active_side:remove_from_deck(true) end - copy_dbl_card(self, self.dbl_side, false) - copy_dbl_card(tmp_side, self, false) + Cryptid.copy_dbl_card(self, self.dbl_side, false) + Cryptid.copy_dbl_card(tmp_side, self, false) active_side:add_to_deck(true) self.children.center:set_sprite_pos(G.P_CENTERS[self.config.center.key].pos) if self.base then @@ -1519,7 +1670,7 @@ local double_sided = { end end if cardTable.dbl_side then - self.dbl_side = cry_deep_copy(self) + self.dbl_side = Cryptid.deep_copy(self) cload(self.dbl_side, cardTable.dbl_side) if self.dbl_side.ability.set == "Default" and self.ability.set ~= "Default" then self.dbl_side:set_ability(G.P_CENTERS.c_base, true) @@ -1626,6 +1777,12 @@ local meld = { end end, cry_credits = { + art = { + "Linus Goof Balls", + }, + code = { + "Math", + }, jolly = { "Jolly Open Winner", "Axolotolus", @@ -1652,6 +1809,17 @@ local meld = { -- Enhancements/Tarots local echo = { + cry_credits = { + idea = { + "Mystic Misclick", + }, + art = { + "Coronacht", + }, + code = { + "AlexZGreat", + }, + }, object_type = "Enhancement", dependencies = { items = { @@ -1686,6 +1854,17 @@ local echo = { end, } local eclipse = { + cry_credits = { + idea = { + "Mystick Misclick", + }, + art = { + "AlexZGreat", + }, + code = { + "AlexZGreat", + }, + }, object_type = "Consumable", dependencies = { items = { @@ -1707,6 +1886,17 @@ local eclipse = { end, } local light = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "AlexZGreat", + }, + code = { + "AlexZGreat", + }, + }, object_type = "Enhancement", dependencies = { items = { @@ -1747,6 +1937,17 @@ local light = { end, } local seraph = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "sachertote", + }, + code = { + "AlexZGreat", + }, + }, object_type = "Consumable", dependencies = { items = { @@ -1768,6 +1969,17 @@ local seraph = { end, } local blessing = { + cry_credits = { + idea = { + "5381", + }, + art = { + "RattlingSnow353", + }, + code = { + "Jevonn", + }, + }, object_type = "Consumable", dependencies = { items = { @@ -1793,10 +2005,10 @@ local blessing = { func = function() if G.consumeables.config.card_limit > #G.consumeables.cards then play_sound("timpani") - local forced_key = get_random_consumable("blessing", nil, "c_cry_blessing") + local forced_key = Cryptid.random_consumable("blessing", nil, "c_cry_blessing") local _card = create_card( "Consumeables", - G.consumables, + G.consumeables, nil, nil, nil, @@ -1817,6 +2029,17 @@ local blessing = { -- Seals local azure_seal = { + cry_credits = { + idea = { + "stupid", + }, + art = { + "stupid", + }, + code = { + "stupid", + }, + }, object_type = "Seal", dependencies = { items = { @@ -1867,6 +2090,17 @@ local azure_seal = { end, } local typhoon = { + cry_credits = { + idea = { + "stupid", + }, + art = { + "stupid", + }, + code = { + "stupid", + }, + }, object_type = "Consumable", dependencies = { items = { @@ -1943,20 +2177,24 @@ local absolute = { should_apply = false, no_sticker_sheet = true, draw = function(self, card, layer) + local notilt = nil + if card.area and card.area.config.type == "deck" then + notilt = true + end G.shared_stickers["cry_absolute"].role.draw_major = card - G.shared_stickers["cry_absolute"]:draw_shader("dissolve", nil, nil, nil, card.children.center) + G.shared_stickers["cry_absolute"]:draw_shader("dissolve", nil, nil, notilt, card.children.center) G.shared_stickers["cry_absolute"]:draw_shader( "polychrome", nil, card.ARGS.send_to_shader, - nil, + notilt, card.children.center ) G.shared_stickers["cry_absolute"]:draw_shader( "voucher", nil, card.ARGS.send_to_shader, - nil, + notilt, card.children.center ) end, diff --git a/Cryptid/items/misc_joker.lua b/Cryptid/items/misc_joker.lua index 4aafb0f..14e531a 100644 --- a/Cryptid/items/misc_joker.lua +++ b/Cryptid/items/misc_joker.lua @@ -76,41 +76,12 @@ local dropshot = { }, art = { "Mystic Misclick", + "George the Rat", }, code = { "Math", }, }, - init = function(self) - local gigo = Game.init_game_object - function Game:init_game_object() - local g = gigo(self) - g.current_round.cry_dropshot_card = { suit = "Spades" } - return g - end - local rcc = reset_castle_card - function reset_castle_card() - rcc() - if not G.GAME.current_round.cry_dropshot_card then - G.GAME.current_round.cry_dropshot_card = {} - end - G.GAME.current_round.cry_dropshot_card.suit = "Spades" - local valid_castle_cards = {} - for k, v in ipairs(G.playing_cards) do - if v.ability.effect ~= "Stone Card" then - valid_castle_cards[#valid_castle_cards + 1] = v - end - end - if valid_castle_cards[1] then - local castle_card = - pseudorandom_element(valid_castle_cards, pseudoseed("cry_dro" .. G.GAME.round_resets.ante)) - if not G.GAME.current_round.cry_dropshot_card then - G.GAME.current_round.cry_dropshot_card = {} - end - G.GAME.current_round.cry_dropshot_card.suit = castle_card.base.suit - end - end - end, } local happyhouse = { object_type = "Joker", @@ -144,9 +115,15 @@ local happyhouse = { if card.ability.extra.check == 114 and G.GAME.round_resets.ante < 8 - and not ( - G.GAME.selected_back.effect.center.key == "antimatter" - or G.GAME.selected_back.effect.center.key == "equilibrium" + and not (G.GAME.selected_back.effect.center.key == "antimatter" or G.GAME.selected_back.effect.center.key == "equilibrium") + and ( + not CardSleeves + or ( + CardSleeves + and G.GAME.selected_sleeve + -- and G.GAME.selected_sleeve ~= "sleeve_cry_antimatter_sleeve" TODO: Add check if Antimatter sleeve gets added + and G.GAME.selected_sleeve ~= "sleeve_cry_equilibrium_sleeve" + ) ) then --Yes, the cut off point is boss blind Ante 7. I'm evil >:3. check_for_unlock({ type = "home_realtor" }) @@ -262,7 +239,7 @@ local potofjokes = { end, calculate = function(self, card, context) if context.end_of_round and not context.individual and not context.repetition and not context.blueprint then - G.hand:change_size(math.min(1000 - card.ability.extra.h_size, card.ability.extra.h_mod)) + G.hand:change_size(math.min(math.max(0, 1000 - card.ability.extra.h_size), card.ability.extra.h_mod)) card.ability.extra.h_size = card.ability.extra.h_size + card.ability.extra.h_mod return { message = localize({ type = "variable", key = "a_handsize", vars = { card.ability.extra.h_mod } }), @@ -326,7 +303,7 @@ local queensgambit = { if context.destroying_card and not context.blueprint then if G.GAME.current_round.current_hand.handname == "Royal Flush" - and SMODS.Ranks[context.destroying_card.base.value].key == "Queen" + and context.destroying_card:get_id() == 12 then card_eval_status_text( card, @@ -347,7 +324,7 @@ local queensgambit = { return true end, })) - return nil, true + return { remove = not context.destroying_card.ability.eternal } end end end, @@ -387,7 +364,7 @@ local wee_fib = { calculate = function(self, card, context) if context.cardarea == G.play and context.individual and not context.blueprint then local rank = context.other_card:get_id() - if rank == "Ace" or rank == "2" or rank == "3" or rank == "5" or rank == "8" then + if rank == 14 or rank == 2 or rank == 3 or rank == 5 or rank == 8 then card.ability.extra.mult = card.ability.extra.mult + card.ability.extra.mult_mod return { @@ -638,19 +615,21 @@ local pickle = { calculate = function(self, card, context) if context.skip_blind then for i = 1, math.min(20, card.ability.extra.tags) do - local tag = Tag(get_next_tag_key("cry_pickle")) - if tag.name == "Orbital Tag" then - local _poker_hands = {} - for k, v in pairs(G.GAME.hands) do - if v.visible then - _poker_hands[#_poker_hands + 1] = k - end - end - tag.ability.orbital_hand = pseudorandom_element(_poker_hands, pseudoseed("cry_pickle_orbital")) - end - if tag.name == "Boss Tag" then + local tag_key = get_next_tag_key("cry_pickle") + if tag_key == "tag_boss" then i = i - 1 --skip these, as they can cause bugs with pack opening from other tags else + local tag = Tag(tag_key) + if tag.name == "Orbital Tag" then + local _poker_hands = {} + for k, v in pairs(G.GAME.hands) do + if v.visible then + _poker_hands[#_poker_hands + 1] = k + end + end + tag.ability.orbital_hand = pseudorandom_element(_poker_hands, pseudoseed("cry_pickle_orbital")) + end + tag.ability.shiny = cry_rollshinybool() add_tag(tag) end end @@ -670,8 +649,8 @@ local pickle = { card_eval_status_text(card, "extra", nil, nil, nil, { message = localize({ type = "variable", - key = card.ability.extra.tags == 1 and "a_tag_minus" or "a_tags_minus", - vars = { card.ability.extra.tags }, + key = card.ability.extra.tags_mod == 1 and "a_tag_minus" or "a_tags_minus", + vars = { card.ability.extra.tags_mod }, })[1], colour = G.C.FILTER, }) @@ -711,6 +690,7 @@ local pickle = { }, art = { "Mystic Misclick", + "unexian", }, code = { "Math", @@ -795,7 +775,7 @@ local triplet_rhythm = { if context.joker_main and context.scoring_hand then local threes = 0 for i = 1, #context.scoring_hand do - if context.scoring_hand[i]:get_id() then + if context.scoring_hand[i]:get_id() == 3 then threes = threes + 1 end end @@ -840,18 +820,12 @@ local booster = { return { vars = { math.min(25, center.ability.extra.booster_slots) } } end, add_to_deck = function(self, card, from_debuff) - if not G.GAME.modifiers.cry_booster_packs then - G.GAME.modifiers.cry_booster_packs = 2 - end - G.GAME.modifiers.cry_booster_packs = G.GAME.modifiers.cry_booster_packs - + math.min(25, card.ability.extra.booster_slots) + local mod = math.min(25, card.ability.extra.booster_slots) + SMODS.change_booster_limit(mod) end, remove_from_deck = function(self, card, from_debuff) - if not G.GAME.modifiers.cry_booster_packs then - G.GAME.modifiers.cry_booster_packs = 2 - end - G.GAME.modifiers.cry_booster_packs = G.GAME.modifiers.cry_booster_packs - - math.min(25, card.ability.extra.booster_slots) + local mod = math.min(25, card.ability.extra.booster_slots) + SMODS.change_booster_limit(-mod) end, cry_credits = { idea = { @@ -945,6 +919,7 @@ local chili_pepper = { }, art = { "Mystic Misclick", + "George the Rat", }, code = { "Math", @@ -975,7 +950,7 @@ local compound_interest = { local bonus = math.max(0, math.floor(0.01 * card.ability.extra.percent * (G.GAME.dollars or 1))) local old = card.ability.extra.percent card.ability.extra.percent = card.ability.extra.percent + card.ability.extra.percent_mod - compound_interest_scale_mod(card, card.ability.extra.percent_mod, old, card.ability.extra.percent) + Cryptid.compound_interest_scale_mod(card, card.ability.extra.percent_mod, old, card.ability.extra.percent) if bonus > to_big(0) then return bonus end @@ -1194,14 +1169,14 @@ local seal_the_deal = { end, set_ability = function(self, card, initial, delay_sprites) local sealtable = { "blue", "red", "purple" } - if Cryptid.enabled["Misc."] then + if Cryptid.enabled("cry_azure") then sealtable[#sealtable + 1] = "azure" end - if Cryptid.enabled["Code Cards"] then + if Cryptid.enabled("cry_green") then sealtable[#sealtable + 1] = "green" end card.ability.extra = pseudorandom_element(sealtable, pseudoseed("abc")) - if G.P_CENTERS["j_cry_seal_the_deal"].discovered then + if self.discovered then --Gold (ULTRA RARE!!!!!!!!) if pseudorandom("xyz") <= 0.000001 and not (card.area and card.area.config.collection) then card.children.center:set_sprite_pos({ x = 6, y = 4 }) @@ -1320,7 +1295,7 @@ local jimball = { end, add_to_deck = function(self, card, from_debuff) if not from_debuff then - create_cryptid_notif_overlay("jimball") + Cryptid.notification_overlay("jimball") end end, atlas = "jimball", @@ -1394,7 +1369,7 @@ local sus = { local function is_impostor(card) return card.base.value and SMODS.Ranks[card.base.value].key == "King" and card:is_suit("Hearts") end - if context.end_of_round and context.cardarea == G.jokers then + if context.end_of_round and context.cardarea == G.jokers and not context.blueprint and not context.retrigger_joker then if not card.ability.used_round or card.ability.used_round ~= G.GAME.round then card.ability.chosen_card = nil end @@ -1477,6 +1452,7 @@ local sus = { }, art = { "Jevonn", + "unexian", }, code = { "Math", @@ -1498,11 +1474,10 @@ local fspinner = { return { vars = { center.ability.extra.chips, center.ability.extra.chip_mod } } end, rarity = 1, - cost = 6, + cost = 5, order = 77, blueprint_compat = true, perishable_compat = false, - atlas = "fspinner", 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) @@ -1530,6 +1505,7 @@ local fspinner = { }, art = { "Jevonn", + "George the Rat", }, code = { "Jevonn", @@ -1755,17 +1731,20 @@ local gardenfork = { return { vars = { center.ability.extra.money } } end, calculate = function(self, card, context) - if context.cardarea == G.jokers and context.before and not context.blueprint then + if context.cardarea == G.jokers and context.before and context.full_hand then + local has_ace = false + local has_7 = false for i = 1, #context.full_hand do - if context.other_card:get_id() == 14 then - for j = 1, #context.full_hand do - if context.other_card:get_id() == 7 then -- :( ekshpenshive - ease_dollars(card.ability.extra.money) - return { message = "$" .. card.ability.extra.money, colour = G.C.MONEY } - end - end + if context.full_hand[i]:get_id() == 14 then + has_ace = true + elseif context.full_hand[i]:get_id() == 7 then + has_7 = true end end + if has_ace and has_7 then + ease_dollars(card.ability.extra.money) + return { message = "$" .. card.ability.extra.money, colour = G.C.MONEY } + end end end, cry_credits = { @@ -1933,6 +1912,10 @@ local hunger = { name = "cry-hunger", key = "hunger", config = { extra = { money = 3 } }, + extra_gamesets = { "exp_modest" }, + gameset_config = { + exp_modest = { extra = { money = 2 } }, + }, pos = { x = 3, y = 0 }, rarity = 2, cost = 6, @@ -2071,7 +2054,7 @@ local redbloon = { "Roguefort Cookie", }, art = { - "Jevonn", + "Darren_The_Frog", }, code = { "Jevonn", @@ -2557,7 +2540,7 @@ local sapling = { }, name = "cry-sapling", key = "sapling", - pos = { x = 3, y = 2 }, + pos = { x = 3, y = 2 }, --todo animations config = { extra = { score = 0, req = 18, check = nil } }, rarity = 2, cost = 6, @@ -2569,8 +2552,9 @@ local sapling = { vars = { center.ability.extra.score, center.ability.extra.req, - cry_card_enabled("set_cry_epic") == true and localize("k_cry_epic") or localize("k_rare"), - colours = { G.C.RARITY[cry_card_enabled("set_cry_epic") == true and "cry_epic" or 3] }, + Cryptid.enabled("set_cry_epic") == true and localize("k_cry_epic") or localize("k_rare"), + colours = { G.C.RARITY[Cryptid.enabled("set_cry_epic") == true and "cry_epic" or 3] }, + Cryptid.enabled("set_cry_epic") == true and localize("cry_sapling_an") or localize("cry_sapling_a"), }, } end, @@ -2594,7 +2578,7 @@ local sapling = { end elseif context.selling_self and not context.blueprint and not context.retrigger_joker then if card.ability.extra.score >= card.ability.extra.req then - local value = cry_card_enabled("set_cry_epic") == true and "cry_epic" or 0.99 + local value = Cryptid.enabled("set_cry_epic") == true and "cry_epic" or 0.99 card_eval_status_text( card, "extra", @@ -2626,6 +2610,7 @@ local sapling = { }, art = { "Jevonn", + "George the Rat", }, code = { "Jevonn", @@ -2707,7 +2692,7 @@ local spaceglobe = { "Jevonn", }, art = { - "Jevonn", + "Selicre", }, code = { "Jevonn", @@ -3089,7 +3074,7 @@ local rnjoker = { blueprint_compat = true, set_ability = function(self, card, initial, delay_sprites) card.ability.abilities = {} - rnjoker_randomize(card) + Cryptid.rnjoker_randomize(card) end, calculate = function(self, card, context) if card.ability and card.ability.abilities then @@ -3746,7 +3731,7 @@ local rnjoker = { end end G.hand:change_size(-hand_size) - rnjoker_randomize(card) + Cryptid.rnjoker_randomize(card) return { message = localize("k_reset"), colour = G.C.RED, @@ -3818,7 +3803,7 @@ local rnjoker = { } localize(target) else - localalize_with_direct(new_loc, target) + Cryptid.direct_localize(new_loc, target) end end, calc_dollar_bonus = function(self, card) @@ -3845,7 +3830,7 @@ local rnjoker = { }, }, init = function(self) - function rnjoker_randomize(card) + function Cryptid.rnjoker_randomize(card) card.ability.abilities = {} card.ability.extra = {} card.ability.extra.value = {} @@ -4214,7 +4199,7 @@ local rnjoker = { values.text_parsed = text_parsed card.ability.abilities = { values } end - function localalize_with_direct(loc_target, args, misc_cat) + function Cryptid.direct_localize(loc_target, args, misc_cat) if loc_target then for _, lines in ipairs( @@ -4361,7 +4346,7 @@ local duos = { calculate = function(self, card, context) if context.joker_main and (to_big(card.ability.x_mult) > to_big(1)) then if - context.poker_hands ~= nil and next(context.poker_hands["Two Pair"]) + context.poker_hands ~= nil and next(context.poker_hands[card.ability.type]) or context.poker_hands ~= nil and next(context.poker_hands["Full House"]) then return { @@ -4407,7 +4392,7 @@ local home = { blueprint_compat = true, calculate = function(self, card, context) if context.joker_main and (to_big(card.ability.x_mult) > to_big(1)) then - if context.poker_hands ~= nil and next(context.poker_hands["Full House"]) then + if context.poker_hands ~= nil and next(context.poker_hands[card.ability.type]) then return { message = localize({ type = "variable", key = "a_xmult", vars = { card.ability.x_mult } }), colour = G.C.RED, @@ -4451,7 +4436,7 @@ local nuts = { blueprint_compat = true, calculate = function(self, card, context) if context.joker_main and (to_big(card.ability.x_mult) > to_big(1)) then - if context.poker_hands ~= nil and next(context.poker_hands["Straight Flush"]) then + if context.poker_hands ~= nil and next(context.poker_hands[card.ability.type]) then return { message = localize({ type = "variable", key = "a_xmult", vars = { card.ability.x_mult } }), colour = G.C.RED, @@ -4495,7 +4480,7 @@ local quintet = { blueprint_compat = true, calculate = function(self, card, context) if context.joker_main and (to_big(card.ability.x_mult) > to_big(1)) then - if context.poker_hands ~= nil and next(context.poker_hands["Five of a Kind"]) then + if context.poker_hands ~= nil and next(context.poker_hands[card.ability.type]) then return { message = localize({ type = "variable", key = "a_xmult", vars = { card.ability.x_mult } }), colour = G.C.RED, @@ -4511,7 +4496,7 @@ local quintet = { return false end, check_for_unlock = function(self, args) - if args.type == "cry_win_with_hand" and args.hand == "Five of a Kind" then + if args.type == "win" and G.GAME.last_hand_played == "Five of a Kind" then return true end end, @@ -4549,7 +4534,7 @@ local unity = { blueprint_compat = true, calculate = function(self, card, context) if context.joker_main and (to_big(card.ability.x_mult) > to_big(1)) then - if context.poker_hands ~= nil and next(context.poker_hands["Flush House"]) then + if context.poker_hands ~= nil and next(context.poker_hands[card.ability.type]) then return { message = localize({ type = "variable", key = "a_xmult", vars = { card.ability.x_mult } }), colour = G.C.RED, @@ -4565,7 +4550,7 @@ local unity = { return false end, check_for_unlock = function(self, args) - if args.type == "cry_win_with_hand" and args.hand == "Flush House" then + if args.type == "win" and G.GAME.last_hand_played == "Flush House" then return true end end, @@ -4603,7 +4588,7 @@ local swarm = { blueprint_compat = true, calculate = function(self, card, context) if context.joker_main and (to_big(card.ability.x_mult) > to_big(1)) then - if context.poker_hands ~= nil and next(context.poker_hands["Flush Five"]) then + if context.poker_hands ~= nil and next(context.poker_hands[card.ability.type]) then return { message = localize({ type = "variable", key = "a_xmult", vars = { card.ability.x_mult } }), colour = G.C.RED, @@ -4619,7 +4604,7 @@ local swarm = { return false end, check_for_unlock = function(self, args) - if args.type == "cry_win_with_hand" and args.hand == "Flush Five" then + if args.type == "win" and G.GAME.last_hand_played == "Flush Five" then return true end end, @@ -4659,7 +4644,7 @@ local stronghold = { blueprint_compat = true, calculate = function(self, card, context) if context.joker_main and (to_big(card.ability.x_mult) > to_big(1)) then - if context.poker_hands ~= nil and next(context.poker_hands["cry_Bulwark"]) then + if context.poker_hands ~= nil and next(context.poker_hands[card.ability.type]) then return { message = localize({ type = "variable", key = "a_xmult", vars = { card.ability.x_mult } }), colour = G.C.RED, @@ -4675,7 +4660,7 @@ local stronghold = { return false end, check_for_unlock = function(self, args) - if args.type == "cry_win_with_hand" and args.hand == "cry_Bulwark" then + if args.type == "win" and G.GAME.last_hand_played == "cry_Bulwark" then return true end end, @@ -4704,7 +4689,7 @@ local wtf = { blueprint_compat = true, calculate = function(self, card, context) if context.joker_main and (to_big(card.ability.x_mult) > to_big(1)) then - if context.poker_hands ~= nil and next(context.poker_hands["cry_Clusterfuck"]) then + if context.poker_hands ~= nil and next(context.poker_hands[card.ability.type]) then return { message = localize({ type = "variable", key = "a_xmult", vars = { card.ability.x_mult } }), colour = G.C.RED, @@ -4720,7 +4705,7 @@ local wtf = { return false end, check_for_unlock = function(self, args) - if args.type == "cry_win_with_hand" and args.hand == "cry_Clusterfuck" then + if args.type == "win" and G.GAME.last_hand_played == "cry_Clusterfuck" then return true end end, @@ -4749,7 +4734,7 @@ local clash = { blueprint_compat = true, calculate = function(self, card, context) if context.joker_main and (to_big(card.ability.x_mult) > to_big(1)) then - if context.poker_hands ~= nil and next(context.poker_hands["cry_UltPair"]) then + if context.poker_hands ~= nil and next(context.poker_hands[card.ability.type]) then return { message = localize({ type = "variable", key = "a_xmult", vars = { card.ability.x_mult } }), colour = G.C.RED, @@ -4765,7 +4750,7 @@ local clash = { return false end, check_for_unlock = function(self, args) - if args.type == "cry_win_with_hand" and args.hand == "cry_UltPair" then + if args.type == "win" and G.GAME.last_hand_played == "cry_UltPair" then return true end end, @@ -4792,7 +4777,7 @@ local filler = { cost = 1, blueprint_compat = true, calculate = function(self, card, context) - if context.joker_main and context.poker_hands and next(context.poker_hands["High Card"]) then + if context.joker_main and context.poker_hands and next(context.poker_hands[card.ability.type]) then return { message = localize({ type = "variable", key = "a_xmult", vars = { card.ability.x_mult } }), colour = G.C.RED, @@ -5692,6 +5677,7 @@ local coin = { }, art = { "Timetoexplode", + "George the Rat", }, code = { "Jevonn", @@ -5923,6 +5909,7 @@ local oldblueprint = { }, art = { "Linus Goof Balls", + "unexian", }, code = { "Math", @@ -6202,17 +6189,17 @@ local membershipcard = { blueprint_compat = true, atlas = "atlasthree", loc_vars = function(self, info_queue, card) - return { vars = { card.ability.extra.Xmult_mod, card.ability.extra.Xmult_mod * GLOBAL_cry_member_count } } + return { vars = { card.ability.extra.Xmult_mod, card.ability.extra.Xmult_mod * Cryptid.member_count } } end, calculate = function(self, card, context) - if context.joker_main and card.ability.extra.Xmult_mod * GLOBAL_cry_member_count > 1 then + if context.joker_main and card.ability.extra.Xmult_mod * Cryptid.member_count > 1 then return { message = localize({ type = "variable", key = "a_xmult", - vars = { card.ability.extra.Xmult_mod * GLOBAL_cry_member_count }, + vars = { card.ability.extra.Xmult_mod * Cryptid.member_count }, }), - Xmult_mod = card.ability.extra.Xmult_mod * GLOBAL_cry_member_count, + Xmult_mod = card.ability.extra.Xmult_mod * Cryptid.member_count, } end end, @@ -6610,6 +6597,7 @@ local astral_bottle = { }, }, name = "cry-astral_bottle", + extra_gamesets = { "exp_modest", "exp_mainline", "exp_madness" }, key = "astral_bottle", eternal_compat = false, pos = { x = 7, y = 0 }, @@ -6622,21 +6610,47 @@ local astral_bottle = { if not center.edition or (center.edition and not center.edition.cry_astral) then info_queue[#info_queue + 1] = G.P_CENTERS.e_cry_astral end + return { + key = Cryptid.gameset_loc( + self, + { exp_modest = "mainline", exp_mainline = "mainline", exp_madness = "madness" } + ), + } end, calculate = function(self, card, context) if context.selling_self and not context.retrigger_joker and not context.blueprint then + local g = Cryptid.gameset(card) + local effect = { { astral = true, perishable = true } } + if g == "exp_modest" or g == "exp_mainline" then + effect = { { astral = true }, { perishable = true } } + end + if g == "exp_madness" then + effect = { { astral = true } } + end local jokers = {} for i = 1, #G.jokers.cards do if G.jokers.cards[i] ~= card and not G.jokers.cards[i].debuff and not G.jokers.cards[i].edition then jokers[#jokers + 1] = G.jokers.cards[i] end end - if #jokers > 0 then + if #jokers >= #effect then card_eval_status_text(card, "extra", nil, nil, nil, { message = localize("k_duplicated_ex") }) - local chosen_joker = pseudorandom_element(jokers, pseudoseed("trans")) - chosen_joker:set_edition({ cry_astral = true }) - chosen_joker.ability.perishable = true -- Done manually to bypass perish compat - chosen_joker.ability.perish_tally = G.GAME.perishable_rounds + for i = 1, #effect do + local chosen_joker = pseudorandom_element(jokers, pseudoseed("astral_bottle")) + if effect[i].astral then + chosen_joker:set_edition({ cry_astral = true }) + end + if effect[i].perishable then + chosen_joker.ability.perishable = true -- Done manually to bypass perish compat + chosen_joker.ability.perish_tally = G.GAME.perishable_rounds + end + for i = 1, #jokers do + if jokers[i] == chosen_joker then + table.remove(jokers, i) + break + end + end + end return nil, true else card_eval_status_text(card, "extra", nil, nil, nil, { message = localize("k_no_other_jokers") }) @@ -6644,6 +6658,38 @@ local astral_bottle = { end end, } +local kittyprinter = { + dependencies = { + items = { + "tag_cry_cat", + }, + }, + object_type = "Joker", + name = "cry-kittyprinter", + key = "kittyprinter", + config = { extra = { Xmult = 2 } }, + pos = { x = 3, y = 5 }, + rarity = 2, + cost = 6, + atlas = "atlasone", + order = 133, + blueprint_compat = true, + loc_vars = function(self, info_queue, card) + return { vars = { card.ability.extra.Xmult } } + end, + calculate = function(self, card, context) + if context.joker_main then + return { + message = localize({ + type = "variable", + key = "a_xmult", + vars = { card.ability.extra.Xmult }, + }), + Xmult_mod = card.ability.extra.Xmult, + } + end + end, +} local kidnap = { object_type = "Joker", dependencies = { @@ -6732,7 +6778,7 @@ local exposed = { atlas = "atlastwo", blueprint_compat = true, loc_vars = function(self, info_queue, center) - return { vars = { center.ability.extra } } + return { vars = { math.min(40, center.ability.extra) } } end, update = function(self, card, dt) if G.deck and card.added_to_deck then @@ -6779,7 +6825,7 @@ local mask = { order = 124, blueprint_compat = true, loc_vars = function(self, info_queue, center) - return { vars = { center.ability.extra } } + return { vars = { math.min(40, center.ability.extra) } } end, update = function(self, card, dt) if G.deck and card.added_to_deck then @@ -6834,8 +6880,13 @@ local tropical_smoothie = { for i, v in pairs(G.jokers.cards) do if v ~= card then if not Card.no(v, "immutable", true) then - cry_with_deck_effects(v, function(cards) - cry_misprintize(cards, { min = card.ability.extra, max = card.ability.extra }, nil, true) + Cryptid.with_deck_effects(v, function(cards) + Cryptid.misprintize( + cards, + { min = card.ability.extra, max = card.ability.extra }, + nil, + true + ) end) check = true end @@ -6983,7 +7034,7 @@ local cookie = { cost = 4, atlas = "atlastwo", order = 133, - config = { extra = { chips = 150, chip_mod = 1 } }, + config = { extra = { chips = 200, chip_mod = 1 } }, blueprint_compat = true, eternal_compat = false, perishable_compat = false, @@ -7080,6 +7131,7 @@ local necromancer = { and context.card.sell_cost > 0 and context.card.config.center.set == "Joker" and G.GAME.jokers_sold + and #G.GAME.jokers_sold > 0 then local card = create_card( "Joker", @@ -7182,8 +7234,8 @@ local oil_lamp = { --You want it? It's yours my friend if i < #G.jokers.cards then if not Card.no(G.jokers.cards[i + 1], "immutable", true) then check = true - cry_with_deck_effects(G.jokers.cards[i + 1], function(cards) - cry_misprintize( + Cryptid.with_deck_effects(G.jokers.cards[i + 1], function(cards) + Cryptid.misprintize( cards, { min = card.ability.extra.increase, max = card.ability.extra.increase }, nil, @@ -7243,8 +7295,8 @@ local tax_fraud = { return { vars = { center.ability.extra.money } } end, calc_dollar_bonus = function(self, card) - if #advanced_find_joker(nil, nil, nil, { "rental" }, true) ~= 0 then - return card.ability.extra.money * #advanced_find_joker(nil, nil, nil, { "rental" }, true) + if #Cryptid.advanced_find_joker(nil, nil, nil, { "rental" }, true) ~= 0 then + return card.ability.extra.money * #Cryptid.advanced_find_joker(nil, nil, nil, { "rental" }, true) end end, cry_credits = { @@ -7280,10 +7332,13 @@ local pity_prize = { end, calculate = function(self, card, context) if context.skipping_booster then - local tag + local tag_key repeat - tag = Tag(get_next_tag_key("cry_pity_prize")) - until tag.name ~= "Boss Tag" and tag.name ~= "Gambler's Tag" and tag.name ~= "Empowered Tag" + 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 + -- this is my first time seeing repeat... wtf + local tag = Tag(tag_key) + tag.ability.shiny = cry_rollshinybool() if tag.name == "Orbital Tag" then local _poker_hands = {} for k, v in pairs(G.GAME.hands) do @@ -7373,6 +7428,27 @@ local digitalhallucinations = { ) then local boosty = context.card + -- finally mod compat? + if boosty.config.center.cry_digital_hallucinations then + local conf = boosty.config.center.cry_digital_hallucinations + G.E_MANAGER:add_event(Event({ + trigger = "before", + delay = 0.0, + func = function() + conf.create() + return true + end, + })) + card_eval_status_text( + context.blueprint_card or card, + "extra", + nil, + nil, + nil, + { message = localize(conf.loc_key), colour = conf.colour } + ) + return nil, true + end local consums = { "Arcana", "Celestial", "Spectral" } local short1 = { "tarot", "planet", "spectral" } local short2 = { "Tarot", "Planet", "Spectral" } @@ -7382,7 +7458,7 @@ local digitalhallucinations = { trigger = "before", delay = 0.0, func = function() - local ccard = create_card(short2[i], G.consumables, nil, nil, nil, nil, nil, "diha") + local ccard = create_card(short2[i], G.consumeables, nil, nil, nil, nil, nil, "diha") ccard:set_edition({ negative = true }, true) ccard:add_to_deck() G.consumeables:emplace(ccard) @@ -7400,34 +7476,21 @@ local digitalhallucinations = { return nil, true -- this triggers BEFORE a retrigger joker and looks like jank. i can't get a message showing up without status text so this is the best option rn end end - if boosty.ability.name:find("code") then - G.E_MANAGER:add_event(Event({ - trigger = "before", - delay = 0.0, - func = function() - local ccard = create_card("Code", G.consumables, nil, nil, nil, nil, nil, "diha") - ccard:set_edition({ negative = true }, true) - ccard:add_to_deck() - G.consumeables:emplace(ccard) - return true - end, - })) - card_eval_status_text( - context.blueprint_card or card, - "extra", - nil, - nil, - nil, - { message = localize("cry_plus_code"), colour = G.C.SET.Code } - ) - return nil, true - end if boosty.ability.name:find("Buffoon") then G.E_MANAGER:add_event(Event({ trigger = "before", delay = 0.0, func = function() - local ccard = create_card("Joker", G.jokers, nil, nil, nil, nil, nil, "diha") + local ccard = create_card( + boosty.ability.name:find("meme") and "Meme" or "Joker", + G.jokers, + nil, + nil, + nil, + nil, + nil, + "diha" + ) -- who up wasting their cycles rn ccard:set_edition({ negative = true }, true) ccard:add_to_deck() G.jokers:emplace(ccard) @@ -7462,6 +7525,7 @@ local digitalhallucinations = { ccard:set_edition({ negative = true }, true) ccard:start_materialize({ G.C.SECONDARY_SET.Enhanced }) G.play:emplace(ccard) + playing_card_joker_effects({ ccard }) -- odd timing table.insert(G.playing_cards, ccard) return true end, @@ -7482,8 +7546,6 @@ local digitalhallucinations = { end, })) draw_card(G.play, G.deck, 90, "up", nil) - - playing_card_joker_effects({ true }) -- who knows what most this stuff does, i just copied it from marble jonkler return nil, true end end @@ -7522,7 +7584,7 @@ local arsonist = { if context.destroying_card then local eval = evaluate_poker_hand(context.full_hand) if next(eval["Full House"]) then - return true + return not context.destroying_card.ability.eternal end end end, @@ -7531,7 +7593,7 @@ local arsonist = { "AlexZGreat", }, art = { - "Darren_the_frog", + "Darren_The_Frog", }, code = { "AlexZGreat", @@ -7600,6 +7662,115 @@ local zooble = { }, }, } +local lebaron_james = { + object_type = "Joker", + dependencies = { + items = { + "set_cry_misc_joker", + }, + }, + name = "cry-LeBaron James", + pools = { ["Meme"] = true }, + key = "lebaron_james", + pos = { x = 2, y = 5 }, + config = { extra = { h_mod = 1 } }, + rarity = 3, + cost = 6, + atlas = "atlasone", + order = 133, + no_dbl = true, + immutable = true, -- has issues with value manip and not easy to fix + loc_vars = function(self, info_queue, center) + return { vars = { center.ability.extra.h_mod } } + end, + calculate = function(self, card, context) + if context.cardarea == G.play and context.individual then + if context.other_card:get_id() == 13 then + local h_size = math.max(0, math.min(1000 - 0, card.ability.extra.h_mod)) + G.hand:change_size(math.floor(h_size)) + G.GAME.round_resets.temp_handsize = (G.GAME.round_resets.temp_handsize or 0) + math.floor(h_size) + if math.floor(h_size) > 0 then + return { + message = localize({ type = "variable", key = "a_handsize", vars = { math.floor(h_size) } }), + colour = G.C.FILTER, + card = card, + } + end + end + end + end, + cry_credits = { + idea = { + "indefenite_idiot", + "HexaCryonic", + }, + code = { + "AlexZGreat", + }, + art = { + "lamborghiniofficial", + }, + }, + init = function(self) + -- Calculate enhancements for kings as if held in hand + -- Note that for enhancements that work when played and held in hand, this will fail + -- Not tested since no enhancements use this yet (Steel is weird, and Gold won't work) + local cce = Card.calculate_enhancement + function Card:calculate_enhancement(context) + local ret = cce(self, context) + if + not ret + and next(SMODS.find_card("j_cry_lebaron_james")) + and SMODS.Ranks[self.base.value].key == "King" + and context.cardarea == G.play + then + context.cardarea = G.hand + local ret = cce(self, context) + context.cardarea = G.play + end + return ret + end + end, +} +local huntingseason = { -- If played hand contains three cards, destroy the middle card after scoring + object_type = "Joker", + dependencies = { + items = { + "set_cry_misc_joker", + }, + }, + name = "cry-huntingseason", + key = "huntingseason", + pos = { x = 4, y = 5 }, + order = 134, + immutable = true, + rarity = 2, + cost = 7, + blueprint_compat = false, + atlas = "atlasone", + calculate = function(self, card, context) + if + (context.cardarea == G.play or context.cardarea == "unscored") + and context.destroy_card == context.full_hand[2] + and #context.full_hand == 3 -- 3 cards in played hand + and not context.blueprint + and not context.retrigger_joker + then + return { remove = not context.destroy_card.ability.eternal } + end + end, + cry_credits = { + art = { + "Unexian", + }, + idea = { + "Nova", + }, + code = { + "Nova", + }, + }, +} local miscitems = { jimball_sprite, dropshot, @@ -7683,6 +7854,7 @@ local miscitems = { savvy, subtle, discreet, + kittyprinter, kidnap, exposed, mask, @@ -7710,6 +7882,8 @@ local miscitems = { fuckedup, foolhardy, translucent, + lebaron_james, + huntingseason, } return { name = "Misc. Jokers", diff --git a/Cryptid/items/planet.lua b/Cryptid/items/planet.lua index 3a2121a..d712ed6 100644 --- a/Cryptid/items/planet.lua +++ b/Cryptid/items/planet.lua @@ -1,4 +1,15 @@ local timantti = { + cry_credits = { + idea = { + "Jevonn", + }, + art = { + "jenwalter666", + }, + code = { + "Math", + }, + }, dependencies = { items = { "set_cry_planet", @@ -48,10 +59,10 @@ local timantti = { } end, use = function(self, card, area, copier) - suit_level_up(self, card, area, copier) + Cryptid.suit_level_up(self, card, area, copier) end, bulk_use = function(self, card, area, copier, number) - suit_level_up(self, card, area, copier, number) + Cryptid.suit_level_up(self, card, area, copier, number) end, calculate = function(self, card, context) if @@ -72,6 +83,17 @@ local timantti = { end, } local klubi = { + cry_credits = { + idea = { + "Jevonn", + }, + art = { + "jenwalter666", + }, + code = { + "Math", + }, + }, dependencies = { items = { "set_cry_planet", @@ -121,10 +143,10 @@ local klubi = { } end, use = function(self, card, area, copier) - suit_level_up(self, card, area, copier) + Cryptid.suit_level_up(self, card, area, copier) end, bulk_use = function(self, card, area, copier, number) - suit_level_up(self, card, area, copier, number) + Cryptid.suit_level_up(self, card, area, copier, number) end, calculate = function(self, card, context) if @@ -145,6 +167,17 @@ local klubi = { end, } local sydan = { + cry_credits = { + idea = { + "Jevonn", + }, + art = { + "jenwalter666", + }, + code = { + "Math", + }, + }, dependencies = { items = { "set_cry_planet", @@ -194,10 +227,10 @@ local sydan = { } end, use = function(self, card, area, copier) - suit_level_up(self, card, area, copier) + Cryptid.suit_level_up(self, card, area, copier) end, bulk_use = function(self, card, area, copier, number) - suit_level_up(self, card, area, copier, number) + Cryptid.suit_level_up(self, card, area, copier, number) end, calculate = function(self, card, context) if @@ -218,6 +251,17 @@ local sydan = { end, } local lapio = { + cry_credits = { + idea = { + "Jevonn", + }, + art = { + "jenwalter666", + }, + code = { + "Math", + }, + }, dependencies = { items = { "set_cry_planet", @@ -267,10 +311,10 @@ local lapio = { } end, use = function(self, card, area, copier) - suit_level_up(self, card, area, copier) + Cryptid.suit_level_up(self, card, area, copier) end, bulk_use = function(self, card, area, copier, number) - suit_level_up(self, card, area, copier, number) + Cryptid.suit_level_up(self, card, area, copier, number) end, calculate = function(self, card, context) if @@ -291,6 +335,17 @@ local lapio = { end, } local kaikki = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "HexaCryonic", + }, + }, dependencies = { items = { "set_cry_planet", @@ -341,10 +396,10 @@ local kaikki = { } end, use = function(self, card, area, copier) - suit_level_up(self, card, area, copier) + Cryptid.suit_level_up(self, card, area, copier) end, bulk_use = function(self, card, area, copier, number) - suit_level_up(self, card, area, copier, number) + Cryptid.suit_level_up(self, card, area, copier, number) end, calculate = function(self, card, context) if @@ -365,6 +420,17 @@ local kaikki = { end, } local planetlua = { + cry_credits = { + idea = { + "Jevonn", + }, + art = { + "Jevonn", + }, + code = { + "Jevonn", + }, + }, dependencies = { items = { "set_cry_planet", @@ -659,6 +725,17 @@ local planetlua = { end, } local nstar = { + cry_credits = { + idea = { + "Jevonn", + }, + art = { + "Jevonn", + }, + code = { + "Jevonn", + }, + }, dependencies = { items = { "set_cry_planet", @@ -689,7 +766,7 @@ local nstar = { --Add +1 to amount of neutron stars used this run G.GAME.neutronstarsusedinthisrun = G.GAME.neutronstarsusedinthisrun + 1 - local neutronhand = neutronstarrandomhand() --Random poker hand + local neutronhand = Cryptid.get_random_hand() --Random poker hand update_hand_text({ sound = "button", volume = 0.7, pitch = 0.8, delay = 0.3 }, { handname = localize(neutronhand, "poker_hands"), chips = G.GAME.hands[neutronhand].chips, @@ -711,7 +788,7 @@ local nstar = { local neutronhand = "n/a" for i = 1, number do G.GAME.neutronstarsusedinthisrun = G.GAME.neutronstarsusedinthisrun + 1 - neutronhand = neutronstarrandomhand() + neutronhand = Cryptid.get_random_hand() handstolv[neutronhand] = (handstolv[neutronhand] or 0) + G.GAME.neutronstarsusedinthisrun end for k, v in pairs(handstolv) do @@ -756,7 +833,7 @@ local nstar = { end end, init = function(self) - function neutronstarrandomhand(ignore, seed, allowhidden) + function Cryptid.get_random_hand(ignore, seed, allowhidden) --From JenLib's get_random_hand local chosen_hand ignore = ignore or {} @@ -783,6 +860,18 @@ local nstar = { end, } local sunplanet = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "Jevonn", + "Toneblock", + }, + }, --TODO: disable ascendant hands if this is disabled dependencies = { items = { @@ -821,7 +910,7 @@ local sunplanet = { 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) - cry_pulse_flame(0.01, sunlevel) + Cryptid.pulse_flame(0.01, sunlevel) used_consumable:juice_up(0.8, 0.5) G.E_MANAGER:add_event(Event({ trigger = "after", @@ -861,7 +950,7 @@ local sunplanet = { 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) - cry_pulse_flame(0.01, (sunlevel - 1) + number) + Cryptid.pulse_flame(0.01, (sunlevel - 1) + number) used_consumable:juice_up(0.8, 0.5) G.E_MANAGER:add_event(Event({ trigger = "after", @@ -920,6 +1009,17 @@ local sunplanet = { end, } local abelt = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "HexaCryonic", + }, + }, dependencies = { items = { "set_cry_poker_hand_stuff", @@ -955,6 +1055,17 @@ local abelt = { generate_ui = 0, } local void = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "HexaCryonic", + }, + }, dependencies = { items = { "set_cry_poker_hand_stuff", @@ -990,6 +1101,17 @@ local void = { generate_ui = 0, } local marsmoons = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "HexaCryonic", + }, + }, dependencies = { items = { "set_cry_poker_hand_stuff", @@ -1025,6 +1147,17 @@ local marsmoons = { generate_ui = 0, } local universe = { + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "HexaCryonic", + }, + }, dependencies = { items = { "set_cry_poker_hand_stuff", @@ -1059,7 +1192,7 @@ local universe = { end, generate_ui = 0, } -function suit_level_up(center, card, area, copier, number) +function Cryptid.suit_level_up(center, card, area, copier, number) local used_consumable = copier or card if not number then number = 1 diff --git a/Cryptid/items/sleeve.lua b/Cryptid/items/sleeve.lua index af4e302..1350726 100644 --- a/Cryptid/items/sleeve.lua +++ b/Cryptid/items/sleeve.lua @@ -1,51 +1,47 @@ if CardSleeves then - local encodedsleeve = CardSleeves.Sleeve({ - key = "encoded_sleeve", - name = "Encoded Sleeve", + local veryfairsleeve = CardSleeves.Sleeve({ + key = "very_fair_sleeve", + name = "Very Fair Sleeve", atlas = "atlasSleeves", - pos = { x = 1, y = 0 }, - config = {}, + pos = { x = 0, y = 2 }, + config = { hands = -2, discards = -2 }, unlocked = true, - unlock_condition = { deck = "Encoded Deck", stake = 1 }, + unlock_condition = { deck = "Very Fair Deck", stake = 1 }, loc_vars = function(self) return { vars = {} } end, - trigger_effect = function(self, args) end, apply = function(self) - G.E_MANAGER:add_event(Event({ - func = function() - if G.jokers then - -- Adding a before spawning becuase jen banned copy_paste - if - G.P_CENTERS["j_cry_CodeJoker"] - and (G.GAME.banned_keys and not G.GAME.banned_keys["j_cry_CodeJoker"]) - then - local card = create_card("Joker", G.jokers, nil, nil, nil, nil, "j_cry_CodeJoker") - card:add_to_deck() - card:start_materialize() - G.jokers:emplace(card) - end - if - G.P_CENTERS["j_cry_copypaste"] - and (G.GAME.banned_keys and not G.GAME.banned_keys["j_cry_copypaste"]) - then - local card = create_card("Joker", G.jokers, nil, nil, nil, nil, "j_cry_copypaste") - card:add_to_deck() - card:start_materialize() - G.jokers:emplace(card) - end - return true - end - end, - })) + G.GAME.starting_params.hands = G.GAME.starting_params.hands + self.config.hands + G.GAME.starting_params.discards = G.GAME.starting_params.discards + self.config.discards + G.GAME.modifiers.cry_no_vouchers = true + end, + init = function(self) + very_fair_quip = {} + local avts = SMODS.add_voucher_to_shop + function SMODS.add_voucher_to_shop(...) + if G.GAME.modifiers.cry_no_vouchers then + return + end + return avts(...) + end + end, + }) - --DOWNSIDE: - - G.GAME.joker_rate = 0 - G.GAME.planet_rate = 0 - G.GAME.tarot_rate = 0 - G.GAME.code_rate = 1e100 + local infinitesleeve = CardSleeves.Sleeve({ + key = "infinite_sleeve", + name = "Unlimited Sleeve", + atlas = "atlasSleeves", + pos = { x = 4, y = 0 }, + config = { cry_highlight_limit = 1e20, hand_size = 1 }, + unlocked = true, + unlock_condition = { deck = "Infinite Deck", stake = 1 }, + loc_vars = function(self) + return { vars = {} } + end, + trigger_effect = function(self, args) end, + apply = function(self) + G.GAME.modifiers.cry_highlight_limit = self.config.cry_highlight_limit end, }) @@ -85,40 +81,6 @@ if CardSleeves then end, }) - local infinitesleeve = CardSleeves.Sleeve({ - key = "infinite_sleeve", - name = "Unlimited Sleeve", - atlas = "atlasSleeves", - pos = { x = 4, y = 0 }, - config = { cry_highlight_limit = 1e20, hand_size = 1 }, - unlocked = true, - unlock_condition = { deck = "Infinite Deck", stake = 1 }, - loc_vars = function(self) - return { vars = {} } - end, - trigger_effect = function(self, args) end, - apply = function(self) - G.GAME.modifiers.cry_highlight_limit = self.config.cry_highlight_limit - end, - }) - - local conveyorsleeve = CardSleeves.Sleeve({ - key = "conveyor_sleeve", - name = "Conveyor Sleeve", - atlas = "atlasSleeves", - pos = { x = 5, y = 0 }, - config = { cry_conveyor = true }, - unlocked = true, - unlock_condition = { deck = "Conveyor Deck", stake = 1 }, - loc_vars = function(self) - return { vars = {} } - end, - trigger_effect = function(self, args) end, - apply = function(self) - G.GAME.modifiers.cry_conveyor = true - end, - }) - local CCDsleeve = CardSleeves.Sleeve({ key = "ccd_sleeve", name = "CCD Sleeve", @@ -166,6 +128,23 @@ if CardSleeves then end, }) + local conveyorsleeve = CardSleeves.Sleeve({ + key = "conveyor_sleeve", + name = "Conveyor Sleeve", + atlas = "atlasSleeves", + pos = { x = 5, y = 0 }, + config = { cry_conveyor = true }, + unlocked = true, + unlock_condition = { deck = "Conveyor Deck", stake = 1 }, + loc_vars = function(self) + return { vars = {} } + end, + trigger_effect = function(self, args) end, + apply = function(self) + G.GAME.modifiers.cry_conveyor = true + end, + }) + local redeemedsleeve = CardSleeves.Sleeve({ key = "redeemed_sleeve", name = "Redeemed Sleeve", @@ -182,6 +161,30 @@ if CardSleeves then end, }) + local glowingsleeve = CardSleeves.Sleeve({ + key = "glowing_sleeve", + name = "Glowing Sleeve", + atlas = "atlasSleeves", + pos = { x = 0, y = 2 }, + config = { cry_glowing = true }, + unlocked = true, + unlock_condition = { deck = "Glowing Deck", stake = 1 }, + loc_vars = function(self) + return { vars = { " " } } + end, + calculate = function(self, back, context) + if context.context == "eval" and Cryptid.safe_get(G.GAME, "last_blind", "boss") then + for i = 1, #G.jokers.cards do + if not Card.no(G.jokers.cards[i], "immutable", true) then + Cryptid.with_deck_effects(G.jokers.cards[i], function(card) + Cryptid.misprintize(card, { min = 1.25, max = 1.25 }, nil, true) + end) + end + end + end + end, + }) + local criticalsleeve = CardSleeves.Sleeve({ key = "critical_sleeve", name = "Critical Sleeve", @@ -238,6 +241,119 @@ if CardSleeves then end end, }) + + local encodedsleeve = CardSleeves.Sleeve({ + key = "encoded_sleeve", + name = "Encoded Sleeve", + atlas = "atlasSleeves", + pos = { x = 1, y = 0 }, + config = {}, + unlocked = true, + unlock_condition = { deck = "Encoded Deck", stake = 1 }, + loc_vars = function(self) + return { vars = {} } + end, + + trigger_effect = function(self, args) end, + apply = function(self) + G.E_MANAGER:add_event(Event({ + func = function() + if G.jokers then + -- Adding a before spawning becuase jen banned copy_paste + if + G.P_CENTERS["j_cry_CodeJoker"] + and (G.GAME.banned_keys and not G.GAME.banned_keys["j_cry_CodeJoker"]) + then + local card = create_card("Joker", G.jokers, nil, nil, nil, nil, "j_cry_CodeJoker") + card:add_to_deck() + card:start_materialize() + G.jokers:emplace(card) + end + if + G.P_CENTERS["j_cry_copypaste"] + and (G.GAME.banned_keys and not G.GAME.banned_keys["j_cry_copypaste"]) + then + local card = create_card("Joker", G.jokers, nil, nil, nil, nil, "j_cry_copypaste") + card:add_to_deck() + card:start_materialize() + G.jokers:emplace(card) + end + return true + end + end, + })) + + --DOWNSIDE: + + G.GAME.joker_rate = 0 + G.GAME.planet_rate = 0 + G.GAME.tarot_rate = 0 + G.GAME.code_rate = 1e100 + end, + }) + + local nostalgicsleeve = CardSleeves.Sleeve({ + key = "beta_sleeve", + name = "Nostalgic Sleeve", + atlas = "atlasSleeves", + pos = { x = 0, y = 2 }, + config = { cry_beta = true }, + unlocked = true, + unlock_condition = { deck = "Nostalgic Deck", stake = 1 }, + loc_vars = function(self) + return { vars = {} } + end, + + trigger_effect = function(self, args) end, + apply = function(self) + G.GAME.modifiers.cry_beta = true + end, + }) + + local bountifulsleeve = CardSleeves.Sleeve({ + key = "bountiful_sleeve", + name = "Bountiful Sleeve", + atlas = "atlasSleeves", + pos = { x = 0, y = 2 }, + config = { cry_forced_draw_amount = 5 }, + unlocked = true, + unlock_condition = { deck = "Bountiful Deck", stake = 1 }, + loc_vars = function(self) + return { vars = {} } + end, + + trigger_effect = function(self, args) end, + apply = function(self) + G.GAME.modifiers.cry_forced_draw_amount = self.config.cry_forced_draw_amount + end, + }) + + local beigesleeve = CardSleeves.Sleeve({ + key = "beige_sleeve", + name = "Beige Sleeve", + atlas = "atlasSleeves", + pos = { x = 3, y = 1 }, + unlocked = true, + unlock_condition = { deck = "Beige Deck", stake = 1 }, + loc_vars = function(self) + local key + if self.get_current_deck_key() == "b_cry_beige" then + key = self.key .. "_alt" + return { key = key, vars = {} } + end + return { vars = {} } + end, + + trigger_effect = function(self, args) end, + apply = function(self) + if self.get_current_deck_key() ~= "b_cry_beige" then + G.GAME.modifiers.cry_common_value_quad = true + else + G.GAME.modifiers.cry_uncommon_value_quad = true + end + end, + }) + local legendarysleeve = CardSleeves.Sleeve({ key = "legendary_sleeve", name = "Legendary Sleeve", @@ -328,38 +444,52 @@ if CardSleeves then })) end, }) - local bountifulsleeve = CardSleeves.Sleeve({ - key = "bountiful_sleeve", - name = "Bountiful Sleeve", + local antimattersleeve = CardSleeves.Sleeve({ + key = "antimatter_sleeve", + name = "Antimatter Sleeve", atlas = "atlasSleeves", pos = { x = 0, y = 2 }, - config = { cry_forced_draw_amount = 5 }, + config = { + cry_antimatter = true, + cry_crit_rate = 0.25, --Critical Deck + cry_legendary_rate = 0.2, --Legendary Deck + -- Enhanced Decks + cry_force_enhancement = "random", + cry_force_edition = "random", + cry_force_seal = "random", + cry_forced_draw_amount = 5, + }, unlocked = true, - unlock_condition = { deck = "Bountiful Deck", stake = 1 }, + unlock_condition = { deck = "Antimatter Deck", stake = 1 }, loc_vars = function(self) return { vars = {} } end, - trigger_effect = function(self, args) end, apply = function(self) - G.GAME.modifiers.cry_forced_draw_amount = self.config.cry_forced_draw_amount + Cryptid.antimatter_apply() end, }) + local sleeveitems = {} if CardSleeves then sleeveitems = { - encodedsleeve, + veryfairsleeve, + infinitesleeve, equilibriumsleeve, misprintsleeve, - infinitesleeve, - conveyorsleeve, CCDsleeve, wormholesleeve, + conveyorsleeve, redeemedsleeve, + glowingsleeve, criticalsleeve, + encodedsleeve, + nostalgicsleeve, + bountifulsleeve, + beigesleeve, legendarysleeve, spookysleeve, - bountifulsleeve, + antimattersleeve, } end end diff --git a/Cryptid/items/spectral.lua b/Cryptid/items/spectral.lua index 4e025bf..28778f0 100644 --- a/Cryptid/items/spectral.lua +++ b/Cryptid/items/spectral.lua @@ -1,4 +1,15 @@ local white_hole = { + cry_credits = { + idea = { + "y_not_tony", + }, + art = { + "5381", + }, + code = { + "Math", + }, + }, object_type = "Consumable", dependencies = { items = { @@ -35,9 +46,16 @@ local white_hole = { for k, v in ipairs(G.handlist) do if to_big(G.GAME.hands[v].level) > to_big(1) then local this_removed_levels = G.GAME.hands[v].level - 1 - removed_levels = removed_levels + this_removed_levels - if v ~= _hand or not modest then - level_up_hand(used_consumable, v, true, -this_removed_levels) + if + -- Due to how these poker hands are loaded they still techically exist even if Poker Hand Stuff is disabled + -- Because they still exist, While Hole needs to ignore levels from these if disabled (via Black Hole, Planet.lua, etc...) + (v ~= "cry_Bulwark" and v ~= "cry_Clusterfuck" and v ~= "cry_UltPair" and v ~= "cry_WholeDeck") + or Cryptid.enabled("set_cry_poker_hand_stuff") == true + then + if v ~= _hand or not modest then + removed_levels = removed_levels + this_removed_levels + level_up_hand(used_consumable, v, true, -this_removed_levels) + end end end end @@ -100,6 +118,17 @@ local white_hole = { end, } local vacuum = { + cry_credits = { + idea = { + "Mjiojio", + }, + art = { + "Linus Goof Balls", + }, + code = { + "jenwalter666", + }, + }, object_type = "Consumable", dependencies = { items = { @@ -176,6 +205,17 @@ local vacuum = { end, } local hammerspace = { + cry_credits = { + idea = { + "jenwalter666", + }, + art = { + "AlexZGreat", + }, + code = { + "jenwalter666", + }, + }, object_type = "Consumable", dependencies = { items = { @@ -226,7 +266,7 @@ local hammerspace = { delay = 0.15, func = function() CARD:flip() - CARD:set_ability(get_random_consumable("cry_hammerspace", nil, "c_cry_hammerspace", nil, true)) + CARD:set_ability(Cryptid.random_consumable("cry_hammerspace", nil, "c_cry_hammerspace", nil, true)) play_sound("tarot2", percent) CARD:juice_up(0.3, 0.3) return true @@ -236,6 +276,17 @@ local hammerspace = { end, } local lock = { + cry_credits = { + idea = { + "Ein13", + }, + art = { + "Jevonn", + }, + code = { + "jenwalter666", + }, + }, object_type = "Consumable", dependencies = { items = { @@ -250,6 +301,9 @@ local lock = { cost = 4, order = 1, atlas = "atlasnotjokers", + loc_vars = function(self, info_queue, card) + info_queue[#info_queue + 1] = { key = "eternal", set = "Other" } + end, can_use = function(self, card) return #G.jokers.cards > 0 end, @@ -295,10 +349,8 @@ local lock = { CARD:set_eternal(nil) end CARD.ability.banana = nil - if Cryptid.enabled["Spooky"] then - CARD.ability.cry_possessed = nil - SMODS.Stickers.cry_flickering:apply(CARD, nil) - end + CARD.ability.cry_possessed = nil + SMODS.Stickers.cry_flickering:apply(CARD, nil) play_sound("card1", percent) CARD:juice_up(0.3, 0.3) return true @@ -348,6 +400,17 @@ local lock = { end, } local trade = { + cry_credits = { + idea = { + "5381", + }, + art = { + "RattlingSnow353", + }, + code = { + "Math", + }, + }, object_type = "Consumable", dependencies = { items = { @@ -471,6 +534,17 @@ local trade = { end, } local analog = { + cry_credits = { + idea = { + "y_not_tony", + }, + art = { + "RattlingSnow353", + }, + code = { + "Math", + }, + }, object_type = "Consumable", dependencies = { items = { @@ -531,6 +605,19 @@ local analog = { end, } local summoning = { + cry_credits = { + idea = { + "AlexZGreat", + }, + art = { + --Summoning's sprite takes some parts from an unused sprite by Rattlingsnow so i'm crediting both users + "Kailen", + "RattlingSnow353", + }, + code = { + "Jevonn", + }, + }, object_type = "Consumable", dependencies = { items = { @@ -547,8 +634,8 @@ local summoning = { loc_vars = function(self, info_queue, center) return { vars = { - cry_card_enabled("set_cry_epic") == true and localize("k_cry_epic") or localize("k_rare"), - colours = { G.C.RARITY[cry_card_enabled("set_cry_epic") == true and "cry_epic" or 3] }, + Cryptid.enabled("set_cry_epic") == true and localize("k_cry_epic") or localize("k_rare"), + colours = { G.C.RARITY[Cryptid.enabled("set_cry_epic") == true and "cry_epic" or 3] }, }, } end, @@ -556,7 +643,7 @@ local summoning = { return #G.jokers.cards > 0 and #G.jokers.cards <= G.jokers.config.card_limit --Prevent use if slots are full and all jokers are eternal (would exceed limit) - and #advanced_find_joker(nil, nil, nil, { "eternal" }, true, "j") < G.jokers.config.card_limit + and #Cryptid.advanced_find_joker(nil, nil, nil, { "eternal" }, true, "j") < G.jokers.config.card_limit end, use = function(self, card, area, copier) local used_consumable = copier or card @@ -567,7 +654,7 @@ local summoning = { end end local chosen_joker = pseudorandom_element(G.jokers.cards, pseudoseed("cry_summoning")) - local value = cry_card_enabled("set_cry_epic") == true and "cry_epic" or 0.99 + local value = Cryptid.enabled("set_cry_epic") == true and "cry_epic" or 0.99 local _first_dissolve = nil G.E_MANAGER:add_event(Event({ trigger = "before", @@ -598,6 +685,17 @@ local summoning = { end, } local replica = { + cry_credits = { + idea = { + "Mystic Misclick", + }, + art = { + "RattlingSnow353", + }, + code = { + "Math", + }, + }, object_type = "Consumable", dependencies = { items = { @@ -703,16 +801,15 @@ local ritual = { atlas = "atlasnotjokers", pos = { x = 5, y = 1 }, can_use = function(self, card) - --TODO: CCD card compat - if #G.hand.highlighted > card.ability.max_highlighted then - return false - end - for _, v in ipairs(G.hand.highlighted) do - if v.edition then - return false + if card.area ~= G.hand then + return G.hand and (#G.hand.highlighted == 1) and G.hand.highlighted[1] and not G.hand.highlighted[1].edition + else + local idx = 1 + if G.hand.highlighted[1] == card then + idx = 2 end + return (#G.hand.highlighted == 2) and not G.hand.highlighted[idx].edition end - return true end, use = function(self, card, area, copier) local used_consumable = copier or card diff --git a/Cryptid/items/spooky.lua b/Cryptid/items/spooky.lua index 6839657..db41b5c 100644 --- a/Cryptid/items/spooky.lua +++ b/Cryptid/items/spooky.lua @@ -117,10 +117,6 @@ local choco_dice = { no_dbl = true, loc_vars = function(self, info_queue, center) if not center then --tooltip - elseif not center.added_to_deck then - for i = 1, 10 do - info_queue[#info_queue + 1] = { set = "Other", key = "ev_cry_choco" .. i } - end else SMODS.Events["ev_cry_choco" .. center.ability.extra.roll]:loc_vars(info_queue, center) end @@ -139,7 +135,7 @@ local choco_dice = { then --todo: check if duplicates of event are already started/finished SMODS.Events["ev_cry_choco" .. card.ability.extra.roll]:finish() - card.ability.extra.roll = roll_dice("cry_choco", 1, 10, { ignore_value = card.ability.extra.roll }) + card.ability.extra.roll = Cryptid.roll("cry_choco", 1, 10, { ignore_value = card.ability.extra.roll }) SMODS.Events["ev_cry_choco" .. card.ability.extra.roll]:start() return { message = tostring(card.ability.extra.roll), @@ -566,10 +562,10 @@ local choco9 = { init = function(self) local ed = ease_dollars function ease_dollars(mod, instant) - if mod == 0 then + if to_big(mod) == to_big(0) then return end - if G.GAME.events.ev_cry_choco9 and mod > to_big(0) then + if G.GAME.events.ev_cry_choco9 and to_big(mod) > to_big(0) then mod = mod * 2 end return ed(mod, instant) @@ -703,7 +699,7 @@ local spy = { desc_nodes[#desc_nodes + 1] = res.main_end end else - local secret_card = cry_deep_copy(G.P_CENTERS[card.ability.extra.secret_card]) + local secret_card = Cryptid.deep_copy(G.P_CENTERS[card.ability.extra.secret_card]) secret_card.ability = secret_card.config local target = { type = "descriptions", @@ -1359,8 +1355,8 @@ local jawbreaker = { not Card.no(G.jokers.cards[i - 1], "immune_to_chemach", true) and not Card.no(G.jokers.cards[i - 1], "immutable", true) then - cry_with_deck_effects(G.jokers.cards[i - 1], function(card) - cry_misprintize(card, { min = 2, max = 2 }, nil, true) + Cryptid.with_deck_effects(G.jokers.cards[i - 1], function(card) + Cryptid.misprintize(card, { min = 2, max = 2 }, nil, true) end) end end @@ -1369,8 +1365,8 @@ local jawbreaker = { not Card.no(G.jokers.cards[i + 1], "immune_to_chemach", true) and not Card.no(G.jokers.cards[i + 1], "immutable", true) then - cry_with_deck_effects(G.jokers.cards[i + 1], function(card) - cry_misprintize(card, { min = 2, max = 2 }, nil, true) + Cryptid.with_deck_effects(G.jokers.cards[i + 1], function(card) + Cryptid.misprintize(card, { min = 2, max = 2 }, nil, true) end) end end diff --git a/Cryptid/items/tag.lua b/Cryptid/items/tag.lua index f77220d..1e3793b 100644 --- a/Cryptid/items/tag.lua +++ b/Cryptid/items/tag.lua @@ -1,4 +1,15 @@ local cat = { + cry_credits = { + idea = { + "Catman", + }, + art = { + "5381", + }, + code = { + "Math", + }, + }, object_type = "Tag", dependencies = { items = { @@ -7,11 +18,26 @@ local cat = { }, atlas = "tag_cry", pos = { x = 0, y = 2 }, + config = { level = 1 }, key = "cat", name = "cry-Cat Tag", order = 12, + loc_vars = function(self, info_queue, tag) + return { vars = { tag.ability.level or 1 } } + end, } local epic_tag = { + cry_credits = { + idea = { + "Jevonn", + }, + art = { + "Math", + }, + code = { + "Math", + }, + }, object_type = "Tag", dependencies = { items = { @@ -56,6 +82,17 @@ local epic_tag = { end, } local schematic = { + cry_credits = { + idea = { + "Jevonn", + }, + art = { + "Jevonn", + }, + code = { + "Jevonn", + }, + }, object_type = "Tag", dependencies = { items = { @@ -103,6 +140,18 @@ local schematic = { end, } local empoweredPack = { + cry_credits = { + idea = { + "Mystic Misclick", + "Mjiojio", + }, + art = { + "Jevonn", + }, + code = { + "Math", + }, + }, object_type = "Booster", dependencies = { items = { @@ -145,15 +194,49 @@ local empoweredPack = { G.booster_pack_sparkles:fade(1, 0) end, create_card = function(self, card, i) - if i % 2 == 1 and Cryptid.enabled["Exotic Jokers"] then + if + i % 2 == 1 + and Cryptid.enabled("c_cry_gateway") == true + and not G.GAME.used_jokers["c_cry_gateway"] + and not next(find_joker("Showman")) + then return create_card("Spectral", G.pack_cards, nil, nil, true, true, "c_cry_gateway") - else + elseif not G.GAME.used_jokers["c_soul"] and not next(find_joker("Showman")) then return create_card("Spectral", G.pack_cards, nil, nil, true, true, "c_soul") + else + return create_card("Spectral", G.pack_cards, nil, nil, true, true) end end, group_key = "k_spectral_pack", + cry_digital_hallucinations = { + colour = G.C.SECONDARY_SET.Spectral, + loc_key = "k_plus_spectral", + create = function() + local ccard + if pseudorandom(pseudoseed("diha")) < 0.5 then + ccard = create_card("Spectral", G.consumeables, nil, nil, true, true, "c_soul") + else + ccard = create_card("Spectral", G.consumeables, nil, nil, true, true, "c_cry_gateway") + end + ccard:set_edition({ negative = true }, true) + ccard:add_to_deck() + G.consumeables:emplace(ccard) + end, + }, } local empowered = { + cry_credits = { + idea = { + "Mystic Misclick", + "Mjiojio", + }, + art = { + "5381", + }, + code = { + "Math", + }, + }, object_type = "Tag", dependencies = { items = { @@ -171,7 +254,7 @@ local empowered = { loc_vars = function(self, info_queue) info_queue[#info_queue + 1] = G.P_CENTERS.p_spectral_normal_1 info_queue[#info_queue + 1] = { set = "Spectral", key = "c_soul" } - if Cryptid.enabled["Exotic Jokers"] then + if Cryptid.enabled("c_cry_gateway") then info_queue[#info_queue + 1] = { set = "Spectral", key = "c_cry_gateway" } end return { vars = {} } @@ -197,7 +280,7 @@ local empowered = { if G.GAME.modifiers.cry_force_edition and not G.GAME.modifiers.cry_force_random_edition then card:set_edition(nil, true, true) elseif G.GAME.modifiers.cry_force_random_edition then - local edition = cry_poll_random_edition() + local edition = Cryptid.poll_random_edition() card:set_edition(edition, true, true) end card:start_materialize() @@ -213,6 +296,17 @@ local empowered = { end, } local gambler = { + cry_credits = { + idea = { + "Catman", + }, + art = { + "SpoofyGuy", + }, + code = { + "Math", + }, + }, object_type = "Tag", dependencies = { items = { @@ -224,7 +318,7 @@ local gambler = { order = 13, atlas = "tag_cry", pos = { x = 2, y = 0 }, - config = { type = "immediate", odds = 4 }, + config = { type = "new_blind_choice", odds = 4 }, min_ante = 2, key = "gambler", loc_vars = function(self, info_queue) @@ -232,18 +326,31 @@ local gambler = { return { vars = { G.GAME.probabilities.normal or 1, self.config.odds } } end, apply = function(self, tag, context) - if context.type == "immediate" then + if context.type == "new_blind_choice" then if pseudorandom("cry_gambler_tag") < G.GAME.probabilities.normal / tag.config.odds then local lock = tag.ID G.CONTROLLER.locks[lock] = true tag:yep("+", G.C.SECONDARY_SET.Spectral, function() - local tag = Tag("tag_cry_empowered") - add_tag(tag) + local emp = Tag("tag_cry_empowered") + if tag.ability.shiny then -- good fucking luck + emp.ability.shiny = cry_rollshinybool() + end + add_tag(emp) + tag.triggered = true + emp:apply_to_run({ type = "new_blind_choice" }) G.CONTROLLER.locks[lock] = nil return true end) else tag:nope() + tag.triggered = true + for i = 1, #G.GAME.tags do + if G.GAME.tags[i] ~= tag then + if G.GAME.tags[i]:apply_to_run({ type = "new_blind_choice" }) then + break + end + end + end end tag.triggered = true return true @@ -251,6 +358,17 @@ local gambler = { end, } local bundle = { + cry_credits = { + idea = { + "Mystic Misclick", + }, + art = { + "5381", + }, + code = { + "Math", + }, + }, object_type = "Tag", dependencies = { items = { @@ -261,7 +379,7 @@ local bundle = { order = 16, atlas = "tag_cry", pos = { x = 0, y = 0 }, - config = { type = "immediate" }, + config = { type = "new_blind_choice" }, key = "bundle", min_ante = 2, loc_vars = function(self, info_queue) @@ -272,14 +390,20 @@ local bundle = { return { vars = {} } end, apply = function(self, tag, context) - if context.type == "immediate" then + if context.type == "new_blind_choice" then local lock = tag.ID G.CONTROLLER.locks[lock] = true tag:yep("+", G.C.ATTENTION, function() - add_tag(Tag("tag_standard")) - add_tag(Tag("tag_charm")) - add_tag(Tag("tag_meteor")) - add_tag(Tag("tag_buffoon")) + local tags = { "standard", "charm", "meteor", "buffoon" } + for i, v in ipairs(tags) do + local _tag = Tag("tag_" .. v) + _tag.ability.shiny = cry_rollshinybool() + add_tag(_tag) + if i == 1 then + tag.triggered = true + _tag:apply_to_run({ type = "new_blind_choice" }) + end + end G.CONTROLLER.locks[lock] = nil return true end) @@ -289,6 +413,17 @@ local bundle = { end, } local memory = { + cry_credits = { + idea = { + "y_not_tony", + }, + art = { + "5381", + }, + code = { + "Math", + }, + }, object_type = "Tag", dependencies = { items = { @@ -351,6 +486,17 @@ local memory = { end, } local glitched_tag = { + cry_credits = { + idea = { + "Jevonn", + }, + art = { + "Jevonn", + }, + code = { + "Jevonn", + }, + }, object_type = "Tag", dependencies = { items = { @@ -373,6 +519,9 @@ local glitched_tag = { apply = function(self, tag, context) if context.type == "store_joker_modify" then local _applied = nil + if Cryptid.forced_edition() then + tag:nope() + end if not context.card.edition and not context.card.temp_edition and context.card.ability.set == "Joker" then local lock = tag.ID G.CONTROLLER.locks[lock] = true @@ -392,6 +541,17 @@ local glitched_tag = { end, } local oversat_tag = { + cry_credits = { + idea = { + "Jevonn", + }, + art = { + "Jevonn", + }, + code = { + "Jevonn", + }, + }, object_type = "Tag", dependencies = { items = { @@ -414,6 +574,9 @@ local oversat_tag = { apply = function(self, tag, context) if context.type == "store_joker_modify" then local _applied = nil + if Cryptid.forced_edition() then + tag:nope() + end if not context.card.edition and not context.card.temp_edition and context.card.ability.set == "Joker" then local lock = tag.ID G.CONTROLLER.locks[lock] = true @@ -433,6 +596,17 @@ local oversat_tag = { end, } local mosaic_tag = { + cry_credits = { + idea = { + "Jevonn", + }, + art = { + "Jevonn", + }, + code = { + "Jevonn", + }, + }, object_type = "Tag", dependencies = { items = { @@ -455,6 +629,9 @@ local mosaic_tag = { apply = function(self, tag, context) if context.type == "store_joker_modify" then local _applied = nil + if Cryptid.forced_edition() then + tag:nope() + end if not context.card.edition and not context.card.temp_edition and context.card.ability.set == "Joker" then local lock = tag.ID G.CONTROLLER.locks[lock] = true @@ -474,6 +651,17 @@ local mosaic_tag = { end, } local gold_tag = { + cry_credits = { + idea = { + "Jevonn", + }, + art = { + "Jevonn", + }, + code = { + "Jevonn", + }, + }, object_type = "Tag", dependencies = { items = { @@ -496,6 +684,9 @@ local gold_tag = { apply = function(self, tag, context) if context.type == "store_joker_modify" then local _applied = nil + if Cryptid.forced_edition() then + tag:nope() + end if not context.card.edition and not context.card.temp_edition and context.card.ability.set == "Joker" then local lock = tag.ID G.CONTROLLER.locks[lock] = true @@ -515,6 +706,17 @@ local gold_tag = { end, } local glass_tag = { + cry_credits = { + idea = { + "Jevonn", + }, + art = { + "Jevonn", + }, + code = { + "Jevonn", + }, + }, object_type = "Tag", dependencies = { items = { @@ -537,6 +739,9 @@ local glass_tag = { apply = function(self, tag, context) if context.type == "store_joker_modify" then local _applied = nil + if Cryptid.forced_edition() then + tag:nope() + end if not context.card.edition and not context.card.temp_edition and context.card.ability.set == "Joker" then local lock = tag.ID G.CONTROLLER.locks[lock] = true @@ -556,6 +761,17 @@ local glass_tag = { end, } local blur_tag = { + cry_credits = { + idea = { + "Jevonn", + }, + art = { + "Jevonn", + }, + code = { + "Jevonn", + }, + }, object_type = "Tag", dependencies = { items = { @@ -578,6 +794,9 @@ local blur_tag = { apply = function(self, tag, context) if context.type == "store_joker_modify" then local _applied = nil + if Cryptid.forced_edition() then + tag:nope() + end if not context.card.edition and not context.card.temp_edition and context.card.ability.set == "Joker" then local lock = tag.ID G.CONTROLLER.locks[lock] = true @@ -598,6 +817,17 @@ local blur_tag = { } --order 8 reserved for Noisy tag (if it ever has a shader / comes into existence) local astral_tag = { + cry_credits = { + idea = { + "Jevonn", + }, + art = { + "Jevonn", + }, + code = { + "Jevonn", + }, + }, object_type = "Tag", dependencies = { items = { @@ -620,6 +850,9 @@ local astral_tag = { apply = function(self, tag, context) if context.type == "store_joker_modify" then local _applied = nil + if Cryptid.forced_edition() then + tag:nope() + end if not context.card.edition and not context.card.temp_edition and context.card.ability.set == "Joker" then local lock = tag.ID G.CONTROLLER.locks[lock] = true @@ -639,6 +872,17 @@ local astral_tag = { end, } local m_tag = { + cry_credits = { + idea = { + "Jevonn", + }, + art = { + "Jevonn", + }, + code = { + "Jevonn", + }, + }, object_type = "Tag", dependencies = { items = { @@ -661,6 +905,9 @@ local m_tag = { apply = function(self, tag, context) if context.type == "store_joker_modify" then local _applied = nil + if Cryptid.forced_edition() then + tag:nope() + end if not context.card.edition and not context.card.temp_edition and context.card.ability.set == "Joker" then local lock = tag.ID G.CONTROLLER.locks[lock] = true @@ -680,6 +927,17 @@ local m_tag = { end, } local double_m_tag = { + cry_credits = { + idea = { + "Jevonn", + }, + art = { + "Jevonn", + }, + code = { + "Jevonn", + }, + }, object_type = "Tag", dependencies = { items = { @@ -702,21 +960,7 @@ local double_m_tag = { apply = function(self, tag, context) if context.type == "store_joker_create" then local card - local option = {} - for k, _ in pairs(Cryptid.M_jokers) do - if G.P_CENTERS[k] then - option[#option + 1] = k - end - end - card = create_card( - "Joker", - context.area, - nil, - nil, - nil, - nil, - pseudorandom_element(option, pseudoseed("M_is_love_M_is_life")) - ) + card = create_card("M", context.area, nil, nil, nil, nil, nil, pseudoseed("M_is_love_M_is_life")) card:set_edition({ cry_m = true, }) @@ -737,6 +981,17 @@ local double_m_tag = { end, } local banana = { + cry_credits = { + idea = { + "Jevonn", + }, + art = { + "Jevonn", + }, + code = { + "Jevonn", + }, + }, object_type = "Tag", dependencies = { items = { @@ -806,6 +1061,17 @@ local banana = { end, } local scope = { + cry_credits = { + idea = { + "Jevonn", + }, + art = { + "Jevonn", + }, + code = { + "Jevonn", + }, + }, object_type = "Tag", dependencies = { items = { @@ -835,6 +1101,17 @@ local scope = { end, } local loss = { + cry_credits = { + idea = { + "Jevonn", + }, + art = { + "Jevonn", + }, + code = { + "Jevonn", + }, + }, object_type = "Tag", dependencies = { items = { @@ -874,7 +1151,7 @@ local loss = { if G.GAME.modifiers.cry_force_edition and not G.GAME.modifiers.cry_force_random_edition then card:set_edition(nil, true, true) elseif G.GAME.modifiers.cry_force_random_edition then - local edition = cry_poll_random_edition() + local edition = Cryptid.poll_random_edition() card:set_edition(edition, true, true) end card:start_materialize() @@ -887,6 +1164,17 @@ local loss = { end, } local gourmand = { + cry_credits = { + idea = { + "Personthateatcheese", + }, + art = { + "Personthateatcheese", + }, + code = { + "Jevonn", + }, + }, object_type = "Tag", dependencies = { items = { @@ -920,6 +1208,17 @@ local gourmand = { end, } local better_top_up = { + cry_credits = { + idea = { + "Mjiojio", + }, + art = { + "Jevonn", + }, + code = { + "Jevonn", + }, + }, object_type = "Tag", dependencies = { items = { @@ -961,6 +1260,17 @@ local better_top_up = { end, } local better_voucher = { + cry_credits = { + idea = { + "Mystic Misclick", + }, + art = { + "Mystic Misclick", + }, + code = { + "Jevonn", + }, + }, object_type = "Tag", dependencies = { items = { @@ -982,7 +1292,7 @@ local better_voucher = { if context.type == "voucher_add" then tag:yep("+", G.C.SECONDARY_SET.Voucher, function() G.ARGS.voucher_tag = G.ARGS.voucher_tag or {} - local voucher_key = get_next_megavoucher_key(true) + local voucher_key = Cryptid.next_tier3_key(true) G.ARGS.voucher_tag[voucher_key] = true G.shop_vouchers.config.card_limit = G.shop_vouchers.config.card_limit + 1 local card = Card( @@ -994,13 +1304,13 @@ local better_voucher = { G.P_CENTERS[voucher_key], { bypass_discovery_center = true, bypass_discovery_ui = true } ) - cry_misprintize(card) + Cryptid.misprintize(card) create_shop_card_ui(card, "Voucher", G.shop_vouchers) card:start_materialize() if G.GAME.modifiers.cry_force_edition and not G.GAME.modifiers.cry_force_random_edition then card:set_edition(nil, true) elseif G.GAME.modifiers.cry_force_random_edition then - local edition = cry_poll_random_edition() + local edition = Cryptid.poll_random_edition() card:set_edition(edition, true) end @@ -1038,6 +1348,17 @@ local better_voucher = { end, } local booster = { + cry_credits = { + idea = { + "Watermelon Lover", + }, + art = { + "Maw", + }, + code = { + "Jevonn", + }, + }, object_type = "Tag", dependencies = { items = { @@ -1059,7 +1380,7 @@ local booster = { local lock = tag.ID G.CONTROLLER.locks[lock] = true tag:yep("+", G.C.BLUE, function() - G.GAME.boostertag = true + G.GAME.boostertag = (G.GAME.boostertag or 0) + 1 G.CONTROLLER.locks[lock] = nil return true end) diff --git a/Cryptid/items/test.lua b/Cryptid/items/test.lua index d531d41..372bc31 100644 --- a/Cryptid/items/test.lua +++ b/Cryptid/items/test.lua @@ -119,7 +119,7 @@ local test3 = { }, }, loc_vars = function(self, info_queue, card) - local a, b, c, d, e = cry_get_enchanced_deck_info() + local a, b, c, d, e = Cryptid.enhanced_deck_info() return { vars = { a, b, c, d, e } } end, cry_credits = { diff --git a/Cryptid/items/voucher.lua b/Cryptid/items/voucher.lua index 95a4161..c0c5de9 100644 --- a/Cryptid/items/voucher.lua +++ b/Cryptid/items/voucher.lua @@ -6,6 +6,18 @@ local voucher_atlas = { py = 95, } local copies = { --Double tags become Triple Tags and are 2X as common + cry_credits = { + idea = { + "Catman", + "Mystic Misclick", + }, + art = { + "Mystic Misclick", + }, + code = { + "Math", + }, + }, object_type = "Voucher", dependencies = { items = { @@ -43,6 +55,18 @@ local copies = { --Double tags become Triple Tags and are 2X as common end, } local tag_printer = { --Double tags become Quadruple Tags and are 3X as common + cry_credits = { + idea = { + "Catman", + "Mystic Misclick", + }, + art = { + "Mystic Misclick", + }, + code = { + "Math", + }, + }, object_type = "Voucher", dependencies = { items = { @@ -63,6 +87,18 @@ local tag_printer = { --Double tags become Quadruple Tags and are 3X as common requires = { "v_cry_copies" }, } local clone_machine = { --Double tags become Quintuple Tags and are 4X as common + cry_credits = { + idea = { + "Catman", + "Mystic Misclick", + }, + art = { + "Linus Goof Balls", + }, + code = { + "Math", + }, + }, object_type = "Voucher", dependencies = { items = { @@ -85,6 +121,17 @@ local clone_machine = { --Double tags become Quintuple Tags and are 4X as common requires = { "v_cry_tag_printer" }, } local command_prompt = { --Code cards can appear in the shop + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "Mathguy", + }, + }, object_type = "Voucher", dependencies = { items = { @@ -117,6 +164,17 @@ local command_prompt = { --Code cards can appear in the shop end, } local satellite_uplink = { --Code cards may appear in any of the Celestial Packs + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "Mathguy", + }, + }, object_type = "Voucher", dependencies = { items = { @@ -135,6 +193,17 @@ local satellite_uplink = { --Code cards may appear in any of the Celestial Packs requires = { "v_cry_command_prompt" }, } local quantum_computing = { --Code cards can spawn with Negative addition + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "Mathguy", + }, + }, object_type = "Voucher", dependencies = { items = { @@ -167,13 +236,19 @@ local pairing = { --Retrigger all M Jokers if played hand is a Pair order = 5, pos = { x = 4, y = 5 }, cry_credits = { + art = { + "lolxddj", + }, + code = { + "Math", + }, jolly = { "Jolly Open Winner", "Xaltios", }, }, in_pool = function(self) - local mcheck = get_m_jokers() + local mcheck = Cryptid.get_m_jokers() if mcheck > 0 then return true end @@ -195,13 +270,19 @@ local repair_man = { --Retrigger all M Jokers if played hand contains a pair pos = { x = 5, y = 5 }, requires = { "v_cry_pairing" }, cry_credits = { + art = { + "lolxddj", + }, + code = { + "Math", + }, jolly = { "Jolly Open Winner", "Xaltios", }, }, in_pool = function(self) - local mcheck = get_m_jokers() + local mcheck = Cryptid.get_m_jokers() if mcheck > 0 then return true end @@ -225,13 +306,19 @@ local pairamount_plus = { --Retrigger all M Jokers once for every pair contained requires = { "v_cry_repair_man" }, pools = { ["Tier3"] = true }, cry_credits = { + art = { + "lolxddj", + }, + code = { + "Math", + }, jolly = { "Jolly Open Winner", "Xaltios", }, }, in_pool = function(self) - local mcheck = get_m_jokers() + local mcheck = Cryptid.get_m_jokers() if mcheck > 0 then return true end @@ -254,6 +341,12 @@ local double_vision = { --Double-Sided cards appear 4x more frequently info_queue[#info_queue + 1] = G.P_CENTERS.e_cry_double_sided end, cry_credits = { + art = { + "Linus Goof Balls", + }, + code = { + "Math", + }, jolly = { "Jolly Open Winner", "Axolotolus", @@ -279,6 +372,12 @@ local double_slit = { --Meld can appear in the shop and Arcana Packs info_queue[#info_queue + 1] = G.P_CENTERS.c_cry_meld end, cry_credits = { + art = { + "Linus Goof Balls", + }, + code = { + "Math", + }, jolly = { "Jolly Open Winner", "Axolotolus", @@ -305,6 +404,12 @@ local double_down = { --After every round, X1.5 to all values on the back of Dou info_queue[#info_queue + 1] = G.P_CENTERS.e_cry_double_sided end, cry_credits = { + art = { + "Linus Goof Balls", + }, + code = { + "Math", + }, jolly = { "Jolly Open Winner", "Axolotolus", @@ -312,6 +417,17 @@ local double_down = { --After every round, X1.5 to all values on the back of Dou }, } local overstock_multi = { --+1 card slot[s], +1 booster pack slot[s] and +1 voucher slot[s] available in the shop + cry_credits = { + idea = { + "Frix", + }, + art = { + "HexaCryonic", + }, + code = { + "Jevonn", + }, + }, object_type = "Voucher", dependencies = { items = { @@ -329,35 +445,42 @@ local overstock_multi = { --+1 card slot[s], +1 booster pack slot[s] and +1 vouc return { vars = { (card and card.ability.extra or self.config.extra) } } end, redeem = function(self, card) - if not G.GAME.modifiers.cry_booster_packs then - G.GAME.modifiers.cry_booster_packs = 2 - end - G.GAME.modifiers.cry_booster_packs = G.GAME.modifiers.cry_booster_packs - + math.floor(card and card.ability.extra or self.config.extra) --Booster slots + local mod = math.floor(card and card.ability.extra or self.config.extra) + SMODS.change_booster_limit(mod) G.E_MANAGER:add_event(Event({ func = function() --card slot - change_shop_size(math.floor(card and card.ability.extra or self.config.extra)) + -- why is this in an event? + change_shop_size(mod) return true end, })) - cry_bonusvouchermod(math.floor(card and card.ability.extra or self.config.extra)) + SMODS.change_voucher_limit(mod) end, unredeem = function(self, card) - if not G.GAME.modifiers.cry_booster_packs then - G.GAME.modifiers.cry_booster_packs = 2 - end - G.GAME.modifiers.cry_booster_packs = G.GAME.modifiers.cry_booster_packs - - math.floor(card and card.ability.extra or self.config.extra) --Booster slots + local mod = math.floor(card and card.ability.extra or self.config.extra) + SMODS.change_booster_limit(-mod) G.E_MANAGER:add_event(Event({ func = function() --card slot - change_shop_size(-1 * math.floor(card and card.ability.extra or self.config.extra)) + -- why is this in an event? + change_shop_size(-mod) return true end, })) - cry_bonusvouchermod(-1 * math.floor(card and card.ability.extra or self.config.extra)) + SMODS.change_voucher_limit(-mod) end, } local massproduct = { --All cards and packs in the shop cost $1 + cry_credits = { + idea = { + "Frix", + }, + art = { + "Ein13", + }, + code = { + "Jevonn", + }, + }, object_type = "Voucher", dependencies = { items = { @@ -399,6 +522,17 @@ local massproduct = { --All cards and packs in the shop cost $1 end, } local curate = { --All cards appear with an Edition + cry_credits = { + idea = { + "Frix", + }, + art = { + "Linus Goof Balls", + }, + code = { + "Math", + }, + }, object_type = "Voucher", dependencies = { items = { @@ -423,6 +557,17 @@ local curate = { --All cards appear with an Edition end, } local rerollexchange = { --All rerolls cost $2 + cry_credits = { + idea = { + "Project666", + }, + art = { + "Linus Goof Balls", + }, + code = { + "Jevonn", + }, + }, object_type = "Voucher", dependencies = { items = { @@ -471,6 +616,17 @@ local scope = { --Also unimplemented pools = { ["Tier3"] = true }, } local dexterity = { --Permanently gain +2 hand[s] each round + cry_credits = { + idea = { + "Frix", + }, + art = { + "Linus Goof Balls", + }, + code = { + "Jevonn", + }, + }, object_type = "Voucher", dependencies = { items = { @@ -497,6 +653,17 @@ local dexterity = { --Permanently gain +2 hand[s] each round end, } local threers = { --Permanently gain +2 discard[s] each round + cry_credits = { + idea = { + "Frix", + }, + art = { + "jenwalter666", + }, + code = { + "Jevonn", + }, + }, object_type = "Voucher", dependencies = { items = { @@ -523,6 +690,18 @@ local threers = { --Permanently gain +2 discard[s] each round end, } local tacclimator = { --Tarot cards appear X6 more frequently in the shop All future Tarot cards are free + cry_credits = { + idea = { + "Frix", + }, + art = { + "jenwalter666", + }, + code = { + "Jevonn", + "Toneblock", + }, + }, object_type = "Voucher", dependencies = { items = { @@ -557,6 +736,18 @@ local tacclimator = { --Tarot cards appear X6 more frequently in the shop All end, } local pacclimator = { --Planet cards appear X6 more frequently in the shop All future Planet cards are free + cry_credits = { + idea = { + "Frix", + }, + art = { + "jenwalter666", + }, + code = { + "Jevonn", + "Toneblock", + }, + }, object_type = "Voucher", dependencies = { items = { @@ -591,6 +782,17 @@ local pacclimator = { --Planet cards appear X6 more frequently in the shop All end, } local moneybean = { --Raise the cap on interest earned in each round to $2.0e299 + cry_credits = { + idea = { + "Frix", + }, + art = { + "Watermelon lover", + }, + code = { + "Jevonn", + }, + }, object_type = "Voucher", dependencies = { items = { @@ -629,6 +831,17 @@ local moneybean = { --Raise the cap on interest earned in each round to $2.0e299 end, } local fabric = { --+2 Joker slot[s] + cry_credits = { + idea = { + "Frix", + }, + art = { + "Linus Goof Balls", + }, + code = { + "Jevonn", + }, + }, object_type = "Voucher", dependencies = { items = { @@ -685,6 +898,17 @@ local fabric = { --+2 Joker slot[s] } --Order 87 reserved for Fake-out (unimplemented) local asteroglyph = { --Set Ante to 0 + cry_credits = { + idea = { + "Frix", + }, + art = { + "Hat Stack", + }, + code = { + "jenwalter666", + }, + }, object_type = "Voucher", dependencies = { items = { @@ -698,10 +922,10 @@ local asteroglyph = { --Set Ante to 0 requires = { "v_petroglyph" }, pools = { ["Tier3"] = true }, loc_vars = function(self, info_queue) - return { vars = { asteroglyph_ante() } } + return { vars = { Cryptid.asteroglyph_ante() } } end, redeem = function(self) - local mod = -G.GAME.round_resets.ante + asteroglyph_ante() + local mod = -G.GAME.round_resets.ante + Cryptid.asteroglyph_ante() ease_ante(mod) G.GAME.modifiers.cry_astero_ante = (G.GAME.modifiers.cry_astero_ante or 0) > 0 and math.min(math.ceil(G.GAME.modifiers.cry_astero_ante ^ 1.13), 1e300) @@ -726,7 +950,7 @@ local asteroglyph = { --Set Ante to 0 end end, init = function(self) - function asteroglyph_ante() + function Cryptid.asteroglyph_ante() if not (G.GAME or {}).modifiers then return 0 end @@ -739,6 +963,17 @@ local asteroglyph = { --Set Ante to 0 } --Order 89 reserved for Ivory Script (unimplemented) local blankcanvas = { --+2 hand size + cry_credits = { + idea = { + "Frix", + }, + art = { + "Watermelon lover", + }, + code = { + "Jevonn", + }, + }, object_type = "Voucher", dependencies = { items = { @@ -775,6 +1010,17 @@ local blankcanvas = { --+2 hand size end, } local stickyhand = { --+1 card selection limit + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "HexaCryonic", + }, + }, object_type = "Voucher", dependencies = { items = { @@ -805,6 +1051,17 @@ local stickyhand = { --+1 card selection limit end, } local grapplinghook = { --+1 card selection limit (replace me when "extra functionality" is added later) + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "HexaCryonic", + }, + }, object_type = "Voucher", dependencies = { items = { @@ -837,6 +1094,17 @@ local grapplinghook = { --+1 card selection limit (replace me when "extra functi end, } local hyperspacetether = { --+2 card selection limit + other stuff + cry_credits = { + idea = { + "HexaCryonic", + }, + art = { + "HexaCryonic", + }, + code = { + "HexaCryonic", + }, + }, object_type = "Voucher", dependencies = { items = { @@ -871,6 +1139,18 @@ local hyperspacetether = { --+2 card selection limit + other stuff end, } local triple = { --Copies voucher triple tag + cry_credits = { + idea = { + "Catman", + "Mystic Misclick", + }, + art = { + "5381", + }, + code = { + "Math", + }, + }, object_type = "Tag", dependencies = { items = { @@ -923,6 +1203,18 @@ local triple = { --Copies voucher triple tag end, } local quadruple = { --Tag printer voucher quadruple tag + cry_credits = { + idea = { + "Catman", + "Mystic Misclick", + }, + art = { + "5381", + }, + code = { + "Math", + }, + }, object_type = "Tag", dependencies = { items = { @@ -975,6 +1267,18 @@ local quadruple = { --Tag printer voucher quadruple tag end, } local quintuple = { --Clone machine voucher quintuple tag + cry_credits = { + idea = { + "Catman", + "Mystic Misclick", + }, + art = { + "5381", + }, + code = { + "Math", + }, + }, object_type = "Tag", dependencies = { items = { @@ -1081,7 +1385,7 @@ return { init = function() --Add T3 Voucher pool for Golden Voucher Tag (in Tags.lua) and maybe other things in the future -- Uncursed this -Math - function get_next_megavoucher_key(_from_tag) + function Cryptid.next_tier3_key(_from_tag) local _pool, _pool_key = get_current_pool("Tier3") if _from_tag then _pool_key = "Voucher_fromtag" diff --git a/Cryptid/lib/ascended.lua b/Cryptid/lib/ascended.lua index acfffa4..14ee1a2 100644 --- a/Cryptid/lib/ascended.lua +++ b/Cryptid/lib/ascended.lua @@ -95,11 +95,11 @@ function G.FUNCS.get_poker_hand_info(_cards) ["Pair"] = G.GAME.used_vouchers.v_cry_hyperspacetether and 2 or nil, ["Two Pair"] = 4, ["Three of a Kind"] = G.GAME.used_vouchers.v_cry_hyperspacetether and 3 or nil, - ["Straight"] = next(SMODS.find_card("j_four_fingers")) and cry_get_gameset() ~= "modest" and 4 or 5, - ["Flush"] = next(SMODS.find_card("j_four_fingers")) and cry_get_gameset() ~= "modest" and 4 or 5, + ["Straight"] = next(SMODS.find_card("j_four_fingers")) and Cryptid.gameset() ~= "modest" and 4 or 5, + ["Flush"] = next(SMODS.find_card("j_four_fingers")) and Cryptid.gameset() ~= "modest" and 4 or 5, ["Full House"] = 5, ["Four of a Kind"] = G.GAME.used_vouchers.v_cry_hyperspacetether and 4 or nil, - ["Straight Flush"] = next(SMODS.find_card("j_four_fingers")) and cry_get_gameset() ~= "modest" and 4 or 5, --debatable + ["Straight Flush"] = next(SMODS.find_card("j_four_fingers")) and Cryptid.gameset() ~= "modest" and 4 or 5, --debatable ["cry_Bulwark"] = 5, ["Five of a Kind"] = 5, ["Flush House"] = 5, @@ -110,7 +110,7 @@ function G.FUNCS.get_poker_hand_info(_cards) } -- this is where all the logic for asc hands is. currently it's very simple but if you want more complex logic, here's the place to do it - if hand_table[text] and cry_card_enabled("set_cry_poker_hand_stuff") == true then + if hand_table[text] and Cryptid.enabled("set_cry_poker_hand_stuff") == true then G.GAME.current_round.current_hand.cry_asc_num = G.GAME.used_vouchers.v_cry_hyperspacetether and #_cards - hand_table[text] or #scoring_hand - hand_table[text] @@ -130,11 +130,11 @@ function G.FUNCS.get_poker_hand_info(_cards) or "" return text, loc_disp_text, poker_hands, scoring_hand, disp_text end -function cry_ascend(num) -- edit this function at your leisure - if cry_card_enabled("set_cry_poker_hand_stuff") ~= true then +function Cryptid.ascend(num) -- edit this function at your leisure + if Cryptid.enabled("set_cry_poker_hand_stuff") ~= true then return num end - if cry_get_gameset() == "modest" then + if Cryptid.gameset() == "modest" then -- x(1.1 + 0.05 per sol) base, each card gives + (0.1 + 0.05 per sol) if not G.GAME.current_round.current_hand.cry_asc_num then return num @@ -155,11 +155,11 @@ function cry_ascend(num) -- edit this function at your leisure else return math.max( num, - num * ((1.25 + (0.05 * (G.GAME.sunnumber or 0))) ^ G.GAME.current_round.current_hand.cry_asc_num or 0) + num * ((1.25 + (0.05 * (G.GAME.sunnumber or 0))) ^ (G.GAME.current_round.current_hand.cry_asc_num or 0)) ) end end -function cry_pulse_flame(duration, intensity) -- duration is in seconds, intensity is in idfk honestly, but it increases pretty quickly +function Cryptid.pulse_flame(duration, intensity) -- duration is in seconds, intensity is in idfk honestly, but it increases pretty quickly G.cry_flame_override = G.cry_flame_override or {} G.cry_flame_override["duration"] = duration or 0.01 G.cry_flame_override["intensity"] = intensity or 2 diff --git a/Cryptid/lib/calculate.lua b/Cryptid/lib/calculate.lua index c1892af..d1059c2 100644 --- a/Cryptid/lib/calculate.lua +++ b/Cryptid/lib/calculate.lua @@ -4,7 +4,7 @@ local ec = eval_card function eval_card(card, context) if card.will_shatter then - return + return {}, {} end -- Store old probability for later reference local ggpn = G.GAME.probabilities.normal @@ -596,7 +596,7 @@ function Card:calculate_joker(context) return ret, trig end -function exponentia_scale_mod(self, orig_scale_scale, orig_scale_base, new_scale_base) +function Cryptid.exponentia_scale_mod(self, orig_scale_scale, orig_scale_base, new_scale_base) local jkr = self local dbl_info = G.GAME.cry_double_scale[jkr.sort_id] if jkr.ability and type(jkr.ability) == "table" then @@ -751,7 +751,7 @@ function exponentia_scale_mod(self, orig_scale_scale, orig_scale_base, new_scale end end -function compound_interest_scale_mod(self, orig_scale_scale, orig_scale_base, new_scale_base) +function Cryptid.compound_interest_scale_mod(self, orig_scale_scale, orig_scale_base, new_scale_base) local jkr = self local dbl_info = G.GAME.cry_double_scale[jkr.sort_id] if jkr.ability and type(jkr.ability) == "table" then diff --git a/Cryptid/lib/content.lua b/Cryptid/lib/content.lua index 355be2b..14c6f9a 100644 --- a/Cryptid/lib/content.lua +++ b/Cryptid/lib/content.lua @@ -15,8 +15,8 @@ SMODS.PokerHand({ { "S_A", true, "m_stone" }, }, evaluate = function(parts, hand) - if cry_card_enabled("set_cry_poker_hand_stuff") ~= true or cry_card_enabled("c_cry_asteroidbelt") ~= true then - return + if Cryptid.enabled("set_cry_poker_hand_stuff") ~= true or Cryptid.enabled("c_cry_asteroidbelt") ~= true then + return {} end local stones = {} for i, card in ipairs(hand) do @@ -27,6 +27,24 @@ SMODS.PokerHand({ return #stones >= 5 and { stones } or {} end, }) +SMODS.PokerHandPart({ + key = "cfpart", + func = function(hand) + if Cryptid.enabled("set_cry_poker_hand_stuff") ~= true or Cryptid.enabled("c_cry_void") ~= true then + return {} + end + local eligible_cards = {} + for i, card in ipairs(hand) do + if true then --card.ability.name ~= "Gold Card" + eligible_cards[#eligible_cards + 1] = card + end + end + if #eligible_cards > 7 then + return { eligible_cards } + end + return {} + end, +}) SMODS.PokerHand({ key = "Clusterfuck", visible = false, @@ -45,15 +63,13 @@ SMODS.PokerHand({ { "C_5", true }, }, evaluate = function(parts, hand) - if cry_card_enabled("set_cry_poker_hand_stuff") ~= true or cry_card_enabled("c_cry_void") ~= true then - return - end local other_hands = next(parts._flush) or next(parts._straight) or next(parts._all_pairs) - if #hand > 7 then + if next(parts.cry_cfpart) then if not other_hands then - return { hand } + return { SMODS.merge_lists(parts.cry_cfpart) } end end + return {} end, }) SMODS.PokerHand({ @@ -74,7 +90,7 @@ SMODS.PokerHand({ { "H_7", true }, }, evaluate = function(parts, hand) - if cry_card_enabled("set_cry_poker_hand_stuff") ~= true or cry_card_enabled("c_cry_marsmoons") ~= true then + if Cryptid.enabled("set_cry_poker_hand_stuff") ~= true or Cryptid.enabled("c_cry_marsmoons") ~= true then return end local scoring_pairs = {} @@ -110,7 +126,7 @@ SMODS.PokerHand({ end end if sc_max == #scored_cards / 2 - 1 and sc_unique == 1 then - return + return {} end if #scored_cards >= 8 then return { scored_cards } @@ -179,7 +195,7 @@ SMODS.PokerHand({ { "D_2", true }, }, evaluate = function(parts, hand) - if cry_card_enabled("set_cry_poker_hand_stuff") ~= true or cry_card_enabled("c_cry_universe") ~= true then + if Cryptid.enabled("set_cry_poker_hand_stuff") ~= true or Cryptid.enabled("c_cry_universe") ~= true then return end if #hand >= 52 then @@ -468,7 +484,7 @@ SMODS.Sound({ select_music_track = function() return Cryptid_config.Cryptid and Cryptid_config.Cryptid.exotic_music - and #advanced_find_joker(nil, "cry_exotic", nil, nil, true) ~= 0 + and #Cryptid.advanced_find_joker(nil, "cry_exotic", nil, nil, true) ~= 0 end, }) SMODS.Sound({ @@ -582,6 +598,21 @@ SMODS.Atlas({ px = 34, py = 34, }) + +-- shiny tags +SMODS.Atlas({ + key = "shinyv", + path = "shinyv.png", + px = 34, + py = 34, +}) +SMODS.Atlas({ + key = "shinyc", + path = "shinyc.png", + px = 34, + py = 34, +}) + SMODS.Atlas({ key = "atlasdeck", path = "atlasdeck.png", diff --git a/Cryptid/lib/d20.lua b/Cryptid/lib/d20.lua index e4903c6..cc61400 100644 --- a/Cryptid/lib/d20.lua +++ b/Cryptid/lib/d20.lua @@ -3,7 +3,7 @@ -- Currently this is very empty since D20 hasn't been fully implemented yet, but it should have a lot more later. --Will be moved to D20 file when that gets added -function roll_dice(seed, min, max, config) +function Cryptid.roll(seed, min, max, config) local val while not val or (config and config.ignore_value == val) do val = pseudorandom(seed, min, max) diff --git a/Cryptid/lib/event.lua b/Cryptid/lib/event.lua index 4d6424f..45af83f 100644 --- a/Cryptid/lib/event.lua +++ b/Cryptid/lib/event.lua @@ -9,7 +9,7 @@ SMODS.Event = SMODS.GameObject:extend({ "key", }, inject = function() end, - set = "Event", + set = "Other", class_prefix = "ev", -- This should be called to start an event. start = function(self) diff --git a/Cryptid/lib/gameset.lua b/Cryptid/lib/gameset.lua index 437119f..73962f6 100644 --- a/Cryptid/lib/gameset.lua +++ b/Cryptid/lib/gameset.lua @@ -137,17 +137,17 @@ G.FUNCS.cry_intro_part = function(_part) G.yawetag.states.hover.can = true G.yawetag.states.drag.can = false G.yawetag.hover = Node.hover - step = cry_intro_info({ + step = Cryptid.intro_info({ text_key = "cry_intro_1", attach = { major = G.ROOM_ATTACH, type = "cm", offset = { x = 0, y = 0 } }, step = step, }) - step = cry_intro_info({ + step = Cryptid.intro_info({ text_key = "cry_intro_2", attach = { major = G.ROOM_ATTACH, type = "cm", offset = { x = 0, y = -3 } }, step = step, }) - step = cry_intro_info({ + step = Cryptid.intro_info({ text_key = "cry_intro_3", attach = { major = G.ROOM_ATTACH, type = "cm", offset = { x = 0, y = -3 } }, step = step, @@ -162,7 +162,7 @@ G.FUNCS.cry_intro_part = function(_part) G.yawetag:set_alignment({ major = G.ROOM_ATTACH, type = "cm", offset = { x = 2.5, y = -3 } }) end, }) - step = cry_intro_info({ + step = Cryptid.intro_info({ text_key = "cry_intro_4", attach = { major = G.ROOM_ATTACH, type = "cm", offset = { x = 0, y = -3 } }, step = step, @@ -238,7 +238,7 @@ G.FUNCS.cry_intro_part = function(_part) config = { major = G.ROOM_ATTACH, type = "cm", offset = { x = 0, y = 2.5 } }, }) G.gamesetUI.states.visible = false - step = cry_intro_info({ + step = Cryptid.intro_info({ text_key = "cry_intro_5", attach = { major = G.ROOM_ATTACH, type = "cm", offset = { x = 0, y = -3 } }, step = step, @@ -274,7 +274,7 @@ G.FUNCS.cry_intro_part = function(_part) G.OVERLAY_TUTORIAL.Jimbo:remove_speech_bubble() G.OVERLAY_TUTORIAL.step = nil for i = 1, desc_length[_part] do - step = cry_intro_info({ + step = Cryptid.intro_info({ text_key = "cry_" .. _part .. "_" .. i, attach = { major = G.ROOM_ATTACH, type = "cm", offset = { x = 0, y = -3 } }, step = step, @@ -283,7 +283,7 @@ G.FUNCS.cry_intro_part = function(_part) }, }) end - step = cry_intro_info({ + step = Cryptid.intro_info({ no_button = true, attach = { major = G.ROOM_ATTACH, type = "cm", offset = { x = 0, y = -3 } }, step = step, @@ -364,7 +364,7 @@ G.FUNCS.cry_gameset_confirm = function(e) end end -function cry_intro_info(args) +function Cryptid.intro_info(args) local overlay_colour = { 0.32, 0.36, 0.41, 0 } ease_value(overlay_colour, 4, 0.6, nil, "REAL", true, 0.4) G.OVERLAY_TUTORIAL = G.OVERLAY_TUTORIAL @@ -524,7 +524,7 @@ end ------------------------ -- Gets gameset sprite of current profile -function gameset_sprite(scale, profile, force_gameset) +function Cryptid.gameset_sprite(scale, profile, force_gameset) gameset = force_gameset or G.PROFILES[profile or G.SETTINGS.profile].cry_gameset_overrides and "modified" or G.PROFILES[profile or G.SETTINGS.profile].cry_gameset @@ -547,7 +547,7 @@ function gameset_sprite(scale, profile, force_gameset) end -- designed to work on any object type -function cry_get_gameset(card, center) +function Cryptid.gameset(card, center) if Jen then return "madness" end @@ -577,11 +577,11 @@ function cry_get_gameset(card, center) local gameset = G.PROFILES[G.SETTINGS.profile].cry_gameset or "mainline" if Cryptid_config.experimental and center.extra_gamesets then for i = 1, #center.extra_gamesets do - if center.extra_gamesets[i] == "experimental_" .. gameset then - gameset = "experimental_" .. gameset + if center.extra_gamesets[i] == "exp_" .. gameset then + gameset = "exp_" .. gameset break - elseif center.extra_gamesets[i] == "experimental" then - gameset = "experimental" + elseif center.extra_gamesets[i] == "exp" then + gameset = "exp" break end end @@ -596,7 +596,7 @@ function cry_get_gameset(card, center) end -- set_ability accounts for gamesets function Card:get_gameset(center) - return cry_get_gameset(self, center) + return Cryptid.gameset(self, center) end local csa = Card.set_ability function Card:set_ability(center, y, z) @@ -659,9 +659,9 @@ if not Jen then end if self.gameset_select then Card.cry_set_gameset(self, self.config.center, self.config.center.force_gameset) - cry_update_obj_registry() + Cryptid.update_obj_registry() end - cry_gameset_config_UI(self.config.center) + Cryptid.gameset_config_UI(self.config.center) end end end @@ -669,7 +669,7 @@ if not Jen then end -- gameset config UI -function cry_gameset_config_UI(center) +function Cryptid.gameset_config_UI(center) if not center then center = G.viewedContentSet end @@ -707,9 +707,9 @@ function cry_gameset_config_UI(center) and center.gameset_config[gamesets[i]].disabled ) then - local _center = cry_deep_copy(center) + local _center = Cryptid.deep_copy(center) _center.force_gameset = gamesets[i] - local card = create_generic_card(_center) + local card = Cryptid.generic_card(_center) card.gameset_select = true G.your_collection[1]:emplace(card) --[[if not is_back then @@ -769,7 +769,7 @@ end function G.FUNCS.cry_gameset_config_UI() G.cry_prev_collec = "your_collection_content_sets" - cry_gameset_config_UI() + Cryptid.gameset_config_UI() end local collection_shtuff = { @@ -825,7 +825,7 @@ function get_type_colour(center, card) end end if - cry_get_gameset(card, center) == "disabled" + Cryptid.gameset(card, center) == "disabled" or (center.cry_disabled and (not card.gameset_select or center.cry_disabled.type ~= "manual")) then color = mix_colours(G.C.RED, G.C.GREY, 0.7) @@ -860,11 +860,11 @@ end function G.FUNCS.reset_gameset_config() G.PROFILES[G.SETTINGS.profile].cry_gameset_overrides = nil - cry_update_obj_registry() + Cryptid.update_obj_registry() G:save_progress() end -function cry_card_enabled(key, iter) +function Cryptid.enabled(key, iter) if not iter then iter = 0 end --iter is used to prevent infinite loops from freezing on startup @@ -872,20 +872,20 @@ function cry_card_enabled(key, iter) print("Warning: Circular dependency with " .. key) return true end - local card = cry_get_center(key) + local card = Cryptid.get_center(key) if not card - or cry_get_gameset(card) == "disabled" + or Cryptid.gameset(card) == "disabled" or card.gameset_config - and card.gameset_config[cry_get_gameset(card)] - and card.gameset_config[cry_get_gameset(card)].disabled + and card.gameset_config[Cryptid.gameset(card)] + and card.gameset_config[Cryptid.gameset(card)].disabled then return { type = "manual" } end if card.dependencies then if card.dependencies.items then for i = 1, #card.dependencies.items do - if cry_card_enabled(card.dependencies.items[i], iter + 1) ~= true then + if Cryptid.enabled(card.dependencies.items[i], iter + 1) ~= true then return { type = "card_dependency", key = card.dependencies.items[i] } end end @@ -910,7 +910,7 @@ function cry_card_enabled(key, iter) return true end -function cry_get_center(key, m) +function Cryptid.get_center(key, m) if not m then -- check for non game objects if SMODS.Seals.obj_table and SMODS.Seals.obj_table[key] then @@ -922,7 +922,7 @@ function cry_get_center(key, m) m = SMODS.GameObject if m.subclasses then for k, v in pairs(m.subclasses) do - local c = cry_get_center(key, v) + local c = Cryptid.get_center(key, v) if c then return c end @@ -932,15 +932,26 @@ function cry_get_center(key, m) return m.obj_table and m.obj_table[key] end +function Cryptid.gameset_loc(card, config) + local gameset = Cryptid.gameset(card) + if config[gameset] then + return card.key .. "_" .. config[gameset] + else + return card.key + end +end + ------------------------------ ---- CARD ENABLING SYSTEM ---- ------------------------------ +---@type fun(self: SMODS.GameObject|table, reason: table)? SMODS.GameObject._disable = function(self, reason) if not self.cry_disabled then self.cry_disabled = reason or { type = "manual" } --used to display more information that can be used later end end +---@type fun(self: SMODS.GameObject|table)? SMODS.GameObject.enable = function(self) if self.cry_disabled then self.cry_disabled = nil @@ -950,6 +961,7 @@ end -- Note: For custom pools, these only support Center.pools, not ObjectType.cards -- That could cause issues with mod compat in the future -- Potential improvement: automatic pool detection from gamesets? +---@type fun(self: SMODS.Center|table, reason: table)? SMODS.Center._disable = function(self, reason) if not self.cry_disabled then self.cry_disabled = reason or { type = "manual" } --used to display more information that can be used later @@ -960,6 +972,7 @@ SMODS.Center._disable = function(self, reason) G.P_CENTERS[self.key] = nil end end +---@type fun(self: SMODS.Center|table)? SMODS.Center.enable = function(self) if self.cry_disabled then self.cry_disabled = nil @@ -970,6 +983,8 @@ SMODS.Center.enable = function(self) end end end + +---@type fun(self: SMODS.Joker|table)? SMODS.Joker.enable = function(self) if self.cry_disabled then SMODS.Center.enable(self) @@ -980,6 +995,7 @@ SMODS.Joker.enable = function(self) end end end +---@type fun(self: SMODS.Joker|table, reason: table)? SMODS.Joker._disable = function(self, reason) if not self.cry_disabled then SMODS.Center._disable(self, reason) @@ -990,6 +1006,7 @@ SMODS.Joker._disable = function(self, reason) end end end +---@type fun(self: SMODS.Joker|table, rarity: string|number)? SMODS.Joker.set_rarity = function(self, rarity) SMODS.remove_pool(G.P_JOKER_RARITY_POOLS[self.rarity], self.key) self.rarity = rarity @@ -1000,12 +1017,14 @@ SMODS.Joker.set_rarity = function(self, rarity) end end +---@type fun(self: SMODS.Consumable|table)? SMODS.Consumable.enable = function(self) if self.cry_disabled then SMODS.Center.enable(self) SMODS.insert_pool(G.P_CENTER_POOLS["Consumeables"], self) end end +---@type fun(self: SMODS.Consumable|table, reason: table)? SMODS.Consumable._disable = function(self, reason) if not self.cry_disabled then SMODS.Center._disable(self, reason) @@ -1013,6 +1032,7 @@ SMODS.Consumable._disable = function(self, reason) end end +---@type fun(self: SMODS.Tag|table, reason: table)? SMODS.Tag._disable = function(self, reason) if not self.cry_disabled then self.cry_disabled = reason or { type = "manual" } --used to display more information that can be used later @@ -1020,6 +1040,7 @@ SMODS.Tag._disable = function(self, reason) G.P_TAGS[self.key] = nil end end +---@type fun(self: SMODS.Tag|table)? SMODS.Tag.enable = function(self) if self.cry_disabled then self.cry_disabled = nil @@ -1028,12 +1049,14 @@ SMODS.Tag.enable = function(self) end end +---@type fun(self: SMODS.Blind|table, reason: table)? SMODS.Blind._disable = function(self, reason) if not self.cry_disabled then self.cry_disabled = reason or { type = "manual" } --used to display more information that can be used later G.P_BLINDS[self.key] = nil end end +---@type fun(self: SMODS.Blind|table)? SMODS.Blind.enable = function(self) if self.cry_disabled then self.cry_disabled = nil @@ -1042,12 +1065,14 @@ SMODS.Blind.enable = function(self) end --Removing seals from the center table causes issues +---@type fun(self: SMODS.Seal|table, reason: table)? SMODS.Seal._disable = function(self, reason) if not self.cry_disabled then self.cry_disabled = reason or { type = "manual" } --used to display more information that can be used later SMODS.remove_pool(G.P_CENTER_POOLS[self.set], self.key) end end +---@type fun(self: SMODS.Seal|table)? SMODS.Seal.enable = function(self) if self.cry_disabled then self.cry_disabled = nil @@ -1056,6 +1081,7 @@ SMODS.Seal.enable = function(self) end --Removing editions from the center table causes issues, so instead we make them unable to spawn naturally +---@type fun(self: SMODS.Seal|table, reason: table)? SMODS.Edition._disable = function(self, reason) if not self.cry_disabled then self.cry_disabled = reason or { type = "manual" } --used to display more information that can be used later @@ -1066,6 +1092,7 @@ SMODS.Edition._disable = function(self, reason) end end end +---@type fun(self: SMODS.Seal|table)? SMODS.Edition.enable = function(self) if self.cry_disabled then self.cry_disabled = nil @@ -1075,19 +1102,19 @@ SMODS.Edition.enable = function(self) end end -function cry_update_obj_registry(m, force_enable) +function Cryptid.update_obj_registry(m, force_enable) if not m then m = SMODS.GameObject if m.subclasses then for k, v in pairs(m.subclasses) do - cry_update_obj_registry(v, force_enable) + Cryptid.update_obj_registry(v, force_enable) end end end if m.obj_table then for k, v in pairs(m.obj_table) do if v.mod and v.mod.id == "Cryptid" then - local en = force_enable or cry_card_enabled(k) + local en = force_enable or Cryptid.enabled(k) if en == true then if v.cry_disabled then v:enable() @@ -1101,12 +1128,12 @@ function cry_update_obj_registry(m, force_enable) end end end -function cry_index_items(func, m) +function Cryptid.index_items(func, m) if not m then m = SMODS.GameObject if m.subclasses then for k, v in pairs(m.subclasses) do - cry_index_items(func, v) + Cryptid.index_items(func, v) end end end @@ -1120,9 +1147,9 @@ function cry_index_items(func, m) end local init_item_prototypes_ref = Game.init_item_prototypes function Game:init_item_prototypes() - cry_update_obj_registry(nil, true) --force enable, to prevent issues with profile reloading + Cryptid.update_obj_registry(nil, true) --force enable, to prevent issues with profile reloading init_item_prototypes_ref(self) - cry_update_obj_registry() + Cryptid.update_obj_registry() end ------------------------ @@ -1325,7 +1352,7 @@ function create_UIBox_your_collection_content_sets() if not center then break end - local card = create_generic_card( + local card = Cryptid.generic_card( center, G.your_collection[j].T.x + G.your_collection[j].T.w / 2, G.your_collection[j].T.y @@ -1393,7 +1420,7 @@ function create_UIBox_your_collection_current_set() end end end - cry_index_items(is_in_set) + Cryptid.index_items(is_in_set) table.sort(joker_pool, function(a, b) return a.cry_order < b.cry_order end) @@ -1415,7 +1442,7 @@ function create_UIBox_your_collection_current_set() if not center then break end - local card = create_generic_card( + local card = Cryptid.generic_card( center, G.your_collection[j].T.x + G.your_collection[j].T.w / 2, G.your_collection[j].T.y @@ -1478,7 +1505,7 @@ G.FUNCS.your_collection_content_set_page = function(args) if not center then break end - local card = create_generic_card( + local card = Cryptid.generic_card( center, G.your_collection[j].T.x + G.your_collection[j].T.w / 2, G.your_collection[j].T.y @@ -1510,7 +1537,7 @@ G.FUNCS.your_collection_current_set_page = function(args) end end end - cry_index_items(is_in_set) + Cryptid.index_items(is_in_set) table.sort(joker_pool, function(a, b) return a.cry_order < b.cry_order end) @@ -1521,7 +1548,7 @@ G.FUNCS.your_collection_current_set_page = function(args) if not center then break end - local card = create_generic_card( + local card = Cryptid.generic_card( center, G.your_collection[j].T.x + G.your_collection[j].T.w / 2, G.your_collection[j].T.y @@ -1536,7 +1563,7 @@ end ---- GENERIC COLLECTIONS ----- ------------------------------ -function create_generic_card(center, x, y) +function Cryptid.generic_card(center, x, y) --todo: make gameset stickers play nicely with resized sprites local is_blind = center.set == "Blind" or center.cry_blind local is_tag = center.set == "Tag" or center.cry_tag @@ -1552,29 +1579,29 @@ function create_generic_card(center, x, y) if center.set == "Edition" then card:set_edition(center.key, true, true) end - if safe_get(center, "config", "cry_antimatter") then + if Cryptid.safe_get(center, "config", "cry_antimatter") then card:set_edition("e_negative", true, true) return card end - if safe_get(center, "config", "cry_force_edition") then + if Cryptid.safe_get(center, "config", "cry_force_edition") then card:set_edition({ [center.config.cry_force_edition] = true }, true, true) end if center.set == "Seal" then card:set_seal(center.key, true, true) - card.config.center = cry_deep_copy(card.config.center) + card.config.center = Cryptid.deep_copy(card.config.center) card.config.center.force_gameset = center.force_gameset card.config.center.key = center.key end - if safe_get(center, "config", "cry_force_seal") then + if Cryptid.safe_get(center, "config", "cry_force_seal") then card:set_seal(center.config.cry_force_seal, true, true) end if center.set == "Sticker" then center:apply(card, true) - card.config.center = cry_deep_copy(card.config.center) + card.config.center = Cryptid.deep_copy(card.config.center) card.config.center.force_gameset = center.force_gameset card.config.center.key = center.key end - if safe_get(center, "config", "cry_force_sticker") then + if Cryptid.safe_get(center, "config", "cry_force_sticker") then SMODS.Stickers[center.config.cry_force_sticker]:apply(card, true) end return card @@ -1628,12 +1655,12 @@ function modsCollectionTally(pool, set) if G.ACTIVE_MOD_UI and G.ACTIVE_MOD_UI.id == "Cryptid" then local obj_tally = { tally = 0, of = 0 } --infer pool - local _set = set or safe_get(pool, 1, "set") + local _set = set or Cryptid.safe_get(pool, 1, "set") --check for general consumables local consumable = false - if _set and safe_get(pool, 1, "consumeable") then + if _set and Cryptid.safe_get(pool, 1, "consumeable") then for i = 1, #pool do - if safe_get(pool, i, "set") ~= _set then + if Cryptid.safe_get(pool, i, "set") ~= _set then consumable = true break end @@ -1651,22 +1678,22 @@ function modsCollectionTally(pool, set) for _, v in pairs(pool) do if v.mod and G.ACTIVE_MOD_UI.id == v.mod.id and not v.no_collection then if consumable then - if safe_get(v, "consumeable") then + if Cryptid.safe_get(v, "consumeable") then obj_tally.of = obj_tally.of + 1 - if cry_card_enabled(v.key) == true then + if Cryptid.enabled(v.key) == true then obj_tally.tally = obj_tally.tally + 1 end end elseif set then if v.set and v.set == set then obj_tally.of = obj_tally.of + 1 - if cry_card_enabled(v.key) == true then + if Cryptid.enabled(v.key) == true then obj_tally.tally = obj_tally.tally + 1 end end else obj_tally.of = obj_tally.of + 1 - if cry_card_enabled(v.key) == true then + if Cryptid.enabled(v.key) == true then obj_tally.tally = obj_tally.tally + 1 end end @@ -1768,7 +1795,7 @@ function create_UIBox_your_collection_seals() modify_card = function(card, center) card:set_seal(center.key, true) -- Make disabled UI appear - card.config.center = cry_deep_copy(card.config.center) + card.config.center = Cryptid.deep_copy(card.config.center) card.config.center.key = center.key end, }) @@ -1791,7 +1818,7 @@ function create_UIBox_your_collection_stickers() card.ignore_pinned = true center:apply(card, true) -- Make disabled UI appear - card.config.center = cry_deep_copy(card.config.center) + card.config.center = Cryptid.deep_copy(card.config.center) card.config.center.key = center.key end, }) diff --git a/Cryptid/lib/https.lua b/Cryptid/lib/https.lua index 8af3676..ff5f920 100644 --- a/Cryptid/lib/https.lua +++ b/Cryptid/lib/https.lua @@ -1,28 +1,23 @@ -- Update the Cryptid member count using HTTPS -function update_cry_member_count() - if Cryptid.enabled["HTTPS Module"] == true and Cryptid.mod_path then - if not GLOBAL_cry_member_update_thread then - -- start up the HTTPS thread if needed - local file_data = assert(NFS.newFileData(Cryptid.mod_path .. "https/thread.lua")) - GLOBAL_cry_member_update_thread = love.thread.newThread(file_data) - GLOBAL_cry_member_update_thread:start() - end - local old = GLOBAL_cry_member_count or 5624 - -- get the HTTPS thread's value for Cryptid members - local ret = love.thread.getChannel("member_count"):pop() - if ret then - GLOBAL_cry_member_count = string.match(ret, '"approximate_member_count"%s*:%s*(%d+)') -- string matching a json is odd but should be fine? - end - if not GLOBAL_cry_member_count then - GLOBAL_cry_member_count = old - -- Something failed, print the error - local error = love.thread.getChannel("member_error"):pop() - if error then - sendDebugMessage(error) - end - end - else - -- Use a fallback value if HTTPS is disabled (you all are awesome) - GLOBAL_cry_member_count = 20000 +local member_fallback = 24000 +local https = require("SMODS.https") +local last_update_time = 0 +local initial = true +Cryptid.member_count = member_fallback +local function apply_discord_member_count(code, body, headers) + if body then + Cryptid.member_count = string.match(body, '"approximate_member_count"%s*:%s*(%d+)') end end +function Cryptid.update_member_count() + if Cryptid_config.HTTPS then + if (os.time() - last_update_time >= 60) or initial then + initial = false + last_update_time = os.time() + https.asyncRequest( + "https://discord.com/api/v10/invites/eUf9Ur6RyB?with_counts=true" .. "&v=" .. tostring(os.time()), + apply_discord_member_count + ) + end + end --you all are awesome :) +end diff --git a/Cryptid/lib/misc.lua b/Cryptid/lib/misc.lua index 95a7d68..9fdc8dd 100644 --- a/Cryptid/lib/misc.lua +++ b/Cryptid/lib/misc.lua @@ -18,7 +18,7 @@ function loc_colour(_c, _default) end -- More advanced version of find joker for things that need to find very specific things -function advanced_find_joker(name, rarity, edition, ability, non_debuff, area) +function Cryptid.advanced_find_joker(name, rarity, edition, ability, non_debuff, area) local jokers = {} if not G.jokers or not G.jokers.cards then return {} @@ -63,7 +63,7 @@ function advanced_find_joker(name, rarity, edition, ability, non_debuff, area) end if edition - and (v.edition and v.edition.key == edition) --[[ make this use safe_get later? if it's possible anyways]] + and (v.edition and v.edition.key == edition) --[[ make this use Cryptid.safe_get later? if it's possible anyways]] then check = check + 1 end @@ -104,7 +104,7 @@ function advanced_find_joker(name, rarity, edition, ability, non_debuff, area) end if edition - and (v.edition and v.edition.key == edition) --[[ make this use safe_get later? if it's possible anyways]] + and (v.edition and v.edition.key == edition) --[[ make this use Cryptid.safe_get later? if it's possible anyways]] then check = check + 1 end @@ -175,29 +175,62 @@ function Card:set_sprites(_center, _front) end end -function cry_edition_to_table(edition) -- look mom i figured it out (this does NOT need to be a function) - if edition then - return { [edition] = true } - end -end - -- simple plural s function for localisation -function cry_pls(str, vars) - if string.sub(str, 1, 1) == "p" or string.sub(str, 1, 1) == "s" or string.sub(str, 1, 1) == "y" then - num = vars[tonumber(string.sub(str, 2, -1))] - if num then - if math.abs(to_big(num) - 1) > to_big(0.001) then - return string.sub(str, 1, 1) == "y" and "ies" or "s" - else - return string.sub(str, 1, 1) == "y" and "y" or "" +function Cryptid.pluralize(str, vars) + local inside = str:match("<(.-)>") -- finds args + local _table = {} + if inside then + for v in inside:gmatch("[^,]+") do -- adds args to array + table.insert(_table, v) + end + local num = vars[tonumber(string.match(str, ">(%d+)"))] -- gets reference variable + local plural = _table[1] -- default + local checks = { [1] = "=" } -- checks 1 by default + local checks1mod = false -- tracks if 1 was modified + if #_table > 1 then + for i = 2, #_table do + local isnum = tonumber(_table[i]) + if isnum then + if not checks1mod then + checks[1] = nil + end -- dumb stuff + checks[isnum] = "<" .. (_table[i + 1] or "") -- do less than for custom values + if isnum == 1 then + checks1mod = true + end + i = i + 1 + elseif i == 2 then + checks[1] = "=" .. _table[i] + end end end + local function fch(str, c) + return string.sub(str, 1, 1) == c -- gets first char and returns boolean + end + local keys = {} + for k in pairs(checks) do + table.insert(keys, k) + end + table.sort(keys, function(a, b) + return a < b + end) + for _, k in ipairs(keys) do + if fch(checks[k], "=") then + if math.abs(to_big(num) - k) < to_big(0.001) then + return string.sub(checks[k], 2, -1) + end + elseif fch(checks[k], "<") then + if to_big(num) < to_big(k - 0.001) then + return string.sub(checks[k], 2, -1) + end + end + end + return plural end - return false -- idk it doesn't really matter end -- generate a random edition (e.g. Antimatter Deck) -function cry_poll_random_edition() +function Cryptid.poll_random_edition() local random_edition = pseudorandom_element(G.P_CENTER_POOLS.Edition, pseudoseed("cry_ant_edition")) while random_edition.key == "e_base" do random_edition = pseudorandom_element(G.P_CENTER_POOLS.Edition, pseudoseed("cry_ant_edition")) @@ -207,7 +240,7 @@ function cry_poll_random_edition() end -- gets a random, valid consumeable (used for Hammerspace, CCD Deck, Blessing, etc.) -function get_random_consumable(seed, excluded_flags, banned_card, pool, no_undiscovered) +function Cryptid.random_consumable(seed, excluded_flags, banned_card, pool, no_undiscovered) -- set up excluded flags - these are the kinds of consumables we DON'T want to have generating excluded_flags = excluded_flags or { "hidden", "no_doe", "no_grc" } local selection = "n/a" @@ -222,7 +255,7 @@ function get_random_consumable(seed, excluded_flags, banned_card, pool, no_undis -- check if it is valid if selection.discovered or not no_undiscovered then for k, v in pairs(excluded_flags) do - if not center_no(selection, v, key, true) then + if not Cryptid.no(selection, v, key, true) then --Makes the consumable invalid if it's a specific card unless it's set to --I use this so cards don't create copies of themselves (eg potential inf Blessing chain, Hammerspace from Hammerspace...) if not banned_card or (banned_card and banned_card ~= key) then @@ -253,7 +286,7 @@ function Card:is_jolly() return false end -function cry_with_deck_effects(card, func) +function Cryptid.with_deck_effects(card, func) if not card.added_to_deck then return func(card) else @@ -264,7 +297,7 @@ function cry_with_deck_effects(card, func) end end -function cry_deep_copy(obj, seen) +function Cryptid.deep_copy(obj, seen) if type(obj) ~= "table" then return obj end @@ -275,7 +308,7 @@ function cry_deep_copy(obj, seen) local res = setmetatable({}, getmetatable(obj)) s[obj] = res for k, v in pairs(obj) do - res[cry_deep_copy(k, s)] = cry_deep_copy(v, s) + res[Cryptid.deep_copy(k, s)] = Cryptid.deep_copy(v, s) end return res end @@ -285,11 +318,11 @@ function SMODS.current_mod.reset_game_globals(run_start) end --Used for m vouchers, perhaps this can have more applications in the future -function get_m_jokers() +function Cryptid.get_m_jokers() local mcount = 0 if G.jokers then for i = 1, #G.jokers.cards do - if safe_get(G.jokers.cards[i], "pools", "M") then + if Cryptid.safe_get(G.jokers.cards[i].config.center, "pools", "M") then mcount = mcount + 1 end if G.jokers.cards[i].ability.name == "cry-mprime" then @@ -325,16 +358,16 @@ function Card:no(m, no_no) return Card.no(self, "no_" .. m, true) end -function center_no(center, m, key, no_no) +function Cryptid.no(center, m, key, no_no) if no_no then return center[m] or (G.GAME and G.GAME[m] and G.GAME[m][key]) or false end - return center_no(center, "no_" .. m, key, true) + return Cryptid.no(center, "no_" .. m, key, true) end --todo: move to respective stake file --[from pre-refactor] make this always active to prevent crashes -function cry_apply_ante_tax() +function Cryptid.apply_ante_tax() if G.GAME.modifiers.cry_ante_tax then local tax = math.max( 0, @@ -348,7 +381,7 @@ end --Changes main menu colors and stuff --has to be modified with new enabling system -if true then --Cryptid.enabled["Menu"] then +if Cryptid_config.menu then local oldfunc = Game.main_menu Game.main_menu = function(change_context) local ret = oldfunc(change_context) @@ -408,7 +441,7 @@ end -- just dumping this garbage here -- this just ensures that extra voucher slots work as expected -function cry_bonusvouchermod(mod) +function Cryptid.bonus_voucher_mod(mod) if not G.GAME.shop then return end @@ -432,7 +465,7 @@ function cry_bonusvouchermod(mod) { bypass_discovery_center = true, bypass_discovery_ui = true } ) card.shop_cry_bonusvoucher = #curr_bonus - cry_misprintize(card) + Cryptid.misprintize(card) if G.GAME.events.ev_cry_choco2 then card.misprint_cost_fac = (card.misprint_cost_fac or 1) * 2 card:set_cost() @@ -455,6 +488,27 @@ function cry_bonusvouchermod(mod) end end +function Cryptid.save() + local data = { + shinytags = {}, + } + data.shinytags = copy_table(Cryptid.shinytagdata) + compress_and_save(G.SETTINGS.profile .. "/" .. "cryptidsave.jkr", STR_PACK(data)) +end + +local sppref = set_profile_progress +function set_profile_progress() + sppref() + if not Cryptid.shinytagdata.init then + for k, v in pairs(G.P_TAGS) do + if Cryptid.shinytagdata[k] == nil then + Cryptid.shinytagdata.init = true + Cryptid.shinytagdata[k] = false + end + end + end +end + Cryptid.big_num_whitelist = { j_ride_the_bus = true, j_egg = true, @@ -505,7 +559,7 @@ Cryptid.big_num_whitelist = { j_cry_mprime = true, } -function is_card_big(joker) +function Cryptid.is_card_big(joker) local center = joker.config and joker.config.center if not center then return false @@ -515,7 +569,10 @@ function is_card_big(joker) end --Utility function to check things without erroring -function safe_get(t, ...) +---@param t table +---@param ... any +---@return table|false +function Cryptid.safe_get(t, ...) local current = t for _, k in ipairs({ ... }) do if current[k] == nil then @@ -589,20 +646,20 @@ function Blind:cry_calc_ante_gain() end return 1 end -function cry_get_enchanced_deck_info(deck) +function Cryptid.enhanced_deck_info(deck) --only accounts for vanilla stuff at the moment (WIP) local edition, enhancement, sticker, suit, seal = - "e_" .. (safe_get(G.PROFILES, G.SETTINGS.profile, "cry_edeck_edition") or "foil"), - safe_get(G.PROFILES, G.SETTINGS.profile, "cry_edeck_enhancement") or "m_bonus", - safe_get(G.PROFILES, G.SETTINGS.profile, "cry_edeck_sticker") or "eternal", - safe_get(G.PROFILES, G.SETTINGS.profile, "cry_edeck_suit") or "Spades", - safe_get(G.PROFILES, G.SETTINGS.profile, "cry_edeck_seal") or "Gold" + "e_" .. (Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "cry_edeck_edition") or "foil"), + Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "cry_edeck_enhancement") or "m_bonus", + Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "cry_edeck_sticker") or "eternal", + Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "cry_edeck_suit") or "Spades", + Cryptid.safe_get(G.PROFILES, G.SETTINGS.profile, "cry_edeck_seal") or "Gold" -- Do Stuff - edition = (safe_get(G.P_CENTERS, edition) and edition or "e_foil"):sub(3) - enhancement = safe_get(G.P_CENTERS, enhancement) and enhancement or "m_bonus" - sticker = safe_get(SMODS.Stickers, sticker) and sticker or "eternal" - suit = safe_get(SMODS.Suits, suit) and suit or "Spades" - seal = safe_get(G.P_SEALS, seal) and seal or "Gold" + edition = (Cryptid.safe_get(G.P_CENTERS, edition) and edition or "e_foil"):sub(3) + enhancement = Cryptid.safe_get(G.P_CENTERS, enhancement) and enhancement or "m_bonus" + sticker = Cryptid.safe_get(SMODS.Stickers, sticker) and sticker or "eternal" + suit = Cryptid.safe_get(SMODS.Suits, suit) and suit or "Spades" + seal = Cryptid.safe_get(G.P_SEALS, seal) and seal or "Gold" local ret = { edition = edition, enhancement = enhancement, @@ -613,7 +670,7 @@ function cry_get_enchanced_deck_info(deck) for k, _ in pairs(ret) do if G.GAME.modifiers["cry_force_" .. k] and not G.GAME.viewed_back then ret[k] = G.GAME.modifiers["cry_force_" .. k] - elseif safe_get(deck, "config", "cry_force_" .. k) then + elseif Cryptid.safe_get(deck, "config", "cry_force_" .. k) then ret[k] = deck.config["cry_force_" .. k] end end @@ -625,7 +682,7 @@ function Cryptid.post_process(center) center.calculate = function(self, card, context) local ret, trig = vc(self, card, context) if context.retrigger_joker_check and context.other_card == card then - local reps = get_m_retriggers(self, card, context) + local reps = Cryptid.get_m_retriggers(self, card, context) if reps > 0 then return { message = localize("k_again_ex"), @@ -641,7 +698,13 @@ end -- Wrapper G.FUNCS function to reset localization -- For resetting localization on the fly for family friendly toggle -function reload_cryptid_localization() +function Cryptid.reload_localization() SMODS.handle_loc_file(Cryptid.path) return init_localization() end + +-- Checks if all jokers in shop will have editions (via Curate, Edition Decks, etc.) +-- Will cause edition tags to Nope! +function Cryptid.forced_edition() + return G.GAME.modifiers.cry_force_edition or G.GAME.used_vouchers.v_cry_curate +end diff --git a/Cryptid/lib/misprintize.lua b/Cryptid/lib/misprintize.lua index af99669..0d2ee5d 100644 --- a/Cryptid/lib/misprintize.lua +++ b/Cryptid/lib/misprintize.lua @@ -2,9 +2,9 @@ --Redefine these here because they're always used Cryptid.base_values = {} -function cry_misprintize_tbl(name, ref_tbl, ref_value, clear, override, stack, big) +function Cryptid.misprintize_tbl(name, ref_tbl, ref_value, clear, override, stack, big) if name and ref_tbl and ref_value then - tbl = cry_deep_copy(ref_tbl[ref_value]) + tbl = Cryptid.deep_copy(ref_tbl[ref_value]) for k, v in pairs(tbl) do if (type(tbl[k]) ~= "table") or is_number(tbl[k]) then if @@ -24,11 +24,11 @@ function cry_misprintize_tbl(name, ref_tbl, ref_value, clear, override, stack, b if not Cryptid.base_values[name][k] then Cryptid.base_values[name][k] = tbl[k] end - tbl[k] = cry_sanity_check( + tbl[k] = Cryptid.sanity_check( clear and Cryptid.base_values[name][k] or cry_format( (stack and tbl[k] or Cryptid.base_values[name][k]) - * cry_log_random( + * Cryptid.log_random( pseudoseed("cry_misprint" .. G.GAME.round_resets.ante), override and override.min or G.GAME.modifiers.cry_misprint_min, override and override.max or G.GAME.modifiers.cry_misprint_max @@ -61,11 +61,11 @@ function cry_misprintize_tbl(name, ref_tbl, ref_value, clear, override, stack, b if not Cryptid.base_values[name][k][_k] then Cryptid.base_values[name][k][_k] = tbl[k][_k] end - tbl[k][_k] = cry_sanity_check( + tbl[k][_k] = Cryptid.sanity_check( clear and Cryptid.base_values[name][k][_k] or cry_format( (stack and tbl[k][_k] or Cryptid.base_values[name][k][_k]) - * cry_log_random( + * Cryptid.log_random( pseudoseed("cry_misprint" .. G.GAME.round_resets.ante), override and override.min or G.GAME.modifiers.cry_misprint_min, override and override.max or G.GAME.modifiers.cry_misprint_max @@ -81,12 +81,12 @@ function cry_misprintize_tbl(name, ref_tbl, ref_value, clear, override, stack, b ref_tbl[ref_value] = tbl end end -function cry_misprintize_val(val, override, big) +function Cryptid.misprintize_val(val, override, big) if is_number(val) then - val = cry_sanity_check( + val = Cryptid.sanity_check( cry_format( val - * cry_log_random( + * Cryptid.log_random( pseudoseed("cry_misprint" .. G.GAME.round_resets.ante), override and override.min or G.GAME.modifiers.cry_misprint_min, override and override.max or G.GAME.modifiers.cry_misprint_max @@ -98,7 +98,7 @@ function cry_misprintize_val(val, override, big) end return val end -function cry_sanity_check(val, is_big) +function Cryptid.sanity_check(val, is_big) if is_big then if not val or type(val) == "number" and (val ~= val or val > 1e300 or val < -1e300) then val = 1e300 @@ -115,7 +115,7 @@ function cry_sanity_check(val, is_big) end return val end -function cry_misprintize(card, override, force_reset, stack) +function Cryptid.misprintize(card, override, force_reset, stack) if Card.no(card, "immutable", true) then force_reset = true end @@ -123,7 +123,7 @@ function cry_misprintize(card, override, force_reset, stack) if card.infinifusion then if card.config.center == card.infinifusion_center or card.config.center.key == "j_infus_fused" then calculate_infinifusion(card, nil, function(i) - cry_misprintize(card, override, force_reset, stack) + Cryptid.misprintize(card, override, force_reset, stack) end) end end @@ -146,15 +146,31 @@ function cry_misprintize(card, override, force_reset, stack) override.max = override.max * G.GAME.modifiers.cry_jkr_misprint_mod end if G.GAME.modifiers.cry_misprint_min or override and override.min then - cry_misprintize_tbl(card.config.center_key, card, "ability", nil, override, stack, is_card_big(card)) + Cryptid.misprintize_tbl( + card.config.center_key, + card, + "ability", + nil, + override, + stack, + Cryptid.is_card_big(card) + ) if card.base then - cry_misprintize_tbl(card.config.card_key, card, "base", nil, override, stack, is_card_big(card)) + Cryptid.misprintize_tbl( + card.config.card_key, + card, + "base", + nil, + override, + stack, + Cryptid.is_card_big(card) + ) end end if G.GAME.modifiers.cry_misprint_min then - --card.cost = cry_format(card.cost / cry_log_random(pseudoseed('cry_misprint'..G.GAME.round_resets.ante),override and override.min or G.GAME.modifiers.cry_misprint_min,override and override.max or G.GAME.modifiers.cry_misprint_max),"%.2f") + --card.cost = cry_format(card.cost / Cryptid.log_random(pseudoseed('cry_misprint'..G.GAME.round_resets.ante),override and override.min or G.GAME.modifiers.cry_misprint_min,override and override.max or G.GAME.modifiers.cry_misprint_max),"%.2f") card.misprint_cost_fac = 1 - / cry_log_random( + / Cryptid.log_random( pseudoseed("cry_misprint" .. G.GAME.round_resets.ante), override and override.min or G.GAME.modifiers.cry_misprint_min, override and override.max or G.GAME.modifiers.cry_misprint_max @@ -162,15 +178,15 @@ function cry_misprintize(card, override, force_reset, stack) card:set_cost() end else - cry_misprintize_tbl(card.config.center_key, card, "ability", true, nil, nil, is_card_big(card)) + Cryptid.misprintize_tbl(card.config.center_key, card, "ability", true, nil, nil, Cryptid.is_card_big(card)) end if card.ability.consumeable then for k, v in pairs(card.ability.consumeable) do - card.ability.consumeable[k] = cry_deep_copy(card.ability[k]) + card.ability.consumeable[k] = Cryptid.deep_copy(card.ability[k]) end end end -function cry_log_random(seed, min, max) +function Cryptid.log_random(seed, min, max) math.randomseed(seed) local lmin = math.log(min, 2.718281828459045) local lmax = math.log(max, 2.718281828459045) diff --git a/Cryptid/lib/modifiers.lua b/Cryptid/lib/modifiers.lua index b2c1a11..6db4eac 100644 --- a/Cryptid/lib/modifiers.lua +++ b/Cryptid/lib/modifiers.lua @@ -100,7 +100,7 @@ function Card:unredeem() end G.E_MANAGER:add_event(Event({ func = function() - cry_update_used_vouchers() + Cryptid.update_used_vouchers() return true end, })) @@ -274,13 +274,13 @@ function Card:set_ability(center, initial, delay_sprites) local edition = nil local sticker = nil local random = nil - if safe_get(G, "GAME", "modifiers", "cry_force_edition") then + if Cryptid.safe_get(G, "GAME", "modifiers", "cry_force_edition") then edition = G.GAME.modifiers.cry_force_edition end - if safe_get(G, "GAME", "modifiers", "cry_force_sticker") then + if Cryptid.safe_get(G, "GAME", "modifiers", "cry_force_sticker") then sticker = G.GAME.modifiers.cry_force_sticker end - if safe_get(G, "GAME", "modifiers", "cry_force_random_edition") then + if Cryptid.safe_get(G, "GAME", "modifiers", "cry_force_random_edition") then random = true end if @@ -290,7 +290,7 @@ function Card:set_ability(center, initial, delay_sprites) if edition and not random then self:set_edition({ [edition] = true }, true, true) elseif random then - self:set_edition(cry_poll_random_edition(), true, true) + self:set_edition(Cryptid.poll_random_edition(), true, true) end if sticker then self.ability[sticker] = true @@ -331,13 +331,13 @@ function Card:start_dissolve(dissolve_colours, silent, dissolve_time_fac, no_jui dissolveref(self, dissolve_colours, silent, dissolve_time_fac, no_juice) G.E_MANAGER:add_event(Event({ func = function() - cry_update_used_vouchers() + Cryptid.update_used_vouchers() return true end, })) end -function cry_update_used_vouchers() +function Cryptid.update_used_vouchers() if G and G.GAME and G.vouchers then G.GAME.used_vouchers = {} for i, v in ipairs(G.vouchers.cards) do @@ -347,7 +347,7 @@ function cry_update_used_vouchers() end -- check if Director's Cut or Retcon offers a cheaper reroll price -function cry_cheapest_boss_reroll() +function Cryptid.cheapest_boss_reroll() local cheapest = 1e300 local vouchers = { SMODS.find_card("v_directors_cut"), @@ -388,16 +388,20 @@ G.FUNCS.evaluate_round = function() G.GAME.interest_cap = cry_best_interest_cap() -- blehhhhhh evaluateroundref() end - +function Cryptid.edition_to_table(edition) -- look mom i figured it out (this does NOT need to be a function) + if edition then + return { [edition] = true } + end +end function cry_get_next_voucher_edition() -- currently only for edition decks, can be modified if voucher editioning becomes more important if G.GAME.modifiers.cry_force_edition then - return cry_edition_to_table(G.GAME.modifiers.cry_force_edition) + return Cryptid.edition_to_table(G.GAME.modifiers.cry_force_edition) elseif G.GAME.modifiers.cry_force_random_edition then - return cry_poll_random_edition() + return Cryptid.poll_random_edition() end end -- code to generate Stickers for Vouchers (and boosters), based on that for Jokers -function cry_get_next_voucher_stickers(booster) +function Cryptid.next_voucher_stickers(booster) local rate = 0.3 if booster then rate = 0.2 @@ -734,6 +738,45 @@ SMODS.Sticker({ end end, }) + +-- shiny tag hooks + +local tagability = Tag.set_ability +function Tag:set_ability() + tagability(self) + if self.ability.blind_type then + G.GAME.cry_shiny_choices = G.GAME.cry_shiny_choices or {} + G.GAME.cry_shiny_choices[G.GAME.round_resets.ante] = G.GAME.cry_shiny_choices[G.GAME.round_resets.ante] or {} + + if not G.GAME.cry_shiny_choices[G.GAME.round_resets.ante][self.ability.blind_type] then + G.GAME.cry_shiny_choices[G.GAME.round_resets.ante][self.ability.blind_type] = cry_rollshiny() + end + self.ability.shiny = G.GAME.cry_shiny_choices[G.GAME.round_resets.ante][self.ability.blind_type] == "shiny" + and true + end +end + +local ycollecref = G.FUNCS.your_collection +G.FUNCS.your_collection = function(e) + ycollecref(e) + G.cry_current_tagpage = nil +end +local omuicryref = G.FUNCS.openModUI_Cryptid +G.FUNCS.openModUI_Cryptid = function(e) + omuicryref(e) + G.cry_current_tagpage = nil +end + +function Cryptid.shinytag_tally() + local ret = 0 + for k, v in pairs(Cryptid.shinytagdata) do + if Cryptid.shinytagdata[k] then + ret = ret + 1 + end + end + return ret +end + -- temp crappy overwrite for voucher ui until smods does stuff function G.UIDEF.used_vouchers() diff --git a/Cryptid/lib/notifications.lua b/Cryptid/lib/notifications.lua index 1f9b194..9ba2147 100644 --- a/Cryptid/lib/notifications.lua +++ b/Cryptid/lib/notifications.lua @@ -1,6 +1,6 @@ -- notifications.lua - Adds notification system for Cryptid -function create_cryptid_notif_overlay(key) +function Cryptid.notification_overlay(key) if not G.SETTINGS.cryptid_notifs then -- I want this to be across profiles G.SETTINGS.cryptid_notifs = {} end diff --git a/Cryptid/lib/overrides.lua b/Cryptid/lib/overrides.lua index c440daa..cb4b8bf 100644 --- a/Cryptid/lib/overrides.lua +++ b/Cryptid/lib/overrides.lua @@ -40,7 +40,11 @@ function get_current_pool(_type, _rarity, _legendary, _append, override_equilibr local valid_pools = { "Joker", "Consumeables", "Voucher", "Booster" } for _, id in ipairs(valid_pools) do for k, v in pairs(G.P_CENTER_POOLS[id]) do - if v.unlocked == true and not center_no(v, "doe", k) and not G.GAME.banned_keys[v.key] then + if + v.unlocked == true + and not Cryptid.no(v, "doe", k) + and not (G.GAME.banned_keys[v.key] or G.GAME.cry_banished_keys[v.key]) + then P_CRY_ITEMS[#P_CRY_ITEMS + 1] = v.key end end @@ -66,15 +70,15 @@ function get_new_boss() if G.GAME.modifiers.cry_beta then local bl_key = string.sub(bl, 4) local nostalgicblinds = { - arm = (cry_card_enabled("bl_cry_oldarm") == true), - fish = (cry_card_enabled("bl_cry_oldfish") == true), - flint = (cry_card_enabled("bl_cry_oldflint") == true), - house = (cry_card_enabled("bl_cry_oldhouse") == true), - manacle = (cry_card_enabled("bl_cry_oldmanacle") == true), - mark = (cry_card_enabled("bl_cry_oldmark") == true), - ox = (cry_card_enabled("bl_cry_oldox") == true), - pillar = (cry_card_enabled("bl_cry_oldpillar") == true), - serpent = (cry_card_enabled("bl_cry_oldserpent") == true), + arm = (Cryptid.enabled("bl_cry_oldarm") == true), + fish = (Cryptid.enabled("bl_cry_oldfish") == true), + flint = (Cryptid.enabled("bl_cry_oldflint") == true), + house = (Cryptid.enabled("bl_cry_oldhouse") == true), + manacle = (Cryptid.enabled("bl_cry_oldmanacle") == true), + mark = (Cryptid.enabled("bl_cry_oldmark") == true), + ox = (Cryptid.enabled("bl_cry_oldox") == true), + pillar = (Cryptid.enabled("bl_cry_oldpillar") == true), + serpent = (Cryptid.enabled("bl_cry_oldserpent") == true), } if nostalgicblinds[bl_key] then return "bl_cry_old" .. bl_key @@ -169,6 +173,7 @@ function Game:init_game_object() -- Add initial dropshot and number blocks card g.current_round.cry_nb_card = { rank = "Ace" } g.current_round.cry_dropshot_card = { suit = "Spades" } + g.monstermult = 1 -- Create G.GAME.events when starting a run, so there's no errors g.events = {} return g @@ -229,6 +234,8 @@ G.C.CRY_BLOSSOM = { 0, 0, 0, 0 } G.C.CRY_AZURE = { 0, 0, 0, 0 } G.C.CRY_ASCENDANT = { 0, 0, 0, 0 } G.C.CRY_JOLLY = { 0, 0, 0, 0 } +G.C.CRY_GREENGRADIENT = { 0, 0, 0, 0 } +G.C.CRY_ALTGREENGRADIENT = { 0, 0, 0, 0 } Cryptid.C = { EXOTIC = { HEX("708b91"), HEX("1e9eba") }, TWILIGHT = { HEX("0800ff"), HEX("aa00ff") }, @@ -241,8 +248,9 @@ Cryptid.C = { ASCENDANT = { HEX("2e00f5"), HEX("e5001d") }, JOLLY = { HEX("6ec1f5"), HEX("456b84") }, SELECTED = { HEX("e38039"), HEX("ccdd1b") }, + GREENGRADIENT = { HEX("51e099"), HEX("1e523a") }, + ALTGREENGRADIENT = { HEX("6bb565"), HEX("bd28bf") }, } - cry_pointer_dt = 0 cry_jimball_dt = 0 cry_glowing_dt = 0 @@ -268,7 +276,7 @@ function Game:update(dt) AllowDividing("Code") CryptidIncanCompat = true end - if cry_card_enabled("set_cry_timer") == true then + if Cryptid.enabled("set_cry_timer") == true then cry_pointer_dt = cry_pointer_dt + dt cry_jimball_dt = cry_jimball_dt + dt cry_glowing_dt = cry_glowing_dt + dt @@ -367,22 +375,31 @@ function Game:update(dt) --Update UI --todo: in blinds screen, too if G.blind_select_opts then - local blind_UI = G.blind_select_opts[string.lower(c)].definition.nodes[1].nodes[1].nodes[1].nodes[1] - local chip_text_node = blind_UI.nodes[1].nodes[3].nodes[1].nodes[2].nodes[2].nodes[3] - if chip_text_node then - chip_text_node.config.text = number_format( - get_blind_amount(G.GAME.round_resets.blind_ante) - * G.GAME.starting_params.ante_scaling - * G.GAME.CRY_BLINDS[c] - ) - chip_text_node.config.scale = score_number_scale( - 0.9, - get_blind_amount(G.GAME.round_resets.blind_ante) - * G.GAME.starting_params.ante_scaling - * G.GAME.CRY_BLINDS[c] - ) + if (SMODS.Mods["StrangeLib"] or {}).can_load then + StrangeLib.dynablind.blind_choice_scores[c] = get_blind_amount(G.GAME.round_resets.blind_ante) + * G.GAME.starting_params.ante_scaling + * G.GAME.CRY_BLINDS[c] + StrangeLib.dynablind.blind_choice_score_texts[c] = + number_format(StrangeLib.dynablind.blind_choice_scores[c]) + else + local blind_UI = + G.blind_select_opts[string.lower(c)].definition.nodes[1].nodes[1].nodes[1].nodes[1] + local chip_text_node = blind_UI.nodes[1].nodes[3].nodes[1].nodes[2].nodes[2].nodes[3] + if chip_text_node then + chip_text_node.config.text = number_format( + get_blind_amount(G.GAME.round_resets.blind_ante) + * G.GAME.starting_params.ante_scaling + * G.GAME.CRY_BLINDS[c] + ) + chip_text_node.config.scale = score_number_scale( + 0.9, + get_blind_amount(G.GAME.round_resets.blind_ante) + * G.GAME.starting_params.ante_scaling + * G.GAME.CRY_BLINDS[c] + ) + end + G.blind_select_opts[string.lower(c)]:recalculate() end - G.blind_select_opts[string.lower(c)]:recalculate() end elseif G.GAME.round_resets.blind_states[c] ~= "Defeated" @@ -420,7 +437,7 @@ function Card:set_cost() -- Makes the edition cost increase usually present not apply if this variable is true -- Used for some of the Jen's almanac edition decks because having the price increase apply was "unfun" if self.edition and G.GAME.modifiers.cry_no_edition_price then - local m = cry_deep_copy(self.edition) + local m = Cryptid.deep_copy(self.edition) self.edition = nil sc(self) self.edition = m @@ -605,12 +622,12 @@ function SMODS.create_mod_badges(obj, badges) } end end - if safe_get(G, "ACTIVE_MOD_UI", "id") == "Cryptid" and obj and not obj.force_gameset then - local set = cry_get_gameset(obj) + if Cryptid.safe_get(G, "ACTIVE_MOD_UI", "id") == "Cryptid" and obj and not obj.force_gameset then + local set = Cryptid.gameset(obj) if set == "disabled" or obj.set == "Content Set" then return end - local card_type = localize("cry_gameset_" .. cry_get_gameset(obj)) + local card_type = localize("cry_gameset_" .. Cryptid.gameset(obj)) if card_type == "ERROR" then card_type = localize("cry_gameset_custom") end @@ -626,7 +643,7 @@ end -- This is short enough that I'm fine overriding it function calculate_reroll_cost(skip_increment) - if G.GAME.current_round.free_rerolls < 0 then + if not G.GAME.current_round.free_rerolls or G.GAME.current_round.free_rerolls < 0 then G.GAME.current_round.free_rerolls = 0 end if next(find_joker("cry-crustulum")) or G.GAME.current_round.free_rerolls > 0 then @@ -659,9 +676,9 @@ function create_card(_type, area, legendary, _rarity, skip_materialize, soulable local ps = pseudoseed if area == "ERROR" then pseudo = function(x) - return pseudorandom(predict_pseudoseed(x)) + return pseudorandom(Cryptid.predict_pseudoseed(x)) end - ps = predict_pseudoseed + ps = Cryptid.predict_pseudoseed end local center = G.P_CENTERS.b_red if (_type == "Joker") and G.GAME and G.GAME.modifiers and G.GAME.modifiers.all_rnj then @@ -669,8 +686,8 @@ function create_card(_type, area, legendary, _rarity, skip_materialize, soulable end local function aeqviable(center) return center.unlocked - and not center_no(center, "doe") - and not center_no(center, "aeq") + and not Cryptid.no(center, "doe") + and not Cryptid.no(center, "aeq") and not (center.rarity == 6 or center.rarity == "cry_exotic") end if _type == "Joker" and not _rarity and not legendary then @@ -979,15 +996,20 @@ function create_card(_type, area, legendary, _rarity, skip_materialize, soulable card:set_edition(nil, true) end if G.GAME.modifiers.cry_force_random_edition and area ~= G.pack_cards then - local edition = cry_poll_random_edition() + local edition = Cryptid.poll_random_edition() card:set_edition(edition, true) end if not (card.edition and (card.edition.cry_oversat or card.edition.cry_glitched)) then - cry_misprintize(card) + Cryptid.misprintize(card) end if _type == "Joker" and G.GAME.modifiers.cry_common_value_quad then if card.config.center.rarity == 1 then - cry_misprintize(card, { min = 4, max = 4 }, nil, true) + Cryptid.misprintize(card, { min = 4, max = 4 }, nil, true) + end + end + if _type == "Joker" and G.GAME.modifiers.cry_uncommon_value_quad then + if card.config.center.rarity == 2 then + Cryptid.misprintize(card, { min = 4, max = 4 }, nil, true) end end if card.ability.consumeable and card.pinned then -- counterpart is in Sticker.toml @@ -1162,8 +1184,7 @@ end --Cryptid (THE MOD) localization local function parse_loc_txt(center) center.text_parsed = {} - if not center.text then - else + if center.text then for _, line in ipairs(center.text) do center.text_parsed[#center.text_parsed + 1] = loc_parse_string(line) end @@ -1195,9 +1216,10 @@ function init_localization() G.localization.descriptions.Voucher.v_crystal_ball.text[1] = "{C:attention}+#1#{} consumable slot" G.localization.descriptions.Joker.j_seance.text[1] = "If {C:attention}played hand{} contains a" -- damnit seance end - if Cryptid.obj_buffer and Cryptid.obj_buffer.Stake then - for i = 1, #Cryptid.obj_buffer.Stake do - local key = Cryptid.obj_buffer.Stake[i].key + il() + if Cryptid.object_buffer and Cryptid.object_buffer.Stake then + for i = 1, #Cryptid.object_buffer.Stake do + local key = Cryptid.object_buffer.Stake[i].key local color = G.localization.descriptions.Stake[key] and G.localization.descriptions.Stake[key].colour if color then local sticker_key = key:sub(7) .. "_sticker" @@ -1219,7 +1241,6 @@ function init_localization() end end end - il() end --Fix a corrupted game state diff --git a/Cryptid/lib/ui.lua b/Cryptid/lib/ui.lua new file mode 100644 index 0000000..7d6b23e --- /dev/null +++ b/Cryptid/lib/ui.lua @@ -0,0 +1,298 @@ +-- ui.lua - Code used for new UI elements/changes in Cryptid + +-- Add/modify Steamodded Draw Steps to work with Cryptid + +-- Edition Decks +SMODS.DrawStep({ + key = "back_edition", + order = 5, + func = function(self) + if Cryptid.safe_get(self, "area", "config", "type") == "deck" then + -- following here is a horrendous mod compatability line + local currentBack = not self.params.galdur_selector + and ((Galdur and Galdur.config.use and type(self.params.galdur_back) == "table" and self.params.galdur_back) or type( + self.params.viewed_back + ) == "table" and self.params.viewed_back or (self.params.viewed_back and G.GAME.viewed_back or G.GAME.selected_back)) + or Back(G.P_CENTERS["b_red"]) + if currentBack.effect.config.cry_force_edition and not currentBack.effect.config.cry_antimatter then + if currentBack.effect.config.cry_force_edition_shader then + self.children.back:draw_shader( + currentBack.effect.config.cry_force_edition_shader, + nil, + self.ARGS.send_to_shader, + true + ) + else + self.children.back:draw_shader( + currentBack.effect.config.cry_force_edition, + nil, + self.ARGS.send_to_shader, + true + ) + end + end + if + currentBack.effect.config.cry_force_seal + and not currentBack.effect.config.hide_seal + and not currentBack.effect.config.cry_antimatter + then + G.shared_seals[currentBack.effect.config.cry_force_seal]:draw_shader( + "dissolve", + nil, + nil, + true, + self.children.center + ) + if currentBack.effect.config.cry_force_seal == "Gold" then + G.shared_seals[currentBack.effect.config.cry_force_seal]:draw_shader( + "voucher", + nil, + self.ARGS.send_to_shader, + true, + self.children.center + ) + end + end + if currentBack.effect.config.cry_force_sticker and not currentBack.effect.config.cry_antimatter then + for k, v in pairs(SMODS.Stickers) do + if currentBack.effect.config.cry_force_sticker == v.key then + if v and v.draw and type(v.draw) == "function" then + v:draw(self) + else + G.shared_stickers[v.key].role.draw_major = self + G.shared_stickers[v.key]:draw_shader("dissolve", nil, nil, true, self.children.center) + G.shared_stickers[v.key]:draw_shader( + "voucher", + nil, + self.ARGS.send_to_shader, + true, + self.children.center + ) + end + end + end + end + if + currentBack.effect.config.cry_antimatter + or currentBack.effect.config.cry_force_edition == "negative" + then + self.children.back:draw_shader("negative", nil, self.ARGS.send_to_shader, true) + self.children.center:draw_shader("negative_shine", nil, self.ARGS.send_to_shader, true) + end + if currentBack.effect.center.edeck_type then + local edition, enhancement, sticker, suit, seal = Cryptid.enhanced_deck_info(currentBack) + local sprite = Cryptid.edeck_atlas_update(currentBack.effect.center) + self.children.back.atlas = G.ASSET_ATLAS[sprite.atlas] or self.children.back.atlas + self.children.back.sprite_pos = sprite.pos + self.children.back:reset() + if currentBack.effect.center.edeck_type == "edition" then + self.children.back:draw_shader(edition, nil, self.ARGS.send_to_shader, true) + if edition == "negative" then + self.children.back:draw_shader("negative", nil, self.ARGS.send_to_shader, true) + self.children.center:draw_shader("negative_shine", nil, self.ARGS.send_to_shader, true) + end + end + if currentBack.effect.center.edeck_type == "seal" then + G.shared_seals[seal]:draw_shader("dissolve", nil, nil, true, self.children.center) + if seal == "Gold" then + G.shared_seals[seal]:draw_shader( + "voucher", + nil, + self.ARGS.send_to_shader, + true, + self.children.center + ) + end + end + if currentBack.effect.center.edeck_type == "sticker" then + for k, v in pairs(SMODS.Stickers) do + if sticker == v.key then + if v and v.draw and type(v.draw) == "function" then + v:draw(self) + else + G.shared_stickers[v.key].role.draw_major = self + G.shared_stickers[v.key]:draw_shader("dissolve", nil, nil, true, self.children.center) + G.shared_stickers[v.key]:draw_shader( + "voucher", + nil, + self.ARGS.send_to_shader, + true, + self.children.center + ) + end + end + end + end + end + end + end, + conditions = { vortex = false, facing = "back" }, +}) +-- Third Layer +SMODS.DrawStep({ + key = "floating_sprite2", + order = 59, + func = function(self) + if self.ability.name == "cry-Gateway" and (self.config.center.discovered or self.bypass_discovery_center) then + local scale_mod2 = 0.07 -- + 0.02*math.cos(1.8*G.TIMERS.REAL) + 0.00*math.cos((G.TIMERS.REAL - math.floor(G.TIMERS.REAL))*math.pi*14)*(1 - (G.TIMERS.REAL - math.floor(G.TIMERS.REAL)))^3 + local rotate_mod2 = 0 --0.05*math.cos(1.219*G.TIMERS.REAL) + 0.00*math.cos((G.TIMERS.REAL)*math.pi*5)*(1 - (G.TIMERS.REAL - math.floor(G.TIMERS.REAL)))^2 + self.children.floating_sprite2:draw_shader( + "dissolve", + 0, + nil, + nil, + self.children.center, + scale_mod2, + rotate_mod2, + nil, + 0.1 --[[ + 0.03*math.cos(1.8*G.TIMERS.REAL)--]], + nil, + 0.6 + ) + self.children.floating_sprite2:draw_shader( + "dissolve", + nil, + nil, + nil, + self.children.center, + scale_mod2, + rotate_mod2 + ) + + local scale_mod = 0.05 + + 0.05 * math.sin(1.8 * G.TIMERS.REAL) + + 0.07 + * math.sin((G.TIMERS.REAL - math.floor(G.TIMERS.REAL)) * math.pi * 14) + * (1 - (G.TIMERS.REAL - math.floor(G.TIMERS.REAL))) ^ 3 + local rotate_mod = 0.1 * math.sin(1.219 * G.TIMERS.REAL) + + 0.07 + * math.sin(G.TIMERS.REAL * math.pi * 5) + * (1 - (G.TIMERS.REAL - math.floor(G.TIMERS.REAL))) ^ 2 + + self.children.floating_sprite.role.draw_major = self + self.children.floating_sprite:draw_shader( + "dissolve", + 0, + nil, + nil, + self.children.center, + scale_mod, + rotate_mod, + nil, + 0.1 + 0.03 * math.sin(1.8 * G.TIMERS.REAL), + nil, + 0.6 + ) + self.children.floating_sprite:draw_shader( + "dissolve", + nil, + nil, + nil, + self.children.center, + scale_mod, + rotate_mod + ) + end + if + self.config.center.soul_pos + and self.config.center.soul_pos.extra + and (self.config.center.discovered or self.bypass_discovery_center) + then + local scale_mod = 0.07 -- + 0.02*math.cos(1.8*G.TIMERS.REAL) + 0.00*math.cos((G.TIMERS.REAL - math.floor(G.TIMERS.REAL))*math.pi*14)*(1 - (G.TIMERS.REAL - math.floor(G.TIMERS.REAL)))^3 + local rotate_mod = 0 --0.05*math.cos(1.219*G.TIMERS.REAL) + 0.00*math.cos((G.TIMERS.REAL)*math.pi*5)*(1 - (G.TIMERS.REAL - math.floor(G.TIMERS.REAL)))^2 + self.children.floating_sprite2:draw_shader( + "dissolve", + 0, + nil, + nil, + self.children.center, + scale_mod, + rotate_mod, + nil, + 0.1 --[[ + 0.03*math.cos(1.8*G.TIMERS.REAL)--]], + nil, + 0.6 + ) + self.children.floating_sprite2:draw_shader( + "dissolve", + nil, + nil, + nil, + self.children.center, + scale_mod, + rotate_mod + ) + end + end, + conditions = { vortex = false, facing = "front" }, +}) +SMODS.draw_ignore_keys.floating_sprite2 = true + +-- Make hover UI collidable - so we can detect collision and display tooltips +local m = Card.move +function Card:move(dt) + m(self, dt) + if self.children.h_popup then + self.children.h_popup.states.collide.can = true + if not self:force_popup() and not self.states.hover.is then + self.children.h_popup:remove() + self.children.h_popup = nil + end + end +end + +-- This defines when we should show a card's description even when it's not hovered +function Card:force_popup() + -- Must be selected + if self.highlighted then + -- Remove all popups in the pause menu (collection excluded) + if G.SETTINGS.paused and not self.area.config.collection then + return false + end + -- Playing cards + if + self.config.center.set == "Default" + or self.config.center.set == "Base" + or self.config.center.set == "Enhanced" + then + return false + end + -- Incantation mod compat + if SMODS.Mods["incantation"] and self.area == G.consumeables then + return false + end + -- Other areas where it doesn't work well + if self.area == G.pack_cards then + return false + end + return true + end +end + +-- Hacky hook to make cards selectable in the collection +-- Unfortunately this doesn't play nicely with gameset UI +local cainit = CardArea.init +function CardArea:init(X, Y, W, H, config) + if config.collection then + config.highlight_limit = config.card_limit + end + return cainit(self, X, Y, W, H, config) +end + +-- Allow highlighting in the collection +local cach = CardArea.can_highlight +function CardArea:can_highlight(card) + if self.config.collection then + return true + end + return cach(self) +end + +-- Prevent hover UI from being redrawn +local ch = Card.hover +function Card:hover() + if self.children.h_popup then + return + end + ch(self) +end diff --git a/Cryptid/localization/de.lua b/Cryptid/localization/de.lua index b6ba870..effdd10 100644 --- a/Cryptid/localization/de.lua +++ b/Cryptid/localization/de.lua @@ -9,6 +9,21 @@ return { "von {C:attention}jedem{} Deck", }, }, + b_cry_antimatter_balanced = { + name = "Antimaterie Deck", + text = { + "Hat die {C:legendary,E:1}positiven Effekte{}", + "von {C:attention}jedem{} Deck", + "mit dem du {C:gold}Goldenen Einsatz{} gewonnen hast", + }, + }, + b_cry_beige = { + name = "Beiges Deck", + text = { + "{C:attention}Gewöhnliche{} Joker haben", + "{C:attention}vierfache{} Werte", + }, + }, b_cry_beta = { name = "Nostalgisches Deck", text = { @@ -604,6 +619,16 @@ return { "{C:inactive,s:0.8}Kopiert keine Nostalgischen Googol Play Karten{}", }, }, + j_cry_altgoogol_balanced = { + name = "Nostalgische Googol Play Karte", + text = { + "Verkaufe diese Karte um", + "{C:attention}#1#{} Kopie#1# von dem linkesten {C:attention}Joker{} zu machen", + "{C:inactive,s:0.8}Kopiert keine Nostalgischen Googol Play Karten{}", + "{C:inactive}(Muss Platz haben){}", + --todo: add "removes negative from copy" like Ankh/Invis Joker + }, + }, j_cry_antennastoheaven = { name = "...Wie Antennen zum Himmel", text = { @@ -774,6 +799,20 @@ return { "auf der rechten Seite hast", }, }, + j_cry_canvas_balanced = { + name = "Leinwand", + text = { + "{C:attention}Löse{} alle {C:attention}Jokers{} auf der linken Seite", + "{C:attention}so oft neu aus{} wie du nicht-{C:blue}Gewöhnliche{C:attention} Joker{}", + "auf der rechten Seite hast", + "{C:inactive}(Up to 2 retriggers)", + }, + unlock = { + "Löse einen {C:attention}Joker", + "{C:attention}114{} mal in einer", + "Hand erneut aus.", + }, + }, j_cry_caramel = { name = "Karamel", text = { @@ -1254,6 +1293,14 @@ return { "{C:inactive,s:0.8}Seems legit...{}", }, }, + j_cry_jtron = { + name = "Jimbo-tron 9000", + text = { + "Dieser Joker bekommt {X:dark_edition,C:white} ^#1# {} Mult", + "für jeden Standard {C:attention}Joker{}", + "{C:inactive}(Momentan {X:dark_edition,C:white}^#2#{C:inactive} Mult)", + }, + }, j_cry_kidnap = { name = "Entführung", text = { @@ -1288,6 +1335,14 @@ return { "wenn {C:attention}Boss Blind{} besiegt wird", }, }, + j_cry_lebaron_james = { + name = "LeBaron James", + text = { + "Gespeilte und gewertete {C:attention}Könige{} geben", + "{C:attention}+#1#{} Handgröße für diese Runde", + "und lösen {C:attention}in der Hand{} Effekte aus", + }, + }, j_cry_lightupthenight = { name = "Erläuchte die Nacht", text = { @@ -1418,7 +1473,7 @@ return { "{X:mult,C:white}X#1#{} Mult für jedes Mitglied", "im {C:attention}Cryptid Discord{}", "{C:inactive}(Momentan {X:mult,C:white}X#2#{C:inactive} Mult)", - "{C:blue,s:0.7}https://discord.gg/eUf9Ur6RyB{}", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", }, }, j_cry_membershipcardtwo = { @@ -1427,7 +1482,16 @@ return { "{C:chips}+#1#{} Chips für jedes Mitglied", "im {C:attention}Cryptid Discord{}", "{C:inactive}(Momentan {C:chips}+#2#{C:inactive} Chips)", - "{C:blue,s:0.7}https://discord.gg/eUf9Ur6RyB{}", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", + }, + }, + j_cry_membershipcardtwo_balanced = { + name = "Alte Mitgliedskarte", --Could probably have a diff Name imo + text = { + "{C:chips}+#1#{} Chip#1# für jedes Mitglied", + "im {C:attention}Cryptid Discord{}", + "{C:inactive}(Momentan {C:chips}+#2#{C:inactive} Chip#2#)", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", }, }, j_cry_meteor = { @@ -1833,6 +1897,20 @@ return { "{C:attention}+#1#{} Karte im Shop", }, }, + j_cry_soccer_balanced = { + name = "Einer für Alle", --changed the name from latin because this isn't exotic + text = { + "{C:attention}+#1#{} Joker Slot#1#", + "{C:attention}+#1#{} Booster Packer Slot#1#", + "{C:attention}+#1#{} Handgröße", + "{C:attention}+#1#{} Verbrauchsgegenstand Slot#1#", + "{C:attention}+#1#{} Karte#1# im Shop", + }, + unlock = { + "Gewinne einen Durchlauf", + "mit nur {C:attention}High Card", + }, + }, j_cry_fleshpanopticon = { name = "Fleischpanoptikum", text = { @@ -1910,6 +1988,14 @@ return { "Ende der Runde", }, }, + j_cry_supercell_balanced = { + name = "Supercell", + text = { + "{X:chips,C:white}X#2#{} Chips, {X:mult,C:white}X#2#{} Mult", + "Verdiene {C:money}$#3#{} am", + "Ende der Runde", + }, + }, j_cry_sus = { name = "SUS", text = { @@ -2220,6 +2306,29 @@ return { }, }, Sleeve = { + sleeve_cry_beige_sleeve = { + name = "Beige Hülle", + text = { + "{C:attention}Gewöhnliche{} Joker haben", + "{C:attention}vierfache{} Werte", + }, + }, + sleeve_cry_beige_sleeve_alt = { + name = "Beige Hülle", + text = { + "{C:attention}Ungewöhnliche{} Joker haben", + "{C:attention}vierfache{} Werte", + }, + }, + sleeve_cry_beta_sleeve = { + name = "Nostalgische Hülle", + text = { + "{C:attention}Joker{} und {C:attention}Verbrauchgegenstände{}", + "Slots sind {C:attention}zusammengefasst", + "{C:attention}Nostalgische{} Blinds ersetzen", + "ihre neuen Versionen.", + }, + }, sleeve_cry_bountiful_sleeve = { name = "Größzügige Hülle", text = { @@ -2269,6 +2378,15 @@ return { "{C:attention,T:v_overstock_plus}Überbestand Plus", }, }, + sleeve_cry_glowing_sleeve = { + name = "Glühende Hülle", + text = { + "Multipliziere die Werte", + "aller Joker mit {X:dark_edition,C:white} X1.25 {}", + "wenn die Boss Blind besiegt wurde.", + "{X:cry_jolly,C:white,s:0.8} Jolly#1#Open#1#Winner#1#-#1#wawa#1#person", + }, + }, sleeve_cry_infinite_sleeve = { name = "Unendliche Hülle", text = { @@ -2300,6 +2418,15 @@ return { "{C:cry_candy}Süßigkeit{} oder einen {X:cry_cursed,C:white}Verfluchten{} Joker", }, }, + sleeve_cry_very_fair_sleeve = { + name = "Sehr Faire Hülle", + text = { + "{C:blue}-2{} Hände, {C:red}-2{} Abwürfe", + "jede Runde", + "{C:attention}Gutscheine{} erscheinen", + "nicht mehr im Shop", + }, + }, sleeve_cry_wormhole_sleeve = { name = "Wurmlochhülle", text = { @@ -3443,6 +3570,72 @@ return { }, }, misc = { + tutorial = { + cry_intro_1 = { + "Hallo, ich bin {C:attention}Joseph J. Joker{}!", + "Wilkommen zu {C:cry_exotic,E:1}Cryptid{}!", + }, + cry_intro_2 = { + "Sieht aus als hättest du auf diesem Profil", + "noch nie {C:cry_exotic,E:1}Cryptid{} genutzt.", + "Lass mich dir zeigen wie es funktioniert!", + }, + cry_intro_3 = { + "*wächst hände*", + }, + cry_intro_4 = { + "Es ist schwer dieses Mod in nur", + "einigen Sätzen zu beschreiben, aber was ich sagen kann", + "ist, dass es jetzt {C:cry_exotic,E:1}wild{} wird!", + "Das ist nicht das selbe {C:attention}Joker Poker{} das du kennst...", + }, + cry_intro_5 = { + "Wie du von diesen {C:cry_ascendant}Gamesets{}", + "sehen kannst, mag ich den Buchstaben {C:attention}M{}.", + "Wähle ein Gameset das ich erklähren soll...", + "{s:0.8}Achtung: An Gamesets wird immernoch gearbeitet.", + "{s:0.8}Erwarte regelmäßige Änderungen!", + }, + cry_modest_1 = { + "Suchst du eine Erfahrung ähnlich zu Vanilla?", + "Dann ist das {C:cry_ascendant}Modest{} Gameset für dich!", + }, + cry_modest_2 = { + "Aber halte trotzdem die Augen offen für all", + "den Schabernack in Cryptid! Du weißt nie", + "was du in der nächsten Runde findest...", + }, + cry_mainline_1 = { + "Willst du das Spiel gerne {E:1,C:attention}zerstören{}? Gute Nachichten!", + "Du kannst es machen ohne komplett durchzudrehen.", + }, + cry_mainline_2 = { + "Hier ist es immernoch verrückt, aber du hast die", + "Chance das {C:cry_ascendant}Fortschrittsystem{} zu", + "erfahren. Aber werde nicht zu gemütlich...", + }, + cry_mainline_3 = { + "Weil du stärker sein wirst,", + "habe ich einige {E:1,C:dark_edition}Bosse{} die", + "dich deine Wahl bereuen lassen könnten.", + }, + cry_madness_1 = { + "Willst du deine Festplatte komplett {C:red,E:1}vernichten{}?", + "Oh, was ein Spaß! Das {C:cry_ascendant}Madness{} Gameset sagt", + "'Balance? {E:1,C:red}WAS IST DAS DEN!?{}'", + }, + cry_madness_2 = { + "Ich habe viele schlaflose Wochen, {C:green}Mountain Dew{}-angetriebene", + "Nächte verbracht um sicherzustellen, dass dieses Gameset für dich", + "{C:cry_ascendant}PERFEKT BALANCIERT{} ist!", + }, + cry_madness_3 = { + "Du beginnst mit allem freigeschaltet, also", + "kannst du die {C:red,E:1}volle Macht{} von Cryptid sofort nutzen!", + "Sei nur vorsichtig, dass das Spiel nicht {C:attention,E:1}abstürzt{},", + "da das Warscheinlich passiert bevor du verlierst...", + }, + }, poker_hands = { ["cry_Bulwark"] = "Bollwerk", ["cry_Clusterfuck"] = "Clusterfuck", @@ -3633,6 +3826,26 @@ return { cry_notif_jimball_d1 = 'Jimball spielt den Song "Funkytown",', cry_notif_jimball_d2 = "welcher urheberrechtlich geschützt ist und nicht", cry_notif_jimball_d3 = "für Streams und Videos genutzt werden kann.", + + cry_gameset_explanation = { + "Wähle eine Gameset Konfiguartion", + "für diese Karte.", + }, + cry_gameset_disabled = "Deaktiviert", + cry_gameset_modest = "Modest", + cry_gameset_mainline = "Mainline", + cry_gameset_madness = "Madness", + cry_gameset_custom = "Modifiziert", + cry_gameset_exp = "Experimentel", + cry_gameset_exp_modest = "Experimentel (Modest)", + cry_gameset_exp_mainline = "Experimentel (Mainline)", + cry_gameset_exp_madness = "Experimentel (Madness)", + + cry_view_set_contents = "Siehe Gegenstände im set", + + b_reset_gameset_modest = "Setzt Gameset Konfiguaration zurück (Modest)", + b_reset_gameset_mainline = "Setzt Gameset Konfiguaration zurück (Mainline)", + b_reset_gameset_madness = "Setzt Gameset Konfiguaration zurück (Madness)", }, labels = { food_jokers = "Essen Joker", @@ -3804,9 +4017,9 @@ return { { "VERSUCHST SPÄTER NOCHMAL", "HINWEIS: DU WIRST NICHT", "GENUG GELD HABEN" }, { "HÄ?", '"GUTSCHEINE"?', "DAS IST NICHTMAL EIN WORT..." }, { 'HALTE "R"', "UM ALLE GUTSCHEINE", "NACHZUFÜLLEN" }, - { "WÜSSTEST DU?", "ALT+F4 DRÜCKEN", "GIBT KOSTENLOSE GUTSCHEINE!" }, + { "WUSSTEST DU?", "ALT+F4 DRÜCKEN", "GIBT KOSTENLOSE GUTSCHEINE!" }, { "TUHT MIR LEID,", "ES GIBT KEINE GUTSCHEINE", "WEGEN BUDGETVERKÜRZUNGEN" }, - { "RUFE 1-600-JIMBO AN", "UM DEINE ERFAHRUNG MIR", "GUTSCHEINEN ZU BEWERTEN" }, + { "RUFE 1-600-JIMBO AN", "UM DEINE ERFAHRUNG MIT", "GUTSCHEINEN ZU BEWERTEN" }, { "BESIEGE", "ANTE 39 BOSS BLIND", "ZUM NACHFÜLLEN" }, { "ZAUBERTRICK", "ICH HABE DIESEN GUTSCHEIN", "VERSCHWINDEN LASSEN" }, { "WARUM IST EIN", "GUTSCHEIN WIE EIN", "SCHREIBTISCH?" }, @@ -3827,11 +4040,11 @@ return { { "ES GIBT KEINEN", "WEINACHTSMANN", "UND AUCH KEINE GUTSCHEINE" }, { "", "GUTNEIN", "" }, { "DU", "HAST GERADE", "DAS SPIEL VERLOREN" }, - { "CAN ICH DIR IN DIESEN", "IN DIESEN SCHWEREN ZEITEN", "EIN SCHÖNES EI ANBIETEN?" }, - { "BERÜHRE ETWAS GRASS", "ANSTATT DIESES", "DECK ZU BENUZEN" }, + { "KANN ICH DIR IN DIESEN", "IN DIESEN SCHWEREN ZEITEN", "EIN SCHÖNES EI ANBIETEN?" }, + { "BERÜHRE ETWAS GRASS", "ANSTATT DIESES", "DECK ZU BENUTZEN" }, { "DU KÖNNTEST JETZT", "GERADE MIT DEM BLAUEN", "DECK SPEILEN" }, { "KOSTENLOSE EXOTISCHE JOKER", "HOHLE SIE BEVOR", "ES ZU SPÄT IST (ausverkauft)" }, - { "DU KANNST BEWEISEN, DASS", "ICH FALSCH LIEGE INDEM", "DU DEN UNSICHBAREN GUTSCHEIN KAUFST" }, + { "DU KANNST BEWEISEN, DASS", "ICH FALSCH LIEGE INDEM", "DU DEN UNSICHTBAREN GUTSCHEIN KAUFST" }, { "", "keine gutscheine?", "" }, { "siehst du diese werbung?", diff --git a/Cryptid/localization/en-us.lua b/Cryptid/localization/en-us.lua index 50aaae8..9b11069 100644 --- a/Cryptid/localization/en-us.lua +++ b/Cryptid/localization/en-us.lua @@ -8,6 +8,14 @@ return { "of {C:attention}every{} deck", }, }, + b_cry_antimatter_balanced = { + name = "Antimatter Deck", + text = { + "Applies the {C:legendary,E:1}upsides{}", + "of {C:attention}every{} deck won", + "with {C:gold}Gold Stake{}", + }, + }, b_cry_beige = { name = "Beige Deck", text = { @@ -384,7 +392,7 @@ return { c_cry_class = { name = "://CLASS", text = { - "Convert {C:cry_code}#1#{} selected card#s1#", + "Convert {C:cry_code}#1#{} selected card#1#", "to a {C:cry_code}chosen{} enhancement", }, }, @@ -493,8 +501,8 @@ return { name = "://OFFBYONE", text = { "Next {C:cry_code}Booster Pack{} has", - "{C:cry_code}#1#{} extra card#s1# and", - "{C:cry_code}#1#{} extra choice#s1#", + "{C:cry_code}#1#{} extra card#1# and", + "{C:cry_code}#1#{} extra choice#1#", "{C:inactive}(Currently {C:cry_code}+#2#{C:inactive})", }, }, @@ -551,7 +559,7 @@ return { c_cry_variable = { name = "://VARIABLE", text = { - "Convert {C:cry_code}#1#{} selected card#s1#", + "Convert {C:cry_code}#1#{} selected card#1#", "to a {C:cry_code}chosen{} rank", }, }, @@ -695,7 +703,7 @@ return { "card {C:attention}1{} time", "{C:green}#1# in #2#{} chance", "to retrigger {C:attention}#3#{}", - "additional time#s3#", + "additional time#3#", }, }, e_cry_double_sided = { @@ -771,14 +779,14 @@ return { text = { "{C:green}#2# in #3#{} chance to", "{C:attention}retrigger{} #1# additional", - "time#s1# when scored", + "time#1# when scored", }, }, m_cry_light = { name = "Light Card", text = { "When triggered with {C:attention}#4#{} {C:inactive}(#3#){} other", - "scoring card#s4#, gain {X:mult,C:white}X#1#{} Mult and", + "scoring card#4#, gain {X:mult,C:white}X#1#{} Mult and", "increase requirement by {C:attention}5{}", "{C:inactive}(Currently {X:mult,C:white}X#2#{C:inactive} Mult)", }, @@ -788,34 +796,34 @@ return { j_cry_test_modest = { name = "Test Joker", text = { - "{C:chips}+#1#{} Chip#s1#", + "{C:chips}+#1#{} Chip#1#", }, }, j_cry_test_mainline = { name = "Test Joker", text = { - "{C:chips}+#1#{} Chip#s1#", + "{C:chips}+#1#{} Chip#1#", "{C:money}+$44{} at start of {C:attention}Blind{}", }, }, j_cry_test_madness = { name = "Test Joker", text = { - "{C:chips}+#1#{} Chip#s1#", + "{C:chips}+#1#{} Chip#1#", "{C:money}+$44444{} at start of {C:attention}Blind{}", }, }, j_cry_test_cryptid_in_2025 = { name = "Test Joker", text = { - "{C:chips}+#1#{} Chip#s1#", + "{C:chips}+#1#{} Chip#1#", "{C:money}+$44444{} at start of {C:attention}Blind{}", }, }, j_cry_adroit = { name = "Adroit Joker", text = { - "{C:chips}+#1#{} Chip#s1# if played", + "{C:chips}+#1#{} Chip#1# if played", "hand contains", "a {C:attention}#2#", }, @@ -824,10 +832,20 @@ return { name = "Nostalgic Googol Play Card", text = { "Sell this card to create", - "{C:attention}#1#{} cop#y1# of the leftmost {C:attention}Joker{}", + "{C:attention}#1#{} cop#1# of the leftmost {C:attention}Joker{}", "{C:inactive,s:0.8}Does not copy Nostalgic Googol Play Cards{}", }, }, + j_cry_altgoogol_balanced = { + name = "Nostalgic Googol Play Card", + text = { + "Sell this card to create", + "{C:attention}#1#{} cop#1# of the leftmost {C:attention}Joker{}", + "{C:inactive,s:0.8}Does not copy Nostalgic Googol Play Cards{}", + "{C:inactive}(Must have room){}", + --todo: add "removes negative from copy" like Ankh/Invis Joker + }, + }, j_cry_antennastoheaven = { name = "...Like Antennas to Heaven", text = { @@ -858,6 +876,21 @@ return { "a random {C:attention}Joker{}", }, }, + j_cry_astral_bottle_mainline = { + name = "Astral in a Bottle", + text = { + "When sold, apply {C:dark_edition}Astral{}", + "and {C:attention}Perishable{} to", + "different, random {C:attention}Jokers{}", + }, + }, + j_cry_astral_bottle_madness = { + name = "Astral in a Bottle", + text = { + "When sold, apply {C:dark_edition}Astral{}", + "to a random {C:attention}Joker{}", + }, + }, j_cry_big_cube = { name = "Big Cube", text = { @@ -895,17 +928,17 @@ return { j_cry_blurred = { name = "Blurred Joker", text = { - "Gain {C:blue}+#1#{} hand#s1# when", + "Gain {C:blue}+#1#{} hand#1# when", "{C:attention}Blind{} is selected", }, }, j_cry_bonk = { name = "Bonk", text = { - "Each {C:attention}Joker{} gives {C:chips}+#1#{} Chip#s1#", + "Each {C:attention}Joker{} gives {C:chips}+#1#{} Chip#1#", "Increase amount by {C:chips}+#2#{} if", "{C:attention} poker hand{} is a {C:attention}#3#{}", - "{C:inactive,s:0.8}Jolly Jokers give{} {C:chips,s:0.8}+#4#{} {C:inactive,s:0.8}Chip#s4# instead{}", + "{C:inactive,s:0.8}Jolly Jokers give{} {C:chips,s:0.8}+#4#{} {C:inactive,s:0.8}Chip#4# instead{}", }, }, j_cry_bonkers = { @@ -930,7 +963,7 @@ return { j_cry_booster = { name = "Booster Joker", text = { - "{C:attention}+#1#{} Booster Pack slot#s1#", + "{C:attention}+#1#{} Booster Pack slot#1#", "available in shop", }, }, @@ -951,7 +984,7 @@ return { j_cry_brittle = { name = "Brittle Candy", text = { - "For the next {C:attention}#1#{} hand#s1#,", + "For the next {C:attention}#1#{} hand#1#,", "add {C:attention}Stone{}, {C:attention}Gold{}, or {C:attention}Steel{} to", "the rightmost scoring card", }, @@ -977,22 +1010,22 @@ return { j_cry_candy_basket = { name = "Candy Basket", text = { - "Sell this card to create {C:attention}#1#{} {C:cry_candy}Cand#y1#", - "{C:attention}+#2#{} {C:cry_candy}Cand#y2#{} every {C:attention}2{} Blinds defeated", - "{C:attention}+#3#{} {C:cry_candy}Cand#y3#{} when {C:attention}Boss Blind{} defeated", + "Sell this card to create {C:attention}#1#{} {C:cry_candy}Cand#1#", + "{C:attention}+#2#{} {C:cry_candy}Cand#2#{} every {C:attention}2{} Blinds defeated", + "{C:attention}+#3#{} {C:cry_candy}Cand#3#{} when {C:attention}Boss Blind{} defeated", }, }, j_cry_candy_buttons = { name = "Candy Buttons", text = { - "The next {C:attention}#1#{} reroll#s1#", + "The next {C:attention}#1#{} reroll#1#", "cost {C:money}$1{}", }, }, j_cry_candy_cane = { name = "Candy Cane", text = { - "For the next {C:attention}#1#{} round#s1#,", + "For the next {C:attention}#1#{} round#1#,", "playing cards give {C:money}$#2#", "when {C:attention}retriggered", }, @@ -1009,7 +1042,7 @@ return { name = "Candy Sticks", text = { "Next boss blind's effect isn't active", - "until you've played {C:attention}#1#{} hand#s1#", + "until you've played {C:attention}#1#{} hand#1#", }, }, j_cry_canvas = { @@ -1025,19 +1058,33 @@ return { "in one hand", }, }, + j_cry_canvas_balanced = { + name = "Canvas", + text = { + "{C:attention}Retrigger{} all {C:attention}Jokers{} to the left", + "once for {C:attention}every{} non-{C:blue}Common{C:attention} Joker{}", + "to the right of this Joker", + "{C:inactive}(Up to 2 retriggers)", + }, + unlock = { + "Retrigger a {C:attention}Joker", + "{C:attention}114{} times", + "in one hand", + }, + }, j_cry_caramel = { name = "Caramel", text = { "Each played card gives", "{X:mult,C:white}X#1#{} Mult when scored", - "for the next {C:attention}#2#{} round#s2#", + "for the next {C:attention}#2#{} round#2#", }, }, j_cry_chad = { name = "Chad", text = { "Retrigger {C:attention}leftmost{} Joker", - "{C:attention}#1#{} additional time#s1#", + "{C:attention}#1#{} additional time#1#", }, }, j_cry_chili_pepper = { @@ -1045,7 +1092,7 @@ return { text = { "This Joker gains {X:mult,C:white} X#2# {} Mult", "at end of round,", - "{C:red,E:2}self destructs{} after {C:attention}#3#{} round#s3#", + "{C:red,E:2}self destructs{} after {C:attention}#3#{} round#3#", "{C:inactive}(Currently{} {X:mult,C:white} X#1# {} {C:inactive}Mult){}", }, }, @@ -1063,7 +1110,7 @@ return { text = { "{X:dark_edition,C:white}^#1#{} Chips and {X:dark_edition,C:white}^#1#{} Mult", "if {C:attention}exactly{} #2#", - "hand#s2# remaining", + "hand#2# remaining", }, }, j_cry_circus = { @@ -1096,8 +1143,8 @@ return { j_cry_clicked_cookie = { name = "Clicked Cookie", text = { - "{C:chips}+#1#{} Chip#s1#", - "{C:chips}-#2#{} Chip#s2# when", + "{C:chips}+#1#{} Chip#1#", + "{C:chips}-#2#{} Chip#2# when", "you {C:attention}click", }, }, @@ -1113,6 +1160,18 @@ return { "{C:cry_code}Code Card", }, }, + j_cry_CodeJoker_modest = { + name = "Code Joker", + text = { + "Create a {C:dark_edition}Negative{}", + "{C:cry_code}Code Card{} when", + "{C:attention}Boss Blind{} is selected", + }, + unlock = { + "Discover {C:attention}every", + "{C:cry_code}Code Card", + }, + }, j_cry_coin = { name = "Crypto Coin", text = { @@ -1139,7 +1198,15 @@ return { "{C:inactive}(Must have room)", }, }, - j_cry_copypaste2 = { + j_cry_copypaste_modest = { + name = "Copy/Paste", + text = { + "Duplicate pulled", + "{C:cry_code}Code{} cards", + "{C:inactive}(Must have room)", + }, + }, + j_cry_copypaste_madness = { name = "Copy/Paste", text = { "{C:green}#1# in #2#{} chance to duplicate", @@ -1157,10 +1224,10 @@ return { j_cry_crustulum = { name = "Crustulum", text = { - "This Joker gains {C:chips}+#2#{} Chip#s1#", + "This Joker gains {C:chips}+#2#{} Chip#1#", "per {C:attention}reroll{} in the shop", "{C:green}All rerolls are free{}", - "{C:inactive}(Currently {C:chips}+#1#{C:inactive} chip#s1#)", + "{C:inactive}(Currently {C:chips}+#1#{C:inactive} chip#1#)", }, }, j_cry_cryptidmoment = { @@ -1174,7 +1241,7 @@ return { j_cry_cube = { name = "Cube", text = { - "{C:chips}+#1#{} Chip#s1#", + "{C:chips}+#1#{} Chip#1#", }, }, j_cry_curse_sob = { @@ -1193,9 +1260,9 @@ return { j_cry_cursor = { name = "Cursor", text = { - "This Joker gains {C:chips}+#2#{} Chip#s2#", + "This Joker gains {C:chips}+#2#{} Chip#2#", "for each card {C:attention}purchased{}", - "{C:inactive}(Currently {C:chips}+#1#{C:inactive} Chip#s1#)", + "{C:inactive}(Currently {C:chips}+#1#{C:inactive} Chip#1#)", }, }, j_cry_cut = { @@ -1251,6 +1318,14 @@ return { "{C:inactive,s:0.8}(grows by +1, +2, +3)", }, }, + ["j_cry_Double Scale_modest"] = { + name = "Double Scale", + text = { + "Scaling {C:attention}Jokers{}", + "scale {C:attention}twice{} as fast", + '{C:inactive,s:0.8}"It\'s called double scale, not quadratic scale!"', + }, + }, j_cry_dropshot = { name = "Dropshot", text = { @@ -1308,7 +1383,7 @@ return { name = "Energia", text = { "When a {C:attention}Tag{} is acquired,", - "create up to {C:attention}#1#{} cop#y1# of it", + "create up to {C:attention}#1#{} cop#1# of it", "and {C:attention}increase{} the number of", "copies by {C:attention}#2#", }, @@ -1318,7 +1393,7 @@ return { text = { "Jokers appear using the", "order from the {C:attention}Collection{}", - "Create {C:attention}#1#{} {C:dark_edition}Negative{} Joker#s1#", + "Create {C:attention}#1#{} {C:dark_edition}Negative{} Joker#1#", "when hand is played", "{C:cry_exotic,s:0.8}Exotic {C:inactive,s:0.8}or better Jokers cannot appear", "{s:0.8}Last Joker Generated: {C:attention,s:0.8}#2#", @@ -1350,7 +1425,7 @@ return { j_cry_exoplanet = { name = "Exoplanet", text = { - "{C:dark_edition}Holographic{} cards", + "Other {C:dark_edition}Holographic{} cards", "each give {C:mult}+#1#{} Mult", }, }, @@ -1365,8 +1440,8 @@ return { j_cry_exposed = { name = "Exposed", text = { - "Retrigger all non-{C:attention}face{} cards", - "{C:attention}#1#{} additional time#s1#", + "Retrigger all scored non-{C:attention}face{} cards", + "{C:attention}#1#{} additional time#1#", "All {C:attention}face{} cards are debuffed", }, }, @@ -1415,7 +1490,7 @@ return { name = "Fast Food M", text = { "{C:mult}+#1#{} Mult", - "{C:red,E:2}self destructs{} in {C:attention}#2#{} round#s2#", + "{C:red,E:2}self destructs{} in {C:attention}#2#{} round#2#", "Increases by {C:attention}#3#{} round when", "{C:attention}Jolly Joker{} is {C:attention}sold{}", "{C:inactive,s:0.8}2 McDoubles, 2 McChickens{}", @@ -1434,7 +1509,7 @@ return { name = "Formidiulosus", text = { "When a {X:cry_cursed,C:white}Cursed{} Joker is obtained, destroy it", - "Creates {C:attention}#1#{} {C:dark_edition}Negative {C:cry_candy}Cand#y1#{} at end of shop", + "Creates {C:attention}#1#{} {C:dark_edition}Negative {C:cry_candy}Cand#1#{} at end of shop", "Gains {X:dark_edition,C:white}^#2#{} Mult for each {C:cry_candy}Candy{} in possession", "{C:inactive}(Currently {X:dark_edition,C:white}^#3#{C:inactive} Mult)", }, @@ -1442,7 +1517,7 @@ return { j_cry_foxy = { name = "Foxy Joker", text = { - "{C:chips}+#1#{} Chip#s1# if played", + "{C:chips}+#1#{} Chip#1# if played", "hand contains", "a {C:attention}#2#", }, @@ -1450,10 +1525,10 @@ return { j_cry_fspinner = { name = "Fidget Spinner", text = { - "This Joker gains {C:chips}+#2#{} Chip#s2#", + "This Joker gains {C:chips}+#2#{} Chip#2#", "if hand played is {C:attention}not{}", "most played {C:attention}poker hand{}", - "{C:inactive}(Currently {C:chips}+#1#{C:inactive} Chip#s1#)", + "{C:inactive}(Currently {C:chips}+#1#{C:inactive} Chip#1#)", }, }, j_cry_fuckedup = { @@ -1557,11 +1632,18 @@ return { "using a {C:attention}consumable{}", }, }, + j_cry_huntingseason = { + name = "Hunting Season", + text = { + "If played hand contains exactly {C:attention}3{} cards,", + "{C:red}destroy{} the {C:attention}center{} card after scoring", + }, + }, j_cry_iterum = { name = "Iterum", text = { "Retrigger all cards played", - "{C:attention}#2#{} time#s2#,", + "{C:attention}#2#{} time#2#,", "each played card gives", "{X:mult,C:white} X#1# {} Mult when scored", }, @@ -1600,6 +1682,14 @@ return { "{C:inactive,s:0.8}Seems legit...{}", }, }, + j_cry_jtron = { + name = "Jimbo-tron 9000", + text = { + "This Joker gains {X:dark_edition,C:white} ^#1# {} Mult", + "for each default {C:attention}Joker{}", + "{C:inactive}(Currently {X:dark_edition,C:white}^#2#{C:inactive} Mult)", + }, + }, j_cry_kidnap = { name = "Kidnapping", text = { @@ -1609,6 +1699,14 @@ return { "{C:attention}Type Chips{} Joker is sold", }, }, + j_cry_kittyprinter = { + name = "Kitty Printer", + text = { + "{X:mult,C:white} X#1# {} Mult", + "All {C:attention}skip{} tags", + "become {C:attention}Cat Tags{}", + }, + }, j_cry_kooky = { name = "Kooky Joker", text = { @@ -1640,6 +1738,14 @@ return { "{C:attention}Jokers", }, }, + j_cry_lebaron_james = { + name = "LeBaron James", + text = { + "Played and scoring {C:attention}Kings{} give", + "{C:attention}+#1#{} hand size for the round", + "and trigger {C:attention}held in hand{} effects", + }, + }, j_cry_lightupthenight = { name = "Light Up the Night", text = { @@ -1662,7 +1768,7 @@ return { "{C:attention}Retrigger{} all Jokers", "once for each {C:attention}Jolly{}", "{C:attention}Joker{} sold this round", - "{C:inactive}(Currently{}{C:attention:} #1#{}{C:inactive} retrigger#s1#){}", + "{C:inactive}(Currently{}{C:attention:} #1#{}{C:inactive} retrigger#1#){}", "{C:inactive,s:0.8}There wasn't enough room...{}", }, }, @@ -1703,7 +1809,7 @@ return { "When {C:attention}Blind{} is selected,", "destroys each {C:attention}Joker{} except", "{C:legendary}M Jokers{} and {C:attention}Jolly Jokers{}", - "and create #1# {C:attention}Jolly Joker#s1#{}", + "and create #1# {C:attention}Jolly Joker#1#{}", "for each destroyed card", }, }, @@ -1727,14 +1833,14 @@ return { name = "Mario", text = { "Retrigger all Jokers", - "{C:attention}#1#{} additional time#s1#", + "{C:attention}#1#{} additional time#1#", }, }, j_cry_mask = { name = "Mask", text = { - "Retrigger all {C:attention}face{} cards", - "{C:attention}#1#{} additional time#s1#", + "Retrigger all scored {C:attention}face{} cards", + "{C:attention}#1#{} additional time#1#", "All non-{C:attention}face{} cards are debuffed", }, }, @@ -1782,23 +1888,32 @@ return { "{X:mult,C:white}X#1#{} Mult for each member", "in the {C:attention}Cryptid Discord{}", "{C:inactive}(Currently {X:mult,C:white}X#2#{C:inactive} Mult)", - "{C:blue,s:0.7}https://discord.gg/eUf9Ur6RyB{}", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", }, }, j_cry_membershipcardtwo = { name = "Old Membership Card", --Could probably have a diff Name imo text = { - "{C:chips}+#1#{} Chip#s1# for each member", + "{C:chips}+#1#{} Chip#1# for each member", "in the {C:attention}Cryptid Discord{}", - "{C:inactive}(Currently {C:chips}+#2#{C:inactive} Chip#s2#)", - "{C:blue,s:0.7}https://discord.gg/eUf9Ur6RyB{}", + "{C:inactive}(Currently {C:chips}+#2#{C:inactive} Chip#2#)", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", + }, + }, + j_cry_membershipcardtwo_balanced = { + name = "Old Membership Card", --Could probably have a diff Name imo + text = { + "{C:chips}+#1#{} Chip#1# for every {C:attention}8{} members", + "in the {C:attention}Cryptid Discord{}", + "{C:inactive}(Currently {C:chips}+#2#{C:inactive} Chip#2#)", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", }, }, j_cry_meteor = { name = "Meteor Shower", text = { - "{C:dark_edition}Foil{} cards each", - "give {C:chips}+#1#{} Chip#s1#", + "Other {C:dark_edition}Foil{} cards each", + "give {C:chips}+#1#{} Chip#1#", }, }, j_cry_mneon = { @@ -1827,7 +1942,7 @@ return { "destroy Joker to the left", "and permanently add {C:attention}ten times{}", "its sell value to this {C:chips}Chips{}", - "{C:inactive}(Currently {C:chips}+#1#{C:inactive} Chip#s1#)", + "{C:inactive}(Currently {C:chips}+#1#{C:inactive} Chip#1#)", }, }, j_cry_monopoly_money = { @@ -1862,7 +1977,7 @@ return { text = { "Retrigger all cards played", "once for every", - "{C:attention}#2#{} {C:inactive}[#3#]{} {C:attention}Jolly Joker#s2#{} sold", + "{C:attention}#2#{} {C:inactive}[#3#]{} {C:attention}Jolly Joker#2#{} sold", "{C:inactive}(Currently{}{C:attention:} #1#{}{C:inactive} retriggers){}", }, }, @@ -1886,13 +2001,13 @@ return { j_cry_negative = { name = "Negative Joker", text = { - "{C:dark_edition}+#1#{C:attention} Joker{} slot#s1#", + "{C:dark_edition}+#1#{C:attention} Joker{} slot#1#", }, }, j_cry_nice = { name = "Nice", text = { - "{C:chips}+#1#{} Chip#s1# if played hand", + "{C:chips}+#1#{} Chip#1# if played hand", "contains a {C:attention}6{} and a {C:attention}9", "{C:inactive,s:0.8}Nice.{}", }, @@ -1910,14 +2025,14 @@ return { name = "No Sound, No Memory", text = { "Retrigger each played {C:attention}7{}", - "{C:attention:}#1#{} additional time#s1#", + "{C:attention:}#1#{} additional time#1#", }, }, j_cry_notebook = { - name = "Notebook", + name = "The Motebook", text = { "{C:green} #1# in #2#{} chance to gain {C:dark_edition}+#6#{} Joker", - "slot#s6# per {C:attention}reroll{} in the shop", + "slot#6# per {C:attention}reroll{} in the shop", "{C:green}Always triggers{} if there are", "{C:attention}#5#{} or more {C:attention}Jolly Jokers{}", "{C:red}Works once per round{}", @@ -2101,7 +2216,7 @@ return { j_cry_redbloon = { name = "Red Bloon", text = { - "Earn {C:money}$#1#{} in {C:attention}#2#{} round#s2#", + "Earn {C:money}$#1#{} in {C:attention}#2#{} round#2#", "{C:red,E:2}self destructs{}", }, }, @@ -2148,8 +2263,8 @@ return { j_cry_sacrifice = { name = "Sacrifice", text = { - "Create #3# {C:green}Uncommon{} Joker#s3#", - "and #2# {C:attention}Jolly Joker#s2#{} when", + "Create #3# {C:green}Uncommon{} Joker#3#", + "and #2# {C:attention}Jolly Joker#2#{} when", "a {C:spectral}Spectral{} card is used", "{C:red}Works once per round{}", "{C:inactive}#1#{}", @@ -2160,13 +2275,13 @@ return { text = { "After scoring {C:attention}#2#{} {C:inactive}[#1#]{} Enhanced", "cards, sell this card to", - "create a(n) {V:1}#3#{} {C:attention}Joker{}", + "create #4# {V:1}#3#{} {C:attention}Joker{}", }, }, j_cry_savvy = { name = "Savvy Joker", text = { - "{C:chips}+#1#{} Chip#s1# if played", + "{C:chips}+#1#{} Chip#1# if played", "hand contains", "a {C:attention}#2#", }, @@ -2179,6 +2294,7 @@ return { "raise degree by {C:attention}#2#{}", "at end of round", "{C:inactive,s:0.8}({C:attention,s:0.8}Scalae{C:inactive,s:0.8} excluded)", + "{C:inactive,s:0.8}(ex. +1, +#3#, +#4#, +#5#)", }, }, j_cry_scrabble = { @@ -2199,7 +2315,7 @@ return { j_cry_shrewd = { name = "Shrewd Joker", text = { - "{C:chips}+#1#{} Chip#s1# if played", + "{C:chips}+#1#{} Chip#1# if played", "hand contains", "a {C:attention}#2#", }, @@ -2224,12 +2340,26 @@ return { j_cry_soccer = { name = "One for All", --changed the name from latin because this isn't exotic text = { - "{C:attention}+#1#{} Joker slot#s1#", - "{C:attention}+#1#{} Booster Pack slot#s1#", + "{C:attention}+#1#{} Joker slot#1#", + "{C:attention}+#1#{} Booster Pack slot#1#", "{C:attention}+#1#{} hand size", - "{C:attention}+#1#{} consumable slot#s1#", - "{C:attention}+#1#{} card#s1# in shop", - "{C:attention}+#1#{} voucher slot#s1#", + "{C:attention}+#1#{} consumable slot#1#", + "{C:attention}+#1#{} card#1# in shop", + "{C:attention}+#1#{} voucher slot#1#", + }, + unlock = { + "Win a run with", + "only {C:attention}High Card", + }, + }, + j_cry_soccer_balanced = { + name = "One for All", --changed the name from latin because this isn't exotic + text = { + "{C:attention}+#1#{} Booster Pack slot#1#", + "{C:attention}+#1#{} hand size", + "{C:attention}+#1#{} consumable slot#1#", + "{C:attention}+#1#{} card#1# in shop", + "{C:attention}+#1#{} voucher slot#1#", }, unlock = { "Win a run with", @@ -2282,7 +2412,7 @@ return { j_cry_stardust = { name = "Stardust", text = { - "{C:dark_edition}Polychrome{} cards", + "Other {C:dark_edition}Polychrome{} cards", "each give {X:mult,C:white}X#1#{} Mult", }, }, @@ -2320,7 +2450,15 @@ return { j_cry_supercell = { name = "Supercell", text = { - "{C:chips}+#1#{} Chip#s1#, {C:mult}+#1#{} Mult,", + "{C:chips}+#1#{} Chip#1#, {C:mult}+#1#{} Mult,", + "{X:chips,C:white}X#2#{} Chips, {X:mult,C:white}X#2#{} Mult", + "Earn {C:money}$#3#{} at", + "end of round", + }, + }, + j_cry_supercell_balanced = { + name = "Supercell", + text = { "{X:chips,C:white}X#2#{} Chips, {X:mult,C:white}X#2#{} Mult", "Earn {C:money}$#3#{} at", "end of round", @@ -2366,7 +2504,7 @@ return { j_cry_tenebris = { name = "Tenebris", text = { - "{C:dark_edition}+#1#{C:attention} Joker{} slot#s1#", + "{C:dark_edition}+#1#{C:attention} Joker{} slot#1#", "Earn {C:money}$#2#{} at end of round", }, }, @@ -2382,7 +2520,7 @@ return { j_cry_treacherous = { name = "Treacherous Joker", text = { - "{C:chips}+#1#{} Chip#s1# if played", + "{C:chips}+#1#{} Chip#1# if played", "hand contains", "an {C:attention}#2#", }, @@ -2399,7 +2537,7 @@ return { j_cry_tricksy = { name = "Tricksy Joker", text = { - "{C:chips}+#1#{} Chip#s1# if played", + "{C:chips}+#1#{} Chip#1# if played", "hand contains", "a {C:attention}#2#", }, @@ -2435,7 +2573,7 @@ return { j_cry_universe = { name = "Universe", text = { - "{C:dark_edition}Astral{} cards", + "Other {C:dark_edition}Astral{} cards", "each give {X:dark_edition,C:white}^#1#{} Mult", }, }, @@ -2513,7 +2651,7 @@ return { name = "2D", text = { "Retrigger each played {C:attention}2{}", --wee gaming - "{C:attention:}#1#{} additional time#s1#", --wee gaming? + "{C:attention:}#1#{} additional time#1#", --wee gaming? "{C:inactive,s:0.8}Wee Gaming?{}", }, }, @@ -2539,7 +2677,7 @@ return { name = "Wrapped Candy", text = { "Create a random {C:attention}Food Joker{}", - "in {C:attention}#1#{} round#s1#", + "in {C:attention}#1#{} round#1#", "{C:red,E:2}self destructs{}", }, }, @@ -2644,7 +2782,7 @@ return { "{S:0.8}({S:0.8,V:1}lvl.#1#{S:0.8}){} Level up", "{C:attention}#2#", "{C:mult}+#3#{} Mult and", - "{C:chips}+#4#{} chip#s4#", + "{C:chips}+#4#{} chip#4#", }, }, c_cry_void = { @@ -2653,7 +2791,7 @@ return { "{S:0.8}({S:0.8,V:1}lvl.#1#{S:0.8}){} Level up", "{C:attention}#2#", "{C:mult}+#3#{} Mult and", - "{C:chips}+#4#{} chip#s4#", + "{C:chips}+#4#{} chip#4#", }, }, c_cry_asteroidbelt = { @@ -2662,7 +2800,7 @@ return { "{S:0.8}({S:0.8,V:1}lvl.#1#{S:0.8}){} Level up", "{C:attention}#2#", "{C:mult}+#3#{} Mult and", - "{C:chips}+#4#{} chip#s4#", + "{C:chips}+#4#{} chip#4#", }, }, c_cry_universe = { @@ -2671,7 +2809,7 @@ return { "{S:0.8}({S:0.8,V:1}lvl.#1#{S:0.8}){} Level up", "{C:attention}#2#", "{C:mult}+#3#{} Mult and", - "{C:chips}+#4#{} chip#s4#", + "{C:chips}+#4#{} chip#4#", }, }, c_cry_sunplanet = { @@ -2685,6 +2823,29 @@ return { }, }, Sleeve = { + sleeve_cry_beige_sleeve = { + name = "Beige Sleeve", + text = { + "{C:attention}Common{} Jokers have", + "{C:attention}quadrupled{} values", + }, + }, + sleeve_cry_beige_sleeve_alt = { + name = "Beige Sleeve", + text = { + "{C:attention}Uncommon{} Jokers have", + "{C:attention}quadrupled{} values", + }, + }, + sleeve_cry_beta_sleeve = { + name = "Nostalgic Sleeve", + text = { + "{C:attention}Joker{} and {C:attention}Consumable{}", + "slots are {C:attention}combined", + "{C:attention}Nostalgic{} Blinds replace", + "their updated Blind", + }, + }, sleeve_cry_bountiful_sleeve = { name = "Bountiful Sleeve", text = { @@ -2734,6 +2895,15 @@ return { "{C:attention,T:v_overstock_plus}+2 Shop Slots", }, }, + sleeve_cry_glowing_sleeve = { + name = "Glowing Sleeve", + text = { + "Multiply the values of", + "all Jokers by {X:dark_edition,C:white} X1.25 {}", + "when Boss Blind is defeated", + "{X:cry_jolly,C:white,s:0.8} Jolly#1#Open#1#Winner#1#-#1#wawa#1#person", --peak loc_vars right here + }, + }, sleeve_cry_infinite_sleeve = { name = "Unlimited Sleeve", text = { @@ -2764,6 +2934,15 @@ return { "{C:cry_candy}Candy{} or {X:cry_cursed,C:white}Cursed{} Joker", }, }, + sleeve_cry_very_fair_sleeve = { + name = "Very Fair Sleeve", + text = { + "{C:blue}-2{} hands, {C:red}-2{} discards", + "every round", + "{C:attention}Vouchers{} no longer", + "appear in the shop", + }, + }, sleeve_cry_wormhole_sleeve = { name = "Wormhole Sleeve", text = { @@ -2781,6 +2960,15 @@ return { "when Boss Blind is defeated {C:inactive}(must have room){}", }, }, + sleeve_cry_antimatter_sleeve = { + name = "Antimatter Sleeve", + text = { + "applies the {C:attention}effects{}", + "and {C:attention}special effects{}", + "of all deck sleeves", + "{C:red}WIP", + }, + }, }, Spectral = { c_cry_adversary = { @@ -2794,7 +2982,7 @@ return { c_cry_analog = { name = "Analog", text = { - "Create {C:attention}#1#{} cop#y1# of a", + "Create {C:attention}#1#{} cop#1# of a", "random {C:attention}Joker{}, destroy", "all other Jokers, {C:attention}+#2#{} Ante", }, @@ -2803,7 +2991,7 @@ return { name = "Chambered", text = { "Create {C:attention}#1#{} {C:dark_edition}Negative{}", - "cop#y1# of a", + "cop#1# of a", "{C:attention}random{} consumable", "in your possession", "{C:inactive,s:0.8}Does not copy Chambered{}", @@ -2863,7 +3051,7 @@ return { text = { "Apply {C:dark_edition}Negative{}, {C:dark_edition}Mosaic{},", "or {C:dark_edition}Astral{} to {C:attention}#1#{}", - "selected card#s1# in hand", + "selected card#1# in hand", }, }, c_cry_source = { @@ -2871,7 +3059,7 @@ return { text = { "Add a {C:cry_code}Green Seal{}", "to {C:attention}#1#{} selected", - "card#s1# in your hand", + "card#1# in your hand", }, }, c_cry_summoning = { @@ -2894,7 +3082,7 @@ return { text = { "Add an {C:cry_azure}Azure Seal{}", "to {C:attention}#1#{} selected", - "card#s1# in your hand", + "card#1# in your hand", }, }, c_cry_vacuum = { @@ -3130,7 +3318,7 @@ return { name = "Better Top-up Tag", text = { "Creates up to {C:attention}#1#", - "{C:green}Uncommon{} Joker#s1#", + "{C:green}Uncommon{} Joker#1#", "{C:inactive}(Must have room){}", }, }, @@ -3252,7 +3440,7 @@ return { tag_cry_memory = { name = "Memory Tag", text = { - "Create {C:attention}#1#{} cop#y1# of", + "Create {C:attention}#1#{} cop#1# of", "the last {C:attention}Tag{} used", "during this run", "{s:0.8,C:inactive}Copying Tags excluded", @@ -3278,7 +3466,7 @@ return { tag_cry_quadruple = { name = "Quadruple Tag", text = { - "Gives {C:attention}#1#{} cop#y1# of the", + "Gives {C:attention}#1#{} cop#1# of the", "next selected {C:attention}Tag", "{s:0.8,C:inactive}Copying Tags excluded", }, @@ -3286,7 +3474,7 @@ return { tag_cry_quintuple = { name = "Quintuple Tag", text = { - "Gives {C:attention}#1#{} cop#y1# of the", + "Gives {C:attention}#1#{} cop#1# of the", "next selected {C:attention}Tag", "{s:0.8,C:inactive}Copying Tags excluded", }, @@ -3308,14 +3496,14 @@ return { tag_cry_scope = { name = "Scope Tag", text = { - "{C:attention}+#1# {C:blue}hand#s1#{} and", - "{C:red}discard#s1#{} next round", + "{C:attention}+#1# {C:blue}hand#1#{} and", + "{C:red}discard#1#{} next round", }, }, tag_cry_triple = { name = "Triple Tag", text = { - "Gives {C:attention}#1#{} cop#y1# of the", + "Gives {C:attention}#1#{} cop#1# of the", "next selected {C:attention}Tag", "{s:0.8,C:inactive}Copying Tags excluded", }, @@ -3326,14 +3514,14 @@ return { name = "The Automaton", text = { "Creates up to {C:attention}#1#", - "random {C:cry_code}Code{} card#s1#", + "random {C:cry_code}Code{} card#1#", "{C:inactive}(Must have room)", }, }, c_cry_eclipse = { name = "The Eclipse", text = { - "Enhances {C:attention}#1#{} selected card#s1#", + "Enhances {C:attention}#1#{} selected card#1#", "into an {C:attention}Echo Card", }, }, @@ -3356,7 +3544,7 @@ return { c_cry_seraph = { name = "The Seraph", text = { - "Enhances {C:attention}#1#{} selected card#s1#", + "Enhances {C:attention}#1#{} selected card#1#", "into a {C:attention}Light Card", }, }, @@ -3421,7 +3609,7 @@ return { name = "Dexterity", text = { "Permanently", - "gain {C:blue}+#1#{} hand#s1#", + "gain {C:blue}+#1#{} hand#1#", "each round", }, unlock = { @@ -3457,7 +3645,7 @@ return { v_cry_fabric = { name = "Universal Fabric", text = { - "{C:dark_edition}+#1#{} Joker slot#s1#", + "{C:dark_edition}+#1#{} Joker slot#1#", }, unlock = { "Redeem {C:dark_edition}Antimatter", @@ -3492,9 +3680,9 @@ return { v_cry_overstock_multi = { name = "Multistock", text = { - "{C:attention}+#1#{} card slot#s1#,", - "{C:attention}+#1#{} booster pack slot#s1#,", - "and {C:attention}+#1#{} voucher slot#s1#,", + "{C:attention}+#1#{} card slot#1#,", + "{C:attention}+#1#{} booster pack slot#1#,", + "and {C:attention}+#1#{} voucher slot#1#,", "available in shop", }, unlock = { @@ -3612,7 +3800,7 @@ return { name = "The 3 Rs", text = { "Permanently", - "gain {C:red}+#1#{} discard#s1#", + "gain {C:red}+#1#{} discard#1#", "each round", }, unlock = { @@ -3712,7 +3900,7 @@ return { name = "Flickering", text = { "Destroyed after", - "{C:attention}#1#{} trigger#s1#", + "{C:attention}#1#{} trigger#1#", }, }, cry_possessed = { @@ -3734,10 +3922,11 @@ return { }, }, ev_cry_choco0 = { - name = "", + name = "Possible Events", text = { - "Details of an active", - "{C:cry_ascendant,E:1}event{} will appear here", + "{T:ev_cry_choco1}1{} {T:ev_cry_choco2}2{} {T:ev_cry_choco3}3{} {T:ev_cry_choco4}4{} {T:ev_cry_choco5}5{}", + "{T:ev_cry_choco6}6{} {T:ev_cry_choco7}7{} {T:ev_cry_choco8}8{} {T:ev_cry_choco9}9{} {T:ev_cry_choco10}10{}", + "{C:inactive}(Hover for info)", }, }, ev_cry_choco1 = { @@ -3951,35 +4140,35 @@ return { name = "Program Pack", text = { "Choose {C:attention}#1#{} of up to", - "{C:attention}#2#{C:cry_code} Code{} card#s2#", + "{C:attention}#2#{C:cry_code} Code{} card#2#", }, }, p_cry_code_normal_2 = { name = "Program Pack", text = { "Choose {C:attention}#1#{} of up to", - "{C:attention}#2#{C:cry_code} Code{} card#s2#", + "{C:attention}#2#{C:cry_code} Code{} card#2#", }, }, p_cry_code_jumbo_1 = { name = "Jumbo Program Pack", text = { "Choose {C:attention}#1#{} of up to", - "{C:attention}#2#{C:cry_code} Code{} card#s2#", + "{C:attention}#2#{C:cry_code} Code{} card#2#", }, }, p_cry_code_mega_1 = { name = "Mega Program Pack", text = { "Choose {C:attention}#1#{} of up to", - "{C:attention}#2#{C:cry_code} Code{} card#s2#", + "{C:attention}#2#{C:cry_code} Code{} card#2#", }, }, p_cry_empowered = { name = "Spectral Pack [Empowered Tag]", text = { "Choose {C:attention}#1#{} of up to", - "{C:attention}#2#{C:spectral} Spectral{} card#s2#", + "{C:attention}#2#{C:spectral} Spectral{} card#2#", "{s:0.8,C:inactive}(Generated by Empowered Tag)", }, }, @@ -3987,21 +4176,21 @@ return { name = "Meme Pack", text = { "Choose {C:attention}#1#{} of", - "up to {C:attention}#2# Meme Joker#s2#{}", + "up to {C:attention}#2# Meme Joker#2#{}", }, }, p_cry_meme_two = { name = "Meme Pack", text = { "Choose {C:attention}#1#{} of", - "up to {C:attention}#2# Meme Joker#s2#{}", + "up to {C:attention}#2# Meme Joker#2#{}", }, }, p_cry_meme_three = { name = "Meme Pack", text = { "Choose {C:attention}#1#{} of", - "up to {C:attention}#2# Meme Joker#s2#{}", + "up to {C:attention}#2# Meme Joker#2#{}", }, }, undiscovered_code = { @@ -4034,7 +4223,7 @@ return { name = "Azure Seal", text = { "Create {C:attention}#1#{} {C:dark_edition}Negative{}", - "{C:planet}Planet#s1#{} for played", + "{C:planet}Planet#1#{} for played", "{C:attention}poker hand{}, then", "{C:red}destroy{} this card", }, @@ -4128,7 +4317,7 @@ return { ["cry_Bulwark"] = "Bulwark", ["cry_Clusterfuck"] = Cryptid_config.family_mode and "Cluster" or "Clusterfuck", ["cry_UltPair"] = "Ultimate Pair", - ["cry_WholeDeck"] = Cryptid_config.family_mode and "Fifty Two" or "The Entire Fucking Deck", + ["cry_WholeDeck"] = Cryptid_config.family_mode and "The Entire Deck" or "The Entire Fucking Deck", }, poker_hand_descriptions = { ["cry_Bulwark"] = { @@ -4170,6 +4359,7 @@ return { ach_cry_ult_full_skip = "Ultimate Full Skip", ach_cry_used_crash = "We Told You Not To", ach_cry_what_have_you_done = "WHAT HAVE YOU DONE?!", + ach_cry_pin = "Pin of Shame", }, achievement_descriptions = { ach_cry_ace_in_crash = 'check_for_unlock({type = "ace_in_crash"})', @@ -4192,6 +4382,7 @@ return { ach_cry_ult_full_skip = "Win in 1 round", ach_cry_used_crash = "Use ://CRASH", ach_cry_what_have_you_done = "Delete or Sacrifice an Exotic Joker", + ach_cry_pin = "Lose a run to The Pin", }, challenge_names = { c_cry_ballin = "Ballin'", @@ -4278,6 +4469,7 @@ return { b_pull = "PULL", cry_hooked_ex = "Hooked!", k_end_blind = "End Blind", + k_cry_shiny = "Shiny", cry_code_rank = "ENTER RANK", cry_code_enh = "ENTER ENHANCEMENT", @@ -4295,6 +4487,10 @@ return { b_flip = "FLIP", b_merge = "MERGE", + cry_hand_bulwark = "Bulwark", + cry_hand_clusterfuck = "Clusterfuck", + cry_hand_ultpair = "Ultimate Pair", + cry_asc_hands = "Asc. Hands", cry_p_star = "Star", @@ -4344,13 +4540,16 @@ return { cry_gameset_mainline = "Mainline", cry_gameset_madness = "Madness", cry_gameset_custom = "Modified", - cry_gameset_experimental = "Experimental", - cry_gameset_experimental_modest = "Experimental (Modest)", - cry_gameset_experimental_mainline = "Experimental (Mainline)", - cry_gameset_experimental_madness = "Experimental (Madness)", + cry_gameset_exp = "Experimental", + cry_gameset_exp_modest = "Experimental (Modest)", + cry_gameset_exp_mainline = "Experimental (Mainline)", + cry_gameset_exp_madness = "Experimental (Madness)", cry_view_set_contents = "View Items in Set", + cry_sapling_an = "an", + cry_sapling_a = "a", + b_reset_gameset_modest = "Reset Gameset Config (Modest)", b_reset_gameset_mainline = "Reset Gameset Config (Mainline)", b_reset_gameset_madness = "Reset Gameset Config (Madness)", @@ -4389,7 +4588,7 @@ return { rnj_loc_txts = { stats = { plus_mult = { "{C:red}+#2#{} Mult" }, - plus_chips = { "{C:blue}+#2#{} Chip#s2#" }, + plus_chips = { "{C:blue}+#2#{} Chip(s)" }, x_mult = { "{X:red,C:white} X#2#{} Mult" }, x_chips = { "{X:blue,C:white} X#2#{} Chips" }, h_size = { "{C:attention}+#2#{} Hand Size" }, @@ -4397,17 +4596,17 @@ return { }, stats_inactive = { plus_mult = { "{C:inactive}(Currently {C:red}+#1#{C:inactive} Mult)" }, - plus_chips = { "{C:inactive}(Currently {C:blue}+#1#{C:inactive} Chip#s1#)" }, + plus_chips = { "{C:inactive}(Currently {C:blue}+#1#{C:inactive} Chip(s))" }, x_mult = { "{C:inactive}(Currently {X:red,C:white} X#1# {C:inactive} Mult)" }, x_chips = { "{C:inactive}(Currently {X:blue,C:white} X#1# {C:inactive} Chips)" }, h_size = { "{C:inactive}(Currently {C:attention}+#1#{C:inactive} Hand Size)" }, money = { "{C:inactive}(Currently {C:money}+$#1#{C:inactive})" }, }, actions = { - make_joker = { "Create {C:attention}#2# Joker#s2#{}" }, - make_tarot = { "Create {C:attention}#2#{C:tarot} Tarot{} card#s2#" }, - make_planet = { "Create {C:attention}#2#{C:planet} Planet{} card#s2#" }, - make_spectral = { "Create {C:attention}#2#{C:spectral} Spectral{} card#s2#" }, + make_joker = { "Create {C:attention}#2# Joker(s){}" }, + make_tarot = { "Create {C:attention}#2#{C:tarot} Tarot{} card(s)" }, + make_planet = { "Create {C:attention}#2#{C:planet} Planet{} card(s)" }, + make_spectral = { "Create {C:attention}#2#{C:spectral} Spectral{} card(s)" }, add_dollars = { "Earn {C:money}$#2#{}" }, }, contexts = { @@ -4460,8 +4659,8 @@ return { poker_hand = { "if hand is a {C:attention}#3#{}" }, or_more = { "if hand contains {C:attention}#3#{} or more cards" }, or_less = { "if hand contains {C:attention}#3#{} or less cards" }, - hands_left = { "if #3# {C:blue}hand#s3#{} remaining at end of round" }, - discards_left = { "if #3# {C:red}discard#s3#{} remaining at end of round" }, + hands_left = { "if #3# {C:blue}hand(s){} remaining at end of round" }, + discards_left = { "if #3# {C:red}discard(s){} remaining at end of round" }, first_discard = { "if it's the {C:attention}first {C:attention}discard{}" }, last_discard = { "if it's the {C:attention}last {C:attention}discard{}" }, odds = { "with a {C:green}#4# {C:green}in {C:green}#3#{} chance" }, @@ -4557,17 +4756,33 @@ return { { "FREE EXOTICS", "GET THEM BEFORE ITS", "TOO LATE (sold out)" }, { "PROVE THEM WRONG", "BUY BUYING AN INVISIBLE", "VOUCHER FOR $10" }, { "", "no vouchers?", "" }, - { "see this ad?", "if you are, then it's working", "and you could have it for your own" }, + { + "see this ad?", + "if you are, then it's working", + "and you could have it for your own", + }, { "YOU'RE MISSING OUT ON", "AT LEAST 5 VOUCHERS RIGHT NOW", "tonktonktonktonktonk" }, { "10", "20 NO VOUCHER XD", "30 GOTO 10" }, { "VOUCHERS", "ARE A PREMIUM FEATURE", "$199.99 JOLLARS TO UNLOCK" }, { "TRUE VOUCHERLESS!?!?", "ASCENDANT STAKE ONLY", "VERY FAIR DECK" }, { "ENJOYING YOUR", "VOUCHER EXPERIENCE? GIVE US A", "FIVE STAR RATING ON JESTELP" }, - { "FREE VOUCHERS", "HOT VOUCHERS NEAR YOU", "GET VOUCHERS QUICK WITH THIS ONE TRICK" }, + { + "FREE VOUCHERS", + "HOT VOUCHERS NEAR YOU", + "GET VOUCHERS QUICK WITH THIS ONE TRICK", + }, { "INTRODUCING", "THE VERY FIRST TIER 0 VOUCHER!", "(coming to Cryptid 1.0 soon)" }, - { "A VOUCHER!", "IT'S JUST IMAGINARY", "WE IMAGINED YOU WOULD WANT IT, THAT IS" }, + { + "A VOUCHER!", + "IT'S JUST IMAGINARY", + "WE IMAGINED YOU WOULD WANT IT, THAT IS", + }, { "TURN OFF ADBLOCKER", "WITHOUT ADS, WE WOULDN'T", "BE ABLE TO SELL YOU VOUCHERS" }, - { "IF YOU HAVE", "A PROBLEM WITH THIS", "EMAIL IT TO US AT NORESPONSE@JMAIL.COM" }, + { + "IF YOU HAVE", + "A PROBLEM WITH THIS", + "EMAIL IT TO US AT NORESPONSE@JMAIL.COM", + }, { "NOT ENOUGH MONEY", "TO BUY THIS VOUCHER", "SO WHY WOULD WE PUT IT HERE?" }, { "WANT A VOUCHER?", "WELL SHUT UP", "YOU CAN'T HAVE ANY LOL" }, { "^$%& NO", "VOUCHERS ^%&% %&$^% FOR", "$%&%%$ %&$&*%$^ YOU" }, diff --git a/Cryptid/localization/es_419.lua b/Cryptid/localization/es_419.lua index 382b0a0..48ee072 100644 --- a/Cryptid/localization/es_419.lua +++ b/Cryptid/localization/es_419.lua @@ -1448,7 +1448,7 @@ return { "{X:mult,C:white}X#1#{} multi por cada miembro", "en el {C:attention}Discord de Cryptid{}", "{C:inactive}(Actual: {X:mult,C:white}X#2#{C:inactive} multi)", - "{C:blue,s:0.7}https://discord.gg/eUf9Ur6RyB{}", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", }, }, j_cry_membershipcardtwo = { @@ -1457,7 +1457,7 @@ return { "{C:chips}+#1#{} fichas por cada miembro", "en el {C:attention}Discord de Cryptid{}", "{C:inactive}(Actual: {C:chips}+#2#{C:inactive} fichas)", - "{C:blue,s:0.7}https://discord.gg/eUf9Ur6RyB{}", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", }, }, j_cry_meteor = { diff --git a/Cryptid/localization/es_ES.lua b/Cryptid/localization/es_ES.lua index d07ae93..68f06c0 100644 --- a/Cryptid/localization/es_ES.lua +++ b/Cryptid/localization/es_ES.lua @@ -1,5 +1,3 @@ ---I couldn't get Meme Packs to work without crashing ---yes somehow that was harder than RNJoker return { descriptions = { Back = { @@ -10,6 +8,21 @@ return { "de {C:attention}todas{} las barajas", }, }, + b_cry_antimatter_balanced = { + name = "Baraja de antimateria", + text = { + "Aplica las {C:legendary,E:1}ventajas{}", + "de {C:attention}todas{} las barajas completadas", + "en la dificultad {C:gold}Pozo de oro{}", + }, + }, + b_cry_beige = { + name = "Baraja castaña", + text = { + "Los comodines {C:attention}comunes{}", + "tienen valores {C:attention}cuadruplicados{}", + }, + }, b_cry_beta = { name = "Baraja nostálgica", text = { @@ -56,6 +69,14 @@ return { "{C:green}#1# en 8{} probabilidades para {X:dark_edition,C:white} ^0.5 {} multi", }, }, + b_cry_e_deck = { + name = "Baraja de edición", + text = { + "Todas las cartas son {C:dark_edition}#1#s{}", + "Las cartas no pueden cambiar de edición", + "{C:inactive}(clic para editar)", + }, + }, b_cry_encoded = { name = "Baraja codificada", text = { @@ -74,6 +95,14 @@ return { "{C:attention,T:v_overstock_plus}Excedente plus", }, }, + b_cry_et_deck = { + name = "Baraja de mejora", + text = { + "Todas las {C:attention}cartas de juego{}", + "son {C:attention}#1#{}", + "{C:inactive}(clic para editar)", + }, + }, b_cry_glowing = { name = "Baraja brillante", text = { @@ -106,6 +135,21 @@ return { "obtén sus {C:attention}niveles extras", }, }, + b_cry_sk_deck = { + name = "Baraja de pegatina", + text = { + "Todas las cartas son {C:attention}#1#{}", + "{C:inactive}(clic para editar)", + }, + }, + b_cry_sl_deck = { + name = "Baraja de sello", + text = { + "Todas las cartas de juego tienen un {C:dark_edition}#1#{}", + "Las cartas no pueden cambiar sello", + "{C:inactive}(clic para editar)", + }, + }, b_cry_spooky = { name = "Baraja espeluznante", text = { @@ -114,8 +158,16 @@ return { "de {C:cry_candy}dulce{} o {X:cry_cursed,C:white}maldito{}", }, }, + b_cry_st_deck = { + name = "Baraja de palo", + text = { + "Todas las cartas de juego son {C:dark_edition}#1#", + "y no pueden cambiar palo", + "{C:inactive}(clic para editar)", + }, + }, b_cry_very_fair = { - name = "Baraja Muy Justa", + name = "Baraja muy justa", text = { "{C:blue}-2{} manos, {C:red}-2{} descartes", "en cada ronda", @@ -168,7 +220,7 @@ return { name = "La broma", text = { "Si la puntuación excede 2X de los requisitos,", - "establece la apuesta a un múltiplo de #1#", + "establece la apuesta a #2#", }, }, bl_cry_magic = { @@ -289,8 +341,8 @@ return { bl_cry_tax = { name = "El impuesto", text = { - "Puntuación por mano limitado a", - "0.4X requisitos de ciega", + "Puntuación por mano", + "limitado a #1#", }, }, bl_cry_tornado = { @@ -307,6 +359,13 @@ return { "las cartas boca-arriba en tu mano", }, }, + bl_cry_trophy = { + name = "Trofeo lemón", + text = { + "Multi no puede", + "exceder fichas", + }, + }, bl_cry_vermillion_virus = { name = "Virus bermellón", text = { @@ -323,10 +382,18 @@ return { }, }, Code = { + c_cry_alttab = { + name = "://ALTTAB", + text = { + "Crea la etiqueta de", + "la ciega {C:cry_code}actual{}", + "{C:inactive}(Actual: {C:cry_code}#1#{C:inactive})", + }, + }, c_cry_class = { name = "://CLASE", text = { - "Convierte {C:cry_code}#1#{} carta seleccionada", + "Convierte {C:cry_code}#1#{} carta#1# seleccionada#1#", "a una mejora {C:cry_code}a elección{}", }, }, @@ -347,16 +414,17 @@ return { c_cry_ctrl_v = { name = "://CTRL+V", text = { - "Crea una {C:cry_code}copia{} de un {C:cry_code}comodín{},", - "carta de juego, o consumible seleccionado", + "Crea una {C:cry_code}copia{} de una", + "carta de juego o consumible seleccionado", }, }, c_cry_delete = { name = "://ELIMINAR", text = { - "Remueve {C:cry_code}permanentemente{} un", - "objeto {C:cry_code}seleccionado{} de la tienda", - "{C:inactive,s:0.8}El objeto no puede aparecer otra vez en esta partida", + "{C:cry_code}Destierra{} cualquier objeto", + "{C:cry_code}seleccionado{} de la tienda, ya no aparecerá", + "normalmente en esta partida", + "{C:inactive}Multiuso: ({C:cry_code}#1#{C:inactive} restante#1#)", }, }, c_cry_divide = { @@ -369,11 +437,10 @@ return { c_cry_exploit = { name = "://EXPLOTAR", text = { - "Cualquier mano jugada se considera que", - "{C:cry_code}contiene{} una mano de póker {C:cry_code}a elección{},", - "se reinicia al final de la ronda", - "{C:inactive,s:0.8}Las manos secretas deben ser", - "{C:inactive,s:0.8}descubiertas para ser válidas", + "{C:cry_code}Escoje{} una mano de póker {C:cry_code}visible{},", + "la siguiente mano es {C:cry_code}calculada{} como esa mano,", + "y gana {C:cry_code}un Poder de Ascención{} temporal", + "{C:inactive}Multiuso: ({C:cry_code}#1#{C:inactive} restante#1#)", }, }, c_cry_hook = { @@ -423,7 +490,7 @@ return { }, }, c_cry_patch = { - name = "://PATCH", + name = "://PARCHE", text = { "Rehabilita y remueve todas las pegatinas", "de todos los objetos visibles", @@ -440,8 +507,8 @@ return { name = "://PORUNPASO", text = { "El siguiente {C:cry_code}paquete potenciador{} contiene", - "{C:cry_code}#1#{} carta adicional y", - "{C:cry_code}#1#{} opción adicional", + "{C:cry_code}#1#{} carta#1# adicional#1# y", + "{C:cry_code}#1#{} opci#1# adicional#1#", "{C:inactive}(Actual: {C:cry_code}+#2#{C:inactive})", }, }, @@ -501,11 +568,136 @@ return { c_cry_variable = { name = "://VARIABLE", text = { - "Convierte {C:cry_code}#1#{} cartas seleccionadas", + "Convierte {C:cry_code}#1#{} carta#1# seleccionada#1#", "a una categoría {C:cry_code}a elección{}", }, }, }, + ["Content Set"] = { + set_cry_blind = { + name = "Ciegas", + text = { + "{C:attention}Ciegas jefe{} añadidas", + "por Cryptid", + }, + }, + set_cry_code = { + name = "Cartas de código", + text = { + "{C:cry_code}Cartas de código{} y", + "contenido relacionado", + }, + }, + set_cry_cursed = { + name = "Comodines malditos", + text = { + "Comodines dañinos con la", + "rareza {X:cry_cursed,C:white}maldita{}", + }, + }, + set_cry_deck = { + name = "Barajas", + text = { + "{C:attention}Barajas{} añadidas", + "por Cryptid", + }, + }, + set_cry_epic = { + name = "Comodines épicos", + text = { + "Comodines con la", + "rareza {C:cry_epic}épica{}", + "{C:inactive,s:0.8}(entre Raro y Legendario)", + }, + }, + set_cry_exotic = { + name = "Comodines exóticos", + text = { + "Comodines poderosos con la", + "rareza {C:cry_exotic}exótica{}", + }, + }, + set_cry_m = { + name = "Comodines M", + text = { + "Comodines relacionados a", + "la letra {C:attention}M{}", + "y {C:attention}Comodín contento", + }, + }, + set_cry_misc = { + name = "Misceláneos", + text = { + "Cosas que no caben", + "en los otros", + "{C:cry_ascendant}sets temáticos", + }, + }, + set_cry_misc_joker = { + name = "Comodines misceláneos", + text = { + "{C:attention}Comodines{} que no caben", + "en los otros", + "{C:cry_ascendant}sets temáticos", + }, + }, + set_cry_planet = { + name = "Cartas de planeta", + text = { + "Cartas de {C:planet}planeta{} misceláneas", + "añadidas por Cryptid", + }, + }, + set_cry_poker_hand_stuff = { + name = "Manos de póker", + text = { + "Añade 4 {C:attention}manos de póker{} nuevas", + "y habilita {C:attention}Manos ascendidas", + }, + }, + set_cry_spectral = { + name = "Cartas espectrales", + text = { + "Cartas {C:spectral}espectrales{} añadidas", + "por Cryptid", + }, + }, + set_cry_spooky = { + name = "Actualización espeluznant", + text = { + "Contenido de la Actualización espeluznante,", + "incluyendo Comodines de {C:cry_candy}dulce{}", + }, + }, + set_cry_tag = { + name = "Etiquetas", + text = { + "{C:attention}Etiquetas{} añadidas", + "por Cryptid", + }, + }, + set_cry_tier3 = { + name = "Vales de nivel 3", + text = { + "Un {C:attention}nivel{} adicional", + "de vales", + }, + }, + set_cry_timer = { + name = "Mecánicas de tiempo", + text = { + "Objetos con efectos y mecánicas", + "{C:attention}basados en tiempo", + }, + }, + set_cry_voucher = { + name = "Vales misceláneos", + text = { + "{C:attention}Vales{} de nivel 1 y 2", + "añadidos por Cryptid", + }, + }, + }, Edition = { e_cry_astral = { name = "Astral", @@ -520,7 +712,7 @@ return { "carta {C:attention}1{} vez", "{C:green}#1# en #2#{} probabilidades", "para reactivar {C:attention}#3#{}", - "vez más", + "ve#3# más", }, }, e_cry_double_sided = { @@ -595,16 +787,52 @@ return { name = "Carta de eco", text = { "{C:green}#2# en #3#{} probabilidades de", - "{C:attention}reactivar{} #1# veces", + "{C:attention}reactivar{} #1# ve#1#", "adicionales al puntuar", }, }, + m_cry_light = { + name = "Carta de luz", + text = { + "Al activarse con {C:attention}#4#{} {C:inactive}(#3#){} otra#4#", + "carta#4# puntuada#4#, obtiene {X:mult,C:white}X#1#{} multi y", + "aumenta el requisito por {C:attention}5{}", + "{C:inactive}(Actual: {X:mult,C:white}X#2#{C:inactive} multi)", + }, + }, }, Joker = { + j_cry_test_modest = { + name = "Test Joker", + text = { + "{C:chips}+#1#{} ficha#s1#", + }, + }, + j_cry_test_mainline = { + name = "Test Joker", + text = { + "{C:chips}+#1#{} ficha#s1#", + "{C:money}+$44{} al principio de la {C:attention}ciega{}", + }, + }, + j_cry_test_madness = { + name = "Test Joker", + text = { + "{C:chips}+#1#{} ficha#s1#", + "{C:money}+$44444{} al principio de la {C:attention}ciega{}", + }, + }, + j_cry_test_cryptid_in_2025 = { + name = "Test Joker", + text = { + "{C:chips}+#1#{} ficha#s1#", + "{C:money}+$44444{} al principio de la {C:attention}ciega{}", + }, + }, j_cry_adroit = { name = "Comodín hábil", text = { - "{C:chips}+#1#{} fichas", + "{C:chips}+#1#{} ficha#1#", "si la mano contiene", "un {C:attention}#2#", }, @@ -613,10 +841,20 @@ return { name = "Carta de Googol Play nostálgica", text = { "Vende esta carta para crear", - "{C:attention}2{} copias del {C:attention}Joker{} del extremo izquierdo", + "{C:attention}#1#{} copia#1# del {C:attention}Joker{} del extremo izquierdo", "{C:inactive,s:0.8}No copia otras Cartas de Googol Play nostálgicas{}", }, }, + j_cry_altgoogol_balanced = { + name = "Carta de Googol Play nostálgica", + text = { + "Vende esta carta para crear", + "{C:attention}#1#{} copia#1# del {C:attention}Joker{} del extremo izquierdo", + "{C:inactive,s:0.8}No copia otras Cartas de Googol Play nostálgicas{}", + "{C:inactive}(debe haber espacio){}", + --"{C:inactive,s:0.9}(Elimina el {C:dark_edition,s:0.9}Negativo{C:inactive,s:0.9} de la copia)", + }, + }, j_cry_antennastoheaven = { name = "...como antenas al cielo", text = { @@ -630,6 +868,15 @@ return { name = "Comodín AP", text = { "{X:mult,C:white} X#1# {} multi contra las {C:attention}ciegas jefe{}" }, }, + j_cry_arsonist = { + name = "Incendiario", + text = { + "Si la mano jugada", + "contiene un {C:attention}Full{},", + "{C:red}destruye{} todas las cartas", + "después de puntuar", + }, + }, j_cry_astral_bottle = { name = "Astral en una botella", text = { @@ -638,7 +885,21 @@ return { "un {C:attention}comodín{} aleatorio", }, }, - + j_cry_astral_bottle_mainline = { + name = "Astral en una botella", + text = { + "Al venderse, aplica {C:dark_edition}Astral{}", + "y {C:attention}Perecedero{} a", + "diferentes {C:attention}comodines{} aleatorios", + }, + }, + j_cry_astral_bottle_madness = { + name = "Astral en una botella", + text = { + "Al venderse, aplica {C:dark_edition}Astral{}", + "a un {C:attention}comodín{} aleatorio", + }, + }, j_cry_big_cube = { name = "Cubo grande", text = { @@ -676,17 +937,17 @@ return { j_cry_blurred = { name = "Comodín borroso", text = { - "Obtén {C:blue}+#1#{} mano(s) al", + "Obtén {C:blue}+#1#{} mano#1# al", "seleccionar una {C:attention}ciega{}", }, }, j_cry_bonk = { name = "Bonk", text = { - "Cada {C:attention}comodín{} da {C:chips}+#1#{} fichas", + "Cada {C:attention}comodín{} da {C:chips}+#1#{} ficha#1#", "aumenta la cantidad por {C:chips}+#2#{} si la ", "{C:attention}mano de póker{} es una {C:attention}#3#{}", - "{C:inactive,s:0.8}Los comodines contentos dan{} {C:chips,s:0.8}+#4#{} {C:inactive,s:0.8}fichas{}", + "{C:inactive,s:0.8}Los comodines contentos dan{} {C:chips,s:0.8}+#4#{} {C:inactive,s:0.8}ficha#4#{}", }, }, j_cry_bonkers = { @@ -703,7 +964,7 @@ return { "{C:green}#1# en #2#{} probabilidades por cada", "carta {C:attention}adicional{} jugada para aumentar", "ranuras de {C:attention}comodín{} o {C:attention}consumible", - "por {C:dark_edition}1{} al puntuar", + "por {C:dark_edition}#3#{} al puntuar", "{C:red}Funciona 2 veces por runda", "{C:inactive,s:0.8}(probabilidad igual por cada uno){}", }, @@ -711,7 +972,7 @@ return { j_cry_booster = { name = "Comodín potenciador", text = { - "{C:attention}+#1#{} ranura de paquete potenciador", + "{C:attention}+#1#{} ranura#1# de paquete potenciador", "disponible en la tienda", }, }, @@ -723,11 +984,16 @@ return { "o {C:attention}carta jugada{}", "{C:inactive,s:0.8}No afecta otros Aburrimientos{}", }, + unlock = { + "Quédate AFK en la", + "pantalla de título", + "por {C:attention}10 minutos", + }, }, j_cry_brittle = { name = "Dulce frágil", text = { - "Por las siguientes {C:attention}#1#{} manos,", + "Por las siguiente#1# {C:attention}#1#{} mano#1#,", "añade {C:attention}Piedra{}, {C:attention}Oro{}, o {C:attention}Acero{} a", "la carta del extremo derecho que puntúa", }, @@ -746,29 +1012,29 @@ return { text = { "{C:green}#1# en #3#{} probabilidades", "para {C:mult}+#2#{} multi", - "{C:green}1 en 4{} probabilidades", + "{C:green}#4# en #3#{} probabilidades", "para {C:mult}-#2#{} multi", }, }, j_cry_candy_basket = { name = "Cesta de dulces", text = { - "Vende esta carta para crear {C:attention}#1#{} {C:cry_candy}dulces", - "{C:attention}+#2#{} {C:cry_candy}dulce{} cada {C:attention}2{} ciegas derrotadas", - "{C:attention}+#3#{} {C:cry_candy}dulces{} al derrotar la {C:attention}ciega jefe{}", + "Vende esta carta para crear {C:attention}#1#{} {C:cry_candy}dulce#1#", + "{C:attention}+#2#{} {C:cry_candy}dulce#2#{} cada {C:attention}2{} ciegas derrotadas", + "{C:attention}+#3#{} {C:cry_candy}dulce#3#{} al derrotar la {C:attention}ciega jefe{}", }, }, j_cry_candy_buttons = { name = "Botones de dulce", text = { - "Las siguientes {C:attention}#1#{} renovaciones", + "Las siguiente#1# {C:attention}#1#{} renovaci#1#", "cuestan {C:money}$1{}", }, }, j_cry_candy_cane = { name = "Bastón de dulce", text = { - "Por las siguientes {C:attention}#1#{} rondas,", + "Por las siguiente#1# {C:attention}#1#{} ronda#1#,", "las cartas de juego otorgan {C:money}$#2#", "cuando se {C:attention}reactivan", }, @@ -785,7 +1051,7 @@ return { name = "Palos de dulce", text = { "El efecto de la siguiente ciega jefe se desactiva", - "hasta que hayas jugado {C:attention}#1#{} msnos", + "hasta que hayas jugado {C:attention}#1#{} mano#1#", }, }, j_cry_canvas = { @@ -795,20 +1061,39 @@ return { "una vez por {C:attention}todos{} los {C:attention}comodines{} no-{C:blue}comunes", "a la derecha de este comodín", }, + unlock = { + "Reactiva un {C:attention}comodín", + "{C:attention}114{} veces", + "en una mano", + }, + }, + j_cry_canvas_balanced = { + name = "Canvas", + text = { + "{C:attention}Reactiva{} todos los {C:attention}comodines{} a la izquierda", + "una vez por {C:attention}todos{} los {C:attention}comodines{} no-{C:blue}comunes", + "a la derecha de este comodín", + "{C:inactive}(hasta 2 reactivaciones)", + }, + unlock = { + "Reactiva un {C:attention}comodín", + "{C:attention}114{} veces", + "en una mano", + }, }, j_cry_caramel = { name = "Caramelo", text = { "Cada carta jugada otorga", "{X:mult,C:white}X#1#{} multi cuando puntúa", - "por las siguientes {C:attention}#2#{} rondas", + "por las siguiente#2# {C:attention}#2#{} ronda#2#", }, }, j_cry_chad = { name = "Chad", text = { "Reactiva el comodín del {C:attention}extremo izquierdo{}", - "{C:attention}#1#{} veces adicionales", + "{C:attention}#1#{} ve#1# adicional#1#", }, }, j_cry_chili_pepper = { @@ -816,7 +1101,7 @@ return { text = { "Este comodín consigue {X:mult,C:white} X#2# {} multi", "al final de la ronda,", - "{C:red,E:2}se autodestruye{} después de {C:attention}#3#{} rondas", + "{C:red,E:2}se autodestruye{} después de {C:attention}#3#{} ronda#3#", "{C:inactive}(Actual:{} {X:mult,C:white} X#1# {} {C:inactive}multi){}", }, }, @@ -834,7 +1119,7 @@ return { text = { "{X:dark_edition,C:white}^#1#{} fichas y {X:dark_edition,C:white}^#1#{} multi", "si tienes {C:attention}exactamente{} #2#", - "manos restantes", + "mano#2# restante#2#", }, }, j_cry_circus = { @@ -845,6 +1130,11 @@ return { "Comodines {C:legendary}legendarios{} otorgan {X:mult,C:white} X#3# {} multi", "Comodines {C:cry_exotic}exóticos{} otorgan {X:mult,C:white} X#4# {} multi", }, + unlock = { + "Obtén un comodín {C:red}raro{},", + "{C:cry_epic}épico{} y {C:legendary}legendario{}", + "antes de la {C:attention}apuesta 9", + }, }, j_cry_clash = { name = "El conflicto", @@ -853,8 +1143,20 @@ return { "si la mano contiene", "una {C:attention}#2#", }, + unlock = { + "Gana una partida con", + "tu última mano siendo", + "una {E:1,C:attention}Pareja suprema", + }, + }, + j_cry_clicked_cookie = { + name = "Galleta clickeada", + text = { + "{C:chips}+#1#{} ficha#1#", + "{C:chips}-#2#{} ficha#2# al", + "hacer {C:attention}clic", + }, }, - j_cry_CodeJoker = { name = "Comodín de código", text = { @@ -862,6 +1164,22 @@ return { "{C:dark_edition}negativa{} cuando se", "selecciona una {C:attention}ciega{}", }, + unlock = { + "Descubre {C:attention}todas", + "las {C:cry_code}cartas de código", + }, + }, + j_cry_CodeJoker_modest = { + name = "Code Joker", + text = { + "Crea una {C:cry_code}carta de código{}", + "{C:dark_edition}negativa{} cuando se", + "selecciona una {C:attention}ciega jefe{}", + }, + unlock = { + "Descubre {C:attention}todas", + "las {C:cry_code}cartas de código", + }, }, j_cry_coin = { name = "Moneda crypto", @@ -883,9 +1201,25 @@ return { j_cry_copypaste = { name = "Copiar y pegar", text = { - "Cuando una carta {C:cry_code}código{} se usa,", - "{C:green}#1# en #2#{} probabilidades para añadir", - "una copia a tus consumibles", + "{C:green}#1# in #2#{} probabilidades de", + "duplicar cartas de {C:cry_code}código{} usadas", + "{C:red}Funciona 1 vez por ronda{}", + "{C:inactive}(debe haber espacio)", + }, + }, + j_cry_copypaste_modest = { + name = "Copiar y pegar", + text = { + "Duplica las cartas de ", + "{C:cry_code}código{} tiradas", + "{C:inactive}(debe haber espacio)", + }, + }, + j_cry_copypaste_madness = { + name = "Copiar y pegar", + text = { + "{C:green}#1# in #2#{} probabilidades de", + "duplicar cartas de {C:cry_code}código{} usadas", "{C:inactive}(debe haber espacio)", }, }, @@ -899,10 +1233,10 @@ return { j_cry_crustulum = { name = "Crustulum", text = { - "Este comodín gana {C:chips}+#2#{} fichas", + "Este comodín gana {C:chips}+#2#{} ficha#2#", "por cada {C:attention}renovación{} en la tienda", "{C:green}Todas las renovaciones son gratis{}", - "{C:inactive}(Actual: {C:chips}+#1#{C:inactive} fichas)", + "{C:inactive}(Actual: {C:chips}+#1#{C:inactive} ficha#1#)", }, }, j_cry_cryptidmoment = { @@ -916,7 +1250,7 @@ return { j_cry_cube = { name = "Cubo", text = { - "{C:chips}+#1#{} fichas", + "{C:chips}+#1#{} ficha#1#", }, }, j_cry_curse_sob = { @@ -927,13 +1261,17 @@ return { "{C:dark_edition,E:1}no puedes escapar...{}", "{C:inactive}(debe haber espacio){}", }, + unlock = { + "Consigue un {C:attention}Obelisco", + "{C:purple}eterno{}", + }, }, j_cry_cursor = { name = "Cursor", text = { - "Este comodín gana {C:chips}+#2#{} fichas", + "Este comodín gana {C:chips}+#2#{} ficha#2#", "por cada carta {C:attention}comprada{}", - "{C:inactive}(Actual: {C:chips}+#1#{C:inactive} fichas)", + "{C:inactive}(Actual: {C:chips}+#1#{C:inactive} ficha#1#)", }, }, j_cry_cut = { @@ -954,6 +1292,15 @@ return { "un {C:attention}#2#", }, }, + j_cry_digitalhallucinations = { + name = "Halucinaciones digitales", + text = { + "Al abrir un {C:attention}paquete potenciador{},", + "{C:green}#1# en #2#{} probabilidades de crear", + "una carta {C:dark_edition}negativa{} al azar", + "de su respectivo {C:attention}tipo{}", + }, + }, j_cry_discreet = { name = "Comodín discreto", text = { @@ -980,6 +1327,14 @@ return { "{C:inactive,s:0.8}(crece por by +1, +2, +3)", }, }, + ["j_cry_Double Scale_modest"] = { + name = "Escala doble", + text = { + "Los {C:attention}comodines{} escaladores", + "aumentan el {C:attention}doble{} de rápido", + '{C:inactive,s:0.8}"¡Se llama Escala doble, no Escala cuadrática!"', + }, + }, j_cry_dropshot = { name = "Tiro al blanco", text = { @@ -988,11 +1343,16 @@ return { "el palo cambia en cada ronda", "{C:inactive}(Actual: {X:mult,C:white} X#3# {C:inactive} multi)", }, + unlock = { + "Juega una {C:attention}Carta más alta{}", + "con {C:attention}4{} cartas", + "del {C:attention}mismo palo", + }, }, j_cry_dubious = { name = "Comodín dudoso", text = { - "{C:chips}+#1#{} fichas", + "{C:chips}+#1#{} ficha#1#", "si la mano contiene", "una {C:attention}#2#", }, @@ -1004,6 +1364,11 @@ return { "si la mano contiene", "una {C:attention}#2#", }, + unlock = { + "Gana una partida", + "sin jugar", + "una {E:1,C:attention}Doble pareja", + }, }, j_cry_duplicare = { name = "Duplicare", @@ -1027,7 +1392,7 @@ return { name = "Energia", text = { "Cuando obtienes una {C:attention}etiqueta{},", - "crea {C:attention}#1#{} copias de ésta,", + "crea hasta {C:attention}#1#{} copia#1# de ésta,", "y {C:attention}aumenta{} la cantidad de", "copias por {C:attention}#2#", }, @@ -1037,7 +1402,7 @@ return { text = { "Comodines aparecen usando el", "orden de la {C:attention}colección{}", - "Crea {C:attention}#1#{} comodín(es) {C:dark_edition}negativos{}", + "Crea {C:attention}#1#{} comod#1# {C:dark_edition}negativo#1#{}", "al jugar una mano", "{C:inactive,s:0.8}Comodines {C:cry_exotic,s:0.8}exóticos {C:inactive,s:0.8}o mejores no pueden aparecer", "{s:0.8}Último comodín generado: {C:attention,s:0.8}#2#", @@ -1050,6 +1415,15 @@ return { }, }, j_cry_eternalflame = { + name = "Llama eterna", + text = { + "Este comodín gana {X:mult,C:white} X#1# {} multi", + "por cada carta {C:attention}vendida{} con", + "al menos {C:money}$3{} de {C:attention}valor de venta", + "{C:inactive}(Actual: {X:mult,C:white} X#2# {C:inactive} multi)", + }, + }, + j_cry_eternalflame2 = { -- no clue if this was unintentional but im porting it just in case name = "Llama eterna", text = { "Este comodín gana {X:mult,C:white} X#1# {} multi", @@ -1076,7 +1450,7 @@ return { name = "Expuesto", text = { "Reactiva todas las cartas {C:attention}numéricas{}", - "{C:attention}#1#{} veces adicionales", + "{C:attention}#1#{} ve#1# adicional#1#", "Todas las cartas de {C:attention}figura{} se debilitan", }, }, @@ -1095,12 +1469,22 @@ return { "si la mano contiene", "una {C:attention}#2#", }, + unlock = { + "Gana una partida", + "sin jugar", + "una {E:1,C:attention}Carta más alta", + }, }, j_cry_fractal = { name = "Dedos fractales", text = { "{C:attention}+#1#{} límite de selección de cartas", }, + unlock = { + "Juega una {C:attention}Escalera de color{}", + "sin la {C:attention}Escalera", + "siendo un {C:attention}Color", + }, }, j_cry_flip_side = { name = "Por el otro lado", @@ -1115,8 +1499,8 @@ return { name = "M de comida rápida", text = { "{C:mult}+#1#{} multi", - "{C:red,E:2}se autodestruye{} en {C:attention}#2#{} ronda(s)", - "Aumenta por {C:attention}#3#{} ronda cuando un", + "{C:red,E:2}se autodestruye{} en {C:attention}#2#{} ronda#2#", + "Aumenta por {C:attention}#3#{} ronda#3# cuando un", "{C:attention}comodín contento{} es {C:attention}vendido{}", "{C:inactive,s:0.8}2 McDoubles, 2 McChickens{}", "{C:inactive,s:0.8}Large Fries, 20 Piece & Large Cake{}", @@ -1134,7 +1518,7 @@ return { name = "Formidiulosus", text = { "Cuando un comodín {X:cry_cursed,C:white}maldito{} es obtenido, destrúyelo", - "Crea {C:attention}#1#{} {C:cry_candy}dulces {C:dark_edition}negativos{} al final de la tienda", + "Crea {C:attention}#1#{} {C:cry_candy}dulce#1# {C:dark_edition}negativo#1#{} al final de la tienda", "Gana {X:dark_edition,C:white}^#2#{} multi por cada {C:cry_candy}dulce{} en tu posesión", "{C:inactive}(Actual: {X:dark_edition,C:white}^#3#{C:inactive} multi)", }, @@ -1142,7 +1526,7 @@ return { j_cry_foxy = { name = "Comodín astuto", text = { - "{C:chips}+#1#{} fichas", + "{C:chips}+#1#{} ficha#1#", "si la mano contiene", "un {C:attention}#2#", }, @@ -1150,14 +1534,14 @@ return { j_cry_fspinner = { name = "Fidget Spinner", text = { - "Este comodín gana {C:chips}+#2#{} fichas", + "Este comodín gana {C:chips}+#2#{} ficha#2#", "si la mano jugada {C:attention}no es{}", "la {C:attention}mano de póker{} más jugada", - "{C:inactive}(Actual: {C:chips}+#1#{C:inactive} fichas)", + "{C:inactive}(Actual: {C:chips}+#1#{C:inactive} ficha#1#)", }, }, j_cry_fuckedup = { - name = "Comodín jodido", + name = Cryptid_config.family_mode and "Comodín ordenado" or "Comodín jodido", text = { "{C:red}+#1#{} multi", "si la mano contiene", @@ -1213,6 +1597,10 @@ return { "{C:green}#1# en #2#{} probabilidades de", "{X:red,C:white} X#3# {} multi", }, + unlock = { + "Consigue {C:attention}1.0e100{} fichas", + "en una sola mano", + }, }, j_cry_happy = { name = ":D", @@ -1240,6 +1628,11 @@ return { "si la mano contiene", "un {C:attention}#2#", }, + unlock = { + "Gana una partida", + "sin jugar", + "un {E:1,C:attention}Full", + }, }, j_cry_hunger = { name = "Consum-ible", @@ -1248,11 +1641,18 @@ return { "usas un {C:attention}consumible{}", }, }, + j_cry_huntingseason = { + name = "Época de caza", + text = { + "Si la mano jugada contiene exactalemte {C:attention}3{} cartas,", + "{C:red}destruye{} la carta {C:attention}central{} después de puntuar", + }, + }, j_cry_iterum = { name = "Iterum", text = { "Reactiva todas las cartas jugadas", - "{C:attention}#2#{} vez,", + "{C:attention}#2#{} ve#2#,", "cada carta jugada otorga", "{X:mult,C:white} X#1# {} multi cuando puntúa", }, @@ -1274,6 +1674,11 @@ return { "{C:attention}mano de póker{} más jugada", "{C:inactive}(Actual: {X:mult,C:white} X#2# {C:inactive} multi)", }, + unlock = { + "Gana una partida", + "jugando {C:attention}sólo un tipo de{}", + "{C:attention}mano de póker", + }, }, j_cry_jollysus = { name = "¿Comodín contento?", @@ -1285,6 +1690,14 @@ return { "{C:inactive,s:0.8}Parece legítimo...{}", }, }, + j_cry_jtron = { + name = "Jimbo-tron 9000", + text = { + "Este comodín gana {X:dark_edition,C:white}^#1#{} multi", + "por cada {C:attention}Comodín{} por defecto", + "{C:inactive}(Actual: {X:dark_edition,C:white}^#2#{C:inactive} multi)", + }, + }, j_cry_kidnap = { name = "Secuestro", text = { @@ -1318,6 +1731,20 @@ return { "un {C:attention}comodín{} aleatorio al", "derrotar la {C:attention}ciega jefe{}", }, + unlock = { + "Vence una {C:attention}ciega jefe", + "con {C:attention}5{} o más", + "{C:attention}cartas {} o {C:attention}comodines", + "con {C:attention}ediciones", + }, + }, + j_cry_lebaron_james = { + name = "LeBaron James", + text = { + "{C:attention}Reyes{} jugados y puntuados otorgan", + "{C:attention}+#1#{} tamaño de mano por esta ronda", + "y activan efectos de {C:attention}tener en la mano{}", + }, }, j_cry_lightupthenight = { name = "Ilumina la noche", @@ -1341,7 +1768,7 @@ return { "{C:attention}Reactiva{} todos los comodines", "una vez por cada {C:attention}comodín{}", "{C:attention}contento{} vendido esta ronda", - "{C:inactive}(Actual:{}{C:attention:} #1#{}{C:inactive} reactivaciones){}", + "{C:inactive}(Actual:{}{C:attention:} #1#{}{C:inactive} reactivaci#2#){}", "{C:inactive,s:0.8}No había suficiente espacio...{}", }, }, @@ -1376,13 +1803,13 @@ return { "selecciona una {C:attention}ciega{}", }, }, - j_cry_macabre = { + j_cry_macabre = { -- macabre my god damn beloathed name = "Comodín macabro", text = { "Al seleccionar una {C:attention}ciega{},", "destruye todos los {C:attention}comodines{} excepto", "{C:legendary}comodines M{} y {C:attention}comodines contentos{}", - "y crea 1 {C:attention}comodín contento{}", + "y crea #1# {C:attention}comod#1# contento#1#{}", "por cada carta destruida", }, }, @@ -1406,14 +1833,14 @@ return { name = "Mario", text = { "Reactiva todos los comodines", - "{C:attention}#1#{} veces adicionales", + "{C:attention}#1#{} ve#1# adicional#1#", }, }, j_cry_mask = { name = "Máscara", text = { "Reactiva todas las cartas de {C:attention}figura{}", - "{C:attention}#1#{} veces adicionales", + "{C:attention}#1#{} ve#1# adicional#1#", "Todas las cartas {C:attention}numéricas{} se debilitan", }, }, @@ -1426,6 +1853,10 @@ return { "todas las cartas de {C:attention}número{}", "son consideradas {C:attention}10s{}", }, + unlock = { + "Juega un {C:attention}Cinco de color{}", + "de {C:attention}Reyes", + }, }, j_cry_maze = { name = "Laberinto", @@ -1440,7 +1871,7 @@ return { name = "Muevo", text = { "Vende esta carta para crear", - "{C:attention}#2#{} Comodines contentos, aumenta", + "{C:attention}#2#{} Comod#2# contento#2#, aumenta", "por {C:attention}#1#{} al final de la ronda", }, }, @@ -1458,23 +1889,33 @@ return { "{X:mult,C:white}X#1#{} multi por cada miembro", "en el {C:attention}Discord de Cryptid{}", "{C:inactive}(Actual: {X:mult,C:white}X#2#{C:inactive} multi)", - "{C:blue,s:0.7}https://discord.gg/eUf9Ur6RyB{}", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", }, }, j_cry_membershipcardtwo = { name = "Carta de miembro antigua", --renamed it for making it distinct text = { - "{C:chips}+#1#{} fichas por cada miembro", + "{C:chips}+#1#{} ficha#1# por cada miembro", "en el {C:attention}Discord de Cryptid{}", "{C:inactive}(Actual: {C:chips}+#2#{C:inactive} fichas)", - "{C:blue,s:0.7}https://discord.gg/eUf9Ur6RyB{}", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", + }, + }, + j_cry_membershipcardtwo_balanced = { + name = "Carta de miembro antigua", + text = { + "{C:chips}+#1#{} ficha#1# por cada {C:attention}8{} miembros", + "en el {C:attention}Discord de Cryptid{}", + "{C:inactive}(Actual: {C:chips}+#2#{C:inactive} fichas)", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", }, }, j_cry_meteor = { name = "Lluvia de meteoros", text = { "Las cartas {C:dark_edition}laminadas{}", - "otorgan {C:chips}+#1#{} fichas", + "otorgan {C:chips}+#1#{} ficha#1#", }, }, j_cry_mneon = { @@ -1503,7 +1944,7 @@ return { "destruye al comodín de la izquierda", "y agrega para siempre {C:attention}10 veces", "de valor de venta a estas {C:chips}fichas{}", - "{C:inactive}(Currently {C:chips}+#1#{C:inactive} Chips)", + "{C:inactive}(Actual: {C:chips}+#1#{C:inactive} ficha#1#)", }, }, j_cry_monopoly_money = { @@ -1538,8 +1979,8 @@ return { text = { "Reactiva todas las cartas jugadas", "una vez por cada", - "{C:attention}#2#{} {C:inactive}[#3#]{} {C:attention}comodines contentos{} vendidos", - "{C:inactive}(Actual:{}{C:attention:} #1#{}{C:inactive} reactivaciones){}", + "{C:attention}#2#{} {C:inactive}[#3#]{} {C:attention}comod#2# contento#2#{} vendido#2#", + "{C:inactive}(Actual:{}{C:attention:} #1#{}{C:inactive} reactivaci#1#){}", }, }, j_cry_multjoker = { @@ -1562,13 +2003,13 @@ return { j_cry_negative = { name = "Comodín negativo", text = { - "{C:dark_edition}+#1#{} ranuras de {C:attention}comodín", + "{C:dark_edition}+#1#{} ranura#1# de {C:attention}comodín", }, }, j_cry_nice = { name = "Nice", text = { - "{C:chips}+#1#{} fichas si la mano jugada", + "{C:chips}+#1#{} ficha#1# si la mano jugada", "contiene un {C:attention}6{} y un {C:attention}9", "{C:inactive,s:0.8}Nice.{}", }, @@ -1586,13 +2027,13 @@ return { name = "Sin sonido, sin memoria", text = { "Reactiva cada {C:attention}7{} jugado", - "{C:attention:}#1#{} veces adicionales", + "{C:attention:}#1#{} ve#1# adicional#1#", }, }, j_cry_notebook = { - name = "Cuaderno", + name = "El Muaderno", text = { - "{C:green} #1# en #2#{} probabilidades para conseguir {C:dark_edition}+1{} ranura", + "{C:green} #1# en #2#{} probabilidades para conseguir {C:dark_edition}+#6#{} ranura#6#", "de comodín por cada {C:attention}renovación{} en la tienda", "{C:green}Siempre se activa{} si hay", "{C:attention}#5#{} o más {C:attention}Comodines contentos{}", @@ -1616,6 +2057,11 @@ return { "si la mano contiene", "una {C:attention}#2#", }, + unlock = { + "Gana una partida", + "sin jugar", + "una {E:1,C:attention}Escalera de color", + }, }, j_cry_nutty = { name = "Comodín loco", @@ -1628,8 +2074,8 @@ return { j_cry_oil_lamp = { name = "Lámpara de aceite", text = { - "Al final de la ronda, aumenta los valores", - "del comodín a la {C:attention}derecha{} por {X:attention,C:white}X#1#{}", + "Al final de la ronda, aumenta los valores del", + "comodín a la {C:attention}derecha{} por {X:attention,C:white}X#1#{}", }, }, @@ -1671,7 +2117,7 @@ return { j_cry_penetrating = { name = "Comodín penetrante", text = { - "{C:chips}+#1#{} fichas", + "{C:chips}+#1#{} ficha#1#", "si la mano contiene", "un {C:attention}#2#", }, @@ -1680,7 +2126,7 @@ return { name = "Pepinillo", text = { "Al saltar una {C:attention}ciega{}, crea", - "{C:attention}#1#{} etiquetas, disminuye por", + "{C:attention}#1#{} etiqueta#1#, disminuye por", "{C:red}#2#{} cuando se selecciona una {C:attention}ciega{}", }, }, @@ -1709,6 +2155,10 @@ return { "aumenta por", "{C:blue}#2#{} cada runda", }, + unlock = { + "Aumenta tu {C:attention}tamaño de mano", + "a {C:attention}12", + }, }, j_cry_primus = { name = "Primus", @@ -1719,6 +2169,23 @@ return { "{C:inactive}(Actual: {X:dark_edition,C:white} ^#2# {C:inactive} multi)", }, }, + j_cry_pumpkin = { + name = "Calabaza", + text = { + "Evita la muerte si las fichas obtenidas", + "son al menos {C:attention}50%{} de lo requerido", + "{C:attention}Se convierte en Calabaza tallada", + "{C:attention}al {S:1.1,C:red,E:2}destruirse{}", + }, + }, + j_cry_carved_pumpkin = { + name = "Calabaza tallada", + text = { + "Las siguientes {C:attention}#1#{} ciegas jefes", + "tendrán sus habilidades", + "{C:attention}desactivadas", + }, + }, j_cry_python = { name = "Python", text = { @@ -1744,11 +2211,16 @@ return { "si la mano contiene", "un {C:attention}#2#", }, + unlock = { + "Gana una partida con", + "tu última mano siendo", + "un {E:1,C:attention}Repóquer", + }, }, j_cry_redbloon = { name = "Bloon rojo", text = { - "Gana {C:money}$#1#{} en {C:attention}#2#{} ronda(s)", + "Gana {C:money}$#1#{} en {C:attention}#2#{} ronda#2#", "{C:red,E:2}se autodestruye{}", }, }, @@ -1786,12 +2258,17 @@ return { text = { "Aleatoriza abilidades por cada {C:attention}apuesta{}", }, + unlock = { + "{C:green}1 en 20{} probabilidades", + "de desbloquear esta carta", + "al {C:attention}terminar una partida", + }, }, j_cry_sacrifice = { name = "Sacrificio", text = { - "Crea un comodín {C:green}inusual{}", - "y 3 {C:attention}Comodines contentos{} al", + "Crea #3# comod#3# {C:green}inusual#3#{}", + "y #2# {C:attention}Comod#2# contento#2#{} al", "usar una carta {C:spectral}espectral{}", "{C:red}Funciona una vez por ronda{}", "{C:inactive}#1#{}", @@ -1802,15 +2279,13 @@ return { text = { "Después de puntuar {C:attention}#2#{} {C:inactive}[#1#]{} cartas", "mejoradas, vende esta carta para", - "crear un {C:attention}comodín{} {C:cry_epic}épico{} ", - "{C:inactive,s:0.8}Creará un {C:attention,s:0.8}comodín{} {C:red,s:0.8}raro{} si los", - "{C:inactive,s:0.8}comodines {C:cry_epic,s:0.8}épicos{} {C:inactive,s:0.8}están desactivados{}", + "crear #4# {C:attention}comodín{} {V:1}#3#{}", }, }, j_cry_savvy = { name = "Comodín inteligente", text = { - "{C:chips}+#1#{} fichas", + "{C:chips}+#1#{} ficha#1#", "si la mano contiene", "un {C:attention}#2#", }, @@ -1843,7 +2318,7 @@ return { j_cry_shrewd = { name = "Comodín perspicaz", text = { - "{C:chips}+#1#{} fichas", + "{C:chips}+#1#{} ficha#1#", "si la mano contiene", "un {C:attention}#2#", }, @@ -1865,14 +2340,33 @@ return { "{C:inactive,s:0.8}ok so básicamente soy muy peque", }, }, - j_cry_soccer = { - name = "Uno para todos", --changed the name from latin because this isn't exotic + j_cry_soccer = { --why tf is this called soccer again + name = "Uno para todos", text = { - "{C:attention}+#1#{} ranura de comodín", - "{C:attention}+#1#{} ranura de paquete potenciador", + "{C:attention}+#1#{} ranura#1# de comodín", + "{C:attention}+#1#{} ranura#1# de paquete potenciador", "{C:attention}+#1#{} tamaño de mano", - "{C:attention}+#1#{} ranura de consumible", - "{C:attention}+#1#{} ranura de carta en la tienda", + "{C:attention}+#1#{} ranura#1# de consumible", + "{C:attention}+#1#{} ranura#1# de carta en la tienda", + "{C:attention}+#1#{} ranura#1# de vales", + }, + unlock = { + "Gana una partida sólo", + "jugando {C:attention}Carta más alta", + }, + }, + j_cry_soccer_balanced = { + name = "Uno para todos", + text = { + "{C:attention}+#1#{} ranura#1# de paquete potenciador", + "{C:attention}+#1#{} tamaño de mano", + "{C:attention}+#1#{} ranura#1# de consumible", + "{C:attention}+#1#{} ranura#1# de carta en la tienda", + "{C:attention}+#1#{} ranura#1# de vales", + }, + unlock = { + "Gana una partida sólo", + "jugando {C:attention}Carta más alta", }, }, j_cry_fleshpanopticon = { @@ -1895,6 +2389,14 @@ return { "{C:inactive}(Actual:{} {X:chips,C:white}X#1#{} {C:inactive}fichas){}", }, }, + j_cry_spectrogram = { + name = "Espectograma", + text = { + "Reactiva el comodín del {C:attention}extremo derecho{}", + "una vez por cada {C:attention}Carta de eco", + "jugada y puntuada", + }, + }, j_cry_speculo = { name = "Speculo", text = { @@ -1935,12 +2437,17 @@ return { "si la mano contiene", "un {C:attention}#2#", }, + unlock = { + "Gana una partida con", + "tu última mano siendo", + "un {E:1,C:attention}Baluarte", + }, }, j_cry_subtle = { name = "Comodín sutil", text = { - "{C:chips}+#1#{} fichas", + "{C:chips}+#1#{} ficha#1#", "si la mano contiene", "un {C:attention}#2#", }, @@ -1948,7 +2455,15 @@ return { j_cry_supercell = { name = "Supercell", text = { - "{C:chips}+#1#{} fichas, {C:mult}+#1#{} multi,", + "{C:chips}+#1#{} ficha#1#, {C:mult}+#1#{} multi,", + "{X:chips,C:white}X#2#{} fichas, {X:mult,C:white}X#2#{} multi", + "Gana {C:money}$#3#{} al", + "final de la ronda", + }, + }, + j_cry_supercell_balanced = { + name = "Supercell", + text = { "{X:chips,C:white}X#2#{} fichas, {X:mult,C:white}X#2#{} multi", "Gana {C:money}$#3#{} al", "final de la ronda", @@ -1971,6 +2486,11 @@ return { "si la mano contiene", "un {C:attention}#2#", }, + unlock = { + "Gana una partida con", + "tu última mano siendo", + "un {E:1,C:attention}Cinco de color", + }, }, j_cry_sync_catalyst = { name = "Catalizador de sincronización", @@ -1989,7 +2509,7 @@ return { j_cry_tenebris = { name = "Tenebris", text = { - "{C:dark_edition}+#1#{} ranuras de {C:attention}comodín{}", + "{C:dark_edition}+#1#{} ranura#1# de {C:attention}comodín{}", "Gana {C:money}$#2#{} al final de la ronda", }, }, @@ -2005,7 +2525,7 @@ return { j_cry_treacherous = { name = "Comodín traicionero", text = { - "{C:chips}+#1#{} fichas", + "{C:chips}+#1#{} ficha#1#", "si la mano contiene", "un {C:attention}#2#", }, @@ -2022,7 +2542,7 @@ return { j_cry_tricksy = { name = "Comodín tramposo", text = { - "{C:chips}+#1#{} fichas", + "{C:chips}+#1#{} ficha#1#", "si la mano contiene", "una {C:attention}#2#", }, @@ -2039,7 +2559,7 @@ return { text = { "Vende esta carta para", "{C:attention}multiplicar{} los valores de los", - "comodines conseguidos por {X:attention,C:white}X1.5{}", + "comodines conseguidos por {X:attention,C:white}X#1#{}", }, }, @@ -2050,6 +2570,11 @@ return { "si la mano contiene", "un {C:attention}#2#", }, + unlock = { + "Gana una partida con", + "tu última mano siendo", + "un {E:1,C:attention}Full de color", + }, }, j_cry_universe = { name = "Universo", @@ -2132,7 +2657,7 @@ return { name = "2D", text = { "Reactica cada {C:attention}2{} jugado", --wee gaming - "{C:attention:}#1#{} veces adicionales", --wee gaming? + "{C:attention:}#1#{} ve#1# adicional#1#", --wee gaming? "{C:inactive,s:0.8}Wee Gaming?{}", --wee gaming :) }, }, @@ -2158,22 +2683,37 @@ return { name = "Dulce envuelto", text = { "Crea un {C:attention}comodín de comida{}", - "en {C:attention}#1#{} ronda(s)", + "en {C:attention}#1#{} ronda#1#", "{C:red,E:2}se autodestruye{}", }, }, j_cry_wtf = { - name = "¡¿Qué rayos?!", + name = Cryptid_config.family_mode and "El desorden" or "¡¿Qué mierda?!", text = { "{X:mult,C:white} X#1# {} multi", "si la mano contiene", "un {C:attention}#2#", }, + unlock = { + "Gana una partida con", + "tu última mano siendo", + "un {E:1,C:attention}Lío de mierda", + }, + }, + j_cry_zooble = { + name = "Zooble", + text = { + "Si la mano jugada", + "{C:attention}no{} contiene una {C:attention}Escalera{},", + "este comodín gana {C:mult}+#2#{} multi por cada", + "{C:attention}categoría única{} en la mano puntuada", + "{C:inactive}(Actual {C:mult}+#1#{C:inactive} multi)", + }, }, }, Planet = { c_cry_Klubi = { - name = "Klubi", + name = "Risti", text = { "({V:1}nvl.#4#{})({V:2}nvl.#5#{})({V:3}nvl.#6#{})", "Aumento de nivel", @@ -2183,7 +2723,7 @@ return { }, }, c_cry_Lapio = { - name = "Lapio", + name = "Pata", text = { "({V:1}nvl.#4#{})({V:2}nvl.#5#{})({V:3}nvl.#6#{})", "Aumento de nivel", @@ -2195,7 +2735,7 @@ return { c_cry_Kaikki = { name = "Kaikki", text = { - "({V:1}lvl.#4#{})({V:2}lvl.#5#{})({V:3}lvl.#6#{})", + "({V:1}nvl.#4#{})({V:2}nvl.#5#{})({V:3}nvl.#6#{})", "Aumento de nivel", "{C:attention}#1#{},", "{C:attention}#2#{},", @@ -2223,7 +2763,7 @@ return { }, }, c_cry_Sydan = { - name = "Sydan", + name = "Hertta", text = { "({V:1}nvl.#4#{})({V:2}nvl.#5#{})({V:3}nvl.#6#{})", "Aumento de nivel", @@ -2233,7 +2773,7 @@ return { }, }, c_cry_Timantti = { - name = "Timantti", + name = "Ruutu", text = { "({V:1}nvl.#4#{})({V:2}nvl.#5#{})({V:3}nvl.#6#{})", "Aumento de nivel", @@ -2248,7 +2788,7 @@ return { "{S:0.8}({S:0.8,V:1}nvl. #1#{S:0.8}){} Aumento de nivel", "{C:attention}#2#", "{C:mult}+#3#{} multi y", - "{C:chips}+#4#{} fichas", + "{C:chips}+#4#{} ficha#4#", }, }, c_cry_void = { @@ -2257,7 +2797,7 @@ return { "{S:0.8}({S:0.8,V:1}nvl. #1#{S:0.8}){} Aumento de nivel", "{C:attention}#2#", "{C:mult}+#3#{} multi y", - "{C:chips}+#4#{} fichas", + "{C:chips}+#4#{} ficha#4#", }, }, c_cry_asteroidbelt = { @@ -2266,29 +2806,68 @@ return { "{S:0.8}({S:0.8,V:1}nvl. #1#{S:0.8}){} Aumento de nivel", "{C:attention}#2#", "{C:mult}+#3#{} multi y", - "{C:chips}+#4#{} fichas", + "{C:chips}+#4#{} ficha#4#", }, }, c_cry_universe = { - name = "El universo en su puta totalidad", + name = Cryptid_config.family_mode and "El universo" or "El universo en su puta totalidad", text = { "{S:0.8}({S:0.8,V:1}nvl. #1#{S:0.8}){} Aumento de nivel", "{C:attention}#2#", "{C:mult}+#3#{} multi y", - "{C:chips}+#4#{} fichas", + "{C:chips}+#4#{} ficha#4#", + }, + }, + c_cry_sunplanet = { + name = "Sol", --already translated heh + text = { + "{S:0.8}({S:0.8,V:1}lvl.#1#{S:0.8}){}", + "Aumenta el poder de", + "las {C:attention}manos ascendidas{} por {X:gold,C:white}0.05{}", + "{C:inactive}(Actual: {X:gold,C:white}X(#2#^asc){C:inactive})", }, }, }, Sleeve = { + sleeve_cry_beige_sleeve = { + name = "Funda Castaña", + text = { + "Los comodines {C:attention}comunes{}", + "tienen valores {C:attention}cuadruplicados{}", + }, + }, + sleeve_cry_beige_sleeve_alt = { + name = "Funda Castaña", + text = { + "Los comodines {C:attention}inusuales{}", + "tienen valores {C:attention}cuadruplicados{}", + }, + }, + sleeve_cry_beta_sleeve = { + name = "Funda Nostálgica", + text = { + "Las ranuras de {C:attention}comodín{} y", + "{C:attention}consumibles{} se {C:attention}combinan", + "Las ciegas {C:attention}nostálgicas{} reemplazan", + "sus ciegas actualizadas", + }, + }, + sleeve_cry_bountiful_sleeve = { + name = "Funda Abundante", + text = { + "Siempre saca 5 cartas después", + "de cada {C:attention}mano jugada{} o {C:attention}descarte{}", + }, + }, sleeve_cry_ccd_sleeve = { - name = "Manga CCD", + name = "Funda CCD", text = { "Todas las cartas también son", "un consumible {C:attention}aleatorio{}", }, }, sleeve_cry_conveyor_sleeve = { - name = "Manga transportadora", + name = "Funda Transportadora", text = { "Los comodines {C:attention}no{} se pueden mover", "Al principio de la runda,", @@ -2297,7 +2876,7 @@ return { }, }, sleeve_cry_critical_sleeve = { - name = "Manga crítica", + name = "Funda Crítica", text = { "Después de cada mano jugada,", "{C:green}#1# en 4{} probabilidades para {X:dark_edition,C:white} ^2 {} multi", @@ -2305,7 +2884,7 @@ return { }, }, sleeve_cry_encoded_sleeve = { - name = "Manga codificada", + name = "Funda Codificada", text = { "Comienza con un {C:cry_code,T:j_cry_CodeJoker}Comodín de código{}", "y {C:cry_code,T:j_cry_copypaste}Copiar y pegar{}", @@ -2313,7 +2892,7 @@ return { }, }, sleeve_cry_equilibrium_sleeve = { - name = "Manga balanceada", + name = "Funda Balanceada", text = { "Todas las cartas tienen la ", "{C:attention}misma probabilidad{} de", @@ -2322,8 +2901,17 @@ return { "{C:attention,T:v_overstock_plus}+2 ranuras de carta", }, }, + sleeve_cry_glowing_sleeve = { + name = "Funda Brillante", + text = { + "Multiplica los valores de", + "todos los comodines por {X:dark_edition,C:white} X1.25 {}", + "cuando se derrota a la {C:attention}ciega jefe{}", + "{X:cry_jolly,C:white,s:0.8} Jolly#1#Open#1#Winner#1#-#1#wawa#1#person", --peak loc_vars right here + }, + }, sleeve_cry_infinite_sleeve = { - name = "Baraja infinita", + name = "Funda Infinita", text = { "Puedes seleccionar {C:attention}cualquier", "cantidad de cartas", @@ -2331,21 +2919,38 @@ return { }, }, sleeve_cry_misprint_sleeve = { - name = "Manga de errata", + name = "Funda de Errata", text = { "Los valures de cartas", "se {C:attention}aleatorizan", }, }, sleeve_cry_redeemed_sleeve = { - name = "Manga redimida", + name = "Funda Redimida", text = { "Cuando se compra un {C:attention}vale{},", "obtén sus {C:attention}niveles extras", }, }, + sleeve_cry_spooky_sleeve = { + name = "Funda Espeluznante", + text = { + "Comienza con un {C:attention,T:j_cry_chocolate_dice}Dado de chocolate {C:eternal}eterno{}", + "Después de cada {C:attention}apuesta{}, crea un comodín", + "de {C:cry_candy}dulce{} o {X:cry_cursed,C:white}maldito{}", + }, + }, + sleeve_cry_very_fair_sleeve = { --is there going to be an achievement for vfd + vfs + name = "Funda Muy Justa", + text = { + "{C:blue}-2{} hands, {C:red}-2{} discards", + "every round", + "{C:attention}Vouchers{} no longer", + "appear in the shop", + }, + }, sleeve_cry_wormhole_sleeve = { - name = "Manga de agujero de gusano", + name = "Funda de Agujero de Gusano", text = { "Comienza con un comodín {C:cry_exotic}exótico{C:attention}", "Los comodines son {C:attention}20X{} más", @@ -2354,7 +2959,7 @@ return { }, }, sleeve_cry_legendary_sleeve = { - name = "Manga legendaria<", + name = "Funda Legendaria", text = { "Comienza con un comodín {C:legendary}legendario{C:legendary}", "{C:green}1 en 5{} probabilidades para crear otro", @@ -2362,6 +2967,15 @@ return { "{C:inactive}(debe haber espacio){}", }, }, + sleeve_cry_antimatter_sleeve = { + name = "Funda de Antimateria", + text = { + "Aplica los {C:attention}efectos{}", + "y {C:attention}efectos especiales{}", + "de {C:attention}todas{} las fundas", + "{C:red}WIP", + }, + }, }, Spectral = { c_cry_adversary = { @@ -2375,7 +2989,7 @@ return { c_cry_analog = { name = "Análogo", text = { - "Crea {C:attention}#1#{} copias de un", + "Crea {C:attention}#1#{} copia#1# de un", "{C:attention}comodín{} aleatorio, destruye", "los demás, {C:attention}+#2#{} apuesta", }, @@ -2383,9 +2997,10 @@ return { c_cry_chambered = { name = "Recámara", text = { - "Crea {C:attention}#1#{} copias", + "Crea {C:attention}#1#{} copia#1#", "{C:dark_edition}negativas{} de un", "consumible {C:attention}al azar{}", + "en tu posesión", "{C:inactive,s:0.8}No copia otros Recámara{}", }, }, @@ -2444,14 +3059,14 @@ return { text = { "Aplica {C:dark_edition}Negativo{}, {C:dark_edition}Mosaico{},", "o {C:dark_edition}Astral{} a {C:attention}#1#{}", - "carta de tu mano seleccionada", + "carta#1# de tu mano seleccionada#1#", }, }, c_cry_source = { name = "Origen", text = { "Agrega un {C:cry_code}sello verde{}", - "a {C:attention}1{} carta seleccionada", + "a {C:attention}1{} carta#1# seleccionada#1#", "de tu mano al azar", }, }, @@ -2459,7 +3074,7 @@ return { name = "Evocación", text = { "Crea un {C:joker}comodín{}", - "{C:cry_epic}épico{} aleatorio, destruye", + "{V:1}#1#{} aleatorio, destruye", "un {C:joker}comodín{} al azar", }, }, @@ -2474,7 +3089,7 @@ return { name = "Tifón", text = { "Agrega un {C:cry_azure}sello azur{}", - "a {C:attention}1{} carta seleccionada", + "a {C:attention}1{} carta#1# seleccionada#1#", "de tu mano al azar", }, }, @@ -2488,6 +3103,14 @@ return { }, }, c_cry_white_hole = { + name = "Agujero blanco", + text = { + "Mejora la mano de póker", + "{C:legendary,E:1}más jugada{} por {C:attention}4{}", + "{C:attention}Remueve{} todos los niveles de las otras manos", + }, + }, + c_cry_white_hole2 = { name = "Agujero blanco", text = { "{C:attention}Remueve{} todos los niveles de mano,", @@ -2515,7 +3138,7 @@ return { }, stake_cry_yellow = { name = "Pozo amarillo", - colour = "amarilla", + colour = "amarillo", text = { "Las {C:attention}pegatinas{} pueden aparecer", "en todos los objetos comprables", @@ -2561,7 +3184,7 @@ return { name = "Pozo ámbar", colour = "ambar", text = { - "{C:attention}-1{} ranuras de paquete potenciador", + "{C:attention}-1{} ranura de paquete potenciador", }, }, stake_cry_bronze = { @@ -2614,7 +3237,7 @@ return { }, stake_cry_platinum = { name = "Pozo platino", - colour = "platina", + colour = "platino", text = { "Las ciegas pequeñas son {C:attention}removidas{}", }, @@ -2629,7 +3252,7 @@ return { }, stake_cry_verdant = { name = "Pozo verdoso", - colour = "verdosa", + colour = "verdoso", text = { "Escalas de puntos requeridas más rápidas", "para cada {C:attention}apuesta inicial", @@ -2662,7 +3285,7 @@ return { }, stake_cry_blossom = { name = "Pozo florido", - colour = "florida", + colour = "florido", text = { "Las ciegas {C:attention}finales{} pueden aparecer", "en {C:attention}cualquier{} apuesta", @@ -2704,8 +3327,8 @@ return { name = "Mejor etiqueta de recarga", text = { "Genera hasta {C:attention}#1#", - "comodines {C:green}inusuales{}", - "{C:inactive}(Debe haber espacio)", + "comod#1# {C:green}inusual#1#{}", + "{C:inactive}(debe haber espacio)", }, }, tag_cry_better_voucher = { @@ -2826,7 +3449,7 @@ return { tag_cry_memory = { name = "Etiqueta de memoria", text = { - "Crea {C:attention}#1#{} copias de", + "Crea {C:attention}#1#{} copia#1# de", "la última {C:attention}etiqueta{} usada", "durante esta partida", "{s:0.8,C:inactive}Etiquetas de copia excluidas", @@ -2852,7 +3475,7 @@ return { tag_cry_quadruple = { name = "Etiqueta cuádruple", text = { - "Otorga {C:attention}#1#{} copias de la", + "Otorga {C:attention}#1#{} copia#1# de la", "siguiente {C:attention}Tag{} seleccionada", "{s:0.8,C:inactive}Etiquetas de copia excluidas", }, @@ -2860,7 +3483,7 @@ return { tag_cry_quintuple = { name = "Etiqueta quíntuple", text = { - "Otorga {C:attention}#1#{} copias de la", + "Otorga {C:attention}#1#{} copia#1# de la", "siguiente {C:attention}Tag{} seleccionada", "{s:0.8,C:inactive}Etiquetas de copia excluidas", }, @@ -2882,14 +3505,14 @@ return { tag_cry_scope = { name = "Etiqueta de alcance", text = { - "{C:attention}+#1# {C:blue}manos{} y {C:red}descartes{}", + "{C:attention}+#1# {C:blue}mano#1#{} y {C:red}descarte#1#{}", "en la siguiente ronda", }, }, tag_cry_triple = { name = "Etiqueta triple", text = { - "Otorga {C:attention}#1#{} copias de la", + "Otorga {C:attention}#1#{} copia#1# de la", "siguiente {C:attention}Tag{} seleccionada", "{s:0.8,C:inactive}Etiquetas de copia excluidas", }, @@ -2900,15 +3523,15 @@ return { name = "El autómata", text = { "Genera hasta {C:attention}#1#", - "cartas de {C:cry_code}código{} al azar", + "carta#1# de {C:cry_code}código{} al azar", "{C:inactive}(Debe haber espacio)", }, }, c_cry_eclipse = { name = "El eclipse", text = { - "Mejora {C:attention}#1#{} carta", - "seleccionada a", + "Mejora {C:attention}#1#{} carta#1#", + "seleccionada#1# a", "una {C:attention}Carta de eco", }, }, @@ -2928,6 +3551,14 @@ return { "{C:inactive}(Debe haber espacio){}", }, }, + c_cry_seraph = { + name = "El serafín", + text = { + "Mejora {C:attention}#1#{} carta#1#", + "seleccionada#1# a", + "una {C:attention}Carta de luz", + }, + }, }, Voucher = { v_cry_asteroglyph = { @@ -2935,12 +3566,20 @@ return { text = { "Establece la apuesta a {C:attention}#1#{}", }, + unlock = { + "Llega a la apuesta inicial", + "nivel {E:1,C:attention}35", + }, }, v_cry_blankcanvas = { name = "Lienzo en blanco", text = { "{C:attention}+#1#{} tamaño de mano", }, + unlock = { + "Reduce el tamaño", + "de mano a {C:attention}0{} cartas", + }, }, v_cry_clone_machine = { name = "Máquina de clonar", @@ -2973,14 +3612,23 @@ return { "aparecen con", "una {C:dark_edition}edición{}", }, + unlock = { + "Descubre todas", + "las {C:attention}ediciones", + }, }, v_cry_dexterity = { name = "Destreza", text = { "Gana para siempre", - "{C:blue}+#1#{} mano(s)", + "{C:blue}+#1#{} mano#1#", "por ronda", }, + unlock = { + "Juega un total", + "de {C:attention}5000{} cartas", + "en total", + }, }, v_cry_double_down = { name = "Doble de apuesta", @@ -3009,7 +3657,11 @@ return { v_cry_fabric = { name = "Fábrica universal", text = { - "{C:dark_edition}+#1#{} ranura(s) de comodín", + "{C:dark_edition}+#1#{} ranura#1# de comodín", + }, + unlock = { + "Canjea {C:voucher}Antimateria{}", + "un total de {C:attention}10{} veces", }, }, v_cry_massproduct = { @@ -3018,22 +3670,38 @@ return { "Todas las cartas y paquetes", "en la tienca cuestan {C:attention}$1{}", }, + unlock = { + "Canjea al menos", + "{C:attention}25 {C:voucher} vales{}", + "en una partida", + }, }, v_cry_moneybean = { - name = "Money Beanstalk", + name = "Tallo de dinero", text = { "Aumenta el límite", "del interés obtenido en cada ronda", - "hasta {C:money}#1#${}", + "hasta {C:money}$#1#{}", + }, + unlock = { + "Maximiza las", + "{C:attention}ganancias de interés{}", + "por {C:attention}toda la partida", }, }, v_cry_overstock_multi = { name = "Multicapital", text = { - "{C:attention}+#1#{} ranura(s) de carta y", - "{C:attention}+#1#{} ranura(s) de paquetes potenciadores", + "{C:attention}+#1#{} ranura#1# de carta,", + "{C:attention}+#1#{} ranura#1# de paquetes potenciadores", + "y {C:attention}+#1#{} ranura#1# de vales", "disponibles en la tienda", }, + unlock = { + "Gasta un total", + "de {C:money}$1000{} en la tienda", + "en una partida", + }, }, v_cry_pacclimator = { name = "Aclamador de planetas", @@ -3041,8 +3709,14 @@ return { "Las cartas de {C:planet}planeta{} aparecen", "{C:attention}#1# X{} veces más seguido", "en la tienda", - "Todas las cartas de {C:planet}planeta{}", - "futuras son {C:green}gratis{}", + "Permite el control de la", + "{C:planet}tasa de planetas{}", + "{C:inactive}(revisa la {C:attention}área de info{C:inactive})", + }, + unlock = { + "Compra un total", + "{C:attention}100 cartas de {C:planet}planeta{}", + "en la tienda", }, }, v_cry_pairamount_plus = { @@ -3080,6 +3754,11 @@ return { "Todas las renovaciones", "cuestan {C:attention}$2{}", }, + unlock = { + "Renueva la tienda", + "un total de {C:attention}250{} veces", + "en una partida", + }, }, v_cry_satellite_uplink = { name = "Enlace satelital", @@ -3094,7 +3773,13 @@ return { text = { "Crea la carta de {C:planet}planeta", "por la {C:attention}mano de póker{} jugada", - "{C:inactive}(Must have room){}", + "{C:inactive}(debe haber espacio){}", + }, + unlock = { + "Usa un total de {C:attention}#1#", + "cartas de {C:planet}planeta{} de cualquier", + "{C:attention}paquete potenciador", + "en una partida", }, }, v_cry_tacclimator = { @@ -3103,8 +3788,14 @@ return { "Las cartas de {C:tarot}tarot{} aparecen", "{C:attention}#1# X{} veces más seguido", "en la tienda", - "Todas las cartas de {C:tarot}tarot{}", - "futuras son {C:green}gratis{}", + "Permite el control de la", + "{C:tarot}tasa de tarots{}", + "{C:inactive}(revisa la {C:attention}área de info{C:inactive})", + }, + unlock = { + "Compra un total", + "de {C:attention}100 cartas de{C:tarot} tarot{}", + "en la tienda", }, }, v_cry_tag_printer = { @@ -3119,9 +3810,13 @@ return { name = "Las 3 Rs", text = { "Consigue {C:red}+#1#{}", - "descartes en cada ronda", + "descarte#1# en cada ronda", "de forma permanente", }, + unlock = { + "Descarta un total", + "de {C:attention}5000{} cartas", + }, }, v_cry_stickyhand = { name = "Mano pegajosa", @@ -3143,11 +3838,39 @@ return { text = { "{C:attention}+#1#{} límite de ", "selección de cartas", - "{C:inactive,s:0.7}NOTA: Tendrá más funcionalidades después{}", + "Todas las cartas seleccionadas contribuyen", + "poder a las {C:attention}manos ascendidas{}", }, }, }, Other = { + disabled = { + name = "Deshabilitado", + text = { + "Ya no aparece", + "durante una partida", + }, + }, + disabled_card_dependency = { + name = "Deshabilitado", + text = { + "Requiere {C:attention}#1#", + }, + }, + disabled_mod_dependency = { + name = "Deshabilitado", + text = { + "Requiere el mod:", + "{C:attention}#1#", + }, + }, + disabled_mod_conflict = { + name = "Deshabilitado", + text = { + "Incompatible con el mod:", + "{C:attention}#1#", + }, + }, banana = { name = "Banana", text = { @@ -3155,6 +3878,14 @@ return { "destruida en cada ronda", }, }, + cry_absolute = { + name = "Absoluto", + text = { + "No se puede vender", + "ni destruir", + "{C:attention}No removible{}", + }, + }, cry_rigged = { name = "Amañada", text = { @@ -3181,7 +3912,7 @@ return { name = "Parpadeante", text = { "Destruido después de", - "{C:attention}#1#{} activaciones", + "{C:attention}#1#{} activaci#1#", }, }, cry_possessed = { @@ -3202,10 +3933,11 @@ return { }, }, ev_cry_choco0 = { - name = "", + name = "Eventos posibles", text = { - "Detalles de un {C:cry_ascendant,E:1}evento{}", - "activo aparecerán aquí", + "{T:ev_cry_choco1}1{} {T:ev_cry_choco2}2{} {T:ev_cry_choco3}3{} {T:ev_cry_choco4}4{} {T:ev_cry_choco5}5{}", + "{T:ev_cry_choco6}6{} {T:ev_cry_choco7}7{} {T:ev_cry_choco8}8{} {T:ev_cry_choco9}9{} {T:ev_cry_choco10}10{}", + "{C:inactive}(pasa el cursor para info.)", }, }, ev_cry_choco1 = { @@ -3397,15 +4129,15 @@ return { cry_rental_consumeable = { name = "De alquiler", text = { - "Pierdes {C:money}#1#${}", + "Pierdes {C:money}$#1#{}", "al final de la ronda, y en uso", }, }, cry_pinned_consumeable = { name = "Fijado", text = { - "No puedes usar consumibles", - "no-{C:attention}fijados{}", + "{C:inactive}No hace nada...", + "{C:inactive}por ahora", }, }, cry_banana_consumeable = { @@ -3419,35 +4151,35 @@ return { name = "Paquete de programa", text = { "Elige {C:attention}#1#{} de hasta", - "{C:attention}#2# cartas{} de {C:cry_code}código{}", + "{C:attention}#2# carta#2#{} de {C:cry_code}código{}", }, }, p_cry_code_normal_2 = { name = "Paquete de programa", text = { "Elige {C:attention}#1#{} de hasta", - "{C:attention}#2# cartas{} de {C:cry_code}código{}", + "{C:attention}#2# carta#2#{} de {C:cry_code}código{}", }, }, p_cry_code_jumbo_1 = { name = "Paquete de programa jumbo", text = { "Elige {C:attention}#1#{} de hasta", - "{C:attention}#2# cartas{} de {C:cry_code}código{}", + "{C:attention}#2# carta#2#{} de {C:cry_code}código{}", }, }, p_cry_code_mega_1 = { name = "Paquete de programa mega", text = { "Elige {C:attention}#1#{} de hasta", - "{C:attention}#2# cartas{} de {C:cry_code}código{}", + "{C:attention}#2# carta#2#{} de {C:cry_code}código{}", }, }, p_cry_empowered = { name = "Paquete espectral [Etiqueta empoderada]", text = { "Elige {C:attention}#1#{} de hasta", - "{C:attention}#2# cartas {C:spectral}espectrales{}", + "{C:attention}#2# carta#2# {C:spectral}espectrales{}", "{s:0.8,C:inactive}(Generado por Etiqueta empoderada)", }, }, @@ -3455,21 +4187,21 @@ return { name = "Paquete meme", text = { "Elige {C:attention}#1#{} de hasta", - "{C:attention}#2# cartas de {C:joker}comodín meme{}", + "{C:attention}#2# carta#2# de {C:joker}comodín meme{}", }, }, p_cry_meme_two = { name = "Paquete meme", text = { "Elige {C:attention}#1#{} de hasta", - "{C:attention}#2# cartas de {C:joker}comodín meme{}", + "{C:attention}#2# carta#2# de {C:joker}comodín meme{}", }, }, p_cry_meme_three = { name = "Paquete meme", text = { "Elige {C:attention}#1#{} de hasta", - "{C:attention}#2# cartas de {C:joker}comodín meme{}", + "{C:attention}#2# carta#2# de {C:joker}comodín meme{}", }, }, undiscovered_code = { @@ -3495,14 +4227,14 @@ return { text = { "Crea una carta de {C:cry_code}código{}", "cuando se juega y no puntúa", - "{C:inactive}(Debe haver espacio)", + "{C:inactive}(Debe haber espacio)", }, }, cry_azure_seal = { name = "Sello azur", text = { - "Crea {C:attention}#1#{} {C:planet}planetas{}", - "{C:dark_edition}negativas{} por la {C:attention}mano de póker{}", + "Crea {C:attention}#1#{} {C:planet}planeta#1#{}", + "{C:dark_edition}negativo#1#{} por la {C:attention}mano de póker{}", "jugada, y {C:red}destruye{} esta carta", }, }, @@ -3525,11 +4257,77 @@ return { }, }, misc = { + tutorial = { + cry_intro_1 = { + "¡Hola, soy {C:attention}Joseph J. Joker{}!", + "¡Bienvenido a {C:cry_exotic,E:1}Cryptid{}!", + }, + cry_intro_2 = { + "Parece que nunca has jugado", + "antes {C:cry_exotic,E:1}Cryptid{} en este perfil.", + "¡Déjame mostrarte como funcionan las cosas!", + }, + cry_intro_3 = { + "*crece manos*", + }, + cry_intro_4 = { + "Es difícil resumir este mod en", + "pocas oraciones, ¡pero lo que te diré", + "es que te espera un viaje {C:cry_exotic,E:1}salvaje{}!", + "Este no es el mismo {C:attention}póker de comodines{} que conoces...", + }, + cry_intro_5 = { + "Como puedas ver por estos", + "{C:cry_ascendant}conjuntos{}, me gusta la letra {C:attention}M{}.", + "Selecciona un conjunto para que explique...", + "{s:0.8}Nota: El balance de los conjuntos todavía esta en progreso.", + "{s:0.8}Espera a que las cosas cambien frecuentemente.", + }, + cry_modest_1 = { + "¿Buscando una experiencia cerca de lo normal?", + "¡Entonces el conjunto {C:cry_ascendant}modesto{} es para tí!", + }, + cry_modest_2 = { + "Aun así, ten cuidado con las mecánicas escondidas", + "a lo largo de Cryptid! Nunca sabrás", + "lo que te encontrarás en la siguiente ronda...", + }, + cry_mainline_1 = { + "¿Quieres {E:1,C:attention}romper{} el juego? Buenas noticias,", + "¡lo puedes hacer sin volverte insano!", + }, + cry_mainline_2 = { + "Las cosas igual son locas aquí, pero tendrás", + "la posibilidad de experimentar el sistema de", + "{C:cry_ascendant}progresión{}. Sólo no te pongas muy cómodo...", + }, + cry_mainline_3 = { + "Porque definitivamente serás más fuerte, pero", + "te tengo unos {E:1,C:dark_edition}jefes{} que", + "quizás te hagan arrepentirte de escoger este {C:cry_ascendant}conjunto{}...", + }, + cry_madness_1 = { + "¿Buscas completamente {C:red,E:1}aniquilar{} tu disco duro?", + "¡Ah, qué divertido! El conjunto {C:cry_ascendant}Maníaco{} dice:", + "'¿Balance? {E:1,C:red}¿¡QUÉ ES ESO!?{}'", + }, + cry_madness_2 = { + "He pasado semanas de noches llenas de {C:green}Mountain Dew{}", + "trabajando para asegurar que este conjunto sea ", + "{C:cry_ascendant}PERFECTAMENTE BALANCEADO{}, ¡sólo para tí!", + }, + cry_madness_3 = { + "¡Empezarás con todo desbloqueado, para que", + "puedas desencadenar el {C:red,E:1}poder completo{} de Cryptid!", + "Sólo ten cuidado de no {C:attention,E:1}crashear{} el juego,", + "porque probablemente va a pasar antes de que pierdas...", + }, + }, poker_hands = { ["cry_Bulwark"] = "Baluarte", - ["cry_Clusterfuck"] = "Lío de mierda", + ["cry_Clusterfuck"] = Cryptid_config.family_mode and "Desorden" or "Lío de mierda", ["cry_UltPair"] = "Pareja suprema", - ["cry_WholeDeck"] = "Toda la puta baraja", + ["cry_WholeDeck"] = Cryptid_config.family_mode and "Cincuenta y dos" or "Toda la puta baraja", }, poker_hand_descriptions = { ["cry_Bulwark"] = { @@ -3551,7 +4349,7 @@ return { }, }, achievement_names = { - ach_cry_ace_in_crash = "Un ACE En Mi Bolsillo", + ach_cry_ace_in_crash = "ACE De Bolsillo", ach_cry_blurred_blurred_joker = "Legalmente Ciego", ach_cry_bullet_hell = "Shooter Maníaco", ach_cry_break_infinity = "Rompe El Infinito", @@ -3571,6 +4369,7 @@ return { ach_cry_ult_full_skip = "Ultimate Full Skip", ach_cry_used_crash = "Te Dijimos Que No Lo Hagas", ach_cry_what_have_you_done = "¡¿QUÉ ACABAS DE HACER?!", + ach_cry_pin = "Pin de la vergüenza", }, achievement_descriptions = { ach_cry_ace_in_crash = 'check_for_unlock({type = "ace_in_crash"})', @@ -3587,31 +4386,32 @@ return { ach_cry_niw_uoy = "Llega a la apuesta -8", ach_cry_now_the_fun_begins = "Consigue a Lienzo", ach_cry_patience_virtue = "Espera a Ciclo Lavanda por 2 minutos antes de jugar la primera mano y vence la ciega", - ach_cry_perfectly_balanced = "Completa la Baraja Muy Justa en Ascendant Stake", + ach_cry_perfectly_balanced = "Completa la Baraja Muy Justa en Pozo ascendente", ach_cry_pull_request = "Haz que ://COMMIT haga aparecer el mismo comodín que destruyó", - ach_cry_traffic_jam = "Beat all Rush Hour challenges", + ach_cry_traffic_jam = "Gana todos los desafíos Hora punta", ach_cry_ult_full_skip = "Gana en 1 ronda", ach_cry_used_crash = "Usa ://CHOQUE", - ach_cry_what_have_you_done = "Delete or Sacrifice an Exotic Joker", + ach_cry_what_have_you_done = "Elimina o sacrifica un comodín exótico", + ach_cry_pin = "Pierde una partida contra El Alfiler", }, challenge_names = { c_cry_ballin = "Ballin'", c_cry_boss_rush = "Enter the Gungeon", - c_cry_dagger_war = "Dagger War", - c_cry_joker_poker = "Joker Poker", - c_cry_onlycard = "Solo Card", + c_cry_dagger_war = "Guerra de dagas", + c_cry_joker_poker = "Póker de comodines", + c_cry_onlycard = "Carta única", c_cry_rng = "RNG", - c_cry_rush_hour = "Rush Hour I", - c_cry_rush_hour_ii = "Rush Hour II", - c_cry_rush_hour_iii = "Rush Hour III", - c_cry_sticker_sheet = "Sticker Sheet", - c_cry_sticker_sheet_plus = "Sticker Sheet+", + c_cry_rush_hour = "Hora punta I", + c_cry_rush_hour_ii = "Hora punta II", + c_cry_rush_hour_iii = "Hora punta III", + c_cry_sticker_sheet = "Hoja de pegatinas", + c_cry_sticker_sheet_plus = "Hoja de pegatinas +", }, dictionary = { --Settings Menu cry_set_features = "Características", cry_set_music = "Música", - cry_set_enable_features = "Selecciona las características para activar (se aplica al reiniciar):", + cry_set_enable_features = "Usa esta sección para activar o desactivar sets temáticos.", cry_feat_achievements = "Logros", ["cry_feat_antimatter deck"] = "Baraja de antimateria", cry_feat_blinds = "Ciegas", @@ -3625,20 +4425,23 @@ return { ["cry_feat_exotic jokers"] = "Comodines exóticos", ["cry_feat_m jokers"] = "Comodines M", cry_feat_menu = "Menú principal personalizado", - ["cry_feat_misc."] = "Misc.", + ["cry_feat_misc."] = "Misceláneo", ["cry_feat_misc. jokers"] = "Comodines misceláneos", cry_feat_planets = "Planetas", cry_feat_jokerdisplay = "JokerDisplay (no hace nada)", cry_feat_tags = "Etiquetas", - cry_feat_sleeves = "Mangas", + cry_feat_sleeves = "Fundas", cry_feat_spectrals = "Espectrales", cry_feat_spooky = "Actualización espeluznante", ["cry_feat_more stakes"] = "Pozos", cry_feat_vouchers = "Vales", - cry_mus_jimball = "Jimball (Funkytown por Lipps Inc. - Copyrighted)", + cry_mus_jimball = "Jimball (Funkytown por Lipps Inc. - Con copyright)", cry_mus_code = "Cartas de código (://LETS_BREAK_THE_GAME por HexaCryonic)", cry_mus_exotic = "Comodines exóticos (Joker in Latin por AlexZGreat)", cry_mus_high_score = "Alto puntaje (Final Boss [For Your Computer] por AlexZGreat)", + cry_mus_alt_bg = "Background Music (por MathIsFun_)", + cry_family = "Modo apto para familias", + cry_experimental = "Modo experimental", k_cry_program_pack = "Paquete de programa", k_cry_meme_pack = "Paquete meme", @@ -3657,13 +4460,26 @@ return { cry_debuff_oldmark = "Sin manos que contengan una Pareja", cry_debuff_obsidian_orb = "Aplica las habilidades de todos los jefes derrotados", + cry_tax_placeholder = "(X0.4 requisitos de ciega)", + cry_joke_placeholder = "(múltiplo of 8)", + k_code = "Código", + k_content_set = "Set temático", + b_content_sets = "Sets temáticos", + --Why aren't these in vanilla? + -- they aren´t??? + b_tag = "Etiqueta", + b_blind = "Ciega", + + b_tarot_rate = "Tasa de tarots", + b_planet_rate = "Tasa de planetas", + k_unique = "Único", b_code_cards = "Cartas de código", b_unique_cards = "Cartas únicas", b_pull = "TIRAR", cry_hooked_ex = "Enganchada!", - k_end_blind = "terminar_ciega", + k_end_blind = "terminar_ciega()", cry_code_rank = "INGRESAR CATEGORÍA", cry_code_enh = "INGRESAR MEJORA", @@ -3681,9 +4497,8 @@ return { b_flip = "VOLTEAR", b_merge = "COMBINAR", - cry_hand_bulwark = "Baluarte", - cry_hand_clusterfuck = "Lío de mierda", - cry_hand_ultpair = "Pareja suprema", + cry_asc_hands = "Manos asc.", + cry_p_star = "Estrella", cry_again_q = "¿Otra vez?", cry_curse = "Maldición", @@ -3692,13 +4507,15 @@ return { cry_gaming = "Gaming", cry_gaming_ex = "¡Gaming!", cry_good_luck_ex = "¡Buena suerte!", - cry_sus_ex = "Impostor!", - cry_jolly_ex = "Jolly Up!", + cry_sus_ex = "¡Impostor!", + cry_jolly_ex = "¡Más contento!", cry_m_minus = "m", cry_m = "M", - cry_m_ex = "M!", + cry_m_ex = "¡M!", cry_minus_round = "-1 ronda", cry_plus_cryptid = "+1 críptido", + cry_plus_card = "+1 carta", + cry_plus_code = "+1 carta de código", cry_no_triggers = "¡Sin activaciones restantes!", cry_unredeemed = "Desredimido...", cry_active = "Activo", @@ -3712,17 +4529,42 @@ return { k_cry_cursed = "Maldito", k_planet_disc = "Disco circunestelar", k_planet_satellite = "Satélites naturales", - k_planet_universe = "El puto Universo Real", + k_planet_universe = Cryptid_config.family_mode and "El universo" or "El puto universo", cry_notif_jimball_1 = "Jimball", cry_notif_jimball_2 = "Nota de copyright", cry_notif_jimball_d1 = 'Jimball reproduce la canción "Funkytown",', cry_notif_jimball_d2 = "la cual tiene copyright y no puede ser", cry_notif_jimball_d3 = "usada por streams y videos.", + + cry_gameset_explanation = { + "Selecciona una configuración de conjunto", + "para aplicar a esta carta.", + }, + cry_gameset_disabled = "Desactivado", + cry_gameset_modest = "Modesto", + cry_gameset_mainline = "Mainline", + cry_gameset_madness = "Maníaco", + cry_gameset_custom = "Modificado", + cry_gameset_exp = "Experimental", + cry_gameset_exp_modest = "Experimental (Modesto)", + cry_gameset_exp_mainline = "Experimental (Mainline)", + cry_gameset_exp_madness = "Experimental (Maníaco)", + + cry_view_set_contents = "Ver objetos en el conjunto", + + cry_sapling_an = "un", --spanish literally has no distinction between these + cry_sapling_a = "un", --but just in case + + b_reset_gameset_modest = "Reiniciar configuración de conjunto (Modesto)", + b_reset_gameset_mainline = "Reiniciar configuración de conjunto (Mainline)", + b_reset_gameset_madness = "Reiniciar configuración de conjunto (Maníaco)", }, labels = { food_jokers = "Comodines de comida", banana = "Banana", + pinned = "Fijado", + cry_absolute = "Absoluto", code = "Código", unique = "Único", cry_rigged = "Amañada", @@ -3734,7 +4576,7 @@ return { cry_azure_seal = "Sello azur", cry_astral = "Astral", - cry_blur = "Borroso", + cry_blur = "Borrosa", cry_double_sided = "Doble cara", cry_glass = "Frágil", cry_glitched = "Errónea", @@ -3752,7 +4594,7 @@ return { rnj_loc_txts = { stats = { plus_mult = { "{C:red}+#2#{} multi" }, - plus_chips = { "{C:blue}+#2#{} fichas" }, + plus_chips = { "{C:blue}+#2#{} ficha#2#" }, x_mult = { "{X:red,C:white} X#2#{} multi" }, x_chips = { "{X:blue,C:white} X#2#{} fichas" }, h_size = { "{C:attention}+#2#{} tamaño de mano" }, @@ -3760,17 +4602,17 @@ return { }, stats_inactive = { plus_mult = { "{C:inactive}(Actual: {C:red}+#1#{C:inactive} multi)" }, - plus_chips = { "{C:inactive}(Actual: {C:blue}+#1#{C:inactive} fichas)" }, + plus_chips = { "{C:inactive}(Actual: {C:blue}+#1#{C:inactive} ficha#2#)" }, x_mult = { "{C:inactive}(Actual: {X:red,C:white} X#1# {C:inactive} multi)" }, x_chips = { "{C:inactive}(Actual: {X:blue,C:white} X#1# {C:inactive} fichas)" }, h_size = { "{C:inactive}(Actual: {C:attention}+#1#{C:inactive} tamaño de mano)" }, money = { "{C:inactive}(Actual: {C:money}+$#1#{C:inactive})" }, }, actions = { - make_joker = { "Crea {C:attention}#2# comodín(es{}" }, - make_tarot = { "Crea {C:attention}#2#{} carta(s) de {C:tarot}tarot{}" }, - make_planet = { "Crea {C:attention}#2#{} carta(s) de {C:planet}planeta{}" }, - make_spectral = { "Crea {C:attention}#2#{} carta(s) {C:spectral}espectrales{}" }, + make_joker = { "Crea {C:attention}#2# comod#2#" }, + make_tarot = { "Crea {C:attention}#2#{} carta#2# de {C:tarot}tarot{}" }, + make_planet = { "Crea {C:attention}#2#{} carta#2# de {C:planet}planeta{}" }, + make_spectral = { "Crea {C:attention}#2#{} carta#2# {C:spectral}espectral#2#{}" }, add_dollars = { "Gana {C:money}$#2#{}" }, }, contexts = { @@ -3823,8 +4665,8 @@ return { poker_hand = { "si la mano es un(a) {C:attention}#3#{}" }, or_more = { "si la mano contiene {C:attention}#3#{} o más cartas" }, or_less = { "si la mano contiene {C:attention}#3#{} o menos cartas" }, - hands_left = { "si tienes #3# {C:blue}manos{} restantes al final de la ronda" }, - discards_left = { "si tienes #3# {C:red}descartes{} restantes al final de la ronda" }, + hands_left = { "si tienes #3# {C:blue}mano#3#{} restante#3# al final de la ronda" }, + discards_left = { "si tienes #3# {C:red}descarte#3#{} restante#3# al final de la ronda" }, first_discard = { "si es el {C:attention}primer descarte{}" }, last_discard = { "si es el {C:attention}último descarte{}" }, odds = { "con {C:green}#4# {C:green}en {C:green}#3#{} probabilidades" }, @@ -3836,7 +4678,7 @@ return { a_powchips = { "^#1# fichas" }, a_powmultchips = { "^#1# multi+fichas" }, a_round = { "+#1# ronda" }, - a_candy = { "+#1# Candy" }, + a_candy = { "+#1# dulce" }, a_xchips_minus = { "-X#1# fichas" }, a_powmult_minus = { "-^#1# multi" }, a_powchips_minus = { "-^#1# fichas" }, @@ -3850,7 +4692,7 @@ return { cry_sticker_name = { "Pegatina #1#" }, cry_sticker_desc = { "Usaste este comodín", - "para ganaer en la dificultad #2##1#", + "para ganar en la dificultad #2##1#", "#2#Pozo#3#", }, @@ -3899,7 +4741,7 @@ return { { "LLAMA A 1-600-JIMBO", "PARA CALIFICAR TU", "EXPERIENCIA DE VALES" }, { "DERROTA LA CIEGA", "JEFE DE APUESTA 39", "PARA RESTABLECER" }, { "TRUCO DE MAGIA", "HICE ESTE VALE", "DESAPARECER" }, - { "¿POR QUÉ ES", "UN VALE COMO", "UN ESCRITORIO?" }, + { "¿POR QUÉ UN", "VALE ES COMO", "UN ESCRITORIO?" }, { "HEMOS RETRAÍDO", "TUS VALES, SERÍAN MEJOR", "USADOS EN OTRAS PARTIDAS" }, { "EL TRADUCTOR NI QUISO", "TRADUCIR ESTE MENSAJE", "NO HAY VALES PARA TI CABRÓN" }, { "PERDÓN", "LOS VALES ESTÁN EXPERIMENTANDO", "VOUCHIFIA ABORTUS" }, @@ -3920,17 +4762,33 @@ return { { "EXÓTICOS GRATIS", "CONSÍGUELOS ANTES DE QUE", "SEA DEMASIADO TARDE (se acabaron)" }, { "PRUÉBALOS MAL", "COMPRA UN VALE", "INVISIBLE POR $10" }, { "", "¿sin vales?", "" }, - { "¿ves este anuncio?", "si lo ves, está funcionando", "y lo puedes tener como tuyo" }, + { + "¿ves este anuncio?", + "si lo ves, está funcionando", + "y lo puedes tener como tuyo", + }, { "TE ESTÁS PERDIENDO EN", "AL MENOS 5 VALES AHORA", "tonktonktonktonktonk" }, { "10", "20 SIN VALES XD", "30 GOTO 10" }, { "LOS VALES", "SON ARTÍCULOS PREMIUM", "$199.99 JÓLARES PARA DESBLOQUEAR" }, { "¡¿SIN VALES?!", "SÓLO EN POZO ASCENDENTE", "BARAJA MUY JUSTA" }, { "¿DISFRUTANDO TU", "EXPERIENCIA DE VALES? DÁNOS UNA CALIFICACIÓN", "DE CINCO ESTRELLAS EN JESTELP" }, - { "VALES GRATIS", "VALES CERCA DE TÍ", "CONSIGUE VALES RÁPIDO CON ESTE TRUCO" }, + { + "VALES GRATIS", + "VALES CERCA DE TÍ", + "CONSIGUE VALES RÁPIDO CON ESTE TRUCO", + }, { "INTRODUCIENDO", "¡EL PRIMER VALE NIVEL 0!", "(llegando pronto a Cryptid 1.0)" }, - { "¡UN VALE!", "ES SÓLO IMAGINARIO", "IMAGINAMOS QUE LO QUERÍAS, ESO SÍ" }, + { + "¡UN VALE!", + "ES SÓLO IMAGINARIO", + "IMAGINAMOS QUE LO QUERÍAS, ESO SÍ", + }, { "DESACTIVA TU ADBLOCKER", "SIN ANUNCIOS, NO PODRÍAMOS", "VENDERTE NINGÚN VALE" }, - { "SI TIENES", "UN PROBLEMA CON ESTO", "ENVÍA UN CORREO A NORESPONSE@JMAIL.COM" }, + { + "SI TIENES", + "UN PROBLEMA CON ESTO", + "ENVÍA UN CORREO A NORESPONSE@JMAIL.COM", + }, { "SIN DINERO SUFICIENTE", "PARA COMPRAR ESTE VALE", "¿PARA QUÉ PONERLO AQUÍ?" }, { "¿QUIERES UN VALE?", "ENTONCES CÁLLATE", "NO PUEDES TENER NINGUNO LOL" }, { "^$%& NINGÚN", "VALE ^%&% %&$^% PARA", "$%&%%$ %&$&*%$^ TÍ" }, diff --git a/Cryptid/localization/fr.lua b/Cryptid/localization/fr.lua index d6b5764..df22ed5 100644 --- a/Cryptid/localization/fr.lua +++ b/Cryptid/localization/fr.lua @@ -1,13 +1,7 @@ ---I couldn't get Meme Packs to work without crashing ---yes somehow that was harder than RNJoker ---Wip Localization, putting this here since people have expressed interst in this - --[[ Progress: -Decks: Almost [ChatSigna] - Beta Deck TODO - Note from Jevonn: Enchanced decks are planned to have their localization done differently, don't worry about these for now +Decks: Yes [ChatSigna] Jokers: Yes [HastagGuigui] Code Cards: Yes [ChatSigna] Deck Sleeves (requires Decksleeves Mod): Yes [HastagGuigui] @@ -18,12 +12,12 @@ Planets: Yes [HastagGuigui] Dictonary: Yes [HastagGuigui] Editions: Yes [HastagGuigui] Vouchers: Yes [HastagGuigui] -Enhancements (aka echo card): Yes [HastagGuigui] +Enhancements: Yes [HastagGuigui] Tags: Yes [HastagGuigui] Other (packs, stickers, etc): Yes [HastagGuigui] Misc: Yes [HastagGuigui] Spooky Update: Yes [HastagGuigui] - +Refactor Update: ?? ]] -- return { @@ -78,8 +72,8 @@ return { name = "Jeu Critique", text = { "Après chaque main jouée,", - "{C:green}#1# chance(s) sur 4{} d'obtenir {X:dark_edition,C:white} ^2 {} Multi", - "{C:green}#1# chance(s) sur 8{} d'obtenir {X:dark_edition,C:white} ^0.5 {} Multi", + "{C:green}#1# chance#1# sur 4{} d'obtenir {X:dark_edition,C:white} ^2 {} Multi", + "{C:green}#1# chance#1# sur 8{} d'obtenir {X:dark_edition,C:white} ^0.5 {} Multi", }, }, b_cry_encoded = { @@ -100,6 +94,14 @@ return { "{C:attention,T:v_overstock_plus}Excédent Plus", }, }, + b_cry_et_deck = { + name = "Jeu Amélioré", + text = { + "Toutes les {C:attention}cartes à jouer{}", + "sont {C:attention}#1#{}(s)", + "{C:inactive}(Cliquez pour modifier)", + }, + }, b_cry_glowing = { name = "Jeu Brillant", --wtf is glowing? text = { @@ -132,6 +134,14 @@ return { "gagne son {C:attention}amélioration", }, }, + b_cry_sl_deck = { + name = "Jeu scellé", + text = { + "Toutes les cartes à jouer ont un {C:dark_edition}#1#{}", + "Les cartes ne peuvent pas changer de sceau", + "{C:inactive}(Cliquez pour modifier)", + }, + }, b_cry_spooky = { name = "Jeu fantôme", text = { @@ -140,6 +150,14 @@ return { "{C:cry_candy}Bonbon{} ou un Joker {X:cry_cursed,C:white}Maudit{}", }, }, + b_cry_st_deck = { + name = "Jeu Couleur", + text = { + "Toutes les cartes à jouer sont des {C:dark_edition}#1#", + "et ne peuvent pas changer de couleur", + "{C:inactive}(Cliquez pour modifier)", + }, + }, b_cry_very_fair = { name = "Jeu Très Équilibré", text = { @@ -350,6 +368,14 @@ return { }, }, Code = { + c_cry_alttab = { + name = "://ALTTAB", + text = { + "Crée le badge de", + "la {C:cry_code}blinde actuelle{}", + "{C:inactive}(Actuellement: {C:cry_code}#1#{C:inactive})", + }, + }, c_cry_class = { name = "://CLASSE", text = { @@ -527,6 +553,131 @@ return { }, }, }, + ["Content Set"] = { + set_cry_blind = { + name = "Blindes", + text = { + "Les {C:attention}Blindes de Boss{} ajoutés", + "par Cryptid", + }, + }, + set_cry_code = { + name = "Cartes Code", + text = { + "Les {C:cry_code}Cartes Code{} et", + "tout ce qui en dépend", + }, + }, + set_cry_cursed = { + name = "Jokers maudits", + text = { + "Les Jokers dangeureux", + "de rareté {X:cry_cursed,C:white}Maudit{}", + }, + }, + set_cry_deck = { + name = "Jeux", + text = { + "Les différents {C:attention}jeux{}", + "ajoutés par Cryptid", + }, + }, + set_cry_epic = { + name = "Jokers épiques", + text = { + "Les Jokers de", + "rareté {C:cry_epic}Épique{}", + "{C:inactive,s:0.8}(Entre Rare et Légendaire)", + }, + }, + set_cry_exotic = { + name = "Jokers exotiques", + text = { + "Les Jokers surpuissants", + "de rareté {C:cry_exotic}Exotique{}", + }, + }, + set_cry_m = { + name = "Jokers M", + text = { + "Les Jokers liés", + "à la lettre {C:attention}M{}", + "et au {C:attention}Joker Joyeux", + }, + }, + set_cry_misc = { + name = "Divers", + text = { + "Tout ce qui est lié à Cryptid", + "mais n'est lié à aucun", + "{C:cry_ascendant}Set thématique", + }, + }, + set_cry_misc_joker = { + name = "Jokers divers", + text = { + "Tous les {C:attention}Jokers{} de Cryptid", + "qui ne rentrent dans aucun autre", + "{C:cry_ascendant}Set thématique", + }, + }, + set_cry_planet = { + name = "Cartes planète", + text = { + "Les diverses cartes {C:planet}Planète{}", + "ajoutés par Cryptid", + }, + }, + set_cry_poker_hand_stuff = { + name = "Mains de poker supplémentaires", + text = { + "Rajoute 4 nouvelles {C:attention}mains de poker", + "et active les {C:attention}mains ascensionnées", + }, + }, + set_cry_spectral = { + name = "Cartes spectrales", + text = { + "Les cartes {C:spectral}Spectrales{}", + "ajoutées par Cryptid", + }, + }, + set_cry_spooky = { + name = "Mise à jour Spooky", + text = { + "Tout le contenu de la mise à jour Spooky,", + "comme les Jokers {C:cry_candy}Bonbon{}", + }, + }, + set_cry_tag = { + name = "Badges", + text = { + "Les {C:attention}Badges{} ajoutés", + "par Cryptid", + }, + }, + set_cry_tier3 = { + name = "Coupons niveau 3", + text = { + "Un {C:attention}niveau supérieur{}", + "de Coupons", + }, + }, + set_cry_timer = { + name = "Mécaniques chrono", + text = { + "Les effets et mécaniques", + "basés sur le {C:attention}temps", + }, + }, + set_cry_voucher = { + name = "Autres coupons", + text = { + "Les {C:attention}Coupons{} de niveau 1 et 2", + "ajoutés par Cryptid", + }, + }, + }, Edition = { e_cry_astral = { name = "Astrale", @@ -539,7 +690,7 @@ return { text = { "{C:attention}Redéclenche{} cette", "carte {C:attention}1{} fois", - "{C:green}#1# chance(s) sur #2#{}", + "{C:green}#1# chance#1# sur #2#{}", "de la redéclencher {C:attention}#3#{}", "fois de plus", }, @@ -557,7 +708,7 @@ return { label = "Fragile", text = { "{C:white,X:mult} X#3# {} Multi", - "{C:green}#1# chance(s) sur #2#{} de", + "{C:green}#1# chance#1# sur #2#{} de", "ne pas {C:red}détruite{} cette carte", "lorsqu'elle est déclenchée", }, @@ -613,17 +764,57 @@ return { m_cry_echo = { name = "Carte Écho", text = { - "{C:green}#2# chance(s) sur #3#{} de", + "{C:green}#2# chance#2# sur #3#{} de", "{C:attention}redéclencher{} cette carte #1# fois", "lorsqu'elle est marquée", }, }, + m_cry_light = { + name = "Carte lumière", + text = { + "Lorsque déclenchée avec {C:attention}#4#{} {C:inactive}(#3#){} autre#4# carte#4#", + "marquée#4#, gagne {X:mult,C:white}X#1#{} Multi et", + "augmente le nombre de cartes avant la prochaîne augmentation de {C:attention}5{}", + "{C:inactive}(Actuellement {X:mult,C:white}X#2#{C:inactive} Multi)", + }, + }, }, Joker = { + j_cry_test_modest = { + name = "Joker de test", + text = { + "{C:chips}+#1#{} Jeton#1#", + "{C:inactive}Salut! :3", + }, + }, + j_cry_test_mainline = { + name = "Joker de test", + text = { + "{C:chips}+#1#{} Jeton#1#", + "{C:money}+$44{} lorsque la {C:attention}Blinde{} est sélectionnée", + "{C:inactive}Salut! :3", + }, + }, + j_cry_test_madness = { + name = "Joker de test", + text = { + "{C:chips}+#1#{} Jeton#1#", + "{C:money}+$44444{} lorsque la {C:attention}Blinde{} est sélectionnée", + "{C:inactive}Salut! :3", + }, + }, + j_cry_test_cryptid_in_2025 = { + name = "Joker de test", + text = { + "{C:chips}+#1#{} Jeton#1#", + "{C:money}+$44444{} lorsque la {C:attention}Blinde{} est sélectionnée", + "{C:inactive}On est où, là, Jen's Almanac?", + }, + }, j_cry_adroit = { name = "Joker adroit", text = { - "{C:chips}+#1#{} Jetons si", + "{C:chips}+#1#{} Jeton#1# si", "la main jouée", "contient une {C:attention}#2#", }, @@ -636,15 +827,6 @@ return { "{C:inactive,s:0.8}Ne copie pas les Carte Googol Play Nostalgiques{}", }, }, - j_cry_astral_bottle = { - name = "Astres en Bouteille", - text = { - "Lorsque cette carte est vendue,", - "applique {C:dark_edition}Astral{}", - "et {C:attention}Périssable{} à", - "un {C:attention}Joker{} aléatoire", - }, - }, j_cry_antennastoheaven = { name = "...Like Antennas to Heaven", text = { @@ -658,6 +840,24 @@ return { name = "Joker AP", text = { "{X:mult,C:white} X#1# {} Multi contre les {C:attention}Blindes de Boss{}" }, }, + j_cry_arsonist = { + name = "Pyromane", + text = { + "Si la main jouée", + "contient un {C:attention}Full{},", + "{C:red}détruit{} toutes les cartes", + "après avoir été marqué", + }, + }, + j_cry_astral_bottle = { + name = "Astres en Bouteille", + text = { + "Lorsque cette carte est vendue,", + "applique {C:dark_edition}Astral{}", + "et {C:attention}Périssable{} à", + "un {C:attention}Joker{} aléatoire", + }, + }, j_cry_big_cube = { name = "Gros cube", text = { @@ -695,17 +895,17 @@ return { j_cry_blurred = { name = "Joker flou", text = { - "Gagne {C:blue}+#1#{} main(s) lorsque", + "Gagne {C:blue}+#1#{} main#1# lorsque", "la {C:attention}Blinde{} est sélectionnée", }, }, j_cry_bonk = { name = "Bonk", text = { - "Chaque {C:attention}Joker{} donne {C:chips}+#1#{} Jetons", + "Chaque {C:attention}Joker{} donne {C:chips}+#1#{} Jeton#1#", "Augmente ce nombre de {C:chips}+#2#{} si la", "{C:attention}main de poker{} jouée est une {C:attention}#3#{}", - "{C:inactive,s:0.8}Les Jokers Joyeux donnent{} {C:chips,s:0.8}+#4#{} {C:inactive,s:0.8}jetons{}", + "{C:inactive,s:0.8}Les Jokers Joyeux donnent{} {C:chips,s:0.8}+#4#{} {C:inactive,s:0.8}jeton#4#{}", }, }, j_cry_bonkers = { @@ -719,7 +919,7 @@ return { j_cry_bonusjoker = { name = "Joker Bonus", text = { - "{C:green}#1# chance(s) sur #2#{} pour que chaque", + "{C:green}#1# chance#1# sur #2#{} pour que chaque", "carte {C:attention}Bonus{} augmente le", "nombre d'emplacements {C:attention}Joker{} or {C:attention}Consommable", "de {C:dark_edition}1{} lorsqu'elle est comptée", @@ -737,11 +937,16 @@ return { j_cry_boredom = { name = "Ennui", text = { - "{C:green}#1# chance(s) sur #2#{} que", + "{C:green}#1# chance#1# sur #2#{} que", "chaque {C:attention}Joker{} ou {C:attention}carte à jouer{}", "soient {C:attention}redéclenché(e)s{}", "{C:inactive,s:0.8}N'affecte pas d'autres Ennuis{}", }, + unlock = { + "Ne rien faire dans", + "l'écran titre pendant", + "{C:attention}10 minutes", + }, }, j_cry_brittle = { name = "Nougatine", @@ -763,9 +968,9 @@ return { j_cry_busdriver = { name = "Chauffeur de bus", text = { - "{C:green}#1# chance(s) sur #3#{}", + "{C:green}#1# chance#1# sur #3#{}", "pour {C:mult}+#2#{} Multi", - "{C:green}1 chance(s) sur 4{}", + "{C:green}1 chance sur 4{}", "pour {C:mult}-#2#{} Multi", }, }, @@ -787,7 +992,7 @@ return { j_cry_candy_cane = { name = "Bonbon canne à sucre", text = { - "Pour les {C:attention}#1#{} prochaine(s) manche(s),", + "Pour #1# {C:attention}#1#{} prochaine#1# manche#1#,", "les cartes à jouer donnent {C:money}$#2#", "lorsqu'elles sont {C:attention}redéclenchées", }, @@ -814,6 +1019,11 @@ return { "une fois pour {C:attention}chaque{C:attention} Joker{} non-{C:blue}Commun", "à droite de ce Joker", }, + unlock = { + "Redéclencher un {C:attention}Joker", + "{C:attention}114{} fois", + "en une main", + }, }, j_cry_caramel = { name = "Caramel", @@ -873,6 +1083,19 @@ return { "la main jouée", "contient un {C:attention}#2#", }, + unlock = { + "Gagner une partie", + "en jouant une {E:1,C:attention}Paire Ultime", + "comme main gagnante", + }, + }, + j_cry_clicked_cookie = { + name = "Cookie cliqué", -- the joke works better in french :3c + text = { + "{C:chips}+#1#{} Jeton#1#", + "{C:chips}-#2#{} Jeton#2# à chaque", + "{C:attention}clic", + }, }, j_cry_CodeJoker = { name = "Joker Code", @@ -881,6 +1104,10 @@ return { "{C:dark_edition}Négative{} lorsque", "la {C:attention}Blinde{} est sélectionnée", }, + unlock = { + "Découvrir {C:attention}toutes", + "les {C:cry_code}Cartes Code", + }, }, j_cry_coin = { name = "Crypto-monnaie", @@ -903,7 +1130,7 @@ return { name = "Copier/Coller", text = { "Lorsqu'une carte {C:cry_code}Code{} est utilisée,", - "{C:green}#1# chance(s) sur #2#{} pour ajouter une copie", + "{C:green}#1# chance#1# sur #2#{} pour ajouter une copie", "dans votre zone de consommables", "{C:inactive}(Selon la place disponible)", }, @@ -918,10 +1145,10 @@ return { j_cry_crustulum = { name = "Crustulum", text = { - "Ce joker gagne {C:chips}+#2#{} Jetons", + "Ce joker gagne {C:chips}+#2#{} Jeton#2#", "par {C:attention}réapprovisionnement{} dans la boutique", "{C:green}Tous les réapprovisionnements sont gratuits{}", - "{C:inactive}(Actuellement {C:chips}+#1#{C:inactive} jetons)", + "{C:inactive}(Actuellement {C:chips}+#1#{C:inactive} jeton#1#)", }, }, j_cry_cryptidmoment = { @@ -935,7 +1162,7 @@ return { j_cry_cube = { name = "Cube", text = { - "{C:chips}+#1#{} Jetons", + "{C:chips}+#1#{} Jeton#1#", }, }, j_cry_curse_sob = { @@ -946,13 +1173,17 @@ return { "{C:dark_edition,E:1}tu ne peux pas m'échapper...{}", "{C:inactive}(Selon la place disponible){}", }, + unlock = { + "Obtenir un {C:attention}Obélisque", + "{C:purple}Éternel{}", + }, }, j_cry_cursor = { name = "Curseur", text = { - "Ce Joker gagne {C:chips}+#2#{} Jetons", + "Ce Joker gagne {C:chips}+#2#{} Jeton#2#", "pour chaque carte {C:attention}achetée{}", - "{C:inactive}(Actuellement {C:chips}+#1#{C:inactive} Jetons)", + "{C:inactive}(Actuellement {C:chips}+#1#{C:inactive} Jeton#1#)", }, }, j_cry_cut = { @@ -973,10 +1204,19 @@ return { "contient une {C:attention}#2#", }, }, - j_cry_discreet = { - name = "Discreet Joker", + j_cry_digitalhallucinations = { + name = "Hallucinations digitales", text = { - "{C:chips}+#1#{} Jetons si", + "Lorsqu'un {C:attention}Paquet{} est ouvert,", + "{C:green}#1# chance#1s# sur #2#{} de créer", + "une carte {C:dark_edition}Negative{} aléatoire", + "du même {C:attention}type{} que le paquet", + }, + }, + j_cry_discreet = { + name = "Joker discret", + text = { + "{C:chips}+#1#{} Jeton#1# si", "la main jouée", "contient une {C:attention}#2#", }, @@ -1007,11 +1247,16 @@ return { "La couleur change toutes les manches", "{C:inactive}(Actuellement {X:mult,C:white} X#3# {C:inactive} Multi)", }, + unlock = { + "Jouer une {C:attention}Carte Haute{}", + "avec {C:attention}4{} cartes", + "de la {C:attention}même couleur", + }, }, j_cry_dubious = { name = "Joker douteux", text = { - "{C:chips}+#1#{} Jetons si", + "{C:chips}+#1#{} Jeton#1# si", "la main jouée", "contient une {C:attention}#2#", }, @@ -1023,6 +1268,11 @@ return { "la main jouée", "contient une {C:attention}#2#", }, + unlock = { + "Gagner une partie", + "sans jouer", + "de {E:1,C:attention}Double Paire", + }, }, j_cry_duplicare = { name = "Duplicare", @@ -1047,7 +1297,7 @@ return { name = "Energia", text = { "Lorsqu'un {C:attention}Badge{} est obtenu,", - "crée {C:attention}#1#{} copies de celui-ci", + "crée {C:attention}#1#{} copie#1# de celui-ci", "et {C:attention}augmente{} le nombre de", "copies de {C:attention}#2#", }, @@ -1057,7 +1307,7 @@ return { text = { "Les Jokers apparaissent en utilisant", "l'ordre de la {C:attention}Collection{}", - "Crée {C:attention}#1#{} Joker(s) {C:dark_edition}Négatif(s){}", + "Crée {C:attention}#1#{} Joker#1# {C:dark_edition}Négatif#1#{}", "lorsqu'une main est jouée", "{C:inactive,s:0.8}Les Jokers {C:cry_exotic,s:0.8}Exotiques {C:inactive,s:0.8}ou mieux ne peuvent pas apparaître", "{s:0.8}Dernier Joker généré: {C:attention,s:0.8}#2#", @@ -1095,9 +1345,9 @@ return { j_cry_exposed = { name = "Exposé", text = { - "Retrigger all non-{C:attention}face{} cards", - "{C:attention}#1#{} additional time(s)", - "All {C:attention}face{} cards are debuffed", + "Redéclenche toutes les cartes {C:attention}non figure{}", + "{C:attention}#1#{} fois de plus", + "Les cartes {C:attention}figure{} sont affaiblies", }, }, j_cry_facile = { @@ -1115,6 +1365,11 @@ return { "la main jouée", "contient une {C:attention}#2#", }, + unlock = { + "Gagner une partie", + "sans jouer", + "de {E:1,C:attention}Carte Haute", + }, }, j_cry_fractal = { name = "Doigts de fractale", @@ -1165,7 +1420,7 @@ return { j_cry_foxy = { name = "Joker narquois", text = { - "{C:chips}+#1#{} Jetons si", + "{C:chips}+#1#{} Jeton#1# si", "la main jouée", "contient une {C:attention}#2#", }, @@ -1173,14 +1428,14 @@ return { j_cry_fspinner = { name = "Hand spinner", text = { - "Ce Joker gagne {C:chips}+#2#{} Jetons", + "Ce Joker gagne {C:chips}+#2#{} Jeton#2#", "si la main jouée n'est {C:attention}pas{}", "la {C:attention}main de poker{} la plus jouée", - "{C:inactive}(Actuellement {C:chips}+#1#{C:inactive} Jetons)", + "{C:inactive}(Actuellement {C:chips}+#1#{C:inactive} Jeton#1#)", }, }, j_cry_fuckedup = { - name = "Joker merdique", + name = Cryptid_config.family_mode and "Joker insensé" or "Joker merdique", text = { "{C:mult}+#1#{} Multi si", "la main jouée", @@ -1206,9 +1461,9 @@ return { name = "Fantôme", text = { "À la fin de la manche:", - "{C:green}#1# chance(s) sur #2#{} de", + "{C:green}#1# chance#1# sur #2#{} de", "{C:attention}posséder{} un {C:attention}Joker{} aléatoire", - "{C:green}#1# chance(s) sur #3#{} de", + "{C:green}#1# chance#1# sur #3#{} de", "{E:2,C:red}s'auto-détruire", }, }, @@ -1233,9 +1488,13 @@ return { j_cry_googol_play = { name = "Carte Googol Play", text = { - "{C:green}#1# chance(s) sur #2#{} de compter", + "{C:green}#1# chance#1# sur #2#{} de compter", "{X:red,C:white} X#3# {} Multi", }, + unlock = { + "Marquer {C:attention}1.0e100{} Jetons", + "en une seule main", + }, }, j_cry_happy = { name = ":D", @@ -1263,6 +1522,11 @@ return { "la main jouée", "contient une {C:attention}#2#", }, + unlock = { + "Gagner une partie", + "sans jouer", + "de {E:1,C:attention}Full", + }, }, j_cry_hunger = { name = "Consomme-able", @@ -1297,6 +1561,12 @@ return { "est jouée", "{C:inactive}(Actuellement {X:mult,C:white} X#2# {C:inactive} Multi)", }, + unlock = { + "Gagner une partie", + "en ne jouant", + "qu'{C:attention}un seul type{}", + "de {C:attention}main de poker", + }, }, j_cry_jollysus = { name = "Joker Joyeux?", @@ -1308,6 +1578,14 @@ return { "{C:inactive,s:0.8}Je vois pas de souci...{}", }, }, + j_cry_jtron = { + name = "Jimbo-tron 9000", + text = { + "Ce Joker gagne {X:dark_edition,C:white} ^#1# {} Multi", + "pour chaque {C:attention}Joker{} par défaut", + "{C:inactive}(Actuellement {X:dark_edition,C:white}^#2#{C:inactive} Multi)", + }, + }, j_cry_kidnap = { name = "Kidnapping", text = { @@ -1341,6 +1619,20 @@ return { "un {C:attention}Joker{} aléatoire lorsque", "{C:attention}la Blinde de Boss{} est battue", }, + unlock = { + "Battre une {C:attention}Blinde de Boss", + "avec {C:attention}5 cartes avec édition", + "et {C:attention}jokers", + "ou plus", + }, + }, + j_cry_lebaron_james = { + name = "LeBaron James", + text = { + "Les {C:attention}Rois{} comptés donnent", + "{C:attention}+#1#{} à la taille de la main cette manche", + "et redéclenchent les effets des cartes {C:attention}tenues en main{}", + }, }, j_cry_lightupthenight = { name = "Light Up the Night", @@ -1364,7 +1656,7 @@ return { "{C:attention}Redéclenche{} tous les jokers", "une fois pour chaque {C:attention}Joker{}", "{C:attention}joyeux{} vendu cette manche", - "{C:inactive}(Actuellement {}{C:attention:}#1#{}{C:inactive} redéclenchement(s)){}", + "{C:inactive}(Actuellement {}{C:attention:}#1#{}{C:inactive} redéclenchement#1#){}", "{C:inactive,s:0.8}Y'avait pas assez de place...{}", }, }, @@ -1435,7 +1727,7 @@ return { name = "Masque", text = { "Redéclenche toutes les cartes {C:attention}Figure{}", - "{C:attention}#1#{} fois supplémentaire(s)", + "{C:attention}#1#{} fois supplémentaire#1#", "Toutes les cartes non-{C:attention}Figure{} sont affaiblies", }, }, @@ -1447,6 +1739,10 @@ return { "toutes les cartes {C:attention}numérotées{}", "sont considérées des {C:attention}10{}", }, + unlock = { + "Jouer un {C:attention}Flush Five{}", + "de {C:attention}Rois", + }, }, j_cry_maze = { name = "Labyrinthe", @@ -1479,23 +1775,23 @@ return { "{X:mult,C:white}X#1#{} Multi pour chaque membre", "dans le {C:attention}serveur Discord{} de {C:attention}Cryptid{}", "{C:inactive}(Actuellement {X:mult,C:white}X#2#{C:inactive} Multi)", - "{C:blue,s:0.7}https://discord.gg/eUf9Ur6RyB{}", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", }, }, j_cry_membershipcardtwo = { name = "Vieille carte de membre", --Could probably have a diff Name imo text = { - "{C:chips}+#1#{} Jetons pour chaque membre", + "{C:chips}+#1#{} Jeton#1# pour chaque membre", "dans le {C:attention}serveur Discord{} de {C:attention}Cryptid{}", - "{C:inactive}(Actuellement {C:chips}+#2#{C:inactive} Jetons)", - "{C:blue,s:0.7}https://discord.gg/eUf9Ur6RyB{}", + "{C:inactive}(Actuellement {C:chips}+#2#{C:inactive} Jeton#2#)", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", }, }, j_cry_meteor = { name = "Pluie de météores", text = { "Les cartes {C:dark_edition}Brillantes{} donnent", - "chacun {C:chips}+#1#{} Jetons", + "chacun {C:chips}+#1#{} Jeton#1#", }, }, j_cry_mneon = { @@ -1524,13 +1820,13 @@ return { "détruit le Joker situé à sa gauche", "et augmente ces {C:mult}Jetons{} de {C:attention}dix fois{}", "la valeur de vente du Joker détruit", - "{C:inactive}(Actuellement {C:chips}+#1#{C:inactive} Jetons)", + "{C:inactive}(Actuellement {C:chips}+#1#{C:inactive} Jeton#1#)", }, }, j_cry_monopoly_money = { name = "Billet de Monopoly", text = { - "{C:green}#1# chance(s) sur #2#{} de", + "{C:green}#1# chance#1# sur #2#{} de", "{C:attention}détruire{} les objets achetés", "Divise l'argent par 2 si {C:attention}vendu", }, @@ -1566,7 +1862,7 @@ return { j_cry_multjoker = { name = "Joker Multi", text = { - "{C:green}#1# chance(s) sur #2#{} pour chaque", + "{C:green}#1# chance#1# sur #2#{} pour chaque", "carte {C:attention}Multi{} jouée de créer", "une carte {C:spectral}Cryptide{} lorsqu'elle est marquée", "{C:inactive}(Selon la place disponible)", @@ -1589,7 +1885,7 @@ return { j_cry_nice = { name = "Nice", text = { - "{C:chips}+#1#{} Jetons si la main jouée", + "{C:chips}+#1#{} Jeton#1# si la main jouée", "contient un {C:attention}6{} et un {C:attention}9", "{C:inactive,s:0.8}Nice.{}", }, @@ -1612,7 +1908,7 @@ return { j_cry_notebook = { name = "Carnet", text = { - "{C:green} #1# chance(s) sur #2#{} de gagner {C:dark_edition}+1{} Joker max", + "{C:green} #1# chance#1# sur #2#{} de gagner {C:dark_edition}+1{} Joker max", "à chaque {C:attention}réapprovisionnement{} de la boutique", "Se {C:green}déclenche toujours{} s'il y a", "{C:attention}#5# Jokers Joyeux{} ou plus", @@ -1636,6 +1932,11 @@ return { "la main jouée", "contient une {C:attention}#2#", }, + unlock = { + "Gagner une partie", + "sans jouer", + "de {E:1,C:attention}Quinte Flush", + }, }, j_cry_nutty = { name = "Joker foldingue", @@ -1657,7 +1958,7 @@ return { text = { "Copie les capacités du", "{C:attention}Joker{} à sa droite", - "{C:green}#1# chance(s) sur #2#{} que", + "{C:green}#1# chance#1# sur #2#{} que", "cette carte soit détruite", "à la fin de la manche", }, @@ -1690,7 +1991,7 @@ return { j_cry_penetrating = { name = "Joker perçant", text = { - "{C:chips}+#1#{} Jetons si", + "{C:chips}+#1#{} Jeton#1# si", "la main jouée", "contient une {C:attention}#2#", }, @@ -1720,6 +2021,10 @@ return { "mais augmente de", "{C:blue}#2#{} à la fin de la manche", }, + unlock = { + "Augmenter la {C:attention}taille de la main", + "à {C:attention}12", + }, }, j_cry_primus = { name = "Primus", @@ -1730,6 +2035,23 @@ return { "{C:inactive}(Actuellement {X:dark_edition,C:white} ^#2# {C:inactive} Multi)", }, }, + j_cry_pumpkin = { + name = "Citrouille", + text = { + "Empêche la mort si les jetons marqués", + "comptent au moins {C:attention}50%{} des jetons nécessaires", + "{C:attention}Devient une Citrouille sculptée", + "{C:attention}lorsqu'elle est{} {C:red}détruite", + }, + }, + j_cry_carved_pumpkin = { + name = "Carved Pumpkin", + text = { + "Les {C:attention}#1#{} prochaînes Blindes de Boss", + "auront leur fonctionnalité", + "{C:attention}désactivée", + }, + }, j_cry_python = { name = "Python", text = { @@ -1755,11 +2077,17 @@ return { "la main jouée", "contient une {C:attention}#2#", }, + unlock = { + "Gagner une partie", + "avec comme dernière main", + "un {E:1,C:attention}Five of a Kind", + -- TODO: Do we want to use vanilla or betterfr hand names? + }, }, j_cry_redbloon = { name = "Bloon Rouge", text = { - "Gagne {C:money}$#1#{} dans {C:attention}#2#{} manche#3#", + "Gagne {C:money}$#1#{} dans {C:attention}#2#{} manche#2#", "{C:red,E:2}s'auto-détruit{}", }, }, @@ -1797,6 +2125,11 @@ return { text = { "Les capacités sont changées à chaque {C:attention}Ante{}", }, + unlock = { + "{C:green}1 chance sur 20{}", + "de débloquer cette carte", + "après un {C:attention}Game Over", + }, }, j_cry_sacrifice = { name = "Sacrifice", @@ -1821,7 +2154,7 @@ return { j_cry_savvy = { name = "Joker avisé", text = { - "{C:chips}+#1#{} Jetons si", + "{C:chips}+#1#{} Jeton#1# si", "la main jouée", "contient un {C:attention}#2#", }, @@ -1839,7 +2172,7 @@ return { j_cry_scrabble = { name = "Lettre de Scrabble", text = { - "{C:green}#1# chance(s) sur #2#{} de créer", + "{C:green}#1# chance#1# sur #2#{} de créer", "un Joker {C:dark_edition}Joyeux {C:green}Peu commun{}", "lorsque la main est jouée", }, @@ -1854,7 +2187,7 @@ return { j_cry_shrewd = { name = "Joker astucieux", text = { - "{C:chips}+#1#{} Jetons si", + "{C:chips}+#1#{} Jeton#1# si", "la main jouée", "contient une {C:attention}#2#", }, @@ -1886,6 +2219,20 @@ return { "{C:attention}+#1#{} emplacement de consommable", "{C:attention}+#1#{} carte dans la boutique", }, + unlock = { + "Gagner une partie", + "en ne jouant que des {C:attention}Carte Haute", + }, + }, + j_cry_fleshpanopticon = { + name = "Flesh Panopticon", + text = { + "{C:red}X#1#{} à la taille de la {C:attention}Blinde de Boss{}", + "Lorsque la {C:attention}Boss Blind{} est battue,", + "{C:red}s'auto-détruit{}, et crée", + "une carte {C:spectral}Portail{} {C:dark_edition}Négative{}", + '{C:inactive,s:0.8}"This prison... to hold... me?"', + }, }, j_cry_spaceglobe = { name = "Globe Céleste", @@ -1938,11 +2285,16 @@ return { "la main jouée", "contient un {C:attention}#2#", }, + unlock = { + "Gagner une partie", + "avec comme dernière main", + "un {E:1,C:attention}Rempart", + }, }, j_cry_subtle = { name = "Joker subtil", text = { - "{C:chips}+#1#{} Jetons si", + "{C:chips}+#1#{} Jeton#1# si", "la main jouée", "contient une {C:attention}#2#", }, @@ -1950,7 +2302,7 @@ return { j_cry_supercell = { name = "Supercell", text = { - "{C:chips}+#1#{} Jetons, {C:mult}+#1#{} Multi,", + "{C:chips}+#1#{} Jeton#1#, {C:mult}+#1#{} Multi,", "{X:chips,C:white}X#2#{} Jetons, {X:mult,C:white}X#2#{} Multi", "Gagne {C:money}$#3#{} à", "la fin de la manche", @@ -1973,6 +2325,11 @@ return { "la main jouée", "contient une {C:attention}#2#", }, + unlock = { + "Gagner une partie", + "avec comme dernière main", + "un {E:1,C:attention}Pentacle flush", -- TODO: *what* do we use for hand names?? + }, }, j_cry_sync_catalyst = { name = "Catalyse Synchro", @@ -2007,7 +2364,7 @@ return { j_cry_treacherous = { name = "Joker traître", text = { - "{C:chips}+#1#{} Jetons si", + "{C:chips}+#1#{} Jeton#1# si", "la main jouée", "contient une {C:attention}#2#", }, @@ -2016,7 +2373,7 @@ return { name = "Des bonbons ou un sort!", text = { "Lorsque cette carte est {C:attention}vendue{}:", - "{C:green}#1# chance(s) sur #2#{} de créer {C:attention}2{} {C:cry_candy}bonbons", + "{C:green}#1# chance#1# sur #2#{} de créer {C:attention}2{} {C:cry_candy}bonbons", "Sinon, crée un Joker {X:cry_cursed,C:white}Maudit{}", "{C:inactive}(Peut dépasser les maximums)", }, @@ -2024,7 +2381,7 @@ return { j_cry_tricksy = { name = "Joker espiègle", text = { - "{C:chips}+#1#{} Jetons si", + "{C:chips}+#1#{} Jeton#1# si", "la main jouée", "contient une {C:attention}#2#", }, @@ -2051,6 +2408,12 @@ return { "la main jouée", "contient une {C:attention}#2#", }, + unlock = { + "Gagner une partie", + "avec comme dernière main", + "un {E:1,C:attention}Full flush", + -- okay for this one i think the betterfr hand name fits better + }, }, j_cry_universe = { name = "L'Univers", @@ -2133,7 +2496,7 @@ return { name = "2D", text = { "Redéclenche chaque {C:attention}2{} joué", --wee gaming - "{C:attention:}#1#{} fois supplémentaire(s)", --wee gaming? + "{C:attention:}#1#{} fois supplémentaire#1#", --wee gaming? "{C:inactive,s:0.8}Wee Gaming?{}", }, }, @@ -2159,17 +2522,33 @@ return { name = "Bonbon enveloppé", text = { "Crée un {C:attention}Joker Nourriture{}", - "dans {C:attention}#1#{} manche(s)", + "dans {C:attention}#1#{} manche#1#", "puis {C:red,E:2}s'auto-détruit{}", }, }, j_cry_wtf = { - name = "Le Bordel", + name = Cryptid_config.family_mode and "Le Capharnaüm" or "Le Bordel", text = { "{X:mult,C:white}x#1#{} Multi si", "la main jouée", "contient un {C:attention}#2#", }, + unlock = { + "Gagner une partie", + "avec comme dernière main", + "un {E:1,C:attention}Bordel", + -- now do we have the family friendly mode here too or + }, + }, + j_cry_zooble = { + name = "Zooble", + text = { + "Si la main jouée", + "ne contient {C:attention}pas{} de {C:attention}Quinte{},", + "ce Joker gagne {C:mult}+#2#{} Multi pour chaque", + "{C:attention}rang unique{} marqué dans la main", + "{C:inactive}(Actuellement {C:mult}+#1#{C:inactive} Multi)", + }, }, }, Planet = { @@ -2217,7 +2596,7 @@ return { c_cry_planetlua = { name = "Planete.lua", text = { - "{C:green}#1# chance(s) sur #2#{}", + "{C:green}#1# chance#1# sur #2#{}", "d'améliorer toutes", "les {C:legendary,E:1}mains de poker{}", "d'{C:attention}1{} niveau", @@ -2249,7 +2628,7 @@ return { "{S:0.8}({S:0.8,V:1}niv.#1#{S:0.8}){} Améliore", "{C:attention}#2#", "{C:mult}+#3#{} Multi et", - "{C:chips}+#4#{} Jetons", + "{C:chips}+#4#{} Jeton#4#", }, }, c_cry_void = { @@ -2258,7 +2637,7 @@ return { "{S:0.8}({S:0.8,V:1}niv.#1#{S:0.8}){} Améliore", "{C:attention}#2#", "{C:mult}+#3#{} Multi et", - "{C:chips}+#4#{} Jetons", + "{C:chips}+#4#{} Jeton#4#", }, }, c_cry_asteroidbelt = { @@ -2267,16 +2646,26 @@ return { "{S:0.8}({S:0.8,V:1}niv.#1#{S:0.8}){} Améliore", "{C:attention}#2#", "{C:mult}+#3#{} Multi et", - "{C:chips}+#4#{} Jetons", + "{C:chips}+#4#{} Jeton#4#", }, }, c_cry_universe = { - name = "l'entièreté du putain d'univers", + name = Cryptid_config.family_mode and "L'entièreté de l'univers observable" + or "l'entièreté du putain d'univers", text = { "{S:0.8}({S:0.8,V:1}niv.#1#{S:0.8}){} Améliore", "{C:attention}#2#", "{C:mult}+#3#{} Multi et", - "{C:chips}+#4#{} Jetons", + "{C:chips}+#4#{} Jeton#4#", + }, + }, + c_cry_sunplanet = { + name = "Soleil", + text = { + "{S:0.8}({S:0.8,V:1}lvl.#1#{S:0.8}){}", + "Augmente la puissance des", + "mains {C:attention}ascensionnées{} de {X:gold,C:white}0.05{}", + "{C:inactive}(Actuellement {X:gold,C:white}X(#2#^asc){C:inactive})", }, }, }, @@ -2301,8 +2690,8 @@ return { name = "Pochette Critique", text = { "Après chaque main jouée,", - "{C:green}1 chance(s) sur 4{} d'obtenir {X:dark_edition,C:white} ^2 {} Multi", - "{C:green}1 chance(s) sur 8{} d'obtenir {X:dark_edition,C:white} ^0.5 {} Multi", + "{C:green}1 chance sur 4{} d'obtenir {X:dark_edition,C:white} ^2 {} Multi", + "{C:green}1 chance sur 8{} d'obtenir {X:dark_edition,C:white} ^0.5 {} Multi", }, }, sleeve_cry_encoded_sleeve = { @@ -2487,6 +2876,14 @@ return { }, }, c_cry_white_hole = { + name = "Trou blanc", + text = { + "Améliore la main de poker", + "la {C:legendary,E:1}plus jouée{} de {C:attention}4{}", + "{C:attention}Enlève les niveaux{} de toutes les autres mains", + }, + }, + c_cry_white_hole2 = { name = "Trou blanc", text = { "{C:attention}Enlève{} toues les niveaux de toutes les mains,", @@ -2624,7 +3021,7 @@ return { colour = "Twilight", text = { "Les cartes peuvent être {C:attention}Banane{}", - "{s:0.8,C:inactive}(1 chance(s) sur 10 d'être détruite à la fin de la manche){}", + "{s:0.8,C:inactive}(1 chance sur 10 d'être détruite à la fin de la manche){}", }, }, stake_cry_verdant = { @@ -2776,7 +3173,7 @@ return { tag_cry_gambler = { name = "Badge du Parieur", text = { - "{C:green}#1# chance(s) sur #2#{} de créer", + "{C:green}#1# chance#1# sur #2#{} de créer", "un {C:cry_exotic,E:1}Badge Renforcé", }, }, @@ -2905,8 +3302,8 @@ return { name = "l'Éclipse", text = { "Transforme jusqu'à {C:attention}#1#", - "cartes sélectionnées en", - "{C:attention}Carte(s) écho", + "carte#1# sélectionnée#1# en", + "{C:attention}Carte#1# écho", }, }, c_cry_meld = { @@ -2925,6 +3322,14 @@ return { "{C:inactive}(Selon la place disponible){}", }, }, + c_cry_seraph = { + name = "le Séraphin", + text = { + "Transforme jusqu'à {C:attention}#1#", + "carte#1# sélectionnée#1# en", + "{C:attention}Carte#1# Lumière", + }, + }, }, Voucher = { v_cry_asteroglyph = { @@ -2932,12 +3337,19 @@ return { text = { "Règle l'Ante sur {C:attention}#1#{}", }, + unlock = { + "Atteindre l'Ante {C:attention}36", + }, }, v_cry_blankcanvas = { name = "Tableau Blanc", text = { "{C:attention}+#1#{} à la taille de la main", }, + unlock = { + "Réduire la {C:attention}taille de la main", + "à {C:attention}0", + }, }, v_cry_clone_machine = { name = "Machine de Clones", @@ -2970,13 +3382,22 @@ return { "apparaissent avec", "une {C:dark_edition}Édition{}", }, + unlock = { + "Découvrir toutes", + "les {C:attention}Éditions", + }, }, v_cry_dexterity = { name = "Dextérité", text = { - "{C:blue}+#1#{} main(s) par manche", + "{C:blue}+#1#{} main#1# par manche", "{C:inactive}(oui, encore)", }, + unlock = { + "Jouer {C:attention}5000{}", + "{C:attention}cartes à jouer{}", + "en tout", + }, }, v_cry_double_down = { name = "Double ou double", @@ -3005,7 +3426,11 @@ return { v_cry_fabric = { name = "Toile Universelle", text = { - "{C:dark_edition}+#1#{} emplacement(s) de Joker", + "{C:dark_edition}+#1#{} emplacement#1# de Joker", + }, + unlock = { + "Récupérer {C:dark_edition}Antimatière", + "{C:attention}10{} fois", }, }, v_cry_massproduct = { @@ -3014,6 +3439,11 @@ return { "Toutes les cartes et tous les paquets", "dans la boutique coutent {C:attention}$1{}", }, + unlock = { + "Récupérer {C:attention}25", + "{C:attention}coupons", + "en une partie", + }, }, v_cry_moneybean = { name = "Haricot d'Argent", @@ -3022,14 +3452,24 @@ return { "des intérêts perçus", "par manche à {C:money}#1#${}", }, + unlock = { + "Atteindre le maximum", + "{C:attention}du gain d'intérêts{}", + "durant {C:attention}toute la partie", + }, }, v_cry_overstock_multi = { name = "Multi-stock", text = { - "{C:attention}+#1#{} emplacement(s) de carte(s) et", - "{C:attention}+#1#{} emplacement(s) de paquet(s)", + "{C:attention}+#1#{} emplacement#1# de carte#1# et", + "{C:attention}+#1#{} emplacement#1# de paquet#1#", "disponibles dans la boutique", }, + unlock = { + "Dépenser {C:attention}1000$", + "dans la boutique", + "en une partie", + }, }, v_cry_pacclimator = { name = "Acclimateur de Planète", @@ -3040,6 +3480,11 @@ return { "Toutes les futures cartes", "{C:planet}Planète{} sont {C:green}gratuites{}", }, + unlock = { + "Acheter {C:attention}100{} cartes", + "{C:planet}Planète{} en tout", + "dans la boutique", + }, }, v_cry_pairamount_plus = { name = "Pair'amount Plus", @@ -3077,6 +3522,11 @@ return { "{C:green}Réassortir{} la boutique", "coûte {C:money}2${}", }, + unlock = { + "{C:attention}Réassortir{} la boutique", + "un total de {C:attention}250 fois{}", + "en une partie", + }, }, v_cry_satellite_uplink = { name = "Liaison Astrale", @@ -3094,6 +3544,12 @@ return { "jouée", "{C:inactive}(Selon la place disponible){}", }, + unlock = { + "Utiliser {C:attention}50{} cartes", + "{C:planet}Planète{} des", + "{C:attention}Paquets Booster{}", + "en une partie", + }, }, v_cry_tacclimator = { name = "Acclimateur de Tarot", @@ -3104,6 +3560,11 @@ return { "Toutes les futures cartes", "{C:tarot}Tarot{} seront {C:green}gratuites{}", }, + unlock = { + "Acheter {C:attention}100{} cartes", + "{C:tarot}Tarot{} en tout", + "dans la boutique", + }, }, v_cry_tag_printer = { name = "Imprimante à Badge", @@ -3119,6 +3580,11 @@ return { "{C:red}#1#{} défausses", "par manche", }, + unlock = { + "Défausser {C:attention}5000{}", + "{C:attention}cartes à jouer{}", + "en tout", + }, }, v_cry_stickyhand = { name = "Main Collante", @@ -3146,13 +3612,48 @@ return { }, }, Other = { + disabled = { + name = "Désactivé", + text = { + "N'apparaîtra plus", + "durant les parties", + }, + }, + disabled_card_dependency = { + name = "Désactivé", + text = { + "Nécessite {C:attention}#1#", + }, + }, + disabled_mod_dependency = { + name = "Désactivé", + text = { + "Nécessite le mod:", + "{C:attention}#1#", + }, + }, + disabled_mod_conflict = { + name = "Désactivé", + text = { + "Incompatible avec le mod:", + "{C:attention}#1#", + }, + }, banana = { name = "Banane", text = { - "{C:green}#1# chance(s) sur #2#{} d'être", + "{C:green}#1# chance#1# sur #2#{} d'être", "détruit après chaque manche", }, }, + cry_absolute = { + name = "Absolu", + text = { + "Ne peut pas être vendu", + "ou détruit", + "{C:attention}Impossible à enlever{}", + }, + }, cry_rigged = { name = "Truqué", text = { @@ -3196,7 +3697,7 @@ return { "{s:0.8}Gros Michel, Œuf, Crème Glacée, Cavendish,", "{s:0.8}Haricot Noir, Cola zéro, Popcorn, Ramen,", "{s:0.8}Eau de Seltz, Cornichon, Piment, Caramel,", - "{s:0.8}Nostalgic Candy, Fast Food M, etc.", + "{s:0.8}Bonbon Nostalgique, M Fast Food, etc.", }, }, cry_https_disabled = { @@ -3381,7 +3882,7 @@ return { cry_banana_voucher = { name = "Banane", text = { - "{C:green}#1# chance(s) sur #2#{} d'être", + "{C:green}#1# chance#1# sur #2#{} d'être", "enlevé à la fin de la manche", }, }, @@ -3526,11 +4027,78 @@ return { }, }, misc = { + tutorial = { + cry_intro_1 = { + "Salut, je suis {C:attention}Joseph J. Joker{},", + "et bienvenue dans {C:cry_exotic,E:1}Cryptid{} !", + }, + cry_intro_2 = { + "On dirait que vous n'avez jamais joué", + "à {C:cry_exotic,E:1}Cryptid{} sur ce profil auparavant.", + "Laisse-moi te montrer comment ça marche, par ici !", + }, + cry_intro_3 = { + "*obtient des mains*", + }, + cry_intro_4 = { + "C'est très dur d'expliquer ce mod", + "en quelques phrases, mais ce que je peux te dire", + "c'est que tu vas avoir des parties de {C:cry_exotic,E:1}taré !", + "On est très loin du {C:attention}Joker Poker{} classique, tu vois...", + }, + cry_intro_5 = { + "Comme tu peux le remarquer par ces", + "{C:cry_ascendant}styles de jeu{}, j'adore la lettre {C:attention}M{}.", + "Sélectionne un style de jeu pour que je t'explique le tout...", + "{s:0.8}À noter: L'équilibrage des styles de jeu est un gros work in progress.", + "{s:0.8}Attends-toi à avoir plein de changements!", + }, + cry_modest_1 = { + "Tu cherches une expérience qui reste proche du vanilla?", + "Le style {C:cry_ascendant}Modeste{} est fait pour toi!", + }, + cry_modest_2 = { + "Mais modeste ne veut pas non plus dire nul, tu pourras", + "toujours rencontrer les nouvelles gimmicks de Cryptid !", + "Qui sait ce qu'il se passera dans tes prochaines manches...", + }, + cry_mainline_1 = { + "Envie de {E:1,C:attention}casser{} le jeu ? Bonne nouvelle,", + "avec le style {C:cry_ascendant}Médian{}, tu peux maintenant le faire", + "sans que tout parte en sucette immédiatement !", + }, + cry_mainline_2 = { + "La folie est toujours là, mais il y a un", + "{C:cry_ascendant}système de progression{} qui t'attend pour t'acclimater", + "au gameplay déjanté. Mais reste quand même sur tes gardes...", + }, + cry_mainline_3 = { + "Tu seras totalement plus puissant, mais", + "j'ai aussi créé de nombreux {E:1,C:dark_edition}boss{} qui vont", + "te faire regretter d'avoir choisi ce {C:cry_ascendant}style{}...", + }, + cry_madness_1 = { + "T'as envie de complètement {C:red,E:1}réduire en cendres{} ton PC ?", + "C'est génial ! Le style {C:cry_ascendant}Maboul{} est plus du genre", + "à envoyer {E:1,C:red}tout équilibrage par la fenêtre !", + }, + cry_madness_2 = { + "Et pour ça, j'ai passé de nombreuses nuits blanches", + "à bosser sur ce style pour qu'il soit", + "{C:cry_ascendant}PARFAITEMENT ÉQUILIBRÉ{}, comme tu le souhaitais !", + }, + cry_madness_3 = { + "Tu commences avec tout ce qui est possible débloqué", + "comme ça tu peux libérer tout le {C:red,E:1}potentiel ultime{}", + "de Cryptid dès le début ! Mais fais attention, il y a plus de chances", + "que tu {C:attention,E:1}plantes le jeu{} plus que tu ne perds de partie...", + }, + }, poker_hands = { ["cry_Bulwark"] = "Rempart", - ["cry_Clusterfuck"] = "Foutoir", + ["cry_Clusterfuck"] = Cryptid_config.family_mode and "Capharnaüm" or "Foutoir", ["cry_UltPair"] = "Super Paire", - ["cry_WholeDeck"] = "un putain de jeu complet", + ["cry_WholeDeck"] = Cryptid_config.family_mode and "Jeu complet" or "un putain de jeu complet", }, poker_hand_descriptions = { ["cry_Bulwark"] = { @@ -3612,7 +4180,7 @@ return { --Settings Menu cry_set_features = "Fonctionnalités", cry_set_music = "Musique", - cry_set_enable_features = "Sélectionnez les fonctionnalités à activer (appliqué au prochain redémarrage):", + cry_set_enable_features = "Utilisez cette section pour activer ou désactiver des Sets thématiques tout entier.", cry_feat_achievements = "Succès", ["cry_feat_antimatter deck"] = "Jeu Anti-matière", cry_feat_blinds = "Blindes", @@ -3640,6 +4208,9 @@ return { cry_mus_code = "Cartes Code (://LETS_BREAK_THE_GAME par HexaCryonic)", cry_mus_exotic = "Jokers exotiques (Joker in Latin par AlexZGreat)", cry_mus_high_score = "High Score (Final Boss [For Your Computer] par AlexZGreat)", + cry_mus_alt_bg = "Musique de titre (by MathIsFun_)", + cry_family = "Mode family-friendly", + cry_experimental = "Mode expérimental", k_cry_program_pack = "Paquet Programme", k_cry_meme_pack = "Paquet Meme", @@ -3658,13 +4229,25 @@ return { cry_debuff_oldmark = "No hands containing a Pair", cry_debuff_obsidian_orb = "Applique les capacités de tous les boss battus", + cry_tax_placeholder = "(X0.4 taille de la blinde)", + cry_joke_placeholder = "(multiple de 8)", + k_code = "Code", + k_content_set = "Set à thème", + b_content_sets = "Sets à thème", + --Why aren't these in vanilla? + b_tag = "Badge", + b_blind = "Blinde", + + b_tarot_rate = "Taux de tarot", + b_planet_rate = "Taux de planète", + k_unique = "Unique", b_code_cards = "Cartes Code", b_unique_cards = "Cartes uniques", b_pull = "TIRER", cry_hooked_ex = "Accroché!", - k_end_blind = "End Blind", + k_end_blind = "Finir la blinde", cry_code_rank = "ENTRER UN RANG", cry_code_enh = "ENTRER UNE AMELIORATION", @@ -3682,6 +4265,9 @@ return { b_flip = "RETOURNER", b_merge = "FUSIONNER", + cry_asc_hands = "Mains Asc.", + cry_p_star = "Étoile", + cry_hand_bulwark = "Muraille", cry_hand_clusterfuck = "Foutoir", cry_hand_ultpair = "Super Paire", @@ -3699,6 +4285,8 @@ return { cry_m_ex = "M!", cry_minus_round = "-1 Tour", cry_plus_cryptid = "+1 Cryptide", + cry_plus_card = "+1 Carte", + cry_plus_code = "+1 Code", cry_no_triggers = "Pas de redéclenchements restants!", cry_unredeemed = "Plus échangé...", cry_active = "Actif", @@ -3712,13 +4300,33 @@ return { k_cry_cursed = "Maudit", k_planet_disc = "Disque Circumstellaire", k_planet_satellite = "Satellites Naturels", - k_planet_universe = "Le putain d'univers", + k_planet_universe = Cryptid_config.family_mode and "Univers" or "Le putain d'univers", cry_notif_jimball_1 = "Jimboule", cry_notif_jimball_2 = "Notice de droits d'auteur", cry_notif_jimball_d1 = 'Jimboule joue la musique "Funkytown",', cry_notif_jimball_d2 = "qui est soumise aux droits d'auteur et ne peut", cry_notif_jimball_d3 = "pas être utilisée dans des streams ou vidéos.", + + cry_gameset_explanation = { + "Sélectionne un style de jeu", + "à appliquer sur cette carte.", + }, + cry_gameset_disabled = "Désactivé", + cry_gameset_modest = "Modeste", + cry_gameset_mainline = "Médian", + cry_gameset_madness = "Maboul", + cry_gameset_custom = "Modifié", + cry_gameset_exp = "Expérimental", + cry_gameset_exp_modest = "Expérimental (Modeste)", + cry_gameset_exp_mainline = "Expérimental (Médian)", + cry_gameset_exp_madness = "Expérimental (Maboul)", + + cry_view_set_contents = "Voir les objets dans le set", + + b_reset_gameset_modest = "Réinitialiser la configuration du style (Modeste)", + b_reset_gameset_mainline = "Réinitialiser la configuration du style (Médian)", + b_reset_gameset_madness = "Réinitialiser la configuration du style (Maboul)", }, labels = { food_jokers = "Jokers nourriture", @@ -3752,7 +4360,7 @@ return { rnj_loc_txts = { stats = { plus_mult = { "{C:red}+#2#{} Multi" }, - plus_chips = { "{C:blue}+#2#{} Jetons" }, + plus_chips = { "{C:blue}+#2#{} Jeton#2#" }, x_mult = { "{X:red,C:white} X#2#{} Multi" }, x_chips = { "{X:blue,C:white} X#2#{} Jetons" }, h_size = { "{C:attention}+#2#{} à la taille de main" }, @@ -3760,7 +4368,7 @@ return { }, stats_inactive = { plus_mult = { "{C:inactive}(Actuellement {C:red}+#1#{C:inactive} Multi)" }, - plus_chips = { "{C:inactive}(Actuellement {C:blue}+#1#{C:inactive} Jetons)" }, + plus_chips = { "{C:inactive}(Actuellement {C:blue}+#1#{C:inactive} Jeton#1#)" }, x_mult = { "{C:inactive}(Actuellement {X:red,C:white} X#1# {C:inactive} Multi)" }, x_chips = { "{C:inactive}(Actuellement {X:blue,C:white} X#1# {C:inactive} Jetons)" }, h_size = { "{C:inactive}(Actuellement {C:attention}+#1#{C:inactive} taille de main)" }, @@ -3835,13 +4443,13 @@ return { a_powmult = { "^#1# Multi" }, a_powchips = { "^#1# Jetons" }, a_powmultchips = { "^#1# Multi+Jetons" }, - a_round = { "+#1# Manche(s)" }, + a_round = { "+#1# Manche#1#" }, a_candy = { "+#1# bonbon" }, a_xchips_minus = { "-X#1# Jetons" }, a_powmult_minus = { "-^#1# Multi" }, a_powchips_minus = { "-^#1# Jetons" }, a_powmultchips_minus = { "-^#1# Multi+Jetons" }, - a_round_minus = { "-#1# Manche(s)" }, + a_round_minus = { "-#1# Manche#1#" }, a_tag_minus = { "-#1# Badge" }, a_tags_minus = { "-#1# Badges" }, a_tag = { "#1# Badge" }, diff --git a/Cryptid/localization/id.lua b/Cryptid/localization/id.lua index dec9d88..cc5579c 100644 --- a/Cryptid/localization/id.lua +++ b/Cryptid/localization/id.lua @@ -1236,7 +1236,7 @@ return { "{X:mult,C:white}X#1#{} Mult for each member", "in the {C:attention}Cryptid Discord{}", "{C:inactive}(Currently {X:mult,C:white}X#2#{C:inactive} Mult)", - "{C:blue,s:0.7}https://discord.gg/eUf9Ur6RyB{}", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", }, }, j_cry_membershipcardtwo = { @@ -1245,7 +1245,7 @@ return { "{C:chips}+#1#{} Chips for each member", "in the {C:attention}Cryptid Discord{}", "{C:inactive}(Currently {C:chips}+#2#{C:inactive} Chips)", - "{C:blue,s:0.7}https://discord.gg/eUf9Ur6RyB{}", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", }, }, j_cry_meteor = { @@ -3083,7 +3083,7 @@ return { k_disable_music = "Disable Music", k_cry_epic = "Epic", - k_cry_epic = "Exotic", + k_cry_exotic = "Exotic", cry_notif_jimball_1 = "Jimball", cry_notif_jimball_2 = "Copyright Notice", @@ -3113,7 +3113,7 @@ return { cry_oversat = "Oversaturated", k_cry_epic = "Epic", - k_cry_epic = "Exotic", + k_cry_exotic = "Exotic", }, rnj_loc_txts = { stats = { diff --git a/Cryptid/localization/ja.lua b/Cryptid/localization/ja.lua index 7728020..24a359e 100644 --- a/Cryptid/localization/ja.lua +++ b/Cryptid/localization/ja.lua @@ -1236,7 +1236,7 @@ return { "{X:mult,C:white}X#1#{} Mult for each member", "in the {C:attention}Cryptid Discord{}", "{C:inactive}(Currently {X:mult,C:white}X#2#{C:inactive} Mult)", - "{C:blue,s:0.7}https://discord.gg/eUf9Ur6RyB{}", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", }, }, j_cry_membershipcardtwo = { @@ -1245,7 +1245,7 @@ return { "{C:chips}+#1#{} Chips for each member", "in the {C:attention}Cryptid Discord{}", "{C:inactive}(Currently {C:chips}+#2#{C:inactive} Chips)", - "{C:blue,s:0.7}https://discord.gg/eUf9Ur6RyB{}", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", }, }, j_cry_meteor = { @@ -3083,7 +3083,7 @@ return { k_disable_music = "Disable Music", k_cry_epic = "Epic", - k_cry_epic = "Exotic", + k_cry_exotic = "Exotic", cry_notif_jimball_1 = "Jimball", cry_notif_jimball_2 = "Copyright Notice", @@ -3113,7 +3113,7 @@ return { cry_oversat = "Oversaturated", k_cry_epic = "Epic", - k_cry_epic = "Exotic", + k_cry_exotic = "Exotic", }, rnj_loc_txts = { stats = { diff --git a/Cryptid/localization/ko.lua b/Cryptid/localization/ko.lua index dec9d88..cc5579c 100644 --- a/Cryptid/localization/ko.lua +++ b/Cryptid/localization/ko.lua @@ -1236,7 +1236,7 @@ return { "{X:mult,C:white}X#1#{} Mult for each member", "in the {C:attention}Cryptid Discord{}", "{C:inactive}(Currently {X:mult,C:white}X#2#{C:inactive} Mult)", - "{C:blue,s:0.7}https://discord.gg/eUf9Ur6RyB{}", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", }, }, j_cry_membershipcardtwo = { @@ -1245,7 +1245,7 @@ return { "{C:chips}+#1#{} Chips for each member", "in the {C:attention}Cryptid Discord{}", "{C:inactive}(Currently {C:chips}+#2#{C:inactive} Chips)", - "{C:blue,s:0.7}https://discord.gg/eUf9Ur6RyB{}", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", }, }, j_cry_meteor = { @@ -3083,7 +3083,7 @@ return { k_disable_music = "Disable Music", k_cry_epic = "Epic", - k_cry_epic = "Exotic", + k_cry_exotic = "Exotic", cry_notif_jimball_1 = "Jimball", cry_notif_jimball_2 = "Copyright Notice", @@ -3113,7 +3113,7 @@ return { cry_oversat = "Oversaturated", k_cry_epic = "Epic", - k_cry_epic = "Exotic", + k_cry_exotic = "Exotic", }, rnj_loc_txts = { stats = { diff --git a/Cryptid/localization/nl.lua b/Cryptid/localization/nl.lua index 461ee49..787f1ae 100644 --- a/Cryptid/localization/nl.lua +++ b/Cryptid/localization/nl.lua @@ -1239,7 +1239,7 @@ return { "{X:mult,C:white}X#1#{} Mult for each member", "in the {C:attention}Cryptid Discord{}", "{C:inactive}(Currently {X:mult,C:white}X#2#{C:inactive} Mult)", - "{C:blue,s:0.7}https://discord.gg/eUf9Ur6RyB{}", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", }, }, j_cry_membershipcardtwo = { @@ -1248,7 +1248,7 @@ return { "{C:chips}+#1#{} Chips for each member", "in the {C:attention}Cryptid Discord{}", "{C:inactive}(Currently {C:chips}+#2#{C:inactive} Chips)", - "{C:blue,s:0.7}https://discord.gg/eUf9Ur6RyB{}", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", }, }, j_cry_meteor = { diff --git a/Cryptid/localization/pl.lua b/Cryptid/localization/pl.lua index 8aeb852..05c7cc6 100644 --- a/Cryptid/localization/pl.lua +++ b/Cryptid/localization/pl.lua @@ -1447,7 +1447,7 @@ return { "Mnoż. {X:mult,C:white}X#1#{} za każdego członka", "discordowego serwera {C:attention}Cryptid{}", "{C:inactive}(obecny mnoż.: {X:mult,C:white}X#2#{C:inactive}", - "{C:blue,s:0.7}https://discord.gg/eUf9Ur6RyB{}", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", }, }, j_cry_membershipcardtwo = { @@ -1456,7 +1456,7 @@ return { "{C:chips}+#1#{} za każdego członka", "discordowego serwera {C:attention}Cryptid{}", "{C:inactive}(obecnie: {C:chips}+#2#{C:inactive} żet.)", - "{C:blue,s:0.7}https://discord.gg/eUf9Ur6RyB{}", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", }, }, j_cry_meteor = { diff --git a/Cryptid/localization/pt_BR.lua b/Cryptid/localization/pt_BR.lua index dec9d88..cc5579c 100644 --- a/Cryptid/localization/pt_BR.lua +++ b/Cryptid/localization/pt_BR.lua @@ -1236,7 +1236,7 @@ return { "{X:mult,C:white}X#1#{} Mult for each member", "in the {C:attention}Cryptid Discord{}", "{C:inactive}(Currently {X:mult,C:white}X#2#{C:inactive} Mult)", - "{C:blue,s:0.7}https://discord.gg/eUf9Ur6RyB{}", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", }, }, j_cry_membershipcardtwo = { @@ -1245,7 +1245,7 @@ return { "{C:chips}+#1#{} Chips for each member", "in the {C:attention}Cryptid Discord{}", "{C:inactive}(Currently {C:chips}+#2#{C:inactive} Chips)", - "{C:blue,s:0.7}https://discord.gg/eUf9Ur6RyB{}", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", }, }, j_cry_meteor = { @@ -3083,7 +3083,7 @@ return { k_disable_music = "Disable Music", k_cry_epic = "Epic", - k_cry_epic = "Exotic", + k_cry_exotic = "Exotic", cry_notif_jimball_1 = "Jimball", cry_notif_jimball_2 = "Copyright Notice", @@ -3113,7 +3113,7 @@ return { cry_oversat = "Oversaturated", k_cry_epic = "Epic", - k_cry_epic = "Exotic", + k_cry_exotic = "Exotic", }, rnj_loc_txts = { stats = { diff --git a/Cryptid/localization/ru.lua b/Cryptid/localization/ru.lua index a286754..2596d7f 100644 --- a/Cryptid/localization/ru.lua +++ b/Cryptid/localization/ru.lua @@ -1270,7 +1270,7 @@ return { "{X:mult,C:white}X#1#{} Mult for each member", "in the {C:attention}Cryptid Discord{}", "{C:inactive}(Currently {X:mult,C:white}X#2#{C:inactive} Mult)", - "{C:blue,s:0.7}https://discord.gg/eUf9Ur6RyB{}", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", }, }, j_cry_membershipcardtwo = { @@ -1279,7 +1279,7 @@ return { "{C:chips}+#1#{} Chips for each member", "in the {C:attention}Cryptid Discord{}", "{C:inactive}(Currently {C:chips}+#2#{C:inactive} Chips)", - "{C:blue,s:0.7}https://discord.gg/eUf9Ur6RyB{}", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", }, }, j_cry_meteor = { @@ -3114,7 +3114,7 @@ return { cry_inactive = "Inactive", k_cry_epic = "Epic", - k_cry_epic = "Exotic", + k_cry_exotic = "Exotic", }, labels = { food_jokers = "Food Jokers", @@ -3138,7 +3138,7 @@ return { cry_oversat = "Oversaturated", k_cry_epic = "Epic", - k_cry_epic = "Exotic", + k_cry_exotic = "Exotic", }, rnj_loc_txts = { stats = { diff --git a/Cryptid/localization/vi.lua b/Cryptid/localization/vi.lua index 4f0f602..bf70d21 100644 --- a/Cryptid/localization/vi.lua +++ b/Cryptid/localization/vi.lua @@ -32,7 +32,7 @@ return { }, }, b_cry_bountiful = { - name = "Bộ Bài Phong phú", + name = "Bộ Bài Phong Phú", text = { "Sau khi {C:blue}Chơi{} hoặc {C:red}Bỏ Bài{},", "luôn bốc {C:attention}5{} lá", @@ -63,6 +63,14 @@ return { "Xác suất {C:green}#1# trên 8{} cho {X:dark_edition,C:white} ^0.5 {} Nhân", }, }, + b_cry_e_deck = { + name = "Bộ Bài Ấn Bản", + text = { + "Mọi lá bài đều có {C:dark_edition}#1#{}", + "Lá bài không thể thay đổi ấn bản", + "{C:inactive}(Nhấn để chỉnh sửa)", + }, + }, b_cry_encoded = { name = "Bộ Bài Mã Hóa", text = { @@ -81,6 +89,14 @@ return { "{C:attention,T:v_overstock_plus}Siêu Quá Trữ", }, }, + b_cry_et_deck = { + name = "Bộ Bài Cường Hoá", + text = { + "Mọi {C:attention}lá bài thường{}", + "đều là {C:attention}#1#{}", + "{C:inactive}(Nhấn để chỉnh sửa)", + }, + }, b_cry_glowing = { name = "Bộ Bài Dạ Quang", text = { @@ -112,12 +128,35 @@ return { "ngay {C:attention}các cấp bổ sung{} của nó", }, }, + b_cry_sk_deck = { + name = "Bộ Bài Nhãn", + text = { + "Mọi lá bài đều có nhãn {C:attention}#1#{}", + "{C:inactive}(Nhấn để chỉnh sửa)", + }, + }, + b_cry_sl_deck = { + name = "Bộ Bài Con Dấu", + text = { + "Mọi lá bài thường đều có {C:dark_edition}#1#{}", + "Lá bài không thể thay đổi con dấu", + "{C:inactive}(Nhấn để chỉnh sửa)", + }, + }, b_cry_spooky = { name = "Bộ Bài Ma Quái", text = { "Bắt đầu với {C:attention,T:j_cry_chocolate_dice}Xúc Sắc Sôcôla {C:eternal}Vĩnh Hằng", "Sau mỗi {C:attention}Ante{}, tạo ra", - "viên {C:cry_candy}Kẹo{} hoặc Joker {X:cry_cursed,C:white}Nguyền Rủa", + "viên {C:cry_candy}Kẹo{} hoặc Joker {X:cry_cursed,C:white}Nguyền_Rủa", + }, + }, + b_cry_st_deck = { + name = "Bộ Bài Đồng Chất", + text = { + "Mọi lá bài thường đều có", + "chất {C:dark_edition}#1#{} và không thể đổi chất", + "{C:inactive}(Nhấn để chỉnh sửa)", }, }, b_cry_very_fair = { @@ -274,8 +313,8 @@ return { bl_cry_sapphire_stamp = { name = "Sapphire Stamp", text = { - "Chọn thêm một lá, bỏ chọn", - "1 lá ngẫu nhiên trước khi tính điểm", + "Chọn thêm một lá, bỏ chọn 1 lá", + "ngẫu nhiên trước khi tính điểm", }, }, bl_cry_shackle = { @@ -313,6 +352,13 @@ return { "sau mỗi tay bài đã chơi", }, }, + bl_cry_trophy = { + name = "Lemon Trophy", + text = { + "Nhân không thể", + "nhiều hơn Chip", + }, + }, bl_cry_vermillion_virus = { name = "Vermillion Virus", text = { @@ -515,6 +561,131 @@ return { }, }, }, + ["Content Set"] = { + set_cry_blind = { + name = "Blind", + text = { + "{C:attention}Boss Blind{} được", + "thêm bởi Cryptid", + }, + }, + set_cry_code = { + name = "Lá Code", + text = { + "{C:cry_code}Lá Code{} và", + "nội dung liên quan", + }, + }, + set_cry_cursed = { + name = "Joker Nguyền Rủa", + text = { + "Joker gây hại với", + "độ hiếm {X:cry_cursed,C:white}Nguyền_Rủa{}", + }, + }, + set_cry_deck = { + name = "Bộ Bài", + text = { + "{C:attention}Bộ Bài{} được", + "thêm bởi Cryptid", + }, + }, + set_cry_epic = { + name = "Joker Sử Thi", + text = { + "Joker có độ hiếm", + "{C:cry_epic}Sử Thi{}", + "{C:inactive,s:0.8}(Giữa Hiếm và Huyền Thoại)", + }, + }, + set_cry_exotic = { + name = "Joker Ngoại Lai", + text = { + "Joker mạnh khủng khiếp", + "có độ hiếm {C:cry_exotic}Ngoại Lai{}", + }, + }, + set_cry_m = { + name = "Joker M", + text = { + "Joker liên quan", + "đến chữ {C:attention}M{}", + "và {C:attention}Joker Vui Nhộn", + }, + }, + set_cry_misc = { + name = "Khác", + text = { + "Vật phẩm không thuộc", + "bất kì {C:cry_ascendant}Nhóm", + "{C:cry_ascendant}Chủ Đề{} nào", + }, + }, + set_cry_misc_joker = { + name = "Joker Khác", + text = { + "Joker không thuộc", + "bất kì {C:cry_ascendant}Nhóm", + "{C:cry_ascendant}Chủ Đề{} nào", + }, + }, + set_cry_planet = { + name = "Lá Hành Tinh", + text = { + "Lá {C:planet}Hành Tinh{} khác", + "được thêm bởi Cryptid", + }, + }, + set_cry_poker_hand_stuff = { + name = "Tay Poker", + text = { + "Thêm 4 {C:attention}tay poker mới", + "và cho phép {C:attention}tay Thăng Thiên", + }, + }, + set_cry_spectral = { + name = "Lá Siêu Linh", + text = { + "Lá {C:spectral}Siêu Linh{} được", + "thêm bởi Cryptid", + }, + }, + set_cry_spooky = { + name = "Bản Cập Nhật Ma Quái", + text = { + "Nội dung Bản Cập Nhật Ma Quái,", + "bao gồm Joker {C:cry_candy}Kẹo{}", + }, + }, + set_cry_tag = { + name = "Nhãn Bỏ Qua", + text = { + "{C:attention}Nhãn{} được thêm", + "bởi Cryptid", + }, + }, + set_cry_tier3 = { + name = "Phiếu Cấp 3", + text = { + "Một {C:attention}cấp{} bổ sung", + "của Phiếu", + }, + }, + set_cry_timer = { + name = "Cơ Chế Thời Gian", + text = { + "Vật phẩm có hiệu ứng", + "và cơ chế {C:attention}thời gian", + }, + }, + set_cry_voucher = { + name = "Phiếu Khác", + text = { + "{C:attention}Phiếu{} cấp 1 và 2", + "được thêm bởi Cryptid", + }, + }, + }, Edition = { e_cry_astral = { name = "Thiên Tú", @@ -617,6 +788,33 @@ return { }, }, Joker = { + j_cry_test_modest = { + name = "Joker Thử Nghiệm", + text = { + "{C:chips}+#1#{} Chip#s1#", + }, + }, + j_cry_test_mainline = { + name = "Joker Thử Nghiệm", + text = { + "{C:chips}+#1#{} Chip#s1#", + "{C:money}+$44{} khi {C:attention}Blind{} được chọn", + }, + }, + j_cry_test_madness = { + name = "Joker Thử Nghiệm", + text = { + "{C:chips}+#1#{} Chip#s1#", + "{C:money}+$44444{} khi {C:attention}Blind{} được chọn", + }, + }, + j_cry_test_cryptid_in_2025 = { + name = "Joker Thử Nghiệm", + text = { + "{C:chips}+#1#{} Chip#s1#", + "{C:money}+$44444{} khi {C:attention}Blind{} được chọn", + }, + }, j_cry_adroit = { name = "Joker Khéo Léo", text = { @@ -740,7 +938,7 @@ return { j_cry_boredom = { name = "Buồn Chán", text = { - "Xác suất {C:green}#1# trong #2#{} để", + "Xác suất {C:green}#1# trên #2#{} để", "{C:attention}tái kích{} mỗi lá {C:attention}Joker{}", "hoặc {C:attention}lá bài đã chơi{}", "{C:inactive,s:0.8}Không tác dụng lên lá Buồn Chán khác{}", @@ -935,9 +1133,17 @@ return { j_cry_copypaste = { name = "Copy/Paste", text = { - "Khi một lá {C:cry_code}Code{} được dùng,", - "Xác suất {C:green}#1# trên #2#{} tạo ra bản sao", - "vào ô tiêu thụ", + "Xác suất {C:green}#1# trên #2#{} để nhân bản", + "lá {C:cry_code}Code{} đã sử dụng", + "{C:red}Dùng được một lần mỗi ván{}", + "{C:inactive}(Phải có ô trống)", + }, + }, + j_cry_copypaste2 = { + name = "Copy/Paste", + text = { + "Xác suất {C:green}#1# trên #2#{} để nhân bản", + "lá {C:cry_code}Code{} đã sử dụng", "{C:inactive}(Phải có ô trống)", }, }, @@ -1125,10 +1331,19 @@ return { }, }, j_cry_eternalflame = { - name = "Ngọn lửa Vĩnh hằng", + name = "Ngọn Lửa Vĩnh Hằng", text = { "Joker này thêm {X:mult,C:white} X#1# {} Nhân", - "cho mỗi lá đã {C:attention}bán{}", + "mỗi lá bài {C:attention}đã bán{} với", + "{C:attention}giá bán{} tối thiểu {C:money}$3{}", + "{C:inactive}(Hiện tại là {X:mult,C:white} X#2# {C:inactive} Nhân)", + }, + }, + j_cry_eternalflame2 = { + name = "Ngọn Lửa Vĩnh Hằng", + text = { + "Joker này thêm {X:mult,C:white} X#1# {} Nhân", + "mỗi lá bài {C:attention}đã bán{}", "{C:inactive}(Hiện tại là {X:mult,C:white} X#2# {C:inactive} Nhân)", }, }, @@ -1218,7 +1433,7 @@ return { j_cry_formidiulosus = { name = "Khu Tà", text = { - "Khi nhận một Joker {X:cry_cursed,C:white}Nguyền Rủa{}, phá hủy nó", + "Khi nhận một Joker {X:cry_cursed,C:white}Nguyền_Rủa{}, phá hủy nó", "Tạo ra {C:attention}#1#{} viên {C:cry_candy}Kẹo {C:dark_edition}Âm Bản{} vào cuối Shop", "Thêm {X:dark_edition,C:white}^#2#{} Nhân cho mỗi viên {C:cry_candy}Kẹo{} đang sở hữu", "{C:inactive}(Hiện tại lạ {X:dark_edition,C:white}^#3#{C:inactive} Nhân)", @@ -1242,7 +1457,7 @@ return { }, }, j_cry_fuckedup = { - name = 'Joker "Hết Cứu"', + name = Cryptid_config.family_mode and "Joker Ngăn Nắp" or 'Joker "Hết Cứu"', text = { "{C:red}+#1#{} Nhân nếu", "tay bài đã chơi", @@ -1384,6 +1599,14 @@ return { "{C:inactive,s:0.8}Nghe có vẻ không sao...{}", }, }, + j_cry_jtron = { + name = "Jimbo-tron 9000", + text = { + "Joker này thêm {X:dark_edition,C:white} ^#1# {} Nhân", + "cho mỗi {C:attention}Joker{} mặc định", + "{C:inactive}(Hiện tại là {X:dark_edition,C:white}^#2#{C:inactive} Nhân)", + }, + }, j_cry_kidnap = { name = "Bắt Cóc", text = { @@ -1424,6 +1647,14 @@ return { "trở lên", }, }, + j_cry_lebaron_james = { + name = "LeBaron James", + text = { + "Lá {C:attention}Già{} đã chơi ghi điểm thêm", + "{C:attention}+#1#{} lá giữ trong tay cho ván này", + "và kích hoạt hiệu ứng {C:attention}giữ trong tay{}", + }, + }, j_cry_lightupthenight = { name = "Thắp Sáng Trời Đêm", text = { @@ -1565,7 +1796,7 @@ return { "{X:mult,C:white}X#1#{} Nhân cho mỗi thành viên", "ở trong {C:attention}Cryptid Discord{}", "{C:inactive}(Hiện tại là {X:mult,C:white}X#2#{C:inactive} Nhân)", - "{C:blue,s:0.7}https://discord.gg/eUf9Ur6RyB{}", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", }, }, j_cry_membershipcardtwo = { @@ -1574,7 +1805,7 @@ return { "{C:chips}+#1#{} Chip cho mỗi thành viên", "ở trong {C:attention}Cryptid Discord{}", "{C:inactive}(Hiện tại là {C:chips}+#2#{C:inactive} Chip)", - "{C:blue,s:0.7}https://discord.gg/eUf9Ur6RyB{}", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", }, }, j_cry_meteor = { @@ -1633,9 +1864,9 @@ return { name = "Sứ Đồ Thập Tam", text = { "Tạo ra một {C:legendary}Joker M{} ở cuối ván", - "thêm {X:dark_edition,C:white}^#1#{} Nhân cho mỗi {C:attention}Joker Vui Nhộn{} hoặc {C:legendary}Joker M ", - "Tăng {X:dark_edition,C:white}^#2#{} khi một {C:attention}Joker Vui Nhộn{} được {C:attention}bán", - "{C:inactive,s:0.8}(Ngoại trừ Thập Tam)", + "thêm {X:dark_edition,C:white}^#1#{} Nhân cho mỗi {C:attention}Joker Vui Nhộn{} hoặc {C:legendary}Joker M", + "Tăng thêm {X:dark_edition,C:white}^#2#{} khi một {C:attention}Joker Vui Nhộn{} được {C:attention}bán", + "{C:inactive,s:0.8}(Ngoại trừ Sứ Đồ Thập Tam)", }, }, j_cry_mstack = { @@ -2174,7 +2405,7 @@ return { text = { "Khi {C:attention}bán{}:", "Xác suất {C:green}#1# trên #2#{} để tạo ra {C:attention}2{} viên {C:cry_candy}Kẹo", - "Nếu trật, tạo ra một Joker {X:cry_cursed,C:white}Nguyền Rủa{}", + "Nếu trật, tạo ra một Joker {X:cry_cursed,C:white}Nguyền_Rủa{}", "{C:inactive}(Có thể tràn ô Joker)", }, }, @@ -2326,7 +2557,7 @@ return { }, }, j_cry_wtf = { - name = "CHUẨN ĐỆCH!?", + name = Cryptid_config.family_mode and "Chuẩn Đống" or "CHUẨN ĐỆCH!?", text = { "{X:mult,C:white} X#1# {} Nhân nếu", "tay bài đã chơi", @@ -2448,7 +2679,7 @@ return { }, }, c_cry_universe = { - name = "Toàn Bộ Cái Vũ Trụ Chết Tiệt", + name = Cryptid_config.family_mode and "Vũ Trụ" or "Toàn Bộ Cái Vũ Trụ Chết Tiệt", text = { "{S:0.8}({S:0.8,V:1}lvl.#1#{S:0.8}){} Nâng level", "{C:attention}#2#", @@ -2544,7 +2775,7 @@ return { text = { "Bắt đầu với {C:attention,T:j_cry_chocolate_dice}Xúc Sắc Sôcôla {C:eternal}Vĩnh Hằng", "Sau mỗi {C:attention}Ante{}, tạo ra", - "viên {C:cry_candy}Kẹo{} hoặc Joker {X:cry_cursed,C:white}Nguyền Rủa", + "viên {C:cry_candy}Kẹo{} hoặc Joker {X:cry_cursed,C:white}Nguyền_Rủa", }, }, sleeve_cry_wormhole_sleeve = { @@ -2690,6 +2921,14 @@ return { }, }, c_cry_white_hole = { + name = "Lỗ Trắng", + text = { + "Nâng level tay poker", + "{C:legendary,E:1}chơi nhiều nhất{} lên 4 lần", + "{C:attention}Loại bỏ{} mọi level khỏi tay poker khác,", + }, + }, + c_cry_white_hole2 = { name = "Lỗ Trắng", text = { "{C:attention}Loại bỏ{} mọi level khỏi các tay poker,", @@ -3415,6 +3654,33 @@ return { }, }, Other = { + disabled = { + name = "Vô Hiệu", + text = { + "Không còn xuất hiện", + "trong trận", + }, + }, + disabled_card_dependency = { + name = "Vô Hiệu", + text = { + "Yêu cầu {C:attention}#1#", + }, + }, + disabled_mod_dependency = { + name = "Vô Hiệu", + text = { + "Yêu cầu mod:", + "{C:attention}#1#", + }, + }, + disabled_mod_conflict = { + name = "Vô Hiệu", + text = { + "Không tương thích với mod:", + "{C:attention}#1#", + }, + }, banana = { name = "Chuối Tiêu", text = { @@ -3724,7 +3990,7 @@ return { text = { "Chọn {C:attention}#1#{} trong tối đa", "{C:attention}#2#{} lá {C:spectral}Siêu Linh", - "{s:0.8,C:inactive}(Được tạo bởi nhãn Siêu Cường)", + "{s:0.8,C:inactive}(Được tạo bởi Nhãn Siêu Cường)", }, }, p_cry_meme_1 = { @@ -3802,11 +4068,77 @@ return { }, }, misc = { + tutorial = { + cry_intro_1 = { + "Chào, tôi tên là {C:attention}Joseph J. Joker{}!", + "Chào mừng đến với {C:cry_exotic,E:1}Cryptid{}!", + }, + cry_intro_2 = { + "Có vẻ như bạn chưa từng chơi", + "{C:cry_exotic,E:1}Cryptid{} bao giờ.", + "Để tôi cho bạn xem cách nó hoạt động nhé!", + }, + cry_intro_3 = { + "*mọc tay*", + }, + cry_intro_4 = { + "Thật khó để tóm tắt mod này trong", + "vài câu, nhưng tôi sẽ nói rằng bạn sắp", + "có một chuyến đi {C:cry_exotic,E:1}dữ dội{} đó!", + "Đây không còn là {C:attention}Joker Poker{} bạn biết nữa đâu...", + }, + cry_intro_5 = { + "Chắc là bạn cũng đoán được thông qua các {C:cry_ascendant}thiết lập{}", + "sau rồi, tôi thì rất thích chữ {C:attention}M{}.", + "Hãy chọn một thiết lập để tôi giải thích...", + "{s:0.8}Lưu ý: Cân bằng thiết lập là một quá trình tốn kém và", + "{s:0.8}lâu dài. Không có gì chắc như đinh đóng cột đâu!", + }, + cry_modest_1 = { + "Bạn đang mong muốn một trải nghiệm gần với bản gốc?", + "Thế thì thiết lập {C:cry_ascendant}M Khiêm Tốn{} là dành cho bạn!", + }, + cry_modest_2 = { + "Tuy nhiên, hãy cẩn thận với những cơ chế ẩn", + "đằng sau Cryptid! Ban không bao giờ biết", + "được thứ gì đang lấp ló ở ván sau đâu...", + }, + cry_mainline_1 = { + "Bạn muốn {E:1,C:attention}phá{} game à? Tui vui đây, bạn hoàn toàn", + "có thể làm thế mà không đi quá sâu vào nội dung!", + }, + cry_mainline_2 = { + "Mọi thứ vẫn rất là điên rồ nha, nhưng bạn vẫn", + "còn cơ hội trải nghiệm hệ thống {C:cry_ascendant}tiến triển{}.", + "Chỉ cần đừng tận hưởng quá là được...", + }, + cry_mainline_3 = { + "Bởi vì bạn chắc chắn sẽ ngày càng mạnh hơn, nhưng", + "tôi nghĩ một vài {E:1,C:dark_edition}Boss Blind{} mới có thể", + "khiến bạn hối hận vì đã chọn {C:cry_ascendant}thiết lập{} này...", + }, + cry_madness_1 = { + "Bạn muốn {C:red,E:1}nổ banh{} ổ cứng luôn à?", + "Ồ, vui đấy! Thiết lập {C:cry_ascendant}M Điên Loạn{} nói", + "'Cân bằng là {E:1,C:red}CÁI MÉO GÌ!?{}'", + }, + cry_madness_2 = { + "Tôi đã bỏ ra hàng tuần mất ngủ và nốc nhiều", + "{C:green}Mountain Dew{} vl ra để đảm bảo rằng thiết lập này là", + "{C:cry_ascendant}CỰC KÌ CÂN BẰNG{}, chỉ dành cho bạn thôi!", + }, + cry_madness_3 = { + "Tất cả mọi thứ đều được mở khoá, vì thế hoàn toàn", + "có thể giải phóng {C:red,E:1}toàn bộ sức mạnh{} của Cryptid!", + "Chỉ cần cẩn thận đừng để {C:attention,E:1}crash{} game,", + "điều đó có lẽ sẽ xảy ra trước khi bạn thua trận...", + }, + }, poker_hands = { ["cry_Bulwark"] = "Tường Thành", - ["cry_Clusterfuck"] = "Mớ Đệch", + ["cry_Clusterfuck"] = Cryptid_config.family_mode and "Mớ Hỗn Độn" or "Mớ Đệch", ["cry_UltPair"] = "Đôi Tối Thượng", - ["cry_WholeDeck"] = "Đệch Mịa Cả Bộ Bài", + ["cry_WholeDeck"] = Cryptid_config.family_mode and "Năm Hai Lá" or "Đệch Mịa Cả Bộ Bài", }, poker_hand_descriptions = { ["cry_Bulwark"] = { @@ -3842,7 +4174,7 @@ return { ach_cry_niw_uoy = "!gnắhT nếihC", ach_cry_now_the_fun_begins = "Cuộc Vui Giờ mới Bắt Đầu.", ach_cry_patience_virtue = "Kiên Nhẫn là Đức Tính Tốt", - ach_cry_perfectly_balanced = "Perfectly Balanced", + ach_cry_perfectly_balanced = "Cực Kì Cân Bằng", ach_cry_pull_request = "Pull Request", ach_cry_traffic_jam = "Tắc Đường", ach_cry_ult_full_skip = "Cú Full Skip Tối Thượng", @@ -3916,6 +4248,9 @@ return { cry_mus_code = "Lá Code (://LETS_BREAK_THE_GAME bởi HexaCryonic)", cry_mus_exotic = "Joker Ngoại Lai (Joker in Latin bởi AlexZGreat)", cry_mus_high_score = "Điểm Cao (Final Boss [For Your Computer] bởi AlexZGreat)", + cry_mus_alt_bg = "Nhạc Nền (bởi MathIsFun_)", + cry_family = "Chế Độ Thận Thiện với Gia Đình", + cry_experimental = "Chế Độ Thử Nghiệm", k_cry_program_pack = "Gói Chương Trình", k_cry_meme_pack = "Gói Meme", @@ -3938,6 +4273,15 @@ return { cry_joke_placeholder = "(bội số của 8)", k_code = "Code", + k_content_set = "Thiết Lập Chủ Đề", + b_content_sets = "Thiết Lập Chủ Đề", + --Why aren't these in vanilla? + b_tag = "Nhãn", + b_blind = "Blind", + + b_tarot_rate = "Tần suất Tarot", + b_planet_rate = "Tần suất Hành Tinh", + k_unique = "Độc Nhất", b_code_cards = "Lá Code", b_unique_cards = "Lá Độc Nhất", @@ -3961,10 +4305,6 @@ return { b_flip = "LẬT LẠI", b_merge = "HỢP NHẤT", - cry_hand_bulwark = "Tường Thành", - cry_hand_clusterfuck = "Mớ Đệch", - cry_hand_ultpair = "Đôi Tối Thượng", - cry_asc_hands = "Tay Thăng Thiên", cry_p_star = "Sao", @@ -3997,17 +4337,38 @@ return { k_cry_cursed = "Nguyền Rủa", k_planet_disc = "Đĩa Cận Sao", k_planet_satellite = "Vệ Tinh Tự Nhiên", - k_planet_universe = "Đệch Mịa Cả Cái Vũ Trụ", + k_planet_universe = Cryptid_config.family_mode and "Vũ Trụ" or "Đệch Mịa Cả Cái Vũ Trụ", cry_notif_jimball_1 = "Jimball", cry_notif_jimball_2 = "Cảnh Báo Bản Quyền", cry_notif_jimball_d1 = 'Jimball sẽ phát bài "Funkytown",', cry_notif_jimball_d2 = "có bản quyền và ảnh hưởng lớn", cry_notif_jimball_d3 = "đến stream và video.", + + cry_gameset_explanation = { + "Chọn nhóm thiết lập", + "để áp dụng lên lá này.", + }, + cry_gameset_disabled = "Vô hiệu", + cry_gameset_modest = "M Khiên Tốn", + cry_gameset_mainline = "M Chính", + cry_gameset_madness = "M Điên Loạn", + cry_gameset_custom = "Đã Sửa Đổi", + cry_gameset_exp = "Thử Nghiệm", + cry_gameset_exp_modest = "Thử Nghiệm (M Khiêm Tốn)", + cry_gameset_exp_mainline = "Experimental (M Chính)", + cry_gameset_exp_madness = "Experimental (M Điên Loạn)", + + cry_view_set_contents = "Xem Vật Phẩm trong Thiết Lập", + + b_reset_gameset_modest = "Đặt Lại Thiết Lập (M Khiêm Tốn)", + b_reset_gameset_mainline = "Đặt Lại Thiết Lập (M Chính)", + b_reset_gameset_madness = "Đặt Lại Thiết Lập (M Điên Loạn)", }, labels = { food_jokers = "Joker Thực Phẩm", banana = "Chuối Tiêu", + pinned = "Bị Ghim", cry_absolute = "Tuyệt Đối", code = "Code", unique = "Độc Nhất", @@ -4130,9 +4491,10 @@ return { a_powchips_minus = { "-^#1# Chip" }, a_powmultchips_minus = { "-^#1# Nhân+Chip" }, a_round_minus = { "-#1# Ván" }, - - a_tag = { "Nhãn #1#" }, - a_tags = { "Nhãn #1#" }, + a_tag_minus = { "-#1# Nhãn" }, + a_tags_minus = { "-#1# Nhãn" }, + a_tag = { "+ Nhãn #1#" }, + a_tags = { "+ Nhãn #1#" }, cry_sticker_name = { "Nhãn #1#" }, cry_sticker_desc = { diff --git a/Cryptid/localization/zh_TW.lua b/Cryptid/localization/zh_TW.lua index dec9d88..cc5579c 100644 --- a/Cryptid/localization/zh_TW.lua +++ b/Cryptid/localization/zh_TW.lua @@ -1236,7 +1236,7 @@ return { "{X:mult,C:white}X#1#{} Mult for each member", "in the {C:attention}Cryptid Discord{}", "{C:inactive}(Currently {X:mult,C:white}X#2#{C:inactive} Mult)", - "{C:blue,s:0.7}https://discord.gg/eUf9Ur6RyB{}", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", }, }, j_cry_membershipcardtwo = { @@ -1245,7 +1245,7 @@ return { "{C:chips}+#1#{} Chips for each member", "in the {C:attention}Cryptid Discord{}", "{C:inactive}(Currently {C:chips}+#2#{C:inactive} Chips)", - "{C:blue,s:0.7}https://discord.gg/eUf9Ur6RyB{}", + "{C:blue,s:0.7}https://discord.gg/cryptid{}", }, }, j_cry_meteor = { @@ -3083,7 +3083,7 @@ return { k_disable_music = "Disable Music", k_cry_epic = "Epic", - k_cry_epic = "Exotic", + k_cry_exotic = "Exotic", cry_notif_jimball_1 = "Jimball", cry_notif_jimball_2 = "Copyright Notice", @@ -3113,7 +3113,7 @@ return { cry_oversat = "Oversaturated", k_cry_epic = "Epic", - k_cry_epic = "Exotic", + k_cry_exotic = "Exotic", }, rnj_loc_txts = { stats = { diff --git a/Cryptid/lovely/Ascended.toml b/Cryptid/lovely/Ascended.toml index 102af62..bfdd552 100644 --- a/Cryptid/lovely/Ascended.toml +++ b/Cryptid/lovely/Ascended.toml @@ -26,7 +26,7 @@ pattern = ''' ''' position = "at" payload = ''' - delay = G.GAME.current_round.current_hand.handname ~= disp_text and 0.4 or 0}, {handname=disp_text, level=G.GAME.hands[text].level, mult = cry_ascend(G.GAME.hands[text].mult), chips = cry_ascend(G.GAME.hands[text].chips)}) + delay = G.GAME.current_round.current_hand.handname ~= disp_text and 0.4 or 0}, {handname=disp_text, level=G.GAME.hands[text].level, mult = Cryptid.ascend(G.GAME.hands[text].mult), chips = Cryptid.ascend(G.GAME.hands[text].chips)}) ''' match_indent = true @@ -54,7 +54,7 @@ pattern = ''' ''' position = "at" payload = ''' - mult = mod_mult(cry_ascend(G.GAME.hands[text].mult)) + mult = mod_mult(Cryptid.ascend(G.GAME.hands[text].mult)) ''' match_indent = true @@ -67,7 +67,7 @@ pattern = ''' ''' position = "at" payload = ''' - hand_chips = mod_chips(cry_ascend(G.GAME.hands[text].chips)) + hand_chips = mod_chips(Cryptid.ascend(G.GAME.hands[text].chips)) ''' match_indent = true @@ -80,7 +80,7 @@ pattern = ''' ''' position = "at" payload = ''' -update_hand_text({delay = 0}, {chips = cry_ascend(G.GAME.hands[hand].chips), StatusText = true}) +update_hand_text({delay = 0}, {chips = Cryptid.ascend(G.GAME.hands[hand].chips), StatusText = true}) ''' match_indent = true @@ -93,7 +93,7 @@ pattern = ''' ''' position = "at" payload = ''' -update_hand_text({delay = 0}, {mult = cry_ascend(G.GAME.hands[hand].mult), StatusText = true}) +update_hand_text({delay = 0}, {mult = Cryptid.ascend(G.GAME.hands[hand].mult), StatusText = true}) ''' match_indent = true @@ -122,7 +122,7 @@ update_hand_text({immediate = true, nopulse = nil, delay = 0}, {handname=disp_te ''' position = "at" payload = ''' -update_hand_text({immediate = true, nopulse = nil, delay = 0}, {handname=disp_text, level=G.GAME.hands[text].level, mult = cry_ascend(G.GAME.hands[text].mult), chips = cry_ascend(G.GAME.hands[text].chips)}) +update_hand_text({immediate = true, nopulse = nil, delay = 0}, {handname=disp_text, level=G.GAME.hands[text].level, mult = Cryptid.ascend(G.GAME.hands[text].mult), chips = Cryptid.ascend(G.GAME.hands[text].chips)}) ''' match_indent = true diff --git a/Cryptid/lovely/Probability.toml b/Cryptid/lovely/Probability.toml deleted file mode 100644 index fc8c5c9..0000000 --- a/Cryptid/lovely/Probability.toml +++ /dev/null @@ -1,300 +0,0 @@ -[manifest] -version = "1.0.0" -dump_lua = true -priority = 5 - -# there's gonna be a lot of this -# init all cards with ability.cry_prob -[[patches]] -[patches.pattern] -target = "card.lua" -pattern = "self.base_cost = center.cost or 1" -position = "before" -payload = ''' -self.ability.cry_prob = 1 -''' -match_indent = true - -# define function in lovely -[[patches]] -[patches.pattern] -target = "functions/misc_functions.lua" -pattern = "function save_run()" -position = "before" -payload = ''' -function cry_prob(owned, den, rigged) - prob = G.GAME and G.GAME.probabilities.normal or 1 - if rigged then - return den - else - if owned then return prob*owned else return prob end - end -end -''' -match_indent = true - -# lucky -[[patches]] -[patches.pattern] -target = "functions/common_events.lua" -pattern = '''elseif _c.effect == 'Lucky Card' then loc_vars = {G.GAME.probabilities.normal, cfg.mult, 5, cfg.p_dollars, 15}''' -position = "at" -payload = ''' -elseif _c.effect == 'Lucky Card' then loc_vars = {cfg.cry_prob and cry_prob(cfg.cry_prob, 15, cfg.cry_rigged) or G.GAME.probabilities.normal, cfg.mult, 5, cfg.p_dollars, 15} -''' -match_indent = true - -[[patches]] -[patches.pattern] -target = "card.lua" -pattern = '''if pseudorandom('lucky_money') < G.GAME.probabilities.normal/15 then''' -position = "at" -payload = ''' -if pseudorandom('lucky_money') < cry_prob(self.ability.cry_prob, 15, self.ability.cry_rigged)/15 then -''' -match_indent = true - -[[patches]] -[patches.pattern] -target = "card.lua" -pattern = '''if pseudorandom('lucky_mult') < G.GAME.probabilities.normal/5 then''' -position = "at" -payload = ''' -if pseudorandom('lucky_mult') < cry_prob(self.ability.cry_prob, 5, self.ability.cry_rigged)/5 then -''' -match_indent = true - -# glass -[[patches]] -[patches.pattern] -target = "functions/common_events.lua" -pattern = '''elseif _c.effect == 'Glass Card' then loc_vars = {cfg.Xmult, G.GAME.probabilities.normal, cfg.extra}''' -position = "at" -payload = ''' -elseif _c.effect == 'Glass Card' then loc_vars = {cfg.Xmult, cfg.cry_prob and cry_prob(cfg.cry_prob, cfg.extra, cfg.cry_rigged) or G.GAME.probabilities.normal, cfg.extra} -''' -match_indent = true - -# wow this is a fat line -# Yellow Stake - Glass can't destroy Eternals -# Glass Stake - Any card can shatter -[[patches]] -[patches.pattern] -target = "functions/state_events.lua" -pattern = '''if SMODS.has_enhancement(scoring_hand[i], 'm_glass') and not scoring_hand[i].debuff and pseudorandom('glass') < G.GAME.probabilities.normal/(scoring_hand[i].ability.name == 'Glass Card' and scoring_hand[i].ability.extra or G.P_CENTERS.m_glass.config.extra) then''' -position = "at" -payload = ''' -if (SMODS.has_enhancement(scoring_hand[i], 'm_glass') - and not scoring_hand[i].debuff - and pseudorandom('glass') < cry_prob( - scoring_hand[i].ability.cry_prob, - scoring_hand[i].ability.extra or G.P_CENTERS.m_glass.config.extra, - scoring_hand[i].ability.cry_rigged - ) / (scoring_hand[i].ability.name == 'Glass Card' - and scoring_hand[i].ability.extra - or G.P_CENTERS.m_glass.config.extra) - or (G.GAME.modifiers.cry_shatter_rate - and pseudorandom('cry_shatter') < 1 / G.GAME.modifiers.cry_shatter_rate)) - and not scoring_hand[i].ability.eternal then''' -match_indent = true - -# wheeeeeeeeeeel -[[patches]] -[patches.pattern] -target = "functions/common_events.lua" -pattern = '''elseif _c.name == "The Wheel of Fortune" then loc_vars = {G.GAME.probabilities.normal, cfg.extra}; info_queue[#info_queue+1] = G.P_CENTERS.e_foil; info_queue[#info_queue+1] = G.P_CENTERS.e_holo; info_queue[#info_queue+1] = G.P_CENTERS.e_polychrome;''' -position = "at" -payload = ''' -elseif _c.name == "The Wheel of Fortune" then loc_vars = {cfg.cry_prob and cry_prob(cfg.cry_prob, cfg.extra, cfg.cry_rigged) or G.GAME.probabilities.normal, cfg.extra}; info_queue[#info_queue+1] = G.P_CENTERS.e_foil; info_queue[#info_queue+1] = G.P_CENTERS.e_holo; info_queue[#info_queue+1] = G.P_CENTERS.e_polychrome; -''' -match_indent = true - -[[patches]] -[patches.pattern] -target = "card.lua" -pattern = '''if self.ability.name == 'Ectoplasm' or self.ability.name == 'Hex' or pseudorandom('wheel_of_fortune') < G.GAME.probabilities.normal/self.ability.extra then''' -position = "at" -payload = ''' -if self.ability.name == 'Ectoplasm' or self.ability.name == 'Hex' or pseudorandom('wheel_of_fortune') < cry_prob(self.ability.cry_prob, self.ability.extra, self.ability.cry_rigged)/self.ability.extra then -''' -match_indent = true - -# ok now onto jonklers - -# space -[[patches]] -[patches.pattern] -target = "card.lua" -pattern = '''elseif self.ability.name == 'Space Joker' then loc_vars = {''..(G.GAME and G.GAME.probabilities.normal or 1), self.ability.extra}''' -position = "at" -payload = ''' -elseif self.ability.name == 'Space Joker' then loc_vars = {cry_prob(self.ability.cry_prob, self.ability.extra, self.ability.cry_rigged), self.ability.extra} -''' -match_indent = true - -[[patches]] -[patches.pattern] -target = "card.lua" -pattern = '''if self.ability.name == 'Space Joker' and pseudorandom('space') < G.GAME.probabilities.normal/self.ability.extra then''' -position = "at" -payload = ''' -if self.ability.name == 'Space Joker' and pseudorandom('space') < cry_prob(self.ability.cry_prob, self.ability.extra, self.ability.cry_rigged)/self.ability.extra then -''' -match_indent = true - -# 8ball -[[patches]] -[patches.pattern] -target = "card.lua" -pattern = '''elseif self.ability.name == '8 Ball' then loc_vars = {''..(G.GAME and G.GAME.probabilities.normal or 1),self.ability.extra}''' -position = "at" -payload = ''' -elseif self.ability.name == '8 Ball' then loc_vars = {cry_prob(self.ability.cry_prob, self.ability.extra, self.ability.cry_rigged),self.ability.extra} -''' -match_indent = true - -[[patches]] -[patches.pattern] -target = "card.lua" -pattern = '''if (context.other_card:get_id() == 8) and (pseudorandom('8ball') < G.GAME.probabilities.normal/self.ability.extra) then''' -position = "at" -payload = ''' -if (context.other_card:get_id() == 8) and (pseudorandom('8ball') < cry_prob(self.ability.cry_prob, self.ability.extra, self.ability.cry_rigged)/self.ability.extra) then -''' -match_indent = true - -# business -[[patches]] -[patches.pattern] -target = "card.lua" -pattern = '''elseif self.ability.name == 'Business Card' then loc_vars = {''..(G.GAME and G.GAME.probabilities.normal or 1), self.ability.extra}''' -position = "at" -payload = ''' -elseif self.ability.name == 'Business Card' then loc_vars = {cry_prob(self.ability.cry_prob, self.ability.extra, self.ability.cry_rigged),self.ability.extra} -''' -match_indent = true - -[[patches]] -[patches.pattern] -target = "card.lua" -pattern = '''pseudorandom('business') < G.GAME.probabilities.normal/self.ability.extra then''' -position = "at" -payload = ''' -pseudorandom('business') < cry_prob(self.ability.cry_prob, self.ability.extra, self.ability.cry_rigged)/self.ability.extra then -''' -match_indent = true - -# gros michel + cavendish -[[patches]] -[patches.pattern] -target = "card.lua" -pattern = '''elseif self.ability.name == 'Gros Michel' then loc_vars = {self.ability.extra.mult, ''..(G.GAME and G.GAME.probabilities.normal or 1), self.ability.extra.odds}''' -position = "at" -payload = ''' -elseif self.ability.name == 'Gros Michel' then loc_vars = {self.ability.extra.mult, cry_prob(self.ability.cry_prob, self.ability.extra.odds, self.ability.cry_rigged), self.ability.extra.odds} -''' -match_indent = true - -[[patches]] -[patches.pattern] -target = "card.lua" -pattern = '''elseif self.ability.name == 'Cavendish' then loc_vars = {self.ability.extra.Xmult, ''..(G.GAME and G.GAME.probabilities.normal or 1), self.ability.extra.odds}''' -position = "at" -payload = ''' -elseif self.ability.name == 'Cavendish' then loc_vars = {self.ability.extra.Xmult, cry_prob(self.ability.cry_prob, self.ability.extra.odds, self.ability.cry_rigged), self.ability.extra.odds} -''' -match_indent = true - -[[patches]] -[patches.pattern] -target = "card.lua" -pattern = '''if pseudorandom(self.ability.name == 'Cavendish' and 'cavendish' or 'gros_michel') < G.GAME.probabilities.normal/self.ability.extra.odds then''' -position = "at" -payload = ''' -if pseudorandom(self.ability.name == 'Cavendish' and 'cavendish' or 'gros_michel') < cry_prob(self.ability.cry_prob, self.ability.extra.odds, self.ability.cry_rigged)/self.ability.extra.odds then -''' -match_indent = true - -# business -[[patches]] -[patches.pattern] -target = "card.lua" -pattern = '''elseif self.ability.name == 'Business Card' then loc_vars = {''..(G.GAME and G.GAME.probabilities.normal or 1), self.ability.extra}''' -position = "at" -payload = ''' -elseif self.ability.name == 'Business Card' then loc_vars = {cry_prob(self.ability.cry_prob, self.ability.extra, self.ability.cry_rigged),self.ability.extra} -''' -match_indent = true - -[[patches]] -[patches.pattern] -target = "card.lua" -pattern = '''pseudorandom('business') < G.GAME.probabilities.normal/self.ability.extra then''' -position = "at" -payload = ''' -pseudorandom('business') < cry_prob(self.ability.cry_prob, self.ability.extra, self.ability.cry_rigged)/self.ability.extra then -''' -match_indent = true - -# bloodstone -[[patches]] -[patches.pattern] -target = "card.lua" -pattern = '''elseif self.ability.name == 'Bloodstone' then loc_vars = {''..(G.GAME and G.GAME.probabilities.normal or 1), self.ability.extra.odds, self.ability.extra.Xmult}''' -position = "at" -payload = ''' -elseif self.ability.name == 'Bloodstone' then loc_vars = {cry_prob(self.ability.cry_prob, self.ability.extra.odds, self.ability.cry_rigged), self.ability.extra.odds, self.ability.extra.Xmult} -''' -match_indent = true - -[[patches]] -[patches.pattern] -target = "card.lua" -pattern = '''pseudorandom('bloodstone') < G.GAME.probabilities.normal/self.ability.extra.odds then''' -position = "at" -payload = ''' -pseudorandom('bloodstone') < cry_prob(self.ability.cry_prob, self.ability.extra.odds, self.ability.cry_rigged)/self.ability.extra.odds then -''' -match_indent = true - -# reserved parking -[[patches]] -[patches.pattern] -target = "card.lua" -pattern = '''elseif self.ability.name == 'Reserved Parking' then loc_vars = {self.ability.extra.dollars, ''..(G.GAME and G.GAME.probabilities.normal or 1), self.ability.extra.odds}''' -position = "at" -payload = ''' -elseif self.ability.name == 'Reserved Parking' then loc_vars = {self.ability.extra.dollars, cry_prob(self.ability.cry_prob, self.ability.extra.odds, self.ability.cry_rigged), self.ability.extra.odds} -''' -match_indent = true - -[[patches]] -[patches.pattern] -target = "card.lua" -pattern = '''pseudorandom('parking') < G.GAME.probabilities.normal/self.ability.extra.odds then''' -position = "at" -payload = ''' -pseudorandom('parking') < cry_prob(self.ability.cry_prob, self.ability.extra.odds, self.ability.cry_rigged)/self.ability.extra.odds then -''' -match_indent = true - -# hallucination -[[patches]] -[patches.pattern] -target = "card.lua" -pattern = '''elseif self.ability.name == 'Hallucination' then loc_vars = {G.GAME.probabilities.normal, self.ability.extra}''' -position = "at" -payload = ''' -elseif self.ability.name == 'Hallucination' then loc_vars = {cry_prob(self.ability.cry_prob, self.ability.extra, self.ability.cry_rigged), self.ability.extra} -''' -match_indent = true - -[[patches]] -[patches.pattern] -target = "card.lua" -pattern = '''if pseudorandom('halu'..G.GAME.round_resets.ante) < G.GAME.probabilities.normal/self.ability.extra then''' -position = "at" -payload = ''' -if pseudorandom('halu'..G.GAME.round_resets.ante) < cry_prob(self.ability.cry_prob, self.ability.extra, self.ability.cry_rigged)/self.ability.extra then -''' -match_indent = true diff --git a/Cryptid/lovely/Voucher.toml b/Cryptid/lovely/Voucher.toml index 0be6c3a..4e731f8 100644 --- a/Cryptid/lovely/Voucher.toml +++ b/Cryptid/lovely/Voucher.toml @@ -29,9 +29,6 @@ self.shop_cry_bonusvoucher = cardTable.shop_cry_bonusvoucher ''' match_indent = true - - - # get rid of this dumb hackfix in :redeem() # also track vouchers redeemed [[patches]] @@ -79,7 +76,7 @@ target = "functions/state_events.lua" pattern = '''G.GAME.current_round.voucher = get_next_voucher_key()''' position = "after" payload = ''' -G.GAME.current_round.cry_voucher_stickers = cry_get_next_voucher_stickers() +G.GAME.current_round.cry_voucher_stickers = Cryptid.next_voucher_stickers() G.GAME.current_round.cry_voucher_edition = cry_get_next_voucher_edition() or {} G.GAME.current_round.cry_bonusvouchers = {} G.GAME.cry_bonusvouchersused = {} -- i'm not sure why i'm putting these in two separate tables but it doesn't matter much @@ -96,7 +93,7 @@ target = "game.lua" pattern = '''self.GAME.current_round.voucher = G.SETTINGS.tutorial_progress and G.SETTINGS.tutorial_progress.forced_voucher or get_next_voucher_key()''' position = "after" payload = ''' -G.GAME.current_round.cry_voucher_stickers = cry_get_next_voucher_stickers() +G.GAME.current_round.cry_voucher_stickers = Cryptid.next_voucher_stickers() G.GAME.current_round.cry_voucher_edition = cry_get_next_voucher_edition() or {} for i = 1, self.GAME.cry_bonusvouchercount do self.GAME.current_round.cry_bonusvouchers[i] = get_next_voucher_key() @@ -128,7 +125,7 @@ for i = 1, #G.GAME.current_round.cry_bonusvouchers do local card = Card(G.shop_vouchers.T.x + G.shop_vouchers.T.w/2, G.shop_vouchers.T.y, G.CARD_W, G.CARD_H, G.P_CARDS.empty, G.P_CENTERS[G.GAME.current_round.cry_bonusvouchers[i]],{bypass_discovery_center = true, bypass_discovery_ui = true}) card.shop_cry_bonusvoucher = i - cry_misprintize(card) + Cryptid.misprintize(card) if G.GAME.events.ev_cry_choco2 then card.misprint_cost_fac = (card.misprint_cost_fac or 1) * 2 card:set_cost() diff --git a/Cryptid/version b/Cryptid/version new file mode 100644 index 0000000..d1d899f --- /dev/null +++ b/Cryptid/version @@ -0,0 +1 @@ +0.5.5 diff --git a/DebugPlus/api.lua b/DebugPlus/debugplus/api.lua similarity index 100% rename from DebugPlus/api.lua rename to DebugPlus/debugplus/api.lua diff --git a/DebugPlus/config.lua b/DebugPlus/debugplus/config.lua similarity index 95% rename from DebugPlus/config.lua rename to DebugPlus/debugplus/config.lua index 5de4c20..d2ab12d 100644 --- a/DebugPlus/config.lua +++ b/DebugPlus/debugplus/config.lua @@ -113,22 +113,22 @@ local configDefinition = { global.configDefinition = configDefinition -local configPages = { -- TODO: implement paging, maybe only when I need to +local configPages = { { - name = "Console", + name = "Console", "showNewLogs", "onlyCommands", "logLevel", - "processTables", - "stringifyPrint", - "hyjackErrorHandler", + "processTables", + "stringifyPrint", + "hyjackErrorHandler", }, - { - name = "Misc", + { + name = "Misc", "debugMode", "ctrlKeybinds", "showHUD", - } + } } for k,v in pairs(configDefinition) do @@ -186,7 +186,7 @@ local function parseConfigFile(data) for str in string.gmatch(data, "([^\n\r]+)") do local name, val = str:match("(%w+)%s*=%s*(.+)") if not name then - logger.errorLog("Failed to parse line:", str) + logger.error("Failed to parse line:", str) else t[name] = parseConfigValue(val) end @@ -214,7 +214,7 @@ local function loadSaveFromFile() if success and type(res) == "table" then return res end - logger.errorLog("Loading save err", res) + logger.error("Loading save err", res) return {} end @@ -235,7 +235,7 @@ local function updateSaveFile() if success then love.filesystem.write("config/DebugPlus.jkr", res) else - logger.errorLog("Failure saving config", res) + logger.error("Failure saving config", res) end end @@ -245,7 +245,7 @@ function global.setValue(key, value) if not def then return end if configTypes[def.type] and configTypes[def.type].validate then if not configTypes[def.type].validate(value, def) then - logger.errorLog('Value for saving key ' .. key .. ' failed to validate') + logger.error('Value for saving key ' .. key .. ' failed to validate') return end end @@ -334,7 +334,7 @@ local function generateMemory() if configTypes[def.type].validate(v, def) then value = v else - logger.errorLog('Value for saved key ' .. k .. ' failed to validate') + logger.error('Value for saved key ' .. k .. ' failed to validate') value = def.default end else diff --git a/DebugPlus/console.lua b/DebugPlus/debugplus/console.lua similarity index 86% rename from DebugPlus/console.lua rename to DebugPlus/debugplus/console.lua index 24cdf7e..949e37c 100644 --- a/DebugPlus/console.lua +++ b/DebugPlus/debugplus/console.lua @@ -11,12 +11,15 @@ local fadeTime = 1 -- Amount of time it takes for a message to fade local consoleOpen = false local openNextFrame = false local gameKeyRepeat = love.keyboard.hasKeyRepeat() +local gameTextInput = love.keyboard.hasTextInput() local showNewLogs = config.getValue("showNewLogs") local firstConsoleRender = nil +---@type string[] local history = {} +---@type {index: number, val: string} local currentHistory = nil +---@type {name: string, source: string, desc: string, shortDesc: string, exec: fun(args: string[], rawArgs: string, dp: table): string, string?, table?}[] local commands = nil -local controller = nil local logOffset = 0 commands = {{ @@ -79,11 +82,25 @@ commands = {{ if not func then return "Syntax Error: " .. err, "ERROR" end - local success, res = pcall(func) - if not success then - return "Error: " .. res, "ERROR" + local res = util.pack(pcall(func)) + local success = table.remove(res, 1) + res.n = res.n - 1 + local resString = "" + if res.n > 1 then + for k = 1, res.n do + local v = res[k] + if k ~= 1 then + resString = resString .. ", " + end + resString = resString .. util.stringifyTable(v) + end + else + resString = util.stringifyTable(res[1]) end - return util.stringifyTable(res) + if not success then + return "Error: " .. resString, "ERROR" + end + return resString end }, { name = "money", @@ -347,10 +364,10 @@ commands = {{ rootC = root.consumeable end if #args < 2 then - return "Please provide a key to set", "ERROR" + return "Please provide a key to set", "ERROR" end if #args < 3 then - return "Please provide a value to set", "ERROR" + return "Please provide a value to set", "ERROR" end for i = 2, #args-2 do root = root[args[i]] @@ -401,6 +418,7 @@ local function runCommand() inputText = "" consoleOpen = false love.keyboard.setKeyRepeat(gameKeyRepeat) + love.keyboard.setTextInput(gameTextInput) local cmd for i, c in ipairs(commands) do @@ -417,7 +435,7 @@ local function runCommand() return logger.handleLog({1, 0, 0}, "ERROR", "< ERROR: Command '" .. cmdName .. "' not found.") end local dp = { - hovered = G.CONTROLLER.hovering.target, + hovered = G and G.CONTROLLER and G.CONTROLLER.hovering.target, handleLog = logger.handleLog } local success, result, loglevel, colourOverride = pcall(cmd.exec, args, rawArgs, dp) @@ -454,6 +472,7 @@ function global.consoleHandleKey(key) if key == "escape" then consoleOpen = false love.keyboard.setKeyRepeat(gameKeyRepeat) + love.keyboard.setTextInput(gameTextInput) inputText = "" end -- This bit stolen from https://love2d.org/wiki/love.textinput @@ -505,29 +524,35 @@ function global.consoleHandleKey(key) end -local orig_textinput = love.textinput +local orig_textinput local function textinput(t) - if orig_textinput then - orig_textinput(t) - end -- That way if another mod uses this, I don't clobber it's implementation if not consoleOpen then + if orig_textinput then + orig_textinput(t) + end -- That way if another mod uses this, I don't clobber it's implementation return end inputText = inputText .. t end -love.textinput = textinput -local orig_wheelmoved = love.wheelmoved +local orig_wheelmoved local function wheelmoved(x, y) - if orig_wheelmoved then - orig_wheelmoved(x, y) - end if not consoleOpen then + if orig_wheelmoved then + orig_wheelmoved(x, y) + end return end logOffset = math.min(math.max(logOffset + y, 0), #logger.logs - 1) end -love.wheelmoved = wheelmoved + +local function hookStuffs() + orig_textinput = love.textinput + love.textinput = textinput + + orig_wheelmoved = love.wheelmoved + love.wheelmoved = wheelmoved +end local function calcHeight(text, width) local font = love.graphics.getFont() @@ -538,60 +563,61 @@ local function calcHeight(text, width) end local function hyjackErrorHandler() - local orig = love.errorhandler - if not orig then -- Vanilla - return -- Doesn't work with love.errhand (need love.errorhandler) - end - local function safeCall(func, ...) - local succ, res = pcall(func, ...) - if not succ then print("ERROR", res) - else return res end - end - function love.errorhandler(msg) - local ret = orig(msg) - orig_wheelmoved = nil - orig_textinput = nil - consoleOpen = false - inputText = "" - love.keyboard.setKeyRepeat(gameKeyRepeat) - local justCrashed = true + local orig = love.errorhandler + if not orig then -- Vanilla + return -- Doesn't work with love.errhand (need love.errorhandler) + end + local function safeCall(func, ...) + local succ, res = pcall(func, ...) + if not succ then print("ERROR", res) + else return res end + end + function love.errorhandler(msg) + local ret = orig(msg) + orig_wheelmoved = nil + orig_textinput = nil + consoleOpen = false + inputText = "" + love.keyboard.setKeyRepeat(gameKeyRepeat) + love.keyboard.setTextInput(gameTextInput) + local justCrashed = true - local present = love.graphics.present - function love.graphics.present() - local r, g, b, a = love.graphics.getColor() - if justCrashed then - firstConsoleRender = love.timer.getTime() - justCrashed = false - end - safeCall(global.doConsoleRender) - love.graphics.setColor(r,g,b,a) - present() - end + local present = love.graphics.present + function love.graphics.present() + local r, g, b, a = love.graphics.getColor() + if justCrashed then + firstConsoleRender = love.timer.getTime() + justCrashed = false + end + safeCall(global.doConsoleRender) + love.graphics.setColor(r,g,b,a) + present() + end - return function() - love.event.pump() + return function() + love.event.pump() - local evts = {} + local evts = {} - for e, a, b, c in love.event.poll() do - if consoleOpen and e == "textinput" then - safeCall(textinput, a) - elseif consoleOpen and e == "wheelmoved" then - safeCall(wheelmoved, a, b) - elseif e == "keypressed" then - if safeCall(global.consoleHandleKey, a) then - table.insert(evts, {e,a,b,c}) - end - else - table.insert(evts, {e,a,b,c}) - end - end - for _,v in ipairs(evts) do -- Add back for the original handler - love.event.push(unpack(v)) - end - return ret() - end - end + for e, a, b, c in love.event.poll() do + if consoleOpen and e == "textinput" then + safeCall(textinput, a) + elseif consoleOpen and e == "wheelmoved" then + safeCall(wheelmoved, a, b) + elseif e == "keypressed" then + if safeCall(global.consoleHandleKey, a) then + table.insert(evts, {e,a,b,c}) + end + else + table.insert(evts, {e,a,b,c}) + end + end + for _,v in ipairs(evts) do -- Add back for the original handler + love.event.push(unpack(v)) + end + return ret() + end + end end function global.doConsoleRender() @@ -604,7 +630,9 @@ function global.doConsoleRender() } logOffset = 0 gameKeyRepeat = love.keyboard.hasKeyRepeat() + gameTextInput = love.keyboard.hasTextInput() love.keyboard.setKeyRepeat(true) + love.keyboard.setTextInput(true) end if not consoleOpen and not showNewLogs then return @@ -616,9 +644,10 @@ function global.doConsoleRender() local bottom = height - padding * 2 local now = love.timer.getTime() if firstConsoleRender == nil then - if config.getValue("hyjackErrorHandler") then hyjackErrorHandler() end + if config.getValue("hyjackErrorHandler") then hyjackErrorHandler() end + hookStuffs() firstConsoleRender = now - logger.logCmd("Press [/] to toggle console and press [shift] + [/] to toggle new log previews") + logger.log("Press [/] to toggle console and press [shift] + [/] to toggle new log previews") end -- Input Box love.graphics.setColor(0, 0, 0, .5) @@ -650,7 +679,7 @@ function global.doConsoleRender() if not consoleOpen and age > showTime + fadeTime then break end - if not logger.levelMeta[v.level].shouldShow and not v.command then + if not logger.levelMeta[v.level].shouldShow and not v.command then goto finishrender end if not v.command and config.getValue("onlyCommands") then @@ -719,7 +748,7 @@ local function handleLogsChange(added) end logger.handleLogsChange = handleLogsChange -config.configDefinition.showNewLogs.onUpdate = function(v) +config.configDefinition.showNewLogs.onUpdate = function(v) showNewLogs = v end diff --git a/DebugPlus/core.lua b/DebugPlus/debugplus/core.lua similarity index 97% rename from DebugPlus/core.lua rename to DebugPlus/debugplus/core.lua index ba1c1e5..06279a9 100644 --- a/DebugPlus/core.lua +++ b/DebugPlus/debugplus/core.lua @@ -146,7 +146,7 @@ function global.handleKeys(controller, key, dt) _card.shattered = true end _card:remove() - if _card.playing_card then + if _card.playing_card and G.jokers then for j = 1, #G.jokers.cards do eval_card(G.jokers.cards[j], { cardarea = G.jokers, @@ -345,7 +345,7 @@ function global.handleKeys(controller, key, dt) end if key == "1" or key == "2" then -- Reload any tooltips when unlocking/discovering stuff - if _element.stop_hover and _element.hover then + if _element and _element.stop_hover and _element.hover then _element:stop_hover() _element:hover() end @@ -417,11 +417,16 @@ function global.togglePerfUI() end end -function global.profileMessage() +function global.toggleProfiler() if G.prof then - log("Enabled performance profiler. Press 'v' again to disable it.") + G.prof.stop() + logger.handleLog({1, 0, 1}, "DEBUG", G.prof.report()) + G.prof = nil + log("Performance profiler stopped") else - log("Disabled performance profiler. Check console for results.") + G.prof = require "debugplus.prof" + G.prof.start() + log("Enabled performance profiler. Press 'v' again to disable it.") end end diff --git a/DebugPlus/logger.lua b/DebugPlus/debugplus/logger.lua similarity index 73% rename from DebugPlus/logger.lua rename to DebugPlus/debugplus/logger.lua index 9af9493..a9057b7 100644 --- a/DebugPlus/logger.lua +++ b/DebugPlus/debugplus/logger.lua @@ -1,6 +1,7 @@ local global = {} local logs = nil local old_print = print +local safeMode = false local util = require("debugplus.util") local levelMeta = { DEBUG = { @@ -36,21 +37,25 @@ local SMODSLevelMeta = { } function global.handleLogAdvanced(data, ...) - local stringifyPrint = require("debugplus.config").getValue("stringifyPrint") - if not stringifyPrint then - old_print(...) - end + local succ, config = pcall(require, "debugplus.config") + local safe = safeMode or not succ + local stringifyPrint = safe or config.getValue("stringifyPrint") + if not stringifyPrint then + old_print(...) + end local _str = "" - local stringify = tostring - if require("debugplus.config").getValue("processTables") then - stringify = util.stringifyTable - end - for _, v in ipairs({...}) do + local stringify = tostring + if safe or config.getValue("processTables") then + stringify = util.stringifyTable + end + local args = util.pack(...) + for i = 1, args.n do + local v = args[i] _str = _str .. stringify(v) .. " " end - if stringifyPrint then - old_print(_str) - end + if stringifyPrint then + old_print(_str) + end local meta = { str = _str, time = love.timer.getTime(), @@ -76,10 +81,6 @@ function global.handleLogAdvanced(data, ...) elseif _str:match("^ERROR LOADING GAME: Card area '[%w%d_-]+' not instantiated before load") then -- Error loading areas meta.level = "ERROR" meta.colour = levelMeta.ERROR.colour - elseif _str:match("^\n [+-]+ \n | #") and debug.getinfo(3).short_src == "engine/controller.lua" then -- Profiler results table. Extra check cause I don't trust this pattern to not have false positives - meta.level = "DEBUG" - meta.colour = levelMeta.DEBUG.colour - meta.command = true end end end @@ -127,31 +128,19 @@ function global.handleLog(colour, level, ...) }, ...) end -function global.log(...) - global.handleLogAdvanced({ - colour = {.65, .36, 1}, - level = "INFO", - }, "[DebugPlus]", ...) -end - -function global.logCmd(...) - global.handleLog({.65, .36, 1}, "INFO", "[DebugPlus]", ...) -end - - -function global.errorLog(...) - global.handleLogAdvanced({ - colour = {1, 0, 0}, - level = "ERROR", - }, "[DebugPlus]", ...) -end - function global.registerLogHandler() if logs then return end logs = {} global.logs = logs + local succ, res = pcall(require, "debugplus.config") + + if not succ then + safeMode = true + print("DebugPlus could not load config!!! Not hooking logging") + error(res) + end print = function(...) global.handleLogAdvanced({ colour = {0, 1, 1}, @@ -164,21 +153,45 @@ end function global.handleLogsChange() -- Placeholder. Overwritten in console.lua end +function global.log(...) + global.handleLog({.65, .36, 1}, "INFO", "[DebugPlus]", ...) +end --- config.configDefinition.logLevel.onUpdate = function(v) --- for k, v in pairs(levelMeta) do --- v.shouldShow = false --- end - --- levelMeta.ERROR.shouldShow = true --- if v == "ERROR" then return end --- levelMeta.WARN.shouldShow = true --- if v == "WARN" then return end --- levelMeta.INFO.shouldShow = true --- if v == "INFO" then return end --- levelMeta.DEBUG.shouldShow = true --- end +function global.error(...) + global.handleLogAdvanced({ + colour = levelMeta.ERROR.colour, + level = "ERROR", + }, "[DebugPlus]", ...) +end --- config.configDefinition.logLevel.onUpdate(config.getValue("logLevel")) +function global.warn(...) + global.handleLogAdvanced({ + colour = levelMeta.WARN.colour, + level = "WARN", + }, "[DebugPlus]", ...) +end + +function global.info(...) + global.handleLogAdvanced({ + colour = levelMeta.INFO.colour, + level = "INFO", + }, "[DebugPlus]", ...) +end + +function global.debug(...) + global.handleLogAdvanced({ + colour = levelMeta.DEBUG.colour, + level = "DEBUG", + }, "[DebugPlus]", ...) +end + +function global.createLogFn(name, level) + return function(...) + global.handleLogAdvanced({ + colour = levelMeta[level].colour, + level = level, + }, "[" .. name .. "]", ...) + end +end return global diff --git a/DebugPlus/debugplus/prof.lua b/DebugPlus/debugplus/prof.lua new file mode 100644 index 0000000..87c3a03 --- /dev/null +++ b/DebugPlus/debugplus/prof.lua @@ -0,0 +1,142 @@ +-- Modified from https://gist.github.com/cigumo/88d7f84ca364015eaf577590db7e6577 + +local logger = require "debugplus.logger" + +local profSucc, profile = pcall(require, "jit.profile") +if not profSucc then + logger.debug("jit.profile unavalible. Falling back to vanilla profiler.\n", profile) + return require "engine/profile" +end +local vmdefSucc, vmdef = pcall(require, "jit.vmdef") +if not vmdefSucc then + logger.debug("jit.vmdef unavailable. Profiler will not be able to resolve builtins.\n", vmdef) + vmdef = nil +end + +local format = string.format +local sort = table.sort +local math = math +local floor = math.floor +local vmstates = { + N = "Native", + I = "Interpreted", + C = "C Code", + G = "Garbage Collector", + J = "JIT Compiler", +} + +local prof = {} + +prof.running = false +prof.flag_l2_shown = true +prof.flag_l2_levels = 3 +prof.profiler_fmt = "Fi10" +prof.min_percent = 1 +prof.l1_stack_fmt = "F" +prof.l2_stack_fmt = "l <" +prof.counts = {} -- double index +prof.top_str = nil + +local total_samples = 0 + +------------------------------------------------------------ +local function prof_cb(thread,samples,vmmode) + local c = prof.counts + total_samples = total_samples + samples + local l1_stack = profile.dumpstack(thread, prof.l1_stack_fmt, 1) + local l2_stack = profile.dumpstack(thread, prof.l2_stack_fmt, 5) + + if vmdef then + l1_stack = l1_stack:gsub("%[builtin#(%d+)%]", function(x) return vmdef.ffnames[tonumber(x)] end) + l2_stack = l2_stack:gsub("%[builtin#(%d+)%]", function(x) return vmdef.ffnames[tonumber(x)] end) + end + + if not c[l1_stack] then + local vl1 = {key=l1_stack, count=0, callers={}, vmmodes = {}} -- double index + c[l1_stack] = vl1 + c[#c+1] = vl1 + end + c[l1_stack].count = c[l1_stack].count + samples + c[l1_stack].vmmodes[vmmode] = (c[l1_stack].vmmodes[vmmode] or 0) + 1 + + if not c[l1_stack].callers[l2_stack] then + local vl2 = {key=l2_stack, count=0, vmmodes = {}} + local c2 = c[l1_stack].callers + c2[l2_stack] = vl2 + c2[#c2+1] = vl2 + end + c[l1_stack].callers[l2_stack].count = c[l1_stack].callers[l2_stack].count + samples + c[l1_stack].callers[l2_stack].vmmodes[vmmode] = (c[l1_stack].callers[l2_stack].vmmodes[vmmode] or 0) + 1 +end + +local function format_vmmodes(vmmodes) + local ret = "" + for k,v in pairs(vmmodes) do + if ret ~= "" then + ret = ret .. ", " + end + ret = ret .. (vmstates[k] or k) .. ": " .. tostring(v) + end + return ret +end + +function prof.format_result() + local c = prof.counts + local out = {} + + -- sort l1 + sort(c, function(a,b) return a.count > b.count end) + + -- sort l2 + for i,v in ipairs(c) do + sort(v.callers, function(a,b) return a.count > b.count end) + end + + -- format + for i=1,#c do + local vl1 = c[i] + local pct = floor(vl1.count * 100 / total_samples + 0.5) + if pct < prof.min_percent then break end + table.insert(out, format("%2d%% %s (%s)", pct, vl1.key, format_vmmodes(vl1.vmmodes))) + local c2 = vl1.callers + + if prof.flag_l2_shown then + for j=1,#c2 do + if j > prof.flag_l2_levels then break end + local vl2 = c2[j] + table.insert(out, format(" %4d %s (%s)", vl2.count, vl2.key, format_vmmodes(vl2.vmmodes))) + end + end + end + + return table.concat(out,'\n') +end + +prof.report = prof.format_result + +function prof.start() + if prof.running then + logger.error("Profiler already running?") + return + end + + total_samples = 0 + prof.counts = {} + profile.start(prof.profiler_fmt, prof_cb) + prof.running = true +end + +function prof.stop() + if not prof.running then + logger.error("Profiler not running?") + return + end + profile.stop() + prof.running = false + prof.flag_dirty = true +end + + +------------------------------------------------------------ +return prof + diff --git a/DebugPlus/smods.lua b/DebugPlus/debugplus/smods.lua similarity index 99% rename from DebugPlus/smods.lua rename to DebugPlus/debugplus/smods.lua index 757143b..bf7cf67 100644 --- a/DebugPlus/smods.lua +++ b/DebugPlus/debugplus/smods.lua @@ -22,3 +22,4 @@ if SMODS.current_mod then function SMODS.current_mod.load_mod_config() end function SMODS.current_mod.save_mod_config() end end + diff --git a/DebugPlus/util.lua b/DebugPlus/debugplus/util.lua similarity index 87% rename from DebugPlus/util.lua rename to DebugPlus/debugplus/util.lua index ee7a9e6..234f1ec 100644 --- a/DebugPlus/util.lua +++ b/DebugPlus/debugplus/util.lua @@ -22,7 +22,7 @@ function global.stringifyTable(tab, depth, num, dec, indent) return tostring(tab) end if (getmetatable(tab) or {}).__tostring then -- For tables with custom tostring values (such as a talisman number) - return tostring(tab) .. "hi" + return tostring(tab) end local res = "Table:\n" local count = 0 @@ -55,7 +55,7 @@ end if isMac then function global.isCtrlDown() - return love.keyboard.isDown('lgui') or love.keyboard.isDown('rgui') + return love.keyboard.isDown('lgui') or love.keyboard.isDown('rgui') or love.keyboard.isDown('lctrl') or love.keyboard.isDown('rctrl') end else function global.isCtrlDown() @@ -67,4 +67,8 @@ function global.trim(string) return string:match("^%s*(.-)%s*$") end +function global.pack(...) -- TODO: Might be nice to make a version of ipairs that uses this + return { n = select("#", ...), ... } +end + return global diff --git a/DebugPlus/watcher.lua b/DebugPlus/debugplus/watcher.lua similarity index 99% rename from DebugPlus/watcher.lua rename to DebugPlus/debugplus/watcher.lua index bdd9ed9..cb3756f 100644 --- a/DebugPlus/watcher.lua +++ b/DebugPlus/debugplus/watcher.lua @@ -232,7 +232,7 @@ local types = { } local function loadFile() - local info = love.filesystem.getInfo(file) + local info = love.filesystem.getInfo(file) or {} local showReloaded = modtime ~= nil if info.modtime == modtime then return @@ -257,6 +257,7 @@ local function makeEvent() no_delete = true, trigger = "after", delay = .5, + timer = "UPTIME", func = function() if not running then return true diff --git a/DebugPlus/docs/changelog.md b/DebugPlus/docs/changelog.md index e883bad..d8f9044 100644 --- a/DebugPlus/docs/changelog.md +++ b/DebugPlus/docs/changelog.md @@ -1,3 +1,24 @@ +# DebugPlus 1.4.0 + +## Features +- Added a new profiler for use with newer luajit versions (see https://canary.discord.com/channels/1116389027176787968/1336473631483760791 [in [the balatro discord](https://discord.gg/balatro)]). +- Eval now works properly for multiple returns. +- Adjust console hooks to play nicer with some other mods. + +## Fixes +- Tables with custom tostring methods had `hi` appended to them. +- Rare crash with watcher. +- Printing a `nil` would not display itself or any args past it. +- Crash when registering a mod with the api. + +# DebugPlus 1.3.1 + +## Fixes +- Fix a crash when the config loader logged. +- Fixed a rare crash with the 1 and 2 keybinds. +- Fixed the console not receiving text input on some platforms. +- Fixed MacOS being unable to use some keybinds (by allowing ctrl or cmd to be used). + # DebugPlus 1.3.0 ## Breaking Changes diff --git a/DebugPlus/lovely/debug-enhancements.toml b/DebugPlus/lovely/debug-enhancements.toml index 98e6d88..e00f5d9 100644 --- a/DebugPlus/lovely/debug-enhancements.toml +++ b/DebugPlus/lovely/debug-enhancements.toml @@ -156,10 +156,14 @@ end [[patches]] [patches.pattern] target = "engine/controller.lua" -pattern = '''print(G.prof.report()); G.prof = nil end''' -position = "after" +pattern = ''' +if not G.prof then G.prof = require "engine/profile"; G.prof.start() +else G.prof:stop(); + print(G.prof.report()); G.prof = nil end +''' +position = "at" payload = ''' -debugplus.profileMessage() +debugplus.toggleProfiler() ''' match_indent = true diff --git a/DebugPlus/lovely/modules.toml b/DebugPlus/lovely/modules.toml index 5901321..e881a27 100644 --- a/DebugPlus/lovely/modules.toml +++ b/DebugPlus/lovely/modules.toml @@ -6,42 +6,49 @@ priority = 0 # Modules [[patches]] [patches.module] -source = "util.lua" +source = "debugplus/util.lua" before = "main.lua" name = "debugplus.util" [[patches]] [patches.module] -source = "config.lua" +source = "debugplus/config.lua" before = "main.lua" name = "debugplus.config" [[patches]] [patches.module] -source = "watcher.lua" +source = "debugplus/watcher.lua" before = "main.lua" name = "debugplus.watcher" [[patches]] [patches.module] -source = "logger.lua" +source = "debugplus/logger.lua" before = "main.lua" name = "debugplus.logger" [[patches]] [patches.module] -source = "console.lua" +source = "debugplus/console.lua" before = "main.lua" name = "debugplus.console" [[patches]] [patches.module] -source = "api.lua" +source = "debugplus/api.lua" before = "main.lua" name = "debugplus-api" [[patches]] [patches.module] -source = "core.lua" +source = "debugplus/core.lua" before = "engine/controller.lua" name = "debugplus.core" + +[[patches]] +[patches.module] +source = "debugplus/prof.lua" +before = "engine/controller.lua" +name = "debugplus.prof" + diff --git a/DebugPlus/smods.json b/DebugPlus/smods.json index f4d0f17..de4fcd8 100644 --- a/DebugPlus/smods.json +++ b/DebugPlus/smods.json @@ -5,6 +5,6 @@ "author": ["WilsontheWolf"], "description": "Better Debug Tools for Balatro ", "prefix": "DebugPlus", - "main_file": "smods.lua", - "version": "1.3.0" + "main_file": "debugplus/smods.lua", + "version": "1.4.1" } diff --git a/DebugPlus/version b/DebugPlus/version new file mode 100644 index 0000000..347f583 --- /dev/null +++ b/DebugPlus/version @@ -0,0 +1 @@ +1.4.1 diff --git a/HandyBalatro/README.md b/HandyBalatro/README.md deleted file mode 100644 index c6e4b89..0000000 --- a/HandyBalatro/README.md +++ /dev/null @@ -1,41 +0,0 @@ -# Handy - Balatro QoL controls mod - -It's a small [Lovely](https://github.com/ethangreen-dev/lovely-injector) mod that adds additional controls to Balatro. - -## New Controls -- `Shift + LMB` on card to: - - Buy joker, card, booster pack, voucher or consumable in shop - - Select joker or card in booster pack - - Sell joker in joker slots - - Sell consumable in consumable slots - -https://github.com/user-attachments/assets/6406309f-f629-41c5-851d-90f99cb35cfa - -- `Ctrl + LMB` on card to: - - Use consumable *(if possible)* in shop, booster pack or consumable slots - -https://github.com/user-attachments/assets/7ed89be3-a362-42c0-ac86-ccbc8fded62a - -- `LMB` to select a card and then `Left/Right arrow` to: - - Move highlight in direction between jokers or consumables - - Hold `Shift` to move card instead - - Hold `Ctrl` to move to the first/last card - -https://github.com/user-attachments/assets/2d40e4a6-9ea1-4ffa-a7fd-e0e8b9856b2b - -- Hold `LMB` and move to: - - Select cards in hand - -https://github.com/user-attachments/assets/9ec9dfba-a7df-4ecf-a3e0-67dc802c310d - -- `Enter` to: - - Skip "Cash Out" stage - -https://github.com/user-attachments/assets/85082445-052a-4f96-aaf0-51e1af1fdaf3 - -## Dangerous controls -- Hold `Shift + MMB (Mouse 3, Wheel Button)` and move to: - - Mass-sell jokers or consumables - -https://github.com/user-attachments/assets/4c958f09-74c3-4c11-88ab-48989c41dfde - diff --git a/HandyBalatro/config_ui.lua b/HandyBalatro/config_ui.lua index d4b5bbc..53dc9a2 100644 --- a/HandyBalatro/config_ui.lua +++ b/HandyBalatro/config_ui.lua @@ -1,7 +1,14 @@ Handy.UI.PARTS = { + format_module_keys = function(module, only_first) + local result = "[" .. module.key_1 .. "]" + if only_first or not module.key_2 or module.key_2 == "None" then + return result + end + return result .. " or [" .. module.key_2 .. "]" + end, create_module_checkbox = function(module, label, text_prefix, text_lines, skip_keybinds) local desc_lines = { - { n = G.UIT.R, config = { minw = 5.25 } }, + { n = G.UIT.R, config = { minw = 5 } }, } if skip_keybinds then @@ -20,82 +27,23 @@ Handy.UI.PARTS = { }, }) else - local key_desc = module.key_2 - and { - { - n = G.UIT.T, - config = { - text = text_prefix .. " [", - scale = 0.3, - colour = G.C.TEXT_LIGHT, - }, - }, - { - n = G.UIT.T, - config = { - ref_table = module, - ref_value = "key_1", - scale = 0.3, - colour = G.C.TEXT_LIGHT, - }, - }, - { - n = G.UIT.T, - config = { - text = "] or [", - scale = 0.3, - colour = G.C.TEXT_LIGHT, - }, - }, - { - n = G.UIT.T, - config = { - ref_table = module, - ref_value = "key_2", - scale = 0.3, - colour = G.C.TEXT_LIGHT, - }, - }, - { - n = G.UIT.T, - config = { - text = "] " .. text_lines[1], - scale = 0.3, - colour = G.C.TEXT_LIGHT, - }, - }, - } - or { - { - n = G.UIT.T, - config = { - text = text_prefix .. " [", - scale = 0.3, - colour = G.C.TEXT_LIGHT, - }, - }, - { - n = G.UIT.T, - config = { - ref_table = module, - ref_value = "key_1", - scale = 0.3, - colour = G.C.TEXT_LIGHT, - }, - }, - { - n = G.UIT.T, - config = { - text = "] " .. text_lines[1], - scale = 0.3, - colour = G.C.TEXT_LIGHT, - }, - }, - } table.insert(desc_lines, { n = G.UIT.R, config = { padding = 0.025 }, - nodes = key_desc, + nodes = { + { + n = G.UIT.T, + config = { + text = text_prefix + .. " " + .. Handy.UI.PARTS.format_module_keys(module) + .. " " + .. text_lines[1], + scale = 0.3, + colour = G.C.TEXT_LIGHT, + }, + }, + }, }) end @@ -178,19 +126,19 @@ Handy.UI.PARTS = { create_module_section = function(label) return { n = G.UIT.R, - config = { align = "cm", padding = 0.1 }, + config = { align = "cm", padding = 0.075 }, nodes = { { n = G.UIT.T, - config = { text = label, colour = G.C.WHITE, scale = 0.4, align = "cm" }, + config = { text = label, colour = G.C.WHITE, scale = 0.35, align = "cm" }, }, }, } end, - create_module_keybind = function(module, label, plus, dangerous) + create_module_keybind = function(module, label, dangerous) return { n = G.UIT.R, - config = { align = "cm", padding = 0.05 }, + config = { align = "cm", padding = 0.01 }, nodes = { { n = G.UIT.C, @@ -198,7 +146,7 @@ Handy.UI.PARTS = { nodes = { { n = G.UIT.T, - config = { text = label, colour = G.C.WHITE, scale = 0.35 }, + config = { text = label, colour = G.C.WHITE, scale = 0.3 }, }, }, }, @@ -210,9 +158,9 @@ Handy.UI.PARTS = { label = { module.key_1 or "None" }, col = true, colour = dangerous and G.C.MULT or G.C.CHIPS, - scale = 0.35, + scale = 0.3, minw = 2.75, - minh = 0.45, + minh = 0.4, ref_table = { module = module, key = "key_1", @@ -225,7 +173,7 @@ Handy.UI.PARTS = { nodes = { { n = G.UIT.T, - config = { text = plus and "+" or "or", colour = G.C.WHITE, scale = 0.3 }, + config = { text = "or", colour = G.C.WHITE, scale = 0.3 }, }, }, }, @@ -233,9 +181,9 @@ Handy.UI.PARTS = { label = { module.key_2 or "None" }, col = true, colour = dangerous and G.C.MULT or G.C.CHIPS, - scale = 0.35, + scale = 0.3, minw = 2.75, - minh = 0.45, + minh = 0.4, ref_table = { module = module, key = "key_2", @@ -247,36 +195,148 @@ Handy.UI.PARTS = { end, } +-- + Handy.UI.get_config_tab_overall = function() return { { n = G.UIT.R, config = { padding = 0.05, align = "cm" }, nodes = { - create_option_cycle({ - minw = 3, - label = "Notifications level", - scale = 0.8, - options = { - "None", - "Dangerous", - "Game state", - "All", + Handy.current_mod and { + n = G.UIT.C, + config = { + align = "cm", + padding = 0.1, }, - opt_callback = "handy_change_notifications_level", - current_option = Handy.config.current.notifications_level, - }), + nodes = { + { + n = G.UIT.R, + config = { + padding = 0.15, + }, + nodes = {}, + }, + { + n = G.UIT.R, + config = { align = "cm" }, + nodes = { + { + n = G.UIT.C, + config = { align = "cm" }, + nodes = { + { + n = G.UIT.R, + config = { minw = 2.5 }, + nodes = { + { + n = G.UIT.T, + config = { + text = "Hide mod button", + scale = 0.4, + colour = G.C.WHITE, + }, + }, + }, + }, + { + n = G.UIT.R, + config = { minw = 2.5 }, + nodes = { + { + n = G.UIT.T, + config = { + text = "in options menu", + scale = 0.4, + colour = G.C.WHITE, + }, + }, + }, + }, + }, + }, + { + n = G.UIT.C, + config = { align = "cm" }, + nodes = { + create_toggle({ + callback = function(b) + return G.FUNCS.handy_toggle_menu_button(b) + end, + label_scale = 0.4, + label = "", + ref_table = Handy.cc, + ref_value = "hide_in_menu", + w = 0, + }), + }, + }, + }, + }, + }, + } or nil, + { + n = G.UIT.C, + nodes = { + create_option_cycle({ + w = 6, + label = "Info popups level", + scale = 0.8, + options = { + "None", + "Dangerous only", + "Features-related", + "All", + }, + opt_callback = "handy_change_notifications_level", + current_option = Handy.cc.notifications_level, + }), + }, + }, + { + n = G.UIT.C, + nodes = { + create_option_cycle({ + w = 6, + label = "Keybinds trigger mode", + scale = 0.8, + options = { + "On key press", + "On key release", + }, + opt_callback = "handy_change_keybinds_trigger_mode", + current_option = Handy.cc.keybinds_trigger_mode, + }), + }, + }, }, }, { n = G.UIT.R, config = { padding = 0.05 }, nodes = {} }, + Handy.UI.PARTS.create_module_checkbox( + Handy.cc.handy, + { "HandyBalatro v" .. Handy.version, "by SleepyG11" }, + "Uncheck", + { + "to disable ALL mod features", + "(no restart required)", + }, + true + ), + { n = G.UIT.R, config = { minh = 0.25 } }, { n = G.UIT.R, nodes = { { n = G.UIT.C, nodes = { + Handy.UI.PARTS.create_module_checkbox(Handy.cc.regular_keybinds, "Regular keybinds", "Use", { + "keybinds for", + "common game actions", + "(Play, Discard, Reroll, Skip blind, etc.)", + }, true), + { n = G.UIT.R, config = { minh = 0.25 } }, Handy.UI.PARTS.create_module_checkbox( - Handy.config.current.insta_highlight, + Handy.cc.insta_highlight, "Quick Highlight", "Hold [Left Mouse]", { @@ -286,43 +346,131 @@ Handy.UI.get_config_tab_overall = function() true ), { n = G.UIT.R, config = { minh = 0.25 } }, - Handy.UI.PARTS.create_module_checkbox( - Handy.config.current.insta_buy_or_sell, - "Quick Buy/Sell", - "Hold", - { - "to", - "buy or sell card on Left-Click", - "instead of selection", - } - ), - { n = G.UIT.R, config = { minh = 0.25 } }, - Handy.UI.PARTS.create_module_checkbox(Handy.config.current.insta_use, "Quick use", "Hold", { + Handy.UI.PARTS.create_module_checkbox(Handy.cc.show_deck_preview, "Deck preview", "Hold", { "to", - "use (if possible) card on Left-Click", - "instead of selection", - "(overrides Quick Buy/Sell)", + "show deck preview", + }), + }, + }, + { + n = G.UIT.C, + config = { minw = 4 }, + nodes = { + Handy.UI.PARTS.create_module_checkbox(Handy.cc.deselect_hand, "Deselect hand", "Press", { + "to", + "deselect hand", + "(disable to use vanilla)", }), { n = G.UIT.R, config = { minh = 0.25 } }, Handy.UI.PARTS.create_module_checkbox( - Handy.config.current.move_highlight, - "Move highlight", - "Press", + Handy.cc.insta_cash_out, + "Quick Cash Out", + "Press/hold", { - "[" - .. tostring(Handy.config.current.move_highlight.dx.one_left.key_1) - .. "] or [" - .. tostring(Handy.config.current.move_highlight.dx.one_right.key_1) - .. "]", - "to move highlight in card area.", - "Hold [" - .. tostring(Handy.config.current.move_highlight.swap.key_1) - .. "] to move card instead.", - "Hold [" - .. tostring(Handy.config.current.move_highlight.to_end.key_1) - .. "] to move to first/last card", + "to", + "skip Cash Out stage", + } + ), + { n = G.UIT.R, config = { minh = 0.25 } }, + Handy.UI.PARTS.create_module_checkbox( + Handy.cc.insta_booster_skip, + { "Quick skip", "Booster Packs" }, + "Press/hold", + { + "to", + "skip booster pack", + } + ), + }, + }, + }, + }, + { n = G.UIT.R, config = { minh = 0.4 } }, + { + n = G.UIT.R, + config = { padding = 0.1, align = "cm" }, + nodes = { + { + n = G.UIT.T, + config = { + text = 'Each control can be assigned to mouse button, mouse wheel or keyboard key in "Keybinds" tabs', + scale = 0.3, + colour = { 1, 1, 1, 0.6 }, + align = "cm", + }, + }, + }, + }, + -- { n = G.UIT.R, config = { minh = 0.25 } }, + } +end + +Handy.UI.get_config_tab_quick = function() + return { + { + n = G.UIT.R, + config = { padding = 0.05, align = "cm" }, + nodes = { + { + n = G.UIT.C, + nodes = { + create_option_cycle({ + w = 6, + label = "Buy/Sell/Use mode", + scale = 0.8, + options = { + "Hold + Card click", + "Card hover + Press", }, - true + opt_callback = "handy_change_insta_actions_trigger_mode", + current_option = Handy.cc.insta_actions_trigger_mode, + }), + }, + }, + }, + }, + { n = G.UIT.R, config = { padding = 0.05 }, nodes = {} }, + Handy.UI.PARTS.create_module_checkbox(Handy.cc.move_highlight, "Move highlight", "Press", { + "[" .. tostring(Handy.cc.move_highlight.dx.one_left.key_1) .. "] or [" .. tostring( + Handy.cc.move_highlight.dx.one_right.key_1 + ) .. "]", + "to move highlight in card area.", + "Hold [" .. tostring(Handy.cc.move_highlight.swap.key_1) .. "] to move card instead.", + "Hold [" .. tostring(Handy.cc.move_highlight.to_end.key_1) .. "] to move to first/last card", + }, true), + { n = G.UIT.R, config = { minh = 0.25 } }, + { + n = G.UIT.R, + nodes = { + { + n = G.UIT.C, + nodes = { + Handy.UI.PARTS.create_module_checkbox(Handy.cc.insta_buy_or_sell, "Quick Buy/Sell", "Use", { + "to", + "buy or sell card", + }), + { n = G.UIT.R, config = { minh = 0.25 } }, + Handy.UI.PARTS.create_module_checkbox(Handy.cc.insta_buy_n_sell, "Quick Buy'n'Sell", "Use", { + "to", + "buy card and sell", + "immediately after", + }), + { n = G.UIT.R, config = { minh = 0.25 } }, + Handy.UI.PARTS.create_module_checkbox(Handy.cc.insta_use, "Quick use", "Use", { + "to", + "use card if possible", + "(overrides Quick Buy/Sell)", + }), + { n = G.UIT.R, config = { minh = 0.3 } }, + Handy.UI.PARTS.create_module_checkbox( + Handy.cc.cryptid_code_use_last_interaction, + { "Cryptid: use", "previous input" }, + "Use", + { + "to", + "use code card if possible with", + "previously inputted value", + } ), }, }, @@ -331,63 +479,47 @@ Handy.UI.get_config_tab_overall = function() config = { minw = 4 }, nodes = { Handy.UI.PARTS.create_module_checkbox( - Handy.config.current.insta_cash_out, - "Quick Cash Out", - "Press", - { - "to", - "speedup animation and", - "skip Cash Out stage", - } - ), - { n = G.UIT.R, config = { minh = 0.25 } }, - Handy.UI.PARTS.create_module_checkbox( - Handy.config.current.insta_booster_skip, - { "Quick skip", "Booster Packs" }, - "Hold", - { - "to", - "skip booster pack", - } - ), - { n = G.UIT.R, config = { minh = 0.25 } }, - Handy.UI.PARTS.create_module_checkbox( - Handy.config.current.speed_multiplier, - "Speed Multiplier", + Handy.cc.nopeus_interaction, + { "Nopeus:", "fast-forward" }, "Hold", { "and", - "[Wheel Up] to multiply or", - "[Wheel Down] to divide game speed", + "[Wheel Up] to increase or", + "[Wheel Down] to decrease", + "fast-forward setting", } ), { n = G.UIT.R, config = { minh = 0.25 } }, Handy.UI.PARTS.create_module_checkbox( - Handy.config.current.shop_reroll, - "Shop Reroll", + Handy.cc.insta_highlight_entire_f_hand, + { "Highlight", "entire hand" }, "Press", { "to", - "reroll a shop", + "highlight entire hand", } ), { n = G.UIT.R, config = { minh = 0.25 } }, + Handy.UI.PARTS.create_module_checkbox(Handy.cc.speed_multiplier, "Speed Multiplier", "Hold", { + "and", + "[Wheel Up] to multiply or", + "[Wheel Down] to divide game speed", + }), + { n = G.UIT.R, config = { minh = 0.25 } }, Handy.UI.PARTS.create_module_checkbox( - Handy.config.current.play_and_discard, - "Play/Discard", + Handy.cc.not_just_yet_interaction, + { "NotJustYet:", "End round" }, "Press", { - "[" .. tostring(Handy.config.current.play_and_discard.play.key_1) .. "] to play a hand", - "or [" - .. tostring(Handy.config.current.play_and_discard.discard.key_1) - .. "] to discard", - }, - true + "to", + "end round", + } ), }, }, }, }, + -- { n = G.UIT.R, config = { minh = 0.25 } }, } end @@ -400,7 +532,7 @@ Handy.UI.get_config_tab_interactions = function() n = G.UIT.C, nodes = { Handy.UI.PARTS.create_module_checkbox( - Handy.config.current.nopeus_interaction, + Handy.cc.nopeus_interaction, { "Nopeus:", "fast-forward" }, "Hold", { @@ -415,7 +547,7 @@ Handy.UI.get_config_tab_interactions = function() config = { minh = 0.25 }, }, Handy.UI.PARTS.create_module_checkbox( - Handy.config.current.not_just_yet_interaction, + Handy.cc.not_just_yet_interaction, { "NotJustYet:", "End round" }, "Press", { @@ -442,12 +574,13 @@ Handy.UI.get_config_tab_dangerous = function() -- { n = G.UIT.R, config = { padding = 0.05 }, nodes = {} }, { n = G.UIT.R, + config = { padding = 0.05, align = "cm" }, nodes = { { n = G.UIT.C, nodes = { Handy.UI.PARTS.create_module_checkbox( - Handy.config.current.dangerous_actions, + Handy.cc.dangerous_actions, { "Dangerous", "actions" }, "Enable", { @@ -457,20 +590,32 @@ Handy.UI.get_config_tab_dangerous = function() }, true ), - { n = G.UIT.R, config = { minh = 0.5 } }, + }, + }, + }, + }, + { n = G.UIT.R, config = { minh = 0.5 } }, + { + n = G.UIT.R, + nodes = { + { + n = G.UIT.C, + nodes = { Handy.UI.PARTS.create_module_checkbox( - Handy.config.current.dangerous_actions.immediate_buy_and_sell, + Handy.cc.dangerous_actions.immediate_buy_and_sell, "Instant Sell", "Hold", { - "to", - "sell card on hover", - "very fast", - } + Handy.UI.PARTS.format_module_keys(Handy.cc.dangerous_actions.immediate_buy_and_sell) + .. ",", + "hold " .. Handy.UI.PARTS.format_module_keys(Handy.cc.insta_buy_or_sell) .. "", + "and hover card to sell it", + }, + true ), - { n = G.UIT.R, config = { minh = 0.1 } }, + { n = G.UIT.R, config = { minh = 0.275 } }, Handy.UI.PARTS.create_module_checkbox( - Handy.config.current.dangerous_actions.immediate_buy_and_sell.queue, + Handy.cc.dangerous_actions.immediate_buy_and_sell.queue, "Sell Queue", "Start", { @@ -479,9 +624,9 @@ Handy.UI.get_config_tab_dangerous = function() }, true ), - { n = G.UIT.R, config = { minh = 0.25 } }, + { n = G.UIT.R, config = { minh = 0.275 } }, Handy.UI.PARTS.create_module_checkbox( - Handy.config.current.dangerous_actions.nopeus_unsafe, + Handy.cc.dangerous_actions.nopeus_unsafe, { "Nopeus: Unsafe", "fast-forward" }, "Allow", { @@ -492,41 +637,119 @@ Handy.UI.get_config_tab_dangerous = function() ), }, }, + { + n = G.UIT.C, + config = { minw = 4 }, + nodes = { + Handy.UI.PARTS.create_module_checkbox( + Handy.cc.dangerous_actions.sell_all_same, + { "Sell all", "card copies" }, + "Hold", + { + Handy.UI.PARTS.format_module_keys(Handy.cc.dangerous_actions.immediate_buy_and_sell) + .. ",", + "hold " + .. Handy.UI.PARTS.format_module_keys(Handy.cc.dangerous_actions.sell_all_same) + .. ",", + "and click on card to sell", + "all of their copies", + }, + true + ), + { n = G.UIT.R, config = { minh = 0.1 } }, + Handy.UI.PARTS.create_module_checkbox( + Handy.cc.dangerous_actions.sell_all, + "Sell ALL", + "Hold", + { + "to", + "sell ALL cards in area instead", + } + ), + { n = G.UIT.R, config = { minh = 0.1 } }, + Handy.UI.PARTS.create_module_checkbox( + Handy.cc.dangerous_actions.card_remove, + { "REMOVE* cards", "or skip tags" }, + "Hold", + { + "to", + "REMOVE cards instead", + "of selling, works for skip tags", + } + ), + }, + }, }, }, + { n = G.UIT.R, config = { minh = 0.4 } }, + { + n = G.UIT.R, + config = { padding = 0.1, align = "cm" }, + nodes = { + { + n = G.UIT.T, + config = { + text = "*REMOVE card/tag - delete without any checks, effects, triggers or money refunds", + scale = 0.3, + colour = { 1, 1, 1, 0.6 }, + align = "cm", + }, + }, + }, + }, + -- { n = G.UIT.R, config = { minh = 0.25 } }, } end -Handy.UI.get_config_tab_keybinds = function() +Handy.UI.get_config_tab_regular_keybinds = function() return { - Handy.UI.PARTS.create_module_section("Quick Actions"), - Handy.UI.PARTS.create_module_keybind(Handy.config.current.insta_buy_or_sell, "Quick Buy/Sell"), - Handy.UI.PARTS.create_module_keybind(Handy.config.current.insta_use, "Quick Use"), - Handy.UI.PARTS.create_module_keybind(Handy.config.current.insta_cash_out, "Quick Cash Out"), - Handy.UI.PARTS.create_module_keybind(Handy.config.current.insta_booster_skip, "Quick skip Booster Packs"), - Handy.UI.PARTS.create_module_keybind(Handy.config.current.shop_reroll, "Shop reroll"), - Handy.UI.PARTS.create_module_keybind(Handy.config.current.play_and_discard.play, "Play hand"), - Handy.UI.PARTS.create_module_keybind(Handy.config.current.play_and_discard.discard, "Discard"), - Handy.UI.PARTS.create_module_keybind( - Handy.config.current.dangerous_actions.immediate_buy_and_sell, - "Instant Buy/Sell", - false, - true - ), - Handy.UI.PARTS.create_module_keybind(Handy.config.current.not_just_yet_interaction, "NotJustYet: End round"), + Handy.UI.PARTS.create_module_section("Round"), + Handy.UI.PARTS.create_module_keybind(Handy.cc.regular_keybinds.play, "Play hand"), + Handy.UI.PARTS.create_module_keybind(Handy.cc.regular_keybinds.discard, "Discard"), + Handy.UI.PARTS.create_module_keybind(Handy.cc.regular_keybinds.sort_by_rank, "Sort by rank"), + Handy.UI.PARTS.create_module_keybind(Handy.cc.regular_keybinds.sort_by_suit, "Sort by suit"), + Handy.UI.PARTS.create_module_keybind(Handy.cc.deselect_hand, "Deselect hand"), + Handy.UI.PARTS.create_module_keybind(Handy.cc.insta_cash_out, "Cash Out"), + Handy.UI.PARTS.create_module_keybind(Handy.cc.not_just_yet_interaction, "NotJustYet: End round"), + Handy.UI.PARTS.create_module_section("Shop and Blinds"), + Handy.UI.PARTS.create_module_keybind(Handy.cc.insta_booster_skip, "Skip Booster Pack"), + Handy.UI.PARTS.create_module_keybind(Handy.cc.regular_keybinds.reroll_shop, "Shop reroll"), + Handy.UI.PARTS.create_module_keybind(Handy.cc.regular_keybinds.leave_shop, "Leave shop"), + Handy.UI.PARTS.create_module_keybind(Handy.cc.regular_keybinds.skip_blind, "Skip blind"), + Handy.UI.PARTS.create_module_keybind(Handy.cc.regular_keybinds.select_blind, "Select blind"), + Handy.UI.PARTS.create_module_section("Menus"), + Handy.UI.PARTS.create_module_keybind(Handy.cc.regular_keybinds.run_info, "Run info: Poker hands"), + Handy.UI.PARTS.create_module_keybind(Handy.cc.regular_keybinds.run_info_blinds, "Run info: Blinds"), + Handy.UI.PARTS.create_module_keybind(Handy.cc.regular_keybinds.view_deck, "View deck"), + Handy.UI.PARTS.create_module_keybind(Handy.cc.show_deck_preview, "Deck preview"), } end Handy.UI.get_config_tab_keybinds_2 = function() return { - Handy.UI.PARTS.create_module_section("Game state"), - Handy.UI.PARTS.create_module_keybind(Handy.config.current.speed_multiplier, "Speed Multiplier"), - Handy.UI.PARTS.create_module_keybind(Handy.config.current.nopeus_interaction, "Nopeus: fast-forward"), - Handy.UI.PARTS.create_module_section("Move highlight"), - Handy.UI.PARTS.create_module_keybind(Handy.config.current.move_highlight.dx.one_left, "Move one left"), - Handy.UI.PARTS.create_module_keybind(Handy.config.current.move_highlight.dx.one_right, "Move one right"), - Handy.UI.PARTS.create_module_keybind(Handy.config.current.move_highlight.swap, "Move card"), - Handy.UI.PARTS.create_module_keybind(Handy.config.current.move_highlight.to_end, "Move to end"), + Handy.UI.PARTS.create_module_section("Quick actions"), + Handy.UI.PARTS.create_module_keybind(Handy.cc.insta_buy_or_sell, "Quick Buy/Sell"), + Handy.UI.PARTS.create_module_keybind(Handy.cc.insta_use, "Quick Use"), + Handy.UI.PARTS.create_module_keybind(Handy.cc.insta_buy_n_sell, "Quick Buy'n'Sell"), + Handy.UI.PARTS.create_module_keybind(Handy.cc.insta_highlight_entire_f_hand, "Highlight entire hand"), + Handy.UI.PARTS.create_module_keybind(Handy.cc.cryptid_code_use_last_interaction, "Cryptid: use previous input"), + Handy.UI.PARTS.create_module_section("Dangerous actions"), + Handy.UI.PARTS.create_module_keybind( + Handy.cc.dangerous_actions.immediate_buy_and_sell, + "Dangerous modifier", + true + ), + Handy.UI.PARTS.create_module_keybind(Handy.cc.dangerous_actions.sell_all_same, "Sell all copies of card", true), + Handy.UI.PARTS.create_module_keybind(Handy.cc.dangerous_actions.sell_all, "Sell ALL cards", true), + Handy.UI.PARTS.create_module_keybind(Handy.cc.dangerous_actions.card_remove, "REMOVE cards", true), + Handy.UI.PARTS.create_module_section("Game speed and animations"), + Handy.UI.PARTS.create_module_keybind(Handy.cc.speed_multiplier, "Speed Multiplier"), + Handy.UI.PARTS.create_module_keybind(Handy.cc.nopeus_interaction, "Nopeus: fast-forward"), + Handy.UI.PARTS.create_module_section("Highlight movement"), + Handy.UI.PARTS.create_module_keybind(Handy.cc.move_highlight.dx.one_left, "Move one left"), + Handy.UI.PARTS.create_module_keybind(Handy.cc.move_highlight.dx.one_right, "Move one right"), + Handy.UI.PARTS.create_module_keybind(Handy.cc.move_highlight.swap, "Move card"), + Handy.UI.PARTS.create_module_keybind(Handy.cc.move_highlight.to_end, "Move to end"), } end @@ -538,14 +761,98 @@ Handy.UI.get_config_tab = function(_tab) } if _tab == "Overall" then result.nodes = Handy.UI.get_config_tab_overall() + elseif _tab == "Quick" then + result.nodes = Handy.UI.get_config_tab_quick() elseif _tab == "Interactions" then result.nodes = Handy.UI.get_config_tab_interactions() elseif _tab == "Dangerous" then result.nodes = Handy.UI.get_config_tab_dangerous() elseif _tab == "Keybinds" then - result.nodes = Handy.UI.get_config_tab_keybinds() + result.nodes = Handy.UI.get_config_tab_regular_keybinds() elseif _tab == "Keybinds 2" then result.nodes = Handy.UI.get_config_tab_keybinds_2() end return result end + +-- + +function Handy.UI.get_options_tabs() + return { + { + label = "General & Vanilla", + tab_definition_function = function() + return Handy.UI.get_config_tab("Overall") + end, + }, + { + label = "Quick actions", + tab_definition_function = function() + return Handy.UI.get_config_tab("Quick") + end, + }, + { + label = "Danger zone", + tab_definition_function = function() + return Handy.UI.get_config_tab("Dangerous") + end, + }, + { + label = "Regular keybinds", + tab_definition_function = function() + return Handy.UI.get_config_tab("Keybinds") + end, + }, + { + label = "Other keybinds", + tab_definition_function = function() + return Handy.UI.get_config_tab("Keybinds 2") + end, + }, + } +end + +-- + +function G.UIDEF.handy_options() + local tabs = Handy.UI.get_options_tabs() + tabs[1].chosen = true + local t = create_UIBox_generic_options({ + back_func = "options", + contents = { + { + n = G.UIT.R, + config = { align = "cm", padding = 0 }, + nodes = { + create_tabs({ + tabs = tabs, + snap_to_nav = true, + colour = G.C.BOOSTER, + }), + }, + }, + }, + }) + return t +end + +function G.FUNCS.handy_open_options() + G.SETTINGS.paused = true + G.FUNCS.overlay_menu({ + definition = G.UIDEF.handy_options(), + }) +end + +function Handy.UI.get_options_button() + return UIBox_button({ label = { "Handy" }, button = "handy_open_options", minw = 5, colour = G.C.CHIPS }) +end + +-- Code taken from Anhk by MathIsFun +local create_uibox_options_ref = create_UIBox_options +function create_UIBox_options() + local contents = create_uibox_options_ref() + if Handy.UI.show_options_button then + table.insert(contents.nodes[1].nodes[1].nodes[1].nodes, Handy.UI.get_options_button()) + end + return contents +end diff --git a/HandyBalatro/index.lua b/HandyBalatro/index.lua index 96685f3..bbe091a 100644 --- a/HandyBalatro/index.lua +++ b/HandyBalatro/index.lua @@ -1,7 +1,12 @@ Handy = setmetatable({ + version = "1.4.1", + last_clicked_area = nil, last_clicked_card = nil, + last_hovered_area = nil, + last_hovered_card = nil, + utils = {}, }, {}) @@ -50,24 +55,87 @@ function Handy.utils.table_contains(t, value) return false end +function Handy.utils.serialize_string(s) + return string.format("%q", s) +end + +function Handy.utils.serialize(t, indent) + indent = indent or "" + local str = "{\n" + for k, v in ipairs(t) do + str = str .. indent .. "\t" + if type(v) == "number" then + str = str .. v + elseif type(v) == "boolean" then + str = str .. (v and "true" or "false") + elseif type(v) == "string" then + str = str .. Handy.utils.serialize_string(v) + elseif type(v) == "table" then + str = str .. Handy.utils.serialize(v, indent .. "\t") + else + -- not serializable + str = str .. "nil" + end + str = str .. ",\n" + end + for k, v in pairs(t) do + if type(k) == "string" then + str = str .. indent .. "\t" .. "[" .. Handy.utils.serialize_string(k) .. "] = " + + if type(v) == "number" then + str = str .. v + elseif type(v) == "boolean" then + str = str .. (v and "true" or "false") + elseif type(v) == "string" then + str = str .. Handy.utils.serialize_string(v) + elseif type(v) == "table" then + str = str .. Handy.utils.serialize(v, indent .. "\t") + else + -- not serializable + str = str .. "nil" + end + str = str .. ",\n" + end + end + str = str .. indent .. "}" + return str +end + -- Handy.config = { default = { + handy = { + enabled = true, + }, + notifications_level = 3, + keybinds_trigger_mode = 1, + insta_actions_trigger_mode = 1, + hide_in_menu = false, insta_highlight = { enabled = true, }, + insta_highlight_entire_f_hand = { + enabled = true, + key_1 = "None", + key_2 = "None", + }, + insta_buy_n_sell = { + enabled = true, + key_1 = "None", + key_2 = "None", + }, insta_buy_or_sell = { enabled = true, key_1 = "Shift", - key_2 = nil, + key_2 = "None", }, insta_use = { enabled = true, key_1 = "Ctrl", - key_2 = nil, + key_2 = "None", }, move_highlight = { enabled = true, @@ -75,24 +143,24 @@ Handy.config = { swap = { enabled = true, key_1 = "Shift", - key_2 = nil, + key_2 = "None", }, to_end = { enabled = true, key_1 = "Ctrl", - key_2 = nil, + key_2 = "None", }, dx = { one_left = { enabled = true, key_1 = "Left", - key_2 = nil, + key_2 = "None", }, one_right = { enabled = true, key_1 = "Right", - key_2 = nil, + key_2 = "None", }, }, }, @@ -100,27 +168,52 @@ Handy.config = { insta_cash_out = { enabled = true, key_1 = "Enter", - key_2 = nil, + key_2 = "None", }, insta_booster_skip = { enabled = true, key_1 = "Enter", - key_2 = nil, + key_2 = "None", + }, + show_deck_preview = { + enabled = true, + key_1 = "None", + key_2 = "None", }, dangerous_actions = { enabled = false, + -- Use it as basic modifier for all dangerous controls + -- Maybe I should change this but idk, backwards compatibility immediate_buy_and_sell = { enabled = true, key_1 = "Middle Mouse", - key_2 = nil, + key_2 = "None", queue = { enabled = false, }, }, + sell_all_same = { + enabled = false, + key_1 = "None", + key_2 = "None", + }, + + sell_all = { + enabled = false, + key_1 = "None", + key_2 = "None", + }, + + card_remove = { + enabled = false, + key_1 = "None", + key_2 = "None", + }, + nopeus_unsafe = { enabled = true, }, @@ -130,25 +223,76 @@ Handy.config = { enabled = true, key_1 = "Alt", - key_2 = nil, + key_2 = "None", }, - shop_reroll = { + deselect_hand = { enabled = true, - key_1 = "Q", - key_2 = nil, + key_1 = "Right Mouse", + key_2 = "None", }, - play_and_discard = { + + regular_keybinds = { enabled = true, + play = { enabled = true, - key_1 = nil, - key_2 = nil, + key_1 = "None", + key_2 = "None", }, discard = { enabled = true, - key_1 = nil, - key_2 = nil, + key_1 = "None", + key_2 = "None", + }, + sort_by_rank = { + enabled = true, + key_1 = "None", + key_2 = "None", + }, + sort_by_suit = { + enabled = true, + key_1 = "None", + key_2 = "None", + }, + + reroll_shop = { + enabled = true, + key_1 = "Q", + key_2 = "None", + }, + leave_shop = { + enabled = true, + key_1 = "None", + key_2 = "None", + }, + + skip_blind = { + enabled = true, + key_1 = "None", + key_2 = "None", + }, + select_blind = { + enabled = true, + key_1 = "None", + key_2 = "None", + }, + + run_info = { + enabled = true, + key_1 = "None", + key_2 = "None", + }, + run_info_blinds = { + enabled = true, + key_1 = "None", + key_2 = "None", + }, + + view_deck = { + enabled = true, + key_1 = "None", + key_2 = "None", }, }, @@ -156,25 +300,73 @@ Handy.config = { enabled = true, key_1 = "]", - key_2 = nil, + key_2 = "None", }, not_just_yet_interaction = { enabled = true, key_1 = "Enter", - key_2 = nil, + key_2 = "None", + }, + + cryptid_code_use_last_interaction = { + enabled = true, + key_1 = "None", + key_2 = "None", }, }, current = {}, + get_module = function(module) + if not module then + return nil + end + local override = Handy.get_module_override(module) + if override then + return Handy.utils.table_merge({}, module, override) + end + return module + end, save = function() - if Handy.current_mod then + if SMODS and SMODS.save_mod_config and Handy.current_mod then Handy.current_mod.config = Handy.config.current SMODS.save_mod_config(Handy.current_mod) + else + love.filesystem.createDirectory("config") + local serialized = "return " .. Handy.utils.serialize(Handy.config.current) + love.filesystem.write("config/Handy.jkr", serialized) end end, + load = function() + Handy.config.current = Handy.utils.table_merge({}, Handy.config.default) + local lovely_mod_config = get_compressed("config/Handy.jkr") + if lovely_mod_config then + Handy.config.current = Handy.utils.table_merge(Handy.config.current, STR_UNPACK(lovely_mod_config)) + end + Handy.cc = Handy.config.current + end, } -Handy.config.current = Handy.utils.table_merge({}, Handy.config.default) + +-- Shorthand for `Handy.config.current` +Handy.cc = Handy.config.current +Handy.config.load() + +function Handy.is_mod_active() + return Handy.cc.handy.enabled +end +function Handy.is_dangerous_actions_active() + return Handy.cc.dangerous_actions.enabled +end +function Handy.get_module_override(module) + return nil +end + +-- Ha-ha, funny Cryptid reference + +-- Resolve module with overrides +function Handy.m(module) + return Handy.config.get_module(module) +end -- @@ -250,7 +442,7 @@ Handy.controller = { end local parsed_key = Handy.controller.parse(key) if parsed_key == "Escape" then - parsed_key = nil + parsed_key = "None" end Handy.controller.complete_bind(parsed_key) Handy.config.save() @@ -354,7 +546,7 @@ Handy.controller = { local parsed_keys = { ... } for i = 1, #parsed_keys do local parsed_key = parsed_keys[i] - if parsed_key and parsed_key ~= "Unknown" then + if parsed_key and parsed_key ~= "Unknown" and parsed_key ~= "None" then if Handy.controller.wheel_buttons[parsed_key] then -- Well, skip elseif Handy.controller.mouse_buttons[parsed_key] then @@ -382,7 +574,12 @@ Handy.controller = { local parsed_key = parsed_keys[i] if parsed_key then local resolved_key_1, resolved_key_2 = Handy.controller.resolve(parsed_key) - if raw_key and raw_key ~= "Unknown" and (raw_key == resolved_key_1 or raw_key == resolved_key_2) then + if + raw_key + and raw_key ~= "Unknown" + and raw_key ~= "None" + and (raw_key == resolved_key_1 or raw_key == resolved_key_2) + then return true end end @@ -390,85 +587,178 @@ Handy.controller = { return false end, - is_module_key_down = function(module) - return module and module.enabled and Handy.controller.is_down(module.key_1, module.key_2) + is_module_key_down = function(module, allow_disabled) + module = Handy.m(module) + return module and (allow_disabled or module.enabled) and Handy.controller.is_down(module.key_1, module.key_2) end, - is_module_key = function(module, raw_key) - return module and module.enabled and Handy.controller.is(raw_key, module.key_1, module.key_2) + is_module_key = function(module, raw_key, allow_disabled) + module = Handy.m(module) + return module + and (allow_disabled or module.enabled) + and Handy.controller.is(raw_key, module.key_1, module.key_2) + end, + is_module_enabled = function(module) + module = Handy.m(module) + return module and module.enabled + end, + + is_trigger_on_release = function() + return Handy.cc.keybinds_trigger_mode == 2 + end, + is_triggered = function(released) + if Handy.controller.is_trigger_on_release() then + return released + end + return not released end, process_key = function(key, released) + if not Handy.is_mod_active() then + return false + end + if G.CONTROLLER.text_input_hook then + return false + end + if not released and Handy.controller.process_bind(key) then + return true + end + + if key == "escape" then + return false + end + if not released then - if Handy.controller.process_bind(key) then - return true + Handy.speed_multiplier.use(key) + end + + if G.STAGE == G.STAGES.RUN and not G.SETTINGS.paused then + if Handy.controller.is_triggered(released) then + Handy.insta_actions.use_alt(key) + Handy.move_highlight.use(key) + Handy.regular_keybinds.use(key) + Handy.insta_highlight_entire_f_hand.use(key) + Handy.deselect_hand.use(key) end - Handy.move_highlight.use(key) - Handy.speed_multiplier.use(key) - Handy.shop_reroll.use(key) - Handy.play_and_discard.use(key) + Handy.dangerous_actions.toggle_queue(key, released) end - Handy.insta_booster_skip.use(key, released) - Handy.insta_cash_out.use(key, released) - Handy.not_just_yet_interaction.use(key, released) - Handy.dangerous_actions.toggle_queue(key, released) + Handy.UI.state_panel.update(key, released) + return false end, process_mouse = function(mouse, released) + if not Handy.is_mod_active() then + return false + end + if G.CONTROLLER.text_input_hook then + return false + end local key = Handy.controller.mouse_to_key_table[mouse] + + if not released and Handy.controller.process_bind(key) then + return true + end + if not released then - if Handy.controller.process_bind(key) then - return true + Handy.speed_multiplier.use(key) + end + + if G.STAGE == G.STAGES.RUN and not G.SETTINGS.paused and not G.OVERLAY_MENU then + if Handy.controller.is_triggered(released) then + Handy.insta_actions.use_alt(key) + Handy.move_highlight.use(key) + Handy.regular_keybinds.use(key) + Handy.insta_highlight_entire_f_hand.use(key) + Handy.deselect_hand.use(key) end - Handy.move_highlight.use(key) - Handy.speed_multiplier.use(key) - Handy.shop_reroll.use(key) - Handy.play_and_discard.use(key) + Handy.dangerous_actions.toggle_queue(key, released) end - Handy.insta_booster_skip.use(key, released) - Handy.insta_cash_out.use(key, released) - Handy.not_just_yet_interaction.use(key, released) - Handy.dangerous_actions.toggle_queue(key, released) + Handy.UI.state_panel.update(key, released) + return false end, process_wheel = function(wheel) + if not Handy.is_mod_active() then + return false + end + if G.CONTROLLER.text_input_hook then + return false + end local key = Handy.controller.wheel_to_key_table[wheel] if Handy.controller.process_bind(key) then return true end - Handy.move_highlight.use(key) Handy.speed_multiplier.use(key) Handy.nopeus_interaction.use(key) - Handy.shop_reroll.use(key) - Handy.play_and_discard.use(key) + + if G.STAGE == G.STAGES.RUN and not G.SETTINGS.paused and not G.OVERLAY_MENU then + Handy.move_highlight.use(key) + Handy.regular_keybinds.use(key) + Handy.insta_highlight_entire_f_hand.use(key) + Handy.deselect_hand.use(key) + end + Handy.UI.state_panel.update(key, false) + + return false end, process_card_click = function(card) - if Handy.insta_actions.use(card) then - return true + if not Handy.is_mod_active() then + return false + end + if G.STAGE == G.STAGES.RUN and not G.SETTINGS.paused and not G.OVERLAY_MENU then + if Handy.insta_actions.use(card) then + return true + end + if Handy.dangerous_actions.use_click(card) then + return true + end + Handy.last_clicked_card = card + Handy.last_clicked_area = card.area end - Handy.last_clicked_card = card - Handy.last_clicked_area = card.area return false end, process_card_hover = function(card) - if Handy.insta_highlight.use(card) then - return true + if not Handy.is_mod_active() then + return false end - if Handy.dangerous_actions.use(card) then - return true + if G.STAGE == G.STAGES.RUN and not G.SETTINGS.paused and not G.OVERLAY_MENU then + if Handy.insta_highlight.use(card) then + return true + end + if Handy.dangerous_actions.use_hover(card) then + return true + end + Handy.last_hovered_card = card + Handy.last_hovered_area = card.area + end + + return false + end, + + process_tag_click = function(tag) + if not Handy.is_mod_active() then + return false + end + if G.STAGE == G.STAGES.RUN and not G.SETTINGS.paused and not G.OVERLAY_MENU then + if Handy.dangerous_actions.use_tag_click(tag) then + return true + end end return false end, + process_update = function(dt) Handy.insta_booster_skip.update() Handy.insta_cash_out.update() + Handy.show_deck_preview.update() Handy.not_just_yet_interaction.update() + Handy.UI.update(dt) end, } @@ -478,44 +768,26 @@ Handy.controller = { Handy.insta_cash_out = { is_hold = false, + can_skip = false, is_skipped = false, - is_button_created = false, - dollars = nil, - can_execute = function(check) - if check then - return not not ( - Handy.insta_cash_out.is_hold - and G.STAGE == G.STAGES.RUN - and Handy.insta_cash_out.is_skipped - and not G.SETTINGS.paused - and G.round_eval - ) - else - return not not ( - Handy.insta_cash_out.is_hold - and G.STAGE == G.STAGES.RUN - and not Handy.insta_cash_out.is_skipped - and Handy.insta_cash_out.dollars - and not G.SETTINGS.paused - and G.round_eval - ) - end + can_execute = function() + return not not ( + Handy.insta_cash_out.is_hold + and Handy.insta_cash_out.can_skip + and not Handy.insta_cash_out.is_skipped + and G.round_eval + ) end, execute = function() Handy.insta_cash_out.is_skipped = true - if Handy.insta_cash_out.is_button_created then - G.GAME.current_round.dollars = Handy.insta_cash_out.dollars - Handy.insta_cash_out.dollars = nil - end G.E_MANAGER:add_event(Event({ trigger = "immediate", func = function() - G.FUNCS.cash_out({ - config = { - id = "cash_out_button", - }, + Handy.fake_events.execute({ + func = G.FUNCS.cash_out, + id = "cash_out_button", }) return true end, @@ -523,37 +795,16 @@ Handy.insta_cash_out = { return true end, - use = function(key, released) - if Handy.controller.is_module_key(Handy.config.current.insta_cash_out, key) then - Handy.insta_cash_out.is_hold = not released - end - return false - end, - update = function() - if not Handy.config.current.insta_cash_out.enabled then - Handy.insta_cash_out.is_hold = false - end + Handy.insta_cash_out.is_hold = ( + G.STAGE == G.STAGES.RUN + and Handy.is_mod_active() + and Handy.controller.is_module_key_down(Handy.cc.insta_cash_out) + ) return Handy.insta_cash_out.can_execute() and Handy.insta_cash_out.execute() or false end, - update_state_panel = function(state, key, released) - -- if G.STAGE ~= G.STAGES.RUN then - -- return false - -- end - -- if Handy.config.current.notifications_level < 4 then - -- return false - -- end - -- if Handy.insta_cash_out.can_execute(true) then - -- state.items.insta_cash_out = { - -- text = "Skip Cash Out", - -- hold = false, - -- order = 10, - -- } - -- return true - -- end - -- return false - end, + update_state_panel = function(state, key, released) end, } Handy.insta_booster_skip = { @@ -561,19 +812,16 @@ Handy.insta_booster_skip = { is_skipped = false, can_execute = function(check) - if check then - return not not ( - Handy.insta_booster_skip.is_hold - and G.STAGE == G.STAGES.RUN - and not G.SETTINGS.paused - and G.booster_pack - ) - end + -- if check then + -- return not not ( + -- Handy.insta_booster_skip.is_hold + -- and not Handy.insta_booster_skip.is_skipped + -- and G.booster_pack + -- ) + -- end return not not ( Handy.insta_booster_skip.is_hold and not Handy.insta_booster_skip.is_skipped - and G.STAGE == G.STAGES.RUN - and not G.SETTINGS.paused and G.booster_pack and Handy.fake_events.check({ func = G.FUNCS.can_skip_booster, @@ -584,50 +832,260 @@ Handy.insta_booster_skip = { Handy.insta_booster_skip.is_skipped = true G.E_MANAGER:add_event(Event({ func = function() - G.FUNCS.skip_booster() + Handy.fake_events.execute({ + func = G.FUNCS.skip_booster, + }) return true end, })) return true end, - use = function(key, released) - if Handy.controller.is_module_key(Handy.config.current.insta_booster_skip, key) then - Handy.insta_booster_skip.is_hold = not released - end - return false - end, - update = function() - if not Handy.config.current.insta_booster_skip.enabled then - Handy.insta_booster_skip.is_hold = false - end + Handy.insta_booster_skip.is_hold = ( + G.STAGE == G.STAGES.RUN + and Handy.is_mod_active() + and Handy.controller.is_module_key_down(Handy.cc.insta_booster_skip) + ) return Handy.insta_booster_skip.can_execute() and Handy.insta_booster_skip.execute() or false end, update_state_panel = function(state, key, released) - if G.STAGE ~= G.STAGES.RUN then + -- if G.STAGE ~= G.STAGES.RUN then + -- return false + -- end + -- if Handy.cc.notifications_level < 4 then + -- return false + -- end + -- if Handy.insta_booster_skip.can_execute(true) then + -- state.items.insta_booster_skip = { + -- text = "Skip Booster Packs", + -- hold = Handy.insta_booster_skip.is_hold, + -- order = 10, + -- } + -- return true + -- end + -- return false + end, +} + +Handy.show_deck_preview = { + is_hold = false, + + update = function() + Handy.show_deck_preview.is_hold = ( + G.STAGE == G.STAGES.RUN + and Handy.is_mod_active() + and Handy.controller.is_module_key_down(Handy.cc.show_deck_preview) + ) + end, +} + +-- + +Handy.deselect_hand = { + should_prevent = function() + return Handy.controller.is_module_enabled(Handy.cc.deselect_hand) + end, + + can_execute = function(key) + return not not ( + G.hand + and G.hand.highlighted[1] + -- Vanilla check + and not ((G.play and #G.play.cards > 0) or G.CONTROLLER.locked or G.CONTROLLER.locks.frame or (G.GAME.STOP_USE and G.GAME.STOP_USE > 0)) + and Handy.controller.is_module_key(Handy.cc.deselect_hand, key) + ) + end, + execute = function() + G.hand:unhighlight_all() + end, + + use = function(key) + return Handy.deselect_hand.can_execute(key) and Handy.deselect_hand.execute() or false + end, +} + +Handy.regular_keybinds = { + shop_reroll_blocker = false, + + can_play = function(key) + return not not ( + Handy.fake_events.check({ + func = G.FUNCS.can_play, + }) and Handy.controller.is_module_key(Handy.cc.regular_keybinds.play, key) + ) + end, + play = function() + Handy.fake_events.execute({ + func = G.FUNCS.play_cards_from_highlighted, + }) + end, + + can_discard = function(key) + return not not ( + Handy.fake_events.check({ + func = G.FUNCS.can_discard, + }) and Handy.controller.is_module_key(Handy.cc.regular_keybinds.discard, key) + ) + end, + discard = function() + Handy.fake_events.execute({ + func = G.FUNCS.discard_cards_from_highlighted, + }) + end, + + can_change_sort = function(key) + if Handy.controller.is_module_key(Handy.cc.regular_keybinds.sort_by_rank, key) then + return true, "rank" + elseif Handy.controller.is_module_key(Handy.cc.regular_keybinds.sort_by_suit, key) then + return true, "suit" + else + return false, nil + end + end, + change_sort = function(sorter) + if sorter == "rank" then + Handy.fake_events.execute({ + func = G.FUNCS.sort_hand_value, + }) + elseif sorter == "suit" then + Handy.fake_events.execute({ + func = G.FUNCS.sort_hand_suit, + }) + end + end, + + can_reroll_shop = function(key) + return not not ( + not Handy.regular_keybinds.shop_reroll_blocker + and Handy.fake_events.check({ func = G.FUNCS.can_reroll, button = "reroll_shop" }) + and Handy.controller.is_module_key(Handy.cc.regular_keybinds.reroll_shop, key) + ) + end, + reroll_shop = function() + Handy.regular_keybinds.shop_reroll_blocker = true + Handy.fake_events.execute({ + func = G.FUNCS.reroll_shop, + }) + G.E_MANAGER:add_event(Event({ + no_delete = true, + func = function() + Handy.regular_keybinds.shop_reroll_blocker = false + return true + end, + })) + end, + + can_leave_shop = function(key) + return not not (Handy.controller.is_module_key(Handy.cc.regular_keybinds.leave_shop, key)) + end, + leave_shop = function() + Handy.fake_events.execute({ + func = G.FUNCS.toggle_shop, + }) + end, + + can_select_blind = function(key) + return not not ( + Handy.controller.is_module_key(Handy.cc.regular_keybinds.select_blind, key) + and G.GAME.blind_on_deck + and G.GAME.round_resets.blind_choices[G.GAME.blind_on_deck] + ) + end, + select_blind = function() + Handy.fake_events.execute({ + func = G.FUNCS.select_blind, + card = G.P_BLINDS[G.GAME.round_resets.blind_choices[G.GAME.blind_on_deck]], + }) + end, + + can_skip_blind = function(key) + return not not ( + Handy.controller.is_module_key(Handy.cc.regular_keybinds.skip_blind, key) + and G.GAME.blind_on_deck + and G.blind_select_opts[string.lower(G.GAME.blind_on_deck)] + ) + end, + skip_blind = function() + Handy.fake_events.execute({ + func = G.FUNCS.skip_blind, + UIBox = G.blind_select_opts[string.lower(G.GAME.blind_on_deck)], + }) + end, + + can_open_run_info = function(key) + if Handy.controller.is_module_key(Handy.cc.regular_keybinds.run_info, key) then + return true, 1 + elseif Handy.controller.is_module_key(Handy.cc.regular_keybinds.run_info_blinds, key) then + return true, 2 + end + return false, nil + end, + open_run_info = function(tab_index) + if tab_index == 2 then + Handy.override_create_tabs_chosen_by_label = localize("b_blinds") + end + Handy.fake_events.execute({ + func = G.FUNCS.run_info, + }) + Handy.override_create_tabs_chosen_by_label = nil + end, + + can_view_deck = function(key) + return not not (Handy.controller.is_module_key(Handy.cc.regular_keybinds.view_deck, key)) + end, + view_deck = function() + Handy.fake_events.execute({ + func = G.FUNCS.deck_info, + }) + end, + + use = function(key) + if not Handy.controller.is_module_enabled(Handy.cc.regular_keybinds) then return false end - if Handy.config.current.notifications_level < 4 then - return false - end - if Handy.insta_booster_skip.can_execute(true) then - state.items.insta_booster_skip = { - text = "Skip Booster Packs", - hold = Handy.insta_booster_skip.is_hold, - order = 10, - } - return true + if not G.SETTINGS.paused and G.STAGE == G.STAGES.RUN then + local can_open_info, info_tab_index = Handy.regular_keybinds.can_open_run_info(key) + if can_open_info then + Handy.regular_keybinds.open_run_info(info_tab_index) + elseif Handy.regular_keybinds.can_view_deck(key) then + Handy.regular_keybinds.view_deck() + elseif G.STATE == G.STATES.SELECTING_HAND then + local need_sort, sorter = Handy.regular_keybinds.can_change_sort(key) + if need_sort then + Handy.regular_keybinds.change_sort(sorter) + elseif Handy.regular_keybinds.can_discard(key) then + Handy.regular_keybinds.discard() + elseif Handy.regular_keybinds.can_play(key) then + Handy.regular_keybinds.play() + end + return false + elseif G.STATE == G.STATES.SHOP then + if Handy.regular_keybinds.can_reroll_shop(key) then + Handy.regular_keybinds.reroll_shop() + elseif Handy.regular_keybinds.can_leave_shop(key) then + Handy.regular_keybinds.leave_shop() + end + return false + elseif G.STATE == G.STATES.BLIND_SELECT then + if Handy.regular_keybinds.can_skip_blind(key) then + Handy.regular_keybinds.skip_blind() + elseif Handy.regular_keybinds.can_select_blind(key) then + Handy.regular_keybinds.select_blind() + end + return false + end end return false end, } +-- + Handy.insta_highlight = { can_execute = function(card) - return G.STAGE == G.STAGES.RUN - and Handy.config.current.insta_highlight.enabled + return Handy.controller.is_module_enabled(Handy.cc.insta_highlight) and card and card.area == G.hand -- TODO: fix it @@ -647,17 +1105,63 @@ Handy.insta_highlight = { update_state_panel = function(state, key, released) end, } +Handy.insta_highlight_entire_f_hand = { + can_execute = function(key) + return G.hand and Handy.controller.is_module_key(Handy.cc.insta_highlight_entire_f_hand, key) + end, + execute = function(key) + G.hand:unhighlight_all() + local cards_count = math.min(G.hand.config.highlighted_limit, #G.hand.cards) + for i = 1, cards_count do + local card = G.hand.cards[i] + G.hand.cards[i]:highlight(true) + G.hand.highlighted[#G.hand.highlighted + 1] = card + end + if G.STATE == G.STATES.SELECTING_HAND then + G.hand:parse_highlighted() + end + return false + end, + + use = function(key) + return Handy.insta_highlight_entire_f_hand.can_execute(key) and Handy.insta_highlight_entire_f_hand.execute(key) + or false + end, +} + Handy.insta_actions = { + action_blocker = false, + get_actions = function() return { - buy_or_sell = Handy.controller.is_module_key_down(Handy.config.current.insta_buy_or_sell), - use = Handy.controller.is_module_key_down(Handy.config.current.insta_use), + buy_n_sell = Handy.controller.is_module_key_down(Handy.cc.insta_buy_n_sell), + buy_or_sell = Handy.controller.is_module_key_down(Handy.cc.insta_buy_or_sell), + use = Handy.controller.is_module_key_down(Handy.cc.insta_use), + cryptid_code_use_last_interaction = Handy.controller.is_module_key_down( + Handy.cc.cryptid_code_use_last_interaction + ), } end, + get_alt_actions = function(key) + return { + buy_n_sell = Handy.controller.is_module_key(Handy.cc.insta_buy_n_sell, key), + buy_or_sell = Handy.controller.is_module_key(Handy.cc.insta_buy_or_sell, key), + use = Handy.controller.is_module_key(Handy.cc.insta_use, key), + cryptid_code_use_last_interaction = Handy.controller.is_module_key( + Handy.cc.cryptid_code_use_last_interaction, + key + ), + } + end, + can_execute = function(card, buy_or_sell, use) - return not not (G.STAGE == G.STAGES.RUN and (buy_or_sell or use) and card and card.area) + return not not (not Handy.insta_actions.action_blocker and (buy_or_sell or use) and card and card.area) end, execute = function(card, buy_or_sell, use, only_sell) + if card.REMOVED then + return false + end + local target_button = nil local is_shop_button = false local is_custom_button = false @@ -675,7 +1179,16 @@ Handy.insta_actions = { local is_booster_pack_card = (G.pack_cards and card.area == G.pack_cards) and not card.ability.consumeable if use then - if card.area == G.hand and card.ability.consumeable then + if type(card.ability.extra) == "table" and card.ability.extra.charges then + local success, isaac_changeable_item = pcall(function() + -- G.UIDEF.use_and_sell_buttons(G.jokers.highlighted[1]).nodes[1].nodes[3].nodes[1].nodes[1] + return card_buttons.nodes[1].nodes[3].nodes[1].nodes[1] + end) + if success and isaac_changeable_item then + target_button = isaac_changeable_item + is_custom_button = true + end + elseif card.area == G.hand and card.ability.consumeable then local success, playale_consumeable_button = pcall(function() -- G.UIDEF.use_and_sell_buttons(G.hand.highlighted[1]).nodes[1].nodes[2].nodes[1].nodes[1] return card_buttons.nodes[1].nodes[2].nodes[1].nodes[1] @@ -754,6 +1267,15 @@ Handy.insta_actions = { UIBox = target_button_UIBox, }) if check then + Handy.insta_actions.action_blocker = true + if Handy.last_clicked_card == card then + Handy.last_clicked_card = nil + Handy.last_clicked_area = nil + end + if Handy.last_hovered_card == card then + Handy.last_hovered_card = nil + Handy.last_hovered_area = nil + end Handy.fake_events.execute({ func = G.FUNCS[button or target_button_definition.config.button], button = nil, @@ -761,6 +1283,13 @@ Handy.insta_actions = { card = card, UIBox = target_button_UIBox, }) + G.E_MANAGER:add_event(Event({ + no_delete = true, + func = function() + Handy.insta_actions.action_blocker = false + return true + end, + })) cleanup() return true end @@ -770,31 +1299,101 @@ Handy.insta_actions = { return false end, - use = function(card) + process_card = function(card, actions) + if not card or card.REMOVED then + return false + end if card.ability and card.ability.handy_dangerous_actions_used then return true end - local actions = Handy.insta_actions.get_actions() + if actions.cryptid_code_use_last_interaction then + local cards_events_list = { + c_cry_variable = "variable_apply_previous", + c_cry_pointer = "pointer_apply_previous", + c_cry_class = "class_apply_previous", + c_cry_exploit = "exploit_apply_previous", + } + local success, card_center = pcall(function() + return card.config.center.key + end) + if success and card_center and cards_events_list[card_center] then + local is_code_card_used = Handy.insta_actions.can_execute(card, false, true) + and Handy.insta_actions.execute(card, false, true) + or false + if is_code_card_used then + Handy.fake_events.execute({ + func = G.FUNCS[cards_events_list[card_center]], + }) + return true + end + end + return false + elseif actions.buy_n_sell then + if + Handy.utils.table_contains({ + G.pack_cards, + G.shop_jokers, + G.shop_booster, + G.shop_vouchers, + }, card.area) + and card.ability + and (card.ability.set == "Joker" or card.ability.consumeable) + then + local is_buyed = Handy.insta_actions.can_execute(card, true, false) + and Handy.insta_actions.execute(card, true, false) + or false + if is_buyed then + G.E_MANAGER:add_event(Event({ + func = function() + G.E_MANAGER:add_event(Event({ + func = function() + return ( + Handy.insta_actions.can_execute(card, true, false) + and Handy.insta_actions.execute(card, true, false) + ) or true + end, + })) + return true + end, + })) + end + return is_buyed + end + return false + else + return Handy.insta_actions.can_execute(card, actions.buy_or_sell, actions.use) + and Handy.insta_actions.execute(card, actions.buy_or_sell, actions.use) + or false + end + end, - return Handy.insta_actions.can_execute(card, actions.buy_or_sell, actions.use) - and Handy.insta_actions.execute(card, actions.buy_or_sell, actions.use) - or false + use = function(card) + return Handy.cc.insta_actions_trigger_mode == 1 + and Handy.insta_actions.process_card(card, Handy.insta_actions.get_actions()) + end, + use_alt = function(key) + return Handy.cc.insta_actions_trigger_mode == 2 + and Handy.insta_actions.process_card(Handy.last_hovered_card, Handy.insta_actions.get_alt_actions(key)) end, update_state_panel = function(state, key, released) - if G.STAGE ~= G.STAGES.RUN then + if G.STAGE ~= G.STAGES.RUN or G.SETTINGS.paused then return false end - if Handy.config.current.notifications_level < 4 then + if Handy.cc.notifications_level < 4 then return false end local result = false - local actions = Handy.insta_actions.get_actions() + local is_alt_action = Handy.cc.insta_actions_trigger_mode == 2 + if is_alt_action and not Handy.controller.is_triggered(released) then + return false + end + local actions = is_alt_action and Handy.insta_actions.get_alt_actions(key) or Handy.insta_actions.get_actions() if actions.use then state.items.insta_use = { text = "Quick use", - hold = true, + hold = not is_alt_action, order = 10, } result = true @@ -802,11 +1401,19 @@ Handy.insta_actions = { if actions.buy_or_sell then state.items.quick_buy_and_sell = { text = "Quick buy and sell", - hold = true, + hold = not is_alt_action, order = 11, } result = true end + if actions.buy_n_sell then + state.items.quick_buy_n_sell = { + text = "Quick buy and immediately sell", + hold = not is_alt_action, + order = 12, + } + result = true + end return result end, } @@ -818,7 +1425,7 @@ Handy.move_highlight = { }, get_dx = function(key, area) - for module_key, module in pairs(Handy.config.current.move_highlight.dx) do + for module_key, module in pairs(Handy.cc.move_highlight.dx) do if Handy.controller.is_module_key(module, key) then return Handy.move_highlight.dx[module_key] end @@ -827,8 +1434,8 @@ Handy.move_highlight = { end, get_actions = function(key, area) return { - swap = Handy.controller.is_module_key_down(Handy.config.current.move_highlight.swap), - to_end = Handy.controller.is_module_key_down(Handy.config.current.move_highlight.to_end), + swap = Handy.controller.is_module_key_down(Handy.cc.move_highlight.swap), + to_end = Handy.controller.is_module_key_down(Handy.cc.move_highlight.to_end), } end, @@ -845,8 +1452,7 @@ Handy.move_highlight = { end, cen_execute = function(key, area) return not not ( - Handy.config.current.move_highlight.enabled - and G.STAGE == G.STAGES.RUN + Handy.controller.is_module_enabled(Handy.cc.move_highlight) and area and area.highlighted and area.highlighted[1] @@ -909,77 +1515,179 @@ Handy.dangerous_actions = { sell_queue = {}, sell_next_card = function() - local card = table.remove(Handy.dangerous_actions.sell_queue, 1) - if not card then + local target = table.remove(Handy.dangerous_actions.sell_queue, 1) + if not target then stop_use() return end - G.GAME.STOP_USE = 0 - Handy.insta_actions.execute(card, true, false, true) + local card = target.card + if target.remove then + card:stop_hover() + card:remove() + else + G.GAME.STOP_USE = 0 + Handy.insta_actions.execute(card, true, false, true) - G.E_MANAGER:add_event(Event({ - blocking = false, - func = function() - if card.ability then - card.ability.handy_dangerous_actions_used = nil - end - return true - end, - })) + G.E_MANAGER:add_event(Event({ + blocking = false, + func = function() + if card.ability then + card.ability.handy_dangerous_actions_used = nil + end + return true + end, + })) + end + if Handy.last_clicked_card == card then + Handy.last_clicked_card = nil + Handy.last_clicked_area = nil + end + if Handy.last_hovered_card == card then + Handy.last_hovered_card = nil + Handy.last_hovered_area = nil + end Handy.dangerous_actions.sell_next_card() end, - can_execute = function(card) - return G.STAGE == G.STAGES.RUN - and Handy.config.current.dangerous_actions.enabled - and card - and not (card.ability and card.ability.handy_dangerous_actions_used) + get_options = function(card) + return { + use_queue = Handy.controller.is_module_enabled(Handy.cc.dangerous_actions.immediate_buy_and_sell.queue), + remove = Handy.controller.is_module_key_down(Handy.cc.dangerous_actions.card_remove) + and (card.area == G.jokers or card.area == G.consumeables), + } end, - execute = function(card) - if Handy.controller.is_module_key_down(Handy.config.current.dangerous_actions.immediate_buy_and_sell) then - if Handy.config.current.dangerous_actions.immediate_buy_and_sell.queue.enabled then + + process_card = function(card, use_queue, remove) + if use_queue then + if not card.ability then + card.ability = {} + end + card.ability.handy_dangerous_actions_used = true + + table.insert(Handy.dangerous_actions.sell_queue, { card = card, remove = remove }) + Handy.UI.state_panel.update(nil, nil) + return false + elseif remove then + card:stop_hover() + card:remove() + return true + else + local result = Handy.insta_actions.execute(card, true, false) + if result then if not card.ability then card.ability = {} end card.ability.handy_dangerous_actions_used = true - table.insert(Handy.dangerous_actions.sell_queue, card) - Handy.UI.state_panel.update(nil, nil) - return false - else - local result = Handy.insta_actions.execute(card, true, false) - if result then - if not card.ability then - card.ability = {} - end - card.ability.handy_dangerous_actions_used = true + G.CONTROLLER.locks.selling_card = nil + G.CONTROLLER.locks.use = nil + G.GAME.STOP_USE = 0 - G.CONTROLLER.locks.selling_card = nil - G.CONTROLLER.locks.use = nil - G.GAME.STOP_USE = 0 + G.E_MANAGER:add_event(Event({ + no_delete = true, + func = function() + if card.ability then + card.ability.handy_dangerous_actions_used = nil + end + return true + end, + })) + end + return result + end + end, - G.E_MANAGER:add_event(Event({ - func = function() - if card.ability then - card.ability.handy_dangerous_actions_used = nil - end - return true - end, - })) + can_execute = function(card) + return Handy.is_dangerous_actions_active() + and card + and not (card.ability and card.ability.handy_dangerous_actions_used) + end, + execute_click = function(card) + if Handy.controller.is_module_key_down(Handy.cc.dangerous_actions.immediate_buy_and_sell, true) then + if Handy.controller.is_module_key_down(Handy.cc.dangerous_actions.sell_all) then + local options = Handy.dangerous_actions.get_options(card) + for _, target_card in ipairs(card.area.cards) do + Handy.dangerous_actions.process_card(target_card, true, options.remove) end - return result + Handy.dangerous_actions.sell_next_card() + return true + elseif Handy.controller.is_module_key_down(Handy.cc.dangerous_actions.sell_all_same) then + local target_cards = {} + local success, card_center_key = pcall(function() + return card.config.center.key + end) + if success and card_center_key then + for _, area_card in ipairs(card.area.cards) do + local _success, area_card_center_key = pcall(function() + return area_card.config.center.key + end) + if _success and area_card_center_key == card_center_key then + table.insert(target_cards, area_card) + end + end + end + + local options = Handy.dangerous_actions.get_options(card) + for _, target_card in ipairs(target_cards) do + Handy.dangerous_actions.process_card(target_card, true, options.remove) + end + Handy.dangerous_actions.sell_next_card() + return true end end return false end, + execute_hover = function(card) + if not Handy.controller.is_module_key_down(Handy.cc.dangerous_actions.immediate_buy_and_sell) then + return false + end + if not Handy.insta_actions.get_actions().buy_or_sell then + return false + end + local options = Handy.dangerous_actions.get_options(card) + return Handy.dangerous_actions.process_card(card, options.use_queue, options.remove) + end, - use = function(card) - return Handy.dangerous_actions.can_execute(card) and Handy.dangerous_actions.execute(card) or false + use_click = function(card) + return Handy.dangerous_actions.can_execute(card) and Handy.dangerous_actions.execute_click(card) or false + end, + use_hover = function(card) + return Handy.dangerous_actions.can_execute(card) and Handy.dangerous_actions.execute_hover(card) or false + end, + + can_execute_tag = function(tag) + return Handy.is_dangerous_actions_active() and tag + end, + execute_tag_click = function(tag) + if Handy.controller.is_module_key_down(Handy.cc.dangerous_actions.card_remove) then + local target_tags = {} + for _, target_tag in ipairs(G.GAME.tags) do + table.insert(target_tags, target_tag) + end + if Handy.controller.is_module_key_down(Handy.cc.dangerous_actions.sell_all) then + for _, target_tag in ipairs(target_tags) do + target_tag:remove() + end + return true + elseif Handy.controller.is_module_key_down(Handy.cc.dangerous_actions.sell_all_same) then + local tag_key = tag.key + for _, target_tag in ipairs(target_tags) do + if target_tag.key == tag_key then + target_tag:remove() + end + end + return true + end + end + return false + end, + use_tag_click = function(tag) + return Handy.dangerous_actions.can_execute_tag(tag) and Handy.dangerous_actions.execute_tag_click(tag) or false end, toggle_queue = function(key, released) - if Handy.controller.is_module_key(Handy.config.current.dangerous_actions.immediate_buy_and_sell, key) then + if Handy.controller.is_module_key(Handy.cc.dangerous_actions.immediate_buy_and_sell, key) then if released then Handy.dangerous_actions.sell_next_card() else @@ -989,47 +1697,90 @@ Handy.dangerous_actions = { end, update_state_panel = function(state, key, released) - if G.STAGE ~= G.STAGES.RUN then + if G.STAGE ~= G.STAGES.RUN or G.SETTINGS.paused then + return false + end + if Handy.cc.notifications_level < 2 then return false end - if not Handy.config.current.dangerous_actions.enabled then + local is_sell = Handy.controller.is_module_key_down(Handy.cc.dangerous_actions.immediate_buy_and_sell, true) + if not is_sell then return false end - if Handy.config.current.notifications_level < 2 then - return false - end - if Handy.controller.is_module_key_down(Handy.config.current.dangerous_actions.immediate_buy_and_sell) then - state.dangerous = true - state.items.dangerous_hint = { - text = "[Unsafe] Bugs can appear!", - dangerous = true, + + if not Handy.controller.is_module_enabled(Handy.cc.dangerous_actions) then + state.items.prevented_dangerous_actions = { + text = "Unsafe actions disabled in mod settings", + hold = true, + order = 99999999, + } + return true + elseif not Handy.is_dangerous_actions_active() then + state.items.prevented_dangerous_actions = { + text = "Unsafe actions disabled by other mod", hold = true, order = 99999999, } - if state.items.quick_buy_and_sell then - state.items.quick_buy_and_sell.dangerous = true - elseif Handy.insta_actions.get_actions().buy_or_sell then - local text = "Quick sell" - if Handy.config.current.dangerous_actions.immediate_buy_and_sell.queue.enabled then - text = text .. " [" .. #Handy.dangerous_actions.sell_queue .. " in queue]" - end - state.items.quick_buy_and_sell = { - text = text, - hold = true, - order = 11, - dangerous = true, - } - end return true end - return false + + local is_insta_sell = Handy.insta_actions.get_actions().buy_or_sell + and Handy.controller.is_module_key_down(Handy.cc.dangerous_actions.immediate_buy_and_sell) + local is_all = Handy.controller.is_module_key_down(Handy.cc.dangerous_actions.sell_all) + local is_all_same = Handy.controller.is_module_key_down(Handy.cc.dangerous_actions.sell_all_same) + local is_remove = Handy.controller.is_module_key_down(Handy.cc.dangerous_actions.card_remove) + + state.dangerous = true + state.items.dangerous_hint = { + text = "[Unsafe] Bugs can appear!", + dangerous = true, + hold = true, + order = 99999999, + } + + if is_insta_sell then + local text = is_remove and "Instant REMOVE" or "Instant sell" + if Handy.controller.is_module_enabled(Handy.cc.dangerous_actions.immediate_buy_and_sell.queue) then + text = text .. " [" .. #Handy.dangerous_actions.sell_queue .. " in queue]" + end + state.items.quick_buy_and_sell = { + text = text, + hold = true, + order = 11, + dangerous = true, + } + elseif is_all then + local text = is_remove and "REMOVE ALL cards/tags in clicked area" or "Sell ALL cards in clicked area" + state.items.sell_all_same = { + text = text, + hold = true, + order = 12, + dangerous = true, + } + elseif is_all_same then + local text = is_remove and "REMOVE all copies of clicked card/tag" or "Sell all copies of clicked card" + state.items.sell_all_same = { + text = text, + hold = true, + order = 12, + dangerous = true, + } + end + return true end, } Handy.speed_multiplier = { value = 1, + get_value = function() + if not Handy.is_mod_active() or not Handy.controller.is_module_enabled(Handy.cc.speed_multiplier) then + return 1 + end + return Handy.speed_multiplier.value + end, + get_actions = function(key) return { multiply = key == Handy.controller.wheel_to_key_table[1], @@ -1037,9 +1788,7 @@ Handy.speed_multiplier = { } end, can_execute = function(key) - return Handy.config.current.speed_multiplier.enabled - and not G.OVERLAY_MENU - and Handy.controller.is_module_key_down(Handy.config.current.speed_multiplier) + return Handy.controller.is_module_key_down(Handy.cc.speed_multiplier) end, execute = function(key) @@ -1068,7 +1817,7 @@ Handy.speed_multiplier = { if not key or not Handy.speed_multiplier.can_execute(key) then return false end - if Handy.config.current.notifications_level < 3 then + if Handy.cc.notifications_level < 3 then return false end @@ -1090,63 +1839,7 @@ Handy.speed_multiplier = { end, } -Handy.shop_reroll = { - can_execute = function(key) - return G.STATE == G.STATES.SHOP - and Handy.fake_events.check({ func = G.FUNCS.can_reroll, button = "reroll_shop" }) - and Handy.controller.is_module_key(Handy.config.current.shop_reroll, key) - end, - execute = function(key) - G.FUNCS.reroll_shop() - return false - end, - - use = function(key) - return Handy.shop_reroll.can_execute(key) and Handy.shop_reroll.execute(key) or false - end, -} - -Handy.play_and_discard = { - get_actions = function(key) - return { - discard = Handy.controller.is_module_key(Handy.config.current.play_and_discard.discard, key), - play = Handy.controller.is_module_key(Handy.config.current.play_and_discard.play, key), - } - end, - - can_execute = function(play, discard) - return not not ( - Handy.config.current.play_and_discard.enabled - and G.STATE == G.STATES.SELECTING_HAND - and ( - (discard and Handy.fake_events.check({ - func = G.FUNCS.can_discard, - })) or (play and Handy.fake_events.check({ - func = G.FUNCS.can_play, - })) - ) - ) - end, - execute = function(play, discard) - if discard then - Handy.fake_events.execute({ - func = G.FUNCS.discard_cards_from_highlighted, - }) - elseif play then - Handy.fake_events.execute({ - func = G.FUNCS.play_cards_from_highlighted, - }) - end - return false - end, - - use = function(key) - local actions = Handy.play_and_discard.get_actions(key) - return Handy.play_and_discard.can_execute(actions.play, actions.discard) - and Handy.play_and_discard.execute(actions.play, actions.discard) - or false - end, -} +-- Handy.nopeus_interaction = { is_present = function() @@ -1162,16 +1855,15 @@ Handy.nopeus_interaction = { can_dangerous = function() return not not ( - Handy.config.current.dangerous_actions.enabled - and Handy.config.current.dangerous_actions.nopeus_unsafe.enabled + Handy.is_mod_active() + and Handy.is_dangerous_actions_active() + and Handy.controller.is_module_enabled(Handy.cc.dangerous_actions.nopeus_unsafe) ) end, can_execute = function(key) return not not ( - Handy.config.current.nopeus_interaction.enabled - and Handy.nopeus_interaction.is_present() - and not G.OVERLAY_MENU - and Handy.controller.is_module_key_down(Handy.config.current.nopeus_interaction) + Handy.nopeus_interaction.is_present() + and Handy.controller.is_module_key_down(Handy.cc.nopeus_interaction) ) end, execute = function(key) @@ -1241,11 +1933,11 @@ Handy.nopeus_interaction = { if is_dangerous then state.dangerous = true - if Handy.config.current.notifications_level < 2 then + if Handy.cc.notifications_level < 2 then return false end else - if Handy.config.current.notifications_level < 3 then + if Handy.cc.notifications_level < 3 then return false end end @@ -1256,6 +1948,17 @@ Handy.nopeus_interaction = { order = 4, dangerous = is_dangerous, } + if + not Handy.nopeus_interaction.can_dangerous() + and actions.increase + and G.SETTINGS.FASTFORWARD == (#states - 2) + then + state.items.prevent_nopeus_unsafe = { + text = "Unsafe option disabled in mod settings", + hold = false, + order = 4.05, + } + end return true end return false @@ -1288,17 +1991,12 @@ Handy.not_just_yet_interaction = { end_round() end, - use = function(key, released) - if Handy.controller.is_module_key(Handy.config.current.not_just_yet_interaction, key) then - GLOBAL_njy_vanilla_override = not released - end - return false - end, - update = function() - if not Handy.config.current.not_just_yet_interaction.enabled then - GLOBAL_njy_vanilla_override = nil - end + GLOBAL_njy_vanilla_override = ( + G.STAGE == G.STAGES.RUN + and Handy.is_mod_active() + and Handy.controller.is_module_key_down(Handy.cc.not_just_yet_interaction) + ) return Handy.not_just_yet_interaction.can_execute() and Handy.not_just_yet_interaction.execute() or false end, } @@ -1308,6 +2006,7 @@ Handy.not_just_yet_interaction = { -- Handy.UI = { + show_options_button = true, counter = 1, C = { TEXT = HEX("FFFFFF"), @@ -1549,42 +2248,12 @@ end -- function Handy.emplace_steamodded() - Handy.current_mod = SMODS.current_mod - Handy.config.current = Handy.utils.table_merge({}, Handy.config.default, SMODS.current_mod.config) + Handy.current_mod = (Handy_Preload and Handy_Preload.current_mod) or SMODS.current_mod + Handy.current_mod.config_tab = true + Handy.UI.show_options_button = not Handy.cc.hide_in_menu Handy.current_mod.extra_tabs = function() - return { - { - label = "Overall", - tab_definition_function = function() - return Handy.UI.get_config_tab("Overall") - end, - }, - { - label = "Interactions", - tab_definition_function = function() - return Handy.UI.get_config_tab("Interactions") - end, - }, - { - label = "Dangerous", - tab_definition_function = function() - return Handy.UI.get_config_tab("Dangerous") - end, - }, - { - label = "Keybinds", - tab_definition_function = function() - return Handy.UI.get_config_tab("Keybinds") - end, - }, - { - label = "More keybinds", - tab_definition_function = function() - return Handy.UI.get_config_tab("Keybinds 2") - end, - }, - } + return Handy.UI.get_options_tabs() end G.E_MANAGER:add_event(Event({ @@ -1593,6 +2262,10 @@ function Handy.emplace_steamodded() return true end, })) + + if Handy_Preload then + Handy_Preload = nil + end end function G.FUNCS.handy_toggle_module_enabled(arg, module) @@ -1600,23 +2273,37 @@ function G.FUNCS.handy_toggle_module_enabled(arg, module) return end module.enabled = arg - if module == Handy.config.current.speed_multiplier then - Handy.speed_multiplier.value = 1 - elseif - module == Handy.config.current.dangerous_actions - or module == Handy.config.current.nopeus_interaction - or module == Handy.config.current.dangerous_actions.nopeus_unsafe - then - Handy.nopeus_interaction.change(0) - end + Handy.nopeus_interaction.change(0) Handy.config.save() end +function G.FUNCS.handy_toggle_menu_button(arg) + Handy.cc.hide_in_menu = arg + Handy.config.save() + if Handy.current_mod then + Handy.UI.show_options_button = not Handy.cc.hide_in_menu + end +end + function G.FUNCS.handy_change_notifications_level(arg) - Handy.config.current.notifications_level = arg.to_key + Handy.cc.notifications_level = arg.to_key + Handy.config.save() +end + +function G.FUNCS.handy_change_keybinds_trigger_mode(arg) + Handy.cc.keybinds_trigger_mode = arg.to_key + Handy.config.save() +end + +function G.FUNCS.handy_change_insta_actions_trigger_mode(arg) + Handy.cc.insta_actions_trigger_mode = arg.to_key Handy.config.save() end function G.FUNCS.handy_init_keybind_change(e) Handy.controller.init_bind(e) end + +if Handy_Preload then + Handy.emplace_steamodded() +end diff --git a/HandyBalatro/lovely.toml b/HandyBalatro/lovely.toml index 566b0d8..251341c 100644 --- a/HandyBalatro/lovely.toml +++ b/HandyBalatro/lovely.toml @@ -18,33 +18,11 @@ sources = ["config_ui.lua"] # Skipping Cash Out stage [[patches]] [patches.pattern] -target = "functions/common_events.lua" -pattern = '''local num_dollars = config.dollars or 1''' +target = "game.lua" +pattern = '''G.FUNCS.evaluate_round()''' position = "after" payload = ''' -Handy.insta_cash_out.dollars = config.dollars or 1 -''' -match_indent = true -overwrite = false - -[[patches]] -[patches.pattern] -target = "functions/common_events.lua" -pattern = '''G.GAME.current_round.dollars = config.dollars''' -position = "before" -payload = ''' -Handy.insta_cash_out.is_button_created = true -''' -match_indent = true -overwrite = false - -[[patches]] -[patches.pattern] -target = "functions/button_callbacks.lua" -pattern = '''G.deck:shuffle('cashout'..G.GAME.round_resets.ante)''' -position = "before" -payload = ''' -Handy.insta_cash_out.is_button_created = false +Handy.insta_cash_out.can_skip = true ''' match_indent = true overwrite = false @@ -78,6 +56,7 @@ pattern = '''G.STATE = G.STATES.SHOP''' position = "after" payload = ''' Handy.insta_cash_out.is_skipped = false +Handy.insta_cash_out.can_skip = false ''' match_indent = true overwrite = false @@ -176,6 +155,40 @@ if Handy.controller.process_card_hover(self) then return end match_indent = true overwrite = false +# Handle card stop hover +[[patches]] +[patches.pattern] +target = "card.lua" +pattern = '''function Card:stop_hover()''' +position = "after" +payload = ''' +if Handy.last_hovered_card == self then + Handy.last_hovered_card = nil + Handy.last_hovered_area = nil +end +''' +match_indent = true +overwrite = false + + +# Handle skip tag click +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = '''local tag_sprite_ui = _tag:generate_UI()''' +position = "after" +payload = ''' +local _handy_tag_click_target = _tag.tag_sprite +local _handy_tag_click_ref = _handy_tag_click_target.click +_handy_tag_click_target.click = function(...) + if Handy.controller.process_tag_click(_tag) then return end + return _handy_tag_click_ref(...) +end +''' +match_indent = true +overwrite = false + + # Apply multiplier to speed [[patches]] [patches.pattern] @@ -183,7 +196,45 @@ target = "game.lua" pattern = '''self.SPEEDFACTOR = self.SPEEDFACTOR + math.max(0, math.abs(G.ACC) - 2)''' position = "after" payload = ''' -self.SPEEDFACTOR = self.SPEEDFACTOR * Handy.speed_multiplier.value or 1 +self.SPEEDFACTOR = self.SPEEDFACTOR * Handy.speed_multiplier.get_value() or 1 +''' +match_indent = true +overwrite = false + +# Show deck preview +[[patches]] +[patches.regex] +target = "game.lua" +pattern = '''G.CONTROLLER.held_buttons.triggerleft''' +position = "after" +payload = ''' + or Handy.show_deck_preview.is_hold +''' +match_indent = true +overwrite = false +times = 2 + +# Prevent default hand deselecting +[[patches]] +[patches.pattern] +target = "engine/controller.lua" +pattern = '''if (G.play and #G.play.cards > 0) or''' +position = "after" +payload = ''' +Handy.deselect_hand.should_prevent() or +''' +match_indent = true +overwrite = false + +# Add ability to override chosen tab in create_tabs +[[patches]] +[patches.pattern] +target = "functions/UI_definitions.lua" +pattern = '''if v.chosen then args.current = {k = k, v = v} end''' +position = "before" +payload = ''' +if Handy.override_create_tabs_chosen then v.chosen = k == Handy.override_create_tabs_chosen +elseif Handy.override_create_tabs_chosen_by_label then v.chosen = v.label == Handy.override_create_tabs_chosen_by_label end ''' match_indent = true overwrite = false diff --git a/HandyBalatro/metadata.json b/HandyBalatro/metadata.json new file mode 100644 index 0000000..9b3c1e3 --- /dev/null +++ b/HandyBalatro/metadata.json @@ -0,0 +1,12 @@ +{ + "id": "Handy", + "name": "Handy", + "display_name": "Handy", + "author": ["SleepyG11"], + "description": "A mod for Balatro which adds new Quality of Life controls.", + "prefix": "handy", + "main_file": "steamodded.lua", + "priority": 0, + "version": "1.4.1", + "dependencies": [] +} diff --git a/HandyBalatro/steamodded.lua b/HandyBalatro/steamodded.lua index a09ff89..f316b27 100644 --- a/HandyBalatro/steamodded.lua +++ b/HandyBalatro/steamodded.lua @@ -7,18 +7,26 @@ --- PRIORITY: 0 --- DISPLAY_NAME: Handy --- PREFIX: handy ---- VERSION: 1.1.5 +--- VERSION: 1.4.1 ---------------------------------------------- ------------MOD CODE ------------------------- -Handy.emplace_steamodded() +if SMODS and SMODS.current_mod then + if Handy then + Handy.emplace_steamodded() + else + Handy_Preload = { + current_mod = SMODS.current_mod, + } + end -SMODS.Atlas({ - key = "modicon", - path = "icon.png", - px = 32, - py = 32, -}) + SMODS.Atlas({ + key = "modicon", + path = "icon.png", + px = 32, + py = 32, + }) +end ---------------------------------------------- ------------MOD CODE END---------------------- diff --git a/HandyBalatro/version b/HandyBalatro/version new file mode 100644 index 0000000..17bcc12 --- /dev/null +++ b/HandyBalatro/version @@ -0,0 +1 @@ +1.4.1: m diff --git a/Steamodded/TODO b/Steamodded/TODO deleted file mode 100644 index 455b484..0000000 --- a/Steamodded/TODO +++ /dev/null @@ -1,29 +0,0 @@ -# Documentation -## To do - - -- Challenge -- DeckSkin - -## In progress -- Enhancement - -## Done - -- Achievement -- Atlas -- Center (Joker, Consumable, Voucher, Back, Booster) -- Blind -- ObjectType -- UndiscoveredSprite -- Edition -- Language -- Sound -- Stake -- PokerHand -- Suit -- Rank -- Seal -- Sticker -- Rarity -- Tag diff --git a/Steamodded/manifest.json b/Steamodded/manifest.json deleted file mode 100644 index 0b06fff..0000000 --- a/Steamodded/manifest.json +++ /dev/null @@ -1,10 +0,0 @@ -{ - "name": "Steamodded", - "version_number": "0.9.8", - "website_url": "https://github.com/Steamopollys/Steamodded", - "description": "A Balatro ModLoader", - "dependencies": [ - "Thunderstore-lovely-0.3.1", - "metherul-nativefs-1.0.0" - ] -} diff --git a/Steamodded/version.lua b/Steamodded/version.lua deleted file mode 100644 index a27c46a..0000000 --- a/Steamodded/version.lua +++ /dev/null @@ -1 +0,0 @@ -return "1.0.0~ALPHA-1422a-STEAMODDED" diff --git a/Talisman/lovely.toml b/Talisman/lovely.toml index 79fa6bb..57ed099 100644 --- a/Talisman/lovely.toml +++ b/Talisman/lovely.toml @@ -564,6 +564,15 @@ position = "at" payload = '''if to_big(G.GAME.dollars) <= to_big(self.ability.extra) then''' match_indent = true +# Luxury Tax Challenge +[[patches]] +[patches.pattern] +target = "cardarea.lua" +pattern = '''self:change_size(self.config.last_poll_size - math.floor(G.GAME.dollars/G.GAME.modifiers.minus_hand_size_per_X_dollar))''' +position = "at" +payload = '''self:change_size(to_big(self.config.last_poll_size - math.floor(G.GAME.dollars/G.GAME.modifiers.minus_hand_size_per_X_dollar)):to_number())''' +match_indent = true + # for now, I'm letting dollar eval ignore bignum, I'll patch it later [[patches]] [patches.pattern] diff --git a/Talisman/steamodded_metadata.lua b/Talisman/steamodded_metadata.lua index 017a0b9..bbe614f 100644 --- a/Talisman/steamodded_metadata.lua +++ b/Talisman/steamodded_metadata.lua @@ -4,7 +4,7 @@ --- MOD_AUTHOR: [MathIsFun_, Mathguy24, jenwalter666, cg-223] --- MOD_DESCRIPTION: A mod that increases Balatro's score limit and skips scoring animations. --- PREFIX: talisman ---- VERSION: 2.1.0~dev +--- VERSION: 2.1.1~dev ---------------------------------------------- ------------MOD CODE ------------------------- diff --git a/Talisman/version b/Talisman/version new file mode 100644 index 0000000..69078c6 --- /dev/null +++ b/Talisman/version @@ -0,0 +1 @@ +cryptid-0.5.5 diff --git a/Steamodded/LICENSE b/smods/LICENSE similarity index 100% rename from Steamodded/LICENSE rename to smods/LICENSE diff --git a/Steamodded/README.md b/smods/README.md similarity index 80% rename from Steamodded/README.md rename to smods/README.md index 4d2aca8..31f18e4 100644 --- a/Steamodded/README.md +++ b/smods/README.md @@ -1,4 +1,4 @@ -# Steamodded - A Balatro ModLoader +# Steamodded - A Balatro Modding Framework ## Introduction @@ -22,7 +22,11 @@ Documentation for this project is currently incomplete. A collection of document ## Contributing -This project is open for contribution; feel free to open a pull request. If you are adding new features, providing documentation is highly appreciated. +This project is open for contribution; feel free to open a pull request. If you are adding new features, providing documentation is highly appreciated. + +## Issues, Suggestions and more + +If you have any suggestions for this project, would like to report a bug, or just want to discuss something with us, you can get in touch by opening an issue or contacting us on [Discord](https://discord.gg/kU8cqCqwy3). ## License diff --git a/Steamodded/assets/1x/default_achievements.png b/smods/assets/1x/default_achievements.png similarity index 100% rename from Steamodded/assets/1x/default_achievements.png rename to smods/assets/1x/default_achievements.png diff --git a/Steamodded/assets/1x/mod_tags.png b/smods/assets/1x/mod_tags.png similarity index 100% rename from Steamodded/assets/1x/mod_tags.png rename to smods/assets/1x/mod_tags.png diff --git a/Steamodded/assets/2x/default_achievements.png b/smods/assets/2x/default_achievements.png similarity index 100% rename from Steamodded/assets/2x/default_achievements.png rename to smods/assets/2x/default_achievements.png diff --git a/Steamodded/assets/2x/mod_tags.png b/smods/assets/2x/mod_tags.png similarity index 100% rename from Steamodded/assets/2x/mod_tags.png rename to smods/assets/2x/mod_tags.png diff --git a/Steamodded/assets/sounds/xchips.ogg b/smods/assets/sounds/xchips.ogg similarity index 100% rename from Steamodded/assets/sounds/xchips.ogg rename to smods/assets/sounds/xchips.ogg diff --git a/Steamodded/config.lua b/smods/config.lua similarity index 98% rename from Steamodded/config.lua rename to smods/config.lua index 032ff99..f1be88e 100644 --- a/Steamodded/config.lua +++ b/smods/config.lua @@ -4,4 +4,4 @@ return { ["graphics_mipmap_level_options"] = {0, 2, 4, 8}, ["achievements"] = 1, ["seeded_unlocks"] = false, -} +} \ No newline at end of file diff --git a/Steamodded/icon.png b/smods/icon.png similarity index 100% rename from Steamodded/icon.png rename to smods/icon.png diff --git a/smods/libs/https/luajit-curl.lua b/smods/libs/https/luajit-curl.lua new file mode 100644 index 0000000..7007645 --- /dev/null +++ b/smods/libs/https/luajit-curl.lua @@ -0,0 +1,1056 @@ +-- This is a modifed version of https://gist.github.com/LPGhatguy/09d3955207ab35d96e97 +-- Original license: +--[[ +LuaJIT-cURL +Lucien Greathouse +LuaJIT FFI cURL binding aimed at cURL version 7.38.0. + +Copyright (c) 2014 lucien Greathouse + +This software is provided 'as-is', without any express +or implied warranty. In no event will the authors be held +liable for any damages arising from the use of this software. + +Permission is granted to anyone to use this software for any purpose, +including commercial applications, andto alter it and redistribute it +freely, subject to the following restrictions: + +1. The origin of this software must not be misrepresented; you must not +claim that you wrote the original software. If you use this software +in a product, an acknowledgment in the product documentation would be +appreciated but is not required. + +2. Altered source versions must be plainly marked as such, and must +not be misrepresented as being the original software. + +3. This notice may not be removed or altered from any source distribution. +]] +local ffi = require("ffi") +local succ, curl = pcall(ffi.load, "libcurl") +if not succ then + sendDebugMessage("ffi.load for libcurl failed: " .. tostring(curl), "luajit-curl") + local succ, curl4 = pcall(ffi.load, "libcurl.so.4") + if not succ then + sendErrorMessage("ffi.load for libcurl and libcurl.so.4 failed! " .. tostring(curl4), "luajit-curl") + error(curl4) + end + curl = curl4 +end + +if (jit.os == "Windows") then + --Windows! + ffi.cdef([[ + //windows layering + enum { + INVALID_SOCKET = ~0, + SOCKET_BAD = ~0 + }; + ]]) +else + --Not Windows! + ffi.cdef([[ + typedef int socket_t; + + enum { + SOCKET_BAD = -1 + }; + ]]) +end + +ffi.cdef([[ + typedef int64_t time_t; + typedef unsigned int size_t; + + typedef size_t (*curl_callback)(char *data, size_t size, size_t nmeb, void *userdata); +]]) + +--curlver.h +ffi.cdef([[ +/*************************************************************************** + * _ _ ____ _ + * Project ___| | | | _ \| | + * / __| | | | |_) | | + * | (__| |_| | _ <| |___ + * \___|\___/|_| \_\_____| + * + * Copyright (C) 1998 - 2014, Daniel Stenberg, , et al. + * + * This software is licensed as described in the file COPYING, which + * you should have received as part of this distribution. The terms + * are also available at http://curl.haxx.se/docs/copyright.html. + * + * You may opt to use, copy, modify, merge, publish, distribute and/or sell + * copies of the Software, and permit persons to whom the Software is + * furnished to do so, under the terms of the COPYING file. + * + * This software is distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY + * KIND, either express or implied. + * + ***************************************************************************/ + +enum { + LIBCURL_VERSION_MAJOR = 7, + LIBCURL_VERSION_MINOR = 38, + LIBCURL_VERSION_PATCH = 0, + LIBCURL_VERSION_NUM = 0x072600 +} +]]) + +--cURL's type aliasing, built around curlbuild.h +ffi.cdef([[ + typedef int64_t curl_off_t; +]]) + +--Constants +ffi.cdef([[ +enum { + CURL_GLOBAL_SSL = (1<<0), + CURL_GLOBAL_WIN32 = (1<<1), + CURL_GLOBAL_ALL = (CURL_GLOBAL_SSL|CURL_GLOBAL_WIN32), + CURL_GLOBAL_NOTHING = 0, + CURL_GLOBAL_DEFAULT = CURL_GLOBAL_ALL, + CURL_GLOBAL_ACK_EINTR = (1<<2) +}; +]]) + +ffi.cdef([[ +typedef void CURL; +typedef int curl_socket_t; +struct curl_httppost { +struct curl_httppost *next; +char *name; +long namelength; +char *contents; +long contentslength; +char *buffer; +long bufferlength; +char *contenttype; +struct curl_slist* contentheader; +struct curl_httppost *more; +long flags; +char *showfilename; +void *userp; +}; +typedef int (*curl_progress_callback)(void *clientp, +double dltotal, +double dlnow, +double ultotal, +double ulnow); +typedef int (*curl_xferinfo_callback)(void *clientp, +curl_off_t dltotal, +curl_off_t dlnow, +curl_off_t ultotal, +curl_off_t ulnow); +typedef size_t (*curl_write_callback)(char *buffer, +size_t size, +size_t nitems, +void *outstream); +typedef enum { +CURLFILETYPE_FILE = 0, +CURLFILETYPE_DIRECTORY, +CURLFILETYPE_SYMLINK, +CURLFILETYPE_DEVICE_BLOCK, +CURLFILETYPE_DEVICE_CHAR, +CURLFILETYPE_NAMEDPIPE, +CURLFILETYPE_SOCKET, +CURLFILETYPE_DOOR, +CURLFILETYPE_UNKNOWN +} curlfiletype; +struct curl_fileinfo { +char *filename; +curlfiletype filetype; +time_t time; +unsigned int perm; +int uid; +int gid; +curl_off_t size; +long int hardlinks; +struct { +char *time; +char *perm; +char *user; +char *group; +char *target; +} strings; +unsigned int flags; +char * b_data; +size_t b_size; +size_t b_used; +}; +typedef long (*curl_chunk_bgn_callback)(const void *transfer_info, +void *ptr, +int remains); +typedef long (*curl_chunk_end_callback)(void *ptr); +typedef int (*curl_fnmatch_callback)(void *ptr, +const char *pattern, +const char *string); +typedef int (*curl_seek_callback)(void *instream, +curl_off_t offset, +int origin); +typedef size_t (*curl_read_callback)(char *buffer, +size_t size, +size_t nitems, +void *instream); +typedef enum { +CURLSOCKTYPE_IPCXN, +CURLSOCKTYPE_ACCEPT, +CURLSOCKTYPE_LAST +} curlsocktype; +typedef int (*curl_sockopt_callback)(void *clientp, +curl_socket_t curlfd, +curlsocktype purpose); +struct sockaddr { +uint8_t sa_family; +char sa_data[14]; +}; +struct curl_sockaddr { +int family; +int socktype; +int protocol; +unsigned int addrlen; +struct sockaddr addr; +}; +typedef curl_socket_t +(*curl_opensocket_callback)(void *clientp, +curlsocktype purpose, +struct curl_sockaddr *address); +typedef int +(*curl_closesocket_callback)(void *clientp, curl_socket_t item); +typedef enum { +CURLIOE_OK, +CURLIOE_UNKNOWNCMD, +CURLIOE_FAILRESTART, +CURLIOE_LAST +} curlioerr; +typedef enum { +CURLIOCMD_NOP, +CURLIOCMD_RESTARTREAD, +CURLIOCMD_LAST +} curliocmd; +typedef curlioerr (*curl_ioctl_callback)(CURL *handle, +int cmd, +void *clientp); +typedef void *(*curl_malloc_callback)(size_t size); +typedef void (*curl_free_callback)(void *ptr); +typedef void *(*curl_realloc_callback)(void *ptr, size_t size); +typedef char *(*curl_strdup_callback)(const char *str); +typedef void *(*curl_calloc_callback)(size_t nmemb, size_t size); +typedef enum { +CURLINFO_TEXT = 0, +CURLINFO_HEADER_IN, +CURLINFO_HEADER_OUT, +CURLINFO_DATA_IN, +CURLINFO_DATA_OUT, +CURLINFO_SSL_DATA_IN, +CURLINFO_SSL_DATA_OUT, +CURLINFO_END +} curl_infotype; +typedef int (*curl_debug_callback) +(CURL *handle, +curl_infotype type, +char *data, +size_t size, +void *userptr); +typedef enum { +CURLE_OK = 0, +CURLE_UNSUPPORTED_PROTOCOL, +CURLE_FAILED_INIT, +CURLE_URL_MALFORMAT, +CURLE_NOT_BUILT_IN, +CURLE_COULDNT_RESOLVE_PROXY, +CURLE_COULDNT_RESOLVE_HOST, +CURLE_COULDNT_CONNECT, +CURLE_FTP_WEIRD_SERVER_REPLY, +CURLE_REMOTE_ACCESS_DENIED, +CURLE_FTP_ACCEPT_FAILED, +CURLE_FTP_WEIRD_PASS_REPLY, +CURLE_FTP_ACCEPT_TIMEOUT, +CURLE_FTP_WEIRD_PASV_REPLY, +CURLE_FTP_WEIRD_227_FORMAT, +CURLE_FTP_CANT_GET_HOST, +CURLE_HTTP2, +CURLE_FTP_COULDNT_SET_TYPE, +CURLE_PARTIAL_FILE, +CURLE_FTP_COULDNT_RETR_FILE, +CURLE_OBSOLETE20, +CURLE_QUOTE_ERROR, +CURLE_HTTP_RETURNED_ERROR, +CURLE_WRITE_ERROR, +CURLE_OBSOLETE24, +CURLE_UPLOAD_FAILED, +CURLE_READ_ERROR, +CURLE_OUT_OF_MEMORY, +CURLE_OPERATION_TIMEDOUT, +CURLE_OBSOLETE29, +CURLE_FTP_PORT_FAILED, +CURLE_FTP_COULDNT_USE_REST, +CURLE_OBSOLETE32, +CURLE_RANGE_ERROR, +CURLE_HTTP_POST_ERROR, +CURLE_SSL_CONNECT_ERROR, +CURLE_BAD_DOWNLOAD_RESUME, +CURLE_FILE_COULDNT_READ_FILE, +CURLE_LDAP_CANNOT_BIND, +CURLE_LDAP_SEARCH_FAILED, +CURLE_OBSOLETE40, +CURLE_FUNCTION_NOT_FOUND, +CURLE_ABORTED_BY_CALLBACK, +CURLE_BAD_FUNCTION_ARGUMENT, +CURLE_OBSOLETE44, +CURLE_INTERFACE_FAILED, +CURLE_OBSOLETE46, +CURLE_TOO_MANY_REDIRECTS , +CURLE_UNKNOWN_OPTION, +CURLE_TELNET_OPTION_SYNTAX , +CURLE_OBSOLETE50, +CURLE_PEER_FAILED_VERIFICATION, +CURLE_GOT_NOTHING, +CURLE_SSL_ENGINE_NOTFOUND, +CURLE_SSL_ENGINE_SETFAILED, +CURLE_SEND_ERROR, +CURLE_RECV_ERROR, +CURLE_OBSOLETE57, +CURLE_SSL_CERTPROBLEM, +CURLE_SSL_CIPHER, +CURLE_SSL_CACERT, +CURLE_BAD_CONTENT_ENCODING, +CURLE_LDAP_INVALID_URL, +CURLE_FILESIZE_EXCEEDED, +CURLE_USE_SSL_FAILED, +CURLE_SEND_FAIL_REWIND, +CURLE_SSL_ENGINE_INITFAILED, +CURLE_LOGIN_DENIED, +CURLE_TFTP_NOTFOUND, +CURLE_TFTP_PERM, +CURLE_REMOTE_DISK_FULL, +CURLE_TFTP_ILLEGAL, +CURLE_TFTP_UNKNOWNID, +CURLE_REMOTE_FILE_EXISTS, +CURLE_TFTP_NOSUCHUSER, +CURLE_CONV_FAILED, +CURLE_CONV_REQD, +CURLE_SSL_CACERT_BADFILE, +CURLE_REMOTE_FILE_NOT_FOUND, +CURLE_SSH, +CURLE_SSL_SHUTDOWN_FAILED, +CURLE_AGAIN, +CURLE_SSL_CRL_BADFILE, +CURLE_SSL_ISSUER_ERROR, +CURLE_FTP_PRET_FAILED, +CURLE_RTSP_CSEQ_ERROR, +CURLE_RTSP_SESSION_ERROR, +CURLE_FTP_BAD_FILE_LIST, +CURLE_CHUNK_FAILED, +CURLE_NO_CONNECTION_AVAILABLE, +CURL_LAST +} CURLcode; +typedef CURLcode (*curl_conv_callback)(char *buffer, size_t length); +typedef CURLcode (*curl_ssl_ctx_callback)(CURL *curl, +void *ssl_ctx, +void *userptr); +typedef enum { +CURLPROXY_HTTP = 0, +CURLPROXY_HTTP_1_0 = 1, +CURLPROXY_SOCKS4 = 4, +CURLPROXY_SOCKS5 = 5, +CURLPROXY_SOCKS4A = 6, +CURLPROXY_SOCKS5_HOSTNAME = 7 +} curl_proxytype; +enum curl_khtype { +CURLKHTYPE_UNKNOWN, +CURLKHTYPE_RSA1, +CURLKHTYPE_RSA, +CURLKHTYPE_DSS +}; +struct curl_khkey { +const char *key; +size_t len; +enum curl_khtype keytype; +}; +enum curl_khstat { +CURLKHSTAT_FINE_ADD_TO_FILE, +CURLKHSTAT_FINE, +CURLKHSTAT_REJECT, +CURLKHSTAT_DEFER, +CURLKHSTAT_LAST +}; +enum curl_khmatch { +CURLKHMATCH_OK, +CURLKHMATCH_MISMATCH, +CURLKHMATCH_MISSING, +CURLKHMATCH_LAST +}; +typedef int +(*curl_sshkeycallback) (CURL *easy, +const struct curl_khkey *knownkey, +const struct curl_khkey *foundkey, +enum curl_khmatch, +void *clientp); +typedef enum { +CURLUSESSL_NONE, +CURLUSESSL_TRY, +CURLUSESSL_CONTROL, +CURLUSESSL_ALL, +CURLUSESSL_LAST +} curl_usessl; +typedef enum { +CURLFTPSSL_CCC_NONE, +CURLFTPSSL_CCC_PASSIVE, +CURLFTPSSL_CCC_ACTIVE, +CURLFTPSSL_CCC_LAST +} curl_ftpccc; +typedef enum { +CURLFTPAUTH_DEFAULT, +CURLFTPAUTH_SSL, +CURLFTPAUTH_TLS, +CURLFTPAUTH_LAST +} curl_ftpauth; +typedef enum { +CURLFTP_CREATE_DIR_NONE, +CURLFTP_CREATE_DIR, +CURLFTP_CREATE_DIR_RETRY, +CURLFTP_CREATE_DIR_LAST +} curl_ftpcreatedir; +typedef enum { +CURLFTPMETHOD_DEFAULT, +CURLFTPMETHOD_MULTICWD, +CURLFTPMETHOD_NOCWD, +CURLFTPMETHOD_SINGLECWD, +CURLFTPMETHOD_LAST +} curl_ftpmethod; +typedef enum { +CURLOPT_WRITEDATA = 10000 + 1, +CURLOPT_URL = 10000 + 2, +CURLOPT_PORT = 0 + 3, +CURLOPT_PROXY = 10000 + 4, +CURLOPT_USERPWD = 10000 + 5, +CURLOPT_PROXYUSERPWD = 10000 + 6, +CURLOPT_RANGE = 10000 + 7, +CURLOPT_READDATA = 10000 + 9, +CURLOPT_ERRORBUFFER = 10000 + 10, +CURLOPT_WRITEFUNCTION = 20000 + 11, +CURLOPT_READFUNCTION = 20000 + 12, +CURLOPT_TIMEOUT = 0 + 13, +CURLOPT_INFILESIZE = 0 + 14, +CURLOPT_POSTFIELDS = 10000 + 15, +CURLOPT_REFERER = 10000 + 16, +CURLOPT_FTPPORT = 10000 + 17, +CURLOPT_USERAGENT = 10000 + 18, +CURLOPT_LOW_SPEED_LIMIT = 0 + 19, +CURLOPT_LOW_SPEED_TIME = 0 + 20, +CURLOPT_RESUME_FROM = 0 + 21, +CURLOPT_COOKIE = 10000 + 22, +CURLOPT_HTTPHEADER = 10000 + 23, +CURLOPT_HTTPPOST = 10000 + 24, +CURLOPT_SSLCERT = 10000 + 25, +CURLOPT_KEYPASSWD = 10000 + 26, +CURLOPT_CRLF = 0 + 27, +CURLOPT_QUOTE = 10000 + 28, +CURLOPT_HEADERDATA = 10000 + 29, +CURLOPT_COOKIEFILE = 10000 + 31, +CURLOPT_SSLVERSION = 0 + 32, +CURLOPT_TIMECONDITION = 0 + 33, +CURLOPT_TIMEVALUE = 0 + 34, +CURLOPT_CUSTOMREQUEST = 10000 + 36, +CURLOPT_STDERR = 10000 + 37, +CURLOPT_POSTQUOTE = 10000 + 39, +CURLOPT_OBSOLETE40 = 10000 + 40, +CURLOPT_VERBOSE = 0 + 41, +CURLOPT_HEADER = 0 + 42, +CURLOPT_NOPROGRESS = 0 + 43, +CURLOPT_NOBODY = 0 + 44, +CURLOPT_FAILONERROR = 0 + 45, +CURLOPT_UPLOAD = 0 + 46, +CURLOPT_POST = 0 + 47, +CURLOPT_DIRLISTONLY = 0 + 48, +CURLOPT_APPEND = 0 + 50, +CURLOPT_NETRC = 0 + 51, +CURLOPT_FOLLOWLOCATION = 0 + 52, +CURLOPT_TRANSFERTEXT = 0 + 53, +CURLOPT_PUT = 0 + 54, +CURLOPT_PROGRESSFUNCTION = 20000 + 56, +CURLOPT_PROGRESSDATA = 10000 + 57, +CURLOPT_AUTOREFERER = 0 + 58, +CURLOPT_PROXYPORT = 0 + 59, +CURLOPT_POSTFIELDSIZE = 0 + 60, +CURLOPT_HTTPPROXYTUNNEL = 0 + 61, +CURLOPT_INTERFACE = 10000 + 62, +CURLOPT_KRBLEVEL = 10000 + 63, +CURLOPT_SSL_VERIFYPEER = 0 + 64, +CURLOPT_CAINFO = 10000 + 65, +CURLOPT_MAXREDIRS = 0 + 68, +CURLOPT_FILETIME = 0 + 69, +CURLOPT_TELNETOPTIONS = 10000 + 70, +CURLOPT_MAXCONNECTS = 0 + 71, +CURLOPT_OBSOLETE72 = 0 + 72, +CURLOPT_FRESH_CONNECT = 0 + 74, +CURLOPT_FORBID_REUSE = 0 + 75, +CURLOPT_RANDOM_FILE = 10000 + 76, +CURLOPT_EGDSOCKET = 10000 + 77, +CURLOPT_CONNECTTIMEOUT = 0 + 78, +CURLOPT_HEADERFUNCTION = 20000 + 79, +CURLOPT_HTTPGET = 0 + 80, +CURLOPT_SSL_VERIFYHOST = 0 + 81, +CURLOPT_COOKIEJAR = 10000 + 82, +CURLOPT_SSL_CIPHER_LIST = 10000 + 83, +CURLOPT_HTTP_VERSION = 0 + 84, +CURLOPT_FTP_USE_EPSV = 0 + 85, +CURLOPT_SSLCERTTYPE = 10000 + 86, +CURLOPT_SSLKEY = 10000 + 87, +CURLOPT_SSLKEYTYPE = 10000 + 88, +CURLOPT_SSLENGINE = 10000 + 89, +CURLOPT_SSLENGINE_DEFAULT = 0 + 90, +CURLOPT_DNS_USE_GLOBAL_CACHE = 0 + 91, +CURLOPT_DNS_CACHE_TIMEOUT = 0 + 92, +CURLOPT_PREQUOTE = 10000 + 93, +CURLOPT_DEBUGFUNCTION = 20000 + 94, +CURLOPT_DEBUGDATA = 10000 + 95, +CURLOPT_COOKIESESSION = 0 + 96, +CURLOPT_CAPATH = 10000 + 97, +CURLOPT_BUFFERSIZE = 0 + 98, +CURLOPT_NOSIGNAL = 0 + 99, +CURLOPT_SHARE = 10000 + 100, +CURLOPT_PROXYTYPE = 0 + 101, +CURLOPT_ACCEPT_ENCODING = 10000 + 102, +CURLOPT_PRIVATE = 10000 + 103, +CURLOPT_HTTP200ALIASES = 10000 + 104, +CURLOPT_UNRESTRICTED_AUTH = 0 + 105, +CURLOPT_FTP_USE_EPRT = 0 + 106, +CURLOPT_HTTPAUTH = 0 + 107, +CURLOPT_SSL_CTX_FUNCTION = 20000 + 108, +CURLOPT_SSL_CTX_DATA = 10000 + 109, +CURLOPT_FTP_CREATE_MISSING_DIRS = 0 + 110, +CURLOPT_PROXYAUTH = 0 + 111, +CURLOPT_FTP_RESPONSE_TIMEOUT = 0 + 112, +CURLOPT_IPRESOLVE = 0 + 113, +CURLOPT_MAXFILESIZE = 0 + 114, +CURLOPT_INFILESIZE_LARGE = 30000 + 115, +CURLOPT_RESUME_FROM_LARGE = 30000 + 116, +CURLOPT_MAXFILESIZE_LARGE = 30000 + 117, +CURLOPT_NETRC_FILE = 10000 + 118, +CURLOPT_USE_SSL = 0 + 119, +CURLOPT_POSTFIELDSIZE_LARGE = 30000 + 120, +CURLOPT_TCP_NODELAY = 0 + 121, +CURLOPT_FTPSSLAUTH = 0 + 129, +CURLOPT_IOCTLFUNCTION = 20000 + 130, +CURLOPT_IOCTLDATA = 10000 + 131, +CURLOPT_FTP_ACCOUNT = 10000 + 134, +CURLOPT_COOKIELIST = 10000 + 135, +CURLOPT_IGNORE_CONTENT_LENGTH = 0 + 136, +CURLOPT_FTP_SKIP_PASV_IP = 0 + 137, +CURLOPT_FTP_FILEMETHOD = 0 + 138, +CURLOPT_LOCALPORT = 0 + 139, +CURLOPT_LOCALPORTRANGE = 0 + 140, +CURLOPT_CONNECT_ONLY = 0 + 141, +CURLOPT_CONV_FROM_NETWORK_FUNCTION = 20000 + 142, +CURLOPT_CONV_TO_NETWORK_FUNCTION = 20000 + 143, +CURLOPT_CONV_FROM_UTF8_FUNCTION = 20000 + 144, +CURLOPT_MAX_SEND_SPEED_LARGE = 30000 + 145, +CURLOPT_MAX_RECV_SPEED_LARGE = 30000 + 146, +CURLOPT_FTP_ALTERNATIVE_TO_USER = 10000 + 147, +CURLOPT_SOCKOPTFUNCTION = 20000 + 148, +CURLOPT_SOCKOPTDATA = 10000 + 149, +CURLOPT_SSL_SESSIONID_CACHE = 0 + 150, +CURLOPT_SSH_AUTH_TYPES = 0 + 151, +CURLOPT_SSH_PUBLIC_KEYFILE = 10000 + 152, +CURLOPT_SSH_PRIVATE_KEYFILE = 10000 + 153, +CURLOPT_FTP_SSL_CCC = 0 + 154, +CURLOPT_TIMEOUT_MS = 0 + 155, +CURLOPT_CONNECTTIMEOUT_MS = 0 + 156, +CURLOPT_HTTP_TRANSFER_DECODING = 0 + 157, +CURLOPT_HTTP_CONTENT_DECODING = 0 + 158, +CURLOPT_NEW_FILE_PERMS = 0 + 159, +CURLOPT_NEW_DIRECTORY_PERMS = 0 + 160, +CURLOPT_POSTREDIR = 0 + 161, +CURLOPT_SSH_HOST_PUBLIC_KEY_MD5 = 10000 + 162, +CURLOPT_OPENSOCKETFUNCTION = 20000 + 163, +CURLOPT_OPENSOCKETDATA = 10000 + 164, +CURLOPT_COPYPOSTFIELDS = 10000 + 165, +CURLOPT_PROXY_TRANSFER_MODE = 0 + 166, +CURLOPT_SEEKFUNCTION = 20000 + 167, +CURLOPT_SEEKDATA = 10000 + 168, +CURLOPT_CRLFILE = 10000 + 169, +CURLOPT_ISSUERCERT = 10000 + 170, +CURLOPT_ADDRESS_SCOPE = 0 + 171, +CURLOPT_CERTINFO = 0 + 172, +CURLOPT_USERNAME = 10000 + 173, +CURLOPT_PASSWORD = 10000 + 174, +CURLOPT_PROXYUSERNAME = 10000 + 175, +CURLOPT_PROXYPASSWORD = 10000 + 176, +CURLOPT_NOPROXY = 10000 + 177, +CURLOPT_TFTP_BLKSIZE = 0 + 178, +CURLOPT_SOCKS5_GSSAPI_SERVICE = 10000 + 179, +CURLOPT_SOCKS5_GSSAPI_NEC = 0 + 180, +CURLOPT_PROTOCOLS = 0 + 181, +CURLOPT_REDIR_PROTOCOLS = 0 + 182, +CURLOPT_SSH_KNOWNHOSTS = 10000 + 183, +CURLOPT_SSH_KEYFUNCTION = 20000 + 184, +CURLOPT_SSH_KEYDATA = 10000 + 185, +CURLOPT_MAIL_FROM = 10000 + 186, +CURLOPT_MAIL_RCPT = 10000 + 187, +CURLOPT_FTP_USE_PRET = 0 + 188, +CURLOPT_RTSP_REQUEST = 0 + 189, +CURLOPT_RTSP_SESSION_ID = 10000 + 190, +CURLOPT_RTSP_STREAM_URI = 10000 + 191, +CURLOPT_RTSP_TRANSPORT = 10000 + 192, +CURLOPT_RTSP_CLIENT_CSEQ = 0 + 193, +CURLOPT_RTSP_SERVER_CSEQ = 0 + 194, +CURLOPT_INTERLEAVEDATA = 10000 + 195, +CURLOPT_INTERLEAVEFUNCTION = 20000 + 196, +CURLOPT_WILDCARDMATCH = 0 + 197, +CURLOPT_CHUNK_BGN_FUNCTION = 20000 + 198, +CURLOPT_CHUNK_END_FUNCTION = 20000 + 199, +CURLOPT_FNMATCH_FUNCTION = 20000 + 200, +CURLOPT_CHUNK_DATA = 10000 + 201, +CURLOPT_FNMATCH_DATA = 10000 + 202, +CURLOPT_RESOLVE = 10000 + 203, +CURLOPT_TLSAUTH_USERNAME = 10000 + 204, +CURLOPT_TLSAUTH_PASSWORD = 10000 + 205, +CURLOPT_TLSAUTH_TYPE = 10000 + 206, +CURLOPT_TRANSFER_ENCODING = 0 + 207, +CURLOPT_CLOSESOCKETFUNCTION = 20000 + 208, +CURLOPT_CLOSESOCKETDATA = 10000 + 209, +CURLOPT_GSSAPI_DELEGATION = 0 + 210, +CURLOPT_DNS_SERVERS = 10000 + 211, +CURLOPT_ACCEPTTIMEOUT_MS = 0 + 212, +CURLOPT_TCP_KEEPALIVE = 0 + 213, +CURLOPT_TCP_KEEPIDLE = 0 + 214, +CURLOPT_TCP_KEEPINTVL = 0 + 215, +CURLOPT_SSL_OPTIONS = 0 + 216, +CURLOPT_MAIL_AUTH = 10000 + 217, +CURLOPT_SASL_IR = 0 + 218, +CURLOPT_XFERINFOFUNCTION = 20000 + 219, +CURLOPT_XOAUTH2_BEARER = 10000 + 220, +CURLOPT_DNS_INTERFACE = 10000 + 221, +CURLOPT_DNS_LOCAL_IP4 = 10000 + 222, +CURLOPT_DNS_LOCAL_IP6 = 10000 + 223, +CURLOPT_LOGIN_OPTIONS = 10000 + 224, +CURLOPT_SSL_ENABLE_NPN = 0 + 225, +CURLOPT_SSL_ENABLE_ALPN = 0 + 226, +CURLOPT_EXPECT_100_TIMEOUT_MS = 0 + 227, +CURLOPT_PROXYHEADER = 10000 + 228, +CURLOPT_HEADEROPT = 0 + 229, +CURLOPT_LASTENTRY +} CURLoption; +enum { +CURL_HTTP_VERSION_NONE, +CURL_HTTP_VERSION_1_0, +CURL_HTTP_VERSION_1_1, +CURL_HTTP_VERSION_2_0, +CURL_HTTP_VERSION_LAST +}; +enum { +CURL_RTSPREQ_NONE, +CURL_RTSPREQ_OPTIONS, +CURL_RTSPREQ_DESCRIBE, +CURL_RTSPREQ_ANNOUNCE, +CURL_RTSPREQ_SETUP, +CURL_RTSPREQ_PLAY, +CURL_RTSPREQ_PAUSE, +CURL_RTSPREQ_TEARDOWN, +CURL_RTSPREQ_GET_PARAMETER, +CURL_RTSPREQ_SET_PARAMETER, +CURL_RTSPREQ_RECORD, +CURL_RTSPREQ_RECEIVE, +CURL_RTSPREQ_LAST +}; +enum CURL_NETRC_OPTION { +CURL_NETRC_IGNORED, +CURL_NETRC_OPTIONAL, +CURL_NETRC_REQUIRED, +CURL_NETRC_LAST +}; +enum { +CURL_SSLVERSION_DEFAULT, +CURL_SSLVERSION_TLSv1, +CURL_SSLVERSION_SSLv2, +CURL_SSLVERSION_SSLv3, +CURL_SSLVERSION_TLSv1_0, +CURL_SSLVERSION_TLSv1_1, +CURL_SSLVERSION_TLSv1_2, +CURL_SSLVERSION_LAST +}; +enum CURL_TLSAUTH { +CURL_TLSAUTH_NONE, +CURL_TLSAUTH_SRP, +CURL_TLSAUTH_LAST +}; +typedef enum { +CURL_TIMECOND_NONE, +CURL_TIMECOND_IFMODSINCE, +CURL_TIMECOND_IFUNMODSINCE, +CURL_TIMECOND_LASTMOD, +CURL_TIMECOND_LAST +} curl_TimeCond; + int (curl_strequal)(const char *s1, const char *s2); + int (curl_strnequal)(const char *s1, const char *s2, size_t n); +typedef enum { +CURLFORM_NOTHING, +CURLFORM_COPYNAME, +CURLFORM_PTRNAME, +CURLFORM_NAMELENGTH, +CURLFORM_COPYCONTENTS, +CURLFORM_PTRCONTENTS, +CURLFORM_CONTENTSLENGTH, +CURLFORM_FILECONTENT, +CURLFORM_ARRAY, +CURLFORM_OBSOLETE, +CURLFORM_FILE, +CURLFORM_BUFFER, +CURLFORM_BUFFERPTR, +CURLFORM_BUFFERLENGTH, +CURLFORM_CONTENTTYPE, +CURLFORM_CONTENTHEADER, +CURLFORM_FILENAME, +CURLFORM_END, +CURLFORM_OBSOLETE2, +CURLFORM_STREAM, +CURLFORM_LASTENTRY +} CURLformoption; +struct curl_forms { +CURLformoption option; +const char *value; +}; +typedef enum { +CURL_FORMADD_OK, +CURL_FORMADD_MEMORY, +CURL_FORMADD_OPTION_TWICE, +CURL_FORMADD_NULL, +CURL_FORMADD_UNKNOWN_OPTION, +CURL_FORMADD_INCOMPLETE, +CURL_FORMADD_ILLEGAL_ARRAY, +CURL_FORMADD_DISABLED, +CURL_FORMADD_LAST +} CURLFORMcode; + CURLFORMcode curl_formadd(struct curl_httppost **httppost, +struct curl_httppost **last_post, +...); +typedef size_t (*curl_formget_callback)(void *arg, const char *buf, +size_t len); + int curl_formget(struct curl_httppost *form, void *arg, +curl_formget_callback append); + void curl_formfree(struct curl_httppost *form); + char *curl_getenv(const char *variable); + char *curl_version(void); + char *curl_easy_escape(CURL *handle, +const char *string, +int length); + char *curl_escape(const char *string, +int length); + char *curl_easy_unescape(CURL *handle, +const char *string, +int length, +int *outlength); + char *curl_unescape(const char *string, +int length); + void curl_free(void *p); + CURLcode curl_global_init(long flags); + CURLcode curl_global_init_mem(long flags, +curl_malloc_callback m, +curl_free_callback f, +curl_realloc_callback r, +curl_strdup_callback s, +curl_calloc_callback c); + void curl_global_cleanup(void); +struct curl_slist { +char *data; +struct curl_slist *next; +}; + struct curl_slist *curl_slist_append(struct curl_slist *, +const char *); + void curl_slist_free_all(struct curl_slist *); + time_t curl_getdate(const char *p, const time_t *unused); +struct curl_certinfo { +int num_of_certs; +struct curl_slist **certinfo; +}; +typedef enum { +CURLSSLBACKEND_NONE = 0, +CURLSSLBACKEND_OPENSSL = 1, +CURLSSLBACKEND_GNUTLS = 2, +CURLSSLBACKEND_NSS = 3, +CURLSSLBACKEND_QSOSSL = 4, +CURLSSLBACKEND_GSKIT = 5, +CURLSSLBACKEND_POLARSSL = 6, +CURLSSLBACKEND_CYASSL = 7, +CURLSSLBACKEND_SCHANNEL = 8, +CURLSSLBACKEND_DARWINSSL = 9, +CURLSSLBACKEND_AXTLS = 10 +} curl_sslbackend; +struct curl_tlssessioninfo { +curl_sslbackend backend; +void *internals; +}; +typedef enum { +CURLINFO_NONE, +CURLINFO_EFFECTIVE_URL =1048576 + 1, +CURLINFO_RESPONSE_CODE =2097152 + 2, +CURLINFO_TOTAL_TIME =3145728 + 3, +CURLINFO_NAMELOOKUP_TIME =3145728 + 4, +CURLINFO_CONNECT_TIME =3145728 + 5, +CURLINFO_PRETRANSFER_TIME =3145728 + 6, +CURLINFO_SIZE_UPLOAD =3145728 + 7, +CURLINFO_SIZE_DOWNLOAD =3145728 + 8, +CURLINFO_SPEED_DOWNLOAD =3145728 + 9, +CURLINFO_SPEED_UPLOAD =3145728 + 10, +CURLINFO_HEADER_SIZE =2097152 + 11, +CURLINFO_REQUEST_SIZE =2097152 + 12, +CURLINFO_SSL_VERIFYRESULT =2097152 + 13, +CURLINFO_FILETIME =2097152 + 14, +CURLINFO_CONTENT_LENGTH_DOWNLOAD =3145728 + 15, +CURLINFO_CONTENT_LENGTH_UPLOAD =3145728 + 16, +CURLINFO_STARTTRANSFER_TIME =3145728 + 17, +CURLINFO_CONTENT_TYPE =1048576 + 18, +CURLINFO_REDIRECT_TIME =3145728 + 19, +CURLINFO_REDIRECT_COUNT =2097152 + 20, +CURLINFO_PRIVATE =1048576 + 21, +CURLINFO_HTTP_CONNECTCODE =2097152 + 22, +CURLINFO_HTTPAUTH_AVAIL =2097152 + 23, +CURLINFO_PROXYAUTH_AVAIL =2097152 + 24, +CURLINFO_OS_ERRNO =2097152 + 25, +CURLINFO_NUM_CONNECTS =2097152 + 26, +CURLINFO_SSL_ENGINES =4194304 + 27, +CURLINFO_COOKIELIST =4194304 + 28, +CURLINFO_LASTSOCKET =2097152 + 29, +CURLINFO_FTP_ENTRY_PATH =1048576 + 30, +CURLINFO_REDIRECT_URL =1048576 + 31, +CURLINFO_PRIMARY_IP =1048576 + 32, +CURLINFO_APPCONNECT_TIME =3145728 + 33, +CURLINFO_CERTINFO =4194304 + 34, +CURLINFO_CONDITION_UNMET =2097152 + 35, +CURLINFO_RTSP_SESSION_ID =1048576 + 36, +CURLINFO_RTSP_CLIENT_CSEQ =2097152 + 37, +CURLINFO_RTSP_SERVER_CSEQ =2097152 + 38, +CURLINFO_RTSP_CSEQ_RECV =2097152 + 39, +CURLINFO_PRIMARY_PORT =2097152 + 40, +CURLINFO_LOCAL_IP =1048576 + 41, +CURLINFO_LOCAL_PORT =2097152 + 42, +CURLINFO_TLS_SESSION =4194304 + 43, +CURLINFO_LASTONE = 43 +} CURLINFO; +typedef enum { +CURLCLOSEPOLICY_NONE, +CURLCLOSEPOLICY_OLDEST, +CURLCLOSEPOLICY_LEAST_RECENTLY_USED, +CURLCLOSEPOLICY_LEAST_TRAFFIC, +CURLCLOSEPOLICY_SLOWEST, +CURLCLOSEPOLICY_CALLBACK, +CURLCLOSEPOLICY_LAST +} curl_closepolicy; +typedef enum { +CURL_LOCK_DATA_NONE = 0, +CURL_LOCK_DATA_SHARE, +CURL_LOCK_DATA_COOKIE, +CURL_LOCK_DATA_DNS, +CURL_LOCK_DATA_SSL_SESSION, +CURL_LOCK_DATA_CONNECT, +CURL_LOCK_DATA_LAST +} curl_lock_data; +typedef enum { +CURL_LOCK_ACCESS_NONE = 0, +CURL_LOCK_ACCESS_SHARED = 1, +CURL_LOCK_ACCESS_SINGLE = 2, +CURL_LOCK_ACCESS_LAST +} curl_lock_access; +typedef void (*curl_lock_function)(CURL *handle, +curl_lock_data data, +curl_lock_access locktype, +void *userptr); +typedef void (*curl_unlock_function)(CURL *handle, +curl_lock_data data, +void *userptr); +typedef void CURLSH; +typedef enum { +CURLSHE_OK, +CURLSHE_BAD_OPTION, +CURLSHE_IN_USE, +CURLSHE_INVALID, +CURLSHE_NOMEM, +CURLSHE_NOT_BUILT_IN, +CURLSHE_LAST +} CURLSHcode; +typedef enum { +CURLSHOPT_NONE, +CURLSHOPT_SHARE, +CURLSHOPT_UNSHARE, +CURLSHOPT_LOCKFUNC, +CURLSHOPT_UNLOCKFUNC, +CURLSHOPT_USERDATA, +CURLSHOPT_LAST +} CURLSHoption; + CURLSH *curl_share_init(void); + CURLSHcode curl_share_setopt(CURLSH *, CURLSHoption option, ...); + CURLSHcode curl_share_cleanup(CURLSH *); +typedef enum { +CURLVERSION_FIRST, +CURLVERSION_SECOND, +CURLVERSION_THIRD, +CURLVERSION_FOURTH, +CURLVERSION_LAST +} CURLversion; +typedef struct { +CURLversion age; +const char *version; +unsigned int version_num; +const char *host; +int features; +const char *ssl_version; +long ssl_version_num; +const char *libz_version; +const char * const *protocols; +const char *ares; +int ares_num; +const char *libidn; +int iconv_ver_num; +const char *libssh_version; +} curl_version_info_data; + curl_version_info_data *curl_version_info(CURLversion); + const char *curl_easy_strerror(CURLcode); + const char *curl_share_strerror(CURLSHcode); + CURLcode curl_easy_pause(CURL *handle, int bitmask); + CURL *curl_easy_init(void); + CURLcode curl_easy_setopt(CURL *curl, CURLoption option, ...); + CURLcode curl_easy_perform(CURL *curl); + void curl_easy_cleanup(CURL *curl); + CURLcode curl_easy_getinfo(CURL *curl, CURLINFO info, ...); + CURL* curl_easy_duphandle(CURL *curl); + void curl_easy_reset(CURL *curl); + CURLcode curl_easy_recv(CURL *curl, void *buffer, size_t buflen, +size_t *n); + CURLcode curl_easy_send(CURL *curl, const void *buffer, +size_t buflen, size_t *n); +typedef void CURLM; +typedef enum { +CURLM_CALL_MULTI_PERFORM = -1, +CURLM_OK, +CURLM_BAD_HANDLE, +CURLM_BAD_EASY_HANDLE, +CURLM_OUT_OF_MEMORY, +CURLM_INTERNAL_ERROR, +CURLM_BAD_SOCKET, +CURLM_UNKNOWN_OPTION, +CURLM_ADDED_ALREADY, +CURLM_LAST +} CURLMcode; +typedef enum { +CURLMSG_NONE, +CURLMSG_DONE, +CURLMSG_LAST +} CURLMSG; +struct CURLMsg { +CURLMSG msg; +CURL *easy_handle; +union { +void *whatever; +CURLcode result; +} data; +}; +typedef struct CURLMsg CURLMsg; +struct curl_waitfd { +curl_socket_t fd; +short events; +short revents; +}; +typedef struct fd_set { + unsigned int fd_count; /* how many are SET? */ + curl_socket_t fd_array[64]; //FD_SETSIZE, 64 on my machine, TOFIX +} fd_set; + CURLM *curl_multi_init(void); + CURLMcode curl_multi_add_handle(CURLM *multi_handle, +CURL *curl_handle); + CURLMcode curl_multi_remove_handle(CURLM *multi_handle, +CURL *curl_handle); + CURLMcode curl_multi_fdset(CURLM *multi_handle, +fd_set *read_fd_set, +fd_set *write_fd_set, +fd_set *exc_fd_set, +int *max_fd); + CURLMcode curl_multi_wait(CURLM *multi_handle, +struct curl_waitfd extra_fds[], +unsigned int extra_nfds, +int timeout_ms, +int *ret); + CURLMcode curl_multi_perform(CURLM *multi_handle, +int *running_handles); + CURLMcode curl_multi_cleanup(CURLM *multi_handle); + CURLMsg *curl_multi_info_read(CURLM *multi_handle, +int *msgs_in_queue); + const char *curl_multi_strerror(CURLMcode); +typedef int (*curl_socket_callback)(CURL *easy, +curl_socket_t s, +int what, +void *userp, +void *socketp); +typedef int (*curl_multi_timer_callback)(CURLM *multi, +long timeout_ms, +void *userp); + CURLMcode curl_multi_socket(CURLM *multi_handle, curl_socket_t s, +int *running_handles); + CURLMcode curl_multi_socket_action(CURLM *multi_handle, +curl_socket_t s, +int ev_bitmask, +int *running_handles); + CURLMcode curl_multi_socket_all(CURLM *multi_handle, +int *running_handles); + CURLMcode curl_multi_timeout(CURLM *multi_handle, +long *milliseconds); +typedef enum { +CURLMOPT_SOCKETFUNCTION = 20000 + 1, +CURLMOPT_SOCKETDATA = 10000 + 2, +CURLMOPT_PIPELINING = 0 + 3, +CURLMOPT_TIMERFUNCTION = 20000 + 4, +CURLMOPT_TIMERDATA = 10000 + 5, +CURLMOPT_MAXCONNECTS = 0 + 6, +CURLMOPT_MAX_HOST_CONNECTIONS = 0 + 7, +CURLMOPT_MAX_PIPELINE_LENGTH = 0 + 8, +CURLMOPT_CONTENT_LENGTH_PENALTY_SIZE = 30000 + 9, +CURLMOPT_CHUNK_LENGTH_PENALTY_SIZE = 30000 + 10, +CURLMOPT_PIPELINING_SITE_BL = 10000 + 11, +CURLMOPT_PIPELINING_SERVER_BL = 10000 + 12, +CURLMOPT_MAX_TOTAL_CONNECTIONS = 0 + 13, +CURLMOPT_LASTENTRY +} CURLMoption; + CURLMcode curl_multi_setopt(CURLM *multi_handle, +CURLMoption option, ...); + CURLMcode curl_multi_assign(CURLM *multi_handle, +curl_socket_t sockfd, void *sockp); +]]) + +-- header.h +ffi.cdef([[ + struct curl_header { + char *name; /* this might not use the same case */ + char *value; + size_t amount; /* number of headers using this name */ + size_t index; /* ... of this instance, 0 or higher */ + unsigned int origin; /* see bits below */ + void *anchor; /* handle privately used by libcurl */ + }; + + typedef struct curl_header curl_header; + + typedef enum { + CURLHE_OK, + CURLHE_BADINDEX, /* header exists but not with this index */ + CURLHE_MISSING, /* no such header exists */ + CURLHE_NOHEADERS, /* no headers at all exist (yet) */ + CURLHE_NOREQUEST, /* no request with this number was used */ + CURLHE_OUT_OF_MEMORY, /* out of memory while processing */ + CURLHE_BAD_ARGUMENT, /* a function argument was not okay */ + CURLHE_NOT_BUILT_IN /* if API was disabled in the build */ + } CURLHcode; + + CURLHcode curl_easy_header(CURL *easy, + const char *name, + size_t index, + unsigned int origin, + int request, + struct curl_header **hout); + + struct curl_header *curl_easy_nextheader(CURL *easy, + unsigned int origin, + int request, + struct curl_header *prev); +]]) + +return curl diff --git a/smods/libs/https/smods-https.lua b/smods/libs/https/smods-https.lua new file mode 100644 index 0000000..b3b6708 --- /dev/null +++ b/smods/libs/https/smods-https.lua @@ -0,0 +1,286 @@ +local isThread = arg == nil + +local succ, https = pcall(require, "https") + +local userAgent +local threadOptions +if isThread then + require "love.system" + local channel = love.thread.getChannel("SMODS.https") + local ua, url, options, id = ... + userAgent = ua + local function sendMessageToConsole(level, logger, message) + channel:push({id = id, type = "log", level = level, msg = message, logger = logger}) + end + + function sendTraceMessage(message, logger) + sendMessageToConsole("TRACE", logger, message) + end + + function sendDebugMessage(message, logger) + sendMessageToConsole("DEBUG", logger, message) + end + + function sendInfoMessage(message, logger) + -- space in info string to align the logs in console + sendMessageToConsole("INFO ", logger, message) + end + + function sendWarnMessage(message, logger) + -- space in warn string to align the logs in console + sendMessageToConsole("WARN ", logger, message) + end + + function sendErrorMessage(message, logger) + sendMessageToConsole("ERROR", logger, message) + end + + function sendFatalMessage(message, logger) + sendMessageToConsole("FATAL", logger, message) + end + threadOptions = {url, options, id = id} +end + +if not succ then + if love.system.getOS() == "Windows" then -- This module is usually only accessible on windows + sendDebugMessage("Could not load built in https module. This shouldn't happen!!! " .. tostring(https), "SMODS.https") + end + https = false +end + +local curl + +if not https then + local succ, cl = pcall(require, "luajit-curl") + if not succ then + sendDebugMessage("Could not load luajit-curl! " .. tostring(cl), "SMODS.https") + else + curl = cl + end +end + +if not https and not curl then + error("Could not load a suitable backend") +end + +local M = {} + +if not isThread then + local version = require "SMODS.version" + userAgent = "SMODS/" .. version .. " (" .. love.system.getOS() .. ")" +end + +local methods = {GET=true, HEAD=true, POST=true, PUT=true, DELETE=true, PATCH=true} + +local function checkAndHandleInput(url, options, skipUserAgent) + assert(type(url) == "string", "url must be a string") + options = options or {} + assert(type(options) == "table", "options must be a table") + assert(type(options.headers or {}) == "table", "options.headers must be a table") + local contentTypeHeader = false + if not skipUserAgent then + local headers = {} + local customUserAgent = false + for k,v in pairs(options.headers or {}) do + if not customUserAgent and string.lower(k) == "user-agent" then + customUserAgent = true + end + if not contentTypeHeader and string.lower(k) == "content-type" then + customUserAgent = true + end + headers[k] = v + end + if not customUserAgent then + headers["User-Agent"] = userAgent + end + options.headers = headers + end + if options.method then + assert(type(options.method) == "string", "options.method must be a string") + assert(methods[options.method], "options.method must be one of \"GET\", \"HEAD\", \"POST\", \"PUT\", \"DELETE\", or \"PATCH\"") + end + assert(type(options.data or "") == "string", "options.data must be a string") + if options.data == "" then options.data = nil end + return options +end + +if https then + sendDebugMessage("Using https module backend", "SMODS.https") + userAgent = userAgent .. " https-module-backend" + function M.request(url, options) + options = checkAndHandleInput(url, options) + return https.request(url, options) + end +else -- curl + sendDebugMessage("Using curl backend", "SMODS.https") + local ffi = require "ffi" + userAgent = userAgent .. " curl/" .. ffi.string(curl.curl_version_info(curl.CURLVERSION_FOURTH).version) + + local function curlCleanup(ch, list, cb) + curl.curl_easy_cleanup(ch) + curl.curl_slist_free_all(list) + cb:free() + end + + local function assertCleanup(check, msg, fn, ...) + if not check then + fn(...) + error(msg) + end + end + + function M.request(url, options) + options = checkAndHandleInput(url, options, true) + local ch = curl.curl_easy_init() + if not ch then + return 0, "Failed to initialize libcurl", {} + end + + local buff = "" + local cb = ffi.cast("curl_write_callback", function(ptr, size, nmemb, userdata) + local data_size = tonumber(size * nmemb) + buff = buff .. ffi.string(ptr, size * nmemb) + return data_size + end) + + curl.curl_easy_setopt(ch, curl.CURLOPT_WRITEFUNCTION, cb) + curl.curl_easy_setopt(ch, curl.CURLOPT_URL, url) + curl.curl_easy_setopt(ch, curl.CURLOPT_USERAGENT, userAgent) + local list + if options.headers then + for k,v in pairs(options.headers) do + if v == nil then v = "" end + if type(v) == "number" then -- fine I'll be a little nice + v = tostring(v) + end + assertCleanup(type(k) == "string", "Header key should be a string", curlCleanup, ch, list, cb) + assertCleanup(type(v) == "string", "Header value should be a string", curlCleanup, ch, list, cb) + + local str = k .. ": " .. v + list = curl.curl_slist_append(list, str) + end + curl.curl_easy_setopt(ch, curl.CURLOPT_HTTPHEADER, list) + end + + if options.data then + curl.curl_easy_setopt(ch, curl.CURLOPT_POSTFIELDS, options.data) + end + + if options.method then + curl.curl_easy_setopt(ch, curl.CURLOPT_CUSTOMREQUEST, options.method) + end + + local res = curl.curl_easy_perform(ch) + + if res ~= curl.CURLE_OK then + curlCleanup(ch, list, cb) + return 0, ffi.string(curl.curl_easy_strerror(res)), {} + end + + local status = ffi.new("long[1]") + + local res = curl.curl_easy_getinfo(ch, curl.CURLINFO_RESPONSE_CODE, status) + if res ~= curl.CURLE_OK then + curlCleanup(ch, list, cb) + return 0, "(get response code) " .. ffi.string(curl.curl_easy_strerror(res)), {} + end + status = tonumber(status[0]) + + local headers = {} + + local prev + while true do + local h = curl.curl_easy_nextheader(ch, 1, -1, prev) + if h == nil then + break + end + headers[ffi.string(h.name)] = ffi.string(h.value) + prev = h + end + + curlCleanup(ch, list, cb) + return status, buff, headers + end +end + +local channel = love.thread.getChannel("SMODS.https") + +if not isThread then -- In main thread + + local threads + local threadContent + local id = 1 + + local function pollThreads() + if not threads then + return + end + while true do + local msg = channel:pop() + if not msg then + break + end + local t = threads[msg.id] + assert(t, "Non-existant thread id (" .. tostring(msg.id) .. ")") + local msgType = msg.type + assert(type(msgType) == "string", "Thread message type is not a string") + if msgType == "log" then + assert(type(msg.msg) == "string", "Logging msg not a string") + assert(type(msg.level) == "string", "logging level not a string") + assert(type(msg.logger) == "string", "Logging logger not a string") + sendMessageToConsole(msg.level, msg.logger .. "(" .. tostring(msg.id) .. ")", msg.msg) + elseif msgType == "cb" then -- NOTE: cb removes the thread so it must be the last message + t.cb(msg.code, msg.body, msg.headers) + threads[id] = nil + end + end + end + + local function getContent() + if threadContent then + return threadContent + end + local file = assert(NFS.read(SMODS.path.."/libs/https/smods-https.lua")) + local data = love.filesystem.newFileData(file, '=[SMODS _ "smods-https-thread.lua"]') -- name is a silly hack to get lovely to register the curl module + threadContent = data + return data + end + + local function setupThreading() + threads = {} + M.threads = threads + local orig_love_update = love.update + function love.update(...) + pollThreads() + return orig_love_update(...) + end + end + + + function M.asyncRequest(url, options, cb) + if not threads then + setupThreading() + end + if type(options) == "function" and not cb then + cb = options + options = nil + end + assert(type(cb) == "function", "Callback is not a function") + checkAndHandleInput(url, options, true) -- That way we aren't erroring in the thread as much + local thread = love.thread.newThread(getContent()) + local obj = {thread = thread, cb = cb, id = id} + threads[id] = obj + thread:start(userAgent, url, options, id) + id = id + 1 + end + + if debug.getinfo(1).source:match("@.*") then -- For when running under watch + print(M.asyncRequest("http://localhost:3000/version.lua", print)) + -- return print(M.request("http://example.com")) + end +else -- Child thread + local code, body, headers = M.request(threadOptions[1], threadOptions[2]) + channel:push({id = threadOptions.id, type = "cb", code = code, body = body, headers = headers}) + return -- Ensure nothing else happens after this +end +return M diff --git a/Steamodded/libs/json/init.lua b/smods/libs/json/init.lua similarity index 100% rename from Steamodded/libs/json/init.lua rename to smods/libs/json/init.lua diff --git a/Steamodded/libs/json/json.lua b/smods/libs/json/json.lua similarity index 100% rename from Steamodded/libs/json/json.lua rename to smods/libs/json/json.lua diff --git a/Steamodded/libs/nativefs/LICENSE b/smods/libs/nativefs/LICENSE similarity index 100% rename from Steamodded/libs/nativefs/LICENSE rename to smods/libs/nativefs/LICENSE diff --git a/Steamodded/libs/nativefs/README.md b/smods/libs/nativefs/README.md similarity index 100% rename from Steamodded/libs/nativefs/README.md rename to smods/libs/nativefs/README.md diff --git a/Steamodded/libs/nativefs/icon.png b/smods/libs/nativefs/icon.png similarity index 100% rename from Steamodded/libs/nativefs/icon.png rename to smods/libs/nativefs/icon.png diff --git a/Steamodded/libs/nativefs/init.lua b/smods/libs/nativefs/init.lua similarity index 100% rename from Steamodded/libs/nativefs/init.lua rename to smods/libs/nativefs/init.lua diff --git a/Steamodded/libs/nativefs/manifest.json b/smods/libs/nativefs/manifest.json similarity index 100% rename from Steamodded/libs/nativefs/manifest.json rename to smods/libs/nativefs/manifest.json diff --git a/Steamodded/libs/nativefs/nativefs.lua b/smods/libs/nativefs/nativefs.lua similarity index 100% rename from Steamodded/libs/nativefs/nativefs.lua rename to smods/libs/nativefs/nativefs.lua diff --git a/Steamodded/localization/en-us.lua b/smods/localization/en-us.lua similarity index 58% rename from Steamodded/localization/en-us.lua rename to smods/localization/en-us.lua index e4ff077..19c68bf 100644 --- a/Steamodded/localization/en-us.lua +++ b/smods/localization/en-us.lua @@ -62,7 +62,80 @@ return { 'This mod has been', '{C:attention}disabled!{}' } - } + }, + + + -- card perma bonuses + card_extra_chips={ + text={ + "{C:chips}#1#{} extra chips", + }, + }, + card_x_chips = { + text = { + "{X:chips,C:white}X#1#{} chips" + } + }, + card_extra_x_chips = { + text = { + "{X:chips,C:white}X#1#{} extra chips" + } + }, + card_extra_mult = { + text = { + "{C:mult}#1#{} extra Mult" + } + }, + card_x_mult = { + text = { + "{X:mult,C:white}X#1#{} Mult" + } + }, + card_extra_x_mult = { + text = { + "{X:mult,C:white}X#1#{} extra Mult" + } + }, + card_extra_p_dollars = { + text = { + "{C:money}#1#{} when scored", + } + }, + card_extra_h_chips = { + text = { + "{C:chips}#1#{} chips when held", + } + }, + card_h_x_chips = { + text = { + "{X:chips,C:white}X#1#{} chips when held", + } + }, + card_extra_h_x_chips = { + text = { + "{X:chips,C:white}X#1#{} extra chips when held", + } + }, + card_extra_h_mult = { + text = { + "{C:mult}#1#{} extra Mult when held", + } + }, + card_h_x_mult = { + text = { + "{X:mult,C:white}X#1#{} Mult when held", + } + }, + card_extra_h_x_mult = { + text = { + "{X:mult,C:white}X#1#{} extra Mult when held", + } + }, + card_extra_h_dollars = { + text = { + "{C:money}#1#{} if held at end of round", + }, + }, }, Edition = { e_negative_playing_card = { @@ -71,6 +144,29 @@ return { "{C:dark_edition}+#1#{} hand size" }, }, + }, + Enhanced = { + m_gold={ + name="Gold Card", + text={ + "{C:money}#1#{} if this", + "card is held in hand", + "at end of round", + }, + }, + m_stone={ + name="Stone Card", + text={ + "{C:chips}#1#{} chips", + "no rank or suit", + }, + }, + m_mult={ + name="Mult Card", + text={ + "{C:mult}#1#{} Mult", + }, + }, } }, misc = { @@ -127,6 +223,14 @@ return { cashout_hidden = '...and #1# more', a_xchips = "X#1# Chips", a_xchips_minus = "-X#1# Chips", + smods_version_mismatch = { + "Your Steamodded version has changed", + "since this run was started!", + "Continuing it may lead to", + "unexpected behaviour and game crashes.", + "Starting version: #1#", + "Current version: #2#", + } }, } } diff --git a/Steamodded/localization/es_419.lua b/smods/localization/es_419.lua similarity index 84% rename from Steamodded/localization/es_419.lua rename to smods/localization/es_419.lua index b016289..c29f162 100644 --- a/Steamodded/localization/es_419.lua +++ b/smods/localization/es_419.lua @@ -41,19 +41,19 @@ return { 'pero la #2# está instalada.' } }, - load_failure_p = { -- To be translated + load_failure_p = { text = { - '{C:attention}Prefix Conflict!{}', - 'This mod\'s prefix is', - 'the same as another mod\'s.', + '{C:attention}¡Conflicto de prefijos!{}', + 'El prefijo del mod', + 'es el mismo que otro mod.', '({C:attention}#1#{})' } }, - load_failure_m = { -- To be translated + load_failure_m = { text = { - '{C:attention}Main File Not Found!{}', - 'This mod\'s main file', - 'could not be found.', + '{C:attention}¡Archivo principal no encontrado!{}', + 'El archivo principal del mod', + 'no ha sido encontrado.', '({C:attention}#1#{})' } }, @@ -83,7 +83,7 @@ return { dictionary = { b_mods = 'Mods', b_mods_cap = 'MODS', - b_modded_version = 'Modded Version!', -- To be translated + b_modded_version = '¡Versión Modeada!', b_steamodded = 'Steamodded', b_credits = 'Créditos', b_open_mods_dir = 'Abrir directorio de Mods', @@ -99,15 +99,15 @@ return { b_author = 'Autor/a', b_authors = 'Autores', b_unknown = 'Desconocido', - b_lovely_mod = '(Lovely Mod) ', -- TODO + b_lovely_mod = '(Mod de Lovely) ', b_by = ' Por: ', b_config = "Configuración", b_additions = 'Adiciones', - b_stickers = 'Stickers', -- TODO + b_stickers = 'Stickers', b_achievements = "Logros", b_applies_stakes_1 = 'Aplica ', b_applies_stakes_2 = '', - b_graphics_mipmap_level = "Mipmap level", -- TODO + b_graphics_mipmap_level = "Nivel de Mipmap", }, v_dictionary = { c_types = '#1# Tipos', diff --git a/Steamodded/localization/es_ES.lua b/smods/localization/es_ES.lua similarity index 84% rename from Steamodded/localization/es_ES.lua rename to smods/localization/es_ES.lua index dbe46bd..c29f162 100644 --- a/Steamodded/localization/es_ES.lua +++ b/smods/localization/es_ES.lua @@ -41,19 +41,19 @@ return { 'pero la #2# está instalada.' } }, - load_failure_p = { -- To be translated + load_failure_p = { text = { - '{C:attention}Prefix Conflict!{}', - 'This mod\'s prefix is', - 'the same as another mod\'s.', + '{C:attention}¡Conflicto de prefijos!{}', + 'El prefijo del mod', + 'es el mismo que otro mod.', '({C:attention}#1#{})' } }, - load_failure_m = { -- To be translated + load_failure_m = { text = { - '{C:attention}Main File Not Found!{}', - 'This mod\'s main file', - 'could not be found.', + '{C:attention}¡Archivo principal no encontrado!{}', + 'El archivo principal del mod', + 'no ha sido encontrado.', '({C:attention}#1#{})' } }, @@ -83,7 +83,7 @@ return { dictionary = { b_mods = 'Mods', b_mods_cap = 'MODS', - b_modded_version = 'Modded Version!', -- To be translated + b_modded_version = '¡Versión Modeada!', b_steamodded = 'Steamodded', b_credits = 'Créditos', b_open_mods_dir = 'Abrir directorio de Mods', @@ -99,15 +99,15 @@ return { b_author = 'Autor/a', b_authors = 'Autores', b_unknown = 'Desconocido', - b_lovely_mod = '(Lovely Mod) ', --TODO + b_lovely_mod = '(Mod de Lovely) ', b_by = ' Por: ', b_config = "Configuración", b_additions = 'Adiciones', - b_stickers = 'Stickers', -- TODO + b_stickers = 'Stickers', b_achievements = "Logros", b_applies_stakes_1 = 'Aplica ', b_applies_stakes_2 = '', - b_graphics_mipmap_level = "Mipmap level", -- TODO + b_graphics_mipmap_level = "Nivel de Mipmap", }, v_dictionary = { c_types = '#1# Tipos', diff --git a/Steamodded/localization/fr.lua b/smods/localization/fr.lua similarity index 100% rename from Steamodded/localization/fr.lua rename to smods/localization/fr.lua diff --git a/Steamodded/localization/pt_BR.lua b/smods/localization/pt_BR.lua similarity index 100% rename from Steamodded/localization/pt_BR.lua rename to smods/localization/pt_BR.lua diff --git a/Steamodded/localization/zh_CN.lua b/smods/localization/zh_CN.lua similarity index 100% rename from Steamodded/localization/zh_CN.lua rename to smods/localization/zh_CN.lua diff --git a/smods/lsp_def/classes/achievement.lua b/smods/lsp_def/classes/achievement.lua new file mode 100644 index 0000000..a68f2a0 --- /dev/null +++ b/smods/lsp_def/classes/achievement.lua @@ -0,0 +1,36 @@ +---@meta + +---@class SMODS.Achievement: SMODS.GameObject +---@field obj_table? table Table of objects registered to this class. +---@field super? SMODS.GameObject|table Parent class. +---@field atlas? string Key to the achievement's atlas. +---@field pos? table|{x: integer, y: integer} Position of the achievement's sprite. +---@field earned? boolean Sets whether the achievemnt is considered "earned" on profile load. To reset, set `reset_on_startup` to `true`. +---@field reset_on_startup? boolean Sets whether the achievement is unearned on profile load. +---@field bypass_all_unlocked? boolean Sets whether the achievement can be earned on profiles that pressed the "Unlock All" button. +---@field hidden_name? boolean Sets if the name of the achievement is hidden when not earned. +---@field hidden_text? boolean Sets if the description of the achievement is hidden when not earned. +---@field __call? fun(self: SMODS.Achievement|table, o: SMODS.Achievement|table): nil|table|SMODS.Achievement +---@field extend? fun(self: SMODS.Achievement|table, o: SMODS.Achievement|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.Achievement|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.Achievement|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.Achievement|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.Achievement|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.Achievement|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.Achievement|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.Achievement|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.Achievement|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.Achievement|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.Achievement|table, i?: number) Called during `inject_class`. Injects the object into the game. +---@field take_ownership? fun(self: SMODS.Achievement|table, key: string, obj: SMODS.Achievement|table, silent?: boolean): nil|table|SMODS.Achievement Takes control of vanilla objects. Child class must have get_obj for this to function +---@field get_obj? fun(self: SMODS.Achievement|table, key: string): SMODS.Achievement|table? Returns an object if one matches the `key`. +---@field unlock_condition? fun(self: SMODS.Achievement|table, args: table): boolean? Controls when the achievement is unlocked. +---@overload fun(self: SMODS.Achievement): SMODS.Achievement +SMODS.Achievement = setmetatable({}, { + __call = function(self) + return self + end +}) + +---@type table +SMODS.Achievements = {} \ No newline at end of file diff --git a/smods/lsp_def/classes/atlas.lua b/smods/lsp_def/classes/atlas.lua new file mode 100644 index 0000000..c9238bd --- /dev/null +++ b/smods/lsp_def/classes/atlas.lua @@ -0,0 +1,36 @@ +---@meta + +---@class SMODS.Atlas: SMODS.GameObject +---@field obj_table? table Table of objects registered to this class. +---@field super? SMODS.GameObject|table Parent class. +---@field px? string|number Width of individual sprites using this atlas. +---@field py? string|number Height of individual sprite using this atlas. +---@field path? string Name of the image file, including extension. +---@field atlas_table? "ASSET_ATLAS"|"ANIMATION_ATLAS"|"ASSET_IMAGES"|string Type of atlas. `ASSET_ATLAS`: non-animated sprites, `ANIMATION_ATLAS`: animated sprites, `ASSET_IMAGES`: anything else. +---@field frames? number Number of frames in the animation. +---@field raw_key? boolean Sets whether the mod prefix is added to atlas key. Used for overriding vanilla sprites. +---@field language? string Key to a language. Restricts the atlas to only when this language is enabled. +---@field disable_mipmap? boolean Sets if the sprite is affected by the mipmap. +---@field __call? fun(self: SMODS.Atlas|table, o: SMODS.Atlas|table): nil|table|SMODS.Atlas +---@field extend? fun(self: SMODS.Atlas|table, o: SMODS.Atlas|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.Atlas|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.Atlas|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.Atlas|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.Atlas|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.Atlas|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.Atlas|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.Atlas|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.Atlas|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.Atlas|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.Atlas|table, i?: number) Called during `inject_class`. Injects the object into the game. +---@field take_ownership? fun(self: SMODS.Atlas|table, key: string, obj: SMODS.Atlas|table, silent?: boolean): nil|table|SMODS.Atlas Takes control of vanilla objects. Child class must have get_obj for this to function +---@field get_obj? fun(self: SMODS.Atlas|table, key: string): SMODS.Atlas|table? Returns an object if one matches the `key`. +---@overload fun(self: SMODS.Atlas): SMODS.Atlas +SMODS.Atlas = setmetatable({}, { + __call = function(self) + return self + end +}) + +---@type table +SMODS.Atlases = {} \ No newline at end of file diff --git a/smods/lsp_def/classes/back.lua b/smods/lsp_def/classes/back.lua new file mode 100644 index 0000000..8269345 --- /dev/null +++ b/smods/lsp_def/classes/back.lua @@ -0,0 +1,26 @@ +---@meta + +---@class SMODS.Back: SMODS.Center +---@field super? SMODS.Center|table Parent class. +---@field __call? fun(self: SMODS.Back|table, o: SMODS.Back|table): nil|table|SMODS.Back +---@field extend? fun(self: SMODS.Back|table, o: SMODS.Back|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.Back|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.Back|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.Back|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.Back|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.Back|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.Back|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.Back|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.Back|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.Back|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.Back|table, i?: number) Called during `inject_class`. Injects the object into the game. +---@field take_ownership? fun(self: SMODS.Back|table, key: string, obj: SMODS.Back|table, silent?: boolean): nil|table|SMODS.Back Takes control of vanilla objects. Child class must have get_obj for this to function +---@field get_obj? fun(self: SMODS.Back|table, key: string): SMODS.Back|table? Returns an object if one matches the `key`. +---@field calculate? fun(self: SMODS.Back|table, back: Back|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.Back|table, back: Back|table) Applied modifiers at the start of a run. +---@overload fun(self: SMODS.Back): SMODS.Back +SMODS.Back = setmetatable({}, { + __call = function(self) + return self + end +}) \ No newline at end of file diff --git a/smods/lsp_def/classes/blind.lua b/smods/lsp_def/classes/blind.lua new file mode 100644 index 0000000..c722d1d --- /dev/null +++ b/smods/lsp_def/classes/blind.lua @@ -0,0 +1,52 @@ +---@meta + +---@class SMODS.Blind: SMODS.GameObject +---@field obj_table? table Table of objects registered to this class. +---@field super? SMODS.GameObject|table Parent class. +---@field atlas? string Key to the blind's atlas. +---@field pos? table|{x: integer, y: integer} Position of the blind's sprite. +---@field discovered? boolean Sets the discovery state of the blind. +---@field dollars? number Amount of money earned when defeated. +---@field mult? number Required score multiplier relative to the Ante's Base score. +---@field boss? table|{min: integer, max: integer, showdown: boolean} Marks this Blind as a Boss Blind. `min` indicates minimum Ante for this Blind to appear. `showdown` indicates this Blind is a Final Boss Blind. For complex conditions, use `in_pool`. +---@field boss_colour? table HEX color for the background when playing this Blind. +---@field debuff? table Configures vanilla blind effects related to debuffing, see [SMODS.Blind](https://github.com/Steamodded/smods/wiki/SMODS.Blind#api-documentation-smodsblind) Documentation. Ignored if Blind defines `debuff_hand` or `debuff_card`. +---@field ignore_showdown_check? boolean Sets if `in_pool` should be respected regardless of whether a showdown Boss Blind was requested or not. +---@field vars? table Variables for this Blind's description in the collection. +---@field __call? fun(self: SMODS.Blind|table, o: SMODS.Blind|table): nil|table|SMODS.Blind +---@field extend? fun(self: SMODS.Blind|table, o: SMODS.Blind|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.Blind|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.Blind|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.Blind|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.Blind|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.Blind|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.Blind|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.Blind|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.Blind|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.Blind|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.Blind|table, i?: number) Called during `inject_class`. Injects the object into the game. +---@field take_ownership? fun(self: SMODS.Blind|table, key: string, obj: SMODS.Blind|table, silent?: boolean): nil|table|SMODS.Blind Takes control of vanilla objects. Child class must have get_obj for this to function +---@field get_obj? fun(self: SMODS.Blind|table, key: string): SMODS.Blind|table? Returns an object if one matches the `key`. +---@field new? fun(self, name, slug, loc_txt, dollars, mult, vars, debuff, pos, boss, boss_colour, defeated, atlas): any DEPRECATED. DO NOT USE +---@field set_blind? fun(self: SMODS.Blind|table) Handles effects when this Blind is selected. +---@field disable? fun(self: SMODS.Blind|table) Handles effect reverting when this Blind is disabled. +---@field defeat? fun(self: SMODS.Blind|table) Handles effect reverting when this Blind is defeated. +---@field drawn_to_hand? fun(self: SMODS.Blind|table) Handles effects when cards are drawn to hand. +---@field press_play? fun(self: SMODS.Blind|table) Handles effects when a hand is played. +---@field recalc_debuff? fun(self: SMODS.Blind|table, card: Card|table, from_blind: boolean): boolean? Determines if a card should be debuffed by this blind. +---@field debuff_hand? fun(self: SMODS.Blind|table, cards: table, hand: table, handname: string, check: nil|boolean): boolean? Determines if the hand is debuffed. +---@field stay_flipped? fun(self: SMODS.Blind|table, area: CardArea|table, card: Card|table): boolean? Determines if a card is drawn face down. +---@field modify_hand? fun(self: SMODS.Blind|table, cards: table, poker_hands: table, text: string, mult: number, hand_chips: number): number?, number?, boolean? Handles modifications of the base score for played poker hand. +---@field get_loc_debuff_text? fun(self: SMODS.Blind|table): string? Handles text displayed for debuff warnings or invalid hands. +---@field loc_vars? fun(self: SMODS.Blind|table): table? Provides control over displaying the Blind descriptions. See [SMODS.Blind `loc_vars` implementation](https://github.com/Steamodded/smods/wiki/SMODS.Blind#api-methods) documentation for return value details. +---@field collection_loc_vars? fun(self: SMODS.Blind|table): table? Provides control over displaying the Blind description in the collections menu. +---@field in_pool? fun(self: SMODS.Blind|table): boolean Allows configuring if the Blind is allowed to appear. +---@overload fun(self: SMODS.Blind): SMODS.Blind +SMODS.Blind = setmetatable({}, { + __call = function(self) + return self + end +}) + +---@type table +SMODS.Blinds = {} \ No newline at end of file diff --git a/smods/lsp_def/classes/booster.lua b/smods/lsp_def/classes/booster.lua new file mode 100644 index 0000000..89458ae --- /dev/null +++ b/smods/lsp_def/classes/booster.lua @@ -0,0 +1,41 @@ +---@meta + +---@class SMODS.Booster: SMODS.Center +---@field super? SMODS.Center|table Parent class. +---@field loc_txt? table|{name: string, text: string[], group_name: string} Contains strings used to display text relating to this object. +---@field group_key? string Key to the group name. Grabs from `G.localization.misc.dictionary[group_key]`. +---@field draw_hand? boolean Sets if playing cards are drawn when booster pack is opened. +---@field kind? string Groups pack types together. For example, this can be used in `get_pack()` to generate a booster pack of a specific type. +---@field weight? number Weight of the booster pack. +---@field select_card? string|{[string]: string} Key to the CardArea (e.x. `G[SMODS.Booster.select_card]`). Consumables inside this booster pack will be "selected" and emplaced into a CardArea instead of used. As a table, each key-value pair is a card set as key and CardArea string as values. +---@field select_exclusions? string[] List of card sets to exclude from being "Selected". +---@field __call? fun(self: SMODS.Booster|table, o: SMODS.Booster|table): nil|table|SMODS.Booster +---@field extend? fun(self: SMODS.Booster|table, o: SMODS.Booster|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.Booster|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.Booster|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.Booster|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.Booster|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.Booster|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.Booster|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.Booster|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.Booster|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.Booster|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.Booster|table, i?: number) Called during `inject_class`. Injects the object into the game. +---@field take_ownership? fun(self: SMODS.Booster|table, key: string, obj: SMODS.Booster|table, silent?: boolean): nil|table|SMODS.Booster Takes control of vanilla objects. Child class must have get_obj for this to function +---@field get_obj? fun(self: SMODS.Booster|table, key: string): SMODS.Booster|table? Returns an object if one matches the `key`. +---@field create_card? fun(self: SMODS.Booster|table, card: Card|table, i: number): Card|table Creates the cards inside the booster pack. Returning a table will create a Card through `SMODS.create_card`. +---@field update_pack? fun(self: SMODS.Booster|table, dt: number) Handles booster pack UI when opened. +---@field ease_background_colour? fun(self: SMODS.Booster|table) Changes background colour when booster pack is opened. +---@field particles? fun(self: SMODS.Booster|table) Handles ambient particle effects when booster pack is opened. +---@field create_UIBox? fun(self: SMODS.Booster|table): table Returns booster pack UIBox. +---@field take_ownership_by_kind? fun(self: SMODS.Booster|table, kind: string, obj: table, silent?: boolean) Finds all booster packs with matching `kind` and applies `SMODS.Booster:take_ownership()` to each one with `obj` and `silent` args passed through. +---@overload fun(self: SMODS.Booster): SMODS.Booster +SMODS.Booster = setmetatable({}, { + __call = function(self) + return self + end +}) + +---@type Card|table|nil +---Last opened Booster Pack. +SMODS.OPENED_BOOSTER = nil \ No newline at end of file diff --git a/smods/lsp_def/classes/center.lua b/smods/lsp_def/classes/center.lua new file mode 100644 index 0000000..3f2b613 --- /dev/null +++ b/smods/lsp_def/classes/center.lua @@ -0,0 +1,61 @@ +---@meta + +---@class SMODS.Center: SMODS.GameObject +---@field obj_table? table Table of objects registered to this class. +---@field super? SMODS.GameObject|table Parent class. +---@field atlas? string Key to the center's atlas. +---@field pos? table|{x: integer, y: integer} Position of the center's sprite. +---@field soul_pos? table|{x: integer, y: integer, draw?: fun(card: Card|table, scale_mod?: number, rotate_mod?: number)} Position of the "soul" sprite. Separate front layer sprite that hovers over the card. +---@field unlocked? boolean Sets the unlock state of the center. +---@field discovered? boolean Sets the discovery state of the center. +---@field no_collection? boolean Sets whether the card shows up in the collections menu. +---@field loc_txt? table|{name: string, text: string[]} Contains strings used for displaying text related to this object. +---@field pools? string[] Array of keys to ObjectTypes this center will be added to. +---@field cost? number Sell cost of this center. +---@field no_pool_flag? string Key to a pool flag defined in `G.GAME.pool_flags`. This center is removed from pools as long as this flag is `true`. +---@field yes_pool_flag? string Key to the pool flag defined in `G.GAME.pool_flags`. This center is removed from pools as long as this flag is `false`. +---@field eternal_compat? boolean Sets whether the center can have "Eternal" sticker. +---@field perishable_compat? boolean Sets whether the center can have "Perishable" sticker. +---@field display_size? table|{w: integer, h: integer} Changes the display size of card. +---@field pixel_size? table|{w: integer, h: integer} Change the size of the sprite drawn onto the card. +---@field __call? fun(self: SMODS.Center|table, o: SMODS.Center|table): nil|table|SMODS.Center +---@field extend? fun(self: SMODS.Center|table, o: SMODS.Center|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.Center|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.Center|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.Center|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.Center|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.Center|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.Center|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.Center|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.Center|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.Center|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.Center|table, i?: number) Called during `inject_class`. Injects the object into the game. +---@field take_ownership? fun(self: SMODS.Center|table, key: string, obj: SMODS.Center|table, silent?: boolean): nil|table|SMODS.Center Takes control of vanilla objects. Child class must have get_obj for this to function +---@field get_obj? fun(self: SMODS.Center|table, key: string): SMODS.Center|table? Returns an object if one matches the `key`. +---@field delete? fun(self: SMODS.Center|table): boolean? Removes provided center. +---@field generate_ui? fun(self: SMODS.Center|table, info_queue: table, card: Card|table, desc_nodes: table, specific_vars: table, full_UI_table: table) Provides complex control over the UI display of the card. See [`generate_ui`](https://github.com/Steamodded/smods/wiki/Localization#generate_ui-advanced) documentation for details. +---@field loc_vars? fun(self: SMODS.Center|table, info_queue: table, card: Card|table): table? Provides simple control over displaying descriptions and tooltips of the card. See [`loc_vars`](https://github.com/Steamodded/smods/wiki/Localization#loc_vars) documentation for return value details. +---@field locked_loc_vars? fun(self: SMODS.Center|table, info_queue: table, card: Card|table): table Provides simple control over displaying descriptions and toolips of this center when not unlocked. +---@field check_for_unlock? fun(self: SMODS.Center|table, args: table): boolean? Configures unlock conditions. See vanilla implementation of `check_for_unlock` for details on `args` parameters. +---@field set_badges? fun(self: SMODS.Center|table, card: Card|table, badges: table) Append `badges` for additional badges on the UI display of the card. To override the rarity/card type badge, see `SMODS.Center:set_card_type_badge()`. +---@field set_card_type_badge? fun(self: SMODS.Center|table, card: Card|table, badges: table) Overrides the rarity/card type badges, allowing you to Append `badges` to replace them. To add extra badges, see `SMODS.Center:sset_badges()`. +---@field draw? fun(self: SMODS.Center|table, card: Card|table, layer: string) Draws the sprite and shader of the card. +---@field update? fun(self: SMODS.Center|table, card: Card|table, dt: number) Allows logic for this card to be run per-frame. +---@field set_sprites? fun(self: SMODS.Center|table, card: Card|table, front?: Card|table) Used for setting and manipulating sprites of the card when created or loaded. +---@field load? fun(self: SMODS.Center|table, card: Card|table, card_table: table, other_card?: table) Used when the card itself is being reloaded. +---@field set_ability? fun(self: SMODS.Center|table, card: Card|table, initial?: boolean, delay_sprites?: boolean) Sets up initial ability and size parameters for the card. +---@field add_to_deck? fun(self: SMODS.Center|table, card: Card|table, from_debuff: boolean) Allows modifying the game state when the card is being added. +---@field remove_from_deck? fun(self: SMODS.Center|table, card: Card|table, from_debuff: boolean) Allows modifying the game state when the card is being removed. +---@field in_pool? fun(self: SMODS.Center|table, args: table): boolean? , table? Allows configuring if the card is allowed to spawn. +---@field calculate? fun(self: SMODS.Center|table, card: Card|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 create_fake_card? fun(self: SMODS.Center|table): table Creates a fake card representing this center. Used internally for `generate_ui` in cases where recieved `card` param is nil. +---@field on_select? fun(self: SMODS.Center|table, card: Card|table) Called when the card is selected from a booster pack. +---@overload fun(self: SMODS.Center): SMODS.Center +SMODS.Center = setmetatable({}, { + __call = function(self) + return self + end +}) + +---@type table +SMODS.Centers = {} diff --git a/smods/lsp_def/classes/challenge.lua b/smods/lsp_def/classes/challenge.lua new file mode 100644 index 0000000..3e7326a --- /dev/null +++ b/smods/lsp_def/classes/challenge.lua @@ -0,0 +1,36 @@ +---@meta + +---@class SMODS.Challenge: SMODS.GameObject +---@field obj_table? table Table of objects registered to this class. +---@field loc_txt? table|{name: string} Contains strings used for displaying text related to this object. +---@field super? SMODS.GameObject|table Parent class. +---@field rules? table|{custom?: table[]|{id: string, value?: any}[], modifiers?: table[]|{id: string, value?: any}} List of tables setting custom rules and modifiers. Each rule/modifier has an `id`, with optional `value` param (defaults to `true`). See [SMODS.Challenge](https://github.com/Steamodded/smods/wiki/SMODS.Challenge) Documentation for default rules/modifiers. +---@field jokers? table[]|{id: string, edition?: string, eternal?: boolean, pinned?: boolean}[] List of tables setting jokers to start with. +---@field consumeables? table[]|{id: string, edition?: string, eternal?: boolean}[] List of tables setting consumables to start with. +---@field vouchers? table[]|{id: string}[] List of tables setting vouchers to start with. +---@field restrictions? table|{banned_cards?: table[]|{id: string}[], banned_tags?: table[]|{id: string}[], banned_other?: table[]|{id: string, type: "blind"}[]} Contains IDs to objects to ban from the challenge. +---@field deck? table|{type?: string|"Challenge Deck", cards?: table[], yes_ranks?: table, yes_suits?: table, no_ranks?: table, no_suits?: table, enhancement?: string, edition?: string, seal?: string} Defines the Challenge's deck. See [SMODS.Challenge](https://github.com/Steamodded/smods/wiki/SMODS.Challenge) Documentation for details. +---@field __call? fun(self: SMODS.Challenge|table, o: SMODS.Challenge|table): nil|table|SMODS.Challenge +---@field extend? fun(self: SMODS.Challenge|table, o: SMODS.Challenge|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.Challenge|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.Challenge|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.Challenge|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.Challenge|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.Challenge|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.Challenge|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.Challenge|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.Challenge|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.Challenge|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.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 +---@overload fun(self: SMODS.Challenge): SMODS.Challenge +SMODS.Challenge = setmetatable({}, { + __call = function(self) + return self + end +}) + +---@type table +SMODS.Challenges = {} \ No newline at end of file diff --git a/smods/lsp_def/classes/consumable.lua b/smods/lsp_def/classes/consumable.lua new file mode 100644 index 0000000..adff780 --- /dev/null +++ b/smods/lsp_def/classes/consumable.lua @@ -0,0 +1,32 @@ +---@meta + +---@class SMODS.Consumable: SMODS.Center +---@field super? SMODS.Center|table Parent class. +---@field hidden? boolean Sets if this consumable is considered "legendary" (e.x. behaves like "The Soul"). +---@field soul_set? string Key to the ConsumableType set this consumable can replace. Requires `hidden` to be true. +---@field soul_rate? number Chance this card replaces a consumable. Requires `hidden` to be true. +---@field type? SMODS.ConsumableType|table ConsumableType this center belongs to. +---@field legendaries? (SMODS.Consumable|table)[] All injected "legendary" consumables. +---@field __call? fun(self: SMODS.Consumable|table, o: SMODS.Consumable|table): nil|table|SMODS.Consumable +---@field extend? fun(self: SMODS.Consumable|table, o: SMODS.Consumable|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.Consumable|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.Consumable|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.Consumable|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.Consumable|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.Consumable|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.Consumable|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.Consumable|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.Consumable|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.Consumable|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.Consumable|table, i?: number) Called during `inject_class`. Injects the object into the game. +---@field take_ownership? fun(self: SMODS.Consumable|table, key: string, obj: SMODS.Consumable|table, silent?: boolean): nil|table|SMODS.Consumable Takes control of vanilla objects. Child class must have get_obj for this to function +---@field get_obj? fun(self: SMODS.Consumable|table, key: string): SMODS.Consumable|table? Returns an object if one matches the `key`. +---@field use? fun(self: SMODS.Consumable|table, card: Card|table, area: CardArea|table, copier?: table) Defines behaviour when this consumable is used. +---@field can_use? fun(self: SMODS.Consumable|table, card: Card|table): boolean? Return `true` if the consumable is allowed to be used. +---@field keep_on_use? fun(self: SMODS.Consumable|table, card: Card|table): boolean? Return `true` if the consumable should stay after use. +---@overload fun(self: SMODS.Consumable): SMODS.Consumable +SMODS.Consumable = setmetatable({}, { + __call = function(self) + return self + end +}) \ No newline at end of file diff --git a/smods/lsp_def/classes/consumable_type.lua b/smods/lsp_def/classes/consumable_type.lua new file mode 100644 index 0000000..93115c4 --- /dev/null +++ b/smods/lsp_def/classes/consumable_type.lua @@ -0,0 +1,35 @@ +---@meta + +---@class SMODS.ConsumableType: SMODS.ObjectType +---@field obj_table? table Table of objects registered to this class. +---@field loc_txt? table|{name: string, collection: string, undiscovered: table|{name: string, text: string[]} } Contains strings used for displaying text related to this object. +---@field super? SMODS.ObjectType|table Parent class. +---@field primary_colour? table HEX color used as the primary color. Set as `G.C.SET[self.key]`. +---@field secondary_colour? table HEX color used as the seconary color. Set as `G.C.SECONDARY_COLOUR[self.key]`. +---@field collection_rows? number[] Array of numbers indicating how many rows and how many cards per row this ConsumableType's collection has. +---@field shop_rate? nil|number Defining this value allows cards part of this ConsumableType to appear in the shop. Defined as `G.GAME[key:lower()..'_rate']`. +---@field ctype_buffer? string[] Array of keys to all objects registered to the ConsumableType class. +---@field __call? fun(self: SMODS.ConsumableType|table, o: SMODS.ConsumableType|table): nil|table|SMODS.ConsumableType +---@field extend? fun(self: SMODS.ConsumableType|table, o: SMODS.ConsumableType|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.ConsumableType|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.ConsumableType|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.ConsumableType|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.ConsumableType|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.ConsumableType|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.ConsumableType|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.ConsumableType|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.ConsumableType|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.ConsumableType|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.ConsumableType|table, i?: number) Called during `inject_class`. Injects the object into the game. +---@field take_ownership? fun(self: SMODS.ConsumableType|table, key: string, obj: SMODS.ConsumableType|table, silent?: boolean): nil|table|SMODS.ConsumableType Takes control of vanilla objects. Child class must have get_obj for this to function +---@field get_obj? fun(self: SMODS.ConsumableType|table, key: string): SMODS.ConsumableType|table? Returns an object if one matches the `key`. +---@field create_UIBox_your_collection? fun(self: SMODS.ConsumableType|table): table Creates the UIBox of the ConsumableType's collections menu. +---@overload fun(self: SMODS.ConsumableType): SMODS.ConsumableType +SMODS.ConsumableType = setmetatable({}, { + __call = function(self) + return self + end +}) + +---@type table +SMODS.ConsumableTypes = {} \ No newline at end of file diff --git a/smods/lsp_def/classes/deck_skin.lua b/smods/lsp_def/classes/deck_skin.lua new file mode 100644 index 0000000..687852d --- /dev/null +++ b/smods/lsp_def/classes/deck_skin.lua @@ -0,0 +1,33 @@ +---@meta + +---@class SMODS.DeckSkin: SMODS.GameObject +---@field obj_table? table Table of objects registered to this class. +---@field super? SMODS.GameObject|table Parent class. +---@field loc_txt? string|table String displayed as the name of this DeckSkin. +---@field suit? string Suit this DeckSkin is tied to. +---@field palettes? table[]|{key: string, ranks: string[], atlas: string, pos_style?: string|{[string]: string}, colour?: table, suit_icon?: {atlas: string, pos: number|{x: number, y: number}, loc_txt?: string}}[] List of tables representing each palette. See [SMODS DeckSkin](https://github.com/Steamodded/smods/wiki/SMODS.DeckSkin) documentation for details. +---@field __call? fun(self: SMODS.DeckSkin|table, o: SMODS.DeckSkin|table): nil|table|SMODS.DeckSkin +---@field extend? fun(self: SMODS.DeckSkin|table, o: SMODS.DeckSkin|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.DeckSkin|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.DeckSkin|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.DeckSkin|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.DeckSkin|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.DeckSkin|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.DeckSkin|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.DeckSkin|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.DeckSkin|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.DeckSkin|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.DeckSkin|table, i?: number) Called during `inject_class`. Injects the object into the game. +---@field take_ownership? fun(self: SMODS.DeckSkin|table, key: string, obj: SMODS.DeckSkin|table, silent?: boolean): nil|table|SMODS.DeckSkin Takes control of vanilla objects. Child class must have get_obj for this to function +---@field get_obj? fun(self: SMODS.DeckSkin|table, key: string): SMODS.DeckSkin|table? Returns an object if one matches the `key`. +---@field add_palette? fun(self: SMODS.DeckSkin|table, palette: table): boolean, string? Internal function. Adds the palette into the DeckSkin. +---@field get_palette_loc_options? fun(key: number|string, suit: string): string[] Internal function. Returns palette options for given key and suit. +---@overload fun(self: SMODS.DeckSkin): SMODS.DeckSkin +SMODS.DeckSkin = setmetatable({}, { + __call = function(self) + return self + end +}) + +---@type table +SMODS.DeckSkins = {} diff --git a/smods/lsp_def/classes/draw_step.lua b/smods/lsp_def/classes/draw_step.lua new file mode 100644 index 0000000..7a1fd1d --- /dev/null +++ b/smods/lsp_def/classes/draw_step.lua @@ -0,0 +1,38 @@ +---@meta + +---@class SMODS.DrawStep: SMODS.GameObject +---@field order? number Sets the order. `DrawStep` objects are evaluated in order from lowest to highest. +---@field layers? table Strings corresponding to draw layers. The `DrawStep` object's `func` will only be called when the `layer` arg in `Card:draw()` matches a string in this table. +---@field conditions? table Table of conditions. This object will not draw if any condition is not `true` when evaluated. +---@field __call? fun(self: SMODS.DrawStep|table, o: SMODS.DrawStep|table): nil|table|SMODS.DrawStep +---@field extend? fun(self: SMODS.DrawStep|table, o: SMODS.DrawStep|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.DrawStep|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.DrawStep|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.DrawStep|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.DrawStep|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.DrawStep|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.DrawStep|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.DrawStep|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.DrawStep|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.DrawStep|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.DrawStep|table, i?: number) Called during `inject_class`. Injects the object into the game. +---@field take_ownership? fun(self: SMODS.DrawStep|table, key: string, obj: SMODS.DrawStep|table, silent?: boolean): nil|table|SMODS.DrawStep Takes control of vanilla objects. Child class must have get_obj for this to function +---@field get_obj? fun(self: SMODS.DrawStep|table, key: string): SMODS.DrawStep|table? Returns an object if one matches the `key`. +---@field func? fun(card: Card|table, layer?: string) Handles the drawing logic of the `DrawStep`. +---@field check_conditions? fun(self: SMODS.DrawStep|table, card: Card|table, layer: string): boolean? Iterates over the `conditions` table, calling `check_individual_condition` per element`. +---@field check_individual_condition? fun(self: SMODS.DrawStep|table, card: Card|table, layer: string, k: string, v: any): boolean? Checks individual `SMODS.DrawStep` conditions, with `k` and `v` as key and value of condition. +---@overload fun(self: SMODS.DrawStep): SMODS.DrawStep +SMODS.DrawStep = setmetatable({}, { + __call = function(self) + return self + end +}) + +---@type table +SMODS.DrawSteps = {} + +---@type table +-- All keys in this table will not be automatically drawn with a default `draw()` call in the "others" DrawStep. +SMODS.draw_ignore_keys = { + focused_ui = true, front = true, back = true, soul_parts = true, center = true, floating_sprite = true, shadow = true, use_button = true, buy_button = true, buy_and_use_button = true, debuff = true, price = true, particles = true, h_popup = true +} \ No newline at end of file diff --git a/smods/lsp_def/classes/edition.lua b/smods/lsp_def/classes/edition.lua new file mode 100644 index 0000000..a40b004 --- /dev/null +++ b/smods/lsp_def/classes/edition.lua @@ -0,0 +1,64 @@ +---@meta + +---@class SMODS.Edition: SMODS.Center +---@field loc_txt? table|{name: string, text: string[], label: string} Contains strings used for displaying text related to this object. +---@field shader? string|false Key to the shader drawn on cards with this Edition. If set to `false`, a shader will not be drawn. +---@field atlas? string Defines the atlas for the card this Edition is drawn on in the collection. +---@field pos? table|{x: integer, y: integer} Defined the position of the card's sprite this Edition is drawn on in the collection. +---@field in_shop? boolean Sets if the Edition spawns naturally in the shop. +---@field weight? number The weight of the Edition. +---@field extra_cost? number Extra cost applied to cards in the shop with this Edition. +---@field apply_to_float? boolean Sets if the shader is drawn on floating sprites. +---@field badge_colour? table HEX color of the Edition's badge +---@field sound? table|{sound: string, per?: number, vol?: number} Used to set a custom sound when the Edition is applied. +---@field disable_shadow? boolean Sets if the shadow is drawn under the card with this Edition. +---@field disable_base_shader? boolean Sets if the default shader for the card is disabled. +---@field super? SMODS.Center|table Parent class. +---@field __call? fun(self: SMODS.Edition|table, o: SMODS.Edition|table): nil|table|SMODS.Edition +---@field extend? fun(self: SMODS.Edition|table, o: SMODS.Edition|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.Edition|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.Edition|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.Edition|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.Edition|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.Edition|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.Edition|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.Edition|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.Edition|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.Edition|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.Edition|table, i?: number) Called during `inject_class`. Injects the object into the game. +---@field take_ownership? fun(self: SMODS.Edition|table, key: string, obj: SMODS.Edition|table, silent?: boolean): nil|table|SMODS.Edition Takes control of vanilla objects. Child class must have get_obj for this to function +---@field get_obj? fun(self: SMODS.Edition|table, key: string): SMODS.Edition|table? Returns an object if one matches the `key`. +---@field get_weight? fun(self: SMODS.Edition|table): number? Allows modifying the weight of this Edition. +---@field on_apply? fun(card: Card|table) Used to modify the card when this Edition is applied. +---@field on_remove? fun(card: Card|table) Used to modify the card when this Edition is removed. +---@field on_load? fun(card: Card|table) Used to modify the card when a card with this Edition is loaded from a save. +---@field draw? fun(self: SMODS.Edition|table, card: Card|table, layer: string) Draws the edition's shader. By default, `self.shader` is drawn. +---@field get_edition_cards? fun(self: SMODS.Edition|table, card_area: CardArea|table, edition: boolean): table +---@overload fun(self: SMODS.Edition): SMODS.Edition +SMODS.Edition = setmetatable({}, { + __call = function(self) + return self + end +}) + +---@param self Card|table +---@param context CalcContext|table +---@return table? +--- Calculates Editions on cards. +function Card:calculate_edition(context) end + +---@param self Card|table +---@param edition string|{[string]: true}? Both `string` values are the key of the edition to apply. +---@param immediate? boolean +---@param silent? boolean +--- Sets the card's edition. +function Card:set_edition(edition, immediate, silent) end + +---@param _key string Used as the seed +---@param _mod? number Scales the chance of landing on an Edition. +---@param _no_neg? boolean Exclude negative from edition polling. +---@param _guaranteed? boolean Function will always return an Edition. +---@param _options? string[]|{name: string, weight: number}[] Allows defining options for what editions should be polled. +---@return string? +--- Polls editions. Returns the key of the edition if successful. +function poll_edition(_key, _mod, _no_neg, _guaranteed, _options) end diff --git a/smods/lsp_def/classes/enhancement.lua b/smods/lsp_def/classes/enhancement.lua new file mode 100644 index 0000000..de96941 --- /dev/null +++ b/smods/lsp_def/classes/enhancement.lua @@ -0,0 +1,43 @@ +---@meta + +---@class SMODS.Enhancement: SMODS.Center +---@field super? SMODS.Center|table Parent class. +---@field replace_base_card? boolean Don't draw base card sprite or give base chips. +---@field no_rank? boolean Enhanced cards have no rank +---@field no_suit? boolean Enhanced cards have no suit. +---@field any_suit? boolean Enhanced cards have all suits. +---@field overrides_base_rank? boolean Enhancement cannot be generated by consumables. Automatically set to `true` if Enhancement has `no_rank`. +---@field always_scores? boolean Enhanced cards always score. +---@field weight? number Weight of the enhancement. +---@field __call? fun(self: SMODS.Enhancement|table, o: SMODS.Enhancement|table): nil|table|SMODS.Enhancement +---@field extend? fun(self: SMODS.Enhancement|table, o: SMODS.Enhancement|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.Enhancement|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.Enhancement|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.Enhancement|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.Enhancement|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.Enhancement|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.Enhancement|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.Enhancement|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.Enhancement|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.Enhancement|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.Enhancement|table, i?: number) Called during `inject_class`. Injects the object into the game. +---@field take_ownership? fun(self: SMODS.Enhancement|table, key: string, obj: SMODS.Enhancement|table, silent?: boolean): nil|table|SMODS.Enhancement Takes control of vanilla objects. Child class must have get_obj for this to function +---@field get_obj? fun(self: SMODS.Enhancement|table, key: string): SMODS.Enhancement|table? Returns an object if one matches the `key`. +---@field get_weight? fun(self: SMODS.Enhancement|table): number? Used to modify the weight of the Enhancement. +---@overload fun(self: SMODS.Enhancement): SMODS.Enhancement +SMODS.Enhancement = setmetatable({}, { + __call = function(self) + return self + end +}) + +---@param self Card|table +---@param context CalcContext|table +---@return table? +--- Calculates Enhancements on cards. +function Card:calculate_enhancement(context) end + +---@param args table|{key?: string, type_key?: string, mod?: number, guaranteed?: true, options?: table} +---@return string? +--- Polls all Enhancements with `args` for additional settings, and returns the key to a selected enhancement. +function SMODS.poll_enhancement(args) end diff --git a/smods/lsp_def/classes/game_object.lua b/smods/lsp_def/classes/game_object.lua new file mode 100644 index 0000000..d0c09a9 --- /dev/null +++ b/smods/lsp_def/classes/game_object.lua @@ -0,0 +1,53 @@ +---@meta + +---@class SMODS.GameObject: metatable +---@field mod? Mod|table The mod this object is created by. +---@field log_interval? number +---@field loc_txt? table|{name: string, text: string[]} Contains strings used for displaying text related to this object. +---@field registered? boolean +---@field obj_table? table Table of objects registered to this class. +---@field obj_buffer? string[] Array of keys to all objects registered to this class. +---@field dependencies? string|string[] Array of mod IDs. Object will fail to register if any specified mods cannot load. +---@field subclasses? SMODS.GameObject[]|table[] Array of child classes. +---@field super? table Parent class. +---@field key? string Unique string to reference this object. +---@field class_prefix? boolean|string All objects created with this class will have their key prefixed with this string. +---@field prefix_config? boolean|table Controls how prefixes are applied. By default, class_prefix and mod_prefix are applied to all registered objects. +---@field required_params? string[] Array of parameters required for objects created by this class. +---@field set? string Important for objects wanting to follow vanilla logic that depends on `set`. For classes, this is used for logging purposes. +---@field no_collection? boolean Sets whether the object shows up in collections. +---@field config? table Cards/Objects representing your center will copy default values from `config` into it's `ability` table. Custom values can be stored within `extra`. +---@field __call? fun(self: SMODS.GameObject|table, o: SMODS.GameObject|table): nil|table|SMODS.GameObject +---@field extend? fun(self: SMODS.GameObject|table, o: SMODS.GameObject|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.GameObject|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.GameObject|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.GameObject|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.GameObject|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.GameObject|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.GameObject|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.GameObject|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.GameObject|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.GameObject|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.GameObject|table, i?: number) Called during `inject_class`. Injects the object into the game. +---@field take_ownership? fun(self: SMODS.GameObject|table, key: string, obj: SMODS.GameObject|table, silent?: boolean): nil|table|SMODS.GameObject Takes control of vanilla objects. Child class must have get_obj for this to function +---@field get_obj? fun(self: SMODS.GameObject|table, key: string): SMODS.GameObject|table? Returns an object if one matches the `key`. +---@field obj_list? fun(self: SMODS.GameObject|table, reversed: boolean): table Returns an object if one matches the `key`. +---@overload fun(o: SMODS.GameObject): SMODS.GameObject +SMODS.GameObject = setmetatable({ + __call = function(self) + return self + end +}) + +---@param obj SMODS.GameObject|table +---@param prefix boolean|string? +---@param condition boolean? +---@param key string? +--- Modifies the object's key. +function SMODS.modify_key(obj, prefix, condition, key) end + +---@param cls SMODS.GameObject|table The class of this object +---@param obj SMODS.GameObject|table The object +---@param from_take_ownership true? +--- Adds prefixes into the object. +function SMODS.add_prefixes(cls, obj, from_take_ownership) end diff --git a/smods/lsp_def/classes/gradient.lua b/smods/lsp_def/classes/gradient.lua new file mode 100644 index 0000000..e6fd7d9 --- /dev/null +++ b/smods/lsp_def/classes/gradient.lua @@ -0,0 +1,38 @@ +---@meta + +---@class SMODS.Gradient: SMODS.GameObject +---@field interpolation? string Interpolation type of the gradient. Currently supported: `'trig'`, '`linear'`. +---@field colours? table> List of colours to interpolate between. +---@field cycle? number Amount of time (in seconds) for the gradient to cycle through all colours. +---@field __call? fun(self: SMODS.Gradient|table, o: SMODS.Gradient|table): nil|table|SMODS.Gradient +---@field extend? fun(self: SMODS.Gradient|table, o: SMODS.Gradient|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.Gradient|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.Gradient|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.Gradient|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.Gradient|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.Gradient|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.Gradient|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.Gradient|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.Gradient|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.Gradient|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.Gradient|table, i?: number) Called during `inject_class`. Injects the object into the game. +---@field take_ownership? fun(self: SMODS.Gradient|table, key: string, obj: SMODS.Gradient|table, silent?: boolean): nil|table|SMODS.Gradient Takes control of vanilla objects. Child class must have get_obj for this to function +---@field get_obj? fun(self: SMODS.Gradient|table, key: string): SMODS.Gradient|table? Returns an object if one matches the `key`. +---@overload fun(self: SMODS.Gradient): SMODS.Gradient +SMODS.Gradient = setmetatable({}, { + __call = function(self) + return self + end +}) + +---@type number? Red component of the current colour +SMODS.Gradient[1] = 0 +---@type number? Green component of the current colour +SMODS.Gradient[2] = 0 +---@type number? Blue component of the current colour +SMODS.Gradient[3] = 0 +---@type number? Opacity component of the current colour +SMODS.Gradient[4] = 1 + +---@type table +SMODS.Gradients = {} \ No newline at end of file diff --git a/smods/lsp_def/classes/joker.lua b/smods/lsp_def/classes/joker.lua new file mode 100644 index 0000000..9eda54c --- /dev/null +++ b/smods/lsp_def/classes/joker.lua @@ -0,0 +1,33 @@ +---@meta + +---@class SMODS.Joker: SMODS.Center +---@field super? SMODS.Center|table Parent class. +---@field __call? fun(self: SMODS.Joker|table, o: SMODS.Joker|table): nil|table|SMODS.Joker +---@field extend? fun(self: SMODS.Joker|table, o: SMODS.Joker|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.Joker|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.Joker|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.Joker|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.Joker|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.Joker|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.Joker|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.Joker|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.Joker|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.Joker|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.Joker|table, i?: number) Called during `inject_class`. Injects the object into the game. +---@field take_ownership? fun(self: SMODS.Joker|table, key: string, obj: SMODS.Joker|table, silent?: boolean): nil|table|SMODS.Joker Takes control of vanilla objects. Child class must have get_obj for this to function +---@field get_obj? fun(self: SMODS.Joker|table, key: string): SMODS.Joker|table? Returns an object if one matches the `key`. +---@field calc_dollar_bonus? fun(self: SMODS.Joker|table, card: Card|table): nil|number Calculates reward money. +---@field new? fun(self, name, slug, config, spritePos, loc_txt, rarity, cost, unlocked, discovered,blueprint_compat, eternal_compat, effect, atlas, soul_pos): any DEPRECATED. DO NOT USE +---@overload fun(self: SMODS.Joker): SMODS.Joker +SMODS.Joker = setmetatable({}, { + __call = function(self) + return self + end +}) + +---@param self Card|table +---@param context CalcContext|table +---@return table? effect +---@return boolean? # Return `true` if the Joker was calculated but no effect was provided. +--- Calculates Jokers. +function Card:calculate_joker(context) end diff --git a/smods/lsp_def/classes/keybind.lua b/smods/lsp_def/classes/keybind.lua new file mode 100644 index 0000000..db06ede --- /dev/null +++ b/smods/lsp_def/classes/keybind.lua @@ -0,0 +1,33 @@ +---@meta + +---@class SMODS.Keybind: SMODS.GameObject +---@field obj_table? table Table of objects registered to this class. +---@field super? SMODS.GameObject|table Parent class. +---@field key_pressed? string Required key to press for this keybind to activate. Keycodes are documented [here](https://love2d.org/wiki/KeyConstant). +---@field event? "pressed"|"released"|"held" Defines when the keybind should trigger. "pressed": on key press, "released": on key release, "held": on key hold for specified amount of time. +---@field held_duration? number How long the keybind needs to be pressed before activation. Only active if `event = "held"`. +---@field held_keys? string[] Array of keycodes additionally required to be pressed for keybind to activate. +---@field __call? fun(self: SMODS.Keybind|table, o: SMODS.Keybind|table): nil|table|SMODS.Keybind +---@field extend? fun(self: SMODS.Keybind|table, o: SMODS.Keybind|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.Keybind|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.Keybind|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.Keybind|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.Keybind|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.Keybind|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.Keybind|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.Keybind|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.Keybind|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.Keybind|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.Keybind|table, i?: number) Called during `inject_class`. Injects the object into the game. +---@field take_ownership? fun(self: SMODS.Keybind|table, key: string, obj: SMODS.Keybind|table, silent?: boolean): nil|table|SMODS.Keybind Takes control of vanilla objects. Child class must have get_obj for this to function +---@field get_obj? fun(self: SMODS.Keybind|table, key: string): SMODS.Keybind|table? Returns an object if one matches the `key`. +---@field action? fun(self: SMODS.Keybind|table) Called when the keybind is triggered. +---@overload fun(self: SMODS.Keybind): SMODS.Keybind +SMODS.Keybind = setmetatable({}, { + __call = function(self) + return self + end +}) + +---@type table +SMODS.Keybinds = {} \ No newline at end of file diff --git a/smods/lsp_def/classes/language.lua b/smods/lsp_def/classes/language.lua new file mode 100644 index 0000000..615a3f8 --- /dev/null +++ b/smods/lsp_def/classes/language.lua @@ -0,0 +1,31 @@ +---@meta + +---@class SMODS.Language: SMODS.GameObject +---@field obj_table? table Table of objects registered to this class. +---@field super? SMODS.GameObject|table Parent class. +---@field label? string Label displayed in the language selection screen. +---@field font? number|table Font the in-game text uses. Using the number 1-9 uses vanilla fonts, and specifying a table uses custom font. See [SMODS.Language](https://github.com/Steamodded/smods/wiki/SMODS.Language) docs for details. +---@field loc_key? string Key to another language. Treats it as a base, keeping any unchanged localization strings intact and adding changes to the language and fonts. +---@field __call? fun(self: SMODS.Language|table, o: SMODS.Language|table): nil|table|SMODS.Language +---@field extend? fun(self: SMODS.Language|table, o: SMODS.Language|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.Language|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.Language|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.Language|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.Language|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.Language|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.Language|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.Language|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.Language|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.Language|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.Language|table, i?: number) Called during `inject_class`. Injects the object into the game. +---@field take_ownership? fun(self: SMODS.Language|table, key: string, obj: SMODS.Language|table, silent?: boolean): nil|table|SMODS.Language Takes control of vanilla objects. Child class must have get_obj for this to function +---@field get_obj? fun(self: SMODS.Language|table, key: string): SMODS.Language|table? Returns an object if one matches the `key`. +---@overload fun(self: SMODS.Language): SMODS.Language +SMODS.Language = setmetatable({}, { + __call = function(self) + return self + end +}) + +---@type table +SMODS.Languages = {} \ No newline at end of file diff --git a/smods/lsp_def/classes/object_type.lua b/smods/lsp_def/classes/object_type.lua new file mode 100644 index 0000000..6d82fcf --- /dev/null +++ b/smods/lsp_def/classes/object_type.lua @@ -0,0 +1,33 @@ +---@meta + +---@class SMODS.ObjectType: SMODS.GameObject +---@field obj_table? table Table of objects registered to this class. +---@field super? SMODS.GameObject|table Parent class. +---@field default? string Key to fallback center when object pool is empty. +---@field cards? table List of keys to centers to auto-inject into the pool. +---@field rarities? table[] Array of tables representing rarities. Each table must contain the key to the rarity, with an optional arg of `weight` (omitting uses rarity default, see `SMODS.Rarity.default_weight`). +---@field __call? fun(self: SMODS.ObjectType|table, o: SMODS.ObjectType|table): nil|table|SMODS.ObjectType +---@field extend? fun(self: SMODS.ObjectType|table, o: SMODS.ObjectType|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.ObjectType|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.ObjectType|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.ObjectType|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.ObjectType|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.ObjectType|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.ObjectType|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.ObjectType|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.ObjectType|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.ObjectType|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.ObjectType|table, i?: number) Called during `inject_class`. Injects the object into the game. +---@field take_ownership? fun(self: SMODS.ObjectType|table, key: string, obj: SMODS.ObjectType|table, silent?: boolean): nil|table|SMODS.ObjectType Takes control of vanilla objects. Child class must have get_obj for this to function +---@field get_obj? fun(self: SMODS.ObjectType|table, key: string): SMODS.ObjectType|table? Returns an object if one matches the `key`. +---@field inject_card? fun(self: SMODS.ObjectType|table, center: table) Injects the center into the ObjectType pools. +---@field remove_card? fun(self: SMODS.ObjectType|table, center: table) Removes the center from ObjectType pools. +---@overload fun(self: SMODS.ObjectType): SMODS.ObjectType +SMODS.ObjectType = setmetatable({}, { + __call = function(self) + return self + end +}) + +---@type table +SMODS.ObjectTypes = {} \ No newline at end of file diff --git a/smods/lsp_def/classes/poker_hand.lua b/smods/lsp_def/classes/poker_hand.lua new file mode 100644 index 0000000..539e7af --- /dev/null +++ b/smods/lsp_def/classes/poker_hand.lua @@ -0,0 +1,66 @@ +---@meta + +---@class SMODS.PokerHand: SMODS.GameObject +---@field obj_table? table Table of objects registered to this class. +---@field loc_txt? table|{name: string, description: string[]} Contains strings used for displaying text related to this object. +---@field super? SMODS.GameObject|table Parent class. +---@field mult? number Base mult for poker hand. +---@field chips? number Base chips for poker hand. +---@field l_mult? number Mult gained per hand level. +---@field l_chips? number Chips gained per hand level. +---@field example? table Table of cards used to represent the hand example in the "Run Info" tab. +---@field visisble? boolean Sets hand visibility in the poker hands menu. If `false`, poker hand is shown only after being played once. +---@field above_hand? string Key to a poker hand. Used to order this poker hand above specified poker hand. +---@field order_offset? number Adds this value to poker hand's mult and chips to offset ordering. +---@field __call? fun(self: SMODS.PokerHand|table, o: SMODS.PokerHand|table): nil|table|SMODS.PokerHand +---@field extend? fun(self: SMODS.PokerHand|table, o: SMODS.PokerHand|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.PokerHand|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.PokerHand|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.PokerHand|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.PokerHand|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.PokerHand|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.PokerHand|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.PokerHand|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.PokerHand|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.PokerHand|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.PokerHand|table, i?: number) Called during `inject_class`. Injects the object into the game. +---@field take_ownership? fun(self: SMODS.PokerHand|table, key: string, obj: SMODS.PokerHand|table, silent?: boolean): nil|table|SMODS.PokerHand Takes control of vanilla objects. Child class must have get_obj for this to function +---@field get_obj? fun(self: SMODS.PokerHand|table, key: string): SMODS.PokerHand|table? Returns an object if one matches the `key`. +---@field evaluate? fun(parts: table, hand: table): table? Determines if played cards contain this hand, and what cards are a part of it. +---@field modify_display_text? fun(self: SMODS.PokerHand|table, cards: Card[]|table[], scoring_hand: Card[]|table[]): string? Allows modifying the display text when this poker hand's text is meant to display. +---@overload fun(self: SMODS.PokerHand): SMODS.PokerHand +SMODS.PokerHand = setmetatable({}, { + __call = function(self) + return self + end +}) + +---@type table +SMODS.PokerHands = {} + +---@class SMODS.PokerHandPart: SMODS.GameObject +---@field super? SMODS.GameObject|table Parent class. +---@field __call? fun(self: SMODS.PokerHandPart|table, o: SMODS.PokerHandPart|table): nil|table|SMODS.PokerHandPart +---@field extend? fun(self: SMODS.PokerHandPart|table, o: SMODS.PokerHandPart|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.PokerHandPart|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.PokerHandPart|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.PokerHandPart|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.PokerHandPart|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.PokerHandPart|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.PokerHandPart|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.PokerHandPart|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.PokerHandPart|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.PokerHandPart|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.PokerHandPart|table, i?: number) Called during `inject_class`. Injects the object into the game. +---@field take_ownership? fun(self: SMODS.PokerHandPart|table, key: string, obj: SMODS.PokerHandPart|table, silent?: boolean): nil|table|SMODS.PokerHandPart Takes control of vanilla objects. Child class must have get_obj for this to function +---@field get_obj? fun(self: SMODS.PokerHandPart|table, key: string): SMODS.PokerHandPart|table? Returns an object if one matches the `key`. +---@field func? fun(hand: Card[]|table[]): Card[]|table[] Returns array of cards that are a part of this hand. +---@overload fun(self: SMODS.PokerHandPart): SMODS.PokerHandPart +SMODS.PokerHandPart = setmetatable({}, { + __call = function(self) + return self + end +}) + +---@type table +SMODS.PokerHandParts = {} \ No newline at end of file diff --git a/smods/lsp_def/classes/rank.lua b/smods/lsp_def/classes/rank.lua new file mode 100644 index 0000000..3d1f5e9 --- /dev/null +++ b/smods/lsp_def/classes/rank.lua @@ -0,0 +1,47 @@ +---@meta + +---@class SMODS.Rank: SMODS.GameObject +---@field obj_table? table Table of objects registered to this class. +---@field loc_txt? table|{name: string} Contains strings used for displaying text related to this object. +---@field super? SMODS.GameObject|table Parent class. +---@field atlas? string Key to the rank's atlas. +---@field pos? table|{x: integer} Position of the center's sprite. `y` is handled automatically. +---@field card_key? string Used for creating keys for playing cards. Card keys follow `S_R`, `S` being the rank and `R` being the rank. +---@field lc_atlas? string Atlas used for low-contrast cards. +---@field hc_atlas? string Atlas used for high-contrast cards. +---@field nominal? number Amount of chips this rank should score. +---@field shorthand? string Short description of this rank in deck preview. +---@field face_nominal? number Determines the displayed order of ranks with the same nominal value. +---@field face? boolean Sets if this rank counts as a "face" card. +---@field next? string[] List of keys to other ranks that come after this card. +---@field prev? string[] List of keys to other ranks that come before this card. Used when evaluating straights. +---@field strength_effect? table|{fixed?: number, random?: boolean, ignore?: boolean} Determines how cards with this rank behave when Strength is used. +---@field straight_edge? boolean Sets if this rank behaves like an Ace for straights. +---@field suit_map? table For any suit keys in this table, use this rank's atlas over the suit's atlas. Provided number is the `y` position of the suit on the rank's atlas. +---@field __call? fun(self: SMODS.Rank|table, o: SMODS.Rank|table): nil|table|SMODS.Rank +---@field extend? fun(self: SMODS.Rank|table, o: SMODS.Rank|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.Rank|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.Rank|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.Rank|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.Rank|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.Rank|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.Rank|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.Rank|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.Rank|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.Rank|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.Rank|table, i?: number) Called during `inject_class`. Injects the object into the game. +---@field take_ownership? fun(self: SMODS.Rank|table, key: string, obj: SMODS.Rank|table, silent?: boolean): nil|table|SMODS.Rank Takes control of vanilla objects. Child class must have get_obj for this to function +---@field get_obj? fun(self: SMODS.Rank|table, key: string): SMODS.Rank|table? Returns an object if one matches the `key`. +---@field loc_vars? fun(self: SMODS.Rank|table, info_queue: table, card: Card|table) Allows adding tooltips onto cards with this suit. Return values not respected. +---@field draw? fun(self: SMODS.Rank|table, card: Card|table, layer: string) Allows drawing additional sprites or shaders onto cards with this suit. +---@field in_pool? fun(self: SMODS.Rank|table, args: table): boolean? Allows configuring if cards with this suit should spawn. +---@field delete? fun(self: SMODS.Rank|table) Deletes this suit. +---@overload fun(self: SMODS.Rank): SMODS.Rank +SMODS.Rank = setmetatable({}, { + __call = function(self) + return self + end +}) + +---@type table +SMODS.Ranks = {} diff --git a/smods/lsp_def/classes/rarity.lua b/smods/lsp_def/classes/rarity.lua new file mode 100644 index 0000000..82a3e49 --- /dev/null +++ b/smods/lsp_def/classes/rarity.lua @@ -0,0 +1,46 @@ +---@meta + +---@class SMODS.Rarity: SMODS.GameObject +---@field obj_table? table Table of objects registered to this class. +---@field loc_txt? table|{name: string} Contains strings used for displaying text related to this object. +---@field super? SMODS.GameObject|table Parent class. +---@field pools? table Table with a list of ObjectTypes keys this rarity should be added to. +---@field badge_colour? table HEX color the rarity badge uses. +---@field default_weight? number Default weight of the rarity. When referenced in ObjectTypes with just the key, this value is used as the default. +---@field __call? fun(self: SMODS.Rarity|table, o: SMODS.Rarity|table): nil|table|SMODS.Rarity +---@field extend? fun(self: SMODS.Rarity|table, o: SMODS.Rarity|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.Rarity|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.Rarity|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.Rarity|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.Rarity|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.Rarity|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.Rarity|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.Rarity|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.Rarity|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.Rarity|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.Rarity|table, i?: number) Called during `inject_class`. Injects the object into the game. +---@field take_ownership? fun(self: SMODS.Rarity|table, key: string, obj: SMODS.Rarity|table, silent?: boolean): nil|table|SMODS.Rarity Takes control of vanilla objects. Child class must have get_obj for this to function +---@field get_obj? fun(self: SMODS.Rarity|table, key: string): SMODS.Rarity|table? Returns an object if one matches the `key`. +---@field get_weight? fun(self: SMODS.Rarity|table, weight: number, object_type: SMODS.ObjectType): number Used for finer control over this rarity's weight. +---@field gradient? fun(self: SMODS.Rarity|table, dt: number) Used to make a gradient for this rarity's `badge_colour`. +---@field get_rarity_badge? fun(self: SMODS.Rarity|table, rarity: string): string Returns localized rarity key. +---@overload fun(self: SMODS.Rarity): SMODS.Rarity +SMODS.Rarity = setmetatable({}, { + __call = function(self) + return self + end +}) + +---@type table +SMODS.Rarities = {} + +---@param _pool_key string Key to ObjectType +---@param _rand_key? string Used as polling seed +---@return string|number rarity_key +---Polls all rarities tied to provided ObjectType. +function SMODS.poll_rarity(_pool_key, _rand_key) end + +---@param object_type SMODS.ObjectType|table +---@param rarity SMODS.Rarity +---Injects `rarity` into `object_type`. +function SMODS.inject_rarity(object_type, rarity) end diff --git a/smods/lsp_def/classes/seal.lua b/smods/lsp_def/classes/seal.lua new file mode 100644 index 0000000..2a0bdce --- /dev/null +++ b/smods/lsp_def/classes/seal.lua @@ -0,0 +1,48 @@ +---@meta + +---@class SMODS.Seal: SMODS.GameObject +---@field obj_table? table Table of objects registered to this class. +---@field loc_txt? table|{name: string, text: string[], label: string} Contains strings used for displaying text related to this object. +---@field super? SMODS.GameObject|table Parent class. +---@field atlas? string Key to the seal's atlas. +---@field pos? table|{x: integer, y: integer} Position of the seal's sprite. +---@field unlocked? boolean Sets the unlock state of the center. +---@field badge_colour? table HEX color the seal badge uses. +---@field sound? table|{} Controls the sound that plays when the seal is applied. `sound`: Key to the sound, `per`: Sound pitch, `vol`: Sound volume. +---@field badge_to_key? string[] Contains keys to each seal indexed by seal badge (`key:lower()..'_seal`). +---@field __call? fun(self: SMODS.Seal|table, o: SMODS.Seal|table): nil|table|SMODS.Seal +---@field extend? fun(self: SMODS.Seal|table, o: SMODS.Seal|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.Seal|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.Seal|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.Seal|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.Seal|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.Seal|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.Seal|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.Seal|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.Seal|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.Seal|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.Seal|table, i?: number) Called during `inject_class`. Injects the object into the game. +---@field take_ownership? fun(self: SMODS.Seal|table, key: string, obj: SMODS.Seal|table, silent?: boolean): nil|table|SMODS.Seal Takes control of vanilla objects. Child class must have get_obj for this to function +---@field get_obj? fun(self: SMODS.Seal|table, key: string): SMODS.Seal|table? Returns an object if one matches the `key`. +---@field loc_vars? fun(self: SMODS.Seal|table, info_queue: table, card: Card|table): table? Provides control over displaying the tooltip of this seal. See [`loc_vars`](https://github.com/Steamodded/smods/wiki/Localization#loc_vars) documentation for details. +---@field calculate? fun(self: SMODS.Seal|table, card: Card|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 get_p_dollars? fun(self: SMODS.Seal|table, card: Card|table): number? Gives money when a card with this seal is played. +---@field draw? fun(self: SMODS.Seal|table, card: Card|table, layer: string) Draws the sprite and shader of the seal. +---@field update? fun(self: SMODS.Seal|table, card: Card|table, dt: number) Allows logic for this card to be run per-frame. +---@field generate_ui? fun(self: SMODS.Seal|table, info_queue: table, card: Card|table, desc_nodes: table, specific_vars: table, full_UI_table: table) Provides complex control over the UI display of the seal. See [`generate_ui`](https://github.com/Steamodded/smods/wiki/Localization#generate_ui-advanced) documentation for details. +---@field create_fake_card? fun(self: SMODS.Seal|table): table Creates a fake card with this seal. Used internally for `generate_ui` in cases where recieved `card` param is nil. +---@field new? fun(self, name, label, full_name, pos, loc_txt, atlas, discovered, color): any DEPRECATED. DO NOT USE +---@overload fun(self: SMODS.Seal): SMODS.Seal +SMODS.Seal = setmetatable({}, { + __call = function(self) + return self + end +}) + +---@type table +SMODS.Seals = {} + +---@param args table|{key?: string, mod?: number, guaranteed?: boolean, options?: table, type_key?: string} +---@return string? +--- Polls seals. +function SMODS.poll_seal(args) end diff --git a/smods/lsp_def/classes/shader.lua b/smods/lsp_def/classes/shader.lua new file mode 100644 index 0000000..57415d6 --- /dev/null +++ b/smods/lsp_def/classes/shader.lua @@ -0,0 +1,31 @@ +---@meta + +---@class SMODS.Shader: SMODS.GameObject +---@field obj_table? table Table of objects registered to this class. +---@field super? SMODS.GameObject|table Parent class. +---@field key? string Unique string to reference this object. This, `path`, and shader name in the GLSL must be the same. +---@field path? string Name of the shader file. This, `key`, and shader name in the GLSL must be the same. +---@field __call? fun(self: SMODS.Shader|table, o: SMODS.Shader|table): nil|table|SMODS.Shader +---@field extend? fun(self: SMODS.Shader|table, o: SMODS.Shader|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.Shader|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.Shader|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.Shader|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.Shader|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.Shader|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.Shader|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.Shader|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.Shader|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.Shader|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.Shader|table, i?: number) Called during `inject_class`. Injects the object into the game. +---@field take_ownership? fun(self: SMODS.Shader|table, key: string, obj: SMODS.Shader|table, silent?: boolean): nil|table|SMODS.Shader Takes control of vanilla objects. Child class must have get_obj for this to function +---@field get_obj? fun(self: SMODS.Shader|table, key: string): SMODS.Shader|table? Returns an object if one matches the `key`. +---@field send_vars? fun(self: SMODS.Shader|table, sprite: Sprite, card: nil|Card): table? Used to send extra args to the shader via `Shader:send(key, value)`. +---@overload fun(self: SMODS.Shader): SMODS.Shader +SMODS.Shader = setmetatable({}, { + __call = function(self) + return self + end +}) + +---@type table +SMODS.Shaders = {} \ No newline at end of file diff --git a/smods/lsp_def/classes/sound.lua b/smods/lsp_def/classes/sound.lua new file mode 100644 index 0000000..d496b41 --- /dev/null +++ b/smods/lsp_def/classes/sound.lua @@ -0,0 +1,38 @@ +---@meta + +---@class SMODS.Sound: SMODS.GameObject +---@field obj_table? table Table of objects registered to this class. +---@field super? SMODS.GameObject|table Parent class. +---@field path? string Name of the sound file, including extension. +---@field pitch? number Pitch for music tracks. +---@field volume? number Volume for music tracks. +---@field replace? string|table Replaces specific sound with this sound whenever played. Behaves like `SMODS.Sound:create_replace_sound()`. +---@field sync? false|table Configured syncing for music tracks. Setting to `false` prevents the music track from syncing with anything. +---@field __call? fun(self: SMODS.Sound|table, o: SMODS.Sound|table): nil|table|SMODS.Sound +---@field extend? fun(self: SMODS.Sound|table, o: SMODS.Sound|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.Sound|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.Sound|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.Sound|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.Sound|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.Sound|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.Sound|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.Sound|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.Sound|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.Sound|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.Sound|table, i?: number) Called during `inject_class`. Injects the object into the game. +---@field take_ownership? fun(self: SMODS.Sound|table, key: string, obj: SMODS.Sound|table, silent?: boolean): nil|table|SMODS.Sound Takes control of vanilla objects. Child class must have get_obj for this to function +---@field get_obj? fun(self: SMODS.Sound|table, key: string): SMODS.Sound|table? Returns an object if one matches the `key`. +---@field select_music_track? fun(self: SMODS.Sound|table): nil|number|boolean Called each frame. Determines what music track to play. Music track with the highest number is played. +---@field create_replace_sound? fun(self: SMODS.Sound|table, replace: string|table) Replaces another sound with this one. +---@field create_stop_sound? fun(self: SMODS.Sound|table, key: string, times: nil|number) Supress sounds with the given sound code `times` amount of times or indefinitely. +---@field register_global? fun(self: SMODS.Sound|table) Registers all sound files of the current mod. +---@field get_current_music? fun(self: SMODS.Sound|table): nil|string Polls `SMODS.Sound:select_music_track` and returns the key to the music to play. +---@overload fun(self: SMODS.Sound): SMODS.Sound +SMODS.Sound = setmetatable({}, { + __call = function(self) + return self + end +}) + +---@type table +SMODS.Sounds = {} \ No newline at end of file diff --git a/smods/lsp_def/classes/stake.lua b/smods/lsp_def/classes/stake.lua new file mode 100644 index 0000000..adae7ca --- /dev/null +++ b/smods/lsp_def/classes/stake.lua @@ -0,0 +1,60 @@ +---@meta + +---@class SMODS.Stake: SMODS.GameObject +---@field obj_table? table Table of objects registered to this class. +---@field loc_txt? table|{name: string, text: string[], sticker: table|{name: string, text: string[]} } Contains strings used for displaying text related to this object. +---@field super? SMODS.GameObject|table Parent class. +---@field applied_stakes? string[] Array of keys to stakes that should be applied when this stake is active. +---@field atlas? string Key to the center's atlas. +---@field pos? table|{x: integer, y: integer} Position of the center's sprite. +---@field sticker_atlas? string Atlas for stake's win sticker. +---@field sticker_pos? table|{x: integer, y: integer} Position of the stake's win sticker sprite. +---@field above_stake? string Key to the stake that this stake appeard above in the run menu. By default, stakes are added on top of the last injected stake. +---@field colour? table HEX color of the stake in the stake selection menu. +---@field unlocked? boolean Sets if the stake is unlocked by default. +---@field shiny? boolean Draws the shiny shader on State sticker. +---@field __call? fun(self: SMODS.Stake|table, o: SMODS.Stake|table): nil|table|SMODS.Stake +---@field extend? fun(self: SMODS.Stake|table, o: SMODS.Stake|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.Stake|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.Stake|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.Stake|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.Stake|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.Stake|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.Stake|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.Stake|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.Stake|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.Stake|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.Stake|table, i?: number) Called during `inject_class`. Injects the object into the game. +---@field take_ownership? fun(self: SMODS.Stake|table, key: string, obj: SMODS.Stake|table, silent?: boolean): nil|table|SMODS.Stake Takes control of vanilla objects. Child class must have get_obj for this to function +---@field get_obj? fun(self: SMODS.Stake|table, key: string): SMODS.Stake|table? Returns an object if one matches the `key`. +---@field modifiers? fun() Applies changes to the game state when this stake is applied at the start of a run. +---@overload fun(self: SMODS.Stake): SMODS.Stake +SMODS.Stake = setmetatable({}, { + __call = function(self) + return self + end +}) + +---@type table +SMODS.Stakes = {} + +---@param stake SMODS.Stake|table +---@param applied table? +---@return table applied +---Builds the stake chain. +function SMODS.build_stake_chain(stake, applied) end + +---@param i number +---Sets up stakes after deck select, calls `SMODS.Stake.modifier()` on all applied stakes. +function SMODS.setup_stake(i) end + +---@param index number +---@return number|string +---Given an index from the Stake pool, return corresponding key or `"error"` if it doesn't exist +function SMODS.stake_from_index(index) end + +---@param i number +---@param stake_desc_rows table +---@param num_added? { val: number } +--- Creates "Applies X" Stake UI. +function SMODS.applied_stakes_UI(i, stake_desc_rows, num_added) end diff --git a/smods/lsp_def/classes/sticker.lua b/smods/lsp_def/classes/sticker.lua new file mode 100644 index 0000000..72f43d1 --- /dev/null +++ b/smods/lsp_def/classes/sticker.lua @@ -0,0 +1,61 @@ +---@meta + +---@class SMODS.Sticker: SMODS.GameObject +---@field obj_table? table Table of objects registered to this class. +---@field super? SMODS.GameObject|table Parent class. +---@field atlas? string Key to the center's atlas. +---@field pos? table|{x: integer, y: integer} Position of the center's sprite. +---@field order? number Position of the sticker in collections menu. +---@field rate? number Change of this sticker applying onto an eligible card. +---@field hide_badge? boolean Sets if the sticker badge shows up on the card. +---@field badge_colour? table HEX color the sticker badge uses. +---@field default_compat? boolean Default compatibility with cards. +---@field compat_exceptions? string[] Array of keys to centers that are exceptions to `default_compat`. +---@field sets? string[] Array of keys to pools that this sticker is allowed to be applied on. +---@field needs_enabled_flag? boolean Sets whether the sticker requires `G.GAME.modifiers["enable_"..key]` to be `true` before it can be applied. +---@field sticker_sprite? Sprite|table Sprite object of the sticker. +---@field __call? fun(self: SMODS.Sticker|table, o: SMODS.Sticker|table): nil|table|SMODS.Sticker +---@field extend? fun(self: SMODS.Sticker|table, o: SMODS.Sticker|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.Sticker|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.Sticker|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.Sticker|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.Sticker|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.Sticker|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.Sticker|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.Sticker|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.Sticker|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.Sticker|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.Sticker|table, i?: number) Called during `inject_class`. Injects the object into the game. +---@field take_ownership? fun(self: SMODS.Sticker|table, key: string, obj: SMODS.Sticker|table, silent?: boolean): nil|table|SMODS.Sticker Takes control of vanilla objects. Child class must have get_obj for this to function +---@field get_obj? fun(self: SMODS.Sticker|table, key: string): SMODS.Sticker|table? Returns an object if one matches the `key`. +---@field loc_vars? fun(self: SMODS.Sticker|table, info_queue: table, card: Card|table): table? Provides control over displaying descriptions and tooltips of the sticker's tooltip. See [SMODS.Sticker `loc_vars` implementation](https://github.com/Steamodded/smods/wiki/SMODS.Sticker#api-methods) documentation for details. +---@field calculate? fun(self: SMODS.Sticker|table, card: Card|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 should_apply? boolean|fun(self: SMODS.Sticker|table, card: Card, center: table, area: CardArea, bypass_reroll?: boolean): boolean Determines if the sticker applies onto the card. If `bypass_reroll` is true, ignore RNG check. +---@field apply? fun(self: SMODS.Sticker|table, card: Card|table, val: any) Handles applying and removing the sticker. By default, sets `card.ability[self.key] = val`. +---@field draw? fun(self: SMODS.Sticker|table, card: Card|table, layer: string) Draws the sprite and shader of the sticker. +---@overload fun(self: SMODS.Sticker): SMODS.Sticker +SMODS.Sticker = setmetatable({}, { + __call = function(self) + return self + end +}) + +---@type table +SMODS.Stickers = {} + +---@param self Card|table +---@param sticker string Key to the sticker to apply. +---@param bypass_check? boolean Whether the sticker's `should_apply` function is called. +--- Adds the sticker onto the card. +function Card:add_sticker(sticker, bypass_check) end + +---@param self Card|table +---@param sticker string Key to the sticker to remove. +--- Removes the sticker from the card, if it has the sticker. +function Card:remove_sticker(sticker) end + +---@param self Card|table +---@param key string +---@return table? +--- Calculates Stickers on cards. +function Card:calculate_sticker(context, key) end diff --git a/smods/lsp_def/classes/suit.lua b/smods/lsp_def/classes/suit.lua new file mode 100644 index 0000000..809e144 --- /dev/null +++ b/smods/lsp_def/classes/suit.lua @@ -0,0 +1,43 @@ +---@meta + +---@class SMODS.Suit: SMODS.GameObject +---@field obj_table? table Table of objects registered to this class. +---@field loc_txt? table|{singular: string, plural: string} Contains strings used for displaying text related to this object. +---@field super? SMODS.GameObject|table Parent class. +---@field atlas? string Key to the suit's atlas. +---@field pos? table|{y: integer} Position of the center's sprite. `x` is handled automatically. +---@field card_key? string Used for creating keys for playing cards. Card keys follow `S_R`, `S` being the suit and `R` being the rank. +---@field ui_pos? table|{x: integer, y: integer} Sprite position of the miniature suit symbol used in deck view. +---@field lc_atlas? string Atlas used for low-contrast cards. +---@field hc_atlas? string Atlas used for high-contrast cards. +---@field lc_ui_atlas? string Atlas used for low-contrast mini suit symbol in deck view. +---@field hc_ui_atlas? string Atlas used for high-contrast mini suit symbol in deck view. +---@field lc_colour? table HEX color of the suit text for low-contrast. +---@field hc_colour? table HEX color of the suit text for high-contrast. +---@field __call? fun(self: SMODS.Suit|table, o: SMODS.Suit|table): nil|table|SMODS.Suit +---@field extend? fun(self: SMODS.Suit|table, o: SMODS.Suit|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.Suit|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.Suit|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.Suit|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.Suit|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.Suit|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.Suit|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.Suit|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.Suit|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.Suit|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.Suit|table, i?: number) Called during `inject_class`. Injects the object into the game. +---@field take_ownership? fun(self: SMODS.Suit|table, key: string, obj: SMODS.Suit|table, silent?: boolean): nil|table|SMODS.Suit Takes control of vanilla objects. Child class must have get_obj for this to function +---@field get_obj? fun(self: SMODS.Suit|table, key: string): SMODS.Suit|table? Returns an object if one matches the `key`. +---@field loc_vars? fun(self: SMODS.Suit|table, info_queue: table, card: Card|table) Allows adding tooltips onto cards with this suit. Return values not respected. +---@field draw? fun(self: SMODS.Suit|table, card: Card|table, layer: string) Allows drawing additional sprites or shaders onto cards with this suit. +---@field in_pool? fun(self: SMODS.Suit|table, args: table): boolean? Allows configuring if cards with this suit should spawn. +---@field delete? fun(self: SMODS.Suit|table) Deletes this suit. +---@overload fun(self: SMODS.Suit): SMODS.Suit +SMODS.Suit = setmetatable({}, { + __call = function(self) + return self + end +}) + +---@type table +SMODS.Suits = {} diff --git a/smods/lsp_def/classes/tag.lua b/smods/lsp_def/classes/tag.lua new file mode 100644 index 0000000..f4bd336 --- /dev/null +++ b/smods/lsp_def/classes/tag.lua @@ -0,0 +1,37 @@ +---@meta + +---@class SMODS.Tag: SMODS.GameObject +---@field obj_table? table Table of objects registered to this class. +---@field super? SMODS.GameObject|table Parent class. +---@field atlas? string Key to the center's atlas. +---@field pos? table|{x: integer, y: integer} Position of the center's sprite. +---@field min_ante? number Minimum ante needed for this tag to appear. For more complex restrictions, use `SMODS.Tag:in_pool()`. +---@field discovered? boolean Sets the discovery state of the tag. +---@field __call? fun(self: SMODS.Tag|table, o: SMODS.Tag|table): nil|table|SMODS.Tag +---@field extend? fun(self: SMODS.Tag|table, o: SMODS.Tag|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.Tag|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.Tag|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.Tag|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.Tag|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.Tag|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.Tag|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.Tag|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.Tag|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.Tag|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.Tag|table, i?: number) Called during `inject_class`. Injects the object into the game. +---@field take_ownership? fun(self: SMODS.Tag|table, key: string, obj: SMODS.Tag|table, silent?: boolean): nil|table|SMODS.Tag Takes control of vanilla objects. Child class must have get_obj for this to function +---@field get_obj? fun(self: SMODS.Tag|table, key: string): SMODS.Tag|table? Returns an object if one matches the `key`. +---@field apply? fun(self: SMODS.Tag|table, tag: Tag|table, context: table): any? Defines behaviour when a tag triggers. To trigger, call `Tag:yep()`. See [SMODS.Tag](https://github.com/Steamodded/smods/wiki/SMODS.Tag#api-methods) wiki for details. +---@field set_ability? fun(self: SMODS.Tag|table, tag: Tag|table) Sets up initial ability for the tag. Values should be stored in `tag.ability`. +---@field generate_ui? fun(self: SMODS.Tag|table, info_queue: table, tag: Tag|table, desc_nodes: table, specific_vars: table, full_UI_table: table) Provides complex control over the UI display of the tag. See [`generate_ui`](https://github.com/Steamodded/smods/wiki/Localization#generate_ui-advanced) documentation for details. +---@field loc_vars? fun(self: SMODS.Tag|table, info_queue: table, tag: Tag|table): table? Provides simple control over displaying descriptions and tooltips of the tag. See [`loc_vars`](https://github.com/Steamodded/smods/wiki/Localization#loc_vars) documentation for details. +---@field in_pool? fun(self: SMODS.Tag|table, args: table): nil|boolean, table? Allows configuring if the tag is allowed to spawn. +---@overload fun(self: SMODS.Tag): SMODS.Tag +SMODS.Tag = setmetatable({}, { + __call = function(self) + return self + end +}) + +---@type table +SMODS.Tags = {} \ No newline at end of file diff --git a/smods/lsp_def/classes/undiscovered_sprite.lua b/smods/lsp_def/classes/undiscovered_sprite.lua new file mode 100644 index 0000000..1fa4e3b --- /dev/null +++ b/smods/lsp_def/classes/undiscovered_sprite.lua @@ -0,0 +1,34 @@ +---@meta + +---@class SMODS.UndiscoveredSprite: SMODS.GameObject +---@field obj_table? table Table of objects registered to this class. +---@field super? SMODS.GameObject|table Parent class. +---@field key? string Key to the ObjectType this UndiscoveredSprite is made for. +---@field atlas? string Key to the undiscovered sprite's atlas. +---@field pos? table|{x: integer, y: integer} Position of the undiscovered sprite. +---@field lc_atlas? string Low constrast atlas. Used when `G.SETTINGS.colourblind_option` is `false`. +---@field hc_atlas? string High contrast atlas. Used when `G.SETTINGS.colourblind_option` is `true`. +---@field no_overlay? boolean Sets whether the floating "?" is drawn or not. +---@field __call? fun(self: SMODS.UndiscoveredSprite|table, o: SMODS.UndiscoveredSprite|table): nil|table|SMODS.UndiscoveredSprite +---@field extend? fun(self: SMODS.UndiscoveredSprite|table, o: SMODS.UndiscoveredSprite|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.UndiscoveredSprite|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.UndiscoveredSprite|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.UndiscoveredSprite|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.UndiscoveredSprite|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.UndiscoveredSprite|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.UndiscoveredSprite|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.UndiscoveredSprite|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.UndiscoveredSprite|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.UndiscoveredSprite|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.UndiscoveredSprite|table, i?: number) Called during `inject_class`. Injects the object into the game. +---@field take_ownership? fun(self: SMODS.UndiscoveredSprite|table, key: string, obj: SMODS.UndiscoveredSprite|table, silent?: boolean): nil|table|SMODS.UndiscoveredSprite Takes control of vanilla objects. Child class must have get_obj for this to function +---@field get_obj? fun(self: SMODS.UndiscoveredSprite|table, key: string): SMODS.UndiscoveredSprite|table? Returns an object if one matches the `key`. +---@overload fun(self: SMODS.UndiscoveredSprite): SMODS.UndiscoveredSprite +SMODS.UndiscoveredSprite = setmetatable({}, { + __call = function(self) + return self + end +}) + +---@type table +SMODS.UndiscoveredSprites = {} \ No newline at end of file diff --git a/smods/lsp_def/classes/voucher.lua b/smods/lsp_def/classes/voucher.lua new file mode 100644 index 0000000..270ed06 --- /dev/null +++ b/smods/lsp_def/classes/voucher.lua @@ -0,0 +1,27 @@ +---@meta + +---@class SMODS.Voucher: SMODS.Center +---@field super? SMODS.Center|table Parent class. +---@field requires? string[] Array of keys to other voucher. This voucher will not appear if those are not redeemed. +---@field __call? fun(self: SMODS.Voucher|table, o: SMODS.Voucher|table): nil|table|SMODS.Voucher +---@field extend? fun(self: SMODS.Voucher|table, o: SMODS.Voucher|table): table Primary method of creating a class. +---@field check_duplicate_register? fun(self: SMODS.Voucher|table): boolean? Ensures objects already registered will not register. +---@field check_duplicate_key? fun(self: SMODS.Voucher|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.Voucher|table) Registers the object. +---@field check_dependencies? fun(self: SMODS.Voucher|table): boolean? Returns `true` if there's no failed dependencies. +---@field process_loc_text? fun(self: SMODS.Voucher|table) Called during `inject_class`. Handles injecting loc_text. +---@field send_to_subclasses? fun(self: SMODS.Voucher|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.Voucher|table) Called before `inject_class`. Injects and manages class information before object injection. +---@field post_inject_class? fun(self: SMODS.Voucher|table) Called after `inject_class`. Injects and manages class information after object injection. +---@field inject_class? fun(self: SMODS.Voucher|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.Voucher|table, i?: number) Called during `inject_class`. Injects the object into the game. +---@field take_ownership? fun(self: SMODS.Voucher|table, key: string, obj: SMODS.Voucher|table, silent?: boolean): nil|table|SMODS.Voucher Takes control of vanilla objects. Child class must have get_obj for this to function +---@field get_obj? fun(self: SMODS.Voucher|table, key: string): SMODS.Voucher|table? Returns an object if one matches the `key`. +---@field redeem? fun(self: SMODS.Voucher|table, voucher?: Card|table) Defines behaviour when this voucher is redeemed. +---@field new? fun(self, name, slug, config, pos, loc_txt, cost, unlocked, discovered, available, requires, atlas): any DEPRECATED. DO NOT USE +---@overload fun(self: SMODS.Voucher): SMODS.Voucher +SMODS.Voucher = setmetatable({}, { + __call = function(self) + return self + end +}) \ No newline at end of file diff --git a/smods/lsp_def/core.lua b/smods/lsp_def/core.lua new file mode 100644 index 0000000..a4acf99 --- /dev/null +++ b/smods/lsp_def/core.lua @@ -0,0 +1,75 @@ +---@meta + +--- Core SMODS classes/functions + +SMODS = {} + +---@type string +--- Current SMODS version +MODDED_VERSION = "" + +---@type string +--- Path to SMODS directory +SMODS.path = "" + +---@class Mod +---@field id? string Unique ID. +---@field name? string Name of the mod. +---@field display_name? string Display name of the mod. +---@field description? string Mod description. +---@field priority? number Loaded mods are sorted via priority. +---@field badge_colour? table HEX color of the mod badge. +---@field badge_text_colour? table HEX color of the text inside the mod badge. +---@field prefix? string Unique string. All objects created by this mod have this string appended to their key. +---@field version? string Mod version. +---@field dump_loc? true Dumps G.localization table into this mod's directory. +---@field dependencies? string[] All mods in this array must be installed and loaded for this mod to load. +---@field conflicts? table[] No mods in this array can be installed for this mod to load. +---@field provides? table[] If any of the mods in this array are not installed or loaded, this mod will act as a stand in. +---@field main_file? string Path to the main .lua file of this mod. +---@field config_file? string Path to the config file of this mod. Defaults to "config.lua" if not provided. +---@field config? table Config values for this mod. +---@field can_load? boolean? +---@field config_tab? fun(): table Creates this mod's config tab UI. +---@field extra_tabs? fun(): table[] Creates additional tabs within this mod's menu. +---@field custom_collection_tabs? fun(): table[] Creates additional buttons displayed inside the "Other" tab in collections. +---@field description_loc_vars? fun(self: Mod|table): table Allows dynamic display of this mod's description. +---@field custom_ui? fun(mod_nodes: table) Allows manipulating this mod's description tab. +---@field set_ability_reset_keys? fun(): table When a card's `ability` table is changed, values with a key matching inside this table will not persist. +---@field reset_game_globals? fun(run_start: boolean) Allows resetting global values every new run or round. +---@field set_debuff? fun(card: Card|table): boolean|string? Allows controlling when a card is debuffed or not. Return `"prevent_debuff"` to force a card to be undebuffable. +---@field optional_features? SMODS.optional_features|(fun(): SMODS.optional_features) Table of optional SMODS features to enable inserted into `SMODS.optional_features`. If function, returns table. +---@field meta_mod? boolean Marked as a "meta mod" by SMODS. Only "Steamodded", "Lovely", and "Balatro" are provided by default. + +---@type table +SMODS.Mods = {} + +---@type Mod|table? +--- The current mod being loaded. +SMODS.current_mod = {} + +SMODS.Mods["Steamodded"] = SMODS +SMODS.Mods["Lovely"] = { + id = "Lovely", + can_load = true, + meta_mod = true +} +SMODS.Mods["Balatro"] = { + id = "Balatro", + can_load = true, + meta_mod = true +} + +---@param modsDirectory string +--- Loads mods. +function loadMods(modsDirectory) end + +--- Initializes Steamodded. +function initSteamodded() end + +--- Injects all classes and items. +function SMODS.injectItems() end + +---@param class SMODS.GameObject|table +--- Inject all SMODS Objects that are part of this class or a subclass. +function SMODS.injectObjects(class) end \ No newline at end of file diff --git a/smods/lsp_def/lib/json.lua b/smods/lsp_def/lib/json.lua new file mode 100644 index 0000000..dad9812 --- /dev/null +++ b/smods/lsp_def/lib/json.lua @@ -0,0 +1,19 @@ +---@meta json + +local json = {} + +---@type string +--- JSON.lua library version. +json._version = "0.1.2" + +---@param val table|string|number|boolean|nil Must be a valid value to encode +---@return string +--- Encodes provided `val`. +function json.encode(val) end + +---@param str string +---@return table +--- Decodes provided `str`. +function json.decode(str) end + +return json \ No newline at end of file diff --git a/smods/lsp_def/lib/lovely.lua b/smods/lsp_def/lib/lovely.lua new file mode 100644 index 0000000..d9ccddd --- /dev/null +++ b/smods/lsp_def/lib/lovely.lua @@ -0,0 +1,17 @@ +---@meta lovely + +local lovely = {} + +---@type string +--- Lovely version. +lovely.version = "" + +---@type string +--- Current mod directory. +lovely.mod_dir = "" + +---@type string +--- Link to the Lovely GitHub repository. +lovely.repo = "" + +return lovely \ No newline at end of file diff --git a/smods/lsp_def/lib/nativefs.lua b/smods/lsp_def/lib/nativefs.lua new file mode 100644 index 0000000..22c2651 --- /dev/null +++ b/smods/lsp_def/lib/nativefs.lua @@ -0,0 +1,94 @@ +---@meta nativefs + +--- NativeFS annotations +--- Partially based on (and depends on) love.filesystem annotations. + +local nativefs = {} + +---@class File: love.File + +---@param name string The name of the file. +---@return File file New File object. +function nativefs.newFile(name) end + +---@param filepath string Path to the file. +---@return string|love.FileData? data The file data. +---@return string? error +function nativefs.newFileData(filepath) end + +---@param archive string +---@param mountPoint string +---@param appendToPath? boolean +---@return boolean success +function nativefs.mount(archive, mountPoint, appendToPath) end + +---@param archive string +---@return boolean success +function nativefs.unmount(archive) end + +---@param containerOrName string +---@param nameOrSize? number|string +---@param sizeOrNil? number|nil +---@return string|love.FileData? +---@return number|string? size Returns as string if error +function nativefs.read(containerOrName, nameOrSize, sizeOrNil) end + +---@param name string +---@param data string +---@param size? number|"all" +---@return boolean +---@return string? error +function nativefs.write(name, data, size) end + +---@param name string +---@param data string +---@param size? number|"all" +---@return boolean +---@return string? error +function nativefs.append(name, data, size) end + +---@param name string +---@return function iterator # Iterates over each line +function nativefs.lines(name) end + +---@param name string +---@return function? chunk +---@return string? error +function nativefs.load(name) end + +---@return string cwd Current working directory +function nativefs.getWorkingDirectory() end + +---@param path string +---@return boolean +---@return string? error +function nativefs.setWorkingDirectory(path) end + +---@return string[] +function nativefs.getDriveList() end + +---@param path string +---@return boolean +---@return string? error +function nativefs.createDirectory(path) end + +---@param name string +---@return boolean +---@return string? error +function nativefs.remove(name) end + +---@param dir string +---@return string[] files +function nativefs.getDirectoryItems(dir) end + +---@param path string +---@param filtertype? love.FileType +---@return table|{type: love.FileType, size: number, modtime: number}[] info_array +function nativefs.getDirectoryItemsInfo(path, filtertype) end + +---@param path string +---@param filtertype? love.FileType +---@return table|{type: love.FileType, size: number, modtime: number} info +function nativefs.getInfo(path, filtertype) end + +return nativefs \ No newline at end of file diff --git a/smods/lsp_def/lib/smods-https.lua b/smods/lsp_def/lib/smods-https.lua new file mode 100644 index 0000000..22c5f92 --- /dev/null +++ b/smods/lsp_def/lib/smods-https.lua @@ -0,0 +1,33 @@ +---@meta SMODS.https + +local https = {} + +---@class Headers +---@field [string] string The headers. + +---@class HttpsOptions +---@field headers? Headers Additional headers to add to the request as key-value pairs. +---@field method? "GET"|"POST"|"HEAD"|"PUT"|"DELETE"|"PATCH" HTTP method. If absent, it's either "GET" or "POST" depending on the data field. +---@field data? string Additional data to send as application/x-www-form-urlencoded (unless specified otherwise in Content-Type header). + +---Make an http(s) request. Designed to work on more platforms out of the box, compared to Balatro's shipped https modules (which is only availible on Windows). +---The API is designed to mirror that of [lua-https](https://love2d.org/wiki/lua-https). +---@param url string The URL to request +---@param options? HttpsOptions Additional options for the request. +---@return number code HTTP status code, or 0 on failure. +---@return string|nil body The response body on success. Either nil or a description of the error on failure. +---@return Headers|nil headers HTTP response headers as key-value pairs, or nil on failure. +function https.request(url, options) end + +---@alias Callback fun(code: number, body: string|nil, headers: Headers|nil) + +---Make an async http(s) request. Designed to work on more platforms out of the box, compared to Balatro's shipped https modules (which is only availible on Windows). +---This API does not block with the request, and instead calls the passed callback when it's done. +---@param url string The URL to request +---@param optionsOrCallback HttpsOptions|Callback If callback is nil, this can be used as the callback. Otherwise used as options. +---@param callback? Callback The callback to call when the request is done. See https.request's return values for more info on passed arguments. +---@async +---@see https.request +function https.asyncRequest(url, optionsOrCallback, callback) end + +return https diff --git a/smods/lsp_def/ui.lua b/smods/lsp_def/ui.lua new file mode 100644 index 0000000..44c85f4 --- /dev/null +++ b/smods/lsp_def/ui.lua @@ -0,0 +1,252 @@ +---@meta + +SMODS.GUI = {} +SMODS.GUI.DynamicUIManager = {} + +---@type string|"achievements"|"config"|"credits"|"mod_desc"|"additions" +SMODS.LAST_SELECTED_MOD_TAB = "" + +---@type boolean? +SMODS.IN_MODS_TAB = nil + +---@enum G.UIT +G.UIT = { + T=1, -- Text node + B=2, -- Box node + C=3, -- Column node (orients children vertically) + R=4, -- Row node (orients children horizontally) + O=5, -- Object node + ROOT=7, -- Top-level node + S=8, -- Slider node + I=9, -- Input node + padding = 0, --default padding +} + +---@class UINode.config: table +---@field align? string String *MUST* be two or less letters, 1st indicating vertical alignment and 2nd horizontal. +---@field h? number Fixed height. +---@field minh? number Minimum height. +---@field maxh? number Maximum height. +---@field w? number Fixed width. +---@field minw? number Minimum width. +---@field maxw? number Maximum width. +---@field padding? number Extra padding in the edges of the node. +---@field r? number Roundness of the node's corners. +---@field colour? table HEX color fill of the node. +---@field no_fill? boolean Set the node to no fill. Also sets text color for text nodes. +---@field outline? number Thickness of the outline. +---@field outline_colour? table HEX color of the outline. +---@field emboss? number How raised the current node is from its parent node. +---@field hover? boolean Renders the node as hovering above the parent node. +---@field shadow? boolean Renders a shadow below the node. +---@field juice? boolean Applied the `juice_up` animation on the node when loaded. +---@field id? string Sets an ID for the node. +---@field instance_type? "NODE"|"MOVEABLE"|"UIBOX"|"CARDAREA"|"CARD"|"UI_BOX"|"ALERT"|"POPUP" Sets the layer this node is drawn on. +---@field ref_table? table Table containing data relevant to this node. +---@field ref_value? string String corresponding to a key inside of `ref_table`. +---@field func? string Key to the function called when this node is drawn. +---@field button? string Key to the function called when this node is clicked. +---@field tooltip? table|{title: string, text: string[]} Displays a tooltip when this node is hovered. +---@field detailed_tooltip? table Contains the center of an object, turned into a detailed tooltip displayed when this node is hovered. +---@field text? string String to displayed as text. +---@field scale? number Size multiplier for text. +---@field vert? boolean Sets if the text is drawn vertically. +---@field object? Node Object to render. +---@field role? "Major"|"Minor"|"Glued" Sets object's role type. + +--- Internal class for annotating UIBox/UIElement tables before being turned into objects. +---@class UINode: table +---@field n G.UIT Type of UIBox/UIElement +---@field config UINode.config Config of the UINode. +---@field nodes? UINode[] Child UINodes + +-- UI Functions +---@param str string +---@return any? +--- Unpacks provided string. +function STR_UNPACK(str) end + +---@param args table +---@return UINode +--- Creates UIBox for individual mod tabs. +function create_UIBox_mods(args) end + +---@param mod Mod +---@return UINode +--- Creates UIBox for Mod's Description tab. +function buildModDescTab(mod) end + +---@param mod Mod +---@return UINode +--- Creates UIBox for Mod's "Additions" tab. +function buildAdditionsTab(mod) end + +---@param e table? +--- Button function for "Other" collections menu +G.FUNCS.your_collection_other_gameobjects = function(e) end + +---@return UINode? +--- Creates UIBox for "Other" collections menu +function create_UIBox_Other_GameObjects() end + +---@param e table? +--- Button function for "Consumables" collections menu UIBox +G.FUNCS.your_collection_consumables = function(e) end + +---@return UINode +--- Creates UIBox for "Consumables" collections menu +function create_UIBox_your_collection_consumables() end + +---@param args table? +--- Pages button function for "Consumables" collection menu +G.FUNCS.your_collection_consumables_page = function(args) end + +---@param page? number +---@return UINode +--- Creates UIBox for "Consumables" collection menu pages. +G.UIDEF.consumable_collection_page = function(page) end + +---@param mod Mod +---@param current_page number? +---@return UINode +--- Creates UIBox for Mod's "Achievements" tab. +function buildAchievementsTab(mod, current_page) end + +---@param args table? +--- Pages button function for "Achievements" tab +G.FUNCS.achievments_tab_page = function(args) end + +---@param pool table[] +---@param set string? Only objects with matching set will be tallied. +---@return {tally: 0|number, of: 0|number} +--- Tallies all objects within `pool` that are discovered. +function modsCollectionTally(pool, set) end + +---@param mod Mod +---@return UINode +--- Creates Mod tag UI for Mods list menu. +function buildModtag(mod) end + +---@param options table? +--- Opens "Mods" directory. +function G.FUNCS.openModsDirectory(options) end + +---@param mod Mod +---@return table +--- Loads mod config. +function SMODS.load_mod_config(mod) end + +---@param mod Mod +---@return boolean +--- Saves mod config +function SMODS.save_mod_config(mod) end + +--- Saves all mod configs. +function SMODS.save_all_config() end + +---@param e table? +--- Exits mods tab. +function G.FUNCS.exit_mods(e) end + +---@return UINode +--- Creates UIBox for SMODS Menu. +function create_UIBox_mods_button() end + +---@param e table? +--- Updates achievements settings. +function G.FUNCS.update_achievement_settings(e) end + +---@param e table? +--- Button function for Steamodded Github link. +function G.FUNCS.steamodded_github(e) end + +---@param e table? +--- Updates UI to display SMODS menu. +function G.FUNCS.mods_button(e) end + +---@param args table +--- Updates mod list. +function G.FUNCS.update_mod_list(args) end + +---@param args table +---@return UINode +--- Same as Balatro base game code, but accepts a value to match against (rather than the index in the option list) +--- e.g. create_option_cycle({ current_option = 1 }) vs. SMODS.GUI.createOptionSelector({ current_option = "Page 1/2" }) +function SMODS.GUI.createOptionSelector(args) end + +---@param args table +---@return UINode +-- Initialize a tab with sections that can be updated dynamically (e.g. modifying text labels, showing additional UI elements after toggling buttons, etc.) +function SMODS.GUI.DynamicUIManager.initTab(args) end + +---@param uiDefinitions table +--- Updates all provided dynamic UIBoxes. +function SMODS.GUI.DynamicUIManager.updateDynamicAreas(uiDefinitions) end + +---@return UINode +--- Define the content in the pane that does not need to update +--- Should include OBJECT nodes that indicate where the dynamic content sections will be populated +--- EX: in this pane the 'modsList' node will contain the dynamic content which is defined in the function below +function SMODS.GUI.staticModListContent() end + +---@param page number? +---@return UINode +--- Creates mod list. +function SMODS.GUI.dynamicModListContent(page) end + +---@param args table +--- Updates mipmap. +function G.FUNCS.SMODS_change_mipmap(args) end + +---@class CardCollection +---@field w_mod? number CardArea width modifier. +---@field h_mod? number CardArea height modifier. +---@field card_scale? number Card scale modifier. +---@field collapse_single_page? boolean Removes a row if there's only one page. +---@field area_type? string CardArea type. +---@field center? string Key to a center. All created cards will have this as their center. +---@field no_materialize? boolean Sets if the card play materialize animations when created. +---@field back_func? string Back function of the collections UI. +---@field hide_single_page? boolean Hides the page portion of the UI if there's only one page. +---@field infotip? string Text displayed above the collections menu (e.x. Edition/Seal/Enhancement). +---@field snap_back? boolean Some controller related. TODO define more specific term +---@field modify_card? fun(card: Card|table, center: SMODS.GameObject|table, i: number, j: number) Modifies all created cards for this collection. + +---@param _pool table +---@param rows number[] +---@param args CardCollection +---@return UINode +--- Creates a default collections UIBox +function SMODS.card_collection_UIBox(_pool, rows, args) end + +---@return UINode +--- Creates UIBox for "Jokers" collection menu +function create_UIBox_your_collection_jokers() end + +---@return UINode +--- Creates UIBox for "Boosters" collection menu +function create_UIBox_your_collection_boosters() end + +---@return UINode +--- Creates UIBox for "Vouchers" collection menu +function create_UIBox_your_collection_vouchers() end + +---@return UINode +--- Creates UIBox for "Enhancements" collection menu +function create_UIBox_your_collection_enhancements() end + +---@return UINode +--- Creates UIBox for "Editions" collection menu +function create_UIBox_your_collection_editions() end + +---@return UINode +--- Creates UIBox for "Seals" collection menu +function create_UIBox_your_collection_seals() end + +---@param e table? +--- Button function for "Stickers" collection menu +G.FUNCS.your_collection_stickers = function(e) end + +---@return UINode +--- Creates UIBox for "Stickers" collection menu +function create_UIBox_your_collection_stickers() end diff --git a/smods/lsp_def/utils.lua b/smods/lsp_def/utils.lua new file mode 100644 index 0000000..5cdb238 --- /dev/null +++ b/smods/lsp_def/utils.lua @@ -0,0 +1,469 @@ +---@meta + +--- Util Classes + +--- Internal class referring args passed as `context` in a SMODS object's `calculate` function. +--- Not all arguments typed here are present in all contexts, see [Calculate Function](https://github.com/Steamodded/smods/wiki/calculate_functions#contexts) for details. +---@class CalcContext: table +---@field cardarea? CardArea|"unscored" The CardArea currently being checked. +---@field full_hand? Card[]|table[] All played or selected cards. +---@field scoring_hand? Card[]|table[] All scoring cards in played hand. +---@field scoring_name? string Key to the scoring poker hand. +---@field poker_hands? table All poker hand parts the played hand can form. +---@field other_card? Card|table The individual card being checked during scoring. +---@field other_joker? Card|table The individual Joker being checked during scoring. +---@field card_effects? table Table of effects that have been calculated. +---@field destroy_card? Card|table The individual card being checked for destruction. +---@field destroying_card? Card|table The individual card being checked for destruction. Only present when calculating G.play. +---@field removed? Card[]|table[] Table of destroyed playing cards. +---@field game_over? boolean Whether the run is lost or not. +---@field blind? Blind|table Current blind being selected. +---@field hook? boolean `true` when "The Hook" discards cards. +---@field card? Card|table The individual card being checked outside of scoring. +---@field cards? table[]|Card[] Table of cards representing how many cards were created. +---@field consumeable? Card|table The Consumable being used. Only a value when `context.using_consumeable` is `true`. +---@field blueprint_card? Card|table The card currently copying the eval effects. +---@field no_blueprint? true Effects akin to Blueprint or Brainstorm should not trigger in this context. +---@field other_context? CalcContext|table The context the last eval happened on. +---@field other_ret? table The return table from the last eval. +---@field before? true Check if `true` for effects that happen before hand scoring. +---@field after? true Check if `true` for effects that happen after hand scoring. +---@field main_scoring? true Check if `true` for effects that happen during scoring. +---@field individual? true Check if `true` for effects on individual playing cards during scoring. +---@field repetition? true Check if `true` for adding repetitions to playing cards. +---@field edition? true `true` for any Edition-specific context (e.x. context.pre_joker and context.post_joker). +---@field pre_joker? true Check if `true` for triggering editions on jokers before they score. +---@field post_joker? true Check if `true` for triggering editions on jokers after they score. +---@field joker_main? true Check if `true` for triggering normal scoring effects on Jokers. +---@field final_scoring_step? true Check if `true` for effects after cards are scored and before the score is totalled. +---@field remove_playing_cards? true Check if `true` for effects on removed cards. +---@field debuffed_hand? true Check if `true` for effects when playing a hand debuffed by a blind. +---@field end_of_round? true Check if `true` for effects at the end of the round. +---@field setting_blind? true Check if `true` for effects when the blind is selected. +---@field pre_discard? true Check if `true` for effects before cards are discarded. +---@field discard? true Check if `true` for effects on each individual card discarded. +---@field open_booster? true Check if `true` for effects when opening a Booster Pack. +---@field skipping_booster? true Check if `true` for effects after a Booster Pack is skipped. +---@field buying_card? true Check if `true` for effects after buying a card. +---@field selling_card? true Check if `true` for effects after selling a card. +---@field reroll_shop? true Check if `true` for effects after rerolling the shop. +---@field ending_shop? true Check if `true` for effects after leaving the shop. +---@field first_hand_drawn? true Check if `true` for effects after drawing the first hand. +---@field hand_drawn? true Check if `true` for effects after drawing a hand. +---@field using_consumeable? true Check if `true` for effects after using a Consumable. +---@field skip_blind? true Check if `true` for effects after skipping a blind. +---@field playing_card_added? true Check if `true` for effects after a playing card was added into the deck. +---@field check_enhancement? true Check if `true` for applying quantum enhancements. +---@field post_trigger? true Check if `true` for effects after another Joker is triggered. +---@field modify_scoring_hand? true Check if `true` for modifying the scoring hand. +---@field ending_booster? true Check if `true` for effects after a Booster Pack ends. +---@field starting_shop? true Check if `true` for effects when the shop is first opened. + +--- Util Functions + +---@param ... table +---@return table +---Flattens given arrays into one, then adds elements from each table to a new one. Skips duplicates. +function SMODS.merge_lists(...) end + +--- A table of SMODS feature that mods can choose to enable. +---@class SMODS.optional_features: table +---@field quantum_enhancements? boolean Enables "Quantum Enhancement" contexts. Cards can count as having multiple enhancements at once. +---@field retrigger_joker? boolean Enables "Joker Retrigger" contexts. Jokers can be retriggered by other jokers or effects. +---@field post_trigger? boolean Enables "Post Trigger" contexts. Allows calculating effects after a Joker has been calculated. +---@field cardarea? table Enables additional CardArea calculation. Currently supports: `deck`, `discards`, `unscored`. + +---@type SMODS.optional_features +SMODS.optional_features = { cardarea = {} } + +--- Inserts all SMODS features enabled by loaded mods into `SMODS.optional_features`. +function SMODS.get_optional_features() end + +---@param context CalcContext|table +---@param return_table? table +--- Used to calculate contexts across `G.jokers`, `scoring_hand` (if present), `G.play` and `G.GAME.selected_back`. +--- Hook this function to add different areas to MOST calculations +function SMODS.calculate_context(context, return_table) end + +---@param card Card|table +---@param context CalcContext|table +--- Scores the provided `card`. +function SMODS.score_card(card, context) end + +---@param context CalcContext|table +---@param scoring_hand Card[]|table[]? +--- Handles calculating the scoring hand. Defaults to `context.cardarea.cards` if `scoring_hand` is not provided. +function SMODS.calculate_main_scoring(context, scoring_hand) end + +---@param context CalcContext|table +--- Handles calculating end of round effects. +function SMODS.calculate_end_of_round_effects(context) end + +---@param context CalcContext|table +---@param cards_destroyed Card[]|table[] +---@param scoring_hand Card[]|table[] +--- Handles calculating destroyed cards. +function SMODS.calculate_destroying_cards(context, cards_destroyed, scoring_hand) end + +---@param effect table +---@param scored_card Card|table +---@param key string +---@param amount number|boolean +---@param from_edition? boolean +---@return boolean|table? +--- This function handles the calculation of each effect returned to evaluate play. +--- Can easily be hooked to add more calculation effects ala Talisman +function SMODS.calculate_individual_effect(effect, scored_card, key, amount, from_edition) end + +---@param effect table +---@param scored_card Card|table +---@param from_edition? boolean +---@return table +--- Handles calculating effects on provided `scored_card`. +function SMODS.calculate_effect(effect, scored_card, from_edition, pre_jokers) end + +---@param effects table +---@param card Card|table +--- Used to calculate a table of effects generated in evaluate_play +function SMODS.trigger_effects(effects, card) end + +---@param card Card|table +---@param context CalcContext|table +---@param _ret table +---@return number[] +--- Calculate retriggers on provided `card`. +function SMODS.calculate_retriggers(card, context, _ret) end + +---@param card Card|table +---@param context CalcContext|table +---@param reps table[] +---@return table[] reps +function SMODS.calculate_repetitions(card, context, reps) end + +---@param card Card|table +---@param blueprint_card Card|table +---@param context CalcContext|table +---@return table? +--- Calculates blueprint-like effects. +function SMODS.blueprint_effect(card, blueprint_card, context) end + +---@param _type string +---@param _context string +---@return CardArea[]|table[] +--- Returns table of CardAreas. +function SMODS.get_card_areas(_type, _context) end + +---@param card Card|table +---@param extra_only boolean? Return table will not have the card's actual enhancement. +---@return table enhancements +--- Returns table of enhancements the provided `card` has. +function SMODS.get_enhancements(card, extra_only) end + +---@param card Card|table +---@param key string +---@return boolean +--- Checks if this card a specific enhancement. +function SMODS.has_enhancement(card, key) end + +---@param card Card|table +---@param effects table +---@param context CalcContext|table +--- Calculates quantum Enhancements. Require `SMODS.optional_features.quantum_enhancements` to be `true`. +function SMODS.calculate_quantum_enhancements(card, effects, context) end + +---@param card Card|table +---@return boolean? +--- Check if the card shoud shatter. +function SMODS.shatters(card) end + +---@param card Card|table +---@return boolean? +--- Checks if the card counts as having no suit. +function SMODS.has_no_suit(card) end + +---@param card Card|table +---@return boolean? +--- Checks if the card counts as having all suits. +function SMODS.has_any_suit(card) end + +---@param card Card|table +---@return boolean? +--- Checks if the card counts as having no rank. +function SMODS.has_no_rank(card) end + +---@param card Card|table +---@return boolean? +--- Checks if the card should score. +function SMODS.always_scores(card) end + +---@param card Card|table +--- Checks if the card should not score. +function SMODS.never_scores(card) end + +---@param card Card|table +---@param scoring_hand Card[]|table[] +---@return true? +--- Returns `true` if provided card is inside the scoring hand. +function SMODS.in_scoring(card, scoring_hand) end + +---@nodiscard +---@param path string Path to the file (excluding `mod.path`) +---@param id string? Key to Mod ID. Default to `SMODS.current_mod` if not provided. +---@return function|nil +---@return nil|string err +--- Loads the file from provided path. +function SMODS.load_file(path, id) end + +---@param table table +---@return string +--- Shallow inspect a table. +function inspect(table) end + +---@param table table +---@param indent number? +---@param depth number? Cap depth of 5 +---@return string +--- Deep inspect a table. +function inspectDepth(table, indent, depth) end + +---@param func function +---@return string +--- Inspect a function. +function inspectFunction(func) end + +--- Handles saving discovery and unlocks. +function SMODS.SAVE_UNLOCKS() end + +---@param ref_table table +---@param ref_value string +---@param loc_txt table|string +---@param key string? Key to the value within `loc_txt`. +--- Injects `loc_txt` into `G.localization`. +function SMODS.process_loc_text(ref_table, ref_value, loc_txt, key) end + +---@param path string +--- Handles injecting localization files. +function SMODS.handle_loc_file(path) end + +---@param pool table[] +---@param center metatable +---@param replace boolean? +--- Injects an object into provided pool. +function SMODS.insert_pool(pool, center, replace) end + +---@param pool table +---@param key string +--- Removes an object from the provided pool. +function SMODS.remove_pool(pool, key) end + +--- Juices up blind. +function SMODS.juice_up_blind() end + +--- Change a card's suit, rank, or both. +--- Accepts keys for both objects instead of needing to build a card key yourself. +--- It is recommended to wrap this function in `assert` to prevent unnoticed errors. +---@nodiscard +---@param card Card|table +---@param suit? string Key to the suit. +---@param rank? string Key to the rank. +---@return Card|table? cardOrErr If successful the card. If it failed `nil`. +---@return string? msg If it failed, a message describing what went wrong. +function SMODS.change_base(card, suit, rank) end + +---@param key string +---@param count_debuffed true? +---@return Card[]|table[] +--- Returns all cards matching provided `key`. +function SMODS.find_card(key, count_debuffed) end + +---@class CreateCard +---@field set? string Set of the card. +---@field area? CardArea|table CardArea to emplace this card to. +---@field legendary? boolean Pools legendary cards, if applicable. +---@field rarity? number|string Only spawns cards with provided rarity, if applicable. +---@field skip_materialize? boolean Skips materialization animations. +---@field soulable? boolean Card could be replace by a legendary version, if applicable. +---@field key? string Created card is forced to have a center matching this key. +---@field key_append? string Appends this string to seeds. +---@field no_edition? boolean Ignore natural edition application. +---@field edition? string Apply this edition. +---@field enhancement? string Apply this enhancement. +---@field seal? string Apply this seal. +---@field stickers? string[] Apply all stickers in this array. + +---@param t CreateCard|table +---@return Card|table +--- Creates a card. +function SMODS.create_card(t) end + +---@param t CreateCard|table +---@return Card|table +--- Adds + creates a card into provided `area`. +function SMODS.add_card(t) end + +---@param card Card|table +---@param debuff boolean|"reset"? +---@param source string? +--- Debuffs provided `card`. +function SMODS.debuff_card(card, debuff, source) end + +---@param card Card|table +--- Recalculate card debuffs. +function SMODS.recalc_debuff(card) end + +--- Restarts the game. +function SMODS.restart_game() end + +---@param obj SMODS.GameObject|table +---@param badges table[] +--- Adds the mod badge into the `badges` of the provided `obj` description UIBox. +function SMODS.create_mod_badges(obj, badges) end + +--- Creates a localization dump. +function SMODS.create_loc_dump() end + +---@param t table +---@param indent string? +---@return string +--- Serializes an input table in valid Lua syntax +--- Keys must be of type number or string +--- Values must be of type number, boolean, string or table +function serialize(t, indent) end + +---@param s string +---@return string +--- Serializes provided string. +function serialize_strings(s) end + +---@param t false|table? +---@param defaults false|table? +---@return false|table? +--- Starting with `t`, insert any key-value pairs from `defaults` that don't already +--- exist in `t` into `t`. Modifies `t`. +--- Returns `t`, the result of the merge. +--- +--- `nil` inputs count as {}; `false` inputs count as a table where +--- every possible key maps to `false`. Therefore, +--- * `t == nil` is weak and falls back to `defaults` +--- * `t == false` explicitly ignores `defaults` +--- (This function might not return a table, due to the above) +function SMODS.merge_defaults(t, defaults) end + +---@param num number +---@param precision number +---@return number +--- Rounds provided `num`. +function round_number(num, precision) end + +---@param value number|string +---@return string +--- Format provided `value` +function format_ui_value(value) end + +---@param ante number +---@return number +--- Returns the blind amount. +function SMODS.get_blind_amount(ante) end + +--- Converts save data for vanilla objects. +function convert_save_data() end + +---@param id string +---@return Mod[]|table[] +--- Returns table representing mods either matching provided `id` or can provide that mod. +function SMODS.find_mod(id) end + +---@param tbl table +---@param val any +---@param mode ("index"|"i")|("value"|"v")? Sets if the value is compared with the indexes or values of the table. +---@param immediate boolean? +---Seatch for val anywhere deep in tbl. Return a table of finds, or the first found if args.immediate is provided. +function SMODS.deepfind(tbl, val, mode, immediate) end + +--- Enables debugging Joker calculations. +function SMODS.debug_calculation() end + +---@param card Card|table +---@param pack SMODS.Booster|table +---@return boolean +--- Controls if the card should be selectable from a Booster Pack. +function Card.selectable_from_pack(card, pack) end + +---@param pool (string|"UNAVAILABLE")[] +---@return number +--- Returns size of the provided pool (excluding `"UNAVAILABLE"`). +function SMODS.size_of_pool(pool) end + +---@param vouchers {[number]: table, spawn: table}? +---@return {[number]: table, spawn: table} vouchers +--- Returns next vouchers to spawn. +function SMODS.get_next_vouchers(vouchers) end + +---@param key string +---@return Card|table voucher +--- Adds a Voucher with matching `key` to the shop. +function SMODS.add_voucher_to_shop(key) end + +---@param mod number +--- Modifies the Voucher shop limit by `mod`. +function SMODS.change_voucher_limit(mod) end + +---@param key string +---@return Card|table booster +--- Adds a Booster Pack with matching `key` to the shop. +function SMODS.add_booster_to_shop(key) end + +---@param mod number +--- Modifies the Booster Pack shop limit by `mod`. +function SMODS.change_booster_limit(mod) end + +---@param mod number +--- Modifies the current amount of free shop rerolls by `mod`. +function SMODS.change_free_rerolls(mod) end + +---@param message string +---@param logger? string +--- Prints to the console at "DEBUG" level +function sendDebugMessage(message, logger) end + +---@param message string +---@param logger? string +--- Prints to the console at "INFO" level +function sendInfoMessage(message, logger) end + +---@param message string +---@param logger? string +--- Prints to the console at "WARN" level +function sendWarnMessage(message, logger) end + +---@param message string +---@param logger? string +--- Prints to the console at "ERROR" level +function sendErrorMessage(message, logger) end + +---@param message string +---@param logger? string +--- Prints to the console at "FATAL" level +function sendFatalMessage(message, logger) end + +---@param level string +---@param logger string +---@param message string +--- Sends the provided `message` to debug console. +function sendMessageToConsole(level, logger, message) end + +---@param val number +---@return string +--- Returns a signed `val`. +function SMODS.signed(val) end + +---@param val number +---@return string +--- Returns a signed `val` with "$". +function SMODS.signed_dollars(val) end + +---@param base number +---@param perma number +---@return number|0 # Returns 0 +--- Returns result of multiplying `base` and `perma`. +function SMODS.multiplicative_stacking(base, perma) end diff --git a/smods/lsp_def/vanilla.lua b/smods/lsp_def/vanilla.lua new file mode 100644 index 0000000..140d279 --- /dev/null +++ b/smods/lsp_def/vanilla.lua @@ -0,0 +1,230 @@ +---@meta + +--- Vanilla classes & functions. + +-- Balatro vanilla classes declared here, allows typing SMODS functions. +---@class Object: metatable +---@overload fun(...: any): Object|table +Object = {} +function Object:__call(...) return self end + +---@class Node: Object +---@overload fun(...: any): Node|table +Node = {} +function Node:__call(...) return self end + +---@class Event: Object +---@overload fun(...: any): Event|table +Event = {} +function Event:__call(...) return self end + +---@class EventManager: Object +---@overload fun(...: any): EventManager|table +EventManager = {} +function EventManager:__call(...) return self end + +---@class Back: Object +---@overload fun(...: any): Back|table +Back = {} +function Back:__call(...) return self end + +---@class Tag: Object +---@overload fun(...: any): Tag|table +Tag = {} +function Tag:__call(...) return self end + +---@param self Tag|table +---@param tag_sprite Sprite|table +---@param vars_only boolean +---@return Sprite|table? tag_sprite Returns `loc_vars` if `vars_only` is `true`. +--- Sets the Tag's description UIBox. +function Tag:get_uibox_table(tag_sprite, vars_only) end + +---@class Game: Object +---@overload fun(...: any): Game|table +Game = {} +function Game:__call(...) return self end + +---@class Moveable: Node +---@overload fun(...: any): Moveable|table +Moveable = {} +function Moveable:__call(...) return self end + +---@class UIBox: Moveable +---@overload fun(...: any): UIBox|table +UIBox = {} +function UIBox:__call(...) return self end + +---@class UIElement: Moveable +---@overload fun(...: any): UIElement|table +UIElement = {} +function UIElement:__call(...) return self end + +---@class DynaText: Moveable +---@overload fun(...: any): DynaText|table +DynaText = {} +function DynaText:__call(...) return self end + +---@class Particles: Moveable +---@overload fun(...: any): Particles|table +Particles = {} +function Particles:__call(...) return self end + +---@class Sprite: Moveable +---@overload fun(...: any): Sprite|table +Sprite = {} +function Sprite:__call(...) return self end + +---@class AnimatedSprite: Sprite +---@overload fun(...: any): AnimatedSprite|table +AnimatedSprite = {} +function AnimatedSprite:__call(...) return self end + +---@class Blind: Moveable +---@overload fun(...: any): Blind|table +Blind = {} +function Blind:__call(...) return self end +---@type Blind|table|nil +G.GAME.blind = Blind() + +---@class Card: Moveable +---@field ability? table +---@field ignore_base_shader? table +---@field ignore_shadow? table +---@overload fun(...: any): Card|table +Card = {} +function Card:__call(...) return self end + +---@param vars_only? boolean Only return description values +---@return table # Becomes `loc_vars` if `vars_only` is `true`. +---@return table? man_start Only returns if `vars_only` is `true`. +---@return table? main_end Only returns if `vars_only` is `true`. +--- Handles variables before passing into `generate_card_ui()`. +function Card:generate_UIBox_ability_table(vars_only) end + +---@param self Card +---@return number +--- Returns card Mult. +function Card:get_chip_mult() end + +---@param self Card +---@return number +--- Returns card XMult. +function Card:get_chip_x_mult() end + +---@param self Card +---@return number +--- Returns card hand Mult. +function Card:get_chip_h_mult() end + +---@param self Card +---@return number +--- Returns card hand XMult. +function Card:get_chip_h_x_mult() end + +---@param self Card +---@return number +--- Returns card XChips. +function Card:get_chip_x_bonus() end + +---@param self Card +---@return number +--- Returns card hand Chips. +function Card:get_chip_h_bonus() end + +---@param self Card +---@return number +--- Returns card hand XChips. +function Card:get_chip_h_x_bonus() end + +---@param self Card +---@return number +--- Returns card dollars. +function Card:get_p_dollars() end + +---@param self Card +---@return number +--- Returns card hand dollars. +function Card:get_h_dollars() end + +---@class Card_Character: Moveable +---@overload fun(...: any): Card_Character|table +Card_Character = {} +function Card_Character:__call(...) return self end + +---@class CardArea: Moveable +---@overload fun(...: any): CardArea|table +CardArea = {} +function CardArea:__call(...) return self end + +--- Vanilla functions + +---@param hex string +---@return table +---Returns HEX color attributed to the string. +function HEX(hex) end + +---@param _c? table Object center. +---@param full_UI_table? table UI Table. +---@param specific_vars? table +---@param card_type? string +---@param badges? table Table of badges added below the card desc. +---@param hide_desc? boolean Undiscovered description instead of normal. +---@param main_start? table Added text above the card's normal description. +---@param main_end? table Added text below the card's normal description. +---@param card? table Card or Card-like object. +---@return table full_UI_table +--- Generates description UI for Cards and Card-like objects. +function generate_card_ui(_c, full_UI_table, specific_vars, card_type, badges, hide_desc, main_start, main_end, card) end + +---@param card Card|table +---@param context CalcContext|table +---@return table effect +---@return table post_trig +--- Evaluates provided `card` for scoring. +function eval_card(card, context) end + +---@param num number +---@param hand Card[]|table[] +---@param or_more? boolean +---@return table|(Card[]|table[]) +--- Returns table containing all cards sharing the same rank equal to provided `num` (or higher). +function get_X_same(num, hand, or_more) end + +---@param num number +---@param e_switch_point? number +---@return string +--- Formats provided number and converts it to string. +function number_format(num, e_switch_point) end + +---@param number? number Returns `scale` if not provided. +---@param scale number +---@param max? number +---@param e_switch_point? number +---@return number +--- Scales provided `number` by `scale`. +function scale_number(number, scale, max, e_switch_point) end + +---@param hand Card[]|table[] +---@param min_length? number Minimum length of the straight. +---@param skip? boolean Sets if the straight can skip ranks. +---@param wrap? boolean Allows straight to wrap. +---@return table|(Card[]|table[]) +--- Returns table of cards forming a straight. +function get_straight(hand, min_length, skip, wrap) end + +---@param pos table|{x: number, y: number} +---@param value string|{string: string, colour: table}[] +---@param tooltip string[] +---@param suit string +---@return table +--- Creates tally sprite UI. +function tally_sprite(pos, value, tooltip, suit) end + +---@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`. +function pseudorandom_element(_t, seed, args) end \ No newline at end of file diff --git a/smods/manifest.json b/smods/manifest.json new file mode 100644 index 0000000..80f570e --- /dev/null +++ b/smods/manifest.json @@ -0,0 +1,9 @@ +{ + "name": "Steamodded", + "version_number": "1.0.0", + "website_url": "https://github.com/Steamodded/smods", + "description": "A Balatro Modding Framework", + "dependencies": [ + "Thunderstore-lovely-0.7.1" + ] +} diff --git a/smods/src/card_draw.lua b/smods/src/card_draw.lua new file mode 100644 index 0000000..3223746 --- /dev/null +++ b/smods/src/card_draw.lua @@ -0,0 +1,463 @@ +SMODS.DrawSteps = {} +SMODS.DrawStep = SMODS.GameObject:extend { + obj_table = SMODS.DrawSteps, + obj_buffer = {}, + required_params = { + 'key', + 'order', + 'func', + }, + layers = { + card = true, + both = true, + }, + -- func = function(card, layer) end, + set = "Draw Step", + register = function(self) + if self.registered then + sendWarnMessage(('Detected duplicate register call on object %s'):format(self.key), self.set) + return + end + SMODS.DrawStep.super.register(self) + end, + inject = function() end, + post_inject_class = function(self) + table.sort(self.obj_buffer, function(_self, _other) return self.obj_table[_self].order < self.obj_table[_other].order end) + end, + conditions = {}, + check_individual_condition = function(self, card, layer, k, v) + if k == 'vortex' then return not not card.vortex == v end + if k == 'facing' then return card.sprite_facing == v end + return true + end, + check_conditions = function(self, card, layer) + if not self.layers[layer] then return end + for k,v in pairs(self.conditions) do + if not self:check_individual_condition(card, layer, k, v) then return end + end + return true + end +} + +SMODS.DrawStep { + key = 'shadow', + order = -1000, + layers = { shadow = true, both = true }, + func = function(self) + self.ARGS.send_to_shader = self.ARGS.send_to_shader or {} + self.ARGS.send_to_shader[1] = math.min(self.VT.r*3, 1) + math.sin(G.TIMERS.REAL/28) + 1 + (self.juice and self.juice.r*20 or 0) + self.tilt_var.amt + self.ARGS.send_to_shader[2] = G.TIMERS.REAL + + for k, v in pairs(self.children) do + v.VT.scale = self.VT.scale + end + + G.shared_shadow = self.sprite_facing == 'front' and self.children.center or self.children.back + + --Draw the shadow + if not self.no_shadow and G.SETTINGS.GRAPHICS.shadows == 'On' and((self.ability.effect ~= 'Glass Card' and not self.greyed and self:should_draw_shadow() ) and ((self.area and self.area ~= G.discard and self.area.config.type ~= 'deck') or not self.area or self.states.drag.is)) then + self.shadow_height = 0*(0.08 + 0.4*math.sqrt(self.velocity.x^2)) + ((((self.highlighted and self.area == G.play) or self.states.drag.is) and 0.35) or (self.area and self.area.config.type == 'title_2') and 0.04 or 0.1) + G.shared_shadow:draw_shader('dissolve', self.shadow_height) + end + end, +} + +SMODS.DrawStep { + key = 'focused_ui_1', + order = -100, + func = function(self) + if self.area ~= G.hand then + if self.children.focused_ui then self.children.focused_ui:draw() end + end + end, +} + +SMODS.DrawStep { + key = 'tilt', + order = -50, + func = function(self) + -- for all hover/tilting: + self.tilt_var = self.tilt_var or {mx = 0, my = 0, dx = self.tilt_var.dx or 0, dy = self.tilt_var.dy or 0, amt = 0} + local tilt_factor = 0.3 + if self.states.focus.is then + self.tilt_var.mx, self.tilt_var.my = G.CONTROLLER.cursor_position.x + self.tilt_var.dx*self.T.w*G.TILESCALE*G.TILESIZE, G.CONTROLLER.cursor_position.y + self.tilt_var.dy*self.T.h*G.TILESCALE*G.TILESIZE + self.tilt_var.amt = math.abs(self.hover_offset.y + self.hover_offset.x - 1 + self.tilt_var.dx + self.tilt_var.dy - 1)*tilt_factor + elseif self.states.hover.is then + self.tilt_var.mx, self.tilt_var.my = G.CONTROLLER.cursor_position.x, G.CONTROLLER.cursor_position.y + self.tilt_var.amt = math.abs(self.hover_offset.y + self.hover_offset.x - 1)*tilt_factor + elseif self.ambient_tilt then + local tilt_angle = G.TIMERS.REAL*(1.56 + (self.ID/1.14212)%1) + self.ID/1.35122 + self.tilt_var.mx = ((0.5 + 0.5*self.ambient_tilt*math.cos(tilt_angle))*self.VT.w+self.VT.x+G.ROOM.T.x)*G.TILESIZE*G.TILESCALE + self.tilt_var.my = ((0.5 + 0.5*self.ambient_tilt*math.sin(tilt_angle))*self.VT.h+self.VT.y+G.ROOM.T.y)*G.TILESIZE*G.TILESCALE + self.tilt_var.amt = self.ambient_tilt*(0.5+math.cos(tilt_angle))*tilt_factor + end + end, +} + +SMODS.DrawStep { + key = 'particles', + order = -40, + func = function(self) + --Any particles + if self.children.particles then self.children.particles:draw() end + end, +} + +SMODS.DrawStep { + key = 'tags_buttons', + order = -30, + func = function(self) + --Draw any tags/buttons + if self.children.price then self.children.price:draw() end + if self.children.buy_button then + if self.highlighted then + self.children.buy_button.states.visible = true + self.children.buy_button:draw() + if self.children.buy_and_use_button then + self.children.buy_and_use_button:draw() + end + else + self.children.buy_button.states.visible = false + end + end + if self.children.use_button and self.highlighted then self.children.use_button:draw() end + end, +} + +SMODS.DrawStep { + key = 'vortex', + order = -20, + func = function(self) + if self.facing == 'back' then + self.children.back:draw_shader('vortex') + else + self.children.center:draw_shader('vortex') + if self.children.front then + self.children.front:draw_shader('vortex') + end + end + + love.graphics.setShader() + end, + conditions = { vortex = true }, +} + +SMODS.DrawStep { + key = 'center', + order = -10, + func = function(self, layer) + --Draw the main part of the card + if (self.edition and self.edition.negative) or (self.ability.name == 'Antimatter' and (self.config.center.discovered or self.bypass_discovery_center)) then + self.children.center:draw_shader('negative', nil, self.ARGS.send_to_shader) + elseif not self:should_draw_base_shader() then + -- Don't render base dissolve shader. + elseif not self.greyed then + self.children.center:draw_shader('dissolve') + end + + --If the card is not yet discovered + if not self.config.center.discovered and (self.ability.consumeable or self.config.center.unlocked) and not self.config.center.demo and not self.bypass_discovery_center then + local shared_sprite = (self.ability.set == 'Edition' or self.ability.set == 'Joker') and G.shared_undiscovered_joker or G.shared_undiscovered_tarot + local scale_mod = -0.05 + 0.05*math.sin(1.8*G.TIMERS.REAL) + local rotate_mod = 0.03*math.sin(1.219*G.TIMERS.REAL) + + shared_sprite.role.draw_major = self + if (self.config.center.undiscovered and not self.config.center.undiscovered.no_overlay) or not( SMODS.UndiscoveredSprites[self.ability.set] and SMODS.UndiscoveredSprites[self.ability.set].no_overlay) then + shared_sprite:draw_shader('dissolve', nil, nil, nil, self.children.center, scale_mod, rotate_mod) + else + if SMODS.UndiscoveredSprites[self.ability.set] and SMODS.UndiscoveredSprites[self.ability.set].overlay_sprite then + SMODS.UndiscoveredSprites[self.ability.set].overlay_sprite:draw_shader('dissolve', nil, nil, nil, self.children.center, scale_mod, rotate_mod) + end + end + end + + if self.ability.name == 'Invisible Joker' and (self.config.center.discovered or self.bypass_discovery_center) then + if self:should_draw_base_shader() then + self.children.center:draw_shader('voucher', nil, self.ARGS.send_to_shader) + end + end + + local center = self.config.center + if center.draw and type(center.draw) == 'function' then + center:draw(self, layer) + end + end, + conditions = { vortex = false, facing = 'front' }, +} + +SMODS.DrawStep { + key = 'front', + order = 0, + func = function(self, layer) + --Draw the main part of the card + if (self.edition and self.edition.negative) or (self.ability.name == 'Antimatter' and (self.config.center.discovered or self.bypass_discovery_center)) then + if self.children.front and (self.ability.delayed or (self.ability.effect ~= 'Stone Card' and not self.config.center.replace_base_card)) then + self.children.front:draw_shader('negative', nil, self.ARGS.send_to_shader) + end + elseif not self:should_draw_base_shader() then + -- Don't render base dissolve shader. + elseif not self.greyed then + if self.children.front and (self.ability.delayed or (self.ability.effect ~= 'Stone Card' and not self.config.center.replace_base_card)) then + self.children.front:draw_shader('dissolve') + end + end + + local center = self.config.center + if center.set == 'Default' or center.set == 'Enhanced' and not center.replace_base_card then + if not center.no_suit then + local suit = SMODS.Suits[self.base.suit] or {} + if suit.draw and type(suit.draw) == 'function' then + suit:draw(self, layer) + end + end + if not center.no_rank then + local rank = SMODS.Ranks[self.base.value] or {} + if rank.draw and type(rank.draw) == 'function' then + rank:draw(self, layer) + end + end + end + end, + conditions = { vortex = false, facing = 'front' }, +} +SMODS.DrawStep { + key = 'card_type_shader', + order = 10, + func = function(self) + if (self.ability.set == 'Voucher' or self.config.center.demo) and (self.ability.name ~= 'Antimatter' or not (self.config.center.discovered or self.bypass_discovery_center)) then + if self:should_draw_base_shader() then + self.children.center:draw_shader('voucher', nil, self.ARGS.send_to_shader) + end + end + if (self.ability.set == 'Booster' or self.ability.set == 'Spectral') and self:should_draw_base_shader() then + self.children.center:draw_shader('booster', nil, self.ARGS.send_to_shader) + end + end, + conditions = { vortex = false, facing = 'front' }, +} + +SMODS.DrawStep { + key = 'edition', + order = 20, + func = function(self, layer) + if self.edition then + for k, v in pairs(G.P_CENTER_POOLS.Edition) do + if self.edition[v.key:sub(3)] and v.shader then + if type(v.draw) == 'function' then + v:draw(self, layer) + else + self.children.center:draw_shader(v.shader, nil, self.ARGS.send_to_shader) + if self.children.front and self.ability.effect ~= 'Stone Card' and not self.config.center.replace_base_card then + self.children.front:draw_shader(v.shader, nil, self.ARGS.send_to_shader) + end + end + end + end + end + if (self.edition and self.edition.negative) or (self.ability.name == 'Antimatter' and (self.config.center.discovered or self.bypass_discovery_center)) then + self.children.center:draw_shader('negative_shine', nil, self.ARGS.send_to_shader) + end + end, + conditions = { vortex = false, facing = 'front' }, +} + +SMODS.DrawStep { + key = 'seal', + order = 30, + func = function(self, layer) + local seal = G.P_SEALS[self.seal] or {} + if type(seal.draw) == 'function' then + seal:draw(self, layer) + elseif self.seal then + G.shared_seals[self.seal].role.draw_major = self + G.shared_seals[self.seal]:draw_shader('dissolve', nil, nil, nil, self.children.center) + if self.seal == 'Gold' then G.shared_seals[self.seal]:draw_shader('voucher', nil, self.ARGS.send_to_shader, nil, self.children.center) end + end + end, + conditions = { vortex = false, facing = 'front' }, +} + +SMODS.DrawStep { + key = 'stickers', + order = 40, + func = function(self, layer) + if self.sticker and G.shared_stickers[self.sticker] then + G.shared_stickers[self.sticker].role.draw_major = self + G.shared_stickers[self.sticker]:draw_shader('dissolve', nil, nil, nil, self.children.center) + G.shared_stickers[self.sticker]:draw_shader('voucher', nil, self.ARGS.send_to_shader, nil, self.children.center) + elseif (self.sticker_run and G.shared_stickers[self.sticker_run]) and G.SETTINGS.run_stake_stickers then + G.shared_stickers[self.sticker_run].role.draw_major = self + G.shared_stickers[self.sticker_run]:draw_shader('dissolve', nil, nil, nil, self.children.center) + G.shared_stickers[self.sticker_run]:draw_shader('voucher', nil, self.ARGS.send_to_shader, nil, self.children.center) + end + + for k, v in pairs(SMODS.Stickers) do + if self.ability[v.key] then + if v and v.draw and type(v.draw) == 'function' then + v:draw(self, layer) + else + G.shared_stickers[v.key].role.draw_major = self + G.shared_stickers[v.key]:draw_shader('dissolve', nil, nil, nil, self.children.center) + G.shared_stickers[v.key]:draw_shader('voucher', nil, self.ARGS.send_to_shader, nil, self.children.center) + end + end + end + end, + conditions = { vortex = false, facing = 'front' }, +} + +SMODS.DrawStep { + key = 'soul', + order = 50, + func = function(self) + if self.ability.name == 'The Soul' and (self.config.center.discovered or self.bypass_discovery_center) then + local scale_mod = 0.05 + 0.05*math.sin(1.8*G.TIMERS.REAL) + 0.07*math.sin((G.TIMERS.REAL - math.floor(G.TIMERS.REAL))*math.pi*14)*(1 - (G.TIMERS.REAL - math.floor(G.TIMERS.REAL)))^3 + local rotate_mod = 0.1*math.sin(1.219*G.TIMERS.REAL) + 0.07*math.sin((G.TIMERS.REAL)*math.pi*5)*(1 - (G.TIMERS.REAL - math.floor(G.TIMERS.REAL)))^2 + + G.shared_soul.role.draw_major = self + G.shared_soul:draw_shader('dissolve',0, nil, nil, self.children.center,scale_mod, rotate_mod,nil, 0.1 + 0.03*math.sin(1.8*G.TIMERS.REAL),nil, 0.6) + G.shared_soul:draw_shader('dissolve', nil, nil, nil, self.children.center, scale_mod, rotate_mod) + end + end, + conditions = { vortex = false, facing = 'front' }, +} + +SMODS.DrawStep { + key = 'floating_sprite', + order = 60, + func = function(self) + if self.config.center.soul_pos and (self.config.center.discovered or self.bypass_discovery_center) then + local scale_mod = 0.07 + 0.02*math.sin(1.8*G.TIMERS.REAL) + 0.00*math.sin((G.TIMERS.REAL - math.floor(G.TIMERS.REAL))*math.pi*14)*(1 - (G.TIMERS.REAL - math.floor(G.TIMERS.REAL)))^3 + local rotate_mod = 0.05*math.sin(1.219*G.TIMERS.REAL) + 0.00*math.sin((G.TIMERS.REAL)*math.pi*5)*(1 - (G.TIMERS.REAL - math.floor(G.TIMERS.REAL)))^2 + + if type(self.config.center.soul_pos.draw) == 'function' then + self.config.center.soul_pos.draw(self, scale_mod, rotate_mod) + elseif self.ability.name == 'Hologram' then + self.hover_tilt = self.hover_tilt*1.5 + self.children.floating_sprite:draw_shader('hologram', nil, self.ARGS.send_to_shader, nil, self.children.center, 2*scale_mod, 2*rotate_mod) + self.hover_tilt = self.hover_tilt/1.5 + else + self.children.floating_sprite:draw_shader('dissolve',0, nil, nil, self.children.center,scale_mod, rotate_mod,nil, 0.1 + 0.03*math.sin(1.8*G.TIMERS.REAL),nil, 0.6) + self.children.floating_sprite:draw_shader('dissolve', nil, nil, nil, self.children.center, scale_mod, rotate_mod) + end + if self.edition then + for k, v in pairs(G.P_CENTER_POOLS.Edition) do + if v.apply_to_float then + if self.edition[v.key:sub(3)] then + self.children.floating_sprite:draw_shader(v.shader, nil, nil, nil, self.children.center, scale_mod, rotate_mod) + end + end + end + end + end + end, + conditions = { vortex = false, facing = 'front' }, +} + +SMODS.DrawStep { + key = 'debuff', + order = 70, + func = function(self) + if self.debuff then + self.children.center:draw_shader('debuff', nil, self.ARGS.send_to_shader) + if self.children.front and (self.ability.delayed or (self.ability.effect ~= 'Stone Card' and not self.config.center.replace_base_card)) then + self.children.front:draw_shader('debuff', nil, self.ARGS.send_to_shader) + end + end + end, + conditions = { vortex = false, facing = 'front' }, +} + +SMODS.DrawStep { + key = 'greyed', + order = 80, + func = function(self) + if self.greyed then + self.children.center:draw_shader('played', nil, self.ARGS.send_to_shader) + if self.children.front and (self.ability.delayed or (self.ability.effect ~= 'Stone Card' and not self.config.center.replace_base_card)) then + self.children.front:draw_shader('played', nil, self.ARGS.send_to_shader) + end + end + end, + conditions = { vortex = false, facing = 'front' }, +} + +SMODS.DrawStep { + key = 'back', + order = 0, + func = function(self) + local overlay = G.C.WHITE + if self.area and self.area.config.type == 'deck' and self.rank > 3 then + self.back_overlay = self.back_overlay or {} + self.back_overlay[1] = 0.5 + ((#self.area.cards - self.rank)%7)/50 + self.back_overlay[2] = 0.5 + ((#self.area.cards - self.rank)%7)/50 + self.back_overlay[3] = 0.5 + ((#self.area.cards - self.rank)%7)/50 + self.back_overlay[4] = 1 + overlay = self.back_overlay + end + + if self.area and self.area.config.type == 'deck' then + self.children.back:draw(overlay) + else + self.children.back:draw_shader('dissolve') + end + end, + conditions = { vortex = false, facing = 'back' }, +} + +SMODS.DrawStep { + key = 'back_sticker', + order = 10, + func = function(self) + if self.sticker and G.shared_stickers[self.sticker] then + G.shared_stickers[self.sticker].role.draw_major = self + local sticker_offset = self.sticker_offset or {} + G.shared_stickers[self.sticker]:draw_shader('dissolve', nil, nil, true, self.children.center, nil, self.sticker_rotation, sticker_offset.x, sticker_offset.y) + local stake = G.P_STAKES['stake_'..string.lower(self.sticker)] or {} + if stake.shiny then G.shared_stickers[self.sticker]:draw_shader('voucher', nil, self.ARGS.send_to_shader, true, self.children.center) end + end + end, + conditions = { vortex = false, facing = 'back' }, +} + +-- All keys in this table will not be automatically drawn with a default `draw()` call in the "others" DrawStep. +SMODS.draw_ignore_keys = { + focused_ui = true, front = true, back = true, soul_parts = true, center = true, floating_sprite = true, shadow = true, use_button = true, buy_button = true, buy_and_use_button = true, debuff = true, price = true, particles = true, h_popup = true +} +SMODS.DrawStep { + key = 'others', + order = 90, + func = function(self) + for k, v in pairs(self.children) do + if not v.custom_draw and not SMODS.draw_ignore_keys[k] then v:draw() end + end + end, +} + +SMODS.DrawStep { + key = 'focused_ui_2', + order = 100, + func = function(self) + if self.area == G.hand then + if self.children.focused_ui then self.children.focused_ui:draw() end + end + end, +} + +SMODS.DrawStep { + key = 'drawhash_boundingrect', + order = 1000, + func = function(self) + add_to_drawhash(self) + self:draw_boundingrect() + end, +} + +function Card:draw(layer) + layer = layer or 'both' + self.hover_tilt = 1 + if not self.states.visible then return end + for _, k in ipairs(SMODS.DrawStep.obj_buffer) do + if SMODS.DrawSteps[k]:check_conditions(self, layer) then SMODS.DrawSteps[k].func(self, layer) end + end +end \ No newline at end of file diff --git a/Steamodded/src/compat_0_9_8.lua b/smods/src/compat_0_9_8.lua similarity index 100% rename from Steamodded/src/compat_0_9_8.lua rename to smods/src/compat_0_9_8.lua diff --git a/Steamodded/src/core.lua b/smods/src/core.lua similarity index 100% rename from Steamodded/src/core.lua rename to smods/src/core.lua diff --git a/Steamodded/src/crash_handler.lua b/smods/src/crash_handler.lua similarity index 98% rename from Steamodded/src/crash_handler.lua rename to smods/src/crash_handler.lua index e762ad1..989889e 100644 --- a/Steamodded/src/crash_handler.lua +++ b/smods/src/crash_handler.lua @@ -38,7 +38,7 @@ function loadStackTracePlus() local table_concat = table.concat local _M = { - max_tb_output_len = 70 -- controls the maximum length of the 'stringified' table before cutting with ' (more...)' + max_tb_output_len = 140 -- controls the maximum length of the 'stringified' table before cutting with ' (more...)' } -- this tables should be weak so the elements in them won't become uncollectable @@ -663,6 +663,9 @@ function injectStackTrace() if sanitizedmsg:find("Syntax error: game.lua:4: '=' expected near 'Game'") then table.insert(err, 'Duplicate installation of Steamodded detected! Please clean your installation: Steam Library > Balatro > Properties > Installed Files > Verify integrity of game files.') + elseif sanitizedmsg:find("Syntax error: game.lua:%d+: duplicate label 'continue'") then + table.insert(err, + 'Duplicate installation of Steamodded detected! Please remove the duplicate steamodded/smods folder in your mods folder.') else table.insert(err, sanitizedmsg) end diff --git a/Steamodded/src/game_object.lua b/smods/src/game_object.lua similarity index 94% rename from Steamodded/src/game_object.lua rename to smods/src/game_object.lua index 7513cd5..91df256 100644 --- a/Steamodded/src/game_object.lua +++ b/smods/src/game_object.lua @@ -23,6 +23,7 @@ function loadAPIs() o = o or {} assert(o.mod == nil) o.mod = SMODS.current_mod + o.original_mod = o.mod setmetatable(o, self) for _, v in ipairs(o.required_params or {}) do assert(not (o[v] == nil), ('Missing required parameter for %s declaration: %s'):format(o.set, v)) @@ -84,7 +85,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. if above_stake_cfg ~= false then if type(above_stake_cfg) ~= 'table' then above_stake_cfg = {} end SMODS.modify_key(obj, mod and mod.prefix, above_stake_cfg.mod, 'above_stake') - SMODS.modify_key(obj, cls.class_prefix, above_stake_cfg.class, 'above_stake') + SMODS.modify_key(obj, cls.class_prefix, above_stake_cfg.class, 'above_stake') end local applied_stakes_cfg = obj.prefix_config.applied_stakes if applied_stakes_cfg ~= false and obj.applied_stakes then @@ -98,7 +99,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. if unlocked_stake_cfg ~= false then if type(unlocked_stake_cfg) ~= 'table' then unlocked_stake_cfg = {} end SMODS.modify_key(obj, mod and mod.prefix, unlocked_stake_cfg.mod, 'unlocked_stake') - SMODS.modify_key(obj, cls.class_prefix, unlocked_stake_cfg.class, 'unlocked_stake') + SMODS.modify_key(obj, cls.class_prefix, unlocked_stake_cfg.class, 'unlocked_stake') end end @@ -144,8 +145,8 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. function SMODS.GameObject:process_loc_text() SMODS.process_loc_text(G.localization.descriptions[self.set], self.key, self.loc_txt) end - - --- Starting from this class, recursively searches for + + --- Starting from this class, recursively searches for --- functions with the given key on all subordinate classes --- and run all found functions with the given arguments function SMODS.GameObject:send_to_subclasses(func, ...) @@ -217,11 +218,11 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. end local is_loc_modified = obj.loc_txt or obj.loc_vars or obj.generate_ui if is_loc_modified then orig_o.is_loc_modified = true end - if not orig_o.is_loc_modified then + if not orig_o.is_loc_modified and not orig_o.original_mod then -- Setting generate_ui to this sentinel value -- makes vanilla localization code run instead of SMODS's code orig_o.generate_ui = 0 - else + elseif not orig_o.original_mod then -- reset the value if otherwise, in case when the object was taken over before and this value was already set to 0 if orig_o.generate_ui == 0 then orig_o.generate_ui = nil @@ -311,7 +312,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. set = '[INTERNAL]', register = function() error('INTERNAL CLASS, DO NOT CALL') end, pre_inject_class = function() - SMODS.handle_loc_file(SMODS.path) + SMODS.handle_loc_file(SMODS.path, '_') if SMODS.dump_loc then SMODS.dump_loc.pre_inject = copy_table(G.localization) end for _, mod in ipairs(SMODS.mod_list) do if mod.process_loc_text and type(mod.process_loc_text) == 'function' then @@ -374,7 +375,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. end end, process_loc_text = function() end, - pre_inject_class = function(self) + pre_inject_class = function(self) G:set_render_settings() -- restore originals first in case a texture pack was disabled end } @@ -422,7 +423,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. replace, times = self.replace, -1 end self.replace_sounds[replace] = { key = self.key, times = times, args = args } - end + end -- TODO detect music state based on if select_music_track exists assert(not self.select_music_track or self.key:find('music')) SMODS.Sound.super.register(self) @@ -628,7 +629,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. SMODS.build_stake_chain(G.P_STAKES[s], applied) end return applied - end + end function SMODS.setup_stake(i) local applied_stakes = SMODS.build_stake_chain(G.P_CENTER_POOLS.Stake[i]) @@ -729,7 +730,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. G.GAME.modifiers.enable_perishables_in_shop = true end, colour = G.C.ORANGE, - loc_txt = {} + loc_txt = {}, } SMODS.Stake { name = "Gold Stake", @@ -762,6 +763,10 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. inject = function(self) G.P_JOKER_RARITY_POOLS[self.key] = {} G.C.RARITY[self.key] = self.badge_colour + -- Called every frame, moving deprecated prints here + if self.gradient and type(self.gradient) == "function" then + sendWarnMessage(('Found `gradient` function on SMODS.Rarity object "%s". This field is deprecated; please use `SMODS.Gradient` API instead.'):format(obj.key), 'Rarity') + end end, process_loc_text = function(self) SMODS.process_loc_text(G.localization.misc.labels, "k_"..self.key:lower(), self.loc_txt, 'name') @@ -769,21 +774,21 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. end, get_rarity_badge = function(self, rarity) local vanilla_rarity_keys = {localize('k_common'), localize('k_uncommon'), localize('k_rare'), localize('k_legendary')} - if (vanilla_rarity_keys)[rarity] then + if (vanilla_rarity_keys)[rarity] then return vanilla_rarity_keys[rarity] --compat layer in case function gets the int of the rarity - else + else return localize("k_"..rarity:lower()) - end + end end, } function SMODS.inject_rarity(object_type, rarity) - if not object_type.rarities then + if not object_type.rarities then object_type.rarities = {} object_type.rarity_pools = {} end object_type.rarities[#object_type.rarities+1] = { - key = rarity.key, + key = rarity.key, weight = type(rarity.pools[object_type.key]) == "table" and rarity.pools[object_type.key].weight or rarity.default_weight } for _, vv in ipairs(object_type.rarities) do @@ -858,7 +863,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. required_params = { 'key', }, - prefix_config = { key = false }, + prefix_config = { key = false }, inject = function(self) G.P_CENTER_POOLS[self.key] = G.P_CENTER_POOLS[self.key] or {} local injected_rarities = {} @@ -1112,8 +1117,8 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. inject = function(self) -- call the parent function to ensure all pools are set SMODS.Center.inject(self) - if self.taken_ownership and self.rarity_original == self.rarity then - SMODS.remove_pool(G.P_JOKER_RARITY_POOLS[self.rarity_original], self.key) + if self.taken_ownership and self.rarity_original and self.rarity_original ~= self.rarity then + SMODS.remove_pool(G.P_JOKER_RARITY_POOLS[self.rarity_original] or {}, self.key) SMODS.insert_pool(G.P_JOKER_RARITY_POOLS[self.rarity], self, false) else SMODS.insert_pool(G.P_JOKER_RARITY_POOLS[self.rarity], self) @@ -1172,7 +1177,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. return {} end } - + SMODS.Tarot = SMODS.Consumable:extend { set = 'Tarot', } @@ -1208,7 +1213,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. SMODS.Voucher:take_ownership('observatory', { calculate = function(self, card, context) - if + if context.other_consumeable and context.other_consumeable.ability.set == 'Planet' and context.other_consumeable.ability.consumeable.hand_type == context.scoring_name @@ -1306,7 +1311,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. if desc_nodes == full_UI_table.main and not full_UI_table.name then full_UI_table.name = localize{type = 'name', set = 'Other', key = res.name_key or target.key, nodes = full_UI_table.name, vars = res.name_vars or target.vars or {}} elseif desc_nodes ~= full_UI_table.main and not desc_nodes.name then - desc_nodes.name = localize{type = 'name_text', key = res.name_key or target.key, set = 'Other' } + desc_nodes.name = localize{type = 'name_text', key = res.name_key or target.key, set = 'Other' } end localize(target) desc_nodes.background_colour = res.background_colour @@ -1320,7 +1325,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. update_pack = function(self, dt) if G.buttons then G.buttons:remove(); G.buttons = nil end if G.shop then G.shop.alignment.offset.y = G.ROOM.T.y+11 end - + if not G.STATE_COMPLETE then G.STATE_COMPLETE = true G.CONTROLLER.interrupt.focus = true @@ -1339,7 +1344,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. trigger = 'immediate', func = function() if self.draw_hand == true then G.FUNCS.draw_from_deck_to_hand() end - + G.E_MANAGER:add_event(Event({ trigger = 'after', delay = 0.5, @@ -1349,10 +1354,10 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. end})) return true end - })) + })) return true end - })) + })) end end, ease_background_colour = function(self) @@ -1364,7 +1369,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. G.pack_cards = CardArea( G.ROOM.T.x + 9 + G.hand.T.x, G.hand.T.y, math.max(1,math.min(_size,5))*G.CARD_W*1.1, - 1.05*G.CARD_H, + 1.05*G.CARD_H, {card_limit = _size, type = 'consumeable', highlight_limit = 1}) local t = {n=G.UIT.ROOT, config = {align = 'tm', r = 0.15, colour = G.C.CLEAR, padding = 0.15}, nodes={ @@ -1412,7 +1417,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. draw_hand = true, update_pack = SMODS.Booster.update_pack, ease_background_colour = function(self) ease_background_colour_blind(G.STATES.TAROT_PACK) end, - create_UIBox = function(self) return create_UIBox_arcana_pack() end, + create_UIBox = SMODS.Booster.create_UIBox, particles = function(self) G.booster_pack_sparkles = Particles(1, 1, 0,0, { timer = 0.015, @@ -1444,7 +1449,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. group_key = "k_celestial_pack", update_pack = SMODS.Booster.update_pack, ease_background_colour = function(self) ease_background_colour_blind(G.STATES.PLANET_PACK) end, - create_UIBox = function(self) return create_UIBox_celestial_pack() end, + create_UIBox = SMODS.Booster.create_UIBox, particles = function(self) G.booster_pack_stars = Particles(1, 1, 0,0, { timer = 0.07, @@ -1498,7 +1503,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. draw_hand = true, update_pack = SMODS.Booster.update_pack, ease_background_colour = function(self) ease_background_colour_blind(G.STATES.SPECTRAL_PACK) end, - create_UIBox = function(self) return create_UIBox_spectral_pack() end, + create_UIBox = SMODS.Booster.create_UIBox, particles = function(self) G.booster_pack_sparkles = Particles(1, 1, 0,0, { timer = 0.015, @@ -1524,7 +1529,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. group_key = "k_standard_pack", update_pack = SMODS.Booster.update_pack, ease_background_colour = function(self) ease_background_colour_blind(G.STATES.STANDARD_PACK) end, - create_UIBox = function(self) return create_UIBox_standard_pack() end, + create_UIBox = SMODS.Booster.create_UIBox, particles = function(self) G.booster_pack_sparkles = Particles(1, 1, 0,0, { timer = 0.015, @@ -1552,7 +1557,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. group_key = "k_buffoon_pack", update_pack = SMODS.Booster.update_pack, ease_background_colour = function(self) ease_background_colour_blind(G.STATES.BUFFOON_PACK) end, - create_UIBox = function(self) return create_UIBox_buffoon_pack() end, + create_UIBox = SMODS.Booster.create_UIBox, create_card = function(self, card) return {set = "Joker", area = G.pack_cards, skip_materialize = true, soulable = true, key_append = "buf"} end, @@ -1684,6 +1689,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. end, get_obj = function(self, key) return G.P_SEALS[key] end, generate_ui = function(self, info_queue, card, desc_nodes, specific_vars, full_UI_table) + card = card or self:create_fake_card() local target = { type = 'other', set = 'Other', @@ -1717,6 +1723,9 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. end desc_nodes.background_colour = res.background_colour end, + create_fake_card = function(self) + return { ability = { seal = copy_table(self.config) }, fake_card = true } + end, } for _,v in ipairs { 'Purple', 'Gold', 'Blue', 'Red' } do SMODS.Seal:take_ownership(v, { badge_colour = G.C[v:upper()], pos = G.shared_seals[v].sprite_pos, generate_ui = SMODS.Seal.generate_ui }) @@ -1884,6 +1893,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. ignore = false }, next = {}, + prev = {}, straight_edge = false, -- TODO we need a better system for what this is doing. -- We should allow setting a playing card's atlas and position to any values, @@ -1929,6 +1939,12 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. else table.insert(self.obj_buffer, self.key) end + for _,v in ipairs(self.next) do + local other = self.obj_table[v] + if other then + table.insert(other.prev, self.key) + end + end end end, process_loc_text = function(self) @@ -2342,7 +2358,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. return end if self:check_dependencies() then - assert(not self.palettes ~= not (self.ranks and self.lc_atlas), + assert(not self.palettes ~= not (self.ranks and self.lc_atlas), ('Error loading DeckSkin %s! Please define your palettes or use the old formatting'):format(self.key)) -- for compat with old format self.pos_style = self.posStyle or self.pos_style @@ -2415,12 +2431,12 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. if type(key) == "number" then key = G.COLLABS.options[suit][key] end - + local conv_palette_loc_options = {} for k, v in pairs(G.localization.misc.collab_palettes[key]) do conv_palette_loc_options[tonumber(k)] = v end - + return conv_palette_loc_options end, post_inject_class = function(self) @@ -2435,7 +2451,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. G.SETTINGS.colour_palettes[k] = skin.palettes[1].key end end - + end } @@ -2569,7 +2585,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. } SMODS.PokerHandPart { key = '_straight', - func = function(hand) return get_straight(hand) end + func = function(hand) return get_straight(hand, next(SMODS.find_card('j_four_fingers')) and 4 or 5, next(SMODS.find_card('j_shortcut'))) end } SMODS.PokerHandPart { key = '_flush', @@ -2600,26 +2616,26 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. ['Flush House'] = function(parts) if #parts._3 < 1 or #parts._2 < 2 or not next(parts._flush) then return {} end return { SMODS.merge_lists(parts._all_pairs, parts._flush) } - end, + end, ['Five of a Kind'] = function(parts) return parts._5 end, ['Straight Flush'] = function(parts) if not next(parts._straight) or not next(parts._flush) then return end return { SMODS.merge_lists(parts._straight, parts._flush) } - end, - ['Four of a Kind'] = function(parts) return parts._4 end, + end, + ['Four of a Kind'] = function(parts) return parts._4 end, ['Full House'] = function(parts) if #parts._3 < 1 or #parts._2 < 2 then return {} end return parts._all_pairs end, ['Flush'] = function(parts) return parts._flush end, ['Straight'] = function(parts) return parts._straight end, - ['Three of a Kind'] = function(parts) return parts._3 end, + ['Three of a Kind'] = function(parts) return parts._3 end, ['Two Pair'] = function(parts) if #parts._2 < 2 then return {} end return parts._all_pairs - end, - ['Pair'] = function(parts) return parts._2 end, - ['High Card'] = function(parts) return parts._highest end, + end, + ['Pair'] = function(parts) return parts._2 end, + ['High Card'] = function(parts) return parts._highest end, } for _, v in ipairs(handlist) do local hand = copy_table(hands[v]) @@ -2747,7 +2763,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. if desc_nodes == full_UI_table.main and not full_UI_table.name then full_UI_table.name = localize { type = 'name', set = target.set, key = res.name_key or target.key, nodes = full_UI_table.name, vars = res.name_vars or res.vars or {} } elseif desc_nodes ~= full_UI_table.main and not desc_nodes.name then - desc_nodes.name = localize{type = 'name_text', key = res.name_key or target.key, set = target.set } + desc_nodes.name = localize{type = 'name_text', key = res.name_key or target.key, set = target.set } end if res.main_start then desc_nodes[#desc_nodes + 1] = res.main_start @@ -2801,13 +2817,13 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. -- or handling it in apply -- TODO: rename should_apply = function(self, card, center, area, bypass_roll) - if + if ( not self.sets or self.sets[center.set or {}]) and ( center[self.key..'_compat'] or -- explicit marker (self.default_compat and not self.compat_exceptions[center.key]) or -- default yes with no exception (not self.default_compat and self.compat_exceptions[center.key]) -- default no with exception - ) and + ) and (not self.needs_enable_flag or G.GAME.modifiers['enable_'..self.key]) then self.last_roll = pseudorandom((area == G.pack_cards and 'packssj' or 'shopssj')..self.key..G.GAME.round_resets.ante) @@ -2820,7 +2836,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. } -- Create base game stickers - -- eternal and perishable follow shared checks for sticker application, therefore omitted + -- eternal and perishable follow shared checks for sticker application, therefore omitted SMODS.Sticker{ key = "eternal", badge_colour = HEX 'c75985', @@ -2893,7 +2909,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. prefix_config = {key = false}, pos = { x = 10, y = 10 }, -- Base game has no art, and I haven't made any yet to represent Pinned with rate = 0, - should_apply = false, + should_apply = false, order = 4, apply = function(self, card, val) card[self.key] = val @@ -2943,16 +2959,44 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. -- You will probably want to override this if your enhancement interacts with -- those parts of the base card. generate_ui = function(self, info_queue, card, desc_nodes, specific_vars, full_UI_table) + local always_show = self.config and self.config.always_show or {} if specific_vars and specific_vars.nominal_chips and not self.replace_base_card then localize { type = 'other', key = 'card_chips', nodes = desc_nodes, vars = { specific_vars.nominal_chips } } end SMODS.Enhancement.super.generate_ui(self, info_queue, card, desc_nodes, specific_vars, full_UI_table) if specific_vars and specific_vars.bonus_chips then local remaining_bonus_chips = specific_vars.bonus_chips - (self.config.bonus or 0) - if remaining_bonus_chips > 0 then - localize { type = 'other', key = 'card_extra_chips', nodes = desc_nodes, vars = { specific_vars.bonus_chips - (self.config.bonus or 0) } } + if remaining_bonus_chips ~= 0 then + localize { type = 'other', key = 'card_extra_chips', nodes = desc_nodes, vars = { SMODS.signed(remaining_bonus_chips) } } end end + 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}} + end + if specific_vars and specific_vars.bonus_mult then + localize{type = 'other', key = 'card_extra_mult', nodes = desc_nodes, vars = {SMODS.signed(specific_vars.bonus_mult)}} + end + if specific_vars and specific_vars.bonus_x_mult then + localize{type = 'other', key = 'card_x_mult', nodes = desc_nodes, vars = {specific_vars.bonus_x_mult}} + end + 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 + 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 + localize{type = 'other', key = 'card_extra_h_mult', nodes = desc_nodes, vars = {SMODS.signed(specific_vars.bonus_h_mult)}} + end + if specific_vars and specific_vars.bonus_h_x_mult then + localize{type = 'other', key = 'card_h_x_mult', nodes = desc_nodes, vars = {specific_vars.bonus_h_x_mult}} + end + if specific_vars and specific_vars.bonus_p_dollars then + localize{type = 'other', key = 'card_extra_p_dollars', nodes = desc_nodes, vars = {SMODS.signed_dollars(specific_vars.bonus_p_dollars)}} + end + if specific_vars and specific_vars.bonus_h_dollars then + localize{type = 'other', key = 'card_extra_h_dollars', nodes = desc_nodes, vars = {SMODS.signed_dollars(specific_vars.bonus_h_dollars)}} + end end, -- other methods: -- calculate(self, context, effect) @@ -3039,7 +3083,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. }, -- optional fields: extra_cost = nil, - + -- TODO badge colours. need to check how Steamodded already does badge colors -- other methods: calculate = nil, -- function (self) @@ -3057,7 +3101,10 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. -- apply_modifier = true when G.GAME.edition_rate is to be applied get_weight = function(self, apply_modifier) return self.weight - end + end, + create_fake_card = function(self) + return { edition = copy_table(self.config), fake_card = true } + end, } -- TODO also, this should probably be a utility method in core @@ -3093,14 +3140,14 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. get_weight = function(self) return G.GAME.edition_rate * self.weight end, - loc_vars = function(self) - return { vars = { self.config.chips } } + loc_vars = function(self, info_queue, card) + return { vars = { card.edition.chips } } end, calculate = function(self, card, context) if context.pre_joker or (context.main_scoring and context.cardarea == G.play) then return { chips = card.edition.chips - } + } end end }) @@ -3124,14 +3171,14 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. get_weight = function(self) return G.GAME.edition_rate * self.weight end, - loc_vars = function(self) - return { vars = { self.config.mult } } + loc_vars = function(self, info_queue, card) + return { vars = { card.edition.mult } } end, calculate = function(self, card, context) if context.pre_joker or (context.main_scoring and context.cardarea == G.play) then return { mult = card.edition.mult - } + } end end }) @@ -3155,14 +3202,14 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. get_weight = function(self) return (G.GAME.edition_rate - 1) * G.P_CENTERS["e_negative"].weight + G.GAME.edition_rate * self.weight end, - loc_vars = function(self) - return { vars = { self.config.x_mult } } + loc_vars = function(self, info_queue, card) + return { vars = { card.edition.x_mult } } end, calculate = function(self, card, context) if context.post_joker or (context.main_scoring and context.cardarea == G.play) then return { x_mult = card.edition.x_mult - } + } end end }) @@ -3186,8 +3233,8 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. get_weight = function(self) return self.weight end, - loc_vars = function(self) - return { vars = { self.config.card_limit } } + loc_vars = function(self, info_queue, card) + return { vars = { card.edition.card_limit } } end, }) @@ -3220,7 +3267,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. end, inject = function(_) end } - + SMODS.Keybind { key_pressed = 'm', event = 'held', @@ -3232,7 +3279,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. } ------------------------------------------------------------------------------------------------- - ------- API CODE GameObject.Achievements + ------- API CODE GameObject.Achievement ------------------------------------------------------------------------------------------------- SMODS.Achievements = {} @@ -3265,6 +3312,54 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. end, } + ------------------------------------------------------------------------------------------------- + ------- API CODE GameObject.Gradient + ------------------------------------------------------------------------------------------------- + + SMODS.Gradients = {} + SMODS.Gradient = SMODS.GameObject:extend { + obj_table = SMODS.Gradients, + obj_buffer = {}, + required_params = { 'key' }, + interpolation = 'trig', + cycle = 10, + colours = {}, + inject = function(self) self[1], self[2], self[3], self[4] = 0,0,0,1 end, + update = function(self, dt) + if #self.colours < 2 then return end + local timer = G.TIMERS.REAL%self.cycle + local start_index = math.ceil(timer*#self.colours/self.cycle) + local end_index = start_index == #self.colours and 1 or start_index+1 + local start_colour, end_colour = self.colours[start_index], self.colours[end_index] + local partial_timer = (timer%(self.cycle/#self.colours))*#self.colours/self.cycle + for i = 1, 4 do + if self.interpolation == 'linear' then + + self[i] = start_colour[i] + partial_timer*(end_colour[i]-start_colour[i]) + elseif self.interpolation == 'trig' then + self[i] = start_colour[i] + 0.5*(1-math.cos(partial_timer*math.pi))*(end_colour[i]-start_colour[i]) + end + end + end, + } + SMODS.Gradient { + key = 'warning_bg', + colours = { G.C.RED, G.C.GREEN }, + cycle = 1, + } + SMODS.Gradient { + key = 'warning_text', + colours = { G.C.WHITE, G.C.RED }, + cycle = 1, + } + + + ------------------------------------------------------------------------------------------------- + ----- API IMPORT GameObject.DrawStep + ------------------------------------------------------------------------------------------------- + + assert(load(NFS.read(SMODS.path..'src/card_draw.lua'), ('=[SMODS _ "src/card_draw.lua"]')))() + ------------------------------------------------------------------------------------------------- ----- INTERNAL API CODE GameObject._Loc_Post ------------------------------------------------------------------------------------------------- @@ -3278,7 +3373,7 @@ Set `prefix_config.key = false` on your object instead.]]):format(obj.key), obj. pre_inject_class = function() for _, mod in ipairs(SMODS.mod_list) do if mod.can_load then - SMODS.handle_loc_file(mod.path) + SMODS.handle_loc_file(mod.path, mod.id) end end end diff --git a/Steamodded/src/index.lua b/smods/src/index.lua similarity index 100% rename from Steamodded/src/index.lua rename to smods/src/index.lua diff --git a/Steamodded/src/loader.lua b/smods/src/loader.lua similarity index 100% rename from Steamodded/src/loader.lua rename to smods/src/loader.lua diff --git a/Steamodded/src/logging.lua b/smods/src/logging.lua similarity index 100% rename from Steamodded/src/logging.lua rename to smods/src/logging.lua diff --git a/Steamodded/src/overrides.lua b/smods/src/overrides.lua similarity index 87% rename from Steamodded/src/overrides.lua rename to smods/src/overrides.lua index 139a35d..281ea3b 100644 --- a/Steamodded/src/overrides.lua +++ b/smods/src/overrides.lua @@ -40,7 +40,7 @@ function create_UIBox_your_collection_blinds(exit) 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 @@ -258,7 +258,7 @@ function create_UIBox_your_collection_blinds(exit) }, create_option_cycle({ options = page_options, - w = 4.5, + w = 4.5, cycle_shoulders = true, opt_callback = 'your_collection_blinds_page', focus_args = {snap_to = true, nav = 'wide'}, @@ -363,7 +363,7 @@ function G.FUNCS.your_collection_blinds_page(args) func = (function() for _, v in ipairs(blinds_to_be_alerted) do v.children.alert = UIBox{ - definition = create_UIBox_card_alert(), + definition = create_UIBox_card_alert(), config = { align="tri", offset = {x = 0.1, y = 0.1}, parent = v} } v.children.alert.states.collide.can = false @@ -512,7 +512,7 @@ function SMODS.applied_stakes_UI(i, stake_desc_rows, num_added) end _full_desc[#_full_desc] = nil stake_desc_rows[#stake_desc_rows + 1] = {n = G.UIT.R, config = {align = "cm" }, nodes = { - {n = G.UIT.C, config = {align = 'cm'}, nodes = { + {n = G.UIT.C, config = {align = 'cm'}, nodes = { {n = G.UIT.C, config = {align = "cm", colour = get_stake_col(i), r = 0.1, minh = 0.35, minw = 0.35, emboss = 0.05 }, nodes = {}}, {n = G.UIT.B, config = {w = 0.1, h = 0.1}}}}, {n = G.UIT.C, config = {align = "cm", padding = 0.03, colour = G.C.WHITE, r = 0.1, minh = 0.7, minw = 4.8 }, nodes = @@ -544,81 +544,70 @@ end --#endregion --#region straights and view deck UI -function get_straight(hand) - local ret = {} - local four_fingers = next(SMODS.find_card('j_four_fingers')) - local can_skip = next(SMODS.find_card('j_shortcut')) - if #hand < (5 - (four_fingers and 1 or 0)) then return ret end - local t = {} - local RANKS = {} - for i = 1, #hand do - if hand[i]:get_id() > 0 then - local rank = hand[i].base.value - RANKS[rank] = RANKS[rank] or {} - RANKS[rank][#RANKS[rank] + 1] = hand[i] - end - end - local straight_length = 0 - local straight = false - local skipped_rank = false - local vals = {} - for k, v in pairs(SMODS.Ranks) do - if v.straight_edge then - table.insert(vals, k) - end - end - local init_vals = {} - for _, v in ipairs(vals) do - init_vals[v] = true - end - if not next(vals) then table.insert(vals, 'Ace') end - local initial = true - local br = false - local end_iter = false - local i = 0 - while 1 do - end_iter = false - if straight_length >= (5 - (four_fingers and 1 or 0)) then - straight = true - end - i = i + 1 - if br or (i > #SMODS.Rank.obj_buffer + 1) then break end - if not next(vals) then break end - for _, val in ipairs(vals) do - if init_vals[val] and not initial then br = true end - if RANKS[val] then - straight_length = straight_length + 1 - skipped_rank = false - for _, vv in ipairs(RANKS[val]) do - t[#t + 1] = vv - end - vals = SMODS.Ranks[val].next - initial = false - end_iter = true - break - end - end - if not end_iter then - local new_vals = {} - for _, val in ipairs(vals) do - for _, r in ipairs(SMODS.Ranks[val].next) do - table.insert(new_vals, r) - end - end - vals = new_vals - if can_skip and not skipped_rank then - skipped_rank = true - else - straight_length = 0 - skipped_rank = false - if not straight then t = {} end - if straight then break end - end - end - end - if not straight then return ret end - table.insert(ret, t) - return ret + +function get_straight(hand, min_length, skip, wrap) + min_length = min_length or 5 + if min_length < 2 then min_length = 2 end + if #hand < min_length then return {} end + local ranks = {} + for k,_ in pairs(SMODS.Ranks) do ranks[k] = {} end + for _,card in ipairs(hand) do + local id = card:get_id() + if id > 0 then + for k,v in pairs(SMODS.Ranks) do + if v.id == id then table.insert(ranks[k], card); break end + end + end + end + local function next_ranks(key) + local rank = SMODS.Ranks[key] + local ret = {} + for _,v in ipairs(rank.next) do + ret[#ret+1] = v + if skip then + for _,w in ipairs(SMODS.Ranks[v].next) do + ret[#ret+1] = w + end + end + end + return ret + end + local tuples = {} + local ret = {} + for _,k in ipairs(SMODS.Rank.obj_buffer) do + if next(ranks[k]) then + tuples[#tuples+1] = {k} + end + end + for i = 2, #hand+1 do + local new_tuples = {} + for _, tuple in ipairs(tuples) do + local any_tuple + if (not SMODS.Ranks[tuple[i-1]].straight_edge or i == 2 or wrap) and i ~= #hand+1 then + for _,l in ipairs(next_ranks(tuple[i-1])) do + if next(ranks[l]) then + local new_tuple = {} + for _,v in ipairs(tuple) do new_tuple[#new_tuple+1] = v end + new_tuple[#new_tuple+1] = l + new_tuples[#new_tuples+1] = new_tuple + any_tuple = true + end + end + end + if i > min_length and not any_tuple then + local straight = {} + for _,v in ipairs(tuple) do + for _,card in ipairs(ranks[v]) do + straight[#straight+1] = card + end + end + ret[#ret+1] = straight + end + end + tuples = new_tuples + end + table.sort(ret, function(a,b) return #a > #b end) + return ret end function G.UIDEF.deck_preview(args) @@ -960,9 +949,9 @@ function G.UIDEF.view_deck(unplayed_only) -- base cards {n = G.UIT.R, config = {align = "cm", minh = 0.05, padding = 0.07}, nodes = { {n = G.UIT.O, config = { - object = DynaText({ - string = { - { string = localize('k_base_cards'), colour = G.C.RED }, + object = DynaText({ + string = { + { string = localize('k_base_cards'), colour = G.C.RED }, modded and { string = localize('k_effective'), colour = G.C.BLUE } or nil }, colours = { G.C.RED }, silent = true, scale = 0.4, pop_in_rate = 10, pop_delay = 4 @@ -1040,7 +1029,7 @@ function G.UIDEF.view_deck(unplayed_only) definition = G.GAME.selected_back:generate_UI(nil, 0.7, 0.5, G.GAME.challenge), config = {offset = { x = 0, y = 0 } } } }}}}}}, - {n = G.UIT.R, config = {align = "cm", r = 0.1, outline_colour = G.C.L_BLACK, line_emboss = 0.05, outline = 1.5}, nodes = + {n = G.UIT.R, config = {align = "cm", r = 0.1, outline_colour = G.C.L_BLACK, line_emboss = 0.05, outline = 1.5}, nodes = tally_ui}}}, {n = G.UIT.C, config = {align = "cm"}, nodes = rank_cols}, {n = G.UIT.B, config = {w = 0.1, h = 0.1}},}}, @@ -1252,16 +1241,101 @@ function evaluate_poker_hand(hand) end --#endregion +function Card:set_sprites(_center, _front) + if _front then + local _atlas, _pos = get_front_spriteinfo(_front) + if self.children.front then self.children.front:remove() end + self.children.front = Sprite(self.T.x, self.T.y, self.T.w, self.T.h, _atlas, _pos) + self.children.front.states.hover = self.states.hover + self.children.front.states.click = self.states.click + self.children.front.states.drag = self.states.drag + self.children.front.states.collide.can = false + self.children.front:set_role({major = self, role_type = 'Glued', draw_major = self}) + end + if _center then + if _center.set then + if self.children.center then self.children.center:remove() end + if _center.set == 'Joker' and not _center.unlocked and not self.params.bypass_discovery_center then + self.children.center = Sprite(self.T.x, self.T.y, self.T.w, self.T.h, G.ASSET_ATLAS["Joker"], G.j_locked.pos) + elseif self.config.center.set == 'Voucher' and not self.config.center.unlocked and not self.params.bypass_discovery_center then + self.children.center = Sprite(self.T.x, self.T.y, self.T.w, self.T.h, G.ASSET_ATLAS["Voucher"], G.v_locked.pos) + elseif self.config.center.consumeable and self.config.center.demo then + self.children.center = Sprite(self.T.x, self.T.y, self.T.w, self.T.h, G.ASSET_ATLAS["Tarot"], G.c_locked.pos) + elseif not self.params.bypass_discovery_center and (_center.set == 'Edition' or _center.set == 'Joker' or _center.consumeable or _center.set == 'Voucher' or _center.set == 'Booster') and not _center.discovered then + local atlas = G.ASSET_ATLAS[ + (_center.undiscovered and + (_center.undiscovered[G.SETTINGS.colourblind_option and 'hc_atlas' or 'lc_atlas'] or + _center.undiscovered.atlas) + ) or + ( + SMODS.UndiscoveredSprites[_center.set] and + (SMODS.UndiscoveredSprites[_center.set][G.SETTINGS.colourblind_option and 'hc_atlas' or 'lc_atlas'] or + SMODS.UndiscoveredSprites[_center.set].atlas) + ) or + _center.set + ] or G.ASSET_ATLAS["Joker"] + local pos = (_center.undiscovered and _center.undiscovered.pos) or + (SMODS.UndiscoveredSprites[_center.set] and SMODS.UndiscoveredSprites[_center.set].pos) or + 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) + 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 + self.children.center.states.hover = self.states.hover + self.children.center.states.click = self.states.click + self.children.center.states.drag = self.states.drag + self.children.center.states.collide.can = false + self.children.center:set_role({major = self, role_type = 'Glued', draw_major = self}) + if _center.name == 'Half Joker' and (_center.discovered or self.bypass_discovery_center) then + self.children.center.scale.y = self.children.center.scale.y/1.7 + end + if _center.name == 'Photograph' and (_center.discovered or self.bypass_discovery_center) then + self.children.center.scale.y = self.children.center.scale.y/1.2 + end + if _center.name == 'Square Joker' and (_center.discovered or self.bypass_discovery_center) then + self.children.center.scale.y = self.children.center.scale.x + end + if _center.pixel_size and _center.pixel_size.h and (_center.discovered or self.bypass_discovery_center) then + self.children.center.scale.y = self.children.center.scale.y*(_center.pixel_size.h/95) + end + if _center.pixel_size and _center.pixel_size.w and (_center.discovered or self.bypass_discovery_center) then + self.children.center.scale.x = self.children.center.scale.x*(_center.pixel_size.w/71) + end + end + + if _center.soul_pos then + if self.children.floating_sprite then self.children.floating_sprite:remove() end + self.children.floating_sprite = 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.soul_pos) + self.children.floating_sprite.role.draw_major = self + self.children.floating_sprite.states.hover.can = false + self.children.floating_sprite.states.click.can = false + end + + if self.children.back then self.children.back:remove() end + self.children.back = Sprite(self.T.x, self.T.y, self.T.w, self.T.h, G.ASSET_ATLAS[(G.GAME.viewed_back or G.GAME.selected_back) and ((G.GAME.viewed_back or G.GAME.selected_back)[G.SETTINGS.colourblind_option and 'hc_atlas' or 'lc_atlas'] or (G.GAME.viewed_back or G.GAME.selected_back).atlas) or 'centers'], self.params.bypass_back or (self.playing_card and G.GAME[self.back].pos or G.P_CENTERS['b_red'].pos)) + self.children.back.states.hover = self.states.hover + self.children.back.states.click = self.states.click + self.children.back.states.drag = self.states.drag + self.children.back.states.collide.can = false + self.children.back:set_role({major = self, role_type = 'Glued', draw_major = self}) + if _center.set_sprites and type(_center.set_sprites) == 'function' then + _center:set_sprites(self, _front) + end + end +end + -- Init custom card parameters. local card_init = Card.init function Card:init(X, Y, W, H, card, center, params) card_init(self, X, Y, W, H, card, center, params) - -- This table contains object keys for layers (e.g. edition) + -- This table contains object keys for layers (e.g. edition) -- that dont want base layer to be drawn. -- When layer is removed, layer's value should be set to nil. self.ignore_base_shader = self.ignore_base_shader or {} - -- This table contains object keys for layers (e.g. edition) + -- This table contains object keys for layers (e.g. edition) -- that dont want shadow to be drawn. -- When layer is removed, layer's value should be set to nil. self.ignore_shadow = self.ignore_shadow or {} @@ -1276,7 +1350,7 @@ function Card:should_draw_shadow() end local smods_card_load = Card.load --- +-- function Card:load(cardTable, other_card) local ret = smods_card_load(self, cardTable, other_card) local on_edition_loaded = self.edition and self.edition.key and G.P_CENTERS[self.edition.key].on_load @@ -1303,6 +1377,9 @@ function Card:set_edition(edition, immediate, silent) elseif self.ability.set == 'Joker' and self.area == G.jokers then G.jokers.config.card_limit = G.jokers.config.card_limit - self.edition.card_limit elseif self.area == G.hand then + if G.hand.config.real_card_limit then + G.hand.config.real_card_limit = G.hand.config.real_card_limit - self.edition.card_limit + end G.hand.config.card_limit = G.hand.config.card_limit - self.edition.card_limit end end @@ -1369,7 +1446,7 @@ function Card:set_edition(edition, immediate, silent) if p_edition.no_shadow or p_edition.disable_shadow then self.ignore_shadow[self.edition.key] = true end - + local on_edition_applied = p_edition.on_apply if type(on_edition_applied) == "function" then on_edition_applied(self) @@ -1588,7 +1665,7 @@ end function get_deck_win_sticker(_center) if G.PROFILES[G.SETTINGS.profile].deck_usage[_center.key] and - G.PROFILES[G.SETTINGS.profile].deck_usage[_center.key].wins_by_key then + G.PROFILES[G.SETTINGS.profile].deck_usage[_center.key].wins_by_key then local _stake = nil for key, _ in pairs(G.PROFILES[G.SETTINGS.profile].deck_usage[_center.key].wins_by_key) do if (G.P_STAKES[key] and G.P_STAKES[key].stake_level or 0) > (_stake and G.P_STAKES[_stake].stake_level or 0) then @@ -1624,7 +1701,7 @@ end function Card:align_h_popup() local focused_ui = self.children.focused_ui and true or false - local popup_direction = (self.children.buy_button or (self.area and self.area.config.view_deck) or (self.area and self.area.config.type == 'shop')) and 'cl' or + local popup_direction = (self.children.buy_button or (self.area and self.area.config.view_deck) or (self.area and self.area.config.type == 'shop')) and 'cl' or (self.T.y < G.CARD_H*0.8) and 'bm' or 'tm' local sign = 1 @@ -1652,7 +1729,7 @@ function Card:align_h_popup() popup_direction == 'tm' and -0.13 or popup_direction == 'bm' and 0.1 or 0 - }, + }, type = popup_direction, --lr_clamp = true } @@ -1669,7 +1746,7 @@ 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 + if v.in_pool and type(v.in_pool) == 'function' then local res, pool_opts = v:in_pool() pool_opts = pool_opts or {} add = res and (add or pool_opts.override_base_checks) @@ -1678,7 +1755,7 @@ function get_pack(_key, _type) end local poll = pseudorandom(pseudoseed((_key or 'pack_generic')..G.GAME.round_resets.ante))*cume for k, v in ipairs(G.P_CENTER_POOLS['Booster']) do - if temp_in_pool[v.key] then + if temp_in_pool[v.key] then it = it + (v.current_weight or 1) if it >= poll and it - (v.current_weight or 1) <= poll then center = v; break end end @@ -1750,4 +1827,4 @@ G.FUNCS.change_colour_palette = function(args) end end G:save_settings() -end \ No newline at end of file +end diff --git a/Steamodded/src/ui.lua b/smods/src/ui.lua similarity index 94% rename from Steamodded/src/ui.lua rename to smods/src/ui.lua index 0490272..97a726a 100644 --- a/Steamodded/src/ui.lua +++ b/smods/src/ui.lua @@ -224,7 +224,6 @@ function buildModDescTab(mod) table.insert(modNodes, { n = G.UIT.R, config = { - padding = 0, align = "cm", r = 0.1, emboss = 0.1, @@ -277,6 +276,39 @@ function buildModDescTab(mod) custom_ui_func(modNodes) end + if not mod.can_load and not mod.disabled then + local _, _, msg_key, specific_vars = getModtagInfo(mod) + local text = localize { type = 'raw_descriptions', set = 'Other', key = msg_key, vars = specific_vars } + local text_nodes = {} + for _,v in ipairs(text) do + text_nodes[#text_nodes+1] = { + n = G.UIT.R, config = { align = 'cm' }, nodes = { + { n = G.UIT.T, config = { text = v, colour = G.SETTINGS.reduced_motion and G.C.WHITE or SMODS.Gradients.warning_text, scale = 0.35, shadow = true } } + } + } + end + table.insert(modNodes, { n = G.UIT.R, config = { align = "cm" }, nodes = { + { n = G.UIT.B, config = { w = 0.1, h = 0.1 }} + }}) + table.insert(modNodes, { + n = G.UIT.R, config = { align = "cm", r = 0.1, minw = 6, minh = 0.6, colour = G.SETTINGS.reduced_motion and G.C.RED or SMODS.Gradients.warning_bg, padding = 0.1 }, nodes={ + { + n = G.UIT.C, config = { align = 'cm' }, nodes = { + { n = G.UIT.O, config = { object = Sprite(0, 0, 0.8, 0.8, G.ASSET_ATLAS['mod_tags'], { x = 0, y = 0 }) } }, + } + }, + { + n = G.UIT.C, config = { align = 'cm' }, nodes = text_nodes + }, + { + n = G.UIT.C, config = { align = 'cm' }, nodes = { + { n = G.UIT.O, config = { object = Sprite(0, 0, 0.8, 0.8, G.ASSET_ATLAS['mod_tags'], { x = 0, y = 0 }) } }, + } + }, + } + }) + end + return { n = G.UIT.ROOT, config = { @@ -743,7 +775,7 @@ function UIBox_button(args) return button end -function buildModtag(mod) +function getModtagInfo(mod) local tag_pos, tag_message, tag_atlas = { x = 0, y = 0 }, "load_success", mod.prefix and mod.prefix .. '_modicon' or 'modicon' local specific_vars = {} @@ -783,7 +815,11 @@ function buildModtag(mod) tag_message = 'load_disabled' end end + return tag_atlas, tag_pos, tag_message, specific_vars +end +function buildModtag(mod) + local tag_atlas, tag_pos, tag_message, specific_vars = getModtagInfo(mod) local tag_sprite_tab = nil @@ -846,9 +882,12 @@ local function createClickableModBox(modInfo, scale) col = G.C.BOOSTER elseif modInfo.disabled then col = G.C.UI.BACKGROUND_INACTIVE - else + elseif G.SETTINGS.reduced_motion then col = mix_colours(G.C.RED, G.C.UI.BACKGROUND_INACTIVE, 0.7) text_col = G.C.TEXT_DARK + else + col = SMODS.Gradients.warning_bg + text_col = SMODS.Gradients.warning_text end local label = { " " .. modInfo.name .. " " } if modInfo.lovely_only then @@ -866,9 +905,11 @@ local function createClickableModBox(modInfo, scale) minh = 0.8, minw = 7 } + local version_col = copy_table(G.C.WHITE) + version_col[4] = 0.6 if modInfo.lovely_only then local config = but.nodes[1].nodes[2].nodes[1].config - config.colour = mix_colours(invert(col), G.C.UI.TEXT_INACTIVE, 0.8) + config.colour = version_col config.scale = scale * .8 end if modInfo.version and modInfo.version ~= '0.0.0' then @@ -877,7 +918,7 @@ local function createClickableModBox(modInfo, scale) config = { text = ('(%s) '):format(modInfo.version), scale = scale*0.8, - colour = mix_colours(invert(col), G.C.UI.TEXT_INACTIVE, 0.8), + colour = version_col, shadow = true, }, }) @@ -1295,7 +1336,8 @@ function create_UIBox_main_menu_buttons() minw = 1.85, col = true, button = "mods_button", - colour = G.C.BOOSTER, + colour = SMODS.mod_button_alert and (G.SETTINGS.reduced_motion and G.C.RED or SMODS.Gradients.warning_bg) or G.C.BOOSTER, + text_colour = (SMODS.mod_button_alert and not G.SETTINGS.reduced_motion) and SMODS.Gradients.warning_text or G.C.TEXT_LIGHT, label = {localize('b_mods_cap')}, scale = 0.45 * 1.2 }) @@ -1338,7 +1380,7 @@ function G.FUNCS.update_mod_list(args) end -- Same as Balatro base game code, but accepts a value to match against (rather than the index in the option list) --- e.g. create_option_cycle({ current_option = 1 }) vs. SMODS.GUID.createOptionSelector({ current_option = "Page 1/2" }) +-- e.g. create_option_cycle({ current_option = 1 }) vs. SMODS.GUI.createOptionSelector({ current_option = "Page 1/2" }) function SMODS.GUI.createOptionSelector(args) args = args or {} args.colour = args.colour or G.C.RED @@ -1818,4 +1860,46 @@ create_UIBox_your_collection_stickers = function() center:apply(card, true) end, }) +end + +-- warning for updating during run +local igo = Game.init_game_object +function Game:init_game_object() + local t = igo(self) + t.smods_version = SMODS.version + return t +end + +local gurso = G.UIDEF.run_setup_option +function G.UIDEF.run_setup_option(_type) + local ret = gurso(_type) + if _type == 'Continue' and V(G.SAVED_GAME.GAME.smods_version or '0.0.0') ~= V(SMODS.version) then + local text = localize { type = 'variable', key = 'smods_version_mismatch', vars = {G.SAVED_GAME.GAME.smods_version or '(unknown)', SMODS.version}} + local text_nodes = {} + for _,v in ipairs(text) do + text_nodes[#text_nodes+1] = { + n = G.UIT.R, config = { align = 'cm' }, nodes = { + { n = G.UIT.T, config = { text = v, colour = G.SETTINGS.reduced_motion and G.C.WHITE or SMODS.Gradients.warning_text, scale = 0.35, shadow = true } } + } + } + end + table.insert(ret.nodes[1].nodes, 1, { + n = G.UIT.R, config = { align = "cm", r = 0.1, minw = 6, minh = 0.6, colour = G.SETTINGS.reduced_motion and G.C.RED or SMODS.Gradients.warning_bg, padding = 0.1 }, nodes={ + { + n = G.UIT.C, config = { align = 'cm' }, nodes = { + { n = G.UIT.O, config = { object = Sprite(0, 0, 0.8, 0.8, G.ASSET_ATLAS['mod_tags'], { x = 0, y = 0 }) } }, + } + }, + { + n = G.UIT.C, config = { align = 'cm' }, nodes = text_nodes + }, + { + n = G.UIT.C, config = { align = 'cm' }, nodes = { + { n = G.UIT.O, config = { object = Sprite(0, 0, 0.8, 0.8, G.ASSET_ATLAS['mod_tags'], { x = 0, y = 0 }) } }, + } + }, + } + }) + end + return ret end diff --git a/Steamodded/src/utils.lua b/smods/src/utils.lua similarity index 83% rename from Steamodded/src/utils.lua rename to smods/src/utils.lua index 4868452..5a7c68c 100644 --- a/Steamodded/src/utils.lua +++ b/smods/src/utils.lua @@ -1,46 +1,46 @@ --- STEAMODDED CORE --- UTILITY FUNCTIONS function inspect(table) - if type(table) ~= 'table' then - return "Not a table" - end + if type(table) ~= 'table' then + return "Not a table" + end - local str = "" - for k, v in pairs(table) do - local valueStr = type(v) == "table" and "table" or tostring(v) - str = str .. tostring(k) .. ": " .. valueStr .. "\n" - end + local str = "" + for k, v in pairs(table) do + local valueStr = type(v) == "table" and "table" or tostring(v) + str = str .. tostring(k) .. ": " .. valueStr .. "\n" + end - return str + return str end function inspectDepth(table, indent, depth) - if depth and depth > 5 then -- Limit the depth to avoid deep nesting - return "Depth limit reached" - end + if depth and depth > 5 then -- Limit the depth to avoid deep nesting + return "Depth limit reached" + end - if type(table) ~= 'table' then -- Ensure the object is a table - return "Not a table" - end + if type(table) ~= 'table' then -- Ensure the object is a table + return "Not a table" + end - local str = "" - if not indent then indent = 0 end + local str = "" + if not indent then indent = 0 end - for k, v in pairs(table) do - local formatting = string.rep(" ", indent) .. tostring(k) .. ": " - if type(v) == "table" then - str = str .. formatting .. "\n" - str = str .. inspectDepth(v, indent + 1, (depth or 0) + 1) - elseif type(v) == 'function' then - str = str .. formatting .. "function\n" - elseif type(v) == 'boolean' then - str = str .. formatting .. tostring(v) .. "\n" - else - str = str .. formatting .. tostring(v) .. "\n" - end - end + for k, v in pairs(table) do + local formatting = string.rep(" ", indent) .. tostring(k) .. ": " + if type(v) == "table" then + str = str .. formatting .. "\n" + str = str .. inspectDepth(v, indent + 1, (depth or 0) + 1) + elseif type(v) == 'function' then + str = str .. formatting .. "function\n" + elseif type(v) == 'boolean' then + str = str .. formatting .. tostring(v) .. "\n" + else + str = str .. formatting .. tostring(v) .. "\n" + end + end - return str + return str end function inspectFunction(func) @@ -74,7 +74,7 @@ end function SMODS.SAVE_UNLOCKS() boot_print_stage("Saving Unlocks") - G:save_progress() + G:save_progress() ------------------------------------- local TESTHELPER_unlocks = false and not _RELEASE_MODE ------------------------------------- @@ -117,30 +117,30 @@ function SMODS.SAVE_UNLOCKS() end end - table.sort(G.P_LOCKED, function (a, b) return a.order and b.order and a.order < b.order end) + table.sort(G.P_LOCKED, function (a, b) return a.order and b.order and a.order < b.order end) - for k, v in pairs(G.P_BLINDS) do + for k, v in pairs(G.P_BLINDS) do v.key = k - if not v.wip and not v.demo then + if not v.wip and not v.demo then if TESTHELPER_unlocks then v.discovered = true; v.alerted = true end --REMOVE THIS - if not v.discovered and meta.discovered[k] then + if not v.discovered and meta.discovered[k] then v.discovered = true end - if v.discovered and meta.alerted[k] then + if v.discovered and meta.alerted[k] then v.alerted = true elseif v.discovered then v.alerted = false end end end - for k, v in pairs(G.P_TAGS) do + for k, v in pairs(G.P_TAGS) do v.key = k - if not v.wip and not v.demo then + if not v.wip and not v.demo then if TESTHELPER_unlocks then v.discovered = true; v.alerted = true end --REMOVE THIS - if not v.discovered and meta.discovered[k] then + if not v.discovered and meta.discovered[k] then v.discovered = true end - if v.discovered and meta.alerted[k] then + if v.discovered and meta.alerted[k] then v.alerted = true elseif v.discovered then v.alerted = false @@ -183,12 +183,12 @@ function SMODS.process_loc_text(ref_table, ref_value, loc_txt, key) ref_table[ref_value] = target end -local function parse_loc_file(file_name, force) +local function parse_loc_file(file_name, force, mod_id) local loc_table = nil if file_name:lower():match("%.json$") then loc_table = assert(JSON.decode(NFS.read(file_name))) else - loc_table = assert(loadstring(NFS.read(file_name)))() + loc_table = assert(loadstring(NFS.read(file_name), ('=[SMODS %s "%s"]'):format(mod_id, string.match(file_name, '[^/]+/[^/]+$'))))() end local function recurse(target, ref_table) if type(target) ~= 'table' then return end --this shouldn't happen unless there's a bad return value @@ -204,41 +204,41 @@ local function parse_loc_file(file_name, force) end end end - recurse(loc_table, G.localization) + recurse(loc_table, G.localization) end -local function handle_loc_file(dir, language, force) +local function handle_loc_file(dir, language, force, mod_id) for k, v in ipairs({ dir .. language .. '.lua', dir .. language .. '.json' }) do if NFS.getInfo(v) then - parse_loc_file(v, force) + parse_loc_file(v, force, mod_id) break end end end -function SMODS.handle_loc_file(path) +function SMODS.handle_loc_file(path, mod_id) local dir = path .. 'localization/' - handle_loc_file(dir, 'en-us', true) - handle_loc_file(dir, 'default', true) - handle_loc_file(dir, G.SETTINGS.language, true) - if G.SETTINGS.real_language then handle_loc_file(dir, G.SETTINGS.real_language, true) end + handle_loc_file(dir, 'en-us', true, mod_id) + handle_loc_file(dir, 'default', true, mod_id) + handle_loc_file(dir, G.SETTINGS.language, true, mod_id) + if G.SETTINGS.real_language then handle_loc_file(dir, G.SETTINGS.real_language, true, mod_id) end end function SMODS.insert_pool(pool, center, replace) - if replace == nil then replace = center.taken_ownership end - if replace then - for k, v in ipairs(pool) do + if replace == nil then replace = center.taken_ownership end + if replace then + for k, v in ipairs(pool) do if v.key == center.key then pool[k] = center + return end - end - else - local prev_order = (pool[#pool] and pool[#pool].order) or 0 - if prev_order ~= nil then - center.order = prev_order + 1 - end - table.insert(pool, center) - end + end + end + local prev_order = (pool[#pool] and pool[#pool].order) or 0 + if prev_order ~= nil then + center.order = prev_order + 1 + end + table.insert(pool, center) end function SMODS.remove_pool(pool, key) @@ -257,7 +257,7 @@ function SMODS.juice_up_blind() G.GAME.blind:juice_up() end --- @deprecated +---@deprecated function SMODS.eval_this(_card, effects) sendWarnMessage('SMODS.eval_this is deprecated. All calculation stages now support returning effects directly. Effects evaluated using this function are out of order and may not use the correct sound pitch.', 'Util') if effects then @@ -282,12 +282,11 @@ end -- Change a card's suit, rank, or both. -- Accepts keys for both objects instead of needing to build a card key yourself. function SMODS.change_base(card, suit, rank) - if not card then return false end + if not card then return nil, "SMODS.change_base called with no card" end local _suit = SMODS.Suits[suit or card.base.suit] local _rank = SMODS.Ranks[rank or card.base.value] if not _suit or not _rank then - sendWarnMessage(('Tried to call SMODS.change_base with invalid arguments: suit="%s", rank="%s"'):format(suit, rank), 'Util') - return false + return nil, ('Tried to call SMODS.change_base with invalid arguments: suit="%s", rank="%s"'):format(suit, rank) end card:set_base(G.P_CARDS[('%s_%s'):format(_suit.card_key, _rank.card_key)]) return card @@ -317,16 +316,16 @@ function SMODS.create_card(t) if not t.area and not t.key and t.set and SMODS.ConsumableTypes[t.set] then t.area = G.consumeables end - SMODS.bypass_create_card_edition = t.no_edition + SMODS.bypass_create_card_edition = t.no_edition or t.edition local _card = create_card(t.set, t.area, t.legendary, t.rarity, t.skip_materialize, t.soulable, t.key, t.key_append) SMODS.bypass_create_card_edition = nil -- Should this be restricted to only cards able to handle these - -- or should that be left to the person calling SMODS.create_card to use it correctly? + -- or should that be left to the person calling SMODS.create_card to use it correctly? if t.edition then _card:set_edition(t.edition) end if t.enhancement then _card:set_ability(G.P_CENTERS[t.enhancement]) end if t.seal then _card:set_seal(t.seal) end - if t.stickers then + if t.stickers then for i, v in ipairs(t.stickers) do local s = SMODS.Stickers[v] if not s or type(s.should_apply) ~= 'function' or s:should_apply(_card, t.area, true) then @@ -453,8 +452,8 @@ function SMODS.create_loc_dump() end cleanup(_dump) local str = 'return ' .. serialize(_dump) - NFS.createDirectory(SMODS.dump_loc.path..'localization/') - NFS.write(SMODS.dump_loc.path..'localization/dump.lua', str) + NFS.createDirectory(SMODS.dump_loc.path..'localization/') + NFS.write(SMODS.dump_loc.path..'localization/dump.lua', str) end -- Serializes an input table in valid Lua syntax @@ -463,9 +462,9 @@ end function serialize(t, indent) indent = indent or '' local str = '{\n' - for k, v in ipairs(t) do + for k, v in ipairs(t) do str = str .. indent .. '\t' - if type(v) == 'number' then + if type(v) == 'number' then str = str .. v elseif type(v) == 'boolean' then str = str .. (v and 'true' or 'false') @@ -477,33 +476,33 @@ function serialize(t, indent) -- not serializable str = str .. 'nil' end - str = str .. ',\n' - end + str = str .. ',\n' + end for k, v in pairs(t) do - if type(k) == 'string' then - str = str .. indent .. '\t' .. '[' .. serialize_string(k) .. '] = ' - - if type(v) == 'number' then - str = str .. v + if type(k) == 'string' then + str = str .. indent .. '\t' .. '[' .. serialize_string(k) .. '] = ' + + if type(v) == 'number' then + str = str .. v elseif type(v) == 'boolean' then str = str .. (v and 'true' or 'false') - elseif type(v) == 'string' then - str = str .. serialize_string(v) - elseif type(v) == 'table' then - str = str .. serialize(v, indent .. '\t') - else - -- not serializable + elseif type(v) == 'string' then + str = str .. serialize_string(v) + elseif type(v) == 'table' then + str = str .. serialize(v, indent .. '\t') + else + -- not serializable str = str .. 'nil' - end - str = str .. ',\n' - end + end + str = str .. ',\n' + end end str = str .. indent .. '}' - return str + return str end function serialize_string(s) - return string.format("%q", s) + return string.format("%q", s) end -- Starting with `t`, insert any key-value pairs from `defaults` that don't already @@ -610,9 +609,9 @@ end --#region Number formatting function round_number(num, precision) - precision = 10^(precision or 0) - - return math.floor(num * precision + 0.4999999999999994) / precision + precision = 10^(precision or 0) + + return math.floor(num * precision + 0.4999999999999994) / precision end -- Formatting util for UI elements (look number_formatting.toml) @@ -653,7 +652,7 @@ function SMODS.poll_seal(args) total_weight = total_weight + seal_option.weight end end - end + end total_weight = total_weight + (total_weight / 2 * 98) -- set base rate to 2% local type_weight = 0 -- modified weight total @@ -661,7 +660,7 @@ function SMODS.poll_seal(args) v.weight = G.P_SEALS[v.key].get_weight and G.P_SEALS[v.key]:get_weight() or v.weight type_weight = type_weight + v.weight end - + local seal_poll = pseudorandom(pseudoseed(key or 'stdseal'..G.GAME.round_resets.ante)) if seal_poll > 1 - (type_weight*mod / total_weight) or guaranteed then -- is a seal generated local seal_type_poll = pseudorandom(pseudoseed(type_key)) -- which seal is generated @@ -687,7 +686,7 @@ function SMODS.get_blind_amount(ante) 10000 + 25000*(scale+1)*((scale/4)^2), 50000 * (scale+1)^2 * (scale/7)^2 } - + if ante < 1 then return 100 end if ante <= 8 then return amounts[ante] - amounts[ante]%(10^math.floor(math.log10(amounts[ante])-1)) end local a, b, c, d = amounts[8], amounts[8]/amounts[7], ante-8, 1 + 0.2*(ante-8) @@ -734,15 +733,15 @@ end function SMODS.poll_rarity(_pool_key, _rand_key) - local rarity_poll = pseudorandom(pseudoseed(_rand_key or ('rarity'..G.GAME.round_resets.ante))) -- Generate the poll value - local available_rarities = copy_table(SMODS.ObjectTypes[_pool_key].rarities) -- Table containing a list of rarities and their rates + local rarity_poll = pseudorandom(pseudoseed(_rand_key or ('rarity'..G.GAME.round_resets.ante))) -- Generate the poll value + local available_rarities = copy_table(SMODS.ObjectTypes[_pool_key].rarities) -- Table containing a list of rarities and their rates local vanilla_rarities = {["Common"] = 1, ["Uncommon"] = 2, ["Rare"] = 3, ["Legendary"] = 4} - + -- Calculate total rates of rarities local total_weight = 0 for _, v in ipairs(available_rarities) do v.mod = G.GAME[tostring(v.key):lower().."_mod"] or 1 - -- Should this fully override the v.weight calcs? + -- Should this fully override the v.weight calcs? if SMODS.Rarities[v.key] and SMODS.Rarities[v.key].get_weight and type(SMODS.Rarities[v.key].get_weight) == "function" then v.weight = SMODS.Rarities[v.key]:get_weight(v.weight, SMODS.ObjectTypes[_pool_key]) end @@ -754,19 +753,19 @@ function SMODS.poll_rarity(_pool_key, _rand_key) v.weight = v.weight / total_weight end - -- Calculate selected rarity - local weight_i = 0 - for _, v in ipairs(available_rarities) do - weight_i = weight_i + v.weight - if rarity_poll < weight_i then - if vanilla_rarities[v.key] then + -- Calculate selected rarity + local weight_i = 0 + for _, v in ipairs(available_rarities) do + weight_i = weight_i + v.weight + if rarity_poll < weight_i then + if vanilla_rarities[v.key] then return vanilla_rarities[v.key] else - return v.key + return v.key end - end - end - return nil + end + end + return nil end function SMODS.poll_enhancement(args) @@ -802,7 +801,7 @@ function SMODS.poll_enhancement(args) total_weight = total_weight + enhance_option.weight end end - end + end total_weight = total_weight + (total_weight / 40 * 60) -- set base rate to 40% local type_weight = 0 -- modified weight total @@ -810,7 +809,7 @@ function SMODS.poll_enhancement(args) v.weight = G.P_CENTERS[v.key].get_weight and G.P_CENTERS[v.key]:get_weight() or v.weight type_weight = type_weight + v.weight end - + local enhance_poll = pseudorandom(pseudoseed(key)) if enhance_poll > 1 - (type_weight*mod / total_weight) or guaranteed then -- is an enhancement selected local seal_type_poll = pseudorandom(pseudoseed(type_key)) -- which enhancement is selected @@ -856,8 +855,14 @@ function Card:calculate_sticker(context, key) end end +function Card:can_calculate(ignore_debuff) + local is_available = (not self.debuff or ignore_debuff) and not self.getting_sliced + -- TARGET : Add extra conditions here + return is_available +end + function Card:calculate_enhancement(context) - if self.debuff or self.ability.set ~= 'Enhanced' then return nil end + if not self:can_calculate() or self.ability.set ~= 'Enhanced' then return nil end local center = self.config.center if center.calculate and type(center.calculate) == 'function' then local o = center:calculate(self, context) @@ -1073,7 +1078,7 @@ G.FUNCS.update_collab_cards = function(key, suit, silent) local card = Card(G.cdds_cards.T.x+G.cdds_cards.T.w/2, G.cdds_cards.T.y+G.cdds_cards.T.h/2, G.CARD_W*1.2, G.CARD_H*1.2, G.P_CARDS[card_code], G.P_CENTERS.c_base) -- Instead of no ui it would be nice to pass info queue to this so that artist credits can be done? card.no_ui = true - + G.cdds_cards:emplace(card) end end @@ -1097,7 +1102,7 @@ end -- Can easily be hooked to add more calculation effects ala Talisman SMODS.calculate_individual_effect = function(effect, scored_card, key, amount, from_edition) if effect.card and effect.card ~= scored_card then juice_card(effect.card) end - if (key == 'chips' or key == 'h_chips' or key == 'chip_mod') and amount then + if (key == 'chips' or key == 'h_chips' or key == 'chip_mod') and amount then hand_chips = mod_chips(hand_chips + amount) update_hand_text({delay = 0}, {chips = hand_chips, mult = mult}) if not effect.remove_default_message then @@ -1116,14 +1121,14 @@ SMODS.calculate_individual_effect = function(effect, scored_card, key, amount, f return true end - if (key == 'mult' or key == 'h_mult' or key == 'mult_mod') and amount then + if (key == 'mult' or key == 'h_mult' or key == 'mult_mod') and amount then mult = mod_mult(mult + amount) update_hand_text({delay = 0}, {chips = hand_chips, mult = mult}) if not effect.remove_default_message then if from_edition then card_eval_status_text(scored_card, 'jokers', nil, percent, nil, {message = localize{type = 'variable', key = amount > 0 and 'a_mult' or 'a_mult_minus', vars = {amount}}, mult_mod = amount, colour = G.C.DARK_EDITION, edition = true}) else - if key ~= 'mult_mod' then + if key ~= 'mult_mod' then if effect.mult_message then card_eval_status_text(scored_card or effect.card or effect.focus, 'extra', nil, percent, nil, effect.mult_message) else @@ -1134,8 +1139,8 @@ SMODS.calculate_individual_effect = function(effect, scored_card, key, amount, f end return true end - - if (key == 'p_dollars' or key == 'dollars' or key == 'h_dollars') and amount then + + if (key == 'p_dollars' or key == 'dollars' or key == 'h_dollars') and amount then ease_dollars(amount) if not effect.remove_default_message then if effect.dollar_message then @@ -1147,7 +1152,7 @@ SMODS.calculate_individual_effect = function(effect, scored_card, key, amount, f return true end - if (key == 'x_chips' or key == 'xchips' or key == 'Xchip_mod') and amount ~= 1 then + if (key == 'x_chips' or key == 'xchips' or key == 'Xchip_mod') and amount ~= 1 then hand_chips = mod_chips(hand_chips * amount) update_hand_text({delay = 0}, {chips = hand_chips, mult = mult}) if not effect.remove_default_message then @@ -1165,8 +1170,8 @@ SMODS.calculate_individual_effect = function(effect, scored_card, key, amount, f end return true end - - if (key == 'x_mult' or key == 'xmult' or key == 'Xmult' or key == 'x_mult_mod' or key == 'Xmult_mod') and amount ~= 1 then + + if (key == 'x_mult' or key == 'xmult' or key == 'Xmult' or key == 'x_mult_mod' or key == 'Xmult_mod') and amount ~= 1 then mult = mod_mult(mult * amount) update_hand_text({delay = 0}, {chips = hand_chips, mult = mult}) if not effect.remove_default_message then @@ -1195,7 +1200,7 @@ SMODS.calculate_individual_effect = function(effect, scored_card, key, amount, f return true end - if key == 'swap' then + if key == 'swap' then local old_mult = mult mult = mod_mult(hand_chips) hand_chips = mod_chips(old_mult) @@ -1204,17 +1209,7 @@ SMODS.calculate_individual_effect = function(effect, scored_card, key, amount, f end if key == 'level_up' then - local old_text = {} - G.E_MANAGER:add_event(Event({ - trigger = 'immediate', - func = function() - old_text = copy_table(G.GAME.current_round.current_hand) - update_hand_text({sound = 'button', volume = 0.7, pitch = 1.1, delay = 0}, {mult = old_text.mult, chips = old_text.chips, handname = old_text.handname, level = old_text.handname ~= "" and G.GAME.hands[G.GAME.last_hand_played].level or ''}) - return true - end - })) local hand_type = effect.level_up_hand or G.GAME.last_hand_played - update_hand_text({sound = 'button', volume = 0.7, pitch = 0.8, delay = 0.3}, {handname=localize(hand_type, 'poker_hands'),chips = G.GAME.hands[hand_type].chips, mult = G.GAME.hands[hand_type].mult, level=G.GAME.hands[hand_type].level}) level_up_hand(scored_card, hand_type, effect.instant, type(amount) == 'number' and amount or 1) return true end @@ -1329,6 +1324,7 @@ SMODS.calculate_retriggers = function(card, context, _ret) if value.repetitions then for h=1, value.repetitions do value.retrigger_card = _card + value.message_card = value.message_card or _card value.message = value.message or (not value.remove_default_message and localize('k_again_ex')) retriggers[#retriggers + 1] = value end @@ -1336,17 +1332,24 @@ SMODS.calculate_retriggers = function(card, context, _ret) end end end + local deck_effect = G.GAME.selected_back:trigger_effect({retrigger_joker_check = true, other_card = card, other_context = context, other_ret = _ret}) + if deck_effect and deck_effect.repetitions then + deck_effect.retrigger_card = G.GAME.selected_back + deck_effect.message_card = deck_effect.message_card or G.deck.cards[1] or G.deck + deck_effect.message = deck_effect.message or (not deck_effect.remove_default_message and localize('k_again_ex')) + retriggers[#retriggers + 1] = deck_effect + end return retriggers end function Card:calculate_edition(context) - if self.debuff then return end + if not self:can_calculate() then return end if self.edition then local edition = G.P_CENTERS[self.edition.key] if edition.calculate and type(edition.calculate) == 'function' then local o = edition:calculate(self, context) if o then - if not o.card then o.card = self end + if not o.card then o.card = self end return o end end @@ -1382,7 +1385,7 @@ function SMODS.calculate_context(context, return_table) context.retrigger_joker = false end if return_table then - for _,v in ipairs(effects) do + for _,v in ipairs(effects) do if v.jokers and not v.jokers.card then v.jokers.card = _card end return_table[#return_table+1] = v end @@ -1393,42 +1396,24 @@ function SMODS.calculate_context(context, return_table) end context.main_eval = nil if context.scoring_hand then - context.cardarea = G.play - for i=1, #context.scoring_hand do + for i=1, #G.play.cards do + if SMODS.in_scoring(G.play.cards[i], context.scoring_hand) then context.cardarea = G.play else context.cardarea = 'unscored' end --calculate the played card effects - if return_table then - return_table[#return_table+1] = eval_card(context.scoring_hand[i], context) - SMODS.calculate_quantum_enhancements(context.scoring_hand[i], return_table, context) + if return_table then + return_table[#return_table+1] = eval_card(G.play.cards[i], context) + SMODS.calculate_quantum_enhancements(G.play.cards[i], return_table, context) else - local effects = {eval_card(context.scoring_hand[i], context)} - SMODS.calculate_quantum_enhancements(context.scoring_hand[i], effects, context) - SMODS.trigger_effects(effects, context.scoring_hand[i]) - end - end - if SMODS.optional_features.cardareas.unscored then - context.cardarea = 'unscored' - local unscored_cards = {} - for _, played_card in pairs(G.play.cards) do - if not SMODS.in_scoring(played_card, context.scoring_hand) then unscored_cards[#unscored_cards + 1] = played_card end - end - for i=1, #unscored_cards do - --calculate the played card effects - if return_table then - return_table[#return_table+1] = eval_card(unscored_cards[i], context) - SMODS.calculate_quantum_enhancements(unscored_cards[i], return_table, context) - else - local effects = {eval_card(unscored_cards[i], context)} - SMODS.calculate_quantum_enhancements(unscored_cards[i], effects, context) - SMODS.trigger_effects(effects, unscored_cards[i]) - end + local effects = {eval_card(G.play.cards[i], context)} + SMODS.calculate_quantum_enhancements(G.play.cards[i], effects, context) + SMODS.trigger_effects(effects, G.play.cards[i]) end end end context.cardarea = G.hand for i=1, #G.hand.cards do --calculate the held card effects - if return_table then - return_table[#return_table+1] = eval_card(G.hand.cards[i], context) + if return_table then + return_table[#return_table+1] = eval_card(G.hand.cards[i], context) else local effects = {eval_card(G.hand.cards[i], context)} SMODS.calculate_quantum_enhancements(G.hand.cards[i], effects, context) @@ -1439,8 +1424,8 @@ function SMODS.calculate_context(context, return_table) context.cardarea = G.deck for i=1, #G.deck.cards do --calculate the held card effects - if return_table then - return_table[#return_table+1] = eval_card(G.deck.cards[i], context) + if return_table then + return_table[#return_table+1] = eval_card(G.deck.cards[i], context) else local effects = {eval_card(G.deck.cards[i], context)} SMODS.calculate_quantum_enhancements(G.deck.cards[i], effects, context) @@ -1452,8 +1437,8 @@ function SMODS.calculate_context(context, return_table) context.cardarea = G.discard for i=1, #G.discard.cards do --calculate the held card effects - if return_table then - return_table[#return_table+1] = eval_card(G.discard.cards[i], context) + if return_table then + return_table[#return_table+1] = eval_card(G.discard.cards[i], context) else local effects = {eval_card(G.discard.cards[i], context)} SMODS.calculate_quantum_enhancements(G.discard.cards[i], effects, context) @@ -1494,13 +1479,21 @@ function SMODS.score_card(card, context) --calculate the joker individual card effects local eval, post = eval_card(_card, context) if next(eval) then - if eval.jokers then eval.jokers.juice_card = eval.jokers.juice_card or eval.jokers.card or _card end + if eval.jokers then + eval.jokers.juice_card = eval.jokers.juice_card or eval.jokers.card or _card + eval.jokers.message_card = eval.jokers.message_card or eval.jokers.card or card + end + table.insert(effects, eval) for _, v in ipairs(post) do effects[#effects+1] = v end if eval.retriggers then - context.retrigger_joker = true + context.retrigger_joker = eval.retriggers.retrigger_card for rt = 1, #eval.retriggers do local rt_eval, rt_post = eval_card(_card, context) + if rt_eval.jokers then + rt_eval.jokers.juice_card = rt_eval.jokers.juice_card or rt_eval.jokers.card or _card + rt_eval.jokers.message_card = rt_eval.jokers.message_card or rt_eval.jokers.card or card + end table.insert(effects, { eval.retriggers[rt] }) table.insert(effects, rt_eval) for _, v in ipairs(rt_post) do effects[#effects+1] = v end @@ -1532,9 +1525,9 @@ function SMODS.score_card(card, context) end function SMODS.calculate_main_scoring(context, scoring_hand) - for _, card in ipairs(scoring_hand or context.cardarea.cards) do + for _, card in ipairs(context.cardarea.cards) do --add cards played to list - if scoring_hand and not SMODS.has_no_rank(card) then + if scoring_hand and not SMODS.has_no_rank(card) and SMODS.in_scoring(card, context.scoring_hand) then G.GAME.cards_played[card.base.value].total = G.GAME.cards_played[card.base.value].total + 1 if not SMODS.has_no_suit(card) then G.GAME.cards_played[card.base.value].suits[card.base.suit] = true @@ -1549,6 +1542,9 @@ function SMODS.calculate_main_scoring(context, scoring_hand) })) card_eval_status_text(card, 'debuff') else + if scoring_hand then + if SMODS.in_scoring(card, context.scoring_hand) then context.cardarea = G.play else context.cardarea = 'unscored' end + end SMODS.score_card(card, context) end end @@ -1583,7 +1579,7 @@ function SMODS.calculate_end_of_round_effects(context) card.ability = old_ability card.config.center = old_center card.config.center_key = old_center_key - card:set_sprites(old_center) + card:set_sprites(old_center) context.playing_card_end_of_round = nil context.individual = true @@ -1591,10 +1587,10 @@ function SMODS.calculate_end_of_round_effects(context) -- context.end_of_round individual calculations for _, area in ipairs(SMODS.get_card_areas('jokers')) do for _, _card in ipairs(area.cards) do - + local eval, post = eval_card(_card, context) eval.juice_card = eval.card - if next(eval) then + if next(eval) then table.insert(effects, eval) end for _, v in ipairs(post) do effects[#effects+1] = v end @@ -1608,28 +1604,36 @@ function SMODS.calculate_end_of_round_effects(context) context.individual = nil context.repetition = true context.card_effects = effects - if reps[j] == 1 then + if reps[j] == 1 then SMODS.calculate_repetitions(card, context, reps) end - + context.repetition = nil context.card_effects = nil j = j + (effects.calculated and 1 or #reps) - + -- TARGET: effects after end of round evaluation end end end function SMODS.calculate_destroying_cards(context, cards_destroyed, scoring_hand) - for i,card in ipairs(scoring_hand or context.cardarea.cards) do + for i,card in ipairs(context.cardarea.cards) do local destroyed = nil --un-highlight all cards - if scoring_hand then highlight_card(card,(i-0.999)/(#scoring_hand-0.998),'down') end + if scoring_hand and SMODS.in_scoring(card, context.scoring_hand) then highlight_card(card,(i-0.999)/(#scoring_hand-0.998),'down') end -- context.destroying_card calculations context.destroy_card = card - context.destroying_card = scoring_hand and card + if scoring_hand then + if SMODS.in_scoring(card, context.scoring_hand) then + context.cardarea = G.play + context.destroying_card = card + else + context.cardarea = 'unscored' + context.destroying_card = nil + end + end for _, area in ipairs(SMODS.get_card_areas('jokers')) do local should_break for _, _card in ipairs(area.cards) do @@ -1643,7 +1647,7 @@ function SMODS.calculate_destroying_cards(context, cards_destroyed, scoring_hand end end SMODS.trigger_effects({post}, card) - if self_destroy then + if self_destroy then destroyed = true should_break = true break @@ -1651,11 +1655,11 @@ function SMODS.calculate_destroying_cards(context, cards_destroyed, scoring_hand end if should_break then break end end - - if scoring_hand and SMODS.has_enhancement(card, 'm_glass') and not card.debuff and pseudorandom('glass') < G.GAME.probabilities.normal/(card.ability.name == 'Glass Card' and card.ability.extra or G.P_CENTERS.m_glass.config.extra) then + + if scoring_hand and SMODS.has_enhancement(card, 'm_glass') and card:can_calculate() and pseudorandom('glass') < G.GAME.probabilities.normal/(card.ability.name == 'Glass Card' and card.ability.extra or G.P_CENTERS.m_glass.config.extra) then destroyed = true end - + local eval, post = eval_card(card, context) local self_destroy = false for key, effect in pairs(eval) do @@ -1663,7 +1667,7 @@ function SMODS.calculate_destroying_cards(context, cards_destroyed, scoring_hand end SMODS.trigger_effects({post}, card) if self_destroy then destroyed = true end - + local deck_effect = G.GAME.selected_back:trigger_effect(context) if deck_effect then self_destroy = SMODS.calculate_effect(deck_effect, G.deck.cards[1] or G.deck) @@ -1672,22 +1676,37 @@ function SMODS.calculate_destroying_cards(context, cards_destroyed, scoring_hand -- TARGET: card destroyed - if destroyed then + if destroyed then if SMODS.shatters(card) then card.shattered = true - else + else card.destroyed = true - end + end cards_destroyed[#cards_destroyed+1] = card end end end +function SMODS.blueprint_effect(card, blueprint_card, context) + if card == blueprint_card then return end + context.blueprint = (context.blueprint and (context.blueprint + 1)) or 1 + context.blueprint_card = context.blueprint_card or card + if context.blueprint > #G.jokers.cards + 1 then return end + local other_joker_ret = blueprint_card:calculate_joker(context) + context.blueprint = nil + local eff_card = context.blueprint_card or card + context.blueprint_card = nil + if other_joker_ret then + other_joker_ret.card = card + other_joker_ret.colour = G.C.BLUE + return other_joker_ret + end +end + function SMODS.get_card_areas(_type, _context) if _type == 'playing_cards' then local t = {} if _context ~= 'end_of_round' then t[#t+1] = G.play end - if _context ~= 'end_of_round' and SMODS.optional_features.cardareas.unscored then t[#t+1] = 'unscored' end t[#t+1] = G.hand if SMODS.optional_features.cardareas.deck then t[#t+1] = G.deck end if SMODS.optional_features.cardareas.discard then t[#t+1] = G.discard end @@ -1769,7 +1788,8 @@ SMODS.deepfind = function(tbl, val, mode, immediate) return collector end ---backwards compat (remove later probably) +---@deprecated +---backwards compat (remove later probably) SMODS.deepfindbyindex = function(tbl, val, immediate) return SMODS.deepfind(tbl, val, "i", immediate) end @@ -1808,8 +1828,10 @@ SMODS.get_optional_features = function() end G.FUNCS.can_select_from_booster = function(e) - local area = booster_obj and e.config.ref_table:selectable_from_pack(booster_obj) - if area and #G[area].cards < G[area].config.card_limit then + local card = e.config.ref_table + local area = booster_obj and card:selectable_from_pack(booster_obj) + local edition_card_limit = card.edition and card.edition.card_limit or 0 + if area and #G[area].cards < G[area].config.card_limit + edition_card_limit then e.config.colour = G.C.GREEN e.config.button = 'use_card' else @@ -1830,4 +1852,96 @@ function Card.selectable_from_pack(card, pack) end return pack.select_card end -end \ No newline at end of file +end + +-- Shop functionality +function SMODS.size_of_pool(pool) + local size = 0 + for _, v in pairs(pool) do + if v ~= 'UNAVAILABLE' then size = size + 1 end + end + return size +end + +function SMODS.get_next_vouchers(vouchers) + vouchers = vouchers or {spawn = {}} + local _pool, _pool_key = get_current_pool('Voucher') + for i=#vouchers+1, math.min(SMODS.size_of_pool(_pool), G.GAME.starting_params.vouchers_in_shop + (G.GAME.modifiers.extra_vouchers or 0)) do + local center = pseudorandom_element(_pool, pseudoseed(_pool_key)) + local it = 1 + while center == 'UNAVAILABLE' or vouchers.spawn[center] do + it = it + 1 + center = pseudorandom_element(_pool, pseudoseed(_pool_key..'_resample'..it)) + end + + vouchers[#vouchers+1] = center + vouchers.spawn[center] = true + end + return vouchers +end + +function SMODS.add_voucher_to_shop(key) + if key then assert(G.P_CENTERS[key], "Invalid voucher key: "..key) else + key = get_next_voucher_key() + G.GAME.current_round.voucher.spawn[key] = true + G.GAME.current_round.voucher[#G.GAME.current_round.voucher + 1] = key + end + local card = Card(G.shop_vouchers.T.x + G.shop_vouchers.T.w/2, + G.shop_vouchers.T.y, G.CARD_W, G.CARD_H, G.P_CARDS.empty, G.P_CENTERS[key],{bypass_discovery_center = true, bypass_discovery_ui = true}) + card.shop_voucher = true + create_shop_card_ui(card, 'Voucher', G.shop_vouchers) + card:start_materialize() + G.shop_vouchers:emplace(card) + G.shop_vouchers.config.card_limit = #G.shop_vouchers.cards + return card +end + +function SMODS.change_voucher_limit(mod) + G.GAME.modifiers.extra_vouchers = (G.GAME.modifiers.extra_vouchers or 0) + mod + if mod > 0 and G.STATE == G.STATES.SHOP then + for i=1, mod do + SMODS.add_voucher_to_shop() + end + end +end + +function SMODS.add_booster_to_shop(key) + if key then assert(G.P_CENTERS[key], "Invalid booster key: "..key) else key = get_pack('shop_pack').key end + local card = Card(G.shop_booster.T.x + G.shop_booster.T.w/2, + G.shop_booster.T.y, G.CARD_W*1.27, G.CARD_H*1.27, G.P_CARDS.empty, G.P_CENTERS[key], {bypass_discovery_center = true, bypass_discovery_ui = true}) + create_shop_card_ui(card, 'Booster', G.shop_booster) + card.ability.booster_pos = #G.shop_booster.cards + 1 + card:start_materialize() + G.shop_booster:emplace(card) + return card +end + +function SMODS.change_booster_limit(mod) + G.GAME.modifiers.extra_boosters = (G.GAME.modifiers.extra_boosters or 0) + mod + if mod > 0 and G.STATE == G.STATES.SHOP then + for i = 1, mod do + SMODS.add_booster_to_shop() + end + end +end + +function SMODS.change_free_rerolls(mod) + G.GAME.round_resets.free_rerolls = G.GAME.round_resets.free_rerolls + mod + G.GAME.current_round.free_rerolls = math.max(G.GAME.current_round.free_rerolls + mod, 0) + calculate_reroll_cost(true) +end + +function SMODS.signed(val) + return val and (val > 0 and '+'..val or ''..val) or '0' +end + +function SMODS.signed_dollars(val) + return val and (val > 0 and '$'..val or '-$'..-val) or '0' +end + +function SMODS.multiplicative_stacking(base, perma) + base = (base ~= 0 and base or 1) + perma = (perma ~= 0 and perma + 1 or 1) + local ret = base * perma + return (ret == 1 and 0) or (ret > 0 and ret) or 0 +end diff --git a/Steamodded/tk_debug_window.py b/smods/tk_debug_window.py similarity index 100% rename from Steamodded/tk_debug_window.py rename to smods/tk_debug_window.py diff --git a/smods/version b/smods/version new file mode 100644 index 0000000..69078c6 --- /dev/null +++ b/smods/version @@ -0,0 +1 @@ +cryptid-0.5.5 diff --git a/smods/version.lua b/smods/version.lua new file mode 100644 index 0000000..73d2cc1 --- /dev/null +++ b/smods/version.lua @@ -0,0 +1 @@ +return "1.0.0~BETA-0309b-STEAMODDED"