Compare commits

..

17 Commits

Author SHA1 Message Date
Ishaan Bhardwaj
042dbd220b text was slightly off-center 2020-12-20 15:31:42 -05:00
Ishaan Bhardwaj
548612123a SFX and BGM are now separate sliders 2020-12-20 15:26:32 -05:00
Ishaan Bhardwaj
f4675da0b0 Unlock and fix BGM, add pause button 2020-12-20 15:08:53 -05:00
Ishaan Bhardwaj
511e9592bc Fixed next piece sounds not playing 2020-12-20 10:47:24 -05:00
Ishaan Bhardwaj
5f3990ff58 Small credits update 2020-12-20 10:35:05 -05:00
Ishaan Bhardwaj
50ff4adf27 Credits scene <3 2020-12-20 10:28:34 -05:00
Ishaan Bhardwaj
87b88f4b42 Refactored settings menus 2020-12-20 09:45:49 -05:00
Ishaan Bhardwaj
130c2ea403 Easier easter egg #2 2020-12-19 20:44:24 -05:00
Ishaan Bhardwaj
1ea304916e Made it easier to see the egg 2020-12-19 20:43:57 -05:00
Ishaan Bhardwaj
e26b094830 A little easter egg... 2020-12-19 20:31:14 -05:00
Ishaan Bhardwaj
bcb44725bf Cambridge RS fix lock in midair 2020-12-19 14:04:08 -05:00
Ishaan Bhardwaj
2990844c52 Adjusted tuning scene 2020-12-18 23:17:53 -05:00
Ishaan Bhardwaj
c343014d6f Tuning scene 2020-12-18 21:28:30 -05:00
Ishaan Bhardwaj
605add7e94 Added customizable DAS and ARR! (read comments)
This only applies to modes that allow it.
This feature does not apply to main modes (yet)
2020-12-18 21:25:09 -05:00
Ishaan Bhardwaj
d3b647ca71 Fixed certain rulesets locking in midair 2020-12-18 21:24:10 -05:00
Ishaan Bhardwaj
1101aa467d Smooth piece drop 2020-12-17 18:00:07 -05:00
Ishaan Bhardwaj
ce27a7ed18 Update Tetra Online README 2020-12-17 10:51:08 -05:00
24 changed files with 427 additions and 23 deletions

View File

@@ -3,8 +3,7 @@
Important notice Important notice
================ ================
Tetra Online was recently struck by an illegal DMCA claim from the Tetris Company. ![Tetra Online Notice](https://pbs.twimg.com/media/Eo3CkIHW8AEoK_U?format=png&name=small)
Please, spread awareness of this, and use the hashtag #DMCAgaming in your posts.
Cambridge Cambridge
========= =========

View File

@@ -114,3 +114,29 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software. The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
simple-slider (https://love2d.org/forums/viewtopic.php?t=80711)
--------------------
Copyright (c) 2016 George Prosser
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

138
libs/simple-slider.lua Normal file
View File

@@ -0,0 +1,138 @@
--[[
Copyright (c) 2016 George Prosser
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
]]
local slider = {}
slider.__index = slider
function newSlider(x, y, length, value, min, max, setter, style)
local s = {}
s.value = (value - min) / (max - min)
s.min = min
s.max = max
s.setter = setter
s.x = x
s.y = y
s.length = length
local p = style or {}
s.width = p.width or length * 0.1
s.orientation = p.orientation or 'horizontal'
s.track = p.track or 'rectangle'
s.knob = p.knob or 'rectangle'
s.grabbed = false
s.wasDown = true
s.ox = 0
s.oy = 0
return setmetatable(s, slider)
end
function slider:update(mouseX, mouseY, mouseDown)
local x = mouseX or love.mouse.getX()
local y = mouseY or love.mouse.getY()
local down = love.mouse.isDown(1)
if mouseDown ~= nil then
down = mouseDown
end
local knobX = self.x
local knobY = self.y
if self.orientation == 'horizontal' then
knobX = self.x - self.length/2 + self.length * self.value
elseif self.orientation == 'vertical' then
knobY = self.y + self.length/2 - self.length * self.value
end
local ox = x - knobX
local oy = y - knobY
local dx = ox - self.ox
local dy = oy - self.oy
if down then
if self.grabbed then
if self.orientation == 'horizontal' then
self.value = self.value + dx / self.length
elseif self.orientation == 'vertical' then
self.value = self.value - dy / self.length
end
elseif (x > knobX - self.width/2 and x < knobX + self.width/2 and y > knobY - self.width/2 and y < knobY + self.width/2) and not self.wasDown then
self.ox = ox
self.oy = oy
self.grabbed = true
end
else
self.grabbed = false
end
self.value = math.max(0, math.min(1, self.value))
if self.setter ~= nil then
self.setter(self.min + self.value * (self.max - self.min))
end
self.wasDown = down
end
function slider:draw()
if self.track == 'rectangle' then
if self.orientation == 'horizontal' then
love.graphics.rectangle('line', self.x - self.length/2 - self.width/2, self.y - self.width/2, self.length + self.width, self.width)
elseif self.orientation == 'vertical' then
love.graphics.rectangle('line', self.x - self.width/2, self.y - self.length/2 - self.width/2, self.width, self.length + self.width)
end
elseif self.track == 'line' then
if self.orientation == 'horizontal' then
love.graphics.line(self.x - self.length/2, self.y, self.x + self.length/2, self.y)
elseif self.orientation == 'vertical' then
love.graphics.line(self.x, self.y - self.length/2, self.x, self.y + self.length/2)
end
elseif self.track == 'roundrect' then
if self.orientation == 'horizontal' then
love.graphics.rectangle('line', self.x - self.length/2 - self.width/2, self.y - self.width/2, self.length + self.width, self.width, self.width/2, self.width)
elseif self.orientation == 'vertical' then
love.graphics.rectangle('line', self.x - self.width/2, self.y - self.length/2 - self.width/2, self.width, self.length + self.width, self.width, self.width/2)
end
end
local knobX = self.x
local knobY = self.y
if self.orientation == 'horizontal' then
knobX = self.x - self.length/2 + self.length * self.value
elseif self.orientation == 'vertical' then
knobY = self.y + self.length/2 - self.length * self.value
end
if self.knob == 'rectangle' then
love.graphics.rectangle('fill', knobX - self.width/2, knobY - self.width/2, self.width, self.width)
elseif self.knob == 'circle' then
love.graphics.circle('fill', knobX, knobY, self.width/2)
end
end
function slider:getValue()
return self.min + self.value * (self.max - self.min)
end

View File

@@ -6,7 +6,7 @@ bgm = {
} }
local current_bgm = nil local current_bgm = nil
local bgm_locked = true local bgm_locked = false
function switchBGM(sound, subsound) function switchBGM(sound, subsound)
if bgm_locked then return end if bgm_locked then return end
@@ -47,7 +47,7 @@ function fadeoutBGM(time)
end end
function resetBGMFadeout(time) function resetBGMFadeout(time)
current_bgm:setVolume(1) current_bgm:setVolume(config.bgm_volume)
fading_bgm = false fading_bgm = false
current_bgm:play() current_bgm:play()
end end
@@ -59,7 +59,7 @@ function processBGMFadeout(dt)
fadeout_time = 0 fadeout_time = 0
fading_bgm = false fading_bgm = false
end end
current_bgm:setVolume(fadeout_time / total_fadeout_time) current_bgm:setVolume(fadeout_time * config.bgm_volume / total_fadeout_time)
end end
end end

View File

@@ -22,17 +22,19 @@ sounds = {
go = love.audio.newSource("res/se/go.wav", "static"), go = love.audio.newSource("res/se/go.wav", "static"),
irs = love.audio.newSource("res/se/irs.wav", "static"), irs = love.audio.newSource("res/se/irs.wav", "static"),
ihs = love.audio.newSource("res/se/ihs.wav", "static"), ihs = love.audio.newSource("res/se/ihs.wav", "static"),
-- a secret sound!
welcome = love.audio.newSource("res/se/welcomeToCambridge.wav", "static"),
} }
function playSE(sound, subsound) function playSE(sound, subsound)
if subsound == nil then if subsound == nil then
sounds[sound]:setVolume(0.5) sounds[sound]:setVolume(config.sfx_volume)
if sounds[sound]:isPlaying() then if sounds[sound]:isPlaying() then
sounds[sound]:stop() sounds[sound]:stop()
end end
sounds[sound]:play() sounds[sound]:play()
else else
sounds[sound][subsound]:setVolume(0.6) sounds[sound][subsound]:setVolume(config.sfx_volume)
if sounds[sound][subsound]:isPlaying() then if sounds[sound][subsound]:isPlaying() then
sounds[sound][subsound]:stop() sounds[sound][subsound]:stop()
end end
@@ -42,13 +44,13 @@ end
function playSEOnce(sound, subsound) function playSEOnce(sound, subsound)
if subsound == nil then if subsound == nil then
sounds[sound]:setVolume(0.5) sounds[sound]:setVolume(config.sfx_volume)
if sounds[sound]:isPlaying() then if sounds[sound]:isPlaying() then
return return
end end
sounds[sound]:play() sounds[sound]:play()
else else
sounds[sound][subsound]:setVolume(0.5) sounds[sound][subsound]:setVolume(config.sfx_volume)
if sounds[sound][subsound]:isPlaying() then if sounds[sound][subsound]:isPlaying() then
return return
end end

View File

@@ -9,12 +9,20 @@ function love.load()
require "load.save" require "load.save"
loadSave() loadSave()
require "scene" require "scene"
config["side_next"] = false --config["side_next"] = false
config["reverse_rotate"] = true --config["reverse_rotate"] = true
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});
if not config.das then config.das = 10 end
if not config.arr then config.arr = 2 end
if not config.sfx_volume then config.sfx_volume = 0.5 end
if not config.bgm_volume then config.bgm_volume = 0.5 end
if config.secret == nil then config.secret = false
elseif config.secret == true then playSE("welcome") end
if not config.gamesettings then if not config.gamesettings then
config.gamesettings = {} config.gamesettings = {}
config["das_last_key"] = false config["das_last_key"] = false
@@ -121,6 +129,13 @@ function love.keypressed(key, scancode)
love.window.setFullscreen(config["fullscreen"]) love.window.setFullscreen(config["fullscreen"])
elseif scancode == "f2" and scene.title ~= "Input Config" and scene.title ~= "Game" then elseif scancode == "f2" and scene.title ~= "Input Config" and scene.title ~= "Game" then
scene = InputConfigScene() scene = InputConfigScene()
-- secret sound playing :eyes:
elseif scancode == "f8" and scene.title == "Title" then
config.secret = not config.secret
saveConfig()
scene.restart_message = true
if config.secret then playSE("mode_decide")
else playSE("erase") end
-- 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

Binary file not shown.

View File

@@ -13,4 +13,7 @@ GameScene = require "scene.game"
ModeSelectScene = require "scene.mode_select" ModeSelectScene = require "scene.mode_select"
InputConfigScene = require "scene.input_config" InputConfigScene = require "scene.input_config"
GameConfigScene = require "scene.game_config" GameConfigScene = require "scene.game_config"
TuningScene = require "scene.tuning"
SettingsScene = require "scene.settings"
CreditsScene = require "scene.credits"
TitleScene = require "scene.title" TitleScene = require "scene.title"

57
scene/credits.lua Normal file
View File

@@ -0,0 +1,57 @@
local CreditsScene = Scene:extend()
CreditsScene.title = "Credits"
function CreditsScene:new()
self.frames = 0
end
function CreditsScene:update()
self.frames = self.frames + 1
if self.frames >= 2200 then
playSE("mode_decide")
scene = TitleScene()
end
end
function CreditsScene:render()
love.graphics.setColor(1, 1, 1, 1)
love.graphics.draw(
backgrounds[19],
0, 0, 0,
0.5, 0.5
)
love.graphics.setFont(font_3x5_4)
love.graphics.print("Cambridge Credits", 320, 500 - self.frames)
love.graphics.print("THANK YOU\nFOR PLAYING!", 320, math.max(1500 - self.frames, 240))
love.graphics.setFont(font_3x5_3)
love.graphics.print("Game Developers", 320, 550 - self.frames)
love.graphics.print("Project Heads", 320, 640 - self.frames)
love.graphics.print("Other Game Developers", 320, 730 - self.frames)
love.graphics.print("Special Thanks", 320, 900 - self.frames)
love.graphics.print("- SashLilac / SpinTriple", 320, math.max(2000 - self.frames, 320))
love.graphics.setFont(font_3x5_2)
love.graphics.print("Oshisaure\nJoe Zeng", 320, 590 - self.frames)
love.graphics.print("Mizu\nHailey", 320, 680 - self.frames)
love.graphics.print("Axel Fox - Multimino\nMine - Tetra Online\nDr Ocelot - Tetra Legends\nFelicity / nightmareci - Shiromino\n2Tie - TGMsim\nPhoenix Flare - Master of Blocks", 320, 770 - self.frames)
love.graphics.print(
"RocketLanterns\nCylinderKnot\nHammrTime\nKirby703\nMattMayuga\nMyPasswordIsWeak\n" ..
"Nikki Karissa\noffwo\nsinefuse\nTetro48\nTimmSkiller\nuser74003\nAgentBasey\n" ..
"CheeZed_Fish\neightsixfivezero\nEricICX\ngizmo4487\nM1ssing0\nMarkGamed7794\n" ..
"pokemonfan1937\nSimon\nstratus\nZaptorZap\nThe Absolute PLUS Discord\nTetra Legends Discord\n" ..
"Tetra Online Discord\nMultimino Discord\nCambridge Discord\nAnd to you, the player!",
320, 940 - self.frames
)
end
function CreditsScene:onInputPress(e)
if e.input == "menu_decide" or e.scancode == "return" or
e.input == "menu_back" or e.scancode == "delete" or e.scancode == "backspace" then
scene = TitleScene()
end
end
return CreditsScene

View File

@@ -22,6 +22,7 @@ function GameScene:new(game_mode, ruleset)
rotate_180=false, rotate_180=false,
hold=false, hold=false,
} }
self.paused = false
DiscordRPC:update({ DiscordRPC:update({
details = self.game.rpc_details, details = self.game.rpc_details,
state = self.game.name, state = self.game.name,
@@ -29,7 +30,7 @@ function GameScene:new(game_mode, ruleset)
end end
function GameScene:update() function GameScene:update()
if love.window.hasFocus() then if love.window.hasFocus() and not self.paused then
local inputs = {} local inputs = {}
for input, value in pairs(self.inputs) do for input, value in pairs(self.inputs) do
inputs[input] = value inputs[input] = value
@@ -72,6 +73,9 @@ function GameScene:render()
if config.gamesettings.display_gamemode == 1 then if config.gamesettings.display_gamemode == 1 then
love.graphics.printf(self.game.name .. " - " .. self.ruleset.name, 0, 460, 640, "left") love.graphics.printf(self.game.name .. " - " .. self.ruleset.name, 0, 460, 640, "left")
end end
love.graphics.setFont(font_3x5_3)
if self.paused then love.graphics.print("PAUSED!", 80, 100) end
end end
function GameScene:onInputPress(e) function GameScene:onInputPress(e)
@@ -82,6 +86,10 @@ function GameScene:onInputPress(e)
scene = e.input == "retry" and GameScene(self.retry_mode, self.retry_ruleset) or ModeSelectScene() scene = e.input == "retry" and GameScene(self.retry_mode, self.retry_ruleset) or ModeSelectScene()
elseif e.input == "retry" then elseif e.input == "retry" then
scene = GameScene(self.retry_mode, self.retry_ruleset) scene = GameScene(self.retry_mode, self.retry_ruleset)
elseif e.input == "pause" and not (self.game.game_over or self.game.completed) then
if not self.paused then pauseBGM()
else resumeBGM() end
self.paused = not self.paused
elseif e.input == "menu_back" then elseif e.input == "menu_back" then
scene = ModeSelectScene() scene = ModeSelectScene()
elseif e.input and string.sub(e.input, 1, 5) ~= "menu_" then elseif e.input and string.sub(e.input, 1, 5) ~= "menu_" then

View File

@@ -3,15 +3,16 @@ local ConfigScene = Scene:extend()
ConfigScene.title = "Game Settings" ConfigScene.title = "Game Settings"
require 'load.save' require 'load.save'
require 'libs.simple-slider'
ConfigScene.options = { ConfigScene.options = {
-- this serves as reference to what the options' values mean i guess? -- this serves as reference to what the options' values mean i guess?
{"manlock", "Manual locking",{"Per ruleset","Per gamemode","Harddrop", "Softdrop"}}, {"manlock", "Manual Locking",{"Per ruleset","Per gamemode","Harddrop", "Softdrop"}},
{"piece_colour", "Piece Colours", {"Per ruleset","Arika" ,"TTC"}}, {"piece_colour", "Piece Colours", {"Per ruleset","Arika" ,"TTC"}},
{"world_reverse","A Button Rotation", {"Left" ,"Auto" ,"Right"}}, {"world_reverse","A Button Rotation", {"Left" ,"Auto" ,"Right"}},
{"display_gamemode", "Display Gamemode", {"On", "Off"}}, {"display_gamemode", "Display Gamemode", {"On", "Off"}},
{"next_se", "Next Piece SFX", {"On", "Off"}},
{"das_last_key", "DAS Switch", {"Default", "Instant"}}, {"das_last_key", "DAS Switch", {"Default", "Instant"}},
{"smooth_movement", "Smooth Piece Drop", {"On", "Off"}},
{"synchroes_allowed", "Synchroes", {"Per ruleset", "On", "Off"}}, {"synchroes_allowed", "Synchroes", {"Per ruleset", "On", "Off"}},
{"diagonal_input", "Diagonal Input", {"On", "Off"}} {"diagonal_input", "Diagonal Input", {"On", "Off"}}
} }
@@ -26,10 +27,15 @@ function ConfigScene:new()
details = "In menus", details = "In menus",
state = "Changing game settings", state = "Changing game settings",
}) })
self.sfxSlider = newSlider(165, 375, 225, config.sfx_volume * 100, 0, 100, function(v) config.sfx_volume = v / 100 end, {width=20})
self.bgmSlider = newSlider(465, 375, 225, config.bgm_volume * 100, 0, 100, function(v) config.bgm_volume = v / 100 end, {width=20})
end end
function ConfigScene:update() function ConfigScene:update()
config["das_last_key"] = config.gamesettings.das_last_key == 2 config["das_last_key"] = config.gamesettings.das_last_key == 2
self.sfxSlider:update()
self.bgmSlider:update()
end end
function ConfigScene:render() function ConfigScene:render()
@@ -40,6 +46,10 @@ function ConfigScene:render()
0.5, 0.5 0.5, 0.5
) )
love.graphics.setFont(font_3x5_3)
love.graphics.print("SFX Volume: " .. math.floor(self.sfxSlider:getValue()) .. "%", 75, 325)
love.graphics.print("BGM Volume: " .. math.floor(self.bgmSlider:getValue()) .. "%", 375, 325)
love.graphics.setFont(font_3x5_4) love.graphics.setFont(font_3x5_4)
love.graphics.print("GAME SETTINGS", 80, 40) love.graphics.print("GAME SETTINGS", 80, 40)
@@ -55,13 +65,17 @@ function ConfigScene:render()
love.graphics.printf(setting, 100 + 110 * j, 100 + i * 20, 100, "center") love.graphics.printf(setting, 100 + 110 * j, 100 + i * 20, 100, "center")
end end
end end
love.graphics.setColor(1, 1, 1, 0.75)
self.sfxSlider:draw()
self.bgmSlider:draw()
end end
function ConfigScene:onInputPress(e) function ConfigScene:onInputPress(e)
if e.input == "menu_decide" or e.scancode == "return" then if e.input == "menu_decide" or e.scancode == "return" then
playSE("mode_decide") playSE("mode_decide")
saveConfig() saveConfig()
scene = TitleScene() scene = SettingsScene()
elseif e.input == "up" or e.scancode == "up" then elseif e.input == "up" or e.scancode == "up" then
playSE("cursor") playSE("cursor")
self.highlight = Mod1(self.highlight-1, optioncount) self.highlight = Mod1(self.highlight-1, optioncount)
@@ -78,7 +92,7 @@ function ConfigScene:onInputPress(e)
config.gamesettings[option[1]] = Mod1(config.gamesettings[option[1]]+1, #option[3]) config.gamesettings[option[1]] = Mod1(config.gamesettings[option[1]]+1, #option[3])
elseif e.input == "menu_back" or e.scancode == "delete" or e.scancode == "backspace" then elseif e.input == "menu_back" or e.scancode == "delete" or e.scancode == "backspace" then
loadSave() loadSave()
scene = TitleScene() scene = SettingsScene()
end end
end end

View File

@@ -18,6 +18,7 @@ local configurable_inputs = {
"rotate_180", "rotate_180",
"hold", "hold",
"retry", "retry",
"pause",
} }
local function newSetInputs() local function newSetInputs()
@@ -82,7 +83,7 @@ function ConfigScene:onInputPress(e)
-- function keys, escape, and tab are reserved and can't be remapped -- function keys, escape, and tab are reserved and can't be remapped
if e.scancode == "escape" and config.input then if e.scancode == "escape" and config.input then
-- cancel only if there was an input config already -- cancel only if there was an input config already
scene = TitleScene() scene = SettingsScene()
elseif self.input_state > table.getn(configurable_inputs) then elseif self.input_state > table.getn(configurable_inputs) then
if e.scancode == "return" then if e.scancode == "return" then
-- save new input, then load next scene -- save new input, then load next scene

View File

@@ -18,6 +18,7 @@ function ModeSelectScene:new()
end end
function ModeSelectScene:update() function ModeSelectScene:update()
switchBGM(nil) -- experimental
end end
function ModeSelectScene:render() function ModeSelectScene:render()

65
scene/settings.lua Normal file
View File

@@ -0,0 +1,65 @@
local SettingsScene = Scene:extend()
SettingsScene.title = "Settings"
local menu_screens = {
InputConfigScene,
GameConfigScene,
TuningScene
}
function SettingsScene:new()
self.menu_state = 1
DiscordRPC:update({
details = "In menus",
state = "Changing settings",
})
end
function SettingsScene:update() end
function SettingsScene:render()
love.graphics.setColor(1, 1, 1, 1)
love.graphics.draw(
backgrounds["game_config"],
0, 0, 0,
0.5, 0.5
)
love.graphics.setFont(font_3x5_4)
love.graphics.print("SETTINGS", 80, 40)
love.graphics.setFont(font_3x5_2)
love.graphics.print("Here, you can change some settings that change\nthe look and feel of the game.", 80, 90)
love.graphics.setColor(1, 1, 1, 0.5)
love.graphics.rectangle("fill", 75, 118 + 50 * self.menu_state, 200, 33)
love.graphics.setFont(font_3x5_3)
love.graphics.setColor(1, 1, 1, 1)
for i, screen in pairs(menu_screens) do
love.graphics.printf(screen.title, 80, 120 + 50 * i, 200, "left")
end
end
function SettingsScene:changeOption(rel)
local len = table.getn(menu_screens)
self.menu_state = (self.menu_state + len + rel - 1) % len + 1
end
function SettingsScene:onInputPress(e)
if e.input == "menu_decide" or e.scancode == "return" then
playSE("main_decide")
scene = menu_screens[self.menu_state]()
elseif e.input == "up" or e.scancode == "up" then
self:changeOption(-1)
playSE("cursor")
elseif e.input == "down" or e.scancode == "down" then
self:changeOption(1)
playSE("cursor")
elseif e.input == "menu_back" or e.scancode == "backspace" or e.scancode == "delete" then
scene = TitleScene()
end
end
return SettingsScene

View File

@@ -1,9 +1,12 @@
local TitleScene = Scene:extend() local TitleScene = Scene:extend()
TitleScene.title = "Title"
TitleScene.restart_message = false
local main_menu_screens = { local main_menu_screens = {
ModeSelectScene, ModeSelectScene,
InputConfigScene, SettingsScene,
GameConfigScene, CreditsScene,
ExitScene, ExitScene,
} }
@@ -42,6 +45,8 @@ function TitleScene:render()
0.5, 0.5 0.5, 0.5
) )
love.graphics.print(self.restart_message and "Restart Cambridge..." or "", 0, 0)
love.graphics.setColor(1, 1, 1, 0.5) love.graphics.setColor(1, 1, 1, 0.5)
love.graphics.rectangle("fill", 20, 278 + 20 * self.main_menu_state, 160, 22) love.graphics.rectangle("fill", 20, 278 + 20 * self.main_menu_state, 160, 22)

57
scene/tuning.lua Normal file
View File

@@ -0,0 +1,57 @@
local TuningScene = Scene:extend()
TuningScene.title = "Tuning Settings"
require 'load.save'
require 'libs.simple-slider'
function TuningScene:new()
DiscordRPC:update({
details = "In menus",
state = "Changing tuning settings",
})
self.dasSlider = newSlider(290, 225, 400, config.das, 0, 20, function(v) config.das = math.floor(v) end, {width=20})
self.arrSlider = newSlider(290, 325, 400, config.arr, 0, 6, function(v) config.arr = math.floor(v) end, {width=20})
end
function TuningScene:update()
self.dasSlider:update()
self.arrSlider:update()
end
function TuningScene:render()
love.graphics.setColor(1, 1, 1, 1)
love.graphics.draw(
backgrounds["game_config"],
0, 0, 0,
0.5, 0.5
)
love.graphics.setFont(font_3x5_4)
love.graphics.print("TUNING SETTINGS", 80, 40)
love.graphics.setFont(font_3x5_2)
love.graphics.print("These settings will only apply to modes\nthat do not use their own tunings.", 80, 90)
love.graphics.setFont(font_3x5_3)
love.graphics.print("Delayed Auto-Shift (DAS): " .. math.floor(self.dasSlider:getValue()) .. "F", 80, 175)
love.graphics.print("Auto-Repeat Rate (ARR): " .. math.floor(self.arrSlider:getValue()) .. "F", 80, 275)
love.graphics.setColor(1, 1, 1, 0.75)
self.dasSlider:draw()
self.arrSlider:draw()
end
function TuningScene:onInputPress(e)
if e.input == "menu_decide" or e.scancode == "return" then
playSE("mode_decide")
saveConfig()
scene = SettingsScene()
elseif e.input == "menu_back" or e.scancode == "delete" or e.scancode == "backspace" then
loadSave()
scene = SettingsScene()
end
end
return TuningScene

View File

@@ -143,9 +143,10 @@ function Piece:draw(opacity, brightness, grid, partial_das)
love.graphics.setColor(brightness, brightness, brightness, opacity) love.graphics.setColor(brightness, brightness, brightness, opacity)
local offsets = self:getBlockOffsets() local offsets = self:getBlockOffsets()
local gravity_offset = 0 local gravity_offset = 0
--if grid ~= nil and not self:isDropBlocked(grid) then if config.gamesettings.smooth_movement == 1 and
-- gravity_offset = self.gravity * 16 grid ~= nil and not self:isDropBlocked(grid) then
--end gravity_offset = self.gravity * 16
end
if partial_das == nil then partial_das = 0 end if partial_das == nil then partial_das = 0 end
for index, offset in pairs(offsets) do for index, offset in pairs(offsets) do
local x = self.position.x + offset.x local x = self.position.x + offset.x

View File

@@ -425,7 +425,7 @@ function GameMode:initializeNextPiece(inputs, ruleset, piece_data, generate_next
table.remove(self.next_queue, 1) table.remove(self.next_queue, 1)
table.insert(self.next_queue, self:getNextPiece(ruleset)) table.insert(self.next_queue, self:getNextPiece(ruleset))
end end
if config.gamesettings.next_se == 1 then self:playNextSound() end self:playNextSound()
end end
function GameMode:playNextSound() function GameMode:playNextSound()

View File

@@ -49,6 +49,7 @@ function ARS:onPieceMove(piece, grid)
if piece:isDropBlocked(grid) then if piece:isDropBlocked(grid) then
piece.manipulations = piece.manipulations + 1 piece.manipulations = piece.manipulations + 1
if piece.manipulations >= 128 then if piece.manipulations >= 128 then
piece:dropToBottom(grid)
piece.locked = true piece.locked = true
end end
end end
@@ -59,6 +60,7 @@ function ARS:onPieceRotate(piece, grid)
if piece:isDropBlocked(grid) then if piece:isDropBlocked(grid) then
piece.manipulations = piece.manipulations + 1 piece.manipulations = piece.manipulations + 1
if piece.manipulations >= 128 then if piece.manipulations >= 128 then
piece:dropToBottom(grid)
piece.locked = true piece.locked = true
end end
end end

View File

@@ -36,6 +36,7 @@ function ARS:onPieceMove(piece, grid)
if piece:isDropBlocked(grid) then if piece:isDropBlocked(grid) then
piece.manipulations = piece.manipulations + 1 piece.manipulations = piece.manipulations + 1
if piece.manipulations >= 128 then if piece.manipulations >= 128 then
piece:dropToBottom(grid)
piece.locked = true piece.locked = true
end end
end end
@@ -46,6 +47,7 @@ function ARS:onPieceRotate(piece, grid)
if piece:isDropBlocked(grid) then if piece:isDropBlocked(grid) then
piece.manipulations = piece.manipulations + 1 piece.manipulations = piece.manipulations + 1
if piece.manipulations >= 128 then if piece.manipulations >= 128 then
piece:dropToBottom(grid)
piece.locked = true piece.locked = true
end end
end end

View File

@@ -31,6 +31,7 @@ function SRS:onPieceMove(piece, grid)
if piece:isDropBlocked(grid) then if piece:isDropBlocked(grid) then
piece.manipulations = piece.manipulations + 1 piece.manipulations = piece.manipulations + 1
if piece.manipulations >= 128 then if piece.manipulations >= 128 then
piece:dropToBottom(grid)
piece.locked = true piece.locked = true
end end
end end
@@ -41,6 +42,7 @@ function SRS:onPieceRotate(piece, grid)
if piece:isDropBlocked(grid) then if piece:isDropBlocked(grid) then
piece.manipulations = piece.manipulations + 1 piece.manipulations = piece.manipulations + 1
if piece.manipulations >= 128 then if piece.manipulations >= 128 then
piece:dropToBottom(grid)
piece.locked = true piece.locked = true
end end
end end

View File

@@ -406,6 +406,7 @@ function CRS:onPieceMove(piece, grid)
if piece:isDropBlocked(grid) then if piece:isDropBlocked(grid) then
piece.move_counter = piece.move_counter + 1 piece.move_counter = piece.move_counter + 1
if piece.move_counter >= 24 then if piece.move_counter >= 24 then
piece:dropToBottom(grid)
piece.locked = true piece.locked = true
end end
end end
@@ -415,6 +416,7 @@ function CRS:onPieceRotate(piece, grid)
if piece:isDropBlocked(grid) then if piece:isDropBlocked(grid) then
piece.rotate_counter = piece.rotate_counter + 1 piece.rotate_counter = piece.rotate_counter + 1
if piece.rotate_counter >= 12 then if piece.rotate_counter >= 12 then
piece:dropToBottom(grid)
piece.locked = true piece.locked = true
end end
end end

View File

@@ -87,6 +87,7 @@ function SRS:onPieceMove(piece, grid)
if piece:isDropBlocked(grid) then if piece:isDropBlocked(grid) then
piece.manipulations = piece.manipulations + 1 piece.manipulations = piece.manipulations + 1
if piece.manipulations >= 15 then if piece.manipulations >= 15 then
piece:dropToBottom(grid)
piece.locked = true piece.locked = true
end end
end end
@@ -98,6 +99,7 @@ function SRS:onPieceRotate(piece, grid)
piece.manipulations = piece.manipulations + 1 piece.manipulations = piece.manipulations + 1
if piece:isDropBlocked(grid) then if piece:isDropBlocked(grid) then
if piece.manipulations >= 15 then if piece.manipulations >= 15 then
piece:dropToBottom(grid)
piece.locked = true piece.locked = true
end end
end end

View File

@@ -170,6 +170,7 @@ function SRS:onPieceMove(piece, grid)
if piece:isDropBlocked(grid) then if piece:isDropBlocked(grid) then
piece.manipulations = piece.manipulations + 1 piece.manipulations = piece.manipulations + 1
if piece.manipulations >= 10 then if piece.manipulations >= 10 then
piece:dropToBottom(grid)
piece.locked = true piece.locked = true
end end
end end
@@ -180,6 +181,7 @@ function SRS:onPieceRotate(piece, grid)
if piece:isDropBlocked(grid) then if piece:isDropBlocked(grid) then
piece.rotations = piece.rotations + 1 piece.rotations = piece.rotations + 1
if piece.rotations >= 8 then if piece.rotations >= 8 then
piece:dropToBottom(grid)
piece.locked = true piece.locked = true
end end
end end