[hideprofile][html]<!-- ТЕХНО-ЗМЕЙКА (ХЁЛЬВАНИЯ) v.6 - JSONP РЕЙТИНГ -->
<div id="hollvania-snake">
<div class="snake-header">
<h2>⚡ TECHNO-CYTE SERPENT ⚡</h2>
<div class="stats">
<div>ЗАРАЖЕНИЕ: <span id="currentScore">0</span></div>
<div>РЕКОРД: <span id="highScore">0</span></div>
</div>
</div>
<canvas id="snakeCanvas" width="400" height="400"></canvas>
<div class="button-panel">
<button id="startBtn">🐍 СТАРТ ИГРЫ</button>
<button id="gameOverBtn" disabled>💀 GAME OVER</button>
<button id="resetBtn" disabled>⟳ НОВАЯ ИГРА</button>
</div>
<div id="leaderboardBlock">
<h3>🏆 ПОСЛЕДНИЕ ОПЕРАТОРЫ 🏆</h3>
<div id="rssLeaderboard">Загрузка рейтинга...</div>
<div class="rssNote"><a href="https://warframe.f-rpg.me/export.php?type=rss&tid=30" target="_blank">📡 лента заражений</a></div>
</div>
</div>
<style>
#hollvania-snake {
max-width: 500px;
margin: 20px auto;
background: #202020;
border: 2px solid #4d6885;
border-radius: 16px;
padding: 20px;
font-family: 'Courier New', monospace;
text-align: center;
box-shadow: 0 0 15px rgba(77,104,133,0.5);
}
.snake-header h2 {
color: #ffc53a;
text-shadow: 0 0 4px #ffc53a;
margin: 0 0 10px;
}
.stats {
display: flex;
justify-content: space-between;
background: #2a2a2a;
padding: 8px 15px;
border-radius: 8px;
margin-bottom: 15px;
color: #ddd;
}
.stats span {
color: #ffc53a;
font-weight: bold;
font-size: 1.3rem;
}
canvas {
background: #0a0a0e;
border: 2px solid #4d6885;
border-radius: 8px;
box-shadow: 0 0 8px #4d6885;
}
.button-panel {
margin-top: 15px;
display: flex;
gap: 10px;
justify-content: center;
}
button {
background: #2a2a2a;
border: 1px solid #4d6885;
color: #ffc53a;
padding: 6px 15px;
border-radius: 30px;
cursor: pointer;
font-family: inherit;
font-weight: bold;
transition: 0.2s;
}
button:hover:not(:disabled) {
background: #584f67;
border-color: #ffc53a;
box-shadow: 0 0 6px #ffc53a;
}
button:disabled {
opacity: 0.5;
cursor: not-allowed;
}
#leaderboardBlock {
margin-top: 20px;
border-top: 1px solid #584f67;
padding-top: 12px;
}
#leaderboardBlock h3 {
color: #ffc53a;
font-size: 1rem;
margin-bottom: 8px;
}
.rss-item {
background: #1a1a1a;
margin: 6px 0;
padding: 6px 10px;
border-left: 3px solid #ffc53a;
text-align: left;
font-size: 0.8rem;
color: #ccc;
}
.rss-item strong {
color: #ffc53a;
}
.rssNote {
font-size: 0.7rem;
margin-top: 8px;
}
.rssNote a {
color: #4d6885;
text-decoration: none;
}
.game-message {
background: #2a2a2a;
color: #ffc53a;
padding: 4px 12px;
border-radius: 20px;
margin-top: 10px;
font-size: 0.75rem;
display: inline-block;
}
</style>
<script>
(function(){
// ---------- ИГРА ----------
const canvas = document.getElementById('snakeCanvas');
const ctx = canvas.getContext('2d');
const scoreSpan = document.getElementById('currentScore');
const highScoreSpan = document.getElementById('highScore');
const startBtn = document.getElementById('startBtn');
const gameOverBtn = document.getElementById('gameOverBtn');
const resetBtn = document.getElementById('resetBtn');
const GRID = 20;
const CELL = canvas.width / GRID;
let snake = [
{x: 10, y: 10},
{x: 9, y: 10},
{x: 8, y: 10},
{x: 7, y: 10}
];
let direction = 'RIGHT';
let nextDir = 'RIGHT';
let food = {x: 15, y: 10};
let score = 0;
let best = 0;
let gameActive = false;
let gameInterval = null;
try {
let saved = localStorage.getItem('snake_hollvania_best');
if(saved && !isNaN(parseInt(saved))) best = parseInt(saved);
highScoreSpan.innerText = best;
} catch(e) {}
function randomFood() {
let free = false;
let attempts = 0;
let newFood = null;
while(!free && attempts < 2000) {
let fx = Math.floor(Math.random() * GRID);
let fy = Math.floor(Math.random() * GRID);
if(!snake.some(s => s.x === fx && s.y === fy)) {
newFood = {x: fx, y: fy};
free = true;
}
attempts++;
}
if(!newFood) {
for(let i=0; i<GRID; i++) {
for(let j=0; j<GRID; j++) {
if(!snake.some(s => s.x === i && s.y === j)) {
newFood = {x: i, y: j};
break;
}
}
if(newFood) break;
}
}
food = newFood;
}
function draw() {
ctx.clearRect(0, 0, canvas.width, canvas.height);
ctx.strokeStyle = '#4d6885';
ctx.lineWidth = 0.5;
for(let i=0; i<=GRID; i++) {
ctx.beginPath();
ctx.moveTo(i*CELL, 0);
ctx.lineTo(i*CELL, canvas.height);
ctx.stroke();
ctx.moveTo(0, i*CELL);
ctx.lineTo(canvas.width, i*CELL);
ctx.stroke();
}
ctx.shadowBlur = 5;
ctx.shadowColor = '#ffc53a';
ctx.fillStyle = '#ffc53a';
ctx.beginPath();
ctx.arc(food.x*CELL + CELL/2, food.y*CELL + CELL/2, CELL/2-2, 0, Math.PI*2);
ctx.fill();
ctx.fillStyle = '#584f67';
ctx.beginPath();
ctx.arc(food.x*CELL + CELL/2, food.y*CELL + CELL/2, CELL/4, 0, Math.PI*2);
ctx.fill();
ctx.shadowBlur = 0;
for(let i=0; i<snake.length; i++) {
let s = snake[i];
let grad = ctx.createLinearGradient(s.x*CELL, s.y*CELL, (s.x+1)*CELL, (s.y+1)*CELL);
grad.addColorStop(0, '#4d6885');
grad.addColorStop(1, '#2c3e55');
ctx.fillStyle = grad;
ctx.fillRect(s.x*CELL, s.y*CELL, CELL-1, CELL-1);
if(i === 0) {
ctx.strokeStyle = '#ffc53a';
ctx.lineWidth = 2;
ctx.strokeRect(s.x*CELL, s.y*CELL, CELL-1, CELL-1);
}
}
let head = snake[0];
ctx.fillStyle = '#ff3333';
ctx.beginPath();
ctx.arc(head.x*CELL + CELL*0.7, head.y*CELL + CELL*0.3, 3, 0, Math.PI*2);
ctx.arc(head.x*CELL + CELL*0.3, head.y*CELL + CELL*0.3, 3, 0, Math.PI*2);
ctx.fill();
}
function updateScoreUI() {
scoreSpan.innerText = score;
if(score > best) {
best = score;
highScoreSpan.innerText = best;
localStorage.setItem('snake_hollvania_best', best);
}
}
function move() {
if(!gameActive) return;
direction = nextDir;
let newHead = {...snake[0]};
switch(direction) {
case 'RIGHT': newHead.x++; break;
case 'LEFT': newHead.x--; break;
case 'UP': newHead.y--; break;
case 'DOWN': newHead.y++; break;
}
let willEat = (newHead.x === food.x && newHead.y === food.y);
if(willEat) {
snake.unshift(newHead);
score++;
updateScoreUI();
randomFood();
if(snake.length === GRID*GRID) { gameOver(true); return; }
} else {
snake.unshift(newHead);
snake.pop();
}
let collision = (newHead.x<0 || newHead.x>=GRID || newHead.y<0 || newHead.y>=GRID);
if(!willEat) collision = collision || snake.slice(1).some(s => s.x === newHead.x && s.y === newHead.y);
if(collision) { gameOver(false); return; }
draw();
}
function gameOver(win) {
if(!gameActive) return;
gameActive = false;
if(gameInterval) clearInterval(gameInterval);
gameInterval = null;
let msg = document.createElement('div');
msg.className = 'game-message';
msg.innerText = win ? '☠️ ПОБЕДА? СБОЙ СИСТЕМЫ ☠️' : '☠️ ЗМЕЙ УНИЧТОЖЕН ☠️';
document.querySelector('.button-panel').after(msg);
setTimeout(() => msg.remove(), 3000);
gameOverBtn.disabled = false;
resetBtn.disabled = false;
startBtn.disabled = false;
window.lastSnakeScore = score;
}
function startGame() {
if(gameInterval) clearInterval(gameInterval);
snake = [
{x: 10, y: 10},
{x: 9, y: 10},
{x: 8, y: 10},
{x: 7, y: 10}
];
direction = 'RIGHT';
nextDir = 'RIGHT';
score = 0;
updateScoreUI();
randomFood();
gameActive = true;
draw();
gameInterval = setInterval(() => { move(); }, 150);
startBtn.disabled = true;
gameOverBtn.disabled = true;
resetBtn.disabled = true;
window.lastSnakeScore = 0;
}
function resetAndRestart() { startGame(); }
async function sendScoreToForum(scoreVal) {
if(scoreVal === undefined) { alert("Нет результата"); return; }
const message = `🐍 TECHNO-CYTE SERPENT: ${scoreVal} очков`;
const postKey = document.querySelector('input[name="my_post_key"]')?.value;
if(!postKey) { alert("Не удалось отправить, скопируйте: "+message); return; }
const tid = 30;
const form = new URLSearchParams();
form.append('my_post_key', postKey);
form.append('tid', tid);
form.append('message', message);
form.append('action', 'do_newreply');
try {
let res = await fetch('/newreply.php?tid='+tid, {
method: 'POST',
headers: { 'Content-Type': 'application/x-www-form-urlencoded' },
body: form,
credentials: 'same-origin'
});
if(res.ok) {
alert("Результат отправлен!");
loadLeaderboard();
} else alert("Ошибка отправки");
} catch(e) { alert("Ошибка сети"); }
}
// ---------- РЕЙТИНГ ЧЕРЕЗ JSONP (export.php?type=js) ----------
function loadLeaderboard() {
const container = document.getElementById('rssLeaderboard');
if(!container) return;
container.innerHTML = "Загрузка рейтинга...";
// Удаляем старый скрипт
const oldScript = document.getElementById('jsonp-script');
if(oldScript) oldScript.remove();
// Уникальное имя функции
const callbackName = 'jsonp_callback_' + Date.now() + '_' + Math.floor(Math.random()*100000);
window[callbackName] = function(data) {
delete window[callbackName];
if (!data || !Array.isArray(data) || data.length === 0) {
container.innerHTML = '<div class="rss-item">Нет сообщений</div>';
return;
}
let html = '';
let count = 0;
// Выводим последние 10 сообщений (первые в массиве — самые новые)
for (let i = 0; i < data.length && count < 10; i++) {
const item = data[i];
// Поля: author, subject, message, dateline (Unix timestamp)
const author = item.author || 'Аноним';
let title = item.subject || item.message;
if (title && title.length > 80) title = title.substring(0, 80) + '…';
const date = item.dateline ? new Date(item.dateline * 1000).toLocaleString() : '';
html += `<div class="rss-item"><strong>${escapeHtml(author)}</strong><br>${escapeHtml(title)}<br><small>${escapeHtml(date)}</small></div>`;
count++;
}
container.innerHTML = html;
};
const script = document.createElement('script');
script.id = 'jsonp-script';
script.src = `https://warframe.f-rpg.me/export.php?type=js&tid=30&callback=${callbackName}`;
script.onerror = function() {
delete window[callbackName];
container.innerHTML = '<div class="rss-item">Ошибка загрузки рейтинга</div>';
};
document.head.appendChild(script);
}
function escapeHtml(str) {
if(!str) return '';
return str.replace(/[&<>]/g, m => ({ '&':'&', '<':'<', '>':'>' }[m]));
}
window.addEventListener('load', () => {
loadLeaderboard();
setInterval(loadLeaderboard, 30000);
startBtn.addEventListener('click', startGame);
gameOverBtn.addEventListener('click', () => {
if(gameActive) {
gameActive = false;
if(gameInterval) clearInterval(gameInterval);
gameOver(false);
} else if(window.lastSnakeScore > 0) {
sendScoreToForum(window.lastSnakeScore);
} else {
alert("Сыграйте сначала");
}
});
resetBtn.addEventListener('click', resetAndRestart);
window.addEventListener('keydown', (e) => {
if(!gameActive) return;
let k = e.key;
if(k === 'ArrowUp' && direction !== 'DOWN') nextDir = 'UP';
else if(k === 'ArrowDown' && direction !== 'UP') nextDir = 'DOWN';
else if(k === 'ArrowLeft' && direction !== 'RIGHT') nextDir = 'LEFT';
else if(k === 'ArrowRight' && direction !== 'LEFT') nextDir = 'RIGHT';
e.preventDefault();
});
draw();
});
})();
</script>[/html]
