commit
e24737a3b8
|
@ -2,3 +2,5 @@
|
||||||
*.love
|
*.love
|
||||||
dist/*.zip
|
dist/*.zip
|
||||||
dist/**/cambridge.exe
|
dist/**/cambridge.exe
|
||||||
|
dist/**/libs
|
||||||
|
dist/**/*.md
|
56
README.md
56
README.md
|
@ -5,48 +5,55 @@ Cambridge
|
||||||
|
|
||||||
Welcome to Cambridge, the next open-source falling-block game engine!
|
Welcome to Cambridge, the next open-source falling-block game engine!
|
||||||
|
|
||||||
This fork is written and maintained exclusively by [SashLilac](https://github.com/SashLilac) and [Oshisaure](https://github.com/oshisaure)!
|
This fork is written and maintained exclusively by [SashLilac](https://github.com/SashLilac), [joezeng](https://github.com/joezeng) and [Oshisaure](https://github.com/oshisaure)!
|
||||||
|
|
||||||
Join our Discord server for help and a welcoming community! https://discord.gg/mteMJw4
|
Join our Discord server for help and a welcoming community! https://discord.gg/mteMJw4
|
||||||
|
|
||||||
Credits
|
Credits
|
||||||
-------
|
-------
|
||||||
|
|
||||||
- [Lilla Oshisaure](https://www.youtube.com/user/LeSpyroshisaure) for their amazing contributions to my life in general!
|
- [Lilla Oshisaure](https://www.youtube.com/user/LeSpyroshisaure) for being my co-dev!
|
||||||
|
- [joezeng](https://github.com/joezeng) for the original project, and for offering to help with the expansion!
|
||||||
- [The Tetra Legends Discord](http://discord.com/invite/7hMx5r2) for supporting me and playtesting!
|
- [The Tetra Legends Discord](http://discord.com/invite/7hMx5r2) for supporting me and playtesting!
|
||||||
- [joezeng](https://github.com/joezeng) for the original project.
|
- [The Absolute Plus](https://discord.gg/6Gf2awJ) for being another source of motivation!
|
||||||
- [Hailey](https://github.com/haileylgbt) for some miscellaneous assets.
|
|
||||||
- CylinderKnot for an amazing gamemode.
|
The following people in no particular order also helped with the project:
|
||||||
- MarkGamed7794 for some miscellaneous contributions.
|
- [Hailey](https://github.com/haileylgbt)
|
||||||
- Mizu for the Cambridge logo and the [Cambridge launcher](https://github.com/rexxt/cambridge-launcher).
|
- CylinderKnot
|
||||||
- MattMayuga for the Cambridge banner.
|
- MarkGamed7794
|
||||||
|
- [Mizu](https://github.com/rexxt)
|
||||||
|
- MattMayuga
|
||||||
|
- Kitaru
|
||||||
|
- switchpalacecorner
|
||||||
|
- [sinefuse](https://github.com/sinefuse)
|
||||||
|
- [2Tie](https://github.com/2Tie)
|
||||||
|
- [nightmareci](https://github.com/nightmareci)
|
||||||
|
- [MyPasswordIsWeak](https://github.com/MyPasswordIsWeak)
|
||||||
|
|
||||||
![Cambridge Logo](https://cdn.discordapp.com/attachments/625496179433668635/763363717730664458/Icon_2.png)
|
![Cambridge Logo](https://cdn.discordapp.com/attachments/625496179433668635/763363717730664458/Icon_2.png)
|
||||||
|
|
||||||
Installation instructions
|
Playing the game
|
||||||
-------------------------
|
----------------
|
||||||
|
|
||||||
Pre-built releases are available on the releases page.
|
|
||||||
|
|
||||||
### Windows
|
### Windows
|
||||||
|
|
||||||
Unzip the exe file and run it directly. All assets are currently bundled inside the executable.
|
You do not need LÖVE on Windows, as it comes bundled with the program.
|
||||||
|
|
||||||
### macOS
|
To get the stable release, simply download the ZIP in the latest release. All assets needed are bundled with the executable.
|
||||||
|
|
||||||
For the time being, the file `cambridge.love` only works on the command line. Install `love` with [Homebrew](https://brew.sh), and run:
|
If you want the bleeding edge version, or want mod pack support, download [this](https://github.com/SashLilac/cambridge/archive/master.zip).
|
||||||
|
|
||||||
$ love cambridge.love
|
Extract the ZIP, open a Command Prompt at the folder you extracted Cambridge to, then run this command:
|
||||||
|
|
||||||
### Linux
|
dist\windows\love.exe .
|
||||||
|
|
||||||
Same as macOS, except install `love` with your favourite package manager.
|
Alternatively, if you're on a 32-bit system, run this instead:
|
||||||
|
|
||||||
|
dist\win32\love.exe .
|
||||||
|
|
||||||
Running from source
|
32-bit systems do not support rich presence integration.
|
||||||
-------------------
|
|
||||||
|
|
||||||
If you want the bleeding-edge release, you can also clone the code straight from this repository.
|
Then, check the mod pack section at the bottom of this page.
|
||||||
|
|
||||||
### macOS, Linux
|
### macOS, Linux
|
||||||
|
|
||||||
|
@ -56,12 +63,19 @@ Clone the repository in git:
|
||||||
|
|
||||||
git clone https://github.com/SashLilac/cambridge
|
git clone https://github.com/SashLilac/cambridge
|
||||||
|
|
||||||
|
Alternatively, download the source code ZIP in the latest release.
|
||||||
|
|
||||||
Then, navigate to the root directory that you just cloned, and type:
|
Then, navigate to the root directory that you just cloned, and type:
|
||||||
|
|
||||||
love .
|
love .
|
||||||
|
|
||||||
It should run automatically!
|
It should run automatically!
|
||||||
|
|
||||||
|
## Installing modpacks
|
||||||
|
|
||||||
|
Simply drag your mode, ruleset, and randomizer Lua files into their respective directory, and they should appear automatically.
|
||||||
|
|
||||||
|
Alternatively, install [this](https://github.com/SashLilac/cambridge/releases/download/v0.2.1/modpackv1.zip) mod pack to get a taste of the mod potential.
|
||||||
|
|
||||||
License
|
License
|
||||||
-------
|
-------
|
||||||
|
|
|
@ -0,0 +1,11 @@
|
||||||
|
@del cambridge.love
|
||||||
|
@del dist\windows\cambridge.exe
|
||||||
|
@del dist\windows\SOURCES.md
|
||||||
|
@del dist\windows\LICENSE.md
|
||||||
|
@rmdir /Q /S dist\windows\libs
|
||||||
|
@del dist\win32\cambridge.exe
|
||||||
|
@del dist\win32\SOURCES.md
|
||||||
|
@del dist\win32\LICENSE.md
|
||||||
|
@rmdir /Q /S dist\win32\libs
|
||||||
|
@del dist\cambridge-windows.zip
|
||||||
|
@del dist\cambridge-win32.zip
|
|
@ -5,12 +5,26 @@ local ffi = require "ffi"
|
||||||
local osname = love.system.getOS()
|
local osname = love.system.getOS()
|
||||||
local discordRPClib = nil
|
local discordRPClib = nil
|
||||||
|
|
||||||
|
-- FFI requires the libraries really be files just sitting in the filesystem. It
|
||||||
|
-- can't load libraries from a .love archive, nor a fused executable on Windows.
|
||||||
|
-- Merely using love.filesystem.getSource() only works when running LOVE with
|
||||||
|
-- the game unarchived from command line, like "love .".
|
||||||
|
--
|
||||||
|
-- The code here setting "source" will set the directory where the game was run
|
||||||
|
-- from, so FFI can load discordRPC. We assume that the discordRPC library's
|
||||||
|
-- libs directory is in the same directory as the .love archive; if it's
|
||||||
|
-- missing, it just won't load.
|
||||||
|
local source = love.filesystem.getSource()
|
||||||
|
if string.sub(source, -5) == ".love" or love.filesystem.isFused() then
|
||||||
|
source = love.filesystem.getSourceBaseDirectory()
|
||||||
|
end
|
||||||
|
|
||||||
if osname == "Linux" then
|
if osname == "Linux" then
|
||||||
discordRPClib = ffi.load(love.filesystem.getSource().."/libs/discord-rpc.so")
|
discordRPClib = ffi.load(source.."/libs/discord-rpc.so")
|
||||||
elseif osname == "OS X" then
|
elseif osname == "OS X" then
|
||||||
discordRPClib = ffi.load(love.filesystem.getSource().."/libs/discord-rpc.dylib")
|
discordRPClib = ffi.load(source.."/libs/discord-rpc.dylib")
|
||||||
elseif osname == "Windows" then
|
elseif osname == "Windows" then
|
||||||
discordRPClib = ffi.load(love.filesystem.getSource().."/libs/discord-rpc.dll")
|
discordRPClib = ffi.load(source.."/libs/discord-rpc.dll")
|
||||||
else
|
else
|
||||||
-- Else it crashes later on
|
-- Else it crashes later on
|
||||||
error(string.format("Discord rpc not supported on platform (%s)", osname))
|
error(string.format("Discord rpc not supported on platform (%s)", osname))
|
||||||
|
|
|
@ -33,6 +33,8 @@ blocks = {
|
||||||
C = love.graphics.newImage("res/img/s2.png"),
|
C = love.graphics.newImage("res/img/s2.png"),
|
||||||
B = love.graphics.newImage("res/img/s4.png"),
|
B = love.graphics.newImage("res/img/s4.png"),
|
||||||
M = love.graphics.newImage("res/img/s5.png"),
|
M = love.graphics.newImage("res/img/s5.png"),
|
||||||
|
F = love.graphics.newImage("res/img/s9.png"),
|
||||||
|
A = love.graphics.newImage("res/img/s8.png"),
|
||||||
X = love.graphics.newImage("res/img/s9.png"),
|
X = love.graphics.newImage("res/img/s9.png"),
|
||||||
},
|
},
|
||||||
["bone"] = {
|
["bone"] = {
|
||||||
|
@ -43,6 +45,8 @@ blocks = {
|
||||||
C = love.graphics.newImage("res/img/bone.png"),
|
C = love.graphics.newImage("res/img/bone.png"),
|
||||||
B = love.graphics.newImage("res/img/bone.png"),
|
B = love.graphics.newImage("res/img/bone.png"),
|
||||||
M = love.graphics.newImage("res/img/bone.png"),
|
M = love.graphics.newImage("res/img/bone.png"),
|
||||||
|
F = love.graphics.newImage("res/img/bone.png"),
|
||||||
|
A = love.graphics.newImage("res/img/bone.png"),
|
||||||
X = love.graphics.newImage("res/img/bone.png"),
|
X = love.graphics.newImage("res/img/bone.png"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
138
main.lua
138
main.lua
|
@ -23,13 +23,34 @@ function love.load()
|
||||||
end
|
end
|
||||||
|
|
||||||
if not config.input then
|
if not config.input then
|
||||||
config.input = {}
|
|
||||||
scene = InputConfigScene()
|
scene = InputConfigScene()
|
||||||
else
|
else
|
||||||
if config.current_mode then current_mode = config.current_mode end
|
if config.current_mode then current_mode = config.current_mode end
|
||||||
if config.current_ruleset then current_ruleset = config.current_ruleset end
|
if config.current_ruleset then current_ruleset = config.current_ruleset end
|
||||||
scene = TitleScene()
|
scene = TitleScene()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
game_modes = {}
|
||||||
|
mode_list = love.filesystem.getDirectoryItems("tetris/modes")
|
||||||
|
for i=1,#mode_list do
|
||||||
|
if(mode_list[i] ~= "gamemode.lua" and mode_list[i] ~= "unrefactored_modes") then
|
||||||
|
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
|
||||||
|
if(rule_list[i] ~= "ruleset.lua" and rule_list[i] ~= "unrefactored_rulesets") then
|
||||||
|
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
|
||||||
|
table.sort(game_modes, function(a,b)
|
||||||
|
return tostring(a.name):gsub("%d+",padnum) < tostring(b.name):gsub("%d+",padnum) end)
|
||||||
|
table.sort(rulesets, function(a,b)
|
||||||
|
return tostring(a.name):gsub("%d+",padnum) < tostring(b.name):gsub("%d+",padnum) end)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
local TARGET_FPS = 60
|
local TARGET_FPS = 60
|
||||||
|
@ -88,13 +109,124 @@ function love.draw()
|
||||||
love.graphics.pop()
|
love.graphics.pop()
|
||||||
end
|
end
|
||||||
|
|
||||||
function love.keypressed(key, scancode, isrepeat)
|
function love.keypressed(key, scancode)
|
||||||
-- global hotkeys
|
-- global hotkeys
|
||||||
if scancode == "f4" then
|
if scancode == "f4" then
|
||||||
config["fullscreen"] = not config["fullscreen"]
|
config["fullscreen"] = not config["fullscreen"]
|
||||||
love.window.setFullscreen(config["fullscreen"])
|
love.window.setFullscreen(config["fullscreen"])
|
||||||
|
elseif scancode == "f2" and scene.title ~= "Input Config" and scene.title ~= "Game" then
|
||||||
|
scene = InputConfigScene()
|
||||||
|
-- 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})
|
||||||
|
-- pass any other key to the scene, with its configured mapping
|
||||||
else
|
else
|
||||||
scene:onKeyPress({key=key, scancode=scancode, isRepeat=isrepeat})
|
local input_pressed = nil
|
||||||
|
if config.input and config.input.keys then
|
||||||
|
input_pressed = config.input.keys[scancode]
|
||||||
|
end
|
||||||
|
scene:onInputPress({input=input_pressed, type="key", key=key, scancode=scancode})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function love.keyreleased(key, scancode)
|
||||||
|
-- escape is reserved for menu_back
|
||||||
|
if scancode == "escape" then
|
||||||
|
scene:onInputRelease({input="menu_back", type="key", key=key, scancode=scancode})
|
||||||
|
-- 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
|
||||||
|
else
|
||||||
|
local input_released = nil
|
||||||
|
if config.input and config.input.keys then
|
||||||
|
input_released = config.input.keys[scancode]
|
||||||
|
end
|
||||||
|
scene:onInputRelease({input=input_released, type="key", key=key, scancode=scancode})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function love.joystickpressed(joystick, button)
|
||||||
|
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})
|
||||||
|
end
|
||||||
|
|
||||||
|
function love.joystickreleased(joystick, button)
|
||||||
|
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})
|
||||||
|
end
|
||||||
|
|
||||||
|
function love.joystickaxis(joystick, axis, value)
|
||||||
|
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
|
||||||
|
if math.abs(value) >= 0.5 then
|
||||||
|
input_pressed = config.input.joysticks[joystick:getName()].axes[axis][value >= 0.5 and "positive" or "negative"]
|
||||||
|
end
|
||||||
|
positive_released = config.input.joysticks[joystick:getName()].axes[axis].positive
|
||||||
|
negative_released = config.input.joysticks[joystick:getName()].axes[axis].negative
|
||||||
|
end
|
||||||
|
if math.abs(value) >= 0.5 then
|
||||||
|
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
|
||||||
|
end
|
||||||
|
|
||||||
|
function love.joystickhat(joystick, hat, direction)
|
||||||
|
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
|
||||||
|
scene:onInputPress({input=input_pressed, type="joyhat", name=joystick:getName(), hat=hat, direction=direction})
|
||||||
|
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
|
||||||
|
elseif direction ~= "c" then
|
||||||
|
scene:onInputPress({input=nil, type="joyhat", name=joystick:getName(), hat=hat, direction=direction})
|
||||||
|
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
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -0,0 +1,2 @@
|
||||||
|
tar -a -c -f cambridge.zip libs/binser.lua libs/classic.lua libs/discordRPC.lua load res scene tetris conf.lua main.lua scene.lua funcs.lua
|
||||||
|
rename cambridge.zip cambridge.love
|
|
@ -0,0 +1,26 @@
|
||||||
|
call package.bat
|
||||||
|
|
||||||
|
mkdir dist
|
||||||
|
mkdir dist\windows
|
||||||
|
mkdir dist\windows\libs
|
||||||
|
mkdir dist\win32
|
||||||
|
mkdir dist\win32\libs
|
||||||
|
|
||||||
|
copy /b dist\windows\love.exe+cambridge.love dist\windows\cambridge.exe
|
||||||
|
copy /b dist\win32\love.exe+cambridge.love dist\win32\cambridge.exe
|
||||||
|
|
||||||
|
copy libs\discord-rpc.dll dist\windows\libs
|
||||||
|
copy libs\discord-rpc.dll dist\win32\libs
|
||||||
|
|
||||||
|
copy SOURCES.md dist\windows
|
||||||
|
copy LICENSE.md dist\windows
|
||||||
|
copy SOURCES.md dist\win32
|
||||||
|
copy LICENSE.md dist\win32
|
||||||
|
|
||||||
|
cd dist\windows
|
||||||
|
tar -a -c -f ..\cambridge-windows.zip cambridge.exe *.dll libs *.md
|
||||||
|
cd ..\..
|
||||||
|
|
||||||
|
cd dist\win32
|
||||||
|
tar -a -c -f ..\cambridge-win32.zip cambridge.exe *.dll libs *.md
|
||||||
|
cd ..\..
|
Binary file not shown.
After Width: | Height: | Size: 229 B |
Binary file not shown.
After Width: | Height: | Size: 233 B |
|
@ -5,7 +5,8 @@ Scene = Object:extend()
|
||||||
function Scene:new() end
|
function Scene:new() end
|
||||||
function Scene:update() end
|
function Scene:update() end
|
||||||
function Scene:render() end
|
function Scene:render() end
|
||||||
function Scene:onKeyPress() end
|
function Scene:onInputPress() end
|
||||||
|
function Scene:onInputRelease() end
|
||||||
|
|
||||||
ExitScene = require "scene.exit"
|
ExitScene = require "scene.exit"
|
||||||
GameScene = require "scene.game"
|
GameScene = require "scene.game"
|
||||||
|
|
|
@ -17,7 +17,7 @@ function ConfigScene:changeOption(rel)
|
||||||
self.main_menu_state = (self.main_menu_state + len + rel - 1) % len + 1
|
self.main_menu_state = (self.main_menu_state + len + rel - 1) % len + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
function ConfigScene:onKeyPress(e)
|
function ConfigScene:onInputPress(e)
|
||||||
end
|
end
|
||||||
|
|
||||||
return ConfigScene
|
return ConfigScene
|
||||||
|
|
|
@ -16,7 +16,7 @@ end
|
||||||
function ExitScene:changeOption(rel)
|
function ExitScene:changeOption(rel)
|
||||||
end
|
end
|
||||||
|
|
||||||
function ExitScene:onKeyPress(e)
|
function ExitScene:onInputPress(e)
|
||||||
end
|
end
|
||||||
|
|
||||||
return ExitScene
|
return ExitScene
|
||||||
|
|
|
@ -1,10 +1,27 @@
|
||||||
local GameScene = Scene:extend()
|
local GameScene = Scene:extend()
|
||||||
|
|
||||||
|
GameScene.title = "Game"
|
||||||
|
|
||||||
require 'load.save'
|
require 'load.save'
|
||||||
|
|
||||||
function GameScene:new(game_mode, ruleset)
|
function GameScene:new(game_mode, ruleset)
|
||||||
|
self.retry_mode = game_mode
|
||||||
|
self.retry_ruleset = ruleset
|
||||||
self.game = game_mode()
|
self.game = game_mode()
|
||||||
self.ruleset = ruleset()
|
self.ruleset = ruleset()
|
||||||
self.game:initialize(self.ruleset)
|
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,
|
||||||
|
}
|
||||||
DiscordRPC:update({
|
DiscordRPC:update({
|
||||||
details = self.game.rpc_details,
|
details = self.game.rpc_details,
|
||||||
state = self.game.name,
|
state = self.game.name,
|
||||||
|
@ -13,18 +30,11 @@ end
|
||||||
|
|
||||||
function GameScene:update()
|
function GameScene:update()
|
||||||
if love.window.hasFocus() then
|
if love.window.hasFocus() then
|
||||||
self.game:update({
|
local inputs = {}
|
||||||
left = love.keyboard.isScancodeDown(config.input.left),
|
for input, value in pairs(self.inputs) do
|
||||||
right = love.keyboard.isScancodeDown(config.input.right),
|
inputs[input] = value
|
||||||
up = love.keyboard.isScancodeDown(config.input.up),
|
end
|
||||||
down = love.keyboard.isScancodeDown(config.input.down),
|
self.game:update(inputs, self.ruleset)
|
||||||
rotate_left = love.keyboard.isScancodeDown(config.input.rotate_left),
|
|
||||||
rotate_left2 = love.keyboard.isScancodeDown(config.input.rotate_left2),
|
|
||||||
rotate_right = love.keyboard.isScancodeDown(config.input.rotate_right),
|
|
||||||
rotate_right2 = love.keyboard.isScancodeDown(config.input.rotate_right2),
|
|
||||||
rotate_180 = love.keyboard.isScancodeDown(config.input.rotate_180),
|
|
||||||
hold = love.keyboard.isScancodeDown(config.input.hold),
|
|
||||||
}, self.ruleset)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
self.game.grid:update()
|
self.game.grid:update()
|
||||||
|
@ -60,23 +70,24 @@ function GameScene:render()
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function GameScene:onKeyPress(e)
|
function GameScene:onInputPress(e)
|
||||||
if (self.game.completed) and
|
if self.game.completed and (e.input == "menu_decide" or e.input == "menu_back" or e.input == "retry") then
|
||||||
(e.scancode == "return" or e.scancode == "escape") and e.isRepeat == false then
|
|
||||||
highscore_entry = self.game:getHighscoreData()
|
highscore_entry = self.game:getHighscoreData()
|
||||||
highscore_hash = self.game.hash .. "-" .. self.ruleset.hash
|
highscore_hash = self.game.hash .. "-" .. self.ruleset.hash
|
||||||
submitHighscore(highscore_hash, highscore_entry)
|
submitHighscore(highscore_hash, highscore_entry)
|
||||||
|
scene = e.input == "retry" and GameScene(self.retry_mode, self.retry_ruleset) or ModeSelectScene()
|
||||||
|
elseif e.input == "retry" then
|
||||||
|
scene = GameScene(self.retry_mode, self.retry_ruleset)
|
||||||
|
elseif e.input == "menu_back" then
|
||||||
scene = ModeSelectScene()
|
scene = ModeSelectScene()
|
||||||
elseif (e.scancode == config.input.retry) then
|
elseif e.input and string.sub(e.input, 1, 5) ~= "menu_" then
|
||||||
-- fuck this, this is hacky but the way this codebase is setup prevents anything else
|
self.inputs[e.input] = true
|
||||||
-- it seems like all the values that get touched in the child gamemode class
|
end
|
||||||
-- stop being linked to the values of the GameMode superclass because of how `mt.__index` works
|
end
|
||||||
-- not even sure this is the actual problem, but I don't want to have to rebuild everything about
|
|
||||||
-- the core organisation of everything. this hacky way will have to do until someone figures out something.
|
function GameScene:onInputRelease(e)
|
||||||
love.keypressed("escape", "escape", false)
|
if e.input and string.sub(e.input, 1, 5) ~= "menu_" then
|
||||||
love.keypressed("return", "return", false)
|
self.inputs[e.input] = false
|
||||||
elseif e.scancode == "escape" then
|
|
||||||
scene = ModeSelectScene()
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -6,9 +6,9 @@ require 'load.save'
|
||||||
|
|
||||||
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", "World Reverse", {"No", "Yes"}},
|
{"world_reverse","A Button Rotation", {"Left" ,"Auto" ,"Right"}},
|
||||||
}
|
}
|
||||||
local optioncount = #ConfigScene.options
|
local optioncount = #ConfigScene.options
|
||||||
|
|
||||||
|
@ -51,26 +51,26 @@ function ConfigScene:render()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function ConfigScene:onKeyPress(e)
|
function ConfigScene:onInputPress(e)
|
||||||
if e.scancode == "return" and e.isRepeat == false then
|
if e.input == "menu_decide" or e.scancode == "return" then
|
||||||
playSE("mode_decide")
|
playSE("mode_decide")
|
||||||
saveConfig()
|
saveConfig()
|
||||||
scene = TitleScene()
|
scene = TitleScene()
|
||||||
elseif (e.scancode == config.input["up"] or e.scancode == "up") and e.isRepeat == false 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)
|
||||||
elseif (e.scancode == config.input["down"] or e.scancode == "down") and e.isRepeat == false then
|
elseif e.input == "down" or e.scancode == "down" then
|
||||||
playSE("cursor")
|
playSE("cursor")
|
||||||
self.highlight = Mod1(self.highlight+1, optioncount)
|
self.highlight = Mod1(self.highlight+1, optioncount)
|
||||||
elseif (e.scancode == config.input["left"] or e.scancode == "left") and e.isRepeat == false then
|
elseif e.input == "left" or e.scancode == "left" then
|
||||||
playSE("cursor_lr")
|
playSE("cursor_lr")
|
||||||
local option = ConfigScene.options[self.highlight]
|
local option = ConfigScene.options[self.highlight]
|
||||||
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.scancode == config.input["right"] or e.scancode == "right") and e.isRepeat == false then
|
elseif e.input == "right" or e.scancode == "right" then
|
||||||
playSE("cursor_lr")
|
playSE("cursor_lr")
|
||||||
local option = ConfigScene.options[self.highlight]
|
local option = ConfigScene.options[self.highlight]
|
||||||
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.scancode == "escape" then
|
elseif e.input == "menu_back" or e.scancode == "delete" or e.scancode == "backspace" then
|
||||||
loadSave()
|
loadSave()
|
||||||
scene = TitleScene()
|
scene = TitleScene()
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,6 +5,8 @@ ConfigScene.title = "Input Config"
|
||||||
require 'load.save'
|
require 'load.save'
|
||||||
|
|
||||||
local configurable_inputs = {
|
local configurable_inputs = {
|
||||||
|
"menu_decide",
|
||||||
|
"menu_back",
|
||||||
"left",
|
"left",
|
||||||
"right",
|
"right",
|
||||||
"up",
|
"up",
|
||||||
|
@ -18,10 +20,18 @@ local configurable_inputs = {
|
||||||
"retry",
|
"retry",
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local function newSetInputs()
|
||||||
|
local set_inputs = {}
|
||||||
|
for i, input in ipairs(configurable_inputs) do
|
||||||
|
set_inputs[input] = false
|
||||||
|
end
|
||||||
|
return set_inputs
|
||||||
|
end
|
||||||
|
|
||||||
function ConfigScene:new()
|
function ConfigScene:new()
|
||||||
-- load current config
|
|
||||||
self.config = config.input
|
|
||||||
self.input_state = 1
|
self.input_state = 1
|
||||||
|
self.set_inputs = newSetInputs()
|
||||||
|
self.new_input = {}
|
||||||
|
|
||||||
DiscordRPC:update({
|
DiscordRPC:update({
|
||||||
details = "In menus",
|
details = "In menus",
|
||||||
|
@ -41,38 +51,105 @@ function ConfigScene:render()
|
||||||
)
|
)
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_2)
|
love.graphics.setFont(font_3x5_2)
|
||||||
for i, input in pairs(configurable_inputs) do
|
for i, input in ipairs(configurable_inputs) do
|
||||||
love.graphics.printf(input, 40, 50 + i * 20, 200, "left")
|
love.graphics.printf(input, 40, 50 + i * 20, 200, "left")
|
||||||
if config.input[input] then
|
if self.set_inputs[input] then
|
||||||
love.graphics.printf(
|
love.graphics.printf(self.set_inputs[input], 240, 50 + i * 20, 300, "left")
|
||||||
love.keyboard.getKeyFromScancode(config.input[input]) .. " (" .. config.input[input] .. ")",
|
|
||||||
240, 50 + i * 20, 200, "left"
|
|
||||||
)
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if self.input_state > table.getn(configurable_inputs) then
|
if self.input_state > table.getn(configurable_inputs) then
|
||||||
love.graphics.print("press enter to confirm, delete to retry")
|
love.graphics.print("press enter to confirm, delete/backspace to retry" .. (config.input and ", escape to cancel" or ""))
|
||||||
else
|
else
|
||||||
love.graphics.print("press key for " .. configurable_inputs[self.input_state])
|
love.graphics.print("press key or joystick input for " .. configurable_inputs[self.input_state] .. ", tab to skip" .. (config.input and ", escape to cancel" or ""), 0, 0)
|
||||||
|
love.graphics.print("function keys (F1, F2, etc.), escape, and tab can't be changed", 0, 20)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function ConfigScene:onKeyPress(e)
|
local function addJoystick(input, name)
|
||||||
if self.input_state > table.getn(configurable_inputs) then
|
if not input.joysticks then
|
||||||
|
input.joysticks = {}
|
||||||
|
end
|
||||||
|
if not input.joysticks[name] then
|
||||||
|
input.joysticks[name] = {}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ConfigScene:onInputPress(e)
|
||||||
|
if e.type == "key" then
|
||||||
|
-- function keys, escape, and tab are reserved and can't be remapped
|
||||||
|
if e.scancode == "escape" and config.input then
|
||||||
|
-- cancel only if there was an input config already
|
||||||
|
scene = TitleScene()
|
||||||
|
elseif self.input_state > table.getn(configurable_inputs) then
|
||||||
if e.scancode == "return" then
|
if e.scancode == "return" then
|
||||||
-- save, then load next scene
|
-- save new input, then load next scene
|
||||||
|
config.input = self.new_input
|
||||||
saveConfig()
|
saveConfig()
|
||||||
scene = TitleScene()
|
scene = TitleScene()
|
||||||
elseif e.scancode == "delete" or e.scancode == "backspace" then
|
elseif e.scancode == "delete" or e.scancode == "backspace" then
|
||||||
|
-- retry
|
||||||
self.input_state = 1
|
self.input_state = 1
|
||||||
|
self.set_inputs = newSetInputs()
|
||||||
|
self.new_input = {}
|
||||||
end
|
end
|
||||||
else
|
elseif e.scancode == "tab" then
|
||||||
if e.scancode == "escape" then
|
self.set_inputs[configurable_inputs[self.input_state]] = "skipped"
|
||||||
loadSave()
|
|
||||||
scene = TitleScene()
|
|
||||||
else
|
|
||||||
config.input[configurable_inputs[self.input_state]] = e.scancode
|
|
||||||
self.input_state = self.input_state + 1
|
self.input_state = self.input_state + 1
|
||||||
|
elseif e.scancode ~= "escape" then
|
||||||
|
-- all other keys can be configured
|
||||||
|
if not self.new_input.keys then
|
||||||
|
self.new_input.keys = {}
|
||||||
|
end
|
||||||
|
self.set_inputs[configurable_inputs[self.input_state]] = "key " .. love.keyboard.getKeyFromScancode(e.scancode) .. " (" .. e.scancode .. ")"
|
||||||
|
self.new_input.keys[e.scancode] = configurable_inputs[self.input_state]
|
||||||
|
self.input_state = self.input_state + 1
|
||||||
|
end
|
||||||
|
elseif string.sub(e.type, 1, 3) == "joy" then
|
||||||
|
if self.input_state <= table.getn(configurable_inputs) then
|
||||||
|
if e.type == "joybutton" then
|
||||||
|
addJoystick(self.new_input, e.name)
|
||||||
|
if not self.new_input.joysticks[e.name].buttons then
|
||||||
|
self.new_input.joysticks[e.name].buttons = {}
|
||||||
|
end
|
||||||
|
self.set_inputs[configurable_inputs[self.input_state]] =
|
||||||
|
"jbtn " ..
|
||||||
|
e.button ..
|
||||||
|
" " .. string.sub(e.name, 1, 10) .. (string.len(e.name) > 10 and "..." or "")
|
||||||
|
self.new_input.joysticks[e.name].buttons[e.button] = configurable_inputs[self.input_state]
|
||||||
|
self.input_state = self.input_state + 1
|
||||||
|
elseif e.type == "joyaxis" then
|
||||||
|
if math.abs(e.value) >= 0.5 then
|
||||||
|
addJoystick(self.new_input, e.name)
|
||||||
|
if not self.new_input.joysticks[e.name].axes then
|
||||||
|
self.new_input.joysticks[e.name].axes = {}
|
||||||
|
end
|
||||||
|
if not self.new_input.joysticks[e.name].axes[e.axis] then
|
||||||
|
self.new_input.joysticks[e.name].axes[e.axis] = {}
|
||||||
|
end
|
||||||
|
self.set_inputs[configurable_inputs[self.input_state]] =
|
||||||
|
"jaxis " ..
|
||||||
|
(e.value >= 0.5 and "+" or "-") .. e.axis ..
|
||||||
|
" " .. string.sub(e.name, 1, 10) .. (string.len(e.name) > 10 and "..." or "")
|
||||||
|
self.new_input.joysticks[e.name].axes[e.axis][e.value >= 0.5 and "positive" or "negative"] = configurable_inputs[self.input_state]
|
||||||
|
self.input_state = self.input_state + 1
|
||||||
|
end
|
||||||
|
elseif e.type == "joyhat" then
|
||||||
|
if e.direction ~= "c" then
|
||||||
|
addJoystick(self.new_input, e.name)
|
||||||
|
if not self.new_input.joysticks[e.name].hats then
|
||||||
|
self.new_input.joysticks[e.name].hats = {}
|
||||||
|
end
|
||||||
|
if not self.new_input.joysticks[e.name].hats[e.hat] then
|
||||||
|
self.new_input.joysticks[e.name].hats[e.hat] = {}
|
||||||
|
end
|
||||||
|
self.set_inputs[configurable_inputs[self.input_state]] =
|
||||||
|
"jhat " ..
|
||||||
|
e.hat .. " " .. e.direction ..
|
||||||
|
" " .. string.sub(e.name, 1, 10) .. (string.len(e.name) > 10 and "..." or "")
|
||||||
|
self.new_input.joysticks[e.name].hats[e.hat][e.direction] = configurable_inputs[self.input_state]
|
||||||
|
self.input_state = self.input_state + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -5,44 +5,6 @@ ModeSelectScene.title = "Game Start"
|
||||||
current_mode = 1
|
current_mode = 1
|
||||||
current_ruleset = 1
|
current_ruleset = 1
|
||||||
|
|
||||||
game_modes = {
|
|
||||||
require 'tetris.modes.marathon_2020',
|
|
||||||
require 'tetris.modes.survival_2020',
|
|
||||||
require 'tetris.modes.ck',
|
|
||||||
--require 'tetris.modes.strategy',
|
|
||||||
--require 'tetris.modes.interval_training',
|
|
||||||
--require 'tetris.modes.pacer_test',
|
|
||||||
require 'tetris.modes.demon_mode',
|
|
||||||
require 'tetris.modes.phantom_mania',
|
|
||||||
require 'tetris.modes.phantom_mania2',
|
|
||||||
require 'tetris.modes.phantom_mania_n',
|
|
||||||
require 'tetris.modes.race_40',
|
|
||||||
require 'tetris.modes.marathon_a1',
|
|
||||||
require 'tetris.modes.marathon_a2',
|
|
||||||
require 'tetris.modes.marathon_a3',
|
|
||||||
require 'tetris.modes.marathon_ax4',
|
|
||||||
require 'tetris.modes.marathon_c89',
|
|
||||||
require 'tetris.modes.survival_a1',
|
|
||||||
require 'tetris.modes.survival_a2',
|
|
||||||
require 'tetris.modes.survival_a3',
|
|
||||||
require 'tetris.modes.big_a2',
|
|
||||||
require 'tetris.modes.konoha',
|
|
||||||
}
|
|
||||||
|
|
||||||
rulesets = {
|
|
||||||
require 'tetris.rulesets.cambridge',
|
|
||||||
require 'tetris.rulesets.arika',
|
|
||||||
require 'tetris.rulesets.arika_ti',
|
|
||||||
require 'tetris.rulesets.ti_srs',
|
|
||||||
require 'tetris.rulesets.arika_ace',
|
|
||||||
require 'tetris.rulesets.arika_ace2',
|
|
||||||
require 'tetris.rulesets.arika_srs',
|
|
||||||
require 'tetris.rulesets.standard_exp',
|
|
||||||
--require 'tetris.rulesets.bonkers',
|
|
||||||
--require 'tetris.rulesets.shirase',
|
|
||||||
--require 'tetris.rulesets.super302',
|
|
||||||
}
|
|
||||||
|
|
||||||
function ModeSelectScene:new()
|
function ModeSelectScene:new()
|
||||||
self.menu_state = {
|
self.menu_state = {
|
||||||
mode = current_mode,
|
mode = current_mode,
|
||||||
|
@ -70,14 +32,14 @@ function ModeSelectScene:render()
|
||||||
elseif self.menu_state.select == "ruleset" then
|
elseif self.menu_state.select == "ruleset" then
|
||||||
love.graphics.setColor(1, 1, 1, 0.25)
|
love.graphics.setColor(1, 1, 1, 0.25)
|
||||||
end
|
end
|
||||||
love.graphics.rectangle("fill", 20, 78 + 20 * self.menu_state.mode, 240, 22)
|
love.graphics.rectangle("fill", 20, 258, 240, 22)
|
||||||
|
|
||||||
if self.menu_state.select == "mode" then
|
if self.menu_state.select == "mode" then
|
||||||
love.graphics.setColor(1, 1, 1, 0.25)
|
love.graphics.setColor(1, 1, 1, 0.25)
|
||||||
elseif self.menu_state.select == "ruleset" then
|
elseif self.menu_state.select == "ruleset" then
|
||||||
love.graphics.setColor(1, 1, 1, 0.5)
|
love.graphics.setColor(1, 1, 1, 0.5)
|
||||||
end
|
end
|
||||||
love.graphics.rectangle("fill", 340, 78 + 20 * self.menu_state.ruleset, 200, 22)
|
love.graphics.rectangle("fill", 340, 258, 200, 22)
|
||||||
|
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
|
|
||||||
|
@ -85,15 +47,19 @@ function ModeSelectScene:render()
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_2)
|
love.graphics.setFont(font_3x5_2)
|
||||||
for idx, mode in pairs(game_modes) do
|
for idx, mode in pairs(game_modes) do
|
||||||
love.graphics.printf(mode.name, 40, 80 + 20 * idx, 200, "left")
|
if(idx >= self.menu_state.mode-9 and idx <= self.menu_state.mode+9) then
|
||||||
|
love.graphics.printf(mode.name, 40, (260 - 20*(self.menu_state.mode)) + 20 * idx, 200, "left")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
for idx, ruleset in pairs(rulesets) do
|
for idx, ruleset in pairs(rulesets) do
|
||||||
love.graphics.printf(ruleset.name, 360, 80 + 20 * idx, 160, "left")
|
if(idx >= self.menu_state.ruleset-9 and idx <= self.menu_state.ruleset+9) then
|
||||||
|
love.graphics.printf(ruleset.name, 360, (260 - 20*(self.menu_state.ruleset)) + 20 * idx, 160, "left")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function ModeSelectScene:onKeyPress(e)
|
function ModeSelectScene:onInputPress(e)
|
||||||
if e.scancode == "return" and e.isRepeat == false then
|
if e.input == "menu_decide" or e.scancode == "return" then
|
||||||
current_mode = self.menu_state.mode
|
current_mode = self.menu_state.mode
|
||||||
current_ruleset = self.menu_state.ruleset
|
current_ruleset = self.menu_state.ruleset
|
||||||
config.current_mode = current_mode
|
config.current_mode = current_mode
|
||||||
|
@ -101,17 +67,16 @@ function ModeSelectScene:onKeyPress(e)
|
||||||
playSE("mode_decide")
|
playSE("mode_decide")
|
||||||
saveConfig()
|
saveConfig()
|
||||||
scene = GameScene(game_modes[self.menu_state.mode], rulesets[self.menu_state.ruleset])
|
scene = GameScene(game_modes[self.menu_state.mode], rulesets[self.menu_state.ruleset])
|
||||||
elseif (e.scancode == config.input["up"] or e.scancode == "up") and e.isRepeat == false then
|
elseif e.input == "up" or e.scancode == "up" then
|
||||||
self:changeOption(-1)
|
self:changeOption(-1)
|
||||||
playSE("cursor")
|
playSE("cursor")
|
||||||
elseif (e.scancode == config.input["down"] or e.scancode == "down") and e.isRepeat == false then
|
elseif e.input == "down" or e.scancode == "down" then
|
||||||
self:changeOption(1)
|
self:changeOption(1)
|
||||||
playSE("cursor")
|
playSE("cursor")
|
||||||
elseif (e.scancode == config.input["left"] or e.scancode == "left") or
|
elseif e.input == "left" or e.input == "right" or e.scancode == "left" or e.scancode == "right" then
|
||||||
(e.scancode == config.input["right"] or e.scancode == "right") then
|
|
||||||
self:switchSelect()
|
self:switchSelect()
|
||||||
playSE("cursor_lr")
|
playSE("cursor_lr")
|
||||||
elseif e.scancode == "escape" then
|
elseif e.input == "menu_back" or e.scancode == "delete" or e.scancode == "backspace" then
|
||||||
scene = TitleScene()
|
scene = TitleScene()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -57,17 +57,17 @@ function TitleScene:changeOption(rel)
|
||||||
self.main_menu_state = (self.main_menu_state + len + rel - 1) % len + 1
|
self.main_menu_state = (self.main_menu_state + len + rel - 1) % len + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
function TitleScene:onKeyPress(e)
|
function TitleScene:onInputPress(e)
|
||||||
if e.scancode == "return" and e.isRepeat == false then
|
if e.input == "menu_decide" or e.scancode == "return" then
|
||||||
playSE("main_decide")
|
playSE("main_decide")
|
||||||
scene = main_menu_screens[self.main_menu_state]()
|
scene = main_menu_screens[self.main_menu_state]()
|
||||||
elseif (e.scancode == config.input["up"] or e.scancode == "up") and e.isRepeat == false then
|
elseif e.input == "up" or e.scancode == "up" then
|
||||||
self:changeOption(-1)
|
self:changeOption(-1)
|
||||||
playSE("cursor")
|
playSE("cursor")
|
||||||
elseif (e.scancode == config.input["down"] or e.scancode == "down") and e.isRepeat == false then
|
elseif e.input == "down" or e.scancode == "down" then
|
||||||
self:changeOption(1)
|
self:changeOption(1)
|
||||||
playSE("cursor")
|
playSE("cursor")
|
||||||
elseif e.scancode == "escape" and e.isRepeat == false then
|
elseif e.input == "menu_back" or e.scancode == "backspace" or e.scancode == "delete" then
|
||||||
love.event.quit()
|
love.event.quit()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
|
@ -4,6 +4,7 @@ local Grid = Object:extend()
|
||||||
|
|
||||||
local empty = { skin = "", colour = "" }
|
local empty = { skin = "", colour = "" }
|
||||||
local oob = { skin = "", colour = "" }
|
local oob = { skin = "", colour = "" }
|
||||||
|
local block = { skin = "2tie", colour = "A" }
|
||||||
|
|
||||||
function Grid:new()
|
function Grid:new()
|
||||||
self.grid = {}
|
self.grid = {}
|
||||||
|
@ -141,14 +142,35 @@ function Grid:copyBottomRow()
|
||||||
self.grid[24] = {empty, empty, empty, empty, empty, empty, empty, empty, empty, empty}
|
self.grid[24] = {empty, empty, empty, empty, empty, empty, empty, empty, empty, empty}
|
||||||
self.grid_age[24] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
self.grid_age[24] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||||
for col = 1, 10 do
|
for col = 1, 10 do
|
||||||
self.grid[24][col] = (self.grid[23][col] == empty) and empty or {
|
self.grid[24][col] = (self.grid[23][col] == empty) and empty or block
|
||||||
skin = self.grid[23][col].skin,
|
|
||||||
colour = "X"
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Grid:garbageRise(row_vals)
|
||||||
|
for row = 1, 23 do
|
||||||
|
self.grid[row] = self.grid[row+1]
|
||||||
|
self.grid_age[row] = self.grid_age[row+1]
|
||||||
|
end
|
||||||
|
self.grid[24] = {empty, empty, empty, empty, empty, empty, empty, empty, empty, empty}
|
||||||
|
self.grid_age[24] = {0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||||
|
for col = 1, 10 do
|
||||||
|
self.grid[24][col] = (row_vals[col] == "e") and empty or block
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Grid:applyFourWide()
|
||||||
|
for row = 1, 24 do
|
||||||
|
local x = self.grid[row]
|
||||||
|
x[1] = x[1]~=block and block or x[1]
|
||||||
|
x[2] = x[2]~=block and block or x[2]
|
||||||
|
x[3] = x[3]~=block and block or x[3]
|
||||||
|
x[8] = x[8]~=block and block or x[8]
|
||||||
|
x[9] = x[9]~=block and block or x[9]
|
||||||
|
x[10] = x[10]~=block and block or x[10]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function Grid:applyPiece(piece)
|
function Grid:applyPiece(piece)
|
||||||
if piece.big then
|
if piece.big then
|
||||||
self:applyBigPiece(piece)
|
self:applyBigPiece(piece)
|
||||||
|
@ -216,7 +238,7 @@ function Grid:checkSecretGrade()
|
||||||
if(validLine) then
|
if(validLine) then
|
||||||
sgrade = sgrade + 1
|
sgrade = sgrade + 1
|
||||||
else
|
else
|
||||||
-- return sgrade
|
return sgrade
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
--[[
|
--[[
|
||||||
|
@ -239,14 +261,18 @@ function Grid:update()
|
||||||
end
|
end
|
||||||
|
|
||||||
function Grid:draw()
|
function Grid:draw()
|
||||||
for y = 1, 24 do
|
for y = 5, 24 do
|
||||||
for x = 1, 10 do
|
for x = 1, 10 do
|
||||||
if self.grid[y][x] ~= empty then
|
if self.grid[y][x] ~= empty then
|
||||||
if self.grid_age[y][x] < 1 then
|
if self.grid_age[y][x] < 2 then
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
love.graphics.draw(blocks[self.grid[y][x].skin]["F"], 48+x*16, y*16)
|
love.graphics.draw(blocks[self.grid[y][x].skin]["F"], 48+x*16, y*16)
|
||||||
|
else
|
||||||
|
if self.grid[y][x].skin == "bone" then
|
||||||
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
else
|
else
|
||||||
love.graphics.setColor(0.5, 0.5, 0.5, 1)
|
love.graphics.setColor(0.5, 0.5, 0.5, 1)
|
||||||
|
end
|
||||||
love.graphics.draw(blocks[self.grid[y][x].skin][self.grid[y][x].colour], 48+x*16, y*16)
|
love.graphics.draw(blocks[self.grid[y][x].skin][self.grid[y][x].colour], 48+x*16, y*16)
|
||||||
end
|
end
|
||||||
if self.grid[y][x].skin ~= "bone" then
|
if self.grid[y][x].skin ~= "bone" then
|
||||||
|
@ -271,12 +297,12 @@ function Grid:draw()
|
||||||
end
|
end
|
||||||
|
|
||||||
function Grid:drawInvisible(opacity_function, garbage_opacity_function)
|
function Grid:drawInvisible(opacity_function, garbage_opacity_function)
|
||||||
for y = 1, 24 do
|
for y = 5, 24 do
|
||||||
for x = 1, 10 do
|
for x = 1, 10 do
|
||||||
if self.grid[y][x] ~= empty then
|
if self.grid[y][x] ~= empty then
|
||||||
if self.grid[y][x].colour == "X" then
|
if self.grid[y][x].colour == "X" then
|
||||||
opacity = 1
|
opacity = 1
|
||||||
elseif garbage_opacity_function and self.grid[y][x].colour == "G" then
|
elseif garbage_opacity_function and self.grid[y][x].colour == "A" then
|
||||||
opacity = garbage_opacity_function(self.grid_age[y][x])
|
opacity = garbage_opacity_function(self.grid_age[y][x])
|
||||||
else
|
else
|
||||||
opacity = opacity_function(self.grid_age[y][x])
|
opacity = opacity_function(self.grid_age[y][x])
|
||||||
|
|
|
@ -98,7 +98,7 @@ end
|
||||||
|
|
||||||
function Piece:dropToBottom(grid)
|
function Piece:dropToBottom(grid)
|
||||||
local piece_y = self.position.y
|
local piece_y = self.position.y
|
||||||
self:dropSquares(24, grid)
|
self:dropSquares(math.huge, grid)
|
||||||
self.gravity = 0
|
self.gravity = 0
|
||||||
if self.position.y > piece_y then
|
if self.position.y > piece_y then
|
||||||
-- if it got dropped any, also reset lock delay
|
-- if it got dropped any, also reset lock delay
|
||||||
|
|
|
@ -19,17 +19,15 @@ function MarathonA2Game:new()
|
||||||
self.big_mode = true
|
self.big_mode = true
|
||||||
self.roll_frames = 0
|
self.roll_frames = 0
|
||||||
self.combo = 1
|
self.combo = 1
|
||||||
self.randomizer = History6RollsRandomizer()
|
|
||||||
self.grade = 0
|
self.grade = 0
|
||||||
self.grade_points = 0
|
self.grade_points = 0
|
||||||
self.grade_point_decay_counter = 0
|
self.grade_point_decay_counter = 0
|
||||||
self.section_start_time = 0
|
|
||||||
self.section_times = { [0] = 0 }
|
|
||||||
self.section_tetrises = { [0] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
|
|
||||||
|
|
||||||
self.randomizer = History6RollsRandomizer()
|
self.randomizer = History6RollsRandomizer()
|
||||||
|
|
||||||
self.lock_drop = false
|
self.lock_drop = false
|
||||||
|
self.lock_hard_drop = false
|
||||||
self.enable_hold = false
|
self.enable_hold = false
|
||||||
self.next_queue_length = 1
|
self.next_queue_length = 1
|
||||||
end
|
end
|
||||||
|
@ -103,11 +101,9 @@ end
|
||||||
function MarathonA2Game:advanceOneFrame()
|
function MarathonA2Game:advanceOneFrame()
|
||||||
if self.clear then
|
if self.clear then
|
||||||
self.roll_frames = self.roll_frames + 1
|
self.roll_frames = self.roll_frames + 1
|
||||||
|
if self.roll_frames < 0 then return false end
|
||||||
if self.roll_frames > 3694 then
|
if self.roll_frames > 3694 then
|
||||||
self.completed = true
|
self.completed = true
|
||||||
if self.grade == 32 then
|
|
||||||
self.grade = 33
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
elseif self.ready_frames == 0 then
|
elseif self.ready_frames == 0 then
|
||||||
self.frames = self.frames + 1
|
self.frames = self.frames + 1
|
||||||
|
@ -123,43 +119,31 @@ end
|
||||||
|
|
||||||
function MarathonA2Game:onLineClear(cleared_row_count)
|
function MarathonA2Game:onLineClear(cleared_row_count)
|
||||||
cleared_row_count = cleared_row_count / 2
|
cleared_row_count = cleared_row_count / 2
|
||||||
self:updateSectionTimes(self.level, self.level + cleared_row_count)
|
|
||||||
self.level = math.min(self.level + cleared_row_count, 999)
|
self.level = math.min(self.level + cleared_row_count, 999)
|
||||||
if self.level == 999 and not self.clear then
|
if self.level == 999 and not self.clear then
|
||||||
self.clear = true
|
self.clear = true
|
||||||
if self:qualifiesForMRoll() then
|
|
||||||
self.grade = 32
|
|
||||||
end
|
|
||||||
self.grid:clear()
|
self.grid:clear()
|
||||||
self.roll_frames = -150
|
self.roll_frames = -150
|
||||||
end
|
end
|
||||||
|
self.lock_drop = self.level >= 900
|
||||||
|
self.lock_hard_drop = self.level >= 900
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA2Game:updateScore(level, drop_bonus, cleared_lines)
|
function MarathonA2Game:updateScore(level, drop_bonus, cleared_lines)
|
||||||
if self.grid:checkForBravo(cleared_lines) then self.bravo = 4 else self.bravo = 1 end
|
if not self.clear then
|
||||||
cleared_lines = cleared_lines / 2
|
cleared_lines = cleared_lines / 2
|
||||||
self:updateGrade(cleared_lines)
|
self:updateGrade(cleared_lines)
|
||||||
|
if self.grid:checkForBravo(cleared_lines) then self.bravo = 4 else self.bravo = 1 end
|
||||||
if cleared_lines > 0 then
|
if cleared_lines > 0 then
|
||||||
|
self.combo = self.combo + (cleared_lines - 1) * 2
|
||||||
self.score = self.score + (
|
self.score = self.score + (
|
||||||
(math.ceil((level + cleared_lines) / 4) + 2 * drop_bonus) *
|
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
||||||
cleared_lines * self.combo * self.bravo
|
cleared_lines * self.combo * self.bravo
|
||||||
)
|
)
|
||||||
self.lines = self.lines + cleared_lines
|
|
||||||
self.combo = self.combo + 2 * (cleared_lines - 1)
|
|
||||||
else
|
else
|
||||||
self.drop_bonus = 0
|
|
||||||
self.combo = 1
|
self.combo = 1
|
||||||
end
|
end
|
||||||
end
|
self.drop_bonus = 0
|
||||||
|
|
||||||
function MarathonA2Game:updateSectionTimes(old_level, new_level)
|
|
||||||
if self.clear then return end
|
|
||||||
if math.floor(old_level / 100) < math.floor(new_level / 100) or
|
|
||||||
new_level >= 999 then
|
|
||||||
-- record new section
|
|
||||||
section_time = self.frames - self.section_start_time
|
|
||||||
self.section_times[math.floor(old_level / 100)] = section_time
|
|
||||||
self.section_start_time = self.frames
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -224,7 +208,7 @@ local grade_conversion = {
|
||||||
1, 2, 3, 4, 5, 5, 6, 6, 7, 7,
|
1, 2, 3, 4, 5, 5, 6, 6, 7, 7,
|
||||||
7, 8, 8, 8, 9, 9, 9, 10, 11, 12,
|
7, 8, 8, 8, 9, 9, 9, 10, 11, 12,
|
||||||
12, 12, 13, 13, 14, 14, 15, 15, 16, 16,
|
12, 12, 13, 13, 14, 14, 15, 15, 16, 16,
|
||||||
17, 18, 19
|
17
|
||||||
}
|
}
|
||||||
|
|
||||||
function MarathonA2Game:updateGrade(cleared_lines)
|
function MarathonA2Game:updateGrade(cleared_lines)
|
||||||
|
@ -249,49 +233,12 @@ function MarathonA2Game:updateGrade(cleared_lines)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local tetris_requirements = { [0] = 2, 2, 2, 2, 2, 1, 1, 1, 1, 1 }
|
|
||||||
|
|
||||||
function MarathonA2Game:qualifiesForMRoll()
|
|
||||||
if not self.clear then return false end
|
|
||||||
-- tetris requirements
|
|
||||||
for section = 0, 9 do
|
|
||||||
if self.section_tetrises[section] < tetris_requirements[section] then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- section time requirements
|
|
||||||
local section_average = 0
|
|
||||||
for section = 0, 4 do
|
|
||||||
section_average = section_average + self.section_times[section]
|
|
||||||
if self.section_times[section] > frameTime(1,05) then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
-- section time average requirements
|
|
||||||
if self.section_times[5] > section_average / 5 then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
for section = 6, 9 do
|
|
||||||
if self.section_times[section] > self.section_times[section - 1] + 120 then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if self.grade < 17 or self.frames > frameTime(8,45) then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonA2Game:getLetterGrade()
|
function MarathonA2Game:getLetterGrade()
|
||||||
local grade = grade_conversion[self.grade]
|
local grade = grade_conversion[self.grade]
|
||||||
if grade < 9 then
|
if grade < 9 then
|
||||||
return tostring(9 - grade)
|
return tostring(9 - grade)
|
||||||
elseif grade < 18 then
|
elseif grade < 18 then
|
||||||
return "S" .. tostring(grade - 8)
|
return "S" .. tostring(grade - 8)
|
||||||
elseif grade == 18 then
|
|
||||||
return "M"
|
|
||||||
else
|
|
||||||
return "GM"
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -301,18 +248,9 @@ MarathonA2Game.rollOpacityFunction = function(age)
|
||||||
else return 1 - (age - 240) / 60 end
|
else return 1 - (age - 240) / 60 end
|
||||||
end
|
end
|
||||||
|
|
||||||
MarathonA2Game.mRollOpacityFunction = function(age)
|
|
||||||
if age > 4 then return 0
|
|
||||||
else return 1 - age / 4 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonA2Game:drawGrid(ruleset)
|
function MarathonA2Game:drawGrid(ruleset)
|
||||||
if self.clear and not (self.completed or self.game_over) then
|
if self.clear and not (self.completed or self.game_over) then
|
||||||
if self:qualifiesForMRoll() then
|
|
||||||
self.grid:drawInvisible(self.mRollOpacityFunction)
|
|
||||||
else
|
|
||||||
self.grid:drawInvisible(self.rollOpacityFunction)
|
self.grid:drawInvisible(self.rollOpacityFunction)
|
||||||
end
|
|
||||||
else
|
else
|
||||||
self.grid:draw()
|
self.grid:draw()
|
||||||
if self.piece ~= nil and self.level < 100 then
|
if self.piece ~= nil and self.level < 100 then
|
||||||
|
@ -336,7 +274,10 @@ function MarathonA2Game:drawScoringInfo()
|
||||||
love.graphics.printf("LEVEL", 240, 320, 40, "left")
|
love.graphics.printf("LEVEL", 240, 320, 40, "left")
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
love.graphics.setFont(font_3x5_3)
|
||||||
|
if self.roll_frames > 3694 then love.graphics.setColor(1, 0.5, 0, 1)
|
||||||
|
elseif self.clear then love.graphics.setColor(0, 1, 0, 1) end
|
||||||
love.graphics.printf(self:getLetterGrade(), 240, 140, 90, "left")
|
love.graphics.printf(self:getLetterGrade(), 240, 140, 90, "left")
|
||||||
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
love.graphics.printf(self.score, 240, 220, 90, "left")
|
love.graphics.printf(self.score, 240, 220, 90, "left")
|
||||||
love.graphics.printf(self.level, 240, 340, 40, "right")
|
love.graphics.printf(self.level, 240, 340, 40, "right")
|
||||||
love.graphics.printf(self:getSectionEndLevel(), 240, 370, 40, "right")
|
love.graphics.printf(self:getSectionEndLevel(), 240, 370, 40, "right")
|
||||||
|
|
|
@ -1,325 +0,0 @@
|
||||||
require 'funcs'
|
|
||||||
|
|
||||||
local GameMode = require 'tetris.modes.gamemode'
|
|
||||||
local Piece = require 'tetris.components.piece'
|
|
||||||
|
|
||||||
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls_35bag'
|
|
||||||
|
|
||||||
local SurvivalCKGame = GameMode:extend()
|
|
||||||
|
|
||||||
SurvivalCKGame.name = "Survival CK"
|
|
||||||
SurvivalCKGame.hash = "SurvivalCK"
|
|
||||||
SurvivalCKGame.tagline = "An endurance mode created by CylinderKnot! Watch out for the fading pieces..."
|
|
||||||
|
|
||||||
function SurvivalCKGame:new()
|
|
||||||
SurvivalCKGame.super:new()
|
|
||||||
|
|
||||||
self.garbage = 0
|
|
||||||
self.roll_frames = 0
|
|
||||||
self.combo = 1
|
|
||||||
self.grade = 0
|
|
||||||
self.level = 0
|
|
||||||
|
|
||||||
self.randomizer = History6RollsRandomizer()
|
|
||||||
|
|
||||||
self.enable_hold = true
|
|
||||||
self.next_queue_length = 3
|
|
||||||
|
|
||||||
self.coolregret_timer = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalCKGame:getARE()
|
|
||||||
if self.level < 100 then return 15
|
|
||||||
elseif self.level < 200 then return 14
|
|
||||||
elseif self.level < 300 then return 13
|
|
||||||
elseif self.level < 400 then return 12
|
|
||||||
elseif self.level < 500 then return 11
|
|
||||||
elseif self.level < 600 then return 10
|
|
||||||
elseif self.level < 700 then return 9
|
|
||||||
elseif self.level < 800 then return 8
|
|
||||||
elseif self.level < 900 then return 7
|
|
||||||
elseif self.level < 1000 then return 6
|
|
||||||
elseif self.level < 2500 then return 5
|
|
||||||
else return 7 end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
function SurvivalCKGame:getLineARE()
|
|
||||||
return SurvivalCKGame:getARE()
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalCKGame:getDasLimit()
|
|
||||||
if self.level < 700 then return 10
|
|
||||||
elseif self.level < 900 then return 9
|
|
||||||
elseif self.level < 1100 then return 8
|
|
||||||
elseif self.level < 1300 then return 7
|
|
||||||
elseif self.level < 1600 then return 6
|
|
||||||
else return 5 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalCKGame:getLineClearDelay()
|
|
||||||
if self.level < 100 then return 10
|
|
||||||
elseif self.level < 200 then return 8
|
|
||||||
elseif self.level < 300 then return 7
|
|
||||||
elseif self.level < 400 then return 6
|
|
||||||
else return 5 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalCKGame:getLockDelay()
|
|
||||||
if self.level < 600 then return 20
|
|
||||||
elseif self.level < 700 then return 19
|
|
||||||
elseif self.level < 800 then return 18
|
|
||||||
elseif self.level < 900 then return 17
|
|
||||||
elseif self.level < 1000 then return 16
|
|
||||||
elseif self.level < 1200 then return 15
|
|
||||||
elseif self.level < 1400 then return 14
|
|
||||||
elseif self.level < 1700 then return 13
|
|
||||||
elseif self.level < 2100 then return 12
|
|
||||||
elseif self.level < 2200 then return 11
|
|
||||||
elseif self.level < 2300 then return 10
|
|
||||||
elseif self.level < 2400 then return 9
|
|
||||||
elseif self.level < 2500 then return 8
|
|
||||||
else return 15 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalCKGame:getGravity()
|
|
||||||
return 20
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalCKGame:getGarbageLimit()
|
|
||||||
if self.level < 1000 then return 20
|
|
||||||
elseif self.level < 1100 then return 17
|
|
||||||
elseif self.level < 1200 then return 14
|
|
||||||
elseif self.level < 1300 then return 11
|
|
||||||
else return 8 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalCKGame:getRegretTime()
|
|
||||||
if self.level < 500 then return frameTime(0,55)
|
|
||||||
elseif self.level < 1000 then return frameTime(0,50)
|
|
||||||
elseif self.level < 1500 then return frameTime(0,40)
|
|
||||||
elseif self.level < 2000 then return frameTime(0,35)
|
|
||||||
else return frameTime(0,30) end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalCKGame:getNextPiece(ruleset)
|
|
||||||
return {
|
|
||||||
skin = self.level >= 2000 and "bone" or "2tie",
|
|
||||||
shape = self.randomizer:nextPiece(),
|
|
||||||
orientation = ruleset:getDefaultOrientation(),
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
local torikan_times = {300, 330, 360, 390, 420, 450, 478, 504, 528, 550, 570}
|
|
||||||
|
|
||||||
function SurvivalCKGame:hitTorikan(old_level, new_level)
|
|
||||||
for i = 1, 11 do
|
|
||||||
if old_level < (900 + i * 100) and new_level >= (900 + i * 100) and self.frames > torikan_times[i] * 60 then
|
|
||||||
self.level = 900 + i * 100
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalCKGame:advanceOneFrame()
|
|
||||||
if self.clear then
|
|
||||||
self.roll_frames = self.roll_frames + 1
|
|
||||||
if self.roll_frames < 0 then
|
|
||||||
if self.roll_frames + 1 == 0 then
|
|
||||||
switchBGM("credit_roll", "gm3")
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
elseif self.roll_frames > 3238 then
|
|
||||||
switchBGM(nil)
|
|
||||||
if self.grade ~= 20 then self.grade = self.grade + 1 end
|
|
||||||
self.completed = true
|
|
||||||
end
|
|
||||||
elseif self.ready_frames == 0 then
|
|
||||||
self.frames = self.frames + 1
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalCKGame:onPieceEnter()
|
|
||||||
if (self.level % 100 ~= 99) and not self.clear and self.frames ~= 0 then
|
|
||||||
self.level = self.level + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalCKGame:onLineClear(cleared_row_count)
|
|
||||||
if not self.clear then
|
|
||||||
local new_level = self.level + cleared_row_count * 2
|
|
||||||
self:updateSectionTimes(self.level, new_level)
|
|
||||||
if new_level >= 2500 or self:hitTorikan(self.level, new_level) then
|
|
||||||
self.clear = true
|
|
||||||
if new_level >= 2500 then
|
|
||||||
self.level = 2500
|
|
||||||
self.grid:clear()
|
|
||||||
self.big_mode = true
|
|
||||||
self.roll_frames = -150
|
|
||||||
end
|
|
||||||
else
|
|
||||||
self.level = math.min(new_level, 2500)
|
|
||||||
end
|
|
||||||
self:advanceBottomRow(-cleared_row_count)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalCKGame:onPieceLock(piece, cleared_row_count)
|
|
||||||
if cleared_row_count == 0 then self:advanceBottomRow(1) end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalCKGame:updateScore(level, drop_bonus, cleared_lines)
|
|
||||||
if cleared_lines > 0 then
|
|
||||||
self.score = self.score + (
|
|
||||||
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
|
||||||
cleared_lines * (cleared_lines * 2 - 1) * (self.combo * 2 - 1)
|
|
||||||
)
|
|
||||||
self.lines = self.lines + cleared_lines
|
|
||||||
self.combo = self.combo + cleared_lines - 1
|
|
||||||
else
|
|
||||||
self.drop_bonus = 0
|
|
||||||
self.combo = 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalCKGame:updateSectionTimes(old_level, new_level)
|
|
||||||
if math.floor(old_level / 100) < math.floor(new_level / 100) then
|
|
||||||
local section = math.floor(old_level / 100) + 1
|
|
||||||
section_time = self.frames - self.section_start_time
|
|
||||||
table.insert(self.section_times, section_time)
|
|
||||||
self.section_start_time = self.frames
|
|
||||||
if section_time <= self:getRegretTime(self.level) then
|
|
||||||
self.grade = self.grade + 1
|
|
||||||
else
|
|
||||||
self.coolregret_message = "REGRET!!"
|
|
||||||
self.coolregret_timer = 300
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalCKGame:advanceBottomRow(dx)
|
|
||||||
if self.level >= 1000 and self.level < 1500 then
|
|
||||||
self.garbage = math.max(self.garbage + dx, 0)
|
|
||||||
if self.garbage >= self:getGarbageLimit() then
|
|
||||||
self.grid:copyBottomRow()
|
|
||||||
self.garbage = 0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalCKGame:drawGrid()
|
|
||||||
if self.level >= 1500 and self.level < 1600 then
|
|
||||||
self.grid:drawInvisible(self.rollOpacityFunction1)
|
|
||||||
elseif self.level >= 1600 and self.level < 1700 then
|
|
||||||
self.grid:drawInvisible(self.rollOpacityFunction2)
|
|
||||||
elseif self.level >= 1700 and self.level < 1800 then
|
|
||||||
self.grid:drawInvisible(self.rollOpacityFunction3)
|
|
||||||
elseif self.level >= 1800 and self.level < 1900 then
|
|
||||||
self.grid:drawInvisible(self.rollOpacityFunction4)
|
|
||||||
elseif self.level >= 1900 and self.level < 2000 then
|
|
||||||
self.grid:drawInvisible(self.rollOpacityFunction5)
|
|
||||||
else
|
|
||||||
self.grid:draw()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
-- screw trying to make this work efficiently
|
|
||||||
-- lua function variables are so garbage
|
|
||||||
|
|
||||||
SurvivalCKGame.rollOpacityFunction1 = function(age)
|
|
||||||
if age < 420 then return 1
|
|
||||||
elseif age > 480 then return 0
|
|
||||||
else return 1 - (age - 420) / 60 end
|
|
||||||
end
|
|
||||||
|
|
||||||
SurvivalCKGame.rollOpacityFunction2 = function(age)
|
|
||||||
if age < 360 then return 1
|
|
||||||
elseif age > 420 then return 0
|
|
||||||
else return 1 - (age - 360) / 60 end
|
|
||||||
end
|
|
||||||
|
|
||||||
SurvivalCKGame.rollOpacityFunction3 = function(age)
|
|
||||||
if age < 300 then return 1
|
|
||||||
elseif age > 360 then return 0
|
|
||||||
else return 1 - (age - 300) / 60 end
|
|
||||||
end
|
|
||||||
|
|
||||||
SurvivalCKGame.rollOpacityFunction4 = function(age)
|
|
||||||
if age < 240 then return 1
|
|
||||||
elseif age > 300 then return 0
|
|
||||||
else return 1 - (age - 240) / 60 end
|
|
||||||
end
|
|
||||||
|
|
||||||
SurvivalCKGame.rollOpacityFunction5 = function(age)
|
|
||||||
if age < 180 then return 1
|
|
||||||
elseif age > 240 then return 0
|
|
||||||
else return 1 - (age - 180) / 60 end
|
|
||||||
end
|
|
||||||
|
|
||||||
local master_grades = { "M", "MK", "MV", "MO", "MM" }
|
|
||||||
|
|
||||||
function SurvivalCKGame:getLetterGrade()
|
|
||||||
if self.grade == 0 then
|
|
||||||
return "1"
|
|
||||||
elseif self.grade < 10 then
|
|
||||||
return "S" .. tostring(self.grade)
|
|
||||||
elseif self.grade < 21 then
|
|
||||||
return "m" .. tostring(self.grade - 9)
|
|
||||||
elseif self.grade < 26 then
|
|
||||||
return master_grades[self.grade - 20]
|
|
||||||
else
|
|
||||||
return "GM"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalCKGame:drawScoringInfo()
|
|
||||||
SurvivalCKGame.super.drawScoringInfo(self)
|
|
||||||
|
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
|
||||||
|
|
||||||
local text_x = config["side_next"] and 320 or 240
|
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_2)
|
|
||||||
love.graphics.printf("GRADE", text_x, 120, 40, "left")
|
|
||||||
love.graphics.printf("SCORE", text_x, 200, 40, "left")
|
|
||||||
love.graphics.printf("LEVEL", text_x, 320, 40, "left")
|
|
||||||
|
|
||||||
if (self.coolregret_timer > 0) then
|
|
||||||
love.graphics.printf(self.coolregret_message, 64, 400, 160, "center")
|
|
||||||
self.coolregret_timer = self.coolregret_timer - 1
|
|
||||||
end
|
|
||||||
|
|
||||||
local current_section = math.floor(self.level / 100) + 1
|
|
||||||
self:drawSectionTimesWithSplits(current_section)
|
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
|
||||||
love.graphics.printf(self:getLetterGrade(self.grade), text_x, 140, 90, "left")
|
|
||||||
love.graphics.printf(self.score, text_x, 220, 90, "left")
|
|
||||||
love.graphics.printf(self.level, text_x, 340, 50, "right")
|
|
||||||
if self.clear then
|
|
||||||
love.graphics.printf(self.level, text_x, 370, 50, "right")
|
|
||||||
else
|
|
||||||
love.graphics.printf(math.floor(self.level / 100 + 1) * 100, text_x, 370, 50, "right")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalCKGame:getHighscoreData()
|
|
||||||
return {
|
|
||||||
grade = self.grade,
|
|
||||||
level = self.level,
|
|
||||||
frames = self.frames,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalCKGame:getSectionEndLevel()
|
|
||||||
return math.floor(self.level / 100 + 1) * 100
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalCKGame:getBackground()
|
|
||||||
return math.min(math.floor(self.level / 100), 19)
|
|
||||||
end
|
|
||||||
|
|
||||||
return SurvivalCKGame
|
|
|
@ -1,265 +0,0 @@
|
||||||
require 'funcs'
|
|
||||||
|
|
||||||
local GameMode = require 'tetris.modes.gamemode'
|
|
||||||
local Piece = require 'tetris.components.piece'
|
|
||||||
|
|
||||||
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
|
||||||
|
|
||||||
local DemonModeGame = GameMode:extend()
|
|
||||||
|
|
||||||
DemonModeGame.name = "Demon Mode"
|
|
||||||
DemonModeGame.hash = "DemonMode"
|
|
||||||
DemonModeGame.tagline = "Can you handle the ludicrous speed past level 20?"
|
|
||||||
|
|
||||||
function DemonModeGame:new()
|
|
||||||
DemonModeGame.super:new()
|
|
||||||
self.roll_frames = 0
|
|
||||||
self.combo = 1
|
|
||||||
self.randomizer = History6RollsRandomizer()
|
|
||||||
|
|
||||||
self.grade = 0
|
|
||||||
self.section_start_time = 0
|
|
||||||
self.section_times = { [0] = 0 }
|
|
||||||
self.section_tetris_count = 0
|
|
||||||
self.section_tries = 0
|
|
||||||
|
|
||||||
self.enable_hold = true
|
|
||||||
self.lock_drop = true
|
|
||||||
self.next_queue_length = 3
|
|
||||||
if math.random() < 1/6.66 then
|
|
||||||
self.rpc_details = "Suffering"
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function DemonModeGame:getARE()
|
|
||||||
if self.level < 500 then return 30
|
|
||||||
elseif self.level < 600 then return 25
|
|
||||||
elseif self.level < 700 then return 15
|
|
||||||
elseif self.level < 800 then return 14
|
|
||||||
elseif self.level < 900 then return 12
|
|
||||||
elseif self.level < 1000 then return 11
|
|
||||||
elseif self.level < 1100 then return 10
|
|
||||||
elseif self.level < 1300 then return 8
|
|
||||||
elseif self.level < 1400 then return 6
|
|
||||||
elseif self.level < 1700 then return 4
|
|
||||||
elseif self.level < 1800 then return 3
|
|
||||||
elseif self.level < 1900 then return 2
|
|
||||||
elseif self.level < 2000 then return 1
|
|
||||||
else return 0 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function DemonModeGame:getLineARE()
|
|
||||||
return self:getARE()
|
|
||||||
end
|
|
||||||
|
|
||||||
function DemonModeGame:getDasLimit()
|
|
||||||
if self.level < 500 then return 15
|
|
||||||
elseif self.level < 1000 then return 10
|
|
||||||
elseif self.level < 1500 then return 5
|
|
||||||
elseif self.level < 1700 then return 4
|
|
||||||
elseif self.level < 1900 then return 3
|
|
||||||
elseif self.level < 2000 then return 2
|
|
||||||
else return 1 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function DemonModeGame:getLineClearDelay()
|
|
||||||
if self.level < 600 then return 15
|
|
||||||
elseif self.level < 800 then return 10
|
|
||||||
elseif self.level < 1000 then return 8
|
|
||||||
elseif self.level < 1500 then return 5
|
|
||||||
elseif self.level < 1700 then return 3
|
|
||||||
elseif self.level < 1900 then return 2
|
|
||||||
elseif self.level < 2000 then return 1
|
|
||||||
else return 0 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function DemonModeGame:getLockDelay()
|
|
||||||
if self.level < 100 then return 30
|
|
||||||
elseif self.level < 200 then return 25
|
|
||||||
elseif self.level < 300 then return 22
|
|
||||||
elseif self.level < 400 then return 20
|
|
||||||
elseif self.level < 1000 then return 15
|
|
||||||
elseif self.level < 1200 then return 10
|
|
||||||
elseif self.level < 1400 then return 9
|
|
||||||
elseif self.level < 1500 then return 8
|
|
||||||
elseif self.level < 1600 then return 7
|
|
||||||
elseif self.level < 1700 then return 6
|
|
||||||
elseif self.level < 1800 then return 5
|
|
||||||
elseif self.level < 1900 then return 4
|
|
||||||
elseif self.level < 2000 then return 3
|
|
||||||
else return 2 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function DemonModeGame:getGravity()
|
|
||||||
return 20
|
|
||||||
end
|
|
||||||
|
|
||||||
local function getSectionForLevel(level)
|
|
||||||
return math.floor(level / 100) + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
local cleared_row_levels = {1, 3, 6, 10}
|
|
||||||
|
|
||||||
function DemonModeGame:advanceOneFrame()
|
|
||||||
if self.clear then
|
|
||||||
self.roll_frames = self.roll_frames + 1
|
|
||||||
if self.roll_frames < 0 then
|
|
||||||
return false
|
|
||||||
elseif self.roll_frames >= 1337 then
|
|
||||||
self.completed = true
|
|
||||||
end
|
|
||||||
elseif self.ready_frames == 0 then
|
|
||||||
self.frames = self.frames + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function DemonModeGame:onPieceEnter()
|
|
||||||
if (self.level % 100 ~= 99) and self.frames ~= 0 then
|
|
||||||
self.level = self.level + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function DemonModeGame:onLineClear(cleared_row_count)
|
|
||||||
if cleared_row_count == 4 then
|
|
||||||
self.section_tetris_count = self.section_tetris_count + 1
|
|
||||||
end
|
|
||||||
local advanced_levels = cleared_row_levels[cleared_row_count]
|
|
||||||
if not self.clear then
|
|
||||||
self:updateSectionTimes(self.level, self.level + advanced_levels)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function DemonModeGame:updateSectionTimes(old_level, new_level)
|
|
||||||
local section = math.floor(old_level / 100) + 1
|
|
||||||
if math.floor(old_level / 100) < math.floor(new_level / 100) then
|
|
||||||
-- If at least one Tetris in this section hasn't been made,
|
|
||||||
-- deny section passage.
|
|
||||||
if old_level > 500 then
|
|
||||||
if self.section_tetris_count == 0 then
|
|
||||||
self.level = 100 * math.floor(old_level / 100)
|
|
||||||
self.section_tries = self.section_tries + 1
|
|
||||||
else
|
|
||||||
self.level = math.min(new_level, 2500)
|
|
||||||
-- if this is first try (no denials, add a grade)
|
|
||||||
if self.section_tries == 0 then
|
|
||||||
self.grade = self.grade + 1
|
|
||||||
end
|
|
||||||
self.section_tries = 0
|
|
||||||
self.section_tetris_count = 0
|
|
||||||
-- record new section
|
|
||||||
section_time = self.frames - self.section_start_time
|
|
||||||
table.insert(self.section_times, section_time)
|
|
||||||
self.section_start_time = self.frames
|
|
||||||
-- maybe clear
|
|
||||||
if self.level == 2500 and not self.clear then
|
|
||||||
self.clear = true
|
|
||||||
self.grid:clear()
|
|
||||||
self.roll_frames = -150
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elseif old_level < 100 then
|
|
||||||
-- If section time is under cutoff, skip to level 500.
|
|
||||||
if self.frames < frameTime(1,00) then
|
|
||||||
self.level = 500
|
|
||||||
self.grade = 5
|
|
||||||
self.section_tries = 0
|
|
||||||
self.section_tetris_count = 0
|
|
||||||
else
|
|
||||||
self.level = math.min(new_level, 2500)
|
|
||||||
self.skip_failed = true
|
|
||||||
end
|
|
||||||
-- record new section
|
|
||||||
section_time = self.frames - self.section_start_time
|
|
||||||
table.insert(self.section_times, section_time)
|
|
||||||
self.section_start_time = self.frames
|
|
||||||
else
|
|
||||||
self.level = math.min(new_level, 2500)
|
|
||||||
if self.skip_failed and new_level >= 500 then
|
|
||||||
self.level = 500
|
|
||||||
self.game_over = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
self.level = math.min(new_level, 2500)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function DemonModeGame:updateScore(level, drop_bonus, cleared_lines)
|
|
||||||
if cleared_lines > 0 then
|
|
||||||
self.score = self.score + (
|
|
||||||
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
|
||||||
cleared_lines * (cleared_lines * 2 - 1) * (self.combo * 2 - 1)
|
|
||||||
)
|
|
||||||
self.lines = self.lines + cleared_lines
|
|
||||||
self.combo = self.combo + cleared_lines - 1
|
|
||||||
else
|
|
||||||
self.drop_bonus = 0
|
|
||||||
self.combo = 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local letter_grades = {
|
|
||||||
[0] = "", "D", "C", "B", "A",
|
|
||||||
"S", "S-A", "S-B", "S-C", "S-D",
|
|
||||||
"X", "X-A", "X-B", "X-C", "X-D",
|
|
||||||
"W", "W-A", "W-B", "W-C", "W-D",
|
|
||||||
"Master", "MasterS", "MasterX", "MasterW", "Grand Master",
|
|
||||||
"Demon Master"
|
|
||||||
}
|
|
||||||
|
|
||||||
function DemonModeGame:getLetterGrade()
|
|
||||||
return letter_grades[self.grade]
|
|
||||||
end
|
|
||||||
|
|
||||||
function DemonModeGame:drawGrid()
|
|
||||||
if self.clear and not (self.completed or self.game_over) then
|
|
||||||
self.grid:drawInvisible(self.rollOpacityFunction)
|
|
||||||
else
|
|
||||||
self.grid:draw()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
DemonModeGame.rollOpacityFunction = function(age)
|
|
||||||
if age > 4 then return 0
|
|
||||||
else return 1 - age / 4 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function DemonModeGame:drawScoringInfo()
|
|
||||||
DemonModeGame.super.drawScoringInfo(self)
|
|
||||||
|
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_2)
|
|
||||||
love.graphics.print(
|
|
||||||
self.das.direction .. " " ..
|
|
||||||
self.das.frames .. " " ..
|
|
||||||
strTrueValues(self.prev_inputs)
|
|
||||||
)
|
|
||||||
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
|
||||||
if self.grade ~= 0 then love.graphics.printf("GRADE", 240, 120, 40, "left") end
|
|
||||||
love.graphics.printf("SCORE", 240, 200, 40, "left")
|
|
||||||
love.graphics.printf("LEVEL", 240, 320, 40, "left")
|
|
||||||
|
|
||||||
-- draw section time data
|
|
||||||
local current_section = getSectionForLevel(self.level)
|
|
||||||
self:drawSectionTimesWithSecondary(current_section)
|
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
|
||||||
love.graphics.printf(self.score, 240, 220, 90, "left")
|
|
||||||
love.graphics.printf(self:getLetterGrade(), 240, 140, 90, "left")
|
|
||||||
love.graphics.printf(string.format("%.2f", self.level / 100), 240, 340, 70, "right")
|
|
||||||
end
|
|
||||||
|
|
||||||
function DemonModeGame:getHighscoreData()
|
|
||||||
return {
|
|
||||||
grade = self.grade,
|
|
||||||
level = self.level,
|
|
||||||
frames = self.frames,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
function DemonModeGame:getBackground()
|
|
||||||
return math.min(math.floor(self.level / 100), 19)
|
|
||||||
end
|
|
||||||
|
|
||||||
return DemonModeGame
|
|
|
@ -389,7 +389,8 @@ function GameMode:drawNextQueue(ruleset)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if self.hold_queue ~= nil then
|
if self.hold_queue ~= nil then
|
||||||
self:setHoldOpacity()
|
local hold_color = self.held and 0.6 or 1
|
||||||
|
self:setHoldOpacity(1, hold_color)
|
||||||
drawPiece(
|
drawPiece(
|
||||||
self.hold_queue.shape,
|
self.hold_queue.shape,
|
||||||
self.hold_queue.skin,
|
self.hold_queue.skin,
|
||||||
|
@ -400,8 +401,16 @@ function GameMode:drawNextQueue(ruleset)
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
function GameMode:setNextOpacity(i) love.graphics.setColor(1, 1, 1, 1) end
|
function GameMode:setNextOpacity(i, j)
|
||||||
function GameMode:setHoldOpacity() love.graphics.setColor(1, 1, 1, 1) end
|
i = i ~= nil and i or 1
|
||||||
|
j = j ~= nil and j or 1
|
||||||
|
love.graphics.setColor(j, j, j, i)
|
||||||
|
end
|
||||||
|
function GameMode:setHoldOpacity(i, j)
|
||||||
|
i = i ~= nil and i or 1
|
||||||
|
j = j ~= nil and j or 1
|
||||||
|
love.graphics.setColor(j, j, j, i)
|
||||||
|
end
|
||||||
|
|
||||||
function GameMode:drawScoringInfo()
|
function GameMode:drawScoringInfo()
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
|
|
|
@ -1,155 +0,0 @@
|
||||||
require 'funcs'
|
|
||||||
|
|
||||||
local GameMode = require 'tetris.modes.gamemode'
|
|
||||||
local Piece = require 'tetris.components.piece'
|
|
||||||
|
|
||||||
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
|
||||||
|
|
||||||
local IntervalTrainingGame = GameMode:extend()
|
|
||||||
|
|
||||||
IntervalTrainingGame.name = "Interval Training"
|
|
||||||
IntervalTrainingGame.hash = "IntervalTraining"
|
|
||||||
IntervalTrainingGame.tagline = "Can you clear the time hurdles when the game goes this fast?"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function IntervalTrainingGame:new()
|
|
||||||
IntervalTrainingGame.super:new()
|
|
||||||
self.roll_frames = 0
|
|
||||||
self.combo = 1
|
|
||||||
self.randomizer = History6RollsRandomizer()
|
|
||||||
self.section_time_limit = 1800
|
|
||||||
self.section_start_time = 0
|
|
||||||
self.section_times = { [0] = 0 }
|
|
||||||
self.lock_drop = true
|
|
||||||
self.enable_hold = true
|
|
||||||
self.next_queue_length = 3
|
|
||||||
end
|
|
||||||
|
|
||||||
function IntervalTrainingGame:getARE()
|
|
||||||
return 4
|
|
||||||
end
|
|
||||||
|
|
||||||
function IntervalTrainingGame:getLineARE()
|
|
||||||
return 4
|
|
||||||
end
|
|
||||||
|
|
||||||
function IntervalTrainingGame:getDasLimit()
|
|
||||||
return 6
|
|
||||||
end
|
|
||||||
|
|
||||||
function IntervalTrainingGame:getLineClearDelay()
|
|
||||||
return 6
|
|
||||||
end
|
|
||||||
|
|
||||||
function IntervalTrainingGame:getLockDelay()
|
|
||||||
return 15
|
|
||||||
end
|
|
||||||
|
|
||||||
function IntervalTrainingGame:getGravity()
|
|
||||||
return 20
|
|
||||||
end
|
|
||||||
|
|
||||||
function IntervalTrainingGame:getSection()
|
|
||||||
return math.floor(level / 100) + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
function IntervalTrainingGame:advanceOneFrame()
|
|
||||||
if self.clear then
|
|
||||||
self.roll_frames = self.roll_frames + 1
|
|
||||||
if self.roll_frames > 2968 then
|
|
||||||
self.completed = true
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
elseif self.ready_frames == 0 then
|
|
||||||
self.frames = self.frames + 1
|
|
||||||
if self:getSectionTime() >= self.section_time_limit then
|
|
||||||
self.game_over = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
function IntervalTrainingGame:onPieceEnter()
|
|
||||||
if (self.level % 100 ~= 99 or self.level == 998) and not self.clear and self.frames ~= 0 then
|
|
||||||
self.level = self.level + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function IntervalTrainingGame:onLineClear(cleared_row_count)
|
|
||||||
if not self.clear then
|
|
||||||
local new_level = self.level + cleared_row_count
|
|
||||||
self:updateSectionTimes(self.level, new_level)
|
|
||||||
self.level = math.min(new_level, 999)
|
|
||||||
if self.level == 999 then
|
|
||||||
self.clear = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function IntervalTrainingGame:getSectionTime()
|
|
||||||
return self.frames - self.section_start_time
|
|
||||||
end
|
|
||||||
|
|
||||||
function IntervalTrainingGame:updateSectionTimes(old_level, new_level)
|
|
||||||
if math.floor(old_level / 100) < math.floor(new_level / 100) then
|
|
||||||
-- record new section
|
|
||||||
table.insert(self.section_times, self:getSectionTime())
|
|
||||||
self.section_start_time = self.frames
|
|
||||||
else
|
|
||||||
self.level = math.min(new_level, 999)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function IntervalTrainingGame:drawGrid(ruleset)
|
|
||||||
self.grid:draw()
|
|
||||||
end
|
|
||||||
|
|
||||||
function IntervalTrainingGame:getHighscoreData()
|
|
||||||
return {
|
|
||||||
level = self.level,
|
|
||||||
frames = self.frames,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
function IntervalTrainingGame:drawScoringInfo()
|
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_2)
|
|
||||||
love.graphics.print(
|
|
||||||
self.das.direction .. " " ..
|
|
||||||
self.das.frames .. " " ..
|
|
||||||
strTrueValues(self.prev_inputs)
|
|
||||||
)
|
|
||||||
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
|
||||||
love.graphics.printf("TIME LEFT", 240, 250, 80, "left")
|
|
||||||
love.graphics.printf("LEVEL", 240, 320, 40, "left")
|
|
||||||
|
|
||||||
local current_section = math.floor(self.level / 100) + 1
|
|
||||||
self:drawSectionTimesWithSplits(current_section)
|
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
|
||||||
love.graphics.printf(self.level, 240, 340, 40, "right")
|
|
||||||
|
|
||||||
-- draw time left, flash red if necessary
|
|
||||||
local time_left = self.section_time_limit - math.max(self:getSectionTime(), 0)
|
|
||||||
if not self.game_over and not self.clear and time_left < frameTime(0,10) and time_left % 4 < 2 then
|
|
||||||
love.graphics.setColor(1, 0.3, 0.3, 1)
|
|
||||||
end
|
|
||||||
love.graphics.printf(formatTime(time_left), 240, 270, 160, "left")
|
|
||||||
|
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
|
||||||
love.graphics.printf(self:getSectionEndLevel(), 240, 370, 40, "right")
|
|
||||||
end
|
|
||||||
|
|
||||||
function IntervalTrainingGame:getSectionEndLevel()
|
|
||||||
if self.level >= 900 then return 999
|
|
||||||
else return math.floor(self.level / 100 + 1) * 100 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function IntervalTrainingGame:getBackground()
|
|
||||||
return math.floor(self.level / 100)
|
|
||||||
end
|
|
||||||
|
|
||||||
return IntervalTrainingGame
|
|
|
@ -1,190 +0,0 @@
|
||||||
require 'funcs'
|
|
||||||
|
|
||||||
local GameMode = require 'tetris.modes.gamemode'
|
|
||||||
local Piece = require 'tetris.components.piece'
|
|
||||||
|
|
||||||
local KonohaRandomizer = require 'tetris.randomizers.bag_konoha'
|
|
||||||
|
|
||||||
local KonohaGame = GameMode:extend()
|
|
||||||
|
|
||||||
KonohaGame.name = "All Clear A4"
|
|
||||||
KonohaGame.hash = "AllClearA4"
|
|
||||||
KonohaGame.tagline = "Get as many bravos as you can under the time limit!"
|
|
||||||
|
|
||||||
function KonohaGame:new()
|
|
||||||
KonohaGame.super:new()
|
|
||||||
|
|
||||||
self.randomizer = KonohaRandomizer()
|
|
||||||
self.bravos = 0
|
|
||||||
self.last_bonus_amount = 0
|
|
||||||
self.last_bonus_display_time = 0
|
|
||||||
self.time_limit = 10800
|
|
||||||
self.big_mode = true
|
|
||||||
|
|
||||||
self.enable_hold = true
|
|
||||||
self.next_queue_length = 3
|
|
||||||
end
|
|
||||||
|
|
||||||
function KonohaGame:getARE()
|
|
||||||
if self.level < 300 then return 30
|
|
||||||
elseif self.level < 400 then return 25
|
|
||||||
elseif self.level < 500 then return 20
|
|
||||||
elseif self.level < 600 then return 17
|
|
||||||
elseif self.level < 800 then return 15
|
|
||||||
elseif self.level < 900 then return 13
|
|
||||||
elseif self.level < 1000 then return 10
|
|
||||||
elseif self.level < 1300 then return 8
|
|
||||||
else return 6 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function KonohaGame:getLineARE()
|
|
||||||
return self:getARE()
|
|
||||||
end
|
|
||||||
|
|
||||||
function KonohaGame:getDasLimit()
|
|
||||||
if self.level < 500 then return 10
|
|
||||||
elseif self.level < 800 then return 9
|
|
||||||
elseif self.level < 1000 then return 8
|
|
||||||
else return 7 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function KonohaGame:getLineClearDelay()
|
|
||||||
if self.level < 200 then return 14
|
|
||||||
elseif self.level < 500 then return 9
|
|
||||||
elseif self.level < 800 then return 8
|
|
||||||
elseif self.level < 1000 then return 7
|
|
||||||
else return 6 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function KonohaGame:getLockDelay()
|
|
||||||
if self.level < 500 then return 30
|
|
||||||
elseif self.level < 600 then return 25
|
|
||||||
elseif self.level < 700 then return 23
|
|
||||||
elseif self.level < 800 then return 20
|
|
||||||
elseif self.level < 900 then return 17
|
|
||||||
elseif self.level < 1000 then return 15
|
|
||||||
elseif self.level < 1200 then return 13
|
|
||||||
elseif self.level < 1300 then return 10
|
|
||||||
else return 8 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function KonohaGame:getGravity()
|
|
||||||
if (self.level < 30) then return 4/256
|
|
||||||
elseif (self.level < 35) then return 8/256
|
|
||||||
elseif (self.level < 40) then return 12/256
|
|
||||||
elseif (self.level < 50) then return 16/256
|
|
||||||
elseif (self.level < 60) then return 32/256
|
|
||||||
elseif (self.level < 70) then return 48/256
|
|
||||||
elseif (self.level < 80) then return 64/256
|
|
||||||
elseif (self.level < 90) then return 128/256
|
|
||||||
elseif (self.level < 100) then return 192/256
|
|
||||||
elseif (self.level < 120) then return 1
|
|
||||||
elseif (self.level < 140) then return 2
|
|
||||||
elseif (self.level < 160) then return 3
|
|
||||||
elseif (self.level < 170) then return 4
|
|
||||||
elseif (self.level < 200) then return 5
|
|
||||||
else return 20 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function KonohaGame:getSection()
|
|
||||||
return math.floor(level / 100) + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
function KonohaGame:getSectionEndLevel()
|
|
||||||
return math.floor(self.level / 100 + 1) * 100
|
|
||||||
end
|
|
||||||
|
|
||||||
function KonohaGame:advanceOneFrame()
|
|
||||||
if self.ready_frames == 0 then
|
|
||||||
self.time_limit = self.time_limit - 1
|
|
||||||
self.frames = self.frames + 1
|
|
||||||
end
|
|
||||||
if self.time_limit <= 0 then
|
|
||||||
self.game_over = true
|
|
||||||
end
|
|
||||||
self.last_bonus_display_time = self.last_bonus_display_time - 1
|
|
||||||
end
|
|
||||||
|
|
||||||
function KonohaGame:onPieceEnter()
|
|
||||||
if (self.level % 100 ~= 99) and self.frames ~= 0 then
|
|
||||||
self.level = self.level + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function KonohaGame:drawGrid(ruleset)
|
|
||||||
self.grid:draw()
|
|
||||||
if self.piece ~= nil and self.level < 100 then
|
|
||||||
self:drawGhostPiece(ruleset)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local cleared_row_levels = {2, 4, 6, 12}
|
|
||||||
local bravo_bonus = {300, 480, 660, 900}
|
|
||||||
local non_bravo_bonus = {0, 0, 20, 40}
|
|
||||||
local bravo_ot_bonus = {0, 60, 120, 180}
|
|
||||||
|
|
||||||
function KonohaGame:onLineClear(cleared_row_count)
|
|
||||||
local oldtime = self.time_limit
|
|
||||||
|
|
||||||
self.level = self.level + cleared_row_levels[cleared_row_count / 2]
|
|
||||||
if self.grid:checkForBravo(cleared_row_count) then
|
|
||||||
self.bravos = self.bravos + 1
|
|
||||||
if self.level < 1000 then self.time_limit = self.time_limit + bravo_bonus[cleared_row_count / 2]
|
|
||||||
else self.time_limit = self.time_limit + bravo_ot_bonus[cleared_row_count / 2]
|
|
||||||
end
|
|
||||||
if self.bravos == 11 then self.randomizer.allowrepeat = true end
|
|
||||||
elseif self.level < 1000 then
|
|
||||||
self.time_limit = self.time_limit + non_bravo_bonus[cleared_row_count / 2]
|
|
||||||
end
|
|
||||||
|
|
||||||
local bonus = self.time_limit - oldtime
|
|
||||||
if bonus > 0 then
|
|
||||||
self.last_bonus_amount = bonus
|
|
||||||
self.last_bonus_display_time = 120
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function KonohaGame:getBackground()
|
|
||||||
return math.floor(self.level / 100)
|
|
||||||
end
|
|
||||||
|
|
||||||
function KonohaGame:drawScoringInfo()
|
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_2)
|
|
||||||
love.graphics.print(
|
|
||||||
self.das.direction .. " " ..
|
|
||||||
self.das.frames .. " " ..
|
|
||||||
strTrueValues(self.prev_inputs)
|
|
||||||
)
|
|
||||||
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
|
||||||
love.graphics.printf("TIME LIMIT", 240, 120, 120, "left")
|
|
||||||
love.graphics.printf("BRAVOS", 240, 200, 50, "left")
|
|
||||||
love.graphics.printf("LEVEL", 240, 320, 40, "left")
|
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
|
||||||
if not self.game_over and self.time_limit < frameTime(0,10) and self.time_limit % 4 < 2 then
|
|
||||||
love.graphics.setColor(1, 0.3, 0.3, 1)
|
|
||||||
end
|
|
||||||
love.graphics.printf(formatTime(self.time_limit), 240, 140, 120, "right")
|
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
|
||||||
if self.last_bonus_display_time > 0 then
|
|
||||||
love.graphics.printf("+"..formatTime(self.last_bonus_amount), 240, 160, 120, "right")
|
|
||||||
end
|
|
||||||
love.graphics.printf(self.bravos, 240, 220, 90, "left")
|
|
||||||
love.graphics.printf(self.level, 240, 340, 50, "right")
|
|
||||||
love.graphics.printf(self:getSectionEndLevel(), 240, 370, 50, "right")
|
|
||||||
|
|
||||||
love.graphics.setFont(font_8x11)
|
|
||||||
love.graphics.printf(formatTime(self.frames), 64, 420, 160, "center")
|
|
||||||
end
|
|
||||||
|
|
||||||
function KonohaGame:getHighscoreData()
|
|
||||||
return {
|
|
||||||
bravos = self.bravos,
|
|
||||||
level = self.level,
|
|
||||||
frames = self.frames,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
return KonohaGame
|
|
|
@ -36,6 +36,8 @@ function Marathon2020Game:new()
|
||||||
self.grade_points = 0
|
self.grade_points = 0
|
||||||
self.grade_point_decay_counter = 0
|
self.grade_point_decay_counter = 0
|
||||||
self.max_grade_points = 0
|
self.max_grade_points = 0
|
||||||
|
|
||||||
|
self.cool_timer = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
function Marathon2020Game:getARE()
|
function Marathon2020Game:getARE()
|
||||||
|
@ -327,6 +329,7 @@ function Marathon2020Game:updateSectionTimes(old_level, new_level)
|
||||||
self.section_cool_count = self.section_cool_count + 1
|
self.section_cool_count = self.section_cool_count + 1
|
||||||
self.delay_level = math.min(20, self.delay_level + 1)
|
self.delay_level = math.min(20, self.delay_level + 1)
|
||||||
table.insert(self.section_status, "cool")
|
table.insert(self.section_status, "cool")
|
||||||
|
self.cool_timer = 300
|
||||||
end
|
end
|
||||||
|
|
||||||
local section = getSectionForLevel(old_level)
|
local section = getSectionForLevel(old_level)
|
||||||
|
@ -430,6 +433,11 @@ function Marathon2020Game:drawScoringInfo()
|
||||||
|
|
||||||
self:drawSectionTimesWithSecondary(current_section)
|
self:drawSectionTimesWithSecondary(current_section)
|
||||||
|
|
||||||
|
if (self.cool_timer > 0) then
|
||||||
|
love.graphics.printf("COOL!!", 64, 400, 160, "center")
|
||||||
|
self.cool_timer = self.cool_timer - 1
|
||||||
|
end
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
love.graphics.setFont(font_3x5_3)
|
||||||
love.graphics.printf(self:getTotalGrade(), text_x, 120, 90, "left")
|
love.graphics.printf(self:getTotalGrade(), text_x, 120, 90, "left")
|
||||||
love.graphics.printf(self.grade_points, text_x, 220, 90, "left")
|
love.graphics.printf(self.grade_points, text_x, 220, 90, "left")
|
||||||
|
|
|
@ -137,15 +137,15 @@ function MarathonA1Game:onLineClear(cleared_row_count)
|
||||||
self:checkGMRequirements(self.level, self.level + cleared_row_count)
|
self:checkGMRequirements(self.level, self.level + cleared_row_count)
|
||||||
if not self.clear then
|
if not self.clear then
|
||||||
local new_level = math.min(self.level + cleared_row_count, 999)
|
local new_level = math.min(self.level + cleared_row_count, 999)
|
||||||
if self.level == 999 then
|
if new_level == 999 then
|
||||||
self.clear = true
|
self.clear = true
|
||||||
else
|
|
||||||
self.level = new_level
|
|
||||||
end
|
end
|
||||||
|
self.level = new_level
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA1Game:updateScore(level, drop_bonus, cleared_lines)
|
function MarathonA1Game:updateScore(level, drop_bonus, cleared_lines)
|
||||||
|
if not self.clear then
|
||||||
if self.grid:checkForBravo(cleared_lines) then
|
if self.grid:checkForBravo(cleared_lines) then
|
||||||
self.bravo = 4
|
self.bravo = 4
|
||||||
self.bravos = self.bravos + 1
|
self.bravos = self.bravos + 1
|
||||||
|
@ -156,25 +156,25 @@ function MarathonA1Game:updateScore(level, drop_bonus, cleared_lines)
|
||||||
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
||||||
cleared_lines * self.combo * self.bravo
|
cleared_lines * self.combo * self.bravo
|
||||||
)
|
)
|
||||||
self.lines = self.lines + cleared_lines
|
|
||||||
else
|
else
|
||||||
self.drop_bonus = 0
|
|
||||||
self.combo = 1
|
self.combo = 1
|
||||||
end
|
end
|
||||||
|
self.drop_bonus = 0
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA1Game:checkGMRequirements(old_level, new_level)
|
function MarathonA1Game:checkGMRequirements(old_level, new_level)
|
||||||
if old_level < 300 and new_level >= 300 then
|
if old_level < 300 and new_level >= 300 then
|
||||||
if self.score > 12000 and self.frames <= frameTime(4,15) then
|
if self.score >= 12000 and self.frames <= frameTime(4,15) then
|
||||||
self.gm_conditions["level300"] = true
|
self.gm_conditions["level300"] = true
|
||||||
end
|
end
|
||||||
elseif old_level < 500 and new_level >= 500 then
|
elseif old_level < 500 and new_level >= 500 then
|
||||||
if self.score > 40000 and self.frames <= frameTime(7,30) then
|
if self.score >= 40000 and self.frames <= frameTime(7,30) then
|
||||||
self.gm_conditions["level500"] = true
|
self.gm_conditions["level500"] = true
|
||||||
end
|
end
|
||||||
elseif old_level < 999 and new_level >= 999 then
|
elseif old_level < 999 and new_level >= 999 then
|
||||||
if self.score > 126000 and self.frames <= frameTime(13,30) then
|
if self.score >= 126000 and self.frames <= frameTime(13,30) then
|
||||||
self.gm_conditions["level900"] = true
|
self.gm_conditions["level999"] = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -210,7 +210,7 @@ function MarathonA1Game:drawScoringInfo()
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
love.graphics.setFont(font_3x5_3)
|
||||||
love.graphics.printf(self.score, 240, 220, 90, "left")
|
love.graphics.printf(self.score, 240, 220, 90, "left")
|
||||||
if self.gm_conditions["level300"] and self.gm_conditions["level500"] and self.gm_conditions["level900"] then
|
if self.gm_conditions["level300"] and self.gm_conditions["level500"] and self.gm_conditions["level999"] then
|
||||||
love.graphics.printf("GM", 240, 140, 90, "left")
|
love.graphics.printf("GM", 240, 140, 90, "left")
|
||||||
else
|
else
|
||||||
love.graphics.printf(getRankForScore(self.score).rank, 240, 140, 90, "left")
|
love.graphics.printf(getRankForScore(self.score).rank, 240, 140, 90, "left")
|
||||||
|
|
|
@ -33,9 +33,8 @@ function MarathonA2Game:new()
|
||||||
"GM"
|
"GM"
|
||||||
}
|
}
|
||||||
|
|
||||||
self.randomizer = History6RollsRandomizer()
|
|
||||||
|
|
||||||
self.lock_drop = false
|
self.lock_drop = false
|
||||||
|
self.lock_hard_drop = false
|
||||||
self.enable_hold = false
|
self.enable_hold = false
|
||||||
self.next_queue_length = 1
|
self.next_queue_length = 1
|
||||||
end
|
end
|
||||||
|
@ -109,6 +108,7 @@ end
|
||||||
function MarathonA2Game:advanceOneFrame()
|
function MarathonA2Game:advanceOneFrame()
|
||||||
if self.clear then
|
if self.clear then
|
||||||
self.roll_frames = self.roll_frames + 1
|
self.roll_frames = self.roll_frames + 1
|
||||||
|
if self.roll_frames < 0 then return false end
|
||||||
if self.roll_frames > 3694 then
|
if self.roll_frames > 3694 then
|
||||||
self.completed = true
|
self.completed = true
|
||||||
if self.grade == 32 then
|
if self.grade == 32 then
|
||||||
|
@ -127,33 +127,33 @@ function MarathonA2Game:onPieceEnter()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA2Game:onLineClear(cleared_row_count)
|
|
||||||
self:updateSectionTimes(self.level, self.level + cleared_row_count)
|
|
||||||
self.level = math.min(self.level + cleared_row_count, 999)
|
|
||||||
if self.level == 999 and not self.clear then
|
|
||||||
self.clear = true
|
|
||||||
if self:qualifiesForMRoll() then
|
|
||||||
self.grade = 32
|
|
||||||
end
|
|
||||||
self.grid:clear()
|
|
||||||
self.roll_frames = -150
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonA2Game:updateScore(level, drop_bonus, cleared_lines)
|
function MarathonA2Game:updateScore(level, drop_bonus, cleared_lines)
|
||||||
|
if not self.clear then
|
||||||
self:updateGrade(cleared_lines)
|
self:updateGrade(cleared_lines)
|
||||||
if self.grid:checkForBravo(cleared_lines) then self.bravo = 4 else self.bravo = 1 end
|
if self.grid:checkForBravo(cleared_lines) then self.bravo = 4 else self.bravo = 1 end
|
||||||
if cleared_lines > 0 then
|
if cleared_lines > 0 then
|
||||||
|
self.combo = self.combo + (cleared_lines - 1) * 2
|
||||||
self.score = self.score + (
|
self.score = self.score + (
|
||||||
(math.ceil((level + cleared_lines) / 4) + 2 * drop_bonus) *
|
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
||||||
cleared_lines * self.combo * self.bravo
|
cleared_lines * self.combo * self.bravo
|
||||||
)
|
)
|
||||||
self.lines = self.lines + cleared_lines
|
|
||||||
self.combo = self.combo + (cleared_lines - 1) * 2
|
|
||||||
else
|
else
|
||||||
self.drop_bonus = 0
|
|
||||||
self.combo = 1
|
self.combo = 1
|
||||||
end
|
end
|
||||||
|
self.drop_bonus = 0
|
||||||
|
else self.lines = self.lines + cleared_lines end
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonA2Game:onLineClear(cleared_row_count)
|
||||||
|
self.level = math.min(self.level + cleared_row_count, 999)
|
||||||
|
if self.level == 999 and not self.clear then
|
||||||
|
self.clear = true
|
||||||
|
self.grid:clear()
|
||||||
|
if self:qualifiesForMRoll() then self.grade = 32 end
|
||||||
|
self.roll_frames = -150
|
||||||
|
end
|
||||||
|
self.lock_drop = self.level >= 900
|
||||||
|
self.lock_hard_drop = self.level >= 900
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA2Game:updateSectionTimes(old_level, new_level)
|
function MarathonA2Game:updateSectionTimes(old_level, new_level)
|
||||||
|
@ -253,7 +253,7 @@ function MarathonA2Game:updateGrade(cleared_lines)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local tetris_requirements = { [0] = 2, 2, 2, 2, 2, 1, 1, 1, 1, 1 }
|
local tetris_requirements = { [0] = 2, 2, 2, 2, 2, 1, 1, 1, 1, 0 }
|
||||||
|
|
||||||
function MarathonA2Game:qualifiesForMRoll()
|
function MarathonA2Game:qualifiesForMRoll()
|
||||||
if not self.clear then return false end
|
if not self.clear then return false end
|
||||||
|
@ -280,7 +280,7 @@ function MarathonA2Game:qualifiesForMRoll()
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if self.grade < 17 or self.frames > frameTime(9,30) then
|
if self.grade < 31 or self.frames > frameTime(8,45) then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
|
@ -344,7 +344,17 @@ function MarathonA2Game:drawScoringInfo()
|
||||||
end
|
end
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
love.graphics.setFont(font_3x5_3)
|
||||||
|
if self.clear then
|
||||||
|
if self:qualifiesForMRoll() then
|
||||||
|
if self.lines >= 32 and self.roll_frames > 3694 then love.graphics.setColor(1, 0.5, 0, 1)
|
||||||
|
else love.graphics.setColor(0, 1, 0, 1) end
|
||||||
|
else
|
||||||
|
if self.roll_frames > 3694 then love.graphics.setColor(1, 0.5, 0, 1)
|
||||||
|
else love.graphics.setColor(0, 1, 0, 1) end
|
||||||
|
end
|
||||||
|
end
|
||||||
love.graphics.printf(self:getLetterGrade(), 240, 140, 90, "left")
|
love.graphics.printf(self:getLetterGrade(), 240, 140, 90, "left")
|
||||||
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
love.graphics.printf(self.score, 240, 220, 90, "left")
|
love.graphics.printf(self.score, 240, 220, 90, "left")
|
||||||
love.graphics.printf(self.level, 240, 340, 40, "right")
|
love.graphics.printf(self.level, 240, 340, 40, "right")
|
||||||
love.graphics.printf(self:getSectionEndLevel(), 240, 370, 40, "right")
|
love.graphics.printf(self:getSectionEndLevel(), 240, 370, 40, "right")
|
||||||
|
|
|
@ -29,6 +29,7 @@ function MarathonA3Game:new()
|
||||||
self.section_start_time = 0
|
self.section_start_time = 0
|
||||||
self.section_70_times = { [0] = 0 }
|
self.section_70_times = { [0] = 0 }
|
||||||
self.section_times = { [0] = 0 }
|
self.section_times = { [0] = 0 }
|
||||||
|
self.section_cool = false
|
||||||
|
|
||||||
self.randomizer = History6RollsRandomizer()
|
self.randomizer = History6RollsRandomizer()
|
||||||
|
|
||||||
|
@ -45,6 +46,8 @@ self.SGnames = {
|
||||||
|
|
||||||
self.coolregret_message = "COOL!!"
|
self.coolregret_message = "COOL!!"
|
||||||
self.coolregret_timer = 0
|
self.coolregret_timer = 0
|
||||||
|
|
||||||
|
self.torikan_passed = false
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA3Game:getARE()
|
function MarathonA3Game:getARE()
|
||||||
|
@ -149,6 +152,7 @@ function MarathonA3Game:onPieceEnter()
|
||||||
self:updateSectionTimes(self.level, self.level + 1)
|
self:updateSectionTimes(self.level, self.level + 1)
|
||||||
self.level = self.level + 1
|
self.level = self.level + 1
|
||||||
self.speed_level = self.speed_level + 1
|
self.speed_level = self.speed_level + 1
|
||||||
|
self.torikan_passed = self.level >= 500 and true or false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -166,7 +170,7 @@ function MarathonA3Game:onLineClear(cleared_row_count)
|
||||||
self.grid:clear()
|
self.grid:clear()
|
||||||
self.roll_frames = -150
|
self.roll_frames = -150
|
||||||
end
|
end
|
||||||
if self.level >= 500 and self.frames >= 25200 then
|
if not self.torikan_passed and self.level >= 500 and self.frames >= 25200 then
|
||||||
self.level = 500
|
self.level = 500
|
||||||
self.game_over = true
|
self.game_over = true
|
||||||
end
|
end
|
||||||
|
@ -192,49 +196,54 @@ function MarathonA3Game:updateSectionTimes(old_level, new_level)
|
||||||
table.insert(self.section_times, section_time)
|
table.insert(self.section_times, section_time)
|
||||||
self.section_start_time = self.frames
|
self.section_start_time = self.frames
|
||||||
|
|
||||||
|
self.speed_level = self.section_cool and self.speed_level + 100 or self.speed_level
|
||||||
|
|
||||||
if section_time > regret_cutoffs[section] then
|
if section_time > regret_cutoffs[section] then
|
||||||
self.section_cool_grade = self.section_cool_grade - 1
|
self.section_cool_grade = self.section_cool_grade - 1
|
||||||
table.insert(self.section_status, "regret")
|
table.insert(self.section_status, "regret")
|
||||||
self.coolregret_message = "REGRET!!"
|
self.coolregret_message = "REGRET!!"
|
||||||
self.coolregret_timer = 300
|
self.coolregret_timer = 300
|
||||||
elseif section <= 9 and self.section_status[section - 1] == "cool" and
|
elseif self.section_cool then
|
||||||
self.section_70_times[section] < self.section_70_times[section - 1] + 120 then
|
|
||||||
self.section_cool_grade = self.section_cool_grade + 1
|
self.section_cool_grade = self.section_cool_grade + 1
|
||||||
self.speed_level = self.speed_level + 100
|
|
||||||
table.insert(self.section_status, "cool")
|
table.insert(self.section_status, "cool")
|
||||||
self.coolregret_message = "COOL!!"
|
|
||||||
self.coolregret_timer = 300
|
|
||||||
elseif self.section_status[section - 1] == "cool" then
|
|
||||||
table.insert(self.section_status, "none")
|
|
||||||
elseif section <= 9 and self.section_70_times[section] < cool_cutoffs[section] then
|
|
||||||
self.section_cool_grade = self.section_cool_grade + 1
|
|
||||||
self.speed_level = self.speed_level + 100
|
|
||||||
table.insert(self.section_status, "cool")
|
|
||||||
self.coolregret_message = "COOL!!"
|
|
||||||
self.coolregret_timer = 300
|
|
||||||
else
|
else
|
||||||
table.insert(self.section_status, "none")
|
table.insert(self.section_status, "none")
|
||||||
end
|
end
|
||||||
elseif section <= 9 and old_level % 100 < 70 and new_level % 100 >= 70 then
|
|
||||||
|
self.section_cool = false
|
||||||
|
elseif old_level % 100 < 70 and new_level % 100 >= 70 then
|
||||||
-- record section 70 time
|
-- record section 70 time
|
||||||
section_70_time = self.frames - self.section_start_time
|
section_70_time = self.frames - self.section_start_time
|
||||||
table.insert(self.section_70_times, section_70_time)
|
table.insert(self.section_70_times, section_70_time)
|
||||||
|
|
||||||
|
if section <= 9 and self.section_status[section - 1] == "cool" and
|
||||||
|
self.section_70_times[section] < self.section_70_times[section - 1] + 120 then
|
||||||
|
self.section_cool = true
|
||||||
|
self.coolregret_message = "COOL!!"
|
||||||
|
self.coolregret_timer = 300
|
||||||
|
elseif self.section_status[section - 1] == "cool" then self.section_cool = false
|
||||||
|
elseif section <= 9 and self.section_70_times[section] < cool_cutoffs[section] then
|
||||||
|
self.section_cool = true
|
||||||
|
self.coolregret_message = "COOL!!"
|
||||||
|
self.coolregret_timer = 300
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA3Game:updateScore(level, drop_bonus, cleared_lines)
|
function MarathonA3Game:updateScore(level, drop_bonus, cleared_lines)
|
||||||
|
if not self.clear then
|
||||||
self:updateGrade(cleared_lines)
|
self:updateGrade(cleared_lines)
|
||||||
if cleared_lines > 0 then
|
if cleared_lines > 0 then
|
||||||
|
self.combo = self.combo + (cleared_lines - 1) * 2
|
||||||
self.score = self.score + (
|
self.score = self.score + (
|
||||||
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
||||||
cleared_lines * (cleared_lines * 2 - 1) * (self.combo * 2 - 1)
|
cleared_lines * self.combo
|
||||||
)
|
)
|
||||||
self.lines = self.lines + cleared_lines
|
|
||||||
self.combo = self.combo + cleared_lines - 1
|
|
||||||
else
|
else
|
||||||
self.drop_bonus = 0
|
|
||||||
self.combo = 1
|
self.combo = 1
|
||||||
end
|
end
|
||||||
|
self.drop_bonus = 0
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local grade_point_bonuses = {
|
local grade_point_bonuses = {
|
||||||
|
@ -353,6 +362,8 @@ function MarathonA3Game:getLetterGrade()
|
||||||
return "M" .. tostring(grade - 17)
|
return "M" .. tostring(grade - 17)
|
||||||
elseif grade < 32 then
|
elseif grade < 32 then
|
||||||
return master_grades[grade - 26]
|
return master_grades[grade - 26]
|
||||||
|
elseif grade >= 32 and self.roll_frames < 3238 then
|
||||||
|
return "MM"
|
||||||
else
|
else
|
||||||
return "GM"
|
return "GM"
|
||||||
end
|
end
|
||||||
|
@ -427,7 +438,7 @@ function MarathonA3Game:drawScoringInfo()
|
||||||
current_x = section_70_x
|
current_x = section_70_x
|
||||||
end
|
end
|
||||||
|
|
||||||
love.graphics.printf(formatTime(self.frames - self.section_start_time), current_x, 40 + 20 * current_section, 90, "left")
|
if not self.clear then love.graphics.printf(formatTime(self.frames - self.section_start_time), current_x, 40 + 20 * current_section, 90, "left") end
|
||||||
|
|
||||||
if(self.coolregret_timer > 0) then
|
if(self.coolregret_timer > 0) then
|
||||||
love.graphics.printf(self.coolregret_message, 64, 400, 160, "center")
|
love.graphics.printf(self.coolregret_message, 64, 400, 160, "center")
|
||||||
|
@ -436,7 +447,10 @@ function MarathonA3Game:drawScoringInfo()
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
love.graphics.setFont(font_3x5_3)
|
||||||
love.graphics.printf(self.score, 240, 220, 90, "left")
|
love.graphics.printf(self.score, 240, 220, 90, "left")
|
||||||
|
if self.roll_frames > 3238 then love.graphics.setColor(1, 0.5, 0, 1)
|
||||||
|
elseif self.clear then love.graphics.setColor(0, 1, 0, 1) end
|
||||||
love.graphics.printf(self:getLetterGrade(), 240, 140, 90, "left")
|
love.graphics.printf(self:getLetterGrade(), 240, 140, 90, "left")
|
||||||
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
love.graphics.printf(self.level, 240, 340, 40, "right")
|
love.graphics.printf(self.level, 240, 340, 40, "right")
|
||||||
love.graphics.printf(self:getSectionEndLevel(), 240, 370, 40, "right")
|
love.graphics.printf(self:getSectionEndLevel(), 240, 370, 40, "right")
|
||||||
if sg >= 5 then
|
if sg >= 5 then
|
||||||
|
|
|
@ -24,6 +24,7 @@ function MarathonAX4Game:new()
|
||||||
self.section_clear = false
|
self.section_clear = false
|
||||||
|
|
||||||
self.lock_drop = true
|
self.lock_drop = true
|
||||||
|
self.lock_hard_drop = true
|
||||||
self.enable_hold = true
|
self.enable_hold = true
|
||||||
self.next_queue_length = 3
|
self.next_queue_length = 3
|
||||||
end
|
end
|
||||||
|
@ -98,6 +99,7 @@ function MarathonAX4Game:onLineClear(cleared_row_count)
|
||||||
self:updateSectionTimes(self.lines, new_lines)
|
self:updateSectionTimes(self.lines, new_lines)
|
||||||
self.lines = math.min(new_lines, 150)
|
self.lines = math.min(new_lines, 150)
|
||||||
if self.lines == 150 then
|
if self.lines == 150 then
|
||||||
|
self.grid:clear()
|
||||||
self.clear = true
|
self.clear = true
|
||||||
self.roll_frames = -150
|
self.roll_frames = -150
|
||||||
end
|
end
|
||||||
|
|
|
@ -1,185 +0,0 @@
|
||||||
require 'funcs'
|
|
||||||
|
|
||||||
local GameMode = require 'tetris.modes.gamemode'
|
|
||||||
local Piece = require 'tetris.components.piece'
|
|
||||||
|
|
||||||
local Randomizer = require 'tetris.randomizers.randomizer'
|
|
||||||
|
|
||||||
local MarathonC89Game = GameMode:extend()
|
|
||||||
|
|
||||||
MarathonC89Game.name = "Marathon C89"
|
|
||||||
MarathonC89Game.hash = "MarathonC89"
|
|
||||||
MarathonC89Game.tagline = "Can you play fast enough to reach the killscreen?"
|
|
||||||
|
|
||||||
|
|
||||||
function MarathonC89Game:new()
|
|
||||||
MarathonC89Game.super:new()
|
|
||||||
|
|
||||||
self.randomizer = Randomizer()
|
|
||||||
|
|
||||||
self.ready_frames = 1
|
|
||||||
self.waiting_frames = 72
|
|
||||||
|
|
||||||
self.start_level = 12
|
|
||||||
self.level = 12
|
|
||||||
|
|
||||||
self.lock_drop = true
|
|
||||||
self.enable_hard_drop = false
|
|
||||||
self.enable_hold = false
|
|
||||||
self.next_queue_length = 1
|
|
||||||
self.additive_gravity = false
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonC89Game:getDropSpeed() return 1/2 end
|
|
||||||
function MarathonC89Game:getDasLimit() return 16 end
|
|
||||||
function MarathonC89Game:getARR() return 6 end
|
|
||||||
|
|
||||||
function MarathonC89Game:getARE() return 6 end
|
|
||||||
function MarathonC89Game:getLineARE() return 6 end
|
|
||||||
function MarathonC89Game:getLineClearDelay() return 30 end
|
|
||||||
function MarathonC89Game:getLockDelay() return 0 end
|
|
||||||
|
|
||||||
function MarathonC89Game:chargeDAS(inputs)
|
|
||||||
if inputs[self.das.direction] == true and
|
|
||||||
self.prev_inputs[self.das.direction] == true and
|
|
||||||
not inputs["down"] and
|
|
||||||
self.piece ~= nil
|
|
||||||
then
|
|
||||||
local das_frames = self.das.frames + 1
|
|
||||||
if das_frames >= self:getDasLimit() then
|
|
||||||
if self.das.direction == "left" then
|
|
||||||
self.move = (self:getARR() == 0 and "speed" or "") .. "left"
|
|
||||||
self.das.frames = self:getDasLimit() - self:getARR()
|
|
||||||
elseif self.das.direction == "right" then
|
|
||||||
self.move = (self:getARR() == 0 and "speed" or "") .. "right"
|
|
||||||
self.das.frames = self:getDasLimit() - self:getARR()
|
|
||||||
end
|
|
||||||
else
|
|
||||||
self.move = "none"
|
|
||||||
self.das.frames = das_frames
|
|
||||||
end
|
|
||||||
elseif inputs["right"] == true then
|
|
||||||
self.das.direction = "right"
|
|
||||||
if not inputs["down"] and self.piece ~= nil then
|
|
||||||
self.move = "right"
|
|
||||||
self.das.frames = 0
|
|
||||||
else
|
|
||||||
self.move = "none"
|
|
||||||
end
|
|
||||||
elseif inputs["left"] == true then
|
|
||||||
self.das.direction = "left"
|
|
||||||
if not inputs["down"] and self.piece ~= nil then
|
|
||||||
self.move = "left"
|
|
||||||
self.das.frames = 0
|
|
||||||
else
|
|
||||||
self.move = "none"
|
|
||||||
end
|
|
||||||
else
|
|
||||||
self.move = "none"
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.das.direction == "left" and self.piece ~= nil and self.piece:isMoveBlocked(self.grid, {x=-1, y=0}) or
|
|
||||||
self.das.direction == "right" and self.piece ~= nil and self.piece:isMoveBlocked(self.grid, {x=1, y=0})
|
|
||||||
then
|
|
||||||
self.das.frames = self:getDasLimit()
|
|
||||||
end
|
|
||||||
|
|
||||||
if inputs["down"] == false and self.prev_inputs["down"] == true then
|
|
||||||
self.drop_bonus = 0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local gravity_table = {
|
|
||||||
[0] =
|
|
||||||
1366/65536, 1525/65536, 1725/65536, 1986/65536, 2341/65536,
|
|
||||||
2850/65536, 3641/65536, 5042/65536, 8192/65536, 10923/65536,
|
|
||||||
13108/65536, 13108/65536, 13108/65536, 16384/65536, 16384/65536,
|
|
||||||
16384/65536, 21846/65536, 21846/65536, 21846/65536
|
|
||||||
}
|
|
||||||
|
|
||||||
function MarathonC89Game:getGravity()
|
|
||||||
if self.waiting_frames > 0 then return 0 end
|
|
||||||
if self.level >= 29 then return 1
|
|
||||||
elseif self.level >= 19 then return 1/2
|
|
||||||
else return gravity_table[self.level] end
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonC89Game:advanceOneFrame()
|
|
||||||
if self.waiting_frames > 0 then
|
|
||||||
self.waiting_frames = self.waiting_frames - 1
|
|
||||||
else
|
|
||||||
self.frames = self.frames + 1
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonC89Game:onPieceLock()
|
|
||||||
self.score = self.score + self.drop_bonus
|
|
||||||
self.drop_bonus = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
local cleared_line_scores = { 40, 100, 300, 1200 }
|
|
||||||
|
|
||||||
function MarathonC89Game:getLevelForLines()
|
|
||||||
if self.start_level < 10 then
|
|
||||||
return math.max(self.start_level, math.floor(self.lines / 10))
|
|
||||||
elseif self.start_level < 16 then
|
|
||||||
return math.max(self.start_level, self.start_level + math.floor((self.lines - 100) / 10))
|
|
||||||
else
|
|
||||||
return math.max(self.start_level, math.floor((self.lines - 60) / 10))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonC89Game:updateScore(level, drop_bonus, cleared_lines)
|
|
||||||
if cleared_lines > 0 then
|
|
||||||
self.score = self.score + cleared_line_scores[cleared_lines] * (self.level + 1)
|
|
||||||
self.lines = self.lines + cleared_lines
|
|
||||||
self.level = self:getLevelForLines()
|
|
||||||
else
|
|
||||||
self.drop_bonus = 0
|
|
||||||
self.combo = 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonC89Game:drawGrid()
|
|
||||||
self.grid:draw()
|
|
||||||
if self.piece ~= nil and self.level < 100 then
|
|
||||||
self:drawGhostPiece(ruleset)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonC89Game:drawScoringInfo()
|
|
||||||
MarathonC89Game.super.drawScoringInfo(self)
|
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_2)
|
|
||||||
love.graphics.print(
|
|
||||||
self.das.direction .. " " ..
|
|
||||||
self.das.frames .. " " ..
|
|
||||||
strTrueValues(self.prev_inputs)
|
|
||||||
)
|
|
||||||
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
|
||||||
love.graphics.printf("LINES", 240, 120, 40, "left")
|
|
||||||
love.graphics.printf("SCORE", 240, 200, 40, "left")
|
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
|
||||||
love.graphics.printf(self.lines, 240, 140, 90, "left")
|
|
||||||
love.graphics.printf(self.score, 240, 220, 90, "left")
|
|
||||||
|
|
||||||
love.graphics.setFont(font_8x11)
|
|
||||||
love.graphics.printf(formatTime(self.frames), 64, 420, 160, "center")
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
function MarathonC89Game:getBackground()
|
|
||||||
return math.min(self.level, 19)
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonC89Game:getHighscoreData()
|
|
||||||
return {
|
|
||||||
score = self.score,
|
|
||||||
level = self.level,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
return MarathonC89Game
|
|
|
@ -1,170 +0,0 @@
|
||||||
require 'funcs'
|
|
||||||
|
|
||||||
local GameMode = require 'tetris.modes.gamemode'
|
|
||||||
local Piece = require 'tetris.components.piece'
|
|
||||||
|
|
||||||
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
|
||||||
|
|
||||||
local PacerTest = GameMode:extend()
|
|
||||||
|
|
||||||
PacerTest.name = "TetrisGram™ Pacer Test"
|
|
||||||
PacerTest.hash = "PacerTest"
|
|
||||||
PacerTest.tagline = ""
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
local function getLevelFrames(level)
|
|
||||||
if level == 1 then return 72 * 60 / 8.0
|
|
||||||
else return 72 * 60 / (8 + level * 0.5)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local level_end_sections = {
|
|
||||||
7, 15, 23, 32, 41, 51, 61, 72, 83, 94,
|
|
||||||
106, 118, 131, 144, 157, 171, 185, 200,
|
|
||||||
215, 231, 247
|
|
||||||
}
|
|
||||||
|
|
||||||
function PacerTest:new()
|
|
||||||
PacerTest.super:new()
|
|
||||||
|
|
||||||
self.ready_frames = 2430
|
|
||||||
self.clear_frames = 0
|
|
||||||
self.randomizer = History6RollsRandomizer()
|
|
||||||
|
|
||||||
self.level = 1
|
|
||||||
self.section = 0
|
|
||||||
self.level_frames = 0
|
|
||||||
|
|
||||||
self.section_lines = 0
|
|
||||||
self.section_clear = false
|
|
||||||
self.strikes = 0
|
|
||||||
|
|
||||||
self.lock_drop = true
|
|
||||||
self.lock_hard_drop = true
|
|
||||||
self.enable_hold = true
|
|
||||||
self.instant_hard_drop = true
|
|
||||||
self.instant_soft_drop = false
|
|
||||||
self.next_queue_length = 3
|
|
||||||
end
|
|
||||||
|
|
||||||
function PacerTest:initialize(ruleset)
|
|
||||||
for i = 1, 30 do
|
|
||||||
table.insert(self.next_queue, self:getNextPiece(ruleset))
|
|
||||||
end
|
|
||||||
self.level_frames = getLevelFrames(1)
|
|
||||||
switchBGM("pacer_test")
|
|
||||||
end
|
|
||||||
|
|
||||||
function PacerTest:getARE()
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function PacerTest:getLineARE()
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function PacerTest:getDasLimit()
|
|
||||||
return 8
|
|
||||||
end
|
|
||||||
|
|
||||||
function PacerTest:getLineClearDelay()
|
|
||||||
return 6
|
|
||||||
end
|
|
||||||
|
|
||||||
function PacerTest:getLockDelay()
|
|
||||||
return 30
|
|
||||||
end
|
|
||||||
|
|
||||||
function PacerTest:getGravity()
|
|
||||||
return 1/64
|
|
||||||
end
|
|
||||||
|
|
||||||
function PacerTest:getSection()
|
|
||||||
return math.floor(level / 100) + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
function PacerTest:advanceOneFrame()
|
|
||||||
if self.clear then
|
|
||||||
self.clear_frames = self.clear_frames + 1
|
|
||||||
if self.clear_frames > 600 then
|
|
||||||
self.completed = true
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
elseif self.ready_frames == 0 then
|
|
||||||
self.frames = self.frames + 1
|
|
||||||
self.level_frames = self.level_frames - 1
|
|
||||||
if self.level_frames <= 0 then
|
|
||||||
self:checkSectionStatus()
|
|
||||||
self.section = self.section + 1
|
|
||||||
if self.section >= level_end_sections[self.level] then
|
|
||||||
self.level = self.level + 1
|
|
||||||
end
|
|
||||||
self.level_frames = self.level_frames + getLevelFrames(self.level)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
function PacerTest:checkSectionStatus()
|
|
||||||
if self.section_clear then
|
|
||||||
self.strikes = 0
|
|
||||||
self.section_clear = false
|
|
||||||
else
|
|
||||||
self.strikes = self.strikes + 1
|
|
||||||
if self.strikes >= 2 then
|
|
||||||
self.game_over = true
|
|
||||||
fadeoutBGM(2.5)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
self.section_lines = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function PacerTest:onLineClear(cleared_row_count)
|
|
||||||
self.section_lines = self.section_lines + cleared_row_count
|
|
||||||
if self.section_lines >= 3 then
|
|
||||||
self.section_clear = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function PacerTest:drawGrid(ruleset)
|
|
||||||
self.grid:draw()
|
|
||||||
if self.piece ~= nil then
|
|
||||||
self:drawGhostPiece(ruleset)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function PacerTest:getHighscoreData()
|
|
||||||
return {
|
|
||||||
level = self.level,
|
|
||||||
frames = self.frames,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
function PacerTest:drawScoringInfo()
|
|
||||||
PacerTest.super.drawScoringInfo(self)
|
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
|
||||||
|
|
||||||
local text_x = config["side_next"] and 320 or 240
|
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_2)
|
|
||||||
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
|
||||||
love.graphics.printf("LINES", text_x, 224, 70, "left")
|
|
||||||
love.graphics.printf("LEVEL", text_x, 320, 40, "left")
|
|
||||||
|
|
||||||
for i = 1, math.min(self.strikes, 3) do
|
|
||||||
love.graphics.draw(misc_graphics["strike"], text_x + (i - 1) * 30, 280)
|
|
||||||
end
|
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
|
||||||
love.graphics.printf(self.section_lines .. "/3", text_x, 244, 40, "left")
|
|
||||||
love.graphics.printf(self.level, text_x, 340, 40, "right")
|
|
||||||
love.graphics.printf(self.section, text_x, 370, 40, "right")
|
|
||||||
end
|
|
||||||
|
|
||||||
function PacerTest:getBackground()
|
|
||||||
return math.min(self.level - 1, 19)
|
|
||||||
end
|
|
||||||
|
|
||||||
return PacerTest
|
|
|
@ -15,6 +15,7 @@ function PhantomManiaGame:new()
|
||||||
PhantomManiaGame.super:new()
|
PhantomManiaGame.super:new()
|
||||||
|
|
||||||
self.lock_drop = true
|
self.lock_drop = true
|
||||||
|
self.lock_hard_drop = true
|
||||||
self.next_queue_length = 1
|
self.next_queue_length = 1
|
||||||
|
|
||||||
self.SGnames = {
|
self.SGnames = {
|
||||||
|
@ -117,17 +118,18 @@ function PhantomManiaGame:onLineClear(cleared_row_count)
|
||||||
end
|
end
|
||||||
|
|
||||||
function PhantomManiaGame:updateScore(level, drop_bonus, cleared_lines)
|
function PhantomManiaGame:updateScore(level, drop_bonus, cleared_lines)
|
||||||
|
if not self.clear then
|
||||||
if cleared_lines > 0 then
|
if cleared_lines > 0 then
|
||||||
|
self.combo = self.combo + (cleared_lines - 1) * 2
|
||||||
self.score = self.score + (
|
self.score = self.score + (
|
||||||
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
||||||
cleared_lines * (cleared_lines * 2 - 1) * (self.combo * 2 - 1)
|
cleared_lines * self.combo
|
||||||
)
|
)
|
||||||
self.lines = self.lines + cleared_lines
|
|
||||||
self.combo = self.combo + cleared_lines - 1
|
|
||||||
else
|
else
|
||||||
self.drop_bonus = 0
|
|
||||||
self.combo = 1
|
self.combo = 1
|
||||||
end
|
end
|
||||||
|
self.drop_bonus = 0
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
PhantomManiaGame.rollOpacityFunction = function(age)
|
PhantomManiaGame.rollOpacityFunction = function(age)
|
||||||
|
|
|
@ -16,7 +16,6 @@ PhantomMania2Game.tagline = "The blocks disappear even faster now! Can you make
|
||||||
|
|
||||||
function PhantomMania2Game:new()
|
function PhantomMania2Game:new()
|
||||||
PhantomMania2Game.super:new()
|
PhantomMania2Game.super:new()
|
||||||
self.level = 0
|
|
||||||
self.grade = 0
|
self.grade = 0
|
||||||
self.garbage = 0
|
self.garbage = 0
|
||||||
self.clear = false
|
self.clear = false
|
||||||
|
@ -36,8 +35,12 @@ function PhantomMania2Game:new()
|
||||||
self.randomizer = History6RollsRandomizer()
|
self.randomizer = History6RollsRandomizer()
|
||||||
|
|
||||||
self.lock_drop = true
|
self.lock_drop = true
|
||||||
|
self.lock_hard_drop = true
|
||||||
self.enable_hold = true
|
self.enable_hold = true
|
||||||
self.next_queue_length = 3
|
self.next_queue_length = 3
|
||||||
|
|
||||||
|
self.coolregret_message = ""
|
||||||
|
self.coolregret_timer = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
function PhantomMania2Game:getARE()
|
function PhantomMania2Game:getARE()
|
||||||
|
@ -122,6 +125,8 @@ function PhantomMania2Game:advanceOneFrame()
|
||||||
return false
|
return false
|
||||||
elseif self.roll_frames > 3238 then
|
elseif self.roll_frames > 3238 then
|
||||||
switchBGM(nil)
|
switchBGM(nil)
|
||||||
|
self.roll_points = self.level >= 1300 and self.roll_points + 150 or self.roll_points
|
||||||
|
self.grade = self.grade + math.floor(self.roll_points / 100)
|
||||||
self.completed = true
|
self.completed = true
|
||||||
end
|
end
|
||||||
elseif self.ready_frames == 0 then
|
elseif self.ready_frames == 0 then
|
||||||
|
@ -143,7 +148,8 @@ function PhantomMania2Game:onPieceEnter()
|
||||||
end
|
end
|
||||||
|
|
||||||
local cleared_row_levels = {1, 2, 4, 6}
|
local cleared_row_levels = {1, 2, 4, 6}
|
||||||
local cleared_row_points = {2, 6, 15, 40}
|
local torikan_roll_points = {10, 20, 30, 100}
|
||||||
|
local big_roll_points = {10, 20, 100, 200}
|
||||||
|
|
||||||
function PhantomMania2Game:onLineClear(cleared_row_count)
|
function PhantomMania2Game:onLineClear(cleared_row_count)
|
||||||
if not self.clear then
|
if not self.clear then
|
||||||
|
@ -162,7 +168,8 @@ function PhantomMania2Game:onLineClear(cleared_row_count)
|
||||||
end
|
end
|
||||||
self:advanceBottomRow(-cleared_row_count)
|
self:advanceBottomRow(-cleared_row_count)
|
||||||
else
|
else
|
||||||
self.roll_points = self.roll_points + cleared_row_points[cleared_row_count / 2]
|
if self.big_mode then self.roll_points = self.roll_points + big_roll_points[cleared_row_count / 2]
|
||||||
|
else self.roll_points = self.roll_points + torikan_roll_points[cleared_row_count] end
|
||||||
if self.roll_points >= 100 then
|
if self.roll_points >= 100 then
|
||||||
self.roll_points = self.roll_points - 100
|
self.roll_points = self.roll_points - 100
|
||||||
self.grade = self.grade + 1
|
self.grade = self.grade + 1
|
||||||
|
@ -171,25 +178,28 @@ function PhantomMania2Game:onLineClear(cleared_row_count)
|
||||||
end
|
end
|
||||||
|
|
||||||
function PhantomMania2Game:onPieceLock(piece, cleared_row_count)
|
function PhantomMania2Game:onPieceLock(piece, cleared_row_count)
|
||||||
|
self.super:onPieceLock()
|
||||||
if cleared_row_count == 0 then self:advanceBottomRow(1) end
|
if cleared_row_count == 0 then self:advanceBottomRow(1) end
|
||||||
end
|
end
|
||||||
|
|
||||||
function PhantomMania2Game:onHold()
|
function PhantomMania2Game:onHold()
|
||||||
|
self.super.onHold()
|
||||||
self.hold_age = 0
|
self.hold_age = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
function PhantomMania2Game:updateScore(level, drop_bonus, cleared_lines)
|
function PhantomMania2Game:updateScore(level, drop_bonus, cleared_lines)
|
||||||
|
if not self.clear then
|
||||||
if cleared_lines > 0 then
|
if cleared_lines > 0 then
|
||||||
|
self.combo = self.combo + (cleared_lines - 1) * 2
|
||||||
self.score = self.score + (
|
self.score = self.score + (
|
||||||
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
||||||
cleared_lines * (cleared_lines * 2 - 1) * (self.combo * 2 - 1)
|
cleared_lines * self.combo
|
||||||
)
|
)
|
||||||
self.lines = self.lines + cleared_lines
|
|
||||||
self.combo = self.combo + cleared_lines - 1
|
|
||||||
else
|
else
|
||||||
self.drop_bonus = 0
|
|
||||||
self.combo = 1
|
self.combo = 1
|
||||||
end
|
end
|
||||||
|
self.drop_bonus = 0
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
||||||
|
@ -213,8 +223,13 @@ function PhantomMania2Game:updateSectionTimes(old_level, new_level)
|
||||||
self.section_start_time = self.frames
|
self.section_start_time = self.frames
|
||||||
if section_time <= cool_cutoffs[section] then
|
if section_time <= cool_cutoffs[section] then
|
||||||
self.grade = self.grade + 2
|
self.grade = self.grade + 2
|
||||||
|
self.coolregret_message = "COOL!!"
|
||||||
|
self.coolregret_timer = 300
|
||||||
elseif section_time <= regret_cutoffs[section] then
|
elseif section_time <= regret_cutoffs[section] then
|
||||||
self.grade = self.grade + 1
|
self.grade = self.grade + 1
|
||||||
|
else
|
||||||
|
self.coolregret_message = "REGRET!!"
|
||||||
|
self.coolregret_timer = 300
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -296,6 +311,13 @@ function PhantomMania2Game:drawScoringInfo()
|
||||||
love.graphics.printf("SECRET GRADE", 240, 430, 180, "left")
|
love.graphics.printf("SECRET GRADE", 240, 430, 180, "left")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
self:drawSectionTimesWithSplits(math.floor(self.level / 100) + 1)
|
||||||
|
|
||||||
|
if(self.coolregret_timer > 0) then
|
||||||
|
love.graphics.printf(self.coolregret_message, 64, 400, 160, "center")
|
||||||
|
self.coolregret_timer = self.coolregret_timer - 1
|
||||||
|
end
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
love.graphics.setFont(font_3x5_3)
|
||||||
love.graphics.printf(getLetterGrade(math.floor(self.grade)), text_x, 140, 90, "left")
|
love.graphics.printf(getLetterGrade(math.floor(self.grade)), text_x, 140, 90, "left")
|
||||||
love.graphics.printf(self.score, text_x, 220, 90, "left")
|
love.graphics.printf(self.score, text_x, 220, 90, "left")
|
||||||
|
|
|
@ -1,22 +0,0 @@
|
||||||
local PhantomManiaGame = require 'tetris.modes.phantom_mania'
|
|
||||||
|
|
||||||
local PhantomManiaNGame = PhantomManiaGame:extend()
|
|
||||||
|
|
||||||
PhantomManiaNGame.name = "Phantom Mania N"
|
|
||||||
PhantomManiaNGame.hash = "PhantomManiaN"
|
|
||||||
PhantomManiaNGame.tagline = "The old mode from Nullpomino, for Ti-ARS and SRS support."
|
|
||||||
|
|
||||||
function PhantomManiaNGame:new()
|
|
||||||
PhantomManiaNGame.super:new()
|
|
||||||
|
|
||||||
self.SGnames = {
|
|
||||||
"M1", "M2", "M3", "M4", "M5", "M6", "M7", "M8", "M9",
|
|
||||||
"M10", "M11", "M12", "M13", "M14", "M15", "M16", "M17", "M18",
|
|
||||||
"GM"
|
|
||||||
}
|
|
||||||
|
|
||||||
self.next_queue_length = 3
|
|
||||||
self.enable_hold = true
|
|
||||||
end
|
|
||||||
|
|
||||||
return PhantomManiaNGame
|
|
|
@ -1,129 +0,0 @@
|
||||||
require 'funcs'
|
|
||||||
|
|
||||||
local GameMode = require 'tetris.modes.gamemode'
|
|
||||||
local Piece = require 'tetris.components.piece'
|
|
||||||
|
|
||||||
local Bag7Randomiser = require 'tetris.randomizers.bag7noSZOstart'
|
|
||||||
|
|
||||||
local Race40Game = GameMode:extend()
|
|
||||||
|
|
||||||
Race40Game.name = "Race 40"
|
|
||||||
Race40Game.hash = "Race40"
|
|
||||||
Race40Game.tagline = "How fast can you clear 40 lines?"
|
|
||||||
|
|
||||||
|
|
||||||
function Race40Game:new()
|
|
||||||
Race40Game.super:new()
|
|
||||||
|
|
||||||
self.lines = 0
|
|
||||||
self.line_goal = 40
|
|
||||||
self.pieces = 0
|
|
||||||
self.randomizer = Bag7Randomiser()
|
|
||||||
|
|
||||||
self.roll_frames = 0
|
|
||||||
|
|
||||||
self.lock_drop = true
|
|
||||||
self.lock_hard_drop = true
|
|
||||||
self.instant_hard_drop = true
|
|
||||||
self.instant_soft_drop = false
|
|
||||||
self.enable_hold = true
|
|
||||||
self.next_queue_length = 3
|
|
||||||
end
|
|
||||||
|
|
||||||
function Race40Game:getDropSpeed()
|
|
||||||
return 20
|
|
||||||
end
|
|
||||||
|
|
||||||
function Race40Game:getARR()
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function Race40Game:getARE()
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function Race40Game:getLineARE()
|
|
||||||
return self:getARE()
|
|
||||||
end
|
|
||||||
|
|
||||||
function Race40Game:getDasLimit()
|
|
||||||
return 6
|
|
||||||
end
|
|
||||||
|
|
||||||
function Race40Game:getLineClearDelay()
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function Race40Game:getLockDelay()
|
|
||||||
return 15
|
|
||||||
end
|
|
||||||
|
|
||||||
function Race40Game:getGravity()
|
|
||||||
return 1/64
|
|
||||||
end
|
|
||||||
|
|
||||||
function Race40Game:advanceOneFrame()
|
|
||||||
if self.clear then
|
|
||||||
self.roll_frames = self.roll_frames + 1
|
|
||||||
if self.roll_frames > 150 then
|
|
||||||
self.completed = true
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
elseif self.ready_frames == 0 then
|
|
||||||
self.frames = self.frames + 1
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
function Race40Game:onPieceLock()
|
|
||||||
self.pieces = self.pieces + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
function Race40Game:onLineClear(cleared_row_count)
|
|
||||||
if not self.clear then
|
|
||||||
self.lines = self.lines + cleared_row_count
|
|
||||||
if self.lines >= self.line_goal then
|
|
||||||
self.clear = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Race40Game:drawGrid(ruleset)
|
|
||||||
self.grid:draw()
|
|
||||||
if self.piece ~= nil then
|
|
||||||
self:drawGhostPiece(ruleset)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Race40Game:getHighscoreData()
|
|
||||||
return {
|
|
||||||
level = self.level,
|
|
||||||
frames = self.frames,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
function Race40Game:drawScoringInfo()
|
|
||||||
Race40Game.super.drawScoringInfo(self)
|
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
|
||||||
|
|
||||||
local text_x = config["side_next"] and 320 or 240
|
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_2)
|
|
||||||
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
|
||||||
love.graphics.printf("LINES", text_x, 320, 40, "left")
|
|
||||||
love.graphics.printf("line/min", text_x, 160, 80, "left")
|
|
||||||
love.graphics.printf("piece/sec", text_x, 220, 80, "left")
|
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
|
||||||
love.graphics.printf(string.format("%.02f", self.lines / math.max(1, self.frames) * 3600), text_x, 180, 80, "left")
|
|
||||||
love.graphics.printf(string.format("%.04f", self.pieces / math.max(1, self.frames) * 60), text_x, 240, 80, "left")
|
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_4)
|
|
||||||
love.graphics.printf(math.max(0, self.line_goal - self.lines), text_x, 340, 40, "left")
|
|
||||||
end
|
|
||||||
|
|
||||||
function Race40Game:getBackground()
|
|
||||||
return 2
|
|
||||||
end
|
|
||||||
|
|
||||||
return Race40Game
|
|
|
@ -16,7 +16,6 @@ StrategyGame.tagline = "You have lots of time to think! Can you use it to place
|
||||||
|
|
||||||
function StrategyGame:new()
|
function StrategyGame:new()
|
||||||
StrategyGame.super:new()
|
StrategyGame.super:new()
|
||||||
self.level = 0
|
|
||||||
self.clear = false
|
self.clear = false
|
||||||
self.completed = false
|
self.completed = false
|
||||||
self.roll_frames = 0
|
self.roll_frames = 0
|
||||||
|
@ -84,7 +83,7 @@ function StrategyGame:advanceOneFrame()
|
||||||
end
|
end
|
||||||
|
|
||||||
function StrategyGame:onPieceEnter()
|
function StrategyGame:onPieceEnter()
|
||||||
if (self.level % 100 ~= 99) and not self.clear and self.frames ~= 0 then
|
if (self.level % 100 ~= 99 and self.level ~= 998) and not self.clear and self.frames ~= 0 then
|
||||||
self.level = self.level + 1
|
self.level = self.level + 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -99,17 +98,18 @@ function StrategyGame:onLineClear(cleared_row_count)
|
||||||
end
|
end
|
||||||
|
|
||||||
function StrategyGame:updateScore(level, drop_bonus, cleared_lines)
|
function StrategyGame:updateScore(level, drop_bonus, cleared_lines)
|
||||||
|
if not self.clear then
|
||||||
if cleared_lines > 0 then
|
if cleared_lines > 0 then
|
||||||
|
self.combo = self.combo + (cleared_lines - 1) * 2
|
||||||
self.score = self.score + (
|
self.score = self.score + (
|
||||||
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
||||||
cleared_lines * (cleared_lines * 2 - 1) * (self.combo * 2 - 1)
|
cleared_lines * self.combo
|
||||||
)
|
)
|
||||||
self.lines = self.lines + cleared_lines
|
|
||||||
self.combo = self.combo + cleared_lines - 1
|
|
||||||
else
|
else
|
||||||
self.drop_bonus = 0
|
|
||||||
self.combo = 1
|
self.combo = 1
|
||||||
end
|
end
|
||||||
|
self.drop_bonus = 0
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function StrategyGame:setNextOpacity(i)
|
function StrategyGame:setNextOpacity(i)
|
||||||
|
@ -135,11 +135,11 @@ function StrategyGame:drawScoringInfo()
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
love.graphics.setFont(font_3x5_3)
|
||||||
love.graphics.printf(self.score, text_x, 220, 90, "left")
|
love.graphics.printf(self.score, text_x, 220, 90, "left")
|
||||||
love.graphics.printf(self.level, text_x, 340, 50, "right")
|
love.graphics.printf(self.level, text_x, 340, 40, "right")
|
||||||
if self.clear then
|
if self.clear then
|
||||||
love.graphics.printf(self.level, text_x, 370, 50, "right")
|
love.graphics.printf(self.level, text_x, 370, 40, "right")
|
||||||
else
|
else
|
||||||
love.graphics.printf(math.floor(self.level / 100 + 1) * 100, text_x, 370, 50, "right")
|
love.graphics.printf(self.level < 900 and math.floor(self.level / 100 + 1) * 100 or 999, text_x, 370, 40, "right")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -27,6 +27,7 @@ function Survival2020Game:new()
|
||||||
self.randomizer = History6RollsRandomizer()
|
self.randomizer = History6RollsRandomizer()
|
||||||
|
|
||||||
self.lock_drop = true
|
self.lock_drop = true
|
||||||
|
self.lock_hard_drop = true
|
||||||
self.enable_hold = true
|
self.enable_hold = true
|
||||||
self.next_queue_length = 3
|
self.next_queue_length = 3
|
||||||
end
|
end
|
||||||
|
@ -174,17 +175,18 @@ function Survival2020Game:onLineClear(cleared_row_count)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Survival2020Game:updateScore(level, drop_bonus, cleared_lines)
|
function Survival2020Game:updateScore(level, drop_bonus, cleared_lines)
|
||||||
|
if not self.clear then
|
||||||
if cleared_lines > 0 then
|
if cleared_lines > 0 then
|
||||||
|
self.combo = self.combo + (cleared_lines - 1) * 2
|
||||||
self.score = self.score + (
|
self.score = self.score + (
|
||||||
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
||||||
cleared_lines * (cleared_lines * 2 - 1) * (self.combo * 2 - 1)
|
cleared_lines * self.combo
|
||||||
)
|
)
|
||||||
self.lines = self.lines + cleared_lines
|
|
||||||
self.combo = self.combo + cleared_lines - 1
|
|
||||||
else
|
else
|
||||||
self.drop_bonus = 0
|
|
||||||
self.combo = 1
|
self.combo = 1
|
||||||
end
|
end
|
||||||
|
self.drop_bonus = 0
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Survival2020Game:updateSectionTimes(old_level, new_level)
|
function Survival2020Game:updateSectionTimes(old_level, new_level)
|
||||||
|
|
|
@ -109,7 +109,7 @@ function SurvivalA1Game:onLineClear(cleared_row_count)
|
||||||
self:checkGMRequirements(self.level, self.level + cleared_row_count)
|
self:checkGMRequirements(self.level, self.level + cleared_row_count)
|
||||||
if not self.clear then
|
if not self.clear then
|
||||||
local new_level = math.min(self.level + cleared_row_count, 999)
|
local new_level = math.min(self.level + cleared_row_count, 999)
|
||||||
if self.level == 999 then
|
if new_level == 999 then
|
||||||
self.clear = true
|
self.clear = true
|
||||||
else
|
else
|
||||||
self.level = new_level
|
self.level = new_level
|
||||||
|
@ -118,35 +118,36 @@ function SurvivalA1Game:onLineClear(cleared_row_count)
|
||||||
end
|
end
|
||||||
|
|
||||||
function SurvivalA1Game:updateScore(level, drop_bonus, cleared_lines)
|
function SurvivalA1Game:updateScore(level, drop_bonus, cleared_lines)
|
||||||
|
if not self.clear then
|
||||||
if self.grid:checkForBravo(cleared_lines) then
|
if self.grid:checkForBravo(cleared_lines) then
|
||||||
self.bravo = 4
|
self.bravo = 4
|
||||||
self.bravos = self.bravos + 1
|
self.bravos = self.bravos + 1
|
||||||
else self.bravo = 1 end
|
else self.bravo = 1 end
|
||||||
if cleared_lines > 0 then
|
if cleared_lines > 0 then
|
||||||
|
self.combo = self.combo + (cleared_lines - 1) * 2
|
||||||
self.score = self.score + (
|
self.score = self.score + (
|
||||||
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
||||||
cleared_lines * self.bravo * self.combo
|
cleared_lines * self.combo * self.bravo
|
||||||
)
|
)
|
||||||
self.lines = self.lines + cleared_lines
|
|
||||||
self.combo = self.combo + (cleared_lines - 1) * 2
|
|
||||||
else
|
else
|
||||||
self.drop_bonus = 0
|
|
||||||
self.combo = 1
|
self.combo = 1
|
||||||
end
|
end
|
||||||
|
self.drop_bonus = 0
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function SurvivalA1Game:checkGMRequirements(old_level, new_level)
|
function SurvivalA1Game:checkGMRequirements(old_level, new_level)
|
||||||
if old_level < 300 and new_level >= 300 then
|
if old_level < 300 and new_level >= 300 then
|
||||||
if self.score > 12000 and self.frames <= frameTime(4,15) then
|
if self.score >= 12000 and self.frames <= frameTime(4,15) then
|
||||||
self.gm_conditions["level300"] = true
|
self.gm_conditions["level300"] = true
|
||||||
end
|
end
|
||||||
elseif old_level < 500 and new_level >= 500 then
|
elseif old_level < 500 and new_level >= 500 then
|
||||||
if self.score > 40000 and self.frames <= frameTime(7,30) then
|
if self.score >= 40000 and self.frames <= frameTime(7,30) then
|
||||||
self.gm_conditions["level500"] = true
|
self.gm_conditions["level500"] = true
|
||||||
end
|
end
|
||||||
elseif old_level < 999 and new_level >= 999 then
|
elseif old_level < 999 and new_level >= 999 then
|
||||||
if self.score > 126000 and self.frames <= frameTime(13,30) then
|
if self.score >= 126000 and self.frames <= frameTime(13,30) then
|
||||||
self.gm_conditions["level900"] = true
|
self.gm_conditions["level999"] = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -179,7 +180,7 @@ function SurvivalA1Game:drawScoringInfo()
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
love.graphics.setFont(font_3x5_3)
|
||||||
love.graphics.printf(self.score, 240, 220, 90, "left")
|
love.graphics.printf(self.score, 240, 220, 90, "left")
|
||||||
if self.gm_conditions["level300"] and self.gm_conditions["level500"] and self.gm_conditions["level900"] then
|
if self.gm_conditions["level300"] and self.gm_conditions["level500"] and self.gm_conditions["level999"] then
|
||||||
love.graphics.printf("GM", 240, 140, 90, "left")
|
love.graphics.printf("GM", 240, 140, 90, "left")
|
||||||
else
|
else
|
||||||
love.graphics.printf(getRankForScore(self.score).rank, 240, 140, 90, "left")
|
love.graphics.printf(getRankForScore(self.score).rank, 240, 140, 90, "left")
|
||||||
|
|
|
@ -27,6 +27,7 @@ function SurvivalA2Game:new()
|
||||||
}
|
}
|
||||||
|
|
||||||
self.lock_drop = true
|
self.lock_drop = true
|
||||||
|
self.lock_hard_drop = true
|
||||||
end
|
end
|
||||||
|
|
||||||
function SurvivalA2Game:getARE()
|
function SurvivalA2Game:getARE()
|
||||||
|
@ -88,7 +89,7 @@ function SurvivalA2Game:advanceOneFrame()
|
||||||
end
|
end
|
||||||
|
|
||||||
function SurvivalA2Game:onPieceEnter()
|
function SurvivalA2Game:onPieceEnter()
|
||||||
if (self.level % 100 ~= 99 or self.level == 998) and not self.clear and self.frames ~= 0 then
|
if (self.level % 100 ~= 99 and self.level ~= 998) and not self.clear and self.frames ~= 0 then
|
||||||
self.level = self.level + 1
|
self.level = self.level + 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
@ -108,18 +109,19 @@ function SurvivalA2Game:onLineClear(cleared_row_count)
|
||||||
end
|
end
|
||||||
|
|
||||||
function SurvivalA2Game:updateScore(level, drop_bonus, cleared_lines)
|
function SurvivalA2Game:updateScore(level, drop_bonus, cleared_lines)
|
||||||
|
if not self.clear then
|
||||||
if self.grid:checkForBravo(cleared_lines) then self.bravo = 4 else self.bravo = 1 end
|
if self.grid:checkForBravo(cleared_lines) then self.bravo = 4 else self.bravo = 1 end
|
||||||
if cleared_lines > 0 then
|
if cleared_lines > 0 then
|
||||||
|
self.combo = self.combo + (cleared_lines - 1) * 2
|
||||||
self.score = self.score + (
|
self.score = self.score + (
|
||||||
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
||||||
cleared_lines * self.bravo * self.combo
|
cleared_lines * self.combo * self.bravo
|
||||||
)
|
)
|
||||||
self.lines = self.lines + cleared_lines
|
|
||||||
self.combo = self.combo + (cleared_lines - 1) * 2
|
|
||||||
else
|
else
|
||||||
self.drop_bonus = 0
|
|
||||||
self.combo = 1
|
self.combo = 1
|
||||||
end
|
end
|
||||||
|
self.drop_bonus = 0
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function SurvivalA2Game:getLetterGrade()
|
function SurvivalA2Game:getLetterGrade()
|
||||||
|
@ -156,6 +158,8 @@ function SurvivalA2Game:drawScoringInfo()
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
love.graphics.setFont(font_3x5_3)
|
||||||
love.graphics.printf(self.score, text_x, 220, 90, "left")
|
love.graphics.printf(self.score, text_x, 220, 90, "left")
|
||||||
|
if self.roll_frames > 2968 then love.graphics.setColor(1, 0.5, 0, 1)
|
||||||
|
elseif self.clear then love.graphics.setColor(0, 1, 0, 1) end
|
||||||
if self:getLetterGrade() ~= "" then love.graphics.printf(self:getLetterGrade(), text_x, 140, 90, "left") end
|
if self:getLetterGrade() ~= "" then love.graphics.printf(self:getLetterGrade(), text_x, 140, 90, "left") end
|
||||||
love.graphics.printf(self.level, text_x, 340, 40, "right")
|
love.graphics.printf(self.level, text_x, 340, 40, "right")
|
||||||
love.graphics.printf(self:getSectionEndLevel(), text_x, 370, 40, "right")
|
love.graphics.printf(self:getSectionEndLevel(), text_x, 370, 40, "right")
|
||||||
|
|
|
@ -12,11 +12,8 @@ SurvivalA3Game.hash = "SurvivalA3"
|
||||||
SurvivalA3Game.tagline = "The blocks turn black and white! Can you make it to level 1300?"
|
SurvivalA3Game.tagline = "The blocks turn black and white! Can you make it to level 1300?"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function SurvivalA3Game:new()
|
function SurvivalA3Game:new()
|
||||||
SurvivalA3Game.super:new()
|
SurvivalA3Game.super:new()
|
||||||
self.level = 0
|
|
||||||
self.grade = 0
|
self.grade = 0
|
||||||
self.garbage = 0
|
self.garbage = 0
|
||||||
self.clear = false
|
self.clear = false
|
||||||
|
@ -32,6 +29,7 @@ function SurvivalA3Game:new()
|
||||||
}
|
}
|
||||||
|
|
||||||
self.lock_drop = true
|
self.lock_drop = true
|
||||||
|
self.lock_hard_drop = true
|
||||||
self.enable_hold = true
|
self.enable_hold = true
|
||||||
self.next_queue_length = 3
|
self.next_queue_length = 3
|
||||||
|
|
||||||
|
@ -140,7 +138,6 @@ function SurvivalA3Game:onPieceEnter()
|
||||||
end
|
end
|
||||||
|
|
||||||
local cleared_row_levels = {1, 2, 4, 6}
|
local cleared_row_levels = {1, 2, 4, 6}
|
||||||
local cleared_row_points = {0.02, 0.05, 0.15, 0.6}
|
|
||||||
|
|
||||||
function SurvivalA3Game:onLineClear(cleared_row_count)
|
function SurvivalA3Game:onLineClear(cleared_row_count)
|
||||||
if not self.clear then
|
if not self.clear then
|
||||||
|
@ -164,21 +161,23 @@ function SurvivalA3Game:onLineClear(cleared_row_count)
|
||||||
end
|
end
|
||||||
|
|
||||||
function SurvivalA3Game:onPieceLock(piece, cleared_row_count)
|
function SurvivalA3Game:onPieceLock(piece, cleared_row_count)
|
||||||
|
self.super:onPieceLock()
|
||||||
if cleared_row_count == 0 then self:advanceBottomRow(1) end
|
if cleared_row_count == 0 then self:advanceBottomRow(1) end
|
||||||
end
|
end
|
||||||
|
|
||||||
function SurvivalA3Game:updateScore(level, drop_bonus, cleared_lines)
|
function SurvivalA3Game:updateScore(level, drop_bonus, cleared_lines)
|
||||||
|
if not self.clear then
|
||||||
if cleared_lines > 0 then
|
if cleared_lines > 0 then
|
||||||
|
self.combo = self.combo + (cleared_lines - 1) * 2
|
||||||
self.score = self.score + (
|
self.score = self.score + (
|
||||||
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
||||||
cleared_lines * (cleared_lines * 2 - 1) * (self.combo * 2 - 1)
|
cleared_lines * self.combo
|
||||||
)
|
)
|
||||||
self.lines = self.lines + cleared_lines
|
|
||||||
self.combo = self.combo + cleared_lines - 1
|
|
||||||
else
|
else
|
||||||
self.drop_bonus = 0
|
|
||||||
self.combo = 1
|
self.combo = 1
|
||||||
end
|
end
|
||||||
|
self.drop_bonus = 0
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function SurvivalA3Game:updateSectionTimes(old_level, new_level)
|
function SurvivalA3Game:updateSectionTimes(old_level, new_level)
|
||||||
|
@ -243,7 +242,10 @@ function SurvivalA3Game:drawScoringInfo()
|
||||||
self:drawSectionTimesWithSplits(current_section)
|
self:drawSectionTimesWithSplits(current_section)
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
love.graphics.setFont(font_3x5_3)
|
||||||
|
if self.roll_frames > 3238 then love.graphics.setColor(1, 0.5, 0, 1)
|
||||||
|
elseif self.clear then love.graphics.setColor(0, 1, 0, 1) end
|
||||||
love.graphics.printf(getLetterGrade(math.floor(self.grade)), text_x, 140, 90, "left")
|
love.graphics.printf(getLetterGrade(math.floor(self.grade)), text_x, 140, 90, "left")
|
||||||
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
love.graphics.printf(self.score, text_x, 220, 90, "left")
|
love.graphics.printf(self.score, text_x, 220, 90, "left")
|
||||||
love.graphics.printf(self.level, text_x, 340, 50, "right")
|
love.graphics.printf(self.level, text_x, 340, 50, "right")
|
||||||
if self.clear then
|
if self.clear then
|
||||||
|
|
|
@ -1,17 +0,0 @@
|
||||||
local Randomizer = require 'tetris.randomizers.randomizer'
|
|
||||||
|
|
||||||
local Bag5Randomizer = Randomizer:extend()
|
|
||||||
|
|
||||||
function Bag5Randomizer:initialize()
|
|
||||||
self.bag = {"I", "J", "L", "O", "T"}
|
|
||||||
end
|
|
||||||
|
|
||||||
function Bag5Randomizer:generatePiece()
|
|
||||||
if next(self.bag) == nil then
|
|
||||||
self.bag = {"I", "J", "L", "O", "T"}
|
|
||||||
end
|
|
||||||
local x = math.random(table.getn(self.bag))
|
|
||||||
return table.remove(self.bag, x)
|
|
||||||
end
|
|
||||||
|
|
||||||
return Bag5Randomizer
|
|
|
@ -1,24 +0,0 @@
|
||||||
local Randomizer = require 'tetris.randomizers.randomizer'
|
|
||||||
|
|
||||||
local Bag5AltRandomizer = Randomizer:extend()
|
|
||||||
|
|
||||||
function Bag5AltRandomizer:initialize()
|
|
||||||
self.bag = {"I", "J", "L", "O", "T"}
|
|
||||||
self.prev = nil
|
|
||||||
end
|
|
||||||
|
|
||||||
function Bag5AltRandomizer:generatePiece()
|
|
||||||
if next(self.bag) == nil then
|
|
||||||
self.bag = {"I", "J", "L", "O", "T"}
|
|
||||||
end
|
|
||||||
local x = math.random(table.getn(self.bag))
|
|
||||||
local temp = table.remove(self.bag, x)
|
|
||||||
if temp == self.prev then
|
|
||||||
local y = math.random(table.getn(self.bag))
|
|
||||||
temp = table.remove(self.bag, y)
|
|
||||||
end
|
|
||||||
self.prev = temp
|
|
||||||
return temp
|
|
||||||
end
|
|
||||||
|
|
||||||
return Bag5AltRandomizer
|
|
|
@ -1,24 +0,0 @@
|
||||||
local Randomizer = require 'tetris.randomizers.randomizer'
|
|
||||||
|
|
||||||
local Bag7Randomizer = Randomizer:extend()
|
|
||||||
|
|
||||||
function Bag7Randomizer:initialize()
|
|
||||||
self.bag = {"I", "J", "L", "O", "S", "T", "Z"}
|
|
||||||
self.extra = {"I", "J", "L", "O", "S", "T", "Z"}
|
|
||||||
table.insert(self.bag, table.remove(self.extra, math.random(table.getn(self.extra))))
|
|
||||||
end
|
|
||||||
|
|
||||||
function Bag7Randomizer:generatePiece()
|
|
||||||
if next(self.extra) == nil then
|
|
||||||
self.extra = {"I", "J", "L", "O", "S", "T", "Z"}
|
|
||||||
end
|
|
||||||
if next(self.bag) == nil then
|
|
||||||
self.bag = {"I", "J", "L", "O", "S", "T", "Z"}
|
|
||||||
table.insert(self.bag, table.remove(self.extra, math.random(table.getn(self.extra))))
|
|
||||||
end
|
|
||||||
local x = math.random(table.getn(self.bag))
|
|
||||||
--print("Bag: "..table.concat(self.bag, ", ").." | Extra: "..table.concat(self.extra, ", "))
|
|
||||||
return table.remove(self.bag, x)
|
|
||||||
end
|
|
||||||
|
|
||||||
return Bag7Randomizer
|
|
|
@ -1,28 +0,0 @@
|
||||||
local Randomizer = require 'tetris.randomizers.randomizer'
|
|
||||||
|
|
||||||
local BagKonoha = Randomizer:extend()
|
|
||||||
|
|
||||||
function BagKonoha:initialize()
|
|
||||||
self.bag = {"I", "J", "L", "O", "T"}
|
|
||||||
self.prev = nil
|
|
||||||
self.allowrepeat = false
|
|
||||||
self.generated = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function BagKonoha:generatePiece()
|
|
||||||
self.generated = self.generated + 1
|
|
||||||
if #self.bag == 0 then
|
|
||||||
self.bag = {"I", "J", "L", "O", "T"}
|
|
||||||
end
|
|
||||||
local x = math.random(#self.bag)
|
|
||||||
local temp = table.remove(self.bag, x)
|
|
||||||
if temp == self.prev and not self.allowrepeat then
|
|
||||||
local y = math.random(#self.bag)
|
|
||||||
table.insert(self.bag, temp) -- should insert at the end of the bag, bag[y] doesnt change
|
|
||||||
temp = table.remove(self.bag, y)
|
|
||||||
end
|
|
||||||
self.prev = temp
|
|
||||||
return temp
|
|
||||||
end
|
|
||||||
|
|
||||||
return BagKonoha
|
|
|
@ -1,30 +0,0 @@
|
||||||
local Randomizer = require 'tetris.randomizers.randomizer'
|
|
||||||
|
|
||||||
local RecursiveRandomizer = Randomizer:extend()
|
|
||||||
|
|
||||||
function RecursiveRandomizer:initialize()
|
|
||||||
self.bag = {"I", "J", "L", "O", "S", "T", "Z"}
|
|
||||||
end
|
|
||||||
|
|
||||||
function RecursiveRandomizer:generatePiece()
|
|
||||||
--if next(self.bag) == nil then
|
|
||||||
-- self.bag = {"I", "J", "L", "O", "S", "T", "Z"}
|
|
||||||
--end
|
|
||||||
local x = math.random(table.getn(self.bag) + 1)
|
|
||||||
while x == table.getn(self.bag) + 1 do
|
|
||||||
--print("Refill piece pulled")
|
|
||||||
table.insert(self.bag, "I")
|
|
||||||
table.insert(self.bag, "J")
|
|
||||||
table.insert(self.bag, "L")
|
|
||||||
table.insert(self.bag, "O")
|
|
||||||
table.insert(self.bag, "S")
|
|
||||||
table.insert(self.bag, "T")
|
|
||||||
table.insert(self.bag, "Z")
|
|
||||||
x = math.random(table.getn(self.bag) + 1)
|
|
||||||
end
|
|
||||||
--print("Number of pieces in bag: "..table.getn(self.bag))
|
|
||||||
--print("Bag: "..table.concat(self.bag, ", "))
|
|
||||||
return table.remove(self.bag, x)
|
|
||||||
end
|
|
||||||
|
|
||||||
return RecursiveRandomizer
|
|
|
@ -1,19 +0,0 @@
|
||||||
local Randomizer = require 'tetris.randomizers.randomizer'
|
|
||||||
|
|
||||||
local SegaRandomizer = Randomizer:extend()
|
|
||||||
|
|
||||||
function SegaRandomizer:initialize()
|
|
||||||
self.bag = {"I", "J", "L", "O", "S", "T", "Z"}
|
|
||||||
self.sequence = {}
|
|
||||||
for i = 1, 1000 do
|
|
||||||
self.sequence[i] = self.bag[math.random(table.getn(self.bag))]
|
|
||||||
end
|
|
||||||
self.counter = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function SegaRandomizer:generatePiece()
|
|
||||||
self.counter = self.counter + 1
|
|
||||||
return self.sequence[self.counter % 1000 + 1]
|
|
||||||
end
|
|
||||||
|
|
||||||
return SegaRandomizer
|
|
|
@ -110,7 +110,14 @@ function ARS:onPieceDrop(piece, grid)
|
||||||
piece.lock_delay = 0 -- step reset
|
piece.lock_delay = 0 -- step reset
|
||||||
end
|
end
|
||||||
|
|
||||||
function ARS:get180RotationValue() return 3 end
|
function ARS:get180RotationValue()
|
||||||
|
if config.gamesettings.world_reverse == 3 then
|
||||||
|
return 3
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function ARS:getDefaultOrientation() return 3 end -- downward facing pieces by default
|
function ARS:getDefaultOrientation() return 3 end -- downward facing pieces by default
|
||||||
|
|
||||||
return ARS
|
return ARS
|
||||||
|
|
|
@ -185,7 +185,14 @@ function ARS:onPieceRotate(piece, grid)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function ARS:get180RotationValue() return 3 end
|
function ARS:get180RotationValue()
|
||||||
|
if config.gamesettings.world_reverse == 3 then
|
||||||
|
return 3
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function ARS:getDefaultOrientation() return 3 end -- downward facing pieces by default
|
function ARS:getDefaultOrientation() return 3 end -- downward facing pieces by default
|
||||||
|
|
||||||
return ARS
|
return ARS
|
||||||
|
|
|
@ -172,7 +172,14 @@ function ARS:onPieceRotate(piece, grid)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function ARS:get180RotationValue() return 3 end
|
function ARS:get180RotationValue()
|
||||||
|
if config.gamesettings.world_reverse == 3 then
|
||||||
|
return 3
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function ARS:getDefaultOrientation() return 3 end -- downward facing pieces by default
|
function ARS:getDefaultOrientation() return 3 end -- downward facing pieces by default
|
||||||
|
|
||||||
return ARS
|
return ARS
|
||||||
|
|
|
@ -18,8 +18,6 @@ SRS.colourscheme = {
|
||||||
SRS.softdrop_lock = false
|
SRS.softdrop_lock = false
|
||||||
SRS.harddrop_lock = true
|
SRS.harddrop_lock = true
|
||||||
|
|
||||||
SRS.enable_IRS_wallkicks = true
|
|
||||||
|
|
||||||
SRS.spawn_positions = {
|
SRS.spawn_positions = {
|
||||||
I = { x=5, y=2 },
|
I = { x=5, y=2 },
|
||||||
J = { x=4, y=3 },
|
J = { x=4, y=3 },
|
||||||
|
@ -186,5 +184,12 @@ function SRS:onPieceRotate(piece, grid)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function SRS:get180RotationValue() return 3 end
|
function SRS:get180RotationValue()
|
||||||
|
if config.gamesettings.world_reverse == 1 then
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
return 3
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return SRS
|
return SRS
|
||||||
|
|
|
@ -151,7 +151,14 @@ function ARS:onPieceDrop(piece, grid)
|
||||||
piece.lock_delay = 0 -- step reset
|
piece.lock_delay = 0 -- step reset
|
||||||
end
|
end
|
||||||
|
|
||||||
function ARS:get180RotationValue() return 3 end
|
function ARS:get180RotationValue()
|
||||||
|
if config.gamesettings.world_reverse == 3 then
|
||||||
|
return 3
|
||||||
|
else
|
||||||
|
return 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function ARS:getDefaultOrientation() return 3 end -- downward facing pieces by default
|
function ARS:getDefaultOrientation() return 3 end -- downward facing pieces by default
|
||||||
|
|
||||||
return ARS
|
return ARS
|
||||||
|
|
|
@ -24,6 +24,60 @@ Ruleset.enable_IRS_wallkicks = false
|
||||||
|
|
||||||
-- Component functions.
|
-- Component functions.
|
||||||
|
|
||||||
|
function Ruleset:new()
|
||||||
|
if config.gamesettings.piece_colour == 1 then
|
||||||
|
blocks["bone"] = (not self.world) and
|
||||||
|
{
|
||||||
|
R = love.graphics.newImage("res/img/bone.png"),
|
||||||
|
O = love.graphics.newImage("res/img/bone.png"),
|
||||||
|
Y = love.graphics.newImage("res/img/bone.png"),
|
||||||
|
G = love.graphics.newImage("res/img/bone.png"),
|
||||||
|
C = love.graphics.newImage("res/img/bone.png"),
|
||||||
|
B = love.graphics.newImage("res/img/bone.png"),
|
||||||
|
M = love.graphics.newImage("res/img/bone.png"),
|
||||||
|
F = love.graphics.newImage("res/img/bone.png"),
|
||||||
|
A = love.graphics.newImage("res/img/bone.png"),
|
||||||
|
X = love.graphics.newImage("res/img/bone.png"),
|
||||||
|
} or {
|
||||||
|
R = love.graphics.newImage("res/img/bonew.png"),
|
||||||
|
O = love.graphics.newImage("res/img/bonew.png"),
|
||||||
|
Y = love.graphics.newImage("res/img/bonew.png"),
|
||||||
|
G = love.graphics.newImage("res/img/bonew.png"),
|
||||||
|
C = love.graphics.newImage("res/img/bonew.png"),
|
||||||
|
B = love.graphics.newImage("res/img/bonew.png"),
|
||||||
|
M = love.graphics.newImage("res/img/bonew.png"),
|
||||||
|
F = love.graphics.newImage("res/img/bonew.png"),
|
||||||
|
A = love.graphics.newImage("res/img/bonew.png"),
|
||||||
|
X = love.graphics.newImage("res/img/bonew.png"),
|
||||||
|
}
|
||||||
|
else
|
||||||
|
blocks["bone"] = (config.gamesettings.piece_colour == 2) and
|
||||||
|
{
|
||||||
|
R = love.graphics.newImage("res/img/bone.png"),
|
||||||
|
O = love.graphics.newImage("res/img/bone.png"),
|
||||||
|
Y = love.graphics.newImage("res/img/bone.png"),
|
||||||
|
G = love.graphics.newImage("res/img/bone.png"),
|
||||||
|
C = love.graphics.newImage("res/img/bone.png"),
|
||||||
|
B = love.graphics.newImage("res/img/bone.png"),
|
||||||
|
M = love.graphics.newImage("res/img/bone.png"),
|
||||||
|
F = love.graphics.newImage("res/img/bone.png"),
|
||||||
|
A = love.graphics.newImage("res/img/bone.png"),
|
||||||
|
X = love.graphics.newImage("res/img/bone.png"),
|
||||||
|
} or {
|
||||||
|
R = love.graphics.newImage("res/img/bonew.png"),
|
||||||
|
O = love.graphics.newImage("res/img/bonew.png"),
|
||||||
|
Y = love.graphics.newImage("res/img/bonew.png"),
|
||||||
|
G = love.graphics.newImage("res/img/bonew.png"),
|
||||||
|
C = love.graphics.newImage("res/img/bonew.png"),
|
||||||
|
B = love.graphics.newImage("res/img/bonew.png"),
|
||||||
|
M = love.graphics.newImage("res/img/bonew.png"),
|
||||||
|
F = love.graphics.newImage("res/img/bonew.png"),
|
||||||
|
A = love.graphics.newImage("res/img/bonew.png"),
|
||||||
|
X = love.graphics.newImage("res/img/bonew.png"),
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function Ruleset:rotatePiece(inputs, piece, grid, prev_inputs, initial)
|
function Ruleset:rotatePiece(inputs, piece, grid, prev_inputs, initial)
|
||||||
local new_inputs = {}
|
local new_inputs = {}
|
||||||
|
|
||||||
|
@ -53,7 +107,7 @@ function Ruleset:attemptRotate(new_inputs, piece, grid, initial)
|
||||||
end
|
end
|
||||||
|
|
||||||
if rot_dir == 0 then return end
|
if rot_dir == 0 then return end
|
||||||
if self.world and config.gamesettings.world_reverse == 2 then
|
if config.gamesettings.world_reverse == 3 or (self.world and config.gamesettings.world_reverse == 2) then
|
||||||
rot_dir = 4 - rot_dir
|
rot_dir = 4 - rot_dir
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
|
@ -18,8 +18,6 @@ SRS.colourscheme = {
|
||||||
SRS.softdrop_lock = false
|
SRS.softdrop_lock = false
|
||||||
SRS.harddrop_lock = true
|
SRS.harddrop_lock = true
|
||||||
|
|
||||||
SRS.enable_IRS_wallkicks = true
|
|
||||||
|
|
||||||
SRS.spawn_positions = {
|
SRS.spawn_positions = {
|
||||||
I = { x=5, y=4 },
|
I = { x=5, y=4 },
|
||||||
J = { x=4, y=5 },
|
J = { x=4, y=5 },
|
||||||
|
@ -187,5 +185,12 @@ function SRS:onPieceRotate(piece, grid)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function SRS:get180RotationValue() return 3 end
|
function SRS:get180RotationValue()
|
||||||
|
if config.gamesettings.world_reverse == 1 then
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
return 3
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return SRS
|
return SRS
|
||||||
|
|
|
@ -1,102 +0,0 @@
|
||||||
Piece = require("tetris.components.piece")
|
|
||||||
|
|
||||||
local BONKERS = {}
|
|
||||||
|
|
||||||
BONKERS.name = "B.O.N.K.E.R.S."
|
|
||||||
BONKERS.hash = "Bonkers"
|
|
||||||
|
|
||||||
BONKERS.spawn_positions = {
|
|
||||||
I = { x=5, y=4 },
|
|
||||||
J = { x=4, y=5 },
|
|
||||||
L = { x=4, y=5 },
|
|
||||||
O = { x=5, y=5 },
|
|
||||||
S = { x=4, y=5 },
|
|
||||||
T = { x=4, y=5 },
|
|
||||||
Z = { x=4, y=5 },
|
|
||||||
}
|
|
||||||
|
|
||||||
BONKERS.block_offsets = {
|
|
||||||
I={
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=0, y=2} },
|
|
||||||
{ {x=0, y=1}, {x=-1, y=1}, {x=-2, y=1}, {x=1, y=1} },
|
|
||||||
{ {x=-1, y=0}, {x=-1, y=-1}, {x=-1, y=1}, {x=-1, y=2} },
|
|
||||||
},
|
|
||||||
J={
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=-1, y=-1} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1} , {x=1, y=-1} },
|
|
||||||
{ {x=0, y=0}, {x=1, y=0}, {x=-1, y=0}, {x=1, y=1} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=-1}, {x=-1, y=1} },
|
|
||||||
},
|
|
||||||
L={
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=1, y=-1} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=1, y=1} },
|
|
||||||
{ {x=0, y=0}, {x=1, y=0}, {x=-1, y=0}, {x=-1, y=1} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=-1}, {x=-1, y=-1} },
|
|
||||||
},
|
|
||||||
O={
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
|
|
||||||
},
|
|
||||||
S={
|
|
||||||
{ {x=1, y=-1}, {x=0, y=-1}, {x=0, y=0}, {x=-1, y=0} },
|
|
||||||
{ {x=1, y=1}, {x=1, y=0}, {x=0, y=0}, {x=0, y=-1} },
|
|
||||||
{ {x=-1, y=1}, {x=0, y=1}, {x=0, y=0}, {x=1, y=0} },
|
|
||||||
{ {x=-1, y=-1}, {x=-1, y=0}, {x=0, y=0}, {x=0, y=1} },
|
|
||||||
},
|
|
||||||
T={
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=0, y=-1} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=1, y=0} },
|
|
||||||
{ {x=0, y=0}, {x=1, y=0}, {x=-1, y=0}, {x=0, y=1} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=-1}, {x=-1, y=0} },
|
|
||||||
},
|
|
||||||
Z={
|
|
||||||
{ {x=-1, y=-1}, {x=0, y=-1}, {x=0, y=0}, {x=1, y=0} },
|
|
||||||
{ {x=1, y=-1}, {x=1, y=0}, {x=0, y=0}, {x=0, y=1} },
|
|
||||||
{ {x=1, y=1}, {x=0, y=1}, {x=0, y=0}, {x=-1, y=0} },
|
|
||||||
{ {x=-1, y=1}, {x=-1, y=0}, {x=0, y=0}, {x=0, y=-1} },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-- Component functions.
|
|
||||||
|
|
||||||
function BONKERS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|
||||||
|
|
||||||
if piece.shape == "O" then
|
|
||||||
break
|
|
||||||
elseif piece.shape == "I" then
|
|
||||||
horizontal_kicks = {0, 1, -1, 2, -2}
|
|
||||||
else
|
|
||||||
horizontal_kicks = {0, 1, -1}
|
|
||||||
end
|
|
||||||
|
|
||||||
for y_offset = 20, new_piece.position.y - 24, -1 do
|
|
||||||
for idx, x_offset in pairs(horizontal_kicks) do
|
|
||||||
local offset = {x=x_offset, y=y_offset}
|
|
||||||
kicked_piece = new_piece:withOffset(offset)
|
|
||||||
if grid:canPlacePiece(kicked_piece) then
|
|
||||||
piece:setRelativeRotation(rot_dir)
|
|
||||||
piece:setOffset(offset)
|
|
||||||
piece.lock_delay = 0 -- rotate reset
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
function BONKERS:onPieceDrop(piece, grid)
|
|
||||||
piece.lock_delay = 0 -- step reset
|
|
||||||
end
|
|
||||||
|
|
||||||
function BONKERS:onPieceMove(piece, grid)
|
|
||||||
piece.lock_delay = 0 -- move reset
|
|
||||||
end
|
|
||||||
|
|
||||||
function BONKERS:onPieceRotate(piece, grid)
|
|
||||||
piece.lock_delay = 0 -- rotate reset
|
|
||||||
end
|
|
||||||
|
|
||||||
return BONKERS
|
|
|
@ -1,235 +0,0 @@
|
||||||
Piece = require("tetris.components.piece")
|
|
||||||
require("funcs")
|
|
||||||
|
|
||||||
local SRS = {}
|
|
||||||
|
|
||||||
SRS.name = "SHIRASE"
|
|
||||||
SRS.hash = "Shirase"
|
|
||||||
|
|
||||||
SRS.spawn_positions = {
|
|
||||||
I = { x=5, y=4 },
|
|
||||||
J = { x=4, y=5 },
|
|
||||||
L = { x=4, y=5 },
|
|
||||||
O = { x=5, y=5 },
|
|
||||||
S = { x=4, y=5 },
|
|
||||||
T = { x=4, y=5 },
|
|
||||||
Z = { x=4, y=5 },
|
|
||||||
}
|
|
||||||
|
|
||||||
SRS.block_offsets = {
|
|
||||||
I={
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=0, y=2} },
|
|
||||||
{ {x=0, y=1}, {x=-1, y=1}, {x=-2, y=1}, {x=1, y=1} },
|
|
||||||
{ {x=-1, y=0}, {x=-1, y=-1}, {x=-1, y=1}, {x=-1, y=2} },
|
|
||||||
},
|
|
||||||
J={
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=-1, y=-1} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1} , {x=1, y=-1} },
|
|
||||||
{ {x=0, y=0}, {x=1, y=0}, {x=-1, y=0}, {x=1, y=1} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=-1}, {x=-1, y=1} },
|
|
||||||
},
|
|
||||||
L={
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=1, y=-1} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=1, y=1} },
|
|
||||||
{ {x=0, y=0}, {x=1, y=0}, {x=-1, y=0}, {x=-1, y=1} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=-1}, {x=-1, y=-1} },
|
|
||||||
},
|
|
||||||
O={
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
|
|
||||||
},
|
|
||||||
S={
|
|
||||||
{ {x=1, y=-1}, {x=0, y=-1}, {x=0, y=0}, {x=-1, y=0} },
|
|
||||||
{ {x=1, y=1}, {x=1, y=0}, {x=0, y=0}, {x=0, y=-1} },
|
|
||||||
{ {x=-1, y=1}, {x=0, y=1}, {x=0, y=0}, {x=1, y=0} },
|
|
||||||
{ {x=-1, y=-1}, {x=-1, y=0}, {x=0, y=0}, {x=0, y=1} },
|
|
||||||
},
|
|
||||||
T={
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=0, y=-1} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=1, y=0} },
|
|
||||||
{ {x=0, y=0}, {x=1, y=0}, {x=-1, y=0}, {x=0, y=1} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=-1}, {x=-1, y=0} },
|
|
||||||
},
|
|
||||||
Z={
|
|
||||||
{ {x=-1, y=-1}, {x=0, y=-1}, {x=0, y=0}, {x=1, y=0} },
|
|
||||||
{ {x=1, y=-1}, {x=1, y=0}, {x=0, y=0}, {x=0, y=1} },
|
|
||||||
{ {x=1, y=1}, {x=0, y=1}, {x=0, y=0}, {x=-1, y=0} },
|
|
||||||
{ {x=-1, y=1}, {x=-1, y=0}, {x=0, y=0}, {x=0, y=-1} },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
SRS.wallkicks_3x3 = {
|
|
||||||
[0]={
|
|
||||||
[1]={{x=-1, y=0}, {x=-1, y=-1}, {x=0, y=2}, {x=-1, y=2}},
|
|
||||||
[2]={{x=0, y=1}, {x=0, y=-1}},
|
|
||||||
[3]={{x=1, y=0}, {x=1, y=-1}, {x=0, y=2}, {x=1, y=2}},
|
|
||||||
},
|
|
||||||
[1]={
|
|
||||||
[0]={{x=1, y=0}, {x=1, y=1}, {x=0, y=-2}, {x=1, y=-2}},
|
|
||||||
[2]={{x=1, y=0}, {x=1, y=1}, {x=0, y=-2}, {x=1, y=-2}},
|
|
||||||
[3]={{x=0, y=1}, {x=0, y=-1}},
|
|
||||||
},
|
|
||||||
[2]={
|
|
||||||
[0]={{x=0, y=1}, {x=0, y=-1}},
|
|
||||||
[1]={{x=-1, y=0}, {x=-1, y=-1}, {x=0, y=2}, {x=-1, y=2}},
|
|
||||||
[3]={{x=1, y=0}, {x=1, y=-1}, {x=0, y=2}, {x=1, y=2}},
|
|
||||||
},
|
|
||||||
[3]={
|
|
||||||
[0]={{x=-1, y=0}, {x=-1, y=1}, {x=0, y=-2}, {x=-1, y=-2}},
|
|
||||||
[1]={{x=0, y=1}, {x=0, y=-1}},
|
|
||||||
[2]={{x=-1, y=0}, {x=-1, y=1}, {x=0, y=-2}, {x=-1, y=-2}},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
SRS.wallkicks_line = {
|
|
||||||
[0]={
|
|
||||||
[1]={{x=-2, y=0}, {x=1, y=0}, {x=-2, y=1}, {x=1, y=-2}},
|
|
||||||
[2]={},
|
|
||||||
[3]={{x=-1, y=0}, {x=2, y=0}, {x=-1, y=-2}, {x=2, y=1}},
|
|
||||||
},
|
|
||||||
[1]={
|
|
||||||
[0]={{x=2, y=0}, {x=-1, y=0}, {x=2, y=-1}, {x=-1, y=2}},
|
|
||||||
[2]={{x=-1, y=0}, {x=2, y=0}, {x=-1, y=-2}, {x=2, y=1}},
|
|
||||||
[3]={{x=0, y=1}, {x=0, y=-1}, {x=0, y=2}, {x=0, y=-2}},
|
|
||||||
},
|
|
||||||
[2]={
|
|
||||||
[0]={},
|
|
||||||
[1]={{x=1, y=0}, {x=-2, y=0}, {x=1, y=2}, {x=-2, y=-1}},
|
|
||||||
[3]={{x=2, y=0}, {x=-1, y=0}, {x=2, y=-1}, {x=-1, y=2}},
|
|
||||||
},
|
|
||||||
[3]={
|
|
||||||
[0]={{x=1, y=0}, {x=-2, y=0}, {x=1, y=2}, {x=-2, y=-1}},
|
|
||||||
[1]={{x=0, y=1}, {x=0, y=-1}, {x=0, y=2}, {x=0, y=-2}},
|
|
||||||
[2]={{x=-2, y=0}, {x=1, y=0}, {x=-2, y=1}, {x=1, y=-2}},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
local basicOffsets = {
|
|
||||||
[0] = { x = 1, y = 0 },
|
|
||||||
[1] = { x = 0, y = 1 },
|
|
||||||
[2] = { x = -1, y = 0 },
|
|
||||||
[3] = { x = 0, y = -1 }
|
|
||||||
}
|
|
||||||
|
|
||||||
-- Component functions.
|
|
||||||
|
|
||||||
local function rotatePiece(inputs, piece, grid, prev_inputs)
|
|
||||||
local new_inputs = {}
|
|
||||||
|
|
||||||
for input, value in pairs(inputs) do
|
|
||||||
if value and not prev_inputs[input] then
|
|
||||||
new_inputs[input] = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local rot_dir = 0
|
|
||||||
if (new_inputs["rotate_left"] or new_inputs["rotate_left2"]) then
|
|
||||||
rot_dir = 3
|
|
||||||
elseif (new_inputs["rotate_right"] or new_inputs["rotate_right2"]) then
|
|
||||||
rot_dir = 1
|
|
||||||
elseif (new_inputs["rotate_180"]) then
|
|
||||||
rot_dir = 2
|
|
||||||
end
|
|
||||||
|
|
||||||
while rot_dir ~= 0 do
|
|
||||||
rotated_piece = piece:withRelativeRotation(rot_dir)
|
|
||||||
rotation_offset = vAdd(
|
|
||||||
basicOffsets[piece.rotation],
|
|
||||||
vNeg(basicOffsets[rotated_piece.rotation])
|
|
||||||
)
|
|
||||||
new_piece = rotated_piece:withOffset(rotation_offset)
|
|
||||||
|
|
||||||
if (grid:canPlacePiece(new_piece)) then
|
|
||||||
piece:setRelativeRotation(rot_dir)
|
|
||||||
piece:setOffset(rotation_offset)
|
|
||||||
piece.lock_delay = 0 -- rotate reset
|
|
||||||
break
|
|
||||||
end
|
|
||||||
|
|
||||||
if piece.shape == "I" then
|
|
||||||
kicks = SRS.wallkicks_line[piece.rotation][new_piece.rotation]
|
|
||||||
else
|
|
||||||
kicks = SRS.wallkicks_3x3[piece.rotation][new_piece.rotation]
|
|
||||||
end
|
|
||||||
|
|
||||||
for idx, offset in pairs(kicks) do
|
|
||||||
kicked_piece = new_piece:withOffset(offset)
|
|
||||||
if grid:canPlacePiece(kicked_piece) then
|
|
||||||
piece:setRelativeRotation(rot_dir)
|
|
||||||
piece:setOffset(vAdd(offset, rotation_offset))
|
|
||||||
piece.lock_delay = 0 -- rotate reset
|
|
||||||
rot_dir = 0
|
|
||||||
end
|
|
||||||
if rot_dir == 0 then
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
rot_dir = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
-- prev_inputs becomes the previous inputs
|
|
||||||
for input, value in pairs(inputs) do
|
|
||||||
prev_inputs[input] = inputs[input]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function movePiece(piece, grid, move)
|
|
||||||
if move == "left" then
|
|
||||||
if not piece:isMoveBlocked(grid, {x=-1, y=0}) then
|
|
||||||
piece.lock_delay = 0 -- move reset
|
|
||||||
end
|
|
||||||
piece:moveInGrid({x=-1, y=0}, 1, grid)
|
|
||||||
elseif move == "right" then
|
|
||||||
if not piece:isMoveBlocked(grid, {x=1, y=0}) then
|
|
||||||
piece.lock_delay = 0 -- move reset
|
|
||||||
end
|
|
||||||
piece:moveInGrid({x=1, y=0}, 1, grid)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function dropPiece(inputs, piece, grid, gravity, drop_speed, drop_locked)
|
|
||||||
local y = piece.position.y
|
|
||||||
if inputs["down"] == true and drop_locked == false then
|
|
||||||
piece:addGravity(gravity + 1, grid):lockIfBottomed(grid)
|
|
||||||
elseif inputs["up"] == true then
|
|
||||||
if piece:isDropBlocked(grid) then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
piece:dropToBottom(grid)
|
|
||||||
else
|
|
||||||
piece:addGravity(gravity, grid)
|
|
||||||
end
|
|
||||||
if piece.position.y ~= y then -- step reset
|
|
||||||
piece.lock_delay = 0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function lockPiece(piece, grid, lock_delay)
|
|
||||||
if piece:isDropBlocked(grid) and piece.lock_delay >= lock_delay then
|
|
||||||
piece.locked = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SRS.initializePiece(inputs, data, grid, gravity, prev_inputs, move, lock_delay, drop_speed, drop_locked)
|
|
||||||
local piece = Piece(shape, 0, {
|
|
||||||
x = SRS.spawn_positions[shape].x,
|
|
||||||
y = SRS.spawn_positions[shape].y
|
|
||||||
}, SRS.block_offsets, 0, 0)
|
|
||||||
-- have to copy that object otherwise it gets referenced
|
|
||||||
rotatePiece(inputs, piece, grid, {})
|
|
||||||
dropPiece(inputs, piece, grid, gravity, drop_speed, drop_locked)
|
|
||||||
return piece
|
|
||||||
end
|
|
||||||
|
|
||||||
function SRS.processPiece(inputs, piece, grid, gravity, prev_inputs, move, lock_delay, drop_speed, drop_locked)
|
|
||||||
rotatePiece(inputs, piece, grid, prev_inputs)
|
|
||||||
movePiece(piece, grid, move)
|
|
||||||
dropPiece(inputs, piece, grid, gravity, drop_speed, drop_locked)
|
|
||||||
lockPiece(piece, grid, lock_delay)
|
|
||||||
end
|
|
||||||
|
|
||||||
return SRS
|
|
|
@ -1,174 +0,0 @@
|
||||||
Piece = require("tetris.components.piece")
|
|
||||||
|
|
||||||
local BONKERS = {}
|
|
||||||
|
|
||||||
BONKERS.name = "SUPER302"
|
|
||||||
BONKERS.hash = "Super302"
|
|
||||||
|
|
||||||
BONKERS.spawn_positions = {
|
|
||||||
I = { x=5, y=4 },
|
|
||||||
J = { x=4, y=5 },
|
|
||||||
L = { x=4, y=5 },
|
|
||||||
O = { x=5, y=5 },
|
|
||||||
S = { x=4, y=5 },
|
|
||||||
T = { x=4, y=5 },
|
|
||||||
Z = { x=4, y=5 },
|
|
||||||
}
|
|
||||||
|
|
||||||
BONKERS.block_offsets = {
|
|
||||||
I={
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=0, y=2} },
|
|
||||||
{ {x=0, y=1}, {x=-1, y=1}, {x=-2, y=1}, {x=1, y=1} },
|
|
||||||
{ {x=-1, y=0}, {x=-1, y=-1}, {x=-1, y=1}, {x=-1, y=2} },
|
|
||||||
},
|
|
||||||
J={
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=-1, y=-1} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1} , {x=1, y=-1} },
|
|
||||||
{ {x=0, y=0}, {x=1, y=0}, {x=-1, y=0}, {x=1, y=1} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=-1}, {x=-1, y=1} },
|
|
||||||
},
|
|
||||||
L={
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=1, y=-1} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=1, y=1} },
|
|
||||||
{ {x=0, y=0}, {x=1, y=0}, {x=-1, y=0}, {x=-1, y=1} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=-1}, {x=-1, y=-1} },
|
|
||||||
},
|
|
||||||
O={
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
|
|
||||||
},
|
|
||||||
S={
|
|
||||||
{ {x=1, y=-1}, {x=0, y=-1}, {x=0, y=0}, {x=-1, y=0} },
|
|
||||||
{ {x=1, y=1}, {x=1, y=0}, {x=0, y=0}, {x=0, y=-1} },
|
|
||||||
{ {x=-1, y=1}, {x=0, y=1}, {x=0, y=0}, {x=1, y=0} },
|
|
||||||
{ {x=-1, y=-1}, {x=-1, y=0}, {x=0, y=0}, {x=0, y=1} },
|
|
||||||
},
|
|
||||||
T={
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=0, y=-1} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=1, y=0} },
|
|
||||||
{ {x=0, y=0}, {x=1, y=0}, {x=-1, y=0}, {x=0, y=1} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=-1}, {x=-1, y=0} },
|
|
||||||
},
|
|
||||||
Z={
|
|
||||||
{ {x=-1, y=-1}, {x=0, y=-1}, {x=0, y=0}, {x=1, y=0} },
|
|
||||||
{ {x=1, y=-1}, {x=1, y=0}, {x=0, y=0}, {x=0, y=1} },
|
|
||||||
{ {x=1, y=1}, {x=0, y=1}, {x=0, y=0}, {x=-1, y=0} },
|
|
||||||
{ {x=-1, y=1}, {x=-1, y=0}, {x=0, y=0}, {x=0, y=-1} },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-- Component functions.
|
|
||||||
|
|
||||||
local function rotatePiece(inputs, piece, grid, prev_inputs)
|
|
||||||
local new_inputs = {}
|
|
||||||
|
|
||||||
for input, value in pairs(inputs) do
|
|
||||||
if value and not prev_inputs[input] then
|
|
||||||
new_inputs[input] = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local rot_dir = 0
|
|
||||||
if (new_inputs["rotate_left"] or new_inputs["rotate_left2"]) then
|
|
||||||
rot_dir = 3
|
|
||||||
elseif (new_inputs["rotate_right"] or new_inputs["rotate_right2"]) then
|
|
||||||
rot_dir = 1
|
|
||||||
elseif (new_inputs["rotate_180"]) then
|
|
||||||
rot_dir = 2
|
|
||||||
end
|
|
||||||
|
|
||||||
while rot_dir ~= 0 do
|
|
||||||
if piece.filled then break end
|
|
||||||
|
|
||||||
new_piece = piece:withRelativeRotation(rot_dir)
|
|
||||||
|
|
||||||
if (grid:canPlacePiece(new_piece)) and piece.shape ~= "O" then
|
|
||||||
piece:setRelativeRotation(rot_dir)
|
|
||||||
piece.lock_delay = 0 -- rotate reset
|
|
||||||
else
|
|
||||||
-- set the piece to occupy the whole grid
|
|
||||||
piece.filled = true
|
|
||||||
unfilled_block_offsets = {}
|
|
||||||
for y = 4, 23 do
|
|
||||||
for x = 0, 9 do
|
|
||||||
if not grid:isOccupied(x, y) then
|
|
||||||
table.insert(unfilled_block_offsets, {x=x, y=y})
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
piece.position = {x=0, y=0}
|
|
||||||
piece.getBlockOffsets = function(piece)
|
|
||||||
return unfilled_block_offsets
|
|
||||||
end
|
|
||||||
piece.isDropBlocked = function(piece)
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
rot_dir = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
-- prev_inputs becomes the previous inputs
|
|
||||||
for input, value in pairs(inputs) do
|
|
||||||
prev_inputs[input] = inputs[input]
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function movePiece(piece, grid, move)
|
|
||||||
if move == "left" then
|
|
||||||
if not piece:isMoveBlocked(grid, {x=-1, y=0}) then
|
|
||||||
piece.lock_delay = 0 -- move reset
|
|
||||||
end
|
|
||||||
piece:moveInGrid({x=-1, y=0}, 1, grid)
|
|
||||||
elseif move == "right" then
|
|
||||||
if not piece:isMoveBlocked(grid, {x=1, y=0}) then
|
|
||||||
piece.lock_delay = 0 -- move reset
|
|
||||||
end
|
|
||||||
piece:moveInGrid({x=1, y=0}, 1, grid)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function dropPiece(inputs, piece, grid, gravity, drop_speed, drop_locked)
|
|
||||||
local y = piece.position.y
|
|
||||||
if inputs["down"] == true and drop_locked == false then
|
|
||||||
piece:addGravity(gravity + 1, grid):lockIfBottomed(grid)
|
|
||||||
elseif inputs["up"] == true then
|
|
||||||
if piece:isDropBlocked(grid) then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
piece:dropToBottom(grid)
|
|
||||||
else
|
|
||||||
piece:addGravity(gravity, grid)
|
|
||||||
end
|
|
||||||
if piece.position.y ~= y then -- step reset
|
|
||||||
piece.lock_delay = 0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local function lockPiece(piece, grid, lock_delay)
|
|
||||||
if piece:isDropBlocked(grid) and piece.lock_delay >= lock_delay then
|
|
||||||
piece.locked = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function BONKERS.initializePiece(inputs, data, grid, gravity, prev_inputs, move, lock_delay, drop_speed, drop_locked)
|
|
||||||
local piece = Piece(shape, 0, {
|
|
||||||
x = BONKERS.spawn_positions[shape].x,
|
|
||||||
y = BONKERS.spawn_positions[shape].y
|
|
||||||
}, BONKERS.block_offsets, 0, 0)
|
|
||||||
-- have to copy that object otherwise it gets referenced
|
|
||||||
rotatePiece(inputs, piece, grid, {})
|
|
||||||
dropPiece(inputs, piece, grid, gravity, drop_speed, drop_locked)
|
|
||||||
return piece
|
|
||||||
end
|
|
||||||
|
|
||||||
function BONKERS.processPiece(inputs, piece, grid, gravity, prev_inputs, move, lock_delay, drop_speed, drop_locked)
|
|
||||||
rotatePiece(inputs, piece, grid, prev_inputs)
|
|
||||||
movePiece(piece, grid, move)
|
|
||||||
dropPiece(inputs, piece, grid, gravity, drop_speed, drop_locked)
|
|
||||||
lockPiece(piece, grid, lock_delay)
|
|
||||||
end
|
|
||||||
|
|
||||||
return BONKERS
|
|
|
@ -1,133 +0,0 @@
|
||||||
local Piece = require 'tetris.components.piece'
|
|
||||||
local Ruleset = require 'tetris.rulesets.ruleset'
|
|
||||||
|
|
||||||
local Tengen = Ruleset:extend()
|
|
||||||
|
|
||||||
Tengen.name = "Tengen"
|
|
||||||
Tengen.hash = "Tengen"
|
|
||||||
|
|
||||||
Tengen.spawn_positions = {
|
|
||||||
I = { x=3, y=4 },
|
|
||||||
J = { x=4, y=4 },
|
|
||||||
L = { x=4, y=4 },
|
|
||||||
O = { x=5, y=4 },
|
|
||||||
S = { x=4, y=4 },
|
|
||||||
T = { x=4, y=4 },
|
|
||||||
Z = { x=4, y=4 },
|
|
||||||
}
|
|
||||||
|
|
||||||
Tengen.block_offsets = {
|
|
||||||
I={
|
|
||||||
{ {x=0, y=0}, {x=1, y=0}, {x=2, y=0}, {x=3, y=0} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=2}, {x=0, y=3} },
|
|
||||||
{ {x=0, y=0}, {x=1, y=0}, {x=2, y=0}, {x=3, y=0} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=2}, {x=0, y=3} },
|
|
||||||
},
|
|
||||||
J={
|
|
||||||
{ {x=0, y=0}, {x=1, y=0}, {x=2, y=0}, {x=2, y=1} },
|
|
||||||
{ {x=1, y=0}, {x=1, y=1}, {x=1, y=2}, {x=0, y=2} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=1}, {x=1, y=1}, {x=2, y=1} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=2}, {x=1, y=0} },
|
|
||||||
},
|
|
||||||
L={
|
|
||||||
{ {x=0, y=0}, {x=1, y=0}, {x=2, y=0}, {x=0, y=1} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=2}, {x=1, y=2} },
|
|
||||||
{ {x=2, y=0}, {x=0, y=1}, {x=1, y=1}, {x=2, y=1} },
|
|
||||||
{ {x=0, y=0}, {x=1, y=0}, {x=1, y=1}, {x=1, y=2} },
|
|
||||||
},
|
|
||||||
O={
|
|
||||||
{ {x=0, y=0}, {x=1, y=0}, {x=1, y=1}, {x=0, y=1} },
|
|
||||||
{ {x=0, y=0}, {x=1, y=0}, {x=1, y=1}, {x=0, y=1} },
|
|
||||||
{ {x=0, y=0}, {x=1, y=0}, {x=1, y=1}, {x=0, y=1} },
|
|
||||||
{ {x=0, y=0}, {x=1, y=0}, {x=1, y=1}, {x=0, y=1} },
|
|
||||||
},
|
|
||||||
-- up to here
|
|
||||||
S={
|
|
||||||
{ {x=0, y=0}, {x=1, y=0}, {x=2, y=0}, {x=3, y=0} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=2}, {x=0, y=3} },
|
|
||||||
{ {x=0, y=0}, {x=1, y=0}, {x=2, y=0}, {x=3, y=0} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=2}, {x=0, y=3} },
|
|
||||||
},
|
|
||||||
T={
|
|
||||||
{ {x=0, y=0}, {x=1, y=0}, {x=2, y=0}, {x=3, y=0} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=2}, {x=0, y=3} },
|
|
||||||
{ {x=0, y=0}, {x=1, y=0}, {x=2, y=0}, {x=3, y=0} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=2}, {x=0, y=3} },
|
|
||||||
},
|
|
||||||
Z={
|
|
||||||
{ {x=0, y=0}, {x=1, y=0}, {x=2, y=0}, {x=3, y=0} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=2}, {x=0, y=3} },
|
|
||||||
{ {x=0, y=0}, {x=1, y=0}, {x=2, y=0}, {x=3, y=0} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=2}, {x=0, y=3} },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
|
|
||||||
-- Component functions.
|
|
||||||
|
|
||||||
function Tengen:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|
||||||
|
|
||||||
-- O doesn't kick
|
|
||||||
if (piece.shape == "O") then return end
|
|
||||||
|
|
||||||
-- center column rule
|
|
||||||
if (
|
|
||||||
piece.shape == "J" or piece.shape == "T" or piece.shape == "L"
|
|
||||||
) and (
|
|
||||||
piece.rotation == 0 or piece.rotation == 2
|
|
||||||
) and (
|
|
||||||
grid:isOccupied(piece.position.x, piece.position.y) or
|
|
||||||
grid:isOccupied(piece.position.x, piece.position.y - 1) or
|
|
||||||
grid:isOccupied(piece.position.x, piece.position.y - 2)
|
|
||||||
) then return end
|
|
||||||
|
|
||||||
if piece.shape == "I" then
|
|
||||||
-- special kick rules for I
|
|
||||||
if new_piece.rotation == 0 or new_piece.rotation == 2 then
|
|
||||||
-- kick right, right2, left
|
|
||||||
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
|
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
|
|
||||||
self:onPieceRotate(piece, grid)
|
|
||||||
elseif grid:canPlacePiece(new_piece:withOffset({x=2, y=0})) then
|
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=2, y=0})
|
|
||||||
self:onPieceRotate(piece, grid)
|
|
||||||
elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then
|
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
|
|
||||||
self:onPieceRotate(piece, grid)
|
|
||||||
end
|
|
||||||
elseif piece:isDropBlocked(grid) and (new_piece.rotation == 1 or new_piece.rotation == 3) and piece.floorkick == 0 then
|
|
||||||
-- kick up, up2
|
|
||||||
if grid:canPlacePiece(new_piece:withOffset({x=0, y=-1})) then
|
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
|
|
||||||
self:onPieceRotate(piece, grid)
|
|
||||||
piece.floorkick = 1
|
|
||||||
elseif grid:canPlacePiece(new_piece:withOffset({x=0, y=-2})) then
|
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-2})
|
|
||||||
self:onPieceRotate(piece, grid)
|
|
||||||
piece.floorkick = 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
elseif piece.shape ~= "I" then
|
|
||||||
-- kick right, kick left
|
|
||||||
if (grid:canPlacePiece(new_piece:withOffset({x=1, y=0}))) then
|
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
|
|
||||||
elseif (grid:canPlacePiece(new_piece:withOffset({x=-1, y=0}))) then
|
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
|
|
||||||
end
|
|
||||||
else
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
function Tengen:onPieceCreate(piece, grid)
|
|
||||||
piece.floorkick = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function Tengen:onPieceDrop(piece, grid)
|
|
||||||
piece.lock_delay = 0 -- step reset
|
|
||||||
end
|
|
||||||
|
|
||||||
function Tengen:get180RotationValue() return config["reverse_rotate"] and 1 or 3 end
|
|
||||||
function Tengen:getDefaultOrientation() return 3 end -- downward facing pieces by default
|
|
||||||
|
|
||||||
return Tengen
|
|
Loading…
Reference in New Issue