cambridge/tetris/rulesets/ruleset.lua

297 lines
7.7 KiB
Lua
Raw Normal View History

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 = ""
-- Arika-type ruleset defaults
Ruleset.world = false
Ruleset.colourscheme = {
I = "R",
L = "O",
J = "B",
S = "M",
Z = "G",
O = "Y",
T = "C",
}
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
Ruleset.spawn_above_field = false
Ruleset.next_sounds = {
I = "I",
L = "L",
J = "J",
S = "S",
Z = "Z",
O = "O",
T = "T"
}
Ruleset.pieces = 7
2019-05-22 22:57:34 -05:00
-- Component functions.
function Ruleset:new(game_mode)
self.game = game_mode
2021-03-10 15:30:45 -06:00
local bones
if config.gamesettings.piece_colour == 1 then
2021-03-10 15:30:45 -06:00
bones = self.world and "w" or ""
else
2021-03-10 15:30:45 -06:00
bones = config.gamesettings.piece_colour == 3 and "w" or ""
end
2021-03-10 15:30:45 -06:00
blocks.bone = {
R = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
O = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
Y = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
G = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
C = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
B = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
M = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
F = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
A = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
X = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
}
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)
if self:canPieceRotate(piece, grid) then
self:attemptRotate(new_inputs, piece, grid, initial)
end
2019-05-22 22:57:34 -05:00
2021-01-12 14:20:22 -06:00
if not was_drop_blocked and piece:isDropBlocked(grid) then
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
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
if config.gamesettings.world_reverse == 3 or (self.world and config.gamesettings.world_reverse == 2) then
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)
self:onPieceRotate(piece, grid)
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
end
end
function Ruleset:attemptWallkicks(piece, new_piece, rot_dir, grid)
-- do nothing in default ruleset
end
function Ruleset:movePiece(piece, grid, move, instant)
if not self:canPieceMove(piece, grid) then return end
2021-01-12 14:57:45 -06:00
local was_drop_blocked = piece:isDropBlocked(grid)
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
offset.x = -1
moves = 1
2019-05-22 22:57:34 -05:00
elseif move == "right" then
offset.x = 1
moves = 1
elseif move == "speedleft" then
offset.x = -1
moves = grid.width
2019-05-22 22:57:34 -05:00
elseif move == "speedright" then
offset.x = 1
moves = grid.width
2019-05-22 22:57:34 -05:00
end
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
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
function Ruleset:dropPiece(
inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked,
hard_drop_enabled, additive_gravity, classic_lock
)
2019-05-22 22:57:34 -05:00
local y = piece.position.y
if 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
elseif inputs["up"] == true and hard_drop_enabled == true then
if hard_drop_locked == true or piece:isDropBlocked(grid) then
piece:addGravity(gravity, grid, classic_lock)
2019-05-22 22:57:34 -05:00
else
piece:dropToBottom(grid)
end
else
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
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
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
)
local spawn_positions
if big then
spawn_positions = self.big_spawn_positions
else
spawn_positions = self.spawn_positions
end
local colours
if self.pieces == 7 then
colours = ({self.colourscheme, ColourSchemes.Arika, ColourSchemes.TTC})[config.gamesettings.piece_colour]
else
colours = self.colourscheme
end
2021-01-11 13:48:03 -06:00
local spawn_x
2021-01-12 12:47:03 -06:00
if (grid.width ~= 10) then
local percent = spawn_positions[data.shape].x / 10
for i = grid.width - 1, 0, -1 do
if i / grid.width <= percent then
2021-01-12 12:47:03 -06:00
spawn_x = i
break
end
2021-01-11 13:48:03 -06:00
end
end
local spawn_dy
if (config.gamesettings.spawn_positions == 1) then
spawn_dy = (
self.spawn_above_field and
self:getAboveFieldOffset(data.shape, data.orientation) or 0
)
else
spawn_dy = (
config.gamesettings.spawn_positions == 3 and
self:getAboveFieldOffset(data.shape, data.orientation) or 0
)
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, {
x = spawn_x or spawn_positions[data.shape].x,
2021-01-12 12:47:03 -06:00
y = spawn_positions[data.shape].y - spawn_dy
}, self.block_offsets, 0, 0, data.skin, colours[data.shape], big)
2019-05-22 22:57:34 -05:00
self:onPieceCreate(piece)
if irs then
self:rotatePiece(inputs, piece, grid, {}, true)
if (data.orientation - 1) ~= piece.rotation then
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,
drop_locked, hard_drop_locked,
hard_drop_enabled, additive_gravity, classic_lock
2019-05-22 22:57:34 -05:00
)
2021-04-20 15:11:49 -05:00
if piece.locked then return end
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, classic_lock
)
self:lockPiece(piece, grid, lock_delay, classic_lock)
2019-05-22 22:57:34 -05:00
end
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