├── README.md
├── assets
├── 5.png
├── 6.png
├── 7.png
├── About.png
├── audiobg.mp3
├── bg.png
├── main-logo.png
├── meme_logo.png
├── nav-tetris.png
├── nico_logo.png
├── tetris-personalized-logo.png
├── tetris_cyrus.png
└── third-bg.png
├── audio
├── audio.html
└── audioManager.js
├── css
├── FLmode.css
├── cascade.css
├── choose-gamemode.css
├── classic.css
├── fl.css
├── game-layout.css
├── home.css
├── navbar.css
├── revflex.css
├── selcomplex.css
└── timetrial.css
├── html
├── cascade.html
├── classic-mode.html
├── flashlight.html
├── game-layout.html
├── game-mode.html
├── reverse-flex.html
├── script.js
├── select-complex.html
└── timetrial.html
├── index.html
├── modded modes
├── .DS_Store
├── chromatic cascade
│ ├── cascade-mod.html
│ └── chromatic-cascade.js
├── flashlight
│ ├── flashlight-mod.html
│ └── flashlight-mod.js
├── reversed flex
│ ├── reversed-flex-mod.html
│ └── tetrisreverseflex.js
└── time trial
│ ├── timetrial-mod.html
│ └── timetrial.js
└── tetris initialization scripts
├── tetris-noghostblock.js
├── tetris.js
└── tetrominoes.js
/README.md:
--------------------------------------------------------------------------------
1 | # Tetris
2 |
3 | 
4 |
5 | Play here: https://ardnyx.github.io/tetris/
6 |
7 | Note: If one of the game modes load really slow, try restarting the page, loading a different game mode, or playing classic first.
8 |
9 | A custom-made classic tetris + 4 different complex gamemodes. Currently, the website is not available for mobile and it is not meant to be played in it (for now). If there are any issues (aside from the ones that are stated below), please open an issue in the "Issues" tab. You can also open suggestions and advices in this tab, not just issues. As of now, the website still suffers from a few styling issues provided below. However, here are some of their workarounds:
10 |
11 | ## Issues
12 | ### Broken Homepage Format
13 | 
14 | Workaround: For Windows based OS, Press Ctrl - or + to zoom in or out. For MacOS, Cmd - or + to zoom in or out.
15 |
16 | ### Scrollable Gameplay Layout
17 | 
18 | Workaround: For Windows based OS, Press Ctrl - to zoom out. For MacOS, Cmd - to zoom out.
19 |
20 | ## Missing Features
21 | ### Hold
22 | The hold feature proved to be a challenge. We actually "did" manage to implement the hold feature, but one of the challeneges in implementing this feature was clearing out the current tetromino from the place where the hold was initiated. When the "C" key was clicked, it would hold the tetromino, but at the same time, that same tetromino would be stuck at the position where we started the hold, and it would only disappear once a tetromino got into its way. It was weird and we cannot fix it, possibly due to the structure of the tetris gameplay itself not being friendly to feature addition.
23 |
24 | ### Next Tetrominoes
25 | In the recent versions of tetris, you can see what the current tetrominoes are upcoming next. Due to the nature of the Math.random method, we could not formulate the logic to show the upcoming "n" tetrominoes using the method.
26 |
27 | ### Responsiveness and Movement Snap
28 | If you've observed in tetr.io and jstris, when you move a tetromino left or right, the key immediately "responds", like there's a snap. In our version of tetris, you need to hold the left/right keys for about ~~ a second before it registers as a hold. Again, limited by our knowledge as beginners. Because of this, fast and quick plays aren't possible, and you will have a hard time in the Chromatic Cascade mode at higher levels, where the tetrominoes drop faster.
29 |
30 | ## The Team, MJ's Servants
31 | Quilatan, Marcis Joseph - Team Leader, and Time Trial & Reversed Flex Mod Developer
32 | Tagle, Jel Kyann - Programmer and Lead Design Artist
33 | Leyesa, Dann Martin (ardnyx ) - Lead Developer and Control Manager
34 | Diazana, Darren - Design and Concept Artist
35 | De Gula, Kerby Brent - Flashlight Mod Developer
36 | Mercado, Nico - Chromatic Cascade Mod Developer
37 | Samaco, Cyrus - Features Developer
38 |
--------------------------------------------------------------------------------
/assets/5.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ardnyx/tetris/1cb2a67ec41871c951b03ecebc59bf2b7bf0f4f1/assets/5.png
--------------------------------------------------------------------------------
/assets/6.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ardnyx/tetris/1cb2a67ec41871c951b03ecebc59bf2b7bf0f4f1/assets/6.png
--------------------------------------------------------------------------------
/assets/7.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ardnyx/tetris/1cb2a67ec41871c951b03ecebc59bf2b7bf0f4f1/assets/7.png
--------------------------------------------------------------------------------
/assets/About.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ardnyx/tetris/1cb2a67ec41871c951b03ecebc59bf2b7bf0f4f1/assets/About.png
--------------------------------------------------------------------------------
/assets/audiobg.mp3:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ardnyx/tetris/1cb2a67ec41871c951b03ecebc59bf2b7bf0f4f1/assets/audiobg.mp3
--------------------------------------------------------------------------------
/assets/bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ardnyx/tetris/1cb2a67ec41871c951b03ecebc59bf2b7bf0f4f1/assets/bg.png
--------------------------------------------------------------------------------
/assets/main-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ardnyx/tetris/1cb2a67ec41871c951b03ecebc59bf2b7bf0f4f1/assets/main-logo.png
--------------------------------------------------------------------------------
/assets/meme_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ardnyx/tetris/1cb2a67ec41871c951b03ecebc59bf2b7bf0f4f1/assets/meme_logo.png
--------------------------------------------------------------------------------
/assets/nav-tetris.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ardnyx/tetris/1cb2a67ec41871c951b03ecebc59bf2b7bf0f4f1/assets/nav-tetris.png
--------------------------------------------------------------------------------
/assets/nico_logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ardnyx/tetris/1cb2a67ec41871c951b03ecebc59bf2b7bf0f4f1/assets/nico_logo.png
--------------------------------------------------------------------------------
/assets/tetris-personalized-logo.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ardnyx/tetris/1cb2a67ec41871c951b03ecebc59bf2b7bf0f4f1/assets/tetris-personalized-logo.png
--------------------------------------------------------------------------------
/assets/tetris_cyrus.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ardnyx/tetris/1cb2a67ec41871c951b03ecebc59bf2b7bf0f4f1/assets/tetris_cyrus.png
--------------------------------------------------------------------------------
/assets/third-bg.png:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ardnyx/tetris/1cb2a67ec41871c951b03ecebc59bf2b7bf0f4f1/assets/third-bg.png
--------------------------------------------------------------------------------
/audio/audio.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Audio Player
7 |
8 |
9 |
10 |
11 |
12 |
--------------------------------------------------------------------------------
/audio/audioManager.js:
--------------------------------------------------------------------------------
1 | class AudioManager {
2 | constructor() {
3 | this.audioElement = null;
4 | this.fadeDuration = 2; // Fade duration in seconds
5 | this.initAudio();
6 | }
7 |
8 | initAudio() {
9 | if (document.getElementById('bgMusic')) {
10 | this.audioElement = document.getElementById('bgMusic');
11 | } else {
12 | this.audioElement = document.createElement('audio');
13 | this.audioElement.id = 'bgMusic';
14 | this.audioElement.autoplay = true;
15 | this.audioElement.loop = true;
16 | this.audioElement.src = '../assets/audiobg.mp3';
17 | document.body.appendChild(this.audioElement);
18 | }
19 | this.loadAudioState();
20 | }
21 |
22 | loadAudioState() {
23 | const savedTime = localStorage.getItem('audioCurrentTime');
24 | if (savedTime) {
25 | this.audioElement.currentTime = savedTime;
26 | }
27 | this.fadeIn();
28 | }
29 |
30 | saveAudioState() {
31 | localStorage.setItem('audioCurrentTime', this.audioElement.currentTime);
32 | }
33 |
34 | fadeIn() {
35 | const fadeSteps = this.fadeDuration * 60; // Number of fade steps (assuming 60 fps)
36 | const initialVolume = 0.1; // Initial volume (adjust as needed)
37 | const targetVolume = 1; // Target volume
38 | const volumeStep = (targetVolume - initialVolume) / fadeSteps;
39 | let currentVolume = initialVolume;
40 |
41 | const fadeInterval = setInterval(() => {
42 | currentVolume += volumeStep;
43 | this.audioElement.volume = currentVolume;
44 |
45 | if (currentVolume >= targetVolume) {
46 | clearInterval(fadeInterval);
47 | }
48 | }, 1000 / 60); // Adjust interval for smoother animation
49 | }
50 |
51 | fadeOut() {
52 | const fadeSteps = this.fadeDuration * 60; // Number of fade steps (assuming 60 fps)
53 | const targetVolume = 0.1; // Target volume (adjust as needed)
54 | const initialVolume = this.audioElement.volume;
55 | const volumeStep = (targetVolume - initialVolume) / fadeSteps;
56 | let currentVolume = initialVolume;
57 |
58 | const fadeInterval = setInterval(() => {
59 | currentVolume += volumeStep;
60 | this.audioElement.volume = currentVolume;
61 |
62 | if (currentVolume <= targetVolume) {
63 | clearInterval(fadeInterval);
64 | this.audioElement.pause();
65 | }
66 | }, 1000 / 60); // Adjust interval for smoother animation
67 | }
68 |
69 | stop() {
70 | this.fadeOut();
71 | this.saveAudioState();
72 | }
73 | }
74 |
75 | const audioManager = new AudioManager();
76 | window.addEventListener('beforeunload', () => {
77 | audioManager.saveAudioState();
78 | });
79 |
--------------------------------------------------------------------------------
/css/FLmode.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: #150323;
3 |
4 | }
5 |
6 | .main-container {
7 | display: flex;
8 | justify-content: center;
9 | }
10 |
11 | .game-container {
12 | margin-top: 10px;
13 | display: flex;
14 | justify-content: center;
15 | align-items: center;
16 | gap: 30px;
17 | }
18 |
19 | .game-container .timer {
20 | margin-top: 40px;
21 | align-self: flex-start;
22 | color: white;
23 | font-size: 37px;
24 | }
25 |
26 | .game-over-screen {
27 | display: none;
28 | position: fixed;
29 | top: 0;
30 | left: 0;
31 | width: 100%;
32 | height: 100%;
33 | background: rgba(0, 0, 0, 0.75);
34 | color: white;
35 | display: flex;
36 | flex-direction: column;
37 | justify-content: center;
38 | align-items: center;
39 | z-index: 10;
40 | }
41 |
42 | .game-over-screen h1 {
43 | font-size: 48px;
44 | margin-bottom: 20px;
45 | }
46 |
47 | .game-over-screen button {
48 | font-size: 24px;
49 | padding: 10px 20px;
50 | cursor: pointer;
51 | }
52 |
53 | .light {
54 | position: absolute;
55 | top: 0;
56 | left: 0;
57 | width: 100%;
58 | height: 100%;
59 | pointer-events: none;
60 | background: radial-gradient(circle at var(--x) var(--y), transparent 0%, black 20%);
61 | }
62 |
--------------------------------------------------------------------------------
/css/cascade.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: #340557;
3 | }
4 |
5 | .main-body {
6 | margin-top: 0%;
7 | display: flex;
8 | justify-content: center;
9 | align-items: center;
10 | flex-direction: column;
11 | gap: 50px;
12 | }
13 |
14 | .container-one h1 {
15 | color: #e3e3e3;
16 | font-size: 75px;
17 | }
18 |
19 | .complex-desc {
20 | display: flex;
21 | flex-direction: column;
22 | align-items: center;
23 | justify-content: space-around;
24 | gap: 10px;
25 | }
26 |
27 | .complex-desc h2 {
28 | color: #d29df9;
29 | }
30 |
31 | .complex-desc p {
32 | color: #aea3b6;
33 | font-weight: 700;
34 | }
35 |
36 | .box {
37 | border: 1.3px solid #5c0b97;
38 | display: flex;
39 | background-color: #210437;
40 | color: white;
41 | width: 65%;
42 | height: 190px;
43 | align-items: center;
44 | }
45 |
46 | .box h3 {
47 | width: 80%;
48 | margin-left: 10%;
49 | }
50 |
51 | .box h1 {
52 | font-size: 60px;
53 | text-align: center;
54 | margin-left: 5%;
55 | }
56 |
57 | .back-start{
58 | display: flex;
59 | width: 65%;
60 | gap: 70px;
61 | margin-top: -14px;
62 | }
63 |
64 | .back, .start {
65 | width: 50%;
66 | display: flex;
67 | justify-content: center;
68 | background-color: #210437;
69 | color: white;
70 | height: 90px;
71 | cursor: pointer;
72 | align-items: center;
73 | border: 1px solid #5c0b97;
74 | }
75 |
76 | .back:hover, .start:hover {
77 |
78 | background-color: #340557;
79 |
80 | }
81 |
82 | .back:active, .start:active {
83 |
84 | background-color: #4a067e;
85 |
86 | }
87 |
88 | @keyframes pulse {
89 | 0% { transform: scale(1); }
90 | 50% { transform: scale(1.05); }
91 | 100% { transform: scale(1); }
92 | }
93 |
94 | .start, .back {
95 | padding: 10px;
96 | display: flex;
97 | flex-direction: column;
98 | align-items: center;
99 | justify-content: space-around;
100 | cursor: pointer;
101 | animation: pulse 2s ease-in-out infinite; /* Adjust duration and other animation properties as needed */
102 | }
103 |
--------------------------------------------------------------------------------
/css/choose-gamemode.css:
--------------------------------------------------------------------------------
1 | .main-body {
2 | margin-top: 2%;
3 | display: flex;
4 | justify-content: center;
5 | align-items: center;
6 | flex-direction: column;
7 | gap: 50px;
8 | }
9 |
10 | .classic, .complex {
11 | width: 50%;
12 | height: 130px;
13 | }
14 |
15 | .classic {
16 | margin-bottom: -20px;
17 | background-color: #15295a;
18 | border: 2px solid #1f3c7c;
19 | }
20 | .classic:hover {
21 | margin-bottom: -20px;
22 | background-color: #233d7e;
23 | border: 2px solid #1f3c7c;
24 | width: 60%;
25 | height: 160px;
26 | }
27 | .classic:active {
28 | margin-bottom: -20px;
29 | background-color: #34519b;
30 | border: 2px solid #1f3c7c;
31 | }
32 |
33 |
34 | .complex {
35 | background-color: #340557;
36 | border: 2px solid #40076b;
37 | }
38 |
39 | .complex:hover {
40 | background-color: #450b71;
41 | border: 2px solid #40076b;
42 | width: 60%;
43 | height: 160px;
44 | }
45 |
46 | .complex:active {
47 | background-color: #58178a;
48 | border: 2px solid #40076b;
49 | }
50 |
51 | .container-one h1 {
52 | color: #e3e3e3;
53 | font-size: 75px;
54 | }
55 |
56 | .container {
57 | padding: 10px;
58 | display: flex;
59 | flex-direction: column;
60 | align-items: center;
61 | justify-content: space-around;
62 | cursor: pointer;
63 | }
64 |
65 | .container .title {
66 | color: #f4eded;
67 | font-size: 40px;
68 | }
69 |
70 | .container p {
71 | color: #adb1bb;
72 | font-weight: bold;
73 | }
74 |
75 | hr {
76 | border-top: 1px solid #806f8d;
77 | width: 40%;
78 | }
79 |
80 | @keyframes pulse {
81 | 0% { transform: scale(1); }
82 | 50% { transform: scale(1.05); }
83 | 100% { transform: scale(1); }
84 | }
85 |
86 | .container {
87 | padding: 10px;
88 | display: flex;
89 | flex-direction: column;
90 | align-items: center;
91 | justify-content: space-around;
92 | cursor: pointer;
93 | animation: pulse 2s ease-in-out infinite; /* Adjust duration and other animation properties as needed */
94 | }
95 |
96 |
--------------------------------------------------------------------------------
/css/classic.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: #210437;
3 | }
4 |
5 | .main-body {
6 | margin-top: 0%;
7 | display: flex;
8 | justify-content: center;
9 | align-items: center;
10 | flex-direction: column;
11 | gap: 50px;
12 | }
13 |
14 | .container-one h1 {
15 | color: #e3e3e3;
16 | font-size: 75px;
17 | }
18 |
19 | .box {
20 | border: 1.3px solid #32459c;
21 | display: flex;
22 | background-color: #15295a;
23 | color: white;
24 | width: 65%;
25 | height: 240px;
26 | flex-direction: column;
27 | justify-content: center;
28 | align-items: center;
29 | gap: 13px;
30 | }
31 |
32 | .box h3 {
33 | color: #adb1bb;
34 | text-align: center;
35 | width: 70%;
36 | }
37 |
38 | .box h1 {
39 | font-size: 76px;
40 | text-align: center;
41 | }
42 |
43 | .back-start{
44 | display: flex;
45 | width: 65%;
46 | gap: 70px;
47 | margin-top: -14px;
48 | }
49 |
50 | .back, .start {
51 | width: 50%;
52 | display: flex;
53 | justify-content: center;
54 | background-color: #15295a;
55 | color: white;
56 | height: 90px;
57 | align-items: center;
58 | border: 1.3px solid #32459c;
59 | cursor: pointer;
60 | }
61 |
62 | .back:hover, .start:hover{
63 | background-color: #243d7c;
64 | width: 60%;
65 | height: 100px;
66 |
67 | }
68 |
69 | .back:active, .start:active{
70 | background-color: #3956a0;
71 | width: 60%;
72 | height: 100px;
73 | }
74 |
75 | @keyframes pulse {
76 | 0% { transform: scale(1); }
77 | 50% { transform: scale(1.05); }
78 | 100% { transform: scale(1); }
79 | }
80 |
81 | .back, .start {
82 | padding: 10px;
83 | display: flex;
84 | flex-direction: column;
85 | align-items: center;
86 | justify-content: space-around;
87 | cursor: pointer;
88 | animation: pulse 2s ease-in-out infinite; /* Adjust duration and other animation properties as needed */
89 | }
--------------------------------------------------------------------------------
/css/fl.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: #340557;
3 |
4 | }
5 |
6 | .main-body {
7 | margin-top: 0%;
8 | display: flex;
9 | justify-content: center;
10 | align-items: center;
11 | flex-direction: column;
12 | gap: 50px;
13 | }
14 |
15 | .container-one h1 {
16 | color: #e3e3e3;
17 | font-size: 75px;
18 | }
19 |
20 | .complex-desc {
21 | display: flex;
22 | flex-direction: column;
23 | align-items: center;
24 | justify-content: space-around;
25 | gap: 10px;
26 | }
27 |
28 | .complex-desc h2 {
29 | color: #d29df9;
30 | }
31 |
32 | .complex-desc p {
33 | color: #aea3b6;
34 | font-weight: 700;
35 | }
36 |
37 | .box {
38 | border: 1.3px solid #5c0b97;
39 | display: flex;
40 | background-color: #210437;
41 | color: white;
42 | width: 65%;
43 | height: 190px;
44 | justify-content: center;
45 | align-items: center;
46 | gap: 60px;
47 | }
48 |
49 | .box h3 {
50 | width: 40%;
51 | margin-right: 3%;
52 | }
53 |
54 | .box h1 {
55 | font-size: 70px;
56 | text-align: center;
57 | margin-left: 5%;
58 | }
59 |
60 | .back-start{
61 | display: flex;
62 | width: 65%;
63 | gap: 70px;
64 | margin-top: -14px;
65 | }
66 |
67 | .back, .start {
68 | width: 50%;
69 | display: flex;
70 | justify-content: center;
71 | background-color: #210437;
72 | color: white;
73 | height: 90px;
74 | align-items: center;
75 | cursor: pointer;
76 |
77 | border: 1px solid #5c0b97;
78 | }
79 |
80 | .back:hover, .start:hover {
81 |
82 | background-color: #340557;
83 |
84 | }
85 |
86 | .back:active, .start:active {
87 |
88 | background-color: #4a067e;
89 |
90 | }
91 |
92 | @keyframes pulse {
93 | 0% { transform: scale(1); }
94 | 50% { transform: scale(1.05); }
95 | 100% { transform: scale(1); }
96 | }
97 |
98 | .start, .back {
99 | padding: 10px;
100 | display: flex;
101 | flex-direction: column;
102 | align-items: center;
103 | justify-content: space-around;
104 | cursor: pointer;
105 | animation: pulse 2s ease-in-out infinite; /* Adjust duration and other animation properties as needed */
106 | }
107 |
--------------------------------------------------------------------------------
/css/game-layout.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: #150323;
3 | /* transform: scale(0.88); /* Adjust the scale value to zoom out
4 | transform-origin: top center; Adjust the origin as needed
5 | overflow: hidden;*/
6 | }
7 |
8 |
9 | .main-container {
10 | display: flex;
11 | justify-content: center;
12 | }
13 |
14 | .game-container {
15 | margin-top: 10px;
16 | display: flex;
17 | justify-content: center;
18 | align-items: center;
19 | gap: 30px;
20 | }
21 |
22 | .game-container .timer {
23 | margin-top: 40px;
24 | align-self: flex-start;
25 | color: white;
26 | font-size: 37px;
27 | }
28 |
29 | .game-over-screen {
30 | display: none;
31 | position: fixed;
32 | top: 0;
33 | left: 0;
34 | width: 100%;
35 | height: 100%;
36 | background: rgba(0, 0, 0, 0.75);
37 | color: white;
38 | display: flex;
39 | flex-direction: column;
40 | justify-content: center;
41 | align-items: center;
42 | z-index: 10;
43 | }
44 |
45 | .game-over-screen h1 {
46 | font-size: 48px;
47 | margin-bottom: 20px;
48 | }
49 |
50 | .game-over-screen button {
51 | font-size: 24px;
52 | padding: 10px 20px;
53 | cursor: pointer;
54 | }
55 |
--------------------------------------------------------------------------------
/css/home.css:
--------------------------------------------------------------------------------
1 | body {
2 | margin-top: 70px;
3 | display: flex;
4 | justify-content: center;
5 | align-items: center;
6 | flex-direction: column;
7 | gap: 50px;
8 | overflow-x: hidden;
9 | }
10 |
11 | .header {
12 | position: fixed;
13 | top: 0;
14 | left: 0;
15 | width: 100%;
16 | z-index: 1000;}
17 |
18 | .top-pic {
19 | width: 105%;
20 | height: auto;
21 | margin-top: -36%;
22 | margin-left: -50%;
23 | position: absolute;
24 |
25 | }
26 |
27 | .second-body {
28 | width: 105%;
29 | height: 907.7px;
30 | background-color: #210437;
31 | position: absolute;
32 | margin-top: 116%;
33 | margin-left: 1.8%;
34 | }
35 |
36 | .third-body {
37 | width: 100%;
38 | height: 907.7px;
39 | background-color: #6a0dad;
40 | position: absolute;
41 | margin-top: 243%;
42 | margin-left: -2.2%;
43 | color: #f2ebeb;
44 | }
45 |
46 | .center-logo {
47 | position: absolute;
48 | z-index: 100;
49 | margin-left: -21%;
50 | margin-top: -23%;
51 | width: 45%;
52 | height: auto;
53 | cursor: pointer;
54 | }
55 |
56 | .center-logo:hover {
57 | width: 60%;
58 | margin-left: -29%;
59 | margin-top: -23%;
60 | }
61 |
62 | .play-but {
63 | z-index: 150;
64 | position: absolute;
65 | background-color: #6A0DAD;
66 | border: 2px solid #f2ebeb;
67 | border-radius: 30px;
68 | padding: 1.5% 6%;
69 | color: #f2ebeb;
70 | font-size: 20px;
71 | font-weight: bold;
72 | margin-top: 3%;
73 | }
74 |
75 | .play-but:hover {
76 | background-color: #9938d1;
77 | cursor: pointer;
78 |
79 | }
80 |
81 | .play-but:active {
82 | background-color: #8b4be0;
83 | }
84 |
85 | .about-icon {
86 | z-index: 0;
87 | margin-top: 0%;
88 | position: absolute;
89 | }
90 |
91 | .lower-content, .upper-content {
92 | z-index: 101;
93 | color: #f2ebeb;
94 | }
95 |
96 | .lower-content {
97 | margin-top: 0%;
98 | font-size: 22px;
99 | font-weight: 500;
100 | }
101 |
102 | .upper-content {
103 | margin-top: 13%;
104 | font-size: 50px;
105 | }
106 |
107 | .third-upper-content {
108 | margin-top: -32%;
109 | }
110 |
111 | .third-lower-content {
112 | margin-top: 8%;
113 | display: flex;
114 | margin-left: 28%;
115 | color: #D29DF9;
116 | }
117 |
118 | .icons {
119 | position: absolute;
120 | display: flex;
121 | height: 125.97px;
122 | }
123 |
124 | .down-button {
125 | position: fixed;
126 | bottom: 30px;
127 | right: 1%;
128 | transform: translateX(-50%);
129 | font-size: 24px;
130 | color: #fff;
131 | background-color: #6A0DAD;
132 | border-color: #f2ebeb;
133 | padding: 10px 20px;
134 | border-radius: 50%;
135 | cursor: pointer;
136 | z-index: 1000;
137 | border-style: solid;
138 | }
139 |
140 | .down-button:hover {
141 | background-color: #580b8f;
142 | color: #dddada;
143 | border-color: #f2ebebd6;
144 |
145 |
146 | }
147 |
148 | .down-button:active {
149 | background-color: #440770;
150 | color: #dddadaa7;
151 | border-color: #f2ebeba6;
152 |
153 |
154 | }
155 |
156 | .music {
157 | position: fixed;
158 | z-index: 1000;
159 |
160 | }
161 |
162 | .play-but {
163 | z-index: 150;
164 | position: absolute;
165 | background-color: #6A0DAD;
166 | border: 2px solid #f2ebeb;
167 | border-radius: 30px;
168 | padding: 1.5% 6%;
169 | color: #f2ebeb;
170 | font-size: 20px;
171 | font-weight: bold;
172 | margin-top: 3%;
173 | transition: transform 0.3s ease, background-color 0.3s ease;
174 | }
175 |
176 | .play-but:hover {
177 | background-color: #9938d1;
178 | cursor: pointer;
179 | transform: scale(1.2); /* Scales the button to 120% */
180 | }
181 |
182 |
183 |
184 | .play:active {
185 | background-color: #9943d6;
186 | }
187 |
188 | @keyframes drop {
189 | 0% { transform: translateY(0); }
190 | 100% { transform: translateY(200vh); }
191 | }
192 |
193 | @keyframes fall {
194 | 0% { transform: translateY(-100%); }
195 | 100% { transform: translateY(100vh); }
196 | }
197 |
198 | .container {
199 | position: relative;
200 | height: 100vh;
201 | overflow: hidden;
202 | }
203 |
204 | .tetrimino {
205 | position: absolute;
206 | opacity: 0.8;
207 | animation: fall 10s linear infinite;
208 | cursor: pointer; /* Add cursor pointer for better indication */
209 | }
210 |
211 | .tetrimino1 { /* Line */
212 | background: #4b245a; /* Purple */
213 | width: 50px;
214 | height: 200px;
215 | }
216 |
217 | .tetrimino2 { /* Square */
218 | background: #8e44ad; /* Darker Purple */
219 | width: 100px;
220 | height: 100px;
221 | }
222 |
223 | .tetrimino3 { /* T-shape */
224 | background: #4f106a; /* Even Darker Purple */
225 | width: 150px;
226 | height: 50px;
227 | }
228 |
229 | .tetrimino3::before {
230 | content: "";
231 | display: block;
232 | width: 50px;
233 | height: 50px;
234 | background: #4f106a;
235 | position: absolute;
236 | top: -50px;
237 | left: 50px;
238 | }
239 |
240 | .tetrimino4 { /* L-shape */
241 | background: #6c3483; /* Darkest Purple */
242 | width: 50px;
243 | height: 150px;
244 | }
245 |
246 | .tetrimino4::before {
247 | content: "";
248 | display: block;
249 | width: 50px;
250 | height: 50px;
251 | background: #6c3483;
252 | position: absolute;
253 | bottom: 0;
254 | left: 50px;
255 | }
256 |
257 | .tetrimino5 { /* J-shape */
258 | background: #3a0f4c; /* Very Dark Purple */
259 | width: 50px;
260 | height: 150px;
261 | }
262 |
263 | .tetrimino5::before {
264 | content: "";
265 | display: block;
266 | width: 50px;
267 | height: 50px;
268 | background: #3a0f4c;
269 | position: absolute;
270 | top: 0;
271 | left: -50px;
272 | }
273 |
274 | .tetrimino6 { /* Z-shape */
275 | background: #7d3c98; /* Even Darker Purple */
276 | width: 150px;
277 | height: 50px;
278 | }
279 |
280 | .tetrimino6::before {
281 | content: "";
282 | display: block;
283 | width: 50px;
284 | height: 50px;
285 | background: #7d3c98;
286 | position: absolute;
287 | top: -50px;
288 | left: 50px;
289 | }
290 |
291 | .tetrimino7 { /* S-shape */
292 | background: #3a0f4c; /* Deepest Purple */
293 | width: 100px;
294 | height: 50px;
295 | }
296 |
297 | .tetrimino7::before {
298 | content: "";
299 | display: block;
300 | width: 50px;
301 | height: 50px;
302 | background: #3a0f4c;
303 | position: absolute;
304 | top: 0;
305 | left: -50px;
306 | }
307 |
308 | .tetrimino:nth-child(odd) {
309 | animation-duration: 5s;
310 | }
311 | .tetrimino:nth-child(even) {
312 | animation-duration: 7s;
313 | }
314 |
315 | @keyframes rotate {
316 | from {
317 | transform: rotate(0deg);
318 | }
319 | to {
320 | transform: rotate(360deg);
321 | }
322 | }
323 |
--------------------------------------------------------------------------------
/css/navbar.css:
--------------------------------------------------------------------------------
1 | * {
2 | box-sizing: border-box;
3 | margin: 0;
4 | padding: 0;
5 | font-family: Verdana, Geneva, Tahoma, sans-serif;
6 | }
7 |
8 | body {
9 | min-height: 100vh;
10 | background-color: #210437;
11 | background-size: cover;
12 | }
13 |
14 | .logo {
15 | font-size: 30px;
16 | text-decoration: none;
17 | color: #6a0dad;
18 | margin-left: 30px;
19 | }
20 |
21 | .header {
22 | top: 0;
23 | left: 0;
24 | width: 100%;
25 | padding: 20px;
26 | display: flex;
27 | justify-content: space-between;
28 | }
29 |
30 | .header img {
31 | max-width: 160px;
32 | height: auto;
33 | }
34 | .navbar {
35 | margin-right: 40px;
36 | display: flex;
37 | align-items: center;
38 | }
39 |
40 | .navbar a {
41 | color: #f2ebeb;
42 | font-weight: bold;
43 | text-decoration: none;
44 | margin-left: 25px;
45 | }
46 |
47 | .nav-item {
48 | margin-left: auto;
49 | }
50 |
51 | .play {
52 | background-color: #6a0dad;
53 | border: 1px solid #d2b9e1;
54 | padding: 8px 20px;
55 | border-radius: 20px;
56 | }
57 |
58 | .play:hover {
59 | background-color: #791eba;
60 | }
61 |
62 | .play:active {
63 | background-color: #9943d6;
64 | }
--------------------------------------------------------------------------------
/css/revflex.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: #340557;
3 | }
4 |
5 | .main-body {
6 | margin-top: 0%;
7 | display: flex;
8 | justify-content: center;
9 | align-items: center;
10 | flex-direction: column;
11 | gap: 50px;
12 | }
13 |
14 | .container-one h1 {
15 | color: #e3e3e3;
16 | font-size: 75px;
17 | }
18 |
19 | .complex-desc {
20 | display: flex;
21 | flex-direction: column;
22 | align-items: center;
23 | justify-content: space-around;
24 | gap: 10px;
25 | }
26 |
27 | .complex-desc h2 {
28 | color: #d29df9;
29 | }
30 |
31 | .complex-desc p {
32 | color: #aea3b6;
33 | font-weight: 700;
34 | }
35 |
36 | .box {
37 | border: 1.3px solid #5c0b97;
38 | display: flex;
39 | background-color: #210437;
40 | color: white;
41 | width: 65%;
42 | height: 190px;
43 | justify-content: center;
44 | align-items: center;
45 | gap: 60px;
46 | }
47 |
48 | .box h3 {
49 | width: 40%;
50 | margin-right: 5%;
51 | }
52 |
53 | .box h1 {
54 | font-size: 70px;
55 | text-align: center;
56 | }
57 |
58 | .back-start{
59 | display: flex;
60 | width: 65%;
61 | gap: 70px;
62 | margin-top: -14px;
63 | }
64 |
65 | .back, .start {
66 | width: 50%;
67 | display: flex;
68 | justify-content: center;
69 | background-color: #210437;
70 | color: white;
71 | height: 90px;
72 | align-items: center;
73 | border: 1px solid #5c0b97;
74 | cursor: pointer;
75 |
76 | }
77 |
78 | .back:hover, .start:hover {
79 |
80 | background-color: #340557;
81 |
82 | }
83 |
84 | .back:active, .start:active {
85 |
86 | background-color: #4a067e;
87 |
88 | }
89 |
90 | @keyframes pulse {
91 | 0% { transform: scale(1); }
92 | 50% { transform: scale(1.05); }
93 | 100% { transform: scale(1); }
94 | }
95 |
96 | .start, .back {
97 | padding: 10px;
98 | display: flex;
99 | flex-direction: column;
100 | align-items: center;
101 | justify-content: space-around;
102 | cursor: pointer;
103 | animation: pulse 2s ease-in-out infinite; /* Adjust duration and other animation properties as needed */
104 | }
105 |
--------------------------------------------------------------------------------
/css/selcomplex.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: #340557;
3 | }
4 |
5 | .main-body {
6 | margin-top: 0%;
7 | display: flex;
8 | justify-content: center;
9 | align-items: center;
10 | flex-direction: column;
11 | gap: 50px;
12 | }
13 |
14 | .container-one h1 {
15 | color: #e3e3e3;
16 | font-size: 75px;
17 | }
18 |
19 | .complex-desc {
20 | display: flex;
21 | flex-direction: column;
22 | align-items: center;
23 | justify-content: space-around;
24 | gap: 10px;
25 | }
26 |
27 | .complex-desc h2 {
28 | color: #d29df9;
29 | }
30 |
31 | .complex-desc p {
32 | color: #aea3b6;
33 | font-weight: 700;
34 | }
35 |
36 | .row {
37 | display: flex;
38 | width: 65%;
39 | gap: 70px;
40 | margin-top: -14px;
41 | cursor: pointer;
42 | }
43 |
44 |
45 | .first, .second {
46 | width: 50%;
47 | display: flex;
48 | flex-direction: column;
49 | justify-content: center;
50 | background-color: #210437;
51 | color: white;
52 | height: 150px;
53 | align-items: center;
54 | border: 1px solid #5c0b97;
55 | gap: 12px;
56 | }
57 |
58 | .first:hover, .second:hover{
59 |
60 | background-color: #2d034d;
61 |
62 | }
63 | .first:active, .second:active{
64 |
65 | background-color: #4e0387;
66 |
67 | }
68 |
69 | .row p {
70 | width: 90%;
71 | text-align: center;
72 | }
73 |
74 | .row h1 {
75 | margin-top: -14px;
76 | }
77 |
78 | @keyframes pulse {
79 | 0% { transform: scale(1); }
80 | 50% { transform: scale(1.05); }
81 | 100% { transform: scale(1); }
82 | }
83 |
84 | .first, .second {
85 | padding: 20px;
86 | display: flex;
87 | flex-direction: column;
88 | align-items: center;
89 | justify-content: space-around;
90 | cursor: pointer;
91 | animation: pulse 2s ease-in-out infinite; /* Adjust duration and other animation properties as needed */
92 | }
--------------------------------------------------------------------------------
/css/timetrial.css:
--------------------------------------------------------------------------------
1 | body {
2 | background-color: #340557;
3 |
4 | }
5 |
6 | .main-body {
7 | margin-top: 0%;
8 | display: flex;
9 | justify-content: center;
10 | align-items: center;
11 | flex-direction: column;
12 | gap: 50px;
13 | }
14 |
15 | .container-one h1 {
16 | color: #e3e3e3;
17 | font-size: 75px;
18 | }
19 |
20 | .complex-desc {
21 | display: flex;
22 | flex-direction: column;
23 | align-items: center;
24 | justify-content: space-around;
25 | gap: 10px;
26 | }
27 |
28 | .complex-desc h2 {
29 | color: #d29df9;
30 | }
31 |
32 | .complex-desc p {
33 | color: #aea3b6;
34 | font-weight: 700;
35 | }
36 |
37 | .box {
38 | border: 1.3px solid #5c0b97;
39 | display: flex;
40 | background-color: #210437;
41 | color: white;
42 | width: 65%;
43 | height: 190px;
44 | justify-content: center;
45 | align-items: center;
46 | }
47 |
48 | .box h3 {
49 | width: 45%;
50 | margin-left: 5%;
51 | }
52 |
53 | .box h1 {
54 | text-align: center;
55 | font-size: 70px;
56 | margin-left: 3%;
57 | }
58 |
59 | .back-start{
60 | display: flex;
61 | width: 65%;
62 | gap: 70px;
63 | margin-top: -14px;
64 | }
65 |
66 | .back, .start {
67 | width: 50%;
68 | display: flex;
69 | justify-content: center;
70 | background-color: #210437;
71 | color: white;
72 | height: 90px;
73 | align-items: center;
74 | border: 1px solid #5c0b97;
75 | cursor: pointer;
76 | }
77 |
78 | .back:hover, .start:hover {
79 |
80 | background-color: #340557;
81 |
82 | }
83 |
84 | .back:active, .start:active {
85 |
86 | background-color: #4a067e;
87 |
88 | }
89 |
90 | @keyframes pulse {
91 | 0% { transform: scale(1); }
92 | 50% { transform: scale(1.05); }
93 | 100% { transform: scale(1); }
94 | }
95 |
96 | .start, .back {
97 | padding: 10px;
98 | display: flex;
99 | flex-direction: column;
100 | align-items: center;
101 | justify-content: space-around;
102 | cursor: pointer;
103 | animation: pulse 2s ease-in-out infinite; /* Adjust duration and other animation properties as needed */
104 | }
105 |
--------------------------------------------------------------------------------
/html/cascade.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Chromatic Cascade
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
26 |
27 |
28 |
29 |
- Select Game Mode -
30 |
31 |
32 |
33 |
COMPLEX
34 |
Additional challenges to add layers of strategy to the gameplay experience
35 |
36 |
37 |
38 |
39 |
CHROMATIC CASCADE
40 |
41 |
42 |
Navigate through a constantly shifting colors, where Tetriminos change hues as they fall.
43 |
44 |
45 |
46 |
47 |
48 |
BACK
49 |
50 |
51 |
START
52 |
53 |
54 |
55 |
56 |
57 |
58 |
59 |
--------------------------------------------------------------------------------
/html/classic-mode.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Classic Mode
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
26 |
27 |
28 |
29 |
- Select Game Mode -
30 |
31 |
32 |
33 |
CLASSIC
34 | Create complete horizontal lines and prevent the stack from reaching the top of the screen.
35 |
36 |
37 |
38 |
39 |
BACK
40 |
41 |
42 |
START
43 |
44 |
45 |
46 |
47 |
48 |
59 |
60 |
--------------------------------------------------------------------------------
/html/flashlight.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Flashlight Mode
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
26 |
27 |
28 |
29 |
- Select Game Mode -
30 |
31 |
32 |
33 |
COMPLEX
34 |
Additional challenges to add layers of strategy to the gameplay experience
35 |
36 |
37 |
38 |
FLASHLIGHT
39 | Plunged into darkness, relying solely on the illumination provided by their mouse cursor to reveal the immediate vicinity.
40 |
41 |
42 |
43 |
44 |
BACK
45 |
46 |
47 |
START
48 |
49 |
50 |
51 |
52 |
53 |
64 |
65 |
--------------------------------------------------------------------------------
/html/game-layout.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Classic Mode
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
26 |
27 |
28 |
29 |
30 |
0
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
GAME OVER
39 |
40 |
Exit
41 |
Retry
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
54 |
55 |
56 |
57 |
58 |
115 |
--------------------------------------------------------------------------------
/html/game-mode.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Game Mode
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
26 |
27 |
28 |
29 |
30 |
- Select Game Mode -
31 |
32 |
33 |
CLASSIC
34 |
Create complete horizontal lines and prevent the stack from reaching the top of the screen.
35 |
36 |
37 |
COMPLEX MODES
38 |
Additional challenges to add layers of strategy and excitement to the gameplay experience.
39 |
40 |
41 |
42 |
61 |
62 |
--------------------------------------------------------------------------------
/html/reverse-flex.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Reversed FLex
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
26 |
27 |
28 |
29 |
- Select Game Mode -
30 |
31 |
32 |
33 |
COMPLEX
34 |
Additional challenges to add layers of strategy to the gameplay experience
35 |
36 |
37 |
38 |
REVERSED FLEX
39 | Contend with a topsy-turvy world where LEFT is RIGHT and UP is DOWN , as traditional controls are flipped on their head.
40 |
41 |
42 |
43 |
44 |
BACK
45 |
46 |
47 |
START
48 |
49 |
50 |
51 |
52 |
53 |
54 |
55 |
--------------------------------------------------------------------------------
/html/script.js:
--------------------------------------------------------------------------------
1 | function back() {
2 | window.location.href = "game-mode.html"
3 | }
4 |
5 | function start() {
6 | document.body.style.transition = 'opacity 0.4s ease';
7 | document.body.style.opacity = 0;
8 |
9 | setTimeout(() => {
10 | window.location.href = "game-layout.html";
11 | }, 400);
12 | }
--------------------------------------------------------------------------------
/html/select-complex.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Complex Modes
7 |
8 |
9 |
10 |
11 |
12 |
13 |
25 |
26 |
27 |
28 |
- Select Game Mode -
29 |
30 |
31 |
32 |
COMPLEX
33 |
Additional challenges to add layers of strategy to the gameplay experience
34 |
35 |
36 |
37 |
38 |
TIME TRIAL
39 |
Race against the clock to clear as many lines as possible within a set time limit. Ghostblocks are disabled.
40 |
41 |
42 |
FLASHLIGHT
43 |
Plunged into darkness, relying solely on the illumination provided by their mouse cursor to reveal the immediate vicinity. Ghostblocks are disabled.
44 |
45 |
46 |
47 |
48 |
49 |
CHROMATIC CASCADE
50 |
Navigate through a constantly shifting colors, where Tetriminos change hues as they fall. Ghostblocks are disabled.
51 |
52 |
53 |
REVERSED FLEX
54 |
Contend with a topsy-turvy world where left is right and up is down, as traditional controls are flipped on their head. Ghostblocks are enabled.
55 |
56 |
57 |
58 |
59 |
76 |
77 |
--------------------------------------------------------------------------------
/html/timetrial.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Time Trial
7 |
8 |
9 |
10 |
11 |
12 |
13 |
25 |
26 |
27 |
28 |
- Select Game Mode -
29 |
30 |
31 |
32 |
COMPLEX
33 |
Additional challenges to add layers of strategy to the gameplay experience
34 |
35 |
36 |
37 |
TIME TRIAL
38 | Race against the clock to clear as many lines as possible within a set time limit
39 |
40 |
41 |
42 |
43 |
BACK
44 |
45 |
46 |
START
47 |
48 |
49 |
50 |
51 |
52 |
53 |
54 |
--------------------------------------------------------------------------------
/index.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Tetris
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
20 |
21 |
22 |
23 |
24 |
25 |
26 |
27 |
28 | PLAY
29 |
30 | V
31 |
32 |
44 |
45 |
46 |
47 |
48 |
About
49 |
50 |
51 |
52 |
53 |
54 | Embark on a timeless journey of spatial strategy and
55 | exhilarating challenge with our Tetris game! Immerse yourself in
56 | the iconic world of falling Tetriminos, where quick thinking and
57 | precision are your greatest allies.
58 |
59 | Challenge yourself to reach new heights, compete against
60 | friends and rivals, and become the ultimate Tetris champion. Are
61 | you ready to embrace the challenge and shape your destiny, one
62 | block at a time?
63 |
64 |
65 |
66 |
67 |
68 |
69 |
70 |
71 |
Contact Us
72 | Have any inquiries? Get in touch with us.
73 |
74 |
75 |
900 San Marcelino St
76 |
(555) 867-5309
77 |
support@tetrisgame.com
78 |
83 |
84 |
85 |
86 |
87 |
150 |
151 |
--------------------------------------------------------------------------------
/modded modes/.DS_Store:
--------------------------------------------------------------------------------
https://raw.githubusercontent.com/ardnyx/tetris/1cb2a67ec41871c951b03ecebc59bf2b7bf0f4f1/modded modes/.DS_Store
--------------------------------------------------------------------------------
/modded modes/chromatic cascade/cascade-mod.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Chromatic Cascade
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
26 |
27 |
28 |
29 |
30 |
0
31 |
Level: 0
32 |
33 |
34 |
35 |
36 |
37 |
38 |
39 |
GAME OVER
40 |
41 |
42 |
43 |
Exit
44 |
Retry
45 |
46 |
47 |
48 |
49 |
50 |
51 |
52 |
57 |
58 |
59 |
60 |
61 |
118 |
--------------------------------------------------------------------------------
/modded modes/chromatic cascade/chromatic-cascade.js:
--------------------------------------------------------------------------------
1 | const cvs = document.getElementById("tetris");
2 | const ctx = cvs.getContext("2d");
3 | const scoreElement = document.getElementById("scoreboard");
4 | const levelElement = document.getElementById("levelboard"); // Add a new element for the level display
5 |
6 | const ROW = 20;
7 | const COL = COLUMN = 10;
8 | const SQ = squareSize = 32;
9 | let VACANT = "black";
10 |
11 | // Track the number of locked pieces
12 | let lockCount = 0;
13 |
14 | // draw a square
15 | function drawSquare(x, y, color) {
16 | ctx.fillStyle = color;
17 | ctx.fillRect(x * SQ, y * SQ, SQ, SQ);
18 | ctx.strokeStyle = "black";
19 | ctx.strokeRect(x * SQ, y * SQ, SQ, SQ);
20 | }
21 |
22 | // create the board
23 | let board = [];
24 | for (r = 0; r < ROW; r++) {
25 | board[r] = [];
26 | for (c = 0; c < COL; c++) {
27 | board[r][c] = VACANT;
28 | }
29 | }
30 |
31 | // draw the board
32 | function drawBoard() {
33 | for (r = 0; r < ROW; r++) {
34 | for (c = 0; c < COL; c++) {
35 | drawSquare(c, r, board[r][c]);
36 | }
37 | }
38 | }
39 |
40 | drawBoard();
41 |
42 | // Function to generate a random color
43 | function getRandomColor() {
44 | let letters = '0123456789ABCDEF';
45 | let color = '#';
46 | for (let i = 0; i < 6; i++) {
47 | color += letters[Math.floor(Math.random() * 16)];
48 | }
49 | return color;
50 | }
51 |
52 | // Function to update board colors
53 | function updateBoardColors() {
54 | let color1 = getRandomColor();
55 | let color2 = getRandomColor();
56 | for (let r = 0; r < ROW; r++) {
57 | for (let c = 0; c < COL; c++) {
58 | if (board[r][c] !== VACANT) {
59 | board[r][c] = (Math.random() < 0.5) ? color1 : color2;
60 | }
61 | }
62 | }
63 | // Update the color of the active piece
64 | if (p) {
65 | p.color = (Math.random() < 0.5) ? color1 : color2;
66 | p.draw();
67 | }
68 |
69 | drawBoard();
70 | }
71 |
72 | // the pieces and their colors
73 | const PIECES = [
74 | [Z, "red"],
75 | [S, "green"],
76 | [T, "yellow"],
77 | [O, "blue"],
78 | [L, "purple"],
79 | [I, "cyan"],
80 | [J, "orange"]
81 | ];
82 |
83 | // generate random pieces
84 | function randomPiece() {
85 | let r = Math.floor(Math.random() * PIECES.length); // 0 -> 6
86 | return new Piece(PIECES[r][0], PIECES[r][1]);
87 | }
88 |
89 | let p;
90 |
91 | // The Object Piece
92 | function Piece(tetromino, color) {
93 | this.tetromino = tetromino;
94 | this.color = color;
95 |
96 | this.tetrominoN = 0; // we start from the first pattern
97 | this.activeTetromino = this.tetromino[this.tetrominoN];
98 |
99 | // we need to control the pieces
100 | this.x = 3;
101 | this.y = -2;
102 | }
103 |
104 | // fill function
105 | Piece.prototype.fill = function (color) {
106 | for (r = 0; r < this.activeTetromino.length; r++) {
107 | for (c = 0; c < this.activeTetromino.length; c++) {
108 | // we draw only occupied squares
109 | if (this.activeTetromino[r][c]) {
110 | drawSquare(this.x + c, this.y + r, color);
111 | }
112 | }
113 | }
114 | }
115 |
116 | // draw a piece to the board
117 | Piece.prototype.draw = function () {
118 | this.fill(this.color);
119 | }
120 |
121 | // undraw a piece
122 | Piece.prototype.unDraw = function () {
123 | this.fill(VACANT);
124 | }
125 |
126 | // move Down the piece
127 | Piece.prototype.moveDown = function () {
128 | if (!this.collision(0, 1, this.activeTetromino)) {
129 | this.unDraw();
130 | this.y++;
131 | this.draw();
132 | } else {
133 | // we lock the piece and generate a new one
134 | this.lock();
135 | if (!gameOver) {
136 | p = randomPiece();
137 | p.draw(); // Draw the new piece so it is included in the color change
138 | updateBoardColors(); // Change colors after locking the piece
139 | }
140 | }
141 | }
142 |
143 | // move Right the piece
144 | Piece.prototype.moveRight = function () {
145 | if (!this.collision(1, 0, this.activeTetromino)) {
146 | this.unDraw();
147 | this.x++;
148 | this.draw();
149 | }
150 | }
151 |
152 | // move Left the piece
153 | Piece.prototype.moveLeft = function () {
154 | if (!this.collision(-1, 0, this.activeTetromino)) {
155 | this.unDraw();
156 | this.x--;
157 | this.draw();
158 | }
159 | }
160 |
161 | // rotate the piece
162 | Piece.prototype.rotate = function () {
163 | let nextPattern = this.tetromino[(this.tetrominoN + 1) % this.tetromino.length];
164 | let kick = 0;
165 |
166 | if (this.collision(0, 0, nextPattern)) {
167 | if (this.x > COL / 2) {
168 | // it's the right wall
169 | kick = -1; // we need to move the piece to the left
170 | } else {
171 | // it's the left wall
172 | kick = 1; // we need to move the piece to the right
173 | }
174 | }
175 |
176 | if (!this.collision(kick, 0, nextPattern)) {
177 | this.unDraw();
178 | this.x += kick;
179 | this.tetrominoN = (this.tetrominoN + 1) % this.tetromino.length; // (0+1)%4 => 1
180 | this.activeTetromino = this.tetromino[this.tetrominoN];
181 | this.draw();
182 | }
183 | }
184 |
185 | let score = 0;
186 | let level = 0; // Initialize level
187 |
188 | // Modify the lock function to show the game over screen
189 | Piece.prototype.lock = function () {
190 | for (let r = 0; r < this.activeTetromino.length; r++) {
191 | for (let c = 0; c < this.activeTetromino.length; c++) {
192 | if (!this.activeTetromino[r][c]) {
193 | continue;
194 | }
195 | if (this.y + r < 0) {
196 | gameOver = true;
197 | document.getElementById("gameOverScreen").style.display = "flex";
198 | return;
199 | }
200 | board[this.y + r][this.x + c] = this.color;
201 | }
202 | }
203 | for (let r = 0; r < ROW; r++) {
204 | let isRowFull = true;
205 | for (let c = 0; c < COL; c++) {
206 | isRowFull = isRowFull && (board[r][c] != VACANT);
207 | }
208 | if (isRowFull) {
209 | for (let y = r; y > 1; y--) {
210 | for (let c = 0; c < COL; c++) {
211 | board[y][c] = board[y - 1][c];
212 | }
213 | }
214 | for (let c = 0; c < COL; c++) {
215 | board[0][c] = VACANT;
216 | }
217 | score += 10;
218 | if (score % 10 === 0 && level < 50) { // Increase level every 100 points
219 | level++;
220 | }
221 | }
222 | }
223 | drawBoard();
224 | scoreElement.innerHTML = score;
225 | levelElement.innerHTML = level; // Update level display
226 |
227 | document.getElementById("highest_level").innerHTML = "Your highest level is: " + level;
228 | }
229 |
230 | // collision function
231 | Piece.prototype.collision = function (x, y, piece) {
232 | for (r = 0; r < piece.length; r++) {
233 | for (c = 0; c < piece.length; c++) {
234 | // if the square is empty, we skip it
235 | if (!piece[r][c]) {
236 | continue;
237 | }
238 | // coordinates of the piece after movement
239 | let newX = this.x + c + x;
240 | let newY = this.y + r + y;
241 |
242 | // conditions
243 | if (newX < 0 || newX >= COL || newY >= ROW) {
244 | return true;
245 | }
246 | // skip newY < 0; board[-1] will crash our game
247 | if (newY < 0) {
248 | continue;
249 | }
250 | // check if there is a locked piece already in place
251 | if (board[newY][newX] != VACANT) {
252 | return true;
253 | }
254 | }
255 | }
256 | return false;
257 | }
258 |
259 | // CONTROL the piece
260 | document.addEventListener("keydown", CONTROL);
261 |
262 | function CONTROL(event) {
263 | if (gameOver) return;
264 | if (event.keyCode == 37) {
265 | p.moveLeft();
266 | } else if (event.keyCode == 38) {
267 | p.rotate();
268 | } else if (event.keyCode == 39) {
269 | p.moveRight();
270 | } else if (event.keyCode == 40) {
271 | p.moveDown();
272 | } else if (event.keyCode == 32) { // Check if spacebar is pressed
273 | while (!p.collision(0, 1, p.activeTetromino)) { // Move down until collision
274 | p.moveDown();
275 | }
276 | p.lock(); // Lock the tetromino in place
277 | scoreElement.innerHTML = score; // Update the score display
278 | if (!gameOver) {
279 | p = randomPiece(); // Generate a new tetromino
280 | p.draw(); // Draw the new piece so it is included in the color change
281 | updateBoardColors(); // Change colors after locking the piece
282 | }
283 | }
284 | }
285 |
286 | let dropStart = Date.now();
287 | let gameOver = false;
288 |
289 | function drop() {
290 | let now = Date.now();
291 | let delta = now - dropStart;
292 | let dropInterval = 500 - (level * 25); // Decrease drop interval as level increases
293 | if (delta > dropInterval) {
294 | if (!gameOver) {
295 | p.moveDown();
296 | }
297 | dropStart = Date.now();
298 | }
299 | if (!gameOver) {
300 | requestAnimationFrame(drop);
301 | }
302 | }
303 |
304 | function initGame() {
305 | // Reset game variables
306 | score = 0;
307 | level = 0; // Reset level
308 | lockCount = 0; // Reset lock count
309 | gameOver = false;
310 | scoreElement.innerHTML = score;
311 | levelElement.innerHTML = level; // Update level display
312 |
313 | // Reset the board
314 | board = [];
315 | for (r = 0; r < ROW; r++) {
316 | board[r] = [];
317 | for (c = 0; c < COL; c++) {
318 | board[r][c] = VACANT;
319 | }
320 | }
321 |
322 | drawBoard();
323 | p = randomPiece();
324 | p.draw(); // Draw the initial piece so it is included in the color change
325 | updateBoardColors(); // Update colors including the initial piece
326 | drop();
327 | }
328 |
329 | // Retry Game
330 | function retryGame() {
331 | document.getElementById("gameOverScreen").style.display = "none";
332 | initGame();
333 | }
334 |
335 | // Initialize the game when the script loads
336 | initGame();
337 |
--------------------------------------------------------------------------------
/modded modes/flashlight/flashlight-mod.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Flashlight
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
26 |
27 |
28 |
29 |
30 |
0
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
GAME OVER
39 |
40 |
Exit
41 |
Retry
42 |
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
55 |
56 |
57 |
58 |
118 |
--------------------------------------------------------------------------------
/modded modes/flashlight/flashlight-mod.js:
--------------------------------------------------------------------------------
1 | const light = document.documentElement
2 | light.addEventListener('mousemove', (e) => {
3 | light.style.setProperty('--x', e.clientX + 'px')
4 | light.style.setProperty('--y', e.clientY + 'px')
5 | })
--------------------------------------------------------------------------------
/modded modes/reversed flex/reversed-flex-mod.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Reversed Flex
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
26 |
27 |
28 |
29 |
30 |
0
31 |
32 |
33 |
34 |
35 |
36 |
37 |
38 |
GAME OVER
39 |
40 |
Exit
41 |
Retry
42 |
43 |
44 |
45 |
46 |
47 |
48 |
53 |
54 |
55 |
56 |
57 |
114 |
--------------------------------------------------------------------------------
/modded modes/reversed flex/tetrisreverseflex.js:
--------------------------------------------------------------------------------
1 | const cvs = document.getElementById("tetris");
2 | const ctx = cvs.getContext("2d");
3 | const scoreElement = document.getElementById("scoreboard");
4 | const timerElement = document.getElementById("timer");
5 |
6 | const ROW = 20;
7 | const COL = COLUMN = 10;
8 | const SQ = squareSize = 32;
9 | const VACANT = "black"; // color of an empty square
10 |
11 | // draw a square
12 | function drawSquare(x, y, color) {
13 | ctx.fillStyle = color;
14 | ctx.fillRect(x * SQ, y * SQ, SQ, SQ);
15 | ctx.strokeStyle = "black";
16 | ctx.strokeRect(x * SQ, y * SQ, SQ, SQ);
17 | }
18 |
19 | // create the board
20 | let board = [];
21 | for (let r = 0; r < ROW; r++) {
22 | board[r] = [];
23 | for (let c = 0; c < COL; c++) {
24 | board[r][c] = VACANT;
25 | }
26 | }
27 |
28 | // draw the board
29 | function drawBoard() {
30 | for (let r = 0; r < ROW; r++) {
31 | for (let c = 0; c < COL; c++) {
32 | drawSquare(c, r, board[r][c]);
33 | }
34 | }
35 | }
36 |
37 | drawBoard();
38 |
39 | // the pieces and their colors
40 | const PIECES = [
41 | [Z, "red"],
42 | [S, "green"],
43 | [T, "yellow"],
44 | [O, "blue"],
45 | [L, "purple"],
46 | [I, "cyan"],
47 | [J, "orange"]
48 | ];
49 |
50 | // generate random pieces
51 | function randomPiece() {
52 | let r = Math.floor(Math.random() * PIECES.length); // 0 -> 6
53 | return new Piece(PIECES[r][0], PIECES[r][1]);
54 | }
55 |
56 | let p;
57 |
58 | // The Object Piece
59 | function Piece(tetromino, color) {
60 | this.tetromino = tetromino;
61 | this.color = color;
62 |
63 | this.tetrominoN = 0; // we start from the first pattern
64 | this.activeTetromino = this.tetromino[this.tetrominoN];
65 |
66 | // we need to control the pieces
67 | this.x = 3;
68 | this.y = -2;
69 | }
70 |
71 | // fill function
72 | Piece.prototype.fill = function(color) {
73 | for (let r = 0; r < this.activeTetromino.length; r++) {
74 | for (let c = 0; c < this.activeTetromino.length; c++) {
75 | // we draw only occupied squares
76 | if (this.activeTetromino[r][c]) {
77 | drawSquare(this.x + c, this.y + r, color);
78 | }
79 | }
80 | }
81 | }
82 |
83 | // draw a piece to the board
84 | Piece.prototype.draw = function() {
85 | this.fill(this.color);
86 | }
87 |
88 | // undraw a piece
89 | Piece.prototype.unDraw = function() {
90 | this.fill(VACANT);
91 | }
92 |
93 | // draw the ghost piece
94 | Piece.prototype.drawGhost = function() {
95 | const ghostColor = 'rgba(255, 255, 255, 0.2)'; // light color with transparency
96 | let ghostY = this.y;
97 |
98 | // Find the position where the piece would land
99 | while (!this.collision(0, 1, this.activeTetromino, ghostY + 1)) {
100 | ghostY++;
101 | }
102 |
103 | // Draw the ghost piece
104 | for (let r = 0; r < this.activeTetromino.length; r++) {
105 | for (let c = 0; c < this.activeTetromino.length; c++) {
106 | if (this.activeTetromino[r][c]) {
107 | drawSquare(this.x + c, ghostY + r, ghostColor);
108 | }
109 | }
110 | }
111 | }
112 |
113 | // move Down the piece
114 | Piece.prototype.moveDown = function() {
115 | if (!this.collision(0, 1, this.activeTetromino)) {
116 | this.unDraw();
117 | this.y++;
118 | draw(); // Update the draw function to include the ghost piece
119 | } else {
120 | // we lock the piece and generate a new one
121 | this.lock();
122 | if (!gameOver) {
123 | p = randomPiece();
124 | }
125 | }
126 | }
127 |
128 | // move Right the piece
129 | Piece.prototype.moveRight = function() {
130 | if (!this.collision(1, 0, this.activeTetromino)) {
131 | this.unDraw();
132 | this.x++;
133 | draw(); // Update the draw function to include the ghost piece
134 | }
135 | }
136 |
137 | // move Left the piece
138 | Piece.prototype.moveLeft = function() {
139 | if (!this.collision(-1, 0, this.activeTetromino)) {
140 | this.unDraw();
141 | this.x--;
142 | draw(); // Update the draw function to include the ghost piece
143 | }
144 | }
145 |
146 | // rotate the piece
147 | Piece.prototype.rotate = function() {
148 | let nextPattern = this.tetromino[(this.tetrominoN + 1) % this.tetromino.length];
149 | let kick = 0;
150 |
151 | if (this.collision(0, 0, nextPattern)) {
152 | if (this.x > COL / 2) {
153 | // it's the right wall
154 | kick = -1; // we need to move the piece to the left
155 | } else {
156 | // it's the left wall
157 | kick = 1; // we need to move the piece to the right
158 | }
159 | }
160 |
161 | if (!this.collision(kick, 0, nextPattern)) {
162 | this.unDraw();
163 | this.x += kick;
164 | this.tetrominoN = (this.tetrominoN + 1) % this.tetromino.length; // (0+1)%4 => 1
165 | this.activeTetromino = nextPattern;
166 | draw(); // Update the draw function to include the ghost piece
167 | }
168 | }
169 |
170 | let score = 0;
171 |
172 | // Modify the lock function to show the game over screen
173 | Piece.prototype.lock = function() {
174 | for (let r = 0; r < this.activeTetromino.length; r++) {
175 | for (let c = 0; c < this.activeTetromino.length; c++) {
176 | if (!this.activeTetromino[r][c]) {
177 | continue;
178 | }
179 | if (this.y + r < 0) {
180 | gameOver = true;
181 | document.getElementById("gameOverScreen").style.display = "flex";
182 | return;
183 | }
184 | board[this.y + r][this.x + c] = this.color;
185 | }
186 | }
187 | for (let r = 0; r < ROW; r++) {
188 | let isRowFull = true;
189 | for (let c = 0; c < COL; c++) {
190 | isRowFull = isRowFull && (board[r][c] != VACANT);
191 | }
192 | if (isRowFull) {
193 | for (let y = r; y > 1; y--) {
194 | for (let c = 0; c < COL; c++) {
195 | board[y][c] = board[y - 1][c];
196 | }
197 | }
198 | for (let c = 0; c < COL; c++) {
199 | board[0][c] = VACANT;
200 | }
201 | score += 10;
202 | }
203 | }
204 | drawBoard();
205 | scoreElement.innerHTML = score;
206 | }
207 |
208 | // collision function
209 | Piece.prototype.collision = function(x, y, piece, newY = this.y + y) {
210 | for (let r = 0; r < piece.length; r++) {
211 | for (let c = 0; c < piece.length; c++) {
212 | // if the square is empty, we skip it
213 | if (!piece[r][c]) {
214 | continue;
215 | }
216 | // coordinates of the piece after movement
217 | let newX = this.x + c + x;
218 | let testY = newY + r;
219 |
220 | // conditions
221 | if (newX < 0 || newX >= COL || testY >= ROW) {
222 | return true;
223 | }
224 | // skip newY < 0; board[-1] will crash our game
225 | if (testY < 0) {
226 | continue;
227 | }
228 | // check if there is a locked piece already in place
229 | if (board[testY][newX] != VACANT) {
230 | return true;
231 | }
232 | }
233 | }
234 | return false;
235 | }
236 |
237 | // CONTROL the piece
238 | document.addEventListener("keydown", CONTROL);
239 |
240 | function CONTROL(event) {
241 | if (gameOver) return;
242 | if (event.keyCode == 39) {
243 | p.moveLeft();
244 | } else if (event.keyCode == 40) {
245 | p.rotate();
246 | } else if (event.keyCode == 37) {
247 | p.moveRight();
248 | } else if (event.keyCode == 38) {
249 | p.moveDown();
250 | } else if (event.keyCode == 32) { // Check if spacebar is pressed
251 | while (!p.collision(0, 1, p.activeTetromino)) { // Move down until collision
252 | p.moveDown();
253 | }
254 | p.lock(); // Lock the tetromino in place
255 | scoreElement.innerHTML = score; // Update the score display
256 | if (!gameOver) {
257 | p = randomPiece(); // Generate a new tetromino
258 | }
259 | }
260 | }
261 |
262 | let dropStart = Date.now();
263 | let gameOver = false;
264 |
265 | function drop() {
266 | let now = Date.now();
267 | let delta = now - dropStart;
268 | if (delta > 500) {
269 | if (!gameOver) {
270 | p.moveDown();
271 | }
272 | dropStart = Date.now();
273 | }
274 | if (!gameOver) {
275 | requestAnimationFrame(drop);
276 | }
277 | }
278 |
279 | function initGame() {
280 | // Reset game variables
281 | score = 0;
282 | gameOver = false;
283 | scoreElement.innerHTML = score;
284 |
285 | // Reset the board
286 | board = [];
287 | for (let r = 0; r < ROW; r++) {
288 | board[r] = [];
289 | for (let c = 0; c < COL; c++) {
290 | board[r][c] = VACANT;
291 | }
292 | }
293 |
294 | drawBoard();
295 | p = randomPiece();
296 | drop();
297 | }
298 |
299 | function retryGame() {
300 | document.getElementById("gameOverScreen").style.display = "none";
301 | initGame();
302 | }
303 |
304 | initGame();
305 |
306 | function draw() {
307 | ctx.clearRect(0, 0, cvs.width, cvs.height); // Clear the canvas
308 | drawBoard();
309 | p.drawGhost(); // Draw the ghost piece
310 | p.draw(); // Draw the main piece
311 | }
--------------------------------------------------------------------------------
/modded modes/time trial/timetrial-mod.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 |
6 | Time Trial
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
26 |
27 |
28 |
29 |
30 |
0
31 | 60
32 |
33 |
34 |
35 |
36 |
37 |
38 |
GAME OVER
39 |
40 |
41 |
Exit
42 |
Retry
43 |
44 |
45 |
46 |
47 |
48 |
49 |
50 |
55 |
56 |
57 |
58 |
59 |
60 |
--------------------------------------------------------------------------------
/modded modes/time trial/timetrial.js:
--------------------------------------------------------------------------------
1 | const cvs = document.getElementById("tetris");
2 | const ctx = cvs.getContext("2d");
3 | const scoreElement = document.getElementById("scoreboard");
4 | const timerDisplay = document.getElementById("timerDisplay");
5 |
6 | const ROW = 20;
7 | const COL = COLUMN = 10;
8 | const SQ = squareSize = 32;
9 | const VACANT = "black"; // color of an empty square
10 |
11 | let totalTime = 60; // Total time in seconds
12 | let timer; // Timer interval variable
13 |
14 | // draw a square
15 | function drawSquare(x, y, color) {
16 | ctx.fillStyle = color;
17 | ctx.fillRect(x * SQ, y * SQ, SQ, SQ);
18 | ctx.strokeStyle = "black";
19 | ctx.strokeRect(x * SQ, y * SQ, SQ, SQ);
20 | }
21 |
22 | // create the board
23 | let board = [];
24 | for (let r = 0; r < ROW; r++) {
25 | board[r] = [];
26 | for (let c = 0; c < COL; c++) {
27 | board[r][c] = VACANT;
28 | }
29 | }
30 |
31 | // draw the board
32 | function drawBoard() {
33 | for (let r = 0; r < ROW; r++) {
34 | for (let c = 0; c < COL; c++) {
35 | drawSquare(c, r, board[r][c]);
36 | }
37 | }
38 | }
39 |
40 | drawBoard();
41 |
42 | // the pieces and their colors
43 | const PIECES = [
44 | [Z, "red"],
45 | [S, "green"],
46 | [T, "yellow"],
47 | [O, "blue"],
48 | [L, "purple"],
49 | [I, "cyan"],
50 | [J, "orange"]
51 | ];
52 |
53 | // generate random pieces
54 | function randomPiece() {
55 | let r = Math.floor(Math.random() * PIECES.length); // 0 -> 6
56 | return new Piece(PIECES[r][0], PIECES[r][1]);
57 | }
58 |
59 | let p;
60 |
61 | // The Object Piece
62 | function Piece(tetromino, color) {
63 | this.tetromino = tetromino;
64 | this.color = color;
65 |
66 | this.tetrominoN = 0; // we start from the first pattern
67 | this.activeTetromino = this.tetromino[this.tetrominoN];
68 |
69 | // we need to control the pieces
70 | this.x = 3;
71 | this.y = -2;
72 | }
73 |
74 | // fill function
75 | Piece.prototype.fill = function (color) {
76 | for (let r = 0; r < this.activeTetromino.length; r++) {
77 | for (let c = 0; c < this.activeTetromino.length; c++) {
78 | // we draw only occupied squares
79 | if (this.activeTetromino[r][c]) {
80 | drawSquare(this.x + c, this.y + r, color);
81 | }
82 | }
83 | }
84 | }
85 |
86 | // draw a piece to the board
87 | Piece.prototype.draw = function () {
88 | this.fill(this.color);
89 | }
90 |
91 | // undraw a piece
92 | Piece.prototype.unDraw = function () {
93 | this.fill(VACANT);
94 | }
95 |
96 | // move Down the piece
97 | Piece.prototype.moveDown = function () {
98 | if (!this.collision(0, 1, this.activeTetromino)) {
99 | this.unDraw();
100 | this.y++;
101 | this.draw();
102 | } else {
103 | // we lock the piece and generate a new one
104 | this.lock();
105 | if (!gameOver) {
106 | p = randomPiece();
107 | }
108 | }
109 | }
110 |
111 | // move Right the piece
112 | Piece.prototype.moveRight = function () {
113 | if (!this.collision(1, 0, this.activeTetromino)) {
114 | this.unDraw();
115 | this.x++;
116 | this.draw();
117 | }
118 | }
119 |
120 | // move Left the piece
121 | Piece.prototype.moveLeft = function () {
122 | if (!this.collision(-1, 0, this.activeTetromino)) {
123 | this.unDraw();
124 | this.x--;
125 | this.draw();
126 | }
127 | }
128 |
129 | // rotate the piece
130 | Piece.prototype.rotate = function () {
131 | let nextPattern = this.tetromino[(this.tetrominoN + 1) % this.tetromino.length];
132 | let kick = 0;
133 |
134 | if (this.collision(0, 0, nextPattern)) {
135 | if (this.x > COL / 2) {
136 | // it's the right wall
137 | kick = -1; // we need to move the piece to the left
138 | } else {
139 | // it's the left wall
140 | kick = 1; // we need to move the piece to the right
141 | }
142 | }
143 |
144 | if (!this.collision(kick, 0, nextPattern)) {
145 | this.unDraw();
146 | this.x += kick;
147 | this.tetrominoN = (this.tetrominoN + 1) % this.tetromino.length; // (0+1)%4 => 1
148 | this.activeTetromino = this.tetromino[this.tetrominoN];
149 | this.draw();
150 | }
151 | }
152 |
153 | let score = 0;
154 |
155 | // Modify the lock function to show the game over screen
156 | Piece.prototype.lock = function () {
157 | for (let r = 0; r < this.activeTetromino.length; r++) {
158 | for (let c = 0; c < this.activeTetromino.length; c++) {
159 | if (!this.activeTetromino[r][c]) {
160 | continue;
161 | }
162 | if (this.y + r < 0) {
163 | gameOver = true;
164 | document.getElementById("gameOverScreen").style.display = "flex";
165 | clearInterval(timer); // Stop the timer
166 | return;
167 | }
168 | board[this.y + r][this.x + c] = this.color;
169 | }
170 | }
171 | for (let r = 0; r < ROW; r++) {
172 | let isRowFull = true;
173 | for (let c = 0; c < COL; c++) {
174 | isRowFull = isRowFull && (board[r][c] != VACANT);
175 | }
176 | if (isRowFull) {
177 | for (let y = r; y > 1; y--) {
178 | for (let c = 0; c < COL; c++) {
179 | board[y][c] = board[y - 1][c];
180 | }
181 | }
182 | for (let c = 0; c < COL; c++) {
183 | board[0][c] = VACANT;
184 | }
185 | score += 10;
186 | }
187 | }
188 | drawBoard();
189 | scoreElement.innerHTML = score;
190 | document.getElementById("finalscore").innerHTML = "Your Score is: " + score;
191 | }
192 |
193 | // collision function
194 | Piece.prototype.collision = function (x, y, piece) {
195 | for (let r = 0; r < piece.length; r++) {
196 | for (let c = 0; c < piece.length; c++) {
197 | // if the square is empty, we skip it
198 | if (!piece[r][c]) {
199 | continue;
200 | }
201 | // coordinates of the piece after movement
202 | let newX = this.x + c + x;
203 | let newY = this.y + r + y;
204 |
205 | // conditions
206 | if (newX < 0 || newX >= COL || newY >= ROW) {
207 | return true;
208 | }
209 | // skip newY < 0; board[-1] will crash our game
210 | if (newY < 0) {
211 | continue;
212 | }
213 | // check if there is a locked piece already in place
214 | if (board[newY][newX] != VACANT) {
215 | return true;
216 | }
217 | }
218 | }
219 | return false;
220 | }
221 |
222 | // CONTROL the piece
223 | document.addEventListener("keydown", CONTROL);
224 |
225 | function CONTROL(event) {
226 | if (gameOver) return;
227 | if (event.keyCode == 37) {
228 | p.moveLeft();
229 | } else if (event.keyCode == 38) {
230 | p.rotate();
231 | } else if (event.keyCode == 39) {
232 | p.moveRight();
233 | } else if (event.keyCode == 40) {
234 | p.moveDown();
235 | } else if (event.keyCode == 32) { // Check if spacebar is pressed
236 | while (!p.collision(0, 1, p.activeTetromino)) { // Move down until collision
237 | p.moveDown();
238 | }
239 | p.lock(); // Lock the tetromino in place
240 | scoreElement.innerHTML = score; // Update the score display
241 | if (!gameOver) {
242 | p = randomPiece(); // Generate a new tetromino
243 | }
244 | }
245 | }
246 |
247 | let dropStart = Date.now();
248 | let gameOver = false;
249 |
250 | function drop() {
251 | let now = Date.now();
252 | let delta = now - dropStart;
253 | if (delta > 500) {
254 | if (!gameOver) {
255 | p.moveDown();
256 | }
257 | dropStart = Date.now();
258 | }
259 | if (!gameOver) {
260 | requestAnimationFrame(drop);
261 | }
262 | }
263 |
264 | function updateTimer() {
265 | if (totalTime > 0) {
266 | totalTime--;
267 | timerDisplay.innerHTML = totalTime;
268 | } else {
269 | gameOver = true;
270 | document.getElementById("gameOverScreen").style.display = "flex";
271 | clearInterval(timer); // Stop the timer
272 | }
273 | }
274 |
275 | // Initialize the timer
276 | function startTimer() {
277 | clearInterval(timer); // Clear any existing interval
278 | timer = setInterval(updateTimer, 1000); // Update timer every second
279 | }
280 |
281 | function initGame() {
282 | // Reset game variables
283 | score = 0;
284 | gameOver = false;
285 | scoreElement.innerHTML = score;
286 | totalTime = 60; // Reset the timer
287 | timerDisplay.innerHTML = totalTime; // Update the display
288 |
289 | // Reset the board
290 | board = [];
291 | for (let r = 0; r < ROW; r++) {
292 | board[r] = [];
293 | for (let c = 0; c < COL; c++) {
294 | board[r][c] = VACANT;
295 | }
296 | }
297 |
298 | drawBoard();
299 | p = randomPiece();
300 | drop();
301 | startTimer(); // Start the timer
302 | }
303 |
304 | // Retry Game
305 | function retryGame() {
306 | document.getElementById("gameOverScreen").style.display = "none";
307 | initGame();
308 | }
309 | // Initialize the game when the script loads
310 | initGame();
--------------------------------------------------------------------------------
/tetris initialization scripts/tetris-noghostblock.js:
--------------------------------------------------------------------------------
1 | const cvs = document.getElementById("tetris");
2 | const ctx = cvs.getContext("2d");
3 | const scoreElement = document.getElementById("scoreboard");
4 |
5 | const ROW = 20;
6 | const COL = COLUMN = 10;
7 | const SQ = squareSize = 32;
8 | const VACANT = "black"; // color of an empty square
9 |
10 | // draw a square
11 | function drawSquare(x, y, color) {
12 | ctx.fillStyle = color;
13 | ctx.fillRect(x * SQ, y * SQ, SQ, SQ);
14 | ctx.strokeStyle = "black";
15 | ctx.strokeRect(x * SQ, y * SQ, SQ, SQ);
16 | }
17 |
18 | // create the board
19 | let board = [];
20 | for (r = 0; r < ROW; r++) {
21 | board[r] = [];
22 | for (c = 0; c < COL; c++) {
23 | board[r][c] = VACANT;
24 | }
25 | }
26 |
27 | // draw the board
28 | function drawBoard() {
29 | for (r = 0; r < ROW; r++) {
30 | for (c = 0; c < COL; c++) {
31 | drawSquare(c, r, board[r][c]);
32 | }
33 | }
34 | }
35 |
36 | drawBoard();
37 |
38 | // the pieces and their colors
39 | const PIECES = [
40 | [Z, "red"],
41 | [S, "green"],
42 | [T, "yellow"],
43 | [O, "blue"],
44 | [L, "purple"],
45 | [I, "cyan"],
46 | [J, "orange"]
47 | ];
48 |
49 | // generate random pieces
50 | function randomPiece() {
51 | let r = Math.floor(Math.random() * PIECES.length); // 0 -> 6
52 | return new Piece(PIECES[r][0], PIECES[r][1]);
53 | }
54 |
55 | let p;
56 |
57 | // The Object Piece
58 | function Piece(tetromino, color) {
59 | this.tetromino = tetromino;
60 | this.color = color;
61 |
62 | this.tetrominoN = 0; // we start from the first pattern
63 | this.activeTetromino = this.tetromino[this.tetrominoN];
64 |
65 | // we need to control the pieces
66 | this.x = 3;
67 | this.y = -2;
68 | }
69 |
70 | // fill function
71 | Piece.prototype.fill = function (color) {
72 | for (r = 0; r < this.activeTetromino.length; r++) {
73 | for (c = 0; c < this.activeTetromino.length; c++) {
74 | // we draw only occupied squares
75 | if (this.activeTetromino[r][c]) {
76 | drawSquare(this.x + c, this.y + r, color);
77 | }
78 | }
79 | }
80 | }
81 |
82 | // draw a piece to the board
83 | Piece.prototype.draw = function () {
84 | this.fill(this.color);
85 | }
86 |
87 | // undraw a piece
88 | Piece.prototype.unDraw = function () {
89 | this.fill(VACANT);
90 | }
91 |
92 | // move Down the piece
93 | Piece.prototype.moveDown = function () {
94 | if (!this.collision(0, 1, this.activeTetromino)) {
95 | this.unDraw();
96 | this.y++;
97 | this.draw();
98 | } else {
99 | // we lock the piece and generate a new one
100 | this.lock();
101 | if (!gameOver) {
102 | p = randomPiece();
103 | }
104 | }
105 | }
106 |
107 | // move Right the piece
108 | Piece.prototype.moveRight = function () {
109 | if (!this.collision(1, 0, this.activeTetromino)) {
110 | this.unDraw();
111 | this.x++;
112 | this.draw();
113 | }
114 | }
115 |
116 | // move Left the piece
117 | Piece.prototype.moveLeft = function () {
118 | if (!this.collision(-1, 0, this.activeTetromino)) {
119 | this.unDraw();
120 | this.x--;
121 | this.draw();
122 | }
123 | }
124 |
125 | // rotate the piece
126 | Piece.prototype.rotate = function () {
127 | let nextPattern = this.tetromino[(this.tetrominoN + 1) % this.tetromino.length];
128 | let kick = 0;
129 |
130 | if (this.collision(0, 0, nextPattern)) {
131 | if (this.x > COL / 2) {
132 | // it's the right wall
133 | kick = -1; // we need to move the piece to the left
134 | } else {
135 | // it's the left wall
136 | kick = 1; // we need to move the piece to the right
137 | }
138 | }
139 |
140 | if (!this.collision(kick, 0, nextPattern)) {
141 | this.unDraw();
142 | this.x += kick;
143 | this.tetrominoN = (this.tetrominoN + 1) % this.tetromino.length; // (0+1)%4 => 1
144 | this.activeTetromino = this.tetromino[this.tetrominoN];
145 | this.draw();
146 | }
147 | }
148 |
149 | let score = 0;
150 |
151 | // Modify the lock function to show the game over screen
152 | Piece.prototype.lock = function () {
153 | for (let r = 0; r < this.activeTetromino.length; r++) {
154 | for (let c = 0; c < this.activeTetromino.length; c++) {
155 | if (!this.activeTetromino[r][c]) {
156 | continue;
157 | }
158 | if (this.y + r < 0) {
159 | gameOver = true;
160 | document.getElementById("gameOverScreen").style.display = "flex";
161 | return;
162 | }
163 | board[this.y + r][this.x + c] = this.color;
164 | }
165 | }
166 | for (let r = 0; r < ROW; r++) {
167 | let isRowFull = true;
168 | for (let c = 0; c < COL; c++) {
169 | isRowFull = isRowFull && (board[r][c] != VACANT);
170 | }
171 | if (isRowFull) {
172 | for (let y = r; y > 1; y--) {
173 | for (let c = 0; c < COL; c++) {
174 | board[y][c] = board[y - 1][c];
175 | }
176 | }
177 | for (let c = 0; c < COL; c++) {
178 | board[0][c] = VACANT;
179 | }
180 | score += 10;
181 | }
182 | }
183 | drawBoard();
184 | scoreElement.innerHTML = score;
185 | }
186 |
187 | // collision function
188 | Piece.prototype.collision = function (x, y, piece) {
189 | for (r = 0; r < piece.length; r++) {
190 | for (c = 0; c < piece.length; c++) {
191 | // if the square is empty, we skip it
192 | if (!piece[r][c]) {
193 | continue;
194 | }
195 | // coordinates of the piece after movement
196 | let newX = this.x + c + x;
197 | let newY = this.y + r + y;
198 |
199 | // conditions
200 | if (newX < 0 || newX >= COL || newY >= ROW) {
201 | return true;
202 | }
203 | // skip newY < 0; board[-1] will crash our game
204 | if (newY < 0) {
205 | continue;
206 | }
207 | // check if there is a locked piece already in place
208 | if (board[newY][newX] != VACANT) {
209 | return true;
210 | }
211 | }
212 | }
213 | return false;
214 | }
215 |
216 | // CONTROL the piece
217 | document.addEventListener("keydown", CONTROL);
218 |
219 | function CONTROL(event) {
220 | if (gameOver) return;
221 | if (event.keyCode == 37) {
222 | p.moveLeft();
223 | } else if (event.keyCode == 38) {
224 | p.rotate();
225 | } else if (event.keyCode == 39) {
226 | p.moveRight();
227 | } else if (event.keyCode == 40) {
228 | p.moveDown();
229 | } else if (event.keyCode == 32) { // Check if spacebar is pressed
230 | while (!p.collision(0, 1, p.activeTetromino)) { // Move down until collision
231 | p.moveDown();
232 | }
233 | p.lock(); // Lock the tetromino in place
234 | scoreElement.innerHTML = score; // Update the score display
235 | if (!gameOver) {
236 | p = randomPiece(); // Generate a new tetromino
237 | }
238 | }
239 | }
240 |
241 | let dropStart = Date.now();
242 | let gameOver = false;
243 |
244 | function drop() {
245 | let now = Date.now();
246 | let delta = now - dropStart;
247 | if (delta > 500) {
248 | if (!gameOver) {
249 | p.moveDown();
250 | }
251 | dropStart = Date.now();
252 | }
253 | if (!gameOver) {
254 | requestAnimationFrame(drop);
255 | }
256 | }
257 |
258 | function initGame() {
259 | // Reset game variables
260 | score = 0;
261 | gameOver = false;
262 | scoreElement.innerHTML = score;
263 |
264 | // Reset the board
265 | board = [];
266 | for (r = 0; r < ROW; r++) {
267 | board[r] = [];
268 | for (c = 0; c < COL; c++) {
269 | board[r][c] = VACANT;
270 | }
271 | }
272 |
273 | drawBoard();
274 | p = randomPiece();
275 | drop();
276 | }
277 |
278 | // Retry Game
279 | function retryGame() {
280 | document.getElementById("gameOverScreen").style.display = "none";
281 | initGame();
282 | }
283 |
284 | // Initialize the game when the script loads
285 | initGame();
286 |
--------------------------------------------------------------------------------
/tetris initialization scripts/tetris.js:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | const cvs = document.getElementById("tetris");
6 | const ctx = cvs.getContext("2d");
7 | const scoreElement = document.getElementById("scoreboard");
8 | const timerElement = document.getElementById("timer");
9 |
10 | const ROW = 20;
11 | const COL = COLUMN = 10;
12 | const SQ = squareSize = 32;
13 | const VACANT = "black"; // color of an empty square
14 |
15 | // draw a square
16 | function drawSquare(x, y, color) {
17 | ctx.fillStyle = color;
18 | ctx.fillRect(x * SQ, y * SQ, SQ, SQ);
19 | ctx.strokeStyle = "black";
20 | ctx.strokeRect(x * SQ, y * SQ, SQ, SQ);
21 | }
22 |
23 | // create the board
24 | let board = [];
25 | for (let r = 0; r < ROW; r++) {
26 | board[r] = [];
27 | for (let c = 0; c < COL; c++) {
28 | board[r][c] = VACANT;
29 | }
30 | }
31 |
32 | // draw the board
33 | function drawBoard() {
34 | for (let r = 0; r < ROW; r++) {
35 | for (let c = 0; c < COL; c++) {
36 | drawSquare(c, r, board[r][c]);
37 | }
38 | }
39 | }
40 |
41 | drawBoard();
42 |
43 | // the pieces and their colors
44 | const PIECES = [
45 | [Z, "red"],
46 | [S, "green"],
47 | [T, "yellow"],
48 | [O, "blue"],
49 | [L, "purple"],
50 | [I, "cyan"],
51 | [J, "orange"]
52 | ];
53 |
54 | // generate random pieces
55 | function randomPiece() {
56 | let r = Math.floor(Math.random() * PIECES.length); // 0 -> 6
57 | return new Piece(PIECES[r][0], PIECES[r][1]);
58 | }
59 |
60 | let p;
61 |
62 | // The Object Piece
63 | function Piece(tetromino, color) {
64 | this.tetromino = tetromino;
65 | this.color = color;
66 |
67 | this.tetrominoN = 0; // we start from the first pattern
68 | this.activeTetromino = this.tetromino[this.tetrominoN];
69 |
70 | // we need to control the pieces
71 | this.x = 3;
72 | this.y = -2;
73 | }
74 |
75 | // fill function
76 | Piece.prototype.fill = function(color) {
77 | for (let r = 0; r < this.activeTetromino.length; r++) {
78 | for (let c = 0; c < this.activeTetromino.length; c++) {
79 | // we draw only occupied squares
80 | if (this.activeTetromino[r][c]) {
81 | drawSquare(this.x + c, this.y + r, color);
82 | }
83 | }
84 | }
85 | }
86 |
87 | // draw a piece to the board
88 | Piece.prototype.draw = function() {
89 | this.fill(this.color);
90 | }
91 |
92 | // undraw a piece
93 | Piece.prototype.unDraw = function() {
94 | this.fill(VACANT);
95 | }
96 |
97 | // draw the ghost piece
98 | Piece.prototype.drawGhost = function() {
99 | const ghostColor = 'rgba(255, 255, 255, 0.2)'; // light color with transparency
100 | let ghostY = this.y;
101 |
102 | // Find the position where the piece would land
103 | while (!this.collision(0, 1, this.activeTetromino, ghostY + 1)) {
104 | ghostY++;
105 | }
106 |
107 | // Draw the ghost piece
108 | for (let r = 0; r < this.activeTetromino.length; r++) {
109 | for (let c = 0; c < this.activeTetromino.length; c++) {
110 | if (this.activeTetromino[r][c]) {
111 | drawSquare(this.x + c, ghostY + r, ghostColor);
112 | }
113 | }
114 | }
115 | }
116 |
117 | // move Down the piece
118 | Piece.prototype.moveDown = function() {
119 | if (!this.collision(0, 1, this.activeTetromino)) {
120 | this.unDraw();
121 | this.y++;
122 | draw(); // Update the draw function to include the ghost piece
123 | } else {
124 | // we lock the piece and generate a new one
125 | this.lock();
126 | if (!gameOver) {
127 | p = randomPiece();
128 | }
129 | }
130 | }
131 |
132 | // move Right the piece
133 | Piece.prototype.moveRight = function() {
134 | if (!this.collision(1, 0, this.activeTetromino)) {
135 | this.unDraw();
136 | this.x++;
137 | draw(); // Update the draw function to include the ghost piece
138 | }
139 | }
140 |
141 | // move Left the piece
142 | Piece.prototype.moveLeft = function() {
143 | if (!this.collision(-1, 0, this.activeTetromino)) {
144 | this.unDraw();
145 | this.x--;
146 | draw(); // Update the draw function to include the ghost piece
147 | }
148 | }
149 |
150 | // rotate the piece
151 | Piece.prototype.rotate = function() {
152 | let nextPattern = this.tetromino[(this.tetrominoN + 1) % this.tetromino.length];
153 | let kick = 0;
154 |
155 | if (this.collision(0, 0, nextPattern)) {
156 | if (this.x > COL / 2) {
157 | // it's the right wall
158 | kick = -1; // we need to move the piece to the left
159 | } else {
160 | // it's the left wall
161 | kick = 1; // we need to move the piece to the right
162 | }
163 | }
164 |
165 | if (!this.collision(kick, 0, nextPattern)) {
166 | this.unDraw();
167 | this.x += kick;
168 | this.tetrominoN = (this.tetrominoN + 1) % this.tetromino.length; // (0+1)%4 => 1
169 | this.activeTetromino = nextPattern;
170 | draw(); // Update the draw function to include the ghost piece
171 | }
172 | }
173 |
174 | let score = 0;
175 |
176 | // Modify the lock function to show the game over screen
177 | Piece.prototype.lock = function() {
178 | for (let r = 0; r < this.activeTetromino.length; r++) {
179 | for (let c = 0; c < this.activeTetromino.length; c++) {
180 | if (!this.activeTetromino[r][c]) {
181 | continue;
182 | }
183 | if (this.y + r < 0) {
184 | gameOver = true;
185 | document.getElementById("gameOverScreen").style.display = "flex";
186 | document.getElementById("gameOverScoreboard").innerHTML = "Score: " + score; // Update the score display
187 | return;
188 | }
189 | board[this.y + r][this.x + c] = this.color;
190 | }
191 | }
192 | for (let r = 0; r < ROW; r++) {
193 | let isRowFull = true;
194 | for (let c = 0; c < COL; c++) {
195 | isRowFull = isRowFull && (board[r][c] != VACANT);
196 | }
197 | if (isRowFull) {
198 | for (let y = r; y > 1; y--) {
199 | for (let c = 0; c < COL; c++) {
200 | board[y][c] = board[y - 1][c];
201 | }
202 | }
203 | for (let c = 0; c < COL; c++) {
204 | board[0][c] = VACANT;
205 | }
206 | score += 10;
207 | }
208 | }
209 | drawBoard();
210 | scoreElement.innerHTML = score;
211 | }
212 |
213 | // collision function
214 | Piece.prototype.collision = function(x, y, piece, newY = this.y + y) {
215 | for (let r = 0; r < piece.length; r++) {
216 | for (let c = 0; c < piece.length; c++) {
217 | // if the square is empty, we skip it
218 | if (!piece[r][c]) {
219 | continue;
220 | }
221 | // coordinates of the piece after movement
222 | let newX = this.x + c + x;
223 | let testY = newY + r;
224 |
225 | // conditions
226 | if (newX < 0 || newX >= COL || testY >= ROW) {
227 | return true;
228 | }
229 | // skip newY < 0; board[-1] will crash our game
230 | if (testY < 0) {
231 | continue;
232 | }
233 | // check if there is a locked piece already in place
234 | if (board[testY][newX] != VACANT) {
235 | return true;
236 | }
237 | }
238 | }
239 | return false;
240 | }
241 |
242 | // CONTROL the piece
243 | document.addEventListener("keydown", CONTROL);
244 |
245 | function CONTROL(event) {
246 | if (gameOver) return;
247 | if (event.keyCode == 37) {
248 | p.moveLeft();
249 | } else if (event.keyCode == 38) {
250 | p.rotate();
251 | } else if (event.keyCode == 39) {
252 | p.moveRight();
253 | } else if (event.keyCode == 40) {
254 | p.moveDown();
255 | } else if (event.keyCode == 32) { // Check if spacebar is pressed
256 | while (!p.collision(0, 1, p.activeTetromino)) { // Move down until collision
257 | p.moveDown();
258 | }
259 | p.lock(); // Lock the tetromino in place
260 | scoreElement.innerHTML = score; // Update the score display
261 | if (!gameOver) {
262 | p = randomPiece(); // Generate a new tetromino
263 | }
264 | }
265 | }
266 |
267 | let dropStart = Date.now();
268 | let gameOver = false;
269 |
270 | function drop() {
271 | let now = Date.now();
272 | let delta = now - dropStart;
273 | if (delta > 500) {
274 | if (!gameOver) {
275 | p.moveDown();
276 | }
277 | dropStart = Date.now();
278 | }
279 | if (!gameOver) {
280 | requestAnimationFrame(drop);
281 | }
282 | }
283 |
284 | function initGame() {
285 | // Reset game variables
286 | score = 0;
287 | gameOver = false;
288 | scoreElement.innerHTML = score;
289 |
290 | // Reset the board
291 | board = [];
292 | for (let r = 0; r < ROW; r++) {
293 | board[r] = [];
294 | for (let c = 0; c < COL; c++) {
295 | board[r][c] = VACANT;
296 | }
297 | }
298 |
299 | drawBoard();
300 | p = randomPiece();
301 | drop();
302 | }
303 |
304 | function retryGame() {
305 | document.getElementById("gameOverScreen").style.display = "none";
306 | initGame();
307 | scoreElement.innerHTML = score; // Add this line to update the score display
308 |
309 | }
310 |
311 | initGame();
312 |
313 | function draw() {
314 | ctx.clearRect(0, 0, cvs.width, cvs.height); // Clear the canvas
315 | drawBoard();
316 | p.drawGhost(); // Draw the ghost piece
317 | p.draw(); // Draw the main piece
318 | }
--------------------------------------------------------------------------------
/tetris initialization scripts/tetrominoes.js:
--------------------------------------------------------------------------------
1 | const I = [
2 | [
3 | [0, 0, 0, 0],
4 | [1, 1, 1, 1],
5 | [0, 0, 0, 0],
6 | [0, 0, 0, 0],
7 | ],
8 | [
9 | [0, 0, 1, 0],
10 | [0, 0, 1, 0],
11 | [0, 0, 1, 0],
12 | [0, 0, 1, 0],
13 | ],
14 | [
15 | [0, 0, 0, 0],
16 | [0, 0, 0, 0],
17 | [1, 1, 1, 1],
18 | [0, 0, 0, 0],
19 | ],
20 | [
21 | [0, 1, 0, 0],
22 | [0, 1, 0, 0],
23 | [0, 1, 0, 0],
24 | [0, 1, 0, 0],
25 | ]
26 | ];
27 |
28 | const J = [
29 | [
30 | [1, 0, 0],
31 | [1, 1, 1],
32 | [0, 0, 0]
33 | ],
34 | [
35 | [0, 1, 1],
36 | [0, 1, 0],
37 | [0, 1, 0]
38 | ],
39 | [
40 | [0, 0, 0],
41 | [1, 1, 1],
42 | [0, 0, 1]
43 | ],
44 | [
45 | [0, 1, 0],
46 | [0, 1, 0],
47 | [1, 1, 0]
48 | ]
49 | ];
50 |
51 | const L = [
52 | [
53 | [0, 0, 1],
54 | [1, 1, 1],
55 | [0, 0, 0]
56 | ],
57 | [
58 | [0, 1, 0],
59 | [0, 1, 0],
60 | [0, 1, 1]
61 | ],
62 | [
63 | [0, 0, 0],
64 | [1, 1, 1],
65 | [1, 0, 0]
66 | ],
67 | [
68 | [1, 1, 0],
69 | [0, 1, 0],
70 | [0, 1, 0]
71 | ]
72 | ];
73 |
74 | const O = [
75 | [
76 | [0, 0, 0, 0],
77 | [0, 1, 1, 0],
78 | [0, 1, 1, 0],
79 | [0, 0, 0, 0],
80 | ]
81 | ];
82 |
83 | const S = [
84 | [
85 | [0, 1, 1],
86 | [1, 1, 0],
87 | [0, 0, 0]
88 | ],
89 | [
90 | [0, 1, 0],
91 | [0, 1, 1],
92 | [0, 0, 1]
93 | ],
94 | [
95 | [0, 0, 0],
96 | [0, 1, 1],
97 | [1, 1, 0]
98 | ],
99 | [
100 | [1, 0, 0],
101 | [1, 1, 0],
102 | [0, 1, 0]
103 | ]
104 | ];
105 |
106 | const T = [
107 | [
108 | [0, 1, 0],
109 | [1, 1, 1],
110 | [0, 0, 0]
111 | ],
112 | [
113 | [0, 1, 0],
114 | [0, 1, 1],
115 | [0, 1, 0]
116 | ],
117 | [
118 | [0, 0, 0],
119 | [1, 1, 1],
120 | [0, 1, 0]
121 | ],
122 | [
123 | [0, 1, 0],
124 | [1, 1, 0],
125 | [0, 1, 0]
126 | ]
127 | ];
128 |
129 | const Z = [
130 | [
131 | [1, 1, 0],
132 | [0, 1, 1],
133 | [0, 0, 0]
134 | ],
135 | [
136 | [0, 0, 1],
137 | [0, 1, 1],
138 | [0, 1, 0]
139 | ],
140 | [
141 | [0, 0, 0],
142 | [1, 1, 0],
143 | [0, 1, 1]
144 | ],
145 | [
146 | [0, 1, 0],
147 | [1, 1, 0],
148 | [1, 0, 0]
149 | ]
150 | ];
--------------------------------------------------------------------------------