diff --git a/tetris/randomizers/ex.lua b/tetris/randomizers/ex.lua new file mode 100644 index 0000000..bd56723 --- /dev/null +++ b/tetris/randomizers/ex.lua @@ -0,0 +1,34 @@ +local Randomizer = require 'tetris.randomizers.randomizer' + +local EXRandomizer = Randomizer:extend() + +function EXRandomizer:initialize() + self.history = {"S", "Z", "S", "Z"} +end + +function EXRandomizer:generatePiece() + local shapes = {"I", "J", "L", "O", "S", "T", "Z"} + for i = 1, 6 do + local x = math.random(7) + if not inHistory(shapes[x], self.history) or i == 6 then + return self:updateHistory(shapes[x]) + end + end +end + +function EXRandomizer:updateHistory(shape) + table.remove(self.history, 1) + table.insert(self.history, shape) + return shape +end + +function inHistory(piece, history) + for idx, entry in pairs(history) do + if entry == piece then + return true + end + end + return false +end + +return EXRandomizer diff --git a/tetris/rulesets/ex_classic.lua b/tetris/rulesets/ex_classic.lua new file mode 100644 index 0000000..ee6f90e --- /dev/null +++ b/tetris/rulesets/ex_classic.lua @@ -0,0 +1,183 @@ +local Ruleset = require 'tetris.rulesets.ruleset' + +local EXClassic = Ruleset:extend() + +EXClassic.name = "T-EX-Classic" +EXClassic.hash = "EXClassic" + +EXClassic.softdrop_lock = false +EXClassic.harddrop_lock = true + +EXClassic.MANIPULATIONS_MAX = 10 +EXClassic.ROTATIONS_MAX = 8 + +EXClassic.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 }, +} + +EXClassic.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 }, +} + +EXClassic.block_offsets = { + I={ + { {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} }, + { {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=0, y=1} }, + { {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} }, + { {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=0, y=1} }, + }, + 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} }, + } +} + +EXClassic.normal_ccw = { + {x=0, y=0}, {x=-1, y=0}, {x=-1, y=1}, {x=0, y=1}, + {x=1, y=1}, {x=1, y=0}, {x=0, y=-1} +} +EXClassic.normal_cw = { + {x=0, y=0}, {x=1, y=0}, {x=1, y=1}, {x=0, y=1}, + {x=-1, y=1}, {x=-1, y=0}, {x=0, y=-1} +} +EXClassic.left_ccw = { + {x=-1, y=0}, {x=-1, y=1}, {x=-2, y=0}, {x=0, y=0}, + {x=0, y=1}, {x=0, y=-1}, {x=1, y=1}, {x=1, y=0} +} +EXClassic.left_cw = { + {x=-1, y=0}, {x=-1, y=1}, {x=0, y=1}, {x=-1, y=2}, + {x=0, y=0}, {x=0, y=-1}, {x=1, y=0}, {x=1, y=1} +} +EXClassic.right_ccw = { + {x=1, y=0}, {x=1, y=1}, {x=0, y=1}, {x=1, y=2}, + {x=0, y=0}, {x=0, y=-1}, {x=-1, y=0}, {x=-1, y=1} +} +EXClassic.right_cw = { + {x=1, y=0}, {x=1, y=1}, {x=2, y=0}, {x=0, y=0}, + {x=0, y=1}, {x=0, y=-1}, {x=-1, y=1}, {x=-1, y=0} +} + +function EXClassic:attemptRotate(new_inputs, piece, grid, initial) + local rot_dir = 0 + + 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 + + local new_piece = piece:withRelativeRotation(rot_dir) + self:attemptWallkicks(piece, new_piece, rot_dir, grid) +end + +function EXClassic:attemptWallkicks(piece, new_piece, rot_dir, grid) + local kicks + if self.game.das.direction == "left" and ( + self.game.das.frames >= self.game:getDasLimit() - self.game:getARR() or + piece:isMoveBlocked(grid, {x=-1, y=0}) + ) then + kicks = rot_dir == 1 and EXClassic.left_cw or EXClassic.left_ccw + elseif self.game.das.direction == "right" and ( + self.game.das.frames >= self.game:getDasLimit() - self.game:getARR() or + piece:isMoveBlocked(grid, {x=1, y=0}) + ) then + kicks = rot_dir == 1 and EXClassic.right_cw or EXClassic.right_ccw + else + kicks = rot_dir == 1 and EXClassic.normal_cw or EXClassic.normal_ccw + end + + 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, offset.y < 0) + return + end + end +end + +function EXClassic:onPieceCreate(piece, grid) + piece.manipulations = 0 + piece.rotations = 0 +end + +function EXClassic:onPieceMove(piece, grid) + if piece.manipulations < self.MANIPULATIONS_MAX then + piece.lock_delay = 0 -- move reset + if piece:isDropBlocked(grid) then + piece.manipulations = piece.manipulations + 1 + end + end +end + +function EXClassic:onPieceRotate(piece, grid, upward) + if piece.rotations < self.ROTATIONS_MAX then + piece.lock_delay = 0 -- rotate reset + if upward or piece:isDropBlocked(grid) then + piece.rotations = piece.rotations + 1 + end + end +end + +function EXClassic:get180RotationValue() + return 3 +end + +function EXClassic:getDefaultOrientation() + return 3 +end + +return EXClassic \ No newline at end of file diff --git a/tetris/rulesets/ex_modern.lua b/tetris/rulesets/ex_modern.lua new file mode 100644 index 0000000..da6086e --- /dev/null +++ b/tetris/rulesets/ex_modern.lua @@ -0,0 +1,68 @@ +local EXClassic = require 'tetris.rulesets.ex_classic' + +local EXModern = EXClassic:extend() + +EXModern.name = "T-EX-Modern" +EXModern.hash = "EXModern" + +EXModern.world = true +EXModern.colourscheme = { + I = "C", + L = "O", + J = "B", + S = "G", + Z = "R", + O = "Y", + T = "M", +} + +EXModern.block_offsets = { + I={ + { {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} }, + { {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=0, y=1} }, + { {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} }, + { {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=0, y=1} }, + }, + 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=-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=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=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} }, + } +} + +function EXModern:getDefaultOrientation() + return 1 +end + +return EXModern \ No newline at end of file