Compare commits

...

44 commits
0.0.1 ... main

Author SHA1 Message Date
57344e1f00
Add sell value on merge, handle consumables and tags separately 2026-01-16 20:49:30 +01:00
13257d91b3
Update submodule 2025-07-02 18:24:55 +02:00
e1e0ce0661
Speed up animation when many tags exist 2025-06-29 00:09:03 +02:00
8cf3988bcc
Remove redundant files 2025-06-24 14:35:23 +02:00
ac2157799e
Remove legendary background 2025-06-24 14:32:26 +02:00
97d50cbb48
Add escape hatch 2025-06-24 14:32:07 +02:00
270b163c22
Update .editorconfig 2025-05-02 23:42:36 +02:00
396a1ff322
Add Afterimage spectral card 2025-05-02 05:23:15 +02:00
12d7e17b72
Re-add missing localization 2025-04-17 01:26:38 +02:00
98e855e314
Remove redundant localization 2025-04-17 01:22:25 +02:00
961225f64d
Remove leaky challenges 2025-04-17 01:15:28 +02:00
Emik
609172919b
Improve probability restoration
Prevents rigged probabilities from leaking into other cards
2025-04-11 19:31:22 +02:00
Emik
db5ced1704
Fix merge ability 2025-04-05 03:09:42 +02:00
Emik
3e1317ec08
Fix merging and The Improbable, reformat 2025-04-04 21:59:44 +02:00
Emik
b222530dd6
Add assertion 2025-04-03 11:12:43 +02:00
Emik
161234d944
Call function 2025-04-03 11:11:45 +02:00
Emik
7ff6b58d32
Update submodule and apply its breaking change 2025-04-03 00:50:24 +02:00
Emik
99f1f6a86f
Fix crash on non-cryptid 2025-03-28 19:47:09 +01:00
Emik
ca30e931d1
Update LuaFunctional 2025-03-27 16:35:08 +01:00
Emik
bf49c8d18e
Bump version 2025-03-27 03:37:49 +01:00
Emik
7fc1e188a0
Buff Void spectral to give 2 free negative cryptids 2025-03-27 03:36:32 +01:00
Emik
24d47bb04e
Add debugger 2025-03-26 18:47:18 +01:00
Emik
e1bf9ef2b2
Embed LuaFunctional properly 2025-03-26 02:36:27 +01:00
Emik
b8872b3090
Fix submodule 2025-03-26 02:11:15 +01:00
Emik
b8a7086c35
Fix all challenges 2025-03-25 22:27:38 +01:00
Emik
d382161a46
Make default joker cost 1$ 2025-03-25 22:27:26 +01:00
Emik
798dcc56ea
Push blind to appear later 2025-03-25 22:27:08 +01:00
Emik
4cfe3fa7c2
Add blind art 2025-03-25 19:55:31 +01:00
Emik
3f5d86af73
Add new blind: The Improbable 2025-03-25 18:04:32 +01:00
Emik
f3fe645e47
Update 2x 2025-03-25 16:20:23 +01:00
Emik
06fae2a55b
Change color of blind 2025-03-25 16:18:49 +01:00
Emik
b7665c5c6a
Improve state management 2025-03-25 16:01:11 +01:00
Emik
4ca5c81801
Add new blind: The Nimble 2025-03-25 15:47:59 +01:00
Emik
570de2f0cd
Use pseudo functions to respect seeded runs 2025-03-25 03:43:33 +01:00
Emik
075233b995
Change text in tag deletion 2025-03-24 18:42:57 +01:00
Emik
e499747a6e
Respect card editions 2025-03-24 11:30:02 +01:00
Emik
d0d81744a7
Properly handle stacked consumables 2025-03-24 11:06:52 +01:00
Emik
aaa04fecd5
Use backing text for emphasis 2025-03-23 22:47:53 +01:00
Emik
58ccd7f0be
Loosen dependency 2025-03-23 22:47:24 +01:00
Emik
50ff498ab0
Fix index error 2025-03-21 02:28:10 +01:00
Emik
db57347fc0
Add void card 2025-03-21 02:22:00 +01:00
Emik
0aaa6cc74e
Remove use of deprecated API 2025-03-18 21:27:34 +01:00
Emik
3ed1929825
Allow joker merging 2025-03-17 13:46:29 +01:00
Emik
8fe1ac19b4
Disable card when debuffed 2025-03-15 16:45:05 +01:00
33 changed files with 619 additions and 119 deletions

171
.editorconfig Normal file
View file

@ -0,0 +1,171 @@
# see https://github.com/CppCXY/EmmyLuaCodeStyle
[*.lua]
# [basic]
# optional space/tab
indent_style = space
# if indent_style is space, this is valid
indent_size = 4
# if indent_style is tab, this is valid
tab_width = 4
# none/single/double
quote_style = double
continuation_indent = 4
## extend option
# continuation_indent.before_block = 4
# continuation_indent.in_expr = 4
# continuation_indent.in_table = 4
# this mean utf8 length , if this is 'unset' then the line width is no longer checked
# this option decides when to chopdown the code
max_line_length = 120
# optional crlf/lf/cr/auto, if it is 'auto', in windows it is crlf other platforms are lf
# in neovim the value 'auto' is not a valid option, please use 'unset'
end_of_line = lf
# none/ comma / semicolon / only_kv_colon
table_separator_style = none
#optional keep/never/always/smart
trailing_table_separator = smart
# keep/remove/remove_table_only/remove_string_only
call_arg_parentheses = keep
detect_end_of_line = false
# this will check text end with new line
insert_final_newline = true
# [space]
space_around_table_field_list = false
space_before_attribute = false
space_before_function_open_parenthesis = false
space_before_function_call_open_parenthesis = false
space_before_closure_open_parenthesis = false
# optional always/only_string/only_table/none
# or true/false
space_before_function_call_single_arg = always
## extend option
## always/keep/none
# space_before_function_call_single_arg.table = always
## always/keep/none
# space_before_function_call_single_arg.string = always
space_before_open_square_bracket = false
space_inside_function_call_parentheses = false
space_inside_function_param_list_parentheses = false
space_inside_square_brackets = false
# like t[#t+1] = 1
space_around_table_append_operator = false
ignore_spaces_inside_function_call = false
# detail number or 'keep'
space_before_inline_comment = 1
# convert '---' to '--- ' or '--' to '-- '
space_after_comment_dash = false
# [operator space]
space_around_math_operator = true
# space_around_math_operator.exponent = false
space_after_comma = true
space_after_comma_in_for_statement = true
# true/false or none/always/no_space_asym
space_around_concat_operator = true
space_around_logical_operator = true
# true/false or none/always/no_space_asym
space_around_assign_operator = true
# [align]
align_call_args = false
align_function_params = true
# true/false or always
align_continuous_assign_statement = true
align_continuous_rect_table_field = true
align_continuous_line_space = 2
align_if_branch = false
# option none / always / contain_curly/
align_array_table = true
align_continuous_similar_call_args = false
align_continuous_inline_comment = true
# option none / always / only_call_stmt
align_chain_expr = none
# [indent]
never_indent_before_if_condition = false
never_indent_comment_on_if_branch = false
keep_indents_on_empty_lines = false
allow_non_indented_comments = false
# [line space]
# The following configuration supports four expressions
# keep
# fixed(n)
# min(n)
# max(n)
# for eg. min(2)
line_space_after_if_statement = fixed(2)
line_space_after_do_statement = fixed(2)
line_space_after_while_statement = fixed(2)
line_space_after_repeat_statement = fixed(2)
line_space_after_for_statement = fixed(2)
line_space_after_local_or_assign_statement = max(2)
line_space_after_function_statement = fixed(2)
line_space_after_expression_statement = max(2)
line_space_after_comment = fixed(1)
line_space_around_block = fixed(1)
# [line break]
break_all_list_when_line_exceed = false
auto_collapse_lines = false
break_before_braces = false
# [preference]
ignore_space_after_colon = false
remove_call_expression_list_finish_comma = true
# keep / always / same_line / replace_with_newline / never
end_statement_with_semicolon = replace_with_newline

4
.gitmodules vendored
View file

@ -1,3 +1,3 @@
[submodule "src/LuaFunctional"]
path = "src/LuaFunctional"
url = "https://github.com/BakersDozenBagels/LuaFunctional.git"
path = src/LuaFunctional
url = https://github.com/BakersDozenBagels/LuaFunctional.git

Binary file not shown.

Before

Width:  |  Height:  |  Size: 5.8 KiB

Binary file not shown.

BIN
assets/1x/afterimage.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 4.2 KiB

BIN
assets/1x/blind.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

BIN
assets/1x/escapey.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.1 KiB

View file

Before

Width:  |  Height:  |  Size: 67 KiB

After

Width:  |  Height:  |  Size: 67 KiB

BIN
assets/1x/void.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 10 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 8.8 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 181 KiB

BIN
assets/2x/afterimage.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.3 KiB

BIN
assets/2x/blind.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.6 KiB

BIN
assets/2x/escapey.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.6 KiB

BIN
assets/2x/icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

BIN
assets/2x/void.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 13 KiB

BIN
assets/sounds/void.ogg Normal file

Binary file not shown.

1
assets/upscale.bat Normal file
View file

@ -0,0 +1 @@
for /F %%x in ('dir /B/D 1x') do magick 1x\%%x -scale 200%% 2x\%%x

6
assets/upscale.sh Executable file
View file

@ -0,0 +1,6 @@
#!/bin/sh
for file in 1x/*.png; do
filename=$(basename "$file")
output_file="2x/${filename}"
magick "$file" -filter point -resize 200% "$output_file"
done

View file

@ -1,50 +1,73 @@
return {
descriptions = {
Blind = {
bl_Roland_improbable = {
name = "The Improbable",
text = {"{C:attention}All probabilities", "cannot happen"},
},
bl_Roland_nimble = {
name = "The Nimble",
text = {"The first {C:attention}5 cards", "drawn are {C:attention}played"},
},
},
Joker = {
j_Roland_Escapey = {
j_Roland_escapey = {
name = "Escapey",
text = {
"Destroy {C:attention}tags{} and {C:attention}non-selected",
"Destroy {C:attention}tags{} or {C:attention}non-selected",
"{C:attention}consumables{} on use. Level up",
"the {C:planet}most played hand{} by {C:planet}#1#{}",
"for each destroyed object",
"{C:inactive}(Currently #2#)",
" ",
"{C:inactive,s:0.75,E:1}#3#{C:red,s:1.5,E:1}#4#",
"{C:inactive,s:0.75,E:1}#5#{C:red,s:1.5,E:1}#6#",
"#3#{C:inactive,s:0.75,E:1}#4#{C:red,s:1.5,E:1}#5#",
"#6#{C:blue,E:1}#7#{}#8#{C:inactive,s:0.75,E:1}#9#{C:red,s:1.5,E:1}#10#",
},
merge = {"Since no objects apply, fuse", "with other ", " jokers"},
quotes = {
marble = {{"there is no escape..."}},
normal = {
{"I can't wait to work with you!"},
{"Did you need something from me?"},
{"Oh! I'm just so happy to see you!"},
{"I can't wait to", "work with you!"},
{"Did you need something", "from me?"},
{"Oh! I'm just so", "happy to see you!"},
{"Can I talk about something irrelevant?", "I promise it won't be long."},
{"Can you introduce me to your friends?", "Assuming you have friends of course!"},
{"Can you introduce me to your friends?", "Assuming you have friends of course!"},
},
scared = {
{"What am I", "going to do?!"},
{"I'm not scared,", "you are!"},
{"Tell me when", "this is over..."},
{"I can't keep", "looking at this!"},
{"What am I", "going to do?!"},
{"I'm not scared,", "you are!"},
{"Tell me when", "this is over..."},
{"I can't keep", "looking at this!"},
{"Let me go hide in", "this corner... Okay?"},
},
},
}
},
},
Spectral = {
c_Roland_afterimage = {
name = "Afterimage",
text = {
"Add {C:dark_edition}Negative {}to {C:attention}#1#",
"selected card in hand",
"{C:red}#2#{} hand size",
},
},
c_Roland_void = {
name = "Void",
text = {
"{C:red}Destroys {X:red,C:white}all{} owned",
"playing cards {}for",
"{C:attention}#1# {C:dark_edition}Negative {C:spectral}Cryptids",
},
},
},
},
misc = {
challenge_names = {
c_Roland_Soaring = "Soaring",
c_Roland_Jokerful = "Jokerful",
c_Roland_Ascension = "Ascension",
c_Roland_Balanced_Jokers = "Balanced Jokers",
},
v_text = {
ch_c_Roland_Accelerated = {"Start with {C:blue}Accelerated Deck"},
ch_c_Roland_Saint = {"Start with an {C:attention}Eternal {C:legendary}Saint"},
ch_c_Roland_Jokerful = {"Only the {C:common}default Joker{} can appear in shops"},
ch_c_Roland_Balanced_Jokers = {"All Cryptid and Jen's jokers {C:attention}cannot appear"},
}
}
},
},
}

View file

@ -1,20 +1,22 @@
{
"priority": 0,
"priority": -2,
"id": "Roland",
"name": "Roland",
"prefix": "Roland",
"author": ["Emik"],
"version": "0.0.1",
"author": [
"Emik"
],
"version": "1.4.5",
"badge_colour": "8BE9FD",
"main_file": "src/main.lua",
"badge_text_colour": "44475A",
"display_name": "Roland (Emik)",
"description": "Adds the most important joker, as well as a handful of challenges.",
"description": "Adds several disconnected funny ideas I had in my head that I couldn't resist implementing in the game.",
"provides": [],
"conflicts": [],
"dependencies": [
"Steamodded (>=1.*)",
"Lovely (>=0.6)",
"Bakery (>=0.1.26)"
]
"Bakery (>=1.3.2~*)"
]
}

1
refs/BalatroBakery Symbolic link
View file

@ -0,0 +1 @@
../../BalatroBakery/src/

1
refs/Cryptid Symbolic link
View file

@ -0,0 +1 @@
../../Cryptid/

1
refs/Talisman Symbolic link
View file

@ -0,0 +1 @@
../../Talisman/

1
refs/dump Symbolic link
View file

@ -0,0 +1 @@
../../lovely/dump/

1
refs/lsp_def Symbolic link
View file

@ -0,0 +1 @@
../../smods/lsp_def/

1
src/LuaFunctional Submodule

@ -0,0 +1 @@
Subproject commit 4f3eae046476664b720a96f91b0e04f388709bbb

111
src/blind.lua Normal file
View file

@ -0,0 +1,111 @@
SMODS.Atlas {
px = 34,
py = 34,
frames = 21,
key = "blind",
path = "blind.png",
atlas_table = "ANIMATION_ATLAS",
}
local function disable_improbable()
G.GAME.improbable = nil
local orig = (getmetatable(G.GAME.probabilities) or {}).orig
if orig then
G.GAME.probabilities = orig
end
end
if cry_prob then
local orig_prob = cry_prob
---@diagnostic disable-next-line: lowercase-global
cry_prob = function(owned, den, rigged)
return G.GAME.improbable and 0 or orig_prob(owned, den, rigged)
end
end
local orig_update = Game.update
---@diagnostic disable-next-line: duplicate-set-field
function Game:update(dt)
orig_update(self, dt)
local orig = G.GAME.probabilities
if not G.GAME.improbable or getmetatable(orig) then
return
end
local normal = orig.normal
local mt = {
orig = orig,
__index = function(_, k)
return k == "normal" and 0 or orig[k]
end,
__newindex = function(_, k, v)
orig[k] = (k == "normal" and v == 0) and normal or v
end,
}
local proxy = {}
setmetatable(proxy, mt)
G.GAME.probabilities = proxy
end
SMODS.Blind {
key = "improbable",
boss = {min = 2, max = 10},
boss_colour = HEX("009966"),
atlas = "blind",
pos = {x = 0, y = 0},
mult = 2,
dollars = 5,
defeat = disable_improbable,
disable = disable_improbable,
set_blind = function(_)
G.GAME.improbable = true
end,
}
SMODS.Blind {
key = "nimble",
boss = {min = 1, max = 10},
boss_colour = HEX("0291fb"),
atlas = "blind",
pos = {x = 0, y = 1},
mult = 2,
dollars = 5,
defeat = function(self)
self.disabled = false
end,
disable = function(self)
self.disabled = true
end,
drawn_to_hand = function(self)
local function force_hand()
for i, v in ipairs(G.hand.cards) do
if i > 5 then
break
end
G.hand:add_to_highlighted(v, true)
end
G.FUNCS.play_cards_from_highlighted(nil)
return true
end
if not self.disabled then
self.disabled = true
G.E_MANAGER:add_event(Event({
delay = 1,
trigger = "after",
func = force_hand,
}))
end
end,
set_blind = function(self)
self.disabled = false
end,
}

View file

@ -1,51 +1,22 @@
local jokerful = {banned_cards = {}}
local balanced_jokers = {banned_cards = {}}
SMODS.Challenge {
key = "Jokerful",
rules = {custom = {{id = "Roland_Jokerful"}}},
restrictions = jokerful
restrictions = jokerful,
}
if Jen then
SMODS.Challenge {
key = "Ascension",
deck = {type = "b_jen_nitro"},
rules = {custom = {{id = "Roland_Saint"}, {id = "Roland_Accelerated"}}},
jokers = {{id = "j_jen_saint", eternal = true}},
}
SMODS.Challenge {
key = "Soaring",
deck = {type = "b_jen_nitro"},
sleeve = "sleeve_cry_equilibrium_sleeve",
rules = {custom = {{id = "Roland_Saint"}, {id = "Roland_Accelerated"}}},
jokers = {{id = "j_jen_saint", eternal = true}},
}
SMODS.Challenge {
key = "Balanced_Jokers",
rules = {custom = {{id = "Roland_Balanced_Jokers"}}},
restrictions = balanced_jokers
}
end
G.E_MANAGER:add_event(Event {
trigger = "immediate",
func = function()
jokerful.banned_cards = F.map(
F.foreach(
F.filter(
G.P_CENTERS,
function (v) return v.set == "Joker" end
function(v) return v.set == "Joker" end
),
function (v) return { id = v.key } end
)
balanced_jokers.banned_cards = F.filter(
jokerful.banned_cards,
function (v) return v.id:sub(1, 6) == "j_cry_" or v.id:sub(1, 6) == "j_jen_" end
function(v) table.insert(jokerful.banned_cards, {id = v.key}) end
)
return true
end
end,
})

View file

@ -1,8 +1,17 @@
local function can_use()
return not ((G.play and #G.play.cards > 0 or
G.CONTROLLER.locked or
(G.GAME.STOP_USE and G.GAME.STOP_USE > 0)) and
G.STATE ~= G.STATES.HAND_PLAYED and
G.STATE ~= G.STATES.DRAW_TO_HAND and
G.STATE ~= G.STATES.PLAY_TAROT)
end
local function common_hand()
return (G.GAME or {}).current_round and F.reduce(
G.GAME.hands,
{name = "High Card", order = -1 / 0, played = 0},
function (a, v, k)
function(a, v, k)
return (a.played < v.played or (a.played == v.played) and (a.order > v.order)) and
{name = k, order = v.order, played = v.played} or a
end,
@ -14,72 +23,139 @@ local function destructible(card)
return not card.highlighted and not (card.ability or {}).eternal
end
local function is_mergeable_with(it)
return function(card)
return it.rank ~= card.rank and
card.label == "j_Roland_escapey" and not
(card.ability or {}).eternal
end
end
SMODS.Atlas {
key = "Escapey",
path = "Escapey.png",
px = 71,
py = 95
py = 95,
key = "escapey",
path = "escapey.png",
}
SMODS.Joker {
key = "Escapey",
atlas = "Escapey",
key = "escapey",
atlas = "escapey",
pos = {x = 0, y = 0},
sinis = {x = 2, y = 0},
soul_pos = {x = 1, y = 0},
config = {extra = {level_up_by = 1}},
cost = 8,
rarity = 3,
unlocked = true,
discovered = true,
eternal_compat = true,
perishable_compat = true,
blueprint_compat = false,
loc_vars = function(_, _, center)
local quotes = G.localization.descriptions.Joker.j_Roland_Escapey.quotes
local normal = (Jen or {}).sinister and {} or quotes.normal[math.random(#quotes.normal)]
local scared = (Jen or {}).sinister and quotes.scared[math.random(#quotes.scared)] or {}
loc_vars = function(_, _, card)
local loc_self = G.localization.descriptions.Joker.j_Roland_escapey
return {vars = {
center.ability.extra.level_up_by,
localize(common_hand(), "poker_hands"),
normal[1] or "",
scared[1] or "",
normal[2] or "",
scared[2] or ""
}}
---@diagnostic disable-next-line: undefined-global
local sinister = (Jen or {}).sinister or G.escapey_sinister
local quotes = loc_self.quotes
local merge = G.jokers
and F.count(F.filter(G.jokers.cards, is_mergeable_with(card))) > 0
and loc_self.merge or {}
local normal = (merge[1] or sinister) and {} or
pseudorandom_element(quotes.normal, pseudoseed("EscapeyQuotes")) or {}
local scared = (merge[1] or not sinister) and {} or
pseudorandom_element(quotes.scared, pseudoseed("EscapeyQuotes")) or {}
return {
vars = {
card.ability.extra.level_up_by,
localize(common_hand(), "poker_hands"),
merge[1] or "",
normal[1] or "",
scared[1] or "",
merge[2] or "",
merge[3] and loc_self.name or "",
merge[3] or "",
normal[2] or "",
scared[2] or "",
},
}
end,
Bakery_can_use = function(_, _)
return #G.GAME.tags ~= 0 or F.any(G.consumeables.cards, destructible)
calculate = function(_, _, context)
if type(G.escapey_debugger) == "function" then
G.escapey_debugger(F.reduce(context, "", function(acc, _, next) return acc .. ", " .. next end, pairs):sub(2))
end
end,
---@param card Card
Bakery_can_use = function(_, card)
return not card.debuff and can_use() and (
#G.GAME.tags ~= 0 or
F.any(G.consumeables.cards, destructible) or
F.any(F.filter(G.jokers.cards, is_mergeable_with(card)))
)
end,
---@param card Card
Bakery_use_button_text = function(_, card)
if card.debuff then
return "DEBUFFED"
end
return #G.GAME.tags == 0 and F.count(G.consumeables.cards, destructible) == 0 and
F.any(F.filter(G.jokers.cards, is_mergeable_with(card))) and "FUSE" or "ESCAPE"
end,
---@param card Card
Bakery_use_joker = function(_, card)
local hand, destroyed = common_hand(), 0
if card.debuff then
return
end
local consumables = F.filter(G.consumeables.cards, destructible)
local consumable_count = F.count(consumables)
local object_count = consumable_count + #G.GAME.tags
if object_count == 0 then
local level_sum, sell_sum = 0, 0
F.foreach(
F.filter(G.jokers.cards, is_mergeable_with(card)),
function(v)
level_sum = level_sum + v.ability.extra.level_up_by * (v.getEvalQty and v:getEvalQty() or 1)
sell_sum = sell_sum + v.sell_cost * (v.getEvalQty and v:getEvalQty() or 1)
v:start_dissolve({HEX("57ecab")}, nil, 1.6)
end
)
card.ability.extra.level_up_by = card.ability.extra.level_up_by + level_sum
card.sell_cost = card.sell_cost + sell_sum
return
end
local function update(name, chip, mul, lv, notif, snd, vol, pit, de)
update_hand_text({
sound = type(snd) == "string" and snd or type(snd) == "nil" and "button",
volume = vol or 0.7,
pitch = pit or 0.8,
delay = de or 0.3
delay = de or 0.3,
}, {
handname = name or "????",
chips = chip or "?",
level = lv or "?",
mult = mul or "?",
StatusText = notif
StatusText = notif,
})
end
local function fast_nope(v)
return function ()
local function fast_delete(v)
return function()
attention_text({
text = "NOPE",
colour = G.C.WHITE,
scale = 0.7,
hold = 0.3 / G.SETTINGS.GAMESPEED,
cover = v.HUD_tag,
cover_colour = G.C.BLACK,
align = "cm",
text = "ESC",
cover = v.HUD_tag,
colour = G.C.WHITE,
cover_colour = G.C.BLACK,
hold = 0.3 / G.SETTINGS.GAMESPEED,
})
play_sound("cancel", 1.66, 0.5)
@ -89,42 +165,43 @@ SMODS.Joker {
end
end
local hand = common_hand()
if hand == "all" or hand == "allhands" or hand == "all_hands" then
update(localize("k_all_hands"), "...", "...", "", notify)
update(localize("k_all_hands"), "...", "...", "")
elseif G.GAME.hands[hand or "NO_HAND_SPECIFIED"] then
update(
localize(hand, "poker_hands"),
G.GAME.hands[hand].chips,
G.GAME.hands[hand].mult,
G.GAME.hands[hand].level,
notify
G.GAME.hands[hand].level
)
end
F.foreach(
F.filter(G.consumeables.cards, destructible),
function (v)
v:start_dissolve({HEX("57ecab")}, nil, 1.6)
destroyed = destroyed + 1
end
)
if consumable_count == 0 then
local trigger = #G.GAME.tags >= 30 and "immediate" or "before"
local delay = #G.GAME.tags >= 30 and 0 or 1 / #G.GAME.tags
F.foreach(
G.GAME.tags,
function (v)
G.E_MANAGER:add_event(Event({trigger = "immediate", func = fast_nope(v)}))
destroyed = destroyed + 1
end
)
F.foreach(
G.GAME.tags,
function(v)
G.E_MANAGER:add_event(Event {trigger = trigger, blocking = #G.GAME.tags < 30, delay = delay, func = fast_delete(v)})
end
)
else
F.foreach(
consumables,
function(v)
v:start_dissolve({HEX("57ecab")}, nil, 1.6)
end
)
end
level_up_hand(card, hand, nil, destroyed * card.ability.extra.level_up_by)
level_up_hand(card, hand, nil, object_count * card.ability.extra.level_up_by)
update_hand_text(
{sound = "button", volume = 0.7, pitch = 1.1, delay = 0},
{mult = 0, chips = 0, handname = "", level = ""}
)
end,
Bakery_use_button_text = function(_, _) return "ESCAPE" end
}
Bakery_API.usable_jokers.j_Roland_Escapey = true

View file

@ -1,10 +1,14 @@
assert(SMODS.load_file("src/LuaFunctional/functional.lua"))()
F = assert(SMODS.load_file("src/LuaFunctional/functional.lua"))()
assert(SMODS.load_file("src/challenge.lua"))()
assert(SMODS.load_file("src/spectral.lua"))()
assert(SMODS.load_file("src/blind.lua"))()
assert(SMODS.load_file("src/joker.lua"))()
SMODS.Atlas {
path = "Icon.png",
key = "modicon",
px = 256,
py = 256,
key = "modicon",
path = "icon.png",
}
SMODS.Joker:take_ownership("joker", {cost = 1}, true)

128
src/spectral.lua Normal file
View file

@ -0,0 +1,128 @@
local function can_use()
return not ((G.play and #G.play.cards > 0 or
G.CONTROLLER.locked or
(G.GAME.STOP_USE and G.GAME.STOP_USE > 0)) and
G.STATE ~= G.STATES.HAND_PLAYED and
G.STATE ~= G.STATES.DRAW_TO_HAND and
G.STATE ~= G.STATES.PLAY_TAROT)
end
SMODS.Sound({key = "void", path = "void.ogg"})
SMODS.Atlas {
px = 71,
py = 95,
key = "afterimage",
path = "afterimage.png",
}
SMODS.Atlas {
px = 71,
py = 95,
key = "void",
path = "void.png",
}
SMODS.Consumable {
key = "afterimage",
set = "Spectral",
pos = {x = 0, y = 0},
cost = 6,
atlas = "afterimage",
config = {extra = {amount = 1, hand = -1}},
loc_vars = function(_, _, card)
return {vars = {card.ability.extra.amount, card.ability.extra.hand}}
end,
can_use = function(_, card)
return can_use() and card.ability.extra.amount == #Bakery_API.get_highlighted()
end,
use = function(_, card, _, _)
for _, v in ipairs(Bakery_API.get_highlighted()) do
G.E_MANAGER:add_event(Event {
delay = 0.1,
func = function()
v:set_edition({negative = true})
v:juice_up(0.5, 0.5)
return true
end,
})
end
G.E_MANAGER:add_event(Event {
delay = 0.1,
func = function()
G.hand:change_size(card.ability.extra.hand)
Bakery_API.unhighlight_all()
return true
end,
})
end,
}
SMODS.Consumable {
key = "void",
set = "Spectral",
pos = {x = 0, y = 0},
cost = 6,
atlas = "void",
config = {extra = {amount = 2}},
loc_vars = function(_, _, card)
return {vars = {card.ability.extra.amount}}
end,
can_use = function(_, _)
return #G.playing_cards > 1 and can_use()
end,
use = function(_, card, _, _)
local function destructible(v)
return not v.ability or not (v.ability.eternal or v.ability.cry_absolute)
end
local function destroy(v)
if v.area then
v.area:remove_card(v)
end
v.rhm = false
v:start_dissolve()
end
local function void()
local cards = F.filter(G.playing_cards, destructible)
local function calculate_joker(v)
v:calculate_joker({remove_playing_cards = true, removed = cards})
end
F.foreach(cards, destroy)
F.foreach(G.jokers.cards, calculate_joker)
for _ = 1, card.ability.extra.amount do
local cryptid = create_card(
nil,
G.consumeables,
nil,
nil,
nil,
nil,
"c_cryptid",
"void"
)
cryptid:set_edition({negative = true}, true)
cryptid:add_to_deck()
G.consumeables:emplace(cryptid)
end
return true
end
play_sound("Roland_void", 1, 0.7)
G.E_MANAGER:add_event(Event({
delay = 0.27,
timer = "REAL",
trigger = "after",
func = void,
}))
end,
}