-
Notifications
You must be signed in to change notification settings - Fork 80
Calculate Functions
Objects can have a calculate
function defined on them to allow them to react to different events happening in the game. The main time for this to happen is during scoring, but there are other contexts that the game calculates effects. There is a full list of contexts available at the end of this guide.
To create a calculate function on your object, add this code to your object definition.
calculate = function(self, card, context)
-- calculation code goes in here
end,
In this function, self
refers to the center object that is used to create cards of this type, card
refers to the actual card you are calculating on, and context
refers to the table of values sent to the calculate. You will need to use card
and context
to calculate any effects within your object.
There are three steps to writing the calculation code within your function.
- Checking for the correct context
- Any logic/effects you want to do
- Returning any effects that need to be handled
All code within your calculate function should be inside a context check. This statement will ensure that your effect will open happen in the timing that you want it to happen. There is a full list of contexts at the end of this guide, but here are some common ones you might want to use.
-
if context.joker_main then
The main scoring timing of jokers -
if context.cardarea == G.play and context.main_scoring
The main scoring of played cards (used for modifiers to cards) -
if context.before then
For effects that happen in the scoring loop but before anything is scored -
if context.final_scoring_step then
For effects that modify the score after all cards have been scored -
if context.cardarea == G.play and context.repetition then
For adding repetitions to played cards
In this step, you need to add your actual logic for calculation. Values that are defined in your object's config can be access by using card.ability.
, for example, here is some code that increases the chips an object will give out by 10 every time the effect is evaluated.
card.ability.extra.chips = card.ability.extra.chips + card.ability.extra.chip_gain
Any effects that you want to be evaluated will need to be returned in a table. To score the chips from Step 2, you should use this return table.
return {
chips = card.ability.extra.chips
}
There are a range of different keys that you can return in this table.
-
chips
,mult
,xmult
,dollars
- scores these values (automatically adds a message to the card that is being scored) -
swap
- swaps current chips and mult values with each other -
level_up
- levels up the played hand by the number returned -
saved
- used duringcontext.end_of_round
to prevent game over -
message
- used to return a custom message- will automatically be put on the scored card unless
message_card
is also returned - colour of message background will be
G.C.FILTER
unlesscolour
is returned - sound will be
generic1
unlesssound
is returned
- will automatically be put on the scored card unless
-
func
- return a function to be called at the correct timing (advanced) -
extra
- an extra table set out the same as this one (advanced)
If you do not want the default messages to be shown when adding chips
etc. there are 2 ways around this
- Use
remove_default_message = true
in your return table to ignore the message completely - Use
chip_message = 'text'
to change the text (this maintains default timings)
Putting all this together, we get the following function that will increment chips each time the object is scored, and then score the new amount of chips.
calculate = function(self, card, context)
if context.joker_main then
card.ability.extra.chips = card.ability.extra.chips + card.ability.extra.chip_gain
return {
chips = card.ability.extra.chips
}
end
end
Here is another example for a Joker that increases the amount of mult it gives when you play a Flush.
calculate = function(self, card, context)
-- Check if we have played a Flush before we do any scoring and increment the chips
if context.before and next(context.poker_hands['Flush']) then
card.ability.extra.mult = card.ability.extra.mult + card.ability.extra.mult_gain
return {
message = 'Upgraded!',
colour = G.C.RED
}
end
-- Add the chips in main scoring context
if context.joker_main then
return {
mult = card.ability.extra.mult
}
end
Note
If you want to evaluate effects outside of the return table, use SMODS.calculate_effect({effects}, card)
,
where {effects}
is a table like the return table of a calculate function, and card
is the card that is being evaluated.
Detailed here is a list of all contexts that are sent to calculate functions, as well as a unique identifier to use to reference them. As each context is sent to different areas, use the following logic statement to make sure you are calculating in the intended area.
if context.cardarea == G.play then -- replace G.play with G.jokers/G.hand as appropriate
This context is used for effects that happen before scoring begins.
if context.before and context.cardarea == G.play then
{
cardarea = G.jokers, -- G.play, G.hand, (G.deck and G.discard optionally enabled)
full_hand = G.play.cards,
scoring_hand = scoring_hand,
scoring_name = text,
poker_hands = poker_hands,
before = true
}
This context is used for the effects from playing cards when they are scored.
if context.main_scoring and context.cardarea == G.play then
{
cardarea = G.play, -- G.hand, (G.deck and G.discard optionally enabled)
full_hand = G.play.cards,
scoring_hand = scoring_hand,
scoring_name = text,
poker_hands = poker_hands,
main_scoring = true
}
This context is used for triggering joker effects on playing cards.
if context.individual and context.cardarea == G.play then
{
cardarea = G.play, -- G.hand, (G.deck and G.discard optionally enabled)
full_hand = G.play.cards,
scoring_hand = scoring_hand,
scoring_name = text,
poker_hands = poker_hands,
individual = true,
other_card = card
}
This context is used for adding repetitions to playing cards.
if context.repetition and context.cardarea == G.play then
{
cardarea = G.play, -- G.hand, G.deck and G.discard optionally enabled
full_hand = G.play.cards,
scoring_hand = scoring_hand,
scoring_name = text,
poker_hands = poker_hands,
repetition = true,
card_effects = effects -- this is the table of effects that has been calculated
}
This context is used for triggering editions on jokers before they score. (used for chips/mult)
if context.pre_joker then
{
cardarea = G.jokers,
full_hand = G.play.cards,
scoring_hand = scoring_hand,
scoring_name = text,
poker_hands = poker_hands,
edition = true,
pre_joker = true
}
This context is used for triggering normal scoring effects on jokers.
if context.joker_main then
{
cardarea = G.jokers,
full_hand = G.play.cards,
scoring_hand = scoring_hand,
scoring_name = text,
poker_hands = poker_hands,
joker_main = true,
}
This context is used for triggering joker effects from other jokers.
if context.other_joker then
{
full_hand = G.play.cards,
scoring_hand = scoring_hand,
scoring_name = text,
poker_hands = poker_hands,
other_joker = card, --changes to other_consumeable as it iterates over consumeables
}
This context is used for triggering editions on jokers after they score. (used for xmult)
if context.post_joker then
{
cardarea = G.jokers,
full_hand = G.play.cards,
scoring_hand = scoring_hand,
scoring_name = text,
poker_hands = poker_hands,
edition = true,
post_joker = true
}
This context is used for any effects after cards have been calculated but before the score is totalled.
if context.final_scoring_step and context.cardarea == G.play then
{
cardarea = G.jokers, -- G.play, G.hand, (G.deck and G.discard optionally enabled)
full_hand = G.play.cards,
scoring_hand = scoring_hand,
scoring_name = text,
poker_hands = poker_hands,
final_scoring_step = true,
}
This context is used for marking cards to be destroyed.
if context.destroy_card and context.cardarea == G.play then
{
cardarea = G.play, -- G.hand, (G.deck and G.discard optionally enabled)
full_hand = G.play.cards,
scoring_hand = scoring_hand,
scoring_name = text,
poker_hands = poker_hands,
destroy_card = card,
destroying_card = card -- only when calculating in G.play
}
Tip
Your return table to destroy a card without a message should look like
return { remove = true }
This context is used for effects on removing cards.
if context.remove_playing_cards then
{
cardarea = G.jokers, -- G.play, G.hand, (G.deck and G.discard optionally enabled)
scoring_hand = scoring_hand,
remove_playing_cards = true,
removed = cards_destroyed
}
Warning
This is also called after discarding a hand without the scoring_hand
part of the context.
This context is used for effects after scoring.
if context.after and context.cardarea == G.play then
{
cardarea = G.jokers, -- G.play, G.hand, (G.deck and G.discard optionally enabled)
full_hand = G.play.cards,
scoring_hand = scoring_hand,
scoring_name = text,
poker_hands = poker_hands,
after = true,
}
This context is used for trigger effects on playing a hand debuffed by the blind.
if context.debuffed_hand and context.cardarea == G.play then
{
cardarea = G.jokers, -- G.play, G.hand, (G.deck and G.discard optionally enabled)
full_hand = G.play.cards,
scoring_hand = scoring_hand,
scoring_name = text,
poker_hands = poker_hands,
debuffed_hand = true,
}
This context is used for end of round effects.
if context.end_of_round and context.cardarea == G.jokers then
{
cardarea = G.jokers, -- G.hand, (G.deck and G.discard optionally enabled)
end_of_round = true,
game_over = game_over -- true or false
}
This context is used for effects on cards from jokers at the end of the round.
if context.end_of_round and context.individual then
{
cardarea = G.hand, -- (G.deck and G.discard optionally enabled)
end_of_round = true,
individual = true,
other_card = card
}
This context is used for repetitions on cards at the end of the round.
if context.end_of_round and context.repetition then
{
cardarea = G.hand, -- (G.deck and G.discard optionally enabled)
end_of_round = true,
repetition = true,
other_card = card,
card_effects = effects -- table of effects for the card
}
This context is used for effects when the blind is started.
if context.setting_blind then
{
cardarea = G.jokers, -- G.hand, (G.deck and G.discard optionally enabled)
setting_blind = true,
blind = G.GAME.round_resets.blind
}
This context is used for effects before discarding.
if context.pre_discard and context.cardarea == G.play then
{
cardarea = G.jokers, -- G.hand, (G.deck and G.discard optionally enabled)
full_hand = G.hand.highlighted,
pre_discard = true,
hook = hook -- true when 'The Hook' discards cards
}
This context is used for effects on discarded cards.
if context.discard then
{
cardarea = G.jokers, -- G.hand, (G.deck and G.discard optionally enabled)
full_hand = G.hand.highlighted,
discard = true
other_card = G.hand.highlighted[i]
}
Tip
Return { remove = true }
to destroy cards in this context.
This context is used for effects after opening a booster.
if context.open_booster then
{
cardarea = G.jokers, -- G.hand, (G.deck and G.discard optionally enabled)
open_booster = true,
card = self -- the booster pack being opened
}
This context is used for effects after skipping a booster.
if context.skipping_booster then
{
cardarea = G.jokers, -- G.hand, (G.deck and G.discard optionally enabled)
skipping_booster = true,
}
This context is used for effects after buying a card.
if context.buying_card then
{
cardarea = G.jokers, -- G.hand, (G.deck and G.discard optionally enabled)
buying_card = true,
card = self -- the card being bought
}
The card being bought also calculates itself with context { buying_card = true, card = c1 }
.
This context is used for effects after selling a card.
if context.selling_card then
{
cardarea = G.jokers, -- G.hand, (G.deck and G.discard optionally enabled)
selling_card = true,
card = card -- the card being sold
}
The card being sold also calculates itself with context { selling_self = true }
.
This context is used for effects after rerolling the shop.
if context.reroll_shop then
{
cardarea = G.jokers, -- G.hand, (G.deck and G.discard optionally enabled)
reroll_shop = true,
}
This context is used for effects after leaving the shop.
if context.ending_shop then
{
cardarea = G.jokers, -- G.hand, (G.deck and G.discard optionally enabled)
ending_shop = true,
}
This context is used for effects after drawing the first hand of a blind.
if context.first_hand_drawn then
{
cardarea = G.jokers, -- G.hand, (G.deck and G.discard optionally enabled)
first_hand_drawn = true,
}
This context is used for effects after drawing a hand.
if context.hand_drawn then
{
cardarea = G.jokers, -- G.hand, (G.deck and G.discard optionally enabled)
hand_drawn = true,
}
This context is used for effects after using a consumable
if context.using_consumeable then
{
cardarea = G.jokers, -- G.hand, (G.deck and G.discard optionally enabled)
using_consumeable = true,
consumeable = card -- the consumable being used
}
This context is used for effects after skipping a blind.
if context.skip_blind then
{
cardarea = G.jokers, -- G.hand, (G.deck and G.discard optionally enabled)
skip_blind = true,
}
This context is used for effects after adding a card to your deck.
if context.playing_card_added then
{
cardarea = G.jokers, -- G.hand, (G.deck and G.discard optionally enabled)
playing_card_added = true,
card = cards -- the cards being added
}
This context is used for applying quantum enhancements.
if context.check_enhancement then
{
cardarea = G.jokers, -- G.hand, (G.deck and G.discard optionally enabled)
check_enhancement = true,
other_card = card,
no_blueprint = true
}
This context is used for effects after a Joker has triggered.
if context.post_trigger then
{
cardarea = G.jokers, -- G.hand, (G.deck and G.discard optionally enabled)
post_trigger = true,
blueprint_card = context.blueprint_card, -- if applicable
other_card = card, -- the card that triggered
other_context = context, -- the context the trigger happened on
other_ret = ret -- the return table from the trigger
}
Note
All calculation of jokers that evaluates no secondary card is called with main_eval = true
in the context table.
All joker triggers are called with again when the joker is retriggered with
retrigger_joker = retrigger_card
added to the context table.
Game Objects
- API Documentation
- SMODS.Achievement
- SMODS.Atlas
- SMODS.Blind
- SMODS.Center
- SMODS.Challenge
- SMODS.DeckSkin
- SMODS.Keybind
- SMODS.Language
- SMODS.ObjectType
- SMODS.PokerHand
- SMODS.Rarity
- SMODS.Seal
- SMODS.Sound
- SMODS.Stake
- SMODS.Sticker
- SMODS.Suit and SMODS.Rank
- SMODS.Tag
Guides
- Your First Mod
- Mod Metadata
- Joker Calculation
- Calculate Functions
- Logging
- Event Manager
- Localization
- Mod functions
- UI Structure
- Utility Functions
Found an issue, or want to add something? Submit a PR to the Wiki repo.