mirror of
https://github.com/SashLilac/cambridge.git
synced 2025-05-13 20:21:25 -05:00
Compare commits
16 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
2b9740768b | ||
|
|
0e65b39395 | ||
|
|
ca04333bb7 | ||
|
|
80c7c99bd7 | ||
|
|
717afbebf6 | ||
|
|
7227085f84 | ||
|
|
c40392f00f | ||
|
|
001c8f0ea8 | ||
|
|
7fa0e60145 | ||
|
|
901f7f2d12 | ||
|
|
35f4aea67d | ||
|
|
7deaa5ab92 | ||
|
|
1254de15d5 | ||
|
|
5c5ffc6887 | ||
|
|
5131061e42 | ||
|
|
209e60e82e |
134
CONTRIBUTING.md
134
CONTRIBUTING.md
@@ -1,47 +1,3 @@
|
|||||||
Coding conventions
|
|
||||||
------------------
|
|
||||||
|
|
||||||
* Use tabs to indent, spaces to align.
|
|
||||||
* Specifically, spaces should not appear at the beginning of a line, and tabs should not appear _except_ at the beginning of a line.
|
|
||||||
* The sole exception is in a multiline `if` statement; the initial `if` should have four spaces before it to align it with an `elseif` on the next line. For example:
|
|
||||||
|
|
||||||
```lua
|
|
||||||
---- 4 spaces
|
|
||||||
if self.level < 900 then return 12
|
|
||||||
elseif self.level < 1200 then return 8
|
|
||||||
else return 6 end
|
|
||||||
```
|
|
||||||
|
|
||||||
* Comments at the end of lines of code must be one line long. Multi-line comments must appear in their own block.
|
|
||||||
|
|
||||||
```lua
|
|
||||||
if self.piece:isDropBlocked(self.grid) then
|
|
||||||
-- this is a comment that appears in a block of its own, separate from any code
|
|
||||||
-- consecutive multiline comments must have the same indentation level and
|
|
||||||
-- not appear next on the same line as actual code
|
|
||||||
self.drop_bonus = math.min(self.drop_bonus - 1, 0) -- comments at the end of a line must stay on that line
|
|
||||||
else
|
|
||||||
if piece_dy >= 1 then -- basically
|
|
||||||
self.drop_bonus = self.drop_bonus + piece_dy * 20 -- this sort of
|
|
||||||
end -- multiline comment
|
|
||||||
self.drop_bonus = self.drop_bonus + 1 -- is completely
|
|
||||||
end -- unacceptable
|
|
||||||
```
|
|
||||||
|
|
||||||
* Use `snake_case` for variables, `camelCase` for functions.
|
|
||||||
|
|
||||||
```lua
|
|
||||||
function MyGameMode:on_activate_bleep_bloop()
|
|
||||||
-- no, bad, use "onActivateBleepBloop"
|
|
||||||
local bleepBloopFrames = 240
|
|
||||||
-- this is also bad, use "bleep_bloop_frames"
|
|
||||||
local bleep_bloop_bonus = self.lock_delay * 150
|
|
||||||
self.bleepBloopSubscore = self.bleepBloopSubscore + bleep_bloop_bonus
|
|
||||||
-- member variables are also variables, this should be "bleep_bloop_subscore"
|
|
||||||
end
|
|
||||||
```
|
|
||||||
|
|
||||||
|
|
||||||
Contributor's License Agreement
|
Contributor's License Agreement
|
||||||
-------------------------------
|
-------------------------------
|
||||||
|
|
||||||
@@ -50,3 +6,93 @@ By contributing source code or other assets (e.g. music, artwork, graphics) to C
|
|||||||
You also waive all moral rights to your contributions insofar as they are used in the Cambridge repository or in any code or works deriving therefrom.
|
You also waive all moral rights to your contributions insofar as they are used in the Cambridge repository or in any code or works deriving therefrom.
|
||||||
|
|
||||||
(Notwithstanding the above clause, I will still make my best effort to provide sufficient attribution to all contributions. At the very least you'll get documentation of your contributions under SOURCES, and probably a special place in the credit roll as well.)
|
(Notwithstanding the above clause, I will still make my best effort to provide sufficient attribution to all contributions. At the very least you'll get documentation of your contributions under SOURCES, and probably a special place in the credit roll as well.)
|
||||||
|
|
||||||
|
|
||||||
|
Git / Repo conventions
|
||||||
|
----------------------
|
||||||
|
|
||||||
|
In general, use `kebab-case` for branch names. Also, make sure they're concise and descriptive - like 2 or 3 words is usually good.
|
||||||
|
|
||||||
|
```
|
||||||
|
* badbeef (badBranchName) This branch name is bad.
|
||||||
|
| * defaced (another_bad_branch_name) This branch name is also bad because it uses snake case.
|
||||||
|
|/
|
||||||
|
| * deadcab (generic) This branch name isn't very descriptive.
|
||||||
|
|/
|
||||||
|
| * bac0040 (this-long-winded-branch-name-that-could-be-its-own-commit-message) Self-explanatory.
|
||||||
|
|/
|
||||||
|
| * 600db01 (good-branch-name) This branch name is good.
|
||||||
|
|/
|
||||||
|
* 0000420 (HEAD -> master, tag: v0.6.9) This is a sexy root commit.
|
||||||
|
```
|
||||||
|
|
||||||
|
The top line of a commit message should generally be one full sentence long, without too many subordinate clauses. Don't sweat 50/72, but try not go over about 100 characters either.
|
||||||
|
* If the message starts with a verb, it should be written in the past tense, as a description of what the commit _did_ to the commit tree. (e.g. _Made_ a change, _Fixed_ a bug, _Added_ a feature)
|
||||||
|
* Alternatively, include a description (in the present tense) of what is now true thanks to this commit. (e.g. "The Puyo Puyo mode can now support up to 50 players.")
|
||||||
|
|
||||||
|
```
|
||||||
|
* 800000d (message-too-long) Made multiplayer stuff play well with the new v0.2.5 server by fixing a problem the client was having with sending multiple 4-KB packets within 2 milliseconds of each other.
|
||||||
|
| * defaced (not-descriptive-enough) Fixed stuff.
|
||||||
|
|/
|
||||||
|
| * bad0003 (present-tense) Lengthens the retry period of the server connection to 15 seconds.
|
||||||
|
|/
|
||||||
|
| * bad0004 (imperative-mood) Force the credit roll to end after 67 seconds if no input is detected.
|
||||||
|
|/
|
||||||
|
| * 600d001 (good-commit-summary) Made the Jenny Marathon mode not top out randomly at level 600.
|
||||||
|
| * 600d002 (also-good) Backgrounds don't suck anymore.
|
||||||
|
|/
|
||||||
|
* 1234567 (HEAD -> master, tag: v0.4.2) Updated docs in preparation for a new release.
|
||||||
|
```
|
||||||
|
|
||||||
|
When making pull requests, always include:
|
||||||
|
|
||||||
|
* A title that works well as a commit title, since that's what's going to appear when it's merged.
|
||||||
|
* A full description of the problem that the pull request solves or the feature that it implements.
|
||||||
|
* If the whole purpose of the pull request is to resolve a particular issue and nothing else, "Fixes #[issue number]" counts as a full description. Otherwise if there's anything else in the pull request, make a short note of "also [did this other thing]".
|
||||||
|
|
||||||
|
|
||||||
|
Coding conventions
|
||||||
|
------------------
|
||||||
|
|
||||||
|
Use tabs to indent, spaces to align.
|
||||||
|
|
||||||
|
* Specifically, spaces should not appear at the beginning of a line, and tabs should not appear _except_ at the beginning of a line.
|
||||||
|
* The sole exception is in a multiline `if` statement; the initial `if` should have four spaces before it to align it with an `elseif` on the next line. For example:
|
||||||
|
|
||||||
|
```lua
|
||||||
|
---- 4 spaces
|
||||||
|
if self.level < 900 then return 12
|
||||||
|
elseif self.level < 1200 then return 8
|
||||||
|
else return 6 end
|
||||||
|
```
|
||||||
|
|
||||||
|
Comments at the end of lines of code must be one line long. Multi-line comments must appear in their own block.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
if not self.piece:isDropBlocked(self.grid) then
|
||||||
|
-- this is a comment that appears in a block of its own, separate from any code
|
||||||
|
-- consecutive multiline comments must have the same indentation level and
|
||||||
|
-- not appear next on the same line as actual code
|
||||||
|
self.drop_bonus = 0 -- comments at the end of a line must stay on that line
|
||||||
|
else
|
||||||
|
if piece_dy >= 1 then -- basically
|
||||||
|
self.drop_bonus = self.drop_bonus + piece_dy * 20 -- this sort of
|
||||||
|
end -- multiline comment
|
||||||
|
self.drop_bonus = self.drop_bonus + 1 -- is completely
|
||||||
|
end -- unacceptable
|
||||||
|
```
|
||||||
|
|
||||||
|
Use `snake_case` for variables, `camelCase` for functions.
|
||||||
|
|
||||||
|
```lua
|
||||||
|
function MyGameMode:on_activate_bleep_bloop()
|
||||||
|
-- no, bad, use "onActivateBleepBloop"
|
||||||
|
|
||||||
|
local bleepBloopFrames = 240
|
||||||
|
-- this is also bad, use "bleep_bloop_frames"
|
||||||
|
|
||||||
|
local bleep_bloop_bonus = self.lock_delay * 150
|
||||||
|
self.bleepBloopSubscore = self.bleepBloopSubscore + bleep_bloop_bonus
|
||||||
|
-- this should be self."bleep_bloop_subscore", member variables are also variables
|
||||||
|
end
|
||||||
|
```
|
||||||
|
|||||||
2
conf.lua
2
conf.lua
@@ -1,6 +1,8 @@
|
|||||||
function love.conf(t)
|
function love.conf(t)
|
||||||
t.identity = "cambridge"
|
t.identity = "cambridge"
|
||||||
|
|
||||||
|
t.console = true
|
||||||
|
|
||||||
t.window.title = "Cambridge"
|
t.window.title = "Cambridge"
|
||||||
t.window.width = 640
|
t.window.width = 640
|
||||||
t.window.height = 480
|
t.window.height = 480
|
||||||
|
|||||||
@@ -1,20 +1,40 @@
|
|||||||
Game modes
|
Game modes
|
||||||
==========
|
==========
|
||||||
|
|
||||||
There are several classes of game modes.
|
There are several classes of game modes. The modes that originate from other games are organized by suffix:
|
||||||
|
|
||||||
|
* The "C" series stand for "Classic" games, games that were produced before around 1992-1993 and generally have no wallkicks or lock delay.
|
||||||
|
* C84 - The original version from the Electronika 60.
|
||||||
|
* C88 - Sega Tetris.
|
||||||
|
* C89 - Nintendo / NES Tetris.
|
||||||
|
* The "A" series stand for "Arika" games, or games in the Tetris the Grand Master series.
|
||||||
|
* A1 - Tetris The Grand Master (the original from 1998).
|
||||||
|
* A2 - Tetris The Absolute The Grand Master 2 PLUS.
|
||||||
|
* A3 - Tetris The Grand Master 3 Terror-Instinct.
|
||||||
|
* AX - Tetris The Grand Master ACE (X for Xbox).
|
||||||
|
* The "G" series stand for "Guideline" games, or games that follow the Tetris Guideline.
|
||||||
|
* GF - Tetris Friends (2007-2019)
|
||||||
|
* GJ - Tetris Online Japan (2005-2011)
|
||||||
|
* The "N" series stands for Nullpomino, only used for Phantom Mania N.
|
||||||
|
* The "W" series stands for "Web" games, which are fanmade games released on the web.
|
||||||
|
* WCB - RainComplex.net's Cat Boi Quatro.
|
||||||
|
|
||||||
MARATHON
|
MARATHON
|
||||||
--------
|
--------
|
||||||
|
|
||||||
Modes in which the goal is to play as well as possible over a limited game interval, to ultimately achieve the title of Grand Master.
|
Modes in which the goal is to play as well as possible over a limited game interval.
|
||||||
|
|
||||||
* **MARATHON 2020**: 2020 levels of pure pain. Can you make it all the way?
|
* **MARATHON 2020**: 2020 levels of pure pain. Can you make it all the way?
|
||||||
|
* **MARATHON WCB**: CatBoiQuatro! Can you control the pieces?
|
||||||
|
|
||||||
From other games:
|
From other games:
|
||||||
* **MARATHON A1**: Tetris the Grand Master 1.
|
* **MARATHON A1**: Tetris the Grand Master 1.
|
||||||
* **MARATHON A2**: Tetris the Grand Master 2 (TAP Master).
|
* **MARATHON A2**: Tetris the Grand Master 2 (TAP Master).
|
||||||
* **MARATHON A3**: Tetris the Grand Master 3 (no exams).
|
* **MARATHON A3**: Tetris the Grand Master 3 (no exams).
|
||||||
|
* **MARATHON AX**: Normal mode from TGM Ace.
|
||||||
|
* **MARATHON AX2**: Hi-Speed1 mode from TGM Ace.
|
||||||
|
* **MARATHON AX3**: Hi-Speed2 mode from TGM Ace.
|
||||||
|
* **MARATHON C89**: Nintendo NES Tetris. Can you transition and make it to the killscreen?
|
||||||
|
|
||||||
|
|
||||||
SURVIVAL
|
SURVIVAL
|
||||||
@@ -28,6 +48,24 @@ From other games:
|
|||||||
* **SURVIVAL A1**: 20G mode from Tetris the Grand Master.
|
* **SURVIVAL A1**: 20G mode from Tetris the Grand Master.
|
||||||
* **SURVIVAL A2**: T.A. Death.
|
* **SURVIVAL A2**: T.A. Death.
|
||||||
* **SURVIVAL A3**: Ti Shirase.
|
* **SURVIVAL A3**: Ti Shirase.
|
||||||
|
* **SURVIVAL AX**: Another mode from TGM Ace.
|
||||||
|
* **SURVIVAL AX2**: Another2 mode from TGM Ace.
|
||||||
|
|
||||||
|
|
||||||
|
RACE
|
||||||
|
----
|
||||||
|
|
||||||
|
Modes with no levels, just a single timed goal.
|
||||||
|
|
||||||
|
* **Race 40**: How fast can you clear 40 lines? No limits, no holds barred.
|
||||||
|
|
||||||
|
|
||||||
|
CREDITS
|
||||||
|
-------
|
||||||
|
|
||||||
|
Modes that are just the credit rolls of specific games.
|
||||||
|
|
||||||
|
* **CREDITS A3**: Tetris the Grand Master 3's famous M-roll.
|
||||||
|
|
||||||
|
|
||||||
PHANTOM MANIA
|
PHANTOM MANIA
|
||||||
@@ -47,4 +85,6 @@ OTHER MODES
|
|||||||
|
|
||||||
* **TetrisGram™ Pacer Test**: is a multi-stage piece-placing ability test that progressively gets more difficult as it continues.
|
* **TetrisGram™ Pacer Test**: is a multi-stage piece-placing ability test that progressively gets more difficult as it continues.
|
||||||
|
|
||||||
* **Interval Training**: 30 seconds per section. 20G. 15 frames of lock delay. How long can you last?
|
* **Interval Training**: 30 seconds per section. 20G. 15 frames of lock delay. How long can you last?
|
||||||
|
|
||||||
|
* **Demon Mode**: An original mode from Oshisaure! Can you push through the ever faster levels and not get denied?
|
||||||
@@ -10,16 +10,13 @@ A ruleset consists of the following things:
|
|||||||
|
|
||||||
If you're used to Nullpomino, you may notice a few things missing from that definition. For example, piece previews, hold queues, and randomizers have been moved to being game-specific rules, rather than rules that are changeable with the ruleset you use. Soft and hard drop behaviour is also game-specific now, so that times can be more plausibly compared across rulesets.
|
If you're used to Nullpomino, you may notice a few things missing from that definition. For example, piece previews, hold queues, and randomizers have been moved to being game-specific rules, rather than rules that are changeable with the ruleset you use. Soft and hard drop behaviour is also game-specific now, so that times can be more plausibly compared across rulesets.
|
||||||
|
|
||||||
|
There are six rulesets currently supported:
|
||||||
|
|
||||||
Rotation system
|
* Cambridge - a ruleset original to Cambridge, used for all custom modes. Supports 180-degree rotations!
|
||||||
---------------
|
|
||||||
A rotation system defines the following things:
|
|
||||||
* The block offsets of each piece orientation.
|
|
||||||
* The wall or floor kicks that will be attempted for each type of rotation.
|
|
||||||
|
|
||||||
There are four rotation systems currently supported:
|
* SRS - the rotation system used in the Tetris Guideline games. Supports 180-degree rotations!
|
||||||
|
* Ti-SRS - SRS but with no 180-degree rotations.
|
||||||
|
|
||||||
* Cambridge
|
* ARS - the rotation system from the original Tetris the Grand Master.
|
||||||
* Classic ARS
|
* Ti-ARS - ARS with floorkicks! From TGM3: Terror Instinct.
|
||||||
* Ti-ARS
|
* Ace-ARS - ARS with floorkicks and move reset! From TGM ACE.
|
||||||
* SRS
|
|
||||||
@@ -49,6 +49,12 @@ blocks = {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
for name, blockset in pairs(blocks) do
|
||||||
|
for shape, image in pairs(blockset) do
|
||||||
|
image:setFilter("nearest")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
misc_graphics = {
|
misc_graphics = {
|
||||||
frame = love.graphics.newImage("res/img/frame.png"),
|
frame = love.graphics.newImage("res/img/frame.png"),
|
||||||
ready = love.graphics.newImage("res/img/ready.png"),
|
ready = love.graphics.newImage("res/img/ready.png"),
|
||||||
|
|||||||
1
main.lua
1
main.lua
@@ -11,6 +11,7 @@ function love.load()
|
|||||||
config["side_next"] = false
|
config["side_next"] = false
|
||||||
config["reverse_rotate"] = true
|
config["reverse_rotate"] = true
|
||||||
config["fullscreen"] = false
|
config["fullscreen"] = false
|
||||||
|
config["das_last_key"] = false
|
||||||
|
|
||||||
love.window.setMode(love.graphics.getWidth(), love.graphics.getHeight(), {resizable = true});
|
love.window.setMode(love.graphics.getWidth(), love.graphics.getHeight(), {resizable = true});
|
||||||
|
|
||||||
|
|||||||
Binary file not shown.
@@ -5,31 +5,42 @@ ModeSelectScene.title = "Game Start"
|
|||||||
current_mode = 1
|
current_mode = 1
|
||||||
current_ruleset = 1
|
current_ruleset = 1
|
||||||
|
|
||||||
|
MAX_MODES = 19
|
||||||
|
|
||||||
game_modes = {
|
game_modes = {
|
||||||
require 'tetris.modes.marathon_2020',
|
require 'tetris.modes.marathon_2020',
|
||||||
require 'tetris.modes.survival_2020',
|
require 'tetris.modes.survival_2020',
|
||||||
require 'tetris.modes.strategy',
|
require 'tetris.modes.strategy',
|
||||||
require 'tetris.modes.interval_training',
|
require 'tetris.modes.interval_training',
|
||||||
require 'tetris.modes.pacer_test',
|
require 'tetris.modes.pacer_test',
|
||||||
|
require 'tetris.modes.marathon_wcb',
|
||||||
require 'tetris.modes.demon_mode',
|
require 'tetris.modes.demon_mode',
|
||||||
require 'tetris.modes.phantom_mania',
|
require 'tetris.modes.phantom_mania',
|
||||||
require 'tetris.modes.phantom_mania2',
|
require 'tetris.modes.phantom_mania2',
|
||||||
require 'tetris.modes.phantom_mania_n',
|
require 'tetris.modes.phantom_mania_n',
|
||||||
require 'tetris.modes.ligne',
|
require 'tetris.modes.race_40',
|
||||||
require 'tetris.modes.marathon_a1',
|
require 'tetris.modes.marathon_a1',
|
||||||
require 'tetris.modes.marathon_a2',
|
require 'tetris.modes.marathon_a2',
|
||||||
require 'tetris.modes.marathon_a3',
|
require 'tetris.modes.marathon_a3',
|
||||||
|
require 'tetris.modes.marathon_ax',
|
||||||
|
require 'tetris.modes.marathon_ax2',
|
||||||
|
require 'tetris.modes.marathon_ax3',
|
||||||
|
require 'tetris.modes.marathon_c89',
|
||||||
require 'tetris.modes.survival_a1',
|
require 'tetris.modes.survival_a1',
|
||||||
require 'tetris.modes.survival_a2',
|
require 'tetris.modes.survival_a2',
|
||||||
require 'tetris.modes.survival_a3',
|
require 'tetris.modes.survival_a3',
|
||||||
require 'tetris.modes.marathon_l1',
|
require 'tetris.modes.survival_ax',
|
||||||
|
require 'tetris.modes.survival_ax2',
|
||||||
|
require 'tetris.modes.credits_a3',
|
||||||
}
|
}
|
||||||
|
|
||||||
rulesets = {
|
rulesets = {
|
||||||
require 'tetris.rulesets.cambridge',
|
require 'tetris.rulesets.cambridge',
|
||||||
|
require 'tetris.rulesets.standard',
|
||||||
|
require 'tetris.rulesets.standard_ti',
|
||||||
require 'tetris.rulesets.arika',
|
require 'tetris.rulesets.arika',
|
||||||
require 'tetris.rulesets.arika_ti',
|
require 'tetris.rulesets.arika_ti',
|
||||||
require 'tetris.rulesets.standard_exp',
|
require 'tetris.rulesets.arika_ace',
|
||||||
--require 'tetris.rulesets.bonkers',
|
--require 'tetris.rulesets.bonkers',
|
||||||
--require 'tetris.rulesets.shirase',
|
--require 'tetris.rulesets.shirase',
|
||||||
--require 'tetris.rulesets.super302',
|
--require 'tetris.rulesets.super302',
|
||||||
@@ -46,38 +57,58 @@ end
|
|||||||
function ModeSelectScene:update()
|
function ModeSelectScene:update()
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function getCursorHeight(x)
|
||||||
|
return 78 + 20 * x
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function ModeSelectScene:drawList(name, items, cursor, x)
|
||||||
|
local start, finish
|
||||||
|
if table.getn(items) < MAX_MODES then
|
||||||
|
start = 1
|
||||||
|
finish = table.getn(items)
|
||||||
|
else
|
||||||
|
if cursor < 10 then
|
||||||
|
start = 1
|
||||||
|
finish = 19
|
||||||
|
elseif cursor > table.getn(items) - 9 then
|
||||||
|
start = table.getn(items) - 18
|
||||||
|
finish = table.getn(items)
|
||||||
|
else
|
||||||
|
start = cursor - 9
|
||||||
|
finish = cursor + 9
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.menu_state.select == name then
|
||||||
|
love.graphics.setColor(1, 1, 1, 0.5)
|
||||||
|
else
|
||||||
|
love.graphics.setColor(1, 1, 1, 0.25)
|
||||||
|
end
|
||||||
|
love.graphics.rectangle("fill", x, getCursorHeight(cursor - start), 240, 22)
|
||||||
|
|
||||||
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
|
|
||||||
|
for idx = start, finish do
|
||||||
|
local item = items[idx]
|
||||||
|
love.graphics.printf(item.name, x + 20, 80 + 20 * (idx - start), 200, "left")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
function ModeSelectScene:render()
|
function ModeSelectScene:render()
|
||||||
|
love.graphics.setFont(font_3x5_2)
|
||||||
|
|
||||||
love.graphics.draw(
|
love.graphics.draw(
|
||||||
backgrounds[0],
|
backgrounds[0],
|
||||||
0, 0, 0,
|
0, 0, 0,
|
||||||
0.5, 0.5
|
0.5, 0.5
|
||||||
)
|
)
|
||||||
|
|
||||||
if self.menu_state.select == "mode" then
|
|
||||||
love.graphics.setColor(1, 1, 1, 0.5)
|
|
||||||
elseif self.menu_state.select == "ruleset" then
|
|
||||||
love.graphics.setColor(1, 1, 1, 0.25)
|
|
||||||
end
|
|
||||||
love.graphics.rectangle("fill", 20, 78 + 20 * self.menu_state.mode, 240, 22)
|
|
||||||
|
|
||||||
if self.menu_state.select == "mode" then
|
love.graphics.draw(misc_graphics["select_mode"], 20, 30)
|
||||||
love.graphics.setColor(1, 1, 1, 0.25)
|
|
||||||
elseif self.menu_state.select == "ruleset" then
|
|
||||||
love.graphics.setColor(1, 1, 1, 0.5)
|
|
||||||
end
|
|
||||||
love.graphics.rectangle("fill", 340, 78 + 20 * self.menu_state.ruleset, 200, 22)
|
|
||||||
|
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
|
||||||
|
|
||||||
love.graphics.draw(misc_graphics["select_mode"], 20, 40)
|
self:drawList("mode", game_modes, self.menu_state.mode, 20)
|
||||||
|
self:drawList("ruleset", rulesets, self.menu_state.ruleset, 320)
|
||||||
love.graphics.setFont(font_3x5_2)
|
|
||||||
for idx, mode in pairs(game_modes) do
|
|
||||||
love.graphics.printf(mode.name, 40, 80 + 20 * idx, 200, "left")
|
|
||||||
end
|
|
||||||
for idx, ruleset in pairs(rulesets) do
|
|
||||||
love.graphics.printf(ruleset.name, 360, 80 + 20 * idx, 160, "left")
|
|
||||||
end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function ModeSelectScene:onKeyPress(e)
|
function ModeSelectScene:onKeyPress(e)
|
||||||
|
|||||||
@@ -38,6 +38,10 @@ function Grid:isRowFull(row)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Grid:canPlacePiece(piece)
|
function Grid:canPlacePiece(piece)
|
||||||
|
if piece.big then
|
||||||
|
return self:canPlaceBigPiece(piece)
|
||||||
|
end
|
||||||
|
|
||||||
local offsets = piece:getBlockOffsets()
|
local offsets = piece:getBlockOffsets()
|
||||||
for index, offset in pairs(offsets) do
|
for index, offset in pairs(offsets) do
|
||||||
local x = piece.position.x + offset.x
|
local x = piece.position.x + offset.x
|
||||||
@@ -49,7 +53,29 @@ function Grid:canPlacePiece(piece)
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Grid:canPlaceBigPiece(piece)
|
||||||
|
local offsets = piece:getBlockOffsets()
|
||||||
|
for index, offset in pairs(offsets) do
|
||||||
|
local x = piece.position.x + offset.x
|
||||||
|
local y = piece.position.y + offset.y
|
||||||
|
if x >= 5 or x < 0 or y >= 12 or y < 0 or
|
||||||
|
self.grid[y * 2 + 1][x * 2 + 1] ~= empty or
|
||||||
|
self.grid[y * 2 + 1][x * 2 + 2] ~= empty or
|
||||||
|
self.grid[y * 2 + 2][x * 2 + 1] ~= empty or
|
||||||
|
self.grid[y * 2 + 2][x * 2 + 2] ~= empty
|
||||||
|
then
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
function Grid:canPlacePieceInVisibleGrid(piece)
|
function Grid:canPlacePieceInVisibleGrid(piece)
|
||||||
|
if piece.big then
|
||||||
|
return self:canPlaceBigPiece(piece)
|
||||||
|
-- forget canPlaceBigPieceInVisibleGrid for now
|
||||||
|
end
|
||||||
|
|
||||||
local offsets = piece:getBlockOffsets()
|
local offsets = piece:getBlockOffsets()
|
||||||
for index, offset in pairs(offsets) do
|
for index, offset in pairs(offsets) do
|
||||||
local x = piece.position.x + offset.x
|
local x = piece.position.x + offset.x
|
||||||
@@ -116,6 +142,10 @@ function Grid:copyBottomRow()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Grid:applyPiece(piece)
|
function Grid:applyPiece(piece)
|
||||||
|
if piece.big then
|
||||||
|
self:applyBigPiece(piece)
|
||||||
|
return
|
||||||
|
end
|
||||||
offsets = piece:getBlockOffsets()
|
offsets = piece:getBlockOffsets()
|
||||||
for index, offset in pairs(offsets) do
|
for index, offset in pairs(offsets) do
|
||||||
x = piece.position.x + offset.x
|
x = piece.position.x + offset.x
|
||||||
@@ -127,6 +157,22 @@ function Grid:applyPiece(piece)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
function Grid:applyBigPiece(piece)
|
||||||
|
offsets = piece:getBlockOffsets()
|
||||||
|
for index, offset in pairs(offsets) do
|
||||||
|
x = piece.position.x + offset.x
|
||||||
|
y = piece.position.y + offset.y
|
||||||
|
for a = 1, 2 do
|
||||||
|
for b = 1, 2 do
|
||||||
|
self.grid[y*2+a][x*2+b] = {
|
||||||
|
skin = piece.skin,
|
||||||
|
colour = piece.shape
|
||||||
|
}
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
function Grid:update()
|
function Grid:update()
|
||||||
for y = 1, 24 do
|
for y = 1, 24 do
|
||||||
for x = 1, 10 do
|
for x = 1, 10 do
|
||||||
@@ -148,19 +194,21 @@ function Grid:draw()
|
|||||||
love.graphics.setColor(0.5, 0.5, 0.5, 1)
|
love.graphics.setColor(0.5, 0.5, 0.5, 1)
|
||||||
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
|
||||||
love.graphics.setColor(0.8, 0.8, 0.8, 1)
|
if self.grid[y][x].skin ~= "bone" then
|
||||||
love.graphics.setLineWidth(1)
|
love.graphics.setColor(0.8, 0.8, 0.8, 1)
|
||||||
if y > 1 and self.grid[y-1][x] == empty then
|
love.graphics.setLineWidth(1)
|
||||||
love.graphics.line(48.0+x*16, -0.5+y*16, 64.0+x*16, -0.5+y*16)
|
if y > 1 and self.grid[y-1][x] == empty then
|
||||||
end
|
love.graphics.line(48.0+x*16, -0.5+y*16, 64.0+x*16, -0.5+y*16)
|
||||||
if y < 24 and self.grid[y+1][x] == empty then
|
end
|
||||||
love.graphics.line(48.0+x*16, 16.5+y*16, 64.0+x*16, 16.5+y*16)
|
if y < 24 and self.grid[y+1][x] == empty then
|
||||||
end
|
love.graphics.line(48.0+x*16, 16.5+y*16, 64.0+x*16, 16.5+y*16)
|
||||||
if x > 1 and self.grid[y][x-1] == empty then
|
end
|
||||||
love.graphics.line(47.5+x*16, -0.0+y*16, 47.5+x*16, 16.0+y*16)
|
if x > 1 and self.grid[y][x-1] == empty then
|
||||||
end
|
love.graphics.line(47.5+x*16, -0.0+y*16, 47.5+x*16, 16.0+y*16)
|
||||||
if x < 10 and self.grid[y][x+1] == empty then
|
end
|
||||||
love.graphics.line(64.5+x*16, -0.0+y*16, 64.5+x*16, 16.0+y*16)
|
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
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -2,7 +2,7 @@ local Object = require 'libs.classic'
|
|||||||
|
|
||||||
local Piece = Object:extend()
|
local Piece = Object:extend()
|
||||||
|
|
||||||
function Piece:new(shape, rotation, position, block_offsets, gravity, lock_delay, skin)
|
function Piece:new(shape, rotation, position, block_offsets, gravity, lock_delay, skin, big)
|
||||||
self.shape = shape
|
self.shape = shape
|
||||||
self.rotation = rotation
|
self.rotation = rotation
|
||||||
self.position = position
|
self.position = position
|
||||||
@@ -12,6 +12,7 @@ function Piece:new(shape, rotation, position, block_offsets, gravity, lock_delay
|
|||||||
self.skin = skin
|
self.skin = skin
|
||||||
self.ghost = false
|
self.ghost = false
|
||||||
self.locked = false
|
self.locked = false
|
||||||
|
self.big = big
|
||||||
end
|
end
|
||||||
|
|
||||||
-- Functions that return a new piece to test in rotation systems.
|
-- Functions that return a new piece to test in rotation systems.
|
||||||
@@ -20,7 +21,7 @@ function Piece:withOffset(offset)
|
|||||||
return Piece(
|
return Piece(
|
||||||
self.shape, self.rotation,
|
self.shape, self.rotation,
|
||||||
{x = self.position.x + offset.x, y = self.position.y + offset.y},
|
{x = self.position.x + offset.x, y = self.position.y + offset.y},
|
||||||
self.block_offsets, self.gravity, self.lock_delay, self.skin
|
self.block_offsets, self.gravity, self.lock_delay, self.skin, self.big
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -30,7 +31,7 @@ function Piece:withRelativeRotation(rot)
|
|||||||
while new_rot >= 4 do new_rot = new_rot - 4 end
|
while new_rot >= 4 do new_rot = new_rot - 4 end
|
||||||
return Piece(
|
return Piece(
|
||||||
self.shape, new_rot, self.position,
|
self.shape, new_rot, self.position,
|
||||||
self.block_offsets, self.gravity, self.lock_delay, self.skin
|
self.block_offsets, self.gravity, self.lock_delay, self.skin, self.big
|
||||||
)
|
)
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -76,12 +77,15 @@ function Piece:setRelativeRotation(rot)
|
|||||||
return self
|
return self
|
||||||
end
|
end
|
||||||
|
|
||||||
function Piece:moveInGrid(step, squares, grid)
|
function Piece:moveInGrid(step, squares, grid, instant)
|
||||||
local moved = false
|
local moved = false
|
||||||
for x = 1, squares do
|
for x = 1, squares do
|
||||||
if grid:canPlacePiece(self:withOffset(step)) then
|
if grid:canPlacePiece(self:withOffset(step)) then
|
||||||
moved = true
|
moved = true
|
||||||
self:setOffset(step)
|
self:setOffset(step)
|
||||||
|
if instant then
|
||||||
|
self:dropToBottom(grid)
|
||||||
|
end
|
||||||
else
|
else
|
||||||
break
|
break
|
||||||
end
|
end
|
||||||
@@ -138,14 +142,25 @@ function Piece:draw(opacity, brightness, grid, partial_das)
|
|||||||
love.graphics.setColor(brightness, brightness, brightness, opacity)
|
love.graphics.setColor(brightness, brightness, brightness, opacity)
|
||||||
local offsets = self:getBlockOffsets()
|
local offsets = self:getBlockOffsets()
|
||||||
local gravity_offset = 0
|
local gravity_offset = 0
|
||||||
if grid ~= nil and not self:isDropBlocked(grid) then
|
--if grid ~= nil and not self:isDropBlocked(grid) then
|
||||||
gravity_offset = self.gravity * 16
|
-- gravity_offset = self.gravity * 16
|
||||||
end
|
--end
|
||||||
if partial_das == nil then partial_das = 0 end
|
if partial_das == nil then partial_das = 0 end
|
||||||
for index, offset in pairs(offsets) do
|
for index, offset in pairs(offsets) do
|
||||||
local x = self.position.x + offset.x
|
local x = self.position.x + offset.x
|
||||||
local y = self.position.y + offset.y
|
local y = self.position.y + offset.y
|
||||||
love.graphics.draw(blocks[self.skin][self.shape], 64+x*16+partial_das, 16+y*16+gravity_offset)
|
if self.big then
|
||||||
|
love.graphics.draw(
|
||||||
|
blocks[self.skin][self.shape],
|
||||||
|
64+x*32+partial_das*2, 16+y*32+gravity_offset*2,
|
||||||
|
0, 2, 2
|
||||||
|
)
|
||||||
|
else
|
||||||
|
love.graphics.draw(
|
||||||
|
blocks[self.skin][self.shape],
|
||||||
|
64+x*16+partial_das, 16+y*16+gravity_offset
|
||||||
|
)
|
||||||
|
end
|
||||||
end
|
end
|
||||||
return false
|
return false
|
||||||
end
|
end
|
||||||
|
|||||||
119
tetris/modes/credits_a3.lua
Normal file
119
tetris/modes/credits_a3.lua
Normal file
@@ -0,0 +1,119 @@
|
|||||||
|
require 'funcs'
|
||||||
|
|
||||||
|
local IntervalTrainingMode = require 'tetris.modes.interval_training'
|
||||||
|
local Piece = require 'tetris.components.piece'
|
||||||
|
|
||||||
|
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
||||||
|
|
||||||
|
local CreditsA3Game = IntervalTrainingMode:extend()
|
||||||
|
|
||||||
|
CreditsA3Game.name = "Credits A3"
|
||||||
|
CreditsA3Game.hash = "CreditsA3"
|
||||||
|
CreditsA3Game.tagline = "How consistently can you clear the Ti M-roll?"
|
||||||
|
|
||||||
|
function CreditsA3Game:new()
|
||||||
|
CreditsA3Game.super:new()
|
||||||
|
self.section_time_limit = 3238
|
||||||
|
self.norm = 0
|
||||||
|
self.section = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function CreditsA3Game:advanceOneFrame(inputs, ruleset)
|
||||||
|
if self.frames == 0 then
|
||||||
|
switchBGM("credit_roll", "gm3")
|
||||||
|
end
|
||||||
|
if self.roll_frames > 0 then
|
||||||
|
self.roll_frames = self.roll_frames - 1
|
||||||
|
if self.roll_frames == 0 then
|
||||||
|
-- reset
|
||||||
|
self.norm = 0
|
||||||
|
self.frames = 0
|
||||||
|
self.grid:clear()
|
||||||
|
switchBGM("credit_roll", "gm3")
|
||||||
|
self:initializeOrHold(inputs, ruleset)
|
||||||
|
else
|
||||||
|
return false
|
||||||
|
end
|
||||||
|
elseif self.ready_frames == 0 then
|
||||||
|
self.frames = self.frames + 1
|
||||||
|
if self:getSectionTime() >= self.section_time_limit then
|
||||||
|
self.norm = self.norm + 16
|
||||||
|
self.piece = nil
|
||||||
|
if self.norm >= 60 then
|
||||||
|
self.section = self.section + 1
|
||||||
|
self.roll_frames = 150
|
||||||
|
else
|
||||||
|
self.game_over = true
|
||||||
|
switchBGM(nil)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function CreditsA3Game:onPieceEnter()
|
||||||
|
-- do nothing
|
||||||
|
end
|
||||||
|
|
||||||
|
function CreditsA3Game:onLineClear(cleared_row_count)
|
||||||
|
if not self.clear then
|
||||||
|
self.norm = self.norm + (cleared_row_count == 4 and 10 or cleared_row_count)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
CreditsA3Game.rollOpacityFunction = function(age)
|
||||||
|
if age > 4 then return 0
|
||||||
|
else return 1 - age / 4 end
|
||||||
|
end
|
||||||
|
|
||||||
|
function CreditsA3Game:drawGrid(ruleset)
|
||||||
|
if not self.game_over and self.roll_frames < 30 then
|
||||||
|
self.grid:drawInvisible(self.rollOpacityFunction)
|
||||||
|
else
|
||||||
|
self.grid:draw()
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function CreditsA3Game:drawScoringInfo()
|
||||||
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
|
|
||||||
|
love.graphics.setFont(font_3x5_2)
|
||||||
|
love.graphics.print(
|
||||||
|
self.das.direction .. " " ..
|
||||||
|
self.das.frames .. " " ..
|
||||||
|
st(self.prev_inputs)
|
||||||
|
)
|
||||||
|
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
||||||
|
love.graphics.printf("TIME LEFT", 240, 250, 80, "left")
|
||||||
|
love.graphics.printf("NORM", 240, 320, 40, "left")
|
||||||
|
|
||||||
|
self:drawSectionTimesWithSplits(self.section)
|
||||||
|
|
||||||
|
love.graphics.setFont(font_3x5_3)
|
||||||
|
-- draw time left, flash red if necessary
|
||||||
|
local time_left = self.section_time_limit - math.max(self:getSectionTime(), 0)
|
||||||
|
|
||||||
|
if not self.game_over and not self.clear and time_left < sp(0,10) and time_left % 4 < 2 then
|
||||||
|
if self.norm >= 44 then
|
||||||
|
love.graphics.setColor(0.3, 1, 0.3, 1) -- flash green if goal has been cleared
|
||||||
|
else
|
||||||
|
love.graphics.setColor(1, 0.3, 0.3, 1) -- otherwise flash red
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
love.graphics.printf(formatTime(time_left), 240, 270, 160, "left")
|
||||||
|
|
||||||
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
|
love.graphics.printf(self.norm, 240, 340, 40, "right")
|
||||||
|
if self.game_over or self.roll_frames > 0 then
|
||||||
|
love.graphics.printf("60", 240, 370, 40, "right")
|
||||||
|
else
|
||||||
|
love.graphics.printf("44", 240, 370, 40, "right")
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function CreditsA3Game:getBackground()
|
||||||
|
return self.section
|
||||||
|
end
|
||||||
|
|
||||||
|
return CreditsA3Game
|
||||||
@@ -104,7 +104,7 @@ function DemonModeGame:advanceOneFrame()
|
|||||||
if self.clear then
|
if self.clear then
|
||||||
self.roll_frames = self.roll_frames + 1
|
self.roll_frames = self.roll_frames + 1
|
||||||
if self.roll_frames < 0 then
|
if self.roll_frames < 0 then
|
||||||
return
|
return false
|
||||||
elseif self.roll_frames >= 1337 then
|
elseif self.roll_frames >= 1337 then
|
||||||
self.completed = true
|
self.completed = true
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -36,8 +36,10 @@ function GameMode:new()
|
|||||||
self.enable_hold = false
|
self.enable_hold = false
|
||||||
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.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
|
||||||
-- variables related to configurable parameters
|
-- variables related to configurable parameters
|
||||||
self.drop_locked = false
|
self.drop_locked = false
|
||||||
self.hard_drop_locked = false
|
self.hard_drop_locked = false
|
||||||
@@ -89,10 +91,20 @@ function GameMode:update(inputs, ruleset)
|
|||||||
if self.completed then return end
|
if self.completed then return end
|
||||||
|
|
||||||
-- advance one frame
|
-- 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())
|
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
|
if self.piece == nil then
|
||||||
self:processDelays(inputs, ruleset)
|
self:processDelays(inputs, ruleset)
|
||||||
else
|
else
|
||||||
@@ -119,7 +131,8 @@ function GameMode:update(inputs, ruleset)
|
|||||||
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.enable_hard_drop
|
self.drop_locked, self.hard_drop_locked,
|
||||||
|
self.enable_hard_drop, self.additive_gravity
|
||||||
)
|
)
|
||||||
|
|
||||||
local piece_dy = self.piece.position.y - piece_y
|
local piece_dy = self.piece.position.y - piece_y
|
||||||
@@ -149,6 +162,10 @@ function GameMode:update(inputs, ruleset)
|
|||||||
|
|
||||||
local cleared_row_count = self.grid:getClearedRowCount()
|
local cleared_row_count = self.grid:getClearedRowCount()
|
||||||
|
|
||||||
|
if self.big_mode then
|
||||||
|
cleared_row_count = cleared_row_count / 2
|
||||||
|
end
|
||||||
|
|
||||||
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)
|
||||||
|
|
||||||
@@ -191,6 +208,8 @@ end
|
|||||||
|
|
||||||
-- event functions
|
-- event functions
|
||||||
function GameMode:whilePieceActive() end
|
function GameMode:whilePieceActive() end
|
||||||
|
function GameMode:onAttemptPieceMove(piece) end
|
||||||
|
function GameMode:onAttemptPieceRotate(piece) end
|
||||||
function GameMode:onPieceLock(piece, cleared_row_count) end
|
function GameMode:onPieceLock(piece, cleared_row_count) end
|
||||||
function GameMode:onLineClear(cleared_row_count) end
|
function GameMode:onLineClear(cleared_row_count) end
|
||||||
function GameMode:onPieceEnter() end
|
function GameMode:onPieceEnter() end
|
||||||
@@ -208,30 +227,66 @@ function GameMode:onGameOver()
|
|||||||
switchBGM(nil)
|
switchBGM(nil)
|
||||||
end
|
end
|
||||||
|
|
||||||
function GameMode:chargeDAS(inputs)
|
-- DAS functions
|
||||||
if inputs[self.das.direction] == true then
|
|
||||||
local das_frames = self.das.frames + 1
|
function GameMode:startRightDAS()
|
||||||
if das_frames >= self:getDasLimit() then
|
self.move = "right"
|
||||||
if self.das.direction == "left" then
|
self.das = { direction = "right", frames = 0 }
|
||||||
self.move = (self:getARR() == 0 and "speed" or "") .. "left"
|
if self:getDasLimit() == 0 then
|
||||||
self.das.frames = self:getDasLimit() - self:getARR()
|
self:continueDAS()
|
||||||
elseif self.das.direction == "right" then
|
end
|
||||||
self.move = (self:getARR() == 0 and "speed" or "") .. "right"
|
end
|
||||||
self.das.frames = self:getDasLimit() - self:getARR()
|
|
||||||
end
|
function GameMode:startLeftDAS()
|
||||||
else
|
self.move = "left"
|
||||||
self.move = "none"
|
self.das = { direction = "left", frames = 0 }
|
||||||
self.das.frames = das_frames
|
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
|
||||||
|
self.move = (self:getARR() == 0 and "speed" or "") .. "left"
|
||||||
|
self.das.frames = self:getDasLimit() - self:getARR()
|
||||||
|
elseif self.das.direction == "right" then
|
||||||
|
self.move = (self:getARR() == 0 and "speed" or "") .. "right"
|
||||||
|
self.das.frames = self:getDasLimit() - self:getARR()
|
||||||
end
|
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
|
else
|
||||||
self.move = "none"
|
self.move = "none"
|
||||||
self.das = { direction = "none", frames = -1 }
|
self.das.frames = das_frames
|
||||||
|
end
|
||||||
|
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
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -298,7 +353,7 @@ function GameMode:initializeNextPiece(inputs, ruleset, piece_data, generate_next
|
|||||||
inputs, piece_data, self.grid, gravity,
|
inputs, piece_data, self.grid, gravity,
|
||||||
self.prev_inputs, self.move,
|
self.prev_inputs, self.move,
|
||||||
self:getLockDelay(), self:getDropSpeed(),
|
self:getLockDelay(), self:getDropSpeed(),
|
||||||
self.lock_drop, self.lock_hard_drop
|
self.lock_drop, self.lock_hard_drop, self.big_mode
|
||||||
)
|
)
|
||||||
if self.lock_drop then
|
if self.lock_drop then
|
||||||
self.drop_locked = true
|
self.drop_locked = true
|
||||||
@@ -389,8 +444,7 @@ function GameMode:drawScoringInfo()
|
|||||||
love.graphics.print(
|
love.graphics.print(
|
||||||
self.das.direction .. " " ..
|
self.das.direction .. " " ..
|
||||||
self.das.frames .. " " ..
|
self.das.frames .. " " ..
|
||||||
st(self.prev_inputs) ..
|
st(self.prev_inputs)
|
||||||
self.drop_bonus
|
|
||||||
)
|
)
|
||||||
|
|
||||||
love.graphics.setFont(font_8x11)
|
love.graphics.setFont(font_8x11)
|
||||||
@@ -400,7 +454,7 @@ end
|
|||||||
function GameMode:drawSectionTimes(current_section)
|
function GameMode:drawSectionTimes(current_section)
|
||||||
local section_x = 530
|
local section_x = 530
|
||||||
|
|
||||||
for section, time in pairs(self.section_times) do
|
for section, time in ipairs(self.section_times) do
|
||||||
if section > 0 then
|
if section > 0 then
|
||||||
love.graphics.printf(formatTime(time), section_x, 40 + 20 * section, 90, "left")
|
love.graphics.printf(formatTime(time), section_x, 40 + 20 * section, 90, "left")
|
||||||
end
|
end
|
||||||
@@ -409,7 +463,7 @@ function GameMode:drawSectionTimes(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")
|
||||||
end
|
end
|
||||||
|
|
||||||
function GameMode:drawSectionTimesWithSecondary(current_section)
|
function GameMode:drawSectionTimesWithSecondary(current_section, section_colour_function)
|
||||||
local section_x = 530
|
local section_x = 530
|
||||||
local section_secondary_x = 440
|
local section_secondary_x = 440
|
||||||
|
|
||||||
@@ -420,6 +474,9 @@ function GameMode:drawSectionTimesWithSecondary(current_section)
|
|||||||
end
|
end
|
||||||
|
|
||||||
for section, time in pairs(self.secondary_section_times) do
|
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
|
if section > 0 then
|
||||||
love.graphics.printf(formatTime(time), section_secondary_x, 40 + 20 * section, 90, "left")
|
love.graphics.printf(formatTime(time), section_secondary_x, 40 + 20 * section, 90, "left")
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -28,19 +28,19 @@ function IntervalTrainingGame:new()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function IntervalTrainingGame:getARE()
|
function IntervalTrainingGame:getARE()
|
||||||
return 4
|
return 6
|
||||||
end
|
end
|
||||||
|
|
||||||
function IntervalTrainingGame:getLineARE()
|
function IntervalTrainingGame:getLineARE()
|
||||||
return 4
|
return 6
|
||||||
end
|
end
|
||||||
|
|
||||||
function IntervalTrainingGame:getDasLimit()
|
function IntervalTrainingGame:getDasLimit()
|
||||||
return 6
|
return 7
|
||||||
end
|
end
|
||||||
|
|
||||||
function IntervalTrainingGame:getLineClearDelay()
|
function IntervalTrainingGame:getLineClearDelay()
|
||||||
return 6
|
return 4
|
||||||
end
|
end
|
||||||
|
|
||||||
function IntervalTrainingGame:getLockDelay()
|
function IntervalTrainingGame:getLockDelay()
|
||||||
@@ -130,8 +130,6 @@ function IntervalTrainingGame:drawScoringInfo()
|
|||||||
self:drawSectionTimesWithSplits(current_section)
|
self:drawSectionTimesWithSplits(current_section)
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
love.graphics.setFont(font_3x5_3)
|
||||||
love.graphics.printf(self.level, 240, 340, 40, "right")
|
|
||||||
|
|
||||||
-- draw time left, flash red if necessary
|
-- draw time left, flash red if necessary
|
||||||
local time_left = self.section_time_limit - math.max(self:getSectionTime(), 0)
|
local time_left = self.section_time_limit - math.max(self:getSectionTime(), 0)
|
||||||
if not self.game_over and not self.clear and time_left < sp(0,10) and time_left % 4 < 2 then
|
if not self.game_over and not self.clear and time_left < sp(0,10) and time_left % 4 < 2 then
|
||||||
@@ -140,6 +138,7 @@ function IntervalTrainingGame:drawScoringInfo()
|
|||||||
love.graphics.printf(formatTime(time_left), 240, 270, 160, "left")
|
love.graphics.printf(formatTime(time_left), 240, 270, 160, "left")
|
||||||
|
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
|
love.graphics.printf(self.level, 240, 340, 40, "right")
|
||||||
love.graphics.printf(self:getSectionEndLevel(), 240, 370, 40, "right")
|
love.graphics.printf(self:getSectionEndLevel(), 240, 370, 40, "right")
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -323,9 +323,9 @@ function Marathon2020Game:checkClear(level)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function Marathon2020Game:updateSectionTimes(old_level, new_level)
|
function Marathon2020Game:updateSectionTimes(old_level, new_level)
|
||||||
function sectionCool()
|
function sectionCool(section)
|
||||||
self.section_cool_count = self.section_cool_count + 1
|
self.section_cool_count = self.section_cool_count + 1
|
||||||
self.delay_level = math.min(20, self.delay_level + 1)
|
if section < 10 then self.delay_level = math.min(20, self.delay_level + 1) end
|
||||||
table.insert(self.section_status, "cool")
|
table.insert(self.section_status, "cool")
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -343,7 +343,7 @@ function Marathon2020Game:updateSectionTimes(old_level, new_level)
|
|||||||
table.insert(self.section_times, section_time)
|
table.insert(self.section_times, section_time)
|
||||||
self.section_start_time = self.frames
|
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:checkTorikan(section)
|
||||||
self:checkClear(new_level)
|
self:checkClear(new_level)
|
||||||
|
|
||||||
@@ -352,11 +352,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] < self.secondary_section_times[section - 1] + 120 and
|
||||||
self.secondary_section_times[section] < cool_cutoffs[section]
|
self.secondary_section_times[section] < cool_cutoffs[section]
|
||||||
) then
|
) then
|
||||||
sectionCool()
|
sectionCool(section)
|
||||||
elseif self.section_status[section - 1] == "cool" then
|
elseif self.section_status[section - 1] == "cool" then
|
||||||
table.insert(self.section_status, "none")
|
table.insert(self.section_status, "none")
|
||||||
elseif section <= 19 and self.secondary_section_times[section] < cool_cutoffs[section] then
|
elseif section <= 19 and self.secondary_section_times[section] < cool_cutoffs[section] then
|
||||||
sectionCool()
|
sectionCool(section)
|
||||||
else
|
else
|
||||||
table.insert(self.section_status, "none")
|
table.insert(self.section_status, "none")
|
||||||
end
|
end
|
||||||
@@ -417,6 +417,14 @@ function Marathon2020Game:drawGrid()
|
|||||||
end
|
end
|
||||||
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()
|
function Marathon2020Game:drawScoringInfo()
|
||||||
Marathon2020Game.super.drawScoringInfo(self)
|
Marathon2020Game.super.drawScoringInfo(self)
|
||||||
|
|
||||||
@@ -428,7 +436,7 @@ function Marathon2020Game:drawScoringInfo()
|
|||||||
love.graphics.printf("GRADE PTS.", text_x, 200, 90, "left")
|
love.graphics.printf("GRADE PTS.", text_x, 200, 90, "left")
|
||||||
love.graphics.printf("LEVEL", text_x, 320, 40, "left")
|
love.graphics.printf("LEVEL", text_x, 320, 40, "left")
|
||||||
|
|
||||||
self:drawSectionTimesWithSecondary(current_section)
|
self:drawSectionTimesWithSecondary(current_section, self.sectionColourFunction)
|
||||||
|
|
||||||
love.graphics.setFont(font_3x5_3)
|
love.graphics.setFont(font_3x5_3)
|
||||||
love.graphics.printf(self:getTotalGrade(), text_x, 120, 90, "left")
|
love.graphics.printf(self:getTotalGrade(), text_x, 120, 90, "left")
|
||||||
|
|||||||
@@ -12,7 +12,6 @@ MarathonA1Game.hash = "MarathonA1"
|
|||||||
MarathonA1Game.tagline = "Can you score enough points to reach the title of Grand Master?"
|
MarathonA1Game.tagline = "Can you score enough points to reach the title of Grand Master?"
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
function MarathonA1Game:new()
|
function MarathonA1Game:new()
|
||||||
MarathonA1Game.super:new()
|
MarathonA1Game.super:new()
|
||||||
|
|
||||||
@@ -131,7 +130,8 @@ function MarathonA1Game:onLineClear(cleared_row_count)
|
|||||||
self:checkGMRequirements(self.level, self.level + cleared_row_count)
|
self:checkGMRequirements(self.level, self.level + cleared_row_count)
|
||||||
if not self.clear then
|
if not self.clear then
|
||||||
local new_level = math.min(self.level + cleared_row_count, 999)
|
local new_level = math.min(self.level + cleared_row_count, 999)
|
||||||
if self.level == 999 then
|
if new_level == 999 then
|
||||||
|
self.level = 999
|
||||||
self.clear = true
|
self.clear = true
|
||||||
else
|
else
|
||||||
self.level = new_level
|
self.level = new_level
|
||||||
@@ -140,6 +140,7 @@ function MarathonA1Game:onLineClear(cleared_row_count)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA1Game:updateScore(level, drop_bonus, cleared_lines)
|
function MarathonA1Game:updateScore(level, drop_bonus, cleared_lines)
|
||||||
|
if self.clear then return end
|
||||||
if cleared_lines > 0 then
|
if cleared_lines > 0 then
|
||||||
self.combo = self.combo + (cleared_lines - 1) * 2
|
self.combo = self.combo + (cleared_lines - 1) * 2
|
||||||
self.score = self.score + (
|
self.score = self.score + (
|
||||||
|
|||||||
@@ -67,7 +67,9 @@ function MarathonA3Game:getLineClearDelay()
|
|||||||
elseif self.speed_level < 600 then return 25
|
elseif self.speed_level < 600 then return 25
|
||||||
elseif self.speed_level < 700 then return 16
|
elseif self.speed_level < 700 then return 16
|
||||||
elseif self.speed_level < 800 then return 12
|
elseif self.speed_level < 800 then return 12
|
||||||
else return 6 end
|
elseif self.speed_level < 1100 then return 6
|
||||||
|
elseif self.speed_level < 1200 then return 5
|
||||||
|
else return 4 end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonA3Game:getLockDelay()
|
function MarathonA3Game:getLockDelay()
|
||||||
@@ -117,7 +119,7 @@ function MarathonA3Game:advanceOneFrame()
|
|||||||
if self.roll_frames + 1 == 0 then
|
if self.roll_frames + 1 == 0 then
|
||||||
switchBGM("credit_roll", "gm3")
|
switchBGM("credit_roll", "gm3")
|
||||||
end
|
end
|
||||||
return
|
return false
|
||||||
elseif self.roll_frames > 3238 then
|
elseif self.roll_frames > 3238 then
|
||||||
if self:qualifiesForMRoll() then
|
if self:qualifiesForMRoll() then
|
||||||
self.roll_points = self.roll_points + 160
|
self.roll_points = self.roll_points + 160
|
||||||
@@ -181,7 +183,7 @@ function MarathonA3Game:updateSectionTimes(old_level, new_level)
|
|||||||
self.section_cool_grade = self.section_cool_grade - 1
|
self.section_cool_grade = self.section_cool_grade - 1
|
||||||
table.insert(self.section_status, "regret")
|
table.insert(self.section_status, "regret")
|
||||||
elseif section <= 9 and self.section_status[section - 1] == "cool" and
|
elseif section <= 9 and self.section_status[section - 1] == "cool" and
|
||||||
self.section_70_times[section] < self.section_70_times[section - 1] + 1000 then
|
self.section_70_times[section] < self.section_70_times[section - 1] + 120 then
|
||||||
self.section_cool_grade = self.section_cool_grade + 1
|
self.section_cool_grade = self.section_cool_grade + 1
|
||||||
self.speed_level = self.speed_level + 100
|
self.speed_level = self.speed_level + 100
|
||||||
table.insert(self.section_status, "cool")
|
table.insert(self.section_status, "cool")
|
||||||
|
|||||||
@@ -5,22 +5,19 @@ local Piece = require 'tetris.components.piece'
|
|||||||
|
|
||||||
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
||||||
|
|
||||||
local MarathonL1Game = GameMode:extend()
|
local MarathonAXGame = GameMode:extend()
|
||||||
|
|
||||||
MarathonL1Game.name = "Line Attack"
|
MarathonAXGame.name = "Marathon AX"
|
||||||
MarathonL1Game.hash = "MarathonL1"
|
MarathonAXGame.hash = "MarathonAX"
|
||||||
MarathonL1Game.tagline = "Can you clear the time hurdles when the game goes this fast?"
|
MarathonAXGame.tagline = "Can you clear the time hurdles when the game goes this fast?"
|
||||||
|
|
||||||
|
|
||||||
|
function MarathonAXGame:new()
|
||||||
|
MarathonAXGame.super:new()
|
||||||
function MarathonL1Game:new()
|
|
||||||
MarathonL1Game.super:new()
|
|
||||||
|
|
||||||
self.roll_frames = 0
|
self.roll_frames = 0
|
||||||
self.randomizer = History6RollsRandomizer()
|
self.randomizer = History6RollsRandomizer()
|
||||||
|
|
||||||
self.section_time_limit = 3600
|
|
||||||
self.section_start_time = 0
|
self.section_start_time = 0
|
||||||
self.section_times = { [0] = 0 }
|
self.section_times = { [0] = 0 }
|
||||||
self.section_clear = false
|
self.section_clear = false
|
||||||
@@ -30,52 +27,48 @@ function MarathonL1Game:new()
|
|||||||
self.next_queue_length = 3
|
self.next_queue_length = 3
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonL1Game:getARE()
|
function MarathonAXGame:getSectionTimeLimit()
|
||||||
if self.lines < 10 then return 18
|
if self.lines < 20 then return 7200
|
||||||
elseif self.lines < 40 then return 14
|
else return 5400 end
|
||||||
elseif self.lines < 60 then return 12
|
|
||||||
elseif self.lines < 70 then return 10
|
|
||||||
elseif self.lines < 80 then return 8
|
|
||||||
elseif self.lines < 90 then return 7
|
|
||||||
else return 6 end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonL1Game:getLineARE()
|
function MarathonAXGame:getARE()
|
||||||
|
return 27
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonAXGame:getLineARE()
|
||||||
return self:getARE()
|
return self:getARE()
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonL1Game:getDasLimit()
|
function MarathonAXGame:getDasLimit()
|
||||||
if self.lines < 20 then return 10
|
return 15
|
||||||
elseif self.lines < 50 then return 9
|
|
||||||
elseif self.lines < 70 then return 8
|
|
||||||
else return 7 end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonL1Game:getLineClearDelay()
|
function MarathonAXGame:getLineClearDelay()
|
||||||
if self.lines < 10 then return 14
|
return 40
|
||||||
elseif self.lines < 30 then return 9
|
|
||||||
else return 5 end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonL1Game:getLockDelay()
|
function MarathonAXGame:getLockDelay()
|
||||||
if self.lines < 10 then return 28
|
return 30
|
||||||
elseif self.lines < 20 then return 24
|
|
||||||
elseif self.lines < 30 then return 22
|
|
||||||
elseif self.lines < 40 then return 20
|
|
||||||
elseif self.lines < 50 then return 18
|
|
||||||
elseif self.lines < 70 then return 14
|
|
||||||
else return 13 end
|
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonL1Game:getGravity()
|
function MarathonAXGame:getGravity()
|
||||||
return 20
|
if self.lines < 10 then return 4/256
|
||||||
|
elseif self.lines < 20 then return 12/256
|
||||||
|
elseif self.lines < 30 then return 48/256
|
||||||
|
elseif self.lines < 40 then return 72/256
|
||||||
|
elseif self.lines < 50 then return 96/256
|
||||||
|
elseif self.lines < 60 then return 1/2
|
||||||
|
elseif self.lines < 70 then return 1
|
||||||
|
elseif self.lines < 80 then return 3/2
|
||||||
|
elseif self.lines < 90 then return 2
|
||||||
|
elseif self.lines < 100 then return 3
|
||||||
|
elseif self.lines < 110 then return 4
|
||||||
|
elseif self.lines < 120 then return 5
|
||||||
|
else return 20 end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonL1Game:getSection()
|
function MarathonAXGame:advanceOneFrame()
|
||||||
return math.floor(level / 100) + 1
|
|
||||||
end
|
|
||||||
|
|
||||||
function MarathonL1Game:advanceOneFrame()
|
|
||||||
if self.clear then
|
if self.clear then
|
||||||
self.roll_frames = self.roll_frames + 1
|
self.roll_frames = self.roll_frames + 1
|
||||||
if self.roll_frames < 0 then
|
if self.roll_frames < 0 then
|
||||||
@@ -87,14 +80,14 @@ function MarathonL1Game:advanceOneFrame()
|
|||||||
if not self.section_clear then
|
if not self.section_clear then
|
||||||
self.frames = self.frames + 1
|
self.frames = self.frames + 1
|
||||||
end
|
end
|
||||||
if self:getSectionTime() >= self.section_time_limit then
|
if self:getSectionTime() >= self:getSectionTimeLimit() then
|
||||||
self.game_over = true
|
self.game_over = true
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonL1Game:onLineClear(cleared_row_count)
|
function MarathonAXGame:onLineClear(cleared_row_count)
|
||||||
if not self.clear then
|
if not self.clear then
|
||||||
local new_lines = self.lines + cleared_row_count
|
local new_lines = self.lines + cleared_row_count
|
||||||
self:updateSectionTimes(self.lines, new_lines)
|
self:updateSectionTimes(self.lines, new_lines)
|
||||||
@@ -106,11 +99,11 @@ function MarathonL1Game:onLineClear(cleared_row_count)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonL1Game:getSectionTime()
|
function MarathonAXGame:getSectionTime()
|
||||||
return self.frames - self.section_start_time
|
return self.frames - self.section_start_time
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonL1Game:updateSectionTimes(old_lines, new_lines)
|
function MarathonAXGame:updateSectionTimes(old_lines, new_lines)
|
||||||
if math.floor(old_lines / 10) < math.floor(new_lines / 10) then
|
if math.floor(old_lines / 10) < math.floor(new_lines / 10) then
|
||||||
-- record new section
|
-- record new section
|
||||||
table.insert(self.section_times, self:getSectionTime())
|
table.insert(self.section_times, self:getSectionTime())
|
||||||
@@ -119,23 +112,23 @@ function MarathonL1Game:updateSectionTimes(old_lines, new_lines)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonL1Game:onPieceEnter()
|
function MarathonAXGame:onPieceEnter()
|
||||||
self.section_clear = false
|
self.section_clear = false
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonL1Game:drawGrid(ruleset)
|
function MarathonAXGame:drawGrid(ruleset)
|
||||||
self.grid:draw()
|
self.grid:draw()
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonL1Game:getHighscoreData()
|
function MarathonAXGame:getHighscoreData()
|
||||||
return {
|
return {
|
||||||
lines = self.lines,
|
lines = self.lines,
|
||||||
frames = self.frames,
|
frames = self.frames,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonL1Game:drawScoringInfo()
|
function MarathonAXGame:drawScoringInfo()
|
||||||
MarathonL1Game.super.drawScoringInfo(self)
|
MarathonAXGame.super.drawScoringInfo(self)
|
||||||
|
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
|
|
||||||
@@ -157,7 +150,7 @@ function MarathonL1Game:drawScoringInfo()
|
|||||||
love.graphics.printf(self.clear and self.lines or self:getSectionEndLines(), 240, 370, 40, "right")
|
love.graphics.printf(self.clear and self.lines or self:getSectionEndLines(), 240, 370, 40, "right")
|
||||||
|
|
||||||
-- draw time left, flash red if necessary
|
-- draw time left, flash red if necessary
|
||||||
local time_left = self.section_time_limit - math.max(self:getSectionTime(), 0)
|
local time_left = self:getSectionTimeLimit() - math.max(self:getSectionTime(), 0)
|
||||||
if not self.game_over and not self.clear and time_left < sp(0,10) and time_left % 4 < 2 then
|
if not self.game_over and not self.clear and time_left < sp(0,10) and time_left % 4 < 2 then
|
||||||
love.graphics.setColor(1, 0.3, 0.3, 1)
|
love.graphics.setColor(1, 0.3, 0.3, 1)
|
||||||
end
|
end
|
||||||
@@ -165,12 +158,12 @@ function MarathonL1Game:drawScoringInfo()
|
|||||||
love.graphics.setColor(1, 1, 1, 1)
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonL1Game:getSectionEndLines()
|
function MarathonAXGame:getSectionEndLines()
|
||||||
return math.floor(self.lines / 10 + 1) * 10
|
return math.floor(self.lines / 10 + 1) * 10
|
||||||
end
|
end
|
||||||
|
|
||||||
function MarathonL1Game:getBackground()
|
function MarathonAXGame:getBackground()
|
||||||
return math.floor(self.lines / 10)
|
return math.floor(self.lines / 10)
|
||||||
end
|
end
|
||||||
|
|
||||||
return MarathonL1Game
|
return MarathonAXGame
|
||||||
42
tetris/modes/marathon_ax2.lua
Normal file
42
tetris/modes/marathon_ax2.lua
Normal file
@@ -0,0 +1,42 @@
|
|||||||
|
require 'funcs'
|
||||||
|
|
||||||
|
local MarathonAX = require 'tetris.modes.marathon_ax'
|
||||||
|
local Piece = require 'tetris.components.piece'
|
||||||
|
|
||||||
|
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
||||||
|
|
||||||
|
local MarathonAX2Game = MarathonAX:extend()
|
||||||
|
|
||||||
|
MarathonAX2Game.name = "Marathon AX2"
|
||||||
|
MarathonAX2Game.hash = "MarathonAX2"
|
||||||
|
MarathonAX2Game.tagline = "Can you clear the time hurdles when the game goes this fast?"
|
||||||
|
|
||||||
|
|
||||||
|
function MarathonAX2Game:new()
|
||||||
|
MarathonAX2Game.super:new()
|
||||||
|
|
||||||
|
self.roll_frames = 0
|
||||||
|
self.randomizer = History6RollsRandomizer()
|
||||||
|
|
||||||
|
self.section_time_limit = 3600
|
||||||
|
self.section_start_time = 0
|
||||||
|
self.section_times = { [0] = 0 }
|
||||||
|
self.section_clear = false
|
||||||
|
|
||||||
|
self.lock_drop = true
|
||||||
|
self.enable_hold = true
|
||||||
|
self.next_queue_length = 3
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonAX2Game:getGravity()
|
||||||
|
if self.lines < 10 then return 84/256
|
||||||
|
elseif self.lines < 20 then return 1/2
|
||||||
|
elseif self.lines < 30 then return 1
|
||||||
|
elseif self.lines < 40 then return 2
|
||||||
|
elseif self.lines < 50 then return 3
|
||||||
|
elseif self.lines < 60 then return 4
|
||||||
|
elseif self.lines < 70 then return 5
|
||||||
|
else return 20 end
|
||||||
|
end
|
||||||
|
|
||||||
|
return MarathonAX2Game
|
||||||
35
tetris/modes/marathon_ax3.lua
Normal file
35
tetris/modes/marathon_ax3.lua
Normal file
@@ -0,0 +1,35 @@
|
|||||||
|
require 'funcs'
|
||||||
|
|
||||||
|
local MarathonAX = require 'tetris.modes.marathon_ax'
|
||||||
|
local Piece = require 'tetris.components.piece'
|
||||||
|
|
||||||
|
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
||||||
|
|
||||||
|
local MarathonAX3Game = MarathonAX:extend()
|
||||||
|
|
||||||
|
MarathonAX3Game.name = "Marathon AX3"
|
||||||
|
MarathonAX3Game.hash = "MarathonAX3"
|
||||||
|
MarathonAX3Game.tagline = "Can you clear the time hurdles when the game goes this fast?"
|
||||||
|
|
||||||
|
|
||||||
|
function MarathonAX3Game:new()
|
||||||
|
MarathonAX3Game.super:new()
|
||||||
|
|
||||||
|
self.roll_frames = 0
|
||||||
|
self.randomizer = History6RollsRandomizer()
|
||||||
|
|
||||||
|
self.section_time_limit = 3600
|
||||||
|
self.section_start_time = 0
|
||||||
|
self.section_times = { [0] = 0 }
|
||||||
|
self.section_clear = false
|
||||||
|
|
||||||
|
self.lock_drop = true
|
||||||
|
self.enable_hold = true
|
||||||
|
self.next_queue_length = 3
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonAX3Game:getGravity()
|
||||||
|
return 20
|
||||||
|
end
|
||||||
|
|
||||||
|
return MarathonAX3Game
|
||||||
185
tetris/modes/marathon_c89.lua
Normal file
185
tetris/modes/marathon_c89.lua
Normal file
@@ -0,0 +1,185 @@
|
|||||||
|
require 'funcs'
|
||||||
|
|
||||||
|
local GameMode = require 'tetris.modes.gamemode'
|
||||||
|
local Piece = require 'tetris.components.piece'
|
||||||
|
|
||||||
|
local Randomizer = require 'tetris.randomizers.randomizer'
|
||||||
|
|
||||||
|
local MarathonC89Game = GameMode:extend()
|
||||||
|
|
||||||
|
MarathonC89Game.name = "Marathon C89"
|
||||||
|
MarathonC89Game.hash = "MarathonC89"
|
||||||
|
MarathonC89Game.tagline = "Can you play fast enough to reach the killscreen?"
|
||||||
|
|
||||||
|
|
||||||
|
function MarathonC89Game:new()
|
||||||
|
MarathonC89Game.super:new()
|
||||||
|
|
||||||
|
self.randomizer = Randomizer()
|
||||||
|
|
||||||
|
self.ready_frames = 1
|
||||||
|
self.waiting_frames = 72
|
||||||
|
|
||||||
|
self.start_level = 12
|
||||||
|
self.level = 12
|
||||||
|
|
||||||
|
self.lock_drop = true
|
||||||
|
self.enable_hard_drop = false
|
||||||
|
self.enable_hold = false
|
||||||
|
self.next_queue_length = 1
|
||||||
|
self.additive_gravity = false
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonC89Game:getDropSpeed() return 1/2 end
|
||||||
|
function MarathonC89Game:getDasLimit() return 16 end
|
||||||
|
function MarathonC89Game:getARR() return 6 end
|
||||||
|
|
||||||
|
function MarathonC89Game:getARE() return 6 end
|
||||||
|
function MarathonC89Game:getLineARE() return 6 end
|
||||||
|
function MarathonC89Game:getLineClearDelay() return 30 end
|
||||||
|
function MarathonC89Game:getLockDelay() return 0 end
|
||||||
|
|
||||||
|
function MarathonC89Game:chargeDAS(inputs)
|
||||||
|
if inputs[self.das.direction] == true and
|
||||||
|
self.prev_inputs[self.das.direction] == true and
|
||||||
|
not inputs["down"] and
|
||||||
|
self.piece ~= nil
|
||||||
|
then
|
||||||
|
local das_frames = self.das.frames + 1
|
||||||
|
if das_frames >= self:getDasLimit() then
|
||||||
|
if self.das.direction == "left" then
|
||||||
|
self.move = (self:getARR() == 0 and "speed" or "") .. "left"
|
||||||
|
self.das.frames = self:getDasLimit() - self:getARR()
|
||||||
|
elseif self.das.direction == "right" then
|
||||||
|
self.move = (self:getARR() == 0 and "speed" or "") .. "right"
|
||||||
|
self.das.frames = self:getDasLimit() - self:getARR()
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self.move = "none"
|
||||||
|
self.das.frames = das_frames
|
||||||
|
end
|
||||||
|
elseif inputs["right"] == true then
|
||||||
|
self.das.direction = "right"
|
||||||
|
if not inputs["down"] and self.piece ~= nil then
|
||||||
|
self.move = "right"
|
||||||
|
self.das.frames = 0
|
||||||
|
else
|
||||||
|
self.move = "none"
|
||||||
|
end
|
||||||
|
elseif inputs["left"] == true then
|
||||||
|
self.das.direction = "left"
|
||||||
|
if not inputs["down"] and self.piece ~= nil then
|
||||||
|
self.move = "left"
|
||||||
|
self.das.frames = 0
|
||||||
|
else
|
||||||
|
self.move = "none"
|
||||||
|
end
|
||||||
|
else
|
||||||
|
self.move = "none"
|
||||||
|
end
|
||||||
|
|
||||||
|
if self.das.direction == "left" and self.piece ~= nil and self.piece:isMoveBlocked(self.grid, {x=-1, y=0}) or
|
||||||
|
self.das.direction == "right" and self.piece ~= nil and self.piece:isMoveBlocked(self.grid, {x=1, y=0})
|
||||||
|
then
|
||||||
|
self.das.frames = self:getDasLimit()
|
||||||
|
end
|
||||||
|
|
||||||
|
if inputs["down"] == false and self.prev_inputs["down"] == true then
|
||||||
|
self.drop_bonus = 0
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
local gravity_table = {
|
||||||
|
[0] =
|
||||||
|
1366/65536, 1525/65536, 1725/65536, 1986/65536, 2341/65536,
|
||||||
|
2850/65536, 3641/65536, 5042/65536, 8192/65536, 10923/65536,
|
||||||
|
13108/65536, 13108/65536, 13108/65536, 16384/65536, 16384/65536,
|
||||||
|
16384/65536, 21846/65536, 21846/65536, 21846/65536
|
||||||
|
}
|
||||||
|
|
||||||
|
function MarathonC89Game:getGravity()
|
||||||
|
if self.waiting_frames > 0 then return 0 end
|
||||||
|
if self.level >= 29 then return 1
|
||||||
|
elseif self.level >= 19 then return 1/2
|
||||||
|
else return gravity_table[self.level] end
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonC89Game:advanceOneFrame()
|
||||||
|
if self.waiting_frames > 0 then
|
||||||
|
self.waiting_frames = self.waiting_frames - 1
|
||||||
|
else
|
||||||
|
self.frames = self.frames + 1
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonC89Game:onPieceLock()
|
||||||
|
self.score = self.score + self.drop_bonus
|
||||||
|
self.drop_bonus = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
local cleared_line_scores = { 40, 100, 300, 1200 }
|
||||||
|
|
||||||
|
function MarathonC89Game:getLevelForLines()
|
||||||
|
if self.start_level < 10 then
|
||||||
|
return math.max(self.start_level, math.floor(self.lines / 10))
|
||||||
|
elseif self.start_level < 16 then
|
||||||
|
return math.max(self.start_level, self.start_level + math.floor((self.lines - 100) / 10))
|
||||||
|
else
|
||||||
|
return math.max(self.start_level, math.floor((self.lines - 60) / 10))
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonC89Game:updateScore(level, drop_bonus, cleared_lines)
|
||||||
|
if cleared_lines > 0 then
|
||||||
|
self.score = self.score + cleared_line_scores[cleared_lines] * (self.level + 1)
|
||||||
|
self.lines = self.lines + cleared_lines
|
||||||
|
self.level = self:getLevelForLines()
|
||||||
|
else
|
||||||
|
self.drop_bonus = 0
|
||||||
|
self.combo = 1
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonC89Game:drawGrid()
|
||||||
|
self.grid:draw()
|
||||||
|
if self.piece ~= nil and self.level < 100 then
|
||||||
|
self:drawGhostPiece(ruleset)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonC89Game:drawScoringInfo()
|
||||||
|
MarathonC89Game.super.drawScoringInfo(self)
|
||||||
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
|
|
||||||
|
love.graphics.setFont(font_3x5_2)
|
||||||
|
love.graphics.print(
|
||||||
|
self.das.direction .. " " ..
|
||||||
|
self.das.frames .. " " ..
|
||||||
|
st(self.prev_inputs)
|
||||||
|
)
|
||||||
|
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
||||||
|
love.graphics.printf("LINES", 240, 120, 40, "left")
|
||||||
|
love.graphics.printf("SCORE", 240, 200, 40, "left")
|
||||||
|
|
||||||
|
love.graphics.setFont(font_3x5_3)
|
||||||
|
love.graphics.printf(self.lines, 240, 140, 90, "left")
|
||||||
|
love.graphics.printf(self.score, 240, 220, 90, "left")
|
||||||
|
|
||||||
|
love.graphics.setFont(font_8x11)
|
||||||
|
love.graphics.printf(formatTime(self.frames), 64, 420, 160, "center")
|
||||||
|
end
|
||||||
|
|
||||||
|
|
||||||
|
function MarathonC89Game:getBackground()
|
||||||
|
return math.min(self.level, 19)
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonC89Game:getHighscoreData()
|
||||||
|
return {
|
||||||
|
score = self.score,
|
||||||
|
level = self.level,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
return MarathonC89Game
|
||||||
133
tetris/modes/marathon_wcb.lua
Normal file
133
tetris/modes/marathon_wcb.lua
Normal file
@@ -0,0 +1,133 @@
|
|||||||
|
require 'funcs'
|
||||||
|
|
||||||
|
local GameMode = require 'tetris.modes.gamemode'
|
||||||
|
local Piece = require 'tetris.components.piece'
|
||||||
|
|
||||||
|
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
||||||
|
|
||||||
|
local MarathonWCBGame = GameMode:extend()
|
||||||
|
|
||||||
|
MarathonWCBGame.name = "Marathon WCB"
|
||||||
|
MarathonWCBGame.hash = "MarathonWCB"
|
||||||
|
MarathonWCBGame.tagline = "When all the pieces slip right to their destinations... can you keep up?"
|
||||||
|
|
||||||
|
|
||||||
|
function MarathonWCBGame:new()
|
||||||
|
MarathonWCBGame.super:new()
|
||||||
|
|
||||||
|
self.pieces = 0
|
||||||
|
self.randomizer = History6RollsRandomizer()
|
||||||
|
|
||||||
|
self.lock_drop = true
|
||||||
|
self.lock_hard_drop = true
|
||||||
|
self.instant_hard_drop = true
|
||||||
|
self.instant_soft_drop = true
|
||||||
|
self.enable_hold = false
|
||||||
|
self.next_queue_length = 3
|
||||||
|
|
||||||
|
self.piece_is_active = false
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonWCBGame:getDropSpeed()
|
||||||
|
return 20
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonWCBGame:getARR()
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonWCBGame:getARE()
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonWCBGame:getLineARE()
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonWCBGame:getDasLimit()
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonWCBGame:getLineClearDelay()
|
||||||
|
return 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonWCBGame:getLockDelay()
|
||||||
|
return math.huge
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonWCBGame:getGravity()
|
||||||
|
return self.piece_is_active and 20 or 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonWCBGame:advanceOneFrame()
|
||||||
|
if self.clear then
|
||||||
|
self.roll_frames = self.roll_frames + 1
|
||||||
|
if self.roll_frames > 150 then
|
||||||
|
self.completed = true
|
||||||
|
end
|
||||||
|
return false
|
||||||
|
elseif self.ready_frames == 0 then
|
||||||
|
self.frames = self.frames + 1
|
||||||
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonWCBGame:onAttemptPieceMove()
|
||||||
|
if self.piece ~= nil then
|
||||||
|
-- don't let the piece move before it's finished dropping
|
||||||
|
self.piece:dropToBottom(self.grid)
|
||||||
|
end
|
||||||
|
self.piece_is_active = true
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonWCBGame:onAttemptPieceRotate()
|
||||||
|
self.piece_is_active = true
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonWCBGame:onPieceLock()
|
||||||
|
self.piece_is_active = false
|
||||||
|
self.pieces = self.pieces + 1
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonWCBGame:onLineClear(cleared_row_count)
|
||||||
|
if not self.clear then
|
||||||
|
self.lines = self.lines + cleared_row_count
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonWCBGame:drawGrid(ruleset)
|
||||||
|
self.grid:draw()
|
||||||
|
if self.piece ~= nil then
|
||||||
|
self:drawGhostPiece(ruleset)
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonWCBGame:getHighscoreData()
|
||||||
|
return {
|
||||||
|
pieces = self.pieces,
|
||||||
|
frames = self.frames,
|
||||||
|
}
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonWCBGame:drawScoringInfo()
|
||||||
|
MarathonWCBGame.super.drawScoringInfo(self)
|
||||||
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
|
|
||||||
|
local text_x = config["side_next"] and 320 or 240
|
||||||
|
|
||||||
|
love.graphics.setFont(font_3x5_2)
|
||||||
|
love.graphics.printf("NEXT", 64, 40, 40, "left")
|
||||||
|
love.graphics.printf("lines", text_x, 160, 80, "left")
|
||||||
|
love.graphics.printf("pieces", text_x, 220, 80, "left")
|
||||||
|
|
||||||
|
love.graphics.setFont(font_3x5_3)
|
||||||
|
love.graphics.printf(self.lines, text_x, 180, 80, "left")
|
||||||
|
love.graphics.printf(self.pieces, text_x, 240, 80, "left")
|
||||||
|
end
|
||||||
|
|
||||||
|
function MarathonWCBGame:getBackground()
|
||||||
|
return (math.floor(self.pieces / 50) % 20)
|
||||||
|
end
|
||||||
|
|
||||||
|
return MarathonWCBGame
|
||||||
@@ -25,6 +25,8 @@ function PhantomMania2Game:new()
|
|||||||
self.combo = 1
|
self.combo = 1
|
||||||
self.hold_age = 0
|
self.hold_age = 0
|
||||||
self.queue_age = 0
|
self.queue_age = 0
|
||||||
|
self.roll_points = 0
|
||||||
|
|
||||||
self.randomizer = History6RollsRandomizer()
|
self.randomizer = History6RollsRandomizer()
|
||||||
|
|
||||||
self.lock_drop = true
|
self.lock_drop = true
|
||||||
@@ -135,7 +137,7 @@ function PhantomMania2Game:onPieceEnter()
|
|||||||
end
|
end
|
||||||
|
|
||||||
local cleared_row_levels = {1, 2, 4, 6}
|
local cleared_row_levels = {1, 2, 4, 6}
|
||||||
local cleared_row_points = {0.02, 0.05, 0.15, 0.6}
|
local cleared_row_points = {2, 6, 15, 40}
|
||||||
|
|
||||||
function PhantomMania2Game:onLineClear(cleared_row_count)
|
function PhantomMania2Game:onLineClear(cleared_row_count)
|
||||||
if not self.clear then
|
if not self.clear then
|
||||||
@@ -144,6 +146,7 @@ function PhantomMania2Game:onLineClear(cleared_row_count)
|
|||||||
if new_level >= 1300 or self:hitTorikan(self.level, new_level) then
|
if new_level >= 1300 or self:hitTorikan(self.level, new_level) then
|
||||||
if new_level >= 1300 then
|
if new_level >= 1300 then
|
||||||
self.level = 1300
|
self.level = 1300
|
||||||
|
self.big_mode = true
|
||||||
end
|
end
|
||||||
self.clear = true
|
self.clear = true
|
||||||
self.grid:clear()
|
self.grid:clear()
|
||||||
@@ -152,6 +155,12 @@ function PhantomMania2Game:onLineClear(cleared_row_count)
|
|||||||
self.level = math.min(new_level, 1300)
|
self.level = math.min(new_level, 1300)
|
||||||
end
|
end
|
||||||
self:advanceBottomRow(-cleared_row_count)
|
self:advanceBottomRow(-cleared_row_count)
|
||||||
|
else
|
||||||
|
self.roll_points = self.roll_points + cleared_row_points[cleared_row_count]
|
||||||
|
if self.roll_points >= 100 then
|
||||||
|
self.roll_points = self.roll_points - 100
|
||||||
|
self.grade = self.grade + 1
|
||||||
|
end
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
@@ -225,7 +234,7 @@ PhantomMania2Game.garbageOpacityFunction = function(age)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function PhantomMania2Game:drawGrid()
|
function PhantomMania2Game:drawGrid()
|
||||||
if not (self.game_over or self.clear) then
|
if not (self.game_over) then
|
||||||
self.grid:drawInvisible(self.rollOpacityFunction, self.garbageOpacityFunction)
|
self.grid:drawInvisible(self.rollOpacityFunction, self.garbageOpacityFunction)
|
||||||
else
|
else
|
||||||
self.grid:draw()
|
self.grid:draw()
|
||||||
@@ -243,7 +252,7 @@ local function getLetterGrade(grade)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function PhantomMania2Game:setNextOpacity(i)
|
function PhantomMania2Game:setNextOpacity(i)
|
||||||
if self.level > 1000 then
|
if self.level > 1000 and self.level < 1300 then
|
||||||
local hidden_next_pieces = math.floor(self.level / 100) - 10
|
local hidden_next_pieces = math.floor(self.level / 100) - 10
|
||||||
if i < hidden_next_pieces then
|
if i < hidden_next_pieces then
|
||||||
love.graphics.setColor(1, 1, 1, 0)
|
love.graphics.setColor(1, 1, 1, 0)
|
||||||
@@ -258,7 +267,7 @@ function PhantomMania2Game:setNextOpacity(i)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function PhantomMania2Game:setHoldOpacity()
|
function PhantomMania2Game:setHoldOpacity()
|
||||||
if self.level > 1000 then
|
if self.level > 1000 and self.level < 1300 then
|
||||||
love.graphics.setColor(1, 1, 1, 1 - math.min(1, self.hold_age / 15))
|
love.graphics.setColor(1, 1, 1, 1 - math.min(1, self.hold_age / 15))
|
||||||
else
|
else
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
|
|||||||
@@ -5,17 +5,15 @@ local Piece = require 'tetris.components.piece'
|
|||||||
|
|
||||||
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
||||||
|
|
||||||
local LigneGame = GameMode:extend()
|
local Race40Game = GameMode:extend()
|
||||||
|
|
||||||
LigneGame.name = "Ligne"
|
Race40Game.name = "Race 40"
|
||||||
LigneGame.hash = "Ligne"
|
Race40Game.hash = "Race40"
|
||||||
LigneGame.tagline = "How fast can you clear 40 lines?"
|
Race40Game.tagline = "How fast can you clear 40 lines?"
|
||||||
|
|
||||||
|
|
||||||
|
function Race40Game:new()
|
||||||
|
Race40Game.super:new()
|
||||||
function LigneGame:new()
|
|
||||||
LigneGame.super:new()
|
|
||||||
|
|
||||||
self.lines = 0
|
self.lines = 0
|
||||||
self.line_goal = 40
|
self.line_goal = 40
|
||||||
@@ -27,44 +25,44 @@ function LigneGame:new()
|
|||||||
self.lock_drop = true
|
self.lock_drop = true
|
||||||
self.lock_hard_drop = true
|
self.lock_hard_drop = true
|
||||||
self.instant_hard_drop = true
|
self.instant_hard_drop = true
|
||||||
self.instant_soft_drop = false
|
self.instant_soft_drop = true
|
||||||
self.enable_hold = true
|
self.enable_hold = true
|
||||||
self.next_queue_length = 3
|
self.next_queue_length = 3
|
||||||
end
|
end
|
||||||
|
|
||||||
function LigneGame:getDropSpeed()
|
function Race40Game:getDropSpeed()
|
||||||
return 20
|
return 20
|
||||||
end
|
end
|
||||||
|
|
||||||
function LigneGame:getARR()
|
function Race40Game:getARR()
|
||||||
return 0
|
return 0
|
||||||
end
|
end
|
||||||
|
|
||||||
function LigneGame:getARE()
|
function Race40Game:getARE()
|
||||||
return 0
|
return 4
|
||||||
end
|
end
|
||||||
|
|
||||||
function LigneGame:getLineARE()
|
function Race40Game:getLineARE()
|
||||||
return self:getARE()
|
return 2
|
||||||
end
|
end
|
||||||
|
|
||||||
function LigneGame:getDasLimit()
|
function Race40Game:getDasLimit()
|
||||||
return 6
|
return 6
|
||||||
end
|
end
|
||||||
|
|
||||||
function LigneGame:getLineClearDelay()
|
function Race40Game:getLineClearDelay()
|
||||||
return 0
|
return 2
|
||||||
end
|
end
|
||||||
|
|
||||||
function LigneGame:getLockDelay()
|
function Race40Game:getLockDelay()
|
||||||
return 15
|
return 30
|
||||||
end
|
end
|
||||||
|
|
||||||
function LigneGame:getGravity()
|
function Race40Game:getGravity()
|
||||||
return 1/64
|
return 20
|
||||||
end
|
end
|
||||||
|
|
||||||
function LigneGame:advanceOneFrame()
|
function Race40Game:advanceOneFrame()
|
||||||
if self.clear then
|
if self.clear then
|
||||||
self.roll_frames = self.roll_frames + 1
|
self.roll_frames = self.roll_frames + 1
|
||||||
if self.roll_frames > 150 then
|
if self.roll_frames > 150 then
|
||||||
@@ -77,11 +75,11 @@ function LigneGame:advanceOneFrame()
|
|||||||
return true
|
return true
|
||||||
end
|
end
|
||||||
|
|
||||||
function LigneGame:onPieceLock()
|
function Race40Game:onPieceLock()
|
||||||
self.pieces = self.pieces + 1
|
self.pieces = self.pieces + 1
|
||||||
end
|
end
|
||||||
|
|
||||||
function LigneGame:onLineClear(cleared_row_count)
|
function Race40Game:onLineClear(cleared_row_count)
|
||||||
if not self.clear then
|
if not self.clear then
|
||||||
self.lines = self.lines + cleared_row_count
|
self.lines = self.lines + cleared_row_count
|
||||||
if self.lines >= self.line_goal then
|
if self.lines >= self.line_goal then
|
||||||
@@ -90,22 +88,22 @@ function LigneGame:onLineClear(cleared_row_count)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function LigneGame:drawGrid(ruleset)
|
function Race40Game:drawGrid(ruleset)
|
||||||
self.grid:draw()
|
self.grid:draw()
|
||||||
if self.piece ~= nil then
|
if self.piece ~= nil then
|
||||||
self:drawGhostPiece(ruleset)
|
self:drawGhostPiece(ruleset)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function LigneGame:getHighscoreData()
|
function Race40Game:getHighscoreData()
|
||||||
return {
|
return {
|
||||||
level = self.level,
|
level = self.level,
|
||||||
frames = self.frames,
|
frames = self.frames,
|
||||||
}
|
}
|
||||||
end
|
end
|
||||||
|
|
||||||
function LigneGame:drawScoringInfo()
|
function Race40Game:drawScoringInfo()
|
||||||
LigneGame.super.drawScoringInfo(self)
|
Race40Game.super.drawScoringInfo(self)
|
||||||
love.graphics.setColor(1, 1, 1, 1)
|
love.graphics.setColor(1, 1, 1, 1)
|
||||||
|
|
||||||
local text_x = config["side_next"] and 320 or 240
|
local text_x = config["side_next"] and 320 or 240
|
||||||
@@ -124,8 +122,8 @@ function LigneGame:drawScoringInfo()
|
|||||||
love.graphics.printf(math.max(0, self.line_goal - self.lines), text_x, 340, 40, "left")
|
love.graphics.printf(math.max(0, self.line_goal - self.lines), text_x, 340, 40, "left")
|
||||||
end
|
end
|
||||||
|
|
||||||
function LigneGame:getBackground()
|
function Race40Game:getBackground()
|
||||||
return 2
|
return 2
|
||||||
end
|
end
|
||||||
|
|
||||||
return LigneGame
|
return Race40Game
|
||||||
@@ -44,13 +44,14 @@ function SurvivalA3Game:getLineARE()
|
|||||||
end
|
end
|
||||||
|
|
||||||
function SurvivalA3Game:getDasLimit()
|
function SurvivalA3Game:getDasLimit()
|
||||||
if self.level < 200 then return 9
|
if self.level < 100 then return 9
|
||||||
elseif self.level < 500 then return 7
|
elseif self.level < 500 then return 7
|
||||||
else return 5 end
|
else return 5 end
|
||||||
end
|
end
|
||||||
|
|
||||||
function SurvivalA3Game:getLineClearDelay()
|
function SurvivalA3Game:getLineClearDelay()
|
||||||
return self:getLineARE() - 2
|
if self.level < 1300 then return self:getLineARE() - 2
|
||||||
|
else return 6 end
|
||||||
end
|
end
|
||||||
|
|
||||||
function SurvivalA3Game:getLockDelay()
|
function SurvivalA3Game:getLockDelay()
|
||||||
@@ -60,7 +61,8 @@ function SurvivalA3Game:getLockDelay()
|
|||||||
elseif self.level < 600 then return 13
|
elseif self.level < 600 then return 13
|
||||||
elseif self.level < 1100 then return 12
|
elseif self.level < 1100 then return 12
|
||||||
elseif self.level < 1200 then return 10
|
elseif self.level < 1200 then return 10
|
||||||
else return 8 end
|
elseif self.level < 1300 then return 8
|
||||||
|
else return 15 end
|
||||||
end
|
end
|
||||||
|
|
||||||
function SurvivalA3Game:getGravity()
|
function SurvivalA3Game:getGravity()
|
||||||
@@ -130,6 +132,7 @@ function SurvivalA3Game:onLineClear(cleared_row_count)
|
|||||||
if new_level >= 1300 or self:hitTorikan(self.level, new_level) then
|
if new_level >= 1300 or self:hitTorikan(self.level, new_level) then
|
||||||
if new_level >= 1300 then
|
if new_level >= 1300 then
|
||||||
self.level = 1300
|
self.level = 1300
|
||||||
|
self.big_mode = true
|
||||||
end
|
end
|
||||||
self.clear = true
|
self.clear = true
|
||||||
self.grid:clear()
|
self.grid:clear()
|
||||||
@@ -188,10 +191,8 @@ end
|
|||||||
local function getLetterGrade(grade)
|
local function getLetterGrade(grade)
|
||||||
if grade == 0 then
|
if grade == 0 then
|
||||||
return "1"
|
return "1"
|
||||||
elseif grade <= 9 then
|
|
||||||
return "S" .. tostring(grade)
|
|
||||||
else
|
else
|
||||||
return "M" .. tostring(grade - 9)
|
return "S" .. tostring(grade)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
76
tetris/modes/survival_ax.lua
Normal file
76
tetris/modes/survival_ax.lua
Normal file
@@ -0,0 +1,76 @@
|
|||||||
|
require 'funcs'
|
||||||
|
|
||||||
|
local MarathonAX = require 'tetris.modes.marathon_ax'
|
||||||
|
local Piece = require 'tetris.components.piece'
|
||||||
|
|
||||||
|
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
||||||
|
|
||||||
|
local SurvivalAXGame = MarathonAX:extend()
|
||||||
|
|
||||||
|
SurvivalAXGame.name = "Survival AX"
|
||||||
|
SurvivalAXGame.hash = "SurvivalAX"
|
||||||
|
SurvivalAXGame.tagline = "Can you clear the time hurdles when the game goes this fast?"
|
||||||
|
|
||||||
|
|
||||||
|
function SurvivalAXGame:new()
|
||||||
|
SurvivalAXGame.super:new()
|
||||||
|
|
||||||
|
self.roll_frames = 0
|
||||||
|
self.randomizer = History6RollsRandomizer()
|
||||||
|
|
||||||
|
self.section_time_limit = 3600
|
||||||
|
self.section_start_time = 0
|
||||||
|
self.section_times = { [0] = 0 }
|
||||||
|
self.section_clear = false
|
||||||
|
|
||||||
|
self.lock_drop = true
|
||||||
|
self.enable_hold = true
|
||||||
|
self.next_queue_length = 3
|
||||||
|
end
|
||||||
|
|
||||||
|
function SurvivalAXGame:getSectionTimeLimit()
|
||||||
|
return 3600
|
||||||
|
end
|
||||||
|
|
||||||
|
function SurvivalAXGame:getARE()
|
||||||
|
if self.lines < 10 then return 18
|
||||||
|
elseif self.lines < 40 then return 14
|
||||||
|
elseif self.lines < 60 then return 12
|
||||||
|
elseif self.lines < 70 then return 10
|
||||||
|
elseif self.lines < 80 then return 8
|
||||||
|
elseif self.lines < 90 then return 7
|
||||||
|
else return 6 end
|
||||||
|
end
|
||||||
|
|
||||||
|
function SurvivalAXGame:getLineARE()
|
||||||
|
return self:getARE()
|
||||||
|
end
|
||||||
|
|
||||||
|
function SurvivalAXGame:getDasLimit()
|
||||||
|
if self.lines < 20 then return 10
|
||||||
|
elseif self.lines < 50 then return 9
|
||||||
|
elseif self.lines < 70 then return 8
|
||||||
|
else return 7 end
|
||||||
|
end
|
||||||
|
|
||||||
|
function SurvivalAXGame:getLineClearDelay()
|
||||||
|
if self.lines < 10 then return 14
|
||||||
|
elseif self.lines < 30 then return 8
|
||||||
|
else return 5 end
|
||||||
|
end
|
||||||
|
|
||||||
|
function SurvivalAXGame:getLockDelay()
|
||||||
|
if self.lines < 10 then return 30
|
||||||
|
elseif self.lines < 20 then return 26
|
||||||
|
elseif self.lines < 30 then return 24
|
||||||
|
elseif self.lines < 40 then return 22
|
||||||
|
elseif self.lines < 50 then return 20
|
||||||
|
elseif self.lines < 70 then return 16
|
||||||
|
else return 15 end
|
||||||
|
end
|
||||||
|
|
||||||
|
function SurvivalAXGame:getGravity()
|
||||||
|
return 20
|
||||||
|
end
|
||||||
|
|
||||||
|
return SurvivalAXGame
|
||||||
59
tetris/modes/survival_ax2.lua
Normal file
59
tetris/modes/survival_ax2.lua
Normal file
@@ -0,0 +1,59 @@
|
|||||||
|
require 'funcs'
|
||||||
|
|
||||||
|
local MarathonAX2 = require 'tetris.modes.marathon_ax2'
|
||||||
|
local Piece = require 'tetris.components.piece'
|
||||||
|
|
||||||
|
local History6RollsRandomizer = require 'tetris.randomizers.history_6rolls'
|
||||||
|
|
||||||
|
local SurvivalAX2Game = MarathonAX2:extend()
|
||||||
|
|
||||||
|
SurvivalAX2Game.name = "Survival AX2"
|
||||||
|
SurvivalAX2Game.hash = "SurvivalAX2"
|
||||||
|
SurvivalAX2Game.tagline = "Can you clear the time hurdles when the game goes this fast?"
|
||||||
|
|
||||||
|
|
||||||
|
function SurvivalAX2Game:new()
|
||||||
|
SurvivalAX2Game.super:new()
|
||||||
|
|
||||||
|
self.roll_frames = 0
|
||||||
|
self.randomizer = History6RollsRandomizer()
|
||||||
|
|
||||||
|
self.section_time_limit = 3600
|
||||||
|
self.section_start_time = 0
|
||||||
|
self.section_times = { [0] = 0 }
|
||||||
|
self.section_clear = false
|
||||||
|
|
||||||
|
self.lock_drop = true
|
||||||
|
self.enable_hold = true
|
||||||
|
self.next_queue_length = 3
|
||||||
|
end
|
||||||
|
|
||||||
|
function SurvivalAX2Game:getSectionTimeLimit()
|
||||||
|
return 3600
|
||||||
|
end
|
||||||
|
|
||||||
|
function SurvivalAX2Game:getARE()
|
||||||
|
return 6
|
||||||
|
end
|
||||||
|
|
||||||
|
function SurvivalAX2Game:getLineARE()
|
||||||
|
return self:getARE()
|
||||||
|
end
|
||||||
|
|
||||||
|
function SurvivalAX2Game:getDasLimit()
|
||||||
|
return 7
|
||||||
|
end
|
||||||
|
|
||||||
|
function SurvivalAX2Game:getLineClearDelay()
|
||||||
|
return 5
|
||||||
|
end
|
||||||
|
|
||||||
|
function SurvivalAX2Game:getLockDelay()
|
||||||
|
return 15
|
||||||
|
end
|
||||||
|
|
||||||
|
function SurvivalAX2Game:getGravity()
|
||||||
|
return 20
|
||||||
|
end
|
||||||
|
|
||||||
|
return SurvivalAX2Game
|
||||||
@@ -16,6 +16,16 @@ ARS.spawn_positions = {
|
|||||||
Z = { x=4, y=5 },
|
Z = { x=4, y=5 },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ARS.big_spawn_positions = {
|
||||||
|
I = { x=2, y=2 },
|
||||||
|
J = { x=2, y=3 },
|
||||||
|
L = { x=2, y=3 },
|
||||||
|
O = { x=2, y=3 },
|
||||||
|
S = { x=2, y=3 },
|
||||||
|
T = { x=2, y=3 },
|
||||||
|
Z = { x=2, y=3 },
|
||||||
|
}
|
||||||
|
|
||||||
ARS.block_offsets = {
|
ARS.block_offsets = {
|
||||||
I={
|
I={
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} },
|
{ {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} },
|
||||||
|
|||||||
32
tetris/rulesets/arika_ace.lua
Normal file
32
tetris/rulesets/arika_ace.lua
Normal file
@@ -0,0 +1,32 @@
|
|||||||
|
local ArikaTI = require 'tetris.rulesets.arika_ti'
|
||||||
|
|
||||||
|
local ARS = ArikaTI:extend()
|
||||||
|
|
||||||
|
ARS.name = "Ace-ARS"
|
||||||
|
ARS.hash = "ArikaAce"
|
||||||
|
|
||||||
|
function ARS:onPieceCreate(piece, grid)
|
||||||
|
piece.floorkick = 0
|
||||||
|
piece.rotate_counter = 0
|
||||||
|
piece.move_counter = 0
|
||||||
|
end
|
||||||
|
|
||||||
|
function ARS:onPieceDrop(piece, grid)
|
||||||
|
piece.lock_delay = 0 -- step reset
|
||||||
|
end
|
||||||
|
|
||||||
|
function ARS:onPieceMove(piece, grid)
|
||||||
|
piece.lock_delay = 0 -- move reset
|
||||||
|
if piece:isDropBlocked(grid) then
|
||||||
|
piece.move_counter = piece.move_counter + 1
|
||||||
|
if piece.move_counter >= 128 then
|
||||||
|
piece.locked = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function ARS:onPieceRotate(piece, grid)
|
||||||
|
self:onPieceMove(piece, grid)
|
||||||
|
end
|
||||||
|
|
||||||
|
return ARS
|
||||||
@@ -16,6 +16,16 @@ ARS.spawn_positions = {
|
|||||||
Z = { x=4, y=5 },
|
Z = { x=4, y=5 },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
ARS.big_spawn_positions = {
|
||||||
|
I = { x=2, y=2 },
|
||||||
|
J = { x=2, y=3 },
|
||||||
|
L = { x=2, y=3 },
|
||||||
|
O = { x=2, y=3 },
|
||||||
|
S = { x=2, y=3 },
|
||||||
|
T = { x=2, y=3 },
|
||||||
|
Z = { x=2, y=3 },
|
||||||
|
}
|
||||||
|
|
||||||
ARS.block_offsets = {
|
ARS.block_offsets = {
|
||||||
I={
|
I={
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} },
|
{ {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} },
|
||||||
@@ -107,13 +117,12 @@ function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
elseif piece.shape ~= "I" then
|
elseif piece.shape ~= "I" then
|
||||||
-- kick right, kick left
|
-- kick right, kick left
|
||||||
if (grid:canPlacePiece(new_piece:withOffset({x=1, y=0}))) then
|
if (grid:canPlacePiece(new_piece:withOffset({x=1, y=0}))) then
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
|
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
|
||||||
elseif (grid:canPlacePiece(new_piece:withOffset({x=-1, y=0}))) then
|
elseif (grid:canPlacePiece(new_piece:withOffset({x=-1, y=0}))) then
|
||||||
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
|
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
|
||||||
end
|
end
|
||||||
else
|
|
||||||
end
|
end
|
||||||
|
|
||||||
end
|
end
|
||||||
|
|||||||
@@ -16,6 +16,16 @@ CRS.spawn_positions = {
|
|||||||
Z = { x=4, y=4 },
|
Z = { x=4, y=4 },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CRS.big_spawn_positions = {
|
||||||
|
I = { x=2, y=2 },
|
||||||
|
J = { x=2, y=3 },
|
||||||
|
L = { x=2, y=3 },
|
||||||
|
O = { x=2, y=3 },
|
||||||
|
S = { x=2, y=2 },
|
||||||
|
T = { x=2, y=3 },
|
||||||
|
Z = { x=2, y=2 },
|
||||||
|
}
|
||||||
|
|
||||||
CRS.block_offsets = {
|
CRS.block_offsets = {
|
||||||
I={
|
I={
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} },
|
{ {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} },
|
||||||
@@ -388,6 +398,7 @@ function CRS:onPieceDrop(piece, grid)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function CRS:onPieceMove(piece, grid)
|
function CRS:onPieceMove(piece, grid)
|
||||||
|
piece.lock_delay = 0 -- move reset
|
||||||
if piece:isDropBlocked(grid) then
|
if piece:isDropBlocked(grid) then
|
||||||
piece.move_counter = piece.move_counter + 1
|
piece.move_counter = piece.move_counter + 1
|
||||||
if piece.move_counter >= 24 then
|
if piece.move_counter >= 24 then
|
||||||
@@ -397,6 +408,7 @@ function CRS:onPieceMove(piece, grid)
|
|||||||
end
|
end
|
||||||
|
|
||||||
function CRS:onPieceRotate(piece, grid)
|
function CRS:onPieceRotate(piece, grid)
|
||||||
|
piece.lock_delay = 0 -- move reset
|
||||||
if piece:isDropBlocked(grid) then
|
if piece:isDropBlocked(grid) then
|
||||||
piece.rotate_counter = piece.rotate_counter + 1
|
piece.rotate_counter = piece.rotate_counter + 1
|
||||||
if piece.rotate_counter >= 12 then
|
if piece.rotate_counter >= 12 then
|
||||||
@@ -405,6 +417,4 @@ function CRS:onPieceRotate(piece, grid)
|
|||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function CRS:getDefaultOrientation() return 1 end -- downward facing pieces by default
|
|
||||||
|
|
||||||
return CRS
|
return CRS
|
||||||
|
|||||||
@@ -56,26 +56,33 @@ function Ruleset:attemptWallkicks(piece, new_piece, rot_dir, grid)
|
|||||||
-- do nothing in default ruleset
|
-- do nothing in default ruleset
|
||||||
end
|
end
|
||||||
|
|
||||||
function Ruleset:movePiece(piece, grid, move)
|
function Ruleset:movePiece(piece, grid, move, instant)
|
||||||
local x = piece.position.x
|
local x = piece.position.x
|
||||||
if move == "left" then
|
if move == "left" 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)
|
|
||||||
elseif move == "right" then
|
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
|
elseif move == "speedright" then
|
||||||
piece:moveInGrid({x=1, y=0}, 10, grid)
|
piece:moveInGrid({x=1, y=0}, 10, grid, instant)
|
||||||
end
|
end
|
||||||
if piece.position.x ~= x then
|
if piece.position.x ~= x then
|
||||||
self:onPieceMove(piece, grid)
|
self:onPieceMove(piece, grid)
|
||||||
end
|
end
|
||||||
end
|
end
|
||||||
|
|
||||||
function Ruleset:dropPiece(inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked, hard_drop_enabled)
|
function Ruleset:dropPiece(
|
||||||
|
inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked,
|
||||||
|
hard_drop_enabled, additive_gravity
|
||||||
|
)
|
||||||
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
|
||||||
piece:addGravity(gravity + drop_speed, grid)
|
if additive_gravity then
|
||||||
|
piece:addGravity(gravity + drop_speed, grid)
|
||||||
|
else
|
||||||
|
piece:addGravity(math.max(gravity, drop_speed), grid)
|
||||||
|
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)
|
||||||
@@ -102,12 +109,19 @@ function Ruleset:getDefaultOrientation() return 1 end
|
|||||||
function Ruleset:initializePiece(
|
function Ruleset:initializePiece(
|
||||||
inputs, data, grid, gravity, prev_inputs,
|
inputs, data, grid, gravity, prev_inputs,
|
||||||
move, lock_delay, drop_speed,
|
move, lock_delay, drop_speed,
|
||||||
drop_locked, hard_drop_locked
|
drop_locked, hard_drop_locked, big
|
||||||
)
|
)
|
||||||
|
local spawn_positions
|
||||||
|
if big then
|
||||||
|
spawn_positions = self.big_spawn_positions
|
||||||
|
else
|
||||||
|
spawn_positions = self.spawn_positions
|
||||||
|
end
|
||||||
local piece = Piece(data.shape, data.orientation - 1, {
|
local piece = Piece(data.shape, data.orientation - 1, {
|
||||||
x = self.spawn_positions[data.shape].x,
|
x = spawn_positions[data.shape].x,
|
||||||
y = self.spawn_positions[data.shape].y
|
y = spawn_positions[data.shape].y
|
||||||
}, self.block_offsets, 0, 0, data.skin)
|
}, self.block_offsets, 0, 0, data.skin, big)
|
||||||
|
|
||||||
self:onPieceCreate(piece)
|
self:onPieceCreate(piece)
|
||||||
self:rotatePiece(inputs, piece, grid, {}, true)
|
self:rotatePiece(inputs, piece, grid, {}, true)
|
||||||
self:dropPiece(inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked)
|
self:dropPiece(inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked)
|
||||||
@@ -120,11 +134,15 @@ function Ruleset:onPieceCreate(piece) end
|
|||||||
function Ruleset:processPiece(
|
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, hard_drop_enabled
|
drop_locked, hard_drop_locked,
|
||||||
|
hard_drop_enabled, additive_gravity
|
||||||
)
|
)
|
||||||
self:rotatePiece(inputs, piece, grid, prev_inputs, false)
|
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)
|
self:dropPiece(
|
||||||
|
inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked,
|
||||||
|
hard_drop_enabled, additive_gravity
|
||||||
|
)
|
||||||
self:lockPiece(piece, grid, lock_delay)
|
self:lockPiece(piece, grid, lock_delay)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|||||||
@@ -18,6 +18,16 @@ SRS.spawn_positions = {
|
|||||||
Z = { x=4, y=5 },
|
Z = { x=4, y=5 },
|
||||||
}
|
}
|
||||||
|
|
||||||
|
SRS.big_spawn_positions = {
|
||||||
|
I = { x=2, y=2 },
|
||||||
|
J = { x=2, y=3 },
|
||||||
|
L = { x=2, y=3 },
|
||||||
|
O = { x=2, y=3 },
|
||||||
|
S = { x=2, y=3 },
|
||||||
|
T = { x=2, y=3 },
|
||||||
|
Z = { x=2, y=3 },
|
||||||
|
}
|
||||||
|
|
||||||
SRS.block_offsets = {
|
SRS.block_offsets = {
|
||||||
I={
|
I={
|
||||||
{ {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} },
|
{ {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} },
|
||||||
30
tetris/rulesets/standard_ti.lua
Normal file
30
tetris/rulesets/standard_ti.lua
Normal file
@@ -0,0 +1,30 @@
|
|||||||
|
local Standard = require 'tetris.rulesets.standard'
|
||||||
|
|
||||||
|
local SRS = Standard:extend()
|
||||||
|
|
||||||
|
SRS.name = "Ti-SRS"
|
||||||
|
SRS.hash = "StandardTI"
|
||||||
|
|
||||||
|
function SRS:onPieceMove(piece, grid)
|
||||||
|
piece.lock_delay = 0 -- move reset
|
||||||
|
if piece:isDropBlocked(grid) then
|
||||||
|
piece.move_counter = piece.move_counter + 1
|
||||||
|
if piece.move_counter >= 10 then
|
||||||
|
piece.locked = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function SRS:onPieceRotate(piece, grid)
|
||||||
|
piece.lock_delay = 0 -- rotate reset
|
||||||
|
if piece:isDropBlocked(grid) then
|
||||||
|
piece.rotate_counter = piece.rotate_counter + 1
|
||||||
|
if piece.rotate_counter >= 8 then
|
||||||
|
piece.locked = true
|
||||||
|
end
|
||||||
|
end
|
||||||
|
end
|
||||||
|
|
||||||
|
function SRS:get180RotationValue() return config["reverse_rotate"] and 1 or 3 end
|
||||||
|
|
||||||
|
return SRS
|
||||||
Reference in New Issue
Block a user