Хз
by GoldenBear871323 lines19.7 KB
<script>
/* =========================================
300 MONET — ЧАСТЬ 3
========================================= */
/* =========================================
РАЗЛЁТ МОНЕТ
========================================= */
function coinBurst(sourceCoin){
if(!running || ending)return;
if(sourceCoin.dataset.busy==="1")return;
sourceCoin.dataset.busy="1";
sourceCoin.classList.add("taken");
removeLockSignForCoin(sourceCoin);
playSound(COIN_SOUND);
const rect =
sourceCoin.getBoundingClientRect();
const count = 6;
for(let i=0;i<count;i++){
const burst =
document.createElement("img");
burst.className="burstCoin";
burst.src=GOLD;
burst.onerror=function(){
fallbackCoin(burst);
};
burst.style.left =
(rect.left + rect.width/2 - 12)+"px";
burst.style.top =
(rect.top + rect.height/2 - 12)+"px";
document.body.appendChild(burst);
const angle =
(Math.PI*2/count)*i +
(Math.random()-.5)*.35;
const distance =
45 + Math.random()*55;
const targetX =
rect.left +
rect.width/2 +
Math.cos(angle)*distance;
const targetY =
rect.top +
rect.height/2 +
Math.sin(angle)*distance;
requestAnimationFrame(function(){
burst.style.left =
(targetX-12)+"px";
burst.style.top =
(targetY-12)+"px";
});
/* Каждая монета начинает полёт
немного позже предыдущей */
setTimeout(function(){
if(!running || ending){
burst.remove();
return;
}
const counter =
counterIcon.getBoundingClientRect();
playSound(COIN_FLY_SOUND);
burst.classList.add("flyToCounter");
burst.style.left =
(counter.left + counter.width/2 - 12)+"px";
burst.style.top =
(counter.top + counter.height/2 - 12)+"px";
},180+i*80);
/* Каждая монета отдельно
добавляет +1 */
setTimeout(function(){
burst.remove();
if(!running || ending)return;
money++;
/* ВАЖНО:
текст НЕ увеличивается,
просто меняется число */
updateMoney(false);
},730+i*80);
}
setTimeout(function(){
sourceCoin.remove();
},160);
}
/* =========================================
УДАЛЕНИЕ ЗНАЧКА БЛОКИРОВКИ
========================================= */
function removeLockSignForCoin(coin){
const id =
coin.dataset.lock;
if(!id)return;
document
.querySelectorAll(".lockSign")
.forEach(function(sign){
if(sign.dataset.coin===id){
sign.remove();
}
});
}
/* =========================================
A-90
========================================= */
function spawnVirus(){
if(!running || ending)return;
const virus =
document.createElement("img");
virus.className="virus";
virus.src=VIRUS;
virus.onerror=function(){
fallbackVirus(virus);
};
const pos =
randomPosition();
virus.style.left =
pos.x+"px";
virus.style.top =
pos.y+"px";
virus.addEventListener(
"click",
function(e){
e.preventDefault();
e.stopPropagation();
if(virus.dataset.hit==="1")return;
virus.dataset.hit="1";
playSound(VIRUS_SOUND);
money =
Math.max(0,money-5);
updateMoney(false);
showMinus(
"-5",
e.clientX,
e.clientY
);
game.classList.remove(
"screenGlitch"
);
void game.offsetWidth;
game.classList.add(
"screenGlitch"
);
glitchOverlay.style.display=
"block";
virus.classList.add(
"glitch"
);
setTimeout(function(){
glitchOverlay.style.display=
"none";
virus.src=VIRUS_AFTER;
virus.onerror=function(){
fallbackGlitch(virus);
};
},180);
setTimeout(function(){
virus.remove();
},650);
}
);
field.appendChild(virus);
}
/* =========================================
ГЛЮЧНАЯ МОНЕТА
========================================= */
function spawnGlitchCoin(){
if(!running || ending)return;
const coin =
document.createElement("img");
coin.className="glitchCoin";
coin.src=VIRUS_AFTER;
coin.onerror=function(){
fallbackGlitch(coin);
};
const pos =
randomPosition();
coin.style.left =
pos.x+"px";
coin.style.top =
pos.y+"px";
coin.addEventListener(
"click",
function(e){
e.preventDefault();
e.stopPropagation();
if(coin.dataset.hit==="1")return;
coin.dataset.hit="1";
coin.classList.add("hit");
playSound(COIN_SOUND);
money+=3;
updateMoney(false);
showGlitchText(
"+3",
e.clientX,
e.clientY
);
setTimeout(function(){
coin.remove();
},550);
}
);
field.appendChild(coin);
}
/* =========================================
ГОРШОК
========================================= */
function spawnMoneyPot(){
if(!running || ending)return;
const pot =
document.createElement("img");
pot.className="moneyPot";
pot.src=MONEY_POT;
pot.onerror=function(){
fallbackPot(pot);
};
const pos =
randomPosition();
pot.style.left =
pos.x+"px";
pot.style.top =
pos.y+"px";
pot.addEventListener(
"click",
function(e){
e.preventDefault();
e.stopPropagation();
if(pot.dataset.opened==="1")return;
pot.dataset.opened="1";
pot.classList.add("opened");
const rect =
pot.getBoundingClientRect();
const counter =
counterIcon.getBoundingClientRect();
playSound(COIN_SOUND);
showPotText(
"+30",
rect.left + rect.width/2,
rect.top
);
for(let i=0;i<30;i++){
const coin =
document.createElement("img");
coin.className="potCoin";
coin.src=GOLD;
coin.onerror=function(){
fallbackCoin(coin);
};
coin.style.left =
(rect.left + rect.width/2 - 14)+"px";
coin.style.top =
(rect.top + rect.height/2 - 14)+"px";
document.body.appendChild(coin);
setTimeout(function(){
coin.style.left =
(counter.left + counter.width/2 - 14)+"px";
coin.style.top =
(counter.top + counter.height/2 - 14)+"px";
coin.classList.add("fly");
},i*25);
setTimeout(function(){
coin.remove();
if(running && !ending){
money++;
updateMoney(false);
}
},700+i*25);
}
setTimeout(function(){
pot.remove();
},450);
}
);
field.appendChild(pot);
}
/* =========================================
FALLBACK ГОРШКА
========================================= */
function fallbackPot(img){
img.src =
"data:image/svg+xml;charset=utf-8,"+
encodeURIComponent(`
<svg xmlns="http://www.w3.org/2000/svg"
viewBox="0 0 100 100">
<ellipse cx="50" cy="35"
rx="31" ry="12"
fill="#6b3518"
stroke="#d8944b"
stroke-width="5"/>
<path d="M20 35 L27 80
Q50 94 73 80 L80 35"
fill="#8b4d20"
stroke="#d8944b"
stroke-width="5"/>
<circle cx="38" cy="30"
r="7"
fill="#ffd34d"/>
<circle cx="53" cy="27"
r="7"
fill="#ffd34d"/>
<circle cx="66" cy="32"
r="7"
fill="#ffd34d"/>
</svg>`);
}
/* =========================================
ТЕКСТОВЫЕ ЭФФЕКТЫ
========================================= */
function showMinus(text,x,y){
const element =
document.createElement("div");
element.id="minus";
element.textContent=text;
element.style.left =
(x-15)+"px";
element.style.top =
(y-15)+"px";
document.body.appendChild(element);
setTimeout(function(){
element.remove();
},850);
}
function showGlitchText(text,x,y){
const element =
document.createElement("div");
element.id="glitchText";
element.textContent=text;
element.style.left =
(x-15)+"px";
element.style.top =
(y-15)+"px";
document.body.appendChild(element);
setTimeout(function(){
element.remove();
},850);
}
function showPotText(text,x,y){
const element =
document.createElement("div");
element.id="potText";
element.textContent=text;
element.style.left =
(x-20)+"px";
element.style.top =
(y-10)+"px";
document.body.appendChild(element);
setTimeout(function(){
element.remove();
},850);
}
/* =========================================
БЛОКИРОВКА МОНЕТ
========================================= */
function lockCoins(){
field
.querySelectorAll(".coin")
.forEach(function(coin){
if(coin.classList.contains("taken"))
return;
coin.classList.add("locked");
const sign =
document.createElement("img");
sign.className="lockSign";
sign.src=A90_SIGN;
sign.onerror=function(){
fallbackVirus(sign);
};
const rect =
coin.getBoundingClientRect();
sign.style.left =
(rect.left + rect.width/2 - 19)+"px";
sign.style.top =
(rect.top + rect.height/2 - 19)+"px";
const id =
Math.random()
.toString(36)
.slice(2);
sign.dataset.coin=id;
coin.dataset.lock=id;
document.body.appendChild(sign);
});
}
/* =========================================
ОКНО ТРАТЫ
========================================= */
function openSpend(){
if(!running || ending)return;
spendOverlay.style.display="flex";
spendImage.src=A90;
lockCoins();
}
function closeSpend(){
spendOverlay.style.display="none";
document
.querySelectorAll(".lockSign")
.forEach(function(sign){
sign.remove();
});
field
.querySelectorAll(".coin.locked")
.forEach(function(coin){
coin.classList.remove("locked");
});
}
function buyCoins(){
if(money<100)return;
money-=100;
money+=10;
updateMoney(false);
closeSpend();
}
/* =========================================
СОЗДАНИЕ НАЧАЛЬНЫХ МОНЕТ
========================================= */
function spawnManyCoins(amount){
for(let i=0;i<amount;i++){
setTimeout(function(){
if(running && !ending){
spawnCoin();
}
},i*90);
}
}
/* =========================================
АВТОМАТИЧЕСКОЕ ПОЯВЛЕНИЕ МОНЕТ
========================================= */
function startCoinSpawning(){
clearInterval(coinAutoTimer);
coinAutoTimer =
setInterval(function(){
if(running && !ending){
spawnCoin();
}
},coinEggMode ? 350 : 800);
}
/* =========================================
МОНЕТНЫЙ ДОЖДЬ
========================================= */
function startCoinRain(){
clearInterval(coinRainInterval);
coinRainInterval =
setInterval(function(){
if(running && coinEggMode){
for(let i=0;i<3;i++){
spawnCoin();
}
}
},700);
}
/* =========================================
ТАЙМЕРЫ ОПАСНОСТЕЙ
========================================= */
function startTrapTimers(){
clearInterval(virusTimer);
clearInterval(glitchCoinTimer);
clearInterval(potTimer);
const difficulty =
difficulties[selectedDifficulty];
virusTimer =
setInterval(function(){
if(running && !ending){
spawnVirus();
}
},difficulty.virusTime);
glitchCoinTimer =
setInterval(function(){
if(running && !ending){
spawnGlitchCoin();
}
},difficulty.glitchTime);
potTimer =
setInterval(function(){
if(running && !ending){
spawnMoneyPot();
}
},15000);
}
/* =========================================
ТАЙМЕР ИГРЫ
========================================= */
function startTimer(){
const started =
Date.now();
clearInterval(timer);
timer =
setInterval(function(){
if(!running)return;
const elapsed =
(Date.now()-started)/1000;
time =
Math.max(
0,
60-elapsed
);
timerText.textContent =
time.toFixed(1);
if(time<=0){
clearInterval(timer);
finishGame(false);
}
},100);
}
/* =========================================
ОЧИСТКА ТАЙМЕРОВ
========================================= */
function clearGameTimers(){
clearInterval(timer);
clearInterval(virusTimer);
clearInterval(glitchCoinTimer);
clearInterval(coinRainInterval);
clearInterval(spendTimer);
clearInterval(coinAutoTimer);
clearInterval(potTimer);
timer=null;
virusTimer=null;
glitchCoinTimer=null;
coinRainInterval=null;
spendTimer=null;
coinAutoTimer=null;
potTimer=null;
}
/* =========================================
ЗАПУСК ИГРЫ
========================================= */
function startGame(){
if(running)return;
running=true;
ending=false;
money=0;
time=60;
clearGameTimers();
startScreen.style.display="none";
difficultyMenu.style.display="none";
mission.style.display="none";
message.style.display="none";
spendOverlay.style.display="none";
glitchOverlay.style.display="none";
field.style.display="block";
hud.style.display="flex";
field.innerHTML="";
document
.querySelectorAll(
".burstCoin,.potCoin,.lockSign,#minus,#glitchText,#potText"
)
.forEach(function(element){
element.remove();
});
updateMoney(false);
timerText.textContent="60.0";
spawnManyCoins(
coinEggMode ? 8 : 5
);
startTimer();
startCoinSpawning();
startTrapTimers();
if(coinEggMode){
startCoinRain();
}
}
/* =========================================
КОНЕЦ ИГРЫ
========================================= */
function finishGame(won){
if(ending)return;
ending=true;
running=false;
clearGameTimers();
spendOverlay.style.display="none";
glitchOverlay.style.display="none";
document
.querySelectorAll(".lockSign")
.forEach(function(sign){
sign.remove();
});
field
.querySelectorAll(".coin.locked")
.forEach(function(coin){
coin.classList.remove("locked");
});
if(won){
messageTitle.textContent =
"ТЫ СОБРАЛ 300!";
messageText.textContent =
"Задание выполнено. Монет найдено: "+
money+".";
}else{
messageTitle.textContent =
"ВРЕМЯ ВЫШЛО";
messageText.textContent =
"Ты собрал "+
money+
" из 300 монет.";
}
message.style.display="flex";
}
/* =========================================
ВОЗВРАТ В МЕНЮ
========================================= */
function returnToMenu(){
clearGameTimers();
running=false;
ending=false;
spendOverlay.style.display="none";
message.style.display="none";
difficultyMenu.style.display="none";
mission.style.display="none";
hud.style.display="none";
field.style.display="none";
glitchOverlay.style.display="none";
field.innerHTML="";
document
.querySelectorAll(
".burstCoin,.potCoin,.lockSign,#minus,#glitchText,#potText"
)
.forEach(function(element){
element.remove();
});
startScreen.style.display="flex";
}
/* =========================================
МОБИЛЬНЫЕ КНОПКИ
========================================= */
function bindTap(element,handler){
let lastTouch=0;
element.addEventListener(
"touchend",
function(event){
event.preventDefault();
event.stopPropagation();
lastTouch=Date.now();
handler(event);
},
{passive:false}
);
element.addEventListener(
"click",
function(event){
if(Date.now()-lastTouch<700)
return;
event.preventDefault();
event.stopPropagation();
handler(event);
}
);
}
/* =========================================
ПРИВЯЗКА КНОПОК
========================================= */
function bindAllButtons(){
bindTap(
difficultyBtn,
function(){
if(!running){
difficultyMenu.style.display=
"flex";
}
}
);
bindTap(
closeDifficulty,
function(){
difficultyMenu.style.display=
"none";
}
);
document
.querySelectorAll(".difficultyOption")
.forEach(function(button){
bindTap(
button,
function(){
selectedDifficulty =
button.dataset.difficulty;
document
.querySelectorAll(
".difficultyOption"
)
.forEach(function(item){
item.classList.remove(
"selected"
);
});
button.classList.add(
"selected"
);
difficultyName.textContent =
difficulties[
selectedDifficulty
].name;
difficultyMenu.style.display=
"none";
}
);
});
bindTap(
startBtn,
function(){
if(running)return;
coinEggMode=false;
missionText.innerHTML =
"Найди мне <b>300 монет</b>.";
missionTime.innerHTML =
"У тебя есть <b>60 секунд</b>.";
difficultyInfo.textContent =
difficulties[
selectedDifficulty
].info;
mission.style.display="flex";
}
);
bindTap(
coinEggBtn,
function(){
if(running)return;
coinEggMode=true;
missionText.innerHTML =
"Насыпь мне <b>300 монет</b>.";
missionTime.innerHTML =
"У тебя есть <b>60 секунд</b>.";
difficultyInfo.textContent =
"ПАСХАЛЬНЫЙ РЕЖИМ: МОНЕТНЫЙ ДОЖДЬ.";
mission.style.display="flex";
}
);
bindTap(
searchBtn,
function(){
startGame();
}
);
bindTap(
buyCoinsBtn,
function(){
buyCoins();
}
);
bindTap(
closeSpendBtn,
function(){
closeSpend();
}
);
bindTap(
againBtn,
function(){
message.style.display="none";
startGame();
}
);
bindTap(
menuBtn,
function(){
returnToMenu();
}
);
}
/* =========================================
ЗАПУСК ОБРАБОТЧИКОВ
========================================= */
let buttonsBound=false;
function safeBindAllButtons(){
if(buttonsBound)return;
buttonsBound=true;
bindAllButtons();
}
/* =========================================
DOM READY
========================================= */
document.addEventListener(
"DOMContentLoaded",
function(){
safeBindAllButtons();
counterIcon.src=GOLD;
spendImage.src=A90;
}
);
/* =========================================
ЕСЛИ DOM УЖЕ ГОТОВ
========================================= */
if(document.readyState!=="loading"){
safeBindAllButtons();
}
/* =========================================
ЗАЩИТА ОТ КОНТЕКСТНОГО МЕНЮ
========================================= */
document.addEventListener(
"contextmenu",
function(event){
event.preventDefault();
}
);
/* =========================================
ЗАЩИТА ОТ ВЫДЕЛЕНИЯ
========================================= */
document.addEventListener(
"selectstart",
function(event){
event.preventDefault();
}
);
/* =========================================
КОНЕЦ ИГРЫ
========================================= */
</script>
</body>
</html>Game Source: Хз
Creator: GoldenBear87
Libraries: none
Complexity: complex (1323 lines, 19.7 KB)
The full source code is displayed above on this page.
Remix Instructions
To remix this game, copy the source code above and modify it. Add a ARCADELAB header at the top with "remix_of: game-goldenbear87-mug5sf9b" to link back to the original. Then publish at arcadelab.ai/publish.