Compare commits

..

38 Commits

Author SHA1 Message Date
Ishaan Bhardwaj
891f96e814 I broke the DAS switch functionality 2020-12-03 14:10:46 -05:00
Ishaan Bhardwaj
36837a3af5 Update main.lua 2020-12-03 13:45:23 -05:00
Ishaan Bhardwaj
01b0f9f618 DAS switch behavior implemented 2020-12-02 21:09:52 -05:00
Ishaan Bhardwaj
7c8c5bb11d Hide hold queue when hold is disabled 2020-12-02 13:41:47 -05:00
Ishaan Bhardwaj
acaa6bdbbf whoops forgot to not require socket 2020-12-01 11:58:29 -05:00
Ishaan Bhardwaj
c37757f592 Implement an axis timer (fixes #12) 2020-12-01 11:57:09 -05:00
Ishaan Bhardwaj
905e4bcc77 drawSectionTimesWithSecondary update 2020-12-01 11:56:44 -05:00
Ishaan Bhardwaj
d956647678 Core mode rebalancing 2020-12-01 11:56:28 -05:00
Ishaan Bhardwaj
10f032b49b Added more functionality to advanceOneFrame 2020-11-30 12:34:21 -05:00
Ishaan Bhardwaj
5590e6c89b Small DAS changes 2020-11-29 11:11:47 -05:00
Joe Z
0393396d74 Made instant DAS respect instant gravity. 2020-11-29 09:19:17 -05:00
Joe Zeng
8c1eaec1aa DAS priority reversal (#25)
* Reversed the priority of key presses when charging DAS.
* Made it an actual config option.
* Config should be false by default.
2020-11-28 23:29:46 -05:00
Ishaan Bhardwaj
957802a78e Fixed a minor bug in the scope of SA2's line 2020-11-27 23:21:59 -05:00
Ishaan Bhardwaj
169a4e4d2f AX4 no longer shows timer in the roll 2020-11-22 10:39:42 -05:00
Ishaan Bhardwaj
48aee18340 Fix I wallkicks in ARS rules 2020-11-21 23:29:06 -05:00
Ishaan Bhardwaj
7b496d9412 Ti and ACE floorkick fix 2020-11-21 21:48:45 -05:00
Ishaan Bhardwaj
7abb861446 Hard drop can ARE cancel now 2020-11-21 16:29:24 -05:00
Ishaan Bhardwaj
21f8769228 Made ARE canceling also cancel LCD 2020-11-20 11:29:46 -05:00
Ishaan Bhardwaj
44423fd2e8 Made ARE canceling less slippery (again) 2020-11-19 22:22:43 -05:00
Ishaan Bhardwaj
351fb4cfe9 Added the functionality to draw only an outline of the stack 2020-11-18 12:17:04 -05:00
Ishaan Bhardwaj
103f04ceaa added a misc function 2020-11-17 21:52:20 -05:00
Ishaan Bhardwaj
88d2f0d8d1 Made ARE canceling more consistent. 2020-11-17 13:50:38 -05:00
Ishaan Bhardwaj
e100289c82 Made ARE canceling less slippery 2020-11-16 22:23:05 -05:00
Ishaan Bhardwaj
e38da49180 ARE canceling 2020-11-16 21:16:59 -05:00
Ishaan Bhardwaj
b03473d2fe IRS fix 2020-11-16 12:51:21 -05:00
Ishaan Bhardwaj
cf6e0be4e7 New IRS and IHS settings 2020-11-16 12:48:28 -05:00
Ishaan Bhardwaj
2bc9dc179c Updated README with another contributor 2020-11-14 20:00:24 -05:00
Ishaan Bhardwaj
d626926d5a Fixed 180 rotation directions 2020-11-14 19:20:25 -05:00
Ishaan Bhardwaj
721acefea0 Cleaned up TAP M-roll 2020-11-14 09:35:16 -05:00
Ishaan Bhardwaj
b9b71e90bb Finished Marathon 2020 grading! 2020-11-12 17:01:28 -05:00
Ishaan Bhardwaj
9f61b139fd TAP M-roll created 2020-11-12 16:52:40 -05:00
Ishaan Bhardwaj
3b0fdba27d Updated README.md to have the updated mod pack 2020-11-12 09:45:48 -05:00
Ishaan Bhardwaj
d8fad3dc37 Added some more developer functions, to aid in building modes. 2020-11-11 22:30:30 -05:00
Ishaan Bhardwaj
f9368fa806 Forgot to add a contributor, whoops... 2020-11-11 11:11:55 -05:00
Ishaan Bhardwaj
189feb1802 Fixed the last of the hard drop safelocks... 2020-11-10 23:13:25 -05:00
Ishaan Bhardwaj
dc09dabacb Fixed Phantom Mania safelock behaviors 2020-11-10 23:10:39 -05:00
Ishaan Bhardwaj
e13278c6a8 Fixed safelock behavior for hard drop modes 2020-11-10 22:34:48 -05:00
Ishaan Bhardwaj
f7f11b0e22 Updated README.md with new Windows instructions 2020-11-10 21:41:34 -05:00
23 changed files with 325 additions and 106 deletions

View File

@@ -28,12 +28,34 @@ The following people in no particular order also helped with the project:
- [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)
Playing the game
----------------
### Windows
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.
If you want the bleeding edge version, or want mod pack support, download [this](https://github.com/SashLilac/cambridge/archive/master.zip).
Extract the ZIP, open a Command Prompt at the folder you extracted Cambridge to, then run this command:
dist\windows\love.exe .
Alternatively, if you're on a 32-bit system, run this instead:
dist\win32\love.exe .
32-bit systems do not support rich presence integration.
Then, check the mod pack section at the bottom of this page.
### macOS, Linux
If you haven't already, install `love` with your favourite package manager (Homebrew on macOS, your system's default on Linux). **Make sure you're using LÖVE 11, because it won't work with earlier versions!**
@@ -50,25 +72,11 @@ Then, navigate to the root directory that you just cloned, and type:
It should run automatically!
### Windows
You do not need LÖVE on Windows, as it comes bundled with the program. Download the source code ZIP in the latest release, or if you want the bleeding edge version, download [this](https://github.com/SashLilac/cambridge/archive/master.zip).
Extract the ZIP, open a Command Prompt at the folder you extracted Cambridge to, then run this command:
dist\windows\love.exe .
Alternatively, if you're on a 32-bit system, run this instead:
dist\win32\love.exe .
32-bit systems do not support rich presence integration.
## Installing modpacks
Simply drag your mode, ruleset, and randomizer Lua files into their respective directory, and they should appear automatically.
Alternatively, install [this](https://files.catbox.moe/66td2i.zip) mod pack to get a taste of the mod potential.
Alternatively, install [this](https://github.com/SashLilac/cambridge-modpack) mod pack to get a taste of the mod potential.
License
-------

View File

@@ -15,7 +15,12 @@ function love.load()
love.window.setMode(love.graphics.getWidth(), love.graphics.getHeight(), {resizable = true});
if not config.gamesettings then config.gamesettings = {} end
if not config.gamesettings then
config.gamesettings = {}
config["das_last_key"] = false
else
config["das_last_key"] = config.gamesettings.das_last_key == 2
end
for _, option in ipairs(GameConfigScene.options) do
if not config.gamesettings[option[1]] then
config.gamesettings[option[1]] = 1

View File

@@ -9,6 +9,7 @@ ConfigScene.options = {
{"manlock", "Manual locking",{"Per ruleset","Per gamemode","Harddrop", "Softdrop"}},
{"piece_colour", "Piece Colours", {"Per ruleset","Arika" ,"TTC"}},
{"world_reverse","A Button Rotation", {"Left" ,"Auto" ,"Right"}},
{"das_last_key", "DAS Switch", {"Default", "Instant"}}
}
local optioncount = #ConfigScene.options
@@ -24,6 +25,7 @@ function ConfigScene:new()
end
function ConfigScene:update()
config["das_last_key"] = config.gamesettings.das_last_key == 2
end
function ConfigScene:render()

View File

@@ -32,6 +32,7 @@ function ConfigScene:new()
self.input_state = 1
self.set_inputs = newSetInputs()
self.new_input = {}
self.axis_timer = 0
DiscordRPC:update({
details = "In menus",
@@ -63,6 +64,8 @@ function ConfigScene:render()
love.graphics.print("press key or joystick input for " .. configurable_inputs[self.input_state] .. ", tab to skip" .. (config.input and ", escape to cancel" or ""), 0, 0)
love.graphics.print("function keys (F1, F2, etc.), escape, and tab can't be changed", 0, 20)
end
self.axis_timer = self.axis_timer + 1
end
local function addJoystick(input, name)
@@ -118,7 +121,7 @@ function ConfigScene:onInputPress(e)
self.new_input.joysticks[e.name].buttons[e.button] = configurable_inputs[self.input_state]
self.input_state = self.input_state + 1
elseif e.type == "joyaxis" then
if math.abs(e.value) >= 0.5 then
if (e.axis ~= self.last_axis or self.axis_timer > 30) and math.abs(e.value) >= 1 then
addJoystick(self.new_input, e.name)
if not self.new_input.joysticks[e.name].axes then
self.new_input.joysticks[e.name].axes = {}
@@ -128,10 +131,12 @@ function ConfigScene:onInputPress(e)
end
self.set_inputs[configurable_inputs[self.input_state]] =
"jaxis " ..
(e.value >= 0.5 and "+" or "-") .. e.axis ..
(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 >= 0.5 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.last_axis = e.axis
self.axis_timer = 0
end
elseif e.type == "joyhat" then
if e.direction ~= "c" then

View File

@@ -171,6 +171,20 @@ function Grid:applyFourWide()
end
end
function Grid:applyCeiling(lines)
for row = 1, lines do
for col = 1, 9 do
self.grid[row][col] = block
end
end
end
function Grid:clearSpecificRow(row)
for col = 1, 10 do
self.grid[row][col] = empty
end
end
function Grid:applyPiece(piece)
if piece.big then
self:applyBigPiece(piece)
@@ -216,6 +230,15 @@ function Grid:checkForBravo(cleared_row_count)
return true
end
function Grid:checkStackHeight()
for i = 0, 23 do
for j = 0, 9 do
if self:isOccupied(j, i) then return 24 - i end
end
end
return 0
end
function Grid:checkSecretGrade()
local sgrade = 0
for i=23,5,-1 do
@@ -296,7 +319,32 @@ function Grid:draw()
end
end
function Grid:drawInvisible(opacity_function, garbage_opacity_function)
function Grid:drawOutline()
for y = 5, 24 do
for x = 1, 10 do
if self.grid[y][x] ~= empty then
love.graphics.setColor(0.8, 0.8, 0.8, 1)
love.graphics.setLineWidth(1)
if y > 1 and self.grid[y-1][x] == empty then
love.graphics.line(48.0+x*16, -0.5+y*16, 64.0+x*16, -0.5+y*16)
end
if y < 24 and self.grid[y+1][x] == empty then
love.graphics.line(48.0+x*16, 16.5+y*16, 64.0+x*16, 16.5+y*16)
end
if x > 1 and self.grid[y][x-1] == empty then
love.graphics.line(47.5+x*16, -0.0+y*16, 47.5+x*16, 16.0+y*16)
end
if x < 10 and self.grid[y][x+1] == empty then
love.graphics.line(64.5+x*16, -0.0+y*16, 64.5+x*16, 16.0+y*16)
end
end
end
end
end
function Grid:drawInvisible(opacity_function, garbage_opacity_function, lock_flash, brightness)
lock_flash = lock_flash == nil and true or lock_flash
brightness = brightness == nil and 0.5 or brightness
for y = 5, 24 do
for x = 1, 10 do
if self.grid[y][x] ~= empty then
@@ -307,8 +355,9 @@ function Grid:drawInvisible(opacity_function, garbage_opacity_function)
else
opacity = opacity_function(self.grid_age[y][x])
end
love.graphics.setColor(0.5, 0.5, 0.5, opacity)
love.graphics.setColor(brightness, brightness, brightness, opacity)
love.graphics.draw(blocks[self.grid[y][x].skin][self.grid[y][x].colour], 48+x*16, y*16)
if lock_flash then
if opacity > 0 and self.grid[y][x].colour ~= "X" then
love.graphics.setColor(0.64, 0.64, 0.64)
love.graphics.setLineWidth(1)
@@ -329,5 +378,6 @@ function Grid:drawInvisible(opacity_function, garbage_opacity_function)
end
end
end
end
return Grid

View File

@@ -78,12 +78,15 @@ function Piece:setRelativeRotation(rot)
return self
end
function Piece:moveInGrid(step, squares, grid)
function Piece:moveInGrid(step, squares, grid, instant)
local moved = false
for x = 1, squares do
if grid:canPlacePiece(self:withOffset(step)) then
moved = true
self:setOffset(step)
if instant then
self:dropToBottom(grid)
end
else
break
end

View File

@@ -27,6 +27,7 @@ function MarathonA2Game:new()
self.randomizer = History6RollsRandomizer()
self.lock_drop = false
self.lock_hard_drop = false
self.enable_hold = false
self.next_queue_length = 1
end
@@ -124,7 +125,8 @@ function MarathonA2Game:onLineClear(cleared_row_count)
self.grid:clear()
self.roll_frames = -150
end
if self.level >= 900 then self.lock_drop = true end
self.lock_drop = self.level >= 900
self.lock_hard_drop = self.level >= 900
end
function MarathonA2Game:updateScore(level, drop_bonus, cleared_lines)
@@ -248,7 +250,7 @@ end
function MarathonA2Game:drawGrid(ruleset)
if self.clear and not (self.completed or self.game_over) then
self.grid:drawInvisible(self.rollOpacityFunction)
self.grid:drawInvisible(self.rollOpacityFunction, nil, false)
else
self.grid:draw()
if self.piece ~= nil and self.level < 100 then

View File

@@ -43,6 +43,8 @@ function GameMode:new()
self.draw_section_times = false
self.draw_secondary_section_times = false
self.big_mode = false
self.irs = true
self.ihs = true
self.rpc_details = "In game"
-- variables related to configurable parameters
self.drop_locked = false
@@ -94,10 +96,20 @@ function GameMode:update(inputs, ruleset)
if self.completed then return end
-- advance one frame
if self:advanceOneFrame(inputs) == false then return end
if self:advanceOneFrame(inputs, ruleset) == false then return end
self:chargeDAS(inputs, self:getDasLimit(), self.getARR())
-- set attempt flags
if inputs["left"] or inputs["right"] then self:onAttemptPieceMove(self.piece) end
if
inputs["rotate_left"] or inputs["rotate_right"] or
inputs["rotate_left2"] or inputs["rotate_right2"] or
inputs["rotate_180"]
then
self:onAttemptPieceRotate(self.piece)
end
if self.piece == nil then
self:processDelays(inputs, ruleset)
else
@@ -105,7 +117,7 @@ function GameMode:update(inputs, ruleset)
self:whilePieceActive()
local gravity = self:getGravity()
if self.enable_hold and inputs["hold"] == true and self.held == false then
if self.enable_hold and inputs["hold"] == true and self.held == false and self.prev_inputs["hold"] == false then
self:hold(inputs, ruleset)
self.prev_inputs = inputs
return
@@ -198,6 +210,8 @@ end
-- event functions
function GameMode:whilePieceActive() end
function GameMode:onAttemptPieceMove(piece) end
function GameMode:onAttemptPieceRotate(piece) end
function GameMode:onPieceLock(piece, cleared_row_count)
playSE("lock")
end
@@ -221,8 +235,25 @@ function GameMode:onGameOver()
switchBGM(nil)
end
function GameMode:chargeDAS(inputs)
if inputs[self.das.direction] == true then
-- DAS functions
function GameMode:startRightDAS()
self.move = "right"
self.das = { direction = "right", frames = 0 }
if self:getDasLimit() == 0 then
self:continueDAS()
end
end
function GameMode:startLeftDAS()
self.move = "left"
self.das = { direction = "left", frames = 0 }
if self:getDasLimit() == 0 then
self:continueDAS()
end
end
function GameMode:continueDAS()
local das_frames = self.das.frames + 1
if das_frames >= self:getDasLimit() then
if self.das.direction == "left" then
@@ -236,16 +267,35 @@ function GameMode:chargeDAS(inputs)
self.move = "none"
self.das.frames = das_frames
end
elseif inputs["right"] == true then
self.move = "right"
self.das = { direction = "right", frames = 0 }
elseif inputs["left"] == true then
self.move = "left"
self.das = { direction = "left", frames = 0 }
else
end
function GameMode:stopDAS()
self.move = "none"
self.das = { direction = "none", frames = -1 }
end
function GameMode:chargeDAS(inputs)
if config["das_last_key"] then
if inputs["right"] == true and self.das.direction ~= "right" and not self.prev_inputs["right"] then
self:startRightDAS()
elseif inputs["left"] == true and self.das.direction ~= "left" and not self.prev_inputs["left"] then
self:startLeftDAS()
elseif inputs[self.das.direction] == true then
self:continueDAS()
else
self:stopDAS()
end
else -- default behaviour, das first key pressed
if inputs[self.das.direction] == true then
self:continueDAS()
elseif inputs["right"] == true then
self:startRightDAS()
elseif inputs["left"] == true then
self:startLeftDAS()
else
self:stopDAS()
end
end
end
function GameMode:processDelays(inputs, ruleset, drop_speed)
@@ -268,6 +318,18 @@ function GameMode:processDelays(inputs, ruleset, drop_speed)
end
elseif self.lcd > 0 then
self.lcd = self.lcd - 1
if ruleset.are_cancel and
(self.move == "none" and not self.prev_inputs["up"] and
not self.prev_inputs["rotate_left"] and not self.prev_inputs["rotate_left2"] and
not self.prev_inputs["rotate_right"] and not self.prev_inputs["rotate_right2"] and
not self.prev_inputs["rotate_180"]) and
(inputs["left"] or inputs["right"] or inputs["up"] or
inputs["rotate_left"] or inputs["rotate_left2"] or
inputs["rotate_right"] or inputs["rotate_right2"] or
inputs["rotate_180"]) then
self.lcd = 0
self.are = 0
end
if self.lcd == 0 then
self.grid:clearClearedRows()
playSE("fall")
@@ -277,6 +339,17 @@ function GameMode:processDelays(inputs, ruleset, drop_speed)
end
elseif self.are > 0 then
self.are = self.are - 1
if ruleset.are_cancel and
(self.move == "none" and not self.prev_inputs["up"] and
not self.prev_inputs["rotate_left"] and not self.prev_inputs["rotate_left2"] and
not self.prev_inputs["rotate_right"] and not self.prev_inputs["rotate_right2"] and
not self.prev_inputs["rotate_180"]) and
(inputs["left"] or inputs["right"] or inputs["up"] or
inputs["rotate_left"] or inputs["rotate_left2"] or
inputs["rotate_right"] or inputs["rotate_right2"] or
inputs["rotate_180"]) then
self.are = 0
end
if self.are == 0 then
self:initializeOrHold(inputs, ruleset)
end
@@ -284,7 +357,7 @@ function GameMode:processDelays(inputs, ruleset, drop_speed)
end
function GameMode:initializeOrHold(inputs, ruleset)
if self.enable_hold and inputs["hold"] == true then
if self.ihs and self.enable_hold and inputs["hold"] == true then
self:hold(inputs, ruleset)
else
self:initializeNextPiece(inputs, ruleset, self.next_queue[1])
@@ -324,7 +397,8 @@ function GameMode:initializeNextPiece(inputs, ruleset, piece_data, generate_next
inputs, piece_data, self.grid, gravity,
self.prev_inputs, self.move,
self:getLockDelay(), self:getDropSpeed(),
self.lock_drop, self.lock_hard_drop, self.big_mode
self.lock_drop, self.lock_hard_drop, self.big_mode,
self.irs
)
if self.lock_drop then
self.drop_locked = true
@@ -388,7 +462,7 @@ function GameMode:drawNextQueue(ruleset)
drawPiece(next_piece, skin, ruleset.block_offsets[next_piece][rotation], -16+i*80, -32)
end
end
if self.hold_queue ~= nil then
if self.hold_queue ~= nil and self.enable_hold then
local hold_color = self.held and 0.6 or 1
self:setHoldOpacity(1, hold_color)
drawPiece(
@@ -445,7 +519,7 @@ function GameMode:drawSectionTimes(current_section)
love.graphics.printf(formatTime(self.frames - self.section_start_time), section_x, 40 + 20 * current_section, 90, "left")
end
function GameMode:drawSectionTimesWithSecondary(current_section)
function GameMode:drawSectionTimesWithSecondary(current_section, section_colour_function)
local section_x = 530
local section_secondary_x = 440
@@ -456,6 +530,9 @@ function GameMode:drawSectionTimesWithSecondary(current_section)
end
for section, time in pairs(self.secondary_section_times) do
if self.section_colour_function then
love.graphics.setColor(self:section_colour_function(section))
end
if section > 0 then
love.graphics.printf(formatTime(time), section_secondary_x, 40 + 20 * section, 90, "left")
end

View File

@@ -144,6 +144,7 @@ function Marathon2020Game:advanceOneFrame()
if self.roll_frames < 0 then
return false
elseif self.roll_frames > 4000 then
if self.grade >= 30 and self.section_cool_count >= 20 then self.grade = 31 end
self.completed = true
end
elseif self.ready_frames == 0 then
@@ -248,6 +249,7 @@ function Marathon2020Game:updateGrade(cleared_lines)
end
function Marathon2020Game:getTotalGrade()
if self.grade + self.section_cool_count > 50 then return "GM" end
return self.grade + self.section_cool_count
end
@@ -325,10 +327,10 @@ function Marathon2020Game:checkClear(level)
end
function Marathon2020Game:updateSectionTimes(old_level, new_level)
function sectionCool()
function sectionCool(section)
self.section_cool_count = self.section_cool_count + 1
self.delay_level = math.min(20, self.delay_level + 1)
table.insert(self.section_status, "cool")
if section < 10 then table.insert(self.section_status, "cool") end
self.cool_timer = 300
end
@@ -346,7 +348,7 @@ function Marathon2020Game:updateSectionTimes(old_level, new_level)
table.insert(self.section_times, section_time)
self.section_start_time = self.frames
if section > 4 then self.delay_level = math.min(20, self.delay_level + 1) end
if section > 5 then self.delay_level = math.min(20, self.delay_level + 1) end
self:checkTorikan(section)
self:checkClear(new_level)
@@ -355,11 +357,11 @@ function Marathon2020Game:updateSectionTimes(old_level, new_level)
self.secondary_section_times[section] < self.secondary_section_times[section - 1] + 120 and
self.secondary_section_times[section] < cool_cutoffs[section]
) then
sectionCool()
sectionCool(section)
elseif self.section_status[section - 1] == "cool" then
table.insert(self.section_status, "none")
elseif section <= 19 and self.secondary_section_times[section] < cool_cutoffs[section] then
sectionCool()
sectionCool(section)
else
table.insert(self.section_status, "none")
end
@@ -392,7 +394,6 @@ Marathon2020Game.mRollOpacityFunction = function(age)
end
function Marathon2020Game:qualifiesForMRoll()
return false -- until I actually have grading working
--[[
GM-roll requirements
@@ -403,6 +404,8 @@ You qualify for the GM roll if you:
- in less than 13:30.00 total.
]]--
return self.level >= 2020 and self:getTotalGrade() == 50 and self.frames <= frameTime(13,30)
end
function Marathon2020Game:drawGrid()
@@ -420,6 +423,14 @@ function Marathon2020Game:drawGrid()
end
end
function Marathon2020Game:sectionColourFunction(section)
if self.section_status[section] == "cool" then
return { 0, 1, 0, 1 }
else
return { 1, 1, 1, 1 }
end
end
function Marathon2020Game:drawScoringInfo()
Marathon2020Game.super.drawScoringInfo(self)
@@ -431,7 +442,7 @@ function Marathon2020Game:drawScoringInfo()
love.graphics.printf("GRADE PTS.", text_x, 200, 90, "left")
love.graphics.printf("LEVEL", text_x, 320, 40, "left")
self:drawSectionTimesWithSecondary(current_section)
self:drawSectionTimesWithSecondary(current_section, self.sectionColourFunction)
if (self.cool_timer > 0) then
love.graphics.printf("COOL!!", 64, 400, 160, "center")

View File

@@ -34,6 +34,7 @@ function MarathonA2Game:new()
}
self.lock_drop = false
self.lock_hard_drop = false
self.enable_hold = false
self.next_queue_length = 1
end
@@ -151,7 +152,8 @@ function MarathonA2Game:onLineClear(cleared_row_count)
if self:qualifiesForMRoll() then self.grade = 32 end
self.roll_frames = -150
end
if self.level >= 900 then self.lock_drop = true end
self.lock_drop = self.level >= 900
self.lock_hard_drop = self.level >= 900
end
function MarathonA2Game:updateSectionTimes(old_level, new_level)
@@ -308,12 +310,12 @@ MarathonA2Game.mRollOpacityFunction = function(age)
else return 1 - age / 4 end
end
function MarathonA2Game:drawGrid(ruleset)
function MarathonA2Game:drawGrid()
if self.clear and not (self.completed or self.game_over) then
if self:qualifiesForMRoll() then
self.grid:drawInvisible(self.mRollOpacityFunction)
self.grid:drawInvisible(self.mRollOpacityFunction, nil, false)
else
self.grid:drawInvisible(self.rollOpacityFunction)
self.grid:drawInvisible(self.rollOpacityFunction, nil, false)
end
else
self.grid:draw()

View File

@@ -231,8 +231,8 @@ function MarathonA3Game:updateSectionTimes(old_level, new_level)
end
function MarathonA3Game:updateScore(level, drop_bonus, cleared_lines)
if not self.clear then
self:updateGrade(cleared_lines)
if not self.clear then
if cleared_lines > 0 then
self.combo = self.combo + (cleared_lines - 1) * 2
self.score = self.score + (

View File

@@ -24,6 +24,7 @@ function MarathonAX4Game:new()
self.section_clear = false
self.lock_drop = true
self.lock_hard_drop = true
self.enable_hold = true
self.next_queue_length = 3
end
@@ -145,7 +146,7 @@ function MarathonAX4Game:drawScoringInfo()
strTrueValues(self.prev_inputs)
)
love.graphics.printf("NEXT", 64, 40, 40, "left")
love.graphics.printf("TIME LEFT", 240, 250, 80, "left")
if self.lines < 150 then love.graphics.printf("TIME LEFT", 240, 250, 80, "left") end
love.graphics.printf("LINES", 240, 320, 40, "left")
local current_section = math.floor(self.lines / 10) + 1
@@ -160,7 +161,7 @@ function MarathonAX4Game:drawScoringInfo()
if not self.game_over and not self.clear and time_left < frameTime(0,10) and time_left % 4 < 2 then
love.graphics.setColor(1, 0.3, 0.3, 1)
end
love.graphics.printf(formatTime(time_left), 240, 270, 160, "left")
if self.lines < 150 then love.graphics.printf(formatTime(time_left), 240, 270, 160, "left") end
love.graphics.setColor(1, 1, 1, 1)
end

View File

@@ -15,6 +15,7 @@ function PhantomManiaGame:new()
PhantomManiaGame.super:new()
self.lock_drop = true
self.lock_hard_drop = true
self.next_queue_length = 1
self.SGnames = {
@@ -138,7 +139,7 @@ end
function PhantomManiaGame:drawGrid()
if not (self.game_over or self.clear) then
self.grid:drawInvisible(self.rollOpacityFunction)
self.grid:drawInvisible(self.rollOpacityFunction, nil, false)
else
self.grid:draw()
end

View File

@@ -35,6 +35,7 @@ function PhantomMania2Game:new()
self.randomizer = History6RollsRandomizer()
self.lock_drop = true
self.lock_hard_drop = true
self.enable_hold = true
self.next_queue_length = 3
@@ -254,7 +255,7 @@ PhantomMania2Game.garbageOpacityFunction = function(age)
end
function PhantomMania2Game:drawGrid()
if not (self.game_over or (self.clear and self.level < 1300)) then
if not (self.game_over) then
self.grid:drawInvisible(self.rollOpacityFunction, self.garbageOpacityFunction)
else
self.grid:draw()

View File

@@ -0,0 +1,22 @@
local PhantomManiaGame = require 'tetris.modes.phantom_mania'
local PhantomManiaNGame = PhantomManiaGame:extend()
PhantomManiaNGame.name = "Phantom Mania N"
PhantomManiaNGame.hash = "PhantomManiaN"
PhantomManiaNGame.tagline = "The old mode from Nullpomino, for Ti-ARS and SRS support."
function PhantomManiaNGame:new()
PhantomManiaNGame.super:new()
self.SGnames = {
"M1", "M2", "M3", "M4", "M5", "M6", "M7", "M8", "M9",
"M10", "M11", "M12", "M13", "M14", "M15", "M16", "M17", "M18",
"GM"
}
self.next_queue_length = 3
self.enable_hold = true
end
return PhantomManiaNGame

View File

@@ -27,6 +27,7 @@ function Survival2020Game:new()
self.randomizer = History6RollsRandomizer()
self.lock_drop = true
self.lock_hard_drop = true
self.enable_hold = true
self.next_queue_length = 3
end

View File

@@ -27,6 +27,7 @@ function SurvivalA2Game:new()
}
self.lock_drop = true
self.lock_hard_drop = true
end
function SurvivalA2Game:getARE()
@@ -160,6 +161,7 @@ function SurvivalA2Game:drawScoringInfo()
if self.roll_frames > 2968 then love.graphics.setColor(1, 0.5, 0, 1)
elseif self.clear then love.graphics.setColor(0, 1, 0, 1) end
if self:getLetterGrade() ~= "" then love.graphics.printf(self:getLetterGrade(), text_x, 140, 90, "left") end
love.graphics.setColor(1, 1, 1, 1)
love.graphics.printf(self.level, text_x, 340, 40, "right")
love.graphics.printf(self:getSectionEndLevel(), text_x, 370, 40, "right")
if sg >= 5 then

View File

@@ -29,6 +29,7 @@ function SurvivalA3Game:new()
}
self.lock_drop = true
self.lock_hard_drop = true
self.enable_hold = true
self.next_queue_length = 3

View File

@@ -112,9 +112,9 @@ end
function ARS:get180RotationValue()
if config.gamesettings.world_reverse == 3 then
return 3
else
return 1
else
return 3
end
end

View File

@@ -113,7 +113,8 @@ function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid)
if piece.shape == "I" then
-- special kick rules for I
if new_piece.rotation == 0 or new_piece.rotation == 2 then
if new_piece.rotation == 0 or new_piece.rotation == 2 and
(piece:isMoveBlocked(grid, {x=-1, y=0}) or piece:isMoveBlocked(grid, {x=1, y=0})) then
-- kick right, right2, left
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
@@ -163,13 +164,16 @@ end
function ARS:onPieceDrop(piece, grid)
piece.lock_delay = 0 -- step reset
if piece.floorkick >= 2 and piece:isDropBlocked(grid) then
piece.locked = true
end
end
function ARS:onPieceMove(piece, grid)
piece.lock_delay = 0 -- move reset
if piece:isDropBlocked(grid) then
piece.manipulations = piece.manipulations + 1
if piece.manipulations >= 127 then
if piece.manipulations >= 128 then
piece.locked = true
end
end
@@ -179,17 +183,20 @@ function ARS:onPieceRotate(piece, grid)
piece.lock_delay = 0 -- rotate reset
if piece:isDropBlocked(grid) then
piece.manipulations = piece.manipulations + 1
if piece.manipulations >= 127 then
if piece.manipulations >= 128 then
piece.locked = true
end
end
if piece.floorkick >= 1 then
piece.floorkick = piece.floorkick + 1
end
end
function ARS:get180RotationValue()
if config.gamesettings.world_reverse == 3 then
return 3
else
return 1
else
return 3
end
end

View File

@@ -100,7 +100,8 @@ function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid)
if piece.shape == "I" then
-- special kick rules for I
if new_piece.rotation == 0 or new_piece.rotation == 2 then
if new_piece.rotation == 0 or new_piece.rotation == 2 and
(piece:isMoveBlocked(grid, {x=-1, y=0}) or piece:isMoveBlocked(grid, {x=1, y=0})) then
-- kick right, right2, left
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
@@ -150,13 +151,16 @@ end
function ARS:onPieceDrop(piece, grid)
piece.lock_delay = 0 -- step reset
if piece.floorkick >= 2 and piece:isDropBlocked(grid) then
piece.locked = true
end
end
function ARS:onPieceMove(piece, grid)
piece.lock_delay = 0 -- move reset
if piece:isDropBlocked(grid) then
piece.manipulations = piece.manipulations + 1
if piece.manipulations >= 127 then
if piece.manipulations >= 128 then
piece.locked = true
end
end
@@ -166,17 +170,20 @@ function ARS:onPieceRotate(piece, grid)
piece.lock_delay = 0 -- rotate reset
if piece:isDropBlocked(grid) then
piece.manipulations = piece.manipulations + 1
if piece.manipulations >= 127 then
if piece.manipulations >= 128 then
piece.locked = true
end
end
if piece.floorkick >= 1 then
piece.floorkick = piece.floorkick + 1
end
end
function ARS:get180RotationValue()
if config.gamesettings.world_reverse == 3 then
return 3
else
return 1
else
return 3
end
end

View File

@@ -100,7 +100,8 @@ function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid)
if piece.shape == "I" then
-- special kick rules for I
if new_piece.rotation == 0 or new_piece.rotation == 2 then
if (new_piece.rotation == 0 or new_piece.rotation == 2) and
(piece:isMoveBlocked(grid, {x=-1, y=0}) or piece:isMoveBlocked(grid, {x=1, y=0})) then
-- kick right, right2, left
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
@@ -149,13 +150,22 @@ end
function ARS:onPieceDrop(piece, grid)
piece.lock_delay = 0 -- step reset
if piece.floorkick >= 2 and piece:isDropBlocked(grid) then
piece.locked = true
end
end
function ARS:onPieceRotate(piece, grid)
if piece.floorkick >= 1 then
piece.floorkick = piece.floorkick + 1
end
end
function ARS:get180RotationValue()
if config.gamesettings.world_reverse == 3 then
return 3
else
return 1
else
return 3
end
end

View File

@@ -21,6 +21,7 @@ Ruleset.softdrop_lock = true
Ruleset.harddrop_lock = false
Ruleset.enable_IRS_wallkicks = false
Ruleset.are_cancel = false
-- Component functions.
@@ -127,16 +128,16 @@ function Ruleset:attemptWallkicks(piece, new_piece, rot_dir, grid)
-- do nothing in default ruleset
end
function Ruleset:movePiece(piece, grid, move)
function Ruleset:movePiece(piece, grid, move, instant)
local x = piece.position.x
if move == "left" then
piece:moveInGrid({x=-1, y=0}, 1, grid)
elseif move == "speedleft" then
piece:moveInGrid({x=-1, y=0}, 10, grid)
piece:moveInGrid({x=-1, y=0}, 1, grid, false)
elseif move == "right" then
piece:moveInGrid({x=1, y=0}, 1, grid)
piece:moveInGrid({x=1, y=0}, 1, grid, false)
elseif move == "speedleft" then
piece:moveInGrid({x=-1, y=0}, 10, grid, instant)
elseif move == "speedright" then
piece:moveInGrid({x=1, y=0}, 10, grid)
piece:moveInGrid({x=1, y=0}, 10, grid, instant)
end
if piece.position.x ~= x then
self:onPieceMove(piece, grid)
@@ -180,7 +181,7 @@ function Ruleset:getDefaultOrientation() return 1 end
function Ruleset:initializePiece(
inputs, data, grid, gravity, prev_inputs,
move, lock_delay, drop_speed,
drop_locked, hard_drop_locked, big
drop_locked, hard_drop_locked, big, irs
)
local spawn_positions
if big then
@@ -196,7 +197,7 @@ function Ruleset:initializePiece(
}, self.block_offsets, 0, 0, data.skin, colours[data.shape], big)
self:onPieceCreate(piece)
self:rotatePiece(inputs, piece, grid, {}, true)
if irs then self:rotatePiece(inputs, piece, grid, {}, true) end
self:dropPiece(inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked)
return piece
end
@@ -211,7 +212,7 @@ function Ruleset:processPiece(
hard_drop_enabled, additive_gravity
)
self:rotatePiece(inputs, piece, grid, prev_inputs, false)
self:movePiece(piece, grid, move)
self:movePiece(piece, grid, move, gravity >= 20)
self:dropPiece(
inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked,
hard_drop_enabled, additive_gravity