Defend your heart against waves of skulls by building a maze of towers but without blocking the way completely. Regular towers cost $2 and attack one enemy at a time but you can buy two upgrades to do…
f="o=wURHmHs=[7:40}];e(P)U2;2+Gx=@-=<-~JD+2>mqRq=:~Bq^sMmq=DPV''+YzV!s^!m[l]^B[60]n=wo(BHS=YHp=X=3PA=8n(Ponclick=wA^n(PxXYJp?p=!p:Bq?`Key?FL++X):>X/3^>1X-=++*3):2>XFM0?F0):X-=2)T=wa.font=i+'px Arial dText(e,x,y+i*.3)setInval(wUc.height=29LW=S/20>>4;Gj1-i/1_0OLi,29L1p|=!A;U8;Gj.2OiN_,1,225)O_,iN225,1PE$'+X+' ∿'+W,2Lj1,245Pa.textAlign='cen E↻▶'[A&&1],p?30:C-Cl*_PE♥ A*24,7N4NZ00'Y=Yz@+x,<+yPE☠ D/`m*161|LQx+@NQy+<*_PV-60?D>0^!++X:A--&0}PBzj.6,(ee=e)&&E♖♜♛'[D],3L@N<NYzV4>x/@-e@)*i+y/<-e<)*izi&&2>eDj1,D-=eD))}PS++%_^0/4>24+W^YLy:lW=(W+55)*2*W^5Lm:W48)z.fil(ws=R[];wfunction(e,i,x){q[x*8+y]ja.globalAlpha=da.fillD._32^||ZdStyle='#fVreturn Ufor*s.P);O,dRect(N*_,Mx:yL0,J,(x|y)>>3^H=[],Gi--;)Fo(Bq=ET('D`eC1Lp?112:@`x<`yBq.e(i=Q{x:i%2.push(=`page-16>>5PZff ,y},})_+shift@*8+<,e:=s.terS%_^(+1 ',p^";for(i in g=" <@CDEFGHJLMNOPQUVZ^_`djqwz")with(f.split(g[i]))f=join(pop(l=new Date%8));eval(f)
Zj0ibz13VVJIbUhzPVsdNxc6NBEwfV07ZRATKFApVTI7MitHeD1ALRwXPTwtfhxKRCsyPm1xDFJxPR0cFzp+HBZCcV5zG01tcT1ECxVQVicnK1l6ViFzFV4hbVtsXV5CWzYwXRZuPXdvKEJIUz1ZSHA9WD0zUEE9OBZuKFBvbmNsaWNrPXdBXm4oUHgaWBkXGlkZSnA/cD0hcDpCcT9gE0tleT9GTCsrWCk6Hws+WC8zXh8+MQxYLT0rKx8qMyk6Mj5YDEZNMBU/RjApOlgtPTIpFlQ9d2EuZm9udD1pKydweCBBcmlhbAlkVGV4dChlLBR4LBR5K2kqLjMpFnNldEluD3ZhbCh3VWMuaGVpZ2h0PTI5TFc9Uy8yMD4+NDtHajEtaS8xXzBPTGksMjlMMRhwfD0hQTtVODtHai4yTxRpTl8sMSwyMjUpT18sFGlOMjI1LDFQRSQnK1grJyAg4oi/JytXLDJMajEsMjQ1UGEudGV4dEFsaWduPSdjZW4PCUXihrvilrYnW0EmJjFdLHA/MzA6Qy1DbCpfUAhF4pmlCUEqMgs0LDdONE5aMDAnGFk9WXoIDgxAKxB4LDwrEHlQReKYoAlEL2BtKjE2CzF8TFF4K0BOUXkrPCpfUFYIEi02MD9EPjBeISsrWDpBLS0mMH1QQnpqLjYsKGVlPWUpJiZF4pmW4pmc4pmbJ1tEXSwzTEBOPE4IWXpWND4eeC8UQC1lQCkqaSseeS8UPC1lPCkqaRV6aSYmMj5lRAxqMSxELT1lRAspFSl9UAhTKyslX14OMC80PjI0K1deWRsdTHk6bBFXPShXKzU1KSoyKldeNUxtOlcVFjQ4KXouZmlsDyh3cz1SWxJdO3dmdW5jdGlvbihlLGkseBcpe3FbeCo4K3ldamEuZ2xvYmFsQWxwaGE9ZGEuZmlsbEQuXzMyXnx8WmRTdHlsZT0nI2ZWcmV0dXJuIFVmb3IeDipzLlApO08sZFJlY3QoTipfLE0deBc6eRFMMCxKLCh4fHkpPj4zXkg9W10sR2ktLTspRm8oQnE9RVQoJ0RgZUMxTHA/MTEyOkBgeDxgeR9CcS5lHihpPVEde3g6HGklMhsucHVzaCgaPWBwYWdlGS0xNj4+NRhQWmZmCRcseRZ9LBV9KRRfKxNzaGlmdBJAKjgrPBEsZToQPXMuD3Rlcg5TJV8MXigLKzEJJywIcF4iO2ZvcihpIGluIGc9IggJCwwODxAREhMUFRYXGBkaGxwdHh88QENERUZHSEpMTU5PUFFVVlpeX2BkanF3eiIpd2l0aChmLnNwbGl0KGdbaV0pKWY9am9pbihwb3AobD1uZXcgRGF0ZSU4KSk7ZXZhbChmKQ==
//////////////////////////////////////////////////////////////////////////
// .-. .-.
// _ _ ___ ___ ___ ____(%%%\/%%%)__ ____ ____ ___ ___ _ _
// | |_| | __| _ | _ |_ _\%%%%%%/ _ |_ | _| _ | _| |_| |
// | _ | __| | _| | | \%%%%/| | | | | | | | |_| _ <
// |_| |_|___|_|_|_|_| |_| \%%/ |_|_| |_| |_| |_|_|___|_| |_|
// \/
// by @veubeke
//////////////////////////////////////////////////////////////////////////
// see http://games.23inch.de/td/ for full documentation
//////////////////////////////////////////////////////////////////////////
// characters used ...
//
// for variables
// local e i m s x y
// global a c l n o p r
// A B R S T W X Y
// in program a b c d e f g h i l m n o p r s t u v w x y
// A B I R S T W X Y
// packing j k q z
// C D E F G H J K L N O P Q U V Z
// cost map generation
genMap = function(e,i,x,y) {
for(i = dir = [], // directions
m = [], // cost map
// starting with the heart, iterate over squares in frontier
s=[{x:7,y:4,e:0}]; e=s.shift();)
// check all adjacent squares
for(i=2;2+i--;)
x = e.x-i%2,
y = e.y-~i%2,
// if square is on the board and new path is shorter...
(x|y)>>3 || e.e+2>m[x*8+y] || (
// update directions
dir[x*8+y] = {x:i%2,y:~i%2},
// keep going if square is free
board[x*8+y] || s.push({x:x,y:y,e:m[x*8+y] = e.e+1}));
// return true if the path hasn't been blocked
return ''+creeps.filter(function(e,i,x,y) { s = dir[e.x*8+e.y]; return !s }) ||
!m[start] || board[60]
},
// game setup
setup = function(e,i,x,y) {
genMap(
// game board
board = [],
// animation step / timer
step =
// enemies
creeps = [],
// paused state
paused =
// money
money = 3
);
// generate map on startup
life = 8
},
setup();
// click handler
onclick = function(e,i,x,y) {
// set up game if over
life || setup();
x = e.pageX-16 >> 5,
y = e.pageY-16 >> 5,
// pause when clicking outside of the board, unpause if paused
(x|y)>>3 || paused ? paused = !paused
: board[x*8+y]
? e.shiftKey
// sell tower
? genMap(board[x*8+y]=0,++money)
// upgrade tower
: board[x*8+y].e+1>money/3 || board[x*8+y].e>1 || (money-=++board[x*8+y].e*3)
: 2>money || (
// try placing tower and...
genMap(board[x*8+y] = {x:x,y:y,e:0})
// remove if is blocking the path...
? genMap(board[x*8+y]=0)
// or charge player
: money -= 2
)
},
// text drawing
drawText = function(e,i,x,y) {
a.font = i+'px Arial',
// draw text relative to board...
// and add difference between alphabetic baseline and middle
a.fillText(e,32+x,32+y+i*.3)
},
// main loop
setInterval(function(e,i,x,y) {
// draw background
for(i = c.height = 290,
wave = step/20 >> 4; i--;)
a.globalAlpha = 1-i/1320,
a.fillRect(0,i,290,1);
a.fillStyle = '#fff',
// pause game if no life left
paused |= !life;
// draw grid
for(i=8; i--;)
a.globalAlpha = .2,
a.fillRect(32+i*32,32,1,225),
a.fillRect(32,32+i*32,225,1);
// print info
drawText('$'+money+' ∿'+wave,20,a.globalAlpha=1,245);
a.textAlign = 'center',
// draw pause/retry symbol or heart and arrow to show game state
drawText('↻▶'[life&&1],paused?30:10,paused?112:-10,paused?112:start*32);
paused || drawText('♥',life*2+14,7*32,4*32,a.fillStyle = '#f00');
a.fillStyle = '#fff',
// update creeps
creeps = creeps.filter(function(e,i,x,y) {
s = dir[e.x*8+e.y];
// update position
paused || step%32 || (e.x += s.x, e.y += s.y);
// draw creep
drawText('☠',e.e/e.m*16+11|0,step%32*s.x+e.x*32,step%32*s.y+e.y*32);
// remove creeps that are dead or reached the heart
return paused || e.x*8+e.y-60 ? e.e>0 || !++money : life--&0
});
// update towers
board.filter(function(e,i,x,y) {
s = dir[e.x*8+e.y];
// inactive towers are darker
a.globalAlpha = .6,
(ee = e) &&
// draw tower
drawText('♖♜♛'[e.e],30,e.x*32,e.y*32,
// find creeps near tower...
paused || creeps.filter(function(e,i,x,y) {
s = dir[e.x*8+e.y];
return 4>(i=step%32*s.x/32+e.x-ee.x)*i+(i=step%32*s.y/32+e.y-ee.y)*i
}).filter(function(e,i,x,y) {
s = dir[e.x*8+e.y];
// and shoot at them
i && 2>ee.e || (a.globalAlpha = 1, e.e -= ee.e+1)
}))
});
// add new creeps every ~15s
paused || step++%32 || step%320/4>24+wave || creeps.push({x:0,y:start,e:wave=(wave+55)*2*wave||50,m:wave})
}, 48)