"The Legend of Ecma." Descend the dungeon to find the amulet of Ecma and then return it to the top floor. Monsters subtract 1 health, potions add 1 health. Features: 1 bit pixel art, randomized dungeo…
eval('d=document;c=d.body.children[0];X=20;L={};E=l=0;V=5;M={};I=parseInt;R=Math.random;A=Math.abs;c.width=600;c.height=H=300;x=c.getContext("2d");_g(e){y=42+I(R()*X)*10+I(R()*6);M[y]=e}_h(e){M={};for(i=0;++i<X;)g(M[X+i]=M[280+i]=M[i*X]=M[i*X+19]=7);g(R()<0.35?4:3);!l||g(1);g(l<X?2:8);M=L[l]=L[l]||M;P=j(e)||84}_j(e){for(i in M)if(M[i]==e)return+i}_k(e,f){x.drawImage(T,e*8,0,8,8,X*(f%X),f-f%X,X,X)}_n(e){d.onkeyup=function(f){V&&n(P+({37:-1,39:1,38:-X,40:X}[f.keyCode]||0))};e=e>0?e:(h(1),P);M[m=j(3)||H]=0;a=(a=P%X-m%X)?a/A(a):0;b=(b=I(P/X)-I(m/X))?X*b/A(b):0;m+=M[m+a+b]?M[m+a]?M[m+b]?0:b:a:a+b;M[m]=3;M[P]==3&&(V--,M[P]=0);q=M[e];q==7||(P=e);(a=q==4?V++:q&8)&&(M[e]=0);q==2?(l++,h(1)):q==1&&(l--,h(2));for(i=0;i<H;)k(i<V?5:0,i++);for(i in M)k(M[i],i);k(V>0?6:3,P)}T=new Image;T.src="data:;base64,R0lGODlhSAAIAIAAAAAAAP///ywAAAAASAAIAAACXYyPqQmtfhw0DVAb8Mx4LdsxVchFXHWh42pm3ud+4NOB4xWjZx2/5kz6ITSp2862guh8LmBzyOrljMqkZkZhPp28HnIJvpaOWx+3XNtUhyJdFCt9oMte6AaWPbonBQA7";setTimeout("n(0)",H)'.replace(/_/g, 'function '))
ZXZhbCgnZD1kb2N1bWVudDtjPWQuYm9keS5jaGlsZHJlblswXTtYPTIwO0w9e307RT1sPTA7Vj01O009e307ST1wYXJzZUludDtSPU1hdGgucmFuZG9tO0E9TWF0aC5hYnM7Yy53aWR0aD02MDA7Yy5oZWlnaHQ9SD0zMDA7eD1jLmdldENvbnRleHQoIjJkIik7X2coZSl7eT00MitJKFIoKSpYKSoxMCtJKFIoKSo2KTtNW3ldPWV9X2goZSl7TT17fTtmb3IoaT0wOysraTxYOylnKE1bWCtpXT1NWzI4MCtpXT1NW2kqWF09TVtpKlgrMTldPTcpO2coUigpPDAuMzU/NDozKTshbHx8ZygxKTtnKGw8WD8yOjgpO009TFtsXT1MW2xdfHxNO1A9aihlKXx8ODR9X2ooZSl7Zm9yKGkgaW4gTSlpZihNW2ldPT1lKXJldHVybitpfV9rKGUsZil7eC5kcmF3SW1hZ2UoVCxlKjgsMCw4LDgsWCooZiVYKSxmLWYlWCxYLFgpfV9uKGUpe2Qub25rZXl1cD1mdW5jdGlvbihmKXtWJiZuKFArKHszNzotMSwzOToxLDM4Oi1YLDQwOlh9W2Yua2V5Q29kZV18fDApKX07ZT1lPjA/ZTooaCgxKSxQKTtNW209aigzKXx8SF09MDthPShhPVAlWC1tJVgpP2EvQShhKTowO2I9KGI9SShQL1gpLUkobS9YKSk/WCpiL0EoYik6MDttKz1NW20rYStiXT9NW20rYV0/TVttK2JdPzA6YjphOmErYjtNW21dPTM7TVtQXT09MyYmKFYtLSxNW1BdPTApO3E9TVtlXTtxPT03fHwoUD1lKTsoYT1xPT00P1YrKzpxJjgpJiYoTVtlXT0wKTtxPT0yPyhsKyssaCgxKSk6cT09MSYmKGwtLSxoKDIpKTtmb3IoaT0wO2k8SDspayhpPFY/NTowLGkrKyk7Zm9yKGkgaW4gTSlrKE1baV0saSk7ayhWPjA/NjozLFApfVQ9bmV3IEltYWdlO1Quc3JjPSJkYXRhOjtiYXNlNjQsUjBsR09EbGhTQUFJQUlBQUFBQUFBUC8vL3l3QUFBQUFTQUFJQUFBQ1hZeVBxUW10Zmh3MERWQWI4TXg0TGRzeFZjaEZYSFdoNDJwbTN1ZCs0Tk9CNHhXalp4Mi81a3o2SVRTcDI4NjJndWg4TG1CenlPcmxqTXFrWmtaaFBwMjhIbklKdnBhT1d4KzNYTnRVaHlKZEZDdDlvTXRlNkFhV1Bib25CUUE3IjtzZXRUaW1lb3V0KCJuKDApIixIKScucmVwbGFjZSgvXy9nLCAnZnVuY3Rpb24gJykp
// P = player position
// Q = next player position
// H = canvas height (300)
// X = 20
// A = Math.abs
// R = Math.random
// M = map
// V = health
// L = Levels (memoized)
// l = level
// I = parseInt
// T = tile image
// Tiles are horizontal offets (*8) in T
// 0 = tile - empty 0
// 1 = tile - stairs up 1
// 2 = tile - stairs down 2
// 3 = tile - monster 3
// 4 = tile - potion 4
// 5 = tile - heart 5
// 6 = tile - player 6
// 7 = tile - wall 7
// 8 = tile - amulet of ecma 8
d=document
c=d.body.children[0]
X=20
L={}
E=l=0
V=2
M={}
I=parseInt
R=Math.random
A=Math.abs
c.width=600
c.height=H=300
x=c.getContext('2d')
function Place(x){y=42+I(R()*X)*10+I(R()*6);M[y]=x}
function Level(w) {
M={} // Square boundary walls // And 20 random interior walls
for(i=0;++i<X;)Place(M[X+i]=M[280+i]=M[i*X]=M[i*X+19]=7)
// Put potion (40% chance) or monster (60% chance)
Place(R()<.4?4:3)
// Place 'up' stairs only on 2nd level and lower
!l?0:Place(1)
// Place 'down' stairs until 20th floor, then place amulet
Place(l<2?2:8)
// Either look up the room from memory or use the one we just built
M=L[l]=L[l]||M
// Put player on up or down stairs if they're present, otherwise start at 255
P=Locate(w)||84
}
// Find the first position of a given tile
function Locate(tile){for(i in M)if(M[i]==tile)return+i}
// Draw the given tile at a given position, scaling to a ratio of 20:8 (eww)
function Draw(tile,pos){x.drawImage(T,tile*8,0,8,8,X*(pos%X),pos-pos%X,X,X)}
// Tick
function Tick(Q){
// I know it seems crazy to put this inside Tick, but it's the only way I could think of to delay binding this without spending any more bytes
d.onkeyup=function(a){V&&Tick(P+({37:-1,39:1,38:-X,40:X}[a.keyCode]||0))}
// On FF, Q is something <= 0 when Tick is called via setTimeout.... ???
Q=(Q>0?Q:(Level(1),P))
// advance monster if there is one. if Locate returns nothign, assign m to H (out of bounds)
M[m=Locate(3)||H]=0
// figure out horizontal component of movement
a=P%X-m%X
a=a?a/A(a):0
// figure out vertical component of movement
b=I(P/X)-I(m/X)
b=b?X*b/A(b):0
// try diagonal then horizontal then vertical
m+=M[m+a+b]?M[m+a]?M[m+b]?0:b:a:a+b
// move the monster
M[m]=3
// If monster is now on our pre-move position, take damage and remove the monster
M[P]==3?(V--,M[P]=0):0
// Look at new position
q=M[Q]
// Move us if the tile was not a wall
q==7?0:P=Q
// If we hit a potion or amulet, take it and remove it
a=(q==4?V++:q&8)
a?M[Q]=0:0
// If we hit stairs, move us up or down
q==2?(l++,Level(1)):q==1?(l--,Level(2)):0
// Blank out the background and draw our health.
for(i=0;i<H;)Draw(i<V?5:0,i++)
// Draw the map
for(i in M)Draw(M[i],i)
// Draw the player
Draw(V>0?6:3,P)
}
T=new Image;T.src='data:;base64,R0lGODlhSAAIAIAAAAAAAP///ywAAAAASAAIAAACXYyPqQmtfhw0DVAb8Mx4LdsxVchFXHWh42pm3ud+4NOB4xWjZx2/5kz6ITSp2862guh8LmBzyOrljMqkZkZhPp28HnIJvpaOWx+3XNtUhyJdFCt9oMte6AaWPbonBQA7'
setTimeout('Tick(0)',H)