mirror of
https://gitea.com/SweetSea-ButImNotSweet/tromi_mobile.git
synced 2025-01-08 17:33:09 +08:00
Add ``.gitignore``
Update ``.vscode\settings.json``
Main file changed a bit
Replace every single ``io.open`` into ``fs.read()``
Add ``input.waiting2trigger`` as buffer for too quick inputs
Replace ``binser`` with ``bitser``
Add the missing buffer logical code in training mode
Add a debug connector
Not a big update
Update VirtualControl.lua
Update in vctrl system
Trimming some unnecessary empty lines in classic library
Update virtual control stuff
Replace ``table.getn`` with ``#`` and ``scene`` with ``SCENE``
Renaming and moving some modules
Removing unnecessary ``local mino = {...}``
Add loading screen
Update loading screen
Apply replay patch
Not showing virtual control on computer
Adding touch screen configuration scene (placeholder)
Fix loading screen
update virtual control texture
Do some preparation for touch config screen
Quick patch
Compress background
Not important uodates
Small changes on how virtual key call action
Add ``SCENE:onInputMove``
Apply V2.2 patch
Clean up unnecessary imports
Test
.
Remove a redudant global variable
Small change
Split up alpha number
Sorting code
Update storeInput function
Optimize replay storing, saving and reading
Add VCTRL.export (for saving feature)
Remove unnecessary imports
Redesign loading screen
Replace loading screen
Make a simple BUTTON module
Update BUTTON module
Update button module
Add new callback
Add new callback
TEST
Update simple-button module
Update simple button module
Set default draw function for button
Add scene type notation
TEST
Not important updates
Design a error screen
Small update
Remove error key
Update
TEST
TEST
Test
TEST
TEST
Update button module
TEST
TEST
TEST
TEST
TEST
TEST
TEST
TEST
test
TEST
TEST
TEST
test
TEST
test
Fix a bug in VCTRL module that affect to SCENE:onInputRelease
Moving VCTRL related calls and adding buttons for name entry screen
Add type notation
Update modules
Final update for touch configuration scene
Fix 2 buttons can be highlighted at the same time in simple-button module
Narrow the safe border
Remove id = b (it was there for test)
Update of touch configuration scene
Add touch gesture for replay and input configuration scene
Add buttons for Replay, add MENU to go out after finishing game or in 20G Training mode
TEST
Fix some bugs (TEST)
Fix lỗi giữa đêm
Fix bug again
It should work imo
TEST
Fix SCENE:onInputMove{type="touch"} is not working
Fix bug once again (DONE!)
Temproraily allowing save
Fix settings module
Fix VCTRL.exportAll()
Fix VCTRL.exportAll returns userdata
Reverse a change
Fix forgetting to import virtual control settings
Fix grid drawing
Fix bugs related to the first time launching game
Add README file
Add README file
Update README and add LICENSE files
Update README
Add TV remote code
Disable debug code
Fix Android code
Small fix
Rename LICENSE to COPYING
Moving scene.lua to modules folder
Add new libraries
Make a new FILE API and add a simple error screen in case most thing went down
Change special code, add a way to skip keys
Update icon + README file
Rename screenshot file
Update README
Updating README file
Replace loading screen
Update README
Update virtual control texture
Fix virtual button method
Update README
Add icon font
Add importing and exporting replays
Update touch control
Update conf.lua
Replacing font, to avoid license issue
convert indents to spaces
Update font related stuff
Replace font
Updating README file
Update virtual control texture
1121 lines
42 KiB
Lua
1121 lines
42 KiB
Lua
local Object = require 'libs.classic'
|
|
local bit = require("bit")
|
|
local lualzw = require 'libs.lualzw'
|
|
local bitser = require 'libs.bitser'
|
|
|
|
local playedReadySE = false
|
|
|
|
local Grid = require 'game.grid'
|
|
local Randomizer = require 'game.randomizer'
|
|
|
|
local GameMode = Object:extend()
|
|
|
|
function GameMode:new(player_name, input_file, replay_grade)
|
|
VCTRL.toggle(MOBILE and not input_file and not SETTINGS.tvMode)
|
|
|
|
if player_name == nil then self.training = true else self.training = false end
|
|
if input_file ~= nil then
|
|
input_file = love.filesystem.read(REPLAY_DIR..input_file)
|
|
input_file = lualzw.decompress(input_file)
|
|
local seed = self:getInputPieceSeq(input_file)
|
|
self.replay_inputs = self:getReplayInputs(input_file)
|
|
self.randomizer = Randomizer(false, tonumber(seed))
|
|
self.input_playback = true
|
|
self.grade = replay_grade
|
|
self.frames = 1
|
|
elseif self.training then
|
|
player_name = 'TRN'
|
|
replay_grade = 'N/A'
|
|
self.randomizer = Randomizer(false, nil)
|
|
self.input_playback = false
|
|
self.frames = 0
|
|
else
|
|
self.randomizer = Randomizer(false, nil)
|
|
self.input_playback = false
|
|
self.frames = 0
|
|
end
|
|
self.player_name = player_name
|
|
self.grid = Grid(10, 20)
|
|
self.piece = nil
|
|
self.ready_frames = 100
|
|
self.game_over_frames = 0
|
|
self.are = 0
|
|
self.lcd = 0
|
|
self.das = { direction = "none", frames = -1 }
|
|
self.move = "none"
|
|
self.prev_inputs = {}
|
|
self.next_queue = {}
|
|
self.game_over = false
|
|
self.clear = false
|
|
self.completed = false
|
|
self.next_queue_length = 1
|
|
self.irs = true
|
|
self.drop_locked = false
|
|
self.hard_drop_locked = false
|
|
self.cleared_block_table = {}
|
|
self.last_lcd = 0
|
|
self.grade_score = 0
|
|
self.did_grades = false
|
|
self.active_frames = 0
|
|
self.total_lines = 0
|
|
self.lineClearPoints = {[0]=0, 0, 1667, 3750, 6668, 8335}
|
|
self.gradeNames = {
|
|
"19k", "18k", "17k", "16k", "15k", "14k", "13k", "12k", "11k", "10k",
|
|
"9k", "8k", "7k", "6k", "5k", "4k", "3k", "2k", "1k",
|
|
"1D", "2D", "3D", "4D", "5D", "6D", "7D", "8D", "9D"
|
|
}
|
|
self.promo_table = {
|
|
26666, 53333, 79999, 106666, 133333, 159999, 186666, 213333, 239999, 266666,
|
|
293333, 319999, 346666, 373333, 399999, 426666, 453333, 479999, 506666,
|
|
533333, 559999, 586666, 613333, 639999, 666666, 693333, 719999, 719999
|
|
}
|
|
self.autopromo_table = {
|
|
79999, 106666, 133333, 159999, 186666, 213333, 239999, 266666, 293333, 319999,
|
|
346666, 373333, 399999, 426666, 453333, 479999, 506666, 533333, 559999,
|
|
586666, 613333, 639999, 666666, 693333, 719999, 746666, 773333, 1000000
|
|
}
|
|
self.demo_table = {
|
|
-1, 13332, 25000, 40000, 50000, 60000, 60000, 120000, 120000, 120000,
|
|
180000, 180000, 240000, 240000, 300000, 300000, 360000, 360000, 360000,
|
|
420000, 420000, 480000, 480000, 480000, 480000, 540000, 540000, 540000
|
|
}
|
|
self.speed_divisor = 10000
|
|
self.line_clear_flash = 0
|
|
self.lines_cleared = 0
|
|
SOUNDS['bgm_firsthalf']:setVolume(0.3)
|
|
SOUNDS['bgm_secondhalf']:setVolume(0.35)
|
|
self.audio_stopped = false
|
|
self.recorded_inputs = {}
|
|
self.input_saved = false
|
|
self.end_grid_clear = false
|
|
self.last_active = 0
|
|
self.move_count = 0
|
|
self.target = 0
|
|
self.last_percent = 0
|
|
self.total_speed_loss = 0
|
|
self.grade_change_flash = 1
|
|
self.grade_change_color = {1,1,1,1}
|
|
self.point_flash = 0
|
|
self.point_flash_color = {1,1,1,1}
|
|
self.end_game_sound = nil
|
|
self.speed_level = 0
|
|
self.last_level = 0
|
|
self.nextbgmflag = false
|
|
self.firstbgmlooped = false
|
|
self.last_holes = 0
|
|
self.last_meter = 0
|
|
self.speed_table = {}
|
|
self.holes_bonus_freeze = 0
|
|
self.holes_bonus = 0
|
|
self.last_speed = 0
|
|
self.holes_bonus_lines = 0
|
|
self.bonus_components = {speed=1666,clean=750}
|
|
self.score_totals = {clean=0,speed=0,lines=0}
|
|
self.score_percents = {clean=0,speed=0,lines=0}
|
|
self.directions_pressed = {}
|
|
self.lines_bonus = 0
|
|
self.moved = false
|
|
self.midspeed_flash = false
|
|
self.lastdir = 1
|
|
self.spin_rng = {0,0,0,0,0,0,0,0,0,0}
|
|
self.lastlock = 0
|
|
self.up_lock = false
|
|
-- gravity, are, lock, das
|
|
self.delay_table = {
|
|
[0]={0.013, 20, 30, 12},{0.015, 20, 30, 12},{0.016, 20, 30, 12},{0.018, 20, 30, 12},{0.021, 20, 30, 12},{0.025, 20, 30, 12},
|
|
{0.027, 20, 30, 12},{0.030, 20, 30, 12},{0.033, 20, 30, 12},{0.038, 20, 30, 12},{0.043, 20, 30, 12},{0.051, 20, 30, 12},
|
|
{0.056, 20, 30, 12},{0.062, 20, 30, 12},{0.070, 20, 30, 12},{0.079, 20, 30, 12},{0.092, 20, 30, 12},{0.109, 20, 30, 12},
|
|
{0.120, 20, 30, 12},{0.134, 20, 30, 12},{0.152, 20, 30, 12},{0.175, 20, 30, 12},{0.206, 20, 30, 12},{0.250, 20, 30, 12},
|
|
{0.281, 20, 30, 12},{0.319, 20, 30, 12},{0.370, 20, 30, 12},{0.441, 20, 30, 12},{0.545, 20, 30, 12},{0.712, 20, 30, 12},
|
|
{0.842, 20, 30, 12},{1.029, 20, 30, 12},{1.323, 20, 30, 12},{1.852, 20, 30, 11},{3.086, 20, 30, 10},{9.259, 20, 30, 9},
|
|
{20, 20, 30, 8},{20, 20, 30, 8},{20, 19, 28, 8},{20, 18, 27, 8},{20, 17, 26, 8},{20, 17, 25, 8},
|
|
{20, 16, 24, 8},{20, 16, 23, 8},{20, 15, 23, 8},{20, 15, 22, 8},{20, 14, 21, 8},{20, 14, 21, 8},
|
|
{20, 14, 20, 8},{20, 13, 20, 8},{20, 13, 20, 8},{20, 13, 19, 8},{20, 13, 19, 8},{20, 13, 19, 8},
|
|
{20, 12, 18, 8}
|
|
}
|
|
if not self.input_playback and not self.training and not PENTO_MODE then
|
|
self:readGradeHistory()
|
|
end
|
|
end
|
|
|
|
function GameMode:readGradeHistory()
|
|
if love.filesystem.getInfo(SAVE_DIR..self.player_name.."_grade_history.sav") then
|
|
self.grade_history = FILE.read(SAVE_DIR..self.player_name.."_grade_history.sav")
|
|
else
|
|
self.grade_history = {1,2,0,0}
|
|
end
|
|
self.grade = self.grade_history[1]
|
|
self.starting_grade = self.grade
|
|
if self.grade > 1 then
|
|
local temp_grade = copy(self.grade_history); temp_grade[2] = 0
|
|
FILE.write(SAVE_DIR..self.player_name.."_grade_history.sav", temp_grade)
|
|
end
|
|
end
|
|
|
|
function GameMode:readHiScores()
|
|
if love.filesystem.getInfo(HIscoreFILE) then
|
|
self.hi_scores = FILE.read(HIscoreFILE)
|
|
else
|
|
self.hi_scores = {"TRO",0,"MIT",0,"ROM",0,"ITR",0,"OMI",0}
|
|
end
|
|
end
|
|
|
|
function GameMode:updateGradeHistory()
|
|
if self.grade_score >= self.promo_table[self.grade] then
|
|
if (self.grade == 28 and self.grade_history[2] < 4) or self.grade < 28 then self.grade_history[2] = self.grade_history[2] + 1 end
|
|
self.point_flash = 60
|
|
self.point_flash_color = {0,1,0,1}
|
|
elseif self.grade_score <= self.demo_table[self.grade] then
|
|
if (self.grade == 1 and self.grade_history[2] > 0) or self.grade > 1 then self.grade_history[2] = self.grade_history[2] - 1 end
|
|
self.point_flash = 60
|
|
self.point_flash_color = {1,0,0,1}
|
|
end
|
|
local auto_flag = false
|
|
while self.grade_score >= self.autopromo_table[self.grade] and self.grade < 28 do
|
|
self.grade = self.grade + 1
|
|
self.point_flash = 1
|
|
self.grade_change_flash = 120
|
|
self.grade_change_color = {0,0,1,1}
|
|
self.end_game_sound = "autopromote"
|
|
auto_flag = true
|
|
end
|
|
if self.grade_history[2] >= 5 and self.grade < 28 and auto_flag == false then
|
|
self.grade = self.grade + 1
|
|
self.point_flash = 1
|
|
self.grade_change_flash = 120
|
|
self.grade_change_color = {0,1,0,1}
|
|
self.end_game_sound = "promote"
|
|
elseif self.grade_history[2] < 0 and self.grade > 1 and auto_flag == false then
|
|
self.grade = self.grade - 1
|
|
self.point_flash = 1
|
|
self.grade_change_flash = 120
|
|
self.grade_change_color = {1,0,0,1}
|
|
self.end_game_sound = "demote"
|
|
end
|
|
if self.starting_grade ~= self.grade then
|
|
self.grade_history[1] = self.grade
|
|
self.grade_history[2] = 2
|
|
end
|
|
self.grade_history[4] = self.grade_history[4] + 1
|
|
end
|
|
|
|
function GameMode:updateHiScores()
|
|
self:readHiScores()
|
|
local hiscore_pos = {0,0}
|
|
local i = 2
|
|
local score_position = -1
|
|
while i <= 10 do
|
|
if score_position == -1 and self.hi_scores[i] < self.grade_score then
|
|
score_position = i
|
|
end
|
|
i = i + 2
|
|
end
|
|
if score_position ~= -1 then
|
|
i = 8
|
|
while i >= score_position-1 do
|
|
self.hi_scores[i+2] = self.hi_scores[i]
|
|
i = i - 1
|
|
end
|
|
self.hi_scores[score_position-1] = self.player_name:upper()
|
|
self.hi_scores[score_position] = self.grade_score
|
|
hiscore_pos = {score_position-1, score_position}
|
|
end
|
|
FILE.write(HIscoreFILE, self.hi_scores)
|
|
return hiscore_pos
|
|
end
|
|
|
|
function GameMode:getARR() return 1 end
|
|
function GameMode:getDropSpeed() return 1 end
|
|
function GameMode:getARE()
|
|
if self.training then return 20 end
|
|
if self.speed_level <= #self.delay_table then return self.delay_table[self.speed_level][2]
|
|
else return self.delay_table[#self.delay_table][2] end
|
|
end
|
|
|
|
function GameMode:getLineARE() return self:getARE() end
|
|
|
|
function GameMode:getLockDelay()
|
|
if self.training then return 99999999999 end
|
|
if self.speed_level <= #self.delay_table then return self.delay_table[self.speed_level][3]
|
|
else return self.delay_table[#self.delay_table][3] end
|
|
end
|
|
|
|
function GameMode:getLineClearDelay() return self:getARE() end
|
|
|
|
function GameMode:getDasLimit()
|
|
if self.training then return 8 end
|
|
if self.speed_level <= #self.delay_table then return self.delay_table[self.speed_level][4]
|
|
else return self.delay_table[#self.delay_table][4] end
|
|
end
|
|
function GameMode:getDasCutDelay() return 0 end
|
|
|
|
function GameMode:getGravity()
|
|
if self.training then return 20 end
|
|
if self.speed_level <= #self.delay_table then return self.delay_table[self.speed_level][1]
|
|
else return self.delay_table[#self.delay_table][1] end
|
|
end
|
|
|
|
function GameMode:getNextPiece(ruleset)
|
|
local shape = self.randomizer:nextPiece()
|
|
return {
|
|
skin = self:getSkin(),
|
|
shape = shape,
|
|
orientation = ruleset:getDefaultOrientation(shape),
|
|
}
|
|
end
|
|
|
|
function GameMode:getSkin()
|
|
return "2tie"
|
|
end
|
|
|
|
function GameMode:initialize(ruleset)
|
|
self.ruleset = ruleset
|
|
for i = 1, math.max(self.next_queue_length, 1) do
|
|
table.insert(self.next_queue, self:getNextPiece(ruleset))
|
|
end
|
|
end
|
|
|
|
function GameMode:saveInputs()
|
|
local input_string = 'NEW'..string.format("%16d", self.randomizer.seed)..';'
|
|
for frame, input_set in pairs(self.recorded_inputs) do
|
|
input_string = input_string..string.format('%03d', tostring(input_set))
|
|
end
|
|
local inputfile = love.filesystem.newFile(REPLAY_DIR..tostring(os.time()).."_"..self.player_name.."_"..self.starting_grade.."_"..self.grade_score.."_replay"..'.sav', 'w')
|
|
inputfile:write(lualzw.compress(input_string))
|
|
inputfile:close()
|
|
end
|
|
|
|
local GAME_input_code_list = {
|
|
right = 1 ,
|
|
rotate_right2 = 2 ,
|
|
up = 4 ,
|
|
rotate_left = 8 ,
|
|
left = 16 ,
|
|
down = 32 ,
|
|
rotate_right = 64 ,
|
|
rotate_left2 = 128,
|
|
}
|
|
function GameMode:storeInput(input_set)
|
|
local current_frame_input = 0
|
|
for key, code in pairs(GAME_input_code_list) do
|
|
if input_set[key] then
|
|
current_frame_input = bit.bor(current_frame_input, code)
|
|
end
|
|
end
|
|
self.recorded_inputs[self.frames] = current_frame_input
|
|
end
|
|
function GameMode:getReplayInputs(input_file)
|
|
local replay_inputs = {}
|
|
local semicolon_position = string.find(input_file, ';', 1, true)
|
|
|
|
if semicolon_position then
|
|
for i = semicolon_position + 1, #input_file, 3 do
|
|
local input_list = {right = false, rotate_right2 = false, up = false, rotate_left = false, left = false, down = false, rotate_right = false, rotate_left2 = false}
|
|
local coded_input = tonumber(string.sub(input_file, i, i+2))
|
|
|
|
for key, code in pairs(GAME_input_code_list) do
|
|
---@diagnostic disable-next-line: param-type-mismatch
|
|
if bit.band(coded_input, code) == code then input_list[key] = true end
|
|
end
|
|
|
|
table.insert(replay_inputs, input_list)
|
|
end
|
|
end
|
|
return replay_inputs
|
|
end
|
|
|
|
function GameMode:getInputPieceSeq(input_file)
|
|
local string_start
|
|
if string.sub(input_file, 1, 3) == 'NEW' then
|
|
string_start = 4
|
|
self.old_replay = false
|
|
else
|
|
string_start = 1
|
|
self.old_replay = true
|
|
end
|
|
return string.sub(
|
|
input_file, string_start,
|
|
string.find(input_file, ';', string_start, true) - 1
|
|
) -- seed
|
|
end
|
|
|
|
function GameMode:update(inputs, ruleset)
|
|
if self.input_playback and self.replay_inputs[self.frames] ~= nil then
|
|
inputs = self.replay_inputs[self.frames]
|
|
end
|
|
if self.grade_change_flash > 0 and self.game_over_frames >= 2 then self.grade_change_flash = self.grade_change_flash - 1 end
|
|
if self.point_flash > 0 and self.game_over_frames >= 2 then self.point_flash = self.point_flash - 1 end
|
|
if self.game_over_frames == 2 then
|
|
PlaySEOnce(self.end_game_sound)
|
|
end
|
|
if self.game_over or self.completed then
|
|
self.game_over_frames = self.game_over_frames + 1
|
|
if self.game_over_frames == 1 then self:storeInput(inputs) end
|
|
if self.lcd > 0 then
|
|
self.lcd = self.lcd - 1
|
|
elseif self.game_over_frames == 30 then
|
|
local cleared_row_count = self.grid:getClearedRowCount()
|
|
self.grid:clearClearedRows()
|
|
self:afterLineClear(cleared_row_count)
|
|
elseif not self.input_playback and not self.input_saved and not self.training and not PENTO_MODE and self.game_over_frames == 50 then
|
|
self:saveInputs()
|
|
self.input_saved = true
|
|
end
|
|
return
|
|
end
|
|
if inputs["up"] and self.training and not self.up_lock then
|
|
table.remove(self.next_queue, 1)
|
|
table.insert(self.next_queue, self:getNextPiece(ruleset))
|
|
self.up_lock = true
|
|
end
|
|
if not inputs["up"] then self.up_lock = false end
|
|
local dir_list = {"down", "left", "right"}
|
|
for i = 1, #dir_list do
|
|
if inputs[dir_list[i]] and not table.contains(self.directions_pressed, dir_list[i]) then
|
|
table.insert(self.directions_pressed, dir_list[i])
|
|
elseif not inputs[dir_list[i]] then
|
|
for j=1, #self.directions_pressed do
|
|
if self.directions_pressed[j] == dir_list[i] then table.remove(self.directions_pressed, j) end
|
|
end
|
|
end
|
|
end
|
|
if #self.directions_pressed > 0 then
|
|
for i=1, #self.directions_pressed-1 do
|
|
inputs[self.directions_pressed[i]] = false
|
|
end
|
|
inputs[self.directions_pressed[#self.directions_pressed]] = true
|
|
if inputs['left'] then self.lastdir = -1
|
|
elseif inputs['right'] then self.lastdir = 1 end
|
|
end
|
|
|
|
-- advance one frame
|
|
|
|
if self:advanceOneFrame(inputs, ruleset) == false then return end
|
|
|
|
self:chargeDAS(inputs, self:getDasLimit(), self:getARR())
|
|
|
|
-- set attempt flags
|
|
if inputs["left"] or inputs["right"] then self:onAttemptPieceMove(self.piece, self.grid) end
|
|
if (
|
|
inputs["rotate_left"] or inputs["rotate_right"] or
|
|
inputs["rotate_left2"] or inputs["rotate_right2"]
|
|
) then
|
|
self:onAttemptPieceRotate(self.piece, self.grid)
|
|
end
|
|
|
|
if self.piece == nil then
|
|
self:processDelays(inputs, ruleset)
|
|
else
|
|
self:whilePieceActive()
|
|
local gravity = self:getGravity()
|
|
|
|
-- diff vars to use in checks
|
|
local piece_y = self.piece.position.y
|
|
local piece_x = self.piece.position.x
|
|
local piece_rot = self.piece.rotation
|
|
ruleset:processPiece(
|
|
inputs, self.piece, self.grid, gravity, self.prev_inputs, self.move,
|
|
self:getLockDelay(), self:getDropSpeed(),
|
|
self.drop_locked, self.hard_drop_locked,
|
|
false, false, false, self.lastdir
|
|
)
|
|
|
|
local piece_dy = self.piece.position.y - piece_y
|
|
local piece_dx = self.piece.position.x - piece_x
|
|
local piece_drot = self.piece.rotation - piece_rot
|
|
|
|
-- das cut
|
|
if (
|
|
(piece_dy ~= 0 and (inputs.up or inputs.down)) or
|
|
(piece_drot ~= 0 and (
|
|
inputs.rotate_left or inputs.rotate_right or
|
|
inputs.rotate_left2 or inputs.rotate_right2
|
|
))
|
|
) then
|
|
self:dasCut()
|
|
end
|
|
|
|
if (piece_dx ~= 0) then
|
|
self.piece.last_rotated = false
|
|
self:onPieceMove(self.piece, self.grid, piece_dx)
|
|
end
|
|
if (piece_dy ~= 0) then
|
|
self.piece.last_rotated = false
|
|
self:onPieceDrop(self.piece, self.grid, piece_dy)
|
|
end
|
|
if (piece_drot ~= 0) then
|
|
self.piece.last_rotated = true
|
|
self:onPieceRotate(self.piece, self.grid, piece_drot)
|
|
end
|
|
|
|
if inputs["down"] == true then
|
|
if self.piece:isDropBlocked(self.grid) and not self.drop_locked then
|
|
self.lastlock = self.piece.lock_delay
|
|
self.piece.locked = true
|
|
self.piece_soft_locked = true
|
|
end
|
|
end
|
|
|
|
if self.piece.locked == true then
|
|
local last_x = self.piece.position.x
|
|
self.grid:applyPiece(self.piece)
|
|
|
|
local cleared_row_count = self.grid:getClearedRowCount()
|
|
self:onPieceLock(self.piece, cleared_row_count)
|
|
if not self.training then self:updateScore(cleared_row_count) end
|
|
|
|
self.cleared_block_table = self.grid:markClearedRows()
|
|
self.piece = nil
|
|
|
|
if cleared_row_count > 0 then
|
|
for i=1, #self.spin_rng do
|
|
local spin = math.abs(i-(last_x+3))
|
|
--if spin < 0 then spin = 0 end
|
|
self.spin_rng[i] = spin
|
|
end
|
|
PlaySE("erase")
|
|
self.lcd = self:getLineClearDelay()
|
|
self.last_lcd = self.lcd
|
|
self.are = self:getLineARE()
|
|
if self.lcd == 0 then
|
|
self.grid:clearClearedRows()
|
|
self:afterLineClear(cleared_row_count)
|
|
if self.are == 0 then
|
|
self:initializeOrHold(inputs, ruleset)
|
|
end
|
|
end
|
|
self:onLineClear(cleared_row_count)
|
|
else
|
|
self.are = self:getARE()
|
|
end
|
|
|
|
end
|
|
end
|
|
self.moved = false
|
|
if not self.input_playback and not self.game_over and not self.completed and not self.training and not PENTO_MODE then self:storeInput(inputs) end
|
|
self.prev_inputs = inputs
|
|
end
|
|
|
|
function GameMode:detectHoles(x, y)
|
|
if y < 1 then return true end -- reached the top, no hole
|
|
local cell = self.grid:getCell(x, y)
|
|
if table.contains(self.visited, x..'.'..y) then
|
|
return false
|
|
else
|
|
table.insert(self.visited, x..'.'..y)
|
|
end
|
|
if cell.colour ~= "" or cell.oob then return false end
|
|
if self:detectHoles(x+1, y) then return true end
|
|
if self:detectHoles(x-1, y) then return true end
|
|
if self:detectHoles(x, y+1) then return true end
|
|
if self:detectHoles(x, y-1) then return true end
|
|
return false
|
|
end
|
|
|
|
function GameMode:stackQualityCheck()
|
|
local hole_num = 0
|
|
self.visited = {}
|
|
for x=1, 10 do
|
|
for y = 1, 20 do
|
|
if self.grid:getCell(x, y).colour == "" and not table.contains(self.visited, x..'.'..y) then
|
|
local stack_clean = self:detectHoles(x, y)
|
|
if not stack_clean then
|
|
hole_num = hole_num + 1
|
|
end
|
|
end
|
|
end
|
|
end
|
|
return hole_num
|
|
end
|
|
|
|
function GameMode:doStackQuality()
|
|
local contiguous_holes = self:stackQualityCheck()
|
|
local total_speed = 0
|
|
if contiguous_holes > self.last_holes then
|
|
self.speed_table[1] = 0
|
|
self.last_percent = 0
|
|
end
|
|
for i=1, #self.speed_table do
|
|
total_speed = total_speed + self.speed_table[i]
|
|
end
|
|
if total_speed <= 0 then total_speed = 0.001 end
|
|
self.total_speed_loss = total_speed / #self.speed_table
|
|
if #self.speed_table == 0 then self.total_speed_loss = 0 end
|
|
self.last_holes = contiguous_holes
|
|
end
|
|
|
|
function GameMode:doSpeedCheck()
|
|
self.target = self.move_count
|
|
local speed = (self.target/self.active_frames)
|
|
if speed > 1 then speed = 1 end
|
|
table.insert(self.speed_table, 1, speed)
|
|
while #self.speed_table > 50 do
|
|
table.remove(self.speed_table, #self.speed_table)
|
|
end
|
|
local total_speed = 0
|
|
for i=1, #self.speed_table do
|
|
total_speed = total_speed + self.speed_table[i]
|
|
end
|
|
if total_speed <= 0 then total_speed = 0.001 end
|
|
self.total_speed_loss = total_speed / #self.speed_table
|
|
if #self.speed_table == 0 then self.total_speed_loss = 0 end
|
|
self.last_active = self.active_frames
|
|
self.last_percent = speed
|
|
self.active_frames = 0
|
|
self.move_count = 0
|
|
end
|
|
|
|
function GameMode:updateScore(cleared_lines)
|
|
self:doSpeedCheck()
|
|
if cleared_lines >= 1 then
|
|
while cleared_lines+self.total_lines > 300 do
|
|
cleared_lines = cleared_lines - 1
|
|
end
|
|
self.last_speed = math.ceil(self.total_speed_loss * self.bonus_components['speed'] * cleared_lines)
|
|
self.line_clear_flash = 240
|
|
self.lines_cleared = cleared_lines
|
|
self.score_to_add = self.lineClearPoints[cleared_lines] + self.last_speed
|
|
self.grade_score = self.grade_score + self.score_to_add
|
|
self.last_meter = self.holes_bonus + self.last_speed
|
|
self.speed_level = math.floor(self.grade_score / self.speed_divisor)
|
|
self.score_totals['speed'] = self.score_totals['speed'] + self.last_speed
|
|
self.score_totals['lines'] = self.score_totals['lines'] + self.lineClearPoints[cleared_lines]
|
|
end
|
|
end
|
|
|
|
function GameMode:advanceOneFrame()
|
|
if self.ready_frames ~= 0 and not self.audio_stopped and not self.training then
|
|
if SOUNDS['bgm_title']:getVolume() > 0.01 then SOUNDS['bgm_title']:setVolume(SOUNDS['bgm_title']:getVolume()-0.01) end
|
|
if self.ready_frames == 5 then
|
|
love.audio.stop()
|
|
self.audio_stopped = true
|
|
end
|
|
end
|
|
if self.training and not SOUNDS['bgm_title']:isPlaying() and SETTINGS["music"] then SOUNDS['bgm_title']:play() end
|
|
if not self.training then
|
|
if self.nextbgmflag and SOUNDS['bgm_firsthalf']:isPlaying() then
|
|
if SOUNDS['bgm_firsthalf']:getVolume() > 0.1 then
|
|
SOUNDS['bgm_firsthalf']:setVolume(SOUNDS['bgm_firsthalf']:getVolume()-0.01)
|
|
else
|
|
SOUNDS['bgm_firsthalf']:stop()
|
|
end
|
|
end
|
|
if self.ready_frames < 1 and not SOUNDS['bgm_firsthalf']:isPlaying() and not SOUNDS['bgm_secondhalf']:isPlaying() and SETTINGS["music"] then
|
|
if not self.nextbgmflag then SOUNDS['bgm_firsthalf']:play()
|
|
elseif self.total_lines < 296 then SOUNDS['bgm_secondhalf']:play() end
|
|
end
|
|
if self.total_lines >= 296 then
|
|
SOUNDS['bgm_firsthalf']:stop()
|
|
SOUNDS['bgm_secondhalf']:stop()
|
|
end
|
|
end
|
|
if self.clear then
|
|
self.completed = true
|
|
end
|
|
self.frames = self.frames + 1
|
|
if self.input_playback == true and self.old_replay == true and self.ready_frames ~= 0 then
|
|
self.frames = 0
|
|
end
|
|
if self.line_clear_flash > 0 then self.line_clear_flash = self.line_clear_flash - 1 end
|
|
if self.line_clear_flash == 0 then
|
|
self.lines_cleared = 0
|
|
self.score_to_add = 0
|
|
self.last_meter = 0
|
|
self.holes_bonus = 0
|
|
self.last_speed = 0
|
|
self.holes_bonus_lines = 0
|
|
self.lines_bonus_lines = 0
|
|
self.lines_bonus = 0
|
|
end
|
|
return true
|
|
end
|
|
|
|
-- event functions
|
|
function GameMode:whilePieceActive()
|
|
self.active_frames = self.active_frames + 1
|
|
end
|
|
function GameMode:onAttemptPieceMove(piece, grid) end
|
|
function GameMode:onAttemptPieceRotate(piece, grid) end
|
|
function GameMode:onPieceMove(piece, grid, dx)
|
|
if not self.moved then
|
|
self.move_count = self.move_count + 1
|
|
self.moved = true
|
|
end
|
|
end
|
|
function GameMode:onPieceRotate(piece, grid, drot)
|
|
if not self.moved then
|
|
self.move_count = self.move_count + 1
|
|
self.moved = true
|
|
end
|
|
end
|
|
function GameMode:onPieceDrop(piece, grid, dy)
|
|
if not self.moved then
|
|
self.move_count = self.move_count + 1
|
|
self.moved = true
|
|
end
|
|
end
|
|
function GameMode:onPieceLock(piece, cleared_row_count)
|
|
if not self.moved then
|
|
self.move_count = self.move_count + 1
|
|
self.moved = true
|
|
end
|
|
self.lastdir = 0
|
|
PlaySE("lock")
|
|
end
|
|
|
|
function GameMode:onLineClear(cleared_row_count)
|
|
if not self.training then self.total_lines = math.min(self.total_lines + cleared_row_count, 300) end
|
|
if self.total_lines == 300 and not self.clear then
|
|
self.clear = true
|
|
end
|
|
end
|
|
|
|
function GameMode:afterLineClear(cleared_row_count) end
|
|
|
|
function GameMode:onPieceEnter()
|
|
self:doStackQuality()
|
|
end
|
|
|
|
function GameMode:onGameOver()
|
|
if not self.training then VCTRL.toggle(false) end
|
|
if not self.input_playback and not self.training and not PENTO_MODE then
|
|
if not self.did_grades then
|
|
self.grade_score = self.grade_score + self.speed_level
|
|
if #self.speed_table >= 49 then
|
|
self:updateGradeHistory()
|
|
end
|
|
hiscore_pos = self:updateHiScores()
|
|
FILE.write(SAVE_DIR..self.player_name.."_grade_history.sav", self.grade_history)
|
|
self.did_grades = true
|
|
end
|
|
self:drawEndScoringInfo()
|
|
elseif not self.did_grades then
|
|
self.grade_score = self.grade_score + self.speed_level
|
|
self.did_grades = true
|
|
end
|
|
if PENTO_MODE and not self.training then self:drawEndScoringInfo() end
|
|
end
|
|
|
|
function GameMode:drawEndScoringInfo()
|
|
love.graphics.setColor(1, 1, 1, 1)
|
|
drawText("Score: ", 247, 135, 1000, "left")
|
|
drawBigText(string.format("%s", self.grade_score), 247, 150, 100, "center")
|
|
if not PENTO_MODE then
|
|
drawText("Best scores:", 247, 220, 1000, "left")
|
|
|
|
local i = 2
|
|
while i <= 10 do
|
|
if i == hiscore_pos[1] or i == hiscore_pos[2] then
|
|
drawText(self.hi_scores[i-1]..' - '..self.hi_scores[i], 255, 220+(i*10), 1000, "left", {0,1,0,1})
|
|
else
|
|
drawText(self.hi_scores[i-1]..' - '..self.hi_scores[i], 255, 220+(i*10), 1000, "left")
|
|
end
|
|
i = i + 2
|
|
end
|
|
end
|
|
end
|
|
|
|
function GameMode:onGameComplete()
|
|
self:onGameOver()
|
|
end
|
|
|
|
-- DAS functions
|
|
|
|
function GameMode:startRightDAS()
|
|
self.move = "right"
|
|
self.das = { direction = "right", frames = 0 }
|
|
if self:getDasLimit() == 0 then
|
|
self:continueDAS()
|
|
end
|
|
end
|
|
|
|
function GameMode:startLeftDAS()
|
|
self.move = "left"
|
|
self.das = { direction = "left", frames = 0 }
|
|
if self:getDasLimit() == 0 then
|
|
self:continueDAS()
|
|
end
|
|
end
|
|
|
|
function GameMode:continueDAS()
|
|
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
|
|
end
|
|
|
|
function GameMode:stopDAS()
|
|
self.move = "none"
|
|
self.das = { direction = "none", frames = -1 }
|
|
end
|
|
|
|
function GameMode:chargeDAS(inputs)
|
|
if inputs[self.das.direction] == true then
|
|
self:continueDAS()
|
|
elseif inputs["right"] == true then
|
|
self:startRightDAS()
|
|
elseif inputs["left"] == true then
|
|
self:startLeftDAS()
|
|
else
|
|
self:stopDAS()
|
|
end
|
|
end
|
|
|
|
function GameMode:dasCut()
|
|
self.das.frames = math.max(
|
|
self.das.frames - self:getDasCutDelay(),
|
|
-(self:getDasCutDelay() + 1)
|
|
)
|
|
end
|
|
|
|
function GameMode:processDelays(inputs, ruleset, drop_speed)
|
|
if self.ready_frames == 100 then
|
|
playedReadySE = false
|
|
playedGoSE = false
|
|
end
|
|
if self.ready_frames > 0 then
|
|
if not playedReadySE then
|
|
playedReadySE = true
|
|
PlaySEOnce("ready")
|
|
end
|
|
self.ready_frames = self.ready_frames - 1
|
|
if self.ready_frames == 0 then
|
|
self:initializeOrHold(inputs, ruleset)
|
|
end
|
|
elseif self.lcd > 0 then
|
|
self.lcd = self.lcd - 1
|
|
if self.lcd == 0 then
|
|
local cleared_row_count = self.grid:getClearedRowCount()
|
|
self.grid:clearClearedRows()
|
|
self:afterLineClear(cleared_row_count)
|
|
PlaySE("fall")
|
|
if self.are == 0 then
|
|
self:initializeOrHold(inputs, ruleset)
|
|
end
|
|
end
|
|
elseif self.are > 0 then
|
|
self.are = self.are - 1
|
|
if self.are == 0 then
|
|
self:initializeOrHold(inputs, ruleset)
|
|
end
|
|
end
|
|
end
|
|
|
|
function GameMode:initializeOrHold(inputs, ruleset)
|
|
self:initializeNextPiece(inputs, ruleset, self.next_queue[1])
|
|
self:onPieceEnter()
|
|
if not self.grid:canPlacePiece(self.piece) then
|
|
self.game_over = true
|
|
end
|
|
ruleset:dropPiece(
|
|
inputs, self.piece, self.grid, self:getGravity(),
|
|
self:getDropSpeed(), self.drop_locked, self.hard_drop_locked
|
|
)
|
|
end
|
|
|
|
function GameMode:initializeNextPiece(inputs, ruleset, piece_data, generate_next_piece)
|
|
self.piece = ruleset:initializePiece(
|
|
inputs, piece_data, self.grid, self:getGravity(),
|
|
self.prev_inputs, self.move,
|
|
self:getLockDelay(), self:getDropSpeed(),
|
|
self.drop_locked, self.hard_drop_locked, false,
|
|
(
|
|
self.frames == 0 or self:getARE() ~= 0
|
|
) and self.irs or false, self.lastdir
|
|
)
|
|
self.piece_hard_dropped = false
|
|
self.piece_soft_locked = false
|
|
if self.piece:isDropBlocked(self.grid) and
|
|
self.grid:canPlacePiece(self.piece) then
|
|
PlaySE("bottom")
|
|
end
|
|
if generate_next_piece == nil then
|
|
table.remove(self.next_queue, 1)
|
|
table.insert(self.next_queue, self:getNextPiece(ruleset))
|
|
end
|
|
end
|
|
|
|
function GameMode:animation(x, y, skin, colour)
|
|
return {
|
|
1, 1, 1,
|
|
-0.25 + 1.25 * (self.lcd / self.last_lcd),
|
|
skin, colour,
|
|
200 + x * 16, y * 16
|
|
}
|
|
end
|
|
|
|
function GameMode:canDrawLCA()
|
|
return self.lcd > 0
|
|
end
|
|
|
|
function GameMode:drawLineClearAnimation()
|
|
local grid_position = {x=200,y=64}
|
|
for y, row in pairs(self.cleared_block_table) do
|
|
for x, block in pairs(row) do
|
|
local real_x = (x * 16) + grid_position['x']
|
|
local real_y = (y * 16) + grid_position['y']
|
|
local drift = self.spin_rng[x]*-1
|
|
local fall_timer = (self:getLineClearDelay()-self.lcd)/2
|
|
fall_timer = (fall_timer*fall_timer)+drift
|
|
fade_timer = self.lcd/20
|
|
love.graphics.setColor(1,1,1,fade_timer)
|
|
love.graphics.draw(BLOCKS[block.skin][block.colour..'_d'], real_x, real_y+fall_timer)
|
|
if self.lcd > self:getLineClearDelay() - 5 then
|
|
love.graphics.setColor(1,1,1,fade_timer*0.3)
|
|
love.graphics.draw(BLOCKS[block.skin]['W'], real_x, real_y+fall_timer)
|
|
end
|
|
end
|
|
end
|
|
end
|
|
|
|
function GameMode:drawPiece()
|
|
if self.piece ~= nil then
|
|
local b = (
|
|
1 - (self.piece.lock_delay / self:getLockDelay())
|
|
)
|
|
self.piece:draw(0.50 + 0.50 * b, 0.50 + 0.50 * b, self.grid)
|
|
end
|
|
end
|
|
|
|
function GameMode:drawNextQueue(ruleset)
|
|
local colourscheme
|
|
function drawPiece(piece, skin, offsets, pos_x, pos_y)
|
|
for index, offset in pairs(offsets) do
|
|
local x = offset.x + ruleset:getDrawOffset(piece, rotation).x + ruleset.spawn_positions[piece].x
|
|
local y = offset.y + ruleset:getDrawOffset(piece, rotation).y + 4.7
|
|
love.graphics.draw(BLOCKS[skin][COLOUR_SCHEMES.Arika[piece]], pos_x+x*16, pos_y+y*16)
|
|
end
|
|
end
|
|
for i = 1, self.next_queue_length do
|
|
love.graphics.setColor(1, 1, 1, 1)
|
|
local highness = -54
|
|
local next_piece = self.next_queue[i].shape
|
|
local skin = self.next_queue[i].skin
|
|
local rotation = self.next_queue[i].orientation
|
|
drawPiece(next_piece, skin, ruleset.block_offsets[next_piece][rotation], 136+i*80, highness)
|
|
end
|
|
return false
|
|
end
|
|
|
|
function GameMode:getBackground()
|
|
bg = math.floor(self.speed_level/6)
|
|
if bg > 9 then bg = 9 end
|
|
if (self.total_lines >= 130 or self.frames >= 23640) and self.last_level ~= bg then self.nextbgmflag = true end
|
|
self.last_level = bg
|
|
return bg
|
|
end
|
|
|
|
function GameMode:drawGrid()
|
|
local greyscale = false
|
|
if self.game_over or self.completed then greyscale = true end
|
|
self.grid:draw(greyscale, (self.game_over_frames/50))
|
|
end
|
|
|
|
function GameMode:drawInputDisplay(left, top)
|
|
if self.replay_inputs[self.frames] ~= nil then
|
|
drawText("•", left+7.5, top+ 8, 1000, "left")
|
|
drawText(CHAR.key.down , left+ 5, top+18, 1000, "left",{1-boolToInt(self.replay_inputs[self.frames]['down']),1,1-boolToInt(self.replay_inputs[self.frames]['down']),1})
|
|
drawText(CHAR.key.left , left- 5, top+ 8, 1000, "left",{1-boolToInt(self.replay_inputs[self.frames]['left']),1,1-boolToInt(self.replay_inputs[self.frames]['left']),1})
|
|
drawText(CHAR.key.right, left+ 15, top+ 8, 1000, "left",{1-boolToInt(self.replay_inputs[self.frames]['right']),1,1-boolToInt(self.replay_inputs[self.frames]['right']),1})
|
|
drawText("L", left+ 35, top+ 8, 1000, "left",{1-boolToInt(self.replay_inputs[self.frames]['rotate_left']),1,1-boolToInt(self.replay_inputs[self.frames]['rotate_left']),1})
|
|
drawText("R", left+ 50, top+ 8, 1000, "left",{1-boolToInt(self.replay_inputs[self.frames]['rotate_right']),1,1-boolToInt(self.replay_inputs[self.frames]['rotate_right']),1})
|
|
drawText("L", left+ 65, top+ 8, 1000, "left",{1-boolToInt(self.replay_inputs[self.frames]['rotate_left2']),1,1-boolToInt(self.replay_inputs[self.frames]['rotate_left2']),1})
|
|
drawText("R", left+ 80, top+ 8, 1000, "left",{1-boolToInt(self.replay_inputs[self.frames]['rotate_right2']),1,1-boolToInt(self.replay_inputs[self.frames]['rotate_right2']),1})
|
|
else
|
|
drawText("•" , left+7.5, top+ 8, 1000, "left")
|
|
drawText(CHAR.key.down , left+ 5, top+18, 1000)
|
|
drawText(CHAR.key.left , left- 5, top+ 8, 1000)
|
|
drawText(CHAR.key.right, left+ 15, top+ 8, 1000)
|
|
drawText("L" , left+ 35, top+ 8, 1000, "left")
|
|
drawText("R" , left+ 50, top+ 8, 1000, "left")
|
|
drawText("L" , left+ 65, top+ 8, 1000, "left")
|
|
drawText("R" , left+ 80, top+ 8, 1000, "left")
|
|
end
|
|
end
|
|
|
|
function GameMode:drawSpeedStats(left, top)
|
|
love.graphics.setColor(0,0,0,0.5)
|
|
love.graphics.rectangle("fill", left+3, top+3, 190, 145, 10, 10)
|
|
love.graphics.setColor(0.05,0.05,0.05,1)
|
|
love.graphics.rectangle("fill", left, top, 190, 145, 10, 10)
|
|
drawText("Efficiency Bonus: ", left+15, top+5, 1000, "left")
|
|
local lines = self.total_lines
|
|
if lines == 0 then lines = 1 end
|
|
if self.move_count == 0 then
|
|
drawText(string.format(" %4d Num. of Moves", self.target), left+15, top+20, 1000, "left")
|
|
else
|
|
drawText(string.format(" %4d Num. of Moves", self.move_count), left+15, top+20, 1000, "left")
|
|
end
|
|
drawText(string.format("/ %4d Active Frames", self.last_active), left+15, top+35, 1000, "left")
|
|
drawText(string.format("= %1.2f\n (0 added for hole)\n %1.2f %dpc Average\nx %s x Lines\n+ %4d", self.last_percent, self.total_speed_loss, #self.speed_table, self.bonus_components['speed'], self.last_speed), left+15, top+50, 1000, "left")
|
|
end
|
|
|
|
function GameMode:drawLinesStats(left, top)
|
|
love.graphics.setColor(0,0,0,0.5)
|
|
love.graphics.rectangle("fill", left+3, top+3, 190, 90, 10, 10)
|
|
love.graphics.setColor(0.05,0.05,0.05,1)
|
|
love.graphics.rectangle("fill", left, top, 190, 90, 10, 10)
|
|
local lines = self.total_lines
|
|
if lines == 0 then lines = 1 end
|
|
drawText("Lines Bonus: ", left+15, top+10, 1000, "left")
|
|
-- drawText(string.format("+ %4d %3d%%", self.lineClearPoints[self.lines_cleared], (self.score_totals['lines']/(self.lineClearPoints[4]*math.ceil(lines/4)))*100), left+15, top+25, 1000, "left")
|
|
drawText(string.format("2 x Lines = %d\n3 x Lines = %d\n4 x Lines = %d", self.lineClearPoints[2], self.lineClearPoints[3], self.lineClearPoints[4]), left+15, top+25, 1000, "left")
|
|
end
|
|
|
|
function GameMode:drawScoringInfo()
|
|
-- Name & Grade
|
|
love.graphics.setColor(0,0,0,0.5)
|
|
love.graphics.rectangle("fill", 98, 83, 110, 180, 10, 10)
|
|
love.graphics.setColor(0.05,0.05,0.05,1)
|
|
love.graphics.rectangle("fill", 95, 80, 110, 180, 10, 10)
|
|
if not PENTO_MODE then drawText("Grade:", 100, 128, 1000, "left") end
|
|
-- Line & Level
|
|
if self.training or SETTINGS["lines"] then
|
|
love.graphics.setColor(0,0,0,0.5)
|
|
love.graphics.rectangle("fill", 241, 407, 116, 40, 5, 5) --lines
|
|
love.graphics.setColor(0.05,0.05,0.05,1)
|
|
love.graphics.rectangle("fill", 239, 405, 116, 40, 5, 5) --lines
|
|
drawText(string.format("Level: %2d\nLines: %3d/300", self:getBackground(), self.total_lines), 249, 408, 1000, "left")
|
|
end
|
|
-- REPLAY
|
|
if self.input_playback then
|
|
love.graphics.setColor(0,0,0,0.5)
|
|
love.graphics.rectangle("fill", 68, 270, 140, 190, 10, 10)
|
|
love.graphics.setColor(0.05,0.05,0.05,1)
|
|
love.graphics.rectangle("fill", 65, 267, 140, 190, 10, 10)
|
|
drawBoldText(string.format("REPLAY IN PROGRESS\n\n\n\n\n\n\n\n\n%s", formatTime(self.frames)), 70, 275, 1000, "left")
|
|
drawBigText(string.format("%s", self.grade), 100, 143, 1000, "left")
|
|
self:drawInputDisplay(103,185)
|
|
elseif not PENTO_MODE then
|
|
if math.mod(self.grade_change_flash, 5) ~= 0 then
|
|
drawBigText(string.format("%s", self.gradeNames[self.grade]), 100, 143, 1000, "left", self.grade_change_color)
|
|
else
|
|
drawBigText(string.format("%s", self.gradeNames[self.grade]), 100, 143, 1000, "left")
|
|
end
|
|
local points_text = nil
|
|
if self.grade == 1 and self.grade_history[2] == 2 then
|
|
points_text = " |.."
|
|
elseif self.grade == 1 and self.grade_history[2] == 3 then
|
|
points_text = " .|."
|
|
elseif self.grade == 1 and self.grade_history[2] == 4 then
|
|
points_text = " ..|"
|
|
elseif self.grade_history[2] == 0 then
|
|
points_text = "|...."
|
|
elseif self.grade_history[2] == 1 then
|
|
points_text = ".|..."
|
|
elseif self.grade_history[2] == 2 then
|
|
points_text = "..|.."
|
|
elseif self.grade_history[2] == 3 then
|
|
points_text = "...|."
|
|
elseif self.grade_history[2] == 4 then
|
|
points_text = "....|"
|
|
end
|
|
if self.grade > 1 then points_text = '-'..points_text
|
|
else points_text = ' '..points_text end
|
|
if self.grade < 28 then points_text = points_text..'+' end
|
|
drawText("Promotion\nMeter:", 100, 174, 1000, "left")
|
|
if self.point_flash > 0 then
|
|
drawBigText(points_text, 100, 208, 1000, "left", self.point_flash_color)
|
|
else
|
|
drawBigText(points_text, 100, 208, 1000, "left")
|
|
end
|
|
end
|
|
if (self.game_over or self.completed) and self.game_over_frames <= 50 and not self.input_playback and not self.training and not PENTO_MODE then
|
|
drawText("SAVING, PLEASE WAIT", 232, 460, 1000, "left")
|
|
end
|
|
drawText("Name:", 100, 83, 1000, "left")
|
|
drawBigText(self.player_name:upper(), 100, 98, 1000, "left")
|
|
drawText("Ver. 2", 550, 435, 1000, "left")
|
|
if self.input_playback then
|
|
self:drawSpeedStats(385, 99)
|
|
self:drawLinesStats(385, 251)
|
|
love.graphics.setColor(0,0,0,0.5)
|
|
love.graphics.rectangle("fill", 385+3, 348+3, 190, 50, 10, 10)
|
|
love.graphics.setColor(0.05,0.05,0.05,1)
|
|
love.graphics.rectangle("fill", 385, 348, 190, 50, 10, 10)
|
|
drawText(string.format("Added: %d\nScore: %d",self.score_to_add, self.grade_score), 392, 356, 1000, "left")
|
|
end
|
|
|
|
|
|
if self.clear or self.game_over then
|
|
SOUNDS['bgm_firsthalf']:stop()
|
|
SOUNDS['bgm_secondhalf']:stop()
|
|
end
|
|
end
|
|
|
|
function GameMode:drawBackground()
|
|
local bg = self:getBackground()
|
|
local brightness = 0.9
|
|
local limit = 4
|
|
if self.training then bg = 0 end
|
|
--if self.training then bg = math.mod(math.floor(((self.frames+1)/1200)), 10) end
|
|
if bg == 0 or bg == 6 or bg == 9 then limit = 5 end
|
|
if bg == 5 then limit = 4.76 end
|
|
if not BACKGROUNDS[bg]:isPlaying() then
|
|
BACKGROUNDS[bg]:play()
|
|
end
|
|
if BACKGROUNDS[bg]:tell() >= limit then
|
|
BACKGROUNDS[bg]:rewind()
|
|
end
|
|
if bg == 0 or bg == 8 or bg == 9 or bg == 3 then brightness = 0.7 end
|
|
love.graphics.setColor(brightness, brightness, brightness, 1)
|
|
love.graphics.draw(BACKGROUNDS[bg])
|
|
end
|
|
|
|
function GameMode:drawFrame()
|
|
love.graphics.setColor(1, 1, 1, 1)
|
|
love.graphics.line(216,80,216,80+(16*self.grid.height))
|
|
love.graphics.line(216+(16*self.grid.width),80,216+(16*self.grid.width),80+(16*self.grid.height))
|
|
love.graphics.line(216,80+(16*self.grid.height),216+(16*self.grid.width),80+(16*self.grid.height))
|
|
love.graphics.line(216,80,216+(16*self.grid.width),80)
|
|
love.graphics.setColor(0, 0, 0, 1)
|
|
love.graphics.rectangle(
|
|
"fill", 216, 80,
|
|
16 * self.grid.width, 16 * (self.grid.height)
|
|
)
|
|
end
|
|
|
|
function GameMode:drawReadyGo()
|
|
-- ready/go graphics
|
|
love.graphics.setColor(1, 1, 1, 1)
|
|
|
|
if self.ready_frames <= 100 and self.ready_frames > 52 then
|
|
drawBigText("Ready...", 246, 240 - 14, 1000)
|
|
elseif self.ready_frames <= 50 and self.ready_frames > 2 then
|
|
drawBigText("Go!", 276, 240 - 14, 1000)
|
|
end
|
|
end
|
|
|
|
function GameMode:drawCustom() end
|
|
|
|
function GameMode:draw(paused)
|
|
self:drawBackground()
|
|
self:drawFrame()
|
|
self:drawGrid()
|
|
self:drawPiece()
|
|
self:drawNextQueue(self.ruleset)
|
|
if not self.training then self:drawScoringInfo() end
|
|
self:drawReadyGo()
|
|
self:drawCustom()
|
|
if self:canDrawLCA() then
|
|
self:drawLineClearAnimation()
|
|
end
|
|
|
|
if self.completed then
|
|
self:onGameComplete()
|
|
elseif self.game_over then
|
|
self:onGameOver()
|
|
end
|
|
end
|
|
|
|
return GameMode
|