diff --git a/docs/gamemodes.md b/docs/gamemodes.md index 19b755e..828cf42 100644 --- a/docs/gamemodes.md +++ b/docs/gamemodes.md @@ -28,7 +28,9 @@ From other games: * **MARATHON A1**: Tetris the Grand Master 1. * **MARATHON A2**: Tetris the Grand Master 2 (TAP Master). * **MARATHON A3**: Tetris the Grand Master 3 (no exams). -* **MARATHON AX4**: Another mode from TGM Ace. +* **MARATHON AX**: Normal mode from TGM Ace. +* **MARATHON AX2**: Hi-Speed1 mode from TGM Ace. +* **MARATHON AX3**: Hi-Speed2 mode from TGM Ace. * **MARATHON C89**: Nintendo NES Tetris. Can you transition and make it to the killscreen? @@ -43,6 +45,8 @@ From other games: * **SURVIVAL A1**: 20G mode from Tetris the Grand Master. * **SURVIVAL A2**: T.A. Death. * **SURVIVAL A3**: Ti Shirase. +* **SURVIVAL AX**: Another mode from TGM Ace. +* **SURVIVAL AX2**: Another2 mode from TGM Ace. RACE @@ -63,7 +67,6 @@ Modes where pieces turn invisible as soon as you lock them. One of Cambridge's s * **Phantom Mania 2**: Phantom Mania but way faster! Can you face a mode where even the garbage and the next preview turn invisible? - OTHER MODES ----------- diff --git a/scene/mode_select.lua b/scene/mode_select.lua index a8b4573..e97d8e4 100644 --- a/scene/mode_select.lua +++ b/scene/mode_select.lua @@ -19,17 +19,22 @@ game_modes = { require 'tetris.modes.marathon_a1', require 'tetris.modes.marathon_a2', require 'tetris.modes.marathon_a3', - require 'tetris.modes.marathon_ax4', + require 'tetris.modes.marathon_ax', + require 'tetris.modes.marathon_ax2', + require 'tetris.modes.marathon_ax3', require 'tetris.modes.marathon_c89', require 'tetris.modes.survival_a1', require 'tetris.modes.survival_a2', require 'tetris.modes.survival_a3', + require 'tetris.modes.survival_ax', + require 'tetris.modes.survival_ax2', } rulesets = { require 'tetris.rulesets.cambridge', require 'tetris.rulesets.arika', require 'tetris.rulesets.arika_ti', + require 'tetris.rulesets.arika_ace', require 'tetris.rulesets.standard_exp', --require 'tetris.rulesets.bonkers', --require 'tetris.rulesets.shirase', diff --git a/tetris/modes/marathon_ax4.lua b/tetris/modes/marathon_ax.lua similarity index 55% rename from tetris/modes/marathon_ax4.lua rename to tetris/modes/marathon_ax.lua index 4ae54d3..4ef60cc 100644 --- a/tetris/modes/marathon_ax4.lua +++ b/tetris/modes/marathon_ax.lua @@ -5,20 +5,19 @@ local Piece = require 'tetris.components.piece' local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls' -local MarathonAX4Game = GameMode:extend() +local MarathonAXGame = GameMode:extend() -MarathonAX4Game.name = "Marathon AX4" -MarathonAX4Game.hash = "MarathonAX4" -MarathonAX4Game.tagline = "Can you clear the time hurdles when the game goes this fast?" +MarathonAXGame.name = "Marathon AX" +MarathonAXGame.hash = "MarathonAX" +MarathonAXGame.tagline = "Can you clear the time hurdles when the game goes this fast?" -function MarathonAX4Game:new() - MarathonAX4Game.super:new() +function MarathonAXGame:new() + MarathonAXGame.super:new() self.roll_frames = 0 self.randomizer = History6RollsRandomizer() - self.section_time_limit = 3600 self.section_start_time = 0 self.section_times = { [0] = 0 } self.section_clear = false @@ -28,52 +27,48 @@ function MarathonAX4Game:new() self.next_queue_length = 3 end -function MarathonAX4Game:getARE() - if self.lines < 10 then return 18 - elseif self.lines < 40 then return 14 - elseif self.lines < 60 then return 12 - elseif self.lines < 70 then return 10 - elseif self.lines < 80 then return 8 - elseif self.lines < 90 then return 7 - else return 6 end +function MarathonAXGame:getSectionTimeLimit() + if self.lines < 20 then return 7200 + else return 5400 end end -function MarathonAX4Game:getLineARE() +function MarathonAXGame:getARE() + return 27 +end + +function MarathonAXGame:getLineARE() return self:getARE() end -function MarathonAX4Game:getDasLimit() - if self.lines < 20 then return 10 - elseif self.lines < 50 then return 9 - elseif self.lines < 70 then return 8 - else return 7 end +function MarathonAXGame:getDasLimit() + return 15 end -function MarathonAX4Game:getLineClearDelay() - if self.lines < 10 then return 14 - elseif self.lines < 30 then return 9 - else return 5 end +function MarathonAXGame:getLineClearDelay() + return 40 end -function MarathonAX4Game:getLockDelay() - if self.lines < 10 then return 28 - elseif self.lines < 20 then return 24 - elseif self.lines < 30 then return 22 - elseif self.lines < 40 then return 20 - elseif self.lines < 50 then return 18 - elseif self.lines < 70 then return 14 - else return 13 end +function MarathonAXGame:getLockDelay() + return 30 end -function MarathonAX4Game:getGravity() - return 20 +function MarathonAXGame:getGravity() + if self.lines < 10 then return 4/256 + elseif self.lines < 20 then return 12/256 + elseif self.lines < 30 then return 48/256 + elseif self.lines < 40 then return 72/256 + elseif self.lines < 50 then return 96/256 + elseif self.lines < 60 then return 1/2 + elseif self.lines < 70 then return 1 + elseif self.lines < 80 then return 3/2 + elseif self.lines < 90 then return 2 + elseif self.lines < 100 then return 3 + elseif self.lines < 110 then return 4 + elseif self.lines < 120 then return 5 + else return 20 end end -function MarathonAX4Game:getSection() - return math.floor(level / 100) + 1 -end - -function MarathonAX4Game:advanceOneFrame() +function MarathonAXGame:advanceOneFrame() if self.clear then self.roll_frames = self.roll_frames + 1 if self.roll_frames < 0 then @@ -85,14 +80,14 @@ function MarathonAX4Game:advanceOneFrame() if not self.section_clear then self.frames = self.frames + 1 end - if self:getSectionTime() >= self.section_time_limit then + if self:getSectionTime() >= self:getSectionTimeLimit() then self.game_over = true end end return true end -function MarathonAX4Game:onLineClear(cleared_row_count) +function MarathonAXGame:onLineClear(cleared_row_count) if not self.clear then local new_lines = self.lines + cleared_row_count self:updateSectionTimes(self.lines, new_lines) @@ -104,11 +99,11 @@ function MarathonAX4Game:onLineClear(cleared_row_count) end end -function MarathonAX4Game:getSectionTime() +function MarathonAXGame:getSectionTime() return self.frames - self.section_start_time end -function MarathonAX4Game:updateSectionTimes(old_lines, new_lines) +function MarathonAXGame:updateSectionTimes(old_lines, new_lines) if math.floor(old_lines / 10) < math.floor(new_lines / 10) then -- record new section table.insert(self.section_times, self:getSectionTime()) @@ -117,23 +112,23 @@ function MarathonAX4Game:updateSectionTimes(old_lines, new_lines) end end -function MarathonAX4Game:onPieceEnter() +function MarathonAXGame:onPieceEnter() self.section_clear = false end -function MarathonAX4Game:drawGrid(ruleset) +function MarathonAXGame:drawGrid(ruleset) self.grid:draw() end -function MarathonAX4Game:getHighscoreData() +function MarathonAXGame:getHighscoreData() return { lines = self.lines, frames = self.frames, } end -function MarathonAX4Game:drawScoringInfo() - MarathonAX4Game.super.drawScoringInfo(self) +function MarathonAXGame:drawScoringInfo() + MarathonAXGame.super.drawScoringInfo(self) love.graphics.setColor(1, 1, 1, 1) @@ -155,7 +150,7 @@ function MarathonAX4Game:drawScoringInfo() love.graphics.printf(self.clear and self.lines or self:getSectionEndLines(), 240, 370, 40, "right") -- draw time left, flash red if necessary - local time_left = self.section_time_limit - math.max(self:getSectionTime(), 0) + local time_left = self:getSectionTimeLimit() - math.max(self:getSectionTime(), 0) if not self.game_over and not self.clear and time_left < sp(0,10) and time_left % 4 < 2 then love.graphics.setColor(1, 0.3, 0.3, 1) end @@ -163,12 +158,12 @@ function MarathonAX4Game:drawScoringInfo() love.graphics.setColor(1, 1, 1, 1) end -function MarathonAX4Game:getSectionEndLines() +function MarathonAXGame:getSectionEndLines() return math.floor(self.lines / 10 + 1) * 10 end -function MarathonAX4Game:getBackground() +function MarathonAXGame:getBackground() return math.floor(self.lines / 10) end -return MarathonAX4Game +return MarathonAXGame diff --git a/tetris/modes/marathon_ax2.lua b/tetris/modes/marathon_ax2.lua new file mode 100644 index 0000000..dc93baf --- /dev/null +++ b/tetris/modes/marathon_ax2.lua @@ -0,0 +1,42 @@ +require 'funcs' + +local MarathonAX = require 'tetris.modes.marathon_ax' +local Piece = require 'tetris.components.piece' + +local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls' + +local MarathonAX2Game = MarathonAX:extend() + +MarathonAX2Game.name = "Marathon AX2" +MarathonAX2Game.hash = "MarathonAX2" +MarathonAX2Game.tagline = "Can you clear the time hurdles when the game goes this fast?" + + +function MarathonAX2Game:new() + MarathonAX2Game.super:new() + + self.roll_frames = 0 + self.randomizer = History6RollsRandomizer() + + self.section_time_limit = 3600 + self.section_start_time = 0 + self.section_times = { [0] = 0 } + self.section_clear = false + + self.lock_drop = true + self.enable_hold = true + self.next_queue_length = 3 +end + +function MarathonAX2Game:getGravity() + if self.lines < 10 then return 84/256 + elseif self.lines < 20 then return 1/2 + elseif self.lines < 30 then return 1 + elseif self.lines < 40 then return 2 + elseif self.lines < 50 then return 3 + elseif self.lines < 60 then return 4 + elseif self.lines < 70 then return 5 + else return 20 end +end + +return MarathonAX2Game diff --git a/tetris/modes/marathon_ax3.lua b/tetris/modes/marathon_ax3.lua new file mode 100644 index 0000000..f01a62f --- /dev/null +++ b/tetris/modes/marathon_ax3.lua @@ -0,0 +1,35 @@ +require 'funcs' + +local MarathonAX = require 'tetris.modes.marathon_ax' +local Piece = require 'tetris.components.piece' + +local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls' + +local MarathonAX3Game = MarathonAX:extend() + +MarathonAX3Game.name = "Marathon AX3" +MarathonAX3Game.hash = "MarathonAX3" +MarathonAX3Game.tagline = "Can you clear the time hurdles when the game goes this fast?" + + +function MarathonAX3Game:new() + MarathonAX3Game.super:new() + + self.roll_frames = 0 + self.randomizer = History6RollsRandomizer() + + self.section_time_limit = 3600 + self.section_start_time = 0 + self.section_times = { [0] = 0 } + self.section_clear = false + + self.lock_drop = true + self.enable_hold = true + self.next_queue_length = 3 +end + +function MarathonAX3Game:getGravity() + return 20 +end + +return MarathonAX3Game diff --git a/tetris/modes/survival_ax.lua b/tetris/modes/survival_ax.lua new file mode 100644 index 0000000..3ccec75 --- /dev/null +++ b/tetris/modes/survival_ax.lua @@ -0,0 +1,76 @@ +require 'funcs' + +local MarathonAX = require 'tetris.modes.marathon_ax' +local Piece = require 'tetris.components.piece' + +local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls' + +local SurvivalAXGame = MarathonAX:extend() + +SurvivalAXGame.name = "Survival AX" +SurvivalAXGame.hash = "SurvivalAX" +SurvivalAXGame.tagline = "Can you clear the time hurdles when the game goes this fast?" + + +function SurvivalAXGame:new() + SurvivalAXGame.super:new() + + self.roll_frames = 0 + self.randomizer = History6RollsRandomizer() + + self.section_time_limit = 3600 + self.section_start_time = 0 + self.section_times = { [0] = 0 } + self.section_clear = false + + self.lock_drop = true + self.enable_hold = true + self.next_queue_length = 3 +end + +function SurvivalAXGame:getSectionTimeLimit() + return 3600 +end + +function SurvivalAXGame:getARE() + if self.lines < 10 then return 18 + elseif self.lines < 40 then return 14 + elseif self.lines < 60 then return 12 + elseif self.lines < 70 then return 10 + elseif self.lines < 80 then return 8 + elseif self.lines < 90 then return 7 + else return 6 end +end + +function SurvivalAXGame:getLineARE() + return self:getARE() +end + +function SurvivalAXGame:getDasLimit() + if self.lines < 20 then return 10 + elseif self.lines < 50 then return 9 + elseif self.lines < 70 then return 8 + else return 7 end +end + +function SurvivalAXGame:getLineClearDelay() + if self.lines < 10 then return 14 + elseif self.lines < 30 then return 8 + else return 5 end +end + +function SurvivalAXGame:getLockDelay() + if self.lines < 10 then return 30 + elseif self.lines < 20 then return 26 + elseif self.lines < 30 then return 24 + elseif self.lines < 40 then return 22 + elseif self.lines < 50 then return 20 + elseif self.lines < 70 then return 16 + else return 15 end +end + +function SurvivalAXGame:getGravity() + return 20 +end + +return SurvivalAXGame diff --git a/tetris/modes/survival_ax2.lua b/tetris/modes/survival_ax2.lua new file mode 100644 index 0000000..ca750ed --- /dev/null +++ b/tetris/modes/survival_ax2.lua @@ -0,0 +1,59 @@ +require 'funcs' + +local MarathonAX2 = require 'tetris.modes.marathon_AX2' +local Piece = require 'tetris.components.piece' + +local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls' + +local SurvivalAX2Game = MarathonAX2:extend() + +SurvivalAX2Game.name = "Survival AX2" +SurvivalAX2Game.hash = "SurvivalAX2" +SurvivalAX2Game.tagline = "Can you clear the time hurdles when the game goes this fast?" + + +function SurvivalAX2Game:new() + SurvivalAX2Game.super:new() + + self.roll_frames = 0 + self.randomizer = History6RollsRandomizer() + + self.section_time_limit = 3600 + self.section_start_time = 0 + self.section_times = { [0] = 0 } + self.section_clear = false + + self.lock_drop = true + self.enable_hold = true + self.next_queue_length = 3 +end + +function SurvivalAX2Game:getSectionTimeLimit() + return 3600 +end + +function SurvivalAX2Game:getARE() + return 6 +end + +function SurvivalAX2Game:getLineARE() + return self:getARE() +end + +function SurvivalAX2Game:getDasLimit() + return 7 +end + +function SurvivalAX2Game:getLineClearDelay() + return 5 +end + +function SurvivalAX2Game:getLockDelay() + return 15 +end + +function SurvivalAX2Game:getGravity() + return 20 +end + +return SurvivalAX2Game diff --git a/tetris/rulesets/arika_ace.lua b/tetris/rulesets/arika_ace.lua new file mode 100644 index 0000000..21065ee --- /dev/null +++ b/tetris/rulesets/arika_ace.lua @@ -0,0 +1,32 @@ +local ArikaTI = require 'tetris.rulesets.arika_ti' + +local ARS = ArikaTI:extend() + +ARS.name = "Ace-ARS" +ARS.hash = "ArikaAce" + +function ARS:onPieceCreate(piece, grid) + piece.floorkick = 0 + piece.rotate_counter = 0 + piece.move_counter = 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.move_counter = piece.move_counter + 1 + if piece.move_counter >= 128 then + piece.locked = true + end + end +end + +function ARS:onPieceRotate(piece, grid) + self:onPieceMove(piece, grid) +end + +return ARS \ No newline at end of file diff --git a/tetris/rulesets/arika_ti.lua b/tetris/rulesets/arika_ti.lua index e477595..b85dca5 100644 --- a/tetris/rulesets/arika_ti.lua +++ b/tetris/rulesets/arika_ti.lua @@ -117,13 +117,12 @@ function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid) end end elseif piece.shape ~= "I" then - -- 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}) - 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}) + end end end diff --git a/tetris/rulesets/cambridge.lua b/tetris/rulesets/cambridge.lua index 148e5c1..0e0eded 100644 --- a/tetris/rulesets/cambridge.lua +++ b/tetris/rulesets/cambridge.lua @@ -398,6 +398,7 @@ function CRS:onPieceDrop(piece, grid) end function CRS:onPieceMove(piece, grid) + piece.lock_delay = 0 -- move reset if piece:isDropBlocked(grid) then piece.move_counter = piece.move_counter + 1 if piece.move_counter >= 24 then @@ -407,6 +408,7 @@ function CRS:onPieceMove(piece, grid) end function CRS:onPieceRotate(piece, grid) + piece.lock_delay = 0 -- move reset if piece:isDropBlocked(grid) then piece.rotate_counter = piece.rotate_counter + 1 if piece.rotate_counter >= 12 then @@ -415,6 +417,4 @@ function CRS:onPieceRotate(piece, grid) end end -function CRS:getDefaultOrientation() return 1 end -- downward facing pieces by default - return CRS