🎮ArcadeLab

Молот Роскомнадзора: Драка

by EpicKoala43
299 lines26.5 KB
▶ Play
<!DOCTYPE html>
<html lang="ru"><head><meta charset="utf-8">
<meta name="viewport" content="width=device-width, initial-scale=1, viewport-fit=cover">
<title>Молот Роскомнадзора: Драка</title>
<style>
:root{--bg:#10131a;--fg:#f2f4f8;--red:#e5383b;box-sizing:border-box;padding-top:env(safe-area-inset-top,0px);padding-bottom:env(safe-area-inset-bottom,0px)}
html{height:100%;scroll-padding-top:env(safe-area-inset-top,0px)}
body{height:100%;margin:0;background:var(--bg);color:var(--fg);font-family:"Courier New",Courier,monospace;font-weight:700;overflow:hidden;touch-action:none;user-select:none;-webkit-user-select:none}
canvas{display:block;position:fixed;inset:0;width:100vw;height:100vh;image-rendering:pixelated}
.b{position:fixed;border:4px solid #fff;border-radius:0;box-shadow:4px 4px 0 #000;background:#e5383b;color:#fff;font-size:22px;display:none;align-items:center;justify-content:center;z-index:2;touch-action:none}
#atk{right:20px;bottom:calc(28px + env(safe-area-inset-bottom,0px));width:96px;height:96px}
#spc{right:126px;bottom:calc(20px + env(safe-area-inset-bottom,0px));width:66px;height:66px;font-size:18px;background:#555;filter:grayscale(1)}
#spc.rdy{background:#f59e0b;filter:none;color:#000}
#ov{position:fixed;inset:0;display:flex;flex-direction:column;align-items:center;text-align:center;background:rgba(10,12,18,.94);padding:24px;z-index:3;overflow-y:auto;touch-action:pan-y}#ov>:first-child{margin-top:auto}#ov>:last-child{margin-bottom:auto}
#ov h1{margin:0 0 8px;font-size:28px;color:var(--red)}
#ov p{margin:4px 0;max-width:340px;line-height:1.4;opacity:.92}
.stamp{font-size:26px;font-weight:900;color:var(--red);border:4px solid var(--red);padding:6px 14px;transform:rotate(-6deg);margin:10px 0}
button.go{margin-top:18px;padding:14px 28px;font-size:18px;font-weight:700;border:0;border-radius:0;box-shadow:4px 4px 0 #000;background:var(--red);color:#fff;font-family:inherit}
.it{display:flex;justify-content:space-between;align-items:center;width:100%;max-width:360px;box-sizing:border-box;border:3px solid #fff3;padding:8px 10px;margin:4px 0;text-align:left;gap:8px}.sm{margin:0!important;padding:8px 10px!important;font-size:14px!important;min-width:84px}button:disabled{opacity:.4}input{font:inherit;padding:8px;border:3px solid #fff;background:#000;color:#fff;width:150px;border-radius:0;box-sizing:border-box}small{opacity:.7}</style></head><body>
<canvas id="c"></canvas>
<div class="b" id="spc">БАН</div><div class="b" id="atk">УДАР</div>
<div id="ov"><h1>МОЛОТ РКН: ДРАКА 8-BIT</h1>
<p>Ты — инспектор с огромным молотом. Приложения озверели и лезут в драку. Круши их волнами!</p>
<p><b>Управление:</b> палец слева — двигаться, УДАР — молот по дуге (цель выбирается сам), БАН — удар на всю арену, когда шкала полна. На ПК: WASD, пробел, E.</p>
<p>VPN убегает, но если поймаешь — вылечит.</p>
<button class="go" id="go">В бой!</button><button class="go" id="shp">МАГАЗИН</button></div>
<script>
const cv=document.getElementById('c'),x=cv.getContext('2d'),ov=document.getElementById('ov'),$=id=>document.getElementById(id);
let W,H;
const S=3,sn=v=>Math.round(v/S)*S;function rs(){W=innerWidth;H=innerHeight;cv.width=Math.ceil(W/S);cv.height=Math.ceil(H/S);x.setTransform(1/S,0,0,1/S,0,0);x.imageSmoothingEnabled=false}
addEventListener('resize',rs);rs();
const ET={
tg:{n:'Telegram',c:'#2aabee',e:'✈️',hp:3,sp:85,r:24,dmg:8,pts:10},
yt:{n:'YouTube',c:'#e11d1d',e:'▶️',hp:7,sp:55,r:26,dmg:14,pts:25},
dc:{n:'Discord',c:'#5865f2',e:'🎮',hp:2,sp:130,r:22,dmg:7,pts:15},
tt:{n:'TikTok',c:'#ff2d6f',e:'🎵',hp:3,sp:80,r:23,dmg:10,pts:20,dash:1},
vpn:{n:'VPN',c:'#7c3aed',e:'🛡️',hp:3,sp:120,r:22,dmg:0,pts:40,flee:1},
boss:{n:'МЕГА-МЕССЕНДЖЕР',c:'#f59e0b',e:'👾',hp:40,sp:60,r:48,dmg:20,pts:300,boss:1}};
const U=[{id:'dmg',n:'Сила молота',d:'+1 урон за удар',max:10,base:50},{id:'reach',n:'Длина рукояти',d:'+8% дальность',max:8,base:80},{id:'hp',n:'Броня',d:'+20 макс. здоровья',max:10,base:60},{id:'spd',n:'Кроссовки',d:'+6% скорость',max:8,base:70},{id:'cd',n:'Быстрые руки',d:'быстрее замах',max:8,base:90},{id:'sp',n:'Заряд БАНа',d:'шкала растёт быстрее',max:8,base:100}];
const SK=[
{n:'Сталь',p:0,h:'#c9ccd3',s:'#8b5a2b',b:'#2b4c9b'},
{n:'Золото',p:5000,h:'#f2c14e',s:'#8b5a2b',b:'#8a6d1d',y:'#fff1b0',pp:'#5a4610',pc:['#f2c14e','#fff1b0'],cm:1.1,pk:'+10% монет'},
{n:'Неон',p:25000,h:'#39ff14',s:'#1b5a10',b:'#1b1b3a',y:'#39ff14',pp:'#0f0f28',pc:['#39ff14','#b6ff9e']},
{n:'Розовый',p:100000,h:'#ff5cf0',s:'#6a2a6a',b:'#7a1fa2',y:'#ffd6f7',pp:'#4a1266',pc:['#ff5cf0','#ffd6f7']},
{n:'Лава',p:1000000,h:'#ff5a1f',s:'#3a1a0a',b:'#7a1f0f',y:'#ffb703',pp:'#3a0f08',pc:['#ff5a1f','#ffb703','#ff2d2d']},
{n:'Лёд',p:10000000,h:'#7fe7ff',s:'#4a6b8a',b:'#3b82c4',y:'#e6faff',pp:'#1e4a80',pc:['#7fe7ff','#e6faff','#4dc3ff']},
{n:'Тьма',p:100000000,h:'#3a2a5a',s:'#1a1a22',b:'#241a3a',y:'#a06bff',pp:'#120c1e',pc:['#a06bff','#3a2a5a','#6b3fd4']},
{n:'Радуга',p:1000000000,rb:1,s:'#8b5a2b',b:'#4a3a8a',y:'#ffffff',pp:'#2a2060',pc:['#ff4d4d','#ffd23f','#5ee05e','#4dc3ff','#c77dff'],cm:1.25,pk:'+25% монет'},
{n:'МАНГО',p:3333333333,mango:1,s:'#5a3a1a',b:'#ff9f1c',y:'#3fb950',pp:'#d9480f',pc:['#ff5a36','#ff9f1c','#ffd23f','#9ad64a'],cm:1.5,db:1,pk:'Король-манго в очках и с цепью AURA! +50% монет, +1 урон'}];
const SC=SK.map(k=>k.p);
const CH=[
{n:'Инспектор',p:0,atk:'hammer',rng:145,arc:1.4,dm:1,kb:440,cd:.45,pc:['#fff'],d:'Огромный молот по дуге'},
{n:'Адмир',p:250000,atk:'burp',rng:260,arc:.6,dm:3,kb:900,cd:.8,pc:['#9be564','#c8f169','#5aa02c'],d:'СИЛЬНО РЫГАЕТ: узкий конус, огромный урон и отброс'},
{n:'Баба Валя',p:2000000,atk:'throw',rng:0,arc:0,dm:2,kb:300,cd:.4,pc:['#ffb703'],d:'Кидает два тапка веером'},
{n:'Качок Гена',p:15000000,atk:'stomp',rng:135,arc:4,dm:2,kb:600,cd:.55,pc:['#c9a26b'],d:'Топает так, что бьёт всех вокруг'}];
let coins=0,runCoins=0,L={dmg:0,reach:0,hp:0,spd:0,cd:0,sp:0},skin=0,owned=[1],used=[],msg='',cs=0,oc=[1],pr=[];
try{const d=JSON.parse(localStorage.getItem('rkn_save')||'{}');coins=d.coins||0;Object.assign(L,d.L||{});skin=d.skin||0;owned=d.owned||owned;used=d.used||[];cs=d.cs||0;oc=d.oc||oc}catch(e){}
function save(){try{localStorage.setItem('rkn_save',JSON.stringify({coins,L,skin,owned,used,cs,oc}))}catch(e){}}
const RM=()=>1+.08*L.reach,cost=(u,l)=>Math.round(u.base*Math.pow(1.75,l));
function fmt(n){const u=['','K','M','B','T','Qa'];let i=0;while(n>=1000&&i<5){n/=1000;i++}return i?n.toFixed(n<10?2:n<100?1:0)+u[i]:''+Math.floor(n)}
function shop(){
 let h='<h1>МАГАЗИН</h1><p>Монеты: <b>'+fmt(coins)+'</b></p><div class="it"><input id="pc" placeholder="Промокод"><button class="go sm" id="pb">ОК</button></div><p>'+msg+'</p>';
 U.forEach((u,i)=>{const l=L[u.id],mx=l>=u.max,c=cost(u,l);
  h+='<div class="it"><span>'+u.n+' '+l+'/'+u.max+'<br><small>'+u.d+'</small></span><button class="go sm" data-u="'+i+'"'+(mx||coins<c?' disabled':'')+'>'+(mx?'МАКС':fmt(c))+'</button></div>'});
 h+='<p>Персонажи</p>';CH.forEach((c,i)=>{h+='<div class="it"><span>'+c.n+'<br><small>'+c.d+'</small></span><button class="go sm" data-c="'+i+'"'+(cs==i||(!oc[i]&&coins<c.p)?' disabled':'')+'>'+(cs==i?'ВЫБРАН':oc[i]?'ВЗЯТЬ':fmt(c.p))+'</button></div>'});
 h+='<p>Скины <small>(молот Инспектора, бонусы у всех)</small></p>';
 SK.forEach((k,i)=>{h+='<div class="it"><span style="color:'+(k.mango?'#ff9f1c':k.rb?'#ff5cf0':k.h)+'">'+k.n+(k.pk?'<br><small>'+k.pk+'</small>':'')+'</span><button class="go sm" data-s="'+i+'"'+(skin==i||(!owned[i]&&coins<SC[i])?' disabled':'')+'>'+(skin==i?'ВЫБРАН':owned[i]?'ВЗЯТЬ':fmt(SC[i]))+'</button></div>'});
 h+='<button class="go" id="bk">Назад</button>';
 ov.innerHTML=h;
 $('bk').onclick=()=>{msg='';ov.innerHTML=menuHTML;bind()};
 $('pb').onclick=()=>{const c=$('pc').value.trim().toLowerCase();
  if(c==='кирилл'){if(used.includes(c))msg='Промокод уже использован';else{used.push(c);coins+=10000000000000000;msg='Активировано! +10 000 000 000 000 000 монет';save()}}else msg='Неверный промокод';shop()};
 ov.querySelectorAll('[data-u]').forEach(b=>b.onclick=()=>{const u=U[b.dataset.u],c=cost(u,L[u.id]);if(coins>=c&&L[u.id]<u.max){coins-=c;L[u.id]++;msg='';save();shop()}});
 ov.querySelectorAll('[data-c]').forEach(b=>b.onclick=()=>{const i=+b.dataset.c,c=CH[i];if(oc[i]){cs=i}else if(coins>=c.p){coins-=c.p;oc[i]=1;cs=i}else return;msg='';save();shop()});
 ov.querySelectorAll('[data-s]').forEach(b=>b.onclick=()=>{const i=+b.dataset.s;if(owned[i]){skin=i}else if(coins>=SC[i]){coins-=SC[i];owned[i]=1;skin=i}else return;msg='';save();shop()});
}
let en=[],ps=[],tx=[],rg=[],p,score,combo,ct,wave,q,sq,run=false,shake=0,flash=0,banner=0,best=0,last=0,bt='';
try{best=+localStorage.getItem('rkn_best2')||0}catch(e){}
const keys={};let joy=null;
function nextWave(){
 wave++;banner=2.2;q=[];const n=3+wave*2,pool=['tg','dc'];
 if(wave>=2)pool.push('yt');if(wave>=3)pool.push('tt');
 for(let i=0;i<n;i++)q.push(Math.random()<.1&&wave>=2?'vpn':pool[Math.random()*pool.length|0]);
 if(wave%5==0)q.splice(q.length>>1,0,'boss');
 bt=wave%5==0?'БОСС: МЕГА-МЕССЕНДЖЕР':'Волна '+wave;sq=1;
}
function reset(){p={x:W/2,y:H/2,hp:100+20*L.hp,mh:100+20*L.hp,face:0,sw:-1,cd:0,inv:0,m:0,hit:0,vx:0,vy:0};en=[];ps=[];tx=[];rg=[];pr=[];score=0;runCoins=0;combo=0;ct=0;wave=0;nextWave()}
function spawn(k){
 const s=Math.random()*4|0,t=ET[k];let X,Y;
 if(s==0){X=-50;Y=Math.random()*H}else if(s==1){X=W+50;Y=Math.random()*H}else if(s==2){X=Math.random()*W;Y=-50}else{X=Math.random()*W;Y=H+50}
 const hp=Math.ceil(t.hp*(1+wave*.06));
 en.push({k,t,x:X,y:Y,hp,mx:hp,kx:0,ky:0,st:0,fl:0,ph:Math.random()*6,dt:2+Math.random()*2,dash:0,life:0});
}
function burst(X,Y,c,n){for(let i=0;i<n;i++){const a=Math.random()*6.28,v=120+Math.random()*320;ps.push({x:X,y:Y,vx:Math.cos(a)*v,vy:Math.sin(a)*v,c,z:S*(1+(Math.random()*2|0)),l:1})}}
function txt(s,X,Y,c){tx.push({s,x:X,y:Y,c,l:1})}
function near(){let b=null,bd=1e9;for(const e of en){if(e.t.flee)continue;const d=Math.hypot(e.x-p.x,e.y-p.y);if(d<bd){bd=d;b=e}}return b||en[0]}
function hurt(dmg,ux,uy){p.hp-=dmg;p.inv=.7;p.vx=ux*420;p.vy=uy*420;shake=Math.max(shake,10);flash=1;if(p.hp<=0)over()}
function kill(e){
 e.dead=1;burst(e.x,e.y,e.t.c,e.t.boss?40:14);combo++;ct=3;
 const m=Math.min(5,1+(combo/3|0)),pts=e.t.pts*m;score+=pts;const cg=Math.round(pts*(SK[skin].cm||1));coins+=cg;runCoins+=cg;save();p.m=Math.min(100,p.m+8*(1+.15*L.sp));
 txt('ЗАБЛОКИРОВАН +'+pts,e.x,e.y,'#ffd166');
 if(e.t.flee){p.hp=Math.min(p.mh,p.hp+20);txt('+20 HP',e.x,e.y-22,'#7CFC9A')}
 if(e.t.boss)shake=26;
}
function dmg(e,d,ux,uy,kb){
 e.hp-=d;e.fl=1;e.st=e.t.boss?.08:.35;e.kx+=ux*kb;e.ky+=uy*kb;
 p.m=Math.min(100,p.m+10*(1+.15*L.sp));burst(e.x,e.y,e.t.c,6);{const K=SK[skin];if(K.pc)for(let i=0;i<8;i++)burst(e.x,e.y,K.pc[i%K.pc.length],1)}shake=Math.max(shake,e.t.boss?9:6);
 if(e.hp<=0)kill(e);else if(Math.random()<.4)txt('БАМ!',e.x,e.y-e.t.r,'#fff');
}
function strike(){
 const C=CH[cs],R=RM(),K=SK[skin],col=K.pc||C.pc;
 if(C.atk==='throw'){for(const o of[-.14,.14]){const a=p.face+o;pr.push({x:p.x,y:p.y,vx:Math.cos(a)*650,vy:Math.sin(a)*650,l:1.3})}return}
 if(C.atk==='burp'){shake=Math.max(shake,12);txt('БУУУРП!',p.x+Math.cos(p.face)*90,p.y+Math.sin(p.face)*90,'#9be564');
  for(let i=0;i<26;i++){const a=p.face+(Math.random()-.5)*1.1,v=250+Math.random()*450;ps.push({x:p.x+Math.cos(p.face)*30,y:p.y+Math.sin(p.face)*30,vx:Math.cos(a)*v,vy:Math.sin(a)*v,c:col[i%col.length],z:S*(2+(Math.random()*3|0)),l:1.2})}}
 if(C.atk==='stomp'){rg.push({x:p.x,y:p.y,r:20,l:.6});shake=Math.max(shake,10)}
 for(const e of en){
  const dx=e.x-p.x,dy=e.y-p.y,d=Math.hypot(dx,dy)||1;
  if(d>C.rng*R+e.t.r)continue;
  let da=Math.atan2(dy,dx)-p.face;da=Math.atan2(Math.sin(da),Math.cos(da));
  if(Math.abs(da)>C.arc)continue;
  dmg(e,C.dm+L.dmg+(K.db||0),dx/d,dy/d,e.t.boss?C.kb*.32:C.kb);
 }
 en=en.filter(e=>!e.dead);
}
function atk(){if(!run||p.sw>=0||p.cd>0)return;const n=near();if(n)p.face=Math.atan2(n.y-p.y,n.x-p.x);p.sw=0;p.hit=0;p.cd=CH[cs].cd*(1-.07*L.cd)}
function spc(){
 if(!run||p.m<100)return;p.m=0;rg.push({x:p.x,y:p.y,r:20,l:1});shake=24;
 for(const e of en){const dx=e.x-p.x,dy=e.y-p.y,d=Math.hypot(dx,dy)||1;if(d<240+e.t.r)dmg(e,5,dx/d,dy/d,800)}
 en=en.filter(e=>!e.dead);txt('БАН!',p.x,p.y-60,'#f59e0b');
}
function begin(){reset();run=true;ov.style.display='none';$('atk').style.display=$('spc').style.display='flex';last=performance.now()}
function over(){
 run=false;$('atk').style.display=$('spc').style.display='none';
 if(score>best){best=score;try{localStorage.setItem('rkn_best2',best)}catch(e){}}
 ov.innerHTML='<div class="stamp">ДОСТУП ОГРАНИЧЕН</div><p>Очки: <b>'+score+'</b> · Волна: <b>'+wave+'</b></p><p>Рекорд: '+best+'</p><p>Монеты за бой: +'+fmt(runCoins)+'</p><button class="go" id="go">Ещё раз</button><button class="go" id="shp">МАГАЗИН</button>';
 menuHTML=ov.innerHTML;ov.style.display='flex';bind();
}
let menuHTML=ov.innerHTML;function bind(){$('go').onclick=begin;$('shp').onclick=shop}bind();
for(const [id,f] of [['atk',atk],['spc',spc]])$(id).addEventListener('pointerdown',e=>{e.preventDefault();f()});
cv.addEventListener('pointerdown',e=>{
 if(e.pointerType==='mouse'){atk();return}
 if(!joy&&e.clientX<W*.65){joy={id:e.pointerId,ox:e.clientX,oy:e.clientY,cx:e.clientX,cy:e.clientY};cv.setPointerCapture(e.pointerId)}
});
cv.addEventListener('pointermove',e=>{if(joy&&e.pointerId===joy.id){joy.cx=e.clientX;joy.cy=e.clientY}});
const up=e=>{if(joy&&e.pointerId===joy.id)joy=null};
cv.addEventListener('pointerup',up);cv.addEventListener('pointercancel',up);
addEventListener('keydown',e=>{if(e.target.tagName==='INPUT')return;keys[e.code]=1;if(e.code==='Space'){e.preventDefault();atk()}if(e.code==='KeyE')spc()});
addEventListener('keyup',e=>{keys[e.code]=0});
const M='oaaaaaaaaaaaaaao',BODY=['..oooooooooooo..','.oaaaaaaaaaaaao.','oaakkaaaaaakkaao','oaaakkaaaakkaaao','oaaawkaaaakwaaao','oaaawwaaaawwaaao',M,M,M,M,M,M,M,M,'.oaaaaaaaaaaaao.','..oooooooooooo..'];
const GL={tg:['....ww','.wwwww','wwwww.','..ww..','...w..'],yt:['ww....','wwww..','wwwwww','wwww..','ww....'],dc:['.wwww.','wwwwww','w.ww.w','wwwwww','.w..w.'],tt:['..wwww','..w..w','..w...','ww.ww.','ww.ww.'],vpn:['wwwwww','wwwwww','wwwwww','.wwww.','..ww..'],boss:['w.ww.w','wwwwww','ww..ww','wwwwww','.w..w.']};
const PL=['....oooooooo....','...obbbbbbbbo...','..obbbbbbbbbbo..','..oyyyyyyyyyyo..','..osssssssssso..','..osksssssskso..','..osssssssssso..','..osssmmmmssso..','..oobbbbbbbboo..','.obbbbbbbbbbbbo.','.obbbyyyybbbbbo.','.obbbbbbbbbbbbo.','..obbbbbbbbbbo..','...oppo..oppo...','...oppo..oppo...','..oooooo.oooooo.'];
function mk(rows,pal,gl){
 const c=document.createElement('canvas');c.width=c.height=16;const g=c.getContext('2d');
 rows.forEach((r,j)=>[...r].forEach((ch,i)=>{if(pal[ch]){g.fillStyle=pal[ch];g.fillRect(i,j,1,1)}}));
 if(gl)gl.forEach((r,j)=>[...r].forEach((ch,i)=>{if(ch=='w'){g.fillStyle='#fff';g.fillRect(i+5,j+8,1,1)}}));
 const f=document.createElement('canvas');f.width=f.height=16;const h=f.getContext('2d');
 h.drawImage(c,0,0);h.globalCompositeOperation='source-in';h.fillStyle='#fff';h.fillRect(0,0,16,16);return[c,f];
}
const SP={};for(const k in ET)SP[k]=mk(BODY,{o:'#0b0b12',a:ET[k].c,w:'#fff',k:'#0b0b12'},GL[k]);
const SPL=SK.map(k=>mk(PL,{o:'#0b0b12',b:k.b,y:k.y||'#f2c14e',s:'#f1c9a0',k:'#0b0b12',m:'#b03030',p:k.pp||'#1d2f66'}));
const ADM=['....oooooooo....','...okkkkkkkko...','..okkkkkkkkkko..','..osssssssssso..','..osksssssskso..','..osssssssssso..','..osmmmmmmmmso..','..osmmmmmmmmso..','..ooossssssooo..','.obbbbbbbbbbbbo.','obbbbbbbbbbbbbbo','obbbbbbbbbbbbbbo','obbbbbbbbbbbbbbo','.obbbbbbbbbbbbo.','..oppo....oppo..','..oooo....oooo..'];
const VAL=['....oooooooo....','...orrrrrrrro...','..orrrrrrrrrro..','..orssssssssro..','..orskssssksro..','..orssssssssro..','..orssmmmmssro..','..osssssssssso..','..oobbbbbbbboo..','.obbbwbbbbwbbbo.','.obbbbbbbbbbbbo.','.obbwbbbbbbwbbo.','..obbbbbbbbbbo..','...osso..osso...','...osso..osso...','..oppppo.oppppo.'];
const GEN=['....oooooooo....','...osssssssso...','..osssssssssso..','..oskksssskkso..','..osksssssskso..','..osssssssssso..','..ossmmmmmssso..','...osssssssso...','osssbbbbbbbbssso','osssbbbbbbbbssso','osssbbbbbbbbssso','.ossbbbbbbbbsso.','..obbbbbbbbbbo..','...opppoopppo...','...opppoopppo...','..oooooooooooo..'];
const SPC=[null,mk(ADM,{o:'#0b0b12',b:'#5fb84a',k:'#2a1a10',m:'#8a1a1a',p:'#2a3a6a',s:'#f1c9a0'}),mk(VAL,{o:'#0b0b12',b:'#3a6ea5',w:'#fff',r:'#d23c3c',m:'#b03030',k:'#0b0b12',p:'#ffb703',s:'#f1c9a0'}),mk(GEN,{o:'#0b0b12',b:'#e5e5e5',k:'#0b0b12',m:'#802020',p:'#2a2a2a',s:'#e0a070'})];
function mkMango(f){
 const N=28,c=document.createElement('canvas');c.width=c.height=N;const g=c.getContext('2d');
 const r=(X,Y,w,h,col)=>{g.fillStyle=col;g.fillRect(X,Y,w,h)};
 const crown=(ox,oy,col)=>{r(13+ox,0+oy,2,3,col);r(9+ox,1+oy,2,2,col);r(17+ox,1+oy,2,2,col);r(9+ox,3+oy,10,2,col)};
 [[-1,0],[1,0],[0,-1],[0,1]].forEach(o=>crown(o[0],o[1],'#0b0b12'));
 for(let Y=4;Y<26;Y++)for(let X=0;X<N;X++){
  const dx=X+.5-14+(Y-14)*.1,dy=Y+.5-14.5,v=dx*dx/144+dy*dy/100;
  if(v>1)continue;
  if(v>.82){r(X,Y,1,1,'#0b0b12');continue}
  const q=dx/12*.6+dy/10*.8;
  r(X,Y,1,1,q<-.55?'#9ad64a':q<-.2?'#ffd23f':q<.35?'#ff9f1c':'#ff5a36');
 }
 r(0,14,5,5,'#0b0b12');r(1,15,3,3,'#ff9f1c');r(23,14,5,5,'#0b0b12');r(24,15,3,3,'#ff9f1c');
 r(7,25,6,3,'#0b0b12');r(8,25,4,2,'#b34a1a');r(15,25,6,3,'#0b0b12');r(16,25,4,2,'#b34a1a');
 r(5,12,2,2,'#ff7a7a');r(21,12,2,2,'#ff7a7a');
 r(19,4,4,2,'#2f9e44');r(22,3,2,1,'#57c25b');r(21,6,2,1,'#57c25b');
 crown(0,0,'#ffd23f');r(9,4,10,1,'#e0a800');
 r(10,3,1,1,'#4dc3ff');r(13,3,2,1,'#ff2d2d');r(17,3,1,1,'#4dc3ff');
 for(let X=5;X<=22;X++){const t=(X-13.5)/8.5,Y=15+Math.round(3*(1-t*t));r(X,Y,1,2,X%2?'#ffd23f':'#e0a800');r(X,Y+2,1,1,'#0b0b12')}
 r(5,18,18,7,'#0b0b12');r(6,19,16,5,'#ffd23f');r(6,23,16,1,'#e0a800');
 const FN={A:['010','101','111','101','101'],U:['101','101','101','101','111'],R:['110','101','110','101','101']};
 'AURA'.split('').forEach((ch,i)=>FN[ch].forEach((row,j)=>[...row].forEach((v,k)=>{if(v=='1')r(6+i*4+k,19+j,1,1,'#0b0b12')})));
 r(4,9,2,1,'#ffd23f');r(22,9,2,1,'#ffd23f');r(12,9,4,1,'#ffd23f');
 r(6,8,6,4,'#ffd23f');r(16,8,6,4,'#ffd23f');r(7,9,4,2,'#0b0b12');r(17,9,4,2,'#0b0b12');
 r(7,9,1,1,'#7fe7ff');r(17,9,1,1,'#7fe7ff');r(10,10,1,1,'#2a4a9a');r(20,10,1,1,'#2a4a9a');
 if(f==1){r(8,7,1,5,'#fff');r(6,9,5,1,'#fff')}
 if(f==2){r(6,6,3,1,'#0b0b12');r(9,7,3,1,'#0b0b12');r(19,6,3,1,'#0b0b12');r(16,7,3,1,'#0b0b12')}
 if(f==2){r(11,14,6,2,'#3a0a0a');r(12,16,4,1,'#ff6b8a')}
 else{r(10,14,1,1,'#0b0b12');r(17,14,1,1,'#0b0b12');r(11,15,6,1,'#0b0b12')}
 return c;
}
const SPM=[0,1,2].map(mkMango);
function drawE(e){
 const sc=e.t.boss?2:1,z=16*S*sc,b=Math.round(Math.sin(e.ph))*S,s=SP[e.k];
 x.fillStyle='rgba(0,0,0,.35)';x.fillRect(sn(e.x-z/2+6),sn(e.y+z/2-9),z-12,9);
 x.drawImage(e.fl>.5?s[1]:s[0],sn(e.x-z/2),sn(e.y-z/2)+b,z,z);
 if(e.dash>.5){x.strokeStyle='#ff3b3b';x.lineWidth=6;x.strokeRect(sn(e.x-z/2),sn(e.y-z/2),z,z)}
 x.fillStyle='#000';x.fillRect(sn(e.x-z/2),sn(e.y+z/2+6),z,6);
 x.fillStyle='#e5383b';x.fillRect(sn(e.x-z/2),sn(e.y+z/2+6),z*Math.max(0,e.hp)/e.mx,6);
 if(e.t.boss){x.fillStyle='#fff';x.font='bold 21px "Courier New",monospace';x.textAlign='center';x.fillText(e.t.n,e.x,e.y+z/2+34)}
}
function drawP(){
 const C=CH[cs],K=SK[skin],sw=p.sw>=0?p.sw/.28:0,ease=sw*sw*(3-2*sw),ang=p.face-1.4+(p.sw>=0?ease*2.8:0),R=RM();
 x.fillStyle='rgba(0,0,0,.35)';x.fillRect(sn(p.x-(K.mango?36:21)),sn(p.y+(K.mango?26:15)),K.mango?72:42,9);
 if(K.mango){x.fillStyle='rgba(255,159,28,'+(.18+.08*Math.sin(last/150))+')';x.fillRect(sn(p.x-33),sn(p.y+9),66,15);x.fillRect(sn(p.x-24),sn(p.y+3),48,27)}
 if(C.atk==='burp'&&p.sw>=0){x.fillStyle='rgba(155,229,100,.28)';x.beginPath();x.moveTo(p.x,p.y);x.arc(p.x,p.y,C.rng*R*(.4+.6*sw),p.face-C.arc,p.face+C.arc);x.closePath();x.fill()}
 if(C.atk==='hammer'){
  if(p.sw>=0){const tc=K.pc||['#fff'];tc.forEach((c,i)=>{x.strokeStyle=c;x.globalAlpha=.55;x.lineWidth=K.pc?9:15;x.beginPath();x.arc(p.x,p.y,(115-i*9)*R,p.face-1.4,ang);x.stroke()});x.globalAlpha=1}
  x.save();x.translate(sn(p.x),sn(p.y));x.rotate(ang);x.scale(R,R);
  x.fillStyle=K.s;x.strokeStyle='#0b0b12';x.lineWidth=3;x.fillRect(10,-6,90,12);x.strokeRect(10,-6,90,12);
  if(K.mango){['#ff5a36','#ff9f1c','#ffd23f','#9ad64a'].forEach((c,i)=>{x.fillStyle=c;x.fillRect(90+i*12,-30,i==3?9:12,60)});
   x.fillStyle='#2f9e44';x.fillRect(100,-42,15,12);x.fillStyle='#57c25b';x.fillRect(106,-48,9,9);
   x.fillStyle='rgba(255,255,255,.6)';x.fillRect(96,-22,6,15)}
  else{x.fillStyle=K.rb?'hsl('+(last/4%360|0)+',90%,60%)':K.h;x.fillRect(90,-30,45,60);x.fillStyle='rgba(0,0,0,.25)';x.fillRect(90,-9,45,18)}
  x.strokeRect(90,-30,45,60);
  x.restore();
 }
 if(!(p.inv>0&&(p.inv*20|0)%2)){
  const jy=C.atk==='stomp'&&p.sw>=0?-Math.round(Math.sin(sw*Math.PI)*15/S)*S:0,ox=C.atk==='burp'&&p.sw>=0?-Math.round(Math.cos(p.face)*6/S)*S:0;
  if(K.mango){const fr=p.sw>=0?2:((last/1000)%3<.14?1:0),bb=Math.round(Math.sin(last/220))*S;x.drawImage(SPM[fr],sn(p.x-42)+ox,sn(p.y-50)+jy+bb,84,84)}
  else x.drawImage((cs?SPC[cs]:SPL[skin])[0],sn(p.x-24)+ox,sn(p.y-24)+jy,48,48)}
}
function loop(now){
 requestAnimationFrame(loop);
 const dt=Math.min((now-last)/1000||0,.05);last=now;
 if(run){
  let mx=(keys.KeyD||keys.ArrowRight?1:0)-(keys.KeyA||keys.ArrowLeft?1:0),my=(keys.KeyS||keys.ArrowDown?1:0)-(keys.KeyW||keys.ArrowUp?1:0);
  if(joy){mx=(joy.cx-joy.ox)/50;my=(joy.cy-joy.oy)/50}
  const ml=Math.hypot(mx,my);if(ml>1){mx/=ml;my/=ml}
  const sv=220*(1+.06*L.spd);p.x+=(mx*sv+p.vx)*dt;p.y+=(my*sv+p.vy)*dt;p.vx*=Math.pow(.01,dt);p.vy*=Math.pow(.01,dt);
  p.x=Math.max(22,Math.min(W-22,p.x));p.y=Math.max(70,Math.min(H-22,p.y));
  p.inv-=dt;p.cd-=dt;
  if(p.sw>=0){p.sw+=dt;{const K=SK[skin];if(K.pc&&CH[cs].atk==='hammer'){const w=Math.min(1,p.sw/.28),a=p.face-1.4+w*w*(3-2*w)*2.8;burst(p.x+Math.cos(a)*112*RM(),p.y+Math.sin(a)*112*RM(),K.pc[Math.random()*K.pc.length|0],K.mango?3:1)}}if(!p.hit&&p.sw>.13){p.hit=1;strike()}if(p.sw>.28)p.sw=-1}
  else{const n=near();if(n)p.face=Math.atan2(n.y-p.y,n.x-p.x);else if(ml>.1)p.face=Math.atan2(my,mx)}
  ct-=dt;if(ct<=0)combo=0;if(SK[skin].mango&&Math.random()<.2)burst(p.x+(Math.random()-.5)*40,p.y+20,'#ffd23f',1);
  for(const e of en){
   e.life+=dt;e.ph+=dt*8;e.fl=Math.max(0,e.fl-dt*5);
   const dx=p.x-e.x,dy=p.y-e.y,d=Math.hypot(dx,dy)||1,fx=dx/d,fy=dy/d;
   if(e.st>0)e.st-=dt;
   else{
    let sp=e.t.sp*(1+wave*.02),ux=fx,uy=fy;
    if(e.t.flee){if(d<300){ux=-fx-fy*.6;uy=-fy+fx*.6}else{ux=-fy*.5;uy=fx*.5}}
    if(e.t.dash){e.dt-=dt;if(e.dt<0&&e.dash<=0){e.dash=.9;e.dt=3+Math.random()*2}
     if(e.dash>0){e.dash-=dt;sp=e.dash>.5?0:sp*4}}
    e.x+=ux*sp*dt;e.y+=uy*sp*dt;
   }
   e.x+=e.kx*dt;e.y+=e.ky*dt;const k=Math.pow(.02,dt);e.kx*=k;e.ky*=k;
   if(e.t.flee){e.x=Math.max(20,Math.min(W-20,e.x));e.y=Math.max(70,Math.min(H-20,e.y));if(e.life>10)e.dead=1}
   if(e.t.dmg&&d<e.t.r+16&&p.inv<=0&&e.st<=0)hurt(e.t.dmg,fx,fy);
  }
  for(let i=0;i<en.length;i++)for(let j=i+1;j<en.length;j++){
   const a=en[i],b=en[j],dx=b.x-a.x,dy=b.y-a.y,d=Math.hypot(dx,dy)||1,m=a.t.r+b.t.r;
   if(d<m){const f=(m-d)/2/d;a.x-=dx*f;a.y-=dy*f;b.x+=dx*f;b.y+=dy*f}
  }
  for(const b of pr){b.x+=b.vx*dt;b.y+=b.vy*dt;b.l-=dt;for(const e of en){if(e.dead)continue;if(Math.hypot(e.x-b.x,e.y-b.y)<e.t.r+12){const d=Math.hypot(b.vx,b.vy);dmg(e,2+L.dmg+(SK[skin].db||0),b.vx/d,b.vy/d,e.t.boss?100:350);b.l=0;break}}}
  pr=pr.filter(b=>b.l>0&&b.x>-40&&b.x<W+40&&b.y>-40&&b.y<H+40);
  en=en.filter(e=>!e.dead);
  if(q.length&&(sq-=dt)<=0){spawn(q.shift());sq=Math.max(.35,.9-wave*.03)}
  if(!q.length&&!en.some(e=>!e.t.flee)){en=[];p.hp=Math.min(p.mh,p.hp+15);nextWave()}
  $('spc').className='b'+(p.m>=100?' rdy':'');
 }
 for(const s of ps){s.x+=s.vx*dt;s.y+=s.vy*dt;s.vx*=.96;s.vy*=.96;s.l-=dt*1.6}
 ps=ps.filter(s=>s.l>0);
 for(const t of tx){t.y-=40*dt;t.l-=dt*.9}tx=tx.filter(t=>t.l>0);
 for(const r of rg){r.r+=700*dt;r.l-=dt*2}rg=rg.filter(r=>r.l>0);
 shake=Math.max(0,shake-dt*45);flash=Math.max(0,flash-dt*2.5);banner=Math.max(0,banner-dt);
 x.save();
 if(shake>0)x.translate((Math.random()-.5)*shake,(Math.random()-.5)*shake);
 for(let j=0;j*48<H+48;j++)for(let i=0;i*48<W+48;i++){x.fillStyle=(i+j)%2?'#161b2b':'#12172a';x.fillRect(i*48,j*48,48,48);if((i*7+j*13)%5==0){x.fillStyle='#1f2640';x.fillRect(i*48+18,j*48+18,6,6)}}
 if(p){
  for(const r of rg){x.strokeStyle='rgba(245,158,11,'+r.l+')';x.lineWidth=12;x.beginPath();x.arc(r.x,r.y,r.r,0,7);x.stroke()}
  for(const e of en.slice().sort((a,b)=>a.y-b.y))drawE(e);
  for(const s of ps){x.globalAlpha=Math.max(0,s.l);x.fillStyle=s.c;x.fillRect(s.x,s.y,s.z,s.z)}
  for(const b of pr){x.save();x.translate(sn(b.x),sn(b.y));x.rotate(b.l*20);x.fillStyle='#ffb703';x.fillRect(-12,-6,24,12);x.fillStyle='#d97706';x.fillRect(-12,-6,24,4);x.strokeStyle='#0b0b12';x.lineWidth=3;x.strokeRect(-12,-6,24,12);x.restore()}
  x.globalAlpha=1;drawP();
  x.font='bold 21px "Courier New",monospace';x.textAlign='center';
  for(const t of tx){x.globalAlpha=Math.max(0,t.l);x.fillStyle=t.c;x.fillText(t.s,Math.min(W-90,Math.max(90,t.x)),t.y)}
  x.globalAlpha=1;
  if(joy){x.strokeStyle='#fff5';x.lineWidth=3;x.beginPath();x.arc(joy.ox,joy.oy,50,0,7);x.stroke();
   const a=Math.atan2(joy.cy-joy.oy,joy.cx-joy.ox),l=Math.min(50,Math.hypot(joy.cx-joy.ox,joy.cy-joy.oy));
   x.fillStyle='#fff6';x.beginPath();x.arc(joy.ox+Math.cos(a)*l,joy.oy+Math.sin(a)*l,22,0,7);x.fill()}
  const T=44;x.textAlign='left';
  x.fillStyle='#0008';x.fillRect(14,T,160,14);x.fillStyle=p.hp>p.mh*.3?'#3ddc84':'#e5383b';x.fillRect(14,T,160*Math.max(0,p.hp)/p.mh,14);
  x.fillStyle='#0008';x.fillRect(14,T+18,160,8);x.fillStyle='#f59e0b';x.fillRect(14,T+18,160*p.m/100,8);
  x.fillStyle='#ffd166';x.font='bold 21px "Courier New",monospace';x.textAlign='left';x.fillText('$'+fmt(coins),14,T+52);x.fillStyle='#fff';x.textAlign='right';
  x.fillText('Очки:'+score,W-14,T+16);x.fillText('Волна '+wave,W-14,T+40);
  if(combo>1){x.fillStyle='#ffd166';x.fillText('Комбо ×'+Math.min(5,1+(combo/3|0)),W-14,T+64)}
  if(banner>0&&run){x.globalAlpha=Math.min(1,banner);x.fillStyle='#e5383b';x.font='bold 45px "Courier New",monospace';x.textAlign='center';x.fillText(bt,W/2,H*.3);x.globalAlpha=1}
 }
 if(flash>0){x.fillStyle='rgba(229,56,59,'+flash*.35+')';x.fillRect(-30,-30,W+60,H+60)}
 x.restore();
}
requestAnimationFrame(t=>{last=t;loop(t)});
</script></body></html>

Game Source: Молот Роскомнадзора: Драка

Creator: EpicKoala43

Libraries: none

Complexity: complex (299 lines, 26.5 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-epickoala43" to link back to the original. Then publish at arcadelab.ai/publish.