2019-05-22 22:57:34 -05:00
|
|
|
local Object = require 'libs.classic'
|
|
|
|
local Piece = require 'tetris.components.piece'
|
|
|
|
|
|
|
|
local Ruleset = Object:extend()
|
|
|
|
|
|
|
|
Ruleset.name = ""
|
|
|
|
Ruleset.hash = ""
|
|
|
|
|
2020-10-10 18:42:56 -05:00
|
|
|
-- Arika-type ruleset defaults
|
|
|
|
Ruleset.world = false
|
|
|
|
Ruleset.colourscheme = {
|
2020-11-06 19:49:44 -06:00
|
|
|
I = "R",
|
|
|
|
L = "O",
|
|
|
|
J = "B",
|
|
|
|
S = "M",
|
|
|
|
Z = "G",
|
|
|
|
O = "Y",
|
|
|
|
T = "C",
|
2020-10-10 18:42:56 -05:00
|
|
|
}
|
|
|
|
Ruleset.softdrop_lock = true
|
|
|
|
Ruleset.harddrop_lock = false
|
|
|
|
|
2019-05-22 22:57:34 -05:00
|
|
|
Ruleset.enable_IRS_wallkicks = false
|
2020-11-16 20:16:59 -06:00
|
|
|
Ruleset.are_cancel = false
|
2021-01-09 22:17:24 -06:00
|
|
|
Ruleset.are = true
|
2021-02-08 22:23:50 -06:00
|
|
|
Ruleset.spawn_above_field = false
|
2021-01-06 21:53:44 -06:00
|
|
|
|
|
|
|
Ruleset.next_sounds = {
|
|
|
|
I = "I",
|
|
|
|
L = "L",
|
|
|
|
J = "J",
|
|
|
|
S = "S",
|
|
|
|
Z = "Z",
|
|
|
|
O = "O",
|
|
|
|
T = "T"
|
|
|
|
}
|
|
|
|
|
2019-05-22 22:57:34 -05:00
|
|
|
-- Component functions.
|
|
|
|
|
2021-02-19 10:01:18 -06:00
|
|
|
function Ruleset:new(game_mode)
|
|
|
|
self.game = game_mode
|
2021-03-10 15:30:45 -06:00
|
|
|
local bones
|
2020-11-10 15:03:30 -06:00
|
|
|
if config.gamesettings.piece_colour == 1 then
|
2021-03-10 15:30:45 -06:00
|
|
|
bones = self.world and "w" or ""
|
2020-11-10 15:03:30 -06:00
|
|
|
else
|
2021-03-10 15:30:45 -06:00
|
|
|
bones = config.gamesettings.piece_colour == 3 and "w" or ""
|
2020-11-10 15:03:30 -06:00
|
|
|
end
|
2021-08-11 18:30:46 -05:00
|
|
|
for colour in pairs(blocks["2tie"]) do
|
|
|
|
blocks.bone[colour] = love.graphics.newImage(
|
|
|
|
"res/img/bone" .. bones .. ".png"
|
|
|
|
)
|
|
|
|
end
|
2020-11-03 09:58:21 -06:00
|
|
|
end
|
|
|
|
|
2019-05-22 22:57:34 -05:00
|
|
|
function Ruleset:rotatePiece(inputs, piece, grid, prev_inputs, initial)
|
|
|
|
local new_inputs = {}
|
|
|
|
|
|
|
|
for input, value in pairs(inputs) do
|
|
|
|
if value and not prev_inputs[input] then
|
|
|
|
new_inputs[input] = true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-01-12 14:20:22 -06:00
|
|
|
local was_drop_blocked = piece:isDropBlocked(grid)
|
|
|
|
|
2021-02-16 22:28:54 -06:00
|
|
|
if self:canPieceRotate(piece, grid) then
|
|
|
|
self:attemptRotate(new_inputs, piece, grid, initial)
|
|
|
|
end
|
2019-05-22 22:57:34 -05:00
|
|
|
|
2021-07-11 13:04:22 -05:00
|
|
|
if not initial and not was_drop_blocked and piece:isDropBlocked(grid) then
|
2021-01-12 14:20:22 -06:00
|
|
|
playSE("bottom")
|
|
|
|
end
|
|
|
|
|
2019-05-22 22:57:34 -05:00
|
|
|
-- prev_inputs becomes the previous inputs
|
|
|
|
for input, value in pairs(inputs) do
|
|
|
|
prev_inputs[input] = inputs[input]
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function Ruleset:attemptRotate(new_inputs, piece, grid, initial)
|
|
|
|
local rot_dir = 0
|
2020-12-05 15:56:12 -06:00
|
|
|
|
2019-05-22 22:57:34 -05:00
|
|
|
if (new_inputs["rotate_left"] or new_inputs["rotate_left2"]) then
|
|
|
|
rot_dir = 3
|
|
|
|
elseif (new_inputs["rotate_right"] or new_inputs["rotate_right2"]) then
|
|
|
|
rot_dir = 1
|
|
|
|
elseif (new_inputs["rotate_180"]) then
|
|
|
|
rot_dir = self:get180RotationValue()
|
|
|
|
end
|
|
|
|
|
|
|
|
if rot_dir == 0 then return end
|
2020-11-06 18:17:32 -06:00
|
|
|
if config.gamesettings.world_reverse == 3 or (self.world and config.gamesettings.world_reverse == 2) then
|
2020-10-10 18:42:56 -05:00
|
|
|
rot_dir = 4 - rot_dir
|
|
|
|
end
|
2019-05-22 22:57:34 -05:00
|
|
|
|
|
|
|
local new_piece = piece:withRelativeRotation(rot_dir)
|
|
|
|
|
|
|
|
if (grid:canPlacePiece(new_piece)) then
|
2020-12-04 19:36:11 -06:00
|
|
|
piece:setRelativeRotation(rot_dir)
|
2020-12-27 21:41:26 -06:00
|
|
|
self:onPieceRotate(piece, grid)
|
2021-09-12 01:59:05 -05:00
|
|
|
playSE("rotate")
|
2019-05-22 22:57:34 -05:00
|
|
|
else
|
|
|
|
if not(initial and self.enable_IRS_wallkicks == false) then
|
|
|
|
self:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|
|
|
end
|
2021-09-12 01:59:05 -05:00
|
|
|
playSE("kick")
|
2019-05-22 22:57:34 -05:00
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function Ruleset:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|
|
|
-- do nothing in default ruleset
|
|
|
|
end
|
|
|
|
|
2019-07-07 16:25:35 -05:00
|
|
|
function Ruleset:movePiece(piece, grid, move, instant)
|
2021-02-16 22:28:54 -06:00
|
|
|
if not self:canPieceMove(piece, grid) then return end
|
2021-01-12 14:57:45 -06:00
|
|
|
local was_drop_blocked = piece:isDropBlocked(grid)
|
2021-02-17 16:21:51 -06:00
|
|
|
local offset = ({x=0, y=0})
|
|
|
|
local moves = 0
|
2021-04-08 10:55:36 -05:00
|
|
|
local y = piece.position.y
|
2019-05-22 22:57:34 -05:00
|
|
|
if move == "left" then
|
2021-02-17 16:21:51 -06:00
|
|
|
offset.x = -1
|
|
|
|
moves = 1
|
2019-05-22 22:57:34 -05:00
|
|
|
elseif move == "right" then
|
2021-02-17 16:21:51 -06:00
|
|
|
offset.x = 1
|
|
|
|
moves = 1
|
2019-07-07 16:25:35 -05:00
|
|
|
elseif move == "speedleft" then
|
2021-02-17 16:21:51 -06:00
|
|
|
offset.x = -1
|
|
|
|
moves = grid.width
|
2019-05-22 22:57:34 -05:00
|
|
|
elseif move == "speedright" then
|
2021-02-17 16:21:51 -06:00
|
|
|
offset.x = 1
|
|
|
|
moves = grid.width
|
2019-05-22 22:57:34 -05:00
|
|
|
end
|
2021-02-17 16:21:51 -06:00
|
|
|
for i = 1, moves do
|
|
|
|
local x = piece.position.x
|
|
|
|
if moves ~= 1 then
|
|
|
|
piece:moveInGrid(offset, 1, grid, instant)
|
|
|
|
else
|
|
|
|
piece:moveInGrid(offset, 1, grid, false)
|
|
|
|
end
|
|
|
|
if piece.position.x ~= x then
|
|
|
|
self:onPieceMove(piece, grid)
|
|
|
|
if piece.locked then break end
|
2021-01-12 14:57:45 -06:00
|
|
|
end
|
2019-05-22 22:57:34 -05:00
|
|
|
end
|
2021-02-17 16:21:51 -06:00
|
|
|
if not was_drop_blocked and piece:isDropBlocked(grid) then
|
|
|
|
playSE("bottom")
|
|
|
|
end
|
2021-04-08 12:17:34 -05:00
|
|
|
if instant and piece.position.y ~= y then
|
2021-04-08 10:55:36 -05:00
|
|
|
self:onPieceDrop(piece, grid)
|
|
|
|
end
|
2019-05-22 22:57:34 -05:00
|
|
|
end
|
|
|
|
|
2019-06-16 21:24:06 -05:00
|
|
|
function Ruleset:dropPiece(
|
|
|
|
inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked,
|
2021-02-16 22:28:54 -06:00
|
|
|
hard_drop_enabled, additive_gravity, classic_lock
|
2019-06-16 21:24:06 -05:00
|
|
|
)
|
2019-05-22 22:57:34 -05:00
|
|
|
local y = piece.position.y
|
2021-09-04 21:33:53 -05:00
|
|
|
if inputs["up"] == true and hard_drop_enabled == true then
|
2019-05-22 22:57:34 -05:00
|
|
|
if hard_drop_locked == true or piece:isDropBlocked(grid) then
|
2021-02-16 22:28:54 -06:00
|
|
|
piece:addGravity(gravity, grid, classic_lock)
|
2019-05-22 22:57:34 -05:00
|
|
|
else
|
|
|
|
piece:dropToBottom(grid)
|
|
|
|
end
|
2021-09-04 21:33:53 -05:00
|
|
|
elseif inputs["down"] == true and drop_locked == false then
|
|
|
|
if additive_gravity then
|
|
|
|
piece:addGravity(gravity + drop_speed, grid, classic_lock)
|
|
|
|
else
|
|
|
|
piece:addGravity(math.max(gravity, drop_speed), grid, classic_lock)
|
|
|
|
end
|
2019-05-22 22:57:34 -05:00
|
|
|
else
|
2021-02-16 22:28:54 -06:00
|
|
|
piece:addGravity(gravity, grid, classic_lock)
|
2019-05-22 22:57:34 -05:00
|
|
|
end
|
|
|
|
if piece.position.y ~= y then
|
|
|
|
self:onPieceDrop(piece, grid)
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
2021-02-11 14:46:56 -06:00
|
|
|
function Ruleset:lockPiece(piece, grid, lock_delay, classic_lock)
|
|
|
|
if piece:isDropBlocked(grid) and (
|
|
|
|
(classic_lock and piece.gravity >= 1) or
|
|
|
|
(not classic_lock and piece.lock_delay >= lock_delay)
|
|
|
|
) then
|
2019-05-22 22:57:34 -05:00
|
|
|
piece.locked = true
|
|
|
|
end
|
|
|
|
end
|
|
|
|
|
|
|
|
function Ruleset:get180RotationValue() return 2 end
|
|
|
|
function Ruleset:getDefaultOrientation() return 1 end
|
2021-02-18 14:09:27 -06:00
|
|
|
function Ruleset:getDrawOffset(shape, orientation) return { x=0, y=0 } end
|
|
|
|
function Ruleset:getAboveFieldOffset(shape, orientation)
|
|
|
|
if shape == "I" then
|
|
|
|
return 1
|
|
|
|
else
|
|
|
|
return 2
|
|
|
|
end
|
|
|
|
end
|
2019-05-22 22:57:34 -05:00
|
|
|
|
|
|
|
function Ruleset:initializePiece(
|
|
|
|
inputs, data, grid, gravity, prev_inputs,
|
|
|
|
move, lock_delay, drop_speed,
|
2021-04-20 15:11:49 -05:00
|
|
|
drop_locked, hard_drop_locked, big, irs
|
2019-05-22 22:57:34 -05:00
|
|
|
)
|
2019-06-16 21:16:09 -05:00
|
|
|
local spawn_positions
|
|
|
|
if big then
|
|
|
|
spawn_positions = self.big_spawn_positions
|
|
|
|
else
|
|
|
|
spawn_positions = self.spawn_positions
|
|
|
|
end
|
2021-03-10 12:58:08 -06:00
|
|
|
|
|
|
|
local colours
|
2021-10-16 19:35:47 -05:00
|
|
|
if table.equalvalues(
|
|
|
|
self.colourscheme, {"I", "J", "L", "O", "S", "T", "Z"}
|
|
|
|
) then
|
2021-03-10 12:58:08 -06:00
|
|
|
colours = ({self.colourscheme, ColourSchemes.Arika, ColourSchemes.TTC})[config.gamesettings.piece_colour]
|
|
|
|
else
|
|
|
|
colours = self.colourscheme
|
|
|
|
end
|
2020-12-05 15:56:12 -06:00
|
|
|
|
2021-08-20 18:09:50 -05:00
|
|
|
local spawn_x = math.floor(spawn_positions[data.shape].x * grid.width / 10)
|
2021-01-11 13:48:03 -06:00
|
|
|
|
2021-02-08 22:23:50 -06:00
|
|
|
local spawn_dy
|
|
|
|
if (config.gamesettings.spawn_positions == 1) then
|
|
|
|
spawn_dy = (
|
2021-02-18 14:09:27 -06:00
|
|
|
self.spawn_above_field and
|
|
|
|
self:getAboveFieldOffset(data.shape, data.orientation) or 0
|
2021-02-08 22:23:50 -06:00
|
|
|
)
|
|
|
|
else
|
|
|
|
spawn_dy = (
|
|
|
|
config.gamesettings.spawn_positions == 3 and
|
2021-02-18 14:09:27 -06:00
|
|
|
self:getAboveFieldOffset(data.shape, data.orientation) or 0
|
2021-02-08 22:23:50 -06:00
|
|
|
)
|
|
|
|
end
|
2021-01-12 12:47:03 -06:00
|
|
|
|
2019-05-22 22:57:34 -05:00
|
|
|
local piece = Piece(data.shape, data.orientation - 1, {
|
2021-08-11 18:30:46 -05:00
|
|
|
x = spawn_x,
|
2021-01-12 12:47:03 -06:00
|
|
|
y = spawn_positions[data.shape].y - spawn_dy
|
2020-10-10 18:42:56 -05:00
|
|
|
}, self.block_offsets, 0, 0, data.skin, colours[data.shape], big)
|
2019-06-16 21:16:09 -05:00
|
|
|
|
2019-05-22 22:57:34 -05:00
|
|
|
self:onPieceCreate(piece)
|
2020-12-05 19:30:59 -06:00
|
|
|
if irs then
|
2021-01-24 13:55:35 -06:00
|
|
|
self:rotatePiece(inputs, piece, grid, {}, true)
|
|
|
|
if (data.orientation - 1) ~= piece.rotation then
|
2020-12-05 19:30:59 -06:00
|
|
|
playSE("irs")
|
|
|
|
end
|
|
|
|
end
|
2019-05-22 22:57:34 -05:00
|
|
|
return piece
|
|
|
|
end
|
|
|
|
|
|
|
|
-- stuff like move count, rotate count, floorkick count go here
|
|
|
|
function Ruleset:onPieceCreate(piece) end
|
|
|
|
|
|
|
|
function Ruleset:processPiece(
|
|
|
|
inputs, piece, grid, gravity, prev_inputs,
|
|
|
|
move, lock_delay, drop_speed,
|
2019-06-16 21:24:06 -05:00
|
|
|
drop_locked, hard_drop_locked,
|
2021-02-11 14:46:56 -06:00
|
|
|
hard_drop_enabled, additive_gravity, classic_lock
|
2019-05-22 22:57:34 -05:00
|
|
|
)
|
2020-12-04 09:57:43 -06:00
|
|
|
local synchroes_allowed = ({not self.world, true, false})[config.gamesettings.synchroes_allowed]
|
|
|
|
|
|
|
|
if synchroes_allowed then
|
|
|
|
self:rotatePiece(inputs, piece, grid, prev_inputs, false)
|
2021-06-26 15:27:33 -05:00
|
|
|
self:movePiece(piece, grid, move, gravity >= grid.height - 4)
|
2020-12-04 09:57:43 -06:00
|
|
|
else
|
2021-06-26 15:27:33 -05:00
|
|
|
self:movePiece(piece, grid, move, gravity >= grid.height - 4)
|
2020-12-04 09:57:43 -06:00
|
|
|
self:rotatePiece(inputs, piece, grid, prev_inputs, false)
|
|
|
|
end
|
2019-06-16 21:24:06 -05:00
|
|
|
self:dropPiece(
|
|
|
|
inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked,
|
2021-02-16 22:28:54 -06:00
|
|
|
hard_drop_enabled, additive_gravity, classic_lock
|
2019-06-16 21:24:06 -05:00
|
|
|
)
|
2021-02-11 14:46:56 -06:00
|
|
|
self:lockPiece(piece, grid, lock_delay, classic_lock)
|
2019-05-22 22:57:34 -05:00
|
|
|
end
|
|
|
|
|
2021-02-16 22:28:54 -06:00
|
|
|
function Ruleset:canPieceMove(piece, grid) return true end
|
|
|
|
function Ruleset:canPieceRotate(piece, grid) return true end
|
2019-05-22 22:57:34 -05:00
|
|
|
function Ruleset:onPieceMove(piece) end
|
|
|
|
function Ruleset:onPieceRotate(piece) end
|
|
|
|
function Ruleset:onPieceDrop(piece) end
|
|
|
|
|
|
|
|
return Ruleset
|