// ==UserScript==
// @name TolyanHammerKombat
// @namespace http://tampermonkey.net/
// @version 4.6
// @description Игра поймай Толяна Хамстеркомбата
// @author Marina Khamsterkombat
// @match https://vk.com/*
// @icon https://i.imgur.com/9hJJv6a.png
// @grant none
// @license MIT
// @run-at document-idle
// ==/UserScript==
(function() {
'use strict';
// Настройки скрипта
const config = {
targets: ["356761121", "252323336", "1035510061", "1032968837", "1042305865", "1023730354", "867502146", "744130756", "649621677", "1047382637", "894118832"],
commentText: '🐹🐹🐹',
notice: {
text: '🚫🐹🔨 Попался, Хомяк! 🔨🐹🚫',
textColor: '#71AAEB',
threshold: 1.0
},
hammer: {
image: {
url: 'https://i.imgur.com/9hJJv6a.png',
size: { widthPx: 50, heightPx: 50 },
offset: { leftPx: 8, topPx: 40 }
},
sound: {
url: 'https://myinstants.com/media/sounds/fnaf-12-3-freddys-nose-sound.mp3',
volume: 0.1,
timeoutMs: 500,
},
animation: { durationMs: 200 }
},
attribute: {
name: 'data-hammerkombat',
hidden: 'hidden'
}
};
// Создает элемент уведомления
const createNotice = () => {
const notice = document.createElement('div');
notice.className = 'hammerkombat-notice';
const text = document.createElement('h2');
text.className = 'hammerkombat-notice-text';
text.textContent = config.notice.text;
notice.append(text);
return notice;
}
// Создает молоток в позиции клика
const createHammer = (x, y) => {
const { image } = config.hammer
const hammer = document.createElement('img');
hammer.className = 'hammerkombat-cursor';
hammer.src = image.url;
Object.assign(hammer.style, {
left: `${x - image.offset.leftPx}px`,
top: `${y - image.offset.topPx}px`,
width: `${image.size.widthPx}px`,
height: `${image.size.heightPx}px`
});
document.body.append(hammer);
return hammer;
}
// Воспроизводит звук удара
const playSound = () => {
const { sound } = config.hammer
const audio = new Audio(sound.url);
audio.volume = sound.volume;
audio.play().catch(() => {});
setTimeout(() => audio.remove(), sound.timeoutMs);
}
// Настраивает обработчик клика на аватар
const setupAvatarClick = (element) => {
const avatar = element.querySelector('a.AvatarRich');
if (!avatar) return;
avatar.style.cursor = 'crosshair';
avatar.style.userSelect = 'none';
avatar.removeAttribute('href');
avatar.addEventListener('click', (event) => {
const hammer = createHammer(event.clientX, event.clientY);
setTimeout(() => hammer.remove(), config.hammer.animation.durationMs);
playSound();
});
}
// Проверяет автора поста/коммента
const handleAuthor = (element, field) => {
const authorId = element?.dataset?.[field];
if (!authorId) return false;
if (!config.targets.includes(authorId)) return false;
element.setAttribute(config.attribute.name, config.attribute.hidden);
return true;
};
// Заменяет содержание поста
const replacePostContent = (post) => {
const content = post.querySelector('div.wall_text');
if (!content) return;
content.style.setProperty('display', 'none');
content.before(createNotice());
};
// Проверяет и обрабатывает пост
const processPost = (post) => {
if (!handleAuthor(post, 'postAuthorId')) return;
// Заменяем содержание поста
replacePostContent(post);
// Настраиваем молоточек на аватарке
setupAvatarClick(post);
};
// Проверяет и обрабатывает комментарий
const processComment = (comment) => {
if (!handleAuthor(comment, 'answeringId')) return;
// Заменяем содержание комментария
const replyText = comment.querySelector('div.wall_reply_text');
if (replyText) replyText.textContent = config.commentText;
// Настраиваем молоточек на аватарке
setupAvatarClick(comment);
};
// Проверяет все посты и комментарии на странице
const checkContent = () => {
document.querySelectorAll(`.post:not([${config.attribute.name}])`).forEach(processPost);
document.querySelectorAll(`.replies_list div:not([${config.attribute.name}])`).forEach(processComment);
};
// Добавляет стили на страницу
const addStyles = () => {
const style = document.createElement('style');
style.type = 'text/css';
style.textContent = `
.hammerkombat-notice {
position: relative;
text-align: center;
padding: 16px;
margin-top: 8px;
}
.hammerkombat-notice-text {
color: ${config.notice.textColor};
font-weight: bold;
text-transform: uppercase;
user-select: none;
}
.hammerkombat-cursor {
position: fixed;
pointer-events: none;
transform-origin: bottom right;
animation: hammer-hit ${config.hammer.animation.durationMs}ms ease-out;
}
@keyframes hammer-hit {
0% { transform: rotate(0deg); }
50% { transform: rotate(-30deg); }
100% { transform: rotate(0deg); }
}
`;
document.head.append(style);
}
// Инициализация скрипта
function init() {
addStyles();
window.addEventListener('load', checkContent);
new MutationObserver(checkContent).observe(document.body, { childList: true, subtree: true });
}
// Запуск скрипта
init();
})();