From 2bce1ae2826c96dff6e48af1c4942e688b4a2163 Mon Sep 17 00:00:00 2001 From: Ishaan Bhardwaj Date: Wed, 19 May 2021 12:40:50 -0400 Subject: [PATCH] LARGE update to the modpack for upcoming beta5.1 --- tetris/modes/baboo.lua | 142 +++++++++++++++++ tetris/modes/combo_challenge.lua | 149 +++++++++++++++++ tetris/modes/lj.lua | 149 +++++++++++++++++ tetris/modes/nes-tgm.lua | 264 +++++++++++++++++++++++++++++++ tetris/modes/survival_axh2.lua | 36 +++++ tetris/rulesets/infinity_srs.lua | 12 ++ tetris/rulesets/kon.lua | 190 ++++++++++++++++++++++ tetris/rulesets/nintendo_x.lua | 66 ++++++++ tetris/rulesets/tod.lua | 43 +++++ tetris/rulesets/vrs.lua | 238 ++++++++++++++++++++++++++++ 10 files changed, 1289 insertions(+) create mode 100644 tetris/modes/baboo.lua create mode 100644 tetris/modes/combo_challenge.lua create mode 100644 tetris/modes/lj.lua create mode 100644 tetris/modes/nes-tgm.lua create mode 100644 tetris/modes/survival_axh2.lua create mode 100644 tetris/rulesets/infinity_srs.lua create mode 100644 tetris/rulesets/kon.lua create mode 100644 tetris/rulesets/nintendo_x.lua create mode 100644 tetris/rulesets/tod.lua create mode 100644 tetris/rulesets/vrs.lua diff --git a/tetris/modes/baboo.lua b/tetris/modes/baboo.lua new file mode 100644 index 0000000..94e8082 --- /dev/null +++ b/tetris/modes/baboo.lua @@ -0,0 +1,142 @@ +local GameMode = require 'tetris.modes.gamemode' + +local MarathonWBGame = GameMode:extend() + +MarathonWBGame.name = "Marathon WB" +MarathonWBGame.hash = "MarathonWB" +MarathonWBGame.tagline = "What can you do with 300 keystrokes?" + +function MarathonWBGame:new() + GameMode:new() + + self.lock_drop = true + self.lock_hard_drop = true + self.instant_hard_drop = true + self.instant_soft_drop = false + self.enable_hold = true + self.next_queue_length = 6 + + self.keystrokes = 0 + self.pieces = 0 + self.b2b = false + self.immobile_spin_bonus = true + + self.message = "" + self.message_timer = 0 +end + +function MarathonWBGame:getARE() return 0 end +function MarathonWBGame:getLineARE() return 0 end +function MarathonWBGame:getLineClearDelay() return 0 end +function MarathonWBGame:getDasLimit() return config.das end +function MarathonWBGame:getARR() return config.arr end +function MarathonWBGame:getDasCutDelay() return config.dcd end +function MarathonWBGame:getGravity() return 0 end + +function MarathonWBGame:onSoftDrop(dropped_row_count) + self.score = self.score + dropped_row_count +end + +function MarathonWBGame:onHardDrop(dropped_row_count) + self.score = self.score + 2 * dropped_row_count +end + +function MarathonWBGame:onPieceLock(piece, cleared_row_count) + playSE("lock") + self.pieces = self.pieces + 1 + if piece.spin then + self.score = self.score + ( + 500 * cleared_row_count + + (self.b2b and cleared_row_count > 0 and 200 or 0) + ) + self.message = ( + ((self.b2b and cleared_row_count > 0) and "B2B " or "") .. + (type(piece.shape) == "string" and piece.shape .. "-" or "") .. + "SPIN " .. cleared_row_count .. "!" + ) + if cleared_row_count > 0 then self.b2b = true end + elseif cleared_row_count > 0 then + local score_table = {100, 400, 700, 1200} + self.score = self.score + ( + score_table[math.min(cleared_row_count, 4)] + + (self.b2b and cleared_row_count >= 4 and 200 or 0) + ) + self.message = cleared_row_count >= 4 and ( + (self.b2b and "B2B " or "") .. + string.upper(string.sub( + number_names[cleared_row_count * 3 + 3], 1, -7 + )) .. "A!" + ) or "" + self.b2b = cleared_row_count >= 4 + else + self.message = "" + end + self.message_timer = 60 +end + +function MarathonWBGame:advanceOneFrame(inputs, ruleset) + if self.ready_frames == 0 then + self.frames = self.frames + 1 + for input, value in pairs(inputs) do + if value and not self.prev_inputs[input] then + self.keystrokes = self.keystrokes + 1 + self.game_over = self.keystrokes >= 300 + end + end + end + return true +end + +function MarathonWBGame:drawGrid() + self.grid:draw() + self:drawGhostPiece() +end + +function MarathonWBGame:drawScoringInfo() + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setFont(font_3x5_2) + + if config["side_next"] then + love.graphics.printf("NEXT", 240, 72, 40, "left") + else + love.graphics.printf("NEXT", 64, 40, 40, "left") + end + + love.graphics.print( + self.das.direction .. " " .. + self.das.frames .. " " .. + strTrueValues(self.prev_inputs) + ) + + love.graphics.print("SCORE", 240, 140) + love.graphics.print("KEYSTROKES", 240, 200) + love.graphics.print("keys/piece", 240, 270) + + if self.message_timer > 0 then + love.graphics.printf(self.message, 64, 400, 160, "center") + self.message_timer = self.message_timer - 1 + end + + love.graphics.setFont(font_3x5_3) + love.graphics.print(self.score, 240, 160) + love.graphics.print( + string.format("%.04f", self.keystrokes / math.max(self.pieces, 1)), + 240, 290 + ) + love.graphics.print("B2B " .. tostring(self.b2b), 240, 330) + + love.graphics.setFont(font_8x11) + love.graphics.printf(formatTime(self.frames), 64, 420, 160, "center") + + love.graphics.setFont(font_3x5_4) + love.graphics.print(math.max(300 - self.keystrokes, 0), 240, 220) + +end + +function MarathonWBGame:getHighscoreData() + return { + score = self.score + } +end + +return MarathonWBGame \ No newline at end of file diff --git a/tetris/modes/combo_challenge.lua b/tetris/modes/combo_challenge.lua new file mode 100644 index 0000000..ca9fca7 --- /dev/null +++ b/tetris/modes/combo_challenge.lua @@ -0,0 +1,149 @@ +local GameMode = require 'tetris.modes.gamemode' +local Grid = require 'tetris.components.grid' +local BagRandomizer = require 'tetris.randomizers.bag7' + +local ComboChallenge = GameMode:extend() + +ComboChallenge.name = "Combo Challenge" +ComboChallenge.hash = "ComboChallenge" +ComboChallenge.tagline = "Make the highest combo you can in 30 seconds!" + +local blk = { skin = "2tie", colour = "A" } + +local maps = { + [1] = { + [23] = {blk, blk, nil, nil}, + [24] = {blk, nil, nil, nil}, + }, + [2] = { + [23] = {blk, nil, nil, nil}, + [24] = {blk, blk, nil, nil}, + }, + [3] = { + [23] = {nil, nil, blk, blk}, + [24] = {nil, nil, nil, blk}, + }, + [4] = { + [23] = {nil, nil, nil, blk}, + [24] = {nil, nil, blk, blk}, + }, + [5] = { + [24] = {blk, blk, blk, nil}, + }, + [6] = { + [24] = {nil, blk, blk, blk}, + } +} + +function ComboChallenge:new() + GameMode:new() + self.grid = Grid(4, 24) + self.grid:applyMap(maps[math.random(#maps)]) + self.lock_drop = true + self.lock_hard_drop = true + self.enable_hold = true + self.next_queue_length = 6 + self.rta = 0 + self.combo = 0 + self.max_combo = 0 + self.skips = 2 +end + +function ComboChallenge:getARR() return config.arr end +function ComboChallenge:getARE() return 6 end +function ComboChallenge:getLineARE() return 6 end +function ComboChallenge:getLineClearDelay() return 12 end +function ComboChallenge:getDasLimit() return config.das end +function ComboChallenge:getDasCutDelay() return config.dcd end + +-- skip instead of hold +function ComboChallenge:hold(inputs, ruleset, ihs) + if self.skips <= 0 then return end + + -- special ihs case + if ihs then + table.remove(self.next_queue, 1) + table.insert(self.next_queue, self:getNextPiece(ruleset)) + end + + -- skip + self:initializeNextPiece(inputs, ruleset, table.remove(self.next_queue, 1), false) + table.insert(self.next_queue, self:getNextPiece(ruleset)) + self.skips = self.skips - 1 + + if ihs then playSE("ihs") + else playSE("hold") end + self:onHold() +end + +function ComboChallenge:advanceOneFrame() + if self.ready_frames == 0 then + self.rta = self.rta + 1 + if self.are == 0 then + self.frames = self.frames + 1 + if self.frames >= frameTime(0,30) then + self.game_over = true + end + end + end +end + +function ComboChallenge:onPieceLock(piece, cleared_row_count) + playSE("lock") + self.skips = math.min(self.skips + 1, 2) + if cleared_row_count > 0 then + self.combo = self.combo + 1 + self.max_combo = math.max(self.combo, self.max_combo) + else + self.combo = 0 + end +end + +function ComboChallenge:drawGrid() + self.grid:draw() + self:drawGhostPiece() +end + +function ComboChallenge:getHighscoreData() + return { + combo = self.max_combo + } +end + +function ComboChallenge:drawScoringInfo() + love.graphics.setColor(1, 1, 1, 1) + love.graphics.setFont(font_3x5_2) + + if config["side_next"] then + love.graphics.printf("NEXT", 240, 72, 40, "left") + else + love.graphics.printf("NEXT", 64, 40, 40, "left") + end + + love.graphics.print( + self.das.direction .. " " .. + self.das.frames .. " " .. + strTrueValues(self.prev_inputs) .. + self.drop_bonus + ) + + love.graphics.print("SKIPS", 200, 120) + love.graphics.print("MAX COMBO", 200, 200) + love.graphics.print("COMBO", 200, 280) + + love.graphics.setFont(font_3x5_4) + love.graphics.print(self.skips, 200, 140) + love.graphics.print(self.max_combo, 200, 220) + love.graphics.print(self.combo, 200, 300) + + love.graphics.setFont(font_8x11) + love.graphics.setColor( + ( + self.frames >= frameTime(0,20) and self.rta % 4 < 2 and not self.game_over + ) and {1, 0.3, 0.3, 1} or {1, 1, 1, 1} + ) + love.graphics.printf(formatTime(frameTime(0,30) - self.frames), 64, 420, 160, "center") + love.graphics.setColor(1, 1, 1, 1) +end + +return ComboChallenge \ No newline at end of file diff --git a/tetris/modes/lj.lua b/tetris/modes/lj.lua new file mode 100644 index 0000000..e256562 --- /dev/null +++ b/tetris/modes/lj.lua @@ -0,0 +1,149 @@ +local GameMode = require 'tetris.modes.gamemode' + +local MarathonWLJGame = GameMode:extend() + +MarathonWLJGame.name = "Marathon WLJ" +MarathonWLJGame.hash = "MarathonWLJ" +MarathonWLJGame.tagline = "A simple marathon mode, originating from Lockjaw." + +function MarathonWLJGame:new() + GameMode:new() + + self.lock_drop = true + self.lock_hard_drop = true + self.instant_hard_drop = true + self.instant_soft_drop = false + self.enable_hold = true + self.next_queue_length = 6 + + self.pieces = 0 + self.b2b = false + self.immobile_spin_bonus = true + + self.message = "" + self.message_timer = 0 +end + +function MarathonWLJGame:getARE() return 6 end +function MarathonWLJGame:getLineARE() return 6 end +function MarathonWLJGame:getLineClearDelay() return 24 end +function MarathonWLJGame:getDasLimit() return config.das end +function MarathonWLJGame:getARR() return config.arr end +function MarathonWLJGame:getDasCutDelay() return config.dcd end + +function MarathonWLJGame:getGravity() + if self.pieces < 609 then + return (1/60) * (259/256) ^ self.pieces + else + return 20 + end +end + +function MarathonWLJGame:getLockDelay() + if self.pieces >= 609 then + return math.ceil(40 / (1 + (3/256) * (self.pieces - 609))) + else + return 40 + end +end + +function MarathonWLJGame:onSoftDrop(dropped_row_count) + self.score = self.score + dropped_row_count +end + +function MarathonWLJGame:onHardDrop(dropped_row_count) + self.score = self.score + 2 * dropped_row_count +end + +function MarathonWLJGame:onPieceLock(piece, cleared_row_count) + playSE("lock") + self.pieces = self.pieces + 1 + self.lines = self.lines + cleared_row_count + if piece.spin then + self.score = self.score + ( + 500 * cleared_row_count + + (self.b2b and cleared_row_count > 0 and 200 or 0) + ) + self.message = ( + ((self.b2b and cleared_row_count > 0) and "B2B " or "") .. + (type(piece.shape) == "string" and piece.shape .. "-" or "") .. + "SPIN " .. cleared_row_count .. "!" + ) + if cleared_row_count > 0 then self.b2b = true end + elseif cleared_row_count > 0 then + local score_table = {100, 400, 700, 1200} + self.score = self.score + ( + score_table[math.min(cleared_row_count, 4)] + + (self.b2b and cleared_row_count >= 4 and 200 or 0) + ) + self.message = cleared_row_count >= 4 and ( + (self.b2b and "B2B " or "") .. + string.upper(string.sub( + number_names[cleared_row_count * 3 + 3], 1, -7 + )) .. "A!" + ) or "" + self.b2b = cleared_row_count >= 4 + else + self.message = "" + end + self.message_timer = 60 +end + +function MarathonWLJGame:advanceOneFrame() + if self.ready_frames == 0 then + self.frames = self.frames + 1 + end + return true +end + +function MarathonWLJGame:drawGrid() + self.grid:draw() + self:drawGhostPiece() +end + +function MarathonWLJGame:getHighscoreData() + return { + score = self.score, + pieces = self.pieces, + frames = self.frames, + } +end + +function MarathonWLJGame:getSectionEndLevel() + return math.floor(self.pieces / 30 + 1) * 30 +end + +function MarathonWLJGame:getBackground() + return math.floor(self.pieces / 30) % 20 +end + +function MarathonWLJGame:drawScoringInfo() + love.graphics.setColor(1, 1, 1, 1) + + love.graphics.setFont(font_3x5_2) + love.graphics.print( + self.das.direction .. " " .. + self.das.frames .. " " .. + strTrueValues(self.prev_inputs) + ) + love.graphics.printf("NEXT", 64, 40, 40, "left") + love.graphics.printf("LINES", 240, 120, 40, "left") + love.graphics.printf("SCORE", 240, 200, 40, "left") + love.graphics.printf("LEVEL", 240, 320, 40, "left") + + if self.message_timer > 0 then + love.graphics.printf(self.message, 64, 400, 160, "center") + self.message_timer = self.message_timer - 1 + end + + love.graphics.setFont(font_3x5_3) + love.graphics.printf(self.lines, 240, 140, 90, "left") + love.graphics.printf(self.score, 240, 220, 90, "left") + love.graphics.printf(self.pieces, 240, 340, 50, "right") + love.graphics.printf(self:getSectionEndLevel(), 240, 370, 50, "right") + + love.graphics.setFont(font_8x11) + love.graphics.printf(formatTime(self.frames), 64, 420, 160, "center") +end + +return MarathonWLJGame \ No newline at end of file diff --git a/tetris/modes/nes-tgm.lua b/tetris/modes/nes-tgm.lua new file mode 100644 index 0000000..d369603 --- /dev/null +++ b/tetris/modes/nes-tgm.lua @@ -0,0 +1,264 @@ +local GameMode = require 'tetris.modes.gamemode' +local NESRandomizer = require 'tetris.randomizers.nes' + +local NESTGMMode = GameMode:extend() + +NESTGMMode.name = "NES-TGM" +NESTGMMode.hash = "NESTGM" +NESTGMMode.tagline = "An arcade-styled mode with roots in retro!" + +function NESTGMMode:new() + GameMode:new() + self.quad_clears = {[0] = 0, 0} + self.roll_frames = 0 + + self.randomizer = NESRandomizer() + + self.ready_frames = 1 + self.waiting_frames = 96 + + self.last_row = 1 + + self.lock_drop = true + self.enable_hard_drop = false + self.enable_hold = false + self.next_queue_length = 1 + self.additive_gravity = false + self.classic_lock = true + + self.irs = false +end + +function NESTGMMode:getDropSpeed() return 1/2 end +function NESTGMMode:getDasLimit() return 16 end +function NESTGMMode:getARR() return 6 end + +function NESTGMMode:getARE() + if self.last_row > 22 then return 10 + elseif self.last_row > 18 then return 12 + elseif self.last_row > 14 then return 14 + elseif self.last_row > 10 then return 16 + else return 18 end +end + +function NESTGMMode:getLineARE() return self:getARE() end + +function NESTGMMode:getLineClearDelay() + for i = 17, 20 do + if (self.frames + i) % 4 == 0 then return i end + end +end + +function NESTGMMode:getLockDelay() return 0 end + +function NESTGMMode:chargeDAS(inputs) + if inputs[self.das.direction] == true and + self.prev_inputs[self.das.direction] == true and + not inputs["down"] and + self.piece ~= nil + 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 + end + elseif inputs["right"] == true then + self.das.direction = "right" + if not inputs["down"] and self.piece ~= nil then + self.move = "right" + self.das.frames = 0 + else + self.move = "none" + end + elseif inputs["left"] == true then + self.das.direction = "left" + if not inputs["down"] and self.piece ~= nil then + self.move = "left" + self.das.frames = 0 + else + self.move = "none" + end + else + self.move = "none" + end + + if self.das.direction == "left" and self.piece ~= nil and self.piece:isMoveBlocked(self.grid, {x=-1, y=0}) or + self.das.direction == "right" and self.piece ~= nil and self.piece:isMoveBlocked(self.grid, {x=1, y=0}) + then + self.das.frames = self:getDasLimit() + end + + if inputs["down"] == false and self.prev_inputs["down"] == true then + self.drop_bonus = 0 + end + + if inputs["down"] then self.waiting_frames = 0 end +end + +function NESTGMMode:getLevelForLines() + if self.lines < 10 then return math.floor(self.lines / 5) + elseif self.lines < 150 then return math.floor(self.lines / 10) + 1 + elseif self.lines < 300 then return math.floor(self.lines / 50) + 13 + else return 19 end +end + +local gravity_table = { + [0] = 1/48, 1/43, 1/38, 1/33, 1/28, + 1/23, 1/48, 1/28, 1/13, 1/8, 1/6, + 1/5, 1/4, 1/4, 1/5, 1/5, 1/3, 1/3, + 1/3, 1/2 +} + +function NESTGMMode:getGravity() + if self.waiting_frames > 0 then return 0 end + return gravity_table[self:getLevelForLines()] +end + +function NESTGMMode:advanceOneFrame() + if self.waiting_frames > 0 then + self.waiting_frames = self.waiting_frames - 1 + elseif self:getLevelForLines() >= 19 then + self.roll_frames = self.roll_frames + 1 + if self.roll_frames >= 3600 then + self.completed = true + end + else + self.frames = self.frames + 1 + end + return true +end + +function NESTGMMode:onPieceLock() + self.super:onPieceLock() + self.score = self.score + self.drop_bonus + self.drop_bonus = 0 + self.last_row = self.piece.position.y +end + +function NESTGMMode:getGrade() + if ( + self.lines >= 300 and + self.score >= 600000 and + self.quad_clears[0] >= 25 and + self.quad_clears[1] >= 15 + ) then + if self.roll_frames >= 3600 then return {19, "???"} + else return {18, "???"} end + else + if self.score < 002000 then return {0, 2000} + elseif self.score < 005300 then return {1, 5300} + elseif self.score < 011000 then return {2, 11000} + elseif self.score < 018000 then return {3, 18000} + elseif self.score < 027000 then return {4, 27000} + elseif self.score < 038000 then return {5, 38000} + elseif self.score < 050000 then return {6, 50000} + elseif self.score < 065000 then return {7, 65000} + elseif self.score < 083000 then return {8, 83000} + elseif self.score < 110000 then return {9, 110000} + elseif self.score < 150000 then return {10, 150000} + elseif self.score < 200000 then return {11, 200000} + elseif self.score < 260000 then return {12, 260000} + elseif self.score < 330000 then return {13, 330000} + elseif self.score < 410000 then return {14, 410000} + elseif self.score < 500000 then return {15, 500000} + elseif self.score < 600000 then return {16, 600000} + else return {17, "???"} end + end +end + +function NESTGMMode:updateScore(level, drop_bonus, cleared_lines) + if cleared_lines > 0 then + if cleared_lines >= 4 and self.lines < 300 then + self.quad_clears[math.floor(self.lines / 150)] = ( + self.quad_clears[math.floor(self.lines / 150)] + 1 + ) + end + self.lines = self.lines + cleared_lines + local score_to_add = 40 + if cleared_lines > 1 then + score_to_add = 100 + for i = 3, cleared_lines do + score_to_add = score_to_add * i + end + end + self.score = self.score + score_to_add * (self:getLevelForLines() + 1) + for i = 1, 4 do + self.grid:clearSpecificRow(i) + end + end +end + +function NESTGMMode:drawScoringInfo() + love.graphics.setColor(1, 1, 1, 1) + + love.graphics.setFont(font_3x5_2) + love.graphics.print( + self.das.direction .. " " .. + self.das.frames .. " " .. + strTrueValues(self.prev_inputs) + ) + love.graphics.printf("NEXT", 64, 40, 40, "left") + love.graphics.printf("GRADE", 240, 120, 40, "left") + love.graphics.printf("SCORE", 240, 200, 40, "left") + love.graphics.printf("NEXT RANK", 240, 260, 90, "left") + love.graphics.printf("LINES", 240, 320, 40, "left") + local sg = self.grid:checkSecretGrade() + if sg >= 5 then + love.graphics.printf("SECRET GRADE", 240, 430, 180, "left") + end + + love.graphics.setFont(font_3x5_3) + love.graphics.printf(self.score, 240, 220, 90, "left") + if self:getGrade()[1] == 19 then + love.graphics.printf("GM", 240, 140, 90, "left") + elseif self:getGrade()[1] == 18 then + love.graphics.printf("M", 240, 140, 90, "left") + else + love.graphics.printf( + self.SGnames[self:getGrade()[1] + 1], 240, 140, 90, "left" + ) + end + love.graphics.printf(self:getGrade()[2], 240, 280, 90, "left") + love.graphics.printf(math.min(300, self.lines), 240, 340, 40, "right") + love.graphics.printf(self:getSectionEndLines(), 240, 370, 40, "right") + if sg >= 5 then + love.graphics.printf(self.SGnames[sg], 240, 450, 180, "left") + end + + love.graphics.setFont(font_8x11) + love.graphics.printf(formatTime(self.frames), 64, 420, 160, "center") +end + +function NESTGMMode:getSectionEndLines() + if self.lines < 10 then return (1 + math.floor(self.lines / 5)) * 5 + elseif self.lines < 150 then return (1 + math.floor(self.lines / 10)) * 10 + elseif self.lines < 300 then return (1 + math.floor(self.lines / 50)) * 50 + else return 300 end +end + +function NESTGMMode:drawGrid() + self.grid:draw() +end + +function NESTGMMode:getBackground() + return self:getLevelForLines() +end + +function NESTGMMode:getHighscoreData() + return { + grade = self:getGrade()[1], + score = self.score, + level = self:getLevelForLines(), + lines = self.lines, + } +end + +return NESTGMMode diff --git a/tetris/modes/survival_axh2.lua b/tetris/modes/survival_axh2.lua new file mode 100644 index 0000000..5371f01 --- /dev/null +++ b/tetris/modes/survival_axh2.lua @@ -0,0 +1,36 @@ +local SurvivalAXHGame = require 'tetris.modes.survival_axh' + +local SurvivalAXH2Game = SurvivalAXHGame:extend() + +SurvivalAXH2Game.name = "Survival AXH2" +SurvivalAXH2Game.hash = "SurvivalAXH2" +SurvivalAXH2Game.tagline = "Hellish speeds, fading blocks!" + +function SurvivalAXH2Game:getSkin() + return "bone" +end + +function SurvivalAXH2Game:getFadeoutTime() + if self.lines >= 190 then return 60 + elseif self.lines >= 150 then return 120 + elseif self.lines >= 50 then return 150 + end +end + +local function rollOpacityFunction(game, block, x, y, age) + local opacity + if age < game:getFadeoutTime() then opacity = 1 + elseif age >= game:getFadeoutTime() + 60 then opacity = 0 + else opacity = 1 - (age - game:getFadeoutTime()) / 60 end + return 0.5, 0.5, 0.5, opacity, 0 +end + +function SurvivalAXH2Game:drawGrid() + if self:getFadeoutTime() then + self.grid:drawCustom(rollOpacityFunction, self) + else + self.grid:draw() + end +end + +return SurvivalAXH2Game \ No newline at end of file diff --git a/tetris/rulesets/infinity_srs.lua b/tetris/rulesets/infinity_srs.lua new file mode 100644 index 0000000..fdf65cf --- /dev/null +++ b/tetris/rulesets/infinity_srs.lua @@ -0,0 +1,12 @@ +local SRS = require 'tetris.rulesets.standard' + +local Infinity = SRS:extend() + +Infinity.name = "Infinity-SRS" +Infinity.hash = "Infinity-SRS" + +function Infinity:onPieceDrop(piece) piece.lock_delay = 0 end +function Infinity:onPieceMove(piece) piece.lock_delay = 0 end +function Infinity:onPieceRotate(piece) piece.lock_delay = 0 end + +return Infinity \ No newline at end of file diff --git a/tetris/rulesets/kon.lua b/tetris/rulesets/kon.lua new file mode 100644 index 0000000..77ba47c --- /dev/null +++ b/tetris/rulesets/kon.lua @@ -0,0 +1,190 @@ +local SRS = require 'tetris.rulesets.standard' + +local kon = SRS:extend() + +kon.name = "kon" +kon.hash = "kon" + +kon.colourscheme = { + I = "M", + L = "R", + J = "C", + S = "Y", + Z = "B", + O = "O", + T = "G", +} + +kon.kicks_cw = { -- also 180 + {x=0, y=0}, {x=1, y=0}, {x=-1, y=0}, + {x=0, y=1}, {x=1, y=1}, {x=-1, y=1}, + {x=0, y=-1}, {x=1, y=-1}, {x=-1, y=-1}, + {x=0, y=2}, {x=0, y=-2}, +} + +kon.kicks_ccw = { + {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, + {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}, + {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, + {x=0, y=2}, {x=0, y=-2}, +} + +kon.kicks_I_cw = {} +kon.kicks_I_ccw = {} + +for _, y in pairs({0, 2, 1, -1, -2}) do + for _, x in pairs({0, 1, -1, 2, -2}) do + table.insert(kon.kicks_I_cw, {x=x, y=y}) + table.insert(kon.kicks_I_ccw, {x=-x, y=y}) + end +end + +kon.corners_I = { + [0] = { + {x=0, y=-1}, {x=-1, y=-1}, {x=-2, y=-1}, {x=1, y=-1}, {x=2, y=0}, + {x=0, y=1}, {x=-1, y=1}, {x=-2, y=1}, {x=1, y=1}, {x=-3, y=0}, + }, + [1] = { + {x=1, y=0}, {x=1, y=-1}, {x=1, y=1}, {x=1, y=2}, {x=0, y=-2}, + {x=-1, y=0}, {x=-1, y=-1}, {x=-1, y=1}, {x=-1, y=2}, {x=0, y=3}, + }, + [2] = { + {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0}, {x=2, y=1}, + {x=0, y=2}, {x=-1, y=2}, {x=-2, y=2}, {x=1, y=2}, {x=-3, y=1}, + }, + [3] = { + {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=0, y=2}, {x=-1, y=-2}, + {x=-2, y=0}, {x=-2, y=-1}, {x=-2, y=1}, {x=-2, y=2}, {x=-1, y=3}, + } +} + +kon.corners_O = { + {x=0, y=1}, {x=-1, y=1}, + {x=-2, y=0}, {x=-2, y=-1}, + {x=-1, y=-2}, {x=0, y=-2}, + {x=1, y=-1}, {x=1, y=0}, +} + +kon.corners_3x3 = { + L = { + [0] = { + {x=-2, y=0}, {x=-1, y=1}, {x=-1, y=-1}, {x=0, y=1}, {x=0, y=-1}, + {x=1, y=1}, {x=1, y=-2}, {x=2, y=0}, {x=2, y=-1}, + } + }, + Z = { + [0] = { + {x=-2, y=-1}, {x=-1, y=-2}, {x=-1, y=0}, {x=0, y=-2}, + {x=0, y=1}, {x=1, y=-1}, {x=1, y=1}, {x=2, y=0}, + } + }, + T = { + [0] = { + {x=-2, y=0}, {x=-1, y=-1}, {x=-1, y=1}, {x=0, y=-2}, + {x=0, y=1}, {x=1, y=-1}, {x=1, y=1}, {x=2, y=0}, + } + }, + S = { + [0] = { + {x=-2, y=0}, {x=-1, y=-1}, {x=-1, y=1}, {x=0, y=-2}, + {x=0, y=1}, {x=1, y=-2}, {x=1, y=0}, {x=2, y=-1}, + } + }, + J = { + [0] = { + {x=-2, y=-1}, {x=-2, y=0}, {x=-1, y=-2}, {x=-1, y=1}, {x=0, y=-1}, + {x=0, y=1}, {x=1, y=-1}, {x=1, y=1}, {x=2, y=0}, + } + } +} + +for piece, _ in pairs(kon.corners_3x3) do + for i = 1, 3 do + kon.corners_3x3[piece][i] = {} + for _, corner in pairs(kon.corners_3x3[piece][i - 1]) do + table.insert( + kon.corners_3x3[piece][i], + {x=-corner.y, y=corner.x} + ) + end + end +end + +function kon: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) + + if (grid:canPlacePiece(new_piece)) then + if piece:isDropBlocked(grid) then + self:attemptWallkicks(piece, new_piece, rot_dir, grid) + else + piece:setRelativeRotation(rot_dir) + self:onPieceRotate(piece, grid) + end + else + if not(initial and self.enable_IRS_wallkicks == false) then + self:attemptWallkicks(piece, new_piece, rot_dir, grid) + end + end +end + +function kon:attemptWallkicks(piece, new_piece, rot_dir, grid) + local kicks + if rot_dir == 3 then + kicks = piece.shape == "I" and kon.kicks_I_ccw or kon.kicks_ccw + else + kicks = piece.shape == "I" and kon.kicks_I_cw or kon.kicks_cw + end + + local corners + if piece.shape == "I" then + corners = kon.corners_I[new_piece.rotation] + elseif piece.shape == "O" then + corners = kon.corners_O + else + corners = kon.corners_3x3[piece.shape][new_piece.rotation] + end + + local chosen_kick + local greatest_corners = -1 + for _, offset in pairs(kicks) do + kicked_piece = new_piece:withOffset(offset) + if grid:canPlacePiece(kicked_piece) then + local occupied_corners = 0 + for _, corner in pairs(corners) do + if grid:isOccupied( + kicked_piece.position.x + corner.x, + kicked_piece.position.y + corner.y + ) then + occupied_corners = occupied_corners + 1 + end + end + if occupied_corners > greatest_corners then + greatest_corners = occupied_corners + chosen_kick = offset + end + end + end + + if chosen_kick then + piece:setRelativeRotation(rot_dir) + piece:setOffset(chosen_kick) + self:onPieceRotate(piece, grid) + end +end + +return kon \ No newline at end of file diff --git a/tetris/rulesets/nintendo_x.lua b/tetris/rulesets/nintendo_x.lua new file mode 100644 index 0000000..c2ea119 --- /dev/null +++ b/tetris/rulesets/nintendo_x.lua @@ -0,0 +1,66 @@ +local NRS_R = require 'tetris.rulesets.nintendo_r' +local NRS_X = NRS_R:extend() + +NRS_X.name = "Nintendo-X" +NRS_X.hash = "NintendoX" + +NRS_X.wallkicks_line_cw = {{x=1, y=0}, {x=2, y=0}, {x=-1, y=0}, {x=0, y=-1}} +NRS_X.wallkicks_line_ccw = {{x=-1, y=0}, {x=1, y=0}, {x=2, y=0}, {x=0, y=-1}} +NRS_X.wallkicks_other_cw = {{x=1, y=0}, {x=-1, y=0}, {x=0, y=-1}} +NRS_X.wallkicks_other_ccw = {{x=-1, y=0}, {x=1, y=0}, {x=0, y=-1}} + +function NRS_X:checkNewLow(piece) + for _, block in pairs(piece:getBlockOffsets()) do + local y = piece.position.y + block.y + if y > piece.lowest_y then + piece.lock_delay = 0 + piece.lowest_y = y + end + end +end + +function NRS_X:onPieceCreate(piece, grid) + piece.lowest_y = -math.huge +end + +function NRS_X:onPieceDrop(piece) + self:checkNewLow(piece) +end + +function NRS_X:onPieceRotate(piece) + self:checkNewLow(piece) +end + +function NRS_X:attemptWallkicks(piece, new_piece, rot_dir, grid) + local kicks + if piece.shape == "O" then + return + elseif piece.shape == "I" then + kicks = ( + rot_dir == 3 and + NRS_X.wallkicks_line_ccw or + NRS_X.wallkicks_line_cw + ) + else + kicks = ( + rot_dir == 3 and + NRS_X.wallkicks_other_ccw or + NRS_X.wallkicks_other_cw + ) + 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, offset.y < 0) + return + end + end + +end + +return NRS_X \ No newline at end of file diff --git a/tetris/rulesets/tod.lua b/tetris/rulesets/tod.lua new file mode 100644 index 0000000..7eaccb0 --- /dev/null +++ b/tetris/rulesets/tod.lua @@ -0,0 +1,43 @@ +local SRS = require 'tetris.rulesets.arika_srs' + +local TOD = SRS:extend() + +TOD.name = "TOD M4" +TOD.hash = "TOD" + +TOD.colourscheme = { + I = "C", + J = "B", + L = "M", + O = "F", + S = "G", + Z = "R", + T = "Y" +} +TOD.harddrop_lock = false + +function TOD:attemptWallkicks(piece, new_piece, rot_dir, grid) + local kicks = {{x=1, y=0}, {x=-1, y=0}, {x=0, y=-1}} + + 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 TOD:onPieceDrop(piece) + piece.lock_delay = math.max( + 0, piece.lock_delay - math.ceil(1 / self.game:getGravity()) + ) +end + +function TOD:onPieceMove() end +function TOD:onPieceRotate() end +function TOD:canPieceRotate() return true end + +return TOD \ No newline at end of file diff --git a/tetris/rulesets/vrs.lua b/tetris/rulesets/vrs.lua new file mode 100644 index 0000000..2354111 --- /dev/null +++ b/tetris/rulesets/vrs.lua @@ -0,0 +1,238 @@ +local Ruleset = require "tetris.rulesets.ruleset" + +local VRS = Ruleset:extend() + +VRS.name = "V.R.S." +VRS.hash = "VRS" + +VRS.world = true +VRS.colourscheme = { + I = "M", + L = "R", + J = "C", + S = "Y", + Z = "B", + O = "O", + T = "G", +} + +VRS.enable_IRS_wallkicks = true +VRS.spawn_above_field = true + +VRS.spawn_positions = { + I = { x=4, y=4 }, + J = { x=4, y=5 }, + L = { x=4, y=5 }, + O = { x=4, y=5 }, + S = { x=4, y=5 }, + T = { x=4, y=5 }, + Z = { x=4, y=5 }, +} + +VRS.big_spawn_positions = { + I = { x=2, y=2 }, + J = { x=2, y=3 }, + L = { x=2, y=3 }, + O = { x=2, y=3 }, + S = { x=2, y=3 }, + T = { x=2, y=3 }, + Z = { x=2, y=3 }, +} + +VRS.block_offsets = { + I = { + {{x=1, y=0}, {x=0, y=0}, {x=-1, y=0}, {x=2, y=0}}, + {{x=1, y=-2}, {x=1, y=-1}, {x=1, y=0}, {x=1, y=1}}, + {{x=1, y=0}, {x=0, y=0}, {x=-1, y=0}, {x=2, y=0}}, + {{x=1, y=-2}, {x=1, y=-1}, {x=1, y=0}, {x=1, y=1}} + }, + S = { + {{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}, {x=1, y=-1}}, + {{x=0, y=-1}, {x=0, y=0}, {x=1, y=0}, {x=1, y=1}} + }, + 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}} + }, + T = { + {{x=1, y=0}, {x=0, y=0}, {x=-1, y=0}, {x=0, y=-1}}, + {{x=0, y=-1}, {x=0, y=0}, {x=0, y=1}, {x=1, y=0}}, + {{x=1, y=0}, {x=0, y=0}, {x=-1, y=0}, {x=0, y=1}}, + {{x=0, y=-1}, {x=0, y=0}, {x=0, y=1}, {x=-1, y=0}} + }, + J = { + {{x=1, y=0}, {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}}, + {{x=0, y=-1}, {x=0, y=0}, {x=0, y=1}, {x=1, y=-1}}, + {{x=1, y=0}, {x=0, y=0}, {x=-1, y=0}, {x=1, y=1}}, + {{x=0, y=-1}, {x=0, y=0}, {x=0, y=1}, {x=-1, y=1}} + }, + L = { + {{x=1, y=0}, {x=0, y=0}, {x=-1, y=0}, {x=1, y=-1}}, + {{x=0, y=-1}, {x=0, y=0}, {x=0, y=1}, {x=1, y=1}}, + {{x=1, y=0}, {x=0, y=0}, {x=-1, y=0}, {x=-1, y=1}}, + {{x=0, y=-1}, {x=0, y=0}, {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}} + }, +} + +VRS.kicks_ccw = { + I = { + [0] = {{x=-1, y=0}, {x=-1, y=1}, {x=-2, y=0}, {x=-2, y=1}, {x=-1, y=-1}, {x=-2, y=-1}, {x=-1, y=2}, {x=-2, y=2}, {x=0, y=0}, {x=0, y=1}, {x=1, y=0}, {x=1, y=1}, {x=0, y=-1}, {x=1, y=-1}, {x=0, y=2}, {x=1, y=2}}, + {{x=0, y=0}, {x=0, y=1}, {x=-1, y=0}, {x=-1, y=1}, {x=0, y=-1}, {x=-1, y=-1}, {x=0, y=-2}, {x=-1, y=-2}, {x=1, y=0}, {x=1, y=1}, {x=2, y=0}, {x=2, y=1}, {x=1, y=-1}, {x=2, y=-1}, {x=1, y=-2}, {x=2, y=-2}}, + {{x=-1, y=0}, {x=-1, y=1}, {x=-2, y=0}, {x=-2, y=1}, {x=-1, y=-1}, {x=-2, y=-1}, {x=-1, y=2}, {x=-2, y=2}, {x=0, y=0}, {x=0, y=1}, {x=1, y=0}, {x=1, y=1}, {x=0, y=-1}, {x=1, y=-1}, {x=0, y=2}, {x=1, y=2}}, + {{x=0, y=0}, {x=0, y=1}, {x=-1, y=0}, {x=-1, y=1}, {x=0, y=-1}, {x=-1, y=-1}, {x=0, y=-2}, {x=-1, y=-2}, {x=1, y=0}, {x=1, y=1}, {x=2, y=0}, {x=2, y=1}, {x=1, y=-1}, {x=2, y=-1}, {x=1, y=-2}, {x=2, y=-2}}, + }, + + TLJ = { + [0] = {{x=0, y=0}, {x=0, y=1}, {x=1, y=0}, {x=1, y=1}, {x=-1, y=0}, {x=-1, y=1}, {x=0, y=-1}, {x=1, y=-1}, {x=-1, y=-1}, {x=0, y=2}, {x=0, y=-2}}, + {{x=0, y=0}, {x=0, y=1}, {x=1, y=0}, {x=1, y=1}, {x=-1, y=0}, {x=-1, y=1}, {x=0, y=-1}, {x=1, y=-1}, {x=-1, y=-1}, {x=0, y=2}, {x=0, y=-2}}, + {{x=0, y=0}, {x=0, y=1}, {x=-1, y=0}, {x=-1, y=1}, {x=1, y=0}, {x=1, y=1}, {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=0, y=2}, {x=0, y=-2}}, + {{x=0, y=0}, {x=0, y=1}, {x=-1, y=0}, {x=-1, y=1}, {x=1, y=0}, {x=1, y=1}, {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=0, y=2}, {x=0, y=-2}}, + }, + + SZ = { + [0] = {{x=-1, y=0}, {x=-1, y=1}, {x=-2, y=0}, {x=-2, y=1}, {x=-1, y=-1}, {x=-2, y=-1}, {x=0, y=0}, {x=0, y=1}, {x=0, y=-1}, {x=-1, y=2}, {x=-1, y=-2}}, + {{x=0, y=0}, {x=0, y=1}, {x=-1, y=0}, {x=-1, y=1}, {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=0}, {x=1, y=1}, {x=1, y=-1}, {x=0, y=2}, {x=0, y=-2}}, + {{x=-1, y=0}, {x=-1, y=1}, {x=-2, y=0}, {x=-2, y=1}, {x=-1, y=-1}, {x=-2, y=-1}, {x=0, y=0}, {x=0, y=1}, {x=0, y=-1}, {x=-1, y=2}, {x=-1, y=-2}}, + {{x=0, y=0}, {x=0, y=1}, {x=-1, y=0}, {x=-1, y=1}, {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=0}, {x=1, y=1}, {x=1, y=-1}, {x=0, y=2}, {x=0, y=-2}}, + }, + + O = { + -- lol + [0] = {{x=0, y=0}}, + {{x=0, y=0}}, + {{x=0, y=0}}, + {{x=0, y=0}}, + }, +} + +VRS.kicks_cw = { + I = { + [0] = {{x=0, y=0}, {x=0, y=1}, {x=1, y=0}, {x=1, y=1}, {x=0, y=-1}, {x=1, y=-1}, {x=0, y=2}, {x=1, y=2}, {x=-1, y=0}, {x=-1, y=1}, {x=-2, y=0}, {x=-2, y=1}, {x=-1, y=-1}, {x=-2, y=-1}, {x=-1, y=2}, {x=-2, y=2}}, + {{x=1, y=0}, {x=1, y=1}, {x=2, y=0}, {x=2, y=1}, {x=1, y=-1}, {x=2, y=-1}, {x=1, y=-2}, {x=2, y=-2}, {x=0, y=0}, {x=0, y=1}, {x=-1, y=0}, {x=-1, y=1}, {x=0, y=-1}, {x=-1, y=-1}, {x=0, y=-2}, {x=-1, y=-2}}, + {{x=0, y=0}, {x=0, y=1}, {x=1, y=0}, {x=1, y=1}, {x=0, y=-1}, {x=1, y=-1}, {x=0, y=2}, {x=1, y=2}, {x=-1, y=0}, {x=-1, y=1}, {x=-2, y=0}, {x=-2, y=1}, {x=-1, y=-1}, {x=-2, y=-1}, {x=-1, y=2}, {x=-2, y=2}}, + {{x=1, y=0}, {x=1, y=1}, {x=2, y=0}, {x=2, y=1}, {x=1, y=-1}, {x=2, y=-1}, {x=1, y=-2}, {x=2, y=-2}, {x=0, y=0}, {x=0, y=1}, {x=-1, y=0}, {x=-1, y=1}, {x=0, y=-1}, {x=-1, y=-1}, {x=0, y=-2}, {x=-1, y=-2}}, + }, + + TLJ = { + [0] = {{x=0, y=0}, {x=0, y=1}, {x=-1, y=0}, {x=-1, y=1}, {x=1, y=0}, {x=1, y=1}, {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=0, y=2}, {x=0, y=-2}}, + {{x=0, y=0}, {x=0, y=1}, {x=1, y=0}, {x=1, y=1}, {x=-1, y=0}, {x=-1, y=1}, {x=0, y=-1}, {x=1, y=-1}, {x=-1, y=-1}, {x=0, y=2}, {x=0, y=-2}}, + {{x=0, y=0}, {x=0, y=1}, {x=1, y=0}, {x=1, y=1}, {x=-1, y=0}, {x=-1, y=1}, {x=0, y=-1}, {x=1, y=-1}, {x=-1, y=-1}, {x=0, y=2}, {x=0, y=-2}}, + {{x=0, y=0}, {x=0, y=1}, {x=-1, y=0}, {x=-1, y=1}, {x=1, y=0}, {x=1, y=1}, {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=0, y=2}, {x=0, y=-2}}, + }, + + SZ = { + [0] = {{x=0, y=0}, {x=0, y=1}, {x=1, y=0}, {x=1, y=1}, {x=0, y=-1}, {x=1, y=-1}, {x=-1, y=0}, {x=-1, y=1}, {x=-1, y=-1}, {x=0, y=2}, {x=0, y=-2}}, + {{x=1, y=0}, {x=1, y=1}, {x=2, y=0}, {x=2, y=1}, {x=1, y=-1}, {x=2, y=-1}, {x=0, y=0}, {x=0, y=1}, {x=0, y=-1}, {x=1, y=2}, {x=1, y=-2}}, + {{x=0, y=0}, {x=0, y=1}, {x=1, y=0}, {x=1, y=1}, {x=0, y=-1}, {x=1, y=-1}, {x=-1, y=0}, {x=-1, y=1}, {x=-1, y=-1}, {x=0, y=2}, {x=0, y=-2}}, + {{x=1, y=0}, {x=1, y=1}, {x=2, y=0}, {x=2, y=1}, {x=1, y=-1}, {x=2, y=-1}, {x=0, y=0}, {x=0, y=1}, {x=0, y=-1}, {x=1, y=2}, {x=1, y=-2}}, + }, + + O = { + -- lol + [0] = {{x=0, y=0}}, + {{x=0, y=0}}, + {{x=0, y=0}}, + {{x=0, y=0}}, + }, +} + +function VRS: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 VRS:attemptWallkicks(piece, new_piece, rot_dir, grid) + local kicks + if rot_dir == 1 then + if piece.shape == "I" then + kicks = VRS.kicks_cw.I[piece.rotation] + elseif ( + piece.shape == "T" or + piece.shape == "L" or + piece.shape == "J" + ) then + kicks = VRS.kicks_cw.TLJ[piece.rotation] + elseif ( + piece.shape == "S" or + piece.shape == "Z" + ) then + kicks = VRS.kicks_cw.SZ[piece.rotation] + else + kicks = VRS.kicks_cw.O[piece.rotation] + end + else + if piece.shape == "I" then + kicks = VRS.kicks_ccw.I[piece.rotation] + elseif ( + piece.shape == "T" or + piece.shape == "L" or + piece.shape == "J" + ) then + kicks = VRS.kicks_ccw.TLJ[piece.rotation] + elseif ( + piece.shape == "S" or + piece.shape == "Z" + ) then + kicks = VRS.kicks_ccw.SZ[piece.rotation] + else + kicks = VRS.kicks_ccw.O[piece.rotation] + end + 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) + return + end + end +end + +function VRS:onPieceCreate(piece) + piece.rotate_counter = 0 +end + +function VRS:onPieceDrop(piece) + piece.lock_delay = 0 -- step reset +end + +function VRS:onPieceRotate(piece) + piece.rotate_counter = piece.rotate_counter + 1 + piece.lock_delay = 0 +end + +function VRS:canPieceRotate(piece) + return piece.rotate_counter < 15 +end + +function VRS:get180RotationValue() return 3 end + +return VRS \ No newline at end of file