mirror of
https://github.com/SashLilac/cambridge.git
synced 2025-05-13 20:21:25 -05:00
Compare commits
24 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
a4984fd687 | ||
|
|
b7ef7d1976 | ||
|
|
293b7398a2 | ||
|
|
8a2237a77c | ||
|
|
bdad32ac79 | ||
|
|
3cc918841f | ||
|
|
5f7ea0648e | ||
|
|
5d34218b97 | ||
|
|
fcd8b0f360 | ||
|
|
b983e1c108 | ||
|
|
36ab451b70 | ||
|
|
8fef7faa6a | ||
|
|
f13e2096b2 | ||
|
|
6b7f18d58a | ||
|
|
d5ce2ee9ba | ||
|
|
f04b57e7eb | ||
|
|
be644bf57b | ||
|
|
9d15feef33 | ||
|
|
634a5bc03b | ||
|
|
f1ad1f0ea4 | ||
|
|
a534331b11 | ||
|
|
d602fdfc7e | ||
|
|
971151e210 | ||
|
|
593cad0e71 |
12
README.md
12
README.md
@@ -3,6 +3,14 @@ Cambridge
|
|||||||
|
|
||||||
Welcome to Cambridge, the next open-source falling-block game engine!
|
Welcome to Cambridge, the next open-source falling-block game engine!
|
||||||
|
|
||||||
|
This fork is written and maintained exclusively by [SashLilac](https://github.com/SashLilac) and [Oshisaure](https://github.com/oshisaure)!
|
||||||
|
|
||||||
|
Credits
|
||||||
|
-------
|
||||||
|
|
||||||
|
- [Lilla Oshisaure](https://www.youtube.com/user/LeSpyroshisaure) for their amazing contributions to my life in general!
|
||||||
|
- [The Tetra Legends Discord](http://discord.com/invite/7hMx5r2) for supporting me and playtesting!
|
||||||
|
- [joezeng](https://github.com/joezeng) for the original project.
|
||||||
|
|
||||||
Installation instructions
|
Installation instructions
|
||||||
-------------------------
|
-------------------------
|
||||||
@@ -15,7 +23,7 @@ Unzip the exe file and run it directly. All assets are currently bundled inside
|
|||||||
|
|
||||||
### macOS
|
### macOS
|
||||||
|
|
||||||
For the time being, the file `cambridge.love` only works on the command line. Install `love` with [https://brew.sh/](Homebrew), and run:
|
For the time being, the file `cambridge.love` only works on the command line. Install `love` with [Homebrew](https://brew.sh), and run:
|
||||||
|
|
||||||
$ love cambridge.love
|
$ love cambridge.love
|
||||||
|
|
||||||
@@ -35,7 +43,7 @@ If you haven't already, install `love` with your favourite package manager (Home
|
|||||||
|
|
||||||
Clone the repository in git:
|
Clone the repository in git:
|
||||||
|
|
||||||
git clone https://github.com/joezeng/cambridge
|
git clone https://github.com/SashLilac/cambridge
|
||||||
|
|
||||||
Then, navigate to the root directory that you just cloned, and type:
|
Then, navigate to the root directory that you just cloned, and type:
|
||||||
|
|
||||||
|
|||||||
@@ -15,9 +15,7 @@ There are several classes of game modes. The modes that originate from other gam
|
|||||||
* The "G" series stand for "Guideline" games, or games that follow the Tetris Guideline.
|
* The "G" series stand for "Guideline" games, or games that follow the Tetris Guideline.
|
||||||
* GF - Tetris Friends (2007-2019)
|
* GF - Tetris Friends (2007-2019)
|
||||||
* GJ - Tetris Online Japan (2005-2011)
|
* GJ - Tetris Online Japan (2005-2011)
|
||||||
* The "N" series stands for Nullpomino, only used for Phantom Mania N.
|
* N stands for Nullpomino, only used for Phantom Mania N.
|
||||||
* The "W" series stands for "Web" games, which are fanmade games released on the web.
|
|
||||||
* WCB - RainComplex.net's Cat Boi Quatro.
|
|
||||||
|
|
||||||
MARATHON
|
MARATHON
|
||||||
--------
|
--------
|
||||||
@@ -25,15 +23,12 @@ MARATHON
|
|||||||
Modes in which the goal is to play as well as possible over a limited game interval.
|
Modes in which the goal is to play as well as possible over a limited game interval.
|
||||||
|
|
||||||
* **MARATHON 2020**: 2020 levels of pure pain. Can you make it all the way?
|
* **MARATHON 2020**: 2020 levels of pure pain. Can you make it all the way?
|
||||||
* **MARATHON WCB**: CatBoiQuatro! Can you control the pieces?
|
|
||||||
|
|
||||||
From other games:
|
From other games:
|
||||||
* **MARATHON A1**: Tetris the Grand Master 1.
|
* **MARATHON A1**: Tetris the Grand Master 1.
|
||||||
* **MARATHON A2**: Tetris the Grand Master 2 (TAP Master).
|
* **MARATHON A2**: Tetris the Grand Master 2 (TAP Master).
|
||||||
* **MARATHON A3**: Tetris the Grand Master 3 (no exams).
|
* **MARATHON A3**: Tetris the Grand Master 3 (no exams).
|
||||||
* **MARATHON AX**: Normal mode from TGM Ace.
|
* **MARATHON AX4**: Another mode from TGM Ace.
|
||||||
* **MARATHON AX2**: Hi-Speed1 mode from TGM Ace.
|
|
||||||
* **MARATHON AX3**: Hi-Speed2 mode from TGM Ace.
|
|
||||||
* **MARATHON C89**: Nintendo NES Tetris. Can you transition and make it to the killscreen?
|
* **MARATHON C89**: Nintendo NES Tetris. Can you transition and make it to the killscreen?
|
||||||
|
|
||||||
|
|
||||||
@@ -48,8 +43,6 @@ From other games:
|
|||||||
* **SURVIVAL A1**: 20G mode from Tetris the Grand Master.
|
* **SURVIVAL A1**: 20G mode from Tetris the Grand Master.
|
||||||
* **SURVIVAL A2**: T.A. Death.
|
* **SURVIVAL A2**: T.A. Death.
|
||||||
* **SURVIVAL A3**: Ti Shirase.
|
* **SURVIVAL A3**: Ti Shirase.
|
||||||
* **SURVIVAL AX**: Another mode from TGM Ace.
|
|
||||||
* **SURVIVAL AX2**: Another2 mode from TGM Ace.
|
|
||||||
|
|
||||||
|
|
||||||
RACE
|
RACE
|
||||||
@@ -60,14 +53,6 @@ Modes with no levels, just a single timed goal.
|
|||||||
* **Race 40**: How fast can you clear 40 lines? No limits, no holds barred.
|
* **Race 40**: How fast can you clear 40 lines? No limits, no holds barred.
|
||||||
|
|
||||||
|
|
||||||
CREDITS
|
|
||||||
-------
|
|
||||||
|
|
||||||
Modes that are just the credit rolls of specific games.
|
|
||||||
|
|
||||||
* **CREDITS A3**: Tetris the Grand Master 3's famous M-roll.
|
|
||||||
|
|
||||||
|
|
||||||
PHANTOM MANIA
|
PHANTOM MANIA
|
||||||
-------------
|
-------------
|
||||||
|
|
||||||
@@ -78,6 +63,7 @@ Modes where pieces turn invisible as soon as you lock them. One of Cambridge's s
|
|||||||
* **Phantom Mania 2**: Phantom Mania but way faster! Can you face a mode where even the garbage and the next preview turn invisible?
|
* **Phantom Mania 2**: Phantom Mania but way faster! Can you face a mode where even the garbage and the next preview turn invisible?
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
OTHER MODES
|
OTHER MODES
|
||||||
-----------
|
-----------
|
||||||
|
|
||||||
|
|||||||
@@ -10,13 +10,16 @@ A ruleset consists of the following things:
|
|||||||
|
|
||||||
If you're used to Nullpomino, you may notice a few things missing from that definition. For example, piece previews, hold queues, and randomizers have been moved to being game-specific rules, rather than rules that are changeable with the ruleset you use. Soft and hard drop behaviour is also game-specific now, so that times can be more plausibly compared across rulesets.
|
If you're used to Nullpomino, you may notice a few things missing from that definition. For example, piece previews, hold queues, and randomizers have been moved to being game-specific rules, rather than rules that are changeable with the ruleset you use. Soft and hard drop behaviour is also game-specific now, so that times can be more plausibly compared across rulesets.
|
||||||
|
|
||||||
There are six rulesets currently supported:
|
|
||||||
|
|
||||||
* Cambridge - a ruleset original to Cambridge, used for all custom modes. Supports 180-degree rotations!
|
Rotation system
|
||||||
|
---------------
|
||||||
|
A rotation system defines the following things:
|
||||||
|
* The block offsets of each piece orientation.
|
||||||
|
* The wall or floor kicks that will be attempted for each type of rotation.
|
||||||
|
|
||||||
* SRS - the rotation system used in the Tetris Guideline games. Supports 180-degree rotations!
|
There are four rotation systems currently supported:
|
||||||
* Ti-SRS - SRS but with no 180-degree rotations.
|
|
||||||
|
|
||||||
* ARS - the rotation system from the original Tetris the Grand Master.
|
* Cambridge
|
||||||
* Ti-ARS - ARS with floorkicks! From TGM3: Terror Instinct.
|
* Classic ARS
|
||||||
* Ace-ARS - ARS with floorkicks and move reset! From TGM ACE.
|
* Ti-ARS
|
||||||
|
* SRS
|
||||||
27
funcs.lua
27
funcs.lua
@@ -1,4 +1,5 @@
|
|||||||
function copy(t)
|
function copy(t)
|
||||||
|
-- returns deep copy of t (as opposed to the shallow copy you get from var = t)
|
||||||
if type(t) ~= "table" then return t end
|
if type(t) ~= "table" then return t end
|
||||||
local meta = getmetatable(t)
|
local meta = getmetatable(t)
|
||||||
local target = {}
|
local target = {}
|
||||||
@@ -7,7 +8,8 @@ function copy(t)
|
|||||||
return target
|
return target
|
||||||
end
|
end
|
||||||
|
|
||||||
function st(tbl)
|
function strTrueValues(tbl)
|
||||||
|
-- returns a concatenation of all the keys in tbl with value true, separated with spaces
|
||||||
str = ""
|
str = ""
|
||||||
for k, v in pairs(tbl) do
|
for k, v in pairs(tbl) do
|
||||||
if v == true then
|
if v == true then
|
||||||
@@ -17,14 +19,16 @@ function st(tbl)
|
|||||||
return str
|
return str
|
||||||
end
|
end
|
||||||
|
|
||||||
function sp(m, s, f)
|
function frameTime(min, sec, hth)
|
||||||
if m == nil then m = 0 end
|
-- returns a time in frames from a time in minutes-seconds-hundredths format
|
||||||
if s == nil then s = 0 end
|
if min == nil then min = 0 end
|
||||||
if f == nil then f = 0 end
|
if sec == nil then sec = 0 end
|
||||||
return m*3600 + s*60 + math.ceil(f * 0.6)
|
if hth == nil then hth = 0 end
|
||||||
|
return min*3600 + sec*60 + math.ceil(hth * 0.6)
|
||||||
end
|
end
|
||||||
|
|
||||||
function vAdd(v1, v2)
|
function vAdd(v1, v2)
|
||||||
|
-- returns the sum of vectors v1 and v2
|
||||||
return {
|
return {
|
||||||
x = v1.x + v2.x,
|
x = v1.x + v2.x,
|
||||||
y = v1.y + v2.y
|
y = v1.y + v2.y
|
||||||
@@ -32,6 +36,7 @@ function vAdd(v1, v2)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function vNeg(v)
|
function vNeg(v)
|
||||||
|
-- returns the opposite of vector v
|
||||||
return {
|
return {
|
||||||
x = -v.x,
|
x = -v.x,
|
||||||
y = -v.y
|
y = -v.y
|
||||||
@@ -39,14 +44,18 @@ function vNeg(v)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function formatTime(frames)
|
function formatTime(frames)
|
||||||
|
-- returns a mm:ss:hh (h=hundredths) representation of the time in frames given
|
||||||
if frames < 0 then return formatTime(0) end
|
if frames < 0 then return formatTime(0) end
|
||||||
str = string.format("%02d", math.floor(frames / 3600)) .. ":"
|
local min, sec, hund
|
||||||
.. string.format("%02d", math.floor(frames / 60) % 60) .. "."
|
min = math.floor(frames/3600)
|
||||||
.. string.format("%02d", math.floor(frames / 0.6) % 100)
|
sec = math.floor(frames/60) % 60
|
||||||
|
hund = math.floor(frames/.6) % 100
|
||||||
|
str = string.format("%02d:%02d.%02d", min, sec, hund)
|
||||||
return str
|
return str
|
||||||
end
|
end
|
||||||
|
|
||||||
function formatBigNum(number)
|
function formatBigNum(number)
|
||||||
|
-- returns a string representing a number with commas as thousands separator (e.g. 12,345,678)
|
||||||
local s = string.format("%d", number)
|
local s = string.format("%d", number)
|
||||||
local pos = string.len(s) % 3
|
local pos = string.len(s) % 3
|
||||||
if pos == 0 then pos = 3 end
|
if pos == 0 then pos = 3 end
|
||||||
|
|||||||
1
main.lua
1
main.lua
@@ -11,7 +11,6 @@ function love.load()
|
|||||||
config["side_next"] = false
|
config["side_next"] = false
|
||||||
config["reverse_rotate"] = true
|
config["reverse_rotate"] = true
|
||||||
config["fullscreen"] = false
|
config["fullscreen"] = false
|
||||||
config["das_last_key"] = false
|
|
||||||
|
|
||||||
love.window.setMode(love.graphics.getWidth(), love.graphics.getHeight(), {resizable = true});
|
love.window.setMode(love.graphics.getWidth(), love.graphics.getHeight(), {resizable = true});
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
92
scene/mode_select.lua
Normal file → Executable file
92
scene/mode_select.lua
Normal file → Executable file
@@ -5,16 +5,13 @@ ModeSelectScene.title = "Game Start"
|
|||||||
current_mode = 1
|
current_mode = 1
|
||||||
current_ruleset = 1
|
current_ruleset = 1
|
||||||
|
|
||||||
MAX_MODES = 19
|
|
||||||
|
|
||||||
game_modes = {
|
game_modes = {
|
||||||
require 'tetris.modes.marathon_2020',
|
require 'tetris.modes.marathon_2020',
|
||||||
require 'tetris.modes.survival_2020',
|
require 'tetris.modes.survival_2020',
|
||||||
require 'tetris.modes.strategy',
|
--require 'tetris.modes.strategy',
|
||||||
require 'tetris.modes.interval_training',
|
--require 'tetris.modes.interval_training',
|
||||||
require 'tetris.modes.pacer_test',
|
--require 'tetris.modes.pacer_test',
|
||||||
require 'tetris.modes.marathon_wcb',
|
--require 'tetris.modes.demon_mode',
|
||||||
require 'tetris.modes.demon_mode',
|
|
||||||
require 'tetris.modes.phantom_mania',
|
require 'tetris.modes.phantom_mania',
|
||||||
require 'tetris.modes.phantom_mania2',
|
require 'tetris.modes.phantom_mania2',
|
||||||
require 'tetris.modes.phantom_mania_n',
|
require 'tetris.modes.phantom_mania_n',
|
||||||
@@ -22,25 +19,22 @@ game_modes = {
|
|||||||
require 'tetris.modes.marathon_a1',
|
require 'tetris.modes.marathon_a1',
|
||||||
require 'tetris.modes.marathon_a2',
|
require 'tetris.modes.marathon_a2',
|
||||||
require 'tetris.modes.marathon_a3',
|
require 'tetris.modes.marathon_a3',
|
||||||
require 'tetris.modes.marathon_ax',
|
require 'tetris.modes.marathon_ax4',
|
||||||
require 'tetris.modes.marathon_ax2',
|
|
||||||
require 'tetris.modes.marathon_ax3',
|
|
||||||
require 'tetris.modes.marathon_c89',
|
require 'tetris.modes.marathon_c89',
|
||||||
require 'tetris.modes.survival_a1',
|
require 'tetris.modes.survival_a1',
|
||||||
require 'tetris.modes.survival_a2',
|
require 'tetris.modes.survival_a2',
|
||||||
require 'tetris.modes.survival_a3',
|
require 'tetris.modes.survival_a3',
|
||||||
require 'tetris.modes.survival_ax',
|
require 'tetris.modes.big_a2',
|
||||||
require 'tetris.modes.survival_ax2',
|
require 'tetris.modes.konoha',
|
||||||
require 'tetris.modes.credits_a3',
|
|
||||||
}
|
}
|
||||||
|
|
||||||
rulesets = {
|
rulesets = {
|
||||||
require 'tetris.rulesets.cambridge',
|
require 'tetris.rulesets.cambridge',
|
||||||
require 'tetris.rulesets.standard',
|
|
||||||
require 'tetris.rulesets.standard_ti',
|
|
||||||
require 'tetris.rulesets.arika',
|
require 'tetris.rulesets.arika',
|
||||||
require 'tetris.rulesets.arika_ti',
|
require 'tetris.rulesets.arika_ti',
|
||||||
require 'tetris.rulesets.arika_ace',
|
require 'tetris.rulesets.arika_ace',
|
||||||
|
require 'tetris.rulesets.arika_srs',
|
||||||
|
require 'tetris.rulesets.standard_exp',
|
||||||
--require 'tetris.rulesets.bonkers',
|
--require 'tetris.rulesets.bonkers',
|
||||||
--require 'tetris.rulesets.shirase',
|
--require 'tetris.rulesets.shirase',
|
||||||
--require 'tetris.rulesets.super302',
|
--require 'tetris.rulesets.super302',
|
||||||
@@ -57,58 +51,38 @@ end
|
|||||||
function ModeSelectScene:update()
|
function ModeSelectScene:update()
|
||||||
end
|
end
|
||||||
|
|
||||||
function getCursorHeight(x)
|
|
||||||
return 78 + 20 * x
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
function ModeSelectScene:drawList(name, items, cursor, x)
|
|
||||||
local start, finish
|
|
||||||
if table.getn(items) < MAX_MODES then
|
|
||||||
start = 1
|
|
||||||
finish = table.getn(items)
|
|
||||||
else
|
|
||||||
if cursor < 10 then
|
|
||||||
start = 1
|
|
||||||
finish = 19
|
|
||||||
elseif cursor > table.getn(items) - 9 then
|
|
||||||
start = table.getn(items) - 18
|
|
||||||
finish = table.getn(items)
|
|
||||||
else
|
|
||||||
start = cursor - 9
|
|
||||||
finish = cursor + 9
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.menu_state.select == name then
|
|
||||||
love.graphics.setColor(1, 1, 1, 0.5)
|
|
||||||
else
|
|
||||||
love.graphics.setColor(1, 1, 1, 0.25)
|
|
||||||
end
|
|
||||||
love.graphics.rectangle("fill", x, getCursorHeight(cursor - start), 240, 22)
|
|
||||||
|
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
|
||||||
|
|
||||||
for idx = start, finish do
|
|
||||||
local item = items[idx]
|
|
||||||
love.graphics.printf(item.name, x + 20, 80 + 20 * (idx - start), 200, "left")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
|
|
||||||
function ModeSelectScene:render()
|
function ModeSelectScene:render()
|
||||||
love.graphics.setFont(font_3x5_2)
|
|
||||||
|
|
||||||
love.graphics.draw(
|
love.graphics.draw(
|
||||||
backgrounds[0],
|
backgrounds[0],
|
||||||
0, 0, 0,
|
0, 0, 0,
|
||||||
0.5, 0.5
|
0.5, 0.5
|
||||||
)
|
)
|
||||||
|
|
||||||
love.graphics.draw(misc_graphics["select_mode"], 20, 30)
|
if self.menu_state.select == "mode" then
|
||||||
|
love.graphics.setColor(1, 1, 1, 0.5)
|
||||||
|
elseif self.menu_state.select == "ruleset" then
|
||||||
|
love.graphics.setColor(1, 1, 1, 0.25)
|
||||||
|
end
|
||||||
|
love.graphics.rectangle("fill", 20, 78 + 20 * self.menu_state.mode, 240, 22)
|
||||||
|
|
||||||
self:drawList("mode", game_modes, self.menu_state.mode, 20)
|
if self.menu_state.select == "mode" then
|
||||||
self:drawList("ruleset", rulesets, self.menu_state.ruleset, 320)
|
love.graphics.setColor(1, 1, 1, 0.25)
|
||||||
|
elseif self.menu_state.select == "ruleset" then
|
||||||
|
love.graphics.setColor(1, 1, 1, 0.5)
|
||||||
|
end
|
||||||
|
love.graphics.rectangle("fill", 340, 78 + 20 * self.menu_state.ruleset, 200, 22)
|
||||||
|
|
||||||
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
|
|
||||||
|
love.graphics.draw(misc_graphics["select_mode"], 20, 40)
|
||||||
|
|
||||||
|
love.graphics.setFont(font_3x5_2)
|
||||||
|
for idx, mode in pairs(game_modes) do
|
||||||
|
love.graphics.printf(mode.name, 40, 80 + 20 * idx, 200, "left")
|
||||||
|
end
|
||||||
|
for idx, ruleset in pairs(rulesets) do
|
||||||
|
love.graphics.printf(ruleset.name, 360, 80 + 20 * idx, 160, "left")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function ModeSelectScene:onKeyPress(e)
|
function ModeSelectScene:onKeyPress(e)
|
||||||
|
|||||||
@@ -3,6 +3,7 @@ local Object = require 'libs.classic'
|
|||||||
local Grid = Object:extend()
|
local Grid = Object:extend()
|
||||||
|
|
||||||
local empty = { skin = "", colour = "" }
|
local empty = { skin = "", colour = "" }
|
||||||
|
local oob = { skin = "", colour = "" }
|
||||||
|
|
||||||
function Grid:new()
|
function Grid:new()
|
||||||
self.grid = {}
|
self.grid = {}
|
||||||
@@ -26,8 +27,15 @@ function Grid:clear()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Grid:getCell(x, y)
|
||||||
|
if x < 1 or x > 10 or y > 24 then return oob
|
||||||
|
elseif y < 1 then return empty
|
||||||
|
else return self.grid[y][x]
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function Grid:isOccupied(x, y)
|
function Grid:isOccupied(x, y)
|
||||||
return self.grid[y+1][x+1] ~= empty
|
return self:getCell(x+1, y+1) ~= empty
|
||||||
end
|
end
|
||||||
|
|
||||||
function Grid:isRowFull(row)
|
function Grid:isRowFull(row)
|
||||||
@@ -46,7 +54,7 @@ function Grid:canPlacePiece(piece)
|
|||||||
for index, offset in pairs(offsets) do
|
for index, offset in pairs(offsets) do
|
||||||
local x = piece.position.x + offset.x
|
local x = piece.position.x + offset.x
|
||||||
local y = piece.position.y + offset.y
|
local y = piece.position.y + offset.y
|
||||||
if x >= 10 or x < 0 or y >= 24 or y < 0 or self.grid[y+1][x+1] ~= empty then
|
if self:isOccupied(x, y) then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -58,12 +66,12 @@ function Grid:canPlaceBigPiece(piece)
|
|||||||
for index, offset in pairs(offsets) do
|
for index, offset in pairs(offsets) do
|
||||||
local x = piece.position.x + offset.x
|
local x = piece.position.x + offset.x
|
||||||
local y = piece.position.y + offset.y
|
local y = piece.position.y + offset.y
|
||||||
if x >= 5 or x < 0 or y >= 12 or y < 0 or
|
if (
|
||||||
self.grid[y * 2 + 1][x * 2 + 1] ~= empty or
|
self:isOccupied(x * 2 + 0, y * 2 + 0)
|
||||||
self.grid[y * 2 + 1][x * 2 + 2] ~= empty or
|
or self:isOccupied(x * 2 + 1, y * 2 + 0)
|
||||||
self.grid[y * 2 + 2][x * 2 + 1] ~= empty or
|
or self:isOccupied(x * 2 + 0, y * 2 + 1)
|
||||||
self.grid[y * 2 + 2][x * 2 + 2] ~= empty
|
or self:isOccupied(x * 2 + 1, y * 2 + 1)
|
||||||
then
|
) then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -80,7 +88,7 @@ function Grid:canPlacePieceInVisibleGrid(piece)
|
|||||||
for index, offset in pairs(offsets) do
|
for index, offset in pairs(offsets) do
|
||||||
local x = piece.position.x + offset.x
|
local x = piece.position.x + offset.x
|
||||||
local y = piece.position.y + offset.y
|
local y = piece.position.y + offset.y
|
||||||
if x >= 10 or x < 0 or y >= 24 or y < 4 or self.grid[y+1][x+1] ~= empty then
|
if y < 4 or self:isOccupied(x, y) ~= empty then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -150,12 +158,14 @@ function Grid:applyPiece(piece)
|
|||||||
for index, offset in pairs(offsets) do
|
for index, offset in pairs(offsets) do
|
||||||
x = piece.position.x + offset.x
|
x = piece.position.x + offset.x
|
||||||
y = piece.position.y + offset.y
|
y = piece.position.y + offset.y
|
||||||
|
if y + 1 > 0 then
|
||||||
self.grid[y+1][x+1] = {
|
self.grid[y+1][x+1] = {
|
||||||
skin = piece.skin,
|
skin = piece.skin,
|
||||||
colour = piece.shape
|
colour = piece.shape
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function Grid:applyBigPiece(piece)
|
function Grid:applyBigPiece(piece)
|
||||||
offsets = piece:getBlockOffsets()
|
offsets = piece:getBlockOffsets()
|
||||||
@@ -164,6 +174,7 @@ function Grid:applyBigPiece(piece)
|
|||||||
y = piece.position.y + offset.y
|
y = piece.position.y + offset.y
|
||||||
for a = 1, 2 do
|
for a = 1, 2 do
|
||||||
for b = 1, 2 do
|
for b = 1, 2 do
|
||||||
|
if y*2+a > 0 then
|
||||||
self.grid[y*2+a][x*2+b] = {
|
self.grid[y*2+a][x*2+b] = {
|
||||||
skin = piece.skin,
|
skin = piece.skin,
|
||||||
colour = piece.shape
|
colour = piece.shape
|
||||||
@@ -172,6 +183,7 @@ function Grid:applyBigPiece(piece)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function Grid:update()
|
function Grid:update()
|
||||||
for y = 1, 24 do
|
for y = 1, 24 do
|
||||||
|
|||||||
@@ -77,15 +77,12 @@ function Piece:setRelativeRotation(rot)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
function Piece:moveInGrid(step, squares, grid, instant)
|
function Piece:moveInGrid(step, squares, grid)
|
||||||
local moved = false
|
local moved = false
|
||||||
for x = 1, squares do
|
for x = 1, squares do
|
||||||
if grid:canPlacePiece(self:withOffset(step)) then
|
if grid:canPlacePiece(self:withOffset(step)) then
|
||||||
moved = true
|
moved = true
|
||||||
self:setOffset(step)
|
self:setOffset(step)
|
||||||
if instant then
|
|
||||||
self:dropToBottom(grid)
|
|
||||||
end
|
|
||||||
else
|
else
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
@@ -100,7 +97,7 @@ end
|
|||||||
|
|
||||||
function Piece:dropToBottom(grid)
|
function Piece:dropToBottom(grid)
|
||||||
local piece_y = self.position.y
|
local piece_y = self.position.y
|
||||||
self:dropSquares(20, grid)
|
self:dropSquares(24, grid)
|
||||||
self.gravity = 0
|
self.gravity = 0
|
||||||
if self.position.y > piece_y then
|
if self.position.y > piece_y then
|
||||||
-- if it got dropped any, also reset lock delay
|
-- if it got dropped any, also reset lock delay
|
||||||
|
|||||||
365
tetris/modes/big_a2.lua
Executable file
365
tetris/modes/big_a2.lua
Executable file
@@ -0,0 +1,365 @@
|
|||||||
|
require 'funcs'
|
||||||
|
|
||||||
|
local GameMode = require 'tetris.modes.gamemode'
|
||||||
|
local Piece = require 'tetris.components.piece'
|
||||||
|
|
||||||
|
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
||||||
|
|
||||||
|
local MarathonA2Game = GameMode:extend()
|
||||||
|
|
||||||
|
MarathonA2Game.name = "Big A2"
|
||||||
|
MarathonA2Game.hash = "BigA2"
|
||||||
|
MarathonA2Game.tagline = "The points don't matter! Can you reach the invisible roll? Big mode too!"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
function MarathonA2Game:new()
|
||||||
|
MarathonA2Game.super:new()
|
||||||
|
self.big_mode = true
|
||||||
|
self.roll_frames = 0
|
||||||
|
self.combo = 1
|
||||||
|
self.randomizer = History6RollsRandomizer()
|
||||||
|
self.grade = 0
|
||||||
|
self.grade_points = 0
|
||||||
|
self.grade_point_decay_counter = 0
|
||||||
|
self.section_start_time = 0
|
||||||
|
self.section_times = { [0] = 0 }
|
||||||
|
self.section_tetrises = { [0] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 }
|
||||||
|
|
||||||
|
self.randomizer = History6RollsRandomizer()
|
||||||
|
|
||||||
|
self.lock_drop = false
|
||||||
|
self.enable_hold = false
|
||||||
|
self.next_queue_length = 1
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonA2Game:getARE()
|
||||||
|
if self.level < 700 then return 27
|
||||||
|
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 > 3694 then
|
||||||
|
self.completed = true
|
||||||
|
if self.grade == 32 then
|
||||||
|
self.grade = 33
|
||||||
|
end
|
||||||
|
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:updateSectionTimes(self.level, self.level + cleared_row_count)
|
||||||
|
self.level = math.min(self.level + cleared_row_count, 999)
|
||||||
|
if self.level == 999 and not self.clear then
|
||||||
|
self.clear = true
|
||||||
|
if self:qualifiesForMRoll() then
|
||||||
|
self.grade = 32
|
||||||
|
end
|
||||||
|
self.grid:clear()
|
||||||
|
self.roll_frames = -150
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonA2Game:updateScore(level, drop_bonus, cleared_lines)
|
||||||
|
cleared_lines = cleared_lines / 2
|
||||||
|
self:updateGrade(cleared_lines)
|
||||||
|
if cleared_lines > 0 then
|
||||||
|
self.score = self.score + (
|
||||||
|
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
||||||
|
cleared_lines * (cleared_lines * 2 - 1) * (self.combo * 2 - 1)
|
||||||
|
)
|
||||||
|
self.lines = self.lines + cleared_lines
|
||||||
|
self.combo = self.combo + cleared_lines - 1
|
||||||
|
else
|
||||||
|
self.drop_bonus = 0
|
||||||
|
self.combo = 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonA2Game:updateSectionTimes(old_level, new_level)
|
||||||
|
if self.clear then return end
|
||||||
|
if math.floor(old_level / 100) < math.floor(new_level / 100) or
|
||||||
|
new_level >= 999 then
|
||||||
|
-- record new section
|
||||||
|
section_time = self.frames - self.section_start_time
|
||||||
|
self.section_times[math.floor(old_level / 100)] = section_time
|
||||||
|
self.section_start_time = self.frames
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local grade_point_bonuses = {
|
||||||
|
{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, 18, 19
|
||||||
|
}
|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|
local tetris_requirements = { [0] = 2, 2, 2, 2, 2, 1, 1, 1, 1, 1 }
|
||||||
|
|
||||||
|
function MarathonA2Game:qualifiesForMRoll()
|
||||||
|
if not self.clear then return false end
|
||||||
|
-- tetris requirements
|
||||||
|
for section = 0, 9 do
|
||||||
|
if self.section_tetrises[section] < tetris_requirements[section] then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- section time requirements
|
||||||
|
local section_average = 0
|
||||||
|
for section = 0, 4 do
|
||||||
|
section_average = section_average + self.section_times[section]
|
||||||
|
if self.section_times[section] > frameTime(1,05) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
-- section time average requirements
|
||||||
|
if self.section_times[5] > section_average / 5 then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
for section = 6, 9 do
|
||||||
|
if self.section_times[section] > self.section_times[section - 1] + 120 then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if self.grade < 17 or self.frames > frameTime(8,45) then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonA2Game:getLetterGrade()
|
||||||
|
local grade = grade_conversion[self.grade]
|
||||||
|
if grade < 9 then
|
||||||
|
return tostring(9 - grade)
|
||||||
|
elseif grade < 18 then
|
||||||
|
return "S" .. tostring(grade - 8)
|
||||||
|
elseif grade == 18 then
|
||||||
|
return "M"
|
||||||
|
else
|
||||||
|
return "GM"
|
||||||
|
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
|
||||||
|
|
||||||
|
MarathonA2Game.mRollOpacityFunction = function(age)
|
||||||
|
if age > 4 then return 0
|
||||||
|
else return 1 - age / 4 end
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonA2Game:drawGrid(ruleset)
|
||||||
|
if self.clear and not (self.completed or self.game_over) then
|
||||||
|
if self:qualifiesForMRoll() then
|
||||||
|
self.grid:drawInvisible(self.mRollOpacityFunction)
|
||||||
|
else
|
||||||
|
self.grid:drawInvisible(self.rollOpacityFunction)
|
||||||
|
end
|
||||||
|
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)
|
||||||
|
love.graphics.printf(self:getLetterGrade(), 240, 140, 90, "left")
|
||||||
|
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
|
||||||
@@ -1,119 +0,0 @@
|
|||||||
require 'funcs'
|
|
||||||
|
|
||||||
local IntervalTrainingMode = require 'tetris.modes.interval_training'
|
|
||||||
local Piece = require 'tetris.components.piece'
|
|
||||||
|
|
||||||
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
|
||||||
|
|
||||||
local CreditsA3Game = IntervalTrainingMode:extend()
|
|
||||||
|
|
||||||
CreditsA3Game.name = "Credits A3"
|
|
||||||
CreditsA3Game.hash = "CreditsA3"
|
|
||||||
CreditsA3Game.tagline = "How consistently can you clear the Ti M-roll?"
|
|
||||||
|
|
||||||
function CreditsA3Game:new()
|
|
||||||
CreditsA3Game.super:new()
|
|
||||||
self.section_time_limit = 3238
|
|
||||||
self.norm = 0
|
|
||||||
self.section = 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function CreditsA3Game:advanceOneFrame(inputs, ruleset)
|
|
||||||
if self.frames == 0 then
|
|
||||||
switchBGM("credit_roll", "gm3")
|
|
||||||
end
|
|
||||||
if self.roll_frames > 0 then
|
|
||||||
self.roll_frames = self.roll_frames - 1
|
|
||||||
if self.roll_frames == 0 then
|
|
||||||
-- reset
|
|
||||||
self.norm = 0
|
|
||||||
self.frames = 0
|
|
||||||
self.grid:clear()
|
|
||||||
switchBGM("credit_roll", "gm3")
|
|
||||||
self:initializeOrHold(inputs, ruleset)
|
|
||||||
else
|
|
||||||
return false
|
|
||||||
end
|
|
||||||
elseif self.ready_frames == 0 then
|
|
||||||
self.frames = self.frames + 1
|
|
||||||
if self:getSectionTime() >= self.section_time_limit then
|
|
||||||
self.norm = self.norm + 16
|
|
||||||
self.piece = nil
|
|
||||||
if self.norm >= 60 then
|
|
||||||
self.section = self.section + 1
|
|
||||||
self.roll_frames = 150
|
|
||||||
else
|
|
||||||
self.game_over = true
|
|
||||||
switchBGM(nil)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
return true
|
|
||||||
end
|
|
||||||
|
|
||||||
function CreditsA3Game:onPieceEnter()
|
|
||||||
-- do nothing
|
|
||||||
end
|
|
||||||
|
|
||||||
function CreditsA3Game:onLineClear(cleared_row_count)
|
|
||||||
if not self.clear then
|
|
||||||
self.norm = self.norm + (cleared_row_count == 4 and 10 or cleared_row_count)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
CreditsA3Game.rollOpacityFunction = function(age)
|
|
||||||
if age > 4 then return 0
|
|
||||||
else return 1 - age / 4 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function CreditsA3Game:drawGrid(ruleset)
|
|
||||||
if not self.game_over and self.roll_frames < 30 then
|
|
||||||
self.grid:drawInvisible(self.rollOpacityFunction)
|
|
||||||
else
|
|
||||||
self.grid:draw()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function CreditsA3Game:drawScoringInfo()
|
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_2)
|
|
||||||
love.graphics.print(
|
|
||||||
self.das.direction .. " " ..
|
|
||||||
self.das.frames .. " " ..
|
|
||||||
st(self.prev_inputs)
|
|
||||||
)
|
|
||||||
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
|
||||||
love.graphics.printf("TIME LEFT", 240, 250, 80, "left")
|
|
||||||
love.graphics.printf("NORM", 240, 320, 40, "left")
|
|
||||||
|
|
||||||
self:drawSectionTimesWithSplits(self.section)
|
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
|
||||||
-- draw time left, flash red if necessary
|
|
||||||
local time_left = self.section_time_limit - math.max(self:getSectionTime(), 0)
|
|
||||||
|
|
||||||
if not self.game_over and not self.clear and time_left < sp(0,10) and time_left % 4 < 2 then
|
|
||||||
if self.norm >= 44 then
|
|
||||||
love.graphics.setColor(0.3, 1, 0.3, 1) -- flash green if goal has been cleared
|
|
||||||
else
|
|
||||||
love.graphics.setColor(1, 0.3, 0.3, 1) -- otherwise flash red
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
love.graphics.printf(formatTime(time_left), 240, 270, 160, "left")
|
|
||||||
|
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
|
||||||
love.graphics.printf(self.norm, 240, 340, 40, "right")
|
|
||||||
if self.game_over or self.roll_frames > 0 then
|
|
||||||
love.graphics.printf("60", 240, 370, 40, "right")
|
|
||||||
else
|
|
||||||
love.graphics.printf("44", 240, 370, 40, "right")
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function CreditsA3Game:getBackground()
|
|
||||||
return self.section
|
|
||||||
end
|
|
||||||
|
|
||||||
return CreditsA3Game
|
|
||||||
@@ -159,7 +159,7 @@ function DemonModeGame:updateSectionTimes(old_level, new_level)
|
|||||||
end
|
end
|
||||||
elseif old_level < 100 then
|
elseif old_level < 100 then
|
||||||
-- If section time is under cutoff, skip to level 500.
|
-- If section time is under cutoff, skip to level 500.
|
||||||
if self.frames < sp(1,00) then
|
if self.frames < frameTime(1,00) then
|
||||||
self.level = 500
|
self.level = 500
|
||||||
self.grade = 5
|
self.grade = 5
|
||||||
self.section_tries = 0
|
self.section_tries = 0
|
||||||
@@ -226,7 +226,7 @@ function DemonModeGame:drawScoringInfo()
|
|||||||
love.graphics.print(
|
love.graphics.print(
|
||||||
self.das.direction .. " " ..
|
self.das.direction .. " " ..
|
||||||
self.das.frames .. " " ..
|
self.das.frames .. " " ..
|
||||||
st(self.prev_inputs)
|
strTrueValues(self.prev_inputs)
|
||||||
)
|
)
|
||||||
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
||||||
love.graphics.printf("GRADE", 240, 120, 40, "left")
|
love.graphics.printf("GRADE", 240, 120, 40, "left")
|
||||||
|
|||||||
@@ -50,13 +50,6 @@ function GameMode:new()
|
|||||||
self.secondary_section_times = { [0] = 0 }
|
self.secondary_section_times = { [0] = 0 }
|
||||||
end
|
end
|
||||||
|
|
||||||
function GameMode:initialize()
|
|
||||||
-- after all the variables are initialized, run initialization procedures
|
|
||||||
for i = 1, 30 do
|
|
||||||
table.insert(self.next_queue, self:getNextPiece(ruleset))
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function GameMode:getARR() return 1 end
|
function GameMode:getARR() return 1 end
|
||||||
function GameMode:getDropSpeed() return 1 end
|
function GameMode:getDropSpeed() return 1 end
|
||||||
function GameMode:getARE() return 25 end
|
function GameMode:getARE() return 25 end
|
||||||
@@ -91,20 +84,10 @@ function GameMode:update(inputs, ruleset)
|
|||||||
if self.completed then return end
|
if self.completed then return end
|
||||||
|
|
||||||
-- advance one frame
|
-- advance one frame
|
||||||
if self:advanceOneFrame(inputs, ruleset) == false then return end
|
if self:advanceOneFrame(inputs) == false then return end
|
||||||
|
|
||||||
self:chargeDAS(inputs, self:getDasLimit(), self.getARR())
|
self:chargeDAS(inputs, self:getDasLimit(), self.getARR())
|
||||||
|
|
||||||
-- set attempt flags
|
|
||||||
if inputs["left"] or inputs["right"] then self:onAttemptPieceMove(self.piece) end
|
|
||||||
if
|
|
||||||
inputs["rotate_left"] or inputs["rotate_right"] or
|
|
||||||
inputs["rotate_left2"] or inputs["rotate_right2"] or
|
|
||||||
inputs["rotate_180"]
|
|
||||||
then
|
|
||||||
self:onAttemptPieceRotate(self.piece)
|
|
||||||
end
|
|
||||||
|
|
||||||
if self.piece == nil then
|
if self.piece == nil then
|
||||||
self:processDelays(inputs, ruleset)
|
self:processDelays(inputs, ruleset)
|
||||||
else
|
else
|
||||||
@@ -162,10 +145,6 @@ function GameMode:update(inputs, ruleset)
|
|||||||
|
|
||||||
local cleared_row_count = self.grid:getClearedRowCount()
|
local cleared_row_count = self.grid:getClearedRowCount()
|
||||||
|
|
||||||
if self.big_mode then
|
|
||||||
cleared_row_count = cleared_row_count / 2
|
|
||||||
end
|
|
||||||
|
|
||||||
self:onPieceLock(self.piece, cleared_row_count)
|
self:onPieceLock(self.piece, cleared_row_count)
|
||||||
self:updateScore(self.level, self.drop_bonus, cleared_row_count)
|
self:updateScore(self.level, self.drop_bonus, cleared_row_count)
|
||||||
|
|
||||||
@@ -208,8 +187,6 @@ end
|
|||||||
|
|
||||||
-- event functions
|
-- event functions
|
||||||
function GameMode:whilePieceActive() end
|
function GameMode:whilePieceActive() end
|
||||||
function GameMode:onAttemptPieceMove(piece) end
|
|
||||||
function GameMode:onAttemptPieceRotate(piece) end
|
|
||||||
function GameMode:onPieceLock(piece, cleared_row_count) end
|
function GameMode:onPieceLock(piece, cleared_row_count) end
|
||||||
function GameMode:onLineClear(cleared_row_count) end
|
function GameMode:onLineClear(cleared_row_count) end
|
||||||
function GameMode:onPieceEnter() end
|
function GameMode:onPieceEnter() end
|
||||||
@@ -227,25 +204,8 @@ function GameMode:onGameOver()
|
|||||||
switchBGM(nil)
|
switchBGM(nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
-- DAS functions
|
function GameMode:chargeDAS(inputs)
|
||||||
|
if inputs[self.das.direction] == true then
|
||||||
function GameMode:startRightDAS()
|
|
||||||
self.move = "right"
|
|
||||||
self.das = { direction = "right", frames = 0 }
|
|
||||||
if self:getDasLimit() == 0 then
|
|
||||||
self:continueDAS()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function GameMode:startLeftDAS()
|
|
||||||
self.move = "left"
|
|
||||||
self.das = { direction = "left", frames = 0 }
|
|
||||||
if self:getDasLimit() == 0 then
|
|
||||||
self:continueDAS()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function GameMode:continueDAS()
|
|
||||||
local das_frames = self.das.frames + 1
|
local das_frames = self.das.frames + 1
|
||||||
if das_frames >= self:getDasLimit() then
|
if das_frames >= self:getDasLimit() then
|
||||||
if self.das.direction == "left" then
|
if self.das.direction == "left" then
|
||||||
@@ -259,35 +219,16 @@ function GameMode:continueDAS()
|
|||||||
self.move = "none"
|
self.move = "none"
|
||||||
self.das.frames = das_frames
|
self.das.frames = das_frames
|
||||||
end
|
end
|
||||||
end
|
elseif inputs["right"] == true then
|
||||||
|
self.move = "right"
|
||||||
function GameMode:stopDAS()
|
self.das = { direction = "right", frames = 0 }
|
||||||
|
elseif inputs["left"] == true then
|
||||||
|
self.move = "left"
|
||||||
|
self.das = { direction = "left", frames = 0 }
|
||||||
|
else
|
||||||
self.move = "none"
|
self.move = "none"
|
||||||
self.das = { direction = "none", frames = -1 }
|
self.das = { direction = "none", frames = -1 }
|
||||||
end
|
end
|
||||||
|
|
||||||
function GameMode:chargeDAS(inputs)
|
|
||||||
if config["das_last_key"] then
|
|
||||||
if inputs["right"] == true and self.das.direction ~= "right" and not self.prev_inputs["right"] then
|
|
||||||
self:startRightDAS()
|
|
||||||
elseif inputs["left"] == true and self.das.direction ~= "left" and not self.prev_inputs["left"] then
|
|
||||||
self:startLeftDAS()
|
|
||||||
elseif inputs[self.das.direction] == true then
|
|
||||||
self:continueDAS()
|
|
||||||
else
|
|
||||||
self:stopDAS()
|
|
||||||
end
|
|
||||||
else -- default behaviour, das first key pressed
|
|
||||||
if inputs[self.das.direction] == true then
|
|
||||||
self:continueDAS()
|
|
||||||
elseif inputs["right"] == true then
|
|
||||||
self:startRightDAS()
|
|
||||||
elseif inputs["left"] == true then
|
|
||||||
self:startLeftDAS()
|
|
||||||
else
|
|
||||||
self:stopDAS()
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function GameMode:processDelays(inputs, ruleset, drop_speed)
|
function GameMode:processDelays(inputs, ruleset, drop_speed)
|
||||||
@@ -400,8 +341,8 @@ end
|
|||||||
function GameMode:drawNextQueue(ruleset)
|
function GameMode:drawNextQueue(ruleset)
|
||||||
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 = ruleset.spawn_positions[piece].x + offset.x
|
local x = offset.x + ruleset.spawn_positions[piece].x
|
||||||
local y = ruleset.spawn_positions[piece].y + offset.y
|
local y = offset.y + 4.7
|
||||||
love.graphics.draw(blocks[skin][piece], pos_x+x*16, pos_y+y*16)
|
love.graphics.draw(blocks[skin][piece], pos_x+x*16, pos_y+y*16)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -444,7 +385,8 @@ function GameMode:drawScoringInfo()
|
|||||||
love.graphics.print(
|
love.graphics.print(
|
||||||
self.das.direction .. " " ..
|
self.das.direction .. " " ..
|
||||||
self.das.frames .. " " ..
|
self.das.frames .. " " ..
|
||||||
st(self.prev_inputs)
|
strTrueValues(self.prev_inputs) ..
|
||||||
|
self.drop_bonus
|
||||||
)
|
)
|
||||||
|
|
||||||
love.graphics.setFont(font_8x11)
|
love.graphics.setFont(font_8x11)
|
||||||
@@ -454,7 +396,7 @@ end
|
|||||||
function GameMode:drawSectionTimes(current_section)
|
function GameMode:drawSectionTimes(current_section)
|
||||||
local section_x = 530
|
local section_x = 530
|
||||||
|
|
||||||
for section, time in ipairs(self.section_times) do
|
for section, time in pairs(self.section_times) do
|
||||||
if section > 0 then
|
if section > 0 then
|
||||||
love.graphics.printf(formatTime(time), section_x, 40 + 20 * section, 90, "left")
|
love.graphics.printf(formatTime(time), section_x, 40 + 20 * section, 90, "left")
|
||||||
end
|
end
|
||||||
@@ -463,7 +405,7 @@ function GameMode:drawSectionTimes(current_section)
|
|||||||
love.graphics.printf(formatTime(self.frames - self.section_start_time), section_x, 40 + 20 * current_section, 90, "left")
|
love.graphics.printf(formatTime(self.frames - self.section_start_time), section_x, 40 + 20 * current_section, 90, "left")
|
||||||
end
|
end
|
||||||
|
|
||||||
function GameMode:drawSectionTimesWithSecondary(current_section, section_colour_function)
|
function GameMode:drawSectionTimesWithSecondary(current_section)
|
||||||
local section_x = 530
|
local section_x = 530
|
||||||
local section_secondary_x = 440
|
local section_secondary_x = 440
|
||||||
|
|
||||||
@@ -474,9 +416,6 @@ function GameMode:drawSectionTimesWithSecondary(current_section, section_colour_
|
|||||||
end
|
end
|
||||||
|
|
||||||
for section, time in pairs(self.secondary_section_times) do
|
for section, time in pairs(self.secondary_section_times) do
|
||||||
if self.section_colour_function then
|
|
||||||
love.graphics.setColor(self:section_colour_function(section))
|
|
||||||
end
|
|
||||||
if section > 0 then
|
if section > 0 then
|
||||||
love.graphics.printf(formatTime(time), section_secondary_x, 40 + 20 * section, 90, "left")
|
love.graphics.printf(formatTime(time), section_secondary_x, 40 + 20 * section, 90, "left")
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -28,19 +28,19 @@ function IntervalTrainingGame:new()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function IntervalTrainingGame:getARE()
|
function IntervalTrainingGame:getARE()
|
||||||
return 6
|
return 4
|
||||||
end
|
end
|
||||||
|
|
||||||
function IntervalTrainingGame:getLineARE()
|
function IntervalTrainingGame:getLineARE()
|
||||||
return 6
|
return 4
|
||||||
end
|
end
|
||||||
|
|
||||||
function IntervalTrainingGame:getDasLimit()
|
function IntervalTrainingGame:getDasLimit()
|
||||||
return 7
|
return 6
|
||||||
end
|
end
|
||||||
|
|
||||||
function IntervalTrainingGame:getLineClearDelay()
|
function IntervalTrainingGame:getLineClearDelay()
|
||||||
return 4
|
return 6
|
||||||
end
|
end
|
||||||
|
|
||||||
function IntervalTrainingGame:getLockDelay()
|
function IntervalTrainingGame:getLockDelay()
|
||||||
@@ -120,7 +120,7 @@ function IntervalTrainingGame:drawScoringInfo()
|
|||||||
love.graphics.print(
|
love.graphics.print(
|
||||||
self.das.direction .. " " ..
|
self.das.direction .. " " ..
|
||||||
self.das.frames .. " " ..
|
self.das.frames .. " " ..
|
||||||
st(self.prev_inputs)
|
strTrueValues(self.prev_inputs)
|
||||||
)
|
)
|
||||||
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
||||||
love.graphics.printf("TIME LEFT", 240, 250, 80, "left")
|
love.graphics.printf("TIME LEFT", 240, 250, 80, "left")
|
||||||
@@ -130,15 +130,16 @@ function IntervalTrainingGame:drawScoringInfo()
|
|||||||
self:drawSectionTimesWithSplits(current_section)
|
self:drawSectionTimesWithSplits(current_section)
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
love.graphics.setFont(font_3x5_3)
|
||||||
|
love.graphics.printf(self.level, 240, 340, 40, "right")
|
||||||
|
|
||||||
-- draw time left, flash red if necessary
|
-- draw time left, flash red if necessary
|
||||||
local time_left = self.section_time_limit - math.max(self:getSectionTime(), 0)
|
local time_left = self.section_time_limit - math.max(self:getSectionTime(), 0)
|
||||||
if not self.game_over and not self.clear and time_left < sp(0,10) and time_left % 4 < 2 then
|
if not self.game_over and not self.clear and time_left < frameTime(0,10) and time_left % 4 < 2 then
|
||||||
love.graphics.setColor(1, 0.3, 0.3, 1)
|
love.graphics.setColor(1, 0.3, 0.3, 1)
|
||||||
end
|
end
|
||||||
love.graphics.printf(formatTime(time_left), 240, 270, 160, "left")
|
love.graphics.printf(formatTime(time_left), 240, 270, 160, "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:getSectionEndLevel(), 240, 370, 40, "right")
|
love.graphics.printf(self:getSectionEndLevel(), 240, 370, 40, "right")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
198
tetris/modes/konoha.lua
Executable file
198
tetris/modes/konoha.lua
Executable file
@@ -0,0 +1,198 @@
|
|||||||
|
require 'funcs'
|
||||||
|
|
||||||
|
local GameMode = require 'tetris.modes.gamemode'
|
||||||
|
local Piece = require 'tetris.components.piece'
|
||||||
|
|
||||||
|
local KonohaRandomizer = require 'tetris.randomizers.bag_konoha'
|
||||||
|
|
||||||
|
local KonohaGame = GameMode:extend()
|
||||||
|
|
||||||
|
KonohaGame.name = "All Clear A4"
|
||||||
|
KonohaGame.hash = "AllClearA4"
|
||||||
|
KonohaGame.tagline = "Get as many bravos as you can under the time limit!"
|
||||||
|
|
||||||
|
function KonohaGame:new()
|
||||||
|
KonohaGame.super:new()
|
||||||
|
|
||||||
|
self.randomizer = KonohaRandomizer()
|
||||||
|
self.bravos = 0
|
||||||
|
self.last_bonus_amount = 0
|
||||||
|
self.last_bonus_display_time = 0
|
||||||
|
self.time_limit = 10800
|
||||||
|
self.big_mode = true
|
||||||
|
|
||||||
|
self.enable_hold = true
|
||||||
|
self.next_queue_length = 3
|
||||||
|
end
|
||||||
|
|
||||||
|
function KonohaGame:getARE()
|
||||||
|
if self.level < 300 then return 30
|
||||||
|
elseif self.level < 400 then return 25
|
||||||
|
elseif self.level < 500 then return 20
|
||||||
|
elseif self.level < 600 then return 17
|
||||||
|
elseif self.level < 800 then return 15
|
||||||
|
elseif self.level < 900 then return 13
|
||||||
|
elseif self.level < 1000 then return 10
|
||||||
|
elseif self.level < 1300 then return 8
|
||||||
|
else return 6 end
|
||||||
|
end
|
||||||
|
|
||||||
|
function KonohaGame:getLineARE()
|
||||||
|
return self:getARE()
|
||||||
|
end
|
||||||
|
|
||||||
|
function KonohaGame:getDasLimit()
|
||||||
|
if self.level < 500 then return 10
|
||||||
|
elseif self.level < 800 then return 9
|
||||||
|
elseif self.level < 1000 then return 8
|
||||||
|
else return 7 end
|
||||||
|
end
|
||||||
|
|
||||||
|
function KonohaGame:getLineClearDelay()
|
||||||
|
if self.level < 200 then return 14
|
||||||
|
elseif self.level < 500 then return 9
|
||||||
|
elseif self.level < 800 then return 8
|
||||||
|
elseif self.level < 1000 then return 7
|
||||||
|
else return 6 end
|
||||||
|
end
|
||||||
|
|
||||||
|
function KonohaGame:getLockDelay()
|
||||||
|
if self.level < 500 then return 30
|
||||||
|
elseif self.level < 600 then return 25
|
||||||
|
elseif self.level < 700 then return 23
|
||||||
|
elseif self.level < 800 then return 20
|
||||||
|
elseif self.level < 900 then return 17
|
||||||
|
elseif self.level < 1000 then return 15
|
||||||
|
elseif self.level < 1200 then return 13
|
||||||
|
elseif self.level < 1300 then return 10
|
||||||
|
else return 8 end
|
||||||
|
end
|
||||||
|
|
||||||
|
function KonohaGame:getGravity()
|
||||||
|
if (self.level < 30) then return 4/256
|
||||||
|
elseif (self.level < 35) then return 8/256
|
||||||
|
elseif (self.level < 40) then return 12/256
|
||||||
|
elseif (self.level < 50) then return 16/256
|
||||||
|
elseif (self.level < 60) then return 32/256
|
||||||
|
elseif (self.level < 70) then return 48/256
|
||||||
|
elseif (self.level < 80) then return 64/256
|
||||||
|
elseif (self.level < 90) then return 128/256
|
||||||
|
elseif (self.level < 100) then return 192/256
|
||||||
|
elseif (self.level < 120) then return 1
|
||||||
|
elseif (self.level < 140) then return 2
|
||||||
|
elseif (self.level < 160) then return 3
|
||||||
|
elseif (self.level < 170) then return 4
|
||||||
|
elseif (self.level < 200) then return 5
|
||||||
|
else return 20 end
|
||||||
|
end
|
||||||
|
|
||||||
|
function KonohaGame:getSection()
|
||||||
|
return math.floor(level / 100) + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
function KonohaGame:getSectionEndLevel()
|
||||||
|
return math.floor(self.level / 100 + 1) * 100
|
||||||
|
end
|
||||||
|
|
||||||
|
function KonohaGame:advanceOneFrame()
|
||||||
|
if self.ready_frames == 0 then
|
||||||
|
self.time_limit = self.time_limit - 1
|
||||||
|
self.frames = self.frames + 1
|
||||||
|
end
|
||||||
|
if self.time_limit <= 0 then
|
||||||
|
self.game_over = true
|
||||||
|
end
|
||||||
|
self.last_bonus_display_time = self.last_bonus_display_time - 1
|
||||||
|
end
|
||||||
|
|
||||||
|
function KonohaGame:onPieceEnter()
|
||||||
|
if (self.level % 100 ~= 99) and self.frames ~= 0 then
|
||||||
|
self.level = self.level + 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function KonohaGame:drawGrid(ruleset)
|
||||||
|
self.grid:draw()
|
||||||
|
if self.piece ~= nil and self.level < 100 then
|
||||||
|
self:drawGhostPiece(ruleset)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local cleared_row_levels = {2, 4, 6, 12}
|
||||||
|
local bravo_bonus = {300, 480, 660, 900}
|
||||||
|
local non_bravo_bonus = {0, 0, 20, 40}
|
||||||
|
local bravo_ot_bonus = {0, 60, 120, 180}
|
||||||
|
|
||||||
|
function KonohaGame:onLineClear(cleared_row_count)
|
||||||
|
local oldtime = self.time_limit
|
||||||
|
|
||||||
|
self.level = self.level + cleared_row_levels[cleared_row_count / 2]
|
||||||
|
self.bravo = true
|
||||||
|
for i = 0, 23 - cleared_row_count do
|
||||||
|
for j = 0, 9 do
|
||||||
|
if self.grid:isOccupied(j, i) then
|
||||||
|
self.bravo = false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
if self.bravo then
|
||||||
|
self.bravos = self.bravos + 1
|
||||||
|
if self.level < 1000 then self.time_limit = self.time_limit + bravo_bonus[cleared_row_count / 2]
|
||||||
|
else self.time_limit = self.time_limit + bravo_ot_bonus[cleared_row_count / 2]
|
||||||
|
end
|
||||||
|
if self.bravos == 11 then self.randomizer.allowrepeat = true end
|
||||||
|
elseif self.level < 1000 then
|
||||||
|
self.time_limit = self.time_limit + non_bravo_bonus[cleared_row_count / 2]
|
||||||
|
end
|
||||||
|
|
||||||
|
local bonus = self.time_limit - oldtime
|
||||||
|
if bonus > 0 then
|
||||||
|
self.last_bonus_amount = bonus
|
||||||
|
self.last_bonus_display_time = 120
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function KonohaGame:getBackground()
|
||||||
|
return math.min(math.floor(self.level / 100), 9)
|
||||||
|
end
|
||||||
|
|
||||||
|
function KonohaGame:drawScoringInfo()
|
||||||
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
|
|
||||||
|
love.graphics.setFont(font_3x5_2)
|
||||||
|
love.graphics.print(
|
||||||
|
self.das.direction .. " " ..
|
||||||
|
self.das.frames .. " " ..
|
||||||
|
strTrueValues(self.prev_inputs)
|
||||||
|
)
|
||||||
|
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
||||||
|
love.graphics.printf("TIME LIMIT", 240, 120, 120, "left")
|
||||||
|
love.graphics.printf("BRAVOS", 240, 200, 50, "left")
|
||||||
|
love.graphics.printf("LEVEL", 240, 320, 40, "left")
|
||||||
|
|
||||||
|
love.graphics.setFont(font_3x5_3)
|
||||||
|
if not self.game_over and self.time_limit < frameTime(0,10) and self.time_limit % 4 < 2 then
|
||||||
|
love.graphics.setColor(1, 0.3, 0.3, 1)
|
||||||
|
end
|
||||||
|
love.graphics.printf(formatTime(self.time_limit), 240, 140, 120, "right")
|
||||||
|
if self.last_bonus_display_time > 0 then
|
||||||
|
love.graphics.printf("+"..formatTime(self.last_bonus_amount), 240, 160, 120, "right")
|
||||||
|
end
|
||||||
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
|
love.graphics.printf(self.bravos, 240, 220, 90, "left")
|
||||||
|
love.graphics.printf(self.level, 240, 340, 50, "right")
|
||||||
|
love.graphics.printf(self:getSectionEndLevel(), 240, 370, 50, "right")
|
||||||
|
|
||||||
|
love.graphics.setFont(font_8x11)
|
||||||
|
love.graphics.printf(formatTime(self.frames), 64, 420, 160, "center")
|
||||||
|
end
|
||||||
|
|
||||||
|
function KonohaGame:getHighscoreData()
|
||||||
|
return {
|
||||||
|
bravos = self.bravos,
|
||||||
|
level = self.level,
|
||||||
|
frames = self.frames,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
return KonohaGame
|
||||||
@@ -151,11 +151,11 @@ function Marathon2020Game:advanceOneFrame()
|
|||||||
end
|
end
|
||||||
|
|
||||||
local cool_cutoffs = {
|
local cool_cutoffs = {
|
||||||
sp(0,45,00), sp(0,41,50), sp(0,38,50), sp(0,35,00), sp(0,32,50),
|
frameTime(0,45,00), frameTime(0,41,50), frameTime(0,38,50), frameTime(0,35,00), frameTime(0,32,50),
|
||||||
sp(0,29,20), sp(0,27,20), sp(0,24,80), sp(0,22,80), sp(0,20,60),
|
frameTime(0,29,20), frameTime(0,27,20), frameTime(0,24,80), frameTime(0,22,80), frameTime(0,20,60),
|
||||||
sp(0,19,60), sp(0,19,40), sp(0,19,40), sp(0,18,40), sp(0,18,20),
|
frameTime(0,19,60), frameTime(0,19,40), frameTime(0,19,40), frameTime(0,18,40), frameTime(0,18,20),
|
||||||
sp(0,16,20), sp(0,16,20), sp(0,16,20), sp(0,16,20), sp(0,16,20),
|
frameTime(0,16,20), frameTime(0,16,20), frameTime(0,16,20), frameTime(0,16,20), frameTime(0,16,20),
|
||||||
sp(0,15,20)
|
frameTime(0,15,20)
|
||||||
}
|
}
|
||||||
|
|
||||||
local levels_for_cleared_rows = { 1, 2, 4, 6 }
|
local levels_for_cleared_rows = { 1, 2, 4, 6 }
|
||||||
@@ -284,11 +284,11 @@ function Marathon2020Game:sectionPassed(old_level, new_level)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Marathon2020Game:checkTorikan(section)
|
function Marathon2020Game:checkTorikan(section)
|
||||||
if section == 5 and self.frames < sp(6,00,00) then self.torikan_passed[500] = true end
|
if section == 5 and self.frames < frameTime(6,00,00) then self.torikan_passed[500] = true end
|
||||||
if section == 9 and self.frames < sp(8,30,00) then self.torikan_passed[900] = true end
|
if section == 9 and self.frames < frameTime(8,30,00) then self.torikan_passed[900] = true end
|
||||||
if section == 10 and self.frames < sp(8,45,00) then self.torikan_passed[1000] = true end
|
if section == 10 and self.frames < frameTime(8,45,00) then self.torikan_passed[1000] = true end
|
||||||
if section == 15 and self.frames < sp(11,30,00) then self.torikan_passed[1500] = true end
|
if section == 15 and self.frames < frameTime(11,30,00) then self.torikan_passed[1500] = true end
|
||||||
if section == 19 and self.frames < sp(13,15,00) then self.torikan_passed[1900] = true end
|
if section == 19 and self.frames < frameTime(13,15,00) then self.torikan_passed[1900] = true end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Marathon2020Game:checkClear(level)
|
function Marathon2020Game:checkClear(level)
|
||||||
@@ -323,9 +323,9 @@ function Marathon2020Game:checkClear(level)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Marathon2020Game:updateSectionTimes(old_level, new_level)
|
function Marathon2020Game:updateSectionTimes(old_level, new_level)
|
||||||
function sectionCool(section)
|
function sectionCool()
|
||||||
self.section_cool_count = self.section_cool_count + 1
|
self.section_cool_count = self.section_cool_count + 1
|
||||||
if section < 10 then self.delay_level = math.min(20, self.delay_level + 1) end
|
self.delay_level = math.min(20, self.delay_level + 1)
|
||||||
table.insert(self.section_status, "cool")
|
table.insert(self.section_status, "cool")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -343,7 +343,7 @@ function Marathon2020Game:updateSectionTimes(old_level, new_level)
|
|||||||
table.insert(self.section_times, section_time)
|
table.insert(self.section_times, section_time)
|
||||||
self.section_start_time = self.frames
|
self.section_start_time = self.frames
|
||||||
|
|
||||||
if section > 5 then self.delay_level = math.min(20, self.delay_level + 1) end
|
if section > 4 then self.delay_level = math.min(20, self.delay_level + 1) end
|
||||||
self:checkTorikan(section)
|
self:checkTorikan(section)
|
||||||
self:checkClear(new_level)
|
self:checkClear(new_level)
|
||||||
|
|
||||||
@@ -352,11 +352,11 @@ function Marathon2020Game:updateSectionTimes(old_level, new_level)
|
|||||||
self.secondary_section_times[section] < self.secondary_section_times[section - 1] + 120 and
|
self.secondary_section_times[section] < self.secondary_section_times[section - 1] + 120 and
|
||||||
self.secondary_section_times[section] < cool_cutoffs[section]
|
self.secondary_section_times[section] < cool_cutoffs[section]
|
||||||
) then
|
) then
|
||||||
sectionCool(section)
|
sectionCool()
|
||||||
elseif self.section_status[section - 1] == "cool" then
|
elseif self.section_status[section - 1] == "cool" then
|
||||||
table.insert(self.section_status, "none")
|
table.insert(self.section_status, "none")
|
||||||
elseif section <= 19 and self.secondary_section_times[section] < cool_cutoffs[section] then
|
elseif section <= 19 and self.secondary_section_times[section] < cool_cutoffs[section] then
|
||||||
sectionCool(section)
|
sectionCool()
|
||||||
else
|
else
|
||||||
table.insert(self.section_status, "none")
|
table.insert(self.section_status, "none")
|
||||||
end
|
end
|
||||||
@@ -417,14 +417,6 @@ function Marathon2020Game:drawGrid()
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Marathon2020Game:sectionColourFunction(section)
|
|
||||||
if self.section_status[section] == "cool" then
|
|
||||||
return { 0, 1, 0, 1 }
|
|
||||||
else
|
|
||||||
return { 1, 1, 1, 1 }
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function Marathon2020Game:drawScoringInfo()
|
function Marathon2020Game:drawScoringInfo()
|
||||||
Marathon2020Game.super.drawScoringInfo(self)
|
Marathon2020Game.super.drawScoringInfo(self)
|
||||||
|
|
||||||
@@ -436,7 +428,7 @@ function Marathon2020Game:drawScoringInfo()
|
|||||||
love.graphics.printf("GRADE PTS.", text_x, 200, 90, "left")
|
love.graphics.printf("GRADE PTS.", text_x, 200, 90, "left")
|
||||||
love.graphics.printf("LEVEL", text_x, 320, 40, "left")
|
love.graphics.printf("LEVEL", text_x, 320, 40, "left")
|
||||||
|
|
||||||
self:drawSectionTimesWithSecondary(current_section, self.sectionColourFunction)
|
self:drawSectionTimesWithSecondary(current_section)
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
love.graphics.setFont(font_3x5_3)
|
||||||
love.graphics.printf(self:getTotalGrade(), text_x, 120, 90, "left")
|
love.graphics.printf(self:getTotalGrade(), text_x, 120, 90, "left")
|
||||||
|
|||||||
@@ -12,6 +12,7 @@ MarathonA1Game.hash = "MarathonA1"
|
|||||||
MarathonA1Game.tagline = "Can you score enough points to reach the title of Grand Master?"
|
MarathonA1Game.tagline = "Can you score enough points to reach the title of Grand Master?"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function MarathonA1Game:new()
|
function MarathonA1Game:new()
|
||||||
MarathonA1Game.super:new()
|
MarathonA1Game.super:new()
|
||||||
|
|
||||||
@@ -130,8 +131,7 @@ function MarathonA1Game:onLineClear(cleared_row_count)
|
|||||||
self:checkGMRequirements(self.level, self.level + cleared_row_count)
|
self:checkGMRequirements(self.level, self.level + cleared_row_count)
|
||||||
if not self.clear then
|
if not self.clear then
|
||||||
local new_level = math.min(self.level + cleared_row_count, 999)
|
local new_level = math.min(self.level + cleared_row_count, 999)
|
||||||
if new_level == 999 then
|
if self.level == 999 then
|
||||||
self.level = 999
|
|
||||||
self.clear = true
|
self.clear = true
|
||||||
else
|
else
|
||||||
self.level = new_level
|
self.level = new_level
|
||||||
@@ -140,7 +140,6 @@ function MarathonA1Game:onLineClear(cleared_row_count)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA1Game:updateScore(level, drop_bonus, cleared_lines)
|
function MarathonA1Game:updateScore(level, drop_bonus, cleared_lines)
|
||||||
if self.clear then return 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
|
||||||
self.score = self.score + (
|
self.score = self.score + (
|
||||||
@@ -156,15 +155,15 @@ end
|
|||||||
|
|
||||||
function MarathonA1Game:checkGMRequirements(old_level, new_level)
|
function MarathonA1Game:checkGMRequirements(old_level, new_level)
|
||||||
if old_level < 300 and new_level >= 300 then
|
if old_level < 300 and new_level >= 300 then
|
||||||
if self.score > 12000 and self.frames <= sp(4,15) then
|
if self.score > 12000 and self.frames <= frameTime(4,15) then
|
||||||
self.gm_conditions["level300"] = true
|
self.gm_conditions["level300"] = true
|
||||||
end
|
end
|
||||||
elseif old_level < 500 and new_level >= 500 then
|
elseif old_level < 500 and new_level >= 500 then
|
||||||
if self.score > 40000 and self.frames <= sp(7,30) then
|
if self.score > 40000 and self.frames <= frameTime(7,30) then
|
||||||
self.gm_conditions["level500"] = true
|
self.gm_conditions["level500"] = true
|
||||||
end
|
end
|
||||||
elseif old_level < 999 and new_level >= 999 then
|
elseif old_level < 999 and new_level >= 999 then
|
||||||
if self.score > 126000 and self.frames <= sp(13,30) then
|
if self.score > 126000 and self.frames <= frameTime(13,30) then
|
||||||
self.gm_conditions["level900"] = true
|
self.gm_conditions["level900"] = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -185,7 +184,7 @@ function MarathonA1Game:drawScoringInfo()
|
|||||||
love.graphics.print(
|
love.graphics.print(
|
||||||
self.das.direction .. " " ..
|
self.das.direction .. " " ..
|
||||||
self.das.frames .. " " ..
|
self.das.frames .. " " ..
|
||||||
st(self.prev_inputs)
|
strTrueValues(self.prev_inputs)
|
||||||
)
|
)
|
||||||
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
||||||
love.graphics.printf("GRADE", 240, 120, 40, "left")
|
love.graphics.printf("GRADE", 240, 120, 40, "left")
|
||||||
|
|||||||
@@ -260,7 +260,7 @@ function MarathonA2Game:qualifiesForMRoll()
|
|||||||
local section_average = 0
|
local section_average = 0
|
||||||
for section = 0, 4 do
|
for section = 0, 4 do
|
||||||
section_average = section_average + self.section_times[section]
|
section_average = section_average + self.section_times[section]
|
||||||
if self.section_times[section] > sp(1,05) then
|
if self.section_times[section] > frameTime(1,05) then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -273,7 +273,7 @@ function MarathonA2Game:qualifiesForMRoll()
|
|||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
if self.grade < 17 or self.frames > sp(8,45) then
|
if self.grade < 17 or self.frames > frameTime(8,45) then
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
@@ -325,7 +325,7 @@ function MarathonA2Game:drawScoringInfo()
|
|||||||
love.graphics.print(
|
love.graphics.print(
|
||||||
self.das.direction .. " " ..
|
self.das.direction .. " " ..
|
||||||
self.das.frames .. " " ..
|
self.das.frames .. " " ..
|
||||||
st(self.prev_inputs)
|
strTrueValues(self.prev_inputs)
|
||||||
)
|
)
|
||||||
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
||||||
love.graphics.printf("GRADE", 240, 120, 40, "left")
|
love.graphics.printf("GRADE", 240, 120, 40, "left")
|
||||||
|
|||||||
@@ -160,13 +160,13 @@ function MarathonA3Game:onLineClear(cleared_row_count)
|
|||||||
end
|
end
|
||||||
|
|
||||||
local cool_cutoffs = {
|
local cool_cutoffs = {
|
||||||
sp(0,52), sp(0,52), sp(0,49), sp(0,45), sp(0,45),
|
frameTime(0,52), frameTime(0,52), frameTime(0,49), frameTime(0,45), frameTime(0,45),
|
||||||
sp(0,42), sp(0,42), sp(0,38), sp(0,38),
|
frameTime(0,42), frameTime(0,42), frameTime(0,38), frameTime(0,38),
|
||||||
}
|
}
|
||||||
|
|
||||||
local regret_cutoffs = {
|
local regret_cutoffs = {
|
||||||
sp(0,90), sp(0,75), sp(0,75), sp(0,68), sp(0,60),
|
frameTime(0,90), frameTime(0,75), frameTime(0,75), frameTime(0,68), frameTime(0,60),
|
||||||
sp(0,60), sp(0,50), sp(0,50), sp(0,50), sp(0,50),
|
frameTime(0,60), frameTime(0,50), frameTime(0,50), frameTime(0,50), frameTime(0,50),
|
||||||
}
|
}
|
||||||
|
|
||||||
function MarathonA3Game:updateSectionTimes(old_level, new_level)
|
function MarathonA3Game:updateSectionTimes(old_level, new_level)
|
||||||
@@ -372,7 +372,7 @@ function MarathonA3Game:drawScoringInfo()
|
|||||||
love.graphics.print(
|
love.graphics.print(
|
||||||
self.das.direction .. " " ..
|
self.das.direction .. " " ..
|
||||||
self.das.frames .. " " ..
|
self.das.frames .. " " ..
|
||||||
st(self.prev_inputs)
|
strTrueValues(self.prev_inputs)
|
||||||
)
|
)
|
||||||
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
||||||
love.graphics.printf("GRADE", 240, 120, 40, "left")
|
love.graphics.printf("GRADE", 240, 120, 40, "left")
|
||||||
|
|||||||
@@ -1,42 +0,0 @@
|
|||||||
require 'funcs'
|
|
||||||
|
|
||||||
local MarathonAX = require 'tetris.modes.marathon_ax'
|
|
||||||
local Piece = require 'tetris.components.piece'
|
|
||||||
|
|
||||||
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
|
||||||
|
|
||||||
local MarathonAX2Game = MarathonAX:extend()
|
|
||||||
|
|
||||||
MarathonAX2Game.name = "Marathon AX2"
|
|
||||||
MarathonAX2Game.hash = "MarathonAX2"
|
|
||||||
MarathonAX2Game.tagline = "Can you clear the time hurdles when the game goes this fast?"
|
|
||||||
|
|
||||||
|
|
||||||
function MarathonAX2Game:new()
|
|
||||||
MarathonAX2Game.super:new()
|
|
||||||
|
|
||||||
self.roll_frames = 0
|
|
||||||
self.randomizer = History6RollsRandomizer()
|
|
||||||
|
|
||||||
self.section_time_limit = 3600
|
|
||||||
self.section_start_time = 0
|
|
||||||
self.section_times = { [0] = 0 }
|
|
||||||
self.section_clear = false
|
|
||||||
|
|
||||||
self.lock_drop = true
|
|
||||||
self.enable_hold = true
|
|
||||||
self.next_queue_length = 3
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonAX2Game:getGravity()
|
|
||||||
if self.lines < 10 then return 84/256
|
|
||||||
elseif self.lines < 20 then return 1/2
|
|
||||||
elseif self.lines < 30 then return 1
|
|
||||||
elseif self.lines < 40 then return 2
|
|
||||||
elseif self.lines < 50 then return 3
|
|
||||||
elseif self.lines < 60 then return 4
|
|
||||||
elseif self.lines < 70 then return 5
|
|
||||||
else return 20 end
|
|
||||||
end
|
|
||||||
|
|
||||||
return MarathonAX2Game
|
|
||||||
@@ -1,35 +0,0 @@
|
|||||||
require 'funcs'
|
|
||||||
|
|
||||||
local MarathonAX = require 'tetris.modes.marathon_ax'
|
|
||||||
local Piece = require 'tetris.components.piece'
|
|
||||||
|
|
||||||
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
|
||||||
|
|
||||||
local MarathonAX3Game = MarathonAX:extend()
|
|
||||||
|
|
||||||
MarathonAX3Game.name = "Marathon AX3"
|
|
||||||
MarathonAX3Game.hash = "MarathonAX3"
|
|
||||||
MarathonAX3Game.tagline = "Can you clear the time hurdles when the game goes this fast?"
|
|
||||||
|
|
||||||
|
|
||||||
function MarathonAX3Game:new()
|
|
||||||
MarathonAX3Game.super:new()
|
|
||||||
|
|
||||||
self.roll_frames = 0
|
|
||||||
self.randomizer = History6RollsRandomizer()
|
|
||||||
|
|
||||||
self.section_time_limit = 3600
|
|
||||||
self.section_start_time = 0
|
|
||||||
self.section_times = { [0] = 0 }
|
|
||||||
self.section_clear = false
|
|
||||||
|
|
||||||
self.lock_drop = true
|
|
||||||
self.enable_hold = true
|
|
||||||
self.next_queue_length = 3
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonAX3Game:getGravity()
|
|
||||||
return 20
|
|
||||||
end
|
|
||||||
|
|
||||||
return MarathonAX3Game
|
|
||||||
@@ -5,19 +5,20 @@ local Piece = require 'tetris.components.piece'
|
|||||||
|
|
||||||
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
||||||
|
|
||||||
local MarathonAXGame = GameMode:extend()
|
local MarathonAX4Game = GameMode:extend()
|
||||||
|
|
||||||
MarathonAXGame.name = "Marathon AX"
|
MarathonAX4Game.name = "Marathon AX4"
|
||||||
MarathonAXGame.hash = "MarathonAX"
|
MarathonAX4Game.hash = "MarathonAX4"
|
||||||
MarathonAXGame.tagline = "Can you clear the time hurdles when the game goes this fast?"
|
MarathonAX4Game.tagline = "Can you clear the time hurdles when the game goes this fast?"
|
||||||
|
|
||||||
|
|
||||||
function MarathonAXGame:new()
|
function MarathonAX4Game:new()
|
||||||
MarathonAXGame.super:new()
|
MarathonAX4Game.super:new()
|
||||||
|
|
||||||
self.roll_frames = 0
|
self.roll_frames = 0
|
||||||
self.randomizer = History6RollsRandomizer()
|
self.randomizer = History6RollsRandomizer()
|
||||||
|
|
||||||
|
self.section_time_limit = 3600
|
||||||
self.section_start_time = 0
|
self.section_start_time = 0
|
||||||
self.section_times = { [0] = 0 }
|
self.section_times = { [0] = 0 }
|
||||||
self.section_clear = false
|
self.section_clear = false
|
||||||
@@ -27,48 +28,52 @@ function MarathonAXGame:new()
|
|||||||
self.next_queue_length = 3
|
self.next_queue_length = 3
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonAXGame:getSectionTimeLimit()
|
function MarathonAX4Game:getARE()
|
||||||
if self.lines < 20 then return 7200
|
if self.lines < 10 then return 18
|
||||||
else return 5400 end
|
elseif self.lines < 40 then return 14
|
||||||
|
elseif self.lines < 60 then return 12
|
||||||
|
elseif self.lines < 70 then return 10
|
||||||
|
elseif self.lines < 80 then return 8
|
||||||
|
elseif self.lines < 90 then return 7
|
||||||
|
else return 6 end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonAXGame:getARE()
|
function MarathonAX4Game:getLineARE()
|
||||||
return 27
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonAXGame:getLineARE()
|
|
||||||
return self:getARE()
|
return self:getARE()
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonAXGame:getDasLimit()
|
function MarathonAX4Game:getDasLimit()
|
||||||
return 15
|
if self.lines < 20 then return 10
|
||||||
|
elseif self.lines < 50 then return 9
|
||||||
|
elseif self.lines < 70 then return 8
|
||||||
|
else return 7 end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonAXGame:getLineClearDelay()
|
function MarathonAX4Game:getLineClearDelay()
|
||||||
return 40
|
if self.lines < 10 then return 14
|
||||||
|
elseif self.lines < 30 then return 9
|
||||||
|
else return 5 end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonAXGame:getLockDelay()
|
function MarathonAX4Game:getLockDelay()
|
||||||
return 30
|
if self.lines < 10 then return 28
|
||||||
|
elseif self.lines < 20 then return 24
|
||||||
|
elseif self.lines < 30 then return 22
|
||||||
|
elseif self.lines < 40 then return 20
|
||||||
|
elseif self.lines < 50 then return 18
|
||||||
|
elseif self.lines < 70 then return 14
|
||||||
|
else return 13 end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonAXGame:getGravity()
|
function MarathonAX4Game:getGravity()
|
||||||
if self.lines < 10 then return 4/256
|
return 20
|
||||||
elseif self.lines < 20 then return 12/256
|
|
||||||
elseif self.lines < 30 then return 48/256
|
|
||||||
elseif self.lines < 40 then return 72/256
|
|
||||||
elseif self.lines < 50 then return 96/256
|
|
||||||
elseif self.lines < 60 then return 1/2
|
|
||||||
elseif self.lines < 70 then return 1
|
|
||||||
elseif self.lines < 80 then return 3/2
|
|
||||||
elseif self.lines < 90 then return 2
|
|
||||||
elseif self.lines < 100 then return 3
|
|
||||||
elseif self.lines < 110 then return 4
|
|
||||||
elseif self.lines < 120 then return 5
|
|
||||||
else return 20 end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonAXGame:advanceOneFrame()
|
function MarathonAX4Game:getSection()
|
||||||
|
return math.floor(level / 100) + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonAX4Game:advanceOneFrame()
|
||||||
if self.clear then
|
if self.clear then
|
||||||
self.roll_frames = self.roll_frames + 1
|
self.roll_frames = self.roll_frames + 1
|
||||||
if self.roll_frames < 0 then
|
if self.roll_frames < 0 then
|
||||||
@@ -80,14 +85,14 @@ function MarathonAXGame:advanceOneFrame()
|
|||||||
if not self.section_clear then
|
if not self.section_clear then
|
||||||
self.frames = self.frames + 1
|
self.frames = self.frames + 1
|
||||||
end
|
end
|
||||||
if self:getSectionTime() >= self:getSectionTimeLimit() then
|
if self:getSectionTime() >= self.section_time_limit then
|
||||||
self.game_over = true
|
self.game_over = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonAXGame:onLineClear(cleared_row_count)
|
function MarathonAX4Game:onLineClear(cleared_row_count)
|
||||||
if not self.clear then
|
if not self.clear then
|
||||||
local new_lines = self.lines + cleared_row_count
|
local new_lines = self.lines + cleared_row_count
|
||||||
self:updateSectionTimes(self.lines, new_lines)
|
self:updateSectionTimes(self.lines, new_lines)
|
||||||
@@ -99,11 +104,11 @@ function MarathonAXGame:onLineClear(cleared_row_count)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonAXGame:getSectionTime()
|
function MarathonAX4Game:getSectionTime()
|
||||||
return self.frames - self.section_start_time
|
return self.frames - self.section_start_time
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonAXGame:updateSectionTimes(old_lines, new_lines)
|
function MarathonAX4Game:updateSectionTimes(old_lines, new_lines)
|
||||||
if math.floor(old_lines / 10) < math.floor(new_lines / 10) then
|
if math.floor(old_lines / 10) < math.floor(new_lines / 10) then
|
||||||
-- record new section
|
-- record new section
|
||||||
table.insert(self.section_times, self:getSectionTime())
|
table.insert(self.section_times, self:getSectionTime())
|
||||||
@@ -112,23 +117,23 @@ function MarathonAXGame:updateSectionTimes(old_lines, new_lines)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonAXGame:onPieceEnter()
|
function MarathonAX4Game:onPieceEnter()
|
||||||
self.section_clear = false
|
self.section_clear = false
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonAXGame:drawGrid(ruleset)
|
function MarathonAX4Game:drawGrid(ruleset)
|
||||||
self.grid:draw()
|
self.grid:draw()
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonAXGame:getHighscoreData()
|
function MarathonAX4Game:getHighscoreData()
|
||||||
return {
|
return {
|
||||||
lines = self.lines,
|
lines = self.lines,
|
||||||
frames = self.frames,
|
frames = self.frames,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonAXGame:drawScoringInfo()
|
function MarathonAX4Game:drawScoringInfo()
|
||||||
MarathonAXGame.super.drawScoringInfo(self)
|
MarathonAX4Game.super.drawScoringInfo(self)
|
||||||
|
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
|
|
||||||
@@ -136,7 +141,7 @@ function MarathonAXGame:drawScoringInfo()
|
|||||||
love.graphics.print(
|
love.graphics.print(
|
||||||
self.das.direction .. " " ..
|
self.das.direction .. " " ..
|
||||||
self.das.frames .. " " ..
|
self.das.frames .. " " ..
|
||||||
st(self.prev_inputs)
|
strTrueValues(self.prev_inputs)
|
||||||
)
|
)
|
||||||
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
||||||
love.graphics.printf("TIME LEFT", 240, 250, 80, "left")
|
love.graphics.printf("TIME LEFT", 240, 250, 80, "left")
|
||||||
@@ -150,20 +155,20 @@ function MarathonAXGame:drawScoringInfo()
|
|||||||
love.graphics.printf(self.clear and self.lines or self:getSectionEndLines(), 240, 370, 40, "right")
|
love.graphics.printf(self.clear and self.lines or self:getSectionEndLines(), 240, 370, 40, "right")
|
||||||
|
|
||||||
-- draw time left, flash red if necessary
|
-- draw time left, flash red if necessary
|
||||||
local time_left = self:getSectionTimeLimit() - math.max(self:getSectionTime(), 0)
|
local time_left = self.section_time_limit - math.max(self:getSectionTime(), 0)
|
||||||
if not self.game_over and not self.clear and time_left < sp(0,10) and time_left % 4 < 2 then
|
if not self.game_over and not self.clear and time_left < frameTime(0,10) and time_left % 4 < 2 then
|
||||||
love.graphics.setColor(1, 0.3, 0.3, 1)
|
love.graphics.setColor(1, 0.3, 0.3, 1)
|
||||||
end
|
end
|
||||||
love.graphics.printf(formatTime(time_left), 240, 270, 160, "left")
|
love.graphics.printf(formatTime(time_left), 240, 270, 160, "left")
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonAXGame:getSectionEndLines()
|
function MarathonAX4Game:getSectionEndLines()
|
||||||
return math.floor(self.lines / 10 + 1) * 10
|
return math.floor(self.lines / 10 + 1) * 10
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonAXGame:getBackground()
|
function MarathonAX4Game:getBackground()
|
||||||
return math.floor(self.lines / 10)
|
return math.floor(self.lines / 10)
|
||||||
end
|
end
|
||||||
|
|
||||||
return MarathonAXGame
|
return MarathonAX4Game
|
||||||
@@ -156,7 +156,7 @@ function MarathonC89Game:drawScoringInfo()
|
|||||||
love.graphics.print(
|
love.graphics.print(
|
||||||
self.das.direction .. " " ..
|
self.das.direction .. " " ..
|
||||||
self.das.frames .. " " ..
|
self.das.frames .. " " ..
|
||||||
st(self.prev_inputs)
|
strTrueValues(self.prev_inputs)
|
||||||
)
|
)
|
||||||
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
||||||
love.graphics.printf("LINES", 240, 120, 40, "left")
|
love.graphics.printf("LINES", 240, 120, 40, "left")
|
||||||
|
|||||||
@@ -1,133 +0,0 @@
|
|||||||
require 'funcs'
|
|
||||||
|
|
||||||
local GameMode = require 'tetris.modes.gamemode'
|
|
||||||
local Piece = require 'tetris.components.piece'
|
|
||||||
|
|
||||||
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
|
||||||
|
|
||||||
local MarathonWCBGame = GameMode:extend()
|
|
||||||
|
|
||||||
MarathonWCBGame.name = "Marathon WCB"
|
|
||||||
MarathonWCBGame.hash = "MarathonWCB"
|
|
||||||
MarathonWCBGame.tagline = "When all the pieces slip right to their destinations... can you keep up?"
|
|
||||||
|
|
||||||
|
|
||||||
function MarathonWCBGame:new()
|
|
||||||
MarathonWCBGame.super:new()
|
|
||||||
|
|
||||||
self.pieces = 0
|
|
||||||
self.randomizer = History6RollsRandomizer()
|
|
||||||
|
|
||||||
self.lock_drop = true
|
|
||||||
self.lock_hard_drop = true
|
|
||||||
self.instant_hard_drop = true
|
|
||||||
self.instant_soft_drop = true
|
|
||||||
self.enable_hold = false
|
|
||||||
self.next_queue_length = 3
|
|
||||||
|
|
||||||
self.piece_is_active = false
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonWCBGame:getDropSpeed()
|
|
||||||
return 20
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonWCBGame:getARR()
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonWCBGame:getARE()
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonWCBGame:getLineARE()
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonWCBGame:getDasLimit()
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonWCBGame:getLineClearDelay()
|
|
||||||
return 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonWCBGame:getLockDelay()
|
|
||||||
return math.huge
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonWCBGame:getGravity()
|
|
||||||
return self.piece_is_active and 20 or 0
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonWCBGame: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 MarathonWCBGame:onAttemptPieceMove()
|
|
||||||
if self.piece ~= nil then
|
|
||||||
-- don't let the piece move before it's finished dropping
|
|
||||||
self.piece:dropToBottom(self.grid)
|
|
||||||
end
|
|
||||||
self.piece_is_active = true
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonWCBGame:onAttemptPieceRotate()
|
|
||||||
self.piece_is_active = true
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonWCBGame:onPieceLock()
|
|
||||||
self.piece_is_active = false
|
|
||||||
self.pieces = self.pieces + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonWCBGame:onLineClear(cleared_row_count)
|
|
||||||
if not self.clear then
|
|
||||||
self.lines = self.lines + cleared_row_count
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonWCBGame:drawGrid(ruleset)
|
|
||||||
self.grid:draw()
|
|
||||||
if self.piece ~= nil then
|
|
||||||
self:drawGhostPiece(ruleset)
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonWCBGame:getHighscoreData()
|
|
||||||
return {
|
|
||||||
pieces = self.pieces,
|
|
||||||
frames = self.frames,
|
|
||||||
}
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonWCBGame:drawScoringInfo()
|
|
||||||
MarathonWCBGame.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, 160, 80, "left")
|
|
||||||
love.graphics.printf("pieces", text_x, 220, 80, "left")
|
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
|
||||||
love.graphics.printf(self.lines, text_x, 180, 80, "left")
|
|
||||||
love.graphics.printf(self.pieces, text_x, 240, 80, "left")
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonWCBGame:getBackground()
|
|
||||||
return (math.floor(self.pieces / 50) % 20)
|
|
||||||
end
|
|
||||||
|
|
||||||
return MarathonWCBGame
|
|
||||||
@@ -61,15 +61,15 @@ function PhantomManiaGame:getGravity()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function PhantomManiaGame:hitTorikan(old_level, new_level)
|
function PhantomManiaGame:hitTorikan(old_level, new_level)
|
||||||
if old_level < 300 and new_level >= 300 and self.frames > sp(2,28) then
|
if old_level < 300 and new_level >= 300 and self.frames > frameTime(2,28) then
|
||||||
self.level = 300
|
self.level = 300
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
if old_level < 500 and new_level >= 500 and self.frames > sp(3,38) then
|
if old_level < 500 and new_level >= 500 and self.frames > frameTime(3,38) then
|
||||||
self.level = 500
|
self.level = 500
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
if old_level < 800 and new_level >= 800 and self.frames > sp(5,23) then
|
if old_level < 800 and new_level >= 800 and self.frames > frameTime(5,23) then
|
||||||
self.level = 800
|
self.level = 800
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -86,19 +86,19 @@ function PhantomMania2Game:getNextPiece(ruleset)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function PhantomMania2Game:hitTorikan(old_level, new_level)
|
function PhantomMania2Game:hitTorikan(old_level, new_level)
|
||||||
if old_level < 300 and new_level >= 300 and self.frames > sp(2,02) then
|
if old_level < 300 and new_level >= 300 and self.frames > frameTime(2,02) then
|
||||||
self.level = 300
|
self.level = 300
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
if old_level < 500 and new_level >= 500 and self.frames > sp(3,03) then
|
if old_level < 500 and new_level >= 500 and self.frames > frameTime(3,03) then
|
||||||
self.level = 500
|
self.level = 500
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
if old_level < 800 and new_level >= 800 and self.frames > sp(4,45) then
|
if old_level < 800 and new_level >= 800 and self.frames > frameTime(4,45) then
|
||||||
self.level = 800
|
self.level = 800
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
if old_level < 1000 and new_level >= 1000 and self.frames > sp(5,38) then
|
if old_level < 1000 and new_level >= 1000 and self.frames > frameTime(5,38) then
|
||||||
self.level = 1000
|
self.level = 1000
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@@ -156,7 +156,7 @@ function PhantomMania2Game:onLineClear(cleared_row_count)
|
|||||||
end
|
end
|
||||||
self:advanceBottomRow(-cleared_row_count)
|
self:advanceBottomRow(-cleared_row_count)
|
||||||
else
|
else
|
||||||
self.roll_points = self.roll_points + cleared_row_points[cleared_row_count]
|
self.roll_points = self.roll_points + cleared_row_points[cleared_row_count / 2]
|
||||||
if self.roll_points >= 100 then
|
if self.roll_points >= 100 then
|
||||||
self.roll_points = self.roll_points - 100
|
self.roll_points = self.roll_points - 100
|
||||||
self.grade = self.grade + 1
|
self.grade = self.grade + 1
|
||||||
@@ -188,15 +188,15 @@ end
|
|||||||
|
|
||||||
|
|
||||||
local cool_cutoffs = {
|
local cool_cutoffs = {
|
||||||
sp(0,36), sp(0,36), sp(0,36), sp(0,36), sp(0,36),
|
frameTime(0,36), frameTime(0,36), frameTime(0,36), frameTime(0,36), frameTime(0,36),
|
||||||
sp(0,30), sp(0,30), sp(0,30), sp(0,30), sp(0,30),
|
frameTime(0,30), frameTime(0,30), frameTime(0,30), frameTime(0,30), frameTime(0,30),
|
||||||
sp(0,27), sp(0,27), sp(0,27),
|
frameTime(0,27), frameTime(0,27), frameTime(0,27),
|
||||||
}
|
}
|
||||||
|
|
||||||
local regret_cutoffs = {
|
local regret_cutoffs = {
|
||||||
sp(0,50), sp(0,50), sp(0,50), sp(0,50), sp(0,50),
|
frameTime(0,50), frameTime(0,50), frameTime(0,50), frameTime(0,50), frameTime(0,50),
|
||||||
sp(0,40), sp(0,40), sp(0,40), sp(0,40), sp(0,40),
|
frameTime(0,40), frameTime(0,40), frameTime(0,40), frameTime(0,40), frameTime(0,40),
|
||||||
sp(0,35), sp(0,35), sp(0,35),
|
frameTime(0,35), frameTime(0,35), frameTime(0,35),
|
||||||
}
|
}
|
||||||
|
|
||||||
function PhantomMania2Game:updateSectionTimes(old_level, new_level)
|
function PhantomMania2Game:updateSectionTimes(old_level, new_level)
|
||||||
@@ -234,7 +234,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.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()
|
||||||
|
|||||||
@@ -25,7 +25,7 @@ function Race40Game:new()
|
|||||||
self.lock_drop = true
|
self.lock_drop = true
|
||||||
self.lock_hard_drop = true
|
self.lock_hard_drop = true
|
||||||
self.instant_hard_drop = true
|
self.instant_hard_drop = true
|
||||||
self.instant_soft_drop = true
|
self.instant_soft_drop = false
|
||||||
self.enable_hold = true
|
self.enable_hold = true
|
||||||
self.next_queue_length = 3
|
self.next_queue_length = 3
|
||||||
end
|
end
|
||||||
@@ -39,11 +39,11 @@ function Race40Game:getARR()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Race40Game:getARE()
|
function Race40Game:getARE()
|
||||||
return 4
|
return 0
|
||||||
end
|
end
|
||||||
|
|
||||||
function Race40Game:getLineARE()
|
function Race40Game:getLineARE()
|
||||||
return 2
|
return self:getARE()
|
||||||
end
|
end
|
||||||
|
|
||||||
function Race40Game:getDasLimit()
|
function Race40Game:getDasLimit()
|
||||||
@@ -51,15 +51,15 @@ function Race40Game:getDasLimit()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Race40Game:getLineClearDelay()
|
function Race40Game:getLineClearDelay()
|
||||||
return 2
|
return 0
|
||||||
end
|
end
|
||||||
|
|
||||||
function Race40Game:getLockDelay()
|
function Race40Game:getLockDelay()
|
||||||
return 30
|
return 15
|
||||||
end
|
end
|
||||||
|
|
||||||
function Race40Game:getGravity()
|
function Race40Game:getGravity()
|
||||||
return 20
|
return 1/64
|
||||||
end
|
end
|
||||||
|
|
||||||
function Race40Game:advanceOneFrame()
|
function Race40Game:advanceOneFrame()
|
||||||
|
|||||||
@@ -102,15 +102,15 @@ function Survival2020Game:getNextPiece(ruleset)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Survival2020Game:hitTorikan(old_level, new_level)
|
function Survival2020Game:hitTorikan(old_level, new_level)
|
||||||
if old_level < 500 and new_level >= 500 and self.frames > sp(3,00) then
|
if old_level < 500 and new_level >= 500 and self.frames > frameTime(3,00) then
|
||||||
self.level = 500
|
self.level = 500
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
if old_level < 1000 and new_level >= 1000 and self.frames > sp(5,00) then
|
if old_level < 1000 and new_level >= 1000 and self.frames > frameTime(5,00) then
|
||||||
self.level = 1000
|
self.level = 1000
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
if old_level < 1500 and new_level >= 1500 and self.frames > sp(7,00) then
|
if old_level < 1500 and new_level >= 1500 and self.frames > frameTime(7,00) then
|
||||||
self.level = 1500
|
self.level = 1500
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@@ -193,7 +193,7 @@ function Survival2020Game:updateSectionTimes(old_level, new_level)
|
|||||||
section_time = self.frames - self.section_start_time
|
section_time = self.frames - self.section_start_time
|
||||||
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_time <= sp(0,30) then
|
if section_time <= frameTime(0,30) then
|
||||||
self.grade = self.grade + 2
|
self.grade = self.grade + 2
|
||||||
else
|
else
|
||||||
self.grade = self.grade + 1
|
self.grade = self.grade + 1
|
||||||
|
|||||||
@@ -125,15 +125,15 @@ end
|
|||||||
|
|
||||||
function SurvivalA1Game:checkGMRequirements(old_level, new_level)
|
function SurvivalA1Game:checkGMRequirements(old_level, new_level)
|
||||||
if old_level < 300 and new_level >= 300 then
|
if old_level < 300 and new_level >= 300 then
|
||||||
if self.score > 12000 and self.frames <= sp(4,15) then
|
if self.score > 12000 and self.frames <= frameTime(4,15) then
|
||||||
self.gm_conditions["level300"] = true
|
self.gm_conditions["level300"] = true
|
||||||
end
|
end
|
||||||
elseif old_level < 500 and new_level >= 500 then
|
elseif old_level < 500 and new_level >= 500 then
|
||||||
if self.score > 40000 and self.frames <= sp(7,30) then
|
if self.score > 40000 and self.frames <= frameTime(7,30) then
|
||||||
self.gm_conditions["level500"] = true
|
self.gm_conditions["level500"] = true
|
||||||
end
|
end
|
||||||
elseif old_level < 999 and new_level >= 999 then
|
elseif old_level < 999 and new_level >= 999 then
|
||||||
if self.score > 126000 and self.frames <= sp(13,30) then
|
if self.score > 126000 and self.frames <= frameTime(13,30) then
|
||||||
self.gm_conditions["level900"] = true
|
self.gm_conditions["level900"] = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -151,7 +151,7 @@ function SurvivalA1Game:drawScoringInfo()
|
|||||||
love.graphics.print(
|
love.graphics.print(
|
||||||
self.das.direction .. " " ..
|
self.das.direction .. " " ..
|
||||||
self.das.frames .. " " ..
|
self.das.frames .. " " ..
|
||||||
st(self.prev_inputs)
|
strTrueValues(self.prev_inputs)
|
||||||
)
|
)
|
||||||
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
||||||
love.graphics.printf("GRADE", 240, 120, 40, "left")
|
love.graphics.printf("GRADE", 240, 120, 40, "left")
|
||||||
|
|||||||
@@ -62,7 +62,7 @@ function SurvivalA2Game:getGravity()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function SurvivalA2Game:hitTorikan(old_level, new_level)
|
function SurvivalA2Game:hitTorikan(old_level, new_level)
|
||||||
if old_level < 500 and new_level >= 500 and self.frames > sp(3,25) then
|
if old_level < 500 and new_level >= 500 and self.frames > frameTime(3,25) then
|
||||||
self.level = 500
|
self.level = 500
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@@ -132,7 +132,7 @@ function SurvivalA2Game:drawScoringInfo()
|
|||||||
love.graphics.print(
|
love.graphics.print(
|
||||||
self.das.direction .. " " ..
|
self.das.direction .. " " ..
|
||||||
self.das.frames .. " " ..
|
self.das.frames .. " " ..
|
||||||
st(self.prev_inputs)
|
strTrueValues(self.prev_inputs)
|
||||||
)
|
)
|
||||||
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
||||||
love.graphics.printf("GRADE", text_x, 120, 40, "left")
|
love.graphics.printf("GRADE", text_x, 120, 40, "left")
|
||||||
|
|||||||
@@ -86,11 +86,11 @@ function SurvivalA3Game:getNextPiece(ruleset)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function SurvivalA3Game:hitTorikan(old_level, new_level)
|
function SurvivalA3Game:hitTorikan(old_level, new_level)
|
||||||
if old_level < 500 and new_level >= 500 and self.frames > sp(2,28) then
|
if old_level < 500 and new_level >= 500 and self.frames > frameTime(2,28) then
|
||||||
self.level = 500
|
self.level = 500
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
if old_level < 1000 and new_level >= 1000 and self.frames > sp(4,56) then
|
if old_level < 1000 and new_level >= 1000 and self.frames > frameTime(4,56) then
|
||||||
self.level = 1000
|
self.level = 1000
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
@@ -132,10 +132,10 @@ function SurvivalA3Game:onLineClear(cleared_row_count)
|
|||||||
if new_level >= 1300 or self:hitTorikan(self.level, new_level) then
|
if new_level >= 1300 or self:hitTorikan(self.level, new_level) then
|
||||||
if new_level >= 1300 then
|
if new_level >= 1300 then
|
||||||
self.level = 1300
|
self.level = 1300
|
||||||
self.big_mode = true
|
|
||||||
end
|
end
|
||||||
self.clear = true
|
self.clear = true
|
||||||
self.grid:clear()
|
self.grid:clear()
|
||||||
|
self.big_mode = true
|
||||||
self.roll_frames = -150
|
self.roll_frames = -150
|
||||||
else
|
else
|
||||||
self.level = math.min(new_level, 1300)
|
self.level = math.min(new_level, 1300)
|
||||||
@@ -168,7 +168,7 @@ function SurvivalA3Game:updateSectionTimes(old_level, new_level)
|
|||||||
section_time = self.frames - self.section_start_time
|
section_time = self.frames - self.section_start_time
|
||||||
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_time <= sp(1,00) then
|
if section_time <= frameTime(1,00) then
|
||||||
self.grade = self.grade + 1
|
self.grade = self.grade + 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -1,76 +0,0 @@
|
|||||||
require 'funcs'
|
|
||||||
|
|
||||||
local MarathonAX = require 'tetris.modes.marathon_ax'
|
|
||||||
local Piece = require 'tetris.components.piece'
|
|
||||||
|
|
||||||
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
|
||||||
|
|
||||||
local SurvivalAXGame = MarathonAX:extend()
|
|
||||||
|
|
||||||
SurvivalAXGame.name = "Survival AX"
|
|
||||||
SurvivalAXGame.hash = "SurvivalAX"
|
|
||||||
SurvivalAXGame.tagline = "Can you clear the time hurdles when the game goes this fast?"
|
|
||||||
|
|
||||||
|
|
||||||
function SurvivalAXGame:new()
|
|
||||||
SurvivalAXGame.super:new()
|
|
||||||
|
|
||||||
self.roll_frames = 0
|
|
||||||
self.randomizer = History6RollsRandomizer()
|
|
||||||
|
|
||||||
self.section_time_limit = 3600
|
|
||||||
self.section_start_time = 0
|
|
||||||
self.section_times = { [0] = 0 }
|
|
||||||
self.section_clear = false
|
|
||||||
|
|
||||||
self.lock_drop = true
|
|
||||||
self.enable_hold = true
|
|
||||||
self.next_queue_length = 3
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalAXGame:getSectionTimeLimit()
|
|
||||||
return 3600
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalAXGame:getARE()
|
|
||||||
if self.lines < 10 then return 18
|
|
||||||
elseif self.lines < 40 then return 14
|
|
||||||
elseif self.lines < 60 then return 12
|
|
||||||
elseif self.lines < 70 then return 10
|
|
||||||
elseif self.lines < 80 then return 8
|
|
||||||
elseif self.lines < 90 then return 7
|
|
||||||
else return 6 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalAXGame:getLineARE()
|
|
||||||
return self:getARE()
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalAXGame:getDasLimit()
|
|
||||||
if self.lines < 20 then return 10
|
|
||||||
elseif self.lines < 50 then return 9
|
|
||||||
elseif self.lines < 70 then return 8
|
|
||||||
else return 7 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalAXGame:getLineClearDelay()
|
|
||||||
if self.lines < 10 then return 14
|
|
||||||
elseif self.lines < 30 then return 8
|
|
||||||
else return 5 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalAXGame:getLockDelay()
|
|
||||||
if self.lines < 10 then return 30
|
|
||||||
elseif self.lines < 20 then return 26
|
|
||||||
elseif self.lines < 30 then return 24
|
|
||||||
elseif self.lines < 40 then return 22
|
|
||||||
elseif self.lines < 50 then return 20
|
|
||||||
elseif self.lines < 70 then return 16
|
|
||||||
else return 15 end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalAXGame:getGravity()
|
|
||||||
return 20
|
|
||||||
end
|
|
||||||
|
|
||||||
return SurvivalAXGame
|
|
||||||
@@ -1,59 +0,0 @@
|
|||||||
require 'funcs'
|
|
||||||
|
|
||||||
local MarathonAX2 = require 'tetris.modes.marathon_ax2'
|
|
||||||
local Piece = require 'tetris.components.piece'
|
|
||||||
|
|
||||||
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
|
||||||
|
|
||||||
local SurvivalAX2Game = MarathonAX2:extend()
|
|
||||||
|
|
||||||
SurvivalAX2Game.name = "Survival AX2"
|
|
||||||
SurvivalAX2Game.hash = "SurvivalAX2"
|
|
||||||
SurvivalAX2Game.tagline = "Can you clear the time hurdles when the game goes this fast?"
|
|
||||||
|
|
||||||
|
|
||||||
function SurvivalAX2Game:new()
|
|
||||||
SurvivalAX2Game.super:new()
|
|
||||||
|
|
||||||
self.roll_frames = 0
|
|
||||||
self.randomizer = History6RollsRandomizer()
|
|
||||||
|
|
||||||
self.section_time_limit = 3600
|
|
||||||
self.section_start_time = 0
|
|
||||||
self.section_times = { [0] = 0 }
|
|
||||||
self.section_clear = false
|
|
||||||
|
|
||||||
self.lock_drop = true
|
|
||||||
self.enable_hold = true
|
|
||||||
self.next_queue_length = 3
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalAX2Game:getSectionTimeLimit()
|
|
||||||
return 3600
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalAX2Game:getARE()
|
|
||||||
return 6
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalAX2Game:getLineARE()
|
|
||||||
return self:getARE()
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalAX2Game:getDasLimit()
|
|
||||||
return 7
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalAX2Game:getLineClearDelay()
|
|
||||||
return 5
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalAX2Game:getLockDelay()
|
|
||||||
return 15
|
|
||||||
end
|
|
||||||
|
|
||||||
function SurvivalAX2Game:getGravity()
|
|
||||||
return 20
|
|
||||||
end
|
|
||||||
|
|
||||||
return SurvivalAX2Game
|
|
||||||
17
tetris/randomizers/bag5.lua
Normal file
17
tetris/randomizers/bag5.lua
Normal file
@@ -0,0 +1,17 @@
|
|||||||
|
local Randomizer = require 'tetris.randomizers.randomizer'
|
||||||
|
|
||||||
|
local Bag5Randomizer = Randomizer:extend()
|
||||||
|
|
||||||
|
function Bag5Randomizer:initialize()
|
||||||
|
self.bag = {"I", "J", "L", "O", "T"}
|
||||||
|
end
|
||||||
|
|
||||||
|
function Bag5Randomizer:generatePiece()
|
||||||
|
if next(self.bag) == nil then
|
||||||
|
self.bag = {"I", "J", "L", "O", "T"}
|
||||||
|
end
|
||||||
|
local x = math.random(table.getn(self.bag))
|
||||||
|
return table.remove(self.bag, x)
|
||||||
|
end
|
||||||
|
|
||||||
|
return Bag5Randomizer
|
||||||
24
tetris/randomizers/bag5alt.lua
Executable file
24
tetris/randomizers/bag5alt.lua
Executable file
@@ -0,0 +1,24 @@
|
|||||||
|
local Randomizer = require 'tetris.randomizers.randomizer'
|
||||||
|
|
||||||
|
local Bag5AltRandomizer = Randomizer:extend()
|
||||||
|
|
||||||
|
function Bag5AltRandomizer:initialize()
|
||||||
|
self.bag = {"I", "J", "L", "O", "T"}
|
||||||
|
self.prev = nil
|
||||||
|
end
|
||||||
|
|
||||||
|
function Bag5AltRandomizer:generatePiece()
|
||||||
|
if next(self.bag) == nil then
|
||||||
|
self.bag = {"I", "J", "L", "O", "T"}
|
||||||
|
end
|
||||||
|
local x = math.random(table.getn(self.bag))
|
||||||
|
local temp = table.remove(self.bag, x)
|
||||||
|
if temp == self.prev then
|
||||||
|
local y = math.random(table.getn(self.bag))
|
||||||
|
temp = table.remove(self.bag, y)
|
||||||
|
end
|
||||||
|
self.prev = temp
|
||||||
|
return temp
|
||||||
|
end
|
||||||
|
|
||||||
|
return Bag5AltRandomizer
|
||||||
28
tetris/randomizers/bag_konoha.lua
Normal file
28
tetris/randomizers/bag_konoha.lua
Normal file
@@ -0,0 +1,28 @@
|
|||||||
|
local Randomizer = require 'tetris.randomizers.randomizer'
|
||||||
|
|
||||||
|
local BagKonoha = Randomizer:extend()
|
||||||
|
|
||||||
|
function BagKonoha:initialize()
|
||||||
|
self.bag = {"I", "J", "L", "O", "T"}
|
||||||
|
self.prev = nil
|
||||||
|
self.allowrepeat = false
|
||||||
|
self.generated = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function BagKonoha:generatePiece()
|
||||||
|
self.generated = self.generated + 1
|
||||||
|
if #self.bag == 0 then
|
||||||
|
self.bag = {"I", "J", "L", "O", "T"}
|
||||||
|
end
|
||||||
|
local x = math.random(#self.bag)
|
||||||
|
local temp = table.remove(self.bag, x)
|
||||||
|
if temp == self.prev and not self.allowrepeat then
|
||||||
|
local y = math.random(#self.bag)
|
||||||
|
table.insert(self.bag, temp) -- should insert at the end of the bag, bag[y] doesnt change
|
||||||
|
temp = table.remove(self.bag, y)
|
||||||
|
end
|
||||||
|
self.prev = temp
|
||||||
|
return temp
|
||||||
|
end
|
||||||
|
|
||||||
|
return BagKonoha
|
||||||
@@ -4,15 +4,10 @@ local Randomizer = Object:extend()
|
|||||||
|
|
||||||
function Randomizer:new()
|
function Randomizer:new()
|
||||||
self:initialize()
|
self:initialize()
|
||||||
self.next_queue = {}
|
|
||||||
for i = 1, 30 do
|
|
||||||
table.insert(self.next_queue, self:generatePiece())
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function Randomizer:nextPiece()
|
function Randomizer:nextPiece()
|
||||||
table.insert(self.next_queue, self:generatePiece())
|
return self:generatePiece()
|
||||||
return table.remove(self.next_queue, 1)
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function Randomizer:initialize()
|
function Randomizer:initialize()
|
||||||
|
|||||||
@@ -81,11 +81,19 @@ function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|||||||
piece.shape == "J" or piece.shape == "T" or piece.shape == "L"
|
piece.shape == "J" or piece.shape == "T" or piece.shape == "L"
|
||||||
) and (
|
) and (
|
||||||
piece.rotation == 0 or piece.rotation == 2
|
piece.rotation == 0 or piece.rotation == 2
|
||||||
) and (
|
) then
|
||||||
grid:isOccupied(piece.position.x, piece.position.y) or
|
local offsets = new_piece:getBlockOffsets()
|
||||||
grid:isOccupied(piece.position.x, piece.position.y - 1) or
|
table.sort(offsets, function(A, B) return A.y < B.y or A.y == B.y and A.x < B.y end)
|
||||||
grid:isOccupied(piece.position.x, piece.position.y - 2)
|
for index, offset in pairs(offsets) do
|
||||||
) then return end
|
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
|
||||||
|
|
||||||
-- 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
|
||||||
|
|||||||
164
tetris/rulesets/arika_ace.lua
Normal file → Executable file
164
tetris/rulesets/arika_ace.lua
Normal file → Executable file
@@ -1,14 +1,151 @@
|
|||||||
local ArikaTI = require 'tetris.rulesets.arika_ti'
|
local Piece = require 'tetris.components.piece'
|
||||||
|
local Ruleset = require 'tetris.rulesets.ruleset'
|
||||||
|
|
||||||
local ARS = ArikaTI:extend()
|
local ARS = Ruleset:extend()
|
||||||
|
|
||||||
ARS.name = "Ace-ARS"
|
ARS.name = "ACE-ARS"
|
||||||
ARS.hash = "ArikaAce"
|
ARS.hash = "ArikaACE"
|
||||||
|
|
||||||
|
ARS.spawn_positions = {
|
||||||
|
I = { x=5, y=2 },
|
||||||
|
J = { x=4, y=3 },
|
||||||
|
L = { x=4, y=3 },
|
||||||
|
O = { x=5, y=3 },
|
||||||
|
S = { x=4, y=3 },
|
||||||
|
T = { x=4, y=3 },
|
||||||
|
Z = { x=4, y=3 },
|
||||||
|
}
|
||||||
|
|
||||||
|
ARS.big_spawn_positions = {
|
||||||
|
I = { x=2, y=0 },
|
||||||
|
J = { x=2, y=1 },
|
||||||
|
L = { x=2, y=1 },
|
||||||
|
O = { x=2, y=1 },
|
||||||
|
S = { x=2, y=1 },
|
||||||
|
T = { x=2, y=1 },
|
||||||
|
Z = { x=2, y=1 },
|
||||||
|
}
|
||||||
|
|
||||||
|
ARS.block_offsets = {
|
||||||
|
I={
|
||||||
|
{ {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} },
|
||||||
|
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=0, y=2} },
|
||||||
|
{ {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} },
|
||||||
|
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=0, y=2} },
|
||||||
|
},
|
||||||
|
J={
|
||||||
|
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=-1, y=-1} },
|
||||||
|
{ {x=0, y=-1}, {x=1, y=-2}, {x=0, y=-2}, {x=0, y=0} },
|
||||||
|
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=1, y=0} },
|
||||||
|
{ {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=-1, y=0} },
|
||||||
|
},
|
||||||
|
L={
|
||||||
|
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=1, y=-1} },
|
||||||
|
{ {x=0, y=-2}, {x=0, y=-1}, {x=1, y=0}, {x=0, y=0} },
|
||||||
|
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=-1, y=0} },
|
||||||
|
{ {x=0, y=-1}, {x=-1, y=-2}, {x=0, y=-2}, {x=0, y=0} },
|
||||||
|
},
|
||||||
|
O={
|
||||||
|
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
|
||||||
|
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
|
||||||
|
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
|
||||||
|
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
|
||||||
|
},
|
||||||
|
S={
|
||||||
|
{ {x=1, y=-1}, {x=0, y=-1}, {x=0, y=0}, {x=-1, y=0} },
|
||||||
|
{ {x=-1, y=-2}, {x=-1, y=-1}, {x=0, y=-1}, {x=0, y=0} },
|
||||||
|
{ {x=1, y=-1}, {x=0, y=-1}, {x=0, y=0}, {x=-1, y=0} },
|
||||||
|
{ {x=-1, y=-2}, {x=-1, y=-1}, {x=0, y=-1}, {x=0, y=0} },
|
||||||
|
},
|
||||||
|
T={
|
||||||
|
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=0, y=-1} },
|
||||||
|
{ {x=0, y=-1}, {x=0, y=0}, {x=1, y=-1}, {x=0, y=-2} },
|
||||||
|
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=0, y=0} },
|
||||||
|
{ {x=0, y=-1}, {x=0, y=0}, {x=-1, y=-1}, {x=0, y=-2} },
|
||||||
|
},
|
||||||
|
Z={
|
||||||
|
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=0}, {x=0, y=0} },
|
||||||
|
{ {x=0, y=-1}, {x=0, y=0}, {x=1, y=-2}, {x=1, y=-1} },
|
||||||
|
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=0}, {x=0, y=0} },
|
||||||
|
{ {x=0, y=-1}, {x=0, y=0}, {x=1, y=-2}, {x=1, y=-1} },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
-- Component functions.
|
||||||
|
|
||||||
|
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 then
|
||||||
|
-- kick right, right2, left
|
||||||
|
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
|
||||||
|
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
|
||||||
|
self:onPieceRotate(piece, grid)
|
||||||
|
elseif grid:canPlacePiece(new_piece:withOffset({x=2, y=0})) then
|
||||||
|
piece:setRelativeRotation(rot_dir):setOffset({x=2, y=0})
|
||||||
|
self:onPieceRotate(piece, grid)
|
||||||
|
elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then
|
||||||
|
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
|
||||||
|
self:onPieceRotate(piece, grid)
|
||||||
|
end
|
||||||
|
elseif piece:isDropBlocked(grid) and (new_piece.rotation == 1 or new_piece.rotation == 3) and piece.floorkick == 0 then
|
||||||
|
-- kick up, up2
|
||||||
|
if grid:canPlacePiece(new_piece:withOffset({x=0, y=-1})) then
|
||||||
|
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
|
||||||
|
self:onPieceRotate(piece, grid)
|
||||||
|
piece.floorkick = 1
|
||||||
|
elseif grid:canPlacePiece(new_piece:withOffset({x=0, y=-2})) then
|
||||||
|
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-2})
|
||||||
|
self:onPieceRotate(piece, grid)
|
||||||
|
piece.floorkick = 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
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})
|
||||||
|
elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then
|
||||||
|
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
|
||||||
|
elseif piece.shape == "T"
|
||||||
|
and new_piece.rotation == 1
|
||||||
|
and piece.floorkick == 0
|
||||||
|
and grid:canPlacePiece(new_piece:withOffset({x=0, y=-1}))
|
||||||
|
then
|
||||||
|
-- T floorkick
|
||||||
|
piece.floorkick = piece.floorkick + 1
|
||||||
|
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
function ARS:onPieceCreate(piece, grid)
|
function ARS:onPieceCreate(piece, grid)
|
||||||
piece.floorkick = 0
|
piece.floorkick = 0
|
||||||
piece.rotate_counter = 0
|
piece.manipulations = 0
|
||||||
piece.move_counter = 0
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function ARS:onPieceDrop(piece, grid)
|
function ARS:onPieceDrop(piece, grid)
|
||||||
@@ -18,15 +155,24 @@ end
|
|||||||
function ARS:onPieceMove(piece, grid)
|
function ARS:onPieceMove(piece, grid)
|
||||||
piece.lock_delay = 0 -- move reset
|
piece.lock_delay = 0 -- move reset
|
||||||
if piece:isDropBlocked(grid) then
|
if piece:isDropBlocked(grid) then
|
||||||
piece.move_counter = piece.move_counter + 1
|
piece.manipulations = piece.manipulations + 1
|
||||||
if piece.move_counter >= 128 then
|
if piece.manipulations >= 127 then
|
||||||
piece.locked = true
|
piece.locked = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function ARS:onPieceRotate(piece, grid)
|
function ARS:onPieceRotate(piece, grid)
|
||||||
self:onPieceMove(piece, grid)
|
piece.lock_delay = 0 -- rotate reset
|
||||||
|
if piece:isDropBlocked(grid) then
|
||||||
|
piece.manipulations = piece.manipulations + 1
|
||||||
|
if piece.manipulations >= 127 then
|
||||||
|
piece.locked = true
|
||||||
|
end
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function ARS:get180RotationValue() return config["reverse_rotate"] and 1 or 3 end
|
||||||
|
function ARS:getDefaultOrientation() return 3 end -- downward facing pieces by default
|
||||||
|
|
||||||
return ARS
|
return ARS
|
||||||
177
tetris/rulesets/arika_srs.lua
Executable file
177
tetris/rulesets/arika_srs.lua
Executable file
@@ -0,0 +1,177 @@
|
|||||||
|
local Piece = require 'tetris.components.piece'
|
||||||
|
local Ruleset = require 'tetris.rulesets.ruleset'
|
||||||
|
|
||||||
|
local SRS = Ruleset:extend()
|
||||||
|
|
||||||
|
SRS.name = "ACE-SRS"
|
||||||
|
SRS.hash = "ACE Standard"
|
||||||
|
|
||||||
|
SRS.enable_IRS_wallkicks = true
|
||||||
|
|
||||||
|
SRS.spawn_positions = {
|
||||||
|
I = { x=5, y=2 },
|
||||||
|
J = { x=4, y=3 },
|
||||||
|
L = { x=4, y=3 },
|
||||||
|
O = { x=5, y=3 },
|
||||||
|
S = { x=4, y=3 },
|
||||||
|
T = { x=4, y=3 },
|
||||||
|
Z = { x=4, y=3 },
|
||||||
|
}
|
||||||
|
|
||||||
|
SRS.big_spawn_positions = {
|
||||||
|
I = { x=2, y=0 },
|
||||||
|
J = { x=2, y=1 },
|
||||||
|
L = { x=2, y=1 },
|
||||||
|
O = { x=2, y=1 },
|
||||||
|
S = { x=2, y=1 },
|
||||||
|
T = { x=2, y=1 },
|
||||||
|
Z = { x=2, y=1 },
|
||||||
|
}
|
||||||
|
|
||||||
|
SRS.block_offsets = {
|
||||||
|
I={
|
||||||
|
{ {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} },
|
||||||
|
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=0, y=2} },
|
||||||
|
{ {x=0, y=1}, {x=-1, y=1}, {x=-2, y=1}, {x=1, y=1} },
|
||||||
|
{ {x=-1, y=0}, {x=-1, y=-1}, {x=-1, y=1}, {x=-1, y=2} },
|
||||||
|
},
|
||||||
|
J={
|
||||||
|
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=-1, y=-1} },
|
||||||
|
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1} , {x=1, y=-1} },
|
||||||
|
{ {x=0, y=0}, {x=1, y=0}, {x=-1, y=0}, {x=1, y=1} },
|
||||||
|
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=-1}, {x=-1, y=1} },
|
||||||
|
},
|
||||||
|
L={
|
||||||
|
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=1, y=-1} },
|
||||||
|
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=1, y=1} },
|
||||||
|
{ {x=0, y=0}, {x=1, y=0}, {x=-1, y=0}, {x=-1, y=1} },
|
||||||
|
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=-1}, {x=-1, y=-1} },
|
||||||
|
},
|
||||||
|
O={
|
||||||
|
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
|
||||||
|
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
|
||||||
|
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
|
||||||
|
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
|
||||||
|
},
|
||||||
|
S={
|
||||||
|
{ {x=1, y=-1}, {x=0, y=-1}, {x=0, y=0}, {x=-1, y=0} },
|
||||||
|
{ {x=1, y=1}, {x=1, y=0}, {x=0, y=0}, {x=0, y=-1} },
|
||||||
|
{ {x=-1, y=1}, {x=0, y=1}, {x=0, y=0}, {x=1, y=0} },
|
||||||
|
{ {x=-1, y=-1}, {x=-1, y=0}, {x=0, y=0}, {x=0, y=1} },
|
||||||
|
},
|
||||||
|
T={
|
||||||
|
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=0, y=-1} },
|
||||||
|
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=1, y=0} },
|
||||||
|
{ {x=0, y=0}, {x=1, y=0}, {x=-1, y=0}, {x=0, y=1} },
|
||||||
|
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=-1}, {x=-1, y=0} },
|
||||||
|
},
|
||||||
|
Z={
|
||||||
|
{ {x=-1, y=-1}, {x=0, y=-1}, {x=0, y=0}, {x=1, y=0} },
|
||||||
|
{ {x=1, y=-1}, {x=1, y=0}, {x=0, y=0}, {x=0, y=1} },
|
||||||
|
{ {x=1, y=1}, {x=0, y=1}, {x=0, y=0}, {x=-1, y=0} },
|
||||||
|
{ {x=-1, y=1}, {x=-1, y=0}, {x=0, y=0}, {x=0, y=-1} },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
SRS.wallkicks_3x3 = {
|
||||||
|
[0]={
|
||||||
|
[1]={{x=-1, y=0}, {x=-1, y=-1}, {x=0, y=2}, {x=-1, y=2}},
|
||||||
|
[2]={{x=0, y=1}, {x=0, y=-1}},
|
||||||
|
[3]={{x=1, y=0}, {x=1, y=-1}, {x=0, y=2}, {x=1, y=2}},
|
||||||
|
},
|
||||||
|
[1]={
|
||||||
|
[0]={{x=1, y=0}, {x=1, y=1}, {x=0, y=-2}, {x=1, y=-2}},
|
||||||
|
[2]={{x=1, y=0}, {x=1, y=1}, {x=0, y=-2}, {x=1, y=-2}},
|
||||||
|
[3]={{x=0, y=1}, {x=0, y=-1}},
|
||||||
|
},
|
||||||
|
[2]={
|
||||||
|
[0]={{x=0, y=1}, {x=0, y=-1}},
|
||||||
|
[1]={{x=-1, y=0}, {x=-1, y=-1}, {x=0, y=2}, {x=-1, y=2}},
|
||||||
|
[3]={{x=1, y=0}, {x=1, y=-1}, {x=0, y=2}, {x=1, y=2}},
|
||||||
|
},
|
||||||
|
[3]={
|
||||||
|
[0]={{x=-1, y=0}, {x=-1, y=1}, {x=0, y=-2}, {x=-1, y=-2}},
|
||||||
|
[1]={{x=0, y=1}, {x=0, y=-1}},
|
||||||
|
[2]={{x=-1, y=0}, {x=-1, y=1}, {x=0, y=-2}, {x=-1, y=-2}},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
SRS.wallkicks_line = {
|
||||||
|
[0]={
|
||||||
|
[1]={{x=-2, y=0}, {x=1, y=0}, {x=-2, y=1}, {x=1, y=-2}},
|
||||||
|
[2]={},
|
||||||
|
[3]={{x=-1, y=0}, {x=2, y=0}, {x=-1, y=-2}, {x=2, y=1}},
|
||||||
|
},
|
||||||
|
[1]={
|
||||||
|
[0]={{x=2, y=0}, {x=-1, y=0}, {x=2, y=-1}, {x=-1, y=2}},
|
||||||
|
[2]={{x=-1, y=0}, {x=2, y=0}, {x=-1, y=-2}, {x=2, y=1}},
|
||||||
|
[3]={{x=0, y=1}, {x=0, y=-1}, {x=0, y=2}, {x=0, y=-2}},
|
||||||
|
},
|
||||||
|
[2]={
|
||||||
|
[0]={},
|
||||||
|
[1]={{x=1, y=0}, {x=-2, y=0}, {x=1, y=2}, {x=-2, y=-1}},
|
||||||
|
[3]={{x=2, y=0}, {x=-1, y=0}, {x=2, y=-1}, {x=-1, y=2}},
|
||||||
|
},
|
||||||
|
[3]={
|
||||||
|
[0]={{x=1, y=0}, {x=-2, y=0}, {x=1, y=2}, {x=-2, y=-1}},
|
||||||
|
[1]={{x=0, y=1}, {x=0, y=-1}, {x=0, y=2}, {x=0, y=-2}},
|
||||||
|
[2]={{x=-2, y=0}, {x=1, y=0}, {x=-2, y=1}, {x=1, y=-2}},
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
|
-- Component functions.
|
||||||
|
|
||||||
|
function SRS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||||
|
|
||||||
|
local kicks
|
||||||
|
if piece.shape == "O" then
|
||||||
|
return
|
||||||
|
elseif piece.shape == "I" then
|
||||||
|
kicks = SRS.wallkicks_line[piece.rotation][new_piece.rotation]
|
||||||
|
else
|
||||||
|
kicks = SRS.wallkicks_3x3[piece.rotation][new_piece.rotation]
|
||||||
|
end
|
||||||
|
|
||||||
|
assert(piece.rotation ~= new_piece.rotation)
|
||||||
|
|
||||||
|
for idx, offset in pairs(kicks) do
|
||||||
|
kicked_piece = new_piece:withOffset(offset)
|
||||||
|
if grid:canPlacePiece(kicked_piece) then
|
||||||
|
piece:setRelativeRotation(rot_dir)
|
||||||
|
piece:setOffset(offset)
|
||||||
|
self:onPieceRotate(piece, grid)
|
||||||
|
return
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function SRS:onPieceCreate(piece, grid)
|
||||||
|
piece.manipulations = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function SRS:onPieceDrop(piece, grid)
|
||||||
|
piece.lock_delay = 0 -- step reset
|
||||||
|
end
|
||||||
|
|
||||||
|
function SRS:onPieceMove(piece, grid)
|
||||||
|
piece.lock_delay = 0 -- move reset
|
||||||
|
if piece:isDropBlocked(grid) then
|
||||||
|
piece.manipulations = piece.manipulations + 1
|
||||||
|
if piece.manipulations >= 127 then
|
||||||
|
piece.locked = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function SRS:onPieceRotate(piece, grid)
|
||||||
|
piece.lock_delay = 0 -- rotate reset
|
||||||
|
if piece:isDropBlocked(grid) then
|
||||||
|
piece.manipulations = piece.manipulations + 1
|
||||||
|
if piece.manipulations >= 127 then
|
||||||
|
piece.locked = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return SRS
|
||||||
@@ -84,11 +84,19 @@ function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|||||||
piece.shape == "J" or piece.shape == "T" or piece.shape == "L"
|
piece.shape == "J" or piece.shape == "T" or piece.shape == "L"
|
||||||
) and (
|
) and (
|
||||||
piece.rotation == 0 or piece.rotation == 2
|
piece.rotation == 0 or piece.rotation == 2
|
||||||
) and (
|
) then
|
||||||
grid:isOccupied(piece.position.x, piece.position.y) or
|
local offsets = new_piece:getBlockOffsets()
|
||||||
grid:isOccupied(piece.position.x, piece.position.y - 1) or
|
table.sort(offsets, function(A, B) return A.y < B.y or A.y == B.y and A.x < B.y end)
|
||||||
grid:isOccupied(piece.position.x, piece.position.y - 2)
|
for index, offset in pairs(offsets) do
|
||||||
) then return end
|
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
|
if piece.shape == "I" then
|
||||||
-- special kick rules for I
|
-- special kick rules for I
|
||||||
@@ -116,12 +124,20 @@ function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|||||||
piece.floorkick = 1
|
piece.floorkick = 1
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif piece.shape ~= "I" then
|
else
|
||||||
-- kick right, kick left
|
-- kick right, kick left
|
||||||
if (grid:canPlacePiece(new_piece:withOffset({x=1, y=0}))) then
|
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
|
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
|
||||||
elseif (grid:canPlacePiece(new_piece:withOffset({x=-1, y=0}))) then
|
elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
|
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
|
||||||
|
elseif piece.shape == "T"
|
||||||
|
and new_piece.rotation == 1
|
||||||
|
and piece.floorkick == 0
|
||||||
|
and grid:canPlacePiece(new_piece:withOffset({x=0, y=-1}))
|
||||||
|
then
|
||||||
|
-- T floorkick
|
||||||
|
piece.floorkick = piece.floorkick + 1
|
||||||
|
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -398,7 +398,6 @@ function CRS:onPieceDrop(piece, grid)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function CRS:onPieceMove(piece, grid)
|
function CRS:onPieceMove(piece, grid)
|
||||||
piece.lock_delay = 0 -- move reset
|
|
||||||
if piece:isDropBlocked(grid) then
|
if piece:isDropBlocked(grid) then
|
||||||
piece.move_counter = piece.move_counter + 1
|
piece.move_counter = piece.move_counter + 1
|
||||||
if piece.move_counter >= 24 then
|
if piece.move_counter >= 24 then
|
||||||
@@ -408,7 +407,6 @@ function CRS:onPieceMove(piece, grid)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function CRS:onPieceRotate(piece, grid)
|
function CRS:onPieceRotate(piece, grid)
|
||||||
piece.lock_delay = 0 -- move reset
|
|
||||||
if piece:isDropBlocked(grid) then
|
if piece:isDropBlocked(grid) then
|
||||||
piece.rotate_counter = piece.rotate_counter + 1
|
piece.rotate_counter = piece.rotate_counter + 1
|
||||||
if piece.rotate_counter >= 12 then
|
if piece.rotate_counter >= 12 then
|
||||||
@@ -417,4 +415,6 @@ function CRS:onPieceRotate(piece, grid)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function CRS:getDefaultOrientation() return 1 end -- downward facing pieces by default
|
||||||
|
|
||||||
return CRS
|
return CRS
|
||||||
|
|||||||
@@ -56,16 +56,16 @@ function Ruleset:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|||||||
-- do nothing in default ruleset
|
-- do nothing in default ruleset
|
||||||
end
|
end
|
||||||
|
|
||||||
function Ruleset:movePiece(piece, grid, move, instant)
|
function Ruleset:movePiece(piece, grid, move)
|
||||||
local x = piece.position.x
|
local x = piece.position.x
|
||||||
if move == "left" then
|
if move == "left" then
|
||||||
piece:moveInGrid({x=-1, y=0}, 1, grid, false)
|
piece:moveInGrid({x=-1, y=0}, 1, grid)
|
||||||
elseif move == "right" then
|
|
||||||
piece:moveInGrid({x=1, y=0}, 1, grid, false)
|
|
||||||
elseif move == "speedleft" then
|
elseif move == "speedleft" then
|
||||||
piece:moveInGrid({x=-1, y=0}, 10, grid, instant)
|
piece:moveInGrid({x=-1, y=0}, 10, grid)
|
||||||
|
elseif move == "right" then
|
||||||
|
piece:moveInGrid({x=1, y=0}, 1, grid)
|
||||||
elseif move == "speedright" then
|
elseif move == "speedright" then
|
||||||
piece:moveInGrid({x=1, y=0}, 10, grid, instant)
|
piece:moveInGrid({x=1, y=0}, 10, grid)
|
||||||
end
|
end
|
||||||
if piece.position.x ~= x then
|
if piece.position.x ~= x then
|
||||||
self:onPieceMove(piece, grid)
|
self:onPieceMove(piece, grid)
|
||||||
@@ -138,7 +138,7 @@ function Ruleset:processPiece(
|
|||||||
hard_drop_enabled, additive_gravity
|
hard_drop_enabled, additive_gravity
|
||||||
)
|
)
|
||||||
self:rotatePiece(inputs, piece, grid, prev_inputs, false)
|
self:rotatePiece(inputs, piece, grid, prev_inputs, false)
|
||||||
self:movePiece(piece, grid, move, gravity >= 20)
|
self:movePiece(piece, grid, move)
|
||||||
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
|
||||||
|
|||||||
30
tetris/rulesets/standard.lua → tetris/rulesets/standard_exp.lua
Normal file → Executable file
30
tetris/rulesets/standard.lua → tetris/rulesets/standard_exp.lua
Normal file → Executable file
@@ -3,29 +3,29 @@ local Ruleset = require 'tetris.rulesets.ruleset'
|
|||||||
|
|
||||||
local SRS = Ruleset:extend()
|
local SRS = Ruleset:extend()
|
||||||
|
|
||||||
SRS.name = "SRS"
|
SRS.name = "Guideline SRS"
|
||||||
SRS.hash = "Standard"
|
SRS.hash = "Standard"
|
||||||
|
|
||||||
SRS.enable_IRS_wallkicks = true
|
SRS.enable_IRS_wallkicks = true
|
||||||
|
|
||||||
SRS.spawn_positions = {
|
SRS.spawn_positions = {
|
||||||
I = { x=5, y=4 },
|
I = { x=5, y=2 },
|
||||||
J = { x=4, y=5 },
|
J = { x=4, y=3 },
|
||||||
L = { x=4, y=5 },
|
L = { x=4, y=3 },
|
||||||
O = { x=5, y=5 },
|
O = { x=5, y=3 },
|
||||||
S = { x=4, y=5 },
|
S = { x=4, y=3 },
|
||||||
T = { x=4, y=5 },
|
T = { x=4, y=3 },
|
||||||
Z = { x=4, y=5 },
|
Z = { x=4, y=3 },
|
||||||
}
|
}
|
||||||
|
|
||||||
SRS.big_spawn_positions = {
|
SRS.big_spawn_positions = {
|
||||||
I = { x=2, y=2 },
|
I = { x=2, y=0 },
|
||||||
J = { x=2, y=3 },
|
J = { x=2, y=1 },
|
||||||
L = { x=2, y=3 },
|
L = { x=2, y=1 },
|
||||||
O = { x=2, y=3 },
|
O = { x=2, y=1 },
|
||||||
S = { x=2, y=3 },
|
S = { x=2, y=1 },
|
||||||
T = { x=2, y=3 },
|
T = { x=2, y=1 },
|
||||||
Z = { x=2, y=3 },
|
Z = { x=2, y=1 },
|
||||||
}
|
}
|
||||||
|
|
||||||
SRS.block_offsets = {
|
SRS.block_offsets = {
|
||||||
@@ -1,30 +0,0 @@
|
|||||||
local Standard = require 'tetris.rulesets.standard'
|
|
||||||
|
|
||||||
local SRS = Standard:extend()
|
|
||||||
|
|
||||||
SRS.name = "Ti-SRS"
|
|
||||||
SRS.hash = "StandardTI"
|
|
||||||
|
|
||||||
function SRS:onPieceMove(piece, grid)
|
|
||||||
piece.lock_delay = 0 -- move reset
|
|
||||||
if piece:isDropBlocked(grid) then
|
|
||||||
piece.move_counter = piece.move_counter + 1
|
|
||||||
if piece.move_counter >= 10 then
|
|
||||||
piece.locked = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SRS:onPieceRotate(piece, grid)
|
|
||||||
piece.lock_delay = 0 -- rotate reset
|
|
||||||
if piece:isDropBlocked(grid) then
|
|
||||||
piece.rotate_counter = piece.rotate_counter + 1
|
|
||||||
if piece.rotate_counter >= 8 then
|
|
||||||
piece.locked = true
|
|
||||||
end
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function SRS:get180RotationValue() return config["reverse_rotate"] and 1 or 3 end
|
|
||||||
|
|
||||||
return SRS
|
|
||||||
Reference in New Issue
Block a user