Localize almost everything

This commit is contained in:
Emik 2026-02-02 20:51:51 +01:00
parent 61194ae6ed
commit eaed4f8486
Signed by: emik
GPG key ID: 6B0CD72A5E503BDF
17 changed files with 341 additions and 38 deletions

BIN
assets/1x/iphone.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 7 KiB

BIN
assets/2x/Pasted image.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 8.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.3 KiB

After

Width:  |  Height:  |  Size: 3.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.6 KiB

After

Width:  |  Height:  |  Size: 2.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.6 KiB

After

Width:  |  Height:  |  Size: 1.6 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 79 KiB

After

Width:  |  Height:  |  Size: 79 KiB

BIN
assets/2x/iphone.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 9.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 398 B

After

Width:  |  Height:  |  Size: 398 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 13 KiB

After

Width:  |  Height:  |  Size: 13 KiB

BIN
assets/sounds/milestone.ogg Normal file

Binary file not shown.

View file

@ -10,8 +10,22 @@ return {
}, },
}, },
b_Roland_go = { b_Roland_go = {
name = "placeholder", name = "Pass GO Deck",
text = {"grr"}, text = {
"Start with a {C:attention}Credit Card",
"Set money to {C:money}0$",
"when entering the shop",
},
},
},
BakeryCharm = {
BakeryCharm_Roland_iphone = {
name = "fat i phone",
text = {
"Enter the shop",
"when any {C:attention}Blind",
"is {C:attention}skipped",
},
}, },
}, },
Blind = { Blind = {
@ -37,6 +51,14 @@ return {
}, },
}, },
Joker = { Joker = {
j_Roland_bulldozer = {
name = "Bulldozer",
text = {
"Give {X:red,C:white}XMult{} equal to",
"the current {C:attention}Blind Size{C:attention}",
"{C:inactive}(Currently {X:red,C:white}X#1#{C:inactive})",
},
},
j_Roland_escapey = { j_Roland_escapey = {
name = "Escapey", name = "Escapey",
text = { text = {
@ -63,6 +85,46 @@ return {
}, },
}, },
}, },
j_Roland_estrogen = {
name = "Estrogen",
text = {"{C:mult}+Chips{} Mult"},
},
j_Roland_hexagon = {
name = "Hexagon",
text = {
"Earn {C:money}#1#${} if",
"played hand is a",
"{C:attention}Four of a Kind",
},
},
j_Roland_hexagoner = {
name = "Hexagoner",
text = {
"This Joker gains the",
"rank of {C:attention}unscored cards",
"if played hand is a",
"{C:attention}Four of a Kind",
"{C:inactive}(Currently {C:red}+#1#{C:inactive} Mult)",
},
},
j_Roland_hexagonest = {
name = "Hexagonest",
text = {
"{C:attention}Unscored cards{} add a",
"permanent copy to deck",
"and draw it to {C:blue}hand",
"if played hand is a",
"{C:attention}Four of a Kind",
},
},
j_Roland_misfortune = {
name = "Misfortune Cookie",
text = {
"{C:tarot}Tarot{} cards created",
"by {C:tarot}Purple Seals",
"become {C:dark_edition}Negative",
},
},
j_Roland_martingale = { j_Roland_martingale = {
name = "Martingale", name = "Martingale",
text = { text = {
@ -76,6 +138,72 @@ return {
"{s:0}Otherwise {C:green,s:0}#1# in #2#{s:0} chance to give {X:mult,C:white,s:0}X#9#{s:0} Mult", "{s:0}Otherwise {C:green,s:0}#1# in #2#{s:0} chance to give {X:mult,C:white,s:0}X#9#{s:0} Mult",
}, },
}, },
j_Roland_mrsbones = {
name = "Mrs. Bones",
text = {
"{X:red,C:white}X#1#{} Mult",
"{C:red,E:1}Self destructs{} if {C:chips}chips",
"scored at the end of",
"the {C:attention}Blind{} are less than",
"{C:attention}#2#%{} of required {C:chips}chips",
},
},
j_Roland_msjoker = {
name = "Ms. Joker",
text = {"{C:chips}+#1#{} Chips"},
},
j_Roland_oops = {
name = "Oops! All 7s",
text = {
"Listed {C:green,E:1}probabilities",
"{C:attention}increase{} for each",
"{C:hand}hand played this round",
"{C:inactive}(Currently {C:green}X#1#{C:inactive})",
},
},
j_Roland_rigged = {
name = "Rigged",
text = {
"{C:blue}#1#{}#2#{C:green}#3#{}#4#{C:red}#5#{}#6#{C:edition}#7#{}#8#{C:legendary}#9#{}#10#{C:dark_edition}#11#",
"jokers cannot appear",
"{C:attention}Upgrade{} this card by",
"obtaining another {C:attention}Rigged",
},
},
j_Roland_sunny = {
name = "Sunny Side Up",
text = {
"Sell this Joker to",
"{C:attention}draw{} the bottom",
"card of the {C:hand}deck",
"{C:inactive}(Currently {V:1}#1##2#{V:2}#3#{C:inactive})",
},
},
j_Roland_temple = {
name = "Temple",
text = {
"{C:attention}Unscored {C:enhanced}wild{} cards",
"give {X:red,C:white}X#1#{} Mult",
},
},
j_Roland_yard = {
name = "Yard Sale",
text = {
"Gain {C:money}#1#${} when a",
"card is {C:attention}removed",
"from the deck",
},
},
},
Other = {
Roland_glass_seal = {
name = "Glass Seal",
text = {
"Gives a random tag at",
"the end of the {C:attention}Blind",
"{C:red,E:1}Self destructs{} if {C:attention}drawn",
},
},
}, },
Spectral = { Spectral = {
c_Roland_afterimage = { c_Roland_afterimage = {
@ -86,6 +214,22 @@ return {
"{C:red}#2#{} hand size", "{C:red}#2#{} hand size",
}, },
}, },
c_Roland_dual = {
name = "Dual",
text = {
"Add random seals",
"to {C:attention}#1#{} random",
"cards in {C:hands}hand",
},
},
c_Roland_mirror = {
name = "Mirror",
text = {
"Add a {C:dark_edition}Glass Tag",
"to {C:attention}#1#{} selected",
"card in {C:hands}hand",
},
},
c_Roland_void = { c_Roland_void = {
name = "Void", name = "Void",
text = { text = {
@ -102,7 +246,13 @@ return {
c_Roland_Pastries = "Sweet Pastries", c_Roland_Pastries = "Sweet Pastries",
}, },
v_dictionary = { v_dictionary = {
b_Roland_comma = ", ",
b_Roland_of = " of ",
b_Roland_most_common_card = "(Rank)", b_Roland_most_common_card = "(Rank)",
b_Roland_na = "N/A",
},
labels = {
Roland_glass_seal = "Glass Seal",
}, },
v_text = { v_text = {
ch_c_Roland_Jokerful = {"Only the {C:common}default Joker{} can appear in shops"}, ch_c_Roland_Jokerful = {"Only the {C:common}default Joker{} can appear in shops"},

View file

@ -71,7 +71,7 @@ target = "card.lua"
pattern = "if self.seal == 'Purple' and #G.consumeables.cards + G.GAME.consumeable_buffer < G.consumeables.config.card_limit then" pattern = "if self.seal == 'Purple' and #G.consumeables.cards + G.GAME.consumeable_buffer < G.consumeables.config.card_limit then"
position = "at" position = "at"
payload = """if self.seal == 'Purple' and payload = """if self.seal == 'Purple' and
(next(SMODS.find_card "j_Roland_negative") or (next(SMODS.find_card "j_Roland_misfortune") or
#G.consumeables.cards + G.GAME.consumeable_buffer < G.consumeables.config.card_limit) then""" #G.consumeables.cards + G.GAME.consumeable_buffer < G.consumeables.config.card_limit) then"""
match_indent = true match_indent = true
@ -81,7 +81,7 @@ target = "card.lua"
pattern = "local card = create_card('Tarot',G.consumeables, nil, nil, nil, nil, nil, '8ba')" pattern = "local card = create_card('Tarot',G.consumeables, nil, nil, nil, nil, nil, '8ba')"
position = "after" position = "after"
times = 1 times = 1
payload = """if next(SMODS.find_card "j_Roland_negative") then payload = """if next(SMODS.find_card "j_Roland_misfortune") then
card:set_edition "e_negative" card:set_edition "e_negative"
end""" end"""
match_indent = true match_indent = true

View file

@ -1,8 +1,15 @@
local _, q = unpack(... or require "src.functional") local _, q = unpack(... or require "src.functional")
SMODS.Atlas {
key = "iphone",
path = "iphone.png",
px = 68,
py = 68,
}
Bakery_API.Charm { Bakery_API.Charm {
key = "tags", key = "iphone",
atlas = "void", atlas = "iphone",
pos = {x = 0, y = 0}, pos = {x = 0, y = 0},
calculate = function(_, _, context) calculate = function(_, _, context)
local _ = context.skip_blind and q(function() local _ = context.skip_blind and q(function()

View file

@ -23,7 +23,9 @@ local function protect_ev(fun)
return fun return fun
end end
local origf = F
local luaf = assert(SMODS.load_file "src/LuaFunctional/functional.lua")() or require "src.LuaFunctional.functional" local luaf = assert(SMODS.load_file "src/LuaFunctional/functional.lua")() or require "src.LuaFunctional.functional"
F = origf -- We do not condone globals as side effects!
if false then if false then
---Returns the elements from the given `list`. This function is equivalent to ---Returns the elements from the given `list`. This function is equivalent to
@ -70,7 +72,7 @@ end
--- Queues an event to be run. --- Queues an event to be run.
--- Note that events added this way implicitly `return true` unless you explicitly `return false`, unlike the vanilla ones. --- Note that events added this way implicitly `return true` unless you explicitly `return false`, unlike the vanilla ones.
--- @param fun (fun():boolean?)|Event The event or a function to run turn into an event. --- @param fun (fun():false|nil)|Event The event or a function to run turn into an event.
--- @param front boolean|nil `true` to add the event to the front of the queue, rather than the end. --- @param front boolean|nil `true` to add the event to the front of the queue, rather than the end.
local function q(fun, front) local function q(fun, front)
G.E_MANAGER:add_event(protect_ev(fun), nil, front) G.E_MANAGER:add_event(protect_ev(fun), nil, front)

View file

@ -45,6 +45,11 @@ local function level_up(hand, by, card)
update("", 0, 0, "", 1.1) update("", 0, 0, "", 1.1)
end end
SMODS.Sound {
key = "milestone",
path = "milestone.ogg",
}
SMODS.Atlas { SMODS.Atlas {
px = 71, px = 71,
py = 95, py = 95,
@ -67,8 +72,8 @@ SMODS.Joker {
sinis = {x = 2, y = 0}, sinis = {x = 2, y = 0},
soul_pos = {x = 1, y = 0}, soul_pos = {x = 1, y = 0},
config = {extra = {hands = 2}}, config = {extra = {hands = 2}},
cost = 8, cost = 6,
rarity = 3, rarity = 2,
eternal_compat = true, eternal_compat = true,
perishable_compat = true, perishable_compat = true,
blueprint_compat = false, blueprint_compat = false,
@ -203,10 +208,14 @@ SMODS.Joker {
level_up(v, 1, card) level_up(v, 1, card)
end) end)
end, end,
debug_export = function(self, obj)
local to = obj or self
to.f, to.q, to.u = f, q, u
end,
} }
SMODS.Joker { SMODS.Joker {
key = "temp", key = "msjoker", -- Blue bow
atlas = "void", atlas = "void",
pronouns = "they_them", pronouns = "they_them",
pos = {x = 0, y = 0}, pos = {x = 0, y = 0},
@ -222,7 +231,7 @@ SMODS.Joker {
} }
SMODS.Joker { SMODS.Joker {
key = "temp2", key = "bulldozer",
atlas = "void", atlas = "void",
pronouns = "they_them", pronouns = "they_them",
pos = {x = 0, y = 0}, pos = {x = 0, y = 0},
@ -240,52 +249,84 @@ SMODS.Joker {
} }
SMODS.Joker { SMODS.Joker {
key = "temp3", key = "oops", -- Slot machine
atlas = "void", atlas = "void",
pronouns = "they_them", pronouns = "they_them",
pos = {x = 0, y = 0}, pos = {x = 0, y = 0},
cost = 8, cost = 8,
rarity = 3, rarity = 3,
config = {extra = {probability = 1}}, config = {extra = {probability = 1, delta = 1}},
loc_vars = function(_, _, card) loc_vars = function(_, _, card)
return {vars = {card.ability.extra.probability}} return {vars = {card.ability.extra.probability}}
end, end,
calculate = function(_, card, context) calculate = function(_, card, context)
if context.mod_probability then if context.mod_probability then
return {numerator = card.ability.extra.probability} return {numerator = card.ability.extra.probability}
elseif context.blind_defeated then
card.ability.extra.probability = card.ability.extra.delta
elseif context.after and not context.blueprint then elseif context.after and not context.blueprint then
card.ability.extra.probability = card.ability.extra.probability + 1 card.ability.extra.probability = card.ability.extra.probability + card.ability.extra.delta
end end
end, end,
} }
SMODS.Joker { SMODS.Joker {
key = "temp4", key = "estrogen",
atlas = "void", atlas = "void",
pronouns = "they_them", pronouns = "they_them",
pos = {x = 0, y = 0}, pos = {x = 0, y = 0},
cost = 8, cost = 6,
rarity = 3, rarity = 2,
calculate = function(_, _, context) calculate = function(_, _, context)
return context.joker_main and {mult = hand_chips} or nil return context.joker_main and {mult = hand_chips} or nil
end, end,
} }
SMODS.Joker { SMODS.Joker {
key = "temp5", key = "sunny", -- Cracked egg
atlas = "void", atlas = "void",
pronouns = "they_them", pronouns = "they_them",
pos = {x = 0, y = 0}, pos = {x = 0, y = 0},
cost = 2, cost = 2,
rarity = 1, rarity = 1,
eternal_compat = false,
loc_vars = function(_, _, card)
local last = ((G.deck or {}).cards or {})[1]
if last or card.area ~= G.jokers then
return {
vars = {
"",
localize {type = "variable", key = "b_Roland_na"},
"",
colours = {G.C.JOKER_GREY, G.C.JOKER_GREY},
},
}
end
local suit = last.base.suit
local value = last.base.value
local name = last.ability.name or ""
local no_rank = SMODS.has_no_rank(last)
local no_suit = SMODS.has_no_suit(last)
return {
vars = {
value and not no_rank and localize(value or 14, "ranks") or name,
not no_rank and not no_suit and localize {type = "variable", key = "b_Roland_of"} or "",
no_suit and "" or localize(suit, "suits_plural"),
colours = {G.C.IMPORTANT, G.C.SUITS[suit] or G.C.JOKER_GREY},
},
}
end,
calculate = function(_, _, context) calculate = function(_, _, context)
local _ = context.selling_self and local _ = context.selling_self and
draw_card(G.deck, G.hand, 100, "up", false, G.deck.cards[#G.deck.cards]) draw_card(G.deck, G.hand, 100, "up", false, G.deck.cards[1])
end, end,
} }
SMODS.Joker { SMODS.Joker {
key = "temp6", key = "yard",
atlas = "void", atlas = "void",
pronouns = "they_them", pronouns = "they_them",
pos = {x = 0, y = 0}, pos = {x = 0, y = 0},
@ -302,12 +343,12 @@ SMODS.Joker {
} }
SMODS.Joker { SMODS.Joker {
key = "temp7", key = "hexagon",
atlas = "void", atlas = "void",
pronouns = "they_them", pronouns = "they_them",
pos = {x = 0, y = 0}, pos = {x = 0, y = 0},
config = {extra = {money = 2}}, config = {extra = {money = 2}},
cost = 3, cost = 4,
rarity = 1, rarity = 1,
loc_vars = function(_, _, card) loc_vars = function(_, _, card)
return {vars = {card.ability.extra.money}} return {vars = {card.ability.extra.money}}
@ -320,13 +361,16 @@ SMODS.Joker {
} }
SMODS.Joker { SMODS.Joker {
key = "temp8", key = "hexagoner",
atlas = "void", atlas = "void",
pronouns = "they_them", pronouns = "they_them",
pos = {x = 0, y = 0}, pos = {x = 0, y = 0},
config = {extra = {mult = 0}}, config = {extra = {mult = 0}},
cost = 8, cost = 6,
rarity = 2, rarity = 2,
loc_vars = function(_, _, card)
return {vars = {card.ability.extra.mult}}
end,
calculate = function(_, card, context) calculate = function(_, card, context)
if context.joker_main then if context.joker_main then
return {mult = card.ability.extra.mult} return {mult = card.ability.extra.mult}
@ -341,7 +385,7 @@ SMODS.Joker {
} }
SMODS.Joker { SMODS.Joker {
key = "temp9", key = "hexagonest",
atlas = "void", atlas = "void",
pronouns = "they_them", pronouns = "they_them",
pos = {x = 0, y = 0}, pos = {x = 0, y = 0},
@ -371,13 +415,16 @@ SMODS.Joker {
} }
SMODS.Joker { SMODS.Joker {
key = "temp10", key = "temple",
atlas = "void", atlas = "void",
pronouns = "they_them", pronouns = "they_them",
pos = {x = 0, y = 0}, pos = {x = 0, y = 0},
config = {extra = {xmult = 1.5}}, config = {extra = {xmult = 1.5}},
cost = 8, cost = 6,
rarity = 3, rarity = 2,
loc_vars = function(_, _, card)
return {vars = {card.ability.extra.xmult}}
end,
calculate = function(_, card, context) calculate = function(_, card, context)
if context.individual and if context.individual and
context.cardarea == "unscored" and context.cardarea == "unscored" and
@ -388,7 +435,7 @@ SMODS.Joker {
} }
SMODS.Joker { SMODS.Joker {
key = "negative", key = "misfortune",
atlas = "void", atlas = "void",
pronouns = "they_them", pronouns = "they_them",
pos = {x = 0, y = 0}, pos = {x = 0, y = 0},
@ -396,26 +443,125 @@ SMODS.Joker {
rarity = 2, rarity = 2,
} }
SMODS.Joker {
key = "rigged",
atlas = "void",
config = {extra = {level = "1"}}, -- Strings do not get mutated by other mods, hopefully.
pos = {x = 0, y = 0},
eternal_compat = false,
cost = 8,
rarity = 2,
loc_vars = function(_, _, card)
return {vars = {}}
end,
}
---@diagnostic disable-next-line: undefined-global
local rarities = Cryptid and
{{1, "Common"}, {2, "Uncommon"}, {3, "Rare"}, {"cry_epic"}, {4, "Legendary"}, {"cry_exotic"}} or
{{1, "Common"}, {2, "Uncommon"}, {3, "Rare"}, {4, "Legendary"}}
local orig_poll_rarity = SMODS.poll_rarity
---@diagnostic disable-next-line: duplicate-set-field
function SMODS.poll_rarity(_pool_key, _rand_key)
local rarity = orig_poll_rarity(_pool_key, _rand_key)
local max = f(SMODS.find_card "j_Roland_rigged"):reduce(0, function(a, n)
return n.debuff and a or math.max(a, tonumber(n.ability.extra.level))
end)
if f(rarities, ipairs):take(max):filter(function(v)
return f(v):any(function(vv)
return vv == rarity
end)
end):any() then
return rarities[max + 1][1] or rarities[#rarities][1]
end
return rarity
end
local orig_update = Game.update
---@diagnostic disable-next-line: duplicate-set-field
function Game:update(dt)
orig_update(self, dt)
if not G.GAME then
return
end
local candidates = {}
local max = f(SMODS.find_card "j_Roland_rigged"):reduce(1, function(a, n)
local level = tonumber(n.ability.extra.level) or 1
if not candidates[level] then
candidates[level] = n
elseif level == 1 then
candidates[0] = n
end
return math.max(a, level)
end)
for i = math.min(max, #rarities - 2), 1, -1 do
if not candidates[i] then
goto continue
end
local skip = true
for j = i - 1, i == 1 and 0 or 1, -1 do
if not candidates[j] then
break
end
skip = j > 1
end
if skip then
goto continue
end
for j = i - 1, i == 1 and 0 or 1, -1 do
candidates[i].sell_cost = candidates[i].sell_cost + candidates[j].sell_cost
candidates[j].ability.extra.level = "-1"
candidates[j]:start_dissolve()
end
local extra = candidates[i].ability.extra
local level = tonumber(extra.level)
extra.level = tostring(level + 1)
candidates[i].children.center:set_sprite_pos({x = 0, y = math.min(level or 0, 2)})
play_sound("Roland_milestone", 0.9 ^ (level - 2))
::continue::
end
end
SMODS.Joker { SMODS.Joker {
key = "mrsbones", key = "mrsbones",
atlas = "void", atlas = "void",
pronouns = "they_them", pronouns = "they_them",
pos = {x = 0, y = 0}, pos = {x = 0, y = 0},
config = {extra = {xmult = 4}}, config = {extra = {xmult = 4, requirement = 4}},
cost = 8, cost = 4,
rarity = 3, rarity = 2,
loc_vars = function(_, _, card)
return {vars = {card.ability.extra.xmult, card.ability.extra.requirement * 100}}
end,
calculate = function(_, card, context) calculate = function(_, card, context)
if context.joker_main then if context.joker_main then
return {xmult = card.ability.extra.xmult} return {xmult = card.ability.extra.xmult}
end end
if context.blind_defeated and G.GAME.chips / card.ability.extra.xmult < G.GAME.blind.chips then if context.blind_defeated and G.GAME.chips / card.ability.extra.requirement < G.GAME.blind.chips then
q(function() q(function()
G.hand_text_area.blind_chips:juice_up() G.hand_text_area.blind_chips:juice_up()
G.hand_text_area.game_chips:juice_up() G.hand_text_area.game_chips:juice_up()
play_sound("tarot1") play_sound("tarot1")
card:start_dissolve() card:start_dissolve()
return true
end) end)
end end
end, end,

View file

@ -8,11 +8,9 @@ local f, q = unpack(... or require "src.functional")
-- } -- }
SMODS.Seal { SMODS.Seal {
key = "glass", key = "glass",
name = "RolandGlass",
badge_colour = HEX "12f254",
atlas = "void", atlas = "void",
pos = {x = 0, y = 0}, pos = {x = 0, y = 0},
config = {ready = true}, badge_colour = HEX "f6f6f6",
calculate = function(_, card, context) calculate = function(_, card, context)
if context.setting_blind or context.starting_shop then if context.setting_blind or context.starting_shop then
card.Roland_glass = nil card.Roland_glass = nil

View file

@ -79,7 +79,7 @@ SMODS.Consumable {
} }
SMODS.Consumable { SMODS.Consumable {
key = "glass", key = "mirror",
set = "Spectral", set = "Spectral",
pos = {x = 0, y = 0}, pos = {x = 0, y = 0},
cost = 6, cost = 6,