Skip to content
Eremel edited this page Mar 1, 2026 · 1 revision

This update adds a few new headline features and a bunch of extra functionality for existing features. It also contains an update to the loading sequence to fully support lovely v0.9.0 and zip loading methods. See the Preflight section of the update for more information. As always, a number of bug fixes are included in this update which are detailed at the end of this update.

Preflight

Lovely 0.9.0 added the feature of zip loading mods, and this update allows SMODS to handle this feature. Most mods should work without changes in zip files, however if mods are manually loading files using NFS or require "nativefs", they should switch to using SMODS.NFS, or require "SMODS.nativefs". The older NFS or require "nativefs" are still provided, but may break zip loading if other mods provide their own copies of them.

SMODS.CanvasSprite

This is a new feature that allows you to turn any sort of love.graphics into a sprite that can be glued to an object to respect the movement of the game. The main use case it for adding dynamic text on top of cards, and there is built-in support for doing this. However, this feature can be used for other things, and I'm looking forward to seeing what people do with it.

Adding Text to Cards

To add some dynamic text to a card object, you should create a SMODS.CanvasSprite object and assign it to card.canvas_text. (This property on a card support a table of SMODS.CanvasSprite objects too)

Here is an example of some text that references a value that can be changed.

card.canvas_text = SMODS.CanvasSprite({
	text_colour = G.C.RED, -- the colour of the text
	ref_table = G.GAME,
	ref_value = 'canvas_text_example',
	text_offset = {x = 35, y = 85}, -- position of the text (anchor point defaults to the center of the text)
	text_width = 48, text_height = 20, -- the maximum dimensions of the text (text will be automatically resized to fit within these dimensions)
})

CanvasSprite objects are able to be customised using the following properties. - canvasW = 71/canvasH = 95: controls the dimensions of the canvas - canvasScale = 10: controls the scale of the canvas, a larger number will make the text sharper - text: a string to display on the card (replaces ref_table and ref_value) - text_colour: a table representing a colour - text_font: a key to a valid Font stored in SMODS.Fonts or G.FONTS - text_offset = {x = 0, y = 0}: adjust the positioning of the text - text_width/text_height: set a maximum width/height of the text - text_transform: provide a custom transformation for the text {x, y, r, sx, sy, ox, oy} (providing an empty table will reset the anchor point to the top left of the text, but also disable the text_offset property)

SMODS.ScreenShader

This is a new feature that allows you to create a shader that is applied to the entire screen, rather than an individual object. ScreenShaders can be layered on top of the base game shader (CRT) to create whatever effects you like!

SMODS.ScreenShader({
	key = 'shader_example',
	path = 'shader_example.fs',
	should_apply = function()
		-- use this function to return true when your shader should be applied
	end,
	send_vars = function(self)
		return {
			-- use this table to return any values that your shader needs to access from the game
		}
	end,
})

Text Formatting Updates

Text formatting has been updated to now work for Blinds, and has also had a new formatting tag added, which allows text to be turned into a button.

Your localization should use the tag like this, where example_button is a reference to a function in G.FUNCS.

"{button:example_button}Click me!"
function G.FUNCS.example_button()
    print('You clicked me')
end

Calculation Updates

There have been a couple of changes to some pre-existing contexts to allow for some additional functionality, as well as some increased functionality in calculate returns, and a new context when poker hands are levelled up.

SMODS.last_hand

This keeps track of the last played hand throughout the game, allowing you to check it for certain things. It is structured as below.

SMODS.last_hand.scoring_namestring of the name of the hand
SMODS.last_hand.scoring_handtable of scoring cards
SMODS.last_hand.full_handtable of all played cards

This has also been added into the end_of_round context and can be accessed as you normally would in a scoring context.

Redirecting Cards

It is now possible to redirect the area to which cards move when they are being drawn, played, or discarded. Using the pre-existing stay_flipped context, you can now return modify = {to_area = CardArea} to change which area the card moves to. An example of bonus cards returning to hand when played would look like this.

if context.stay_flipped and context.from_area == G.play then
	if context.other_card.config.center_key == "m_bonus" then
	    return {
            modify = {to_area = G.hand}
		}
	end
end

Message returns

It is now possible to customise the colour of messages that show from calculation returns by adding text_colour = G.C.RED to your return table.

pre_func returns

This is mainly to be used when you are calculating within the post_trigger context to trigger animations in between effects from the triggering joker and any of your own effects.

New Contexts

context.poker_hand_changed

This context is used when a poker hand has its chips and/or mult changed.

if context.poker_hand_changed then
context.poker_hand_changed -- flag to identify this context, always TRUE
context.old_level, context.new_level -- the poker hand's level before and after this modification (only present when level changes)
context.old_parameters, context.new_parameters -- tables mapping a scoring parameter's key to its value before and after this modification (only modified parameters are present)
context.scoring_name -- the poker hand being modified
context.card -- the card that caused this change (optional)

New Functionality

There are a number of new additions to a wide range of things that SMODS provides which are explained here.

mod.menu_cards()

This function allows you to easily add cards to the main menu of the game, or to adjust the card that is already there. It can be used to add a single card, or a group of cards, by providing tables of inputs to SMODS.create_card. (If you are adding a single card, you can treat the entire return table as the input to SMODS.create_card)

SMODS.current_mod.menu_cards = function()
	return {
		{set = 'Tarot'}, -- adds a random Tarot to the menu
		{key = 'j_perkeo'}, -- adds Perkeo to the menu
	}
end

You can optionally remove the initial card from the menu by including remove_original = true to your return table, and you can also define a func = function() ... that will be run after all mods have added their cards to the menu. G.title_top is the CardArea that holds these cards.

SMODS.Back.initial_deck

This option allows for easier customisation of your starting deck in custom Back objects. You can specify which Ranks and Suits to include within your deck (or exclude from your deck with a simple toggle) and the system will automatically handle creating the correct combinations for you. Any specific Rank:Suit mappings will still need to be created manually.

-- This example will create a deck of Clubs and Spades, with ranks Ace through 10
initial_deck = { 
	exclude = true, -- OPTIONAL: turns the lists into blacklists, rather than whitelists
	Suits = {'Diamonds', 'Hearts'}, -- A list of suits to include/exclude
	Ranks = {'King', 'Queen', 'Jack'}, -- A list of ranks to include/exclude
},

-- This example will create a deck of Diamonds and Hearts, with only face cards
initial_deck = { 
	Suits = {'Diamonds', 'Hearts'},
	Ranks = {'King', 'Queen', 'Jack'},
},

SMODS.get_clean_pool

This function is a wrapper for get_current_pool that will exclude any "UNAVAILABLE" values in the pool, therefore giving a list of valid keys only.

function SMODS.get_clean_pool(_type, _rarity, _legendary, _append)

Localization loading

It is now possible to load sub-folders within the localization folder. Sub-folders can be named as you see fit, but should have files inside named for each language, as before.

Ranks with negative chips

Support has been added for tooltips to automatically display negative chips on custom ranks.

Challenges text_colour

Challenges can now have a custom colour for their text.

Badge Text Colour

Adding text_colour to objects now controls the colour of the badges applied by them. This can also be added to ConsumableType definitions too.

Bug Fixes and Other Changes

  • Fix Tiny Hands achievement triggering incorrectly
  • Fix crash when some tables were seen as UI elements in card_eval_status_text
  • Fix win detection when winning ante is skipped
  • Fix eternal checks providing unexpected behaviour for objects without an eternal_compat value
  • Fix cards converted by Death wrongly retaining debuffs
  • Fix version handling issue
  • Fix rank display in deck view extending off the screen when a large number of custom ranks are present
  • Added align_buttons property on CardArea objects to replicate vanilla button positioning on custom areas
  • Hide the palette selector for DeckSkins with only one palette
  • Ability to set a custom StatusText value in update_hand_text and SMODS.upgrade_poker_hands
  • Fix copy_card from incorrectly handling card_limit and extra_slots_used values
  • Fix ghost cards being drawn when the final card of the deck has a card_limit value
  • Fix main tooltips being replaced by info queue items in collection
  • context.modify_scoring_hand can now affect debuffed cards
  • Fix some vanilla Jokers that have custom debuff messages (add keys to SMODS.custom_debuff_handling to use on your own jokers)
  • Fix card limits of areas updating incorrectly when changed whilst holding a card with extra_slots_used
  • Fix set = 'Consumeables' from ignoring given area value in SMODS.create_card
  • Vanilla functions that are overwritten have a note in game dumps
  • Card:remove_sticker can remove pinned
  • no_juice correctly works if included in calculation returns

Known Issues

This update unintentionally removes the Crimson Bean exploit. I am looking into this and will hopefully have a "fix" to reimplement this exploit in the next release.

Clone this wiki locally