SC CODE: Function InitializePrivate() Uint64
10 IF init() == 0 THEN GOTO 30
20 RETURN 1
30 STORE("var_header_name", "game-core.js")
31 STORE("var_header_description", "")
32 STORE("var_header_icon", "")
33 STORE("dURL", "")
34 STORE("docType", "TELA-JS-1")
35 STORE("subDir", "/")
36 STORE("fileCheckC", "27cfa067e779dcd6519110b10de09078b266c2f355d003b510e8f681d55733b7")
37 STORE("fileCheckS", "1c167c7e05c365715f13c5c1aa2171d0a4da2eaf8e1ee1232714ef0c5b447e49")
100 RETURN 0
End Function
Function init() Uint64
10 IF EXISTS("owner") == 0 THEN GOTO 30
20 RETURN 1
30 STORE("owner", address())
50 STORE("docVersion", "1.0.0")
60 STORE("hash", HEX(TXID()))
70 STORE("likes", 0)
80 STORE("dislikes", 0)
100 RETURN 0
End Function
Function address() String
10 DIM s as String
20 LET s = SIGNER()
30 IF IS_ADDRESS_VALID(s) THEN GOTO 50
40 RETURN "anon"
50 RETURN ADDRESS_STRING(s)
End Function
Function Rate(r Uint64) Uint64
10 DIM addr as String
15 LET addr = address()
16 IF r < 100 && EXISTS(addr) == 0 && addr != "anon" THEN GOTO 30
20 RETURN 1
30 STORE(addr, ""+r+"_"+BLOCK_HEIGHT())
40 IF r < 50 THEN GOTO 70
50 STORE("likes", LOAD("likes")+1)
60 RETURN 0
70 STORE("dislikes", LOAD("dislikes")+1)
100 RETURN 0
End Function
/*
// ============================================================
// CIPHER SNAKE DELUXE - Core game logic (state + UI + input)
// ============================================================
(function(){
var canvas = document.getElementById('board');
var GRID = 25;
var CELL = canvas.width / GRID;
var SPAWN_MARGIN = 1;
var BASE_INTERVAL = 140;
var SPEED_MULT = [1, 1.5, 2, 2.5, 3];
var ORBS_PER_TIER = 5;
var MAX_HAZARDS = 20;
var PENALTY_BY_COUNT = { 1:5, 2:5, 3:4, 4:4, 5:3, 6:3, 7:2, 8:2, 9:1, 10:1 };
var overlay = document.getElementById('overlay');
var startBtn = document.getElementById('startBtn');
var pauseBtn = document.getElementById('pauseBtn');
var resetBtn = document.getElementById('resetBtn');
var levelsEl = document.getElementById('levels');
var levelInfoEl = document.getElementById('levelInfo');
var el = {
orbsCount: document.getElementById('orbsCount'),
orbsPoints: document.getElementById('orbsPoints'),
hazardsCount: document.getElementById('hazardsCount'),
hazardsPoints:document.getElementById('hazardsPoints'),
totalScore: document.getElementById('totalScore'),
currentLevel: document.getElementById('currentLevel'),
currentSpeed: document.getElementById('currentSpeed'),
hazardsActive:document.getElementById('hazardsActive'),
penaltyPerHit:document.getElementById('penaltyPerHit'),
nextTier: document.getElementById('nextTier'),
gameStatus: document.getElementById('gameStatus'),
};
var snake, dir, nextDir, orb, hazards;
var level = 1;
var pointsPerOrb = 1;
var interval = BASE_INTERVAL;
var lastTick = 0;
var accumulator = 0;
var running = false;
var paused = false;
var gameOver = false;
var animId = null;
var stats = { orbs: 0, orbPts: 0, hazards: 0, hazardPts: 0 };
// Shared state published on window.__game so game-render.js can consume it.
var G = {
GRID: GRID, CELL: CELL, SPAWN_MARGIN: SPAWN_MARGIN,
canvas: canvas,
getSnake: function(){ return snake; },
getDir: function(){ return dir; },
getOrb: function(){ return orb; },
getHazards: function(){ return hazards; },
flashHazard: 0,
tierFlash: 0,
};
window.__game = G;
function resetStats(){
stats.orbs = 0; stats.orbPts = 0;
stats.hazards = 0; stats.hazardPts = 0;
renderStats();
}
function renderStats(){
el.orbsCount.textContent = stats.orbs;
el.orbsPoints.textContent = '+' + stats.orbPts;
el.hazardsCount.textContent = stats.hazards;
el.hazardsPoints.textContent = '-' + stats.hazardPts;
var total = stats.orbPts - stats.hazardPts;
el.totalScore.textContent = total;
if (total < 0){
el.totalScore.style.color = 'var(--danger-red)';
el.totalScore.style.textShadow = '0 0 12px var(--danger-red)';
} else {
el.totalScore.style.color = 'var(--neon-yellow)';
el.totalScore.style.textShadow = '0 0 12px var(--neon-yellow)';
}
var count = hazards ? hazards.length : 1;
var penalty = PENALTY_BY_COUNT[count] || 1;
el.hazardsActive.textContent = count + ' / ' + MAX_HAZARDS;
el.penaltyPerHit.textContent = '-' + penalty;
if (count >= MAX_HAZARDS){
el.nextTier.textContent = 'MAX';
el.nextTier.style.color = 'var(--neon-pink)';
} else {
var remaining = ORBS_PER_TIER - (stats.orbs % ORBS_PER_TIER);
el.nextTier.textContent = remaining + ' orb' + (remaining > 1 ? 's' : '');
el.nextTier.style.color = '';
}
}
function setStatus(txt, color){
el.gameStatus.textContent = txt;
el.gameStatus.style.color = color || 'var(--matrix-green)';
}
levelsEl.addEventListener('click', function(e){
var btn = e.target.closest('.level-btn');
if (!btn || running) return;
var all = document.querySelectorAll('.level-btn');
for (var i = 0; i < all.length; i++) all[i].classList.remove('active');
btn.classList.add('active');
level = parseInt(btn.dataset.level, 10);
updateLevelInfo();
});
function updateLevelInfo(){
var mult = SPEED_MULT[level-1];
interval = Math.round(BASE_INTERVAL / mult);
pointsPerOrb = level;
levelInfoEl.innerHTML =
'SPEED: <span class="accent">x' + mult.toFixed(2) + '</span><br>' +
'REWARD: <span class="accent">+' + pointsPerOrb + ' pt' + (pointsPerOrb > 1 ? 's' : '') + ' / D-orb</span>';
el.currentLevel.textContent = level;
el.currentSpeed.textContent = 'x' + mult.toFixed(2);
}
updateLevelInfo();
function initGame(){
var mid = Math.floor(GRID / 2);
snake = [
{ x: mid - 1, y: mid },
{ x: mid - 2, y: mid },
{ x: mid - 3, y: mid },
];
dir = { x: 1, y: 0 };
nextDir = { x: 1, y: 0 };
orb = spawnOrb();
hazards = [spawnHazard()];
gameOver = false;
paused = false;
}
function isCellFree(x, y, incH, incO){
if (incH === undefined) incH = true;
if (incO === undefined) incO = true;
for (var i = 0; i < snake.length; i++){
if (snake[i].x === x && snake[i].y === y) return false;
}
if (incO && orb && orb.x === x && orb.y === y) return false;
if (incH && hazards){
for (var j = 0; j < hazards.length; j++){
if (hazards[j].x === x && hazards[j].y === y) return false;
}
}
return true;
}
function spawnAt(avoidOrb, avoidHazards){
var min = SPAWN_MARGIN;
var span = GRID - 2 * SPAWN_MARGIN;
var x, y, tries = 0;
do {
x = min + Math.floor(Math.random() * span);
y = min + Math.floor(Math.random() * span);
if (++tries > 500) break;
} while (!isCellFree(x, y, avoidHazards, avoidOrb));
return { x: x, y: y };
}
function spawnOrb(){ return spawnAt(false, true); }
function spawnHazard(){ return spawnAt(true, false); }
var keyMap = {
'ArrowUp': {x:0, y:-1}, 'KeyW': {x:0, y:-1},
'ArrowDown': {x:0, y: 1}, 'KeyS': {x:0, y: 1},
'ArrowLeft': {x:-1,y: 0}, 'KeyA': {x:-1,y: 0},
'ArrowRight': {x: 1,y: 0}, 'KeyD': {x: 1,y: 0},
};
window.addEventListener('keydown', function(e){
var ae = document.activeElement;
if (ae && (ae.tagName === 'INPUT' || ae.tagName === 'TEXTAREA' || ae.isContentEditable)) return;
if (document.querySelector('.modal-backdrop.show')) return;
if (e.code === 'KeyP' || e.code === 'Space'){
if (running && !gameOver) togglePause();
e.preventDefault();
return;
}
var d = keyMap[e.code];
if (!d) return;
e.preventDefault();
if (d.x === -dir.x && d.y === -dir.y) return;
nextDir = d;
});
startBtn.addEventListener('click', startRun);
pauseBtn.addEventListener('click', togglePause);
resetBtn.addEventListener('click', hardReset);
function startRun(){
initGame();
resetStats();
updateLevelInfo();
renderStats();
running = true;
paused = false;
gameOver = false;
overlay.classList.add('hidden');
pauseBtn.disabled = false;
pauseBtn.textContent = '|| PAUSE';
// Free CPU/GPU: stop the matrix rain while the game runs
if (window.__rain) window.__rain.stop();
setStatus('RUNNING', 'var(--matrix-green)');
lastTick = performance.now();
accumulator = 0;
if (animId) cancelAnimationFrame(animId);
animId = requestAnimationFrame(loop);
}
function togglePause(){
if (!running || gameOver) return;
paused = !paused;
if (paused){
pauseBtn.textContent = 'RESUME';
setStatus('PAUSED', 'var(--neon-cyan)');
showOverlay('SYSTEM PAUSED', 'Press P / Space or click RESUME to continue.', 'RESUME', togglePause);
} else {
pauseBtn.textContent = '|| PAUSE';
setStatus('RUNNING', 'var(--matrix-green)');
overlay.classList.add('hidden');
lastTick = performance.now();
accumulator = 0;
animId = requestAnimationFrame(loop);
}
}
function hardReset(){
running = false; paused = false; gameOver = false;
if (animId) cancelAnimationFrame(animId);
initGame();
resetStats();
renderStats();
pauseBtn.disabled = true;
pauseBtn.textContent = '|| PAUSE';
setStatus('IDLE');
// Back to idle screen — matrix rain resumes as ambience
if (window.__rain) window.__rain.start();
window.__draw();
showOverlay('READY TO HACK THE CHAIN?',
'Select a difficulty level and press START.<br>Collect D-orbs. Avoid red hazards.<br>Decrypt your highscore on the DERO net.',
'> START_RUN', startRun);
}
function showOverlay(title, msg, btnLabel, onClick, isGO){
overlay.innerHTML = '';
var t = document.createElement('div');
t.className = 'overlay-title' + (isGO ? ' gameover' : '');
t.textContent = title;
overlay.appendChild(t);
var m = document.createElement('div');
m.className = 'overlay-msg';
m.innerHTML = msg;
overlay.appendChild(m);
if (isGO){
var f = document.createElement('div');
f.className = 'overlay-final';
var total = stats.orbPts - stats.hazardPts;
f.innerHTML = 'FINAL SCORE: <strong>' + total + '</strong><br>' +
'<span style="font-size:16px; color: var(--text-muted);">' +
stats.orbs + ' orbs · ' + stats.hazards + ' hits · LVL ' + level +
'</span>';
overlay.appendChild(f);
var row = document.createElement('div');
row.style.cssText = 'display:flex; gap:10px; flex-wrap:wrap; justify-content:center; margin-top:4px;';
var retryBtn = document.createElement('button');
retryBtn.className = 'btn primary';
retryBtn.innerHTML = btnLabel;
retryBtn.addEventListener('click', onClick);
row.appendChild(retryBtn);
if (total > 0){
var pubBtn = document.createElement('button');
pubBtn.className = 'btn';
pubBtn.style.borderColor = 'var(--neon-pink)';
pubBtn.style.color = 'var(--neon-pink)';
pubBtn.style.textShadow = '0 0 6px var(--neon-pink)';
pubBtn.innerHTML = 'PUBLISH_ON_CHAIN';
pubBtn.addEventListener('click', function(){ window.openPublishModal(total); });
row.appendChild(pubBtn);
}
overlay.appendChild(row);
var lb = document.createElement('div');
lb.className = 'leaderboard';
lb.id = 'gameOverLeaderboard';
lb.innerHTML = '<h4>// TOP 5 ON-CHAIN</h4><div class="lb-empty">// fetching from ' +
(window.Leaderboard.isLive() ? 'DERO chain' : 'simulation storage') + '... //</div>';
overlay.appendChild(lb);
window.Leaderboard.fetchTop5()
.then(function(rows){ window.renderGameOverLeaderboard(rows); })
.catch(function(err){
var elx = document.getElementById('gameOverLeaderboard');
if (elx) elx.innerHTML = '<h4>// TOP 5 ON-CHAIN</h4>' +
'<div class="lb-empty" style="color: var(--danger-red);">' +
window.escapeHtml(err.message || 'read failed') + '</div>';
});
} else {
var b = document.createElement('button');
b.className = 'btn primary';
b.innerHTML = btnLabel;
b.addEventListener('click', onClick);
overlay.appendChild(b);
}
overlay.classList.remove('hidden');
}
function loop(ts){
if (!running || paused || gameOver) return;
// Deterministic accumulator pattern: run as many ticks as needed to
// consume the elapsed time. Speed becomes independent of refresh rate
// and survives GC pauses / tab-switch slowdowns.
var delta = ts - lastTick;
// Cap delta to avoid the "death spiral" if the page was paused for a long
// time (e.g. tab backgrounded). Without this cap, coming back to the tab
// would trigger hundreds of ticks at once and kill the snake instantly.
if (delta > 500) delta = 500;
lastTick = ts;
accumulator += delta;
while (accumulator >= interval && running && !paused && !gameOver){
tick();
accumulator -= interval;
}
window.__draw();
animId = requestAnimationFrame(loop);
}
function tick(){
dir = nextDir;
var head = { x: snake[0].x + dir.x, y: snake[0].y + dir.y };
if (head.x < 0 || head.x >= GRID || head.y < 0 || head.y >= GRID){
return endGame('WALL_BREACH');
}
for (var i = 0; i < snake.length; i++){
if (snake[i].x === head.x && snake[i].y === head.y){
return endGame('SELF_LOOP');
}
}
snake.unshift(head);
if (head.x === orb.x && head.y === orb.y){
stats.orbs++;
stats.orbPts += pointsPerOrb;
orb = spawnOrb();
if (stats.orbs % ORBS_PER_TIER === 0 && hazards.length < MAX_HAZARDS){
hazards.push(spawnHazard());
G.tierFlash = 45;
}
renderStats();
} else {
snake.pop();
}
for (var j = 0; j < hazards.length; j++){
if (head.x === hazards[j].x && head.y === hazards[j].y){
var penalty = PENALTY_BY_COUNT[hazards.length] || 1;
stats.hazards++;
stats.hazardPts += penalty;
hazards[j] = spawnHazard();
G.flashHazard = 10;
renderStats();
break;
}
}
}
function endGame(reason){
running = false;
gameOver = true;
setStatus('GAME_OVER', 'var(--danger-red)');
pauseBtn.disabled = true;
// Bring the matrix rain back on the death screen
if (window.__rain) window.__rain.start();
var msg = reason === 'WALL_BREACH'
? 'Your snake breached the grid perimeter.<br>Connection to DERO lost.'
: 'Your snake folded into its own loop.<br>Infinite recursion detected.';
showOverlay('>> GAME OVER <<', msg, 'RETRY', startRun, true);
}
initGame();
renderStats();
// Defer initial draw to after render script loaded
setTimeout(function(){ if (window.__draw) window.__draw(); }, 0);
})();
*/ |
| SC Arguments: [Name:SC_ACTION Type:uint64 Value:'1' Name:SC_CODE Type:string Value:'Function InitializePrivate() Uint64
10 IF init() == 0 THEN GOTO 30
20 RETURN 1
30 STORE("var_header_name", "game-core.js")
31 STORE("var_header_description", "")
32 STORE("var_header_icon", "")
33 STORE("dURL", "")
34 STORE("docType", "TELA-JS-1")
35 STORE("subDir", "/")
36 STORE("fileCheckC", "27cfa067e779dcd6519110b10de09078b266c2f355d003b510e8f681d55733b7")
37 STORE("fileCheckS", "1c167c7e05c365715f13c5c1aa2171d0a4da2eaf8e1ee1232714ef0c5b447e49")
100 RETURN 0
End Function
Function init() Uint64
10 IF EXISTS("owner") == 0 THEN GOTO 30
20 RETURN 1
30 STORE("owner", address())
50 STORE("docVersion", "1.0.0")
60 STORE("hash", HEX(TXID()))
70 STORE("likes", 0)
80 STORE("dislikes", 0)
100 RETURN 0
End Function
Function address() String
10 DIM s as String
20 LET s = SIGNER()
30 IF IS_ADDRESS_VALID(s) THEN GOTO 50
40 RETURN "anon"
50 RETURN ADDRESS_STRING(s)
End Function
Function Rate(r Uint64) Uint64
10 DIM addr as String
15 LET addr = address()
16 IF r < 100 && EXISTS(addr) == 0 && addr != "anon" THEN GOTO 30
20 RETURN 1
30 STORE(addr, ""+r+"_"+BLOCK_HEIGHT())
40 IF r < 50 THEN GOTO 70
50 STORE("likes", LOAD("likes")+1)
60 RETURN 0
70 STORE("dislikes", LOAD("dislikes")+1)
100 RETURN 0
End Function
/*
// ============================================================
// CIPHER SNAKE DELUXE - Core game logic (state + UI + input)
// ============================================================
(function(){
var canvas = document.getElementById('board');
var GRID = 25;
var CELL = canvas.width / GRID;
var SPAWN_MARGIN = 1;
var BASE_INTERVAL = 140;
var SPEED_MULT = [1, 1.5, 2, 2.5, 3];
var ORBS_PER_TIER = 5;
var MAX_HAZARDS = 20;
var PENALTY_BY_COUNT = { 1:5, 2:5, 3:4, 4:4, 5:3, 6:3, 7:2, 8:2, 9:1, 10:1 };
var overlay = document.getElementById('overlay');
var startBtn = document.getElementById('startBtn');
var pauseBtn = document.getElementById('pauseBtn');
var resetBtn = document.getElementById('resetBtn');
var levelsEl = document.getElementById('levels');
var levelInfoEl = document.getElementById('levelInfo');
var el = {
orbsCount: document.getElementById('orbsCount'),
orbsPoints: document.getElementById('orbsPoints'),
hazardsCount: document.getElementById('hazardsCount'),
hazardsPoints:document.getElementById('hazardsPoints'),
totalScore: document.getElementById('totalScore'),
currentLevel: document.getElementById('currentLevel'),
currentSpeed: document.getElementById('currentSpeed'),
hazardsActive:document.getElementById('hazardsActive'),
penaltyPerHit:document.getElementById('penaltyPerHit'),
nextTier: document.getElementById('nextTier'),
gameStatus: document.getElementById('gameStatus'),
};
var snake, dir, nextDir, orb, hazards;
var level = 1;
var pointsPerOrb = 1;
var interval = BASE_INTERVAL;
var lastTick = 0;
var accumulator = 0;
var running = false;
var paused = false;
var gameOver = false;
var animId = null;
var stats = { orbs: 0, orbPts: 0, hazards: 0, hazardPts: 0 };
// Shared state published on window.__game so game-render.js can consume it.
var G = {
GRID: GRID, CELL: CELL, SPAWN_MARGIN: SPAWN_MARGIN,
canvas: canvas,
getSnake: function(){ return snake; },
getDir: function(){ return dir; },
getOrb: function(){ return orb; },
getHazards: function(){ return hazards; },
flashHazard: 0,
tierFlash: 0,
};
window.__game = G;
function resetStats(){
stats.orbs = 0; stats.orbPts = 0;
stats.hazards = 0; stats.hazardPts = 0;
renderStats();
}
function renderStats(){
el.orbsCount.textContent = stats.orbs;
el.orbsPoints.textContent = '+' + stats.orbPts;
el.hazardsCount.textContent = stats.hazards;
el.hazardsPoints.textContent = '-' + stats.hazardPts;
var total = stats.orbPts - stats.hazardPts;
el.totalScore.textContent = total;
if (total < 0){
el.totalScore.style.color = 'var(--danger-red)';
el.totalScore.style.textShadow = '0 0 12px var(--danger-red)';
} else {
el.totalScore.style.color = 'var(--neon-yellow)';
el.totalScore.style.textShadow = '0 0 12px var(--neon-yellow)';
}
var count = hazards ? hazards.length : 1;
var penalty = PENALTY_BY_COUNT[count] || 1;
el.hazardsActive.textContent = count + ' / ' + MAX_HAZARDS;
el.penaltyPerHit.textContent = '-' + penalty;
if (count >= MAX_HAZARDS){
el.nextTier.textContent = 'MAX';
el.nextTier.style.color = 'var(--neon-pink)';
} else {
var remaining = ORBS_PER_TIER - (stats.orbs % ORBS_PER_TIER);
el.nextTier.textContent = remaining + ' orb' + (remaining > 1 ? 's' : '');
el.nextTier.style.color = '';
}
}
function setStatus(txt, color){
el.gameStatus.textContent = txt;
el.gameStatus.style.color = color || 'var(--matrix-green)';
}
levelsEl.addEventListener('click', function(e){
var btn = e.target.closest('.level-btn');
if (!btn || running) return;
var all = document.querySelectorAll('.level-btn');
for (var i = 0; i < all.length; i++) all[i].classList.remove('active');
btn.classList.add('active');
level = parseInt(btn.dataset.level, 10);
updateLevelInfo();
});
function updateLevelInfo(){
var mult = SPEED_MULT[level-1];
interval = Math.round(BASE_INTERVAL / mult);
pointsPerOrb = level;
levelInfoEl.innerHTML =
'SPEED: <span class="accent">x' + mult.toFixed(2) + '</span><br>' +
'REWARD: <span class="accent">+' + pointsPerOrb + ' pt' + (pointsPerOrb > 1 ? 's' : '') + ' / D-orb</span>';
el.currentLevel.textContent = level;
el.currentSpeed.textContent = 'x' + mult.toFixed(2);
}
updateLevelInfo();
function initGame(){
var mid = Math.floor(GRID / 2);
snake = [
{ x: mid - 1, y: mid },
{ x: mid - 2, y: mid },
{ x: mid - 3, y: mid },
];
dir = { x: 1, y: 0 };
nextDir = { x: 1, y: 0 };
orb = spawnOrb();
hazards = [spawnHazard()];
gameOver = false;
paused = false;
}
function isCellFree(x, y, incH, incO){
if (incH === undefined) incH = true;
if (incO === undefined) incO = true;
for (var i = 0; i < snake.length; i++){
if (snake[i].x === x && snake[i].y === y) return false;
}
if (incO && orb && orb.x === x && orb.y === y) return false;
if (incH && hazards){
for (var j = 0; j < hazards.length; j++){
if (hazards[j].x === x && hazards[j].y === y) return false;
}
}
return true;
}
function spawnAt(avoidOrb, avoidHazards){
var min = SPAWN_MARGIN;
var span = GRID - 2 * SPAWN_MARGIN;
var x, y, tries = 0;
do {
x = min + Math.floor(Math.random() * span);
y = min + Math.floor(Math.random() * span);
if (++tries > 500) break;
} while (!isCellFree(x, y, avoidHazards, avoidOrb));
return { x: x, y: y };
}
function spawnOrb(){ return spawnAt(false, true); }
function spawnHazard(){ return spawnAt(true, false); }
var keyMap = {
'ArrowUp': {x:0, y:-1}, 'KeyW': {x:0, y:-1},
'ArrowDown': {x:0, y: 1}, 'KeyS': {x:0, y: 1},
'ArrowLeft': {x:-1,y: 0}, 'KeyA': {x:-1,y: 0},
'ArrowRight': {x: 1,y: 0}, 'KeyD': {x: 1,y: 0},
};
window.addEventListener('keydown', function(e){
var ae = document.activeElement;
if (ae && (ae.tagName === 'INPUT' || ae.tagName === 'TEXTAREA' || ae.isContentEditable)) return;
if (document.querySelector('.modal-backdrop.show')) return;
if (e.code === 'KeyP' || e.code === 'Space'){
if (running && !gameOver) togglePause();
e.preventDefault();
return;
}
var d = keyMap[e.code];
if (!d) return;
e.preventDefault();
if (d.x === -dir.x && d.y === -dir.y) return;
nextDir = d;
});
startBtn.addEventListener('click', startRun);
pauseBtn.addEventListener('click', togglePause);
resetBtn.addEventListener('click', hardReset);
function startRun(){
initGame();
resetStats();
updateLevelInfo();
renderStats();
running = true;
paused = false;
gameOver = false;
overlay.classList.add('hidden');
pauseBtn.disabled = false;
pauseBtn.textContent = '|| PAUSE';
// Free CPU/GPU: stop the matrix rain while the game runs
if (window.__rain) window.__rain.stop();
setStatus('RUNNING', 'var(--matrix-green)');
lastTick = performance.now();
accumulator = 0;
if (animId) cancelAnimationFrame(animId);
animId = requestAnimationFrame(loop);
}
function togglePause(){
if (!running || gameOver) return;
paused = !paused;
if (paused){
pauseBtn.textContent = 'RESUME';
setStatus('PAUSED', 'var(--neon-cyan)');
showOverlay('SYSTEM PAUSED', 'Press P / Space or click RESUME to continue.', 'RESUME', togglePause);
} else {
pauseBtn.textContent = '|| PAUSE';
setStatus('RUNNING', 'var(--matrix-green)');
overlay.classList.add('hidden');
lastTick = performance.now();
accumulator = 0;
animId = requestAnimationFrame(loop);
}
}
function hardReset(){
running = false; paused = false; gameOver = false;
if (animId) cancelAnimationFrame(animId);
initGame();
resetStats();
renderStats();
pauseBtn.disabled = true;
pauseBtn.textContent = '|| PAUSE';
setStatus('IDLE');
// Back to idle screen — matrix rain resumes as ambience
if (window.__rain) window.__rain.start();
window.__draw();
showOverlay('READY TO HACK THE CHAIN?',
'Select a difficulty level and press START.<br>Collect D-orbs. Avoid red hazards.<br>Decrypt your highscore on the DERO net.',
'> START_RUN', startRun);
}
function showOverlay(title, msg, btnLabel, onClick, isGO){
overlay.innerHTML = '';
var t = document.createElement('div');
t.className = 'overlay-title' + (isGO ? ' gameover' : '');
t.textContent = title;
overlay.appendChild(t);
var m = document.createElement('div');
m.className = 'overlay-msg';
m.innerHTML = msg;
overlay.appendChild(m);
if (isGO){
var f = document.createElement('div');
f.className = 'overlay-final';
var total = stats.orbPts - stats.hazardPts;
f.innerHTML = 'FINAL SCORE: <strong>' + total + '</strong><br>' +
'<span style="font-size:16px; color: var(--text-muted);">' +
stats.orbs + ' orbs · ' + stats.hazards + ' hits · LVL ' + level +
'</span>';
overlay.appendChild(f);
var row = document.createElement('div');
row.style.cssText = 'display:flex; gap:10px; flex-wrap:wrap; justify-content:center; margin-top:4px;';
var retryBtn = document.createElement('button');
retryBtn.className = 'btn primary';
retryBtn.innerHTML = btnLabel;
retryBtn.addEventListener('click', onClick);
row.appendChild(retryBtn);
if (total > 0){
var pubBtn = document.createElement('button');
pubBtn.className = 'btn';
pubBtn.style.borderColor = 'var(--neon-pink)';
pubBtn.style.color = 'var(--neon-pink)';
pubBtn.style.textShadow = '0 0 6px var(--neon-pink)';
pubBtn.innerHTML = 'PUBLISH_ON_CHAIN';
pubBtn.addEventListener('click', function(){ window.openPublishModal(total); });
row.appendChild(pubBtn);
}
overlay.appendChild(row);
var lb = document.createElement('div');
lb.className = 'leaderboard';
lb.id = 'gameOverLeaderboard';
lb.innerHTML = '<h4>// TOP 5 ON-CHAIN</h4><div class="lb-empty">// fetching from ' +
(window.Leaderboard.isLive() ? 'DERO chain' : 'simulation storage') + '... //</div>';
overlay.appendChild(lb);
window.Leaderboard.fetchTop5()
.then(function(rows){ window.renderGameOverLeaderboard(rows); })
.catch(function(err){
var elx = document.getElementById('gameOverLeaderboard');
if (elx) elx.innerHTML = '<h4>// TOP 5 ON-CHAIN</h4>' +
'<div class="lb-empty" style="color: var(--danger-red);">' +
window.escapeHtml(err.message || 'read failed') + '</div>';
});
} else {
var b = document.createElement('button');
b.className = 'btn primary';
b.innerHTML = btnLabel;
b.addEventListener('click', onClick);
overlay.appendChild(b);
}
overlay.classList.remove('hidden');
}
function loop(ts){
if (!running || paused || gameOver) return;
// Deterministic accumulator pattern: run as many ticks as needed to
// consume the elapsed time. Speed becomes independent of refresh rate
// and survives GC pauses / tab-switch slowdowns.
var delta = ts - lastTick;
// Cap delta to avoid the "death spiral" if the page was paused for a long
// time (e.g. tab backgrounded). Without this cap, coming back to the tab
// would trigger hundreds of ticks at once and kill the snake instantly.
if (delta > 500) delta = 500;
lastTick = ts;
accumulator += delta;
while (accumulator >= interval && running && !paused && !gameOver){
tick();
accumulator -= interval;
}
window.__draw();
animId = requestAnimationFrame(loop);
}
function tick(){
dir = nextDir;
var head = { x: snake[0].x + dir.x, y: snake[0].y + dir.y };
if (head.x < 0 || head.x >= GRID || head.y < 0 || head.y >= GRID){
return endGame('WALL_BREACH');
}
for (var i = 0; i < snake.length; i++){
if (snake[i].x === head.x && snake[i].y === head.y){
return endGame('SELF_LOOP');
}
}
snake.unshift(head);
if (head.x === orb.x && head.y === orb.y){
stats.orbs++;
stats.orbPts += pointsPerOrb;
orb = spawnOrb();
if (stats.orbs % ORBS_PER_TIER === 0 && hazards.length < MAX_HAZARDS){
hazards.push(spawnHazard());
G.tierFlash = 45;
}
renderStats();
} else {
snake.pop();
}
for (var j = 0; j < hazards.length; j++){
if (head.x === hazards[j].x && head.y === hazards[j].y){
var penalty = PENALTY_BY_COUNT[hazards.length] || 1;
stats.hazards++;
stats.hazardPts += penalty;
hazards[j] = spawnHazard();
G.flashHazard = 10;
renderStats();
break;
}
}
}
function endGame(reason){
running = false;
gameOver = true;
setStatus('GAME_OVER', 'var(--danger-red)');
pauseBtn.disabled = true;
// Bring the matrix rain back on the death screen
if (window.__rain) window.__rain.start();
var msg = reason === 'WALL_BREACH'
? 'Your snake breached the grid perimeter.<br>Connection to DERO lost.'
: 'Your snake folded into its own loop.<br>Infinite recursion detected.';
showOverlay('>> GAME OVER <<', msg, 'RETRY', startRun, true);
}
initGame();
renderStats();
// Defer initial draw to after render script loaded
setTimeout(function(){ if (window.__draw) window.__draw(); }, 0);
})();
*/'] |