Compare commits

...

45 Commits

Author SHA1 Message Date
Ishaan Bhardwaj
83e498534c Merge branch 'master' of https://github.com/sashlilac/cambridge 2021-02-18 12:01:05 -05:00
Ishaan Bhardwaj
8f19c73e2a Simultaneous keyboard and joystick inputs implemented!
Implements #9!!!
2021-02-18 12:00:57 -05:00
Ishaan Bhardwaj
e36b855ff7 The Discord server is no longer sponsored by the project. 2021-02-18 10:42:19 -05:00
Ishaan Bhardwaj
23b58951cb World rule Survival A2 has a lenient torikan time 2021-02-17 22:46:33 -05:00
Ishaan Bhardwaj
1d73916b7c Arika-SRS rulesets no longer lock immediately 2021-02-17 18:29:14 -05:00
Ishaan Bhardwaj
3947e9f02f Fix the drop block lock rotation with SRS 2021-02-17 17:31:16 -05:00
Ishaan Bhardwaj
99b15803ee Adjusted 0 ARR to trigger onPieceMove multiple times 2021-02-17 17:21:51 -05:00
Ishaan Bhardwaj
d350b25726 Forgot to set guideline SRS to always rotate 2021-02-17 14:52:05 -05:00
Ishaan Bhardwaj
44e4d00172 Merge branch 'master' of https://github.com/sashlilac/cambridge 2021-02-17 14:48:42 -05:00
Ishaan Bhardwaj
31e2529265 Upward kicks for SRS count toward rotation limit 2021-02-17 14:48:35 -05:00
Ishaan Bhardwaj
ea7c75f0b3 Cambridge Discord Server temp. decommissioned
Please contact Milla#7746 on Discord for help.
2021-02-17 10:45:07 -05:00
Ishaan Bhardwaj
714c6b5e99 Floorkicks reworked (read comments)
If not classic lock, upward kicks reset to the top of the tile
2021-02-16 23:28:54 -05:00
Ishaan Bhardwaj
6a5d5a9c88 Fixed some modes' getNextPiece routines 2021-02-16 17:02:13 -05:00
Ishaan Bhardwaj
03491ba151 Strategy mode endgame nerfed 2021-02-16 16:57:31 -05:00
Ishaan Bhardwaj
6e22e3d15b Ti-ARS autolock fix 2021-02-16 16:19:51 -05:00
Ishaan Bhardwaj
66ab5992ad Added onPieceMove/Rotate/Drop for gamemodes 2021-02-16 15:27:57 -05:00
Ishaan Bhardwaj
2c07c2a58c BigInt changes, read extended description
Disabled strict type checking, can be re-enabled in bleeding edge. (This is done so bigint ops run faster)
Added a negation method and updated the corresponding metamethod to use it.
2021-02-16 13:03:53 -05:00
Ishaan Bhardwaj
a4d3f3bffc Update README.md 2021-02-16 13:00:07 -05:00
Ishaan Bhardwaj
9ac60cbb5e afterLineClear func added and splits time draw fix 2021-02-15 12:26:52 -05:00
Ishaan Bhardwaj
cdd846c3e6 Made the volume sliders scroll more consistently 2021-02-13 22:00:45 -05:00
Ishaan Bhardwaj
33d260b753 Removed the print statement from A2 2021-02-12 23:31:13 -05:00
Ishaan Bhardwaj
1644fcdf8e Bigint exponentiation by 1 now returns a clone 2021-02-12 10:05:04 -05:00
Ishaan Bhardwaj
f3c1cf6e1f Fixed an issue where DS-World wouldn't harddrop 2021-02-11 22:11:35 -05:00
Ishaan Bhardwaj
06a8a2ebf7 Mandate safelock on 0 ARE rulesets/modes 2021-02-11 22:08:52 -05:00
Ishaan Bhardwaj
15354ce004 dropToBottom no longer resets lock delay
it's already handled by the rulesets anyhow
2021-02-11 21:20:23 -05:00
Ishaan Bhardwaj
af02cd3467 Classic lock (GB/NES-like) added as a gamemode var 2021-02-11 15:46:56 -05:00
Ishaan Bhardwaj
acb05918c1 Custom line clear animations 2021-02-10 23:10:10 -05:00
Ishaan Bhardwaj
b644c8e457 Revert "Default line clear animation set to fadeout"
Please, reminder to self, TEST YOUR COMMITS.
This reverts commit 288961e12a.
2021-02-10 22:46:58 -05:00
Ishaan Bhardwaj
288961e12a Default line clear animation set to fadeout 2021-02-10 22:41:07 -05:00
Ishaan Bhardwaj
a047e51681 Framework for custom line clear animations added
Colored fadeout is the default
2021-02-10 18:35:51 -05:00
Ishaan Bhardwaj
77f24f5ee5 Human readable bigint output changes 2021-02-10 12:45:55 -05:00
Ishaan Bhardwaj
32c2274bef Optimized bigint exponentiation (again) 2021-02-10 11:38:10 -05:00
Ishaan Bhardwaj
4920e5de1c Added another type check to the bigint 2021-02-10 11:15:56 -05:00
Ishaan Bhardwaj
8418fc8ab7 Update README.md 2021-02-10 10:32:18 -05:00
Ishaan Bhardwaj
711a5120f1 Update README.md 2021-02-10 10:31:52 -05:00
Ishaan Bhardwaj
e7c3c9446a Cambridge banner looks better on dark theme now
Courtesy of @sinefuse
2021-02-10 09:05:10 -05:00
Ishaan Bhardwaj
3ac39acd7a Removed bigint comparison metamethods (read below)
Use bigint.compare from now on
2021-02-09 12:27:57 -05:00
Ishaan Bhardwaj
d0505251b3 Spawn positions now ruleset dependent
Is configurable in options
2021-02-08 23:23:50 -05:00
Ishaan Bhardwaj
bb0fe2ac20 BigInt now has a digits method (read comments)
Kind of unnecessary but included for completeness
2021-02-08 16:56:06 -05:00
Ishaan Bhardwaj
986ebac47f BigInt division fixed 2021-02-08 16:07:48 -05:00
Ishaan Bhardwaj
9799147f96 Revert "BigInt fixes and optimization (read comments)"
Apparently division *still* isn't being handled correctly.
This reverts commit 1dda12e4be.
2021-02-08 14:53:19 -05:00
Ishaan Bhardwaj
1dda12e4be BigInt fixes and optimization (read comments)
Fixed a nasty division bug where intermediate operations could result in negative zero. Optimized exponentiation to use exponentiation by squaring.
2021-02-08 14:10:34 -05:00
Ishaan Bhardwaj
38947e00c0 Added a tostring function for bigints 2021-02-08 10:34:47 -05:00
Ishaan Bhardwaj
035f6dd7b4 Fixed big division when (big1 < big2) 2021-02-08 10:23:10 -05:00
Ishaan Bhardwaj
aa3eadc93d Update README.md 2021-02-08 09:00:51 -05:00
20 changed files with 374 additions and 204 deletions

View File

@@ -1,13 +1,13 @@
![Cambridge Banner](https://cdn.discordapp.com/attachments/764432435802013709/767724895076614154/cambridge_logo_lt.png) ![Cambridge Banner](https://t-sp.in/public/img/cambridge.png)
Cambridge Cambridge
========= =========
Welcome to Cambridge, the next open-source falling-block game engine! 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 Credits
------- -------
@@ -17,19 +17,7 @@ Credits
- [The Tetra Legends Discord](http://discord.com/invite/7hMx5r2) for supporting me and playtesting! - [The Tetra Legends Discord](http://discord.com/invite/7hMx5r2) for supporting me and playtesting!
- [The Absolute Plus](https://discord.gg/6Gf2awJ) for being another source of motivation! - [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: More special thanks can be found in-game, under the "Credits" menu.
- [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) ![Cambridge Logo](https://cdn.discordapp.com/attachments/625496179433668635/763363717730664458/Icon_2.png)
@@ -40,7 +28,13 @@ Playing the game
You do not need LÖVE on Windows, as it comes bundled with the program. 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). 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 ## 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. 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.
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 License
------- -------

View File

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

View File

@@ -83,6 +83,7 @@ function GameScene:render()
end end
self.game:drawGrid() self.game:drawGrid()
if self.game.lcd > 0 then self.game:drawLineClearAnimation() end
self.game:drawPiece() self.game:drawPiece()
self.game:drawNextQueue(self.ruleset) self.game:drawNextQueue(self.ruleset)
self.game:drawScoringInfo() self.game:drawScoringInfo()

View File

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

View File

@@ -31,6 +31,7 @@ end
function ConfigScene:new() function ConfigScene:new()
self.input_state = 1 self.input_state = 1
self.key = 1
self.set_inputs = newSetInputs() self.set_inputs = newSetInputs()
self.new_input = {} self.new_input = {}
self.axis_timer = 0 self.axis_timer = 0
@@ -62,7 +63,7 @@ function ConfigScene:render()
if self.input_state > table.getn(configurable_inputs) then 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 "")) love.graphics.print("press enter to confirm, delete/backspace to retry" .. (config.input and ", escape to cancel" or ""))
else 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) love.graphics.print("function keys (F1, F2, etc.), escape, and tab can't be changed", 0, 20)
end end
@@ -97,18 +98,28 @@ function ConfigScene:onInputPress(e)
self.new_input = {} self.new_input = {}
end end
elseif e.scancode == "tab" then 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 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 -- all other keys can be configured
if not self.new_input.keys then if not self.new_input.keys then
self.new_input.keys = {} self.new_input.keys = {}
end end
self.set_inputs[configurable_inputs[self.input_state]] = "key " .. love.keyboard.getKeyFromScancode(e.scancode) .. " (" .. e.scancode .. ")" 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.new_input.keys[e.scancode] = configurable_inputs[self.input_state]
self.input_state = self.input_state + 1 self.key = 2
end 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 self.input_state <= table.getn(configurable_inputs) then
if e.type == "joybutton" then if e.type == "joybutton" then
addJoystick(self.new_input, e.name) addJoystick(self.new_input, e.name)
@@ -116,11 +127,13 @@ function ConfigScene:onInputPress(e)
self.new_input.joysticks[e.name].buttons = {} self.new_input.joysticks[e.name].buttons = {}
end end
self.set_inputs[configurable_inputs[self.input_state]] = self.set_inputs[configurable_inputs[self.input_state]] =
"jbtn " .. self.set_inputs[configurable_inputs[self.input_state]] ..
" / jbtn " ..
e.button .. e.button ..
" " .. string.sub(e.name, 1, 10) .. (string.len(e.name) > 10 and "..." or "") " " .. 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.new_input.joysticks[e.name].buttons[e.button] = configurable_inputs[self.input_state]
self.input_state = self.input_state + 1 self.input_state = self.input_state + 1
self.key = 1
elseif e.type == "joyaxis" then elseif e.type == "joyaxis" then
if (e.axis ~= self.last_axis or self.axis_timer > 30) and math.abs(e.value) >= 1 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) addJoystick(self.new_input, e.name)
@@ -131,11 +144,13 @@ function ConfigScene:onInputPress(e)
self.new_input.joysticks[e.name].axes[e.axis] = {} self.new_input.joysticks[e.name].axes[e.axis] = {}
end end
self.set_inputs[configurable_inputs[self.input_state]] = 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 .. (e.value >= 1 and "+" or "-") .. e.axis ..
" " .. string.sub(e.name, 1, 10) .. (string.len(e.name) > 10 and "..." or "") " " .. 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.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.input_state = self.input_state + 1
self.key = 1
self.last_axis = e.axis self.last_axis = e.axis
self.axis_timer = 0 self.axis_timer = 0
end end
@@ -149,11 +164,13 @@ function ConfigScene:onInputPress(e)
self.new_input.joysticks[e.name].hats[e.hat] = {} self.new_input.joysticks[e.name].hats[e.hat] = {}
end end
self.set_inputs[configurable_inputs[self.input_state]] = self.set_inputs[configurable_inputs[self.input_state]] =
"jhat " .. self.set_inputs[configurable_inputs[self.input_state]]
" / jhat " ..
e.hat .. " " .. e.direction .. e.hat .. " " .. e.direction ..
" " .. string.sub(e.name, 1, 10) .. (string.len(e.name) > 10 and "..." or "") " " .. 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.new_input.joysticks[e.name].hats[e.hat][e.direction] = configurable_inputs[self.input_state]
self.input_state = self.input_state + 1 self.input_state = self.input_state + 1
self.key = 1
end end
end end
end end

View File

@@ -111,18 +111,24 @@ function Grid:getClearedRowCount()
end end
function Grid:markClearedRows() function Grid:markClearedRows()
local block_table = {}
for row = 1, self.height do for row = 1, self.height do
if self:isRowFull(row) then if self:isRowFull(row) then
block_table[row] = {}
for x = 1, self.width do 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] = { self.grid[row][x] = {
skin = self.grid[row][x].skin, skin = self.grid[row][x].skin,
colour = "X" colour = "X"
} }
self.grid_age[row][x] = 0 --self.grid_age[row][x] = 0
end end
end end
end end
return true return block_table
end end
function Grid:clearClearedRows() function Grid:clearClearedRows()
@@ -388,7 +394,8 @@ end
function Grid:draw() function Grid:draw()
for y = 5, self.height do for y = 5, self.height do
for x = 1, self.width 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 if self.grid_age[y][x] < 2 then
love.graphics.setColor(1, 1, 1, 1) love.graphics.setColor(1, 1, 1, 1)
love.graphics.draw(blocks[self.grid[y][x].skin]["F"], 48+x*16, y*16) 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 if self.grid[y][x].skin == "bone" then
love.graphics.setColor(1, 1, 1, 1) love.graphics.setColor(1, 1, 1, 1)
elseif self.grid[y][x].colour == "X" then 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 else
love.graphics.setColor(0.5, 0.5, 0.5, 1) love.graphics.setColor(0.5, 0.5, 0.5, 1)
end end
@@ -427,10 +435,12 @@ end
function Grid:drawOutline() function Grid:drawOutline()
for y = 5, self.height do for y = 5, self.height do
for x = 1, self.width do for x = 1, self.width do
--[[
if self.grid[y][x].colour == "X" then 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.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) love.graphics.draw(blocks[self.grid[y][x].skin][self.grid[y][x].colour], 48+x*16, y*16)
end end
]]
if self.grid[y][x] ~= empty and self.grid[y][x].colour ~= "X" then 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.setColor(0.8, 0.8, 0.8, 1)
love.graphics.setLineWidth(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 for x = 1, self.width do
if self.grid[y][x] ~= empty then if self.grid[y][x] ~= empty then
if self.grid[y][x].colour == "X" 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 elseif garbage_opacity_function and self.grid[y][x].colour == "A" then
opacity = garbage_opacity_function(self.grid_age[y][x]) opacity = garbage_opacity_function(self.grid_age[y][x])
else else
@@ -506,7 +517,8 @@ function Grid:drawCustom(colour_function, gamestate)
if block ~= empty then if block ~= empty then
local R, G, B, A, outline = colour_function(gamestate, block, x, y, self.grid_age[y][x]) 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 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 end
love.graphics.setColor(R, G, B, A) 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) love.graphics.draw(blocks[self.grid[y][x].skin][self.grid[y][x].colour], 48+x*16, y*16)

View File

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

View File

@@ -45,6 +45,7 @@ function GameMode:new(secret_inputs)
self.enable_hard_drop = true self.enable_hard_drop = true
self.next_queue_length = 1 self.next_queue_length = 1
self.additive_gravity = true self.additive_gravity = true
self.classic_lock = false
self.draw_section_times = false self.draw_section_times = false
self.draw_secondary_section_times = false self.draw_secondary_section_times = false
self.big_mode = false self.big_mode = false
@@ -63,6 +64,7 @@ function GameMode:new(secret_inputs)
self.hard_drop_locked = false self.hard_drop_locked = false
self.lock_on_soft_drop = false self.lock_on_soft_drop = false
self.lock_on_hard_drop = false self.lock_on_hard_drop = false
self.cleared_block_table = {}
self.used_randomizer = nil self.used_randomizer = nil
self.hold_queue = nil self.hold_queue = nil
self.held = false self.held = false
@@ -135,7 +137,7 @@ function GameMode:update(inputs, ruleset)
-- set attempt flags -- set attempt flags
if inputs["left"] or inputs["right"] then 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 self.immobile_spin_bonus and self.piece ~= nil then
if not self.piece:isMoveBlocked(self.grid, { x=-1, y=0 }) and if not self.piece:isMoveBlocked(self.grid, { x=-1, y=0 }) and
not self.piece:isMoveBlocked(self.grid, { x=1, y=0 }) then 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_left2"] or inputs["rotate_right2"] or
inputs["rotate_180"] inputs["rotate_180"]
then then
self:onAttemptPieceRotate(self.piece) self:onAttemptPieceRotate(self.piece, self.grid)
if self.immobile_spin_bonus and self.piece ~= nil then if self.immobile_spin_bonus and self.piece ~= nil then
if self.piece:isDropBlocked(self.grid) and if self.piece:isDropBlocked(self.grid) and
self.piece:isMoveBlocked(self.grid, { x=-1, y=0 }) and self.piece:isMoveBlocked(self.grid, { x=-1, y=0 }) and
@@ -177,26 +179,32 @@ function GameMode:update(inputs, ruleset)
return return
end 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 self.drop_locked = false
end 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 self.hard_drop_locked = false
end end
-- diff vars to use in checks -- diff vars to use in checks
local piece_y = self.piece.position.y local piece_y = self.piece.position.y
local piece_x = self.piece.position.x
local piece_rot = self.piece.rotation local piece_rot = self.piece.rotation
ruleset:processPiece( ruleset:processPiece(
inputs, self.piece, self.grid, self:getGravity(), self.prev_inputs, inputs, self.piece, self.grid, self:getGravity(), self.prev_inputs,
self.move, self:getLockDelay(), self:getDropSpeed(), self.move, self:getLockDelay(), self:getDropSpeed(),
self.drop_locked, self.hard_drop_locked, 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_dy = self.piece.position.y - piece_y
local piece_dx = self.piece.position.x - piece_x
local piece_drot = self.piece.rotation - piece_rot local piece_drot = self.piece.rotation - piece_rot
-- das cut -- das cut
@@ -208,12 +216,13 @@ function GameMode:update(inputs, ruleset)
inputs.rotate_180 inputs.rotate_180
)) ))
) then ) then
self.das.frames = math.max( self:dasCut()
self.das.frames - self:getDasCutDelay(),
-(self:getDasCutDelay() + 1)
)
end 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 if inputs["up"] == true and
self.piece:isDropBlocked(self.grid) and self.piece:isDropBlocked(self.grid) and
not self.hard_drop_locked then not self.hard_drop_locked then
@@ -244,7 +253,7 @@ function GameMode:update(inputs, ruleset)
self:onPieceLock(self.piece, cleared_row_count) self:onPieceLock(self.piece, cleared_row_count)
self:updateScore(self.level, self.drop_bonus, 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 self.piece = nil
if self.enable_hold then if self.enable_hold then
self.held = false self.held = false
@@ -258,6 +267,7 @@ function GameMode:update(inputs, ruleset)
) )
if self.lcd == 0 then if self.lcd == 0 then
self.grid:clearClearedRows() self.grid:clearClearedRows()
self:afterLineClear(cleared_row_count)
if self.are == 0 then if self.are == 0 then
self:initializeOrHold(inputs, ruleset) self:initializeOrHold(inputs, ruleset)
end end
@@ -287,13 +297,17 @@ end
-- event functions -- event functions
function GameMode:whilePieceActive() end function GameMode:whilePieceActive() end
function GameMode:onAttemptPieceMove(piece) end function GameMode:onAttemptPieceMove(piece, grid) end
function GameMode:onAttemptPieceRotate(piece) 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) function GameMode:onPieceLock(piece, cleared_row_count)
playSE("lock") playSE("lock")
end end
function GameMode:onLineClear(cleared_row_count) end function GameMode:onLineClear(cleared_row_count) end
function GameMode:afterLineClear(cleared_row_count) end
function GameMode:onPieceEnter() end function GameMode:onPieceEnter() end
function GameMode:onHold() end function GameMode:onHold() end
@@ -382,6 +396,13 @@ function GameMode:chargeDAS(inputs)
end end
end end
function GameMode:dasCut()
self.das.frames = math.max(
self.das.frames - self:getDasCutDelay(),
-(self:getDasCutDelay() + 1)
)
end
function GameMode:areCancel(inputs, ruleset) function GameMode:areCancel(inputs, ruleset)
if ruleset.are_cancel and self.piece_hard_dropped and if ruleset.are_cancel and self.piece_hard_dropped and
not self.prev_inputs.up and not self.prev_inputs.up and
@@ -425,7 +446,9 @@ function GameMode:processDelays(inputs, ruleset, drop_speed)
self.lcd = self.lcd - 1 self.lcd = self.lcd - 1
self:areCancel(inputs, ruleset) self:areCancel(inputs, ruleset)
if self.lcd == 0 then if self.lcd == 0 then
local cleared_row_count = self.grid:getClearedRowCount()
self.grid:clearClearedRows() self.grid:clearClearedRows()
self:afterLineClear(cleared_row_count)
playSE("fall") playSE("fall")
if self.are == 0 then if self.are == 0 then
self:initializeOrHold(inputs, ruleset) self:initializeOrHold(inputs, ruleset)
@@ -513,10 +536,14 @@ function GameMode:initializeNextPiece(inputs, ruleset, piece_data, generate_next
if self.buffer_soft_drop then if self.buffer_soft_drop then
self.buffer_soft_drop = false self.buffer_soft_drop = false
end end
if self.lock_drop then if self.lock_drop or (
not ruleset.are or self:getARE() == 0
) then
self.drop_locked = true self.drop_locked = true
end 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 self.hard_drop_locked = true
end end
if generate_next_piece == nil then if generate_next_piece == nil then
@@ -536,14 +563,87 @@ function GameMode:getHighScoreData()
} }
end 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() function GameMode:drawPiece()
if self.piece ~= nil then if self.piece ~= nil then
self.piece:draw( local b = (
1, self.classic_lock and
self:getLockDelay() == 0 and 1 or (
(0.25 + 0.75 * math.max(1 - self.piece.gravity, 1 - (self.piece.lock_delay / self:getLockDelay()))), self.piece:isDropBlocked(self.grid) and
self.grid 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
end end
@@ -676,7 +776,9 @@ function GameMode:drawSectionTimesWithSecondary(current_section, section_limit)
end end
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 section_x = 440
local split_x = 530 local split_x = 530
@@ -684,15 +786,19 @@ function GameMode:drawSectionTimesWithSplits(current_section)
for section, time in pairs(self.section_times) do for section, time in pairs(self.section_times) do
if section > 0 then if section > 0 then
love.graphics.setColor(self:sectionColourFunction(section))
love.graphics.printf(formatTime(time), section_x, 40 + 20 * section, 90, "left") love.graphics.printf(formatTime(time), section_x, 40 + 20 * section, 90, "left")
love.graphics.setColor(1, 1, 1, 1)
split_time = split_time + time split_time = split_time + time
love.graphics.printf(formatTime(split_time), split_x, 40 + 20 * section, 90, "left") love.graphics.printf(formatTime(split_time), split_x, 40 + 20 * section, 90, "left")
end end
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 - 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") love.graphics.printf(formatTime(self.frames), split_x, 40 + 20 * current_section, 90, "left")
end end
end
function GameMode:drawCustom() end function GameMode:drawCustom() end

View File

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

View File

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

View File

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

View File

@@ -30,6 +30,11 @@ function SurvivalA2Game:new()
self.lock_hard_drop = true self.lock_hard_drop = true
end end
function SurvivalA2Game:initialize(ruleset)
SurvivalA2Game.super.initialize(self, ruleset)
self.world = ruleset.world
end
function SurvivalA2Game:getARE() function SurvivalA2Game:getARE()
if self.level < 100 then return 18 if self.level < 100 then return 18
elseif self.level < 300 then return 14 elseif self.level < 300 then return 14
@@ -69,7 +74,8 @@ function SurvivalA2Game:getGravity()
end end
function SurvivalA2Game:hitTorikan(old_level, new_level) 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 self.level = 500
return true return true
end end

View File

@@ -18,6 +18,7 @@ ARS.colourscheme = {
ARS.softdrop_lock = false ARS.softdrop_lock = false
ARS.harddrop_lock = true ARS.harddrop_lock = true
ARS.spawn_above_field = true
function ARS:onPieceCreate(piece, grid) function ARS:onPieceCreate(piece, grid)
piece.floorkick = 0 piece.floorkick = 0

View File

@@ -5,6 +5,7 @@ local ARS = Ruleset:extend()
ARS.name = "ACE-ARS2" ARS.name = "ACE-ARS2"
ARS.hash = "ArikaACE2" ARS.hash = "ArikaACE2"
ARS.spawn_above_field = true
function ARS:onPieceCreate(piece, grid) function ARS:onPieceCreate(piece, grid)
piece.floorkick = 0 piece.floorkick = 0

View File

@@ -17,17 +17,22 @@ SRS.colourscheme = {
} }
SRS.softdrop_lock = false SRS.softdrop_lock = false
SRS.harddrop_lock = true SRS.harddrop_lock = true
SRS.spawn_above_field = true
SRS.MANIPULATIONS_MAX = 128 SRS.MANIPULATIONS_MAX = 128
function SRS:onPieceRotate(piece, grid) function SRS:onPieceRotate(piece, grid, upward)
piece.lock_delay = 0 -- rotate reset piece.lock_delay = 0 -- rotate reset
if piece:isDropBlocked(grid) then if upward or piece:isDropBlocked(grid) then
piece.manipulations = piece.manipulations + 1 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 piece.locked = true
end end
end end
end end
function SRS:canPieceRotate(piece)
return piece.manipulations < self.MANIPULATIONS_MAX
end
return SRS return SRS

View File

@@ -96,6 +96,9 @@ end
function ARS:onPieceRotate(piece, grid) function ARS:onPieceRotate(piece, grid)
if piece.floorkick >= 1 then if piece.floorkick >= 1 then
piece.floorkick = piece.floorkick + 1 piece.floorkick = piece.floorkick + 1
if piece:isDropBlocked(grid) then
piece.locked = true
end
end end
end end

View File

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

View File

@@ -92,11 +92,14 @@ function SRS:onPieceRotate(piece, grid)
piece.lock_delay = 0 -- rotate reset piece.lock_delay = 0 -- rotate reset
self:checkNewLow(piece) self:checkNewLow(piece)
piece.manipulations = piece.manipulations + 1 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:isDropBlocked(grid) then
if piece.manipulations >= SRS.MANIPULATIONS_MAX then
piece.locked = true piece.locked = true
end end
end end
end end
function SRS:canPieceRotate() return true end
return SRS return SRS

View File

@@ -54,7 +54,7 @@ function SRS:attemptWallkicks(piece, new_piece, rot_dir, grid)
if grid:canPlacePiece(kicked_piece) then if grid:canPlacePiece(kicked_piece) then
piece:setRelativeRotation(rot_dir) piece:setRelativeRotation(rot_dir)
piece:setOffset(offset) piece:setOffset(offset)
self:onPieceRotate(piece, grid) self:onPieceRotate(piece, grid, offset.y < 0)
return return
end end
end end
@@ -69,7 +69,10 @@ end
function SRS:onPieceDrop(piece, grid) function SRS:onPieceDrop(piece, grid)
self:checkNewLow(piece) 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 piece.locked = true
else else
piece.lock_delay = 0 -- step reset piece.lock_delay = 0 -- step reset
@@ -86,18 +89,20 @@ function SRS:onPieceMove(piece, grid)
end end
end end
function SRS:onPieceRotate(piece, grid) function SRS:onPieceRotate(piece, grid, upward)
piece.lock_delay = 0 -- rotate reset piece.lock_delay = 0 -- rotate reset
self:checkNewLow(piece) if upward or piece:isDropBlocked(grid) then
if piece.rotations >= self.ROTATIONS_MAX then
piece.rotations = piece.rotations + 1 piece.rotations = piece.rotations + 1
piece:moveInGrid({ x = 0, y = 1 }, 1, grid) if piece.rotations >= self.ROTATIONS_MAX and piece:isDropBlocked(grid) then
if piece:isDropBlocked(grid) then
piece.locked = true piece.locked = true
end end
end end
end end
function SRS:canPieceRotate(piece)
return piece.rotations < self.ROTATIONS_MAX
end
function SRS:get180RotationValue() return 2 end function SRS:get180RotationValue() return 2 end
return SRS return SRS

View File

@@ -150,9 +150,9 @@ function SRS:attemptWallkicks(piece, new_piece, rot_dir, grid)
for idx, offset in pairs(kicks) do for idx, offset in pairs(kicks) do
kicked_piece = new_piece:withOffset(offset) kicked_piece = new_piece:withOffset(offset)
if grid:canPlacePiece(kicked_piece) then if grid:canPlacePiece(kicked_piece) then
self:onPieceRotate(piece, grid)
piece:setRelativeRotation(rot_dir) piece:setRelativeRotation(rot_dir)
piece:setOffset(offset) piece:setOffset(offset)
self:onPieceRotate(piece, grid, offset.y < 0)
return return
end end
end end
@@ -182,16 +182,20 @@ function SRS:onPieceMove(piece, grid)
end end
end end
function SRS:onPieceRotate(piece, grid) function SRS:onPieceRotate(piece, grid, upward)
piece.lock_delay = 0 -- rotate reset piece.lock_delay = 0 -- rotate reset
if piece:isDropBlocked(grid) then if upward or piece:isDropBlocked(grid) then
piece.rotations = piece.rotations + 1 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 piece.locked = true
end end
end end
end end
function SRS:canPieceRotate(piece)
return piece.rotations < self.ROTATIONS_MAX
end
function SRS:get180RotationValue() return 3 end function SRS:get180RotationValue() return 3 end
return SRS return SRS