Compare commits

..

44 Commits

Author SHA1 Message Date
Ishaan Bhardwaj
ffd808e6a0 Added white and black as their own separate colors...
... instead of borrowing from the lock flash / garbage colors
2021-09-21 23:30:51 -04:00
Ishaan Bhardwaj
dd96db170e newline 2021-09-21 18:01:36 -04:00
Ishaan Bhardwaj
7fa547c307 Two quick changes (read comments)
Added mouse wheel support to the mode select menu
BGM now interatcs with pausing correctly
2021-09-20 23:33:27 -04:00
b2d0838f90 Pull bigint.lua from bigint.lua repo 2021-09-20 16:09:02 -04:00
Ishaan Bhardwaj
42375cb2b8 Changed mode select DAS to 15/4 (old 24/6) 2021-09-16 18:05:38 -04:00
Ishaan Bhardwaj
fe162ed215 Mode select changes (read below)
Added DAS to the up/down actions (24F start-up, 6F period)
Added wheel scroll to the up/down/left/right actions
Added a warning in case somehow the player has no modes or rulesets
Mode select will load new modules every time you access it
However, this does not reload changes to existing modules
2021-09-16 14:54:49 -04:00
Brandon McGriff
dda116f00f Merge branch 'master' of https://github.com/SashLilac/cambridge 2021-09-15 17:54:26 -07:00
Brandon McGriff
2d3aeeb47d Fix loading of discordRPC when source path contains non-ASCII characters 2021-09-15 17:54:22 -07:00
Ishaan Bhardwaj
784c768c57 Update SOURCES.md 2021-09-14 22:15:08 -04:00
Ishaan Bhardwaj
c18e7ed244 Fixed hold opacity when level < 1000 2021-09-12 19:28:00 -04:00
Ishaan Bhardwaj
9df6bb9989 Small clean-up in PM2 2021-09-12 19:26:47 -04:00
Brandon McGriff
f5873c97bc Remove debugging prints in save.lua 2021-09-12 14:36:21 -07:00
Brandon McGriff
fabdad056e Fix save data handling when save data directory contains non-ASCII characters 2021-09-12 14:32:21 -07:00
Joe Zeng
0e82a8758c Merge pull request #34 from Kirby703/patch-3
made mode extensible
2021-09-11 23:47:11 -04:00
Kirby703
e78df19112 made mode extensible 2021-09-11 22:39:20 -04:00
Ishaan Bhardwaj
49775b9578 Fixed onEnterOrHold running twice on IHS 2021-09-11 18:19:03 -04:00
Ishaan Bhardwaj
6a3c6ecac0 Changed fullscreen bind to F11 2021-09-09 19:02:38 -04:00
Ishaan Bhardwaj
90cf2ebef5 New onEnterOrHold function (fixes #29) 2021-09-05 23:08:54 -04:00
Ishaan Bhardwaj
799a905a9c Remove redundant if 2021-09-05 22:50:31 -04:00
Ishaan Bhardwaj
985f73c39d Revert "Yet more SOCD handling"
This reverts commit b5db5bbdc3.
2021-09-05 22:44:21 -04:00
Ishaan Bhardwaj
b5db5bbdc3 Yet more SOCD handling 2021-09-04 22:45:20 -04:00
Ishaan Bhardwaj
438acde2e2 Better (default) SOCD handling 2021-09-04 22:33:53 -04:00
Ishaan Bhardwaj
0e1f40ad30 Amend the copying functions 2021-08-27 17:18:06 -04:00
Ishaan Bhardwaj
6cf6568a57 Revert "Fixed spawn positions on larger than 10w boards"
This reverts commit dafc113038.

This didn't actually fix the problem, so it's been reverted.
2021-08-20 19:09:50 -04:00
Ishaan Bhardwaj
dafc113038 Fixed spawn positions on larger than 10w boards 2021-08-20 18:53:07 -04:00
Ishaan Bhardwaj
923f3d3696 Added drawIfPaused to gamemode.lua 2021-08-19 14:16:34 -04:00
Ishaan Bhardwaj
db4132bf31 License update, added more credits 2021-08-19 14:15:57 -04:00
Ishaan Bhardwaj
c58018dd51 Two changes to main.lua (read comments)
Disallowed trying to load a directory
Required funcs.lua at the beginning of the program so mod makers don't have to anywhere else
2021-08-15 23:50:00 -04:00
Ishaan Bhardwaj
c7d0034f9b Two changes to gamemode.lua (read comments)
Shape is now passed as an argument to ruleset:getDefaultOrientation()
Fixed the comment for GameMode:transformScreen()
2021-08-11 19:44:57 -04:00
Ishaan Bhardwaj
ed5ea72e66 Cleaning up ruleset.lua 2021-08-11 19:30:46 -04:00
Ishaan Bhardwaj
dc3ad825dc Fix to #27 + some other gamemode functionality 2021-08-09 00:29:22 -04:00
Ishaan Bhardwaj
40cba83003 Fixed a bug with the volume sliders...
...where the SFX that played upon changing the slider's value...
...reflected the old value instead of the new one.
2021-08-04 16:46:41 -04:00
a1b3f73787 Merge pull request #25 from Kirby703/patch-2
fix a3 cools
2021-07-29 23:41:27 -04:00
Kirby703
4243d6b2ba fix a3 cools 2021-07-28 18:38:22 -04:00
33b3ad2889 Merge pull request #24 from Kirby703/patch-1
0xx-3xx line clear delay fix
2021-07-28 10:42:09 -04:00
Kirby703
adab1df480 0xx-3xx line clear delay fix 2021-07-28 05:22:26 -04:00
Joe Z
711fa830a3 Added a few minutes to the torikans. 2021-07-18 22:20:51 -04:00
Joe Z
c434a3406b Changed the 2-second rule to give the cool at exactly 2 seconds. 2021-07-18 21:23:50 -04:00
Joe Zeng
769b5043e3 Added a 25,000 grade point requirement to the GM roll.
You need to go a _little_ further than the point grade of 30 to qualify for GM.
2021-07-18 00:25:05 -04:00
Ishaan Bhardwaj
713c62d807 Fixed Death giving GM below 999 2021-07-18 00:13:57 -04:00
Ishaan Bhardwaj
c3f6e34518 New build scripts for targets other than Windows 2021-07-17 23:08:01 -04:00
Ishaan Bhardwaj
4d0f6ab9fc Easier-to-see bone blocks 2021-07-17 16:25:16 -04:00
Ishaan Bhardwaj
594aa2620f Added another game to the notable games section 2021-07-16 16:50:27 -04:00
Ishaan Bhardwaj
199b535f70 Added a game to the README 2021-07-16 16:24:01 -04:00
28 changed files with 373 additions and 148 deletions

1
.gitignore vendored
View File

@@ -1,5 +1,6 @@
*.sav *.sav
*.love *.love
*.zip
dist/*.zip dist/*.zip
dist/**/cambridge.exe dist/**/cambridge.exe
dist/**/libs dist/**/libs

View File

@@ -1,4 +1,4 @@
Copyright (c) 2018-2019 Joe Zeng Copyright (c) 2018-2021 Joe Zeng, Ishaan Bhardwaj
Permission is hereby granted, free of charge, to any person obtaining a copy Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal of this software and associated documentation files (the "Software"), to deal

View File

@@ -98,12 +98,14 @@ Other Notable Games
- [ZTrix](https://discord.gg/MGhqCBDGNH) by Electra - [ZTrix](https://discord.gg/MGhqCBDGNH) by Electra
- [Shiromino](https://github.com/shiromino/shiromino) by Felicity/nightmareci/kdex - [Shiromino](https://github.com/shiromino/shiromino) by Felicity/nightmareci/kdex
- [Cursed Blocks](https://github.com/Manabender/Cursed-Blocks) by Manabender - [Cursed Blocks](https://github.com/Manabender/Cursed-Blocks) by Manabender
- Picoris 1/2 by MarkGamed - [Picoris 2](https://www.lexaloffle.com/bbs/?tid=41733) by MarkGamed
- [Tetra Online](https://github.com/Juan-Cartes/Tetra-Offline) by Mine - [Tetra Online](https://github.com/Juan-Cartes/Tetra-Offline) by Mine
- [Techmino](https://discord.gg/6Yuww44tq8) by MrZ - [Techmino](https://discord.gg/6Yuww44tq8) by MrZ
- [Example Block Game](https://github.com/oshisaure/example-block-game) by Oshisaure
- [TETR.IO](https://tetr.io) by osk - [TETR.IO](https://tetr.io) by osk
- [Master of Blocks](https://discord.gg/72FZ49mjWh) by Phoenix Flare - [Master of Blocks](https://discord.gg/72FZ49mjWh) by Phoenix Flare
- [Spirit Drop](https://rayblastgames.com/spiritdrop.php) by RayRay26 - [Spirit Drop](https://rayblastgames.com/spiritdrop.php) by RayRay26
- [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/625496179433668635/763363717730664458/Icon_2.png)

View File

@@ -170,3 +170,51 @@ LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
discord-rpc (https://github.com/discord/discord-rpc)
--------------------
Copyright 2017 Discord, Inc.
Permission is hereby granted, free of charge, to any person obtaining a copy of
this software and associated documentation files (the "Software"), to deal in
the Software without restriction, including without limitation the rights to
use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies
of the Software, and to permit persons to whom the Software is furnished to do
so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
lua-discordRPC (https://github.com/pfirsich/lua-discordRPC)
--------------------
MIT License
Copyright (c) 2018 Joel Schumacher
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

View File

@@ -7,5 +7,11 @@
@del dist\win32\SOURCES.md @del dist\win32\SOURCES.md
@del dist\win32\LICENSE.md @del dist\win32\LICENSE.md
@rmdir /Q /S dist\win32\libs @rmdir /Q /S dist\win32\libs
@del dist\other\cambridge.love
@del dist\other\SOURCES.md
@del dist\other\LICENSE.md
@rmdir /Q /S dist\other\libs
@rmdir /Q /S dist\other
@del dist\cambridge-windows.zip @del dist\cambridge-windows.zip
@del dist\cambridge-win32.zip @del dist\cambridge-win32.zip
@del dist\cambridge-other.zip

View File

@@ -1,10 +1,20 @@
function copy(t) function copy(t)
-- returns deep copy of t (as opposed to the shallow copy you get from var = t) -- returns top-layer shallow copy of t
if type(t) ~= "table" then return t end if type(t) ~= "table" then return t end
local meta = getmetatable(t)
local target = {} local target = {}
for k, v in pairs(t) do target[k] = v end for k, v in next, t do target[k] = v end
setmetatable(target, meta) setmetatable(target, getmetatable(t))
return target
end
function deepcopy(t)
-- returns infinite-layer deep copy of t
if type(t) ~= "table" then return t end
local target = {}
for k, v in next, t do
target[deepcopy(k)] = deepcopy(v)
end
setmetatable(target, deepcopy(getmetatable(t)))
return target return target
end end

View File

@@ -2,11 +2,12 @@
-- If this variable is true, then strict type checking is performed for all -- If this variable is true, then strict type checking is performed for all
-- operations. This may result in slower code, but it will allow you to catch -- operations. This may result in slower code, but it will allow you to catch
-- errors and bugs earlier. -- errors and bugs earlier.
local strict = false local strict = true
-------------------------------------------------------------------------------- --------------------------------------------------------------------------------
local bigint = {} local bigint = {}
setmetatable(bigint, {__call = function(_, arg) return bigint.new(arg) end})
local mt = { local mt = {
__add = function(lhs, rhs) __add = function(lhs, rhs)
@@ -76,7 +77,7 @@ function bigint.new(num)
end end
end end
return self return bigint.strip(self)
end end
-- Check the type of a big -- Check the type of a big
@@ -96,6 +97,14 @@ function bigint.check(big, force)
return true return true
end end
-- Strip leading zeroes from a big, but don't remove the last zero
function bigint.strip(big)
while (#big.digits > 1) and (big.digits[1] == 0) do
table.remove(big.digits, 1)
end
return big
end
-- Return a new big with the same digits but with a positive sign (absolute -- Return a new big with the same digits but with a positive sign (absolute
-- value) -- value)
function bigint.abs(big) function bigint.abs(big)
@@ -329,12 +338,7 @@ function bigint.subtract_raw(big1, big2)
---------------------------------------------------------------------------- ----------------------------------------------------------------------------
-- Strip leading zeroes if any, but not if 0 is the only digit return bigint.strip(result)
while (#result.digits > 1) and (result.digits[1] == 0) do
table.remove(result.digits, 1)
end
return result
end end
-- FRONTEND: Addition and subtraction operations, accounting for signs -- FRONTEND: Addition and subtraction operations, accounting for signs
@@ -364,6 +368,7 @@ function bigint.add(big1, big2)
return result return result
end end
function bigint.subtract(big1, big2) function bigint.subtract(big1, big2)
-- Type checking is done by bigint.compare in bigint.add -- Type checking is done by bigint.compare in bigint.add
-- Subtracting is like adding a negative -- Subtracting is like adding a negative
@@ -460,7 +465,7 @@ end
function bigint.exponentiate(big, power) function bigint.exponentiate(big, power)
-- Type checking for big done by bigint.multiply -- Type checking for big done by bigint.multiply
assert(bigint.compare(power, bigint.new(0), ">="), assert(bigint.compare(power, bigint.new(0), ">="),
" negative powers are not supported") "negative powers are not supported")
local exp = power:clone() local exp = power:clone()
if (bigint.compare(exp, bigint.new(0), "==")) then if (bigint.compare(exp, bigint.new(0), "==")) then
@@ -530,12 +535,7 @@ function bigint.divide_raw(big1, big2)
end end
end end
-- Remove leading zeros from result return bigint.strip(result), dividend
while (result.digits[1] == 0) do
table.remove(result.digits, 1)
end
return result, dividend
end end
end end

View File

@@ -24,6 +24,59 @@ if osname == "Linux" then
elseif osname == "OS X" then elseif osname == "OS X" then
discordRPClib = ffi.load(source.."/libs/discord-rpc.dylib") discordRPClib = ffi.load(source.."/libs/discord-rpc.dylib")
elseif osname == "Windows" then elseif osname == "Windows" then
-- I would strongly advise never touching this. It was not trivial to get correct. -nightmareci
ffi.cdef[[
typedef uint32_t DWORD;
typedef char CHAR;
typedef CHAR *LPSTR;
typedef const CHAR *LPCSTR;
typedef wchar_t WCHAR;
typedef WCHAR *LPWSTR;
typedef LPWSTR PWSTR;
typedef const WCHAR *LPCWSTR;
static const DWORD CP_UTF8 = 65001;
int32_t MultiByteToWideChar(
DWORD CodePage,
DWORD dwFlags,
LPCSTR lpMultiByteStr,
int32_t cbMultiByte,
LPWSTR lpWideCharStr,
int32_t cchWideChar
);
int32_t WideCharToMultiByte(
DWORD CodePage,
DWORD dwFlags,
LPCWSTR lpWideCharStr,
int32_t cchWideChar,
LPSTR lpMultiByteStr,
int32_t cbMultiByte,
void* lpDefaultChar,
void* lpUsedDefaultChar
);
DWORD GetShortPathNameW(
LPCWSTR lpszLongPath,
LPWSTR lpszShortPath,
DWORD cchBuffer
);
]]
local originalWideSize = ffi.C.MultiByteToWideChar(ffi.C.CP_UTF8, 0, source, -1, nil, 0)
local originalWide = ffi.new('WCHAR[?]', originalWideSize)
ffi.C.MultiByteToWideChar(ffi.C.CP_UTF8, 0, source, -1, originalWide, originalWideSize)
local sourceSize = ffi.C.GetShortPathNameW(originalWide, nil, 0)
local sourceWide = ffi.new('WCHAR[?]', sourceSize)
ffi.C.GetShortPathNameW(originalWide, sourceWide, sourceSize)
local sourceChar = ffi.new('char[?]', sourceSize)
ffi.C.WideCharToMultiByte(ffi.C.CP_UTF8, 0, sourceWide, sourceSize, sourceChar, sourceSize, nil, nil)
source = ffi.string(sourceChar)
discordRPClib = ffi.load(source.."/libs/discord-rpc.dll") discordRPClib = ffi.load(source.."/libs/discord-rpc.dll")
else else
-- Else it crashes later on -- Else it crashes later on

View File

@@ -7,6 +7,7 @@ bgm = {
local current_bgm = nil local current_bgm = nil
local bgm_locked = false local bgm_locked = false
local unfocused = false
function switchBGM(sound, subsound) function switchBGM(sound, subsound)
if current_bgm ~= nil then if current_bgm ~= nil then
@@ -56,7 +57,7 @@ end
function resetBGMFadeout(time) function resetBGMFadeout(time)
current_bgm:setVolume(config.bgm_volume) current_bgm:setVolume(config.bgm_volume)
fading_bgm = false fading_bgm = false
current_bgm:play() resumeBGM()
end end
function processBGMFadeout(dt) function processBGMFadeout(dt)
@@ -70,13 +71,20 @@ function processBGMFadeout(dt)
end end
end end
function pauseBGM() function pauseBGM(f)
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() function resumeBGM(f)
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()
end end

View File

@@ -25,6 +25,15 @@ backgrounds = {
game_config = love.graphics.newImage("res/backgrounds/options-game.png"), game_config = love.graphics.newImage("res/backgrounds/options-game.png"),
} }
-- in order, the colors are:
-- red, orange, yellow, green, cyan, blue
-- magenta (or purple), white, black
-- the next three don't have colors tied to them
-- F is used for lock flash
-- A is a garbage block
-- X is an invisible "block"
-- don't use these for piece colors when making a ruleset
-- all the others are fine to use
blocks = { blocks = {
["2tie"] = { ["2tie"] = {
R = love.graphics.newImage("res/img/s1.png"), R = love.graphics.newImage("res/img/s1.png"),
@@ -34,6 +43,8 @@ blocks = {
C = love.graphics.newImage("res/img/s2.png"), C = love.graphics.newImage("res/img/s2.png"),
B = love.graphics.newImage("res/img/s4.png"), B = love.graphics.newImage("res/img/s4.png"),
M = love.graphics.newImage("res/img/s5.png"), M = love.graphics.newImage("res/img/s5.png"),
W = love.graphics.newImage("res/img/s9.png"),
D = love.graphics.newImage("res/img/s8.png"),
F = love.graphics.newImage("res/img/s9.png"), F = love.graphics.newImage("res/img/s9.png"),
A = love.graphics.newImage("res/img/s8.png"), A = love.graphics.newImage("res/img/s8.png"),
X = love.graphics.newImage("res/img/s9.png"), X = love.graphics.newImage("res/img/s9.png"),
@@ -46,6 +57,8 @@ blocks = {
C = love.graphics.newImage("res/img/bone.png"), C = love.graphics.newImage("res/img/bone.png"),
B = love.graphics.newImage("res/img/bone.png"), B = love.graphics.newImage("res/img/bone.png"),
M = love.graphics.newImage("res/img/bone.png"), M = love.graphics.newImage("res/img/bone.png"),
W = love.graphics.newImage("res/img/bone.png"),
D = love.graphics.newImage("res/img/bone.png"),
F = love.graphics.newImage("res/img/bone.png"), F = love.graphics.newImage("res/img/bone.png"),
A = love.graphics.newImage("res/img/bone.png"), A = love.graphics.newImage("res/img/bone.png"),
X = love.graphics.newImage("res/img/bone.png"), X = love.graphics.newImage("res/img/bone.png"),
@@ -58,13 +71,16 @@ blocks = {
C = love.graphics.newImage("res/img/gem2.png"), C = love.graphics.newImage("res/img/gem2.png"),
B = love.graphics.newImage("res/img/gem4.png"), B = love.graphics.newImage("res/img/gem4.png"),
M = love.graphics.newImage("res/img/gem5.png"), M = love.graphics.newImage("res/img/gem5.png"),
W = love.graphics.newImage("res/img/gem9.png"),
D = love.graphics.newImage("res/img/gem9.png"),
F = love.graphics.newImage("res/img/gem9.png"), F = love.graphics.newImage("res/img/gem9.png"),
A = love.graphics.newImage("res/img/gem9.png"), A = love.graphics.newImage("res/img/gem9.png"),
X = love.graphics.newImage("res/img/gem9.png"), X = love.graphics.newImage("res/img/gem9.png"),
}, },
["square"] = { ["square"] = {
F = love.graphics.newImage("res/img/squares.png"), W = love.graphics.newImage("res/img/squares.png"),
Y = love.graphics.newImage("res/img/squareg.png"), Y = love.graphics.newImage("res/img/squareg.png"),
F = love.graphics.newImage("res/img/squares.png"),
X = love.graphics.newImage("res/img/squares.png"), X = love.graphics.newImage("res/img/squares.png"),
} }
} }
@@ -87,7 +103,7 @@ ColourSchemes = {
Z = "R", Z = "R",
O = "Y", O = "Y",
T = "M", T = "M",
}, }
} }
for name, blockset in pairs(blocks) do for name, blockset in pairs(blocks) do

View File

@@ -1,23 +1,16 @@
local binser = require 'libs.binser' local binser = require 'libs.binser'
function loadSave() function loadSave()
local info = love.filesystem.getInfo( config = loadFromFile('config.sav')
love.filesystem.getSaveDirectory(), "directory" highscores = loadFromFile('highscores.sav')
)
if not info then
love.filesystem.remove(love.filesystem.getSaveDirectory())
love.filesystem.createDirectory(love.filesystem.getSaveDirectory())
end
config = loadFromFile(
love.filesystem.getSaveDirectory() .. '/config.sav'
)
highscores = loadFromFile(
love.filesystem.getSaveDirectory() .. '/highscores.sav'
)
end end
function loadFromFile(filename) function loadFromFile(filename)
local save_data, len = binser.readFile(filename) local file_data = love.filesystem.read(filename)
if file_data == nil then
return {} -- new object
end
local save_data = binser.deserialize(file_data)
if save_data == nil then if save_data == nil then
return {} -- new object return {} -- new object
end end
@@ -51,13 +44,13 @@ function initConfig()
end end
function saveConfig() function saveConfig()
binser.writeFile( love.filesystem.write(
love.filesystem.getSaveDirectory() .. '/config.sav', config 'config.sav', binser.serialize(config)
) )
end end
function saveHighscores() function saveHighscores()
binser.writeFile( love.filesystem.write(
love.filesystem.getSaveDirectory() .. '/highscores.sav', highscores 'highscores.sav', binser.serialize(highscores)
) )
end end

View File

@@ -10,6 +10,7 @@ function love.load()
require "load.bigint" require "load.bigint"
require "load.version" require "load.version"
loadSave() loadSave()
require "funcs"
require "scene" require "scene"
--config["side_next"] = false --config["side_next"] = false
@@ -36,14 +37,14 @@ function initModules()
game_modes = {} game_modes = {}
mode_list = love.filesystem.getDirectoryItems("tetris/modes") mode_list = love.filesystem.getDirectoryItems("tetris/modes")
for i=1,#mode_list do for i=1,#mode_list do
if(mode_list[i] ~= "gamemode.lua" and mode_list[i] ~= "unrefactored_modes") then if(mode_list[i] ~= "gamemode.lua" and string.sub(mode_list[i], -4) == ".lua") then
game_modes[#game_modes+1] = require ("tetris.modes."..string.sub(mode_list[i],1,-5)) game_modes[#game_modes+1] = require ("tetris.modes."..string.sub(mode_list[i],1,-5))
end end
end end
rulesets = {} rulesets = {}
rule_list = love.filesystem.getDirectoryItems("tetris/rulesets") rule_list = love.filesystem.getDirectoryItems("tetris/rulesets")
for i=1,#rule_list do for i=1,#rule_list do
if(rule_list[i] ~= "ruleset.lua" and rule_list[i] ~= "unrefactored_rulesets") then if(rule_list[i] ~= "ruleset.lua" and string.sub(rule_list[i], -4) == ".lua") then
rulesets[#rulesets+1] = require ("tetris.rulesets."..string.sub(rule_list[i],1,-5)) rulesets[#rulesets+1] = require ("tetris.rulesets."..string.sub(rule_list[i],1,-5))
end end
end end
@@ -82,7 +83,7 @@ end
function love.keypressed(key, scancode) function love.keypressed(key, scancode)
-- global hotkeys -- global hotkeys
if scancode == "f4" then if scancode == "f11" then
config["fullscreen"] = not config["fullscreen"] config["fullscreen"] = not config["fullscreen"]
saveConfig() saveConfig()
love.window.setFullscreen(config["fullscreen"]) love.window.setFullscreen(config["fullscreen"])
@@ -258,11 +259,15 @@ function love.joystickhat(joystick, hat, direction)
end end
end end
function love.wheelmoved(x, y)
scene:onInputPress({input=nil, type="wheel", x=x, y=y})
end
function love.focus(f) function love.focus(f)
if f and (scene.title ~= "Game" or not scene.paused) then if f then
resumeBGM() resumeBGM(true)
else else
pauseBGM() pauseBGM(true)
end end
end end

View File

@@ -2,8 +2,10 @@
mkdir dist mkdir dist
mkdir dist/windows mkdir dist/windows
mkdir dist/win32 mkdir dist/win32
cp cambridge.love dist/ mkdir dist/other
cat dist/windows/love.exe cambridge.love > dist/windows/cambridge.exe cat dist/windows/love.exe cambridge.love > dist/windows/cambridge.exe
zip dist/cambridge-windows.zip dist/windows/* SOURCES.md LICENSE.md zip dist/cambridge-windows.zip dist/windows/* SOURCES.md LICENSE.md
cat dist/win32/love.exe cambridge.love > dist/win32/cambridge.exe cat dist/win32/love.exe cambridge.love > dist/win32/cambridge.exe
zip dist/cambridge-win32.zip dist/win32/* SOURCES.md LICENSE.md zip dist/cambridge-win32.zip dist/win32/* SOURCES.md LICENSE.md
cp cambridge.love dist/other/
zip dist/cambridge-other.zip cambridge.love libs/discord-rpc.* SOURCES.md LICENSE.md

View File

@@ -5,17 +5,23 @@ mkdir dist\windows
mkdir dist\windows\libs mkdir dist\windows\libs
mkdir dist\win32 mkdir dist\win32
mkdir dist\win32\libs mkdir dist\win32\libs
mkdir dist\other
mkdir dist\other\libs
copy /b dist\windows\love.exe+cambridge.love dist\windows\cambridge.exe copy /b dist\windows\love.exe+cambridge.love dist\windows\cambridge.exe
copy /b dist\win32\love.exe+cambridge.love dist\win32\cambridge.exe copy /b dist\win32\love.exe+cambridge.love dist\win32\cambridge.exe
copy /b cambridge.love dist\other\cambridge.love
copy libs\discord-rpc.dll dist\windows\libs copy libs\discord-rpc.dll dist\windows\libs
copy libs\discord-rpc.dll dist\win32\libs copy libs\discord-rpc.dll dist\win32\libs
copy libs\discord-rpc.* dist\other\libs
copy SOURCES.md dist\windows copy SOURCES.md dist\windows
copy LICENSE.md dist\windows copy LICENSE.md dist\windows
copy SOURCES.md dist\win32 copy SOURCES.md dist\win32
copy LICENSE.md dist\win32 copy LICENSE.md dist\win32
copy SOURCES.md dist\other
copy LICENSE.md dist\other
cd dist\windows cd dist\windows
tar -a -c -f ..\cambridge-windows.zip cambridge.exe *.dll libs *.md tar -a -c -f ..\cambridge-windows.zip cambridge.exe *.dll libs *.md
@@ -24,3 +30,7 @@ cd ..\..
cd dist\win32 cd dist\win32
tar -a -c -f ..\cambridge-win32.zip cambridge.exe *.dll libs *.md tar -a -c -f ..\cambridge-win32.zip cambridge.exe *.dll libs *.md
cd ..\.. cd ..\..
cd dist\other
tar -a -c -f ..\cambridge-other.zip cambridge.love libs *.md
cd ..\..

Binary file not shown.

Before

Width:  |  Height:  |  Size: 188 B

After

Width:  |  Height:  |  Size: 151 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 153 B

After

Width:  |  Height:  |  Size: 151 B

Binary file not shown.

Before

Width:  |  Height:  |  Size: 926 B

After

Width:  |  Height:  |  Size: 1.1 KiB

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.9 self.scroll_speed = 1.85
switchBGM("credit_roll", "gm3") switchBGM("credit_roll", "gm3")
end end
@@ -34,14 +34,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(2010 - offset, 240)) love.graphics.print("THANK YOU\nFOR PLAYING!", 320, math.max(2030 - 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, 730 - offset) love.graphics.print("Notable Game Developers", 320, 730 - offset)
love.graphics.print("Special Thanks", 320, 980 - offset) love.graphics.print("Special Thanks", 320, 1000 - offset)
love.graphics.print("- Milla", 320, math.max(2090 - offset, 320)) love.graphics.print("- Milla", 320, math.max(2110 - 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)
@@ -51,7 +51,7 @@ function CreditsScene:render()
"Electra - ZTrix\nFelicity/nightmareci/kdex - Shiromino\n" .. "Electra - ZTrix\nFelicity/nightmareci/kdex - Shiromino\n" ..
"Mine - Tetra Online\nMrZ - Techmino\nosk - TETR.IO\n" .. "Mine - Tetra Online\nMrZ - Techmino\nosk - TETR.IO\n" ..
"Phoenix Flare - Master of Blocks\nRayRay26 - Spirit Drop\n" .. "Phoenix Flare - Master of Blocks\nRayRay26 - Spirit Drop\n" ..
"sinefuse - stackfuse", "Rin - Puzzle Trial\nsinefuse - stackfuse",
320, 770 - offset 320, 770 - offset
) )
love.graphics.print( love.graphics.print(
@@ -69,7 +69,7 @@ function CreditsScene:render()
"Tetra Legends Discord\nTetra Online Discord\nMultimino Discord\n" .. "Tetra Legends Discord\nTetra Online Discord\nMultimino Discord\n" ..
"Hard Drop Discord\nRusty's Systemspace\nCambridge Discord\n" .. "Hard Drop Discord\nRusty's Systemspace\nCambridge Discord\n" ..
"And to you, the player!", "And to you, the player!",
320, 1020 - offset 320, 1040 - offset
) )
end end

View File

@@ -100,9 +100,10 @@ function ConfigScene:onInputPress(e)
local option = ConfigScene.options[self.highlight] local option = ConfigScene.options[self.highlight]
config.gamesettings[option[1]] = Mod1(config.gamesettings[option[1]]-1, #option[4]) config.gamesettings[option[1]] = Mod1(config.gamesettings[option[1]]-1, #option[4])
else else
playSE("cursor") local sld = self[self.options[self.highlight][4]]
sld = self[self.options[self.highlight][4]]
sld.value = math.max(sld.min, math.min(sld.max, (sld:getValue() - 5) / (sld.max - sld.min))) sld.value = math.max(sld.min, math.min(sld.max, (sld:getValue() - 5) / (sld.max - sld.min)))
sld:update()
playSE("cursor")
end end
elseif e.input == "right" or e.scancode == "right" then elseif e.input == "right" or e.scancode == "right" then
if not self.options[self.highlight][3] then if not self.options[self.highlight][3] then
@@ -110,9 +111,10 @@ function ConfigScene:onInputPress(e)
local option = ConfigScene.options[self.highlight] local option = ConfigScene.options[self.highlight]
config.gamesettings[option[1]] = Mod1(config.gamesettings[option[1]]+1, #option[4]) config.gamesettings[option[1]] = Mod1(config.gamesettings[option[1]]+1, #option[4])
else else
playSE("cursor")
sld = self[self.options[self.highlight][4]] sld = self[self.options[self.highlight][4]]
sld.value = math.max(sld.min, math.min(sld.max, (sld:getValue() + 5) / (sld.max - sld.min)))--math.max(0, (math.floor(sld:getValue())+2)/(sld.max-sld.min)) sld.value = math.max(sld.min, math.min(sld.max, (sld:getValue() + 5) / (sld.max - sld.min)))
sld:update()
playSE("cursor")
end end
elseif e.input == "menu_back" or e.scancode == "delete" or e.scancode == "backspace" then elseif e.input == "menu_back" or e.scancode == "delete" or e.scancode == "backspace" then
loadSave() loadSave()

View File

@@ -6,6 +6,22 @@ current_mode = 1
current_ruleset = 1 current_ruleset = 1
function ModeSelectScene:new() function ModeSelectScene:new()
-- reload custom modules
initModules()
if table.getn(game_modes) == 0 or table.getn(rulesets) == 0 then
self.display_warning = true
current_mode = 1
current_ruleset = 1
else
self.display_warning = false
if current_mode > table.getn(game_modes) then
current_mode = 1
end
if current_ruleset > table.getn(rulesets) then
current_ruleset = 1
end
end
self.menu_state = { self.menu_state = {
mode = current_mode, mode = current_mode,
ruleset = current_ruleset, ruleset = current_ruleset,
@@ -19,6 +35,7 @@ function ModeSelectScene:new()
rotate_180 = false, rotate_180 = false,
hold = false, hold = false,
} }
self.das = 0
DiscordRPC:update({ DiscordRPC:update({
details = "In menus", details = "In menus",
state = "Choosing a mode", state = "Choosing a mode",
@@ -27,6 +44,17 @@ end
function ModeSelectScene:update() function ModeSelectScene:update()
switchBGM(nil) -- experimental switchBGM(nil) -- experimental
if self.das_up or self.das_down then
self.das = self.das + 1
else
self.das = 0
end
if self.das >= 15 then
self:changeOption(self.das_up and -1 or 1)
self.das = self.das - 4
end
end end
function ModeSelectScene:render() function ModeSelectScene:render()
@@ -36,6 +64,23 @@ function ModeSelectScene:render()
0.5, 0.5 0.5, 0.5
) )
love.graphics.draw(misc_graphics["select_mode"], 20, 40)
if self.display_warning then
love.graphics.setFont(font_3x5_3)
love.graphics.printf(
"You have no modes or rulesets.",
80, 200, 480, "center"
)
love.graphics.setFont(font_3x5_2)
love.graphics.printf(
"Come back to this menu after getting more modes or rulesets. " ..
"Press any button to return to the main menu.",
80, 250, 480, "center"
)
return
end
if self.menu_state.select == "mode" then if self.menu_state.select == "mode" then
love.graphics.setColor(1, 1, 1, 0.5) love.graphics.setColor(1, 1, 1, 0.5)
elseif self.menu_state.select == "ruleset" then elseif self.menu_state.select == "ruleset" then
@@ -52,8 +97,6 @@ function ModeSelectScene:render()
love.graphics.setColor(1, 1, 1, 1) love.graphics.setColor(1, 1, 1, 1)
love.graphics.draw(misc_graphics["select_mode"], 20, 40)
love.graphics.setFont(font_3x5_2) love.graphics.setFont(font_3x5_2)
for idx, mode in pairs(game_modes) do for idx, mode in pairs(game_modes) do
if(idx >= self.menu_state.mode-9 and idx <= self.menu_state.mode+9) then if(idx >= self.menu_state.mode-9 and idx <= self.menu_state.mode+9) then
@@ -68,23 +111,37 @@ function ModeSelectScene:render()
end end
function ModeSelectScene:onInputPress(e) function ModeSelectScene:onInputPress(e)
if e.input == "menu_decide" or e.scancode == "return" then if self.display_warning and e.input then
scene = TitleScene()
elseif e.type == "wheel" then
if e.x % 2 == 1 then
self:switchSelect()
end
if e.y ~= 0 then
self:changeOption(-e.y)
end
elseif e.input == "menu_decide" or e.scancode == "return" then
current_mode = self.menu_state.mode current_mode = self.menu_state.mode
current_ruleset = self.menu_state.ruleset current_ruleset = self.menu_state.ruleset
config.current_mode = current_mode config.current_mode = current_mode
config.current_ruleset = current_ruleset config.current_ruleset = current_ruleset
playSE("mode_decide") playSE("mode_decide")
saveConfig() saveConfig()
scene = GameScene(game_modes[self.menu_state.mode], rulesets[self.menu_state.ruleset], self.secret_inputs) scene = GameScene(
game_modes[self.menu_state.mode],
rulesets[self.menu_state.ruleset],
self.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)
playSE("cursor") self.das_up = true
self.das_down = nil
elseif e.input == "down" or e.scancode == "down" then elseif e.input == "down" or e.scancode == "down" then
self:changeOption(1) self:changeOption(1)
playSE("cursor") self.das_down = true
self.das_up = nil
elseif e.input == "left" or e.input == "right" or e.scancode == "left" or e.scancode == "right" then elseif e.input == "left" or e.input == "right" or e.scancode == "left" or e.scancode == "right" then
self:switchSelect() self:switchSelect()
playSE("cursor_lr")
elseif e.input == "menu_back" or e.scancode == "delete" or e.scancode == "backspace" then elseif e.input == "menu_back" or e.scancode == "delete" or e.scancode == "backspace" then
scene = TitleScene() scene = TitleScene()
elseif e.input then elseif e.input then
@@ -95,6 +152,10 @@ end
function ModeSelectScene:onInputRelease(e) function ModeSelectScene:onInputRelease(e)
if e.input == "hold" or (e.input and string.sub(e.input, 1, 7) == "rotate_") then if e.input == "hold" or (e.input and string.sub(e.input, 1, 7) == "rotate_") then
self.secret_inputs[e.input] = false self.secret_inputs[e.input] = false
elseif e.input == "up" or e.scancode == "up" then
self.das_up = nil
elseif e.input == "down" or e.scancode == "down" then
self.das_down = nil
end end
end end
@@ -104,24 +165,26 @@ function ModeSelectScene:changeOption(rel)
elseif self.menu_state.select == "ruleset" then elseif self.menu_state.select == "ruleset" then
self:changeRuleset(rel) self:changeRuleset(rel)
end end
playSE("cursor")
end end
function ModeSelectScene:switchSelect(rel) function ModeSelectScene:switchSelect()
if self.menu_state.select == "mode" then if self.menu_state.select == "mode" then
self.menu_state.select = "ruleset" self.menu_state.select = "ruleset"
elseif self.menu_state.select == "ruleset" then elseif self.menu_state.select == "ruleset" then
self.menu_state.select = "mode" self.menu_state.select = "mode"
end end
playSE("cursor_lr")
end end
function ModeSelectScene:changeMode(rel) function ModeSelectScene:changeMode(rel)
local len = table.getn(game_modes) local len = table.getn(game_modes)
self.menu_state.mode = (self.menu_state.mode + len + rel - 1) % len + 1 self.menu_state.mode = Mod1(self.menu_state.mode + rel, len)
end end
function ModeSelectScene:changeRuleset(rel) function ModeSelectScene:changeRuleset(rel)
local len = table.getn(rulesets) local len = table.getn(rulesets)
self.menu_state.ruleset = (self.menu_state.ruleset + len + rel - 1) % len + 1 self.menu_state.ruleset = Mod1(self.menu_state.ruleset + rel, len)
end end
return ModeSelectScene return ModeSelectScene

View File

@@ -349,7 +349,7 @@ function Grid:markSquares()
elseif i == 2 then elseif i == 2 then
for j = 0, 3 do for j = 0, 3 do
for k = 0, 3 do for k = 0, 3 do
self.grid[y+j][x+k].colour = "F" self.grid[y+j][x+k].colour = "W"
self.grid[y+j][x+k].skin = "square" self.grid[y+j][x+k].skin = "square"
end end

View File

@@ -126,9 +126,6 @@ function GameMode:update(inputs, ruleset)
if inputs["left"] or inputs["right"] then if inputs["left"] or inputs["right"] then
inputs["up"] = false inputs["up"] = false
inputs["down"] = false inputs["down"] = false
elseif inputs["up"] or inputs["down"] then
inputs["left"] = false
inputs["right"] = false
end end
end end
@@ -490,20 +487,15 @@ end
function GameMode:initializeOrHold(inputs, ruleset) function GameMode:initializeOrHold(inputs, ruleset)
if ( if (
(self.frames == 0 or (ruleset.are and self:getARE() ~= 0)) and self.ihs or false (self.frames == 0 or (ruleset.are and self:getARE() ~= 0))
and self.ihs or false
) and self.enable_hold and inputs["hold"] == true then ) and self.enable_hold and inputs["hold"] == true then
self:hold(inputs, ruleset, true) self:hold(inputs, ruleset, true)
else else
self:initializeNextPiece(inputs, ruleset, self.next_queue[1]) self:initializeNextPiece(inputs, ruleset, self.next_queue[1])
end end
self:onPieceEnter() self:onPieceEnter()
if not self.grid:canPlacePiece(self.piece) then self:onEnterOrHold(inputs, ruleset)
self.game_over = true
end
ruleset:dropPiece(
inputs, self.piece, self.grid, self:getGravity(),
self:getDropSpeed(), self.drop_locked, self.hard_drop_locked
)
end end
function GameMode:hold(inputs, ruleset, ihs) function GameMode:hold(inputs, ruleset, ihs)
@@ -516,7 +508,7 @@ function GameMode:hold(inputs, ruleset, ihs)
self.hold_queue = { self.hold_queue = {
skin = self.piece.skin, skin = self.piece.skin,
shape = self.piece.shape, shape = self.piece.shape,
orientation = ruleset:getDefaultOrientation(), orientation = ruleset:getDefaultOrientation(self.piece.shape),
} }
end end
if data == nil then if data == nil then
@@ -525,21 +517,35 @@ function GameMode:hold(inputs, ruleset, ihs)
self:initializeNextPiece(inputs, ruleset, data, false) self:initializeNextPiece(inputs, ruleset, data, false)
end end
self.held = true self.held = true
if ihs then playSE("ihs")
else playSE("hold") end
self:onHold() self:onHold()
if not self.grid:canPlacePiece(self.piece) then if ihs then
self.game_over = true playSE("ihs")
else
playSE("hold")
self:onEnterOrHold(inputs, ruleset)
end end
end end
function GameMode:initializeNextPiece(inputs, ruleset, piece_data, generate_next_piece) function GameMode:onEnterOrHold(inputs, ruleset)
if not self.buffer_soft_drop and self.lock_drop or ( if not self.grid:canPlacePiece(self.piece) then
self.game_over = true
return
end
ruleset:dropPiece(
inputs, self.piece, self.grid, self:getGravity(),
self:getDropSpeed(), self.drop_locked, self.hard_drop_locked
)
end
function GameMode:initializeNextPiece(
inputs, ruleset, piece_data, generate_next_piece
)
if not inputs.hold and not self.buffer_soft_drop and self.lock_drop or (
not ruleset.are or self:getARE() == 0 not ruleset.are or self:getARE() == 0
) then ) then
self.drop_locked = true self.drop_locked = true
end end
if not self.buffer_hard_drop and self.lock_hard_drop or ( if not inputs.hold and not self.buffer_hard_drop and self.lock_hard_drop or (
not ruleset.are or self:getARE() == 0 not ruleset.are or self:getARE() == 0
) then ) then
self.hard_drop_locked = true self.hard_drop_locked = true
@@ -683,7 +689,9 @@ function GameMode:drawPiece()
end end
function GameMode:drawGhostPiece(ruleset) function GameMode:drawGhostPiece(ruleset)
if self.piece == nil then return end if self.piece == nil or not self.grid:canPlacePiece(self.piece) then
return
end
local ghost_piece = self.piece:withOffset({x=0, y=0}) local ghost_piece = self.piece:withOffset({x=0, y=0})
ghost_piece.ghost = true ghost_piece.ghost = true
ghost_piece:dropToBottom(self.grid) ghost_piece:dropToBottom(self.grid)
@@ -853,15 +861,7 @@ function GameMode:drawFrame()
-- game frame -- game frame
if self.grid.width == 10 and self.grid.height == 24 then if self.grid.width == 10 and self.grid.height == 24 then
love.graphics.draw(misc_graphics["frame"], 48, 64) love.graphics.draw(misc_graphics["frame"], 48, 64)
end else
love.graphics.setColor(0, 0, 0, 200)
love.graphics.rectangle(
"fill", 64, 80,
16 * self.grid.width, 16 * (self.grid.height - 4)
)
if self.grid.width ~= 10 or self.grid.height ~= 24 then
love.graphics.setColor(174/255, 83/255, 76/255, 1) love.graphics.setColor(174/255, 83/255, 76/255, 1)
love.graphics.setLineWidth(8) love.graphics.setLineWidth(8)
love.graphics.line( love.graphics.line(
@@ -881,6 +881,11 @@ function GameMode:drawFrame()
60,76 60,76
) )
love.graphics.setLineWidth(1) love.graphics.setLineWidth(1)
love.graphics.setColor(0, 0, 0, 200)
love.graphics.rectangle(
"fill", 64, 80,
16 * self.grid.width, 16 * (self.grid.height - 4)
)
end end
end end
@@ -897,7 +902,20 @@ end
function GameMode:drawCustom() end function GameMode:drawCustom() end
function GameMode:drawIfPaused()
love.graphics.setFont(font_3x5_3)
love.graphics.printf("GAME PAUSED!", 64, 160, 160, "center")
end
-- transforms specified in here will transform the whole screen
-- if you want a transform for a particular component, push the
-- default transform by using love.graphics.push(), do your
-- transform, and then love.graphics.pop() at the end of that
-- component's draw call!
function GameMode:transformScreen() end
function GameMode:draw(paused) function GameMode:draw(paused)
self:transformScreen()
self:drawBackground() self:drawBackground()
self:drawFrame() self:drawFrame()
self:drawGrid() self:drawGrid()
@@ -919,9 +937,8 @@ function GameMode:draw(paused)
) )
end end
love.graphics.setFont(font_3x5_3)
if paused then if paused then
love.graphics.printf("GAME PAUSED!", 64, 160, 160, "center") self:drawIfPaused()
end end
if self.completed then if self.completed then

View File

@@ -290,10 +290,10 @@ function Marathon2020Game:sectionPassed(old_level, new_level)
end end
function Marathon2020Game:checkTorikan(section) function Marathon2020Game:checkTorikan(section)
if section == 5 and self.frames < frameTime(6,00,00) then self.torikan_passed[500] = true end if section == 5 and self.frames < frameTime(8,00,00) then self.torikan_passed[500] = true end
if section == 9 and self.frames < frameTime(8,30,00) then self.torikan_passed[900] = true end if section == 9 and self.frames < frameTime(10,30,00) then self.torikan_passed[900] = true end
if section == 10 and self.frames < frameTime(8,45,00) then self.torikan_passed[1000] = true end if section == 10 and self.frames < frameTime(10,45,00) then self.torikan_passed[1000] = true end
if section == 15 and self.frames < frameTime(11,30,00) then self.torikan_passed[1500] = true end if section == 15 and self.frames < frameTime(12,30,00) then self.torikan_passed[1500] = true end
if section == 19 and self.frames < frameTime(13,15,00) then self.torikan_passed[1900] = true end if section == 19 and self.frames < frameTime(13,15,00) then self.torikan_passed[1900] = true end
end end
@@ -354,7 +354,7 @@ function Marathon2020Game:updateSectionTimes(old_level, new_level)
if ( if (
self.section_status[section - 1] == "cool" and self.section_status[section - 1] == "cool" and
self.secondary_section_times[section] < self.secondary_section_times[section - 1] + 120 and self.secondary_section_times[section] <= self.secondary_section_times[section - 1] + 120 and
self.secondary_section_times[section] < cool_cutoffs[self.delay_level] self.secondary_section_times[section] < cool_cutoffs[self.delay_level]
) then ) then
sectionCool(section) sectionCool(section)
@@ -407,11 +407,12 @@ GM-roll requirements
You qualify for the GM roll if you: You qualify for the GM roll if you:
- Reach level 2020 - Reach level 2020
- with a grade of 50 - with a grade of 50
- and at least 25,000 grade points
- in less than 13:30.00 total. - in less than 13:30.00 total.
]]-- ]]--
return self.level >= 2020 and self:getTotalGrade() == 50 and self.frames <= frameTime(13,30) return self.level >= 2020 and self:getTotalGrade() == 50 and self.grade_points >= 25000 and self.frames <= frameTime(13,30)
end end
function Marathon2020Game:drawGrid() function Marathon2020Game:drawGrid()

View File

@@ -218,16 +218,11 @@ function MarathonA3Game:updateSectionTimes(old_level, new_level)
section_70_time = self.frames - self.section_start_time section_70_time = self.frames - self.section_start_time
table.insert(self.secondary_section_times, section_70_time) table.insert(self.secondary_section_times, section_70_time)
if section <= 9 and self.section_status[section - 1] == "cool" and if section <= 9 and self.secondary_section_times[section] < cool_cutoffs[section] and
self.secondary_section_times[section] < self.secondary_section_times[section - 1] + 120 then (section == 1 or self.secondary_section_times[section] <= self.secondary_section_times[section - 1] + 120) then
self.section_cool = true self.section_cool = true
self.coolregret_message = "COOL!!" self.coolregret_message = "COOL!!"
self.coolregret_timer = 300 self.coolregret_timer = 300
elseif self.section_status[section - 1] == "cool" then self.section_cool = false
elseif section <= 9 and self.secondary_section_times[section] < cool_cutoffs[section] then
self.section_cool = true
self.coolregret_message = "COOL!!"
self.coolregret_timer = 300
end end
end end
end end

View File

@@ -41,7 +41,7 @@ function PhantomManiaGame:getARE()
end end
function PhantomManiaGame:getLineARE() function PhantomManiaGame:getLineARE()
if self.level < 100 then return 18 if self.level < 100 then return 14
elseif self.level < 400 then return 8 elseif self.level < 400 then return 8
elseif self.level < 500 then return 7 elseif self.level < 500 then return 7
else return 6 end else return 6 end

View File

@@ -179,7 +179,7 @@ function PhantomMania2Game:onPieceLock(piece, cleared_row_count)
end end
function PhantomMania2Game:onHold() function PhantomMania2Game:onHold()
self.super.onHold() self.super:onHold()
self.hold_age = 0 self.hold_age = 0
end end
@@ -287,7 +287,8 @@ function PhantomMania2Game:setHoldOpacity()
if self.level > 1000 and self.level < 1300 then if self.level > 1000 and self.level < 1300 then
love.graphics.setColor(1, 1, 1, 1 - math.min(1, self.hold_age / 15)) love.graphics.setColor(1, 1, 1, 1 - math.min(1, self.hold_age / 15))
else else
self.super:setHoldOpacity(1, self.held and 0.6 or 1) local colour = self.held and 0.6 or 1
love.graphics.setColor(colour, colour, colour, 1)
end end
end end

View File

@@ -97,14 +97,13 @@ end
function SurvivalA2Game:onLineClear(cleared_row_count) function SurvivalA2Game:onLineClear(cleared_row_count)
if not self.clear then if not self.clear then
local new_level = math.min(self.level + cleared_row_count, 999) local new_level = math.min(self.level + cleared_row_count, 999)
if self.level == 999 or self:hitTorikan(self.level, new_level) then if new_level == 999 or self:hitTorikan(self.level, new_level) then
self.clear = true self.clear = true
if self.level < 999 then if new_level < 999 then
self.game_over = true self.game_over = true
end end
else
self.level = new_level
end end
self.level = new_level
end end
end end
@@ -158,7 +157,7 @@ function SurvivalA2Game:drawScoringInfo()
love.graphics.setFont(font_3x5_3) love.graphics.setFont(font_3x5_3)
love.graphics.printf(self.score, text_x, 220, 90, "left") love.graphics.printf(self.score, text_x, 220, 90, "left")
if self.roll_frames > 2968 then love.graphics.setColor(1, 0.5, 0, 1) if self.roll_frames > 1800 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:getLetterGrade() ~= "" then love.graphics.printf(self:getLetterGrade(), text_x, 140, 90, "left") end if self:getLetterGrade() ~= "" then love.graphics.printf(self:getLetterGrade(), text_x, 140, 90, "left") end
love.graphics.setColor(1, 1, 1, 1) love.graphics.setColor(1, 1, 1, 1)

View File

@@ -47,18 +47,11 @@ function Ruleset:new(game_mode)
else else
bones = config.gamesettings.piece_colour == 3 and "w" or "" bones = config.gamesettings.piece_colour == 3 and "w" or ""
end end
blocks.bone = { for colour in pairs(blocks["2tie"]) do
R = love.graphics.newImage("res/img/bone" .. bones .. ".png"), blocks.bone[colour] = love.graphics.newImage(
O = love.graphics.newImage("res/img/bone" .. bones .. ".png"), "res/img/bone" .. bones .. ".png"
Y = love.graphics.newImage("res/img/bone" .. bones .. ".png"), )
G = love.graphics.newImage("res/img/bone" .. bones .. ".png"), end
C = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
B = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
M = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
F = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
A = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
X = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
}
end end
function Ruleset:rotatePiece(inputs, piece, grid, prev_inputs, initial) function Ruleset:rotatePiece(inputs, piece, grid, prev_inputs, initial)
@@ -162,18 +155,18 @@ function Ruleset:dropPiece(
hard_drop_enabled, additive_gravity, classic_lock hard_drop_enabled, additive_gravity, classic_lock
) )
local y = piece.position.y local y = piece.position.y
if inputs["down"] == true and drop_locked == false then if inputs["up"] == true and hard_drop_enabled == true then
if additive_gravity then
piece:addGravity(gravity + drop_speed, grid, classic_lock)
else
piece:addGravity(math.max(gravity, drop_speed), grid, classic_lock)
end
elseif inputs["up"] == true and hard_drop_enabled == true then
if hard_drop_locked == true or piece:isDropBlocked(grid) then if hard_drop_locked == true or piece:isDropBlocked(grid) then
piece:addGravity(gravity, grid, classic_lock) piece:addGravity(gravity, grid, classic_lock)
else else
piece:dropToBottom(grid) piece:dropToBottom(grid)
end end
elseif inputs["down"] == true and drop_locked == false then
if additive_gravity then
piece:addGravity(gravity + drop_speed, grid, classic_lock)
else
piece:addGravity(math.max(gravity, drop_speed), grid, classic_lock)
end
else else
piece:addGravity(gravity, grid, classic_lock) piece:addGravity(gravity, grid, classic_lock)
end end
@@ -221,7 +214,7 @@ function Ruleset:initializePiece(
colours = self.colourscheme colours = self.colourscheme
end end
local spawn_x = math.floor(spawn_positions[data.shape].x / 10 * grid.width) local spawn_x = math.floor(spawn_positions[data.shape].x * grid.width / 10)
local spawn_dy local spawn_dy
if (config.gamesettings.spawn_positions == 1) then if (config.gamesettings.spawn_positions == 1) then
@@ -237,7 +230,7 @@ function Ruleset:initializePiece(
end end
local piece = Piece(data.shape, data.orientation - 1, { local piece = Piece(data.shape, data.orientation - 1, {
x = spawn_x or spawn_positions[data.shape].x, x = spawn_x,
y = spawn_positions[data.shape].y - spawn_dy y = spawn_positions[data.shape].y - spawn_dy
}, self.block_offsets, 0, 0, data.skin, colours[data.shape], big) }, self.block_offsets, 0, 0, data.skin, colours[data.shape], big)