Implemented challenges!!!!!

This commit is contained in:
Hailey 2021-11-14 14:18:55 +10:00
parent 23b42a534e
commit 9f5f9bc336
12 changed files with 375 additions and 21 deletions

View File

@ -118,7 +118,8 @@ misc_graphics = {
ready = love.graphics.newImage("res/img/ready.png"), ready = love.graphics.newImage("res/img/ready.png"),
go = love.graphics.newImage("res/img/go.png"), go = love.graphics.newImage("res/img/go.png"),
select_mode = love.graphics.newImage("res/img/select_mode.png"), select_mode = love.graphics.newImage("res/img/select_mode.png"),
select_challenge = love.graphics.newImage("res/img/select_challenge_placeholder.png"),
strike = love.graphics.newImage("res/img/strike.png"), strike = love.graphics.newImage("res/img/strike.png"),
santa = love.graphics.newImage("res/img/santa.png"), santa = love.graphics.newImage("res/img/santa.png"),
icon = love.graphics.newImage("res/img/cambridge_transparent.png") icon = love.graphics.newImage("res/img/cambridge_transparent.png")
} }

View File

@ -13,14 +13,14 @@ function love.load()
loadSave() loadSave()
require "funcs" require "funcs"
require "scene" require "scene"
--config["side_next"] = false --config["side_next"] = false
--config["reverse_rotate"] = true --config["reverse_rotate"] = true
--config["das_last_key"] = false --config["das_last_key"] = false
--config["fullscreen"] = false --config["fullscreen"] = false
love.window.setMode(love.graphics.getWidth(), love.graphics.getHeight(), {resizable = true}); love.window.setMode(love.graphics.getWidth(), love.graphics.getHeight(), {resizable = true});
-- used for screenshots -- used for screenshots
GLOBAL_CANVAS = love.graphics.newCanvas() GLOBAL_CANVAS = love.graphics.newCanvas()
@ -42,6 +42,13 @@ function initModules()
game_modes[#game_modes+1] = require ("tetris.modes."..string.sub(mode_list[i],1,-5)) game_modes[#game_modes+1] = require ("tetris.modes."..string.sub(mode_list[i],1,-5))
end end
end end
challenges = {}
challenge_list = love.filesystem.getDirectoryItems("tetris/challenges")
for i=1,#challenge_list do
if(challenge_list[i] ~= "challenge.lua" and string.sub(challenge_list[i], -4) == ".lua") then
challenges[#challenges+1] = require ("tetris.challenges."..string.sub(challenge_list[i],1,-5))
end
end
rulesets = {} rulesets = {}
rule_list = love.filesystem.getDirectoryItems("tetris/rulesets") rule_list = love.filesystem.getDirectoryItems("tetris/rulesets")
for i=1,#rule_list do for i=1,#rule_list do
@ -72,7 +79,7 @@ function love.draw()
(height - scale_factor * 480) / 2 (height - scale_factor * 480) / 2
) )
love.graphics.scale(scale_factor) love.graphics.scale(scale_factor)
scene:render() scene:render()
if config.gamesettings.display_gamemode == 1 or scene.title == "Title" then if config.gamesettings.display_gamemode == 1 or scene.title == "Title" then
@ -83,9 +90,9 @@ function love.draw()
"fps - " .. version, 0, 460, 635, "right" "fps - " .. version, 0, 460, 635, "right"
) )
end end
love.graphics.pop() love.graphics.pop()
love.graphics.setCanvas() love.graphics.setCanvas()
love.graphics.setColor(1,1,1,1) love.graphics.setColor(1,1,1,1)
love.graphics.draw(GLOBAL_CANVAS) love.graphics.draw(GLOBAL_CANVAS)
@ -120,7 +127,7 @@ function love.keypressed(key, scancode)
GLOBAL_CANVAS:newImageData():encode("png", ss_name) GLOBAL_CANVAS:newImageData():encode("png", ss_name)
-- function keys are reserved -- function keys are reserved
elseif string.match(scancode, "^f[1-9]$") or string.match(scancode, "^f[1-9][0-9]+$") then elseif string.match(scancode, "^f[1-9]$") or string.match(scancode, "^f[1-9][0-9]+$") then
return return
-- escape is reserved for menu_back -- escape is reserved for menu_back
elseif scancode == "escape" then elseif scancode == "escape" then
scene:onInputPress({input="menu_back", type="key", key=key, scancode=scancode}) scene:onInputPress({input="menu_back", type="key", key=key, scancode=scancode})
@ -140,7 +147,7 @@ function love.keyreleased(key, scancode)
scene:onInputRelease({input="menu_back", type="key", key=key, scancode=scancode}) scene:onInputRelease({input="menu_back", type="key", key=key, scancode=scancode})
-- function keys are reserved -- function keys are reserved
elseif string.match(scancode, "^f[1-9]$") or string.match(scancode, "^f[1-9][0-9]+$") then elseif string.match(scancode, "^f[1-9]$") or string.match(scancode, "^f[1-9][0-9]+$") then
return return
-- handle all other keys; tab is reserved, but the input config scene keeps it from getting configured as a game input, so pass tab to the scene here -- handle all other keys; tab is reserved, but the input config scene keeps it from getting configured as a game input, so pass tab to the scene here
else else
local input_released = nil local input_released = nil
@ -186,7 +193,7 @@ function love.joystickaxis(joystick, axis, value)
config.input.joysticks and config.input.joysticks and
config.input.joysticks[joystick:getName()] and config.input.joysticks[joystick:getName()] and
config.input.joysticks[joystick:getName()].axes and config.input.joysticks[joystick:getName()].axes and
config.input.joysticks[joystick:getName()].axes[axis] config.input.joysticks[joystick:getName()].axes[axis]
then then
if math.abs(value) >= 1 then if math.abs(value) >= 1 then
input_pressed = config.input.joysticks[joystick:getName()].axes[axis][value >= 1 and "positive" or "negative"] input_pressed = config.input.joysticks[joystick:getName()].axes[axis][value >= 1 and "positive" or "negative"]
@ -314,10 +321,10 @@ function love.run()
if love.timer then if love.timer then
processBGMFadeout(love.timer.step()) processBGMFadeout(love.timer.step())
end end
if scene and scene.update and love.timer then if scene and scene.update and love.timer then
scene:update() scene:update()
local frame_duration = 1.0 / TARGET_FPS local frame_duration = 1.0 / TARGET_FPS
if time_accumulator < frame_duration then if time_accumulator < frame_duration then
if love.graphics and love.graphics.isActive() and love.draw then if love.graphics and love.graphics.isActive() and love.draw then

Binary file not shown.

After

Width:  |  Height:  |  Size: 7.6 KiB

View File

@ -10,7 +10,9 @@ function Scene:onInputRelease() end
ExitScene = require "scene.exit" ExitScene = require "scene.exit"
GameScene = require "scene.game" GameScene = require "scene.game"
ChallengeScene = require "scene.challenge"
ModeSelectScene = require "scene.mode_select" ModeSelectScene = require "scene.mode_select"
ChallengeSelectScene = require "scene.challenge_select"
KeyConfigScene = require "scene.key_config" KeyConfigScene = require "scene.key_config"
StickConfigScene = require "scene.stick_config" StickConfigScene = require "scene.stick_config"
InputConfigScene = require "scene.input_config" InputConfigScene = require "scene.input_config"

93
scene/challenge.lua Normal file
View File

@ -0,0 +1,93 @@
local ChallengeScene = Scene:extend()
ChallengeScene.title = "Challenge"
require 'load.save'
function ChallengeScene:new(game_mode, ruleset, inputs)
self.retry_mode = game_mode
self.retry_ruleset = ruleset
self.secret_inputs = inputs
self.game = game_mode(self.secret_inputs)
self.ruleset = ruleset(self.game)
self.game:initialize(self.ruleset)
self.inputs = {
left=false,
right=false,
up=false,
down=false,
rotate_left=false,
rotate_left2=false,
rotate_right=false,
rotate_right2=false,
rotate_180=false,
hold=false,
}
self.paused = false
DiscordRPC:update({
details = "In challenge",
state = self.game.name,
largeImageKey = "ingame-"..self.game:getBackground().."00"
})
end
function ChallengeScene:update()
if love.window.hasFocus() and not self.paused then
local inputs = {}
for input, value in pairs(self.inputs) do
inputs[input] = value
end
self.game:update(inputs, self.ruleset)
self.game.grid:update()
DiscordRPC:update({
largeImageKey = "ingame-"..self.game:getBackground().."00"
})
end
end
function ChallengeScene:render()
self.game:draw(self.paused)
end
function ChallengeScene:onInputPress(e)
if (
self.game.game_over or self.game.completed
) and (
e.input == "menu_decide" or
e.input == "menu_back" or
e.input == "retry"
) then
highscore_entry = self.game:getHighscoreData()
highscore_hash = self.game.hash .. "-" .. self.ruleset.hash
submitHighscore(highscore_hash, highscore_entry)
self.game:onExit()
scene = e.input == "retry" and ChallengeScene(self.retry_mode, self.retry_ruleset, self.secret_inputs) or ModeSelectScene()
elseif e.input == "retry" then
switchBGM(nil)
self.game:onExit()
scene = ChallengeScene(self.retry_mode, self.retry_ruleset, self.secret_inputs)
elseif e.input == "pause" and not (self.game.game_over or self.game.completed) then
self.paused = not self.paused
if self.paused then pauseBGM()
else resumeBGM() end
elseif e.input == "menu_back" then
self.game:onExit()
scene = ChallengeSelectScene()
elseif e.input and string.sub(e.input, 1, 5) ~= "menu_" then
self.inputs[e.input] = true
end
end
function ChallengeScene:onInputRelease(e)
if e.input and string.sub(e.input, 1, 5) ~= "menu_" then
self.inputs[e.input] = false
end
end
function submitHighscore(hash, data)
if not highscores[hash] then highscores[hash] = {} end
table.insert(highscores[hash], data)
saveHighscores()
end
return ChallengeScene

182
scene/challenge_select.lua Normal file
View File

@ -0,0 +1,182 @@
local ChallengeSelectScene = Scene:extend()
ChallengeSelectScene.title = "Challenges"
current_challenge = 1
function indexOf(array, value)
for i, v in ipairs(array) do
if v == value then
return i
end
end
return nil
end
function ChallengeSelectScene:new()
-- reload custom modules
initModules()
if table.getn(challenges) == 0 then
self.display_warning = true
current_challenge = 1
else
self.display_warning = false
if current_challenge > table.getn(challenges) then
current_challenge = 1
end
end
self.menu_state = {
challenge = current_challenge,
select = "challenge",
}
self.secret_inputs = {}
self.das = 0
DiscordRPC:update({
details = "In menus",
state = "Choosing a challenge",
largeImageKey = "ingame-000"
})
end
function ChallengeSelectScene: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 challenge",
largeImageKey = "ingame-000"
})
end
function ChallengeSelectScene:render()
love.graphics.draw(
backgrounds[0],
0, 0, 0,
0.5, 0.5
)
love.graphics.draw(misc_graphics["select_challenge"], 20, 40)
if self.display_warning then
love.graphics.setFont(font_3x5_3)
love.graphics.printf(
"You have no challenges",
80, 200, 480, "center"
)
love.graphics.setFont(font_3x5_2)
love.graphics.printf(
"Come back to this menu after getting more challenges. " ..
"Press any button to return to the main menu.",
80, 250, 480, "center"
)
return
end
if self.menu_state.select == "challenge" then
love.graphics.setColor(1, 1, 1, 0.5)
end
love.graphics.rectangle("fill", 20, 258, 240, 22)
if self.menu_state.select == "challenge" then
love.graphics.setColor(1, 1, 1, 0.25)
end
love.graphics.setColor(1, 1, 1, 1)
love.graphics.setFont(font_3x5_2)
for idx, challenge in pairs(challenges) do
if(idx >= self.menu_state.challenge-9 and idx <= self.menu_state.challenge+9) then
love.graphics.printf(challenge.name, 40, (260 - 20*(self.menu_state.challenge)) + 20 * idx, 200, "left")
cur_tagline = challenge.tagline
end
end
end
function ChallengeSelectScene: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
for idx, mode in pairs(game_modes) do
if mode.hash == challenges[self.menu_state.challenge].mode then
cur_mode = idx
break
end
end
for idx, ruleset in pairs(rulesets) do
if ruleset.hash == challenges[self.menu_state.challenge].ruleset then
cur_ruleset = idx
break
end
end
playSE("mode_decide")
saveConfig()
scene = ChallengeScene(
challenges[current_challenge],
rulesets[cur_ruleset]
)
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
love.graphics.printf("test???", 340, 258, 200, "left")
end
function ChallengeSelectScene: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 ChallengeSelectScene:changeOption(rel)
self:changechallenge(rel)
playSE("cursor")
end
function ChallengeSelectScene:changechallenge(rel)
local len = table.getn(challenges)
self.menu_state.challenge = Mod1(self.menu_state.challenge + rel, len)
end
return ChallengeSelectScene

View File

@ -1,6 +1,6 @@
local ModeSelectScene = Scene:extend() local ModeSelectScene = Scene:extend()
ModeSelectScene.title = "Game Start" ModeSelectScene.title = "Freeplay"
current_mode = 1 current_mode = 1
current_ruleset = 1 current_ruleset = 1

View File

@ -5,6 +5,7 @@ TitleScene.restart_message = false
local main_menu_screens = { local main_menu_screens = {
ModeSelectScene, ModeSelectScene,
ChallengeSelectScene,
SettingsScene, SettingsScene,
CreditsScene, CreditsScene,
ExitScene, ExitScene,

View File

@ -0,0 +1,26 @@
require 'funcs'
local GameMode = require 'tetris.modes.gamemode'
local Piece = require 'tetris.components.piece'
local Grid = require 'tetris.components.grid'
local Randomizer = require 'tetris.randomizers.randomizer'
local Bag7Randomizer = require 'tetris.randomizers.bag7noI'
local MarathonGF = require 'tetris.modes.marathon_gf'
local TetrsChallenge = MarathonGF:extend()
TetrsChallenge.name = "Tetrs"
TetrsChallenge.hash = "Tetrs"
TetrsChallenge.mode = "MarathonGF"
TetrsChallenge.ruleset = "Standard"
TetrsChallenge.tagline = "abababa"
TetrsChallenge.description = "Complete a mode with a specific ruleset and idk they did some other stupid things too lol"
function TetrsChallenge:new()
TetrsChallenge.super:new()
self.randomizer = Bag7Randomizer()
self.next_queue_length = 6
end
return TetrsChallenge

View File

@ -0,0 +1,23 @@
-- currently you need to require and extend the gamemode you're making a challenge out of
require 'funcs'
local GameMode = require 'tetris.modes.gamemode'
local Piece = require 'tetris.components.piece'
local Grid = require 'tetris.components.grid'
local Randomizer = require 'tetris.randomizers.randomizer'
local BagRandomizer = require 'tetris.randomizers.bag'
local MarathonGF = require 'tetris.modes.marathon_gf'
local Challenge = GameMode:extend()
Challenge.name = "A really cool challenge name"
Challenge.hash = ""
Challenge.mode = ""
Challenge.ruleset = "Guideline SRS"
Challenge.tagline = "Are you up for this challenge?"
Challenge.description = "Complete a mode with a specific ruleset and idk they did some other stupid things too lol"
return Challenge

View File

@ -143,7 +143,7 @@ function GameMode:update(inputs, ruleset)
) then ) then
self:onAttemptPieceRotate(self.piece, self.grid) self:onAttemptPieceRotate(self.piece, self.grid)
end end
if self.piece == nil then if self.piece == nil then
self:processDelays(inputs, ruleset) self:processDelays(inputs, ruleset)
else else
@ -243,7 +243,7 @@ function GameMode:update(inputs, ruleset)
if self.immobile_spin_bonus and if self.immobile_spin_bonus and
self.piece.last_rotated and ( self.piece.last_rotated and (
self.piece:isDropBlocked(self.grid) and self.piece:isDropBlocked(self.grid) and
self.piece:isMoveBlocked(self.grid, { x=-1, y=0 }) and self.piece:isMoveBlocked(self.grid, { x=-1, y=0 }) and
self.piece:isMoveBlocked(self.grid, { x=1, y=0 }) and self.piece:isMoveBlocked(self.grid, { x=1, y=0 }) and
self.piece:isMoveBlocked(self.grid, { x=0, y=-1 }) self.piece:isMoveBlocked(self.grid, { x=0, y=-1 })
) then ) then
@ -251,7 +251,7 @@ function GameMode:update(inputs, ruleset)
end end
self.grid:applyPiece(self.piece) self.grid:applyPiece(self.piece)
-- mark squares (can be overridden) -- mark squares (can be overridden)
if self.square_mode then if self.square_mode then
self.squares = self.squares + self.grid:markSquares() self.squares = self.squares + self.grid:markSquares()
@ -312,7 +312,7 @@ function GameMode:onAttemptPieceRotate(piece, grid) end
function GameMode:onPieceMove(piece, grid, dx) end function GameMode:onPieceMove(piece, grid, dx) end
function GameMode:onPieceRotate(piece, grid, drot) end function GameMode:onPieceRotate(piece, grid, drot) end
function GameMode:onPieceDrop(piece, grid, dy) end function GameMode:onPieceDrop(piece, grid, dy) end
function GameMode:onPieceLock(piece, cleared_row_count) function GameMode:onPieceLock(piece, cleared_row_count)
playSE("lock") playSE("lock")
end end
@ -616,7 +616,7 @@ function GameMode:drawLineClearAnimation()
-- animation function -- animation function
-- params: block x, y, skin, colour -- params: block x, y, skin, colour
-- returns: table with RGBA, skin, colour, x, y -- returns: table with RGBA, skin, colour, x, y
-- Fadeout (default) -- Fadeout (default)
--[[ --[[
function animation(x, y, skin, colour) function animation(x, y, skin, colour)
@ -728,8 +728,8 @@ function GameMode:drawNextQueue(ruleset)
if self.hold_queue ~= nil and self.enable_hold then if self.hold_queue ~= nil and self.enable_hold then
self:setHoldOpacity() self:setHoldOpacity()
drawPiece( drawPiece(
self.hold_queue.shape, self.hold_queue.shape,
self.hold_queue.skin, self.hold_queue.skin,
ruleset.block_offsets[self.hold_queue.shape][self.hold_queue.orientation], ruleset.block_offsets[self.hold_queue.shape][self.hold_queue.orientation],
-16, -32 -16, -32
) )
@ -828,7 +828,7 @@ end
function GameMode:drawSectionTimesWithSplits(current_section, section_limit) function GameMode:drawSectionTimesWithSplits(current_section, section_limit)
section_limit = section_limit or math.huge section_limit = section_limit or math.huge
local section_x = 440 local section_x = 440
local split_x = 530 local split_x = 530
@ -843,7 +843,7 @@ function GameMode:drawSectionTimesWithSplits(current_section, section_limit)
love.graphics.printf(formatTime(split_time), split_x, 40 + 20 * section, 90, "left") love.graphics.printf(formatTime(split_time), split_x, 40 + 20 * section, 90, "left")
end end
end end
if (current_section <= section_limit) then if (current_section <= section_limit) then
love.graphics.printf(formatTime(self.frames - self.section_start_time), section_x, 40 + 20 * current_section, 90, "left") love.graphics.printf(formatTime(self.frames - self.section_start_time), section_x, 40 + 20 * current_section, 90, "left")
love.graphics.printf(formatTime(self.frames), split_x, 40 + 20 * current_section, 90, "left") love.graphics.printf(formatTime(self.frames), split_x, 40 + 20 * current_section, 90, "left")

View File

@ -0,0 +1,19 @@
-- for the pre-packaged/example challenge tetrs
local Randomizer = require 'tetris.randomizers.randomizer'
local Bag7NoIRandomizer = Randomizer:extend()
function Bag7NoIRandomizer:initialize()
self.bag = {"J", "L", "O", "S", "T", "Z"}
end
function Bag7NoIRandomizer:generatePiece()
if next(self.bag) == nil then
self.bag = {"J", "L", "O", "S", "T", "Z"}
end
local x = math.random(table.getn(self.bag))
return table.remove(self.bag, x)
end
return Bag7NoIRandomizer