<!-- GM02 - Модификация для Тильды. Игра "Memory" в стиле Игры в кальмара https://mod.tistols.com/memory-squid -->
<!-- Все стили и SVG для заливки -->
<style>
:root { --pathBg:#FF0000 }
.shape-overlays { width: 100vw; height: 100vh; pointer-events: none; position: fixed; top: 0; left: 0; z-index: 1; opacity: 0; transition: opacity 0.5s; }
.shape-overlays .shape-overlays__path { fill: var(--pathBg) }
.shape-overlays__blue { width: 100vw; height: 100vh; pointer-events: none; position: absolute; top: 0; left: 0 }
.hidden { opacity: 0; pointer-events: none; transition: opacity 1.5s ease; }
.visible { opacity: 1; pointer-events: auto; transition: opacity 1.5s ease; }
.closepopup { cursor: pointer; transition: transform 0.2s ease, opacity 0.2s ease; }
.closepopup:hover { transform: scale(1.1); opacity: 0.8; }
.flip-card { width: 100%; height: 100%; perspective: 1000px; position: absolute; top: 0; left: 0; }
.flip-card-inner { position: relative; width: 100%; height: 100%; transition: transform 0.6s; transform-style: preserve-3d; cursor: pointer; }
.flip-card-front, .flip-card-back { position: absolute; width: 100%; height: 100%; backface-visibility: hidden; border-radius: 10px; display: flex; align-items: center; justify-content: center; font-family: Arial, sans-serif; color: white; }
.flip-card-front { background-size: cover; background-position: center; }
.flip-card-front p { margin-top: auto; margin-bottom: 20px; }
.flip-card-back { background-size: cover; transform: rotateY(180deg); text-align: center; }
.flip-card-back p { max-width: 90% }
.flip-card.flipped .flip-card-inner { transform: rotateY(180deg); }
.uc-succes,
.uc-lose {
display: none;
}
.textlose {
position: fixed;
z-index: 1000!important;
}
</style>
<svg class="shape-overlays" viewBox="0 0 100 100" preserveAspectRatio="none" style="position:fixed;top:0;left:0;z-index:999;"><path class="shape-overlays__path" d="M 0 0 V 100 C 10 100 10 100 20 100 C 30 100 30 100 40 100 C 50 100 50 100 60 100 C 70 100 70 100 80 100 C 90 100 90 100 100 100 V 0 H 0"></path></svg>
<script>
/* === КОНСТАНТЫ === */
const LOCAL_TIMER_DURATION = 25 * 1000; // 25 сек на игру (замените на 60*1000 для 1 мин)
const LS_KEY = 'uc-banner-timer-start';
let timerFinished = false;
let gameWon = false;
function getStartTime() {
let start = localStorage.getItem(LS_KEY);
if (!start) {
start = Date.now();
localStorage.setItem(LS_KEY, start);
}
return parseInt(start, 10);
}
function resetStartTime() {
const now = Date.now();
localStorage.setItem(LS_KEY, now);
return now;
}
/* === ТАЙМЕР === */
function updateLocalTimer() {
const startTime = getStartTime();
const now = Date.now();
let diff = LOCAL_TIMER_DURATION - (now - startTime);
if (diff <= 0 && !timerFinished) {
timerFinished = true;
clearInterval(localTimerInterval);
// Если игра не выиграна — показать провал
if (!gameWon) {
showFailureState();
}
// Скрыть баннер
const zeroBlock = document.querySelector('.uc-tistols-banner');
if (zeroBlock) {
zeroBlock.classList.remove('visible');
zeroBlock.classList.add('hidden');
}
return;
}
// Выводим оставшееся время (если нужно)
const seconds = Math.max(0, Math.floor(diff / 1000));
const minElem = document.querySelector('.tmin .tn-atom');
const secElem = document.querySelector('.tsec .tn-atom');
if (minElem) minElem.textContent = Math.floor(seconds / 60);
if (secElem) secElem.textContent = seconds % 60;
}
// При первой загрузке страницы и каждом обновлении — сбрасываем таймер
resetStartTime();
const localTimerInterval = setInterval(updateLocalTimer, 1000);
/* === ИГРА MEMORY === */
$(window).on('load', function () {
let flippedCards = [];
let matchedCards = [];
const totalCards = $('.flip-card').length;
function flipCard($card) {
if (flippedCards.length < 2 && !flippedCards.includes($card[0]) && !matchedCards.includes($card[0])) {
$card.addClass('flipped');
flippedCards.push($card[0]);
if (flippedCards.length === 2) {
checkForMatch();
}
}
}
function checkForMatch() {
const [card1, card2] = flippedCards;
const card1Type = $(card1).data('card');
const card2Type = $(card2).data('card');
if (card1Type === card2Type) {
matchedCards.push(card1, card2);
flippedCards = [];
// Проверка, все ли карточки угаданы
if (matchedCards.length === totalCards) {
onGameSuccess();
}
} else {
setTimeout(() => {
$(card1).removeClass('flipped');
$(card2).removeClass('flipped');
flippedCards = [];
}, 1000);
}
}
function shuffleElements() {
const $molecule = $('.flip-board .tn-molecule');
if (!$molecule.length) return;
const $elements = $molecule.children().toArray();
$elements.sort(() => Math.random() - 0.5);
$molecule.empty().append($elements);
}
shuffleElements();
$(document).on('click', '.flip-card', function () {
if (!timerFinished && !gameWon)
flipCard($(this));
});
});
/* === УСПЕХ: игра пройдена === */
function onGameSuccess() {
gameWon = true;
// Скрыть блок игры
const gameBlock = document.querySelector('.uc-game');
if (gameBlock) gameBlock.style.display = 'none';
// Показать блок успеха
const successBlock = document.querySelector('.uc-succes');
if (successBlock) successBlock.style.display = 'block';
// Отключить открытие попапа (если есть)
const popupTrigger = document.querySelector('.flipсhik');
if (popupTrigger) {
popupTrigger.onclick = function(e){ e.stopPropagation(); return false; };
popupTrigger.style.pointerEvents = 'none';
}
// Скрыть баннер (если нужен этот эффект)
const zeroBlock = document.querySelector('.uc-tistols-banner');
if (zeroBlock) {
zeroBlock.classList.remove('visible');
zeroBlock.classList.add('hidden');
}
}
/* === ПРОВАЛ: время вышло === */
function showFailureState() {
// Скрыть блок игры
const gameBlock = document.querySelector('.uc-game');
if (gameBlock) gameBlock.style.display = 'none';
// Показать блок "lose"
const loseBlock = document.querySelector('.uc-lose');
if (loseBlock) loseBlock.style.display = 'block';
// Запустить анимацию заливки
runFillAnimation();
}
/* === АНИМАЦИЯ ЗАЛИВКИ === */
function runFillAnimation() {
// Класс-аниматор (из вашего кода)
const DURATION = 2400;
const DELAY_POINTS_MAX = 1160;
const DELAY_PER_PATH = 340;
const points = 6;
class J {
constructor(e) {
this.elm = e;
this.path = e.querySelectorAll(".shape-overlays path");
this.numPoints = points;
this.duration = DURATION;
this.delayPointsArray = [];
this.delayPointsMax = DELAY_POINTS_MAX;
this.delayPerPath = DELAY_PER_PATH;
this.timeStart = Date.now();
this.isOpened = false;
this.isAnimating = false;
}
toggle() {
this.isAnimating = true;
const t = Math.random() * Math.PI * 2;
for (let e = 0; e < this.numPoints; e++) {
const n = e / (this.numPoints - 1) * Math.PI * 2;
this.delayPointsArray[e] = (Math.sin(n + t) + 1) / 2 * this.delayPointsMax;
}
!this.isOpened ? this.open() : this.close();
}
open() {
this.isOpened = true;
this.elm.classList.add("is-opened");
this.timeStart = Date.now();
this.renderLoop();
}
close() {
this.isOpened = false;
this.elm.classList.remove("is-opened");
this.timeStart = Date.now();
this.renderLoop();
}
updatePath(t) {
const e = [];
for (let n = 0; n < this.numPoints; n++) {
e[n] = 100 * this.constructor.cubicInOut(Math.min(Math.max(t - this.delayPointsArray[n], 0) / this.duration, 1));
}
let i = "";
i += this.isOpened ? "M 0 0 V " + e[0] + " " : "M 0 " + e[0] + " ";
for (let r = 0; r < this.numPoints - 1; r++) {
const a = (r + 1) / (this.numPoints - 1) * 100;
const o = a - 1 / (this.numPoints - 1) * 100 / 2;
i += "C " + o + " " + e[r] + " " + o + " " + e[r + 1] + " " + a + " " + e[r + 1] + " ";
}
return i += this.isOpened ? "V 0 H 0" : "V 100 H 0";
}
render() {
if (this.isOpened) {
for (let t = 0; t < this.path.length; t++) {
this.path[t].setAttribute("d", this.updatePath(Date.now() - (this.timeStart + this.delayPerPath * t)));
}
} else {
for (let e = 0; e < this.path.length; e++) {
this.path[e].setAttribute("d", this.updatePath(Date.now() - (this.timeStart + this.delayPerPath * (this.path.length - e - 1))));
}
}
}
renderLoop() {
this.render();
if (Date.now() - this.timeStart < this.duration + this.delayPerPath * (this.path.length - 1) + this.delayPointsMax) {
requestAnimationFrame(() => this.renderLoop());
} else {
this.isAnimating = false;
}
}
static cubicInOut(t) {
return t < 0.5 ? 4 * t * t * t : 0.5 * Math.pow(2 * t - 2, 3) + 1;
}
}
// Запуск
const svgElement = document.querySelector(".shape-overlays");
if (svgElement) {
svgElement.style.opacity = 1;
if (!svgElement.jInstance) {
svgElement.jInstance = new J(svgElement);
}
if (!svgElement.jInstance.isAnimating) {
svgElement.jInstance.toggle();
}
}
}
</script>