mirror of
https://github.com/SashLilac/cambridge.git
synced 2025-05-13 20:21:25 -05:00
Compare commits
71 Commits
v0.3-beta4
...
v0.3-beta5
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
9f8e9a9778 | ||
|
|
62f9475fa9 | ||
|
|
99d3732d00 | ||
|
|
f5121b62e5 | ||
|
|
cbdbfa6633 | ||
|
|
1b1abc9792 | ||
|
|
894e99e677 | ||
|
|
d4b619da89 | ||
|
|
3766149cb7 | ||
|
|
449ca16bc4 | ||
|
|
71d76e8a6b | ||
|
|
3bdc6e1b2d | ||
|
|
d9b6c85704 | ||
|
|
5ce0686e1a | ||
|
|
3cf496ba98 | ||
|
|
5ddc6ec561 | ||
|
|
b91ffc913b | ||
|
|
ab445ff699 | ||
|
|
7b7a255bf8 | ||
|
|
57721ed35d | ||
|
|
8383d3f445 | ||
|
|
116284f31c | ||
|
|
2189e3a7b8 | ||
|
|
b1d325b714 | ||
|
|
4ab5e3747a | ||
|
|
9761ead48f | ||
|
|
8dedc8a70e | ||
|
|
21769f21c8 | ||
|
|
5cf26b4500 | ||
|
|
4b4a968632 | ||
|
|
e0d98de50d | ||
|
|
4992ea733c | ||
|
|
30ca434027 | ||
|
|
502a50d004 | ||
|
|
36f5287a39 | ||
|
|
a9bbe4a08d | ||
|
|
ee431f5fd8 | ||
|
|
36f2672e06 | ||
|
|
6ecea7edb1 | ||
|
|
dc764b9177 | ||
|
|
5a1494cb5a | ||
|
|
684c4f5b78 | ||
|
|
b568c0fe69 | ||
|
|
2ea75cdfaf | ||
|
|
1f0b43f1b7 | ||
|
|
40bdc5ed99 | ||
|
|
33f2a96ae8 | ||
|
|
846013ce7a | ||
|
|
37c85adc75 | ||
|
|
e7bb44deb4 | ||
|
|
57518dc299 | ||
|
|
0453a3db97 | ||
|
|
b85de17e51 | ||
|
|
163b8f6cc5 | ||
|
|
7250bee619 | ||
|
|
83de216408 | ||
|
|
ba235c8a41 | ||
|
|
ca18d090c9 | ||
|
|
a3a27d2566 | ||
|
|
b15cd9802f | ||
|
|
4c4a818c5c | ||
|
|
716de2814b | ||
|
|
bf19f49323 | ||
|
|
1234e78354 | ||
|
|
9129503d54 | ||
|
|
eae58f11e9 | ||
|
|
3cf5daeb2e | ||
|
|
1dfe68ccff | ||
|
|
8a459b68ba | ||
|
|
cb2b693bcb | ||
|
|
ef6d156d38 |
@@ -7,6 +7,8 @@ Welcome to Cambridge, the next open-source falling-block game engine!
|
||||
|
||||
The project is written and maintained exclusively by [SashLilac](https://github.com/SashLilac), [joezeng](https://github.com/joezeng) and [Oshisaure](https://github.com/oshisaure)!
|
||||
|
||||
The Discord server has been reopened! https://discord.gg/AADZUmgsph
|
||||
|
||||
The game also has a website now with more detail than seen on this README: https://t-sp.in/cambridge
|
||||
|
||||
Credits
|
||||
|
||||
1
conf.lua
1
conf.lua
@@ -6,5 +6,6 @@ function love.conf(t)
|
||||
t.window.title = "Cambridge"
|
||||
t.window.width = 640
|
||||
t.window.height = 480
|
||||
t.window.icon = "res/img/cambridge_icon.png"
|
||||
t.window.vsync = false
|
||||
end
|
||||
|
||||
@@ -87,6 +87,9 @@ function table.contains(table, element)
|
||||
return false
|
||||
end
|
||||
|
||||
function clamp(a, b, c)
|
||||
return math.min(a, math.max(b, c))
|
||||
end
|
||||
function clamp(x, min, max)
|
||||
if max < min then
|
||||
min, max = max, min
|
||||
end
|
||||
return x < min and min or (x > max and max or x)
|
||||
end
|
||||
|
||||
@@ -8,6 +8,42 @@ local strict = false
|
||||
|
||||
local bigint = {}
|
||||
|
||||
local mt = {
|
||||
__add = function(lhs, rhs)
|
||||
return bigint.add(lhs, rhs)
|
||||
end,
|
||||
__unm = function()
|
||||
return bigint.negate(self)
|
||||
end,
|
||||
__sub = function(lhs, rhs)
|
||||
return bigint.subtract(lhs, rhs)
|
||||
end,
|
||||
__mul = function(lhs, rhs)
|
||||
return bigint.multiply(lhs, rhs)
|
||||
end,
|
||||
__div = function(lhs, rhs)
|
||||
return bigint.divide(lhs, rhs)
|
||||
end,
|
||||
__mod = function(lhs, rhs)
|
||||
return bigint.modulus(lhs, rhs)
|
||||
end,
|
||||
__pow = function(lhs, rhs)
|
||||
return bigint.exponentiate(lhs, rhs)
|
||||
end,
|
||||
__tostring = function()
|
||||
return bigint.unserialize(self, "s")
|
||||
end,
|
||||
__eq = function(lhs, rhs)
|
||||
return bigint.compare(lhs, rhs, "==")
|
||||
end,
|
||||
__lt = function(lhs, rhs)
|
||||
return bigint.compare(lhs, rhs, "<")
|
||||
end,
|
||||
__le = function(lhs, rhs)
|
||||
return bigint.compare(lhs, rhs, "<=")
|
||||
end
|
||||
}
|
||||
|
||||
local named_powers = require("libs.bigint.named-powers-of-ten")
|
||||
|
||||
-- Create a new bigint or convert a number or string into a big
|
||||
@@ -28,32 +64,7 @@ function bigint.new(num)
|
||||
return newint
|
||||
end
|
||||
|
||||
setmetatable(self, {
|
||||
__add = function(lhs, rhs)
|
||||
return bigint.add(lhs, rhs)
|
||||
end,
|
||||
__unm = function()
|
||||
return bigint.negate(self)
|
||||
end,
|
||||
__sub = function(lhs, rhs)
|
||||
return bigint.subtract(lhs, rhs)
|
||||
end,
|
||||
__mul = function(lhs, rhs)
|
||||
return bigint.multiply(lhs, rhs)
|
||||
end,
|
||||
__div = function(lhs, rhs)
|
||||
return bigint.divide(lhs, rhs)
|
||||
end,
|
||||
__mod = function(lhs, rhs)
|
||||
return bigint.modulus(lhs, rhs)
|
||||
end,
|
||||
__pow = function(lhs, rhs)
|
||||
return bigint.exponentiate(lhs, rhs)
|
||||
end,
|
||||
__tostring = function()
|
||||
return bigint.unserialize(self, "s")
|
||||
end
|
||||
})
|
||||
setmetatable(self, mt)
|
||||
|
||||
if (num) then
|
||||
local num_string = tostring(num)
|
||||
@@ -73,10 +84,11 @@ end
|
||||
-- forced by supplying "true" as the second argument.
|
||||
function bigint.check(big, force)
|
||||
if (strict or force) then
|
||||
assert(getmetatable(big) == mt, "at least one arg is not a bigint")
|
||||
assert(#big.digits > 0, "bigint is empty")
|
||||
assert(type(big.sign) == "string", "bigint is unsigned")
|
||||
assert(big.sign == "+" or big.sign == "-", "bigint is unsigned")
|
||||
for _, digit in pairs(big.digits) do
|
||||
assert(type(digit) == "number", digit .. " is not a number")
|
||||
assert(type(digit) == "number", "at least one digit is invalid")
|
||||
assert(digit <= 9 and digit >= 0, digit .. " is not between 0 and 9")
|
||||
assert(math.floor(digit) == digit, digit .. " is not an integer")
|
||||
end
|
||||
|
||||
@@ -13,7 +13,31 @@ function loadFromFile(filename)
|
||||
return save_data[1]
|
||||
end
|
||||
|
||||
function initConfig()
|
||||
if not config.das then config.das = 10 end
|
||||
if not config.arr then config.arr = 2 end
|
||||
if not config.dcd then config.dcd = 0 end
|
||||
if not config.sfx_volume then config.sfx_volume = 0.5 end
|
||||
if not config.bgm_volume then config.bgm_volume = 0.5 end
|
||||
|
||||
if config.fullscreen == nil then config.fullscreen = false end
|
||||
if config.secret == nil then config.secret = false end
|
||||
|
||||
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
|
||||
scene = InputConfigScene()
|
||||
else
|
||||
if config.current_mode then current_mode = config.current_mode end
|
||||
if config.current_ruleset then current_ruleset = config.current_ruleset end
|
||||
scene = TitleScene()
|
||||
end
|
||||
end
|
||||
|
||||
function saveConfig()
|
||||
binser.writeFile('config.sav', config)
|
||||
|
||||
1
load/version.lua
Normal file
1
load/version.lua
Normal file
@@ -0,0 +1 @@
|
||||
version = "v0.3-beta5.1"
|
||||
98
main.lua
98
main.lua
@@ -8,11 +8,14 @@ function love.load()
|
||||
require "load.bgm"
|
||||
require "load.save"
|
||||
require "load.bigint"
|
||||
require "load.version"
|
||||
loadSave()
|
||||
require "scene"
|
||||
|
||||
--config["side_next"] = false
|
||||
--config["reverse_rotate"] = true
|
||||
config["fullscreen"] = false
|
||||
--config["das_last_key"] = false
|
||||
--config["fullscreen"] = false
|
||||
|
||||
love.window.setMode(love.graphics.getWidth(), love.graphics.getHeight(), {resizable = true});
|
||||
|
||||
@@ -20,35 +23,16 @@ function love.load()
|
||||
GLOBAL_CANVAS = love.graphics.newCanvas()
|
||||
|
||||
-- init config
|
||||
if not config.das then config.das = 10 end
|
||||
if not config.arr then config.arr = 2 end
|
||||
if not config.dcd then config.dcd = 0 end
|
||||
if not config.sfx_volume then config.sfx_volume = 0.5 end
|
||||
if not config.bgm_volume then config.bgm_volume = 0.5 end
|
||||
|
||||
if config.secret == nil then config.secret = false
|
||||
elseif config.secret == true then playSE("welcome") end
|
||||
initConfig()
|
||||
|
||||
if not config.gamesettings then
|
||||
config.gamesettings = {}
|
||||
config["das_last_key"] = false
|
||||
else
|
||||
config["das_last_key"] = config.gamesettings.das_last_key == 2
|
||||
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
|
||||
scene = InputConfigScene()
|
||||
else
|
||||
if config.current_mode then current_mode = config.current_mode end
|
||||
if config.current_ruleset then current_ruleset = config.current_ruleset end
|
||||
scene = TitleScene()
|
||||
end
|
||||
love.window.setFullscreen(config["fullscreen"])
|
||||
if config.secret then playSE("welcome") end
|
||||
|
||||
-- import custom modules
|
||||
initModules()
|
||||
end
|
||||
|
||||
function initModules()
|
||||
game_modes = {}
|
||||
mode_list = love.filesystem.getDirectoryItems("tetris/modes")
|
||||
for i=1,#mode_list do
|
||||
@@ -69,7 +53,6 @@ function love.load()
|
||||
return tostring(a.name):gsub("%d+",padnum) < tostring(b.name):gsub("%d+",padnum) end)
|
||||
table.sort(rulesets, function(a,b)
|
||||
return tostring(a.name):gsub("%d+",padnum) < tostring(b.name):gsub("%d+",padnum) end)
|
||||
|
||||
end
|
||||
|
||||
local TARGET_FPS = 60
|
||||
@@ -139,6 +122,7 @@ function love.keypressed(key, scancode)
|
||||
-- global hotkeys
|
||||
if scancode == "f4" then
|
||||
config["fullscreen"] = not config["fullscreen"]
|
||||
saveConfig()
|
||||
love.window.setFullscreen(config["fullscreen"])
|
||||
elseif scancode == "f2" and scene.title ~= "Input Config" and scene.title ~= "Game" then
|
||||
scene = InputConfigScene()
|
||||
@@ -153,9 +137,11 @@ function love.keypressed(key, scancode)
|
||||
-- f12 is reserved for saving screenshots
|
||||
elseif scancode == "f12" then
|
||||
local ss_name = os.date("ss/%Y-%m-%d_%H-%M-%S.png")
|
||||
if not love.filesystem.getInfo("ss") then
|
||||
love.filesystem.createDirectory("ss")
|
||||
end
|
||||
local info = love.filesystem.getInfo("ss")
|
||||
if not info or info.type ~= "directory" then
|
||||
love.filesystem.remove("ss")
|
||||
love.filesystem.createDirectory("ss")
|
||||
end
|
||||
print("Saving screenshot as "..ss_name)
|
||||
GLOBAL_CANVAS:newImageData():encode("png", ss_name)
|
||||
-- function keys are reserved
|
||||
@@ -228,13 +214,13 @@ function love.joystickaxis(joystick, axis, value)
|
||||
config.input.joysticks[joystick:getName()].axes and
|
||||
config.input.joysticks[joystick:getName()].axes[axis]
|
||||
then
|
||||
if math.abs(value) >= 0.5 then
|
||||
input_pressed = config.input.joysticks[joystick:getName()].axes[axis][value >= 0.5 and "positive" or "negative"]
|
||||
if math.abs(value) >= 1 then
|
||||
input_pressed = config.input.joysticks[joystick:getName()].axes[axis][value >= 1 and "positive" or "negative"]
|
||||
end
|
||||
positive_released = config.input.joysticks[joystick:getName()].axes[axis].positive
|
||||
negative_released = config.input.joysticks[joystick:getName()].axes[axis].negative
|
||||
end
|
||||
if math.abs(value) >= 0.5 then
|
||||
if math.abs(value) >= 1 then
|
||||
scene:onInputPress({input=input_pressed, type="joyaxis", name=joystick:getName(), axis=axis, value=value})
|
||||
else
|
||||
scene:onInputRelease({input=positive_released, type="joyaxis", name=joystick:getName(), axis=axis, value=value})
|
||||
@@ -242,6 +228,14 @@ function love.joystickaxis(joystick, axis, value)
|
||||
end
|
||||
end
|
||||
|
||||
local last_hat_direction = ""
|
||||
local directions = {
|
||||
["u"] = "up",
|
||||
["d"] = "down",
|
||||
["l"] = "left",
|
||||
["r"] = "right",
|
||||
}
|
||||
|
||||
function love.joystickhat(joystick, hat, direction)
|
||||
local input_pressed = nil
|
||||
local has_hat = false
|
||||
@@ -258,17 +252,47 @@ function love.joystickhat(joystick, hat, direction)
|
||||
has_hat = true
|
||||
end
|
||||
if input_pressed then
|
||||
scene:onInputPress({input=input_pressed, type="joyhat", name=joystick:getName(), hat=hat, direction=direction})
|
||||
for i = 1, #direction do
|
||||
local char = direction:sub(i, i)
|
||||
local _, count = last_hat_direction:gsub(char, char)
|
||||
if count == 0 then
|
||||
scene:onInputPress({input=config.input.joysticks[joystick:getName()].hats[hat][char], type="joyhat", name=joystick:getName(), hat=hat, direction=char})
|
||||
end
|
||||
end
|
||||
for i = 1, #last_hat_direction do
|
||||
local char = last_hat_direction:sub(i, i)
|
||||
local _, count = direction:gsub(char, char)
|
||||
if count == 0 then
|
||||
scene:onInputRelease({input=config.input.joysticks[joystick:getName()].hats[hat][char], type="joyhat", name=joystick:getName(), hat=hat, direction=char})
|
||||
end
|
||||
end
|
||||
last_hat_direction = direction
|
||||
elseif has_hat then
|
||||
for i, direction in ipairs{"d", "l", "ld", "lu", "r", "rd", "ru", "u"} do
|
||||
scene:onInputRelease({input=config.input.joysticks[joystick:getName()].hats[hat][direction], type="joyhat", name=joystick:getName(), hat=hat, direction=direction})
|
||||
end
|
||||
last_hat_direction = ""
|
||||
elseif direction ~= "c" then
|
||||
scene:onInputPress({input=nil, type="joyhat", name=joystick:getName(), hat=hat, direction=direction})
|
||||
for i = 1, #direction do
|
||||
local char = direction:sub(i, i)
|
||||
local _, count = last_hat_direction:gsub(char, char)
|
||||
if count == 0 then
|
||||
scene:onInputPress({input=directions[char], type="joyhat", name=joystick:getName(), hat=hat, direction=char})
|
||||
end
|
||||
end
|
||||
for i = 1, #last_hat_direction do
|
||||
local char = last_hat_direction:sub(i, i)
|
||||
local _, count = direction:gsub(char, char)
|
||||
if count == 0 then
|
||||
scene:onInputRelease({input=directions[char], type="joyhat", name=joystick:getName(), hat=hat, direction=char})
|
||||
end
|
||||
end
|
||||
last_hat_direction = direction
|
||||
else
|
||||
for i, direction in ipairs{"d", "l", "ld", "lu", "r", "rd", "ru", "u"} do
|
||||
scene:onInputRelease({input=nil, type="joyhat", name=joystick:getName(), hat=hat, direction=direction})
|
||||
end
|
||||
last_hat_direction = ""
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
Binary file not shown.
Binary file not shown.
|
Before Width: | Height: | Size: 229 B After Width: | Height: | Size: 153 B |
BIN
res/img/cambridge_icon.png
Normal file
BIN
res/img/cambridge_icon.png
Normal file
Binary file not shown.
|
After Width: | Height: | Size: 2.5 KiB |
@@ -11,6 +11,8 @@ function Scene:onInputRelease() end
|
||||
ExitScene = require "scene.exit"
|
||||
GameScene = require "scene.game"
|
||||
ModeSelectScene = require "scene.mode_select"
|
||||
KeyConfigScene = require "scene.key_config"
|
||||
StickConfigScene = require "scene.stick_config"
|
||||
InputConfigScene = require "scene.input_config"
|
||||
GameConfigScene = require "scene.game_config"
|
||||
TuningScene = require "scene.tuning"
|
||||
|
||||
@@ -30,26 +30,35 @@ function CreditsScene:render()
|
||||
|
||||
love.graphics.setFont(font_3x5_4)
|
||||
love.graphics.print("Cambridge Credits", 320, 500 - self.frames / 2)
|
||||
love.graphics.print("THANK YOU\nFOR PLAYING!", 320, math.max(1500 - self.frames / 2, 240))
|
||||
love.graphics.print("THANK YOU\nFOR PLAYING!", 320, math.max(1770 - self.frames / 2, 240))
|
||||
|
||||
love.graphics.setFont(font_3x5_3)
|
||||
love.graphics.print("Game Developers", 320, 550 - self.frames / 2)
|
||||
love.graphics.print("Project Heads", 320, 640 - self.frames / 2)
|
||||
love.graphics.print("Other Game Developers", 320, 730 - self.frames / 2)
|
||||
love.graphics.print("Special Thanks", 320, 900 - self.frames / 2)
|
||||
love.graphics.print("- SashLilac / SpinTriple", 320, math.max(2000 - self.frames / 2, 320))
|
||||
love.graphics.print("Special Thanks", 320, 950 - self.frames / 2)
|
||||
love.graphics.print("- SashLilac / TS3 / Milla", 320, math.max(1850 - self.frames / 2, 320))
|
||||
|
||||
love.graphics.setFont(font_3x5_2)
|
||||
love.graphics.print("Oshisaure\nJoe Zeng", 320, 590 - self.frames / 2)
|
||||
love.graphics.print("Mizu\nHailey", 320, 680 - self.frames / 2)
|
||||
love.graphics.print("Axel Fox - Multimino\nMine - Tetra Online\nDr Ocelot - Tetra Legends\nFelicity / nightmareci - Shiromino\n2Tie - TGMsim\nPhoenix Flare - Master of Blocks", 320, 770 - self.frames / 2)
|
||||
love.graphics.print(
|
||||
"Axel Fox - Multimino\nMine - Tetra Online\nDr Ocelot - Tetra Legends\n" ..
|
||||
"Felicity / nightmareci - Shiromino\n2Tie - TGMsim\nPhoenix Flare - Master of Blocks\n" ..
|
||||
"RayRay26 - Spirit Drop\nosk - TETR.IO\nMarkGamed7794 - Picoris 2",
|
||||
320, 770 - self.frames / 2
|
||||
)
|
||||
love.graphics.print(
|
||||
"RocketLanterns\nCylinderKnot\nHammrTime\nKirby703\nMattMayuga\nMyPasswordIsWeak\n" ..
|
||||
"Nikki Karissa\noffwo\nsinefuse\nTetro48\nTimmSkiller\nuser74003\nAgentBasey\n" ..
|
||||
"CheeZed_Fish\neightsixfivezero\nEricICX\ngizmo4487\nM1ssing0\nMarkGamed7794\n" ..
|
||||
"pokemonfan1937\nSimon\nstratus\nZaptorZap\nThe Absolute PLUS Discord\nTetra Legends Discord\n" ..
|
||||
"Tetra Online Discord\nMultimino Discord\nCambridge Discord\nAnd to you, the player!",
|
||||
320, 940 - self.frames / 2
|
||||
"CheeZed_Fish\neightsixfivezero\nEricICX\ngizmo4487\nM1ssing0\n" ..
|
||||
"pokemonfan1937\nSimon\nstratus\nZaptorZap\nArchina\nOliver\ncolour_thief\n" ..
|
||||
"Caithness\nkdex\nzid\nsaphie\nSuper302\nAurora\nswitchpalacecorner\nKitaru\n" ..
|
||||
"JBroms\nMany more I definitely missed!\n" ..
|
||||
"The Absolute PLUS Discord\nTetra Legends Discord\nTetra Online Discord\n" ..
|
||||
"Multimino Discord\nHard Drop Discord\nCambridge Discord\n" ..
|
||||
"And to you, the player!",
|
||||
320, 990 - self.frames / 2
|
||||
)
|
||||
end
|
||||
|
||||
|
||||
@@ -7,10 +7,10 @@ require 'load.save'
|
||||
function GameScene:new(game_mode, ruleset, inputs)
|
||||
self.retry_mode = game_mode
|
||||
self.retry_ruleset = ruleset
|
||||
self.secret_inputs = copy(inputs)
|
||||
self.secret_inputs = inputs
|
||||
self.game = game_mode(self.secret_inputs)
|
||||
self.ruleset = ruleset()
|
||||
self.game:initialize(self.ruleset, self.secret_inputs)
|
||||
self.ruleset = ruleset(self.game)
|
||||
self.game:initialize(self.ruleset)
|
||||
self.inputs = {
|
||||
left=false,
|
||||
right=false,
|
||||
@@ -118,15 +118,18 @@ function GameScene:onInputPress(e)
|
||||
highscore_entry = self.game:getHighscoreData()
|
||||
highscore_hash = self.game.hash .. "-" .. self.ruleset.hash
|
||||
submitHighscore(highscore_hash, highscore_entry)
|
||||
self.game:onExit()
|
||||
scene = e.input == "retry" and GameScene(self.retry_mode, self.retry_ruleset, self.secret_inputs) or ModeSelectScene()
|
||||
elseif e.input == "retry" then
|
||||
switchBGM(nil)
|
||||
self.game:onExit()
|
||||
scene = GameScene(self.retry_mode, self.retry_ruleset, self.secret_inputs)
|
||||
elseif e.input == "pause" and not (self.game.game_over or self.game.completed) then
|
||||
self.paused = not self.paused
|
||||
if self.paused then pauseBGM()
|
||||
else resumeBGM() end
|
||||
elseif e.input == "menu_back" then
|
||||
self.game:onExit()
|
||||
scene = ModeSelectScene()
|
||||
elseif e.input and string.sub(e.input, 1, 5) ~= "menu_" then
|
||||
self.inputs[e.input] = true
|
||||
|
||||
@@ -13,7 +13,7 @@ ConfigScene.options = {
|
||||
{"world_reverse", "A Button Rotation", false, {"Left", "Auto", "Right"}},
|
||||
{"spawn_positions", "Spawn Positions", false, {"Per ruleset", "In field", "Out of field"}},
|
||||
{"display_gamemode", "Display Gamemode", false, {"On", "Off"}},
|
||||
{"das_last_key", "DAS Switch", false, {"Default", "Instant"}},
|
||||
{"das_last_key", "DAS Last Key", false, {"Off", "On"}},
|
||||
{"smooth_movement", "Smooth Piece Drop", false, {"On", "Off"}},
|
||||
{"synchroes_allowed", "Synchroes", false, {"Per ruleset", "On", "Off"}},
|
||||
{"diagonal_input", "Diagonal Input", false, {"On", "Off"}},
|
||||
@@ -38,7 +38,6 @@ function ConfigScene:new()
|
||||
end
|
||||
|
||||
function ConfigScene:update()
|
||||
config["das_last_key"] = config.gamesettings.das_last_key == 2
|
||||
self.sfxSlider:update()
|
||||
self.bgmSlider:update()
|
||||
end
|
||||
|
||||
@@ -2,179 +2,65 @@ local ConfigScene = Scene:extend()
|
||||
|
||||
ConfigScene.title = "Input Config"
|
||||
|
||||
require 'load.save'
|
||||
|
||||
local configurable_inputs = {
|
||||
"menu_decide",
|
||||
"menu_back",
|
||||
"left",
|
||||
"right",
|
||||
"up",
|
||||
"down",
|
||||
"rotate_left",
|
||||
"rotate_left2",
|
||||
"rotate_right",
|
||||
"rotate_right2",
|
||||
"rotate_180",
|
||||
"hold",
|
||||
"retry",
|
||||
"pause",
|
||||
local menu_screens = {
|
||||
KeyConfigScene,
|
||||
StickConfigScene
|
||||
}
|
||||
|
||||
local function newSetInputs()
|
||||
local set_inputs = {}
|
||||
for i, input in ipairs(configurable_inputs) do
|
||||
set_inputs[input] = false
|
||||
end
|
||||
return set_inputs
|
||||
end
|
||||
|
||||
function ConfigScene:new()
|
||||
self.input_state = 1
|
||||
self.key = 1
|
||||
self.set_inputs = newSetInputs()
|
||||
self.new_input = {}
|
||||
self.axis_timer = 0
|
||||
|
||||
DiscordRPC:update({
|
||||
details = "In menus",
|
||||
state = "Changing input config",
|
||||
})
|
||||
self.menu_state = 1
|
||||
DiscordRPC:update({
|
||||
details = "In menus",
|
||||
state = "Changing input config",
|
||||
})
|
||||
end
|
||||
|
||||
function ConfigScene:update()
|
||||
end
|
||||
function ConfigScene:update() end
|
||||
|
||||
function ConfigScene:render()
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
love.graphics.draw(
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
love.graphics.draw(
|
||||
backgrounds["input_config"],
|
||||
0, 0, 0,
|
||||
0.5, 0.5
|
||||
)
|
||||
)
|
||||
|
||||
love.graphics.setFont(font_3x5_2)
|
||||
for i, input in ipairs(configurable_inputs) do
|
||||
love.graphics.printf(input, 40, 50 + i * 20, 200, "left")
|
||||
if self.set_inputs[input] then
|
||||
love.graphics.printf(self.set_inputs[input], 240, 50 + i * 20, 300, "left")
|
||||
end
|
||||
end
|
||||
if self.input_state > table.getn(configurable_inputs) then
|
||||
love.graphics.print("press enter to confirm, delete/backspace to retry" .. (config.input and ", escape to cancel" or ""))
|
||||
else
|
||||
love.graphics.print("press " .. (self.key == 2 and "joystick" or "key") .. " input for " .. configurable_inputs[self.input_state] .. ", tab to skip" .. (config.input and ", escape to cancel" or ""), 0, 0)
|
||||
love.graphics.print("function keys (F1, F2, etc.), escape, and tab can't be changed", 0, 20)
|
||||
end
|
||||
love.graphics.setFont(font_3x5_4)
|
||||
love.graphics.print("INPUT CONFIG", 80, 40)
|
||||
|
||||
self.axis_timer = self.axis_timer + 1
|
||||
love.graphics.setFont(font_3x5_2)
|
||||
love.graphics.print("Which controls do you want to configure?", 80, 90)
|
||||
|
||||
love.graphics.setColor(1, 1, 1, 0.5)
|
||||
love.graphics.rectangle("fill", 75, 118 + 50 * self.menu_state, 200, 33)
|
||||
|
||||
love.graphics.setFont(font_3x5_3)
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
for i, screen in pairs(menu_screens) do
|
||||
love.graphics.printf(screen.title, 80, 120 + 50 * i, 200, "left")
|
||||
end
|
||||
end
|
||||
|
||||
local function addJoystick(input, name)
|
||||
if not input.joysticks then
|
||||
input.joysticks = {}
|
||||
end
|
||||
if not input.joysticks[name] then
|
||||
input.joysticks[name] = {}
|
||||
end
|
||||
function ConfigScene:changeOption(rel)
|
||||
local len = table.getn(menu_screens)
|
||||
self.menu_state = (self.menu_state + len + rel - 1) % len + 1
|
||||
end
|
||||
|
||||
function ConfigScene:onInputPress(e)
|
||||
if e.type == "key" then
|
||||
-- function keys, escape, and tab are reserved and can't be remapped
|
||||
if e.scancode == "escape" and config.input then
|
||||
-- cancel only if there was an input config already
|
||||
scene = SettingsScene()
|
||||
elseif self.input_state > table.getn(configurable_inputs) then
|
||||
if e.scancode == "return" then
|
||||
-- save new input, then load next scene
|
||||
config.input = self.new_input
|
||||
saveConfig()
|
||||
scene = TitleScene()
|
||||
elseif e.scancode == "delete" or e.scancode == "backspace" then
|
||||
-- retry
|
||||
self.input_state = 1
|
||||
self.set_inputs = newSetInputs()
|
||||
self.new_input = {}
|
||||
end
|
||||
elseif e.scancode == "tab" then
|
||||
self.set_inputs[configurable_inputs[self.input_state]] =
|
||||
(
|
||||
self.set_inputs[configurable_inputs[self.input_state]] == false
|
||||
and "" or self.set_inputs[configurable_inputs[self.input_state]]
|
||||
) ..
|
||||
(self.key == 2 and " / " or "") .. "skipped"
|
||||
if self.key == 2 then
|
||||
self.input_state = self.input_state + 1
|
||||
self.key = 1
|
||||
else
|
||||
self.key = 2
|
||||
end
|
||||
elseif e.scancode ~= "escape" and self.key == 1 then
|
||||
-- all other keys can be configured
|
||||
if not self.new_input.keys then
|
||||
self.new_input.keys = {}
|
||||
end
|
||||
self.set_inputs[configurable_inputs[self.input_state]] = "key " .. love.keyboard.getKeyFromScancode(e.scancode) .. " (" .. e.scancode .. ")"
|
||||
self.new_input.keys[e.scancode] = configurable_inputs[self.input_state]
|
||||
self.key = 2
|
||||
end
|
||||
elseif string.sub(e.type, 1, 3) == "joy" and self.key == 2 then
|
||||
if self.input_state <= table.getn(configurable_inputs) then
|
||||
if e.type == "joybutton" then
|
||||
addJoystick(self.new_input, e.name)
|
||||
if not self.new_input.joysticks[e.name].buttons then
|
||||
self.new_input.joysticks[e.name].buttons = {}
|
||||
end
|
||||
self.set_inputs[configurable_inputs[self.input_state]] =
|
||||
self.set_inputs[configurable_inputs[self.input_state]] ..
|
||||
" / jbtn " ..
|
||||
e.button ..
|
||||
" " .. string.sub(e.name, 1, 10) .. (string.len(e.name) > 10 and "..." or "")
|
||||
self.new_input.joysticks[e.name].buttons[e.button] = configurable_inputs[self.input_state]
|
||||
self.input_state = self.input_state + 1
|
||||
self.key = 1
|
||||
elseif e.type == "joyaxis" then
|
||||
if (e.axis ~= self.last_axis or self.axis_timer > 30) and math.abs(e.value) >= 1 then
|
||||
addJoystick(self.new_input, e.name)
|
||||
if not self.new_input.joysticks[e.name].axes then
|
||||
self.new_input.joysticks[e.name].axes = {}
|
||||
end
|
||||
if not self.new_input.joysticks[e.name].axes[e.axis] then
|
||||
self.new_input.joysticks[e.name].axes[e.axis] = {}
|
||||
end
|
||||
self.set_inputs[configurable_inputs[self.input_state]] =
|
||||
self.set_inputs[configurable_inputs[self.input_state]] ..
|
||||
" / jaxis " ..
|
||||
(e.value >= 1 and "+" or "-") .. e.axis ..
|
||||
" " .. string.sub(e.name, 1, 10) .. (string.len(e.name) > 10 and "..." or "")
|
||||
self.new_input.joysticks[e.name].axes[e.axis][e.value >= 1 and "positive" or "negative"] = configurable_inputs[self.input_state]
|
||||
self.input_state = self.input_state + 1
|
||||
self.key = 1
|
||||
self.last_axis = e.axis
|
||||
self.axis_timer = 0
|
||||
end
|
||||
elseif e.type == "joyhat" then
|
||||
if e.direction ~= "c" then
|
||||
addJoystick(self.new_input, e.name)
|
||||
if not self.new_input.joysticks[e.name].hats then
|
||||
self.new_input.joysticks[e.name].hats = {}
|
||||
end
|
||||
if not self.new_input.joysticks[e.name].hats[e.hat] then
|
||||
self.new_input.joysticks[e.name].hats[e.hat] = {}
|
||||
end
|
||||
self.set_inputs[configurable_inputs[self.input_state]] =
|
||||
self.set_inputs[configurable_inputs[self.input_state]]
|
||||
" / jhat " ..
|
||||
e.hat .. " " .. e.direction ..
|
||||
" " .. string.sub(e.name, 1, 10) .. (string.len(e.name) > 10 and "..." or "")
|
||||
self.new_input.joysticks[e.name].hats[e.hat][e.direction] = configurable_inputs[self.input_state]
|
||||
self.input_state = self.input_state + 1
|
||||
self.key = 1
|
||||
end
|
||||
end
|
||||
end
|
||||
if e.input == "menu_decide" or e.scancode == "return" then
|
||||
playSE("main_decide")
|
||||
scene = menu_screens[self.menu_state]()
|
||||
elseif e.input == "up" or e.scancode == "up" then
|
||||
self:changeOption(-1)
|
||||
playSE("cursor")
|
||||
elseif e.input == "down" or e.scancode == "down" then
|
||||
self:changeOption(1)
|
||||
playSE("cursor")
|
||||
elseif config.input and (
|
||||
e.input == "menu_back" or e.scancode == "backspace" or e.scancode == "delete"
|
||||
) then
|
||||
scene = SettingsScene()
|
||||
end
|
||||
end
|
||||
|
||||
return ConfigScene
|
||||
return ConfigScene
|
||||
100
scene/key_config.lua
Normal file
100
scene/key_config.lua
Normal file
@@ -0,0 +1,100 @@
|
||||
local KeyConfigScene = Scene:extend()
|
||||
|
||||
KeyConfigScene.title = "Key Config"
|
||||
|
||||
require 'load.save'
|
||||
|
||||
local configurable_inputs = {
|
||||
"menu_decide",
|
||||
"menu_back",
|
||||
"left",
|
||||
"right",
|
||||
"up",
|
||||
"down",
|
||||
"rotate_left",
|
||||
"rotate_left2",
|
||||
"rotate_right",
|
||||
"rotate_right2",
|
||||
"rotate_180",
|
||||
"hold",
|
||||
"retry",
|
||||
"pause",
|
||||
}
|
||||
|
||||
local function newSetInputs()
|
||||
local set_inputs = {}
|
||||
for i, input in ipairs(configurable_inputs) do
|
||||
set_inputs[input] = false
|
||||
end
|
||||
return set_inputs
|
||||
end
|
||||
|
||||
function KeyConfigScene:new()
|
||||
self.input_state = 1
|
||||
self.set_inputs = newSetInputs()
|
||||
self.new_input = {}
|
||||
|
||||
DiscordRPC:update({
|
||||
details = "In menus",
|
||||
state = "Changing key config",
|
||||
})
|
||||
end
|
||||
|
||||
function KeyConfigScene:update()
|
||||
end
|
||||
|
||||
function KeyConfigScene:render()
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
love.graphics.draw(
|
||||
backgrounds["input_config"],
|
||||
0, 0, 0,
|
||||
0.5, 0.5
|
||||
)
|
||||
|
||||
love.graphics.setFont(font_3x5_2)
|
||||
for i, input in ipairs(configurable_inputs) do
|
||||
love.graphics.printf(input, 40, 50 + i * 20, 200, "left")
|
||||
if self.set_inputs[input] then
|
||||
love.graphics.printf(self.set_inputs[input], 240, 50 + i * 20, 300, "left")
|
||||
end
|
||||
end
|
||||
if self.input_state > table.getn(configurable_inputs) then
|
||||
love.graphics.print("press enter to confirm, delete/backspace to retry" .. (config.input and ", escape to cancel" or ""))
|
||||
else
|
||||
love.graphics.print("press key input for " .. configurable_inputs[self.input_state] .. ", tab to skip, escape to cancel", 0, 0)
|
||||
love.graphics.print("function keys (F1, F2, etc.), escape, and tab can't be changed", 0, 20)
|
||||
end
|
||||
end
|
||||
|
||||
function KeyConfigScene:onInputPress(e)
|
||||
if e.type == "key" then
|
||||
-- function keys, escape, and tab are reserved and can't be remapped
|
||||
if e.scancode == "escape" then
|
||||
scene = InputConfigScene()
|
||||
elseif self.input_state > table.getn(configurable_inputs) then
|
||||
if e.scancode == "return" then
|
||||
-- save new input, then load next scene
|
||||
local had_config = config.input ~= nil
|
||||
if not config.input then config.input = {} end
|
||||
config.input.keys = self.new_input
|
||||
saveConfig()
|
||||
scene = had_config and InputConfigScene() or TitleScene()
|
||||
elseif e.scancode == "delete" or e.scancode == "backspace" then
|
||||
-- retry
|
||||
self.input_state = 1
|
||||
self.set_inputs = newSetInputs()
|
||||
self.new_input = {}
|
||||
end
|
||||
elseif e.scancode == "tab" then
|
||||
self.set_inputs[configurable_inputs[self.input_state]] = "skipped"
|
||||
self.input_state = self.input_state + 1
|
||||
elseif e.scancode ~= "escape" then
|
||||
-- all other keys can be configured
|
||||
self.set_inputs[configurable_inputs[self.input_state]] = "key " .. love.keyboard.getKeyFromScancode(e.scancode) .. " (" .. e.scancode .. ")"
|
||||
self.new_input[e.scancode] = configurable_inputs[self.input_state]
|
||||
self.input_state = self.input_state + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return KeyConfigScene
|
||||
152
scene/stick_config.lua
Normal file
152
scene/stick_config.lua
Normal file
@@ -0,0 +1,152 @@
|
||||
local StickConfigScene = Scene:extend()
|
||||
|
||||
StickConfigScene.title = "Joystick Config"
|
||||
|
||||
require 'load.save'
|
||||
|
||||
local configurable_inputs = {
|
||||
"menu_decide",
|
||||
"menu_back",
|
||||
"left",
|
||||
"right",
|
||||
"up",
|
||||
"down",
|
||||
"rotate_left",
|
||||
"rotate_left2",
|
||||
"rotate_right",
|
||||
"rotate_right2",
|
||||
"rotate_180",
|
||||
"hold",
|
||||
"retry",
|
||||
"pause",
|
||||
}
|
||||
|
||||
local function newSetInputs()
|
||||
local set_inputs = {}
|
||||
for i, input in ipairs(configurable_inputs) do
|
||||
set_inputs[input] = false
|
||||
end
|
||||
return set_inputs
|
||||
end
|
||||
|
||||
function StickConfigScene:new()
|
||||
self.input_state = 1
|
||||
self.set_inputs = newSetInputs()
|
||||
self.new_input = {}
|
||||
self.axis_timer = 0
|
||||
|
||||
DiscordRPC:update({
|
||||
details = "In menus",
|
||||
state = "Changing joystick config",
|
||||
})
|
||||
end
|
||||
|
||||
function StickConfigScene:update()
|
||||
end
|
||||
|
||||
function StickConfigScene:render()
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
love.graphics.draw(
|
||||
backgrounds["input_config"],
|
||||
0, 0, 0,
|
||||
0.5, 0.5
|
||||
)
|
||||
|
||||
love.graphics.setFont(font_3x5_2)
|
||||
for i, input in ipairs(configurable_inputs) do
|
||||
love.graphics.printf(input, 40, 50 + i * 20, 200, "left")
|
||||
if self.set_inputs[input] then
|
||||
love.graphics.printf(self.set_inputs[input], 240, 50 + i * 20, 300, "left")
|
||||
end
|
||||
end
|
||||
if self.input_state > table.getn(configurable_inputs) then
|
||||
love.graphics.print("press enter to confirm, delete/backspace to retry" .. (config.input and ", escape to cancel" or ""))
|
||||
else
|
||||
love.graphics.print("press joystick input for " .. configurable_inputs[self.input_state] .. ", tab to skip, escape to cancel", 0, 0)
|
||||
end
|
||||
|
||||
self.axis_timer = self.axis_timer + 1
|
||||
end
|
||||
|
||||
local function addJoystick(input, name)
|
||||
if not input[name] then
|
||||
input[name] = {}
|
||||
end
|
||||
end
|
||||
|
||||
function StickConfigScene:onInputPress(e)
|
||||
if e.type == "key" then
|
||||
-- function keys, escape, and tab are reserved and can't be remapped
|
||||
if e.scancode == "escape" then
|
||||
scene = InputConfigScene()
|
||||
elseif self.input_state > table.getn(configurable_inputs) then
|
||||
if e.scancode == "return" then
|
||||
-- save new input, then load next scene
|
||||
local had_config = config.input ~= nil
|
||||
if not config.input then config.input = {} end
|
||||
config.input.joysticks = self.new_input
|
||||
saveConfig()
|
||||
scene = had_config and InputConfigScene() or TitleScene()
|
||||
elseif e.scancode == "delete" or e.scancode == "backspace" then
|
||||
-- retry
|
||||
self.input_state = 1
|
||||
self.set_inputs = newSetInputs()
|
||||
self.new_input = {}
|
||||
end
|
||||
elseif e.scancode == "tab" then
|
||||
self.set_inputs[configurable_inputs[self.input_state]] = "skipped"
|
||||
self.input_state = self.input_state + 1
|
||||
end
|
||||
elseif string.sub(e.type, 1, 3) == "joy" then
|
||||
if self.input_state <= table.getn(configurable_inputs) then
|
||||
if e.type == "joybutton" then
|
||||
addJoystick(self.new_input, e.name)
|
||||
if not self.new_input[e.name].buttons then
|
||||
self.new_input[e.name].buttons = {}
|
||||
end
|
||||
self.set_inputs[configurable_inputs[self.input_state]] =
|
||||
"jbtn " ..
|
||||
e.button ..
|
||||
" " .. string.sub(e.name, 1, 10) .. (string.len(e.name) > 10 and "..." or "")
|
||||
self.new_input[e.name].buttons[e.button] = configurable_inputs[self.input_state]
|
||||
self.input_state = self.input_state + 1
|
||||
elseif e.type == "joyaxis" then
|
||||
if (e.axis ~= self.last_axis or self.axis_timer > 30) and math.abs(e.value) >= 1 then
|
||||
addJoystick(self.new_input, e.name)
|
||||
if not self.new_input[e.name].axes then
|
||||
self.new_input[e.name].axes = {}
|
||||
end
|
||||
if not self.new_input[e.name].axes[e.axis] then
|
||||
self.new_input[e.name].axes[e.axis] = {}
|
||||
end
|
||||
self.set_inputs[configurable_inputs[self.input_state]] =
|
||||
"jaxis " ..
|
||||
(e.value >= 1 and "+" or "-") .. e.axis ..
|
||||
" " .. string.sub(e.name, 1, 10) .. (string.len(e.name) > 10 and "..." or "")
|
||||
self.new_input[e.name].axes[e.axis][e.value >= 1 and "positive" or "negative"] = configurable_inputs[self.input_state]
|
||||
self.input_state = self.input_state + 1
|
||||
self.last_axis = e.axis
|
||||
self.axis_timer = 0
|
||||
end
|
||||
elseif e.type == "joyhat" then
|
||||
if e.direction ~= "c" then
|
||||
addJoystick(self.new_input, e.name)
|
||||
if not self.new_input[e.name].hats then
|
||||
self.new_input[e.name].hats = {}
|
||||
end
|
||||
if not self.new_input[e.name].hats[e.hat] then
|
||||
self.new_input[e.name].hats[e.hat] = {}
|
||||
end
|
||||
self.set_inputs[configurable_inputs[self.input_state]] =
|
||||
"jhat " ..
|
||||
e.hat .. " " .. e.direction ..
|
||||
" " .. string.sub(e.name, 1, 10) .. (string.len(e.name) > 10 and "..." or "")
|
||||
self.new_input[e.name].hats[e.hat][e.direction] = configurable_inputs[self.input_state]
|
||||
self.input_state = self.input_state + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
return StickConfigScene
|
||||
@@ -83,6 +83,7 @@ function TitleScene:render()
|
||||
love.graphics.printf(screen.title, 40, 280 + 20 * i, 120, "left")
|
||||
end
|
||||
|
||||
love.graphics.printf(version, 0, 460, love.graphics.getWidth() - 5, "right")
|
||||
end
|
||||
|
||||
function TitleScene:changeOption(rel)
|
||||
|
||||
@@ -400,11 +400,10 @@ function Grid:draw()
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
love.graphics.draw(blocks[self.grid[y][x].skin]["F"], 48+x*16, y*16)
|
||||
else
|
||||
if self.grid[y][x].skin == "bone" then
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
elseif self.grid[y][x].colour == "X" then
|
||||
if self.grid[y][x].colour == "X" then
|
||||
love.graphics.setColor(0, 0, 0, 0)
|
||||
--love.graphics.setColor(0.5, 0.5, 0.5, 1 - self.grid_age[y][x] / 15)
|
||||
elseif self.grid[y][x].skin == "bone" then
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
else
|
||||
love.graphics.setColor(0.5, 0.5, 0.5, 1)
|
||||
end
|
||||
@@ -435,12 +434,6 @@ end
|
||||
function Grid:drawOutline()
|
||||
for y = 5, self.height do
|
||||
for x = 1, self.width do
|
||||
--[[
|
||||
if self.grid[y][x].colour == "X" then
|
||||
love.graphics.setColor(0.5, 0.5, 0.5, 1 - self.grid_age[y][x] / 15)
|
||||
love.graphics.draw(blocks[self.grid[y][x].skin][self.grid[y][x].colour], 48+x*16, y*16)
|
||||
end
|
||||
]]
|
||||
if self.grid[y][x] ~= empty and self.grid[y][x].colour ~= "X" then
|
||||
love.graphics.setColor(0.8, 0.8, 0.8, 1)
|
||||
love.graphics.setLineWidth(1)
|
||||
@@ -470,7 +463,6 @@ function Grid:drawInvisible(opacity_function, garbage_opacity_function, lock_fla
|
||||
if self.grid[y][x] ~= empty then
|
||||
if self.grid[y][x].colour == "X" then
|
||||
opacity = 0
|
||||
--opacity = 1 - self.grid_age[y][x] / 15
|
||||
elseif garbage_opacity_function and self.grid[y][x].colour == "A" then
|
||||
opacity = garbage_opacity_function(self.grid_age[y][x])
|
||||
else
|
||||
@@ -518,7 +510,6 @@ function Grid:drawCustom(colour_function, gamestate)
|
||||
local R, G, B, A, outline = colour_function(gamestate, block, x, y, self.grid_age[y][x])
|
||||
if self.grid[y][x].colour == "X" then
|
||||
A = 0
|
||||
--A = 1 - self.grid_age[y][x] / 15
|
||||
end
|
||||
love.graphics.setColor(R, G, B, A)
|
||||
love.graphics.draw(blocks[self.grid[y][x].skin][self.grid[y][x].colour], 48+x*16, y*16)
|
||||
|
||||
@@ -126,14 +126,27 @@ function Piece:addGravity(gravity, grid, classic_lock)
|
||||
self.gravity = 0
|
||||
self.lock_delay = self.lock_delay + 1
|
||||
end
|
||||
else
|
||||
local dropped_squares = math.floor(new_gravity)
|
||||
local new_frac_gravity = new_gravity - dropped_squares
|
||||
self.gravity = new_frac_gravity
|
||||
self:dropSquares(dropped_squares, grid)
|
||||
if self:isDropBlocked(grid) then
|
||||
playSE("bottom")
|
||||
elseif not (
|
||||
self:isMoveBlocked(grid, { x=0, y=-1 }) and gravity < 0
|
||||
) then
|
||||
local dropped_squares = math.floor(math.abs(new_gravity))
|
||||
if gravity >= 0 then
|
||||
local new_frac_gravity = new_gravity - dropped_squares
|
||||
self.gravity = new_frac_gravity
|
||||
self:dropSquares(dropped_squares, grid)
|
||||
if self:isDropBlocked(grid) then
|
||||
playSE("bottom")
|
||||
end
|
||||
else
|
||||
local new_frac_gravity = new_gravity + dropped_squares
|
||||
self.gravity = new_frac_gravity
|
||||
self:moveInGrid({ x=0, y=-1 }, dropped_squares, grid)
|
||||
if self:isMoveBlocked(grid, { x=0, y=-1 }) then
|
||||
playSE("bottom")
|
||||
end
|
||||
end
|
||||
else
|
||||
self.gravity = 0
|
||||
end
|
||||
return self
|
||||
end
|
||||
|
||||
@@ -1,138 +1,24 @@
|
||||
require 'funcs'
|
||||
|
||||
local GameMode = require 'tetris.modes.gamemode'
|
||||
local Piece = require 'tetris.components.piece'
|
||||
local MarathonA2Game = require 'tetris.modes.marathon_a2'
|
||||
|
||||
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
||||
local BigA2Game = MarathonA2Game:extend()
|
||||
|
||||
local MarathonA2Game = GameMode:extend()
|
||||
BigA2Game.name = "Big A2"
|
||||
BigA2Game.hash = "BigA2"
|
||||
BigA2Game.tagline = "Big blocks in the most celebrated TGM mode!"
|
||||
|
||||
MarathonA2Game.name = "Big A2"
|
||||
MarathonA2Game.hash = "BigA2"
|
||||
MarathonA2Game.tagline = "The points don't matter! Can you reach the invisible roll? Big mode too!"
|
||||
|
||||
|
||||
|
||||
|
||||
function MarathonA2Game:new()
|
||||
self.super:new()
|
||||
function BigA2Game:new()
|
||||
BigA2Game.super:new()
|
||||
self.big_mode = true
|
||||
self.roll_frames = 0
|
||||
self.combo = 1
|
||||
|
||||
self.grade = 0
|
||||
self.grade_points = 0
|
||||
self.grade_point_decay_counter = 0
|
||||
|
||||
self.randomizer = History6RollsRandomizer()
|
||||
|
||||
self.lock_drop = false
|
||||
self.lock_hard_drop = false
|
||||
self.enable_hold = false
|
||||
self.next_queue_length = 1
|
||||
end
|
||||
|
||||
function MarathonA2Game:getARE()
|
||||
if self.level < 700 then return 27
|
||||
elseif self.level < 800 then return 18
|
||||
else return 14 end
|
||||
end
|
||||
|
||||
function MarathonA2Game:getLineARE()
|
||||
if self.level < 600 then return 27
|
||||
elseif self.level < 700 then return 18
|
||||
elseif self.level < 800 then return 14
|
||||
else return 8 end
|
||||
end
|
||||
|
||||
function MarathonA2Game:getDasLimit()
|
||||
if self.level < 500 then return 15
|
||||
elseif self.level < 900 then return 9
|
||||
else return 7 end
|
||||
end
|
||||
|
||||
function MarathonA2Game:getLineClearDelay()
|
||||
if self.level < 500 then return 40
|
||||
elseif self.level < 600 then return 25
|
||||
elseif self.level < 700 then return 16
|
||||
elseif self.level < 800 then return 12
|
||||
else return 6 end
|
||||
end
|
||||
|
||||
function MarathonA2Game:getLockDelay()
|
||||
if self.level < 900 then return 30
|
||||
else return 17 end
|
||||
end
|
||||
|
||||
function MarathonA2Game:getGravity()
|
||||
if (self.level < 30) then return 4/256
|
||||
elseif (self.level < 35) then return 6/256
|
||||
elseif (self.level < 40) then return 8/256
|
||||
elseif (self.level < 50) then return 10/256
|
||||
elseif (self.level < 60) then return 12/256
|
||||
elseif (self.level < 70) then return 16/256
|
||||
elseif (self.level < 80) then return 32/256
|
||||
elseif (self.level < 90) then return 48/256
|
||||
elseif (self.level < 100) then return 64/256
|
||||
elseif (self.level < 120) then return 80/256
|
||||
elseif (self.level < 140) then return 96/256
|
||||
elseif (self.level < 160) then return 112/256
|
||||
elseif (self.level < 170) then return 128/256
|
||||
elseif (self.level < 200) then return 144/256
|
||||
elseif (self.level < 220) then return 4/256
|
||||
elseif (self.level < 230) then return 32/256
|
||||
elseif (self.level < 233) then return 64/256
|
||||
elseif (self.level < 236) then return 96/256
|
||||
elseif (self.level < 239) then return 128/256
|
||||
elseif (self.level < 243) then return 160/256
|
||||
elseif (self.level < 247) then return 192/256
|
||||
elseif (self.level < 251) then return 224/256
|
||||
elseif (self.level < 300) then return 1
|
||||
elseif (self.level < 330) then return 2
|
||||
elseif (self.level < 360) then return 3
|
||||
elseif (self.level < 400) then return 4
|
||||
elseif (self.level < 420) then return 5
|
||||
elseif (self.level < 450) then return 4
|
||||
elseif (self.level < 500) then return 3
|
||||
else return 20
|
||||
end
|
||||
end
|
||||
|
||||
function MarathonA2Game:advanceOneFrame()
|
||||
if self.clear then
|
||||
self.roll_frames = self.roll_frames + 1
|
||||
if self.roll_frames < 0 then return false end
|
||||
if self.roll_frames > 3694 then
|
||||
self.completed = true
|
||||
end
|
||||
elseif self.ready_frames == 0 then
|
||||
self.frames = self.frames + 1
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function MarathonA2Game:onPieceEnter()
|
||||
if (self.level % 100 ~= 99 and self.level ~= 998) and not self.clear and self.frames ~= 0 then
|
||||
self.level = self.level + 1
|
||||
end
|
||||
end
|
||||
|
||||
function MarathonA2Game:onLineClear(cleared_row_count)
|
||||
cleared_row_count = cleared_row_count / 2
|
||||
self.level = math.min(self.level + cleared_row_count, 999)
|
||||
if self.level == 999 and not self.clear then
|
||||
self.clear = true
|
||||
self.grid:clear()
|
||||
self.roll_frames = -150
|
||||
end
|
||||
self.lock_drop = self.level >= 900
|
||||
self.lock_hard_drop = self.level >= 900
|
||||
end
|
||||
|
||||
function MarathonA2Game:updateScore(level, drop_bonus, cleared_lines)
|
||||
function BigA2Game:updateScore(level, drop_bonus, cleared_lines)
|
||||
cleared_lines = cleared_lines / 2
|
||||
if not self.clear then
|
||||
cleared_lines = cleared_lines / 2
|
||||
self:updateGrade(cleared_lines)
|
||||
if cleared_lines >= 4 then
|
||||
self.tetris_count = self.tetris_count + 1
|
||||
end
|
||||
if self.grid:checkForBravo(cleared_lines) then self.bravo = 4 else self.bravo = 1 end
|
||||
if cleared_lines > 0 then
|
||||
self.combo = self.combo + (cleared_lines - 1) * 2
|
||||
@@ -144,164 +30,21 @@ function MarathonA2Game:updateScore(level, drop_bonus, cleared_lines)
|
||||
self.combo = 1
|
||||
end
|
||||
self.drop_bonus = 0
|
||||
else self.lines = self.lines + cleared_lines end
|
||||
end
|
||||
|
||||
function BigA2Game:onLineClear(cleared_row_count)
|
||||
cleared_row_count = cleared_row_count / 2
|
||||
self:updateSectionTimes(self.level, self.level + cleared_row_count)
|
||||
self.level = math.min(self.level + cleared_row_count, 999)
|
||||
if self.level == 999 and not self.clear then
|
||||
self.clear = true
|
||||
self.grid:clear()
|
||||
if self:qualifiesForMRoll() then self.grade = 32 end
|
||||
self.roll_frames = -150
|
||||
end
|
||||
self.lock_drop = self.level >= 900
|
||||
self.lock_hard_drop = self.level >= 900
|
||||
end
|
||||
|
||||
local grade_point_bonuses = {
|
||||
{10, 20, 40, 50},
|
||||
{10, 20, 30, 40},
|
||||
{10, 20, 30, 40},
|
||||
{10, 15, 30, 40},
|
||||
{10, 15, 20, 40},
|
||||
{5, 15, 20, 30},
|
||||
{5, 10, 20, 30},
|
||||
{5, 10, 15, 30},
|
||||
{5, 10, 15, 30},
|
||||
{5, 10, 15, 30},
|
||||
{2, 12, 13, 30},
|
||||
{2, 12, 13, 30},
|
||||
{2, 12, 13, 30},
|
||||
{2, 12, 13, 30},
|
||||
{2, 12, 13, 30},
|
||||
{2, 12, 13, 30},
|
||||
{2, 12, 13, 30},
|
||||
{2, 12, 13, 30},
|
||||
{2, 12, 13, 30},
|
||||
{2, 12, 13, 30},
|
||||
{2, 12, 13, 30},
|
||||
{2, 12, 13, 30},
|
||||
{2, 12, 13, 30},
|
||||
{2, 12, 13, 30},
|
||||
{2, 12, 13, 30},
|
||||
{2, 12, 13, 30},
|
||||
{2, 12, 13, 30},
|
||||
{2, 12, 13, 30},
|
||||
{2, 12, 13, 30},
|
||||
{2, 12, 13, 30},
|
||||
{2, 12, 13, 30},
|
||||
{2, 12, 13, 30},
|
||||
}
|
||||
|
||||
local grade_point_decays = {
|
||||
125, 80, 80, 50, 45, 45, 45,
|
||||
40, 40, 40, 40, 40, 30, 30, 30,
|
||||
20, 20, 20, 20, 20,
|
||||
15, 15, 15, 15, 15, 15, 15, 15, 15, 15,
|
||||
10, 10
|
||||
}
|
||||
|
||||
local combo_multipliers = {
|
||||
{1.0, 1.0, 1.0, 1.0},
|
||||
{1.2, 1.4, 1.5, 1.0},
|
||||
{1.2, 1.5, 1.8, 1.0},
|
||||
{1.4, 1.6, 2.0, 1.0},
|
||||
{1.4, 1.7, 2.2, 1.0},
|
||||
{1.4, 1.8, 2.3, 1.0},
|
||||
{1.4, 1.9, 2.4, 1.0},
|
||||
{1.5, 2.0, 2.5, 1.0},
|
||||
{1.5, 2.1, 2.6, 1.0},
|
||||
{2.0, 2.5, 3.0, 1.0},
|
||||
}
|
||||
|
||||
local grade_conversion = {
|
||||
[0] = 0,
|
||||
1, 2, 3, 4, 5, 5, 6, 6, 7, 7,
|
||||
7, 8, 8, 8, 9, 9, 9, 10, 11, 12,
|
||||
12, 12, 13, 13, 14, 14, 15, 15, 16, 16,
|
||||
17
|
||||
}
|
||||
|
||||
function MarathonA2Game:updateGrade(cleared_lines)
|
||||
if self.clear then return end
|
||||
if cleared_lines == 0 then
|
||||
self.grade_point_decay_counter = self.grade_point_decay_counter + 1
|
||||
if self.grade_point_decay_counter >= grade_point_decays[self.grade + 1] then
|
||||
self.grade_point_decay_counter = 0
|
||||
self.grade_points = math.max(0, self.grade_points - 1)
|
||||
end
|
||||
else
|
||||
self.grade_points = self.grade_points + (
|
||||
math.ceil(
|
||||
grade_point_bonuses[self.grade + 1][cleared_lines] *
|
||||
combo_multipliers[math.min(self.combo, 10)][cleared_lines]
|
||||
) * (1 + math.floor(self.level / 250))
|
||||
)
|
||||
if self.grade_points >= 100 and self.grade < 31 then
|
||||
self.grade_points = 0
|
||||
self.grade = self.grade + 1
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function MarathonA2Game:getLetterGrade()
|
||||
local grade = grade_conversion[self.grade]
|
||||
if grade < 9 then
|
||||
return tostring(9 - grade)
|
||||
elseif grade < 18 then
|
||||
return "S" .. tostring(grade - 8)
|
||||
end
|
||||
end
|
||||
|
||||
MarathonA2Game.rollOpacityFunction = function(age)
|
||||
if age < 240 then return 1
|
||||
elseif age > 300 then return 0
|
||||
else return 1 - (age - 240) / 60 end
|
||||
end
|
||||
|
||||
function MarathonA2Game:drawGrid(ruleset)
|
||||
if self.clear and not (self.completed or self.game_over) then
|
||||
self.grid:drawInvisible(self.rollOpacityFunction, nil, false)
|
||||
else
|
||||
self.grid:draw()
|
||||
if self.piece ~= nil and self.level < 100 then
|
||||
self:drawGhostPiece(ruleset)
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function MarathonA2Game:drawScoringInfo()
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
|
||||
love.graphics.setFont(font_3x5_2)
|
||||
love.graphics.print(
|
||||
self.das.direction .. " " ..
|
||||
self.das.frames .. " " ..
|
||||
strTrueValues(self.prev_inputs)
|
||||
)
|
||||
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
||||
love.graphics.printf("GRADE", 240, 120, 40, "left")
|
||||
love.graphics.printf("SCORE", 240, 200, 40, "left")
|
||||
love.graphics.printf("LEVEL", 240, 320, 40, "left")
|
||||
|
||||
love.graphics.setFont(font_3x5_3)
|
||||
if self.roll_frames > 3694 then love.graphics.setColor(1, 0.5, 0, 1)
|
||||
elseif self.clear then love.graphics.setColor(0, 1, 0, 1) end
|
||||
love.graphics.printf(self:getLetterGrade(), 240, 140, 90, "left")
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
love.graphics.printf(self.score, 240, 220, 90, "left")
|
||||
love.graphics.printf(self.level, 240, 340, 40, "right")
|
||||
love.graphics.printf(self:getSectionEndLevel(), 240, 370, 40, "right")
|
||||
|
||||
love.graphics.setFont(font_8x11)
|
||||
love.graphics.printf(formatTime(self.frames), 64, 420, 160, "center")
|
||||
end
|
||||
|
||||
function MarathonA2Game:getHighscoreData()
|
||||
return {
|
||||
grade = grade_conversion[self.grade],
|
||||
score = self.score,
|
||||
level = self.level,
|
||||
frames = self.frames,
|
||||
}
|
||||
end
|
||||
|
||||
function MarathonA2Game:getSectionEndLevel()
|
||||
if self.level >= 900 then return 999
|
||||
else return math.floor(self.level / 100 + 1) * 100 end
|
||||
end
|
||||
|
||||
function MarathonA2Game:getBackground()
|
||||
return math.floor(self.level / 100)
|
||||
end
|
||||
|
||||
return MarathonA2Game
|
||||
return BigA2Game
|
||||
@@ -65,6 +65,7 @@ function GameMode:new(secret_inputs)
|
||||
self.lock_on_soft_drop = false
|
||||
self.lock_on_hard_drop = false
|
||||
self.cleared_block_table = {}
|
||||
self.last_lcd = 0
|
||||
self.used_randomizer = nil
|
||||
self.hold_queue = nil
|
||||
self.held = false
|
||||
@@ -95,9 +96,8 @@ function GameMode:getSkin()
|
||||
return "2tie"
|
||||
end
|
||||
|
||||
function GameMode:initialize(ruleset, secret_inputs)
|
||||
function GameMode:initialize(ruleset)
|
||||
-- generate next queue
|
||||
self:new(secret_inputs)
|
||||
self.used_randomizer = (
|
||||
ruleset.pieces == self.randomizer.possible_pieces and
|
||||
self.randomizer or
|
||||
@@ -107,6 +107,7 @@ function GameMode:initialize(ruleset, secret_inputs)
|
||||
BagRandomizer(ruleset.pieces)
|
||||
)
|
||||
)
|
||||
self.ruleset = ruleset
|
||||
for i = 1, math.max(self.next_queue_length, 1) do
|
||||
table.insert(self.next_queue, self:getNextPiece(ruleset))
|
||||
end
|
||||
@@ -136,31 +137,13 @@ function GameMode:update(inputs, ruleset)
|
||||
self:chargeDAS(inputs, self:getDasLimit(), self:getARR())
|
||||
|
||||
-- set attempt flags
|
||||
if inputs["left"] or inputs["right"] then
|
||||
self:onAttemptPieceMove(self.piece, self.grid)
|
||||
if self.immobile_spin_bonus and self.piece ~= nil then
|
||||
if not self.piece:isMoveBlocked(self.grid, { x=-1, y=0 }) and
|
||||
not self.piece:isMoveBlocked(self.grid, { x=1, y=0 }) then
|
||||
self.piece.spin = false
|
||||
end
|
||||
end
|
||||
end
|
||||
if
|
||||
if inputs["left"] or inputs["right"] then self:onAttemptPieceMove(self.piece, self.grid) end
|
||||
if (
|
||||
inputs["rotate_left"] or inputs["rotate_right"] or
|
||||
inputs["rotate_left2"] or inputs["rotate_right2"] or
|
||||
inputs["rotate_180"]
|
||||
then
|
||||
) then
|
||||
self:onAttemptPieceRotate(self.piece, self.grid)
|
||||
if self.immobile_spin_bonus and self.piece ~= nil then
|
||||
if self.piece:isDropBlocked(self.grid) and
|
||||
self.piece:isMoveBlocked(self.grid, { x=-1, y=0 }) and
|
||||
self.piece:isMoveBlocked(self.grid, { x=1, y=0 }) and
|
||||
self.piece:isMoveBlocked(self.grid, { x=0, y=-1 }) then
|
||||
self.piece.spin = true
|
||||
else
|
||||
self.piece.spin = false
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
if self.piece == nil then
|
||||
@@ -219,9 +202,18 @@ function GameMode:update(inputs, ruleset)
|
||||
self:dasCut()
|
||||
end
|
||||
|
||||
if (piece_dx ~= 0) then self:onPieceMove(self.piece, self.grid) end
|
||||
if (piece_drot ~= 0) then self:onPieceRotate(self.piece, self.grid) end
|
||||
if (piece_dy ~= 0) then self:onPieceDrop(self.piece, self.grid) end
|
||||
if (piece_dx ~= 0) then
|
||||
self.piece.last_rotated = false
|
||||
self:onPieceMove(self.piece, self.grid, piece_dx)
|
||||
end
|
||||
if (piece_drot ~= 0) then
|
||||
self.piece.last_rotated = true
|
||||
self:onPieceRotate(self.piece, self.grid, piece_drot)
|
||||
end
|
||||
if (piece_dy ~= 0) then
|
||||
self.piece.last_rotated = false
|
||||
self:onPieceDrop(self.piece, self.grid, piece_dy)
|
||||
end
|
||||
|
||||
if inputs["up"] == true and
|
||||
self.piece:isDropBlocked(self.grid) and
|
||||
@@ -234,7 +226,12 @@ function GameMode:update(inputs, ruleset)
|
||||
end
|
||||
|
||||
if inputs["down"] == true then
|
||||
self:onSoftDrop(piece_dy)
|
||||
if not (
|
||||
self.piece:isDropBlocked(self.grid) and
|
||||
piece_drot ~= 0
|
||||
) then
|
||||
self:onSoftDrop(piece_dy)
|
||||
end
|
||||
if self.piece:isDropBlocked(self.grid) and
|
||||
not self.drop_locked and
|
||||
self.lock_on_soft_drop
|
||||
@@ -244,7 +241,19 @@ function GameMode:update(inputs, ruleset)
|
||||
end
|
||||
|
||||
if self.piece.locked == true then
|
||||
-- spin detection, immobile only for now
|
||||
if self.immobile_spin_bonus and (
|
||||
self.piece:isDropBlocked(self.grid) and
|
||||
self.piece:isMoveBlocked(self.grid, { x=-1, y=0 }) and
|
||||
self.piece:isMoveBlocked(self.grid, { x=1, y=0 }) and
|
||||
self.piece:isMoveBlocked(self.grid, { x=0, y=-1 })
|
||||
) then
|
||||
self.piece.spin = true
|
||||
end
|
||||
|
||||
self.grid:applyPiece(self.piece)
|
||||
|
||||
-- mark squares (can be overridden)
|
||||
if self.square_mode then
|
||||
self.squares = self.squares + self.grid:markSquares()
|
||||
end
|
||||
@@ -262,6 +271,7 @@ function GameMode:update(inputs, ruleset)
|
||||
if cleared_row_count > 0 then
|
||||
playSE("erase")
|
||||
self.lcd = self:getLineClearDelay()
|
||||
self.last_lcd = self.lcd
|
||||
self.are = (
|
||||
ruleset.are and self:getLineARE() or 0
|
||||
)
|
||||
@@ -299,9 +309,9 @@ end
|
||||
function GameMode:whilePieceActive() end
|
||||
function GameMode:onAttemptPieceMove(piece, grid) end
|
||||
function GameMode:onAttemptPieceRotate(piece, grid) end
|
||||
function GameMode:onPieceMove(piece, grid) end
|
||||
function GameMode:onPieceRotate(piece, grid) end
|
||||
function GameMode:onPieceDrop(piece, grid) end
|
||||
function GameMode:onPieceMove(piece, grid, dx) end
|
||||
function GameMode:onPieceRotate(piece, grid, drot) end
|
||||
function GameMode:onPieceDrop(piece, grid, dy) end
|
||||
function GameMode:onPieceLock(piece, cleared_row_count)
|
||||
playSE("lock")
|
||||
end
|
||||
@@ -333,6 +343,8 @@ function GameMode:onGameComplete()
|
||||
self:onGameOver()
|
||||
end
|
||||
|
||||
function GameMode:onExit() end
|
||||
|
||||
-- DAS functions
|
||||
|
||||
function GameMode:startRightDAS()
|
||||
@@ -373,7 +385,7 @@ function GameMode:stopDAS()
|
||||
end
|
||||
|
||||
function GameMode:chargeDAS(inputs)
|
||||
if config["das_last_key"] then
|
||||
if config.gamesettings.das_last_key == 2 then
|
||||
if inputs["right"] == true and self.das.direction ~= "right" and not self.prev_inputs["right"] then
|
||||
self:startRightDAS()
|
||||
elseif inputs["left"] == true and self.das.direction ~= "left" and not self.prev_inputs["left"] then
|
||||
@@ -471,7 +483,7 @@ end
|
||||
|
||||
function GameMode:initializeOrHold(inputs, ruleset)
|
||||
if (
|
||||
self.frames == 0 or (ruleset.are and self:getARE() ~= 0) and self.ihs or false
|
||||
(self.frames == 0 or (ruleset.are and self:getARE() ~= 0)) and self.ihs or false
|
||||
) and self.enable_hold and inputs["hold"] == true then
|
||||
self:hold(inputs, ruleset, true)
|
||||
else
|
||||
@@ -517,25 +529,42 @@ function GameMode:initializeNextPiece(inputs, ruleset, piece_data, generate_next
|
||||
self.lock_drop, self.lock_hard_drop, self.big_mode,
|
||||
(
|
||||
self.frames == 0 or (ruleset.are and self:getARE() ~= 0)
|
||||
) and self.irs or false,
|
||||
self.buffer_hard_drop, self.buffer_soft_drop,
|
||||
self.lock_on_hard_drop, self.lock_on_soft_drop
|
||||
) and self.irs or false
|
||||
)
|
||||
if self.buffer_hard_drop then
|
||||
if config.gamesettings.buffer_lock == 1 then
|
||||
self.piece:dropToBottom(self.grid)
|
||||
if self.lock_on_hard_drop then self.piece.locked = true end
|
||||
end
|
||||
local above_field = (
|
||||
(config.gamesettings.spawn_positions == 1 and
|
||||
ruleset.spawn_above_field) or
|
||||
config.gamesettings.spawn_positions == 3
|
||||
)
|
||||
self:onHardDrop(self.piece.position.y - (
|
||||
self.piece.big and
|
||||
ruleset.big_spawn_positions[self.piece.shape].y or
|
||||
ruleset.spawn_positions[self.piece.shape].y) +
|
||||
(above_field and ruleset:getAboveFieldOffset(
|
||||
piece_data.shape, piece_data.orientation
|
||||
) or 0)
|
||||
)
|
||||
self.buffer_hard_drop = false
|
||||
end
|
||||
if self.buffer_soft_drop then
|
||||
if (
|
||||
self.lock_on_soft_drop and
|
||||
self.piece:isDropBlocked(self.grid) and
|
||||
config.gamesettings.buffer_lock == 1
|
||||
) then
|
||||
self.piece.locked = true
|
||||
end
|
||||
self.buffer_soft_drop = false
|
||||
end
|
||||
if self.piece:isDropBlocked(self.grid) and
|
||||
self.grid:canPlacePiece(self.piece) then
|
||||
playSE("bottom")
|
||||
end
|
||||
if self.buffer_hard_drop then
|
||||
self.buffer_hard_drop = false
|
||||
self:onHardDrop(self.piece.position.y - (
|
||||
self.big_mode and
|
||||
ruleset.big_spawn_positions[self.piece.shape].y or
|
||||
ruleset.spawn_positions[self.piece.shape].y)
|
||||
)
|
||||
end
|
||||
if self.buffer_soft_drop then
|
||||
self.buffer_soft_drop = false
|
||||
end
|
||||
if self.lock_drop or (
|
||||
not ruleset.are or self:getARE() == 0
|
||||
) then
|
||||
@@ -566,7 +595,7 @@ end
|
||||
function GameMode:animation(x, y, skin, colour)
|
||||
return {
|
||||
1, 1, 1,
|
||||
-0.25 + 1.25 * (self.lcd / self:getLineClearDelay()),
|
||||
-0.25 + 1.25 * (self.lcd / self.last_lcd),
|
||||
skin, colour,
|
||||
48 + x * 16, y * 16
|
||||
}
|
||||
@@ -582,7 +611,7 @@ function GameMode:drawLineClearAnimation()
|
||||
function animation(x, y, skin, colour)
|
||||
return {
|
||||
1, 1, 1,
|
||||
-0.25 + 1.25 * (self.lcd / self:getLineClearDelay()),
|
||||
-0.25 + 1.25 * (self.lcd / self.last_lcd),
|
||||
skin, colour,
|
||||
48 + x * 16, y * 16
|
||||
}
|
||||
@@ -606,7 +635,7 @@ function GameMode:drawLineClearAnimation()
|
||||
function animation(x, y, skin, colour)
|
||||
local p = 0.5
|
||||
local l = (
|
||||
(self:getLineClearDelay() - self.lcd) / self:getLineClearDelay()
|
||||
(self.last_lcd - self.lcd) / self.last_lcd
|
||||
)
|
||||
local dx = l * (x - (1 + self.grid.width) / 2)
|
||||
local dy = l * (y - (1 + self.grid.height) / 2)
|
||||
@@ -656,11 +685,16 @@ function GameMode:drawGhostPiece(ruleset)
|
||||
end
|
||||
|
||||
function GameMode:drawNextQueue(ruleset)
|
||||
local colourscheme = ({ruleset.colourscheme, ColourSchemes.Arika, ColourSchemes.TTC})[config.gamesettings.piece_colour]
|
||||
local colourscheme
|
||||
if ruleset.pieces == 7 then
|
||||
colourscheme = ({ruleset.colourscheme, ColourSchemes.Arika, ColourSchemes.TTC})[config.gamesettings.piece_colour]
|
||||
else
|
||||
colourscheme = ruleset.colourscheme
|
||||
end
|
||||
function drawPiece(piece, skin, offsets, pos_x, pos_y)
|
||||
for index, offset in pairs(offsets) do
|
||||
local x = offset.x + ruleset.draw_offsets[piece].x + ruleset.spawn_positions[piece].x
|
||||
local y = offset.y + ruleset.draw_offsets[piece].y + 4.7
|
||||
local x = offset.x + ruleset:getDrawOffset(piece, rotation).x + ruleset.spawn_positions[piece].x
|
||||
local y = offset.y + ruleset:getDrawOffset(piece, rotation).y + 4.7
|
||||
love.graphics.draw(blocks[skin][colourscheme[piece]], pos_x+x*16, pos_y+y*16)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -33,6 +33,7 @@ function MarathonA1Game:new()
|
||||
|
||||
self.randomizer = History4RollsRandomizer()
|
||||
|
||||
self.additive_gravity = false
|
||||
self.lock_drop = false
|
||||
self.enable_hard_drop = false
|
||||
self.enable_hold = false
|
||||
|
||||
@@ -34,6 +34,7 @@ function MarathonA2Game:new()
|
||||
"GM"
|
||||
}
|
||||
|
||||
self.additive_gravity = false
|
||||
self.lock_drop = false
|
||||
self.lock_hard_drop = false
|
||||
self.enable_hold = false
|
||||
|
||||
@@ -39,6 +39,7 @@ self.SGnames = {
|
||||
"GM"
|
||||
}
|
||||
|
||||
self.additive_gravity = false
|
||||
self.lock_drop = true
|
||||
self.lock_hard_drop = true
|
||||
self.enable_hold = true
|
||||
|
||||
155
tetris/modes/race_40.lua
Normal file
155
tetris/modes/race_40.lua
Normal file
@@ -0,0 +1,155 @@
|
||||
require 'funcs'
|
||||
|
||||
local GameMode = require 'tetris.modes.gamemode'
|
||||
local Piece = require 'tetris.components.piece'
|
||||
|
||||
local Bag7Randomiser = require 'tetris.randomizers.bag7noSZOstart'
|
||||
|
||||
local Race40Game = GameMode:extend()
|
||||
|
||||
Race40Game.name = "Race 40"
|
||||
Race40Game.hash = "Race40"
|
||||
Race40Game.tagline = "How fast can you clear 40 lines?"
|
||||
|
||||
|
||||
function Race40Game:new()
|
||||
Race40Game.super:new()
|
||||
|
||||
self.lines = 0
|
||||
self.line_goal = 40
|
||||
self.pieces = 0
|
||||
self.randomizer = Bag7Randomiser()
|
||||
|
||||
self.roll_frames = 0
|
||||
|
||||
self.SGnames = {
|
||||
[0] = "",
|
||||
"9", "8", "7", "6", "5", "4", "3", "2", "1",
|
||||
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
|
||||
"GM"
|
||||
}
|
||||
self.upstacked = false
|
||||
|
||||
self.lock_drop = true
|
||||
self.lock_hard_drop = true
|
||||
self.instant_hard_drop = true
|
||||
self.instant_soft_drop = false
|
||||
self.enable_hold = true
|
||||
self.next_queue_length = 6
|
||||
end
|
||||
|
||||
function Race40Game:getDropSpeed()
|
||||
return 20
|
||||
end
|
||||
|
||||
function Race40Game:getARR()
|
||||
return config.arr
|
||||
end
|
||||
|
||||
function Race40Game:getARE()
|
||||
return 0
|
||||
end
|
||||
|
||||
function Race40Game:getLineARE()
|
||||
return self:getARE()
|
||||
end
|
||||
|
||||
function Race40Game:getDasLimit()
|
||||
return config.das
|
||||
end
|
||||
|
||||
function Race40Game:getLineClearDelay()
|
||||
return 0
|
||||
end
|
||||
|
||||
function Race40Game:getLockDelay()
|
||||
return 30
|
||||
end
|
||||
|
||||
function Race40Game:getGravity()
|
||||
return 1/64
|
||||
end
|
||||
|
||||
function Race40Game:getDasCutDelay()
|
||||
return config.dcd
|
||||
end
|
||||
|
||||
function Race40Game:advanceOneFrame()
|
||||
if self.clear then
|
||||
self.roll_frames = self.roll_frames + 1
|
||||
if self.roll_frames > 150 then
|
||||
self.completed = true
|
||||
end
|
||||
return false
|
||||
elseif self.ready_frames == 0 then
|
||||
self.frames = self.frames + 1
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function Race40Game:onPieceLock()
|
||||
self.super:onPieceLock()
|
||||
self.pieces = self.pieces + 1
|
||||
end
|
||||
|
||||
function Race40Game:onLineClear(cleared_row_count)
|
||||
if not self.clear then
|
||||
self.lines = self.lines + cleared_row_count
|
||||
if self.lines >= self.line_goal then
|
||||
self.clear = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function Race40Game:drawGrid(ruleset)
|
||||
self.grid:draw()
|
||||
if self.piece ~= nil then
|
||||
self:drawGhostPiece(ruleset)
|
||||
end
|
||||
end
|
||||
|
||||
function Race40Game:getHighscoreData()
|
||||
return {
|
||||
level = self.level,
|
||||
frames = self.frames,
|
||||
}
|
||||
end
|
||||
|
||||
function Race40Game:getSecretGrade(sg)
|
||||
if sg == 19 then self.upstacked = true end
|
||||
if self.upstacked then return self.SGnames[14 + math.floor((20 - sg) / 4)]
|
||||
else return self.SGnames[math.floor((sg / 19) * 14)] end
|
||||
end
|
||||
|
||||
function Race40Game:drawScoringInfo()
|
||||
Race40Game.super.drawScoringInfo(self)
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
|
||||
local text_x = config["side_next"] and 320 or 240
|
||||
|
||||
love.graphics.setFont(font_3x5_2)
|
||||
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
||||
love.graphics.printf("LINES", text_x, 320, 40, "left")
|
||||
love.graphics.printf("line/min", text_x, 160, 80, "left")
|
||||
love.graphics.printf("piece/sec", text_x, 220, 80, "left")
|
||||
local sg = self.grid:checkSecretGrade()
|
||||
if sg >= 7 or self.upstacked then
|
||||
love.graphics.printf("SECRET GRADE", 240, 430, 180, "left")
|
||||
end
|
||||
|
||||
love.graphics.setFont(font_3x5_3)
|
||||
love.graphics.printf(string.format("%.02f", self.lines / math.max(1, self.frames) * 3600), text_x, 180, 80, "left")
|
||||
love.graphics.printf(string.format("%.04f", self.pieces / math.max(1, self.frames) * 60), text_x, 240, 80, "left")
|
||||
if sg >= 7 or self.upstacked then
|
||||
love.graphics.printf(self:getSecretGrade(sg), 240, 450, 180, "left")
|
||||
end
|
||||
|
||||
love.graphics.setFont(font_3x5_4)
|
||||
love.graphics.printf(math.max(0, self.line_goal - self.lines), text_x, 340, 40, "left")
|
||||
end
|
||||
|
||||
function Race40Game:getBackground()
|
||||
return 2
|
||||
end
|
||||
|
||||
return Race40Game
|
||||
@@ -1,585 +0,0 @@
|
||||
require 'funcs'
|
||||
|
||||
local GameMode = require 'tetris.modes.gamemode'
|
||||
local Piece = require 'tetris.components.piece'
|
||||
|
||||
local SakuraRandomizer = require 'tetris.randomizers.sakura'
|
||||
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls_35bag'
|
||||
|
||||
local SakuraGame = GameMode:extend()
|
||||
|
||||
SakuraGame.name = "Sakura A3"
|
||||
SakuraGame.hash = "SakuraA3"
|
||||
SakuraGame.tagline = "Clear away the Gem Blocks as fast as possible!"
|
||||
|
||||
local b = {
|
||||
["r"] = { skin = "2tie", colour = "R" },
|
||||
["o"] = { skin = "2tie", colour = "O" },
|
||||
["y"] = { skin = "2tie", colour = "Y" },
|
||||
["g"] = { skin = "2tie", colour = "G" },
|
||||
["c"] = { skin = "2tie", colour = "C" },
|
||||
["b"] = { skin = "2tie", colour = "B" },
|
||||
["m"] = { skin = "2tie", colour = "M" },
|
||||
["R"] = { skin = "gem", colour = "R" },
|
||||
["O"] = { skin = "gem", colour = "O" },
|
||||
["Y"] = { skin = "gem", colour = "Y" },
|
||||
["G"] = { skin = "gem", colour = "G" },
|
||||
["C"] = { skin = "gem", colour = "C" },
|
||||
["B"] = { skin = "gem", colour = "B" },
|
||||
["M"] = { skin = "gem", colour = "M" },
|
||||
}
|
||||
|
||||
local effects = {
|
||||
[4] = "mirror",
|
||||
[8] = "xray",
|
||||
[12] = "color",
|
||||
[13] = "mirror",
|
||||
[16] = "roll",
|
||||
[23] = "big"
|
||||
}
|
||||
|
||||
local maps = {
|
||||
[1] = {
|
||||
[22] = {nil, nil, b.O, b.R, nil, nil, b.M, b.m, nil, nil},
|
||||
[23] = {nil, b.G, b.c, b.c, b.c, b.c, b.c, b.c, b.Y, nil},
|
||||
[24] = {nil, b.C, b.y, b.y, b.y, b.y, b.y, b.y, b.B, nil},
|
||||
},
|
||||
[2] = {
|
||||
[20] = {nil, nil, nil, nil, b.G, b.b, b.b, b.M, nil, nil},
|
||||
[21] = {nil, nil, nil, nil, b.c, b.c, b.c, b.c, nil, nil},
|
||||
[22] = {nil, nil, nil, nil, nil, b.R, b.Y, b.O, nil, nil},
|
||||
[23] = {nil, b.B, b.c, b.c, b.c, b.c, b.c, b.c, b.c, nil},
|
||||
[24] = {nil, b.b, b.b, b.b, b.b, b.b, b.b, b.b, b.C, nil},
|
||||
},
|
||||
[3] = {
|
||||
[20] = {nil, nil, nil, b.R, b.m, b.o, b.M, nil, nil, nil},
|
||||
[21] = {nil, nil, nil, nil, b.o, b.O, nil, nil, nil, nil},
|
||||
[22] = {nil, nil, nil, nil, b.G, b.Y, nil, nil, nil, nil},
|
||||
[23] = {nil, b.m, b.o, b.m, b.o, b.m, b.o, b.m, b.o, nil},
|
||||
[24] = {nil, b.B, b.m, b.o, b.m, b.o, b.m, b.o, b.C, nil},
|
||||
},
|
||||
[4] = {
|
||||
[21] = {nil, nil, b.O, b.g, b.g, b.g, b.g, nil, nil, nil},
|
||||
[22] = {nil, nil, nil, b.R, b.M, b.b, b.b, nil, nil, nil},
|
||||
[23] = {b.G, nil, b.Y, b.g, b.g, b.g, b.g, b.g, nil, nil},
|
||||
[24] = {b.b, b.C, b.b, b.b, b.b, b.b, b.b, b.b, b.B, nil},
|
||||
},
|
||||
[5] = {
|
||||
[16] = {nil, b.B, b.c, b.y, b.c, b.G, b.c, b.y, b.C, nil},
|
||||
[22] = {nil, nil, b.c, b.y, b.c, b.y, b.c, b.y, nil, nil},
|
||||
[23] = {nil, b.O, b.y, b.c, b.y, b.c, b.y, b.c, b.Y, nil},
|
||||
[24] = {nil, b.R, b.c, b.y, b.c, b.y, b.c, b.y, b.M, nil},
|
||||
},
|
||||
[6] = {
|
||||
[21] = {nil, nil, nil, nil, b.O, b.Y, nil, nil, nil, nil},
|
||||
[22] = {nil, nil, b.R, nil, b.b, b.y, nil, b.M, nil, nil},
|
||||
[23] = {nil, nil, nil, nil, b.y, b.b, nil, nil, nil, nil},
|
||||
[24] = {nil, b.G, b.y, b.b, b.C, b.y, b.b, b.y, b.B, nil},
|
||||
},
|
||||
[7] = {
|
||||
[20] = {nil, b.C, b.G, nil, b.r, b.g, b.r, b.g, nil, nil},
|
||||
[21] = {nil, nil, nil, nil, b.R, b.M, b.g, b.r, nil, nil},
|
||||
[22] = {b.r, nil, nil, nil, b.r, b.g, b.O, b.Y, nil, nil},
|
||||
[23] = {b.g, b.r, b.g, b.r, b.g, b.r, b.g, b.r, nil, nil},
|
||||
[24] = {b.r, b.g, b.r, b.g, b.r, b.g, b.r, b.g, b.B, nil},
|
||||
},
|
||||
[8] = {
|
||||
[15] = {nil, nil, nil, b.B, b.m, b.m, b.m, b.m, b.m, b.C},
|
||||
[16] = {nil, nil, nil, nil, nil, nil, nil, nil, nil, b.m},
|
||||
[17] = {nil, nil, nil, nil, nil, nil, nil, nil, nil, b.m},
|
||||
[18] = {nil, b.Y, b.y, b.y, b.y, b.y, b.y, b.y, b.y, b.G},
|
||||
[21] = {b.b, b.b, b.b, b.b, b.b, b.b, b.O, nil, nil, nil},
|
||||
[22] = {b.b, nil, nil, nil, nil, nil, nil, nil, nil, nil},
|
||||
[23] = {b.M, nil, nil, nil, nil, nil, nil, nil, nil, nil},
|
||||
[24] = {b.o, b.o, b.o, b.o, b.o, b.o, b.o, b.o, b.R, nil},
|
||||
},
|
||||
[9] = {
|
||||
[18] = {nil, nil, nil, b.Y, b.m, b.m, b.m, b.m, nil, nil},
|
||||
[19] = {nil, nil, nil, b.c, b.c, b.c, b.c, b.G, nil, nil},
|
||||
[20] = {b.m, b.m, b.m, b.O, b.M, b.R, nil, nil, nil, nil},
|
||||
[21] = {b.c, b.c, b.c, b.c, b.c, b.c, b.c, b.c, nil, nil},
|
||||
[22] = {b.m, b.m, b.m, b.m, b.m, b.m, b.m, b.m, nil, nil},
|
||||
[23] = {b.c, b.c, b.c, b.c, b.c, b.c, b.c, b.c, b.C, nil},
|
||||
[24] = {b.m, b.m, b.m, b.m, b.m, b.m, b.m, b.m, b.B, nil},
|
||||
},
|
||||
[10] = {
|
||||
[18] = {nil, nil, nil, b.C, b.g, b.g, b.B, nil, nil, nil},
|
||||
[19] = {nil, nil, b.G, b.g, b.g, b.g, b.g, b.Y, nil, nil},
|
||||
[20] = {nil, b.M, b.g, b.g, b.g, b.g, b.g, b.g, b.O, nil},
|
||||
[21] = {nil, nil, nil, nil, b.c, nil, nil, nil, nil, nil},
|
||||
[22] = {nil, nil, nil, nil, b.c, nil, nil, nil, nil, nil},
|
||||
[23] = {nil, nil, nil, nil, b.c, nil, b.o, nil, nil, nil},
|
||||
[24] = {nil, nil, nil, nil, b.R, b.o, b.o, nil, nil, nil},
|
||||
},
|
||||
[11] = {
|
||||
[18] = {nil, nil, nil, nil, b.o, b.o, nil, nil, nil, nil},
|
||||
[19] = {nil, nil, nil, nil, b.R, nil, nil, nil, nil, nil},
|
||||
[20] = {nil, nil, nil, nil, b.r, b.O, nil, nil, nil, nil},
|
||||
[21] = {nil, nil, nil, nil, nil, b.M, nil, nil, nil, nil},
|
||||
[22] = {nil, nil, nil, nil, b.o, b.o, nil, nil, nil, nil},
|
||||
[23] = {nil, nil, nil, nil, b.G, b.Y, nil, nil, nil, nil},
|
||||
[24] = {b.C, b.g, b.g, nil, b.o, b.o, nil, b.g, b.g, b.B},
|
||||
},
|
||||
[12] = {
|
||||
[21] = {nil, nil, nil, nil, nil, nil, nil, b.g, b.g, b.Y},
|
||||
[22] = {nil, nil, b.r, b.G, b.r, nil, nil, nil, b.O, b.g},
|
||||
[23] = {nil, b.r, b.C, b.r, b.B, b.r, nil, nil, nil, b.M},
|
||||
[24] = {b.r, b.r, b.r, b.R, b.r, b.r, b.r, nil, nil, nil},
|
||||
},
|
||||
[13] = {
|
||||
[20] = {b.c, nil, nil, nil, nil, nil, nil, nil, nil, b.B},
|
||||
[21] = {b.c, b.c, nil, nil, nil, nil, nil, nil, b.C, b.c},
|
||||
[22] = {b.c, b.c, b.c, nil, nil, nil, nil, b.G, b.c, b.c},
|
||||
[23] = {b.b, b.b, b.b, b.b, nil, nil, b.Y, b.b, b.b, b.b},
|
||||
[24] = {nil, b.M, b.b, b.b, b.b, b.O, b.b, b.b, b.R, nil},
|
||||
},
|
||||
[14] = {
|
||||
[20] = {nil, nil, nil, b.y, b.r, b.y, nil, nil, nil, nil},
|
||||
[21] = {b.R, nil, nil, b.Y, b.y, b.r, b.G, nil, nil, nil},
|
||||
[22] = {nil, nil, nil, b.y, b.r, b.y, b.r, b.y, b.r, b.B},
|
||||
[23] = {nil, nil, nil, nil, nil, nil, nil, b.O, b.y, b.r},
|
||||
[24] = {nil, nil, nil, nil, nil, nil, b.M, b.y, b.r, b.C},
|
||||
},
|
||||
[15] = {
|
||||
[17] = {nil, nil, b.b, nil, nil, nil, nil, b.b, nil, nil},
|
||||
[18] = {nil, nil, b.b, b.y, b.b, b.b, b.y, b.b, nil, nil},
|
||||
[19] = {nil, nil, nil, b.y, b.b, b.b, b.y, nil, nil, nil},
|
||||
[20] = {nil, nil, nil, nil, b.O, b.Y, nil, nil, nil, nil},
|
||||
[22] = {nil, nil, nil, nil, b.M, b.R, nil, nil, nil, nil},
|
||||
[23] = {nil, nil, nil, b.G, b.y, b.y, b.C, nil, nil, nil},
|
||||
[24] = {nil, nil, b.B, b.y, b.y, b.y, b.y, b.y, nil, nil},
|
||||
},
|
||||
[16] = {
|
||||
[18] = {nil, nil, b.O, nil, nil, nil, nil, b.B, nil, nil},
|
||||
[19] = {nil, nil, b.c, nil, nil, b.G, nil, b.c, nil, nil},
|
||||
[20] = {nil, nil, b.c, nil, b.C, b.R, nil, b.c, nil, nil},
|
||||
[21] = {nil, nil, b.c, nil, nil, nil, nil, b.c, nil, nil},
|
||||
[22] = {nil, nil, b.Y, b.c, b.c, b.c, b.c, b.M, nil, nil},
|
||||
},
|
||||
[17] = {
|
||||
[15] = {b.O, nil, nil, b.g, nil, nil, b.m, nil, nil, b.Y},
|
||||
[16] = {nil, nil, nil, b.g, nil, nil, b.m, nil, nil, nil},
|
||||
[17] = {nil, nil, nil, b.g, nil, nil, b.R, nil, nil, nil},
|
||||
[18] = {nil, nil, nil, b.g, nil, nil, b.m, nil, nil, nil},
|
||||
[19] = {nil, nil, nil, b.M, nil, nil, b.m, nil, nil, nil},
|
||||
[20] = {nil, nil, nil, b.g, nil, nil, b.m, nil, nil, nil},
|
||||
[21] = {nil, nil, nil, b.g, nil, nil, b.G, nil, nil, nil},
|
||||
[22] = {nil, nil, nil, b.g, nil, nil, b.m, nil, nil, nil},
|
||||
[23] = {nil, nil, nil, b.g, nil, nil, b.m, nil, nil, nil},
|
||||
[24] = {nil, b.m, b.m, b.m, b.B, b.C, b.g, b.g, b.g, nil},
|
||||
},
|
||||
[18] = {
|
||||
[19] = {nil, nil, nil, b.y, b.B, b.y, b.y, nil, nil, nil},
|
||||
[20] = {nil, nil, b.y, nil, nil, nil, nil, b.y, nil, nil},
|
||||
[21] = {nil, b.o, nil, nil, b.C, b.R, nil, nil, b.O, nil},
|
||||
[22] = {nil, b.M, nil, nil, b.Y, b.G, nil, nil, b.o, nil},
|
||||
[23] = {nil, b.r, b.o, nil, nil, nil, nil, b.o, b.r, nil},
|
||||
[24] = {nil, b.r, b.r, b.o, b.o, b.o, b.o, b.r, b.r, nil},
|
||||
},
|
||||
[19] = {
|
||||
[15] = {nil, nil, nil, nil, nil, nil, b.O, nil, nil, nil},
|
||||
[16] = {nil, nil, nil, nil, nil, b.o, nil, nil, nil, nil},
|
||||
[17] = {nil, nil, nil, nil, b.o, b.r, b.o, nil, nil, nil},
|
||||
[18] = {nil, b.o, nil, nil, b.o, b.r, b.r, b.o, nil, nil},
|
||||
[19] = {nil, b.o, b.o, nil, nil, b.R, b.r, b.r, nil, nil},
|
||||
[20] = {nil, nil, b.M, b.r, nil, b.r, b.r, b.r, b.r, nil},
|
||||
[21] = {nil, nil, b.r, b.r, b.r, b.r, b.y, b.G, b.o, b.o},
|
||||
[22] = {nil, b.r, b.o, b.y, b.Y, b.y, b.y, b.y, b.y, b.o},
|
||||
[23] = {nil, b.o, b.o, b.y, b.y, b.c, b.c, b.c, b.c, b.C},
|
||||
[24] = {nil, nil, b.o, b.y, b.b, b.b, b.B, b.b, b.b, b.b},
|
||||
},
|
||||
[20] = {
|
||||
[20] = {nil, nil, b.B, b.b, b.b, b.b, b.b, b.b, nil, nil},
|
||||
[21] = {b.c, nil, nil, b.C, b.c, b.c, b.c, nil, nil, b.c},
|
||||
[22] = {b.g, b.g, nil, nil, b.G, b.g, nil, nil, b.g, b.g},
|
||||
[23] = {b.y, b.y, b.o, nil, nil, nil, nil, b.Y, b.y, b.y},
|
||||
[24] = {b.r, b.r, b.r, b.R, nil, nil, b.M, b.r, b.r, b.r},
|
||||
},
|
||||
[21] = {
|
||||
[16] = {nil, nil, b.g, b.g, b.g, b.g, b.g, nil, nil, nil},
|
||||
[17] = {nil, b.g, b.g, b.g, b.g, b.g, b.g, b.B, b.g, nil},
|
||||
[18] = {b.g, b.g, b.g, b.g, b.g, b.g, b.g, b.g, b.C, nil},
|
||||
[19] = {b.g, nil, nil, b.g, b.o, b.o, b.g, nil, nil, b.g},
|
||||
[20] = {nil, b.R, nil, b.g, b.o, b.o, nil, b.M, nil, b.G},
|
||||
[21] = {nil, nil, nil, nil, b.o, b.o, nil, nil, nil, nil},
|
||||
[22] = {nil, nil, nil, nil, b.o, b.o, nil, nil, nil, nil},
|
||||
[23] = {nil, nil, nil, nil, b.o, b.o, nil, nil, nil, nil},
|
||||
[24] = {nil, nil, nil, nil, b.Y, b.O, nil, nil, nil, nil},
|
||||
},
|
||||
[22] = {
|
||||
[15] = {nil, nil, b.b, nil, nil, nil, nil, b.b, nil, nil},
|
||||
[16] = {nil, b.b, b.O, b.b, nil, nil, b.b, b.Y, b.b, nil},
|
||||
[17] = {nil, nil, b.b, nil, nil, nil, nil, b.b, nil, nil},
|
||||
[20] = {nil, nil, nil, nil, b.R, b.M, nil, nil, nil, nil},
|
||||
[23] = {nil, nil, nil, b.b, b.C, b.G, b.b, nil, nil, nil},
|
||||
[24] = {nil, nil, nil, b.b, b.b, b.B, b.b, nil, nil, nil},
|
||||
},
|
||||
[23] = {
|
||||
[13] = {nil, nil, nil, nil, nil, nil, nil, nil, b.c, b.m},
|
||||
[14] = {nil, nil, nil, nil, nil, nil, nil, nil, b.y, b.g},
|
||||
[15] = {b.G, b.B, nil, nil, nil, nil, nil, nil, nil, nil},
|
||||
[16] = {b.r, b.O, nil, nil, nil, nil, nil, nil, nil, nil},
|
||||
[23] = {nil, nil, nil, nil, b.C, b.M, nil, nil, nil, nil},
|
||||
[24] = {nil, nil, nil, nil, b.R, b.Y, nil, nil, nil, nil},
|
||||
},
|
||||
[24] = {
|
||||
[20] = {b.g, b.g, b.g, b.g, b.G, nil, nil, nil, nil, nil},
|
||||
[21] = {nil, nil, nil, nil, nil, b.O, b.y, b.y, b.y, b.Y},
|
||||
[23] = {b.M, b.r, b.r, b.r, b.R, nil, nil, nil, nil, nil},
|
||||
[24] = {nil, nil, nil, nil, nil, b.M, b.r, b.r, b.r, b.R},
|
||||
},
|
||||
[25] = {
|
||||
[18] = {nil, nil, nil, nil, nil, b.B, nil, nil, nil, nil},
|
||||
[19] = {nil, nil, nil, b.G, nil, nil, nil, b.C, nil, nil},
|
||||
[20] = {nil, nil, nil, nil, nil, b.Y, nil, nil, nil, nil},
|
||||
[21] = {nil, nil, nil, b.M, nil, nil, nil, b.O, nil, nil},
|
||||
[22] = {nil, nil, nil, nil, nil, b.R, nil, nil, nil, nil},
|
||||
},
|
||||
[26] = {
|
||||
[13] = {nil, nil, nil, nil, b.r, b.r, nil, nil, nil, nil},
|
||||
[14] = {nil, nil, nil, nil, b.o, b.o, nil, nil, nil, nil},
|
||||
[15] = {nil, nil, nil, nil, b.o, b.o, nil, nil, nil, nil},
|
||||
[16] = {nil, nil, nil, nil, b.o, b.o, nil, nil, nil, nil},
|
||||
[17] = {nil, nil, nil, b.O, b.o, b.o, b.Y, nil, nil, nil},
|
||||
[18] = {nil, nil, b.o, b.c, b.c, b.c, b.c, b.o, nil, nil},
|
||||
[19] = {nil, nil, b.o, b.c, b.c, b.c, b.c, b.o, nil, nil},
|
||||
[20] = {nil, nil, b.o, nil, nil, b.G, nil, b.o, nil, nil},
|
||||
[21] = {nil, nil, b.o, nil, b.M, b.R, nil, b.o, nil, nil},
|
||||
[22] = {nil, nil, b.o, b.b, b.b, b.b, b.B, b.o, nil, nil},
|
||||
[23] = {nil, nil, b.o, b.C, b.b, b.b, b.b, b.o, nil, nil},
|
||||
[24] = {nil, nil, b.o, b.o, b.o, b.o, b.o, b.o, nil, nil},
|
||||
},
|
||||
[27] = {
|
||||
[15] = {nil, b.C, b.o, b.g, b.g, b.g, b.g, b.g, b.B, nil},
|
||||
[16] = {b.g, nil, b.y, b.o, b.g, b.g, b.g, b.g, nil, b.y},
|
||||
[17] = {b.g, b.g, nil, b.y, b.o, b.g, b.g, nil, b.y, b.o},
|
||||
[18] = {b.g, b.g, b.g, nil, b.y, b.o, nil, b.y, b.o, b.g},
|
||||
[19] = {b.g, b.g, b.g, b.o, nil, b.G, b.y, b.o, b.g, b.g},
|
||||
[20] = {b.g, b.g, b.o, b.o, b.Y, nil, b.o, b.g, b.g, b.g},
|
||||
[21] = {b.g, b.o, b.y, nil, b.o, b.O, nil, b.g, b.g, b.g},
|
||||
[22] = {b.o, b.y, nil, b.g, b.g, b.o, b.y, nil, b.g, b.g},
|
||||
[23] = {b.y, nil, b.g, b.g, b.g, b.g, b.o, b.y, nil, b.g},
|
||||
[24] = {nil, b.M, b.g, b.g, b.g, b.g, b.g, b.o, b.R, nil},
|
||||
},
|
||||
}
|
||||
|
||||
local STAGE_TRANSITION_TIME = 300
|
||||
|
||||
function SakuraGame:new(secret_inputs)
|
||||
self.super:new()
|
||||
|
||||
self.randomizer = (
|
||||
(
|
||||
secret_inputs.rotate_left and secret_inputs.rotate_right
|
||||
) and History6RollsRandomizer() or SakuraRandomizer()
|
||||
)
|
||||
|
||||
self.current_map = 1
|
||||
self.time_limit = 10800
|
||||
self.cleared_frames = STAGE_TRANSITION_TIME
|
||||
self.stage_frames = 0
|
||||
self.time_extend = 0
|
||||
self.maps_cleared = 0
|
||||
self.map_20_time = 0
|
||||
self.stage_pieces = 0
|
||||
self.grid:applyMap(maps[self.current_map])
|
||||
|
||||
self.lock_drop = true
|
||||
self.lock_hard_drop = true
|
||||
self.enable_hold = true
|
||||
self.next_queue_length = 3
|
||||
end
|
||||
|
||||
function SakuraGame:checkRequirements()
|
||||
if self.maps_cleared >= 14 + 2 * (self.current_map - 20) and
|
||||
self.map_20_time <= frameTime(8,00) - frameTime(0,30) * (self.current_map - 20)
|
||||
then
|
||||
return false
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function SakuraGame:getGravity()
|
||||
if self.level < 8 then return 4/256
|
||||
elseif self.level < 19 then return 5/256
|
||||
elseif self.level < 35 then return 6/256
|
||||
elseif self.level < 40 then return 8/256
|
||||
elseif self.level < 50 then return 10/256
|
||||
elseif self.level < 60 then return 12/256
|
||||
elseif self.level < 70 then return 16/256
|
||||
elseif self.level < 80 then return 32/256
|
||||
elseif self.level < 90 then return 48/256
|
||||
elseif self.level < 100 then return 64/256
|
||||
elseif self.level < 108 then return 4/256
|
||||
elseif self.level < 119 then return 5/256
|
||||
elseif self.level < 125 then return 6/256
|
||||
elseif self.level < 131 then return 8/256
|
||||
elseif self.level < 139 then return 12/256
|
||||
elseif self.level < 149 then return 32/256
|
||||
elseif self.level < 156 then return 48/256
|
||||
elseif self.level < 164 then return 80/256
|
||||
elseif self.level < 174 then return 112/256
|
||||
elseif self.level < 180 then return 128/256
|
||||
elseif self.level < 200 then return 144/256
|
||||
elseif self.level < 212 then return 16/256
|
||||
elseif self.level < 221 then return 48/256
|
||||
elseif self.level < 232 then return 80/256
|
||||
elseif self.level < 244 then return 112/256
|
||||
elseif self.level < 256 then return 144/256
|
||||
elseif self.level < 267 then return 176/256
|
||||
elseif self.level < 277 then return 192/256
|
||||
elseif self.level < 287 then return 208/256
|
||||
elseif self.level < 295 then return 224/256
|
||||
elseif self.level < 300 then return 240/256
|
||||
else return 20 end
|
||||
end
|
||||
|
||||
function SakuraGame:onLineClear(cleared_row_count)
|
||||
self.level = self.level + cleared_row_count
|
||||
for i = 13, 24 do
|
||||
for j = 1, 10 do
|
||||
local block = self.grid.grid[i][j]
|
||||
if block and block.skin == "gem" and block.colour == "X" then
|
||||
self.time_limit = self.time_limit + 60
|
||||
end
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SakuraGame:onPieceEnter()
|
||||
if self.level % 100 ~= 99 and not self.clear and self.stage_frames ~= 0 then
|
||||
self.level = self.level + 1
|
||||
end
|
||||
if effects[self.current_map] == "mirror" and
|
||||
self.stage_pieces % 3 == 0 and self.stage_pieces ~= 0
|
||||
then
|
||||
self.grid:mirror()
|
||||
end
|
||||
self.stage_pieces = self.stage_pieces + 1
|
||||
end
|
||||
|
||||
function SakuraGame:advanceOneFrame(inputs, ruleset)
|
||||
if self.ready_frames == 0 then
|
||||
if self.lcd > 0 then
|
||||
if self.stage_frames <= frameTime(0,10) then self.time_extend = 600
|
||||
elseif self.stage_frames <= frameTime(0,30) then self.time_extend = 300
|
||||
else self.time_extend = 0 end
|
||||
end
|
||||
|
||||
if not self.grid:hasGemBlocks() or
|
||||
(self.stage_frames >= 3600 and self.current_map <= 20) then
|
||||
self.lcd = 0
|
||||
self.are = 0
|
||||
if self.stage_frames >= 3600 then self.time_extend = 0 end
|
||||
self.piece = nil
|
||||
|
||||
-- transition to next map
|
||||
if self.cleared_frames > 0 then
|
||||
self.cleared_frames = self.cleared_frames - 1
|
||||
if self.time_extend > 0 then
|
||||
self.time_limit = self.time_limit + 3
|
||||
self.time_extend = self.time_extend - 3
|
||||
end
|
||||
return false
|
||||
end
|
||||
|
||||
self.hold_queue = nil
|
||||
if self.current_map > 20 or (self.stage_frames < 3600 and self.current_map <= 20) then self.maps_cleared = self.maps_cleared + 1 end
|
||||
self.stage_frames = -1
|
||||
self.level = 0
|
||||
self.grid:clear()
|
||||
if (self.current_map == 20) then self.map_20_time = self.frames end
|
||||
if self.current_map >= 20 and self:checkRequirements() then
|
||||
self.clear = true
|
||||
self.completed = true
|
||||
return false
|
||||
else
|
||||
self.current_map = self.current_map + 1
|
||||
self.big_mode = effects[self.current_map] == "big"
|
||||
self.ready_frames = 100
|
||||
self.stage_pieces = 0
|
||||
self.grid:applyMap(maps[self.current_map])
|
||||
end
|
||||
|
||||
-- this is necessary to fix timer
|
||||
self.frames = self.frames - 1
|
||||
self.time_limit = self.time_limit + 1
|
||||
end
|
||||
|
||||
self.frames = self.frames + 1
|
||||
self.stage_frames = self.stage_frames + 1
|
||||
self.time_limit = math.max(self.time_limit - 1, 0)
|
||||
if self.time_limit <= 0 and self.piece == nil then
|
||||
self.game_over = true
|
||||
end
|
||||
|
||||
if self.piece ~= nil and
|
||||
effects[self.current_map] == "roll" and
|
||||
self.stage_pieces % 4 == 0
|
||||
then
|
||||
self.piece.colour = "F"
|
||||
if self.stage_frames % 30 == 0 then
|
||||
ruleset:attemptRotate(
|
||||
{[config.gamesettings.world_reverse == 3 or
|
||||
(ruleset.world and config.gamesettings.world_reverse == 2)
|
||||
and "rotate_left" or "rotate_right"] = true},
|
||||
self.piece, self.grid, false
|
||||
)
|
||||
end
|
||||
end
|
||||
else
|
||||
self.cleared_frames = STAGE_TRANSITION_TIME
|
||||
if not self.prev_inputs.hold and inputs.hold then
|
||||
self.hold_queue = table.remove(self.next_queue, 1)
|
||||
table.insert(self.next_queue, self:getNextPiece(ruleset))
|
||||
end
|
||||
end
|
||||
return true
|
||||
end
|
||||
|
||||
function SakuraGame:onGameComplete() end
|
||||
|
||||
local function colourXRay(game, block, x, y, age)
|
||||
local r, g, b, a = .5,.5,.5
|
||||
if ((game.stage_frames/2 - x) % 30 < 1)
|
||||
or game.stage_frames == 0
|
||||
or game.cleared_frames ~= STAGE_TRANSITION_TIME
|
||||
or game.stage_pieces % 2 == 0
|
||||
then
|
||||
a = 1
|
||||
else
|
||||
a = 1 - age / 4
|
||||
end
|
||||
return r, g, b, a, a
|
||||
end
|
||||
|
||||
local function colourColor(game, block, x, y, age)
|
||||
local r, g, b, a = .5,.5,.5
|
||||
if game.stage_frames == 0 or game.cleared_frames ~= STAGE_TRANSITION_TIME then
|
||||
a = 1
|
||||
else
|
||||
a = (game.stage_frames/30 + (y + math.abs(x-5.5))/5) % 1
|
||||
end
|
||||
return r, g, b, a, 0
|
||||
end
|
||||
|
||||
function SakuraGame:drawGrid()
|
||||
if effects[self.current_map] == "xray" then
|
||||
self.grid:drawCustom(colourXRay, self)
|
||||
elseif effects[self.current_map] == "color" then
|
||||
self.grid:drawCustom(colourColor, self)
|
||||
else
|
||||
self.grid:draw()
|
||||
end
|
||||
if self.piece ~= nil and self.level < 100 then
|
||||
self:drawGhostPiece()
|
||||
end
|
||||
end
|
||||
|
||||
function SakuraGame:drawScoringInfo()
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
|
||||
love.graphics.setFont(font_3x5_2)
|
||||
love.graphics.print(
|
||||
self.das.direction .. " " ..
|
||||
self.das.frames .. " " ..
|
||||
strTrueValues(self.prev_inputs)
|
||||
)
|
||||
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
||||
love.graphics.printf("STAGE", 240, 120, 80, "left")
|
||||
love.graphics.printf("TIME LIMIT", 240, 180, 80, "left")
|
||||
love.graphics.printf("LEVEL", 240, 320, 40, "left")
|
||||
if self.current_map <= 20 then
|
||||
love.graphics.printf("STAGE LIMIT", 240, 240, 100, "left")
|
||||
end
|
||||
if effects[self.current_map] then
|
||||
love.graphics.printf("EFFECT: " .. effects[self.current_map], 240, 300, 160, "left")
|
||||
end
|
||||
if self.used_randomizer.history then
|
||||
love.graphics.printf("RANDOM PIECES ACTIVE!", 240, 150, 200, "left")
|
||||
end
|
||||
|
||||
love.graphics.setFont(font_3x5_3)
|
||||
love.graphics.setColor(
|
||||
(self.time_limit % 4 < 2 and
|
||||
self.time_limit <= frameTime(0,10) and
|
||||
self.grid:hasGemBlocks() and
|
||||
self.time_limit ~= 0 and
|
||||
self.ready_frames == 0) and
|
||||
{ 1, 0.3, 0.3, 1 } or
|
||||
{ 1, 1, 1, 1 }
|
||||
)
|
||||
love.graphics.printf(formatTime(self.time_limit), 240, 200, 120, "left")
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
if self.current_map <= 20 then
|
||||
love.graphics.printf(formatTime(3600 - self.stage_frames), 240, 260, 120, "left")
|
||||
end
|
||||
love.graphics.printf(self.level, 240, 340, 40, "right")
|
||||
love.graphics.printf(math.floor((self.level + 100) / 100) * 100, 240, 370, 40, "right")
|
||||
|
||||
love.graphics.setFont(font_8x11)
|
||||
love.graphics.printf(formatTime(self.frames), 64, 420, 160, "center")
|
||||
love.graphics.printf(self.current_map, 290, 110, 80, "left")
|
||||
end
|
||||
|
||||
function SakuraGame:drawCustom()
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
|
||||
if self.ready_frames ~= 0 and not self.clear then
|
||||
love.graphics.setFont(font_3x5_4)
|
||||
love.graphics.printf("STAGE " .. self.current_map, 64, 170, 160, "center")
|
||||
|
||||
love.graphics.setFont(font_3x5_3)
|
||||
if effects[self.current_map] then
|
||||
love.graphics.printf("EFFECT: " .. effects[self.current_map], 64, 270, 160, "center")
|
||||
end
|
||||
end
|
||||
|
||||
if self.cleared_frames > 0 and
|
||||
(not self.grid:hasGemBlocks() or
|
||||
(self.stage_frames >= 3600 and self.current_map <= 20)) then
|
||||
love.graphics.setFont(font_3x5_2)
|
||||
love.graphics.printf("TIME LIMIT", 64, 180, 160, "center")
|
||||
love.graphics.printf("TIME EXTEND", 64, 240, 160, "center")
|
||||
love.graphics.printf("STAGE TIME", 64, 300, 160, "center")
|
||||
|
||||
love.graphics.setFont(font_3x5_3)
|
||||
love.graphics.printf("STAGE " .. self.current_map, 64, 100, 160, "center")
|
||||
love.graphics.setColor(
|
||||
self.cleared_frames % 4 < 2 and
|
||||
{ 1, 1, 0.3, 1 } or
|
||||
{ 1, 1, 1, 1 }
|
||||
)
|
||||
love.graphics.printf(formatTime(self.time_limit), 64, 200, 160, "center")
|
||||
love.graphics.setColor(1, 1, 1, 1)
|
||||
love.graphics.printf(formatTime(self.time_extend), 64, 260, 160, "center")
|
||||
love.graphics.printf(formatTime(self.stage_frames), 64, 320, 160, "center")
|
||||
|
||||
love.graphics.setFont(font_3x5_4)
|
||||
love.graphics.printf((self.stage_frames >= 3600 and self.current_map <= 20) and "" or "CLEAR!", 64, 130, 160, "center")
|
||||
end
|
||||
|
||||
if self.clear then
|
||||
love.graphics.setFont(font_3x5_3)
|
||||
love.graphics.printf("EXCELLENT!", 64, 180, 160, "center")
|
||||
|
||||
love.graphics.setFont(font_3x5_2)
|
||||
if self.current_map ~= 27 then
|
||||
love.graphics.printf("...but let's go\nbetter next time", 64, 220, 160, "center")
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SakuraGame:getBackground()
|
||||
return (self.current_map - 1) % 20
|
||||
end
|
||||
|
||||
function SakuraGame:getHighscoreData()
|
||||
return {
|
||||
maps = self.maps_cleared,
|
||||
current_map = self.current_map,
|
||||
frames = self.frames,
|
||||
}
|
||||
end
|
||||
|
||||
return SakuraGame
|
||||
@@ -111,9 +111,8 @@ function SurvivalA1Game:onLineClear(cleared_row_count)
|
||||
local new_level = math.min(self.level + cleared_row_count, 999)
|
||||
if new_level == 999 then
|
||||
self.clear = true
|
||||
else
|
||||
self.level = new_level
|
||||
end
|
||||
self.level = new_level
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -30,11 +30,6 @@ function SurvivalA2Game:new()
|
||||
self.lock_hard_drop = true
|
||||
end
|
||||
|
||||
function SurvivalA2Game:initialize(ruleset)
|
||||
SurvivalA2Game.super.initialize(self, ruleset)
|
||||
self.world = ruleset.world
|
||||
end
|
||||
|
||||
function SurvivalA2Game:getARE()
|
||||
if self.level < 100 then return 18
|
||||
elseif self.level < 300 then return 14
|
||||
@@ -74,8 +69,7 @@ function SurvivalA2Game:getGravity()
|
||||
end
|
||||
|
||||
function SurvivalA2Game:hitTorikan(old_level, new_level)
|
||||
local torikan_time = self.world and frameTime(3,55) or frameTime(3,25)
|
||||
if old_level < 500 and new_level >= 500 and self.frames > torikan_time then
|
||||
if old_level < 500 and new_level >= 500 and self.frames > frameTime(3,25) then
|
||||
self.level = 500
|
||||
return true
|
||||
end
|
||||
|
||||
@@ -15,7 +15,6 @@ SurvivalAXGame.tagline = "Can you clear the time hurdles when the game goes this
|
||||
function SurvivalAXGame:new()
|
||||
SurvivalAXGame.super:new()
|
||||
|
||||
self.roll_frames = 0
|
||||
self.randomizer = Bag7NoSZOStartRandomizer()
|
||||
|
||||
self.section_time_limit = 3600
|
||||
@@ -75,14 +74,7 @@ function SurvivalAXGame:getSection()
|
||||
end
|
||||
|
||||
function SurvivalAXGame:advanceOneFrame()
|
||||
if self.clear then
|
||||
self.roll_frames = self.roll_frames + 1
|
||||
if self.roll_frames < 0 then
|
||||
return false
|
||||
elseif self.roll_frames > 2968 then
|
||||
self.completed = true
|
||||
end
|
||||
elseif self.ready_frames == 0 then
|
||||
if self.ready_frames == 0 then
|
||||
if not self.section_clear then
|
||||
self.frames = self.frames + 1
|
||||
end
|
||||
@@ -101,7 +93,7 @@ function SurvivalAXGame:onLineClear(cleared_row_count)
|
||||
if self.lines == 150 then
|
||||
self.grid:clear()
|
||||
self.clear = true
|
||||
self.roll_frames = -150
|
||||
self.completed = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
@@ -4,6 +4,7 @@ local BagRandomizer = Randomizer:extend()
|
||||
|
||||
function BagRandomizer:new(pieces)
|
||||
self.bag = {}
|
||||
self.possible_pieces = pieces
|
||||
self.pieces = pieces
|
||||
for i = 1, self.pieces do
|
||||
table.insert(self.bag, i)
|
||||
|
||||
@@ -28,11 +28,8 @@ end
|
||||
function History6Rolls35PoolRandomizer:generatePiece()
|
||||
local index, x
|
||||
if self.first then
|
||||
local prevent = {"S", "Z", "O"}
|
||||
repeat
|
||||
index = math.random(#self.pool)
|
||||
x = self.pool[index]
|
||||
until not inHistory(x, prevent)
|
||||
index = math.random(20)
|
||||
x = self.pool[index]
|
||||
self.first = false
|
||||
else
|
||||
for i = 1, 6 do
|
||||
|
||||
@@ -1,5 +1,5 @@
|
||||
local Piece = require 'tetris.components.piece'
|
||||
local Ruleset = require 'tetris.rulesets.arika_ti'
|
||||
local Ruleset = require 'tetris.rulesets.arika_ace2'
|
||||
|
||||
local ARS = Ruleset:extend()
|
||||
|
||||
@@ -18,40 +18,5 @@ ARS.colourscheme = {
|
||||
|
||||
ARS.softdrop_lock = false
|
||||
ARS.harddrop_lock = true
|
||||
ARS.spawn_above_field = true
|
||||
|
||||
function ARS:onPieceCreate(piece, grid)
|
||||
piece.floorkick = 0
|
||||
piece.manipulations = 0
|
||||
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 >= 128 then
|
||||
piece:dropToBottom(grid)
|
||||
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 >= 128 then
|
||||
piece:dropToBottom(grid)
|
||||
piece.locked = true
|
||||
end
|
||||
end
|
||||
if piece.floorkick >= 1 then
|
||||
piece.floorkick = piece.floorkick + 1
|
||||
end
|
||||
end
|
||||
|
||||
function ARS:get180RotationValue() return 3 end
|
||||
|
||||
function ARS:getDefaultOrientation() return 3 end -- downward facing pieces by default
|
||||
|
||||
return ARS
|
||||
|
||||
@@ -7,11 +7,84 @@ ARS.name = "ACE-ARS2"
|
||||
ARS.hash = "ArikaACE2"
|
||||
ARS.spawn_above_field = true
|
||||
|
||||
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) and
|
||||
(piece:isMoveBlocked(grid, {x=-1, y=0}) or piece:isMoveBlocked(grid, {x=1, y=0})) 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) 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)
|
||||
elseif grid:canPlacePiece(new_piece:withOffset({x=0, y=-2})) then
|
||||
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-2})
|
||||
self:onPieceRotate(piece, grid)
|
||||
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})
|
||||
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)
|
||||
elseif piece.shape == "T"
|
||||
and new_piece.rotation == 0
|
||||
and piece:isDropBlocked(grid)
|
||||
and grid:canPlacePiece(new_piece:withOffset({x=0, y=-1}))
|
||||
then
|
||||
-- T floorkick
|
||||
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
|
||||
self:onPieceRotate(piece, grid)
|
||||
end
|
||||
end
|
||||
|
||||
end
|
||||
|
||||
function ARS:onPieceCreate(piece, grid)
|
||||
piece.floorkick = 0
|
||||
piece.manipulations = 0
|
||||
end
|
||||
|
||||
function ARS:onPieceDrop(piece, grid)
|
||||
piece.lock_delay = 0
|
||||
end
|
||||
|
||||
function ARS:onPieceMove(piece, grid)
|
||||
piece.lock_delay = 0 -- move reset
|
||||
if piece:isDropBlocked(grid) then
|
||||
@@ -32,9 +105,6 @@ function ARS:onPieceRotate(piece, grid)
|
||||
piece.locked = true
|
||||
end
|
||||
end
|
||||
if piece.floorkick >= 1 then
|
||||
piece.floorkick = piece.floorkick + 1
|
||||
end
|
||||
end
|
||||
|
||||
function ARS:get180RotationValue() return 3 end
|
||||
|
||||
@@ -38,35 +38,35 @@ function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||
(piece:isMoveBlocked(grid, {x=-1, y=0}) or piece:isMoveBlocked(grid, {x=1, y=0})) then
|
||||
-- kick right, right2, left
|
||||
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
|
||||
self:onPieceRotate(piece, grid)
|
||||
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
|
||||
self:onPieceRotate(piece, grid)
|
||||
elseif grid:canPlacePiece(new_piece:withOffset({x=2, y=0})) then
|
||||
self:onPieceRotate(piece, grid)
|
||||
piece:setRelativeRotation(rot_dir):setOffset({x=2, y=0})
|
||||
elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then
|
||||
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
|
||||
self:onPieceRotate(piece, grid)
|
||||
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
|
||||
piece.floorkick = 1
|
||||
self:onPieceRotate(piece, grid, true)
|
||||
elseif grid:canPlacePiece(new_piece:withOffset({x=0, y=-2})) then
|
||||
self:onPieceRotate(piece, grid)
|
||||
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-2})
|
||||
piece.floorkick = 1
|
||||
self:onPieceRotate(piece, grid, true)
|
||||
end
|
||||
end
|
||||
else
|
||||
-- kick right, kick left
|
||||
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
|
||||
self:onPieceRotate(piece, grid)
|
||||
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
|
||||
elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then
|
||||
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)
|
||||
elseif piece.shape == "T"
|
||||
and new_piece.rotation == 0
|
||||
and piece.floorkick == 0
|
||||
@@ -75,8 +75,8 @@ function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||
then
|
||||
-- T floorkick
|
||||
piece.floorkick = piece.floorkick + 1
|
||||
self:onPieceRotate(piece, grid)
|
||||
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
|
||||
self:onPieceRotate(piece, grid, true)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -93,12 +93,11 @@ function ARS:onPieceDrop(piece, grid)
|
||||
end
|
||||
end
|
||||
|
||||
function ARS:onPieceRotate(piece, grid)
|
||||
if piece.floorkick >= 1 then
|
||||
function ARS:onPieceRotate(piece, grid, floorkick)
|
||||
if piece.floorkick >= 2 and piece:isDropBlocked(grid) then
|
||||
piece.locked = true
|
||||
elseif piece.floorkick >= 1 and not floorkick then
|
||||
piece.floorkick = piece.floorkick + 1
|
||||
if piece:isDropBlocked(grid) then
|
||||
piece.locked = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
|
||||
@@ -384,9 +384,9 @@ function CRS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||
for idx, offset in pairs(kicks) do
|
||||
kicked_piece = new_piece:withOffset(offset)
|
||||
if grid:canPlacePiece(kicked_piece) then
|
||||
self:onPieceRotate(piece, grid)
|
||||
piece:setRelativeRotation(rot_dir)
|
||||
piece:setOffset(offset)
|
||||
self:onPieceRotate(piece, grid)
|
||||
return
|
||||
end
|
||||
end
|
||||
|
||||
@@ -1,275 +0,0 @@
|
||||
local Ruleset = require 'tetris.rulesets.ruleset'
|
||||
|
||||
local PAIRS = Ruleset:extend()
|
||||
|
||||
PAIRS.name = "PAIRS"
|
||||
PAIRS.hash = "PAIRS"
|
||||
PAIRS.world = true
|
||||
|
||||
PAIRS.spawn_positions = {
|
||||
[1] = { x=4, y=4 },
|
||||
[2] = { x=4, y=5 },
|
||||
[3] = { x=4, y=5 },
|
||||
[4] = { x=4, y=5 },
|
||||
[5] = { x=5, y=5 },
|
||||
[6] = { x=5, y=5 },
|
||||
[7] = { x=5, y=5 },
|
||||
[8] = { x=5, y=5 },
|
||||
[9] = { x=5, y=5 },
|
||||
[10] = { x=5, y=5 },
|
||||
[11] = { x=4, y=5 },
|
||||
[12] = { x=4, y=5 },
|
||||
[13] = { x=4, y=5 },
|
||||
[14] = { x=4, y=5 },
|
||||
[15] = { x=4, y=5 },
|
||||
[16] = { x=4, y=5 },
|
||||
[17] = { x=4, y=5 },
|
||||
[18] = { x=4, y=5 },
|
||||
}
|
||||
|
||||
PAIRS.big_spawn_positions = {
|
||||
[1] = { x=2, y=2 },
|
||||
[2] = { x=2, y=3 },
|
||||
[3] = { x=2, y=3 },
|
||||
[4] = { x=2, y=3 },
|
||||
[5] = { x=3, y=3 },
|
||||
[6] = { x=3, y=3 },
|
||||
[7] = { x=3, y=3 },
|
||||
[8] = { x=3, y=3 },
|
||||
[9] = { x=3, y=3 },
|
||||
[10] = { x=3, y=3 },
|
||||
[11] = { x=2, y=3 },
|
||||
[12] = { x=2, y=3 },
|
||||
[13] = { x=2, y=3 },
|
||||
[14] = { x=2, y=3 },
|
||||
[15] = { x=2, y=3 },
|
||||
[16] = { x=2, y=3 },
|
||||
[17] = { x=2, y=3 },
|
||||
[18] = { x=2, y=3 },
|
||||
}
|
||||
|
||||
PAIRS.draw_offsets = {
|
||||
[1] = { x=0, y=0 },
|
||||
[2] = { x=0, y=0 },
|
||||
[3] = { x=0, y=0 },
|
||||
[4] = { x=0, y=0 },
|
||||
[5] = { x=0, y=0 },
|
||||
[6] = { x=0, y=0 },
|
||||
[7] = { x=0, y=0 },
|
||||
[8] = { x=0, y=0 },
|
||||
[9] = { x=0, y=0 },
|
||||
[10] = { x=0, y=0 },
|
||||
[11] = { x=0, y=0 },
|
||||
[12] = { x=0, y=0 },
|
||||
[13] = { x=0, y=0 },
|
||||
[14] = { x=0, y=0 },
|
||||
[15] = { x=0, y=0 },
|
||||
[16] = { x=0, y=0 },
|
||||
[17] = { x=0, y=0 },
|
||||
[18] = { x=0, y=0 },
|
||||
}
|
||||
|
||||
PAIRS.next_sounds = {
|
||||
[1] = "I",
|
||||
[2] = "O",
|
||||
[3] = "S",
|
||||
[4] = "Z",
|
||||
[5] = "L",
|
||||
[6] = "J",
|
||||
[7] = "Z",
|
||||
[8] = "S",
|
||||
[9] = "J",
|
||||
[10] = "L",
|
||||
[11] = "O",
|
||||
[12] = "O",
|
||||
[13] = "T",
|
||||
[14] = "L",
|
||||
[15] = "J",
|
||||
[16] = "T",
|
||||
[17] = "J",
|
||||
[18] = "I"
|
||||
}
|
||||
|
||||
PAIRS.colourscheme = {
|
||||
[1] = "R",
|
||||
[2] = "C",
|
||||
[3] = "G",
|
||||
[4] = "M",
|
||||
[5] = "O",
|
||||
[6] = "C",
|
||||
[7] = "G",
|
||||
[8] = "M",
|
||||
[9] = "G",
|
||||
[10] = "M",
|
||||
[11] = "Y",
|
||||
[12] = "B",
|
||||
[13] = "M",
|
||||
[14] = "O",
|
||||
[15] = "B",
|
||||
[16] = "G",
|
||||
[17] = "C",
|
||||
[18] = "R"
|
||||
}
|
||||
|
||||
PAIRS.pieces = 18
|
||||
|
||||
PAIRS.block_offsets = {
|
||||
[1]={
|
||||
{ {x=-2, y=0}, {x=-1, y=0}, {x=0, y=0}, {x=1, y=0}, {x=2, y=0} },
|
||||
{ {x=0, y=-2}, {x=0, y=-1}, {x=0, y=0}, {x=0, y=1}, {x=0, y=2} },
|
||||
{ {x=-2, y=0}, {x=-1, y=0}, {x=0, y=0}, {x=1, y=0}, {x=2, y=0} },
|
||||
{ {x=0, y=-2}, {x=0, y=-1}, {x=0, y=0}, {x=0, y=1}, {x=0, y=2} },
|
||||
},
|
||||
[2]={
|
||||
{ {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=1, y=-1}, {x=-1, y=-1} },
|
||||
{ {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=1, y=-1}, {x=-1, y=-1} },
|
||||
{ {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=1, y=-1}, {x=-1, y=-1} },
|
||||
{ {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=1, y=-1}, {x=-1, y=-1} },
|
||||
},
|
||||
[3]={
|
||||
{ {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=1, y=-2}, {x=-1, y=0} },
|
||||
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=1, y=0}, {x=-1, y=-2} },
|
||||
{ {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=1, y=-2}, {x=-1, y=0} },
|
||||
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=1, y=0}, {x=-1, y=-2} },
|
||||
},
|
||||
[4]={
|
||||
{ {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=1, y=0}, {x=-1, y=-2} },
|
||||
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=-1, y=0}, {x=1, y=-2} },
|
||||
{ {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=1, y=0}, {x=-1, y=-2} },
|
||||
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=-1, y=0}, {x=1, y=-2} },
|
||||
},
|
||||
[5]={
|
||||
{ {x=1, y=-1}, {x=-2, y=0}, {x=-1, y=0}, {x=0, y=0}, {x=1, y=0} },
|
||||
{ {x=0, y=0}, {x=-1, y=-3}, {x=-1, y=-2}, {x=-1, y=-1}, {x=-1, y=0} },
|
||||
{ {x=-2, y=0}, {x=-2, y=-1}, {x=-1, y=-1}, {x=0, y=-1}, {x=1, y=-1} },
|
||||
{ {x=-1, y=-3}, {x=0, y=-3}, {x=0, y=-2}, {x=0, y=-1}, {x=0, y=0} },
|
||||
},
|
||||
[6]={
|
||||
{ {x=-2, y=-1}, {x=-2, y=0}, {x=-1, y=0}, {x=0, y=0}, {x=1, y=0} },
|
||||
{ {x=0, y=-3}, {x=-1, y=-3}, {x=-1, y=-2}, {x=-1, y=-1}, {x=-1, y=0} },
|
||||
{ {x=1, y=0}, {x=-2, y=-1}, {x=-1, y=-1}, {x=0, y=-1}, {x=1, y=-1} },
|
||||
{ {x=-1, y=0}, {x=0, y=-3}, {x=0, y=-2}, {x=0, y=-1}, {x=0, y=0} },
|
||||
},
|
||||
[7]={
|
||||
{ {x=-2, y=-1}, {x=-1, y=-1}, {x=-1, y=0}, {x=0, y=0}, {x=1, y=0} },
|
||||
{ {x=0, y=-3}, {x=0, y=-2}, {x=-1, y=-2}, {x=-1, y=-1}, {x=-1, y=0} },
|
||||
{ {x=-2, y=-1}, {x=-1, y=-1}, {x=0, y=-1}, {x=0, y=0}, {x=1, y=0} },
|
||||
{ {x=-1, y=0}, {x=0, y=-3}, {x=0, y=-2}, {x=0, y=-1}, {x=-1, y=-1} },
|
||||
},
|
||||
[8]={
|
||||
{ {x=1, y=-1}, {x=-2, y=0}, {x=-1, y=0}, {x=0, y=0}, {x=0, y=-1} },
|
||||
{ {x=0, y=0}, {x=-1, y=-3}, {x=-1, y=-2}, {x=-1, y=-1}, {x=0, y=-1} },
|
||||
{ {x=-2, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1}, {x=1, y=-1} },
|
||||
{ {x=-1, y=-3}, {x=-1, y=-2}, {x=0, y=-2}, {x=0, y=-1}, {x=0, y=0} },
|
||||
},
|
||||
[9]={
|
||||
{ {x=-1, y=-1}, {x=-2, y=0}, {x=-1, y=0}, {x=0, y=0}, {x=1, y=0} },
|
||||
{ {x=0, y=-2}, {x=-1, y=-3}, {x=-1, y=-2}, {x=-1, y=-1}, {x=-1, y=0} },
|
||||
{ {x=0, y=0}, {x=-2, y=-1}, {x=-1, y=-1}, {x=0, y=-1}, {x=1, y=-1} },
|
||||
{ {x=-1, y=-1}, {x=0, y=-3}, {x=0, y=-2}, {x=0, y=-1}, {x=0, y=0} },
|
||||
},
|
||||
[10]={
|
||||
{ {x=0, y=-1}, {x=-2, y=0}, {x=-1, y=0}, {x=0, y=0}, {x=1, y=0} },
|
||||
{ {x=0, y=-1}, {x=-1, y=-3}, {x=-1, y=-2}, {x=-1, y=-1}, {x=-1, y=0} },
|
||||
{ {x=-1, y=0}, {x=-2, y=-1}, {x=-1, y=-1}, {x=0, y=-1}, {x=1, y=-1} },
|
||||
{ {x=-1, y=-2}, {x=0, y=-3}, {x=0, y=-2}, {x=0, y=-1}, {x=0, y=0} },
|
||||
},
|
||||
[11]={
|
||||
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=0, y=-1}, {x=-1, y=-1} },
|
||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=-2}, {x=1, y=-1}, {x=1, y=-2} },
|
||||
{ {x=0, y=0}, {x=1, y=-1}, {x=1, y=0}, {x=0, y=-1}, {x=-1, y=-1} },
|
||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=-2}, {x=-1, y=-1}, {x=-1, y=0} },
|
||||
},
|
||||
[12]={
|
||||
{ {x=0, y=0}, {x=1, y=-1}, {x=1, y=0}, {x=0, y=-1}, {x=-1, y=0} },
|
||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=-2}, {x=1, y=-1}, {x=1, y=0} },
|
||||
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=-1}, {x=0, y=-1}, {x=-1, y=-1} },
|
||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=-2}, {x=-1, y=-1}, {x=-1, y=-2} },
|
||||
},
|
||||
[13]={
|
||||
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=-1, y=-1}, {x=1, y=-1} },
|
||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=-2}, {x=1, y=0}, {x=1, y=-2} },
|
||||
{ {x=0, y=-1}, {x=-1, y=0}, {x=1, y=0}, {x=-1, y=-1}, {x=1, y=-1} },
|
||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=-2}, {x=-1, y=0}, {x=-1, y=-2} },
|
||||
},
|
||||
[14]={
|
||||
{ {x=0, y=-1}, {x=0, y=0}, {x=0, y=-2}, {x=-1, y=-1}, {x=1, y=0} },
|
||||
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=0, y=-2}, {x=-1, y=0} },
|
||||
{ {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=1, y=-1}, {x=-1, y=-2} },
|
||||
{ {x=0, y=-1}, {x=1, y=-1}, {x=-1, y=-1}, {x=0, y=0}, {x=1, y=-2} },
|
||||
},
|
||||
[15]={
|
||||
{ {x=0, y=-1}, {x=0, y=0}, {x=0, y=-2}, {x=-1, y=0}, {x=1, y=-1} },
|
||||
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=-1, y=-2}, {x=0, y=0} },
|
||||
{ {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=1, y=-2}, {x=-1, y=-1} },
|
||||
{ {x=0, y=-1}, {x=1, y=-1}, {x=-1, y=-1}, {x=1, y=0}, {x=0, y=-2} },
|
||||
},
|
||||
[16]={
|
||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=-2}, {x=-1, y=0}, {x=1, y=0} },
|
||||
{ {x=-1, y=0}, {x=0, y=-1}, {x=-1, y=-2}, {x=-1, y=-1}, {x=1, y=-1} },
|
||||
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=-2}, {x=-1, y=-2}, {x=1, y=-2} },
|
||||
{ {x=1, y=0}, {x=0, y=-1}, {x=1, y=-2}, {x=-1, y=-1}, {x=1, y=-1} },
|
||||
},
|
||||
[17]={
|
||||
{ {x=0, y=0}, {x=1, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=-1, y=-2} },
|
||||
{ {x=0, y=-2}, {x=1, y=-2}, {x=-1, y=0}, {x=-1, y=-1}, {x=-1, y=-2} },
|
||||
{ {x=0, y=-2}, {x=1, y=0}, {x=-1, y=-2}, {x=1, y=-1}, {x=1, y=-2} },
|
||||
{ {x=0, y=0}, {x=1, y=0}, {x=-1, y=0}, {x=1, y=-1}, {x=1, y=-2} },
|
||||
},
|
||||
[18]={
|
||||
{ {x=1, y=0}, {x=0, y=0}, {x=0, y=-1}, {x=-1, y=-1}, {x=-1, y=-2} },
|
||||
{ {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1}, {x=0, y=-2}, {x=1, y=-2} },
|
||||
{ {x=-1, y=-2}, {x=0, y=-2}, {x=0, y=-1}, {x=1, y=-1}, {x=1, y=0} },
|
||||
{ {x=1, y=-2}, {x=1, y=-1}, {x=0, y=-1}, {x=0, y=0}, {x=-1, y=0} },
|
||||
},
|
||||
}
|
||||
|
||||
PAIRS.wallkicks = {
|
||||
{x=1, y=0}, {x=-1, y=0}, {x=2, y=0}, {x=-2, y=0}, {x=0, y=-1}
|
||||
}
|
||||
|
||||
function PAIRS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||
if (piece.shape == 2) then return end
|
||||
|
||||
local kicks = PAIRS.wallkicks
|
||||
|
||||
assert(piece.rotation ~= new_piece.rotation)
|
||||
|
||||
for idx, offset in pairs(kicks) do
|
||||
kicked_piece = new_piece:withOffset(offset)
|
||||
if grid:canPlacePiece(kicked_piece) then
|
||||
self:onPieceRotate(piece, grid)
|
||||
piece:setRelativeRotation(rot_dir)
|
||||
piece:setOffset(offset)
|
||||
return
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PAIRS:checkNewLow(piece)
|
||||
for _, block in pairs(piece:getBlockOffsets()) do
|
||||
local y = piece.position.y + block.y
|
||||
if y > piece.lowest_y then
|
||||
piece.lock_delay = 0
|
||||
piece.lowest_y = y
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function PAIRS:onPieceCreate(piece, grid)
|
||||
piece.lowest_y = -math.huge
|
||||
end
|
||||
|
||||
function PAIRS:onPieceDrop(piece, grid)
|
||||
self:checkNewLow(piece)
|
||||
end
|
||||
|
||||
function PAIRS:get180RotationValue()
|
||||
if config.gamesettings.world_reverse == 1 then
|
||||
return 1
|
||||
else
|
||||
return 3
|
||||
end
|
||||
end
|
||||
|
||||
return PAIRS
|
||||
@@ -35,73 +35,30 @@ Ruleset.next_sounds = {
|
||||
T = "T"
|
||||
}
|
||||
|
||||
Ruleset.draw_offsets = {
|
||||
I = { x=0, y=0 },
|
||||
J = { x=0, y=0 },
|
||||
L = { x=0, y=0 },
|
||||
O = { x=0, y=0 },
|
||||
S = { x=0, y=0 },
|
||||
T = { x=0, y=0 },
|
||||
Z = { x=0, y=0 },
|
||||
}
|
||||
|
||||
Ruleset.pieces = 7
|
||||
|
||||
-- Component functions.
|
||||
|
||||
function Ruleset:new()
|
||||
|
||||
function Ruleset:new(game_mode)
|
||||
self.game = game_mode
|
||||
local bones
|
||||
if config.gamesettings.piece_colour == 1 then
|
||||
blocks["bone"] = (not self.world) and
|
||||
{
|
||||
R = love.graphics.newImage("res/img/bone.png"),
|
||||
O = love.graphics.newImage("res/img/bone.png"),
|
||||
Y = 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"),
|
||||
F = love.graphics.newImage("res/img/bone.png"),
|
||||
A = love.graphics.newImage("res/img/bone.png"),
|
||||
X = love.graphics.newImage("res/img/bone.png"),
|
||||
} or {
|
||||
R = love.graphics.newImage("res/img/bonew.png"),
|
||||
O = love.graphics.newImage("res/img/bonew.png"),
|
||||
Y = love.graphics.newImage("res/img/bonew.png"),
|
||||
G = love.graphics.newImage("res/img/bonew.png"),
|
||||
C = love.graphics.newImage("res/img/bonew.png"),
|
||||
B = love.graphics.newImage("res/img/bonew.png"),
|
||||
M = love.graphics.newImage("res/img/bonew.png"),
|
||||
F = love.graphics.newImage("res/img/bonew.png"),
|
||||
A = love.graphics.newImage("res/img/bonew.png"),
|
||||
X = love.graphics.newImage("res/img/bonew.png"),
|
||||
}
|
||||
bones = self.world and "w" or ""
|
||||
else
|
||||
blocks["bone"] = (config.gamesettings.piece_colour == 2) and
|
||||
{
|
||||
R = love.graphics.newImage("res/img/bone.png"),
|
||||
O = love.graphics.newImage("res/img/bone.png"),
|
||||
Y = 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"),
|
||||
F = love.graphics.newImage("res/img/bone.png"),
|
||||
A = love.graphics.newImage("res/img/bone.png"),
|
||||
X = love.graphics.newImage("res/img/bone.png"),
|
||||
} or {
|
||||
R = love.graphics.newImage("res/img/bonew.png"),
|
||||
O = love.graphics.newImage("res/img/bonew.png"),
|
||||
Y = love.graphics.newImage("res/img/bonew.png"),
|
||||
G = love.graphics.newImage("res/img/bonew.png"),
|
||||
C = love.graphics.newImage("res/img/bonew.png"),
|
||||
B = love.graphics.newImage("res/img/bonew.png"),
|
||||
M = love.graphics.newImage("res/img/bonew.png"),
|
||||
F = love.graphics.newImage("res/img/bonew.png"),
|
||||
A = love.graphics.newImage("res/img/bonew.png"),
|
||||
X = love.graphics.newImage("res/img/bonew.png"),
|
||||
}
|
||||
bones = config.gamesettings.piece_colour == 3 and "w" or ""
|
||||
end
|
||||
blocks.bone = {
|
||||
R = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
|
||||
O = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
|
||||
Y = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
|
||||
G = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
|
||||
C = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
|
||||
B = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
|
||||
M = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
|
||||
F = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
|
||||
A = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
|
||||
X = love.graphics.newImage("res/img/bone" .. bones .. ".png"),
|
||||
}
|
||||
end
|
||||
|
||||
function Ruleset:rotatePiece(inputs, piece, grid, prev_inputs, initial)
|
||||
@@ -166,6 +123,7 @@ function Ruleset:movePiece(piece, grid, move, instant)
|
||||
local was_drop_blocked = piece:isDropBlocked(grid)
|
||||
local offset = ({x=0, y=0})
|
||||
local moves = 0
|
||||
local y = piece.position.y
|
||||
if move == "left" then
|
||||
offset.x = -1
|
||||
moves = 1
|
||||
@@ -194,6 +152,9 @@ function Ruleset:movePiece(piece, grid, move, instant)
|
||||
if not was_drop_blocked and piece:isDropBlocked(grid) then
|
||||
playSE("bottom")
|
||||
end
|
||||
if instant and piece.position.y ~= y then
|
||||
self:onPieceDrop(piece, grid)
|
||||
end
|
||||
end
|
||||
|
||||
function Ruleset:dropPiece(
|
||||
@@ -237,13 +198,19 @@ end
|
||||
|
||||
function Ruleset:get180RotationValue() return 2 end
|
||||
function Ruleset:getDefaultOrientation() return 1 end
|
||||
function Ruleset:getDrawOffset(shape, orientation) return { x=0, y=0 } end
|
||||
function Ruleset:getAboveFieldOffset(shape, orientation)
|
||||
if shape == "I" then
|
||||
return 1
|
||||
else
|
||||
return 2
|
||||
end
|
||||
end
|
||||
|
||||
function Ruleset:initializePiece(
|
||||
inputs, data, grid, gravity, prev_inputs,
|
||||
move, lock_delay, drop_speed,
|
||||
drop_locked, hard_drop_locked, big, irs,
|
||||
buffer_hard_drop, buffer_soft_drop,
|
||||
lock_on_hard_drop, lock_on_soft_drop
|
||||
drop_locked, hard_drop_locked, big, irs
|
||||
)
|
||||
local spawn_positions
|
||||
if big then
|
||||
@@ -251,13 +218,19 @@ function Ruleset:initializePiece(
|
||||
else
|
||||
spawn_positions = self.spawn_positions
|
||||
end
|
||||
local colours = ({self.colourscheme, ColourSchemes.Arika, ColourSchemes.TTC})[config.gamesettings.piece_colour]
|
||||
|
||||
local colours
|
||||
if self.pieces == 7 then
|
||||
colours = ({self.colourscheme, ColourSchemes.Arika, ColourSchemes.TTC})[config.gamesettings.piece_colour]
|
||||
else
|
||||
colours = self.colourscheme
|
||||
end
|
||||
|
||||
local spawn_x
|
||||
if (grid.width ~= 10) then
|
||||
local percent = spawn_positions[data.shape].x / 10
|
||||
for i = 0, grid.width - 1 do
|
||||
if i / grid.width >= percent then
|
||||
for i = grid.width - 1, 0, -1 do
|
||||
if i / grid.width <= percent then
|
||||
spawn_x = i
|
||||
break
|
||||
end
|
||||
@@ -267,17 +240,18 @@ function Ruleset:initializePiece(
|
||||
local spawn_dy
|
||||
if (config.gamesettings.spawn_positions == 1) then
|
||||
spawn_dy = (
|
||||
self.spawn_above_field and 2 or 0
|
||||
self.spawn_above_field and
|
||||
self:getAboveFieldOffset(data.shape, data.orientation) or 0
|
||||
)
|
||||
else
|
||||
spawn_dy = (
|
||||
config.gamesettings.spawn_positions == 3 and
|
||||
2 or 0
|
||||
self:getAboveFieldOffset(data.shape, data.orientation) or 0
|
||||
)
|
||||
end
|
||||
|
||||
local piece = Piece(data.shape, data.orientation - 1, {
|
||||
x = spawn_x and spawn_x or spawn_positions[data.shape].x,
|
||||
x = spawn_x or spawn_positions[data.shape].x,
|
||||
y = spawn_positions[data.shape].y - spawn_dy
|
||||
}, self.block_offsets, 0, 0, data.skin, colours[data.shape], big)
|
||||
|
||||
@@ -289,13 +263,6 @@ function Ruleset:initializePiece(
|
||||
end
|
||||
end
|
||||
self:dropPiece(inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked)
|
||||
if (buffer_hard_drop and config.gamesettings.buffer_lock == 1) then
|
||||
piece:dropToBottom(grid)
|
||||
if lock_on_hard_drop then piece.locked = true end
|
||||
end
|
||||
if (buffer_soft_drop and lock_on_soft_drop and piece:isDropBlocked(grid) and config.gamesettings.buffer_lock == 1) then
|
||||
piece.locked = true
|
||||
end
|
||||
return piece
|
||||
end
|
||||
|
||||
@@ -308,6 +275,7 @@ function Ruleset:processPiece(
|
||||
drop_locked, hard_drop_locked,
|
||||
hard_drop_enabled, additive_gravity, classic_lock
|
||||
)
|
||||
if piece.locked then return end
|
||||
|
||||
local synchroes_allowed = ({not self.world, true, false})[config.gamesettings.synchroes_allowed]
|
||||
|
||||
|
||||
Reference in New Issue
Block a user