mirror of
https://github.com/SashLilac/cambridge.git
synced 2024-12-22 16:59:02 -06:00
Removed modes from core game to create modpack. Check README
This commit is contained in:
parent
a470b40def
commit
10a9d97848
@ -50,7 +50,7 @@ Then, navigate to the root directory that you just cloned, and type:
|
||||
|
||||
It should run automatically!
|
||||
|
||||
## Windows
|
||||
### Windows
|
||||
|
||||
You do not need LÖVE on Windows, as it comes bundled with the program. Download the source code ZIP in the latest release, or if you want the bleeding edge version, download [this](https://github.com/SashLilac/cambridge/archive/master.zip).
|
||||
|
||||
@ -64,6 +64,12 @@ Alternatively, if you're on a 32-bit system, run this instead:
|
||||
|
||||
32-bit systems do not support rich presence integration.
|
||||
|
||||
## Installing modpacks
|
||||
|
||||
Simply drag your mode, ruleset, and randomizer Lua files into their respective directory, and they should appear automatically.
|
||||
|
||||
Alternatively, install [this](https://files.catbox.moe/66td2i.zip) mod pack to get a taste of the mod potential.
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
|
@ -1,39 +0,0 @@
|
||||
require 'funcs'
|
||||
|
||||
local SurvivalA3Game = require 'tetris.modes.survival_a3'
|
||||
|
||||
local FourWideGame = SurvivalA3Game:extend()
|
||||
|
||||
FourWideGame.name = "4-wide Simulator"
|
||||
FourWideGame.hash = "4wide"
|
||||
FourWideGame.tagline = "The board has gotten narrower! Can you survive the increasing speeds?"
|
||||
|
||||
function FourWideGame:initialize(ruleset)
|
||||
self.super:initialize(ruleset)
|
||||
self.grid:applyFourWide()
|
||||
end
|
||||
|
||||
local cleared_row_levels = {1, 2, 4, 6}
|
||||
|
||||
function FourWideGame:onLineClear(cleared_row_count)
|
||||
if not self.clear then
|
||||
local new_level = self.level + cleared_row_levels[cleared_row_count]
|
||||
self:updateSectionTimes(self.level, new_level)
|
||||
if new_level >= 1300 or self:hitTorikan(self.level, new_level) then
|
||||
self.clear = true
|
||||
if new_level >= 1300 then
|
||||
self.level = 1300
|
||||
self.grid:clear()
|
||||
self.roll_frames = -150
|
||||
else
|
||||
self.game_over = true
|
||||
end
|
||||
else
|
||||
self.level = math.min(new_level, 1300)
|
||||
end
|
||||
self:advanceBottomRow(-cleared_row_count)
|
||||
end
|
||||
self.grid:applyFourWide()
|
||||
end
|
||||
|
||||
return FourWideGame
|
@ -1,328 +0,0 @@
|
||||
require 'funcs'
|
||||
|
||||
local GameMode = require 'tetris.modes.gamemode'
|
||||
local Piece = require 'tetris.components.piece'
|
||||
|
||||
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls_35bag'
|
||||
|
||||
local SurvivalCKGame = GameMode:extend()
|
||||
|
||||
SurvivalCKGame.name = "Survival CK"
|
||||
SurvivalCKGame.hash = "SurvivalCK"
|
||||
SurvivalCKGame.tagline = "An endurance mode created by CylinderKnot! Watch out for the fading pieces..."
|
||||
|
||||
function SurvivalCKGame:new()
|
||||
SurvivalCKGame.super:new()
|
||||
|
||||
self.garbage = 0
|
||||
self.roll_frames = 0
|
||||
self.combo = 1
|
||||
self.grade = 0
|
||||
self.level = 0
|
||||
|
||||
self.randomizer = History6RollsRandomizer()
|
||||
|
||||
self.lock_drop = true
|
||||
self.enable_hold = true
|
||||
self.next_queue_length = 3
|
||||
|
||||
self.coolregret_timer = 0
|
||||
end
|
||||
|
||||
function SurvivalCKGame:getARE()
|
||||
if self.level < 100 then return 15
|
||||
elseif self.level < 200 then return 14
|
||||
elseif self.level < 300 then return 13
|
||||
elseif self.level < 400 then return 12
|
||||
elseif self.level < 500 then return 11
|
||||
elseif self.level < 600 then return 10
|
||||
elseif self.level < 700 then return 9
|
||||
elseif self.level < 800 then return 8
|
||||
elseif self.level < 900 then return 7
|
||||
elseif self.level < 1000 then return 6
|
||||
elseif self.level < 2500 then return 5
|
||||
else return 7 end
|
||||
end
|
||||
|
||||
|
||||
function SurvivalCKGame:getLineARE()
|
||||
return SurvivalCKGame:getARE()
|
||||
end
|
||||
|
||||
function SurvivalCKGame:getDasLimit()
|
||||
if self.level < 700 then return 10
|
||||
elseif self.level < 900 then return 9
|
||||
elseif self.level < 1100 then return 8
|
||||
elseif self.level < 1300 then return 7
|
||||
elseif self.level < 1600 then return 6
|
||||
else return 5 end
|
||||
end
|
||||
|
||||
function SurvivalCKGame:getLineClearDelay()
|
||||
if self.level < 100 then return 10
|
||||
elseif self.level < 200 then return 8
|
||||
elseif self.level < 300 then return 7
|
||||
elseif self.level < 400 then return 6
|
||||
else return 5 end
|
||||
end
|
||||
|
||||
function SurvivalCKGame:getLockDelay()
|
||||
if self.level < 600 then return 20
|
||||
elseif self.level < 700 then return 19
|
||||
elseif self.level < 800 then return 18
|
||||
elseif self.level < 900 then return 17
|
||||
elseif self.level < 1000 then return 16
|
||||
elseif self.level < 1200 then return 15
|
||||
elseif self.level < 1400 then return 14
|
||||
elseif self.level < 1700 then return 13
|
||||
elseif self.level < 2100 then return 12
|
||||
elseif self.level < 2200 then return 11
|
||||
elseif self.level < 2300 then return 10
|
||||
elseif self.level < 2400 then return 9
|
||||
elseif self.level < 2500 then return 8
|
||||
else return 15 end
|
||||
end
|
||||
|
||||
function SurvivalCKGame:getGravity()
|
||||
return 20
|
||||
end
|
||||
|
||||
function SurvivalCKGame:getGarbageLimit()
|
||||
if self.level < 1000 then return 20
|
||||
elseif self.level < 1100 then return 17
|
||||
elseif self.level < 1200 then return 14
|
||||
elseif self.level < 1300 then return 11
|
||||
else return 8 end
|
||||
end
|
||||
|
||||
function SurvivalCKGame:getRegretTime()
|
||||
if self.level < 500 then return frameTime(0,55)
|
||||
elseif self.level < 1000 then return frameTime(0,50)
|
||||
elseif self.level < 1500 then return frameTime(0,40)
|
||||
elseif self.level < 2000 then return frameTime(0,35)
|
||||
else return frameTime(0,30) end
|
||||
end
|
||||
|
||||
function SurvivalCKGame:getNextPiece(ruleset)
|
||||
return {
|
||||
skin = self.level >= 2000 and "bone" or "2tie",
|
||||
shape = self.randomizer:nextPiece(),
|
||||
orientation = ruleset:getDefaultOrientation(),
|
||||
}
|
||||
end
|
||||
|
||||
local torikan_times = {300, 330, 360, 390, 420, 450, 478, 504, 528, 550, 570}
|
||||
|
||||
function SurvivalCKGame:hitTorikan(old_level, new_level)
|
||||
for i = 1, 11 do
|
||||
if old_level < (900 + i * 100) and new_level >= (900 + i * 100) and self.frames > torikan_times[i] * 60 then
|
||||
self.level = 900 + i * 100
|
||||
return true
|
||||
end
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
function SurvivalCKGame:advanceOneFrame()
|
||||
if self.clear then
|
||||
self.roll_frames = self.roll_frames + 1
|
||||
if self.roll_frames < 0 then
|
||||
if self.roll_frames + 1 == 0 then
|
||||
switchBGM("credit_roll", "gm3")
|
||||
return true
|
||||
end
|
||||
return false
|
||||
elseif self.roll_frames > 3238 then
|
||||
switchBGM(nil)
|
||||
if self.grade ~= 20 then self.grade = self.grade + 1 end
|
||||
self.completed = true
|
||||
end
|
||||
elseif self.ready_frames == 0 then
|
||||
self.frames = self.frames + 1
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function SurvivalCKGame:onPieceEnter()
|
||||
if (self.level % 100 ~= 99) and not self.clear and self.frames ~= 0 then
|
||||
self.level = self.level + 1
|
||||
end
|
||||
end
|
||||
|
||||
function SurvivalCKGame:onLineClear(cleared_row_count)
|
||||
if not self.clear then
|
||||
local new_level = self.level + cleared_row_count * 2
|
||||
self:updateSectionTimes(self.level, new_level)
|
||||
if new_level >= 2500 or self:hitTorikan(self.level, new_level) then
|
||||
self.clear = true
|
||||
if new_level >= 2500 then
|
||||
self.level = 2500
|
||||
self.grid:clear()
|
||||
self.big_mode = true
|
||||
self.roll_frames = -150
|
||||
end
|
||||
else
|
||||
self.level = math.min(new_level, 2500)
|
||||
end
|
||||
self:advanceBottomRow(-cleared_row_count)
|
||||
end
|
||||
end
|
||||
|
||||
function SurvivalCKGame:onPieceLock(piece, cleared_row_count)
|
||||
self.super:onPieceLock()
|
||||
if cleared_row_count == 0 then self:advanceBottomRow(1) end
|
||||
end
|
||||
|
||||
function SurvivalCKGame:updateScore(level, drop_bonus, cleared_lines)
|
||||
if not self.clear then
|
||||
if cleared_lines > 0 then
|
||||
self.combo = self.combo + (cleared_lines - 1) * 2
|
||||
self.score = self.score + (
|
||||
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
||||
cleared_lines * self.combo
|
||||
)
|
||||
else
|
||||
self.combo = 1
|
||||
end
|
||||
self.drop_bonus = 0
|
||||
end
|
||||
end
|
||||
|
||||
function SurvivalCKGame:updateSectionTimes(old_level, new_level)
|
||||
if math.floor(old_level / 100) < math.floor(new_level / 100) then
|
||||
local section = math.floor(old_level / 100) + 1
|
||||
section_time = self.frames - self.section_start_time
|
||||
table.insert(self.section_times, section_time)
|
||||
self.section_start_time = self.frames
|
||||
if section_time <= self:getRegretTime(self.level) then
|
||||
self.grade = self.grade + 1
|
||||
else
|
||||
self.coolregret_message = "REGRET!!"
|
||||
self.coolregret_timer = 300
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SurvivalCKGame:advanceBottomRow(dx)
|
||||
if self.level >= 1000 and self.level < 1500 then
|
||||
self.garbage = math.max(self.garbage + dx, 0)
|
||||
if self.garbage >= self:getGarbageLimit() then
|
||||
self.grid:copyBottomRow()
|
||||
self.garbage = 0
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SurvivalCKGame:drawGrid()
|
||||
if self.level >= 1500 and self.level < 1600 then
|
||||
self.grid:drawInvisible(self.rollOpacityFunction1)
|
||||
elseif self.level >= 1600 and self.level < 1700 then
|
||||
self.grid:drawInvisible(self.rollOpacityFunction2)
|
||||
elseif self.level >= 1700 and self.level < 1800 then
|
||||
self.grid:drawInvisible(self.rollOpacityFunction3)
|
||||
elseif self.level >= 1800 and self.level < 1900 then
|
||||
self.grid:drawInvisible(self.rollOpacityFunction4)
|
||||
elseif self.level >= 1900 and self.level < 2000 then
|
||||
self.grid:drawInvisible(self.rollOpacityFunction5)
|
||||
else
|
||||
self.grid:draw()
|
||||
end
|
||||
end
|
||||
|
||||
-- screw trying to make this work efficiently
|
||||
-- lua function variables are so garbage
|
||||
|
||||
SurvivalCKGame.rollOpacityFunction1 = function(age)
|
||||
if age < 420 then return 1
|
||||
elseif age > 480 then return 0
|
||||
else return 1 - (age - 420) / 60 end
|
||||
end
|
||||
|
||||
SurvivalCKGame.rollOpacityFunction2 = function(age)
|
||||
if age < 360 then return 1
|
||||
elseif age > 420 then return 0
|
||||
else return 1 - (age - 360) / 60 end
|
||||
end
|
||||
|
||||
SurvivalCKGame.rollOpacityFunction3 = function(age)
|
||||
if age < 300 then return 1
|
||||
elseif age > 360 then return 0
|
||||
else return 1 - (age - 300) / 60 end
|
||||
end
|
||||
|
||||
SurvivalCKGame.rollOpacityFunction4 = function(age)
|
||||
if age < 240 then return 1
|
||||
elseif age > 300 then return 0
|
||||
else return 1 - (age - 240) / 60 end
|
||||
end
|
||||
|
||||
SurvivalCKGame.rollOpacityFunction5 = function(age)
|
||||
if age < 180 then return 1
|
||||
elseif age > 240 then return 0
|
||||
else return 1 - (age - 180) / 60 end
|
||||
end
|
||||
|
||||
local master_grades = { "M", "MK", "MV", "MO", "MM" }
|
||||
|
||||
function SurvivalCKGame:getLetterGrade()
|
||||
if self.grade == 0 then
|
||||
return "1"
|
||||
elseif self.grade < 10 then
|
||||
return "S" .. tostring(self.grade)
|
||||
elseif self.grade < 21 then
|
||||
return "m" .. tostring(self.grade - 9)
|
||||
elseif self.grade < 26 then
|
||||
return master_grades[self.grade - 20]
|
||||
else
|
||||
return "GM"
|
||||
end
|
||||
end
|
||||
|
||||
function SurvivalCKGame:drawScoringInfo()
|
||||
SurvivalCKGame.super.drawScoringInfo(self)
|
||||
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
|
||||
local text_x = config["side_next"] and 320 or 240
|
||||
|
||||
love.graphics.setFont(font_3x5_2)
|
||||
love.graphics.printf("GRADE", text_x, 120, 40, "left")
|
||||
love.graphics.printf("SCORE", text_x, 200, 40, "left")
|
||||
love.graphics.printf("LEVEL", text_x, 320, 40, "left")
|
||||
|
||||
if (self.coolregret_timer > 0) then
|
||||
love.graphics.printf(self.coolregret_message, 64, 400, 160, "center")
|
||||
self.coolregret_timer = self.coolregret_timer - 1
|
||||
end
|
||||
|
||||
local current_section = math.floor(self.level / 100) + 1
|
||||
self:drawSectionTimesWithSplits(current_section)
|
||||
|
||||
love.graphics.setFont(font_3x5_3)
|
||||
love.graphics.printf(self:getLetterGrade(self.grade), text_x, 140, 90, "left")
|
||||
love.graphics.printf(self.score, text_x, 220, 90, "left")
|
||||
love.graphics.printf(self.level, text_x, 340, 50, "right")
|
||||
if self.clear then
|
||||
love.graphics.printf(self.level, text_x, 370, 50, "right")
|
||||
else
|
||||
love.graphics.printf(math.floor(self.level / 100 + 1) * 100, text_x, 370, 50, "right")
|
||||
end
|
||||
end
|
||||
|
||||
function SurvivalCKGame:getHighscoreData()
|
||||
return {
|
||||
grade = self.grade,
|
||||
level = self.level,
|
||||
frames = self.frames,
|
||||
}
|
||||
end
|
||||
|
||||
function SurvivalCKGame:getSectionEndLevel()
|
||||
return math.floor(self.level / 100 + 1) * 100
|
||||
end
|
||||
|
||||
function SurvivalCKGame:getBackground()
|
||||
return math.min(math.floor(self.level / 100), 19)
|
||||
end
|
||||
|
||||
return SurvivalCKGame
|
@ -1,268 +0,0 @@
|
||||
require 'funcs'
|
||||
|
||||
local GameMode = require 'tetris.modes.gamemode'
|
||||
local Piece = require 'tetris.components.piece'
|
||||
|
||||
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
||||
|
||||
local DemonModeGame = GameMode:extend()
|
||||
|
||||
DemonModeGame.name = "Demon Mode"
|
||||
DemonModeGame.hash = "DemonMode"
|
||||
DemonModeGame.tagline = "Can you handle the ludicrous speed past level 20?"
|
||||
|
||||
function DemonModeGame:new()
|
||||
DemonModeGame.super:new()
|
||||
self.roll_frames = 0
|
||||
self.combo = 1
|
||||
self.randomizer = History6RollsRandomizer()
|
||||
|
||||
self.grade = 0
|
||||
self.section_start_time = 0
|
||||
self.section_times = { [0] = 0 }
|
||||
self.section_tetris_count = 0
|
||||
self.section_tries = 0
|
||||
|
||||
self.enable_hold = true
|
||||
self.lock_drop = true
|
||||
self.next_queue_length = 3
|
||||
if math.random() < 1/6.66 then
|
||||
self.rpc_details = "Suffering"
|
||||
end
|
||||
end
|
||||
|
||||
function DemonModeGame:getARE()
|
||||
if self.level < 500 then return 30
|
||||
elseif self.level < 600 then return 25
|
||||
elseif self.level < 700 then return 15
|
||||
elseif self.level < 800 then return 14
|
||||
elseif self.level < 900 then return 12
|
||||
elseif self.level < 1000 then return 11
|
||||
elseif self.level < 1100 then return 10
|
||||
elseif self.level < 1300 then return 8
|
||||
elseif self.level < 1400 then return 6
|
||||
elseif self.level < 1700 then return 4
|
||||
elseif self.level < 1800 then return 3
|
||||
elseif self.level < 1900 then return 2
|
||||
elseif self.level < 2000 then return 1
|
||||
else return 0 end
|
||||
end
|
||||
|
||||
function DemonModeGame:getLineARE()
|
||||
return self:getARE()
|
||||
end
|
||||
|
||||
function DemonModeGame:getDasLimit()
|
||||
if self.level < 500 then return 15
|
||||
elseif self.level < 1000 then return 10
|
||||
elseif self.level < 1500 then return 5
|
||||
elseif self.level < 1700 then return 4
|
||||
elseif self.level < 1900 then return 3
|
||||
elseif self.level < 2000 then return 2
|
||||
else return 1 end
|
||||
end
|
||||
|
||||
function DemonModeGame:getLineClearDelay()
|
||||
if self.level < 600 then return 15
|
||||
elseif self.level < 800 then return 10
|
||||
elseif self.level < 1000 then return 8
|
||||
elseif self.level < 1500 then return 5
|
||||
elseif self.level < 1700 then return 3
|
||||
elseif self.level < 1900 then return 2
|
||||
elseif self.level < 2000 then return 1
|
||||
else return 0 end
|
||||
end
|
||||
|
||||
function DemonModeGame:getLockDelay()
|
||||
if self.level < 100 then return 30
|
||||
elseif self.level < 200 then return 25
|
||||
elseif self.level < 300 then return 22
|
||||
elseif self.level < 400 then return 20
|
||||
elseif self.level < 1000 then return 15
|
||||
elseif self.level < 1200 then return 10
|
||||
elseif self.level < 1400 then return 9
|
||||
elseif self.level < 1500 then return 8
|
||||
elseif self.level < 1600 then return 7
|
||||
elseif self.level < 1700 then return 6
|
||||
elseif self.level < 1800 then return 5
|
||||
elseif self.level < 1900 then return 4
|
||||
elseif self.level < 2000 then return 3
|
||||
else return 2 end
|
||||
end
|
||||
|
||||
function DemonModeGame:getGravity()
|
||||
return 20
|
||||
end
|
||||
|
||||
local function getSectionForLevel(level)
|
||||
return math.floor(level / 100) + 1
|
||||
end
|
||||
|
||||
local cleared_row_levels = {1, 3, 6, 10}
|
||||
|
||||
function DemonModeGame:advanceOneFrame()
|
||||
if self.clear then
|
||||
self.roll_frames = self.roll_frames + 1
|
||||
if self.roll_frames < 0 then
|
||||
return false
|
||||
elseif self.roll_frames >= 1337 then
|
||||
self.completed = true
|
||||
end
|
||||
elseif self.ready_frames == 0 then
|
||||
self.frames = self.frames + 1
|
||||
end
|
||||
end
|
||||
|
||||
function DemonModeGame:onPieceEnter()
|
||||
if (self.level % 100 ~= 99) and self.frames ~= 0 then
|
||||
self.level = self.level + 1
|
||||
end
|
||||
end
|
||||
|
||||
function DemonModeGame:onLineClear(cleared_row_count)
|
||||
if cleared_row_count == 4 then
|
||||
self.section_tetris_count = self.section_tetris_count + 1
|
||||
end
|
||||
local advanced_levels = cleared_row_levels[cleared_row_count]
|
||||
if not self.clear then
|
||||
self:updateSectionTimes(self.level, self.level + advanced_levels)
|
||||
end
|
||||
end
|
||||
|
||||
function DemonModeGame:updateSectionTimes(old_level, new_level)
|
||||
local section = math.floor(old_level / 100) + 1
|
||||
if math.floor(old_level / 100) < math.floor(new_level / 100) then
|
||||
-- If at least one Tetris in this section hasn't been made,
|
||||
-- deny section passage.
|
||||
if old_level > 500 then
|
||||
if self.section_tetris_count == 0 then
|
||||
self.level = 100 * math.floor(old_level / 100)
|
||||
self.section_tries = self.section_tries + 1
|
||||
else
|
||||
self.level = math.min(new_level, 2500)
|
||||
-- if this is first try (no denials, add a grade)
|
||||
if self.section_tries == 0 then
|
||||
self.grade = self.grade + 1
|
||||
end
|
||||
self.section_tries = 0
|
||||
self.section_tetris_count = 0
|
||||
-- record new section
|
||||
section_time = self.frames - self.section_start_time
|
||||
table.insert(self.section_times, section_time)
|
||||
self.section_start_time = self.frames
|
||||
-- maybe clear
|
||||
if self.level == 2500 and not self.clear then
|
||||
self.clear = true
|
||||
self.grid:clear()
|
||||
self.roll_frames = -150
|
||||
end
|
||||
end
|
||||
elseif old_level < 100 then
|
||||
-- If section time is under cutoff, skip to level 500.
|
||||
if self.frames < frameTime(1,00) then
|
||||
self.level = 500
|
||||
self.grade = 5
|
||||
self.section_tries = 0
|
||||
self.section_tetris_count = 0
|
||||
else
|
||||
self.level = math.min(new_level, 2500)
|
||||
self.skip_failed = true
|
||||
self.grade = self.grade + 1
|
||||
end
|
||||
-- record new section
|
||||
section_time = self.frames - self.section_start_time
|
||||
table.insert(self.section_times, section_time)
|
||||
self.section_start_time = self.frames
|
||||
else
|
||||
self.level = math.min(new_level, 2500)
|
||||
if self.skip_failed and new_level >= 500 then
|
||||
self.level = 500
|
||||
self.game_over = true
|
||||
end
|
||||
self.grade = math.min(self.grade + 1, 4)
|
||||
end
|
||||
else
|
||||
self.level = math.min(new_level, 2500)
|
||||
end
|
||||
end
|
||||
|
||||
function DemonModeGame:updateScore(level, drop_bonus, cleared_lines)
|
||||
if not self.clear then
|
||||
if cleared_lines > 0 then
|
||||
self.combo = self.combo + (cleared_lines - 1) * 2
|
||||
self.score = self.score + (
|
||||
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
||||
cleared_lines * self.combo
|
||||
)
|
||||
else
|
||||
self.combo = 1
|
||||
end
|
||||
self.drop_bonus = 0
|
||||
end
|
||||
end
|
||||
|
||||
local letter_grades = {
|
||||
[0] = "", "D", "C", "B", "A",
|
||||
"S", "S-A", "S-B", "S-C", "S-D",
|
||||
"X", "X-A", "X-B", "X-C", "X-D",
|
||||
"W", "W-A", "W-B", "W-C", "W-D",
|
||||
"Master", "MasterS", "MasterX", "MasterW", "Grand Master",
|
||||
"Demon Master"
|
||||
}
|
||||
|
||||
function DemonModeGame:getLetterGrade()
|
||||
return letter_grades[self.grade]
|
||||
end
|
||||
|
||||
function DemonModeGame:drawGrid()
|
||||
if self.clear and not (self.completed or self.game_over) then
|
||||
self.grid:drawInvisible(self.rollOpacityFunction)
|
||||
else
|
||||
self.grid:draw()
|
||||
end
|
||||
end
|
||||
|
||||
DemonModeGame.rollOpacityFunction = function(age)
|
||||
if age > 4 then return 0
|
||||
else return 1 - age / 4 end
|
||||
end
|
||||
|
||||
function DemonModeGame:drawScoringInfo()
|
||||
DemonModeGame.super.drawScoringInfo(self)
|
||||
|
||||
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")
|
||||
if self.grade ~= 0 then love.graphics.printf("GRADE", 240, 120, 40, "left") end
|
||||
love.graphics.printf("SCORE", 240, 200, 40, "left")
|
||||
love.graphics.printf("LEVEL", 240, 320, 40, "left")
|
||||
|
||||
-- draw section time data
|
||||
local current_section = getSectionForLevel(self.level)
|
||||
self:drawSectionTimesWithSecondary(current_section)
|
||||
|
||||
love.graphics.setFont(font_3x5_3)
|
||||
love.graphics.printf(self.score, 240, 220, 90, "left")
|
||||
love.graphics.printf(self:getLetterGrade(), 240, 140, 90, "left")
|
||||
love.graphics.printf(string.format("%.2f", self.level / 100), 240, 340, 70, "right")
|
||||
end
|
||||
|
||||
function DemonModeGame:getHighscoreData()
|
||||
return {
|
||||
grade = self.grade,
|
||||
level = self.level,
|
||||
frames = self.frames,
|
||||
}
|
||||
end
|
||||
|
||||
function DemonModeGame:getBackground()
|
||||
return math.min(math.floor(self.level / 100), 19)
|
||||
end
|
||||
|
||||
return DemonModeGame
|
@ -1,160 +0,0 @@
|
||||
require 'funcs'
|
||||
|
||||
local GameMode = require 'tetris.modes.gamemode'
|
||||
local Piece = require 'tetris.components.piece'
|
||||
|
||||
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls_35bag'
|
||||
|
||||
local IntervalTrainingGame = GameMode:extend()
|
||||
|
||||
IntervalTrainingGame.name = "Interval Training"
|
||||
IntervalTrainingGame.hash = "IntervalTraining"
|
||||
IntervalTrainingGame.tagline = "Can you clear the time hurdles when the game goes this fast?"
|
||||
|
||||
|
||||
|
||||
|
||||
function IntervalTrainingGame:new()
|
||||
self.level = 0
|
||||
IntervalTrainingGame.super:new()
|
||||
self.roll_frames = 0
|
||||
self.combo = 1
|
||||
self.randomizer = History6RollsRandomizer()
|
||||
|
||||
self.section_start_time = 0
|
||||
self.section_times = { [0] = 0 }
|
||||
self.lock_drop = true
|
||||
self.enable_hold = true
|
||||
self.next_queue_length = 3
|
||||
end
|
||||
|
||||
function IntervalTrainingGame:initialize(ruleset)
|
||||
self.section_time_limit = 1800
|
||||
if ruleset.world then self.section_time_limit = 37 * 60 end
|
||||
self.super.initialize(self, ruleset)
|
||||
end
|
||||
|
||||
function IntervalTrainingGame:getARE()
|
||||
return 6
|
||||
end
|
||||
|
||||
function IntervalTrainingGame:getLineARE()
|
||||
return 6
|
||||
end
|
||||
|
||||
function IntervalTrainingGame:getDasLimit()
|
||||
return 7
|
||||
end
|
||||
|
||||
function IntervalTrainingGame:getLineClearDelay()
|
||||
return 4
|
||||
end
|
||||
|
||||
function IntervalTrainingGame:getLockDelay()
|
||||
return 15
|
||||
end
|
||||
|
||||
function IntervalTrainingGame:getGravity()
|
||||
return 20
|
||||
end
|
||||
|
||||
function IntervalTrainingGame:getSection()
|
||||
return math.floor(level / 100) + 1
|
||||
end
|
||||
|
||||
function IntervalTrainingGame:advanceOneFrame()
|
||||
if self.clear then
|
||||
self.roll_frames = self.roll_frames + 1
|
||||
if self.roll_frames > 2968 then
|
||||
self.completed = true
|
||||
end
|
||||
elseif self.ready_frames == 0 then
|
||||
self.frames = self.frames + 1
|
||||
if self:getSectionTime() >= self.section_time_limit then
|
||||
self.game_over = true
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function IntervalTrainingGame: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 IntervalTrainingGame:onLineClear(cleared_row_count)
|
||||
local cleared_level_bonus = {1, 2, 4, 6}
|
||||
if not self.clear then
|
||||
local new_level = self.level + cleared_level_bonus[cleared_row_count]
|
||||
self:updateSectionTimes(self.level, new_level)
|
||||
self.level = math.min(new_level, 999)
|
||||
if self.level == 999 then
|
||||
self.clear = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function IntervalTrainingGame:getSectionTime()
|
||||
return self.frames - self.section_start_time
|
||||
end
|
||||
|
||||
function IntervalTrainingGame:updateSectionTimes(old_level, new_level)
|
||||
if math.floor(old_level / 100) < math.floor(new_level / 100) then
|
||||
-- record new section
|
||||
table.insert(self.section_times, self:getSectionTime())
|
||||
self.section_start_time = self.frames
|
||||
end
|
||||
end
|
||||
|
||||
function IntervalTrainingGame:drawGrid()
|
||||
self.grid:draw()
|
||||
end
|
||||
|
||||
function IntervalTrainingGame:getHighscoreData()
|
||||
return {
|
||||
level = self.level,
|
||||
frames = self.frames,
|
||||
}
|
||||
end
|
||||
|
||||
function IntervalTrainingGame: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")
|
||||
if not self.clear then love.graphics.printf("TIME LEFT", 240, 250, 80, "left") end
|
||||
love.graphics.printf("LEVEL", 240, 320, 40, "left")
|
||||
|
||||
local current_section = math.floor(self.level / 100) + 1
|
||||
self:drawSectionTimesWithSplits(current_section)
|
||||
|
||||
love.graphics.setFont(font_3x5_3)
|
||||
love.graphics.printf(self.level, 240, 340, 40, "right")
|
||||
|
||||
-- draw time left, flash red if necessary
|
||||
local time_left = self.section_time_limit - math.max(self:getSectionTime(), 0)
|
||||
if not self.game_over and time_left < frameTime(0,10) and time_left % 4 < 2 then
|
||||
love.graphics.setColor(1, 0.3, 0.3, 1)
|
||||
end
|
||||
if not self.clear then love.graphics.printf(formatTime(time_left), 240, 270, 160, "left") end
|
||||
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
love.graphics.printf(self:getSectionEndLevel(), 240, 370, 40, "right")
|
||||
end
|
||||
|
||||
function IntervalTrainingGame:getSectionEndLevel()
|
||||
if self.level >= 900 then return 999
|
||||
else return math.floor(self.level / 100 + 1) * 100 end
|
||||
end
|
||||
|
||||
function IntervalTrainingGame:getBackground()
|
||||
return math.floor(self.level / 100)
|
||||
end
|
||||
|
||||
return IntervalTrainingGame
|
@ -1,191 +0,0 @@
|
||||
require 'funcs'
|
||||
|
||||
local GameMode = require 'tetris.modes.gamemode'
|
||||
local Piece = require 'tetris.components.piece'
|
||||
|
||||
local KonohaRandomizer = require 'tetris.randomizers.bag_konoha'
|
||||
|
||||
local KonohaGame = GameMode:extend()
|
||||
|
||||
KonohaGame.name = "All Clear A4"
|
||||
KonohaGame.hash = "AllClearA4"
|
||||
KonohaGame.tagline = "Get as many bravos as you can under the time limit!"
|
||||
|
||||
function KonohaGame:new()
|
||||
KonohaGame.super:new()
|
||||
|
||||
self.randomizer = KonohaRandomizer()
|
||||
self.bravos = 0
|
||||
self.last_bonus_amount = 0
|
||||
self.last_bonus_display_time = 0
|
||||
self.time_limit = 10800
|
||||
self.big_mode = true
|
||||
|
||||
self.lock_drop = true
|
||||
self.enable_hold = true
|
||||
self.next_queue_length = 3
|
||||
end
|
||||
|
||||
function KonohaGame:getARE()
|
||||
if self.level < 300 then return 30
|
||||
elseif self.level < 400 then return 25
|
||||
elseif self.level < 500 then return 20
|
||||
elseif self.level < 600 then return 17
|
||||
elseif self.level < 800 then return 15
|
||||
elseif self.level < 900 then return 13
|
||||
elseif self.level < 1000 then return 10
|
||||
elseif self.level < 1300 then return 8
|
||||
else return 6 end
|
||||
end
|
||||
|
||||
function KonohaGame:getLineARE()
|
||||
return self:getARE()
|
||||
end
|
||||
|
||||
function KonohaGame:getDasLimit()
|
||||
if self.level < 500 then return 10
|
||||
elseif self.level < 800 then return 9
|
||||
elseif self.level < 1000 then return 8
|
||||
else return 7 end
|
||||
end
|
||||
|
||||
function KonohaGame:getLineClearDelay()
|
||||
if self.level < 200 then return 14
|
||||
elseif self.level < 500 then return 9
|
||||
elseif self.level < 800 then return 8
|
||||
elseif self.level < 1000 then return 7
|
||||
else return 6 end
|
||||
end
|
||||
|
||||
function KonohaGame:getLockDelay()
|
||||
if self.level < 500 then return 30
|
||||
elseif self.level < 600 then return 25
|
||||
elseif self.level < 700 then return 23
|
||||
elseif self.level < 800 then return 20
|
||||
elseif self.level < 900 then return 17
|
||||
elseif self.level < 1000 then return 15
|
||||
elseif self.level < 1200 then return 13
|
||||
elseif self.level < 1300 then return 10
|
||||
else return 8 end
|
||||
end
|
||||
|
||||
function KonohaGame:getGravity()
|
||||
if (self.level < 30) then return 4/256
|
||||
elseif (self.level < 35) then return 8/256
|
||||
elseif (self.level < 40) then return 12/256
|
||||
elseif (self.level < 50) then return 16/256
|
||||
elseif (self.level < 60) then return 32/256
|
||||
elseif (self.level < 70) then return 48/256
|
||||
elseif (self.level < 80) then return 64/256
|
||||
elseif (self.level < 90) then return 128/256
|
||||
elseif (self.level < 100) then return 192/256
|
||||
elseif (self.level < 120) then return 1
|
||||
elseif (self.level < 140) then return 2
|
||||
elseif (self.level < 160) then return 3
|
||||
elseif (self.level < 170) then return 4
|
||||
elseif (self.level < 200) then return 5
|
||||
else return 20 end
|
||||
end
|
||||
|
||||
function KonohaGame:getSection()
|
||||
return math.floor(level / 100) + 1
|
||||
end
|
||||
|
||||
function KonohaGame:getSectionEndLevel()
|
||||
return math.floor(self.level / 100 + 1) * 100
|
||||
end
|
||||
|
||||
function KonohaGame:advanceOneFrame()
|
||||
if self.ready_frames == 0 then
|
||||
self.time_limit = self.time_limit - 1
|
||||
self.frames = self.frames + 1
|
||||
end
|
||||
if self.time_limit <= 0 then
|
||||
self.game_over = true
|
||||
end
|
||||
self.last_bonus_display_time = self.last_bonus_display_time - 1
|
||||
end
|
||||
|
||||
function KonohaGame:onPieceEnter()
|
||||
if (self.level % 100 ~= 99) and self.frames ~= 0 then
|
||||
self.level = self.level + 1
|
||||
end
|
||||
end
|
||||
|
||||
function KonohaGame:drawGrid(ruleset)
|
||||
self.grid:draw()
|
||||
if self.piece ~= nil and self.level < 100 then
|
||||
self:drawGhostPiece(ruleset)
|
||||
end
|
||||
end
|
||||
|
||||
local cleared_row_levels = {2, 4, 6, 12}
|
||||
local bravo_bonus = {300, 480, 660, 900}
|
||||
local non_bravo_bonus = {0, 0, 20, 40}
|
||||
local bravo_ot_bonus = {0, 60, 120, 180}
|
||||
|
||||
function KonohaGame:onLineClear(cleared_row_count)
|
||||
local oldtime = self.time_limit
|
||||
|
||||
self.level = self.level + cleared_row_levels[cleared_row_count / 2]
|
||||
if self.grid:checkForBravo(cleared_row_count) then
|
||||
self.bravos = self.bravos + 1
|
||||
if self.level < 1000 then self.time_limit = self.time_limit + bravo_bonus[cleared_row_count / 2]
|
||||
else self.time_limit = self.time_limit + bravo_ot_bonus[cleared_row_count / 2]
|
||||
end
|
||||
if self.bravos == 11 then self.randomizer.allowrepeat = true end
|
||||
elseif self.level < 1000 then
|
||||
self.time_limit = self.time_limit + non_bravo_bonus[cleared_row_count / 2]
|
||||
end
|
||||
|
||||
local bonus = self.time_limit - oldtime
|
||||
if bonus > 0 then
|
||||
self.last_bonus_amount = bonus
|
||||
self.last_bonus_display_time = 120
|
||||
end
|
||||
end
|
||||
|
||||
function KonohaGame:getBackground()
|
||||
return math.floor(self.level / 100)
|
||||
end
|
||||
|
||||
function KonohaGame: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("TIME LIMIT", 240, 120, 120, "left")
|
||||
love.graphics.printf("BRAVOS", 240, 200, 50, "left")
|
||||
love.graphics.printf("LEVEL", 240, 320, 40, "left")
|
||||
|
||||
love.graphics.setFont(font_3x5_3)
|
||||
if not self.game_over and self.time_limit < frameTime(0,10) and self.time_limit % 4 < 2 then
|
||||
love.graphics.setColor(1, 0.3, 0.3, 1)
|
||||
end
|
||||
love.graphics.printf(formatTime(self.time_limit), 240, 140, 120, "right")
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
if self.last_bonus_display_time > 0 then
|
||||
love.graphics.printf("+"..formatTime(self.last_bonus_amount), 240, 160, 120, "right")
|
||||
end
|
||||
love.graphics.printf(self.bravos, 240, 220, 90, "left")
|
||||
love.graphics.printf(self.level, 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
|
||||
|
||||
function KonohaGame:getHighscoreData()
|
||||
return {
|
||||
bravos = self.bravos,
|
||||
level = self.level,
|
||||
frames = self.frames,
|
||||
}
|
||||
end
|
||||
|
||||
return KonohaGame
|
@ -1,186 +0,0 @@
|
||||
require 'funcs'
|
||||
|
||||
local GameMode = require 'tetris.modes.gamemode'
|
||||
local Piece = require 'tetris.components.piece'
|
||||
|
||||
local Randomizer = require 'tetris.randomizers.randomizer'
|
||||
|
||||
local MarathonC89Game = GameMode:extend()
|
||||
|
||||
MarathonC89Game.name = "Marathon C89"
|
||||
MarathonC89Game.hash = "MarathonC89"
|
||||
MarathonC89Game.tagline = "Can you play fast enough to reach the killscreen?"
|
||||
|
||||
|
||||
function MarathonC89Game:new()
|
||||
MarathonC89Game.super:new()
|
||||
|
||||
self.randomizer = Randomizer()
|
||||
|
||||
self.ready_frames = 1
|
||||
self.waiting_frames = 72
|
||||
|
||||
self.start_level = 12
|
||||
self.level = 12
|
||||
|
||||
self.lock_drop = true
|
||||
self.enable_hard_drop = false
|
||||
self.enable_hold = false
|
||||
self.next_queue_length = 1
|
||||
self.additive_gravity = false
|
||||
end
|
||||
|
||||
function MarathonC89Game:getDropSpeed() return 1/2 end
|
||||
function MarathonC89Game:getDasLimit() return 16 end
|
||||
function MarathonC89Game:getARR() return 6 end
|
||||
|
||||
function MarathonC89Game:getARE() return 6 end
|
||||
function MarathonC89Game:getLineARE() return 6 end
|
||||
function MarathonC89Game:getLineClearDelay() return 30 end
|
||||
function MarathonC89Game:getLockDelay() return 0 end
|
||||
|
||||
function MarathonC89Game: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
|
||||
end
|
||||
|
||||
local gravity_table = {
|
||||
[0] =
|
||||
1366/65536, 1525/65536, 1725/65536, 1986/65536, 2341/65536,
|
||||
2850/65536, 3641/65536, 5042/65536, 8192/65536, 10923/65536,
|
||||
13108/65536, 13108/65536, 13108/65536, 16384/65536, 16384/65536,
|
||||
16384/65536, 21846/65536, 21846/65536, 21846/65536
|
||||
}
|
||||
|
||||
function MarathonC89Game:getGravity()
|
||||
if self.waiting_frames > 0 then return 0 end
|
||||
if self.level >= 29 then return 1
|
||||
elseif self.level >= 19 then return 1/2
|
||||
else return gravity_table[self.level] end
|
||||
end
|
||||
|
||||
function MarathonC89Game:advanceOneFrame()
|
||||
if self.waiting_frames > 0 then
|
||||
self.waiting_frames = self.waiting_frames - 1
|
||||
else
|
||||
self.frames = self.frames + 1
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function MarathonC89Game:onPieceLock()
|
||||
self.super:onPieceLock()
|
||||
self.score = self.score + self.drop_bonus
|
||||
self.drop_bonus = 0
|
||||
end
|
||||
|
||||
local cleared_line_scores = { 40, 100, 300, 1200 }
|
||||
|
||||
function MarathonC89Game:getLevelForLines()
|
||||
if self.start_level < 10 then
|
||||
return math.max(self.start_level, math.floor(self.lines / 10))
|
||||
elseif self.start_level < 16 then
|
||||
return math.max(self.start_level, self.start_level + math.floor((self.lines - 100) / 10))
|
||||
else
|
||||
return math.max(self.start_level, math.floor((self.lines - 60) / 10))
|
||||
end
|
||||
end
|
||||
|
||||
function MarathonC89Game:updateScore(level, drop_bonus, cleared_lines)
|
||||
if cleared_lines > 0 then
|
||||
self.score = self.score + cleared_line_scores[cleared_lines] * (self.level + 1)
|
||||
self.lines = self.lines + cleared_lines
|
||||
self.level = self:getLevelForLines()
|
||||
else
|
||||
self.drop_bonus = 0
|
||||
self.combo = 1
|
||||
end
|
||||
end
|
||||
|
||||
function MarathonC89Game:drawGrid()
|
||||
self.grid:draw()
|
||||
if self.piece ~= nil and self.level < 100 then
|
||||
self:drawGhostPiece(ruleset)
|
||||
end
|
||||
end
|
||||
|
||||
function MarathonC89Game:drawScoringInfo()
|
||||
MarathonC89Game.super.drawScoringInfo(self)
|
||||
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.setFont(font_3x5_3)
|
||||
love.graphics.printf(self.lines, 240, 140, 90, "left")
|
||||
love.graphics.printf(self.score, 240, 220, 90, "left")
|
||||
|
||||
love.graphics.setFont(font_8x11)
|
||||
love.graphics.printf(formatTime(self.frames), 64, 420, 160, "center")
|
||||
end
|
||||
|
||||
|
||||
function MarathonC89Game:getBackground()
|
||||
return math.min(self.level, 19)
|
||||
end
|
||||
|
||||
function MarathonC89Game:getHighscoreData()
|
||||
return {
|
||||
score = self.score,
|
||||
level = self.level,
|
||||
}
|
||||
end
|
||||
|
||||
return MarathonC89Game
|
@ -310,6 +310,8 @@ function PhantomMania2Game:drawScoringInfo()
|
||||
love.graphics.printf("SECRET GRADE", 240, 430, 180, "left")
|
||||
end
|
||||
|
||||
self:drawSectionTimesWithSplits(math.floor(self.level / 100) + 1)
|
||||
|
||||
if(self.coolregret_timer > 0) then
|
||||
love.graphics.printf(self.coolregret_message, 64, 400, 160, "center")
|
||||
self.coolregret_timer = self.coolregret_timer - 1
|
||||
|
@ -1,22 +0,0 @@
|
||||
local PhantomManiaGame = require 'tetris.modes.phantom_mania'
|
||||
|
||||
local PhantomManiaNGame = PhantomManiaGame:extend()
|
||||
|
||||
PhantomManiaNGame.name = "Phantom Mania N"
|
||||
PhantomManiaNGame.hash = "PhantomManiaN"
|
||||
PhantomManiaNGame.tagline = "The old mode from Nullpomino, for Ti-ARS and SRS support."
|
||||
|
||||
function PhantomManiaNGame:new()
|
||||
PhantomManiaNGame.super:new()
|
||||
|
||||
self.SGnames = {
|
||||
"M1", "M2", "M3", "M4", "M5", "M6", "M7", "M8", "M9",
|
||||
"M10", "M11", "M12", "M13", "M14", "M15", "M16", "M17", "M18",
|
||||
"GM"
|
||||
}
|
||||
|
||||
self.next_queue_length = 3
|
||||
self.enable_hold = true
|
||||
end
|
||||
|
||||
return PhantomManiaNGame
|
@ -1,151 +0,0 @@
|
||||
require 'funcs'
|
||||
|
||||
local GameMode = require 'tetris.modes.gamemode'
|
||||
local Piece = require 'tetris.components.piece'
|
||||
|
||||
local Bag7Randomiser = require 'tetris.randomizers.bag7noSZOstart'
|
||||
|
||||
local Race40Game = GameMode:extend()
|
||||
|
||||
Race40Game.name = "Race 40"
|
||||
Race40Game.hash = "Race40"
|
||||
Race40Game.tagline = "How fast can you clear 40 lines?"
|
||||
|
||||
|
||||
function Race40Game:new()
|
||||
Race40Game.super:new()
|
||||
|
||||
self.lines = 0
|
||||
self.line_goal = 40
|
||||
self.pieces = 0
|
||||
self.randomizer = Bag7Randomiser()
|
||||
|
||||
self.roll_frames = 0
|
||||
|
||||
self.SGnames = {
|
||||
[0] = "",
|
||||
"9", "8", "7", "6", "5", "4", "3", "2", "1",
|
||||
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
|
||||
"GM"
|
||||
}
|
||||
self.upstacked = false
|
||||
|
||||
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 = 3
|
||||
end
|
||||
|
||||
function Race40Game:getDropSpeed()
|
||||
return 20
|
||||
end
|
||||
|
||||
function Race40Game:getARR()
|
||||
return 1
|
||||
end
|
||||
|
||||
function Race40Game:getARE()
|
||||
return 0
|
||||
end
|
||||
|
||||
function Race40Game:getLineARE()
|
||||
return self:getARE()
|
||||
end
|
||||
|
||||
function Race40Game:getDasLimit()
|
||||
return 10
|
||||
end
|
||||
|
||||
function Race40Game:getLineClearDelay()
|
||||
return 0
|
||||
end
|
||||
|
||||
function Race40Game:getLockDelay()
|
||||
return 30
|
||||
end
|
||||
|
||||
function Race40Game:getGravity()
|
||||
return 1/64
|
||||
end
|
||||
|
||||
function Race40Game:advanceOneFrame()
|
||||
if self.clear then
|
||||
self.roll_frames = self.roll_frames + 1
|
||||
if self.roll_frames > 150 then
|
||||
self.completed = true
|
||||
end
|
||||
return false
|
||||
elseif self.ready_frames == 0 then
|
||||
self.frames = self.frames + 1
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function Race40Game:onPieceLock()
|
||||
self.super:onPieceLock()
|
||||
self.pieces = self.pieces + 1
|
||||
end
|
||||
|
||||
function Race40Game:onLineClear(cleared_row_count)
|
||||
if not self.clear then
|
||||
self.lines = self.lines + cleared_row_count
|
||||
if self.lines >= self.line_goal then
|
||||
self.clear = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Race40Game:drawGrid(ruleset)
|
||||
self.grid:draw()
|
||||
if self.piece ~= nil then
|
||||
self:drawGhostPiece(ruleset)
|
||||
end
|
||||
end
|
||||
|
||||
function Race40Game:getHighscoreData()
|
||||
return {
|
||||
level = self.level,
|
||||
frames = self.frames,
|
||||
}
|
||||
end
|
||||
|
||||
function Race40Game:getSecretGrade(sg)
|
||||
if sg == 19 then self.upstacked = true end
|
||||
if self.upstacked then return self.SGnames[14 + math.floor((20 - sg) / 4)]
|
||||
else return self.SGnames[math.floor((sg / 19) * 14)] end
|
||||
end
|
||||
|
||||
function Race40Game:drawScoringInfo()
|
||||
Race40Game.super.drawScoringInfo(self)
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
|
||||
local text_x = config["side_next"] and 320 or 240
|
||||
|
||||
love.graphics.setFont(font_3x5_2)
|
||||
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
||||
love.graphics.printf("LINES", text_x, 320, 40, "left")
|
||||
love.graphics.printf("line/min", text_x, 160, 80, "left")
|
||||
love.graphics.printf("piece/sec", text_x, 220, 80, "left")
|
||||
local sg = self.grid:checkSecretGrade()
|
||||
if sg >= 7 or self.upstacked then
|
||||
love.graphics.printf("SECRET GRADE", 240, 430, 180, "left")
|
||||
end
|
||||
|
||||
love.graphics.setFont(font_3x5_3)
|
||||
love.graphics.printf(string.format("%.02f", self.lines / math.max(1, self.frames) * 3600), text_x, 180, 80, "left")
|
||||
love.graphics.printf(string.format("%.04f", self.pieces / math.max(1, self.frames) * 60), text_x, 240, 80, "left")
|
||||
if sg >= 7 or self.upstacked then
|
||||
love.graphics.printf(self:getSecretGrade(sg), 240, 450, 180, "left")
|
||||
end
|
||||
|
||||
love.graphics.setFont(font_3x5_4)
|
||||
love.graphics.printf(math.max(0, self.line_goal - self.lines), text_x, 340, 40, "left")
|
||||
end
|
||||
|
||||
function Race40Game:getBackground()
|
||||
return 2
|
||||
end
|
||||
|
||||
return Race40Game
|
@ -1,189 +0,0 @@
|
||||
require 'funcs'
|
||||
|
||||
local GameMode = require 'tetris.modes.gamemode'
|
||||
local Piece = require 'tetris.components.piece'
|
||||
|
||||
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls_35bag'
|
||||
|
||||
local ScoreDrainGame = GameMode:extend()
|
||||
|
||||
ScoreDrainGame.name = "Score Drain"
|
||||
ScoreDrainGame.hash = "ScoreDrain"
|
||||
ScoreDrainGame.tagline = "Your score goes down over time! Avoid hitting 0 points, or your game is over!"
|
||||
|
||||
function ScoreDrainGame:new()
|
||||
self.super:new()
|
||||
|
||||
self.score = 2500
|
||||
self.drain_rate = 50
|
||||
self.combo = 1
|
||||
self.randomizer = History6RollsRandomizer()
|
||||
|
||||
self.lock_drop = true
|
||||
self.lock_hard_drop = true
|
||||
self.enable_hold = true
|
||||
self.next_queue_length = 3
|
||||
end
|
||||
|
||||
function ScoreDrainGame:getARE()
|
||||
if self.level < 700 then return 27
|
||||
elseif self.level < 800 then return 18
|
||||
elseif self.level < 1000 then return 14
|
||||
elseif self.level < 1100 then return 8
|
||||
elseif self.level < 1200 then return 7
|
||||
else return 6 end
|
||||
end
|
||||
|
||||
function ScoreDrainGame:getLineARE()
|
||||
if self.level < 600 then return 27
|
||||
elseif self.level < 700 then return 18
|
||||
elseif self.level < 800 then return 14
|
||||
elseif self.level < 1100 then return 8
|
||||
elseif self.level < 1200 then return 7
|
||||
else return 6 end
|
||||
end
|
||||
|
||||
function ScoreDrainGame:getDasLimit()
|
||||
if self.level < 500 then return 15
|
||||
elseif self.level < 900 then return 9
|
||||
else return 7 end
|
||||
end
|
||||
|
||||
function ScoreDrainGame: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
|
||||
elseif self.level < 1100 then return 6
|
||||
elseif self.level < 1200 then return 5
|
||||
else return 4 end
|
||||
end
|
||||
|
||||
function ScoreDrainGame:getLockDelay()
|
||||
if self.level < 900 then return 30
|
||||
elseif self.level < 1100 then return 17
|
||||
else return 15 end
|
||||
end
|
||||
|
||||
function ScoreDrainGame: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 ScoreDrainGame:advanceOneFrame()
|
||||
if self.ready_frames == 0 then
|
||||
self.frames = self.frames + 1
|
||||
self.score = math.max(0, self.score - self.drain_rate / 60)
|
||||
self.game_over = self.score <= 0 and true or false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function ScoreDrainGame:onPieceEnter()
|
||||
if (self.level % 100 ~= 99) and self.frames ~= 0 then
|
||||
self.level = self.level + 1
|
||||
end
|
||||
end
|
||||
|
||||
local cleared_row_levels = {1, 2, 4, 6}
|
||||
|
||||
function ScoreDrainGame:onLineClear(cleared_row_count)
|
||||
local new_level = self.level + cleared_row_levels[cleared_row_count]
|
||||
self.drain_rate = math.floor(self.level / 100) < math.floor(new_level / 100) and self.drain_rate * 1.5 or self.drain_rate
|
||||
self.level = new_level
|
||||
end
|
||||
|
||||
function ScoreDrainGame:updateScore(level, drop_bonus, cleared_lines)
|
||||
if cleared_lines > 0 then
|
||||
self.combo = self.combo + (cleared_lines - 1) * 2
|
||||
self.score = self.score + (
|
||||
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
||||
cleared_lines * self.combo
|
||||
)
|
||||
else
|
||||
self.combo = 1
|
||||
end
|
||||
self.drop_bonus = 0
|
||||
end
|
||||
|
||||
function ScoreDrainGame:drawGrid()
|
||||
self.grid:draw()
|
||||
if self.piece ~= nil and self.level < 100 then
|
||||
self:drawGhostPiece(ruleset)
|
||||
end
|
||||
end
|
||||
|
||||
function ScoreDrainGame: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("DRAIN RATE", 240, 90, 80, "left")
|
||||
love.graphics.printf("SCORE", 240, 170, 40, "left")
|
||||
love.graphics.printf("TIME LEFT", 240, 250, 80, "left")
|
||||
love.graphics.printf("LEVEL", 240, 320, 40, "left")
|
||||
|
||||
love.graphics.setFont(font_3x5_3)
|
||||
love.graphics.printf(math.floor(self.drain_rate).."/s", 240, 110, 120, "left")
|
||||
local frames_left = self.score / self.drain_rate * 60
|
||||
if frames_left <= 600 and frames_left % 4 < 2 and not self.game_over then love.graphics.setColor(1, 0.3, 0.3, 1) end
|
||||
love.graphics.printf(formatTime(frames_left), 240, 270, 120, "left")
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
love.graphics.printf(math.floor(self.score), 240, 190, 90, "left")
|
||||
love.graphics.printf(self.level, 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
|
||||
|
||||
function ScoreDrainGame:getHighscoreData()
|
||||
return {
|
||||
level = self.level,
|
||||
frames = self.frames,
|
||||
}
|
||||
end
|
||||
|
||||
function ScoreDrainGame:getSectionEndLevel()
|
||||
return math.floor(self.level / 100 + 1) * 100
|
||||
end
|
||||
|
||||
function ScoreDrainGame:getBackground()
|
||||
return math.floor(self.level / 100)
|
||||
end
|
||||
|
||||
return ScoreDrainGame
|
@ -1,212 +0,0 @@
|
||||
require 'funcs'
|
||||
|
||||
local GameMode = require 'tetris.modes.gamemode'
|
||||
local Piece = require 'tetris.components.piece'
|
||||
|
||||
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
||||
|
||||
local TGMPlusGame = GameMode:extend()
|
||||
|
||||
TGMPlusGame.name = "Marathon A2+"
|
||||
TGMPlusGame.hash = "A2Plus"
|
||||
TGMPlusGame.tagline = "The garbage rises steadily! Can you make it to level 999?"
|
||||
|
||||
function TGMPlusGame:new()
|
||||
TGMPlusGame.super:new()
|
||||
|
||||
self.roll_frames = 0
|
||||
self.combo = 1
|
||||
|
||||
self.SGnames = {
|
||||
"9", "8", "7", "6", "5", "4", "3", "2", "1",
|
||||
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
|
||||
"GM"
|
||||
}
|
||||
|
||||
self.randomizer = History6RollsRandomizer()
|
||||
|
||||
self.lock_drop = false
|
||||
self.enable_hold = false
|
||||
self.next_queue_length = 1
|
||||
|
||||
self.garbage_queue = 0
|
||||
self.garbage_pos = 0
|
||||
self.garbage_rows = {
|
||||
[0] =
|
||||
{"e", "b", "b", "b", "b", "b", "b", "b", "b", "b"},
|
||||
{"e", "b", "b", "b", "b", "b", "b", "b", "b", "b"},
|
||||
{"e", "b", "b", "b", "b", "b", "b", "b", "b", "b"},
|
||||
{"e", "b", "b", "b", "b", "b", "b", "b", "b", "b"},
|
||||
{"b", "b", "b", "b", "b", "b", "b", "b", "b", "e"},
|
||||
{"b", "b", "b", "b", "b", "b", "b", "b", "b", "e"},
|
||||
{"b", "b", "b", "b", "b", "b", "b", "b", "b", "e"},
|
||||
{"b", "b", "b", "b", "b", "b", "b", "b", "b", "e"},
|
||||
{"e", "e", "b", "b", "b", "b", "b", "b", "b", "b"},
|
||||
{"e", "b", "b", "b", "b", "b", "b", "b", "b", "b"},
|
||||
{"e", "b", "b", "b", "b", "b", "b", "b", "b", "b"},
|
||||
{"b", "b", "b", "b", "b", "b", "b", "b", "e", "e"},
|
||||
{"b", "b", "b", "b", "b", "b", "b", "b", "b", "e"},
|
||||
{"b", "b", "b", "b", "b", "b", "b", "b", "b", "e"},
|
||||
{"b", "b", "e", "b", "b", "b", "b", "b", "b", "b"},
|
||||
{"b", "e", "e", "b", "b", "b", "b", "b", "b", "b"},
|
||||
{"b", "e", "b", "b", "b", "b", "b", "b", "b", "b"},
|
||||
{"b", "b", "b", "b", "b", "b", "b", "e", "b", "b"},
|
||||
{"b", "b", "b", "b", "b", "b", "b", "e", "e", "b"},
|
||||
{"b", "b", "b", "b", "b", "b", "b", "b", "e", "b"},
|
||||
{"b", "b", "b", "b", "e", "e", "b", "b", "b", "b"},
|
||||
{"b", "b", "b", "b", "e", "e", "b", "b", "b", "b"},
|
||||
{"b", "b", "b", "b", "e", "b", "b", "b", "b", "b"},
|
||||
{"b", "b", "b", "e", "e", "e", "b", "b", "b", "b"},
|
||||
}
|
||||
end
|
||||
|
||||
function TGMPlusGame:getARE() return 25 end
|
||||
function TGMPlusGame:getDasLimit() return 15 end
|
||||
function TGMPlusGame:getLockDelay() return 30 end
|
||||
function TGMPlusGame:getLineClearDelay() return 40 end
|
||||
|
||||
function TGMPlusGame: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 TGMPlusGame:getGarbageLimit() return 13 - math.floor(self.level / 100) end
|
||||
|
||||
function TGMPlusGame:advanceOneFrame()
|
||||
if self.clear then
|
||||
self.roll_frames = self.roll_frames + 1
|
||||
if self.roll_frames > 3694 then
|
||||
self.completed = true
|
||||
end
|
||||
elseif self.ready_frames == 0 then
|
||||
self.frames = self.frames + 1
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function TGMPlusGame: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 TGMPlusGame:onPieceLock(piece, cleared_row_count)
|
||||
self.super:onPieceLock()
|
||||
if cleared_row_count == 0 then self:advanceBottomRow() end
|
||||
end
|
||||
|
||||
function TGMPlusGame:onLineClear(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 end
|
||||
if self.level >= 900 then self.lock_drop = true end
|
||||
end
|
||||
|
||||
function TGMPlusGame:advanceBottomRow()
|
||||
self.garbage_queue = self.garbage_queue + 1
|
||||
if self.garbage_queue >= self:getGarbageLimit() then
|
||||
self.grid:garbageRise(self.garbage_rows[self.garbage_pos])
|
||||
self.garbage_queue = 0
|
||||
self.garbage_pos = (self.garbage_pos + 1) % 24
|
||||
end
|
||||
end
|
||||
|
||||
function TGMPlusGame:updateScore(level, drop_bonus, cleared_lines)
|
||||
if not self.clear then
|
||||
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
|
||||
self.score = self.score + (
|
||||
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
||||
cleared_lines * self.combo * self.bravo
|
||||
)
|
||||
else
|
||||
self.combo = 1
|
||||
end
|
||||
self.drop_bonus = 0
|
||||
end
|
||||
end
|
||||
|
||||
function TGMPlusGame:drawGrid(ruleset)
|
||||
self.grid:draw()
|
||||
if self.piece ~= nil and self.level < 100 then
|
||||
self:drawGhostPiece(ruleset)
|
||||
end
|
||||
end
|
||||
|
||||
function TGMPlusGame:getHighscoreData()
|
||||
return {
|
||||
score = self.score,
|
||||
level = self.level,
|
||||
frames = self.frames,
|
||||
}
|
||||
end
|
||||
|
||||
function TGMPlusGame:getSectionEndLevel()
|
||||
if self.level >= 900 then return 999
|
||||
else return math.floor(self.level / 100 + 1) * 100 end
|
||||
end
|
||||
|
||||
function TGMPlusGame:getBackground()
|
||||
return math.floor(self.level / 100)
|
||||
end
|
||||
|
||||
function TGMPlusGame: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("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)
|
||||
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
|
||||
|
||||
|
||||
return TGMPlusGame
|
@ -1,167 +0,0 @@
|
||||
require 'funcs'
|
||||
|
||||
local GameMode = require 'tetris.modes.gamemode'
|
||||
local Piece = require 'tetris.components.piece'
|
||||
|
||||
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
||||
|
||||
local PacerTest = GameMode:extend()
|
||||
|
||||
PacerTest.name = "TetrisGram™ Pacer Test"
|
||||
PacerTest.hash = "PacerTest"
|
||||
PacerTest.tagline = ""
|
||||
|
||||
|
||||
|
||||
|
||||
local function getLevelFrames(level)
|
||||
if level == 1 then return 72 * 60 / 8.0
|
||||
else return 72 * 60 / (8 + level * 0.5)
|
||||
end
|
||||
end
|
||||
|
||||
local level_end_sections = {
|
||||
7, 15, 23, 32, 41, 51, 61, 72, 83, 94,
|
||||
106, 118, 131, 144, 157, 171, 185, 200,
|
||||
215, 231, 247
|
||||
}
|
||||
|
||||
function PacerTest:new()
|
||||
PacerTest.super:new()
|
||||
|
||||
self.ready_frames = 2430
|
||||
self.clear_frames = 0
|
||||
self.randomizer = History6RollsRandomizer()
|
||||
|
||||
self.level = 1
|
||||
self.section = 0
|
||||
self.level_frames = 0
|
||||
|
||||
self.section_lines = 0
|
||||
self.section_clear = false
|
||||
self.strikes = 0
|
||||
|
||||
self.lock_drop = true
|
||||
self.lock_hard_drop = true
|
||||
self.enable_hold = true
|
||||
self.instant_hard_drop = true
|
||||
self.instant_soft_drop = false
|
||||
self.next_queue_length = 3
|
||||
end
|
||||
|
||||
function PacerTest:initialize(ruleset)
|
||||
self.level_frames = getLevelFrames(1)
|
||||
switchBGM("pacer_test")
|
||||
end
|
||||
|
||||
function PacerTest:getARE()
|
||||
return 0
|
||||
end
|
||||
|
||||
function PacerTest:getLineARE()
|
||||
return 0
|
||||
end
|
||||
|
||||
function PacerTest:getDasLimit()
|
||||
return 8
|
||||
end
|
||||
|
||||
function PacerTest:getLineClearDelay()
|
||||
return 6
|
||||
end
|
||||
|
||||
function PacerTest:getLockDelay()
|
||||
return 30
|
||||
end
|
||||
|
||||
function PacerTest:getGravity()
|
||||
return 1/64
|
||||
end
|
||||
|
||||
function PacerTest:getSection()
|
||||
return math.floor(level / 100) + 1
|
||||
end
|
||||
|
||||
function PacerTest:advanceOneFrame()
|
||||
if self.clear then
|
||||
self.clear_frames = self.clear_frames + 1
|
||||
if self.clear_frames > 600 then
|
||||
self.completed = true
|
||||
end
|
||||
return false
|
||||
elseif self.ready_frames == 0 then
|
||||
self.frames = self.frames + 1
|
||||
self.level_frames = self.level_frames - 1
|
||||
if self.level_frames <= 0 then
|
||||
self:checkSectionStatus()
|
||||
self.section = self.section + 1
|
||||
if self.section >= level_end_sections[self.level] then
|
||||
self.level = self.level + 1
|
||||
end
|
||||
self.level_frames = self.level_frames + getLevelFrames(self.level)
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function PacerTest:checkSectionStatus()
|
||||
if self.section_clear then
|
||||
self.strikes = 0
|
||||
self.section_clear = false
|
||||
else
|
||||
self.strikes = self.strikes + 1
|
||||
if self.strikes >= 2 then
|
||||
self.game_over = true
|
||||
fadeoutBGM(2.5)
|
||||
end
|
||||
end
|
||||
self.section_lines = 0
|
||||
end
|
||||
|
||||
function PacerTest:onLineClear(cleared_row_count)
|
||||
self.section_lines = self.section_lines + cleared_row_count
|
||||
if self.section_lines >= 3 then
|
||||
self.section_clear = true
|
||||
end
|
||||
end
|
||||
|
||||
function PacerTest:drawGrid(ruleset)
|
||||
self.grid:draw()
|
||||
if self.piece ~= nil then
|
||||
self:drawGhostPiece(ruleset)
|
||||
end
|
||||
end
|
||||
|
||||
function PacerTest:getHighscoreData()
|
||||
return {
|
||||
level = self.level,
|
||||
frames = self.frames,
|
||||
}
|
||||
end
|
||||
|
||||
function PacerTest:drawScoringInfo()
|
||||
PacerTest.super.drawScoringInfo(self)
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
|
||||
local text_x = config["side_next"] and 320 or 240
|
||||
|
||||
love.graphics.setFont(font_3x5_2)
|
||||
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
||||
love.graphics.printf("LINES", text_x, 224, 70, "left")
|
||||
love.graphics.printf("LEVEL", text_x, 320, 40, "left")
|
||||
|
||||
for i = 1, math.min(self.strikes, 3) do
|
||||
love.graphics.draw(misc_graphics["strike"], text_x + (i - 1) * 30, 280)
|
||||
end
|
||||
|
||||
love.graphics.setFont(font_3x5_3)
|
||||
love.graphics.printf(self.section_lines .. "/3", text_x, 244, 40, "left")
|
||||
love.graphics.printf(self.level, text_x, 340, 40, "right")
|
||||
love.graphics.printf(self.section, text_x, 370, 40, "right")
|
||||
end
|
||||
|
||||
function PacerTest:getBackground()
|
||||
return math.min(self.level - 1, 19)
|
||||
end
|
||||
|
||||
return PacerTest
|
@ -1,17 +0,0 @@
|
||||
local Randomizer = require 'tetris.randomizers.randomizer'
|
||||
|
||||
local Bag5Randomizer = Randomizer:extend()
|
||||
|
||||
function Bag5Randomizer:initialize()
|
||||
self.bag = {"I", "J", "L", "O", "T"}
|
||||
end
|
||||
|
||||
function Bag5Randomizer:generatePiece()
|
||||
if next(self.bag) == nil then
|
||||
self.bag = {"I", "J", "L", "O", "T"}
|
||||
end
|
||||
local x = math.random(table.getn(self.bag))
|
||||
return table.remove(self.bag, x)
|
||||
end
|
||||
|
||||
return Bag5Randomizer
|
@ -1,24 +0,0 @@
|
||||
local Randomizer = require 'tetris.randomizers.randomizer'
|
||||
|
||||
local Bag5AltRandomizer = Randomizer:extend()
|
||||
|
||||
function Bag5AltRandomizer:initialize()
|
||||
self.bag = {"I", "J", "L", "O", "T"}
|
||||
self.prev = nil
|
||||
end
|
||||
|
||||
function Bag5AltRandomizer:generatePiece()
|
||||
if next(self.bag) == nil then
|
||||
self.bag = {"I", "J", "L", "O", "T"}
|
||||
end
|
||||
local x = math.random(table.getn(self.bag))
|
||||
local temp = table.remove(self.bag, x)
|
||||
if temp == self.prev then
|
||||
local y = math.random(table.getn(self.bag))
|
||||
temp = table.remove(self.bag, y)
|
||||
end
|
||||
self.prev = temp
|
||||
return temp
|
||||
end
|
||||
|
||||
return Bag5AltRandomizer
|
@ -1,24 +0,0 @@
|
||||
local Randomizer = require 'tetris.randomizers.randomizer'
|
||||
|
||||
local Bag7Randomizer = Randomizer:extend()
|
||||
|
||||
function Bag7Randomizer:initialize()
|
||||
self.bag = {"I", "J", "L", "O", "S", "T", "Z"}
|
||||
self.extra = {"I", "J", "L", "O", "S", "T", "Z"}
|
||||
table.insert(self.bag, table.remove(self.extra, math.random(table.getn(self.extra))))
|
||||
end
|
||||
|
||||
function Bag7Randomizer:generatePiece()
|
||||
if next(self.extra) == nil then
|
||||
self.extra = {"I", "J", "L", "O", "S", "T", "Z"}
|
||||
end
|
||||
if next(self.bag) == nil then
|
||||
self.bag = {"I", "J", "L", "O", "S", "T", "Z"}
|
||||
table.insert(self.bag, table.remove(self.extra, math.random(table.getn(self.extra))))
|
||||
end
|
||||
local x = math.random(table.getn(self.bag))
|
||||
--print("Bag: "..table.concat(self.bag, ", ").." | Extra: "..table.concat(self.extra, ", "))
|
||||
return table.remove(self.bag, x)
|
||||
end
|
||||
|
||||
return Bag7Randomizer
|
@ -1,28 +0,0 @@
|
||||
local Randomizer = require 'tetris.randomizers.randomizer'
|
||||
|
||||
local BagKonoha = Randomizer:extend()
|
||||
|
||||
function BagKonoha:initialize()
|
||||
self.bag = {"I", "J", "L", "O", "T"}
|
||||
self.prev = nil
|
||||
self.allowrepeat = false
|
||||
self.generated = 0
|
||||
end
|
||||
|
||||
function BagKonoha:generatePiece()
|
||||
self.generated = self.generated + 1
|
||||
if #self.bag == 0 then
|
||||
self.bag = {"I", "J", "L", "O", "T"}
|
||||
end
|
||||
local x = math.random(#self.bag)
|
||||
local temp = table.remove(self.bag, x)
|
||||
if temp == self.prev and not self.allowrepeat then
|
||||
local y = math.random(#self.bag)
|
||||
table.insert(self.bag, temp) -- should insert at the end of the bag, bag[y] doesnt change
|
||||
temp = table.remove(self.bag, y)
|
||||
end
|
||||
self.prev = temp
|
||||
return temp
|
||||
end
|
||||
|
||||
return BagKonoha
|
@ -1,30 +0,0 @@
|
||||
local Randomizer = require 'tetris.randomizers.randomizer'
|
||||
|
||||
local RecursiveRandomizer = Randomizer:extend()
|
||||
|
||||
function RecursiveRandomizer:initialize()
|
||||
self.bag = {"I", "J", "L", "O", "S", "T", "Z"}
|
||||
end
|
||||
|
||||
function RecursiveRandomizer:generatePiece()
|
||||
--if next(self.bag) == nil then
|
||||
-- self.bag = {"I", "J", "L", "O", "S", "T", "Z"}
|
||||
--end
|
||||
local x = math.random(table.getn(self.bag) + 1)
|
||||
while x == table.getn(self.bag) + 1 do
|
||||
--print("Refill piece pulled")
|
||||
table.insert(self.bag, "I")
|
||||
table.insert(self.bag, "J")
|
||||
table.insert(self.bag, "L")
|
||||
table.insert(self.bag, "O")
|
||||
table.insert(self.bag, "S")
|
||||
table.insert(self.bag, "T")
|
||||
table.insert(self.bag, "Z")
|
||||
x = math.random(table.getn(self.bag) + 1)
|
||||
end
|
||||
--print("Number of pieces in bag: "..table.getn(self.bag))
|
||||
--print("Bag: "..table.concat(self.bag, ", "))
|
||||
return table.remove(self.bag, x)
|
||||
end
|
||||
|
||||
return RecursiveRandomizer
|
@ -1,19 +0,0 @@
|
||||
local Randomizer = require 'tetris.randomizers.randomizer'
|
||||
|
||||
local SegaRandomizer = Randomizer:extend()
|
||||
|
||||
function SegaRandomizer:initialize()
|
||||
self.bag = {"I", "J", "L", "O", "S", "T", "Z"}
|
||||
self.sequence = {}
|
||||
for i = 1, 1000 do
|
||||
self.sequence[i] = self.bag[math.random(table.getn(self.bag))]
|
||||
end
|
||||
self.counter = 0
|
||||
end
|
||||
|
||||
function SegaRandomizer:generatePiece()
|
||||
self.counter = self.counter + 1
|
||||
return self.sequence[self.counter % 1000 + 1]
|
||||
end
|
||||
|
||||
return SegaRandomizer
|
@ -1,173 +0,0 @@
|
||||
local Piece = require 'tetris.components.piece'
|
||||
local Ruleset = require 'tetris.rulesets.ruleset'
|
||||
|
||||
local CRAP = Ruleset:extend()
|
||||
|
||||
CRAP.name = "C.R.A.P."
|
||||
CRAP.hash = "Completely Random Auto-Positioner"
|
||||
CRAP.world = true
|
||||
CRAP.colors={"C","O","M","R","G","Y","B"}
|
||||
CRAP.colourscheme = {
|
||||
I = CRAP.colors[math.ceil(math.random(7))],
|
||||
L = CRAP.colors[math.ceil(math.random(7))],
|
||||
J = CRAP.colors[math.ceil(math.random(7))],
|
||||
S = CRAP.colors[math.ceil(math.random(7))],
|
||||
Z = CRAP.colors[math.ceil(math.random(7))],
|
||||
O = CRAP.colors[math.ceil(math.random(7))],
|
||||
T = CRAP.colors[math.ceil(math.random(7))],
|
||||
}
|
||||
CRAP.softdrop_lock = true
|
||||
CRAP.harddrop_lock = false
|
||||
|
||||
CRAP.enable_IRS_wallkicks = true
|
||||
|
||||
CRAP.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 },
|
||||
}
|
||||
|
||||
CRAP.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 },
|
||||
}
|
||||
|
||||
CRAP.block_offsets = {
|
||||
I={
|
||||
{ {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=1}, {x=-1, y=1}, {x=-2, y=1}, {x=1, y=1} },
|
||||
{ {x=-1, y=0}, {x=-1, y=-1}, {x=-1, y=1}, {x=-1, y=2} },
|
||||
},
|
||||
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=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=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=-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} },
|
||||
}
|
||||
}
|
||||
|
||||
-- Component functions.
|
||||
|
||||
function CRAP: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 CRAP:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||
|
||||
for i=1,20 do
|
||||
dx=math.floor(math.random(11))-5
|
||||
dy=math.floor(math.random(11))-5
|
||||
if grid:canPlacePiece(new_piece:withOffset({x=dx, y=dy})) then
|
||||
piece:setRelativeRotation(rot_dir):setOffset({x=dx, y=dy})
|
||||
self:onPieceRotate(piece, grid)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function CRAP:onPieceCreate(piece, grid)
|
||||
CRAP:randomizeColours()
|
||||
piece.manipulations = 0
|
||||
piece.rotations = 0
|
||||
end
|
||||
|
||||
function CRAP:onPieceDrop(piece, grid)
|
||||
CRAP:randomizeColours()
|
||||
piece.lock_delay = 0 -- step reset
|
||||
end
|
||||
|
||||
function CRAP:onPieceMove(piece, grid)
|
||||
CRAP:randomizeColours()
|
||||
piece.lock_delay = 0 -- move reset
|
||||
if piece:isDropBlocked(grid) then
|
||||
piece.manipulations = piece.manipulations + 1
|
||||
if piece.manipulations >= 10 then
|
||||
piece.locked = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function CRAP:onPieceRotate(piece, grid)
|
||||
CRAP:randomizeColours()
|
||||
piece.lock_delay = 0 -- rotate reset
|
||||
if piece:isDropBlocked(grid) then
|
||||
piece.rotations = piece.rotations + 1
|
||||
if piece.rotations >= 8 then
|
||||
piece.locked = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function CRAP:get180RotationValue() return 2 end
|
||||
|
||||
function CRAP:randomizeColours()
|
||||
CRAP.colourscheme = {
|
||||
I = CRAP.colors[math.ceil(math.random(7))],
|
||||
L = CRAP.colors[math.ceil(math.random(7))],
|
||||
J = CRAP.colors[math.ceil(math.random(7))],
|
||||
S = CRAP.colors[math.ceil(math.random(7))],
|
||||
Z = CRAP.colors[math.ceil(math.random(7))],
|
||||
O = CRAP.colors[math.ceil(math.random(7))],
|
||||
T = CRAP.colors[math.ceil(math.random(7))],
|
||||
}
|
||||
end
|
||||
|
||||
return CRAP
|
@ -1,153 +0,0 @@
|
||||
local Piece = require 'tetris.components.piece'
|
||||
local Ruleset = require 'tetris.rulesets.ruleset'
|
||||
|
||||
local DTET = Ruleset:extend()
|
||||
|
||||
DTET.name = "D.R.S."
|
||||
DTET.hash = "DTET"
|
||||
|
||||
DTET.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 },
|
||||
}
|
||||
|
||||
DTET.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 },
|
||||
}
|
||||
|
||||
DTET.block_offsets = {
|
||||
I={
|
||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} },
|
||||
{ {x=-1, y=-1}, {x=-1, y=-2}, {x=-1, y=0}, {x=-1, 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=-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} },
|
||||
{ {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} },
|
||||
},
|
||||
L={
|
||||
{ {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} },
|
||||
{ {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} },
|
||||
},
|
||||
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=0}, {x=0, y=0}, {x=0, y=-1}, {x=1, y=-1} },
|
||||
{ {x=1, y=0}, {x=1, y=-1}, {x=0, y=-1}, {x=0, y=-2} },
|
||||
},
|
||||
T={
|
||||
{ {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} },
|
||||
{ {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} },
|
||||
},
|
||||
Z={
|
||||
{ {x=1, y=0}, {x=0, y=0}, {x=0, y=-1}, {x=-1, y=-1} },
|
||||
{ {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1}, {x=0, y=-2} },
|
||||
{ {x=1, y=0}, {x=0, y=0}, {x=0, y=-1}, {x=-1, y=-1} },
|
||||
{ {x=1, y=-2}, {x=1, y=-1}, {x=0, y=-1}, {x=0, y=0} },
|
||||
}
|
||||
}
|
||||
|
||||
-- clockwise kicks: {{x=1, y=0}, {x=-1, y=0}, {x=0, y=1}, {x=1, y=1}, {x=-1, y=1}},
|
||||
-- counterclockwise kicks: {{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
||||
|
||||
DTET.wallkicks_3x3 = {
|
||||
[0]={
|
||||
[1]={{x=1, y=0}, {x=-1, y=0}, {x=0, y=1}, {x=1, y=1}, {x=-1, y=1}},
|
||||
[2]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
||||
[3]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
||||
},
|
||||
[1]={
|
||||
[0]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
||||
[2]={{x=1, y=0}, {x=-1, y=0}, {x=0, y=1}, {x=1, y=1}, {x=-1, y=1}},
|
||||
[3]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
||||
},
|
||||
[2]={
|
||||
[0]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
||||
[1]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
||||
[3]={{x=1, y=0}, {x=-1, y=0}, {x=0, y=1}, {x=1, y=1}, {x=-1, y=1}},
|
||||
},
|
||||
[3]={
|
||||
[0]={{x=1, y=0}, {x=-1, y=0}, {x=0, y=1}, {x=1, y=1}, {x=-1, y=1}},
|
||||
[1]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
||||
[2]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
||||
},
|
||||
};
|
||||
|
||||
DTET.wallkicks_line = {
|
||||
[0]={
|
||||
[1]={{x=1, y=0}, {x=-1, y=0}, {x=0, y=1}, {x=1, y=1}, {x=-1, y=1}},
|
||||
[2]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
||||
[3]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
||||
},
|
||||
[1]={
|
||||
[0]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
||||
[2]={{x=1, y=0}, {x=-1, y=0}, {x=0, y=1}, {x=1, y=1}, {x=-1, y=1}},
|
||||
[3]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
||||
},
|
||||
[2]={
|
||||
[0]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
||||
[1]={{x=1, y=0}, {x=-1, y=0}, {x=0, y=1}, {x=1, y=1}, {x=-1, y=1}},
|
||||
[3]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
||||
},
|
||||
[3]={
|
||||
[0]={{x=1, y=0}, {x=-1, y=0}, {x=0, y=1}, {x=1, y=1}, {x=-1, y=1}},
|
||||
[1]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
||||
[2]={{x=-1, y=0}, {x=1, y=0}, {x=0, y=1}, {x=-1, y=1}, {x=1, y=1}},
|
||||
},
|
||||
};
|
||||
|
||||
function DTET:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||
|
||||
local kicks
|
||||
if piece.shape == "O" then
|
||||
return
|
||||
elseif piece.shape == "I" then
|
||||
kicks = DTET.wallkicks_line[piece.rotation][new_piece.rotation]
|
||||
else
|
||||
kicks = DTET.wallkicks_3x3[piece.rotation][new_piece.rotation]
|
||||
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)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function DTET:onPieceDrop(piece, grid)
|
||||
piece.lock_delay = 0 -- step reset
|
||||
end
|
||||
|
||||
function DTET:getDefaultOrientation() return 1 end
|
||||
|
||||
return DTET
|
@ -1,45 +0,0 @@
|
||||
local Piece = require 'tetris.components.piece'
|
||||
local ARS = require 'tetris.rulesets.arika'
|
||||
|
||||
local EHeart = ARS:extend()
|
||||
|
||||
EHeart.name = "E-Heart ARS"
|
||||
EHeart.hash = "EHeartARS"
|
||||
|
||||
function EHeart:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||
|
||||
-- I and O don't kick
|
||||
if (piece.shape == "I" or piece.shape == "O") then return end
|
||||
|
||||
-- center column rule (kicks)
|
||||
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
|
||||
-- individual checks for all 9 cells, in the given order
|
||||
if offset.y < 0 then
|
||||
if offset.x < 0 then self:lateralKick(1, piece, new_piece, rot_dir, grid)
|
||||
elseif offset.x == 0 then return
|
||||
elseif offset.x > 0 then self:lateralKick(-1, piece, new_piece, rot_dir, grid) end
|
||||
elseif offset.y == 0 then
|
||||
if offset.x < 0 then self:lateralKick(1, piece, new_piece, rot_dir, grid)
|
||||
elseif offset.x == 0 then return
|
||||
elseif offset.x > 0 then self:lateralKick(-1, piece, new_piece, rot_dir, grid) end
|
||||
elseif offset.y > 0 then
|
||||
if offset.x < 0 then self:lateralKick(1, piece, new_piece, rot_dir, grid)
|
||||
elseif offset.x == 0 then return
|
||||
elseif offset.x > 0 then self:lateralKick(-1, piece, new_piece, rot_dir, grid) end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function EHeart:lateralKick(dx, piece, new_piece, rot_dir, grid)
|
||||
if (grid:canPlacePiece(new_piece:withOffset({x=dx, y=0}))) then
|
||||
piece:setRelativeRotation(rot_dir):setOffset({x=dx, y=0})
|
||||
self:onPieceRotate(piece, grid)
|
||||
end
|
||||
end
|
||||
|
||||
return EHeart
|
@ -1,102 +0,0 @@
|
||||
local Piece = require 'tetris.components.piece'
|
||||
local SRS = require 'tetris.rulesets.standard_exp'
|
||||
|
||||
local PPTPRS = SRS:extend()
|
||||
|
||||
PPTPRS.name = "PPTPRS"
|
||||
PPTPRS.hash = "Puyo Tetris Pentos"
|
||||
|
||||
PPTPRS.block_offsets = {
|
||||
I={
|
||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0}, {x=-3, y=0} },
|
||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=0, y=2}, {x=0, y=-2} },
|
||||
{ {x=0, y=1}, {x=-1, y=1}, {x=-2, y=1}, {x=1, y=1}, {x=2, y=1} },
|
||||
{ {x=-1, y=0}, {x=-1, y=-1}, {x=-1, y=1}, {x=-1, y=2}, {x=-1, y=3} },
|
||||
},
|
||||
J={
|
||||
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=-1, y=-1}, {x=0, y=1} },
|
||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1} , {x=1, y=-1}, {x=-1, y=0} },
|
||||
{ {x=0, y=0}, {x=1, y=0}, {x=-1, y=0}, {x=1, y=1}, {x=0, y=-1} },
|
||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=-1}, {x=-1, y=1}, {x=1, y=0} },
|
||||
},
|
||||
L={
|
||||
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=1, y=-1}, {x=-1, y=1} },
|
||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=1, y=1}, {x=-1, y=-1} },
|
||||
{ {x=0, y=0}, {x=1, y=0}, {x=-1, y=0}, {x=-1, y=1}, {x=1, y=-1} },
|
||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=1} },
|
||||
},
|
||||
O={
|
||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1}, {x=-1, y=1} },
|
||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1}, {x=-2, y=-1} },
|
||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1}, {x=0, y=-2} },
|
||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1}, {x=1, y=0} },
|
||||
},
|
||||
S={
|
||||
{ {x=1, y=-1}, {x=0, y=-1}, {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0} },
|
||||
{ {x=1, y=1}, {x=1, y=0}, {x=0, y=0}, {x=0, y=-1}, {x=0, y=-2} },
|
||||
{ {x=-1, y=1}, {x=0, y=1}, {x=0, y=0}, {x=1, y=0}, {x=2, y=0} },
|
||||
{ {x=-1, y=-1}, {x=-1, y=0}, {x=0, y=0}, {x=0, y=1}, {x=0, y=2} },
|
||||
},
|
||||
T={
|
||||
{ {x=0, y=0}, {x=-1, 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=1}, {x=1, y=0}, {x=2, y=0} },
|
||||
{ {x=0, y=0}, {x=1, 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=-1}, {x=-1, y=0}, {x=-2, y=0} },
|
||||
},
|
||||
Z={
|
||||
{ {x=-1, y=-1}, {x=0, y=-1}, {x=0, y=0}, {x=1, y=0}, {x=1, y=1} },
|
||||
{ {x=1, y=-1}, {x=1, y=0}, {x=0, y=0}, {x=0, y=1}, {x=-1, 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=1}, {x=-1, y=0}, {x=0, y=0}, {x=0, y=-1}, {x=1, y=-1} },
|
||||
}
|
||||
}
|
||||
|
||||
PPTPRS.wallkicks_O = {
|
||||
[0]={
|
||||
[1]={{x=0, y=1}},
|
||||
[2]={{x=0, y=1}},
|
||||
[3]={{x=-1, y=0}},
|
||||
},
|
||||
[1]={
|
||||
[0]={{x=0, y=-1}},
|
||||
[2]={{x=-1, y=0}},
|
||||
[3]={{x=-1, y=0}},
|
||||
},
|
||||
[2]={
|
||||
[0]={{x=0, y=-1}},
|
||||
[1]={{x=1, y=0}},
|
||||
[3]={{x=0, y=-1}},
|
||||
},
|
||||
[3]={
|
||||
[0]={{x=1, y=0}},
|
||||
[1]={{x=1, y=0}},
|
||||
[2]={{x=0, y=1}},
|
||||
},
|
||||
}
|
||||
|
||||
function PPTPRS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||
local kicks
|
||||
|
||||
if piece.shape == "O" then
|
||||
kicks = PPTPRS.wallkicks_O[piece.rotation][new_piece.rotation]
|
||||
elseif piece.shape == "I" then
|
||||
kicks = SRS.wallkicks_line[piece.rotation][new_piece.rotation]
|
||||
else
|
||||
kicks = SRS.wallkicks_3x3[piece.rotation][new_piece.rotation]
|
||||
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)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return PPTPRS
|
@ -1,102 +0,0 @@
|
||||
Piece = require("tetris.components.piece")
|
||||
|
||||
local BONKERS = {}
|
||||
|
||||
BONKERS.name = "B.O.N.K.E.R.S."
|
||||
BONKERS.hash = "Bonkers"
|
||||
|
||||
BONKERS.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 },
|
||||
}
|
||||
|
||||
BONKERS.block_offsets = {
|
||||
I={
|
||||
{ {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=1}, {x=-1, y=1}, {x=-2, y=1}, {x=1, y=1} },
|
||||
{ {x=-1, y=0}, {x=-1, y=-1}, {x=-1, y=1}, {x=-1, y=2} },
|
||||
},
|
||||
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=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=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=-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} },
|
||||
}
|
||||
}
|
||||
|
||||
-- Component functions.
|
||||
|
||||
function BONKERS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||
|
||||
if piece.shape == "O" then
|
||||
break
|
||||
elseif piece.shape == "I" then
|
||||
horizontal_kicks = {0, 1, -1, 2, -2}
|
||||
else
|
||||
horizontal_kicks = {0, 1, -1}
|
||||
end
|
||||
|
||||
for y_offset = 20, new_piece.position.y - 24, -1 do
|
||||
for idx, x_offset in pairs(horizontal_kicks) do
|
||||
local offset = {x=x_offset, y=y_offset}
|
||||
kicked_piece = new_piece:withOffset(offset)
|
||||
if grid:canPlacePiece(kicked_piece) then
|
||||
piece:setRelativeRotation(rot_dir)
|
||||
piece:setOffset(offset)
|
||||
piece.lock_delay = 0 -- rotate reset
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function BONKERS:onPieceDrop(piece, grid)
|
||||
piece.lock_delay = 0 -- step reset
|
||||
end
|
||||
|
||||
function BONKERS:onPieceMove(piece, grid)
|
||||
piece.lock_delay = 0 -- move reset
|
||||
end
|
||||
|
||||
function BONKERS:onPieceRotate(piece, grid)
|
||||
piece.lock_delay = 0 -- rotate reset
|
||||
end
|
||||
|
||||
return BONKERS
|
@ -1,235 +0,0 @@
|
||||
Piece = require("tetris.components.piece")
|
||||
require("funcs")
|
||||
|
||||
local SRS = {}
|
||||
|
||||
SRS.name = "SHIRASE"
|
||||
SRS.hash = "Shirase"
|
||||
|
||||
SRS.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 },
|
||||
}
|
||||
|
||||
SRS.block_offsets = {
|
||||
I={
|
||||
{ {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=1}, {x=-1, y=1}, {x=-2, y=1}, {x=1, y=1} },
|
||||
{ {x=-1, y=0}, {x=-1, y=-1}, {x=-1, y=1}, {x=-1, y=2} },
|
||||
},
|
||||
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=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=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=-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} },
|
||||
}
|
||||
}
|
||||
|
||||
SRS.wallkicks_3x3 = {
|
||||
[0]={
|
||||
[1]={{x=-1, y=0}, {x=-1, y=-1}, {x=0, y=2}, {x=-1, y=2}},
|
||||
[2]={{x=0, y=1}, {x=0, y=-1}},
|
||||
[3]={{x=1, y=0}, {x=1, y=-1}, {x=0, y=2}, {x=1, y=2}},
|
||||
},
|
||||
[1]={
|
||||
[0]={{x=1, y=0}, {x=1, y=1}, {x=0, y=-2}, {x=1, y=-2}},
|
||||
[2]={{x=1, y=0}, {x=1, y=1}, {x=0, y=-2}, {x=1, y=-2}},
|
||||
[3]={{x=0, y=1}, {x=0, y=-1}},
|
||||
},
|
||||
[2]={
|
||||
[0]={{x=0, y=1}, {x=0, y=-1}},
|
||||
[1]={{x=-1, y=0}, {x=-1, y=-1}, {x=0, y=2}, {x=-1, y=2}},
|
||||
[3]={{x=1, y=0}, {x=1, y=-1}, {x=0, y=2}, {x=1, y=2}},
|
||||
},
|
||||
[3]={
|
||||
[0]={{x=-1, y=0}, {x=-1, y=1}, {x=0, y=-2}, {x=-1, y=-2}},
|
||||
[1]={{x=0, y=1}, {x=0, y=-1}},
|
||||
[2]={{x=-1, y=0}, {x=-1, y=1}, {x=0, y=-2}, {x=-1, y=-2}},
|
||||
},
|
||||
};
|
||||
|
||||
SRS.wallkicks_line = {
|
||||
[0]={
|
||||
[1]={{x=-2, y=0}, {x=1, y=0}, {x=-2, y=1}, {x=1, y=-2}},
|
||||
[2]={},
|
||||
[3]={{x=-1, y=0}, {x=2, y=0}, {x=-1, y=-2}, {x=2, y=1}},
|
||||
},
|
||||
[1]={
|
||||
[0]={{x=2, y=0}, {x=-1, y=0}, {x=2, y=-1}, {x=-1, y=2}},
|
||||
[2]={{x=-1, y=0}, {x=2, y=0}, {x=-1, y=-2}, {x=2, y=1}},
|
||||
[3]={{x=0, y=1}, {x=0, y=-1}, {x=0, y=2}, {x=0, y=-2}},
|
||||
},
|
||||
[2]={
|
||||
[0]={},
|
||||
[1]={{x=1, y=0}, {x=-2, y=0}, {x=1, y=2}, {x=-2, y=-1}},
|
||||
[3]={{x=2, y=0}, {x=-1, y=0}, {x=2, y=-1}, {x=-1, y=2}},
|
||||
},
|
||||
[3]={
|
||||
[0]={{x=1, y=0}, {x=-2, y=0}, {x=1, y=2}, {x=-2, y=-1}},
|
||||
[1]={{x=0, y=1}, {x=0, y=-1}, {x=0, y=2}, {x=0, y=-2}},
|
||||
[2]={{x=-2, y=0}, {x=1, y=0}, {x=-2, y=1}, {x=1, y=-2}},
|
||||
},
|
||||
};
|
||||
|
||||
local basicOffsets = {
|
||||
[0] = { x = 1, y = 0 },
|
||||
[1] = { x = 0, y = 1 },
|
||||
[2] = { x = -1, y = 0 },
|
||||
[3] = { x = 0, y = -1 }
|
||||
}
|
||||
|
||||
-- Component functions.
|
||||
|
||||
local function rotatePiece(inputs, piece, grid, prev_inputs)
|
||||
local new_inputs = {}
|
||||
|
||||
for input, value in pairs(inputs) do
|
||||
if value and not prev_inputs[input] then
|
||||
new_inputs[input] = true
|
||||
end
|
||||
end
|
||||
|
||||
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 = 2
|
||||
end
|
||||
|
||||
while rot_dir ~= 0 do
|
||||
rotated_piece = piece:withRelativeRotation(rot_dir)
|
||||
rotation_offset = vAdd(
|
||||
basicOffsets[piece.rotation],
|
||||
vNeg(basicOffsets[rotated_piece.rotation])
|
||||
)
|
||||
new_piece = rotated_piece:withOffset(rotation_offset)
|
||||
|
||||
if (grid:canPlacePiece(new_piece)) then
|
||||
piece:setRelativeRotation(rot_dir)
|
||||
piece:setOffset(rotation_offset)
|
||||
piece.lock_delay = 0 -- rotate reset
|
||||
break
|
||||
end
|
||||
|
||||
if piece.shape == "I" then
|
||||
kicks = SRS.wallkicks_line[piece.rotation][new_piece.rotation]
|
||||
else
|
||||
kicks = SRS.wallkicks_3x3[piece.rotation][new_piece.rotation]
|
||||
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(vAdd(offset, rotation_offset))
|
||||
piece.lock_delay = 0 -- rotate reset
|
||||
rot_dir = 0
|
||||
end
|
||||
if rot_dir == 0 then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
rot_dir = 0
|
||||
end
|
||||
|
||||
-- prev_inputs becomes the previous inputs
|
||||
for input, value in pairs(inputs) do
|
||||
prev_inputs[input] = inputs[input]
|
||||
end
|
||||
end
|
||||
|
||||
local function movePiece(piece, grid, move)
|
||||
if move == "left" then
|
||||
if not piece:isMoveBlocked(grid, {x=-1, y=0}) then
|
||||
piece.lock_delay = 0 -- move reset
|
||||
end
|
||||
piece:moveInGrid({x=-1, y=0}, 1, grid)
|
||||
elseif move == "right" then
|
||||
if not piece:isMoveBlocked(grid, {x=1, y=0}) then
|
||||
piece.lock_delay = 0 -- move reset
|
||||
end
|
||||
piece:moveInGrid({x=1, y=0}, 1, grid)
|
||||
end
|
||||
end
|
||||
|
||||
local function dropPiece(inputs, piece, grid, gravity, drop_speed, drop_locked)
|
||||
local y = piece.position.y
|
||||
if inputs["down"] == true and drop_locked == false then
|
||||
piece:addGravity(gravity + 1, grid):lockIfBottomed(grid)
|
||||
elseif inputs["up"] == true then
|
||||
if piece:isDropBlocked(grid) then
|
||||
return
|
||||
end
|
||||
piece:dropToBottom(grid)
|
||||
else
|
||||
piece:addGravity(gravity, grid)
|
||||
end
|
||||
if piece.position.y ~= y then -- step reset
|
||||
piece.lock_delay = 0
|
||||
end
|
||||
end
|
||||
|
||||
local function lockPiece(piece, grid, lock_delay)
|
||||
if piece:isDropBlocked(grid) and piece.lock_delay >= lock_delay then
|
||||
piece.locked = true
|
||||
end
|
||||
end
|
||||
|
||||
function SRS.initializePiece(inputs, data, grid, gravity, prev_inputs, move, lock_delay, drop_speed, drop_locked)
|
||||
local piece = Piece(shape, 0, {
|
||||
x = SRS.spawn_positions[shape].x,
|
||||
y = SRS.spawn_positions[shape].y
|
||||
}, SRS.block_offsets, 0, 0)
|
||||
-- have to copy that object otherwise it gets referenced
|
||||
rotatePiece(inputs, piece, grid, {})
|
||||
dropPiece(inputs, piece, grid, gravity, drop_speed, drop_locked)
|
||||
return piece
|
||||
end
|
||||
|
||||
function SRS.processPiece(inputs, piece, grid, gravity, prev_inputs, move, lock_delay, drop_speed, drop_locked)
|
||||
rotatePiece(inputs, piece, grid, prev_inputs)
|
||||
movePiece(piece, grid, move)
|
||||
dropPiece(inputs, piece, grid, gravity, drop_speed, drop_locked)
|
||||
lockPiece(piece, grid, lock_delay)
|
||||
end
|
||||
|
||||
return SRS
|
@ -1,174 +0,0 @@
|
||||
Piece = require("tetris.components.piece")
|
||||
|
||||
local BONKERS = {}
|
||||
|
||||
BONKERS.name = "SUPER302"
|
||||
BONKERS.hash = "Super302"
|
||||
|
||||
BONKERS.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 },
|
||||
}
|
||||
|
||||
BONKERS.block_offsets = {
|
||||
I={
|
||||
{ {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=1}, {x=-1, y=1}, {x=-2, y=1}, {x=1, y=1} },
|
||||
{ {x=-1, y=0}, {x=-1, y=-1}, {x=-1, y=1}, {x=-1, y=2} },
|
||||
},
|
||||
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=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=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=-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} },
|
||||
}
|
||||
}
|
||||
|
||||
-- Component functions.
|
||||
|
||||
local function rotatePiece(inputs, piece, grid, prev_inputs)
|
||||
local new_inputs = {}
|
||||
|
||||
for input, value in pairs(inputs) do
|
||||
if value and not prev_inputs[input] then
|
||||
new_inputs[input] = true
|
||||
end
|
||||
end
|
||||
|
||||
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 = 2
|
||||
end
|
||||
|
||||
while rot_dir ~= 0 do
|
||||
if piece.filled then break end
|
||||
|
||||
new_piece = piece:withRelativeRotation(rot_dir)
|
||||
|
||||
if (grid:canPlacePiece(new_piece)) and piece.shape ~= "O" then
|
||||
piece:setRelativeRotation(rot_dir)
|
||||
piece.lock_delay = 0 -- rotate reset
|
||||
else
|
||||
-- set the piece to occupy the whole grid
|
||||
piece.filled = true
|
||||
unfilled_block_offsets = {}
|
||||
for y = 4, 23 do
|
||||
for x = 0, 9 do
|
||||
if not grid:isOccupied(x, y) then
|
||||
table.insert(unfilled_block_offsets, {x=x, y=y})
|
||||
end
|
||||
end
|
||||
end
|
||||
piece.position = {x=0, y=0}
|
||||
piece.getBlockOffsets = function(piece)
|
||||
return unfilled_block_offsets
|
||||
end
|
||||
piece.isDropBlocked = function(piece)
|
||||
return true
|
||||
end
|
||||
end
|
||||
rot_dir = 0
|
||||
end
|
||||
|
||||
-- prev_inputs becomes the previous inputs
|
||||
for input, value in pairs(inputs) do
|
||||
prev_inputs[input] = inputs[input]
|
||||
end
|
||||
end
|
||||
|
||||
local function movePiece(piece, grid, move)
|
||||
if move == "left" then
|
||||
if not piece:isMoveBlocked(grid, {x=-1, y=0}) then
|
||||
piece.lock_delay = 0 -- move reset
|
||||
end
|
||||
piece:moveInGrid({x=-1, y=0}, 1, grid)
|
||||
elseif move == "right" then
|
||||
if not piece:isMoveBlocked(grid, {x=1, y=0}) then
|
||||
piece.lock_delay = 0 -- move reset
|
||||
end
|
||||
piece:moveInGrid({x=1, y=0}, 1, grid)
|
||||
end
|
||||
end
|
||||
|
||||
local function dropPiece(inputs, piece, grid, gravity, drop_speed, drop_locked)
|
||||
local y = piece.position.y
|
||||
if inputs["down"] == true and drop_locked == false then
|
||||
piece:addGravity(gravity + 1, grid):lockIfBottomed(grid)
|
||||
elseif inputs["up"] == true then
|
||||
if piece:isDropBlocked(grid) then
|
||||
return
|
||||
end
|
||||
piece:dropToBottom(grid)
|
||||
else
|
||||
piece:addGravity(gravity, grid)
|
||||
end
|
||||
if piece.position.y ~= y then -- step reset
|
||||
piece.lock_delay = 0
|
||||
end
|
||||
end
|
||||
|
||||
local function lockPiece(piece, grid, lock_delay)
|
||||
if piece:isDropBlocked(grid) and piece.lock_delay >= lock_delay then
|
||||
piece.locked = true
|
||||
end
|
||||
end
|
||||
|
||||
function BONKERS.initializePiece(inputs, data, grid, gravity, prev_inputs, move, lock_delay, drop_speed, drop_locked)
|
||||
local piece = Piece(shape, 0, {
|
||||
x = BONKERS.spawn_positions[shape].x,
|
||||
y = BONKERS.spawn_positions[shape].y
|
||||
}, BONKERS.block_offsets, 0, 0)
|
||||
-- have to copy that object otherwise it gets referenced
|
||||
rotatePiece(inputs, piece, grid, {})
|
||||
dropPiece(inputs, piece, grid, gravity, drop_speed, drop_locked)
|
||||
return piece
|
||||
end
|
||||
|
||||
function BONKERS.processPiece(inputs, piece, grid, gravity, prev_inputs, move, lock_delay, drop_speed, drop_locked)
|
||||
rotatePiece(inputs, piece, grid, prev_inputs)
|
||||
movePiece(piece, grid, move)
|
||||
dropPiece(inputs, piece, grid, gravity, drop_speed, drop_locked)
|
||||
lockPiece(piece, grid, lock_delay)
|
||||
end
|
||||
|
||||
return BONKERS
|
@ -1,140 +0,0 @@
|
||||
local Piece = require 'tetris.components.piece'
|
||||
local Ruleset = require 'tetris.rulesets.ruleset'
|
||||
|
||||
local Tengen = Ruleset:extend()
|
||||
|
||||
Tengen.name = "Tengen"
|
||||
Tengen.hash = "Tengen"
|
||||
|
||||
Tengen.spawn_positions = {
|
||||
I = { x=3, y=4 },
|
||||
J = { x=4, y=4 },
|
||||
L = { x=4, y=4 },
|
||||
O = { x=5, y=4 },
|
||||
S = { x=4, y=4 },
|
||||
T = { x=4, y=4 },
|
||||
Z = { x=4, y=4 },
|
||||
}
|
||||
|
||||
Tengen.block_offsets = {
|
||||
I={
|
||||
{ {x=0, y=0}, {x=1, y=0}, {x=2, y=0}, {x=3, y=0} },
|
||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=2}, {x=0, y=3} },
|
||||
{ {x=0, y=0}, {x=1, y=0}, {x=2, y=0}, {x=3, y=0} },
|
||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=2}, {x=0, y=3} },
|
||||
},
|
||||
J={
|
||||
{ {x=0, y=0}, {x=1, y=0}, {x=2, y=0}, {x=2, y=1} },
|
||||
{ {x=1, y=0}, {x=1, y=1}, {x=1, y=2}, {x=0, y=2} },
|
||||
{ {x=0, y=0}, {x=0, y=1}, {x=1, y=1}, {x=2, y=1} },
|
||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=2}, {x=1, y=0} },
|
||||
},
|
||||
L={
|
||||
{ {x=0, y=0}, {x=1, y=0}, {x=2, y=0}, {x=0, y=1} },
|
||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=2}, {x=1, y=2} },
|
||||
{ {x=2, y=0}, {x=0, y=1}, {x=1, y=1}, {x=2, y=1} },
|
||||
{ {x=0, y=0}, {x=1, y=0}, {x=1, y=1}, {x=1, y=2} },
|
||||
},
|
||||
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} },
|
||||
},
|
||||
-- up to here
|
||||
S={
|
||||
{ {x=0, y=0}, {x=1, y=0}, {x=2, y=0}, {x=3, y=0} },
|
||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=2}, {x=0, y=3} },
|
||||
{ {x=0, y=0}, {x=1, y=0}, {x=2, y=0}, {x=3, y=0} },
|
||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=2}, {x=0, y=3} },
|
||||
},
|
||||
T={
|
||||
{ {x=0, y=0}, {x=1, y=0}, {x=2, y=0}, {x=3, y=0} },
|
||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=2}, {x=0, y=3} },
|
||||
{ {x=0, y=0}, {x=1, y=0}, {x=2, y=0}, {x=3, y=0} },
|
||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=2}, {x=0, y=3} },
|
||||
},
|
||||
Z={
|
||||
{ {x=0, y=0}, {x=1, y=0}, {x=2, y=0}, {x=3, y=0} },
|
||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=2}, {x=0, y=3} },
|
||||
{ {x=0, y=0}, {x=1, y=0}, {x=2, y=0}, {x=3, y=0} },
|
||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=2}, {x=0, y=3} },
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
-- Component functions.
|
||||
|
||||
function Tengen:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||
|
||||
-- O doesn't kick
|
||||
if (piece.shape == "O") then return end
|
||||
|
||||
-- center column rule
|
||||
if (
|
||||
piece.shape == "J" or piece.shape == "T" or piece.shape == "L"
|
||||
) and (
|
||||
piece.rotation == 0 or piece.rotation == 2
|
||||
) and (
|
||||
grid:isOccupied(piece.position.x, piece.position.y) or
|
||||
grid:isOccupied(piece.position.x, piece.position.y - 1) or
|
||||
grid:isOccupied(piece.position.x, piece.position.y - 2)
|
||||
) then return end
|
||||
|
||||
if piece.shape == "I" then
|
||||
-- special kick rules for I
|
||||
if new_piece.rotation == 0 or new_piece.rotation == 2 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})
|
||||
self:onPieceRotate(piece, grid)
|
||||
piece.floorkick = 1
|
||||
elseif grid:canPlacePiece(new_piece:withOffset({x=0, y=-2})) then
|
||||
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-2})
|
||||
self:onPieceRotate(piece, grid)
|
||||
piece.floorkick = 1
|
||||
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
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function Tengen:onPieceCreate(piece, grid)
|
||||
piece.floorkick = 0
|
||||
end
|
||||
|
||||
function Tengen:onPieceDrop(piece, grid)
|
||||
piece.lock_delay = 0 -- step reset
|
||||
end
|
||||
|
||||
function Tengen:get180RotationValue()
|
||||
if config.gamesettings.world_reverse == 3 then
|
||||
return 1
|
||||
else
|
||||
return 3
|
||||
end
|
||||
end
|
||||
|
||||
function Tengen:getDefaultOrientation() return 3 end -- downward facing pieces by default
|
||||
|
||||
return Tengen
|
Loading…
Reference in New Issue
Block a user