Compare commits

..

94 Commits

Author SHA1 Message Date
Ishaan Bhardwaj
57c7d9c4c3 v0.3-beta1: Sakura done 2021-01-04 18:01:29 -05:00
Ishaan Bhardwaj
9f52d8bf10 relocated non bgm to modpack 2021-01-04 14:43:39 -05:00
Ishaan Bhardwaj
57bd6a8286 Almost done with Sakura 2021-01-03 23:18:57 -05:00
Oshisaure
1a68cd8fce More work on sakura, Xray and colour block effects implemented. Added Grid:drawCustom() to handle custom opacity/tint effects. 2021-01-03 00:05:54 +00:00
Ishaan Bhardwaj
56baf46839 Sakura *should* be complete now, please bug-report 2021-01-02 14:31:53 -05:00
Ishaan Bhardwaj
305d07e10a Sakura beta v2.k 2021-01-02 14:10:01 -05:00
Ishaan Bhardwaj
8d954cabc2 Sakura Beta v2.j 2021-01-02 12:56:52 -05:00
Ishaan Bhardwaj
0281220ea0 Sakura Beta v2.i 2021-01-02 12:51:00 -05:00
Ishaan Bhardwaj
aef5d88d3f Sakura Beta v2.h 2021-01-02 12:36:26 -05:00
Ishaan Bhardwaj
3676f7697c Sakura Beta v2 2021-01-02 12:21:10 -05:00
Ishaan Bhardwaj
acb0eb1a71 Sakura mode beta 2020-12-30 15:19:53 -05:00
Ishaan Bhardwaj
a89bf05cab Fixed an issue with controllers on the menu 2020-12-29 22:55:51 -05:00
Ishaan Bhardwaj
8008315994 Condensed ARE canceling code a bit 2020-12-29 14:00:11 -05:00
Ishaan Bhardwaj
90f62cb7dd Refactored ARE cancel 2020-12-28 23:32:41 -05:00
Oshisaure
eaee5fc7f0 Tweaked rotation/manipulation behaviour on SRS rules.
Also changed order of operations to call onPieceRotate in Rulesets after actually rotating the piece.
2020-12-28 03:41:26 +00:00
Ishaan Bhardwaj
e3b038b5a7 A festive easter egg has arrived! (v0.2.6.1)
Good luck hunting for the egg!
2020-12-24 22:58:06 -05:00
Ishaan Bhardwaj
083693496e Grid piece placement conditions 2020-12-22 22:04:06 -05:00
Ishaan Bhardwaj
ba576dfc77 Allow sliders to be controlled with keyboard
Credits to Phoenix Flare
2020-12-22 14:43:59 -05:00
Ishaan Bhardwaj
e195ccd721 Marathon A3 fixes 2020-12-21 23:32:39 -05:00
Ishaan Bhardwaj
70f703eb2f Fixed piece fade out when paused 2020-12-21 16:20:25 -05:00
Ishaan Bhardwaj
dc4d4a8259 Credits now stops music when you exit the screen 2020-12-21 16:00:03 -05:00
Ishaan Bhardwaj
565510c7b2 Credits and credit roll music updated 2020-12-21 15:48:34 -05:00
Ishaan Bhardwaj
c26a3f37de Update README.md 2020-12-20 20:35:36 -05:00
Ishaan Bhardwaj
0c1ce2f717 Fix package script not packing slider lib 2020-12-20 20:06:16 -05:00
Ishaan Bhardwaj
f14ab2a328 BGM focus fix 2020-12-20 16:55:34 -05:00
Ishaan Bhardwaj
042dbd220b text was slightly off-center 2020-12-20 15:31:42 -05:00
Ishaan Bhardwaj
548612123a SFX and BGM are now separate sliders 2020-12-20 15:26:32 -05:00
Ishaan Bhardwaj
f4675da0b0 Unlock and fix BGM, add pause button 2020-12-20 15:08:53 -05:00
Ishaan Bhardwaj
511e9592bc Fixed next piece sounds not playing 2020-12-20 10:47:24 -05:00
Ishaan Bhardwaj
5f3990ff58 Small credits update 2020-12-20 10:35:05 -05:00
Ishaan Bhardwaj
50ff4adf27 Credits scene <3 2020-12-20 10:28:34 -05:00
Ishaan Bhardwaj
87b88f4b42 Refactored settings menus 2020-12-20 09:45:49 -05:00
Ishaan Bhardwaj
130c2ea403 Easier easter egg #2 2020-12-19 20:44:24 -05:00
Ishaan Bhardwaj
1ea304916e Made it easier to see the egg 2020-12-19 20:43:57 -05:00
Ishaan Bhardwaj
e26b094830 A little easter egg... 2020-12-19 20:31:14 -05:00
Ishaan Bhardwaj
bcb44725bf Cambridge RS fix lock in midair 2020-12-19 14:04:08 -05:00
Ishaan Bhardwaj
2990844c52 Adjusted tuning scene 2020-12-18 23:17:53 -05:00
Ishaan Bhardwaj
c343014d6f Tuning scene 2020-12-18 21:28:30 -05:00
Ishaan Bhardwaj
605add7e94 Added customizable DAS and ARR! (read comments)
This only applies to modes that allow it.
This feature does not apply to main modes (yet)
2020-12-18 21:25:09 -05:00
Ishaan Bhardwaj
d3b647ca71 Fixed certain rulesets locking in midair 2020-12-18 21:24:10 -05:00
Ishaan Bhardwaj
1101aa467d Smooth piece drop 2020-12-17 18:00:07 -05:00
Ishaan Bhardwaj
ce27a7ed18 Update Tetra Online README 2020-12-17 10:51:08 -05:00
Ishaan Bhardwaj
f31beffab8 Update release script 2020-12-16 22:47:56 -05:00
Ishaan Bhardwaj
2ff8fb5edc Modpack README update 2020-12-16 22:33:48 -05:00
Boshi
1bf8f91ef2 Displays current gamemode in game (toggle) 2020-12-16 22:21:26 -05:00
Ishaan Bhardwaj
ba5f78d5f1 Merge branch 'master' of https://github.com/sashlilac/cambridge 2020-12-14 22:44:16 -05:00
Ishaan Bhardwaj
f7c4908062 Added an option to disable diagonal input 2020-12-14 22:43:50 -05:00
Ishaan Bhardwaj
3aa5bae7be Tetra Online notice and stuff 2020-12-10 21:22:16 -05:00
Ishaan Bhardwaj
40a2e78280 Marathon 2020 section colour function fixed 2020-12-06 11:38:45 -05:00
Ishaan Bhardwaj
696da3fa3f Marathon 2020 colour function removed 2020-12-06 11:27:44 -05:00
Ishaan Bhardwaj
4afe9f2bd4 Major sound effect update (closes #7?)
Sound effects can still be changed, and #7 can still be reopened.
2020-12-05 20:30:59 -05:00
Ishaan Bhardwaj
1f686fb5d4 Ti-ARS: T can no longer floorkick the air 2020-12-05 18:32:06 -05:00
Ishaan Bhardwaj
f4779c9847 Added the ability to toggle next piece SFX 2020-12-05 17:32:15 -05:00
Ishaan Bhardwaj
06cbec4bc8 Guideline SRS kicks fixed 2020-12-05 17:15:28 -05:00
Ishaan Bhardwaj
668564ffb0 Revert "big a3! (but its buggy??)"
This reverts commit 513cd6ba90.
Hailey, please do not add modes.
2020-12-05 16:56:12 -05:00
Hailey
e6edeea3d1 Merge branch 'master' of https://github.com/SashLilac/cambridge 2020-12-05 12:50:45 +10:00
Hailey
513cd6ba90 big a3! (but its buggy??) 2020-12-05 12:49:57 +10:00
Ishaan Bhardwaj
1beef8f157 Guideline SRS has 180s now 2020-12-04 21:36:25 -05:00
Ishaan Bhardwaj
d3b2b4c2d9 Ruleset refactoring! 2020-12-04 20:36:11 -05:00
Ishaan Bhardwaj
2b8b9d5084 Reduced the sound volume a little bit. 2020-12-04 20:12:36 -05:00
Ishaan Bhardwaj
2728780c45 Raised the piece sound volume by a factor of 10. 2020-12-04 19:42:33 -05:00
Ishaan Bhardwaj
ca592a3bcf Changed piece sounds, added sound sources 2020-12-04 19:27:02 -05:00
Ishaan Bhardwaj
b6f4158d70 Fixed SRS infinity bug! 2020-12-04 16:51:53 -05:00
Ishaan Bhardwaj
e43f5c470a Renaming backgrounds 2020-12-04 16:32:29 -05:00
Ishaan Bhardwaj
7bcdc517c0 Revert "Merge pull request #11 from Rexxt/master"
Reverting this pull request for a few reasons:
The piece sounds were too quiet.
The piece landing sound was distasteful.
2020-12-04 16:22:22 -05:00
Ishaan Bhardwaj
1d30987f9a Merge pull request #11 from Rexxt/master
Uncopyrightening and making the game slightly friendlier to mod
2020-12-04 16:13:38 -05:00
Ishaan Bhardwaj
1dd46a11ef Fixed torikans giving you a green line 2020-12-04 15:41:44 -05:00
Ishaan Bhardwaj
935c7aa14c Default secret grade names 2020-12-04 15:16:13 -05:00
Ishaan Bhardwaj
aea115d953 ACE-SRS has correct number of resets 2020-12-04 11:22:32 -05:00
Ishaan Bhardwaj
3d5b33f41a Added ability to enable/disable synchroes
On by default in anything but world rulesets.
Gamemodes / rulesets can override this setting.
2020-12-04 10:57:43 -05:00
Mizu
29f07bb6ab Update piece sounds 2020-12-04 15:38:34 +01:00
Ishaan Bhardwaj
891f96e814 I broke the DAS switch functionality 2020-12-03 14:10:46 -05:00
Ishaan Bhardwaj
36837a3af5 Update main.lua 2020-12-03 13:45:23 -05:00
Ishaan Bhardwaj
01b0f9f618 DAS switch behavior implemented 2020-12-02 21:09:52 -05:00
Ishaan Bhardwaj
7c8c5bb11d Hide hold queue when hold is disabled 2020-12-02 13:41:47 -05:00
Ishaan Bhardwaj
acaa6bdbbf whoops forgot to not require socket 2020-12-01 11:58:29 -05:00
Ishaan Bhardwaj
c37757f592 Implement an axis timer (fixes #12) 2020-12-01 11:57:09 -05:00
Ishaan Bhardwaj
905e4bcc77 drawSectionTimesWithSecondary update 2020-12-01 11:56:44 -05:00
Ishaan Bhardwaj
d956647678 Core mode rebalancing 2020-12-01 11:56:28 -05:00
Ishaan Bhardwaj
10f032b49b Added more functionality to advanceOneFrame 2020-11-30 12:34:21 -05:00
Ishaan Bhardwaj
5590e6c89b Small DAS changes 2020-11-29 11:11:47 -05:00
Joe Z
0393396d74 Made instant DAS respect instant gravity. 2020-11-29 09:19:17 -05:00
Joe Zeng
8c1eaec1aa DAS priority reversal (#25)
* Reversed the priority of key presses when charging DAS.
* Made it an actual config option.
* Config should be false by default.
2020-11-28 23:29:46 -05:00
Ishaan Bhardwaj
957802a78e Fixed a minor bug in the scope of SA2's line 2020-11-27 23:21:59 -05:00
Ishaan Bhardwaj
169a4e4d2f AX4 no longer shows timer in the roll 2020-11-22 10:39:42 -05:00
Ishaan Bhardwaj
48aee18340 Fix I wallkicks in ARS rules 2020-11-21 23:29:06 -05:00
Ishaan Bhardwaj
7b496d9412 Ti and ACE floorkick fix 2020-11-21 21:48:45 -05:00
Ishaan Bhardwaj
7abb861446 Hard drop can ARE cancel now 2020-11-21 16:29:24 -05:00
Ishaan Bhardwaj
21f8769228 Made ARE canceling also cancel LCD 2020-11-20 11:29:46 -05:00
Ishaan Bhardwaj
44423fd2e8 Made ARE canceling less slippery (again) 2020-11-19 22:22:43 -05:00
Mizu
6d326a142c Update some sounds (not the pieces 2020-11-11 18:38:45 +01:00
Mizu
b6f1072587 Merge branch 'master' of https://github.com/Rexxt/cambridge 2020-11-11 17:43:53 +01:00
Mizu
eef04ebf05 Update graphic names and SOURCES.md 2020-11-11 17:42:48 +01:00
Mizu
e24737a3b8 Merge pull request #1 from SashLilac/master
Update fork
2020-11-11 17:17:22 +01:00
87 changed files with 1536 additions and 772 deletions

View File

@@ -1,5 +1,10 @@
![Cambridge Banner](https://cdn.discordapp.com/attachments/764432435802013709/767724895076614154/cambridge_logo_lt.png)
Important notice
================
![Tetra Online Notice](https://pbs.twimg.com/media/Eo3CkIHW8AEoK_U?format=png&name=small)
Cambridge
=========
@@ -42,7 +47,7 @@ You do not need LÖVE on Windows, as it comes bundled with the program.
To get the stable release, simply download the ZIP in the latest release. All assets needed are bundled with the executable.
If you want the bleeding edge version, or want mod pack support, download [this](https://github.com/SashLilac/cambridge/archive/master.zip).
If you want the bleeding edge version, download [this](https://github.com/SashLilac/cambridge/archive/master.zip).
Extract the ZIP, open a Command Prompt at the folder you extracted Cambridge to, then run this command:
@@ -74,9 +79,11 @@ It should run automatically!
## Installing modpacks
Simply drag your mode, ruleset, and randomizer Lua files into their respective directory, and they should appear automatically.
Simply drag your mode, ruleset, and randomizer Lua files into their respective [directory](https://love2d.org/wiki/love.filesystem), and they should appear automatically.
Alternatively, install [this](https://github.com/SashLilac/cambridge-modpack) mod pack to get a taste of the mod potential.
**WARNING:** The .exe / .love files and the bleeding edge releases have different save directories. Read the above link carefully!
For more detailed instructions, install [this](https://github.com/SashLilac/cambridge-modpack) mod pack to get a taste of the mod potential.
License
-------

View File

@@ -8,7 +8,7 @@ Some of the assets are used without proper licenses. We aim to have fully licens
Backgrounds
-----------
1. Title: "Motus Glacies." Contributed by Daniel "Explo" McCarthy.
1. Title: Original picrute found on the Wikipedia article for Cambridge
1. *Gameplay level 0: "Quantum foam." Alex Sukontsev. https://www.flickr.com/photos/control9/14957509814/
2. *Gameplay level 1: No name. http://www.onekind.tv/univision-mqb/q5mqh5brlvuuj2nhdx7ch7eum183uu
@@ -34,10 +34,18 @@ Backgrounds
Backgrounds marked with a * are placeholders that will be replaced in later versions due to incompatible licenses. We are generally aiming for public domain background images, but will also accept backgrounds given proper licenses to be included within Cambridge.
Sounds
------
All piece sounds are (c) 2020 Damian Yerrick.
Other sounds from:
- NullpoMino
- DTET, (c) 2003 Mihys.
Music
-----
1. TGM3 credit roll music.
1. Second Reality opening scene music (1993).
2. The FitnessGram™ Pacer Test.
All background music is (currently) only unofficially included. In later releases they may be replaced with specifically licensed music as applicable.
@@ -106,3 +114,29 @@ Permission is hereby granted, free of charge, to any person obtaining a copy of
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
simple-slider (https://love2d.org/forums/viewtopic.php?t=80711)
--------------------
Copyright (c) 2016 George Prosser
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.

138
libs/simple-slider.lua Normal file
View File

@@ -0,0 +1,138 @@
--[[
Copyright (c) 2016 George Prosser
Permission is hereby granted, free of charge, to any person
obtaining a copy of this software and associated documentation
files (the "Software"), to deal in the Software without
restriction, including without limitation the rights to use,
copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the
Software is furnished to do so, subject to the following
conditions:
The above copyright notice and this permission notice shall be
included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES
OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT
HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY,
WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
OTHER DEALINGS IN THE SOFTWARE.
]]
local slider = {}
slider.__index = slider
function newSlider(x, y, length, value, min, max, setter, style)
local s = {}
s.value = (value - min) / (max - min)
s.min = min
s.max = max
s.setter = setter
s.x = x
s.y = y
s.length = length
local p = style or {}
s.width = p.width or length * 0.1
s.orientation = p.orientation or 'horizontal'
s.track = p.track or 'rectangle'
s.knob = p.knob or 'rectangle'
s.grabbed = false
s.wasDown = true
s.ox = 0
s.oy = 0
return setmetatable(s, slider)
end
function slider:update(mouseX, mouseY, mouseDown)
local x = mouseX or love.mouse.getX()
local y = mouseY or love.mouse.getY()
local down = love.mouse.isDown(1)
if mouseDown ~= nil then
down = mouseDown
end
local knobX = self.x
local knobY = self.y
if self.orientation == 'horizontal' then
knobX = self.x - self.length/2 + self.length * self.value
elseif self.orientation == 'vertical' then
knobY = self.y + self.length/2 - self.length * self.value
end
local ox = x - knobX
local oy = y - knobY
local dx = ox - self.ox
local dy = oy - self.oy
if down then
if self.grabbed then
if self.orientation == 'horizontal' then
self.value = self.value + dx / self.length
elseif self.orientation == 'vertical' then
self.value = self.value - dy / self.length
end
elseif (x > knobX - self.width/2 and x < knobX + self.width/2 and y > knobY - self.width/2 and y < knobY + self.width/2) and not self.wasDown then
self.ox = ox
self.oy = oy
self.grabbed = true
end
else
self.grabbed = false
end
self.value = math.max(0, math.min(1, self.value))
if self.setter ~= nil then
self.setter(self.min + self.value * (self.max - self.min))
end
self.wasDown = down
end
function slider:draw()
if self.track == 'rectangle' then
if self.orientation == 'horizontal' then
love.graphics.rectangle('line', self.x - self.length/2 - self.width/2, self.y - self.width/2, self.length + self.width, self.width)
elseif self.orientation == 'vertical' then
love.graphics.rectangle('line', self.x - self.width/2, self.y - self.length/2 - self.width/2, self.width, self.length + self.width)
end
elseif self.track == 'line' then
if self.orientation == 'horizontal' then
love.graphics.line(self.x - self.length/2, self.y, self.x + self.length/2, self.y)
elseif self.orientation == 'vertical' then
love.graphics.line(self.x, self.y - self.length/2, self.x, self.y + self.length/2)
end
elseif self.track == 'roundrect' then
if self.orientation == 'horizontal' then
love.graphics.rectangle('line', self.x - self.length/2 - self.width/2, self.y - self.width/2, self.length + self.width, self.width, self.width/2, self.width)
elseif self.orientation == 'vertical' then
love.graphics.rectangle('line', self.x - self.width/2, self.y - self.length/2 - self.width/2, self.width, self.length + self.width, self.width, self.width/2)
end
end
local knobX = self.x
local knobY = self.y
if self.orientation == 'horizontal' then
knobX = self.x - self.length/2 + self.length * self.value
elseif self.orientation == 'vertical' then
knobY = self.y + self.length/2 - self.length * self.value
end
if self.knob == 'rectangle' then
love.graphics.rectangle('fill', knobX - self.width/2, knobY - self.width/2, self.width, self.width)
elseif self.knob == 'circle' then
love.graphics.circle('fill', knobX, knobY, self.width/2)
end
end
function slider:getValue()
return self.min + self.value * (self.max - self.min)
end

View File

@@ -6,7 +6,7 @@ bgm = {
}
local current_bgm = nil
local bgm_locked = true
local bgm_locked = false
function switchBGM(sound, subsound)
if bgm_locked then return end
@@ -47,7 +47,7 @@ function fadeoutBGM(time)
end
function resetBGMFadeout(time)
current_bgm:setVolume(1)
current_bgm:setVolume(config.bgm_volume)
fading_bgm = false
current_bgm:play()
end
@@ -59,7 +59,7 @@ function processBGMFadeout(dt)
fadeout_time = 0
fading_bgm = false
end
current_bgm:setVolume(fadeout_time / total_fadeout_time)
current_bgm:setVolume(fadeout_time * config.bgm_volume / total_fadeout_time)
end
end

View File

@@ -1,27 +1,28 @@
backgrounds = {
[0] = love.graphics.newImage("res/backgrounds/0-quantum-foam.png"),
love.graphics.newImage("res/backgrounds/100-big-bang.png"),
love.graphics.newImage("res/backgrounds/200-spiral-galaxy.png"),
love.graphics.newImage("res/backgrounds/300-sun-and-dust.png"),
love.graphics.newImage("res/backgrounds/400-earth-and-moon.png"),
love.graphics.newImage("res/backgrounds/500-cambrian-explosion.png"),
love.graphics.newImage("res/backgrounds/600-dinosaurs.png"),
love.graphics.newImage("res/backgrounds/700-asteroid.png"),
love.graphics.newImage("res/backgrounds/800-human-fire.png"),
love.graphics.newImage("res/backgrounds/900-early-civilization.png"),
love.graphics.newImage("res/backgrounds/1000-vikings.png"),
love.graphics.newImage("res/backgrounds/1100-crusades.png"),
love.graphics.newImage("res/backgrounds/1200-genghis-khan.png"),
love.graphics.newImage("res/backgrounds/1300-black-death.png"),
love.graphics.newImage("res/backgrounds/1400-columbus-discovery.png"),
love.graphics.newImage("res/backgrounds/1500-aztecas.png"),
love.graphics.newImage("res/backgrounds/1600-telescope.png"),
love.graphics.newImage("res/backgrounds/1700-american-revolution.png"),
love.graphics.newImage("res/backgrounds/1800-railways.png"),
love.graphics.newImage("res/backgrounds/1900-world-wide-web.png"),
title = love.graphics.newImage("res/backgrounds/title_v0.1.png"),
input_config = love.graphics.newImage("res/backgrounds/options-pcb.png"),
game_config = love.graphics.newImage("res/backgrounds/options-gears.png"),
[0] = love.graphics.newImage("res/backgrounds/0.png"),
love.graphics.newImage("res/backgrounds/100.png"),
love.graphics.newImage("res/backgrounds/200.png"),
love.graphics.newImage("res/backgrounds/300.png"),
love.graphics.newImage("res/backgrounds/400.png"),
love.graphics.newImage("res/backgrounds/500.png"),
love.graphics.newImage("res/backgrounds/600.png"),
love.graphics.newImage("res/backgrounds/700.png"),
love.graphics.newImage("res/backgrounds/800.png"),
love.graphics.newImage("res/backgrounds/900.png"),
love.graphics.newImage("res/backgrounds/1000.png"),
love.graphics.newImage("res/backgrounds/1100.png"),
love.graphics.newImage("res/backgrounds/1200.png"),
love.graphics.newImage("res/backgrounds/1300.png"),
love.graphics.newImage("res/backgrounds/1400.png"),
love.graphics.newImage("res/backgrounds/1500.png"),
love.graphics.newImage("res/backgrounds/1600.png"),
love.graphics.newImage("res/backgrounds/1700.png"),
love.graphics.newImage("res/backgrounds/1800.png"),
love.graphics.newImage("res/backgrounds/1900.png"),
title = love.graphics.newImage("res/backgrounds/title.png"),
snow = love.graphics.newImage("res/backgrounds/snow.png"),
input_config = love.graphics.newImage("res/backgrounds/options-input.png"),
game_config = love.graphics.newImage("res/backgrounds/options-game.png"),
}
blocks = {
@@ -48,6 +49,18 @@ blocks = {
F = love.graphics.newImage("res/img/bone.png"),
A = love.graphics.newImage("res/img/bone.png"),
X = love.graphics.newImage("res/img/bone.png"),
},
["gem"] = {
R = love.graphics.newImage("res/img/gem1.png"),
O = love.graphics.newImage("res/img/gem3.png"),
Y = love.graphics.newImage("res/img/gem7.png"),
G = love.graphics.newImage("res/img/gem6.png"),
C = love.graphics.newImage("res/img/gem2.png"),
B = love.graphics.newImage("res/img/gem4.png"),
M = love.graphics.newImage("res/img/gem5.png"),
F = love.graphics.newImage("res/img/gem9.png"),
A = love.graphics.newImage("res/img/gem9.png"),
X = love.graphics.newImage("res/img/gem9.png"),
}
}
@@ -84,4 +97,5 @@ misc_graphics = {
go = love.graphics.newImage("res/img/go.png"),
select_mode = love.graphics.newImage("res/img/select_mode.png"),
strike = love.graphics.newImage("res/img/strike.png"),
santa = love.graphics.newImage("res/img/santa.png")
}

View File

@@ -20,17 +20,21 @@ sounds = {
fall = love.audio.newSource("res/se/fall.wav", "static"),
ready = love.audio.newSource("res/se/ready.wav", "static"),
go = love.audio.newSource("res/se/go.wav", "static"),
irs = love.audio.newSource("res/se/irs.wav", "static"),
ihs = love.audio.newSource("res/se/ihs.wav", "static"),
-- a secret sound!
welcome = love.audio.newSource("res/se/welcomeToCambridge.wav", "static"),
}
function playSE(sound, subsound)
if subsound == nil then
sounds[sound]:setVolume(0.5)
sounds[sound]:setVolume(config.sfx_volume)
if sounds[sound]:isPlaying() then
sounds[sound]:stop()
end
sounds[sound]:play()
else
sounds[sound][subsound]:setVolume(0.1)
sounds[sound][subsound]:setVolume(config.sfx_volume)
if sounds[sound][subsound]:isPlaying() then
sounds[sound][subsound]:stop()
end
@@ -40,13 +44,13 @@ end
function playSEOnce(sound, subsound)
if subsound == nil then
sounds[sound]:setVolume(0.5)
sounds[sound]:setVolume(config.sfx_volume)
if sounds[sound]:isPlaying() then
return
end
sounds[sound]:play()
else
sounds[sound][subsound]:setVolume(0.5)
sounds[sound][subsound]:setVolume(config.sfx_volume)
if sounds[sound][subsound]:isPlaying() then
return
end

View File

@@ -9,13 +9,26 @@ function love.load()
require "load.save"
loadSave()
require "scene"
config["side_next"] = false
config["reverse_rotate"] = true
--config["side_next"] = false
--config["reverse_rotate"] = true
config["fullscreen"] = false
love.window.setMode(love.graphics.getWidth(), love.graphics.getHeight(), {resizable = true});
if not config.gamesettings then config.gamesettings = {} end
if not config.das then config.das = 10 end
if not config.arr then config.arr = 2 end
if not config.sfx_volume then config.sfx_volume = 0.5 end
if not config.bgm_volume then config.bgm_volume = 0.5 end
if config.secret == nil then config.secret = false
elseif config.secret == true then playSE("welcome") end
if not config.gamesettings then
config.gamesettings = {}
config["das_last_key"] = false
else
config["das_last_key"] = config.gamesettings.das_last_key == 2
end
for _, option in ipairs(GameConfigScene.options) do
if not config.gamesettings[option[1]] then
config.gamesettings[option[1]] = 1
@@ -116,6 +129,14 @@ function love.keypressed(key, scancode)
love.window.setFullscreen(config["fullscreen"])
elseif scancode == "f2" and scene.title ~= "Input Config" and scene.title ~= "Game" then
scene = InputConfigScene()
switchBGM(nil)
-- secret sound playing :eyes:
elseif scancode == "f8" and scene.title == "Title" then
config.secret = not config.secret
saveConfig()
scene.restart_message = true
if config.secret then playSE("mode_decide")
else playSE("erase") end
-- function keys are reserved
elseif string.match(scancode, "^f[1-9]$") or string.match(scancode, "^f[1-9][0-9]+$") then
return
@@ -231,7 +252,7 @@ function love.joystickhat(joystick, hat, direction)
end
function love.focus(f)
if f then
if f and (scene.title ~= "Game" or not scene.paused) then
resumeBGM()
else
pauseBGM()

View File

@@ -1,2 +1,2 @@
tar -a -c -f cambridge.zip libs/binser.lua libs/classic.lua libs/discordRPC.lua load res scene tetris conf.lua main.lua scene.lua funcs.lua
tar -a -c -f cambridge.zip libs/binser.lua libs/classic.lua libs/simple-slider.lua libs/discordRPC.lua load res scene tetris conf.lua main.lua scene.lua funcs.lua
rename cambridge.zip cambridge.love

View File

@@ -4,6 +4,6 @@ mkdir dist/windows
mkdir dist/win32
cp cambridge.love dist/
cat dist/windows/love.exe cambridge.love > dist/windows/cambridge.exe
zip dist/cambridge-windows.zip dist/windows/* SOURCES.md LICENSE
zip dist/cambridge-windows.zip dist/windows/* SOURCES.md LICENSE.md
cat dist/win32/love.exe cambridge.love > dist/win32/cambridge.exe
zip dist/cambridge-win32.zip dist/win32/* SOURCES.md LICENSE
zip dist/cambridge-win32.zip dist/win32/* SOURCES.md LICENSE.md

View File

Before

Width:  |  Height:  |  Size: 2.4 MiB

After

Width:  |  Height:  |  Size: 2.4 MiB

View File

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.9 MiB

After

Width:  |  Height:  |  Size: 2.9 MiB

View File

Before

Width:  |  Height:  |  Size: 2.1 MiB

After

Width:  |  Height:  |  Size: 2.1 MiB

View File

Before

Width:  |  Height:  |  Size: 1.4 MiB

After

Width:  |  Height:  |  Size: 1.4 MiB

View File

Before

Width:  |  Height:  |  Size: 2.6 MiB

After

Width:  |  Height:  |  Size: 2.6 MiB

View File

Before

Width:  |  Height:  |  Size: 2.1 MiB

After

Width:  |  Height:  |  Size: 2.1 MiB

View File

Before

Width:  |  Height:  |  Size: 2.1 MiB

After

Width:  |  Height:  |  Size: 2.1 MiB

View File

Before

Width:  |  Height:  |  Size: 2.1 MiB

After

Width:  |  Height:  |  Size: 2.1 MiB

View File

Before

Width:  |  Height:  |  Size: 2.4 MiB

After

Width:  |  Height:  |  Size: 2.4 MiB

View File

Before

Width:  |  Height:  |  Size: 1.9 MiB

After

Width:  |  Height:  |  Size: 1.9 MiB

View File

Before

Width:  |  Height:  |  Size: 1.6 MiB

After

Width:  |  Height:  |  Size: 1.6 MiB

View File

Before

Width:  |  Height:  |  Size: 1.7 MiB

After

Width:  |  Height:  |  Size: 1.7 MiB

View File

Before

Width:  |  Height:  |  Size: 2.0 MiB

After

Width:  |  Height:  |  Size: 2.0 MiB

View File

Before

Width:  |  Height:  |  Size: 2.1 MiB

After

Width:  |  Height:  |  Size: 2.1 MiB

View File

Before

Width:  |  Height:  |  Size: 3.1 MiB

After

Width:  |  Height:  |  Size: 3.1 MiB

View File

Before

Width:  |  Height:  |  Size: 1.2 MiB

After

Width:  |  Height:  |  Size: 1.2 MiB

View File

Before

Width:  |  Height:  |  Size: 2.7 MiB

After

Width:  |  Height:  |  Size: 2.7 MiB

View File

Before

Width:  |  Height:  |  Size: 3.6 MiB

After

Width:  |  Height:  |  Size: 3.6 MiB

View File

Before

Width:  |  Height:  |  Size: 2.9 MiB

After

Width:  |  Height:  |  Size: 2.9 MiB

View File

Before

Width:  |  Height:  |  Size: 3.0 MiB

After

Width:  |  Height:  |  Size: 3.0 MiB

BIN
res/backgrounds/snow.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 1.7 MiB

View File

Before

Width:  |  Height:  |  Size: 1.3 MiB

After

Width:  |  Height:  |  Size: 1.3 MiB

Binary file not shown.

BIN
res/img/gem1.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 462 B

BIN
res/img/gem2.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 388 B

BIN
res/img/gem3.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 445 B

BIN
res/img/gem4.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 426 B

BIN
res/img/gem5.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 376 B

BIN
res/img/gem6.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 377 B

BIN
res/img/gem7.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 399 B

BIN
res/img/gem9.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 354 B

BIN
res/img/santa.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 75 KiB

Binary file not shown.

Binary file not shown.

BIN
res/se/ihs.wav Normal file

Binary file not shown.

BIN
res/se/irs.wav Normal file

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@@ -13,4 +13,7 @@ GameScene = require "scene.game"
ModeSelectScene = require "scene.mode_select"
InputConfigScene = require "scene.input_config"
GameConfigScene = require "scene.game_config"
TuningScene = require "scene.tuning"
SettingsScene = require "scene.settings"
CreditsScene = require "scene.credits"
TitleScene = require "scene.title"

62
scene/credits.lua Normal file
View File

@@ -0,0 +1,62 @@
local CreditsScene = Scene:extend()
CreditsScene.title = "Credits"
function CreditsScene:new()
self.frames = 0
switchBGM("credit_roll", "gm3")
end
function CreditsScene:update()
self.frames = self.frames + 1
if self.frames >= 4200 then
playSE("mode_decide")
scene = TitleScene()
switchBGM(nil)
elseif self.frames == 3600 then
fadeoutBGM(2)
end
end
function CreditsScene:render()
love.graphics.setColor(1, 1, 1, 1)
love.graphics.draw(
backgrounds[19],
0, 0, 0,
0.5, 0.5
)
love.graphics.setFont(font_3x5_4)
love.graphics.print("Cambridge Credits", 320, 500 - self.frames / 2)
love.graphics.print("THANK YOU\nFOR PLAYING!", 320, math.max(1500 - self.frames / 2, 240))
love.graphics.setFont(font_3x5_3)
love.graphics.print("Game Developers", 320, 550 - self.frames / 2)
love.graphics.print("Project Heads", 320, 640 - self.frames / 2)
love.graphics.print("Other Game Developers", 320, 730 - self.frames / 2)
love.graphics.print("Special Thanks", 320, 900 - self.frames / 2)
love.graphics.print("- SashLilac / SpinTriple", 320, math.max(2000 - self.frames / 2, 320))
love.graphics.setFont(font_3x5_2)
love.graphics.print("Oshisaure\nJoe Zeng", 320, 590 - self.frames / 2)
love.graphics.print("Mizu\nHailey", 320, 680 - self.frames / 2)
love.graphics.print("Axel Fox - Multimino\nMine - Tetra Online\nDr Ocelot - Tetra Legends\nFelicity / nightmareci - Shiromino\n2Tie - TGMsim\nPhoenix Flare - Master of Blocks", 320, 770 - self.frames / 2)
love.graphics.print(
"RocketLanterns\nCylinderKnot\nHammrTime\nKirby703\nMattMayuga\nMyPasswordIsWeak\n" ..
"Nikki Karissa\noffwo\nsinefuse\nTetro48\nTimmSkiller\nuser74003\nAgentBasey\n" ..
"CheeZed_Fish\neightsixfivezero\nEricICX\ngizmo4487\nM1ssing0\nMarkGamed7794\n" ..
"pokemonfan1937\nSimon\nstratus\nZaptorZap\nThe Absolute PLUS Discord\nTetra Legends Discord\n" ..
"Tetra Online Discord\nMultimino Discord\nCambridge Discord\nAnd to you, the player!",
320, 940 - self.frames / 2
)
end
function CreditsScene:onInputPress(e)
if e.input == "menu_decide" or e.scancode == "return" or
e.input == "menu_back" or e.scancode == "delete" or e.scancode == "backspace" then
scene = TitleScene()
switchBGM(nil)
end
end
return CreditsScene

View File

@@ -22,6 +22,7 @@ function GameScene:new(game_mode, ruleset)
rotate_180=false,
hold=false,
}
self.paused = false
DiscordRPC:update({
details = self.game.rpc_details,
state = self.game.name,
@@ -29,15 +30,14 @@ function GameScene:new(game_mode, ruleset)
end
function GameScene:update()
if love.window.hasFocus() then
if love.window.hasFocus() and not self.paused then
local inputs = {}
for input, value in pairs(self.inputs) do
inputs[input] = value
end
self.game:update(inputs, self.ruleset)
self.game.grid:update()
end
self.game.grid:update()
end
function GameScene:render()
@@ -68,6 +68,13 @@ function GameScene:render()
self.game:drawCustom()
love.graphics.setFont(font_3x5_2)
if config.gamesettings.display_gamemode == 1 then
love.graphics.printf(self.game.name .. " - " .. self.ruleset.name, 0, 460, 640, "left")
end
love.graphics.setFont(font_3x5_3)
if self.paused then love.graphics.print("PAUSED!", 80, 100) end
end
function GameScene:onInputPress(e)
@@ -78,6 +85,10 @@ function GameScene:onInputPress(e)
scene = e.input == "retry" and GameScene(self.retry_mode, self.retry_ruleset) or ModeSelectScene()
elseif e.input == "retry" then
scene = GameScene(self.retry_mode, self.retry_ruleset)
elseif e.input == "pause" and not (self.game.game_over or self.game.completed) then
self.paused = not self.paused
if self.paused then pauseBGM()
else resumeBGM() end
elseif e.input == "menu_back" then
scene = ModeSelectScene()
elseif e.input and string.sub(e.input, 1, 5) ~= "menu_" then

View File

@@ -3,12 +3,21 @@ local ConfigScene = Scene:extend()
ConfigScene.title = "Game Settings"
require 'load.save'
require 'libs.simple-slider'
ConfigScene.options = {
-- this serves as reference to what the options' values mean i guess?
{"manlock", "Manual locking",{"Per ruleset","Per gamemode","Harddrop", "Softdrop"}},
{"piece_colour", "Piece Colours", {"Per ruleset","Arika" ,"TTC"}},
{"world_reverse","A Button Rotation", {"Left" ,"Auto" ,"Right"}},
-- Format: {name in config, displayed name, uses slider?, options OR slider name}
{"manlock", "Manual Locking", false, {"Per ruleset", "Per gamemode", "Harddrop", "Softdrop"}},
{"piece_colour", "Piece Colours", false, {"Per ruleset", "Arika", "TTC"}},
{"world_reverse", "A Button Rotation", false, {"Left", "Auto", "Right"}},
{"display_gamemode", "Display Gamemode", false, {"On", "Off"}},
{"das_last_key", "DAS Switch", false, {"Default", "Instant"}},
{"smooth_movement", "Smooth Piece Drop", false, {"On", "Off"}},
{"synchroes_allowed", "Synchroes", false, {"Per ruleset", "On", "Off"}},
{"diagonal_input", "Diagonal Input", false, {"On", "Off"}},
{"sfx_volume", "SFX", true, "sfxSlider"},
{"bgm_volume", "BGM", true, "bgmSlider"},
}
local optioncount = #ConfigScene.options
@@ -21,9 +30,15 @@ function ConfigScene:new()
details = "In menus",
state = "Changing game settings",
})
self.sfxSlider = newSlider(165, 375, 225, config.sfx_volume * 100, 0, 100, function(v) config.sfx_volume = v / 100 end, {width=20})
self.bgmSlider = newSlider(465, 375, 225, config.bgm_volume * 100, 0, 100, function(v) config.bgm_volume = v / 100 end, {width=20})
end
function ConfigScene:update()
config["das_last_key"] = config.gamesettings.das_last_key == 2
self.sfxSlider:update()
self.bgmSlider:update()
end
function ConfigScene:render()
@@ -33,29 +48,45 @@ function ConfigScene:render()
0, 0, 0,
0.5, 0.5
)
love.graphics.setFont(font_3x5_4)
love.graphics.print("GAME SETTINGS", 80, 40)
--Lazy check to see if we're on the SFX or BGM slider. Probably will need to be rewritten if more options get added.
love.graphics.setColor(1, 1, 1, 0.5)
love.graphics.rectangle("fill", 20, 98 + self.highlight * 20, 170, 22)
if not ConfigScene.options[self.highlight][3] then
love.graphics.rectangle("fill", 20, 98 + self.highlight * 20, 170, 22)
else
love.graphics.rectangle("fill", 65 + (1+self.highlight-#self.options) * 300, 322, 215, 33)
end
love.graphics.setFont(font_3x5_2)
for i, option in ipairs(ConfigScene.options) do
love.graphics.setColor(1, 1, 1, 1)
love.graphics.printf(option[2], 40, 100 + i * 20, 150, "left")
for j, setting in ipairs(option[3]) do
love.graphics.setColor(1, 1, 1, config.gamesettings[option[1]] == j and 1 or 0.5)
love.graphics.printf(setting, 100 + 110 * j, 100 + i * 20, 100, "center")
if not option[3] then
love.graphics.setColor(1, 1, 1, 1)
love.graphics.printf(option[2], 40, 100 + i * 20, 150, "left")
for j, setting in ipairs(option[4]) do
love.graphics.setColor(1, 1, 1, config.gamesettings[option[1]] == j and 1 or 0.5)
love.graphics.printf(setting, 100 + 110 * j, 100 + i * 20, 100, "center")
end
end
end
love.graphics.setColor(1, 1, 1, 1)
love.graphics.setFont(font_3x5_3)
love.graphics.print("SFX Volume: " .. math.floor(self.sfxSlider:getValue()) .. "%", 75, 325)
love.graphics.print("BGM Volume: " .. math.floor(self.bgmSlider:getValue()) .. "%", 375, 325)
love.graphics.setColor(1, 1, 1, 0.75)
self.sfxSlider:draw()
self.bgmSlider:draw()
end
function ConfigScene:onInputPress(e)
if e.input == "menu_decide" or e.scancode == "return" then
playSE("mode_decide")
saveConfig()
scene = TitleScene()
scene = SettingsScene()
elseif e.input == "up" or e.scancode == "up" then
playSE("cursor")
self.highlight = Mod1(self.highlight-1, optioncount)
@@ -63,16 +94,28 @@ function ConfigScene:onInputPress(e)
playSE("cursor")
self.highlight = Mod1(self.highlight+1, optioncount)
elseif e.input == "left" or e.scancode == "left" then
playSE("cursor_lr")
local option = ConfigScene.options[self.highlight]
config.gamesettings[option[1]] = Mod1(config.gamesettings[option[1]]-1, #option[3])
if not self.options[self.highlight][3] then
playSE("cursor_lr")
local option = ConfigScene.options[self.highlight]
config.gamesettings[option[1]] = Mod1(config.gamesettings[option[1]]-1, #option[4])
else
playSE("cursor")
sld = self[self.options[self.highlight][4]]
sld.value = math.max(sld.min, math.min(sld.max, (sld:getValue() - 3) / (sld.max - sld.min)))
end
elseif e.input == "right" or e.scancode == "right" then
playSE("cursor_lr")
local option = ConfigScene.options[self.highlight]
config.gamesettings[option[1]] = Mod1(config.gamesettings[option[1]]+1, #option[3])
if not self.options[self.highlight][3] then
playSE("cursor_lr")
local option = ConfigScene.options[self.highlight]
config.gamesettings[option[1]] = Mod1(config.gamesettings[option[1]]+1, #option[4])
else
playSE("cursor")
sld = self[self.options[self.highlight][4]]
sld.value = math.max(sld.min, math.min(sld.max, (sld:getValue() + 3) / (sld.max - sld.min)))--math.max(0, (math.floor(sld:getValue())+2)/(sld.max-sld.min))
end
elseif e.input == "menu_back" or e.scancode == "delete" or e.scancode == "backspace" then
loadSave()
scene = TitleScene()
scene = SettingsScene()
end
end

View File

@@ -18,6 +18,7 @@ local configurable_inputs = {
"rotate_180",
"hold",
"retry",
"pause",
}
local function newSetInputs()
@@ -32,6 +33,7 @@ function ConfigScene:new()
self.input_state = 1
self.set_inputs = newSetInputs()
self.new_input = {}
self.axis_timer = 0
DiscordRPC:update({
details = "In menus",
@@ -63,6 +65,8 @@ function ConfigScene:render()
love.graphics.print("press key or joystick input for " .. configurable_inputs[self.input_state] .. ", tab to skip" .. (config.input and ", escape to cancel" or ""), 0, 0)
love.graphics.print("function keys (F1, F2, etc.), escape, and tab can't be changed", 0, 20)
end
self.axis_timer = self.axis_timer + 1
end
local function addJoystick(input, name)
@@ -79,7 +83,7 @@ function ConfigScene:onInputPress(e)
-- function keys, escape, and tab are reserved and can't be remapped
if e.scancode == "escape" and config.input then
-- cancel only if there was an input config already
scene = TitleScene()
scene = SettingsScene()
elseif self.input_state > table.getn(configurable_inputs) then
if e.scancode == "return" then
-- save new input, then load next scene
@@ -118,7 +122,7 @@ function ConfigScene:onInputPress(e)
self.new_input.joysticks[e.name].buttons[e.button] = configurable_inputs[self.input_state]
self.input_state = self.input_state + 1
elseif e.type == "joyaxis" then
if math.abs(e.value) >= 0.5 then
if (e.axis ~= self.last_axis or self.axis_timer > 30) and math.abs(e.value) >= 1 then
addJoystick(self.new_input, e.name)
if not self.new_input.joysticks[e.name].axes then
self.new_input.joysticks[e.name].axes = {}
@@ -128,10 +132,12 @@ function ConfigScene:onInputPress(e)
end
self.set_inputs[configurable_inputs[self.input_state]] =
"jaxis " ..
(e.value >= 0.5 and "+" or "-") .. e.axis ..
(e.value >= 1 and "+" or "-") .. e.axis ..
" " .. string.sub(e.name, 1, 10) .. (string.len(e.name) > 10 and "..." or "")
self.new_input.joysticks[e.name].axes[e.axis][e.value >= 0.5 and "positive" or "negative"] = configurable_inputs[self.input_state]
self.new_input.joysticks[e.name].axes[e.axis][e.value >= 1 and "positive" or "negative"] = configurable_inputs[self.input_state]
self.input_state = self.input_state + 1
self.last_axis = e.axis
self.axis_timer = 0
end
elseif e.type == "joyhat" then
if e.direction ~= "c" then

View File

@@ -18,6 +18,7 @@ function ModeSelectScene:new()
end
function ModeSelectScene:update()
switchBGM(nil) -- experimental
end
function ModeSelectScene:render()

65
scene/settings.lua Normal file
View File

@@ -0,0 +1,65 @@
local SettingsScene = Scene:extend()
SettingsScene.title = "Settings"
local menu_screens = {
InputConfigScene,
GameConfigScene,
TuningScene
}
function SettingsScene:new()
self.menu_state = 1
DiscordRPC:update({
details = "In menus",
state = "Changing settings",
})
end
function SettingsScene:update() end
function SettingsScene:render()
love.graphics.setColor(1, 1, 1, 1)
love.graphics.draw(
backgrounds["game_config"],
0, 0, 0,
0.5, 0.5
)
love.graphics.setFont(font_3x5_4)
love.graphics.print("SETTINGS", 80, 40)
love.graphics.setFont(font_3x5_2)
love.graphics.print("Here, you can change some settings that change\nthe look and feel of the game.", 80, 90)
love.graphics.setColor(1, 1, 1, 0.5)
love.graphics.rectangle("fill", 75, 118 + 50 * self.menu_state, 200, 33)
love.graphics.setFont(font_3x5_3)
love.graphics.setColor(1, 1, 1, 1)
for i, screen in pairs(menu_screens) do
love.graphics.printf(screen.title, 80, 120 + 50 * i, 200, "left")
end
end
function SettingsScene:changeOption(rel)
local len = table.getn(menu_screens)
self.menu_state = (self.menu_state + len + rel - 1) % len + 1
end
function SettingsScene:onInputPress(e)
if e.input == "menu_decide" or e.scancode == "return" then
playSE("main_decide")
scene = menu_screens[self.menu_state]()
elseif e.input == "up" or e.scancode == "up" then
self:changeOption(-1)
playSE("cursor")
elseif e.input == "down" or e.scancode == "down" then
self:changeOption(1)
playSE("cursor")
elseif e.input == "menu_back" or e.scancode == "backspace" or e.scancode == "delete" then
scene = TitleScene()
end
end
return SettingsScene

View File

@@ -1,9 +1,12 @@
local TitleScene = Scene:extend()
TitleScene.title = "Title"
TitleScene.restart_message = false
local main_menu_screens = {
ModeSelectScene,
InputConfigScene,
GameConfigScene,
SettingsScene,
CreditsScene,
ExitScene,
}
@@ -24,6 +27,11 @@ local mainmenuidle = {
function TitleScene:new()
self.main_menu_state = 1
self.frames = 0
self.snow_bg_opacity = 0
self.y_offset = 0
self.text = ""
self.text_flag = false
DiscordRPC:update({
details = "In menus",
state = mainmenuidle[math.random(#mainmenuidle)],
@@ -31,17 +39,41 @@ function TitleScene:new()
end
function TitleScene:update()
if self.text_flag then
self.frames = self.frames + 1
self.snow_bg_opacity = self.snow_bg_opacity + 0.01
end
if self.frames < 125 then self.y_offset = self.frames
elseif self.frames < 185 then self.y_offset = 125
else self.y_offset = 310 - self.frames end
end
function TitleScene:render()
love.graphics.setFont(font_3x5_2)
love.graphics.setColor(1, 1, 1, 1 - self.snow_bg_opacity)
love.graphics.draw(
backgrounds["title"],
0, 0, 0,
0.5, 0.5
)
love.graphics.setColor(1, 1, 1, self.snow_bg_opacity)
love.graphics.draw(
backgrounds["snow"],
0, 0, 0,
0.5, 0.5
)
love.graphics.draw(
misc_graphics["santa"],
400, -205 + self.y_offset,
0, 0.5, 0.5
)
love.graphics.print("Happy Holidays!", 320, -100 + self.y_offset)
love.graphics.print(self.restart_message and "Restart Cambridge..." or "", 0, 0)
love.graphics.setColor(1, 1, 1, 0.5)
love.graphics.rectangle("fill", 20, 278 + 20 * self.main_menu_state, 160, 22)
@@ -69,6 +101,11 @@ function TitleScene:onInputPress(e)
playSE("cursor")
elseif e.input == "menu_back" or e.scancode == "backspace" or e.scancode == "delete" then
love.event.quit()
else
self.text = self.text .. (e.scancode ~= nil and e.scancode or "")
if self.text == "ffffff" then
self.text_flag = true
end
end
end

85
scene/tuning.lua Normal file
View File

@@ -0,0 +1,85 @@
local TuningScene = Scene:extend()
TuningScene.title = "Tuning Settings"
require 'load.save'
require 'libs.simple-slider'
TuningScene.options = {
-- Serves as a reference for the options available in the menu. Format: {name in config, name as displayed if applicable, slider name}
{"das", "DAS", "dasSlider"},
{"arr", "ARR", "arrSlider"},
}
local optioncount = #TuningScene.options
function TuningScene:new()
DiscordRPC:update({
details = "In menus",
state = "Changing tuning settings",
})
self.highlight = 1
self.dasSlider = newSlider(290, 225, 400, config.das, 0, 20, function(v) config.das = math.floor(v) end, {width=20})
self.arrSlider = newSlider(290, 325, 400, config.arr, 0, 6, function(v) config.arr = math.floor(v) end, {width=20})
end
function TuningScene:update()
self.dasSlider:update()
self.arrSlider:update()
end
function TuningScene:render()
love.graphics.setColor(1, 1, 1, 1)
love.graphics.draw(
backgrounds["game_config"],
0, 0, 0,
0.5, 0.5
)
love.graphics.setColor(1, 1, 1, 0.5)
love.graphics.rectangle("fill", 75, 73 + self.highlight * 100, 400, 33)
love.graphics.setColor(1, 1, 1, 1)
love.graphics.setFont(font_3x5_4)
love.graphics.print("TUNING SETTINGS", 80, 40)
love.graphics.setFont(font_3x5_2)
love.graphics.print("These settings will only apply to modes\nthat do not use their own tunings.", 80, 90)
love.graphics.setFont(font_3x5_3)
love.graphics.print("Delayed Auto-Shift (DAS): " .. math.floor(self.dasSlider:getValue()) .. "F", 80, 175)
love.graphics.print("Auto-Repeat Rate (ARR): " .. math.floor(self.arrSlider:getValue()) .. "F", 80, 275)
love.graphics.setColor(1, 1, 1, 0.75)
self.dasSlider:draw()
self.arrSlider:draw()
end
function TuningScene:onInputPress(e)
if e.input == "menu_decide" or e.scancode == "return" then
playSE("mode_decide")
saveConfig()
scene = SettingsScene()
elseif e.input == "up" or e.scancode == "up" then
playSE("cursor")
self.highlight = Mod1(self.highlight-1, optioncount)
elseif e.input == "down" or e.scancode == "down" then
playSE("cursor")
self.highlight = Mod1(self.highlight+1, optioncount)
elseif e.input == "left" or e.scancode == "left" then
playSE("cursor")
sld = self[self.options[self.highlight][3]]
sld.value = math.max(sld.min, math.min(sld.max, (sld:getValue() - 1) / (sld.max - sld.min)))
elseif e.input == "right" or e.scancode == "right" then
playSE("cursor")
sld = self[self.options[self.highlight][3]]
sld.value = math.max(sld.min, math.min(sld.max, (sld:getValue() + 1) / (sld.max - sld.min)))
elseif e.input == "menu_back" or e.scancode == "delete" or e.scancode == "backspace" then
loadSave()
scene = SettingsScene()
end
end
return TuningScene

View File

@@ -194,7 +194,7 @@ function Grid:applyPiece(piece)
for index, offset in pairs(offsets) do
x = piece.position.x + offset.x
y = piece.position.y + offset.y
if y + 1 > 0 then
if y + 1 > 0 and y < 24 then
self.grid[y+1][x+1] = {
skin = piece.skin,
colour = piece.colour
@@ -273,6 +273,43 @@ function Grid:checkSecretGrade()
return sgrade
end
function Grid:hasGemBlocks()
for y = 1, 24 do
for x = 1, 10 do
if self.grid[y][x].skin == "gem" then
return true
end
end
end
return false
end
function Grid:mirror()
local new_grid = {}
for y = 1, 24 do
new_grid[y] = {}
for x = 1, 10 do
new_grid[y][x] = empty
end
end
for y = 1, 24 do
for x = 1, 10 do
new_grid[y][x] = self.grid[y][11 - x]
end
end
self.grid = new_grid
end
function Grid:applyMap(map)
for y, row in pairs(map) do
for x, block in pairs(row) do
self.grid_age[y][x] = 0
self.grid[y][x] = block
end
end
end
function Grid:update()
for y = 1, 24 do
for x = 1, 10 do
@@ -380,4 +417,44 @@ function Grid:drawInvisible(opacity_function, garbage_opacity_function, lock_fla
end
end
function Grid:drawCustom(colour_function, gamestate)
--[[
colour_function: (game, block, x, y, age) -> (R, G, B, A, outlineA)
When called, calls the supplied function on every block passing the block itself as argument
as well as coordinates and the grid_age value of the same cell.
Should return a RGBA colour for the block, as well as the opacity of the stack outline (0 for no outline).
gamestate: the gamemode instance itself to pass in colour_function
]]
for y = 5, 24 do
for x = 1, 10 do
local block = self.grid[y][x]
if block ~= empty then
local R, G, B, A, outline = colour_function(gamestate, block, x, y, self.grid_age[y][x])
if self.grid[y][x].colour == "X" then
A = 1
end
love.graphics.setColor(R, G, B, A)
love.graphics.draw(blocks[self.grid[y][x].skin][self.grid[y][x].colour], 48+x*16, y*16)
if outline > 0 and self.grid[y][x].colour ~= "X" then
love.graphics.setColor(0.64, 0.64, 0.64, outline)
love.graphics.setLineWidth(1)
if y > 1 and self.grid[y-1][x] == empty then
love.graphics.line(48.0+x*16, -0.5+y*16, 64.0+x*16, -0.5+y*16)
end
if y < 24 and self.grid[y+1][x] == empty then
love.graphics.line(48.0+x*16, 16.5+y*16, 64.0+x*16, 16.5+y*16)
end
if x > 1 and self.grid[y][x-1] == empty then
love.graphics.line(47.5+x*16, -0.0+y*16, 47.5+x*16, 16.0+y*16)
end
if x < 10 and self.grid[y][x+1] == empty then
love.graphics.line(64.5+x*16, -0.0+y*16, 64.5+x*16, 16.0+y*16)
end
end
end
end
end
end
return Grid

View File

@@ -78,12 +78,15 @@ function Piece:setRelativeRotation(rot)
return self
end
function Piece:moveInGrid(step, squares, grid)
function Piece:moveInGrid(step, squares, grid, instant)
local moved = false
for x = 1, squares do
if grid:canPlacePiece(self:withOffset(step)) then
moved = true
self:setOffset(step)
if instant then
self:dropToBottom(grid)
end
else
break
end
@@ -140,9 +143,10 @@ function Piece:draw(opacity, brightness, grid, partial_das)
love.graphics.setColor(brightness, brightness, brightness, opacity)
local offsets = self:getBlockOffsets()
local gravity_offset = 0
--if grid ~= nil and not self:isDropBlocked(grid) then
-- gravity_offset = self.gravity * 16
--end
if config.gamesettings.smooth_movement == 1 and
grid ~= nil and not self:isDropBlocked(grid) then
gravity_offset = self.gravity * 16
end
if partial_das == nil then partial_das = 0 end
for index, offset in pairs(offsets) do
local x = self.position.x + offset.x

View File

@@ -46,6 +46,11 @@ function GameMode:new()
self.irs = true
self.ihs = true
self.rpc_details = "In game"
self.SGnames = {
"9", "8", "7", "6", "5", "4", "3", "2", "1",
"S1", "S2", "S3", "S4", "S5", "S6", "S7", "S8", "S9",
"GM"
}
-- variables related to configurable parameters
self.drop_locked = false
self.hard_drop_locked = false
@@ -95,11 +100,31 @@ function GameMode:update(inputs, ruleset)
end
if self.completed then return end
if config.gamesettings.diagonal_input == 2 then
if inputs["left"] or inputs["right"] then
inputs["up"] = false
inputs["down"] = false
elseif inputs["up"] or inputs["down"] then
inputs["left"] = false
inputs["right"] = false
end
end
-- advance one frame
if self:advanceOneFrame(inputs) == false then return end
if self:advanceOneFrame(inputs, ruleset) == false then return end
self:chargeDAS(inputs, self:getDasLimit(), self.getARR())
-- set attempt flags
if inputs["left"] or inputs["right"] then self:onAttemptPieceMove(self.piece) end
if
inputs["rotate_left"] or inputs["rotate_right"] or
inputs["rotate_left2"] or inputs["rotate_right2"] or
inputs["rotate_180"]
then
self:onAttemptPieceRotate(self.piece)
end
if self.piece == nil then
self:processDelays(inputs, ruleset)
else
@@ -137,6 +162,7 @@ function GameMode:update(inputs, ruleset)
not self.hard_drop_locked then
self:onHardDrop(piece_dy)
if self.lock_on_hard_drop then
self.piece_hard_dropped = true
self.piece.locked = true
end
end
@@ -200,6 +226,8 @@ end
-- event functions
function GameMode:whilePieceActive() end
function GameMode:onAttemptPieceMove(piece) end
function GameMode:onAttemptPieceRotate(piece) end
function GameMode:onPieceLock(piece, cleared_row_count)
playSE("lock")
end
@@ -207,9 +235,7 @@ end
function GameMode:onLineClear(cleared_row_count) end
function GameMode:onPieceEnter() end
function GameMode:onHold()
playSE("hold")
end
function GameMode:onHold() end
function GameMode:onSoftDrop(dropped_row_count)
self.drop_bonus = self.drop_bonus + 1 * dropped_row_count
@@ -223,30 +249,75 @@ function GameMode:onGameOver()
switchBGM(nil)
end
function GameMode:chargeDAS(inputs)
if inputs[self.das.direction] == true 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
-- DAS functions
function GameMode:startRightDAS()
self.move = "right"
self.das = { direction = "right", frames = 0 }
if self:getDasLimit() == 0 then
self:continueDAS()
end
end
function GameMode:startLeftDAS()
self.move = "left"
self.das = { direction = "left", frames = 0 }
if self:getDasLimit() == 0 then
self:continueDAS()
end
end
function GameMode:continueDAS()
local das_frames = self.das.frames + 1
if das_frames >= self:getDasLimit() then
if self.das.direction == "left" then
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
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
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
function GameMode:areCancel(inputs, ruleset)
if ruleset.are_cancel and self.piece_hard_dropped and
not self.prev_inputs.up and
strTrueValues(inputs) ~= "" then
self.lcd = 0
self.are = 0
end
end
@@ -270,6 +341,7 @@ function GameMode:processDelays(inputs, ruleset, drop_speed)
end
elseif self.lcd > 0 then
self.lcd = self.lcd - 1
self:areCancel(inputs, ruleset)
if self.lcd == 0 then
self.grid:clearClearedRows()
playSE("fall")
@@ -279,13 +351,7 @@ function GameMode:processDelays(inputs, ruleset, drop_speed)
end
elseif self.are > 0 then
self.are = self.are - 1
if ruleset.are_cancel and
(inputs["left"] or inputs["right"] or
inputs["rotate_left"] or inputs["rotate_left2"] or
inputs["rotate_right"] or inputs["rotate_right2"] or
inputs["rotate_180"]) then
self.are = 0
end
self:areCancel(inputs, ruleset)
if self.are == 0 then
self:initializeOrHold(inputs, ruleset)
end
@@ -294,7 +360,7 @@ end
function GameMode:initializeOrHold(inputs, ruleset)
if self.ihs and self.enable_hold and inputs["hold"] == true then
self:hold(inputs, ruleset)
self:hold(inputs, ruleset, true)
else
self:initializeNextPiece(inputs, ruleset, self.next_queue[1])
end
@@ -305,7 +371,7 @@ function GameMode:initializeOrHold(inputs, ruleset)
end
end
function GameMode:hold(inputs, ruleset)
function GameMode:hold(inputs, ruleset, ihs)
local data = copy(self.hold_queue)
if self.piece == nil then
self.hold_queue = self.next_queue[1]
@@ -324,10 +390,13 @@ function GameMode:hold(inputs, ruleset)
self:initializeNextPiece(inputs, ruleset, data, false)
end
self.held = true
if ihs then playSE("ihs")
else playSE("hold") end
self:onHold()
end
function GameMode:initializeNextPiece(inputs, ruleset, piece_data, generate_next_piece)
self.piece_hard_dropped = false
local gravity = self:getGravity()
self.piece = ruleset:initializePiece(
inputs, piece_data, self.grid, gravity,
@@ -398,7 +467,7 @@ function GameMode:drawNextQueue(ruleset)
drawPiece(next_piece, skin, ruleset.block_offsets[next_piece][rotation], -16+i*80, -32)
end
end
if self.hold_queue ~= nil then
if self.hold_queue ~= nil and self.enable_hold then
local hold_color = self.held and 0.6 or 1
self:setHoldOpacity(1, hold_color)
drawPiece(
@@ -455,6 +524,10 @@ function GameMode:drawSectionTimes(current_section)
love.graphics.printf(formatTime(self.frames - self.section_start_time), section_x, 40 + 20 * current_section, 90, "left")
end
function GameMode:sectionColourFunction(section)
return { 1, 1, 1, 1 }
end
function GameMode:drawSectionTimesWithSecondary(current_section)
local section_x = 530
local section_secondary_x = 440
@@ -466,9 +539,11 @@ function GameMode:drawSectionTimesWithSecondary(current_section)
end
for section, time in pairs(self.secondary_section_times) do
love.graphics.setColor(self:sectionColourFunction(section))
if section > 0 then
love.graphics.printf(formatTime(time), section_secondary_x, 40 + 20 * section, 90, "left")
end
love.graphics.setColor(1, 1, 1, 1)
end
local current_x

View File

@@ -327,10 +327,10 @@ function Marathon2020Game:checkClear(level)
end
function Marathon2020Game:updateSectionTimes(old_level, new_level)
function sectionCool()
function sectionCool(section)
self.section_cool_count = self.section_cool_count + 1
self.delay_level = math.min(20, self.delay_level + 1)
table.insert(self.section_status, "cool")
if section < 10 then table.insert(self.section_status, "cool") end
self.cool_timer = 300
end
@@ -348,7 +348,7 @@ function Marathon2020Game:updateSectionTimes(old_level, new_level)
table.insert(self.section_times, section_time)
self.section_start_time = self.frames
if section > 4 then self.delay_level = math.min(20, self.delay_level + 1) end
if section > 5 then self.delay_level = math.min(20, self.delay_level + 1) end
self:checkTorikan(section)
self:checkClear(new_level)
@@ -357,11 +357,11 @@ function Marathon2020Game:updateSectionTimes(old_level, new_level)
self.secondary_section_times[section] < self.secondary_section_times[section - 1] + 120 and
self.secondary_section_times[section] < cool_cutoffs[section]
) then
sectionCool()
sectionCool(section)
elseif self.section_status[section - 1] == "cool" then
table.insert(self.section_status, "none")
elseif section <= 19 and self.secondary_section_times[section] < cool_cutoffs[section] then
sectionCool()
sectionCool(section)
else
table.insert(self.section_status, "none")
end
@@ -423,6 +423,14 @@ function Marathon2020Game:drawGrid()
end
end
function Marathon2020Game:sectionColourFunction(section)
if self.section_status[section] == "cool" then
return { 0, 1, 0, 1 }
else
return { 1, 1, 1, 1 }
end
end
function Marathon2020Game:drawScoringInfo()
Marathon2020Game.super.drawScoringInfo(self)

View File

@@ -27,7 +27,7 @@ function MarathonA3Game:new()
self.section_cool_grade = 0
self.section_status = { [0] = "none" }
self.section_start_time = 0
self.section_70_times = { [0] = 0 }
self.secondary_section_times = { [0] = 0 }
self.section_times = { [0] = 0 }
self.section_cool = false
@@ -163,8 +163,8 @@ function MarathonA3Game:onLineClear(cleared_row_count)
self:updateSectionTimes(self.level, self.level + advanced_levels)
if not self.clear then
self.level = math.min(self.level + advanced_levels, 999)
self.speed_level = self.speed_level + advanced_levels
end
self.speed_level = self.speed_level + advanced_levels
if self.level == 999 and not self.clear then
self.clear = true
self.grid:clear()
@@ -194,7 +194,7 @@ function MarathonA3Game:updateSectionTimes(old_level, new_level)
-- record new section
section_time = self.frames - self.section_start_time
table.insert(self.section_times, section_time)
self.section_start_time = self.frames
if new_level < 999 then self.section_start_time = self.frames end
self.speed_level = self.section_cool and self.speed_level + 100 or self.speed_level
@@ -214,15 +214,15 @@ function MarathonA3Game:updateSectionTimes(old_level, new_level)
elseif old_level % 100 < 70 and new_level % 100 >= 70 then
-- record section 70 time
section_70_time = self.frames - self.section_start_time
table.insert(self.section_70_times, section_70_time)
table.insert(self.secondary_section_times, section_70_time)
if section <= 9 and self.section_status[section - 1] == "cool" and
self.section_70_times[section] < self.section_70_times[section - 1] + 120 then
self.secondary_section_times[section] < self.secondary_section_times[section - 1] + 120 then
self.section_cool = true
self.coolregret_message = "COOL!!"
self.coolregret_timer = 300
elseif self.section_status[section - 1] == "cool" then self.section_cool = false
elseif section <= 9 and self.section_70_times[section] < cool_cutoffs[section] then
elseif section <= 9 and self.secondary_section_times[section] < cool_cutoffs[section] then
self.section_cool = true
self.coolregret_message = "COOL!!"
self.coolregret_timer = 300
@@ -395,6 +395,16 @@ MarathonA3Game.mRollOpacityFunction = function(age)
else return 1 - age / 4 end
end
function MarathonA3Game:sectionColourFunction(section)
if self.section_status[section] == "cool" then
return { 0, 1, 0, 1 }
elseif self.section_status[section] == "regret" then
return { 1, 0, 0, 1 }
else
return { 1, 1, 1, 1 }
end
end
function MarathonA3Game:drawScoringInfo()
love.graphics.setColor(1, 1, 1, 1)
@@ -415,6 +425,8 @@ function MarathonA3Game:drawScoringInfo()
-- draw section time data
current_section = math.floor(self.level / 100) + 1
self:drawSectionTimesWithSecondary(current_section)
--[[
section_x = 530
section_70_x = 440
@@ -425,21 +437,22 @@ function MarathonA3Game:drawScoringInfo()
end
end
for section, time in pairs(self.section_70_times) do
for section, time in pairs(self.secondary_section_times) do
if section > 0 then
love.graphics.printf(formatTime(time), section_70_x, 40 + 20 * section, 90, "left")
end
end
local current_x
if table.getn(self.section_times) < table.getn(self.section_70_times) then
if table.getn(self.section_times) < table.getn(self.secondary_section_times) then
current_x = section_x
else
current_x = section_70_x
end
if not self.clear then love.graphics.printf(formatTime(self.frames - self.section_start_time), current_x, 40 + 20 * current_section, 90, "left") end
]]--
if(self.coolregret_timer > 0) then
love.graphics.printf(self.coolregret_message, 64, 400, 160, "center")
self.coolregret_timer = self.coolregret_timer - 1
@@ -448,7 +461,7 @@ function MarathonA3Game:drawScoringInfo()
love.graphics.setFont(font_3x5_3)
love.graphics.printf(self.score, 240, 220, 90, "left")
if self.roll_frames > 3238 then love.graphics.setColor(1, 0.5, 0, 1)
elseif self.clear then love.graphics.setColor(0, 1, 0, 1) end
elseif self.level >= 999 and self.clear then love.graphics.setColor(0, 1, 0, 1) end
love.graphics.printf(self:getLetterGrade(), 240, 140, 90, "left")
love.graphics.setColor(1, 1, 1, 1)
love.graphics.printf(self.level, 240, 340, 40, "right")
@@ -475,7 +488,7 @@ function MarathonA3Game:getSectionEndLevel()
end
function MarathonA3Game:getBackground()
return math.floor(self.level / 100)
return math.floor(self.speed_level / 100)
end
return MarathonA3Game

View File

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

View File

@@ -255,7 +255,7 @@ PhantomMania2Game.garbageOpacityFunction = function(age)
end
function PhantomMania2Game:drawGrid()
if not (self.game_over or (self.clear and self.level < 1300)) then
if not (self.game_over) then
self.grid:drawInvisible(self.rollOpacityFunction, self.garbageOpacityFunction)
else
self.grid:draw()
@@ -291,7 +291,7 @@ function PhantomMania2Game:setHoldOpacity()
if self.level > 1000 and self.level < 1300 then
love.graphics.setColor(1, 1, 1, 1 - math.min(1, self.hold_age / 15))
else
love.graphics.setColor(1, 1, 1, 1)
self.super:setHoldOpacity(1, self.held and 0.6 or 1)
end
end

568
tetris/modes/sakura.lua Normal file
View File

@@ -0,0 +1,568 @@
require 'funcs'
local GameMode = require 'tetris.modes.gamemode'
local Piece = require 'tetris.components.piece'
local SakuraRandomizer = require 'tetris.randomizers.sakura'
local SakuraGame = GameMode:extend()
SakuraGame.name = "Sakura A3"
SakuraGame.hash = "SakuraA3"
SakuraGame.tagline = "Clear away the Gem Blocks as fast as possible!"
local b = {
["r"] = { skin = "2tie", colour = "R" },
["o"] = { skin = "2tie", colour = "O" },
["y"] = { skin = "2tie", colour = "Y" },
["g"] = { skin = "2tie", colour = "G" },
["c"] = { skin = "2tie", colour = "C" },
["b"] = { skin = "2tie", colour = "B" },
["m"] = { skin = "2tie", colour = "M" },
["R"] = { skin = "gem", colour = "R" },
["O"] = { skin = "gem", colour = "O" },
["Y"] = { skin = "gem", colour = "Y" },
["G"] = { skin = "gem", colour = "G" },
["C"] = { skin = "gem", colour = "C" },
["B"] = { skin = "gem", colour = "B" },
["M"] = { skin = "gem", colour = "M" },
}
local effects = {
[4] = "mirror",
[8] = "xray",
[12] = "color",
[13] = "mirror",
[16] = "roll",
[23] = "big"
}
local maps = {
[1] = {
[22] = {nil, nil, b.O, b.R, nil, nil, b.M, b.m, nil, nil},
[23] = {nil, b.G, b.c, b.c, b.c, b.c, b.c, b.c, b.Y, nil},
[24] = {nil, b.C, b.y, b.y, b.y, b.y, b.y, b.y, b.B, nil},
},
[2] = {
[20] = {nil, nil, nil, nil, b.G, b.b, b.b, b.M, nil, nil},
[21] = {nil, nil, nil, nil, b.c, b.c, b.c, b.c, nil, nil},
[22] = {nil, nil, nil, nil, nil, b.R, b.Y, b.O, nil, nil},
[23] = {nil, b.B, b.c, b.c, b.c, b.c, b.c, b.c, b.c, nil},
[24] = {nil, b.b, b.b, b.b, b.b, b.b, b.b, b.b, b.C, nil},
},
[3] = {
[20] = {nil, nil, nil, b.R, b.m, b.o, b.M, nil, nil, nil},
[21] = {nil, nil, nil, nil, b.o, b.O, nil, nil, nil, nil},
[22] = {nil, nil, nil, nil, b.G, b.Y, nil, nil, nil, nil},
[23] = {nil, b.m, b.o, b.m, b.o, b.m, b.o, b.m, b.o, nil},
[24] = {nil, b.B, b.m, b.o, b.m, b.o, b.m, b.o, b.C, nil},
},
[4] = {
[21] = {nil, nil, b.O, b.g, b.g, b.g, b.g, nil, nil, nil},
[22] = {nil, nil, nil, b.R, b.M, b.b, b.b, nil, nil, nil},
[23] = {b.G, nil, b.Y, b.g, b.g, b.g, b.g, b.g, nil, nil},
[24] = {b.b, b.C, b.b, b.b, b.b, b.b, b.b, b.b, b.B, nil},
},
[5] = {
[16] = {nil, b.B, b.c, b.y, b.c, b.G, b.c, b.y, b.C, nil},
[22] = {nil, nil, b.c, b.y, b.c, b.y, b.c, b.y, nil, nil},
[23] = {nil, b.O, b.y, b.c, b.y, b.c, b.y, b.c, b.Y, nil},
[24] = {nil, b.R, b.c, b.y, b.c, b.y, b.c, b.y, b.M, nil},
},
[6] = {
[21] = {nil, nil, nil, nil, b.O, b.Y, nil, nil, nil, nil},
[22] = {nil, nil, b.R, nil, b.b, b.y, nil, b.M, nil, nil},
[23] = {nil, nil, nil, nil, b.y, b.b, nil, nil, nil, nil},
[24] = {nil, b.G, b.y, b.b, b.C, b.y, b.b, b.y, b.B, nil},
},
[7] = {
[20] = {nil, b.C, b.G, nil, b.r, b.g, b.r, b.g, nil, nil},
[21] = {nil, nil, nil, nil, b.R, b.M, b.g, b.r, nil, nil},
[22] = {b.r, nil, nil, nil, b.r, b.g, b.O, b.Y, nil, nil},
[23] = {b.g, b.r, b.g, b.r, b.g, b.r, b.g, b.r, nil, nil},
[24] = {b.r, b.g, b.r, b.g, b.r, b.g, b.r, b.g, b.B, nil},
},
[8] = {
[15] = {nil, nil, nil, b.B, b.m, b.m, b.m, b.m, b.m, b.C},
[16] = {nil, nil, nil, nil, nil, nil, nil, nil, nil, b.m},
[17] = {nil, nil, nil, nil, nil, nil, nil, nil, nil, b.m},
[18] = {nil, b.Y, b.y, b.y, b.y, b.y, b.y, b.y, b.y, b.G},
[21] = {b.b, b.b, b.b, b.b, b.b, b.b, b.O, nil, nil, nil},
[22] = {b.b, nil, nil, nil, nil, nil, nil, nil, nil, nil},
[23] = {b.M, nil, nil, nil, nil, nil, nil, nil, nil, nil},
[24] = {b.o, b.o, b.o, b.o, b.o, b.o, b.o, b.o, b.R, nil},
},
[9] = {
[18] = {nil, nil, nil, b.Y, b.m, b.m, b.m, b.m, nil, nil},
[19] = {nil, nil, nil, b.c, b.c, b.c, b.c, b.G, nil, nil},
[20] = {b.m, b.m, b.m, b.O, b.M, b.R, nil, nil, nil, nil},
[21] = {b.c, b.c, b.c, b.c, b.c, b.c, b.c, b.c, nil, nil},
[22] = {b.m, b.m, b.m, b.m, b.m, b.m, b.m, b.m, nil, nil},
[23] = {b.c, b.c, b.c, b.c, b.c, b.c, b.c, b.c, b.C, nil},
[24] = {b.m, b.m, b.m, b.m, b.m, b.m, b.m, b.m, b.B, nil},
},
[10] = {
[18] = {nil, nil, nil, b.C, b.g, b.g, b.B, nil, nil, nil},
[19] = {nil, nil, b.G, b.g, b.g, b.g, b.g, b.Y, nil, nil},
[20] = {nil, b.M, b.g, b.g, b.g, b.g, b.g, b.g, b.O, nil},
[21] = {nil, nil, nil, nil, b.c, nil, nil, nil, nil, nil},
[22] = {nil, nil, nil, nil, b.c, nil, nil, nil, nil, nil},
[23] = {nil, nil, nil, nil, b.c, nil, b.o, nil, nil, nil},
[24] = {nil, nil, nil, nil, b.R, b.o, b.o, nil, nil, nil},
},
[11] = {
[18] = {nil, nil, nil, nil, b.o, b.o, nil, nil, nil, nil},
[19] = {nil, nil, nil, nil, b.R, nil, nil, nil, nil, nil},
[20] = {nil, nil, nil, nil, b.r, b.O, nil, nil, nil, nil},
[21] = {nil, nil, nil, nil, nil, b.M, nil, nil, nil, nil},
[22] = {nil, nil, nil, nil, b.o, b.o, nil, nil, nil, nil},
[23] = {nil, nil, nil, nil, b.G, b.Y, nil, nil, nil, nil},
[24] = {b.C, b.g, b.g, nil, b.o, b.o, nil, b.g, b.g, b.B},
},
[12] = {
[21] = {nil, nil, nil, nil, nil, nil, nil, b.g, b.g, b.Y},
[22] = {nil, nil, b.r, b.G, b.r, nil, nil, nil, b.O, b.g},
[23] = {nil, b.r, b.C, b.r, b.B, b.r, nil, nil, nil, b.M},
[24] = {b.r, b.r, b.r, b.R, b.r, b.r, b.r, nil, nil, nil},
},
[13] = {
[20] = {b.c, nil, nil, nil, nil, nil, nil, nil, nil, b.B},
[21] = {b.c, b.c, nil, nil, nil, nil, nil, nil, b.C, b.c},
[22] = {b.c, b.c, b.c, nil, nil, nil, nil, b.G, b.c, b.c},
[23] = {b.b, b.b, b.b, b.b, nil, nil, b.Y, b.b, b.b, b.b},
[24] = {nil, b.M, b.b, b.b, b.b, b.O, b.b, b.b, b.R, nil},
},
[14] = {
[20] = {nil, nil, nil, b.y, b.r, b.y, nil, nil, nil, nil},
[21] = {b.R, nil, nil, b.Y, b.y, b.r, b.G, nil, nil, nil},
[22] = {nil, nil, nil, b.y, b.r, b.y, b.r, b.y, b.r, b.B},
[23] = {nil, nil, nil, nil, nil, nil, nil, b.O, b.y, b.r},
[24] = {nil, nil, nil, nil, nil, nil, b.M, b.y, b.r, b.C},
},
[15] = {
[17] = {nil, nil, b.b, nil, nil, nil, nil, b.b, nil, nil},
[18] = {nil, nil, b.b, b.y, b.b, b.b, b.y, b.b, nil, nil},
[19] = {nil, nil, nil, b.y, b.b, b.b, b.y, nil, nil, nil},
[20] = {nil, nil, nil, nil, b.O, b.Y, nil, nil, nil, nil},
[22] = {nil, nil, nil, nil, b.M, b.R, nil, nil, nil, nil},
[23] = {nil, nil, nil, b.G, b.y, b.y, b.C, nil, nil, nil},
[24] = {nil, nil, b.B, b.y, b.y, b.y, b.y, b.y, nil, nil},
},
[16] = {
[18] = {nil, nil, b.O, nil, nil, nil, nil, b.B, nil, nil},
[19] = {nil, nil, b.c, nil, nil, b.G, nil, b.c, nil, nil},
[20] = {nil, nil, b.c, nil, b.C, b.R, nil, b.c, nil, nil},
[21] = {nil, nil, b.c, nil, nil, nil, nil, b.c, nil, nil},
[22] = {nil, nil, b.Y, b.c, b.c, b.c, b.c, b.M, nil, nil},
},
[17] = {
[15] = {b.O, nil, nil, b.g, nil, nil, b.m, nil, nil, b.Y},
[16] = {nil, nil, nil, b.g, nil, nil, b.m, nil, nil, nil},
[17] = {nil, nil, nil, b.g, nil, nil, b.R, nil, nil, nil},
[18] = {nil, nil, nil, b.g, nil, nil, b.m, nil, nil, nil},
[19] = {nil, nil, nil, b.M, nil, nil, b.m, nil, nil, nil},
[20] = {nil, nil, nil, b.g, nil, nil, b.m, nil, nil, nil},
[21] = {nil, nil, nil, b.g, nil, nil, b.G, nil, nil, nil},
[22] = {nil, nil, nil, b.g, nil, nil, b.m, nil, nil, nil},
[23] = {nil, nil, nil, b.g, nil, nil, b.m, nil, nil, nil},
[24] = {nil, b.m, b.m, b.m, b.B, b.C, b.g, b.g, b.g, nil},
},
[18] = {
[19] = {nil, nil, nil, b.y, b.B, b.y, b.y, nil, nil, nil},
[20] = {nil, nil, b.y, nil, nil, nil, nil, b.y, nil, nil},
[21] = {nil, b.o, nil, nil, b.C, b.R, nil, nil, b.O, nil},
[22] = {nil, b.M, nil, nil, b.Y, b.G, nil, nil, b.o, nil},
[23] = {nil, b.r, b.o, nil, nil, nil, nil, b.o, b.r, nil},
[24] = {nil, b.r, b.r, b.o, b.o, b.o, b.o, b.r, b.r, nil},
},
[19] = {
[15] = {nil, nil, nil, nil, nil, nil, b.O, nil, nil, nil},
[16] = {nil, nil, nil, nil, nil, b.o, nil, nil, nil, nil},
[17] = {nil, nil, nil, nil, b.o, b.r, b.o, nil, nil, nil},
[18] = {nil, b.o, nil, nil, b.o, b.r, b.r, b.o, nil, nil},
[19] = {nil, b.o, b.o, nil, nil, b.R, b.r, b.r, nil, nil},
[20] = {nil, nil, b.M, b.r, nil, b.r, b.r, b.r, b.r, nil},
[21] = {nil, nil, b.r, b.r, b.r, b.r, b.y, b.G, b.o, b.o},
[22] = {nil, b.r, b.o, b.y, b.Y, b.y, b.y, b.y, b.y, b.o},
[23] = {nil, b.o, b.o, b.y, b.y, b.c, b.c, b.c, b.c, b.C},
[24] = {nil, nil, b.o, b.y, b.b, b.b, b.B, b.b, b.b, b.b},
},
[20] = {
[20] = {nil, nil, b.B, b.b, b.b, b.b, b.b, b.b, nil, nil},
[21] = {b.c, nil, nil, b.C, b.c, b.c, b.c, nil, nil, b.c},
[22] = {b.g, b.g, nil, nil, b.G, b.g, nil, nil, b.g, b.g},
[23] = {b.y, b.y, b.o, nil, nil, nil, nil, b.Y, b.y, b.y},
[24] = {b.r, b.r, b.r, b.R, nil, nil, b.M, b.r, b.r, b.r},
},
[21] = {
[16] = {nil, nil, b.g, b.g, b.g, b.g, b.g, nil, nil, nil},
[17] = {nil, b.g, b.g, b.g, b.g, b.g, b.g, b.B, b.g, nil},
[18] = {b.g, b.g, b.g, b.g, b.g, b.g, b.g, b.g, b.C, nil},
[19] = {b.g, nil, nil, b.g, b.o, b.o, b.g, nil, nil, b.g},
[20] = {nil, b.R, nil, b.g, b.o, b.o, nil, b.M, nil, b.G},
[21] = {nil, nil, nil, nil, b.o, b.o, nil, nil, nil, nil},
[22] = {nil, nil, nil, nil, b.o, b.o, nil, nil, nil, nil},
[23] = {nil, nil, nil, nil, b.o, b.o, nil, nil, nil, nil},
[24] = {nil, nil, nil, nil, b.Y, b.O, nil, nil, nil, nil},
},
[22] = {
[15] = {nil, nil, b.b, nil, nil, nil, nil, b.b, nil, nil},
[16] = {nil, b.b, b.O, b.b, nil, nil, b.b, b.Y, b.b, nil},
[17] = {nil, nil, b.b, nil, nil, nil, nil, b.b, nil, nil},
[20] = {nil, nil, nil, nil, b.R, b.M, nil, nil, nil, nil},
[23] = {nil, nil, nil, b.b, b.C, b.G, b.b, nil, nil, nil},
[24] = {nil, nil, nil, b.b, b.b, b.B, b.b, nil, nil, nil},
},
[23] = {
[13] = {nil, nil, nil, nil, nil, nil, nil, nil, b.c, b.m},
[14] = {nil, nil, nil, nil, nil, nil, nil, nil, b.y, b.g},
[15] = {b.G, b.B, nil, nil, nil, nil, nil, nil, nil, nil},
[16] = {b.r, b.O, nil, nil, nil, nil, nil, nil, nil, nil},
[23] = {nil, nil, nil, nil, b.C, b.M, nil, nil, nil, nil},
[24] = {nil, nil, nil, nil, b.R, b.Y, nil, nil, nil, nil},
},
[24] = {
[20] = {b.g, b.g, b.g, b.g, b.G, nil, nil, nil, nil, nil},
[21] = {nil, nil, nil, nil, nil, b.O, b.y, b.y, b.y, b.Y},
[23] = {b.M, b.r, b.r, b.r, b.R, nil, nil, nil, nil, nil},
[24] = {nil, nil, nil, nil, nil, b.M, b.r, b.r, b.r, b.R},
},
[25] = {
[18] = {nil, nil, nil, nil, nil, b.B, nil, nil, nil, nil},
[19] = {nil, nil, nil, b.G, nil, nil, nil, b.C, nil, nil},
[20] = {nil, nil, nil, nil, nil, b.Y, nil, nil, nil, nil},
[21] = {nil, nil, nil, b.M, nil, nil, nil, b.O, nil, nil},
[22] = {nil, nil, nil, nil, nil, b.R, nil, nil, nil, nil},
},
[26] = {
[13] = {nil, nil, nil, nil, b.r, b.r, nil, nil, nil, nil},
[14] = {nil, nil, nil, nil, b.o, b.o, nil, nil, nil, nil},
[15] = {nil, nil, nil, nil, b.o, b.o, nil, nil, nil, nil},
[16] = {nil, nil, nil, nil, b.o, b.o, nil, nil, nil, nil},
[17] = {nil, nil, nil, b.O, b.o, b.o, b.Y, nil, nil, nil},
[18] = {nil, nil, b.o, b.c, b.c, b.c, b.c, b.o, nil, nil},
[19] = {nil, nil, b.o, b.c, b.c, b.c, b.c, b.o, nil, nil},
[20] = {nil, nil, b.o, nil, nil, b.G, nil, b.o, nil, nil},
[21] = {nil, nil, b.o, nil, b.M, b.R, nil, b.o, nil, nil},
[22] = {nil, nil, b.o, b.b, b.b, b.b, b.B, b.o, nil, nil},
[23] = {nil, nil, b.o, b.C, b.b, b.b, b.b, b.o, nil, nil},
[24] = {nil, nil, b.o, b.o, b.o, b.o, b.o, b.o, nil, nil},
},
[27] = {
[15] = {nil, b.C, b.o, b.g, b.g, b.g, b.g, b.g, b.B, nil},
[16] = {b.g, nil, b.y, b.o, b.g, b.g, b.g, b.g, nil, b.y},
[17] = {b.g, b.g, nil, b.y, b.o, b.g, b.g, nil, b.y, b.o},
[18] = {b.g, b.g, b.g, nil, b.y, b.o, nil, b.y, b.o, b.g},
[19] = {b.g, b.g, b.g, b.o, nil, b.G, b.y, b.o, b.g, b.g},
[20] = {b.g, b.g, b.o, b.o, b.Y, nil, b.o, b.g, b.g, b.g},
[21] = {b.g, b.o, b.y, nil, b.o, b.O, nil, b.g, b.g, b.g},
[22] = {b.o, b.y, nil, b.g, b.g, b.o, b.y, nil, b.g, b.g},
[23] = {b.y, nil, b.g, b.g, b.g, b.g, b.o, b.y, nil, b.g},
[24] = {nil, b.M, b.g, b.g, b.g, b.g, b.g, b.o, b.R, nil},
},
}
local STAGE_TRANSITION_TIME = 300
function SakuraGame:new()
self.super:new()
self.randomizer = SakuraRandomizer()
self.current_map = 1
self.time_limit = 10800
self.cleared_frames = STAGE_TRANSITION_TIME
self.stage_frames = 0
self.time_extend = 0
self.maps_cleared = 0
self.map_20_time = 0
self.stage_pieces = 0
self.grid:applyMap(maps[self.current_map])
self.lock_drop = true
self.lock_hard_drop = true
self.enable_hold = true
self.next_queue_length = 3
end
function SakuraGame:checkRequirements()
if self.maps_cleared >= 14 + 2 * (self.current_map - 20) and
self.map_20_time <= frameTime(8,00) - frameTime(0,30) * (self.current_map - 20)
then
return false
end
return true
end
function SakuraGame:getGravity()
if self.level < 8 then return 4/256
elseif self.level < 19 then return 5/256
elseif self.level < 35 then return 6/256
elseif self.level < 40 then return 8/256
elseif self.level < 50 then return 10/256
elseif self.level < 60 then return 12/256
elseif self.level < 70 then return 16/256
elseif self.level < 80 then return 32/256
elseif self.level < 90 then return 48/256
elseif self.level < 100 then return 64/256
elseif self.level < 108 then return 4/256
elseif self.level < 119 then return 5/256
elseif self.level < 125 then return 6/256
elseif self.level < 131 then return 8/256
elseif self.level < 139 then return 12/256
elseif self.level < 149 then return 32/256
elseif self.level < 156 then return 48/256
elseif self.level < 164 then return 80/256
elseif self.level < 174 then return 112/256
elseif self.level < 180 then return 128/256
elseif self.level < 200 then return 144/256
elseif self.level < 212 then return 16/256
elseif self.level < 221 then return 48/256
elseif self.level < 232 then return 80/256
elseif self.level < 244 then return 112/256
elseif self.level < 256 then return 144/256
elseif self.level < 267 then return 176/256
elseif self.level < 277 then return 192/256
elseif self.level < 287 then return 208/256
elseif self.level < 295 then return 224/256
elseif self.level < 300 then return 240/256
else return 20 end
end
function SakuraGame:onLineClear(cleared_row_count)
self.level = self.level + cleared_row_count
for i = 13, 24 do
for j = 1, 10 do
local block = self.grid.grid[i][j]
if block and block.skin == "gem" and block.colour == "X" then
self.time_limit = self.time_limit + 60
end
end
end
end
function SakuraGame:onPieceEnter()
if self.level % 100 ~= 99 and not self.clear and self.stage_frames ~= 0 then
self.level = self.level + 1
end
if effects[self.current_map] == "mirror" and
self.stage_pieces % 3 == 0 and self.stage_pieces ~= 0
then
self.grid:mirror()
end
self.stage_pieces = self.stage_pieces + 1
end
function SakuraGame:advanceOneFrame(inputs, ruleset)
if self.ready_frames == 0 then
if self.lcd > 0 then
if self.stage_frames <= frameTime(0,10) then self.time_extend = 600
elseif self.stage_frames <= frameTime(0,30) then self.time_extend = 300
else self.time_extend = 0 end
end
if not self.grid:hasGemBlocks() or
(self.stage_frames >= 3600 and self.current_map <= 20) then
self.lcd = 0
self.are = 0
if self.stage_frames >= 3600 then self.time_extend = 0 end
self.piece = nil
-- transition to next map
if self.cleared_frames > 0 then
self.cleared_frames = self.cleared_frames - 1
if self.time_extend > 0 then
self.time_limit = self.time_limit + 3
self.time_extend = self.time_extend - 3
end
return false
end
self.hold_queue = nil
if self.current_map > 20 or (self.stage_frames < 3600 and self.current_map <= 20) then self.maps_cleared = self.maps_cleared + 1 end
self.stage_frames = -1
self.level = 0
self.grid:clear()
if (self.current_map == 20) then self.map_20_time = self.frames end
if self.current_map >= 20 and self:checkRequirements() then
self.clear = true
self.completed = true
return false
else
self.current_map = self.current_map + 1
self.big_mode = effects[self.current_map] == "big"
self.ready_frames = 100
self.stage_pieces = 0
self.grid:applyMap(maps[self.current_map])
end
-- this is necessary to fix timer
self.frames = self.frames - 1
self.time_limit = self.time_limit + 1
end
self.frames = self.frames + 1
self.stage_frames = self.stage_frames + 1
self.time_limit = self.time_limit - 1
if self.time_limit <= 0 then self.game_over = true end
if self.piece ~= nil and self.frames % 30 == 0 and
effects[self.current_map] == "roll"
then
ruleset:attemptRotate(
{[config.gamesettings.world_reverse == 3 or
(ruleset.world and config.gamesettings.world_reverse == 2)
and "rotate_left" or "rotate_right"] = true},
self.piece, self.grid, false
)
end
else
self.cleared_frames = STAGE_TRANSITION_TIME
if not self.prev_inputs.hold and inputs.hold then
self.hold_queue = table.remove(self.next_queue, 1)
table.insert(self.next_queue, self:getNextPiece(ruleset))
end
end
return true
end
local function colourXRay(game, block, x, y, age)
local r, g, b, a = .5,.5,.5
if ((game.stage_frames/2 - x) % 30 < 1)
or game.stage_frames == 0
or game.cleared_frames ~= STAGE_TRANSITION_TIME
or game.stage_pieces % 2 == 0
then
a = 1
else
a = 1 - age / 4
end
return r, g, b, a, a
end
local function colourColor(game, block, x, y, age)
local r, g, b, a = .5,.5,.5
if game.stage_frames == 0 or game.cleared_frames ~= STAGE_TRANSITION_TIME then
a = 1
else
a = (game.stage_frames/30 + (y + math.abs(x-5.5))/5) % 1
end
return r, g, b, a, 0
end
function SakuraGame:drawGrid()
if effects[self.current_map] == "xray" then
self.grid:drawCustom(colourXRay, self)
elseif effects[self.current_map] == "color" then
self.grid:drawCustom(colourColor, self)
else
self.grid:draw()
-- if self.piece ~= nil and self.level < 100 then
self:drawGhostPiece(ruleset)
-- end
end
end
function SakuraGame:drawScoringInfo()
love.graphics.setColor(1, 1, 1, 1)
love.graphics.setFont(font_3x5_2)
love.graphics.print(
self.das.direction .. " " ..
self.das.frames .. " " ..
strTrueValues(self.prev_inputs)
)
love.graphics.printf("NEXT", 64, 40, 40, "left")
love.graphics.printf("STAGE", 240, 120, 80, "left")
love.graphics.printf("TIME LIMIT", 240, 180, 80, "left")
love.graphics.printf("LEVEL", 240, 320, 40, "left")
if self.current_map <= 20 then
love.graphics.printf("STAGE LIMIT", 240, 240, 100, "left")
end
if effects[self.current_map] then
love.graphics.printf("EFFECT: " .. effects[self.current_map], 240, 300, 160, "left")
end
love.graphics.setFont(font_3x5_3)
love.graphics.setColor(
(self.time_limit % 4 < 2 and
self.time_limit <= frameTime(0,10) and
self.grid:hasGemBlocks() and
self.time_limit ~= 0) and
{ 1, 0.3, 0.3, 1 } or
{ 1, 1, 1, 1 }
)
love.graphics.printf(formatTime(self.time_limit), 240, 200, 120, "left")
love.graphics.setColor(1, 1, 1, 1)
if self.current_map <= 20 then
love.graphics.printf(formatTime(3600 - self.stage_frames), 240, 260, 120, "left")
end
love.graphics.printf(self.level, 240, 340, 40, "right")
love.graphics.printf(math.floor((self.level + 100) / 100) * 100, 240, 370, 40, "right")
love.graphics.setFont(font_8x11)
love.graphics.printf(formatTime(self.frames), 64, 420, 160, "center")
love.graphics.printf(self.current_map, 290, 110, 80, "left")
end
function SakuraGame:drawCustom()
love.graphics.setColor(1, 1, 1, 1)
if self.ready_frames ~= 0 and not self.clear then
love.graphics.setFont(font_3x5_4)
love.graphics.printf("STAGE " .. self.current_map, 64, 170, 160, "center")
love.graphics.setFont(font_3x5_3)
if effects[self.current_map] then
love.graphics.printf("EFFECT: " .. effects[self.current_map], 64, 270, 160, "center")
end
end
if self.cleared_frames > 0 and
(not self.grid:hasGemBlocks() or
(self.stage_frames >= 3600 and self.current_map <= 20)) then
love.graphics.setFont(font_3x5_2)
love.graphics.printf("TIME LIMIT", 64, 180, 160, "center")
love.graphics.printf("TIME EXTEND", 64, 240, 160, "center")
love.graphics.printf("STAGE TIME", 64, 300, 160, "center")
love.graphics.setFont(font_3x5_3)
love.graphics.printf("STAGE " .. self.current_map, 64, 100, 160, "center")
love.graphics.setColor(
self.cleared_frames % 4 < 2 and
{ 1, 1, 0.3, 1 } or
{ 1, 1, 1, 1 }
)
love.graphics.printf(formatTime(self.time_limit), 64, 200, 160, "center")
love.graphics.setColor(1, 1, 1, 1)
love.graphics.printf(formatTime(self.time_extend), 64, 260, 160, "center")
love.graphics.printf(formatTime(self.stage_frames), 64, 320, 160, "center")
love.graphics.setFont(font_3x5_4)
love.graphics.printf((self.stage_frames >= 3600 and self.current_map <= 20) and "" or "CLEAR!", 64, 130, 160, "center")
end
if self.clear then
love.graphics.setFont(font_3x5_3)
love.graphics.printf("EXCELLENT!", 64, 180, 160, "center")
love.graphics.setFont(font_3x5_2)
if self.current_map ~= 27 then
love.graphics.printf("...but let's go\nbetter next time", 64, 220, 160, "center")
end
end
end
function SakuraGame:getBackground()
return (self.current_map - 1) % 20
end
function SakuraGame:getHighscoreData()
return {
maps = self.maps_cleared,
current_map = self.current_map,
frames = self.frames,
}
end
return SakuraGame

View File

@@ -159,8 +159,9 @@ function SurvivalA2Game:drawScoringInfo()
love.graphics.setFont(font_3x5_3)
love.graphics.printf(self.score, text_x, 220, 90, "left")
if self.roll_frames > 2968 then love.graphics.setColor(1, 0.5, 0, 1)
elseif self.clear then love.graphics.setColor(0, 1, 0, 1) end
elseif self.level >= 999 and self.clear then love.graphics.setColor(0, 1, 0, 1) end
if self:getLetterGrade() ~= "" then love.graphics.printf(self:getLetterGrade(), text_x, 140, 90, "left") end
love.graphics.setColor(1, 1, 1, 1)
love.graphics.printf(self.level, text_x, 340, 40, "right")
love.graphics.printf(self:getSectionEndLevel(), text_x, 370, 40, "right")
if sg >= 5 then

View File

@@ -243,7 +243,7 @@ function SurvivalA3Game:drawScoringInfo()
love.graphics.setFont(font_3x5_3)
if self.roll_frames > 3238 then love.graphics.setColor(1, 0.5, 0, 1)
elseif self.clear then love.graphics.setColor(0, 1, 0, 1) end
elseif self.level >= 1300 and self.clear then love.graphics.setColor(0, 1, 0, 1) end
love.graphics.printf(getLetterGrade(math.floor(self.grade)), text_x, 140, 90, "left")
love.graphics.setColor(1, 1, 1, 1)
love.graphics.printf(self.score, text_x, 220, 90, "left")

View File

@@ -0,0 +1,16 @@
local Randomizer = require 'tetris.randomizers.randomizer'
local Sequence = Randomizer:extend()
function Sequence:initialize()
self.sequence = "IJLOT"
self.counter = 0
end
function Sequence:generatePiece()
local piece = string.sub(self.sequence, self.counter + 1, self.counter + 1)
self.counter = (self.counter + 1) % string.len(self.sequence)
return piece
end
return Sequence

View File

@@ -0,0 +1,10 @@
local Sequence = require 'tetris.randomizers.fixed_sequence'
local Sakura = Sequence:extend()
function Sakura:initialize()
self.super:initialize()
self.sequence = "LIJOTSZILJOTISJZLOIJSZTIOJZTLSOZTISOLTJSIZTOJLIZSTOIZLTJOSILTZSOITJLZSTJJISOLJITSLZOIZSJOITSZLJTSZLISTJLZOTIOZSJILTZSOITZJSOLTJSZIOJLZIOJTZIZLOSIZTJOILZSOJIOSZTJILOSSILZOTJIZTSOLZTSOIJTZSILTZOSIJZTOLJISOLJTZSOLTZJSOTILZJTOLZIJSOZTJLOZSTLOZITSOLZTJIOSLZJTO"
end
return Sakura

View File

@@ -97,11 +97,11 @@ function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid)
-- kick right, kick left
if (grid:canPlacePiece(new_piece:withOffset({x=1, y=0}))) then
self:onPieceRotate(piece, grid)
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
self:onPieceRotate(piece, grid)
elseif (grid:canPlacePiece(new_piece:withOffset({x=-1, y=0}))) then
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
self:onPieceRotate(piece, grid)
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
end
end

View File

@@ -1,5 +1,5 @@
local Piece = require 'tetris.components.piece'
local Ruleset = require 'tetris.rulesets.ruleset'
local Ruleset = require 'tetris.rulesets.arika_ti'
local ARS = Ruleset:extend()
@@ -39,137 +39,17 @@ ARS.big_spawn_positions = {
Z = { x=2, y=1 },
}
ARS.block_offsets = {
I={
{ {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} },
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=0, y=2} },
{ {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} },
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=0, y=2} },
},
J={
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=-1, y=-1} },
{ {x=0, y=-1}, {x=1, y=-2}, {x=0, y=-2}, {x=0, y=0} },
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=1, y=0} },
{ {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=-1, y=0} },
},
L={
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=1, y=-1} },
{ {x=0, y=-2}, {x=0, y=-1}, {x=1, y=0}, {x=0, y=0} },
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=-1, y=0} },
{ {x=0, y=-1}, {x=-1, y=-2}, {x=0, y=-2}, {x=0, y=0} },
},
O={
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
},
S={
{ {x=1, y=-1}, {x=0, y=-1}, {x=0, y=0}, {x=-1, y=0} },
{ {x=-1, y=-2}, {x=-1, y=-1}, {x=0, y=-1}, {x=0, y=0} },
{ {x=1, y=-1}, {x=0, y=-1}, {x=0, y=0}, {x=-1, y=0} },
{ {x=-1, y=-2}, {x=-1, y=-1}, {x=0, y=-1}, {x=0, y=0} },
},
T={
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=0, y=-1} },
{ {x=0, y=-1}, {x=0, y=0}, {x=1, y=-1}, {x=0, y=-2} },
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=0, y=0} },
{ {x=0, y=-1}, {x=0, y=0}, {x=-1, y=-1}, {x=0, y=-2} },
},
Z={
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=0}, {x=0, y=0} },
{ {x=0, y=-1}, {x=0, y=0}, {x=1, y=-2}, {x=1, y=-1} },
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=0}, {x=0, y=0} },
{ {x=0, y=-1}, {x=0, y=0}, {x=1, y=-2}, {x=1, y=-1} },
}
}
-- Component functions.
function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid)
-- O doesn't kick
if (piece.shape == "O") then return end
-- center column rule
if (
piece.shape == "J" or piece.shape == "T" or piece.shape == "L"
) and (
piece.rotation == 0 or piece.rotation == 2
) then
local offsets = new_piece:getBlockOffsets()
table.sort(offsets, function(A, B) return A.y < B.y or A.y == B.y and A.x < B.y end)
for index, offset in pairs(offsets) do
if grid:isOccupied(piece.position.x + offset.x, piece.position.y + offset.y) then
if offset.x == 0 then
return
else
break
end
end
end
end
if piece.shape == "I" then
-- special kick rules for I
if new_piece.rotation == 0 or new_piece.rotation == 2 then
-- kick right, right2, left
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
self:onPieceRotate(piece, grid)
elseif grid:canPlacePiece(new_piece:withOffset({x=2, y=0})) then
piece:setRelativeRotation(rot_dir):setOffset({x=2, y=0})
self:onPieceRotate(piece, grid)
elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
self:onPieceRotate(piece, grid)
end
elseif piece:isDropBlocked(grid) and (new_piece.rotation == 1 or new_piece.rotation == 3) and piece.floorkick == 0 then
-- kick up, up2
if grid:canPlacePiece(new_piece:withOffset({x=0, y=-1})) then
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
self:onPieceRotate(piece, grid)
piece.floorkick = 1
elseif grid:canPlacePiece(new_piece:withOffset({x=0, y=-2})) then
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-2})
self:onPieceRotate(piece, grid)
piece.floorkick = 1
end
end
else
-- kick right, kick left
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
elseif piece.shape == "T"
and new_piece.rotation == 0
and piece.floorkick == 0
and grid:canPlacePiece(new_piece:withOffset({x=0, y=-1}))
then
-- T floorkick
piece.floorkick = piece.floorkick + 1
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
end
end
end
function ARS:onPieceCreate(piece, grid)
piece.floorkick = 0
piece.manipulations = 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.manipulations = piece.manipulations + 1
if piece.manipulations >= 127 then
if piece.manipulations >= 128 then
piece:dropToBottom(grid)
piece.locked = true
end
end
@@ -179,20 +59,14 @@ function ARS:onPieceRotate(piece, grid)
piece.lock_delay = 0 -- rotate reset
if piece:isDropBlocked(grid) then
piece.manipulations = piece.manipulations + 1
if piece.manipulations >= 127 then
if piece.manipulations >= 128 then
piece:dropToBottom(grid)
piece.locked = true
end
end
if piece.floorkick >= 1 then
piece.floorkick = piece.floorkick + 1
end
end
function ARS:get180RotationValue()
if config.gamesettings.world_reverse == 3 then
return 1
else
return 3
end
end
function ARS:getDefaultOrientation() return 3 end -- downward facing pieces by default
return ARS

View File

@@ -1,5 +1,5 @@
local Piece = require 'tetris.components.piece'
local Ruleset = require 'tetris.rulesets.ruleset'
local Ruleset = require 'tetris.rulesets.arika_ti'
local ARS = Ruleset:extend()
@@ -26,137 +26,17 @@ ARS.big_spawn_positions = {
Z = { x=2, y=1 },
}
ARS.block_offsets = {
I={
{ {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} },
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=0, y=2} },
{ {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} },
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=0, y=2} },
},
J={
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=-1, y=-1} },
{ {x=0, y=-1}, {x=1, y=-2}, {x=0, y=-2}, {x=0, y=0} },
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=1, y=0} },
{ {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=-1, y=0} },
},
L={
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=1, y=-1} },
{ {x=0, y=-2}, {x=0, y=-1}, {x=1, y=0}, {x=0, y=0} },
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=-1, y=0} },
{ {x=0, y=-1}, {x=-1, y=-2}, {x=0, y=-2}, {x=0, y=0} },
},
O={
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
},
S={
{ {x=1, y=-1}, {x=0, y=-1}, {x=0, y=0}, {x=-1, y=0} },
{ {x=-1, y=-2}, {x=-1, y=-1}, {x=0, y=-1}, {x=0, y=0} },
{ {x=1, y=-1}, {x=0, y=-1}, {x=0, y=0}, {x=-1, y=0} },
{ {x=-1, y=-2}, {x=-1, y=-1}, {x=0, y=-1}, {x=0, y=0} },
},
T={
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=0, y=-1} },
{ {x=0, y=-1}, {x=0, y=0}, {x=1, y=-1}, {x=0, y=-2} },
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=0, y=0} },
{ {x=0, y=-1}, {x=0, y=0}, {x=-1, y=-1}, {x=0, y=-2} },
},
Z={
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=0}, {x=0, y=0} },
{ {x=0, y=-1}, {x=0, y=0}, {x=1, y=-2}, {x=1, y=-1} },
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=0}, {x=0, y=0} },
{ {x=0, y=-1}, {x=0, y=0}, {x=1, y=-2}, {x=1, y=-1} },
}
}
-- Component functions.
function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid)
-- O doesn't kick
if (piece.shape == "O") then return end
-- center column rule
if (
piece.shape == "J" or piece.shape == "T" or piece.shape == "L"
) and (
piece.rotation == 0 or piece.rotation == 2
) then
local offsets = new_piece:getBlockOffsets()
table.sort(offsets, function(A, B) return A.y < B.y or A.y == B.y and A.x < B.y end)
for index, offset in pairs(offsets) do
if grid:isOccupied(piece.position.x + offset.x, piece.position.y + offset.y) then
if offset.x == 0 then
return
else
break
end
end
end
end
if piece.shape == "I" then
-- special kick rules for I
if new_piece.rotation == 0 or new_piece.rotation == 2 then
-- kick right, right2, left
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
self:onPieceRotate(piece, grid)
elseif grid:canPlacePiece(new_piece:withOffset({x=2, y=0})) then
piece:setRelativeRotation(rot_dir):setOffset({x=2, y=0})
self:onPieceRotate(piece, grid)
elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
self:onPieceRotate(piece, grid)
end
elseif piece:isDropBlocked(grid) and (new_piece.rotation == 1 or new_piece.rotation == 3) and piece.floorkick == 0 then
-- kick up, up2
if grid:canPlacePiece(new_piece:withOffset({x=0, y=-1})) then
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
self:onPieceRotate(piece, grid)
piece.floorkick = 1
elseif grid:canPlacePiece(new_piece:withOffset({x=0, y=-2})) then
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-2})
self:onPieceRotate(piece, grid)
piece.floorkick = 1
end
end
else
-- kick right, kick left
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
elseif piece.shape == "T"
and new_piece.rotation == 0
and piece.floorkick == 0
and grid:canPlacePiece(new_piece:withOffset({x=0, y=-1}))
then
-- T floorkick
piece.floorkick = piece.floorkick + 1
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
end
end
end
function ARS:onPieceCreate(piece, grid)
piece.floorkick = 0
piece.manipulations = 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.manipulations = piece.manipulations + 1
if piece.manipulations >= 127 then
if piece.manipulations >= 128 then
piece:dropToBottom(grid)
piece.locked = true
end
end
@@ -166,20 +46,14 @@ function ARS:onPieceRotate(piece, grid)
piece.lock_delay = 0 -- rotate reset
if piece:isDropBlocked(grid) then
piece.manipulations = piece.manipulations + 1
if piece.manipulations >= 127 then
if piece.manipulations >= 128 then
piece:dropToBottom(grid)
piece.locked = true
end
end
if piece.floorkick >= 1 then
piece.floorkick = piece.floorkick + 1
end
end
function ARS:get180RotationValue()
if config.gamesettings.world_reverse == 3 then
return 1
else
return 3
end
end
function ARS:getDefaultOrientation() return 3 end -- downward facing pieces by default
return ARS

View File

@@ -1,22 +1,12 @@
local Piece = require 'tetris.components.piece'
local Ruleset = require 'tetris.rulesets.ruleset'
local Ruleset = require 'tetris.rulesets.ti_srs'
local SRS = Ruleset:extend()
SRS.name = "ACE-SRS"
SRS.hash = "ACE Standard"
SRS.world = true
SRS.colourscheme = {
I = "C",
L = "O",
J = "B",
S = "G",
Z = "R",
O = "Y",
T = "M",
}
SRS.softdrop_lock = false
SRS.harddrop_lock = true
SRS.MANIPULATIONS_MAX = 128
SRS.spawn_positions = {
I = { x=5, y=2 },
@@ -38,158 +28,14 @@ SRS.big_spawn_positions = {
Z = { x=2, y=1 },
}
SRS.block_offsets = {
I={
{ {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} },
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=0, y=2} },
{ {x=0, y=1}, {x=-1, y=1}, {x=-2, y=1}, {x=1, y=1} },
{ {x=-1, y=0}, {x=-1, y=-1}, {x=-1, y=1}, {x=-1, y=2} },
},
J={
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=-1, y=-1} },
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1} , {x=1, y=-1} },
{ {x=0, y=0}, {x=1, y=0}, {x=-1, y=0}, {x=1, y=1} },
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=-1}, {x=-1, y=1} },
},
L={
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=1, y=-1} },
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=1, y=1} },
{ {x=0, y=0}, {x=1, y=0}, {x=-1, y=0}, {x=-1, y=1} },
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=-1}, {x=-1, y=-1} },
},
O={
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
},
S={
{ {x=1, y=-1}, {x=0, y=-1}, {x=0, y=0}, {x=-1, y=0} },
{ {x=1, y=1}, {x=1, y=0}, {x=0, y=0}, {x=0, y=-1} },
{ {x=-1, y=1}, {x=0, y=1}, {x=0, y=0}, {x=1, y=0} },
{ {x=-1, y=-1}, {x=-1, y=0}, {x=0, y=0}, {x=0, y=1} },
},
T={
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=0, y=-1} },
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=1, y=0} },
{ {x=0, y=0}, {x=1, y=0}, {x=-1, y=0}, {x=0, y=1} },
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=-1}, {x=-1, y=0} },
},
Z={
{ {x=-1, y=-1}, {x=0, y=-1}, {x=0, y=0}, {x=1, y=0} },
{ {x=1, y=-1}, {x=1, y=0}, {x=0, y=0}, {x=0, y=1} },
{ {x=1, y=1}, {x=0, y=1}, {x=0, y=0}, {x=-1, y=0} },
{ {x=-1, y=1}, {x=-1, y=0}, {x=0, y=0}, {x=0, y=-1} },
}
}
SRS.wallkicks_3x3 = {
[0]={
[1]={{x=-1, y=0}, {x=-1, y=-1}, {x=0, y=2}, {x=-1, y=2}},
[2]={{x=0, y=1}, {x=0, y=-1}},
[3]={{x=1, y=0}, {x=1, y=-1}, {x=0, y=2}, {x=1, y=2}},
},
[1]={
[0]={{x=1, y=0}, {x=1, y=1}, {x=0, y=-2}, {x=1, y=-2}},
[2]={{x=1, y=0}, {x=1, y=1}, {x=0, y=-2}, {x=1, y=-2}},
[3]={{x=0, y=1}, {x=0, y=-1}},
},
[2]={
[0]={{x=0, y=1}, {x=0, y=-1}},
[1]={{x=-1, y=0}, {x=-1, y=-1}, {x=0, y=2}, {x=-1, y=2}},
[3]={{x=1, y=0}, {x=1, y=-1}, {x=0, y=2}, {x=1, y=2}},
},
[3]={
[0]={{x=-1, y=0}, {x=-1, y=1}, {x=0, y=-2}, {x=-1, y=-2}},
[1]={{x=0, y=1}, {x=0, y=-1}},
[2]={{x=-1, y=0}, {x=-1, y=1}, {x=0, y=-2}, {x=-1, y=-2}},
},
};
SRS.wallkicks_line = {
[0]={
[1]={{x=-2, y= 0}, {x= 1, y= 0}, {x= 1, y=-2}, {x=-2, y= 1}},
[2]={},
[3]={{x= 2, y= 0}, {x=-1, y= 0}, {x=-1, y=-2}, {x= 2, y= 1}},
},
[1]={
[0]={{x= 2, y= 0}, {x=-1, y= 0}, {x= 2, y=-1}, {x=-1, y= 2}},
[2]={{x=-1, y= 0}, {x= 2, y= 0}, {x=-1, y=-2}, {x= 2, y= 1}},
[3]={},
},
[2]={
[0]={},
[1]={{x=-2, y= 0}, {x= 1, y= 0}, {x=-2, y=-1}, {x= 1, y= 1}},
[3]={{x= 2, y= 0}, {x=-1, y= 0}, {x= 2, y=-1}, {x=-1, y= 1}},
},
[3]={
[0]={{x=-2, y= 0}, {x= 1, y= 0}, {x=-2, y=-1}, {x= 1, y= 2}},
[1]={},
[2]={{x= 1, y= 0}, {x=-2, y= 0}, {x= 1, y=-2}, {x=-2, y= 1}},
},
};
-- Component functions.
function SRS:attemptWallkicks(piece, new_piece, rot_dir, grid)
local kicks
if piece.shape == "O" then
return
elseif piece.shape == "I" then
kicks = SRS.wallkicks_line[piece.rotation][new_piece.rotation]
else
kicks = SRS.wallkicks_3x3[piece.rotation][new_piece.rotation]
end
assert(piece.rotation ~= new_piece.rotation)
for idx, offset in pairs(kicks) do
kicked_piece = new_piece:withOffset(offset)
if grid:canPlacePiece(kicked_piece) then
piece:setRelativeRotation(rot_dir)
piece:setOffset(offset)
self:onPieceRotate(piece, grid)
return
end
end
end
function SRS:onPieceCreate(piece, grid)
piece.manipulations = 0
end
function SRS:onPieceDrop(piece, grid)
piece.lock_delay = 0 -- step reset
end
function SRS:onPieceMove(piece, grid)
piece.lock_delay = 0 -- move reset
if piece:isDropBlocked(grid) then
piece.manipulations = piece.manipulations + 1
if piece.manipulations >= 127 then
piece.locked = true
end
end
end
function SRS:onPieceRotate(piece, grid)
piece.lock_delay = 0 -- rotate reset
if piece:isDropBlocked(grid) then
piece.manipulations = piece.manipulations + 1
if piece.manipulations >= 127 then
piece.manipulations = piece.manipulations + 1
if piece.manipulations >= self.MANIPULATIONS_MAX then
piece.locked = true
end
end
end
function SRS:get180RotationValue()
if config.gamesettings.world_reverse == 1 then
return 1
else
return 3
end
end
return SRS

View File

@@ -1,77 +1,11 @@
local Piece = require 'tetris.components.piece'
local Ruleset = require 'tetris.rulesets.ruleset'
local Ruleset = require 'tetris.rulesets.arika'
local ARS = Ruleset:extend()
ARS.name = "Ti-ARS"
ARS.hash = "ArikaTI"
ARS.spawn_positions = {
I = { x=5, y=4 },
J = { x=4, y=5 },
L = { x=4, y=5 },
O = { x=5, y=5 },
S = { x=4, y=5 },
T = { x=4, y=5 },
Z = { x=4, y=5 },
}
ARS.big_spawn_positions = {
I = { x=3, y=2 },
J = { x=2, y=3 },
L = { x=2, y=3 },
O = { x=3, y=3 },
S = { x=2, y=3 },
T = { x=2, y=3 },
Z = { x=2, y=3 },
}
ARS.block_offsets = {
I={
{ {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} },
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=0, y=2} },
{ {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} },
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=0, y=2} },
},
J={
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=-1, y=-1} },
{ {x=0, y=-1}, {x=1, y=-2}, {x=0, y=-2}, {x=0, y=0} },
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=1, y=0} },
{ {x=0, y=-1}, {x=0, y=-2}, {x=0, y=0}, {x=-1, y=0} },
},
L={
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=1, y=-1} },
{ {x=0, y=-2}, {x=0, y=-1}, {x=1, y=0}, {x=0, y=0} },
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=-1, y=0} },
{ {x=0, y=-1}, {x=-1, y=-2}, {x=0, y=-2}, {x=0, y=0} },
},
O={
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
},
S={
{ {x=1, y=-1}, {x=0, y=-1}, {x=0, y=0}, {x=-1, y=0} },
{ {x=-1, y=-2}, {x=-1, y=-1}, {x=0, y=-1}, {x=0, y=0} },
{ {x=1, y=-1}, {x=0, y=-1}, {x=0, y=0}, {x=-1, y=0} },
{ {x=-1, y=-2}, {x=-1, y=-1}, {x=0, y=-1}, {x=0, y=0} },
},
T={
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=0, y=-1} },
{ {x=0, y=-1}, {x=0, y=0}, {x=1, y=-1}, {x=0, y=-2} },
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=-1}, {x=0, y=0} },
{ {x=0, y=-1}, {x=0, y=0}, {x=-1, y=-1}, {x=0, y=-2} },
},
Z={
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=0}, {x=0, y=0} },
{ {x=0, y=-1}, {x=0, y=0}, {x=1, y=-2}, {x=1, y=-1} },
{ {x=0, y=-1}, {x=-1, y=-1}, {x=1, y=0}, {x=0, y=0} },
{ {x=0, y=-1}, {x=0, y=0}, {x=1, y=-2}, {x=1, y=-1} },
}
}
-- Component functions.
function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid)
@@ -100,43 +34,48 @@ function ARS:attemptWallkicks(piece, new_piece, rot_dir, grid)
if piece.shape == "I" then
-- special kick rules for I
if new_piece.rotation == 0 or new_piece.rotation == 2 then
if (new_piece.rotation == 0 or new_piece.rotation == 2) and
(piece:isMoveBlocked(grid, {x=-1, y=0}) or piece:isMoveBlocked(grid, {x=1, y=0})) then
-- kick right, right2, left
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
self:onPieceRotate(piece, grid)
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
self:onPieceRotate(piece, grid)
elseif grid:canPlacePiece(new_piece:withOffset({x=2, y=0})) then
self:onPieceRotate(piece, grid)
piece:setRelativeRotation(rot_dir):setOffset({x=2, y=0})
self:onPieceRotate(piece, grid)
elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
self:onPieceRotate(piece, grid)
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
end
elseif piece:isDropBlocked(grid) and (new_piece.rotation == 1 or new_piece.rotation == 3) and piece.floorkick == 0 then
-- kick up, up2
if grid:canPlacePiece(new_piece:withOffset({x=0, y=-1})) then
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
self:onPieceRotate(piece, grid)
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
piece.floorkick = 1
elseif grid:canPlacePiece(new_piece:withOffset({x=0, y=-2})) then
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-2})
self:onPieceRotate(piece, grid)
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-2})
piece.floorkick = 1
end
end
else
-- kick right, kick left
if grid:canPlacePiece(new_piece:withOffset({x=1, y=0})) then
self:onPieceRotate(piece, grid)
piece:setRelativeRotation(rot_dir):setOffset({x=1, y=0})
elseif grid:canPlacePiece(new_piece:withOffset({x=-1, y=0})) then
self:onPieceRotate(piece, grid)
piece:setRelativeRotation(rot_dir):setOffset({x=-1, y=0})
elseif piece.shape == "T"
and new_piece.rotation == 0
and piece.floorkick == 0
and piece:isDropBlocked(grid)
and grid:canPlacePiece(new_piece:withOffset({x=0, y=-1}))
then
-- T floorkick
piece.floorkick = piece.floorkick + 1
self:onPieceRotate(piece, grid)
piece:setRelativeRotation(rot_dir):setOffset({x=0, y=-1})
end
end
@@ -149,16 +88,15 @@ end
function ARS:onPieceDrop(piece, grid)
piece.lock_delay = 0 -- step reset
end
function ARS:get180RotationValue()
if config.gamesettings.world_reverse == 3 then
return 1
else
return 3
if piece.floorkick >= 2 and piece:isDropBlocked(grid) then
piece.locked = true
end
end
function ARS:getDefaultOrientation() return 3 end -- downward facing pieces by default
function ARS:onPieceRotate(piece, grid)
if piece.floorkick >= 1 then
piece.floorkick = piece.floorkick + 1
end
end
return ARS

View File

@@ -384,9 +384,9 @@ function CRS:attemptWallkicks(piece, new_piece, rot_dir, grid)
for idx, offset in pairs(kicks) do
kicked_piece = new_piece:withOffset(offset)
if grid:canPlacePiece(kicked_piece) then
self:onPieceRotate(piece, grid)
piece:setRelativeRotation(rot_dir)
piece:setOffset(offset)
self:onPieceRotate(piece, grid)
return
end
end
@@ -406,6 +406,7 @@ function CRS:onPieceMove(piece, grid)
if piece:isDropBlocked(grid) then
piece.move_counter = piece.move_counter + 1
if piece.move_counter >= 24 then
piece:dropToBottom(grid)
piece.locked = true
end
end
@@ -415,6 +416,7 @@ function CRS:onPieceRotate(piece, grid)
if piece:isDropBlocked(grid) then
piece.rotate_counter = piece.rotate_counter + 1
if piece.rotate_counter >= 12 then
piece:dropToBottom(grid)
piece.locked = true
end
end

View File

@@ -128,16 +128,16 @@ function Ruleset:attemptWallkicks(piece, new_piece, rot_dir, grid)
-- do nothing in default ruleset
end
function Ruleset:movePiece(piece, grid, move)
function Ruleset:movePiece(piece, grid, move, instant)
local x = piece.position.x
if move == "left" then
piece:moveInGrid({x=-1, y=0}, 1, grid)
elseif move == "speedleft" then
piece:moveInGrid({x=-1, y=0}, 10, grid)
piece:moveInGrid({x=-1, y=0}, 1, grid, false)
elseif move == "right" then
piece:moveInGrid({x=1, y=0}, 1, grid)
piece:moveInGrid({x=1, y=0}, 1, grid, false)
elseif move == "speedleft" then
piece:moveInGrid({x=-1, y=0}, 10, grid, instant)
elseif move == "speedright" then
piece:moveInGrid({x=1, y=0}, 10, grid)
piece:moveInGrid({x=1, y=0}, 10, grid, instant)
end
if piece.position.x ~= x then
self:onPieceMove(piece, grid)
@@ -197,7 +197,14 @@ function Ruleset:initializePiece(
}, self.block_offsets, 0, 0, data.skin, colours[data.shape], big)
self:onPieceCreate(piece)
if irs then self:rotatePiece(inputs, piece, grid, {}, true) end
if irs then
if inputs.rotate_left or inputs.rotate_left2 or
inputs.rotate_right or inputs.rotate_right2 or
inputs.rotate_180 then
playSE("irs")
end
self:rotatePiece(inputs, piece, grid, {}, true)
end
self:dropPiece(inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked)
return piece
end
@@ -211,8 +218,16 @@ function Ruleset:processPiece(
drop_locked, hard_drop_locked,
hard_drop_enabled, additive_gravity
)
self:rotatePiece(inputs, piece, grid, prev_inputs, false)
self:movePiece(piece, grid, move)
local synchroes_allowed = ({not self.world, true, false})[config.gamesettings.synchroes_allowed]
if synchroes_allowed then
self:rotatePiece(inputs, piece, grid, prev_inputs, false)
self:movePiece(piece, grid, move, gravity >= 20)
else
self:movePiece(piece, grid, move, gravity >= 20)
self:rotatePiece(inputs, piece, grid, prev_inputs, false)
end
self:dropPiece(
inputs, piece, grid, gravity, drop_speed, drop_locked, hard_drop_locked,
hard_drop_enabled, additive_gravity

View File

@@ -1,112 +1,24 @@
local Piece = require 'tetris.components.piece'
local Ruleset = require 'tetris.rulesets.ruleset'
local Ruleset = require 'tetris.rulesets.arika_srs'
local SRS = Ruleset:extend()
SRS.name = "Guideline SRS"
SRS.hash = "Standard"
SRS.world = true
SRS.colourscheme = {
I = "C",
L = "O",
J = "B",
S = "G",
Z = "R",
O = "Y",
T = "M",
}
SRS.softdrop_lock = false
SRS.harddrop_lock = true
SRS.enable_IRS_wallkicks = true
SRS.spawn_positions = {
I = { x=5, y=2 },
J = { x=4, y=3 },
L = { x=4, y=3 },
O = { x=5, y=3 },
S = { x=4, y=3 },
T = { x=4, y=3 },
Z = { x=4, y=3 },
}
SRS.MANIPULATIONS_MAX = 15
SRS.big_spawn_positions = {
I = { x=3, y=0 },
J = { x=2, y=1 },
L = { x=2, y=1 },
O = { x=3, y=1 },
S = { x=2, y=1 },
T = { x=2, y=1 },
Z = { x=2, y=1 },
}
SRS.block_offsets = {
I={
{ {x=0, y=0}, {x=-1, y=0}, {x=-2, y=0}, {x=1, y=0} },
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=0, y=2} },
{ {x=0, y=1}, {x=-1, y=1}, {x=-2, y=1}, {x=1, y=1} },
{ {x=-1, y=0}, {x=-1, y=-1}, {x=-1, y=1}, {x=-1, y=2} },
},
J={
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=-1, y=-1} },
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1} , {x=1, y=-1} },
{ {x=0, y=0}, {x=1, y=0}, {x=-1, y=0}, {x=1, y=1} },
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=-1}, {x=-1, y=1} },
},
L={
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=1, y=-1} },
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=1, y=1} },
{ {x=0, y=0}, {x=1, y=0}, {x=-1, y=0}, {x=-1, y=1} },
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=-1}, {x=-1, y=-1} },
},
O={
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
{ {x=0, y=0}, {x=-1, y=0}, {x=-1, y=-1}, {x=0, y=-1} },
},
S={
{ {x=1, y=-1}, {x=0, y=-1}, {x=0, y=0}, {x=-1, y=0} },
{ {x=1, y=1}, {x=1, y=0}, {x=0, y=0}, {x=0, y=-1} },
{ {x=-1, y=1}, {x=0, y=1}, {x=0, y=0}, {x=1, y=0} },
{ {x=-1, y=-1}, {x=-1, y=0}, {x=0, y=0}, {x=0, y=1} },
},
T={
{ {x=0, y=0}, {x=-1, y=0}, {x=1, y=0}, {x=0, y=-1} },
{ {x=0, y=0}, {x=0, y=-1}, {x=0, y=1}, {x=1, y=0} },
{ {x=0, y=0}, {x=1, y=0}, {x=-1, y=0}, {x=0, y=1} },
{ {x=0, y=0}, {x=0, y=1}, {x=0, y=-1}, {x=-1, y=0} },
},
Z={
{ {x=-1, y=-1}, {x=0, y=-1}, {x=0, y=0}, {x=1, y=0} },
{ {x=1, y=-1}, {x=1, y=0}, {x=0, y=0}, {x=0, y=1} },
{ {x=1, y=1}, {x=0, y=1}, {x=0, y=0}, {x=-1, y=0} },
{ {x=-1, y=1}, {x=-1, y=0}, {x=0, y=0}, {x=0, y=-1} },
}
}
SRS.wallkicks_3x3 = {
[0]={
[1]={{x=-1, y=0}, {x=-1, y=-1}, {x=0, y=2}, {x=-1, y=2}},
[2]={{x=0, y=1}, {x=0, y=-1}},
[3]={{x=1, y=0}, {x=1, y=-1}, {x=0, y=2}, {x=1, y=2}},
},
[1]={
[0]={{x=1, y=0}, {x=1, y=1}, {x=0, y=-2}, {x=1, y=-2}},
[2]={{x=1, y=0}, {x=1, y=1}, {x=0, y=-2}, {x=1, y=-2}},
[3]={{x=0, y=1}, {x=0, y=-1}},
},
[2]={
[0]={{x=0, y=1}, {x=0, y=-1}},
[1]={{x=-1, y=0}, {x=-1, y=-1}, {x=0, y=2}, {x=-1, y=2}},
[3]={{x=1, y=0}, {x=1, y=-1}, {x=0, y=2}, {x=1, y=2}},
},
[3]={
[0]={{x=-1, y=0}, {x=-1, y=1}, {x=0, y=-2}, {x=-1, y=-2}},
[1]={{x=0, y=1}, {x=0, y=-1}},
[2]={{x=-1, y=0}, {x=-1, y=1}, {x=0, y=-2}, {x=-1, y=-2}},
},
};
function SRS:check_new_low(piece)
for _, block in pairs(piece:getBlockOffsets()) do
local y = piece.position.y + block.y
if y > piece.lowest_y then
piece.manipulations = 0
piece.lowest_y = y
end
end
end
SRS.wallkicks_line = {
[0]={
@@ -131,16 +43,6 @@ SRS.wallkicks_line = {
},
};
function SRS:check_new_low(piece)
for _, block in pairs(piece:getBlockOffsets()) do
local y = piece.position.y + block.y
if y > piece.lowest_y then
piece.manipulations = 0
piece.lowest_y = y
end
end
end
-- Component functions.
function SRS:attemptWallkicks(piece, new_piece, rot_dir, grid)
@@ -175,7 +77,7 @@ end
function SRS:onPieceDrop(piece, grid)
self:check_new_low(piece)
if piece.manipulations >= 15 and piece:isDropBlocked(grid) then
if piece.manipulations >= self.MANIPULATIONS_MAX and piece:isDropBlocked(grid) then
piece.locked = true
else
piece.lock_delay = 0 -- step reset
@@ -186,7 +88,7 @@ function SRS:onPieceMove(piece, grid)
piece.lock_delay = 0 -- move reset
if piece:isDropBlocked(grid) then
piece.manipulations = piece.manipulations + 1
if piece.manipulations >= 15 then
if piece.manipulations >= self.MANIPULATIONS_MAX then
piece.locked = true
end
end
@@ -196,11 +98,14 @@ function SRS:onPieceRotate(piece, grid)
piece.lock_delay = 0 -- rotate reset
self:check_new_low(piece)
piece.manipulations = piece.manipulations + 1
if piece:isDropBlocked(grid) then
if piece.manipulations >= 15 then
piece.locked = true
end
end
if piece.manipulations >= self.MANIPULATIONS_MAX then
piece:moveInGrid({ x = 0, y = 1 }, 1, grid)
if piece:isDropBlocked(grid) then
piece.locked = true
end
end
end
function SRS:get180RotationValue() return 2 end
return SRS

View File

@@ -18,6 +18,9 @@ SRS.colourscheme = {
SRS.softdrop_lock = false
SRS.harddrop_lock = true
SRS.MANIPULATIONS_MAX = 10
SRS.ROTATIONS_MAX = 8
SRS.spawn_positions = {
I = { x=5, y=4 },
J = { x=4, y=5 },
@@ -147,9 +150,9 @@ function SRS:attemptWallkicks(piece, new_piece, rot_dir, grid)
for idx, offset in pairs(kicks) do
kicked_piece = new_piece:withOffset(offset)
if grid:canPlacePiece(kicked_piece) then
self:onPieceRotate(piece, grid)
piece:setRelativeRotation(rot_dir)
piece:setOffset(offset)
self:onPieceRotate(piece, grid)
return
end
end
@@ -162,14 +165,18 @@ function SRS:onPieceCreate(piece, grid)
end
function SRS:onPieceDrop(piece, grid)
piece.lock_delay = 0 -- step reset
if (piece.manipulations >= self.MANIPULATIONS_MAX or piece.rotations >= self.ROTATIONS_MAX) and piece:isDropBlocked(grid) then
piece.locked = true
else
piece.lock_delay = 0 -- step reset
end
end
function SRS:onPieceMove(piece, grid)
piece.lock_delay = 0 -- move reset
if piece:isDropBlocked(grid) then
piece.manipulations = piece.manipulations + 1
if piece.manipulations >= 10 then
if piece.manipulations >= self.MANIPULATIONS_MAX then
piece.locked = true
end
end
@@ -178,8 +185,8 @@ end
function SRS:onPieceRotate(piece, grid)
piece.lock_delay = 0 -- rotate reset
if piece:isDropBlocked(grid) then
piece.rotations = piece.rotations + 1
if piece.rotations >= 8 then
piece.rotations = piece.rotations + 1
if piece.rotations >= self.ROTATIONS_MAX then
piece.locked = true
end
end