๐ŸŽฎArcadeLab

Chicken Quest: WWI Trench Defence

by AtomicFlame49
231 lines19.4 KB
โ–ถ Play

<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width,initial-scale=1,maximum-scale=1,user-scalable=no">
<title>Chicken Quest: WWI Trench Defence</title>
<style>
*{box-sizing:border-box}
body{margin:0;background:#151710;color:#fff;font-family:system-ui,Arial,sans-serif;overflow:hidden;touch-action:manipulation}
#game{display:block;width:100%;height:100dvh;object-fit:contain;background:#554c38;touch-action:none}
#hud{position:fixed;top:7px;left:8px;right:8px;display:flex;gap:6px;flex-wrap:wrap;pointer-events:none}
.stat{background:linear-gradient(#59472c,#211c14);border:3px solid #9d8050;border-radius:10px;padding:5px 10px;font-weight:900;text-shadow:1px 2px #000;box-shadow:0 2px 4px #000;min-width:100px}
#health{color:#ff5a45}#ammo{color:#ffe5a2}
#mission{flex:1;min-width:145px}
#objective{position:fixed;right:9px;top:95px;background:#392a17dd;border:3px solid #b18b49;border-radius:8px;padding:8px;font-weight:900;text-align:center;max-width:155px;text-shadow:1px 2px #000}
#allies{position:fixed;left:8px;top:100px;width:100px;background:#302719ed;border:3px solid #9b7746;border-radius:10px;padding:7px;font-size:12px}
#allies div{margin:7px 0}
#bottom{position:fixed;bottom:7px;left:8px;right:8px;display:grid;grid-template-columns:repeat(9,minmax(0,1fr));gap:5px}
.action{border:3px solid #b49a63;border-radius:12px;background:linear-gradient(#62733b,#29351d);color:white;min-width:0;min-height:66px;padding:5px 2px;font-weight:900;font-size:clamp(10px,1.7vw,16px);text-shadow:1px 2px #000;box-shadow:0 3px #15130c;cursor:pointer}
.action .emoji{display:block;font-size:clamp(20px,3vw,32px);margin-bottom:2px}
.action.active{background:linear-gradient(#a68137,#59401b);border-color:#ffe29a}
.action:active{transform:translateY(2px)}
#notice{position:fixed;top:28%;left:50%;transform:translateX(-50%);font-weight:1000;font-size:clamp(18px,4vw,35px);color:#ffe36e;text-shadow:2px 3px #000;text-align:center;pointer-events:none}
#pad{position:fixed;bottom:100px;left:12px;width:92px;height:92px;border-radius:50%;background:#a4a78a55;border:3px solid #ded0a777;display:grid;place-items:center;color:white;font-size:25px;touch-action:none}
#fire{position:fixed;right:15px;bottom:105px;border-radius:50%;width:83px;height:83px;border:4px solid #e4c27a;background:#842b20dd;color:white;font-size:16px;font-weight:1000;touch-action:none}
#menu{display:none;position:fixed;inset:12%;background:#292719f5;border:4px solid #b79a5e;border-radius:18px;padding:20px;text-align:center;overflow:auto}
#menu button{padding:12px;margin:5px;border-radius:8px;background:#61743a;color:white;font-weight:bold;border:2px solid #c8b27a}
@media(max-width:650px){
 .stat{padding:4px 6px;min-width:0;font-size:11px}
 #hud{gap:3px}
 #allies{top:100px;width:75px;font-size:10px;padding:4px}
 #objective{top:105px;max-width:110px;font-size:11px}
 #bottom{grid-template-columns:repeat(5,minmax(0,1fr));gap:3px;bottom:3px}
 .action{min-height:44px;padding:2px;font-size:10px;border-width:2px}
 .action .emoji{font-size:18px;display:inline;margin-right:2px}
 #pad{bottom:120px;width:65px;height:65px}
 #fire{bottom:120px;width:68px;height:68px}
}
</style>
</head>
<body>
<canvas id="game"></canvas>
<div id="hud">
 <div class="stat">๐Ÿ” CHICKEN QUEST</div>
 <div class="stat" id="health">โค๏ธ Health: 100/100</div>
 <div class="stat" id="ammo">๐Ÿ”ซ Ammo: 30/30</div>
 <div class="stat" id="coins">๐Ÿฅš Coins: 0</div>
 <div class="stat" id="wave">โ˜ ๏ธ Wave: 1</div>
 <div class="stat" id="mission">๐Ÿช– Campaign</div>
</div>
<div id="allies"><b>ALLIES</b><div>๐Ÿช– <span id="allyCount">1 soldier</span></div><div>โœš <span id="medCount">0 medics</span></div><div>๐ŸŸข <span id="allyHealth">Ready</span></div></div>
<div id="objective">๐ŸŽฏ OBJECTIVE<br><span id="objectiveText">Survive the fox assault!</span><hr><span id="weather">๐ŸŒง๏ธ Rain</span></div>
<div id="notice">DEFEND THE TRENCH!</div>
<div id="pad">โœฅ</div><button id="fire">FIRE!</button>
<div id="bottom">
 <button class="action active" data-weapon="Rifle"><span class="emoji">๐Ÿ”ซ</span>Rifle</button>
 <button class="action" data-weapon="Machine Gun"><span class="emoji">โš™๏ธ</span>Machine Gun</button>
 <button class="action" data-weapon="Submachine Gun"><span class="emoji">๐Ÿ’ฅ</span>Submachine Gun</button>
 <button class="action" data-weapon="Shotgun"><span class="emoji">๐Ÿชต</span>Shotgun</button>
 <button class="action" id="grenade"><span class="emoji">๐Ÿ’ฃ</span>Grenade</button>
 <button class="action" id="artillery"><span class="emoji">๐Ÿ’ฅ</span>Artillery</button>
 <button class="action" id="medic"><span class="emoji">โœš</span>Medic</button>
 <button class="action" id="upgrade"><span class="emoji">๐Ÿฅš</span>Upgrade</button>
 <button class="action" id="menuBtn"><span class="emoji">โš™๏ธ</span>Menu</button>
</div>
<div id="menu"><h1>๐Ÿ” TRENCH COMMAND</h1><p>Choose your battle mode</p><button onclick="newGame('Campaign')">Campaign</button><button onclick="newGame('Endless Survival')">Endless Survival</button><button onclick="newGame('Sandbox')">Sandbox</button><button onclick="closeMenu()">Return to Battle</button><p>Move with the left pad or WASD. Tap the battlefield to aim. Hold FIRE to shoot.</p></div>
<script>
(()=>{
const c=document.getElementById('game'),ctx=c.getContext('2d');
const $=id=>document.getElementById(id);
let W=1000,H=650,scale=1;
function resize(){const d=devicePixelRatio||1;W=innerWidth;H=innerHeight;c.width=W*d;c.height=H*d;c.style.width=W+'px';c.style.height=H+'px';ctx.setTransform(d,0,0,d,0,0);scale=d}
addEventListener('resize',resize);resize();
let mode='Campaign',weapon='Rifle',health=100,maxHealth=100,ammo=30,mag=30,coins=0,wave=1,kills=0;
let player={x:.31,y:.69,dir:1},foxes=[],shots=[],stains=[],effects=[],allies=[],rain=[],keys={};
let moving={x:0,y:0},aim={x:.7,y:.6},shooting=false,dead=false,bossSpawned=false;
let fireRate=0,shake=0,weather='Rain',weatherTime=0,upgradeLevel=0;
const weapons={
 'Rifle':{damage:28,rate:340,ammo:30,spread:.025,speed:.85},
 'Machine Gun':{damage:12,rate:105,ammo:80,spread:.07,speed:1.1},
 'Submachine Gun':{damage:10,rate:75,ammo:90,spread:.055,speed:1.25},
 'Shotgun':{damage:12,rate:600,ammo:24,spread:.22,speed:.8}
};
function text(s,x,y,size=16,color='#fff',align='left'){ctx.fillStyle=color;ctx.font=`900 ${size}px system-ui`;ctx.textAlign=align;ctx.fillText(s,x,y)}
function rr(x,y,w,h,r,color,stroke){ctx.beginPath();ctx.roundRect(x,y,w,h,r);ctx.fillStyle=color;ctx.fill();if(stroke){ctx.strokeStyle=stroke;ctx.lineWidth=3;ctx.stroke()}}
function addStain(x,y,big=false){let n=big?9:3;for(let i=0;i<n;i++)stains.push({x:x+(Math.random()-.5)*(big?45:16),y:y+(Math.random()-.5)*(big?18:8),r:2+Math.random()*(big?10:5),a:.45+Math.random()*.5});if(stains.length>1200)stains.splice(0,100)}
function effect(x,y,color='#ffd76b',n=8){for(let i=0;i<n;i++)effects.push({x,y,vx:(Math.random()-.5)*.22,vy:(Math.random()-.5)*.22,life:18+Math.random()*22,color})}
function spawnFox(boss=false){let edge=Math.random()<.5?-.06:1.06;foxes.push({x:edge,y:.36+Math.random()*.36,hp:boss?480+wave*40:55+wave*8,max:boss?480+wave*40:55+wave*8,boss,speed:(boss?.000035:.00008)+Math.random()*.00004,attack:0,dead:false})}
function newGame(m=mode){mode=m;health=maxHealth;ammo=weapons[weapon].ammo;mag=ammo;coins=0;wave=1;kills=0;foxes=[];shots=[];stains=[];effects=[];allies=[];dead=false;player.x=.31;player.y=.69;bossSpawned=false;upgradeLevel=0;for(let i=0;i<4;i++)spawnFox();closeMenu();notice('DEFEND THE TRENCH!');updateHud()}
function notice(s){$('notice').textContent=s;$('notice').style.display='block';clearTimeout(notice.timer);notice.timer=setTimeout(()=>$('notice').style.display='none',2000)}
function updateHud(){
 $('health').textContent=`โค๏ธ Health: ${Math.max(0,Math.ceil(health))}/${maxHealth}`;
 $('ammo').textContent=`๐Ÿ”ซ Ammo: ${ammo}/${mag}`;
 $('coins').textContent=`๐Ÿฅš Coins: ${coins}`;
 $('wave').textContent=`โ˜ ๏ธ Wave: ${wave}`;
 $('mission').textContent=`๐Ÿช– ${mode} ยท Wave ${wave}`;
 $('allyCount').textContent=allies.length+' soldiers';
 $('medCount').textContent=allies.filter(a=>a.medic).length+' medics';
 $('allyHealth').textContent=dead?'Down!':'Ready';
 $('objectiveText').textContent=dead?'Chicken down! Open Menu':'Defeat '+foxes.filter(f=>!f.dead).length+' foxes!';
 $('weather').textContent=weather==='Rain'?'๐ŸŒง๏ธ Rain':weather==='Fog'?'๐ŸŒซ๏ธ Fog':weather==='Snow'?'โ„๏ธ Snow':'โ˜€๏ธ Clear';
}
function selectWeapon(w){weapon=w;document.querySelectorAll('[data-weapon]').forEach(b=>b.classList.toggle('active',b.dataset.weapon===w));mag=weapons[w].ammo;ammo=Math.min(ammo,mag);notice(w.toUpperCase());updateHud()}
function shoot(){if(dead||fireRate>0)return;let w=weapons[weapon];if(ammo<=0){notice('RELOAD!');return}ammo--;fireRate=w.rate;
let dx=aim.x-player.x,dy=aim.y-player.y,l=Math.hypot(dx,dy)||1;
let count=weapon==='Shotgun'?6:1;
for(let i=0;i<count;i++){let a=Math.atan2(dy,dx)+(Math.random()-.5)*w.spread;shots.push({x:player.x,y:player.y-.015,vx:Math.cos(a)*w.speed/100,vy:Math.sin(a)*w.speed/100,damage:w.damage+upgradeLevel*3,life:120,owner:'player'})}
effect(player.x+.025,player.y-.03,'#ffdb6b',4);updateHud()}
function hitFox(f,damage){if(f.dead)return;f.hp-=damage;addStain(f.x,f.y,f.boss);effect(f.x,f.y,'#ff5b45',5);if(f.hp<=0){f.dead=true;kills++;coins+=f.boss?60:5;addStain(f.x,f.y,true);effect(f.x,f.y,'#ff3b26',f.boss?30:12);notice(f.boss?'BOSS FOX DEFEATED!':'FOX DEFEATED!');updateHud()}}
function explode(x,y,r,damage){effect(x,y,'#ff8c26',32);shake=8;foxes.forEach(f=>{if(!f.dead&&Math.hypot(f.x-x,f.y-y)<r)hitFox(f,damage)})}
function drawGround(){
let g=ctx.createLinearGradient(0,0,0,H);g.addColorStop(0,'#77756c');g.addColorStop(.42,'#77705a');g.addColorStop(1,'#51402b');ctx.fillStyle=g;ctx.fillRect(0,0,W,H);
ctx.fillStyle='#9b9b91';ctx.fillRect(0,0,W,H*.25);
for(let i=0;i<30;i++){let x=(i*173)%W,y=H*.18+(i*97)%(H*.42);ctx.fillStyle=i%3?'#655f50':'#b4a895';ctx.fillRect(x,y,30+(i%5)*8,6)}
// burning ruins
rr(W*.41,H*.25,W*.17,H*.13,4,'#625a4b','#302b24');
for(let i=0;i<8;i++){ctx.fillStyle='#3c342a';ctx.fillRect(W*.42+i*W*.019,H*.24+Math.random()*0,8,H*.13)}
ctx.fillStyle='#ff7b18';ctx.beginPath();ctx.moveTo(W*.48,H*.38);ctx.lineTo(W*.49,H*.29);ctx.lineTo(W*.51,H*.34);ctx.lineTo(W*.53,H*.28);ctx.lineTo(W*.55,H*.38);ctx.fill();
for(let i=0;i<8;i++){ctx.fillStyle='#393834aa';ctx.beginPath();ctx.arc(W*.48+Math.random()*W*.1,H*.22+Math.random()*H*.08,15+Math.random()*20,0,7);ctx.fill()}
// muddy ground
ctx.fillStyle='#4b3827';ctx.fillRect(0,H*.58,W,H*.42);
for(let i=0;i<80;i++){let x=(i*131)%W,y=H*.59+(i*47)%(H*.38);ctx.fillStyle=i%2?'#6a4b31':'#382c21';ctx.beginPath();ctx.ellipse(x,y,5+i%8,2+i%4,-.2,0,7);ctx.fill()}
// trench sandbags
for(let i=0;i<Math.ceil(W/55);i++){let x=i*55;rr(x,H*.58,52,H*.055,8,i%2?'#9b8054':'#b09a6a','#4a3b28');rr(x+5,H*.645,48,H*.052,7,'#786044','#403322')}
// wooden trench boards
ctx.fillStyle='#533923';ctx.fillRect(0,H*.69,W,H*.045);ctx.fillRect(0,H*.77,W,H*.035);
for(let i=0;i<W/45;i++){ctx.strokeStyle='#241b12';ctx.lineWidth=3;ctx.beginPath();ctx.moveTo(i*45,H*.69);ctx.lineTo(i*45+8,H*.81);ctx.stroke()}
for(let x=0;x<W;x+=125){ctx.fillStyle='#76512f';ctx.fillRect(x,H*.63,9,H*.18);ctx.fillStyle='#bb9562';ctx.fillRect(x+2,H*.64,3,H*.13)}
// sandbags foreground
for(let i=0;i<W/65;i++)rr(i*65,H*.83+((i%2)*9),61,25,7,'#8d805b','#3e3829');
}
function drawChicken(x,y,dir=1,ally=false){
ctx.save();ctx.translate(x*W,y*H);ctx.scale(dir,1);
ctx.fillStyle='#d6bd84';ctx.beginPath();ctx.ellipse(0,0,20,23,0,0,7);ctx.fill();
ctx.fillStyle='#f2dfae';ctx.beginPath();ctx.ellipse(-10,5,10,14,-.5,0,7);ctx.fill();
ctx.fillStyle='#e2d3a5';ctx.beginPath();ctx.arc(3,-22,16,0,7);ctx.fill();
ctx.fillStyle='#d53e2d';ctx.beginPath();ctx.arc(0,-39,5,0,7);ctx.arc(7,-38,4,0,7);ctx.fill();
ctx.fillStyle='#f4a51d';ctx.beginPath();ctx.moveTo(16,-22);ctx.lineTo(29,-17);ctx.lineTo(16,-13);ctx.fill();
ctx.fillStyle='#fff';ctx.beginPath();ctx.arc(9,-25,6,0,7);ctx.fill();ctx.fillStyle='#111';ctx.beginPath();ctx.arc(11,-25,2.5,0,7);ctx.fill();
// helmet
ctx.fillStyle='#53603a';ctx.beginPath();ctx.ellipse(2,-32,20,10,0,Math.PI,Math.PI*2);ctx.lineTo(22,-31);ctx.lineTo(-17,-31);ctx.fill();ctx.fillStyle='#8e9a60';ctx.fillRect(-14,-33,31,3);
// gun
ctx.fillStyle='#543c24';ctx.fillRect(4,-5,25,5);ctx.fillStyle='#303532';ctx.fillRect(13,-17,34,5);ctx.fillRect(40,-15,10,3);
if(weapon==='Submachine Gun'){ctx.fillRect(24,-12,9,12);ctx.fillRect(15,-12,8,3)}
if(weapon==='Machine Gun'){ctx.fillRect(20,-12,17,3);ctx.fillRect(22,-10,5,8)}
ctx.fillStyle='#f1a921';ctx.fillRect(-6,18,4,9);ctx.fillRect(7,18,4,9);
if(ally){ctx.fillStyle='#9c4932';ctx.fillRect(-12,-6,24,5)}
ctx.restore()
}
function drawFox(f){
ctx.save();ctx.translate(f.x*W,f.y*H);let dir=f.x>player.x?-1:1;ctx.scale(dir,1);
ctx.fillStyle=f.boss?'#a94b22':'#bd652e';
ctx.beginPath();ctx.ellipse(0,0,f.boss?43:25,f.boss?26:17,-.2,0,7);ctx.fill();
ctx.fillStyle='#d69b60';ctx.beginPath();ctx.ellipse(15,-5,16,11,0,0,7);ctx.fill();
ctx.fillStyle='#c66a32';ctx.beginPath();ctx.arc(21,-21,f.boss?19:13,0,7);ctx.fill();
ctx.beginPath();ctx.moveTo(12,-30);ctx.lineTo(11,-47);ctx.lineTo(24,-32);ctx.fill();ctx.beginPath();ctx.moveTo(28,-30);ctx.lineTo(37,-45);ctx.lineTo(37,-25);ctx.fill();
ctx.fillStyle='#f3e4bd';ctx.beginPath();ctx.moveTo(30,-19);ctx.lineTo(49,-15);ctx.lineTo(30,-9);ctx.fill();
ctx.fillStyle='#f4d35b';ctx.beginPath();ctx.arc(26,-24,3,0,7);ctx.fill();ctx.fillStyle='#15110b';ctx.beginPath();ctx.arc(27,-24,1.5,0,7);ctx.fill();
ctx.fillStyle='#3a2820';ctx.fillRect(-15,12,5,12);ctx.fillRect(8,12,5,12);
if(f.boss){ctx.strokeStyle='#d5d1c4';ctx.lineWidth=4;ctx.beginPath();ctx.moveTo(-18,-15);ctx.lineTo(4,8);ctx.moveTo(4,-15);ctx.lineTo(-18,8);ctx.stroke();text('BOSS',0,-48,12,'#ffcf55','center')}
ctx.restore();
let bw=f.boss?65:38,bh=5;rr(f.x*W-bw/2,f.y*H-(f.boss?58:35),bw,bh,2,'#321b14');rr(f.x*W-bw/2,f.y*H-(f.boss?58:35),bw*Math.max(0,f.hp/f.max),bh,2,'#e73728')
}
function draw(){
ctx.save();if(shake>0){ctx.translate((Math.random()-.5)*shake,(Math.random()-.5)*shake);shake*=.85}
drawGround();
// permanent ground stains remain until a new game
for(let s of stains){ctx.fillStyle=`rgba(125,8,10,${s.a})`;ctx.beginPath();ctx.ellipse(s.x*W,s.y*H,s.r,s.r*.55,Math.random()*.1,0,7);ctx.fill()}
for(let i=0;i<18;i++){let x=(i*79+performance.now()*.015)%W;ctx.strokeStyle='#2a2b27';ctx.lineWidth=2;ctx.beginPath();ctx.moveTo(x,H*.6);ctx.lineTo(x-8,H*.7);ctx.stroke()}
foxes.forEach(f=>{if(!f.dead)drawFox(f)});
allies.forEach(a=>drawChicken(a.x,a.y,1,true));
drawChicken(player.x,player.y,player.dir);
shots.forEach(b=>{ctx.fillStyle=b.owner==='player'?'#ffe46b':'#ff6d36';ctx.beginPath();ctx.arc(b.x*W,b.y*H,4,0,7);ctx.fill();ctx.strokeStyle='#ffad37';ctx.beginPath();ctx.moveTo(b.x*W,b.y*H);ctx.lineTo((b.x-b.vx*3)*W,(b.y-b.vy*3)*H);ctx.stroke()});
effects.forEach(e=>{ctx.globalAlpha=Math.max(0,e.life/35);ctx.fillStyle=e.color;ctx.beginPath();ctx.arc(e.x*W,e.y*H,3+(35-e.life)*.15,0,7);ctx.fill();ctx.globalAlpha=1});
if(weather==='Rain'){ctx.strokeStyle='#a7c9e0aa';ctx.lineWidth=1;for(let i=0;i<70;i++){let x=(i*89+performance.now()*.25)%W,y=(i*57+performance.now()*.7)%H;ctx.beginPath();ctx.moveTo(x,y);ctx.lineTo(x-5,y+13);ctx.stroke()}}
if(weather==='Fog'){ctx.fillStyle='#b5b7b588';ctx.fillRect(0,0,W,H)}
// aim reticle
ctx.strokeStyle='#fff4c6';ctx.lineWidth=2;ctx.beginPath();ctx.arc(aim.x*W,aim.y*H,9,0,7);ctx.moveTo(aim.x*W-15,aim.y*H);ctx.lineTo(aim.x*W-5,aim.y*H);ctx.moveTo(aim.x*W+5,aim.y*H);ctx.lineTo(aim.x*W+15,aim.y*H);ctx.stroke();
ctx.restore();
}
function update(dt){
if(dead)return;
fireRate=Math.max(0,fireRate-dt);
player.x=Math.max(.05,Math.min(.95,player.x+moving.x*dt*.00015));
player.y=Math.max(.43,Math.min(.79,player.y+moving.y*dt*.00015));
if(keys.ArrowLeft||keys.a)player.x-=dt*.00012;
if(keys.ArrowRight||keys.d)player.x+=dt*.00012;
if(keys.ArrowUp||keys.w)player.y-=dt*.00012;
if(keys.ArrowDown||keys.s)player.y+=dt*.00012;
if(shooting&&fireRate<=0)shoot();
shots.forEach(b=>{b.x+=b.vx*dt;b.y+=b.vy*dt;b.life-=dt;
if(b.owner==='player'){for(let f of foxes){if(!f.dead&&Math.hypot(f.x-b.x,f.y-b.y)<(f.boss?.065:.04)){hitFox(f,b.damage);b.life=0;break}}}
else if(Math.hypot(player.x-b.x,player.y-b.y)<.035){health-=8;b.life=0;addStain(player.x,player.y);if(health<=0){health=0;dead=true;notice('CHICKEN DOWN! OPEN MENU')}}});
shots=shots.filter(b=>b.life>0&&b.x>-.1&&b.x<1.1&&b.y>-.1&&b.y<1.1);
foxes.forEach(f=>{if(f.dead)return;let dx=player.x-f.x,dy=player.y-f.y,l=Math.hypot(dx,dy)||1;f.x+=dx/l*f.speed*dt;f.y+=dy/l*f.speed*dt;
if(l<.12){f.attack+=dt;if(f.attack>900){health-=f.boss?14:6;f.attack=0;addStain(player.x,player.y);effect(player.x,player.y,'#e83a2b',5);if(health<=0){health=0;dead=true;notice('CHICKEN DOWN! OPEN MENU')}}}
else f.attack=0});
// allies automatically shoot the nearest fox
allies.forEach(a=>{a.cool=(a.cool||0)-dt;if(a.cool<=0){let f=foxes.filter(f=>!f.dead).sort((x,y)=>Math.hypot(x.x-a.x,x.y-a.y)-Math.hypot(y.x-a.x,y.y-a.y))[0];if(f){hitFox(f,a.medic?2:8);a.cool=a.medic?1200:650}}});
effects.forEach(e=>{e.x+=e.vx*dt*.001;e.y+=e.vy*dt*.001;e.life-=dt*.04});effects=effects.filter(e=>e.life>0);
if(foxes.filter(f=>!f.dead).length===0){wave++;coins+=10;notice('WAVE '+wave+'! +10 EGG COINS');if(wave%5===0){spawnFox(true);bossSpawned=true;notice('BOSS FOX INCOMING!')}for(let i=0;i<Math.min(4+wave,14);i++)spawnFox();if(wave%3===0)weather=['Rain','Fog','Snow','Clear'][Math.floor(Math.random()*4)];updateHud()}
if(Math.random()<dt*.00005&&mode==='Endless Survival')spawnFox();
weatherTime+=dt;
}
let last=performance.now();
function loop(now){let dt=Math.min(40,now-last);last=now;update(dt);draw();requestAnimationFrame(loop)}
requestAnimationFrame(loop);
document.querySelectorAll('[data-weapon]').forEach(b=>b.addEventListener('click',()=>selectWeapon(b.dataset.weapon)));
$('fire').addEventListener('pointerdown',e=>{e.preventDefault();shooting=true;shoot()});
for(let ev of ['pointerup','pointercancel','pointerleave'])$('fire').addEventListener(ev,()=>shooting=false);
c.addEventListener('pointerdown',e=>{if(e.clientY<H-100){aim={x:e.clientX/W,y:e.clientY/H};player.dir=aim.x>=player.x?1:-1;if(e.pointerType==='mouse')shoot()}});
c.addEventListener('pointermove',e=>{if(e.buttons){aim={x:e.clientX/W,y:e.clientY/H};player.dir=aim.x>=player.x?1:-1}});
addEventListener('keydown',e=>{keys[e.key]=true;if(e.key===' '){e.preventDefault();shoot()}if(e.key.toLowerCase()==='r'){ammo=mag;notice('RELOADED');updateHud()}});
addEventListener('keyup',e=>keys[e.key]=false);
const pad=$('pad');pad.addEventListener('pointerdown',e=>{pad.setPointerCapture(e.pointerId);pad._start=[e.clientX,e.clientY]});
pad.addEventListener('pointermove',e=>{if(!pad.hasPointerCapture(e.pointerId)||!pad._start)return;moving.x=Math.max(-1,Math.min(1,(e.clientX-pad._start[0])/30));moving.y=Math.max(-1,Math.min(1,(e.clientY-pad._start[1])/30))});
for(let ev of ['pointerup','pointercancel'])pad.addEventListener(ev,()=>{moving={x:0,y:0};pad._start=null});
$('grenade').onclick=()=>{if(coins<5){notice('NEED 5 EGG COINS');return}coins-=5;explode(aim.x,aim.y,.24,90);updateHud()};
$('artillery').onclick=()=>{if(coins<15){notice('NEED 15 EGG COINS');return}coins-=15;explode(aim.x,aim.y,.38,200);updateHud()};
$('medic').onclick=()=>{if(coins<20){notice('NEED 20 EGG COINS');return}coins-=20;health=Math.min(maxHealth,health+35);allies.push({x:.22+Math.random()*.2,y:.69,medic:true});notice('MEDIC DEPLOYED');updateHud()};
$('upgrade').onclick=()=>{if(coins<25){notice('NEED 25 EGG COINS');return}coins-=25;upgradeLevel++;maxHealth+=10;health=Math.min(maxHealth,health+25);notice('UPGRADE LEVEL '+upgradeLevel);updateHud()};
$('menuBtn').onclick=()=>{$('menu').style.display='block';shooting=false};
function closeMenu(){$('menu').style.display='none'}
window.closeMenu=closeMenu;window.newGame=newGame;
newGame('Campaign');
})();
</script>
</body>
</html>

Game Source: Chicken Quest: WWI Trench Defence

Creator: AtomicFlame49

Libraries: none

Complexity: complex (231 lines, 19.4 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: chicken-quest-wwi-trench-defence-atomicflame49" to link back to the original. Then publish at arcadelab.ai/publish.