improve jstris skin
This commit is contained in:
@@ -11,6 +11,7 @@
|
||||
background-image: var(--skin-url);
|
||||
background-size: cover;
|
||||
background-repeat: no-repeat;
|
||||
vertical-align: middle;
|
||||
}
|
||||
|
||||
.result {
|
||||
@@ -20,7 +21,7 @@
|
||||
.selection {
|
||||
background-position-x: calc(-1 * var(--sprite-pos) * var(--cell-size));
|
||||
--nb-sprites: 4;
|
||||
--sprite-pos: 3;
|
||||
--sprite-pos: 4;
|
||||
}
|
||||
|
||||
.minoes-table {
|
||||
@@ -30,8 +31,7 @@
|
||||
#matrixCard {
|
||||
background-image: url(jstris-skin/jstris-grid.png);
|
||||
background-position: bottom;
|
||||
background-repeat: no-repeat;
|
||||
background-blend-mode: screen;
|
||||
background-repeat: no-repeat;
|
||||
}
|
||||
|
||||
tr.matrix td:not(.mino) {
|
||||
@@ -76,13 +76,19 @@ tr.matrix td:not(.mino) {
|
||||
}
|
||||
|
||||
.ghost {
|
||||
--sprite-pos: 0;
|
||||
--sprite-pos: 1;
|
||||
opacity: 50%;
|
||||
}
|
||||
|
||||
.disabled {
|
||||
--sprite-pos: 1;
|
||||
--sprite-pos: 0;
|
||||
}
|
||||
|
||||
.locking.mino {
|
||||
filter: saturate(60%) brightness(180%);
|
||||
}
|
||||
|
||||
#holdTable .mino,
|
||||
#nextTable .mino {
|
||||
box-shadow: 4px 4px 10px #0002;
|
||||
}
|
||||
33
index.html
33
index.html
@@ -76,19 +76,10 @@
|
||||
<label for="dasInput" class="col-2 col-form-label"><abbr title="Delayed AutoShift : délai initial avant répétition">DAS</abbr></label>
|
||||
</fieldset>
|
||||
<fieldset class="row g-2 mb-3 align-items-center text-center"><legend class="text-start">Interface</legend>
|
||||
<label for="sfxVolumeRange" class="col-2 col-form-label">Volume</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>
|
||||
<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; skinURLdiv.style.setProperty('display', this.value === 'css/tetrio-skin.css' || this.value === 'css/jstris-skin.css' ? 'flex' : 'none')">
|
||||
oninput="selectedStyleSheet.href = this.value; skinURLSelect.disabled = this.value !== 'css/jstris-skin.css';">
|
||||
<option value="css/classic.css" selected>Classique</option>
|
||||
<option value="css/neo-classic.css" selected>Néo-classique</option>
|
||||
<option value="css/synthwave.css">Synthwave</option>
|
||||
@@ -100,15 +91,21 @@
|
||||
<option value="css/jstris-skin.css">Sample...</option>
|
||||
</select>
|
||||
</div>
|
||||
<div id="skinURLdiv" class="col-6" style="display: none;">
|
||||
<div class="col-8">
|
||||
<select name="skinURL" id="skinURLInput" class="form-select" value="https://i.imgur.com/0l7LFMT.png"
|
||||
oninput="document.documentElement.style.setProperty('--skin-url', `url(${this.value})`)">
|
||||
</select>
|
||||
</script>
|
||||
</div>
|
||||
<label for="skinURLInput" class="col-4 col-form-label">Sample</label>
|
||||
<div class="col-4">
|
||||
<select name="skinURL" id="skinURLSelect" class="form-select" disabled
|
||||
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">Volume</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>
|
||||
|
||||
520
js/interface.js
520
js/interface.js
@@ -1,384 +1,404 @@
|
||||
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]
|
||||
})
|
||||
selectedStyleSheet.href = stylesheetSelect.value
|
||||
if (stylesheetSelect.value === "css/tetrio-skin.css" || stylesheetSelect.value === "css/jstris-skin.css") {
|
||||
skinURLdiv.style.setProperty('display', 'flex')
|
||||
} else {
|
||||
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"]})`)
|
||||
}
|
||||
this.form.querySelectorAll('[name]').forEach(element => {
|
||||
if (element.name in localStorage) element.value = localStorage[element.name];
|
||||
});
|
||||
selectedStyleSheet.href = stylesheetSelect.value;
|
||||
skinURLSelect.disabled = stylesheetSelect.value !== 'css/jstris-skin.css';
|
||||
|
||||
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);
|
||||
});
|
||||
skinURLSelect.appendChild(optgroup);
|
||||
}
|
||||
|
||||
$('#skinURLSelect').select2({
|
||||
templateResult: state =>
|
||||
state.id
|
||||
? $(`<img class="option result" src="${state.id}" title="${state.text}" loading="lazy"/>`)
|
||||
: state.text,
|
||||
templateSelection: state =>
|
||||
state.id
|
||||
? $(`<span class="option selection" style="--skin-url: url(${state.id})" title="${state.text}" loading="lazy"></span>`)
|
||||
: state.text,
|
||||
theme: 'bootstrap-5',
|
||||
width: '100%',
|
||||
selectionCssClass: 'form-select',
|
||||
dropdownAutoWidth: true,
|
||||
dropdownParent: $('#settingsModal'),
|
||||
placeholder: "URL de l'image",
|
||||
tags: true,
|
||||
});
|
||||
if (localStorage['skinURL']) {
|
||||
if (
|
||||
$('#skinURLSelect').find("option[value='" + localStorage['skinURL'] + "']")
|
||||
.length
|
||||
) {
|
||||
$('#skinURLSelect').val(localStorage['skinURL']).trigger('change');
|
||||
} else {
|
||||
var option = new Option(
|
||||
localStorage['skinURL'],
|
||||
'Ajouté manuellement',
|
||||
localStorage['skinURL'],
|
||||
true,
|
||||
true,
|
||||
);
|
||||
$('#skinURLSelect').append(option).trigger('change');
|
||||
}
|
||||
document.documentElement.style.setProperty(
|
||||
'--skin-url',
|
||||
`url(${localStorage['skinURL']})`,
|
||||
);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
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 = 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;
|
||||
}
|
||||
|
||||
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++
|
||||
this.totalClearedLines += nbClearedLines;
|
||||
if (nbClearedLines == 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][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],
|
||||
});
|
||||
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++
|
||||
this.combo++;
|
||||
if (this.combo >= 1) {
|
||||
let comboScore = (nbClearedLines == 1 ? 20 : 50) * this.combo * this.level
|
||||
let comboScore = (nbClearedLines == 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
|
||||
this.combo = -1;
|
||||
}
|
||||
|
||||
// Back to back sequence
|
||||
if ((nbClearedLines == 4) || (tSpin && nbClearedLines)) {
|
||||
this.b2b++
|
||||
if (nbClearedLines == 4 || (tSpin && nbClearedLines)) {
|
||||
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 À 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 À 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 (nbClearedLines && !tSpin) {
|
||||
if (this.b2b >= 1) {
|
||||
messagesSpan.addNewChild("div", {
|
||||
className: "zoom-in-animation",
|
||||
style: "animation-delay: .4s",
|
||||
innerHTML: `FIN DU BOUT À BOUT`
|
||||
})
|
||||
messagesSpan.addNewChild('div', {
|
||||
className: 'zoom-in-animation',
|
||||
style: 'animation-delay: .4s',
|
||||
innerHTML: `FIN DU BOUT À BOUT`,
|
||||
});
|
||||
}
|
||||
this.b2b = -1
|
||||
this.b2b = -1;
|
||||
}
|
||||
|
||||
// Sound
|
||||
if (sfxVolumeRange.value) {
|
||||
if (nbClearedLines == 4) playSound(quatuorSound, this.combo)
|
||||
else if (nbClearedLines) playSound(lineClearSound, this.combo)
|
||||
if (tSpin) playSound(tSpinSound, this.combo)
|
||||
if (nbClearedLines == 4) playSound(quatuorSound, this.combo);
|
||||
else if (nbClearedLines) playSound(lineClearSound, this.combo);
|
||||
if (tSpin) playSound(tSpinSound, this.combo);
|
||||
}
|
||||
|
||||
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 = Math.pow(5 / 4, note);
|
||||
sound.play();
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user