2026-03-09 19:06:48 +01:00
parent b2601e9c24
commit 4bac3face1
7 changed files with 14060 additions and 218 deletions

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

@@ -4,10 +4,40 @@
--skin-url: url(https://i.imgur.com/HqGYC5G.png); --skin-url: url(https://i.imgur.com/HqGYC5G.png);
} }
.option {
display: inline-block;
width: calc(var(--nb-sprites) * var(--cell-size));
height: var(--cell-size);
background-image: var(--skin-url);
background-size: cover;
background-repeat: no-repeat;
}
.result {
--nb-sprites: 9;
}
.selection {
background-position-x: calc(-1 * var(--sprite-pos) * var(--cell-size));
--nb-sprites: 4;
--sprite-pos: 3;
}
.minoes-table { .minoes-table {
border-collapse: collapse; border-collapse: collapse;
} }
#matrixCard {
background-image: url(jstris-skin/jstris-grid.png);
background-position: bottom;
background-repeat: no-repeat;
background-blend-mode: screen;
}
tr.matrix td:not(.mino) {
border: none;
}
.mino { .mino {
width: var(--cell-size); width: var(--cell-size);
height: var(--cell-size); height: var(--cell-size);

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.7 KiB

View File

@@ -8,6 +8,9 @@
<meta name="color-scheme" content="dark"> <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@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="https://cdn.jsdelivr.net/npm/bootstrap-icons@1.10.4/font/bootstrap-icons.css">
<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/_common.css">
<link rel="stylesheet" href="css/classic.css" title="Thème sélectionné" id="selectedStyleSheet"> <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/classic.css" title="Classique">
@@ -18,8 +21,10 @@
<link rel="alternate stylesheet" href="css/jazz.css" title="Jazz"> <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/old-school.css" title="Old School">
<link rel="alternate stylesheet" href="css/stereo.css" title="Stéréo (3D)"> <link rel="alternate stylesheet" href="css/stereo.css" title="Stéréo (3D)">
<link rel="alternate stylesheet" href="css/jstris-skin.css" title="Skin type Jstris"> <link rel="alternate stylesheet" href="css/jstris-skin.css" title="Sample...">
<link rel="alternate stylesheet" href="css/tetrio-skin.css" title="Skin type Tetr.io"> <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="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="32x32" href="favicons/T-2.png">
<link rel="icon" type="image/png" sizes="16x16" href="favicons/favicon-16x16.png"> <link rel="icon" type="image/png" sizes="16x16" href="favicons/favicon-16x16.png">
@@ -63,7 +68,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> <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> <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>
<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> <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="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> <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>
@@ -91,18 +97,17 @@
<option value="css/jazz.css">Jazz</option> <option value="css/jazz.css">Jazz</option>
<option value="css/old-school.css">Old School</option> <option value="css/old-school.css">Old School</option>
<option value="css/stereo.css">Stéréo (3D)</option> <option value="css/stereo.css">Stéréo (3D)</option>
<option value="css/jstris-skin.css">Skin type Jstris</option> <option value="css/jstris-skin.css">Sample...</option>
<option value="css/tetrio-skin.css">Skin type Tetr.io</option>
</select> </select>
</div> </div>
<div id="skinURLdiv" class="col-6" style="display: none;"> <div id="skinURLdiv" class="col-6" style="display: none;">
<div class="col-8"> <div class="col-8">
<input name="skinURL" id="skinURLInput" type="text" class="col-8 form-control text-start" <select name="skinURL" id="skinURLInput" class="form-select" value="https://i.imgur.com/0l7LFMT.png"
placeholder="Adresse du skin" oninput="document.documentElement.style.setProperty('--skin-url', `url(${this.value})`)">
oninput="document.documentElement.style.setProperty('--skin-url', `url(${this.value})`)" </select>
onfocus="this.select()"> </script>
</div> </div>
<label for="skinURLInput" class="col-4 col-form-label">URL</label> <label for="skinURLInput" class="col-4 col-form-label">Sample</label>
</div> </div>
</fieldset> </fieldset>
<fieldset class="row g-2 mb-3 align-items-center text-center"><legend class="text-start">Partie</legend> <fieldset class="row g-2 mb-3 align-items-center text-center"><legend class="text-start">Partie</legend>
@@ -252,7 +257,6 @@
<audio id="quatuorSound" src="sounds/BRRDC1.wav" preload="auto" type="audio/wav"></audio> <audio id="quatuorSound" src="sounds/BRRDC1.wav" preload="auto" type="audio/wav"></audio>
</span> </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/game_logic.js" language="Javascript" type="text/javascript"></script>
<script src="js/interface.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> <script src="js/app.js" language="Javascript" type="text/javascript"></script>

371
js/app.js
View File

@@ -1,130 +1,128 @@
let scheduler = new Scheduler() let scheduler = new Scheduler();
let settings = new Settings() let settings = new Settings();
let stats = new Stats() let stats = new Stats();
let holdQueue = new HoldQueue() let holdQueue = new HoldQueue();
let matrix = new Matrix() let matrix = new Matrix();
let nextQueue = new NextQueue() let nextQueue = new NextQueue();
let playing = false let playing = false;
//let lastActionSucceded = true //let lastActionSucceded = true
let favicon let favicon;
window.onload = function(event) { window.onload = function (event) {
document.selectedStyleSheetSet = selectedStyleSheet.title favicon = document.querySelector("link[rel~='icon']");
selectedStyleSheet.href = stylesheetSelect.value
favicon = document.querySelector("link[rel~='icon']")
fullscreenCheckbox.onchange = function() { fullscreenCheckbox.onchange = function () {
if (this.checked) { if (this.checked) {
document.documentElement.requestFullscreen() document.documentElement.requestFullscreen();
} else { } else {
document.exitFullscreen() document.exitFullscreen();
}
} }
};
restart() restart();
} };
document.onfullscreenchange = function() { document.onfullscreenchange = function () {
if (document.fullscreenElement) { if (document.fullscreenElement) {
fullscreenCheckbox.checked = true fullscreenCheckbox.checked = true;
} else { } else {
fullscreenCheckbox.checked = false fullscreenCheckbox.checked = false;
if (playing) pauseSettings() if (playing) pauseSettings();
} }
} };
document.onfullscreenerror = function() { document.onfullscreenerror = function () {
fullscreenCheckbox.checked = false fullscreenCheckbox.checked = false;
} };
function restart() { function restart() {
stats.modal.hide() stats.modal.hide();
holdQueue.init() holdQueue.init();
holdQueue.redraw() holdQueue.redraw();
stats.init() stats.init();
matrix.init() matrix.init();
nextQueue.init() nextQueue.init();
settings.init() settings.init();
pauseSettings() pauseSettings();
} }
function pauseSettings() { function pauseSettings() {
scheduler.clearInterval(fall) scheduler.clearInterval(fall);
scheduler.clearTimeout(lockDown) scheduler.clearTimeout(lockDown);
scheduler.clearTimeout(repeat) scheduler.clearTimeout(repeat);
scheduler.clearInterval(autorepeat) scheduler.clearInterval(autorepeat);
scheduler.clearInterval(ticktack) scheduler.clearInterval(ticktack);
stats.pauseTime = stats.time stats.pauseTime = stats.time;
document.onkeydown = null document.onkeydown = null;
settings.show() settings.show();
} }
function newGame(event) { function newGame(event) {
if (!settings.form.checkValidity()) { if (!settings.form.checkValidity()) {
event.preventDefault() event.preventDefault();
event.stopPropagation() event.stopPropagation();
settings.form.reportValidity() settings.form.reportValidity();
settings.form.classList.add('was-validated') settings.form.classList.add('was-validated');
} else { } else {
const audioContext = new AudioContext() const audioContext = new AudioContext();
for(const sound of document.getElementsByTagName("audio")) { for (const sound of document.getElementsByTagName('audio')) {
sound.preservesPitch = false sound.preservesPitch = false;
audioContext.createMediaElementSource(sound).connect(audioContext.destination) audioContext.createMediaElementSource(sound).connect(audioContext.destination);
} }
levelInput.name = "level" levelInput.name = 'level';
levelInput.disabled = true levelInput.disabled = true;
titleHeader.innerHTML = "PAUSE" titleHeader.innerHTML = 'PAUSE';
resumeButton.innerHTML = "Reprendre" resumeButton.innerHTML = 'Reprendre';
event.target.onsubmit = resume event.target.onsubmit = resume;
stats.level = levelInput.valueAsNumber stats.level = levelInput.valueAsNumber;
localStorage["startLevel"] = levelInput.value localStorage['startLevel'] = levelInput.value;
playing = true playing = true;
onblur = pauseSettings onblur = pauseSettings;
resume(event) resume(event);
} }
} }
function resume(event) { function resume(event) {
event.preventDefault() event.preventDefault();
event.stopPropagation() event.stopPropagation();
settings.form.reportValidity() settings.form.reportValidity();
settings.form.classList.add('was-validated') settings.form.classList.add('was-validated');
if (settings.form.checkValidity()) { if (settings.form.checkValidity()) {
for(const sound of document.getElementsByTagName("audio")) for (const sound of document.getElementsByTagName('audio'))
sound.volume = sfxVolumeRange.value sound.volume = sfxVolumeRange.value;
settings.modal.hide() settings.modal.hide();
settings.getInputs() settings.getInputs();
document.onkeydown = onkeydown document.onkeydown = onkeydown;
document.onkeyup = onkeyup document.onkeyup = onkeyup;
stats.time = stats.pauseTime stats.time = stats.pauseTime;
scheduler.setInterval(ticktack, 1000) scheduler.setInterval(ticktack, 1000);
if (matrix.piece) scheduler.setInterval(fall, stats.fallPeriod) if (matrix.piece) scheduler.setInterval(fall, stats.fallPeriod);
else generate() else generate();
} }
} }
function ticktack() { function ticktack() {
timeCell.innerText = stats.timeFormat.format(stats.time) timeCell.innerText = stats.timeFormat.format(stats.time);
} }
function generate(piece) { function generate(piece) {
matrix.piece = piece || nextQueue.shift() matrix.piece = piece || nextQueue.shift();
if (!piece && holdQueue.piece) holdQueue.drawPiece() if (!piece && holdQueue.piece) holdQueue.drawPiece();
//lastActionSucceded = true //lastActionSucceded = true
favicon.href = matrix.piece.favicon_href favicon.href = matrix.piece.favicon_href;
if (matrix.piece.canMove(TRANSLATION.NONE)) { if (matrix.piece.canMove(TRANSLATION.NONE)) {
scheduler.setInterval(fall, stats.fallPeriod) scheduler.setInterval(fall, stats.fallPeriod);
} else { } else {
gameOver() // block out gameOver(); // block out
} }
} }
@@ -139,72 +137,73 @@ let playerActions = {
softDrop: () => matrix.piece.move(TRANSLATION.DOWN) && ++stats.score, softDrop: () => matrix.piece.move(TRANSLATION.DOWN) && ++stats.score,
hardDrop: function() { hardDrop: function () {
scheduler.clearTimeout(lockDown) scheduler.clearTimeout(lockDown);
playSound(hardDropSound) playSound(hardDropSound);
while (matrix.piece.move(TRANSLATION.DOWN, ROTATION.NONE, true)) stats.score += 2 while (matrix.piece.move(TRANSLATION.DOWN, ROTATION.NONE, true)) stats.score += 2;
matrixCard.classList.remove("hard-dropped-table-animation") matrixCard.classList.remove('hard-dropped-table-animation');
matrixCard.offsetHeight; matrixCard.offsetHeight;
matrixCard.classList.add("hard-dropped-table-animation") // restart animation matrixCard.classList.add('hard-dropped-table-animation'); // restart animation
lockDown() lockDown();
return true return true;
}, },
hold: function() { hold: function () {
if (matrix.piece.holdEnabled) { if (matrix.piece.holdEnabled) {
scheduler.clearInterval(fall) scheduler.clearInterval(fall);
scheduler.clearTimeout(lockDown) scheduler.clearTimeout(lockDown);
let piece = matrix.piece let piece = matrix.piece;
piece.facing = FACING.NORTH piece.facing = FACING.NORTH;
piece.locked = false piece.locked = false;
generate(holdQueue.piece) generate(holdQueue.piece);
matrix.piece.holdEnabled = false matrix.piece.holdEnabled = false;
holdQueue.piece = piece holdQueue.piece = piece;
} }
}, },
pause: pauseSettings, pause: pauseSettings,
} };
// Handle player inputs // Handle player inputs
const REPEATABLE_ACTIONS = [ const REPEATABLE_ACTIONS = [
playerActions.moveLeft, playerActions.moveLeft,
playerActions.moveRight, playerActions.moveRight,
playerActions.softDrop playerActions.softDrop,
] ];
pressedKeys = new Set() pressedKeys = new Set();
actionsQueue = [] actionsQueue = [];
function onkeydown(event) { function onkeydown(event) {
if (event.key in settings.keyBind) { if (event.key in settings.keyBind) {
event.preventDefault() event.preventDefault();
if (!pressedKeys.has(event.key)) { if (!pressedKeys.has(event.key)) {
pressedKeys.add(event.key) pressedKeys.add(event.key);
action = settings.keyBind[event.key] action = settings.keyBind[event.key];
/*if (action()) { /*if (action()) {
lastActionSucceded = true lastActionSucceded = true
} else if (lastActionSucceded || !(action in REPEATABLE_ACTIONS)) { } else if (lastActionSucceded || !(action in REPEATABLE_ACTIONS)) {
playSound(wallSound) playSound(wallSound)
lastActionSucceded = false lastActionSucceded = false
}*/ }*/
action() action();
if (REPEATABLE_ACTIONS.includes(action)) { if (REPEATABLE_ACTIONS.includes(action)) {
actionsQueue.unshift(action) actionsQueue.unshift(action);
scheduler.clearTimeout(repeat) scheduler.clearTimeout(repeat);
scheduler.clearInterval(autorepeat) scheduler.clearInterval(autorepeat);
if (action == playerActions.softDrop) scheduler.setInterval(autorepeat, settings.fallPeriod/20) if (action == playerActions.softDrop)
else scheduler.setTimeout(repeat, settings.das) scheduler.setInterval(autorepeat, settings.fallPeriod / 20);
else scheduler.setTimeout(repeat, settings.das);
} }
matrix.drawPiece() matrix.drawPiece();
} }
} }
} }
function repeat() { function repeat() {
if (actionsQueue.length) { if (actionsQueue.length) {
actionsQueue[0]() actionsQueue[0]();
scheduler.setInterval(autorepeat, settings.arr) scheduler.setInterval(autorepeat, settings.arr);
} }
} }
@@ -216,121 +215,121 @@ function autorepeat() {
wallSound.play() wallSound.play()
lastActionSucceded = false lastActionSucceded = false
}*/ }*/
actionsQueue[0]() actionsQueue[0]();
} } else scheduler.clearInterval(autorepeat);
else scheduler.clearInterval(autorepeat)
} }
function onkeyup(event) { function onkeyup(event) {
if (event.key in settings.keyBind) { if (event.key in settings.keyBind) {
event.preventDefault() event.preventDefault();
pressedKeys.delete(event.key) pressedKeys.delete(event.key);
action = settings.keyBind[event.key] action = settings.keyBind[event.key];
if (actionsQueue.includes(action)) { if (actionsQueue.includes(action)) {
actionsQueue.splice(actionsQueue.indexOf(action), 1) actionsQueue.splice(actionsQueue.indexOf(action), 1);
scheduler.clearTimeout(repeat) scheduler.clearTimeout(repeat);
scheduler.clearInterval(autorepeat) scheduler.clearInterval(autorepeat);
if (actionsQueue.length) { if (actionsQueue.length) {
if (actionsQueue[0] == playerActions.softDrop) scheduler.setInterval(autorepeat, settings.fallPeriod/20) if (actionsQueue[0] == playerActions.softDrop)
else scheduler.setTimeout(repeat, settings.das) scheduler.setInterval(autorepeat, settings.fallPeriod / 20);
else scheduler.setTimeout(repeat, settings.das);
} else { } else {
matrix.drawPiece() matrix.drawPiece();
} }
} }
} }
} }
function fall() { function fall() {
matrix.piece.move(TRANSLATION.DOWN) matrix.piece.move(TRANSLATION.DOWN);
} }
function lockDown() { function lockDown() {
scheduler.clearTimeout(lockDown) scheduler.clearTimeout(lockDown);
scheduler.clearInterval(fall) scheduler.clearInterval(fall);
if (matrix.lock()) { if (matrix.lock()) {
stats.lockDown(matrix.piece.tSpin, matrix.clearLines()) stats.lockDown(matrix.piece.tSpin, matrix.clearLines());
generate() generate();
} else { } else {
gameOver() // lock out gameOver(); // lock out
} }
} }
onanimationend = function (event) { onanimationend = function (event) {
event.target.classList.remove(event.animationName) event.target.classList.remove(event.animationName);
} };
messagesSpan.onanimationend = function(event) { messagesSpan.onanimationend = function (event) {
event.target.remove() event.target.remove();
} };
function gameOver() { function gameOver() {
matrix.piece.locked = true matrix.piece.locked = true;
matrix.drawPiece() matrix.drawPiece();
document.onkeydown = null document.onkeydown = null;
onblur = null onblur = null;
scheduler.clearInterval(ticktack) scheduler.clearInterval(ticktack);
playing = false playing = false;
stats.show() stats.show();
} }
window.onbeforeunload = function(event) { window.onbeforeunload = function (event) {
stats.save() stats.save();
settings.save() settings.save();
if (playing) return false; if (playing) return false;
} };
// Play with 3D // Play with 3D
let mousedown = false let mousedown = false;
let rX0 = -15 let rX0 = -15;
let rY0 = 0 let rY0 = 0;
let clientX0 = 0 let clientX0 = 0;
let clientY0 = 0 let clientY0 = 0;
sceneDiv.onmousedown = function(event) { sceneDiv.onmousedown = function (event) {
mousedown = true mousedown = true;
rX0 = parseInt(getComputedStyle(screenRow).getPropertyValue("--rX")) rX0 = parseInt(getComputedStyle(screenRow).getPropertyValue('--rX'));
dy0 = parseInt(getComputedStyle(screenRow).getPropertyValue("--rY")) dy0 = parseInt(getComputedStyle(screenRow).getPropertyValue('--rY'));
clientX0 = event.clientX clientX0 = event.clientX;
clientY0 = event.clientY clientY0 = event.clientY;
} };
sceneDiv.onmousemove = function(event) { sceneDiv.onmousemove = function (event) {
if (mousedown) { if (mousedown) {
event.preventDefault() event.preventDefault();
event.stopPropagation() event.stopPropagation();
rX = (rX0 - 0.5 * (event.clientY - clientY0)) % 360 rX = (rX0 - 0.5 * (event.clientY - clientY0)) % 360;
screenRow.style.setProperty("--rX", rX) screenRow.style.setProperty('--rX', rX);
if (rX >= 0) { if (rX >= 0) {
screenRow.classList.remove("top") screenRow.classList.remove('top');
screenRow.classList.add("bottom") screenRow.classList.add('bottom');
} else { } else {
screenRow.classList.add("top") screenRow.classList.add('top');
screenRow.classList.remove("bottom") screenRow.classList.remove('bottom');
} }
rY = (rY0 + 0.5 * (event.clientX - clientX0)) % 360 rY = (rY0 + 0.5 * (event.clientX - clientX0)) % 360;
screenRow.style.setProperty("--rY", rY) screenRow.style.setProperty('--rY', rY);
if (rY <= 0) { if (rY <= 0) {
screenRow.classList.remove("left") screenRow.classList.remove('left');
screenRow.classList.add("right") screenRow.classList.add('right');
} else { } else {
screenRow.classList.add("left") screenRow.classList.add('left');
screenRow.classList.remove("right") screenRow.classList.remove('right');
} }
} }
} };
sceneDiv.onmouseup = document.onmouseleave = function(event) { sceneDiv.onmouseup = document.onmouseleave = function (event) {
mousedown = false mousedown = false;
} };
sceneDiv.onwheel = function(event) { sceneDiv.onwheel = function (event) {
event.preventDefault() event.preventDefault();
event.stopPropagation() event.stopPropagation();
let tZ = parseInt(getComputedStyle(screenRow).getPropertyValue("--tZ")) let tZ = parseInt(getComputedStyle(screenRow).getPropertyValue('--tZ'));
tZ -= event.deltaY tZ -= event.deltaY;
screenRow.style.setProperty("--tZ", tZ + "px") screenRow.style.setProperty('--tZ', tZ + 'px');
} };

View File

@@ -35,13 +35,56 @@ class Settings {
if (element.name in localStorage) if (element.name in localStorage)
element.value = localStorage[element.name] element.value = localStorage[element.name]
}) })
window.document.selectedStyleSheetSet = stylesheetSelect.value selectedStyleSheet.href = stylesheetSelect.value
if (stylesheetSelect.value === "css/tetrio-skin.css" || stylesheetSelect.value === "css/jstris-skin.css") { if (stylesheetSelect.value === "css/tetrio-skin.css" || stylesheetSelect.value === "css/jstris-skin.css") {
skinURLdiv.style.setProperty('display', 'flex') skinURLdiv.style.setProperty('display', 'flex')
document.documentElement.style.setProperty('--skin-url', `url(${skinURLInput.value})`)
} else { } else {
skinURLdiv.style.setProperty('display', 'none') skinURLdiv.style.setProperty('display', 'none')
} }
fetch('https://konsola5.github.io/jstris-customization-database/jstrisCustomizationDatabase.json')
.then(response => response.json())
.then(json => {
for (const group in json) {
const optgroup = document.createElement('optgroup');
optgroup.label = group;
json[group].forEach(skin => {
const option = document.createElement('option');
option.value = skin.link;
option.textContent = `${skin.name} (${skin.author})`;
optgroup.appendChild(option);
});
skinURLInput.appendChild(optgroup);
}
$('#skinURLInput').select2({
templateResult: state => state.id ? $(`<span class="option result" style="--skin-url: url(${state.id})" title="${state.text}"></span>`): state.text,
templateSelection: state => state.id ? $(`<span class="option selection" style="--skin-url: url(${state.id})" title="${state.text}"></span>`): state.text,
theme: 'bootstrap-5',
width: '100%',
selectionCssClass: 'form-select',
dropdownAutoWidth: true,
dropdownParent: $('#settingsModal'),
placeholder: "URL de l'image",
tags: true,
createTag: function(params) {
return {
id: params.term,
text: "Ajouté manuellement",
newTag: true
};
},
})
if (localStorage["skinURL"]) {
if ($('#skinURLInput').find("option[value='" + localStorage["skinURL"] + "']").length) {
$('#skinURLInput').val(localStorage["skinURL"]).trigger('change');
} else {
var option = new Option(localStorage["skinURL"], "Ajouté manuellement", localStorage["skinURL"], true, true);
$('#skinURLInput').append(option).trigger('change');
}
document.documentElement.style.setProperty('--skin-url', `url(${localStorage["skinURL"]})`)
}
});
} }
save() { save() {

File diff suppressed because it is too large Load Diff