Compare commits

..

1 Commits

Author SHA1 Message Date
Ishaan Bhardwaj
9f570306f5 Init 2021-01-26 13:36:50 -05:00
35 changed files with 389 additions and 650 deletions

View File

@@ -1,13 +1,13 @@
![Cambridge Banner](https://t-sp.in/public/img/cambridge.png)
![Cambridge Banner](https://cdn.discordapp.com/attachments/764432435802013709/767724895076614154/cambridge_logo_lt.png)
Cambridge
=========
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)!
This fork is written and maintained exclusively by [SashLilac](https://github.com/SashLilac), [joezeng](https://github.com/joezeng) and [Oshisaure](https://github.com/oshisaure)!
The game also has a website now with more detail than seen on this README: https://t-sp.in/cambridge
Join our Discord server for help and a welcoming community! https://discord.gg/mteMJw4
Credits
-------
@@ -17,7 +17,19 @@ Credits
- [The Tetra Legends Discord](http://discord.com/invite/7hMx5r2) for supporting me and playtesting!
- [The Absolute Plus](https://discord.gg/6Gf2awJ) for being another source of motivation!
More special thanks can be found in-game, under the "Credits" menu.
The following people in no particular order also helped with the project:
- [Hailey](https://github.com/haileylgbt)
- CylinderKnot
- MarkGamed7794
- [Mizu](https://github.com/rexxt)
- MattMayuga
- Kitaru
- switchpalacecorner
- [sinefuse](https://github.com/sinefuse)
- [2Tie](https://github.com/2Tie)
- [nightmareci](https://github.com/nightmareci)
- [MyPasswordIsWeak](https://github.com/MyPasswordIsWeak)
- [Dr Ocelot](https://github.com/Dr-Ocelot)
![Cambridge Logo](https://cdn.discordapp.com/attachments/625496179433668635/763363717730664458/Icon_2.png)
@@ -28,13 +40,7 @@ Playing the game
You do not need LÖVE on Windows, as it comes bundled with the program.
#### Stable release
To get the stable release, simply download either `cambridge-win32.zip` (32-bit) or `cambridge-windows.zip` (64-bit) in the [latest release](https://github.com/sashlilac/cambridge/releases/latest).
All assets needed are bundled with the executable.
#### Bleeding edge
To get the stable release, simply download the ZIP in the latest release. All assets needed are bundled with the executable.
If you want the bleeding edge version, download [this](https://github.com/SashLilac/cambridge/archive/master.zip).
@@ -76,7 +82,13 @@ It should run automatically!
## Installing modpacks
For instructions on how to install modpacks, go to [this](https://github.com/SashLilac/cambridge-modpack) mod pack to get a taste of the mod potential.
Simply drag your mode, ruleset, and randomizer Lua files into their respective [directory](https://love2d.org/wiki/love.filesystem), and they should appear automatically.
You can also load custom assets through this way, assuming you preserve the directory structure.
**WARNING:** The .exe / .love files and the bleeding edge releases have different save directories. Read the above link carefully!
For more detailed instructions, install [this](https://github.com/SashLilac/cambridge-modpack) mod pack to get a taste of the mod potential.
License
-------

View File

@@ -3,11 +3,19 @@ Game modes
There are several classes of game modes. The modes that originate from other games are organized by suffix:
* The "C" series stand for "Classic" games, games that were produced before around 1992-1993 and generally have no wallkicks or lock delay.
* C84 - The original version from the Electronika 60.
* C88 - Sega Tetris.
* C89 - Nintendo / NES Tetris.
* The "A" series stand for "Arika" games, or games in the Tetris the Grand Master series.
* A1 - Tetris The Grand Master (the original from 1998).
* A2 - Tetris The Absolute The Grand Master 2 PLUS.
* A3 - Tetris The Grand Master 3 Terror-Instinct.
* AX - Tetris The Grand Master ACE (X for Xbox).
* The "G" series stand for "Guideline" games, or games that follow the Tetris Guideline.
* GF - Tetris Friends (2007-2019)
* GJ - Tetris Online Japan (2005-2011)
* N stands for Nullpomino, only used for Phantom Mania N.
MARATHON
--------
@@ -20,6 +28,8 @@ From other games:
* **MARATHON A1**: Tetris the Grand Master 1.
* **MARATHON A2**: Tetris the Grand Master 2 (TAP Master).
* **MARATHON A3**: Tetris the Grand Master 3 (no exams).
* **MARATHON AX4**: Another mode from TGM Ace.
* **MARATHON C89**: Nintendo NES Tetris. Can you transition and make it to the killscreen?
SURVIVAL
@@ -33,7 +43,14 @@ From other games:
* **SURVIVAL A1**: 20G mode from Tetris the Grand Master.
* **SURVIVAL A2**: T.A. Death.
* **SURVIVAL A3**: Ti Shirase.
* **SURVIVAL AX**: Another mode from TGM Ace.
RACE
----
Modes with no levels, just a single timed goal.
* **Race 40**: How fast can you clear 40 lines? No limits, no holds barred.
PHANTOM MANIA
@@ -52,4 +69,8 @@ OTHER MODES
* **Strategy**: How well can you plan ahead your movements? Can you handle only having a short time to place each piece?
* **Big A2**: Marathon A2 but all the pieces are BIG!
* **TetrisGram™ Pacer Test**: is a multi-stage piece-placing ability test that progressively gets more difficult as it continues.
* **Interval Training**: 30 seconds per section. 20G. 15 frames of lock delay. How long can you last?
* **Demon Mode**: An original mode from Oshisaure! Can you push through the ever faster levels and not get denied?

View File

@@ -86,7 +86,3 @@ function table.contains(table, element)
end
return false
end
function clamp(a, b, c)
return math.min(a, math.max(b, c))
end

View File

@@ -2,7 +2,7 @@
-- If this variable is true, then strict type checking is performed for all
-- operations. This may result in slower code, but it will allow you to catch
-- errors and bugs earlier.
local strict = false
local strict = true
--------------------------------------------------------------------------------
@@ -33,7 +33,12 @@ function bigint.new(num)
return bigint.add(lhs, rhs)
end,
__unm = function()
return bigint.negate(self)
if (self.sign == "+") then
self.sign = "-"
else
self.sign = "+"
end
return self
end,
__sub = function(lhs, rhs)
return bigint.subtract(lhs, rhs)
@@ -50,6 +55,15 @@ function bigint.new(num)
__pow = function(lhs, rhs)
return bigint.exponentiate(lhs, rhs)
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,
__tostring = function()
return bigint.unserialize(self, "s")
end
@@ -77,8 +91,7 @@ function bigint.check(big, force)
assert(type(big.sign) == "string", "bigint is unsigned")
for _, digit in pairs(big.digits) do
assert(type(digit) == "number", digit .. " is not a number")
assert(digit <= 9 and digit >= 0, digit .. " is not between 0 and 9")
assert(math.floor(digit) == digit, digit .. " is not an integer")
assert(digit < 10, digit .. " is greater than or equal to 10")
end
end
return true
@@ -93,24 +106,6 @@ function bigint.abs(big)
return result
end
-- Return a new big with the same digits but the opposite sign (negation)
function bigint.negate(big)
bigint.check(big)
local result = big:clone()
if (result.sign == "+") then
result.sign = "-"
else
result.sign = "+"
end
return result
end
-- Return the number of digits in the big
function bigint.digits(big)
bigint.check(big)
return #big.digits
end
-- Convert a big to a number or string
function bigint.unserialize(big, output_type, precision)
bigint.check(big)
@@ -145,7 +140,7 @@ function bigint.unserialize(big, output_type, precision)
-- Unserialization to human-readable form or scientific notation only
-- requires reading the first few digits
if (precision == nil) then
precision = math.min(#big.digits, 3)
precision = 3
else
assert(precision > 0, "Precision cannot be less than 1")
assert(math.floor(precision) == precision,
@@ -154,18 +149,17 @@ function bigint.unserialize(big, output_type, precision)
-- num is the first (precision + 1) digits, the first being separated by
-- a decimal point from the others
num = num .. math.floor(big.digits[1])
num = num .. big.digits[1]
if (precision > 1) then
num = num .. "."
for i = 1, (precision - 1) do
num = num .. math.floor(big.digits[i + 1])
num = num .. big.digits[i + 1]
end
end
if ((output_type == "human-readable")
or (output_type == "human")
or (output_type == "h"))
and (#big.digits >= 3 and #big.digits <= 10002) then
or (output_type == "h")) then
-- Human-readable output contributed by 123eee555
local name
@@ -444,6 +438,7 @@ function bigint.multiply(big1, big2)
return result
end
-- Raise a big to a positive integer or big power (TODO: negative integer power)
function bigint.exponentiate(big, power)
-- Type checking for big done by bigint.multiply
@@ -454,23 +449,13 @@ function bigint.exponentiate(big, power)
if (bigint.compare(exp, bigint.new(0), "==")) then
return bigint.new(1)
elseif (bigint.compare(exp, bigint.new(1), "==")) then
return big:clone()
return big
else
local result = bigint.new(1)
local base = big:clone()
local result = big:clone()
while (true) do
if (bigint.compare(
bigint.modulus(exp, bigint.new(2)), bigint.new(1), "=="
)) then
result = bigint.multiply(result, base)
end
if (bigint.compare(exp, bigint.new(1), "==")) then
break
else
exp = bigint.divide(exp, bigint.new(2))
base = bigint.multiply(base, base)
end
while (bigint.compare(exp, bigint.new(1), ">")) do
result = bigint.multiply(result, big)
exp = bigint.subtract(exp, bigint.new(1))
end
return result
@@ -486,7 +471,7 @@ function bigint.divide_raw(big1, big2)
if (bigint.compare(big1, big2, "==")) then
return bigint.new(1), bigint.new(0)
elseif (bigint.compare(big1, big2, "<")) then
return bigint.new(0), big1:clone()
return bigint.new(0), bigint.new(0)
else
assert(bigint.compare(big2, bigint.new(0), "!="), "error: divide by zero")
assert(big1.sign == "+", "error: big1 is not positive")
@@ -494,35 +479,54 @@ function bigint.divide_raw(big1, big2)
local result = bigint.new()
local dividend = bigint.new() -- Dividend of a single operation
local dividend = bigint.new() -- Dividend of a single operation, not the
-- dividend of the overall function
local divisor = big2:clone()
local factor = 1
local neg_zero = bigint.new(0)
neg_zero.sign = "-"
-- Walk left to right among digits in the dividend, like in long
-- division
for _, digit in pairs(big1.digits) do
dividend.digits[#dividend.digits + 1] = digit
for i = 1, #big1.digits do
-- Fixes a negative zero bug
if (#dividend.digits ~= 0) and (bigint.compare(dividend, neg_zero, "==")) then
dividend = bigint.new()
-- The dividend is smaller than the divisor, so a zero is appended
-- to the result and the loop ends
if (bigint.compare(dividend, divisor, "<")) then
if (#result.digits > 0) then -- Don't add leading zeroes
result.digits[#result.digits + 1] = 0
end
else
-- Find the maximum number of divisors that fit into the
-- dividend
factor = 0
while (bigint.compare(divisor, dividend, "<=")) do
divisor = bigint.add(divisor, big2)
factor = factor + 1
end
table.insert(dividend.digits, big1.digits[i])
local factor = bigint.new(0)
while bigint.compare(dividend, big2, ">=") do
dividend = bigint.subtract(dividend, big2)
factor = bigint.add(factor, bigint.new(1))
-- Append the factor to the result
if (factor == 10) then
-- Fixes a weird bug that introduces a new bug if fixed by
-- changing the comparison in the while loop to "<="
result.digits[#result.digits] = 1
result.digits[#result.digits + 1] = 0
else
result.digits[#result.digits + 1] = factor
end
for i = 0, #factor.digits - 1 do
result.digits[#result.digits + 1 - i] = factor.digits[i + 1]
end
-- Subtract the divisor from the dividend to obtain the
-- remainder, which is the new dividend for the next loop
dividend = bigint.subtract(dividend,
bigint.subtract(divisor, big2))
-- Reset the divisor
divisor = big2:clone()
end
-- Remove leading zeros from result
while (result.digits[1] == 0) do
table.remove(result.digits, 1)
end
-- The remainder of the final loop is returned as the function's
-- overall remainder
return result, dividend
end
end

View File

@@ -16,9 +16,6 @@ function love.load()
love.window.setMode(love.graphics.getWidth(), love.graphics.getHeight(), {resizable = true});
-- used for screenshots
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
@@ -111,9 +108,6 @@ function love.update(dt)
end
function love.draw()
love.graphics.setCanvas(GLOBAL_CANVAS)
love.graphics.clear()
love.graphics.push()
-- get offset matrix
@@ -129,10 +123,6 @@ function love.draw()
scene:render()
love.graphics.pop()
love.graphics.setCanvas()
love.graphics.setColor(1,1,1,1)
love.graphics.draw(GLOBAL_CANVAS)
end
function love.keypressed(key, scancode)
@@ -150,14 +140,6 @@ function love.keypressed(key, scancode)
scene.restart_message = true
if config.secret then playSE("mode_decide")
else playSE("erase") end
-- 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
print("Saving screenshot as "..ss_name)
GLOBAL_CANVAS:newImageData():encode("png", ss_name)
-- function keys are reserved
elseif string.match(scancode, "^f[1-9]$") or string.match(scancode, "^f[1-9][0-9]+$") then
return
@@ -279,8 +261,3 @@ function love.focus(f)
pauseBGM()
end
end
function love.resize(w, h)
GLOBAL_CANVAS:release()
GLOBAL_CANVAS = love.graphics.newCanvas(w, h)
end

View File

@@ -1,2 +1,2 @@
tar -a -c -f cambridge.zip libs load res scene tetris conf.lua main.lua scene.lua funcs.lua
tar -a -c -f cambridge.zip libs/binser.lua libs/classic.lua libs/simple-slider.lua libs/discordRPC.lua load res scene tetris conf.lua main.lua scene.lua funcs.lua
rename cambridge.zip cambridge.love

Binary file not shown.

Before

Width:  |  Height:  |  Size: 1.8 KiB

After

Width:  |  Height:  |  Size: 1.3 KiB

Binary file not shown.

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.1 KiB

After

Width:  |  Height:  |  Size: 1.7 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.7 KiB

After

Width:  |  Height:  |  Size: 2.2 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.4 KiB

After

Width:  |  Height:  |  Size: 1.9 KiB

View File

@@ -83,7 +83,6 @@ function GameScene:render()
end
self.game:drawGrid()
if self.game.lcd > 0 then self.game:drawLineClearAnimation() end
self.game:drawPiece()
self.game:drawNextQueue(self.ruleset)
self.game:drawScoringInfo()
@@ -140,8 +139,19 @@ function GameScene:onInputRelease(e)
end
function submitHighscore(hash, data)
function isHighscore(score, high)
for k, _ in pairs(score) do
if not high[k] or score[k] > high[k] then
return true
end
end
return false
end
if not highscores[hash] then highscores[hash] = {} end
table.insert(highscores[hash], data)
if isHighscore(data, highscores[hash]) then
highscores[hash] = data
end
saveHighscores()
end

View File

@@ -11,7 +11,7 @@ ConfigScene.options = {
{"manlock", "Manual Locking", false, {"Per ruleset", "Per gamemode", "Harddrop", "Softdrop"}},
{"piece_colour", "Piece Colours", false, {"Per ruleset", "Arika", "TTC"}},
{"world_reverse", "A Button Rotation", false, {"Left", "Auto", "Right"}},
{"spawn_positions", "Spawn Positions", false, {"Per ruleset", "In field", "Out of field"}},
{"spawn_positions", "Spawn Positions", false, {"In field", "Out of field"}},
{"display_gamemode", "Display Gamemode", false, {"On", "Off"}},
{"das_last_key", "DAS Switch", false, {"Default", "Instant"}},
{"smooth_movement", "Smooth Piece Drop", false, {"On", "Off"}},
@@ -103,7 +103,7 @@ function ConfigScene:onInputPress(e)
else
playSE("cursor")
sld = self[self.options[self.highlight][4]]
sld.value = math.max(sld.min, math.min(sld.max, (sld:getValue() - 5) / (sld.max - sld.min)))
sld.value = math.max(sld.min, math.min(sld.max, (sld:getValue() - 3) / (sld.max - sld.min)))
end
elseif e.input == "right" or e.scancode == "right" then
if not self.options[self.highlight][3] then
@@ -113,7 +113,7 @@ function ConfigScene:onInputPress(e)
else
playSE("cursor")
sld = self[self.options[self.highlight][4]]
sld.value = math.max(sld.min, math.min(sld.max, (sld:getValue() + 5) / (sld.max - sld.min)))--math.max(0, (math.floor(sld:getValue())+2)/(sld.max-sld.min))
sld.value = math.max(sld.min, math.min(sld.max, (sld:getValue() + 3) / (sld.max - sld.min)))--math.max(0, (math.floor(sld:getValue())+2)/(sld.max-sld.min))
end
elseif e.input == "menu_back" or e.scancode == "delete" or e.scancode == "backspace" then
loadSave()

View File

@@ -31,7 +31,6 @@ end
function ConfigScene:new()
self.input_state = 1
self.key = 1
self.set_inputs = newSetInputs()
self.new_input = {}
self.axis_timer = 0
@@ -63,7 +62,7 @@ function ConfigScene:render()
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("press key or joystick 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
@@ -98,28 +97,18 @@ function ConfigScene:onInputPress(e)
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.set_inputs[configurable_inputs[self.input_state]] = "skipped"
self.input_state = self.input_state + 1
self.key = 1
else
self.key = 2
end
elseif e.scancode ~= "escape" and self.key == 1 then
elseif e.scancode ~= "escape" 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
self.input_state = self.input_state + 1
end
elseif string.sub(e.type, 1, 3) == "joy" and self.key == 2 then
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)
@@ -127,13 +116,11 @@ function ConfigScene:onInputPress(e)
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 " ..
"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)
@@ -144,13 +131,11 @@ function ConfigScene:onInputPress(e)
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 " ..
"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
@@ -164,13 +149,11 @@ function ConfigScene:onInputPress(e)
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 " ..
"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

View File

@@ -41,14 +41,14 @@ function ModeSelectScene:render()
elseif self.menu_state.select == "ruleset" then
love.graphics.setColor(1, 1, 1, 0.25)
end
love.graphics.rectangle("fill", 20, 258, 240, 22)
love.graphics.rectangle("fill", 20, 198, 240, 22)
if self.menu_state.select == "mode" then
love.graphics.setColor(1, 1, 1, 0.25)
elseif self.menu_state.select == "ruleset" then
love.graphics.setColor(1, 1, 1, 0.5)
end
love.graphics.rectangle("fill", 340, 258, 200, 22)
love.graphics.rectangle("fill", 340, 198, 200, 22)
love.graphics.setColor(1, 1, 1, 1)
@@ -56,13 +56,36 @@ function ModeSelectScene:render()
love.graphics.setFont(font_3x5_2)
for idx, mode in pairs(game_modes) do
if(idx >= self.menu_state.mode-9 and idx <= self.menu_state.mode+9) then
love.graphics.printf(mode.name, 40, (260 - 20*(self.menu_state.mode)) + 20 * idx, 200, "left")
if(idx >= self.menu_state.mode-6 and idx <= self.menu_state.mode+6) then
love.graphics.printf(mode.name, 40, (200 - 20*(self.menu_state.mode)) + 20 * idx, 200, "left")
end
end
for idx, ruleset in pairs(rulesets) do
if(idx >= self.menu_state.ruleset-9 and idx <= self.menu_state.ruleset+9) then
love.graphics.printf(ruleset.name, 360, (260 - 20*(self.menu_state.ruleset)) + 20 * idx, 160, "left")
if(idx >= self.menu_state.ruleset-6 and idx <= self.menu_state.ruleset+6) then
love.graphics.printf(ruleset.name, 360, (200 - 20*(self.menu_state.ruleset)) + 20 * idx, 160, "left")
end
end
-- mode description and highscore
for midx, mode in pairs(game_modes) do
for ridx, ruleset in pairs(rulesets) do
if (midx == self.menu_state.mode) and (ridx == self.menu_state.ruleset) then
love.graphics.printf(
"Mode Description:\n\n" .. mode.tagline, 20, 350, 200, "left"
)
love.graphics.printf(
ruleset.name .. " Highscore:", 240, 350, 200, "right"
)
local highscore_string = ""
if highscores[mode.hash .. "-" .. ruleset.hash] then
for k, v in ipairs(highscores[mode.hash .. "-" .. ruleset.hash]) do
highscore_string = highscore_string .. k .. ": " .. v .. "\n"
end
else
highscore_string = "You don't have any highscores yet!"
end
love.graphics.printf(highscore_string, 450, 350, 200, "left")
end
end
end
end

View File

@@ -111,24 +111,18 @@ function Grid:getClearedRowCount()
end
function Grid:markClearedRows()
local block_table = {}
for row = 1, self.height do
if self:isRowFull(row) then
block_table[row] = {}
for x = 1, self.width do
block_table[row][x] = {
skin = self.grid[row][x].skin,
colour = self.grid[row][x].colour,
}
self.grid[row][x] = {
skin = self.grid[row][x].skin,
colour = "X"
}
--self.grid_age[row][x] = 0
self.grid_age[row][x] = 0
end
end
end
return block_table
return true
end
function Grid:clearClearedRows()
@@ -394,8 +388,7 @@ end
function Grid:draw()
for y = 5, self.height do
for x = 1, self.width do
if blocks[self.grid[y][x].skin] and
blocks[self.grid[y][x].skin][self.grid[y][x].colour] then
if self.grid[y][x] ~= empty then
if self.grid_age[y][x] < 2 then
love.graphics.setColor(1, 1, 1, 1)
love.graphics.draw(blocks[self.grid[y][x].skin]["F"], 48+x*16, y*16)
@@ -403,8 +396,7 @@ function Grid:draw()
if self.grid[y][x].skin == "bone" then
love.graphics.setColor(1, 1, 1, 1)
elseif 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)
love.graphics.setColor(0.5, 0.5, 0.5, 1 - self.grid_age[y][x] / 15)
else
love.graphics.setColor(0.5, 0.5, 0.5, 1)
end
@@ -413,11 +405,11 @@ function Grid:draw()
if self.grid[y][x].skin ~= "bone" and self.grid[y][x].colour ~= "X" then
love.graphics.setColor(0.8, 0.8, 0.8, 1)
love.graphics.setLineWidth(1)
if y > 5 and self.grid[y-1][x] == empty or self.grid[y-1][x].colour == "X" then
if y > 1 and self.grid[y-1][x] == empty or self.grid[y-1][x].colour == "X" then
love.graphics.line(48.0+x*16, -0.5+y*16, 64.0+x*16, -0.5+y*16)
end
if y < self.height and self.grid[y+1][x] == empty or
(y + 1 <= self.height and self.grid[y+1][x].colour == "X") then
(y + 1 > self.height or self.grid[y+1][x].colour == "X") then
love.graphics.line(48.0+x*16, 16.5+y*16, 64.0+x*16, 16.5+y*16)
end
if x > 1 and self.grid[y][x-1] == empty then
@@ -435,20 +427,18 @@ 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)
if y > 5 and self.grid[y-1][x] == empty or self.grid[y-1][x].colour == "X" then
if y > 1 and self.grid[y-1][x] == empty or self.grid[y-1][x].colour == "X" then
love.graphics.line(48.0+x*16, -0.5+y*16, 64.0+x*16, -0.5+y*16)
end
if y < self.height and self.grid[y+1][x] == empty or
(y + 1 <= self.height and self.grid[y+1][x].colour == "X") then
(y + 1 > self.height or self.grid[y+1][x].colour == "X") then
love.graphics.line(48.0+x*16, 16.5+y*16, 64.0+x*16, 16.5+y*16)
end
if x > 1 and self.grid[y][x-1] == empty then
@@ -469,8 +459,7 @@ function Grid:drawInvisible(opacity_function, garbage_opacity_function, lock_fla
for x = 1, self.width do
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
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
@@ -482,11 +471,11 @@ function Grid:drawInvisible(opacity_function, garbage_opacity_function, lock_fla
if opacity > 0 and self.grid[y][x].colour ~= "X" then
love.graphics.setColor(0.64, 0.64, 0.64)
love.graphics.setLineWidth(1)
if y > 5 and self.grid[y-1][x] == empty or self.grid[y-1][x].colour == "X" then
if y > 1 and self.grid[y-1][x] == empty or self.grid[y-1][x].colour == "X" then
love.graphics.line(48.0+x*16, -0.5+y*16, 64.0+x*16, -0.5+y*16)
end
if y < self.height and self.grid[y+1][x] == empty or
(y + 1 <= self.height and self.grid[y+1][x].colour == "X") then
(y + 1 > self.height or self.grid[y+1][x].colour == "X") then
love.graphics.line(48.0+x*16, 16.5+y*16, 64.0+x*16, 16.5+y*16)
end
if x > 1 and self.grid[y][x-1] == empty then
@@ -517,19 +506,18 @@ function Grid:drawCustom(colour_function, gamestate)
if block ~= empty then
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
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)
if outline > 0 and self.grid[y][x].colour ~= "X" then
love.graphics.setColor(0.64, 0.64, 0.64, outline)
love.graphics.setLineWidth(1)
if y > 5 and self.grid[y-1][x] == empty or self.grid[y-1][x].colour == "X" then
if y > 1 and self.grid[y-1][x] == empty or self.grid[y-1][x].colour == "X" then
love.graphics.line(48.0+x*16, -0.5+y*16, 64.0+x*16, -0.5+y*16)
end
if y < self.height and self.grid[y+1][x] == empty or
(y + 1 <= self.height and self.grid[y+1][x].colour == "X") then
(y + 1 > self.height or self.grid[y+1][x].colour == "X") then
love.graphics.line(48.0+x*16, 16.5+y*16, 64.0+x*16, 16.5+y*16)
end
if x > 1 and self.grid[y][x-1] == empty then

View File

@@ -104,8 +104,9 @@ function Piece:dropToBottom(grid)
self:dropSquares(math.huge, grid)
self.gravity = 0
if self.position.y > piece_y then
-- if it got dropped any, also reset lock delay
if self.ghost == false then playSE("bottom") end
-- self.lock_delay = 0
self.lock_delay = 0
end
return self
end
@@ -117,15 +118,11 @@ function Piece:lockIfBottomed(grid)
return self
end
function Piece:addGravity(gravity, grid, classic_lock)
function Piece:addGravity(gravity, grid)
local new_gravity = self.gravity + gravity
if self:isDropBlocked(grid) then
if classic_lock then
self.gravity = math.min(1, new_gravity)
else
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

View File

@@ -10,9 +10,6 @@ local BagRandomizer = require 'tetris.randomizers.bag'
local GameMode = Object:extend()
GameMode.name = ""
GameMode.hash = ""
GameMode.tagline = ""
GameMode.rollOpacityFunction = function(age) return 0 end
function GameMode:new(secret_inputs)
@@ -45,7 +42,6 @@ function GameMode:new(secret_inputs)
self.enable_hard_drop = true
self.next_queue_length = 1
self.additive_gravity = true
self.classic_lock = false
self.draw_section_times = false
self.draw_secondary_section_times = false
self.big_mode = false
@@ -64,7 +60,6 @@ function GameMode:new(secret_inputs)
self.hard_drop_locked = false
self.lock_on_soft_drop = false
self.lock_on_hard_drop = false
self.cleared_block_table = {}
self.used_randomizer = nil
self.hold_queue = nil
self.held = false
@@ -81,7 +76,6 @@ function GameMode:getLockDelay() return 30 end
function GameMode:getLineClearDelay() return 40 end
function GameMode:getDasLimit() return 15 end
function GameMode:getDasCutDelay() return 0 end
function GameMode:getGravity() return 1/64 end
function GameMode:getNextPiece(ruleset)
return {
@@ -107,7 +101,7 @@ function GameMode:initialize(ruleset, secret_inputs)
BagRandomizer(ruleset.pieces)
)
)
for i = 1, math.max(self.next_queue_length, 1) do
for i = 1, self.next_queue_length do
table.insert(self.next_queue, self:getNextPiece(ruleset))
end
self.lock_on_soft_drop = ({ruleset.softdrop_lock, self.instant_soft_drop, false, true })[config.gamesettings.manlock]
@@ -137,7 +131,7 @@ function GameMode:update(inputs, ruleset)
-- set attempt flags
if inputs["left"] or inputs["right"] then
self:onAttemptPieceMove(self.piece, self.grid)
self:onAttemptPieceMove(self.piece)
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
@@ -150,7 +144,7 @@ function GameMode:update(inputs, ruleset)
inputs["rotate_left2"] or inputs["rotate_right2"] or
inputs["rotate_180"]
then
self:onAttemptPieceRotate(self.piece, self.grid)
self:onAttemptPieceRotate(self.piece)
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
@@ -173,38 +167,29 @@ function GameMode:update(inputs, ruleset)
if self.enable_hold and inputs["hold"] == true and self.held == false and self.prev_inputs["hold"] == false then
self:hold(inputs, ruleset)
self.prev_inputs = inputs
if not self.grid:canPlacePiece(self.piece) then
self.game_over = true
end
return
end
if (self.lock_drop or (
not ruleset.are or self:getARE() == 0
)) and inputs["down"] ~= true then
if self.lock_drop and inputs["down"] ~= true then
self.drop_locked = false
end
if (self.lock_hard_drop or (
not ruleset.are or self:getARE() == 0
)) and inputs["up"] ~= true then
if self.lock_hard_drop and inputs["up"] ~= true then
self.hard_drop_locked = false
end
-- diff vars to use in checks
local piece_y = self.piece.position.y
local piece_x = self.piece.position.x
local piece_rot = self.piece.rotation
ruleset:processPiece(
inputs, self.piece, self.grid, self:getGravity(), self.prev_inputs,
self.move, self:getLockDelay(), self:getDropSpeed(),
self.drop_locked, self.hard_drop_locked,
self.enable_hard_drop, self.additive_gravity, self.classic_lock
self.enable_hard_drop, self.additive_gravity
)
local piece_dy = self.piece.position.y - piece_y
local piece_dx = self.piece.position.x - piece_x
local piece_drot = self.piece.rotation - piece_rot
-- das cut
@@ -216,13 +201,12 @@ function GameMode:update(inputs, ruleset)
inputs.rotate_180
))
) then
self:dasCut()
self.das.frames = math.max(
self.das.frames - self:getDasCutDelay(),
-self:getDasCutDelay()
)
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 inputs["up"] == true and
self.piece:isDropBlocked(self.grid) and
not self.hard_drop_locked then
@@ -253,7 +237,7 @@ function GameMode:update(inputs, ruleset)
self:onPieceLock(self.piece, cleared_row_count)
self:updateScore(self.level, self.drop_bonus, cleared_row_count)
self.cleared_block_table = self.grid:markClearedRows()
self.grid:markClearedRows()
self.piece = nil
if self.enable_hold then
self.held = false
@@ -267,7 +251,6 @@ function GameMode:update(inputs, ruleset)
)
if self.lcd == 0 then
self.grid:clearClearedRows()
self:afterLineClear(cleared_row_count)
if self.are == 0 then
self:initializeOrHold(inputs, ruleset)
end
@@ -297,17 +280,13 @@ end
-- event functions
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:onAttemptPieceMove(piece) end
function GameMode:onAttemptPieceRotate(piece) end
function GameMode:onPieceLock(piece, cleared_row_count)
playSE("lock")
end
function GameMode:onLineClear(cleared_row_count) end
function GameMode:afterLineClear(cleared_row_count) end
function GameMode:onPieceEnter() end
function GameMode:onHold() end
@@ -396,13 +375,6 @@ function GameMode:chargeDAS(inputs)
end
end
function GameMode:dasCut()
self.das.frames = math.max(
self.das.frames - self:getDasCutDelay(),
-(self:getDasCutDelay() + 1)
)
end
function GameMode:areCancel(inputs, ruleset)
if ruleset.are_cancel and self.piece_hard_dropped and
not self.prev_inputs.up and
@@ -446,9 +418,7 @@ function GameMode:processDelays(inputs, ruleset, drop_speed)
self.lcd = self.lcd - 1
self:areCancel(inputs, ruleset)
if self.lcd == 0 then
local cleared_row_count = self.grid:getClearedRowCount()
self.grid:clearClearedRows()
self:afterLineClear(cleared_row_count)
playSE("fall")
if self.are == 0 then
self:initializeOrHold(inputs, ruleset)
@@ -536,14 +506,10 @@ function GameMode:initializeNextPiece(inputs, ruleset, piece_data, generate_next
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
if self.lock_drop then
self.drop_locked = true
end
if self.lock_hard_drop or (
not ruleset.are or self:getARE() == 0
) then
if self.lock_hard_drop then
self.hard_drop_locked = true
end
if generate_next_piece == nil then
@@ -563,87 +529,14 @@ function GameMode:getHighScoreData()
}
end
function GameMode:animation(x, y, skin, colour)
return {
1, 1, 1,
-0.25 + 1.25 * (self.lcd / self:getLineClearDelay()),
skin, colour,
48 + x * 16, y * 16
}
end
function GameMode:drawLineClearAnimation()
-- animation function
-- params: block x, y, skin, colour
-- returns: table with RGBA, skin, colour, x, y
-- Fadeout (default)
--[[
function animation(x, y, skin, colour)
return {
1, 1, 1,
-0.25 + 1.25 * (self.lcd / self:getLineClearDelay()),
skin, colour,
48 + x * 16, y * 16
}
end
--]]
-- Flash
--[[
function animation(x, y, skin, colour)
return {
1, 1, 1,
self.lcd % 6 < 3 and 1 or 0.25,
skin, colour,
48 + x * 16, y * 16
}
end
--]]
-- TGM1 pop-out
--[[
function animation(x, y, skin, colour)
local p = 0.5
local l = (
(self:getLineClearDelay() - self.lcd) / self:getLineClearDelay()
)
local dx = l * (x - (1 + self.grid.width) / 2)
local dy = l * (y - (1 + self.grid.height) / 2)
return {
1, 1, 1, 1, skin, colour,
48 + (x + dx) * 16,
(y + dy) * 16 + (464 / (p - 1)) * l * (p - l)
}
end
--]]
for y, row in pairs(self.cleared_block_table) do
for x, block in pairs(row) do
local animation_table = self:animation(x, y, block.skin, block.colour)
love.graphics.setColor(
animation_table[1], animation_table[2],
animation_table[3], animation_table[4]
)
love.graphics.draw(
blocks[animation_table[5]][animation_table[6]],
animation_table[7], animation_table[8]
)
end
end
end
function GameMode:drawPiece()
if self.piece ~= nil then
local b = (
self.classic_lock and
(
self.piece:isDropBlocked(self.grid) and
1 - self.piece.gravity or 1
) or
1 - (self.piece.lock_delay / self:getLockDelay())
self.piece:draw(
1,
self:getLockDelay() == 0 and 1 or
(0.25 + 0.75 * math.max(1 - self.piece.gravity, 1 - (self.piece.lock_delay / self:getLockDelay()))),
self.grid
)
self.piece:draw(1, 0.25 + 0.75 * b, self.grid)
end
end
@@ -696,18 +589,6 @@ function GameMode:setHoldOpacity()
love.graphics.setColor(colour, colour, colour, 1)
end
function GameMode:getBackground()
return 0
end
function GameMode:getHighscoreData()
return {}
end
function GameMode:drawGrid()
self.grid:draw()
end
function GameMode:drawScoringInfo()
love.graphics.setColor(1, 1, 1, 1)
love.graphics.setFont(font_3x5_2)
@@ -776,9 +657,7 @@ function GameMode:drawSectionTimesWithSecondary(current_section, section_limit)
end
end
function GameMode:drawSectionTimesWithSplits(current_section, section_limit)
section_limit = section_limit or math.huge
function GameMode:drawSectionTimesWithSplits(current_section)
local section_x = 440
local split_x = 530
@@ -786,19 +665,15 @@ function GameMode:drawSectionTimesWithSplits(current_section, section_limit)
for section, time in pairs(self.section_times) do
if section > 0 then
love.graphics.setColor(self:sectionColourFunction(section))
love.graphics.printf(formatTime(time), section_x, 40 + 20 * section, 90, "left")
love.graphics.setColor(1, 1, 1, 1)
split_time = split_time + time
love.graphics.printf(formatTime(split_time), split_x, 40 + 20 * section, 90, "left")
end
end
if (current_section <= section_limit) then
love.graphics.printf(formatTime(self.frames - self.section_start_time), section_x, 40 + 20 * current_section, 90, "left")
love.graphics.printf(formatTime(self.frames), split_x, 40 + 20 * current_section, 90, "left")
end
end
function GameMode:drawCustom() end

View File

@@ -171,6 +171,7 @@ function MarathonA2Game:updateSectionTimes(old_level, new_level)
self.section_start_time = self.frames
self.section_tetrises[math.floor(old_level / 100)] = self.tetris_count
self.tetris_count = 0
print(self.section_tetrises[math.floor(old_level / 100)])
end
end

View File

@@ -5,15 +5,15 @@ local Piece = require 'tetris.components.piece'
local Bag7NoSZOStartRandomizer = require 'tetris.randomizers.bag7noSZOstart'
local SurvivalAXGame = GameMode:extend()
local MarathonAX4Game = GameMode:extend()
SurvivalAXGame.name = "Survival AX"
SurvivalAXGame.hash = "SurvivalAX"
SurvivalAXGame.tagline = "Can you clear the time hurdles when the game goes this fast?"
MarathonAX4Game.name = "Marathon AX4"
MarathonAX4Game.hash = "MarathonAX4"
MarathonAX4Game.tagline = "Can you clear the time hurdles when the game goes this fast?"
function SurvivalAXGame:new()
SurvivalAXGame.super:new()
function MarathonAX4Game:new()
MarathonAX4Game.super:new()
self.roll_frames = 0
self.randomizer = Bag7NoSZOStartRandomizer()
@@ -29,7 +29,7 @@ function SurvivalAXGame:new()
self.next_queue_length = 3
end
function SurvivalAXGame:getARE()
function MarathonAX4Game:getARE()
if self.lines < 10 then return 18
elseif self.lines < 40 then return 14
elseif self.lines < 60 then return 12
@@ -39,24 +39,24 @@ function SurvivalAXGame:getARE()
else return 6 end
end
function SurvivalAXGame:getLineARE()
function MarathonAX4Game:getLineARE()
return self:getARE()
end
function SurvivalAXGame:getDasLimit()
function MarathonAX4Game:getDasLimit()
if self.lines < 20 then return 10
elseif self.lines < 50 then return 9
elseif self.lines < 70 then return 8
else return 7 end
end
function SurvivalAXGame:getLineClearDelay()
function MarathonAX4Game:getLineClearDelay()
if self.lines < 10 then return 14
elseif self.lines < 30 then return 9
else return 5 end
end
function SurvivalAXGame:getLockDelay()
function MarathonAX4Game:getLockDelay()
if self.lines < 10 then return 28
elseif self.lines < 20 then return 24
elseif self.lines < 30 then return 22
@@ -66,15 +66,15 @@ function SurvivalAXGame:getLockDelay()
else return 13 end
end
function SurvivalAXGame:getGravity()
function MarathonAX4Game:getGravity()
return 20
end
function SurvivalAXGame:getSection()
function MarathonAX4Game:getSection()
return math.floor(level / 100) + 1
end
function SurvivalAXGame:advanceOneFrame()
function MarathonAX4Game:advanceOneFrame()
if self.clear then
self.roll_frames = self.roll_frames + 1
if self.roll_frames < 0 then
@@ -93,7 +93,7 @@ function SurvivalAXGame:advanceOneFrame()
return true
end
function SurvivalAXGame:onLineClear(cleared_row_count)
function MarathonAX4Game:onLineClear(cleared_row_count)
if not self.clear then
local new_lines = self.lines + cleared_row_count
self:updateSectionTimes(self.lines, new_lines)
@@ -106,11 +106,11 @@ function SurvivalAXGame:onLineClear(cleared_row_count)
end
end
function SurvivalAXGame:getSectionTime()
function MarathonAX4Game:getSectionTime()
return self.frames - self.section_start_time
end
function SurvivalAXGame:updateSectionTimes(old_lines, new_lines)
function MarathonAX4Game:updateSectionTimes(old_lines, new_lines)
if math.floor(old_lines / 10) < math.floor(new_lines / 10) then
-- record new section
table.insert(self.section_times, self:getSectionTime())
@@ -119,23 +119,23 @@ function SurvivalAXGame:updateSectionTimes(old_lines, new_lines)
end
end
function SurvivalAXGame:onPieceEnter()
function MarathonAX4Game:onPieceEnter()
self.section_clear = false
end
function SurvivalAXGame:drawGrid(ruleset)
function MarathonAX4Game:drawGrid(ruleset)
self.grid:draw()
end
function SurvivalAXGame:getHighscoreData()
function MarathonAX4Game:getHighscoreData()
return {
lines = self.lines,
frames = self.frames,
}
end
function SurvivalAXGame:drawScoringInfo()
SurvivalAXGame.super.drawScoringInfo(self)
function MarathonAX4Game:drawScoringInfo()
MarathonAX4Game.super.drawScoringInfo(self)
love.graphics.setColor(1, 1, 1, 1)
@@ -165,12 +165,12 @@ function SurvivalAXGame:drawScoringInfo()
love.graphics.setColor(1, 1, 1, 1)
end
function SurvivalAXGame:getSectionEndLines()
function MarathonAX4Game:getSectionEndLines()
return math.floor(self.lines / 10 + 1) * 10
end
function SurvivalAXGame:getBackground()
function MarathonAX4Game:getBackground()
return math.floor(self.lines / 10)
end
return SurvivalAXGame
return MarathonAX4Game

View File

@@ -437,8 +437,6 @@ function SakuraGame:advanceOneFrame(inputs, ruleset)
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)
@@ -470,9 +468,9 @@ function SakuraGame:drawGrid()
self.grid:drawCustom(colourColor, self)
else
self.grid:draw()
end
if self.piece ~= nil and self.level < 100 then
self:drawGhostPiece()
-- if self.piece ~= nil and self.level < 100 then
self:drawGhostPiece(ruleset)
-- end
end
end

View File

@@ -52,14 +52,23 @@ function StrategyGame:getLineClearDelay()
end
function StrategyGame:getLockDelay()
if self.level < 700 then return 8
else return 6 end
if self.level < 500 then return 8
elseif self.level < 700 then return 6
else return 4 end
end
function StrategyGame:getGravity()
return 20
end
function StrategyGame:getNextPiece(ruleset)
return {
skin = "2tie",
shape = self.randomizer:nextPiece(),
orientation = ruleset:getDefaultOrientation(),
}
end
function StrategyGame:advanceOneFrame()
if self.clear then
self.roll_frames = self.roll_frames + 1

View File

@@ -94,8 +94,12 @@ function Survival2020Game:getGravity()
return 20
end
function Survival2020Game:getSkin()
return self.level >= 1000 and "bone" or "2tie"
function Survival2020Game:getNextPiece(ruleset)
return {
skin = self.level >= 1000 and "bone" or "2tie",
shape = self.randomizer:nextPiece(),
orientation = ruleset:getDefaultOrientation(),
}
end
function Survival2020Game:hitTorikan(old_level, new_level)

View File

@@ -66,24 +66,24 @@ function SurvivalA1Game:getGravity()
end
local function getRankForScore(score)
if score < 400 then return {rank = "9", next = 400}
elseif score < 800 then return {rank = "8", next = 800}
elseif score < 1400 then return {rank = "7", next = 1400}
elseif score < 2000 then return {rank = "6", next = 2000}
elseif score < 3500 then return {rank = "5", next = 3500}
elseif score < 5500 then return {rank = "4", next = 5500}
elseif score < 8000 then return {rank = "3", next = 8000}
elseif score < 12000 then return {rank = "2", next = 12000}
elseif score < 16000 then return {rank = "1", next = 16000}
elseif score < 22000 then return {rank = "S1", next = 22000}
elseif score < 30000 then return {rank = "S2", next = 30000}
elseif score < 40000 then return {rank = "S3", next = 40000}
elseif score < 52000 then return {rank = "S4", next = 52000}
elseif score < 66000 then return {rank = "S5", next = 66000}
elseif score < 82000 then return {rank = "S6", next = 82000}
elseif score < 100000 then return {rank = "S7", next = 100000}
elseif score < 120000 then return {rank = "S8", next = 120000}
else return {rank = "S9", next = "???"}
if score < 400 then return {rank = "9", next = 400, grade = 0}
elseif score < 800 then return {rank = "8", next = 800, grade = 1}
elseif score < 1400 then return {rank = "7", next = 1400, grade = 2}
elseif score < 2000 then return {rank = "6", next = 2000, grade = 3}
elseif score < 3500 then return {rank = "5", next = 3500, grade = 4}
elseif score < 5500 then return {rank = "4", next = 5500, grade = 5}
elseif score < 8000 then return {rank = "3", next = 8000, grade = 6}
elseif score < 12000 then return {rank = "2", next = 12000, grade = 7}
elseif score < 16000 then return {rank = "1", next = 16000, grade = 8}
elseif score < 22000 then return {rank = "S1", next = 22000, grade = 9}
elseif score < 30000 then return {rank = "S2", next = 30000, grade = 10}
elseif score < 40000 then return {rank = "S3", next = 40000, grade = 11}
elseif score < 52000 then return {rank = "S4", next = 52000, grade = 12}
elseif score < 66000 then return {rank = "S5", next = 66000, grade = 13}
elseif score < 82000 then return {rank = "S6", next = 82000, grade = 14}
elseif score < 100000 then return {rank = "S7", next = 100000, grade = 15}
elseif score < 120000 then return {rank = "S8", next = 120000, grade = 16}
else return {rank = "S9", next = "???", grade = 17}
end
end
@@ -208,10 +208,15 @@ end
function SurvivalA1Game:getHighscoreData()
return {
grade = self.grade,
grade = (
(self.gm_conditions["level300"] and
self.gm_conditions["level500"] and
self.gm_conditions["level999"]) and
18 or getRankForScore(self.score).grade
),
frames = self.frames,
score = self.score,
level = self.level,
frames = self.frames,
}
end

View File

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

View File

@@ -110,7 +110,13 @@ function ARS:onPieceDrop(piece, grid)
piece.lock_delay = 0 -- step reset
end
function ARS:get180RotationValue() return 3 end
function ARS:get180RotationValue()
if config.gamesettings.world_reverse == 3 then
return 1
else
return 3
end
end
function ARS:getDefaultOrientation() return 3 end -- downward facing pieces by default

View File

@@ -18,7 +18,6 @@ ARS.colourscheme = {
ARS.softdrop_lock = false
ARS.harddrop_lock = true
ARS.spawn_above_field = true
function ARS:onPieceCreate(piece, grid)
piece.floorkick = 0
@@ -50,8 +49,4 @@ function ARS:onPieceRotate(piece, grid)
end
end
function ARS:get180RotationValue() return 3 end
function ARS:getDefaultOrientation() return 3 end -- downward facing pieces by default
return ARS

View File

@@ -5,7 +5,6 @@ local ARS = Ruleset:extend()
ARS.name = "ACE-ARS2"
ARS.hash = "ArikaACE2"
ARS.spawn_above_field = true
function ARS:onPieceCreate(piece, grid)
piece.floorkick = 0
@@ -37,8 +36,4 @@ function ARS:onPieceRotate(piece, grid)
end
end
function ARS:get180RotationValue() return 3 end
function ARS:getDefaultOrientation() return 3 end -- downward facing pieces by default
return ARS

View File

@@ -4,35 +4,18 @@ local Ruleset = require 'tetris.rulesets.ti_srs'
local SRS = Ruleset:extend()
SRS.name = "ACE-SRS"
SRS.hash = "StandardACE"
SRS.world = true
SRS.colourscheme = {
I = "C",
L = "O",
J = "B",
S = "G",
Z = "R",
O = "Y",
T = "M",
}
SRS.softdrop_lock = false
SRS.harddrop_lock = true
SRS.spawn_above_field = true
SRS.hash = "ACE Standard"
SRS.MANIPULATIONS_MAX = 128
function SRS:onPieceRotate(piece, grid, upward)
function SRS:onPieceRotate(piece, grid)
piece.lock_delay = 0 -- rotate reset
if upward or piece:isDropBlocked(grid) then
if piece:isDropBlocked(grid) then
piece.manipulations = piece.manipulations + 1
if piece.manipulations >= self.MANIPULATIONS_MAX and piece:isDropBlocked(grid) then
if piece.manipulations >= self.MANIPULATIONS_MAX then
piece.locked = true
end
end
end
function SRS:canPieceRotate(piece)
return piece.manipulations < self.MANIPULATIONS_MAX
end
return SRS

View File

@@ -96,14 +96,7 @@ end
function ARS:onPieceRotate(piece, grid)
if piece.floorkick >= 1 then
piece.floorkick = piece.floorkick + 1
if piece:isDropBlocked(grid) then
piece.locked = true
end
end
end
function ARS:get180RotationValue() return 3 end
function ARS:getDefaultOrientation() return 3 end -- downward facing pieces by default
return ARS

View File

@@ -364,7 +364,7 @@ function CRS:attemptRotate(new_inputs, piece, grid, initial)
if rot_dir == 0 then return end
if config.gamesettings.world_reverse == 3 or (self.world and config.gamesettings.world_reverse == 2) then
if self.world and config.gamesettings.world_reverse == 2 then
rot_dir = 4 - rot_dir
end

View File

@@ -23,7 +23,6 @@ Ruleset.harddrop_lock = false
Ruleset.enable_IRS_wallkicks = false
Ruleset.are_cancel = false
Ruleset.are = true
Ruleset.spawn_above_field = false
Ruleset.next_sounds = {
I = "I",
@@ -115,9 +114,7 @@ function Ruleset:rotatePiece(inputs, piece, grid, prev_inputs, initial)
local was_drop_blocked = piece:isDropBlocked(grid)
if self:canPieceRotate(piece, grid) then
self:attemptRotate(new_inputs, piece, grid, initial)
end
if not was_drop_blocked and piece:isDropBlocked(grid) then
playSE("bottom")
@@ -162,43 +159,28 @@ function Ruleset:attemptWallkicks(piece, new_piece, rot_dir, grid)
end
function Ruleset:movePiece(piece, grid, move, instant)
if not self:canPieceMove(piece, grid) then return end
local was_drop_blocked = piece:isDropBlocked(grid)
local offset = ({x=0, y=0})
local moves = 0
if move == "left" then
offset.x = -1
moves = 1
elseif move == "right" then
offset.x = 1
moves = 1
elseif move == "speedleft" then
offset.x = -1
moves = grid.width
elseif move == "speedright" then
offset.x = 1
moves = grid.width
end
for i = 1, moves do
local x = piece.position.x
if moves ~= 1 then
piece:moveInGrid(offset, 1, grid, instant)
else
piece:moveInGrid(offset, 1, grid, false)
local was_drop_blocked = piece:isDropBlocked(grid)
if move == "left" then
piece:moveInGrid({x=-1, y=0}, 1, grid, false)
elseif move == "right" then
piece:moveInGrid({x=1, y=0}, 1, grid, false)
elseif move == "speedleft" then
piece:moveInGrid({x=-1, y=0}, grid.width, grid, instant)
elseif move == "speedright" then
piece:moveInGrid({x=1, y=0}, grid.width, grid, instant)
end
if piece.position.x ~= x then
self:onPieceMove(piece, grid)
if piece.locked then break end
end
end
if not was_drop_blocked and piece:isDropBlocked(grid) then
playSE("bottom")
end
end
end
function Ruleset:dropPiece(
inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked,
hard_drop_enabled, additive_gravity, classic_lock
hard_drop_enabled, additive_gravity
)
if piece.big then
gravity = gravity / 2
@@ -208,29 +190,26 @@ function Ruleset:dropPiece(
local y = piece.position.y
if inputs["down"] == true and drop_locked == false then
if additive_gravity then
piece:addGravity(gravity + drop_speed, grid, classic_lock)
piece:addGravity(gravity + drop_speed, grid)
else
piece:addGravity(math.max(gravity, drop_speed), grid, classic_lock)
piece:addGravity(math.max(gravity, drop_speed), grid)
end
elseif inputs["up"] == true and hard_drop_enabled == true then
if hard_drop_locked == true or piece:isDropBlocked(grid) then
piece:addGravity(gravity, grid, classic_lock)
piece:addGravity(gravity, grid)
else
piece:dropToBottom(grid)
end
else
piece:addGravity(gravity, grid, classic_lock)
piece:addGravity(gravity, grid)
end
if piece.position.y ~= y then
self:onPieceDrop(piece, grid)
end
end
function Ruleset:lockPiece(piece, grid, lock_delay, classic_lock)
if piece:isDropBlocked(grid) and (
(classic_lock and piece.gravity >= 1) or
(not classic_lock and piece.lock_delay >= lock_delay)
) then
function Ruleset:lockPiece(piece, grid, lock_delay)
if piece:isDropBlocked(grid) and piece.gravity >= 1 and piece.lock_delay >= lock_delay then
piece.locked = true
end
end
@@ -264,17 +243,10 @@ function Ruleset:initializePiece(
end
end
local spawn_dy
if (config.gamesettings.spawn_positions == 1) then
spawn_dy = (
self.spawn_above_field and 2 or 0
)
else
spawn_dy = (
config.gamesettings.spawn_positions == 3 and
local spawn_dy = (
config.gamesettings.spawn_positions == 2 and
2 or 0
)
end
local piece = Piece(data.shape, data.orientation - 1, {
x = spawn_x and spawn_x or spawn_positions[data.shape].x,
@@ -306,7 +278,7 @@ function Ruleset:processPiece(
inputs, piece, grid, gravity, prev_inputs,
move, lock_delay, drop_speed,
drop_locked, hard_drop_locked,
hard_drop_enabled, additive_gravity, classic_lock
hard_drop_enabled, additive_gravity
)
local synchroes_allowed = ({not self.world, true, false})[config.gamesettings.synchroes_allowed]
@@ -320,13 +292,11 @@ function Ruleset:processPiece(
end
self:dropPiece(
inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked,
hard_drop_enabled, additive_gravity, classic_lock
hard_drop_enabled, additive_gravity
)
self:lockPiece(piece, grid, lock_delay, classic_lock)
self:lockPiece(piece, grid, lock_delay)
end
function Ruleset:canPieceMove(piece, grid) return true end
function Ruleset:canPieceRotate(piece, grid) return true end
function Ruleset:onPieceMove(piece) end
function Ruleset:onPieceRotate(piece) end
function Ruleset:onPieceDrop(piece) end

View File

@@ -1,105 +0,0 @@
local Piece = require 'tetris.components.piece'
local Ruleset = require 'tetris.rulesets.standard_exp'
local SRS = Ruleset:extend()
SRS.name = "Guideline SRS"
SRS.hash = "Standard"
SRS.softdrop_lock = false
SRS.harddrop_lock = true
SRS.MANIPULATIONS_MAX = 15
SRS.wallkicks_line = {
[0]={
[1]={{x=-2, y=0}, {x=1, y=0}, {x=-2, y=1}, {x=1, y=-2}},
[2]={{x=-1,y=0},{x=-2,y=0},{x=1,y=0},{x=2,y=0},{x=0,y=1}},
[3]={{x=-1, y=0}, {x=2, y=0}, {x=-1, y=-2}, {x=2, y=1}},
},
[1]={
[0]={{x=2, y=0}, {x=-1, y=0}, {x=2, y=-1}, {x=-1, y=2}},
[2]={{x=-1, y=0}, {x=2, y=0}, {x=-1, y=-2}, {x=2, y=1}},
[3]={{x=0,y=1},{x=0,y=2},{x=0,y=-1},{x=0,y=-2},{x=-1,y=0}},
},
[2]={
[0]={{x=1,y=0},{x=2,y=0},{x=-1,y=0},{x=-2,y=0},{x=0,y=-1}},
[1]={{x=1, y=0}, {x=-2, y=0}, {x=1, y=2}, {x=-2, y=-1}},
[3]={{x=2, y=0}, {x=-1, y=0}, {x=2, y=-1}, {x=-1, y=2}},
},
[3]={
[0]={{x=1, y=0}, {x=-2, y=0}, {x=1, y=2}, {x=-2, y=-1}},
[1]={{x=0,y=1},{x=0,y=2},{x=0,y=-1},{x=0,y=-2},{x=1,y=0}},
[2]={{x=-2, y=0}, {x=1, y=0}, {x=-2, y=1}, {x=1, y=-2}},
},
};
function SRS:attemptWallkicks(piece, new_piece, rot_dir, grid)
local kicks
if piece.shape == "O" then
return
elseif piece.shape == "I" then
kicks = SRS.wallkicks_line[piece.rotation][new_piece.rotation]
else
kicks = SRS.wallkicks_3x3[piece.rotation][new_piece.rotation]
end
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
piece:setRelativeRotation(rot_dir)
piece:setOffset(offset)
self:onPieceRotate(piece, grid)
return
end
end
end
function SRS:checkNewLow(piece)
for _, block in pairs(piece:getBlockOffsets()) do
local y = piece.position.y + block.y
if y > piece.lowest_y then
piece.manipulations = 0
piece.rotations = 0
piece.lowest_y = y
end
end
end
function SRS:onPieceDrop(piece, grid)
self:checkNewLow(piece)
if piece.manipulations >= self.MANIPULATIONS_MAX and piece:isDropBlocked(grid) then
piece.locked = true
else
piece.lock_delay = 0 -- step reset
end
end
function SRS:onPieceMove(piece, grid)
piece.lock_delay = 0 -- move reset
if piece:isDropBlocked(grid) then
piece.manipulations = piece.manipulations + 1
if piece.manipulations >= SRS.MANIPULATIONS_MAX then
piece.locked = true
end
end
end
function SRS:onPieceRotate(piece, grid)
piece.lock_delay = 0 -- rotate reset
self:checkNewLow(piece)
piece.manipulations = piece.manipulations + 1
if piece.manipulations >= self.MANIPULATIONS_MAX then
piece:moveInGrid({ x = 0, y = 1 }, 1, grid)
if piece:isDropBlocked(grid) then
piece.locked = true
end
end
end
function SRS:canPieceRotate() return true end
return SRS

View File

@@ -3,37 +3,46 @@ local Ruleset = require 'tetris.rulesets.arika_srs'
local SRS = Ruleset:extend()
SRS.name = "SRS-X"
SRS.hash = "StandardEXP"
SRS.world = true
SRS.colourscheme = {
I = "C",
L = "O",
J = "B",
S = "G",
Z = "R",
O = "Y",
T = "M",
}
SRS.softdrop_lock = true
SRS.harddrop_lock = false
SRS.name = "Guideline SRS"
SRS.hash = "Standard"
SRS.enable_IRS_wallkicks = true
SRS.MANIPULATIONS_MAX = 24
SRS.ROTATIONS_MAX = 12
SRS.MANIPULATIONS_MAX = 15
function SRS:checkNewLow(piece)
for _, block in pairs(piece:getBlockOffsets()) do
local y = piece.position.y + block.y
if y > piece.lowest_y then
--piece.manipulations = 0
--piece.rotations = 0
piece.manipulations = 0
piece.lowest_y = y
end
end
end
SRS.wallkicks_line = {
[0]={
[1]={{x=-2, y=0}, {x=1, y=0}, {x=-2, y=1}, {x=1, y=-2}},
[2]={},
[3]={{x=-1, y=0}, {x=2, y=0}, {x=-1, y=-2}, {x=2, y=1}},
},
[1]={
[0]={{x=2, y=0}, {x=-1, y=0}, {x=2, y=-1}, {x=-1, y=2}},
[2]={{x=-1, y=0}, {x=2, y=0}, {x=-1, y=-2}, {x=2, y=1}},
[3]={{x=0, y=1}, {x=0, y=-1}, {x=0, y=2}, {x=0, y=-2}},
},
[2]={
[0]={},
[1]={{x=1, y=0}, {x=-2, y=0}, {x=1, y=2}, {x=-2, y=-1}},
[3]={{x=2, y=0}, {x=-1, y=0}, {x=2, y=-1}, {x=-1, y=2}},
},
[3]={
[0]={{x=1, y=0}, {x=-2, y=0}, {x=1, y=2}, {x=-2, y=-1}},
[1]={{x=0, y=1}, {x=0, y=-1}, {x=0, y=2}, {x=0, y=-2}},
[2]={{x=-2, y=0}, {x=1, y=0}, {x=-2, y=1}, {x=1, y=-2}},
},
};
-- Component functions.
function SRS:attemptWallkicks(piece, new_piece, rot_dir, grid)
@@ -54,7 +63,7 @@ function SRS:attemptWallkicks(piece, new_piece, rot_dir, grid)
if grid:canPlacePiece(kicked_piece) then
piece:setRelativeRotation(rot_dir)
piece:setOffset(offset)
self:onPieceRotate(piece, grid, offset.y < 0)
self:onPieceRotate(piece, grid)
return
end
end
@@ -63,16 +72,12 @@ end
function SRS:onPieceCreate(piece, grid)
piece.manipulations = 0
piece.rotations = 0
piece.lowest_y = -math.huge
end
function SRS:onPieceDrop(piece, grid)
self:checkNewLow(piece)
if (
piece.manipulations >= self.MANIPULATIONS_MAX or
piece.rotations >= self.ROTATIONS_MAX
) and piece:isDropBlocked(grid) then
if piece.manipulations >= self.MANIPULATIONS_MAX and piece:isDropBlocked(grid) then
piece.locked = true
else
piece.lock_delay = 0 -- step reset
@@ -83,26 +88,24 @@ function SRS:onPieceMove(piece, grid)
piece.lock_delay = 0 -- move reset
if piece:isDropBlocked(grid) then
piece.manipulations = piece.manipulations + 1
if piece.manipulations >= SRS.MANIPULATIONS_MAX then
if piece.manipulations >= self.MANIPULATIONS_MAX then
piece.locked = true
end
end
end
function SRS:onPieceRotate(piece, grid, upward)
function SRS:onPieceRotate(piece, grid)
piece.lock_delay = 0 -- rotate reset
if upward or piece:isDropBlocked(grid) then
piece.rotations = piece.rotations + 1
if piece.rotations >= self.ROTATIONS_MAX and piece:isDropBlocked(grid) then
self:checkNewLow(piece)
piece.manipulations = piece.manipulations + 1
if piece.manipulations >= self.MANIPULATIONS_MAX then
piece:moveInGrid({ x = 0, y = 1 }, 1, grid)
if piece:isDropBlocked(grid) then
piece.locked = true
end
end
end
function SRS:canPieceRotate(piece)
return piece.rotations < self.ROTATIONS_MAX
end
function SRS:get180RotationValue() return 2 end
return SRS

View File

@@ -4,7 +4,7 @@ local Ruleset = require 'tetris.rulesets.ruleset'
local SRS = Ruleset:extend()
SRS.name = "Ti-World"
SRS.hash = "StandardTI"
SRS.hash = "Bad I-kicks"
SRS.world = true
SRS.colourscheme = {
I = "C",
@@ -89,22 +89,22 @@ SRS.block_offsets = {
SRS.wallkicks_3x3 = {
[0]={
[1]={{x=-1, y=0}, {x=-1, y=-1}, {x=0, y=2}, {x=-1, y=2}},
[2]={{x=1,y=0},{x=2,y=0},{x=1,y=1},{x=2,y=1},{x=-1,y=0},{x=-2,y=0},{x=-1,y=1},{x=-2,y=1},{x=0,y=-1},{x=3,y=0},{x=-3,y=0}},
[2]={{x=0, y=1}, {x=0, y=-1}},
[3]={{x=1, y=0}, {x=1, y=-1}, {x=0, y=2}, {x=1, y=2}},
},
[1]={
[0]={{x=1, y=0}, {x=1, y=1}, {x=0, y=-2}, {x=1, y=-2}},
[2]={{x=1, y=0}, {x=1, y=1}, {x=0, y=-2}, {x=1, y=-2}},
[3]={{x=0,y=1},{x=0,y=2},{x=-1,y=1},{x=-1,y=2},{x=0,y=-1},{x=0,y=-2},{x=-1,y=-1},{x=-1,y=-2},{x=1,y=0},{x=0,y=3},{x=0,y=-3}},
[3]={{x=0, y=1}, {x=0, y=-1}},
},
[2]={
[0]={{x=-1,y=0},{x=-2,y=0},{x=-1,y=-1},{x=-2,y=-1},{x=1,y=0},{x=2,y=0},{x=1,y=-1},{x=2,y=-1},{x=0,y=1},{x=-3,y=0},{x=3,y=0}},
[0]={{x=0, y=1}, {x=0, y=-1}},
[1]={{x=-1, y=0}, {x=-1, y=-1}, {x=0, y=2}, {x=-1, y=2}},
[3]={{x=1, y=0}, {x=1, y=-1}, {x=0, y=2}, {x=1, y=2}},
},
[3]={
[0]={{x=-1, y=0}, {x=-1, y=1}, {x=0, y=-2}, {x=-1, y=-2}},
[1]={{x=0,y=1},{x=0,y=2},{x=1,y=1},{x=1,y=2},{x=0,y=-1},{x=0,y=-2},{x=1,y=-1},{x=1,y=-2},{x=-1,y=0},{x=0,y=3},{x=0,y=-3}},
[1]={{x=0, y=1}, {x=0, y=-1}},
[2]={{x=-1, y=0}, {x=-1, y=1}, {x=0, y=-2}, {x=-1, y=-2}},
},
};
@@ -112,22 +112,22 @@ SRS.wallkicks_3x3 = {
SRS.wallkicks_line = {
[0]={
[1]={{x=-2, y= 0}, {x= 1, y= 0}, {x= 1, y=-2}, {x=-2, y= 1}},
[2]={{x=-1,y=0},{x=-2,y=0},{x=1,y=0},{x=2,y=0},{x=0,y=1}},
[2]={},
[3]={{x= 2, y= 0}, {x=-1, y= 0}, {x=-1, y=-2}, {x= 2, y= 1}},
},
[1]={
[0]={{x= 2, y= 0}, {x=-1, y= 0}, {x= 2, y=-1}, {x=-1, y= 2}},
[2]={{x=-1, y= 0}, {x= 2, y= 0}, {x=-1, y=-2}, {x= 2, y= 1}},
[3]={{x=0,y=1},{x=0,y=2},{x=0,y=-1},{x=0,y=-2},{x=-1,y=0}},
[3]={},
},
[2]={
[0]={{x=1,y=0},{x=2,y=0},{x=-1,y=0},{x=-2,y=0},{x=0,y=-1}},
[0]={},
[1]={{x=-2, y= 0}, {x= 1, y= 0}, {x=-2, y=-1}, {x= 1, y= 1}},
[3]={{x= 2, y= 0}, {x=-1, y= 0}, {x= 2, y=-1}, {x=-1, y= 1}},
},
[3]={
[0]={{x=-2, y= 0}, {x= 1, y= 0}, {x=-2, y=-1}, {x= 1, y= 2}},
[1]={{x=0,y=1},{x=0,y=2},{x=0,y=-1},{x=0,y=-2},{x=1,y=0}},
[1]={},
[2]={{x= 1, y= 0}, {x=-2, y= 0}, {x= 1, y=-2}, {x=-2, y= 1}},
},
};
@@ -150,9 +150,9 @@ function SRS: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, offset.y < 0)
return
end
end
@@ -182,20 +182,22 @@ function SRS:onPieceMove(piece, grid)
end
end
function SRS:onPieceRotate(piece, grid, upward)
function SRS:onPieceRotate(piece, grid)
piece.lock_delay = 0 -- rotate reset
if upward or piece:isDropBlocked(grid) then
if piece:isDropBlocked(grid) then
piece.rotations = piece.rotations + 1
if piece.rotations >= self.ROTATIONS_MAX and piece:isDropBlocked(grid) then
if piece.rotations >= self.ROTATIONS_MAX then
piece.locked = true
end
end
end
function SRS:canPieceRotate(piece)
return piece.rotations < self.ROTATIONS_MAX
function SRS:get180RotationValue()
if config.gamesettings.world_reverse == 1 then
return 1
else
return 3
end
end
function SRS:get180RotationValue() return 3 end
return SRS