Compare commits

110 Commits

Author SHA1 Message Date
81b243bd85 hard drop rotation 2026-03-16 13:30:20 +01:00
4320b46e37 group tetr.io skins by authors 2026-03-14 17:53:56 +01:00
b2738f6923 game over sound 2026-03-12 09:32:37 +01:00
7730d72315 improve sounds 2026-03-12 09:25:51 +01:00
56ed3b5c13 if (sfxVolumeRange.value) 2026-03-12 03:13:28 +01:00
6706d60086 more sounds 2026-03-12 02:41:08 +01:00
040dc5d5e9 round 2026-03-11 19:52:19 +01:00
b8b743871e defaults, round 2026-03-11 18:10:20 +01:00
018d623143 fix space in url 2026-03-11 16:18:32 +01:00
54cb17fb88 use https://you.have.fail/tetrioplus/ skins 2026-03-11 15:05:34 +01:00
7bdb9524ad sanitize input 2026-03-10 03:23:30 +01:00
923ec9f95d improve jstris skin 2026-03-10 02:06:05 +01:00
1d9a521595 escapeMarkup 2026-03-09 21:49:02 +01:00
3bb9f302ed improve jstris skin 2026-03-09 21:03:45 +01:00
4bac3face1 use https://konsola5.github.io/jstris-customization-database/ 2026-03-09 19:06:48 +01:00
b2601e9c24 tweaks 2026-03-09 01:50:18 +01:00
89b08832d1 ghost opacity 2026-03-08 05:35:43 +01:00
7ed61e135b support for jstris skin as well 2026-03-08 05:28:16 +01:00
a49c95f1aa no overlay 2026-03-08 04:08:48 +01:00
d0a2f1b7f9 use external skins 2026-03-07 23:13:45 +01:00
aed0601933 a bit of 3D 2026-03-05 21:14:34 +01:00
896b26684a sprites 2026-03-05 09:03:17 +01:00
bf18998caa fix paste error 2026-03-05 08:46:10 +01:00
f261f01684 less blinks 2026-03-05 02:01:38 +01:00
49e56427b1 optimization 2026-03-04 23:54:27 +01:00
b72276b76c neo-classic theme 2026-03-04 19:50:44 +01:00
d4d0dfaf30 merge and rename themes 2026-03-04 08:52:24 +01:00
5ba379d968 ridge 2026-03-04 00:17:41 +01:00
f6ebe87434 shadow 2026-03-03 16:50:32 +01:00
24b0e72eab more bounce 2026-03-03 14:51:59 +01:00
ab105bf485 settings reorder 2026-03-01 21:29:21 +01:00
ea8dbff564 pseudo 3d 2026-03-01 21:29:10 +01:00
9a2989616a top side 2026-03-01 15:32:02 +01:00
d6006e657f ghost 2026-03-01 11:48:18 +01:00
ce758c1e92 update cleared line animation 2026-02-28 10:31:24 +01:00
8a0590f1b3 hsl 2026-02-23 23:21:11 +01:00
70caed8fb8 ridge 2026-02-23 18:15:31 +01:00
b6eeae15b9 pop is the new classic 2026-02-23 17:11:34 +01:00
45c0e090e5 less brilliant 2026-02-21 11:52:26 +01:00
73ec2015ba more more brilliant 2026-02-21 02:23:48 +01:00
91e1ea9d3a more brilliant 2026-02-20 21:02:52 +01:00
798ac21372 pause on fullscreen exit 2026-02-20 09:05:23 +01:00
2820c42ba8 cover 2026-02-16 00:20:54 +01:00
8e043b9e8c background position 2026-02-16 00:18:31 +01:00
136ea4156f fix hold glich; prefered theme pop 2026-02-16 00:07:32 +01:00
c01c6dcf58 new theme 2026-02-01 16:30:01 +01:00
25826565af bootstrap checkbox 2026-01-27 11:04:09 +01:00
56b906723c fullscreen checkbox 2026-01-27 08:56:28 +01:00
20b96da34b fix border 2026-01-23 08:22:58 +01:00
bd195f7da6 softer blink 2026-01-23 08:21:15 +01:00
06b444c37e more transparency 2026-01-23 00:56:55 +01:00
71945a7ade clearPiece 2026-01-23 00:54:17 +01:00
0956e3d6e0 don't close game over modal 2026-01-21 20:45:44 +01:00
cc4c477a10 classic locked-animation box-shadow 2026-01-21 20:36:47 +01:00
e196d931ca speed up css 2026-01-18 05:29:07 +01:00
a4117b782a locked-animation 2026-01-16 21:16:05 +01:00
3e3fd6d7f4 tweaks 2026-01-16 03:38:58 +01:00
50a4536994 100px 2026-01-16 03:27:09 +01:00
a4e210526f 3D cleared line animation 2026-01-16 03:23:26 +01:00
cb49d42266 3D cleared line animation 2026-01-16 02:31:13 +01:00
90b1251ebf restart hard dropped animation 2026-01-16 01:31:15 +01:00
26a4d113b5 no cleared line animation 2026-01-15 17:55:24 +01:00
b3d012f489 3d trail 2026-01-15 16:51:02 +01:00
021d67b877 less grab 2026-01-15 16:15:51 +01:00
3af40de841 scroll backward 2026-01-15 13:39:47 +01:00
2d700f1927 fix border translation 2026-01-12 08:45:19 +01:00
280ff0ef9f more light 2026-01-12 01:21:44 +01:00
8e5b45bf6f fix border translation 2026-01-12 01:19:21 +01:00
18977dfd1b more light 2026-01-12 00:23:34 +01:00
334e0e0178 tweaks 2026-01-11 22:38:06 +01:00
02a24ec1f2 border 2026-01-11 22:26:58 +01:00
0cb9fd4c27 more shadows 2026-01-11 18:07:00 +01:00
e21f9c7dfa text-shadow 2026-01-11 17:56:25 +01:00
baf5672de8 hold and next light 2026-01-11 00:55:54 +01:00
9ed62d1e79 hold and next light 2026-01-11 00:51:01 +01:00
2a5ce8faab more text-shadow 2026-01-10 03:49:30 +01:00
4f7d44de4b text-shadow 2026-01-10 03:28:11 +01:00
44e048624a top light 2026-01-10 02:30:12 +01:00
d7fa6c4fe5 Merge branch 'master' of https://git.malingrey.fr/adrien/quatuor 2026-01-10 02:18:05 +01:00
b5ece6f892 stats 2026-01-10 02:15:57 +01:00
181b6d28f6 stats 2026-01-10 02:01:10 +01:00
616b364d40 light! 2026-01-09 21:38:04 +01:00
e17517e2eb left always bright, right always dark 2026-01-09 08:15:50 +01:00
e4c0ba5719 floating ghost 2026-01-09 02:32:03 +01:00
a1028cb054 ghost desaturate 2026-01-09 02:28:41 +01:00
1babf41efe beautifuller 2026-01-09 02:17:45 +01:00
8d371a52ec 3D light 2026-01-09 01:45:22 +01:00
743e23d729 nearer 2026-01-08 22:43:50 +01:00
46ca9f92d3 change side color from orientation 2026-01-08 18:49:41 +01:00
6d0b93dfdb left face from right neighbour 2026-01-08 18:35:58 +01:00
97ca770641 left face on first then right face 2026-01-08 18:34:44 +01:00
3093d880aa border-radius: 2px; 2026-01-07 02:31:33 +01:00
fe77be0381 border-radius 2026-01-07 02:29:09 +01:00
a7fae60a1c 4 faced cubes 2026-01-07 02:18:31 +01:00
7927038fb2 universal? double backdrop-filters 2026-01-06 21:02:03 +01:00
bb74fbef45 Revert "universal? double backdrop-filters"
This reverts commit 994a7a7f04.
2026-01-06 17:26:45 +01:00
994a7a7f04 universal? double backdrop-filters 2026-01-06 11:57:25 +01:00
0c186ccd59 backdrop-filter bug 2026-01-06 09:14:37 +01:00
44d68d79cc grab cursor on all sceneDiv 2026-01-06 02:16:56 +01:00
52a7f37eb0 replace synthwave by new wave style 2026-01-06 02:12:32 +01:00
1f78b2dc10 bout à bout 2026-01-06 01:53:51 +01:00
491f5c021a corrections 2026-01-03 13:06:28 +01:00
c4d9621551 corrections 2026-01-03 05:17:20 +01:00
3d8bc0ce11 Merge branch '3729a3762aa6b1aa08a682aea48fb37ab5fe9bd5' 2026-01-03 05:06:08 +01:00
3729a3762a pop2 style 2026-01-03 02:55:03 +01:00
4b2cd0e5d2 change minimal ghost piece 2025-08-28 10:40:19 +02:00
08763c501e change classic ghost piece 2025-08-28 10:32:48 +02:00
bc5de2448d less blink 2025-08-28 02:32:22 +02:00
67a0f06d03 trail on soft drop 2025-08-28 02:30:17 +02:00
2f1ec2a6f7 white border 2025-08-28 02:17:10 +02:00
127 changed files with 16040 additions and 1239 deletions

View File

@@ -1,22 +1,28 @@
:root {
--cell-side: 24px;
--rX: -15deg;
--rY: 0;
--tZ: 0;
--cell-size: 25px;
--rX: -15;
--rY: 0;
--tZ: 25px;
}
body {
background: linear-gradient(#212529, #14171a) fixed;
background: linear-gradient(#212529, #14171a) fixed;
}
@supports (backdrop-filter: blur()) {
.modal {
.modal::before {
content: '';
position: absolute;
top: 0;
bottom: 0;
left: 0;
right: 0;
backdrop-filter: blur(2px);
}
.modal-content {
background-color: #2125294d;
backdrop-filter: blur(15px);
background-color: #212529b3;
backdrop-filter: blur(10px);
}
}
@@ -25,7 +31,7 @@ body {
}
#matrixCard {
background-image: radial-gradient(#222, #25292d)
background-image: radial-gradient(#222, #25292d);
}
.card-header {
@@ -34,6 +40,7 @@ body {
.modal-title {
text-shadow: 0 0 8px var(--bs-light);
font-weight: 600;
}
#statsTable td,
@@ -41,9 +48,13 @@ body {
text-align: right;
}
td#timeCell {
min-width: 10ch;
}
.minoes-table {
--piece-column: 0;
--piece-row : 0;
--piece-column: 0;
--piece-row: 0;
table-layout: fixed;
border-collapse: separate;
border-spacing: 0;
@@ -51,16 +62,16 @@ body {
}
#matrixTable {
margin-top: calc(-1 * var(--buffer-zone-rows) * var(--cell-side));
margin-top: calc(-1 * var(--buffer-zone-rows) * var(--cell-size));
}
@keyframes hard-dropped-table-animation {
25% {
transform: translateY(2px);
50% {
transform: translate(0, 5px);
}
}
.hard-dropped-table-animation {
animation: hard-dropped-table-animation .2s;
animation: hard-dropped-table-animation ease-in-out 0.2s;
}
tr.buffer-zone td:not(.mino) {
@@ -68,52 +79,73 @@ tr.buffer-zone td:not(.mino) {
}
tr.matrix td:not(.mino) {
border-left : 1px solid #333;
border-right : 1px solid #333;
border-top : 1px solid #303030;
border-left: 1px solid #333;
border-right: 1px solid #333;
border-top: 1px solid #303030;
border-bottom: 1px solid #303030;
}
td {
overflow: hidden;
width: var(--cell-side);
height: var(--cell-side);
width: var(--cell-size);
height: var(--cell-size);
box-sizing: border-box;
}
@keyframes trail-animation {
from {
background-color: #ceffff40;
filter: saturate(50%) brightness(300%);
}
to {
background-color: transparent;
}
}
@keyframes locked-animation {
from {
filter: saturate(50%) brightness(400%);
}
}
.locked.mino {
animation: locked-animation;
animation-duration: 0.2s;
}
td.trail-animation {
animation: trail-animation ease-out .3s;
animation: trail-animation ease-out 0.3s;
}
@keyframes cleared-line-animation {
from {
background-color: #ceffff66;
background-color: white;
filter: saturate(50%) brightness(300%);
box-shadow: -200px 0 5px white, 200px 0 5px white;
box-shadow:
0 0 0 #adb5bd,
0 0 0 #adb5bd;
}
60% {
box-shadow:
-60px 0 2px #adb5bd66,
60px 0 2px #adb5bd66;
}
to {
background-color: transparent;
box-shadow:
-100px 0 5px transparent,
100px 0 5px transparent;
}
}
tr.cleared-line-animation {
animation: cleared-line-animation ease-out .3s;
animation: cleared-line-animation ease-out 0.3s;
}
#holdTable .J,
#holdTable .L,
#holdTable .S,
#holdTable .T,
#holdTable .Z,
#holdTable .Z,
#nextTable .J,
#nextTable .L,
#nextTable .S,
@@ -131,6 +163,7 @@ tr.cleared-line-animation {
text-shadow: 1px 1px #000c;
font-size: 3vmin;
text-align: center;
z-index: 200;
}
#messagesSpan div {
@@ -166,7 +199,6 @@ tr.cleared-line-animation {
opacity: 0;
transform: scale3d(0.3, 0.3, 0.3);
line-height: var(--bs-body-line-height);
}
30% {
opacity: 1;
@@ -186,13 +218,13 @@ tr.cleared-line-animation {
@keyframes rotate-in-animation {
0% {
opacity:0;
transform:rotate(200deg);
opacity: 0;
transform: rotate(200deg);
line-height: var(--bs-body-line-height);
}
30% {
opacity:1;
transform:translateZ(0);
opacity: 1;
transform: translateZ(0);
transform: scale3d(1, 1, 1);
}
80% {
@@ -208,15 +240,15 @@ tr.cleared-line-animation {
}
#messagesSpan div.rotate-in-animation {
animation-name: rotate-in-animation;
animation-timing-function: cubic-bezier(.25,.46,.45,.94);
animation-name: rotate-in-animation;
animation-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
animation-duration: 1s;
}
#messagesSpan div.zoom-in-animation {
animation-name: zoom-in-animation;
animation-timing-function: cubic-bezier(.25,.46,.45,.94);
transform-origin:center;
animation-timing-function: cubic-bezier(0.25, 0.46, 0.45, 0.94);
transform-origin: center;
animation-duration: 1s;
}
@@ -236,4 +268,37 @@ tr.cleared-line-animation {
animation: game-over-animation;
animation-timing-function: (0.4, 0, 0.6, 1);
animation-duration: 2s;
}
}
#statsModal table {
border-collapse: collapse;
}
#statsModal th {
padding-left: 0;
padding-right: 0.5rem;
padding-bottom: 0.2rem;
border-left: 0.5rem solid transparent;
border-right: 0;
}
#statsModal td {
padding-left: 0.5rem;
padding-right: 0;
padding-bottom: 0.2rem;
border-left: 0;
border-right: 0.5rem solid transparent;
}
#statsModal tr:last-child th,
#statsModal tr:last-child td {
border-bottom: none;
}
.select2-dropdown {
width: min-content !important;
}
.select2-results__group {
display: inline-block;
}

204
css/_select2-dark.css Normal file
View File

@@ -0,0 +1,204 @@
body .select2-container--bootstrap-5 .select2-selection {
color: var(--bs-body-color);
background-color: var(--bs-body-bg);
border: var(--bs-border-width) solid var(--bs-border-color);
}
body
.select2-container--bootstrap-5.select2-container--focus
.select2-selection,
body
.select2-container--bootstrap-5.select2-container--open
.select2-selection {
border-color: var(--bs-link-hover-color);
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
}
body
.select2-container--bootstrap-5
.select2-selection--multiple
.select2-selection__clear,
body
.select2-container--bootstrap-5
.select2-selection--single
.select2-selection__clear {
background: transparent
url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23676a6d'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e")
50%/0.75rem auto no-repeat;
}
body
.select2-container--bootstrap-5
.select2-selection--multiple
.select2-selection__clear:hover,
body
.select2-container--bootstrap-5
.select2-selection--single
.select2-selection__clear:hover {
background: transparent
url("data:image/svg+xml,%3csvg xmlns='http://www.w3.org/2000/svg' viewBox='0 0 16 16' fill='%23000'%3e%3cpath d='M.293.293a1 1 0 011.414 0L8 6.586 14.293.293a1 1 0 111.414 1.414L9.414 8l6.293 6.293a1 1 0 01-1.414 1.414L8 9.414l-6.293 6.293a1 1 0 01-1.414-1.414L6.586 8 .293 1.707a1 1 0 010-1.414z'/%3e%3c/svg%3e")
50%/0.75rem auto no-repeat;
}
body .select2-container--bootstrap-5 .select2-dropdown {
color: var(--bs-body-color);
background-color: var(--bs-body-bg);
border-color: var(--bs-link-hover-color);
}
body
.select2-container--bootstrap-5
.select2-dropdown
.select2-search
.select2-search__field {
color: var(--bs-body-color);
background-color: var(--bs-body-bg);
background-clip: padding-box;
border: var(--bs-border-width) solid var(--bs-border-color);
}
body
.select2-container--bootstrap-5
.select2-dropdown
.select2-search
.select2-search__field:focus {
border-color: var(--bs-link-hover-color);
box-shadow: 0 0 0 0.25rem rgba(13, 110, 253, 0.25);
}
body
.select2-container--bootstrap-5
.select2-dropdown
.select2-results__options
.select2-results__option.select2-results__message {
color: #6c757d;
}
body
.select2-container--bootstrap-5
.select2-dropdown
.select2-results__options
.select2-results__option.select2-results__option--highlighted {
color: var(--bs-body-color);
background-color: var(--bs-light-bg-subtle) !important;
}
body
.select2-container--bootstrap-5
.select2-dropdown
.select2-results__options
.select2-results__option.select2-results__option--selected,
body
.select2-container--bootstrap-5
.select2-dropdown
.select2-results__options
.select2-results__option[aria-selected="true"]:not(
.select2-results__option--highlighted
) {
color: var(--bs-body-color);
background-color: var(--bs-dark-bg-subtle);
}
body
.select2-container--bootstrap-5
.select2-dropdown
.select2-results__options
.select2-results__option.select2-results__option--disabled,
body
.select2-container--bootstrap-5
.select2-dropdown
.select2-results__options
.select2-results__option[aria-disabled="true"] {
color: #6c757d;
}
body
.select2-container--bootstrap-5
.select2-dropdown
.select2-results__options
.select2-results__option[role="group"]
.select2-results__group {
color: #6c757d;
}
body
.select2-container--bootstrap-5
.select2-selection--single
.select2-selection__rendered {
color: var(--bs-body-color);
}
body
.select2-container--bootstrap-5
.select2-selection--single
.select2-selection__rendered
.select2-selection__placeholder {
color: #6c757d;
}
body
.select2-container--bootstrap-5
.select2-selection--multiple
.select2-selection__rendered
.select2-selection__choice {
color: var(--bs-body-color);
border: var(--bs-border-width) solid var(--bs-border-color);
}
body
.select2-container--bootstrap-5.select2-container--disabled
.select2-selection,
body
.select2-container--bootstrap-5.select2-container--disabled.select2-container--focus
.select2-selection {
color: #6c757d;
background-color: var(--bs-light-bg-subtle);
border-color: var(--bs-dark-bg-subtle);
}
.is-valid + body .select2-container--bootstrap-5 .select2-selection,
.was-validated
select:valid
+ body
.select2-container--bootstrap-5
.select2-selection {
border-color: #198754;
}
.is-valid
+ body
.select2-container--bootstrap-5.select2-container--focus
.select2-selection,
.is-valid
+ body
.select2-container--bootstrap-5.select2-container--open
.select2-selection,
.was-validated
select:valid
+ body
.select2-container--bootstrap-5.select2-container--focus
.select2-selection,
.was-validated
select:valid
+ body
.select2-container--bootstrap-5.select2-container--open
.select2-selection {
border-color: #198754;
box-shadow: 0 0 0 0.25rem rgba(25, 135, 84, 0.25);
}
.is-invalid + body .select2-container--bootstrap-5 .select2-selection,
.was-validated
select:invalid
+ body
.select2-container--bootstrap-5
.select2-selection {
border-color: #dc3545;
}
.is-invalid
+ body
.select2-container--bootstrap-5.select2-container--focus
.select2-selection,
.is-invalid
+ body
.select2-container--bootstrap-5.select2-container--open
.select2-selection,
.was-validated
select:invalid
+ body
.select2-container--bootstrap-5.select2-container--focus
.select2-selection,
.was-validated
select:invalid
+ body
.select2-container--bootstrap-5.select2-container--open
.select2-selection {
border-color: #dc3545;
box-shadow: 0 0 0 0.25rem rgba(220, 53, 69, 0.25);
}

View File

@@ -1,276 +0,0 @@
body {
background-image: url(binaural/bg.jpg),
radial-gradient(
circle at center,
#39444f 0%,
#2c323b 25%,
#293036 28%,
#252b32 34%,
#242930 38%,
#1a1d22 52%,
#191c22 53%,
#151519 63%,
#141418 65%,
#0f0f12 74%,
#0a0c0d 100%
);
background-repeat: round;
}
#sceneDiv {
perspective: 500px;
}
#sceneDiv * {
transform-style: preserve-3d;
}
#screenRow {
display: block;
transform: translateZ(var(--tZ)) rotateX(var(--rX)) rotateY(var(--rY));
cursor: grab;
}
#screenRow:active {
cursor: grabbing;
}
#screenRow * {
display: block;
}
#screenRow .col {
display: inline-block !important;
width: max-content;
height: 100%;
vertical-align: top;
}
.card {
background: #36394180;
}
#matrixCard {
background-image: none;
}
#screenRow .card > * {
transform: translateZ(var(--cell-side));
}
#screenRow .card-header {
background-color: transparent;
border: none;
}
.minoes-table th,
.minoes-table td {
display: inline-block !important;
width: max-content;
}
.minoes-table tr {
width: max-content;
height: var(--cell-side);
}
#statsTable tr {
display: table;
width: 100%;
}
#statsTable th,
#statsTable td {
display: table-cell;
border: 0;
}
tr.matrix td:not(.mino) {
border: 0;
will-change: transform;
transform: translateZ(0);
}
.minoes-table td {
width: var(--cell-side) !important;
height: var(--cell-side);
}
.minoes-table .mino {
background: radial-gradient(circle at -150% -200%, #fffb 0%, var(--background-color) 100%);
overflow: visible;
}
.mino::before,
.mino::after {
content: '';
position: absolute;
display: block;
top: 0;
left: 0;
width: inherit;
height: inherit;
}
.mino::before {
background: var(--light-color);
transform: translateZ(calc(-1 * var(--cell-side))) rotateY(-90deg);
transform-origin: left;
}
.right .mino::before {
background: var(--dark-color);
transform: translateZ(calc(-1 * var(--cell-side))) rotateY(90deg);
transform-origin: right;
}
.mino::after {
background: var(--light-color);
transform: translateZ(calc(-1 * var(--cell-side))) rotateX(90deg);
transform-origin: top;
}
.bottom .mino::after {
background: var(--dark-color);
transform: translateZ(calc(-1 * var(--cell-side))) rotateX(-90deg);
transform-origin: bottom;
}
.I.mino {
--background-color: #42afe1b0;
--light-color: #6ceaff80;
--dark-color: #00a4b0b0;
}
.J.mino {
--background-color: #1165b5b0;
--light-color: #339bff80;
--dark-color: #00009db0;
}
.L.mino {
--background-color: #f38927b0;
--light-color: #ffba5980;
--dark-color: #c54800b0;
}
.O.mino {
--background-color: #f6d03cb0;
--light-color: #ffff7f80;
--dark-color: #ca9501b0;
}
.S.mino {
--background-color: #51b84db0;
--light-color: #84f88080;
--dark-color: #1cbc02b0;
}
.T.mino {
--background-color: #9739a2b0;
--light-color: #d958e980;
--dark-color: #6e019ab0;
}
.Z.mino {
--background-color: #eb4f65b0;
--light-color: #ff7f7980;
--dark-color: #ad1936b0;
}
.ghost.mino {
--background-color: #8886;
--light-color: #ccc6;
--dark-color: #3336;
}
.locking.mino {
--background-color: #eeeb;
--light-color: #fffb;
--dark-color: #dddb;
}
.disabled.mino {
--background-color: #888b;
--light-color: #cccb;
--dark-color: #333b;
}
@keyframes cleared-line-animation {
from {
background-color: #ceffff66;
box-shadow: -200px 0 5px white, 200px 0 5px white;
}
to {
background-color: transparent;
}
}
@keyframes show-level-animation {
from {
opacity: 1;
transform: translateY(200%);
}
50% {
transform: translateY(0) scaleY(1);
line-height: var(--bs-body-line-height);
}
to {
opacity: 1;
transform: translateY(-100%) scaleY(0);
line-height: 0;
}
}
@keyframes zoom-in-animation {
from {
opacity: 1;
transform: scale3d(0.3, 0.3, 0.3);
line-height: var(--bs-body-line-height);
}
30% {
transform: scale3d(1, 1, 1);
}
80% {
transform: scale3d(1, 1, 1);
line-height: var(--bs-body-line-height);
}
to {
opacity: 1;
transform: scale3d(1.5, 0, 1);
line-height: 0;
}
}
@keyframes rotate-in-animation {
0% {
opacity: 1;
transform: rotate(200deg);
line-height: var(--bs-body-line-height);
}
30% {
transform: translateZ(0);
transform: scale3d(1, 1, 1);
}
80% {
transform: scale3d(1, 1, 1);
line-height: var(--bs-body-line-height);
}
to {
opacity: 1;
transform: scale3d(1.5, 0, 1);
line-height: 0;
}
}
@keyframes game-over-animation {
from {
opacity: 1;
transform: translateY(200%);
}
to {
opacity: 1;
transform: translateY(0) scaleY(1);
line-height: var(--bs-body-line-height);
}
}

View File

@@ -1,123 +1,88 @@
.minoes-table tr {
z-index: calc(100 - var(--row));
position: sticky;
}
tr.matrix td:not(.mino) {
border-left: none;
border-bottom: none;
}
.mino {
background: radial-gradient(
ellipse 140% 66% at 122% 88%,
var(--background-color) 100%,
var(--frontier-color) 105%,
var(--light-color) 130%
--color: hsl(var(--hue), var(--saturation), 40%);
--light: hsl(var(--hue), calc(0.66 * var(--saturation)), 84%);
--top: hsl(var(--hue), calc(0.6 * var(--saturation)), 68%);
background-color: var(--color);
background-image:
radial-gradient(
ellipse 22% 8% at 25% 22%,
#ffffff66,
#ffffff33 40%,
transparent 70%
),
radial-gradient(
ellipse 140% 85% at 50% -15%,
var(--light) 0%,
#ffffff77 40%,
#00000005 55%
),
radial-gradient(
ellipse 120% 220% at 50% 140%,
var(--light) 0%,
var(--color) 55%,
#00000066 95%
);
border: 4px solid;
padding: 0;
opacity: 100%;
border-radius: 1px;
box-shadow: 2px 2px 4px #000a;
border: 4px ridge var(--color);
border-top-color: var(--light);
border-radius: 3px;
box-shadow:
inset 2px 0 4px rgba(0,0,0,.06),
inset -2px 0 4px rgba(0,0,0,.12),
0 -4px 0 var(--top),
0 2px 4px #0008;
filter: saturate(1.1) contrast(1.05);
}
.I.mino {
--background-color : #00d6fb;
--frontier-color : #43e7fd;
--light-color : #afeff9;
border-top-color : #7cf2fd;
border-left-color : #2ed5e5;
border-right-color : #01b8ca;
border-bottom-color: #00a4b0;
.I {
--hue: 193;
--saturation: 100%;
}
.J.mino {
--background-color : #2E00FB;
--frontier-color : #7054fb;
--light-color : #b8b4ff;
border-top-color : #4985fd;
border-left-color : #2f36ea;
border-right-color : #0006ca;
border-bottom-color: #00009d;
.J {
--hue: 215;
--saturation: 100%;
}
.L.mino {
--background-color : #FF7900;
--frontier-color : #fe9551;
--light-color : #fdd0b7;
border-top-color : #fd9f6b;
border-left-color : #e76d28;
border-right-color : #e74f00;
border-bottom-color: #c54800;
.L {
--hue: 25;
--saturation: 100%;
}
.O.mino {
--background-color : #FeCB00;
--frontier-color : #fce15c;
--light-color : #ffedac;;
border-top-color : #ffe364;
border-left-color : #e7ba23;
border-right-color : #e3a707;
border-bottom-color: #ca9501;
.O {
--hue: 42;
--saturation: 100%;
}
.S.mino {
--background-color : #67EE12;
--frontier-color : #93f85a;
--light-color : #C8FBA8;
border-top-color : #a4fc6d;
border-left-color : #5ee82b;
border-right-color : #35db00;
border-bottom-color: #1cbc02;
.S {
--hue: 95;
--saturation: 100%;
}
.T.mino {
--background-color : #B000FE;
--frontier-color : #c541fc;
--light-color : #edb2ff;
border-top-color : #d380ff;
border-left-color : #b42deb;
border-right-color : #8000cd;
border-bottom-color: #6e019a;
.T {
--hue: 300;
--saturation: 56%;
}
.Z.mino {
--background-color : #ed2939;
--frontier-color : #fe6483;
--light-color : #ffb8c5;
border-top-color : #fd718d;
border-left-color : #e62250;
border-right-color : #e20332;
border-bottom-color: #ad1936;
.Z {
--hue: 357;
--saturation: 84%;
}
.ghost.mino {
margin: 1px;
opacity: 20%;
filter: brightness(180%) saturate(60%) blur(1px);
}
.moving.mino {
filter: saturate(80%) brightness(150%);
}
.locking.mino {
filter: saturate(50%) brightness(200%);
box-shadow:
-1px -1px 4px #FFF2,
-1px 1px 4px #FFF2,
1px -1px 4px #FFF2,
1px 1px 4px #FFF2;
}
.disabled.mino {
filter: brightness(50%) contrast(80%);
opacity: 70%;
}
@keyframes locked-animation {
from {
filter: saturate(50%) brightness(400%);
box-shadow:
-1px -1px 4px #FFF2,
-1px 1px 4px #FFF2,
1px -1px 4px #FFF2,
1px 1px 4px #FFF2;
}
}
.locked.mino {
animation: locked-animation;
animation-duration: 0.2s;
.ghost {
border: 3px solid #fff2;
padding: 3px;
background-color: #fff2;
background-clip: content-box;
background-image: none;
box-shadow: none;
}

View File

@@ -1,14 +1,14 @@
body {
background-image: url("electro/bg.jpg");
background-image: url('electro/bg.jpg');
background-size: cover;
}
body[data-bs-theme="dark"] {
--bs-body-bg: #2125296b;
body[data-bs-theme='dark'] {
--bs-body-bg: #2125296b;
}
.btn-dark {
--bs-btn-bg: #2125296b;
--bs-btn-bg: #2125296b;
}
.card {
@@ -16,7 +16,7 @@ body[data-bs-theme="dark"] {
}
tr.matrix td:not(.mino) {
border-left : none;
border-left: none;
border-bottom: none;
}
@@ -30,29 +30,30 @@ tr.matrix td:not(.mino) {
}
.mino:not(.ghost):not(.locking):before {
content: "";
content: '';
position: absolute;
z-index: -1;
inset: 0;
margin: 1px 1px 0px 0px;
padding: 2px;
border-radius: 4px;
--glint-x: calc(50% + 50% * (var(--piece-column) - var(--column))/10);
--glint-y: calc(50% + 50% * (var(--piece-row) - var(--row))/25);
--glint-x: calc(50% + 50% * (var(--piece-column) - var(--column)) / 10);
--glint-y: calc(50% + 50% * (var(--piece-row) - var(--row)) / 25);
background: radial-gradient(
at var(--glint-x) var(--glint-y),
rgba(204, 238, 247, 0.9) 0%,
rgba(10, 159, 218, 0.9) 150%);
mask:
linear-gradient(#666 0 0) content-box,
linear-gradient(#fff 0 0);
rgba(204, 238, 247, 0.9) 0%,
rgba(10, 159, 218, 0.9) 150%
);
mask:
linear-gradient(#666 0 0) content-box,
linear-gradient(#fff 0 0);
mask-mode: luminance;
mask-composite: intersect;
}
.ghost.mino {
background: rgba(242, 255, 255, 10%);
border : 2px solid rgba(255, 255, 255, 0.3);
border: 2px solid rgba(255, 255, 255, 0.3);
border-radius: 3px;
box-shadow: 0px 0px 10px rgba(242, 255, 255, 75%);
}
@@ -78,6 +79,7 @@ tr.matrix td:not(.mino) {
.disabled.mino {
opacity: 60%;
position: relative;
}
.disabled.mino:before {
@@ -92,8 +94,3 @@ tr.matrix td:not(.mino) {
border-color: white;
}
}
.locked.mino {
animation: locked-animation;
animation-duration: 0.2s;
}

61
css/heavy-metal.css Normal file
View File

@@ -0,0 +1,61 @@
#sceneDiv {
perspective: 500px;
}
#screenRow {
transform: rotateX(15deg);
}
#screenRow .card {
box-shadow:
0 10px 3px #25292d,
0 15px 0 var(--bs-card-border-color) !important;;
}
tr.matrix td:not(.mino) {
border-left: none;
border-bottom: none;
}
.mino {
background-color: hsl(var(--hue), 55%, 55%);
background-image: linear-gradient(30deg, #fff4, transparent);
border: 1px outset hsl(var(--hue), 55%, 45%);
border-radius: 2px;
box-shadow:
0 10px 3px hsl(var(--hue), 70%, 10%),
0 15px 0 hsla(var(--hue), 90%, 40%, 70%);
opacity: 80%;
backdrop-filter: blur(6px);
}
.I {
--hue: 197;
}
.J {
--hue: 217;
}
.L {
--hue: 36;
}
.O {
--hue: 60;
}
.S {
--hue: 113;
}
.T {
--hue: 268;
}
.Z {
--hue: 0;
}
.ghost {
opacity: 30%;
}

217
css/jazz.css Normal file
View File

@@ -0,0 +1,217 @@
body {
--bs-gutter-x: 0;
background: black !important;
}
#screenRow {
gap: 0 !important;
margin: 0;
text-transform: uppercase;
letter-spacing: 0.1em;
}
#screenRow {
--bs-gutter-x: 0;
}
.card {
background: black;
border: none;
border-radius: 0;
margin-bottom: 0.5em !important;
}
.card:first-of-type {
border-bottom: 3px solid white;
}
.card-header,
.card-header th {
background: transparent;
font-weight: 400 !important;
font-size: 1.3em;
border: none;
}
#screenRow .table {
--bs-border-width: 0;
}
.minoes-table {
display: flex;
flex-direction: column;
filter: drop-shadow(-2px 0 0 white) drop-shadow(2px 0 0 white) drop-shadow(0 -2px 0 white)
drop-shadow(0 2px 0 white) drop-shadow(5px 8px 0 rgba(9, 9, 9, 22%));
}
.minoes-table tr {
display: flex;
position: relative;
flex-direction: row;
z-index: calc(100 - var(--row));
}
#holdTable {
margin: 0 !important;
}
#statsTable {
width: 10rem;
}
#statsTable tr {
display: flex;
flex-flow: column;
align-items: center;
}
#statsTable td,
#statsTable th {
margin: 0;
padding: 0 !important;
width: auto;
height: auto;
text-transform: uppercase;
}
#statsTable th {
display: inline;
flex-flow: row;
font-size: 0.8em;
text-align: center;
width: 200%;
}
#statsTable td {
font-size: 1.3em;
font-weight: 600;
color: white;
}
td#timeCell {
text-align: center;
}
#matrixCard {
background: transparent;
border-top: none;
border-left: 3px solid white;
border-right: 3px solid white;
border-bottom: 3px solid white;
}
tr.matrix td:not(.mino) {
border: 0;
}
.minoes-table td {
display: inline-block;
width: var(--cell-size);
height: var(--cell-size);
padding: 0 !important;
z-index: calc(200 - var(--row));
}
.mino {
width: inherit;
height: inherit;
display: block;
padding: 0;
opacity: 100%;
border-width: 1px;
border-style: solid;
box-shadow: 0 -6px 0 var(--box-shadow-color);
}
.I.mino {
background-color: #42afe1;
border-color: #6ceaff;
--box-shadow-color: #6ceaff;
}
.J.mino {
background-color: #1165b5;
border-color: #339bff;
--box-shadow-color: #339bff;
}
.L.mino {
background-color: #f38927;
border-color: #ffba59;
--box-shadow-color: #ffba59;
}
.O.mino {
background-color: #f6d03c;
border-color: #ffff7f;
--box-shadow-color: #ffff7f;
}
.S.mino {
background-color: #32ee3e;
border-color: #84f880;
--box-shadow-color: #84f880;
}
.T.mino {
background-color: #9739a2;
border-color: #d958e9;
--box-shadow-color: #d958e9;
}
.Z.mino {
background-color: #eb4f65;
border-color: #ff7f79;
--box-shadow-color: #ff7f79;
}
.ghost.mino {
background-color: #fff4;
border: none;
opacity: 5%;
box-shadow: none;
transform: translateY(-3px);
}
.moving.mino {
filter: saturate(80%) brightness(130%);
}
.locking.mino {
filter: saturate(20%) brightness(300%);
}
.locked.mino {
animation: locked-animation;
animation-duration: 0.2s;
}
.disabled.mino {
filter: brightness(50%) contrast(65%);
opacity: 70%;
}
@keyframes locked-animation {
from {
filter: saturate(50%) brightness(300%);
}
}
@keyframes cleared-line-animation {
from {
background-color: #eeeeee;
}
to {
background-color: transparent;
}
}
@keyframes trail-animation {
from {
background-color: #ceffff05;
filter: saturate(50%) brightness(110%);
}
to {
background-color: transparent;
}
}

118
css/jazz2.css Normal file
View File

@@ -0,0 +1,118 @@
.minoes-table {
display: flex;
flex-direction: column;
filter: drop-shadow(0 8px 1px #0008);
}
.minoes-table tr {
display: flex;
position: relative;
flex-direction: row;
z-index: calc(100 - var(--row));
}
tr.matrix td:not(.mino) {
border: none;
border-right: 1px solid #8884;
}
.minoes-table td {
display: inline-block;
width: var(--cell-size);
height: var(--cell-size);
padding: 0 !important;
z-index: calc(200 - var(--row));
}
.mino {
width: inherit;
height: inherit;
display: block;
padding: 0;
opacity: 100%;
border: none;
box-shadow: 0 -6px 0 var(--box-shadow-color);
}
.I.mino {
background-color: #0293b0;
--box-shadow-color: #05d2f2;
}
.J.mino {
background-color: #2c69c2;
--box-shadow-color: #7bb7f6;
}
.L.mino {
background-color: #fa9b23;
--box-shadow-color: #ffba59;
}
.O.mino {
background-color: #f9d92c;
--box-shadow-color: #fff194;
}
.S.mino {
background-color: #01a493;
--box-shadow-color: #03e7d3;
}
.T.mino {
background-color: #6830d1;
--box-shadow-color: #bb88fc;
}
.Z.mino {
background-color: #ee2b58;
--box-shadow-color: #fd4487;
}
.ghost.mino {
background-color: #fff8;
box-shadow: none;
transform: blue(4px);
}
.moving.mino {
filter: saturate(80%) brightness(130%);
}
.locking.mino {
filter: saturate(20%) brightness(300%);
}
.locked.mino {
animation: locked-animation;
animation-duration: 0.2s;
}
.disabled.mino {
filter: brightness(50%) contrast(65%);
}
@keyframes locked-animation {
from {
filter: saturate(50%) brightness(300%);
}
}
@keyframes cleared-line-animation {
from {
background-color: #eeeeee;
}
to {
background-color: transparent;
}
}
@keyframes trail-animation {
from {
background-color: #ceffff05;
filter: saturate(50%) brightness(110%);
}
to {
background-color: transparent;
}
}

81
css/jstris-skin.css Normal file
View File

@@ -0,0 +1,81 @@
:root {
--cell-size: 24px;
--sprite-size: round(100% / 8, 1px);
--skin-url: url(https://i.imgur.com/HqGYC5G.png);
}
.card {
background-color: #1c1c1c;
}
.card-body {
background-color: black;
}
#matrixCard {
background-image: url(jstris-skin/jstris-grid.png);
background-position: bottom;
background-repeat: no-repeat;
}
tr.matrix td:not(.mino) {
border: none;
}
.mino {
background-image: var(--skin-url);
background-size: cover;
background-repeat: no-repeat;
background-position-x: calc(var(--sprite-pos) * var(--sprite-size));
}
.I {
--sprite-pos: 6;
}
.J {
--sprite-pos: 7;
}
.L {
--sprite-pos: 3;
}
.O {
--sprite-pos: 4;
}
.S {
--sprite-pos: 5;
}
.T {
--sprite-pos: 8;
}
.Z {
--sprite-pos: 2;
}
.ghost {
--sprite-pos: 1;
opacity: 50%;
}
.disabled {
--sprite-pos: 0;
}
.locking.mino {
filter: saturate(60%) brightness(180%);
}
#holdTable .mino,
#nextTable .mino {
box-shadow: 4px 4px 10px #0002;
}
.preview {
--cell-size: 24px;
height: var(--cell-size);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@@ -5,12 +5,8 @@
.minoes-table {
display: flex;
flex-direction: column;
filter:
drop-shadow(-2px 0 0 white)
drop-shadow(2px 0 0 white)
drop-shadow(0 -2px 0 white)
drop-shadow(0 2px 0 white)
drop-shadow(5px 8px 0 rgba(9, 9, 9, 22%));
filter: drop-shadow(-2px 0 0 white) drop-shadow(2px 0 0 white) drop-shadow(0 -2px 0 white)
drop-shadow(0 2px 0 white) drop-shadow(5px 8px 0 rgba(9, 9, 9, 22%));
}
.minoes-table tr {
@@ -26,8 +22,8 @@ tr.matrix td:not(.mino) {
.minoes-table td {
display: inline-block;
width: var(--cell-side);
height: var(--cell-side);
width: var(--cell-size);
height: var(--cell-size);
padding: 0 !important;
z-index: calc(200 - var(--row));
}
@@ -41,43 +37,44 @@ tr.matrix td:not(.mino) {
}
.I.mino {
--background-color: #42AFE1;
--box-shadow-color: #6CEAFF;
--background-color: #42afe1;
--box-shadow-color: #6ceaff;
}
.J.mino {
--background-color: #1165B5;
--box-shadow-color: #339BFF;
--background-color: #1165b5;
--box-shadow-color: #339bff;
}
.L.mino {
--background-color: #F38927;
--box-shadow-color: #FFBA59;
--background-color: #f38927;
--box-shadow-color: #ffba59;
}
.O.mino {
--background-color: #F6D03C;
--box-shadow-color: #FFFF7F;
--background-color: #f6d03c;
--box-shadow-color: #ffff7f;
}
.S.mino {
--background-color: #51B84D;
--box-shadow-color: #84F880;
--background-color: #51b84d;
--box-shadow-color: #84f880;
}
.T.mino {
--background-color: #9739A2;
--box-shadow-color: #D958E9;
--background-color: #9739a2;
--box-shadow-color: #d958e9;
}
.Z.mino {
--background-color: #EB4F65;
--box-shadow-color: #FF7F79;
--background-color: #eb4f65;
--box-shadow-color: #ff7f79;
}
.ghost.mino {
opacity: 50%;
opacity: 5%;
box-shadow: none;
transform: translateY(-6px);
}
.moving.mino {
@@ -85,8 +82,8 @@ tr.matrix td:not(.mino) {
}
.locking.mino {
--background-color: white;
--box-shadow-color: #DDD;
--background-color: white;
--box-shadow-color: #ddd;
}
.locked.mino {
@@ -121,4 +118,4 @@ tr.matrix td:not(.mino) {
to {
background-color: transparent;
}
}
}

89
css/neo-classic.css Normal file
View File

@@ -0,0 +1,89 @@
.minoes-table tr {
z-index: calc(100 - var(--row));
position: sticky;
}
tr.matrix td:not(.mino) {
border-left: none;
border-bottom: none;
}
.mino {
--color: hsl(var(--hue), var(--saturation), 60%);
--dark: hsl(var(--hue), var(--saturation), 28%);
--light: hsl(var(--hue), calc(0.66 * var(--saturation)), 90%);
--border: hsl(var(--hue), var(--saturation), 40%);
--top: hsl(var(--hue), calc(0.6 * var(--saturation)), 75%);
position: relative;
background-color: var(--dark);
background-image: radial-gradient(
ellipse 200% 120% at 50% 75%,
#fff8 10%,
var(--dark) 28%,
#fff8 38%,
var(--dark) 48%
);
border: 1px outset var(--border);
border-radius: 3px;
box-shadow:
inset 3px 0 4px rgba(0,0,0,.06),
inset -3px 0 4px rgba(0,0,0,.12),
0 -3px 0 var(--top),
0 2px 2px #0004;
}
.mino:after {
--size: calc(var(--cell-size) - 12px);
position: absolute;
content: "";
box-sizing: content-box;
width: var(--size);
height: var(--size);
opacity: 40%;
background: var(--color);
left: 3px;
top: 3px;
border: 2px solid var(--border);
border-top-color: white;
}
.I {
--hue: 193;
--saturation: 100%;
}
.J {
--hue: 215;
--saturation: 100%;
}
.L {
--hue: 25;
--saturation: 100%;
}
.O {
--hue: 42;
--saturation: 100%;
}
.S {
--hue: 95;
--saturation: 100%;
}
.T {
--hue: 300;
--saturation: 56%;
}
.Z {
--hue: 357;
--saturation: 84%;
}
.ghost {
--hue: 0;
--saturation: 0%;
opacity: 30%;
}

View File

@@ -1,70 +0,0 @@
body {
background-image: url("new-wave/bg.png");
background-size: cover;
}
body[data-bs-theme="dark"] {
--bs-body-bg: #2125296b;
}
.btn-dark {
--bs-btn-bg: #2125296b;
}
.card {
background: #25292d66;
}
#matrixCard {
background-image: radial-gradient(#2226, #25292d66);
}
.minoes-table {
background: transparent;
}
.mino {
background: var(--color);
border: 3px solid var(--border);
box-shadow: 0 0 8px var(--border);
}
.I {
--color: #00eaf888;
--border: #00eaf5;
}
.J {
--color: #00a9f788;
--border: #00a9f7;
}
.L {
--color: #f9b60088;
--border: #f9b600;
}
.O {
--color: #e3e04988;
--border: #e3e049;
}
.S {
--color: #7bd59e88;
--border: #7bd59e;
}
.T {
--color: #d136e288;
--border: #d136e2;
}
.Z {
--color: #E67D8688;
--border: #E67D86;
}
.ghost {
--color: #fff4;
--border: #fff5;
}

171
css/old-school.css Normal file
View File

@@ -0,0 +1,171 @@
:root {
--cell-size: 20px;
--sprite-size: 40px;
}
@font-face {
font-family: 'Early GameBoy';
src: url('old-school/Early GameBoy.ttf');
}
#screenRow {
background-image: url('old-school/bg.png');
background-size: 10px;
padding: 40px 20px;
border: 3px inset black;
border-radius: 10px;
}
.col {
gap: 8px;
}
.card {
background: #8d8e04;
border-radius: 0;
border-image-source: url('old-school/border-sm.png');
border-image-slice: 25;
border-image-width: 13px;
border-image-repeat: repeat;
border-image-outset: 12px;
box-shadow: unset;
width: 100%;
}
.card-header {
background: #8d8e04;
}
#matrixCard {
background: #808302;
border-image-source: url('old-school/border-lg.png');
border-image-slice: 30;
border-image-width: 15px;
border-image-outset: 15px;
}
#statsTable,
.card,
.card-header,
#messagesSpan div {
font-family: 'Early GameBoy', monospace;
font-smooth: never;
-webkit-font-smoothing: none;
color: #254806;
text-shadow:
-1px -1px 3px rgba(0, 0, 0, 40%),
1px 1px 1px rgba(0, 0, 0, 40%);
}
#statsTable {
font-size: 0.7em;
letter-spacing: -0.1em;
}
#statsTable tr {
display: flex;
flex-flow: column;
}
#statsTable th,
#statsTable td {
border: 0;
padding: 0 0.2rem;
}
#statsTable td {
width: auto;
text-align: end;
}
#messagesSpan {
text-shadow:
-2px -2px #808302,
-2px 2px #808302,
2px -2px #808302,
2px 2px #808302;
}
.minoes-table td {
border: 0 !important;
}
.mino {
box-shadow:
-2px -2px 5px rgba(0, 0, 0, 40%),
1px 1px 2px rgba(0, 0, 0, 40%);
background-size: cover;
background-image: url('old-school/sprites.png');
background-position: calc(var(--sprite-pos) * var(--sprite-size)) 0px;
}
.I.mino {
--sprite-pos: 0;
}
.J.mino {
--sprite-pos: 1;
}
.L.mino {
--sprite-pos: 2;
}
.O.mino {
--sprite-pos: 3;
}
.S.mino {
--sprite-pos: 4;
}
.T.mino {
--sprite-pos: 5;
}
.Z.mino {
--sprite-pos: 6;
}
@keyframes blinker {
35% {
opacity: 50%;
}
}
.locking.mino {
filter: brightness(135%) contrast(70%);
}
.ghost.mino,
.disabled.mino {
opacity: 50%;
}
.locked.mino {
animation: none;
}
.hard-dropped-table-animation {
animation: hard-dropped-table-animation steps(1) 0.2s;
}
@keyframes cleared-line-animation {
10%,
30%,
50%,
70%,
90% {
opacity: 0;
}
20%,
40%,
60%,
80% {
opacity: 100%;
}
}
tr.cleared-line-animation {
animation: cleared-line-animation ease-out 0.4s;
}

View File

Before

Width:  |  Height:  |  Size: 870 B

After

Width:  |  Height:  |  Size: 870 B

View File

Before

Width:  |  Height:  |  Size: 14 KiB

After

Width:  |  Height:  |  Size: 14 KiB

View File

Before

Width:  |  Height:  |  Size: 10 KiB

After

Width:  |  Height:  |  Size: 10 KiB

View File

Before

Width:  |  Height:  |  Size: 298 KiB

After

Width:  |  Height:  |  Size: 298 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 117 KiB

BIN
css/old-school/sprites.png Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 21 KiB

View File

@@ -1,5 +1,5 @@
body {
--bs-gutter-x: 0;
--bs-gutter-x: 0;
background: black !important;
}
@@ -7,11 +7,11 @@ body {
gap: 0 !important;
margin: 0;
text-transform: uppercase;
letter-spacing: .1em;
letter-spacing: 0.1em;
}
#screenRow {
--bs-gutter-x: 0;
--bs-gutter-x: 0;
}
.card {
@@ -22,7 +22,7 @@ body {
}
.card-header,
.card-header th{
.card-header th {
background: transparent;
font-weight: 400 !important;
font-size: 1.3em;
@@ -30,7 +30,7 @@ body {
}
#screenRow .table {
--bs-border-width: 0;
--bs-border-width: 0;
}
#holdTable {
@@ -75,6 +75,10 @@ body {
color: white;
}
td#timeCell {
text-align: center;
}
#matrixCard {
background: transparent;
border-top: none;
@@ -91,38 +95,38 @@ body {
}
.I.mino {
background-color: #42AFE1;
border-color: #6CEAFF;
background-color: #42afe1;
border-color: #6ceaff;
}
.J.mino {
background-color: #1165B5;
border-color: #339BFF;
background-color: #1165b5;
border-color: #339bff;
}
.L.mino {
background-color: #F38927;
border-color: #FFBA59;
background-color: #f38927;
border-color: #ffba59;
}
.O.mino {
background-color: #F6D03C;
border-color: #FFFF7F;
background-color: #f6d03c;
border-color: #ffff7f;
}
.S.mino {
background-color: #32ee3e;
border-color: #84F880;
border-color: #84f880;
}
.T.mino {
background-color: #9739A2;
border-color: #D958E9;
background-color: #9739a2;
border-color: #d958e9;
}
.Z.mino {
background-color: #EB4F65;
border-color: #FF7F79;
background-color: #eb4f65;
border-color: #ff7f79;
}
.ghost.mino {
@@ -142,14 +146,3 @@ body {
filter: brightness(50%) contrast(80%);
opacity: 70%;
}
@keyframes locked-animation {
from {
filter: saturate(50%) brightness(400%);
}
}
.locked.mino {
animation: locked-animation;
animation-duration: 0.2s;
}

View File

@@ -1,156 +0,0 @@
:root {
--cell-side: 20px;
}
@font-face {
font-family: "Early GameBoy";
src: url("retro/Early GameBoy.ttf");
}
body {
}
#screenRow {
background-image: url("retro/bg.png");
background-size: 10px;
padding: 40px 20px;
border: 3px inset black;
border-radius: 10px;
}
.col {
gap: 8px;
}
.card {
background: #8D8E04;
border-radius: 0;
border-image-source: url("retro/border-sm.png");
border-image-slice: 25;
border-image-width: 13px;
border-image-repeat: repeat;
border-image-outset: 12px;
box-shadow: unset;
width: 100%;
}
.card-header {
background: #8D8E04;
}
#matrixCard {
background: #808302;
border-image-source: url("retro/border-lg.png");
border-image-slice: 30;
border-image-width: 15px;
border-image-outset: 15px;
}
#statsTable,
.card,
.card-header,
#messagesSpan {
font-family: "Early GameBoy", monospace;
font-smooth: never;
-webkit-font-smoothing: none;
color: #254806;
text-shadow: -1px -1px 3px rgba(0, 0, 0, 40%), 1px 1px 1px rgba(0, 0, 0, 40%);
}
#statsTable {
font-size: .7em;
letter-spacing: -.1em;
}
#statsTable tr {
display: flex;
flex-flow: column;
}
#statsTable th,
#statsTable td {
border: 0;
padding: 0 .2rem;
}
#statsTable td {
width: auto;
text-align: end;
}
#messagesSpan {
text-shadow: -2px -2px #808302, -2px 2px #808302, 2px -2px #808302, 2px 2px #808302;
}
td {
border: 0 !important;
}
.mino {
box-shadow: -2px -2px 5px rgba(0, 0, 0, 40%), 1px 1px 2px rgba(0, 0, 0, 40%);
background-size: 100%;
}
.I.mino {
background-image: url("retro/I-mino.png")
}
.J.mino {
background-image: url("retro/J-mino.png")
}
.L.mino {
background-image: url("retro/L-mino.png")
}
.O.mino {
background-image: url("retro/O-mino.png")
}
.S.mino {
background-image: url("retro/S-mino.png")
}
.T.mino {
background-image: url("retro/T-mino.png")
}
.Z.mino {
background-image: url("retro/Z-mino.png")
}
@keyframes blinker {
50% {
opacity: 0;
}
}
.locking.mino {
animation: blinker 0.08s step-start infinite;
}
.ghost.mino,
.disabled.mino {
opacity: 50%;
}
.locked.mino {
animation: none;
}
.hard-dropped-table-animation {
animation: hard-dropped-table-animation steps(1) .2s;
}
@keyframes cleared-line-animation {
10%, 30%, 50%, 70%, 90% {
opacity: 0;
}
20%, 40%, 60%, 80% {
opacity: 100%;
}
}
tr.cleared-line-animation {
animation: cleared-line-animation ease-out .4s;
}

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.1 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 3.0 KiB

Binary file not shown.

Before

Width:  |  Height:  |  Size: 2.9 KiB

443
css/stereo.css Normal file
View File

@@ -0,0 +1,443 @@
:root {
--rbw: 4px;
--tl: calc(-1 * var(--rbw));
--cell-size-opposite: calc(-1 * var(--cell-size));
--t3d: translate3d(var(--tl), var(--tl), var(--cell-size-opposite));
}
body {
background-image:
url(stereo/bg.jpg),
radial-gradient(
circle at center,
#39444f 0%,
#2c323b 25%,
#293036 28%,
#252b32 34%,
#242930 38%,
#1a1d22 52%,
#191c22 53%,
#151519 63%,
#141418 65%,
#0f0f12 74%,
#0a0c0d 100%
);
background-repeat: space;
background-position: center;
background-size: cover;
}
#sceneDiv {
perspective: 500px;
cursor: grab;
}
#sceneDiv:active {
cursor: grabbing;
}
#screenRow {
--light-rX: calc(-1 * var(--rY) / 30);
--light-rY: calc(var(--rX) / 20);
display: block;
transform: translateZ(var(--tZ)) rotateX(calc((var(--rX)) * 1deg))
rotateY(calc((var(--rY)) * 1deg));
}
#sceneDiv,
#screenRow,
#screenRow .col,
#screenRow .card,
#screenRow .card-body,
.minoes-table,
.minoes-table tbody,
.minoes-table tr,
.minoes-table td {
display: block;
transform-style: preserve-3d;
}
#screenRow .col {
display: inline-block !important;
width: max-content;
height: 100%;
vertical-align: top;
}
.card {
background: #36394180;
}
#matrixCard {
background-image: none;
transform-origin: bottom;
}
#screenRow .card > * {
transform: translateZ(var(--cell-size));
}
#screenRow .card-header {
background-color: transparent;
border: none;
}
.card,
.card-header {
text-shadow: calc(-0.3px * var(--rY)) calc(0.4px * var(--rX)) 5px #0008;
}
#holdTable .mino {
--row: 7;
--column: -5;
}
#nextTable .mino {
--row: 15;
--column: 15;
}
.minoes-table th,
.minoes-table td {
display: inline-block !important;
width: max-content;
}
.minoes-table tr {
width: max-content;
height: var(--cell-size);
}
#statsTable tr {
display: table;
width: 100%;
}
#statsTable th,
#statsTable td {
display: table-cell;
border: 0;
}
tr.matrix td:not(.mino) {
border: 0;
}
.minoes-table td {
width: var(--cell-size);
height: var(--cell-size);
overflow: visible;
position: relative;
}
.mino,
.mino::before,
.mino + :not(.mino)::before,
.mino::after {
--light-pX: calc(0.5 - var(--column) / 10);
--light-pY: calc(3.5 - var(--row) / 6);
--light-x: calc(var(--light-rX) + var(--light-pX));
--light-y: calc(var(--light-rY) + var(--light-pY));
--center-color: hsla(var(--h), var(--s), calc(var(--l) * var(--light) * 1.1), var(--a));
--edge-color: hsla(var(--h), var(--s), calc(var(--l) * (var(--light) * 0.9)), var(--a));
background: var(--center-color);
border-radius: 4px;
border: 2px outset var(--center-color);
}
.mino::before,
.mino + :not(.mino)::before,
.mino::after,
td.trail-animation::before,
td.trail-animation::after,
tr.cleared-line-animation td::before,
tr.cleared-line-animation td::after {
content: '';
position: absolute;
top: 0;
left: 0;
display: block;
width: var(--cell-size);
height: var(--cell-size);
}
/* Front face */
.mino,
td.trail-animation {
--light: calc(1 + (var(--light-y) * 0.3) + (var(--light-x) * 0.2));
--center-x: calc(35% + var(--light-x) * 10%);
--center-y: calc(35% + var(--light-y) * 10%);
background: radial-gradient(
circle at var(--center-x) var(--center-y),
var(--center-color) 15%,
var(--edge-color) 100%
);
box-shadow: 0 0 6px hsla(var(--h), var(--s), calc(var(--l) * var(--light) * 1.3), 40%);
border-style: ridge;
border-width: var(--rbw);
}
/* Left face */
.mino::before,
td.trail-animation::before,
tr.cleared-line-animation td::before,
.mino + .mino::before {
--light: calc(1.1 + (var(--light-x) * -0.2) + (var(--light-y) * 0.15));
transform: var(--t3d) rotateY(-90deg);
transform-origin: left;
}
/* Right face */
.mino + :not(.mino)::before,
.right .mino + .mino::before,
.right td.trail-animation::before,
.right tr.cleared-line-animation td::before {
--light: calc(0.85 + (var(--light-x) * -0.2) + (var(--light-y) * -0.15));
--center-x: calc(65% + var(--light-x) * 10%);
--center-y: calc(35% + var(--light-y) * 10%);
filter: saturate(0.95);
transform: translate3d(0, 0, var(--cell-size-opposite)) rotateY(-90deg);
transform-origin: left;
}
.right .mino:last-child::before {
transform: var(--t3d) rotateY(90deg) !important;
transform-origin: right !important;
}
/* Top face */
.mino::after,
td.trail-animation::after,
tr.cleared-line-animation td::after {
--light: calc(1.5 + (var(--light-y) * 0.2));
transform: var(--t3d) rotateX(90deg);
transform-origin: top;
}
/* Bottom face */
.bottom .mino::after,
.bottom td.trail-animation::after,
.bottom tr.cleared-line-animation td::after {
--light: calc(1.1 + (var(--light-y) * -0.3));
--center-x: calc(65% + var(--light-x) * 10%);
--center-y: calc(65% + var(--light-y) * 10%);
filter: saturate(0.95);
transform: var(--t3d) rotateX(-90deg);
transform-origin: bottom;
}
.J,
.J + :not(.mino) {
--h: 210deg;
--s: 78%;
--l: 52%;
--a: 0.75;
}
.L,
.L + :not(.mino) {
--h: 28deg;
--s: 85%;
--l: 52%;
--a: 0.75;
}
.O,
.O + :not(.mino) {
--h: 48deg;
--s: 88%;
--l: 52%;
--a: 0.75;
}
.I,
.I + :not(.mino) {
--h: 200deg;
--s: 70%;
--l: 52%;
--a: 0.75;
}
.S,
.S + :not(.mino) {
--h: 118deg;
--s: 45%;
--l: 52%;
--a: 0.75;
}
.T,
.T + :not(.mino) {
--h: 293deg;
--s: 48%;
--l: 52%;
--a: 0.75;
}
.Z,
.Z + :not(.mino) {
--h: 352deg;
--s: 75%;
--l: 52%;
--a: 0.75;
}
.ghost.mino,
.ghost.mino + :not(.mino) {
--h: 0deg;
--s: 0%;
--l: 55%;
--a: 0.4;
}
.locking.mino,
.locking.mino + :not(.mino) {
--h: 0deg;
--s: 0%;
--l: 92%;
--a: 0.72;
}
.disabled.mino,
.disabled.mino + :not(.mino) {
--h: 0deg;
--s: 0%;
--l: 45%;
--a: 0.72;
}
#holdTable .J + :not(.mino),
#holdTable .L + :not(.mino),
#holdTable .S + :not(.mino),
#holdTable .T + :not(.mino),
#holdTable .Z + :not(.mino),
#nextTable .J + :not(.mino),
#nextTable .L + :not(.mino),
#nextTable .S + :not(.mino),
#nextTable .T + :not(.mino),
#nextTable .Z + :not(.mino) {
transform: translateX(50%);
}
@keyframes trail-animation {
from {
background-color: hsla(180, 100%, 100%, 0.1);
border-color: hsla(180, 100%, 100%, 0.1);
}
to {
background-color: transparent;
border-color: transparent;
}
}
td.trail-animation::before,
td.trail-animation::after {
animation: trail-animation ease-out 0.3s;
}
@keyframes hard-dropped-table-animation {
50% {
transform: translateY(10px) rotateX(-3deg);
}
}
@keyframes locked-animation {
from {
--h: 0deg;
--s: 0%;
--l: 100%;
--a: 1;
box-shadow: 0 0 10px hsla(180, 100%, 100%, 0.2);
}
}
.locked.mino::before,
.locked.mino::after {
animation: locked-animation;
animation-duration: 0.2s;
}
@keyframes cleared-line-animation {
from {
background-color: white !important;
box-shadow: 0 0 0 white;
}
to {
background-color: #fff0;
box-shadow: 0 0 100px transparent;
}
}
tr.cleared-line-animation td::before,
tr.cleared-line-animation td::after {
animation: cleared-line-animation ease-out 0.3s;
}
@keyframes show-level-animation {
from {
opacity: 1;
transform: translateY(200%);
}
50% {
transform: translateY(0) scaleY(1);
line-height: var(--bs-body-line-height);
}
to {
opacity: 1;
transform: translateY(-100%) scaleY(0);
line-height: 0;
}
}
@keyframes zoom-in-animation {
from {
opacity: 1;
transform: scale3d(0.3, 0.3, 0.3);
line-height: var(--bs-body-line-height);
}
30% {
transform: scale3d(1, 1, 1);
}
80% {
transform: scale3d(1, 1, 1);
line-height: var(--bs-body-line-height);
}
to {
opacity: 1;
transform: scale3d(1.5, 0, 1);
line-height: 0;
}
}
@keyframes rotate-in-animation {
0% {
opacity: 1;
transform: rotate(200deg);
line-height: var(--bs-body-line-height);
}
30% {
transform: translateZ(0) scale3d(1, 1, 1);
}
80% {
transform: scale3d(1, 1, 1);
line-height: var(--bs-body-line-height);
}
to {
opacity: 1;
transform: scale3d(1.5, 0, 1);
line-height: 0;
}
}
@keyframes game-over-animation {
from {
opacity: 1;
transform: translateY(200%);
}
to {
opacity: 1;
transform: translateY(0) scaleY(1);
line-height: var(--bs-body-line-height);
}
}

View File

Before

Width:  |  Height:  |  Size: 62 KiB

After

Width:  |  Height:  |  Size: 62 KiB

43
css/svg.css Normal file
View File

@@ -0,0 +1,43 @@
tr.matrix td:not(.mino),
tr.matrix td.mino {
border-left: none;
border-right: 1px solid #333;
border-top: 1px solid #333;
border-bottom: none;
}
.mino {
background-size: cover
}
.I {
background-image: url(https://www.svgrepo.com/show/395902/blue-square.svg)
}
.J {
background-image: url(https://www.svgrepo.com/show/395944/brown-square.svg);
}
.L {
background-image: url(https://www.svgrepo.com/show/397681/orange-square.svg);
}
.O {
background-image: url(https://www.svgrepo.com/show/398716/yellow-square.svg);
}
.S {
background-image: url(https://www.svgrepo.com/show/396582/green-square.svg);
}
.T {
background-image: url(https://www.svgrepo.com/show/398143/purple-square.svg);
}
.Z {
background-image: url(https://www.svgrepo.com/show/397699/red-square.svg);
}
.ghost {
background-image: url(https://www.svgrepo.com/show/398610/white-large-square.svg);
}

View File

@@ -1,123 +1,89 @@
body {
background-image: url("new-wave/bg.png");
background-image: url(synthwave/wtCSusF.jpeg);
background-size: cover;
}
body[data-bs-theme="dark"] {
--bs-body-bg: #2125296b;
body[data-bs-theme='dark'] {
--bs-body-bg: #2125296b;
}
.btn-dark {
--bs-btn-bg: #2125296b;
--bs-btn-bg: #2125296b;
}
.card {
background: #25292d66;
}
#matrixCard {
background-image: radial-gradient(#2226, #25292d66);
}
.card,
#matrixCard {
background: repeating-linear-gradient(transparent, #111 1px);
background: repeating-linear-gradient(transparent, transparent 2px, #1114 2px, #1114 5px);
backdrop-filter: blur(3px);
}
.card-header {
background-color: rgba(37, 41, 45, 50%);
.minoes-table {
background: transparent;
border-spacing: 2px;
}
#matrixTable {
border-spacing: 1px;
margin-top: calc(-1 * var(--buffer-zone-rows) * var(--cell-size) - 8px);
}
tr.matrix td:not(.mino) {
border: 1px solid #111;
#matrixTable td:not(.mino) {
border-color: #8881;
border-top: none;
border-bottom: none;
}
.mino {
background: radial-gradient(#fff3 0%, var(--color) 170%);
border: 2px solid var(--color);
border-radius: 0;
outline: 1px solid #0006;
opacity: 100%;
box-shadow: 0 0 12px var(--color);
background: var(--color);
border: 3px solid var(--border);
border-radius: 6px;
box-shadow: 0 0 8px var(--border);
filter: blur(0.5px);
}
.I.mino {
--color: #00eaf5;
.I {
--color: #00eaf866;
--border: #00eaf5;
}
.J.mino {
--color: #00a9f7;
.J {
--color: #00a9f766;
--border: #00a9f7;
}
.L.mino {
--color: #f9b600;
.L {
--color: #f9b60066;
--border: #f9b600;
}
.O.mino {
--color: #f7f200;;
.O {
--color: #e3e04966;
--border: #e3e049;
}
.T.mino {
--color: #d136e2;;
.S {
--color: #7bd59e66;
--border: #7bd59e;
}
.S.mino {
--color: #35da3f;
.T {
--color: #d136e266;
--border: #d136e2;
}
.Z.mino {
--color: #ee3b3a;
.Z {
--color: #e67d8666;
--border: #e67d86;
}
.ghost.mino {
background: transparent;
opacity: 50%;
.ghost {
--color: #fff4;
--border: #fff5;
}
.moving.mino {
filter: brightness(120%);
}
.locking.mino {
--color: white;
box-shadow: 0 0 10px var(--color);
}
@keyframes locked-animation {
from {
background: white;
--color: white;
}
}
.locked.mino {
animation: locked-animation;
animation-duration: 0.2s;
}
.disabled.mino {
outline: 0px;
box-shadow: none;
filter: contrast(40%) brightness(50%);
}
tr.cleared-line-animation {
animation: none;
}
tr.cleared-line-animation::after {
content: "";
width: 100%;
height: var(--cell-side);
position: fixed;
left: 50%;
transform: translateX(-50%);
display: block;
background: repeating-linear-gradient(transparent, #fffb 1px);
opacity: 0;
animation: cleared-line-animation ease-out .3s;
}
@keyframes cleared-line-animation {
25% {
width: 200%;
opacity: 100%;
}
}

View File

Before

Width:  |  Height:  |  Size: 444 KiB

After

Width:  |  Height:  |  Size: 444 KiB

BIN
css/synthwave/wtCSusF.jpeg Normal file

Binary file not shown.

After

Width:  |  Height:  |  Size: 972 KiB

68
css/tetrio-skin.css Normal file
View File

@@ -0,0 +1,68 @@
:root {
--cell-size: 30px;
--sprite-size: round(100% / 11, 1px);
--skin-url: url(tetrio-skin/a_forest.png);
}
tr.matrix td:not(.mino) {
border-left: none;
border-bottom: none;
}
.mino {
background-image: var(--skin-url);
background-size: cover;
background-repeat: no-repeat;
background-position-x: calc(var(--sprite-pos) * var(--sprite-size));
}
.I {
--sprite-pos: 4;
}
.J {
--sprite-pos: 5;
}
.L {
--sprite-pos: 1;
}
.O {
--sprite-pos: 2;
}
.S {
--sprite-pos: 3;
}
.T {
--sprite-pos: 6;
}
.Z {
--sprite-pos: 0;
}
.ghost {
--sprite-pos: 7;
opacity: 40%;
}
.disabled {
--sprite-pos: 8;
}
.locking.mino {
filter: saturate(60%) brightness(180%);
}
#holdTable .mino,
#nextTable .mino {
box-shadow: 4px 4px 10px #0002;
}
.preview {
--cell-size: 24px;
height: var(--cell-size);
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 95 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 83 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

View File

@@ -1,5 +1,5 @@
<!doctype html>
<html lang="fr">
<html lang="fr" data-bs-theme="dark">
<head>
<meta charset="utf-8" />
@@ -8,16 +8,24 @@
<meta name="color-scheme" content="dark">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/css/bootstrap.min.css" integrity="sha384-KK94CHFLLe+nY2dmCWGMq91rCGa5gtU4mk92HdvYe+M/SXH301p5ILy+dN9+nJOZ" crossorigin="anonymous">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.4/font/bootstrap-icons.css">
<link rel="stylesheet" href="css/common.css">
<link rel="stylesheet" href="css/classic.css" title="Thème sélectionné" id="selectedStyleSheet">
<link rel="alternate stylesheet" href="css/classic.css" title="Classique">
<link rel="alternate stylesheet" href="css/minimal.css" title="Minimal">
<link rel="alternate stylesheet" href="css/electro.css" title="Électro">
<link rel="alternate stylesheet" href="css/new-wave.css" title="New Wave">
<link rel="alternate stylesheet" href="css/synthwave.css" title="Synthwave">
<link rel="alternate stylesheet" href="css/retro.css" title="Rétro">
<link rel="alternate stylesheet" href="css/opera.css" title="Opéra">
<link rel="alternate stylesheet" href="css/binaural.css" title="Binaural">
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/select2@4.1.0-rc.0/dist/css/select2.min.css"/>
<link rel="stylesheet" href="https://cdn.jsdelivr.net/npm/select2-bootstrap-5-theme@1.3.0/dist/select2-bootstrap-5-theme.min.css" />
<link rel="stylesheet" href="css/_select2-dark.css">
<link rel="stylesheet" href="css/_common.css">
<link rel="stylesheet" href="css/tetrio-skin.css" title="Thème sélectionné" id="selectedStyleSheet">
<link rel="alternate stylesheet" href="css/tetrio-skin.css" title="Sample Tetr.io...">
<link rel="alternate stylesheet" href="css/jstris-skin.css" title="Sample JStris...">
<link rel="alternate stylesheet" href="css/classic.css" title="Classique">
<link rel="alternate stylesheet" href="css/neo-classic.css" title="Néo-classique">
<link rel="alternate stylesheet" href="css/electro.css" title="Électro">
<link rel="alternate stylesheet" href="css/synthwave.css" title="Synthwave">
<link rel="alternate stylesheet" href="css/heavy-metal.css" title="Heavy metal">
<link rel="alternate stylesheet" href="css/jazz.css" title="Jazz">
<link rel="alternate stylesheet" href="css/old-school.css" title="Old School">
<link rel="alternate stylesheet" href="css/stereo.css" title="3D">
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ENjdO4Dr2bkBIFxQpeoTz1HIcje39Wm4jDKdf19U8gI4ddQ3GYNS7NTKfAdVQSZe" crossorigin="anonymous"></script>
<script src="https://code.jquery.com/jquery-3.6.0.min.js"></script>
<script src="https://cdnjs.cloudflare.com/ajax/libs/select2/4.1.0-rc.0/js/select2.min.js"></script>
<link rel="apple-touch-icon" sizes="180x180" href="favicons/apple-touch-icon.png">
<link rel="icon" type="image/png" sizes="32x32" href="favicons/T-2.png">
<link rel="icon" type="image/png" sizes="16x16" href="favicons/favicon-16x16.png">
@@ -28,12 +36,12 @@
<meta property="og:image" content="https://adrien.malingrey.fr/jeux/quatuor/thumbnail.png"/>
<meta property="og:image:width" content="288"/>
<meta property="og:image:height" content="288"/>
<meta property="og:description" content="Un jeu avec un quatuor de blocs qui tombent."/>
<meta property="og:description" content="Un jeu de quatuors de blocs qui tombent."/>
<meta property="og:locale" content="fr_FR"/>
<meta property="og:site_name" content="adrien.malingrey.fr"/>
</head>
<body data-bs-theme="dark">
<body>
<div class="modal fade" id="settingsModal" data-bs-backdrop="static" data-bs-keyboard="false">
<div class="modal-dialog modal-dialog-centered">
@@ -61,7 +69,8 @@
<div class="col-4"><input name="pause" id="pauseInput" type="text" class="form-control text-center" value="Échap." onfocus="changeKey(this)" placeholder="Touche ?" title="Modifier la touche" required></div>
<label for="pauseInput" title="Pause" class="col-2 col-form-label d-flex align-items-center justify-content-center"><i class="bi bi-pause"></i></label>
</fieldset>
<fieldset id="autorepeatFieldset" class="row g-2 mb-3 align-items-center text-center"><legend class="text-start">Répétition automatique</legend>
<fieldset id="autorepeatFieldset" class="row g-2 mb-3 align-items-center text-center">
<!--<legend class="text-start">Répétition automatique</legend>-->
<label for="arrInput" class="col-2 col-form-label"><abbr title="Automatic Repeat Rate : période de répétition de l'action">ARR</abbr></label>
<div class="col-4"><div class="input-group"><input name="arr" id="arrInput" type="number" class="form-control text-center" value="50" min="2" max="200" step="1"><div class="input-group-text">ms</div></div></div>
<div class="col-4"><div class="input-group"><input name="das" id="dasInput" type="number" class="form-control text-center" value="300" min="100" max="500" step="5"><div class="input-group-text">ms</div></div></div>
@@ -69,18 +78,37 @@
</fieldset>
<fieldset class="row g-2 mb-3 align-items-center text-center"><legend class="text-start">Interface</legend>
<label for="stylesheetSelect" class="col-2 col-form-label">Thème</label>
<div class="col-4"><select name="stylesheet" id="stylesheetSelect" class="form-select" oninput="selectedStyleSheet.href = this.value">
<option value="css/classic.css" selected>Classique</option>
<option value="css/minimal.css">Minimal</option>
<option value="css/new-wave.css">New Wave</option>
<option value="css/synthwave.css">Synthwave</option>
<option value="css/electro.css">Électro</option>
<option value="css/retro.css">Rétro</option>
<option value="css/opera.css">Opéra</option>
<option value="css/binaural.css">Binaural</option>
</select></div>
<div class="col-4 d-flex align-items-baseline"><input name="sfxVolumeRange" id="sfxVolumeRange" class="form-range" type="range" min="0" max="1" step="any" value="0.7"></div>
<label for="sfxVolumeRange" class="col-2 col-form-label">Volume</label>
<div class="col-4">
<select name="stylesheet" id="stylesheetSelect" class="form-select">
<option value="css/tetrio-skin.css" selected>Sample Tetr.io...</option>
<option value="css/jstris-skin.css">Sample JStris...</option>
<option value="css/classic.css">Classique</option>
<option value="css/neo-classic.css">Néo-classique</option>
<option value="css/synthwave.css">Synthwave</option>
<option value="css/electro.css">Électro</option>
<option value="css/heavy-metal.css">Heavy metal</option>
<option value="css/jazz.css">Jazz</option>
<option value="css/old-school.css">Old School</option>
<option value="css/stereo.css">3D</option>
</select>
</div>
<div class="col-4">
<select name="skinURL" id="skinURLSelect" class="form-select"
oninput="document.documentElement.style.setProperty('--skin-url', `url(${this.value})`)">
</select>
</div>
<label for="skinURLSelect" class="col-2 col-form-label">Sample</label>
<label for="sfxVolumeRange" class="col-2 col-form-label"><abbr title="Auteur des effets sonores : 25Pi25">Volume</abbr></label>
<div class="col-4 d-flex align-items-baseline">
<input name="sfxVolumeRange" id="sfxVolumeRange" class="form-range" type="range" min="0" max="1" step="any" value="0.7">
</div>
<div class="col-4">
<div class="form-check form-switch text-start">
<input id="fullscreenCheckbox" type="checkbox" role="switch" class="form-check-input" tabindex="0">
<label for="fullscreenCheckbox" class="form-check-label">Plein écran</label>
</div>
</div>
<div class="col-2"></div>
</fieldset>
<fieldset class="row g-2 mb-3 align-items-center text-center"><legend class="text-start">Partie</legend>
<label for="levelInput" class="col-2 col-form-label text-center">Niveau</label>
@@ -117,9 +145,9 @@
<table id="statsTable" class="table mb-0">
<tr class="card-header fw-bold text-uppercase"><th>Score</th><td id="scoreCell">0</td> </tr>
<tr><th>Meilleur<br/>score</th><td id="highScoreCell"><script>document.write(Number(localStorage["highScore"]) || 0)</script></td></tr>
<tr><th>Niveau</th> <td id="levelCell">0</td> </tr>
<tr><th>But</th> <td id="goalCell">0</td> </tr>
<tr><th>Temps</th> <td id="timeCell">00:00</td> </tr>
<tr><th>Niveau</th><td id="levelCell">0</td> </tr>
<tr><th>But</th> <td id="goalCell">0</td> </tr>
<tr><th>Temps</th> <td id="timeCell">00:00:00</td></tr>
</table>
</div>
</div>
@@ -188,21 +216,21 @@
</div>
<div class="modal fade" id="statsModal" tabindex="-1">
<div class="modal fade" id="statsModal" data-bs-backdrop="static" data-bs-keyboard="false" tabindex="-1">
<div class="modal-dialog modal-dialog-centered">
<div class="modal-dialog">
<div class="modal-content">
<div class="modal-header">
<h2 class="modal-title w-100 text-center">Fin</h2>
<button type="button" class="btn-close" data-bs-dismiss="modal"></button>
<!-- <button type="button" class="btn-close" data-bs-dismiss="modal"></button> -->
</div>
<div class="modal-body p-0">
<table class="table mb-0">
<tr><th>Score</th> <td id="statsModalScoreCell"></td> <th>Niveau</th> <td id="statsModalLevelCell"></td> </tr>
<tr><th>Meilleur score</th><td id="statsModalHighScoreCell"></td> <th>Temps</th> <td id="statsModalTimeCell"></td> </tr>
<tr><th>Lignes</th> <td id="statsModaltotalClearedLines"></td><th>Lignes par minute</th> <td id="statsModaltotalClearedLinesPM"></td></tr>
<tr><th>Quatuors</th> <td id="statsModalNbQuatuors"></td> <th>Plus long combo</th> <td id="statsModalMaxCombo"></td> </tr>
<tr><th>Pirouettes</th> <td id="statsModalNbTSpin"></td> <th>Plus long bout en bout</th><td id="statsModalMaxB2B"></td> </tr>
<tr><th>Score</th> <td id="statsModalScoreCell"></td> <th>Quatuors</th> <td id="statsModalNbQuatuors"></td> </tr>
<tr><th>Meilleur score</th><td id="statsModalHighScoreCell"></td> <th>Pirouettes</th> <td id="statsModalNbTSpin"></td> </tr>
<tr><th>Temps</th> <td id="statsModalTimeCell"></td> <th>Plus long combo</th> <td id="statsModalMaxCombo"></td> </tr>
<tr><th>Niveau</th> <td id="statsModalLevelCell"></td> <th>Plus long bout à bout</th><td id="statsModalMaxB2B"></td> </tr>
<tr><th>Lignes</th> <td id="statsModaltotalClearedLines"></td><th>Lignes par minute</th> <td id="statsModaltotalClearedLinesPM"></td></tr>
</table>
</div>
<div class="modal-footer">
@@ -222,14 +250,59 @@
<img src="favicons/T-0.png"/><img src="favicons/T-1.png"/><img src="favicons/T-2.png"/><img src="favicons/T-3.png"/>
<img src="favicons/Z-0.png"/><img src="favicons/Z-1.png"/><img src="favicons/Z-2.png"/><img src="favicons/Z-3.png"/>
<audio id="wallSound" src="sounds/808K_A.wav" preload="auto" type="audio/wav"></audio>
<audio id="hardDropSound" src="sounds/909S.wav" preload="auto" type="audio/wav"></audio>
<audio id="lineClearSound" src="sounds/808COW.wav" preload="auto" type="audio/wav"></audio>
<audio id="tSpinSound" src="sounds/78GUIR.wav" preload="auto" type="audio/wav"></audio>
<audio id="quatuorSound" src="sounds/BRRDC1.wav" preload="auto" type="audio/wav"></audio>
<audio id="btb_1" src="snd/btb_1.ogg" preload="auto" type="audio/ogg"></audio>
<audio id="btb_2" src="snd/btb_2.ogg" preload="auto" type="audio/ogg"></audio>
<audio id="btb_3" src="snd/btb_3.ogg" preload="auto" type="audio/ogg"></audio>
<audio id="btb_break" src="snd/btb_break.ogg" preload="auto" type="audio/ogg"></audio>
<audio id="clearbtb" src="snd/clearbtb.ogg" preload="auto" type="audio/ogg"></audio>
<audio id="clearline" src="snd/clearline.ogg" preload="auto" type="audio/ogg"></audio>
<audio id="clearquad" src="snd/clearquad.ogg" preload="auto" type="audio/ogg"></audio>
<audio id="clearspin" src="snd/clearspin.ogg" preload="auto" type="audio/ogg"></audio>
<audio id="combo_1_power" src="snd/combo_1_power.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="combo_1" src="snd/combo_1.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="combo_10_power" src="snd/combo_10_power.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="combo_10" src="snd/combo_10.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="combo_11_power" src="snd/combo_11_power.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="combo_11" src="snd/combo_11.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="combo_12_power" src="snd/combo_12_power.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="combo_12" src="snd/combo_12.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="combo_13_power" src="snd/combo_13_power.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="combo_13" src="snd/combo_13.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="combo_14_power" src="snd/combo_14_power.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="combo_14" src="snd/combo_14.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="combo_15_power" src="snd/combo_15_power.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="combo_15" src="snd/combo_15.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="combo_16_power" src="snd/combo_16_power.ogg" preload="auto" type="audio/ogg"></audio>
<audio id="combo_16" src="snd/combo_16.ogg" preload="auto" type="audio/ogg"></audio>
<audio id="combo_2_power" src="snd/combo_2_power.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="combo_2" src="snd/combo_2.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="combo_3_power" src="snd/combo_3_power.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="combo_3" src="snd/combo_3.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="combo_4_power" src="snd/combo_4_power.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="combo_4" src="snd/combo_4.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="combo_5_power" src="snd/combo_5_power.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="combo_5" src="snd/combo_5.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="combo_6_power" src="snd/combo_6_power.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="combo_6" src="snd/combo_6.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="combo_7_power" src="snd/combo_7_power.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="combo_7" src="snd/combo_7.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="combo_8_power" src="snd/combo_8_power.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="combo_8" src="snd/combo_8.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="combo_9_power" src="snd/combo_9_power.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="combo_9" src="snd/combo_9.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="combobreak" src="snd/combobreak.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="floor" src="snd/floor.ogg" preload="auto" type="audio/ogg"></audio>
<audio id="gameover" src="snd/topout.ogg" preload="auto" type="audio/ogg"></audio>
<audio id="harddrop" src="snd/harddrop.ogg" preload="auto" type="audio/ogg"></audio>
<audio id="hit" src="snd/hit.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="hold" src="snd/hold.ogg" preload="auto" type="audio/ogg"></audio>
<audio id="menuconfirm" src="snd/menuconfirm.mp3" preload="auto" type="audio/mp3"></audio>
<audio id="menuhover" src="snd/menuhover.ogg" preload="auto" type="audio/ogg"></audio>
<audio id="move" src="snd/move.ogg" preload="auto" type="audio/ogg"></audio>
<audio id="rotate" src="snd/rotate.ogg" preload="auto" type="audio/ogg"></audio>
<audio id="spin" src="snd/spin.ogg" preload="auto" type="audio/ogg"></audio>
</span>
<script src="https://cdn.jsdelivr.net/npm/bootstrap@5.3.0-alpha3/dist/js/bootstrap.bundle.min.js" integrity="sha384-ENjdO4Dr2bkBIFxQpeoTz1HIcje39Wm4jDKdf19U8gI4ddQ3GYNS7NTKfAdVQSZe" crossorigin="anonymous"></script>
<script src="js/game_logic.js" language="Javascript" type="text/javascript"></script>
<script src="js/interface.js" language="Javascript" type="text/javascript"></script>
<script src="js/app.js" language="Javascript" type="text/javascript"></script>

493
js/app.js
View File

@@ -1,188 +1,189 @@
let scheduler = new Scheduler()
let settings = new Settings()
let stats = new Stats()
let holdQueue = new HoldQueue()
let matrix = new Matrix()
let nextQueue = new NextQueue()
let playing = false
//let lastActionSucceded = true
let favicon
window.onload = function(event) {
document.selectedStyleSheetSet = selectedStyleSheet.title
selectedStyleSheet.href = stylesheetSelect.value
favicon = document.querySelector("link[rel~='icon']")
restart()
}
document.onfullscreenchange = function () {
if (document.fullscreenElement) {
fullscreenCheckbox.checked = true;
} else {
fullscreenCheckbox.checked = false;
if (playing) pauseSettings();
}
};
document.onfullscreenerror = function () {
fullscreenCheckbox.checked = false;
};
function restart() {
stats.modal.hide()
holdQueue.init()
holdQueue.redraw()
stats.init()
matrix.init()
nextQueue.init()
settings.init()
pauseSettings()
stats.modal.hide();
holdQueue.init();
holdQueue.redraw();
stats.init();
matrix.init();
nextQueue.init();
settings.init();
pauseSettings();
}
function pauseSettings() {
scheduler.clearInterval(fall)
scheduler.clearTimeout(lockDown)
scheduler.clearTimeout(repeat)
scheduler.clearInterval(autorepeat)
scheduler.clearInterval(ticktack)
stats.pauseTime = stats.time
scheduler.clearInterval(fall);
scheduler.clearTimeout(lockDown);
scheduler.clearTimeout(repeat);
scheduler.clearInterval(autorepeat);
scheduler.clearInterval(ticktack);
stats.pauseTime = stats.time;
document.onkeydown = null
document.onkeydown = null;
settings.show()
settings.show();
playSound(menuhover)
}
function newGame(event) {
if (!settings.form.checkValidity()) {
event.preventDefault()
event.stopPropagation()
settings.form.reportValidity()
settings.form.classList.add('was-validated')
event.preventDefault();
event.stopPropagation();
settings.form.reportValidity();
settings.form.classList.add('was-validated');
} else {
const audioContext = new AudioContext()
for(const sound of document.getElementsByTagName("audio")) {
sound.preservesPitch = false
audioContext.createMediaElementSource(sound).connect(audioContext.destination)
const audioContext = new AudioContext();
for (const sound of document.getElementsByTagName('audio')) {
sound.preservesPitch = false;
audioContext.createMediaElementSource(sound).connect(audioContext.destination);
}
levelInput.name = "level"
levelInput.disabled = true
titleHeader.innerHTML = "PAUSE"
resumeButton.innerHTML = "Reprendre"
event.target.onsubmit = resume
stats.level = levelInput.valueAsNumber
localStorage["startLevel"] = levelInput.value
playing = true
onblur = pauseSettings
resume(event)
levelInput.name = 'level';
levelInput.disabled = true;
titleHeader.innerHTML = 'PAUSE';
resumeButton.innerHTML = 'Reprendre';
event.target.onsubmit = resume;
stats.level = levelInput.valueAsNumber;
localStorage['startLevel'] = levelInput.value;
playing = true;
onblur = pauseSettings;
resume(event);
}
}
function resume(event) {
event.preventDefault()
event.stopPropagation()
event.preventDefault();
event.stopPropagation();
settings.form.reportValidity()
settings.form.classList.add('was-validated')
settings.form.reportValidity();
settings.form.classList.add('was-validated');
if (settings.form.checkValidity()) {
for(const sound of document.getElementsByTagName("audio"))
sound.volume = sfxVolumeRange.value
for (const sound of document.getElementsByTagName('audio'))
sound.volume = sfxVolumeRange.value;
settings.modal.hide()
settings.getInputs()
settings.modal.hide();
settings.getInputs();
document.onkeydown = onkeydown
document.onkeyup = onkeyup
stats.time = stats.pauseTime
scheduler.setInterval(ticktack, 1000)
document.onkeydown = onkeydown;
document.onkeyup = onkeyup;
if (matrix.piece) scheduler.setInterval(fall, stats.fallPeriod)
else generate()
stats.time = stats.pauseTime;
scheduler.setInterval(ticktack, 1000);
if (matrix.piece) scheduler.setInterval(fall, stats.fallPeriod);
else generate();
playSound(menuconfirm)
}
}
function ticktack() {
timeCell.innerText = stats.timeFormat.format(stats.time)
timeCell.innerText = stats.timeFormat.format(stats.time);
}
function generate(piece) {
matrix.piece = piece || nextQueue.shift()
if (!piece && holdQueue.piece) holdQueue.drawPiece()
matrix.piece = piece || nextQueue.shift();
if (!piece && holdQueue.piece) holdQueue.drawPiece();
//lastActionSucceded = true
favicon.href = matrix.piece.favicon_href
favicon.href = matrix.piece.favicon_href;
if (matrix.piece.canMove(TRANSLATION.NONE)) {
scheduler.setInterval(fall, stats.fallPeriod)
scheduler.setInterval(fall, stats.fallPeriod);
} else {
gameOver() // block out
gameOver(); // block out
}
}
let playerActions = {
moveLeft: () => matrix.piece.move(TRANSLATION.LEFT),
moveLeft: () => matrix.piece.move(TRANSLATION.LEFT)? playSound(move) : playSound(hit),
moveRight: () => matrix.piece.move(TRANSLATION.RIGHT),
moveRight: () => matrix.piece.move(TRANSLATION.RIGHT)? playSound(move) : playSound(hit),
rotateClockwise: () => matrix.piece.rotate(ROTATION.CW),
rotateClockwise: () => matrix.piece.rotate(ROTATION.CW)? playSound(rotate) : playSound(hit),
rotateCounterclockwise: () => matrix.piece.rotate(ROTATION.CCW),
rotateCounterclockwise: () => matrix.piece.rotate(ROTATION.CCW)? playSound(rotate) : playSound(hit),
softDrop: () => matrix.piece.move(TRANSLATION.DOWN) && ++stats.score,
softDrop: () => (matrix.piece.move(TRANSLATION.DOWN) && ++stats.score)? playSound(move) : playSound(floor),
hardDrop: function() {
scheduler.clearTimeout(lockDown)
playSound(hardDropSound)
while (matrix.piece.move(TRANSLATION.DOWN, ROTATION.NONE, true)) stats.score += 2
matrixCard.classList.add("hard-dropped-table-animation")
lockDown()
return true
hardDrop: function () {
scheduler.clearTimeout(lockDown);
playSound(harddrop);
while (matrix.piece.move(TRANSLATION.DOWN, ROTATION.NONE, true)) stats.score += 2;
matrixCard.classList.remove('hard-dropped-table-animation');
matrixCard.offsetHeight;
matrixCard.classList.add('hard-dropped-table-animation'); // restart animation
lockDown();
return true;
},
hold: function() {
hold: function () {
if (matrix.piece.holdEnabled) {
scheduler.clearInterval(fall)
scheduler.clearTimeout(lockDown)
scheduler.clearInterval(fall);
scheduler.clearTimeout(lockDown);
playSound(hold)
let piece = matrix.piece
piece.facing = FACING.NORTH
piece.locked = false
generate(holdQueue.piece)
matrix.piece.holdEnabled = false
holdQueue.piece = piece
let piece = matrix.piece;
piece.facing = FACING.NORTH;
piece.locked = false;
generate(holdQueue.piece);
matrix.piece.holdEnabled = false;
holdQueue.piece = piece;
}
},
pause: pauseSettings,
}
};
// Handle player inputs
const REPEATABLE_ACTIONS = [
playerActions.moveLeft,
playerActions.moveRight,
playerActions.softDrop
]
pressedKeys = new Set()
actionsQueue = []
playerActions.softDrop,
];
pressedKeys = new Set();
actionsQueue = [];
function onkeydown(event) {
if (event.key in settings.keyBind) {
event.preventDefault()
event.preventDefault();
if (!pressedKeys.has(event.key)) {
pressedKeys.add(event.key)
action = settings.keyBind[event.key]
pressedKeys.add(event.key);
action = settings.keyBind[event.key];
/*if (action()) {
lastActionSucceded = true
} else if (lastActionSucceded || !(action in REPEATABLE_ACTIONS)) {
playSound(wallSound)
lastActionSucceded = false
}*/
action()
action();
if (REPEATABLE_ACTIONS.includes(action)) {
actionsQueue.unshift(action)
scheduler.clearTimeout(repeat)
scheduler.clearInterval(autorepeat)
if (action == playerActions.softDrop) scheduler.setInterval(autorepeat, settings.fallPeriod/20)
else scheduler.setTimeout(repeat, settings.das)
actionsQueue.unshift(action);
scheduler.clearTimeout(repeat);
scheduler.clearInterval(autorepeat);
if (action == playerActions.softDrop)
scheduler.setInterval(autorepeat, settings.fallPeriod / 20);
else scheduler.setTimeout(repeat, settings.das);
}
matrix.drawPiece()
matrix.drawPiece();
}
}
}
function repeat() {
if (actionsQueue.length) {
actionsQueue[0]()
scheduler.setInterval(autorepeat, settings.arr)
actionsQueue[0]();
scheduler.setInterval(autorepeat, settings.arr);
}
}
@@ -194,121 +195,241 @@ function autorepeat() {
wallSound.play()
lastActionSucceded = false
}*/
actionsQueue[0]()
}
else scheduler.clearInterval(autorepeat)
actionsQueue[0]();
} else scheduler.clearInterval(autorepeat);
}
function onkeyup(event) {
if (event.key in settings.keyBind) {
event.preventDefault()
pressedKeys.delete(event.key)
action = settings.keyBind[event.key]
event.preventDefault();
pressedKeys.delete(event.key);
action = settings.keyBind[event.key];
if (actionsQueue.includes(action)) {
actionsQueue.splice(actionsQueue.indexOf(action), 1)
scheduler.clearTimeout(repeat)
scheduler.clearInterval(autorepeat)
actionsQueue.splice(actionsQueue.indexOf(action), 1);
scheduler.clearTimeout(repeat);
scheduler.clearInterval(autorepeat);
if (actionsQueue.length) {
if (actionsQueue[0] == playerActions.softDrop) scheduler.setInterval(autorepeat, settings.fallPeriod/20)
else scheduler.setTimeout(repeat, settings.das)
if (actionsQueue[0] == playerActions.softDrop)
scheduler.setInterval(autorepeat, settings.fallPeriod / 20);
else scheduler.setTimeout(repeat, settings.das);
} else {
matrix.drawPiece()
matrix.drawPiece();
}
}
}
}
function fall() {
matrix.piece.move(TRANSLATION.DOWN)
matrix.piece.move(TRANSLATION.DOWN);
}
function lockDown() {
scheduler.clearTimeout(lockDown)
scheduler.clearInterval(fall)
scheduler.clearTimeout(lockDown);
scheduler.clearInterval(fall);
if (matrix.lock()) {
stats.lockDown(matrix.piece.tSpin, matrix.clearLines())
generate()
stats.lockDown(matrix.piece.tSpin, matrix.clearLines());
generate();
} else {
gameOver() // lock out
gameOver(); // lock out
}
}
onanimationend = function (event) {
event.target.classList.remove(event.animationName)
}
event.target.classList.remove(event.animationName);
};
messagesSpan.onanimationend = function(event) {
event.target.remove()
}
messagesSpan.onanimationend = function (event) {
event.target.remove();
};
function gameOver() {
matrix.piece.locked = true
matrix.drawPiece()
matrix.piece.locked = true;
matrix.drawPiece();
document.onkeydown = null
onblur = null
scheduler.clearInterval(ticktack)
playing = false
document.onkeydown = null;
onblur = null;
scheduler.clearInterval(ticktack);
playing = false;
stats.show()
stats.show();
playSound(gameover)
}
window.onbeforeunload = function(event) {
stats.save()
settings.save()
window.onbeforeunload = function (event) {
stats.save();
settings.save();
if (playing) return false;
}
};
// Play with 3D
let mousedown = false
let rX0 = 0
let rY0 = 0
let clientX0 = 0
let clientY0 = 0
let mousedown = false;
let rX0 = -15;
let rY0 = 0;
let clientX0 = 0;
let clientY0 = 0;
sceneDiv.onmousedown = function(event) {
mousedown = true
rX0 = parseInt(getComputedStyle(screenRow).getPropertyValue("--rX"))
dy0 = parseInt(getComputedStyle(screenRow).getPropertyValue("--rY"))
clientX0 = event.clientX
clientY0 = event.clientY
}
sceneDiv.onmousedown = function (event) {
mousedown = true;
rX0 = parseInt(getComputedStyle(screenRow).getPropertyValue('--rX'));
dy0 = parseInt(getComputedStyle(screenRow).getPropertyValue('--rY'));
clientX0 = event.clientX;
clientY0 = event.clientY;
};
sceneDiv.onmousemove = function(event) {
if (mousedown) {
event.preventDefault()
event.stopPropagation()
rX = (rX0 - event.clientY + clientY0 + 360) % 360
screenRow.style.setProperty("--rX", rX + "deg")
if (rX <= 180) {
screenRow.classList.remove("top")
screenRow.classList.add("bottom")
sceneDiv.onmousemove = function (event) {
if (mousedown) {
event.preventDefault();
event.stopPropagation();
rX = (rX0 - 0.5 * (event.clientY - clientY0)) % 360;
screenRow.style.setProperty('--rX', rX);
if (rX >= 0) {
screenRow.classList.remove('top');
screenRow.classList.add('bottom');
} else {
screenRow.classList.add("top")
screenRow.classList.remove("bottom")
screenRow.classList.add('top');
screenRow.classList.remove('bottom');
}
rY = (rY0 + event.clientX - clientX0 + 360) % 360
screenRow.style.setProperty("--rY", rY + "deg")
if (rY >= 180) {
screenRow.classList.remove("left")
screenRow.classList.add("right")
rY = (rY0 + 0.5 * (event.clientX - clientX0)) % 360;
screenRow.style.setProperty('--rY', rY);
if (rY <= 0) {
screenRow.classList.remove('left');
screenRow.classList.add('right');
} else {
screenRow.classList.add("left")
screenRow.classList.remove("right")
screenRow.classList.add('left');
screenRow.classList.remove('right');
}
}
};
sceneDiv.onmouseup = document.onmouseleave = function (event) {
mousedown = false;
};
fullscreenCheckbox.onchange = function () {
if (this.checked) {
document.documentElement.requestFullscreen();
} else {
document.exitFullscreen();
}
};
sceneDiv.onwheel = function (event) {
event.preventDefault();
event.stopPropagation();
let tZ = parseInt(getComputedStyle(screenRow).getPropertyValue('--tZ'));
tZ -= event.deltaY;
screenRow.style.setProperty('--tZ', tZ + 'px');
};
const ImageURLPattern = /^(https?:\/\/.*\.(?:png|jpg|jpeg|gif|bmp|webp|svg))$/i
$.fn.select2.defaults.set("templateResult", (state) =>
state.id
? $(`<img class="preview" src="${state.id}" title="${state.text}" loading="lazy"/>`)
: state.text
)
$.fn.select2.defaults.set("templateSelection", (state) =>
state.id
? $(`
<table class="minoes-table preview" style="--skin-url: url(${state.id});">
<tr><td class="Z mino"></td><td class="O mino"></td><td class="T mino"></td><td class="I mino"></td></tr>
</table>
`)
: state.text
)
$.fn.select2.defaults.set("theme", "bootstrap-5")
$.fn.select2.defaults.set("selectionCssClass", 'form-select')
$.fn.select2.defaults.set("dropdownParent", $('#settingsModal'))
$.fn.select2.defaults.set("dropdownAutoWidth", true)
$.fn.select2.defaults.set("placeholder", "URL de l'image")
$.fn.select2.defaults.set("tags", true)
$.fn.select2.defaults.set("createTag", function (params) {
const url = encodeURI(params.term);
if (ImageURLPattern.test(url)) {
return {
id: url,
text: 'Source externe',
newTag: true,
};
}
});
stylesheetSelect.oninput = function (event) {
selectedStyleSheet.href = this.value;
$("#skinURLSelect").empty();
switch (this.value) {
case 'css/tetrio-skin.css':
skinURLSelect.disabled = false;
const baseURL = "https://you.have.fail/tetrioplus/data"
fetch(`${baseURL}/data.json`)
.then((resp) => resp.json())
.then((json) => {
json = json.filter((item) => (item.type == "skin" && item.format == "tetrioraster" && /\.(?:png|jpg|jpeg|gif|bmp|webp|svg)$/i.test(item.path)))
const groups = Map.groupBy(json, (skin) => skin.author)
var data = groups.entries().map(([author, skins]) => {
return {
text: author,
children: skins.map((skin) => {
return {
id: `${baseURL}/${encodeURI(skin.path)}`,
text:`${skin.name}\n${skin.description}`
}
})
}
}).toArray()
data.push({
text: "AdrienMalin",
children: [{
id: `${document.location.href}/css/tetrio-skin/a_forest.png`,
text: "A forest"
}]
})
data.sort((group1, group2) => group1.text > group2.text)
$('#skinURLSelect').select2({data: data});
})
break;
case 'css/jstris-skin.css':
skinURLSelect.disabled = false;
fetch('https://konsola5.github.io/jstris-customization-database/jstrisCustomizationDatabase.json')
.then(response => response.json())
.then(json => {
const data = [];
for (const group in json) {
const groupData = {
text: group,
children: json[group].map(skin => ({
id: skin.link,
text: `${skin.name} by ${skin.author}`,
})),
};
data.push(groupData);
}
$('#skinURLSelect').select2({data: data});
});
break;
default:
skinURLSelect.disabled = true;
break;
}
}
sceneDiv.onmouseup = document.onmouseleave = function(event) {
mousedown = false
}
let scheduler = new Scheduler();
let settings = new Settings();
let stats = new Stats();
let holdQueue = new HoldQueue();
let matrix = new Matrix();
let nextQueue = new NextQueue();
let playing = false;
//let lastActionSucceded = true
let favicon = document.querySelector("link[rel~='icon']");
sceneDiv.onwheel = function(event) {
event.preventDefault()
event.stopPropagation()
let tZ = parseInt(getComputedStyle(screenRow).getPropertyValue("--tZ"))
tZ += event.deltaY
screenRow.style.setProperty("--tZ", tZ + "px")
}
window.onload = function (event) {
restart();
};

View File

@@ -17,7 +17,7 @@ const T_SPIN = {
T_SPIN: "PIROUETTE"
}
// score = AWARDED_LINE_CLEARS[tSpin][nbClearedLines]
// score = AWARDED_LINE_CLEARS[tSpin][clearedLines]
const AWARDED_LINE_CLEARS = {
[T_SPIN.NONE]: [0, 1, 3, 5, 8],
[T_SPIN.MINI]: [1, 2],
@@ -251,8 +251,12 @@ class Matrix extends MinoesTable {
if (piece.locked) className += " locking"
if (piece==this.piece && actionsQueue.length) className += " moving"
super.drawPiece(piece, className)
matrix.table.style.setProperty('--piece-column', this.piece.center.x)
matrix.table.style.setProperty('--piece-row', this.piece.center.y)
this.table.style.setProperty('--piece-column', this.piece.center.x)
this.table.style.setProperty('--piece-row', this.piece.center.y)
}
clearPiece(piece=this.piece, className="") {
super.drawPiece(piece, className)
}
redraw() {
@@ -278,18 +282,18 @@ class Matrix extends MinoesTable {
}
clearLines() {
let nbClearedLines = 0
let clearedLines = 0
for (let y=0; y<this.rows; y++) {
let row = this.blocks[y]
if (row.filter(lockedMino => lockedMino).length == this.columns) {
nbClearedLines++
clearedLines++
this.blocks.splice(y, 1)
this.blocks.unshift(Array(matrix.columns))
this.table.rows[y].classList.add("cleared-line-animation")
}
}
this.redraw()
return nbClearedLines
return clearedLines
}
}
Matrix.prototype.init_center = [4, 4]
@@ -328,7 +332,7 @@ class Tetromino {
let success = this.canMove(translation, rotation)
if (success) {
scheduler.clearTimeout(lockDown)
matrix.drawPiece(this, hardDropped? "trail-animation" : "")
matrix.clearPiece(this, hardDropped? "trail-animation" : "")
this.center = success.center
if (rotation) this.facing = success.facing
this.lastRotation = rotation

View File

@@ -1,334 +1,399 @@
const KEY_NAMES = new Proxy({
["ArrowLeft"] : "←",
["←"] : "ArrowLeft",
["ArrowRight"] : "→",
["→"] : "ArrowRight",
["ArrowUp"] : "↑",
["↑"] : "ArrowUp",
["ArrowDown"] : "↓",
["↓"] : "ArrowDown",
[" "] : "Espace",
["Espace"] : " ",
["Escape"] : "Échap.",
["Échap."] : "Escape",
["Backspace"] : "Ret. arrière",
["Ret. arrière"]: "Backspace",
["Enter"] : "Entrée",
["Entrée"] : "Enter",
}, {
get(target, key) {
return key in target? target[key] : key
}
})
const KEY_NAMES = new Proxy(
{
['ArrowLeft']: '←',
['←']: 'ArrowLeft',
['ArrowRight']: '→',
['→']: 'ArrowRight',
['ArrowUp']: '↑',
['↑']: 'ArrowUp',
['ArrowDown']: '↓',
['↓']: 'ArrowDown',
[' ']: 'Espace',
['Espace']: ' ',
['Escape']: 'Échap.',
['Échap.']: 'Escape',
['Backspace']: 'Ret. arrière',
['Ret. arrière']: 'Backspace',
['Enter']: 'Entrée',
['Entrée']: 'Enter',
},
{
get(target, key) {
return key in target ? target[key] : key;
},
},
);
class Settings {
constructor() {
this.form = settingsForm
this.load()
this.modal = new bootstrap.Modal('#settingsModal')
settingsModal.addEventListener('shown.bs.modal', () => resumeButton.focus())
this.form = settingsForm;
this.load();
this.modal = new bootstrap.Modal('#settingsModal');
settingsModal.addEventListener('shown.bs.modal', () => resumeButton.focus());
}
load() {
this.form.querySelectorAll("[name]").forEach(element => {
if (element.name in localStorage)
element.value = localStorage[element.name]
})
window.document.selectedStyleSheetSet = stylesheetSelect.value
this.form.querySelectorAll('[name]').forEach(element => {
if (element.name in localStorage) element.value = localStorage[element.name];
});
stylesheetSelect.oninput();
if (localStorage['skinURL']) {
if ($('#skinURLSelect').find("option[value='" + localStorage['skinURL'] + "']").length) {
$('#skinURLSelect').val(localStorage['skinURL']).trigger('change');
} else {
var option = new Option('Sample sauvegardé', localStorage['skinURL']);
$('#skinURLSelect').append(option).trigger('change');
}
skinURLSelect.oninput();
}
}
save() {
this.form.querySelectorAll("[name]").forEach(element => localStorage[element.name] = element.value)
this.form
.querySelectorAll('[name]')
.forEach(element => (localStorage[element.name] = element.value));
}
init() {
this.form.onsubmit = newGame
levelInput.name = "startLevel"
levelInput.disabled = false
titleHeader.innerHTML = "QUATUOR"
resumeButton.innerHTML = "Jouer"
this.form.onsubmit = newGame;
levelInput.name = 'startLevel';
levelInput.disabled = false;
titleHeader.innerHTML = 'QUATUOR';
resumeButton.innerHTML = 'Jouer';
}
show() {
resumeButton.disabled = false
settings.form.classList.remove('was-validated')
settings.modal.show()
settings.form.reportValidity()
resumeButton.disabled = false;
settings.form.classList.remove('was-validated');
settings.modal.show();
settings.form.reportValidity();
}
getInputs() {
for (let input of this.form.querySelectorAll("input[type='text']")) {
this[input.name] = KEY_NAMES[input.value]
this[input.name] = KEY_NAMES[input.value];
}
for (let input of this.form.querySelectorAll("input[type='number'], input[type='range']")) {
this[input.name] = input.valueAsNumber
this[input.name] = input.valueAsNumber;
}
for (let input of this.form.querySelectorAll("input[type='checkbox']")) {
this[input.name] = input.checked == true
this[input.name] = input.checked == true;
}
this.keyBind = new Proxy({}, {
get: (target, key) => target[key.toLowerCase()],
set: (target, key, value) => target[key.toLowerCase()] = value,
has: (target, key) => key.toLowerCase() in target
})
this.keyBind = new Proxy(
{},
{
get: (target, key) => target[key.toLowerCase()],
set: (target, key, value) => (target[key.toLowerCase()] = value),
has: (target, key) => key.toLowerCase() in target,
},
);
for (let actionName in playerActions) {
this.keyBind[settings[actionName]] = playerActions[actionName]
this.keyBind[settings[actionName]] = playerActions[actionName];
}
}
}
function changeKey(input) {
prevValue = input.value
input.value = ""
keyInputs = Array.from(input.form.querySelectorAll("input[type='text']"))
prevValue = input.value;
input.value = '';
keyInputs = Array.from(input.form.querySelectorAll("input[type='text']"));
input.onkeydown = function (event) {
event.preventDefault()
input.value = KEY_NAMES[event.key]
event.preventDefault();
input.value = KEY_NAMES[event.key];
keyInputs.forEach(input => {
input.setCustomValidity("")
input.classList.remove("is-invalid")
})
input.setCustomValidity('');
input.classList.remove('is-invalid');
});
keyInputs.sort((input1, input2) => {
if(input1.value == input2.value) {
input1.setCustomValidity("Touche déjà utilisée")
input1.classList.add("is-invalid")
input2.setCustomValidity("Touche déjà utilisée")
input2.classList.add("is-invalid")
if (input1.value == input2.value) {
input1.setCustomValidity('Touche déjà utilisée');
input1.classList.add('is-invalid');
input2.setCustomValidity('Touche déjà utilisée');
input2.classList.add('is-invalid');
}
return input1.value > input2.value
})
return input1.value > input2.value;
});
if (input.checkValidity()) {
input.blur()
input.blur();
}
}
};
input.onblur = function (event) {
if (!input.value) input.value = prevValue
input.onkeydown = null
input.onblur = null
}
if (!input.value) input.value = prevValue;
input.onkeydown = null;
input.onblur = null;
};
}
class Stats {
constructor() {
this.modal = new bootstrap.Modal('#statsModal')
this.load()
this.modal = new bootstrap.Modal('#statsModal');
this.load();
}
load() {
this.highScore = Number(localStorage["highScore"]) || 0
this.highScore = Number(localStorage['highScore']) || 0;
}
init() {
levelInput.value = localStorage["startLevel"] || 1
this.score = 0
this.goal = 0
this.combo = 0
this.b2b = 0
this.startTime = new Date()
this.lockDelay = DELAY.LOCK
this.totalClearedLines = 0
this.nbQuatuors = 0
this.nbTSpin = 0
this.maxCombo = 0
this.maxB2B = 0
levelInput.value = localStorage['startLevel'] || 1;
this.score = 0;
this.goal = 0;
this.combo = -1;
this.b2b = -1;
this.startTime = new Date();
this.lockDelay = DELAY.LOCK;
this.totalClearedLines = 0;
this.nbQuatuors = 0;
this.nbTSpin = 0;
this.maxCombo = 0;
this.maxB2B = 0;
}
set score(score) {
this._score = score
scoreCell.innerText = score.toLocaleString()
this._score = score;
scoreCell.innerText = score.toLocaleString();
if (score > this.highScore) {
this.highScore = score
this.highScore = score;
}
}
get score() {
return this._score
return this._score;
}
set highScore(highScore) {
this._highScore = highScore
highScoreCell.innerText = highScore.toLocaleString()
this._highScore = highScore;
highScoreCell.innerText = highScore.toLocaleString();
}
get highScore() {
return this._highScore
return this._highScore;
}
set level(level) {
this._level = level
this.goal += level * 5
if (level <= 20){
this.fallPeriod = 1000 * Math.pow(0.8 - ((level - 1) * 0.007), level - 1)
this._level = level;
this.goal += level * 5;
if (level <= 20) {
this.fallPeriod = 1000 * Math.pow(0.8 - (level - 1) * 0.007, level - 1);
}
if (level > 15)
this.lockDelay = 500 * Math.pow(0.9, level - 15)
levelInput.value = level
levelCell.innerText = level
messagesSpan.addNewChild("div", { className: "show-level-animation", innerHTML: `<h1>NIVEAU<br/>${this.level}</h1>` })
if (level > 15) this.lockDelay = 500 * Math.pow(0.9, level - 15);
levelInput.value = level;
levelCell.innerText = level;
messagesSpan.addNewChild('div', {
className: 'show-level-animation',
innerHTML: `<h1>NIVEAU<br/>${this.level}</h1>`,
});
}
get level() {
return this._level
return this._level;
}
set goal(goal) {
this._goal = goal
goalCell.innerText = goal
this._goal = goal;
goalCell.innerText = goal;
}
get goal() {
return this._goal
return this._goal;
}
set combo(combo) {
this._combo = combo
if (combo > this.maxCombo) this.maxCombo = combo
this._combo = combo;
if (combo > this.maxCombo) this.maxCombo = combo;
}
get combo() {
return this._combo
return this._combo;
}
set b2b(b2b) {
this._b2b = b2b
if (b2b > this.maxB2B) this.maxB2B = b2b
this._b2b = b2b;
if (b2b > this.maxB2B) this.maxB2B = b2b;
}
get b2b() {
return this._b2b
return this._b2b;
}
set time(time) {
this.startTime = new Date() - time
ticktack()
this.startTime = new Date() - time;
ticktack();
}
get time() {
return new Date() - this.startTime
return new Date() - this.startTime;
}
lockDown(tSpin, nbClearedLines) {
this.totalClearedLines += nbClearedLines
if (nbClearedLines == 4) this.nbQuatuors++
if (tSpin == T_SPIN.T_SPIN) this.nbTSpin++
lockDown(tSpin, clearedLines) {
this.totalClearedLines += clearedLines;
if (clearedLines == 4) this.nbQuatuors++;
if (tSpin == T_SPIN.T_SPIN) this.nbTSpin++;
// Cleared lines & T-Spin
let awardedLineClears = AWARDED_LINE_CLEARS[tSpin][nbClearedLines]
let patternScore = 100 * this.level * awardedLineClears
if (tSpin) messagesSpan.addNewChild("div", {
className: "rotate-in-animation",
innerHTML: tSpin
})
if (nbClearedLines) messagesSpan.addNewChild("div", {
className: "zoom-in-animation",
innerHTML: CLEARED_LINES_NAMES[nbClearedLines]
})
let awardedLineClears = AWARDED_LINE_CLEARS[tSpin][clearedLines];
let patternScore = 100 * this.level * awardedLineClears;
if (tSpin)
messagesSpan.addNewChild('div', {
className: 'rotate-in-animation',
innerHTML: tSpin,
});
if (clearedLines)
messagesSpan.addNewChild('div', {
className: 'zoom-in-animation',
innerHTML: CLEARED_LINES_NAMES[clearedLines],
});
if (patternScore) {
messagesSpan.addNewChild("div", {
className: "zoom-in-animation",
style: "animation-delay: .2s",
innerHTML: patternScore
})
this.score += patternScore
messagesSpan.addNewChild('div', {
className: 'zoom-in-animation',
style: 'animation-delay: .2s',
innerHTML: patternScore,
});
this.score += patternScore;
}
// Combo
if (nbClearedLines) {
this.combo++
if (clearedLines) {
this.combo++;
if (this.combo >= 1) {
let comboScore = (nbClearedLines == 1 ? 20 : 50) * this.combo * this.level
let comboScore = (clearedLines == 1 ? 20 : 50) * this.combo * this.level;
if (this.combo == 1) {
messagesSpan.addNewChild("div", {
className: "zoom-in-animation",
style: "animation-delay: .4s",
innerHTML: `COMBO<br/>${comboScore}`
})
messagesSpan.addNewChild('div', {
className: 'zoom-in-animation',
style: 'animation-delay: .4s',
innerHTML: `COMBO<br/>${comboScore}`,
});
} else {
messagesSpan.addNewChild("div", {
className: "zoom-in-animation",
style: "animation-delay: .4s",
innerHTML: `COMBO x${this.combo}<br/>${comboScore}`
})
messagesSpan.addNewChild('div', {
className: 'zoom-in-animation',
style: 'animation-delay: .4s',
innerHTML: `COMBO x${this.combo}<br/>${comboScore}`,
});
}
this.score += comboScore
this.score += comboScore;
}
} else {
this.combo = -1
if (this.combo >= 1) playSound(combobreak)
this.combo = -1;
}
// Back to back sequence
if ((nbClearedLines == 4) || (tSpin && nbClearedLines)) {
this.b2b++
if (clearedLines == 4 || (tSpin && clearedLines)) {
this.b2b++;
if (this.b2b >= 1) {
let b2bScore = patternScore / 2
let b2bScore = patternScore / 2;
if (this.b2b == 1) {
messagesSpan.addNewChild("div", {
className: "zoom-in-animation",
style: "animation-delay: .4s",
innerHTML: `BOUT EN BOUT<br/>${b2bScore}`
})
messagesSpan.addNewChild('div', {
className: 'zoom-in-animation',
style: 'animation-delay: .4s',
innerHTML: `BOUT À BOUT<br/>${b2bScore}`,
});
} else {
messagesSpan.addNewChild("div", {
className: "zoom-in-animation",
style: "animation-delay: .4s",
innerHTML: `BOUT EN BOUT x${this.b2b}<br/>${b2bScore}`
})
messagesSpan.addNewChild('div', {
className: 'zoom-in-animation',
style: 'animation-delay: .4s',
innerHTML: `BOUT À BOUT x${this.b2b}<br/>${b2bScore}`,
});
}
this.score += b2bScore
this.score += b2bScore;
}
} else if (nbClearedLines && !tSpin ) {
} else if (clearedLines && !tSpin) {
if (this.b2b >= 1) {
messagesSpan.addNewChild("div", {
className: "zoom-in-animation",
style: "animation-delay: .4s",
innerHTML: `FIN DU BOUT EN BOUT`
})
messagesSpan.addNewChild('div', {
className: 'zoom-in-animation',
style: 'animation-delay: .4s',
innerHTML: `FIN DU BOUT À BOUT`,
});
playSound(btb_break)
}
this.b2b = -1
this.b2b = -1;
}
// Sound
// Sounds
if (sfxVolumeRange.value) {
if (nbClearedLines == 4) playSound(quatuorSound, this.combo)
else if (nbClearedLines) playSound(lineClearSound, this.combo)
if (tSpin) playSound(tSpinSound, this.combo)
if (clearedLines == 4 || (tSpin && clearedLines)) switch(this.b2b) {
case -1:
case 0: playSound(clearbtb); break
case 1: playSound(btb_1); break
case 2: playSound(btb_2); break
default: playSound(btb_3)
} else if (tSpin) switch(this.combo) {
case -1: playSound(spin); break
case 0: playSound(clearspin); break
case 1: playSound(combo_1_power); break
case 2: playSound(combo_2_power); break
case 3: playSound(combo_3_power); break
case 4: playSound(combo_4_power); break
case 5: playSound(combo_5_power); break
case 6: playSound(combo_6_power); break
case 7: playSound(combo_7_power); break
case 8: playSound(combo_8_power); break
case 9: playSound(combo_9_power); break
case 10: playSound(combo_10_power); break
case 11: playSound(combo_11_power); break
case 12: playSound(combo_12_power); break
case 13: playSound(combo_13_power); break
case 14: playSound(combo_14_power); break
case 15: playSound(combo_15_power); break
default: playSound(combo_16_power)
} else switch(this.combo) {
case -1: break;
case 0: playSound(clearline); break
case 1: playSound(combo_1); break
case 2: playSound(combo_2); break
case 3: playSound(combo_3); break
case 4: playSound(combo_4); break
case 5: playSound(combo_5); break
case 6: playSound(combo_6); break
case 7: playSound(combo_7); break
case 8: playSound(combo_8); break
case 9: playSound(combo_9); break
case 10: playSound(combo_10); break
case 11: playSound(combo_11); break
case 12: playSound(combo_12); break
case 13: playSound(combo_13); break
case 14: playSound(combo_14); break
case 15: playSound(combo_15); break
default: playSound(combo_16)
}
}
this.goal -= awardedLineClears
if (this.goal <= 0) this.level++
this.goal -= awardedLineClears;
if (this.goal <= 0) this.level++;
}
show() {
let time = stats.time
statsModalScoreCell.innerText = this.score.toLocaleString()
statsModalHighScoreCell.innerText = this.highScore.toLocaleString()
statsModalLevelCell.innerText = this.level
statsModalTimeCell.innerText = this.timeFormat.format(time)
statsModaltotalClearedLines.innerText = this.totalClearedLines
statsModaltotalClearedLinesPM.innerText = (stats.totalClearedLines * 60000 / time).toFixed(2)
statsModalNbQuatuors.innerText = this.nbQuatuors
statsModalNbTSpin.innerText = this.nbTSpin
statsModalMaxCombo.innerText = this.maxCombo
statsModalMaxB2B.innerText = this.maxB2B
this.modal.show()
let time = stats.time;
statsModalScoreCell.innerText = this.score.toLocaleString();
statsModalHighScoreCell.innerText = this.highScore.toLocaleString();
statsModalLevelCell.innerText = this.level;
statsModalTimeCell.innerText = this.timeFormat.format(time);
statsModaltotalClearedLines.innerText = this.totalClearedLines;
statsModaltotalClearedLinesPM.innerText = (
(stats.totalClearedLines * 60000) /
time
).toFixed(2);
statsModalNbQuatuors.innerText = this.nbQuatuors;
statsModalNbTSpin.innerText = this.nbTSpin;
statsModalMaxCombo.innerText = this.maxCombo;
statsModalMaxB2B.innerText = this.maxB2B;
this.modal.show();
}
save() {
localStorage["highScore"] = this.highScore
localStorage['highScore'] = this.highScore;
}
}
Stats.prototype.timeFormat = new Intl.DateTimeFormat("fr-FR", {
hour: "numeric",
minute: "2-digit",
second: "2-digit",
timeZone: "UTC"
})
Stats.prototype.timeFormat = new Intl.DateTimeFormat('fr-FR', {
hour: 'numeric',
minute: '2-digit',
second: '2-digit',
timeZone: 'UTC',
});
function playSound(sound, note=0) {
sound.currentTime = 0
sound.playbackRate = Math.pow(5/4, note)
sound.play()
}
function playSound(sound, note = 0) {
sound.currentTime = 0;
sound.playbackRate = note? Math.pow(5 / 4, note): 1;
sound.play();
}

File diff suppressed because it is too large Load Diff

BIN
snd/allclear.ogg Normal file

Binary file not shown.

BIN
snd/btb_1.ogg Normal file

Binary file not shown.

BIN
snd/btb_2.ogg Normal file

Binary file not shown.

BIN
snd/btb_3.ogg Normal file

Binary file not shown.

BIN
snd/btb_break.ogg Normal file

Binary file not shown.

BIN
snd/clearbtb.ogg Normal file

Binary file not shown.

BIN
snd/clearline.ogg Normal file

Binary file not shown.

BIN
snd/clearquad.ogg Normal file

Binary file not shown.

BIN
snd/clearspin.ogg Normal file

Binary file not shown.

BIN
snd/clutch.mp3 Normal file

Binary file not shown.

BIN
snd/combo_1.mp3 Normal file

Binary file not shown.

BIN
snd/combo_10.mp3 Normal file

Binary file not shown.

BIN
snd/combo_10_power.mp3 Normal file

Binary file not shown.

BIN
snd/combo_11.mp3 Normal file

Binary file not shown.

BIN
snd/combo_11_power.mp3 Normal file

Binary file not shown.

BIN
snd/combo_12.mp3 Normal file

Binary file not shown.

BIN
snd/combo_12_power.mp3 Normal file

Binary file not shown.

BIN
snd/combo_13.mp3 Normal file

Binary file not shown.

BIN
snd/combo_13_power.mp3 Normal file

Binary file not shown.

BIN
snd/combo_14.mp3 Normal file

Binary file not shown.

BIN
snd/combo_14_power.mp3 Normal file

Binary file not shown.

BIN
snd/combo_15.mp3 Normal file

Binary file not shown.

BIN
snd/combo_15_power.mp3 Normal file

Binary file not shown.

BIN
snd/combo_16.ogg Normal file

Binary file not shown.

BIN
snd/combo_16_power.ogg Normal file

Binary file not shown.

BIN
snd/combo_1_power.mp3 Normal file

Binary file not shown.

BIN
snd/combo_2.mp3 Normal file

Binary file not shown.

BIN
snd/combo_2_power.mp3 Normal file

Binary file not shown.

BIN
snd/combo_3.mp3 Normal file

Binary file not shown.

BIN
snd/combo_3_power.mp3 Normal file

Binary file not shown.

BIN
snd/combo_4.mp3 Normal file

Binary file not shown.

BIN
snd/combo_4_power.mp3 Normal file

Binary file not shown.

BIN
snd/combo_5.mp3 Normal file

Binary file not shown.

BIN
snd/combo_5_power.mp3 Normal file

Binary file not shown.

BIN
snd/combo_6.mp3 Normal file

Binary file not shown.

BIN
snd/combo_6_power.mp3 Normal file

Binary file not shown.

BIN
snd/combo_7.mp3 Normal file

Binary file not shown.

BIN
snd/combo_7_power.mp3 Normal file

Binary file not shown.

BIN
snd/combo_8.mp3 Normal file

Binary file not shown.

BIN
snd/combo_8_power.mp3 Normal file

Binary file not shown.

BIN
snd/combo_9.mp3 Normal file

Binary file not shown.

BIN
snd/combo_9_power.mp3 Normal file

Binary file not shown.

BIN
snd/combobreak.mp3 Normal file

Binary file not shown.

BIN
snd/counter.ogg Normal file

Binary file not shown.

BIN
snd/damage_alert.ogg Normal file

Binary file not shown.

BIN
snd/damage_large.ogg Normal file

Binary file not shown.

BIN
snd/damage_medium.ogg Normal file

Binary file not shown.

BIN
snd/damage_small.ogg Normal file

Binary file not shown.

BIN
snd/death.mp3 Normal file

Binary file not shown.

BIN
snd/elim.mp3 Normal file

Binary file not shown.

BIN
snd/exchange.ogg Normal file

Binary file not shown.

BIN
snd/floor.ogg Normal file

Binary file not shown.

BIN
snd/garbage_in_large.ogg Normal file

Binary file not shown.

BIN
snd/garbage_in_medium.ogg Normal file

Binary file not shown.

BIN
snd/garbage_in_small.ogg Normal file

Binary file not shown.

Some files were not shown because too many files have changed in this diff Show More