Compare commits

...

56 Commits

Author SHA1 Message Date
Ishaan Bhardwaj
788aa11470 Bump version to v0.3.3.2 2023-07-07 18:16:34 -04:00
Ishaan Bhardwaj
a303e82b90 Merge branch 'master' of https://github.com/millabasset/cambridge 2023-07-07 18:14:20 -04:00
Ishaan Bhardwaj
b06d03c4e6 Fix bravo detection 2023-07-07 18:14:17 -04:00
Ishaan Bhardwaj
a6b8abff6d Merge pull request #69 from Kirby703/patch-11
hotfix cool logic
2023-07-07 17:19:24 -04:00
Kirby703
bdc317c3c5 hotfix cool logic 2023-07-07 17:10:24 -04:00
Ishaan Bhardwaj
71c9147a2c Merge pull request #68 from Kirby703/patch-10
re-add 180s and IRS wallkicks after inheritance change
2023-07-04 02:38:52 -04:00
Kirby703
79d706a415 re-add 180s and IRS wallkicks after inheritance change
fixes results of 323c457809
2023-07-04 02:27:04 -04:00
Ishaan Bhardwaj
5fa144f146 Fix Marathon 2020 section cool highlighting 2023-07-02 19:47:39 -04:00
Ishaan Bhardwaj
244e67074d Bump version to v0.3.3.1 2023-07-02 19:13:13 -04:00
Ishaan Bhardwaj
4b456cf49c Removed xcf fonts 2023-07-02 18:20:56 -04:00
Ishaan Bhardwaj
9a67a6ce03 8x11 font by MattMayuga with more characters 2023-07-02 18:07:40 -04:00
Ishaan Bhardwaj
df19129228 Update main.lua 2023-07-01 23:30:36 -04:00
--global
80de771d2a Elaborate on TARGET_FPS 2023-07-01 23:27:10 -04:00
--global
7c32273971 Alias Lua random functions to Love2D's 2023-07-01 23:15:14 -04:00
--global
9d5dbb4674 Bump version to v0.3.3 2023-07-01 22:34:34 -04:00
Ishaan Bhardwaj
8d7ccae2bc README: fix Cambridge logo link 2023-07-01 22:25:50 -04:00
Ishaan Bhardwaj
1e06a1ce8a Merge pull request #67 from MillaBasset/features/backgrounds
Slight revamp on BG image handling
2023-07-01 22:22:50 -04:00
Ishaan Bhardwaj
d24fff5bdc Merge pull request #65 from nightmareci/master
Create unified batch file for running the game from the source directory on Windows and update README.md
2023-07-01 22:22:38 -04:00
Ishaan Bhardwaj
e34005093c Merge pull request #64 from hebo-MAI/master
fix the bug hanging up when starting M-roll
2023-07-01 22:22:04 -04:00
Ishaan Bhardwaj
3dc8b1214b Merge pull request #63 from Kirby703/patch-9
fix line clear delay
2023-07-01 22:21:45 -04:00
Ishaan Bhardwaj
5d2da1b4fb Merge pull request #62 from Tetro48/replay-qol
New replay file naming and fast replay saving.
2023-07-01 22:21:30 -04:00
Ishaan Bhardwaj
f786bda9dd Merge pull request #59 from Tetro48/fixes
Replay tunings fix
2023-07-01 22:21:10 -04:00
Ishaan Bhardwaj
3f789210a6 Merge pull request #56 from Kirby703/patch-8
added cool+regret colors to splits
2023-07-01 22:20:52 -04:00
Ishaan Bhardwaj
a7e7ac43a6 Merge pull request #55 from Kirby703/patch-7
fixes a3 regret grading
2023-07-01 22:20:43 -04:00
Ishaan Bhardwaj
5dc72037ec Merge pull request #54 from Kirby703/patch-6
fixed 2s rule for cools
2023-07-01 22:20:30 -04:00
Oshisaure
e5cb69df43 Slight revamp on BG image handling
- The game can now load more than 20 backgrounds by putting them in /res/backgrounds in the save directory
- If a gamemode tries to set its background to an ID higher than the max it will be clamped down to the last background loaded
2023-07-01 01:56:51 +01:00
Oshisaure
3e68af6a5b Merge pull request #66 from MillaBasset/features/pausing
Added counter for amount of pauses used
2023-06-24 20:35:17 +01:00
Oshisaure
8e6a760fe7 Added counter for amount of pauses used
* Pause count is saved in replays and shown when viewing replay
* Old replays display ?? pauses
* Removed suspend on lose focus
2023-06-24 15:46:38 +01:00
Joe Zeng
a4b7a41a15 Changed the Phantom Mania non-N requirement back to automatic GM at 999.
(Only N should have the 31-tetris rule.)
2023-04-11 12:19:38 -04:00
nightmareci
aa9e03506b Create unified batch file for running the game from the source directory on Windows and update README.md 2023-02-13 09:35:28 -08:00
hebo-MAI
40ac08c7e5 fix the bug hanging up when starting M-roll 2023-01-09 00:12:00 +09:00
Joe Zeng
323c457809 Reorganized the ruleset names and added ARS-X.
Also, the ruleset inheritance was a little wonky, so I changed that too.
In particular, I made SRS-X always spawn in-frame since that was always
supposed to be how it worked.
2022-10-24 20:09:08 -04:00
Joe Zeng
decc1f563f Changed cool/regret cutoffs.
They're all the same past 500 now - I've been meaning to tweak that for quite some time now.
2022-09-28 00:18:44 -04:00
Kirby703
63823ed4b1 fix line clear delay 2022-06-14 00:28:27 -04:00
Tetro48
d7c83b0bc7 New replay file naming and *fast replay saving.
*fast because lower CPU and IO use. No longer O(n²).
2022-05-16 19:53:31 +07:00
nightmareci
e5892c0fae Rename shell scripts and implement better frame timing 2022-04-28 11:47:31 -07:00
--global
23a8c400ba Revert "made the experience feel closer to arcade stackers"
Happy April Fools!
This reverts commit bfbba75f17.
2022-04-01 18:43:35 -04:00
--global
bfbba75f17 made the experience feel closer to arcade stackers 2022-03-31 23:27:22 -04:00
--global
27e699841e Fixed a graphical issue in Survival A2 when getting torikanned 2022-03-31 23:00:39 -04:00
--global
fac8c6584e Added batch scripts to start the game on Windows 2022-03-10 22:36:21 -05:00
Tetro48
d868e8b803 Replay tunings fix 2022-03-09 10:05:06 +07:00
Oshisaure
9e447d51a7 Merge pull request #57 from jjdelvalle/master
Include complete path when printing screenshot info
2022-03-03 19:29:48 +00:00
JDV
4dfa234bc3 Include complete path when printing screenshot info 2022-03-03 20:27:41 +01:00
Kirby703
47863175a3 added cool+regret colors to splits 2022-02-10 01:09:21 -05:00
Kirby703
8730261a78 fixes a3 regret grading
getting a cool and a regret in the same split displays as yellow
2022-02-10 00:40:25 -05:00
Kirby703
703ce66c42 fix 2s rule for cools 2022-02-09 23:48:09 -05:00
Ishaan Bhardwaj
92d67968f5 Tiny UI feature added to the title screen.
If you load a custom block skin, the title screen will use your skin to draw the logo.
2022-02-07 20:39:26 -05:00
Ishaan Bhardwaj
d68bd13d2a LOVE 11.3 notice
Reminder that Windows is unaffected by this, because Windows releases come bundled with the correct version, and the bleeding edge source includes the correct version of LOVE for Windows
2022-01-28 22:22:05 -05:00
Ishaan Bhardwaj
a84335646d Fix two bugs with Marathon A3 grading
S4 now correctly has 3 internal grades instead of 4
You can get a green-line GM
2022-01-28 20:51:25 -05:00
Ishaan Bhardwaj
d46973f12d Fixed color scheme setting not applying to active piece 2021-12-18 21:30:19 -05:00
Ishaan Bhardwaj
d4360b3662 Fixed the replay system's interaction with secret inputs 2021-12-09 23:00:20 -05:00
Ishaan Bhardwaj
06225bd35a Fixed an issue where replays played in the menu could save a duplicate copy 2021-12-09 22:21:48 -05:00
Ishaan Bhardwaj
e68238cbce Fixed disabling saving replays 2021-12-09 22:00:13 -05:00
Ishaan Bhardwaj
83e197b5d6 Slight RPC change to the selection menus 2021-12-09 21:51:41 -05:00
Ishaan Bhardwaj
1c0b73987d Rearrange sliders on the game settings menu 2021-12-09 21:48:39 -05:00
Ishaan Bhardwaj
afe6a43dab Rearrange game settings, add toggle for replay saving 2021-12-09 21:44:18 -05:00
34 changed files with 337 additions and 143 deletions

View File

@@ -26,13 +26,13 @@ All assets needed are bundled with the executable.
#### Bleeding edge #### Bleeding edge
If you want the bleeding edge version, download [this](https://github.com/MillaBasset/cambridge/archive/master.zip). If you want the bleeding edge version, download [this](https://github.com/MillaBasset/cambridge/archive/master.zip). Extract the ZIP to a folder of your choosing.
Extract the ZIP, open a Command Prompt at the folder you extracted Cambridge to, then run this command: If you're on Windows, you can double-click `start.bat` to run the game. If that doesn't work, open a Command Prompt where you extracted Cambridge and run:
dist\windows\love.exe . dist\windows\love.exe .
Alternatively, if you're on a 32-bit system, run this instead: If that doesn't work, run this instead, still using Command Prompt where you extracted Cambridge:
dist\win32\love.exe . dist\win32\love.exe .
@@ -42,7 +42,7 @@ Then, check the mod pack section at the bottom of this page.
### macOS, Linux ### macOS, Linux
If you haven't already, install `love` with your favourite package manager (Homebrew on macOS, your system's default on Linux). **Make sure you're using LÖVE 11, because it won't work with earlier versions!** If you haven't already, install `love` with your favourite package manager (Homebrew on macOS, your system's default on Linux). **Make sure you're using LÖVE 11.3, because it won't work with earlier or later versions!**
#### Downloading a release #### Downloading a release
@@ -107,4 +107,4 @@ Other Notable Games
- [Puzzle Trial](https://kagamine-rin.itch.io/puzzle-trial) by Rin - [Puzzle Trial](https://kagamine-rin.itch.io/puzzle-trial) by Rin
- [stackfuse](https://github.com/sinefuse/stackfuse) by sinefuse - [stackfuse](https://github.com/sinefuse/stackfuse) by sinefuse
![Cambridge Logo](https://cdn.discordapp.com/attachments/625496179433668635/763363717730664458/Icon_2.png) ![Cambridge Logo](https://cdn.discordapp.com/attachments/827186653772644452/1077674343544393820/Icon_2.png)

View File

@@ -26,8 +26,18 @@ font_3x5_4 = love.graphics.newImageFont(
-4 -4
) )
font_8x11 = love.graphics.newImageFont( -- this would be font_8x11 with the other one as 8x11_2
"res/fonts/8x11_medium.png", -- but that would break compatibility :(
"0123456789:.", font_8x11_small = love.graphics.newImageFont(
"res/fonts/8x11.png",
" 0123456789:;.,ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" ..
"?!/\\^@$%<=>()*-+[]_&",
1
)
font_8x11 = love.graphics.newImageFont(
"res/fonts/8x11_medium.png",
" 0123456789:;.,ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz" ..
"?!/\\^@$%<=>()*-+[]_&",
1 1
) )

View File

@@ -1,31 +1,19 @@
backgrounds = { backgrounds = {
[0] = love.graphics.newImage("res/backgrounds/0.png"),
love.graphics.newImage("res/backgrounds/100.png"),
love.graphics.newImage("res/backgrounds/200.png"),
love.graphics.newImage("res/backgrounds/300.png"),
love.graphics.newImage("res/backgrounds/400.png"),
love.graphics.newImage("res/backgrounds/500.png"),
love.graphics.newImage("res/backgrounds/600.png"),
love.graphics.newImage("res/backgrounds/700.png"),
love.graphics.newImage("res/backgrounds/800.png"),
love.graphics.newImage("res/backgrounds/900.png"),
love.graphics.newImage("res/backgrounds/1000.png"),
love.graphics.newImage("res/backgrounds/1100.png"),
love.graphics.newImage("res/backgrounds/1200.png"),
love.graphics.newImage("res/backgrounds/1300.png"),
love.graphics.newImage("res/backgrounds/1400.png"),
love.graphics.newImage("res/backgrounds/1500.png"),
love.graphics.newImage("res/backgrounds/1600.png"),
love.graphics.newImage("res/backgrounds/1700.png"),
love.graphics.newImage("res/backgrounds/1800.png"),
love.graphics.newImage("res/backgrounds/1900.png"),
title = love.graphics.newImage("res/backgrounds/title.png"), title = love.graphics.newImage("res/backgrounds/title.png"),
title_no_icon = love.graphics.newImage("res/backgrounds/title-no-icon.jpg"),
title_night = love.graphics.newImage("res/backgrounds/title-night.jpg"), title_night = love.graphics.newImage("res/backgrounds/title-night.jpg"),
snow = love.graphics.newImage("res/backgrounds/snow.png"), snow = love.graphics.newImage("res/backgrounds/snow.png"),
input_config = love.graphics.newImage("res/backgrounds/options-input.png"), input_config = love.graphics.newImage("res/backgrounds/options-input.png"),
game_config = love.graphics.newImage("res/backgrounds/options-game.png"), game_config = love.graphics.newImage("res/backgrounds/options-game.png"),
} }
local i = 0
local bgpath = "res/backgrounds/%d.png"
while love.filesystem.getInfo(bgpath:format(i*100)) do
backgrounds[i] = love.graphics.newImage(bgpath:format(i*100))
i = i + 1
end
-- in order, the colors are: -- in order, the colors are:
-- red, orange, yellow, green, cyan, blue -- red, orange, yellow, green, cyan, blue
-- magenta (or purple), white, black -- magenta (or purple), white, black

View File

@@ -1 +1 @@
version = "v0.3.1" version = "v0.3.3.2"

View File

@@ -1,5 +1,4 @@
function love.load() function love.load()
math.randomseed(os.time())
highscores = {} highscores = {}
love.graphics.setDefaultFilter("linear", "nearest") love.graphics.setDefaultFilter("linear", "nearest")
require "load.rpc" require "load.rpc"
@@ -24,6 +23,11 @@ function love.load()
-- used for screenshots -- used for screenshots
GLOBAL_CANVAS = love.graphics.newCanvas() GLOBAL_CANVAS = love.graphics.newCanvas()
-- aliasing to prevent people using math.random by accident
math.random = love.math.random
math.randomseed = love.math.setRandomSeed
math.randomseed(os.time())
-- init config -- init config
initConfig() initConfig()
@@ -81,7 +85,7 @@ function love.draw()
love.graphics.setFont(font_3x5_2) love.graphics.setFont(font_3x5_2)
love.graphics.setColor(1, 1, 1, 1) love.graphics.setColor(1, 1, 1, 1)
love.graphics.printf( love.graphics.printf(
string.format("%.2f", 1 / love.timer.getAverageDelta()) .. string.format("%.2f", 1.0 / love.timer.getAverageDelta()) ..
"fps - " .. version, 0, 460, 635, "right" "fps - " .. version, 0, 460, 635, "right"
) )
end end
@@ -118,7 +122,7 @@ function love.keypressed(key, scancode)
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 "..love.filesystem.getSaveDirectory().."/"..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
@@ -289,8 +293,12 @@ function love.resize(w, h)
GLOBAL_CANVAS = love.graphics.newCanvas(w, h) GLOBAL_CANVAS = love.graphics.newCanvas(w, h)
end end
-- higher values of TARGET_FPS will make the game run "faster"
-- since the game is mostly designed for 60 FPS
local TARGET_FPS = 60 local TARGET_FPS = 60
local FRAME_DURATION = 1.0 / TARGET_FPS
-- custom run function; optimizes game by syncing draw/update calls
function love.run() function love.run()
if love.load then love.load(love.arg.parseGameArguments(arg), arg) end if love.load then love.load(love.arg.parseGameArguments(arg), arg) end
@@ -299,7 +307,7 @@ function love.run()
local dt = 0 local dt = 0
local last_time = love.timer.getTime() local last_time = love.timer.getTime()
local time_accumulator = 0 local time_accumulator = 0.0
return function() return function()
if love.event then if love.event then
love.event.pump() love.event.pump()
@@ -320,24 +328,39 @@ function love.run()
if scene and scene.update and love.timer then if scene and scene.update and love.timer then
scene:update() scene:update()
local frame_duration = 1.0 / TARGET_FPS if time_accumulator < FRAME_DURATION then
if time_accumulator < frame_duration then
if love.graphics and love.graphics.isActive() and love.draw then if love.graphics and love.graphics.isActive() and love.draw then
love.graphics.origin() love.graphics.origin()
love.graphics.clear(love.graphics.getBackgroundColor()) love.graphics.clear(love.graphics.getBackgroundColor())
love.draw() love.draw()
love.graphics.present() love.graphics.present()
end end
local end_time = last_time + frame_duration
local time = love.timer.getTime() -- request 1ms delays first but stop short of overshooting, then do "0ms" delays without overshooting (0ms requests generally do a delay of some nonzero amount of time, but maybe less than 1ms)
while time < end_time do for milliseconds=0.001,0.000,-0.001 do
love.timer.sleep(0.001) local max_delay = 0.0
time = love.timer.getTime() while max_delay < FRAME_DURATION do
local delay_start_time = love.timer.getTime()
if delay_start_time - last_time < FRAME_DURATION - max_delay then
love.timer.sleep(milliseconds)
local last_delay = love.timer.getTime() - delay_start_time
if last_delay > max_delay then
max_delay = last_delay
end
else
break
end
end
end
while love.timer.getTime() - last_time < FRAME_DURATION do
-- busy loop, do nothing here until delay is finished; delays above stop short of finishing, so this part can finish it off precisely
end
end
local finish_delay_time = love.timer.getTime()
local real_frame_duration = finish_delay_time - last_time
time_accumulator = time_accumulator + real_frame_duration - FRAME_DURATION
last_time = finish_delay_time
end end
time_accumulator = time_accumulator + time - last_time
end
time_accumulator = time_accumulator - frame_duration
end
last_time = love.timer.getTime()
end end
end end

View File

@@ -1 +1,3 @@
#!/bin/sh
zip -r cambridge.love libs load res scene tetris conf.lua main.lua scene.lua funcs.lua zip -r cambridge.love libs load res scene tetris conf.lua main.lua scene.lua funcs.lua

View File

@@ -1,4 +1,6 @@
./package #!/bin/sh
./package-love.sh
mkdir dist mkdir dist
mkdir dist/windows mkdir dist/windows
mkdir dist/win32 mkdir dist/win32

Binary file not shown.

After

Width:  |  Height:  |  Size: 343 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 591 B

After

Width:  |  Height:  |  Size: 2.3 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 734 B

After

Width:  |  Height:  |  Size: 4.9 KiB

Binary file not shown.

View File

@@ -5,7 +5,7 @@ CreditsScene.title = "Credits"
function CreditsScene:new() function CreditsScene:new()
self.frames = 0 self.frames = 0
-- higher = slower -- higher = slower
self.scroll_speed = 1.85 self.scroll_speed = 1.8
switchBGM("credit_roll", "gm3") switchBGM("credit_roll", "gm3")
DiscordRPC:update({ DiscordRPC:update({
@@ -40,14 +40,14 @@ function CreditsScene:render()
love.graphics.setFont(font_3x5_4) love.graphics.setFont(font_3x5_4)
love.graphics.print("Cambridge Credits", 320, 500 - offset) love.graphics.print("Cambridge Credits", 320, 500 - offset)
love.graphics.print("THANK YOU\nFOR PLAYING!", 320, math.max(2030 - offset, 240)) love.graphics.print("THANK YOU\nFOR PLAYING!", 320, math.max(2050 - offset, 240))
love.graphics.setFont(font_3x5_3) love.graphics.setFont(font_3x5_3)
love.graphics.print("Game Developers", 320, 550 - offset) love.graphics.print("Game Developers", 320, 550 - offset)
love.graphics.print("Project Heads", 320, 640 - offset) love.graphics.print("Project Heads", 320, 640 - offset)
love.graphics.print("Notable Game Developers", 320, 750 - offset) love.graphics.print("Notable Game Developers", 320, 750 - offset)
love.graphics.print("Special Thanks", 320, 1000 - offset) love.graphics.print("Special Thanks", 320, 1000 - offset)
love.graphics.print("- Milla", 320, math.max(2110 - offset, 320)) love.graphics.print("- Milla", 320, math.max(2130 - offset, 320))
love.graphics.setFont(font_3x5_2) love.graphics.setFont(font_3x5_2)
love.graphics.print("Oshisaure\nJoe Zeng", 320, 590 - offset) love.graphics.print("Oshisaure\nJoe Zeng", 320, 590 - offset)
@@ -66,7 +66,7 @@ function CreditsScene:render()
"CylinderKnot\neightsixfivezero\nEricICX\nGesomaru\n" .. "CylinderKnot\neightsixfivezero\nEricICX\nGesomaru\n" ..
"gizmo4487\nJBroms\nKirby703\nKitaru\n" .. "gizmo4487\nJBroms\nKirby703\nKitaru\n" ..
"M1ssing0\nMattMayuga\nMyPasswordIsWeak\n" .. "M1ssing0\nMattMayuga\nMyPasswordIsWeak\n" ..
"Nikki Karissa\noffwo\nOliver\nPineapple\npokemonfan1937\n" .. "Nikki Karissa\nnim\noffwo\nOliver\nPineapple\npokemonfan1937\n" ..
"Pyra Neoxi\nRDST64\nRocketLanterns\nRustyFoxxo\n" .. "Pyra Neoxi\nRDST64\nRocketLanterns\nRustyFoxxo\n" ..
"saphie\nShelleloch\nSimon\nstratus\nSuper302\n" .. "saphie\nShelleloch\nSimon\nstratus\nSuper302\n" ..
"switchpalacecorner\nterpyderp\nTetrian22\nTetro48\nThatCookie\n" .. "switchpalacecorner\nterpyderp\nTetrian22\nTetro48\nThatCookie\n" ..

View File

@@ -9,6 +9,7 @@ function GameScene:new(game_mode, ruleset, inputs)
self.retry_ruleset = ruleset self.retry_ruleset = ruleset
self.secret_inputs = inputs self.secret_inputs = inputs
self.game = game_mode(self.secret_inputs) self.game = game_mode(self.secret_inputs)
self.game.secret_inputs = inputs
self.ruleset = ruleset(self.game) self.ruleset = ruleset(self.game)
self.game:initialize(self.ruleset) self.game:initialize(self.ruleset)
self.inputs = { self.inputs = {
@@ -24,6 +25,8 @@ function GameScene:new(game_mode, ruleset, inputs)
hold=false, hold=false,
} }
self.paused = false self.paused = false
self.game.pause_count = 0
self.game.pause_time = 0
DiscordRPC:update({ DiscordRPC:update({
details = self.game.rpc_details, details = self.game.rpc_details,
state = self.game.name, state = self.game.name,
@@ -32,7 +35,9 @@ function GameScene:new(game_mode, ruleset, inputs)
end end
function GameScene:update() function GameScene:update()
if love.window.hasFocus() and not self.paused then if self.paused then
self.game.pause_time = self.game.pause_time + 1
else
local inputs = {} local inputs = {}
for input, value in pairs(self.inputs) do for input, value in pairs(self.inputs) do
inputs[input] = value inputs[input] = value
@@ -40,6 +45,8 @@ function GameScene:update()
self.game:update(inputs, self.ruleset) self.game:update(inputs, self.ruleset)
self.game.grid:update() self.game.grid:update()
DiscordRPC:update({ DiscordRPC:update({
details = self.game.rpc_details,
state = self.game.name,
largeImageKey = "ingame-"..self.game:getBackground().."00" largeImageKey = "ingame-"..self.game:getBackground().."00"
}) })
end end
@@ -47,6 +54,16 @@ end
function GameScene:render() function GameScene:render()
self.game:draw(self.paused) self.game:draw(self.paused)
if self.game.pause_time > 0 or self.game.pause_count > 0 then
love.graphics.setColor(1, 1, 1, 1)
love.graphics.setFont(font_3x5_2)
love.graphics.printf(string.format(
"%d PAUSE%s (%s)",
self.game.pause_count,
self.game.pause_count == 1 and "" or "S",
formatTime(self.game.pause_time)
), 0, 0, 635, "right")
end
end end
function GameScene:onInputPress(e) function GameScene:onInputPress(e)
@@ -68,8 +85,12 @@ function GameScene:onInputPress(e)
scene = GameScene(self.retry_mode, self.retry_ruleset, self.secret_inputs) scene = GameScene(self.retry_mode, self.retry_ruleset, self.secret_inputs)
elseif e.input == "pause" and not (self.game.game_over or self.game.completed) then elseif e.input == "pause" and not (self.game.game_over or self.game.completed) then
self.paused = not self.paused self.paused = not self.paused
if self.paused then pauseBGM() if self.paused then
else resumeBGM() end pauseBGM()
self.game.pause_count = self.game.pause_count + 1
else
resumeBGM()
end
elseif e.input == "menu_back" then elseif e.input == "menu_back" then
self.game:onExit() self.game:onExit()
scene = ModeSelectScene() scene = ModeSelectScene()

View File

@@ -13,11 +13,12 @@ ConfigScene.options = {
{"world_reverse", "A Button Rotation", false, {"Left", "Auto", "Right"}}, {"world_reverse", "A Button Rotation", false, {"Left", "Auto", "Right"}},
{"spawn_positions", "Spawn Positions", false, {"Per ruleset", "In field", "Out of field"}}, {"spawn_positions", "Spawn Positions", false, {"Per ruleset", "In field", "Out of field"}},
{"display_gamemode", "Debug Info", false, {"On", "Off"}}, {"display_gamemode", "Debug Info", false, {"On", "Off"}},
{"das_last_key", "DAS Last Key", false, {"Off", "On"}}, {"save_replay", "Save Replays", false, {"On", "Off"}},
{"smooth_movement", "Smooth Piece Drop", false, {"On", "Off"}}, {"smooth_movement", "Smooth Piece Drop", false, {"On", "Off"}},
{"synchroes_allowed", "Synchroes", false, {"Per ruleset", "On", "Off"}},
{"diagonal_input", "Diagonal Input", false, {"On", "Off"}}, {"diagonal_input", "Diagonal Input", false, {"On", "Off"}},
{"das_last_key", "DAS Last Key", false, {"Off", "On"}},
{"buffer_lock", "Buffer Drop Type", false, {"Off", "Hold", "Tap"}}, {"buffer_lock", "Buffer Drop Type", false, {"Off", "Hold", "Tap"}},
{"synchroes_allowed", "Synchroes", false, {"Per ruleset", "On", "Off"}},
{"sfx_volume", "SFX", true, "sfxSlider"}, {"sfx_volume", "SFX", true, "sfxSlider"},
{"bgm_volume", "BGM", true, "bgmSlider"}, {"bgm_volume", "BGM", true, "bgmSlider"},
} }
@@ -33,8 +34,8 @@ function ConfigScene:new()
state = "Changing game settings", state = "Changing game settings",
}) })
self.sfxSlider = newSlider(165, 400, 225, config.sfx_volume * 100, 0, 100, function(v) config.sfx_volume = v / 100 end, {width=20, knob="circle", track="roundrect"}) self.sfxSlider = newSlider(165, 420, 225, config.sfx_volume * 100, 0, 100, function(v) config.sfx_volume = v / 100 end, {width=20, knob="circle", track="roundrect"})
self.bgmSlider = newSlider(465, 400, 225, config.bgm_volume * 100, 0, 100, function(v) config.bgm_volume = v / 100 end, {width=20, knob="circle", track="roundrect"}) self.bgmSlider = newSlider(465, 420, 225, config.bgm_volume * 100, 0, 100, function(v) config.bgm_volume = v / 100 end, {width=20, knob="circle", track="roundrect"})
end end
function ConfigScene:update() function ConfigScene:update()
@@ -58,7 +59,7 @@ function ConfigScene:render()
if not ConfigScene.options[self.highlight][3] then if not ConfigScene.options[self.highlight][3] then
love.graphics.rectangle("fill", 25, 98 + self.highlight * 20, 170, 22) love.graphics.rectangle("fill", 25, 98 + self.highlight * 20, 170, 22)
else else
love.graphics.rectangle("fill", 65 + (1+self.highlight-#self.options) * 300, 342, 215, 33) love.graphics.rectangle("fill", 65 + (1+self.highlight-#self.options) * 300, 362, 215, 33)
end end
love.graphics.setFont(font_3x5_2) love.graphics.setFont(font_3x5_2)
@@ -75,8 +76,8 @@ function ConfigScene:render()
love.graphics.setColor(1, 1, 1, 1) love.graphics.setColor(1, 1, 1, 1)
love.graphics.setFont(font_3x5_3) love.graphics.setFont(font_3x5_3)
love.graphics.print("SFX Volume: " .. math.floor(self.sfxSlider:getValue()) .. "%", 75, 345) love.graphics.print("SFX Volume: " .. math.floor(self.sfxSlider:getValue()) .. "%", 75, 365)
love.graphics.print("BGM Volume: " .. math.floor(self.bgmSlider:getValue()) .. "%", 375, 345) love.graphics.print("BGM Volume: " .. math.floor(self.bgmSlider:getValue()) .. "%", 375, 365)
love.graphics.setColor(1, 1, 1, 0.75) love.graphics.setColor(1, 1, 1, 0.75)
self.sfxSlider:draw() self.sfxSlider:draw()

View File

@@ -4,17 +4,21 @@ local ReplayScene = Scene:extend()
ReplayScene.title = "Replay" ReplayScene.title = "Replay"
function ReplayScene:new(replay, game_mode, ruleset, inputs) function ReplayScene:new(replay, game_mode, ruleset)
config.gamesettings = replay["gamesettings"] config.gamesettings = replay["gamesettings"]
if replay["delayed_auto_shift"] then config.das = replay["delayed_auto_shift"] end
if replay["auto_repeat_rate"] then config.arr = replay["auto_repeat_rate"] end
if replay["das_cut_delay"] then config.dcd = replay["das_cut_delay"] end
love.math.setRandomSeed(replay["random_low"], replay["random_high"]) love.math.setRandomSeed(replay["random_low"], replay["random_high"])
love.math.setRandomState(replay["random_state"]) love.math.setRandomState(replay["random_state"])
self.retry_replay = replay self.retry_replay = replay
self.retry_mode = game_mode self.retry_mode = game_mode
self.retry_ruleset = ruleset self.retry_ruleset = ruleset
self.secret_inputs = inputs self.secret_inputs = replay["secret_inputs"]
self.game = game_mode(self.secret_inputs) self.game = game_mode(self.secret_inputs)
self.game.save_replay = false
self.ruleset = ruleset(self.game) self.ruleset = ruleset(self.game)
self.game:initialize(self.ruleset, true) self.game:initialize(self.ruleset)
self.inputs = { self.inputs = {
left=false, left=false,
right=false, right=false,
@@ -28,6 +32,8 @@ function ReplayScene:new(replay, game_mode, ruleset, inputs)
hold=false, hold=false,
} }
self.paused = false self.paused = false
self.game.pause_count = replay["pause_count"]
self.game.pause_time = replay["pause_time"]
self.replay = deepcopy(replay) self.replay = deepcopy(replay)
self.replay_index = 1 self.replay_index = 1
DiscordRPC:update({ DiscordRPC:update({
@@ -38,7 +44,7 @@ function ReplayScene:new(replay, game_mode, ruleset, inputs)
end end
function ReplayScene:update() function ReplayScene:update()
if love.window.hasFocus() and not self.paused then if not self.paused then
self.inputs = self.replay["inputs"][self.replay_index]["inputs"] self.inputs = self.replay["inputs"][self.replay_index]["inputs"]
self.replay["inputs"][self.replay_index]["frames"] = self.replay["inputs"][self.replay_index]["frames"] - 1 self.replay["inputs"][self.replay_index]["frames"] = self.replay["inputs"][self.replay_index]["frames"] - 1
if self.replay["inputs"][self.replay_index]["frames"] == 0 and self.replay_index < table.getn(self.replay["inputs"]) then if self.replay["inputs"][self.replay_index]["frames"] == 0 and self.replay_index < table.getn(self.replay["inputs"]) then
@@ -51,6 +57,8 @@ function ReplayScene:update()
self.game:update(input_copy, self.ruleset) self.game:update(input_copy, self.ruleset)
self.game.grid:update() self.game.grid:update()
DiscordRPC:update({ DiscordRPC:update({
details = "Viewing a replay",
state = self.game.name,
largeImageKey = "ingame-"..self.game:getBackground().."00" largeImageKey = "ingame-"..self.game:getBackground().."00"
}) })
end end
@@ -61,6 +69,19 @@ function ReplayScene:render()
love.graphics.setColor(1, 1, 1, 1) love.graphics.setColor(1, 1, 1, 1)
love.graphics.setFont(font_3x5_3) love.graphics.setFont(font_3x5_3)
love.graphics.printf("REPLAY", 0, 0, 635, "right") love.graphics.printf("REPLAY", 0, 0, 635, "right")
love.graphics.setFont(font_3x5_2)
if self.game.pause_time and self.game.pause_count then
if self.game.pause_time > 0 or self.game.pause_count > 0 then
love.graphics.printf(string.format(
"%d PAUSE%s (%s)",
self.game.pause_count,
self.game.pause_count == 1 and "" or "S",
formatTime(self.game.pause_time)
), 0, 23, 635, "right")
end
else
love.graphics.printf("?? PAUSES (--:--.--)", 0, 23, 635, "right")
end
end end
function ReplayScene:onInputPress(e) function ReplayScene:onInputPress(e)

View File

@@ -83,7 +83,7 @@ function ReplaySelectScene:render()
-- Same graphic as mode select -- Same graphic as mode select
--love.graphics.draw(misc_graphics["select_mode"], 20, 40) --love.graphics.draw(misc_graphics["select_mode"], 20, 40)
love.graphics.setFont(font_3x5_4) love.graphics.setFont(font_8x11)
love.graphics.print("SELECT REPLAY", 20, 35) love.graphics.print("SELECT REPLAY", 20, 35)
if self.display_warning then if self.display_warning then
@@ -121,12 +121,15 @@ function ReplaySelectScene:render()
love.graphics.setFont(font_3x5_2) love.graphics.setFont(font_3x5_2)
for idx, replay in ipairs(replays) do for idx, replay in ipairs(replays) do
if(idx >= self.menu_state.replay-9 and idx <= self.menu_state.replay+9) then if(idx >= self.menu_state.replay-9 and idx <= self.menu_state.replay+9) then
local display_string = os.date("%c", replay["timestamp"]).." "..replay["mode"].." "..replay["ruleset"] local display_string = os.date("%c", replay["timestamp"]).." - "..replay["mode"].." - "..replay["ruleset"]
if replay["level"] ~= nil then if replay["level"] ~= nil then
display_string = display_string.." Level: "..replay["level"] display_string = display_string.." - Level: "..replay["level"]
end end
if replay["timer"] ~= nil then if replay["timer"] ~= nil then
display_string = display_string.." Time: "..formatTime(replay["timer"]) display_string = display_string.." - Time: "..formatTime(replay["timer"])
end
if #display_string > 75 then
display_string = display_string:sub(1, 75) .. "..."
end end
love.graphics.printf(display_string, 6, (260 - 20*(self.menu_state.replay)) + 20 * idx, 640, "left") love.graphics.printf(display_string, 6, (260 - 20*(self.menu_state.replay)) + 20 * idx, 640, "left")
end end
@@ -167,8 +170,7 @@ function ReplaySelectScene:onInputPress(e)
scene = ReplayScene( scene = ReplayScene(
replays[self.menu_state.replay], replays[self.menu_state.replay],
mode, mode,
rules, rules
replays[self.menu_state.replay]["secret_inputs"]
) )
elseif e.input == "up" or e.scancode == "up" then elseif e.input == "up" or e.scancode == "up" then
self:changeOption(-1) self:changeOption(-1)

View File

@@ -60,18 +60,38 @@ function TitleScene:update()
else self.y_offset = 310 - self.frames end else self.y_offset = 310 - self.frames end
end end
local block_offsets = {
{color = "M", x = 0, y = 0},
{color = "G", x = 32, y = 0},
{color = "Y", x = 64, y = 0},
{color = "B", x = 0, y = 32},
{color = "O", x = 0, y = 64},
{color = "C", x = 32, y = 64},
{color = "R", x = 64, y = 64}
}
function TitleScene:render() function TitleScene:render()
love.graphics.setFont(font_3x5_4) love.graphics.setFont(font_3x5_4)
love.graphics.setColor(1, 1, 1, 1 - self.snow_bg_opacity) love.graphics.setColor(1, 1, 1, 1 - self.snow_bg_opacity)
love.graphics.draw( love.graphics.draw(
backgrounds["title"], -- title_night backgrounds["title_no_icon"], -- title, title_night
0, 0, 0, 0, 0, 0,
0.5, 0.5 0.5, 0.5
) )
-- 490, 192
for _, b in ipairs(block_offsets) do
love.graphics.draw(
blocks["2tie"][b.color],
490 + b.x, 192 + b.y, 0,
2, 2
)
end
--[[ --[[
love.graphics.draw( love.graphics.draw(
misc_graphics["icon"], misc_graphics["icon"],
460, 170, 0, 490, 192, 0,
2, 2 2, 2
) )
]] ]]

7
start.bat Normal file
View File

@@ -0,0 +1,7 @@
@echo OFF
rem This solution of detecting the current CPU taken from here: https://stackoverflow.com/a/24590583
reg Query "HKLM\Hardware\Description\System\CentralProcessor\0" | find /i "x86" > NUL && set CURRENT_CPU=32BIT || set CURRENT_CPU=64BIT
if %CURRENT_CPU%==32BIT .\dist\win32\love.exe .
if %CURRENT_CPU%==64BIT .\dist\windows\love.exe .

View File

@@ -231,12 +231,15 @@ function Grid:applyBigPiece(piece)
end end
end end
function Grid:checkForBravo(cleared_row_count) -- places where you see this take an argument used the old, buggy method
for i = 0, self.height - 1 - cleared_row_count do function Grid:checkForBravo()
for i = 0, self.height - 1 do
if not self:isRowFull(i+1) then
for j = 0, self.width - 1 do for j = 0, self.width - 1 do
if self:isOccupied(j, i) then return false end if self:isOccupied(j, i) then return false end
end end
end end
end
return true return true
end end

View File

@@ -16,12 +16,11 @@ GameMode.hash = ""
GameMode.tagline = "" GameMode.tagline = ""
GameMode.rollOpacityFunction = function(age) return 0 end GameMode.rollOpacityFunction = function(age) return 0 end
function GameMode:new(secret_inputs) function GameMode:new()
self.replay_inputs = {} self.replay_inputs = {}
self.random_low, self.random_high = love.math.getRandomSeed() self.random_low, self.random_high = love.math.getRandomSeed()
self.random_state = love.math.getRandomState() self.random_state = love.math.getRandomState()
self.secret_inputs = secret_inputs self.save_replay = config.gamesettings.save_replay == 1
self.save_replay = true
self.grid = Grid(10, 24) self.grid = Grid(10, 24)
self.randomizer = Randomizer() self.randomizer = Randomizer()
@@ -104,7 +103,7 @@ function GameMode:getSkin()
return "2tie" return "2tie"
end end
function GameMode:initialize(ruleset, replay) function GameMode:initialize(ruleset)
-- generate next queue -- generate next queue
self.used_randomizer = ( self.used_randomizer = (
table.equalvalues( table.equalvalues(
@@ -114,7 +113,6 @@ function GameMode:initialize(ruleset, replay)
self.randomizer or BagRandomizer(table.keys(ruleset.colourscheme)) self.randomizer or BagRandomizer(table.keys(ruleset.colourscheme))
) )
self.ruleset = ruleset self.ruleset = ruleset
self.save_replay = not replay
for i = 1, math.max(self.next_queue_length, 1) do for i = 1, math.max(self.next_queue_length, 1) do
table.insert(self.next_queue, self:getNextPiece(ruleset)) table.insert(self.next_queue, self:getNextPiece(ruleset))
end end
@@ -137,25 +135,27 @@ function GameMode:saveReplay()
replay["lines"] = self.lines replay["lines"] = self.lines
replay["gamesettings"] = config.gamesettings replay["gamesettings"] = config.gamesettings
replay["secret_inputs"] = self.secret_inputs replay["secret_inputs"] = self.secret_inputs
replay["delayed_auto_shift"] = config.das
replay["auto_repeat_rate"] = config.arr
replay["das_cut_delay"] = config.dcd
replay["timestamp"] = os.time() replay["timestamp"] = os.time()
replay["pause_count"] = self.pause_count
replay["pause_time"] = self.pause_time
if love.filesystem.getInfo("replays") == nil then if love.filesystem.getInfo("replays") == nil then
love.filesystem.createDirectory("replays") love.filesystem.createDirectory("replays")
end end
local replay_files = love.filesystem.getDirectoryItems("replays") local init_name = string.format("replays/%s.crp", os.date("%Y-%m-%d_%H-%M-%S"))
-- Select replay filename that doesn't collide with an existing one local replay_name = init_name
local replay_number = 0 local replay_number = 0
local collision = true while true do
while collision do if love.filesystem.getInfo(replay_name, "file") then
collision = false
replay_number = replay_number + 1 replay_number = replay_number + 1
for key, file in pairs(replay_files) do replay_name = string.format("%s (%d)", init_name, replay_number)
if file == replay_number..".crp" then else
collision = true
break break
end end
end end
end love.filesystem.write(replay_name, binser.serialize(replay))
love.filesystem.write("replays/"..replay_number..".crp", binser.serialize(replay))
end end
function GameMode:addReplayInput(inputs) function GameMode:addReplayInput(inputs)
@@ -979,9 +979,11 @@ function GameMode:drawSectionTimesWithSplits(current_section, section_limit)
end end
function GameMode:drawBackground() function GameMode:drawBackground()
local id = self:getBackground()
if type(id) == "number" then id = clamp(id, 0, #backgrounds) end
love.graphics.setColor(1, 1, 1, 1) love.graphics.setColor(1, 1, 1, 1)
love.graphics.draw( love.graphics.draw(
backgrounds[self:getBackground()], backgrounds[id],
0, 0, 0, 0, 0, 0,
0.5, 0.5 0.5, 0.5
) )

View File

@@ -353,15 +353,10 @@ function Marathon2020Game:updateSectionTimes(old_level, new_level)
self.section_start_time = self.frames self.section_start_time = self.frames
if ( if (
self.section_status[section - 1] == "cool" and (self.secondary_section_times[section] < cool_cutoffs[self.delay_level]) and
self.secondary_section_times[section] <= self.secondary_section_times[section - 1] + 120 and (section == 1 or self.secondary_section_times[section] <= self.secondary_section_times[section - 1] + 120)
self.secondary_section_times[section] < cool_cutoffs[self.delay_level]
) then ) then
sectionCool(section) sectionCool(section)
elseif self.section_status[section - 1] == "cool" then
table.insert(self.section_status, "none")
elseif self.secondary_section_times[section] < cool_cutoffs[self.delay_level] then
sectionCool(section)
else else
table.insert(self.section_status, "none") table.insert(self.section_status, "none")
end end

View File

@@ -249,12 +249,15 @@ local grade_conversion = {
} }
function MarathonA2Game:whilePieceActive() function MarathonA2Game:whilePieceActive()
if self.clear then return
else
self.grade_point_decay_counter = self.grade_point_decay_counter + 1 self.grade_point_decay_counter = self.grade_point_decay_counter + 1
if self.grade_point_decay_counter >= grade_point_decays[self.grade + 1] then if self.grade_point_decay_counter >= grade_point_decays[self.grade + 1] then
self.grade_point_decay_counter = 0 self.grade_point_decay_counter = 0
self.grade_points = math.max(0, self.grade_points - 1) self.grade_points = math.max(0, self.grade_points - 1)
end end
end end
end
function MarathonA2Game:updateGrade(cleared_lines) function MarathonA2Game:updateGrade(cleared_lines)
if self.clear or cleared_lines == 0 then return if self.clear or cleared_lines == 0 then return

View File

@@ -26,7 +26,9 @@ function MarathonA3Game:new()
self.roll_points = 0 self.roll_points = 0
self.grade_point_decay_counter = 0 self.grade_point_decay_counter = 0
self.section_cool_grade = 0 self.section_cool_grade = 0
self.section_status = { [0] = "none" } --self.section_status = { [0] = "none" }
self.section_cools = { [0] = 0 }
self.section_regrets = { [0] = 0 }
self.section_start_time = 0 self.section_start_time = 0
self.secondary_section_times = { [0] = 0 } self.secondary_section_times = { [0] = 0 }
self.section_times = { [0] = 0 } self.section_times = { [0] = 0 }
@@ -201,15 +203,23 @@ function MarathonA3Game:updateSectionTimes(old_level, new_level)
self.speed_level = self.section_cool and self.speed_level + 100 or self.speed_level self.speed_level = self.section_cool and self.speed_level + 100 or self.speed_level
if section_time > regret_cutoffs[section] then if section_time > regret_cutoffs[section] then
self.section_cool_grade = self.section_cool_grade - 1 if self.grade > 0 then
table.insert(self.section_status, "regret") --this happens after the points are added, intentionally
local currentgrade = self:getAggregateGrade()
while self:getAggregateGrade() >= currentgrade do
self.grade = self.grade - 1
end
self.grade_points = 0
end
table.insert(self.section_regrets, 1)
self.coolregret_message = "REGRET!!" self.coolregret_message = "REGRET!!"
self.coolregret_timer = 300 self.coolregret_timer = 300
elseif self.section_cool then
self.section_cool_grade = self.section_cool_grade + 1
table.insert(self.section_status, "cool")
else else
table.insert(self.section_status, "none") table.insert(self.section_regrets, 0)
end
if self.section_cool then
self.section_cool_grade = self.section_cool_grade + 1
end end
self.section_cool = false self.section_cool = false
@@ -223,6 +233,9 @@ function MarathonA3Game:updateSectionTimes(old_level, new_level)
self.section_cool = true self.section_cool = true
self.coolregret_message = "COOL!!" self.coolregret_message = "COOL!!"
self.coolregret_timer = 300 self.coolregret_timer = 300
table.insert(self.section_cools, 1)
else
table.insert(self.section_cools, 0)
end end
end end
end end
@@ -309,7 +322,7 @@ local mroll_points = {10, 20, 30, 100}
local grade_conversion = { local grade_conversion = {
[0] = 0, [0] = 0,
1, 2, 3, 4, 5, 5, 6, 6, 7, 7, 1, 2, 3, 4, 5, 5, 6, 6, 7, 7,
7, 8, 8, 8, 9, 9, 9, 10, 11, 12, 12, 7, 8, 8, 8, 9, 9, 9, 10, 11, 12,
12, 12, 13, 13, 14, 14, 15, 15, 16, 16, 12, 12, 13, 13, 14, 14, 15, 15, 16, 16,
17 17
} }
@@ -354,8 +367,7 @@ function MarathonA3Game:getAggregateGrade()
return math.min( return math.min(
self.section_cool_grade + self.section_cool_grade +
math.floor(self.roll_points / 100) + math.floor(self.roll_points / 100) +
grade_conversion[self.grade], grade_conversion[self.grade]
self.roll_frames > 3238 and 32 or 31
) )
end end
@@ -403,9 +415,11 @@ MarathonA3Game.mRollOpacityFunction = function(age)
end end
function MarathonA3Game:sectionColourFunction(section) function MarathonA3Game:sectionColourFunction(section)
if self.section_status[section] == "cool" then if self.section_cools[section] == 1 and self.section_regrets[section] == 1 then
return { 1, 1, 0, 1 }
elseif self.section_cools[section] == 1 then
return { 0, 1, 0, 1 } return { 0, 1, 0, 1 }
elseif self.section_status[section] == "regret" then elseif self.section_regrets[section] == 1 then
return { 1, 0, 0, 1 } return { 1, 0, 0, 1 }
else else
return { 1, 1, 1, 1 } return { 1, 1, 1, 1 }

View File

@@ -28,7 +28,6 @@ function PhantomManiaGame:new()
self.combo = 1 self.combo = 1
self.tetrises = 0 self.tetrises = 0
self.section_tetrises = {[0] = 0, 0, 0, 0, 0, 0, 0, 0, 0, 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
@@ -55,7 +54,7 @@ function PhantomManiaGame:getDasLimit()
end end
function PhantomManiaGame:getLineClearDelay() function PhantomManiaGame:getLineClearDelay()
return self:getLineARE() return self:getLineARE() - 2
end end
function PhantomManiaGame:getLockDelay() function PhantomManiaGame:getLockDelay()
@@ -120,11 +119,6 @@ function PhantomManiaGame:onLineClear(cleared_row_count)
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
@@ -175,6 +169,10 @@ local function getLetterGrade(level, clear)
end end
end end
function PhantomManiaGame:qualifiesForGM()
return true
end
function PhantomManiaGame:drawScoringInfo() function PhantomManiaGame:drawScoringInfo()
PhantomManiaGame.super.drawScoringInfo(self) PhantomManiaGame.super.drawScoringInfo(self)
@@ -195,7 +193,7 @@ function PhantomManiaGame:drawScoringInfo()
if getLetterGrade(self.level, self.clear) ~= "" then if getLetterGrade(self.level, self.clear) ~= "" then
if self.roll_frames > 1982 then love.graphics.setColor(1, 0.5, 0, 1) 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 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 if self.level == 999 and self:qualifiesForGM() then
love.graphics.printf("GM", text_x, 140, 90, "left") love.graphics.printf("GM", text_x, 140, 90, "left")
else else
love.graphics.printf(getLetterGrade(self.level, self.clear), text_x, 140, 90, "left") love.graphics.printf(getLetterGrade(self.level, self.clear), text_x, 140, 90, "left")

View File

@@ -41,6 +41,7 @@ function PhantomMania2Game:new()
self.coolregret_message = "" self.coolregret_message = ""
self.coolregret_timer = 0 self.coolregret_timer = 0
self.coolregrets = { [0] = 0 }
end end
function PhantomMania2Game:getARE() function PhantomMania2Game:getARE()
@@ -202,13 +203,13 @@ end
local cool_cutoffs = { local cool_cutoffs = {
frameTime(0,36), frameTime(0,36), frameTime(0,36), frameTime(0,36), frameTime(0,36), frameTime(0,36), frameTime(0,36), frameTime(0,36), frameTime(0,36), frameTime(0,36),
frameTime(0,30), frameTime(0,30), frameTime(0,30), frameTime(0,30), frameTime(0,30), frameTime(0,30), frameTime(0,30), frameTime(0,30), frameTime(0,30), frameTime(0,30),
frameTime(0,27), frameTime(0,27), frameTime(0,27), frameTime(0,30), frameTime(0,30), frameTime(0,30),
} }
local regret_cutoffs = { local regret_cutoffs = {
frameTime(0,50), frameTime(0,50), frameTime(0,50), frameTime(0,50), frameTime(0,50), frameTime(0,50), frameTime(0,50), frameTime(0,50), frameTime(0,50), frameTime(0,50),
frameTime(0,40), frameTime(0,40), frameTime(0,40), frameTime(0,40), frameTime(0,40), frameTime(0,42), frameTime(0,42), frameTime(0,42), frameTime(0,42), frameTime(0,42),
frameTime(0,35), frameTime(0,35), frameTime(0,35), frameTime(0,42), frameTime(0,42), frameTime(0,42),
} }
function PhantomMania2Game:updateSectionTimes(old_level, new_level) function PhantomMania2Game:updateSectionTimes(old_level, new_level)
@@ -219,11 +220,14 @@ function PhantomMania2Game:updateSectionTimes(old_level, new_level)
self.section_start_time = self.frames self.section_start_time = self.frames
if section_time <= cool_cutoffs[section] then if section_time <= cool_cutoffs[section] then
self.grade = self.grade + 2 self.grade = self.grade + 2
table.insert(self.coolregrets, 2)
self.coolregret_message = "COOL!!" self.coolregret_message = "COOL!!"
self.coolregret_timer = 300 self.coolregret_timer = 300
elseif section_time <= regret_cutoffs[section] then elseif section_time <= regret_cutoffs[section] then
self.grade = self.grade + 1 self.grade = self.grade + 1
table.insert(self.coolregrets, 1)
else else
table.insert(self.coolregrets, 0)
self.coolregret_message = "REGRET!!" self.coolregret_message = "REGRET!!"
self.coolregret_timer = 300 self.coolregret_timer = 300
end end
@@ -292,6 +296,16 @@ function PhantomMania2Game:setHoldOpacity()
end end
end end
function PhantomMania2Game:sectionColourFunction(section)
if self.coolregrets[section] == 2 then
return { 0, 1, 0, 1 }
elseif self.coolregrets[section] == 0 then
return { 1, 0, 0, 1 }
else
return { 1, 1, 1, 1 }
end
end
function PhantomMania2Game:drawScoringInfo() function PhantomMania2Game:drawScoringInfo()
PhantomMania2Game.super.drawScoringInfo(self) PhantomMania2Game.super.drawScoringInfo(self)

View File

@@ -13,4 +13,14 @@ function PhantomManiaNGame:new()
self.enable_hold = true self.enable_hold = true
end end
function PhantomManiaNGame:qualifiesForGM()
if self.tetrises < 31 then return false end
for i = 0, 9 do
if self.section_tetrises[i] < (i == 9 and 1 or 2) then
return false
end
end
return true
end
return PhantomManiaNGame return PhantomManiaNGame

View File

@@ -101,6 +101,7 @@ function SurvivalA2Game:onLineClear(cleared_row_count)
self.clear = true self.clear = true
if new_level < 999 then if new_level < 999 then
self.game_over = true self.game_over = true
return
end end
end end
self.level = new_level self.level = new_level

View File

@@ -0,0 +1,49 @@
local Piece = require 'tetris.components.piece'
local Ruleset = require 'tetris.rulesets.arika_ace2'
local ARS = Ruleset:extend()
ARS.name = "ARS-X"
ARS.hash = "ArikaEXP"
ARS.MANIPULATIONS_MAX = 24
ARS.ROTATIONS_MAX = 12
function ARS:onPieceCreate(piece, grid)
piece.manipulations = 0
piece.rotations = 0
piece.lowest_y = -math.huge
end
function ARS:checkNewLow(piece)
for _, block in pairs(piece:getBlockOffsets()) do
local y = piece.position.y + block.y
if y > piece.lowest_y then
piece.manipulations = 0
piece.rotations = 0
piece.lowest_y = y
end
end
end
function ARS:onPieceMove(piece, grid)
piece.lock_delay = 0 -- move reset
if piece:isDropBlocked(grid) then
piece.manipulations = piece.manipulations + 1
if piece.manipulations >= ARS.MANIPULATIONS_MAX then
piece.locked = true
end
end
end
function ARS:onPieceRotate(piece, grid, upward)
piece.lock_delay = 0 -- rotate reset
if upward or piece:isDropBlocked(grid) then
piece.rotations = piece.rotations + 1
if piece.rotations >= ARS.ROTATIONS_MAX and piece:isDropBlocked(grid) then
piece.locked = true
end
end
end
return ARS

View File

@@ -209,7 +209,7 @@ function Ruleset:initializePiece(
local colours local colours
if table.equalvalues( if table.equalvalues(
self.colourscheme, {"I", "J", "L", "O", "S", "T", "Z"} table.keys(self.colourscheme), {"I", "J", "L", "O", "S", "T", "Z"}
) then ) then
colours = ({self.colourscheme, ColourSchemes.Arika, ColourSchemes.TTC})[config.gamesettings.piece_colour] colours = ({self.colourscheme, ColourSchemes.Arika, ColourSchemes.TTC})[config.gamesettings.piece_colour]
else else

View File

@@ -1,5 +1,5 @@
local Piece = require 'tetris.components.piece' local Piece = require 'tetris.components.piece'
local Ruleset = require 'tetris.rulesets.standard_exp' local Ruleset = require 'tetris.rulesets.standard_ace'
local SRS = Ruleset:extend() local SRS = Ruleset:extend()
@@ -8,6 +8,8 @@ SRS.hash = "Standard"
SRS.softdrop_lock = false SRS.softdrop_lock = false
SRS.harddrop_lock = true SRS.harddrop_lock = true
SRS.enable_IRS_wallkicks = true
SRS.MANIPULATIONS_MAX = 15 SRS.MANIPULATIONS_MAX = 15
SRS.wallkicks_line = { SRS.wallkicks_line = {
@@ -33,8 +35,8 @@ SRS.wallkicks_line = {
}, },
}; };
function SRS:attemptWallkicks(piece, new_piece, rot_dir, grid)
function SRS:attemptWallkicks(piece, new_piece, rot_dir, grid)
local kicks local kicks
if piece.shape == "O" then if piece.shape == "O" then
return return
@@ -69,6 +71,12 @@ function SRS:checkNewLow(piece)
end end
end end
function SRS:onPieceCreate(piece, grid)
piece.manipulations = 0
piece.rotations = 0
piece.lowest_y = -math.huge
end
function SRS:onPieceDrop(piece, grid) function SRS:onPieceDrop(piece, grid)
self:checkNewLow(piece) self:checkNewLow(piece)
if piece.manipulations >= self.MANIPULATIONS_MAX and piece:isDropBlocked(grid) then if piece.manipulations >= self.MANIPULATIONS_MAX and piece:isDropBlocked(grid) then
@@ -102,4 +110,6 @@ end
function SRS:canPieceRotate() return true end function SRS:canPieceRotate() return true end
function SRS:get180RotationValue() return 2 end
return SRS return SRS

View File

@@ -1,5 +1,5 @@
local Piece = require 'tetris.components.piece' local Piece = require 'tetris.components.piece'
local Ruleset = require 'tetris.rulesets.ti_srs' local Ruleset = require 'tetris.rulesets.standard_ti'
local SRS = Ruleset:extend() local SRS = Ruleset:extend()

View File

@@ -1,5 +1,5 @@
local Piece = require 'tetris.components.piece' local Piece = require 'tetris.components.piece'
local Ruleset = require 'tetris.rulesets.arika_srs' local Ruleset = require 'tetris.rulesets.standard_ti'
local SRS = Ruleset:extend() local SRS = Ruleset:extend()
@@ -27,8 +27,6 @@ function SRS:checkNewLow(piece)
for _, block in pairs(piece:getBlockOffsets()) do for _, block in pairs(piece:getBlockOffsets()) do
local y = piece.position.y + block.y local y = piece.position.y + block.y
if y > piece.lowest_y then if y > piece.lowest_y then
--piece.manipulations = 0
--piece.rotations = 0
piece.lowest_y = y piece.lowest_y = y
end end
end end