mirror of
https://github.com/SashLilac/cambridge-modpack.git
synced 2024-12-26 03:19:01 -06:00
Whole bunch of good stuff added
This commit is contained in:
parent
3776393354
commit
3674c78609
175
tetris/modes/beginner_a2.lua
Normal file
175
tetris/modes/beginner_a2.lua
Normal file
@ -0,0 +1,175 @@
|
||||
require 'funcs'
|
||||
|
||||
local GameMode = require 'tetris.modes.gamemode'
|
||||
|
||||
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
||||
|
||||
local BeginnerA2Game = GameMode:extend()
|
||||
|
||||
BeginnerA2Game.name = "Beginner A2"
|
||||
BeginnerA2Game.hash = "BeginnerA2"
|
||||
BeginnerA2Game.tagline = "How many points can you score in 300 levels?"
|
||||
|
||||
function BeginnerA2Game:new()
|
||||
self.super:new()
|
||||
|
||||
self.roll_frames = 0
|
||||
self.combo = 1
|
||||
self.randomizer = History6RollsRandomizer()
|
||||
self.piece_time = 0
|
||||
|
||||
self.SGnames = {
|
||||
"9", "8", "7", "6", "5", "4", "3", "2", "1",
|
||||
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
|
||||
"GM"
|
||||
}
|
||||
|
||||
self.lock_drop = false
|
||||
self.lock_hard_drop = false
|
||||
self.enable_hold = false
|
||||
self.next_queue_length = 1
|
||||
end
|
||||
|
||||
function BeginnerA2Game:getARE() return 25 end
|
||||
function BeginnerA2Game:getLineARE() return self:getARE() end
|
||||
function BeginnerA2Game:getLineClearDelay() return 40 end
|
||||
function BeginnerA2Game:getDasLimit() return 14 end
|
||||
function BeginnerA2Game:getLockDelay() return 30 end
|
||||
|
||||
function BeginnerA2Game:getGravity()
|
||||
if self.level < 8 then return 4/256
|
||||
elseif self.level < 19 then return 5/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 < 108 then return 4/256
|
||||
elseif self.level < 119 then return 5/256
|
||||
elseif self.level < 125 then return 6/256
|
||||
elseif self.level < 131 then return 8/256
|
||||
elseif self.level < 139 then return 12/256
|
||||
elseif self.level < 149 then return 32/256
|
||||
elseif self.level < 156 then return 48/256
|
||||
elseif self.level < 164 then return 80/256
|
||||
elseif self.level < 174 then return 112/256
|
||||
elseif self.level < 180 then return 128/256
|
||||
elseif self.level < 200 then return 144/256
|
||||
elseif self.level < 212 then return 16/256
|
||||
elseif self.level < 221 then return 48/256
|
||||
elseif self.level < 232 then return 80/256
|
||||
elseif self.level < 244 then return 112/256
|
||||
elseif self.level < 256 then return 144/256
|
||||
elseif self.level < 267 then return 176/256
|
||||
elseif self.level < 277 then return 192/256
|
||||
elseif self.level < 287 then return 208/256
|
||||
elseif self.level < 295 then return 224/256
|
||||
elseif self.level < 300 then return 240/256
|
||||
else return 20 end
|
||||
end
|
||||
|
||||
function BeginnerA2Game:advanceOneFrame()
|
||||
if self.clear then
|
||||
self.roll_frames = self.roll_frames + 1
|
||||
if self.roll_frames > 1800 then
|
||||
self.completed = true
|
||||
end
|
||||
elseif self.ready_frames == 0 then
|
||||
self.frames = self.frames + 1
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function BeginnerA2Game:onPieceEnter()
|
||||
if self.level ~= 299 and not self.clear and self.frames ~= 0 then
|
||||
self.level = self.level + 1
|
||||
end
|
||||
end
|
||||
|
||||
function BeginnerA2Game: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 +
|
||||
math.ceil(math.min(300, level + cleared_lines) / 2) +
|
||||
math.max(self:getLockDelay() - self.piece_time, 0) * 7)
|
||||
* 6
|
||||
)
|
||||
else
|
||||
self.combo = 1
|
||||
end
|
||||
self.drop_bonus = 0
|
||||
self.piece_time = 0
|
||||
end
|
||||
end
|
||||
|
||||
function BeginnerA2Game:whilePieceActive()
|
||||
self.piece_time = self.piece_time + 1
|
||||
end
|
||||
|
||||
function BeginnerA2Game:onLineClear(cleared_row_count)
|
||||
self.level = math.min(self.level + cleared_row_count, 300)
|
||||
if self.level == 300 and not self.clear then
|
||||
self.clear = true
|
||||
self.score = self.score + (
|
||||
1253 * math.ceil(math.max(0, 18000 - self.frames) / 60)
|
||||
)
|
||||
end
|
||||
end
|
||||
|
||||
function BeginnerA2Game:drawGrid()
|
||||
self.grid:draw()
|
||||
if self.piece ~= nil and self.level < 100 then
|
||||
self:drawGhostPiece(ruleset)
|
||||
end
|
||||
end
|
||||
|
||||
function BeginnerA2Game:getHighscoreData()
|
||||
return {
|
||||
score = self.score,
|
||||
level = self.level,
|
||||
frames = self.frames,
|
||||
}
|
||||
end
|
||||
|
||||
function BeginnerA2Game:getBackground()
|
||||
return math.floor(self.level / 100)
|
||||
end
|
||||
|
||||
function BeginnerA2Game:drawScoringInfo()
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
|
||||
love.graphics.setFont(font_3x5_2)
|
||||
love.graphics.print(
|
||||
self.das.direction .. " " ..
|
||||
self.das.frames .. " " ..
|
||||
self.piece_time .. " " ..
|
||||
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(300, 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 BeginnerA2Game
|
40
tetris/modes/big_meme.lua
Normal file
40
tetris/modes/big_meme.lua
Normal file
@ -0,0 +1,40 @@
|
||||
require 'funcs'
|
||||
|
||||
local SurvivalA3Game = require 'tetris.modes.survival_a3'
|
||||
|
||||
local BigMemeGame = SurvivalA3Game:extend()
|
||||
|
||||
BigMemeGame.name = "Big Survival A3"
|
||||
BigMemeGame.hash = "BigA3"
|
||||
BigMemeGame.tagline = "The blocks are bigger and the speeds are faster!"
|
||||
|
||||
function BigMemeGame:initialize(ruleset)
|
||||
self.super:initialize(ruleset)
|
||||
self.big_mode = true
|
||||
end
|
||||
|
||||
local cleared_row_levels = {1, 2, 4, 6}
|
||||
|
||||
function BigMemeGame:onLineClear(cleared_row_count)
|
||||
cleared_row_count = cleared_row_count / 2
|
||||
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.big_mode = true
|
||||
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
|
||||
end
|
||||
|
||||
return BigMemeGame
|
119
tetris/modes/credits_a3.lua
Normal file
119
tetris/modes/credits_a3.lua
Normal file
@ -0,0 +1,119 @@
|
||||
require 'funcs'
|
||||
|
||||
local IntervalTrainingMode = require 'tetris.modes.interval_training'
|
||||
local Piece = require 'tetris.components.piece'
|
||||
|
||||
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
||||
|
||||
local CreditsA3Game = IntervalTrainingMode:extend()
|
||||
|
||||
CreditsA3Game.name = "Credits A3"
|
||||
CreditsA3Game.hash = "CreditsA3"
|
||||
CreditsA3Game.tagline = "How consistently can you clear the Ti M-roll?"
|
||||
|
||||
function CreditsA3Game:new()
|
||||
CreditsA3Game.super:new()
|
||||
self.section_time_limit = 3238
|
||||
self.norm = 0
|
||||
self.section = 0
|
||||
end
|
||||
|
||||
function CreditsA3Game:advanceOneFrame(inputs, ruleset)
|
||||
if self.frames == 0 then
|
||||
switchBGM("credit_roll", "gm3")
|
||||
end
|
||||
if self.roll_frames > 0 then
|
||||
self.roll_frames = self.roll_frames - 1
|
||||
if self.roll_frames == 0 then
|
||||
-- reset
|
||||
self.norm = 0
|
||||
self.frames = 0
|
||||
self.grid:clear()
|
||||
switchBGM("credit_roll", "gm3")
|
||||
self:initializeOrHold(inputs, ruleset)
|
||||
else
|
||||
return false
|
||||
end
|
||||
elseif self.ready_frames == 0 then
|
||||
self.frames = self.frames + 1
|
||||
if self:getSectionTime() >= self.section_time_limit then
|
||||
self.norm = self.norm + 16
|
||||
self.piece = nil
|
||||
if self.norm >= 60 then
|
||||
self.section = self.section + 1
|
||||
self.roll_frames = 150
|
||||
else
|
||||
self.game_over = true
|
||||
switchBGM(nil)
|
||||
end
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function CreditsA3Game:onPieceEnter()
|
||||
-- do nothing
|
||||
end
|
||||
|
||||
function CreditsA3Game:onLineClear(cleared_row_count)
|
||||
if not self.clear then
|
||||
self.norm = self.norm + (cleared_row_count == 4 and 10 or cleared_row_count)
|
||||
end
|
||||
end
|
||||
|
||||
CreditsA3Game.rollOpacityFunction = function(age)
|
||||
if age > 4 then return 0
|
||||
else return 1 - age / 4 end
|
||||
end
|
||||
|
||||
function CreditsA3Game:drawGrid(ruleset)
|
||||
if not self.game_over and self.roll_frames < 30 then
|
||||
self.grid:drawInvisible(self.rollOpacityFunction)
|
||||
else
|
||||
self.grid:draw()
|
||||
end
|
||||
end
|
||||
|
||||
function CreditsA3Game: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 LEFT", 240, 250, 80, "left")
|
||||
love.graphics.printf("NORM", 240, 320, 40, "left")
|
||||
|
||||
self:drawSectionTimesWithSplits(self.section)
|
||||
|
||||
love.graphics.setFont(font_3x5_3)
|
||||
-- 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 not self.clear and time_left < frameTime(0,10) and time_left % 4 < 2 then
|
||||
if self.norm >= 44 then
|
||||
love.graphics.setColor(0.3, 1, 0.3, 1) -- flash green if goal has been cleared
|
||||
else
|
||||
love.graphics.setColor(1, 0.3, 0.3, 1) -- otherwise flash red
|
||||
end
|
||||
end
|
||||
|
||||
love.graphics.printf(formatTime(time_left), 240, 270, 160, "left")
|
||||
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
love.graphics.printf(self.norm, 240, 340, 40, "right")
|
||||
if self.game_over or self.roll_frames > 0 then
|
||||
love.graphics.printf("60", 240, 370, 40, "right")
|
||||
else
|
||||
love.graphics.printf("44", 240, 370, 40, "right")
|
||||
end
|
||||
end
|
||||
|
||||
function CreditsA3Game:getBackground()
|
||||
return self.section
|
||||
end
|
||||
|
||||
return CreditsA3Game
|
@ -206,7 +206,9 @@ function GLock:drawScoringInfo()
|
||||
love.graphics.setFont(font_3x5_3)
|
||||
|
||||
if self:getGSection() == 11 then
|
||||
if self.frames <= 18000 then love.graphics.printf("GM", 240, 140, 90, "left")
|
||||
-- blame gizmo4487 for this time
|
||||
-- he's a legend
|
||||
if self.frames <= frameTime(5,19) then love.graphics.printf("GM", 240, 140, 90, "left")
|
||||
else love.graphics.printf("M", 240, 140, 90, "left") end
|
||||
else
|
||||
love.graphics.printf("G"..1+self:getGSection(), 240, 140, 90, "left")
|
||||
|
131
tetris/modes/kamui.lua
Normal file
131
tetris/modes/kamui.lua
Normal file
@ -0,0 +1,131 @@
|
||||
require 'funcs'
|
||||
|
||||
local GameMode = require 'tetris.modes.gamemode'
|
||||
|
||||
local Randomizer = require 'tetris.randomizers.kamui_sequence'
|
||||
|
||||
local KamuiGame = GameMode:extend()
|
||||
|
||||
KamuiGame.name = "Race A3"
|
||||
KamuiGame.hash = "RaceA3"
|
||||
KamuiGame.tagline = "How fast can you reach level 500?"
|
||||
|
||||
function KamuiGame:new()
|
||||
self.super:new()
|
||||
|
||||
self.randomizer = Randomizer()
|
||||
self.time_limit = 18000
|
||||
|
||||
self.section_start_time = 0
|
||||
self.section_times = { [0] = 0 }
|
||||
|
||||
self.lock_drop = true
|
||||
self.lock_hard_drop = true
|
||||
self.enable_hold = true
|
||||
self.next_queue_length = 3
|
||||
end
|
||||
|
||||
function KamuiGame:getARE()
|
||||
if self.level < 100 then return 16
|
||||
elseif self.level < 300 then return 12
|
||||
elseif self.level < 400 then return 6
|
||||
else return 5 end
|
||||
end
|
||||
|
||||
function KamuiGame:getLineARE()
|
||||
if self.level < 100 then return 12
|
||||
elseif self.level < 400 then return 6
|
||||
else return 5 end
|
||||
end
|
||||
|
||||
function KamuiGame:getLineClearDelay() return self:getLineARE() end
|
||||
|
||||
function KamuiGame:getDasLimit()
|
||||
if self.level < 200 then return 10
|
||||
elseif self.level < 300 then return 9
|
||||
elseif self.level < 400 then return 8
|
||||
else return 6 end
|
||||
end
|
||||
|
||||
function KamuiGame:getLockDelay()
|
||||
if self.level < 100 then return 30
|
||||
elseif self.level < 200 then return 26
|
||||
elseif self.level < 300 then return 22
|
||||
elseif self.level < 400 then return 18
|
||||
else return 15 end
|
||||
end
|
||||
|
||||
function KamuiGame:getGravity() return 20 end
|
||||
|
||||
function KamuiGame:onPieceEnter()
|
||||
if self.level % 100 ~= 99 and self.frames ~= 0 then
|
||||
self.level = self.level + 1
|
||||
end
|
||||
end
|
||||
|
||||
function KamuiGame:onLineClear(cleared_row_count)
|
||||
local cleared_row_levels = {1, 2, 4, 6}
|
||||
local new_level = self.level + cleared_row_levels[cleared_row_count]
|
||||
self:updateSectionTimes(self.level, new_level)
|
||||
self.level = math.min(500, new_level)
|
||||
self.game_over = self.level == 500
|
||||
end
|
||||
|
||||
function KamuiGame: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.frames - self.section_start_time)
|
||||
self.section_start_time = self.frames
|
||||
end
|
||||
end
|
||||
|
||||
function KamuiGame:advanceOneFrame()
|
||||
if self.ready_frames == 0 then
|
||||
self.frames = self.frames + 1
|
||||
self.time_limit = self.time_limit - 1
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function KamuiGame:drawGrid() self.grid:draw() end
|
||||
|
||||
function KamuiGame: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 LEFT", 240, 250, 80, "left")
|
||||
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")
|
||||
love.graphics.printf(self.level == 500 and self.level or (math.floor(self.level / 100) + 1) * 100, 240, 370, 40, "right")
|
||||
|
||||
-- draw time left, flash red if necessary
|
||||
if not self.game_over and self.time_limit < frameTime(0,10) and time_left % 4 < 2 then
|
||||
love.graphics.setColor(1, 0.3, 0.3, 1)
|
||||
end
|
||||
love.graphics.printf(formatTime(self.time_limit), 240, 270, 160, "left")
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
end
|
||||
|
||||
function KamuiGame:getBackground()
|
||||
return math.floor(self.level / 100)
|
||||
end
|
||||
|
||||
function KamuiGame:getHighscoreData()
|
||||
return {
|
||||
level = self.level,
|
||||
frames = self.frames,
|
||||
}
|
||||
end
|
||||
|
||||
return KamuiGame
|
@ -27,6 +27,7 @@ function MarathonC88Game:new()
|
||||
self.enable_hold = false
|
||||
self.next_queue_length = 1
|
||||
|
||||
self.irs = false
|
||||
self.grid:applyCeiling(4)
|
||||
end
|
||||
|
||||
|
135
tetris/modes/marathon_wcb.lua
Normal file
135
tetris/modes/marathon_wcb.lua
Normal file
@ -0,0 +1,135 @@
|
||||
require 'funcs'
|
||||
|
||||
local GameMode = require 'tetris.modes.gamemode'
|
||||
local Piece = require 'tetris.components.piece'
|
||||
|
||||
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
||||
|
||||
local MarathonWCBGame = GameMode:extend()
|
||||
|
||||
MarathonWCBGame.name = "Marathon WCB"
|
||||
MarathonWCBGame.hash = "MarathonWCB"
|
||||
MarathonWCBGame.tagline = "When all the pieces slip right to their destinations... can you keep up?"
|
||||
|
||||
|
||||
function MarathonWCBGame:new()
|
||||
MarathonWCBGame.super:new()
|
||||
|
||||
self.pieces = 0
|
||||
self.randomizer = History6RollsRandomizer()
|
||||
|
||||
self.lock_drop = true
|
||||
self.lock_hard_drop = true
|
||||
self.instant_hard_drop = true
|
||||
self.instant_soft_drop = true
|
||||
self.enable_hold = false
|
||||
self.next_queue_length = 3
|
||||
|
||||
self.piece_is_active = false
|
||||
end
|
||||
|
||||
function MarathonWCBGame:getDropSpeed()
|
||||
return 20
|
||||
end
|
||||
|
||||
function MarathonWCBGame:getARR()
|
||||
return 0
|
||||
end
|
||||
|
||||
function MarathonWCBGame:getARE()
|
||||
return 0
|
||||
end
|
||||
|
||||
function MarathonWCBGame:getLineARE()
|
||||
return 0
|
||||
end
|
||||
|
||||
function MarathonWCBGame:getDasLimit()
|
||||
return 0
|
||||
end
|
||||
|
||||
function MarathonWCBGame:getLineClearDelay()
|
||||
return 0
|
||||
end
|
||||
|
||||
function MarathonWCBGame:getLockDelay()
|
||||
return math.huge
|
||||
end
|
||||
|
||||
function MarathonWCBGame:getGravity()
|
||||
return self.piece_is_active and 20 or 0
|
||||
end
|
||||
|
||||
function MarathonWCBGame:advanceOneFrame()
|
||||
if self.ready_frames == 0 then
|
||||
self.frames = self.frames + 1
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function MarathonWCBGame:onAttemptPieceMove()
|
||||
if self.piece ~= nil then
|
||||
-- don't let the piece move before it's finished dropping
|
||||
self.piece:dropToBottom(self.grid)
|
||||
end
|
||||
self.piece_is_active = true
|
||||
end
|
||||
|
||||
function MarathonWCBGame:onAttemptPieceRotate()
|
||||
self.piece_is_active = true
|
||||
end
|
||||
|
||||
function MarathonWCBGame:onPieceLock()
|
||||
self.super:onPieceLock()
|
||||
self.piece_is_active = false
|
||||
self.pieces = self.pieces + 1
|
||||
end
|
||||
|
||||
function MarathonWCBGame:onLineClear(cleared_row_count)
|
||||
self.lines = self.lines + cleared_row_count
|
||||
end
|
||||
|
||||
function MarathonWCBGame:drawGrid(ruleset)
|
||||
self.grid:draw()
|
||||
if self.piece ~= nil then
|
||||
self:drawGhostPiece(ruleset)
|
||||
end
|
||||
end
|
||||
|
||||
function MarathonWCBGame:getHighscoreData()
|
||||
return {
|
||||
pieces = self.pieces,
|
||||
frames = self.frames,
|
||||
}
|
||||
end
|
||||
|
||||
function MarathonWCBGame:drawScoringInfo()
|
||||
MarathonWCBGame.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, 160, 80, "left")
|
||||
love.graphics.printf("pieces", text_x, 220, 80, "left")
|
||||
love.graphics.printf("piece/sec", text_x, 280, 80, "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.lines, text_x, 180, 80, "left")
|
||||
love.graphics.printf(self.pieces, text_x, 240, 80, "left")
|
||||
love.graphics.printf(string.format("%.04f", self.pieces / math.max(1, self.frames) * 60), text_x, 300, 80, "left")
|
||||
if sg >= 5 then
|
||||
love.graphics.printf(self.SGnames[sg], 240, 450, 180, "left")
|
||||
end
|
||||
end
|
||||
|
||||
function MarathonWCBGame:getBackground()
|
||||
return (math.floor(self.pieces / 50) % 20)
|
||||
end
|
||||
|
||||
return MarathonWCBGame
|
77
tetris/modes/non.lua
Normal file
77
tetris/modes/non.lua
Normal file
@ -0,0 +1,77 @@
|
||||
require 'funcs'
|
||||
|
||||
local GameMode = require 'tetris.modes.gamemode'
|
||||
|
||||
local Bag7NoSZOStartRandomizer = require 'tetris.randomizers.bag7noSZOstart'
|
||||
|
||||
local NightOfNights = GameMode:extend()
|
||||
|
||||
NightOfNights.name = "Night of Nights"
|
||||
NightOfNights.hash = "NightOfNights"
|
||||
NightOfNights.tagline = "The pieces lock down super fast! How long can you survive?"
|
||||
|
||||
function NightOfNights:new()
|
||||
self.super:new()
|
||||
|
||||
self.active_time = 0
|
||||
|
||||
self.randomizer = Bag7NoSZOStartRandomizer()
|
||||
|
||||
self.lock_drop = true
|
||||
self.lock_hard_drop = true
|
||||
self.enable_hold = true
|
||||
self.next_queue_length = 3
|
||||
end
|
||||
|
||||
function NightOfNights:getARE() return 0 end
|
||||
function NightOfNights:getLineARE() return 0 end
|
||||
function NightOfNights:getLineClearDelay() return 0 end
|
||||
function NightOfNights:getDasLimit() return 6 end
|
||||
function NightOfNights:getGravity() return 20 end
|
||||
|
||||
function NightOfNights:whilePieceActive()
|
||||
self.active_time = self.active_time + 1
|
||||
if self.active_time >= 20 then self.piece.locked = true end
|
||||
end
|
||||
|
||||
function NightOfNights:onPieceLock(piece, cleared_row_count)
|
||||
self.super:onPieceLock()
|
||||
self.active_time = 0
|
||||
self.lines = self.lines + cleared_row_count
|
||||
end
|
||||
|
||||
function NightOfNights:drawGrid()
|
||||
self.grid:draw()
|
||||
end
|
||||
|
||||
function NightOfNights:drawScoringInfo()
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
|
||||
love.graphics.setFont(font_3x5_2)
|
||||
love.graphics.print(
|
||||
self.das.direction .. " " ..
|
||||
self.das.frames .. " " ..
|
||||
strTrueValues(self.prev_inputs)
|
||||
)
|
||||
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
||||
love.graphics.printf("LINES", 240, 200, 40, "left")
|
||||
|
||||
love.graphics.setFont(font_3x5_4)
|
||||
love.graphics.printf(self.lines, 240, 220, 90, "left")
|
||||
|
||||
love.graphics.setFont(font_8x11)
|
||||
love.graphics.printf(formatTime(self.frames), 64, 420, 160, "center")
|
||||
end
|
||||
|
||||
function NightOfNights:getBackground()
|
||||
return 19
|
||||
end
|
||||
|
||||
function NightOfNights:getHighscoreData()
|
||||
return {
|
||||
level = self.level,
|
||||
frames = self.frames,
|
||||
}
|
||||
end
|
||||
|
||||
return NightOfNights
|
136
tetris/modes/pro_tl.lua
Normal file
136
tetris/modes/pro_tl.lua
Normal file
@ -0,0 +1,136 @@
|
||||
require 'funcs'
|
||||
|
||||
local MarathonAX4Game = require 'tetris.modes.marathon_ax4'
|
||||
local TetraRandomizer = require 'tetris.randomizers.tetra'
|
||||
|
||||
local ProGame = MarathonAX4Game:extend()
|
||||
|
||||
ProGame.name = "Final TL"
|
||||
ProGame.hash = "ProTL"
|
||||
ProGame.tagline = "Your next pieces start disappearing! What lies past Mach 9?"
|
||||
|
||||
function ProGame:new()
|
||||
self.super:new()
|
||||
self.next_queue_length = 6
|
||||
self.randomizer = TetraRandomizer()
|
||||
end
|
||||
|
||||
function ProGame:getARE() return 6 end
|
||||
function ProGame:getLineARE() return 6 end
|
||||
function ProGame:getLineClearDelay() return 6 end
|
||||
function ProGame:getDasLimit() return 6 end
|
||||
function ProGame:getDropSpeed() return 20 end
|
||||
|
||||
function ProGame:getGravity()
|
||||
if self.lines < 20 then return 1
|
||||
elseif self.lines < 40 then return 3
|
||||
elseif self.lines < 60 then return 5
|
||||
else return 20 end
|
||||
end
|
||||
|
||||
function ProGame:getLockDelay()
|
||||
if self.lines < 20 then return 30
|
||||
elseif self.lines < 40 then return 29
|
||||
elseif self.lines < 60 then return 27
|
||||
elseif self.lines < 80 then return 23
|
||||
elseif self.lines < 100 then return 21
|
||||
elseif self.lines < 120 then return 20
|
||||
elseif self.lines < 140 then return 18
|
||||
elseif self.lines < 160 then return 17
|
||||
elseif self.lines < 180 then return 15
|
||||
else return 14 end
|
||||
end
|
||||
|
||||
function ProGame:advanceOneFrame(inputs, ruleset)
|
||||
if self.clear then
|
||||
self.roll_frames = self.roll_frames + 1
|
||||
if self.roll_frames < 0 then
|
||||
return false
|
||||
elseif self.roll_frames > 2968 then
|
||||
self.completed = true
|
||||
end
|
||||
elseif self.ready_frames == 0 then
|
||||
if not self.section_clear then
|
||||
self.frames = self.frames + 1
|
||||
end
|
||||
if self:getSectionTime() >= self.section_time_limit then
|
||||
self.game_over = true
|
||||
end
|
||||
end
|
||||
|
||||
ruleset.onPieceMove = function() end
|
||||
ruleset.onPieceRotate = function() end
|
||||
|
||||
return true
|
||||
end
|
||||
|
||||
function ProGame:onLineClear(cleared_row_count)
|
||||
if not self.clear then
|
||||
local new_lines = self.lines + cleared_row_count
|
||||
self:updateSectionTimes(self.lines, new_lines)
|
||||
self.lines = math.min(new_lines, 200)
|
||||
if self.lines == 200 then
|
||||
self.grid:clear()
|
||||
self.clear = true
|
||||
self.roll_frames = -150
|
||||
else
|
||||
self.enable_hold = self.lines < 160
|
||||
self.next_queue_length = math.max(1, 6 - math.floor(self.lines / 20))
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function ProGame:updateSectionTimes(old_lines, new_lines)
|
||||
if math.floor(old_lines / 20) < math.floor(new_lines / 20) then
|
||||
-- record new section
|
||||
table.insert(self.section_times, self:getSectionTime())
|
||||
self.section_start_time = self.frames
|
||||
self.section_clear = true
|
||||
end
|
||||
end
|
||||
|
||||
function ProGame:drawGrid()
|
||||
self.grid:draw()
|
||||
self:drawGhostPiece()
|
||||
end
|
||||
|
||||
function ProGame:drawScoringInfo()
|
||||
MarathonAX4Game.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.lines < 200 then love.graphics.printf("TIME LEFT", 240, 250, 80, "left") end
|
||||
love.graphics.printf("LINES", 240, 320, 40, "left")
|
||||
|
||||
local current_section = math.floor(self.lines / 20) + 1
|
||||
self:drawSectionTimesWithSplits(current_section)
|
||||
|
||||
love.graphics.setFont(font_3x5_3)
|
||||
love.graphics.printf(self.lines, 240, 340, 40, "right")
|
||||
love.graphics.printf(self.clear and self.lines or self:getSectionEndLines(), 240, 370, 40, "right")
|
||||
|
||||
-- draw time left, flash red if necessary
|
||||
local time_left = self.section_time_limit - math.max(self:getSectionTime(), 0)
|
||||
if not self.game_over and not self.clear and time_left < frameTime(0,10) and time_left % 4 < 2 then
|
||||
love.graphics.setColor(1, 0.3, 0.3, 1)
|
||||
end
|
||||
if self.lines < 200 then love.graphics.printf(formatTime(time_left), 240, 270, 160, "left") end
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
end
|
||||
|
||||
function ProGame:getSectionEndLines()
|
||||
return math.floor(self.lines / 20 + 1) * 20
|
||||
end
|
||||
|
||||
function ProGame:getBackground()
|
||||
return math.floor(self.lines / 20)
|
||||
end
|
||||
|
||||
return ProGame
|
@ -58,7 +58,7 @@ function Race40Game:getLineARE()
|
||||
end
|
||||
|
||||
function Race40Game:getDasLimit()
|
||||
return 10
|
||||
return 8
|
||||
end
|
||||
|
||||
function Race40Game:getLineClearDelay()
|
||||
|
135
tetris/modes/speed.lua
Normal file
135
tetris/modes/speed.lua
Normal file
@ -0,0 +1,135 @@
|
||||
require 'funcs'
|
||||
|
||||
local GameMode = require 'tetris.modes.gamemode'
|
||||
|
||||
local Bag7Randomizer = require 'tetris.randomizers.bag7'
|
||||
|
||||
local LudicrousSpeed = GameMode:extend()
|
||||
|
||||
LudicrousSpeed.name = "Ludicrous Speed"
|
||||
LudicrousSpeed.hash = "LSpeed"
|
||||
LudicrousSpeed.tagline = "Don't make Keanu sad. Always stay above the speed limit."
|
||||
|
||||
function LudicrousSpeed:new()
|
||||
self.super:new()
|
||||
|
||||
self.time_limit = 301
|
||||
self.pps = {}
|
||||
self.pps_limit = 1
|
||||
self.pieces = 0
|
||||
|
||||
self.randomizer = Bag7Randomizer()
|
||||
|
||||
self.lock_drop = true
|
||||
self.lock_hard_drop = true
|
||||
self.instant_soft_drop = false
|
||||
self.instant_hard_drop = true
|
||||
self.enable_hold = true
|
||||
self.next_queue_length = 3
|
||||
|
||||
self.irs = false
|
||||
self.ihs = false
|
||||
end
|
||||
|
||||
function LudicrousSpeed:getGravity()
|
||||
if self.lines < 180 then
|
||||
return (0.8 - (math.floor(self.lines / 10) * 0.007)) ^ -math.floor(self.lines / 10) / 60
|
||||
else return 20 end
|
||||
end
|
||||
|
||||
function LudicrousSpeed:getARE() return 0 end
|
||||
function LudicrousSpeed:getLineARE() return 0 end
|
||||
function LudicrousSpeed:getLineClearDelay() return 0 end
|
||||
function LudicrousSpeed:getDasLimit() return 8 end
|
||||
function LudicrousSpeed:getDropSpeed() return 20 end
|
||||
|
||||
local function mean(t)
|
||||
local sum = 0
|
||||
local count = 0
|
||||
|
||||
for k, v in pairs(t) do
|
||||
if type(v) == 'number' then
|
||||
sum = sum + v
|
||||
count = count + 1
|
||||
end
|
||||
end
|
||||
|
||||
return (sum / count)
|
||||
end
|
||||
|
||||
function LudicrousSpeed:advanceOneFrame()
|
||||
if self.ready_frames == 0 then
|
||||
self.frames = self.frames + 1
|
||||
if mean(self.pps) * 2 < self.pps_limit then
|
||||
self.time_limit = self.time_limit - 1
|
||||
self.game_over = self.time_limit <= 0
|
||||
else self.time_limit = 301 end
|
||||
if self.frames % 30 == 0 and self.frames ~= 0 then
|
||||
if table.getn(self.pps) == 30 then
|
||||
table.remove(self.pps, 1)
|
||||
table.insert(self.pps, self.pieces)
|
||||
else table.insert(self.pps, self.pieces) end
|
||||
self.pieces = 0
|
||||
--print(table.concat(self.pps, " "))
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function LudicrousSpeed:onPieceLock()
|
||||
self.super:onPieceLock()
|
||||
self.pieces = self.pieces + 1
|
||||
end
|
||||
|
||||
function LudicrousSpeed:onLineClear(cleared_row_count)
|
||||
self.lines = self.lines + cleared_row_count
|
||||
self.pps_limit = 1 + math.floor(self.lines / 10) / 10
|
||||
end
|
||||
|
||||
function LudicrousSpeed:drawGrid()
|
||||
self.grid:draw()
|
||||
self:drawGhostPiece()
|
||||
end
|
||||
|
||||
function LudicrousSpeed:drawScoringInfo()
|
||||
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, 120, 80, "left")
|
||||
love.graphics.printf("piece/sec", text_x, 180, 80, "left")
|
||||
love.graphics.printf("REQUIRED PPS", text_x, 240, 120, "left")
|
||||
|
||||
love.graphics.print(
|
||||
self.das.direction .. " " ..
|
||||
self.das.frames .. " " ..
|
||||
strTrueValues(self.prev_inputs) ..
|
||||
self.drop_bonus
|
||||
)
|
||||
|
||||
love.graphics.setFont(font_3x5_4)
|
||||
if self.time_limit <= 300 then love.graphics.printf(formatTime(self.time_limit), text_x, 320, 160, "left") end
|
||||
|
||||
love.graphics.setFont(font_3x5_3)
|
||||
love.graphics.printf(self.lines, text_x, 140, 80, "left")
|
||||
love.graphics.printf(string.format("%.02f", self.frames > 30 and mean(self.pps) * 2 or 0), text_x, 200, 80, "left")
|
||||
love.graphics.printf(string.format("%.02f", self.pps_limit), text_x, 260, 80, "left")
|
||||
|
||||
love.graphics.setFont(font_8x11)
|
||||
love.graphics.printf(formatTime(self.frames), 64, 420, 160, "center")
|
||||
end
|
||||
|
||||
function LudicrousSpeed:getBackground()
|
||||
return math.floor(self.lines / 10)
|
||||
end
|
||||
|
||||
function LudicrousSpeed:getHighscoreData()
|
||||
return {
|
||||
lines = self.lines,
|
||||
frames = self.frames,
|
||||
}
|
||||
end
|
||||
|
||||
return LudicrousSpeed
|
15
tetris/modes/survival_c88.lua
Normal file
15
tetris/modes/survival_c88.lua
Normal file
@ -0,0 +1,15 @@
|
||||
require 'funcs'
|
||||
|
||||
local MarathonC88Game = require 'tetris.modes.marathon_c88'
|
||||
|
||||
local SurvivalC88Game = MarathonC88Game:extend()
|
||||
|
||||
SurvivalC88Game.name = "Survival C88"
|
||||
SurvivalC88Game.hash = "Shimizu"
|
||||
SurvivalC88Game.tagline = "You can't rotate the pieces initially! What will you do?"
|
||||
|
||||
function SurvivalC88Game:getGravity()
|
||||
return 20
|
||||
end
|
||||
|
||||
return SurvivalC88Game
|
16
tetris/randomizers/fixed_sequence.lua
Normal file
16
tetris/randomizers/fixed_sequence.lua
Normal file
@ -0,0 +1,16 @@
|
||||
local Randomizer = require 'tetris.randomizers.randomizer'
|
||||
|
||||
local Sequence = Randomizer:extend()
|
||||
|
||||
function Sequence:initialize()
|
||||
self.sequence = "IJLOT"
|
||||
self.counter = 0
|
||||
end
|
||||
|
||||
function Sequence:generatePiece()
|
||||
local piece = string.sub(self.sequence, self.counter + 1, self.counter + 1)
|
||||
self.counter = (self.counter + 1) % string.len(self.sequence)
|
||||
return piece
|
||||
end
|
||||
|
||||
return Sequence
|
10
tetris/randomizers/kamui_sequence.lua
Normal file
10
tetris/randomizers/kamui_sequence.lua
Normal file
@ -0,0 +1,10 @@
|
||||
local Sequence = require 'tetris.randomizers.fixed_sequence'
|
||||
|
||||
local KamuiSequence = Sequence:extend()
|
||||
|
||||
function KamuiSequence:initialize()
|
||||
self.super:initialize()
|
||||
self.sequence = "JISTZOSJITOZLISTJLOSZTJOILZJOITZJLISZTLJIOZLSTJZLSOTJLIZSTJOLISTZJOLTZSOJLZIOJSLZTJSIZOJTLSIJTLZSOJTZSLIOZSJLTZOISTZLOJTZILOSTIJOLSTIZLJOTZILSJZTOSIZJOLTISJZOLITSJZLTSOJLTZOJISTZLOSIZJTSIOZLSJIZTLJIZTLSJZILOTJZLOISZJLOTSJIZTOLSZJITSOZITSLJOTSLJOZITJOZLSTIOJSTLOIJTSOZILTSOJZILSOTZLSJTIZSJOTILZJOISLJZITLOZJTILSJTIZOJTIZOLJTSOZJTSILJZTSOIZJSTOIJLZTIJOLSISOJTLZOIJLTZOILSSJTOZILSOTZLSJIOLZJTSOIJZTSOJLISTZLIOJTZSSOLIZSTJOSLTIZSJLOTZISLJOTZLJOSTZJIOLSTIZOSLJZISOJLIZTOJILZOJILTOJISZOTJTIOSZTLJSZOITLZOJSILZJOILJZOISJTLOZSJIOLJSZTLISJOZLISOJZILOSTILOTJSLZITSOJITLZSJTIZOLJISTOJILZSTOILZSJOTISLOZJITOLZJSILOZSIJLZTSOJZLTIJSLTIZJLOSTJZLSIOTJZLOSOTSLIOZSTJOILSZTJLOZSTILZSOJITLZSIJTOLZSTJOZSLJIZSOJLZITJSLZOJTLSOIZJSOSLTZOSSTLZOIJSTOZILJSOSTIJLSOTJLSOTIJSZOLTSJZLOSJTZILOTSZLOITZSJITLZJIOSZTLIJOSLIZTOLIZTJLSZOTJLSOTZJIOSZTJTOSZIJTSOIZJLSOSILJTZOIJSTIJLTOSZJLOTSIZOLSTJIOJZTILSOJZTILJZSOSITLZSOTJIZOSLJTOSZLITSJLIZTOLSIZOJTSZOJTLZSJTOILZJTSLZJTISLZTJISOLZTSIOLJTZIOJSLTIJZSTLJIOTSLZJITLOJIZLZSOIJLZOTSSJZTIO"
|
||||
end
|
||||
|
||||
return KamuiSequence
|
72
tetris/randomizers/tetra.lua
Normal file
72
tetris/randomizers/tetra.lua
Normal file
@ -0,0 +1,72 @@
|
||||
-- A randomizer based on Tetra Legends' "Tetra-X" game mode
|
||||
-- There are two main rules:
|
||||
-- * if piece hasn't been generated for 13+ pieces, force it
|
||||
-- * if piece has been generated in the last two pieces, don't give it out
|
||||
--
|
||||
-- The official implementation also has self-balancing functionality (bias
|
||||
-- towards pieces that have appeared less often).
|
||||
|
||||
local Randomizer = require 'tetris.randomizers.randomizer'
|
||||
|
||||
local TetraXRandomizer = Randomizer:extend()
|
||||
|
||||
function TetraXRandomizer:initialize()
|
||||
local pieces = {"I", "J", "L", "O", "S", "T", "Z"}
|
||||
|
||||
self.count = {}
|
||||
self.lastseen = {}
|
||||
self.totalcount = 0
|
||||
self.pieceselection = pieces
|
||||
|
||||
for _, piece in ipairs(pieces) do
|
||||
self.count[piece] = 0
|
||||
self.lastseen[piece] = -1 -- use -1 as magic value for "not seen"
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function TetraXRandomizer:generatePiece()
|
||||
local generated = nil
|
||||
while true do
|
||||
generated = self.pieceselection[math.random(#self.pieceselection)]
|
||||
if not (self.lastseen[generated] == 0 or self.lastseen[generated] == 1) then
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
-- piece has not been generated in the last 13+
|
||||
for piece, val in pairs(self.lastseen) do
|
||||
if val >= 13 then
|
||||
generated = piece
|
||||
break
|
||||
end
|
||||
end
|
||||
|
||||
for piece, val in pairs(self.lastseen) do
|
||||
if piece == generated then
|
||||
self.lastseen[piece] = 0
|
||||
else
|
||||
if val ~= -1 then
|
||||
self.lastseen[piece] = val + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
self.count[generated] = self.count[generated] + 1
|
||||
self.totalcount = self.totalcount + 1
|
||||
|
||||
-- shuffle the piece selection for the next time
|
||||
self.pieceselection = {}
|
||||
for piece, count in pairs(self.count) do
|
||||
-- in this case 6 = #piece types - 1, so all probabilities sum to 1
|
||||
local probability = (self.totalcount - count) / (self.totalcount * 6)
|
||||
local chances = math.floor(probability * 1000 + 0.5) -- simulated "round"
|
||||
for _ = 1, chances do
|
||||
table.insert(self.pieceselection, piece)
|
||||
end
|
||||
end
|
||||
|
||||
return generated
|
||||
end
|
||||
|
||||
return TetraXRandomizer
|
147
tetris/rulesets/bonkers.lua
Normal file
147
tetris/rulesets/bonkers.lua
Normal file
@ -0,0 +1,147 @@
|
||||
local Ruleset = require "tetris.rulesets.ruleset"
|
||||
|
||||
local BONKERS = Ruleset:extend()
|
||||
|
||||
BONKERS.name = "B.O.N.K.E.R.S."
|
||||
BONKERS.hash = "Bonkers"
|
||||
BONKERS.world = true
|
||||
|
||||
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.colourscheme = {
|
||||
I = "G",
|
||||
J = "G",
|
||||
L = "G",
|
||||
O = "G",
|
||||
S = "G",
|
||||
T = "G",
|
||||
Z = "G",
|
||||
}
|
||||
|
||||
BONKERS.softdrop_lock = false
|
||||
BONKERS.harddrop_lock = true
|
||||
BONKERS.enable_IRS_wallkicks = true
|
||||
|
||||
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:attemptRotate(new_inputs, piece, grid, initial)
|
||||
local rot_dir = 0
|
||||
|
||||
if (new_inputs["rotate_left"] or new_inputs["rotate_left2"]) then
|
||||
rot_dir = 3
|
||||
elseif (new_inputs["rotate_right"] or new_inputs["rotate_right2"]) then
|
||||
rot_dir = 1
|
||||
elseif (new_inputs["rotate_180"]) then
|
||||
rot_dir = self:get180RotationValue()
|
||||
end
|
||||
|
||||
if rot_dir == 0 then return end
|
||||
if config.gamesettings.world_reverse == 3 or (self.world and config.gamesettings.world_reverse == 2) then
|
||||
rot_dir = 4 - rot_dir
|
||||
end
|
||||
|
||||
local new_piece = piece:withRelativeRotation(rot_dir)
|
||||
|
||||
if (grid:canPlacePiece(new_piece)) then
|
||||
if piece:isDropBlocked(grid) then
|
||||
self:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||
else
|
||||
piece:setRelativeRotation(rot_dir)
|
||||
self:onPieceRotate(piece, grid)
|
||||
end
|
||||
else
|
||||
if not(initial and self.enable_IRS_wallkicks == false) then
|
||||
self:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function BONKERS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||
|
||||
if piece.shape == "I" then
|
||||
horizontal_kicks = {0, 1, -1, 2, -2}
|
||||
else
|
||||
horizontal_kicks = {0, 1, -1}
|
||||
end
|
||||
|
||||
for y_offset = 24, -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
|
@ -115,8 +115,8 @@ function CRAP:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||
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)
|
||||
piece:setRelativeRotation(rot_dir):setOffset({x=dx, y=dy})
|
||||
return
|
||||
end
|
||||
end
|
||||
|
@ -27,9 +27,9 @@ function Cultris:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||
for idx, offset in pairs(kicks) do
|
||||
kicked_piece = new_piece:withOffset(offset)
|
||||
if grid:canPlacePiece(kicked_piece) then
|
||||
self:onPieceRotate(piece, grid)
|
||||
piece:setRelativeRotation(rot_dir)
|
||||
piece:setOffset(offset)
|
||||
self:onPieceRotate(piece, grid)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
@ -32,22 +32,22 @@ DTET.big_spawn_positions = {
|
||||
|
||||
DTET.block_offsets = {
|
||||
I={
|
||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} },
|
||||
{ {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=0, y=1} },
|
||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} },
|
||||
{ {x=-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} },
|
||||
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=1, y=0} },
|
||||
{ {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=-1, y=0} },
|
||||
},
|
||||
L={
|
||||
{ {x=0, y=-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} },
|
||||
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=-1, y=0} },
|
||||
{ {x=0, y=-1}, {x=-1, y=-2}, {x=0, y=-2}, {x=0, y=0} },
|
||||
},
|
||||
O={
|
||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
|
||||
@ -62,10 +62,10 @@ DTET.block_offsets = {
|
||||
{ {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} },
|
||||
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=0, y=0} },
|
||||
{ {x=0, y=-1}, {x=0, y=0}, {x=-1, y=-1}, {x=0, y=-2} },
|
||||
},
|
||||
Z={
|
||||
{ {x=1, y=0}, {x=0, y=0}, {x=0, y=-1}, {x=-1, y=-1} },
|
||||
@ -75,64 +75,18 @@ DTET.block_offsets = {
|
||||
}
|
||||
}
|
||||
|
||||
-- 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}},
|
||||
},
|
||||
};
|
||||
DTET.wallkicks_cw = {{x=1, y=0}, {x=-1, y=0}, {x=0, y=1}, {x=1, y=1}, {x=-1, y=1}}
|
||||
DTET.wallkicks_ccw = {{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
|
||||
if piece.shape == "O" then
|
||||
return
|
||||
elseif piece.shape == "I" then
|
||||
kicks = DTET.wallkicks_line[piece.rotation][new_piece.rotation]
|
||||
elseif rot_dir == 1 then
|
||||
kicks = DTET.wallkicks_cw
|
||||
else
|
||||
kicks = DTET.wallkicks_3x3[piece.rotation][new_piece.rotation]
|
||||
kicks = DTET.wallkicks_ccw
|
||||
end
|
||||
|
||||
assert(piece.rotation ~= new_piece.rotation)
|
||||
@ -140,18 +94,19 @@ function DTET:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||
for idx, offset in pairs(kicks) do
|
||||
kicked_piece = new_piece:withOffset(offset)
|
||||
if grid:canPlacePiece(kicked_piece) then
|
||||
self:onPieceRotate(piece, grid)
|
||||
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
|
||||
function DTET:getDefaultOrientation() return 3 end
|
||||
|
||||
return DTET
|
@ -37,8 +37,8 @@ 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)
|
||||
piece:setRelativeRotation(rot_dir):setOffset({x=dx, y=0})
|
||||
end
|
||||
end
|
||||
|
||||
|
@ -90,9 +90,9 @@ function PPTPRS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||
for idx, offset in pairs(kicks) do
|
||||
kicked_piece = new_piece:withOffset(offset)
|
||||
if grid:canPlacePiece(kicked_piece) then
|
||||
self:onPieceRotate(piece, grid)
|
||||
piece:setRelativeRotation(rot_dir)
|
||||
piece:setOffset(offset)
|
||||
self:onPieceRotate(piece, grid)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
23
tetris/rulesets/segaccw.lua
Normal file
23
tetris/rulesets/segaccw.lua
Normal file
@ -0,0 +1,23 @@
|
||||
local ARS = require 'tetris.rulesets.arika'
|
||||
|
||||
local Sega = ARS:extend()
|
||||
|
||||
Sega.name = "Sega CCW"
|
||||
Sega.hash = "SegaCCW"
|
||||
|
||||
function Sega:attemptRotate(new_inputs, piece, grid)
|
||||
local rot_dir = 0
|
||||
|
||||
if new_inputs["rotate_left"] or new_inputs["rotate_left2"] or
|
||||
new_inputs["rotate_right"] or new_inputs["rotate_right2"] or
|
||||
new_inputs["rotate_180"] then rot_dir = 3 end
|
||||
|
||||
local new_piece = piece:withRelativeRotation(rot_dir)
|
||||
|
||||
if (grid:canPlacePiece(new_piece)) then
|
||||
self:onPieceRotate(piece, grid)
|
||||
piece:setRelativeRotation(rot_dir)
|
||||
end
|
||||
end
|
||||
|
||||
return Sega
|
76
tetris/rulesets/srs_o_spin.lua
Normal file
76
tetris/rulesets/srs_o_spin.lua
Normal file
@ -0,0 +1,76 @@
|
||||
local SRS = require 'tetris.rulesets.standard_exp'
|
||||
|
||||
local OSpin = SRS:extend()
|
||||
|
||||
OSpin.name = "SRS O-Spin"
|
||||
OSpin.hash = "OSpin"
|
||||
|
||||
OSpin.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=-1, y=0}, {x=-2, y=0}, {x=-2, y=-1}, {x=-1, y=-1} },
|
||||
{ {x=-1, y=-1}, {x=-2, y=-1}, {x=-2, y=-2}, {x=-1, y=-2} },
|
||||
{ {x=0, y=-1}, {x=-1, y=-1}, {x=-1, y=-2}, {x=0, y=-2} },
|
||||
},
|
||||
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} },
|
||||
}
|
||||
}
|
||||
|
||||
function OSpin:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||
|
||||
local kicks
|
||||
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
|
||||
|
||||
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
|
||||
self:onPieceRotate(piece, grid)
|
||||
piece:setRelativeRotation(rot_dir)
|
||||
piece:setOffset(offset)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
return OSpin
|
@ -1,159 +1,23 @@
|
||||
local Piece = require 'tetris.components.piece'
|
||||
local Ruleset = require 'tetris.rulesets.ruleset'
|
||||
local Ruleset = require 'tetris.rulesets.ti_srs'
|
||||
|
||||
local SRS = Ruleset:extend()
|
||||
|
||||
SRS.name = "SRS-X"
|
||||
SRS.hash = "Reversed SRS drop functions"
|
||||
SRS.world = true
|
||||
SRS.softdrop_lock = true
|
||||
SRS.harddrop_lock = false
|
||||
|
||||
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.colourscheme = {
|
||||
I = "R",
|
||||
L = "O",
|
||||
J = "B",
|
||||
S = "M",
|
||||
Z = "G",
|
||||
O = "Y",
|
||||
T = "C",
|
||||
}
|
||||
|
||||
SRS.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 },
|
||||
}
|
||||
|
||||
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= 1, y=-2}, {x=-2, y= 1}},
|
||||
[2]={},
|
||||
[3]={{x= 2, y= 0}, {x=-1, 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]={},
|
||||
},
|
||||
[2]={
|
||||
[0]={},
|
||||
[1]={{x=-2, y= 0}, {x= 1, y= 0}, {x=-2, y=-1}, {x= 1, y= 1}},
|
||||
[3]={{x= 2, y= 0}, {x=-1, y= 0}, {x= 2, y=-1}, {x=-1, y= 1}},
|
||||
},
|
||||
[3]={
|
||||
[0]={{x=-2, y= 0}, {x= 1, y= 0}, {x=-2, y=-1}, {x= 1, y= 2}},
|
||||
[1]={},
|
||||
[2]={{x= 1, y= 0}, {x=-2, y= 0}, {x= 1, y=-2}, {x=-2, y= 1}},
|
||||
},
|
||||
};
|
||||
|
||||
-- Component functions.
|
||||
|
||||
function SRS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||
|
||||
local kicks
|
||||
if piece.shape == "O" then
|
||||
return
|
||||
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
|
||||
|
||||
function SRS:onPieceCreate(piece, grid)
|
||||
piece.manipulations = 0
|
||||
piece.rotations = 0
|
||||
end
|
||||
|
||||
function SRS:onPieceDrop(piece, grid)
|
||||
piece.lock_delay = 0 -- step reset
|
||||
end
|
||||
|
||||
function SRS:onPieceMove(piece, grid)
|
||||
piece.lock_delay = 0 -- move reset
|
||||
if piece:isDropBlocked(grid) then
|
||||
|
@ -77,9 +77,9 @@ function Tetra:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||
for idx, offset in pairs(kicks) do
|
||||
kicked_piece = new_piece:withOffset(offset)
|
||||
if grid:canPlacePiece(kicked_piece) then
|
||||
self:onPieceRotate(piece, grid)
|
||||
piece:setRelativeRotation(rot_dir)
|
||||
piece:setOffset(offset)
|
||||
self:onPieceRotate(piece, grid)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
@ -103,9 +103,9 @@ function TheNext:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||
for idx, offset in pairs(kicks) do
|
||||
kicked_piece = new_piece:withOffset(offset)
|
||||
if grid:canPlacePiece(kicked_piece) then
|
||||
self:onPieceRotate(piece, grid)
|
||||
piece:setRelativeRotation(rot_dir)
|
||||
piece:setOffset(offset)
|
||||
self:onPieceRotate(piece, grid)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
Loading…
Reference in New Issue
Block a user