Official Public Relase

pull/13/head
Xx-Henry-xX 2023-03-02 18:03:57 +09:00
parent f2be04f269
commit 515540d84f
1 changed files with 569 additions and 0 deletions

View File

@ -0,0 +1,569 @@
require 'funcs'
local GameMode = require 'tetris.modes.gamemode'
local Piece = require 'tetris.components.piece'
local Bag7NoSZOStartRandomizer = require 'tetris.randomizers.bag7noSZOstart'
local HighStackerGame = GameMode:extend()
HighStackerGame.name = "High Stacker"
HighStackerGame.hash = "HighStacker"
HighStackerGame.tagline = "Play risky on the higher fields and don't be a chicken!"
--Official Release v1.0
--Concept & Coding by Xx_Henry_xX (Xx_Henry_xX#0296)
--Code mostly & shamelessly stolen from...
--Marathon A2 / A3
--Survival 2020
--[[
changelog
Official Release v1.0
-2'-ALL ending appearing on other ALLs fixed
-transition bug is fixed AT LAST!!!!!!!!!!!!!
Official Release v0.2
-null piece bug fixed
-some pointless bool == bool stuffs edited
Official Release v0.1
-total delay is now ura loop 2 exclusive
-edited total delay values
-end of game bonus details added
-2'-ALL ending added
-roll bgm added
Discord Beta v2.0
-scoring rehaul (mostly on REN)
-slot is gone
-current section score & section cool requirement display added
Discord Beta v1.2
-adjusted section cool cutoffs and ura 2nd loop cutoff
-fixed end of game bonus being given endlessly (kudos 2 infinifen#1129)
Discord Beta v1.1
-bugfixes on section score text color
-end of game bonus added
Discord Beta v1.0
-initial semi-public release
]]
function HighStackerGame:new()
HighStackerGame.super:new()
self.roll_frames = 0
self.combo = 0
self.randomizer = Bag7NoSZOStartRandomizer()
self.grade = 0
self.grade_points = 0
self.grade_point_decay_counter = 0
self.section_start_score = 0
self.section_scores = { [0] = 0 }
self.loop = 0 --0 == loop 1 / 1 == omote / 2 == ura
self.total_lines = 0
self.section_cools = 0
self.cool_timer = 0
self.ground_touched = false
self.total_delay = 300
self.show_loop = false
self.actually_cue_the_rolls = false
self.ren_on = false
self.line_details = { }
self.line_details_second = { }
self.detail_timer = 0
self.ending = 0
self.clear_bonus_given = false
--debug
--[[
self.level = 499
self.section_cools = 4
self.score = 50000000
self.section_scores = {
[0] = 10000000,
[1] = 10000000,
[2] = 10000000,
[3] = 10000000
}
]]
self.additive_gravity = false
self.lock_drop = false
self.lock_hard_drop = false
self.enable_hold = true
self.next_queue_length = 3
end
function HighStackerGame:getARE()
if self.level < 700 then return 27
elseif self.level < 800 then return 18
else return 14 end
end
function HighStackerGame:getLineARE()
if self.level < 600 then return 27
elseif self.level < 700 then return 18
elseif self.level < 800 then return 14
else return 8 end
end
function HighStackerGame:getDasLimit()
if self.level < 500 then return 15
elseif self.level < 900 then return 9
else return 7 end
end
function HighStackerGame:getLineClearDelay()
if self.level < 500 then return 40
elseif self.level < 600 then return 25
elseif self.level < 700 then return 16
elseif self.level < 800 then return 12
else return 6 end
end
function HighStackerGame:getLockDelay()
if self.level < 900 then return 30
else return 17 end
end
function HighStackerGame: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 HighStackerGame:getTotalDelay()
if self.loop ~= 2 then return 300
elseif self.level < 530 then return 270
elseif self.level < 600 then return 240
elseif self.level < 700 then return 210
elseif self.level < 800 then return 180
elseif self.level < 900 then return 150
else return 120 end
end
function HighStackerGame:advanceOneFrame()
if self.clear then
self.roll_frames = self.roll_frames + 1
if not self.actually_cue_the_rolls then
if self.roll_frames < -120 then
return false
elseif self.roll_frames >= 0 then
if self.loop ~= 0 then
self.clear = false
self.ready_frames = 100
self.show_loop = true
end
return true
end
return false
elseif self.roll_frames < 0 then
if self.roll_frames + 1 == 0 then
switchBGM("credit_roll", "gm3")
end
return false
elseif self.roll_frames > 3701 then
self.completed = true
switchBGM(nil)
end
elseif self.ready_frames == 0 then
self.frames = self.frames + 1
if self.piece ~= nil then
if self.ground_touched and self.loop == 2 then
self.total_delay = self.total_delay + 1
if self.total_delay >= self:getTotalDelay() and self.piece:isDropBlocked(self.grid) then
self.piece.locked = true
end
elseif self.piece:isDropBlocked(self.grid) then self.ground_touched = true end
end
end
if self.detail_timer > 0 then
self.detail_timer = self.detail_timer - 1
end
return true
end
function HighStackerGame:onPieceEnter()
self.total_delay = 0
self.ground_touched = false
if (self.level % 100 ~= 99) and not self.clear and self.frames ~= 0 and not self.ren_on then
self.level = self.level + 1
end
end
local line_count_multiplier = {1, 2, 4, 6}
local line_position_score = {
15000,
15000,
15000,
15000, --lowest off-field row
15000,
10000,
9000,
8000,
7000,
6000,
5000,
4000,
3000,
2000,
1000,
900,
800,
700,
600,
500,
40,
30,
20,
10
}
function HighStackerGame:updateScore(level, drop_bonus, cleared_lines)
local ae, cleared_lines_table = self.grid:getClearedRowCount()
self.total_lines = self.total_lines + cleared_lines
if cleared_lines > 0 then
self.detail_timer = 120
self.line_details = { }
self.line_details_second = { }
local basescore = self.combo
local levelscore = self.level * 10
table.insert(self.line_details_second, levelscore)
if basescore > 0 then
table.insert(self.line_details_second, basescore)
self.ren_on = true
end
if self.loop == 1 then levelscore = levelscore - 5000 end
basescore = basescore + levelscore
for key, pos in ipairs(cleared_lines_table) do
basescore = basescore + line_position_score[pos]
table.insert(self.line_details, line_position_score[pos])
end
self.score = self.score + basescore * line_count_multiplier[cleared_lines]
self.combo = basescore
else
self.combo = 0
self.ren_on = false
end
self.drop_bonus = 0
if self.clear then self.lines = self.lines + cleared_lines end --reminder that this is for roll lines
end
function HighStackerGame:onLineClear(cleared_row_count)
if self.ren_on == false then
self:updateSectionScores(self.level, self.level + cleared_row_count)
self.level = math.min(self.level + cleared_row_count, 1000)
end
if self.level >= 500 and not self.clear and self.loop == 0 then
self.level = 500
self.clear = true
self.grid:clear()
self.roll_frames = -150
if self:nextloopcheck() then
self.roll_frames = self.roll_frames - 120
self.lcd = 0
self.are = 0
else
self.actually_cue_the_rolls = true
end
elseif self.level == 1000 and not self.clear then
self.clear = true
self.grid:clear()
self.actually_cue_the_rolls = true
self.roll_frames = -150
end
self.lock_drop = self.level >= 900
self.lock_hard_drop = self.level >= 900
end
local lowest_section_cool_cutoff = 800000
function HighStackerGame:updateSectionScores(old_level, new_level)
if self.clear or self.loop ~= 0 then return end
if math.floor(old_level / 100) < math.floor(new_level / 100) or
new_level >= 500 then
-- record new section
section_score = self.score - self.section_start_score
self.section_scores[math.floor(old_level / 100)] = section_score
self.section_start_score = self.score
if self.loop == 0 then
if section_score >= lowest_section_cool_cutoff + 50000 * (math.floor(old_level / 100) + self.section_cools) then
self.section_cools = self.section_cools + 1
self.cool_timer = 300
end
end
end
end
function HighStackerGame:nextloopcheck()
if not self.clear then return false end
if self.section_cools >= 5 and self.score >= 6000000 then
self.loop = 2
return true
elseif self.section_cools >= 3 and self.score >= 4000000 then
self.loop = 1
return true
end
return false
end
function HighStackerGame:getSkin()
return (self.level >= 701 and self.loop == 2) and "bone" or "2tie"
end
function HighStackerGame:onGameComplete()
if not self.clear_bonus_given then
self.clear_bonus_given = true
if self.loop == 2 then
self.score = self.score + self.total_lines * 100 + self.lines * 1000
elseif self.loop == 1 then
self.score = self.score + self.total_lines * 100 + self.lines * 500
else
self.score = self.score + self.total_lines * 10 + self.lines * 100
end
end
self:onGameOver()
end
function HighStackerGame:onGameOver()
switchBGM(nil)
if not self.clear_bonus_given then
love.graphics.setColor(1, 1, 1, 1)
love.graphics.setFont(font_3x5_3)
love.graphics.printf("GAME\nOVER", 64, 200, 160, "center")
else
if self.game_over_frames >= 300 then
local alpha = 0
local animation_length = 120
if self.game_over_frames - 300 < animation_length then
-- Show field for a bit, then fade out.
alpha = math.pow(2048, (self.game_over_frames - 300)/animation_length - 1)
else
alpha = 1
end
love.graphics.setColor(0, 0, 0, alpha)
love.graphics.rectangle(
"fill", 64, 80,
16 * self.grid.width, 16 * (self.grid.height - 4)
)
end
if self.game_over_frames >= 420 and loop == 2 then
love.graphics.setColor(1, 1, 1, 1)
love.graphics.setFont(font_3x5_2)
love.graphics.printf(
[[And so, the journey
for the true end of
this absurd scoring
mode is over...
From now on,
aim for an even
higher score.
May fortune
be with you.
-Xx_Henry_xX]], 67, math.max(125, 1000 - self.game_over_frames), 160, "left")
end
end
end
HighStackerGame.rollOpacityFunction = function(age)
if age < 240 then return 1
elseif age > 300 then return 0
else return 1 - (age - 240) / 60 end
end
HighStackerGame.mRollOpacityFunction = function(age)
if age > 4 then return 0
else return 1 - age / 4 end
end
function HighStackerGame:drawGrid()
if self.clear and not (self.completed or self.game_over) then
if self.loop == 2 then
self.grid:drawInvisible(self.mRollOpacityFunction, nil, false)
elseif self.loop == 1 then
self.grid:drawInvisible(self.rollOpacityFunction, nil, false)
else
self.grid:draw()
end
else
self.grid:draw()
if self.piece ~= nil then
self:drawGhostPiece(ruleset)
end
end
end
function HighStackerGame:drawScoringInfo()
love.graphics.setColor(1, 1, 1, 1)
love.graphics.setFont(font_3x5_2)
--y is dis debug text everywhere
--[[
love.graphics.setFont(font_3x5_2)
love.graphics.print(
self.das.direction .. " " ..
self.das.frames .. " " ..
strTrueValues(self.prev_inputs)
)
]]
love.graphics.printf("NEXT", 126, 6, 40, "left")
love.graphics.printf("HOLD", 46, 6, 40, "left")
--love.graphics.printf("SCORE", 240, 200, 40, "left")
local vertpos = 320
if self.show_loop then vertpos = 290 end
love.graphics.printf("LEVEL", 240, vertpos, 40, "left")
love.graphics.setFont(font_3x5_3)
if self.clear and not self.actually_cue_the_rolls and self.roll_frames >= -120 then
if self.loop == 2 then
love.graphics.printf("WELCOME TO THE SPECIAL ROUND", 64, 200, 160, "center")
else
love.graphics.printf("Let's try everything again", 64, 200, 160, "center")
end
end
if self.clear_bonus_given then
if self.loop == 0 then
love.graphics.setFont(font_3x5_3)
love.graphics.printf("ALL CLEAR!", 44, 100, 200, "center")
love.graphics.setFont(font_3x5)
love.graphics.printf("(probably)", 44, 125, 200, "center")
love.graphics.setFont(font_3x5_2)
love.graphics.printf("TOTAL LINES", 80, 240, 120, "left")
love.graphics.printf(self.total_lines .. " x 10\n" .. (self.total_lines * 10), 80, 260, 120, "right")
love.graphics.printf("ROLL LINES", 80, 320, 120, "left")
love.graphics.printf(self.lines .. " x 100\n" .. (self.lines * 100), 80, 340, 120, "right")
elseif self.loop == 1 then
love.graphics.setFont(font_3x5_3)
love.graphics.printf("ALL CLEAR!", 44, 100, 200, "center")
love.graphics.setFont(font_3x5)
love.graphics.printf("(probably)", 44, 125, 200, "center")
love.graphics.setFont(font_3x5_2)
love.graphics.printf("TOTAL LINES", 80, 240, 120, "left")
love.graphics.printf(self.total_lines .. " x 100\n" .. (self.total_lines * 100), 80, 260, 120, "right")
love.graphics.printf("ROLL LINES", 80, 320, 120, "left")
love.graphics.printf(self.lines .. " x 500\n" .. (self.lines * 500), 80, 340, 120, "right")
elseif self.game_over_frames < 300 then
love.graphics.printf("CONGRATULATIONS!\nTRUE 2-ALL\nCLEAR!!!", 44, 100, 200, "center")
love.graphics.setFont(font_3x5_2)
love.graphics.printf("TOTAL LINES", 80, 240, 120, "left")
love.graphics.printf(self.total_lines .. " x 100\n" .. (self.total_lines * 100), 80, 260, 120, "right")
love.graphics.printf("ROLL LINES", 80, 320, 120, "left")
love.graphics.printf(self.lines .. " x 1000\n" .. (self.lines * 1000), 80, 340, 120, "right")
end
end
if(self.cool_timer > 0) then
love.graphics.printf("COOL!!", 64, 400, 160, "center")
self.cool_timer = self.cool_timer - 1
end
love.graphics.setFont(font_8x11)
love.graphics.setColor(1, 1, 1, 1)
love.graphics.printf(self.score, 48, 420, 180, "right")
love.graphics.setFont(font_3x5_3)
if self.show_loop then
if self.loop == 2 then
love.graphics.printf("2'-", 240, 310, 40, "right")
elseif self.loop == 1 then
love.graphics.printf("2-", 240, 310, 40, "left")
end
end
love.graphics.printf(self:getLevel(), 240, 340, 40, "right")
love.graphics.printf(self:getSectionEndLevel(), 240, 370, 40, "right")
love.graphics.setFont(font_3x5_2)
love.graphics.printf(formatTime(self.frames), 500, 420, 180, "left")
love.graphics.setColor(1, 1, 1, 1)
if self.loop == 0 then
local prevSectionTotal = 0
for i = 0, #self.section_scores do
prevSectionTotal = prevSectionTotal + self.section_scores[i]
end
love.graphics.printf(self.score - prevSectionTotal, 240, 420, 70, "right")
love.graphics.printf("/" .. lowest_section_cool_cutoff + 50000 * (math.floor(self.level / 100) + self.section_cools), 240, 436, 70, "right")
end
cool_counter = 0
for i = 0, #self.section_scores do
love.graphics.setColor(1, 1, 1, 1)
if self.section_scores[i] > lowest_section_cool_cutoff + 50000 * (i + cool_counter) then
love.graphics.setColor(0, 1, 0, 1)
cool_counter = cool_counter + 1
end
love.graphics.printf(self.section_scores[i], 400, 80 + 16 * i, 180, "right")
end
love.graphics.setColor(1, 1, 1, 1)
if self.detail_timer > 0 then
for i = 1, #self.line_details do
love.graphics.printf(self.line_details[i] .. "x" .. line_count_multiplier[#self.line_details], 240, 134 + 16 * i, 60, "right")
end
for i = 1, #self.line_details_second do
love.graphics.printf(self.line_details_second[i] .. "x" .. line_count_multiplier[#self.line_details], 240, 196 + 16 * i, 60, "right")
end
end
end
function HighStackerGame:getHighscoreData()
return {
score = self.score,
level = self.level,
frames = self.frames,
}
end
function HighStackerGame:getLevel()
if self.loop ~=0 then return self.level - 500 end
return self.level
end
function HighStackerGame:getSectionEndLevel()
if self.loop ~=0 then return math.min(math.floor((self.level - 500) / 100 + 1) * 100, 500) end
return math.min(math.floor(self.level / 100 + 1) * 100, 500)
end
function HighStackerGame:getBackground()
return math.floor(self.level / 100)
end
return HighStackerGame