mirror of
https://github.com/SashLilac/cambridge.git
synced 2025-05-13 20:21:25 -05:00
Compare commits
70 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
891f96e814 | ||
|
|
36837a3af5 | ||
|
|
01b0f9f618 | ||
|
|
7c8c5bb11d | ||
|
|
acaa6bdbbf | ||
|
|
c37757f592 | ||
|
|
905e4bcc77 | ||
|
|
d956647678 | ||
|
|
10f032b49b | ||
|
|
5590e6c89b | ||
|
|
0393396d74 | ||
|
|
8c1eaec1aa | ||
|
|
957802a78e | ||
|
|
169a4e4d2f | ||
|
|
48aee18340 | ||
|
|
7b496d9412 | ||
|
|
7abb861446 | ||
|
|
21f8769228 | ||
|
|
44423fd2e8 | ||
|
|
351fb4cfe9 | ||
|
|
103f04ceaa | ||
|
|
88d2f0d8d1 | ||
|
|
e100289c82 | ||
|
|
e38da49180 | ||
|
|
b03473d2fe | ||
|
|
cf6e0be4e7 | ||
|
|
2bc9dc179c | ||
|
|
d626926d5a | ||
|
|
721acefea0 | ||
|
|
b9b71e90bb | ||
|
|
9f61b139fd | ||
|
|
3b0fdba27d | ||
|
|
d8fad3dc37 | ||
|
|
f9368fa806 | ||
|
|
189feb1802 | ||
|
|
dc09dabacb | ||
|
|
e13278c6a8 | ||
|
|
f7f11b0e22 | ||
|
|
869a0f7ec5 | ||
|
|
10a9d97848 | ||
|
|
a470b40def | ||
|
|
fd739dcfdf | ||
|
|
e1dc01d0d0 | ||
|
|
7228707241 | ||
|
|
af86ce3a98 | ||
|
|
78ae0ae671 | ||
|
|
c614e9c4cd | ||
|
|
b27ef0e9f4 | ||
|
|
843b1e108a | ||
|
|
a8d697064c | ||
|
|
cf32474898 | ||
|
|
6a295cad59 | ||
|
|
2d80e20c82 | ||
|
|
2279c24d11 | ||
|
|
8510ad9bea | ||
|
|
6b77ad8547 | ||
|
|
6834e92674 | ||
|
|
3479374686 | ||
|
|
863c614a4c | ||
|
|
49e52c6a39 | ||
|
|
a105086ca6 | ||
|
|
1b381c4bf3 | ||
|
|
91a87fea73 | ||
|
|
28b455fcc0 | ||
|
|
2e3eff025f | ||
|
|
4670cb7c15 | ||
|
|
9b04e14388 | ||
|
|
a324e0015a | ||
|
|
d38168ca00 | ||
|
|
b0ce0f17f5 |
2
.gitignore
vendored
2
.gitignore
vendored
@@ -2,3 +2,5 @@
|
|||||||
*.love
|
*.love
|
||||||
dist/*.zip
|
dist/*.zip
|
||||||
dist/**/cambridge.exe
|
dist/**/cambridge.exe
|
||||||
|
dist/**/libs
|
||||||
|
dist/**/*.md
|
||||||
47
README.md
47
README.md
@@ -5,7 +5,7 @@ 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
|
||||||
|
|
||||||
@@ -13,9 +13,9 @@ Credits
|
|||||||
-------
|
-------
|
||||||
|
|
||||||
- [Lilla Oshisaure](https://www.youtube.com/user/LeSpyroshisaure) for being my co-dev!
|
- [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!
|
||||||
- [The Absolute Plus](https://discord.gg/6Gf2awJ) for being another source of motivation!
|
- [The Absolute Plus](https://discord.gg/6Gf2awJ) for being another source of motivation!
|
||||||
- [joezeng](https://github.com/joezeng) for the original project.
|
|
||||||
|
|
||||||
The following people in no particular order also helped with the project:
|
The following people in no particular order also helped with the project:
|
||||||
- [Hailey](https://github.com/haileylgbt)
|
- [Hailey](https://github.com/haileylgbt)
|
||||||
@@ -25,41 +25,58 @@ The following people in no particular order also helped with the project:
|
|||||||
- MattMayuga
|
- MattMayuga
|
||||||
- Kitaru
|
- Kitaru
|
||||||
- switchpalacecorner
|
- switchpalacecorner
|
||||||
|
- [sinefuse](https://github.com/sinefuse)
|
||||||
|
- [2Tie](https://github.com/2Tie)
|
||||||
|
- [nightmareci](https://github.com/nightmareci)
|
||||||
|
- [MyPasswordIsWeak](https://github.com/MyPasswordIsWeak)
|
||||||
|
- [Dr Ocelot](https://github.com/Dr-Ocelot)
|
||||||
|
|
||||||

|

|
||||||
|
|
||||||
Playing the game
|
Playing the game
|
||||||
----------------
|
----------------
|
||||||
|
|
||||||
|
### Windows
|
||||||
|
|
||||||
|
You do not need LÖVE on Windows, as it comes bundled with the program.
|
||||||
|
|
||||||
|
To get the stable release, simply download the ZIP in the latest release. All assets needed are bundled with the executable.
|
||||||
|
|
||||||
|
If you want the bleeding edge version, or want mod pack support, download [this](https://github.com/SashLilac/cambridge/archive/master.zip).
|
||||||
|
|
||||||
|
Extract the ZIP, open a Command Prompt at the folder you extracted Cambridge to, then run this command:
|
||||||
|
|
||||||
|
dist\windows\love.exe .
|
||||||
|
|
||||||
|
Alternatively, if you're on a 32-bit system, run this instead:
|
||||||
|
|
||||||
|
dist\win32\love.exe .
|
||||||
|
|
||||||
|
32-bit systems do not support rich presence integration.
|
||||||
|
|
||||||
|
Then, check the mod pack section at the bottom of this page.
|
||||||
|
|
||||||
### macOS, Linux
|
### macOS, Linux
|
||||||
|
|
||||||
If you haven't already, install `love` with your favourite package manager (Homebrew on macOS, your system's default on Linux). **Make sure you're using LÖVE 11, because it won't work with earlier versions!**
|
If you haven't already, install `love` with your favourite package manager (Homebrew on macOS, your system's default on Linux). **Make sure you're using LÖVE 11, because it won't work with earlier versions!**
|
||||||
|
|
||||||
Clone the repository in git:
|
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.
|
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!
|
||||||
|
|
||||||
## Windows
|
## Installing modpacks
|
||||||
|
|
||||||
You do not need LÖVE on Windows, as it comes bundled with the program. Download the source code ZIP in the latest release, or if you want the bleeding edge version, download [this](https://github.com/SashLilac/cambridge/archive/master.zip).
|
Simply drag your mode, ruleset, and randomizer Lua files into their respective directory, and they should appear automatically.
|
||||||
|
|
||||||
Extract the ZIP, open a Command Prompt at the folder you extracted Cambridge to, then run this command:
|
Alternatively, install [this](https://github.com/SashLilac/cambridge-modpack) mod pack to get a taste of the mod potential.
|
||||||
|
|
||||||
dist\windows\love.exe .
|
|
||||||
|
|
||||||
Alternatively, if you're on a 32-bit system, run this instead:
|
|
||||||
|
|
||||||
dist\win32\love.exe .
|
|
||||||
|
|
||||||
32-bit systems do not support rich presence integration.
|
|
||||||
|
|
||||||
License
|
License
|
||||||
-------
|
-------
|
||||||
|
|||||||
11
clean.bat
Normal file
11
clean.bat
Normal file
@@ -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
|
||||||
@@ -4,17 +4,17 @@ Game modes
|
|||||||
There are several classes of game modes. The modes that originate from other games are organized by suffix:
|
There are several classes of game modes. The modes that originate from other games are organized by suffix:
|
||||||
|
|
||||||
* The "C" series stand for "Classic" games, games that were produced before around 1992-1993 and generally have no wallkicks or lock delay.
|
* The "C" series stand for "Classic" games, games that were produced before around 1992-1993 and generally have no wallkicks or lock delay.
|
||||||
* C84 - The original version from the Electronika 60.
|
* C84 - The original version from the Electronika 60.
|
||||||
* C88 - Sega Tetris.
|
* C88 - Sega Tetris.
|
||||||
* C89 - Nintendo / NES Tetris.
|
* C89 - Nintendo / NES Tetris.
|
||||||
* The "A" series stand for "Arika" games, or games in the Tetris the Grand Master series.
|
* The "A" series stand for "Arika" games, or games in the Tetris the Grand Master series.
|
||||||
* A1 - Tetris The Grand Master (the original from 1998).
|
* A1 - Tetris The Grand Master (the original from 1998).
|
||||||
* A2 - Tetris The Absolute The Grand Master 2 PLUS.
|
* A2 - Tetris The Absolute The Grand Master 2 PLUS.
|
||||||
* A3 - Tetris The Grand Master 3 Terror-Instinct.
|
* A3 - Tetris The Grand Master 3 Terror-Instinct.
|
||||||
* AX - Tetris The Grand Master ACE (X for Xbox).
|
* AX - Tetris The Grand Master ACE (X for Xbox).
|
||||||
* The "G" series stand for "Guideline" games, or games that follow the Tetris Guideline.
|
* The "G" series stand for "Guideline" games, or games that follow the Tetris Guideline.
|
||||||
* GF - Tetris Friends (2007-2019)
|
* GF - Tetris Friends (2007-2019)
|
||||||
* GJ - Tetris Online Japan (2005-2011)
|
* GJ - Tetris Online Japan (2005-2011)
|
||||||
* N stands for Nullpomino, only used for Phantom Mania N.
|
* N stands for Nullpomino, only used for Phantom Mania N.
|
||||||
|
|
||||||
MARATHON
|
MARATHON
|
||||||
|
|||||||
14
funcs.lua
14
funcs.lua
@@ -1,11 +1,11 @@
|
|||||||
function copy(t)
|
function copy(t)
|
||||||
-- returns deep copy of t (as opposed to the shallow copy you get from var = t)
|
-- returns deep copy of t (as opposed to the shallow copy you get from var = t)
|
||||||
if type(t) ~= "table" then return t end
|
if type(t) ~= "table" then return t end
|
||||||
local meta = getmetatable(t)
|
local meta = getmetatable(t)
|
||||||
local target = {}
|
local target = {}
|
||||||
for k, v in pairs(t) do target[k] = v end
|
for k, v in pairs(t) do target[k] = v end
|
||||||
setmetatable(target, meta)
|
setmetatable(target, meta)
|
||||||
return target
|
return target
|
||||||
end
|
end
|
||||||
|
|
||||||
function strTrueValues(tbl)
|
function strTrueValues(tbl)
|
||||||
@@ -64,6 +64,6 @@ function formatBigNum(number)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Mod1(n, m)
|
function Mod1(n, m)
|
||||||
-- returns a number congruent to n modulo m in the range [1;m] (as opposed to [0;m-1])
|
-- returns a number congruent to n modulo m in the range [1;m] (as opposed to [0;m-1])
|
||||||
return ((n-1) % m) + 1
|
return ((n-1) % m) + 1
|
||||||
end
|
end
|
||||||
@@ -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))
|
||||||
|
|||||||
@@ -20,8 +20,8 @@ backgrounds = {
|
|||||||
love.graphics.newImage("res/backgrounds/1800-railways.png"),
|
love.graphics.newImage("res/backgrounds/1800-railways.png"),
|
||||||
love.graphics.newImage("res/backgrounds/1900-world-wide-web.png"),
|
love.graphics.newImage("res/backgrounds/1900-world-wide-web.png"),
|
||||||
title = love.graphics.newImage("res/backgrounds/title_v0.1.png"),
|
title = love.graphics.newImage("res/backgrounds/title_v0.1.png"),
|
||||||
input_config = love.graphics.newImage("res/backgrounds/options-pcb.png"),
|
input_config = love.graphics.newImage("res/backgrounds/options-pcb.png"),
|
||||||
game_config = love.graphics.newImage("res/backgrounds/options-gears.png"),
|
game_config = love.graphics.newImage("res/backgrounds/options-gears.png"),
|
||||||
}
|
}
|
||||||
|
|
||||||
blocks = {
|
blocks = {
|
||||||
@@ -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,29 +45,31 @@ 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"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
ColourSchemes = {
|
ColourSchemes = {
|
||||||
Arika = {
|
Arika = {
|
||||||
I = "R",
|
I = "R",
|
||||||
L = "O",
|
L = "O",
|
||||||
J = "B",
|
J = "B",
|
||||||
S = "M",
|
S = "M",
|
||||||
Z = "G",
|
Z = "G",
|
||||||
O = "Y",
|
O = "Y",
|
||||||
T = "C",
|
T = "C",
|
||||||
},
|
},
|
||||||
TTC = {
|
TTC = {
|
||||||
I = "C",
|
I = "C",
|
||||||
L = "O",
|
L = "O",
|
||||||
J = "B",
|
J = "B",
|
||||||
S = "G",
|
S = "G",
|
||||||
Z = "R",
|
Z = "R",
|
||||||
O = "Y",
|
O = "Y",
|
||||||
T = "M",
|
T = "M",
|
||||||
},
|
},
|
||||||
}
|
}
|
||||||
|
|
||||||
for name, blockset in pairs(blocks) do
|
for name, blockset in pairs(blocks) do
|
||||||
|
|||||||
74
load/rpc.lua
74
load/rpc.lua
@@ -1,58 +1,58 @@
|
|||||||
print("Loading discord RPC...")
|
print("Loading discord RPC...")
|
||||||
DiscordRPC = {
|
DiscordRPC = {
|
||||||
loaded = false
|
loaded = false
|
||||||
}
|
}
|
||||||
local success, RPC = pcall(require, "libs.discordRPC")
|
local success, RPC = pcall(require, "libs.discordRPC")
|
||||||
if success then
|
if success then
|
||||||
DiscordRPC.loaded = true
|
DiscordRPC.loaded = true
|
||||||
DiscordRPC.appId = "599778517789573120"
|
DiscordRPC.appId = "599778517789573120"
|
||||||
|
|
||||||
function RPC.ready(userId, username, discriminator, avatar)
|
function RPC.ready(userId, username, discriminator, avatar)
|
||||||
print(string.format("Discord: ready (%s, %s, %s, %s)", userId, username, discriminator, avatar))
|
print(string.format("Discord: ready (%s, %s, %s, %s)", userId, username, discriminator, avatar))
|
||||||
end
|
end
|
||||||
|
|
||||||
function RPC.disconnected(errorCode, message)
|
function RPC.disconnected(errorCode, message)
|
||||||
print(string.format("Discord: disconnected (%d: %s)", errorCode, message))
|
print(string.format("Discord: disconnected (%d: %s)", errorCode, message))
|
||||||
end
|
end
|
||||||
|
|
||||||
function RPC.errored(errorCode, message)
|
function RPC.errored(errorCode, message)
|
||||||
print(string.format("Discord: error (%d: %s)", errorCode, message))
|
print(string.format("Discord: error (%d: %s)", errorCode, message))
|
||||||
end
|
end
|
||||||
|
|
||||||
function RPC.joinGame(joinSecret)
|
function RPC.joinGame(joinSecret)
|
||||||
print(string.format("Discord: join (%s)", joinSecret))
|
print(string.format("Discord: join (%s)", joinSecret))
|
||||||
end
|
end
|
||||||
|
|
||||||
function RPC.spectateGame(spectateSecret)
|
function RPC.spectateGame(spectateSecret)
|
||||||
print(string.format("Discord: spectate (%s)", spectateSecret))
|
print(string.format("Discord: spectate (%s)", spectateSecret))
|
||||||
end
|
end
|
||||||
|
|
||||||
function RPC.joinRequest(userId, username, discriminator, avatar)
|
function RPC.joinRequest(userId, username, discriminator, avatar)
|
||||||
print(string.format("Discord: join request (%s, %s, %s, %s)", userId, username, discriminator, avatar))
|
print(string.format("Discord: join request (%s, %s, %s, %s)", userId, username, discriminator, avatar))
|
||||||
RPC.respond(userId, "yes")
|
RPC.respond(userId, "yes")
|
||||||
end
|
end
|
||||||
|
|
||||||
RPC.initialize(DiscordRPC.appId, true)
|
RPC.initialize(DiscordRPC.appId, true)
|
||||||
local now = os.time(os.date("*t"))
|
local now = os.time(os.date("*t"))
|
||||||
|
|
||||||
DiscordRPC.RPC = RPC
|
DiscordRPC.RPC = RPC
|
||||||
print("DiscordRPC successfully loaded.")
|
print("DiscordRPC successfully loaded.")
|
||||||
else
|
else
|
||||||
print("DiscordRPC failed to load!")
|
print("DiscordRPC failed to load!")
|
||||||
print(RPC)
|
print(RPC)
|
||||||
end
|
end
|
||||||
|
|
||||||
DiscordRPC.presence = {
|
DiscordRPC.presence = {
|
||||||
startTimestamp = now,
|
startTimestamp = now,
|
||||||
details = "Loading game...",
|
details = "Loading game...",
|
||||||
state = "",
|
state = "",
|
||||||
largeImageKey = "icon2",
|
largeImageKey = "icon2",
|
||||||
largeImageText = "Arcade Stacker",
|
largeImageText = "Arcade Stacker",
|
||||||
smallImageKey = "",
|
smallImageKey = "",
|
||||||
smallImageText = ""
|
smallImageText = ""
|
||||||
}
|
}
|
||||||
|
|
||||||
function DiscordRPC:update(newstuff)
|
function DiscordRPC:update(newstuff)
|
||||||
for k, v in pairs(newstuff) do self.presence[k] = v end
|
for k, v in pairs(newstuff) do self.presence[k] = v end
|
||||||
if self.loaded then self.RPC.updatePresence(self.presence) end
|
if self.loaded then self.RPC.updatePresence(self.presence) end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -14,11 +14,17 @@ sounds = {
|
|||||||
cursor_lr = love.audio.newSource("res/se/cursor_lr.wav", "static"),
|
cursor_lr = love.audio.newSource("res/se/cursor_lr.wav", "static"),
|
||||||
main_decide = love.audio.newSource("res/se/main_decide.wav", "static"),
|
main_decide = love.audio.newSource("res/se/main_decide.wav", "static"),
|
||||||
mode_decide = love.audio.newSource("res/se/mode_decide.wav", "static"),
|
mode_decide = love.audio.newSource("res/se/mode_decide.wav", "static"),
|
||||||
|
lock = love.audio.newSource("res/se/lock.wav", "static"),
|
||||||
|
hold = love.audio.newSource("res/se/hold.wav", "static"),
|
||||||
|
erase = love.audio.newSource("res/se/erase.wav", "static"),
|
||||||
|
fall = love.audio.newSource("res/se/fall.wav", "static"),
|
||||||
|
ready = love.audio.newSource("res/se/ready.wav", "static"),
|
||||||
|
go = love.audio.newSource("res/se/go.wav", "static"),
|
||||||
}
|
}
|
||||||
|
|
||||||
function playSE(sound, subsound)
|
function playSE(sound, subsound)
|
||||||
if subsound == nil then
|
if subsound == nil then
|
||||||
sounds[sound]:setVolume(0.1)
|
sounds[sound]:setVolume(0.5)
|
||||||
if sounds[sound]:isPlaying() then
|
if sounds[sound]:isPlaying() then
|
||||||
sounds[sound]:stop()
|
sounds[sound]:stop()
|
||||||
end
|
end
|
||||||
@@ -31,3 +37,19 @@ function playSE(sound, subsound)
|
|||||||
sounds[sound][subsound]:play()
|
sounds[sound][subsound]:play()
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function playSEOnce(sound, subsound)
|
||||||
|
if subsound == nil then
|
||||||
|
sounds[sound]:setVolume(0.5)
|
||||||
|
if sounds[sound]:isPlaying() then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
sounds[sound]:play()
|
||||||
|
else
|
||||||
|
sounds[sound][subsound]:setVolume(0.5)
|
||||||
|
if sounds[sound][subsound]:isPlaying() then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
sounds[sound][subsound]:play()
|
||||||
|
end
|
||||||
|
end
|
||||||
139
main.lua
139
main.lua
@@ -15,15 +15,19 @@ function love.load()
|
|||||||
|
|
||||||
love.window.setMode(love.graphics.getWidth(), love.graphics.getHeight(), {resizable = true});
|
love.window.setMode(love.graphics.getWidth(), love.graphics.getHeight(), {resizable = true});
|
||||||
|
|
||||||
if not config.gamesettings then config.gamesettings = {} end
|
if not config.gamesettings then
|
||||||
for _, option in ipairs(GameConfigScene.options) do
|
config.gamesettings = {}
|
||||||
if not config.gamesettings[option[1]] then
|
config["das_last_key"] = false
|
||||||
config.gamesettings[option[1]] = 1
|
else
|
||||||
end
|
config["das_last_key"] = config.gamesettings.das_last_key == 2
|
||||||
end
|
end
|
||||||
|
for _, option in ipairs(GameConfigScene.options) do
|
||||||
|
if not config.gamesettings[option[1]] then
|
||||||
|
config.gamesettings[option[1]] = 1
|
||||||
|
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
|
||||||
@@ -47,10 +51,10 @@ function love.load()
|
|||||||
end
|
end
|
||||||
--sort mode/rule lists
|
--sort mode/rule lists
|
||||||
local function padnum(d) return ("%03d%s"):format(#d, d) end
|
local function padnum(d) return ("%03d%s"):format(#d, d) end
|
||||||
table.sort(game_modes, function(a,b)
|
table.sort(game_modes, function(a,b)
|
||||||
return tostring(a.name):gsub("%d+",padnum) < tostring(b.name):gsub("%d+",padnum) end)
|
return tostring(a.name):gsub("%d+",padnum) < tostring(b.name):gsub("%d+",padnum) end)
|
||||||
table.sort(rulesets, function(a,b)
|
table.sort(rulesets, function(a,b)
|
||||||
return tostring(a.name):gsub("%d+",padnum) < tostring(b.name):gsub("%d+",padnum) end)
|
return tostring(a.name):gsub("%d+",padnum) < tostring(b.name):gsub("%d+",padnum) end)
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -110,13 +114,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
|
||||||
|
|
||||||
|
|||||||
2
package.bat
Normal file
2
package.bat
Normal file
@@ -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
|
||||||
26
release.bat
Normal file
26
release.bat
Normal file
@@ -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.
|
Before Width: | Height: | Size: 1.6 MiB After Width: | Height: | Size: 1.3 MiB |
BIN
res/img/s8.png
Normal file
BIN
res/img/s8.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 233 B |
Binary file not shown.
BIN
res/se/erase.wav
Normal file
BIN
res/se/erase.wav
Normal file
Binary file not shown.
BIN
res/se/fall.wav
Normal file
BIN
res/se/fall.wav
Normal file
Binary file not shown.
BIN
res/se/go.wav
Normal file
BIN
res/se/go.wav
Normal file
Binary file not shown.
BIN
res/se/hold.wav
Normal file
BIN
res/se/hold.wav
Normal file
Binary file not shown.
BIN
res/se/lock.wav
Normal file
BIN
res/se/lock.wav
Normal file
Binary file not shown.
BIN
res/se/ready.wav
Normal file
BIN
res/se/ready.wav
Normal file
Binary file not shown.
@@ -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
|
||||||
|
|||||||
@@ -7,7 +7,7 @@ function ExitScene:new()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function ExitScene:update()
|
function ExitScene:update()
|
||||||
love.event.quit()
|
love.event.quit()
|
||||||
end
|
end
|
||||||
|
|
||||||
function ExitScene:render()
|
function ExitScene:render()
|
||||||
@@ -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,30 +1,40 @@
|
|||||||
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,
|
||||||
})
|
})
|
||||||
end
|
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()
|
||||||
@@ -49,6 +59,7 @@ function GameScene:render()
|
|||||||
self.game:drawScoringInfo()
|
self.game:drawScoringInfo()
|
||||||
|
|
||||||
-- ready/go graphics
|
-- ready/go graphics
|
||||||
|
|
||||||
if self.game.ready_frames <= 100 and self.game.ready_frames > 52 then
|
if self.game.ready_frames <= 100 and self.game.ready_frames > 52 then
|
||||||
love.graphics.draw(misc_graphics["ready"], 144 - 50, 240 - 14)
|
love.graphics.draw(misc_graphics["ready"], 144 - 50, 240 - 14)
|
||||||
elseif self.game.ready_frames <= 50 and self.game.ready_frames > 2 then
|
elseif self.game.ready_frames <= 50 and self.game.ready_frames > 2 then
|
||||||
@@ -59,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
|
||||||
|
|
||||||
|
|||||||
@@ -5,10 +5,11 @@ ConfigScene.title = "Game Settings"
|
|||||||
require 'load.save'
|
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"}},
|
||||||
|
{"das_last_key", "DAS Switch", {"Default", "Instant"}}
|
||||||
}
|
}
|
||||||
local optioncount = #ConfigScene.options
|
local optioncount = #ConfigScene.options
|
||||||
|
|
||||||
@@ -18,12 +19,13 @@ function ConfigScene:new()
|
|||||||
self.highlight = 1
|
self.highlight = 1
|
||||||
|
|
||||||
DiscordRPC:update({
|
DiscordRPC:update({
|
||||||
details = "In menus",
|
details = "In menus",
|
||||||
state = "Changing game settings",
|
state = "Changing game settings",
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
function ConfigScene:update()
|
function ConfigScene:update()
|
||||||
|
config["das_last_key"] = config.gamesettings.das_last_key == 2
|
||||||
end
|
end
|
||||||
|
|
||||||
function ConfigScene:render()
|
function ConfigScene:render()
|
||||||
@@ -35,44 +37,44 @@ function ConfigScene:render()
|
|||||||
)
|
)
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_4)
|
love.graphics.setFont(font_3x5_4)
|
||||||
love.graphics.print("GAME SETTINGS", 80, 40)
|
love.graphics.print("GAME SETTINGS", 80, 40)
|
||||||
|
|
||||||
love.graphics.setColor(1, 1, 1, 0.5)
|
love.graphics.setColor(1, 1, 1, 0.5)
|
||||||
love.graphics.rectangle("fill", 20, 98 + self.highlight * 20, 170, 22)
|
love.graphics.rectangle("fill", 20, 98 + self.highlight * 20, 170, 22)
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_2)
|
love.graphics.setFont(font_3x5_2)
|
||||||
for i, option in ipairs(ConfigScene.options) do
|
for i, option in ipairs(ConfigScene.options) do
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
love.graphics.printf(option[2], 40, 100 + i * 20, 150, "left")
|
love.graphics.printf(option[2], 40, 100 + i * 20, 150, "left")
|
||||||
for j, setting in ipairs(option[3]) do
|
for j, setting in ipairs(option[3]) do
|
||||||
love.graphics.setColor(1, 1, 1, config.gamesettings[option[1]] == j and 1 or 0.5)
|
love.graphics.setColor(1, 1, 1, config.gamesettings[option[1]] == j and 1 or 0.5)
|
||||||
love.graphics.printf(setting, 100 + 110 * j, 100 + i * 20, 100, "center")
|
love.graphics.printf(setting, 100 + 110 * j, 100 + i * 20, 100, "center")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
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
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -5,28 +5,39 @@ 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",
|
||||||
"down",
|
"down",
|
||||||
"rotate_left",
|
"rotate_left",
|
||||||
"rotate_left2",
|
"rotate_left2",
|
||||||
"rotate_right",
|
"rotate_right",
|
||||||
"rotate_right2",
|
"rotate_right2",
|
||||||
"rotate_180",
|
"rotate_180",
|
||||||
"hold",
|
"hold",
|
||||||
"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 = {}
|
||||||
|
self.axis_timer = 0
|
||||||
|
|
||||||
DiscordRPC:update({
|
DiscordRPC:update({
|
||||||
details = "In menus",
|
details = "In menus",
|
||||||
state = "Changing input config",
|
state = "Changing input config",
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
function ConfigScene:update()
|
function ConfigScene:update()
|
||||||
@@ -41,39 +52,110 @@ 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
|
||||||
|
|
||||||
|
self.axis_timer = self.axis_timer + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
local function addJoystick(input, name)
|
||||||
|
if not input.joysticks then
|
||||||
|
input.joysticks = {}
|
||||||
|
end
|
||||||
|
if not input.joysticks[name] then
|
||||||
|
input.joysticks[name] = {}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function ConfigScene:onKeyPress(e)
|
function ConfigScene:onInputPress(e)
|
||||||
if self.input_state > table.getn(configurable_inputs) then
|
if e.type == "key" then
|
||||||
if e.scancode == "return" then
|
-- function keys, escape, and tab are reserved and can't be remapped
|
||||||
-- save, then load next scene
|
if e.scancode == "escape" and config.input then
|
||||||
saveConfig()
|
-- cancel only if there was an input config already
|
||||||
scene = TitleScene()
|
scene = TitleScene()
|
||||||
elseif e.scancode == "delete" or e.scancode == "backspace" then
|
elseif self.input_state > table.getn(configurable_inputs) then
|
||||||
self.input_state = 1
|
if e.scancode == "return" then
|
||||||
|
-- save new input, then load next scene
|
||||||
|
config.input = self.new_input
|
||||||
|
saveConfig()
|
||||||
|
scene = TitleScene()
|
||||||
|
elseif e.scancode == "delete" or e.scancode == "backspace" then
|
||||||
|
-- retry
|
||||||
|
self.input_state = 1
|
||||||
|
self.set_inputs = newSetInputs()
|
||||||
|
self.new_input = {}
|
||||||
|
end
|
||||||
|
elseif e.scancode == "tab" then
|
||||||
|
self.set_inputs[configurable_inputs[self.input_state]] = "skipped"
|
||||||
|
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 (e.axis ~= self.last_axis or self.axis_timer > 30) and math.abs(e.value) >= 1 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 >= 1 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 >= 1 and "positive" or "negative"] = configurable_inputs[self.input_state]
|
||||||
|
self.input_state = self.input_state + 1
|
||||||
|
self.last_axis = e.axis
|
||||||
|
self.axis_timer = 0
|
||||||
|
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
|
||||||
else
|
|
||||||
if e.scancode == "escape" then
|
|
||||||
loadSave()
|
|
||||||
scene = TitleScene()
|
|
||||||
else
|
|
||||||
config.input[configurable_inputs[self.input_state]] = e.scancode
|
|
||||||
self.input_state = self.input_state + 1
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -12,9 +12,9 @@ function ModeSelectScene:new()
|
|||||||
select = "mode",
|
select = "mode",
|
||||||
}
|
}
|
||||||
DiscordRPC:update({
|
DiscordRPC:update({
|
||||||
details = "In menus",
|
details = "In menus",
|
||||||
state = "Choosing a mode",
|
state = "Choosing a mode",
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
function ModeSelectScene:update()
|
function ModeSelectScene:update()
|
||||||
@@ -58,8 +58,8 @@ function ModeSelectScene:render()
|
|||||||
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
|
||||||
@@ -67,18 +67,17 @@ 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
|
||||||
|
|
||||||
|
|||||||
@@ -4,30 +4,30 @@ local main_menu_screens = {
|
|||||||
ModeSelectScene,
|
ModeSelectScene,
|
||||||
InputConfigScene,
|
InputConfigScene,
|
||||||
GameConfigScene,
|
GameConfigScene,
|
||||||
ExitScene,
|
ExitScene,
|
||||||
}
|
}
|
||||||
|
|
||||||
local mainmenuidle = {
|
local mainmenuidle = {
|
||||||
"Idle",
|
"Idle",
|
||||||
"On title screen",
|
"On title screen",
|
||||||
"On main menu screen",
|
"On main menu screen",
|
||||||
"Twiddling their thumbs",
|
"Twiddling their thumbs",
|
||||||
"Admiring the main menu's BG",
|
"Admiring the main menu's BG",
|
||||||
"Waiting for spring to come",
|
"Waiting for spring to come",
|
||||||
"Actually not playing",
|
"Actually not playing",
|
||||||
"Contemplating collecting stars",
|
"Contemplating collecting stars",
|
||||||
"Preparing to put the block!!",
|
"Preparing to put the block!!",
|
||||||
"Having a nap",
|
"Having a nap",
|
||||||
"In menus",
|
"In menus",
|
||||||
"Bottom text",
|
"Bottom text",
|
||||||
}
|
}
|
||||||
|
|
||||||
function TitleScene:new()
|
function TitleScene:new()
|
||||||
self.main_menu_state = 1
|
self.main_menu_state = 1
|
||||||
DiscordRPC:update({
|
DiscordRPC:update({
|
||||||
details = "In menus",
|
details = "In menus",
|
||||||
state = mainmenuidle[math.random(#mainmenuidle)],
|
state = mainmenuidle[math.random(#mainmenuidle)],
|
||||||
})
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
function TitleScene:update()
|
function TitleScene:update()
|
||||||
@@ -57,18 +57,18 @@ 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,7 +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 = "X" }
|
local block = { skin = "2tie", colour = "A" }
|
||||||
|
|
||||||
function Grid:new()
|
function Grid:new()
|
||||||
self.grid = {}
|
self.grid = {}
|
||||||
@@ -29,10 +29,10 @@ function Grid:clear()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Grid:getCell(x, y)
|
function Grid:getCell(x, y)
|
||||||
if x < 1 or x > 10 or y > 24 then return oob
|
if x < 1 or x > 10 or y > 24 then return oob
|
||||||
elseif y < 1 then return empty
|
elseif y < 1 then return empty
|
||||||
else return self.grid[y][x]
|
else return self.grid[y][x]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Grid:isOccupied(x, y)
|
function Grid:isOccupied(x, y)
|
||||||
@@ -67,11 +67,11 @@ function Grid:canPlaceBigPiece(piece)
|
|||||||
for index, offset in pairs(offsets) do
|
for index, offset in pairs(offsets) do
|
||||||
local x = piece.position.x + offset.x
|
local x = piece.position.x + offset.x
|
||||||
local y = piece.position.y + offset.y
|
local y = piece.position.y + offset.y
|
||||||
if (
|
if (
|
||||||
self:isOccupied(x * 2 + 0, y * 2 + 0)
|
self:isOccupied(x * 2 + 0, y * 2 + 0)
|
||||||
or self:isOccupied(x * 2 + 1, y * 2 + 0)
|
or self:isOccupied(x * 2 + 1, y * 2 + 0)
|
||||||
or self:isOccupied(x * 2 + 0, y * 2 + 1)
|
or self:isOccupied(x * 2 + 0, y * 2 + 1)
|
||||||
or self:isOccupied(x * 2 + 1, y * 2 + 1)
|
or self:isOccupied(x * 2 + 1, y * 2 + 1)
|
||||||
) then
|
) then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
@@ -148,28 +148,43 @@ function Grid:copyBottomRow()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Grid:garbageRise(row_vals)
|
function Grid:garbageRise(row_vals)
|
||||||
for row = 1, 23 do
|
for row = 1, 23 do
|
||||||
self.grid[row] = self.grid[row+1]
|
self.grid[row] = self.grid[row+1]
|
||||||
self.grid_age[row] = self.grid_age[row+1]
|
self.grid_age[row] = self.grid_age[row+1]
|
||||||
end
|
end
|
||||||
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] = (row_vals[col] == "e") and empty or block
|
self.grid[24][col] = (row_vals[col] == "e") and empty or block
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Grid:applyFourWide()
|
function Grid:applyFourWide()
|
||||||
for row = 1, 24 do
|
for row = 1, 24 do
|
||||||
local x = self.grid[row]
|
local x = self.grid[row]
|
||||||
x[1] = x[1]~=block and block or x[1]
|
x[1] = x[1]~=block and block or x[1]
|
||||||
x[2] = x[2]~=block and block or x[2]
|
x[2] = x[2]~=block and block or x[2]
|
||||||
x[3] = x[3]~=block and block or x[3]
|
x[3] = x[3]~=block and block or x[3]
|
||||||
x[8] = x[8]~=block and block or x[8]
|
x[8] = x[8]~=block and block or x[8]
|
||||||
x[9] = x[9]~=block and block or x[9]
|
x[9] = x[9]~=block and block or x[9]
|
||||||
x[10] = x[10]~=block and block or x[10]
|
x[10] = x[10]~=block and block or x[10]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Grid:applyCeiling(lines)
|
||||||
|
for row = 1, lines do
|
||||||
|
for col = 1, 9 do
|
||||||
|
self.grid[row][col] = block
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Grid:clearSpecificRow(row)
|
||||||
|
for col = 1, 10 do
|
||||||
|
self.grid[row][col] = empty
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function Grid:applyPiece(piece)
|
function Grid:applyPiece(piece)
|
||||||
if piece.big then
|
if piece.big then
|
||||||
self:applyBigPiece(piece)
|
self:applyBigPiece(piece)
|
||||||
@@ -195,12 +210,12 @@ function Grid:applyBigPiece(piece)
|
|||||||
y = piece.position.y + offset.y
|
y = piece.position.y + offset.y
|
||||||
for a = 1, 2 do
|
for a = 1, 2 do
|
||||||
for b = 1, 2 do
|
for b = 1, 2 do
|
||||||
if y*2+a > 0 then
|
if y*2+a > 0 then
|
||||||
self.grid[y*2+a][x*2+b] = {
|
self.grid[y*2+a][x*2+b] = {
|
||||||
skin = piece.skin,
|
skin = piece.skin,
|
||||||
colour = piece.colour
|
colour = piece.colour
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -208,45 +223,54 @@ end
|
|||||||
|
|
||||||
function Grid:checkForBravo(cleared_row_count)
|
function Grid:checkForBravo(cleared_row_count)
|
||||||
for i = 0, 23 - cleared_row_count do
|
for i = 0, 23 - cleared_row_count do
|
||||||
for j = 0, 9 do
|
for j = 0, 9 do
|
||||||
if self:isOccupied(j, i) then return false end
|
if self:isOccupied(j, i) then return false end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Grid:checkStackHeight()
|
||||||
|
for i = 0, 23 do
|
||||||
|
for j = 0, 9 do
|
||||||
|
if self:isOccupied(j, i) then return 24 - i end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
function Grid:checkSecretGrade()
|
function Grid:checkSecretGrade()
|
||||||
local sgrade = 0
|
local sgrade = 0
|
||||||
for i=23,5,-1 do
|
for i=23,5,-1 do
|
||||||
local validLine = true
|
local validLine = true
|
||||||
local emptyCell = 0
|
local emptyCell = 0
|
||||||
if i > 13 then
|
if i > 13 then
|
||||||
emptyCell = 23-i
|
emptyCell = 23-i
|
||||||
end
|
end
|
||||||
if i <= 13 then
|
if i <= 13 then
|
||||||
emptyCell = i-5
|
emptyCell = i-5
|
||||||
end
|
end
|
||||||
for j=0,9 do
|
for j=0,9 do
|
||||||
if (not self:isOccupied(j,i) and j ~= emptyCell) or (j == emptyCell and self:isOccupied(j,i)) then
|
if (not self:isOccupied(j,i) and j ~= emptyCell) or (j == emptyCell and self:isOccupied(j,i)) then
|
||||||
validLine = false
|
validLine = false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if not self:isOccupied(emptyCell,i-1) then
|
if not self:isOccupied(emptyCell,i-1) then
|
||||||
validLine = false
|
validLine = false
|
||||||
end
|
end
|
||||||
if(validLine) then
|
if(validLine) then
|
||||||
sgrade = sgrade + 1
|
sgrade = sgrade + 1
|
||||||
else
|
else
|
||||||
return sgrade
|
return sgrade
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
--[[
|
--[[
|
||||||
if(sgrade == 0) then return ""
|
if(sgrade == 0) then return ""
|
||||||
elseif(sgrade < 10) then return 10-sgrade
|
elseif(sgrade < 10) then return 10-sgrade
|
||||||
elseif(sgrade < 19) then return "S"..(sgrade-9) end
|
elseif(sgrade < 19) then return "S"..(sgrade-9) end
|
||||||
return "GM"
|
return "GM"
|
||||||
--]]
|
--]]
|
||||||
return sgrade
|
return sgrade
|
||||||
end
|
end
|
||||||
|
|
||||||
function Grid:update()
|
function Grid:update()
|
||||||
@@ -263,11 +287,15 @@ function Grid:draw()
|
|||||||
for y = 5, 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
|
else
|
||||||
love.graphics.setColor(0.5, 0.5, 0.5, 1)
|
if self.grid[y][x].skin == "bone" then
|
||||||
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
|
else
|
||||||
|
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
|
||||||
@@ -291,33 +319,60 @@ function Grid:draw()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Grid:drawInvisible(opacity_function, garbage_opacity_function)
|
function Grid:drawOutline()
|
||||||
|
for y = 5, 24 do
|
||||||
|
for x = 1, 10 do
|
||||||
|
if self.grid[y][x] ~= empty then
|
||||||
|
love.graphics.setColor(0.8, 0.8, 0.8, 1)
|
||||||
|
love.graphics.setLineWidth(1)
|
||||||
|
if y > 1 and self.grid[y-1][x] == empty then
|
||||||
|
love.graphics.line(48.0+x*16, -0.5+y*16, 64.0+x*16, -0.5+y*16)
|
||||||
|
end
|
||||||
|
if y < 24 and self.grid[y+1][x] == empty then
|
||||||
|
love.graphics.line(48.0+x*16, 16.5+y*16, 64.0+x*16, 16.5+y*16)
|
||||||
|
end
|
||||||
|
if x > 1 and self.grid[y][x-1] == empty then
|
||||||
|
love.graphics.line(47.5+x*16, -0.0+y*16, 47.5+x*16, 16.0+y*16)
|
||||||
|
end
|
||||||
|
if x < 10 and self.grid[y][x+1] == empty then
|
||||||
|
love.graphics.line(64.5+x*16, -0.0+y*16, 64.5+x*16, 16.0+y*16)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function Grid:drawInvisible(opacity_function, garbage_opacity_function, lock_flash, brightness)
|
||||||
|
lock_flash = lock_flash == nil and true or lock_flash
|
||||||
|
brightness = brightness == nil and 0.5 or brightness
|
||||||
for y = 5, 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])
|
||||||
end
|
end
|
||||||
love.graphics.setColor(0.5, 0.5, 0.5, opacity)
|
love.graphics.setColor(brightness, brightness, brightness, opacity)
|
||||||
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)
|
||||||
if opacity > 0 and self.grid[y][x].colour ~= "X" then
|
if lock_flash then
|
||||||
love.graphics.setColor(0.64, 0.64, 0.64)
|
if opacity > 0 and self.grid[y][x].colour ~= "X" then
|
||||||
love.graphics.setLineWidth(1)
|
love.graphics.setColor(0.64, 0.64, 0.64)
|
||||||
if y > 1 and self.grid[y-1][x] == empty then
|
love.graphics.setLineWidth(1)
|
||||||
love.graphics.line(48.0+x*16, -0.5+y*16, 64.0+x*16, -0.5+y*16)
|
if y > 1 and self.grid[y-1][x] == empty then
|
||||||
end
|
love.graphics.line(48.0+x*16, -0.5+y*16, 64.0+x*16, -0.5+y*16)
|
||||||
if y < 24 and self.grid[y+1][x] == empty then
|
end
|
||||||
love.graphics.line(48.0+x*16, 16.5+y*16, 64.0+x*16, 16.5+y*16)
|
if y < 24 and self.grid[y+1][x] == empty then
|
||||||
end
|
love.graphics.line(48.0+x*16, 16.5+y*16, 64.0+x*16, 16.5+y*16)
|
||||||
if x > 1 and self.grid[y][x-1] == empty then
|
end
|
||||||
love.graphics.line(47.5+x*16, -0.0+y*16, 47.5+x*16, 16.0+y*16)
|
if x > 1 and self.grid[y][x-1] == empty then
|
||||||
end
|
love.graphics.line(47.5+x*16, -0.0+y*16, 47.5+x*16, 16.0+y*16)
|
||||||
if x < 10 and self.grid[y][x+1] == empty then
|
end
|
||||||
love.graphics.line(64.5+x*16, -0.0+y*16, 64.5+x*16, 16.0+y*16)
|
if x < 10 and self.grid[y][x+1] == empty then
|
||||||
|
love.graphics.line(64.5+x*16, -0.0+y*16, 64.5+x*16, 16.0+y*16)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ function Piece:new(shape, rotation, position, block_offsets, gravity, lock_delay
|
|||||||
self.gravity = gravity
|
self.gravity = gravity
|
||||||
self.lock_delay = lock_delay
|
self.lock_delay = lock_delay
|
||||||
self.skin = skin
|
self.skin = skin
|
||||||
self.colour = colour
|
self.colour = colour
|
||||||
self.ghost = false
|
self.ghost = false
|
||||||
self.locked = false
|
self.locked = false
|
||||||
self.big = big
|
self.big = big
|
||||||
@@ -78,12 +78,15 @@ function Piece:setRelativeRotation(rot)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
function Piece:moveInGrid(step, squares, grid)
|
function Piece:moveInGrid(step, squares, grid, instant)
|
||||||
local moved = false
|
local moved = false
|
||||||
for x = 1, squares do
|
for x = 1, squares do
|
||||||
if grid:canPlacePiece(self:withOffset(step)) then
|
if grid:canPlacePiece(self:withOffset(step)) then
|
||||||
moved = true
|
moved = true
|
||||||
self:setOffset(step)
|
self:setOffset(step)
|
||||||
|
if instant then
|
||||||
|
self:dropToBottom(grid)
|
||||||
|
end
|
||||||
else
|
else
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,39 +0,0 @@
|
|||||||
require 'funcs'
|
|
||||||
|
|
||||||
local SurvivalA3Game = require 'tetris.modes.survival_a3'
|
|
||||||
|
|
||||||
local FourWideGame = SurvivalA3Game:extend()
|
|
||||||
|
|
||||||
FourWideGame.name = "4-wide Simulator"
|
|
||||||
FourWideGame.hash = "4wide"
|
|
||||||
FourWideGame.tagline = "The board has gotten narrower! Can you survive the increasing speeds?"
|
|
||||||
|
|
||||||
function FourWideGame:initialize(ruleset)
|
|
||||||
self.super:initialize(ruleset)
|
|
||||||
self.grid:applyFourWide()
|
|
||||||
end
|
|
||||||
|
|
||||||
local cleared_row_levels = {1, 2, 4, 6}
|
|
||||||
|
|
||||||
function FourWideGame:onLineClear(cleared_row_count)
|
|
||||||
if not self.clear then
|
|
||||||
local new_level = self.level + cleared_row_levels[cleared_row_count]
|
|
||||||
self:updateSectionTimes(self.level, new_level)
|
|
||||||
if new_level >= 1300 or self:hitTorikan(self.level, new_level) then
|
|
||||||
self.clear = true
|
|
||||||
if new_level >= 1300 then
|
|
||||||
self.level = 1300
|
|
||||||
self.grid:clear()
|
|
||||||
self.roll_frames = -150
|
|
||||||
else
|
|
||||||
self.game_over = true
|
|
||||||
end
|
|
||||||
else
|
|
||||||
self.level = math.min(new_level, 1300)
|
|
||||||
end
|
|
||||||
self:advanceBottomRow(-cleared_row_count)
|
|
||||||
end
|
|
||||||
self.grid:applyFourWide()
|
|
||||||
end
|
|
||||||
|
|
||||||
return FourWideGame
|
|
||||||
@@ -15,10 +15,10 @@ MarathonA2Game.tagline = "The points don't matter! Can you reach the invisible r
|
|||||||
|
|
||||||
|
|
||||||
function MarathonA2Game:new()
|
function MarathonA2Game:new()
|
||||||
self.super:new()
|
self.super:new()
|
||||||
self.big_mode = true
|
self.big_mode = true
|
||||||
self.roll_frames = 0
|
self.roll_frames = 0
|
||||||
self.combo = 1
|
self.combo = 1
|
||||||
|
|
||||||
self.grade = 0
|
self.grade = 0
|
||||||
self.grade_points = 0
|
self.grade_points = 0
|
||||||
@@ -26,75 +26,76 @@ function MarathonA2Game:new()
|
|||||||
|
|
||||||
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
|
||||||
|
|
||||||
function MarathonA2Game:getARE()
|
function MarathonA2Game:getARE()
|
||||||
if self.level < 700 then return 27
|
if self.level < 700 then return 27
|
||||||
elseif self.level < 800 then return 18
|
elseif self.level < 800 then return 18
|
||||||
else return 14 end
|
else return 14 end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA2Game:getLineARE()
|
function MarathonA2Game:getLineARE()
|
||||||
if self.level < 600 then return 27
|
if self.level < 600 then return 27
|
||||||
elseif self.level < 700 then return 18
|
elseif self.level < 700 then return 18
|
||||||
elseif self.level < 800 then return 14
|
elseif self.level < 800 then return 14
|
||||||
else return 8 end
|
else return 8 end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA2Game:getDasLimit()
|
function MarathonA2Game:getDasLimit()
|
||||||
if self.level < 500 then return 15
|
if self.level < 500 then return 15
|
||||||
elseif self.level < 900 then return 9
|
elseif self.level < 900 then return 9
|
||||||
else return 7 end
|
else return 7 end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA2Game:getLineClearDelay()
|
function MarathonA2Game:getLineClearDelay()
|
||||||
if self.level < 500 then return 40
|
if self.level < 500 then return 40
|
||||||
elseif self.level < 600 then return 25
|
elseif self.level < 600 then return 25
|
||||||
elseif self.level < 700 then return 16
|
elseif self.level < 700 then return 16
|
||||||
elseif self.level < 800 then return 12
|
elseif self.level < 800 then return 12
|
||||||
else return 6 end
|
else return 6 end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA2Game:getLockDelay()
|
function MarathonA2Game:getLockDelay()
|
||||||
if self.level < 900 then return 30
|
if self.level < 900 then return 30
|
||||||
else return 17 end
|
else return 17 end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA2Game:getGravity()
|
function MarathonA2Game:getGravity()
|
||||||
if (self.level < 30) then return 4/256
|
if (self.level < 30) then return 4/256
|
||||||
elseif (self.level < 35) then return 6/256
|
elseif (self.level < 35) then return 6/256
|
||||||
elseif (self.level < 40) then return 8/256
|
elseif (self.level < 40) then return 8/256
|
||||||
elseif (self.level < 50) then return 10/256
|
elseif (self.level < 50) then return 10/256
|
||||||
elseif (self.level < 60) then return 12/256
|
elseif (self.level < 60) then return 12/256
|
||||||
elseif (self.level < 70) then return 16/256
|
elseif (self.level < 70) then return 16/256
|
||||||
elseif (self.level < 80) then return 32/256
|
elseif (self.level < 80) then return 32/256
|
||||||
elseif (self.level < 90) then return 48/256
|
elseif (self.level < 90) then return 48/256
|
||||||
elseif (self.level < 100) then return 64/256
|
elseif (self.level < 100) then return 64/256
|
||||||
elseif (self.level < 120) then return 80/256
|
elseif (self.level < 120) then return 80/256
|
||||||
elseif (self.level < 140) then return 96/256
|
elseif (self.level < 140) then return 96/256
|
||||||
elseif (self.level < 160) then return 112/256
|
elseif (self.level < 160) then return 112/256
|
||||||
elseif (self.level < 170) then return 128/256
|
elseif (self.level < 170) then return 128/256
|
||||||
elseif (self.level < 200) then return 144/256
|
elseif (self.level < 200) then return 144/256
|
||||||
elseif (self.level < 220) then return 4/256
|
elseif (self.level < 220) then return 4/256
|
||||||
elseif (self.level < 230) then return 32/256
|
elseif (self.level < 230) then return 32/256
|
||||||
elseif (self.level < 233) then return 64/256
|
elseif (self.level < 233) then return 64/256
|
||||||
elseif (self.level < 236) then return 96/256
|
elseif (self.level < 236) then return 96/256
|
||||||
elseif (self.level < 239) then return 128/256
|
elseif (self.level < 239) then return 128/256
|
||||||
elseif (self.level < 243) then return 160/256
|
elseif (self.level < 243) then return 160/256
|
||||||
elseif (self.level < 247) then return 192/256
|
elseif (self.level < 247) then return 192/256
|
||||||
elseif (self.level < 251) then return 224/256
|
elseif (self.level < 251) then return 224/256
|
||||||
elseif (self.level < 300) then return 1
|
elseif (self.level < 300) then return 1
|
||||||
elseif (self.level < 330) then return 2
|
elseif (self.level < 330) then return 2
|
||||||
elseif (self.level < 360) then return 3
|
elseif (self.level < 360) then return 3
|
||||||
elseif (self.level < 400) then return 4
|
elseif (self.level < 400) then return 4
|
||||||
elseif (self.level < 420) then return 5
|
elseif (self.level < 420) then return 5
|
||||||
elseif (self.level < 450) then return 4
|
elseif (self.level < 450) then return 4
|
||||||
elseif (self.level < 500) then return 3
|
elseif (self.level < 500) then return 3
|
||||||
else return 20
|
else return 20
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA2Game:advanceOneFrame()
|
function MarathonA2Game:advanceOneFrame()
|
||||||
@@ -118,12 +119,14 @@ 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.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
|
||||||
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)
|
||||||
@@ -247,7 +250,7 @@ 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
|
||||||
self.grid:drawInvisible(self.rollOpacityFunction)
|
self.grid:drawInvisible(self.rollOpacityFunction, nil, false)
|
||||||
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
|
||||||
|
|||||||
@@ -1,326 +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 not self.clear then
|
|
||||||
if cleared_lines > 0 then
|
|
||||||
self.combo = self.combo + (cleared_lines - 1) * 2
|
|
||||||
self.score = self.score + (
|
|
||||||
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
|
||||||
cleared_lines * self.combo
|
|
||||||
)
|
|
||||||
else
|
|
||||||
self.combo = 1
|
|
||||||
end
|
|
||||||
self.drop_bonus = 0
|
|
||||||
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,268 +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
|
|
||||||
self.grade = self.grade + 1
|
|
||||||
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
|
|
||||||
self.grade = math.min(self.grade + 1, 4)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
self.level = math.min(new_level, 2500)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function DemonModeGame:updateScore(level, drop_bonus, cleared_lines)
|
|
||||||
if not self.clear then
|
|
||||||
if cleared_lines > 0 then
|
|
||||||
self.combo = self.combo + (cleared_lines - 1) * 2
|
|
||||||
self.score = self.score + (
|
|
||||||
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
|
||||||
cleared_lines * self.combo
|
|
||||||
)
|
|
||||||
else
|
|
||||||
self.combo = 1
|
|
||||||
end
|
|
||||||
self.drop_bonus = 0
|
|
||||||
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
|
|
||||||
@@ -1,6 +1,9 @@
|
|||||||
local Object = require 'libs.classic'
|
local Object = require 'libs.classic'
|
||||||
require 'funcs'
|
require 'funcs'
|
||||||
|
|
||||||
|
local playedReadySE = false
|
||||||
|
local playedGoSE = false
|
||||||
|
|
||||||
local Grid = require 'tetris.components.grid'
|
local Grid = require 'tetris.components.grid'
|
||||||
local Randomizer = require 'tetris.randomizers.randomizer'
|
local Randomizer = require 'tetris.randomizers.randomizer'
|
||||||
|
|
||||||
@@ -40,12 +43,14 @@ function GameMode:new()
|
|||||||
self.draw_section_times = false
|
self.draw_section_times = false
|
||||||
self.draw_secondary_section_times = false
|
self.draw_secondary_section_times = false
|
||||||
self.big_mode = false
|
self.big_mode = false
|
||||||
self.rpc_details = "In game"
|
self.irs = true
|
||||||
|
self.ihs = true
|
||||||
|
self.rpc_details = "In game"
|
||||||
-- variables related to configurable parameters
|
-- variables related to configurable parameters
|
||||||
self.drop_locked = false
|
self.drop_locked = false
|
||||||
self.hard_drop_locked = false
|
self.hard_drop_locked = false
|
||||||
self.lock_on_soft_drop = false
|
self.lock_on_soft_drop = false
|
||||||
self.lock_on_hard_drop = false
|
self.lock_on_hard_drop = false
|
||||||
self.hold_queue = nil
|
self.hold_queue = nil
|
||||||
self.held = false
|
self.held = false
|
||||||
self.section_start_time = 0
|
self.section_start_time = 0
|
||||||
@@ -72,12 +77,12 @@ end
|
|||||||
|
|
||||||
function GameMode:initialize(ruleset)
|
function GameMode:initialize(ruleset)
|
||||||
-- generate next queue
|
-- generate next queue
|
||||||
self:new()
|
self:new()
|
||||||
for i = 1, self.next_queue_length do
|
for i = 1, self.next_queue_length do
|
||||||
table.insert(self.next_queue, self:getNextPiece(ruleset))
|
table.insert(self.next_queue, self:getNextPiece(ruleset))
|
||||||
end
|
end
|
||||||
self.lock_on_soft_drop = ({ruleset.softdrop_lock, self.instant_soft_drop, false, true })[config.gamesettings.manlock]
|
self.lock_on_soft_drop = ({ruleset.softdrop_lock, self.instant_soft_drop, false, true })[config.gamesettings.manlock]
|
||||||
self.lock_on_hard_drop = ({ruleset.harddrop_lock, self.instant_hard_drop, true, false})[config.gamesettings.manlock]
|
self.lock_on_hard_drop = ({ruleset.harddrop_lock, self.instant_hard_drop, true, false})[config.gamesettings.manlock]
|
||||||
end
|
end
|
||||||
|
|
||||||
function GameMode:update(inputs, ruleset)
|
function GameMode:update(inputs, ruleset)
|
||||||
@@ -91,10 +96,20 @@ function GameMode:update(inputs, ruleset)
|
|||||||
if self.completed then return end
|
if self.completed then return end
|
||||||
|
|
||||||
-- advance one frame
|
-- advance one frame
|
||||||
if self:advanceOneFrame(inputs) == false then return end
|
if self:advanceOneFrame(inputs, ruleset) == false then return end
|
||||||
|
|
||||||
self:chargeDAS(inputs, self:getDasLimit(), self.getARR())
|
self:chargeDAS(inputs, self:getDasLimit(), self.getARR())
|
||||||
|
|
||||||
|
-- set attempt flags
|
||||||
|
if inputs["left"] or inputs["right"] then self:onAttemptPieceMove(self.piece) end
|
||||||
|
if
|
||||||
|
inputs["rotate_left"] or inputs["rotate_right"] or
|
||||||
|
inputs["rotate_left2"] or inputs["rotate_right2"] or
|
||||||
|
inputs["rotate_180"]
|
||||||
|
then
|
||||||
|
self:onAttemptPieceRotate(self.piece)
|
||||||
|
end
|
||||||
|
|
||||||
if self.piece == nil then
|
if self.piece == nil then
|
||||||
self:processDelays(inputs, ruleset)
|
self:processDelays(inputs, ruleset)
|
||||||
else
|
else
|
||||||
@@ -102,7 +117,7 @@ function GameMode:update(inputs, ruleset)
|
|||||||
self:whilePieceActive()
|
self:whilePieceActive()
|
||||||
local gravity = self:getGravity()
|
local gravity = self:getGravity()
|
||||||
|
|
||||||
if self.enable_hold and inputs["hold"] == true and self.held == false then
|
if self.enable_hold and inputs["hold"] == true and self.held == false and self.prev_inputs["hold"] == false then
|
||||||
self:hold(inputs, ruleset)
|
self:hold(inputs, ruleset)
|
||||||
self.prev_inputs = inputs
|
self.prev_inputs = inputs
|
||||||
return
|
return
|
||||||
@@ -161,6 +176,7 @@ function GameMode:update(inputs, ruleset)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if cleared_row_count > 0 then
|
if cleared_row_count > 0 then
|
||||||
|
playSE("erase")
|
||||||
self.lcd = self:getLineClearDelay()
|
self.lcd = self:getLineClearDelay()
|
||||||
self.are = self:getLineARE()
|
self.are = self:getLineARE()
|
||||||
if self.lcd == 0 then
|
if self.lcd == 0 then
|
||||||
@@ -194,10 +210,18 @@ end
|
|||||||
|
|
||||||
-- event functions
|
-- event functions
|
||||||
function GameMode:whilePieceActive() end
|
function GameMode:whilePieceActive() end
|
||||||
function GameMode:onPieceLock(piece, cleared_row_count) end
|
function GameMode:onAttemptPieceMove(piece) end
|
||||||
|
function GameMode:onAttemptPieceRotate(piece) end
|
||||||
|
function GameMode:onPieceLock(piece, cleared_row_count)
|
||||||
|
playSE("lock")
|
||||||
|
end
|
||||||
|
|
||||||
function GameMode:onLineClear(cleared_row_count) end
|
function GameMode:onLineClear(cleared_row_count) end
|
||||||
|
|
||||||
function GameMode:onPieceEnter() end
|
function GameMode:onPieceEnter() end
|
||||||
function GameMode:onHold() end
|
function GameMode:onHold()
|
||||||
|
playSE("hold")
|
||||||
|
end
|
||||||
|
|
||||||
function GameMode:onSoftDrop(dropped_row_count)
|
function GameMode:onSoftDrop(dropped_row_count)
|
||||||
self.drop_bonus = self.drop_bonus + 1 * dropped_row_count
|
self.drop_bonus = self.drop_bonus + 1 * dropped_row_count
|
||||||
@@ -211,49 +235,121 @@ function GameMode:onGameOver()
|
|||||||
switchBGM(nil)
|
switchBGM(nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
function GameMode:chargeDAS(inputs)
|
-- DAS functions
|
||||||
if inputs[self.das.direction] == true then
|
|
||||||
local das_frames = self.das.frames + 1
|
function GameMode:startRightDAS()
|
||||||
if das_frames >= self:getDasLimit() then
|
self.move = "right"
|
||||||
if self.das.direction == "left" then
|
self.das = { direction = "right", frames = 0 }
|
||||||
self.move = (self:getARR() == 0 and "speed" or "") .. "left"
|
if self:getDasLimit() == 0 then
|
||||||
self.das.frames = self:getDasLimit() - self:getARR()
|
self:continueDAS()
|
||||||
elseif self.das.direction == "right" then
|
end
|
||||||
self.move = (self:getARR() == 0 and "speed" or "") .. "right"
|
end
|
||||||
self.das.frames = self:getDasLimit() - self:getARR()
|
|
||||||
end
|
function GameMode:startLeftDAS()
|
||||||
else
|
self.move = "left"
|
||||||
self.move = "none"
|
self.das = { direction = "left", frames = 0 }
|
||||||
self.das.frames = das_frames
|
if self:getDasLimit() == 0 then
|
||||||
|
self:continueDAS()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function GameMode:continueDAS()
|
||||||
|
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
|
end
|
||||||
elseif inputs["right"] == true then
|
|
||||||
self.move = "right"
|
|
||||||
self.das = { direction = "right", frames = 0 }
|
|
||||||
elseif inputs["left"] == true then
|
|
||||||
self.move = "left"
|
|
||||||
self.das = { direction = "left", frames = 0 }
|
|
||||||
else
|
else
|
||||||
self.move = "none"
|
self.move = "none"
|
||||||
self.das = { direction = "none", frames = -1 }
|
self.das.frames = das_frames
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function GameMode:stopDAS()
|
||||||
|
self.move = "none"
|
||||||
|
self.das = { direction = "none", frames = -1 }
|
||||||
|
end
|
||||||
|
|
||||||
|
function GameMode:chargeDAS(inputs)
|
||||||
|
if config["das_last_key"] then
|
||||||
|
if inputs["right"] == true and self.das.direction ~= "right" and not self.prev_inputs["right"] then
|
||||||
|
self:startRightDAS()
|
||||||
|
elseif inputs["left"] == true and self.das.direction ~= "left" and not self.prev_inputs["left"] then
|
||||||
|
self:startLeftDAS()
|
||||||
|
elseif inputs[self.das.direction] == true then
|
||||||
|
self:continueDAS()
|
||||||
|
else
|
||||||
|
self:stopDAS()
|
||||||
|
end
|
||||||
|
else -- default behaviour, das first key pressed
|
||||||
|
if inputs[self.das.direction] == true then
|
||||||
|
self:continueDAS()
|
||||||
|
elseif inputs["right"] == true then
|
||||||
|
self:startRightDAS()
|
||||||
|
elseif inputs["left"] == true then
|
||||||
|
self:startLeftDAS()
|
||||||
|
else
|
||||||
|
self:stopDAS()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function GameMode:processDelays(inputs, ruleset, drop_speed)
|
function GameMode:processDelays(inputs, ruleset, drop_speed)
|
||||||
|
if self.ready_frames == 100 then
|
||||||
|
playedReadySE = false
|
||||||
|
playedGoSE = false
|
||||||
|
end
|
||||||
if self.ready_frames > 0 then
|
if self.ready_frames > 0 then
|
||||||
|
if not playedReadySE then
|
||||||
|
playedReadySE = true
|
||||||
|
playSEOnce("ready")
|
||||||
|
end
|
||||||
self.ready_frames = self.ready_frames - 1
|
self.ready_frames = self.ready_frames - 1
|
||||||
|
if self.ready_frames == 50 and not playedGoSE then
|
||||||
|
playedGoSE = true
|
||||||
|
playSEOnce("go")
|
||||||
|
end
|
||||||
if self.ready_frames == 0 then
|
if self.ready_frames == 0 then
|
||||||
self:initializeOrHold(inputs, ruleset)
|
self:initializeOrHold(inputs, ruleset)
|
||||||
end
|
end
|
||||||
elseif self.lcd > 0 then
|
elseif self.lcd > 0 then
|
||||||
self.lcd = self.lcd - 1
|
self.lcd = self.lcd - 1
|
||||||
|
if ruleset.are_cancel and
|
||||||
|
(self.move == "none" and not self.prev_inputs["up"] and
|
||||||
|
not self.prev_inputs["rotate_left"] and not self.prev_inputs["rotate_left2"] and
|
||||||
|
not self.prev_inputs["rotate_right"] and not self.prev_inputs["rotate_right2"] and
|
||||||
|
not self.prev_inputs["rotate_180"]) and
|
||||||
|
(inputs["left"] or inputs["right"] or inputs["up"] or
|
||||||
|
inputs["rotate_left"] or inputs["rotate_left2"] or
|
||||||
|
inputs["rotate_right"] or inputs["rotate_right2"] or
|
||||||
|
inputs["rotate_180"]) then
|
||||||
|
self.lcd = 0
|
||||||
|
self.are = 0
|
||||||
|
end
|
||||||
if self.lcd == 0 then
|
if self.lcd == 0 then
|
||||||
self.grid:clearClearedRows()
|
self.grid:clearClearedRows()
|
||||||
|
playSE("fall")
|
||||||
if self.are == 0 then
|
if self.are == 0 then
|
||||||
self:initializeOrHold(inputs, ruleset)
|
self:initializeOrHold(inputs, ruleset)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif self.are > 0 then
|
elseif self.are > 0 then
|
||||||
self.are = self.are - 1
|
self.are = self.are - 1
|
||||||
|
if ruleset.are_cancel and
|
||||||
|
(self.move == "none" and not self.prev_inputs["up"] and
|
||||||
|
not self.prev_inputs["rotate_left"] and not self.prev_inputs["rotate_left2"] and
|
||||||
|
not self.prev_inputs["rotate_right"] and not self.prev_inputs["rotate_right2"] and
|
||||||
|
not self.prev_inputs["rotate_180"]) and
|
||||||
|
(inputs["left"] or inputs["right"] or inputs["up"] or
|
||||||
|
inputs["rotate_left"] or inputs["rotate_left2"] or
|
||||||
|
inputs["rotate_right"] or inputs["rotate_right2"] or
|
||||||
|
inputs["rotate_180"]) then
|
||||||
|
self.are = 0
|
||||||
|
end
|
||||||
if self.are == 0 then
|
if self.are == 0 then
|
||||||
self:initializeOrHold(inputs, ruleset)
|
self:initializeOrHold(inputs, ruleset)
|
||||||
end
|
end
|
||||||
@@ -261,7 +357,7 @@ function GameMode:processDelays(inputs, ruleset, drop_speed)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function GameMode:initializeOrHold(inputs, ruleset)
|
function GameMode:initializeOrHold(inputs, ruleset)
|
||||||
if self.enable_hold and inputs["hold"] == true then
|
if self.ihs and self.enable_hold and inputs["hold"] == true then
|
||||||
self:hold(inputs, ruleset)
|
self:hold(inputs, ruleset)
|
||||||
else
|
else
|
||||||
self:initializeNextPiece(inputs, ruleset, self.next_queue[1])
|
self:initializeNextPiece(inputs, ruleset, self.next_queue[1])
|
||||||
@@ -301,7 +397,8 @@ function GameMode:initializeNextPiece(inputs, ruleset, piece_data, generate_next
|
|||||||
inputs, piece_data, self.grid, gravity,
|
inputs, piece_data, self.grid, gravity,
|
||||||
self.prev_inputs, self.move,
|
self.prev_inputs, self.move,
|
||||||
self:getLockDelay(), self:getDropSpeed(),
|
self:getLockDelay(), self:getDropSpeed(),
|
||||||
self.lock_drop, self.lock_hard_drop, self.big_mode
|
self.lock_drop, self.lock_hard_drop, self.big_mode,
|
||||||
|
self.irs
|
||||||
)
|
)
|
||||||
if self.lock_drop then
|
if self.lock_drop then
|
||||||
self.drop_locked = true
|
self.drop_locked = true
|
||||||
@@ -346,7 +443,7 @@ function GameMode:drawGhostPiece(ruleset)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function GameMode:drawNextQueue(ruleset)
|
function GameMode:drawNextQueue(ruleset)
|
||||||
local colourscheme = ({ruleset.colourscheme, ColourSchemes.Arika, ColourSchemes.TTC})[config.gamesettings.piece_colour]
|
local colourscheme = ({ruleset.colourscheme, ColourSchemes.Arika, ColourSchemes.TTC})[config.gamesettings.piece_colour]
|
||||||
function drawPiece(piece, skin, offsets, pos_x, pos_y)
|
function drawPiece(piece, skin, offsets, pos_x, pos_y)
|
||||||
for index, offset in pairs(offsets) do
|
for index, offset in pairs(offsets) do
|
||||||
local x = offset.x + ruleset.spawn_positions[piece].x
|
local x = offset.x + ruleset.spawn_positions[piece].x
|
||||||
@@ -365,7 +462,7 @@ function GameMode:drawNextQueue(ruleset)
|
|||||||
drawPiece(next_piece, skin, ruleset.block_offsets[next_piece][rotation], -16+i*80, -32)
|
drawPiece(next_piece, skin, ruleset.block_offsets[next_piece][rotation], -16+i*80, -32)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if self.hold_queue ~= nil then
|
if self.hold_queue ~= nil and self.enable_hold then
|
||||||
local hold_color = self.held and 0.6 or 1
|
local hold_color = self.held and 0.6 or 1
|
||||||
self:setHoldOpacity(1, hold_color)
|
self:setHoldOpacity(1, hold_color)
|
||||||
drawPiece(
|
drawPiece(
|
||||||
@@ -379,9 +476,9 @@ function GameMode:drawNextQueue(ruleset)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function GameMode:setNextOpacity(i, j)
|
function GameMode:setNextOpacity(i, j)
|
||||||
i = i ~= nil and i or 1
|
i = i ~= nil and i or 1
|
||||||
j = j ~= nil and j or 1
|
j = j ~= nil and j or 1
|
||||||
love.graphics.setColor(j, j, j, i)
|
love.graphics.setColor(j, j, j, i)
|
||||||
end
|
end
|
||||||
function GameMode:setHoldOpacity(i, j)
|
function GameMode:setHoldOpacity(i, j)
|
||||||
i = i ~= nil and i or 1
|
i = i ~= nil and i or 1
|
||||||
@@ -422,7 +519,7 @@ function GameMode:drawSectionTimes(current_section)
|
|||||||
love.graphics.printf(formatTime(self.frames - self.section_start_time), section_x, 40 + 20 * current_section, 90, "left")
|
love.graphics.printf(formatTime(self.frames - self.section_start_time), section_x, 40 + 20 * current_section, 90, "left")
|
||||||
end
|
end
|
||||||
|
|
||||||
function GameMode:drawSectionTimesWithSecondary(current_section)
|
function GameMode:drawSectionTimesWithSecondary(current_section, section_colour_function)
|
||||||
local section_x = 530
|
local section_x = 530
|
||||||
local section_secondary_x = 440
|
local section_secondary_x = 440
|
||||||
|
|
||||||
@@ -433,6 +530,9 @@ function GameMode:drawSectionTimesWithSecondary(current_section)
|
|||||||
end
|
end
|
||||||
|
|
||||||
for section, time in pairs(self.secondary_section_times) do
|
for section, time in pairs(self.secondary_section_times) do
|
||||||
|
if self.section_colour_function then
|
||||||
|
love.graphics.setColor(self:section_colour_function(section))
|
||||||
|
end
|
||||||
if section > 0 then
|
if section > 0 then
|
||||||
love.graphics.printf(formatTime(time), section_secondary_x, 40 + 20 * section, 90, "left")
|
love.graphics.printf(formatTime(time), section_secondary_x, 40 + 20 * section, 90, "left")
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,160 +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 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()
|
|
||||||
self.level = 0
|
|
||||||
IntervalTrainingGame.super:new()
|
|
||||||
self.roll_frames = 0
|
|
||||||
self.combo = 1
|
|
||||||
self.randomizer = History6RollsRandomizer()
|
|
||||||
|
|
||||||
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:initialize(ruleset)
|
|
||||||
self.section_time_limit = 1800
|
|
||||||
if ruleset.world then self.section_time_limit = 37 * 60 end
|
|
||||||
self.super.initialize(self, ruleset)
|
|
||||||
end
|
|
||||||
|
|
||||||
function IntervalTrainingGame:getARE()
|
|
||||||
return 6
|
|
||||||
end
|
|
||||||
|
|
||||||
function IntervalTrainingGame:getLineARE()
|
|
||||||
return 6
|
|
||||||
end
|
|
||||||
|
|
||||||
function IntervalTrainingGame:getDasLimit()
|
|
||||||
return 7
|
|
||||||
end
|
|
||||||
|
|
||||||
function IntervalTrainingGame:getLineClearDelay()
|
|
||||||
return 4
|
|
||||||
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
|
|
||||||
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 and 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)
|
|
||||||
local cleared_level_bonus = {1, 2, 4, 6}
|
|
||||||
if not self.clear then
|
|
||||||
local new_level = self.level + cleared_level_bonus[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
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function IntervalTrainingGame:drawGrid()
|
|
||||||
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")
|
|
||||||
if not self.clear then love.graphics.printf("TIME LEFT", 240, 250, 80, "left") end
|
|
||||||
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 time_left < frameTime(0,10) and time_left % 4 < 2 then
|
|
||||||
love.graphics.setColor(1, 0.3, 0.3, 1)
|
|
||||||
end
|
|
||||||
if not self.clear then love.graphics.printf(formatTime(time_left), 240, 270, 160, "left") end
|
|
||||||
|
|
||||||
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
|
|
||||||
@@ -41,7 +41,7 @@ function Marathon2020Game:new()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Marathon2020Game:getARE()
|
function Marathon2020Game:getARE()
|
||||||
if self.delay_level < 1 then return 27
|
if self.delay_level < 1 then return 27
|
||||||
elseif self.delay_level < 2 then return 24
|
elseif self.delay_level < 2 then return 24
|
||||||
elseif self.delay_level < 3 then return 21
|
elseif self.delay_level < 3 then return 21
|
||||||
elseif self.delay_level < 4 then return 18
|
elseif self.delay_level < 4 then return 18
|
||||||
@@ -60,7 +60,7 @@ function Marathon2020Game:getLineARE()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Marathon2020Game:getDasLimit()
|
function Marathon2020Game:getDasLimit()
|
||||||
if self.delay_level < 1 then return 15
|
if self.delay_level < 1 then return 15
|
||||||
elseif self.delay_level < 3 then return 12
|
elseif self.delay_level < 3 then return 12
|
||||||
elseif self.delay_level < 5 then return 9
|
elseif self.delay_level < 5 then return 9
|
||||||
elseif self.delay_level < 8 then return 8
|
elseif self.delay_level < 8 then return 8
|
||||||
@@ -72,7 +72,7 @@ function Marathon2020Game:getDasLimit()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Marathon2020Game:getLineClearDelay()
|
function Marathon2020Game:getLineClearDelay()
|
||||||
if self.delay_level < 1 then return 40
|
if self.delay_level < 1 then return 40
|
||||||
elseif self.delay_level < 3 then return 25
|
elseif self.delay_level < 3 then return 25
|
||||||
elseif self.delay_level < 4 then return 20
|
elseif self.delay_level < 4 then return 20
|
||||||
elseif self.delay_level < 5 then return 15
|
elseif self.delay_level < 5 then return 15
|
||||||
@@ -84,7 +84,7 @@ function Marathon2020Game:getLineClearDelay()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Marathon2020Game:getLockDelay()
|
function Marathon2020Game:getLockDelay()
|
||||||
if self.delay_level < 6 then return 30
|
if self.delay_level < 6 then return 30
|
||||||
elseif self.delay_level < 7 then return 26
|
elseif self.delay_level < 7 then return 26
|
||||||
elseif self.delay_level < 8 then return 22
|
elseif self.delay_level < 8 then return 22
|
||||||
elseif self.delay_level < 9 then return 19
|
elseif self.delay_level < 9 then return 19
|
||||||
@@ -98,35 +98,35 @@ function Marathon2020Game:getLockDelay()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Marathon2020Game:getGravity()
|
function Marathon2020Game:getGravity()
|
||||||
if self.level < 30 then return 4/256
|
if self.level < 30 then return 4/256
|
||||||
elseif self.level < 35 then return 6/256
|
elseif self.level < 35 then return 6/256
|
||||||
elseif self.level < 40 then return 8/256
|
elseif self.level < 40 then return 8/256
|
||||||
elseif self.level < 50 then return 10/256
|
elseif self.level < 50 then return 10/256
|
||||||
elseif self.level < 60 then return 12/256
|
elseif self.level < 60 then return 12/256
|
||||||
elseif self.level < 70 then return 16/256
|
elseif self.level < 70 then return 16/256
|
||||||
elseif self.level < 80 then return 32/256
|
elseif self.level < 80 then return 32/256
|
||||||
elseif self.level < 90 then return 48/256
|
elseif self.level < 90 then return 48/256
|
||||||
elseif self.level < 100 then return 64/256
|
elseif self.level < 100 then return 64/256
|
||||||
elseif self.level < 120 then return 80/256
|
elseif self.level < 120 then return 80/256
|
||||||
elseif self.level < 140 then return 96/256
|
elseif self.level < 140 then return 96/256
|
||||||
elseif self.level < 160 then return 112/256
|
elseif self.level < 160 then return 112/256
|
||||||
elseif self.level < 170 then return 128/256
|
elseif self.level < 170 then return 128/256
|
||||||
elseif self.level < 200 then return 144/256
|
elseif self.level < 200 then return 144/256
|
||||||
elseif self.level < 220 then return 4/256
|
elseif self.level < 220 then return 4/256
|
||||||
elseif self.level < 230 then return 32/256
|
elseif self.level < 230 then return 32/256
|
||||||
elseif self.level < 233 then return 64/256
|
elseif self.level < 233 then return 64/256
|
||||||
elseif self.level < 236 then return 96/256
|
elseif self.level < 236 then return 96/256
|
||||||
elseif self.level < 239 then return 128/256
|
elseif self.level < 239 then return 128/256
|
||||||
elseif self.level < 243 then return 160/256
|
elseif self.level < 243 then return 160/256
|
||||||
elseif self.level < 247 then return 192/256
|
elseif self.level < 247 then return 192/256
|
||||||
elseif self.level < 251 then return 224/256
|
elseif self.level < 251 then return 224/256
|
||||||
elseif self.level < 300 then return 1
|
elseif self.level < 300 then return 1
|
||||||
elseif self.level < 330 then return 2
|
elseif self.level < 330 then return 2
|
||||||
elseif self.level < 360 then return 3
|
elseif self.level < 360 then return 3
|
||||||
elseif self.level < 400 then return 4
|
elseif self.level < 400 then return 4
|
||||||
elseif self.level < 420 then return 5
|
elseif self.level < 420 then return 5
|
||||||
elseif self.level < 450 then return 4
|
elseif self.level < 450 then return 4
|
||||||
elseif self.level < 500 then return 3
|
elseif self.level < 500 then return 3
|
||||||
else return 20 end
|
else return 20 end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -144,6 +144,7 @@ function Marathon2020Game:advanceOneFrame()
|
|||||||
if self.roll_frames < 0 then
|
if self.roll_frames < 0 then
|
||||||
return false
|
return false
|
||||||
elseif self.roll_frames > 4000 then
|
elseif self.roll_frames > 4000 then
|
||||||
|
if self.grade >= 30 and self.section_cool_count >= 20 then self.grade = 31 end
|
||||||
self.completed = true
|
self.completed = true
|
||||||
end
|
end
|
||||||
elseif self.ready_frames == 0 then
|
elseif self.ready_frames == 0 then
|
||||||
@@ -248,6 +249,7 @@ function Marathon2020Game:updateGrade(cleared_lines)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Marathon2020Game:getTotalGrade()
|
function Marathon2020Game:getTotalGrade()
|
||||||
|
if self.grade + self.section_cool_count > 50 then return "GM" end
|
||||||
return self.grade + self.section_cool_count
|
return self.grade + self.section_cool_count
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -260,7 +262,7 @@ local function getSectionForLevel(level)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Marathon2020Game:getEndOfSectionForSection(section)
|
function Marathon2020Game:getEndOfSectionForSection(section)
|
||||||
if self.torikan_passed[900] == false and section == 10 then return 999
|
if self.torikan_passed[900] == false and section == 10 then return 999
|
||||||
elseif self.torikan_passed[1900] == false and section == 20 then return 2000
|
elseif self.torikan_passed[1900] == false and section == 20 then return 2000
|
||||||
elseif section == 20 then return 2020
|
elseif section == 20 then return 2020
|
||||||
else return section * 100 end
|
else return section * 100 end
|
||||||
@@ -303,7 +305,7 @@ function Marathon2020Game:checkClear(level)
|
|||||||
level >= 2020
|
level >= 2020
|
||||||
) then
|
) then
|
||||||
|
|
||||||
if self.torikan_passed[500] == false then self.level = 500
|
if self.torikan_passed[500] == false then self.level = 500
|
||||||
elseif self.torikan_passed[900] == false then self.level = 999
|
elseif self.torikan_passed[900] == false then self.level = 999
|
||||||
elseif self.torikan_passed[1000] == false then self.level = 1000
|
elseif self.torikan_passed[1000] == false then self.level = 1000
|
||||||
elseif self.torikan_passed[1500] == false then self.level = 1500
|
elseif self.torikan_passed[1500] == false then self.level = 1500
|
||||||
@@ -325,10 +327,10 @@ function Marathon2020Game:checkClear(level)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Marathon2020Game:updateSectionTimes(old_level, new_level)
|
function Marathon2020Game:updateSectionTimes(old_level, new_level)
|
||||||
function sectionCool()
|
function sectionCool(section)
|
||||||
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")
|
if section < 10 then table.insert(self.section_status, "cool") end
|
||||||
self.cool_timer = 300
|
self.cool_timer = 300
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -346,7 +348,7 @@ function Marathon2020Game: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
|
||||||
|
|
||||||
if section > 4 then self.delay_level = math.min(20, self.delay_level + 1) end
|
if section > 5 then self.delay_level = math.min(20, self.delay_level + 1) end
|
||||||
self:checkTorikan(section)
|
self:checkTorikan(section)
|
||||||
self:checkClear(new_level)
|
self:checkClear(new_level)
|
||||||
|
|
||||||
@@ -355,11 +357,11 @@ function Marathon2020Game:updateSectionTimes(old_level, new_level)
|
|||||||
self.secondary_section_times[section] < self.secondary_section_times[section - 1] + 120 and
|
self.secondary_section_times[section] < self.secondary_section_times[section - 1] + 120 and
|
||||||
self.secondary_section_times[section] < cool_cutoffs[section]
|
self.secondary_section_times[section] < cool_cutoffs[section]
|
||||||
) then
|
) then
|
||||||
sectionCool()
|
sectionCool(section)
|
||||||
elseif self.section_status[section - 1] == "cool" then
|
elseif self.section_status[section - 1] == "cool" then
|
||||||
table.insert(self.section_status, "none")
|
table.insert(self.section_status, "none")
|
||||||
elseif section <= 19 and self.secondary_section_times[section] < cool_cutoffs[section] then
|
elseif section <= 19 and self.secondary_section_times[section] < cool_cutoffs[section] then
|
||||||
sectionCool()
|
sectionCool(section)
|
||||||
else
|
else
|
||||||
table.insert(self.section_status, "none")
|
table.insert(self.section_status, "none")
|
||||||
end
|
end
|
||||||
@@ -392,7 +394,6 @@ Marathon2020Game.mRollOpacityFunction = function(age)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Marathon2020Game:qualifiesForMRoll()
|
function Marathon2020Game:qualifiesForMRoll()
|
||||||
return false -- until I actually have grading working
|
|
||||||
--[[
|
--[[
|
||||||
|
|
||||||
GM-roll requirements
|
GM-roll requirements
|
||||||
@@ -403,6 +404,8 @@ You qualify for the GM roll if you:
|
|||||||
- in less than 13:30.00 total.
|
- in less than 13:30.00 total.
|
||||||
|
|
||||||
]]--
|
]]--
|
||||||
|
|
||||||
|
return self.level >= 2020 and self:getTotalGrade() == 50 and self.frames <= frameTime(13,30)
|
||||||
end
|
end
|
||||||
|
|
||||||
function Marathon2020Game:drawGrid()
|
function Marathon2020Game:drawGrid()
|
||||||
@@ -420,6 +423,14 @@ function Marathon2020Game:drawGrid()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Marathon2020Game:sectionColourFunction(section)
|
||||||
|
if self.section_status[section] == "cool" then
|
||||||
|
return { 0, 1, 0, 1 }
|
||||||
|
else
|
||||||
|
return { 1, 1, 1, 1 }
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function Marathon2020Game:drawScoringInfo()
|
function Marathon2020Game:drawScoringInfo()
|
||||||
Marathon2020Game.super.drawScoringInfo(self)
|
Marathon2020Game.super.drawScoringInfo(self)
|
||||||
|
|
||||||
@@ -431,12 +442,12 @@ function Marathon2020Game:drawScoringInfo()
|
|||||||
love.graphics.printf("GRADE PTS.", text_x, 200, 90, "left")
|
love.graphics.printf("GRADE PTS.", text_x, 200, 90, "left")
|
||||||
love.graphics.printf("LEVEL", text_x, 320, 40, "left")
|
love.graphics.printf("LEVEL", text_x, 320, 40, "left")
|
||||||
|
|
||||||
self:drawSectionTimesWithSecondary(current_section)
|
self:drawSectionTimesWithSecondary(current_section, self.sectionColourFunction)
|
||||||
|
|
||||||
if (self.cool_timer > 0) then
|
if (self.cool_timer > 0) then
|
||||||
love.graphics.printf("COOL!!", 64, 400, 160, "center")
|
love.graphics.printf("COOL!!", 64, 400, 160, "center")
|
||||||
self.cool_timer = self.cool_timer - 1
|
self.cool_timer = self.cool_timer - 1
|
||||||
end
|
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")
|
||||||
|
|||||||
@@ -14,26 +14,26 @@ MarathonA1Game.tagline = "Can you score enough points to reach the title of Gran
|
|||||||
|
|
||||||
|
|
||||||
function MarathonA1Game:new()
|
function MarathonA1Game:new()
|
||||||
MarathonA1Game.super:new()
|
MarathonA1Game.super:new()
|
||||||
|
|
||||||
self.roll_frames = 0
|
self.roll_frames = 0
|
||||||
self.combo = 1
|
self.combo = 1
|
||||||
self.bravos = 0
|
self.bravos = 0
|
||||||
self.gm_conditions = {
|
self.gm_conditions = {
|
||||||
level300 = false,
|
level300 = false,
|
||||||
level500 = false,
|
level500 = false,
|
||||||
level999 = false
|
level999 = false
|
||||||
}
|
}
|
||||||
self.SGnames = {
|
self.SGnames = {
|
||||||
"9", "8", "7", "6", "5", "4", "3", "2", "1",
|
"9", "8", "7", "6", "5", "4", "3", "2", "1",
|
||||||
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
|
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
|
||||||
"GM"
|
"GM"
|
||||||
}
|
}
|
||||||
|
|
||||||
self.randomizer = History4RollsRandomizer()
|
self.randomizer = History4RollsRandomizer()
|
||||||
|
|
||||||
self.lock_drop = false
|
self.lock_drop = false
|
||||||
self.enable_hard_drop = false
|
self.enable_hard_drop = false
|
||||||
self.enable_hold = false
|
self.enable_hold = false
|
||||||
self.next_queue_length = 1
|
self.next_queue_length = 1
|
||||||
end
|
end
|
||||||
@@ -59,60 +59,60 @@ function MarathonA1Game:getLockDelay()
|
|||||||
end
|
end
|
||||||
|
|
||||||
local function getRankForScore(score)
|
local function getRankForScore(score)
|
||||||
if score < 400 then return {rank = "9", next = 400}
|
if score < 400 then return {rank = "9", next = 400}
|
||||||
elseif score < 800 then return {rank = "8", next = 800}
|
elseif score < 800 then return {rank = "8", next = 800}
|
||||||
elseif score < 1400 then return {rank = "7", next = 1400}
|
elseif score < 1400 then return {rank = "7", next = 1400}
|
||||||
elseif score < 2000 then return {rank = "6", next = 2000}
|
elseif score < 2000 then return {rank = "6", next = 2000}
|
||||||
elseif score < 3500 then return {rank = "5", next = 3500}
|
elseif score < 3500 then return {rank = "5", next = 3500}
|
||||||
elseif score < 5500 then return {rank = "4", next = 5500}
|
elseif score < 5500 then return {rank = "4", next = 5500}
|
||||||
elseif score < 8000 then return {rank = "3", next = 8000}
|
elseif score < 8000 then return {rank = "3", next = 8000}
|
||||||
elseif score < 12000 then return {rank = "2", next = 12000}
|
elseif score < 12000 then return {rank = "2", next = 12000}
|
||||||
elseif score < 16000 then return {rank = "1", next = 16000}
|
elseif score < 16000 then return {rank = "1", next = 16000}
|
||||||
elseif score < 22000 then return {rank = "S1", next = 22000}
|
elseif score < 22000 then return {rank = "S1", next = 22000}
|
||||||
elseif score < 30000 then return {rank = "S2", next = 30000}
|
elseif score < 30000 then return {rank = "S2", next = 30000}
|
||||||
elseif score < 40000 then return {rank = "S3", next = 40000}
|
elseif score < 40000 then return {rank = "S3", next = 40000}
|
||||||
elseif score < 52000 then return {rank = "S4", next = 52000}
|
elseif score < 52000 then return {rank = "S4", next = 52000}
|
||||||
elseif score < 66000 then return {rank = "S5", next = 66000}
|
elseif score < 66000 then return {rank = "S5", next = 66000}
|
||||||
elseif score < 82000 then return {rank = "S6", next = 82000}
|
elseif score < 82000 then return {rank = "S6", next = 82000}
|
||||||
elseif score < 100000 then return {rank = "S7", next = 100000}
|
elseif score < 100000 then return {rank = "S7", next = 100000}
|
||||||
elseif score < 120000 then return {rank = "S8", next = 120000}
|
elseif score < 120000 then return {rank = "S8", next = 120000}
|
||||||
else return {rank = "S9", next = "???"}
|
else return {rank = "S9", next = "???"}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA1Game:getGravity()
|
function MarathonA1Game:getGravity()
|
||||||
local level = self.level
|
local level = self.level
|
||||||
if (level < 30) then return 4/256
|
if (level < 30) then return 4/256
|
||||||
elseif (level < 35) then return 6/256
|
elseif (level < 35) then return 6/256
|
||||||
elseif (level < 40) then return 8/256
|
elseif (level < 40) then return 8/256
|
||||||
elseif (level < 50) then return 10/256
|
elseif (level < 50) then return 10/256
|
||||||
elseif (level < 60) then return 12/256
|
elseif (level < 60) then return 12/256
|
||||||
elseif (level < 70) then return 16/256
|
elseif (level < 70) then return 16/256
|
||||||
elseif (level < 80) then return 32/256
|
elseif (level < 80) then return 32/256
|
||||||
elseif (level < 90) then return 48/256
|
elseif (level < 90) then return 48/256
|
||||||
elseif (level < 100) then return 64/256
|
elseif (level < 100) then return 64/256
|
||||||
elseif (level < 120) then return 80/256
|
elseif (level < 120) then return 80/256
|
||||||
elseif (level < 140) then return 96/256
|
elseif (level < 140) then return 96/256
|
||||||
elseif (level < 160) then return 112/256
|
elseif (level < 160) then return 112/256
|
||||||
elseif (level < 170) then return 128/256
|
elseif (level < 170) then return 128/256
|
||||||
elseif (level < 200) then return 144/256
|
elseif (level < 200) then return 144/256
|
||||||
elseif (level < 220) then return 4/256
|
elseif (level < 220) then return 4/256
|
||||||
elseif (level < 230) then return 32/256
|
elseif (level < 230) then return 32/256
|
||||||
elseif (level < 233) then return 64/256
|
elseif (level < 233) then return 64/256
|
||||||
elseif (level < 236) then return 96/256
|
elseif (level < 236) then return 96/256
|
||||||
elseif (level < 239) then return 128/256
|
elseif (level < 239) then return 128/256
|
||||||
elseif (level < 243) then return 160/256
|
elseif (level < 243) then return 160/256
|
||||||
elseif (level < 247) then return 192/256
|
elseif (level < 247) then return 192/256
|
||||||
elseif (level < 251) then return 224/256
|
elseif (level < 251) then return 224/256
|
||||||
elseif (level < 300) then return 1
|
elseif (level < 300) then return 1
|
||||||
elseif (level < 330) then return 2
|
elseif (level < 330) then return 2
|
||||||
elseif (level < 360) then return 3
|
elseif (level < 360) then return 3
|
||||||
elseif (level < 400) then return 4
|
elseif (level < 400) then return 4
|
||||||
elseif (level < 420) then return 5
|
elseif (level < 420) then return 5
|
||||||
elseif (level < 450) then return 4
|
elseif (level < 450) then return 4
|
||||||
elseif (level < 500) then return 3
|
elseif (level < 500) then return 3
|
||||||
else return 20
|
else return 20
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA1Game:advanceOneFrame()
|
function MarathonA1Game:advanceOneFrame()
|
||||||
@@ -134,7 +134,7 @@ function MarathonA1Game:onPieceEnter()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA1Game:onLineClear(cleared_row_count)
|
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 new_level == 999 then
|
if new_level == 999 then
|
||||||
@@ -201,10 +201,10 @@ function MarathonA1Game:drawScoringInfo()
|
|||||||
love.graphics.printf("SCORE", 240, 200, 40, "left")
|
love.graphics.printf("SCORE", 240, 200, 40, "left")
|
||||||
love.graphics.printf("NEXT RANK", 240, 260, 90, "left")
|
love.graphics.printf("NEXT RANK", 240, 260, 90, "left")
|
||||||
love.graphics.printf("LEVEL", 240, 320, 40, "left")
|
love.graphics.printf("LEVEL", 240, 320, 40, "left")
|
||||||
local sg = self.grid:checkSecretGrade()
|
local sg = self.grid:checkSecretGrade()
|
||||||
if sg >= 5 then
|
if sg >= 5 then
|
||||||
love.graphics.printf("SECRET GRADE", 240, 430, 180, "left")
|
love.graphics.printf("SECRET GRADE", 240, 430, 180, "left")
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.bravos > 0 then love.graphics.printf("BRAVO", 300, 120, 40, "left") end
|
if self.bravos > 0 then love.graphics.printf("BRAVO", 300, 120, 40, "left") end
|
||||||
|
|
||||||
@@ -218,9 +218,9 @@ function MarathonA1Game:drawScoringInfo()
|
|||||||
love.graphics.printf(getRankForScore(self.score).next, 240, 280, 90, "left")
|
love.graphics.printf(getRankForScore(self.score).next, 240, 280, 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")
|
||||||
if sg >= 5 then
|
if sg >= 5 then
|
||||||
love.graphics.printf(self.SGnames[sg], 240, 450, 180, "left")
|
love.graphics.printf(self.SGnames[sg], 240, 450, 180, "left")
|
||||||
end
|
end
|
||||||
if self.bravos > 0 then love.graphics.printf(self.bravos, 300, 140, 40, "left") end
|
if self.bravos > 0 then love.graphics.printf(self.bravos, 300, 140, 40, "left") end
|
||||||
|
|
||||||
love.graphics.setFont(font_8x11)
|
love.graphics.setFont(font_8x11)
|
||||||
|
|||||||
@@ -15,10 +15,10 @@ MarathonA2Game.tagline = "The points don't matter! Can you reach the invisible r
|
|||||||
|
|
||||||
|
|
||||||
function MarathonA2Game:new()
|
function MarathonA2Game:new()
|
||||||
MarathonA2Game.super:new()
|
MarathonA2Game.super:new()
|
||||||
|
|
||||||
self.roll_frames = 0
|
self.roll_frames = 0
|
||||||
self.combo = 1
|
self.combo = 1
|
||||||
self.randomizer = History6RollsRandomizer()
|
self.randomizer = History6RollsRandomizer()
|
||||||
self.grade = 0
|
self.grade = 0
|
||||||
self.grade_points = 0
|
self.grade_points = 0
|
||||||
@@ -27,81 +27,82 @@ function MarathonA2Game:new()
|
|||||||
self.section_times = { [0] = 0 }
|
self.section_times = { [0] = 0 }
|
||||||
self.section_tetrises = { [0] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
|
self.section_tetrises = { [0] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
|
||||||
|
|
||||||
self.SGnames = {
|
self.SGnames = {
|
||||||
"9", "8", "7", "6", "5", "4", "3", "2", "1",
|
"9", "8", "7", "6", "5", "4", "3", "2", "1",
|
||||||
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
|
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
|
||||||
"GM"
|
"GM"
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
function MarathonA2Game:getARE()
|
function MarathonA2Game:getARE()
|
||||||
if self.level < 700 then return 27
|
if self.level < 700 then return 27
|
||||||
elseif self.level < 800 then return 18
|
elseif self.level < 800 then return 18
|
||||||
else return 14 end
|
else return 14 end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA2Game:getLineARE()
|
function MarathonA2Game:getLineARE()
|
||||||
if self.level < 600 then return 27
|
if self.level < 600 then return 27
|
||||||
elseif self.level < 700 then return 18
|
elseif self.level < 700 then return 18
|
||||||
elseif self.level < 800 then return 14
|
elseif self.level < 800 then return 14
|
||||||
else return 8 end
|
else return 8 end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA2Game:getDasLimit()
|
function MarathonA2Game:getDasLimit()
|
||||||
if self.level < 500 then return 15
|
if self.level < 500 then return 15
|
||||||
elseif self.level < 900 then return 9
|
elseif self.level < 900 then return 9
|
||||||
else return 7 end
|
else return 7 end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA2Game:getLineClearDelay()
|
function MarathonA2Game:getLineClearDelay()
|
||||||
if self.level < 500 then return 40
|
if self.level < 500 then return 40
|
||||||
elseif self.level < 600 then return 25
|
elseif self.level < 600 then return 25
|
||||||
elseif self.level < 700 then return 16
|
elseif self.level < 700 then return 16
|
||||||
elseif self.level < 800 then return 12
|
elseif self.level < 800 then return 12
|
||||||
else return 6 end
|
else return 6 end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA2Game:getLockDelay()
|
function MarathonA2Game:getLockDelay()
|
||||||
if self.level < 900 then return 30
|
if self.level < 900 then return 30
|
||||||
else return 17 end
|
else return 17 end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA2Game:getGravity()
|
function MarathonA2Game:getGravity()
|
||||||
if (self.level < 30) then return 4/256
|
if (self.level < 30) then return 4/256
|
||||||
elseif (self.level < 35) then return 6/256
|
elseif (self.level < 35) then return 6/256
|
||||||
elseif (self.level < 40) then return 8/256
|
elseif (self.level < 40) then return 8/256
|
||||||
elseif (self.level < 50) then return 10/256
|
elseif (self.level < 50) then return 10/256
|
||||||
elseif (self.level < 60) then return 12/256
|
elseif (self.level < 60) then return 12/256
|
||||||
elseif (self.level < 70) then return 16/256
|
elseif (self.level < 70) then return 16/256
|
||||||
elseif (self.level < 80) then return 32/256
|
elseif (self.level < 80) then return 32/256
|
||||||
elseif (self.level < 90) then return 48/256
|
elseif (self.level < 90) then return 48/256
|
||||||
elseif (self.level < 100) then return 64/256
|
elseif (self.level < 100) then return 64/256
|
||||||
elseif (self.level < 120) then return 80/256
|
elseif (self.level < 120) then return 80/256
|
||||||
elseif (self.level < 140) then return 96/256
|
elseif (self.level < 140) then return 96/256
|
||||||
elseif (self.level < 160) then return 112/256
|
elseif (self.level < 160) then return 112/256
|
||||||
elseif (self.level < 170) then return 128/256
|
elseif (self.level < 170) then return 128/256
|
||||||
elseif (self.level < 200) then return 144/256
|
elseif (self.level < 200) then return 144/256
|
||||||
elseif (self.level < 220) then return 4/256
|
elseif (self.level < 220) then return 4/256
|
||||||
elseif (self.level < 230) then return 32/256
|
elseif (self.level < 230) then return 32/256
|
||||||
elseif (self.level < 233) then return 64/256
|
elseif (self.level < 233) then return 64/256
|
||||||
elseif (self.level < 236) then return 96/256
|
elseif (self.level < 236) then return 96/256
|
||||||
elseif (self.level < 239) then return 128/256
|
elseif (self.level < 239) then return 128/256
|
||||||
elseif (self.level < 243) then return 160/256
|
elseif (self.level < 243) then return 160/256
|
||||||
elseif (self.level < 247) then return 192/256
|
elseif (self.level < 247) then return 192/256
|
||||||
elseif (self.level < 251) then return 224/256
|
elseif (self.level < 251) then return 224/256
|
||||||
elseif (self.level < 300) then return 1
|
elseif (self.level < 300) then return 1
|
||||||
elseif (self.level < 330) then return 2
|
elseif (self.level < 330) then return 2
|
||||||
elseif (self.level < 360) then return 3
|
elseif (self.level < 360) then return 3
|
||||||
elseif (self.level < 400) then return 4
|
elseif (self.level < 400) then return 4
|
||||||
elseif (self.level < 420) then return 5
|
elseif (self.level < 420) then return 5
|
||||||
elseif (self.level < 450) then return 4
|
elseif (self.level < 450) then return 4
|
||||||
elseif (self.level < 500) then return 3
|
elseif (self.level < 500) then return 3
|
||||||
else return 20
|
else return 20
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA2Game:advanceOneFrame()
|
function MarathonA2Game:advanceOneFrame()
|
||||||
@@ -144,13 +145,15 @@ function MarathonA2Game:updateScore(level, drop_bonus, cleared_lines)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA2Game:onLineClear(cleared_row_count)
|
function MarathonA2Game:onLineClear(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
|
||||||
self.grid:clear()
|
self.grid:clear()
|
||||||
if self:qualifiesForMRoll() then self.grade = 32 end
|
if self:qualifiesForMRoll() then self.grade = 32 end
|
||||||
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:updateSectionTimes(old_level, new_level)
|
function MarathonA2Game:updateSectionTimes(old_level, new_level)
|
||||||
@@ -307,12 +310,12 @@ MarathonA2Game.mRollOpacityFunction = function(age)
|
|||||||
else return 1 - age / 4 end
|
else return 1 - age / 4 end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA2Game:drawGrid(ruleset)
|
function MarathonA2Game:drawGrid()
|
||||||
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
|
if self:qualifiesForMRoll() then
|
||||||
self.grid:drawInvisible(self.mRollOpacityFunction)
|
self.grid:drawInvisible(self.mRollOpacityFunction, nil, false)
|
||||||
else
|
else
|
||||||
self.grid:drawInvisible(self.rollOpacityFunction)
|
self.grid:drawInvisible(self.rollOpacityFunction, nil, false)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self.grid:draw()
|
self.grid:draw()
|
||||||
@@ -335,10 +338,10 @@ function MarathonA2Game:drawScoringInfo()
|
|||||||
love.graphics.printf("GRADE", 240, 120, 40, "left")
|
love.graphics.printf("GRADE", 240, 120, 40, "left")
|
||||||
love.graphics.printf("SCORE", 240, 200, 40, "left")
|
love.graphics.printf("SCORE", 240, 200, 40, "left")
|
||||||
love.graphics.printf("LEVEL", 240, 320, 40, "left")
|
love.graphics.printf("LEVEL", 240, 320, 40, "left")
|
||||||
local sg = self.grid:checkSecretGrade()
|
local sg = self.grid:checkSecretGrade()
|
||||||
if sg >= 5 then
|
if sg >= 5 then
|
||||||
love.graphics.printf("SECRET GRADE", 240, 430, 180, "left")
|
love.graphics.printf("SECRET GRADE", 240, 430, 180, "left")
|
||||||
end
|
end
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
love.graphics.setFont(font_3x5_3)
|
||||||
if self.clear then
|
if self.clear then
|
||||||
@@ -355,9 +358,9 @@ function MarathonA2Game:drawScoringInfo()
|
|||||||
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")
|
||||||
if sg >= 5 then
|
if sg >= 5 then
|
||||||
love.graphics.printf(self.SGnames[sg], 240, 450, 180, "left")
|
love.graphics.printf(self.SGnames[sg], 240, 450, 180, "left")
|
||||||
end
|
end
|
||||||
|
|
||||||
love.graphics.setFont(font_8x11)
|
love.graphics.setFont(font_8x11)
|
||||||
love.graphics.printf(formatTime(self.frames), 64, 420, 160, "center")
|
love.graphics.printf(formatTime(self.frames), 64, 420, 160, "center")
|
||||||
|
|||||||
@@ -15,11 +15,11 @@ MarathonA3Game.tagline = "The game gets faster way more quickly! Can you get all
|
|||||||
|
|
||||||
|
|
||||||
function MarathonA3Game:new()
|
function MarathonA3Game:new()
|
||||||
MarathonA3Game.super:new()
|
MarathonA3Game.super:new()
|
||||||
|
|
||||||
self.speed_level = 0
|
self.speed_level = 0
|
||||||
self.roll_frames = 0
|
self.roll_frames = 0
|
||||||
self.combo = 1
|
self.combo = 1
|
||||||
self.grade = 0
|
self.grade = 0
|
||||||
self.grade_points = 0
|
self.grade_points = 0
|
||||||
self.roll_points = 0
|
self.roll_points = 0
|
||||||
@@ -34,13 +34,13 @@ function MarathonA3Game:new()
|
|||||||
self.randomizer = History6RollsRandomizer()
|
self.randomizer = History6RollsRandomizer()
|
||||||
|
|
||||||
self.SGnames = {
|
self.SGnames = {
|
||||||
"9", "8", "7", "6", "5", "4", "3", "2", "1",
|
"9", "8", "7", "6", "5", "4", "3", "2", "1",
|
||||||
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
|
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
|
||||||
"GM"
|
"GM"
|
||||||
}
|
}
|
||||||
|
|
||||||
self.lock_drop = true
|
self.lock_drop = true
|
||||||
self.lock_hard_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
|
||||||
|
|
||||||
@@ -51,77 +51,77 @@ self.SGnames = {
|
|||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA3Game:getARE()
|
function MarathonA3Game:getARE()
|
||||||
if self.speed_level < 700 then return 27
|
if self.speed_level < 700 then return 27
|
||||||
elseif self.speed_level < 800 then return 18
|
elseif self.speed_level < 800 then return 18
|
||||||
elseif self.speed_level < 1000 then return 14
|
elseif self.speed_level < 1000 then return 14
|
||||||
elseif self.speed_level < 1100 then return 8
|
elseif self.speed_level < 1100 then return 8
|
||||||
elseif self.speed_level < 1200 then return 7
|
elseif self.speed_level < 1200 then return 7
|
||||||
else return 6 end
|
else return 6 end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA3Game:getLineARE()
|
function MarathonA3Game:getLineARE()
|
||||||
if self.speed_level < 600 then return 27
|
if self.speed_level < 600 then return 27
|
||||||
elseif self.speed_level < 700 then return 18
|
elseif self.speed_level < 700 then return 18
|
||||||
elseif self.speed_level < 800 then return 14
|
elseif self.speed_level < 800 then return 14
|
||||||
elseif self.speed_level < 1100 then return 8
|
elseif self.speed_level < 1100 then return 8
|
||||||
elseif self.speed_level < 1200 then return 7
|
elseif self.speed_level < 1200 then return 7
|
||||||
else return 6 end
|
else return 6 end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA3Game:getDasLimit()
|
function MarathonA3Game:getDasLimit()
|
||||||
if self.speed_level < 500 then return 15
|
if self.speed_level < 500 then return 15
|
||||||
elseif self.speed_level < 900 then return 9
|
elseif self.speed_level < 900 then return 9
|
||||||
else return 7 end
|
else return 7 end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA3Game:getLineClearDelay()
|
function MarathonA3Game:getLineClearDelay()
|
||||||
if self.speed_level < 500 then return 40
|
if self.speed_level < 500 then return 40
|
||||||
elseif self.speed_level < 600 then return 25
|
elseif self.speed_level < 600 then return 25
|
||||||
elseif self.speed_level < 700 then return 16
|
elseif self.speed_level < 700 then return 16
|
||||||
elseif self.speed_level < 800 then return 12
|
elseif self.speed_level < 800 then return 12
|
||||||
elseif self.speed_level < 1100 then return 6
|
elseif self.speed_level < 1100 then return 6
|
||||||
elseif self.speed_level < 1200 then return 5
|
elseif self.speed_level < 1200 then return 5
|
||||||
else return 4 end
|
else return 4 end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA3Game:getLockDelay()
|
function MarathonA3Game:getLockDelay()
|
||||||
if self.speed_level < 900 then return 30
|
if self.speed_level < 900 then return 30
|
||||||
elseif self.speed_level < 1100 then return 17
|
elseif self.speed_level < 1100 then return 17
|
||||||
else return 15 end
|
else return 15 end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA3Game:getGravity()
|
function MarathonA3Game:getGravity()
|
||||||
if (self.speed_level < 30) then return 4/256
|
if (self.speed_level < 30) then return 4/256
|
||||||
elseif (self.speed_level < 35) then return 6/256
|
elseif (self.speed_level < 35) then return 6/256
|
||||||
elseif (self.speed_level < 40) then return 8/256
|
elseif (self.speed_level < 40) then return 8/256
|
||||||
elseif (self.speed_level < 50) then return 10/256
|
elseif (self.speed_level < 50) then return 10/256
|
||||||
elseif (self.speed_level < 60) then return 12/256
|
elseif (self.speed_level < 60) then return 12/256
|
||||||
elseif (self.speed_level < 70) then return 16/256
|
elseif (self.speed_level < 70) then return 16/256
|
||||||
elseif (self.speed_level < 80) then return 32/256
|
elseif (self.speed_level < 80) then return 32/256
|
||||||
elseif (self.speed_level < 90) then return 48/256
|
elseif (self.speed_level < 90) then return 48/256
|
||||||
elseif (self.speed_level < 100) then return 64/256
|
elseif (self.speed_level < 100) then return 64/256
|
||||||
elseif (self.speed_level < 120) then return 80/256
|
elseif (self.speed_level < 120) then return 80/256
|
||||||
elseif (self.speed_level < 140) then return 96/256
|
elseif (self.speed_level < 140) then return 96/256
|
||||||
elseif (self.speed_level < 160) then return 112/256
|
elseif (self.speed_level < 160) then return 112/256
|
||||||
elseif (self.speed_level < 170) then return 128/256
|
elseif (self.speed_level < 170) then return 128/256
|
||||||
elseif (self.speed_level < 200) then return 144/256
|
elseif (self.speed_level < 200) then return 144/256
|
||||||
elseif (self.speed_level < 220) then return 4/256
|
elseif (self.speed_level < 220) then return 4/256
|
||||||
elseif (self.speed_level < 230) then return 32/256
|
elseif (self.speed_level < 230) then return 32/256
|
||||||
elseif (self.speed_level < 233) then return 64/256
|
elseif (self.speed_level < 233) then return 64/256
|
||||||
elseif (self.speed_level < 236) then return 96/256
|
elseif (self.speed_level < 236) then return 96/256
|
||||||
elseif (self.speed_level < 239) then return 128/256
|
elseif (self.speed_level < 239) then return 128/256
|
||||||
elseif (self.speed_level < 243) then return 160/256
|
elseif (self.speed_level < 243) then return 160/256
|
||||||
elseif (self.speed_level < 247) then return 192/256
|
elseif (self.speed_level < 247) then return 192/256
|
||||||
elseif (self.speed_level < 251) then return 224/256
|
elseif (self.speed_level < 251) then return 224/256
|
||||||
elseif (self.speed_level < 300) then return 1
|
elseif (self.speed_level < 300) then return 1
|
||||||
elseif (self.speed_level < 330) then return 2
|
elseif (self.speed_level < 330) then return 2
|
||||||
elseif (self.speed_level < 360) then return 3
|
elseif (self.speed_level < 360) then return 3
|
||||||
elseif (self.speed_level < 400) then return 4
|
elseif (self.speed_level < 400) then return 4
|
||||||
elseif (self.speed_level < 420) then return 5
|
elseif (self.speed_level < 420) then return 5
|
||||||
elseif (self.speed_level < 450) then return 4
|
elseif (self.speed_level < 450) then return 4
|
||||||
elseif (self.speed_level < 500) then return 3
|
elseif (self.speed_level < 500) then return 3
|
||||||
else return 20
|
else return 20
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA3Game:advanceOneFrame()
|
function MarathonA3Game:advanceOneFrame()
|
||||||
@@ -149,28 +149,28 @@ end
|
|||||||
|
|
||||||
function MarathonA3Game:onPieceEnter()
|
function MarathonA3Game:onPieceEnter()
|
||||||
if (self.level % 100 ~= 99) and self.level ~= 998 and self.frames ~= 0 then
|
if (self.level % 100 ~= 99) and self.level ~= 998 and self.frames ~= 0 then
|
||||||
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
|
self.torikan_passed = self.level >= 500 and true or false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local cleared_row_levels = {1, 2, 4, 6}
|
local cleared_row_levels = {1, 2, 4, 6}
|
||||||
|
|
||||||
function MarathonA3Game:onLineClear(cleared_row_count)
|
function MarathonA3Game:onLineClear(cleared_row_count)
|
||||||
local advanced_levels = cleared_row_levels[cleared_row_count]
|
local advanced_levels = cleared_row_levels[cleared_row_count]
|
||||||
self:updateSectionTimes(self.level, self.level + advanced_levels)
|
self:updateSectionTimes(self.level, self.level + advanced_levels)
|
||||||
if not self.clear then
|
if not self.clear then
|
||||||
self.level = math.min(self.level + advanced_levels, 999)
|
self.level = math.min(self.level + advanced_levels, 999)
|
||||||
end
|
end
|
||||||
self.speed_level = self.speed_level + advanced_levels
|
self.speed_level = self.speed_level + advanced_levels
|
||||||
if self.level == 999 and not self.clear then
|
if self.level == 999 and not self.clear then
|
||||||
self.clear = true
|
self.clear = true
|
||||||
self.grid:clear()
|
self.grid:clear()
|
||||||
self.roll_frames = -150
|
self.roll_frames = -150
|
||||||
end
|
end
|
||||||
if not self.torikan_passed and 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
|
||||||
@@ -217,22 +217,22 @@ function MarathonA3Game:updateSectionTimes(old_level, new_level)
|
|||||||
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
|
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_70_times[section] < self.section_70_times[section - 1] + 120 then
|
||||||
self.section_cool = true
|
self.section_cool = true
|
||||||
self.coolregret_message = "COOL!!"
|
self.coolregret_message = "COOL!!"
|
||||||
self.coolregret_timer = 300
|
self.coolregret_timer = 300
|
||||||
elseif self.section_status[section - 1] == "cool" then self.section_cool = false
|
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
|
elseif section <= 9 and self.section_70_times[section] < cool_cutoffs[section] then
|
||||||
self.section_cool = true
|
self.section_cool = true
|
||||||
self.coolregret_message = "COOL!!"
|
self.coolregret_message = "COOL!!"
|
||||||
self.coolregret_timer = 300
|
self.coolregret_timer = 300
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA3Game:updateScore(level, drop_bonus, cleared_lines)
|
function MarathonA3Game:updateScore(level, drop_bonus, cleared_lines)
|
||||||
|
self:updateGrade(cleared_lines)
|
||||||
if not self.clear then
|
if not self.clear then
|
||||||
self:updateGrade(cleared_lines)
|
|
||||||
if cleared_lines > 0 then
|
if cleared_lines > 0 then
|
||||||
self.combo = self.combo + (cleared_lines - 1) * 2
|
self.combo = self.combo + (cleared_lines - 1) * 2
|
||||||
self.score = self.score + (
|
self.score = self.score + (
|
||||||
@@ -362,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
|
||||||
@@ -407,9 +409,9 @@ function MarathonA3Game:drawScoringInfo()
|
|||||||
love.graphics.printf("SCORE", 240, 200, 40, "left")
|
love.graphics.printf("SCORE", 240, 200, 40, "left")
|
||||||
love.graphics.printf("LEVEL", 240, 320, 40, "left")
|
love.graphics.printf("LEVEL", 240, 320, 40, "left")
|
||||||
local sg = self.grid:checkSecretGrade()
|
local sg = self.grid:checkSecretGrade()
|
||||||
if sg >= 5 then
|
if sg >= 5 then
|
||||||
love.graphics.printf("SECRET GRADE", 240, 430, 180, "left")
|
love.graphics.printf("SECRET GRADE", 240, 430, 180, "left")
|
||||||
end
|
end
|
||||||
|
|
||||||
-- draw section time data
|
-- draw section time data
|
||||||
current_section = math.floor(self.level / 100) + 1
|
current_section = math.floor(self.level / 100) + 1
|
||||||
@@ -439,9 +441,9 @@ function MarathonA3Game:drawScoringInfo()
|
|||||||
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 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")
|
||||||
self.coolregret_timer = self.coolregret_timer - 1
|
self.coolregret_timer = self.coolregret_timer - 1
|
||||||
end
|
end
|
||||||
|
|
||||||
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")
|
||||||
@@ -452,8 +454,8 @@ function MarathonA3Game:drawScoringInfo()
|
|||||||
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
|
||||||
love.graphics.printf(self.SGnames[sg], 240, 450, 180, "left")
|
love.graphics.printf(self.SGnames[sg], 240, 450, 180, "left")
|
||||||
end
|
end
|
||||||
|
|
||||||
love.graphics.setFont(font_8x11)
|
love.graphics.setFont(font_8x11)
|
||||||
love.graphics.printf(formatTime(self.frames), 64, 420, 160, "center")
|
love.graphics.printf(formatTime(self.frames), 64, 420, 160, "center")
|
||||||
|
|||||||
@@ -24,12 +24,13 @@ 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
|
||||||
|
|
||||||
function MarathonAX4Game:getARE()
|
function MarathonAX4Game:getARE()
|
||||||
if self.lines < 10 then return 18
|
if self.lines < 10 then return 18
|
||||||
elseif self.lines < 40 then return 14
|
elseif self.lines < 40 then return 14
|
||||||
elseif self.lines < 60 then return 12
|
elseif self.lines < 60 then return 12
|
||||||
elseif self.lines < 70 then return 10
|
elseif self.lines < 70 then return 10
|
||||||
@@ -43,14 +44,14 @@ function MarathonAX4Game:getLineARE()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function MarathonAX4Game:getDasLimit()
|
function MarathonAX4Game:getDasLimit()
|
||||||
if self.lines < 20 then return 10
|
if self.lines < 20 then return 10
|
||||||
elseif self.lines < 50 then return 9
|
elseif self.lines < 50 then return 9
|
||||||
elseif self.lines < 70 then return 8
|
elseif self.lines < 70 then return 8
|
||||||
else return 7 end
|
else return 7 end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonAX4Game:getLineClearDelay()
|
function MarathonAX4Game:getLineClearDelay()
|
||||||
if self.lines < 10 then return 14
|
if self.lines < 10 then return 14
|
||||||
elseif self.lines < 30 then return 9
|
elseif self.lines < 30 then return 9
|
||||||
else return 5 end
|
else return 5 end
|
||||||
end
|
end
|
||||||
@@ -145,7 +146,7 @@ function MarathonAX4Game:drawScoringInfo()
|
|||||||
strTrueValues(self.prev_inputs)
|
strTrueValues(self.prev_inputs)
|
||||||
)
|
)
|
||||||
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
||||||
love.graphics.printf("TIME LEFT", 240, 250, 80, "left")
|
if self.lines < 150 then love.graphics.printf("TIME LEFT", 240, 250, 80, "left") end
|
||||||
love.graphics.printf("LINES", 240, 320, 40, "left")
|
love.graphics.printf("LINES", 240, 320, 40, "left")
|
||||||
|
|
||||||
local current_section = math.floor(self.lines / 10) + 1
|
local current_section = math.floor(self.lines / 10) + 1
|
||||||
@@ -160,7 +161,7 @@ function MarathonAX4Game:drawScoringInfo()
|
|||||||
if not self.game_over and not self.clear and time_left < frameTime(0,10) and time_left % 4 < 2 then
|
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)
|
love.graphics.setColor(1, 0.3, 0.3, 1)
|
||||||
end
|
end
|
||||||
love.graphics.printf(formatTime(time_left), 240, 270, 160, "left")
|
if self.lines < 150 then love.graphics.printf(formatTime(time_left), 240, 270, 160, "left") end
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
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
|
|
||||||
@@ -15,13 +15,14 @@ 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 = {
|
||||||
"9", "8", "7", "6", "5", "4", "3", "2", "1",
|
"9", "8", "7", "6", "5", "4", "3", "2", "1",
|
||||||
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
|
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
|
||||||
"GM"
|
"GM"
|
||||||
}
|
}
|
||||||
|
|
||||||
self.roll_frames = 0
|
self.roll_frames = 0
|
||||||
self.combo = 1
|
self.combo = 1
|
||||||
@@ -29,7 +30,7 @@ function PhantomManiaGame:new()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function PhantomManiaGame:getARE()
|
function PhantomManiaGame:getARE()
|
||||||
if self.level < 100 then return 18
|
if self.level < 100 then return 18
|
||||||
elseif self.level < 200 then return 14
|
elseif self.level < 200 then return 14
|
||||||
elseif self.level < 400 then return 8
|
elseif self.level < 400 then return 8
|
||||||
elseif self.level < 500 then return 7
|
elseif self.level < 500 then return 7
|
||||||
@@ -37,14 +38,14 @@ function PhantomManiaGame:getARE()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function PhantomManiaGame:getLineARE()
|
function PhantomManiaGame:getLineARE()
|
||||||
if self.level < 100 then return 18
|
if self.level < 100 then return 18
|
||||||
elseif self.level < 400 then return 8
|
elseif self.level < 400 then return 8
|
||||||
elseif self.level < 500 then return 7
|
elseif self.level < 500 then return 7
|
||||||
else return 6 end
|
else return 6 end
|
||||||
end
|
end
|
||||||
|
|
||||||
function PhantomManiaGame:getDasLimit()
|
function PhantomManiaGame:getDasLimit()
|
||||||
if self.level < 200 then return 11
|
if self.level < 200 then return 11
|
||||||
elseif self.level < 300 then return 10
|
elseif self.level < 300 then return 10
|
||||||
elseif self.level < 400 then return 9
|
elseif self.level < 400 then return 9
|
||||||
else return 7 end
|
else return 7 end
|
||||||
@@ -55,7 +56,7 @@ function PhantomManiaGame:getLineClearDelay()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function PhantomManiaGame:getLockDelay()
|
function PhantomManiaGame:getLockDelay()
|
||||||
if self.level < 100 then return 30
|
if self.level < 100 then return 30
|
||||||
elseif self.level < 200 then return 26
|
elseif self.level < 200 then return 26
|
||||||
elseif self.level < 300 then return 22
|
elseif self.level < 300 then return 22
|
||||||
elseif self.level < 400 then return 18
|
elseif self.level < 400 then return 18
|
||||||
@@ -138,7 +139,7 @@ end
|
|||||||
|
|
||||||
function PhantomManiaGame:drawGrid()
|
function PhantomManiaGame:drawGrid()
|
||||||
if not (self.game_over or self.clear) then
|
if not (self.game_over or self.clear) then
|
||||||
self.grid:drawInvisible(self.rollOpacityFunction)
|
self.grid:drawInvisible(self.rollOpacityFunction, nil, false)
|
||||||
else
|
else
|
||||||
self.grid:draw()
|
self.grid:draw()
|
||||||
end
|
end
|
||||||
@@ -171,10 +172,10 @@ function PhantomManiaGame:drawScoringInfo()
|
|||||||
if getLetterGrade(self.level, self.clear) ~= "" then love.graphics.printf("GRADE", text_x, 120, 40, "left") end
|
if getLetterGrade(self.level, self.clear) ~= "" then love.graphics.printf("GRADE", text_x, 120, 40, "left") end
|
||||||
love.graphics.printf("SCORE", text_x, 200, 40, "left")
|
love.graphics.printf("SCORE", text_x, 200, 40, "left")
|
||||||
love.graphics.printf("LEVEL", text_x, 320, 40, "left")
|
love.graphics.printf("LEVEL", text_x, 320, 40, "left")
|
||||||
local sg = self.grid:checkSecretGrade()
|
local sg = self.grid:checkSecretGrade()
|
||||||
if sg >= 5 then
|
if sg >= 5 then
|
||||||
love.graphics.printf("SECRET GRADE", 240, 430, 180, "left")
|
love.graphics.printf("SECRET GRADE", 240, 430, 180, "left")
|
||||||
end
|
end
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
love.graphics.setFont(font_3x5_3)
|
||||||
if getLetterGrade(self.level, self.clear) ~= "" then love.graphics.printf(getLetterGrade(self.level, self.clear), text_x, 140, 90, "left") end
|
if getLetterGrade(self.level, self.clear) ~= "" then love.graphics.printf(getLetterGrade(self.level, self.clear), text_x, 140, 90, "left") end
|
||||||
@@ -186,9 +187,9 @@ function PhantomManiaGame:drawScoringInfo()
|
|||||||
love.graphics.printf(self:getSectionEndLevel(), text_x, 370, 40, "right")
|
love.graphics.printf(self:getSectionEndLevel(), text_x, 370, 40, "right")
|
||||||
end
|
end
|
||||||
|
|
||||||
if sg >= 5 then
|
if sg >= 5 then
|
||||||
love.graphics.printf(self.SGnames[sg], 240, 450, 180, "left")
|
love.graphics.printf(self.SGnames[sg], 240, 450, 180, "left")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function PhantomManiaGame:getSectionEndLevel()
|
function PhantomManiaGame:getSectionEndLevel()
|
||||||
|
|||||||
@@ -26,15 +26,16 @@ function PhantomMania2Game:new()
|
|||||||
self.queue_age = 0
|
self.queue_age = 0
|
||||||
self.roll_points = 0
|
self.roll_points = 0
|
||||||
|
|
||||||
self.SGnames = {
|
self.SGnames = {
|
||||||
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
|
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
|
||||||
"m1", "m2", "m3", "m4", "m5", "m6", "m7", "m8", "m9",
|
"m1", "m2", "m3", "m4", "m5", "m6", "m7", "m8", "m9",
|
||||||
"GM"
|
"GM"
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
@@ -43,12 +44,12 @@ function PhantomMania2Game:new()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function PhantomMania2Game:getARE()
|
function PhantomMania2Game:getARE()
|
||||||
if self.level < 300 then return 12
|
if self.level < 300 then return 12
|
||||||
else return 6 end
|
else return 6 end
|
||||||
end
|
end
|
||||||
|
|
||||||
function PhantomMania2Game:getLineARE()
|
function PhantomMania2Game:getLineARE()
|
||||||
if self.level < 100 then return 8
|
if self.level < 100 then return 8
|
||||||
elseif self.level < 200 then return 7
|
elseif self.level < 200 then return 7
|
||||||
elseif self.level < 500 then return 6
|
elseif self.level < 500 then return 6
|
||||||
elseif self.level < 1300 then return 5
|
elseif self.level < 1300 then return 5
|
||||||
@@ -56,7 +57,7 @@ function PhantomMania2Game:getLineARE()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function PhantomMania2Game:getDasLimit()
|
function PhantomMania2Game:getDasLimit()
|
||||||
if self.level < 200 then return 9
|
if self.level < 200 then return 9
|
||||||
elseif self.level < 500 then return 7
|
elseif self.level < 500 then return 7
|
||||||
else return 5 end
|
else return 5 end
|
||||||
end
|
end
|
||||||
@@ -66,7 +67,7 @@ function PhantomMania2Game:getLineClearDelay()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function PhantomMania2Game:getLockDelay()
|
function PhantomMania2Game:getLockDelay()
|
||||||
if self.level < 200 then return 18
|
if self.level < 200 then return 18
|
||||||
elseif self.level < 300 then return 17
|
elseif self.level < 300 then return 17
|
||||||
elseif self.level < 500 then return 15
|
elseif self.level < 500 then return 15
|
||||||
elseif self.level < 600 then return 13
|
elseif self.level < 600 then return 13
|
||||||
@@ -124,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
|
||||||
@@ -145,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
|
||||||
@@ -164,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
|
||||||
@@ -173,10 +178,12 @@ 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
|
||||||
|
|
||||||
@@ -248,7 +255,7 @@ PhantomMania2Game.garbageOpacityFunction = function(age)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function PhantomMania2Game:drawGrid()
|
function PhantomMania2Game:drawGrid()
|
||||||
if not (self.game_over or (self.clear and self.level < 1300)) then
|
if not (self.game_over) then
|
||||||
self.grid:drawInvisible(self.rollOpacityFunction, self.garbageOpacityFunction)
|
self.grid:drawInvisible(self.rollOpacityFunction, self.garbageOpacityFunction)
|
||||||
else
|
else
|
||||||
self.grid:draw()
|
self.grid:draw()
|
||||||
@@ -299,15 +306,17 @@ function PhantomMania2Game:drawScoringInfo()
|
|||||||
love.graphics.printf("GRADE", text_x, 120, 40, "left")
|
love.graphics.printf("GRADE", text_x, 120, 40, "left")
|
||||||
love.graphics.printf("SCORE", text_x, 200, 40, "left")
|
love.graphics.printf("SCORE", text_x, 200, 40, "left")
|
||||||
love.graphics.printf("LEVEL", text_x, 320, 40, "left")
|
love.graphics.printf("LEVEL", text_x, 320, 40, "left")
|
||||||
local sg = self.grid:checkSecretGrade()
|
local sg = self.grid:checkSecretGrade()
|
||||||
if sg >= 5 then
|
if sg >= 5 then
|
||||||
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
|
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")
|
||||||
self.coolregret_timer = self.coolregret_timer - 1
|
self.coolregret_timer = self.coolregret_timer - 1
|
||||||
end
|
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")
|
||||||
@@ -319,9 +328,9 @@ function PhantomMania2Game:drawScoringInfo()
|
|||||||
love.graphics.printf(math.floor(self.level / 100 + 1) * 100, text_x, 370, 50, "right")
|
love.graphics.printf(math.floor(self.level / 100 + 1) * 100, text_x, 370, 50, "right")
|
||||||
end
|
end
|
||||||
|
|
||||||
if sg >= 5 then
|
if sg >= 5 then
|
||||||
love.graphics.printf(self.SGnames[sg], 240, 450, 180, "left")
|
love.graphics.printf(self.SGnames[sg], 240, 450, 180, "left")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function PhantomMania2Game:getBackground()
|
function PhantomMania2Game:getBackground()
|
||||||
|
|||||||
@@ -9,11 +9,11 @@ PhantomManiaNGame.tagline = "The old mode from Nullpomino, for Ti-ARS and SRS su
|
|||||||
function PhantomManiaNGame:new()
|
function PhantomManiaNGame:new()
|
||||||
PhantomManiaNGame.super:new()
|
PhantomManiaNGame.super:new()
|
||||||
|
|
||||||
self.SGnames = {
|
self.SGnames = {
|
||||||
"M1", "M2", "M3", "M4", "M5", "M6", "M7", "M8", "M9",
|
"M1", "M2", "M3", "M4", "M5", "M6", "M7", "M8", "M9",
|
||||||
"M10", "M11", "M12", "M13", "M14", "M15", "M16", "M17", "M18",
|
"M10", "M11", "M12", "M13", "M14", "M15", "M16", "M17", "M18",
|
||||||
"GM"
|
"GM"
|
||||||
}
|
}
|
||||||
|
|
||||||
self.next_queue_length = 3
|
self.next_queue_length = 3
|
||||||
self.enable_hold = true
|
self.enable_hold = true
|
||||||
|
|||||||
@@ -1,150 +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.SGnames = {
|
|
||||||
[0] = "",
|
|
||||||
"9", "8", "7", "6", "5", "4", "3", "2", "1",
|
|
||||||
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
|
|
||||||
"GM"
|
|
||||||
}
|
|
||||||
self.upstacked = false
|
|
||||||
|
|
||||||
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 1
|
|
||||||
end
|
|
||||||
|
|
||||||
function Race40Game:getARE()
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function Race40Game:getLineARE()
|
|
||||||
return self:getARE()
|
|
||||||
end
|
|
||||||
|
|
||||||
function Race40Game:getDasLimit()
|
|
||||||
return 10
|
|
||||||
end
|
|
||||||
|
|
||||||
function Race40Game:getLineClearDelay()
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function Race40Game:getLockDelay()
|
|
||||||
return 30
|
|
||||||
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:getSecretGrade(sg)
|
|
||||||
if sg == 19 then self.upstacked = true end
|
|
||||||
if self.upstacked then return self.SGnames[14 + math.floor((20 - sg) / 4)]
|
|
||||||
else return self.SGnames[math.floor((sg / 19) * 14)] end
|
|
||||||
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")
|
|
||||||
local sg = self.grid:checkSecretGrade()
|
|
||||||
if sg >= 7 or self.upstacked then
|
|
||||||
love.graphics.printf("SECRET GRADE", 240, 430, 180, "left")
|
|
||||||
end
|
|
||||||
|
|
||||||
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")
|
|
||||||
if sg >= 7 or self.upstacked then
|
|
||||||
love.graphics.printf(self:getSecretGrade(sg), 240, 450, 180, "left")
|
|
||||||
end
|
|
||||||
|
|
||||||
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
|
|
||||||
@@ -1,189 +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 ScoreDrainGame = GameMode:extend()
|
|
||||||
|
|
||||||
ScoreDrainGame.name = "Score Drain"
|
|
||||||
ScoreDrainGame.hash = "ScoreDrain"
|
|
||||||
ScoreDrainGame.tagline = "Your score goes down over time! Avoid hitting 0 points, or your game is over!"
|
|
||||||
|
|
||||||
function ScoreDrainGame:new()
|
|
||||||
self.super:new()
|
|
||||||
|
|
||||||
self.score = 2500
|
|
||||||
self.drain_rate = 50
|
|
||||||
self.combo = 1
|
|
||||||
self.randomizer = History6RollsRandomizer()
|
|
||||||
|
|
||||||
self.lock_drop = true
|
|
||||||
self.lock_hard_drop = true
|
|
||||||
self.enable_hold = true
|
|
||||||
self.next_queue_length = 3
|
|
||||||
end
|
|
||||||
|
|
||||||
function ScoreDrainGame:getARE()
|
|
||||||
if self.level < 700 then return 27
|
|
||||||
elseif self.level < 800 then return 18
|
|
||||||
elseif self.level < 1000 then return 14
|
|
||||||
elseif self.level < 1100 then return 8
|
|
||||||
elseif self.level < 1200 then return 7
|
|
||||||
else return 6 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function ScoreDrainGame:getLineARE()
|
|
||||||
if self.level < 600 then return 27
|
|
||||||
elseif self.level < 700 then return 18
|
|
||||||
elseif self.level < 800 then return 14
|
|
||||||
elseif self.level < 1100 then return 8
|
|
||||||
elseif self.level < 1200 then return 7
|
|
||||||
else return 6 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function ScoreDrainGame:getDasLimit()
|
|
||||||
if self.level < 500 then return 15
|
|
||||||
elseif self.level < 900 then return 9
|
|
||||||
else return 7 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function ScoreDrainGame:getLineClearDelay()
|
|
||||||
if self.level < 500 then return 40
|
|
||||||
elseif self.level < 600 then return 25
|
|
||||||
elseif self.level < 700 then return 16
|
|
||||||
elseif self.level < 800 then return 12
|
|
||||||
elseif self.level < 1100 then return 6
|
|
||||||
elseif self.level < 1200 then return 5
|
|
||||||
else return 4 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function ScoreDrainGame:getLockDelay()
|
|
||||||
if self.level < 900 then return 30
|
|
||||||
elseif self.level < 1100 then return 17
|
|
||||||
else return 15 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function ScoreDrainGame:getGravity()
|
|
||||||
if (self.level < 30) then return 4/256
|
|
||||||
elseif (self.level < 35) then return 6/256
|
|
||||||
elseif (self.level < 40) then return 8/256
|
|
||||||
elseif (self.level < 50) then return 10/256
|
|
||||||
elseif (self.level < 60) then return 12/256
|
|
||||||
elseif (self.level < 70) then return 16/256
|
|
||||||
elseif (self.level < 80) then return 32/256
|
|
||||||
elseif (self.level < 90) then return 48/256
|
|
||||||
elseif (self.level < 100) then return 64/256
|
|
||||||
elseif (self.level < 120) then return 80/256
|
|
||||||
elseif (self.level < 140) then return 96/256
|
|
||||||
elseif (self.level < 160) then return 112/256
|
|
||||||
elseif (self.level < 170) then return 128/256
|
|
||||||
elseif (self.level < 200) then return 144/256
|
|
||||||
elseif (self.level < 220) then return 4/256
|
|
||||||
elseif (self.level < 230) then return 32/256
|
|
||||||
elseif (self.level < 233) then return 64/256
|
|
||||||
elseif (self.level < 236) then return 96/256
|
|
||||||
elseif (self.level < 239) then return 128/256
|
|
||||||
elseif (self.level < 243) then return 160/256
|
|
||||||
elseif (self.level < 247) then return 192/256
|
|
||||||
elseif (self.level < 251) then return 224/256
|
|
||||||
elseif (self.level < 300) then return 1
|
|
||||||
elseif (self.level < 330) then return 2
|
|
||||||
elseif (self.level < 360) then return 3
|
|
||||||
elseif (self.level < 400) then return 4
|
|
||||||
elseif (self.level < 420) then return 5
|
|
||||||
elseif (self.level < 450) then return 4
|
|
||||||
elseif (self.level < 500) then return 3
|
|
||||||
else return 20
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function ScoreDrainGame:advanceOneFrame()
|
|
||||||
if self.ready_frames == 0 then
|
|
||||||
self.frames = self.frames + 1
|
|
||||||
self.score = math.max(0, self.score - self.drain_rate / 60)
|
|
||||||
self.game_over = self.score <= 0 and true or false
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
function ScoreDrainGame:onPieceEnter()
|
|
||||||
if (self.level % 100 ~= 99) and self.frames ~= 0 then
|
|
||||||
self.level = self.level + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
local cleared_row_levels = {1, 2, 4, 6}
|
|
||||||
|
|
||||||
function ScoreDrainGame:onLineClear(cleared_row_count)
|
|
||||||
local new_level = self.level + cleared_row_levels[cleared_row_count]
|
|
||||||
self.drain_rate = math.floor(self.level / 100) < math.floor(new_level / 100) and self.drain_rate * 1.5 or self.drain_rate
|
|
||||||
self.level = new_level
|
|
||||||
end
|
|
||||||
|
|
||||||
function ScoreDrainGame:updateScore(level, drop_bonus, cleared_lines)
|
|
||||||
if cleared_lines > 0 then
|
|
||||||
self.combo = self.combo + (cleared_lines - 1) * 2
|
|
||||||
self.score = self.score + (
|
|
||||||
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
|
||||||
cleared_lines * self.combo
|
|
||||||
)
|
|
||||||
else
|
|
||||||
self.combo = 1
|
|
||||||
end
|
|
||||||
self.drop_bonus = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function ScoreDrainGame:drawGrid()
|
|
||||||
self.grid:draw()
|
|
||||||
if self.piece ~= nil and self.level < 100 then
|
|
||||||
self:drawGhostPiece(ruleset)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function ScoreDrainGame: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("DRAIN RATE", 240, 90, 80, "left")
|
|
||||||
love.graphics.printf("SCORE", 240, 170, 40, "left")
|
|
||||||
love.graphics.printf("TIME LEFT", 240, 250, 80, "left")
|
|
||||||
love.graphics.printf("LEVEL", 240, 320, 40, "left")
|
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
|
||||||
love.graphics.printf(math.floor(self.drain_rate).."/s", 240, 110, 120, "left")
|
|
||||||
local frames_left = self.score / self.drain_rate * 60
|
|
||||||
if frames_left <= 600 and frames_left % 4 < 2 and not self.game_over then love.graphics.setColor(1, 0.3, 0.3, 1) end
|
|
||||||
love.graphics.printf(formatTime(frames_left), 240, 270, 120, "left")
|
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
|
||||||
love.graphics.printf(math.floor(self.score), 240, 190, 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 ScoreDrainGame:getHighscoreData()
|
|
||||||
return {
|
|
||||||
level = self.level,
|
|
||||||
frames = self.frames,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
function ScoreDrainGame:getSectionEndLevel()
|
|
||||||
return math.floor(self.level / 100 + 1) * 100
|
|
||||||
end
|
|
||||||
|
|
||||||
function ScoreDrainGame:getBackground()
|
|
||||||
return math.floor(self.level / 100)
|
|
||||||
end
|
|
||||||
|
|
||||||
return ScoreDrainGame
|
|
||||||
@@ -27,7 +27,7 @@ function StrategyGame:new()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function StrategyGame:getARE()
|
function StrategyGame:getARE()
|
||||||
if self.level < 100 then return 60
|
if self.level < 100 then return 60
|
||||||
elseif self.level < 200 then return 54
|
elseif self.level < 200 then return 54
|
||||||
elseif self.level < 300 then return 48
|
elseif self.level < 300 then return 48
|
||||||
elseif self.level < 400 then return 42
|
elseif self.level < 400 then return 42
|
||||||
@@ -52,7 +52,7 @@ function StrategyGame:getLineClearDelay()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function StrategyGame:getLockDelay()
|
function StrategyGame:getLockDelay()
|
||||||
if self.level < 500 then return 8
|
if self.level < 500 then return 8
|
||||||
elseif self.level < 700 then return 6
|
elseif self.level < 700 then return 6
|
||||||
else return 4 end
|
else return 4 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
|
||||||
@@ -45,7 +46,7 @@ function Survival2020Game:getLineARE()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Survival2020Game:getDasLimit()
|
function Survival2020Game:getDasLimit()
|
||||||
if self.level < 200 then return 9
|
if self.level < 200 then return 9
|
||||||
elseif self.level < 500 then return 7
|
elseif self.level < 500 then return 7
|
||||||
elseif self.level < 1000 then return 5
|
elseif self.level < 1000 then return 5
|
||||||
elseif self.level < 1500 then return 4
|
elseif self.level < 1500 then return 4
|
||||||
|
|||||||
@@ -15,28 +15,28 @@ SurvivalA1Game.tagline = "The game starts fast and only gets faster!"
|
|||||||
|
|
||||||
|
|
||||||
function SurvivalA1Game:new()
|
function SurvivalA1Game:new()
|
||||||
SurvivalA1Game.super:new()
|
SurvivalA1Game.super:new()
|
||||||
|
|
||||||
self.roll_frames = 0
|
self.roll_frames = 0
|
||||||
self.combo = 1
|
self.combo = 1
|
||||||
self.bravos = 0
|
self.bravos = 0
|
||||||
|
|
||||||
self.gm_conditions = {
|
self.gm_conditions = {
|
||||||
level300 = false,
|
level300 = false,
|
||||||
level500 = false,
|
level500 = false,
|
||||||
level999 = false
|
level999 = false
|
||||||
}
|
}
|
||||||
|
|
||||||
self.SGnames = {
|
self.SGnames = {
|
||||||
"9", "8", "7", "6", "5", "4", "3", "2", "1",
|
"9", "8", "7", "6", "5", "4", "3", "2", "1",
|
||||||
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
|
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
|
||||||
"GM"
|
"GM"
|
||||||
}
|
}
|
||||||
|
|
||||||
self.randomizer = History4RollsRandomizer()
|
self.randomizer = History4RollsRandomizer()
|
||||||
|
|
||||||
self.lock_drop = false
|
self.lock_drop = false
|
||||||
self.enable_hard_drop = false
|
self.enable_hard_drop = false
|
||||||
self.enable_hold = false
|
self.enable_hold = false
|
||||||
self.next_queue_length = 1
|
self.next_queue_length = 1
|
||||||
end
|
end
|
||||||
@@ -62,29 +62,29 @@ function SurvivalA1Game:getLockDelay()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function SurvivalA1Game:getGravity()
|
function SurvivalA1Game:getGravity()
|
||||||
return 20
|
return 20
|
||||||
end
|
end
|
||||||
|
|
||||||
local function getRankForScore(score)
|
local function getRankForScore(score)
|
||||||
if score < 400 then return {rank = "9", next = 400}
|
if score < 400 then return {rank = "9", next = 400}
|
||||||
elseif score < 800 then return {rank = "8", next = 800}
|
elseif score < 800 then return {rank = "8", next = 800}
|
||||||
elseif score < 1400 then return {rank = "7", next = 1400}
|
elseif score < 1400 then return {rank = "7", next = 1400}
|
||||||
elseif score < 2000 then return {rank = "6", next = 2000}
|
elseif score < 2000 then return {rank = "6", next = 2000}
|
||||||
elseif score < 3500 then return {rank = "5", next = 3500}
|
elseif score < 3500 then return {rank = "5", next = 3500}
|
||||||
elseif score < 5500 then return {rank = "4", next = 5500}
|
elseif score < 5500 then return {rank = "4", next = 5500}
|
||||||
elseif score < 8000 then return {rank = "3", next = 8000}
|
elseif score < 8000 then return {rank = "3", next = 8000}
|
||||||
elseif score < 12000 then return {rank = "2", next = 12000}
|
elseif score < 12000 then return {rank = "2", next = 12000}
|
||||||
elseif score < 16000 then return {rank = "1", next = 16000}
|
elseif score < 16000 then return {rank = "1", next = 16000}
|
||||||
elseif score < 22000 then return {rank = "S1", next = 22000}
|
elseif score < 22000 then return {rank = "S1", next = 22000}
|
||||||
elseif score < 30000 then return {rank = "S2", next = 30000}
|
elseif score < 30000 then return {rank = "S2", next = 30000}
|
||||||
elseif score < 40000 then return {rank = "S3", next = 40000}
|
elseif score < 40000 then return {rank = "S3", next = 40000}
|
||||||
elseif score < 52000 then return {rank = "S4", next = 52000}
|
elseif score < 52000 then return {rank = "S4", next = 52000}
|
||||||
elseif score < 66000 then return {rank = "S5", next = 66000}
|
elseif score < 66000 then return {rank = "S5", next = 66000}
|
||||||
elseif score < 82000 then return {rank = "S6", next = 82000}
|
elseif score < 82000 then return {rank = "S6", next = 82000}
|
||||||
elseif score < 100000 then return {rank = "S7", next = 100000}
|
elseif score < 100000 then return {rank = "S7", next = 100000}
|
||||||
elseif score < 120000 then return {rank = "S8", next = 120000}
|
elseif score < 120000 then return {rank = "S8", next = 120000}
|
||||||
else return {rank = "S9", next = "???"}
|
else return {rank = "S9", next = "???"}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function SurvivalA1Game:advanceOneFrame()
|
function SurvivalA1Game:advanceOneFrame()
|
||||||
@@ -106,7 +106,7 @@ function SurvivalA1Game:onPieceEnter()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function SurvivalA1Game:onLineClear(cleared_row_count)
|
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 new_level == 999 then
|
if new_level == 999 then
|
||||||
@@ -171,10 +171,10 @@ function SurvivalA1Game:drawScoringInfo()
|
|||||||
love.graphics.printf("SCORE", 240, 200, 40, "left")
|
love.graphics.printf("SCORE", 240, 200, 40, "left")
|
||||||
love.graphics.printf("NEXT RANK", 240, 260, 90, "left")
|
love.graphics.printf("NEXT RANK", 240, 260, 90, "left")
|
||||||
love.graphics.printf("LEVEL", 240, 320, 40, "left")
|
love.graphics.printf("LEVEL", 240, 320, 40, "left")
|
||||||
local sg = self.grid:checkSecretGrade()
|
local sg = self.grid:checkSecretGrade()
|
||||||
if sg >= 5 then
|
if sg >= 5 then
|
||||||
love.graphics.printf("SECRET GRADE", 240, 430, 180, "left")
|
love.graphics.printf("SECRET GRADE", 240, 430, 180, "left")
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.bravos > 0 then love.graphics.printf("BRAVO", 300, 120, 40, "left") end
|
if self.bravos > 0 then love.graphics.printf("BRAVO", 300, 120, 40, "left") end
|
||||||
|
|
||||||
@@ -188,9 +188,9 @@ function SurvivalA1Game:drawScoringInfo()
|
|||||||
love.graphics.printf(getRankForScore(self.score).next, 240, 280, 90, "left")
|
love.graphics.printf(getRankForScore(self.score).next, 240, 280, 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")
|
||||||
if sg >= 5 then
|
if sg >= 5 then
|
||||||
love.graphics.printf(self.SGnames[sg], 240, 450, 180, "left")
|
love.graphics.printf(self.SGnames[sg], 240, 450, 180, "left")
|
||||||
end
|
end
|
||||||
if self.bravos > 0 then love.graphics.printf(self.bravos, 300, 140, 40, "left") end
|
if self.bravos > 0 then love.graphics.printf(self.bravos, 300, 140, 40, "left") end
|
||||||
|
|
||||||
love.graphics.setFont(font_8x11)
|
love.graphics.setFont(font_8x11)
|
||||||
|
|||||||
@@ -20,13 +20,14 @@ function SurvivalA2Game:new()
|
|||||||
self.combo = 1
|
self.combo = 1
|
||||||
self.randomizer = History6RollsRandomizer()
|
self.randomizer = History6RollsRandomizer()
|
||||||
|
|
||||||
self.SGnames = {
|
self.SGnames = {
|
||||||
"9", "8", "7", "6", "5", "4", "3", "2", "1",
|
"9", "8", "7", "6", "5", "4", "3", "2", "1",
|
||||||
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
|
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
|
||||||
"GM"
|
"GM"
|
||||||
}
|
}
|
||||||
|
|
||||||
self.lock_drop = true
|
self.lock_drop = true
|
||||||
|
self.lock_hard_drop = true
|
||||||
end
|
end
|
||||||
|
|
||||||
function SurvivalA2Game:getARE()
|
function SurvivalA2Game:getARE()
|
||||||
@@ -98,9 +99,9 @@ function SurvivalA2Game:onLineClear(cleared_row_count)
|
|||||||
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 or self:hitTorikan(self.level, new_level) then
|
if self.level == 999 or self:hitTorikan(self.level, new_level) then
|
||||||
self.clear = true
|
self.clear = true
|
||||||
if self.level < 999 then
|
if self.level < 999 then
|
||||||
self.game_over = true
|
self.game_over = true
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self.level = new_level
|
self.level = new_level
|
||||||
end
|
end
|
||||||
@@ -150,21 +151,22 @@ function SurvivalA2Game:drawScoringInfo()
|
|||||||
if self:getLetterGrade() ~= "" then love.graphics.printf("GRADE", text_x, 120, 40, "left") end
|
if self:getLetterGrade() ~= "" then love.graphics.printf("GRADE", text_x, 120, 40, "left") end
|
||||||
love.graphics.printf("SCORE", text_x, 200, 40, "left")
|
love.graphics.printf("SCORE", text_x, 200, 40, "left")
|
||||||
love.graphics.printf("LEVEL", text_x, 320, 40, "left")
|
love.graphics.printf("LEVEL", text_x, 320, 40, "left")
|
||||||
local sg = self.grid:checkSecretGrade()
|
local sg = self.grid:checkSecretGrade()
|
||||||
if sg >= 5 then
|
if sg >= 5 then
|
||||||
love.graphics.printf("SECRET GRADE", 240, 430, 180, "left")
|
love.graphics.printf("SECRET GRADE", 240, 430, 180, "left")
|
||||||
end
|
end
|
||||||
|
|
||||||
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)
|
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
|
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.setColor(1, 1, 1, 1)
|
||||||
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")
|
||||||
if sg >= 5 then
|
if sg >= 5 then
|
||||||
love.graphics.printf(self.SGnames[sg], 240, 450, 180, "left")
|
love.graphics.printf(self.SGnames[sg], 240, 450, 180, "left")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function SurvivalA2Game:getSectionEndLevel()
|
function SurvivalA2Game:getSectionEndLevel()
|
||||||
|
|||||||
@@ -12,8 +12,6 @@ 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.grade = 0
|
self.grade = 0
|
||||||
@@ -24,13 +22,14 @@ function SurvivalA3Game:new()
|
|||||||
self.combo = 1
|
self.combo = 1
|
||||||
self.randomizer = History6RollsRandomizer()
|
self.randomizer = History6RollsRandomizer()
|
||||||
|
|
||||||
self.SGnames = {
|
self.SGnames = {
|
||||||
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
|
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
|
||||||
"m1", "m2", "m3", "m4", "m5", "m6", "m7", "m8", "m9",
|
"m1", "m2", "m3", "m4", "m5", "m6", "m7", "m8", "m9",
|
||||||
"GM"
|
"GM"
|
||||||
}
|
}
|
||||||
|
|
||||||
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
|
||||||
|
|
||||||
@@ -40,19 +39,19 @@ end
|
|||||||
|
|
||||||
function SurvivalA3Game:initialize(ruleset)
|
function SurvivalA3Game:initialize(ruleset)
|
||||||
|
|
||||||
self.torikan_time = frameTime(2,28)
|
self.torikan_time = frameTime(2,28)
|
||||||
if ruleset.world then self.torikan_time = frameTime(3,03) end
|
if ruleset.world then self.torikan_time = frameTime(3,03) end
|
||||||
self.super.initialize(self, ruleset)
|
self.super.initialize(self, ruleset)
|
||||||
-- ^ notice the . here instead of the :
|
-- ^ notice the . here instead of the :
|
||||||
end
|
end
|
||||||
|
|
||||||
function SurvivalA3Game:getARE()
|
function SurvivalA3Game:getARE()
|
||||||
if self.level < 300 then return 12
|
if self.level < 300 then return 12
|
||||||
else return 6 end
|
else return 6 end
|
||||||
end
|
end
|
||||||
|
|
||||||
function SurvivalA3Game:getLineARE()
|
function SurvivalA3Game:getLineARE()
|
||||||
if self.level < 100 then return 8
|
if self.level < 100 then return 8
|
||||||
elseif self.level < 200 then return 7
|
elseif self.level < 200 then return 7
|
||||||
elseif self.level < 500 then return 6
|
elseif self.level < 500 then return 6
|
||||||
elseif self.level < 1300 then return 5
|
elseif self.level < 1300 then return 5
|
||||||
@@ -60,7 +59,7 @@ function SurvivalA3Game:getLineARE()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function SurvivalA3Game:getDasLimit()
|
function SurvivalA3Game:getDasLimit()
|
||||||
if self.level < 100 then return 9
|
if self.level < 100 then return 9
|
||||||
elseif self.level < 500 then return 7
|
elseif self.level < 500 then return 7
|
||||||
else return 5 end
|
else return 5 end
|
||||||
end
|
end
|
||||||
@@ -71,7 +70,7 @@ function SurvivalA3Game:getLineClearDelay()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function SurvivalA3Game:getLockDelay()
|
function SurvivalA3Game:getLockDelay()
|
||||||
if self.level < 200 then return 18
|
if self.level < 200 then return 18
|
||||||
elseif self.level < 300 then return 17
|
elseif self.level < 300 then return 17
|
||||||
elseif self.level < 500 then return 15
|
elseif self.level < 500 then return 15
|
||||||
elseif self.level < 600 then return 13
|
elseif self.level < 600 then return 13
|
||||||
@@ -145,14 +144,14 @@ function SurvivalA3Game:onLineClear(cleared_row_count)
|
|||||||
local new_level = self.level + cleared_row_levels[cleared_row_count]
|
local new_level = self.level + cleared_row_levels[cleared_row_count]
|
||||||
self:updateSectionTimes(self.level, new_level)
|
self:updateSectionTimes(self.level, new_level)
|
||||||
if new_level >= 1300 or self:hitTorikan(self.level, new_level) then
|
if new_level >= 1300 or self:hitTorikan(self.level, new_level) then
|
||||||
self.clear = true
|
self.clear = true
|
||||||
if new_level >= 1300 then
|
if new_level >= 1300 then
|
||||||
self.level = 1300
|
self.level = 1300
|
||||||
self.grid:clear()
|
self.grid:clear()
|
||||||
self.big_mode = true
|
self.big_mode = true
|
||||||
self.roll_frames = -150
|
self.roll_frames = -150
|
||||||
else
|
else
|
||||||
self.game_over = true
|
self.game_over = true
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self.level = math.min(new_level, 1300)
|
self.level = math.min(new_level, 1300)
|
||||||
@@ -162,6 +161,7 @@ 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
|
||||||
|
|
||||||
@@ -228,10 +228,10 @@ function SurvivalA3Game:drawScoringInfo()
|
|||||||
love.graphics.printf("GRADE", text_x, 120, 40, "left")
|
love.graphics.printf("GRADE", text_x, 120, 40, "left")
|
||||||
love.graphics.printf("SCORE", text_x, 200, 40, "left")
|
love.graphics.printf("SCORE", text_x, 200, 40, "left")
|
||||||
love.graphics.printf("LEVEL", text_x, 320, 40, "left")
|
love.graphics.printf("LEVEL", text_x, 320, 40, "left")
|
||||||
local sg = self.grid:checkSecretGrade()
|
local sg = self.grid:checkSecretGrade()
|
||||||
if sg >= 5 then
|
if sg >= 5 then
|
||||||
love.graphics.printf("SECRET GRADE", 240, 430, 180, "left")
|
love.graphics.printf("SECRET GRADE", 240, 430, 180, "left")
|
||||||
end
|
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")
|
||||||
@@ -243,7 +243,7 @@ function SurvivalA3Game:drawScoringInfo()
|
|||||||
|
|
||||||
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)
|
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
|
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.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")
|
||||||
@@ -253,9 +253,9 @@ function SurvivalA3Game:drawScoringInfo()
|
|||||||
else
|
else
|
||||||
love.graphics.printf(math.floor(self.level / 100 + 1) * 100, text_x, 370, 50, "right")
|
love.graphics.printf(math.floor(self.level / 100 + 1) * 100, text_x, 370, 50, "right")
|
||||||
end
|
end
|
||||||
if sg >= 5 then
|
if sg >= 5 then
|
||||||
love.graphics.printf(self.SGnames[sg], 240, 450, 180, "left")
|
love.graphics.printf(self.SGnames[sg], 240, 450, 180, "left")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function SurvivalA3Game:getBackground()
|
function SurvivalA3Game:getBackground()
|
||||||
|
|||||||
@@ -1,209 +0,0 @@
|
|||||||
require 'funcs'
|
|
||||||
|
|
||||||
local GameMode = require 'tetris.modes.gamemode'
|
|
||||||
local Piece = require 'tetris.components.piece'
|
|
||||||
|
|
||||||
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
|
||||||
|
|
||||||
local TGMPlusGame = GameMode:extend()
|
|
||||||
|
|
||||||
TGMPlusGame.name = "Marathon A2+"
|
|
||||||
TGMPlusGame.hash = "A2Plus"
|
|
||||||
TGMPlusGame.tagline = "The garbage rises steadily! Can you make it to level 999?"
|
|
||||||
|
|
||||||
function TGMPlusGame:new()
|
|
||||||
TGMPlusGame.super:new()
|
|
||||||
|
|
||||||
self.roll_frames = 0
|
|
||||||
self.combo = 1
|
|
||||||
|
|
||||||
self.SGnames = {
|
|
||||||
"9", "8", "7", "6", "5", "4", "3", "2", "1",
|
|
||||||
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
|
|
||||||
"GM"
|
|
||||||
}
|
|
||||||
|
|
||||||
self.randomizer = History6RollsRandomizer()
|
|
||||||
|
|
||||||
self.lock_drop = false
|
|
||||||
self.enable_hold = false
|
|
||||||
self.next_queue_length = 1
|
|
||||||
|
|
||||||
self.garbage_queue = 0
|
|
||||||
self.garbage_pos = 0
|
|
||||||
self.garbage_rows = {
|
|
||||||
[0] = {"e", "b", "b", "b", "b", "b", "b", "b", "b", "b"},
|
|
||||||
{"e", "b", "b", "b", "b", "b", "b", "b", "b", "b"},
|
|
||||||
{"e", "b", "b", "b", "b", "b", "b", "b", "b", "b"},
|
|
||||||
{"e", "b", "b", "b", "b", "b", "b", "b", "b", "b"},
|
|
||||||
{"b", "b", "b", "b", "b", "b", "b", "b", "b", "e"},
|
|
||||||
{"b", "b", "b", "b", "b", "b", "b", "b", "b", "e"},
|
|
||||||
{"b", "b", "b", "b", "b", "b", "b", "b", "b", "e"},
|
|
||||||
{"b", "b", "b", "b", "b", "b", "b", "b", "b", "e"},
|
|
||||||
{"e", "e", "b", "b", "b", "b", "b", "b", "b", "b"},
|
|
||||||
{"e", "b", "b", "b", "b", "b", "b", "b", "b", "b"},
|
|
||||||
{"e", "b", "b", "b", "b", "b", "b", "b", "b", "b"},
|
|
||||||
{"b", "b", "b", "b", "b", "b", "b", "b", "e", "e"},
|
|
||||||
{"b", "b", "b", "b", "b", "b", "b", "b", "b", "e"},
|
|
||||||
{"b", "b", "b", "b", "b", "b", "b", "b", "b", "e"},
|
|
||||||
{"b", "b", "e", "b", "b", "b", "b", "b", "b", "b"},
|
|
||||||
{"b", "e", "e", "b", "b", "b", "b", "b", "b", "b"},
|
|
||||||
{"b", "e", "b", "b", "b", "b", "b", "b", "b", "b"},
|
|
||||||
{"b", "b", "b", "b", "b", "b", "b", "e", "b", "b"},
|
|
||||||
{"b", "b", "b", "b", "b", "b", "b", "e", "e", "b"},
|
|
||||||
{"b", "b", "b", "b", "b", "b", "b", "b", "e", "b"},
|
|
||||||
{"b", "b", "b", "b", "e", "e", "b", "b", "b", "b"},
|
|
||||||
{"b", "b", "b", "b", "e", "e", "b", "b", "b", "b"},
|
|
||||||
{"b", "b", "b", "b", "e", "b", "b", "b", "b", "b"},
|
|
||||||
{"b", "b", "b", "e", "e", "e", "b", "b", "b", "b"},
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
function TGMPlusGame:getARE() return 25 end
|
|
||||||
function TGMPlusGame:getDasLimit() return 15 end
|
|
||||||
function TGMPlusGame:getLockDelay() return 30 end
|
|
||||||
function TGMPlusGame:getLineClearDelay() return 40 end
|
|
||||||
|
|
||||||
function TGMPlusGame:getGravity()
|
|
||||||
if (self.level < 30) then return 4/256
|
|
||||||
elseif (self.level < 35) then return 6/256
|
|
||||||
elseif (self.level < 40) then return 8/256
|
|
||||||
elseif (self.level < 50) then return 10/256
|
|
||||||
elseif (self.level < 60) then return 12/256
|
|
||||||
elseif (self.level < 70) then return 16/256
|
|
||||||
elseif (self.level < 80) then return 32/256
|
|
||||||
elseif (self.level < 90) then return 48/256
|
|
||||||
elseif (self.level < 100) then return 64/256
|
|
||||||
elseif (self.level < 120) then return 80/256
|
|
||||||
elseif (self.level < 140) then return 96/256
|
|
||||||
elseif (self.level < 160) then return 112/256
|
|
||||||
elseif (self.level < 170) then return 128/256
|
|
||||||
elseif (self.level < 200) then return 144/256
|
|
||||||
elseif (self.level < 220) then return 4/256
|
|
||||||
elseif (self.level < 230) then return 32/256
|
|
||||||
elseif (self.level < 233) then return 64/256
|
|
||||||
elseif (self.level < 236) then return 96/256
|
|
||||||
elseif (self.level < 239) then return 128/256
|
|
||||||
elseif (self.level < 243) then return 160/256
|
|
||||||
elseif (self.level < 247) then return 192/256
|
|
||||||
elseif (self.level < 251) then return 224/256
|
|
||||||
elseif (self.level < 300) then return 1
|
|
||||||
elseif (self.level < 330) then return 2
|
|
||||||
elseif (self.level < 360) then return 3
|
|
||||||
elseif (self.level < 400) then return 4
|
|
||||||
elseif (self.level < 420) then return 5
|
|
||||||
elseif (self.level < 450) then return 4
|
|
||||||
elseif (self.level < 500) then return 3
|
|
||||||
else return 20
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function TGMPlusGame:getGarbageLimit() return 13 - math.floor(self.level / 100) end
|
|
||||||
|
|
||||||
function TGMPlusGame:advanceOneFrame()
|
|
||||||
if self.clear then
|
|
||||||
self.roll_frames = self.roll_frames + 1
|
|
||||||
if self.roll_frames > 3694 then
|
|
||||||
self.completed = true
|
|
||||||
end
|
|
||||||
elseif self.ready_frames == 0 then
|
|
||||||
self.frames = self.frames + 1
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
function TGMPlusGame:onPieceEnter()
|
|
||||||
if (self.level % 100 ~= 99 and self.level ~= 998) and not self.clear and self.frames ~= 0 then
|
|
||||||
self.level = self.level + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function TGMPlusGame:onPieceLock(piece, cleared_row_count)
|
|
||||||
if cleared_row_count == 0 then self:advanceBottomRow() end
|
|
||||||
end
|
|
||||||
|
|
||||||
function TGMPlusGame: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 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function TGMPlusGame:advanceBottomRow()
|
|
||||||
self.garbage_queue = self.garbage_queue + 1
|
|
||||||
if self.garbage_queue >= self:getGarbageLimit() then
|
|
||||||
self.grid:garbageRise(self.garbage_rows[self.garbage_pos])
|
|
||||||
self.garbage_queue = 0
|
|
||||||
self.garbage_pos = (self.garbage_pos + 1) % 24
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function TGMPlusGame: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 cleared_lines > 0 then
|
|
||||||
self.combo = self.combo + (cleared_lines - 1) * 2
|
|
||||||
self.score = self.score + (
|
|
||||||
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
|
||||||
cleared_lines * self.combo * self.bravo
|
|
||||||
)
|
|
||||||
else
|
|
||||||
self.combo = 1
|
|
||||||
end
|
|
||||||
self.drop_bonus = 0
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function TGMPlusGame:drawGrid(ruleset)
|
|
||||||
self.grid:draw()
|
|
||||||
if self.piece ~= nil and self.level < 100 then
|
|
||||||
self:drawGhostPiece(ruleset)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function TGMPlusGame:getHighscoreData()
|
|
||||||
return {
|
|
||||||
score = self.score,
|
|
||||||
level = self.level,
|
|
||||||
frames = self.frames,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
function TGMPlusGame:getSectionEndLevel()
|
|
||||||
if self.level >= 900 then return 999
|
|
||||||
else return math.floor(self.level / 100 + 1) * 100 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function TGMPlusGame:getBackground()
|
|
||||||
return math.floor(self.level / 100)
|
|
||||||
end
|
|
||||||
|
|
||||||
function TGMPlusGame: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("SCORE", 240, 200, 40, "left")
|
|
||||||
love.graphics.printf("LEVEL", 240, 320, 40, "left")
|
|
||||||
local sg = self.grid:checkSecretGrade()
|
|
||||||
if sg >= 5 then
|
|
||||||
love.graphics.printf("SECRET GRADE", 240, 430, 180, "left")
|
|
||||||
end
|
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
|
||||||
love.graphics.printf(self.score, 240, 220, 90, "left")
|
|
||||||
love.graphics.printf(self.level, 240, 340, 40, "right")
|
|
||||||
love.graphics.printf(self:getSectionEndLevel(), 240, 370, 40, "right")
|
|
||||||
if sg >= 5 then
|
|
||||||
love.graphics.printf(self.SGnames[sg], 240, 450, 180, "left")
|
|
||||||
end
|
|
||||||
|
|
||||||
love.graphics.setFont(font_8x11)
|
|
||||||
love.graphics.printf(formatTime(self.frames), 64, 420, 160, "center")
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
return TGMPlusGame
|
|
||||||
@@ -1,167 +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)
|
|
||||||
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
|
|
||||||
@@ -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
|
|
||||||
@@ -3,27 +3,27 @@ local Randomizer = require 'tetris.randomizers.randomizer'
|
|||||||
local Bag7NoSZOStartRandomizer = Randomizer:extend()
|
local Bag7NoSZOStartRandomizer = Randomizer:extend()
|
||||||
|
|
||||||
function Bag7NoSZOStartRandomizer:shuffleBag()
|
function Bag7NoSZOStartRandomizer:shuffleBag()
|
||||||
local b = self.bag
|
local b = self.bag
|
||||||
local ln = #b
|
local ln = #b
|
||||||
for i = 1, ln do
|
for i = 1, ln do
|
||||||
local j = math.random(i, ln)
|
local j = math.random(i, ln)
|
||||||
b[i], b[j] = b[j], b[i]
|
b[i], b[j] = b[j], b[i]
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function isnotSZO(x) return not(x == "S" or x == "Z" or x == "O") end
|
local function isnotSZO(x) return not(x == "S" or x == "Z" or x == "O") end
|
||||||
|
|
||||||
function Bag7NoSZOStartRandomizer:initialize()
|
function Bag7NoSZOStartRandomizer:initialize()
|
||||||
self.bag = {"I", "J", "L", "O", "S", "T", "Z"}
|
self.bag = {"I", "J", "L", "O", "S", "T", "Z"}
|
||||||
repeat
|
repeat
|
||||||
self:shuffleBag()
|
self:shuffleBag()
|
||||||
until isnotSZO(self.bag[7])
|
until isnotSZO(self.bag[7])
|
||||||
end
|
end
|
||||||
|
|
||||||
function Bag7NoSZOStartRandomizer:generatePiece()
|
function Bag7NoSZOStartRandomizer:generatePiece()
|
||||||
if #self.bag == 0 then
|
if #self.bag == 0 then
|
||||||
self.bag = {"I", "J", "L", "O", "S", "T", "Z"}
|
self.bag = {"I", "J", "L", "O", "S", "T", "Z"}
|
||||||
self:shuffleBag()
|
self:shuffleBag()
|
||||||
end
|
end
|
||||||
return table.remove(self.bag)
|
return table.remove(self.bag)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -4,22 +4,22 @@ local History4RollsRandomizer = Randomizer:extend()
|
|||||||
|
|
||||||
function History4RollsRandomizer:initialize()
|
function History4RollsRandomizer:initialize()
|
||||||
self.history = {"Z", "Z", "Z", "Z"}
|
self.history = {"Z", "Z", "Z", "Z"}
|
||||||
self.first = true
|
self.first = true
|
||||||
end
|
end
|
||||||
|
|
||||||
function History4RollsRandomizer:generatePiece()
|
function History4RollsRandomizer:generatePiece()
|
||||||
if self.first then
|
if self.first then
|
||||||
self.first = false
|
self.first = false
|
||||||
return self:updateHistory(({"L", "J", "I", "T"})[math.random(4)])
|
return self:updateHistory(({"L", "J", "I", "T"})[math.random(4)])
|
||||||
else
|
else
|
||||||
local shapes = {"I", "J", "L", "O", "S", "T", "Z"}
|
local shapes = {"I", "J", "L", "O", "S", "T", "Z"}
|
||||||
for i = 1, 4 do
|
for i = 1, 4 do
|
||||||
local x = math.random(7)
|
local x = math.random(7)
|
||||||
if not inHistory(shapes[x], self.history) or i == 4 then
|
if not inHistory(shapes[x], self.history) or i == 4 then
|
||||||
return self:updateHistory(shapes[x])
|
return self:updateHistory(shapes[x])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function History4RollsRandomizer:updateHistory(shape)
|
function History4RollsRandomizer:updateHistory(shape)
|
||||||
|
|||||||
@@ -4,22 +4,22 @@ local History6RollsRandomizer = Randomizer:extend()
|
|||||||
|
|
||||||
function History6RollsRandomizer:initialize()
|
function History6RollsRandomizer:initialize()
|
||||||
self.history = {"Z", "S", "Z", "S"}
|
self.history = {"Z", "S", "Z", "S"}
|
||||||
self.first = true
|
self.first = true
|
||||||
end
|
end
|
||||||
|
|
||||||
function History6RollsRandomizer:generatePiece()
|
function History6RollsRandomizer:generatePiece()
|
||||||
if self.first then
|
if self.first then
|
||||||
self.first = false
|
self.first = false
|
||||||
return self:updateHistory(({"L", "J", "I", "T"})[math.random(4)])
|
return self:updateHistory(({"L", "J", "I", "T"})[math.random(4)])
|
||||||
else
|
else
|
||||||
local shapes = {"I", "J", "L", "O", "S", "T", "Z"}
|
local shapes = {"I", "J", "L", "O", "S", "T", "Z"}
|
||||||
for i = 1, 6 do
|
for i = 1, 6 do
|
||||||
local x = math.random(7)
|
local x = math.random(7)
|
||||||
if not inHistory(shapes[x], self.history) or i == 6 then
|
if not inHistory(shapes[x], self.history) or i == 6 then
|
||||||
return self:updateHistory(shapes[x])
|
return self:updateHistory(shapes[x])
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function History6RollsRandomizer:updateHistory(shape)
|
function History6RollsRandomizer:updateHistory(shape)
|
||||||
|
|||||||
@@ -3,67 +3,67 @@ local Randomizer = require 'tetris.randomizers.randomizer'
|
|||||||
local History6Rolls35PoolRandomizer = Randomizer:extend()
|
local History6Rolls35PoolRandomizer = Randomizer:extend()
|
||||||
|
|
||||||
function History6Rolls35PoolRandomizer:initialize()
|
function History6Rolls35PoolRandomizer:initialize()
|
||||||
self.first = true
|
self.first = true
|
||||||
self.history = {"Z", "S", "Z", "S"}
|
self.history = {"Z", "S", "Z", "S"}
|
||||||
self.pool = {
|
self.pool = {
|
||||||
"I", "I", "I", "I", "I",
|
"I", "I", "I", "I", "I",
|
||||||
"T", "T", "T", "T", "T",
|
"T", "T", "T", "T", "T",
|
||||||
"L", "L", "L", "L", "L",
|
"L", "L", "L", "L", "L",
|
||||||
"J", "J", "J", "J", "J",
|
"J", "J", "J", "J", "J",
|
||||||
"S", "S", "S", "S", "S",
|
"S", "S", "S", "S", "S",
|
||||||
"Z", "Z", "Z", "Z", "Z",
|
"Z", "Z", "Z", "Z", "Z",
|
||||||
"O", "O", "O", "O", "O",
|
"O", "O", "O", "O", "O",
|
||||||
|
}
|
||||||
|
self.droughts = {
|
||||||
|
I = 0,
|
||||||
|
T = 0,
|
||||||
|
L = 0,
|
||||||
|
J = 0,
|
||||||
|
S = 0,
|
||||||
|
Z = 0,
|
||||||
|
O = 0,
|
||||||
}
|
}
|
||||||
self.droughts = {
|
|
||||||
I = 0,
|
|
||||||
T = 0,
|
|
||||||
L = 0,
|
|
||||||
J = 0,
|
|
||||||
S = 0,
|
|
||||||
Z = 0,
|
|
||||||
O = 0,
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function History6Rolls35PoolRandomizer:generatePiece()
|
function History6Rolls35PoolRandomizer:generatePiece()
|
||||||
local index, x
|
local index, x
|
||||||
if self.first then
|
if self.first then
|
||||||
local prevent = {"S", "Z", "O"}
|
local prevent = {"S", "Z", "O"}
|
||||||
repeat
|
repeat
|
||||||
index = math.random(#self.pool)
|
index = math.random(#self.pool)
|
||||||
x = self.pool[index]
|
x = self.pool[index]
|
||||||
until not inHistory(x, prevent)
|
until not inHistory(x, prevent)
|
||||||
self.first = false
|
self.first = false
|
||||||
else
|
else
|
||||||
for i = 1, 6 do
|
for i = 1, 6 do
|
||||||
index = math.random(#self.pool)
|
index = math.random(#self.pool)
|
||||||
x = self.pool[index]
|
x = self.pool[index]
|
||||||
if not inHistory(x, self.history) or i == 6 then
|
if not inHistory(x, self.history) or i == 6 then
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
self.pool[index] = self:updateHistory(x)
|
self.pool[index] = self:updateHistory(x)
|
||||||
return x
|
return x
|
||||||
end
|
end
|
||||||
|
|
||||||
function History6Rolls35PoolRandomizer:updateHistory(shape)
|
function History6Rolls35PoolRandomizer:updateHistory(shape)
|
||||||
table.remove(self.history, 1)
|
table.remove(self.history, 1)
|
||||||
table.insert(self.history, shape)
|
table.insert(self.history, shape)
|
||||||
|
|
||||||
local highdrought
|
local highdrought
|
||||||
local highdroughtcount = 0
|
local highdroughtcount = 0
|
||||||
for k, v in pairs(self.droughts) do
|
for k, v in pairs(self.droughts) do
|
||||||
if k == shape then
|
if k == shape then
|
||||||
self.droughts[k] = 0
|
self.droughts[k] = 0
|
||||||
else
|
else
|
||||||
self.droughts[k] = v + 1
|
self.droughts[k] = v + 1
|
||||||
if v >= highdroughtcount then
|
if v >= highdroughtcount then
|
||||||
highdrought = k
|
highdrought = k
|
||||||
highdroughtcount = v
|
highdroughtcount = v
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return highdrought
|
return highdrought
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -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
|
|
||||||
@@ -82,18 +82,18 @@ function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|||||||
) and (
|
) and (
|
||||||
piece.rotation == 0 or piece.rotation == 2
|
piece.rotation == 0 or piece.rotation == 2
|
||||||
) then
|
) then
|
||||||
local offsets = new_piece:getBlockOffsets()
|
local offsets = new_piece:getBlockOffsets()
|
||||||
table.sort(offsets, function(A, B) return A.y < B.y or A.y == B.y and A.x < B.y end)
|
table.sort(offsets, function(A, B) return A.y < B.y or A.y == B.y and A.x < B.y end)
|
||||||
for index, offset in pairs(offsets) do
|
for index, offset in pairs(offsets) do
|
||||||
if grid:isOccupied(piece.position.x + offset.x, piece.position.y + offset.y) then
|
if grid:isOccupied(piece.position.x + offset.x, piece.position.y + offset.y) then
|
||||||
if offset.x == 0 then
|
if offset.x == 0 then
|
||||||
return
|
return
|
||||||
else
|
else
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- kick right, kick left
|
-- kick right, kick left
|
||||||
if (grid:canPlacePiece(new_piece:withOffset({x=1, y=0}))) then
|
if (grid:canPlacePiece(new_piece:withOffset({x=1, y=0}))) then
|
||||||
@@ -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 1
|
||||||
|
else
|
||||||
|
return 3
|
||||||
|
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
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ ARS.name = "ACE-ARS"
|
|||||||
ARS.hash = "ArikaACE"
|
ARS.hash = "ArikaACE"
|
||||||
|
|
||||||
ARS.colourscheme = {
|
ARS.colourscheme = {
|
||||||
I = "C",
|
I = "C",
|
||||||
L = "O",
|
L = "O",
|
||||||
J = "B",
|
J = "B",
|
||||||
S = "G",
|
S = "G",
|
||||||
Z = "R",
|
Z = "R",
|
||||||
O = "Y",
|
O = "Y",
|
||||||
T = "M",
|
T = "M",
|
||||||
}
|
}
|
||||||
|
|
||||||
ARS.softdrop_lock = false
|
ARS.softdrop_lock = false
|
||||||
@@ -98,22 +98,23 @@ function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|||||||
) and (
|
) and (
|
||||||
piece.rotation == 0 or piece.rotation == 2
|
piece.rotation == 0 or piece.rotation == 2
|
||||||
) then
|
) then
|
||||||
local offsets = new_piece:getBlockOffsets()
|
local offsets = new_piece:getBlockOffsets()
|
||||||
table.sort(offsets, function(A, B) return A.y < B.y or A.y == B.y and A.x < B.y end)
|
table.sort(offsets, function(A, B) return A.y < B.y or A.y == B.y and A.x < B.y end)
|
||||||
for index, offset in pairs(offsets) do
|
for index, offset in pairs(offsets) do
|
||||||
if grid:isOccupied(piece.position.x + offset.x, piece.position.y + offset.y) then
|
if grid:isOccupied(piece.position.x + offset.x, piece.position.y + offset.y) then
|
||||||
if offset.x == 0 then
|
if offset.x == 0 then
|
||||||
return
|
return
|
||||||
else
|
else
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if piece.shape == "I" then
|
if piece.shape == "I" then
|
||||||
-- special kick rules for I
|
-- special kick rules for I
|
||||||
if new_piece.rotation == 0 or new_piece.rotation == 2 then
|
if new_piece.rotation == 0 or new_piece.rotation == 2 and
|
||||||
|
(piece:isMoveBlocked(grid, {x=-1, y=0}) or piece:isMoveBlocked(grid, {x=1, y=0})) then
|
||||||
-- kick right, right2, left
|
-- kick right, right2, left
|
||||||
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
|
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
|
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
|
||||||
@@ -138,20 +139,20 @@ function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
-- kick right, kick left
|
-- kick right, kick left
|
||||||
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
|
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
|
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
|
||||||
elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then
|
elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
|
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
|
||||||
elseif piece.shape == "T"
|
elseif piece.shape == "T"
|
||||||
and new_piece.rotation == 0
|
and new_piece.rotation == 0
|
||||||
and piece.floorkick == 0
|
and piece.floorkick == 0
|
||||||
and grid:canPlacePiece(new_piece:withOffset({x=0, y=-1}))
|
and grid:canPlacePiece(new_piece:withOffset({x=0, y=-1}))
|
||||||
then
|
then
|
||||||
-- T floorkick
|
-- T floorkick
|
||||||
piece.floorkick = piece.floorkick + 1
|
piece.floorkick = piece.floorkick + 1
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
|
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -163,13 +164,16 @@ end
|
|||||||
|
|
||||||
function ARS:onPieceDrop(piece, grid)
|
function ARS:onPieceDrop(piece, grid)
|
||||||
piece.lock_delay = 0 -- step reset
|
piece.lock_delay = 0 -- step reset
|
||||||
|
if piece.floorkick >= 2 and piece:isDropBlocked(grid) then
|
||||||
|
piece.locked = true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function ARS:onPieceMove(piece, grid)
|
function ARS:onPieceMove(piece, grid)
|
||||||
piece.lock_delay = 0 -- move reset
|
piece.lock_delay = 0 -- move reset
|
||||||
if piece:isDropBlocked(grid) then
|
if piece:isDropBlocked(grid) then
|
||||||
piece.manipulations = piece.manipulations + 1
|
piece.manipulations = piece.manipulations + 1
|
||||||
if piece.manipulations >= 127 then
|
if piece.manipulations >= 128 then
|
||||||
piece.locked = true
|
piece.locked = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -179,13 +183,23 @@ function ARS:onPieceRotate(piece, grid)
|
|||||||
piece.lock_delay = 0 -- rotate reset
|
piece.lock_delay = 0 -- rotate reset
|
||||||
if piece:isDropBlocked(grid) then
|
if piece:isDropBlocked(grid) then
|
||||||
piece.manipulations = piece.manipulations + 1
|
piece.manipulations = piece.manipulations + 1
|
||||||
if piece.manipulations >= 127 then
|
if piece.manipulations >= 128 then
|
||||||
piece.locked = true
|
piece.locked = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if piece.floorkick >= 1 then
|
||||||
|
piece.floorkick = piece.floorkick + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ARS:get180RotationValue()
|
||||||
|
if config.gamesettings.world_reverse == 3 then
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
return 3
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function ARS:get180RotationValue() return 3 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
|
||||||
|
|||||||
@@ -85,22 +85,23 @@ function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|||||||
) and (
|
) and (
|
||||||
piece.rotation == 0 or piece.rotation == 2
|
piece.rotation == 0 or piece.rotation == 2
|
||||||
) then
|
) then
|
||||||
local offsets = new_piece:getBlockOffsets()
|
local offsets = new_piece:getBlockOffsets()
|
||||||
table.sort(offsets, function(A, B) return A.y < B.y or A.y == B.y and A.x < B.y end)
|
table.sort(offsets, function(A, B) return A.y < B.y or A.y == B.y and A.x < B.y end)
|
||||||
for index, offset in pairs(offsets) do
|
for index, offset in pairs(offsets) do
|
||||||
if grid:isOccupied(piece.position.x + offset.x, piece.position.y + offset.y) then
|
if grid:isOccupied(piece.position.x + offset.x, piece.position.y + offset.y) then
|
||||||
if offset.x == 0 then
|
if offset.x == 0 then
|
||||||
return
|
return
|
||||||
else
|
else
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if piece.shape == "I" then
|
if piece.shape == "I" then
|
||||||
-- special kick rules for I
|
-- special kick rules for I
|
||||||
if new_piece.rotation == 0 or new_piece.rotation == 2 then
|
if new_piece.rotation == 0 or new_piece.rotation == 2 and
|
||||||
|
(piece:isMoveBlocked(grid, {x=-1, y=0}) or piece:isMoveBlocked(grid, {x=1, y=0})) then
|
||||||
-- kick right, right2, left
|
-- kick right, right2, left
|
||||||
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
|
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
|
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
|
||||||
@@ -125,20 +126,20 @@ function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
-- kick right, kick left
|
-- kick right, kick left
|
||||||
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
|
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
|
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
|
||||||
elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then
|
elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
|
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
|
||||||
elseif piece.shape == "T"
|
elseif piece.shape == "T"
|
||||||
and new_piece.rotation == 0
|
and new_piece.rotation == 0
|
||||||
and piece.floorkick == 0
|
and piece.floorkick == 0
|
||||||
and grid:canPlacePiece(new_piece:withOffset({x=0, y=-1}))
|
and grid:canPlacePiece(new_piece:withOffset({x=0, y=-1}))
|
||||||
then
|
then
|
||||||
-- T floorkick
|
-- T floorkick
|
||||||
piece.floorkick = piece.floorkick + 1
|
piece.floorkick = piece.floorkick + 1
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
|
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -150,13 +151,16 @@ end
|
|||||||
|
|
||||||
function ARS:onPieceDrop(piece, grid)
|
function ARS:onPieceDrop(piece, grid)
|
||||||
piece.lock_delay = 0 -- step reset
|
piece.lock_delay = 0 -- step reset
|
||||||
|
if piece.floorkick >= 2 and piece:isDropBlocked(grid) then
|
||||||
|
piece.locked = true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function ARS:onPieceMove(piece, grid)
|
function ARS:onPieceMove(piece, grid)
|
||||||
piece.lock_delay = 0 -- move reset
|
piece.lock_delay = 0 -- move reset
|
||||||
if piece:isDropBlocked(grid) then
|
if piece:isDropBlocked(grid) then
|
||||||
piece.manipulations = piece.manipulations + 1
|
piece.manipulations = piece.manipulations + 1
|
||||||
if piece.manipulations >= 127 then
|
if piece.manipulations >= 128 then
|
||||||
piece.locked = true
|
piece.locked = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -166,13 +170,23 @@ function ARS:onPieceRotate(piece, grid)
|
|||||||
piece.lock_delay = 0 -- rotate reset
|
piece.lock_delay = 0 -- rotate reset
|
||||||
if piece:isDropBlocked(grid) then
|
if piece:isDropBlocked(grid) then
|
||||||
piece.manipulations = piece.manipulations + 1
|
piece.manipulations = piece.manipulations + 1
|
||||||
if piece.manipulations >= 127 then
|
if piece.manipulations >= 128 then
|
||||||
piece.locked = true
|
piece.locked = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
if piece.floorkick >= 1 then
|
||||||
|
piece.floorkick = piece.floorkick + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ARS:get180RotationValue()
|
||||||
|
if config.gamesettings.world_reverse == 3 then
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
return 3
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function ARS:get180RotationValue() return 3 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
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ SRS.name = "ACE-SRS"
|
|||||||
SRS.hash = "ACE Standard"
|
SRS.hash = "ACE Standard"
|
||||||
SRS.world = true
|
SRS.world = true
|
||||||
SRS.colourscheme = {
|
SRS.colourscheme = {
|
||||||
I = "C",
|
I = "C",
|
||||||
L = "O",
|
L = "O",
|
||||||
J = "B",
|
J = "B",
|
||||||
S = "G",
|
S = "G",
|
||||||
Z = "R",
|
Z = "R",
|
||||||
O = "Y",
|
O = "Y",
|
||||||
T = "M",
|
T = "M",
|
||||||
}
|
}
|
||||||
SRS.softdrop_lock = false
|
SRS.softdrop_lock = false
|
||||||
SRS.harddrop_lock = true
|
SRS.harddrop_lock = true
|
||||||
@@ -184,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
|
||||||
|
|||||||
@@ -85,22 +85,23 @@ function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|||||||
) and (
|
) and (
|
||||||
piece.rotation == 0 or piece.rotation == 2
|
piece.rotation == 0 or piece.rotation == 2
|
||||||
) then
|
) then
|
||||||
local offsets = new_piece:getBlockOffsets()
|
local offsets = new_piece:getBlockOffsets()
|
||||||
table.sort(offsets, function(A, B) return A.y < B.y or A.y == B.y and A.x < B.y end)
|
table.sort(offsets, function(A, B) return A.y < B.y or A.y == B.y and A.x < B.y end)
|
||||||
for index, offset in pairs(offsets) do
|
for index, offset in pairs(offsets) do
|
||||||
if grid:isOccupied(piece.position.x + offset.x, piece.position.y + offset.y) then
|
if grid:isOccupied(piece.position.x + offset.x, piece.position.y + offset.y) then
|
||||||
if offset.x == 0 then
|
if offset.x == 0 then
|
||||||
return
|
return
|
||||||
else
|
else
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if piece.shape == "I" then
|
if piece.shape == "I" then
|
||||||
-- special kick rules for I
|
-- special kick rules for I
|
||||||
if new_piece.rotation == 0 or new_piece.rotation == 2 then
|
if (new_piece.rotation == 0 or new_piece.rotation == 2) and
|
||||||
|
(piece:isMoveBlocked(grid, {x=-1, y=0}) or piece:isMoveBlocked(grid, {x=1, y=0})) then
|
||||||
-- kick right, right2, left
|
-- kick right, right2, left
|
||||||
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
|
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
|
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
|
||||||
@@ -125,20 +126,20 @@ function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
-- kick right, kick left
|
-- kick right, kick left
|
||||||
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
|
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
|
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
|
||||||
elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then
|
elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
|
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
|
||||||
elseif piece.shape == "T"
|
elseif piece.shape == "T"
|
||||||
and new_piece.rotation == 0
|
and new_piece.rotation == 0
|
||||||
and piece.floorkick == 0
|
and piece.floorkick == 0
|
||||||
and grid:canPlacePiece(new_piece:withOffset({x=0, y=-1}))
|
and grid:canPlacePiece(new_piece:withOffset({x=0, y=-1}))
|
||||||
then
|
then
|
||||||
-- T floorkick
|
-- T floorkick
|
||||||
piece.floorkick = piece.floorkick + 1
|
piece.floorkick = piece.floorkick + 1
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
|
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
@@ -149,9 +150,25 @@ end
|
|||||||
|
|
||||||
function ARS:onPieceDrop(piece, grid)
|
function ARS:onPieceDrop(piece, grid)
|
||||||
piece.lock_delay = 0 -- step reset
|
piece.lock_delay = 0 -- step reset
|
||||||
|
if piece.floorkick >= 2 and piece:isDropBlocked(grid) then
|
||||||
|
piece.locked = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ARS:onPieceRotate(piece, grid)
|
||||||
|
if piece.floorkick >= 1 then
|
||||||
|
piece.floorkick = piece.floorkick + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ARS:get180RotationValue()
|
||||||
|
if config.gamesettings.world_reverse == 3 then
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
return 3
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function ARS:get180RotationValue() return 3 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
|
||||||
|
|||||||
@@ -364,9 +364,9 @@ function CRS:attemptRotate(new_inputs, piece, grid, initial)
|
|||||||
|
|
||||||
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 self.world and config.gamesettings.world_reverse == 2 then
|
||||||
rot_dir = 4 - rot_dir
|
rot_dir = 4 - rot_dir
|
||||||
end
|
end
|
||||||
|
|
||||||
local new_piece = piece:withRelativeRotation(rot_dir)
|
local new_piece = piece:withRelativeRotation(rot_dir)
|
||||||
self:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
self:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||||
|
|||||||
@@ -1,173 +0,0 @@
|
|||||||
local Piece = require 'tetris.components.piece'
|
|
||||||
local Ruleset = require 'tetris.rulesets.ruleset'
|
|
||||||
|
|
||||||
local CRAP = Ruleset:extend()
|
|
||||||
|
|
||||||
CRAP.name = "C.R.A.P."
|
|
||||||
CRAP.hash = "Completely Random Auto-Positioner"
|
|
||||||
CRAP.world = true
|
|
||||||
CRAP.colors={"C","O","M","R","G","Y","B"}
|
|
||||||
CRAP.colourscheme = {
|
|
||||||
I = CRAP.colors[math.ceil(math.random(7))],
|
|
||||||
L = CRAP.colors[math.ceil(math.random(7))],
|
|
||||||
J = CRAP.colors[math.ceil(math.random(7))],
|
|
||||||
S = CRAP.colors[math.ceil(math.random(7))],
|
|
||||||
Z = CRAP.colors[math.ceil(math.random(7))],
|
|
||||||
O = CRAP.colors[math.ceil(math.random(7))],
|
|
||||||
T = CRAP.colors[math.ceil(math.random(7))],
|
|
||||||
}
|
|
||||||
CRAP.softdrop_lock = true
|
|
||||||
CRAP.harddrop_lock = false
|
|
||||||
|
|
||||||
CRAP.enable_IRS_wallkicks = true
|
|
||||||
|
|
||||||
CRAP.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 },
|
|
||||||
}
|
|
||||||
|
|
||||||
CRAP.big_spawn_positions = {
|
|
||||||
I = { x=3, y=2 },
|
|
||||||
J = { x=2, y=3 },
|
|
||||||
L = { x=2, y=3 },
|
|
||||||
O = { x=3, y=3 },
|
|
||||||
S = { x=2, y=3 },
|
|
||||||
T = { x=2, y=3 },
|
|
||||||
Z = { x=2, y=3 },
|
|
||||||
}
|
|
||||||
|
|
||||||
CRAP.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 CRAP:attemptRotate(new_inputs, piece, grid, initial)
|
|
||||||
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 = self:get180RotationValue()
|
|
||||||
end
|
|
||||||
|
|
||||||
if rot_dir == 0 then return end
|
|
||||||
if self.world and config.gamesettings.world_reverse == 2 then
|
|
||||||
rot_dir = 4 - rot_dir
|
|
||||||
end
|
|
||||||
|
|
||||||
local new_piece = piece:withRelativeRotation(rot_dir)
|
|
||||||
|
|
||||||
self:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|
||||||
end
|
|
||||||
|
|
||||||
function CRAP:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|
||||||
|
|
||||||
for i=1,20 do
|
|
||||||
dx=math.floor(math.random(11))-5
|
|
||||||
dy=math.floor(math.random(11))-5
|
|
||||||
if grid:canPlacePiece(new_piece:withOffset({x=dx, y=dy})) then
|
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=dx, y=dy})
|
|
||||||
self:onPieceRotate(piece, grid)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
function CRAP:onPieceCreate(piece, grid)
|
|
||||||
CRAP:randomizeColours()
|
|
||||||
piece.manipulations = 0
|
|
||||||
piece.rotations = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function CRAP:onPieceDrop(piece, grid)
|
|
||||||
CRAP:randomizeColours()
|
|
||||||
piece.lock_delay = 0 -- step reset
|
|
||||||
end
|
|
||||||
|
|
||||||
function CRAP:onPieceMove(piece, grid)
|
|
||||||
CRAP:randomizeColours()
|
|
||||||
piece.lock_delay = 0 -- move reset
|
|
||||||
if piece:isDropBlocked(grid) then
|
|
||||||
piece.manipulations = piece.manipulations + 1
|
|
||||||
if piece.manipulations >= 10 then
|
|
||||||
piece.locked = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function CRAP:onPieceRotate(piece, grid)
|
|
||||||
CRAP:randomizeColours()
|
|
||||||
piece.lock_delay = 0 -- rotate reset
|
|
||||||
if piece:isDropBlocked(grid) then
|
|
||||||
piece.rotations = piece.rotations + 1
|
|
||||||
if piece.rotations >= 8 then
|
|
||||||
piece.locked = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function CRAP:get180RotationValue() return 2 end
|
|
||||||
|
|
||||||
function CRAP:randomizeColours()
|
|
||||||
CRAP.colourscheme = {
|
|
||||||
I = CRAP.colors[math.ceil(math.random(7))],
|
|
||||||
L = CRAP.colors[math.ceil(math.random(7))],
|
|
||||||
J = CRAP.colors[math.ceil(math.random(7))],
|
|
||||||
S = CRAP.colors[math.ceil(math.random(7))],
|
|
||||||
Z = CRAP.colors[math.ceil(math.random(7))],
|
|
||||||
O = CRAP.colors[math.ceil(math.random(7))],
|
|
||||||
T = CRAP.colors[math.ceil(math.random(7))],
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
return CRAP
|
|
||||||
@@ -1,153 +0,0 @@
|
|||||||
local Piece = require 'tetris.components.piece'
|
|
||||||
local Ruleset = require 'tetris.rulesets.ruleset'
|
|
||||||
|
|
||||||
local DTET = Ruleset:extend()
|
|
||||||
|
|
||||||
DTET.name = "D.R.S."
|
|
||||||
DTET.hash = "DTET"
|
|
||||||
|
|
||||||
DTET.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 },
|
|
||||||
}
|
|
||||||
|
|
||||||
DTET.big_spawn_positions = {
|
|
||||||
I = { x=3, y=2 },
|
|
||||||
J = { x=2, y=3 },
|
|
||||||
L = { x=2, y=3 },
|
|
||||||
O = { x=3, y=3 },
|
|
||||||
S = { x=2, y=3 },
|
|
||||||
T = { x=2, y=3 },
|
|
||||||
Z = { x=2, y=3 },
|
|
||||||
}
|
|
||||||
|
|
||||||
DTET.block_offsets = {
|
|
||||||
I={
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} },
|
|
||||||
{ {x=-1, y=-1}, {x=-1, y=-2}, {x=-1, y=0}, {x=-1, y=1} },
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} },
|
|
||||||
{ {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=0, y=1} },
|
|
||||||
},
|
|
||||||
J={
|
|
||||||
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=1, y=0} },
|
|
||||||
{ {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=-1, y=0} },
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=-1, y=-1} },
|
|
||||||
{ {x=0, y=-1}, {x=1, y=-2}, {x=0, y=-2}, {x=0, y=0} },
|
|
||||||
},
|
|
||||||
L={
|
|
||||||
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=-1, y=0} },
|
|
||||||
{ {x=0, y=-1}, {x=-1, y=-2}, {x=0, y=-2}, {x=0, y=0} },
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=1, y=-1} },
|
|
||||||
{ {x=0, y=-2}, {x=0, y=-1}, {x=1, y=0}, {x=0, y=0} },
|
|
||||||
},
|
|
||||||
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=-2}, {x=-1, y=-1}, {x=0, y=-1}, {x=0, y=0} },
|
|
||||||
{ {x=-1, y=0}, {x=0, y=0}, {x=0, y=-1}, {x=1, y=-1} },
|
|
||||||
{ {x=1, y=0}, {x=1, y=-1}, {x=0, y=-1}, {x=0, y=-2} },
|
|
||||||
},
|
|
||||||
T={
|
|
||||||
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=0, y=0} },
|
|
||||||
{ {x=0, y=-1}, {x=0, y=0}, {x=-1, y=-1}, {x=0, y=-2} },
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=0, y=-1} },
|
|
||||||
{ {x=0, y=-1}, {x=0, y=0}, {x=1, y=-1}, {x=0, y=-2} },
|
|
||||||
},
|
|
||||||
Z={
|
|
||||||
{ {x=1, y=0}, {x=0, y=0}, {x=0, y=-1}, {x=-1, y=-1} },
|
|
||||||
{ {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1}, {x=0, y=-2} },
|
|
||||||
{ {x=1, y=0}, {x=0, y=0}, {x=0, y=-1}, {x=-1, y=-1} },
|
|
||||||
{ {x=1, y=-2}, {x=1, y=-1}, {x=0, y=-1}, {x=0, y=0} },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
-- clockwise kicks: {{x=1, y=0}, {x=-1, y=0}, {x=0, y=1}, {x=1, y=1}, {x=-1, y=1}},
|
|
||||||
-- counterclockwise kicks: {{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
|
||||||
|
|
||||||
DTET.wallkicks_3x3 = {
|
|
||||||
[0]={
|
|
||||||
[1]={{x=1, y=0}, {x=-1, y=0}, {x=0, y=1}, {x=1, y=1}, {x=-1, y=1}},
|
|
||||||
[2]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
|
||||||
[3]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
|
||||||
},
|
|
||||||
[1]={
|
|
||||||
[0]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
|
||||||
[2]={{x=1, y=0}, {x=-1, y=0}, {x=0, y=1}, {x=1, y=1}, {x=-1, y=1}},
|
|
||||||
[3]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
|
||||||
},
|
|
||||||
[2]={
|
|
||||||
[0]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
|
||||||
[1]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
|
||||||
[3]={{x=1, y=0}, {x=-1, y=0}, {x=0, y=1}, {x=1, y=1}, {x=-1, y=1}},
|
|
||||||
},
|
|
||||||
[3]={
|
|
||||||
[0]={{x=1, y=0}, {x=-1, y=0}, {x=0, y=1}, {x=1, y=1}, {x=-1, y=1}},
|
|
||||||
[1]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
|
||||||
[2]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
DTET.wallkicks_line = {
|
|
||||||
[0]={
|
|
||||||
[1]={{x=1, y=0}, {x=-1, y=0}, {x=0, y=1}, {x=1, y=1}, {x=-1, y=1}},
|
|
||||||
[2]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
|
||||||
[3]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
|
||||||
},
|
|
||||||
[1]={
|
|
||||||
[0]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
|
||||||
[2]={{x=1, y=0}, {x=-1, y=0}, {x=0, y=1}, {x=1, y=1}, {x=-1, y=1}},
|
|
||||||
[3]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
|
||||||
},
|
|
||||||
[2]={
|
|
||||||
[0]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
|
||||||
[1]={{x=1, y=0}, {x=-1, y=0}, {x=0, y=1}, {x=1, y=1}, {x=-1, y=1}},
|
|
||||||
[3]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
|
||||||
},
|
|
||||||
[3]={
|
|
||||||
[0]={{x=1, y=0}, {x=-1, y=0}, {x=0, y=1}, {x=1, y=1}, {x=-1, y=1}},
|
|
||||||
[1]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
|
||||||
[2]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
|
||||||
},
|
|
||||||
};
|
|
||||||
|
|
||||||
function DTET:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|
||||||
|
|
||||||
local kicks
|
|
||||||
if piece.shape == "O" then
|
|
||||||
return
|
|
||||||
elseif piece.shape == "I" then
|
|
||||||
kicks = DTET.wallkicks_line[piece.rotation][new_piece.rotation]
|
|
||||||
else
|
|
||||||
kicks = DTET.wallkicks_3x3[piece.rotation][new_piece.rotation]
|
|
||||||
end
|
|
||||||
|
|
||||||
assert(piece.rotation ~= new_piece.rotation)
|
|
||||||
|
|
||||||
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(offset)
|
|
||||||
self:onPieceRotate(piece, grid)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function DTET:onPieceDrop(piece, grid)
|
|
||||||
piece.lock_delay = 0 -- step reset
|
|
||||||
end
|
|
||||||
|
|
||||||
function DTET:getDefaultOrientation() return 1 end
|
|
||||||
|
|
||||||
return DTET
|
|
||||||
@@ -1,45 +0,0 @@
|
|||||||
local Piece = require 'tetris.components.piece'
|
|
||||||
local ARS = require 'tetris.rulesets.arika'
|
|
||||||
|
|
||||||
local EHeart = ARS:extend()
|
|
||||||
|
|
||||||
EHeart.name = "E-Heart ARS"
|
|
||||||
EHeart.hash = "EHeartARS"
|
|
||||||
|
|
||||||
function EHeart:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|
||||||
|
|
||||||
-- I and O don't kick
|
|
||||||
if (piece.shape == "I" or piece.shape == "O") then return end
|
|
||||||
|
|
||||||
-- center column rule (kicks)
|
|
||||||
local offsets = new_piece:getBlockOffsets()
|
|
||||||
table.sort(offsets, function(A, B) return A.y < B.y or A.y == B.y and A.x < B.y end)
|
|
||||||
for index, offset in pairs(offsets) do
|
|
||||||
if grid:isOccupied(piece.position.x + offset.x, piece.position.y + offset.y) then
|
|
||||||
-- individual checks for all 9 cells, in the given order
|
|
||||||
if offset.y < 0 then
|
|
||||||
if offset.x < 0 then self:lateralKick(1, piece, new_piece, rot_dir, grid)
|
|
||||||
elseif offset.x == 0 then return
|
|
||||||
elseif offset.x > 0 then self:lateralKick(-1, piece, new_piece, rot_dir, grid) end
|
|
||||||
elseif offset.y == 0 then
|
|
||||||
if offset.x < 0 then self:lateralKick(1, piece, new_piece, rot_dir, grid)
|
|
||||||
elseif offset.x == 0 then return
|
|
||||||
elseif offset.x > 0 then self:lateralKick(-1, piece, new_piece, rot_dir, grid) end
|
|
||||||
elseif offset.y > 0 then
|
|
||||||
if offset.x < 0 then self:lateralKick(1, piece, new_piece, rot_dir, grid)
|
|
||||||
elseif offset.x == 0 then return
|
|
||||||
elseif offset.x > 0 then self:lateralKick(-1, piece, new_piece, rot_dir, grid) end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
function EHeart:lateralKick(dx, piece, new_piece, rot_dir, grid)
|
|
||||||
if (grid:canPlacePiece(new_piece:withOffset({x=dx, y=0}))) then
|
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=dx, y=0})
|
|
||||||
self:onPieceRotate(piece, grid)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return EHeart
|
|
||||||
@@ -1,102 +0,0 @@
|
|||||||
local Piece = require 'tetris.components.piece'
|
|
||||||
local SRS = require 'tetris.rulesets.standard_exp'
|
|
||||||
|
|
||||||
local PPTPRS = SRS:extend()
|
|
||||||
|
|
||||||
PPTPRS.name = "PPTPRS"
|
|
||||||
PPTPRS.hash = "Puyo Tetris Pentos"
|
|
||||||
|
|
||||||
PPTPRS.block_offsets = {
|
|
||||||
I={
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0}, {x=-3, y=0} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=0, y=2}, {x=0, y=-2} },
|
|
||||||
{ {x=0, y=1}, {x=-1, y=1}, {x=-2, y=1}, {x=1, y=1}, {x=2, y=1} },
|
|
||||||
{ {x=-1, y=0}, {x=-1, y=-1}, {x=-1, y=1}, {x=-1, y=2}, {x=-1, y=3} },
|
|
||||||
},
|
|
||||||
J={
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=-1, y=-1}, {x=0, y=1} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1} , {x=1, y=-1}, {x=-1, y=0} },
|
|
||||||
{ {x=0, y=0}, {x=1, y=0}, {x=-1, y=0}, {x=1, y=1}, {x=0, y=-1} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=-1}, {x=-1, y=1}, {x=1, y=0} },
|
|
||||||
},
|
|
||||||
L={
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=1, y=-1}, {x=-1, y=1} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=1, y=1}, {x=-1, y=-1} },
|
|
||||||
{ {x=0, y=0}, {x=1, y=0}, {x=-1, y=0}, {x=-1, y=1}, {x=1, y=-1} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=1} },
|
|
||||||
},
|
|
||||||
O={
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1}, {x=-1, y=1} },
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1}, {x=-2, y=-1} },
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1}, {x=0, y=-2} },
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1}, {x=1, y=0} },
|
|
||||||
},
|
|
||||||
S={
|
|
||||||
{ {x=1, y=-1}, {x=0, y=-1}, {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0} },
|
|
||||||
{ {x=1, y=1}, {x=1, y=0}, {x=0, y=0}, {x=0, y=-1}, {x=0, y=-2} },
|
|
||||||
{ {x=-1, y=1}, {x=0, y=1}, {x=0, y=0}, {x=1, y=0}, {x=2, y=0} },
|
|
||||||
{ {x=-1, y=-1}, {x=-1, y=0}, {x=0, y=0}, {x=0, y=1}, {x=0, y=2} },
|
|
||||||
},
|
|
||||||
T={
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=0, y=-1}, {x=0, y=-2} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=1, y=0}, {x=2, y=0} },
|
|
||||||
{ {x=0, y=0}, {x=1, y=0}, {x=-1, y=0}, {x=0, y=1}, {x=0, y=2} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=-1}, {x=-1, y=0}, {x=-2, 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=-1}, {x=1, y=0}, {x=0, y=0}, {x=0, y=1}, {x=-1, 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=1}, {x=-1, y=0}, {x=0, y=0}, {x=0, y=-1}, {x=1, y=-1} },
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
PPTPRS.wallkicks_O = {
|
|
||||||
[0]={
|
|
||||||
[1]={{x=0, y=1}},
|
|
||||||
[2]={{x=0, y=1}},
|
|
||||||
[3]={{x=-1, y=0}},
|
|
||||||
},
|
|
||||||
[1]={
|
|
||||||
[0]={{x=0, y=-1}},
|
|
||||||
[2]={{x=-1, y=0}},
|
|
||||||
[3]={{x=-1, y=0}},
|
|
||||||
},
|
|
||||||
[2]={
|
|
||||||
[0]={{x=0, y=-1}},
|
|
||||||
[1]={{x=1, y=0}},
|
|
||||||
[3]={{x=0, y=-1}},
|
|
||||||
},
|
|
||||||
[3]={
|
|
||||||
[0]={{x=1, y=0}},
|
|
||||||
[1]={{x=1, y=0}},
|
|
||||||
[2]={{x=0, y=1}},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
function PPTPRS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|
||||||
local kicks
|
|
||||||
|
|
||||||
if piece.shape == "O" then
|
|
||||||
kicks = PPTPRS.wallkicks_O[piece.rotation][new_piece.rotation]
|
|
||||||
elseif piece.shape == "I" then
|
|
||||||
kicks = SRS.wallkicks_line[piece.rotation][new_piece.rotation]
|
|
||||||
else
|
|
||||||
kicks = SRS.wallkicks_3x3[piece.rotation][new_piece.rotation]
|
|
||||||
end
|
|
||||||
|
|
||||||
assert(piece.rotation ~= new_piece.rotation)
|
|
||||||
|
|
||||||
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(offset)
|
|
||||||
self:onPieceRotate(piece, grid)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
end
|
|
||||||
|
|
||||||
return PPTPRS
|
|
||||||
@@ -9,42 +9,74 @@ Ruleset.hash = ""
|
|||||||
-- Arika-type ruleset defaults
|
-- Arika-type ruleset defaults
|
||||||
Ruleset.world = false
|
Ruleset.world = false
|
||||||
Ruleset.colourscheme = {
|
Ruleset.colourscheme = {
|
||||||
I = "R",
|
I = "R",
|
||||||
L = "O",
|
L = "O",
|
||||||
J = "B",
|
J = "B",
|
||||||
S = "M",
|
S = "M",
|
||||||
Z = "G",
|
Z = "G",
|
||||||
O = "Y",
|
O = "Y",
|
||||||
T = "C",
|
T = "C",
|
||||||
}
|
}
|
||||||
Ruleset.softdrop_lock = true
|
Ruleset.softdrop_lock = true
|
||||||
Ruleset.harddrop_lock = false
|
Ruleset.harddrop_lock = false
|
||||||
|
|
||||||
Ruleset.enable_IRS_wallkicks = false
|
Ruleset.enable_IRS_wallkicks = false
|
||||||
|
Ruleset.are_cancel = false
|
||||||
|
|
||||||
-- Component functions.
|
-- Component functions.
|
||||||
|
|
||||||
function Ruleset:new()
|
function Ruleset:new()
|
||||||
blocks["bone"] = (not self.world) and
|
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"),
|
R = love.graphics.newImage("res/img/bone.png"),
|
||||||
Y = love.graphics.newImage("res/img/bone.png"),
|
O = love.graphics.newImage("res/img/bone.png"),
|
||||||
G = love.graphics.newImage("res/img/bone.png"),
|
Y = love.graphics.newImage("res/img/bone.png"),
|
||||||
C = love.graphics.newImage("res/img/bone.png"),
|
G = love.graphics.newImage("res/img/bone.png"),
|
||||||
B = love.graphics.newImage("res/img/bone.png"),
|
C = love.graphics.newImage("res/img/bone.png"),
|
||||||
M = love.graphics.newImage("res/img/bone.png"),
|
B = love.graphics.newImage("res/img/bone.png"),
|
||||||
X = love.graphics.newImage("res/img/bone.png"),
|
M = love.graphics.newImage("res/img/bone.png"),
|
||||||
} or {
|
F = love.graphics.newImage("res/img/bone.png"),
|
||||||
R = love.graphics.newImage("res/img/bonew.png"),
|
A = love.graphics.newImage("res/img/bone.png"),
|
||||||
O = love.graphics.newImage("res/img/bonew.png"),
|
X = love.graphics.newImage("res/img/bone.png"),
|
||||||
Y = love.graphics.newImage("res/img/bonew.png"),
|
} or {
|
||||||
G = love.graphics.newImage("res/img/bonew.png"),
|
R = love.graphics.newImage("res/img/bonew.png"),
|
||||||
C = love.graphics.newImage("res/img/bonew.png"),
|
O = love.graphics.newImage("res/img/bonew.png"),
|
||||||
B = love.graphics.newImage("res/img/bonew.png"),
|
Y = love.graphics.newImage("res/img/bonew.png"),
|
||||||
M = love.graphics.newImage("res/img/bonew.png"),
|
G = love.graphics.newImage("res/img/bonew.png"),
|
||||||
X = 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
|
end
|
||||||
|
|
||||||
function Ruleset:rotatePiece(inputs, piece, grid, prev_inputs, initial)
|
function Ruleset:rotatePiece(inputs, piece, grid, prev_inputs, initial)
|
||||||
@@ -76,7 +108,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
|
||||||
|
|
||||||
@@ -96,16 +128,16 @@ function Ruleset:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|||||||
-- do nothing in default ruleset
|
-- do nothing in default ruleset
|
||||||
end
|
end
|
||||||
|
|
||||||
function Ruleset:movePiece(piece, grid, move)
|
function Ruleset:movePiece(piece, grid, move, instant)
|
||||||
local x = piece.position.x
|
local x = piece.position.x
|
||||||
if move == "left" then
|
if move == "left" then
|
||||||
piece:moveInGrid({x=-1, y=0}, 1, grid)
|
piece:moveInGrid({x=-1, y=0}, 1, grid, false)
|
||||||
elseif move == "speedleft" then
|
|
||||||
piece:moveInGrid({x=-1, y=0}, 10, grid)
|
|
||||||
elseif move == "right" then
|
elseif move == "right" then
|
||||||
piece:moveInGrid({x=1, y=0}, 1, grid)
|
piece:moveInGrid({x=1, y=0}, 1, grid, false)
|
||||||
|
elseif move == "speedleft" then
|
||||||
|
piece:moveInGrid({x=-1, y=0}, 10, grid, instant)
|
||||||
elseif move == "speedright" then
|
elseif move == "speedright" then
|
||||||
piece:moveInGrid({x=1, y=0}, 10, grid)
|
piece:moveInGrid({x=1, y=0}, 10, grid, instant)
|
||||||
end
|
end
|
||||||
if piece.position.x ~= x then
|
if piece.position.x ~= x then
|
||||||
self:onPieceMove(piece, grid)
|
self:onPieceMove(piece, grid)
|
||||||
@@ -149,7 +181,7 @@ function Ruleset:getDefaultOrientation() return 1 end
|
|||||||
function Ruleset:initializePiece(
|
function Ruleset:initializePiece(
|
||||||
inputs, data, grid, gravity, prev_inputs,
|
inputs, data, grid, gravity, prev_inputs,
|
||||||
move, lock_delay, drop_speed,
|
move, lock_delay, drop_speed,
|
||||||
drop_locked, hard_drop_locked, big
|
drop_locked, hard_drop_locked, big, irs
|
||||||
)
|
)
|
||||||
local spawn_positions
|
local spawn_positions
|
||||||
if big then
|
if big then
|
||||||
@@ -157,7 +189,7 @@ function Ruleset:initializePiece(
|
|||||||
else
|
else
|
||||||
spawn_positions = self.spawn_positions
|
spawn_positions = self.spawn_positions
|
||||||
end
|
end
|
||||||
local colours = ({self.colourscheme, ColourSchemes.Arika, ColourSchemes.TTC})[config.gamesettings.piece_colour]
|
local colours = ({self.colourscheme, ColourSchemes.Arika, ColourSchemes.TTC})[config.gamesettings.piece_colour]
|
||||||
|
|
||||||
local piece = Piece(data.shape, data.orientation - 1, {
|
local piece = Piece(data.shape, data.orientation - 1, {
|
||||||
x = spawn_positions[data.shape].x,
|
x = spawn_positions[data.shape].x,
|
||||||
@@ -165,7 +197,7 @@ function Ruleset:initializePiece(
|
|||||||
}, self.block_offsets, 0, 0, data.skin, colours[data.shape], big)
|
}, self.block_offsets, 0, 0, data.skin, colours[data.shape], big)
|
||||||
|
|
||||||
self:onPieceCreate(piece)
|
self:onPieceCreate(piece)
|
||||||
self:rotatePiece(inputs, piece, grid, {}, true)
|
if irs then self:rotatePiece(inputs, piece, grid, {}, true) end
|
||||||
self:dropPiece(inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked)
|
self:dropPiece(inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked)
|
||||||
return piece
|
return piece
|
||||||
end
|
end
|
||||||
@@ -180,7 +212,7 @@ function Ruleset:processPiece(
|
|||||||
hard_drop_enabled, additive_gravity
|
hard_drop_enabled, additive_gravity
|
||||||
)
|
)
|
||||||
self:rotatePiece(inputs, piece, grid, prev_inputs, false)
|
self:rotatePiece(inputs, piece, grid, prev_inputs, false)
|
||||||
self:movePiece(piece, grid, move)
|
self:movePiece(piece, grid, move, gravity >= 20)
|
||||||
self:dropPiece(
|
self:dropPiece(
|
||||||
inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked,
|
inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked,
|
||||||
hard_drop_enabled, additive_gravity
|
hard_drop_enabled, additive_gravity
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ SRS.name = "Guideline SRS"
|
|||||||
SRS.hash = "Standard"
|
SRS.hash = "Standard"
|
||||||
SRS.world = true
|
SRS.world = true
|
||||||
SRS.colourscheme = {
|
SRS.colourscheme = {
|
||||||
I = "C",
|
I = "C",
|
||||||
L = "O",
|
L = "O",
|
||||||
J = "B",
|
J = "B",
|
||||||
S = "G",
|
S = "G",
|
||||||
Z = "R",
|
Z = "R",
|
||||||
O = "Y",
|
O = "Y",
|
||||||
T = "M",
|
T = "M",
|
||||||
}
|
}
|
||||||
SRS.softdrop_lock = false
|
SRS.softdrop_lock = false
|
||||||
SRS.harddrop_lock = true
|
SRS.harddrop_lock = true
|
||||||
@@ -132,13 +132,13 @@ SRS.wallkicks_line = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
function SRS:check_new_low(piece)
|
function SRS:check_new_low(piece)
|
||||||
for _, block in pairs(piece:getBlockOffsets()) do
|
for _, block in pairs(piece:getBlockOffsets()) do
|
||||||
local y = piece.position.y + block.y
|
local y = piece.position.y + block.y
|
||||||
if y > piece.lowest_y then
|
if y > piece.lowest_y then
|
||||||
piece.manipulations = 0
|
piece.manipulations = 0
|
||||||
piece.lowest_y = y
|
piece.lowest_y = y
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Component functions.
|
-- Component functions.
|
||||||
@@ -170,16 +170,16 @@ end
|
|||||||
|
|
||||||
function SRS:onPieceCreate(piece, grid)
|
function SRS:onPieceCreate(piece, grid)
|
||||||
piece.manipulations = 0
|
piece.manipulations = 0
|
||||||
piece.lowest_y = -math.huge
|
piece.lowest_y = -math.huge
|
||||||
end
|
end
|
||||||
|
|
||||||
function SRS:onPieceDrop(piece, grid)
|
function SRS:onPieceDrop(piece, grid)
|
||||||
self:check_new_low(piece)
|
self:check_new_low(piece)
|
||||||
if piece.manipulations >= 15 and piece:isDropBlocked(grid) then
|
if piece.manipulations >= 15 and piece:isDropBlocked(grid) then
|
||||||
piece.locked = true
|
piece.locked = true
|
||||||
else
|
else
|
||||||
piece.lock_delay = 0 -- step reset
|
piece.lock_delay = 0 -- step reset
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function SRS:onPieceMove(piece, grid)
|
function SRS:onPieceMove(piece, grid)
|
||||||
@@ -194,8 +194,8 @@ end
|
|||||||
|
|
||||||
function SRS:onPieceRotate(piece, grid)
|
function SRS:onPieceRotate(piece, grid)
|
||||||
piece.lock_delay = 0 -- rotate reset
|
piece.lock_delay = 0 -- rotate reset
|
||||||
self:check_new_low(piece)
|
self:check_new_low(piece)
|
||||||
piece.manipulations = piece.manipulations + 1
|
piece.manipulations = piece.manipulations + 1
|
||||||
if piece:isDropBlocked(grid) then
|
if piece:isDropBlocked(grid) then
|
||||||
if piece.manipulations >= 15 then
|
if piece.manipulations >= 15 then
|
||||||
piece.locked = true
|
piece.locked = true
|
||||||
|
|||||||
@@ -7,13 +7,13 @@ SRS.name = "Ti-World"
|
|||||||
SRS.hash = "Bad I-kicks"
|
SRS.hash = "Bad I-kicks"
|
||||||
SRS.world = true
|
SRS.world = true
|
||||||
SRS.colourscheme = {
|
SRS.colourscheme = {
|
||||||
I = "C",
|
I = "C",
|
||||||
L = "O",
|
L = "O",
|
||||||
J = "B",
|
J = "B",
|
||||||
S = "G",
|
S = "G",
|
||||||
Z = "R",
|
Z = "R",
|
||||||
O = "Y",
|
O = "Y",
|
||||||
T = "M",
|
T = "M",
|
||||||
}
|
}
|
||||||
SRS.softdrop_lock = false
|
SRS.softdrop_lock = false
|
||||||
SRS.harddrop_lock = true
|
SRS.harddrop_lock = true
|
||||||
@@ -185,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
|
|
||||||
Reference in New Issue
Block a user