Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions localization/en-us.lua
Original file line number Diff line number Diff line change
Expand Up @@ -1385,6 +1385,7 @@ return {
k_amount_short = "Amt.",
k_filed_ex = "Filed!",
k_timer = "Timer",
k_nemesis_timer = "Nemesis",
k_mods_list = "Mods List",
k_enemy_jokers = "Enemy Jokers",
k_your_jokers = "Your Jokers",
Expand Down
26 changes: 24 additions & 2 deletions networking/action_handlers.lua
Original file line number Diff line number Diff line change
Expand Up @@ -26,9 +26,16 @@ local json = require("json")

Client = {}

local no_log_actions = {
dataSync = true,
keepAlive = true,
keepAliveAck = true,
}

function Client.send(msg)
local should_send_log = not (msg and msg.action and no_log_actions[msg.action])
msg = json.encode(msg)
if msg ~= '{"action":"keepAliveAck"}' then
if should_send_log then
sendTraceMessage(string.format("Client sent message: %s", msg), "MULTIPLAYER")
end
love.thread.getChannel("uiToNetwork"):push(msg)
Expand Down Expand Up @@ -781,6 +788,12 @@ local function action_magnet_response(p)
sendTraceMessage(string.format("Received magnet joker: %s", MP.UTILS.joker_to_string(card)), "MULTIPLAYER")
end

local function action_data_sync(data)
if data.timer then
MP.GAME.enemy.last_timer = data.timer or 0
end
end

function G.FUNCS.load_end_game_jokers()
local card_area_save, success, err

Expand Down Expand Up @@ -1380,6 +1393,14 @@ function MP.ACTIONS.update_player_usernames()
end
end

function MP.ACTIONS.data_sync()
local timer = (MP.is_layer_active("speedlatro_timer") and MP.speedlatro_timer and MP.speedlatro_timer.real) or MP.GAME.timer
Client.send({
action = "dataSync",
timer = timer
})
end

local function string_to_table(str)
local tbl = {}
for part in string.gmatch(str, "([^,]+)") do
Expand Down Expand Up @@ -1438,6 +1459,7 @@ local HANDLERS = {
moddedAction = action_modded_action,
error = action_error,
keepAlive = action_keep_alive,
dataSync = action_data_sync,
}

function MP.register_action(name, cb)
Expand Down Expand Up @@ -1476,7 +1498,7 @@ function Game:update(dt)

local ok, parsedAction = pcall(json.decode, msg)
if ok then
if not ((parsedAction.action == "keepAlive") or (parsedAction.action == "keepAliveAck")) then
if not no_log_actions[parsedAction.action] then
local log = string.format("Client got %s message: ", parsedAction.action)
for k, v in pairs(parsedAction) do
if parsedAction.action == "startGame" and k == "seed" then
Expand Down
159 changes: 130 additions & 29 deletions ui/game/timer.lua
Original file line number Diff line number Diff line change
Expand Up @@ -2,13 +2,13 @@

function MP.UI.cam_timer_opponent()
if not MP.LOBBY.config.timer then return false end
if MP.GAME.pvp_countdown_in_progress then return false end
if MP.GAME.timer <= 0 then return false end
if MP.GAME.nemesis_timer_started then return false end
if MP.GAME.pvp_countdown_in_progress then return false end
if MP.GAME.timer <= 0 then return false end
if MP.GAME.nemesis_timer_started then return false end
if MP.is_pvp_boss() and MP.is_layer_active("pvp_timer") then
if G.STATE == G.STATES.ROUND_EVAL or G.STATE == G.STATES.NEW_ROUND then return false end
if MP.INSANE_INT.greater_than(MP.GAME.score, MP.GAME.enemy.score) then return true end
if MP.INSANE_INT.equal(MP.GAME.score, MP.GAME.enemy.score) then return MP.GAME.pvp_reached_first end
if MP.INSANE_INT.equal(MP.GAME.score, MP.GAME.enemy.score) then return MP.GAME.pvp_reached_first end
return false
end
return MP.GAME.ready_blind
Expand Down Expand Up @@ -41,6 +41,8 @@ function MP.UI.timer_hud()
colour = G.C.DYN_UI.BOSS_MAIN,
emboss = 0.05,
r = 0.1,
hover = true,
collideable = true,
},
nodes = {
{
Expand Down Expand Up @@ -69,6 +71,8 @@ function MP.UI.timer_hud()
id = "row_round_text",
func = "set_timer_box",
button = "mp_timer_button",
hover = true,
collideable = true,
},
nodes = {
{
Expand Down Expand Up @@ -105,34 +109,114 @@ function MP.UI.timer_hud()
}
end
end
function MP.UI.nemesis_timer_hud()
return {
n = G.UIT.ROOT,
config = { align = "cm", colour = G.C.CLEAR },
nodes = {
{
n = G.UIT.C,
config = {
align = "cm",
padding = 0.05,
minw = 1.45,
minh = 1,
colour = G.C.DYN_UI.BOSS_MAIN,
emboss = 0.05,
r = 0.1,
},
nodes = {
{
n = G.UIT.R,
config = { align = "cm", maxw = 1.35 },
nodes = {
{
n = G.UIT.T,
config = {
text = localize("k_nemesis_timer"),
minh = 0.33,
scale = 0.34,
colour = G.C.UI.TEXT_LIGHT,
shadow = true,
},
},
},
},
{
n = G.UIT.R,
config = {
align = "cm",
r = 0.1,
minw = 1.2,
colour = G.C.DYN_UI.BOSS_DARK,
id = "row_round_text",
},
nodes = {
{
n = G.UIT.O,
config = {
object = DynaText({
string = {
{
ref_table = setmetatable({}, {
__index = function()
if not MP.GAME.enemy or not MP.GAME.enemy.last_timer then
return "0.0"
end
-- All numbers bigger then 10 - display as integer
-- Also accounting for rounding to prevent 10.0 to be displayed
if MP.GAME.enemy.last_timer > 9.95 then
return string.format("%d", MP.GAME.enemy.last_timer)
end
-- Less than 10 - display decimal part
return string.format("%.1f", MP.GAME.enemy.last_timer)
end,
}),
ref_value = "timer",
},
}, -- sorry
colours = { G.C.IMPORTANT },
shadow = true,
scale = 0.8,
}),
id = "timer_UI_count",
},
},
},
},
},
},
},
}
end

function MP.UI.start_pvp_countdown(callback)
local seconds = countdown_seconds
local tick_delay = 1
if MP.LOBBY and MP.LOBBY.config and MP.LOBBY.config.pvp_countdown_seconds then
seconds = MP.LOBBY.config.pvp_countdown_seconds
end
MP.GAME.pvp_countdown_in_progress = true
MP.GAME.pvp_countdown_in_progress = true
MP.GAME.pvp_countdown = seconds

G.CONTROLLER.locks.enter_pvp = true

local function show_next()
if MP.GAME.pvp_countdown <= 0 then
if callback then callback() end
G.E_MANAGER:add_event(Event({
blocking = false,
func = function()
G.E_MANAGER:add_event(Event({
blocking = false,
func = function()
MP.GAME.pvp_countdown_in_progress = nil
return true
end,
}))
return true
end,
}))
G.E_MANAGER:add_event(Event({
blocking = false,
func = function()
G.E_MANAGER:add_event(Event({
blocking = false,
func = function()
MP.GAME.pvp_countdown_in_progress = nil
return true
end,
}))
return true
end,
}))
G.E_MANAGER:add_event(Event({
no_delete = true,
trigger = "after",
Expand Down Expand Up @@ -227,7 +311,7 @@ SMODS.Gradient({
if #self.colours < 2 or not MP.speedlatro_timer then return end
local speedup = MP.current_ruleset().timer_speedup_multiplier or 1

local timer_value = MP.GAME.ready_blind and 0 or -(MP.speedlatro_timer.real or 0)
local timer_value = MP.GAME.ready_blind and 0 or -(MP.speedlatro_timer.real or 0)
local timer = (timer_value / speedup) % self.cycle
local start_index = math.ceil(timer * #self.colours / self.cycle)
if start_index == 0 then start_index = 1 end
Expand All @@ -246,6 +330,23 @@ SMODS.Gradient({
})

function G.FUNCS.set_timer_box(e)
if e.states and e.parent and e.parent.states then
local is_hovered = e.states.hover.is or e.parent.states.hover.is
if is_hovered and not e.parent.children.mp_timer_info then
e.parent.children.mp_timer_info = UIBox({
definition = MP.UI.nemesis_timer_hud(),
config = {
parent = e.parent,
major = e.parent,
align = "tm",
offset = { x = 0, y = -0.1 },
},
})
elseif not is_hovered and e.parent.children.mp_timer_info then
e.parent.children.mp_timer_info:remove()
e.parent.children.mp_timer_info = nil
end
end
if MP.LOBBY.config.timer then
if MP.GAME.timer_started or MP.GAME.nemesis_timer_started then
e.config.colour = G.C.DYN_UI.BOSS_DARK
Expand All @@ -261,7 +362,7 @@ function G.FUNCS.set_timer_box(e)
return
end
e.config.colour = G.C.DYN_UI.BOSS_DARK
e.children[1].config.object.colours =
e.children[1].config.object.colours =
{
(not MP.is_pvp_boss() and not MP.GAME.pvp_countdown_in_progress and MP.is_layer_active("pressure_timer"))
and G.C.IMPORTANT or G.C.UI.TEXT_DARK
Expand Down Expand Up @@ -322,25 +423,25 @@ function Game:update(dt)
local should_check_animations = false

if is_pvp_timer then
-- PvP timer: tick when opponent timering, stop when animations, state checks, pvp blind only
-- PvP timer: tick when opponent timering, stop when animations, state checks, pvp blind only
if not MP.GAME.nemesis_timer_started then return end
if G.GAME.current_round.hands_left <= 0 then return end
if G.GAME.current_round.hands_left <= 0 then return end
if G.STATE == G.STATES.NEW_ROUND or G.STATE == G.STATES.ROUND_EVAL then return end
should_check_animations = true
elseif is_pressure_timer then
-- Pressure timer: tick from the start of a game, stop when reached pvp (unless timered) or animations, not in pvp blind
-- Pressure timer: tick from the start of a game, stop when reached pvp (unless timered) or animations, not in pvp blind
if MP.GAME.pvp_reached and not MP.GAME.nemesis_timer_started then return end
if MP.GAME.ready_blind or is_pvp_boss then return end
should_check_animations = true
elseif is_no_animation_timer then
-- No-animation timer: tick when opponen timering, stop when animations, not in pvp
-- No-animation timer: tick when opponen timering, stop when animations, not in pvp
if not MP.GAME.nemesis_timer_started then return end
if MP.GAME.ready_blind or is_pvp_boss then return end
should_check_animations = true
else
-- Old timer: tick when opponent timering, not in pvp
if is_pvp_boss then return end
if MP.GAME.pvp_reached and MP.GAME.ready_blind and not MP.GAME.timer_started then return end
-- Old timer: tick when opponent timering, not in pvp
if is_pvp_boss then return end
if MP.GAME.pvp_reached and MP.GAME.ready_blind and not MP.GAME.timer_started then return end
if not (MP.GAME.timer_started or MP.GAME.nemesis_timer_started) then return end
end

Expand All @@ -367,8 +468,8 @@ function Game:update(dt)

if MP.GAME.timer == 0 then
MP.GAME.timer_consumed = true
-- PvP timer: end PvP immediately as a loss (only when timered by opponent)
if is_pvp_timer then
-- PvP timer: end PvP immediately as a loss (only when timered by opponent)
if is_pvp_timer then
if MP.GAME.nemesis_timer_started then
MP.ACTIONS.fail_pvp_timer()
end
Expand Down
11 changes: 11 additions & 0 deletions ui/lobby/lobby.lua
Original file line number Diff line number Diff line change
Expand Up @@ -548,6 +548,9 @@ function set_main_menu_UI()
end
end

local data_sync_interval = 5
local data_sync_delay = data_sync_interval

local in_lobby = false
local gameUpdateRef = Game.update
---@diagnostic disable-next-line: duplicate-set-field
Expand All @@ -561,6 +564,14 @@ function Game:update(dt)
MP.reset_game_states()
end
end
-- Data sync every 5 seconds
if MP.LOBBY.code and G.STAGE == G.STAGES.RUN then
data_sync_delay = data_sync_delay - dt
if data_sync_delay < 0 then
data_sync_delay = data_sync_interval
MP.ACTIONS.data_sync()
end
end
gameUpdateRef(self, dt)
end

Expand Down