--[[ Blitz Mode Design by MattMayuga Spaghetti code by terpyderp Music from Bejeweled Twist HSV to RGB code copied from https://gist.github.com/GigsD4X/8513963 because I'm lazy and stupid lol. ]]-- require 'funcs' local GameMode = require 'tetris.modes.gamemode' local Piece = require 'tetris.components.piece' local Bag7Randomiser = require 'tetris.randomizers.bag7noSZOstart' local Blitz = GameMode:extend() sounds.blitz = { multi_up = love.audio.newSource("res/se/multiplier_up.wav", "static") } bgm.blitz = { blitz = love.audio.newSource("res/bgm/blitz.mp3", "stream"), } Blitz.name = "Blitz" Blitz.hash = "Blitz" Blitz.tagline = "How many points can you get in 5 minutes? Do cool tricks, get All Clears, increase your score multiplier and bring your best game to reach higher speed levels and gain more points in this action-packed mode!" local scoreTable = { 250, -- Single 750, 1250, 2000, -- Quadruple 3750, -- Quintuple 1000, -- T-Spin Zero 2000, 3000, 4000, -- T-Spin Triple 250, -- T-Spin Mini Zero 750, 1000, -- T-Spin Mini Double 2000, -- All Clear Single 3000, 4500, 5000, 6000, -- All Clear Quintuple 8000, -- B2B AC Quadruple 9000 -- B2B AC Quintuple } local chainActions = { 3, 4, 6, 8, 10, 10, 10, 10, 10, 10, 10 } local SRSTPiece = { { {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} }, } local ARSTPiece = { { {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} }, } function Blitz:new() Blitz.super:new() self.lines = 0 self.frames = 18000 self.pieces = 0 self.roll_frames = 0 self.upstacked = false self.activeTime = 0 self.framesButBackwards = 0 -- blitz mode variables self.score = 0 self.b2b = 0 self.b2bMulti = 1 self.multi = 1 self.chain = 0 self.lastLineCount = 4 self.lastPieceTime = 0 self.rainbowMode = 0 -- 0 = not started, 1 = active, 2 = finished self.tSpin = 0 -- 0 = none, 1 = normal, 2 = mini self.randomizer = Bag7Randomiser() 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 = 5 self.immobile_spin_bonus = true end function Blitz:getDropSpeed() return 20 end function Blitz:getARR() return config.arr end function Blitz:getARE() return 0 end function Blitz:getLineARE() return self:getARE() end function Blitz:getDasLimit() return config.das end function Blitz:getLineClearDelay() return 0 end function Blitz:getLockDelay() return 30 end function Blitz:getGravity() return 1/64 end function Blitz:getDasCutDelay() return config.dcd end function Blitz:getBackground() return 3 end function Blitz:advanceOneFrame() if self.ready_frames == 0 then if self.frames == 18000 then switchBGM("blitz", "blitz") end end if self.clear then self.roll_frames = self.roll_frames + 1 if self.roll_frames > 360 then self.completed = true end return false elseif self.ready_frames == 0 then self.frames = self.frames - 1 if self.frames <= 0 then self.clear = true end end self.framesButBackwards = self.framesButBackwards + 1 return true end function Blitz:onPieceLock(piece, cleared_row_count) self.super:onPieceLock() self.pieces = self.pieces + 1 allClear = self.grid:checkForBravo(cleared_row_count) -- detect what kind of T piece the ruleset has (either 0-SRS, 1-ARS, or 2-idk) (pain) if piece.shape == "T" then SRS = true for i,v in ipairs(self.ruleset.block_offsets.T) do -- for every rotation of the T for ii,vv in ipairs(v) do -- for every block in the T if #(v) == 4 then if vv.x ~= SRSTPiece[i][ii].x and vv.y ~= SRSTPiece[i][ii].y then SRS = false break end else SRS = false break end end end if SRS then self.rulesetType = 0 else ARS = true for i,v in ipairs(self.ruleset.block_offsets.T) do -- for every rotation of the T for ii,vv in ipairs(v) do -- for every block in the T if #(v) == 4 then if vv.x ~= ARSTPiece[i][ii].x and vv.y ~= ARSTPiece[i][ii].y then ARS = false break end else ARS = false break end end end if ARS then self.rulesetType = 1 else self.rulesetType = 2 end end end -- 4-corner T-Spin detection (also pain) if self.rulesetType == 2 then -- just be lazy and do immobile if it's not SRS or ARS if self.piece.spin and self.piece.shape == "T" then self.tSpin = 1 else self.tSpin = 0 end else if self.rulesetType == 0 then tempYOffset = 0 else tempYOffset = -1 end if piece.shape == "T" and piece.last_rotated then topCount = 0 bottomCount = 0 if self.grid:isOccupied(piece.position.x+1, piece.position.y+1) then if piece.rotation <= 1 then bottomCount = bottomCount + 1 else topCount = topCount + 1 end end if self.grid:isOccupied(piece.position.x+1, piece.position.y-1+tempYOffset) then if piece.rotation <= 1 then topCount = topCount + 1 else bottomCount = bottomCount + 1 end end if self.grid:isOccupied(piece.position.x-1, piece.position.y+1+tempYOffset) then if piece.rotation == 1 or piece.rotation == 2 then topCount = topCount + 1 else bottomCount = bottomCount + 1 end end if self.grid:isOccupied(piece.position.x-1, piece.position.y-1+tempYOffset) then if piece.rotation == 1 or piece.rotation == 2 then bottomCount = bottomCount + 1 else topCount = topCount + 1 end end if topCount == 2 and bottomCount >= 1 then self.tSpin = 1 -- normal elseif topCount == 1 and bottomCount == 2 then self.tSpin = 2 -- mini else self.tSpin = 0 -- none end else self.tSpin = 0 end end -- updates the multiplier for back to back if self.b2b > 0 then self.b2bMulti = 1.5 else self.b2bMulti = 1 end -- updates the score -- if it's a T spin if self.tSpin == 1 then self.score = self.score + scoreTable[cleared_row_count+6] * self.b2bMulti * self.multi -- if it's a T spin mini elseif self.tSpin == 2 then self.score = self.score + scoreTable[cleared_row_count+10] * self.b2bMulti * self.multi -- if it's an all clear elseif self.grid:checkForBravo(cleared_row_count) then if self.b2b > 0 and cleared_row_count >= 4 then self.score = self.score + scoreTable[cleared_row_count+14] * self.multi else self.score = self.score + scoreTable[cleared_row_count+12] * self.multi end -- if it's a quad or quin elseif cleared_row_count >= 4 then self.score = self.score + scoreTable[cleared_row_count] * self.b2bMulti * self.multi -- if it's none of the above and it clears at least one line elseif cleared_row_count > 0 then self.score = self.score + scoreTable[cleared_row_count] * self.multi end -- raises the chain count if necessary -- if it's an all clear if allClear then self.chain = self.chain + 12 -- if at least 4 lines are cleared or it's a T-Spin elseif self.tSpin ~= 0 or cleared_row_count >= 4 then if self.b2b > 10 then self.chain = self.chain + 2 else self.chain = self.chain + 1 end -- if 3 lines are cleared elseif cleared_row_count >= 3 then self.chain = self.chain + 1 end -- decreases the multiplier or chain meter if necessary if self.lastLineCount < 3 and (cleared_row_count < 3 and cleared_row_count ~= 0) and not allClear then if self.chain < 1 then if self.multi > 1 then self.multi = self.multi - 1 self.rainbowMode = 0 end else if self.rainbowMode == 2 then self.rainbowMode = 0 self.multi = 9 end self.chain = 0 end elseif self.lastPieceTime >= 180 and self.activeTime >= 180 and self.multi > 1 then self.multi = self.multi - 1 end -- increases the multiplier if necessary if self.multi < 10 then while self.chain >= chainActions[self.multi] do self.chain = self.chain - chainActions[self.multi] self.multi = self.multi + 1 playSE("blitz", "multi_up") end elseif self.rainbowMode == 0 then if self.chain >= chainActions[10] then self.rainbowMode = 1 self.chain = self.chain - chainActions[10] playSE("blitz", "multi_up") end elseif self.rainbowMode == 1 then if self.chain >= chainActions[11] then self.score = self.score + 300000 self.chain = 10 self.rainbowMode = 2 playSE("blitz", "multi_up") end end -- updates back to back if self.tSpin ~= 0 or cleared_row_count >= 4 then self.b2b = self.b2b + 1 elseif cleared_row_count > 0 and cleared_row_count < 4 then self.b2b = 0 end -- print("chain: " .. tostring(self.chain) .. " multiplier: " .. tostring(self.multi) .. " rainbow mode: " .. tostring(self.rainbowMode) .. " lastLineCount: " .. tostring(self.lastLineCount)) -- update some other stuff self.lastPieceTime = self.activeTime self.activeTime = 0 if self.tSpin ~= 0 then self.lastLineCount = 4 -- if it works it's not stupid right? elseif cleared_row_count ~= 0 then self.lastLineCount = cleared_row_count end if self.rainbowMode == 2 then self.chain = chainActions[11] end end function Blitz:onLineClear(cleared_row_count) if not self.clear then self.lines = self.lines + cleared_row_count end end function Blitz:drawGrid(ruleset) self.grid:draw() if self.piece ~= nil then self:drawGhostPiece(ruleset) end end function Blitz:getHighscoreData() return { level = self.level, frames = self.frames, } end function Blitz:drawScoringInfo() love.graphics.setColor(1, 1, 1, 1) if config["side_next"] then love.graphics.printf("NEXT", 240, 72, 40, "left") else love.graphics.printf("NEXT", 64, 40, 40, "left") end local text_x = config["side_next"] and 316 or 240 love.graphics.setFont(font_3x5_2) love.graphics.printf("SCORE", text_x, 72, 80, "left") love.graphics.printf("PPS", text_x, 132, 80, "left") love.graphics.printf("LINES", text_x, 192, 40, "left") love.graphics.setFont(font_3x5_3) love.graphics.printf(self.score, text_x, 92, 80, "left") love.graphics.printf(string.format("%.04f", self.pieces / math.max(1, self.framesButBackwards) * 60), text_x, 152, 80, "left") love.graphics.printf(math.max(0, self.lines), text_x, 212, 40, "left") -- draw chain meter if self.rainbowMode == 1 then self.red, self.green, self.blue = Blitz:HSVToRGB(((-self.frames+180000)*2)%360, 1, 1) else self.red, self.green, self.blue = Blitz:HSVToRGB((-self.multi*36)+395, 1, 1) end love.graphics.setColor(self.red/4, self.blue/4, self.green/4) love.graphics.rectangle("fill", 240, 382, 160, 24) love.graphics.setColor(self.red, self.blue, self.green) love.graphics.rectangle("fill", 240, 382, (self.chain/chainActions[self.multi])*160, 24) love.graphics.setColor(0, 0, 0) love.graphics.setLineWidth(4) love.graphics.rectangle("line", 240, 382, 160, 24) love.graphics.setColor(1, 1, 1, 1) love.graphics.setFont(font_3x5_2) love.graphics.printf(tostring(self.chain) .. " / " .. tostring(chainActions[self.multi]), 240, 412, 160, "center") -- draw multiplier love.graphics.setFont(font_3x5_3) love.graphics.printf("MULTI: X" .. tostring(self.multi), 240, 352, 400, "left") love.graphics.setColor(1, 1, 1, 1) end function Blitz:whilePieceActive() self.activeTime = self.activeTime + 1 end -- copied from https://gist.github.com/GigsD4X/8513963 function Blitz:HSVToRGB( hue, saturation, value ) -- Returns the RGB equivalent of the given HSV-defined color -- (adapted from some code found around the web) -- If it's achromatic, just return the value if saturation == 0 then return value, value, value; end; -- Get the hue sector local hue_sector = math.floor( hue / 60 ); local hue_sector_offset = ( hue / 60 ) - hue_sector; local p = value * ( 1 - saturation ); local q = value * ( 1 - saturation * hue_sector_offset ); local t = value * ( 1 - saturation * ( 1 - hue_sector_offset ) ); if hue_sector == 0 then return value, t, p; elseif hue_sector == 1 then return q, value, p; elseif hue_sector == 2 then return p, value, t; elseif hue_sector == 3 then return p, q, value; elseif hue_sector == 4 then return t, p, value; elseif hue_sector == 5 then return value, p, q; end; end; return Blitz