Compare commits

..

18 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
14 changed files with 161 additions and 100 deletions

View File

@@ -7,7 +7,7 @@ Welcome to Cambridge, the next open-source falling-block game engine!
The project is written and maintained exclusively by [SashLilac](https://github.com/SashLilac), [joezeng](https://github.com/joezeng) and [Oshisaure](https://github.com/oshisaure)! The 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)

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)
@@ -98,6 +93,18 @@ 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 -- Return the number of digits in the big
function bigint.digits(big) function bigint.digits(big)
bigint.check(big) bigint.check(big)

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

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

@@ -137,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
@@ -150,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
@@ -193,6 +193,7 @@ function GameMode:update(inputs, ruleset)
-- 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(
@@ -203,6 +204,7 @@ function GameMode:update(inputs, ruleset)
) )
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
@@ -214,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
@@ -294,8 +297,11 @@ 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
@@ -390,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
@@ -773,14 +786,15 @@ function GameMode:drawSectionTimesWithSplits(current_section, section_limit)
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 if (current_section <= section_limit) then
love.graphics.setColor(self:sectionColourFunction(current_section))
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

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

@@ -21,14 +21,18 @@ 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

@@ -115,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")
@@ -160,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
@@ -191,18 +208,18 @@ 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)
@@ -303,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, classic_lock) 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