Compare commits

...

79 Commits

Author SHA1 Message Date
nightmareci
ea133c6f8c Merge branch 'master' into 3d_blocks 2023-12-31 08:50:23 -08:00
Ishaan Bhardwaj
d0fdaf30ab
Merge pull request #81 from Tetro48/std-rs-lockpatch
Patch standard.lua to prevent midair lock
2023-10-19 04:27:06 -04:00
Aymir Dmitrievich Danilov
8062f6e3fa
Patch standard.lua to prevent midair lock 2023-10-19 14:33:25 +07:00
Ishaan Bhardwaj
7c3cf0b1bd
Merge pull request #79 from aur9ra/feat-save-replay-once-per-game-only
Ensure replays are only saved once per game
2023-08-25 19:28:34 -04:00
aur9ra
52ddbbc174 Ensure replays are only saved once per game 2023-08-20 22:22:36 -07:00
Ishaan Bhardwaj
5f81c35677
Merge pull request #78 from Tetro48/replay-qol
Replay frame stepping
2023-08-14 11:26:56 -04:00
Tetro48
635ef6270f
Changed frame step input to rotate_left 2023-08-14 21:52:22 +07:00
Tetro48
649dd5f31d
Added frame stepping for replays
`menu_decide` for frame step action is temporary
2023-08-14 21:46:00 +07:00
Ishaan Bhardwaj
34fcc3f659
Merge pull request #77 from Kirby703/master-1
easter egg
2023-08-13 15:49:56 -04:00
Kirby703
4caa268adc
easter egg
scholars remain divided on whether 15640 frames should also be rounded up so as to never jump by .03, or whether it should remain rounded down so as to only have one exceptional timestamp rather than two
2023-08-13 13:51:36 -04:00
Ishaan Bhardwaj
a79552a6f3 Pitching BGM added and implemented in replays 2023-07-30 04:53:23 -04:00
Ishaan Bhardwaj
cd90405865 Simplified Big A2 code 2023-07-27 06:00:48 -04:00
Ishaan Bhardwaj
e69659b2ad Changed the order of the image extensions list
To avoid Funny Stuff
2023-07-26 05:20:55 -04:00
Ishaan Bhardwaj
d90e382037
Merge pull request #76 from infinifen/survival-2020-math-fix
Fix a typo causing crashes in Survival 2020 level 1500+
2023-07-22 11:29:39 -04:00
infinifen
ba6f5bb837 Fix a typo causing crashes in Survival 2020 level 1500+ 2023-07-22 13:21:21 +02:00
Ishaan Bhardwaj
39e9dc3303 Fixed pressing F8 twice at the title screen 2023-07-21 22:55:00 -04:00
Ishaan Bhardwaj
a1f0dfd9f2 Hotfix: Key config screen draws the correct background 2023-07-16 18:40:10 -04:00
Ishaan Bhardwaj
2a21484137 Bump version to v0.3.4 2023-07-16 02:02:55 -04:00
Ishaan Bhardwaj
50410958f0 Re-add clamp for backgrounds beyond the limit 2023-07-16 01:54:20 -04:00
Ishaan Bhardwaj
6fb583e463 Typo fix 2023-07-16 01:52:02 -04:00
Ishaan Bhardwaj
91c8dc3dcc Bump version to v0.3.3.3 2023-07-16 01:50:42 -04:00
Ishaan Bhardwaj
2166a3c6d8 Added support for backgrounds that are not 1280x960 2023-07-16 01:49:26 -04:00
Ishaan Bhardwaj
1556b247fe Style fixes for last pull request 2023-07-16 01:06:06 -04:00
Ishaan Bhardwaj
23d9feb357
Merge pull request #74 from aur9ra/add-video-background-support
Add video background support
2023-07-16 00:48:35 -04:00
Ishaan Bhardwaj
c693871621 Added error handling in the case of a corrupt replay 2023-07-16 00:46:45 -04:00
aur9ra
2ba3611c56 Added support for video backgrounds 2023-07-15 21:28:03 -07:00
aur9ra
602e7105ab Merge branch 'master' into add-video-background-support 2023-07-14 23:23:49 -07:00
Ishaan Bhardwaj
7199aa7ef6 BGM playing changes and bugfixes 2023-07-15 02:18:43 -04:00
Ishaan Bhardwaj
a972c31d9a
Merge pull request #73 from aur9ra/feat-show-invis-in-replay-option
show invis in replay
2023-07-15 01:59:07 -04:00
aur9ra
02f314997d Removed unnecessary change 2023-07-14 22:55:10 -07:00
aur9ra
4769daedf4 Added show invis support to replays. 2023-07-14 22:50:16 -07:00
aur9ra
4478c07acf First commit, WIP 2023-07-14 17:54:35 -07:00
Ishaan Bhardwaj
52d4aeb3d0 Merge branch 'Tetro48-replay-qol' 2023-07-10 20:51:02 -04:00
Ishaan Bhardwaj
91279c9f38 Merge branch 'replay-qol' of https://github.com/Tetro48/cambridge into Tetro48-replay-qol 2023-07-10 20:50:44 -04:00
Ishaan Bhardwaj
0572803627 Fixed a slight indentation error 2023-07-09 22:35:07 -04:00
Tetro48
1fef7b4880
Added replay fast-forwarding 2023-07-10 08:58:09 +07:00
Ishaan Bhardwaj
e09b044de4
Merge pull request #71 from Kirby703/patch-13
fix lategame levelling bug
2023-07-09 20:45:35 -04:00
Kirby703
7d6f783c40
fix lategame levelling bug 2023-07-09 20:06:27 -04:00
Ishaan Bhardwaj
9d365f61a7
Merge pull request #70 from Kirby703/patch-12
fix duplicate cool at 2000
2023-07-09 15:44:04 -04:00
Kirby703
082697c3cd
fix duplicate cool at 2000
now you have to survive the roll for gm! terrifying
2023-07-09 15:41:19 -04:00
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
Tetro48
d868e8b803 Replay tunings fix 2022-03-09 10:05:06 +07: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
42 changed files with 466 additions and 238 deletions

View File

@ -28,11 +28,11 @@ All assets needed are bundled with the executable.
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. 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.
Assuming you're on a 64-bit system, you can double-click `start_win64.bat` to run the game. If that doesn't work, open a Command Prompt where you extracted Cambridge and run: 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 .
If you're on a 32-bit system, you'll want to double-click `start_win32.bat`. If that doesn't work, 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 .
@ -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

@ -60,6 +60,9 @@ function formatTime(frames)
min = math.floor(frames/3600) min = math.floor(frames/3600)
sec = math.floor(frames/60) % 60 sec = math.floor(frames/60) % 60
hund = math.floor(frames/.6) % 100 hund = math.floor(frames/.6) % 100
if frames == 15641 then
hund = math.ceil(frames/.6) % 100
end
str = string.format("%02d:%02d.%02d", min, sec, hund) str = string.format("%02d:%02d.%02d", min, sec, hund)
return str return str
end end

View File

@ -6,14 +6,17 @@ bgm = {
} }
local current_bgm = nil local current_bgm = nil
local pitch = 1
local bgm_locked = false local bgm_locked = false
local unfocused = 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 bgm_locked or config.bgm_volume <= 0 then if config.bgm_volume <= 0 then
current_bgm = nil current_bgm = nil
elseif sound ~= nil then elseif sound ~= nil then
if subsound ~= nil then if subsound ~= nil then
@ -67,25 +70,28 @@ function processBGMFadeout(dt)
fadeout_time = 0 fadeout_time = 0
fading_bgm = false fading_bgm = false
end end
current_bgm:setVolume(fadeout_time * config.bgm_volume / total_fadeout_time) current_bgm:setVolume(
fadeout_time * config.bgm_volume / total_fadeout_time
)
end end
end end
function pauseBGM(f) function pauseBGM()
if f then
unfocused = true
end
if current_bgm ~= nil then if current_bgm ~= nil then
current_bgm:pause() current_bgm:pause()
end end
end end
function resumeBGM(f) function resumeBGM()
if f and scene.paused and unfocused then
unfocused = false
return
end
if current_bgm ~= nil then if current_bgm ~= nil then
current_bgm:play() current_bgm:play()
current_bgm:setPitch(pitch)
end
end
function pitchBGM(new_pitch)
pitch = new_pitch
if current_bgm ~= nil then
current_bgm:setPitch(pitch)
end end
end end

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,106 @@
backgrounds = { named_backgrounds = {
[0] = love.graphics.newImage("res/backgrounds/0.png"), "title", "title_no_icon", "title_night",
love.graphics.newImage("res/backgrounds/100.png"), "snow", "options_input", "options_game"
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_no_icon = love.graphics.newImage("res/backgrounds/title-no-icon.jpg"),
title_night = love.graphics.newImage("res/backgrounds/title-night.jpg"),
snow = love.graphics.newImage("res/backgrounds/snow.png"),
input_config = love.graphics.newImage("res/backgrounds/options-input.png"),
game_config = love.graphics.newImage("res/backgrounds/options-game.png"),
} }
current_playing_bgs = {}
extended_bgs = {}
image_formats = {".jpg", ".png"}
bgpath = "res/backgrounds/"
dir = love.filesystem.getDirectoryItems(bgpath)
backgrounds = {}
local function loadExtendedBgs()
extended_bgs = require("res.backgrounds.extend_section_bg")
end
-- error handling for if there is no extend_section_bg
if pcall(loadExtendedBgs) then end
-- helper method to populate backgrounds
local function createBackgroundIfExists(name, file_name)
local format_index = 1
-- see if background is an extension of another background
if extended_bgs[file_name] ~= nil then
copy_bg = extended_bgs[file_name]
copy_bg = copy_bg / 100
backgrounds[name] = backgrounds[copy_bg]
return true
end
-- try creating image backgrounds
while format_index <= #image_formats do
for num, existing_file in pairs(dir) do
if existing_file == (file_name..image_formats[format_index]) then
local tempBgPath = bgpath .. file_name .. image_formats[format_index]
backgrounds[name] = love.graphics.newImage(tempBgPath)
return true
end
end
format_index = format_index + 1
end
-- try creating video background
if love.filesystem.getInfo(bgpath .. file_name .. ".ogv") then
for num, existing_file in pairs(dir) do
if existing_file == (file_name..".ogv") then
local tempBgPath = bgpath .. file_name .. ".ogv"
backgrounds[name] = love.graphics.newVideo(
tempBgPath, {["audio"] = false}
)
-- you can set audio to true, but the video will not loop
-- properly if audio extends beyond video frames
return true
end
end
end
return false
end
local function stopOtherBgs(bg)
if #current_playing_bgs == 0 and bg:typeOf("Video") then
current_playing_bgs[#current_playing_bgs+1] = bg
end
if #current_playing_bgs >= 1 then
while current_playing_bgs[1] ~= bg and #current_playing_bgs >= 1 do
current_playing_bgs[1]:pause()
current_playing_bgs[1]:rewind()
table.remove(current_playing_bgs, 1)
end
end
end
function fetchBackgroundAndLoop(id)
bg = backgrounds[id]
if bg:typeOf("Video") and not bg:isPlaying() then
bg:rewind()
bg:play()
end
stopOtherBgs(bg)
return bg
end
-- create section backgrounds
local section = 0
while (createBackgroundIfExists(section, section*100)) do
section = section + 1
end
-- create named backgrounds
local nbgIndex = 1
while nbgIndex <= #named_backgrounds do
createBackgroundIfExists(
named_backgrounds[nbgIndex],
string.gsub(named_backgrounds[nbgIndex], "_", "-")
)
nbgIndex = nbgIndex + 1
end
-- in order, the colors are: -- in order, the colors are:
-- red, orange, yellow, green, cyan, blue -- red, orange, yellow, green, cyan, blue
@ -123,3 +198,16 @@ misc_graphics = {
santa = love.graphics.newImage("res/img/santa.png"), santa = love.graphics.newImage("res/img/santa.png"),
icon = love.graphics.newImage("res/img/cambridge_transparent.png") icon = love.graphics.newImage("res/img/cambridge_transparent.png")
} }
-- utility function to allow any size background to be used
-- this will stretch the background to 4:3 aspect ratio
function drawBackground(id)
local bg_object = fetchBackgroundAndLoop(id)
local width = bg_object:getWidth()
local height = bg_object:getHeight()
love.graphics.draw(
bg_object,
0, 0, 0,
640 / width, 480 / height
)
end

View File

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

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"
@ -25,6 +24,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()
config.depth_3d = 100 -- TODO add a setting for this to the menu config.depth_3d = 100 -- TODO add a setting for this to the menu
@ -111,8 +115,8 @@ function love.keypressed(key, scancode)
saveConfig() saveConfig()
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", "single") 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", "directory") local info = love.filesystem.getInfo("ss", "directory")
@ -278,22 +282,17 @@ function love.wheelmoved(x, y)
scene:onInputPress({input=nil, type="wheel", x=x, y=y}) scene:onInputPress({input=nil, type="wheel", x=x, y=y})
end end
function love.focus(f)
if f then
resumeBGM(true)
else
pauseBGM(true)
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
-- 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 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

View File

@ -0,0 +1,14 @@
-- ex: extend_section_bg[100] = 0
-- extend_section_bg[200] = 0
-- the video background associated with section 0 will continue playing into 100 and 200 without restarting.
-- will also cause any existing level 100, 200 backgrounds specified to NOT render.
-- please also note that you cannot currently extend any "named" backgrounds, such as "title" and "options-input"
extend_section_bg = {}
-- extend_section_bg[100] = 0
-- extend_section_bg[200] = 0
-- remove the dashes
return extend_section_bg

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

@ -16,9 +16,7 @@ function CreditsScene:new()
end end
function CreditsScene:update() function CreditsScene:update()
if love.window.hasFocus() then self.frames = self.frames + 1
self.frames = self.frames + 1
end
if self.frames >= 2100 * self.scroll_speed then if self.frames >= 2100 * self.scroll_speed then
playSE("mode_decide") playSE("mode_decide")
scene = TitleScene() scene = TitleScene()
@ -32,11 +30,7 @@ function CreditsScene:render()
local offset = self.frames / self.scroll_speed local offset = self.frames / self.scroll_speed
love.graphics.setColor(1, 1, 1, 1) love.graphics.setColor(1, 1, 1, 1)
love.graphics.draw( drawBackground(19)
backgrounds[19],
0, 0, 0,
0.5, 0.5
)
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)

View File

@ -25,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,
@ -33,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
@ -50,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)
@ -67,12 +81,17 @@ function GameScene:onInputPress(e)
scene = e.input == "retry" and GameScene(self.retry_mode, self.retry_ruleset, self.secret_inputs) or ModeSelectScene() scene = e.input == "retry" and GameScene(self.retry_mode, self.retry_ruleset, self.secret_inputs) or ModeSelectScene()
elseif e.input == "retry" then elseif e.input == "retry" then
switchBGM(nil) switchBGM(nil)
pitchBGM(1)
self.game:onExit() self.game:onExit()
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

@ -45,11 +45,7 @@ end
function ConfigScene:render() function ConfigScene:render()
love.graphics.setColor(1, 1, 1, 1) love.graphics.setColor(1, 1, 1, 1)
love.graphics.draw( drawBackground("options_game")
backgrounds["game_config"],
0, 0, 0,
0.5, 0.5
)
love.graphics.setFont(font_3x5_4) love.graphics.setFont(font_3x5_4)
love.graphics.print("GAME SETTINGS", 80, 40) love.graphics.print("GAME SETTINGS", 80, 40)

View File

@ -20,11 +20,7 @@ function ConfigScene:update() end
function ConfigScene:render() function ConfigScene:render()
love.graphics.setColor(1, 1, 1, 1) love.graphics.setColor(1, 1, 1, 1)
love.graphics.draw( drawBackground("options_input")
backgrounds["input_config"],
0, 0, 0,
0.5, 0.5
)
love.graphics.setFont(font_3x5_4) love.graphics.setFont(font_3x5_4)
love.graphics.print("INPUT CONFIG", 80, 40) love.graphics.print("INPUT CONFIG", 80, 40)

View File

@ -45,11 +45,7 @@ end
function KeyConfigScene:render() function KeyConfigScene:render()
love.graphics.setColor(1, 1, 1, 1) love.graphics.setColor(1, 1, 1, 1)
love.graphics.draw( drawBackground("options_input")
backgrounds["input_config"],
0, 0, 0,
0.5, 0.5
)
love.graphics.setFont(font_3x5_2) love.graphics.setFont(font_3x5_2)
for i, input in ipairs(configurable_inputs) do for i, input in ipairs(configurable_inputs) do

View File

@ -58,11 +58,7 @@ function ModeSelectScene:update()
end end
function ModeSelectScene:render() function ModeSelectScene:render()
love.graphics.draw( drawBackground(0)
backgrounds[0],
0, 0, 0,
0.5, 0.5
)
love.graphics.draw(misc_graphics["select_mode"], 20, 40) love.graphics.draw(misc_graphics["select_mode"], 20, 40)

View File

@ -6,6 +6,9 @@ ReplayScene.title = "Replay"
function ReplayScene:new(replay, game_mode, ruleset) 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
@ -29,8 +32,13 @@ function ReplayScene:new(replay, game_mode, ruleset)
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
self.replay_speed = 1
self.show_invisible = false
self.frame_steps = 0
DiscordRPC:update({ DiscordRPC:update({
details = "Viewing a replay", details = "Viewing a replay",
state = self.game.name, state = self.game.name,
@ -39,18 +47,25 @@ function ReplayScene:new(replay, game_mode, ruleset)
end end
function ReplayScene:update() function ReplayScene:update()
if love.window.hasFocus() and not self.paused then local frames_left = self.replay_speed
self.inputs = self.replay["inputs"][self.replay_index]["inputs"] if not self.paused or self.frame_steps > 0 then
self.replay["inputs"][self.replay_index]["frames"] = self.replay["inputs"][self.replay_index]["frames"] - 1 if self.frame_steps > 0 then
if self.replay["inputs"][self.replay_index]["frames"] == 0 and self.replay_index < table.getn(self.replay["inputs"]) then self.frame_steps = self.frame_steps - 1
self.replay_index = self.replay_index + 1
end end
local input_copy = {} while frames_left > 0 do
for input, value in pairs(self.inputs) do frames_left = frames_left - 1
input_copy[input] = value self.inputs = self.replay["inputs"][self.replay_index]["inputs"]
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
self.replay_index = self.replay_index + 1
end
local input_copy = {}
for input, value in pairs(self.inputs) do
input_copy[input] = value
end
self.game:update(input_copy, self.ruleset)
self.game.grid:update()
end end
self.game:update(input_copy, self.ruleset)
self.game.grid:update()
DiscordRPC:update({ DiscordRPC:update({
details = "Viewing a replay", details = "Viewing a replay",
state = self.game.name, state = self.game.name,
@ -64,6 +79,30 @@ 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")
local pauses_y_coordinate = 23
if self.replay_speed > 1 then
pauses_y_coordinate = pauses_y_coordinate + 20
love.graphics.printf(self.replay_speed.."X", 0, 20, 635, "right")
end
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, pauses_y_coordinate, 635, "right")
end
else
love.graphics.printf("?? PAUSES (--:--.--)", 0, pauses_y_coordinate, 635, "right")
end
if self.show_invisible then
self.game.grid:draw()
love.graphics.setColor(1, 1, 1, 1)
love.graphics.setFont(font_3x5_3)
love.graphics.printf("SHOW INVIS", 64, 60, 160, "center")
end
end end
function ReplayScene:onInputPress(e) function ReplayScene:onInputPress(e)
@ -72,6 +111,8 @@ function ReplayScene:onInputPress(e)
e.input == "menu_decide" or e.input == "menu_decide" or
e.input == "retry" e.input == "retry"
) then ) then
switchBGM(nil)
pitchBGM(1)
self.game:onExit() self.game:onExit()
loadSave() loadSave()
love.math.setRandomSeed(os.time()) love.math.setRandomSeed(os.time())
@ -86,6 +127,23 @@ function ReplayScene:onInputPress(e)
self.paused = not self.paused self.paused = not self.paused
if self.paused then pauseBGM() if self.paused then pauseBGM()
else resumeBGM() end else resumeBGM() end
--frame step
elseif e.input == "rotate_left" then
self.frame_steps = self.frame_steps + 1
elseif e.input == "left" then
self.replay_speed = self.replay_speed - 1
if self.replay_speed < 1 then
self.replay_speed = 1
end
pitchBGM(self.replay_speed)
elseif e.input == "right" then
self.replay_speed = self.replay_speed + 1
if self.replay_speed > 99 then
self.replay_speed = 99
end
pitchBGM(self.replay_speed)
elseif e.input == "hold" then
self.show_invisible = not self.show_invisible
end end
end end

View File

@ -14,8 +14,12 @@ function ReplaySelectScene:new()
replay_file_list = love.filesystem.getDirectoryItems("replays") replay_file_list = love.filesystem.getDirectoryItems("replays")
for i=1,#replay_file_list do for i=1,#replay_file_list do
local data = love.filesystem.read("replays/"..replay_file_list[i]) local data = love.filesystem.read("replays/"..replay_file_list[i])
local new_replay = binser.deserialize(data)[1] local success, new_replay = pcall(
replays[#replays + 1] = new_replay function() return binser.deserialize(data)[1] end
)
if success then
replays[#replays + 1] = new_replay
end
end end
table.sort(replays, function(a, b) table.sort(replays, function(a, b)
return a["timestamp"] > b["timestamp"] return a["timestamp"] > b["timestamp"]
@ -43,8 +47,6 @@ function ReplaySelectScene:new()
end end
function ReplaySelectScene:update() function ReplaySelectScene:update()
switchBGM(nil) -- experimental
if self.das_up or self.das_down or self.das_left or self.das_right then if self.das_up or self.das_down or self.das_left or self.das_right then
self.das = self.das + 1 self.das = self.das + 1
else else
@ -74,16 +76,12 @@ function ReplaySelectScene:update()
end end
function ReplaySelectScene:render() function ReplaySelectScene:render()
love.graphics.draw( drawBackground(0)
backgrounds[0],
0, 0, 0,
0.5, 0.5
)
-- 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

View File

@ -29,11 +29,7 @@ function SettingsScene:update() end
function SettingsScene:render() function SettingsScene:render()
love.graphics.setColor(1, 1, 1, 1) love.graphics.setColor(1, 1, 1, 1)
love.graphics.draw( drawBackground("options_game")
backgrounds["game_config"],
0, 0, 0,
0.5, 0.5
)
love.graphics.setFont(font_3x5_4) love.graphics.setFont(font_3x5_4)
love.graphics.print("SETTINGS", 80, 40) love.graphics.print("SETTINGS", 80, 40)

View File

@ -46,11 +46,7 @@ end
function StickConfigScene:render() function StickConfigScene:render()
love.graphics.setColor(1, 1, 1, 1) love.graphics.setColor(1, 1, 1, 1)
love.graphics.draw( drawBackground("options_input")
backgrounds["input_config"],
0, 0, 0,
0.5, 0.5
)
love.graphics.setFont(font_3x5_2) love.graphics.setFont(font_3x5_2)
for i, input in ipairs(configurable_inputs) do for i, input in ipairs(configurable_inputs) do

View File

@ -74,11 +74,7 @@ local block_offsets = {
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( drawBackground("title_no_icon") -- title, title_night
backgrounds["title_no_icon"], -- title, title_night
0, 0, 0,
0.5, 0.5
)
-- 490, 192 -- 490, 192
for _, b in ipairs(block_offsets) do for _, b in ipairs(block_offsets) do
@ -109,11 +105,7 @@ function TitleScene:render()
love.graphics.setFont(font_3x5_2) love.graphics.setFont(font_3x5_2)
love.graphics.setColor(1, 1, 1, self.snow_bg_opacity) love.graphics.setColor(1, 1, 1, self.snow_bg_opacity)
love.graphics.draw( drawBackground("snow")
backgrounds["snow"],
0, 0, 0,
0.5, 0.5
)
love.graphics.draw( love.graphics.draw(
misc_graphics["santa"], misc_graphics["santa"],

View File

@ -34,11 +34,7 @@ end
function TuningScene:render() function TuningScene:render()
love.graphics.setColor(1, 1, 1, 1) love.graphics.setColor(1, 1, 1, 1)
love.graphics.draw( drawBackground("options_game")
backgrounds["game_config"],
0, 0, 0,
0.5, 0.5
)
love.graphics.setColor(1, 1, 1, 0.5) love.graphics.setColor(1, 1, 1, 0.5)
love.graphics.rectangle("fill", 75, 98 + self.highlight * 75, 400, 33) love.graphics.rectangle("fill", 75, 98 + self.highlight * 75, 400, 33)

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

@ -1 +0,0 @@
dist\win32\love.exe .

View File

@ -1 +0,0 @@
dist\windows\love.exe .

View File

@ -232,12 +232,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 j = 0, self.width - 1 do for i = 0, self.height - 1 do
if self:isOccupied(j, i) then return false end if not self:isRowFull(i+1) then
end for j = 0, self.width - 1 do
if self:isOccupied(j, i) then return false end
end
end end
end
return true return true
end end

View File

@ -10,41 +10,10 @@ BigA2Game.tagline = "Big blocks in the most celebrated TGM mode!"
function BigA2Game:new() function BigA2Game:new()
BigA2Game.super:new() BigA2Game.super:new()
self.big_mode = true self.big_mode = true
end local getClearedRowCount = self.grid.getClearedRowCount
self.grid.getClearedRowCount = function(self)
function BigA2Game:updateScore(level, drop_bonus, cleared_lines) return getClearedRowCount(self) / 2
cleared_lines = cleared_lines / 2
if not self.clear then
self:updateGrade(cleared_lines)
if cleared_lines >= 4 then
self.tetris_count = self.tetris_count + 1
end
if self.grid:checkForBravo(cleared_lines) then self.bravo = 4 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
else self.lines = self.lines + cleared_lines end
end
function BigA2Game:onLineClear(cleared_row_count)
cleared_row_count = cleared_row_count / 2
self:updateSectionTimes(self.level, self.level + cleared_row_count)
self.level = math.min(self.level + cleared_row_count, 999)
if self.level == 999 and not self.clear then
self.clear = true
self.grid:clear()
if self:qualifiesForMRoll() then self.grade = 32 end
self.roll_frames = -150
end end
self.lock_drop = self.level >= 900
self.lock_hard_drop = self.level >= 900
end end
return BigA2Game return BigA2Game

View File

@ -136,25 +136,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 replay_name = string.format("%s (%d)", init_name, replay_number)
for key, file in pairs(replay_files) do else
if file == replay_number..".crp" then break
collision = true
break
end
end end
end end
love.filesystem.write("replays/"..replay_number..".crp", binser.serialize(replay)) love.filesystem.write(replay_name, binser.serialize(replay))
end end
function GameMode:addReplayInput(inputs) function GameMode:addReplayInput(inputs)
@ -178,6 +180,9 @@ function GameMode:update(inputs, ruleset)
if self.game_over or self.completed then if self.game_over or self.completed then
if self.save_replay and self.game_over_frames == 0 then if self.save_replay and self.game_over_frames == 0 then
self:saveReplay() self:saveReplay()
-- ensure replays are only saved once per game, incase self.game_over_frames == 0 for longer than one frame
self.save_replay = false
end end
self.game_over_frames = self.game_over_frames + 1 self.game_over_frames = self.game_over_frames + 1
return return
@ -399,6 +404,7 @@ end
function GameMode:onGameOver() function GameMode:onGameOver()
switchBGM(nil) switchBGM(nil)
pitchBGM(1)
local alpha = 0 local alpha = 0
local animation_length = 120 local animation_length = 120
if self.game_over_frames < animation_length then if self.game_over_frames < animation_length then
@ -981,12 +987,10 @@ 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( drawBackground(id)
backgrounds[self:getBackground()],
0, 0, 0,
0.5, 0.5
)
end end
function GameMode:drawFrame() function GameMode:drawFrame()

View File

@ -283,7 +283,7 @@ function Marathon2020Game:sectionPassed(old_level, new_level)
) )
else else
return ( return (
(new_level < 2001 and math.floor(old_level / 100) < math.floor(new_level / 100)) or (new_level < 2000 and math.floor(old_level / 100) < math.floor(new_level / 100)) or
(new_level >= 2020) (new_level >= 2020)
) )
end end
@ -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,10 +249,13 @@ local grade_conversion = {
} }
function MarathonA2Game:whilePieceActive() function MarathonA2Game:whilePieceActive()
self.grade_point_decay_counter = self.grade_point_decay_counter + 1 if self.clear then return
if self.grade_point_decay_counter >= grade_point_decays[self.grade + 1] then else
self.grade_point_decay_counter = 0 self.grade_point_decay_counter = self.grade_point_decay_counter + 1
self.grade_points = math.max(0, self.grade_points - 1) if self.grade_point_decay_counter >= grade_point_decays[self.grade + 1] then
self.grade_point_decay_counter = 0
self.grade_points = math.max(0, self.grade_points - 1)
end
end end
end end

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
@ -402,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

@ -143,7 +143,7 @@ end
function Survival2020Game:onPieceEnter() function Survival2020Game:onPieceEnter()
if not self.clear and ( if not self.clear and (
(self.level < 1900 and self.level % 100 ~= 99) or (self.level < 1900 and self.level % 100 ~= 99) or
self.level == 2019 (1900 <= self.level and self.level < 2019)
) then ) then
self.level = self.level + 1 self.level = self.level + 1
end end
@ -201,7 +201,7 @@ end
Survival2020Game.opacityFunction = function(age) Survival2020Game.opacityFunction = function(age)
if age > 300 then return 0 if age > 300 then return 0
else return 1 - Math.max(age - 240, 0) / 60 end else return 1 - math.max(age - 240, 0) / 60 end
end end
function Survival2020Game:drawGrid() function Survival2020Game:drawGrid()
@ -249,7 +249,7 @@ function Survival2020Game:drawScoringInfo()
end end
function Survival2020Game:getBackground() function Survival2020Game:getBackground()
return math.floor(self.level / 100) return math.min(19, math.floor(self.level / 100))
end end
function Survival2020Game:getHighscoreData() function Survival2020Game:getHighscoreData()

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

@ -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
@ -85,6 +93,8 @@ function SRS:onPieceMove(piece, grid)
if piece.manipulations >= SRS.MANIPULATIONS_MAX then if piece.manipulations >= SRS.MANIPULATIONS_MAX then
piece.locked = true piece.locked = true
end end
else
piece.locked = false
end end
end end
@ -102,4 +112,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