2238 lines
82 KiB
Lua
2238 lines
82 KiB
Lua
LOVELY_INTEGRITY = '7af2e0e0690a3e982bc378e0f2810cf02634e614841ab27a2036b576c0fdc825'
|
|
|
|
--Updates all display information for all displays for a given screenmode. Returns the key for the resolution option cycle
|
|
--
|
|
---@param screenmode string optional arg for one of 'Windowed', 'Fullscreen', or 'Borderless'
|
|
---@param display number optional arg to match fullscreen resolution with only the current display
|
|
function GET_DISPLAYINFO(screenmode, display)
|
|
--default the display to the current display, otherwise we need to return all available modes for the selected display
|
|
display = display or G.SETTINGS.WINDOW.selcted_display or 1
|
|
|
|
--default to current mode/'windowed', otherwise return all available options for specified mode
|
|
screenmode = screenmode or G.SETTINGS.WINDOW.screenmode or 'Windowed'
|
|
|
|
--Get a count of the connected displays and iterate through them to update our window setting options accordingly
|
|
local display_count = love.window.getDisplayCount()
|
|
local res_option = 1 --This is the mode that the fullscreen option will default to for resolution, if we can find it in the list for the current monitor
|
|
local realw, realh = love.window.getMode() --the actual render resolution the window is currently using
|
|
local current_res_values = {w = realw, h = realh}
|
|
|
|
--reset names to populate for displays
|
|
G.SETTINGS.WINDOW.display_names = {}
|
|
|
|
for i = 1, display_count do
|
|
--reset the screen resolution table for this display and set the name
|
|
G.SETTINGS.WINDOW.DISPLAYS[i] = {}
|
|
G.SETTINGS.WINDOW.DISPLAYS[i].screen_resolutions = {
|
|
strings = {},
|
|
values = {},
|
|
}
|
|
G.SETTINGS.WINDOW.display_names[i] = ''..i
|
|
|
|
--Get the render resolution and desktop resolution, this is a workaround to a known OpenGL issue where windows doesn't supply the correct DPI scaling factor
|
|
local render_w, render_h = love.window.getDesktopDimensions(i)
|
|
local unscaled_dims = love.window.getFullscreenModes(i)[1]
|
|
|
|
--determine the DPI scale here, this can be used to determine the actual render resolution per display
|
|
G.SETTINGS.WINDOW.DISPLAYS[i].DPI_scale = 1--math.floor((0.5*unscaled_dims.width/render_w + 0.5*unscaled_dims.height/render_h)*500 + 0.5)/500
|
|
G.SETTINGS.WINDOW.DISPLAYS[i].MONITOR_DIMS = unscaled_dims
|
|
|
|
if screenmode == 'Fullscreen' then --Iterate through all possible screenmodes and populate the screen_resolutions table
|
|
--if the real resolution of the window is found, make sure we return that value
|
|
for _, v in ipairs(love.window.getFullscreenModes(i)) do
|
|
local _w, _h = v.width*G.SETTINGS.WINDOW.DISPLAYS[i].DPI_scale, v.height*G.SETTINGS.WINDOW.DISPLAYS[i].DPI_scale
|
|
if _w <= G.SETTINGS.WINDOW.DISPLAYS[i].MONITOR_DIMS.width and _h <= G.SETTINGS.WINDOW.DISPLAYS[i].MONITOR_DIMS.height then
|
|
G.SETTINGS.WINDOW.DISPLAYS[i].screen_resolutions.strings[#G.SETTINGS.WINDOW.DISPLAYS[i].screen_resolutions.strings+1] = ''..v.width..' X '..v.height
|
|
G.SETTINGS.WINDOW.DISPLAYS[i].screen_resolutions.values[#G.SETTINGS.WINDOW.DISPLAYS[i].screen_resolutions.values+1] = {w = v.width, h = v.height}
|
|
if i == G.SETTINGS.WINDOW.selected_display and i == display and current_res_values.w == v.width and current_res_values.h == v.height then
|
|
res_option = #G.SETTINGS.WINDOW.DISPLAYS[i].screen_resolutions.values
|
|
end
|
|
end
|
|
end
|
|
elseif screenmode == 'Windowed' then
|
|
G.SETTINGS.WINDOW.DISPLAYS[i].screen_resolutions.strings[1] = '-'
|
|
G.SETTINGS.WINDOW.DISPLAYS[i].screen_resolutions.values[1] = {w = 1280, h = 720}
|
|
elseif screenmode == 'Borderless' then
|
|
G.SETTINGS.WINDOW.DISPLAYS[i].screen_resolutions.strings[1] =
|
|
''..G.SETTINGS.WINDOW.DISPLAYS[i].MONITOR_DIMS.width/G.SETTINGS.WINDOW.DISPLAYS[i].DPI_scale..' X '
|
|
..G.SETTINGS.WINDOW.DISPLAYS[i].MONITOR_DIMS.height/G.SETTINGS.WINDOW.DISPLAYS[i].DPI_scale
|
|
G.SETTINGS.WINDOW.DISPLAYS[i].screen_resolutions.values[1] = current_res_values
|
|
end
|
|
end
|
|
return res_option
|
|
end
|
|
|
|
function timer_checkpoint(label, type, reset)
|
|
G.PREV_GARB = G.PREV_GARB or 0
|
|
if not G.F_ENABLE_PERF_OVERLAY then return end
|
|
G.check = G.check or {
|
|
draw = {
|
|
checkpoint_list = {},
|
|
checkpoints = 0,
|
|
last_time = 0,
|
|
},
|
|
update = {
|
|
checkpoint_list = {},
|
|
checkpoints = 0,
|
|
last_time = 0,
|
|
}
|
|
}
|
|
local cp = G.check[type]
|
|
if reset then
|
|
cp.last_time = love.timer.getTime()
|
|
cp.checkpoints = 0
|
|
return
|
|
end
|
|
|
|
cp.checkpoint_list[cp.checkpoints+1] = cp.checkpoint_list[cp.checkpoints+1] or {}
|
|
cp.checkpoints = cp.checkpoints+1
|
|
cp.checkpoint_list[cp.checkpoints].label = label..': '..(collectgarbage( "count" ) - G.PREV_GARB)
|
|
cp.checkpoint_list[cp.checkpoints].time = love.timer.getTime()
|
|
cp.checkpoint_list[cp.checkpoints].TTC = cp.checkpoint_list[cp.checkpoints].time - cp.last_time
|
|
cp.checkpoint_list[cp.checkpoints].trend = cp.checkpoint_list[cp.checkpoints].trend or {}
|
|
cp.checkpoint_list[cp.checkpoints].states = cp.checkpoint_list[cp.checkpoints].states or {}
|
|
table.insert(cp.checkpoint_list[cp.checkpoints].trend, 1, cp.checkpoint_list[cp.checkpoints].TTC)
|
|
table.insert(cp.checkpoint_list[cp.checkpoints].states, 1, G.STATE)
|
|
cp.checkpoint_list[cp.checkpoints].trend[401] = nil
|
|
cp.checkpoint_list[cp.checkpoints].states[401] = nil
|
|
cp.last_time = cp.checkpoint_list[cp.checkpoints].time
|
|
G.PREV_GARB = collectgarbage( "count" )
|
|
local av = 0
|
|
for k, v in ipairs(cp.checkpoint_list[cp.checkpoints].trend) do
|
|
av = av + v/#cp.checkpoint_list[cp.checkpoints].trend
|
|
end
|
|
cp.checkpoint_list[cp.checkpoints].average = av
|
|
end
|
|
|
|
function boot_timer(_label, _next, progress)
|
|
progress = progress or 0
|
|
G.LOADING = G.LOADING or {
|
|
font = love.graphics.setNewFont("resources/fonts/m6x11plus.ttf", 20),
|
|
love.graphics.dis
|
|
}
|
|
local realw, realh = love.window.getMode()
|
|
love.graphics.setCanvas()
|
|
love.graphics.push()
|
|
love.graphics.setShader()
|
|
love.graphics.clear(0,0,0,1)
|
|
love.graphics.setColor(0.6, 0.8, 0.9,1)
|
|
if progress > 0 then love.graphics.rectangle('fill', realw/2 - 150, realh/2 - 15, progress*300, 30, 5) end
|
|
love.graphics.setColor(1, 1, 1,1)
|
|
love.graphics.setLineWidth(3)
|
|
love.graphics.rectangle('line', realw/2 - 150, realh/2 - 15, 300, 30, 5)
|
|
if G.F_VERBOSE and not _RELEASE_MODE then love.graphics.print("LOADING: ".._next, realw/2 - 150, realh/2 +40) end
|
|
love.graphics.pop()
|
|
love.graphics.present()
|
|
|
|
G.ARGS.bt = G.ARGS.bt or love.timer.getTime()
|
|
G.ARGS.bt = love.timer.getTime()
|
|
end
|
|
|
|
function EMPTY(t)
|
|
if not t then return {} end
|
|
for k, v in pairs(t) do
|
|
t[k] = nil
|
|
end
|
|
return t
|
|
end
|
|
|
|
function interp(per, max, min)
|
|
min = min or 0
|
|
if per and max then
|
|
return per*(max - min) + min
|
|
end
|
|
end
|
|
|
|
function remove_all(t)
|
|
for i=#t, 1, -1 do
|
|
local v=t[i]
|
|
table.remove(t, i)
|
|
if v and v.children then
|
|
remove_all(v.children)
|
|
end
|
|
if v then v:remove() end
|
|
v = nil
|
|
end
|
|
for _, v in pairs(t) do
|
|
if v.children then remove_all(v.children) end
|
|
v:remove()
|
|
v = nil
|
|
end
|
|
end
|
|
|
|
function Vector_Dist(trans1, trans2, mid)
|
|
local x = trans1.x - trans2.x + (mid and 0.5*(trans1.w-trans2.w) or 0)
|
|
local y = trans1.y - trans2.y + (mid and 0.5*(trans1.h-trans2.h) or 0)
|
|
return math.sqrt((x)*(x) + (y)*(y))
|
|
end
|
|
|
|
function Vector_Len(trans1)
|
|
return math.sqrt((trans1.x)*(trans1.x) + (trans1.y)*(trans1.y))
|
|
end
|
|
|
|
function Vector_Sub(trans1, trans2)
|
|
return {x = trans1.x - trans2.x, y = trans1.y - trans2.y}
|
|
end
|
|
|
|
function get_index(t, val)
|
|
local index = nil
|
|
for i, v in pairs(t) do
|
|
if v == val then
|
|
index = i
|
|
end
|
|
end
|
|
return index
|
|
end
|
|
|
|
function table_length(t)
|
|
local count = 0
|
|
for _ in pairs(t) do count = count + 1 end
|
|
return count
|
|
end
|
|
|
|
function remove_nils(t)
|
|
local ans = {}
|
|
for _,v in pairs(t) do
|
|
ans[ #ans+1 ] = v
|
|
end
|
|
return ans
|
|
end
|
|
|
|
function SWAP(t, i, j)
|
|
if not t or not i or not j then return end
|
|
local temp = t[i]
|
|
t[i] = t[j]
|
|
t[j] = temp
|
|
end
|
|
|
|
function pseudoshuffle(list, seed)
|
|
if seed then math.randomseed(seed) end
|
|
|
|
if list[1] and list[1].sort_id then
|
|
table.sort(list, function (a, b) return (a.sort_id or 1) < (b.sort_id or 2) end)
|
|
end
|
|
|
|
for i = #list, 2, -1 do
|
|
local j = math.random(i)
|
|
list[i], list[j] = list[j], list[i]
|
|
end
|
|
end
|
|
|
|
function generate_starting_seed()
|
|
if G.GAME.stake >= #G.P_CENTER_POOLS['Stake'] then
|
|
local r_leg, r_tally = {}, 0
|
|
local g_leg, g_tally = {}, 0
|
|
for k, v in pairs(G.P_JOKER_RARITY_POOLS[4]) do
|
|
local win_ante = get_joker_win_sticker(v, true)
|
|
if win_ante and (win_ante >= 8) or (v.in_pool and type(v.in_pool) == 'function' and not v:in_pool()) then
|
|
g_leg[v.key] = true
|
|
g_tally = g_tally + 1
|
|
else
|
|
r_leg[v.key] = true
|
|
r_tally = r_tally + 1
|
|
end
|
|
end
|
|
if r_tally > 0 and g_tally > 0 then
|
|
local seed_found = nil
|
|
local extra_num = 0
|
|
while not seed_found do
|
|
extra_num = extra_num + 0.561892350821
|
|
seed_found = random_string(8, extra_num + G.CONTROLLER.cursor_hover.T.x*0.33411983 + G.CONTROLLER.cursor_hover.T.y*0.874146 + 0.412311010*G.CONTROLLER.cursor_hover.time)
|
|
if not r_leg[get_first_legendary(seed_found)] then seed_found = nil end
|
|
end
|
|
return seed_found
|
|
end
|
|
end
|
|
|
|
return random_string(8, G.CONTROLLER.cursor_hover.T.x*0.33411983 + G.CONTROLLER.cursor_hover.T.y*0.874146 + 0.412311010*G.CONTROLLER.cursor_hover.time)
|
|
end
|
|
|
|
function get_first_legendary(_key)
|
|
local _t, key = pseudorandom_element(G.P_JOKER_RARITY_POOLS[4], pseudoseed('Joker4', _key))
|
|
return _t.key
|
|
end
|
|
|
|
function pseudorandom_element(_t, seed, args)
|
|
-- TODO special cases for now
|
|
-- Preserves reverse nominal order for Suits, nominal+face_nominal order for Ranks
|
|
-- for vanilla RNG
|
|
if _t == SMODS.Suits then
|
|
_t = SMODS.Suit:obj_list(true)
|
|
end
|
|
if _t == SMODS.Ranks then
|
|
_t = SMODS.Rank:obj_list()
|
|
end
|
|
if seed then math.randomseed(seed) end
|
|
local keys = {}
|
|
for k, v in pairs(_t) do
|
|
local keep = true
|
|
local in_pool_func =
|
|
args and args.in_pool
|
|
or type(v) == 'table' and type(v.in_pool) == 'function' and v.in_pool
|
|
or _t == G.P_CARDS and function(c)
|
|
--Handles special case for Erratic Deck
|
|
local initial_deck = args and args.starting_deck or false
|
|
|
|
return not (
|
|
type(SMODS.Ranks[c.value].in_pool) == 'function' and not SMODS.Ranks[c.value]:in_pool({initial_deck = initial_deck, suit = c.suit})
|
|
or type(SMODS.Suits[c.suit].in_pool) == 'function' and not SMODS.Suits[c.suit]:in_pool({initial_deck = initial_deck, rank = c.value})
|
|
)
|
|
end
|
|
if in_pool_func then
|
|
keep = in_pool_func(v, args)
|
|
end
|
|
if keep then
|
|
keys[#keys+1] = {k = k,v = v}
|
|
end
|
|
end
|
|
|
|
if keys[1] and keys[1].v and type(keys[1].v) == 'table' and keys[1].v.sort_id then
|
|
table.sort(keys, function (a, b) return a.v.sort_id < b.v.sort_id end)
|
|
else
|
|
table.sort(keys, function (a, b) return a.k < b.k end)
|
|
end
|
|
|
|
if #keys == 0 then return nil, nil end
|
|
local key = keys[math.random(#keys)].k
|
|
return _t[key], key
|
|
end
|
|
|
|
function random_string(length, seed)
|
|
if seed then math.randomseed(seed) end
|
|
local ret = ''
|
|
for i = 1, length do
|
|
ret = ret..string.char(math.random() > 0.7 and math.random(string.byte('1'),string.byte('9')) or (math.random() > 0.45 and math.random(string.byte('A'),string.byte('N')) or math.random(string.byte('P'),string.byte('Z'))))
|
|
end
|
|
return string.upper(ret)
|
|
end
|
|
|
|
function pseudohash(str)
|
|
if true then
|
|
local num = 1
|
|
for i=#str, 1, -1 do
|
|
num = ((1.1239285023/num)*string.byte(str, i)*math.pi + math.pi*i)%1
|
|
end
|
|
return num
|
|
else
|
|
str = string.sub(string.format("%-16s",str), 1, 24)
|
|
|
|
local h = 0
|
|
|
|
for i=#str, 1, -1 do
|
|
h = bit.bxor(h, bit.lshift(h, 7) + bit.rshift(h, 3) + string.byte(str, i))
|
|
end
|
|
return tonumber(string.format("%.13f",math.sqrt(math.abs(h))%1))
|
|
end
|
|
end
|
|
|
|
function pseudoseed(key, predict_seed)
|
|
if key == 'seed' then return math.random() end
|
|
|
|
if predict_seed then
|
|
local _pseed = pseudohash(key..(predict_seed or ''))
|
|
_pseed = math.abs(tonumber(string.format("%.13f", (2.134453429141+_pseed*1.72431234)%1)))
|
|
return (_pseed + (pseudohash(predict_seed) or 0))/2
|
|
end
|
|
|
|
if not G.GAME.pseudorandom[key] then
|
|
G.GAME.pseudorandom[key] = pseudohash(key..(G.GAME.pseudorandom.seed or ''))
|
|
end
|
|
|
|
G.GAME.pseudorandom[key] = math.abs(tonumber(string.format("%.13f", (2.134453429141+G.GAME.pseudorandom[key]*1.72431234)%1)))
|
|
return (G.GAME.pseudorandom[key] + (G.GAME.pseudorandom.hashed_seed or 0))/2
|
|
end
|
|
|
|
function pseudorandom(seed, min, max)
|
|
if type(seed) == 'string' then seed = pseudoseed(seed) end
|
|
math.randomseed(seed)
|
|
if min and max then return math.random(min, max)
|
|
else return math.random() end
|
|
end
|
|
|
|
function tprint(tbl, indent)
|
|
if not indent then indent = 0 end
|
|
local toprint = string.rep(" ", indent) .. "{\r\n"
|
|
indent = indent + 2
|
|
for k, v in pairs(tbl) do
|
|
toprint = toprint .. string.rep(" ", indent)
|
|
if (type(k) == "number") then
|
|
toprint = toprint .. "[" .. k .. "] = "
|
|
elseif (type(k) == "string") then
|
|
toprint = toprint .. k .. "= "
|
|
end
|
|
if (type(v) == "number") then
|
|
toprint = toprint .. v .. ",\r\n"
|
|
elseif (type(v) == "string") then
|
|
toprint = toprint .. "\"" .. v .. "\",\r\n"
|
|
elseif (type(v) == "table") then
|
|
if indent>=10 then
|
|
toprint = toprint .. tostring(v) .. ",\r\n"
|
|
else
|
|
toprint = toprint .. tostring(v) .. tprint(v, indent + 1) .. ",\r\n"
|
|
end
|
|
else
|
|
toprint = toprint .. "\"" .. tostring(v) .. "\",\r\n"
|
|
end
|
|
end
|
|
toprint = toprint .. string.rep(" ", indent-2) .. "}"
|
|
return toprint
|
|
end
|
|
|
|
function sortingFunction(e1, e2)
|
|
return e1.order < e2.order
|
|
end
|
|
|
|
function HEX(hex)
|
|
if #hex <= 6 then hex = hex.."FF" end
|
|
local _,_,r,g,b,a = hex:find('(%x%x)(%x%x)(%x%x)(%x%x)')
|
|
local color = {tonumber(r,16)/255,tonumber(g,16)/255,tonumber(b,16)/255,tonumber(a,16)/255 or 255}
|
|
return color
|
|
end
|
|
|
|
function get_blind_main_colour(blind) --either in the form of the blind key for the P_BLINDS table or type
|
|
local disabled = false
|
|
blind = blind or ''
|
|
if blind == 'Boss' or blind == 'Small' or blind == 'Big' then
|
|
G.GAME.round_resets.blind_states = G.GAME.round_resets.blind_states or {}
|
|
if G.GAME.round_resets.blind_states[blind] == 'Defeated' or G.GAME.round_resets.blind_states[blind] == 'Skipped' then disabled = true end
|
|
blind = G.GAME.round_resets.blind_choices[blind]
|
|
end
|
|
return (disabled or not G.P_BLINDS[blind]) and G.C.BLACK or
|
|
G.P_BLINDS[blind].boss_colour or
|
|
(blind == 'bl_small' and mix_colours(G.C.BLUE, G.C.BLACK, 0.6) or
|
|
blind == 'bl_big' and mix_colours(G.C.ORANGE, G.C.BLACK, 0.6)) or G.C.BLACK
|
|
end
|
|
|
|
function evaluate_poker_hand(hand)
|
|
|
|
local results = {
|
|
["Flush Five"] = {},
|
|
["Flush House"] = {},
|
|
["Five of a Kind"] = {},
|
|
["Straight Flush"] = {},
|
|
["Four of a Kind"] = {},
|
|
["Full House"] = {},
|
|
["Flush"] = {},
|
|
["Straight"] = {},
|
|
["Three of a Kind"] = {},
|
|
["Two Pair"] = {},
|
|
["Pair"] = {},
|
|
["High Card"] = {},
|
|
top = nil
|
|
}
|
|
|
|
for _,v in ipairs(SMODS.PokerHand.obj_buffer) do
|
|
results[v] = {}
|
|
end
|
|
local parts = {
|
|
_5 = get_X_same(5,hand),
|
|
_4 = get_X_same(4,hand),
|
|
_3 = get_X_same(3,hand),
|
|
_2 = get_X_same(2,hand),
|
|
_flush = get_flush(hand),
|
|
_straight = get_straight(hand),
|
|
_highest = get_highest(hand)
|
|
}
|
|
|
|
for _,_hand in pairs(SMODS.PokerHands) do
|
|
if _hand.atomic_part and type(_hand.atomic_part) == 'function' then
|
|
parts[_hand.key] = _hand.atomic_part(hand)
|
|
end
|
|
end
|
|
if next(parts._5) and next(parts._flush) then
|
|
results["Flush Five"] = parts._5
|
|
if not results.top then results.top = results["Flush Five"] end
|
|
end
|
|
|
|
if next(parts._3) and next(parts._2) and next(parts._flush) then
|
|
local fh_hand = {}
|
|
local fh_3 = parts._3[1]
|
|
local fh_2 = parts._2[1]
|
|
for i=1, #fh_3 do
|
|
fh_hand[#fh_hand+1] = fh_3[i]
|
|
end
|
|
for i=1, #fh_2 do
|
|
fh_hand[#fh_hand+1] = fh_2[i]
|
|
end
|
|
table.insert(results["Flush House"], fh_hand)
|
|
if not results.top then results.top = results["Flush House"] end
|
|
end
|
|
|
|
if next(parts._5) then
|
|
results["Five of a Kind"] = parts._5
|
|
if not results.top then results.top = results["Five of a Kind"] end
|
|
end
|
|
|
|
if next(parts._flush) and next(parts._straight) then
|
|
local _s, _f, ret = parts._straight, parts._flush, {}
|
|
for _, v in ipairs(_f[1]) do
|
|
ret[#ret+1] = v
|
|
end
|
|
for _, v in ipairs(_s[1]) do
|
|
local in_straight = nil
|
|
for _, vv in ipairs(_f[1]) do
|
|
if vv == v then in_straight = true end
|
|
end
|
|
if not in_straight then ret[#ret+1] = v end
|
|
end
|
|
|
|
results["Straight Flush"] = {ret}
|
|
if not results.top then results.top = results["Straight Flush"] end
|
|
end
|
|
|
|
if next(parts._4) then
|
|
results["Four of a Kind"] = parts._4
|
|
if not results.top then results.top = results["Four of a Kind"] end
|
|
end
|
|
|
|
if next(parts._3) and next(parts._2) then
|
|
local fh_hand = {}
|
|
local fh_3 = parts._3[1]
|
|
local fh_2 = parts._2[1]
|
|
for i=1, #fh_3 do
|
|
fh_hand[#fh_hand+1] = fh_3[i]
|
|
end
|
|
for i=1, #fh_2 do
|
|
fh_hand[#fh_hand+1] = fh_2[i]
|
|
end
|
|
table.insert(results["Full House"], fh_hand)
|
|
if not results.top then results.top = results["Full House"] end
|
|
end
|
|
|
|
if next(parts._flush) then
|
|
results["Flush"] = parts._flush
|
|
if not results.top then results.top = results["Flush"] end
|
|
end
|
|
|
|
if next(parts._straight) then
|
|
results["Straight"] = parts._straight
|
|
if not results.top then results.top = results["Straight"] end
|
|
end
|
|
|
|
if next(parts._3) then
|
|
results["Three of a Kind"] = parts._3
|
|
if not results.top then results.top = results["Three of a Kind"] end
|
|
end
|
|
|
|
if (#parts._2 == 2) or (#parts._3 == 1 and #parts._2 == 1) then
|
|
local fh_hand = {}
|
|
local r = parts._2
|
|
local fh_2a = r[1]
|
|
local fh_2b = r[2]
|
|
if not fh_2b then
|
|
fh_2b = parts._3[1]
|
|
end
|
|
for i=1, #fh_2a do
|
|
fh_hand[#fh_hand+1] = fh_2a[i]
|
|
end
|
|
for i=1, #fh_2b do
|
|
fh_hand[#fh_hand+1] = fh_2b[i]
|
|
end
|
|
table.insert(results["Two Pair"], fh_hand)
|
|
if not results.top then results.top = results["Two Pair"] end
|
|
end
|
|
|
|
if next(parts._2) then
|
|
results["Pair"] = parts._2
|
|
if not results.top then results.top = results["Pair"] end
|
|
end
|
|
|
|
if next(parts._highest) then
|
|
results["High Card"] = parts._highest
|
|
if not results.top then results.top = results["High Card"] end
|
|
end
|
|
|
|
if results["Five of a Kind"][1] then
|
|
results["Four of a Kind"] = {results["Five of a Kind"][1], results["Five of a Kind"][2], results["Five of a Kind"][3], results["Five of a Kind"][4]}
|
|
end
|
|
|
|
if results["Four of a Kind"][1] then
|
|
results["Three of a Kind"] = {results["Four of a Kind"][1], results["Four of a Kind"][2], results["Four of a Kind"][3]}
|
|
end
|
|
|
|
if results["Three of a Kind"][1] then
|
|
results["Pair"] = {results["Three of a Kind"][1], results["Three of a Kind"][2]}
|
|
end
|
|
|
|
for _,_hand in pairs(SMODS.PokerHands) do
|
|
if _hand.composite and type(_hand.composite) == 'function' then
|
|
local other_hands
|
|
results[_hand.key], other_hands = _hand.composite(parts)
|
|
results[_hand.key] = results[_hand.key] or {}
|
|
if other_hands and type(other_hands) == 'table' then
|
|
for k, v in pairs(other_hands) do
|
|
results[k] = v
|
|
end
|
|
end
|
|
else
|
|
results[_hand.key] = parts[_hand.key]
|
|
end
|
|
end
|
|
results.top = nil
|
|
for _, v in ipairs(G.handlist) do
|
|
if not results.top and results[v] then
|
|
results.top = results[v]
|
|
break
|
|
end
|
|
end
|
|
return results
|
|
end
|
|
|
|
function get_flush(hand)
|
|
local ret = {}
|
|
local four_fingers = next(find_joker('Four Fingers'))
|
|
local suits = SMODS.Suit.obj_buffer
|
|
if #hand < (5 - (four_fingers and 1 or 0)) then return ret else
|
|
for j = 1, #suits do
|
|
local t = {}
|
|
local suit = suits[j]
|
|
local flush_count = 0
|
|
for i=1, #hand do
|
|
if hand[i]:is_suit(suit, nil, true) then flush_count = flush_count + 1; t[#t+1] = hand[i] end
|
|
end
|
|
if flush_count >= (5 - (four_fingers and 1 or 0)) then
|
|
table.insert(ret, t)
|
|
return ret
|
|
end
|
|
end
|
|
return {}
|
|
end
|
|
end
|
|
|
|
function get_straight(hand)
|
|
local ret = {}
|
|
local four_fingers = next(find_joker('Four Fingers'))
|
|
if #hand > 5 or #hand < (5 - (four_fingers and 1 or 0)) then return ret else
|
|
local t = {}
|
|
local IDS = {}
|
|
for i=1, #hand do
|
|
local id = hand[i]:get_id()
|
|
if id > 1 and id < 15 then
|
|
if IDS[id] then
|
|
IDS[id][#IDS[id]+1] = hand[i]
|
|
else
|
|
IDS[id] = {hand[i]}
|
|
end
|
|
end
|
|
end
|
|
|
|
local straight_length = 0
|
|
local straight = false
|
|
local can_skip = next(find_joker('Shortcut'))
|
|
local skipped_rank = false
|
|
for j = 1, 14 do
|
|
if IDS[j == 1 and 14 or j] then
|
|
straight_length = straight_length + 1
|
|
skipped_rank = false
|
|
for k, v in ipairs(IDS[j == 1 and 14 or j]) do
|
|
t[#t+1] = v
|
|
end
|
|
elseif can_skip and not skipped_rank and j ~= 14 then
|
|
skipped_rank = true
|
|
else
|
|
straight_length = 0
|
|
skipped_rank = false
|
|
if not straight then t = {} end
|
|
if straight then break end
|
|
end
|
|
if straight_length >= (5 - (four_fingers and 1 or 0)) then straight = true end
|
|
end
|
|
if not straight then return ret end
|
|
table.insert(ret, t)
|
|
return ret
|
|
end
|
|
end
|
|
|
|
function get_X_same(num, hand, or_more)
|
|
local vals = {}
|
|
for i = 1, SMODS.Rank.max_id.value do
|
|
vals[i] = {}
|
|
end
|
|
for i=#hand, 1, -1 do
|
|
local curr = {}
|
|
table.insert(curr, hand[i])
|
|
for j=1, #hand do
|
|
if hand[i]:get_id() == hand[j]:get_id() and i ~= j then
|
|
table.insert(curr, hand[j])
|
|
end
|
|
end
|
|
if or_more and (#curr >= num) or (#curr == num) then
|
|
vals[curr[1]:get_id()] = curr
|
|
end
|
|
end
|
|
local ret = {}
|
|
for i=#vals, 1, -1 do
|
|
if next(vals[i]) then table.insert(ret, vals[i]) end
|
|
end
|
|
return ret
|
|
end
|
|
|
|
function get_highest(hand)
|
|
local highest = nil
|
|
for k, v in ipairs(hand) do
|
|
if not highest or v:get_nominal() > highest:get_nominal() then
|
|
highest = v
|
|
end
|
|
end
|
|
if #hand > 0 then return {{highest}} else return {} end
|
|
end
|
|
|
|
function reset_drawhash()
|
|
G.DRAW_HASH = EMPTY(G.DRAW_HASH)
|
|
end
|
|
|
|
--Copyright 2021 Max Cahill (Zlib license)
|
|
--
|
|
--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, and to 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.
|
|
--This function was slightly modified from it's original state
|
|
function nuGC(time_budget, memory_ceiling, disable_otherwise)
|
|
time_budget = time_budget or 3e-4
|
|
memory_ceiling = memory_ceiling or 300
|
|
local max_steps = 1000
|
|
local steps = 0
|
|
local start_time = love.timer.getTime()
|
|
while
|
|
love.timer.getTime() - start_time < time_budget and
|
|
steps < max_steps
|
|
do
|
|
collectgarbage("step", 1)
|
|
steps = steps + 1
|
|
end
|
|
--safety net
|
|
if collectgarbage("count") / 1024 > memory_ceiling then
|
|
collectgarbage("collect")
|
|
end
|
|
--don't collect gc outside this margin
|
|
if disable_otherwise then
|
|
collectgarbage("stop")
|
|
end
|
|
end
|
|
|
|
--The drawhash is a hash table of all drawn nodes and all nodes that may be invisible but still collide with the cursor
|
|
function add_to_drawhash(obj)
|
|
if obj then
|
|
G.DRAW_HASH[#G.DRAW_HASH+1] = obj
|
|
end
|
|
end
|
|
|
|
function mix_colours(C1, C2, proportionC1)
|
|
return {
|
|
(C1[1] or 0.5)*proportionC1 + (C2[1] or 0.5)*(1-proportionC1),
|
|
(C1[2] or 0.5)*proportionC1 + (C2[2] or 0.5)*(1-proportionC1),
|
|
(C1[3] or 0.5)*proportionC1 + (C2[3] or 0.5)*(1-proportionC1),
|
|
(C1[4] or 1)*proportionC1 + (C2[4] or 1)*(1-proportionC1),
|
|
}
|
|
end
|
|
|
|
function mod_chips(_chips)
|
|
if G.GAME.modifiers.chips_dollar_cap then
|
|
_chips = math.min(_chips, math.max(G.GAME.dollars, 0))
|
|
end
|
|
return _chips
|
|
end
|
|
|
|
function mod_mult(_mult)
|
|
return _mult
|
|
end
|
|
|
|
function play_sound(sound_code, per, vol)
|
|
if G.F_MUTE then return end
|
|
if sound_code and G.SETTINGS.SOUND.volume > 0.001 then
|
|
G.ARGS.play_sound = G.ARGS.play_sound or {}
|
|
G.ARGS.play_sound.type = 'sound'
|
|
G.ARGS.play_sound.time = G.TIMERS.REAL
|
|
G.ARGS.play_sound.crt = G.SETTINGS.GRAPHICS.crt
|
|
G.ARGS.play_sound.sound_code = sound_code
|
|
G.ARGS.play_sound.per = per
|
|
G.ARGS.play_sound.vol = vol
|
|
G.ARGS.play_sound.pitch_mod = G.PITCH_MOD
|
|
G.ARGS.play_sound.state = G.STATE
|
|
G.ARGS.play_sound.music_control = G.SETTINGS.music_control
|
|
G.ARGS.play_sound.sound_settings = G.SETTINGS.SOUND
|
|
G.ARGS.play_sound.splash_vol = G.SPLASH_VOL
|
|
G.ARGS.play_sound.overlay_menu = not (not G.OVERLAY_MENU)
|
|
if G.F_SOUND_THREAD then
|
|
G.SOUND_MANAGER.channel:push(G.ARGS.play_sound)
|
|
else
|
|
PLAY_SOUND(G.ARGS.play_sound)
|
|
end
|
|
end
|
|
end
|
|
|
|
function modulate_sound(dt)
|
|
--volume of the splash screen is set here
|
|
G.SPLASH_VOL = 2*dt*(G.STATE == G.STATES.SPLASH and 1 or 0) + (G.SPLASH_VOL or 1)*(1-2*dt)
|
|
|
|
--Control the music here
|
|
local desired_track =
|
|
G.video_soundtrack or
|
|
(G.STATE == G.STATES.SPLASH and '') or
|
|
SMODS.Sound:get_current_music() or
|
|
(G.booster_pack_sparkles and not G.booster_pack_sparkles.REMOVED and 'music2') or
|
|
(G.booster_pack_meteors and not G.booster_pack_meteors.REMOVED and 'music3') or
|
|
(G.booster_pack and not G.booster_pack.REMOVED and 'music2') or
|
|
(G.shop and not G.shop.REMOVED and 'music4') or
|
|
(G.GAME.blind and G.GAME.blind.boss and 'music5') or
|
|
('music1')
|
|
|
|
G.PITCH_MOD = (G.PITCH_MOD or 1)*(1 - dt) + dt*((not G.normal_music_speed and G.STATE == G.STATES.GAME_OVER) and 0.5 or 1)
|
|
|
|
--For ambient sound control
|
|
G.SETTINGS.ambient_control = G.SETTINGS.ambient_control or {}
|
|
G.ARGS.score_intensity = G.ARGS.score_intensity or {}
|
|
if not is_number(G.GAME.current_round.current_hand.chips) or not is_number(G.GAME.current_round.current_hand.mult) then
|
|
G.ARGS.score_intensity.earned_score = 0
|
|
else
|
|
G.ARGS.score_intensity.earned_score = G.GAME.current_round.current_hand.chips*G.GAME.current_round.current_hand.mult
|
|
end
|
|
G.ARGS.score_intensity.required_score = G.GAME.blind and G.GAME.blind.chips or 0
|
|
if G.cry_flame_override and G.cry_flame_override['duration'] > 0 then
|
|
G.cry_flame_override['duration'] = math.max(0, G.cry_flame_override['duration'] - dt)
|
|
end
|
|
G.ARGS.score_intensity.flames = math.min(1, (G.STAGE == G.STAGES.RUN and 1 or 0)*(
|
|
(G.ARGS.chip_flames and (G.ARGS.chip_flames.real_intensity + G.ARGS.chip_flames.change) or 0))/10)
|
|
G.ARGS.score_intensity.organ = G.video_organ or to_big(G.ARGS.score_intensity.required_score) > to_big(0) and math.max(math.min(0.4, 0.1*math.log(G.ARGS.score_intensity.earned_score/(G.ARGS.score_intensity.required_score+1), 5)),0.) or 0
|
|
|
|
local AC = G.SETTINGS.ambient_control
|
|
G.ARGS.ambient_sounds = G.ARGS.ambient_sounds or {
|
|
ambientFire2 = {volfunc = function(_prev_volume) return _prev_volume*(1 - dt) + dt*0.9*((G.ARGS.score_intensity.flames > 0.3) and 1 or G.ARGS.score_intensity.flames/0.3) end},
|
|
ambientFire1 = {volfunc = function(_prev_volume) return _prev_volume*(1 - dt) + dt*0.8*((G.ARGS.score_intensity.flames > 0.3) and (G.ARGS.score_intensity.flames-0.3)/0.7 or 0) end},
|
|
ambientFire3 = {volfunc = function(_prev_volume) return _prev_volume*(1 - dt) + dt*0.4*((G.ARGS.chip_flames and G.ARGS.chip_flames.change or 0) + (G.ARGS.mult_flames and G.ARGS.mult_flames.change or 0)) end},
|
|
ambientOrgan1 = {volfunc = function(_prev_volume) return _prev_volume*(1 - dt) + dt*0.6*(G.SETTINGS.SOUND.music_volume + 100)/200*(G.ARGS.score_intensity.organ) end},
|
|
}
|
|
|
|
for k, v in pairs(G.ARGS.ambient_sounds) do
|
|
AC[k] = AC[k] or {}
|
|
AC[k].per = (k == 'ambientOrgan1') and 0.7 or (k == 'ambientFire1' and 1.1) or (k == 'ambientFire2' and 1.05) or 1
|
|
AC[k].vol = Cartomancer.handle_flames_volume((not G.video_organ and G.STATE == G.STATES.SPLASH) and 0 or AC[k].vol and v.volfunc(AC[k].vol) or 0)
|
|
end
|
|
|
|
G.ARGS.push = G.ARGS.push or {}
|
|
G.ARGS.push.type = 'modulate'
|
|
G.ARGS.push.pitch_mod = G.PITCH_MOD
|
|
G.ARGS.push.state = G.STATE
|
|
G.ARGS.push.time = G.TIMERS.REAL
|
|
G.ARGS.push.dt = dt
|
|
G.ARGS.push.desired_track = desired_track
|
|
G.ARGS.push.sound_settings = G.SETTINGS.SOUND
|
|
G.ARGS.push.splash_vol = G.SPLASH_VOL
|
|
G.ARGS.push.overlay_menu = not (not G.OVERLAY_MENU)
|
|
G.ARGS.push.ambient_control = G.SETTINGS.ambient_control
|
|
if SMODS.remove_replace_sound and SMODS.remove_replace_sound ~= desired_track then
|
|
SMODS.Sound.replace_sounds[SMODS.remove_replace_sound] = nil
|
|
SMODS.remove_replace_sound = nil
|
|
end
|
|
local replace_sound = SMODS.Sound.replace_sounds[desired_track]
|
|
if replace_sound then
|
|
local replaced_track = desired_track
|
|
desired_track = replace_sound.key
|
|
G.ARGS.push.desired_track = desired_track
|
|
if SMODS.previous_track ~= desired_track then
|
|
if replace_sound.times > 0 then replace_sound.times = replace_sound.times - 1 end
|
|
if replace_sound.times == 0 then SMODS.remove_replace_sound = replaced_track end
|
|
end
|
|
end
|
|
local stop_sound = SMODS.Sound.stop_sounds[desired_track]
|
|
if SMODS.Sound.stop_sounds[desired_track] then
|
|
if SMODS.previous_track ~= '' and stop_sound > 0 then stop_sound = stop_sound - 1 end
|
|
SMODS.Sound.stop_sounds[desired_track] = stop_sound ~= 0 and stop_sound or nil
|
|
SMODS.previous_track = ''
|
|
return
|
|
end
|
|
|
|
if G.F_SOUND_THREAD then
|
|
G.SOUND_MANAGER.channel:push(G.ARGS.push)
|
|
SMODS.previous_track = SMODS.previous_track or ''
|
|
local in_sync = (SMODS.Sounds[desired_track] or {}).sync
|
|
local out_sync = (SMODS.Sounds[SMODS.previous_track] or {}).sync
|
|
local should_sync = true
|
|
if (type(in_sync) == 'table' and not in_sync[SMODS.previous_track]) or in_sync == false then should_sync = false end
|
|
if (type(out_sync) == 'table' and not out_sync[desired_track]) or out_sync == false then should_sync = false end
|
|
if
|
|
SMODS.previous_track and SMODS.previous_track ~= desired_track and
|
|
not should_sync
|
|
then
|
|
G.ARGS.push.type = 'restart_music'
|
|
G.SOUND_MANAGER.channel:push(G.ARGS.push)
|
|
end
|
|
SMODS.previous_track = desired_track
|
|
else
|
|
MODULATE(G.ARGS.push)
|
|
end
|
|
end
|
|
|
|
function count_of_suit(area, suit)
|
|
local num = 0
|
|
for _,c in pairs(area.cards) do
|
|
if c.base.suit == suit then
|
|
num = num +1
|
|
end
|
|
end
|
|
return num
|
|
end
|
|
|
|
function prep_draw(moveable, scale, rotate, offset)
|
|
if Big and G.STATE == G.STATES.MENU then moveable.VT.x = to_big(moveable.VT.x):to_number()
|
|
moveable.VT.y = to_big(moveable.VT.y):to_number()
|
|
moveable.VT.w = to_big(moveable.VT.w):to_number()
|
|
moveable.VT.h = to_big(moveable.VT.h):to_number() end
|
|
love.graphics.push()
|
|
love.graphics.scale(G.TILESCALE*G.TILESIZE)
|
|
love.graphics.translate(
|
|
moveable.VT.x+moveable.VT.w/2 + (offset and offset.x or 0) + ((moveable.layered_parallax and moveable.layered_parallax.x) or ((moveable.parent and moveable.parent.layered_parallax and moveable.parent.layered_parallax.x)) or 0),
|
|
moveable.VT.y+moveable.VT.h/2 + (offset and offset.y or 0) + ((moveable.layered_parallax and moveable.layered_parallax.y) or ((moveable.parent and moveable.parent.layered_parallax and moveable.parent.layered_parallax.y)) or 0))
|
|
if moveable.VT.r ~= 0 or moveable.juice or rotate then love.graphics.rotate(moveable.VT.r + (rotate or 0)) end
|
|
love.graphics.translate(
|
|
-scale*moveable.VT.w*(moveable.VT.scale)/2,
|
|
-scale*moveable.VT.h*(moveable.VT.scale)/2)
|
|
love.graphics.scale(moveable.VT.scale*scale)
|
|
end
|
|
|
|
function get_chosen_triangle_from_rect(x, y, w, h, vert)
|
|
local scale = 2
|
|
if vert then
|
|
x = x + math.min(0.6*math.sin(G.TIMERS.REAL*9)*scale+0.2, 0)
|
|
return {
|
|
x-3.5*scale, y+h/2 - 1.5*scale,
|
|
x-0.5*scale, y+h/2 + 0,
|
|
x-3.5*scale,y+h/2 + 1.5*scale
|
|
}
|
|
else
|
|
y = y + math.min(0.6*math.sin(G.TIMERS.REAL*9)*scale+0.2, 0)
|
|
return {
|
|
x+w/2 - 1.5*scale, y-4*scale,
|
|
x+w/2 + 0, y-1.1*scale,
|
|
x+w/2 + 1.5*scale, y-4*scale
|
|
}
|
|
end
|
|
end
|
|
|
|
function point_translate(_T, delta)
|
|
_T.x = (_T.x + delta.x) or 0
|
|
_T.y = (_T.y + delta.y) or 0
|
|
end
|
|
|
|
function point_rotate(_T, angle)
|
|
local _cos, _sin, _ox, _oy = math.cos(angle+math.pi/2), math.sin(angle+math.pi/2), _T.x , _T.y
|
|
_T.x = -_oy*_cos + _ox*_sin
|
|
_T.y = _oy*_sin + _ox*_cos
|
|
end
|
|
|
|
function lighten(colour, percent, no_tab)
|
|
if no_tab then
|
|
return
|
|
colour[1]*(1-percent)+percent,
|
|
colour[2]*(1-percent)+percent,
|
|
colour[3]*(1-percent)+percent,
|
|
colour[4]
|
|
end
|
|
return {
|
|
colour[1]*(1-percent)+percent,
|
|
colour[2]*(1-percent)+percent,
|
|
colour[3]*(1-percent)+percent,
|
|
colour[4]
|
|
}
|
|
end
|
|
|
|
function darken(colour, percent, no_tab)
|
|
if no_tab then
|
|
return
|
|
colour[1]*(1-percent),
|
|
colour[2]*(1-percent),
|
|
colour[3]*(1-percent),
|
|
colour[4]
|
|
end
|
|
return {
|
|
colour[1]*(1-percent),
|
|
colour[2]*(1-percent),
|
|
colour[3]*(1-percent),
|
|
colour[4]
|
|
}
|
|
end
|
|
|
|
function adjust_alpha(colour, new_alpha, no_tab)
|
|
if no_tab then
|
|
return
|
|
colour[1],
|
|
colour[2],
|
|
colour[3],
|
|
new_alpha
|
|
end
|
|
return {
|
|
colour[1],
|
|
colour[2],
|
|
colour[3],
|
|
new_alpha
|
|
}
|
|
end
|
|
|
|
function alert_no_space(card, area)
|
|
G.CONTROLLER.locks.no_space = true
|
|
attention_text({
|
|
scale = 0.9, text = localize('k_no_space_ex'), hold = 0.9, align = 'cm',
|
|
cover = area, cover_padding = 0.1, cover_colour = adjust_alpha(G.C.BLACK, 0.7)
|
|
})
|
|
card:juice_up(0.3, 0.2)
|
|
for i = 1, #area.cards do
|
|
area.cards[i]:juice_up(0.15)
|
|
end
|
|
G.E_MANAGER:add_event(Event({trigger = 'after', delay = 0.06*G.SETTINGS.GAMESPEED, blockable = false, blocking = false, func = function()
|
|
play_sound('tarot2', 0.76, 0.4);return true end}))
|
|
play_sound('tarot2', 1, 0.4)
|
|
|
|
G.E_MANAGER:add_event(Event({trigger = 'after', delay = 0.5*G.SETTINGS.GAMESPEED, blockable = false, blocking = false,
|
|
func = function()
|
|
G.CONTROLLER.locks.no_space = nil
|
|
return true end}))
|
|
end
|
|
|
|
function find_joker(name, non_debuff)
|
|
local jokers = {}
|
|
if not G.jokers or not G.jokers.cards then return {} end
|
|
for k, v in pairs(G.jokers.cards) do
|
|
if v and type(v) == 'table' and v.ability.name == name and (non_debuff or not v.debuff) then
|
|
table.insert(jokers, v)
|
|
end
|
|
end
|
|
for k, v in pairs(G.consumeables.cards) do
|
|
if v and type(v) == 'table' and v.ability.name == name and (non_debuff or not v.debuff) then
|
|
table.insert(jokers, v)
|
|
end
|
|
end
|
|
return jokers
|
|
end
|
|
|
|
function get_blind_amount(ante)
|
|
if G.GAME.modifiers.scaling and G.GAME.modifiers.scaling > 3 then return SMODS.get_blind_amount(ante) end
|
|
local k = 0.75
|
|
if not G.GAME.modifiers.scaling or G.GAME.modifiers.scaling == 1 then
|
|
local amounts = {
|
|
300, 800, 2000, 5000, 11000, 20000, 35000, 50000
|
|
}
|
|
if ante < 1 then return 100 end
|
|
if ante <= 8 then return amounts[ante] end
|
|
local a, b, c, d = amounts[8],1.6,ante-8, 1 + 0.2*(ante-8)
|
|
local amount = math.floor(a*(b+(k*c)^d)^c)
|
|
amount = amount - amount%(10^math.floor(math.log10(amount)-1))
|
|
return amount
|
|
elseif G.GAME.modifiers.scaling == 2 then
|
|
local amounts = {
|
|
300, 900, 2600, 8000, 20000, 36000, 60000, 100000
|
|
--300, 900, 2400, 7000, 18000, 32000, 56000, 90000
|
|
}
|
|
if ante < 1 then return 100 end
|
|
if ante <= 8 then return amounts[ante] end
|
|
local a, b, c, d = amounts[8],1.6,ante-8, 1 + 0.2*(ante-8)
|
|
local amount = math.floor(a*(b+(k*c)^d)^c)
|
|
amount = amount - amount%(10^math.floor(math.log10(amount)-1))
|
|
return amount
|
|
elseif G.GAME.modifiers.scaling == 3 then
|
|
local amounts = {
|
|
300, 1000, 3200, 9000, 25000, 60000, 110000, 200000
|
|
--300, 1000, 3000, 8000, 22000, 50000, 90000, 180000
|
|
}
|
|
if ante < 1 then return 100 end
|
|
if ante <= 8 then return amounts[ante] end
|
|
local a, b, c, d = amounts[8],1.6,ante-8, 1 + 0.2*(ante-8)
|
|
local amount = math.floor(a*(b+(k*c)^d)^c)
|
|
amount = amount - amount%(10^math.floor(math.log10(amount)-1))
|
|
return amount
|
|
end
|
|
end
|
|
|
|
function number_format(num, e_switch_point)
|
|
if type(num) ~= 'number' then return num end
|
|
|
|
local sign = (num >= 0 and "") or "-"
|
|
num = math.abs(num)
|
|
G.E_SWITCH_POINT = G.E_SWITCH_POINT or 100000000000
|
|
if not num or type(num) ~= 'number' then return num or '' end
|
|
if num >= (e_switch_point or G.E_SWITCH_POINT) then
|
|
local x = string.format("%.4g",num)
|
|
local fac = math.floor(math.log(tonumber(x), 10))
|
|
if num == math.huge then
|
|
return sign.."naneinf"
|
|
end
|
|
|
|
local mantissa = round_number(x/(10^fac), 3)
|
|
if mantissa >= 10 then
|
|
mantissa = mantissa / 10
|
|
fac = fac + 1
|
|
end
|
|
return sign..(string.format(fac >= 100 and "%.1fe%i" or fac >= 10 and "%.2fe%i" or "%.3fe%i", mantissa, fac))
|
|
end
|
|
local formatted
|
|
if num ~= math.floor(num) and num < 100 then
|
|
formatted = string.format(num >= 10 and "%.1f" or "%.2f", num)
|
|
if formatted:sub(-1) == "0" then
|
|
formatted = formatted:gsub("%.?0+$", "")
|
|
end
|
|
-- Return already to avoid comas being added
|
|
if num < 0.01 then return tostring(num) end
|
|
else
|
|
formatted = string.format("%.0f", num)
|
|
end
|
|
return sign..(formatted:reverse():gsub("(%d%d%d)", "%1,"):gsub(",$", ""):reverse())
|
|
end
|
|
|
|
function score_number_scale(scale, amt)
|
|
G.E_SWITCH_POINT = G.E_SWITCH_POINT or 100000000000
|
|
if type(amt) ~= 'number' then return 0.7*(scale or 1) end
|
|
if amt >= G.E_SWITCH_POINT then
|
|
return 0.7*(scale or 1)
|
|
elseif amt >= 1000000 then
|
|
return 14*0.75/(math.floor(math.log(amt))+4)*(scale or 1)
|
|
else
|
|
return 0.75*(scale or 1)
|
|
end
|
|
end
|
|
|
|
function copy_table(O)
|
|
local O_type = type(O)
|
|
local copy
|
|
if O_type == 'table' then
|
|
copy = {}
|
|
for k, v in next, O, nil do
|
|
copy[copy_table(k)] = copy_table(v)
|
|
end
|
|
setmetatable(copy, copy_table(getmetatable(O)))
|
|
else
|
|
copy = O
|
|
end
|
|
return copy
|
|
end
|
|
|
|
function send_score(_score)
|
|
if G.F_HTTP_SCORES and G.SETTINGS.COMP and G.F_STREAMER_EVENT then
|
|
G.HTTP_MANAGER.out_channel:push({
|
|
set_score = true,
|
|
score = _score,
|
|
username = G.SETTINGS.COMP.name,
|
|
uid = tostring(G.STEAM.user.getSteamID()),
|
|
version = G.VERSION
|
|
})
|
|
end
|
|
end
|
|
|
|
function send_name()
|
|
if G.F_HTTP_SCORES and G.SETTINGS.COMP and G.F_STREAMER_EVENT then
|
|
G.HTTP_MANAGER.out_channel:push({
|
|
set_name = true,
|
|
username = G.SETTINGS.COMP.name,
|
|
uid = tostring(G.STEAM.user.getSteamID()),
|
|
version = G.VERSION
|
|
})
|
|
end
|
|
end
|
|
|
|
function check_and_set_high_score(score, amt)
|
|
if not amt or type(amt) ~= 'number' then return end
|
|
if G.GAME.round_scores[score] and math.floor(amt) > (G.GAME.round_scores[score].amt or 0) then
|
|
G.GAME.round_scores[score].amt = math.floor(amt)
|
|
end
|
|
if G.GAME.seeded then return end
|
|
if score == 'hand' and G.SETTINGS.COMP and ((not G.SETTINGS.COMP.score) or (G.SETTINGS.COMP.score < math.floor(amt))) then
|
|
G.SETTINGS.COMP.score = amt
|
|
send_score(math.floor(amt))
|
|
end
|
|
if G.PROFILES[G.SETTINGS.profile].high_scores[score] and math.floor(amt) > G.PROFILES[G.SETTINGS.profile].high_scores[score].amt then
|
|
if G.GAME.round_scores[score] then G.GAME.round_scores[score].high_score = true end
|
|
G.PROFILES[G.SETTINGS.profile].high_scores[score].amt = math.floor(amt)
|
|
G:save_settings()
|
|
end
|
|
end
|
|
|
|
function set_joker_usage()
|
|
for k, v in pairs(G.jokers.cards) do
|
|
if v.config.center_key and v.ability.set == 'Joker' then
|
|
if G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key] then
|
|
G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key].count = G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key].count + 1
|
|
else
|
|
G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key] = {count = 1, order = v.config.center.order, wins = {}, losses = {}, wins_by_key = {}, losses_by_key = {}}
|
|
end
|
|
end
|
|
end
|
|
G:save_settings()
|
|
end
|
|
|
|
function set_joker_win()
|
|
for k, v in pairs(G.jokers.cards) do
|
|
if v.config.center_key and v.ability.set == 'Joker' then
|
|
G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key] = G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key] or {count = 1, order = v.config.center.order, wins = {}, losses = {}, wins_by_key = {}, losses_by_key = {}}
|
|
if G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key] then
|
|
G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key].wins = G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key].wins or {}
|
|
G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key].wins[G.GAME.stake] = (G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key].wins[G.GAME.stake] or 0) + 1
|
|
G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key].wins_by_key[SMODS.stake_from_index(G.GAME.stake)] = (G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key].wins_by_key[SMODS.stake_from_index(G.GAME.stake)] or 0) + 1
|
|
end
|
|
end
|
|
end
|
|
G:save_settings()
|
|
end
|
|
|
|
function get_joker_win_sticker(_center, index)
|
|
if G.PROFILES[G.SETTINGS.profile].joker_usage[_center.key] and
|
|
G.PROFILES[G.SETTINGS.profile].joker_usage[_center.key].wins then
|
|
local _w = 0
|
|
for k, v in pairs(G.PROFILES[G.SETTINGS.profile].joker_usage[_center.key].wins) do
|
|
_w = math.max(k, _w)
|
|
end
|
|
if index then return _w end
|
|
if _w > 0 then return G.sticker_map[_w] end
|
|
end
|
|
if index then return 0 end
|
|
end
|
|
|
|
function set_joker_loss()
|
|
for k, v in pairs(G.jokers.cards) do
|
|
if v.config.center_key and v.ability.set == 'Joker' then
|
|
if G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key] then
|
|
G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key].losses = G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key].losses or {}
|
|
G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key].losses[G.GAME.stake] = (G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key].losses[G.GAME.stake] or 0) + 1
|
|
G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key].losses_by_key[SMODS.stake_from_index(G.GAME.stake)] = (G.PROFILES[G.SETTINGS.profile].joker_usage[v.config.center_key].losses_by_key[SMODS.stake_from_index(G.GAME.stake)] or 0) + 1
|
|
end
|
|
end
|
|
end
|
|
G:save_settings()
|
|
end
|
|
|
|
function set_deck_usage()
|
|
if G.GAME.selected_back and G.GAME.selected_back.effect and G.GAME.selected_back.effect.center and G.GAME.selected_back.effect.center.key then
|
|
local deck_key = G.GAME.selected_back.effect.center.key
|
|
if G.PROFILES[G.SETTINGS.profile].deck_usage[deck_key] then
|
|
G.PROFILES[G.SETTINGS.profile].deck_usage[deck_key].count = G.PROFILES[G.SETTINGS.profile].deck_usage[deck_key].count + 1
|
|
else
|
|
G.PROFILES[G.SETTINGS.profile].deck_usage[deck_key] = {count = 1, order = G.GAME.selected_back.effect.center.order, wins = {}, losses = {}, wins_by_key = {}, losses_by_key = {}}
|
|
end
|
|
G:save_settings()
|
|
end
|
|
end
|
|
|
|
function set_deck_win()
|
|
if G.GAME.selected_back and G.GAME.selected_back.effect and G.GAME.selected_back.effect.center and G.GAME.selected_back.effect.center.key then
|
|
local deck_key = G.GAME.selected_back.effect.center.key
|
|
if not G.PROFILES[G.SETTINGS.profile].deck_usage[deck_key] then G.PROFILES[G.SETTINGS.profile].deck_usage[deck_key] = {count = 1, order = G.GAME.selected_back.effect.center.order, wins = {}, losses = {}, wins_by_key = {}, losses_by_key = {}} end
|
|
if G.PROFILES[G.SETTINGS.profile].deck_usage[deck_key] then
|
|
G.PROFILES[G.SETTINGS.profile].deck_usage[deck_key].wins[G.GAME.stake] = (G.PROFILES[G.SETTINGS.profile].deck_usage[deck_key].wins[G.GAME.stake] or 0) + 1
|
|
for i = 1,
|
|
(G.P_CENTER_POOLS["Stake"][G.GAME.stake].unlocked_stake) and
|
|
(G.P_STAKES[G.P_CENTER_POOLS["Stake"][G.GAME.stake].unlocked_stake].stake_level-1) or (G.GAME.stake-1)
|
|
do
|
|
G.PROFILES[G.SETTINGS.profile].deck_usage[deck_key].wins[i] = (G.PROFILES[G.SETTINGS.profile].deck_usage[deck_key].wins[i] or 1)
|
|
end
|
|
end
|
|
set_challenge_unlock()
|
|
G:save_settings()
|
|
end
|
|
end
|
|
|
|
function set_challenge_unlock()
|
|
if G.PROFILES[G.SETTINGS.profile].all_unlocked then return end
|
|
if G.PROFILES[G.SETTINGS.profile].challenges_unlocked then
|
|
local _ch_comp, _ch_tot = 0,#G.CHALLENGES
|
|
for k, v in ipairs(G.CHALLENGES) do
|
|
if v.id and G.PROFILES[G.SETTINGS.profile].challenge_progress.completed[v.id or ''] then
|
|
_ch_comp = _ch_comp + 1
|
|
end
|
|
end
|
|
G.PROFILES[G.SETTINGS.profile].challenges_unlocked = math.min(_ch_tot, _ch_comp+5)
|
|
else
|
|
local deck_wins = 0
|
|
for k, v in pairs(G.PROFILES[G.SETTINGS.profile].deck_usage) do
|
|
if v.wins and v.wins[1] then
|
|
deck_wins = deck_wins + 1
|
|
end
|
|
end
|
|
if deck_wins >= G.CHALLENGE_WINS and not G.PROFILES[G.SETTINGS.profile].challenges_unlocked then
|
|
G.PROFILES[G.SETTINGS.profile].challenges_unlocked = 5
|
|
notify_alert('b_challenge', "Back")
|
|
end
|
|
end
|
|
end
|
|
|
|
function get_deck_win_stake(_deck_key)
|
|
if not _deck_key then
|
|
local _w, _w_low = 0, nil
|
|
local deck_count = 0
|
|
for _, deck in pairs(G.PROFILES[G.SETTINGS.profile].deck_usage) do
|
|
local deck_won_with = nil
|
|
for k, v in pairs(deck.wins) do
|
|
deck_won_with = true
|
|
_w = math.max(k, _w)
|
|
end
|
|
if deck_won_with then deck_count = deck_count + 1 end
|
|
_w_low = _w_low and (math.min(_w_low, _w)) or _w
|
|
end
|
|
return _w, ((deck_count >= #G.P_CENTER_POOLS.Back) and _w_low or 0)
|
|
end
|
|
if G.PROFILES[G.SETTINGS.profile].deck_usage[_deck_key] and
|
|
G.PROFILES[G.SETTINGS.profile].deck_usage[_deck_key].wins then
|
|
local _w = 0
|
|
for k, v in pairs(G.PROFILES[G.SETTINGS.profile].deck_usage[_deck_key].wins) do
|
|
_w = math.max(k, _w)
|
|
end
|
|
return _w
|
|
end
|
|
return 0
|
|
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 then
|
|
local _w = -1
|
|
for k, v in pairs(G.PROFILES[G.SETTINGS.profile].deck_usage[_center.key].wins) do
|
|
_w = math.max(k, _w)
|
|
end
|
|
if _w > 0 then return G.sticker_map[_w] end
|
|
end
|
|
end
|
|
|
|
function set_deck_loss()
|
|
if G.GAME.selected_back and G.GAME.selected_back.effect and G.GAME.selected_back.effect.center and G.GAME.selected_back.effect.center.key then
|
|
local deck_key = G.GAME.selected_back.effect.center.key
|
|
if not G.PROFILES[G.SETTINGS.profile].deck_usage[deck_key] then G.PROFILES[G.SETTINGS.profile].deck_usage[deck_key] = {count = 1, order = G.GAME.selected_back.effect.center.order, wins = {}, losses = {}, wins_by_key = {}, losses_by_key = {}} end
|
|
if G.PROFILES[G.SETTINGS.profile].deck_usage[deck_key] then
|
|
G.PROFILES[G.SETTINGS.profile].deck_usage[deck_key].losses[G.GAME.stake] = (G.PROFILES[G.SETTINGS.profile].deck_usage[deck_key].losses[G.GAME.stake] or 0) + 1
|
|
end
|
|
G:save_settings()
|
|
end
|
|
end
|
|
|
|
function set_consumeable_usage(card)
|
|
if card.config.center_key and card.ability.consumeable then
|
|
if G.PROFILES[G.SETTINGS.profile].consumeable_usage[card.config.center_key] then
|
|
G.PROFILES[G.SETTINGS.profile].consumeable_usage[card.config.center_key].count = G.PROFILES[G.SETTINGS.profile].consumeable_usage[card.config.center_key].count + 1
|
|
else
|
|
G.PROFILES[G.SETTINGS.profile].consumeable_usage[card.config.center_key] = {count = 1, order = card.config.center.order}
|
|
end
|
|
if G.GAME.consumeable_usage[card.config.center_key] then
|
|
G.GAME.consumeable_usage[card.config.center_key].count = G.GAME.consumeable_usage[card.config.center_key].count + 1
|
|
else
|
|
G.GAME.consumeable_usage[card.config.center_key] = {count = 1, order = card.config.center.order, set = card.ability.set}
|
|
end
|
|
G.GAME.consumeable_usage_total = G.GAME.consumeable_usage_total or {tarot = 0, planet = 0, spectral = 0, tarot_planet = 0, all = 0}
|
|
if card.config.center.set == 'Tarot' then
|
|
G.GAME.consumeable_usage_total.tarot = G.GAME.consumeable_usage_total.tarot + 1
|
|
G.GAME.consumeable_usage_total.tarot_planet = G.GAME.consumeable_usage_total.tarot_planet + 1
|
|
elseif card.config.center.set == 'Planet' then
|
|
G.GAME.consumeable_usage_total.planet = G.GAME.consumeable_usage_total.planet + 1
|
|
G.GAME.consumeable_usage_total.tarot_planet = G.GAME.consumeable_usage_total.tarot_planet + 1
|
|
elseif card.config.center.set == 'Spectral' then G.GAME.consumeable_usage_total.spectral = G.GAME.consumeable_usage_total.spectral + 1
|
|
end
|
|
|
|
G.GAME.consumeable_usage_total.all = G.GAME.consumeable_usage_total.all + 1
|
|
|
|
if not card.config.center.discovered then
|
|
discover_card(card)
|
|
end
|
|
|
|
if card.config.center.set == 'Tarot' or card.config.center.set == 'Planet' then
|
|
G.E_MANAGER:add_event(Event({
|
|
trigger = 'immediate',
|
|
func = function()
|
|
G.E_MANAGER:add_event(Event({
|
|
trigger = 'immediate',
|
|
func = function()
|
|
G.GAME.last_tarot_planet = card.config.center_key
|
|
return true
|
|
end
|
|
}))
|
|
return true
|
|
end
|
|
}))
|
|
end
|
|
|
|
end
|
|
G:save_settings()
|
|
end
|
|
|
|
function set_voucher_usage(card)
|
|
if card.config.center_key and card.ability.set == 'Voucher' then
|
|
if G.PROFILES[G.SETTINGS.profile].voucher_usage[card.config.center_key] then
|
|
G.PROFILES[G.SETTINGS.profile].voucher_usage[card.config.center_key].count = G.PROFILES[G.SETTINGS.profile].voucher_usage[card.config.center_key].count + 1
|
|
else
|
|
G.PROFILES[G.SETTINGS.profile].voucher_usage[card.config.center_key] = {count = 1, order = card.config.center.order}
|
|
end
|
|
end
|
|
G:save_settings()
|
|
end
|
|
|
|
function set_hand_usage(hand)
|
|
local hand_label = hand
|
|
hand = hand:gsub("%s+", "")
|
|
if G.PROFILES[G.SETTINGS.profile].hand_usage[hand] then
|
|
G.PROFILES[G.SETTINGS.profile].hand_usage[hand].count = G.PROFILES[G.SETTINGS.profile].hand_usage[hand].count + 1
|
|
else
|
|
G.PROFILES[G.SETTINGS.profile].hand_usage[hand] = {count = 1, order = hand_label}
|
|
end
|
|
if G.GAME.hand_usage[hand] then
|
|
G.GAME.hand_usage[hand].count = G.GAME.hand_usage[hand].count + 1
|
|
else
|
|
G.GAME.hand_usage[hand] = {count = 1, order = hand_label}
|
|
end
|
|
G:save_settings()
|
|
end
|
|
|
|
function set_profile_progress()
|
|
G.PROGRESS = G.PROGRESS or {
|
|
joker_stickers = {tally = 0, of = 0},
|
|
deck_stakes = {tally = 0, of = 0},
|
|
challenges = {tally = 0, of = 0},
|
|
}
|
|
for _, v in pairs(G.PROGRESS) do
|
|
if type(v) == 'table' then
|
|
v.tally = 0
|
|
v.of = 0
|
|
end
|
|
end
|
|
|
|
for _, v in pairs(G.P_CENTERS) do
|
|
if v.set == 'Back' and not v.omit then
|
|
G.PROGRESS.deck_stakes.of = G.PROGRESS.deck_stakes.of + #G.P_CENTER_POOLS.Stake
|
|
G.PROGRESS.deck_stakes.tally = G.PROGRESS.deck_stakes.tally + get_deck_win_stake(v.key)
|
|
end
|
|
if v.set == 'Joker' then
|
|
G.PROGRESS.joker_stickers.of = G.PROGRESS.joker_stickers.of + #G.P_CENTER_POOLS.Stake
|
|
G.PROGRESS.joker_stickers.tally = G.PROGRESS.joker_stickers.tally + get_joker_win_sticker(v, true)
|
|
end
|
|
end
|
|
|
|
for _, v in pairs(G.CHALLENGES) do
|
|
G.PROGRESS.challenges.of = G.PROGRESS.challenges.of + 1
|
|
if G.PROFILES[G.SETTINGS.profile].challenge_progress.completed[v.id] then
|
|
G.PROGRESS.challenges.tally = G.PROGRESS.challenges.tally + 1
|
|
end
|
|
end
|
|
|
|
G.PROFILES[G.SETTINGS.profile].progress.joker_stickers = copy_table(G.PROGRESS.joker_stickers)
|
|
G.PROFILES[G.SETTINGS.profile].progress.deck_stakes = copy_table(G.PROGRESS.deck_stakes)
|
|
G.PROFILES[G.SETTINGS.profile].progress.challenges = copy_table(G.PROGRESS.challenges)
|
|
end
|
|
|
|
function set_discover_tallies()
|
|
G.DISCOVER_TALLIES = G.DISCOVER_TALLIES or {
|
|
blinds = {tally = 0, of = 0},
|
|
tags = {tally = 0, of = 0},
|
|
jokers = {tally = 0, of = 0},
|
|
consumeables = {tally = 0, of = 0},
|
|
vouchers = {tally = 0, of = 0},
|
|
boosters = {tally = 0, of = 0},
|
|
editions = {tally = 0, of = 0},
|
|
backs = {tally = 0, of = 0},
|
|
total = {tally = 0, of = 0},
|
|
}
|
|
for _, v in ipairs(SMODS.ConsumableType.ctype_buffer) do
|
|
G.DISCOVER_TALLIES[v:lower()..'s'] = {tally = 0, of = 0}
|
|
end for _, v in pairs(G.DISCOVER_TALLIES) do
|
|
v.tally = 0
|
|
v.of = 0
|
|
end
|
|
|
|
for _, v in pairs(G.P_CENTERS) do
|
|
if not v.omit and not v.no_collection then
|
|
if v.set and ((v.set == 'Joker') or v.consumeable or (v.set == 'Edition') or (v.set == 'Voucher') or (v.set == 'Back') or (v.set == 'Booster')) then
|
|
G.DISCOVER_TALLIES.total.of = G.DISCOVER_TALLIES.total.of+1
|
|
if v.discovered then
|
|
G.DISCOVER_TALLIES.total.tally = G.DISCOVER_TALLIES.total.tally+1
|
|
end
|
|
end
|
|
if v.set and v.set == 'Joker' then
|
|
G.DISCOVER_TALLIES.jokers.of = G.DISCOVER_TALLIES.jokers.of+1
|
|
if v.discovered then
|
|
G.DISCOVER_TALLIES.jokers.tally = G.DISCOVER_TALLIES.jokers.tally+1
|
|
end
|
|
end
|
|
if v.set and v.set == 'Back' then
|
|
G.DISCOVER_TALLIES.backs.of = G.DISCOVER_TALLIES.backs.of+1
|
|
if v.unlocked then
|
|
G.DISCOVER_TALLIES.backs.tally = G.DISCOVER_TALLIES.backs.tally+1
|
|
end
|
|
end
|
|
if v.set and v.consumeable then
|
|
G.DISCOVER_TALLIES.consumeables.of = G.DISCOVER_TALLIES.consumeables.of+1
|
|
if v.discovered then
|
|
G.DISCOVER_TALLIES.consumeables.tally = G.DISCOVER_TALLIES.consumeables.tally+1
|
|
end
|
|
local tally = G.DISCOVER_TALLIES[v.set:lower()..'s']
|
|
if tally then
|
|
tally.of = tally.of + 1
|
|
if v.discovered then
|
|
tally.tally = tally.tally + 1
|
|
end
|
|
end
|
|
end
|
|
if v.set and v.set == 'Voucher' then
|
|
G.DISCOVER_TALLIES.vouchers.of = G.DISCOVER_TALLIES.vouchers.of+1
|
|
if v.discovered then
|
|
G.DISCOVER_TALLIES.vouchers.tally = G.DISCOVER_TALLIES.vouchers.tally+1
|
|
end
|
|
end
|
|
if v.set and v.set == 'Booster' then
|
|
G.DISCOVER_TALLIES.boosters.of = G.DISCOVER_TALLIES.boosters.of+1
|
|
if v.discovered then
|
|
G.DISCOVER_TALLIES.boosters.tally = G.DISCOVER_TALLIES.boosters.tally+1
|
|
end
|
|
end
|
|
if v.set and v.set == 'Edition' then
|
|
G.DISCOVER_TALLIES.editions.of = G.DISCOVER_TALLIES.editions.of+1
|
|
if v.discovered then
|
|
G.DISCOVER_TALLIES.editions.tally = G.DISCOVER_TALLIES.editions.tally+1
|
|
end
|
|
end
|
|
end
|
|
end
|
|
for _, v in pairs(G.P_BLINDS) do
|
|
if not v.no_collection then
|
|
|
|
G.DISCOVER_TALLIES.total.of = G.DISCOVER_TALLIES.total.of+1
|
|
G.DISCOVER_TALLIES.blinds.of = G.DISCOVER_TALLIES.blinds.of+1
|
|
if v.discovered then
|
|
G.DISCOVER_TALLIES.blinds.tally = G.DISCOVER_TALLIES.blinds.tally+1
|
|
G.DISCOVER_TALLIES.total.tally = G.DISCOVER_TALLIES.total.tally+1
|
|
end
|
|
end
|
|
end
|
|
|
|
for _, v in pairs(G.P_TAGS) do
|
|
if not v.no_collection then
|
|
|
|
G.DISCOVER_TALLIES.total.of = G.DISCOVER_TALLIES.total.of+1
|
|
G.DISCOVER_TALLIES.tags.of = G.DISCOVER_TALLIES.tags.of+1
|
|
if v.discovered then
|
|
G.DISCOVER_TALLIES.tags.tally = G.DISCOVER_TALLIES.tags.tally+1
|
|
G.DISCOVER_TALLIES.total.tally = G.DISCOVER_TALLIES.total.tally+1
|
|
end
|
|
end
|
|
end
|
|
|
|
G.PROFILES[G.SETTINGS.profile].high_scores.collection.amt = G.DISCOVER_TALLIES.total.tally
|
|
G.PROFILES[G.SETTINGS.profile].high_scores.collection.tot = G.DISCOVER_TALLIES.total.of
|
|
G.PROFILES[G.SETTINGS.profile].progress.discovered = copy_table(G.DISCOVER_TALLIES.total)
|
|
|
|
if check_for_unlock then check_for_unlock({type = 'discover_amount',
|
|
amount = G.DISCOVER_TALLIES.total.tally,
|
|
planet_count = G.DISCOVER_TALLIES.planets.tally,
|
|
tarot_count = G.DISCOVER_TALLIES.tarots.tally})
|
|
end
|
|
end
|
|
|
|
function stop_use()
|
|
G.GAME.STOP_USE = (G.GAME.STOP_USE or 0) + 1
|
|
dec_stop_use(6)
|
|
end
|
|
|
|
function dec_stop_use(_depth)
|
|
if _depth > 0 then
|
|
G.E_MANAGER:add_event(Event({
|
|
blocking = false,
|
|
no_delete = true,
|
|
func = (function()
|
|
dec_stop_use(_depth - 1)
|
|
return true end)}))
|
|
else
|
|
G.E_MANAGER:add_event(Event({
|
|
blocking = false,
|
|
no_delete = true,
|
|
func = (function()
|
|
G.GAME.STOP_USE = math.max(G.GAME.STOP_USE - 1, 0)
|
|
return true end)}))
|
|
end
|
|
end
|
|
|
|
function inc_career_stat(stat, mod)
|
|
if G.GAME.seeded or G.GAME.challenge then return end
|
|
if not G.PROFILES[G.SETTINGS.profile].career_stats[stat] then G.PROFILES[G.SETTINGS.profile].career_stats[stat] = 0 end
|
|
G.PROFILES[G.SETTINGS.profile].career_stats[stat] = G.PROFILES[G.SETTINGS.profile].career_stats[stat] + (mod or 0)
|
|
G:save_settings()
|
|
end
|
|
|
|
function recursive_table_cull(t)
|
|
local ret_t = {}
|
|
for k, v in pairs(t) do
|
|
if type(v) == 'table' then
|
|
if v.is and v:is(Object) then ret_t[k] = [["]].."MANUAL_REPLACE"..[["]]
|
|
else ret_t[k] = recursive_table_cull(v)
|
|
end
|
|
else ret_t[k] = v end
|
|
end
|
|
return ret_t
|
|
end
|
|
|
|
function save_with_action(action)
|
|
G.action = action
|
|
save_run()
|
|
G.action = nil
|
|
end
|
|
|
|
function save_run()
|
|
if G.F_NO_SAVING == true then return end
|
|
local cardAreas = {}
|
|
for k, v in pairs(G) do
|
|
if (type(v) == "table") and v.is and v:is(CardArea) then
|
|
local cardAreaSer = v:save()
|
|
if cardAreaSer then cardAreas[k] = cardAreaSer end
|
|
end
|
|
end
|
|
|
|
local tags = {}
|
|
for k, v in ipairs(G.GAME.tags) do
|
|
if (type(v) == "table") and v.is and v:is(Tag) then
|
|
local tagSer = v:save()
|
|
if tagSer then tags[k] = tagSer end
|
|
end
|
|
end
|
|
|
|
G.culled_table = recursive_table_cull{
|
|
cardAreas = cardAreas,
|
|
tags = tags,
|
|
GAME = G.GAME,
|
|
STATE = G.STATE,
|
|
ACTION = G.action or nil,
|
|
BLIND = G.GAME.blind:save(),
|
|
BACK = G.GAME.selected_back:save(),
|
|
VERSION = G.VERSION
|
|
}
|
|
G.ARGS.save_run = G.culled_table
|
|
|
|
G.FILE_HANDLER = G.FILE_HANDLER or {}
|
|
G.FILE_HANDLER.run = true
|
|
G.FILE_HANDLER.update_queued = true
|
|
end
|
|
|
|
function remove_save()
|
|
love.filesystem.remove(G.SETTINGS.profile..'/save.jkr')
|
|
G.SAVED_GAME = nil
|
|
G.FILE_HANDLER.run = nil
|
|
end
|
|
|
|
function loc_colour(_c, _default)
|
|
G.ARGS.LOC_COLOURS = G.ARGS.LOC_COLOURS or {
|
|
red = G.C.RED,
|
|
mult = G.C.MULT,
|
|
blue = G.C.BLUE,
|
|
chips = G.C.CHIPS,
|
|
green = G.C.GREEN,
|
|
money = G.C.MONEY,
|
|
gold = G.C.GOLD,
|
|
attention = G.C.FILTER,
|
|
purple = G.C.PURPLE,
|
|
white = G.C.WHITE,
|
|
inactive = G.C.UI.TEXT_INACTIVE,
|
|
spades = G.C.SUITS.Spades,
|
|
hearts = G.C.SUITS.Hearts,
|
|
clubs = G.C.SUITS.Clubs,
|
|
diamonds = G.C.SUITS.Diamonds,
|
|
tarot = G.C.SECONDARY_SET.Tarot,
|
|
planet = G.C.SECONDARY_SET.Planet,
|
|
spectral = G.C.SECONDARY_SET.Spectral,
|
|
edition = G.C.EDITION,
|
|
dark_edition = G.C.DARK_EDITION,
|
|
legendary = G.C.RARITY[4],
|
|
enhanced = G.C.SECONDARY_SET.Enhanced
|
|
}
|
|
for _, v in ipairs(SMODS.Rarity.obj_buffer) do
|
|
G.ARGS.LOC_COLOURS[v:lower()] = G.C.RARITY[v]
|
|
end
|
|
for _, v in ipairs(SMODS.ConsumableType.ctype_buffer) do
|
|
G.ARGS.LOC_COLOURS[v:lower()] = G.C.SECONDARY_SET[v]
|
|
end
|
|
for _, v in ipairs(SMODS.Suit.obj_buffer) do
|
|
G.ARGS.LOC_COLOURS[v:lower()] = G.C.SUITS[v]
|
|
end
|
|
return G.ARGS.LOC_COLOURS[_c] or _default or G.C.UI.TEXT_DARK
|
|
end
|
|
|
|
function init_localization()
|
|
G.localization.misc.v_dictionary_parsed = {}
|
|
for k, v in pairs(G.localization.misc.v_dictionary) do
|
|
if type(v) == 'table' then
|
|
G.localization.misc.v_dictionary_parsed[k] = {multi_line = true}
|
|
for kk, vv in ipairs(v) do
|
|
G.localization.misc.v_dictionary_parsed[k][kk] = loc_parse_string(vv)
|
|
end
|
|
else
|
|
G.localization.misc.v_dictionary_parsed[k] = loc_parse_string(v)
|
|
end
|
|
end
|
|
G.localization.misc.v_text_parsed = {}
|
|
for k, v in pairs(G.localization.misc.v_text) do
|
|
G.localization.misc.v_text_parsed[k] = {}
|
|
for kk, vv in ipairs(v) do
|
|
G.localization.misc.v_text_parsed[k][kk] = loc_parse_string(vv)
|
|
end
|
|
end
|
|
G.localization.tutorial_parsed = {}
|
|
for k, v in pairs(G.localization.misc.tutorial) do
|
|
G.localization.tutorial_parsed[k] = {multi_line = true}
|
|
for kk, vv in ipairs(v) do
|
|
G.localization.tutorial_parsed[k][kk] = loc_parse_string(vv)
|
|
end
|
|
end
|
|
G.localization.quips_parsed = {}
|
|
for k, v in pairs(G.localization.misc.quips or {}) do
|
|
G.localization.quips_parsed[k] = {multi_line = true}
|
|
for kk, vv in ipairs(v) do
|
|
G.localization.quips_parsed[k][kk] = loc_parse_string(vv)
|
|
end
|
|
end
|
|
for g_k, group in pairs(G.localization) do
|
|
if g_k == 'descriptions' then
|
|
for _, set in pairs(group) do
|
|
for _, center in pairs(set) do
|
|
center.text_parsed = {}
|
|
if not center.text then else
|
|
for _, line in ipairs(center.text) do
|
|
center.text_parsed[#center.text_parsed+1] = loc_parse_string(line)
|
|
end
|
|
center.name_parsed = {}
|
|
for _, line in ipairs(type(center.name) == 'table' and center.name or {center.name}) do
|
|
center.name_parsed[#center.name_parsed+1] = loc_parse_string(line)
|
|
end
|
|
if center.unlock then
|
|
center.unlock_parsed = {}
|
|
for _, line in ipairs(center.unlock) do
|
|
center.unlock_parsed[#center.unlock_parsed+1] = loc_parse_string(line)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function playing_card_joker_effects(cards)
|
|
for i = 1, #G.jokers.cards do
|
|
G.jokers.cards[i]:calculate_joker({playing_card_added = true, cards = cards})
|
|
end
|
|
end
|
|
|
|
function convert_save_to_meta()
|
|
if love.filesystem.getInfo(G.SETTINGS.profile..'/'..'unlocked_jokers.jkr') then
|
|
local _meta = {
|
|
unlocked = {},
|
|
alerted = {},
|
|
discovered = {}
|
|
}
|
|
if love.filesystem.getInfo(G.SETTINGS.profile..'/'..'unlocked_jokers.jkr') then
|
|
for line in string.gmatch( (get_compressed(G.SETTINGS.profile..'/'..'unlocked_jokers.jkr') or '').. "\n", "([^\n]*)\n") do
|
|
local key = line:gsub("%s+", "")
|
|
if key and (key ~= '') then
|
|
_meta.unlocked[key] = true
|
|
end
|
|
end
|
|
end
|
|
if love.filesystem.getInfo(G.SETTINGS.profile..'/'..'discovered_jokers.jkr') then
|
|
for line in string.gmatch( (get_compressed(G.SETTINGS.profile..'/'..'discovered_jokers.jkr') or '').. "\n", "([^\n]*)\n") do
|
|
local key = line:gsub("%s+", "")
|
|
if key and (key ~= '') then
|
|
_meta.discovered[key] = true
|
|
end
|
|
end
|
|
end
|
|
if love.filesystem.getInfo(G.SETTINGS.profile..'/'..'alerted_jokers.jkr') then
|
|
for line in string.gmatch( (get_compressed(G.SETTINGS.profile..'/'..'alerted_jokers.jkr') or '').. "\n", "([^\n]*)\n") do
|
|
local key = line:gsub("%s+", "")
|
|
if key and (key ~= '') then
|
|
_meta.alerted[key] = true
|
|
end
|
|
end
|
|
end
|
|
love.filesystem.remove(G.SETTINGS.profile..'/'..'unlocked_jokers.jkr')
|
|
love.filesystem.remove(G.SETTINGS.profile..'/'..'discovered_jokers.jkr')
|
|
love.filesystem.remove(G.SETTINGS.profile..'/'..'alerted_jokers.jkr')
|
|
|
|
compress_and_save( G.SETTINGS.profile..'/'..'meta.jkr', STR_PACK(_meta))
|
|
end
|
|
end
|
|
|
|
function card_from_control(control)
|
|
G.playing_card = (G.playing_card and G.playing_card + 1) or 1
|
|
local _card = Card(G.deck.T.x, G.deck.T.y, G.CARD_W, G.CARD_H, G.P_CARDS[control.s..'_'..control.r], G.P_CENTERS[control.e or 'c_base'], {playing_card = G.playing_card})
|
|
if control.d then _card:set_edition({[control.d] = true}, true, true) end
|
|
if control.g then _card:set_seal(control.g, true, true) end
|
|
G.deck:emplace(_card)
|
|
table.insert(G.playing_cards, _card)
|
|
end
|
|
|
|
function loc_parse_string(line)
|
|
local parsed_line = {}
|
|
local control = {}
|
|
local _c, _c_name, _c_val, _c_gather = nil, nil, nil, nil
|
|
local _s_gather, _s_ref = nil, nil
|
|
local str_parts, str_it = {}, 1
|
|
for i = 1, #line do
|
|
local char = line:sub(i,i)
|
|
if char == '{' then --Start of a control section, extract all controls
|
|
if str_parts[1] then parsed_line[#parsed_line+1] = {strings = str_parts, control = control or {}} end
|
|
str_parts, str_it = {}, 1
|
|
control, _c, _c_name, _c_val, _c_gather = {}, nil, nil, nil, nil
|
|
_s_gather, _s_ref = nil, nil
|
|
_c = true
|
|
elseif _c and not (char == ':' or char == '}') and not _c_gather then _c_name = (_c_name or '')..char
|
|
elseif _c and char == ':' then _c_gather = true
|
|
elseif _c and not (char == ',' or char == '}') and _c_gather then _c_val = (_c_val or '')..char
|
|
elseif _c and (char == ',' or char == '}') then _c_gather = nil; if _c_name then control[_c_name] = _c_val end; _c_name = nil; _c_val = nil; if char == '}' then _c = nil end
|
|
|
|
elseif not _c and char ~= '#' and not _s_gather then str_parts[str_it] = (str_parts[str_it] or '')..(control['X'] and char:gsub("%s+", "") or char)
|
|
elseif not _c and char == '#' and not _s_gather then _s_gather = true; if str_parts[str_it] then str_it = str_it + 1 end
|
|
elseif not _c and char == '#' and _s_gather then _s_gather = nil; if _s_ref then str_parts[str_it] = {_s_ref}; str_it = str_it + 1; _s_ref = nil end
|
|
elseif not _c and _s_gather then _s_ref = (_s_ref or '')..char
|
|
end
|
|
if i == #line then
|
|
if str_parts[1] then parsed_line[#parsed_line+1] = {strings = str_parts, control = control or {}} end
|
|
return parsed_line
|
|
end
|
|
end
|
|
end
|
|
|
|
--UTF8 handler for special characters, from https://github.com/blitmap/lua-utf8-simple
|
|
utf8 = {pattern = '[%z\1-\127\194-\244][\128-\191]*'}
|
|
utf8.map =
|
|
function (s, f, no_subs)
|
|
local i = 0
|
|
|
|
if no_subs then
|
|
for b, e in s:gmatch('()' .. utf8.pattern .. '()') do
|
|
i = i + 1
|
|
local c = e - b
|
|
f(i, c, b)
|
|
end
|
|
else
|
|
for b, c in s:gmatch('()(' .. utf8.pattern .. ')') do
|
|
i = i + 1
|
|
f(i, c, b)
|
|
end
|
|
end
|
|
end
|
|
utf8.chars =
|
|
function (s, no_subs)
|
|
return coroutine.wrap(function () return utf8.map(s, coroutine.yield, no_subs) end)
|
|
end
|
|
|
|
function localize(args, misc_cat)
|
|
if args and args.vars then
|
|
local reset = {}
|
|
for i, j in pairs(args.vars) do
|
|
if type(j) == 'table' then
|
|
if (j.new and type(j.new) == "function") and ((j.m and j.e) or (j.array and j.sign and (type(j.array) == "table"))) then
|
|
reset[i] = number_format(j)
|
|
end
|
|
end
|
|
end
|
|
for i, j in pairs(reset) do
|
|
args.vars[i] = j
|
|
end
|
|
end
|
|
if args and not (type(args) == 'table') then
|
|
if misc_cat and G.localization.misc[misc_cat] then return G.localization.misc[misc_cat][args] or 'ERROR' end
|
|
return G.localization.misc.dictionary[args] or 'ERROR'
|
|
end
|
|
|
|
local loc_target = nil
|
|
local ret_string = nil
|
|
if args.type == 'other' then
|
|
loc_target = G.localization.descriptions.Other[args.key]
|
|
elseif args.type == 'descriptions' or args.type == 'unlocks' then
|
|
loc_target = G.localization.descriptions[args.set][args.key]
|
|
elseif args.type == 'tutorial' then
|
|
loc_target = G.localization.tutorial_parsed[args.key]
|
|
elseif args.type == 'quips' then
|
|
loc_target = G.localization.quips_parsed[args.key]
|
|
elseif args.type == 'raw_descriptions' then
|
|
loc_target = G.localization.descriptions[args.set][args.key]
|
|
local multi_line = {}
|
|
if loc_target then
|
|
for _, lines in ipairs(args.type == 'unlocks' and loc_target.unlock_parsed or args.type == 'name' and loc_target.name_parsed or args.type == 'text' and loc_target or loc_target.text_parsed) do
|
|
local final_line = ''
|
|
for _, part in ipairs(lines) do
|
|
local assembled_string = ''
|
|
for _, subpart in ipairs(part.strings) do
|
|
assembled_string = assembled_string..(type(subpart) == 'string' and subpart or format_ui_value(args.vars[tonumber(subpart[1])]) or 'ERROR')
|
|
end
|
|
final_line = final_line..assembled_string
|
|
end
|
|
multi_line[#multi_line+1] = final_line
|
|
end
|
|
end
|
|
return multi_line
|
|
elseif args.type == 'text' then
|
|
loc_target = G.localization.misc.v_text_parsed[args.key]
|
|
elseif args.type == 'variable' then
|
|
loc_target = G.localization.misc.v_dictionary_parsed[args.key]
|
|
if not loc_target then return 'ERROR' end
|
|
if loc_target.multi_line then
|
|
local assembled_strings = {}
|
|
for k, v in ipairs(loc_target) do
|
|
local assembled_string = ''
|
|
for _, subpart in ipairs(v[1].strings) do
|
|
assembled_string = assembled_string..(type(subpart) == 'string' and subpart or format_ui_value(args.vars[tonumber(subpart[1])]))
|
|
end
|
|
assembled_strings[k] = assembled_string
|
|
end
|
|
return assembled_strings or {'ERROR'}
|
|
else
|
|
local assembled_string = ''
|
|
for _, subpart in ipairs(loc_target[1].strings) do
|
|
assembled_string = assembled_string..(type(subpart) == 'string' and subpart or format_ui_value(args.vars[tonumber(subpart[1])]))
|
|
end
|
|
ret_string = assembled_string or 'ERROR'
|
|
end
|
|
elseif args.type == 'name_text' then
|
|
if pcall(function() ret_string = G.localization.descriptions[(args.set or args.node.config.center.set)][args.key or args.node.config.center.key].name end) then
|
|
else ret_string = "ERROR" end
|
|
elseif args.type == 'name' then
|
|
loc_target = G.localization.descriptions[(args.set or args.node.config.center.set)][args.key or args.node.config.center.key]
|
|
end
|
|
|
|
if ret_string then return ret_string end
|
|
|
|
if loc_target then
|
|
for _, lines in ipairs(args.type == 'unlocks' and loc_target.unlock_parsed or args.type == 'name' and loc_target.name_parsed or (args.type == 'text' or args.type == 'tutorial' or args.type == 'quips') and loc_target or loc_target.text_parsed) do
|
|
local final_line = {}
|
|
for _, part in ipairs(lines) do
|
|
local assembled_string = ''
|
|
for _, subpart in ipairs(part.strings) do
|
|
assembled_string = assembled_string..(type(subpart) == 'string' and subpart or format_ui_value(args.vars[tonumber(subpart[1])]) or 'ERROR')
|
|
end
|
|
local desc_scale = G.LANG.font.DESCSCALE
|
|
if G.F_MOBILE_UI then desc_scale = desc_scale*1.5 end
|
|
if args.type == 'name' then
|
|
final_line[#final_line+1] = {n=G.UIT.O, config={
|
|
object = DynaText({string = {assembled_string},
|
|
colours = {(part.control.V and args.vars.colours[tonumber(part.control.V)]) or (part.control.C and loc_colour(part.control.C)) or args.text_colour or G.C.UI.TEXT_LIGHT},
|
|
bump = true,
|
|
silent = true,
|
|
pop_in = 0,
|
|
pop_in_rate = 4,
|
|
maxw = 5,
|
|
shadow = true,
|
|
y_offset = -0.6,
|
|
spacing = math.max(0, 0.32*(17 - #assembled_string)),
|
|
scale = (0.55 - 0.004*#assembled_string)*(part.control.s and tonumber(part.control.s) or args.scale or 1)
|
|
})
|
|
}}
|
|
elseif part.control.E then
|
|
local _float, _silent, _pop_in, _bump, _spacing = nil, true, nil, nil, nil
|
|
if part.control.E == '1' then
|
|
_float = true; _silent = true; _pop_in = 0
|
|
elseif part.control.E == '2' then
|
|
_bump = true; _spacing = 1
|
|
end
|
|
final_line[#final_line+1] = {n=G.UIT.O, config={
|
|
object = DynaText({string = {assembled_string}, colours = {part.control.V and args.vars.colours[tonumber(part.control.V)] or loc_colour(part.control.C or nil)},
|
|
float = _float,
|
|
silent = _silent,
|
|
pop_in = _pop_in,
|
|
bump = _bump,
|
|
spacing = _spacing,
|
|
scale = 0.32*(part.control.s and tonumber(part.control.s) or args.scale or 1)*desc_scale})
|
|
}}
|
|
elseif part.control.X then
|
|
final_line[#final_line+1] = {n=G.UIT.C, config={align = "m", colour = loc_colour(part.control.X), r = 0.05, padding = 0.03, res = 0.15}, nodes={
|
|
{n=G.UIT.T, config={
|
|
text = assembled_string,
|
|
colour = loc_colour(part.control.C or nil),
|
|
scale = 0.32*(part.control.s and tonumber(part.control.s) or args.scale or 1)*desc_scale}},
|
|
}}
|
|
else
|
|
final_line[#final_line+1] = {n=G.UIT.T, config={
|
|
detailed_tooltip = part.control.T and (G.P_CENTERS[part.control.T] or G.P_TAGS[part.control.T]) or nil,
|
|
text = assembled_string,
|
|
shadow = args.shadow,
|
|
colour = part.control.V and args.vars.colours[tonumber(part.control.V)] or not part.control.C and args.text_colour or loc_colour(part.control.C or nil, args.default_col),
|
|
scale = 0.32*(part.control.s and tonumber(part.control.s) or args.scale or 1)*desc_scale},}
|
|
end
|
|
end
|
|
if args.type == 'name' or args.type == 'text' then return final_line end
|
|
args.nodes[#args.nodes+1] = final_line
|
|
end
|
|
end
|
|
end
|
|
|
|
function get_stake_sprite(_stake, _scale)
|
|
_stake = _stake or 1
|
|
_scale = _scale or 1
|
|
local stake_sprite = Sprite(0,0,_scale*1,_scale*1,G.ASSET_ATLAS[G.P_CENTER_POOLS.Stake[_stake].atlas], G.P_CENTER_POOLS.Stake[_stake].pos)
|
|
stake_sprite.states.drag.can = false
|
|
if G.P_CENTER_POOLS['Stake'][_stake].shiny then
|
|
stake_sprite.draw = function(_sprite)
|
|
_sprite.ARGS.send_to_shader = _sprite.ARGS.send_to_shader or {}
|
|
_sprite.ARGS.send_to_shader[1] = math.min(_sprite.VT.r*3, 1) + G.TIMERS.REAL/(18) + (_sprite.juice and _sprite.juice.r*20 or 0) + 1
|
|
_sprite.ARGS.send_to_shader[2] = G.TIMERS.REAL
|
|
|
|
Sprite.draw_shader(_sprite, 'dissolve')
|
|
Sprite.draw_shader(_sprite, 'voucher', nil, _sprite.ARGS.send_to_shader)
|
|
end
|
|
end
|
|
return stake_sprite
|
|
end
|
|
|
|
function get_front_spriteinfo(_front)
|
|
if _front and _front.suit and G.SETTINGS.CUSTOM_DECK and G.SETTINGS.CUSTOM_DECK.Collabs then
|
|
local collab = G.SETTINGS.CUSTOM_DECK.Collabs[_front.suit]
|
|
if collab then
|
|
local deckSkin = SMODS.DeckSkins[collab]
|
|
if deckSkin then
|
|
if deckSkin.outdated then
|
|
local hasRank = false
|
|
for i = 1, #deckSkin.ranks do
|
|
if deckSkin.ranks[i] == _front.value then hasRank = true break end
|
|
end
|
|
if hasRank then
|
|
local atlas = G.ASSET_ATLAS[G.SETTINGS.colour_palettes[_front.suit] == 'hc' and deckSkin.hc_atlas or deckSkin.lc_atlas]
|
|
if atlas then
|
|
if deckSkin.pos_style == 'collab' then
|
|
return atlas, G.COLLABS.pos[_front.value]
|
|
elseif deckSkin.pos_style == 'suit' then
|
|
return atlas, { x = _front.pos.x, y = 0}
|
|
elseif deckSkin.pos_style == 'deck' then
|
|
return atlas, _front.pos
|
|
elseif deckSkin.pos_style == 'ranks' or nil then
|
|
for i, rank in ipairs(deckSkin.ranks) do
|
|
if rank == _front.value then
|
|
return atlas, { x = i - 1, y = 0}
|
|
end
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return G.ASSET_ATLAS[G.SETTINGS.colour_palettes[_front.suit] == 'hc' and _front.hc_atlas or _front.lc_atlas or {}] or G.ASSET_ATLAS[_front.atlas] or G.ASSET_ATLAS["cards_"..(G.SETTINGS.colour_palettes[_front.suit] == 'hc' and 2 or 1)], _front.pos
|
|
else
|
|
local palette = deckSkin.palette_map and deckSkin.palette_map[G.SETTINGS.colour_palettes[_front.suit] or ''] or (deckSkin.palettes or {})[1]
|
|
local hasRank = false
|
|
for i = 1, #palette.ranks do
|
|
if palette.ranks[i] == _front.value then hasRank = true break end
|
|
end
|
|
if hasRank then
|
|
local atlas = G.ASSET_ATLAS[palette.atlas]
|
|
if type(palette.pos_style) == "table" then
|
|
if palette.pos_style[_front.value] then
|
|
if palette.pos_style[_front.value].atlas then
|
|
atlas = G.ASSET_ATLAS[palette.pos_style[_front.value].atlas]
|
|
end
|
|
if palette.pos_style[_front.value].pos then
|
|
return atlas, palette.pos_style[_front.value].pos
|
|
end
|
|
elseif palette.pos_style.fallback_style then
|
|
if palette.pos_style.fallback_style == 'collab' then
|
|
return atlas, G.COLLABS.pos[_front.value]
|
|
elseif palette.pos_style.fallback_style == 'suit' then
|
|
return atlas, { x = _front.pos.x, y = 0}
|
|
elseif palette.pos_style.fallback_style == 'deck' then
|
|
return atlas, _front.pos
|
|
end
|
|
end
|
|
elseif palette.pos_style == 'collab' then
|
|
return atlas, G.COLLABS.pos[_front.value]
|
|
elseif palette.pos_style == 'suit' then
|
|
return atlas, { x = _front.pos.x, y = 0}
|
|
elseif palette.pos_style == 'deck' then
|
|
return atlas, _front.pos
|
|
elseif palette.pos_style == 'ranks' or nil then
|
|
for i, rank in ipairs(palette.ranks) do
|
|
if rank == _front.value then
|
|
return atlas, { x = i - 1, y = 0}
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return G.ASSET_ATLAS[palette.hc_default and _front.hc_atlas or _front.lc_atlas or {}] or G.ASSET_ATLAS[_front.atlas] or G.ASSET_ATLAS["cards_"..(palette.hc_default and 2 or 1)], _front.pos
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
return G.ASSET_ATLAS[G.SETTINGS.colourblind_option and _front.hc_atlas or _front.lc_atlas or {}] or G.ASSET_ATLAS[_front.atlas] or G.ASSET_ATLAS["cards_"..(G.SETTINGS.colourblind_option and 2 or 1)], _front.pos
|
|
end
|
|
|
|
function get_stake_col(_stake)
|
|
G.C.STAKES = G.C.STAKES or {
|
|
G.C.WHITE,
|
|
G.C.RED,
|
|
G.C.GREEN,
|
|
G.C.BLACK,
|
|
G.C.BLUE,
|
|
G.C.PURPLE,
|
|
G.C.ORANGE,
|
|
G.C.GOLD
|
|
}
|
|
return G.C.STAKES[_stake]
|
|
end
|
|
|
|
function get_challenge_int_from_id(_id)
|
|
for k, v in pairs(G.CHALLENGES) do
|
|
if v.id == _id then return k end
|
|
end
|
|
return 0
|
|
end
|
|
|
|
function get_starting_params()
|
|
return {
|
|
dollars = 4,
|
|
hand_size = 8,
|
|
discards = 3,
|
|
hands = 4,
|
|
reroll_cost = 5,
|
|
joker_slots = 5,
|
|
ante_scaling = 1,
|
|
consumable_slots = 2,
|
|
no_faces = false,
|
|
erratic_suits_and_ranks = false,
|
|
}
|
|
end
|
|
|
|
function get_challenge_rule(_challenge, _type, _id)
|
|
if _challenge and _challenge.rules and _challenge.rules[_type] then
|
|
for k, v in ipairs(_challenge.rules[_type]) do
|
|
if _id == v.id then return v.value end
|
|
end
|
|
end
|
|
end
|
|
|
|
--SOUND
|
|
function PLAY_SOUND(args)
|
|
args.per = args.per or 1
|
|
args.vol = args.vol or 1
|
|
SOURCES[args.sound_code] = SOURCES[args.sound_code] or {}
|
|
|
|
local should_stream = (string.find(args.sound_code,'music') or string.find(args.sound_code,'ambient'))
|
|
local s = {sound = love.audio.newSource("resources/sounds/"..args.sound_code..'.ogg', should_stream and "stream" or 'static')}
|
|
table.insert(SOURCES[args.sound_code], s)
|
|
s.sound_code = args.sound_code
|
|
s.original_pitch = args.per or 1
|
|
s.original_volume = args.vol or 1
|
|
s.created_on_pause = (args.overlay_menu and true or false)
|
|
s.created_on_state = args.state
|
|
s.sfx_handled = 0
|
|
s.transition_timer = 0
|
|
SET_SFX(s, args)
|
|
love.audio.play(s.sound)
|
|
return s
|
|
end
|
|
|
|
function STOP_AUDIO()
|
|
for _, source in pairs(SOURCES) do
|
|
for _, s in pairs(source) do
|
|
if s.sound:isPlaying() then
|
|
s.sound:stop()
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function SET_SFX(s, args)
|
|
if string.find(s.sound_code,'music') then
|
|
if s.sound_code == args.desired_track then
|
|
s.current_volume = s.current_volume or 1
|
|
s.current_volume = 1*(args.dt*3) + (1-(args.dt*3))*s.current_volume
|
|
else
|
|
s.current_volume = s.current_volume or 0
|
|
s.current_volume = 0*(args.dt*3) + (1-(args.dt*3))*s.current_volume
|
|
end
|
|
s.sound:setVolume(s.current_volume*s.original_volume*(args.sound_settings.volume/100.0)*(args.sound_settings.music_volume/100.0))
|
|
s.sound:setPitch(s.original_pitch*args.pitch_mod)
|
|
else
|
|
if s.temp_pitch ~= s.original_pitch then
|
|
s.sound:setPitch(s.original_pitch)
|
|
s.temp_pitch = s.original_pitch
|
|
end
|
|
local sound_vol = s.original_volume*(args.sound_settings.volume/100.0)*(args.sound_settings.game_sounds_volume/100.0)
|
|
if s.created_on_state == 13 then sound_vol = sound_vol*args.splash_vol end
|
|
if sound_vol <= 0 then
|
|
s.sound:stop()
|
|
else
|
|
s.sound:setVolume(sound_vol)
|
|
end
|
|
end
|
|
end
|
|
|
|
function MODULATE(args)
|
|
for k, v in pairs(SOURCES) do
|
|
if (string.find(k,'music') and (args.desired_track ~= '')) then
|
|
if v[1] and v[1].sound and v[1].sound:isPlaying() then
|
|
else
|
|
RESTART_MUSIC(args)
|
|
break;
|
|
end
|
|
end
|
|
end
|
|
|
|
for k, v in pairs(SOURCES) do
|
|
local i=1
|
|
while i <= #v do
|
|
if not v[i].sound:isPlaying() then
|
|
table.remove(v, i)
|
|
else
|
|
i = i + 1
|
|
end
|
|
end
|
|
|
|
for i, s in ipairs(v) do
|
|
if s.sound and s.sound:isPlaying() and s.original_volume then
|
|
SET_SFX(s, args)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function RESTART_MUSIC(args)
|
|
for k, v in pairs(SOURCES) do
|
|
if string.find(k,'music') then
|
|
for i, s in ipairs(v) do
|
|
s.sound:stop()
|
|
end
|
|
SOURCES[k] = {}
|
|
args.per = 0.7
|
|
args.vol = 0.6
|
|
args.sound_code = k
|
|
local s = PLAY_SOUND(args)
|
|
s.initialized = true
|
|
end
|
|
end
|
|
end
|
|
|
|
function AMBIENT(args)
|
|
for k, v in pairs(SOURCES) do
|
|
if args.ambient_control[k] then
|
|
local start_ambient = args.ambient_control[k].vol > 0
|
|
|
|
for i, s in ipairs(v) do
|
|
if s.sound and s.sound:isPlaying() and s.original_volume then
|
|
s.original_volume = args.ambient_control[k].vol
|
|
SET_SFX(s, args)
|
|
start_ambient = false
|
|
end
|
|
end
|
|
|
|
if start_ambient then
|
|
args.sound_code = k
|
|
args.vol = args.ambient_control[k].vol
|
|
args.per = args.ambient_control[k].per
|
|
PLAY_SOUND(args)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function RESET_STATES(state)
|
|
for k, v in pairs(SOURCES) do
|
|
for i, s in ipairs(v) do
|
|
s.created_on_state = state
|
|
end
|
|
end
|
|
end
|