mirror of
https://github.com/SashLilac/cambridge.git
synced 2025-05-13 20:21:25 -05:00
Compare commits
56 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
e6a60b0021 | ||
|
|
5f29c987f2 | ||
|
|
608d75b1ac | ||
|
|
1427c0d19e | ||
|
|
e221a91d73 | ||
|
|
bdcd25b82c | ||
|
|
a5158e0994 | ||
|
|
d946b17e13 | ||
|
|
69a5c0a21a | ||
|
|
b6423c3335 | ||
|
|
5b960d7291 | ||
|
|
54f4b0b890 | ||
|
|
8c62f321a0 | ||
|
|
fdffd2cd9a | ||
|
|
8ddf468121 | ||
|
|
8e77407ff2 | ||
|
|
92c852d178 | ||
|
|
f658ed63f2 | ||
|
|
c2d1c1183c | ||
|
|
36c568feaf | ||
|
|
bf30fcefbd | ||
|
|
d9f5bd16d7 | ||
|
|
d978ff8d87 | ||
|
|
b47d0f36b9 | ||
|
|
abc210c69c | ||
|
|
436e4ac861 | ||
|
|
a48d7c67b5 | ||
|
|
f6ca79ff91 | ||
|
|
4eb3901610 | ||
|
|
3f7fc4b622 | ||
|
|
ac7ae91c39 | ||
|
|
0c8e910245 | ||
|
|
6233ffb12d | ||
|
|
1f78bb9e99 | ||
|
|
a125c09106 | ||
|
|
090ffa5126 | ||
|
|
12a6f42198 | ||
|
|
0c317d9ce1 | ||
|
|
eddfee566d | ||
|
|
7fe366a8de | ||
|
|
55be30c99f | ||
|
|
36ceef8488 | ||
|
|
b59edb5e8e | ||
|
|
5d32b6a3e7 | ||
|
|
05230ac046 | ||
|
|
f28dc08ae2 | ||
|
|
ecd958bdc5 | ||
|
|
43f59cfde8 | ||
|
|
00c46961f9 | ||
|
|
0a0053276b | ||
|
|
d0f1d869a8 | ||
|
|
29ee000998 | ||
|
|
995fd7fee9 | ||
|
|
67abf35a28 | ||
|
|
9982613e26 | ||
|
|
629beb7240 |
10
README.md
10
README.md
@@ -1,3 +1,5 @@
|
|||||||
|

|
||||||
|
|
||||||
Cambridge
|
Cambridge
|
||||||
=========
|
=========
|
||||||
|
|
||||||
@@ -5,12 +7,20 @@ Welcome to Cambridge, the next open-source falling-block game engine!
|
|||||||
|
|
||||||
This fork is written and maintained exclusively by [SashLilac](https://github.com/SashLilac) and [Oshisaure](https://github.com/oshisaure)!
|
This fork is written and maintained exclusively by [SashLilac](https://github.com/SashLilac) and [Oshisaure](https://github.com/oshisaure)!
|
||||||
|
|
||||||
|
Join our Discord server for help and a welcoming community! https://discord.gg/mteMJw4
|
||||||
|
|
||||||
Credits
|
Credits
|
||||||
-------
|
-------
|
||||||
|
|
||||||
- [Lilla Oshisaure](https://www.youtube.com/user/LeSpyroshisaure) for their amazing contributions to my life in general!
|
- [Lilla Oshisaure](https://www.youtube.com/user/LeSpyroshisaure) for their amazing contributions to my life in general!
|
||||||
- [The Tetra Legends Discord](http://discord.com/invite/7hMx5r2) for supporting me and playtesting!
|
- [The Tetra Legends Discord](http://discord.com/invite/7hMx5r2) for supporting me and playtesting!
|
||||||
- [joezeng](https://github.com/joezeng) for the original project.
|
- [joezeng](https://github.com/joezeng) for the original project.
|
||||||
|
- [Hailey](https://github.com/haileylgbt) for some miscellaneous assets.
|
||||||
|
- MarkGamed7794 for some miscellaneous contributions.
|
||||||
|
- Mizu for the Cambridge logo and the [Cambridge launcher](https://github.com/rexxt/cambridge-launcher).
|
||||||
|
- MattMayuga for the Cambridge banner.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
Installation instructions
|
Installation instructions
|
||||||
-------------------------
|
-------------------------
|
||||||
|
|||||||
@@ -61,4 +61,9 @@ function formatBigNum(number)
|
|||||||
if pos == 0 then pos = 3 end
|
if pos == 0 then pos = 3 end
|
||||||
return string.sub(s, 1, pos)
|
return string.sub(s, 1, pos)
|
||||||
.. string.gsub(string.sub(s, pos+1), "(...)", ",%1")
|
.. string.gsub(string.sub(s, pos+1), "(...)", ",%1")
|
||||||
|
end
|
||||||
|
|
||||||
|
function Mod1(n, m)
|
||||||
|
-- returns a number congruent to n modulo m in the range [1;m] (as opposed to [0;m-1])
|
||||||
|
return ((n-1) % m) + 1
|
||||||
end
|
end
|
||||||
BIN
libs/discord-rpc.dll
Normal file
BIN
libs/discord-rpc.dll
Normal file
Binary file not shown.
BIN
libs/discord-rpc.dylib
Normal file
BIN
libs/discord-rpc.dylib
Normal file
Binary file not shown.
BIN
libs/discord-rpc.so
Normal file
BIN
libs/discord-rpc.so
Normal file
Binary file not shown.
268
libs/discordRPC.lua
Normal file
268
libs/discordRPC.lua
Normal file
@@ -0,0 +1,268 @@
|
|||||||
|
local ffi = require "ffi"
|
||||||
|
|
||||||
|
|
||||||
|
-- Get the host os to load correct lib
|
||||||
|
local osname = love.system.getOS()
|
||||||
|
local discordRPClib = nil
|
||||||
|
|
||||||
|
if osname == "Linux" then
|
||||||
|
discordRPClib = ffi.load(love.filesystem.getSource().."/libs/discord-rpc.so")
|
||||||
|
elseif osname == "OS X" then
|
||||||
|
discordRPClib = ffi.load(love.filesystem.getSource().."/libs/discord-rpc.dylib")
|
||||||
|
elseif osname == "Windows" then
|
||||||
|
discordRPClib = ffi.load(love.filesystem.getSource().."/libs/discord-rpc.dll")
|
||||||
|
else
|
||||||
|
-- Else it crashes later on
|
||||||
|
error(string.format("Discord rpc not supported on platform (%s)", osname))
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
ffi.cdef[[
|
||||||
|
typedef struct DiscordRichPresence {
|
||||||
|
const char* state; /* max 128 bytes */
|
||||||
|
const char* details; /* max 128 bytes */
|
||||||
|
int64_t startTimestamp;
|
||||||
|
int64_t endTimestamp;
|
||||||
|
const char* largeImageKey; /* max 32 bytes */
|
||||||
|
const char* largeImageText; /* max 128 bytes */
|
||||||
|
const char* smallImageKey; /* max 32 bytes */
|
||||||
|
const char* smallImageText; /* max 128 bytes */
|
||||||
|
const char* partyId; /* max 128 bytes */
|
||||||
|
int partySize;
|
||||||
|
int partyMax;
|
||||||
|
const char* matchSecret; /* max 128 bytes */
|
||||||
|
const char* joinSecret; /* max 128 bytes */
|
||||||
|
const char* spectateSecret; /* max 128 bytes */
|
||||||
|
int8_t instance;
|
||||||
|
} DiscordRichPresence;
|
||||||
|
|
||||||
|
typedef struct DiscordUser {
|
||||||
|
const char* userId;
|
||||||
|
const char* username;
|
||||||
|
const char* discriminator;
|
||||||
|
const char* avatar;
|
||||||
|
} DiscordUser;
|
||||||
|
|
||||||
|
typedef void (*readyPtr)(const DiscordUser* request);
|
||||||
|
typedef void (*disconnectedPtr)(int errorCode, const char* message);
|
||||||
|
typedef void (*erroredPtr)(int errorCode, const char* message);
|
||||||
|
typedef void (*joinGamePtr)(const char* joinSecret);
|
||||||
|
typedef void (*spectateGamePtr)(const char* spectateSecret);
|
||||||
|
typedef void (*joinRequestPtr)(const DiscordUser* request);
|
||||||
|
|
||||||
|
typedef struct DiscordEventHandlers {
|
||||||
|
readyPtr ready;
|
||||||
|
disconnectedPtr disconnected;
|
||||||
|
erroredPtr errored;
|
||||||
|
joinGamePtr joinGame;
|
||||||
|
spectateGamePtr spectateGame;
|
||||||
|
joinRequestPtr joinRequest;
|
||||||
|
} DiscordEventHandlers;
|
||||||
|
|
||||||
|
void Discord_Initialize(const char* applicationId,
|
||||||
|
DiscordEventHandlers* handlers,
|
||||||
|
int autoRegister,
|
||||||
|
const char* optionalSteamId);
|
||||||
|
|
||||||
|
void Discord_Shutdown(void);
|
||||||
|
|
||||||
|
void Discord_RunCallbacks(void);
|
||||||
|
|
||||||
|
void Discord_UpdatePresence(const DiscordRichPresence* presence);
|
||||||
|
|
||||||
|
void Discord_ClearPresence(void);
|
||||||
|
|
||||||
|
void Discord_Respond(const char* userid, int reply);
|
||||||
|
|
||||||
|
void Discord_UpdateHandlers(DiscordEventHandlers* handlers);
|
||||||
|
]]
|
||||||
|
|
||||||
|
local discordRPC = {} -- module table
|
||||||
|
|
||||||
|
-- proxy to detect garbage collection of the module
|
||||||
|
discordRPC.gcDummy = newproxy(true)
|
||||||
|
|
||||||
|
local function unpackDiscordUser(request)
|
||||||
|
return ffi.string(request.userId), ffi.string(request.username),
|
||||||
|
ffi.string(request.discriminator), ffi.string(request.avatar)
|
||||||
|
end
|
||||||
|
|
||||||
|
-- callback proxies
|
||||||
|
-- note: callbacks are not JIT compiled (= SLOW), try to avoid doing performance critical tasks in them
|
||||||
|
-- luajit.org/ext_ffi_semantics.html
|
||||||
|
local ready_proxy = ffi.cast("readyPtr", function(request)
|
||||||
|
if discordRPC.ready then
|
||||||
|
discordRPC.ready(unpackDiscordUser(request))
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
local disconnected_proxy = ffi.cast("disconnectedPtr", function(errorCode, message)
|
||||||
|
if discordRPC.disconnected then
|
||||||
|
discordRPC.disconnected(errorCode, ffi.string(message))
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
local errored_proxy = ffi.cast("erroredPtr", function(errorCode, message)
|
||||||
|
if discordRPC.errored then
|
||||||
|
discordRPC.errored(errorCode, ffi.string(message))
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
local joinGame_proxy = ffi.cast("joinGamePtr", function(joinSecret)
|
||||||
|
if discordRPC.joinGame then
|
||||||
|
discordRPC.joinGame(ffi.string(joinSecret))
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
local spectateGame_proxy = ffi.cast("spectateGamePtr", function(spectateSecret)
|
||||||
|
if discordRPC.spectateGame then
|
||||||
|
discordRPC.spectateGame(ffi.string(spectateSecret))
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
local joinRequest_proxy = ffi.cast("joinRequestPtr", function(request)
|
||||||
|
if discordRPC.joinRequest then
|
||||||
|
discordRPC.joinRequest(unpackDiscordUser(request))
|
||||||
|
end
|
||||||
|
end)
|
||||||
|
|
||||||
|
-- helpers
|
||||||
|
local function checkArg(arg, argType, argName, func, maybeNil)
|
||||||
|
assert(type(arg) == argType or (maybeNil and arg == nil),
|
||||||
|
string.format("Argument \"%s\" to function \"%s\" has to be of type \"%s\"",
|
||||||
|
argName, func, argType))
|
||||||
|
end
|
||||||
|
|
||||||
|
local function checkStrArg(arg, maxLen, argName, func, maybeNil)
|
||||||
|
if maxLen then
|
||||||
|
assert(type(arg) == "string" and arg:len() <= maxLen or (maybeNil and arg == nil),
|
||||||
|
string.format("Argument \"%s\" of function \"%s\" has to be of type string with maximum length %d",
|
||||||
|
argName, func, maxLen))
|
||||||
|
else
|
||||||
|
checkArg(arg, "string", argName, func, true)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local function checkIntArg(arg, maxBits, argName, func, maybeNil)
|
||||||
|
maxBits = math.min(maxBits or 32, 52) -- lua number (double) can only store integers < 2^53
|
||||||
|
local maxVal = 2^(maxBits-1) -- assuming signed integers, which, for now, are the only ones in use
|
||||||
|
assert(type(arg) == "number" and math.floor(arg) == arg
|
||||||
|
and arg < maxVal and arg >= -maxVal
|
||||||
|
or (maybeNil and arg == nil),
|
||||||
|
string.format("Argument \"%s\" of function \"%s\" has to be a whole number <= %d",
|
||||||
|
argName, func, maxVal))
|
||||||
|
end
|
||||||
|
|
||||||
|
-- function wrappers
|
||||||
|
function discordRPC.initialize(applicationId, autoRegister, optionalSteamId)
|
||||||
|
local func = "discordRPC.Initialize"
|
||||||
|
checkStrArg(applicationId, nil, "applicationId", func)
|
||||||
|
checkArg(autoRegister, "boolean", "autoRegister", func)
|
||||||
|
if optionalSteamId ~= nil then
|
||||||
|
checkStrArg(optionalSteamId, nil, "optionalSteamId", func)
|
||||||
|
end
|
||||||
|
|
||||||
|
local eventHandlers = ffi.new("struct DiscordEventHandlers")
|
||||||
|
eventHandlers.ready = ready_proxy
|
||||||
|
eventHandlers.disconnected = disconnected_proxy
|
||||||
|
eventHandlers.errored = errored_proxy
|
||||||
|
eventHandlers.joinGame = joinGame_proxy
|
||||||
|
eventHandlers.spectateGame = spectateGame_proxy
|
||||||
|
eventHandlers.joinRequest = joinRequest_proxy
|
||||||
|
|
||||||
|
discordRPClib.Discord_Initialize(applicationId, eventHandlers,
|
||||||
|
autoRegister and 1 or 0, optionalSteamId)
|
||||||
|
end
|
||||||
|
|
||||||
|
function discordRPC.shutdown()
|
||||||
|
discordRPClib.Discord_Shutdown()
|
||||||
|
end
|
||||||
|
|
||||||
|
function discordRPC.runCallbacks()
|
||||||
|
discordRPClib.Discord_RunCallbacks()
|
||||||
|
end
|
||||||
|
-- http://luajit.org/ext_ffi_semantics.html#callback :
|
||||||
|
-- It is not allowed, to let an FFI call into a C function (runCallbacks)
|
||||||
|
-- get JIT-compiled, which in turn calls a callback, calling into Lua again (e.g. discordRPC.ready).
|
||||||
|
-- Usually this attempt is caught by the interpreter first and the C function
|
||||||
|
-- is blacklisted for compilation.
|
||||||
|
-- solution:
|
||||||
|
-- "Then you'll need to manually turn off JIT-compilation with jit.off() for
|
||||||
|
-- the surrounding Lua function that invokes such a message polling function."
|
||||||
|
jit.off(discordRPC.runCallbacks)
|
||||||
|
|
||||||
|
function discordRPC.updatePresence(presence)
|
||||||
|
local func = "discordRPC.updatePresence"
|
||||||
|
checkArg(presence, "table", "presence", func)
|
||||||
|
|
||||||
|
-- -1 for string length because of 0-termination
|
||||||
|
checkStrArg(presence.state, 127, "presence.state", func, true)
|
||||||
|
checkStrArg(presence.details, 127, "presence.details", func, true)
|
||||||
|
|
||||||
|
checkIntArg(presence.startTimestamp, 64, "presence.startTimestamp", func, true)
|
||||||
|
checkIntArg(presence.endTimestamp, 64, "presence.endTimestamp", func, true)
|
||||||
|
|
||||||
|
checkStrArg(presence.largeImageKey, 31, "presence.largeImageKey", func, true)
|
||||||
|
checkStrArg(presence.largeImageText, 127, "presence.largeImageText", func, true)
|
||||||
|
checkStrArg(presence.smallImageKey, 31, "presence.smallImageKey", func, true)
|
||||||
|
checkStrArg(presence.smallImageText, 127, "presence.smallImageText", func, true)
|
||||||
|
checkStrArg(presence.partyId, 127, "presence.partyId", func, true)
|
||||||
|
|
||||||
|
checkIntArg(presence.partySize, 32, "presence.partySize", func, true)
|
||||||
|
checkIntArg(presence.partyMax, 32, "presence.partyMax", func, true)
|
||||||
|
|
||||||
|
checkStrArg(presence.matchSecret, 127, "presence.matchSecret", func, true)
|
||||||
|
checkStrArg(presence.joinSecret, 127, "presence.joinSecret", func, true)
|
||||||
|
checkStrArg(presence.spectateSecret, 127, "presence.spectateSecret", func, true)
|
||||||
|
|
||||||
|
checkIntArg(presence.instance, 8, "presence.instance", func, true)
|
||||||
|
|
||||||
|
local cpresence = ffi.new("struct DiscordRichPresence")
|
||||||
|
cpresence.state = presence.state
|
||||||
|
cpresence.details = presence.details
|
||||||
|
cpresence.startTimestamp = presence.startTimestamp or 0
|
||||||
|
cpresence.endTimestamp = presence.endTimestamp or 0
|
||||||
|
cpresence.largeImageKey = presence.largeImageKey
|
||||||
|
cpresence.largeImageText = presence.largeImageText
|
||||||
|
cpresence.smallImageKey = presence.smallImageKey
|
||||||
|
cpresence.smallImageText = presence.smallImageText
|
||||||
|
cpresence.partyId = presence.partyId
|
||||||
|
cpresence.partySize = presence.partySize or 0
|
||||||
|
cpresence.partyMax = presence.partyMax or 0
|
||||||
|
cpresence.matchSecret = presence.matchSecret
|
||||||
|
cpresence.joinSecret = presence.joinSecret
|
||||||
|
cpresence.spectateSecret = presence.spectateSecret
|
||||||
|
cpresence.instance = presence.instance or 0
|
||||||
|
|
||||||
|
discordRPClib.Discord_UpdatePresence(cpresence)
|
||||||
|
end
|
||||||
|
|
||||||
|
function discordRPC.clearPresence()
|
||||||
|
discordRPClib.Discord_ClearPresence()
|
||||||
|
end
|
||||||
|
|
||||||
|
local replyMap = {
|
||||||
|
no = 0,
|
||||||
|
yes = 1,
|
||||||
|
ignore = 2
|
||||||
|
}
|
||||||
|
|
||||||
|
-- maybe let reply take ints too (0, 1, 2) and add constants to the module
|
||||||
|
function discordRPC.respond(userId, reply)
|
||||||
|
checkStrArg(userId, nil, "userId", "discordRPC.respond")
|
||||||
|
assert(replyMap[reply], "Argument 'reply' to discordRPC.respond has to be one of \"yes\", \"no\" or \"ignore\"")
|
||||||
|
discordRPClib.Discord_Respond(userId, replyMap[reply])
|
||||||
|
end
|
||||||
|
|
||||||
|
-- garbage collection callback
|
||||||
|
getmetatable(discordRPC.gcDummy).__gc = function()
|
||||||
|
discordRPC.shutdown()
|
||||||
|
ready_proxy:free()
|
||||||
|
disconnected_proxy:free()
|
||||||
|
errored_proxy:free()
|
||||||
|
joinGame_proxy:free()
|
||||||
|
spectateGame_proxy:free()
|
||||||
|
joinRequest_proxy:free()
|
||||||
|
end
|
||||||
|
|
||||||
|
return discordRPC
|
||||||
@@ -6,7 +6,7 @@ bgm = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
local current_bgm = nil
|
local current_bgm = nil
|
||||||
local bgm_locked = false
|
local bgm_locked = true
|
||||||
|
|
||||||
function switchBGM(sound, subsound)
|
function switchBGM(sound, subsound)
|
||||||
if bgm_locked then return end
|
if bgm_locked then return end
|
||||||
|
|||||||
@@ -20,36 +20,54 @@ backgrounds = {
|
|||||||
love.graphics.newImage("res/backgrounds/1800-railways.png"),
|
love.graphics.newImage("res/backgrounds/1800-railways.png"),
|
||||||
love.graphics.newImage("res/backgrounds/1900-world-wide-web.png"),
|
love.graphics.newImage("res/backgrounds/1900-world-wide-web.png"),
|
||||||
title = love.graphics.newImage("res/backgrounds/title_v0.1.png"),
|
title = love.graphics.newImage("res/backgrounds/title_v0.1.png"),
|
||||||
input_config = love.graphics.newImage("res/backgrounds/options-gears.png")
|
input_config = love.graphics.newImage("res/backgrounds/options-pcb.png"),
|
||||||
|
game_config = love.graphics.newImage("res/backgrounds/options-gears.png"),
|
||||||
}
|
}
|
||||||
|
|
||||||
blocks = {
|
blocks = {
|
||||||
["2tie"] = {
|
["2tie"] = {
|
||||||
I = love.graphics.newImage("res/img/s1.png"),
|
R = love.graphics.newImage("res/img/s1.png"),
|
||||||
J = love.graphics.newImage("res/img/s4.png"),
|
O = love.graphics.newImage("res/img/s3.png"),
|
||||||
L = love.graphics.newImage("res/img/s3.png"),
|
Y = love.graphics.newImage("res/img/s7.png"),
|
||||||
O = love.graphics.newImage("res/img/s7.png"),
|
G = love.graphics.newImage("res/img/s6.png"),
|
||||||
S = love.graphics.newImage("res/img/s5.png"),
|
C = love.graphics.newImage("res/img/s2.png"),
|
||||||
T = love.graphics.newImage("res/img/s2.png"),
|
B = love.graphics.newImage("res/img/s4.png"),
|
||||||
Z = love.graphics.newImage("res/img/s6.png"),
|
M = love.graphics.newImage("res/img/s5.png"),
|
||||||
F = love.graphics.newImage("res/img/s9.png"),
|
|
||||||
G = love.graphics.newImage("res/img/s9.png"),
|
|
||||||
X = love.graphics.newImage("res/img/s9.png"),
|
X = love.graphics.newImage("res/img/s9.png"),
|
||||||
},
|
},
|
||||||
["bone"] = {
|
["bone"] = {
|
||||||
I = love.graphics.newImage("res/img/bone.png"),
|
R = love.graphics.newImage("res/img/bone.png"),
|
||||||
J = love.graphics.newImage("res/img/bone.png"),
|
|
||||||
L = love.graphics.newImage("res/img/bone.png"),
|
|
||||||
O = love.graphics.newImage("res/img/bone.png"),
|
O = love.graphics.newImage("res/img/bone.png"),
|
||||||
S = love.graphics.newImage("res/img/bone.png"),
|
Y = love.graphics.newImage("res/img/bone.png"),
|
||||||
T = love.graphics.newImage("res/img/bone.png"),
|
|
||||||
Z = love.graphics.newImage("res/img/bone.png"),
|
|
||||||
F = love.graphics.newImage("res/img/bone.png"),
|
|
||||||
G = love.graphics.newImage("res/img/bone.png"),
|
G = love.graphics.newImage("res/img/bone.png"),
|
||||||
|
C = love.graphics.newImage("res/img/bone.png"),
|
||||||
|
B = love.graphics.newImage("res/img/bone.png"),
|
||||||
|
M = love.graphics.newImage("res/img/bone.png"),
|
||||||
X = love.graphics.newImage("res/img/bone.png"),
|
X = love.graphics.newImage("res/img/bone.png"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ColourSchemes = {
|
||||||
|
Arika = {
|
||||||
|
I = "R",
|
||||||
|
L = "O",
|
||||||
|
J = "B",
|
||||||
|
S = "M",
|
||||||
|
Z = "G",
|
||||||
|
O = "Y",
|
||||||
|
T = "C",
|
||||||
|
},
|
||||||
|
TTC = {
|
||||||
|
I = "C",
|
||||||
|
L = "O",
|
||||||
|
J = "B",
|
||||||
|
S = "G",
|
||||||
|
Z = "R",
|
||||||
|
O = "Y",
|
||||||
|
T = "M",
|
||||||
|
},
|
||||||
|
}
|
||||||
|
|
||||||
for name, blockset in pairs(blocks) do
|
for name, blockset in pairs(blocks) do
|
||||||
for shape, image in pairs(blockset) do
|
for shape, image in pairs(blockset) do
|
||||||
image:setFilter("nearest")
|
image:setFilter("nearest")
|
||||||
|
|||||||
58
load/rpc.lua
Normal file
58
load/rpc.lua
Normal file
@@ -0,0 +1,58 @@
|
|||||||
|
print("Loading discord RPC...")
|
||||||
|
DiscordRPC = {
|
||||||
|
loaded = false
|
||||||
|
}
|
||||||
|
local success, RPC = pcall(require, "libs.discordRPC")
|
||||||
|
if success then
|
||||||
|
DiscordRPC.loaded = true
|
||||||
|
DiscordRPC.appId = "599778517789573120"
|
||||||
|
|
||||||
|
function RPC.ready(userId, username, discriminator, avatar)
|
||||||
|
print(string.format("Discord: ready (%s, %s, %s, %s)", userId, username, discriminator, avatar))
|
||||||
|
end
|
||||||
|
|
||||||
|
function RPC.disconnected(errorCode, message)
|
||||||
|
print(string.format("Discord: disconnected (%d: %s)", errorCode, message))
|
||||||
|
end
|
||||||
|
|
||||||
|
function RPC.errored(errorCode, message)
|
||||||
|
print(string.format("Discord: error (%d: %s)", errorCode, message))
|
||||||
|
end
|
||||||
|
|
||||||
|
function RPC.joinGame(joinSecret)
|
||||||
|
print(string.format("Discord: join (%s)", joinSecret))
|
||||||
|
end
|
||||||
|
|
||||||
|
function RPC.spectateGame(spectateSecret)
|
||||||
|
print(string.format("Discord: spectate (%s)", spectateSecret))
|
||||||
|
end
|
||||||
|
|
||||||
|
function RPC.joinRequest(userId, username, discriminator, avatar)
|
||||||
|
print(string.format("Discord: join request (%s, %s, %s, %s)", userId, username, discriminator, avatar))
|
||||||
|
RPC.respond(userId, "yes")
|
||||||
|
end
|
||||||
|
|
||||||
|
RPC.initialize(DiscordRPC.appId, true)
|
||||||
|
local now = os.time(os.date("*t"))
|
||||||
|
|
||||||
|
DiscordRPC.RPC = RPC
|
||||||
|
print("DiscordRPC successfully loaded.")
|
||||||
|
else
|
||||||
|
print("DiscordRPC failed to load!")
|
||||||
|
print(RPC)
|
||||||
|
end
|
||||||
|
|
||||||
|
DiscordRPC.presence = {
|
||||||
|
startTimestamp = now,
|
||||||
|
details = "Loading game...",
|
||||||
|
state = "",
|
||||||
|
largeImageKey = "icon2",
|
||||||
|
largeImageText = "Arcade Stacker",
|
||||||
|
smallImageKey = "",
|
||||||
|
smallImageText = ""
|
||||||
|
}
|
||||||
|
|
||||||
|
function DiscordRPC:update(newstuff)
|
||||||
|
for k, v in pairs(newstuff) do self.presence[k] = v end
|
||||||
|
if self.loaded then self.RPC.updatePresence(self.presence) end
|
||||||
|
end
|
||||||
@@ -10,6 +10,10 @@ sounds = {
|
|||||||
},
|
},
|
||||||
move = love.audio.newSource("res/se/move.wav", "static"),
|
move = love.audio.newSource("res/se/move.wav", "static"),
|
||||||
bottom = love.audio.newSource("res/se/bottom.wav", "static"),
|
bottom = love.audio.newSource("res/se/bottom.wav", "static"),
|
||||||
|
cursor = love.audio.newSource("res/se/cursor.wav", "static"),
|
||||||
|
cursor_lr = love.audio.newSource("res/se/cursor_lr.wav", "static"),
|
||||||
|
main_decide = love.audio.newSource("res/se/main_decide.wav", "static"),
|
||||||
|
mode_decide = love.audio.newSource("res/se/mode_decide.wav", "static"),
|
||||||
}
|
}
|
||||||
|
|
||||||
function playSE(sound, subsound)
|
function playSE(sound, subsound)
|
||||||
|
|||||||
10
main.lua
10
main.lua
@@ -1,6 +1,7 @@
|
|||||||
function love.load()
|
function love.load()
|
||||||
math.randomseed(os.time())
|
math.randomseed(os.time())
|
||||||
highscores = {}
|
highscores = {}
|
||||||
|
require "load.rpc"
|
||||||
require "load.graphics"
|
require "load.graphics"
|
||||||
require "load.fonts"
|
require "load.fonts"
|
||||||
require "load.sounds"
|
require "load.sounds"
|
||||||
@@ -14,6 +15,13 @@ function love.load()
|
|||||||
|
|
||||||
love.window.setMode(love.graphics.getWidth(), love.graphics.getHeight(), {resizable = true});
|
love.window.setMode(love.graphics.getWidth(), love.graphics.getHeight(), {resizable = true});
|
||||||
|
|
||||||
|
if not config.gamesettings then config.gamesettings = {} end
|
||||||
|
for _, option in ipairs(GameConfigScene.options) do
|
||||||
|
if not config.gamesettings[option[1]] then
|
||||||
|
config.gamesettings[option[1]] = 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
if not config.input then
|
if not config.input then
|
||||||
config.input = {}
|
config.input = {}
|
||||||
scene = InputConfigScene()
|
scene = InputConfigScene()
|
||||||
@@ -64,7 +72,7 @@ end
|
|||||||
|
|
||||||
function love.draw()
|
function love.draw()
|
||||||
love.graphics.push()
|
love.graphics.push()
|
||||||
|
|
||||||
-- get offset matrix
|
-- get offset matrix
|
||||||
love.graphics.setDefaultFilter("linear", "nearest")
|
love.graphics.setDefaultFilter("linear", "nearest")
|
||||||
local width = love.graphics.getWidth()
|
local width = love.graphics.getWidth()
|
||||||
|
|||||||
BIN
res/backgrounds/options-pcb.png
Normal file
BIN
res/backgrounds/options-pcb.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 3.0 MiB |
BIN
res/se/cursor.wav
Normal file
BIN
res/se/cursor.wav
Normal file
Binary file not shown.
BIN
res/se/cursor_lr.wav
Normal file
BIN
res/se/cursor_lr.wav
Normal file
Binary file not shown.
BIN
res/se/main_decide.wav
Normal file
BIN
res/se/main_decide.wav
Normal file
Binary file not shown.
BIN
res/se/mode_decide.wav
Normal file
BIN
res/se/mode_decide.wav
Normal file
Binary file not shown.
@@ -11,5 +11,5 @@ ExitScene = require "scene.exit"
|
|||||||
GameScene = require "scene.game"
|
GameScene = require "scene.game"
|
||||||
ModeSelectScene = require "scene.mode_select"
|
ModeSelectScene = require "scene.mode_select"
|
||||||
InputConfigScene = require "scene.input_config"
|
InputConfigScene = require "scene.input_config"
|
||||||
ConfigScene = require "scene.config"
|
GameConfigScene = require "scene.game_config"
|
||||||
TitleScene = require "scene.title"
|
TitleScene = require "scene.title"
|
||||||
|
|||||||
@@ -5,6 +5,10 @@ function GameScene:new(game_mode, ruleset)
|
|||||||
self.game = game_mode()
|
self.game = game_mode()
|
||||||
self.ruleset = ruleset()
|
self.ruleset = ruleset()
|
||||||
self.game:initialize(self.ruleset)
|
self.game:initialize(self.ruleset)
|
||||||
|
DiscordRPC:update({
|
||||||
|
details = self.game.rpc_details,
|
||||||
|
state = self.game.name,
|
||||||
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
function GameScene:update()
|
function GameScene:update()
|
||||||
@@ -66,7 +70,7 @@ function GameScene:onKeyPress(e)
|
|||||||
-- fuck this, this is hacky but the way this codebase is setup prevents anything else
|
-- fuck this, this is hacky but the way this codebase is setup prevents anything else
|
||||||
-- it seems like all the values that get touched in the child gamemode class
|
-- it seems like all the values that get touched in the child gamemode class
|
||||||
-- stop being linked to the values of the GameMode superclass because of how `mt.__index` works
|
-- stop being linked to the values of the GameMode superclass because of how `mt.__index` works
|
||||||
-- not even sure this is the actual problem, but I don't want to have to rebuild everything about
|
-- not even sure this is the actual problem, but I don't want to have to rebuild everything about
|
||||||
-- the core organisation of everything. this hacky way will have to do until someone figures out something.
|
-- the core organisation of everything. this hacky way will have to do until someone figures out something.
|
||||||
love.keypressed("escape", "escape", false)
|
love.keypressed("escape", "escape", false)
|
||||||
love.keypressed("return", "return", false)
|
love.keypressed("return", "return", false)
|
||||||
|
|||||||
79
scene/game_config.lua
Normal file
79
scene/game_config.lua
Normal file
@@ -0,0 +1,79 @@
|
|||||||
|
local ConfigScene = Scene:extend()
|
||||||
|
|
||||||
|
ConfigScene.title = "Game Settings"
|
||||||
|
|
||||||
|
require 'load.save'
|
||||||
|
|
||||||
|
ConfigScene.options = {
|
||||||
|
-- this serves as reference to what the options' values mean i guess?
|
||||||
|
{"manlock", "Manual locking", {"Per ruleset","Per gamemode","Harddrop", "Softdrop"}},
|
||||||
|
{"piece_colour", "Piece Colours", {"Per ruleset", "Arika", "TTC"}},
|
||||||
|
{"world_reverse", "World Reverse", {"No", "Yes"}},
|
||||||
|
}
|
||||||
|
local optioncount = #ConfigScene.options
|
||||||
|
|
||||||
|
function ConfigScene:new()
|
||||||
|
-- load current config
|
||||||
|
self.config = config.input
|
||||||
|
self.highlight = 1
|
||||||
|
|
||||||
|
DiscordRPC:update({
|
||||||
|
details = "In menus",
|
||||||
|
state = "Changing game settings",
|
||||||
|
})
|
||||||
|
end
|
||||||
|
|
||||||
|
function ConfigScene:update()
|
||||||
|
end
|
||||||
|
|
||||||
|
function ConfigScene:render()
|
||||||
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
|
love.graphics.draw(
|
||||||
|
backgrounds["game_config"],
|
||||||
|
0, 0, 0,
|
||||||
|
0.5, 0.5
|
||||||
|
)
|
||||||
|
|
||||||
|
love.graphics.setFont(font_3x5_4)
|
||||||
|
love.graphics.print("GAME SETTINGS", 80, 40)
|
||||||
|
|
||||||
|
love.graphics.setColor(1, 1, 1, 0.5)
|
||||||
|
love.graphics.rectangle("fill", 20, 98 + self.highlight * 20, 170, 22)
|
||||||
|
|
||||||
|
love.graphics.setFont(font_3x5_2)
|
||||||
|
for i, option in ipairs(ConfigScene.options) do
|
||||||
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
|
love.graphics.printf(option[2], 40, 100 + i * 20, 150, "left")
|
||||||
|
for j, setting in ipairs(option[3]) do
|
||||||
|
love.graphics.setColor(1, 1, 1, config.gamesettings[option[1]] == j and 1 or 0.5)
|
||||||
|
love.graphics.printf(setting, 100 + 110 * j, 100 + i * 20, 100, "center")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ConfigScene:onKeyPress(e)
|
||||||
|
if e.scancode == "return" and e.isRepeat == false then
|
||||||
|
playSE("mode_decide")
|
||||||
|
saveConfig()
|
||||||
|
scene = TitleScene()
|
||||||
|
elseif (e.scancode == config.input["up"] or e.scancode == "up") and e.isRepeat == false then
|
||||||
|
playSE("cursor")
|
||||||
|
self.highlight = Mod1(self.highlight-1, optioncount)
|
||||||
|
elseif (e.scancode == config.input["down"] or e.scancode == "down") and e.isRepeat == false then
|
||||||
|
playSE("cursor")
|
||||||
|
self.highlight = Mod1(self.highlight+1, optioncount)
|
||||||
|
elseif (e.scancode == config.input["left"] or e.scancode == "left") and e.isRepeat == false then
|
||||||
|
playSE("cursor_lr")
|
||||||
|
local option = ConfigScene.options[self.highlight]
|
||||||
|
config.gamesettings[option[1]] = Mod1(config.gamesettings[option[1]]-1, #option[3])
|
||||||
|
elseif (e.scancode == config.input["right"] or e.scancode == "right") and e.isRepeat == false then
|
||||||
|
playSE("cursor_lr")
|
||||||
|
local option = ConfigScene.options[self.highlight]
|
||||||
|
config.gamesettings[option[1]] = Mod1(config.gamesettings[option[1]]+1, #option[3])
|
||||||
|
elseif e.scancode == "escape" then
|
||||||
|
loadSave()
|
||||||
|
scene = TitleScene()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
return ConfigScene
|
||||||
@@ -22,6 +22,11 @@ function ConfigScene:new()
|
|||||||
-- load current config
|
-- load current config
|
||||||
self.config = config.input
|
self.config = config.input
|
||||||
self.input_state = 1
|
self.input_state = 1
|
||||||
|
|
||||||
|
DiscordRPC:update({
|
||||||
|
details = "In menus",
|
||||||
|
state = "Changing input config",
|
||||||
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
function ConfigScene:update()
|
function ConfigScene:update()
|
||||||
@@ -34,11 +39,11 @@ function ConfigScene:render()
|
|||||||
0, 0, 0,
|
0, 0, 0,
|
||||||
0.5, 0.5
|
0.5, 0.5
|
||||||
)
|
)
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_2)
|
love.graphics.setFont(font_3x5_2)
|
||||||
for i, input in pairs(configurable_inputs) do
|
for i, input in pairs(configurable_inputs) do
|
||||||
|
love.graphics.printf(input, 40, 50 + i * 20, 200, "left")
|
||||||
if config.input[input] then
|
if config.input[input] then
|
||||||
love.graphics.printf(input, 40, 50 + i * 20, 200, "left")
|
|
||||||
love.graphics.printf(
|
love.graphics.printf(
|
||||||
love.keyboard.getKeyFromScancode(config.input[input]) .. " (" .. config.input[input] .. ")",
|
love.keyboard.getKeyFromScancode(config.input[input]) .. " (" .. config.input[input] .. ")",
|
||||||
240, 50 + i * 20, 200, "left"
|
240, 50 + i * 20, 200, "left"
|
||||||
@@ -62,8 +67,13 @@ function ConfigScene:onKeyPress(e)
|
|||||||
self.input_state = 1
|
self.input_state = 1
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
config.input[configurable_inputs[self.input_state]] = e.scancode
|
if e.scancode == "escape" then
|
||||||
self.input_state = self.input_state + 1
|
loadSave()
|
||||||
|
scene = TitleScene()
|
||||||
|
else
|
||||||
|
config.input[configurable_inputs[self.input_state]] = e.scancode
|
||||||
|
self.input_state = self.input_state + 1
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ game_modes = {
|
|||||||
--require 'tetris.modes.strategy',
|
--require 'tetris.modes.strategy',
|
||||||
--require 'tetris.modes.interval_training',
|
--require 'tetris.modes.interval_training',
|
||||||
--require 'tetris.modes.pacer_test',
|
--require 'tetris.modes.pacer_test',
|
||||||
--require 'tetris.modes.demon_mode',
|
require 'tetris.modes.demon_mode',
|
||||||
require 'tetris.modes.phantom_mania',
|
require 'tetris.modes.phantom_mania',
|
||||||
require 'tetris.modes.phantom_mania2',
|
require 'tetris.modes.phantom_mania2',
|
||||||
require 'tetris.modes.phantom_mania_n',
|
require 'tetris.modes.phantom_mania_n',
|
||||||
@@ -34,6 +34,7 @@ rulesets = {
|
|||||||
require 'tetris.rulesets.arika_ti',
|
require 'tetris.rulesets.arika_ti',
|
||||||
require 'tetris.rulesets.ti_srs',
|
require 'tetris.rulesets.ti_srs',
|
||||||
require 'tetris.rulesets.arika_ace',
|
require 'tetris.rulesets.arika_ace',
|
||||||
|
require 'tetris.rulesets.arika_ace2',
|
||||||
require 'tetris.rulesets.arika_srs',
|
require 'tetris.rulesets.arika_srs',
|
||||||
require 'tetris.rulesets.standard_exp',
|
require 'tetris.rulesets.standard_exp',
|
||||||
--require 'tetris.rulesets.bonkers',
|
--require 'tetris.rulesets.bonkers',
|
||||||
@@ -47,6 +48,10 @@ function ModeSelectScene:new()
|
|||||||
ruleset = current_ruleset,
|
ruleset = current_ruleset,
|
||||||
select = "mode",
|
select = "mode",
|
||||||
}
|
}
|
||||||
|
DiscordRPC:update({
|
||||||
|
details = "In menus",
|
||||||
|
state = "Choosing a mode",
|
||||||
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
function ModeSelectScene:update()
|
function ModeSelectScene:update()
|
||||||
@@ -58,7 +63,7 @@ function ModeSelectScene:render()
|
|||||||
0, 0, 0,
|
0, 0, 0,
|
||||||
0.5, 0.5
|
0.5, 0.5
|
||||||
)
|
)
|
||||||
|
|
||||||
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
|
||||||
@@ -72,7 +77,7 @@ function ModeSelectScene:render()
|
|||||||
love.graphics.setColor(1, 1, 1, 0.5)
|
love.graphics.setColor(1, 1, 1, 0.5)
|
||||||
end
|
end
|
||||||
love.graphics.rectangle("fill", 340, 78 + 20 * self.menu_state.ruleset, 200, 22)
|
love.graphics.rectangle("fill", 340, 78 + 20 * self.menu_state.ruleset, 200, 22)
|
||||||
|
|
||||||
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.draw(misc_graphics["select_mode"], 20, 40)
|
||||||
@@ -92,15 +97,19 @@ function ModeSelectScene:onKeyPress(e)
|
|||||||
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")
|
||||||
saveConfig()
|
saveConfig()
|
||||||
scene = GameScene(game_modes[self.menu_state.mode], rulesets[self.menu_state.ruleset])
|
scene = GameScene(game_modes[self.menu_state.mode], rulesets[self.menu_state.ruleset])
|
||||||
elseif (e.scancode == config.input["up"] or e.scancode == "up") and e.isRepeat == false then
|
elseif (e.scancode == config.input["up"] or e.scancode == "up") and e.isRepeat == false then
|
||||||
self:changeOption(-1)
|
self:changeOption(-1)
|
||||||
|
playSE("cursor")
|
||||||
elseif (e.scancode == config.input["down"] or e.scancode == "down") and e.isRepeat == false then
|
elseif (e.scancode == config.input["down"] or e.scancode == "down") and e.isRepeat == false then
|
||||||
self:changeOption(1)
|
self:changeOption(1)
|
||||||
|
playSE("cursor")
|
||||||
elseif (e.scancode == config.input["left"] or e.scancode == "left") or
|
elseif (e.scancode == config.input["left"] or e.scancode == "left") or
|
||||||
(e.scancode == config.input["right"] or e.scancode == "right") then
|
(e.scancode == config.input["right"] or e.scancode == "right") then
|
||||||
self:switchSelect()
|
self:switchSelect()
|
||||||
|
playSE("cursor_lr")
|
||||||
elseif e.scancode == "escape" then
|
elseif e.scancode == "escape" then
|
||||||
scene = TitleScene()
|
scene = TitleScene()
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -3,11 +3,31 @@ local TitleScene = Scene:extend()
|
|||||||
local main_menu_screens = {
|
local main_menu_screens = {
|
||||||
ModeSelectScene,
|
ModeSelectScene,
|
||||||
InputConfigScene,
|
InputConfigScene,
|
||||||
|
GameConfigScene,
|
||||||
ExitScene,
|
ExitScene,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
local mainmenuidle = {
|
||||||
|
"Idle",
|
||||||
|
"On title screen",
|
||||||
|
"On main menu screen",
|
||||||
|
"Twiddling their thumbs",
|
||||||
|
"Admiring the main menu's BG",
|
||||||
|
"Waiting for spring to come",
|
||||||
|
"Actually not playing",
|
||||||
|
"Contemplating collecting stars",
|
||||||
|
"Preparing to put the block!!",
|
||||||
|
"Having a nap",
|
||||||
|
"In menus",
|
||||||
|
"Bottom text",
|
||||||
|
}
|
||||||
|
|
||||||
function TitleScene:new()
|
function TitleScene:new()
|
||||||
self.main_menu_state = 1
|
self.main_menu_state = 1
|
||||||
|
DiscordRPC:update({
|
||||||
|
details = "In menus",
|
||||||
|
state = mainmenuidle[math.random(#mainmenuidle)],
|
||||||
|
})
|
||||||
end
|
end
|
||||||
|
|
||||||
function TitleScene:update()
|
function TitleScene:update()
|
||||||
@@ -39,11 +59,14 @@ end
|
|||||||
|
|
||||||
function TitleScene:onKeyPress(e)
|
function TitleScene:onKeyPress(e)
|
||||||
if e.scancode == "return" and e.isRepeat == false then
|
if e.scancode == "return" and e.isRepeat == false then
|
||||||
|
playSE("main_decide")
|
||||||
scene = main_menu_screens[self.main_menu_state]()
|
scene = main_menu_screens[self.main_menu_state]()
|
||||||
elseif (e.scancode == config.input["up"] or e.scancode == "up") and e.isRepeat == false then
|
elseif (e.scancode == config.input["up"] or e.scancode == "up") and e.isRepeat == false then
|
||||||
self:changeOption(-1)
|
self:changeOption(-1)
|
||||||
|
playSE("cursor")
|
||||||
elseif (e.scancode == config.input["down"] or e.scancode == "down") and e.isRepeat == false then
|
elseif (e.scancode == config.input["down"] or e.scancode == "down") and e.isRepeat == false then
|
||||||
self:changeOption(1)
|
self:changeOption(1)
|
||||||
|
playSE("cursor")
|
||||||
elseif e.scancode == "escape" and e.isRepeat == false then
|
elseif e.scancode == "escape" and e.isRepeat == false then
|
||||||
love.event.quit()
|
love.event.quit()
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -143,7 +143,7 @@ function Grid:copyBottomRow()
|
|||||||
for col = 1, 10 do
|
for col = 1, 10 do
|
||||||
self.grid[24][col] = (self.grid[23][col] == empty) and empty or {
|
self.grid[24][col] = (self.grid[23][col] == empty) and empty or {
|
||||||
skin = self.grid[23][col].skin,
|
skin = self.grid[23][col].skin,
|
||||||
colour = "G"
|
colour = "X"
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
@@ -161,7 +161,7 @@ function Grid:applyPiece(piece)
|
|||||||
if y + 1 > 0 then
|
if y + 1 > 0 then
|
||||||
self.grid[y+1][x+1] = {
|
self.grid[y+1][x+1] = {
|
||||||
skin = piece.skin,
|
skin = piece.skin,
|
||||||
colour = piece.shape
|
colour = piece.colour
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -177,7 +177,7 @@ function Grid:applyBigPiece(piece)
|
|||||||
if y*2+a > 0 then
|
if y*2+a > 0 then
|
||||||
self.grid[y*2+a][x*2+b] = {
|
self.grid[y*2+a][x*2+b] = {
|
||||||
skin = piece.skin,
|
skin = piece.skin,
|
||||||
colour = piece.shape
|
colour = piece.colour
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ local Object = require 'libs.classic'
|
|||||||
|
|
||||||
local Piece = Object:extend()
|
local Piece = Object:extend()
|
||||||
|
|
||||||
function Piece:new(shape, rotation, position, block_offsets, gravity, lock_delay, skin, big)
|
function Piece:new(shape, rotation, position, block_offsets, gravity, lock_delay, skin, colour, big)
|
||||||
self.shape = shape
|
self.shape = shape
|
||||||
self.rotation = rotation
|
self.rotation = rotation
|
||||||
self.position = position
|
self.position = position
|
||||||
@@ -10,6 +10,7 @@ function Piece:new(shape, rotation, position, block_offsets, gravity, lock_delay
|
|||||||
self.gravity = gravity
|
self.gravity = gravity
|
||||||
self.lock_delay = lock_delay
|
self.lock_delay = lock_delay
|
||||||
self.skin = skin
|
self.skin = skin
|
||||||
|
self.colour = colour
|
||||||
self.ghost = false
|
self.ghost = false
|
||||||
self.locked = false
|
self.locked = false
|
||||||
self.big = big
|
self.big = big
|
||||||
@@ -21,7 +22,7 @@ function Piece:withOffset(offset)
|
|||||||
return Piece(
|
return Piece(
|
||||||
self.shape, self.rotation,
|
self.shape, self.rotation,
|
||||||
{x = self.position.x + offset.x, y = self.position.y + offset.y},
|
{x = self.position.x + offset.x, y = self.position.y + offset.y},
|
||||||
self.block_offsets, self.gravity, self.lock_delay, self.skin, self.big
|
self.block_offsets, self.gravity, self.lock_delay, self.skin, self.colour, self.big
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -31,7 +32,7 @@ function Piece:withRelativeRotation(rot)
|
|||||||
while new_rot >= 4 do new_rot = new_rot - 4 end
|
while new_rot >= 4 do new_rot = new_rot - 4 end
|
||||||
return Piece(
|
return Piece(
|
||||||
self.shape, new_rot, self.position,
|
self.shape, new_rot, self.position,
|
||||||
self.block_offsets, self.gravity, self.lock_delay, self.skin, self.big
|
self.block_offsets, self.gravity, self.lock_delay, self.skin, self.colour, self.big
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -148,13 +149,13 @@ function Piece:draw(opacity, brightness, grid, partial_das)
|
|||||||
local y = self.position.y + offset.y
|
local y = self.position.y + offset.y
|
||||||
if self.big then
|
if self.big then
|
||||||
love.graphics.draw(
|
love.graphics.draw(
|
||||||
blocks[self.skin][self.shape],
|
blocks[self.skin][self.colour],
|
||||||
64+x*32+partial_das*2, 16+y*32+gravity_offset*2,
|
64+x*32+partial_das*2, 16+y*32+gravity_offset*2,
|
||||||
0, 2, 2
|
0, 2, 2
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
love.graphics.draw(
|
love.graphics.draw(
|
||||||
blocks[self.skin][self.shape],
|
blocks[self.skin][self.colour],
|
||||||
64+x*16+partial_das, 16+y*16+gravity_offset
|
64+x*16+partial_das, 16+y*16+gravity_offset
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -136,15 +136,16 @@ function MarathonA2Game:onLineClear(cleared_row_count)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA2Game:updateScore(level, drop_bonus, cleared_lines)
|
function MarathonA2Game:updateScore(level, drop_bonus, cleared_lines)
|
||||||
|
if self.grid:checkForBravo(cleared_lines) then self.bravo = 4 else self.bravo = 1 end
|
||||||
cleared_lines = cleared_lines / 2
|
cleared_lines = cleared_lines / 2
|
||||||
self:updateGrade(cleared_lines)
|
self:updateGrade(cleared_lines)
|
||||||
if cleared_lines > 0 then
|
if cleared_lines > 0 then
|
||||||
self.score = self.score + (
|
self.score = self.score + (
|
||||||
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
(math.ceil((level + cleared_lines) / 4) + 2 * drop_bonus) *
|
||||||
cleared_lines * (cleared_lines * 2 - 1) * (self.combo * 2 - 1)
|
cleared_lines * self.combo * self.bravo
|
||||||
)
|
)
|
||||||
self.lines = self.lines + cleared_lines
|
self.lines = self.lines + cleared_lines
|
||||||
self.combo = self.combo + cleared_lines - 1
|
self.combo = self.combo + 2 * (cleared_lines - 1)
|
||||||
else
|
else
|
||||||
self.drop_bonus = 0
|
self.drop_bonus = 0
|
||||||
self.combo = 1
|
self.combo = 1
|
||||||
|
|||||||
@@ -11,9 +11,6 @@ DemonModeGame.name = "Demon Mode"
|
|||||||
DemonModeGame.hash = "DemonMode"
|
DemonModeGame.hash = "DemonMode"
|
||||||
DemonModeGame.tagline = "Can you handle the ludicrous speed past level 20?"
|
DemonModeGame.tagline = "Can you handle the ludicrous speed past level 20?"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function DemonModeGame:new()
|
function DemonModeGame:new()
|
||||||
DemonModeGame.super:new()
|
DemonModeGame.super:new()
|
||||||
self.roll_frames = 0
|
self.roll_frames = 0
|
||||||
@@ -29,6 +26,9 @@ function DemonModeGame:new()
|
|||||||
self.enable_hold = true
|
self.enable_hold = true
|
||||||
self.lock_drop = true
|
self.lock_drop = true
|
||||||
self.next_queue_length = 3
|
self.next_queue_length = 3
|
||||||
|
if math.random() < 1/6.66 then
|
||||||
|
self.rpc_details = "Suffering"
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function DemonModeGame:getARE()
|
function DemonModeGame:getARE()
|
||||||
@@ -166,11 +166,18 @@ function DemonModeGame:updateSectionTimes(old_level, new_level)
|
|||||||
self.section_tetris_count = 0
|
self.section_tetris_count = 0
|
||||||
else
|
else
|
||||||
self.level = math.min(new_level, 2500)
|
self.level = math.min(new_level, 2500)
|
||||||
|
self.skip_failed = true
|
||||||
end
|
end
|
||||||
-- record new section
|
-- record new section
|
||||||
section_time = self.frames - self.section_start_time
|
section_time = self.frames - self.section_start_time
|
||||||
table.insert(self.section_times, section_time)
|
table.insert(self.section_times, section_time)
|
||||||
self.section_start_time = self.frames
|
self.section_start_time = self.frames
|
||||||
|
else
|
||||||
|
self.level = math.min(new_level, 2500)
|
||||||
|
if self.skip_failed and new_level >= 500 then
|
||||||
|
self.level = 500
|
||||||
|
self.game_over = true
|
||||||
|
end
|
||||||
end
|
end
|
||||||
else
|
else
|
||||||
self.level = math.min(new_level, 2500)
|
self.level = math.min(new_level, 2500)
|
||||||
@@ -229,7 +236,7 @@ function DemonModeGame:drawScoringInfo()
|
|||||||
strTrueValues(self.prev_inputs)
|
strTrueValues(self.prev_inputs)
|
||||||
)
|
)
|
||||||
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
||||||
love.graphics.printf("GRADE", 240, 120, 40, "left")
|
if self.grade ~= 0 then love.graphics.printf("GRADE", 240, 120, 40, "left") end
|
||||||
love.graphics.printf("SCORE", 240, 200, 40, "left")
|
love.graphics.printf("SCORE", 240, 200, 40, "left")
|
||||||
love.graphics.printf("LEVEL", 240, 320, 40, "left")
|
love.graphics.printf("LEVEL", 240, 320, 40, "left")
|
||||||
|
|
||||||
|
|||||||
@@ -40,9 +40,12 @@ function GameMode:new()
|
|||||||
self.draw_section_times = false
|
self.draw_section_times = false
|
||||||
self.draw_secondary_section_times = false
|
self.draw_secondary_section_times = false
|
||||||
self.big_mode = false
|
self.big_mode = false
|
||||||
|
self.rpc_details = "In game"
|
||||||
-- variables related to configurable parameters
|
-- variables related to configurable parameters
|
||||||
self.drop_locked = false
|
self.drop_locked = false
|
||||||
self.hard_drop_locked = false
|
self.hard_drop_locked = false
|
||||||
|
self.lock_on_soft_drop = false
|
||||||
|
self.lock_on_hard_drop = false
|
||||||
self.hold_queue = nil
|
self.hold_queue = nil
|
||||||
self.held = false
|
self.held = false
|
||||||
self.section_start_time = 0
|
self.section_start_time = 0
|
||||||
@@ -59,6 +62,7 @@ function GameMode:getLineClearDelay() return 40 end
|
|||||||
function GameMode:getDasLimit() return 15 end
|
function GameMode:getDasLimit() return 15 end
|
||||||
|
|
||||||
function GameMode:getNextPiece(ruleset)
|
function GameMode:getNextPiece(ruleset)
|
||||||
|
|
||||||
return {
|
return {
|
||||||
skin = "2tie",
|
skin = "2tie",
|
||||||
shape = self.randomizer:nextPiece(),
|
shape = self.randomizer:nextPiece(),
|
||||||
@@ -72,6 +76,8 @@ function GameMode:initialize(ruleset)
|
|||||||
for i = 1, self.next_queue_length do
|
for i = 1, self.next_queue_length do
|
||||||
table.insert(self.next_queue, self:getNextPiece(ruleset))
|
table.insert(self.next_queue, self:getNextPiece(ruleset))
|
||||||
end
|
end
|
||||||
|
self.lock_on_soft_drop = ({ruleset.softdrop_lock, self.instant_soft_drop, false, true })[config.gamesettings.manlock]
|
||||||
|
self.lock_on_hard_drop = ({ruleset.harddrop_lock, self.instant_hard_drop, true, false})[config.gamesettings.manlock]
|
||||||
end
|
end
|
||||||
|
|
||||||
function GameMode:update(inputs, ruleset)
|
function GameMode:update(inputs, ruleset)
|
||||||
@@ -125,7 +131,7 @@ function GameMode:update(inputs, ruleset)
|
|||||||
self.piece:isDropBlocked(self.grid) and
|
self.piece:isDropBlocked(self.grid) and
|
||||||
not self.hard_drop_locked then
|
not self.hard_drop_locked then
|
||||||
self:onHardDrop(piece_dy)
|
self:onHardDrop(piece_dy)
|
||||||
if self.instant_hard_drop then
|
if self.lock_on_hard_drop then
|
||||||
self.piece.locked = true
|
self.piece.locked = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -134,7 +140,7 @@ function GameMode:update(inputs, ruleset)
|
|||||||
self:onSoftDrop(piece_dy)
|
self:onSoftDrop(piece_dy)
|
||||||
if self.piece:isDropBlocked(self.grid) and
|
if self.piece:isDropBlocked(self.grid) and
|
||||||
not self.drop_locked and
|
not self.drop_locked and
|
||||||
self.instant_soft_drop
|
self.lock_on_soft_drop
|
||||||
then
|
then
|
||||||
self.piece.locked = true
|
self.piece.locked = true
|
||||||
end
|
end
|
||||||
@@ -340,11 +346,12 @@ function GameMode:drawGhostPiece(ruleset)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function GameMode:drawNextQueue(ruleset)
|
function GameMode:drawNextQueue(ruleset)
|
||||||
|
local colourscheme = ({ruleset.colourscheme, ColourSchemes.Arika, ColourSchemes.TTC})[config.gamesettings.piece_colour]
|
||||||
function drawPiece(piece, skin, offsets, pos_x, pos_y)
|
function drawPiece(piece, skin, offsets, pos_x, pos_y)
|
||||||
for index, offset in pairs(offsets) do
|
for index, offset in pairs(offsets) do
|
||||||
local x = offset.x + ruleset.spawn_positions[piece].x
|
local x = offset.x + ruleset.spawn_positions[piece].x
|
||||||
local y = offset.y + 4.7
|
local y = offset.y + 4.7
|
||||||
love.graphics.draw(blocks[skin][piece], pos_x+x*16, pos_y+y*16)
|
love.graphics.draw(blocks[skin][colourscheme[piece]], pos_x+x*16, pos_y+y*16)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
for i = 1, self.next_queue_length do
|
for i = 1, self.next_queue_length do
|
||||||
|
|||||||
@@ -145,7 +145,7 @@ function KonohaGame:onLineClear(cleared_row_count)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function KonohaGame:getBackground()
|
function KonohaGame:getBackground()
|
||||||
return math.min(math.floor(self.level / 100), 9)
|
return math.floor(self.level / 100)
|
||||||
end
|
end
|
||||||
|
|
||||||
function KonohaGame:drawScoringInfo()
|
function KonohaGame:drawScoringInfo()
|
||||||
|
|||||||
@@ -18,6 +18,7 @@ function MarathonA1Game:new()
|
|||||||
|
|
||||||
self.roll_frames = 0
|
self.roll_frames = 0
|
||||||
self.combo = 1
|
self.combo = 1
|
||||||
|
self.bravos = 0
|
||||||
self.gm_conditions = {
|
self.gm_conditions = {
|
||||||
level300 = false,
|
level300 = false,
|
||||||
level500 = false,
|
level500 = false,
|
||||||
@@ -145,11 +146,15 @@ function MarathonA1Game:onLineClear(cleared_row_count)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA1Game:updateScore(level, drop_bonus, cleared_lines)
|
function MarathonA1Game:updateScore(level, drop_bonus, cleared_lines)
|
||||||
|
if self.grid:checkForBravo(cleared_lines) then
|
||||||
|
self.bravo = 4
|
||||||
|
self.bravos = self.bravos + 1
|
||||||
|
else self.bravo = 1 end
|
||||||
if cleared_lines > 0 then
|
if cleared_lines > 0 then
|
||||||
self.combo = self.combo + (cleared_lines - 1) * 2
|
self.combo = self.combo + (cleared_lines - 1) * 2
|
||||||
self.score = self.score + (
|
self.score = self.score + (
|
||||||
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
||||||
cleared_lines * self.combo
|
cleared_lines * self.combo * self.bravo
|
||||||
)
|
)
|
||||||
self.lines = self.lines + cleared_lines
|
self.lines = self.lines + cleared_lines
|
||||||
else
|
else
|
||||||
@@ -201,6 +206,8 @@ function MarathonA1Game:drawScoringInfo()
|
|||||||
love.graphics.printf("SECRET GRADE", 240, 430, 180, "left")
|
love.graphics.printf("SECRET GRADE", 240, 430, 180, "left")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if self.bravos > 0 then love.graphics.printf("BRAVO", 300, 120, 40, "left") end
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
love.graphics.setFont(font_3x5_3)
|
||||||
love.graphics.printf(self.score, 240, 220, 90, "left")
|
love.graphics.printf(self.score, 240, 220, 90, "left")
|
||||||
if self.gm_conditions["level300"] and self.gm_conditions["level500"] and self.gm_conditions["level900"] then
|
if self.gm_conditions["level300"] and self.gm_conditions["level500"] and self.gm_conditions["level900"] then
|
||||||
@@ -214,6 +221,7 @@ function MarathonA1Game:drawScoringInfo()
|
|||||||
if sg >= 5 then
|
if sg >= 5 then
|
||||||
love.graphics.printf(self.SGnames[sg], 240, 450, 180, "left")
|
love.graphics.printf(self.SGnames[sg], 240, 450, 180, "left")
|
||||||
end
|
end
|
||||||
|
if self.bravos > 0 then love.graphics.printf(self.bravos, 300, 140, 40, "left") end
|
||||||
|
|
||||||
love.graphics.setFont(font_8x11)
|
love.graphics.setFont(font_8x11)
|
||||||
love.graphics.printf(formatTime(self.frames), 64, 420, 160, "center")
|
love.graphics.printf(formatTime(self.frames), 64, 420, 160, "center")
|
||||||
|
|||||||
@@ -142,13 +142,14 @@ end
|
|||||||
|
|
||||||
function MarathonA2Game:updateScore(level, drop_bonus, cleared_lines)
|
function MarathonA2Game:updateScore(level, drop_bonus, cleared_lines)
|
||||||
self:updateGrade(cleared_lines)
|
self:updateGrade(cleared_lines)
|
||||||
|
if self.grid:checkForBravo(cleared_lines) then self.bravo = 4 else self.bravo = 1 end
|
||||||
if cleared_lines > 0 then
|
if cleared_lines > 0 then
|
||||||
self.score = self.score + (
|
self.score = self.score + (
|
||||||
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
(math.ceil((level + cleared_lines) / 4) + 2 * drop_bonus) *
|
||||||
cleared_lines * (cleared_lines * 2 - 1) * (self.combo * 2 - 1)
|
cleared_lines * self.combo * self.bravo
|
||||||
)
|
)
|
||||||
self.lines = self.lines + cleared_lines
|
self.lines = self.lines + cleared_lines
|
||||||
self.combo = self.combo + cleared_lines - 1
|
self.combo = self.combo + (cleared_lines - 1) * 2
|
||||||
else
|
else
|
||||||
self.drop_bonus = 0
|
self.drop_bonus = 0
|
||||||
self.combo = 1
|
self.combo = 1
|
||||||
|
|||||||
@@ -32,6 +32,12 @@ function MarathonA3Game:new()
|
|||||||
|
|
||||||
self.randomizer = History6RollsRandomizer()
|
self.randomizer = History6RollsRandomizer()
|
||||||
|
|
||||||
|
self.SGnames = {
|
||||||
|
"9", "8", "7", "6", "5", "4", "3", "2", "1",
|
||||||
|
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
|
||||||
|
"GM"
|
||||||
|
}
|
||||||
|
|
||||||
self.lock_drop = true
|
self.lock_drop = true
|
||||||
self.lock_hard_drop = true
|
self.lock_hard_drop = true
|
||||||
self.enable_hold = true
|
self.enable_hold = true
|
||||||
|
|||||||
@@ -16,6 +16,12 @@ function PhantomManiaGame:new()
|
|||||||
|
|
||||||
self.lock_drop = true
|
self.lock_drop = true
|
||||||
self.next_queue_length = 1
|
self.next_queue_length = 1
|
||||||
|
|
||||||
|
self.SGnames = {
|
||||||
|
"9", "8", "7", "6", "5", "4", "3", "2", "1",
|
||||||
|
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
|
||||||
|
"GM"
|
||||||
|
}
|
||||||
|
|
||||||
self.roll_frames = 0
|
self.roll_frames = 0
|
||||||
self.combo = 1
|
self.combo = 1
|
||||||
@@ -161,12 +167,16 @@ function PhantomManiaGame:drawScoringInfo()
|
|||||||
local text_x = config["side_next"] and 320 or 240
|
local text_x = config["side_next"] and 320 or 240
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_2)
|
love.graphics.setFont(font_3x5_2)
|
||||||
love.graphics.printf("GRADE", text_x, 120, 40, "left")
|
if getLetterGrade(self.level, self.clear) ~= "" then love.graphics.printf("GRADE", text_x, 120, 40, "left") end
|
||||||
love.graphics.printf("SCORE", text_x, 200, 40, "left")
|
love.graphics.printf("SCORE", text_x, 200, 40, "left")
|
||||||
love.graphics.printf("LEVEL", text_x, 320, 40, "left")
|
love.graphics.printf("LEVEL", text_x, 320, 40, "left")
|
||||||
|
local sg = self.grid:checkSecretGrade()
|
||||||
|
if sg >= 5 then
|
||||||
|
love.graphics.printf("SECRET GRADE", 240, 430, 180, "left")
|
||||||
|
end
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
love.graphics.setFont(font_3x5_3)
|
||||||
love.graphics.printf(getLetterGrade(self.level, self.clear), text_x, 140, 90, "left")
|
if getLetterGrade(self.level, self.clear) ~= "" then love.graphics.printf(getLetterGrade(self.level, self.clear), text_x, 140, 90, "left") end
|
||||||
love.graphics.printf(self.score, text_x, 220, 90, "left")
|
love.graphics.printf(self.score, text_x, 220, 90, "left")
|
||||||
love.graphics.printf(self.level, text_x, 340, 40, "right")
|
love.graphics.printf(self.level, text_x, 340, 40, "right")
|
||||||
if self.clear then
|
if self.clear then
|
||||||
@@ -175,6 +185,9 @@ function PhantomManiaGame:drawScoringInfo()
|
|||||||
love.graphics.printf(self:getSectionEndLevel(), text_x, 370, 40, "right")
|
love.graphics.printf(self:getSectionEndLevel(), text_x, 370, 40, "right")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if sg >= 5 then
|
||||||
|
love.graphics.printf(self.SGnames[sg], 240, 450, 180, "left")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function PhantomManiaGame:getSectionEndLevel()
|
function PhantomManiaGame:getSectionEndLevel()
|
||||||
|
|||||||
@@ -26,6 +26,12 @@ function PhantomMania2Game:new()
|
|||||||
self.hold_age = 0
|
self.hold_age = 0
|
||||||
self.queue_age = 0
|
self.queue_age = 0
|
||||||
self.roll_points = 0
|
self.roll_points = 0
|
||||||
|
|
||||||
|
self.SGnames = {
|
||||||
|
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
|
||||||
|
"m1", "m2", "m3", "m4", "m5", "m6", "m7", "m8", "m9",
|
||||||
|
"GM"
|
||||||
|
}
|
||||||
|
|
||||||
self.randomizer = History6RollsRandomizer()
|
self.randomizer = History6RollsRandomizer()
|
||||||
|
|
||||||
@@ -285,6 +291,10 @@ function PhantomMania2Game:drawScoringInfo()
|
|||||||
love.graphics.printf("GRADE", text_x, 120, 40, "left")
|
love.graphics.printf("GRADE", text_x, 120, 40, "left")
|
||||||
love.graphics.printf("SCORE", text_x, 200, 40, "left")
|
love.graphics.printf("SCORE", text_x, 200, 40, "left")
|
||||||
love.graphics.printf("LEVEL", text_x, 320, 40, "left")
|
love.graphics.printf("LEVEL", text_x, 320, 40, "left")
|
||||||
|
local sg = self.grid:checkSecretGrade()
|
||||||
|
if sg >= 5 then
|
||||||
|
love.graphics.printf("SECRET GRADE", 240, 430, 180, "left")
|
||||||
|
end
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
love.graphics.setFont(font_3x5_3)
|
||||||
love.graphics.printf(getLetterGrade(math.floor(self.grade)), text_x, 140, 90, "left")
|
love.graphics.printf(getLetterGrade(math.floor(self.grade)), text_x, 140, 90, "left")
|
||||||
@@ -295,6 +305,10 @@ function PhantomMania2Game:drawScoringInfo()
|
|||||||
else
|
else
|
||||||
love.graphics.printf(math.floor(self.level / 100 + 1) * 100, text_x, 370, 50, "right")
|
love.graphics.printf(math.floor(self.level / 100 + 1) * 100, text_x, 370, 50, "right")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if sg >= 5 then
|
||||||
|
love.graphics.printf(self.SGnames[sg], 240, 450, 180, "left")
|
||||||
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function PhantomMania2Game:getBackground()
|
function PhantomMania2Game:getBackground()
|
||||||
|
|||||||
@@ -8,6 +8,12 @@ PhantomManiaNGame.tagline = "The old mode from Nullpomino, for Ti-ARS and SRS su
|
|||||||
|
|
||||||
function PhantomManiaNGame:new()
|
function PhantomManiaNGame:new()
|
||||||
PhantomManiaNGame.super:new()
|
PhantomManiaNGame.super:new()
|
||||||
|
|
||||||
|
self.SGnames = {
|
||||||
|
"M1", "M2", "M3", "M4", "M5", "M6", "M7", "M8", "M9",
|
||||||
|
"M10", "M11", "M12", "M13", "M14", "M15", "M16", "M17", "M18",
|
||||||
|
"GM"
|
||||||
|
}
|
||||||
|
|
||||||
self.next_queue_length = 3
|
self.next_queue_length = 3
|
||||||
self.enable_hold = true
|
self.enable_hold = true
|
||||||
|
|||||||
@@ -3,7 +3,7 @@ require 'funcs'
|
|||||||
local GameMode = require 'tetris.modes.gamemode'
|
local GameMode = require 'tetris.modes.gamemode'
|
||||||
local Piece = require 'tetris.components.piece'
|
local Piece = require 'tetris.components.piece'
|
||||||
|
|
||||||
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
local Bag7Randomiser = require 'tetris.randomizers.bag7noSZOstart'
|
||||||
|
|
||||||
local Race40Game = GameMode:extend()
|
local Race40Game = GameMode:extend()
|
||||||
|
|
||||||
@@ -18,7 +18,7 @@ function Race40Game:new()
|
|||||||
self.lines = 0
|
self.lines = 0
|
||||||
self.line_goal = 40
|
self.line_goal = 40
|
||||||
self.pieces = 0
|
self.pieces = 0
|
||||||
self.randomizer = History6RollsRandomizer()
|
self.randomizer = Bag7Randomiser()
|
||||||
|
|
||||||
self.roll_frames = 0
|
self.roll_frames = 0
|
||||||
|
|
||||||
|
|||||||
@@ -19,6 +19,8 @@ function SurvivalA1Game:new()
|
|||||||
|
|
||||||
self.roll_frames = 0
|
self.roll_frames = 0
|
||||||
self.combo = 1
|
self.combo = 1
|
||||||
|
self.bravos = 0
|
||||||
|
|
||||||
self.gm_conditions = {
|
self.gm_conditions = {
|
||||||
level300 = false,
|
level300 = false,
|
||||||
level500 = false,
|
level500 = false,
|
||||||
@@ -116,10 +118,14 @@ function SurvivalA1Game:onLineClear(cleared_row_count)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function SurvivalA1Game:updateScore(level, drop_bonus, cleared_lines)
|
function SurvivalA1Game:updateScore(level, drop_bonus, cleared_lines)
|
||||||
|
if self.grid:checkForBravo(cleared_lines) then
|
||||||
|
self.bravo = 4
|
||||||
|
self.bravos = self.bravos + 1
|
||||||
|
else self.bravo = 1 end
|
||||||
if cleared_lines > 0 then
|
if cleared_lines > 0 then
|
||||||
self.score = self.score + (
|
self.score = self.score + (
|
||||||
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
||||||
cleared_lines * (cleared_lines * 2 - 1) * self.combo
|
cleared_lines * self.bravo * self.combo
|
||||||
)
|
)
|
||||||
self.lines = self.lines + cleared_lines
|
self.lines = self.lines + cleared_lines
|
||||||
self.combo = self.combo + (cleared_lines - 1) * 2
|
self.combo = self.combo + (cleared_lines - 1) * 2
|
||||||
@@ -169,6 +175,8 @@ function SurvivalA1Game:drawScoringInfo()
|
|||||||
love.graphics.printf("SECRET GRADE", 240, 430, 180, "left")
|
love.graphics.printf("SECRET GRADE", 240, 430, 180, "left")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
if self.bravos > 0 then love.graphics.printf("BRAVO", 300, 120, 40, "left") end
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
love.graphics.setFont(font_3x5_3)
|
||||||
love.graphics.printf(self.score, 240, 220, 90, "left")
|
love.graphics.printf(self.score, 240, 220, 90, "left")
|
||||||
if self.gm_conditions["level300"] and self.gm_conditions["level500"] and self.gm_conditions["level900"] then
|
if self.gm_conditions["level300"] and self.gm_conditions["level500"] and self.gm_conditions["level900"] then
|
||||||
@@ -182,6 +190,7 @@ function SurvivalA1Game:drawScoringInfo()
|
|||||||
if sg >= 5 then
|
if sg >= 5 then
|
||||||
love.graphics.printf(self.SGnames[sg], 240, 450, 180, "left")
|
love.graphics.printf(self.SGnames[sg], 240, 450, 180, "left")
|
||||||
end
|
end
|
||||||
|
if self.bravos > 0 then love.graphics.printf(self.bravos, 300, 140, 40, "left") end
|
||||||
|
|
||||||
love.graphics.setFont(font_8x11)
|
love.graphics.setFont(font_8x11)
|
||||||
love.graphics.printf(formatTime(self.frames), 64, 420, 160, "center")
|
love.graphics.printf(formatTime(self.frames), 64, 420, 160, "center")
|
||||||
|
|||||||
@@ -105,10 +105,11 @@ function SurvivalA2Game:onLineClear(cleared_row_count)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function SurvivalA2Game:updateScore(level, drop_bonus, cleared_lines)
|
function SurvivalA2Game:updateScore(level, drop_bonus, cleared_lines)
|
||||||
|
if self.grid:checkForBravo(cleared_lines) then self.bravo = 4 else self.bravo = 1 end
|
||||||
if cleared_lines > 0 then
|
if cleared_lines > 0 then
|
||||||
self.score = self.score + (
|
self.score = self.score + (
|
||||||
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
(math.ceil((level + cleared_lines) / 4) + drop_bonus) *
|
||||||
cleared_lines * (cleared_lines * 2 - 1) * self.combo
|
cleared_lines * self.bravo * self.combo
|
||||||
)
|
)
|
||||||
self.lines = self.lines + cleared_lines
|
self.lines = self.lines + cleared_lines
|
||||||
self.combo = self.combo + (cleared_lines - 1) * 2
|
self.combo = self.combo + (cleared_lines - 1) * 2
|
||||||
@@ -141,7 +142,7 @@ function SurvivalA2Game:drawScoringInfo()
|
|||||||
strTrueValues(self.prev_inputs)
|
strTrueValues(self.prev_inputs)
|
||||||
)
|
)
|
||||||
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
||||||
love.graphics.printf("GRADE", text_x, 120, 40, "left")
|
if self:getLetterGrade() ~= "" then love.graphics.printf("GRADE", text_x, 120, 40, "left") end
|
||||||
love.graphics.printf("SCORE", text_x, 200, 40, "left")
|
love.graphics.printf("SCORE", text_x, 200, 40, "left")
|
||||||
love.graphics.printf("LEVEL", text_x, 320, 40, "left")
|
love.graphics.printf("LEVEL", text_x, 320, 40, "left")
|
||||||
local sg = self.grid:checkSecretGrade()
|
local sg = self.grid:checkSecretGrade()
|
||||||
@@ -151,7 +152,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")
|
||||||
love.graphics.printf(self:getLetterGrade(), text_x, 140, 90, "left")
|
if self:getLetterGrade() ~= "" then love.graphics.printf(self:getLetterGrade(), text_x, 140, 90, "left") end
|
||||||
love.graphics.printf(self.level, text_x, 340, 40, "right")
|
love.graphics.printf(self.level, text_x, 340, 40, "right")
|
||||||
love.graphics.printf(self:getSectionEndLevel(), text_x, 370, 40, "right")
|
love.graphics.printf(self:getSectionEndLevel(), text_x, 370, 40, "right")
|
||||||
if sg >= 5 then
|
if sg >= 5 then
|
||||||
|
|||||||
@@ -30,7 +30,7 @@ function SurvivalA3Game:new()
|
|||||||
"m1", "m2", "m3", "m4", "m5", "m6", "m7", "m8", "m9",
|
"m1", "m2", "m3", "m4", "m5", "m6", "m7", "m8", "m9",
|
||||||
"GM"
|
"GM"
|
||||||
}
|
}
|
||||||
|
|
||||||
self.lock_drop = true
|
self.lock_drop = true
|
||||||
self.enable_hold = true
|
self.enable_hold = true
|
||||||
self.next_queue_length = 3
|
self.next_queue_length = 3
|
||||||
@@ -39,6 +39,14 @@ function SurvivalA3Game:new()
|
|||||||
self.coolregret_timer = 0
|
self.coolregret_timer = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function SurvivalA3Game:initialize(ruleset)
|
||||||
|
|
||||||
|
self.torikan_time = frameTime(2,28)
|
||||||
|
if ruleset.world then self.torikan_time = frameTime(3,03) end
|
||||||
|
self.super.initialize(self, ruleset)
|
||||||
|
-- ^ notice the . here instead of the :
|
||||||
|
end
|
||||||
|
|
||||||
function SurvivalA3Game:getARE()
|
function SurvivalA3Game:getARE()
|
||||||
if self.level < 300 then return 12
|
if self.level < 300 then return 12
|
||||||
else return 6 end
|
else return 6 end
|
||||||
@@ -95,11 +103,11 @@ function SurvivalA3Game:getNextPiece(ruleset)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function SurvivalA3Game:hitTorikan(old_level, new_level)
|
function SurvivalA3Game:hitTorikan(old_level, new_level)
|
||||||
if old_level < 500 and new_level >= 500 and self.frames > frameTime(2,28) then
|
if old_level < 500 and new_level >= 500 and self.frames > self.torikan_time then
|
||||||
self.level = 500
|
self.level = 500
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
if old_level < 1000 and new_level >= 1000 and self.frames > frameTime(4,56) then
|
if old_level < 1000 and new_level >= 1000 and self.frames > self.torikan_time*2 then
|
||||||
self.level = 1000
|
self.level = 1000
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -2,17 +2,8 @@ local Randomizer = require 'tetris.randomizers.randomizer'
|
|||||||
|
|
||||||
local AlwaysRandomizer = Randomizer:extend()
|
local AlwaysRandomizer = Randomizer:extend()
|
||||||
|
|
||||||
function AlwaysRandomizer:new(piece)
|
|
||||||
self.piece = piece
|
|
||||||
self:initialize()
|
|
||||||
self.next_queue = {}
|
|
||||||
for i = 1, 30 do
|
|
||||||
table.insert(self.next_queue, self:generatePiece())
|
|
||||||
end
|
|
||||||
end
|
|
||||||
|
|
||||||
function AlwaysRandomizer:generatePiece()
|
function AlwaysRandomizer:generatePiece()
|
||||||
return self.piece
|
return "I"
|
||||||
end
|
end
|
||||||
|
|
||||||
return AlwaysRandomizer
|
return AlwaysRandomizer
|
||||||
|
|||||||
24
tetris/randomizers/bag8.lua
Normal file
24
tetris/randomizers/bag8.lua
Normal file
@@ -0,0 +1,24 @@
|
|||||||
|
local Randomizer = require 'tetris.randomizers.randomizer'
|
||||||
|
|
||||||
|
local Bag7Randomizer = Randomizer:extend()
|
||||||
|
|
||||||
|
function Bag7Randomizer:initialize()
|
||||||
|
self.bag = {"I", "J", "L", "O", "S", "T", "Z"}
|
||||||
|
self.extra = {"I", "J", "L", "O", "S", "T", "Z"}
|
||||||
|
table.insert(self.bag, table.remove(self.extra, math.random(table.getn(self.extra))))
|
||||||
|
end
|
||||||
|
|
||||||
|
function Bag7Randomizer:generatePiece()
|
||||||
|
if next(self.extra) == nil then
|
||||||
|
self.extra = {"I", "J", "L", "O", "S", "T", "Z"}
|
||||||
|
end
|
||||||
|
if next(self.bag) == nil then
|
||||||
|
self.bag = {"I", "J", "L", "O", "S", "T", "Z"}
|
||||||
|
table.insert(self.bag, table.remove(self.extra, math.random(table.getn(self.extra))))
|
||||||
|
end
|
||||||
|
local x = math.random(table.getn(self.bag))
|
||||||
|
--print("Bag: "..table.concat(self.bag, ", ").." | Extra: "..table.concat(self.extra, ", "))
|
||||||
|
return table.remove(self.bag, x)
|
||||||
|
end
|
||||||
|
|
||||||
|
return Bag7Randomizer
|
||||||
30
tetris/randomizers/recursive_bag.lua
Normal file
30
tetris/randomizers/recursive_bag.lua
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
local Randomizer = require 'tetris.randomizers.randomizer'
|
||||||
|
|
||||||
|
local RecursiveRandomizer = Randomizer:extend()
|
||||||
|
|
||||||
|
function RecursiveRandomizer:initialize()
|
||||||
|
self.bag = {"I", "J", "L", "O", "S", "T", "Z"}
|
||||||
|
end
|
||||||
|
|
||||||
|
function RecursiveRandomizer:generatePiece()
|
||||||
|
--if next(self.bag) == nil then
|
||||||
|
-- self.bag = {"I", "J", "L", "O", "S", "T", "Z"}
|
||||||
|
--end
|
||||||
|
local x = math.random(table.getn(self.bag) + 1)
|
||||||
|
while x == table.getn(self.bag) + 1 do
|
||||||
|
--print("Refill piece pulled")
|
||||||
|
table.insert(self.bag, "I")
|
||||||
|
table.insert(self.bag, "J")
|
||||||
|
table.insert(self.bag, "L")
|
||||||
|
table.insert(self.bag, "O")
|
||||||
|
table.insert(self.bag, "S")
|
||||||
|
table.insert(self.bag, "T")
|
||||||
|
table.insert(self.bag, "Z")
|
||||||
|
x = math.random(table.getn(self.bag) + 1)
|
||||||
|
end
|
||||||
|
--print("Number of pieces in bag: "..table.getn(self.bag))
|
||||||
|
--print("Bag: "..table.concat(self.bag, ", "))
|
||||||
|
return table.remove(self.bag, x)
|
||||||
|
end
|
||||||
|
|
||||||
|
return RecursiveRandomizer
|
||||||
19
tetris/randomizers/sega.lua
Normal file
19
tetris/randomizers/sega.lua
Normal file
@@ -0,0 +1,19 @@
|
|||||||
|
local Randomizer = require 'tetris.randomizers.randomizer'
|
||||||
|
|
||||||
|
local SegaRandomizer = Randomizer:extend()
|
||||||
|
|
||||||
|
function SegaRandomizer:initialize()
|
||||||
|
self.bag = {"I", "J", "L", "O", "S", "T", "Z"}
|
||||||
|
self.sequence = {}
|
||||||
|
for i = 1, 1000 do
|
||||||
|
self.sequence[i] = self.bag[math.random(table.getn(self.bag))]
|
||||||
|
end
|
||||||
|
self.counter = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function SegaRandomizer:generatePiece()
|
||||||
|
self.counter = self.counter + 1
|
||||||
|
return self.sequence[self.counter % 1000 + 1]
|
||||||
|
end
|
||||||
|
|
||||||
|
return SegaRandomizer
|
||||||
@@ -17,10 +17,10 @@ ARS.spawn_positions = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ARS.big_spawn_positions = {
|
ARS.big_spawn_positions = {
|
||||||
I = { x=2, y=2 },
|
I = { x=3, y=2 },
|
||||||
J = { x=2, y=3 },
|
J = { x=2, y=3 },
|
||||||
L = { x=2, y=3 },
|
L = { x=2, y=3 },
|
||||||
O = { x=2, y=3 },
|
O = { x=3, y=3 },
|
||||||
S = { x=2, y=3 },
|
S = { x=2, y=3 },
|
||||||
T = { x=2, y=3 },
|
T = { x=2, y=3 },
|
||||||
Z = { x=2, y=3 },
|
Z = { x=2, y=3 },
|
||||||
@@ -110,7 +110,7 @@ function ARS:onPieceDrop(piece, grid)
|
|||||||
piece.lock_delay = 0 -- step reset
|
piece.lock_delay = 0 -- step reset
|
||||||
end
|
end
|
||||||
|
|
||||||
function ARS:get180RotationValue() return config["reverse_rotate"] and 1 or 3 end
|
function ARS:get180RotationValue() return 3 end
|
||||||
function ARS:getDefaultOrientation() return 3 end -- downward facing pieces by default
|
function ARS:getDefaultOrientation() return 3 end -- downward facing pieces by default
|
||||||
|
|
||||||
return ARS
|
return ARS
|
||||||
|
|||||||
@@ -6,6 +6,19 @@ local ARS = Ruleset:extend()
|
|||||||
ARS.name = "ACE-ARS"
|
ARS.name = "ACE-ARS"
|
||||||
ARS.hash = "ArikaACE"
|
ARS.hash = "ArikaACE"
|
||||||
|
|
||||||
|
ARS.colourscheme = {
|
||||||
|
I = "C",
|
||||||
|
L = "O",
|
||||||
|
J = "B",
|
||||||
|
S = "G",
|
||||||
|
Z = "R",
|
||||||
|
O = "Y",
|
||||||
|
T = "M",
|
||||||
|
}
|
||||||
|
|
||||||
|
ARS.softdrop_lock = false
|
||||||
|
ARS.harddrop_lock = true
|
||||||
|
|
||||||
ARS.spawn_positions = {
|
ARS.spawn_positions = {
|
||||||
I = { x=5, y=2 },
|
I = { x=5, y=2 },
|
||||||
J = { x=4, y=3 },
|
J = { x=4, y=3 },
|
||||||
@@ -17,10 +30,10 @@ ARS.spawn_positions = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ARS.big_spawn_positions = {
|
ARS.big_spawn_positions = {
|
||||||
I = { x=2, y=0 },
|
I = { x=3, y=0 },
|
||||||
J = { x=2, y=1 },
|
J = { x=2, y=1 },
|
||||||
L = { x=2, y=1 },
|
L = { x=2, y=1 },
|
||||||
O = { x=2, y=1 },
|
O = { x=3, y=1 },
|
||||||
S = { x=2, y=1 },
|
S = { x=2, y=1 },
|
||||||
T = { x=2, y=1 },
|
T = { x=2, y=1 },
|
||||||
Z = { x=2, y=1 },
|
Z = { x=2, y=1 },
|
||||||
@@ -131,7 +144,7 @@ function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|||||||
elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then
|
elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
|
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
|
||||||
elseif piece.shape == "T"
|
elseif piece.shape == "T"
|
||||||
and new_piece.rotation == 1
|
and new_piece.rotation == 0
|
||||||
and piece.floorkick == 0
|
and piece.floorkick == 0
|
||||||
and grid:canPlacePiece(new_piece:withOffset({x=0, y=-1}))
|
and grid:canPlacePiece(new_piece:withOffset({x=0, y=-1}))
|
||||||
then
|
then
|
||||||
@@ -172,7 +185,7 @@ function ARS:onPieceRotate(piece, grid)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function ARS:get180RotationValue() return config["reverse_rotate"] and 1 or 3 end
|
function ARS:get180RotationValue() return 3 end
|
||||||
function ARS:getDefaultOrientation() return 3 end -- downward facing pieces by default
|
function ARS:getDefaultOrientation() return 3 end -- downward facing pieces by default
|
||||||
|
|
||||||
return ARS
|
return ARS
|
||||||
|
|||||||
178
tetris/rulesets/arika_ace2.lua
Normal file
178
tetris/rulesets/arika_ace2.lua
Normal file
@@ -0,0 +1,178 @@
|
|||||||
|
local Piece = require 'tetris.components.piece'
|
||||||
|
local Ruleset = require 'tetris.rulesets.ruleset'
|
||||||
|
|
||||||
|
local ARS = Ruleset:extend()
|
||||||
|
|
||||||
|
ARS.name = "ACE-ARS2"
|
||||||
|
ARS.hash = "ArikaACE2"
|
||||||
|
|
||||||
|
ARS.spawn_positions = {
|
||||||
|
I = { x=5, y=2 },
|
||||||
|
J = { x=4, y=3 },
|
||||||
|
L = { x=4, y=3 },
|
||||||
|
O = { x=5, y=3 },
|
||||||
|
S = { x=4, y=3 },
|
||||||
|
T = { x=4, y=3 },
|
||||||
|
Z = { x=4, y=3 },
|
||||||
|
}
|
||||||
|
|
||||||
|
ARS.big_spawn_positions = {
|
||||||
|
I = { x=3, y=0 },
|
||||||
|
J = { x=2, y=1 },
|
||||||
|
L = { x=2, y=1 },
|
||||||
|
O = { x=3, y=1 },
|
||||||
|
S = { x=2, y=1 },
|
||||||
|
T = { x=2, y=1 },
|
||||||
|
Z = { x=2, y=1 },
|
||||||
|
}
|
||||||
|
|
||||||
|
ARS.block_offsets = {
|
||||||
|
I={
|
||||||
|
{ {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} },
|
||||||
|
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=0, y=2} },
|
||||||
|
{ {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} },
|
||||||
|
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=0, y=2} },
|
||||||
|
},
|
||||||
|
J={
|
||||||
|
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=-1, y=-1} },
|
||||||
|
{ {x=0, y=-1}, {x=1, y=-2}, {x=0, y=-2}, {x=0, y=0} },
|
||||||
|
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=1, y=0} },
|
||||||
|
{ {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=-1, y=0} },
|
||||||
|
},
|
||||||
|
L={
|
||||||
|
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=1, y=-1} },
|
||||||
|
{ {x=0, y=-2}, {x=0, y=-1}, {x=1, y=0}, {x=0, y=0} },
|
||||||
|
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=-1, y=0} },
|
||||||
|
{ {x=0, y=-1}, {x=-1, y=-2}, {x=0, y=-2}, {x=0, y=0} },
|
||||||
|
},
|
||||||
|
O={
|
||||||
|
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
|
||||||
|
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
|
||||||
|
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
|
||||||
|
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
|
||||||
|
},
|
||||||
|
S={
|
||||||
|
{ {x=1, y=-1}, {x=0, y=-1}, {x=0, y=0}, {x=-1, y=0} },
|
||||||
|
{ {x=-1, y=-2}, {x=-1, y=-1}, {x=0, y=-1}, {x=0, y=0} },
|
||||||
|
{ {x=1, y=-1}, {x=0, y=-1}, {x=0, y=0}, {x=-1, y=0} },
|
||||||
|
{ {x=-1, y=-2}, {x=-1, y=-1}, {x=0, y=-1}, {x=0, y=0} },
|
||||||
|
},
|
||||||
|
T={
|
||||||
|
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=0, y=-1} },
|
||||||
|
{ {x=0, y=-1}, {x=0, y=0}, {x=1, y=-1}, {x=0, y=-2} },
|
||||||
|
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=0, y=0} },
|
||||||
|
{ {x=0, y=-1}, {x=0, y=0}, {x=-1, y=-1}, {x=0, y=-2} },
|
||||||
|
},
|
||||||
|
Z={
|
||||||
|
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=0}, {x=0, y=0} },
|
||||||
|
{ {x=0, y=-1}, {x=0, y=0}, {x=1, y=-2}, {x=1, y=-1} },
|
||||||
|
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=0}, {x=0, y=0} },
|
||||||
|
{ {x=0, y=-1}, {x=0, y=0}, {x=1, y=-2}, {x=1, y=-1} },
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
-- Component functions.
|
||||||
|
|
||||||
|
function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||||
|
|
||||||
|
-- O doesn't kick
|
||||||
|
if (piece.shape == "O") then return end
|
||||||
|
|
||||||
|
-- center column rule
|
||||||
|
if (
|
||||||
|
piece.shape == "J" or piece.shape == "T" or piece.shape == "L"
|
||||||
|
) and (
|
||||||
|
piece.rotation == 0 or piece.rotation == 2
|
||||||
|
) then
|
||||||
|
local offsets = new_piece:getBlockOffsets()
|
||||||
|
table.sort(offsets, function(A, B) return A.y < B.y or A.y == B.y and A.x < B.y end)
|
||||||
|
for index, offset in pairs(offsets) do
|
||||||
|
if grid:isOccupied(piece.position.x + offset.x, piece.position.y + offset.y) then
|
||||||
|
if offset.x == 0 then
|
||||||
|
return
|
||||||
|
else
|
||||||
|
break
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if piece.shape == "I" then
|
||||||
|
-- special kick rules for I
|
||||||
|
if new_piece.rotation == 0 or new_piece.rotation == 2 then
|
||||||
|
-- kick right, right2, left
|
||||||
|
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
|
||||||
|
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
|
||||||
|
self:onPieceRotate(piece, grid)
|
||||||
|
elseif grid:canPlacePiece(new_piece:withOffset({x=2, y=0})) then
|
||||||
|
piece:setRelativeRotation(rot_dir):setOffset({x=2, y=0})
|
||||||
|
self:onPieceRotate(piece, grid)
|
||||||
|
elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then
|
||||||
|
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
|
||||||
|
self:onPieceRotate(piece, grid)
|
||||||
|
end
|
||||||
|
elseif piece:isDropBlocked(grid) and (new_piece.rotation == 1 or new_piece.rotation == 3) and piece.floorkick == 0 then
|
||||||
|
-- kick up, up2
|
||||||
|
if grid:canPlacePiece(new_piece:withOffset({x=0, y=-1})) then
|
||||||
|
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
|
||||||
|
self:onPieceRotate(piece, grid)
|
||||||
|
piece.floorkick = 1
|
||||||
|
elseif grid:canPlacePiece(new_piece:withOffset({x=0, y=-2})) then
|
||||||
|
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-2})
|
||||||
|
self:onPieceRotate(piece, grid)
|
||||||
|
piece.floorkick = 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
else
|
||||||
|
-- kick right, kick left
|
||||||
|
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
|
||||||
|
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
|
||||||
|
elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then
|
||||||
|
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
|
||||||
|
elseif piece.shape == "T"
|
||||||
|
and new_piece.rotation == 0
|
||||||
|
and piece.floorkick == 0
|
||||||
|
and grid:canPlacePiece(new_piece:withOffset({x=0, y=-1}))
|
||||||
|
then
|
||||||
|
-- T floorkick
|
||||||
|
piece.floorkick = piece.floorkick + 1
|
||||||
|
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
end
|
||||||
|
|
||||||
|
function ARS:onPieceCreate(piece, grid)
|
||||||
|
piece.floorkick = 0
|
||||||
|
piece.manipulations = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function ARS:onPieceDrop(piece, grid)
|
||||||
|
piece.lock_delay = 0 -- step reset
|
||||||
|
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 >= 127 then
|
||||||
|
piece.locked = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ARS:onPieceRotate(piece, grid)
|
||||||
|
piece.lock_delay = 0 -- rotate reset
|
||||||
|
if piece:isDropBlocked(grid) then
|
||||||
|
piece.manipulations = piece.manipulations + 1
|
||||||
|
if piece.manipulations >= 127 then
|
||||||
|
piece.locked = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ARS:get180RotationValue() return 3 end
|
||||||
|
function ARS:getDefaultOrientation() return 3 end -- downward facing pieces by default
|
||||||
|
|
||||||
|
return ARS
|
||||||
@@ -5,6 +5,18 @@ local SRS = Ruleset:extend()
|
|||||||
|
|
||||||
SRS.name = "ACE-SRS"
|
SRS.name = "ACE-SRS"
|
||||||
SRS.hash = "ACE Standard"
|
SRS.hash = "ACE Standard"
|
||||||
|
SRS.world = true
|
||||||
|
SRS.colourscheme = {
|
||||||
|
I = "C",
|
||||||
|
L = "O",
|
||||||
|
J = "B",
|
||||||
|
S = "G",
|
||||||
|
Z = "R",
|
||||||
|
O = "Y",
|
||||||
|
T = "M",
|
||||||
|
}
|
||||||
|
SRS.softdrop_lock = false
|
||||||
|
SRS.harddrop_lock = true
|
||||||
|
|
||||||
SRS.enable_IRS_wallkicks = true
|
SRS.enable_IRS_wallkicks = true
|
||||||
|
|
||||||
@@ -19,10 +31,10 @@ SRS.spawn_positions = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SRS.big_spawn_positions = {
|
SRS.big_spawn_positions = {
|
||||||
I = { x=2, y=0 },
|
I = { x=3, y=0 },
|
||||||
J = { x=2, y=1 },
|
J = { x=2, y=1 },
|
||||||
L = { x=2, y=1 },
|
L = { x=2, y=1 },
|
||||||
O = { x=2, y=1 },
|
O = { x=3, y=1 },
|
||||||
S = { x=2, y=1 },
|
S = { x=2, y=1 },
|
||||||
T = { x=2, y=1 },
|
T = { x=2, y=1 },
|
||||||
Z = { x=2, y=1 },
|
Z = { x=2, y=1 },
|
||||||
@@ -98,24 +110,24 @@ SRS.wallkicks_3x3 = {
|
|||||||
|
|
||||||
SRS.wallkicks_line = {
|
SRS.wallkicks_line = {
|
||||||
[0]={
|
[0]={
|
||||||
[1]={{x=-2, y=0}, {x=1, y=0}, {x=-2, y=1}, {x=1, y=-2}},
|
[1]={{x=-2, y= 0}, {x= 1, y= 0}, {x= 1, y=-2}, {x=-2, y= 1}},
|
||||||
[2]={},
|
[2]={},
|
||||||
[3]={{x=-1, y=0}, {x=2, y=0}, {x=-1, y=-2}, {x=2, y=1}},
|
[3]={{x= 2, y= 0}, {x=-1, y= 0}, {x=-1, y=-2}, {x= 2, y= 1}},
|
||||||
},
|
},
|
||||||
[1]={
|
[1]={
|
||||||
[0]={{x=2, y=0}, {x=-1, y=0}, {x=2, y=-1}, {x=-1, y=2}},
|
[0]={{x= 2, y= 0}, {x=-1, y= 0}, {x= 2, y=-1}, {x=-1, y= 2}},
|
||||||
[2]={{x=-1, y=0}, {x=2, y=0}, {x=-1, y=-2}, {x=2, y=1}},
|
[2]={{x=-1, y= 0}, {x= 2, y= 0}, {x=-1, y=-2}, {x= 2, y= 1}},
|
||||||
[3]={{x=0, y=1}, {x=0, y=-1}, {x=0, y=2}, {x=0, y=-2}},
|
[3]={},
|
||||||
},
|
},
|
||||||
[2]={
|
[2]={
|
||||||
[0]={},
|
[0]={},
|
||||||
[1]={{x=1, y=0}, {x=-2, y=0}, {x=1, y=2}, {x=-2, y=-1}},
|
[1]={{x=-2, y= 0}, {x= 1, y= 0}, {x=-2, y=-1}, {x= 1, y= 1}},
|
||||||
[3]={{x=2, y=0}, {x=-1, y=0}, {x=2, y=-1}, {x=-1, y=2}},
|
[3]={{x= 2, y= 0}, {x=-1, y= 0}, {x= 2, y=-1}, {x=-1, y= 1}},
|
||||||
},
|
},
|
||||||
[3]={
|
[3]={
|
||||||
[0]={{x=1, y=0}, {x=-2, y=0}, {x=1, y=2}, {x=-2, y=-1}},
|
[0]={{x=-2, y= 0}, {x= 1, y= 0}, {x=-2, y=-1}, {x= 1, y= 2}},
|
||||||
[1]={{x=0, y=1}, {x=0, y=-1}, {x=0, y=2}, {x=0, y=-2}},
|
[1]={},
|
||||||
[2]={{x=-2, y=0}, {x=1, y=0}, {x=-2, y=1}, {x=1, y=-2}},
|
[2]={{x= 1, y= 0}, {x=-2, y= 0}, {x= 1, y=-2}, {x=-2, y= 1}},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -174,4 +186,5 @@ function SRS:onPieceRotate(piece, grid)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function SRS:get180RotationValue() return 3 end
|
||||||
return SRS
|
return SRS
|
||||||
|
|||||||
@@ -17,10 +17,10 @@ ARS.spawn_positions = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
ARS.big_spawn_positions = {
|
ARS.big_spawn_positions = {
|
||||||
I = { x=2, y=2 },
|
I = { x=3, y=2 },
|
||||||
J = { x=2, y=3 },
|
J = { x=2, y=3 },
|
||||||
L = { x=2, y=3 },
|
L = { x=2, y=3 },
|
||||||
O = { x=2, y=3 },
|
O = { x=3, y=3 },
|
||||||
S = { x=2, y=3 },
|
S = { x=2, y=3 },
|
||||||
T = { x=2, y=3 },
|
T = { x=2, y=3 },
|
||||||
Z = { x=2, y=3 },
|
Z = { x=2, y=3 },
|
||||||
@@ -131,7 +131,7 @@ function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|||||||
elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then
|
elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
|
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
|
||||||
elseif piece.shape == "T"
|
elseif piece.shape == "T"
|
||||||
and new_piece.rotation == 1
|
and new_piece.rotation == 0
|
||||||
and piece.floorkick == 0
|
and piece.floorkick == 0
|
||||||
and grid:canPlacePiece(new_piece:withOffset({x=0, y=-1}))
|
and grid:canPlacePiece(new_piece:withOffset({x=0, y=-1}))
|
||||||
then
|
then
|
||||||
@@ -151,7 +151,7 @@ function ARS:onPieceDrop(piece, grid)
|
|||||||
piece.lock_delay = 0 -- step reset
|
piece.lock_delay = 0 -- step reset
|
||||||
end
|
end
|
||||||
|
|
||||||
function ARS:get180RotationValue() return config["reverse_rotate"] and 1 or 3 end
|
function ARS:get180RotationValue() return 3 end
|
||||||
function ARS:getDefaultOrientation() return 3 end -- downward facing pieces by default
|
function ARS:getDefaultOrientation() return 3 end -- downward facing pieces by default
|
||||||
|
|
||||||
return ARS
|
return ARS
|
||||||
|
|||||||
@@ -5,25 +5,26 @@ local CRS = Ruleset:extend()
|
|||||||
|
|
||||||
CRS.name = "Cambridge"
|
CRS.name = "Cambridge"
|
||||||
CRS.hash = "Cambridge"
|
CRS.hash = "Cambridge"
|
||||||
|
CRS.world = true
|
||||||
|
|
||||||
CRS.spawn_positions = {
|
CRS.spawn_positions = {
|
||||||
I = { x=5, y=4 },
|
I = { x=5, y=4 },
|
||||||
J = { x=4, y=5 },
|
J = { x=4, y=5 },
|
||||||
L = { x=4, y=5 },
|
L = { x=4, y=5 },
|
||||||
O = { x=5, y=5 },
|
O = { x=5, y=5 },
|
||||||
S = { x=4, y=4 },
|
S = { x=4, y=5 },
|
||||||
T = { x=4, y=5 },
|
T = { x=4, y=5 },
|
||||||
Z = { x=4, y=4 },
|
Z = { x=4, y=5 },
|
||||||
}
|
}
|
||||||
|
|
||||||
CRS.big_spawn_positions = {
|
CRS.big_spawn_positions = {
|
||||||
I = { x=2, y=2 },
|
I = { x=3, y=2 },
|
||||||
J = { x=2, y=3 },
|
J = { x=2, y=3 },
|
||||||
L = { x=2, y=3 },
|
L = { x=2, y=3 },
|
||||||
O = { x=2, y=3 },
|
O = { x=3, y=3 },
|
||||||
S = { x=2, y=2 },
|
S = { x=2, y=3 },
|
||||||
T = { x=2, y=3 },
|
T = { x=2, y=3 },
|
||||||
Z = { x=2, y=2 },
|
Z = { x=2, y=3 },
|
||||||
}
|
}
|
||||||
|
|
||||||
CRS.block_offsets = {
|
CRS.block_offsets = {
|
||||||
@@ -52,10 +53,10 @@ CRS.block_offsets = {
|
|||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
|
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
|
||||||
},
|
},
|
||||||
S={
|
S={
|
||||||
{ {x=-1, y=1}, {x=0, y=1}, {x=0, y=0}, {x=1, y=0} },
|
{ {x=-1, y=0}, {x=0, y=0}, {x=0, y=-1}, {x=1, y=-1} },
|
||||||
{ {x=0, y=1}, {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1} },
|
{ {x=0, y=0}, {x=0, y=-1}, {x=-1, y=-1}, {x=-1, y=-2} },
|
||||||
{ {x=-1, y=1}, {x=0, y=1}, {x=0, y=0}, {x=1, y=0} },
|
{ {x=-1, y=0}, {x=0, y=0}, {x=0, y=-1}, {x=1, y=-1} },
|
||||||
{ {x=0, y=1}, {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1} },
|
{ {x=0, y=0}, {x=0, y=-1}, {x=-1, y=-1}, {x=-1, y=-2} },
|
||||||
},
|
},
|
||||||
T={
|
T={
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=0, y=-1} },
|
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=0, y=-1} },
|
||||||
@@ -64,10 +65,10 @@ CRS.block_offsets = {
|
|||||||
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=-1}, {x=-1, y=0} },
|
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=-1}, {x=-1, y=0} },
|
||||||
},
|
},
|
||||||
Z={
|
Z={
|
||||||
{ {x=1, y=1}, {x=0, y=1}, {x=0, y=0}, {x=-1, y=0} },
|
{ {x=1, y=0}, {x=0, y=0}, {x=0, y=-1}, {x=-1, y=-1} },
|
||||||
{ {x=1, y=-1}, {x=1, y=0}, {x=0, y=0}, {x=0, y=1} },
|
{ {x=1, y=-2}, {x=1, y=-1}, {x=0, y=-1}, {x=0, y=0} },
|
||||||
{ {x=1, y=1}, {x=0, y=1}, {x=0, y=0}, {x=-1, y=0} },
|
{ {x=1, y=0}, {x=0, y=0}, {x=0, y=-1}, {x=-1, y=-1} },
|
||||||
{ {x=1, y=-1}, {x=1, y=0}, {x=0, y=0}, {x=0, y=1} },
|
{ {x=1, y=-2}, {x=1, y=-1}, {x=0, y=-1}, {x=0, y=0} },
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -362,6 +363,10 @@ function CRS:attemptRotate(new_inputs, piece, grid, initial)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if rot_dir == 0 then return end
|
if rot_dir == 0 then return end
|
||||||
|
|
||||||
|
if self.world and config.gamesettings.world_reverse == 2 then
|
||||||
|
rot_dir = 4 - rot_dir
|
||||||
|
end
|
||||||
|
|
||||||
local new_piece = piece:withRelativeRotation(rot_dir)
|
local new_piece = piece:withRelativeRotation(rot_dir)
|
||||||
self:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
self:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||||
|
|||||||
@@ -6,6 +6,20 @@ local Ruleset = Object:extend()
|
|||||||
Ruleset.name = ""
|
Ruleset.name = ""
|
||||||
Ruleset.hash = ""
|
Ruleset.hash = ""
|
||||||
|
|
||||||
|
-- Arika-type ruleset defaults
|
||||||
|
Ruleset.world = false
|
||||||
|
Ruleset.colourscheme = {
|
||||||
|
I = "R",
|
||||||
|
L = "O",
|
||||||
|
J = "B",
|
||||||
|
S = "M",
|
||||||
|
Z = "G",
|
||||||
|
O = "Y",
|
||||||
|
T = "C",
|
||||||
|
}
|
||||||
|
Ruleset.softdrop_lock = true
|
||||||
|
Ruleset.harddrop_lock = false
|
||||||
|
|
||||||
Ruleset.enable_IRS_wallkicks = false
|
Ruleset.enable_IRS_wallkicks = false
|
||||||
|
|
||||||
-- Component functions.
|
-- Component functions.
|
||||||
@@ -39,6 +53,9 @@ function Ruleset:attemptRotate(new_inputs, piece, grid, initial)
|
|||||||
end
|
end
|
||||||
|
|
||||||
if rot_dir == 0 then return end
|
if rot_dir == 0 then return end
|
||||||
|
if self.world and config.gamesettings.world_reverse == 2 then
|
||||||
|
rot_dir = 4 - rot_dir
|
||||||
|
end
|
||||||
|
|
||||||
local new_piece = piece:withRelativeRotation(rot_dir)
|
local new_piece = piece:withRelativeRotation(rot_dir)
|
||||||
|
|
||||||
@@ -117,10 +134,12 @@ function Ruleset:initializePiece(
|
|||||||
else
|
else
|
||||||
spawn_positions = self.spawn_positions
|
spawn_positions = self.spawn_positions
|
||||||
end
|
end
|
||||||
|
local colours = ({self.colourscheme, ColourSchemes.Arika, ColourSchemes.TTC})[config.gamesettings.piece_colour]
|
||||||
|
|
||||||
local piece = Piece(data.shape, data.orientation - 1, {
|
local piece = Piece(data.shape, data.orientation - 1, {
|
||||||
x = spawn_positions[data.shape].x,
|
x = spawn_positions[data.shape].x,
|
||||||
y = spawn_positions[data.shape].y
|
y = spawn_positions[data.shape].y
|
||||||
}, self.block_offsets, 0, 0, data.skin, big)
|
}, self.block_offsets, 0, 0, data.skin, colours[data.shape], big)
|
||||||
|
|
||||||
self:onPieceCreate(piece)
|
self:onPieceCreate(piece)
|
||||||
self:rotatePiece(inputs, piece, grid, {}, true)
|
self:rotatePiece(inputs, piece, grid, {}, true)
|
||||||
|
|||||||
@@ -5,6 +5,18 @@ local SRS = Ruleset:extend()
|
|||||||
|
|
||||||
SRS.name = "Guideline SRS"
|
SRS.name = "Guideline SRS"
|
||||||
SRS.hash = "Standard"
|
SRS.hash = "Standard"
|
||||||
|
SRS.world = true
|
||||||
|
SRS.colourscheme = {
|
||||||
|
I = "C",
|
||||||
|
L = "O",
|
||||||
|
J = "B",
|
||||||
|
S = "G",
|
||||||
|
Z = "R",
|
||||||
|
O = "Y",
|
||||||
|
T = "M",
|
||||||
|
}
|
||||||
|
SRS.softdrop_lock = false
|
||||||
|
SRS.harddrop_lock = true
|
||||||
|
|
||||||
SRS.enable_IRS_wallkicks = true
|
SRS.enable_IRS_wallkicks = true
|
||||||
|
|
||||||
@@ -19,10 +31,10 @@ SRS.spawn_positions = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
SRS.big_spawn_positions = {
|
SRS.big_spawn_positions = {
|
||||||
I = { x=2, y=0 },
|
I = { x=3, y=0 },
|
||||||
J = { x=2, y=1 },
|
J = { x=2, y=1 },
|
||||||
L = { x=2, y=1 },
|
L = { x=2, y=1 },
|
||||||
O = { x=2, y=1 },
|
O = { x=3, y=1 },
|
||||||
S = { x=2, y=1 },
|
S = { x=2, y=1 },
|
||||||
T = { x=2, y=1 },
|
T = { x=2, y=1 },
|
||||||
Z = { x=2, y=1 },
|
Z = { x=2, y=1 },
|
||||||
|
|||||||
@@ -5,27 +5,39 @@ local SRS = Ruleset:extend()
|
|||||||
|
|
||||||
SRS.name = "Ti-World"
|
SRS.name = "Ti-World"
|
||||||
SRS.hash = "Bad I-kicks"
|
SRS.hash = "Bad I-kicks"
|
||||||
|
SRS.world = true
|
||||||
|
SRS.colourscheme = {
|
||||||
|
I = "C",
|
||||||
|
L = "O",
|
||||||
|
J = "B",
|
||||||
|
S = "G",
|
||||||
|
Z = "R",
|
||||||
|
O = "Y",
|
||||||
|
T = "M",
|
||||||
|
}
|
||||||
|
SRS.softdrop_lock = false
|
||||||
|
SRS.harddrop_lock = true
|
||||||
|
|
||||||
SRS.enable_IRS_wallkicks = true
|
SRS.enable_IRS_wallkicks = true
|
||||||
|
|
||||||
SRS.spawn_positions = {
|
SRS.spawn_positions = {
|
||||||
I = { x=5, y=2 },
|
I = { x=5, y=4 },
|
||||||
J = { x=4, y=3 },
|
J = { x=4, y=5 },
|
||||||
L = { x=4, y=3 },
|
L = { x=4, y=5 },
|
||||||
O = { x=5, y=3 },
|
O = { x=5, y=5 },
|
||||||
S = { x=4, y=3 },
|
S = { x=4, y=5 },
|
||||||
T = { x=4, y=3 },
|
T = { x=4, y=5 },
|
||||||
Z = { x=4, y=3 },
|
Z = { x=4, y=5 },
|
||||||
}
|
}
|
||||||
|
|
||||||
SRS.big_spawn_positions = {
|
SRS.big_spawn_positions = {
|
||||||
I = { x=2, y=0 },
|
I = { x=3, y=2 },
|
||||||
J = { x=2, y=1 },
|
J = { x=2, y=3 },
|
||||||
L = { x=2, y=1 },
|
L = { x=2, y=3 },
|
||||||
O = { x=2, y=1 },
|
O = { x=3, y=3 },
|
||||||
S = { x=2, y=1 },
|
S = { x=2, y=3 },
|
||||||
T = { x=2, y=1 },
|
T = { x=2, y=3 },
|
||||||
Z = { x=2, y=1 },
|
Z = { x=2, y=3 },
|
||||||
}
|
}
|
||||||
|
|
||||||
SRS.block_offsets = {
|
SRS.block_offsets = {
|
||||||
@@ -98,24 +110,24 @@ SRS.wallkicks_3x3 = {
|
|||||||
|
|
||||||
SRS.wallkicks_line = {
|
SRS.wallkicks_line = {
|
||||||
[0]={
|
[0]={
|
||||||
[1]={{x=-2, y=0}, {x=1, y=0}, {x=-2, y=1}, {x=1, y=-2}},
|
[1]={{x=-2, y= 0}, {x= 1, y= 0}, {x= 1, y=-2}, {x=-2, y= 1}},
|
||||||
[2]={},
|
[2]={},
|
||||||
[3]={{x=-1, y=0}, {x=2, y=0}, {x=-1, y=-2}, {x=2, y=1}},
|
[3]={{x= 2, y= 0}, {x=-1, y= 0}, {x=-1, y=-2}, {x= 2, y= 1}},
|
||||||
},
|
},
|
||||||
[1]={
|
[1]={
|
||||||
[0]={{x=2, y=0}, {x=-1, y=0}, {x=2, y=-1}, {x=-1, y=2}},
|
[0]={{x= 2, y= 0}, {x=-1, y= 0}, {x= 2, y=-1}, {x=-1, y= 2}},
|
||||||
[2]={{x=-1, y=0}, {x=2, y=0}, {x=-1, y=-2}, {x=2, y=1}},
|
[2]={{x=-1, y= 0}, {x= 2, y= 0}, {x=-1, y=-2}, {x= 2, y= 1}},
|
||||||
[3]={{x=0, y=1}, {x=0, y=-1}, {x=0, y=2}, {x=0, y=-2}},
|
[3]={},
|
||||||
},
|
},
|
||||||
[2]={
|
[2]={
|
||||||
[0]={},
|
[0]={},
|
||||||
[1]={{x=1, y=0}, {x=-2, y=0}, {x=1, y=2}, {x=-2, y=-1}},
|
[1]={{x=-2, y= 0}, {x= 1, y= 0}, {x=-2, y=-1}, {x= 1, y= 1}},
|
||||||
[3]={{x=2, y=0}, {x=-1, y=0}, {x=2, y=-1}, {x=-1, y=2}},
|
[3]={{x= 2, y= 0}, {x=-1, y= 0}, {x= 2, y=-1}, {x=-1, y= 1}},
|
||||||
},
|
},
|
||||||
[3]={
|
[3]={
|
||||||
[0]={{x=1, y=0}, {x=-2, y=0}, {x=1, y=2}, {x=-2, y=-1}},
|
[0]={{x=-2, y= 0}, {x= 1, y= 0}, {x=-2, y=-1}, {x= 1, y= 2}},
|
||||||
[1]={{x=0, y=1}, {x=0, y=-1}, {x=0, y=2}, {x=0, y=-2}},
|
[1]={},
|
||||||
[2]={{x=-2, y=0}, {x=1, y=0}, {x=-2, y=1}, {x=1, y=-2}},
|
[2]={{x= 1, y= 0}, {x=-2, y= 0}, {x= 1, y=-2}, {x=-2, y= 1}},
|
||||||
},
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
@@ -148,6 +160,7 @@ end
|
|||||||
|
|
||||||
function SRS:onPieceCreate(piece, grid)
|
function SRS:onPieceCreate(piece, grid)
|
||||||
piece.manipulations = 0
|
piece.manipulations = 0
|
||||||
|
piece.rotations = 0
|
||||||
end
|
end
|
||||||
|
|
||||||
function SRS:onPieceDrop(piece, grid)
|
function SRS:onPieceDrop(piece, grid)
|
||||||
@@ -158,7 +171,7 @@ function SRS:onPieceMove(piece, grid)
|
|||||||
piece.lock_delay = 0 -- move reset
|
piece.lock_delay = 0 -- move reset
|
||||||
if piece:isDropBlocked(grid) then
|
if piece:isDropBlocked(grid) then
|
||||||
piece.manipulations = piece.manipulations + 1
|
piece.manipulations = piece.manipulations + 1
|
||||||
if piece.manipulations >= 8 then
|
if piece.manipulations >= 10 then
|
||||||
piece.locked = true
|
piece.locked = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
@@ -167,11 +180,12 @@ end
|
|||||||
function SRS:onPieceRotate(piece, grid)
|
function SRS:onPieceRotate(piece, grid)
|
||||||
piece.lock_delay = 0 -- rotate reset
|
piece.lock_delay = 0 -- rotate reset
|
||||||
if piece:isDropBlocked(grid) then
|
if piece:isDropBlocked(grid) then
|
||||||
piece.manipulations = piece.manipulations + 1
|
piece.rotations = piece.rotations + 1
|
||||||
if piece.manipulations >= 8 then
|
if piece.rotations >= 8 then
|
||||||
piece.locked = true
|
piece.locked = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function SRS:get180RotationValue() return 3 end
|
||||||
return SRS
|
return SRS
|
||||||
|
|||||||
Reference in New Issue
Block a user