From 71ada76a004f81b6fe83c64ec532d447b5ed0fbd Mon Sep 17 00:00:00 2001 From: BoatsandJoes Date: Sat, 4 Dec 2021 23:17:25 -0600 Subject: [PATCH] Started work on replay select menu. --- main.lua | 2 + scene.lua | 2 + scene/replay.lua | 11 +++ scene/replay_select.lua | 148 ++++++++++++++++++++++++++++++++++++++ scene/title.lua | 1 + tetris/modes/gamemode.lua | 30 ++++++-- 6 files changed, 189 insertions(+), 5 deletions(-) create mode 100644 scene/replay.lua create mode 100644 scene/replay_select.lua diff --git a/main.lua b/main.lua index f54b3c1..c48c24f 100644 --- a/main.lua +++ b/main.lua @@ -35,6 +35,8 @@ function love.load() end function initModules() + -- replays are not loaded here, but they are cleared + replays = {} game_modes = {} mode_list = love.filesystem.getDirectoryItems("tetris/modes") for i=1,#mode_list do diff --git a/scene.lua b/scene.lua index aaa81b8..cc5a2f6 100644 --- a/scene.lua +++ b/scene.lua @@ -10,7 +10,9 @@ function Scene:onInputRelease() end ExitScene = require "scene.exit" GameScene = require "scene.game" +ReplayScene = require "scene.replay" ModeSelectScene = require "scene.mode_select" +ReplaySelectScene = require "scene.replay_select" KeyConfigScene = require "scene.key_config" StickConfigScene = require "scene.stick_config" InputConfigScene = require "scene.input_config" diff --git a/scene/replay.lua b/scene/replay.lua new file mode 100644 index 0000000..2be8812 --- /dev/null +++ b/scene/replay.lua @@ -0,0 +1,11 @@ +local ReplayScene = Scene:extend() + +ReplayScene.title = "Replay" + +require 'load.save' + +function ReplayScene:new(replay, inputs) + -- TODO +end + +return ReplayScene diff --git a/scene/replay_select.lua b/scene/replay_select.lua new file mode 100644 index 0000000..b359e8d --- /dev/null +++ b/scene/replay_select.lua @@ -0,0 +1,148 @@ +local ReplaySelectScene = Scene:extend() + +ReplaySelectScene.title = "Replays" + +local binser = require 'libs.binser' + +current_replay = 1 + +function ReplaySelectScene:new() + -- reload custom modules + initModules() + -- load replays + replays = {} + replay_file_list = love.filesystem.getDirectoryItems("replays") + for i=1,#replay_file_list do + replays[i] = binser.deserialize(love.filesystem.read("replays/"..replay_file_list[i])) + end + -- TODO sort replays list + if table.getn(replays) == 0 then + self.display_warning = true + current_replay = 1 + else + self.display_warning = false + if current_replay > table.getn(replays) then + current_replay = 1 + end + end + + self.menu_state = { + replay = current_replay, + } + self.secret_inputs = {} + self.das = 0 + DiscordRPC:update({ + details = "In menus", + state = "Choosing a replay", + largeImageKey = "ingame-000" + }) +end + +function ReplaySelectScene:update() + switchBGM(nil) -- experimental + + if self.das_up or self.das_down then + self.das = self.das + 1 + else + self.das = 0 + end + + if self.das >= 15 then + self:changeOption(self.das_up and -1 or 1) + self.das = self.das - 4 + end + + DiscordRPC:update({ + details = "In menus", + state = "Choosing a replay", + largeImageKey = "ingame-000" + }) +end + +function ReplaySelectScene:render() + love.graphics.draw( + backgrounds[0], + 0, 0, 0, + 0.5, 0.5 + ) + + -- Same graphic as mode select + love.graphics.draw(misc_graphics["select_mode"], 20, 40) + + if self.display_warning then + love.graphics.setFont(font_3x5_3) + love.graphics.printf( + "You have no replays.", + 80, 200, 480, "center" + ) + love.graphics.setFont(font_3x5_2) + love.graphics.printf( + "Come back to this menu after playing some games. " .. + "Press any button to return to the main menu.", + 80, 250, 480, "center" + ) + return + end + + love.graphics.setColor(1, 1, 1, 0.5) + love.graphics.rectangle("fill", 20, 258, 240, 22) + + love.graphics.setFont(font_3x5_2) + for idx, replay in pairs(replays) do + if(idx >= self.menu_state.replay-9 and idx <= self.menu_state.replay+9) then + local display_string = replay["mode"].." "..replay["ruleset"].." "..replay["timer"].." "..replay["level"].." "..os.date("%c", replay["timestamp"]) + love.graphics.printf(display_string, 40, (260 - 20*(self.menu_state.replay)) + 20 * idx, 200, "left") + end + end +end + +function ReplaySelectScene:onInputPress(e) + if self.display_warning and e.input then + scene = TitleScene() + elseif e.type == "wheel" then + if e.x % 2 == 1 then + self:switchSelect() + end + if e.y ~= 0 then + self:changeOption(-e.y) + end + elseif e.input == "menu_decide" or e.scancode == "return" then + current_replay = self.menu_state.replay + -- Same as mode decide + playSE("mode_decide") + scene = ReplayScene( + replays[self.menu_state.replay], + self.secret_inputs + ) + elseif e.input == "up" or e.scancode == "up" then + self:changeOption(-1) + self.das_up = true + self.das_down = nil + elseif e.input == "down" or e.scancode == "down" then + self:changeOption(1) + self.das_down = true + self.das_up = nil + elseif e.input == "menu_back" or e.scancode == "delete" or e.scancode == "backspace" then + scene = TitleScene() + elseif e.input then + self.secret_inputs[e.input] = true + end +end + +function ReplaySelectScene:onInputRelease(e) + if e.input == "up" or e.scancode == "up" then + self.das_up = nil + elseif e.input == "down" or e.scancode == "down" then + self.das_down = nil + elseif e.input then + self.secret_inputs[e.input] = false + end +end + +function ReplaySelectScene:changeOption(rel) + local len = table.getn(replays) + self.menu_state.replay = Mod1(self.menu_state.replay + rel, len) + playSE("cursor") +end + +return ReplaySelectScene diff --git a/scene/title.lua b/scene/title.lua index 05df3bb..6f111dc 100644 --- a/scene/title.lua +++ b/scene/title.lua @@ -5,6 +5,7 @@ TitleScene.restart_message = false local main_menu_screens = { ModeSelectScene, + ReplaySelectScene, SettingsScene, CreditsScene, ExitScene, diff --git a/tetris/modes/gamemode.lua b/tetris/modes/gamemode.lua index f765be1..1c4632a 100644 --- a/tetris/modes/gamemode.lua +++ b/tetris/modes/gamemode.lua @@ -360,21 +360,41 @@ function GameMode:onGameOver() if self.game_over_frames < animation_length then -- Show field for a bit, then fade out. alpha = math.pow(2048, self.game_over_frames/animation_length - 1) - elseif self.game_over_frames < 2 * animation_length then - -- Keep field hidden for a short time, then pop it back in (for screenshots). + elseif self.game_over_frames == animation_length then alpha = 1 - elseif self.game_over_frames == 2 * animation_length then -- Save replay. local replay = {} replay["inputs"] = self.replay_inputs replay["pieces"] = self.replay_pieces replay["mode"] = self.name replay["ruleset"] = self.ruleset.name + replay["timer"] = self.frames + replay["score"] = self.score + replay["level"] = self.level + replay["lines"] = self.lines + replay["gamesettings"] = config.gamesettings + replay["timestamp"] = os.time() if love.filesystem.getInfo("replays") == nil then love.filesystem.createDirectory("replays") end - local replay_number = table.getn(love.filesystem.getDirectoryItems("replays")) + 1 - love.filesystem.write("replays/"..replay_number..".lua", binser.serialize(replay)) + local replay_files = love.filesystem.getDirectoryItems("replays") + -- Select replay filename that doesn't collide with an existing one + local replay_number = 0 + local collision = true + while collision do + collision = false + replay_number = replay_number + 1 + for key, file in pairs(replay_files) do + if file == replay_number..".rply" then + collision = true + break + end + end + end + love.filesystem.write("replays/"..replay_number..".rply", binser.serialize(replay)) + elseif self.game_over_frames < 2 * animation_length then + -- Keep field hidden for a short time, then pop it back in (for screenshots). + alpha = 1 end love.graphics.setColor(0, 0, 0, alpha) love.graphics.rectangle(