mirror of
https://github.com/SashLilac/cambridge.git
synced 2025-05-13 20:21:25 -05:00
Compare commits
45 Commits
v0.3-beta2
...
v0.3-beta4
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
83e498534c | ||
|
|
8f19c73e2a | ||
|
|
e36b855ff7 | ||
|
|
23b58951cb | ||
|
|
1d73916b7c | ||
|
|
3947e9f02f | ||
|
|
99b15803ee | ||
|
|
d350b25726 | ||
|
|
44e4d00172 | ||
|
|
31e2529265 | ||
|
|
ea7c75f0b3 | ||
|
|
714c6b5e99 | ||
|
|
6a5d5a9c88 | ||
|
|
03491ba151 | ||
|
|
6e22e3d15b | ||
|
|
66ab5992ad | ||
|
|
2c07c2a58c | ||
|
|
a4d3f3bffc | ||
|
|
9ac60cbb5e | ||
|
|
cdd846c3e6 | ||
|
|
33d260b753 | ||
|
|
1644fcdf8e | ||
|
|
f3c1cf6e1f | ||
|
|
06a8a2ebf7 | ||
|
|
15354ce004 | ||
|
|
af02cd3467 | ||
|
|
acb05918c1 | ||
|
|
b644c8e457 | ||
|
|
288961e12a | ||
|
|
a047e51681 | ||
|
|
77f24f5ee5 | ||
|
|
32c2274bef | ||
|
|
4920e5de1c | ||
|
|
8418fc8ab7 | ||
|
|
711a5120f1 | ||
|
|
e7c3c9446a | ||
|
|
3ac39acd7a | ||
|
|
d0505251b3 | ||
|
|
bb0fe2ac20 | ||
|
|
986ebac47f | ||
|
|
9799147f96 | ||
|
|
1dda12e4be | ||
|
|
38947e00c0 | ||
|
|
035f6dd7b4 | ||
|
|
aa3eadc93d |
36
README.md
36
README.md
@@ -1,13 +1,13 @@
|
||||

|
||||

|
||||
|
||||
Cambridge
|
||||
=========
|
||||
|
||||
Welcome to Cambridge, the next open-source falling-block game engine!
|
||||
|
||||
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 project is written and maintained exclusively by [SashLilac](https://github.com/SashLilac), [joezeng](https://github.com/joezeng) and [Oshisaure](https://github.com/oshisaure)!
|
||||
|
||||
Join our Discord server for help and a welcoming community! https://discord.gg/mteMJw4
|
||||
The game also has a website now with more detail than seen on this README: https://t-sp.in/cambridge
|
||||
|
||||
Credits
|
||||
-------
|
||||
@@ -17,19 +17,7 @@ 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!
|
||||
|
||||
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)
|
||||
More special thanks can be found in-game, under the "Credits" menu.
|
||||
|
||||

|
||||
|
||||
@@ -40,7 +28,13 @@ Playing the game
|
||||
|
||||
You do not need LÖVE on Windows, as it comes bundled with the program.
|
||||
|
||||
To get the stable release, simply download the ZIP in the latest release. All assets needed are bundled with the executable.
|
||||
#### 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
|
||||
|
||||
If you want the bleeding edge version, download [this](https://github.com/SashLilac/cambridge/archive/master.zip).
|
||||
|
||||
@@ -82,13 +76,7 @@ It should run automatically!
|
||||
|
||||
## Installing modpacks
|
||||
|
||||
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.
|
||||
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.
|
||||
|
||||
License
|
||||
-------
|
||||
|
||||
@@ -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 = true
|
||||
local strict = false
|
||||
|
||||
--------------------------------------------------------------------------------
|
||||
|
||||
@@ -33,12 +33,7 @@ function bigint.new(num)
|
||||
return bigint.add(lhs, rhs)
|
||||
end,
|
||||
__unm = function()
|
||||
if (self.sign == "+") then
|
||||
self.sign = "-"
|
||||
else
|
||||
self.sign = "+"
|
||||
end
|
||||
return self
|
||||
return bigint.negate(self)
|
||||
end,
|
||||
__sub = function(lhs, rhs)
|
||||
return bigint.subtract(lhs, rhs)
|
||||
@@ -55,14 +50,8 @@ 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, "<=")
|
||||
__tostring = function()
|
||||
return bigint.unserialize(self, "s")
|
||||
end
|
||||
})
|
||||
|
||||
@@ -88,7 +77,8 @@ 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 < 10, digit .. " is greater than or equal to 10")
|
||||
assert(digit <= 9 and digit >= 0, digit .. " is not between 0 and 9")
|
||||
assert(math.floor(digit) == digit, digit .. " is not an integer")
|
||||
end
|
||||
end
|
||||
return true
|
||||
@@ -103,6 +93,24 @@ 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)
|
||||
@@ -137,7 +145,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 = 3
|
||||
precision = math.min(#big.digits, 3)
|
||||
else
|
||||
assert(precision > 0, "Precision cannot be less than 1")
|
||||
assert(math.floor(precision) == precision,
|
||||
@@ -146,17 +154,18 @@ 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 .. big.digits[1]
|
||||
num = num .. math.floor(big.digits[1])
|
||||
if (precision > 1) then
|
||||
num = num .. "."
|
||||
for i = 1, (precision - 1) do
|
||||
num = num .. big.digits[i + 1]
|
||||
num = num .. math.floor(big.digits[i + 1])
|
||||
end
|
||||
end
|
||||
|
||||
if ((output_type == "human-readable")
|
||||
or (output_type == "human")
|
||||
or (output_type == "h")) then
|
||||
or (output_type == "h"))
|
||||
and (#big.digits >= 3 and #big.digits <= 10002) then
|
||||
-- Human-readable output contributed by 123eee555
|
||||
|
||||
local name
|
||||
@@ -435,7 +444,6 @@ 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
|
||||
@@ -446,13 +454,23 @@ 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
|
||||
return big:clone()
|
||||
else
|
||||
local result = big:clone()
|
||||
local result = bigint.new(1)
|
||||
local base = big:clone()
|
||||
|
||||
while (bigint.compare(exp, bigint.new(1), ">")) do
|
||||
result = bigint.multiply(result, big)
|
||||
exp = bigint.subtract(exp, bigint.new(1))
|
||||
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
|
||||
end
|
||||
|
||||
return result
|
||||
@@ -468,7 +486,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), bigint.new(0)
|
||||
return bigint.new(0), big1:clone()
|
||||
else
|
||||
assert(bigint.compare(big2, bigint.new(0), "!="), "error: divide by zero")
|
||||
assert(big1.sign == "+", "error: big1 is not positive")
|
||||
@@ -476,54 +494,35 @@ function bigint.divide_raw(big1, big2)
|
||||
|
||||
local result = bigint.new()
|
||||
|
||||
local dividend = bigint.new() -- Dividend of a single operation, not the
|
||||
-- dividend of the overall function
|
||||
local divisor = big2:clone()
|
||||
local factor = 1
|
||||
local dividend = bigint.new() -- Dividend of a single operation
|
||||
|
||||
-- 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
|
||||
local neg_zero = bigint.new(0)
|
||||
neg_zero.sign = "-"
|
||||
|
||||
-- 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
|
||||
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()
|
||||
end
|
||||
|
||||
-- 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
|
||||
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))
|
||||
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()
|
||||
for i = 0, #factor.digits - 1 do
|
||||
result.digits[#result.digits + 1 - i] = factor.digits[i + 1]
|
||||
end
|
||||
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
|
||||
|
||||
@@ -83,6 +83,7 @@ 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()
|
||||
|
||||
@@ -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, {"In field", "Out of field"}},
|
||||
{"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"}},
|
||||
{"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() - 3) / (sld.max - sld.min)))
|
||||
sld.value = math.max(sld.min, math.min(sld.max, (sld:getValue() - 5) / (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() + 3) / (sld.max - sld.min)))--math.max(0, (math.floor(sld:getValue())+2)/(sld.max-sld.min))
|
||||
sld.value = math.max(sld.min, math.min(sld.max, (sld:getValue() + 5) / (sld.max - sld.min)))--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()
|
||||
|
||||
@@ -31,6 +31,7 @@ end
|
||||
|
||||
function ConfigScene:new()
|
||||
self.input_state = 1
|
||||
self.key = 1
|
||||
self.set_inputs = newSetInputs()
|
||||
self.new_input = {}
|
||||
self.axis_timer = 0
|
||||
@@ -62,7 +63,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 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("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
|
||||
|
||||
@@ -97,18 +98,28 @@ function ConfigScene:onInputPress(e)
|
||||
self.new_input = {}
|
||||
end
|
||||
elseif e.scancode == "tab" then
|
||||
self.set_inputs[configurable_inputs[self.input_state]] = "skipped"
|
||||
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
|
||||
elseif e.scancode ~= "escape" then
|
||||
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.input_state = self.input_state + 1
|
||||
self.key = 2
|
||||
end
|
||||
elseif string.sub(e.type, 1, 3) == "joy" then
|
||||
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)
|
||||
@@ -116,11 +127,13 @@ function ConfigScene:onInputPress(e)
|
||||
self.new_input.joysticks[e.name].buttons = {}
|
||||
end
|
||||
self.set_inputs[configurable_inputs[self.input_state]] =
|
||||
"jbtn " ..
|
||||
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)
|
||||
@@ -131,11 +144,13 @@ function ConfigScene:onInputPress(e)
|
||||
self.new_input.joysticks[e.name].axes[e.axis] = {}
|
||||
end
|
||||
self.set_inputs[configurable_inputs[self.input_state]] =
|
||||
"jaxis " ..
|
||||
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
|
||||
@@ -149,11 +164,13 @@ function ConfigScene:onInputPress(e)
|
||||
self.new_input.joysticks[e.name].hats[e.hat] = {}
|
||||
end
|
||||
self.set_inputs[configurable_inputs[self.input_state]] =
|
||||
"jhat " ..
|
||||
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
|
||||
|
||||
@@ -111,18 +111,24 @@ 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 true
|
||||
return block_table
|
||||
end
|
||||
|
||||
function Grid:clearClearedRows()
|
||||
@@ -388,7 +394,8 @@ end
|
||||
function Grid:draw()
|
||||
for y = 5, self.height do
|
||||
for x = 1, self.width do
|
||||
if self.grid[y][x] ~= empty then
|
||||
if blocks[self.grid[y][x].skin] and
|
||||
blocks[self.grid[y][x].skin][self.grid[y][x].colour] 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)
|
||||
@@ -396,7 +403,8 @@ 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.5, 0.5, 0.5, 1 - self.grid_age[y][x] / 15)
|
||||
love.graphics.setColor(0, 0, 0, 0)
|
||||
--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
|
||||
@@ -427,10 +435,12 @@ 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)
|
||||
@@ -459,7 +469,8 @@ 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 = 1 - self.grid_age[y][x] / 15
|
||||
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
|
||||
@@ -506,7 +517,8 @@ 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 = 1 - self.grid_age[y][x] / 15
|
||||
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)
|
||||
|
||||
@@ -104,9 +104,8 @@ 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
|
||||
@@ -118,11 +117,15 @@ function Piece:lockIfBottomed(grid)
|
||||
return self
|
||||
end
|
||||
|
||||
function Piece:addGravity(gravity, grid)
|
||||
function Piece:addGravity(gravity, grid, classic_lock)
|
||||
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
|
||||
|
||||
@@ -45,6 +45,7 @@ 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
|
||||
@@ -63,6 +64,7 @@ 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
|
||||
@@ -135,7 +137,7 @@ function GameMode:update(inputs, ruleset)
|
||||
|
||||
-- set attempt flags
|
||||
if inputs["left"] or inputs["right"] then
|
||||
self:onAttemptPieceMove(self.piece)
|
||||
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
|
||||
@@ -148,7 +150,7 @@ function GameMode:update(inputs, ruleset)
|
||||
inputs["rotate_left2"] or inputs["rotate_right2"] or
|
||||
inputs["rotate_180"]
|
||||
then
|
||||
self:onAttemptPieceRotate(self.piece)
|
||||
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
|
||||
@@ -177,26 +179,32 @@ function GameMode:update(inputs, ruleset)
|
||||
return
|
||||
end
|
||||
|
||||
if self.lock_drop and inputs["down"] ~= true then
|
||||
if (self.lock_drop or (
|
||||
not ruleset.are or self:getARE() == 0
|
||||
)) and inputs["down"] ~= true then
|
||||
self.drop_locked = false
|
||||
end
|
||||
|
||||
if self.lock_hard_drop and inputs["up"] ~= true then
|
||||
if (self.lock_hard_drop or (
|
||||
not ruleset.are or self:getARE() == 0
|
||||
)) 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.enable_hard_drop, self.additive_gravity, self.classic_lock
|
||||
)
|
||||
|
||||
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
|
||||
@@ -208,12 +216,13 @@ function GameMode:update(inputs, ruleset)
|
||||
inputs.rotate_180
|
||||
))
|
||||
) then
|
||||
self.das.frames = math.max(
|
||||
self.das.frames - self:getDasCutDelay(),
|
||||
-(self:getDasCutDelay() + 1)
|
||||
)
|
||||
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 inputs["up"] == true and
|
||||
self.piece:isDropBlocked(self.grid) and
|
||||
not self.hard_drop_locked then
|
||||
@@ -244,7 +253,7 @@ function GameMode:update(inputs, ruleset)
|
||||
self:onPieceLock(self.piece, cleared_row_count)
|
||||
self:updateScore(self.level, self.drop_bonus, cleared_row_count)
|
||||
|
||||
self.grid:markClearedRows()
|
||||
self.cleared_block_table = self.grid:markClearedRows()
|
||||
self.piece = nil
|
||||
if self.enable_hold then
|
||||
self.held = false
|
||||
@@ -258,6 +267,7 @@ 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
|
||||
@@ -287,13 +297,17 @@ end
|
||||
|
||||
-- event functions
|
||||
function GameMode:whilePieceActive() end
|
||||
function GameMode:onAttemptPieceMove(piece) end
|
||||
function GameMode:onAttemptPieceRotate(piece) 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: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
|
||||
@@ -382,6 +396,13 @@ 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
|
||||
@@ -425,7 +446,9 @@ 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)
|
||||
@@ -513,10 +536,14 @@ 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 then
|
||||
if self.lock_drop or (
|
||||
not ruleset.are or self:getARE() == 0
|
||||
) then
|
||||
self.drop_locked = true
|
||||
end
|
||||
if self.lock_hard_drop then
|
||||
if self.lock_hard_drop or (
|
||||
not ruleset.are or self:getARE() == 0
|
||||
) then
|
||||
self.hard_drop_locked = true
|
||||
end
|
||||
if generate_next_piece == nil then
|
||||
@@ -536,14 +563,87 @@ 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
|
||||
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
|
||||
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, 0.25 + 0.75 * b, self.grid)
|
||||
end
|
||||
end
|
||||
|
||||
@@ -676,7 +776,9 @@ function GameMode:drawSectionTimesWithSecondary(current_section, section_limit)
|
||||
end
|
||||
end
|
||||
|
||||
function GameMode:drawSectionTimesWithSplits(current_section)
|
||||
function GameMode:drawSectionTimesWithSplits(current_section, section_limit)
|
||||
section_limit = section_limit or math.huge
|
||||
|
||||
local section_x = 440
|
||||
local split_x = 530
|
||||
|
||||
@@ -684,15 +786,19 @@ function GameMode:drawSectionTimesWithSplits(current_section)
|
||||
|
||||
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
|
||||
|
||||
|
||||
@@ -171,7 +171,6 @@ 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
|
||||
|
||||
|
||||
@@ -52,23 +52,14 @@ function StrategyGame:getLineClearDelay()
|
||||
end
|
||||
|
||||
function StrategyGame:getLockDelay()
|
||||
if self.level < 500 then return 8
|
||||
elseif self.level < 700 then return 6
|
||||
else return 4 end
|
||||
if self.level < 700 then return 8
|
||||
else return 6 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
|
||||
|
||||
@@ -94,12 +94,8 @@ function Survival2020Game:getGravity()
|
||||
return 20
|
||||
end
|
||||
|
||||
function Survival2020Game:getNextPiece(ruleset)
|
||||
return {
|
||||
skin = self.level >= 1000 and "bone" or "2tie",
|
||||
shape = self.randomizer:nextPiece(),
|
||||
orientation = ruleset:getDefaultOrientation(),
|
||||
}
|
||||
function Survival2020Game:getSkin()
|
||||
return self.level >= 1000 and "bone" or "2tie"
|
||||
end
|
||||
|
||||
function Survival2020Game:hitTorikan(old_level, new_level)
|
||||
|
||||
@@ -30,6 +30,11 @@ 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
|
||||
@@ -69,7 +74,8 @@ function SurvivalA2Game:getGravity()
|
||||
end
|
||||
|
||||
function SurvivalA2Game:hitTorikan(old_level, new_level)
|
||||
if old_level < 500 and new_level >= 500 and self.frames > frameTime(3,25) then
|
||||
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
|
||||
self.level = 500
|
||||
return true
|
||||
end
|
||||
|
||||
@@ -18,6 +18,7 @@ ARS.colourscheme = {
|
||||
|
||||
ARS.softdrop_lock = false
|
||||
ARS.harddrop_lock = true
|
||||
ARS.spawn_above_field = true
|
||||
|
||||
function ARS:onPieceCreate(piece, grid)
|
||||
piece.floorkick = 0
|
||||
|
||||
@@ -5,6 +5,7 @@ local ARS = Ruleset:extend()
|
||||
|
||||
ARS.name = "ACE-ARS2"
|
||||
ARS.hash = "ArikaACE2"
|
||||
ARS.spawn_above_field = true
|
||||
|
||||
function ARS:onPieceCreate(piece, grid)
|
||||
piece.floorkick = 0
|
||||
|
||||
@@ -17,17 +17,22 @@ SRS.colourscheme = {
|
||||
}
|
||||
SRS.softdrop_lock = false
|
||||
SRS.harddrop_lock = true
|
||||
SRS.spawn_above_field = true
|
||||
|
||||
SRS.MANIPULATIONS_MAX = 128
|
||||
|
||||
function SRS:onPieceRotate(piece, grid)
|
||||
function SRS:onPieceRotate(piece, grid, upward)
|
||||
piece.lock_delay = 0 -- rotate reset
|
||||
if piece:isDropBlocked(grid) then
|
||||
if upward or piece:isDropBlocked(grid) then
|
||||
piece.manipulations = piece.manipulations + 1
|
||||
if piece.manipulations >= self.MANIPULATIONS_MAX then
|
||||
if piece.manipulations >= self.MANIPULATIONS_MAX and piece:isDropBlocked(grid) then
|
||||
piece.locked = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SRS:canPieceRotate(piece)
|
||||
return piece.manipulations < self.MANIPULATIONS_MAX
|
||||
end
|
||||
|
||||
return SRS
|
||||
|
||||
@@ -96,6 +96,9 @@ 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
|
||||
|
||||
|
||||
@@ -23,6 +23,7 @@ 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",
|
||||
@@ -114,7 +115,9 @@ 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")
|
||||
@@ -159,28 +162,43 @@ function Ruleset:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
||||
end
|
||||
|
||||
function Ruleset:movePiece(piece, grid, move, instant)
|
||||
local x = piece.position.x
|
||||
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
|
||||
piece:moveInGrid({x=-1, y=0}, 1, grid, false)
|
||||
offset.x = -1
|
||||
moves = 1
|
||||
elseif move == "right" then
|
||||
piece:moveInGrid({x=1, y=0}, 1, grid, false)
|
||||
offset.x = 1
|
||||
moves = 1
|
||||
elseif move == "speedleft" then
|
||||
piece:moveInGrid({x=-1, y=0}, grid.width, grid, instant)
|
||||
offset.x = -1
|
||||
moves = grid.width
|
||||
elseif move == "speedright" then
|
||||
piece:moveInGrid({x=1, y=0}, grid.width, grid, instant)
|
||||
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)
|
||||
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
|
||||
hard_drop_enabled, additive_gravity, classic_lock
|
||||
)
|
||||
if piece.big then
|
||||
gravity = gravity / 2
|
||||
@@ -190,26 +208,29 @@ 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)
|
||||
piece:addGravity(gravity + drop_speed, grid, classic_lock)
|
||||
else
|
||||
piece:addGravity(math.max(gravity, drop_speed), grid)
|
||||
piece:addGravity(math.max(gravity, drop_speed), grid, classic_lock)
|
||||
end
|
||||
elseif inputs["up"] == true and hard_drop_enabled == true then
|
||||
if hard_drop_locked == true or piece:isDropBlocked(grid) then
|
||||
piece:addGravity(gravity, grid)
|
||||
piece:addGravity(gravity, grid, classic_lock)
|
||||
else
|
||||
piece:dropToBottom(grid)
|
||||
end
|
||||
else
|
||||
piece:addGravity(gravity, grid)
|
||||
piece:addGravity(gravity, grid, classic_lock)
|
||||
end
|
||||
if piece.position.y ~= y then
|
||||
self:onPieceDrop(piece, grid)
|
||||
end
|
||||
end
|
||||
|
||||
function Ruleset:lockPiece(piece, grid, lock_delay)
|
||||
if piece:isDropBlocked(grid) and piece.gravity >= 1 and piece.lock_delay >= lock_delay then
|
||||
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
|
||||
piece.locked = true
|
||||
end
|
||||
end
|
||||
@@ -243,10 +264,17 @@ function Ruleset:initializePiece(
|
||||
end
|
||||
end
|
||||
|
||||
local spawn_dy = (
|
||||
config.gamesettings.spawn_positions == 2 and
|
||||
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
|
||||
2 or 0
|
||||
)
|
||||
end
|
||||
|
||||
local piece = Piece(data.shape, data.orientation - 1, {
|
||||
x = spawn_x and spawn_x or spawn_positions[data.shape].x,
|
||||
@@ -278,7 +306,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
|
||||
hard_drop_enabled, additive_gravity, classic_lock
|
||||
)
|
||||
|
||||
local synchroes_allowed = ({not self.world, true, false})[config.gamesettings.synchroes_allowed]
|
||||
@@ -292,11 +320,13 @@ function Ruleset:processPiece(
|
||||
end
|
||||
self:dropPiece(
|
||||
inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked,
|
||||
hard_drop_enabled, additive_gravity
|
||||
hard_drop_enabled, additive_gravity, classic_lock
|
||||
)
|
||||
self:lockPiece(piece, grid, lock_delay)
|
||||
self:lockPiece(piece, grid, lock_delay, classic_lock)
|
||||
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
|
||||
|
||||
@@ -92,11 +92,14 @@ 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
|
||||
if piece.manipulations >= SRS.MANIPULATIONS_MAX then
|
||||
piece.locked = true
|
||||
end
|
||||
end
|
||||
end
|
||||
|
||||
function SRS:canPieceRotate() return true end
|
||||
|
||||
return SRS
|
||||
|
||||
@@ -54,7 +54,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)
|
||||
self:onPieceRotate(piece, grid, offset.y < 0)
|
||||
return
|
||||
end
|
||||
end
|
||||
@@ -69,7 +69,10 @@ end
|
||||
|
||||
function SRS:onPieceDrop(piece, grid)
|
||||
self:checkNewLow(piece)
|
||||
if piece.manipulations >= self.MANIPULATIONS_MAX and piece:isDropBlocked(grid) then
|
||||
if (
|
||||
piece.manipulations >= self.MANIPULATIONS_MAX or
|
||||
piece.rotations >= self.ROTATIONS_MAX
|
||||
) and piece:isDropBlocked(grid) then
|
||||
piece.locked = true
|
||||
else
|
||||
piece.lock_delay = 0 -- step reset
|
||||
@@ -86,18 +89,20 @@ function SRS:onPieceMove(piece, grid)
|
||||
end
|
||||
end
|
||||
|
||||
function SRS:onPieceRotate(piece, grid)
|
||||
function SRS:onPieceRotate(piece, grid, upward)
|
||||
piece.lock_delay = 0 -- rotate reset
|
||||
self:checkNewLow(piece)
|
||||
if piece.rotations >= self.ROTATIONS_MAX then
|
||||
if upward or piece:isDropBlocked(grid) then
|
||||
piece.rotations = piece.rotations + 1
|
||||
piece:moveInGrid({ x = 0, y = 1 }, 1, grid)
|
||||
if piece:isDropBlocked(grid) then
|
||||
if piece.rotations >= self.ROTATIONS_MAX and 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
|
||||
|
||||
@@ -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,16 +182,20 @@ function SRS:onPieceMove(piece, grid)
|
||||
end
|
||||
end
|
||||
|
||||
function SRS:onPieceRotate(piece, grid)
|
||||
function SRS:onPieceRotate(piece, grid, upward)
|
||||
piece.lock_delay = 0 -- rotate reset
|
||||
if piece:isDropBlocked(grid) then
|
||||
if upward or piece:isDropBlocked(grid) then
|
||||
piece.rotations = piece.rotations + 1
|
||||
if piece.rotations >= self.ROTATIONS_MAX then
|
||||
if piece.rotations >= self.ROTATIONS_MAX and 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 3 end
|
||||
|
||||
return SRS
|
||||
|
||||
Reference in New Issue
Block a user