mirror of
https://github.com/SashLilac/cambridge.git
synced 2025-05-13 20:21:25 -05:00
Compare commits
124 Commits
v0.3-beta3
...
v0.3-beta6
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9fbfbd5cda | ||
|
|
c5c4c4d95c | ||
|
|
53c51c2062 | ||
|
|
e4eb9972e6 | ||
|
|
7dbfe23059 | ||
|
|
61d5410f22 | ||
|
|
2cb0416548 | ||
| 83f3e297ce | |||
|
|
8fb01dc9a8 | ||
|
|
61de3c6dbf | ||
|
|
3c718c38e4 | ||
|
|
d18c3e298d | ||
|
|
33934bfb53 | ||
|
|
3e2d107687 | ||
|
|
312b95728d | ||
|
|
5013443302 | ||
|
|
a8ac8f5966 | ||
|
|
a5032386e6 | ||
|
|
264255290d | ||
|
|
a5839bede2 | ||
|
|
4ebf24316a | ||
|
|
f2acab4496 | ||
| 929069c1b6 | |||
|
|
3f2b38f7b3 | ||
|
|
56fb5aebea | ||
|
|
6c201596b0 | ||
|
|
50466c5902 | ||
| ae1231c47a | |||
|
|
366ac1d552 | ||
| 302353f716 | |||
|
|
7f550b629f | ||
|
|
6b2252e6d9 | ||
|
|
e1741440f2 | ||
|
|
c56f290921 | ||
|
|
86e975f929 | ||
|
|
9f8e9a9778 | ||
|
|
62f9475fa9 | ||
|
|
99d3732d00 | ||
|
|
f5121b62e5 | ||
|
|
cbdbfa6633 | ||
|
|
1b1abc9792 | ||
|
|
894e99e677 | ||
|
|
d4b619da89 | ||
|
|
3766149cb7 | ||
|
|
449ca16bc4 | ||
|
|
71d76e8a6b | ||
|
|
3bdc6e1b2d | ||
|
|
d9b6c85704 | ||
|
|
5ce0686e1a | ||
|
|
3cf496ba98 | ||
|
|
5ddc6ec561 | ||
|
|
b91ffc913b | ||
|
|
ab445ff699 | ||
|
|
7b7a255bf8 | ||
|
|
57721ed35d | ||
|
|
8383d3f445 | ||
|
|
116284f31c | ||
|
|
2189e3a7b8 | ||
|
|
b1d325b714 | ||
|
|
4ab5e3747a | ||
|
|
9761ead48f | ||
|
|
8dedc8a70e | ||
|
|
21769f21c8 | ||
|
|
5cf26b4500 | ||
|
|
4b4a968632 | ||
|
|
e0d98de50d | ||
|
|
4992ea733c | ||
|
|
30ca434027 | ||
|
|
502a50d004 | ||
|
|
36f5287a39 | ||
|
|
a9bbe4a08d | ||
|
|
ee431f5fd8 | ||
|
|
36f2672e06 | ||
|
|
6ecea7edb1 | ||
|
|
dc764b9177 | ||
|
|
5a1494cb5a | ||
|
|
684c4f5b78 | ||
|
|
b568c0fe69 | ||
|
|
2ea75cdfaf | ||
|
|
1f0b43f1b7 | ||
|
|
40bdc5ed99 | ||
|
|
33f2a96ae8 | ||
|
|
846013ce7a | ||
|
|
37c85adc75 | ||
|
|
e7bb44deb4 | ||
|
|
57518dc299 | ||
|
|
0453a3db97 | ||
|
|
b85de17e51 | ||
|
|
163b8f6cc5 | ||
|
|
7250bee619 | ||
|
|
83de216408 | ||
|
|
ba235c8a41 | ||
|
|
ca18d090c9 | ||
|
|
a3a27d2566 | ||
|
|
b15cd9802f | ||
|
|
4c4a818c5c | ||
|
|
716de2814b | ||
|
|
bf19f49323 | ||
|
|
1234e78354 | ||
|
|
9129503d54 | ||
|
|
eae58f11e9 | ||
|
|
3cf5daeb2e | ||
|
|
1dfe68ccff | ||
|
|
8a459b68ba | ||
|
|
cb2b693bcb | ||
|
|
ef6d156d38 | ||
|
|
83e498534c | ||
|
|
8f19c73e2a | ||
|
|
e36b855ff7 | ||
|
|
23b58951cb | ||
|
|
1d73916b7c | ||
|
|
3947e9f02f | ||
|
|
99b15803ee | ||
|
|
d350b25726 | ||
|
|
44e4d00172 | ||
|
|
31e2529265 | ||
|
|
ea7c75f0b3 | ||
|
|
714c6b5e99 | ||
|
|
6a5d5a9c88 | ||
|
|
03491ba151 | ||
|
|
6e22e3d15b | ||
|
|
66ab5992ad | ||
|
|
2c07c2a58c | ||
|
|
a4d3f3bffc |
65
README.md
65
README.md
@@ -5,33 +5,11 @@ Cambridge
|
|||||||
|
|
||||||
Welcome to Cambridge, the next open-source falling-block game engine!
|
Welcome to Cambridge, the next open-source falling-block game engine!
|
||||||
|
|
||||||
The project is written and maintained exclusively by [SashLilac](https://github.com/SashLilac), [joezeng](https://github.com/joezeng) and [Oshisaure](https://github.com/oshisaure)!
|
The project is written and maintained exclusively by [Milla](https://github.com/MillaBasset), [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
|
The Discord server has been reopened! https://discord.gg/AADZUmgsph
|
||||||
|
|
||||||
Credits
|
The game also has a website now with more detail than seen on this README: https://t-sp.in/cambridge
|
||||||
-------
|
|
||||||
|
|
||||||
- [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 Absolute Plus](https://discord.gg/6Gf2awJ) for being another source of motivation!
|
|
||||||
|
|
||||||
The following people in no particular order also helped with the project:
|
|
||||||
- [Hailey](https://github.com/haileylgbt)
|
|
||||||
- CylinderKnot
|
|
||||||
- MarkGamed7794
|
|
||||||
- [Mizu](https://github.com/rexxt)
|
|
||||||
- MattMayuga
|
|
||||||
- Kitaru
|
|
||||||
- switchpalacecorner
|
|
||||||
- [sinefuse](https://github.com/sinefuse)
|
|
||||||
- [2Tie](https://github.com/2Tie)
|
|
||||||
- [nightmareci](https://github.com/nightmareci)
|
|
||||||
- [MyPasswordIsWeak](https://github.com/MyPasswordIsWeak)
|
|
||||||
- [Dr Ocelot](https://github.com/Dr-Ocelot)
|
|
||||||
|
|
||||||

|
|
||||||
|
|
||||||
Playing the game
|
Playing the game
|
||||||
----------------
|
----------------
|
||||||
@@ -42,13 +20,13 @@ You do not need LÖVE on Windows, as it comes bundled with the program.
|
|||||||
|
|
||||||
#### Stable release
|
#### Stable release
|
||||||
|
|
||||||
To get the stable release, simply download either `cambridge-win32.zip` (32-bit) or `cambridge-windows.zip` (64-bit) in the [latest release](https://github.com/sashlilac/cambridge/releases/latest).
|
To get the stable release, simply download either `cambridge-win32.zip` (32-bit) or `cambridge-windows.zip` (64-bit) in the [latest release](https://github.com/MillaBasset/cambridge/releases/latest).
|
||||||
|
|
||||||
All assets needed are bundled with the executable.
|
All assets needed are bundled with the executable.
|
||||||
|
|
||||||
#### Bleeding edge
|
#### Bleeding edge
|
||||||
|
|
||||||
If you want the bleeding edge version, download [this](https://github.com/SashLilac/cambridge/archive/master.zip).
|
If you want the bleeding edge version, download [this](https://github.com/MillaBasset/cambridge/archive/master.zip).
|
||||||
|
|
||||||
Extract the ZIP, open a Command Prompt at the folder you extracted Cambridge to, then run this command:
|
Extract the ZIP, open a Command Prompt at the folder you extracted Cambridge to, then run this command:
|
||||||
|
|
||||||
@@ -76,7 +54,7 @@ You can download the .love file in the latest release, and run it with:
|
|||||||
|
|
||||||
Clone the repository in git:
|
Clone the repository in git:
|
||||||
|
|
||||||
git clone https://github.com/SashLilac/cambridge
|
git clone https://github.com/MillaBasset/cambridge
|
||||||
|
|
||||||
Alternatively, download the source code ZIP in the latest release.
|
Alternatively, download the source code ZIP in the latest release.
|
||||||
|
|
||||||
@@ -88,7 +66,7 @@ It should run automatically!
|
|||||||
|
|
||||||
## Installing modpacks
|
## Installing modpacks
|
||||||
|
|
||||||
For instructions on how to install modpacks, go to [this](https://github.com/SashLilac/cambridge-modpack) mod pack to get a taste of the mod potential.
|
For instructions on how to install modpacks, go to [this](https://github.com/MillaBasset/cambridge-modpack) mod pack to get a taste of the mod potential.
|
||||||
|
|
||||||
License
|
License
|
||||||
-------
|
-------
|
||||||
@@ -100,3 +78,32 @@ community, as well as borrowed from other places, either with licensing
|
|||||||
or as placeholders until suitable material can be found that is properly
|
or as placeholders until suitable material can be found that is properly
|
||||||
licensed. Their original sources, and copyright notices if applicable, are
|
licensed. Their original sources, and copyright notices if applicable, are
|
||||||
listed in the file SOURCES.
|
listed in the file SOURCES.
|
||||||
|
|
||||||
|
Credits
|
||||||
|
-------
|
||||||
|
|
||||||
|
- [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 Absolute Plus](https://discord.gg/6Gf2awJ) for being another source of motivation!
|
||||||
|
|
||||||
|
More special thanks can be found in-game, under the "Credits" menu.
|
||||||
|
|
||||||
|
Other Notable Games
|
||||||
|
-------------------
|
||||||
|
|
||||||
|
- [TGMsim](https://github.com/2Tie/TGMsim) by 2Tie
|
||||||
|
- [Multimino](https://gamejolt.com/games/multimino/556683) by Axel Fox
|
||||||
|
- [Tetra Legends](https://tetralegends.app) by Dr Ocelot
|
||||||
|
- [ZTrix](https://discord.gg/MGhqCBDGNH) by Electra
|
||||||
|
- [Shiromino](https://github.com/shiromino/shiromino) by Felicity/nightmareci/kdex
|
||||||
|
- [Cursed Blocks](https://github.com/Manabender/Cursed-Blocks) by Manabender
|
||||||
|
- Picoris 1/2 by MarkGamed
|
||||||
|
- [Tetra Online](https://github.com/Juan-Cartes/Tetra-Offline) by Mine
|
||||||
|
- [Techmino](https://discord.gg/6Yuww44tq8) by MrZ
|
||||||
|
- [TETR.IO](https://tetr.io) by osk
|
||||||
|
- [Master of Blocks](https://discord.gg/72FZ49mjWh) by Phoenix Flare
|
||||||
|
- [Spirit Drop](https://rayblastgames.com/spiritdrop.php) by RayRay26
|
||||||
|
- [stackfuse](https://github.com/sinefuse/stackfuse) by sinefuse
|
||||||
|
|
||||||
|

|
||||||
|
|||||||
1
conf.lua
1
conf.lua
@@ -6,5 +6,6 @@ function love.conf(t)
|
|||||||
t.window.title = "Cambridge"
|
t.window.title = "Cambridge"
|
||||||
t.window.width = 640
|
t.window.width = 640
|
||||||
t.window.height = 480
|
t.window.height = 480
|
||||||
|
t.window.icon = "res/img/cambridge_icon.png"
|
||||||
t.window.vsync = false
|
t.window.vsync = false
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -87,6 +87,9 @@ function table.contains(table, element)
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|
||||||
function clamp(a, b, c)
|
function clamp(x, min, max)
|
||||||
return math.min(a, math.max(b, c))
|
if max < min then
|
||||||
end
|
min, max = max, min
|
||||||
|
end
|
||||||
|
return x < min and min or (x > max and max or x)
|
||||||
|
end
|
||||||
|
|||||||
@@ -2,12 +2,48 @@
|
|||||||
-- If this variable is true, then strict type checking is performed for all
|
-- If this variable is true, then strict type checking is performed for all
|
||||||
-- operations. This may result in slower code, but it will allow you to catch
|
-- operations. This may result in slower code, but it will allow you to catch
|
||||||
-- errors and bugs earlier.
|
-- errors and bugs earlier.
|
||||||
local strict = true
|
local strict = false
|
||||||
|
|
||||||
--------------------------------------------------------------------------------
|
--------------------------------------------------------------------------------
|
||||||
|
|
||||||
local bigint = {}
|
local bigint = {}
|
||||||
|
|
||||||
|
local mt = {
|
||||||
|
__add = function(lhs, rhs)
|
||||||
|
return bigint.add(lhs, rhs)
|
||||||
|
end,
|
||||||
|
__unm = function(arg)
|
||||||
|
return bigint.negate(arg)
|
||||||
|
end,
|
||||||
|
__sub = function(lhs, rhs)
|
||||||
|
return bigint.subtract(lhs, rhs)
|
||||||
|
end,
|
||||||
|
__mul = function(lhs, rhs)
|
||||||
|
return bigint.multiply(lhs, rhs)
|
||||||
|
end,
|
||||||
|
__div = function(lhs, rhs)
|
||||||
|
return bigint.divide(lhs, rhs)
|
||||||
|
end,
|
||||||
|
__mod = function(lhs, rhs)
|
||||||
|
return bigint.modulus(lhs, rhs)
|
||||||
|
end,
|
||||||
|
__pow = function(lhs, rhs)
|
||||||
|
return bigint.exponentiate(lhs, rhs)
|
||||||
|
end,
|
||||||
|
__tostring = function(arg)
|
||||||
|
return bigint.unserialize(arg, "s")
|
||||||
|
end,
|
||||||
|
__eq = function(lhs, rhs)
|
||||||
|
return bigint.compare(lhs, rhs, "==")
|
||||||
|
end,
|
||||||
|
__lt = function(lhs, rhs)
|
||||||
|
return bigint.compare(lhs, rhs, "<")
|
||||||
|
end,
|
||||||
|
__le = function(lhs, rhs)
|
||||||
|
return bigint.compare(lhs, rhs, "<=")
|
||||||
|
end
|
||||||
|
}
|
||||||
|
|
||||||
local named_powers = require("libs.bigint.named-powers-of-ten")
|
local named_powers = require("libs.bigint.named-powers-of-ten")
|
||||||
|
|
||||||
-- Create a new bigint or convert a number or string into a big
|
-- Create a new bigint or convert a number or string into a big
|
||||||
@@ -28,37 +64,7 @@ function bigint.new(num)
|
|||||||
return newint
|
return newint
|
||||||
end
|
end
|
||||||
|
|
||||||
setmetatable(self, {
|
setmetatable(self, mt)
|
||||||
__add = function(lhs, rhs)
|
|
||||||
return bigint.add(lhs, rhs)
|
|
||||||
end,
|
|
||||||
__unm = function()
|
|
||||||
if (self.sign == "+") then
|
|
||||||
self.sign = "-"
|
|
||||||
else
|
|
||||||
self.sign = "+"
|
|
||||||
end
|
|
||||||
return self
|
|
||||||
end,
|
|
||||||
__sub = function(lhs, rhs)
|
|
||||||
return bigint.subtract(lhs, rhs)
|
|
||||||
end,
|
|
||||||
__mul = function(lhs, rhs)
|
|
||||||
return bigint.multiply(lhs, rhs)
|
|
||||||
end,
|
|
||||||
__div = function(lhs, rhs)
|
|
||||||
return bigint.divide(lhs, rhs)
|
|
||||||
end,
|
|
||||||
__mod = function(lhs, rhs)
|
|
||||||
return bigint.modulus(lhs, rhs)
|
|
||||||
end,
|
|
||||||
__pow = function(lhs, rhs)
|
|
||||||
return bigint.exponentiate(lhs, rhs)
|
|
||||||
end,
|
|
||||||
__tostring = function()
|
|
||||||
return bigint.unserialize(self, "s")
|
|
||||||
end
|
|
||||||
})
|
|
||||||
|
|
||||||
if (num) then
|
if (num) then
|
||||||
local num_string = tostring(num)
|
local num_string = tostring(num)
|
||||||
@@ -78,10 +84,11 @@ end
|
|||||||
-- forced by supplying "true" as the second argument.
|
-- forced by supplying "true" as the second argument.
|
||||||
function bigint.check(big, force)
|
function bigint.check(big, force)
|
||||||
if (strict or force) then
|
if (strict or force) then
|
||||||
|
assert(getmetatable(big) == mt, "at least one arg is not a bigint")
|
||||||
assert(#big.digits > 0, "bigint is empty")
|
assert(#big.digits > 0, "bigint is empty")
|
||||||
assert(type(big.sign) == "string", "bigint is unsigned")
|
assert(big.sign == "+" or big.sign == "-", "bigint is unsigned")
|
||||||
for _, digit in pairs(big.digits) do
|
for _, digit in pairs(big.digits) do
|
||||||
assert(type(digit) == "number", digit .. " is not a number")
|
assert(type(digit) == "number", "at least one digit is invalid")
|
||||||
assert(digit <= 9 and digit >= 0, digit .. " is not between 0 and 9")
|
assert(digit <= 9 and digit >= 0, digit .. " is not between 0 and 9")
|
||||||
assert(math.floor(digit) == digit, digit .. " is not an integer")
|
assert(math.floor(digit) == digit, digit .. " is not an integer")
|
||||||
end
|
end
|
||||||
@@ -98,6 +105,18 @@ function bigint.abs(big)
|
|||||||
return result
|
return result
|
||||||
end
|
end
|
||||||
|
|
||||||
|
-- Return a new big with the same digits but the opposite sign (negation)
|
||||||
|
function bigint.negate(big)
|
||||||
|
bigint.check(big)
|
||||||
|
local result = big:clone()
|
||||||
|
if (result.sign == "+") then
|
||||||
|
result.sign = "-"
|
||||||
|
else
|
||||||
|
result.sign = "+"
|
||||||
|
end
|
||||||
|
return result
|
||||||
|
end
|
||||||
|
|
||||||
-- Return the number of digits in the big
|
-- Return the number of digits in the big
|
||||||
function bigint.digits(big)
|
function bigint.digits(big)
|
||||||
bigint.check(big)
|
bigint.check(big)
|
||||||
|
|||||||
25
load/bgm.lua
25
load/bgm.lua
@@ -9,31 +9,38 @@ local current_bgm = nil
|
|||||||
local bgm_locked = false
|
local bgm_locked = false
|
||||||
|
|
||||||
function switchBGM(sound, subsound)
|
function switchBGM(sound, subsound)
|
||||||
if bgm_locked then return end
|
|
||||||
if current_bgm ~= nil then
|
if current_bgm ~= nil then
|
||||||
current_bgm:stop()
|
current_bgm:stop()
|
||||||
end
|
end
|
||||||
if subsound ~= nil then
|
if bgm_locked or config.bgm_volume <= 0 then
|
||||||
current_bgm = bgm[sound][subsound]
|
current_bgm = nil
|
||||||
resetBGMFadeout()
|
|
||||||
elseif sound ~= nil then
|
elseif sound ~= nil then
|
||||||
current_bgm = bgm[sound]
|
if subsound ~= nil then
|
||||||
resetBGMFadeout()
|
current_bgm = bgm[sound][subsound]
|
||||||
|
else
|
||||||
|
current_bgm = bgm[sound]
|
||||||
|
end
|
||||||
else
|
else
|
||||||
current_bgm = nil
|
current_bgm = nil
|
||||||
end
|
end
|
||||||
|
if current_bgm ~= nil then
|
||||||
|
resetBGMFadeout()
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function switchBGMLoop(sound, subsound)
|
function switchBGMLoop(sound, subsound)
|
||||||
if bgm_locked then return end
|
|
||||||
switchBGM(sound, subsound)
|
switchBGM(sound, subsound)
|
||||||
current_bgm:setLooping(true)
|
if current_bgm then current_bgm:setLooping(true) end
|
||||||
end
|
end
|
||||||
|
|
||||||
function lockBGM()
|
function lockBGM()
|
||||||
bgm_locked = true
|
bgm_locked = true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function unlockBGM()
|
||||||
|
bgm_locked = false
|
||||||
|
end
|
||||||
|
|
||||||
local fading_bgm = false
|
local fading_bgm = false
|
||||||
local fadeout_time = 0
|
local fadeout_time = 0
|
||||||
local total_fadeout_time = 0
|
local total_fadeout_time = 0
|
||||||
@@ -53,7 +60,7 @@ function resetBGMFadeout(time)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function processBGMFadeout(dt)
|
function processBGMFadeout(dt)
|
||||||
if fading_bgm then
|
if current_bgm and fading_bgm then
|
||||||
fadeout_time = fadeout_time - dt
|
fadeout_time = fadeout_time - dt
|
||||||
if fadeout_time < 0 then
|
if fadeout_time < 0 then
|
||||||
fadeout_time = 0
|
fadeout_time = 0
|
||||||
|
|||||||
@@ -1,8 +1,19 @@
|
|||||||
local binser = require 'libs.binser'
|
local binser = require 'libs.binser'
|
||||||
|
|
||||||
function loadSave()
|
function loadSave()
|
||||||
config = loadFromFile('config.sav')
|
local info = love.filesystem.getInfo(
|
||||||
highscores = loadFromFile('highscores.sav')
|
love.filesystem.getSaveDirectory(), "directory"
|
||||||
|
)
|
||||||
|
if not info then
|
||||||
|
love.filesystem.remove(love.filesystem.getSaveDirectory())
|
||||||
|
love.filesystem.createDirectory(love.filesystem.getSaveDirectory())
|
||||||
|
end
|
||||||
|
config = loadFromFile(
|
||||||
|
love.filesystem.getSaveDirectory() .. '/config.sav'
|
||||||
|
)
|
||||||
|
highscores = loadFromFile(
|
||||||
|
love.filesystem.getSaveDirectory() .. '/highscores.sav'
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
function loadFromFile(filename)
|
function loadFromFile(filename)
|
||||||
@@ -13,12 +24,40 @@ function loadFromFile(filename)
|
|||||||
return save_data[1]
|
return save_data[1]
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function initConfig()
|
||||||
|
if not config.das then config.das = 10 end
|
||||||
|
if not config.arr then config.arr = 2 end
|
||||||
|
if not config.dcd then config.dcd = 0 end
|
||||||
|
if not config.sfx_volume then config.sfx_volume = 0.5 end
|
||||||
|
if not config.bgm_volume then config.bgm_volume = 0.5 end
|
||||||
|
|
||||||
|
if config.fullscreen == nil then config.fullscreen = false end
|
||||||
|
if config.secret == nil then config.secret = false end
|
||||||
|
|
||||||
|
if not config.gamesettings then config.gamesettings = {} 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
|
||||||
|
scene = InputConfigScene()
|
||||||
|
else
|
||||||
|
if config.current_mode then current_mode = config.current_mode end
|
||||||
|
if config.current_ruleset then current_ruleset = config.current_ruleset end
|
||||||
|
scene = TitleScene()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function saveConfig()
|
function saveConfig()
|
||||||
binser.writeFile('config.sav', config)
|
binser.writeFile(
|
||||||
|
love.filesystem.getSaveDirectory() .. '/config.sav', config
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
function saveHighscores()
|
function saveHighscores()
|
||||||
binser.writeFile('highscores.sav', highscores)
|
binser.writeFile(
|
||||||
|
love.filesystem.getSaveDirectory() .. '/highscores.sav', highscores
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -27,33 +27,37 @@ sounds = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
function playSE(sound, subsound)
|
function playSE(sound, subsound)
|
||||||
if subsound == nil then
|
if sound ~= nil then
|
||||||
sounds[sound]:setVolume(config.sfx_volume)
|
if subsound ~= nil then
|
||||||
if sounds[sound]:isPlaying() then
|
sounds[sound][subsound]:setVolume(config.sfx_volume)
|
||||||
sounds[sound]:stop()
|
if sounds[sound][subsound]:isPlaying() then
|
||||||
|
sounds[sound][subsound]:stop()
|
||||||
|
end
|
||||||
|
sounds[sound][subsound]:play()
|
||||||
|
else
|
||||||
|
sounds[sound]:setVolume(config.sfx_volume)
|
||||||
|
if sounds[sound]:isPlaying() then
|
||||||
|
sounds[sound]:stop()
|
||||||
|
end
|
||||||
|
sounds[sound]:play()
|
||||||
end
|
end
|
||||||
sounds[sound]:play()
|
|
||||||
else
|
|
||||||
sounds[sound][subsound]:setVolume(config.sfx_volume)
|
|
||||||
if sounds[sound][subsound]:isPlaying() then
|
|
||||||
sounds[sound][subsound]:stop()
|
|
||||||
end
|
|
||||||
sounds[sound][subsound]:play()
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function playSEOnce(sound, subsound)
|
function playSEOnce(sound, subsound)
|
||||||
if subsound == nil then
|
if sound ~= nil then
|
||||||
sounds[sound]:setVolume(config.sfx_volume)
|
if subsound ~= nil then
|
||||||
if sounds[sound]:isPlaying() then
|
sounds[sound][subsound]:setVolume(config.sfx_volume)
|
||||||
return
|
if sounds[sound][subsound]:isPlaying() then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
sounds[sound][subsound]:play()
|
||||||
|
else
|
||||||
|
sounds[sound]:setVolume(config.sfx_volume)
|
||||||
|
if sounds[sound]:isPlaying() then
|
||||||
|
return
|
||||||
|
end
|
||||||
|
sounds[sound]:play()
|
||||||
end
|
end
|
||||||
sounds[sound]:play()
|
|
||||||
else
|
|
||||||
sounds[sound][subsound]:setVolume(config.sfx_volume)
|
|
||||||
if sounds[sound][subsound]:isPlaying() then
|
|
||||||
return
|
|
||||||
end
|
|
||||||
sounds[sound][subsound]:play()
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
1
load/version.lua
Normal file
1
load/version.lua
Normal file
@@ -0,0 +1 @@
|
|||||||
|
version = "v0.3-beta6"
|
||||||
229
main.lua
229
main.lua
@@ -8,47 +8,31 @@ function love.load()
|
|||||||
require "load.bgm"
|
require "load.bgm"
|
||||||
require "load.save"
|
require "load.save"
|
||||||
require "load.bigint"
|
require "load.bigint"
|
||||||
|
require "load.version"
|
||||||
loadSave()
|
loadSave()
|
||||||
require "scene"
|
require "scene"
|
||||||
|
|
||||||
--config["side_next"] = false
|
--config["side_next"] = false
|
||||||
--config["reverse_rotate"] = true
|
--config["reverse_rotate"] = true
|
||||||
config["fullscreen"] = false
|
--config["das_last_key"] = false
|
||||||
|
--config["fullscreen"] = false
|
||||||
|
|
||||||
love.window.setMode(love.graphics.getWidth(), love.graphics.getHeight(), {resizable = true});
|
love.window.setMode(love.graphics.getWidth(), love.graphics.getHeight(), {resizable = true});
|
||||||
|
|
||||||
-- used for screenshots
|
-- used for screenshots
|
||||||
GLOBAL_CANVAS = love.graphics.newCanvas()
|
GLOBAL_CANVAS = love.graphics.newCanvas()
|
||||||
|
|
||||||
-- init config
|
-- init config
|
||||||
if not config.das then config.das = 10 end
|
initConfig()
|
||||||
if not config.arr then config.arr = 2 end
|
|
||||||
if not config.dcd then config.dcd = 0 end
|
|
||||||
if not config.sfx_volume then config.sfx_volume = 0.5 end
|
|
||||||
if not config.bgm_volume then config.bgm_volume = 0.5 end
|
|
||||||
|
|
||||||
if config.secret == nil then config.secret = false
|
|
||||||
elseif config.secret == true then playSE("welcome") end
|
|
||||||
|
|
||||||
if not config.gamesettings then
|
love.window.setFullscreen(config["fullscreen"])
|
||||||
config.gamesettings = {}
|
if config.secret then playSE("welcome") end
|
||||||
config["das_last_key"] = false
|
|
||||||
else
|
|
||||||
config["das_last_key"] = config.gamesettings.das_last_key == 2
|
|
||||||
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
|
|
||||||
scene = InputConfigScene()
|
|
||||||
else
|
|
||||||
if config.current_mode then current_mode = config.current_mode end
|
|
||||||
if config.current_ruleset then current_ruleset = config.current_ruleset end
|
|
||||||
scene = TitleScene()
|
|
||||||
end
|
|
||||||
|
|
||||||
|
-- import custom modules
|
||||||
|
initModules()
|
||||||
|
end
|
||||||
|
|
||||||
|
function initModules()
|
||||||
game_modes = {}
|
game_modes = {}
|
||||||
mode_list = love.filesystem.getDirectoryItems("tetris/modes")
|
mode_list = love.filesystem.getDirectoryItems("tetris/modes")
|
||||||
for i=1,#mode_list do
|
for i=1,#mode_list do
|
||||||
@@ -69,52 +53,13 @@ function love.load()
|
|||||||
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
|
|
||||||
|
|
||||||
local TARGET_FPS = 60
|
|
||||||
local SAMPLE_SIZE = 60
|
|
||||||
|
|
||||||
local rolling_samples = {}
|
|
||||||
local rolling_total = 0
|
|
||||||
local average_n = 0
|
|
||||||
local frame = 0
|
|
||||||
|
|
||||||
function getSmoothedDt(dt)
|
|
||||||
rolling_total = rolling_total + dt
|
|
||||||
frame = frame + 1
|
|
||||||
if frame > SAMPLE_SIZE then frame = frame - SAMPLE_SIZE end
|
|
||||||
if average_n == SAMPLE_SIZE then
|
|
||||||
rolling_total = rolling_total - rolling_samples[frame]
|
|
||||||
else
|
|
||||||
average_n = average_n + 1
|
|
||||||
end
|
|
||||||
rolling_samples[frame] = dt
|
|
||||||
return rolling_total / average_n
|
|
||||||
end
|
|
||||||
|
|
||||||
local update_time = 0.52
|
|
||||||
|
|
||||||
function love.update(dt)
|
|
||||||
processBGMFadeout(dt)
|
|
||||||
local old_update_time = update_time
|
|
||||||
update_time = update_time + getSmoothedDt(dt) * TARGET_FPS
|
|
||||||
updates = 0
|
|
||||||
while (update_time >= 1.02) do
|
|
||||||
scene:update()
|
|
||||||
updates = updates + 1
|
|
||||||
update_time = update_time - 1
|
|
||||||
end
|
|
||||||
if math.abs(update_time - old_update_time) < 0.02 then
|
|
||||||
update_time = old_update_time
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function love.draw()
|
function love.draw()
|
||||||
love.graphics.setCanvas(GLOBAL_CANVAS)
|
love.graphics.setCanvas(GLOBAL_CANVAS)
|
||||||
love.graphics.clear()
|
love.graphics.clear()
|
||||||
|
|
||||||
love.graphics.push()
|
love.graphics.push()
|
||||||
|
|
||||||
-- get offset matrix
|
-- get offset matrix
|
||||||
love.graphics.setDefaultFilter("linear", "nearest")
|
love.graphics.setDefaultFilter("linear", "nearest")
|
||||||
@@ -126,19 +71,20 @@ function love.draw()
|
|||||||
(height - scale_factor * 480) / 2
|
(height - scale_factor * 480) / 2
|
||||||
)
|
)
|
||||||
love.graphics.scale(scale_factor)
|
love.graphics.scale(scale_factor)
|
||||||
|
|
||||||
scene:render()
|
scene:render()
|
||||||
love.graphics.pop()
|
love.graphics.pop()
|
||||||
|
|
||||||
love.graphics.setCanvas()
|
love.graphics.setCanvas()
|
||||||
love.graphics.setColor(1,1,1,1)
|
love.graphics.setColor(1,1,1,1)
|
||||||
love.graphics.draw(GLOBAL_CANVAS)
|
love.graphics.draw(GLOBAL_CANVAS)
|
||||||
end
|
end
|
||||||
|
|
||||||
function love.keypressed(key, scancode)
|
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"]
|
||||||
|
saveConfig()
|
||||||
love.window.setFullscreen(config["fullscreen"])
|
love.window.setFullscreen(config["fullscreen"])
|
||||||
elseif scancode == "f2" and scene.title ~= "Input Config" and scene.title ~= "Game" then
|
elseif scancode == "f2" and scene.title ~= "Input Config" and scene.title ~= "Game" then
|
||||||
scene = InputConfigScene()
|
scene = InputConfigScene()
|
||||||
@@ -150,14 +96,16 @@ function love.keypressed(key, scancode)
|
|||||||
scene.restart_message = true
|
scene.restart_message = true
|
||||||
if config.secret then playSE("mode_decide")
|
if config.secret then playSE("mode_decide")
|
||||||
else playSE("erase") end
|
else playSE("erase") end
|
||||||
-- f12 is reserved for saving screenshots
|
-- f12 is reserved for saving screenshots
|
||||||
elseif scancode == "f12" then
|
elseif scancode == "f12" then
|
||||||
local ss_name = os.date("ss/%Y-%m-%d_%H-%M-%S.png")
|
local ss_name = os.date("ss/%Y-%m-%d_%H-%M-%S.png")
|
||||||
if not love.filesystem.getInfo("ss") then
|
local info = love.filesystem.getInfo("ss", "directory")
|
||||||
love.filesystem.createDirectory("ss")
|
if not info then
|
||||||
end
|
love.filesystem.remove("ss")
|
||||||
print("Saving screenshot as "..ss_name)
|
love.filesystem.createDirectory("ss")
|
||||||
GLOBAL_CANVAS:newImageData():encode("png", ss_name)
|
end
|
||||||
|
print("Saving screenshot as "..ss_name)
|
||||||
|
GLOBAL_CANVAS:newImageData():encode("png", ss_name)
|
||||||
-- function keys are reserved
|
-- function keys are reserved
|
||||||
elseif string.match(scancode, "^f[1-9]$") or string.match(scancode, "^f[1-9][0-9]+$") then
|
elseif string.match(scancode, "^f[1-9]$") or string.match(scancode, "^f[1-9][0-9]+$") then
|
||||||
return
|
return
|
||||||
@@ -228,13 +176,13 @@ function love.joystickaxis(joystick, axis, value)
|
|||||||
config.input.joysticks[joystick:getName()].axes and
|
config.input.joysticks[joystick:getName()].axes and
|
||||||
config.input.joysticks[joystick:getName()].axes[axis]
|
config.input.joysticks[joystick:getName()].axes[axis]
|
||||||
then
|
then
|
||||||
if math.abs(value) >= 0.5 then
|
if math.abs(value) >= 1 then
|
||||||
input_pressed = config.input.joysticks[joystick:getName()].axes[axis][value >= 0.5 and "positive" or "negative"]
|
input_pressed = config.input.joysticks[joystick:getName()].axes[axis][value >= 1 and "positive" or "negative"]
|
||||||
end
|
end
|
||||||
positive_released = config.input.joysticks[joystick:getName()].axes[axis].positive
|
positive_released = config.input.joysticks[joystick:getName()].axes[axis].positive
|
||||||
negative_released = config.input.joysticks[joystick:getName()].axes[axis].negative
|
negative_released = config.input.joysticks[joystick:getName()].axes[axis].negative
|
||||||
end
|
end
|
||||||
if math.abs(value) >= 0.5 then
|
if math.abs(value) >= 1 then
|
||||||
scene:onInputPress({input=input_pressed, type="joyaxis", name=joystick:getName(), axis=axis, value=value})
|
scene:onInputPress({input=input_pressed, type="joyaxis", name=joystick:getName(), axis=axis, value=value})
|
||||||
else
|
else
|
||||||
scene:onInputRelease({input=positive_released, type="joyaxis", name=joystick:getName(), axis=axis, value=value})
|
scene:onInputRelease({input=positive_released, type="joyaxis", name=joystick:getName(), axis=axis, value=value})
|
||||||
@@ -242,6 +190,14 @@ function love.joystickaxis(joystick, axis, value)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local last_hat_direction = ""
|
||||||
|
local directions = {
|
||||||
|
["u"] = "up",
|
||||||
|
["d"] = "down",
|
||||||
|
["l"] = "left",
|
||||||
|
["r"] = "right",
|
||||||
|
}
|
||||||
|
|
||||||
function love.joystickhat(joystick, hat, direction)
|
function love.joystickhat(joystick, hat, direction)
|
||||||
local input_pressed = nil
|
local input_pressed = nil
|
||||||
local has_hat = false
|
local has_hat = false
|
||||||
@@ -258,17 +214,47 @@ function love.joystickhat(joystick, hat, direction)
|
|||||||
has_hat = true
|
has_hat = true
|
||||||
end
|
end
|
||||||
if input_pressed then
|
if input_pressed then
|
||||||
scene:onInputPress({input=input_pressed, type="joyhat", name=joystick:getName(), hat=hat, direction=direction})
|
for i = 1, #direction do
|
||||||
|
local char = direction:sub(i, i)
|
||||||
|
local _, count = last_hat_direction:gsub(char, char)
|
||||||
|
if count == 0 then
|
||||||
|
scene:onInputPress({input=config.input.joysticks[joystick:getName()].hats[hat][char], type="joyhat", name=joystick:getName(), hat=hat, direction=char})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for i = 1, #last_hat_direction do
|
||||||
|
local char = last_hat_direction:sub(i, i)
|
||||||
|
local _, count = direction:gsub(char, char)
|
||||||
|
if count == 0 then
|
||||||
|
scene:onInputRelease({input=config.input.joysticks[joystick:getName()].hats[hat][char], type="joyhat", name=joystick:getName(), hat=hat, direction=char})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
last_hat_direction = direction
|
||||||
elseif has_hat then
|
elseif has_hat then
|
||||||
for i, direction in ipairs{"d", "l", "ld", "lu", "r", "rd", "ru", "u"} do
|
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})
|
scene:onInputRelease({input=config.input.joysticks[joystick:getName()].hats[hat][direction], type="joyhat", name=joystick:getName(), hat=hat, direction=direction})
|
||||||
end
|
end
|
||||||
|
last_hat_direction = ""
|
||||||
elseif direction ~= "c" then
|
elseif direction ~= "c" then
|
||||||
scene:onInputPress({input=nil, type="joyhat", name=joystick:getName(), hat=hat, direction=direction})
|
for i = 1, #direction do
|
||||||
|
local char = direction:sub(i, i)
|
||||||
|
local _, count = last_hat_direction:gsub(char, char)
|
||||||
|
if count == 0 then
|
||||||
|
scene:onInputPress({input=directions[char], type="joyhat", name=joystick:getName(), hat=hat, direction=char})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
for i = 1, #last_hat_direction do
|
||||||
|
local char = last_hat_direction:sub(i, i)
|
||||||
|
local _, count = direction:gsub(char, char)
|
||||||
|
if count == 0 then
|
||||||
|
scene:onInputRelease({input=directions[char], type="joyhat", name=joystick:getName(), hat=hat, direction=char})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
last_hat_direction = direction
|
||||||
else
|
else
|
||||||
for i, direction in ipairs{"d", "l", "ld", "lu", "r", "rd", "ru", "u"} do
|
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})
|
scene:onInputRelease({input=nil, type="joyhat", name=joystick:getName(), hat=hat, direction=direction})
|
||||||
end
|
end
|
||||||
|
last_hat_direction = ""
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -281,6 +267,59 @@ function love.focus(f)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function love.resize(w, h)
|
function love.resize(w, h)
|
||||||
GLOBAL_CANVAS:release()
|
GLOBAL_CANVAS:release()
|
||||||
GLOBAL_CANVAS = love.graphics.newCanvas(w, h)
|
GLOBAL_CANVAS = love.graphics.newCanvas(w, h)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local TARGET_FPS = 60
|
||||||
|
|
||||||
|
function love.run()
|
||||||
|
if love.load then love.load(love.arg.parseGameArguments(arg), arg) end
|
||||||
|
|
||||||
|
if love.timer then love.timer.step() end
|
||||||
|
|
||||||
|
local dt = 0
|
||||||
|
|
||||||
|
local last_time = love.timer.getTime()
|
||||||
|
local time_accumulator = 0
|
||||||
|
return function()
|
||||||
|
if love.event then
|
||||||
|
love.event.pump()
|
||||||
|
for name, a,b,c,d,e,f in love.event.poll() do
|
||||||
|
if name == "quit" then
|
||||||
|
if not love.quit or not love.quit() then
|
||||||
|
return a or 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
love.handlers[name](a,b,c,d,e,f)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if love.timer then
|
||||||
|
processBGMFadeout(love.timer.step())
|
||||||
|
end
|
||||||
|
|
||||||
|
if scene and scene.update and love.timer then
|
||||||
|
scene:update()
|
||||||
|
|
||||||
|
local frame_duration = 1.0 / TARGET_FPS
|
||||||
|
if time_accumulator < frame_duration then
|
||||||
|
if love.graphics and love.graphics.isActive() and love.draw then
|
||||||
|
love.graphics.origin()
|
||||||
|
love.graphics.clear(love.graphics.getBackgroundColor())
|
||||||
|
love.draw()
|
||||||
|
love.graphics.present()
|
||||||
|
end
|
||||||
|
local end_time = last_time + frame_duration
|
||||||
|
local time = love.timer.getTime()
|
||||||
|
while time < end_time do
|
||||||
|
love.timer.sleep(0.001)
|
||||||
|
time = love.timer.getTime()
|
||||||
|
end
|
||||||
|
time_accumulator = time_accumulator + time - last_time
|
||||||
|
end
|
||||||
|
time_accumulator = time_accumulator - frame_duration
|
||||||
|
end
|
||||||
|
last_time = love.timer.getTime()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|||||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 229 B After Width: | Height: | Size: 153 B |
BIN
res/img/cambridge_icon.png
Normal file
BIN
res/img/cambridge_icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
@@ -11,6 +11,8 @@ function Scene:onInputRelease() end
|
|||||||
ExitScene = require "scene.exit"
|
ExitScene = require "scene.exit"
|
||||||
GameScene = require "scene.game"
|
GameScene = require "scene.game"
|
||||||
ModeSelectScene = require "scene.mode_select"
|
ModeSelectScene = require "scene.mode_select"
|
||||||
|
KeyConfigScene = require "scene.key_config"
|
||||||
|
StickConfigScene = require "scene.stick_config"
|
||||||
InputConfigScene = require "scene.input_config"
|
InputConfigScene = require "scene.input_config"
|
||||||
GameConfigScene = require "scene.game_config"
|
GameConfigScene = require "scene.game_config"
|
||||||
TuningScene = require "scene.tuning"
|
TuningScene = require "scene.tuning"
|
||||||
|
|||||||
@@ -4,6 +4,8 @@ CreditsScene.title = "Credits"
|
|||||||
|
|
||||||
function CreditsScene:new()
|
function CreditsScene:new()
|
||||||
self.frames = 0
|
self.frames = 0
|
||||||
|
-- higher = slower
|
||||||
|
self.scroll_speed = 1.9
|
||||||
switchBGM("credit_roll", "gm3")
|
switchBGM("credit_roll", "gm3")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -11,16 +13,18 @@ function CreditsScene:update()
|
|||||||
if love.window.hasFocus() then
|
if love.window.hasFocus() then
|
||||||
self.frames = self.frames + 1
|
self.frames = self.frames + 1
|
||||||
end
|
end
|
||||||
if self.frames >= 4200 then
|
if self.frames >= 2100 * self.scroll_speed then
|
||||||
playSE("mode_decide")
|
playSE("mode_decide")
|
||||||
scene = TitleScene()
|
scene = TitleScene()
|
||||||
switchBGM(nil)
|
switchBGM(nil)
|
||||||
elseif self.frames == 3600 then
|
elseif self.frames == math.floor(1950 * self.scroll_speed) then
|
||||||
fadeoutBGM(2)
|
fadeoutBGM(2)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function CreditsScene:render()
|
function CreditsScene:render()
|
||||||
|
local offset = self.frames / self.scroll_speed
|
||||||
|
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
love.graphics.draw(
|
love.graphics.draw(
|
||||||
backgrounds[19],
|
backgrounds[19],
|
||||||
@@ -29,27 +33,43 @@ function CreditsScene:render()
|
|||||||
)
|
)
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_4)
|
love.graphics.setFont(font_3x5_4)
|
||||||
love.graphics.print("Cambridge Credits", 320, 500 - self.frames / 2)
|
love.graphics.print("Cambridge Credits", 320, 500 - offset)
|
||||||
love.graphics.print("THANK YOU\nFOR PLAYING!", 320, math.max(1500 - self.frames / 2, 240))
|
love.graphics.print("THANK YOU\nFOR PLAYING!", 320, math.max(2010 - offset, 240))
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
love.graphics.setFont(font_3x5_3)
|
||||||
love.graphics.print("Game Developers", 320, 550 - self.frames / 2)
|
love.graphics.print("Game Developers", 320, 550 - offset)
|
||||||
love.graphics.print("Project Heads", 320, 640 - self.frames / 2)
|
love.graphics.print("Project Heads", 320, 640 - offset)
|
||||||
love.graphics.print("Other Game Developers", 320, 730 - self.frames / 2)
|
love.graphics.print("Notable Game Developers", 320, 730 - offset)
|
||||||
love.graphics.print("Special Thanks", 320, 900 - self.frames / 2)
|
love.graphics.print("Special Thanks", 320, 980 - offset)
|
||||||
love.graphics.print("- SashLilac / SpinTriple", 320, math.max(2000 - self.frames / 2, 320))
|
love.graphics.print("- Milla", 320, math.max(2090 - offset, 320))
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_2)
|
love.graphics.setFont(font_3x5_2)
|
||||||
love.graphics.print("Oshisaure\nJoe Zeng", 320, 590 - self.frames / 2)
|
love.graphics.print("Oshisaure\nJoe Zeng", 320, 590 - offset)
|
||||||
love.graphics.print("Mizu\nHailey", 320, 680 - self.frames / 2)
|
love.graphics.print("Mizu\nMarkGamed", 320, 680 - offset)
|
||||||
love.graphics.print("Axel Fox - Multimino\nMine - Tetra Online\nDr Ocelot - Tetra Legends\nFelicity / nightmareci - Shiromino\n2Tie - TGMsim\nPhoenix Flare - Master of Blocks", 320, 770 - self.frames / 2)
|
|
||||||
love.graphics.print(
|
love.graphics.print(
|
||||||
"RocketLanterns\nCylinderKnot\nHammrTime\nKirby703\nMattMayuga\nMyPasswordIsWeak\n" ..
|
"2Tie - TGMsim\nAxel Fox - Multimino\nDr Ocelot - Tetra Legends\n" ..
|
||||||
"Nikki Karissa\noffwo\nsinefuse\nTetro48\nTimmSkiller\nuser74003\nAgentBasey\n" ..
|
"Electra - ZTrix\nFelicity/nightmareci/kdex - Shiromino\n" ..
|
||||||
"CheeZed_Fish\neightsixfivezero\nEricICX\ngizmo4487\nM1ssing0\nMarkGamed7794\n" ..
|
"Mine - Tetra Online\nMrZ - Techmino\nosk - TETR.IO\n" ..
|
||||||
"pokemonfan1937\nSimon\nstratus\nZaptorZap\nThe Absolute PLUS Discord\nTetra Legends Discord\n" ..
|
"Phoenix Flare - Master of Blocks\nRayRay26 - Spirit Drop\n" ..
|
||||||
"Tetra Online Discord\nMultimino Discord\nCambridge Discord\nAnd to you, the player!",
|
"sinefuse - stackfuse",
|
||||||
320, 940 - self.frames / 2
|
320, 770 - offset
|
||||||
|
)
|
||||||
|
love.graphics.print(
|
||||||
|
"321MrHaatz\nAdventium\nAgentBasey\nArchina\nAurora\n" ..
|
||||||
|
"Caithness\nCheez\ncolour_thief\nCommando\nCublex\n" ..
|
||||||
|
"CylinderKnot\neightsixfivezero\nEricICX\nGesomaru\n" ..
|
||||||
|
"gizmo4487\nJBroms\nKirby703\nKitaru\n" ..
|
||||||
|
"M1ssing0\nMattMayuga\nMyPasswordIsWeak\n" ..
|
||||||
|
"Nikki Karissa\noffwo\nOliver\nPineapple\npokemonfan1937\n" ..
|
||||||
|
"Pyra Neoxi\nRDST64\nRocketLanterns\nRustyFoxxo\n" ..
|
||||||
|
"saphie\nShelleloch\nSimon\nstratus\nSuper302\n" ..
|
||||||
|
"switchpalacecorner\nterpyderp\nTetrian22\nTetro48\nThatCookie\n" ..
|
||||||
|
"TimmSkiller\nTrixciel\nuser74003\nZaptorZap\nZircean\n" ..
|
||||||
|
"All other contributors and friends!\nThe Absolute PLUS Discord\n" ..
|
||||||
|
"Tetra Legends Discord\nTetra Online Discord\nMultimino Discord\n" ..
|
||||||
|
"Hard Drop Discord\nRusty's Systemspace\nCambridge Discord\n" ..
|
||||||
|
"And to you, the player!",
|
||||||
|
320, 1020 - offset
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -7,10 +7,10 @@ require 'load.save'
|
|||||||
function GameScene:new(game_mode, ruleset, inputs)
|
function GameScene:new(game_mode, ruleset, inputs)
|
||||||
self.retry_mode = game_mode
|
self.retry_mode = game_mode
|
||||||
self.retry_ruleset = ruleset
|
self.retry_ruleset = ruleset
|
||||||
self.secret_inputs = copy(inputs)
|
self.secret_inputs = inputs
|
||||||
self.game = game_mode(self.secret_inputs)
|
self.game = game_mode(self.secret_inputs)
|
||||||
self.ruleset = ruleset()
|
self.ruleset = ruleset(self.game)
|
||||||
self.game:initialize(self.ruleset, self.secret_inputs)
|
self.game:initialize(self.ruleset)
|
||||||
self.inputs = {
|
self.inputs = {
|
||||||
left=false,
|
left=false,
|
||||||
right=false,
|
right=false,
|
||||||
@@ -42,91 +42,32 @@ function GameScene:update()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function GameScene:render()
|
function GameScene:render()
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
self.game:draw(self.paused)
|
||||||
love.graphics.draw(
|
|
||||||
backgrounds[self.game:getBackground()],
|
|
||||||
0, 0, 0,
|
|
||||||
0.5, 0.5
|
|
||||||
)
|
|
||||||
|
|
||||||
-- game frame
|
|
||||||
if self.game.grid.width == 10 and self.game.grid.height == 24 then
|
|
||||||
love.graphics.draw(misc_graphics["frame"], 48, 64)
|
|
||||||
end
|
|
||||||
|
|
||||||
love.graphics.setColor(0, 0, 0, 200)
|
|
||||||
love.graphics.rectangle(
|
|
||||||
"fill", 64, 80,
|
|
||||||
16 * self.game.grid.width, 16 * (self.game.grid.height - 4)
|
|
||||||
)
|
|
||||||
|
|
||||||
if self.game.grid.width ~= 10 or self.game.grid.height ~= 24 then
|
|
||||||
love.graphics.setColor(174/255, 83/255, 76/255, 1)
|
|
||||||
love.graphics.setLineWidth(8)
|
|
||||||
love.graphics.line(
|
|
||||||
60,76,
|
|
||||||
68+16*self.game.grid.width,76,
|
|
||||||
68+16*self.game.grid.width,84+16*(self.game.grid.height-4),
|
|
||||||
60,84+16*(self.game.grid.height-4),
|
|
||||||
60,76
|
|
||||||
)
|
|
||||||
love.graphics.setColor(203/255, 137/255, 111/255, 1)
|
|
||||||
love.graphics.setLineWidth(4)
|
|
||||||
love.graphics.line(
|
|
||||||
60,76,
|
|
||||||
68+16*self.game.grid.width,76,
|
|
||||||
68+16*self.game.grid.width,84+16*(self.game.grid.height-4),
|
|
||||||
60,84+16*(self.game.grid.height-4),
|
|
||||||
60,76
|
|
||||||
)
|
|
||||||
love.graphics.setLineWidth(1)
|
|
||||||
end
|
|
||||||
|
|
||||||
self.game:drawGrid()
|
|
||||||
if self.game.lcd > 0 then self.game:drawLineClearAnimation() end
|
|
||||||
self.game:drawPiece()
|
|
||||||
self.game:drawNextQueue(self.ruleset)
|
|
||||||
self.game:drawScoringInfo()
|
|
||||||
|
|
||||||
-- ready/go graphics
|
|
||||||
|
|
||||||
if self.game.ready_frames <= 100 and self.game.ready_frames > 52 then
|
|
||||||
love.graphics.draw(misc_graphics["ready"], 144 - 50, 240 - 14)
|
|
||||||
elseif self.game.ready_frames <= 50 and self.game.ready_frames > 2 then
|
|
||||||
love.graphics.draw(misc_graphics["go"], 144 - 27, 240 - 14)
|
|
||||||
end
|
|
||||||
|
|
||||||
self.game:drawCustom()
|
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_2)
|
|
||||||
if config.gamesettings.display_gamemode == 1 then
|
|
||||||
love.graphics.printf(self.game.name .. " - " .. self.ruleset.name, 0, 460, 640, "left")
|
|
||||||
end
|
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
|
||||||
if self.paused then love.graphics.print("PAUSED!", 80, 100) end
|
|
||||||
|
|
||||||
if self.game.completed then
|
|
||||||
self.game:onGameComplete()
|
|
||||||
elseif self.game.game_over then
|
|
||||||
self.game:onGameOver()
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function GameScene:onInputPress(e)
|
function GameScene:onInputPress(e)
|
||||||
if (self.game.game_over or self.game.completed) and (e.input == "menu_decide" or e.input == "menu_back" or e.input == "retry") then
|
if (
|
||||||
|
self.game.game_over or self.game.completed
|
||||||
|
) and (
|
||||||
|
e.input == "menu_decide" or
|
||||||
|
e.input == "menu_back" or
|
||||||
|
e.input == "retry"
|
||||||
|
) then
|
||||||
highscore_entry = self.game:getHighscoreData()
|
highscore_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)
|
||||||
|
self.game:onExit()
|
||||||
scene = e.input == "retry" and GameScene(self.retry_mode, self.retry_ruleset, self.secret_inputs) or ModeSelectScene()
|
scene = e.input == "retry" and GameScene(self.retry_mode, self.retry_ruleset, self.secret_inputs) or ModeSelectScene()
|
||||||
elseif e.input == "retry" then
|
elseif e.input == "retry" then
|
||||||
switchBGM(nil)
|
switchBGM(nil)
|
||||||
|
self.game:onExit()
|
||||||
scene = GameScene(self.retry_mode, self.retry_ruleset, self.secret_inputs)
|
scene = GameScene(self.retry_mode, self.retry_ruleset, self.secret_inputs)
|
||||||
elseif e.input == "pause" and not (self.game.game_over or self.game.completed) then
|
elseif e.input == "pause" and not (self.game.game_over or self.game.completed) then
|
||||||
self.paused = not self.paused
|
self.paused = not self.paused
|
||||||
if self.paused then pauseBGM()
|
if self.paused then pauseBGM()
|
||||||
else resumeBGM() end
|
else resumeBGM() end
|
||||||
elseif e.input == "menu_back" then
|
elseif e.input == "menu_back" then
|
||||||
|
self.game:onExit()
|
||||||
scene = ModeSelectScene()
|
scene = ModeSelectScene()
|
||||||
elseif e.input and string.sub(e.input, 1, 5) ~= "menu_" then
|
elseif e.input and string.sub(e.input, 1, 5) ~= "menu_" then
|
||||||
self.inputs[e.input] = true
|
self.inputs[e.input] = true
|
||||||
|
|||||||
@@ -13,11 +13,11 @@ ConfigScene.options = {
|
|||||||
{"world_reverse", "A Button Rotation", false, {"Left", "Auto", "Right"}},
|
{"world_reverse", "A Button Rotation", false, {"Left", "Auto", "Right"}},
|
||||||
{"spawn_positions", "Spawn Positions", false, {"Per ruleset", "In field", "Out of field"}},
|
{"spawn_positions", "Spawn Positions", false, {"Per ruleset", "In field", "Out of field"}},
|
||||||
{"display_gamemode", "Display Gamemode", false, {"On", "Off"}},
|
{"display_gamemode", "Display Gamemode", false, {"On", "Off"}},
|
||||||
{"das_last_key", "DAS Switch", false, {"Default", "Instant"}},
|
{"das_last_key", "DAS Last Key", false, {"Off", "On"}},
|
||||||
{"smooth_movement", "Smooth Piece Drop", false, {"On", "Off"}},
|
{"smooth_movement", "Smooth Piece Drop", false, {"On", "Off"}},
|
||||||
{"synchroes_allowed", "Synchroes", false, {"Per ruleset", "On", "Off"}},
|
{"synchroes_allowed", "Synchroes", false, {"Per ruleset", "On", "Off"}},
|
||||||
{"diagonal_input", "Diagonal Input", false, {"On", "Off"}},
|
{"diagonal_input", "Diagonal Input", false, {"On", "Off"}},
|
||||||
{"buffer_lock", "Buffer Lock Inputs", false, {"On", "Off"}},
|
{"buffer_lock", "Buffer Drop Type", false, {"Off", "Hold", "Tap"}},
|
||||||
{"sfx_volume", "SFX", true, "sfxSlider"},
|
{"sfx_volume", "SFX", true, "sfxSlider"},
|
||||||
{"bgm_volume", "BGM", true, "bgmSlider"},
|
{"bgm_volume", "BGM", true, "bgmSlider"},
|
||||||
}
|
}
|
||||||
@@ -38,7 +38,6 @@ function ConfigScene:new()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function ConfigScene:update()
|
function ConfigScene:update()
|
||||||
config["das_last_key"] = config.gamesettings.das_last_key == 2
|
|
||||||
self.sfxSlider:update()
|
self.sfxSlider:update()
|
||||||
self.bgmSlider:update()
|
self.bgmSlider:update()
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -2,162 +2,65 @@ local ConfigScene = Scene:extend()
|
|||||||
|
|
||||||
ConfigScene.title = "Input Config"
|
ConfigScene.title = "Input Config"
|
||||||
|
|
||||||
require 'load.save'
|
local menu_screens = {
|
||||||
|
KeyConfigScene,
|
||||||
local configurable_inputs = {
|
StickConfigScene
|
||||||
"menu_decide",
|
|
||||||
"menu_back",
|
|
||||||
"left",
|
|
||||||
"right",
|
|
||||||
"up",
|
|
||||||
"down",
|
|
||||||
"rotate_left",
|
|
||||||
"rotate_left2",
|
|
||||||
"rotate_right",
|
|
||||||
"rotate_right2",
|
|
||||||
"rotate_180",
|
|
||||||
"hold",
|
|
||||||
"retry",
|
|
||||||
"pause",
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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()
|
||||||
self.input_state = 1
|
self.menu_state = 1
|
||||||
self.set_inputs = newSetInputs()
|
DiscordRPC:update({
|
||||||
self.new_input = {}
|
details = "In menus",
|
||||||
self.axis_timer = 0
|
state = "Changing input config",
|
||||||
|
})
|
||||||
DiscordRPC:update({
|
|
||||||
details = "In menus",
|
|
||||||
state = "Changing input config",
|
|
||||||
})
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function ConfigScene:update()
|
function ConfigScene:update() end
|
||||||
end
|
|
||||||
|
|
||||||
function ConfigScene:render()
|
function ConfigScene:render()
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
love.graphics.draw(
|
love.graphics.draw(
|
||||||
backgrounds["input_config"],
|
backgrounds["input_config"],
|
||||||
0, 0, 0,
|
0, 0, 0,
|
||||||
0.5, 0.5
|
0.5, 0.5
|
||||||
)
|
)
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_2)
|
love.graphics.setFont(font_3x5_4)
|
||||||
for i, input in ipairs(configurable_inputs) do
|
love.graphics.print("INPUT CONFIG", 80, 40)
|
||||||
love.graphics.printf(input, 40, 50 + i * 20, 200, "left")
|
|
||||||
if self.set_inputs[input] then
|
|
||||||
love.graphics.printf(self.set_inputs[input], 240, 50 + i * 20, 300, "left")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if self.input_state > table.getn(configurable_inputs) then
|
|
||||||
love.graphics.print("press enter to confirm, delete/backspace to retry" .. (config.input and ", escape to cancel" or ""))
|
|
||||||
else
|
|
||||||
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
|
love.graphics.setFont(font_3x5_2)
|
||||||
|
love.graphics.print("Which controls do you want to configure?", 80, 90)
|
||||||
|
|
||||||
|
love.graphics.setColor(1, 1, 1, 0.5)
|
||||||
|
love.graphics.rectangle("fill", 75, 118 + 50 * self.menu_state, 200, 33)
|
||||||
|
|
||||||
|
love.graphics.setFont(font_3x5_3)
|
||||||
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
|
for i, screen in pairs(menu_screens) do
|
||||||
|
love.graphics.printf(screen.title, 80, 120 + 50 * i, 200, "left")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
local function addJoystick(input, name)
|
function ConfigScene:changeOption(rel)
|
||||||
if not input.joysticks then
|
local len = table.getn(menu_screens)
|
||||||
input.joysticks = {}
|
self.menu_state = (self.menu_state + len + rel - 1) % len + 1
|
||||||
end
|
|
||||||
if not input.joysticks[name] then
|
|
||||||
input.joysticks[name] = {}
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function ConfigScene:onInputPress(e)
|
function ConfigScene:onInputPress(e)
|
||||||
if e.type == "key" then
|
if e.input == "menu_decide" or e.scancode == "return" then
|
||||||
-- function keys, escape, and tab are reserved and can't be remapped
|
playSE("main_decide")
|
||||||
if e.scancode == "escape" and config.input then
|
scene = menu_screens[self.menu_state]()
|
||||||
-- cancel only if there was an input config already
|
elseif e.input == "up" or e.scancode == "up" then
|
||||||
scene = SettingsScene()
|
self:changeOption(-1)
|
||||||
elseif self.input_state > table.getn(configurable_inputs) then
|
playSE("cursor")
|
||||||
if e.scancode == "return" then
|
elseif e.input == "down" or e.scancode == "down" then
|
||||||
-- save new input, then load next scene
|
self:changeOption(1)
|
||||||
config.input = self.new_input
|
playSE("cursor")
|
||||||
saveConfig()
|
elseif config.input and (
|
||||||
scene = TitleScene()
|
e.input == "menu_back" or e.scancode == "backspace" or e.scancode == "delete"
|
||||||
elseif e.scancode == "delete" or e.scancode == "backspace" then
|
) then
|
||||||
-- retry
|
scene = SettingsScene()
|
||||||
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
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
return ConfigScene
|
return ConfigScene
|
||||||
100
scene/key_config.lua
Normal file
100
scene/key_config.lua
Normal file
@@ -0,0 +1,100 @@
|
|||||||
|
local KeyConfigScene = Scene:extend()
|
||||||
|
|
||||||
|
KeyConfigScene.title = "Key Config"
|
||||||
|
|
||||||
|
require 'load.save'
|
||||||
|
|
||||||
|
local configurable_inputs = {
|
||||||
|
"menu_decide",
|
||||||
|
"menu_back",
|
||||||
|
"left",
|
||||||
|
"right",
|
||||||
|
"up",
|
||||||
|
"down",
|
||||||
|
"rotate_left",
|
||||||
|
"rotate_left2",
|
||||||
|
"rotate_right",
|
||||||
|
"rotate_right2",
|
||||||
|
"rotate_180",
|
||||||
|
"hold",
|
||||||
|
"retry",
|
||||||
|
"pause",
|
||||||
|
}
|
||||||
|
|
||||||
|
local function newSetInputs()
|
||||||
|
local set_inputs = {}
|
||||||
|
for i, input in ipairs(configurable_inputs) do
|
||||||
|
set_inputs[input] = false
|
||||||
|
end
|
||||||
|
return set_inputs
|
||||||
|
end
|
||||||
|
|
||||||
|
function KeyConfigScene:new()
|
||||||
|
self.input_state = 1
|
||||||
|
self.set_inputs = newSetInputs()
|
||||||
|
self.new_input = {}
|
||||||
|
|
||||||
|
DiscordRPC:update({
|
||||||
|
details = "In menus",
|
||||||
|
state = "Changing key config",
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
function KeyConfigScene:update()
|
||||||
|
end
|
||||||
|
|
||||||
|
function KeyConfigScene:render()
|
||||||
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
|
love.graphics.draw(
|
||||||
|
backgrounds["input_config"],
|
||||||
|
0, 0, 0,
|
||||||
|
0.5, 0.5
|
||||||
|
)
|
||||||
|
|
||||||
|
love.graphics.setFont(font_3x5_2)
|
||||||
|
for i, input in ipairs(configurable_inputs) do
|
||||||
|
love.graphics.printf(input, 40, 50 + i * 20, 200, "left")
|
||||||
|
if self.set_inputs[input] then
|
||||||
|
love.graphics.printf(self.set_inputs[input], 240, 50 + i * 20, 300, "left")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if self.input_state > table.getn(configurable_inputs) then
|
||||||
|
love.graphics.print("press enter to confirm, delete/backspace to retry" .. (config.input and ", escape to cancel" or ""))
|
||||||
|
else
|
||||||
|
love.graphics.print("press key input for " .. configurable_inputs[self.input_state] .. ", tab to skip, escape to cancel", 0, 0)
|
||||||
|
love.graphics.print("function keys (F1, F2, etc.), escape, and tab can't be changed", 0, 20)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function KeyConfigScene:onInputPress(e)
|
||||||
|
if e.type == "key" then
|
||||||
|
-- function keys, escape, and tab are reserved and can't be remapped
|
||||||
|
if e.scancode == "escape" then
|
||||||
|
scene = InputConfigScene()
|
||||||
|
elseif self.input_state > table.getn(configurable_inputs) then
|
||||||
|
if e.scancode == "return" then
|
||||||
|
-- save new input, then load next scene
|
||||||
|
local had_config = config.input ~= nil
|
||||||
|
if not config.input then config.input = {} end
|
||||||
|
config.input.keys = self.new_input
|
||||||
|
saveConfig()
|
||||||
|
scene = had_config and InputConfigScene() or 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" and not self.new_input[e.scancode] then
|
||||||
|
-- all other keys can be configured
|
||||||
|
self.set_inputs[configurable_inputs[self.input_state]] = "key " .. love.keyboard.getKeyFromScancode(e.scancode) .. " (" .. e.scancode .. ")"
|
||||||
|
self.new_input[e.scancode] = configurable_inputs[self.input_state]
|
||||||
|
self.input_state = self.input_state + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return KeyConfigScene
|
||||||
159
scene/stick_config.lua
Normal file
159
scene/stick_config.lua
Normal file
@@ -0,0 +1,159 @@
|
|||||||
|
local StickConfigScene = Scene:extend()
|
||||||
|
|
||||||
|
StickConfigScene.title = "Joystick Config"
|
||||||
|
|
||||||
|
require 'load.save'
|
||||||
|
|
||||||
|
local configurable_inputs = {
|
||||||
|
"menu_decide",
|
||||||
|
"menu_back",
|
||||||
|
"left",
|
||||||
|
"right",
|
||||||
|
"up",
|
||||||
|
"down",
|
||||||
|
"rotate_left",
|
||||||
|
"rotate_left2",
|
||||||
|
"rotate_right",
|
||||||
|
"rotate_right2",
|
||||||
|
"rotate_180",
|
||||||
|
"hold",
|
||||||
|
"retry",
|
||||||
|
"pause",
|
||||||
|
}
|
||||||
|
|
||||||
|
local function newSetInputs()
|
||||||
|
local set_inputs = {}
|
||||||
|
for i, input in ipairs(configurable_inputs) do
|
||||||
|
set_inputs[input] = false
|
||||||
|
end
|
||||||
|
return set_inputs
|
||||||
|
end
|
||||||
|
|
||||||
|
function StickConfigScene:new()
|
||||||
|
self.input_state = 1
|
||||||
|
self.set_inputs = newSetInputs()
|
||||||
|
self.new_input = {}
|
||||||
|
self.axis_timer = 0
|
||||||
|
|
||||||
|
DiscordRPC:update({
|
||||||
|
details = "In menus",
|
||||||
|
state = "Changing joystick config",
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
function StickConfigScene:update()
|
||||||
|
end
|
||||||
|
|
||||||
|
function StickConfigScene:render()
|
||||||
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
|
love.graphics.draw(
|
||||||
|
backgrounds["input_config"],
|
||||||
|
0, 0, 0,
|
||||||
|
0.5, 0.5
|
||||||
|
)
|
||||||
|
|
||||||
|
love.graphics.setFont(font_3x5_2)
|
||||||
|
for i, input in ipairs(configurable_inputs) do
|
||||||
|
love.graphics.printf(input, 40, 50 + i * 20, 200, "left")
|
||||||
|
if self.set_inputs[input] then
|
||||||
|
love.graphics.printf(self.set_inputs[input], 240, 50 + i * 20, 300, "left")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if self.input_state > table.getn(configurable_inputs) then
|
||||||
|
love.graphics.print("press enter to confirm, delete/backspace to retry" .. (config.input and ", escape to cancel" or ""))
|
||||||
|
else
|
||||||
|
love.graphics.print("press joystick input for " .. configurable_inputs[self.input_state] .. ", tab to skip, escape to cancel", 0, 0)
|
||||||
|
end
|
||||||
|
|
||||||
|
self.axis_timer = self.axis_timer + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
local function addJoystick(input, name)
|
||||||
|
if not input[name] then
|
||||||
|
input[name] = {}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function StickConfigScene:onInputPress(e)
|
||||||
|
if e.type == "key" then
|
||||||
|
-- function keys, escape, and tab are reserved and can't be remapped
|
||||||
|
if e.scancode == "escape" then
|
||||||
|
scene = InputConfigScene()
|
||||||
|
elseif self.input_state > table.getn(configurable_inputs) then
|
||||||
|
if e.scancode == "return" then
|
||||||
|
-- save new input, then load next scene
|
||||||
|
local had_config = config.input ~= nil
|
||||||
|
if not config.input then config.input = {} end
|
||||||
|
config.input.joysticks = self.new_input
|
||||||
|
saveConfig()
|
||||||
|
scene = had_config and InputConfigScene() or 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
|
||||||
|
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[e.name].buttons then
|
||||||
|
self.new_input[e.name].buttons = {}
|
||||||
|
end
|
||||||
|
if self.new_input[e.name].buttons[e.button] then return 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[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[e.name].axes then
|
||||||
|
self.new_input[e.name].axes = {}
|
||||||
|
end
|
||||||
|
if not self.new_input[e.name].axes[e.axis] then
|
||||||
|
self.new_input[e.name].axes[e.axis] = {}
|
||||||
|
end
|
||||||
|
if (
|
||||||
|
self.new_input[e.name].axes[e.axis][e.value >= 1 and "positive" or "negative"]
|
||||||
|
) then return 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[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[e.name].hats then
|
||||||
|
self.new_input[e.name].hats = {}
|
||||||
|
end
|
||||||
|
if not self.new_input[e.name].hats[e.hat] then
|
||||||
|
self.new_input[e.name].hats[e.hat] = {}
|
||||||
|
end
|
||||||
|
if self.new_input[e.name].hats[e.hat][e.direction] then
|
||||||
|
return
|
||||||
|
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[e.name].hats[e.hat][e.direction] = configurable_inputs[self.input_state]
|
||||||
|
self.input_state = self.input_state + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return StickConfigScene
|
||||||
@@ -83,6 +83,7 @@ function TitleScene:render()
|
|||||||
love.graphics.printf(screen.title, 40, 280 + 20 * i, 120, "left")
|
love.graphics.printf(screen.title, 40, 280 + 20 * i, 120, "left")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
love.graphics.printf(version, 0, 460, love.graphics.getWidth() - 5, "right")
|
||||||
end
|
end
|
||||||
|
|
||||||
function TitleScene:changeOption(rel)
|
function TitleScene:changeOption(rel)
|
||||||
|
|||||||
@@ -400,11 +400,10 @@ function Grid:draw()
|
|||||||
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
|
||||||
if self.grid[y][x].skin == "bone" then
|
if self.grid[y][x].colour == "X" then
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
|
||||||
elseif self.grid[y][x].colour == "X" then
|
|
||||||
love.graphics.setColor(0, 0, 0, 0)
|
love.graphics.setColor(0, 0, 0, 0)
|
||||||
--love.graphics.setColor(0.5, 0.5, 0.5, 1 - self.grid_age[y][x] / 15)
|
elseif self.grid[y][x].skin == "bone" then
|
||||||
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
else
|
else
|
||||||
love.graphics.setColor(0.5, 0.5, 0.5, 1)
|
love.graphics.setColor(0.5, 0.5, 0.5, 1)
|
||||||
end
|
end
|
||||||
@@ -435,12 +434,6 @@ end
|
|||||||
function Grid:drawOutline()
|
function Grid:drawOutline()
|
||||||
for y = 5, self.height do
|
for y = 5, self.height do
|
||||||
for x = 1, self.width do
|
for x = 1, self.width do
|
||||||
--[[
|
|
||||||
if self.grid[y][x].colour == "X" then
|
|
||||||
love.graphics.setColor(0.5, 0.5, 0.5, 1 - self.grid_age[y][x] / 15)
|
|
||||||
love.graphics.draw(blocks[self.grid[y][x].skin][self.grid[y][x].colour], 48+x*16, y*16)
|
|
||||||
end
|
|
||||||
]]
|
|
||||||
if self.grid[y][x] ~= empty and self.grid[y][x].colour ~= "X" then
|
if self.grid[y][x] ~= empty and self.grid[y][x].colour ~= "X" then
|
||||||
love.graphics.setColor(0.8, 0.8, 0.8, 1)
|
love.graphics.setColor(0.8, 0.8, 0.8, 1)
|
||||||
love.graphics.setLineWidth(1)
|
love.graphics.setLineWidth(1)
|
||||||
@@ -470,7 +463,6 @@ function Grid:drawInvisible(opacity_function, garbage_opacity_function, lock_fla
|
|||||||
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 = 0
|
opacity = 0
|
||||||
--opacity = 1 - self.grid_age[y][x] / 15
|
|
||||||
elseif garbage_opacity_function and self.grid[y][x].colour == "A" 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
|
||||||
@@ -518,7 +510,6 @@ function Grid:drawCustom(colour_function, gamestate)
|
|||||||
local R, G, B, A, outline = colour_function(gamestate, block, x, y, self.grid_age[y][x])
|
local R, G, B, A, outline = colour_function(gamestate, block, x, y, self.grid_age[y][x])
|
||||||
if self.grid[y][x].colour == "X" then
|
if self.grid[y][x].colour == "X" then
|
||||||
A = 0
|
A = 0
|
||||||
--A = 1 - self.grid_age[y][x] / 15
|
|
||||||
end
|
end
|
||||||
love.graphics.setColor(R, G, B, A)
|
love.graphics.setColor(R, G, B, A)
|
||||||
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)
|
||||||
|
|||||||
@@ -117,19 +117,37 @@ function Piece:lockIfBottomed(grid)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
function Piece:addGravity(gravity, grid)
|
function Piece:addGravity(gravity, grid, classic_lock)
|
||||||
|
gravity = gravity / (self.big and 2 or 1)
|
||||||
local new_gravity = self.gravity + gravity
|
local new_gravity = self.gravity + gravity
|
||||||
if self:isDropBlocked(grid) then
|
if self:isDropBlocked(grid) then
|
||||||
self.gravity = math.min(1, new_gravity)
|
if classic_lock then
|
||||||
self.lock_delay = self.lock_delay + 1
|
self.gravity = new_gravity
|
||||||
else
|
else
|
||||||
local dropped_squares = math.floor(new_gravity)
|
self.gravity = 0
|
||||||
local new_frac_gravity = new_gravity - dropped_squares
|
self.lock_delay = self.lock_delay + 1
|
||||||
self.gravity = new_frac_gravity
|
|
||||||
self:dropSquares(dropped_squares, grid)
|
|
||||||
if self:isDropBlocked(grid) then
|
|
||||||
playSE("bottom")
|
|
||||||
end
|
end
|
||||||
|
elseif not (
|
||||||
|
self:isMoveBlocked(grid, { x=0, y=-1 }) and gravity < 0
|
||||||
|
) then
|
||||||
|
local dropped_squares = math.floor(math.abs(new_gravity))
|
||||||
|
if gravity >= 0 then
|
||||||
|
local new_frac_gravity = new_gravity - dropped_squares
|
||||||
|
self.gravity = new_frac_gravity
|
||||||
|
self:dropSquares(dropped_squares, grid)
|
||||||
|
if self:isDropBlocked(grid) then
|
||||||
|
playSE("bottom")
|
||||||
|
end
|
||||||
|
else
|
||||||
|
local new_frac_gravity = new_gravity + dropped_squares
|
||||||
|
self.gravity = new_frac_gravity
|
||||||
|
self:moveInGrid({ x=0, y=-1 }, dropped_squares, grid)
|
||||||
|
if self:isMoveBlocked(grid, { x=0, y=-1 }) then
|
||||||
|
playSE("bottom")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self.gravity = 0
|
||||||
end
|
end
|
||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,138 +1,24 @@
|
|||||||
require 'funcs'
|
|
||||||
|
|
||||||
local GameMode = require 'tetris.modes.gamemode'
|
local GameMode = require 'tetris.modes.gamemode'
|
||||||
local Piece = require 'tetris.components.piece'
|
local MarathonA2Game = require 'tetris.modes.marathon_a2'
|
||||||
|
|
||||||
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
local BigA2Game = MarathonA2Game:extend()
|
||||||
|
|
||||||
local MarathonA2Game = GameMode:extend()
|
BigA2Game.name = "Big A2"
|
||||||
|
BigA2Game.hash = "BigA2"
|
||||||
|
BigA2Game.tagline = "Big blocks in the most celebrated TGM mode!"
|
||||||
|
|
||||||
MarathonA2Game.name = "Big A2"
|
function BigA2Game:new()
|
||||||
MarathonA2Game.hash = "BigA2"
|
BigA2Game.super:new()
|
||||||
MarathonA2Game.tagline = "The points don't matter! Can you reach the invisible roll? Big mode too!"
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function MarathonA2Game:new()
|
|
||||||
self.super:new()
|
|
||||||
self.big_mode = true
|
self.big_mode = true
|
||||||
self.roll_frames = 0
|
|
||||||
self.combo = 1
|
|
||||||
|
|
||||||
self.grade = 0
|
|
||||||
self.grade_points = 0
|
|
||||||
self.grade_point_decay_counter = 0
|
|
||||||
|
|
||||||
self.randomizer = History6RollsRandomizer()
|
|
||||||
|
|
||||||
self.lock_drop = false
|
|
||||||
self.lock_hard_drop = false
|
|
||||||
self.enable_hold = false
|
|
||||||
self.next_queue_length = 1
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA2Game:getARE()
|
function BigA2Game:updateScore(level, drop_bonus, cleared_lines)
|
||||||
if self.level < 700 then return 27
|
cleared_lines = cleared_lines / 2
|
||||||
elseif self.level < 800 then return 18
|
|
||||||
else return 14 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonA2Game:getLineARE()
|
|
||||||
if self.level < 600 then return 27
|
|
||||||
elseif self.level < 700 then return 18
|
|
||||||
elseif self.level < 800 then return 14
|
|
||||||
else return 8 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonA2Game:getDasLimit()
|
|
||||||
if self.level < 500 then return 15
|
|
||||||
elseif self.level < 900 then return 9
|
|
||||||
else return 7 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonA2Game: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
|
|
||||||
else return 6 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonA2Game:getLockDelay()
|
|
||||||
if self.level < 900 then return 30
|
|
||||||
else return 17 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonA2Game: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 MarathonA2Game:advanceOneFrame()
|
|
||||||
if self.clear then
|
|
||||||
self.roll_frames = self.roll_frames + 1
|
|
||||||
if self.roll_frames < 0 then return false end
|
|
||||||
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 MarathonA2Game: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 MarathonA2Game:onLineClear(cleared_row_count)
|
|
||||||
cleared_row_count = cleared_row_count / 2
|
|
||||||
self.level = math.min(self.level + cleared_row_count, 999)
|
|
||||||
if self.level == 999 and not self.clear then
|
|
||||||
self.clear = true
|
|
||||||
self.grid:clear()
|
|
||||||
self.roll_frames = -150
|
|
||||||
end
|
|
||||||
self.lock_drop = self.level >= 900
|
|
||||||
self.lock_hard_drop = self.level >= 900
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonA2Game:updateScore(level, drop_bonus, cleared_lines)
|
|
||||||
if not self.clear then
|
if not self.clear then
|
||||||
cleared_lines = cleared_lines / 2
|
|
||||||
self:updateGrade(cleared_lines)
|
self:updateGrade(cleared_lines)
|
||||||
|
if cleared_lines >= 4 then
|
||||||
|
self.tetris_count = self.tetris_count + 1
|
||||||
|
end
|
||||||
if self.grid:checkForBravo(cleared_lines) then self.bravo = 4 else self.bravo = 1 end
|
if self.grid:checkForBravo(cleared_lines) then self.bravo = 4 else self.bravo = 1 end
|
||||||
if cleared_lines > 0 then
|
if cleared_lines > 0 then
|
||||||
self.combo = self.combo + (cleared_lines - 1) * 2
|
self.combo = self.combo + (cleared_lines - 1) * 2
|
||||||
@@ -144,164 +30,21 @@ function MarathonA2Game:updateScore(level, drop_bonus, cleared_lines)
|
|||||||
self.combo = 1
|
self.combo = 1
|
||||||
end
|
end
|
||||||
self.drop_bonus = 0
|
self.drop_bonus = 0
|
||||||
|
else self.lines = self.lines + cleared_lines end
|
||||||
|
end
|
||||||
|
|
||||||
|
function BigA2Game:onLineClear(cleared_row_count)
|
||||||
|
cleared_row_count = cleared_row_count / 2
|
||||||
|
self:updateSectionTimes(self.level, self.level + cleared_row_count)
|
||||||
|
self.level = math.min(self.level + cleared_row_count, 999)
|
||||||
|
if self.level == 999 and not self.clear then
|
||||||
|
self.clear = true
|
||||||
|
self.grid:clear()
|
||||||
|
if self:qualifiesForMRoll() then self.grade = 32 end
|
||||||
|
self.roll_frames = -150
|
||||||
end
|
end
|
||||||
|
self.lock_drop = self.level >= 900
|
||||||
|
self.lock_hard_drop = self.level >= 900
|
||||||
end
|
end
|
||||||
|
|
||||||
local grade_point_bonuses = {
|
return BigA2Game
|
||||||
{10, 20, 40, 50},
|
|
||||||
{10, 20, 30, 40},
|
|
||||||
{10, 20, 30, 40},
|
|
||||||
{10, 15, 30, 40},
|
|
||||||
{10, 15, 20, 40},
|
|
||||||
{5, 15, 20, 30},
|
|
||||||
{5, 10, 20, 30},
|
|
||||||
{5, 10, 15, 30},
|
|
||||||
{5, 10, 15, 30},
|
|
||||||
{5, 10, 15, 30},
|
|
||||||
{2, 12, 13, 30},
|
|
||||||
{2, 12, 13, 30},
|
|
||||||
{2, 12, 13, 30},
|
|
||||||
{2, 12, 13, 30},
|
|
||||||
{2, 12, 13, 30},
|
|
||||||
{2, 12, 13, 30},
|
|
||||||
{2, 12, 13, 30},
|
|
||||||
{2, 12, 13, 30},
|
|
||||||
{2, 12, 13, 30},
|
|
||||||
{2, 12, 13, 30},
|
|
||||||
{2, 12, 13, 30},
|
|
||||||
{2, 12, 13, 30},
|
|
||||||
{2, 12, 13, 30},
|
|
||||||
{2, 12, 13, 30},
|
|
||||||
{2, 12, 13, 30},
|
|
||||||
{2, 12, 13, 30},
|
|
||||||
{2, 12, 13, 30},
|
|
||||||
{2, 12, 13, 30},
|
|
||||||
{2, 12, 13, 30},
|
|
||||||
{2, 12, 13, 30},
|
|
||||||
{2, 12, 13, 30},
|
|
||||||
{2, 12, 13, 30},
|
|
||||||
}
|
|
||||||
|
|
||||||
local grade_point_decays = {
|
|
||||||
125, 80, 80, 50, 45, 45, 45,
|
|
||||||
40, 40, 40, 40, 40, 30, 30, 30,
|
|
||||||
20, 20, 20, 20, 20,
|
|
||||||
15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
|
|
||||||
10, 10
|
|
||||||
}
|
|
||||||
|
|
||||||
local combo_multipliers = {
|
|
||||||
{1.0, 1.0, 1.0, 1.0},
|
|
||||||
{1.2, 1.4, 1.5, 1.0},
|
|
||||||
{1.2, 1.5, 1.8, 1.0},
|
|
||||||
{1.4, 1.6, 2.0, 1.0},
|
|
||||||
{1.4, 1.7, 2.2, 1.0},
|
|
||||||
{1.4, 1.8, 2.3, 1.0},
|
|
||||||
{1.4, 1.9, 2.4, 1.0},
|
|
||||||
{1.5, 2.0, 2.5, 1.0},
|
|
||||||
{1.5, 2.1, 2.6, 1.0},
|
|
||||||
{2.0, 2.5, 3.0, 1.0},
|
|
||||||
}
|
|
||||||
|
|
||||||
local grade_conversion = {
|
|
||||||
[0] = 0,
|
|
||||||
1, 2, 3, 4, 5, 5, 6, 6, 7, 7,
|
|
||||||
7, 8, 8, 8, 9, 9, 9, 10, 11, 12,
|
|
||||||
12, 12, 13, 13, 14, 14, 15, 15, 16, 16,
|
|
||||||
17
|
|
||||||
}
|
|
||||||
|
|
||||||
function MarathonA2Game:updateGrade(cleared_lines)
|
|
||||||
if self.clear then return end
|
|
||||||
if cleared_lines == 0 then
|
|
||||||
self.grade_point_decay_counter = self.grade_point_decay_counter + 1
|
|
||||||
if self.grade_point_decay_counter >= grade_point_decays[self.grade + 1] then
|
|
||||||
self.grade_point_decay_counter = 0
|
|
||||||
self.grade_points = math.max(0, self.grade_points - 1)
|
|
||||||
end
|
|
||||||
else
|
|
||||||
self.grade_points = self.grade_points + (
|
|
||||||
math.ceil(
|
|
||||||
grade_point_bonuses[self.grade + 1][cleared_lines] *
|
|
||||||
combo_multipliers[math.min(self.combo, 10)][cleared_lines]
|
|
||||||
) * (1 + math.floor(self.level / 250))
|
|
||||||
)
|
|
||||||
if self.grade_points >= 100 and self.grade < 31 then
|
|
||||||
self.grade_points = 0
|
|
||||||
self.grade = self.grade + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonA2Game:getLetterGrade()
|
|
||||||
local grade = grade_conversion[self.grade]
|
|
||||||
if grade < 9 then
|
|
||||||
return tostring(9 - grade)
|
|
||||||
elseif grade < 18 then
|
|
||||||
return "S" .. tostring(grade - 8)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
MarathonA2Game.rollOpacityFunction = function(age)
|
|
||||||
if age < 240 then return 1
|
|
||||||
elseif age > 300 then return 0
|
|
||||||
else return 1 - (age - 240) / 60 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonA2Game:drawGrid(ruleset)
|
|
||||||
if self.clear and not (self.completed or self.game_over) then
|
|
||||||
self.grid:drawInvisible(self.rollOpacityFunction, nil, false)
|
|
||||||
else
|
|
||||||
self.grid:draw()
|
|
||||||
if self.piece ~= nil and self.level < 100 then
|
|
||||||
self:drawGhostPiece(ruleset)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonA2Game: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("GRADE", 240, 120, 40, "left")
|
|
||||||
love.graphics.printf("SCORE", 240, 200, 40, "left")
|
|
||||||
love.graphics.printf("LEVEL", 240, 320, 40, "left")
|
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
|
||||||
if self.roll_frames > 3694 then love.graphics.setColor(1, 0.5, 0, 1)
|
|
||||||
elseif self.clear then love.graphics.setColor(0, 1, 0, 1) end
|
|
||||||
love.graphics.printf(self:getLetterGrade(), 240, 140, 90, "left")
|
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
|
||||||
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")
|
|
||||||
|
|
||||||
love.graphics.setFont(font_8x11)
|
|
||||||
love.graphics.printf(formatTime(self.frames), 64, 420, 160, "center")
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonA2Game:getHighscoreData()
|
|
||||||
return {
|
|
||||||
grade = grade_conversion[self.grade],
|
|
||||||
score = self.score,
|
|
||||||
level = self.level,
|
|
||||||
frames = self.frames,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonA2Game:getSectionEndLevel()
|
|
||||||
if self.level >= 900 then return 999
|
|
||||||
else return math.floor(self.level / 100 + 1) * 100 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonA2Game:getBackground()
|
|
||||||
return math.floor(self.level / 100)
|
|
||||||
end
|
|
||||||
|
|
||||||
return MarathonA2Game
|
|
||||||
@@ -65,6 +65,7 @@ function GameMode:new(secret_inputs)
|
|||||||
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.cleared_block_table = {}
|
self.cleared_block_table = {}
|
||||||
|
self.last_lcd = 0
|
||||||
self.used_randomizer = nil
|
self.used_randomizer = nil
|
||||||
self.hold_queue = nil
|
self.hold_queue = nil
|
||||||
self.held = false
|
self.held = false
|
||||||
@@ -84,10 +85,11 @@ function GameMode:getDasCutDelay() return 0 end
|
|||||||
function GameMode:getGravity() return 1/64 end
|
function GameMode:getGravity() return 1/64 end
|
||||||
|
|
||||||
function GameMode:getNextPiece(ruleset)
|
function GameMode:getNextPiece(ruleset)
|
||||||
|
local shape = self.used_randomizer:nextPiece()
|
||||||
return {
|
return {
|
||||||
skin = self:getSkin(),
|
skin = self:getSkin(),
|
||||||
shape = self.used_randomizer:nextPiece(),
|
shape = shape,
|
||||||
orientation = ruleset:getDefaultOrientation(),
|
orientation = ruleset:getDefaultOrientation(shape),
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -95,9 +97,8 @@ function GameMode:getSkin()
|
|||||||
return "2tie"
|
return "2tie"
|
||||||
end
|
end
|
||||||
|
|
||||||
function GameMode:initialize(ruleset, secret_inputs)
|
function GameMode:initialize(ruleset)
|
||||||
-- generate next queue
|
-- generate next queue
|
||||||
self:new(secret_inputs)
|
|
||||||
self.used_randomizer = (
|
self.used_randomizer = (
|
||||||
ruleset.pieces == self.randomizer.possible_pieces and
|
ruleset.pieces == self.randomizer.possible_pieces and
|
||||||
self.randomizer or
|
self.randomizer or
|
||||||
@@ -107,6 +108,7 @@ function GameMode:initialize(ruleset, secret_inputs)
|
|||||||
BagRandomizer(ruleset.pieces)
|
BagRandomizer(ruleset.pieces)
|
||||||
)
|
)
|
||||||
)
|
)
|
||||||
|
self.ruleset = ruleset
|
||||||
for i = 1, math.max(self.next_queue_length, 1) do
|
for i = 1, math.max(self.next_queue_length, 1) do
|
||||||
table.insert(self.next_queue, self:getNextPiece(ruleset))
|
table.insert(self.next_queue, self:getNextPiece(ruleset))
|
||||||
end
|
end
|
||||||
@@ -136,31 +138,13 @@ function GameMode:update(inputs, ruleset)
|
|||||||
self:chargeDAS(inputs, self:getDasLimit(), self:getARR())
|
self:chargeDAS(inputs, self:getDasLimit(), self:getARR())
|
||||||
|
|
||||||
-- set attempt flags
|
-- set attempt flags
|
||||||
if inputs["left"] or inputs["right"] then
|
if inputs["left"] or inputs["right"] then self:onAttemptPieceMove(self.piece, self.grid) end
|
||||||
self:onAttemptPieceMove(self.piece)
|
if (
|
||||||
if self.immobile_spin_bonus and self.piece ~= nil then
|
|
||||||
if not self.piece:isMoveBlocked(self.grid, { x=-1, y=0 }) and
|
|
||||||
not self.piece:isMoveBlocked(self.grid, { x=1, y=0 }) then
|
|
||||||
self.piece.spin = false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if
|
|
||||||
inputs["rotate_left"] or inputs["rotate_right"] or
|
inputs["rotate_left"] or inputs["rotate_right"] or
|
||||||
inputs["rotate_left2"] or inputs["rotate_right2"] or
|
inputs["rotate_left2"] or inputs["rotate_right2"] or
|
||||||
inputs["rotate_180"]
|
inputs["rotate_180"]
|
||||||
then
|
) then
|
||||||
self:onAttemptPieceRotate(self.piece)
|
self:onAttemptPieceRotate(self.piece, self.grid)
|
||||||
if self.immobile_spin_bonus and self.piece ~= nil then
|
|
||||||
if self.piece:isDropBlocked(self.grid) and
|
|
||||||
self.piece:isMoveBlocked(self.grid, { x=-1, y=0 }) and
|
|
||||||
self.piece:isMoveBlocked(self.grid, { x=1, y=0 }) and
|
|
||||||
self.piece:isMoveBlocked(self.grid, { x=0, y=-1 }) then
|
|
||||||
self.piece.spin = true
|
|
||||||
else
|
|
||||||
self.piece.spin = false
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.piece == nil then
|
if self.piece == nil then
|
||||||
@@ -173,9 +157,6 @@ function GameMode:update(inputs, ruleset)
|
|||||||
if self.enable_hold and inputs["hold"] == true and self.held == false and self.prev_inputs["hold"] == 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
|
||||||
if not self.grid:canPlacePiece(self.piece) then
|
|
||||||
self.game_over = true
|
|
||||||
end
|
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -193,16 +174,21 @@ function GameMode:update(inputs, ruleset)
|
|||||||
|
|
||||||
-- diff vars to use in checks
|
-- diff vars to use in checks
|
||||||
local piece_y = self.piece.position.y
|
local piece_y = self.piece.position.y
|
||||||
|
local piece_x = self.piece.position.x
|
||||||
local piece_rot = self.piece.rotation
|
local piece_rot = self.piece.rotation
|
||||||
|
|
||||||
ruleset:processPiece(
|
ruleset:processPiece(
|
||||||
inputs, self.piece, self.grid, self:getGravity(), self.prev_inputs,
|
inputs, self.piece, self.grid, self:getGravity(), self.prev_inputs,
|
||||||
self.move, self:getLockDelay(), self:getDropSpeed(),
|
(
|
||||||
|
inputs.up and self.lock_on_hard_drop and not self.hard_drop_locked
|
||||||
|
) and "none" or self.move,
|
||||||
|
self:getLockDelay(), self:getDropSpeed(),
|
||||||
self.drop_locked, self.hard_drop_locked,
|
self.drop_locked, self.hard_drop_locked,
|
||||||
self.enable_hard_drop, self.additive_gravity, self.classic_lock
|
self.enable_hard_drop, self.additive_gravity, self.classic_lock
|
||||||
)
|
)
|
||||||
|
|
||||||
local piece_dy = self.piece.position.y - piece_y
|
local piece_dy = self.piece.position.y - piece_y
|
||||||
|
local piece_dx = self.piece.position.x - piece_x
|
||||||
local piece_drot = self.piece.rotation - piece_rot
|
local piece_drot = self.piece.rotation - piece_rot
|
||||||
|
|
||||||
-- das cut
|
-- das cut
|
||||||
@@ -214,10 +200,20 @@ function GameMode:update(inputs, ruleset)
|
|||||||
inputs.rotate_180
|
inputs.rotate_180
|
||||||
))
|
))
|
||||||
) then
|
) then
|
||||||
self.das.frames = math.max(
|
self:dasCut()
|
||||||
self.das.frames - self:getDasCutDelay(),
|
end
|
||||||
-(self:getDasCutDelay() + 1)
|
|
||||||
)
|
if (piece_dx ~= 0) then
|
||||||
|
self.piece.last_rotated = false
|
||||||
|
self:onPieceMove(self.piece, self.grid, piece_dx)
|
||||||
|
end
|
||||||
|
if (piece_dy ~= 0) then
|
||||||
|
self.piece.last_rotated = false
|
||||||
|
self:onPieceDrop(self.piece, self.grid, piece_dy)
|
||||||
|
end
|
||||||
|
if (piece_drot ~= 0) then
|
||||||
|
self.piece.last_rotated = true
|
||||||
|
self:onPieceRotate(self.piece, self.grid, piece_drot)
|
||||||
end
|
end
|
||||||
|
|
||||||
if inputs["up"] == true and
|
if inputs["up"] == true and
|
||||||
@@ -231,17 +227,36 @@ function GameMode:update(inputs, ruleset)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if inputs["down"] == true then
|
if inputs["down"] == true then
|
||||||
self:onSoftDrop(piece_dy)
|
if not (
|
||||||
|
self.piece:isDropBlocked(self.grid) and
|
||||||
|
piece_drot ~= 0
|
||||||
|
) then
|
||||||
|
self:onSoftDrop(piece_dy)
|
||||||
|
end
|
||||||
if self.piece:isDropBlocked(self.grid) and
|
if self.piece:isDropBlocked(self.grid) and
|
||||||
not self.drop_locked and
|
not self.drop_locked and
|
||||||
self.lock_on_soft_drop
|
self.lock_on_soft_drop
|
||||||
then
|
then
|
||||||
self.piece.locked = true
|
self.piece.locked = true
|
||||||
|
self.piece_soft_locked = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if self.piece.locked == true then
|
if self.piece.locked == true then
|
||||||
|
-- spin detection, immobile only for now
|
||||||
|
if self.immobile_spin_bonus and
|
||||||
|
self.piece.last_rotated and (
|
||||||
|
self.piece:isDropBlocked(self.grid) and
|
||||||
|
self.piece:isMoveBlocked(self.grid, { x=-1, y=0 }) and
|
||||||
|
self.piece:isMoveBlocked(self.grid, { x=1, y=0 }) and
|
||||||
|
self.piece:isMoveBlocked(self.grid, { x=0, y=-1 })
|
||||||
|
) then
|
||||||
|
self.piece.spin = true
|
||||||
|
end
|
||||||
|
|
||||||
self.grid:applyPiece(self.piece)
|
self.grid:applyPiece(self.piece)
|
||||||
|
|
||||||
|
-- mark squares (can be overridden)
|
||||||
if self.square_mode then
|
if self.square_mode then
|
||||||
self.squares = self.squares + self.grid:markSquares()
|
self.squares = self.squares + self.grid:markSquares()
|
||||||
end
|
end
|
||||||
@@ -259,6 +274,7 @@ function GameMode:update(inputs, ruleset)
|
|||||||
if cleared_row_count > 0 then
|
if cleared_row_count > 0 then
|
||||||
playSE("erase")
|
playSE("erase")
|
||||||
self.lcd = self:getLineClearDelay()
|
self.lcd = self:getLineClearDelay()
|
||||||
|
self.last_lcd = self.lcd
|
||||||
self.are = (
|
self.are = (
|
||||||
ruleset.are and self:getLineARE() or 0
|
ruleset.are and self:getLineARE() or 0
|
||||||
)
|
)
|
||||||
@@ -294,8 +310,11 @@ end
|
|||||||
|
|
||||||
-- event functions
|
-- event functions
|
||||||
function GameMode:whilePieceActive() end
|
function GameMode:whilePieceActive() end
|
||||||
function GameMode:onAttemptPieceMove(piece) end
|
function GameMode:onAttemptPieceMove(piece, grid) end
|
||||||
function GameMode:onAttemptPieceRotate(piece) end
|
function GameMode:onAttemptPieceRotate(piece, grid) end
|
||||||
|
function GameMode:onPieceMove(piece, grid, dx) end
|
||||||
|
function GameMode:onPieceRotate(piece, grid, drot) end
|
||||||
|
function GameMode:onPieceDrop(piece, grid, dy) end
|
||||||
function GameMode:onPieceLock(piece, cleared_row_count)
|
function GameMode:onPieceLock(piece, cleared_row_count)
|
||||||
playSE("lock")
|
playSE("lock")
|
||||||
end
|
end
|
||||||
@@ -307,11 +326,13 @@ function GameMode:onPieceEnter() end
|
|||||||
function GameMode:onHold() end
|
function GameMode:onHold() 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 + (
|
||||||
|
(self.piece.big and 2 or 1) * dropped_row_count
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
function GameMode:onHardDrop(dropped_row_count)
|
function GameMode:onHardDrop(dropped_row_count)
|
||||||
self.drop_bonus = self.drop_bonus + 2 * dropped_row_count
|
self:onSoftDrop(dropped_row_count * 2)
|
||||||
end
|
end
|
||||||
|
|
||||||
function GameMode:onGameOver()
|
function GameMode:onGameOver()
|
||||||
@@ -327,6 +348,8 @@ function GameMode:onGameComplete()
|
|||||||
self:onGameOver()
|
self:onGameOver()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function GameMode:onExit() end
|
||||||
|
|
||||||
-- DAS functions
|
-- DAS functions
|
||||||
|
|
||||||
function GameMode:startRightDAS()
|
function GameMode:startRightDAS()
|
||||||
@@ -367,7 +390,7 @@ function GameMode:stopDAS()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function GameMode:chargeDAS(inputs)
|
function GameMode:chargeDAS(inputs)
|
||||||
if config["das_last_key"] then
|
if config.gamesettings.das_last_key == 2 then
|
||||||
if inputs["right"] == true and self.das.direction ~= "right" and not self.prev_inputs["right"] then
|
if inputs["right"] == true and self.das.direction ~= "right" and not self.prev_inputs["right"] then
|
||||||
self:startRightDAS()
|
self:startRightDAS()
|
||||||
elseif inputs["left"] == true and self.das.direction ~= "left" and not self.prev_inputs["left"] then
|
elseif inputs["left"] == true and self.das.direction ~= "left" and not self.prev_inputs["left"] then
|
||||||
@@ -390,27 +413,46 @@ function GameMode:chargeDAS(inputs)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function GameMode:dasCut()
|
||||||
|
self.das.frames = math.max(
|
||||||
|
self.das.frames - self:getDasCutDelay(),
|
||||||
|
-(self:getDasCutDelay() + 1)
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
function GameMode:areCancel(inputs, ruleset)
|
function GameMode:areCancel(inputs, ruleset)
|
||||||
if ruleset.are_cancel and self.piece_hard_dropped and
|
if ruleset.are_cancel and strTrueValues(inputs) ~= "" and
|
||||||
not self.prev_inputs.up and
|
not self.prev_inputs.up and
|
||||||
strTrueValues(inputs) ~= "" then
|
(self.piece_hard_dropped or
|
||||||
|
(self.piece_soft_locked and not self.prev_inputs.down)) then
|
||||||
self.lcd = 0
|
self.lcd = 0
|
||||||
self.are = 0
|
self.are = 0
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function GameMode:checkBufferedInputs(inputs)
|
||||||
|
if (
|
||||||
|
config.gamesettings.buffer_lock ~= 1 and
|
||||||
|
not self.prev_inputs["up"] and inputs["up"] and
|
||||||
|
self.enable_hard_drop
|
||||||
|
) then
|
||||||
|
self.buffer_hard_drop = true
|
||||||
|
end
|
||||||
|
if (
|
||||||
|
config.gamesettings.buffer_lock ~= 1 and
|
||||||
|
not self.prev_inputs["down"] and inputs["down"]
|
||||||
|
) then
|
||||||
|
self.buffer_soft_drop = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function GameMode:processDelays(inputs, ruleset, drop_speed)
|
function GameMode:processDelays(inputs, ruleset, drop_speed)
|
||||||
if self.ready_frames == 100 then
|
if self.ready_frames == 100 then
|
||||||
playedReadySE = false
|
playedReadySE = false
|
||||||
playedGoSE = false
|
playedGoSE = false
|
||||||
end
|
end
|
||||||
if self.ready_frames > 0 then
|
if self.ready_frames > 0 then
|
||||||
if not self.prev_inputs["up"] and inputs["up"] and self.enable_hard_drop then
|
self:checkBufferedInputs(inputs)
|
||||||
self.buffer_hard_drop = true
|
|
||||||
end
|
|
||||||
if not self.prev_inputs["down"] and inputs["down"] then
|
|
||||||
self.buffer_soft_drop = true
|
|
||||||
end
|
|
||||||
if not playedReadySE then
|
if not playedReadySE then
|
||||||
playedReadySE = true
|
playedReadySE = true
|
||||||
playSEOnce("ready")
|
playSEOnce("ready")
|
||||||
@@ -424,12 +466,7 @@ function GameMode:processDelays(inputs, ruleset, drop_speed)
|
|||||||
self:initializeOrHold(inputs, ruleset)
|
self:initializeOrHold(inputs, ruleset)
|
||||||
end
|
end
|
||||||
elseif self.lcd > 0 then
|
elseif self.lcd > 0 then
|
||||||
if not self.prev_inputs["up"] and inputs["up"] and self.enable_hard_drop then
|
self:checkBufferedInputs(inputs)
|
||||||
self.buffer_hard_drop = true
|
|
||||||
end
|
|
||||||
if not self.prev_inputs["down"] and inputs["down"] then
|
|
||||||
self.buffer_soft_drop = true
|
|
||||||
end
|
|
||||||
self.lcd = self.lcd - 1
|
self.lcd = self.lcd - 1
|
||||||
self:areCancel(inputs, ruleset)
|
self:areCancel(inputs, ruleset)
|
||||||
if self.lcd == 0 then
|
if self.lcd == 0 then
|
||||||
@@ -442,12 +479,7 @@ function GameMode:processDelays(inputs, ruleset, drop_speed)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif self.are > 0 then
|
elseif self.are > 0 then
|
||||||
if not self.prev_inputs["up"] and inputs["up"] and self.enable_hard_drop then
|
self:checkBufferedInputs(inputs)
|
||||||
self.buffer_hard_drop = true
|
|
||||||
end
|
|
||||||
if not self.prev_inputs["down"] and inputs["down"] then
|
|
||||||
self.buffer_soft_drop = true
|
|
||||||
end
|
|
||||||
self.are = self.are - 1
|
self.are = self.are - 1
|
||||||
self:areCancel(inputs, ruleset)
|
self:areCancel(inputs, ruleset)
|
||||||
if self.are == 0 then
|
if self.are == 0 then
|
||||||
@@ -458,7 +490,7 @@ end
|
|||||||
|
|
||||||
function GameMode:initializeOrHold(inputs, ruleset)
|
function GameMode:initializeOrHold(inputs, ruleset)
|
||||||
if (
|
if (
|
||||||
self.frames == 0 or (ruleset.are and self:getARE() ~= 0) and self.ihs or false
|
(self.frames == 0 or (ruleset.are and self:getARE() ~= 0)) and self.ihs or false
|
||||||
) and self.enable_hold and inputs["hold"] == true then
|
) and self.enable_hold and inputs["hold"] == true then
|
||||||
self:hold(inputs, ruleset, true)
|
self:hold(inputs, ruleset, true)
|
||||||
else
|
else
|
||||||
@@ -468,6 +500,10 @@ function GameMode:initializeOrHold(inputs, ruleset)
|
|||||||
if not self.grid:canPlacePiece(self.piece) then
|
if not self.grid:canPlacePiece(self.piece) then
|
||||||
self.game_over = true
|
self.game_over = true
|
||||||
end
|
end
|
||||||
|
ruleset:dropPiece(
|
||||||
|
inputs, self.piece, self.grid, self:getGravity(),
|
||||||
|
self:getDropSpeed(), self.drop_locked, self.hard_drop_locked
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
function GameMode:hold(inputs, ruleset, ihs)
|
function GameMode:hold(inputs, ruleset, ihs)
|
||||||
@@ -492,47 +528,55 @@ function GameMode:hold(inputs, ruleset, ihs)
|
|||||||
if ihs then playSE("ihs")
|
if ihs then playSE("ihs")
|
||||||
else playSE("hold") end
|
else playSE("hold") end
|
||||||
self:onHold()
|
self:onHold()
|
||||||
|
if not self.grid:canPlacePiece(self.piece) then
|
||||||
|
self.game_over = true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function GameMode:initializeNextPiece(inputs, ruleset, piece_data, generate_next_piece)
|
function GameMode:initializeNextPiece(inputs, ruleset, piece_data, generate_next_piece)
|
||||||
self.piece_hard_dropped = false
|
if not self.buffer_soft_drop and self.lock_drop or (
|
||||||
local gravity = self:getGravity()
|
|
||||||
self.piece = ruleset:initializePiece(
|
|
||||||
inputs, piece_data, self.grid, gravity,
|
|
||||||
self.prev_inputs, self.move,
|
|
||||||
self:getLockDelay(), self:getDropSpeed(),
|
|
||||||
self.lock_drop, self.lock_hard_drop, self.big_mode,
|
|
||||||
(
|
|
||||||
self.frames == 0 or (ruleset.are and self:getARE() ~= 0)
|
|
||||||
) and self.irs or false,
|
|
||||||
self.buffer_hard_drop, self.buffer_soft_drop,
|
|
||||||
self.lock_on_hard_drop, self.lock_on_soft_drop
|
|
||||||
)
|
|
||||||
if self.piece:isDropBlocked(self.grid) and
|
|
||||||
self.grid:canPlacePiece(self.piece) then
|
|
||||||
playSE("bottom")
|
|
||||||
end
|
|
||||||
if self.buffer_hard_drop then
|
|
||||||
self.buffer_hard_drop = false
|
|
||||||
self:onHardDrop(self.piece.position.y - (
|
|
||||||
self.big_mode and
|
|
||||||
ruleset.big_spawn_positions[self.piece.shape].y or
|
|
||||||
ruleset.spawn_positions[self.piece.shape].y)
|
|
||||||
)
|
|
||||||
end
|
|
||||||
if self.buffer_soft_drop then
|
|
||||||
self.buffer_soft_drop = false
|
|
||||||
end
|
|
||||||
if self.lock_drop or (
|
|
||||||
not ruleset.are or self:getARE() == 0
|
not ruleset.are or self:getARE() == 0
|
||||||
) then
|
) then
|
||||||
self.drop_locked = true
|
self.drop_locked = true
|
||||||
end
|
end
|
||||||
if self.lock_hard_drop or (
|
if not self.buffer_hard_drop and self.lock_hard_drop or (
|
||||||
not ruleset.are or self:getARE() == 0
|
not ruleset.are or self:getARE() == 0
|
||||||
) then
|
) then
|
||||||
self.hard_drop_locked = true
|
self.hard_drop_locked = true
|
||||||
end
|
end
|
||||||
|
self.piece = ruleset:initializePiece(
|
||||||
|
inputs, piece_data, self.grid, self:getGravity(),
|
||||||
|
self.prev_inputs, self.move,
|
||||||
|
self:getLockDelay(), self:getDropSpeed(),
|
||||||
|
self.drop_locked, self.hard_drop_locked, self.big_mode,
|
||||||
|
(
|
||||||
|
self.frames == 0 or (ruleset.are and self:getARE() ~= 0)
|
||||||
|
) and self.irs or false
|
||||||
|
)
|
||||||
|
if config.gamesettings.buffer_lock == 3 then
|
||||||
|
if self.buffer_hard_drop then
|
||||||
|
local prev_y = self.piece.position.y
|
||||||
|
self.piece:dropToBottom(self.grid)
|
||||||
|
self.piece.locked = self.lock_on_hard_drop
|
||||||
|
self:onHardDrop(self.piece.position.y - prev_y)
|
||||||
|
end
|
||||||
|
if self.buffer_soft_drop then
|
||||||
|
if (
|
||||||
|
self.lock_on_soft_drop and
|
||||||
|
self.piece:isDropBlocked(self.grid)
|
||||||
|
) then
|
||||||
|
self.piece.locked = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
self.piece_hard_dropped = false
|
||||||
|
self.piece_soft_locked = false
|
||||||
|
self.buffer_hard_drop = false
|
||||||
|
self.buffer_soft_drop = false
|
||||||
|
if self.piece:isDropBlocked(self.grid) and
|
||||||
|
self.grid:canPlacePiece(self.piece) then
|
||||||
|
playSE("bottom")
|
||||||
|
end
|
||||||
if generate_next_piece == nil then
|
if generate_next_piece == nil then
|
||||||
table.remove(self.next_queue, 1)
|
table.remove(self.next_queue, 1)
|
||||||
table.insert(self.next_queue, self:getNextPiece(ruleset))
|
table.insert(self.next_queue, self:getNextPiece(ruleset))
|
||||||
@@ -553,12 +597,16 @@ end
|
|||||||
function GameMode:animation(x, y, skin, colour)
|
function GameMode:animation(x, y, skin, colour)
|
||||||
return {
|
return {
|
||||||
1, 1, 1,
|
1, 1, 1,
|
||||||
-0.25 + 1.25 * (self.lcd / self:getLineClearDelay()),
|
-0.25 + 1.25 * (self.lcd / self.last_lcd),
|
||||||
skin, colour,
|
skin, colour,
|
||||||
48 + x * 16, y * 16
|
48 + x * 16, y * 16
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function GameMode:canDrawLCA()
|
||||||
|
return self.lcd > 0
|
||||||
|
end
|
||||||
|
|
||||||
function GameMode:drawLineClearAnimation()
|
function GameMode:drawLineClearAnimation()
|
||||||
-- animation function
|
-- animation function
|
||||||
-- params: block x, y, skin, colour
|
-- params: block x, y, skin, colour
|
||||||
@@ -569,7 +617,7 @@ function GameMode:drawLineClearAnimation()
|
|||||||
function animation(x, y, skin, colour)
|
function animation(x, y, skin, colour)
|
||||||
return {
|
return {
|
||||||
1, 1, 1,
|
1, 1, 1,
|
||||||
-0.25 + 1.25 * (self.lcd / self:getLineClearDelay()),
|
-0.25 + 1.25 * (self.lcd / self.last_lcd),
|
||||||
skin, colour,
|
skin, colour,
|
||||||
48 + x * 16, y * 16
|
48 + x * 16, y * 16
|
||||||
}
|
}
|
||||||
@@ -593,7 +641,7 @@ function GameMode:drawLineClearAnimation()
|
|||||||
function animation(x, y, skin, colour)
|
function animation(x, y, skin, colour)
|
||||||
local p = 0.5
|
local p = 0.5
|
||||||
local l = (
|
local l = (
|
||||||
(self:getLineClearDelay() - self.lcd) / self:getLineClearDelay()
|
(self.last_lcd - self.lcd) / self.last_lcd
|
||||||
)
|
)
|
||||||
local dx = l * (x - (1 + self.grid.width) / 2)
|
local dx = l * (x - (1 + self.grid.width) / 2)
|
||||||
local dy = l * (y - (1 + self.grid.height) / 2)
|
local dy = l * (y - (1 + self.grid.height) / 2)
|
||||||
@@ -643,11 +691,16 @@ 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
|
||||||
|
if ruleset.pieces == 7 then
|
||||||
|
colourscheme = ({ruleset.colourscheme, ColourSchemes.Arika, ColourSchemes.TTC})[config.gamesettings.piece_colour]
|
||||||
|
else
|
||||||
|
colourscheme = ruleset.colourscheme
|
||||||
|
end
|
||||||
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.draw_offsets[piece].x + ruleset.spawn_positions[piece].x
|
local x = offset.x + ruleset:getDrawOffset(piece, rotation).x + ruleset.spawn_positions[piece].x
|
||||||
local y = offset.y + ruleset.draw_offsets[piece].y + 4.7
|
local y = offset.y + ruleset:getDrawOffset(piece, rotation).y + 4.7
|
||||||
love.graphics.draw(blocks[skin][colourscheme[piece]], pos_x+x*16, pos_y+y*16)
|
love.graphics.draw(blocks[skin][colourscheme[piece]], pos_x+x*16, pos_y+y*16)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -773,19 +826,109 @@ function GameMode:drawSectionTimesWithSplits(current_section, section_limit)
|
|||||||
|
|
||||||
for section, time in pairs(self.section_times) do
|
for section, time in pairs(self.section_times) do
|
||||||
if section > 0 then
|
if section > 0 then
|
||||||
|
love.graphics.setColor(self:sectionColourFunction(section))
|
||||||
love.graphics.printf(formatTime(time), section_x, 40 + 20 * section, 90, "left")
|
love.graphics.printf(formatTime(time), section_x, 40 + 20 * section, 90, "left")
|
||||||
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
split_time = split_time + time
|
split_time = split_time + time
|
||||||
love.graphics.printf(formatTime(split_time), split_x, 40 + 20 * section, 90, "left")
|
love.graphics.printf(formatTime(split_time), split_x, 40 + 20 * section, 90, "left")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
if (current_section <= section_limit) then
|
if (current_section <= section_limit) then
|
||||||
love.graphics.setColor(self:sectionColourFunction(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")
|
||||||
love.graphics.printf(formatTime(self.frames), split_x, 40 + 20 * current_section, 90, "left")
|
love.graphics.printf(formatTime(self.frames), split_x, 40 + 20 * current_section, 90, "left")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function GameMode:drawBackground()
|
||||||
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
|
love.graphics.draw(
|
||||||
|
backgrounds[self:getBackground()],
|
||||||
|
0, 0, 0,
|
||||||
|
0.5, 0.5
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
function GameMode:drawFrame()
|
||||||
|
-- game frame
|
||||||
|
if self.grid.width == 10 and self.grid.height == 24 then
|
||||||
|
love.graphics.draw(misc_graphics["frame"], 48, 64)
|
||||||
|
end
|
||||||
|
|
||||||
|
love.graphics.setColor(0, 0, 0, 200)
|
||||||
|
love.graphics.rectangle(
|
||||||
|
"fill", 64, 80,
|
||||||
|
16 * self.grid.width, 16 * (self.grid.height - 4)
|
||||||
|
)
|
||||||
|
|
||||||
|
if self.grid.width ~= 10 or self.grid.height ~= 24 then
|
||||||
|
love.graphics.setColor(174/255, 83/255, 76/255, 1)
|
||||||
|
love.graphics.setLineWidth(8)
|
||||||
|
love.graphics.line(
|
||||||
|
60,76,
|
||||||
|
68+16*self.grid.width,76,
|
||||||
|
68+16*self.grid.width,84+16*(self.grid.height-4),
|
||||||
|
60,84+16*(self.grid.height-4),
|
||||||
|
60,76
|
||||||
|
)
|
||||||
|
love.graphics.setColor(203/255, 137/255, 111/255, 1)
|
||||||
|
love.graphics.setLineWidth(4)
|
||||||
|
love.graphics.line(
|
||||||
|
60,76,
|
||||||
|
68+16*self.grid.width,76,
|
||||||
|
68+16*self.grid.width,84+16*(self.grid.height-4),
|
||||||
|
60,84+16*(self.grid.height-4),
|
||||||
|
60,76
|
||||||
|
)
|
||||||
|
love.graphics.setLineWidth(1)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function GameMode:drawReadyGo()
|
||||||
|
-- ready/go graphics
|
||||||
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
|
|
||||||
|
if self.ready_frames <= 100 and self.ready_frames > 52 then
|
||||||
|
love.graphics.draw(misc_graphics["ready"], 144 - 50, 240 - 14)
|
||||||
|
elseif self.ready_frames <= 50 and self.ready_frames > 2 then
|
||||||
|
love.graphics.draw(misc_graphics["go"], 144 - 27, 240 - 14)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function GameMode:drawCustom() end
|
function GameMode:drawCustom() end
|
||||||
|
|
||||||
|
function GameMode:draw(paused)
|
||||||
|
self:drawBackground()
|
||||||
|
self:drawFrame()
|
||||||
|
self:drawGrid()
|
||||||
|
self:drawPiece()
|
||||||
|
self:drawNextQueue(self.ruleset)
|
||||||
|
self:drawScoringInfo()
|
||||||
|
self:drawReadyGo()
|
||||||
|
self:drawCustom()
|
||||||
|
if self:canDrawLCA() then
|
||||||
|
self:drawLineClearAnimation()
|
||||||
|
end
|
||||||
|
|
||||||
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
|
love.graphics.setFont(font_3x5_2)
|
||||||
|
if config.gamesettings.display_gamemode == 1 then
|
||||||
|
love.graphics.printf(
|
||||||
|
self.name .. " - " .. self.ruleset.name,
|
||||||
|
0, 460, 640, "left"
|
||||||
|
)
|
||||||
|
end
|
||||||
|
|
||||||
|
love.graphics.setFont(font_3x5_3)
|
||||||
|
if paused then
|
||||||
|
love.graphics.printf("GAME PAUSED!", 64, 160, 160, "center")
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.completed then
|
||||||
|
self:onGameComplete()
|
||||||
|
elseif self.game_over then
|
||||||
|
self:onGameOver()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
return GameMode
|
return GameMode
|
||||||
|
|||||||
@@ -144,7 +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
|
if self:qualifiesForMRoll() 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
|
||||||
@@ -154,11 +154,11 @@ function Marathon2020Game:advanceOneFrame()
|
|||||||
end
|
end
|
||||||
|
|
||||||
local cool_cutoffs = {
|
local cool_cutoffs = {
|
||||||
frameTime(0,45,00), frameTime(0,41,50), frameTime(0,38,50), frameTime(0,35,00), frameTime(0,32,50),
|
[0] = frameTime(0,45,00),
|
||||||
frameTime(0,29,20), frameTime(0,27,20), frameTime(0,24,80), frameTime(0,22,80), frameTime(0,20,60),
|
frameTime(0,41,50), frameTime(0,38,50), frameTime(0,35,00), frameTime(0,32,50), frameTime(0,29,20),
|
||||||
frameTime(0,19,60), frameTime(0,19,40), frameTime(0,19,40), frameTime(0,18,40), frameTime(0,18,20),
|
frameTime(0,27,20), frameTime(0,24,80), frameTime(0,22,80), frameTime(0,20,60), frameTime(0,19,60),
|
||||||
frameTime(0,16,20), frameTime(0,16,20), frameTime(0,16,20), frameTime(0,16,20), frameTime(0,16,20),
|
frameTime(0,19,40), frameTime(0,19,40), frameTime(0,18,40), frameTime(0,18,20), frameTime(0,16,20),
|
||||||
frameTime(0,15,20)
|
frameTime(0,16,20), frameTime(0,16,20), frameTime(0,16,20), frameTime(0,16,20), frameTime(0,15,20)
|
||||||
}
|
}
|
||||||
|
|
||||||
local levels_for_cleared_rows = { 1, 2, 4, 6 }
|
local levels_for_cleared_rows = { 1, 2, 4, 6 }
|
||||||
@@ -227,13 +227,14 @@ local mid_cleared_line_points = {2, 6, 12, 24}
|
|||||||
local high_cleared_line_points = {1, 4, 9, 20}
|
local high_cleared_line_points = {1, 4, 9, 20}
|
||||||
|
|
||||||
local function getGradeForGradePoints(points)
|
local function getGradeForGradePoints(points)
|
||||||
return math.floor(math.sqrt((points / 50) * 8 + 1) / 2 - 0.5)
|
return math.min(30, math.floor(math.sqrt((points / 50) * 8 + 1) / 2 - 0.5))
|
||||||
-- Don't be afraid of the above function. All it does is make it so that
|
-- Don't be afraid of the above function. All it does is make it so that
|
||||||
-- you need 50 points to get to grade 1, 100 points to grade 2, etc.
|
-- you need 50 points to get to grade 1, 100 points to grade 2, etc.
|
||||||
end
|
end
|
||||||
|
|
||||||
function Marathon2020Game:updateGrade(cleared_lines)
|
function Marathon2020Game:updateGrade(cleared_lines)
|
||||||
-- update grade points and max grade points
|
-- update grade points and max grade points
|
||||||
|
if self.clear then return end
|
||||||
local point_level = math.floor(self.level / 100) + self.delay_level
|
local point_level = math.floor(self.level / 100) + self.delay_level
|
||||||
local plus_points = math.max(
|
local plus_points = math.max(
|
||||||
low_cleared_line_points[cleared_lines],
|
low_cleared_line_points[cleared_lines],
|
||||||
@@ -249,12 +250,11 @@ 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
|
||||||
|
|
||||||
local function getSectionForLevel(level)
|
local function getSectionForLevel(level)
|
||||||
if level < 2001 then
|
if level < 2000 then
|
||||||
return math.floor(level / 100) + 1
|
return math.floor(level / 100) + 1
|
||||||
elseif level < 2020 then
|
elseif level < 2020 then
|
||||||
return 20
|
return 20
|
||||||
@@ -331,14 +331,16 @@ end
|
|||||||
function Marathon2020Game:updateSectionTimes(old_level, new_level)
|
function Marathon2020Game:updateSectionTimes(old_level, new_level)
|
||||||
function sectionCool(section)
|
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)
|
if section <= 10 then
|
||||||
if section < 10 then table.insert(self.section_status, "cool") end
|
self.delay_level = math.min(20, self.delay_level + 1)
|
||||||
|
end
|
||||||
|
table.insert(self.section_status, "cool")
|
||||||
self.cool_timer = 300
|
self.cool_timer = 300
|
||||||
end
|
end
|
||||||
|
|
||||||
local section = getSectionForLevel(old_level)
|
local section = getSectionForLevel(old_level)
|
||||||
|
|
||||||
if section <= 19 and old_level % 100 < 70 and new_level >= math.floor(old_level / 100) * 100 + 70 then
|
if old_level % 100 < 70 and new_level >= math.floor(old_level / 100) * 100 + 70 then
|
||||||
-- record section 70 time
|
-- record section 70 time
|
||||||
section_70_time = self.frames - self.section_start_time
|
section_70_time = self.frames - self.section_start_time
|
||||||
table.insert(self.secondary_section_times, section_70_time)
|
table.insert(self.secondary_section_times, section_70_time)
|
||||||
@@ -350,23 +352,25 @@ 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 > 5 then self.delay_level = math.min(20, self.delay_level + 1) end
|
|
||||||
self:checkTorikan(section)
|
|
||||||
self:checkClear(new_level)
|
|
||||||
|
|
||||||
if (
|
if (
|
||||||
section <= 19 and self.section_status[section - 1] == "cool" and
|
self.section_status[section - 1] == "cool" and
|
||||||
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[self.delay_level]
|
||||||
) then
|
) then
|
||||||
sectionCool(section)
|
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 self.secondary_section_times[section] < cool_cutoffs[self.delay_level] then
|
||||||
sectionCool(section)
|
sectionCool(section)
|
||||||
else
|
else
|
||||||
table.insert(self.section_status, "none")
|
table.insert(self.section_status, "none")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if section > 5 then
|
||||||
|
self.delay_level = math.min(20, self.delay_level + 1)
|
||||||
|
end
|
||||||
|
self:checkTorikan(section)
|
||||||
|
self:checkClear(new_level)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -452,7 +456,13 @@ function Marathon2020Game:drawScoringInfo()
|
|||||||
end
|
end
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
love.graphics.setFont(font_3x5_3)
|
||||||
love.graphics.printf(self:getTotalGrade(), text_x, 120, 90, "left")
|
|
||||||
|
local grade = self:getTotalGrade()
|
||||||
|
love.graphics.printf(
|
||||||
|
grade > 50 and "GM" or grade,
|
||||||
|
text_x, 120, 90, "left"
|
||||||
|
)
|
||||||
|
|
||||||
love.graphics.printf(self.grade_points, text_x, 220, 90, "left")
|
love.graphics.printf(self.grade_points, text_x, 220, 90, "left")
|
||||||
love.graphics.printf(self.level, text_x, 340, 50, "right")
|
love.graphics.printf(self.level, text_x, 340, 50, "right")
|
||||||
|
|
||||||
@@ -466,7 +476,7 @@ end
|
|||||||
|
|
||||||
function Marathon2020Game:getHighscoreData()
|
function Marathon2020Game:getHighscoreData()
|
||||||
return {
|
return {
|
||||||
grade = self.grade,
|
grade = self:getTotalGrade(),
|
||||||
level = self.level,
|
level = self.level,
|
||||||
frames = self.frames,
|
frames = self.frames,
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -33,6 +33,7 @@ function MarathonA1Game:new()
|
|||||||
|
|
||||||
self.randomizer = History4RollsRandomizer()
|
self.randomizer = History4RollsRandomizer()
|
||||||
|
|
||||||
|
self.additive_gravity = false
|
||||||
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
|
||||||
|
|||||||
@@ -19,6 +19,7 @@ function MarathonA2Game:new()
|
|||||||
|
|
||||||
self.roll_frames = 0
|
self.roll_frames = 0
|
||||||
self.combo = 1
|
self.combo = 1
|
||||||
|
self.grade_combo = 1
|
||||||
self.randomizer = History6RollsRandomizer()
|
self.randomizer = History6RollsRandomizer()
|
||||||
self.grade = 0
|
self.grade = 0
|
||||||
self.grade_points = 0
|
self.grade_points = 0
|
||||||
@@ -34,6 +35,7 @@ function MarathonA2Game:new()
|
|||||||
"GM"
|
"GM"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.additive_gravity = false
|
||||||
self.lock_drop = false
|
self.lock_drop = false
|
||||||
self.lock_hard_drop = false
|
self.lock_hard_drop = false
|
||||||
self.enable_hold = false
|
self.enable_hold = false
|
||||||
@@ -134,15 +136,23 @@ function MarathonA2Game:updateScore(level, drop_bonus, cleared_lines)
|
|||||||
if cleared_lines >= 4 then
|
if cleared_lines >= 4 then
|
||||||
self.tetris_count = self.tetris_count + 1
|
self.tetris_count = self.tetris_count + 1
|
||||||
end
|
end
|
||||||
if self.grid:checkForBravo(cleared_lines) then self.bravo = 4 else self.bravo = 1 end
|
if self.grid:checkForBravo(cleared_lines) then
|
||||||
|
self.bravo = 4
|
||||||
|
else
|
||||||
|
self.bravo = 1
|
||||||
|
end
|
||||||
if cleared_lines > 0 then
|
if cleared_lines > 0 then
|
||||||
self.combo = self.combo + (cleared_lines - 1) * 2
|
self.combo = self.combo + (cleared_lines - 1) * 2
|
||||||
|
if cleared_lines > 1 then
|
||||||
|
self.grade_combo = self.grade_combo + 1
|
||||||
|
end
|
||||||
self.score = self.score + (
|
self.score = self.score + (
|
||||||
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
||||||
cleared_lines * self.combo * self.bravo
|
cleared_lines * self.combo * self.bravo
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
self.combo = 1
|
self.combo = 1
|
||||||
|
self.grade_combo = 1
|
||||||
end
|
end
|
||||||
self.drop_bonus = 0
|
self.drop_bonus = 0
|
||||||
else self.lines = self.lines + cleared_lines end
|
else self.lines = self.lines + cleared_lines end
|
||||||
@@ -252,7 +262,7 @@ function MarathonA2Game:updateGrade(cleared_lines)
|
|||||||
self.grade_points = self.grade_points + (
|
self.grade_points = self.grade_points + (
|
||||||
math.ceil(
|
math.ceil(
|
||||||
grade_point_bonuses[self.grade + 1][cleared_lines] *
|
grade_point_bonuses[self.grade + 1][cleared_lines] *
|
||||||
combo_multipliers[math.min(self.combo, 10)][cleared_lines]
|
combo_multipliers[math.min(self.grade_combo, 10)][cleared_lines]
|
||||||
) * (1 + math.floor(self.level / 250))
|
) * (1 + math.floor(self.level / 250))
|
||||||
)
|
)
|
||||||
if self.grade_points >= 100 and self.grade < 31 then
|
if self.grade_points >= 100 and self.grade < 31 then
|
||||||
|
|||||||
@@ -20,6 +20,7 @@ function MarathonA3Game: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_combo = 1
|
||||||
self.grade = 0
|
self.grade = 0
|
||||||
self.grade_points = 0
|
self.grade_points = 0
|
||||||
self.roll_points = 0
|
self.roll_points = 0
|
||||||
@@ -39,6 +40,7 @@ self.SGnames = {
|
|||||||
"GM"
|
"GM"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
self.additive_gravity = false
|
||||||
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
|
||||||
@@ -235,12 +237,16 @@ function MarathonA3Game:updateScore(level, drop_bonus, cleared_lines)
|
|||||||
if not self.clear then
|
if not self.clear then
|
||||||
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
|
||||||
|
if cleared_lines > 1 then
|
||||||
|
self.grade_combo = self.grade_combo + 1
|
||||||
|
end
|
||||||
self.score = self.score + (
|
self.score = self.score + (
|
||||||
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
||||||
cleared_lines * self.combo
|
cleared_lines * self.combo
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
self.combo = 1
|
self.combo = 1
|
||||||
|
self.grade_combo = 1
|
||||||
end
|
end
|
||||||
self.drop_bonus = 0
|
self.drop_bonus = 0
|
||||||
end
|
end
|
||||||
@@ -334,7 +340,7 @@ function MarathonA3Game:updateGrade(cleared_lines)
|
|||||||
self.grade_points = self.grade_points + (
|
self.grade_points = self.grade_points + (
|
||||||
math.ceil(
|
math.ceil(
|
||||||
grade_point_bonuses[self.grade + 1][cleared_lines] *
|
grade_point_bonuses[self.grade + 1][cleared_lines] *
|
||||||
combo_multipliers[math.min(self.combo, 10)][cleared_lines]
|
combo_multipliers[math.min(self.grade_combo, 10)][cleared_lines]
|
||||||
) * (1 + math.floor(self.level / 250))
|
) * (1 + math.floor(self.level / 250))
|
||||||
)
|
)
|
||||||
if self.grade_points >= 100 and self.grade < 31 then
|
if self.grade_points >= 100 and self.grade < 31 then
|
||||||
@@ -350,7 +356,12 @@ function MarathonA3Game:qualifiesForMRoll()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA3Game:getAggregateGrade()
|
function MarathonA3Game:getAggregateGrade()
|
||||||
return self.section_cool_grade + math.floor(self.roll_points / 100) + grade_conversion[self.grade]
|
return math.min(
|
||||||
|
self.section_cool_grade +
|
||||||
|
math.floor(self.roll_points / 100) +
|
||||||
|
grade_conversion[self.grade],
|
||||||
|
self.roll_frames > 3238 and 32 or 31
|
||||||
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
local master_grades = { "M", "MK", "MV", "MO", "MM" }
|
local master_grades = { "M", "MK", "MV", "MO", "MM" }
|
||||||
@@ -365,8 +376,6 @@ 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
|
||||||
@@ -464,7 +473,7 @@ function MarathonA3Game:drawScoringInfo()
|
|||||||
love.graphics.setFont(font_3x5_3)
|
love.graphics.setFont(font_3x5_3)
|
||||||
love.graphics.printf(self.score, 240, 220, 90, "left")
|
love.graphics.printf(self.score, 240, 220, 90, "left")
|
||||||
if self.roll_frames > 3238 then love.graphics.setColor(1, 0.5, 0, 1)
|
if self.roll_frames > 3238 then love.graphics.setColor(1, 0.5, 0, 1)
|
||||||
elseif self.level >= 999 and self.clear then love.graphics.setColor(0, 1, 0, 1) end
|
elseif self.level >= 999 then love.graphics.setColor(0, 1, 0, 1) end
|
||||||
love.graphics.printf(self:getLetterGrade(), 240, 140, 90, "left")
|
love.graphics.printf(self:getLetterGrade(), 240, 140, 90, "left")
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
love.graphics.printf(self.level, 240, 340, 40, "right")
|
love.graphics.printf(self.level, 240, 340, 40, "right")
|
||||||
|
|||||||
@@ -19,13 +19,16 @@ function PhantomManiaGame:new()
|
|||||||
self.next_queue_length = 1
|
self.next_queue_length = 1
|
||||||
|
|
||||||
self.SGnames = {
|
self.SGnames = {
|
||||||
"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",
|
||||||
|
"M1", "M2", "M3", "M4", "M5", "M6", "M7", "M8", "M9",
|
||||||
"GM"
|
"GM"
|
||||||
}
|
}
|
||||||
|
|
||||||
self.roll_frames = 0
|
self.roll_frames = 0
|
||||||
self.combo = 1
|
self.combo = 1
|
||||||
|
self.tetrises = 0
|
||||||
|
self.section_tetrises = {[0] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
|
||||||
|
self.section_req = true
|
||||||
self.randomizer = History6RollsRandomizer()
|
self.randomizer = History6RollsRandomizer()
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -105,12 +108,23 @@ end
|
|||||||
|
|
||||||
function PhantomManiaGame:onLineClear(cleared_row_count)
|
function PhantomManiaGame:onLineClear(cleared_row_count)
|
||||||
if not self.clear then
|
if not self.clear then
|
||||||
|
if cleared_row_count >= 4 then
|
||||||
|
self.tetrises = self.tetrises + 1
|
||||||
|
self.section_tetrises[math.floor(self.level / 100)] = (
|
||||||
|
self.section_tetrises[math.floor(self.level / 100)] + 1
|
||||||
|
)
|
||||||
|
end
|
||||||
local new_level = self.level + cleared_row_count
|
local new_level = self.level + cleared_row_count
|
||||||
if new_level >= 999 or self:hitTorikan(self.level, new_level) then
|
if new_level >= 999 or self:hitTorikan(self.level, new_level) then
|
||||||
if new_level >= 999 then
|
if new_level >= 999 then
|
||||||
self.level = 999
|
self.level = 999
|
||||||
end
|
end
|
||||||
self.clear = true
|
self.clear = true
|
||||||
|
for i = 0, 9 do
|
||||||
|
if self.section_tetrises[i] < (i == 9 and 1 or 2) then
|
||||||
|
self.section_req = false
|
||||||
|
end
|
||||||
|
end
|
||||||
else
|
else
|
||||||
self.level = new_level
|
self.level = new_level
|
||||||
end
|
end
|
||||||
@@ -138,7 +152,7 @@ PhantomManiaGame.rollOpacityFunction = function(age)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function PhantomManiaGame:drawGrid()
|
function PhantomManiaGame:drawGrid()
|
||||||
if not (self.game_over or self.clear) then
|
if not (self.game_over or self.completed or (self.clear and self.level < 999)) then
|
||||||
self.grid:drawInvisible(self.rollOpacityFunction, nil, false)
|
self.grid:drawInvisible(self.rollOpacityFunction, nil, false)
|
||||||
else
|
else
|
||||||
self.grid:draw()
|
self.grid:draw()
|
||||||
@@ -150,16 +164,14 @@ local function getLetterGrade(level, clear)
|
|||||||
return ""
|
return ""
|
||||||
elseif level < 500 or level == 500 and clear then
|
elseif level < 500 or level == 500 and clear then
|
||||||
return "M"
|
return "M"
|
||||||
elseif level < 700 then
|
elseif level < 600 then
|
||||||
return "MK"
|
return "MK"
|
||||||
elseif level < 800 or level == 800 and clear then
|
elseif level < 700 then
|
||||||
return "MV"
|
return "MV"
|
||||||
elseif level < 900 then
|
elseif level < 800 or level == 800 and clear then
|
||||||
return "MO"
|
return "MO"
|
||||||
elseif level < 999 then
|
elseif level <= 999 then
|
||||||
return "MM"
|
return "MM"
|
||||||
elseif level == 999 then
|
|
||||||
return "GM"
|
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -169,7 +181,9 @@ function PhantomManiaGame:drawScoringInfo()
|
|||||||
local text_x = config["side_next"] and 320 or 240
|
local text_x = config["side_next"] and 320 or 240
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_2)
|
love.graphics.setFont(font_3x5_2)
|
||||||
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()
|
||||||
@@ -178,7 +192,16 @@ function PhantomManiaGame:drawScoringInfo()
|
|||||||
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
|
||||||
|
if self.roll_frames > 1982 then love.graphics.setColor(1, 0.5, 0, 1)
|
||||||
|
elseif self.level == 999 and self.clear then love.graphics.setColor(0, 1, 0, 1) end
|
||||||
|
if self.level == 999 and self.section_req and self.tetrises >= 31 then
|
||||||
|
love.graphics.printf("GM", text_x, 140, 90, "left")
|
||||||
|
else
|
||||||
|
love.graphics.printf(getLetterGrade(self.level, self.clear), text_x, 140, 90, "left")
|
||||||
|
end
|
||||||
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
|
end
|
||||||
love.graphics.printf(self.score, text_x, 220, 90, "left")
|
love.graphics.printf(self.score, text_x, 220, 90, "left")
|
||||||
love.graphics.printf(self.level, text_x, 340, 40, "right")
|
love.graphics.printf(self.level, text_x, 340, 40, "right")
|
||||||
if self.clear then
|
if self.clear then
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ require 'funcs'
|
|||||||
local GameMode = require 'tetris.modes.gamemode'
|
local GameMode = require 'tetris.modes.gamemode'
|
||||||
local Piece = require 'tetris.components.piece'
|
local Piece = require 'tetris.components.piece'
|
||||||
|
|
||||||
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls_35bag'
|
||||||
|
|
||||||
local PhantomMania2Game = GameMode:extend()
|
local PhantomMania2Game = GameMode:extend()
|
||||||
|
|
||||||
@@ -28,7 +28,7 @@ function PhantomMania2Game:new()
|
|||||||
|
|
||||||
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"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -251,7 +251,7 @@ PhantomMania2Game.garbageOpacityFunction = function(age)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function PhantomMania2Game:drawGrid()
|
function PhantomMania2Game:drawGrid()
|
||||||
if not (self.game_over) then
|
if not (self.game_over or self.completed or (self.clear and self.level < 1300)) then
|
||||||
self.grid:drawInvisible(self.rollOpacityFunction, self.garbageOpacityFunction)
|
self.grid:drawInvisible(self.rollOpacityFunction, self.garbageOpacityFunction)
|
||||||
else
|
else
|
||||||
self.grid:draw()
|
self.grid:draw()
|
||||||
|
|||||||
@@ -8,12 +8,6 @@ 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 = {
|
|
||||||
"M1", "M2", "M3", "M4", "M5", "M6", "M7", "M8", "M9",
|
|
||||||
"M10", "M11", "M12", "M13", "M14", "M15", "M16", "M17", "M18",
|
|
||||||
"GM"
|
|
||||||
}
|
|
||||||
|
|
||||||
self.next_queue_length = 3
|
self.next_queue_length = 3
|
||||||
self.enable_hold = true
|
self.enable_hold = true
|
||||||
|
|||||||
155
tetris/modes/race_40.lua
Normal file
155
tetris/modes/race_40.lua
Normal file
@@ -0,0 +1,155 @@
|
|||||||
|
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 = 6
|
||||||
|
end
|
||||||
|
|
||||||
|
function Race40Game:getDropSpeed()
|
||||||
|
return 20
|
||||||
|
end
|
||||||
|
|
||||||
|
function Race40Game:getARR()
|
||||||
|
return config.arr
|
||||||
|
end
|
||||||
|
|
||||||
|
function Race40Game:getARE()
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function Race40Game:getLineARE()
|
||||||
|
return self:getARE()
|
||||||
|
end
|
||||||
|
|
||||||
|
function Race40Game:getDasLimit()
|
||||||
|
return config.das
|
||||||
|
end
|
||||||
|
|
||||||
|
function Race40Game:getLineClearDelay()
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function Race40Game:getLockDelay()
|
||||||
|
return 30
|
||||||
|
end
|
||||||
|
|
||||||
|
function Race40Game:getGravity()
|
||||||
|
return 1/64
|
||||||
|
end
|
||||||
|
|
||||||
|
function Race40Game:getDasCutDelay()
|
||||||
|
return config.dcd
|
||||||
|
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.super: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,585 +0,0 @@
|
|||||||
require 'funcs'
|
|
||||||
|
|
||||||
local GameMode = require 'tetris.modes.gamemode'
|
|
||||||
local Piece = require 'tetris.components.piece'
|
|
||||||
|
|
||||||
local SakuraRandomizer = require 'tetris.randomizers.sakura'
|
|
||||||
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls_35bag'
|
|
||||||
|
|
||||||
local SakuraGame = GameMode:extend()
|
|
||||||
|
|
||||||
SakuraGame.name = "Sakura A3"
|
|
||||||
SakuraGame.hash = "SakuraA3"
|
|
||||||
SakuraGame.tagline = "Clear away the Gem Blocks as fast as possible!"
|
|
||||||
|
|
||||||
local b = {
|
|
||||||
["r"] = { skin = "2tie", colour = "R" },
|
|
||||||
["o"] = { skin = "2tie", colour = "O" },
|
|
||||||
["y"] = { skin = "2tie", colour = "Y" },
|
|
||||||
["g"] = { skin = "2tie", colour = "G" },
|
|
||||||
["c"] = { skin = "2tie", colour = "C" },
|
|
||||||
["b"] = { skin = "2tie", colour = "B" },
|
|
||||||
["m"] = { skin = "2tie", colour = "M" },
|
|
||||||
["R"] = { skin = "gem", colour = "R" },
|
|
||||||
["O"] = { skin = "gem", colour = "O" },
|
|
||||||
["Y"] = { skin = "gem", colour = "Y" },
|
|
||||||
["G"] = { skin = "gem", colour = "G" },
|
|
||||||
["C"] = { skin = "gem", colour = "C" },
|
|
||||||
["B"] = { skin = "gem", colour = "B" },
|
|
||||||
["M"] = { skin = "gem", colour = "M" },
|
|
||||||
}
|
|
||||||
|
|
||||||
local effects = {
|
|
||||||
[4] = "mirror",
|
|
||||||
[8] = "xray",
|
|
||||||
[12] = "color",
|
|
||||||
[13] = "mirror",
|
|
||||||
[16] = "roll",
|
|
||||||
[23] = "big"
|
|
||||||
}
|
|
||||||
|
|
||||||
local maps = {
|
|
||||||
[1] = {
|
|
||||||
[22] = {nil, nil, b.O, b.R, nil, nil, b.M, b.m, nil, nil},
|
|
||||||
[23] = {nil, b.G, b.c, b.c, b.c, b.c, b.c, b.c, b.Y, nil},
|
|
||||||
[24] = {nil, b.C, b.y, b.y, b.y, b.y, b.y, b.y, b.B, nil},
|
|
||||||
},
|
|
||||||
[2] = {
|
|
||||||
[20] = {nil, nil, nil, nil, b.G, b.b, b.b, b.M, nil, nil},
|
|
||||||
[21] = {nil, nil, nil, nil, b.c, b.c, b.c, b.c, nil, nil},
|
|
||||||
[22] = {nil, nil, nil, nil, nil, b.R, b.Y, b.O, nil, nil},
|
|
||||||
[23] = {nil, b.B, b.c, b.c, b.c, b.c, b.c, b.c, b.c, nil},
|
|
||||||
[24] = {nil, b.b, b.b, b.b, b.b, b.b, b.b, b.b, b.C, nil},
|
|
||||||
},
|
|
||||||
[3] = {
|
|
||||||
[20] = {nil, nil, nil, b.R, b.m, b.o, b.M, nil, nil, nil},
|
|
||||||
[21] = {nil, nil, nil, nil, b.o, b.O, nil, nil, nil, nil},
|
|
||||||
[22] = {nil, nil, nil, nil, b.G, b.Y, nil, nil, nil, nil},
|
|
||||||
[23] = {nil, b.m, b.o, b.m, b.o, b.m, b.o, b.m, b.o, nil},
|
|
||||||
[24] = {nil, b.B, b.m, b.o, b.m, b.o, b.m, b.o, b.C, nil},
|
|
||||||
},
|
|
||||||
[4] = {
|
|
||||||
[21] = {nil, nil, b.O, b.g, b.g, b.g, b.g, nil, nil, nil},
|
|
||||||
[22] = {nil, nil, nil, b.R, b.M, b.b, b.b, nil, nil, nil},
|
|
||||||
[23] = {b.G, nil, b.Y, b.g, b.g, b.g, b.g, b.g, nil, nil},
|
|
||||||
[24] = {b.b, b.C, b.b, b.b, b.b, b.b, b.b, b.b, b.B, nil},
|
|
||||||
},
|
|
||||||
[5] = {
|
|
||||||
[16] = {nil, b.B, b.c, b.y, b.c, b.G, b.c, b.y, b.C, nil},
|
|
||||||
[22] = {nil, nil, b.c, b.y, b.c, b.y, b.c, b.y, nil, nil},
|
|
||||||
[23] = {nil, b.O, b.y, b.c, b.y, b.c, b.y, b.c, b.Y, nil},
|
|
||||||
[24] = {nil, b.R, b.c, b.y, b.c, b.y, b.c, b.y, b.M, nil},
|
|
||||||
},
|
|
||||||
[6] = {
|
|
||||||
[21] = {nil, nil, nil, nil, b.O, b.Y, nil, nil, nil, nil},
|
|
||||||
[22] = {nil, nil, b.R, nil, b.b, b.y, nil, b.M, nil, nil},
|
|
||||||
[23] = {nil, nil, nil, nil, b.y, b.b, nil, nil, nil, nil},
|
|
||||||
[24] = {nil, b.G, b.y, b.b, b.C, b.y, b.b, b.y, b.B, nil},
|
|
||||||
},
|
|
||||||
[7] = {
|
|
||||||
[20] = {nil, b.C, b.G, nil, b.r, b.g, b.r, b.g, nil, nil},
|
|
||||||
[21] = {nil, nil, nil, nil, b.R, b.M, b.g, b.r, nil, nil},
|
|
||||||
[22] = {b.r, nil, nil, nil, b.r, b.g, b.O, b.Y, nil, nil},
|
|
||||||
[23] = {b.g, b.r, b.g, b.r, b.g, b.r, b.g, b.r, nil, nil},
|
|
||||||
[24] = {b.r, b.g, b.r, b.g, b.r, b.g, b.r, b.g, b.B, nil},
|
|
||||||
},
|
|
||||||
[8] = {
|
|
||||||
[15] = {nil, nil, nil, b.B, b.m, b.m, b.m, b.m, b.m, b.C},
|
|
||||||
[16] = {nil, nil, nil, nil, nil, nil, nil, nil, nil, b.m},
|
|
||||||
[17] = {nil, nil, nil, nil, nil, nil, nil, nil, nil, b.m},
|
|
||||||
[18] = {nil, b.Y, b.y, b.y, b.y, b.y, b.y, b.y, b.y, b.G},
|
|
||||||
[21] = {b.b, b.b, b.b, b.b, b.b, b.b, b.O, nil, nil, nil},
|
|
||||||
[22] = {b.b, nil, nil, nil, nil, nil, nil, nil, nil, nil},
|
|
||||||
[23] = {b.M, nil, nil, nil, nil, nil, nil, nil, nil, nil},
|
|
||||||
[24] = {b.o, b.o, b.o, b.o, b.o, b.o, b.o, b.o, b.R, nil},
|
|
||||||
},
|
|
||||||
[9] = {
|
|
||||||
[18] = {nil, nil, nil, b.Y, b.m, b.m, b.m, b.m, nil, nil},
|
|
||||||
[19] = {nil, nil, nil, b.c, b.c, b.c, b.c, b.G, nil, nil},
|
|
||||||
[20] = {b.m, b.m, b.m, b.O, b.M, b.R, nil, nil, nil, nil},
|
|
||||||
[21] = {b.c, b.c, b.c, b.c, b.c, b.c, b.c, b.c, nil, nil},
|
|
||||||
[22] = {b.m, b.m, b.m, b.m, b.m, b.m, b.m, b.m, nil, nil},
|
|
||||||
[23] = {b.c, b.c, b.c, b.c, b.c, b.c, b.c, b.c, b.C, nil},
|
|
||||||
[24] = {b.m, b.m, b.m, b.m, b.m, b.m, b.m, b.m, b.B, nil},
|
|
||||||
},
|
|
||||||
[10] = {
|
|
||||||
[18] = {nil, nil, nil, b.C, b.g, b.g, b.B, nil, nil, nil},
|
|
||||||
[19] = {nil, nil, b.G, b.g, b.g, b.g, b.g, b.Y, nil, nil},
|
|
||||||
[20] = {nil, b.M, b.g, b.g, b.g, b.g, b.g, b.g, b.O, nil},
|
|
||||||
[21] = {nil, nil, nil, nil, b.c, nil, nil, nil, nil, nil},
|
|
||||||
[22] = {nil, nil, nil, nil, b.c, nil, nil, nil, nil, nil},
|
|
||||||
[23] = {nil, nil, nil, nil, b.c, nil, b.o, nil, nil, nil},
|
|
||||||
[24] = {nil, nil, nil, nil, b.R, b.o, b.o, nil, nil, nil},
|
|
||||||
},
|
|
||||||
[11] = {
|
|
||||||
[18] = {nil, nil, nil, nil, b.o, b.o, nil, nil, nil, nil},
|
|
||||||
[19] = {nil, nil, nil, nil, b.R, nil, nil, nil, nil, nil},
|
|
||||||
[20] = {nil, nil, nil, nil, b.r, b.O, nil, nil, nil, nil},
|
|
||||||
[21] = {nil, nil, nil, nil, nil, b.M, nil, nil, nil, nil},
|
|
||||||
[22] = {nil, nil, nil, nil, b.o, b.o, nil, nil, nil, nil},
|
|
||||||
[23] = {nil, nil, nil, nil, b.G, b.Y, nil, nil, nil, nil},
|
|
||||||
[24] = {b.C, b.g, b.g, nil, b.o, b.o, nil, b.g, b.g, b.B},
|
|
||||||
},
|
|
||||||
[12] = {
|
|
||||||
[21] = {nil, nil, nil, nil, nil, nil, nil, b.g, b.g, b.Y},
|
|
||||||
[22] = {nil, nil, b.r, b.G, b.r, nil, nil, nil, b.O, b.g},
|
|
||||||
[23] = {nil, b.r, b.C, b.r, b.B, b.r, nil, nil, nil, b.M},
|
|
||||||
[24] = {b.r, b.r, b.r, b.R, b.r, b.r, b.r, nil, nil, nil},
|
|
||||||
},
|
|
||||||
[13] = {
|
|
||||||
[20] = {b.c, nil, nil, nil, nil, nil, nil, nil, nil, b.B},
|
|
||||||
[21] = {b.c, b.c, nil, nil, nil, nil, nil, nil, b.C, b.c},
|
|
||||||
[22] = {b.c, b.c, b.c, nil, nil, nil, nil, b.G, b.c, b.c},
|
|
||||||
[23] = {b.b, b.b, b.b, b.b, nil, nil, b.Y, b.b, b.b, b.b},
|
|
||||||
[24] = {nil, b.M, b.b, b.b, b.b, b.O, b.b, b.b, b.R, nil},
|
|
||||||
},
|
|
||||||
[14] = {
|
|
||||||
[20] = {nil, nil, nil, b.y, b.r, b.y, nil, nil, nil, nil},
|
|
||||||
[21] = {b.R, nil, nil, b.Y, b.y, b.r, b.G, nil, nil, nil},
|
|
||||||
[22] = {nil, nil, nil, b.y, b.r, b.y, b.r, b.y, b.r, b.B},
|
|
||||||
[23] = {nil, nil, nil, nil, nil, nil, nil, b.O, b.y, b.r},
|
|
||||||
[24] = {nil, nil, nil, nil, nil, nil, b.M, b.y, b.r, b.C},
|
|
||||||
},
|
|
||||||
[15] = {
|
|
||||||
[17] = {nil, nil, b.b, nil, nil, nil, nil, b.b, nil, nil},
|
|
||||||
[18] = {nil, nil, b.b, b.y, b.b, b.b, b.y, b.b, nil, nil},
|
|
||||||
[19] = {nil, nil, nil, b.y, b.b, b.b, b.y, nil, nil, nil},
|
|
||||||
[20] = {nil, nil, nil, nil, b.O, b.Y, nil, nil, nil, nil},
|
|
||||||
[22] = {nil, nil, nil, nil, b.M, b.R, nil, nil, nil, nil},
|
|
||||||
[23] = {nil, nil, nil, b.G, b.y, b.y, b.C, nil, nil, nil},
|
|
||||||
[24] = {nil, nil, b.B, b.y, b.y, b.y, b.y, b.y, nil, nil},
|
|
||||||
},
|
|
||||||
[16] = {
|
|
||||||
[18] = {nil, nil, b.O, nil, nil, nil, nil, b.B, nil, nil},
|
|
||||||
[19] = {nil, nil, b.c, nil, nil, b.G, nil, b.c, nil, nil},
|
|
||||||
[20] = {nil, nil, b.c, nil, b.C, b.R, nil, b.c, nil, nil},
|
|
||||||
[21] = {nil, nil, b.c, nil, nil, nil, nil, b.c, nil, nil},
|
|
||||||
[22] = {nil, nil, b.Y, b.c, b.c, b.c, b.c, b.M, nil, nil},
|
|
||||||
},
|
|
||||||
[17] = {
|
|
||||||
[15] = {b.O, nil, nil, b.g, nil, nil, b.m, nil, nil, b.Y},
|
|
||||||
[16] = {nil, nil, nil, b.g, nil, nil, b.m, nil, nil, nil},
|
|
||||||
[17] = {nil, nil, nil, b.g, nil, nil, b.R, nil, nil, nil},
|
|
||||||
[18] = {nil, nil, nil, b.g, nil, nil, b.m, nil, nil, nil},
|
|
||||||
[19] = {nil, nil, nil, b.M, nil, nil, b.m, nil, nil, nil},
|
|
||||||
[20] = {nil, nil, nil, b.g, nil, nil, b.m, nil, nil, nil},
|
|
||||||
[21] = {nil, nil, nil, b.g, nil, nil, b.G, nil, nil, nil},
|
|
||||||
[22] = {nil, nil, nil, b.g, nil, nil, b.m, nil, nil, nil},
|
|
||||||
[23] = {nil, nil, nil, b.g, nil, nil, b.m, nil, nil, nil},
|
|
||||||
[24] = {nil, b.m, b.m, b.m, b.B, b.C, b.g, b.g, b.g, nil},
|
|
||||||
},
|
|
||||||
[18] = {
|
|
||||||
[19] = {nil, nil, nil, b.y, b.B, b.y, b.y, nil, nil, nil},
|
|
||||||
[20] = {nil, nil, b.y, nil, nil, nil, nil, b.y, nil, nil},
|
|
||||||
[21] = {nil, b.o, nil, nil, b.C, b.R, nil, nil, b.O, nil},
|
|
||||||
[22] = {nil, b.M, nil, nil, b.Y, b.G, nil, nil, b.o, nil},
|
|
||||||
[23] = {nil, b.r, b.o, nil, nil, nil, nil, b.o, b.r, nil},
|
|
||||||
[24] = {nil, b.r, b.r, b.o, b.o, b.o, b.o, b.r, b.r, nil},
|
|
||||||
},
|
|
||||||
[19] = {
|
|
||||||
[15] = {nil, nil, nil, nil, nil, nil, b.O, nil, nil, nil},
|
|
||||||
[16] = {nil, nil, nil, nil, nil, b.o, nil, nil, nil, nil},
|
|
||||||
[17] = {nil, nil, nil, nil, b.o, b.r, b.o, nil, nil, nil},
|
|
||||||
[18] = {nil, b.o, nil, nil, b.o, b.r, b.r, b.o, nil, nil},
|
|
||||||
[19] = {nil, b.o, b.o, nil, nil, b.R, b.r, b.r, nil, nil},
|
|
||||||
[20] = {nil, nil, b.M, b.r, nil, b.r, b.r, b.r, b.r, nil},
|
|
||||||
[21] = {nil, nil, b.r, b.r, b.r, b.r, b.y, b.G, b.o, b.o},
|
|
||||||
[22] = {nil, b.r, b.o, b.y, b.Y, b.y, b.y, b.y, b.y, b.o},
|
|
||||||
[23] = {nil, b.o, b.o, b.y, b.y, b.c, b.c, b.c, b.c, b.C},
|
|
||||||
[24] = {nil, nil, b.o, b.y, b.b, b.b, b.B, b.b, b.b, b.b},
|
|
||||||
},
|
|
||||||
[20] = {
|
|
||||||
[20] = {nil, nil, b.B, b.b, b.b, b.b, b.b, b.b, nil, nil},
|
|
||||||
[21] = {b.c, nil, nil, b.C, b.c, b.c, b.c, nil, nil, b.c},
|
|
||||||
[22] = {b.g, b.g, nil, nil, b.G, b.g, nil, nil, b.g, b.g},
|
|
||||||
[23] = {b.y, b.y, b.o, nil, nil, nil, nil, b.Y, b.y, b.y},
|
|
||||||
[24] = {b.r, b.r, b.r, b.R, nil, nil, b.M, b.r, b.r, b.r},
|
|
||||||
},
|
|
||||||
[21] = {
|
|
||||||
[16] = {nil, nil, b.g, b.g, b.g, b.g, b.g, nil, nil, nil},
|
|
||||||
[17] = {nil, b.g, b.g, b.g, b.g, b.g, b.g, b.B, b.g, nil},
|
|
||||||
[18] = {b.g, b.g, b.g, b.g, b.g, b.g, b.g, b.g, b.C, nil},
|
|
||||||
[19] = {b.g, nil, nil, b.g, b.o, b.o, b.g, nil, nil, b.g},
|
|
||||||
[20] = {nil, b.R, nil, b.g, b.o, b.o, nil, b.M, nil, b.G},
|
|
||||||
[21] = {nil, nil, nil, nil, b.o, b.o, nil, nil, nil, nil},
|
|
||||||
[22] = {nil, nil, nil, nil, b.o, b.o, nil, nil, nil, nil},
|
|
||||||
[23] = {nil, nil, nil, nil, b.o, b.o, nil, nil, nil, nil},
|
|
||||||
[24] = {nil, nil, nil, nil, b.Y, b.O, nil, nil, nil, nil},
|
|
||||||
},
|
|
||||||
[22] = {
|
|
||||||
[15] = {nil, nil, b.b, nil, nil, nil, nil, b.b, nil, nil},
|
|
||||||
[16] = {nil, b.b, b.O, b.b, nil, nil, b.b, b.Y, b.b, nil},
|
|
||||||
[17] = {nil, nil, b.b, nil, nil, nil, nil, b.b, nil, nil},
|
|
||||||
[20] = {nil, nil, nil, nil, b.R, b.M, nil, nil, nil, nil},
|
|
||||||
[23] = {nil, nil, nil, b.b, b.C, b.G, b.b, nil, nil, nil},
|
|
||||||
[24] = {nil, nil, nil, b.b, b.b, b.B, b.b, nil, nil, nil},
|
|
||||||
},
|
|
||||||
[23] = {
|
|
||||||
[13] = {nil, nil, nil, nil, nil, nil, nil, nil, b.c, b.m},
|
|
||||||
[14] = {nil, nil, nil, nil, nil, nil, nil, nil, b.y, b.g},
|
|
||||||
[15] = {b.G, b.B, nil, nil, nil, nil, nil, nil, nil, nil},
|
|
||||||
[16] = {b.r, b.O, nil, nil, nil, nil, nil, nil, nil, nil},
|
|
||||||
[23] = {nil, nil, nil, nil, b.C, b.M, nil, nil, nil, nil},
|
|
||||||
[24] = {nil, nil, nil, nil, b.R, b.Y, nil, nil, nil, nil},
|
|
||||||
},
|
|
||||||
[24] = {
|
|
||||||
[20] = {b.g, b.g, b.g, b.g, b.G, nil, nil, nil, nil, nil},
|
|
||||||
[21] = {nil, nil, nil, nil, nil, b.O, b.y, b.y, b.y, b.Y},
|
|
||||||
[23] = {b.M, b.r, b.r, b.r, b.R, nil, nil, nil, nil, nil},
|
|
||||||
[24] = {nil, nil, nil, nil, nil, b.M, b.r, b.r, b.r, b.R},
|
|
||||||
},
|
|
||||||
[25] = {
|
|
||||||
[18] = {nil, nil, nil, nil, nil, b.B, nil, nil, nil, nil},
|
|
||||||
[19] = {nil, nil, nil, b.G, nil, nil, nil, b.C, nil, nil},
|
|
||||||
[20] = {nil, nil, nil, nil, nil, b.Y, nil, nil, nil, nil},
|
|
||||||
[21] = {nil, nil, nil, b.M, nil, nil, nil, b.O, nil, nil},
|
|
||||||
[22] = {nil, nil, nil, nil, nil, b.R, nil, nil, nil, nil},
|
|
||||||
},
|
|
||||||
[26] = {
|
|
||||||
[13] = {nil, nil, nil, nil, b.r, b.r, nil, nil, nil, nil},
|
|
||||||
[14] = {nil, nil, nil, nil, b.o, b.o, nil, nil, nil, nil},
|
|
||||||
[15] = {nil, nil, nil, nil, b.o, b.o, nil, nil, nil, nil},
|
|
||||||
[16] = {nil, nil, nil, nil, b.o, b.o, nil, nil, nil, nil},
|
|
||||||
[17] = {nil, nil, nil, b.O, b.o, b.o, b.Y, nil, nil, nil},
|
|
||||||
[18] = {nil, nil, b.o, b.c, b.c, b.c, b.c, b.o, nil, nil},
|
|
||||||
[19] = {nil, nil, b.o, b.c, b.c, b.c, b.c, b.o, nil, nil},
|
|
||||||
[20] = {nil, nil, b.o, nil, nil, b.G, nil, b.o, nil, nil},
|
|
||||||
[21] = {nil, nil, b.o, nil, b.M, b.R, nil, b.o, nil, nil},
|
|
||||||
[22] = {nil, nil, b.o, b.b, b.b, b.b, b.B, b.o, nil, nil},
|
|
||||||
[23] = {nil, nil, b.o, b.C, b.b, b.b, b.b, b.o, nil, nil},
|
|
||||||
[24] = {nil, nil, b.o, b.o, b.o, b.o, b.o, b.o, nil, nil},
|
|
||||||
},
|
|
||||||
[27] = {
|
|
||||||
[15] = {nil, b.C, b.o, b.g, b.g, b.g, b.g, b.g, b.B, nil},
|
|
||||||
[16] = {b.g, nil, b.y, b.o, b.g, b.g, b.g, b.g, nil, b.y},
|
|
||||||
[17] = {b.g, b.g, nil, b.y, b.o, b.g, b.g, nil, b.y, b.o},
|
|
||||||
[18] = {b.g, b.g, b.g, nil, b.y, b.o, nil, b.y, b.o, b.g},
|
|
||||||
[19] = {b.g, b.g, b.g, b.o, nil, b.G, b.y, b.o, b.g, b.g},
|
|
||||||
[20] = {b.g, b.g, b.o, b.o, b.Y, nil, b.o, b.g, b.g, b.g},
|
|
||||||
[21] = {b.g, b.o, b.y, nil, b.o, b.O, nil, b.g, b.g, b.g},
|
|
||||||
[22] = {b.o, b.y, nil, b.g, b.g, b.o, b.y, nil, b.g, b.g},
|
|
||||||
[23] = {b.y, nil, b.g, b.g, b.g, b.g, b.o, b.y, nil, b.g},
|
|
||||||
[24] = {nil, b.M, b.g, b.g, b.g, b.g, b.g, b.o, b.R, nil},
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
local STAGE_TRANSITION_TIME = 300
|
|
||||||
|
|
||||||
function SakuraGame:new(secret_inputs)
|
|
||||||
self.super:new()
|
|
||||||
|
|
||||||
self.randomizer = (
|
|
||||||
(
|
|
||||||
secret_inputs.rotate_left and secret_inputs.rotate_right
|
|
||||||
) and History6RollsRandomizer() or SakuraRandomizer()
|
|
||||||
)
|
|
||||||
|
|
||||||
self.current_map = 1
|
|
||||||
self.time_limit = 10800
|
|
||||||
self.cleared_frames = STAGE_TRANSITION_TIME
|
|
||||||
self.stage_frames = 0
|
|
||||||
self.time_extend = 0
|
|
||||||
self.maps_cleared = 0
|
|
||||||
self.map_20_time = 0
|
|
||||||
self.stage_pieces = 0
|
|
||||||
self.grid:applyMap(maps[self.current_map])
|
|
||||||
|
|
||||||
self.lock_drop = true
|
|
||||||
self.lock_hard_drop = true
|
|
||||||
self.enable_hold = true
|
|
||||||
self.next_queue_length = 3
|
|
||||||
end
|
|
||||||
|
|
||||||
function SakuraGame:checkRequirements()
|
|
||||||
if self.maps_cleared >= 14 + 2 * (self.current_map - 20) and
|
|
||||||
self.map_20_time <= frameTime(8,00) - frameTime(0,30) * (self.current_map - 20)
|
|
||||||
then
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
function SakuraGame:getGravity()
|
|
||||||
if self.level < 8 then return 4/256
|
|
||||||
elseif self.level < 19 then return 5/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 < 108 then return 4/256
|
|
||||||
elseif self.level < 119 then return 5/256
|
|
||||||
elseif self.level < 125 then return 6/256
|
|
||||||
elseif self.level < 131 then return 8/256
|
|
||||||
elseif self.level < 139 then return 12/256
|
|
||||||
elseif self.level < 149 then return 32/256
|
|
||||||
elseif self.level < 156 then return 48/256
|
|
||||||
elseif self.level < 164 then return 80/256
|
|
||||||
elseif self.level < 174 then return 112/256
|
|
||||||
elseif self.level < 180 then return 128/256
|
|
||||||
elseif self.level < 200 then return 144/256
|
|
||||||
elseif self.level < 212 then return 16/256
|
|
||||||
elseif self.level < 221 then return 48/256
|
|
||||||
elseif self.level < 232 then return 80/256
|
|
||||||
elseif self.level < 244 then return 112/256
|
|
||||||
elseif self.level < 256 then return 144/256
|
|
||||||
elseif self.level < 267 then return 176/256
|
|
||||||
elseif self.level < 277 then return 192/256
|
|
||||||
elseif self.level < 287 then return 208/256
|
|
||||||
elseif self.level < 295 then return 224/256
|
|
||||||
elseif self.level < 300 then return 240/256
|
|
||||||
else return 20 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SakuraGame:onLineClear(cleared_row_count)
|
|
||||||
self.level = self.level + cleared_row_count
|
|
||||||
for i = 13, 24 do
|
|
||||||
for j = 1, 10 do
|
|
||||||
local block = self.grid.grid[i][j]
|
|
||||||
if block and block.skin == "gem" and block.colour == "X" then
|
|
||||||
self.time_limit = self.time_limit + 60
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SakuraGame:onPieceEnter()
|
|
||||||
if self.level % 100 ~= 99 and not self.clear and self.stage_frames ~= 0 then
|
|
||||||
self.level = self.level + 1
|
|
||||||
end
|
|
||||||
if effects[self.current_map] == "mirror" and
|
|
||||||
self.stage_pieces % 3 == 0 and self.stage_pieces ~= 0
|
|
||||||
then
|
|
||||||
self.grid:mirror()
|
|
||||||
end
|
|
||||||
self.stage_pieces = self.stage_pieces + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
function SakuraGame:advanceOneFrame(inputs, ruleset)
|
|
||||||
if self.ready_frames == 0 then
|
|
||||||
if self.lcd > 0 then
|
|
||||||
if self.stage_frames <= frameTime(0,10) then self.time_extend = 600
|
|
||||||
elseif self.stage_frames <= frameTime(0,30) then self.time_extend = 300
|
|
||||||
else self.time_extend = 0 end
|
|
||||||
end
|
|
||||||
|
|
||||||
if not self.grid:hasGemBlocks() or
|
|
||||||
(self.stage_frames >= 3600 and self.current_map <= 20) then
|
|
||||||
self.lcd = 0
|
|
||||||
self.are = 0
|
|
||||||
if self.stage_frames >= 3600 then self.time_extend = 0 end
|
|
||||||
self.piece = nil
|
|
||||||
|
|
||||||
-- transition to next map
|
|
||||||
if self.cleared_frames > 0 then
|
|
||||||
self.cleared_frames = self.cleared_frames - 1
|
|
||||||
if self.time_extend > 0 then
|
|
||||||
self.time_limit = self.time_limit + 3
|
|
||||||
self.time_extend = self.time_extend - 3
|
|
||||||
end
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
|
|
||||||
self.hold_queue = nil
|
|
||||||
if self.current_map > 20 or (self.stage_frames < 3600 and self.current_map <= 20) then self.maps_cleared = self.maps_cleared + 1 end
|
|
||||||
self.stage_frames = -1
|
|
||||||
self.level = 0
|
|
||||||
self.grid:clear()
|
|
||||||
if (self.current_map == 20) then self.map_20_time = self.frames end
|
|
||||||
if self.current_map >= 20 and self:checkRequirements() then
|
|
||||||
self.clear = true
|
|
||||||
self.completed = true
|
|
||||||
return false
|
|
||||||
else
|
|
||||||
self.current_map = self.current_map + 1
|
|
||||||
self.big_mode = effects[self.current_map] == "big"
|
|
||||||
self.ready_frames = 100
|
|
||||||
self.stage_pieces = 0
|
|
||||||
self.grid:applyMap(maps[self.current_map])
|
|
||||||
end
|
|
||||||
|
|
||||||
-- this is necessary to fix timer
|
|
||||||
self.frames = self.frames - 1
|
|
||||||
self.time_limit = self.time_limit + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
self.frames = self.frames + 1
|
|
||||||
self.stage_frames = self.stage_frames + 1
|
|
||||||
self.time_limit = math.max(self.time_limit - 1, 0)
|
|
||||||
if self.time_limit <= 0 and self.piece == nil then
|
|
||||||
self.game_over = true
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.piece ~= nil and
|
|
||||||
effects[self.current_map] == "roll" and
|
|
||||||
self.stage_pieces % 4 == 0
|
|
||||||
then
|
|
||||||
self.piece.colour = "F"
|
|
||||||
if self.stage_frames % 30 == 0 then
|
|
||||||
ruleset:attemptRotate(
|
|
||||||
{[config.gamesettings.world_reverse == 3 or
|
|
||||||
(ruleset.world and config.gamesettings.world_reverse == 2)
|
|
||||||
and "rotate_left" or "rotate_right"] = true},
|
|
||||||
self.piece, self.grid, false
|
|
||||||
)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
else
|
|
||||||
self.cleared_frames = STAGE_TRANSITION_TIME
|
|
||||||
if not self.prev_inputs.hold and inputs.hold then
|
|
||||||
self.hold_queue = table.remove(self.next_queue, 1)
|
|
||||||
table.insert(self.next_queue, self:getNextPiece(ruleset))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
function SakuraGame:onGameComplete() end
|
|
||||||
|
|
||||||
local function colourXRay(game, block, x, y, age)
|
|
||||||
local r, g, b, a = .5,.5,.5
|
|
||||||
if ((game.stage_frames/2 - x) % 30 < 1)
|
|
||||||
or game.stage_frames == 0
|
|
||||||
or game.cleared_frames ~= STAGE_TRANSITION_TIME
|
|
||||||
or game.stage_pieces % 2 == 0
|
|
||||||
then
|
|
||||||
a = 1
|
|
||||||
else
|
|
||||||
a = 1 - age / 4
|
|
||||||
end
|
|
||||||
return r, g, b, a, a
|
|
||||||
end
|
|
||||||
|
|
||||||
local function colourColor(game, block, x, y, age)
|
|
||||||
local r, g, b, a = .5,.5,.5
|
|
||||||
if game.stage_frames == 0 or game.cleared_frames ~= STAGE_TRANSITION_TIME then
|
|
||||||
a = 1
|
|
||||||
else
|
|
||||||
a = (game.stage_frames/30 + (y + math.abs(x-5.5))/5) % 1
|
|
||||||
end
|
|
||||||
return r, g, b, a, 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function SakuraGame:drawGrid()
|
|
||||||
if effects[self.current_map] == "xray" then
|
|
||||||
self.grid:drawCustom(colourXRay, self)
|
|
||||||
elseif effects[self.current_map] == "color" then
|
|
||||||
self.grid:drawCustom(colourColor, self)
|
|
||||||
else
|
|
||||||
self.grid:draw()
|
|
||||||
end
|
|
||||||
if self.piece ~= nil and self.level < 100 then
|
|
||||||
self:drawGhostPiece()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SakuraGame: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("STAGE", 240, 120, 80, "left")
|
|
||||||
love.graphics.printf("TIME LIMIT", 240, 180, 80, "left")
|
|
||||||
love.graphics.printf("LEVEL", 240, 320, 40, "left")
|
|
||||||
if self.current_map <= 20 then
|
|
||||||
love.graphics.printf("STAGE LIMIT", 240, 240, 100, "left")
|
|
||||||
end
|
|
||||||
if effects[self.current_map] then
|
|
||||||
love.graphics.printf("EFFECT: " .. effects[self.current_map], 240, 300, 160, "left")
|
|
||||||
end
|
|
||||||
if self.used_randomizer.history then
|
|
||||||
love.graphics.printf("RANDOM PIECES ACTIVE!", 240, 150, 200, "left")
|
|
||||||
end
|
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
|
||||||
love.graphics.setColor(
|
|
||||||
(self.time_limit % 4 < 2 and
|
|
||||||
self.time_limit <= frameTime(0,10) and
|
|
||||||
self.grid:hasGemBlocks() and
|
|
||||||
self.time_limit ~= 0 and
|
|
||||||
self.ready_frames == 0) and
|
|
||||||
{ 1, 0.3, 0.3, 1 } or
|
|
||||||
{ 1, 1, 1, 1 }
|
|
||||||
)
|
|
||||||
love.graphics.printf(formatTime(self.time_limit), 240, 200, 120, "left")
|
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
|
||||||
if self.current_map <= 20 then
|
|
||||||
love.graphics.printf(formatTime(3600 - self.stage_frames), 240, 260, 120, "left")
|
|
||||||
end
|
|
||||||
love.graphics.printf(self.level, 240, 340, 40, "right")
|
|
||||||
love.graphics.printf(math.floor((self.level + 100) / 100) * 100, 240, 370, 40, "right")
|
|
||||||
|
|
||||||
love.graphics.setFont(font_8x11)
|
|
||||||
love.graphics.printf(formatTime(self.frames), 64, 420, 160, "center")
|
|
||||||
love.graphics.printf(self.current_map, 290, 110, 80, "left")
|
|
||||||
end
|
|
||||||
|
|
||||||
function SakuraGame:drawCustom()
|
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
|
||||||
|
|
||||||
if self.ready_frames ~= 0 and not self.clear then
|
|
||||||
love.graphics.setFont(font_3x5_4)
|
|
||||||
love.graphics.printf("STAGE " .. self.current_map, 64, 170, 160, "center")
|
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
|
||||||
if effects[self.current_map] then
|
|
||||||
love.graphics.printf("EFFECT: " .. effects[self.current_map], 64, 270, 160, "center")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.cleared_frames > 0 and
|
|
||||||
(not self.grid:hasGemBlocks() or
|
|
||||||
(self.stage_frames >= 3600 and self.current_map <= 20)) then
|
|
||||||
love.graphics.setFont(font_3x5_2)
|
|
||||||
love.graphics.printf("TIME LIMIT", 64, 180, 160, "center")
|
|
||||||
love.graphics.printf("TIME EXTEND", 64, 240, 160, "center")
|
|
||||||
love.graphics.printf("STAGE TIME", 64, 300, 160, "center")
|
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
|
||||||
love.graphics.printf("STAGE " .. self.current_map, 64, 100, 160, "center")
|
|
||||||
love.graphics.setColor(
|
|
||||||
self.cleared_frames % 4 < 2 and
|
|
||||||
{ 1, 1, 0.3, 1 } or
|
|
||||||
{ 1, 1, 1, 1 }
|
|
||||||
)
|
|
||||||
love.graphics.printf(formatTime(self.time_limit), 64, 200, 160, "center")
|
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
|
||||||
love.graphics.printf(formatTime(self.time_extend), 64, 260, 160, "center")
|
|
||||||
love.graphics.printf(formatTime(self.stage_frames), 64, 320, 160, "center")
|
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_4)
|
|
||||||
love.graphics.printf((self.stage_frames >= 3600 and self.current_map <= 20) and "" or "CLEAR!", 64, 130, 160, "center")
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.clear then
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
|
||||||
love.graphics.printf("EXCELLENT!", 64, 180, 160, "center")
|
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_2)
|
|
||||||
if self.current_map ~= 27 then
|
|
||||||
love.graphics.printf("...but let's go\nbetter next time", 64, 220, 160, "center")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SakuraGame:getBackground()
|
|
||||||
return (self.current_map - 1) % 20
|
|
||||||
end
|
|
||||||
|
|
||||||
function SakuraGame:getHighscoreData()
|
|
||||||
return {
|
|
||||||
maps = self.maps_cleared,
|
|
||||||
current_map = self.current_map,
|
|
||||||
frames = self.frames,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
return SakuraGame
|
|
||||||
@@ -52,23 +52,14 @@ function StrategyGame:getLineClearDelay()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function StrategyGame:getLockDelay()
|
function StrategyGame:getLockDelay()
|
||||||
if self.level < 500 then return 8
|
if self.level < 700 then return 8
|
||||||
elseif self.level < 700 then return 6
|
else return 6 end
|
||||||
else return 4 end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function StrategyGame:getGravity()
|
function StrategyGame:getGravity()
|
||||||
return 20
|
return 20
|
||||||
end
|
end
|
||||||
|
|
||||||
function StrategyGame:getNextPiece(ruleset)
|
|
||||||
return {
|
|
||||||
skin = "2tie",
|
|
||||||
shape = self.randomizer:nextPiece(),
|
|
||||||
orientation = ruleset:getDefaultOrientation(),
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
function StrategyGame:advanceOneFrame()
|
function StrategyGame:advanceOneFrame()
|
||||||
if self.clear then
|
if self.clear then
|
||||||
self.roll_frames = self.roll_frames + 1
|
self.roll_frames = self.roll_frames + 1
|
||||||
|
|||||||
@@ -94,12 +94,8 @@ function Survival2020Game:getGravity()
|
|||||||
return 20
|
return 20
|
||||||
end
|
end
|
||||||
|
|
||||||
function Survival2020Game:getNextPiece(ruleset)
|
function Survival2020Game:getSkin()
|
||||||
return {
|
return self.level >= 1000 and "bone" or "2tie"
|
||||||
skin = self.level >= 1000 and "bone" or "2tie",
|
|
||||||
shape = self.randomizer:nextPiece(),
|
|
||||||
orientation = ruleset:getDefaultOrientation(),
|
|
||||||
}
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function Survival2020Game:hitTorikan(old_level, new_level)
|
function Survival2020Game:hitTorikan(old_level, new_level)
|
||||||
|
|||||||
@@ -1,218 +1,18 @@
|
|||||||
require 'funcs'
|
require 'funcs'
|
||||||
|
|
||||||
local GameMode = require 'tetris.modes.gamemode'
|
local MarathonA1Game = require 'tetris.modes.marathon_a1'
|
||||||
local Piece = require 'tetris.components.piece'
|
local Piece = require 'tetris.components.piece'
|
||||||
|
|
||||||
local History4RollsRandomizer = require 'tetris.randomizers.history_4rolls'
|
local History4RollsRandomizer = require 'tetris.randomizers.history_4rolls'
|
||||||
|
|
||||||
local SurvivalA1Game = GameMode:extend()
|
local SurvivalA1Game = MarathonA1Game:extend()
|
||||||
|
|
||||||
SurvivalA1Game.name = "Survival A1"
|
SurvivalA1Game.name = "Survival A1"
|
||||||
SurvivalA1Game.hash = "SurvivalA1"
|
SurvivalA1Game.hash = "SurvivalA1"
|
||||||
SurvivalA1Game.tagline = "The game starts fast and only gets faster!"
|
SurvivalA1Game.tagline = "A constant high-speed marathon!"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function SurvivalA1Game:new()
|
|
||||||
SurvivalA1Game.super:new()
|
|
||||||
|
|
||||||
self.roll_frames = 0
|
|
||||||
self.combo = 1
|
|
||||||
self.bravos = 0
|
|
||||||
|
|
||||||
self.gm_conditions = {
|
|
||||||
level300 = false,
|
|
||||||
level500 = false,
|
|
||||||
level999 = false
|
|
||||||
}
|
|
||||||
|
|
||||||
self.SGnames = {
|
|
||||||
"9", "8", "7", "6", "5", "4", "3", "2", "1",
|
|
||||||
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
|
|
||||||
"GM"
|
|
||||||
}
|
|
||||||
|
|
||||||
self.randomizer = History4RollsRandomizer()
|
|
||||||
|
|
||||||
self.lock_drop = false
|
|
||||||
self.enable_hard_drop = false
|
|
||||||
self.enable_hold = false
|
|
||||||
self.next_queue_length = 1
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalA1Game:getARE()
|
|
||||||
return 30
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalA1Game:getLineARE()
|
|
||||||
return 27
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalA1Game:getDasLimit()
|
|
||||||
return 15
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalA1Game:getLineClearDelay()
|
|
||||||
return 44
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalA1Game:getLockDelay()
|
|
||||||
return 30
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalA1Game:getGravity()
|
function SurvivalA1Game:getGravity()
|
||||||
return 20
|
return 20
|
||||||
end
|
end
|
||||||
|
|
||||||
local function getRankForScore(score)
|
|
||||||
if score < 400 then return {rank = "9", next = 400}
|
|
||||||
elseif score < 800 then return {rank = "8", next = 800}
|
|
||||||
elseif score < 1400 then return {rank = "7", next = 1400}
|
|
||||||
elseif score < 2000 then return {rank = "6", next = 2000}
|
|
||||||
elseif score < 3500 then return {rank = "5", next = 3500}
|
|
||||||
elseif score < 5500 then return {rank = "4", next = 5500}
|
|
||||||
elseif score < 8000 then return {rank = "3", next = 8000}
|
|
||||||
elseif score < 12000 then return {rank = "2", next = 12000}
|
|
||||||
elseif score < 16000 then return {rank = "1", next = 16000}
|
|
||||||
elseif score < 22000 then return {rank = "S1", next = 22000}
|
|
||||||
elseif score < 30000 then return {rank = "S2", next = 30000}
|
|
||||||
elseif score < 40000 then return {rank = "S3", next = 40000}
|
|
||||||
elseif score < 52000 then return {rank = "S4", next = 52000}
|
|
||||||
elseif score < 66000 then return {rank = "S5", next = 66000}
|
|
||||||
elseif score < 82000 then return {rank = "S6", next = 82000}
|
|
||||||
elseif score < 100000 then return {rank = "S7", next = 100000}
|
|
||||||
elseif score < 120000 then return {rank = "S8", next = 120000}
|
|
||||||
else return {rank = "S9", next = "???"}
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalA1Game: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
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalA1Game: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 SurvivalA1Game:onLineClear(cleared_row_count)
|
|
||||||
self:checkGMRequirements(self.level, self.level + cleared_row_count)
|
|
||||||
if not self.clear then
|
|
||||||
local new_level = math.min(self.level + cleared_row_count, 999)
|
|
||||||
if new_level == 999 then
|
|
||||||
self.clear = true
|
|
||||||
else
|
|
||||||
self.level = new_level
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalA1Game:updateScore(level, drop_bonus, cleared_lines)
|
|
||||||
if not self.clear then
|
|
||||||
if self.grid:checkForBravo(cleared_lines) then
|
|
||||||
self.bravo = 4
|
|
||||||
self.bravos = self.bravos + 1
|
|
||||||
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 SurvivalA1Game:checkGMRequirements(old_level, new_level)
|
|
||||||
if old_level < 300 and new_level >= 300 then
|
|
||||||
if self.score >= 12000 and self.frames <= frameTime(4,15) then
|
|
||||||
self.gm_conditions["level300"] = true
|
|
||||||
end
|
|
||||||
elseif old_level < 500 and new_level >= 500 then
|
|
||||||
if self.score >= 40000 and self.frames <= frameTime(7,30) then
|
|
||||||
self.gm_conditions["level500"] = true
|
|
||||||
end
|
|
||||||
elseif old_level < 999 and new_level >= 999 then
|
|
||||||
if self.score >= 126000 and self.frames <= frameTime(13,30) then
|
|
||||||
self.gm_conditions["level999"] = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalA1Game:drawGrid()
|
|
||||||
self.grid:draw()
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalA1Game:drawScoringInfo()
|
|
||||||
SurvivalA1Game.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("GRADE", 240, 120, 40, "left")
|
|
||||||
love.graphics.printf("SCORE", 240, 200, 40, "left")
|
|
||||||
love.graphics.printf("NEXT RANK", 240, 260, 90, "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
|
|
||||||
|
|
||||||
if self.bravos > 0 then love.graphics.printf("BRAVO", 300, 120, 40, "left") end
|
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
|
||||||
love.graphics.printf(self.score, 240, 220, 90, "left")
|
|
||||||
if self.gm_conditions["level300"] and self.gm_conditions["level500"] and self.gm_conditions["level999"] then
|
|
||||||
love.graphics.printf("GM", 240, 140, 90, "left")
|
|
||||||
else
|
|
||||||
love.graphics.printf(getRankForScore(self.score).rank, 240, 140, 90, "left")
|
|
||||||
end
|
|
||||||
love.graphics.printf(getRankForScore(self.score).next, 240, 280, 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
|
|
||||||
if self.bravos > 0 then love.graphics.printf(self.bravos, 300, 140, 40, "left") end
|
|
||||||
|
|
||||||
love.graphics.setFont(font_8x11)
|
|
||||||
love.graphics.printf(formatTime(self.frames), 64, 420, 160, "center")
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalA1Game:getSectionEndLevel()
|
|
||||||
if self.level >= 900 then return 999
|
|
||||||
else return math.floor(self.level / 100 + 1) * 100 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalA1Game:getBackground()
|
|
||||||
return math.floor(self.level / 100)
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalA1Game:getHighscoreData()
|
|
||||||
return {
|
|
||||||
grade = self.grade,
|
|
||||||
score = self.score,
|
|
||||||
level = self.level,
|
|
||||||
frames = self.frames,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
return SurvivalA1Game
|
return SurvivalA1Game
|
||||||
|
|||||||
@@ -79,7 +79,7 @@ end
|
|||||||
function SurvivalA2Game:advanceOneFrame()
|
function SurvivalA2Game:advanceOneFrame()
|
||||||
if self.clear then
|
if self.clear then
|
||||||
self.roll_frames = self.roll_frames + 1
|
self.roll_frames = self.roll_frames + 1
|
||||||
if self.roll_frames > 2968 then
|
if self.roll_frames > 1800 then
|
||||||
self.completed = true
|
self.completed = true
|
||||||
end
|
end
|
||||||
elseif self.ready_frames == 0 then
|
elseif self.ready_frames == 0 then
|
||||||
|
|||||||
@@ -24,7 +24,7 @@ function SurvivalA3Game:new()
|
|||||||
|
|
||||||
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"
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -38,11 +38,9 @@ function SurvivalA3Game:new()
|
|||||||
end
|
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)
|
GameMode.initialize(self, ruleset)
|
||||||
-- ^ notice the . here instead of the :
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function SurvivalA3Game:getARE()
|
function SurvivalA3Game:getARE()
|
||||||
@@ -239,7 +237,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.level >= 1300 and self.clear then love.graphics.setColor(0, 1, 0, 1) end
|
elseif self.level >= 1300 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")
|
||||||
|
|||||||
@@ -15,7 +15,6 @@ SurvivalAXGame.tagline = "Can you clear the time hurdles when the game goes this
|
|||||||
function SurvivalAXGame:new()
|
function SurvivalAXGame:new()
|
||||||
SurvivalAXGame.super:new()
|
SurvivalAXGame.super:new()
|
||||||
|
|
||||||
self.roll_frames = 0
|
|
||||||
self.randomizer = Bag7NoSZOStartRandomizer()
|
self.randomizer = Bag7NoSZOStartRandomizer()
|
||||||
|
|
||||||
self.section_time_limit = 3600
|
self.section_time_limit = 3600
|
||||||
@@ -75,14 +74,7 @@ function SurvivalAXGame:getSection()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function SurvivalAXGame:advanceOneFrame()
|
function SurvivalAXGame:advanceOneFrame()
|
||||||
if self.clear then
|
if self.ready_frames == 0 then
|
||||||
self.roll_frames = self.roll_frames + 1
|
|
||||||
if self.roll_frames < 0 then
|
|
||||||
return false
|
|
||||||
elseif self.roll_frames > 2968 then
|
|
||||||
self.completed = true
|
|
||||||
end
|
|
||||||
elseif self.ready_frames == 0 then
|
|
||||||
if not self.section_clear then
|
if not self.section_clear then
|
||||||
self.frames = self.frames + 1
|
self.frames = self.frames + 1
|
||||||
end
|
end
|
||||||
@@ -101,7 +93,7 @@ function SurvivalAXGame:onLineClear(cleared_row_count)
|
|||||||
if self.lines == 150 then
|
if self.lines == 150 then
|
||||||
self.grid:clear()
|
self.grid:clear()
|
||||||
self.clear = true
|
self.clear = true
|
||||||
self.roll_frames = -150
|
self.completed = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ local BagRandomizer = Randomizer:extend()
|
|||||||
|
|
||||||
function BagRandomizer:new(pieces)
|
function BagRandomizer:new(pieces)
|
||||||
self.bag = {}
|
self.bag = {}
|
||||||
|
self.possible_pieces = pieces
|
||||||
self.pieces = pieces
|
self.pieces = pieces
|
||||||
for i = 1, self.pieces do
|
for i = 1, self.pieces do
|
||||||
table.insert(self.bag, i)
|
table.insert(self.bag, i)
|
||||||
|
|||||||
@@ -28,11 +28,8 @@ 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"}
|
index = math.random(20)
|
||||||
repeat
|
x = self.pool[index]
|
||||||
index = math.random(#self.pool)
|
|
||||||
x = self.pool[index]
|
|
||||||
until not inHistory(x, prevent)
|
|
||||||
self.first = false
|
self.first = false
|
||||||
else
|
else
|
||||||
for i = 1, 6 do
|
for i = 1, 6 do
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
local Piece = require 'tetris.components.piece'
|
local Piece = require 'tetris.components.piece'
|
||||||
local Ruleset = require 'tetris.rulesets.arika_ti'
|
local Ruleset = require 'tetris.rulesets.arika_ace2'
|
||||||
|
|
||||||
local ARS = Ruleset:extend()
|
local ARS = Ruleset:extend()
|
||||||
|
|
||||||
@@ -18,40 +18,5 @@ ARS.colourscheme = {
|
|||||||
|
|
||||||
ARS.softdrop_lock = false
|
ARS.softdrop_lock = false
|
||||||
ARS.harddrop_lock = true
|
ARS.harddrop_lock = true
|
||||||
ARS.spawn_above_field = true
|
|
||||||
|
|
||||||
function ARS:onPieceCreate(piece, grid)
|
|
||||||
piece.floorkick = 0
|
|
||||||
piece.manipulations = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function ARS:onPieceMove(piece, grid)
|
|
||||||
piece.lock_delay = 0 -- move reset
|
|
||||||
if piece:isDropBlocked(grid) then
|
|
||||||
piece.manipulations = piece.manipulations + 1
|
|
||||||
if piece.manipulations >= 128 then
|
|
||||||
piece:dropToBottom(grid)
|
|
||||||
piece.locked = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function ARS:onPieceRotate(piece, grid)
|
|
||||||
piece.lock_delay = 0 -- rotate reset
|
|
||||||
if piece:isDropBlocked(grid) then
|
|
||||||
piece.manipulations = piece.manipulations + 1
|
|
||||||
if piece.manipulations >= 128 then
|
|
||||||
piece:dropToBottom(grid)
|
|
||||||
piece.locked = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
if piece.floorkick >= 1 then
|
|
||||||
piece.floorkick = piece.floorkick + 1
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function ARS:get180RotationValue() return 3 end
|
|
||||||
|
|
||||||
function ARS:getDefaultOrientation() return 3 end -- downward facing pieces by default
|
|
||||||
|
|
||||||
return ARS
|
return ARS
|
||||||
|
|||||||
@@ -7,11 +7,84 @@ ARS.name = "ACE-ARS2"
|
|||||||
ARS.hash = "ArikaACE2"
|
ARS.hash = "ArikaACE2"
|
||||||
ARS.spawn_above_field = true
|
ARS.spawn_above_field = true
|
||||||
|
|
||||||
|
function ARS: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
|
||||||
|
) then
|
||||||
|
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
|
||||||
|
if offset.x == 0 then
|
||||||
|
return
|
||||||
|
else
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if piece.shape == "I" then
|
||||||
|
-- special kick rules for I
|
||||||
|
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
|
||||||
|
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) 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)
|
||||||
|
elseif grid:canPlacePiece(new_piece:withOffset({x=0, y=-2})) then
|
||||||
|
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-2})
|
||||||
|
self:onPieceRotate(piece, grid)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- kick right, kick 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=-1, y=0})) then
|
||||||
|
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
|
||||||
|
self:onPieceRotate(piece, grid)
|
||||||
|
elseif piece.shape == "T"
|
||||||
|
and new_piece.rotation == 0
|
||||||
|
and piece:isDropBlocked(grid)
|
||||||
|
and grid:canPlacePiece(new_piece:withOffset({x=0, y=-1}))
|
||||||
|
then
|
||||||
|
-- T floorkick
|
||||||
|
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
|
||||||
|
self:onPieceRotate(piece, grid)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
function ARS:onPieceCreate(piece, grid)
|
function ARS:onPieceCreate(piece, grid)
|
||||||
piece.floorkick = 0
|
|
||||||
piece.manipulations = 0
|
piece.manipulations = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function ARS:onPieceDrop(piece, grid)
|
||||||
|
piece.lock_delay = 0
|
||||||
|
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
|
||||||
@@ -32,9 +105,6 @@ function ARS:onPieceRotate(piece, grid)
|
|||||||
piece.locked = true
|
piece.locked = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if piece.floorkick >= 1 then
|
|
||||||
piece.floorkick = piece.floorkick + 1
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function ARS:get180RotationValue() return 3 end
|
function ARS:get180RotationValue() return 3 end
|
||||||
|
|||||||
@@ -21,14 +21,18 @@ SRS.spawn_above_field = true
|
|||||||
|
|
||||||
SRS.MANIPULATIONS_MAX = 128
|
SRS.MANIPULATIONS_MAX = 128
|
||||||
|
|
||||||
function SRS:onPieceRotate(piece, grid)
|
function SRS:onPieceRotate(piece, grid, upward)
|
||||||
piece.lock_delay = 0 -- rotate reset
|
piece.lock_delay = 0 -- rotate reset
|
||||||
if piece:isDropBlocked(grid) then
|
if upward or piece:isDropBlocked(grid) then
|
||||||
piece.manipulations = piece.manipulations + 1
|
piece.manipulations = piece.manipulations + 1
|
||||||
if piece.manipulations >= self.MANIPULATIONS_MAX then
|
if piece.manipulations >= self.MANIPULATIONS_MAX and piece:isDropBlocked(grid) then
|
||||||
piece.locked = true
|
piece.locked = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function SRS:canPieceRotate(piece)
|
||||||
|
return piece.manipulations < self.MANIPULATIONS_MAX
|
||||||
|
end
|
||||||
|
|
||||||
return SRS
|
return SRS
|
||||||
|
|||||||
@@ -38,35 +38,35 @@ function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|||||||
(piece:isMoveBlocked(grid, {x=-1, y=0}) or piece:isMoveBlocked(grid, {x=1, y=0})) then
|
(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
|
||||||
self:onPieceRotate(piece, grid)
|
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
|
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
|
||||||
|
self:onPieceRotate(piece, grid)
|
||||||
elseif grid:canPlacePiece(new_piece:withOffset({x=2, y=0})) then
|
elseif grid:canPlacePiece(new_piece:withOffset({x=2, y=0})) then
|
||||||
self:onPieceRotate(piece, grid)
|
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=2, y=0})
|
piece:setRelativeRotation(rot_dir):setOffset({x=2, y=0})
|
||||||
elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then
|
|
||||||
self:onPieceRotate(piece, grid)
|
self:onPieceRotate(piece, grid)
|
||||||
|
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})
|
||||||
|
self:onPieceRotate(piece, grid)
|
||||||
end
|
end
|
||||||
elseif piece:isDropBlocked(grid) and (new_piece.rotation == 1 or new_piece.rotation == 3) and piece.floorkick == 0 then
|
elseif piece:isDropBlocked(grid) and (new_piece.rotation == 1 or new_piece.rotation == 3) and piece.floorkick == 0 then
|
||||||
-- kick up, up2
|
-- kick up, up2
|
||||||
if grid:canPlacePiece(new_piece:withOffset({x=0, y=-1})) then
|
if grid:canPlacePiece(new_piece:withOffset({x=0, y=-1})) then
|
||||||
self:onPieceRotate(piece, grid)
|
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
|
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
|
||||||
piece.floorkick = 1
|
piece.floorkick = 1
|
||||||
|
self:onPieceRotate(piece, grid, true)
|
||||||
elseif grid:canPlacePiece(new_piece:withOffset({x=0, y=-2})) then
|
elseif grid:canPlacePiece(new_piece:withOffset({x=0, y=-2})) then
|
||||||
self:onPieceRotate(piece, grid)
|
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-2})
|
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-2})
|
||||||
piece.floorkick = 1
|
piece.floorkick = 1
|
||||||
|
self:onPieceRotate(piece, grid, true)
|
||||||
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
|
||||||
self:onPieceRotate(piece, grid)
|
|
||||||
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
|
|
||||||
self:onPieceRotate(piece, grid)
|
self:onPieceRotate(piece, grid)
|
||||||
|
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})
|
||||||
|
self:onPieceRotate(piece, grid)
|
||||||
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
|
||||||
@@ -75,8 +75,8 @@ function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|||||||
then
|
then
|
||||||
-- T floorkick
|
-- T floorkick
|
||||||
piece.floorkick = piece.floorkick + 1
|
piece.floorkick = piece.floorkick + 1
|
||||||
self:onPieceRotate(piece, grid)
|
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
|
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
|
||||||
|
self:onPieceRotate(piece, grid, true)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -93,8 +93,10 @@ function ARS:onPieceDrop(piece, grid)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function ARS:onPieceRotate(piece, grid)
|
function ARS:onPieceRotate(piece, grid, floorkick)
|
||||||
if piece.floorkick >= 1 then
|
if piece.floorkick >= 2 and piece:isDropBlocked(grid) then
|
||||||
|
piece.locked = true
|
||||||
|
elseif piece.floorkick >= 1 and not floorkick then
|
||||||
piece.floorkick = piece.floorkick + 1
|
piece.floorkick = piece.floorkick + 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -375,7 +375,10 @@ end
|
|||||||
|
|
||||||
function CRS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
function CRS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||||
|
|
||||||
if piece.shape == "O" then return end
|
if piece.shape == "O" then
|
||||||
|
self:onPieceRotate(piece, grid)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
|
||||||
local kicks = CRS.wallkicks[piece.shape][piece:isDropBlocked(grid)][piece.rotation][new_piece.rotation]
|
local kicks = CRS.wallkicks[piece.shape][piece:isDropBlocked(grid)][piece.rotation][new_piece.rotation]
|
||||||
|
|
||||||
@@ -384,9 +387,9 @@ function CRS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|||||||
for idx, offset in pairs(kicks) do
|
for idx, offset in pairs(kicks) do
|
||||||
kicked_piece = new_piece:withOffset(offset)
|
kicked_piece = new_piece:withOffset(offset)
|
||||||
if grid:canPlacePiece(kicked_piece) then
|
if grid:canPlacePiece(kicked_piece) then
|
||||||
self:onPieceRotate(piece, grid)
|
|
||||||
piece:setRelativeRotation(rot_dir)
|
piece:setRelativeRotation(rot_dir)
|
||||||
piece:setOffset(offset)
|
piece:setOffset(offset)
|
||||||
|
self:onPieceRotate(piece, grid)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,275 +0,0 @@
|
|||||||
local Ruleset = require 'tetris.rulesets.ruleset'
|
|
||||||
|
|
||||||
local PAIRS = Ruleset:extend()
|
|
||||||
|
|
||||||
PAIRS.name = "PAIRS"
|
|
||||||
PAIRS.hash = "PAIRS"
|
|
||||||
PAIRS.world = true
|
|
||||||
|
|
||||||
PAIRS.spawn_positions = {
|
|
||||||
[1] = { x=4, y=4 },
|
|
||||||
[2] = { x=4, y=5 },
|
|
||||||
[3] = { x=4, y=5 },
|
|
||||||
[4] = { x=4, y=5 },
|
|
||||||
[5] = { x=5, y=5 },
|
|
||||||
[6] = { x=5, y=5 },
|
|
||||||
[7] = { x=5, y=5 },
|
|
||||||
[8] = { x=5, y=5 },
|
|
||||||
[9] = { x=5, y=5 },
|
|
||||||
[10] = { x=5, y=5 },
|
|
||||||
[11] = { x=4, y=5 },
|
|
||||||
[12] = { x=4, y=5 },
|
|
||||||
[13] = { x=4, y=5 },
|
|
||||||
[14] = { x=4, y=5 },
|
|
||||||
[15] = { x=4, y=5 },
|
|
||||||
[16] = { x=4, y=5 },
|
|
||||||
[17] = { x=4, y=5 },
|
|
||||||
[18] = { x=4, y=5 },
|
|
||||||
}
|
|
||||||
|
|
||||||
PAIRS.big_spawn_positions = {
|
|
||||||
[1] = { x=2, y=2 },
|
|
||||||
[2] = { x=2, y=3 },
|
|
||||||
[3] = { x=2, y=3 },
|
|
||||||
[4] = { x=2, y=3 },
|
|
||||||
[5] = { x=3, y=3 },
|
|
||||||
[6] = { x=3, y=3 },
|
|
||||||
[7] = { x=3, y=3 },
|
|
||||||
[8] = { x=3, y=3 },
|
|
||||||
[9] = { x=3, y=3 },
|
|
||||||
[10] = { x=3, y=3 },
|
|
||||||
[11] = { x=2, y=3 },
|
|
||||||
[12] = { x=2, y=3 },
|
|
||||||
[13] = { x=2, y=3 },
|
|
||||||
[14] = { x=2, y=3 },
|
|
||||||
[15] = { x=2, y=3 },
|
|
||||||
[16] = { x=2, y=3 },
|
|
||||||
[17] = { x=2, y=3 },
|
|
||||||
[18] = { x=2, y=3 },
|
|
||||||
}
|
|
||||||
|
|
||||||
PAIRS.draw_offsets = {
|
|
||||||
[1] = { x=0, y=0 },
|
|
||||||
[2] = { x=0, y=0 },
|
|
||||||
[3] = { x=0, y=0 },
|
|
||||||
[4] = { x=0, y=0 },
|
|
||||||
[5] = { x=0, y=0 },
|
|
||||||
[6] = { x=0, y=0 },
|
|
||||||
[7] = { x=0, y=0 },
|
|
||||||
[8] = { x=0, y=0 },
|
|
||||||
[9] = { x=0, y=0 },
|
|
||||||
[10] = { x=0, y=0 },
|
|
||||||
[11] = { x=0, y=0 },
|
|
||||||
[12] = { x=0, y=0 },
|
|
||||||
[13] = { x=0, y=0 },
|
|
||||||
[14] = { x=0, y=0 },
|
|
||||||
[15] = { x=0, y=0 },
|
|
||||||
[16] = { x=0, y=0 },
|
|
||||||
[17] = { x=0, y=0 },
|
|
||||||
[18] = { x=0, y=0 },
|
|
||||||
}
|
|
||||||
|
|
||||||
PAIRS.next_sounds = {
|
|
||||||
[1] = "I",
|
|
||||||
[2] = "O",
|
|
||||||
[3] = "S",
|
|
||||||
[4] = "Z",
|
|
||||||
[5] = "L",
|
|
||||||
[6] = "J",
|
|
||||||
[7] = "Z",
|
|
||||||
[8] = "S",
|
|
||||||
[9] = "J",
|
|
||||||
[10] = "L",
|
|
||||||
[11] = "O",
|
|
||||||
[12] = "O",
|
|
||||||
[13] = "T",
|
|
||||||
[14] = "L",
|
|
||||||
[15] = "J",
|
|
||||||
[16] = "T",
|
|
||||||
[17] = "J",
|
|
||||||
[18] = "I"
|
|
||||||
}
|
|
||||||
|
|
||||||
PAIRS.colourscheme = {
|
|
||||||
[1] = "R",
|
|
||||||
[2] = "C",
|
|
||||||
[3] = "G",
|
|
||||||
[4] = "M",
|
|
||||||
[5] = "O",
|
|
||||||
[6] = "C",
|
|
||||||
[7] = "G",
|
|
||||||
[8] = "M",
|
|
||||||
[9] = "G",
|
|
||||||
[10] = "M",
|
|
||||||
[11] = "Y",
|
|
||||||
[12] = "B",
|
|
||||||
[13] = "M",
|
|
||||||
[14] = "O",
|
|
||||||
[15] = "B",
|
|
||||||
[16] = "G",
|
|
||||||
[17] = "C",
|
|
||||||
[18] = "R"
|
|
||||||
}
|
|
||||||
|
|
||||||
PAIRS.pieces = 18
|
|
||||||
|
|
||||||
PAIRS.block_offsets = {
|
|
||||||
[1]={
|
|
||||||
{ {x=-2, y=0}, {x=-1, y=0}, {x=0, y=0}, {x=1, y=0}, {x=2, y=0} },
|
|
||||||
{ {x=0, y=-2}, {x=0, y=-1}, {x=0, y=0}, {x=0, y=1}, {x=0, y=2} },
|
|
||||||
{ {x=-2, y=0}, {x=-1, y=0}, {x=0, y=0}, {x=1, y=0}, {x=2, y=0} },
|
|
||||||
{ {x=0, y=-2}, {x=0, y=-1}, {x=0, y=0}, {x=0, y=1}, {x=0, y=2} },
|
|
||||||
},
|
|
||||||
[2]={
|
|
||||||
{ {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=1, y=-1}, {x=-1, y=-1} },
|
|
||||||
{ {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=1, y=-1}, {x=-1, y=-1} },
|
|
||||||
{ {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=1, y=-1}, {x=-1, y=-1} },
|
|
||||||
{ {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=1, y=-1}, {x=-1, y=-1} },
|
|
||||||
},
|
|
||||||
[3]={
|
|
||||||
{ {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=1, y=-2}, {x=-1, y=0} },
|
|
||||||
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=1, y=0}, {x=-1, y=-2} },
|
|
||||||
{ {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=1, y=-2}, {x=-1, y=0} },
|
|
||||||
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=1, y=0}, {x=-1, y=-2} },
|
|
||||||
},
|
|
||||||
[4]={
|
|
||||||
{ {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=1, y=0}, {x=-1, y=-2} },
|
|
||||||
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=-1, y=0}, {x=1, y=-2} },
|
|
||||||
{ {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=1, y=0}, {x=-1, y=-2} },
|
|
||||||
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=-1, y=0}, {x=1, y=-2} },
|
|
||||||
},
|
|
||||||
[5]={
|
|
||||||
{ {x=1, y=-1}, {x=-2, y=0}, {x=-1, y=0}, {x=0, y=0}, {x=1, y=0} },
|
|
||||||
{ {x=0, y=0}, {x=-1, y=-3}, {x=-1, y=-2}, {x=-1, y=-1}, {x=-1, y=0} },
|
|
||||||
{ {x=-2, y=0}, {x=-2, y=-1}, {x=-1, y=-1}, {x=0, y=-1}, {x=1, y=-1} },
|
|
||||||
{ {x=-1, y=-3}, {x=0, y=-3}, {x=0, y=-2}, {x=0, y=-1}, {x=0, y=0} },
|
|
||||||
},
|
|
||||||
[6]={
|
|
||||||
{ {x=-2, y=-1}, {x=-2, y=0}, {x=-1, y=0}, {x=0, y=0}, {x=1, y=0} },
|
|
||||||
{ {x=0, y=-3}, {x=-1, y=-3}, {x=-1, y=-2}, {x=-1, y=-1}, {x=-1, y=0} },
|
|
||||||
{ {x=1, y=0}, {x=-2, y=-1}, {x=-1, y=-1}, {x=0, y=-1}, {x=1, y=-1} },
|
|
||||||
{ {x=-1, y=0}, {x=0, y=-3}, {x=0, y=-2}, {x=0, y=-1}, {x=0, y=0} },
|
|
||||||
},
|
|
||||||
[7]={
|
|
||||||
{ {x=-2, y=-1}, {x=-1, y=-1}, {x=-1, y=0}, {x=0, y=0}, {x=1, y=0} },
|
|
||||||
{ {x=0, y=-3}, {x=0, y=-2}, {x=-1, y=-2}, {x=-1, y=-1}, {x=-1, y=0} },
|
|
||||||
{ {x=-2, y=-1}, {x=-1, y=-1}, {x=0, y=-1}, {x=0, y=0}, {x=1, y=0} },
|
|
||||||
{ {x=-1, y=0}, {x=0, y=-3}, {x=0, y=-2}, {x=0, y=-1}, {x=-1, y=-1} },
|
|
||||||
},
|
|
||||||
[8]={
|
|
||||||
{ {x=1, y=-1}, {x=-2, y=0}, {x=-1, y=0}, {x=0, y=0}, {x=0, y=-1} },
|
|
||||||
{ {x=0, y=0}, {x=-1, y=-3}, {x=-1, y=-2}, {x=-1, y=-1}, {x=0, y=-1} },
|
|
||||||
{ {x=-2, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1}, {x=1, y=-1} },
|
|
||||||
{ {x=-1, y=-3}, {x=-1, y=-2}, {x=0, y=-2}, {x=0, y=-1}, {x=0, y=0} },
|
|
||||||
},
|
|
||||||
[9]={
|
|
||||||
{ {x=-1, y=-1}, {x=-2, y=0}, {x=-1, y=0}, {x=0, y=0}, {x=1, y=0} },
|
|
||||||
{ {x=0, y=-2}, {x=-1, y=-3}, {x=-1, y=-2}, {x=-1, y=-1}, {x=-1, y=0} },
|
|
||||||
{ {x=0, y=0}, {x=-2, y=-1}, {x=-1, y=-1}, {x=0, y=-1}, {x=1, y=-1} },
|
|
||||||
{ {x=-1, y=-1}, {x=0, y=-3}, {x=0, y=-2}, {x=0, y=-1}, {x=0, y=0} },
|
|
||||||
},
|
|
||||||
[10]={
|
|
||||||
{ {x=0, y=-1}, {x=-2, y=0}, {x=-1, y=0}, {x=0, y=0}, {x=1, y=0} },
|
|
||||||
{ {x=0, y=-1}, {x=-1, y=-3}, {x=-1, y=-2}, {x=-1, y=-1}, {x=-1, y=0} },
|
|
||||||
{ {x=-1, y=0}, {x=-2, y=-1}, {x=-1, y=-1}, {x=0, y=-1}, {x=1, y=-1} },
|
|
||||||
{ {x=-1, y=-2}, {x=0, y=-3}, {x=0, y=-2}, {x=0, y=-1}, {x=0, y=0} },
|
|
||||||
},
|
|
||||||
[11]={
|
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=0, y=-1}, {x=-1, y=-1} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=-2}, {x=1, y=-1}, {x=1, y=-2} },
|
|
||||||
{ {x=0, y=0}, {x=1, y=-1}, {x=1, y=0}, {x=0, y=-1}, {x=-1, y=-1} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=-2}, {x=-1, y=-1}, {x=-1, y=0} },
|
|
||||||
},
|
|
||||||
[12]={
|
|
||||||
{ {x=0, y=0}, {x=1, y=-1}, {x=1, y=0}, {x=0, y=-1}, {x=-1, y=0} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=-2}, {x=1, y=-1}, {x=1, y=0} },
|
|
||||||
{ {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=0, y=-1}, {x=0, y=-2}, {x=-1, y=-1}, {x=-1, y=-2} },
|
|
||||||
},
|
|
||||||
[13]={
|
|
||||||
{ {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=-2}, {x=1, y=0}, {x=1, y=-2} },
|
|
||||||
{ {x=0, y=-1}, {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=-2}, {x=-1, y=0}, {x=-1, y=-2} },
|
|
||||||
},
|
|
||||||
[14]={
|
|
||||||
{ {x=0, y=-1}, {x=0, y=0}, {x=0, y=-2}, {x=-1, y=-1}, {x=1, y=0} },
|
|
||||||
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=0, y=-2}, {x=-1, y=0} },
|
|
||||||
{ {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=1, y=-1}, {x=-1, y=-2} },
|
|
||||||
{ {x=0, y=-1}, {x=1, y=-1}, {x=-1, y=-1}, {x=0, y=0}, {x=1, y=-2} },
|
|
||||||
},
|
|
||||||
[15]={
|
|
||||||
{ {x=0, y=-1}, {x=0, y=0}, {x=0, y=-2}, {x=-1, y=0}, {x=1, y=-1} },
|
|
||||||
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=-1, y=-2}, {x=0, y=0} },
|
|
||||||
{ {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=1, y=-2}, {x=-1, y=-1} },
|
|
||||||
{ {x=0, y=-1}, {x=1, y=-1}, {x=-1, y=-1}, {x=1, y=0}, {x=0, y=-2} },
|
|
||||||
},
|
|
||||||
[16]={
|
|
||||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=-2}, {x=-1, y=0}, {x=1, y=0} },
|
|
||||||
{ {x=-1, y=0}, {x=0, y=-1}, {x=-1, y=-2}, {x=-1, y=-1}, {x=1, y=-1} },
|
|
||||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=-2}, {x=-1, y=-2}, {x=1, y=-2} },
|
|
||||||
{ {x=1, y=0}, {x=0, y=-1}, {x=1, y=-2}, {x=-1, y=-1}, {x=1, y=-1} },
|
|
||||||
},
|
|
||||||
[17]={
|
|
||||||
{ {x=0, y=0}, {x=1, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=-1, y=-2} },
|
|
||||||
{ {x=0, y=-2}, {x=1, y=-2}, {x=-1, y=0}, {x=-1, y=-1}, {x=-1, y=-2} },
|
|
||||||
{ {x=0, y=-2}, {x=1, y=0}, {x=-1, y=-2}, {x=1, y=-1}, {x=1, y=-2} },
|
|
||||||
{ {x=0, y=0}, {x=1, y=0}, {x=-1, y=0}, {x=1, y=-1}, {x=1, y=-2} },
|
|
||||||
},
|
|
||||||
[18]={
|
|
||||||
{ {x=1, y=0}, {x=0, y=0}, {x=0, y=-1}, {x=-1, y=-1}, {x=-1, y=-2} },
|
|
||||||
{ {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1}, {x=0, y=-2}, {x=1, y=-2} },
|
|
||||||
{ {x=-1, y=-2}, {x=0, y=-2}, {x=0, y=-1}, {x=1, y=-1}, {x=1, y=0} },
|
|
||||||
{ {x=1, y=-2}, {x=1, y=-1}, {x=0, y=-1}, {x=0, y=0}, {x=-1, y=0} },
|
|
||||||
},
|
|
||||||
}
|
|
||||||
|
|
||||||
PAIRS.wallkicks = {
|
|
||||||
{x=1, y=0}, {x=-1, y=0}, {x=2, y=0}, {x=-2, y=0}, {x=0, y=-1}
|
|
||||||
}
|
|
||||||
|
|
||||||
function PAIRS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|
||||||
if (piece.shape == 2) then return end
|
|
||||||
|
|
||||||
local kicks = PAIRS.wallkicks
|
|
||||||
|
|
||||||
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
|
|
||||||
self:onPieceRotate(piece, grid)
|
|
||||||
piece:setRelativeRotation(rot_dir)
|
|
||||||
piece:setOffset(offset)
|
|
||||||
return
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function PAIRS:checkNewLow(piece)
|
|
||||||
for _, block in pairs(piece:getBlockOffsets()) do
|
|
||||||
local y = piece.position.y + block.y
|
|
||||||
if y > piece.lowest_y then
|
|
||||||
piece.lock_delay = 0
|
|
||||||
piece.lowest_y = y
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function PAIRS:onPieceCreate(piece, grid)
|
|
||||||
piece.lowest_y = -math.huge
|
|
||||||
end
|
|
||||||
|
|
||||||
function PAIRS:onPieceDrop(piece, grid)
|
|
||||||
self:checkNewLow(piece)
|
|
||||||
end
|
|
||||||
|
|
||||||
function PAIRS:get180RotationValue()
|
|
||||||
if config.gamesettings.world_reverse == 1 then
|
|
||||||
return 1
|
|
||||||
else
|
|
||||||
return 3
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
return PAIRS
|
|
||||||
@@ -35,73 +35,30 @@ Ruleset.next_sounds = {
|
|||||||
T = "T"
|
T = "T"
|
||||||
}
|
}
|
||||||
|
|
||||||
Ruleset.draw_offsets = {
|
|
||||||
I = { x=0, y=0 },
|
|
||||||
J = { x=0, y=0 },
|
|
||||||
L = { x=0, y=0 },
|
|
||||||
O = { x=0, y=0 },
|
|
||||||
S = { x=0, y=0 },
|
|
||||||
T = { x=0, y=0 },
|
|
||||||
Z = { x=0, y=0 },
|
|
||||||
}
|
|
||||||
|
|
||||||
Ruleset.pieces = 7
|
Ruleset.pieces = 7
|
||||||
|
|
||||||
-- Component functions.
|
-- Component functions.
|
||||||
|
|
||||||
function Ruleset:new()
|
function Ruleset:new(game_mode)
|
||||||
|
self.game = game_mode
|
||||||
|
local bones
|
||||||
if config.gamesettings.piece_colour == 1 then
|
if config.gamesettings.piece_colour == 1 then
|
||||||
blocks["bone"] = (not self.world) and
|
bones = self.world and "w" or ""
|
||||||
{
|
|
||||||
R = love.graphics.newImage("res/img/bone.png"),
|
|
||||||
O = love.graphics.newImage("res/img/bone.png"),
|
|
||||||
Y = love.graphics.newImage("res/img/bone.png"),
|
|
||||||
G = love.graphics.newImage("res/img/bone.png"),
|
|
||||||
C = love.graphics.newImage("res/img/bone.png"),
|
|
||||||
B = love.graphics.newImage("res/img/bone.png"),
|
|
||||||
M = love.graphics.newImage("res/img/bone.png"),
|
|
||||||
F = love.graphics.newImage("res/img/bone.png"),
|
|
||||||
A = love.graphics.newImage("res/img/bone.png"),
|
|
||||||
X = love.graphics.newImage("res/img/bone.png"),
|
|
||||||
} or {
|
|
||||||
R = love.graphics.newImage("res/img/bonew.png"),
|
|
||||||
O = love.graphics.newImage("res/img/bonew.png"),
|
|
||||||
Y = love.graphics.newImage("res/img/bonew.png"),
|
|
||||||
G = love.graphics.newImage("res/img/bonew.png"),
|
|
||||||
C = love.graphics.newImage("res/img/bonew.png"),
|
|
||||||
B = love.graphics.newImage("res/img/bonew.png"),
|
|
||||||
M = love.graphics.newImage("res/img/bonew.png"),
|
|
||||||
F = love.graphics.newImage("res/img/bonew.png"),
|
|
||||||
A = love.graphics.newImage("res/img/bonew.png"),
|
|
||||||
X = love.graphics.newImage("res/img/bonew.png"),
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
blocks["bone"] = (config.gamesettings.piece_colour == 2) and
|
bones = config.gamesettings.piece_colour == 3 and "w" or ""
|
||||||
{
|
|
||||||
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
|
||||||
|
blocks.bone = {
|
||||||
|
R = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
|
||||||
|
O = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
|
||||||
|
Y = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
|
||||||
|
G = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
|
||||||
|
C = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
|
||||||
|
B = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
|
||||||
|
M = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
|
||||||
|
F = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
|
||||||
|
A = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
|
||||||
|
X = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
|
||||||
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
function Ruleset:rotatePiece(inputs, piece, grid, prev_inputs, initial)
|
function Ruleset:rotatePiece(inputs, piece, grid, prev_inputs, initial)
|
||||||
@@ -115,9 +72,11 @@ function Ruleset:rotatePiece(inputs, piece, grid, prev_inputs, initial)
|
|||||||
|
|
||||||
local was_drop_blocked = piece:isDropBlocked(grid)
|
local was_drop_blocked = piece:isDropBlocked(grid)
|
||||||
|
|
||||||
self:attemptRotate(new_inputs, piece, grid, initial)
|
if self:canPieceRotate(piece, grid) then
|
||||||
|
self:attemptRotate(new_inputs, piece, grid, initial)
|
||||||
|
end
|
||||||
|
|
||||||
if not was_drop_blocked and piece:isDropBlocked(grid) then
|
if not initial and not was_drop_blocked and piece:isDropBlocked(grid) then
|
||||||
playSE("bottom")
|
playSE("bottom")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -160,49 +119,63 @@ function Ruleset:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Ruleset:movePiece(piece, grid, move, instant)
|
function Ruleset:movePiece(piece, grid, move, instant)
|
||||||
local x = piece.position.x
|
if not self:canPieceMove(piece, grid) then return end
|
||||||
local was_drop_blocked = piece:isDropBlocked(grid)
|
local was_drop_blocked = piece:isDropBlocked(grid)
|
||||||
|
local offset = ({x=0, y=0})
|
||||||
|
local moves = 0
|
||||||
|
local y = piece.position.y
|
||||||
if move == "left" then
|
if move == "left" then
|
||||||
piece:moveInGrid({x=-1, y=0}, 1, grid, false)
|
offset.x = -1
|
||||||
|
moves = 1
|
||||||
elseif move == "right" then
|
elseif move == "right" then
|
||||||
piece:moveInGrid({x=1, y=0}, 1, grid, false)
|
offset.x = 1
|
||||||
|
moves = 1
|
||||||
elseif move == "speedleft" then
|
elseif move == "speedleft" then
|
||||||
piece:moveInGrid({x=-1, y=0}, grid.width, grid, instant)
|
offset.x = -1
|
||||||
|
moves = grid.width
|
||||||
elseif move == "speedright" then
|
elseif move == "speedright" then
|
||||||
piece:moveInGrid({x=1, y=0}, grid.width, grid, instant)
|
offset.x = 1
|
||||||
|
moves = grid.width
|
||||||
end
|
end
|
||||||
if piece.position.x ~= x then
|
for i = 1, moves do
|
||||||
self:onPieceMove(piece, grid)
|
local x = piece.position.x
|
||||||
if not was_drop_blocked and piece:isDropBlocked(grid) then
|
if moves ~= 1 then
|
||||||
playSE("bottom")
|
piece:moveInGrid(offset, 1, grid, instant)
|
||||||
|
else
|
||||||
|
piece:moveInGrid(offset, 1, grid, false)
|
||||||
end
|
end
|
||||||
|
if piece.position.x ~= x then
|
||||||
|
self:onPieceMove(piece, grid)
|
||||||
|
if piece.locked then break end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if not was_drop_blocked and piece:isDropBlocked(grid) then
|
||||||
|
playSE("bottom")
|
||||||
|
end
|
||||||
|
if instant and piece.position.y ~= y then
|
||||||
|
self:onPieceDrop(piece, grid)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Ruleset:dropPiece(
|
function Ruleset: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, classic_lock
|
||||||
)
|
)
|
||||||
if piece.big then
|
|
||||||
gravity = gravity / 2
|
|
||||||
drop_speed = drop_speed / 2
|
|
||||||
end
|
|
||||||
|
|
||||||
local y = piece.position.y
|
local y = piece.position.y
|
||||||
if inputs["down"] == true and drop_locked == false then
|
if inputs["down"] == true and drop_locked == false then
|
||||||
if additive_gravity then
|
if additive_gravity then
|
||||||
piece:addGravity(gravity + drop_speed, grid)
|
piece:addGravity(gravity + drop_speed, grid, classic_lock)
|
||||||
else
|
else
|
||||||
piece:addGravity(math.max(gravity, drop_speed), grid)
|
piece:addGravity(math.max(gravity, drop_speed), grid, classic_lock)
|
||||||
end
|
end
|
||||||
elseif inputs["up"] == true and hard_drop_enabled == true then
|
elseif inputs["up"] == true and hard_drop_enabled == true then
|
||||||
if hard_drop_locked == true or piece:isDropBlocked(grid) then
|
if hard_drop_locked == true or piece:isDropBlocked(grid) then
|
||||||
piece:addGravity(gravity, grid)
|
piece:addGravity(gravity, grid, classic_lock)
|
||||||
else
|
else
|
||||||
piece:dropToBottom(grid)
|
piece:dropToBottom(grid)
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
piece:addGravity(gravity, grid)
|
piece:addGravity(gravity, grid, classic_lock)
|
||||||
end
|
end
|
||||||
if piece.position.y ~= y then
|
if piece.position.y ~= y then
|
||||||
self:onPieceDrop(piece, grid)
|
self:onPieceDrop(piece, grid)
|
||||||
@@ -220,13 +193,19 @@ end
|
|||||||
|
|
||||||
function Ruleset:get180RotationValue() return 2 end
|
function Ruleset:get180RotationValue() return 2 end
|
||||||
function Ruleset:getDefaultOrientation() return 1 end
|
function Ruleset:getDefaultOrientation() return 1 end
|
||||||
|
function Ruleset:getDrawOffset(shape, orientation) return { x=0, y=0 } end
|
||||||
|
function Ruleset:getAboveFieldOffset(shape, orientation)
|
||||||
|
if shape == "I" then
|
||||||
|
return 1
|
||||||
|
else
|
||||||
|
return 2
|
||||||
|
end
|
||||||
|
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, irs,
|
drop_locked, hard_drop_locked, big, irs
|
||||||
buffer_hard_drop, buffer_soft_drop,
|
|
||||||
lock_on_hard_drop, lock_on_soft_drop
|
|
||||||
)
|
)
|
||||||
local spawn_positions
|
local spawn_positions
|
||||||
if big then
|
if big then
|
||||||
@@ -234,33 +213,31 @@ 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
|
||||||
local spawn_x
|
if self.pieces == 7 then
|
||||||
if (grid.width ~= 10) then
|
colours = ({self.colourscheme, ColourSchemes.Arika, ColourSchemes.TTC})[config.gamesettings.piece_colour]
|
||||||
local percent = spawn_positions[data.shape].x / 10
|
else
|
||||||
for i = 0, grid.width - 1 do
|
colours = self.colourscheme
|
||||||
if i / grid.width >= percent then
|
|
||||||
spawn_x = i
|
|
||||||
break
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
|
local spawn_x = math.floor(spawn_positions[data.shape].x / 10 * grid.width)
|
||||||
|
|
||||||
local spawn_dy
|
local spawn_dy
|
||||||
if (config.gamesettings.spawn_positions == 1) then
|
if (config.gamesettings.spawn_positions == 1) then
|
||||||
spawn_dy = (
|
spawn_dy = (
|
||||||
self.spawn_above_field and 2 or 0
|
self.spawn_above_field and
|
||||||
|
self:getAboveFieldOffset(data.shape, data.orientation) or 0
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
spawn_dy = (
|
spawn_dy = (
|
||||||
config.gamesettings.spawn_positions == 3 and
|
config.gamesettings.spawn_positions == 3 and
|
||||||
2 or 0
|
self:getAboveFieldOffset(data.shape, data.orientation) or 0
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
local piece = Piece(data.shape, data.orientation - 1, {
|
local piece = Piece(data.shape, data.orientation - 1, {
|
||||||
x = spawn_x and spawn_x or spawn_positions[data.shape].x,
|
x = spawn_x or spawn_positions[data.shape].x,
|
||||||
y = spawn_positions[data.shape].y - spawn_dy
|
y = spawn_positions[data.shape].y - spawn_dy
|
||||||
}, self.block_offsets, 0, 0, data.skin, colours[data.shape], big)
|
}, self.block_offsets, 0, 0, data.skin, colours[data.shape], big)
|
||||||
|
|
||||||
@@ -271,14 +248,6 @@ function Ruleset:initializePiece(
|
|||||||
playSE("irs")
|
playSE("irs")
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
self:dropPiece(inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked)
|
|
||||||
if (buffer_hard_drop and config.gamesettings.buffer_lock == 1) then
|
|
||||||
piece:dropToBottom(grid)
|
|
||||||
if lock_on_hard_drop then piece.locked = true end
|
|
||||||
end
|
|
||||||
if (buffer_soft_drop and lock_on_soft_drop and piece:isDropBlocked(grid) and config.gamesettings.buffer_lock == 1) then
|
|
||||||
piece.locked = true
|
|
||||||
end
|
|
||||||
return piece
|
return piece
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -291,23 +260,24 @@ function Ruleset:processPiece(
|
|||||||
drop_locked, hard_drop_locked,
|
drop_locked, hard_drop_locked,
|
||||||
hard_drop_enabled, additive_gravity, classic_lock
|
hard_drop_enabled, additive_gravity, classic_lock
|
||||||
)
|
)
|
||||||
|
|
||||||
local synchroes_allowed = ({not self.world, true, false})[config.gamesettings.synchroes_allowed]
|
local synchroes_allowed = ({not self.world, true, false})[config.gamesettings.synchroes_allowed]
|
||||||
|
|
||||||
if synchroes_allowed then
|
if synchroes_allowed then
|
||||||
self:rotatePiece(inputs, piece, grid, prev_inputs, false)
|
self:rotatePiece(inputs, piece, grid, prev_inputs, false)
|
||||||
self:movePiece(piece, grid, move, gravity >= 20)
|
self:movePiece(piece, grid, move, gravity >= grid.height - 4)
|
||||||
else
|
else
|
||||||
self:movePiece(piece, grid, move, gravity >= 20)
|
self:movePiece(piece, grid, move, gravity >= grid.height - 4)
|
||||||
self:rotatePiece(inputs, piece, grid, prev_inputs, false)
|
self:rotatePiece(inputs, piece, grid, prev_inputs, false)
|
||||||
end
|
end
|
||||||
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, classic_lock
|
||||||
)
|
)
|
||||||
self:lockPiece(piece, grid, lock_delay, classic_lock)
|
self:lockPiece(piece, grid, lock_delay, classic_lock)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Ruleset:canPieceMove(piece, grid) return true end
|
||||||
|
function Ruleset:canPieceRotate(piece, grid) return true end
|
||||||
function Ruleset:onPieceMove(piece) end
|
function Ruleset:onPieceMove(piece) end
|
||||||
function Ruleset:onPieceRotate(piece) end
|
function Ruleset:onPieceRotate(piece) end
|
||||||
function Ruleset:onPieceDrop(piece) end
|
function Ruleset:onPieceDrop(piece) end
|
||||||
|
|||||||
@@ -92,11 +92,14 @@ function SRS:onPieceRotate(piece, grid)
|
|||||||
piece.lock_delay = 0 -- rotate reset
|
piece.lock_delay = 0 -- rotate reset
|
||||||
self:checkNewLow(piece)
|
self:checkNewLow(piece)
|
||||||
piece.manipulations = piece.manipulations + 1
|
piece.manipulations = piece.manipulations + 1
|
||||||
if piece:isDropBlocked(grid) then
|
if piece.manipulations >= self.MANIPULATIONS_MAX then
|
||||||
if piece.manipulations >= SRS.MANIPULATIONS_MAX then
|
piece:moveInGrid({ x = 0, y = 1 }, 1, grid)
|
||||||
piece.locked = true
|
if piece:isDropBlocked(grid) then
|
||||||
end
|
piece.locked = true
|
||||||
end
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function SRS:canPieceRotate() return true end
|
||||||
|
|
||||||
return SRS
|
return SRS
|
||||||
|
|||||||
@@ -54,7 +54,7 @@ function SRS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|||||||
if grid:canPlacePiece(kicked_piece) then
|
if grid:canPlacePiece(kicked_piece) then
|
||||||
piece:setRelativeRotation(rot_dir)
|
piece:setRelativeRotation(rot_dir)
|
||||||
piece:setOffset(offset)
|
piece:setOffset(offset)
|
||||||
self:onPieceRotate(piece, grid)
|
self:onPieceRotate(piece, grid, offset.y < 0)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -69,7 +69,10 @@ end
|
|||||||
|
|
||||||
function SRS:onPieceDrop(piece, grid)
|
function SRS:onPieceDrop(piece, grid)
|
||||||
self:checkNewLow(piece)
|
self:checkNewLow(piece)
|
||||||
if piece.manipulations >= self.MANIPULATIONS_MAX and piece:isDropBlocked(grid) then
|
if (
|
||||||
|
piece.manipulations >= self.MANIPULATIONS_MAX or
|
||||||
|
piece.rotations >= self.ROTATIONS_MAX
|
||||||
|
) 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
|
||||||
@@ -86,16 +89,18 @@ function SRS:onPieceMove(piece, grid)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function SRS:onPieceRotate(piece, grid)
|
function SRS:onPieceRotate(piece, grid, upward)
|
||||||
piece.lock_delay = 0 -- rotate reset
|
piece.lock_delay = 0 -- rotate reset
|
||||||
self:checkNewLow(piece)
|
if upward or piece:isDropBlocked(grid) then
|
||||||
if piece.rotations >= self.ROTATIONS_MAX then
|
piece.rotations = piece.rotations + 1
|
||||||
piece.rotations = piece.rotations + 1
|
if piece.rotations >= self.ROTATIONS_MAX and piece:isDropBlocked(grid) then
|
||||||
piece:moveInGrid({ x = 0, y = 1 }, 1, grid)
|
piece.locked = true
|
||||||
if piece:isDropBlocked(grid) then
|
end
|
||||||
piece.locked = true
|
end
|
||||||
end
|
end
|
||||||
end
|
|
||||||
|
function SRS:canPieceRotate(piece)
|
||||||
|
return piece.rotations < self.ROTATIONS_MAX
|
||||||
end
|
end
|
||||||
|
|
||||||
function SRS:get180RotationValue() return 2 end
|
function SRS:get180RotationValue() return 2 end
|
||||||
|
|||||||
@@ -150,9 +150,9 @@ function SRS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|||||||
for idx, offset in pairs(kicks) do
|
for idx, offset in pairs(kicks) do
|
||||||
kicked_piece = new_piece:withOffset(offset)
|
kicked_piece = new_piece:withOffset(offset)
|
||||||
if grid:canPlacePiece(kicked_piece) then
|
if grid:canPlacePiece(kicked_piece) then
|
||||||
self:onPieceRotate(piece, grid)
|
|
||||||
piece:setRelativeRotation(rot_dir)
|
piece:setRelativeRotation(rot_dir)
|
||||||
piece:setOffset(offset)
|
piece:setOffset(offset)
|
||||||
|
self:onPieceRotate(piece, grid, offset.y < 0)
|
||||||
return
|
return
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -182,16 +182,20 @@ function SRS:onPieceMove(piece, grid)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function SRS:onPieceRotate(piece, grid)
|
function SRS:onPieceRotate(piece, grid, upward)
|
||||||
piece.lock_delay = 0 -- rotate reset
|
piece.lock_delay = 0 -- rotate reset
|
||||||
if piece:isDropBlocked(grid) then
|
if upward or piece:isDropBlocked(grid) then
|
||||||
piece.rotations = piece.rotations + 1
|
piece.rotations = piece.rotations + 1
|
||||||
if piece.rotations >= self.ROTATIONS_MAX then
|
if piece.rotations >= self.ROTATIONS_MAX and piece:isDropBlocked(grid) then
|
||||||
piece.locked = true
|
piece.locked = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function SRS:canPieceRotate(piece)
|
||||||
|
return piece.rotations < self.ROTATIONS_MAX
|
||||||
|
end
|
||||||
|
|
||||||
function SRS:get180RotationValue() return 3 end
|
function SRS:get180RotationValue() return 3 end
|
||||||
|
|
||||||
return SRS
|
return SRS
|
||||||
|
|||||||
Reference in New Issue
Block a user