Compare commits
52 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
f31beffab8 | ||
|
|
2ff8fb5edc | ||
|
|
1bf8f91ef2 | ||
|
|
ba5f78d5f1 | ||
|
|
f7c4908062 | ||
|
|
3aa5bae7be | ||
|
|
40a2e78280 | ||
|
|
696da3fa3f | ||
|
|
4afe9f2bd4 | ||
|
|
1f686fb5d4 | ||
|
|
f4779c9847 | ||
|
|
06cbec4bc8 | ||
|
|
668564ffb0 | ||
|
|
e6edeea3d1 | ||
|
|
513cd6ba90 | ||
|
|
1beef8f157 | ||
|
|
d3b2b4c2d9 | ||
|
|
2b8b9d5084 | ||
|
|
2728780c45 | ||
|
|
ca592a3bcf | ||
|
|
b6f4158d70 | ||
|
|
e43f5c470a | ||
|
|
7bcdc517c0 | ||
|
|
1d30987f9a | ||
|
|
1dd46a11ef | ||
|
|
935c7aa14c | ||
|
|
aea115d953 | ||
|
|
3d5b33f41a | ||
|
|
29f07bb6ab | ||
|
|
891f96e814 | ||
|
|
36837a3af5 | ||
|
|
01b0f9f618 | ||
|
|
7c8c5bb11d | ||
|
|
acaa6bdbbf | ||
|
|
c37757f592 | ||
|
|
905e4bcc77 | ||
|
|
d956647678 | ||
|
|
10f032b49b | ||
|
|
5590e6c89b | ||
|
|
0393396d74 | ||
|
|
8c1eaec1aa | ||
|
|
957802a78e | ||
|
|
169a4e4d2f | ||
|
|
48aee18340 | ||
|
|
7b496d9412 | ||
|
|
7abb861446 | ||
|
|
21f8769228 | ||
|
|
44423fd2e8 | ||
|
|
6d326a142c | ||
|
|
b6f1072587 | ||
|
|
eef04ebf05 | ||
|
|
e24737a3b8 |
12
README.md
@@ -1,5 +1,11 @@
|
||||

|
||||
|
||||
Important notice
|
||||
================
|
||||
|
||||
Tetra Online was recently struck by an illegal DMCA claim from the Tetris Company.
|
||||
Please, spread awareness of this, and use the hashtag #DMCAgaming in your posts.
|
||||
|
||||
Cambridge
|
||||
=========
|
||||
|
||||
@@ -42,7 +48,7 @@ You do not need LÖVE on Windows, as it comes bundled with the program.
|
||||
|
||||
To get the stable release, simply download the ZIP in the latest release. All assets needed are bundled with the executable.
|
||||
|
||||
If you want the bleeding edge version, or want mod pack support, download [this](https://github.com/SashLilac/cambridge/archive/master.zip).
|
||||
If you want the bleeding edge version, download [this](https://github.com/SashLilac/cambridge/archive/master.zip).
|
||||
|
||||
Extract the ZIP, open a Command Prompt at the folder you extracted Cambridge to, then run this command:
|
||||
|
||||
@@ -74,9 +80,9 @@ It should run automatically!
|
||||
|
||||
## Installing modpacks
|
||||
|
||||
Simply drag your mode, ruleset, and randomizer Lua files into their respective directory, and they should appear automatically.
|
||||
Simply drag your mode, ruleset, and randomizer Lua files into their respective [directory](https://love2d.org/wiki/love.filesystem), and they should appear automatically.
|
||||
|
||||
Alternatively, install [this](https://github.com/SashLilac/cambridge-modpack) mod pack to get a taste of the mod potential.
|
||||
For more detailed instructions, install [this](https://github.com/SashLilac/cambridge-modpack) mod pack to get a taste of the mod potential.
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
10
SOURCES.md
@@ -8,7 +8,7 @@ Some of the assets are used without proper licenses. We aim to have fully licens
|
||||
Backgrounds
|
||||
-----------
|
||||
|
||||
1. Title: "Motus Glacies." Contributed by Daniel "Explo" McCarthy.
|
||||
1. Title: Original picrute found on the Wikipedia article for Cambridge
|
||||
|
||||
1. *Gameplay level 0: "Quantum foam." Alex Sukontsev. https://www.flickr.com/photos/control9/14957509814/
|
||||
2. *Gameplay level 1: No name. http://www.onekind.tv/univision-mqb/q5mqh5brlvuuj2nhdx7ch7eum183uu
|
||||
@@ -34,6 +34,14 @@ Backgrounds
|
||||
Backgrounds marked with a * are placeholders that will be replaced in later versions due to incompatible licenses. We are generally aiming for public domain background images, but will also accept backgrounds given proper licenses to be included within Cambridge.
|
||||
|
||||
|
||||
Sounds
|
||||
------
|
||||
|
||||
All piece sounds are (c) 2020 Damian Yerrick.
|
||||
Other sounds from:
|
||||
- NullpoMino
|
||||
- DTET, (c) 2003 Mihys.
|
||||
|
||||
Music
|
||||
-----
|
||||
|
||||
|
||||
@@ -1,27 +1,27 @@
|
||||
backgrounds = {
|
||||
[0] = love.graphics.newImage("res/backgrounds/0-quantum-foam.png"),
|
||||
love.graphics.newImage("res/backgrounds/100-big-bang.png"),
|
||||
love.graphics.newImage("res/backgrounds/200-spiral-galaxy.png"),
|
||||
love.graphics.newImage("res/backgrounds/300-sun-and-dust.png"),
|
||||
love.graphics.newImage("res/backgrounds/400-earth-and-moon.png"),
|
||||
love.graphics.newImage("res/backgrounds/500-cambrian-explosion.png"),
|
||||
love.graphics.newImage("res/backgrounds/600-dinosaurs.png"),
|
||||
love.graphics.newImage("res/backgrounds/700-asteroid.png"),
|
||||
love.graphics.newImage("res/backgrounds/800-human-fire.png"),
|
||||
love.graphics.newImage("res/backgrounds/900-early-civilization.png"),
|
||||
love.graphics.newImage("res/backgrounds/1000-vikings.png"),
|
||||
love.graphics.newImage("res/backgrounds/1100-crusades.png"),
|
||||
love.graphics.newImage("res/backgrounds/1200-genghis-khan.png"),
|
||||
love.graphics.newImage("res/backgrounds/1300-black-death.png"),
|
||||
love.graphics.newImage("res/backgrounds/1400-columbus-discovery.png"),
|
||||
love.graphics.newImage("res/backgrounds/1500-aztecas.png"),
|
||||
love.graphics.newImage("res/backgrounds/1600-telescope.png"),
|
||||
love.graphics.newImage("res/backgrounds/1700-american-revolution.png"),
|
||||
love.graphics.newImage("res/backgrounds/1800-railways.png"),
|
||||
love.graphics.newImage("res/backgrounds/1900-world-wide-web.png"),
|
||||
title = love.graphics.newImage("res/backgrounds/title_v0.1.png"),
|
||||
input_config = love.graphics.newImage("res/backgrounds/options-pcb.png"),
|
||||
game_config = love.graphics.newImage("res/backgrounds/options-gears.png"),
|
||||
[0] = love.graphics.newImage("res/backgrounds/0.png"),
|
||||
love.graphics.newImage("res/backgrounds/100.png"),
|
||||
love.graphics.newImage("res/backgrounds/200.png"),
|
||||
love.graphics.newImage("res/backgrounds/300.png"),
|
||||
love.graphics.newImage("res/backgrounds/400.png"),
|
||||
love.graphics.newImage("res/backgrounds/500.png"),
|
||||
love.graphics.newImage("res/backgrounds/600.png"),
|
||||
love.graphics.newImage("res/backgrounds/700.png"),
|
||||
love.graphics.newImage("res/backgrounds/800.png"),
|
||||
love.graphics.newImage("res/backgrounds/900.png"),
|
||||
love.graphics.newImage("res/backgrounds/1000.png"),
|
||||
love.graphics.newImage("res/backgrounds/1100.png"),
|
||||
love.graphics.newImage("res/backgrounds/1200.png"),
|
||||
love.graphics.newImage("res/backgrounds/1300.png"),
|
||||
love.graphics.newImage("res/backgrounds/1400.png"),
|
||||
love.graphics.newImage("res/backgrounds/1500.png"),
|
||||
love.graphics.newImage("res/backgrounds/1600.png"),
|
||||
love.graphics.newImage("res/backgrounds/1700.png"),
|
||||
love.graphics.newImage("res/backgrounds/1800.png"),
|
||||
love.graphics.newImage("res/backgrounds/1900.png"),
|
||||
title = love.graphics.newImage("res/backgrounds/title.png"),
|
||||
input_config = love.graphics.newImage("res/backgrounds/options-input.png"),
|
||||
game_config = love.graphics.newImage("res/backgrounds/options-game.png"),
|
||||
}
|
||||
|
||||
blocks = {
|
||||
|
||||
@@ -20,6 +20,8 @@ sounds = {
|
||||
fall = love.audio.newSource("res/se/fall.wav", "static"),
|
||||
ready = love.audio.newSource("res/se/ready.wav", "static"),
|
||||
go = love.audio.newSource("res/se/go.wav", "static"),
|
||||
irs = love.audio.newSource("res/se/irs.wav", "static"),
|
||||
ihs = love.audio.newSource("res/se/ihs.wav", "static"),
|
||||
}
|
||||
|
||||
function playSE(sound, subsound)
|
||||
@@ -30,7 +32,7 @@ function playSE(sound, subsound)
|
||||
end
|
||||
sounds[sound]:play()
|
||||
else
|
||||
sounds[sound][subsound]:setVolume(0.1)
|
||||
sounds[sound][subsound]:setVolume(0.6)
|
||||
if sounds[sound][subsound]:isPlaying() then
|
||||
sounds[sound][subsound]:stop()
|
||||
end
|
||||
|
||||
7
main.lua
@@ -15,7 +15,12 @@ function love.load()
|
||||
|
||||
love.window.setMode(love.graphics.getWidth(), love.graphics.getHeight(), {resizable = true});
|
||||
|
||||
if not config.gamesettings then config.gamesettings = {} end
|
||||
if not config.gamesettings then
|
||||
config.gamesettings = {}
|
||||
config["das_last_key"] = false
|
||||
else
|
||||
config["das_last_key"] = config.gamesettings.das_last_key == 2
|
||||
end
|
||||
for _, option in ipairs(GameConfigScene.options) do
|
||||
if not config.gamesettings[option[1]] then
|
||||
config.gamesettings[option[1]] = 1
|
||||
|
||||
4
release
@@ -4,6 +4,6 @@ mkdir dist/windows
|
||||
mkdir dist/win32
|
||||
cp cambridge.love dist/
|
||||
cat dist/windows/love.exe cambridge.love > dist/windows/cambridge.exe
|
||||
zip dist/cambridge-windows.zip dist/windows/* SOURCES.md LICENSE
|
||||
zip dist/cambridge-windows.zip dist/windows/* SOURCES.md LICENSE.md
|
||||
cat dist/win32/love.exe cambridge.love > dist/win32/cambridge.exe
|
||||
zip dist/cambridge-win32.zip dist/win32/* SOURCES.md LICENSE
|
||||
zip dist/cambridge-win32.zip dist/win32/* SOURCES.md LICENSE.md
|
||||
|
||||
0
res/backgrounds/0-quantum-foam.png → res/backgrounds/0.png
Executable file → Normal file
|
Before Width: | Height: | Size: 2.4 MiB After Width: | Height: | Size: 2.4 MiB |
0
res/backgrounds/100-big-bang.png → res/backgrounds/100.png
Executable file → Normal file
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
0
res/backgrounds/1000-vikings.png → res/backgrounds/1000.png
Executable file → Normal file
|
Before Width: | Height: | Size: 2.0 MiB After Width: | Height: | Size: 2.0 MiB |
0
res/backgrounds/1100-crusades.png → res/backgrounds/1100.png
Executable file → Normal file
|
Before Width: | Height: | Size: 2.9 MiB After Width: | Height: | Size: 2.9 MiB |
0
res/backgrounds/1200-genghis-khan.png → res/backgrounds/1200.png
Executable file → Normal file
|
Before Width: | Height: | Size: 2.1 MiB After Width: | Height: | Size: 2.1 MiB |
0
res/backgrounds/1300-black-death.png → res/backgrounds/1300.png
Executable file → Normal file
|
Before Width: | Height: | Size: 1.4 MiB After Width: | Height: | Size: 1.4 MiB |
0
res/backgrounds/1400-columbus-discovery.png → res/backgrounds/1400.png
Executable file → Normal file
|
Before Width: | Height: | Size: 2.6 MiB After Width: | Height: | Size: 2.6 MiB |
0
res/backgrounds/1500-aztecas.png → res/backgrounds/1500.png
Executable file → Normal file
|
Before Width: | Height: | Size: 2.1 MiB After Width: | Height: | Size: 2.1 MiB |
0
res/backgrounds/1600-telescope.png → res/backgrounds/1600.png
Executable file → Normal file
|
Before Width: | Height: | Size: 2.1 MiB After Width: | Height: | Size: 2.1 MiB |
0
res/backgrounds/1700-american-revolution.png → res/backgrounds/1700.png
Executable file → Normal file
|
Before Width: | Height: | Size: 2.1 MiB After Width: | Height: | Size: 2.1 MiB |
0
res/backgrounds/1800-railways.png → res/backgrounds/1800.png
Executable file → Normal file
|
Before Width: | Height: | Size: 2.4 MiB After Width: | Height: | Size: 2.4 MiB |
0
res/backgrounds/1900-world-wide-web.png → res/backgrounds/1900.png
Executable file → Normal file
|
Before Width: | Height: | Size: 1.9 MiB After Width: | Height: | Size: 1.9 MiB |
0
res/backgrounds/200-spiral-galaxy.png → res/backgrounds/200.png
Executable file → Normal file
|
Before Width: | Height: | Size: 1.6 MiB After Width: | Height: | Size: 1.6 MiB |
0
res/backgrounds/300-sun-and-dust.png → res/backgrounds/300.png
Executable file → Normal file
|
Before Width: | Height: | Size: 1.7 MiB After Width: | Height: | Size: 1.7 MiB |
0
res/backgrounds/400-earth-and-moon.png → res/backgrounds/400.png
Executable file → Normal file
|
Before Width: | Height: | Size: 2.0 MiB After Width: | Height: | Size: 2.0 MiB |
0
res/backgrounds/500-cambrian-explosion.png → res/backgrounds/500.png
Executable file → Normal file
|
Before Width: | Height: | Size: 2.1 MiB After Width: | Height: | Size: 2.1 MiB |
0
res/backgrounds/600-dinosaurs.png → res/backgrounds/600.png
Executable file → Normal file
|
Before Width: | Height: | Size: 3.1 MiB After Width: | Height: | Size: 3.1 MiB |
0
res/backgrounds/700-asteroid.png → res/backgrounds/700.png
Executable file → Normal file
|
Before Width: | Height: | Size: 1.2 MiB After Width: | Height: | Size: 1.2 MiB |
0
res/backgrounds/800-human-fire.png → res/backgrounds/800.png
Executable file → Normal file
|
Before Width: | Height: | Size: 2.7 MiB After Width: | Height: | Size: 2.7 MiB |
0
res/backgrounds/900-early-civilization.png → res/backgrounds/900.png
Executable file → Normal file
|
Before Width: | Height: | Size: 3.6 MiB After Width: | Height: | Size: 3.6 MiB |
|
Before Width: | Height: | Size: 2.9 MiB After Width: | Height: | Size: 2.9 MiB |
|
Before Width: | Height: | Size: 3.0 MiB After Width: | Height: | Size: 3.0 MiB |
|
Before Width: | Height: | Size: 1.3 MiB After Width: | Height: | Size: 1.3 MiB |
BIN
res/se/ihs.wav
Normal file
BIN
res/se/irs.wav
Normal file
@@ -68,6 +68,10 @@ function GameScene:render()
|
||||
|
||||
self.game:drawCustom()
|
||||
|
||||
love.graphics.setFont(font_3x5_2)
|
||||
if config.gamesettings.display_gamemode == 1 then
|
||||
love.graphics.printf(self.game.name .. " - " .. self.ruleset.name, 0, 460, 640, "left")
|
||||
end
|
||||
end
|
||||
|
||||
function GameScene:onInputPress(e)
|
||||
|
||||
@@ -9,6 +9,11 @@ ConfigScene.options = {
|
||||
{"manlock", "Manual locking",{"Per ruleset","Per gamemode","Harddrop", "Softdrop"}},
|
||||
{"piece_colour", "Piece Colours", {"Per ruleset","Arika" ,"TTC"}},
|
||||
{"world_reverse","A Button Rotation", {"Left" ,"Auto" ,"Right"}},
|
||||
{"display_gamemode", "Display Gamemode", {"On", "Off"}},
|
||||
{"next_se", "Next Piece SFX", {"On", "Off"}},
|
||||
{"das_last_key", "DAS Switch", {"Default", "Instant"}},
|
||||
{"synchroes_allowed", "Synchroes", {"Per ruleset", "On", "Off"}},
|
||||
{"diagonal_input", "Diagonal Input", {"On", "Off"}}
|
||||
}
|
||||
local optioncount = #ConfigScene.options
|
||||
|
||||
@@ -24,6 +29,7 @@ function ConfigScene:new()
|
||||
end
|
||||
|
||||
function ConfigScene:update()
|
||||
config["das_last_key"] = config.gamesettings.das_last_key == 2
|
||||
end
|
||||
|
||||
function ConfigScene:render()
|
||||
|
||||
@@ -32,6 +32,7 @@ function ConfigScene:new()
|
||||
self.input_state = 1
|
||||
self.set_inputs = newSetInputs()
|
||||
self.new_input = {}
|
||||
self.axis_timer = 0
|
||||
|
||||
DiscordRPC:update({
|
||||
details = "In menus",
|
||||
@@ -63,6 +64,8 @@ function ConfigScene:render()
|
||||
love.graphics.print("press key or joystick input for " .. configurable_inputs[self.input_state] .. ", tab to skip" .. (config.input and ", escape to cancel" or ""), 0, 0)
|
||||
love.graphics.print("function keys (F1, F2, etc.), escape, and tab can't be changed", 0, 20)
|
||||
end
|
||||
|
||||
self.axis_timer = self.axis_timer + 1
|
||||
end
|
||||
|
||||
local function addJoystick(input, name)
|
||||
@@ -118,7 +121,7 @@ function ConfigScene:onInputPress(e)
|
||||
self.new_input.joysticks[e.name].buttons[e.button] = configurable_inputs[self.input_state]
|
||||
self.input_state = self.input_state + 1
|
||||
elseif e.type == "joyaxis" then
|
||||
if math.abs(e.value) >= 0.5 then
|
||||
if (e.axis ~= self.last_axis or self.axis_timer > 30) and math.abs(e.value) >= 1 then
|
||||
addJoystick(self.new_input, e.name)
|
||||
if not self.new_input.joysticks[e.name].axes then
|
||||
self.new_input.joysticks[e.name].axes = {}
|
||||
@@ -128,10 +131,12 @@ function ConfigScene:onInputPress(e)
|
||||
end
|
||||
self.set_inputs[configurable_inputs[self.input_state]] =
|
||||
"jaxis " ..
|
||||
(e.value >= 0.5 and "+" or "-") .. e.axis ..
|
||||
(e.value >= 1 and "+" or "-") .. e.axis ..
|
||||
" " .. string.sub(e.name, 1, 10) .. (string.len(e.name) > 10 and "..." or "")
|
||||
self.new_input.joysticks[e.name].axes[e.axis][e.value >= 0.5 and "positive" or "negative"] = configurable_inputs[self.input_state]
|
||||
self.new_input.joysticks[e.name].axes[e.axis][e.value >= 1 and "positive" or "negative"] = configurable_inputs[self.input_state]
|
||||
self.input_state = self.input_state + 1
|
||||
self.last_axis = e.axis
|
||||
self.axis_timer = 0
|
||||
end
|
||||
elseif e.type == "joyhat" then
|
||||
if e.direction ~= "c" then
|
||||
|
||||
@@ -78,12 +78,15 @@ function Piece:setRelativeRotation(rot)
|
||||
return self
|
||||
end
|
||||
|
||||
function Piece:moveInGrid(step, squares, grid)
|
||||
function Piece:moveInGrid(step, squares, grid, instant)
|
||||
local moved = false
|
||||
for x = 1, squares do
|
||||
if grid:canPlacePiece(self:withOffset(step)) then
|
||||
moved = true
|
||||
self:setOffset(step)
|
||||
if instant then
|
||||
self:dropToBottom(grid)
|
||||
end
|
||||
else
|
||||
break
|
||||
end
|
||||
|
||||
@@ -46,6 +46,11 @@ function GameMode:new()
|
||||
self.irs = true
|
||||
self.ihs = true
|
||||
self.rpc_details = "In game"
|
||||
self.SGnames = {
|
||||
"9", "8", "7", "6", "5", "4", "3", "2", "1",
|
||||
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
|
||||
"GM"
|
||||
}
|
||||
-- variables related to configurable parameters
|
||||
self.drop_locked = false
|
||||
self.hard_drop_locked = false
|
||||
@@ -95,11 +100,31 @@ function GameMode:update(inputs, ruleset)
|
||||
end
|
||||
if self.completed then return end
|
||||
|
||||
if config.gamesettings.diagonal_input == 2 then
|
||||
if inputs["left"] or inputs["right"] then
|
||||
inputs["up"] = false
|
||||
inputs["down"] = false
|
||||
elseif inputs["up"] or inputs["down"] then
|
||||
inputs["left"] = false
|
||||
inputs["right"] = false
|
||||
end
|
||||
end
|
||||
|
||||
-- advance one frame
|
||||
if self:advanceOneFrame(inputs) == false then return end
|
||||
if self:advanceOneFrame(inputs, ruleset) == false then return end
|
||||
|
||||
self:chargeDAS(inputs, self:getDasLimit(), self.getARR())
|
||||
|
||||
-- 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
|
||||
self:processDelays(inputs, ruleset)
|
||||
else
|
||||
@@ -200,6 +225,8 @@ end
|
||||
|
||||
-- event functions
|
||||
function GameMode:whilePieceActive() end
|
||||
function GameMode:onAttemptPieceMove(piece) end
|
||||
function GameMode:onAttemptPieceRotate(piece) end
|
||||
function GameMode:onPieceLock(piece, cleared_row_count)
|
||||
playSE("lock")
|
||||
end
|
||||
@@ -207,9 +234,7 @@ end
|
||||
function GameMode:onLineClear(cleared_row_count) end
|
||||
|
||||
function GameMode:onPieceEnter() end
|
||||
function GameMode:onHold()
|
||||
playSE("hold")
|
||||
end
|
||||
function GameMode:onHold() end
|
||||
|
||||
function GameMode:onSoftDrop(dropped_row_count)
|
||||
self.drop_bonus = self.drop_bonus + 1 * dropped_row_count
|
||||
@@ -223,30 +248,66 @@ function GameMode:onGameOver()
|
||||
switchBGM(nil)
|
||||
end
|
||||
|
||||
function GameMode:chargeDAS(inputs)
|
||||
if inputs[self.das.direction] == true then
|
||||
local das_frames = self.das.frames + 1
|
||||
if das_frames >= self:getDasLimit() then
|
||||
if self.das.direction == "left" then
|
||||
self.move = (self:getARR() == 0 and "speed" or "") .. "left"
|
||||
self.das.frames = self:getDasLimit() - self:getARR()
|
||||
elseif self.das.direction == "right" then
|
||||
self.move = (self:getARR() == 0 and "speed" or "") .. "right"
|
||||
self.das.frames = self:getDasLimit() - self:getARR()
|
||||
end
|
||||
else
|
||||
self.move = "none"
|
||||
self.das.frames = das_frames
|
||||
-- DAS functions
|
||||
|
||||
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
|
||||
if das_frames >= self:getDasLimit() then
|
||||
if self.das.direction == "left" then
|
||||
self.move = (self:getARR() == 0 and "speed" or "") .. "left"
|
||||
self.das.frames = self:getDasLimit() - self:getARR()
|
||||
elseif self.das.direction == "right" then
|
||||
self.move = (self:getARR() == 0 and "speed" or "") .. "right"
|
||||
self.das.frames = self:getDasLimit() - self:getARR()
|
||||
end
|
||||
elseif inputs["right"] == true then
|
||||
self.move = "right"
|
||||
self.das = { direction = "right", frames = 0 }
|
||||
elseif inputs["left"] == true then
|
||||
self.move = "left"
|
||||
self.das = { direction = "left", frames = 0 }
|
||||
else
|
||||
self.move = "none"
|
||||
self.das = { direction = "none", frames = -1 }
|
||||
self.das.frames = das_frames
|
||||
end
|
||||
end
|
||||
|
||||
function GameMode:stopDAS()
|
||||
self.move = "none"
|
||||
self.das = { direction = "none", frames = -1 }
|
||||
end
|
||||
|
||||
function GameMode:chargeDAS(inputs)
|
||||
if config["das_last_key"] then
|
||||
if inputs["right"] == true and self.das.direction ~= "right" and not self.prev_inputs["right"] then
|
||||
self:startRightDAS()
|
||||
elseif inputs["left"] == true and self.das.direction ~= "left" and not self.prev_inputs["left"] then
|
||||
self:startLeftDAS()
|
||||
elseif inputs[self.das.direction] == true then
|
||||
self:continueDAS()
|
||||
else
|
||||
self:stopDAS()
|
||||
end
|
||||
else -- default behaviour, das first key pressed
|
||||
if inputs[self.das.direction] == true then
|
||||
self:continueDAS()
|
||||
elseif inputs["right"] == true then
|
||||
self:startRightDAS()
|
||||
elseif inputs["left"] == true then
|
||||
self:startLeftDAS()
|
||||
else
|
||||
self:stopDAS()
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -270,6 +331,18 @@ function GameMode:processDelays(inputs, ruleset, drop_speed)
|
||||
end
|
||||
elseif self.lcd > 0 then
|
||||
self.lcd = self.lcd - 1
|
||||
if ruleset.are_cancel and
|
||||
(self.move == "none" and not self.prev_inputs["up"] and
|
||||
not self.prev_inputs["rotate_left"] and not self.prev_inputs["rotate_left2"] and
|
||||
not self.prev_inputs["rotate_right"] and not self.prev_inputs["rotate_right2"] and
|
||||
not self.prev_inputs["rotate_180"]) and
|
||||
(inputs["left"] or inputs["right"] or inputs["up"] or
|
||||
inputs["rotate_left"] or inputs["rotate_left2"] or
|
||||
inputs["rotate_right"] or inputs["rotate_right2"] or
|
||||
inputs["rotate_180"]) then
|
||||
self.lcd = 0
|
||||
self.are = 0
|
||||
end
|
||||
if self.lcd == 0 then
|
||||
self.grid:clearClearedRows()
|
||||
playSE("fall")
|
||||
@@ -280,7 +353,11 @@ function GameMode:processDelays(inputs, ruleset, drop_speed)
|
||||
elseif self.are > 0 then
|
||||
self.are = self.are - 1
|
||||
if ruleset.are_cancel and
|
||||
(inputs["left"] or inputs["right"] or
|
||||
(self.move == "none" and not self.prev_inputs["up"] and
|
||||
not self.prev_inputs["rotate_left"] and not self.prev_inputs["rotate_left2"] and
|
||||
not self.prev_inputs["rotate_right"] and not self.prev_inputs["rotate_right2"] and
|
||||
not self.prev_inputs["rotate_180"]) and
|
||||
(inputs["left"] or inputs["right"] or inputs["up"] or
|
||||
inputs["rotate_left"] or inputs["rotate_left2"] or
|
||||
inputs["rotate_right"] or inputs["rotate_right2"] or
|
||||
inputs["rotate_180"]) then
|
||||
@@ -294,7 +371,7 @@ end
|
||||
|
||||
function GameMode:initializeOrHold(inputs, ruleset)
|
||||
if self.ihs and self.enable_hold and inputs["hold"] == true then
|
||||
self:hold(inputs, ruleset)
|
||||
self:hold(inputs, ruleset, true)
|
||||
else
|
||||
self:initializeNextPiece(inputs, ruleset, self.next_queue[1])
|
||||
end
|
||||
@@ -305,7 +382,7 @@ function GameMode:initializeOrHold(inputs, ruleset)
|
||||
end
|
||||
end
|
||||
|
||||
function GameMode:hold(inputs, ruleset)
|
||||
function GameMode:hold(inputs, ruleset, ihs)
|
||||
local data = copy(self.hold_queue)
|
||||
if self.piece == nil then
|
||||
self.hold_queue = self.next_queue[1]
|
||||
@@ -324,6 +401,8 @@ function GameMode:hold(inputs, ruleset)
|
||||
self:initializeNextPiece(inputs, ruleset, data, false)
|
||||
end
|
||||
self.held = true
|
||||
if ihs then playSE("ihs")
|
||||
else playSE("hold") end
|
||||
self:onHold()
|
||||
end
|
||||
|
||||
@@ -346,7 +425,7 @@ function GameMode:initializeNextPiece(inputs, ruleset, piece_data, generate_next
|
||||
table.remove(self.next_queue, 1)
|
||||
table.insert(self.next_queue, self:getNextPiece(ruleset))
|
||||
end
|
||||
self:playNextSound()
|
||||
if config.gamesettings.next_se == 1 then self:playNextSound() end
|
||||
end
|
||||
|
||||
function GameMode:playNextSound()
|
||||
@@ -398,7 +477,7 @@ function GameMode:drawNextQueue(ruleset)
|
||||
drawPiece(next_piece, skin, ruleset.block_offsets[next_piece][rotation], -16+i*80, -32)
|
||||
end
|
||||
end
|
||||
if self.hold_queue ~= nil then
|
||||
if self.hold_queue ~= nil and self.enable_hold then
|
||||
local hold_color = self.held and 0.6 or 1
|
||||
self:setHoldOpacity(1, hold_color)
|
||||
drawPiece(
|
||||
@@ -455,6 +534,10 @@ function GameMode:drawSectionTimes(current_section)
|
||||
love.graphics.printf(formatTime(self.frames - self.section_start_time), section_x, 40 + 20 * current_section, 90, "left")
|
||||
end
|
||||
|
||||
function GameMode:sectionColourFunction(section)
|
||||
return { 1, 1, 1, 1 }
|
||||
end
|
||||
|
||||
function GameMode:drawSectionTimesWithSecondary(current_section)
|
||||
local section_x = 530
|
||||
local section_secondary_x = 440
|
||||
@@ -466,9 +549,11 @@ function GameMode:drawSectionTimesWithSecondary(current_section)
|
||||
end
|
||||
|
||||
for section, time in pairs(self.secondary_section_times) do
|
||||
love.graphics.setColor(self:sectionColourFunction(section))
|
||||
if section > 0 then
|
||||
love.graphics.printf(formatTime(time), section_secondary_x, 40 + 20 * section, 90, "left")
|
||||
end
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
end
|
||||
|
||||
local current_x
|
||||
|
||||
@@ -327,10 +327,10 @@ function Marathon2020Game:checkClear(level)
|
||||
end
|
||||
|
||||
function Marathon2020Game:updateSectionTimes(old_level, new_level)
|
||||
function sectionCool()
|
||||
function sectionCool(section)
|
||||
self.section_cool_count = self.section_cool_count + 1
|
||||
self.delay_level = math.min(20, self.delay_level + 1)
|
||||
table.insert(self.section_status, "cool")
|
||||
if section < 10 then table.insert(self.section_status, "cool") end
|
||||
self.cool_timer = 300
|
||||
end
|
||||
|
||||
@@ -348,7 +348,7 @@ function Marathon2020Game:updateSectionTimes(old_level, new_level)
|
||||
table.insert(self.section_times, section_time)
|
||||
self.section_start_time = self.frames
|
||||
|
||||
if section > 4 then self.delay_level = math.min(20, self.delay_level + 1) end
|
||||
if section > 5 then self.delay_level = math.min(20, self.delay_level + 1) end
|
||||
self:checkTorikan(section)
|
||||
self:checkClear(new_level)
|
||||
|
||||
@@ -357,11 +357,11 @@ function Marathon2020Game:updateSectionTimes(old_level, new_level)
|
||||
self.secondary_section_times[section] < self.secondary_section_times[section - 1] + 120 and
|
||||
self.secondary_section_times[section] < cool_cutoffs[section]
|
||||
) then
|
||||
sectionCool()
|
||||
sectionCool(section)
|
||||
elseif self.section_status[section - 1] == "cool" then
|
||||
table.insert(self.section_status, "none")
|
||||
elseif section <= 19 and self.secondary_section_times[section] < cool_cutoffs[section] then
|
||||
sectionCool()
|
||||
sectionCool(section)
|
||||
else
|
||||
table.insert(self.section_status, "none")
|
||||
end
|
||||
@@ -423,6 +423,14 @@ function Marathon2020Game:drawGrid()
|
||||
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()
|
||||
Marathon2020Game.super.drawScoringInfo(self)
|
||||
|
||||
|
||||
@@ -448,7 +448,7 @@ function MarathonA3Game:drawScoringInfo()
|
||||
love.graphics.setFont(font_3x5_3)
|
||||
love.graphics.printf(self.score, 240, 220, 90, "left")
|
||||
if self.roll_frames > 3238 then love.graphics.setColor(1, 0.5, 0, 1)
|
||||
elseif self.clear then love.graphics.setColor(0, 1, 0, 1) end
|
||||
elseif self.level >= 999 and self.clear then love.graphics.setColor(0, 1, 0, 1) end
|
||||
love.graphics.printf(self:getLetterGrade(), 240, 140, 90, "left")
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
love.graphics.printf(self.level, 240, 340, 40, "right")
|
||||
|
||||
@@ -146,7 +146,7 @@ function MarathonAX4Game:drawScoringInfo()
|
||||
strTrueValues(self.prev_inputs)
|
||||
)
|
||||
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
||||
love.graphics.printf("TIME LEFT", 240, 250, 80, "left")
|
||||
if self.lines < 150 then love.graphics.printf("TIME LEFT", 240, 250, 80, "left") end
|
||||
love.graphics.printf("LINES", 240, 320, 40, "left")
|
||||
|
||||
local current_section = math.floor(self.lines / 10) + 1
|
||||
@@ -161,7 +161,7 @@ function MarathonAX4Game:drawScoringInfo()
|
||||
if not self.game_over and not self.clear and time_left < frameTime(0,10) and time_left % 4 < 2 then
|
||||
love.graphics.setColor(1, 0.3, 0.3, 1)
|
||||
end
|
||||
love.graphics.printf(formatTime(time_left), 240, 270, 160, "left")
|
||||
if self.lines < 150 then love.graphics.printf(formatTime(time_left), 240, 270, 160, "left") end
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
end
|
||||
|
||||
|
||||
@@ -255,7 +255,7 @@ PhantomMania2Game.garbageOpacityFunction = function(age)
|
||||
end
|
||||
|
||||
function PhantomMania2Game:drawGrid()
|
||||
if not (self.game_over or (self.clear and self.level < 1300)) then
|
||||
if not (self.game_over) then
|
||||
self.grid:drawInvisible(self.rollOpacityFunction, self.garbageOpacityFunction)
|
||||
else
|
||||
self.grid:draw()
|
||||
@@ -291,7 +291,7 @@ function PhantomMania2Game:setHoldOpacity()
|
||||
if self.level > 1000 and self.level < 1300 then
|
||||
love.graphics.setColor(1, 1, 1, 1 - math.min(1, self.hold_age / 15))
|
||||
else
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
self.super:setHoldOpacity(1, self.held and 0.6 or 1)
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -159,8 +159,9 @@ function SurvivalA2Game:drawScoringInfo()
|
||||
love.graphics.setFont(font_3x5_3)
|
||||
love.graphics.printf(self.score, text_x, 220, 90, "left")
|
||||
if self.roll_frames > 2968 then love.graphics.setColor(1, 0.5, 0, 1)
|
||||
elseif self.clear then love.graphics.setColor(0, 1, 0, 1) end
|
||||
elseif self.level >= 999 and self.clear then love.graphics.setColor(0, 1, 0, 1) end
|
||||
if self:getLetterGrade() ~= "" then love.graphics.printf(self:getLetterGrade(), text_x, 140, 90, "left") end
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
love.graphics.printf(self.level, text_x, 340, 40, "right")
|
||||
love.graphics.printf(self:getSectionEndLevel(), text_x, 370, 40, "right")
|
||||
if sg >= 5 then
|
||||
|
||||
@@ -243,7 +243,7 @@ function SurvivalA3Game:drawScoringInfo()
|
||||
|
||||
love.graphics.setFont(font_3x5_3)
|
||||
if self.roll_frames > 3238 then love.graphics.setColor(1, 0.5, 0, 1)
|
||||
elseif self.clear then love.graphics.setColor(0, 1, 0, 1) end
|
||||
elseif self.level >= 1300 and self.clear then love.graphics.setColor(0, 1, 0, 1) end
|
||||
love.graphics.printf(getLetterGrade(math.floor(self.grade)), text_x, 140, 90, "left")
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
love.graphics.printf(self.score, text_x, 220, 90, "left")
|
||||
|
||||
@@ -97,11 +97,11 @@ function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||
|
||||
-- kick right, kick left
|
||||
if (grid:canPlacePiece(new_piece:withOffset({x=1, y=0}))) then
|
||||
self:onPieceRotate(piece, grid)
|
||||
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
|
||||
self:onPieceRotate(piece, grid)
|
||||
elseif (grid:canPlacePiece(new_piece:withOffset({x=-1, y=0}))) then
|
||||
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
|
||||
self:onPieceRotate(piece, grid)
|
||||
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
local Piece = require 'tetris.components.piece'
|
||||
local Ruleset = require 'tetris.rulesets.ruleset'
|
||||
local Ruleset = require 'tetris.rulesets.arika_ti'
|
||||
|
||||
local ARS = Ruleset:extend()
|
||||
|
||||
@@ -39,137 +39,16 @@ ARS.big_spawn_positions = {
|
||||
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 == 0
|
||||
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)
|
||||
piece.floorkick = 0
|
||||
piece.manipulations = 0
|
||||
end
|
||||
|
||||
function ARS:onPieceDrop(piece, grid)
|
||||
piece.lock_delay = 0 -- step reset
|
||||
end
|
||||
|
||||
function ARS:onPieceMove(piece, grid)
|
||||
piece.lock_delay = 0 -- move reset
|
||||
if piece:isDropBlocked(grid) then
|
||||
piece.manipulations = piece.manipulations + 1
|
||||
if piece.manipulations >= 127 then
|
||||
if piece.manipulations >= 128 then
|
||||
piece.locked = true
|
||||
end
|
||||
end
|
||||
@@ -179,20 +58,13 @@ function ARS:onPieceRotate(piece, grid)
|
||||
piece.lock_delay = 0 -- rotate reset
|
||||
if piece:isDropBlocked(grid) then
|
||||
piece.manipulations = piece.manipulations + 1
|
||||
if piece.manipulations >= 127 then
|
||||
if piece.manipulations >= 128 then
|
||||
piece.locked = true
|
||||
end
|
||||
end
|
||||
if piece.floorkick >= 1 then
|
||||
piece.floorkick = piece.floorkick + 1
|
||||
end
|
||||
end
|
||||
|
||||
function ARS:get180RotationValue()
|
||||
if config.gamesettings.world_reverse == 3 then
|
||||
return 1
|
||||
else
|
||||
return 3
|
||||
end
|
||||
end
|
||||
|
||||
function ARS:getDefaultOrientation() return 3 end -- downward facing pieces by default
|
||||
|
||||
return ARS
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
local Piece = require 'tetris.components.piece'
|
||||
local Ruleset = require 'tetris.rulesets.ruleset'
|
||||
local Ruleset = require 'tetris.rulesets.arika_ti'
|
||||
|
||||
local ARS = Ruleset:extend()
|
||||
|
||||
@@ -26,137 +26,16 @@ ARS.big_spawn_positions = {
|
||||
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 == 0
|
||||
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)
|
||||
piece.floorkick = 0
|
||||
piece.manipulations = 0
|
||||
end
|
||||
|
||||
function ARS:onPieceDrop(piece, grid)
|
||||
piece.lock_delay = 0 -- step reset
|
||||
end
|
||||
|
||||
function ARS:onPieceMove(piece, grid)
|
||||
piece.lock_delay = 0 -- move reset
|
||||
if piece:isDropBlocked(grid) then
|
||||
piece.manipulations = piece.manipulations + 1
|
||||
if piece.manipulations >= 127 then
|
||||
if piece.manipulations >= 128 then
|
||||
piece.locked = true
|
||||
end
|
||||
end
|
||||
@@ -166,20 +45,13 @@ function ARS:onPieceRotate(piece, grid)
|
||||
piece.lock_delay = 0 -- rotate reset
|
||||
if piece:isDropBlocked(grid) then
|
||||
piece.manipulations = piece.manipulations + 1
|
||||
if piece.manipulations >= 127 then
|
||||
if piece.manipulations >= 128 then
|
||||
piece.locked = true
|
||||
end
|
||||
end
|
||||
if piece.floorkick >= 1 then
|
||||
piece.floorkick = piece.floorkick + 1
|
||||
end
|
||||
end
|
||||
|
||||
function ARS:get180RotationValue()
|
||||
if config.gamesettings.world_reverse == 3 then
|
||||
return 1
|
||||
else
|
||||
return 3
|
||||
end
|
||||
end
|
||||
|
||||
function ARS:getDefaultOrientation() return 3 end -- downward facing pieces by default
|
||||
|
||||
return ARS
|
||||
|
||||
@@ -1,22 +1,10 @@
|
||||
local Piece = require 'tetris.components.piece'
|
||||
local Ruleset = require 'tetris.rulesets.ruleset'
|
||||
local Ruleset = require 'tetris.rulesets.ti_srs'
|
||||
|
||||
local SRS = Ruleset:extend()
|
||||
|
||||
SRS.name = "ACE-SRS"
|
||||
SRS.hash = "ACE Standard"
|
||||
SRS.world = true
|
||||
SRS.colourscheme = {
|
||||
I = "C",
|
||||
L = "O",
|
||||
J = "B",
|
||||
S = "G",
|
||||
Z = "R",
|
||||
O = "Y",
|
||||
T = "M",
|
||||
}
|
||||
SRS.softdrop_lock = false
|
||||
SRS.harddrop_lock = true
|
||||
|
||||
SRS.spawn_positions = {
|
||||
I = { x=5, y=2 },
|
||||
@@ -38,137 +26,11 @@ SRS.big_spawn_positions = {
|
||||
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= 1, y=-2}, {x=-2, y= 1}},
|
||||
[2]={},
|
||||
[3]={{x= 2, y= 0}, {x=-1, 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]={},
|
||||
},
|
||||
[2]={
|
||||
[0]={},
|
||||
[1]={{x=-2, y= 0}, {x= 1, y= 0}, {x=-2, y=-1}, {x= 1, y= 1}},
|
||||
[3]={{x= 2, y= 0}, {x=-1, y= 0}, {x= 2, y=-1}, {x=-1, y= 1}},
|
||||
},
|
||||
[3]={
|
||||
[0]={{x=-2, y= 0}, {x= 1, y= 0}, {x=-2, y=-1}, {x= 1, y= 2}},
|
||||
[1]={},
|
||||
[2]={{x= 1, y= 0}, {x=-2, y= 0}, {x= 1, y=-2}, {x=-2, y= 1}},
|
||||
},
|
||||
};
|
||||
|
||||
-- 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
|
||||
if piece.manipulations >= 128 then
|
||||
piece.locked = true
|
||||
end
|
||||
end
|
||||
@@ -178,18 +40,10 @@ 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
|
||||
if piece.manipulations >= 128 then
|
||||
piece.locked = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SRS:get180RotationValue()
|
||||
if config.gamesettings.world_reverse == 1 then
|
||||
return 1
|
||||
else
|
||||
return 3
|
||||
end
|
||||
end
|
||||
|
||||
return SRS
|
||||
|
||||
@@ -1,77 +1,11 @@
|
||||
local Piece = require 'tetris.components.piece'
|
||||
local Ruleset = require 'tetris.rulesets.ruleset'
|
||||
local Ruleset = require 'tetris.rulesets.arika'
|
||||
|
||||
local ARS = Ruleset:extend()
|
||||
|
||||
ARS.name = "Ti-ARS"
|
||||
ARS.hash = "ArikaTI"
|
||||
|
||||
ARS.spawn_positions = {
|
||||
I = { x=5, y=4 },
|
||||
J = { x=4, y=5 },
|
||||
L = { x=4, y=5 },
|
||||
O = { x=5, y=5 },
|
||||
S = { x=4, y=5 },
|
||||
T = { x=4, y=5 },
|
||||
Z = { x=4, y=5 },
|
||||
}
|
||||
|
||||
ARS.big_spawn_positions = {
|
||||
I = { x=3, y=2 },
|
||||
J = { x=2, y=3 },
|
||||
L = { x=2, y=3 },
|
||||
O = { x=3, y=3 },
|
||||
S = { x=2, y=3 },
|
||||
T = { x=2, y=3 },
|
||||
Z = { x=2, y=3 },
|
||||
}
|
||||
|
||||
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)
|
||||
@@ -100,43 +34,48 @@ function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||
|
||||
if piece.shape == "I" then
|
||||
-- special kick rules for I
|
||||
if new_piece.rotation == 0 or new_piece.rotation == 2 then
|
||||
if (new_piece.rotation == 0 or new_piece.rotation == 2) and
|
||||
(piece:isMoveBlocked(grid, {x=-1, y=0}) or piece:isMoveBlocked(grid, {x=1, y=0})) then
|
||||
-- kick right, right2, left
|
||||
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
|
||||
self:onPieceRotate(piece, grid)
|
||||
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
|
||||
self:onPieceRotate(piece, grid)
|
||||
elseif grid:canPlacePiece(new_piece:withOffset({x=2, y=0})) then
|
||||
self:onPieceRotate(piece, grid)
|
||||
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)
|
||||
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
|
||||
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:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
|
||||
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:setRelativeRotation(rot_dir):setOffset({x=0, y=-2})
|
||||
piece.floorkick = 1
|
||||
end
|
||||
end
|
||||
else
|
||||
-- kick right, kick left
|
||||
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
|
||||
self:onPieceRotate(piece, grid)
|
||||
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
|
||||
elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then
|
||||
self:onPieceRotate(piece, grid)
|
||||
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
|
||||
elseif piece.shape == "T"
|
||||
and new_piece.rotation == 0
|
||||
and piece.floorkick == 0
|
||||
and piece:isDropBlocked(grid)
|
||||
and grid:canPlacePiece(new_piece:withOffset({x=0, y=-1}))
|
||||
then
|
||||
-- T floorkick
|
||||
piece.floorkick = piece.floorkick + 1
|
||||
self:onPieceRotate(piece, grid)
|
||||
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
|
||||
end
|
||||
end
|
||||
@@ -149,16 +88,15 @@ end
|
||||
|
||||
function ARS:onPieceDrop(piece, grid)
|
||||
piece.lock_delay = 0 -- step reset
|
||||
end
|
||||
|
||||
function ARS:get180RotationValue()
|
||||
if config.gamesettings.world_reverse == 3 then
|
||||
return 1
|
||||
else
|
||||
return 3
|
||||
if piece.floorkick >= 2 and piece:isDropBlocked(grid) then
|
||||
piece.locked = true
|
||||
end
|
||||
end
|
||||
|
||||
function ARS:getDefaultOrientation() return 3 end -- downward facing pieces by default
|
||||
function ARS:onPieceRotate(piece, grid)
|
||||
if piece.floorkick >= 1 then
|
||||
piece.floorkick = piece.floorkick + 1
|
||||
end
|
||||
end
|
||||
|
||||
return ARS
|
||||
|
||||
@@ -384,9 +384,9 @@ function CRS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||
for idx, offset in pairs(kicks) do
|
||||
kicked_piece = new_piece:withOffset(offset)
|
||||
if grid:canPlacePiece(kicked_piece) then
|
||||
self:onPieceRotate(piece, grid)
|
||||
piece:setRelativeRotation(rot_dir)
|
||||
piece:setOffset(offset)
|
||||
self:onPieceRotate(piece, grid)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
@@ -115,8 +115,8 @@ function Ruleset:attemptRotate(new_inputs, piece, grid, initial)
|
||||
local new_piece = piece:withRelativeRotation(rot_dir)
|
||||
|
||||
if (grid:canPlacePiece(new_piece)) then
|
||||
piece:setRelativeRotation(rot_dir)
|
||||
self:onPieceRotate(piece, grid)
|
||||
piece:setRelativeRotation(rot_dir)
|
||||
else
|
||||
if not(initial and self.enable_IRS_wallkicks == false) then
|
||||
self:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||
@@ -128,16 +128,16 @@ function Ruleset:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||
-- do nothing in default ruleset
|
||||
end
|
||||
|
||||
function Ruleset:movePiece(piece, grid, move)
|
||||
function Ruleset:movePiece(piece, grid, move, instant)
|
||||
local x = piece.position.x
|
||||
if move == "left" then
|
||||
piece:moveInGrid({x=-1, y=0}, 1, grid)
|
||||
elseif move == "speedleft" then
|
||||
piece:moveInGrid({x=-1, y=0}, 10, grid)
|
||||
piece:moveInGrid({x=-1, y=0}, 1, grid, false)
|
||||
elseif move == "right" then
|
||||
piece:moveInGrid({x=1, y=0}, 1, grid)
|
||||
piece:moveInGrid({x=1, y=0}, 1, grid, false)
|
||||
elseif move == "speedleft" then
|
||||
piece:moveInGrid({x=-1, y=0}, 10, grid, instant)
|
||||
elseif move == "speedright" then
|
||||
piece:moveInGrid({x=1, y=0}, 10, grid)
|
||||
piece:moveInGrid({x=1, y=0}, 10, grid, instant)
|
||||
end
|
||||
if piece.position.x ~= x then
|
||||
self:onPieceMove(piece, grid)
|
||||
@@ -197,7 +197,14 @@ function Ruleset:initializePiece(
|
||||
}, self.block_offsets, 0, 0, data.skin, colours[data.shape], big)
|
||||
|
||||
self:onPieceCreate(piece)
|
||||
if irs then self:rotatePiece(inputs, piece, grid, {}, true) end
|
||||
if irs then
|
||||
if inputs.rotate_left or inputs.rotate_left2 or
|
||||
inputs.rotate_right or inputs.rotate_right2 or
|
||||
inputs.rotate_180 then
|
||||
playSE("irs")
|
||||
end
|
||||
self:rotatePiece(inputs, piece, grid, {}, true)
|
||||
end
|
||||
self:dropPiece(inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked)
|
||||
return piece
|
||||
end
|
||||
@@ -211,8 +218,16 @@ function Ruleset:processPiece(
|
||||
drop_locked, hard_drop_locked,
|
||||
hard_drop_enabled, additive_gravity
|
||||
)
|
||||
self:rotatePiece(inputs, piece, grid, prev_inputs, false)
|
||||
self:movePiece(piece, grid, move)
|
||||
|
||||
local synchroes_allowed = ({not self.world, true, false})[config.gamesettings.synchroes_allowed]
|
||||
|
||||
if synchroes_allowed then
|
||||
self:rotatePiece(inputs, piece, grid, prev_inputs, false)
|
||||
self:movePiece(piece, grid, move, gravity >= 20)
|
||||
else
|
||||
self:movePiece(piece, grid, move, gravity >= 20)
|
||||
self:rotatePiece(inputs, piece, grid, prev_inputs, false)
|
||||
end
|
||||
self:dropPiece(
|
||||
inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked,
|
||||
hard_drop_enabled, additive_gravity
|
||||
|
||||
@@ -1,112 +1,22 @@
|
||||
local Piece = require 'tetris.components.piece'
|
||||
local Ruleset = require 'tetris.rulesets.ruleset'
|
||||
local Ruleset = require 'tetris.rulesets.arika_srs'
|
||||
|
||||
local SRS = Ruleset:extend()
|
||||
|
||||
SRS.name = "Guideline SRS"
|
||||
SRS.hash = "Standard"
|
||||
SRS.world = true
|
||||
SRS.colourscheme = {
|
||||
I = "C",
|
||||
L = "O",
|
||||
J = "B",
|
||||
S = "G",
|
||||
Z = "R",
|
||||
O = "Y",
|
||||
T = "M",
|
||||
}
|
||||
SRS.softdrop_lock = false
|
||||
SRS.harddrop_lock = true
|
||||
|
||||
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=3, y=0 },
|
||||
J = { x=2, y=1 },
|
||||
L = { x=2, y=1 },
|
||||
O = { x=3, 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}},
|
||||
},
|
||||
};
|
||||
function SRS:check_new_low(piece)
|
||||
for _, block in pairs(piece:getBlockOffsets()) do
|
||||
local y = piece.position.y + block.y
|
||||
if y > piece.lowest_y then
|
||||
piece.manipulations = 0
|
||||
piece.lowest_y = y
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
SRS.wallkicks_line = {
|
||||
[0]={
|
||||
@@ -131,16 +41,6 @@ SRS.wallkicks_line = {
|
||||
},
|
||||
};
|
||||
|
||||
function SRS:check_new_low(piece)
|
||||
for _, block in pairs(piece:getBlockOffsets()) do
|
||||
local y = piece.position.y + block.y
|
||||
if y > piece.lowest_y then
|
||||
piece.manipulations = 0
|
||||
piece.lowest_y = y
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
-- Component functions.
|
||||
|
||||
function SRS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||
@@ -203,4 +103,6 @@ function SRS:onPieceRotate(piece, grid)
|
||||
end
|
||||
end
|
||||
|
||||
function SRS:get180RotationValue() return 2 end
|
||||
|
||||
return SRS
|
||||
|
||||
@@ -147,9 +147,9 @@ function SRS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||
for idx, offset in pairs(kicks) do
|
||||
kicked_piece = new_piece:withOffset(offset)
|
||||
if grid:canPlacePiece(kicked_piece) then
|
||||
self:onPieceRotate(piece, grid)
|
||||
piece:setRelativeRotation(rot_dir)
|
||||
piece:setOffset(offset)
|
||||
self:onPieceRotate(piece, grid)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||