diff --git a/tetris/modes/marathon_A2_16.lua b/tetris/modes/marathon_A2_16.lua new file mode 100644 index 0000000..25bb016 --- /dev/null +++ b/tetris/modes/marathon_A2_16.lua @@ -0,0 +1,406 @@ +require 'funcs' + +local GameMode = require 'tetris.modes.gamemode' +local Piece = require 'tetris.components.piece' + +local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls' + +local MarathonA2Game = GameMode:extend() + +MarathonA2Game.name = "Marathon A2 ARS16" +MarathonA2Game.hash = "MarathonA2" +MarathonA2Game.tagline = "The requirements are easier but can you cope with 9 additional pieces?" + + + + +function MarathonA2Game:new() + MarathonA2Game.super:new() + + self.roll_frames = 0 + self.combo = 1 + self.grade_combo = 1 + self.randomizer = History6RollsRandomizer() + self.grade = 0 + self.grade_points = 0 + self.grade_point_decay_counter = 0 + self.section_start_time = 0 + self.section_times = { [0] = 0 } + self.section_tetrises = { [0] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } + self.tetris_count = 0 + + self.SGnames = { + "9", "8", "7", "6", "5", "4", "3", "2", "1", + "S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9", + "GM" + } + + self.additive_gravity = false + self.lock_drop = false + self.lock_hard_drop = false + self.enable_hold = false + self.next_queue_length = 1 +end + +function MarathonA2Game:getARE() + if self.level < 700 then return 27 + elseif self.level < 800 then return 18 + else return 14 end +end + +function MarathonA2Game:getLineARE() + if self.level < 600 then return 27 + elseif self.level < 700 then return 18 + elseif self.level < 800 then return 14 + else return 8 end +end + +function MarathonA2Game:getDasLimit() + if self.level < 500 then return 15 + elseif self.level < 900 then return 9 + else return 7 end +end + +function MarathonA2Game:getLineClearDelay() + if self.level < 500 then return 40 + elseif self.level < 600 then return 25 + elseif self.level < 700 then return 16 + elseif self.level < 800 then return 12 + else return 6 end +end + +function MarathonA2Game:getLockDelay() + if self.level < 900 then return 30 + else return 17 end +end + +function MarathonA2Game:getGravity() + if (self.level < 30) then return 4/256 + elseif (self.level < 35) then return 6/256 + elseif (self.level < 40) then return 8/256 + elseif (self.level < 50) then return 10/256 + elseif (self.level < 60) then return 12/256 + elseif (self.level < 70) then return 16/256 + elseif (self.level < 80) then return 32/256 + elseif (self.level < 90) then return 48/256 + elseif (self.level < 100) then return 64/256 + elseif (self.level < 120) then return 80/256 + elseif (self.level < 140) then return 96/256 + elseif (self.level < 160) then return 112/256 + elseif (self.level < 170) then return 128/256 + elseif (self.level < 200) then return 144/256 + elseif (self.level < 220) then return 4/256 + elseif (self.level < 230) then return 32/256 + elseif (self.level < 233) then return 64/256 + elseif (self.level < 236) then return 96/256 + elseif (self.level < 239) then return 128/256 + elseif (self.level < 243) then return 160/256 + elseif (self.level < 247) then return 192/256 + elseif (self.level < 251) then return 224/256 + elseif (self.level < 300) then return 1 + elseif (self.level < 330) then return 2 + elseif (self.level < 360) then return 3 + elseif (self.level < 400) then return 4 + elseif (self.level < 420) then return 5 + elseif (self.level < 450) then return 4 + elseif (self.level < 500) then return 3 + else return 20 + end +end + +function MarathonA2Game:advanceOneFrame() + if self.clear then + self.roll_frames = self.roll_frames + 1 + if self.roll_frames < 0 then return false end + if self.roll_frames > 3694 then + self.completed = true + if self.grade == 32 then + self.grade = 33 + end + end + elseif self.ready_frames == 0 then + self.frames = self.frames + 1 + end + return true +end + +function MarathonA2Game:onPieceEnter() + if (self.level % 100 ~= 99 and self.level ~= 998) and not self.clear and self.frames ~= 0 then + self.level = self.level + 1 + end +end + +function MarathonA2Game:updateScore(level, drop_bonus, cleared_lines) + if not self.clear then + self:updateGrade(cleared_lines) + if cleared_lines >= 4 then + self.tetris_count = self.tetris_count + 1 + end + if self.grid:checkForBravo(cleared_lines) then + self.bravo = 4 + else + self.bravo = 1 + end + if cleared_lines > 0 then + self.combo = self.combo + (cleared_lines - 1) * 2 + if cleared_lines > 1 then + self.grade_combo = self.grade_combo + 1 + end + self.score = self.score + ( + (math.ceil((level + cleared_lines) / 4) + drop_bonus) * + cleared_lines * self.combo * self.bravo + ) + else + self.combo = 1 + self.grade_combo = 1 + end + self.drop_bonus = 0 + else self.lines = self.lines + cleared_lines end +end + +function MarathonA2Game:onLineClear(cleared_row_count) + self:updateSectionTimes(self.level, self.level + cleared_row_count) + self.level = math.min(self.level + cleared_row_count, 999) + if self.level == 999 and not self.clear then + self.clear = true + self.grid:clear() + if self:qualifiesForMRoll() then self.grade = 32 end + self.roll_frames = -150 + end + self.lock_drop = self.level >= 900 + self.lock_hard_drop = self.level >= 900 +end + +function MarathonA2Game:updateSectionTimes(old_level, new_level) + if self.clear then return end + if math.floor(old_level / 100) < math.floor(new_level / 100) or + new_level >= 999 then + -- record new section + section_time = self.frames - self.section_start_time + self.section_times[math.floor(old_level / 100)] = section_time + self.section_start_time = self.frames + self.section_tetrises[math.floor(old_level / 100)] = self.tetris_count + self.tetris_count = 0 + end +end + +local grade_point_bonuses = { + {50, 100, 100, 100}, + {50, 100, 100, 100}, + {20, 50, 100, 100}, + {10, 15, 50, 100}, + {10, 21, 40, 100}, + {5, 15, 25, 30}, + {5, 12, 25, 30}, + {5, 12, 20, 30}, + {5, 12, 20, 30}, + {5, 12, 20, 30}, + {5, 20, 40, 80}, + {5, 20, 40, 80}, + {5, 20, 40, 80}, + {5, 20, 40, 80}, + {5, 20, 40, 80}, + {5, 20, 40, 80}, + {5, 20, 40, 80}, + {5, 20, 40, 80}, + {5, 20, 40, 80}, + {5, 20, 40, 80}, + {5, 20, 40, 80}, + {5, 20, 40, 80}, + {5, 20, 40, 80}, + {5, 20, 40, 80}, + {5, 20, 40, 80}, + {5, 20, 40, 80}, + {5, 20, 40, 80}, + {5, 20, 40, 80}, + {5, 20, 40, 80}, + {5, 20, 40, 80}, + {5, 20, 40, 80}, + {5, 20, 40, 80}, +} + +local grade_point_decays = { + 125, 80, 80, 50, 45, 45, 45, + 40, 40, 40, 40, 40, 30, 30, 30, + 20, 20, 20, 20, 20, + 15, 15, 15, 15, 15, 15, 15, 15, 15, 15, + 10, 10 +} + +local combo_multipliers = { + {1.0, 1.0, 1.0, 1.0}, + {1.2, 1.4, 1.5, 1.0}, + {1.2, 1.5, 1.8, 1.0}, + {1.4, 1.6, 2.0, 1.0}, + {1.4, 1.7, 2.2, 1.0}, + {1.4, 1.8, 2.3, 1.0}, + {1.4, 1.9, 2.4, 1.0}, + {1.5, 2.0, 2.5, 1.0}, + {1.5, 2.1, 2.6, 1.0}, + {2.0, 2.5, 3.0, 1.0}, +} + +local grade_conversion = { + [0] = 0, + 1, 2, 3, 4, 5, 5, 6, 6, 7, 7, + 7, 8, 8, 8, 9, 9, 9, 10, 11, 12, + 12, 12, 13, 13, 14, 14, 15, 15, 16, 16, + 17, 18, 19 +} + +function MarathonA2Game:whilePieceActive() + self.grade_point_decay_counter = self.grade_point_decay_counter + 1 + if self.grade_point_decay_counter >= grade_point_decays[self.grade + 1] then + self.grade_point_decay_counter = 0 + self.grade_points = math.max(0, self.grade_points - 1) + end +end + +function MarathonA2Game:updateGrade(cleared_lines) + if self.clear or cleared_lines == 0 then return + else + self.grade_points = self.grade_points + ( + math.ceil( + grade_point_bonuses[self.grade + 1][cleared_lines] * + combo_multipliers[math.min(self.grade_combo, 10)][cleared_lines] + ) * (1 + math.floor(self.level / 250)) + ) + if self.grade_points >= 100 and self.grade < 31 then + self.grade_points = 0 + self.grade = self.grade + 1 + end + end +end + +local tetris_requirements = { [0] = 1, 1, 1, 1, 1, 0, 0, 0, 0, 0 } + +function MarathonA2Game:qualifiesForMRoll() + if not self.clear then return false end + -- tetris requirements + for section = 0, 9 do + if self.section_tetrises[section] < tetris_requirements[section] then + return false + end + end + -- section time requirements + local section_average = 0 + for section = 0, 4 do + section_average = section_average + self.section_times[section] + if self.section_times[section] > frameTime(1,45) then + return false + end + end + -- section time average requirements + if self.section_times[5] > section_average / 5 then + return false + end + for section = 6, 9 do + if self.section_times[section] > self.section_times[section - 1] + 120 then + return false + end + end + if self.grade < 31 or self.frames > frameTime(13,30) then + return false + end + return true +end + +function MarathonA2Game:getLetterGrade() + local grade = grade_conversion[self.grade] + if grade < 9 then + return tostring(9 - grade) + elseif grade < 18 then + return "S" .. tostring(grade - 8) + elseif grade == 18 then + return "M" + else + return "GM" + end +end + +MarathonA2Game.rollOpacityFunction = function(age) + if age < 240 then return 1 + elseif age > 300 then return 0 + else return 1 - (age - 240) / 60 end +end + +MarathonA2Game.mRollOpacityFunction = function(age) + if age > 4 then return 0 + else return 1 - age / 4 end +end + +function MarathonA2Game:drawGrid() + if self.clear and not (self.completed or self.game_over) then + if self:qualifiesForMRoll() then + self.grid:drawInvisible(self.mRollOpacityFunction, nil, false) + else + self.grid:drawInvisible(self.rollOpacityFunction, nil, false) + end + else + self.grid:draw() + if self.piece ~= nil and self.level < 100 then + self:drawGhostPiece(ruleset) + end + end +end + +function MarathonA2Game: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("LEVEL", 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) + if self.clear then + if self:qualifiesForMRoll() then + if self.lines >= 32 and self.roll_frames > 3694 then love.graphics.setColor(1, 0.5, 0, 1) + else love.graphics.setColor(0, 1, 0, 1) end + else + if self.roll_frames > 3694 then love.graphics.setColor(1, 0.5, 0, 1) + else love.graphics.setColor(0, 1, 0, 1) end + end + end + love.graphics.printf(self:getLetterGrade(), 240, 140, 90, "left") + love.graphics.setColor(1, 1, 1, 1) + love.graphics.printf(self.score, 240, 220, 90, "left") + love.graphics.printf(self.level, 240, 340, 40, "right") + love.graphics.printf(self:getSectionEndLevel(), 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 MarathonA2Game:getHighscoreData() + return { + grade = grade_conversion[self.grade], + score = self.score, + level = self.level, + frames = self.frames, + } +end + +function MarathonA2Game:getSectionEndLevel() + if self.level >= 900 then return 999 + else return math.floor(self.level / 100 + 1) * 100 end +end + +function MarathonA2Game:getBackground() + return math.floor(self.level / 100) +end + +return MarathonA2Game diff --git a/tetris/rulesets/16ARS.lua b/tetris/rulesets/16ARS.lua new file mode 100644 index 0000000..e70551d --- /dev/null +++ b/tetris/rulesets/16ARS.lua @@ -0,0 +1,365 @@ +--local Piece = require 'tetris.components.piece' +local Ruleset = require 'tetris.rulesets.arika' + +local ARS = Ruleset:extend() + +ARS.name = "Ti-ARS16" +ARS.hash = "ArikaTI" + +ARS.spawn_positions = { + [1] = { x=5, y=4 }, + [2] = { x=4, y=5 }, + [3] = { x=4, y=5 }, + [4] = { x=5, y=5 }, + [5] = { x=4, y=5 }, + [6] = { x=4, y=5 }, + [7] = { x=4, y=5 }, + [8] = { x=5, y=4 }, + [9] = { x=4, y=5 }, + [10] = { x=4, y=5 }, + [11] = { x=5, y=5 }, + [12] = { x=4, y=5 }, + [13] = { x=4, y=5 }, + [14] = { x=4, y=5 }, + [15] = { x=4, y=5 }, + [16] = { x=4, y=5 }, + [17] = { x=5, y=4 }, + [18] = { x=4, y=5 }, + [19] = { x=4, y=5 }, + [20] = { x=5, y=5 }, + [21] = { x=4, y=5 }, + [22] = { x=4, y=5 }, + [23] = { x=4, y=5 }, + [24] = { x=5, y=4 }, + [25] = { x=4, y=5 }, +} + +ARS.big_spawn_positions = { + [1] = { x=3, y=2 }, + [2] = { x=2, y=3 }, + [3] = { x=2, y=3 }, + [4] = { x=3, y=3 }, + [5] = { x=2, y=3 }, + [6] = { x=2, y=3 }, + [7] = { x=2, y=3 }, +} + +ARS.next_sounds = { + [1] = "I", + [2] = "O", + [3] = "S", + [4] = "Z", + [5] = "L", + [6] = "J", + [7] = "Z", + [8] = "S", + [9] = "J", + [10] = "L", + [11] = "O", + [12] = "O", + [13] = "T", + [14] = "L", + [15] = "J", + [16] = "O", + [17] = "I", + [18] = "O", + [19] = "S", + [20] = "Z", + [21] = "L", + [22] = "J", + [23] = "Z", + [24] = "S", + [25] = "J" +} + +ARS.colourscheme = { + [1] = "R", + [2] = "B", + [3] = "O", + [4] = "Y", + [5] = "M", + [6] = "C", + [7] = "G", + [8] = "R", + [9] = "B", + [10] = "O", + [11] = "Y", + [12] = "M", + [13] = "C", + [14] = "G", + [15] = "B", + [16] = "M", + [17] = "R", + [18] = "B", + [19] = "O", + [20] = "Y", + [21] = "M", + [22] = "C", + [23] = "G", + [24] = "R", + [25] = "B" +} + +ARS.block_offsets = { + [1]={ + { {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} }, + { {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=0, y=2} }, + { {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} }, + { {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=0, y=2} }, + }, + [2]={ + { {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} }, + }, + [3]={ + { {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} }, + }, + [4]={ + { {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} }, + }, + [5]={ + { {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} }, + }, + [6]={ + { {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} }, + }, + [7]={ + { {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} }, + }, + [8]={ + { {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=0}, {x=-1, y=0}, {x=1, y=0} }, + { {x=0, y=-1}, {x=0, y=0}, {x=0, y=1} }, + }, + [9]={ + { {x=0, y=0}, {x=1, y=-0}, {x=0, y=1} }, + { {x=0, y=0}, {x=-1, y=0}, {x=0, y=1}, }, + { {x=0, y=0}, {x=0, y=-1}, {x=-1, y=0}, }, + { {x=0, y=0}, {x=1, y=0}, {x=0, y=-1}, }, + }, + [10]={ + { {x=0, y=1}, {x=1, y=0}, {x=2, y=0} }, + { {x=-1, y=0}, {x=0, y=1}, {x=0, y=2} }, + { {x=0, y=-1}, {x=-1, y=0}, {x=-2, y=0} }, + { {x=1, y=0}, {x=0, y=-1}, {x=0, y=-2} }, + }, + [11]={ + { {x=0, y=0}, }, + { {x=0, y=0}, }, + { {x=0, y=0}, }, + { {x=0, y=0}, }, + }, + [12]={ + { {x=1, y=1}, {x=0, y=0}, {x=-1, y=-1}, }, + { {x=-1, y=1}, {x=0, y=0}, {x=1, y=-1}, }, + { {x=1, y=1}, {x=0, y=0}, {x=-1, y=-1}, }, + { {x=-1, y=1}, {x=0, y=0}, {x=1, y=-1}, }, + }, + [13]={ + { {x=-1, y=-1}, {x=1, y=-1}, {x=0, y=-2} }, + { {x=0, y=0}, {x=0, y=-2}, {x=1, y=-1} }, + { {x=1, y=-1}, {x=-1, y=-1}, {x=0, y=0} }, + { {x=0, y=0}, {x=0, y=-2}, {x=-1, y=-1} }, + }, + [14]={ + { {x=0, y=0}, {x=1, y=0}, }, + { {x=0, y=0}, {x=0, y=1}, }, + { {x=0, y=0}, {x=1, y=0}, }, + { {x=0, y=0}, {x=0, y=1}, }, + }, + [15]={ + { {x=0, y=1}, {x=1, y=1}, {x=2, y=0} }, + { {x=-1, y=0}, {x=-1, y=1}, {x=0, y=2} }, + { {x=0, y=-1}, {x=-1, y=-1}, {x=-2, y=0} }, + { {x=1, y=0}, {x=1, y=-1}, {x=0, y=-2} }, + }, + [16]={ + { {x=1, y=1}, {x=0, y=0}, }, + { {x=-1, y=1}, {x=0, y=0}, }, + { {x=1, y=1}, {x=0, y=0}, }, + { {x=-1, y=1}, {x=0, y=0}, }, + }, + [17]={ + { {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} }, + { {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=0, y=2} }, + { {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} }, + { {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=0, y=2} }, + }, + [18]={ + { {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} }, + }, + [19]={ + { {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} }, + }, + [20]={ + { {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} }, + }, + [21]={ + { {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} }, + }, + [22]={ + { {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} }, + }, + [23]={ + { {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} }, + }, + [24]={ + { {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=0}, {x=-1, y=0}, {x=1, y=0} }, + { {x=0, y=-1}, {x=0, y=0}, {x=0, y=1} }, + }, + [25]={ + { {x=0, y=0}, {x=1, y=-0}, {x=0, y=1} }, + { {x=0, y=0}, {x=-1, y=0}, {x=0, y=1}, }, + { {x=0, y=0}, {x=0, y=-1}, {x=-1, y=0}, }, + { {x=0, y=0}, {x=1, y=0}, {x=0, y=-1}, }, + }, + +} + +ARS.pieces = 25 + +function ARS:get180RotationValue() + return 3 +end + +function ARS:getDefaultOrientation() return 3 end -- downward facing pieces by default + + +-- Component functions. + +function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid) + + -- O doesn't kick + if (piece.shape == "4") then return end + + -- center column rule + if ( + piece.shape == "2" or piece.shape == "6" or piece.shape == "3" + ) and ( + piece.rotation == 0 or piece.rotation == 2 + ) then + local offsets = new_piece:getBlockOffsets() + table.sort(offsets, function(A, B) return A.y < B.y or A.y == B.y and A.x < B.y end) + for index, offset in pairs(offsets) do + if grid:isOccupied(piece.position.x + offset.x, piece.position.y + offset.y) then + if offset.x == 0 then + return + else + break + end + end + end + end + + if piece.shape == "1" then + -- special kick rules for I + if (new_piece.rotation == 0 or new_piece.rotation == 2) and + (piece:isMoveBlocked(grid, {x=-1, y=0}) or piece:isMoveBlocked(grid, {x=1, y=0})) then + -- kick right, right2, left + if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then + piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0}) + self:onPieceRotate(piece, grid) + elseif grid:canPlacePiece(new_piece:withOffset({x=2, y=0})) then + piece:setRelativeRotation(rot_dir):setOffset({x=2, y=0}) + self:onPieceRotate(piece, grid) + elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then + piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0}) + self:onPieceRotate(piece, grid) + end + elseif piece:isDropBlocked(grid) and (new_piece.rotation == 1 or new_piece.rotation == 3) and piece.floorkick == 0 then + -- kick up, up2 + if grid:canPlacePiece(new_piece:withOffset({x=0, y=-1})) then + piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1}) + piece.floorkick = 1 + self:onPieceRotate(piece, grid, true) + elseif grid:canPlacePiece(new_piece:withOffset({x=0, y=-2})) then + piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-2}) + piece.floorkick = 1 + self:onPieceRotate(piece, grid, true) + end + 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}) + self:onPieceRotate(piece, grid) + elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then + piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0}) + self:onPieceRotate(piece, grid) + elseif piece.shape == "6" + and new_piece.rotation == 0 + and piece.floorkick == 0 + and piece:isDropBlocked(grid) + and grid:canPlacePiece(new_piece:withOffset({x=0, y=-1})) + then + -- T floorkick + piece.floorkick = piece.floorkick + 1 + piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1}) + self:onPieceRotate(piece, grid, true) + end + end + +end + +function ARS:onPieceCreate(piece, grid) + piece.floorkick = 0 +end + +function ARS:onPieceDrop(piece, grid) + piece.lock_delay = 0 -- step reset + if piece.floorkick >= 2 and piece:isDropBlocked(grid) then + piece.locked = true + end +end + +function ARS:onPieceRotate(piece, grid, floorkick) + if piece.floorkick >= 2 and piece:isDropBlocked(grid) then + piece.locked = true + elseif piece.floorkick >= 1 and not floorkick then + piece.floorkick = piece.floorkick + 1 + end +end + +function ARS:get180RotationValue() return 3 end + +function ARS:getDefaultOrientation() return 3 end -- downward facing pieces by default + +return ARS