Compare commits

..

48 Commits

Author SHA1 Message Date
Ishaan Bhardwaj
9fbfbd5cda Refined and cleaned up buffer drop input functionality 2021-07-11 17:10:51 -04:00
Ishaan Bhardwaj
c5c4c4d95c Fixed delay curve calculation in Marathon 2020 2021-07-11 15:38:38 -04:00
Ishaan Bhardwaj
53c51c2062 Removed debug code for Marathon 2020 2021-07-11 14:57:14 -04:00
Ishaan Bhardwaj
e4eb9972e6 Fixed section COOL conditions for Marathon 2020 2021-07-11 14:55:45 -04:00
Ishaan Bhardwaj
7dbfe23059 Bump version to beta6 (also closes #19) 2021-07-11 14:04:22 -04:00
Ishaan Bhardwaj
61d5410f22 Prevent mapping the same key to two controls (fixes #20) 2021-07-11 13:53:27 -04:00
Ishaan Bhardwaj
2cb0416548 Shorten Death credit roll 2021-07-07 18:23:37 -04:00
83f3e297ce Changed "Notable Games" to "Other Notable Games" 2021-07-07 03:33:13 -04:00
Ishaan Bhardwaj
8fb01dc9a8 Another credits update 2021-07-05 22:09:06 -04:00
Ishaan Bhardwaj
61de3c6dbf Miscellaneous fixes to piece behavior in addition to fixing prev. commit 2021-06-26 16:27:33 -04:00
Ishaan Bhardwaj
3c718c38e4 Revert "Fixed a bug where pieces would check gravity before a block out"
This reverts commit d18c3e298d.
2021-06-26 14:55:18 -04:00
Ishaan Bhardwaj
d18c3e298d Fixed a bug where pieces would check gravity before a block out 2021-06-26 00:20:47 -04:00
Ishaan Bhardwaj
33934bfb53 Fixed some redundancies in the piece class and Survival A1 2021-06-20 15:20:09 -04:00
Ishaan Bhardwaj
3e2d107687 Small grade fix for Marathon A3 2021-06-19 13:31:45 -04:00
Ishaan Bhardwaj
312b95728d Fixed an issue with Survival A3 that prevented extension of the mode 2021-06-17 22:59:30 -04:00
Ishaan Bhardwaj
5013443302 Phantom Mania mechanic bugfixes 2021-06-17 19:10:21 -04:00
Ishaan Bhardwaj
a8ac8f5966 Whoops forgot a contributor, fixed 2021-06-15 21:47:38 -04:00
Ishaan Bhardwaj
a5032386e6 Small update to a contributor's name 2021-06-14 23:55:36 -04:00
Ishaan Bhardwaj
264255290d Credit bump! 2021-06-14 23:53:14 -04:00
Ishaan Bhardwaj
a5839bede2 Added another notable game 2021-06-14 23:28:27 -04:00
Ishaan Bhardwaj
4ebf24316a Added notable games that I think you should play 2021-06-14 23:25:32 -04:00
Ishaan Bhardwaj
f2acab4496 A few minor changes, read below
Clean up big pieces for a temporary hotfix, an overhaul soon to come
Refactored BGM and SE playing
Moved draw code completely into gamemode - mod makers can now control everything on screen
2021-06-09 20:15:37 -04:00
929069c1b6 Merge pull request #21 from Trixciel/master
Fixed ARE Cancelling when using a Sonic Drop RS
2021-06-07 23:12:58 -04:00
Trixciel
3f2b38f7b3 Fixed ARE Cancelling with Sonic Drop RS
Changed the code in a way that allows ARE Cancelling to work with rotation systems that use sonic drop and a locking soft drop.
2021-06-06 17:38:47 +02:00
Ishaan Bhardwaj
56fb5aebea Small cleanup to file info checking 2021-06-03 16:00:33 -04:00
Ishaan Bhardwaj
6c201596b0 Fixed O failing to rotate in CRS 2021-06-02 12:10:02 -04:00
Ishaan Bhardwaj
50466c5902 Fixed unary negation and to-string bigint metamethods 2021-05-29 19:48:34 -04:00
ae1231c47a Merge pull request #17 from nightmareci/master
Improved latency and performance
2021-05-27 09:34:46 -04:00
Ishaan Bhardwaj
366ac1d552 Update credits.lua 2021-05-23 17:37:38 -04:00
302353f716 Update README.md 2021-05-23 17:20:26 -04:00
nightmareci
7f550b629f Made start-of-line spacing all hard tabs 2021-05-23 11:57:04 -07:00
nightmareci
6b2252e6d9 Implemented custom love.run to get lower latency 2021-05-23 11:07:07 -07:00
Ishaan Bhardwaj
e1741440f2 Fixed an edge case with the last save commit 2021-05-22 21:42:14 -04:00
Ishaan Bhardwaj
c56f290921 Fixed a bug where the game would sometimes not save on macOS
Version bump to beta5.2
2021-05-22 21:19:33 -04:00
Ishaan Bhardwaj
86e975f929 Fixed up an edge case in immobile spin 2021-05-22 14:41:51 -04:00
Ishaan Bhardwaj
9f8e9a9778 Changed additive gravity behavior for main TGM modes 2021-05-21 15:34:50 -04:00
Ishaan Bhardwaj
62f9475fa9 Small cosmetic change to input config menus 2021-05-21 15:32:28 -04:00
Ishaan Bhardwaj
99d3732d00 Bump to v0.3-beta5.1, release tomorrow 2021-05-20 23:25:24 -04:00
Ishaan Bhardwaj
f5121b62e5 Added bigint comparison metamethods 2021-05-15 22:39:15 -04:00
Ishaan Bhardwaj
cbdbfa6633 Fixed a small cosmetic issue in Survival A1 2021-04-26 21:51:42 -04:00
Ishaan Bhardwaj
1b1abc9792 Fixed an issue with buffer lock inputs 2021-04-20 16:11:49 -04:00
Ishaan Bhardwaj
894e99e677 Cambridge has a logo now! 2021-04-16 22:14:59 -04:00
Ishaan Bhardwaj
d4b619da89 Fixed an edge case with last commit 2021-04-08 13:17:34 -04:00
Ishaan Bhardwaj
3766149cb7 Fixed a 0 ARR gravity bug 2021-04-08 11:55:36 -04:00
Ishaan Bhardwaj
449ca16bc4 Updated to be on rebrand 2021-04-01 14:11:38 -04:00
Ishaan Bhardwaj
71d76e8a6b Fixed Death torikan (why was this changed?) 2021-03-30 22:08:48 -04:00
Ishaan Bhardwaj
3bdc6e1b2d HOTFIX TO BETA5: Fixed another floorkick issue with ARS 2021-03-30 21:29:09 -04:00
Ishaan Bhardwaj
d9b6c85704 Fix up credits a bit, add new people 2021-03-28 10:03:27 -04:00
31 changed files with 556 additions and 598 deletions

View File

@@ -5,24 +5,12 @@ Cambridge
Welcome to Cambridge, the next open-source falling-block game engine! Welcome to Cambridge, the next open-source falling-block game engine!
The project is written and maintained exclusively by [SashLilac](https://github.com/SashLilac), [joezeng](https://github.com/joezeng) and [Oshisaure](https://github.com/oshisaure)! The project is written and maintained exclusively by [Milla](https://github.com/MillaBasset), [joezeng](https://github.com/joezeng) and [Oshisaure](https://github.com/oshisaure)!
The Discord server has been reopened! https://discord.gg/AADZUmgsph The Discord server has been reopened! https://discord.gg/AADZUmgsph
The game also has a website now with more detail than seen on this README: https://t-sp.in/cambridge The game also has a website now with more detail than seen on this README: https://t-sp.in/cambridge
Credits
-------
- [Lilla Oshisaure](https://www.youtube.com/user/LeSpyroshisaure) for being my co-dev!
- [joezeng](https://github.com/joezeng) for the original project, and for offering to help with the expansion!
- [The Tetra Legends Discord](http://discord.com/invite/7hMx5r2) for supporting me and playtesting!
- [The Absolute Plus](https://discord.gg/6Gf2awJ) for being another source of motivation!
More special thanks can be found in-game, under the "Credits" menu.
![Cambridge Logo](https://cdn.discordapp.com/attachments/625496179433668635/763363717730664458/Icon_2.png)
Playing the game Playing the game
---------------- ----------------
@@ -32,13 +20,13 @@ You do not need LÖVE on Windows, as it comes bundled with the program.
#### Stable release #### Stable release
To get the stable release, simply download either `cambridge-win32.zip` (32-bit) or `cambridge-windows.zip` (64-bit) in the [latest release](https://github.com/sashlilac/cambridge/releases/latest). To get the stable release, simply download either `cambridge-win32.zip` (32-bit) or `cambridge-windows.zip` (64-bit) in the [latest release](https://github.com/MillaBasset/cambridge/releases/latest).
All assets needed are bundled with the executable. All assets needed are bundled with the executable.
#### Bleeding edge #### Bleeding edge
If you want the bleeding edge version, download [this](https://github.com/SashLilac/cambridge/archive/master.zip). If you want the bleeding edge version, download [this](https://github.com/MillaBasset/cambridge/archive/master.zip).
Extract the ZIP, open a Command Prompt at the folder you extracted Cambridge to, then run this command: Extract the ZIP, open a Command Prompt at the folder you extracted Cambridge to, then run this command:
@@ -66,7 +54,7 @@ You can download the .love file in the latest release, and run it with:
Clone the repository in git: Clone the repository in git:
git clone https://github.com/SashLilac/cambridge git clone https://github.com/MillaBasset/cambridge
Alternatively, download the source code ZIP in the latest release. Alternatively, download the source code ZIP in the latest release.
@@ -78,7 +66,7 @@ It should run automatically!
## Installing modpacks ## Installing modpacks
For instructions on how to install modpacks, go to [this](https://github.com/SashLilac/cambridge-modpack) mod pack to get a taste of the mod potential. For instructions on how to install modpacks, go to [this](https://github.com/MillaBasset/cambridge-modpack) mod pack to get a taste of the mod potential.
License License
------- -------
@@ -90,3 +78,32 @@ community, as well as borrowed from other places, either with licensing
or as placeholders until suitable material can be found that is properly or as placeholders until suitable material can be found that is properly
licensed. Their original sources, and copyright notices if applicable, are licensed. Their original sources, and copyright notices if applicable, are
listed in the file SOURCES. listed in the file SOURCES.
Credits
-------
- [Lilla Oshisaure](https://www.youtube.com/user/LeSpyroshisaure) for being my co-dev!
- [joezeng](https://github.com/joezeng) for the original project, and for offering to help with the expansion!
- [The Tetra Legends Discord](http://discord.com/invite/7hMx5r2) for supporting me and playtesting!
- [The Absolute Plus](https://discord.gg/6Gf2awJ) for being another source of motivation!
More special thanks can be found in-game, under the "Credits" menu.
Other Notable Games
-------------------
- [TGMsim](https://github.com/2Tie/TGMsim) by 2Tie
- [Multimino](https://gamejolt.com/games/multimino/556683) by Axel Fox
- [Tetra Legends](https://tetralegends.app) by Dr Ocelot
- [ZTrix](https://discord.gg/MGhqCBDGNH) by Electra
- [Shiromino](https://github.com/shiromino/shiromino) by Felicity/nightmareci/kdex
- [Cursed Blocks](https://github.com/Manabender/Cursed-Blocks) by Manabender
- Picoris 1/2 by MarkGamed
- [Tetra Online](https://github.com/Juan-Cartes/Tetra-Offline) by Mine
- [Techmino](https://discord.gg/6Yuww44tq8) by MrZ
- [TETR.IO](https://tetr.io) by osk
- [Master of Blocks](https://discord.gg/72FZ49mjWh) by Phoenix Flare
- [Spirit Drop](https://rayblastgames.com/spiritdrop.php) by RayRay26
- [stackfuse](https://github.com/sinefuse/stackfuse) by sinefuse
![Cambridge Logo](https://cdn.discordapp.com/attachments/625496179433668635/763363717730664458/Icon_2.png)

View File

@@ -6,5 +6,6 @@ function love.conf(t)
t.window.title = "Cambridge" t.window.title = "Cambridge"
t.window.width = 640 t.window.width = 640
t.window.height = 480 t.window.height = 480
t.window.icon = "res/img/cambridge_icon.png"
t.window.vsync = false t.window.vsync = false
end end

View File

@@ -12,8 +12,8 @@ local mt = {
__add = function(lhs, rhs) __add = function(lhs, rhs)
return bigint.add(lhs, rhs) return bigint.add(lhs, rhs)
end, end,
__unm = function() __unm = function(arg)
return bigint.negate(self) return bigint.negate(arg)
end, end,
__sub = function(lhs, rhs) __sub = function(lhs, rhs)
return bigint.subtract(lhs, rhs) return bigint.subtract(lhs, rhs)
@@ -30,8 +30,17 @@ local mt = {
__pow = function(lhs, rhs) __pow = function(lhs, rhs)
return bigint.exponentiate(lhs, rhs) return bigint.exponentiate(lhs, rhs)
end, end,
__tostring = function() __tostring = function(arg)
return bigint.unserialize(self, "s") return bigint.unserialize(arg, "s")
end,
__eq = function(lhs, rhs)
return bigint.compare(lhs, rhs, "==")
end,
__lt = function(lhs, rhs)
return bigint.compare(lhs, rhs, "<")
end,
__le = function(lhs, rhs)
return bigint.compare(lhs, rhs, "<=")
end end
} }

View File

@@ -9,31 +9,38 @@ local current_bgm = nil
local bgm_locked = false local bgm_locked = false
function switchBGM(sound, subsound) function switchBGM(sound, subsound)
if bgm_locked then return end
if current_bgm ~= nil then if current_bgm ~= nil then
current_bgm:stop() current_bgm:stop()
end end
if subsound ~= nil then if bgm_locked or config.bgm_volume <= 0 then
current_bgm = bgm[sound][subsound] current_bgm = nil
resetBGMFadeout()
elseif sound ~= nil then elseif sound ~= nil then
current_bgm = bgm[sound] if subsound ~= nil then
resetBGMFadeout() current_bgm = bgm[sound][subsound]
else
current_bgm = bgm[sound]
end
else else
current_bgm = nil current_bgm = nil
end end
if current_bgm ~= nil then
resetBGMFadeout()
end
end end
function switchBGMLoop(sound, subsound) function switchBGMLoop(sound, subsound)
if bgm_locked then return end
switchBGM(sound, subsound) switchBGM(sound, subsound)
current_bgm:setLooping(true) if current_bgm then current_bgm:setLooping(true) end
end end
function lockBGM() function lockBGM()
bgm_locked = true bgm_locked = true
end end
function unlockBGM()
bgm_locked = false
end
local fading_bgm = false local fading_bgm = false
local fadeout_time = 0 local fadeout_time = 0
local total_fadeout_time = 0 local total_fadeout_time = 0
@@ -53,7 +60,7 @@ function resetBGMFadeout(time)
end end
function processBGMFadeout(dt) function processBGMFadeout(dt)
if fading_bgm then if current_bgm and fading_bgm then
fadeout_time = fadeout_time - dt fadeout_time = fadeout_time - dt
if fadeout_time < 0 then if fadeout_time < 0 then
fadeout_time = 0 fadeout_time = 0

View File

@@ -1,8 +1,19 @@
local binser = require 'libs.binser' local binser = require 'libs.binser'
function loadSave() function loadSave()
config = loadFromFile('config.sav') local info = love.filesystem.getInfo(
highscores = loadFromFile('highscores.sav') love.filesystem.getSaveDirectory(), "directory"
)
if not info then
love.filesystem.remove(love.filesystem.getSaveDirectory())
love.filesystem.createDirectory(love.filesystem.getSaveDirectory())
end
config = loadFromFile(
love.filesystem.getSaveDirectory() .. '/config.sav'
)
highscores = loadFromFile(
love.filesystem.getSaveDirectory() .. '/highscores.sav'
)
end end
function loadFromFile(filename) function loadFromFile(filename)
@@ -31,7 +42,7 @@ function initConfig()
end end
if not config.input then if not config.input then
scene = KeyConfigScene() scene = InputConfigScene()
else else
if config.current_mode then current_mode = config.current_mode end if config.current_mode then current_mode = config.current_mode end
if config.current_ruleset then current_ruleset = config.current_ruleset end if config.current_ruleset then current_ruleset = config.current_ruleset end
@@ -40,9 +51,13 @@ function initConfig()
end end
function saveConfig() function saveConfig()
binser.writeFile('config.sav', config) binser.writeFile(
love.filesystem.getSaveDirectory() .. '/config.sav', config
)
end end
function saveHighscores() function saveHighscores()
binser.writeFile('highscores.sav', highscores) binser.writeFile(
love.filesystem.getSaveDirectory() .. '/highscores.sav', highscores
)
end end

View File

@@ -27,33 +27,37 @@ sounds = {
} }
function playSE(sound, subsound) function playSE(sound, subsound)
if subsound == nil then if sound ~= nil then
sounds[sound]:setVolume(config.sfx_volume) if subsound ~= nil then
if sounds[sound]:isPlaying() then sounds[sound][subsound]:setVolume(config.sfx_volume)
sounds[sound]:stop() if sounds[sound][subsound]:isPlaying() then
sounds[sound][subsound]:stop()
end
sounds[sound][subsound]:play()
else
sounds[sound]:setVolume(config.sfx_volume)
if sounds[sound]:isPlaying() then
sounds[sound]:stop()
end
sounds[sound]:play()
end end
sounds[sound]:play()
else
sounds[sound][subsound]:setVolume(config.sfx_volume)
if sounds[sound][subsound]:isPlaying() then
sounds[sound][subsound]:stop()
end
sounds[sound][subsound]:play()
end end
end end
function playSEOnce(sound, subsound) function playSEOnce(sound, subsound)
if subsound == nil then if sound ~= nil then
sounds[sound]:setVolume(config.sfx_volume) if subsound ~= nil then
if sounds[sound]:isPlaying() then sounds[sound][subsound]:setVolume(config.sfx_volume)
return if sounds[sound][subsound]:isPlaying() then
return
end
sounds[sound][subsound]:play()
else
sounds[sound]:setVolume(config.sfx_volume)
if sounds[sound]:isPlaying() then
return
end
sounds[sound]:play()
end end
sounds[sound]:play()
else
sounds[sound][subsound]:setVolume(config.sfx_volume)
if sounds[sound][subsound]:isPlaying() then
return
end
sounds[sound][subsound]:play()
end end
end end

View File

@@ -1 +1 @@
version = "v0.3-beta5" version = "v0.3-beta6"

135
main.lua
View File

@@ -18,9 +18,9 @@ function love.load()
--config["fullscreen"] = false --config["fullscreen"] = false
love.window.setMode(love.graphics.getWidth(), love.graphics.getHeight(), {resizable = true}); love.window.setMode(love.graphics.getWidth(), love.graphics.getHeight(), {resizable = true});
-- used for screenshots -- used for screenshots
GLOBAL_CANVAS = love.graphics.newCanvas() GLOBAL_CANVAS = love.graphics.newCanvas()
-- init config -- init config
initConfig() initConfig()
@@ -55,49 +55,11 @@ function initModules()
return tostring(a.name):gsub("%d+",padnum) < tostring(b.name):gsub("%d+",padnum) end) return tostring(a.name):gsub("%d+",padnum) < tostring(b.name):gsub("%d+",padnum) end)
end end
local TARGET_FPS = 60
local SAMPLE_SIZE = 60
local rolling_samples = {}
local rolling_total = 0
local average_n = 0
local frame = 0
function getSmoothedDt(dt)
rolling_total = rolling_total + dt
frame = frame + 1
if frame > SAMPLE_SIZE then frame = frame - SAMPLE_SIZE end
if average_n == SAMPLE_SIZE then
rolling_total = rolling_total - rolling_samples[frame]
else
average_n = average_n + 1
end
rolling_samples[frame] = dt
return rolling_total / average_n
end
local update_time = 0.52
function love.update(dt)
processBGMFadeout(dt)
local old_update_time = update_time
update_time = update_time + getSmoothedDt(dt) * TARGET_FPS
updates = 0
while (update_time >= 1.02) do
scene:update()
updates = updates + 1
update_time = update_time - 1
end
if math.abs(update_time - old_update_time) < 0.02 then
update_time = old_update_time
end
end
function love.draw() function love.draw()
love.graphics.setCanvas(GLOBAL_CANVAS) love.graphics.setCanvas(GLOBAL_CANVAS)
love.graphics.clear() love.graphics.clear()
love.graphics.push() love.graphics.push()
-- get offset matrix -- get offset matrix
love.graphics.setDefaultFilter("linear", "nearest") love.graphics.setDefaultFilter("linear", "nearest")
@@ -109,13 +71,13 @@ function love.draw()
(height - scale_factor * 480) / 2 (height - scale_factor * 480) / 2
) )
love.graphics.scale(scale_factor) love.graphics.scale(scale_factor)
scene:render() scene:render()
love.graphics.pop() love.graphics.pop()
love.graphics.setCanvas() love.graphics.setCanvas()
love.graphics.setColor(1,1,1,1) love.graphics.setColor(1,1,1,1)
love.graphics.draw(GLOBAL_CANVAS) love.graphics.draw(GLOBAL_CANVAS)
end end
function love.keypressed(key, scancode) function love.keypressed(key, scancode)
@@ -134,16 +96,16 @@ function love.keypressed(key, scancode)
scene.restart_message = true scene.restart_message = true
if config.secret then playSE("mode_decide") if config.secret then playSE("mode_decide")
else playSE("erase") end else playSE("erase") end
-- f12 is reserved for saving screenshots -- f12 is reserved for saving screenshots
elseif scancode == "f12" then elseif scancode == "f12" then
local ss_name = os.date("ss/%Y-%m-%d_%H-%M-%S.png") local ss_name = os.date("ss/%Y-%m-%d_%H-%M-%S.png")
local info = love.filesystem.getInfo("ss") local info = love.filesystem.getInfo("ss", "directory")
if not info or info.type ~= "directory" then if not info then
love.filesystem.remove("ss") love.filesystem.remove("ss")
love.filesystem.createDirectory("ss") love.filesystem.createDirectory("ss")
end end
print("Saving screenshot as "..ss_name) print("Saving screenshot as "..ss_name)
GLOBAL_CANVAS:newImageData():encode("png", ss_name) GLOBAL_CANVAS:newImageData():encode("png", ss_name)
-- function keys are reserved -- function keys are reserved
elseif string.match(scancode, "^f[1-9]$") or string.match(scancode, "^f[1-9][0-9]+$") then elseif string.match(scancode, "^f[1-9]$") or string.match(scancode, "^f[1-9][0-9]+$") then
return return
@@ -305,6 +267,59 @@ function love.focus(f)
end end
function love.resize(w, h) function love.resize(w, h)
GLOBAL_CANVAS:release() GLOBAL_CANVAS:release()
GLOBAL_CANVAS = love.graphics.newCanvas(w, h) GLOBAL_CANVAS = love.graphics.newCanvas(w, h)
end end
local TARGET_FPS = 60
function love.run()
if love.load then love.load(love.arg.parseGameArguments(arg), arg) end
if love.timer then love.timer.step() end
local dt = 0
local last_time = love.timer.getTime()
local time_accumulator = 0
return function()
if love.event then
love.event.pump()
for name, a,b,c,d,e,f in love.event.poll() do
if name == "quit" then
if not love.quit or not love.quit() then
return a or 0
end
end
love.handlers[name](a,b,c,d,e,f)
end
end
if love.timer then
processBGMFadeout(love.timer.step())
end
if scene and scene.update and love.timer then
scene:update()
local frame_duration = 1.0 / TARGET_FPS
if time_accumulator < frame_duration then
if love.graphics and love.graphics.isActive() and love.draw then
love.graphics.origin()
love.graphics.clear(love.graphics.getBackgroundColor())
love.draw()
love.graphics.present()
end
local end_time = last_time + frame_duration
local time = love.timer.getTime()
while time < end_time do
love.timer.sleep(0.001)
time = love.timer.getTime()
end
time_accumulator = time_accumulator + time - last_time
end
time_accumulator = time_accumulator - frame_duration
end
last_time = love.timer.getTime()
end
end

BIN
res/img/cambridge_icon.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 2.5 KiB

View File

@@ -4,6 +4,8 @@ CreditsScene.title = "Credits"
function CreditsScene:new() function CreditsScene:new()
self.frames = 0 self.frames = 0
-- higher = slower
self.scroll_speed = 1.9
switchBGM("credit_roll", "gm3") switchBGM("credit_roll", "gm3")
end end
@@ -11,16 +13,18 @@ function CreditsScene:update()
if love.window.hasFocus() then if love.window.hasFocus() then
self.frames = self.frames + 1 self.frames = self.frames + 1
end end
if self.frames >= 4200 then if self.frames >= 2100 * self.scroll_speed then
playSE("mode_decide") playSE("mode_decide")
scene = TitleScene() scene = TitleScene()
switchBGM(nil) switchBGM(nil)
elseif self.frames == 3600 then elseif self.frames == math.floor(1950 * self.scroll_speed) then
fadeoutBGM(2) fadeoutBGM(2)
end end
end end
function CreditsScene:render() function CreditsScene:render()
local offset = self.frames / self.scroll_speed
love.graphics.setColor(1, 1, 1, 1) love.graphics.setColor(1, 1, 1, 1)
love.graphics.draw( love.graphics.draw(
backgrounds[19], backgrounds[19],
@@ -29,31 +33,43 @@ function CreditsScene:render()
) )
love.graphics.setFont(font_3x5_4) love.graphics.setFont(font_3x5_4)
love.graphics.print("Cambridge Credits", 320, 500 - self.frames / 2) love.graphics.print("Cambridge Credits", 320, 500 - offset)
love.graphics.print("THANK YOU\nFOR PLAYING!", 320, math.max(1750 - self.frames / 2, 240)) love.graphics.print("THANK YOU\nFOR PLAYING!", 320, math.max(2010 - offset, 240))
love.graphics.setFont(font_3x5_3) love.graphics.setFont(font_3x5_3)
love.graphics.print("Game Developers", 320, 550 - self.frames / 2) love.graphics.print("Game Developers", 320, 550 - offset)
love.graphics.print("Project Heads", 320, 640 - self.frames / 2) love.graphics.print("Project Heads", 320, 640 - offset)
love.graphics.print("Other Game Developers", 320, 730 - self.frames / 2) love.graphics.print("Notable Game Developers", 320, 730 - offset)
love.graphics.print("Special Thanks", 320, 900 - self.frames / 2) love.graphics.print("Special Thanks", 320, 980 - offset)
love.graphics.print("- SashLilac / SpinTriple", 320, math.max(2000 - self.frames / 2, 320)) love.graphics.print("- Milla", 320, math.max(2090 - offset, 320))
love.graphics.setFont(font_3x5_2) love.graphics.setFont(font_3x5_2)
love.graphics.print("Oshisaure\nJoe Zeng", 320, 590 - self.frames / 2) love.graphics.print("Oshisaure\nJoe Zeng", 320, 590 - offset)
love.graphics.print("Mizu\nHailey", 320, 680 - self.frames / 2) love.graphics.print("Mizu\nMarkGamed", 320, 680 - offset)
love.graphics.print("Axel Fox - Multimino\nMine - Tetra Online\nDr Ocelot - Tetra Legends\nFelicity / nightmareci - Shiromino\n2Tie - TGMsim\nPhoenix Flare - Master of Blocks", 320, 770 - self.frames / 2)
love.graphics.print( love.graphics.print(
"RocketLanterns\nCylinderKnot\nHammrTime\nKirby703\nMattMayuga\nMyPasswordIsWeak\n" .. "2Tie - TGMsim\nAxel Fox - Multimino\nDr Ocelot - Tetra Legends\n" ..
"Nikki Karissa\noffwo\nsinefuse\nTetro48\nTimmSkiller\nuser74003\nAgentBasey\n" .. "Electra - ZTrix\nFelicity/nightmareci/kdex - Shiromino\n" ..
"CheeZed_Fish\neightsixfivezero\nEricICX\ngizmo4487\nM1ssing0\nMarkGamed7794\n" .. "Mine - Tetra Online\nMrZ - Techmino\nosk - TETR.IO\n" ..
"pokemonfan1937\nSimon\nstratus\nZaptorZap\nArchina\nOliver\ncolour_thief\n" .. "Phoenix Flare - Master of Blocks\nRayRay26 - Spirit Drop\n" ..
"Caithness\nkdex\nzid\nsaphie\nSuper302\nAurora\nswitchpalacecorner\nKitaru\n" .. "sinefuse - stackfuse",
"JBroms\nMany more I definitely missed!\n" .. 320, 770 - offset
"The Absolute PLUS Discord\nTetra Legends Discord\nTetra Online Discord\n" .. )
"Multimino Discord\nHard Drop Discord\nCambridge Discord (R.I.P.)\n" .. love.graphics.print(
"321MrHaatz\nAdventium\nAgentBasey\nArchina\nAurora\n" ..
"Caithness\nCheez\ncolour_thief\nCommando\nCublex\n" ..
"CylinderKnot\neightsixfivezero\nEricICX\nGesomaru\n" ..
"gizmo4487\nJBroms\nKirby703\nKitaru\n" ..
"M1ssing0\nMattMayuga\nMyPasswordIsWeak\n" ..
"Nikki Karissa\noffwo\nOliver\nPineapple\npokemonfan1937\n" ..
"Pyra Neoxi\nRDST64\nRocketLanterns\nRustyFoxxo\n" ..
"saphie\nShelleloch\nSimon\nstratus\nSuper302\n" ..
"switchpalacecorner\nterpyderp\nTetrian22\nTetro48\nThatCookie\n" ..
"TimmSkiller\nTrixciel\nuser74003\nZaptorZap\nZircean\n" ..
"All other contributors and friends!\nThe Absolute PLUS Discord\n" ..
"Tetra Legends Discord\nTetra Online Discord\nMultimino Discord\n" ..
"Hard Drop Discord\nRusty's Systemspace\nCambridge Discord\n" ..
"And to you, the player!", "And to you, the player!",
320, 940 - self.frames / 2 320, 1020 - offset
) )
end end

View File

@@ -42,79 +42,17 @@ function GameScene:update()
end end
function GameScene:render() function GameScene:render()
love.graphics.setColor(1, 1, 1, 1) self.game:draw(self.paused)
love.graphics.draw(
backgrounds[self.game:getBackground()],
0, 0, 0,
0.5, 0.5
)
-- game frame
if self.game.grid.width == 10 and self.game.grid.height == 24 then
love.graphics.draw(misc_graphics["frame"], 48, 64)
end
love.graphics.setColor(0, 0, 0, 200)
love.graphics.rectangle(
"fill", 64, 80,
16 * self.game.grid.width, 16 * (self.game.grid.height - 4)
)
if self.game.grid.width ~= 10 or self.game.grid.height ~= 24 then
love.graphics.setColor(174/255, 83/255, 76/255, 1)
love.graphics.setLineWidth(8)
love.graphics.line(
60,76,
68+16*self.game.grid.width,76,
68+16*self.game.grid.width,84+16*(self.game.grid.height-4),
60,84+16*(self.game.grid.height-4),
60,76
)
love.graphics.setColor(203/255, 137/255, 111/255, 1)
love.graphics.setLineWidth(4)
love.graphics.line(
60,76,
68+16*self.game.grid.width,76,
68+16*self.game.grid.width,84+16*(self.game.grid.height-4),
60,84+16*(self.game.grid.height-4),
60,76
)
love.graphics.setLineWidth(1)
end
self.game:drawGrid()
if self.game.lcd > 0 then self.game:drawLineClearAnimation() end
self.game:drawPiece()
self.game:drawNextQueue(self.ruleset)
self.game:drawScoringInfo()
-- ready/go graphics
if self.game.ready_frames <= 100 and self.game.ready_frames > 52 then
love.graphics.draw(misc_graphics["ready"], 144 - 50, 240 - 14)
elseif self.game.ready_frames <= 50 and self.game.ready_frames > 2 then
love.graphics.draw(misc_graphics["go"], 144 - 27, 240 - 14)
end
self.game:drawCustom()
love.graphics.setFont(font_3x5_2)
if config.gamesettings.display_gamemode == 1 then
love.graphics.printf(self.game.name .. " - " .. self.ruleset.name, 0, 460, 640, "left")
end
love.graphics.setFont(font_3x5_3)
if self.paused then love.graphics.print("PAUSED!", 80, 100) end
if self.game.completed then
self.game:onGameComplete()
elseif self.game.game_over then
self.game:onGameOver()
end
end end
function GameScene:onInputPress(e) function GameScene:onInputPress(e)
if (self.game.game_over or self.game.completed) and (e.input == "menu_decide" or e.input == "menu_back" or e.input == "retry") then if (
self.game.game_over or self.game.completed
) and (
e.input == "menu_decide" or
e.input == "menu_back" or
e.input == "retry"
) then
highscore_entry = self.game:getHighscoreData() highscore_entry = self.game:getHighscoreData()
highscore_hash = self.game.hash .. "-" .. self.ruleset.hash highscore_hash = self.game.hash .. "-" .. self.ruleset.hash
submitHighscore(highscore_hash, highscore_entry) submitHighscore(highscore_hash, highscore_entry)

View File

@@ -17,7 +17,7 @@ ConfigScene.options = {
{"smooth_movement", "Smooth Piece Drop", false, {"On", "Off"}}, {"smooth_movement", "Smooth Piece Drop", false, {"On", "Off"}},
{"synchroes_allowed", "Synchroes", false, {"Per ruleset", "On", "Off"}}, {"synchroes_allowed", "Synchroes", false, {"Per ruleset", "On", "Off"}},
{"diagonal_input", "Diagonal Input", false, {"On", "Off"}}, {"diagonal_input", "Diagonal Input", false, {"On", "Off"}},
{"buffer_lock", "Buffer Lock Inputs", false, {"On", "Off"}}, {"buffer_lock", "Buffer Drop Type", false, {"Off", "Hold", "Tap"}},
{"sfx_volume", "SFX", true, "sfxSlider"}, {"sfx_volume", "SFX", true, "sfxSlider"},
{"bgm_volume", "BGM", true, "bgmSlider"}, {"bgm_volume", "BGM", true, "bgmSlider"},
} }

View File

@@ -29,7 +29,7 @@ function ConfigScene:render()
love.graphics.print("INPUT CONFIG", 80, 40) love.graphics.print("INPUT CONFIG", 80, 40)
love.graphics.setFont(font_3x5_2) love.graphics.setFont(font_3x5_2)
love.graphics.print("Which controls do you want to change?", 80, 90) love.graphics.print("Which controls do you want to configure?", 80, 90)
love.graphics.setColor(1, 1, 1, 0.5) love.graphics.setColor(1, 1, 1, 0.5)
love.graphics.rectangle("fill", 75, 118 + 50 * self.menu_state, 200, 33) love.graphics.rectangle("fill", 75, 118 + 50 * self.menu_state, 200, 33)
@@ -56,7 +56,9 @@ function ConfigScene:onInputPress(e)
elseif e.input == "down" or e.scancode == "down" then elseif e.input == "down" or e.scancode == "down" then
self:changeOption(1) self:changeOption(1)
playSE("cursor") playSE("cursor")
elseif e.input == "menu_back" or e.scancode == "backspace" or e.scancode == "delete" then elseif config.input and (
e.input == "menu_back" or e.scancode == "backspace" or e.scancode == "delete"
) then
scene = SettingsScene() scene = SettingsScene()
end end
end end

View File

@@ -61,7 +61,7 @@ function KeyConfigScene:render()
if self.input_state > table.getn(configurable_inputs) then if self.input_state > table.getn(configurable_inputs) then
love.graphics.print("press enter to confirm, delete/backspace to retry" .. (config.input and ", escape to cancel" or "")) love.graphics.print("press enter to confirm, delete/backspace to retry" .. (config.input and ", escape to cancel" or ""))
else else
love.graphics.print("press key input for " .. configurable_inputs[self.input_state] .. ", tab to skip" .. (config.input and ", escape to cancel" or ""), 0, 0) love.graphics.print("press key input for " .. configurable_inputs[self.input_state] .. ", tab to skip, escape to cancel", 0, 0)
love.graphics.print("function keys (F1, F2, etc.), escape, and tab can't be changed", 0, 20) love.graphics.print("function keys (F1, F2, etc.), escape, and tab can't be changed", 0, 20)
end end
end end
@@ -69,8 +69,7 @@ end
function KeyConfigScene:onInputPress(e) function KeyConfigScene:onInputPress(e)
if e.type == "key" then if e.type == "key" then
-- function keys, escape, and tab are reserved and can't be remapped -- function keys, escape, and tab are reserved and can't be remapped
if e.scancode == "escape" and config.input then if e.scancode == "escape" then
-- cancel only if there was an input config already
scene = InputConfigScene() scene = InputConfigScene()
elseif self.input_state > table.getn(configurable_inputs) then elseif self.input_state > table.getn(configurable_inputs) then
if e.scancode == "return" then if e.scancode == "return" then
@@ -89,7 +88,7 @@ function KeyConfigScene:onInputPress(e)
elseif e.scancode == "tab" then elseif e.scancode == "tab" then
self.set_inputs[configurable_inputs[self.input_state]] = "skipped" self.set_inputs[configurable_inputs[self.input_state]] = "skipped"
self.input_state = self.input_state + 1 self.input_state = self.input_state + 1
elseif e.scancode ~= "escape" then elseif e.scancode ~= "escape" and not self.new_input[e.scancode] then
-- all other keys can be configured -- all other keys can be configured
self.set_inputs[configurable_inputs[self.input_state]] = "key " .. love.keyboard.getKeyFromScancode(e.scancode) .. " (" .. e.scancode .. ")" self.set_inputs[configurable_inputs[self.input_state]] = "key " .. love.keyboard.getKeyFromScancode(e.scancode) .. " (" .. e.scancode .. ")"
self.new_input[e.scancode] = configurable_inputs[self.input_state] self.new_input[e.scancode] = configurable_inputs[self.input_state]

View File

@@ -62,7 +62,7 @@ function StickConfigScene:render()
if self.input_state > table.getn(configurable_inputs) then if self.input_state > table.getn(configurable_inputs) then
love.graphics.print("press enter to confirm, delete/backspace to retry" .. (config.input and ", escape to cancel" or "")) love.graphics.print("press enter to confirm, delete/backspace to retry" .. (config.input and ", escape to cancel" or ""))
else else
love.graphics.print("press joystick input for " .. configurable_inputs[self.input_state] .. ", tab to skip" .. (config.input and ", escape to cancel" or ""), 0, 0) love.graphics.print("press joystick input for " .. configurable_inputs[self.input_state] .. ", tab to skip, escape to cancel", 0, 0)
end end
self.axis_timer = self.axis_timer + 1 self.axis_timer = self.axis_timer + 1
@@ -82,9 +82,11 @@ function StickConfigScene:onInputPress(e)
elseif self.input_state > table.getn(configurable_inputs) then elseif self.input_state > table.getn(configurable_inputs) then
if e.scancode == "return" then if e.scancode == "return" then
-- save new input, then load next scene -- save new input, then load next scene
config.input.joysticks = self.new_input local had_config = config.input ~= nil
if not config.input then config.input = {} end
config.input.joysticks = self.new_input
saveConfig() saveConfig()
scene = InputConfigScene() scene = had_config and InputConfigScene() or TitleScene()
elseif e.scancode == "delete" or e.scancode == "backspace" then elseif e.scancode == "delete" or e.scancode == "backspace" then
-- retry -- retry
self.input_state = 1 self.input_state = 1
@@ -102,6 +104,7 @@ function StickConfigScene:onInputPress(e)
if not self.new_input[e.name].buttons then if not self.new_input[e.name].buttons then
self.new_input[e.name].buttons = {} self.new_input[e.name].buttons = {}
end end
if self.new_input[e.name].buttons[e.button] then return end
self.set_inputs[configurable_inputs[self.input_state]] = self.set_inputs[configurable_inputs[self.input_state]] =
"jbtn " .. "jbtn " ..
e.button .. e.button ..
@@ -117,6 +120,9 @@ function StickConfigScene:onInputPress(e)
if not self.new_input[e.name].axes[e.axis] then if not self.new_input[e.name].axes[e.axis] then
self.new_input[e.name].axes[e.axis] = {} self.new_input[e.name].axes[e.axis] = {}
end end
if (
self.new_input[e.name].axes[e.axis][e.value >= 1 and "positive" or "negative"]
) then return end
self.set_inputs[configurable_inputs[self.input_state]] = self.set_inputs[configurable_inputs[self.input_state]] =
"jaxis " .. "jaxis " ..
(e.value >= 1 and "+" or "-") .. e.axis .. (e.value >= 1 and "+" or "-") .. e.axis ..
@@ -135,6 +141,9 @@ function StickConfigScene:onInputPress(e)
if not self.new_input[e.name].hats[e.hat] then if not self.new_input[e.name].hats[e.hat] then
self.new_input[e.name].hats[e.hat] = {} self.new_input[e.name].hats[e.hat] = {}
end end
if self.new_input[e.name].hats[e.hat][e.direction] then
return
end
self.set_inputs[configurable_inputs[self.input_state]] = self.set_inputs[configurable_inputs[self.input_state]] =
"jhat " .. "jhat " ..
e.hat .. " " .. e.direction .. e.hat .. " " .. e.direction ..

View File

@@ -118,10 +118,11 @@ function Piece:lockIfBottomed(grid)
end end
function Piece:addGravity(gravity, grid, classic_lock) function Piece:addGravity(gravity, grid, classic_lock)
gravity = gravity / (self.big and 2 or 1)
local new_gravity = self.gravity + gravity local new_gravity = self.gravity + gravity
if self:isDropBlocked(grid) then if self:isDropBlocked(grid) then
if classic_lock then if classic_lock then
self.gravity = math.min(1, new_gravity) self.gravity = new_gravity
else else
self.gravity = 0 self.gravity = 0
self.lock_delay = self.lock_delay + 1 self.lock_delay = self.lock_delay + 1

View File

@@ -85,10 +85,11 @@ function GameMode:getDasCutDelay() return 0 end
function GameMode:getGravity() return 1/64 end function GameMode:getGravity() return 1/64 end
function GameMode:getNextPiece(ruleset) function GameMode:getNextPiece(ruleset)
local shape = self.used_randomizer:nextPiece()
return { return {
skin = self:getSkin(), skin = self:getSkin(),
shape = self.used_randomizer:nextPiece(), shape = shape,
orientation = ruleset:getDefaultOrientation(), orientation = ruleset:getDefaultOrientation(shape),
} }
end end
@@ -156,9 +157,6 @@ function GameMode:update(inputs, ruleset)
if self.enable_hold and inputs["hold"] == true and self.held == false and self.prev_inputs["hold"] == false then if self.enable_hold and inputs["hold"] == true and self.held == false and self.prev_inputs["hold"] == false then
self:hold(inputs, ruleset) self:hold(inputs, ruleset)
self.prev_inputs = inputs self.prev_inputs = inputs
if not self.grid:canPlacePiece(self.piece) then
self.game_over = true
end
return return
end end
@@ -181,7 +179,10 @@ function GameMode:update(inputs, ruleset)
ruleset:processPiece( ruleset:processPiece(
inputs, self.piece, self.grid, self:getGravity(), self.prev_inputs, inputs, self.piece, self.grid, self:getGravity(), self.prev_inputs,
self.move, self:getLockDelay(), self:getDropSpeed(), (
inputs.up and self.lock_on_hard_drop and not self.hard_drop_locked
) and "none" or self.move,
self:getLockDelay(), self:getDropSpeed(),
self.drop_locked, self.hard_drop_locked, self.drop_locked, self.hard_drop_locked,
self.enable_hard_drop, self.additive_gravity, self.classic_lock self.enable_hard_drop, self.additive_gravity, self.classic_lock
) )
@@ -206,14 +207,14 @@ function GameMode:update(inputs, ruleset)
self.piece.last_rotated = false self.piece.last_rotated = false
self:onPieceMove(self.piece, self.grid, piece_dx) self:onPieceMove(self.piece, self.grid, piece_dx)
end end
if (piece_drot ~= 0) then
self.piece.last_rotated = true
self:onPieceRotate(self.piece, self.grid, piece_drot)
end
if (piece_dy ~= 0) then if (piece_dy ~= 0) then
self.piece.last_rotated = false self.piece.last_rotated = false
self:onPieceDrop(self.piece, self.grid, piece_dy) self:onPieceDrop(self.piece, self.grid, piece_dy)
end end
if (piece_drot ~= 0) then
self.piece.last_rotated = true
self:onPieceRotate(self.piece, self.grid, piece_drot)
end
if inputs["up"] == true and if inputs["up"] == true and
self.piece:isDropBlocked(self.grid) and self.piece:isDropBlocked(self.grid) and
@@ -237,12 +238,14 @@ function GameMode:update(inputs, ruleset)
self.lock_on_soft_drop self.lock_on_soft_drop
then then
self.piece.locked = true self.piece.locked = true
self.piece_soft_locked = true
end end
end end
if self.piece.locked == true then if self.piece.locked == true then
-- spin detection, immobile only for now -- spin detection, immobile only for now
if self.immobile_spin_bonus and ( if self.immobile_spin_bonus and
self.piece.last_rotated and (
self.piece:isDropBlocked(self.grid) and self.piece:isDropBlocked(self.grid) and
self.piece:isMoveBlocked(self.grid, { x=-1, y=0 }) and self.piece:isMoveBlocked(self.grid, { x=-1, y=0 }) and
self.piece:isMoveBlocked(self.grid, { x=1, y=0 }) and self.piece:isMoveBlocked(self.grid, { x=1, y=0 }) and
@@ -323,11 +326,13 @@ function GameMode:onPieceEnter() end
function GameMode:onHold() end function GameMode:onHold() end
function GameMode:onSoftDrop(dropped_row_count) function GameMode:onSoftDrop(dropped_row_count)
self.drop_bonus = self.drop_bonus + 1 * dropped_row_count self.drop_bonus = self.drop_bonus + (
(self.piece.big and 2 or 1) * dropped_row_count
)
end end
function GameMode:onHardDrop(dropped_row_count) function GameMode:onHardDrop(dropped_row_count)
self.drop_bonus = self.drop_bonus + 2 * dropped_row_count self:onSoftDrop(dropped_row_count * 2)
end end
function GameMode:onGameOver() function GameMode:onGameOver()
@@ -416,26 +421,38 @@ function GameMode:dasCut()
end end
function GameMode:areCancel(inputs, ruleset) function GameMode:areCancel(inputs, ruleset)
if ruleset.are_cancel and self.piece_hard_dropped and if ruleset.are_cancel and strTrueValues(inputs) ~= "" and
not self.prev_inputs.up and not self.prev_inputs.up and
strTrueValues(inputs) ~= "" then (self.piece_hard_dropped or
(self.piece_soft_locked and not self.prev_inputs.down)) then
self.lcd = 0 self.lcd = 0
self.are = 0 self.are = 0
end end
end end
function GameMode:checkBufferedInputs(inputs)
if (
config.gamesettings.buffer_lock ~= 1 and
not self.prev_inputs["up"] and inputs["up"] and
self.enable_hard_drop
) then
self.buffer_hard_drop = true
end
if (
config.gamesettings.buffer_lock ~= 1 and
not self.prev_inputs["down"] and inputs["down"]
) then
self.buffer_soft_drop = true
end
end
function GameMode:processDelays(inputs, ruleset, drop_speed) function GameMode:processDelays(inputs, ruleset, drop_speed)
if self.ready_frames == 100 then if self.ready_frames == 100 then
playedReadySE = false playedReadySE = false
playedGoSE = false playedGoSE = false
end end
if self.ready_frames > 0 then if self.ready_frames > 0 then
if not self.prev_inputs["up"] and inputs["up"] and self.enable_hard_drop then self:checkBufferedInputs(inputs)
self.buffer_hard_drop = true
end
if not self.prev_inputs["down"] and inputs["down"] then
self.buffer_soft_drop = true
end
if not playedReadySE then if not playedReadySE then
playedReadySE = true playedReadySE = true
playSEOnce("ready") playSEOnce("ready")
@@ -449,12 +466,7 @@ function GameMode:processDelays(inputs, ruleset, drop_speed)
self:initializeOrHold(inputs, ruleset) self:initializeOrHold(inputs, ruleset)
end end
elseif self.lcd > 0 then elseif self.lcd > 0 then
if not self.prev_inputs["up"] and inputs["up"] and self.enable_hard_drop then self:checkBufferedInputs(inputs)
self.buffer_hard_drop = true
end
if not self.prev_inputs["down"] and inputs["down"] then
self.buffer_soft_drop = true
end
self.lcd = self.lcd - 1 self.lcd = self.lcd - 1
self:areCancel(inputs, ruleset) self:areCancel(inputs, ruleset)
if self.lcd == 0 then if self.lcd == 0 then
@@ -467,12 +479,7 @@ function GameMode:processDelays(inputs, ruleset, drop_speed)
end end
end end
elseif self.are > 0 then elseif self.are > 0 then
if not self.prev_inputs["up"] and inputs["up"] and self.enable_hard_drop then self:checkBufferedInputs(inputs)
self.buffer_hard_drop = true
end
if not self.prev_inputs["down"] and inputs["down"] then
self.buffer_soft_drop = true
end
self.are = self.are - 1 self.are = self.are - 1
self:areCancel(inputs, ruleset) self:areCancel(inputs, ruleset)
if self.are == 0 then if self.are == 0 then
@@ -493,6 +500,10 @@ function GameMode:initializeOrHold(inputs, ruleset)
if not self.grid:canPlacePiece(self.piece) then if not self.grid:canPlacePiece(self.piece) then
self.game_over = true self.game_over = true
end end
ruleset:dropPiece(
inputs, self.piece, self.grid, self:getGravity(),
self:getDropSpeed(), self.drop_locked, self.hard_drop_locked
)
end end
function GameMode:hold(inputs, ruleset, ihs) function GameMode:hold(inputs, ruleset, ihs)
@@ -517,55 +528,55 @@ function GameMode:hold(inputs, ruleset, ihs)
if ihs then playSE("ihs") if ihs then playSE("ihs")
else playSE("hold") end else playSE("hold") end
self:onHold() self:onHold()
if not self.grid:canPlacePiece(self.piece) then
self.game_over = true
end
end end
function GameMode:initializeNextPiece(inputs, ruleset, piece_data, generate_next_piece) function GameMode:initializeNextPiece(inputs, ruleset, piece_data, generate_next_piece)
self.piece_hard_dropped = false if not self.buffer_soft_drop and self.lock_drop or (
local gravity = self:getGravity()
self.piece = ruleset:initializePiece(
inputs, piece_data, self.grid, gravity,
self.prev_inputs, self.move,
self:getLockDelay(), self:getDropSpeed(),
self.lock_drop, self.lock_hard_drop, self.big_mode,
(
self.frames == 0 or (ruleset.are and self:getARE() ~= 0)
) and self.irs or false,
self.buffer_hard_drop, self.buffer_soft_drop,
self.lock_on_hard_drop, self.lock_on_soft_drop
)
if self.piece:isDropBlocked(self.grid) and
self.grid:canPlacePiece(self.piece) then
playSE("bottom")
end
if self.buffer_hard_drop then
self.buffer_hard_drop = false
local above_field = (
(config.gamesettings.spawn_positions == 1 and
ruleset.spawn_above_field) or
config.gamesettings.spawn_positions == 3
)
self:onHardDrop(self.piece.position.y - (
self.piece.big and
ruleset.big_spawn_positions[self.piece.shape].y or
ruleset.spawn_positions[self.piece.shape].y) +
(above_field and ruleset:getAboveFieldOffset(
piece_data.shape, piece_data.orientation
) or 0)
)
end
if self.buffer_soft_drop then
self.buffer_soft_drop = false
end
if self.lock_drop or (
not ruleset.are or self:getARE() == 0 not ruleset.are or self:getARE() == 0
) then ) then
self.drop_locked = true self.drop_locked = true
end end
if self.lock_hard_drop or ( if not self.buffer_hard_drop and self.lock_hard_drop or (
not ruleset.are or self:getARE() == 0 not ruleset.are or self:getARE() == 0
) then ) then
self.hard_drop_locked = true self.hard_drop_locked = true
end end
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, self.big_mode,
(
self.frames == 0 or (ruleset.are and self:getARE() ~= 0)
) and self.irs or false
)
if config.gamesettings.buffer_lock == 3 then
if self.buffer_hard_drop then
local prev_y = self.piece.position.y
self.piece:dropToBottom(self.grid)
self.piece.locked = self.lock_on_hard_drop
self:onHardDrop(self.piece.position.y - prev_y)
end
if self.buffer_soft_drop then
if (
self.lock_on_soft_drop and
self.piece:isDropBlocked(self.grid)
) then
self.piece.locked = true
end
end
end
self.piece_hard_dropped = false
self.piece_soft_locked = false
self.buffer_hard_drop = false
self.buffer_soft_drop = false
if self.piece:isDropBlocked(self.grid) and
self.grid:canPlacePiece(self.piece) then
playSE("bottom")
end
if generate_next_piece == nil then if generate_next_piece == nil then
table.remove(self.next_queue, 1) table.remove(self.next_queue, 1)
table.insert(self.next_queue, self:getNextPiece(ruleset)) table.insert(self.next_queue, self:getNextPiece(ruleset))
@@ -592,6 +603,10 @@ function GameMode:animation(x, y, skin, colour)
} }
end end
function GameMode:canDrawLCA()
return self.lcd > 0
end
function GameMode:drawLineClearAnimation() function GameMode:drawLineClearAnimation()
-- animation function -- animation function
-- params: block x, y, skin, colour -- params: block x, y, skin, colour
@@ -825,6 +840,95 @@ function GameMode:drawSectionTimesWithSplits(current_section, section_limit)
end end
end end
function GameMode:drawBackground()
love.graphics.setColor(1, 1, 1, 1)
love.graphics.draw(
backgrounds[self:getBackground()],
0, 0, 0,
0.5, 0.5
)
end
function GameMode:drawFrame()
-- game frame
if self.grid.width == 10 and self.grid.height == 24 then
love.graphics.draw(misc_graphics["frame"], 48, 64)
end
love.graphics.setColor(0, 0, 0, 200)
love.graphics.rectangle(
"fill", 64, 80,
16 * self.grid.width, 16 * (self.grid.height - 4)
)
if self.grid.width ~= 10 or self.grid.height ~= 24 then
love.graphics.setColor(174/255, 83/255, 76/255, 1)
love.graphics.setLineWidth(8)
love.graphics.line(
60,76,
68+16*self.grid.width,76,
68+16*self.grid.width,84+16*(self.grid.height-4),
60,84+16*(self.grid.height-4),
60,76
)
love.graphics.setColor(203/255, 137/255, 111/255, 1)
love.graphics.setLineWidth(4)
love.graphics.line(
60,76,
68+16*self.grid.width,76,
68+16*self.grid.width,84+16*(self.grid.height-4),
60,84+16*(self.grid.height-4),
60,76
)
love.graphics.setLineWidth(1)
end
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
love.graphics.draw(misc_graphics["ready"], 144 - 50, 240 - 14)
elseif self.ready_frames <= 50 and self.ready_frames > 2 then
love.graphics.draw(misc_graphics["go"], 144 - 27, 240 - 14)
end
end
function GameMode:drawCustom() end function GameMode:drawCustom() end
function GameMode:draw(paused)
self:drawBackground()
self:drawFrame()
self:drawGrid()
self:drawPiece()
self:drawNextQueue(self.ruleset)
self:drawScoringInfo()
self:drawReadyGo()
self:drawCustom()
if self:canDrawLCA() then
self:drawLineClearAnimation()
end
love.graphics.setColor(1, 1, 1, 1)
love.graphics.setFont(font_3x5_2)
if config.gamesettings.display_gamemode == 1 then
love.graphics.printf(
self.name .. " - " .. self.ruleset.name,
0, 460, 640, "left"
)
end
love.graphics.setFont(font_3x5_3)
if paused then
love.graphics.printf("GAME PAUSED!", 64, 160, 160, "center")
end
if self.completed then
self:onGameComplete()
elseif self.game_over then
self:onGameOver()
end
end
return GameMode return GameMode

View File

@@ -144,7 +144,7 @@ function Marathon2020Game:advanceOneFrame()
if self.roll_frames < 0 then if self.roll_frames < 0 then
return false return false
elseif self.roll_frames > 4000 then elseif self.roll_frames > 4000 then
if self.grade >= 30 and self.section_cool_count >= 20 then self.grade = 31 end if self:qualifiesForMRoll() then self.grade = 31 end
self.completed = true self.completed = true
end end
elseif self.ready_frames == 0 then elseif self.ready_frames == 0 then
@@ -154,11 +154,11 @@ function Marathon2020Game:advanceOneFrame()
end end
local cool_cutoffs = { local cool_cutoffs = {
frameTime(0,45,00), frameTime(0,41,50), frameTime(0,38,50), frameTime(0,35,00), frameTime(0,32,50), [0] = frameTime(0,45,00),
frameTime(0,29,20), frameTime(0,27,20), frameTime(0,24,80), frameTime(0,22,80), frameTime(0,20,60), frameTime(0,41,50), frameTime(0,38,50), frameTime(0,35,00), frameTime(0,32,50), frameTime(0,29,20),
frameTime(0,19,60), frameTime(0,19,40), frameTime(0,19,40), frameTime(0,18,40), frameTime(0,18,20), frameTime(0,27,20), frameTime(0,24,80), frameTime(0,22,80), frameTime(0,20,60), frameTime(0,19,60),
frameTime(0,16,20), frameTime(0,16,20), frameTime(0,16,20), frameTime(0,16,20), frameTime(0,16,20), frameTime(0,19,40), frameTime(0,19,40), frameTime(0,18,40), frameTime(0,18,20), frameTime(0,16,20),
frameTime(0,15,20) frameTime(0,16,20), frameTime(0,16,20), frameTime(0,16,20), frameTime(0,16,20), frameTime(0,15,20)
} }
local levels_for_cleared_rows = { 1, 2, 4, 6 } local levels_for_cleared_rows = { 1, 2, 4, 6 }
@@ -227,13 +227,14 @@ local mid_cleared_line_points = {2, 6, 12, 24}
local high_cleared_line_points = {1, 4, 9, 20} local high_cleared_line_points = {1, 4, 9, 20}
local function getGradeForGradePoints(points) local function getGradeForGradePoints(points)
return math.floor(math.sqrt((points / 50) * 8 + 1) / 2 - 0.5) return math.min(30, math.floor(math.sqrt((points / 50) * 8 + 1) / 2 - 0.5))
-- Don't be afraid of the above function. All it does is make it so that -- Don't be afraid of the above function. All it does is make it so that
-- you need 50 points to get to grade 1, 100 points to grade 2, etc. -- you need 50 points to get to grade 1, 100 points to grade 2, etc.
end end
function Marathon2020Game:updateGrade(cleared_lines) function Marathon2020Game:updateGrade(cleared_lines)
-- update grade points and max grade points -- update grade points and max grade points
if self.clear then return end
local point_level = math.floor(self.level / 100) + self.delay_level local point_level = math.floor(self.level / 100) + self.delay_level
local plus_points = math.max( local plus_points = math.max(
low_cleared_line_points[cleared_lines], low_cleared_line_points[cleared_lines],
@@ -249,12 +250,11 @@ function Marathon2020Game:updateGrade(cleared_lines)
end end
function Marathon2020Game:getTotalGrade() function Marathon2020Game:getTotalGrade()
if self.grade + self.section_cool_count > 50 then return "GM" end
return self.grade + self.section_cool_count return self.grade + self.section_cool_count
end end
local function getSectionForLevel(level) local function getSectionForLevel(level)
if level < 2001 then if level < 2000 then
return math.floor(level / 100) + 1 return math.floor(level / 100) + 1
elseif level < 2020 then elseif level < 2020 then
return 20 return 20
@@ -331,14 +331,16 @@ end
function Marathon2020Game:updateSectionTimes(old_level, new_level) function Marathon2020Game:updateSectionTimes(old_level, new_level)
function sectionCool(section) function sectionCool(section)
self.section_cool_count = self.section_cool_count + 1 self.section_cool_count = self.section_cool_count + 1
self.delay_level = math.min(20, self.delay_level + 1) if section <= 10 then
if section < 10 then table.insert(self.section_status, "cool") end self.delay_level = math.min(20, self.delay_level + 1)
end
table.insert(self.section_status, "cool")
self.cool_timer = 300 self.cool_timer = 300
end end
local section = getSectionForLevel(old_level) local section = getSectionForLevel(old_level)
if section <= 19 and old_level % 100 < 70 and new_level >= math.floor(old_level / 100) * 100 + 70 then if old_level % 100 < 70 and new_level >= math.floor(old_level / 100) * 100 + 70 then
-- record section 70 time -- record section 70 time
section_70_time = self.frames - self.section_start_time section_70_time = self.frames - self.section_start_time
table.insert(self.secondary_section_times, section_70_time) table.insert(self.secondary_section_times, section_70_time)
@@ -350,23 +352,25 @@ function Marathon2020Game:updateSectionTimes(old_level, new_level)
table.insert(self.section_times, section_time) table.insert(self.section_times, section_time)
self.section_start_time = self.frames self.section_start_time = self.frames
if section > 5 then self.delay_level = math.min(20, self.delay_level + 1) end
self:checkTorikan(section)
self:checkClear(new_level)
if ( if (
section <= 19 and self.section_status[section - 1] == "cool" and self.section_status[section - 1] == "cool" and
self.secondary_section_times[section] < self.secondary_section_times[section - 1] + 120 and self.secondary_section_times[section] < self.secondary_section_times[section - 1] + 120 and
self.secondary_section_times[section] < cool_cutoffs[section] self.secondary_section_times[section] < cool_cutoffs[self.delay_level]
) then ) then
sectionCool(section) sectionCool(section)
elseif self.section_status[section - 1] == "cool" then elseif self.section_status[section - 1] == "cool" then
table.insert(self.section_status, "none") table.insert(self.section_status, "none")
elseif section <= 19 and self.secondary_section_times[section] < cool_cutoffs[section] then elseif self.secondary_section_times[section] < cool_cutoffs[self.delay_level] then
sectionCool(section) sectionCool(section)
else else
table.insert(self.section_status, "none") table.insert(self.section_status, "none")
end end
if section > 5 then
self.delay_level = math.min(20, self.delay_level + 1)
end
self:checkTorikan(section)
self:checkClear(new_level)
end end
end end
@@ -452,7 +456,13 @@ function Marathon2020Game:drawScoringInfo()
end end
love.graphics.setFont(font_3x5_3) love.graphics.setFont(font_3x5_3)
love.graphics.printf(self:getTotalGrade(), text_x, 120, 90, "left")
local grade = self:getTotalGrade()
love.graphics.printf(
grade > 50 and "GM" or grade,
text_x, 120, 90, "left"
)
love.graphics.printf(self.grade_points, text_x, 220, 90, "left") love.graphics.printf(self.grade_points, text_x, 220, 90, "left")
love.graphics.printf(self.level, text_x, 340, 50, "right") love.graphics.printf(self.level, text_x, 340, 50, "right")
@@ -466,7 +476,7 @@ end
function Marathon2020Game:getHighscoreData() function Marathon2020Game:getHighscoreData()
return { return {
grade = self.grade, grade = self:getTotalGrade(),
level = self.level, level = self.level,
frames = self.frames, frames = self.frames,
} }

View File

@@ -33,6 +33,7 @@ function MarathonA1Game:new()
self.randomizer = History4RollsRandomizer() self.randomizer = History4RollsRandomizer()
self.additive_gravity = false
self.lock_drop = false self.lock_drop = false
self.enable_hard_drop = false self.enable_hard_drop = false
self.enable_hold = false self.enable_hold = false

View File

@@ -19,6 +19,7 @@ function MarathonA2Game:new()
self.roll_frames = 0 self.roll_frames = 0
self.combo = 1 self.combo = 1
self.grade_combo = 1
self.randomizer = History6RollsRandomizer() self.randomizer = History6RollsRandomizer()
self.grade = 0 self.grade = 0
self.grade_points = 0 self.grade_points = 0
@@ -34,6 +35,7 @@ function MarathonA2Game:new()
"GM" "GM"
} }
self.additive_gravity = false
self.lock_drop = false self.lock_drop = false
self.lock_hard_drop = false self.lock_hard_drop = false
self.enable_hold = false self.enable_hold = false
@@ -134,15 +136,23 @@ function MarathonA2Game:updateScore(level, drop_bonus, cleared_lines)
if cleared_lines >= 4 then if cleared_lines >= 4 then
self.tetris_count = self.tetris_count + 1 self.tetris_count = self.tetris_count + 1
end end
if self.grid:checkForBravo(cleared_lines) then self.bravo = 4 else self.bravo = 1 end if self.grid:checkForBravo(cleared_lines) then
self.bravo = 4
else
self.bravo = 1
end
if cleared_lines > 0 then if cleared_lines > 0 then
self.combo = self.combo + (cleared_lines - 1) * 2 self.combo = self.combo + (cleared_lines - 1) * 2
if cleared_lines > 1 then
self.grade_combo = self.grade_combo + 1
end
self.score = self.score + ( self.score = self.score + (
(math.ceil((level + cleared_lines) / 4) + drop_bonus) * (math.ceil((level + cleared_lines) / 4) + drop_bonus) *
cleared_lines * self.combo * self.bravo cleared_lines * self.combo * self.bravo
) )
else else
self.combo = 1 self.combo = 1
self.grade_combo = 1
end end
self.drop_bonus = 0 self.drop_bonus = 0
else self.lines = self.lines + cleared_lines end else self.lines = self.lines + cleared_lines end
@@ -252,7 +262,7 @@ function MarathonA2Game:updateGrade(cleared_lines)
self.grade_points = self.grade_points + ( self.grade_points = self.grade_points + (
math.ceil( math.ceil(
grade_point_bonuses[self.grade + 1][cleared_lines] * grade_point_bonuses[self.grade + 1][cleared_lines] *
combo_multipliers[math.min(self.combo, 10)][cleared_lines] combo_multipliers[math.min(self.grade_combo, 10)][cleared_lines]
) * (1 + math.floor(self.level / 250)) ) * (1 + math.floor(self.level / 250))
) )
if self.grade_points >= 100 and self.grade < 31 then if self.grade_points >= 100 and self.grade < 31 then

View File

@@ -20,6 +20,7 @@ function MarathonA3Game:new()
self.speed_level = 0 self.speed_level = 0
self.roll_frames = 0 self.roll_frames = 0
self.combo = 1 self.combo = 1
self.grade_combo = 1
self.grade = 0 self.grade = 0
self.grade_points = 0 self.grade_points = 0
self.roll_points = 0 self.roll_points = 0
@@ -39,6 +40,7 @@ self.SGnames = {
"GM" "GM"
} }
self.additive_gravity = false
self.lock_drop = true self.lock_drop = true
self.lock_hard_drop = true self.lock_hard_drop = true
self.enable_hold = true self.enable_hold = true
@@ -235,12 +237,16 @@ function MarathonA3Game:updateScore(level, drop_bonus, cleared_lines)
if not self.clear then if not self.clear then
if cleared_lines > 0 then if cleared_lines > 0 then
self.combo = self.combo + (cleared_lines - 1) * 2 self.combo = self.combo + (cleared_lines - 1) * 2
if cleared_lines > 1 then
self.grade_combo = self.grade_combo + 1
end
self.score = self.score + ( self.score = self.score + (
(math.ceil((level + cleared_lines) / 4) + drop_bonus) * (math.ceil((level + cleared_lines) / 4) + drop_bonus) *
cleared_lines * self.combo cleared_lines * self.combo
) )
else else
self.combo = 1 self.combo = 1
self.grade_combo = 1
end end
self.drop_bonus = 0 self.drop_bonus = 0
end end
@@ -334,7 +340,7 @@ function MarathonA3Game:updateGrade(cleared_lines)
self.grade_points = self.grade_points + ( self.grade_points = self.grade_points + (
math.ceil( math.ceil(
grade_point_bonuses[self.grade + 1][cleared_lines] * grade_point_bonuses[self.grade + 1][cleared_lines] *
combo_multipliers[math.min(self.combo, 10)][cleared_lines] combo_multipliers[math.min(self.grade_combo, 10)][cleared_lines]
) * (1 + math.floor(self.level / 250)) ) * (1 + math.floor(self.level / 250))
) )
if self.grade_points >= 100 and self.grade < 31 then if self.grade_points >= 100 and self.grade < 31 then
@@ -350,7 +356,12 @@ function MarathonA3Game:qualifiesForMRoll()
end end
function MarathonA3Game:getAggregateGrade() function MarathonA3Game:getAggregateGrade()
return self.section_cool_grade + math.floor(self.roll_points / 100) + grade_conversion[self.grade] return math.min(
self.section_cool_grade +
math.floor(self.roll_points / 100) +
grade_conversion[self.grade],
self.roll_frames > 3238 and 32 or 31
)
end end
local master_grades = { "M", "MK", "MV", "MO", "MM" } local master_grades = { "M", "MK", "MV", "MO", "MM" }
@@ -365,8 +376,6 @@ function MarathonA3Game:getLetterGrade()
return "M" .. tostring(grade - 17) return "M" .. tostring(grade - 17)
elseif grade < 32 then elseif grade < 32 then
return master_grades[grade - 26] return master_grades[grade - 26]
elseif grade >= 32 and self.roll_frames < 3238 then
return "MM"
else else
return "GM" return "GM"
end end
@@ -464,7 +473,7 @@ function MarathonA3Game:drawScoringInfo()
love.graphics.setFont(font_3x5_3) love.graphics.setFont(font_3x5_3)
love.graphics.printf(self.score, 240, 220, 90, "left") love.graphics.printf(self.score, 240, 220, 90, "left")
if self.roll_frames > 3238 then love.graphics.setColor(1, 0.5, 0, 1) if self.roll_frames > 3238 then love.graphics.setColor(1, 0.5, 0, 1)
elseif self.level >= 999 and self.clear then love.graphics.setColor(0, 1, 0, 1) end elseif self.level >= 999 then love.graphics.setColor(0, 1, 0, 1) end
love.graphics.printf(self:getLetterGrade(), 240, 140, 90, "left") love.graphics.printf(self:getLetterGrade(), 240, 140, 90, "left")
love.graphics.setColor(1, 1, 1, 1) love.graphics.setColor(1, 1, 1, 1)
love.graphics.printf(self.level, 240, 340, 40, "right") love.graphics.printf(self.level, 240, 340, 40, "right")

View File

@@ -19,13 +19,16 @@ function PhantomManiaGame:new()
self.next_queue_length = 1 self.next_queue_length = 1
self.SGnames = { self.SGnames = {
"9", "8", "7", "6", "5", "4", "3", "2", "1",
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9", "S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
"M1", "M2", "M3", "M4", "M5", "M6", "M7", "M8", "M9",
"GM" "GM"
} }
self.roll_frames = 0 self.roll_frames = 0
self.combo = 1 self.combo = 1
self.tetrises = 0
self.section_tetrises = {[0] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 0}
self.section_req = true
self.randomizer = History6RollsRandomizer() self.randomizer = History6RollsRandomizer()
end end
@@ -105,12 +108,23 @@ end
function PhantomManiaGame:onLineClear(cleared_row_count) function PhantomManiaGame:onLineClear(cleared_row_count)
if not self.clear then if not self.clear then
if cleared_row_count >= 4 then
self.tetrises = self.tetrises + 1
self.section_tetrises[math.floor(self.level / 100)] = (
self.section_tetrises[math.floor(self.level / 100)] + 1
)
end
local new_level = self.level + cleared_row_count local new_level = self.level + cleared_row_count
if new_level >= 999 or self:hitTorikan(self.level, new_level) then if new_level >= 999 or self:hitTorikan(self.level, new_level) then
if new_level >= 999 then if new_level >= 999 then
self.level = 999 self.level = 999
end end
self.clear = true self.clear = true
for i = 0, 9 do
if self.section_tetrises[i] < (i == 9 and 1 or 2) then
self.section_req = false
end
end
else else
self.level = new_level self.level = new_level
end end
@@ -138,7 +152,7 @@ PhantomManiaGame.rollOpacityFunction = function(age)
end end
function PhantomManiaGame:drawGrid() function PhantomManiaGame:drawGrid()
if not (self.game_over or self.clear) then if not (self.game_over or self.completed or (self.clear and self.level < 999)) then
self.grid:drawInvisible(self.rollOpacityFunction, nil, false) self.grid:drawInvisible(self.rollOpacityFunction, nil, false)
else else
self.grid:draw() self.grid:draw()
@@ -150,16 +164,14 @@ local function getLetterGrade(level, clear)
return "" return ""
elseif level < 500 or level == 500 and clear then elseif level < 500 or level == 500 and clear then
return "M" return "M"
elseif level < 700 then elseif level < 600 then
return "MK" return "MK"
elseif level < 800 or level == 800 and clear then elseif level < 700 then
return "MV" return "MV"
elseif level < 900 then elseif level < 800 or level == 800 and clear then
return "MO" return "MO"
elseif level < 999 then elseif level <= 999 then
return "MM" return "MM"
elseif level == 999 then
return "GM"
end end
end end
@@ -169,7 +181,9 @@ function PhantomManiaGame:drawScoringInfo()
local text_x = config["side_next"] and 320 or 240 local text_x = config["side_next"] and 320 or 240
love.graphics.setFont(font_3x5_2) love.graphics.setFont(font_3x5_2)
if getLetterGrade(self.level, self.clear) ~= "" then love.graphics.printf("GRADE", text_x, 120, 40, "left") end if getLetterGrade(self.level, self.clear) ~= "" then
love.graphics.printf("GRADE", text_x, 120, 40, "left")
end
love.graphics.printf("SCORE", text_x, 200, 40, "left") love.graphics.printf("SCORE", text_x, 200, 40, "left")
love.graphics.printf("LEVEL", text_x, 320, 40, "left") love.graphics.printf("LEVEL", text_x, 320, 40, "left")
local sg = self.grid:checkSecretGrade() local sg = self.grid:checkSecretGrade()
@@ -178,7 +192,16 @@ function PhantomManiaGame:drawScoringInfo()
end end
love.graphics.setFont(font_3x5_3) love.graphics.setFont(font_3x5_3)
if getLetterGrade(self.level, self.clear) ~= "" then love.graphics.printf(getLetterGrade(self.level, self.clear), text_x, 140, 90, "left") end if getLetterGrade(self.level, self.clear) ~= "" then
if self.roll_frames > 1982 then love.graphics.setColor(1, 0.5, 0, 1)
elseif self.level == 999 and self.clear then love.graphics.setColor(0, 1, 0, 1) end
if self.level == 999 and self.section_req and self.tetrises >= 31 then
love.graphics.printf("GM", text_x, 140, 90, "left")
else
love.graphics.printf(getLetterGrade(self.level, self.clear), text_x, 140, 90, "left")
end
love.graphics.setColor(1, 1, 1, 1)
end
love.graphics.printf(self.score, text_x, 220, 90, "left") love.graphics.printf(self.score, text_x, 220, 90, "left")
love.graphics.printf(self.level, text_x, 340, 40, "right") love.graphics.printf(self.level, text_x, 340, 40, "right")
if self.clear then if self.clear then

View File

@@ -3,7 +3,7 @@ require 'funcs'
local GameMode = require 'tetris.modes.gamemode' local GameMode = require 'tetris.modes.gamemode'
local Piece = require 'tetris.components.piece' local Piece = require 'tetris.components.piece'
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls' local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls_35bag'
local PhantomMania2Game = GameMode:extend() local PhantomMania2Game = GameMode:extend()
@@ -28,7 +28,7 @@ function PhantomMania2Game:new()
self.SGnames = { self.SGnames = {
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9", "S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
"m1", "m2", "m3", "m4", "m5", "m6", "m7", "m8", "m9", "M1", "M2", "M3", "M4", "M5", "M6", "M7", "M8", "M9",
"GM" "GM"
} }
@@ -251,7 +251,7 @@ PhantomMania2Game.garbageOpacityFunction = function(age)
end end
function PhantomMania2Game:drawGrid() function PhantomMania2Game:drawGrid()
if not (self.game_over) then if not (self.game_over or self.completed or (self.clear and self.level < 1300)) then
self.grid:drawInvisible(self.rollOpacityFunction, self.garbageOpacityFunction) self.grid:drawInvisible(self.rollOpacityFunction, self.garbageOpacityFunction)
else else
self.grid:draw() self.grid:draw()

View File

@@ -8,12 +8,6 @@ PhantomManiaNGame.tagline = "The old mode from Nullpomino, for Ti-ARS and SRS su
function PhantomManiaNGame:new() function PhantomManiaNGame:new()
PhantomManiaNGame.super:new() PhantomManiaNGame.super:new()
self.SGnames = {
"M1", "M2", "M3", "M4", "M5", "M6", "M7", "M8", "M9",
"M10", "M11", "M12", "M13", "M14", "M15", "M16", "M17", "M18",
"GM"
}
self.next_queue_length = 3 self.next_queue_length = 3
self.enable_hold = true self.enable_hold = true

View File

@@ -1,218 +1,18 @@
require 'funcs' require 'funcs'
local GameMode = require 'tetris.modes.gamemode' local MarathonA1Game = require 'tetris.modes.marathon_a1'
local Piece = require 'tetris.components.piece' local Piece = require 'tetris.components.piece'
local History4RollsRandomizer = require 'tetris.randomizers.history_4rolls' local History4RollsRandomizer = require 'tetris.randomizers.history_4rolls'
local SurvivalA1Game = GameMode:extend() local SurvivalA1Game = MarathonA1Game:extend()
SurvivalA1Game.name = "Survival A1" SurvivalA1Game.name = "Survival A1"
SurvivalA1Game.hash = "SurvivalA1" SurvivalA1Game.hash = "SurvivalA1"
SurvivalA1Game.tagline = "The game starts fast and only gets faster!" SurvivalA1Game.tagline = "A constant high-speed marathon!"
function SurvivalA1Game:new()
SurvivalA1Game.super:new()
self.roll_frames = 0
self.combo = 1
self.bravos = 0
self.gm_conditions = {
level300 = false,
level500 = false,
level999 = false
}
self.SGnames = {
"9", "8", "7", "6", "5", "4", "3", "2", "1",
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
"GM"
}
self.randomizer = History4RollsRandomizer()
self.lock_drop = false
self.enable_hard_drop = false
self.enable_hold = false
self.next_queue_length = 1
end
function SurvivalA1Game:getARE()
return 30
end
function SurvivalA1Game:getLineARE()
return 27
end
function SurvivalA1Game:getDasLimit()
return 15
end
function SurvivalA1Game:getLineClearDelay()
return 44
end
function SurvivalA1Game:getLockDelay()
return 30
end
function SurvivalA1Game:getGravity() function SurvivalA1Game:getGravity()
return 20 return 20
end end
local function getRankForScore(score)
if score < 400 then return {rank = "9", next = 400}
elseif score < 800 then return {rank = "8", next = 800}
elseif score < 1400 then return {rank = "7", next = 1400}
elseif score < 2000 then return {rank = "6", next = 2000}
elseif score < 3500 then return {rank = "5", next = 3500}
elseif score < 5500 then return {rank = "4", next = 5500}
elseif score < 8000 then return {rank = "3", next = 8000}
elseif score < 12000 then return {rank = "2", next = 12000}
elseif score < 16000 then return {rank = "1", next = 16000}
elseif score < 22000 then return {rank = "S1", next = 22000}
elseif score < 30000 then return {rank = "S2", next = 30000}
elseif score < 40000 then return {rank = "S3", next = 40000}
elseif score < 52000 then return {rank = "S4", next = 52000}
elseif score < 66000 then return {rank = "S5", next = 66000}
elseif score < 82000 then return {rank = "S6", next = 82000}
elseif score < 100000 then return {rank = "S7", next = 100000}
elseif score < 120000 then return {rank = "S8", next = 120000}
else return {rank = "S9", next = "???"}
end
end
function SurvivalA1Game:advanceOneFrame()
if self.clear then
self.roll_frames = self.roll_frames + 1
if self.roll_frames > 2968 then
self.completed = true
end
elseif self.ready_frames == 0 then
self.frames = self.frames + 1
end
return true
end
function SurvivalA1Game:onPieceEnter()
if (self.level % 100 ~= 99 and self.level ~= 998) and not self.clear and self.frames ~= 0 then
self.level = self.level + 1
end
end
function SurvivalA1Game:onLineClear(cleared_row_count)
self:checkGMRequirements(self.level, self.level + cleared_row_count)
if not self.clear then
local new_level = math.min(self.level + cleared_row_count, 999)
if new_level == 999 then
self.clear = true
else
self.level = new_level
end
end
end
function SurvivalA1Game:updateScore(level, drop_bonus, cleared_lines)
if not self.clear then
if self.grid:checkForBravo(cleared_lines) then
self.bravo = 4
self.bravos = self.bravos + 1
else self.bravo = 1 end
if cleared_lines > 0 then
self.combo = self.combo + (cleared_lines - 1) * 2
self.score = self.score + (
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
cleared_lines * self.combo * self.bravo
)
else
self.combo = 1
end
self.drop_bonus = 0
end
end
function SurvivalA1Game:checkGMRequirements(old_level, new_level)
if old_level < 300 and new_level >= 300 then
if self.score >= 12000 and self.frames <= frameTime(4,15) then
self.gm_conditions["level300"] = true
end
elseif old_level < 500 and new_level >= 500 then
if self.score >= 40000 and self.frames <= frameTime(7,30) then
self.gm_conditions["level500"] = true
end
elseif old_level < 999 and new_level >= 999 then
if self.score >= 126000 and self.frames <= frameTime(13,30) then
self.gm_conditions["level999"] = true
end
end
end
function SurvivalA1Game:drawGrid()
self.grid:draw()
end
function SurvivalA1Game:drawScoringInfo()
SurvivalA1Game.super.drawScoringInfo(self)
love.graphics.setColor(1, 1, 1, 1)
love.graphics.setFont(font_3x5_2)
love.graphics.print(
self.das.direction .. " " ..
self.das.frames .. " " ..
strTrueValues(self.prev_inputs)
)
love.graphics.printf("NEXT", 64, 40, 40, "left")
love.graphics.printf("GRADE", 240, 120, 40, "left")
love.graphics.printf("SCORE", 240, 200, 40, "left")
love.graphics.printf("NEXT RANK", 240, 260, 90, "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
if self.bravos > 0 then love.graphics.printf("BRAVO", 300, 120, 40, "left") end
love.graphics.setFont(font_3x5_3)
love.graphics.printf(self.score, 240, 220, 90, "left")
if self.gm_conditions["level300"] and self.gm_conditions["level500"] and self.gm_conditions["level999"] then
love.graphics.printf("GM", 240, 140, 90, "left")
else
love.graphics.printf(getRankForScore(self.score).rank, 240, 140, 90, "left")
end
love.graphics.printf(getRankForScore(self.score).next, 240, 280, 90, "left")
love.graphics.printf(self.level, 240, 340, 40, "right")
love.graphics.printf(self:getSectionEndLevel(), 240, 370, 40, "right")
if sg >= 5 then
love.graphics.printf(self.SGnames[sg], 240, 450, 180, "left")
end
if self.bravos > 0 then love.graphics.printf(self.bravos, 300, 140, 40, "left") end
love.graphics.setFont(font_8x11)
love.graphics.printf(formatTime(self.frames), 64, 420, 160, "center")
end
function SurvivalA1Game:getSectionEndLevel()
if self.level >= 900 then return 999
else return math.floor(self.level / 100 + 1) * 100 end
end
function SurvivalA1Game:getBackground()
return math.floor(self.level / 100)
end
function SurvivalA1Game:getHighscoreData()
return {
grade = self.grade,
score = self.score,
level = self.level,
frames = self.frames,
}
end
return SurvivalA1Game return SurvivalA1Game

View File

@@ -30,11 +30,6 @@ function SurvivalA2Game:new()
self.lock_hard_drop = true self.lock_hard_drop = true
end end
function SurvivalA2Game:initialize(ruleset)
SurvivalA2Game.super.initialize(self, ruleset)
self.world = ruleset.world
end
function SurvivalA2Game:getARE() function SurvivalA2Game:getARE()
if self.level < 100 then return 18 if self.level < 100 then return 18
elseif self.level < 300 then return 14 elseif self.level < 300 then return 14
@@ -74,8 +69,7 @@ function SurvivalA2Game:getGravity()
end end
function SurvivalA2Game:hitTorikan(old_level, new_level) function SurvivalA2Game:hitTorikan(old_level, new_level)
local torikan_time = self.world and frameTime(3,55) or frameTime(3,25) if old_level < 500 and new_level >= 500 and self.frames > frameTime(3,25) then
if old_level < 500 and new_level >= 500 and self.frames > torikan_time then
self.level = 500 self.level = 500
return true return true
end end
@@ -85,7 +79,7 @@ end
function SurvivalA2Game:advanceOneFrame() function SurvivalA2Game:advanceOneFrame()
if self.clear then if self.clear then
self.roll_frames = self.roll_frames + 1 self.roll_frames = self.roll_frames + 1
if self.roll_frames > 2968 then if self.roll_frames > 1800 then
self.completed = true self.completed = true
end end
elseif self.ready_frames == 0 then elseif self.ready_frames == 0 then

View File

@@ -24,7 +24,7 @@ function SurvivalA3Game:new()
self.SGnames = { self.SGnames = {
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9", "S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
"m1", "m2", "m3", "m4", "m5", "m6", "m7", "m8", "m9", "M1", "M2", "M3", "M4", "M5", "M6", "M7", "M8", "M9",
"GM" "GM"
} }
@@ -38,11 +38,9 @@ function SurvivalA3Game:new()
end end
function SurvivalA3Game:initialize(ruleset) function SurvivalA3Game:initialize(ruleset)
self.torikan_time = frameTime(2,28) self.torikan_time = frameTime(2,28)
if ruleset.world then self.torikan_time = frameTime(3,03) end if ruleset.world then self.torikan_time = frameTime(3,03) end
self.super.initialize(self, ruleset) GameMode.initialize(self, ruleset)
-- ^ notice the . here instead of the :
end end
function SurvivalA3Game:getARE() function SurvivalA3Game:getARE()
@@ -239,7 +237,7 @@ function SurvivalA3Game:drawScoringInfo()
love.graphics.setFont(font_3x5_3) love.graphics.setFont(font_3x5_3)
if self.roll_frames > 3238 then love.graphics.setColor(1, 0.5, 0, 1) if self.roll_frames > 3238 then love.graphics.setColor(1, 0.5, 0, 1)
elseif self.level >= 1300 and self.clear then love.graphics.setColor(0, 1, 0, 1) end elseif self.level >= 1300 then love.graphics.setColor(0, 1, 0, 1) end
love.graphics.printf(getLetterGrade(math.floor(self.grade)), text_x, 140, 90, "left") love.graphics.printf(getLetterGrade(math.floor(self.grade)), text_x, 140, 90, "left")
love.graphics.setColor(1, 1, 1, 1) love.graphics.setColor(1, 1, 1, 1)
love.graphics.printf(self.score, text_x, 220, 90, "left") love.graphics.printf(self.score, text_x, 220, 90, "left")

View File

@@ -37,41 +37,41 @@ function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid)
(piece:isMoveBlocked(grid, {x=-1, y=0}) or piece:isMoveBlocked(grid, {x=1, y=0})) then (piece:isMoveBlocked(grid, {x=-1, y=0}) or piece:isMoveBlocked(grid, {x=1, y=0})) then
-- kick right, right2, left -- kick right, right2, left
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
self:onPieceRotate(piece, grid)
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0}) piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
self:onPieceRotate(piece, grid)
elseif grid:canPlacePiece(new_piece:withOffset({x=2, y=0})) then elseif grid:canPlacePiece(new_piece:withOffset({x=2, y=0})) then
self:onPieceRotate(piece, grid)
piece:setRelativeRotation(rot_dir):setOffset({x=2, y=0}) piece:setRelativeRotation(rot_dir):setOffset({x=2, y=0})
elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then
self:onPieceRotate(piece, grid) self:onPieceRotate(piece, grid)
elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0}) piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
self:onPieceRotate(piece, grid)
end end
elseif piece:isDropBlocked(grid) and (new_piece.rotation == 1 or new_piece.rotation == 3) then elseif piece:isDropBlocked(grid) and (new_piece.rotation == 1 or new_piece.rotation == 3) then
-- kick up, up2 -- kick up, up2
if grid:canPlacePiece(new_piece:withOffset({x=0, y=-1})) then if grid:canPlacePiece(new_piece:withOffset({x=0, y=-1})) then
self:onPieceRotate(piece, grid)
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1}) piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
elseif grid:canPlacePiece(new_piece:withOffset({x=0, y=-2})) then
self:onPieceRotate(piece, grid) self:onPieceRotate(piece, grid)
elseif grid:canPlacePiece(new_piece:withOffset({x=0, y=-2})) then
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-2}) piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-2})
self:onPieceRotate(piece, grid)
end end
end end
else else
-- kick right, kick left -- kick right, kick left
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
self:onPieceRotate(piece, grid)
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0}) piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then
self:onPieceRotate(piece, grid) self:onPieceRotate(piece, grid)
elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0}) piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
self:onPieceRotate(piece, grid)
elseif piece.shape == "T" elseif piece.shape == "T"
and new_piece.rotation == 0 and new_piece.rotation == 0
and piece:isDropBlocked(grid) and piece:isDropBlocked(grid)
and grid:canPlacePiece(new_piece:withOffset({x=0, y=-1})) and grid:canPlacePiece(new_piece:withOffset({x=0, y=-1}))
then then
-- T floorkick -- T floorkick
self:onPieceRotate(piece, grid)
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1}) piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
self:onPieceRotate(piece, grid)
end end
end end

View File

@@ -52,11 +52,11 @@ function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid)
if grid:canPlacePiece(new_piece:withOffset({x=0, y=-1})) then if grid:canPlacePiece(new_piece:withOffset({x=0, y=-1})) then
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1}) piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
piece.floorkick = 1 piece.floorkick = 1
self:onPieceRotate(piece, grid) self:onPieceRotate(piece, grid, true)
elseif grid:canPlacePiece(new_piece:withOffset({x=0, y=-2})) then elseif grid:canPlacePiece(new_piece:withOffset({x=0, y=-2})) then
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-2}) piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-2})
piece.floorkick = 1 piece.floorkick = 1
self:onPieceRotate(piece, grid) self:onPieceRotate(piece, grid, true)
end end
end end
else else
@@ -76,7 +76,7 @@ function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid)
-- T floorkick -- T floorkick
piece.floorkick = piece.floorkick + 1 piece.floorkick = piece.floorkick + 1
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1}) piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
self:onPieceRotate(piece, grid) self:onPieceRotate(piece, grid, true)
end end
end end
@@ -93,10 +93,10 @@ function ARS:onPieceDrop(piece, grid)
end end
end end
function ARS:onPieceRotate(piece, grid) function ARS:onPieceRotate(piece, grid, floorkick)
if piece.floorkick >= 2 and piece:isDropBlocked(grid) then if piece.floorkick >= 2 and piece:isDropBlocked(grid) then
piece.locked = true piece.locked = true
elseif piece.floorkick >= 1 then elseif piece.floorkick >= 1 and not floorkick then
piece.floorkick = piece.floorkick + 1 piece.floorkick = piece.floorkick + 1
end end
end end

View File

@@ -375,7 +375,10 @@ end
function CRS:attemptWallkicks(piece, new_piece, rot_dir, grid) function CRS:attemptWallkicks(piece, new_piece, rot_dir, grid)
if piece.shape == "O" then return end if piece.shape == "O" then
self:onPieceRotate(piece, grid)
return
end
local kicks = CRS.wallkicks[piece.shape][piece:isDropBlocked(grid)][piece.rotation][new_piece.rotation] local kicks = CRS.wallkicks[piece.shape][piece:isDropBlocked(grid)][piece.rotation][new_piece.rotation]

View File

@@ -76,7 +76,7 @@ function Ruleset:rotatePiece(inputs, piece, grid, prev_inputs, initial)
self:attemptRotate(new_inputs, piece, grid, initial) self:attemptRotate(new_inputs, piece, grid, initial)
end end
if not was_drop_blocked and piece:isDropBlocked(grid) then if not initial and not was_drop_blocked and piece:isDropBlocked(grid) then
playSE("bottom") playSE("bottom")
end end
@@ -123,6 +123,7 @@ function Ruleset:movePiece(piece, grid, move, instant)
local was_drop_blocked = piece:isDropBlocked(grid) local was_drop_blocked = piece:isDropBlocked(grid)
local offset = ({x=0, y=0}) local offset = ({x=0, y=0})
local moves = 0 local moves = 0
local y = piece.position.y
if move == "left" then if move == "left" then
offset.x = -1 offset.x = -1
moves = 1 moves = 1
@@ -151,17 +152,15 @@ function Ruleset:movePiece(piece, grid, move, instant)
if not was_drop_blocked and piece:isDropBlocked(grid) then if not was_drop_blocked and piece:isDropBlocked(grid) then
playSE("bottom") playSE("bottom")
end end
if instant and piece.position.y ~= y then
self:onPieceDrop(piece, grid)
end
end end
function Ruleset:dropPiece( function Ruleset:dropPiece(
inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked, inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked,
hard_drop_enabled, additive_gravity, classic_lock hard_drop_enabled, additive_gravity, classic_lock
) )
if piece.big then
gravity = gravity / 2
drop_speed = drop_speed / 2
end
local y = piece.position.y local y = piece.position.y
if inputs["down"] == true and drop_locked == false then if inputs["down"] == true and drop_locked == false then
if additive_gravity then if additive_gravity then
@@ -206,9 +205,7 @@ end
function Ruleset:initializePiece( function Ruleset:initializePiece(
inputs, data, grid, gravity, prev_inputs, inputs, data, grid, gravity, prev_inputs,
move, lock_delay, drop_speed, move, lock_delay, drop_speed,
drop_locked, hard_drop_locked, big, irs, drop_locked, hard_drop_locked, big, irs
buffer_hard_drop, buffer_soft_drop,
lock_on_hard_drop, lock_on_soft_drop
) )
local spawn_positions local spawn_positions
if big then if big then
@@ -224,16 +221,7 @@ function Ruleset:initializePiece(
colours = self.colourscheme colours = self.colourscheme
end end
local spawn_x local spawn_x = math.floor(spawn_positions[data.shape].x / 10 * grid.width)
if (grid.width ~= 10) then
local percent = spawn_positions[data.shape].x / 10
for i = grid.width - 1, 0, -1 do
if i / grid.width <= percent then
spawn_x = i
break
end
end
end
local spawn_dy local spawn_dy
if (config.gamesettings.spawn_positions == 1) then if (config.gamesettings.spawn_positions == 1) then
@@ -260,14 +248,6 @@ function Ruleset:initializePiece(
playSE("irs") playSE("irs")
end end
end end
self:dropPiece(inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked)
if (buffer_hard_drop and config.gamesettings.buffer_lock == 1) then
piece:dropToBottom(grid)
if lock_on_hard_drop then piece.locked = true end
end
if (buffer_soft_drop and lock_on_soft_drop and piece:isDropBlocked(grid) and config.gamesettings.buffer_lock == 1) then
piece.locked = true
end
return piece return piece
end end
@@ -280,14 +260,13 @@ function Ruleset:processPiece(
drop_locked, hard_drop_locked, drop_locked, hard_drop_locked,
hard_drop_enabled, additive_gravity, classic_lock hard_drop_enabled, additive_gravity, classic_lock
) )
local synchroes_allowed = ({not self.world, true, false})[config.gamesettings.synchroes_allowed] local synchroes_allowed = ({not self.world, true, false})[config.gamesettings.synchroes_allowed]
if synchroes_allowed then if synchroes_allowed then
self:rotatePiece(inputs, piece, grid, prev_inputs, false) self:rotatePiece(inputs, piece, grid, prev_inputs, false)
self:movePiece(piece, grid, move, gravity >= 20) self:movePiece(piece, grid, move, gravity >= grid.height - 4)
else else
self:movePiece(piece, grid, move, gravity >= 20) self:movePiece(piece, grid, move, gravity >= grid.height - 4)
self:rotatePiece(inputs, piece, grid, prev_inputs, false) self:rotatePiece(inputs, piece, grid, prev_inputs, false)
end end
self:dropPiece( self:dropPiece(