2020-10-10 18:42:56 -05:00
|
|
|
function love.load()
|
2019-05-22 22:57:34 -05:00
|
|
|
math.randomseed(os.time())
|
|
|
|
highscores = {}
|
2020-10-10 20:17:48 -05:00
|
|
|
require "load.rpc"
|
2019-05-22 22:57:34 -05:00
|
|
|
require "load.graphics"
|
|
|
|
require "load.fonts"
|
|
|
|
require "load.sounds"
|
|
|
|
require "load.bgm"
|
|
|
|
require "load.save"
|
2021-01-24 13:55:35 -06:00
|
|
|
require "load.bigint"
|
2021-03-03 09:33:10 -06:00
|
|
|
require "load.version"
|
2019-05-22 22:57:34 -05:00
|
|
|
loadSave()
|
2021-08-15 22:50:00 -05:00
|
|
|
require "funcs"
|
2019-05-22 22:57:34 -05:00
|
|
|
require "scene"
|
2021-02-22 20:43:01 -06:00
|
|
|
|
2020-12-20 08:45:49 -06:00
|
|
|
--config["side_next"] = false
|
|
|
|
--config["reverse_rotate"] = true
|
2021-02-22 20:43:01 -06:00
|
|
|
--config["das_last_key"] = false
|
2021-03-11 07:33:05 -06:00
|
|
|
--config["fullscreen"] = false
|
2019-05-29 20:55:01 -05:00
|
|
|
|
|
|
|
love.window.setMode(love.graphics.getWidth(), love.graphics.getHeight(), {resizable = true});
|
2021-05-23 13:07:07 -05:00
|
|
|
|
2021-05-23 13:57:04 -05:00
|
|
|
-- used for screenshots
|
|
|
|
GLOBAL_CANVAS = love.graphics.newCanvas()
|
2019-05-29 20:55:01 -05:00
|
|
|
|
2021-01-24 13:55:35 -06:00
|
|
|
-- init config
|
2021-03-11 08:24:19 -06:00
|
|
|
initConfig()
|
2021-03-11 07:33:05 -06:00
|
|
|
|
2021-03-11 08:24:19 -06:00
|
|
|
love.window.setFullscreen(config["fullscreen"])
|
|
|
|
if config.secret then playSE("welcome") end
|
2020-12-18 20:25:09 -06:00
|
|
|
|
2021-03-11 08:24:19 -06:00
|
|
|
-- import custom modules
|
|
|
|
initModules()
|
|
|
|
end
|
2020-11-02 21:47:58 -06:00
|
|
|
|
2021-03-11 08:24:19 -06:00
|
|
|
function initModules()
|
2020-11-02 21:47:58 -06:00
|
|
|
game_modes = {}
|
|
|
|
mode_list = love.filesystem.getDirectoryItems("tetris/modes")
|
|
|
|
for i=1,#mode_list do
|
2021-08-15 22:50:00 -05:00
|
|
|
if(mode_list[i] ~= "gamemode.lua" and string.sub(mode_list[i], -4) == ".lua") then
|
2020-11-02 21:47:58 -06:00
|
|
|
game_modes[#game_modes+1] = require ("tetris.modes."..string.sub(mode_list[i],1,-5))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
rulesets = {}
|
|
|
|
rule_list = love.filesystem.getDirectoryItems("tetris/rulesets")
|
|
|
|
for i=1,#rule_list do
|
2021-08-15 22:50:00 -05:00
|
|
|
if(rule_list[i] ~= "ruleset.lua" and string.sub(rule_list[i], -4) == ".lua") then
|
2020-11-02 21:47:58 -06:00
|
|
|
rulesets[#rulesets+1] = require ("tetris.rulesets."..string.sub(rule_list[i],1,-5))
|
|
|
|
end
|
|
|
|
end
|
|
|
|
--sort mode/rule lists
|
|
|
|
local function padnum(d) return ("%03d%s"):format(#d, d) end
|
2020-11-08 15:19:01 -06:00
|
|
|
table.sort(game_modes, function(a,b)
|
|
|
|
return tostring(a.name):gsub("%d+",padnum) < tostring(b.name):gsub("%d+",padnum) end)
|
2020-11-02 21:47:58 -06:00
|
|
|
table.sort(rulesets, function(a,b)
|
2020-11-08 15:19:01 -06:00
|
|
|
return tostring(a.name):gsub("%d+",padnum) < tostring(b.name):gsub("%d+",padnum) end)
|
2019-05-22 22:57:34 -05:00
|
|
|
end
|
|
|
|
|
|
|
|
function love.draw()
|
2021-05-23 13:57:04 -05:00
|
|
|
love.graphics.setCanvas(GLOBAL_CANVAS)
|
|
|
|
love.graphics.clear()
|
|
|
|
|
|
|
|
love.graphics.push()
|
2020-10-09 17:43:22 -05:00
|
|
|
|
2019-05-29 20:55:01 -05:00
|
|
|
-- get offset matrix
|
|
|
|
love.graphics.setDefaultFilter("linear", "nearest")
|
|
|
|
local width = love.graphics.getWidth()
|
|
|
|
local height = love.graphics.getHeight()
|
|
|
|
local scale_factor = math.min(width / 640, height / 480)
|
|
|
|
love.graphics.translate(
|
|
|
|
(width - scale_factor * 640) / 2,
|
|
|
|
(height - scale_factor * 480) / 2
|
|
|
|
)
|
|
|
|
love.graphics.scale(scale_factor)
|
2021-05-23 13:07:07 -05:00
|
|
|
|
2019-05-22 22:57:34 -05:00
|
|
|
scene:render()
|
|
|
|
love.graphics.pop()
|
2021-05-23 13:07:07 -05:00
|
|
|
|
2021-05-23 13:57:04 -05:00
|
|
|
love.graphics.setCanvas()
|
|
|
|
love.graphics.setColor(1,1,1,1)
|
|
|
|
love.graphics.draw(GLOBAL_CANVAS)
|
2019-05-22 22:57:34 -05:00
|
|
|
end
|
|
|
|
|
2020-11-08 14:55:06 -06:00
|
|
|
function love.keypressed(key, scancode)
|
2019-05-22 22:57:34 -05:00
|
|
|
-- global hotkeys
|
2021-09-09 18:02:38 -05:00
|
|
|
if scancode == "f11" then
|
2019-05-22 22:57:34 -05:00
|
|
|
config["fullscreen"] = not config["fullscreen"]
|
2021-03-11 07:33:05 -06:00
|
|
|
saveConfig()
|
2019-05-22 22:57:34 -05:00
|
|
|
love.window.setFullscreen(config["fullscreen"])
|
2020-11-10 16:37:59 -06:00
|
|
|
elseif scancode == "f2" and scene.title ~= "Input Config" and scene.title ~= "Game" then
|
|
|
|
scene = InputConfigScene()
|
2020-12-21 15:00:03 -06:00
|
|
|
switchBGM(nil)
|
2020-12-19 19:31:14 -06:00
|
|
|
-- secret sound playing :eyes:
|
|
|
|
elseif scancode == "f8" and scene.title == "Title" then
|
|
|
|
config.secret = not config.secret
|
|
|
|
saveConfig()
|
2020-12-19 19:43:57 -06:00
|
|
|
scene.restart_message = true
|
2020-12-19 19:31:14 -06:00
|
|
|
if config.secret then playSE("mode_decide")
|
|
|
|
else playSE("erase") end
|
2021-05-23 13:07:07 -05:00
|
|
|
-- f12 is reserved for saving screenshots
|
|
|
|
elseif scancode == "f12" then
|
|
|
|
local ss_name = os.date("ss/%Y-%m-%d_%H-%M-%S.png")
|
2021-06-03 15:00:33 -05:00
|
|
|
local info = love.filesystem.getInfo("ss", "directory")
|
|
|
|
if not info then
|
2021-03-01 19:37:44 -06:00
|
|
|
love.filesystem.remove("ss")
|
|
|
|
love.filesystem.createDirectory("ss")
|
|
|
|
end
|
2021-05-23 13:57:04 -05:00
|
|
|
print("Saving screenshot as "..ss_name)
|
|
|
|
GLOBAL_CANVAS:newImageData():encode("png", ss_name)
|
2021-01-29 16:29:27 -06:00
|
|
|
-- function keys are reserved
|
|
|
|
elseif string.match(scancode, "^f[1-9]$") or string.match(scancode, "^f[1-9][0-9]+$") then
|
|
|
|
return
|
|
|
|
-- escape is reserved for menu_back
|
|
|
|
elseif scancode == "escape" then
|
|
|
|
scene:onInputPress({input="menu_back", type="key", key=key, scancode=scancode})
|
2020-11-10 16:37:59 -06:00
|
|
|
-- pass any other key to the scene, with its configured mapping
|
2019-05-22 22:57:34 -05:00
|
|
|
else
|
2020-11-08 15:19:01 -06:00
|
|
|
local input_pressed = nil
|
|
|
|
if config.input and config.input.keys then
|
|
|
|
input_pressed = config.input.keys[scancode]
|
|
|
|
end
|
2020-11-08 14:55:06 -06:00
|
|
|
scene:onInputPress({input=input_pressed, type="key", key=key, scancode=scancode})
|
2019-05-22 22:57:34 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2020-11-08 14:55:06 -06:00
|
|
|
function love.keyreleased(key, scancode)
|
2020-11-10 16:37:59 -06:00
|
|
|
-- escape is reserved for menu_back
|
|
|
|
if scancode == "escape" then
|
2020-11-08 15:19:01 -06:00
|
|
|
scene:onInputRelease({input="menu_back", type="key", key=key, scancode=scancode})
|
2020-11-10 16:37:59 -06:00
|
|
|
-- function keys are reserved
|
|
|
|
elseif string.match(scancode, "^f[1-9]$") or string.match(scancode, "^f[1-9][0-9]+$") then
|
|
|
|
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
|
2020-11-08 14:55:06 -06:00
|
|
|
else
|
2020-11-08 15:19:01 -06:00
|
|
|
local input_released = nil
|
|
|
|
if config.input and config.input.keys then
|
|
|
|
input_released = config.input.keys[scancode]
|
|
|
|
end
|
2020-11-08 14:55:06 -06:00
|
|
|
scene:onInputRelease({input=input_released, type="key", key=key, scancode=scancode})
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function love.joystickpressed(joystick, button)
|
2020-11-08 15:19:01 -06:00
|
|
|
local input_pressed = nil
|
|
|
|
if
|
|
|
|
config.input and
|
|
|
|
config.input.joysticks and
|
|
|
|
config.input.joysticks[joystick:getName()] and
|
|
|
|
config.input.joysticks[joystick:getName()].buttons
|
|
|
|
then
|
|
|
|
input_pressed = config.input.joysticks[joystick:getName()].buttons[button]
|
|
|
|
end
|
|
|
|
scene:onInputPress({input=input_pressed, type="joybutton", name=joystick:getName(), button=button})
|
2020-11-08 14:55:06 -06:00
|
|
|
end
|
|
|
|
|
|
|
|
function love.joystickreleased(joystick, button)
|
2020-11-08 15:19:01 -06:00
|
|
|
local input_released = nil
|
|
|
|
if
|
|
|
|
config.input and
|
|
|
|
config.input.joysticks and
|
|
|
|
config.input.joysticks[joystick:getName()] and
|
|
|
|
config.input.joysticks[joystick:getName()].buttons
|
|
|
|
then
|
|
|
|
input_released = config.input.joysticks[joystick:getName()].buttons[button]
|
|
|
|
end
|
|
|
|
scene:onInputRelease({input=input_released, type="joybutton", name=joystick:getName(), button=button})
|
2020-11-08 14:55:06 -06:00
|
|
|
end
|
|
|
|
|
|
|
|
function love.joystickaxis(joystick, axis, value)
|
2020-11-08 15:19:01 -06:00
|
|
|
local input_pressed = nil
|
|
|
|
local positive_released = nil
|
|
|
|
local negative_released = nil
|
|
|
|
if
|
|
|
|
config.input and
|
|
|
|
config.input.joysticks and
|
|
|
|
config.input.joysticks[joystick:getName()] and
|
|
|
|
config.input.joysticks[joystick:getName()].axes and
|
|
|
|
config.input.joysticks[joystick:getName()].axes[axis]
|
|
|
|
then
|
2021-02-24 15:58:42 -06:00
|
|
|
if math.abs(value) >= 1 then
|
2021-03-07 15:03:02 -06:00
|
|
|
input_pressed = config.input.joysticks[joystick:getName()].axes[axis][value >= 1 and "positive" or "negative"]
|
2020-11-08 15:19:01 -06:00
|
|
|
end
|
|
|
|
positive_released = config.input.joysticks[joystick:getName()].axes[axis].positive
|
|
|
|
negative_released = config.input.joysticks[joystick:getName()].axes[axis].negative
|
|
|
|
end
|
2021-02-24 15:58:42 -06:00
|
|
|
if math.abs(value) >= 1 then
|
2020-11-08 15:19:01 -06:00
|
|
|
scene:onInputPress({input=input_pressed, type="joyaxis", name=joystick:getName(), axis=axis, value=value})
|
|
|
|
else
|
|
|
|
scene:onInputRelease({input=positive_released, type="joyaxis", name=joystick:getName(), axis=axis, value=value})
|
|
|
|
scene:onInputRelease({input=negative_released, type="joyaxis", name=joystick:getName(), axis=axis, value=value})
|
|
|
|
end
|
2020-11-08 14:55:06 -06:00
|
|
|
end
|
|
|
|
|
2021-03-07 15:42:33 -06:00
|
|
|
local last_hat_direction = ""
|
2021-03-07 19:43:55 -06:00
|
|
|
local directions = {
|
|
|
|
["u"] = "up",
|
|
|
|
["d"] = "down",
|
|
|
|
["l"] = "left",
|
|
|
|
["r"] = "right",
|
|
|
|
}
|
2021-03-07 15:42:33 -06:00
|
|
|
|
2020-11-08 14:55:06 -06:00
|
|
|
function love.joystickhat(joystick, hat, direction)
|
2020-11-08 15:19:01 -06:00
|
|
|
local input_pressed = nil
|
|
|
|
local has_hat = false
|
|
|
|
if
|
|
|
|
config.input and
|
|
|
|
config.input.joysticks and
|
|
|
|
config.input.joysticks[joystick:getName()] and
|
|
|
|
config.input.joysticks[joystick:getName()].hats and
|
|
|
|
config.input.joysticks[joystick:getName()].hats[hat]
|
|
|
|
then
|
|
|
|
if direction ~= "c" then
|
|
|
|
input_pressed = config.input.joysticks[joystick:getName()].hats[hat][direction]
|
|
|
|
end
|
|
|
|
has_hat = true
|
|
|
|
end
|
|
|
|
if input_pressed then
|
2021-03-07 15:42:33 -06:00
|
|
|
for i = 1, #direction do
|
|
|
|
local char = direction:sub(i, i)
|
|
|
|
local _, count = last_hat_direction:gsub(char, char)
|
|
|
|
if count == 0 then
|
2021-03-07 19:43:55 -06:00
|
|
|
scene:onInputPress({input=config.input.joysticks[joystick:getName()].hats[hat][char], type="joyhat", name=joystick:getName(), hat=hat, direction=char})
|
|
|
|
end
|
|
|
|
end
|
|
|
|
for i = 1, #last_hat_direction do
|
|
|
|
local char = last_hat_direction:sub(i, i)
|
|
|
|
local _, count = direction:gsub(char, char)
|
|
|
|
if count == 0 then
|
|
|
|
scene:onInputRelease({input=config.input.joysticks[joystick:getName()].hats[hat][char], type="joyhat", name=joystick:getName(), hat=hat, direction=char})
|
2021-03-07 15:42:33 -06:00
|
|
|
end
|
|
|
|
end
|
|
|
|
last_hat_direction = direction
|
2020-11-08 15:19:01 -06:00
|
|
|
elseif has_hat then
|
|
|
|
for i, direction in ipairs{"d", "l", "ld", "lu", "r", "rd", "ru", "u"} do
|
|
|
|
scene:onInputRelease({input=config.input.joysticks[joystick:getName()].hats[hat][direction], type="joyhat", name=joystick:getName(), hat=hat, direction=direction})
|
|
|
|
end
|
2021-03-07 19:43:55 -06:00
|
|
|
last_hat_direction = ""
|
2020-11-08 15:19:01 -06:00
|
|
|
elseif direction ~= "c" then
|
2021-03-07 15:42:33 -06:00
|
|
|
for i = 1, #direction do
|
|
|
|
local char = direction:sub(i, i)
|
|
|
|
local _, count = last_hat_direction:gsub(char, char)
|
|
|
|
if count == 0 then
|
2021-03-07 19:43:55 -06:00
|
|
|
scene:onInputPress({input=directions[char], type="joyhat", name=joystick:getName(), hat=hat, direction=char})
|
|
|
|
end
|
|
|
|
end
|
|
|
|
for i = 1, #last_hat_direction do
|
|
|
|
local char = last_hat_direction:sub(i, i)
|
|
|
|
local _, count = direction:gsub(char, char)
|
|
|
|
if count == 0 then
|
|
|
|
scene:onInputRelease({input=directions[char], type="joyhat", name=joystick:getName(), hat=hat, direction=char})
|
2021-03-07 15:42:33 -06:00
|
|
|
end
|
|
|
|
end
|
|
|
|
last_hat_direction = direction
|
2020-11-08 15:19:01 -06:00
|
|
|
else
|
|
|
|
for i, direction in ipairs{"d", "l", "ld", "lu", "r", "rd", "ru", "u"} do
|
|
|
|
scene:onInputRelease({input=nil, type="joyhat", name=joystick:getName(), hat=hat, direction=direction})
|
|
|
|
end
|
2021-03-07 19:43:55 -06:00
|
|
|
last_hat_direction = ""
|
2020-11-08 15:19:01 -06:00
|
|
|
end
|
2020-11-08 14:55:06 -06:00
|
|
|
end
|
|
|
|
|
2021-09-20 22:33:27 -05:00
|
|
|
function love.wheelmoved(x, y)
|
|
|
|
scene:onInputPress({input=nil, type="wheel", x=x, y=y})
|
|
|
|
end
|
|
|
|
|
2019-05-22 22:57:34 -05:00
|
|
|
function love.focus(f)
|
2021-09-20 22:33:27 -05:00
|
|
|
if f then
|
|
|
|
resumeBGM(true)
|
2019-05-22 22:57:34 -05:00
|
|
|
else
|
2021-09-20 22:33:27 -05:00
|
|
|
pauseBGM(true)
|
2019-05-22 22:57:34 -05:00
|
|
|
end
|
|
|
|
end
|
2021-01-28 22:13:17 -06:00
|
|
|
|
|
|
|
function love.resize(w, h)
|
2021-05-23 13:07:07 -05:00
|
|
|
GLOBAL_CANVAS:release()
|
|
|
|
GLOBAL_CANVAS = love.graphics.newCanvas(w, h)
|
|
|
|
end
|
|
|
|
|
|
|
|
local TARGET_FPS = 60
|
|
|
|
|
|
|
|
function love.run()
|
|
|
|
if love.load then love.load(love.arg.parseGameArguments(arg), arg) end
|
|
|
|
|
|
|
|
if love.timer then love.timer.step() end
|
|
|
|
|
|
|
|
local dt = 0
|
|
|
|
|
|
|
|
local last_time = love.timer.getTime()
|
|
|
|
local time_accumulator = 0
|
|
|
|
return function()
|
|
|
|
if love.event then
|
|
|
|
love.event.pump()
|
|
|
|
for name, a,b,c,d,e,f in love.event.poll() do
|
|
|
|
if name == "quit" then
|
|
|
|
if not love.quit or not love.quit() then
|
|
|
|
return a or 0
|
|
|
|
end
|
|
|
|
end
|
|
|
|
love.handlers[name](a,b,c,d,e,f)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
if love.timer then
|
2021-05-23 13:57:04 -05:00
|
|
|
processBGMFadeout(love.timer.step())
|
|
|
|
end
|
|
|
|
|
2021-05-23 13:07:07 -05:00
|
|
|
if scene and scene.update and love.timer then
|
2021-05-23 13:57:04 -05:00
|
|
|
scene:update()
|
|
|
|
|
|
|
|
local frame_duration = 1.0 / TARGET_FPS
|
|
|
|
if time_accumulator < frame_duration then
|
|
|
|
if love.graphics and love.graphics.isActive() and love.draw then
|
|
|
|
love.graphics.origin()
|
|
|
|
love.graphics.clear(love.graphics.getBackgroundColor())
|
|
|
|
love.draw()
|
|
|
|
love.graphics.present()
|
|
|
|
end
|
|
|
|
local end_time = last_time + frame_duration
|
|
|
|
local time = love.timer.getTime()
|
|
|
|
while time < end_time do
|
|
|
|
love.timer.sleep(0.001)
|
|
|
|
time = love.timer.getTime()
|
|
|
|
end
|
|
|
|
time_accumulator = time_accumulator + time - last_time
|
|
|
|
end
|
|
|
|
time_accumulator = time_accumulator - frame_duration
|
|
|
|
end
|
|
|
|
last_time = love.timer.getTime()
|
2021-05-23 13:07:07 -05:00
|
|
|
end
|
2021-05-23 13:57:04 -05:00
|
|
|
end
|