1
0
mirror of https://github.com/osmarks/website synced 2024-11-08 12:19:54 +00:00
website/experiments/apioform/index.html
2022-03-07 20:07:16 +00:00

689 lines
33 KiB
HTML

---
title: Apioform Game
description: A game about... apioforms... by Heavpoot.
---
<canvas style="border:3px solid black" width=500 height=500 id=a></canvas>
<p id="kills">Kills: </p>
<script>
turn=(()=>{
const canvas=document.getElementById("a")
const ctx=canvas.getContext("2d")
/*var framecount=0
var entities={}
var particles=new Set()
var attacks=new Set()
var kills=0;*/
let frigidmode=false
let paritychallenge=false
let parityoverlay=false
let prevkilled=false // parity challenge thingy.
if (localStorage.tutorial===undefined){localStorage.tutorial=true;}
const solid={
"player":true,
"bee":true,
"barrier":true,
"apioform":true,
"apiodiagoform":true,
"apiokinetoform":true,
"apiopyroform":true,
"cryoapioform":true,
"apiopariform":true,
}
const killable={
"bee":true,
"apioform":true,
"apiodiagoform":true,
"apiokinetoform":true,
"apiopyroform":true,
"cryoapioform":true,
"apiopariform":true,
}
const freezable={
"player":true,
"bee":true,
"apioform":true,
"apiodiagoform":true,
"apiokinetoform":true,
"apiopyroform":true,
"cryoapioform":true,
"apiopariform":true,
}
class Tile {
constructor(x,y,type,meta){
this.x=x;
this.y=y;
this.type=type;
this.meta=meta;
this.cx=x;
this.cy=y;
this.meta.clock=this.meta.clock===undefined?0:this.meta.clock;
this.meta.cooldown=0
this.meta.frozen=0
}
}
class Attack {
constructor(x,y,type,meta){
this.x=x;
this.y=y;
this.type=type;
this.meta=meta;
if (this.type=="fireball"||this.type=="iceball"){
this.meta.clock=-1;
}
this.turn=function(){
switch (this.type){
case "fireball":
var suicide=true
for (i in entities[this.x+" "+this.y]){
if (entities[this.x+" "+this.y][i].type=="apiopyroform"){
suicide=false
}
}
if (this.meta.clock==2||suicide){
attacks.delete(this)
}else{
if (this.meta.clock==1){
if (this.x==px&&this.meta.dx==1){
php-=2
}
if (this.y==py&&this.meta.dy==1){
php-=2
}
for (i in entities){
for (j=entities[i].length-1;j>=0;j--){
if (killable[entities[i][j].type]===true&&i!==this.x+" "+this.y&&((this.meta.dx==1&&this.x==entities[i][j].x)||(this.meta.dy==1&&this.y==entities[i][j].y))){
spawneffect("death",entities[i][j].x,entities[i][j].y)
entities[i].splice(j,1)
}
}
}
}
this.meta.clock++;
}
break;
case "iceball":
var suicide=true
for (i in entities[this.x+" "+this.y]){
if (entities[this.x+" "+this.y][i].type=="cryoapioform"){
suicide=false
}
}
if (this.meta.clock==2||suicide){
attacks.delete(this)
}else{
if (this.meta.clock==1){
for (i in entities){
for (j=entities[i].length-1;j>=0;j--){
if (freezable[entities[i][j].type]===true&&i!==this.x+" "+this.y&&((this.meta.dx==1&&this.x==entities[i][j].x)||(this.meta.dy==1&&this.y==entities[i][j].y))){
entities[i][j].meta.frozen=4
}
}
}
}
this.meta.clock++;
}
break;
}
}
this.tick=function(){
switch (this.type){
case "fireball":
if (this.meta.clock==0){
for (var i=0;i<20;i++){
particles.add(new Particle((Math.random()*1000-500)*this.meta.dy+this.x*10+5,(Math.random()*1000-500)*this.meta.dx+this.y*10+5,80,80,80,10,Math.random()-0.5*this.meta.dx+(Math.random()*0.125-0.0625),Math.random()-0.5*this.meta.dy+(Math.random()*0.125-0.0625),some(["basic","big","basic"])))
}
}
if (this.meta.clock==1){
for (var i=0;i<60;i++){
particles.add(new Particle((Math.random()*1000-500)*this.meta.dy+this.x*10+5,(Math.random()*1000-500)*this.meta.dx+this.y*10+5,128,128,128,20,Math.random()-0.5*this.meta.dx+(Math.random()*0.125-0.0625),Math.random()-0.5*this.meta.dy+(Math.random()*0.125-0.0625),some(["basic","big","basic"])))
}
}
if (this.meta.clock==2){
for (var i=0;i<80;i++){
let r=some([255,200,180])
let g=some([r,128])
particles.add(new Particle((Math.random()*1000-500)*this.meta.dy+this.x*10+5,(Math.random()*1000-500)*this.meta.dx+this.y*10+5,r,g,128,20,(Math.random()*2-1)*this.meta.dx+(Math.random()*0.125-0.0625),(Math.random()*2-1)*this.meta.dy+(Math.random()*0.125-0.0625),some(["big","big","basic"])))
}
}
break;
case "iceball":
if (this.meta.clock==0){
for (var i=0;i<20;i++){
particles.add(new Particle((Math.random()*1000-500)*this.meta.dy+this.x*10+5,(Math.random()*1000-500)*this.meta.dx+this.y*10+5,80,80,120,10,Math.random()-0.5*this.meta.dx+(Math.random()*0.125-0.0625),Math.random()-0.5*this.meta.dy+(Math.random()*0.125-0.0625),some(["basic","big","basic"])))
}
}
if (this.meta.clock==1){
for (var i=0;i<60;i++){
particles.add(new Particle((Math.random()*1000-500)*this.meta.dy+this.x*10+5,(Math.random()*1000-500)*this.meta.dx+this.y*10+5,128,128,200,20,Math.random()-0.5*this.meta.dx+(Math.random()*0.125-0.0625),Math.random()-0.5*this.meta.dy+(Math.random()*0.125-0.0625),some(["basic","big","basic"])))
}
}
if (this.meta.clock==2){
for (var i=0;i<80;i++){
let b=some([255,200,180])
let g=some([b,128,0])
particles.add(new Particle((Math.random()*1000-500)*this.meta.dy+this.x*10+5,(Math.random()*1000-500)*this.meta.dx+this.y*10+5,0,g,b,20,(Math.random()*2-1)*this.meta.dx+(Math.random()*0.125-0.0625),(Math.random()*2-1)*this.meta.dy+(Math.random()*0.125-0.0625),some(["big","big","basic"])))
}
}
break;
}
}
}
}
class Particle {
constructor(x,y,r,g,b,fade,xv,yv,type){
this.x=x;
this.y=y;
this.r=r
this.g=g
this.b=b
this.fade=fade;
this.cfade=fade;
this.xv=xv;
this.yv=yv;
this.type=type;
this.tick=function(){
if (this.cfade==0){
particles.delete(this)
}else{
switch (this.type){
case "basic":
this.xv*=0.99;
this.yv*=0.99;
this.x+=this.xv;
this.y+=this.yv;
ctx.fillStyle=`rgba(${this.r},${this.g},${this.b},${this.cfade/this.fade})`
ctx.fillRect(this.x,this.y,1,1)
break;
case "big":
this.xv*=0.99;
this.yv*=0.99;
this.x+=this.xv;
this.y+=this.yv;
ctx.fillStyle=`rgba(${this.r},${this.g},${this.b},${this.cfade/this.fade})`
ctx.fillRect(this.x-1,this.y-1,3,3)
break;
}
}
this.cfade--
}
}
}
var cam={
"x":0,"y":0
}
let px; let php; let py; let entities; let particles; let framecount; let attacks; let kills;
function render(ent){
switch (ent.type){
case "player":
ctx.fillStyle="#000000"
ctx.fillRect(ent.cx*10,ent.cy*10,10,10)
if (parityoverlay&&paritychallenge){
ctx.fillStyle="#ffffff"
ctx.textBaseline="middle"
ctx.textAlign="center"
ctx.font="10px monospace";
if (ent.x%2==0&&ent.y%2==0) ctx.fillText("a",ent.cx*10+5,ent.cy*10+5)
if (ent.x%2==1&&ent.y%2==0) ctx.fillText("b",ent.cx*10+5,ent.cy*10+5)
if (ent.x%2==0&&ent.y%2==1) ctx.fillText("d",ent.cx*10+5,ent.cy*10+5)
if (ent.x%2==1&&ent.y%2==1) ctx.fillText("c",ent.cx*10+5,ent.cy*10+5)
}
break;
case "bee":
if (ent.meta.clock%2==0) ctx.fillStyle="#808020"
else ctx.fillStyle="#A0A050"
ctx.fillRect(ent.cx*10,ent.cy*10,10,10)
break;
case "apioform":
ctx.fillStyle="#A08020"
ctx.fillRect(ent.cx*10,ent.cy*10,10,10)
break;
case "apiodiagoform":
ctx.fillStyle="#A080A0"
ctx.fillRect(ent.cx*10,ent.cy*10,10,10)
break;
case "apiokinetoform":
if (ent.meta.clock%2==0) ctx.fillStyle="#3030FF"
else ctx.fillStyle="#101080"
ctx.fillRect(ent.cx*10,ent.cy*10,10,10)
break;
case "apiopyroform":
ctx.fillStyle="#F02030"
ctx.fillRect(ent.cx*10,ent.cy*10,10,10)
break;
case "cryoapioform":
ctx.fillStyle="#0080FF"
ctx.fillRect(ent.cx*10,ent.cy*10,10,10)
break;
case "apiopariform":
ctx.fillStyle="#808080"
ctx.fillRect(ent.cx*10,ent.cy*10,10,10)
if (parityoverlay&&paritychallenge){
ctx.fillStyle="#ffffff"
ctx.textBaseline="middle"
ctx.textAlign="center"
ctx.font="10px monospace";
if (ent.x%2==0&&ent.y%2==0) ctx.fillText("a",ent.cx*10+5,ent.cy*10+5)
if (ent.x%2==1&&ent.y%2==0) ctx.fillText("b",ent.cx*10+5,ent.cy*10+5)
if (ent.x%2==0&&ent.y%2==1) ctx.fillText("d",ent.cx*10+5,ent.cy*10+5)
if (ent.x%2==1&&ent.y%2==1) ctx.fillText("c",ent.cx*10+5,ent.cy*10+5)
}
break;
case "apiocryokinetoform":
ctx.fillStyle="#FFFFFF"
ctx.fillRect(ent.cx*10,ent.cy*10,10,10)
break;
}
ent.cx+=(ent.x-ent.cx)*0.4
ent.cy+=(ent.y-ent.cy)*0.4
if (ent.meta.frozen){
ctx.fillStyle="rgba(0,255,255,0.3)"
ctx.fillRect(ent.x*10,ent.y*10,10,10)
spawneffect("frigid",ent.x,ent.y)
}
}
function makeent(x,y,type,meta){
let ent=new Tile(x,y,type,meta)
if (entities[x+" "+y]===undefined){
entities[x+" "+y]=[]
}
entities[x+" "+y].push(ent)
}
function issolid(i){
if (entities[i]!==undefined){
for (j in entities[i]){
if (solid[entities[i][j].type]) return true
}
}
return false
}
function move(tile,subtile,dx,dy){
let tilen=(dx+tile.x)+" "+(dy+tile.y)
if (!issolid(tilen)&&entities[tile.x+" "+tile.y][subtile].meta.frozen==0){
if (entities[tilen]===undefined){
entities[tilen]=[]
}
entities[tilen].push(entities[tile.x+" "+tile.y].splice(subtile,1)[0])
entities[tilen][entities[tilen].length-1].x+=dx
entities[tilen][entities[tilen].length-1].y+=dy
if (entities[tilen][entities[tilen].length-1].type=="player"){
px+=dx
py+=dy
}
return true
} else {
return false;
}
}
function move_atk(tile,subtile,dx,dy){
if (entities[tile.x+" "+tile.y][subtile].meta.frozen==0&&tile.x+dx==px&&tile.y+dy==py){
for (i in entities[px+" "+py]){
if (entities[px+" "+py][i].type=="player"){
php--;
}
}
} else {
move(tile,subtile,dx,dy)
}
}
function partrender(particle){
particle.tick()
}
function some(a){
return a[Math.floor(Math.random()*a.length)]
}
function call_turn(a){
a.turn()
}
function turn(e){
let maketurn=false
let dx=0;
let dy=0;
switch (e.keyCode){
case 87: case 38:
maketurn=true;dy=-1;
break;
case 65: case 37:
maketurn=true;dx=-1;
break;
case 83: case 40:
maketurn=true;dy=1;
break;
case 68: case 39:
maketurn=true;dx=1;
break;
case 82:
php=1
framecount=0
entities={}
particles=new Set()
attacks=new Set()
kills=0;
makeent(3,3,"player",{})
px=3
py=3
prevkilled=false
if (!paritychallenge){
for (var i=0;i<14;i++){
try_spawn()
}
}
break;
case 80:
paritychallenge=!paritychallenge
turn({keyCode:82})
break;
case 79:
parityoverlay=!parityoverlay
break;
}
if (px+dx<0||px+dx>49||py+dy<0||py+dy>49){
maketurn=false
}
if (maketurn&&php>0){
for (i in entities[px+" "+py]){
if (entities[px+" "+py][i].type=="player"){
if (!move({"x":px,"y":py},i,dx,dy)&&entities[px+" "+py][i].meta.frozen==0){
let nent=(px+dx)+" "+(py+dy)
for (i in entities[nent]){
if (killable[entities[nent][i].type]===true){
entities[nent][i].meta.dead=true
spawneffect("death",px+dx,py+dy)
kills++
}
}
for (var i=entities[nent].length-1;i>=0;i--){
if (entities[nent][i].meta.dead!==undefined){
entities[nent].splice(i,1)
prevkilled=true
}
}
}
}
}
for (i in entities){
for (j in entities[i]){
switch (entities[i][j].type){
case "bee":
entities[i][j].meta.moved=false
var edx=0;
var edy=0;
entities[i][j].meta.clock++;
if (entities[i][j].meta.clock%4==0){
edy=1
} else if (entities[i][j].meta.clock%4==2){
edy=-1
}
entities[i][j].meta.dx=edx;
entities[i][j].meta.dy=edy;
entities[i][j].atk=true
break;
case "apioform":
entities[i][j].meta.moved=false
var edx=0;
var edy=0;
entities[i][j].meta.clock++;
if (entities[i][j].meta.clock%4==0){
edy=1
} else if (entities[i][j].meta.clock%4==1){
edx=1
} else if (entities[i][j].meta.clock%4==2){
edy=-1
} else if (entities[i][j].meta.clock%4==3){
edx=-1
}
entities[i][j].meta.dx=edx;
entities[i][j].meta.dy=edy;
entities[i][j].atk=true
break;
case "apiodiagoform":
entities[i][j].meta.moved=false
var edx=0;
var edy=0;
entities[i][j].meta.clock++;
if (entities[i][j].meta.clock%4==0){
edy=1;edx=1;
} else if (entities[i][j].meta.clock%4==1){
edx=1;edy=-1;
} else if (entities[i][j].meta.clock%4==2){
edy=-1;edx=-1;
} else if (entities[i][j].meta.clock%4==3){
edx=-1;edy=1;
}
entities[i][j].meta.dx=edx;
entities[i][j].meta.dy=edy;
entities[i][j].atk=true
break;
case "apiokinetoform":
entities[i][j].meta.moved=false
var edx=0;
var edy=0;
entities[i][j].meta.clock++;
if (entities[i][j].meta.clock%2==0){
if (entities[i][j].x>px) edx=-1
if (entities[i][j].x<px) edx=1
if (entities[i][j].y>py) edy=-1
if (entities[i][j].y<py) edy=1
}
entities[i][j].meta.dx=edx;
entities[i][j].meta.dy=edy;
entities[i][j].atk=true
break;
case "apiopyroform":
entities[i][j].meta.moved=false
var edx=0;
var edy=0;
entities[i][j].meta.clock++;
if (entities[i][j].meta.cooldown!=0){
entities[i][j].meta.cooldown--;
}else if (entities[i][j].meta.frozen!=0){
}else{
if (entities[i][j].x==px) {
entities[i][j].meta.cooldown=2
attacks.add(new Attack(entities[i][j].x,entities[i][j].y,"fireball",{"dx":1,"dy":0}))
}else if (entities[i][j].y==py){
entities[i][j].meta.cooldown=2
attacks.add(new Attack(entities[i][j].x,entities[i][j].y,"fireball",{"dx":0,"dy":1}))
} else {
if (entities[i][j].meta.clock%2==0){
if (entities[i][j].x>px&&entities[i][j].y>py) {if (Math.random()<0.5) {edx-=1} else {edy-=1}}
else if (entities[i][j].x>px&&entities[i][j].y<py) {if (Math.random()<0.5) {edx-=1} else {edy+=1}}
else if (entities[i][j].x<px&&entities[i][j].y>py) {if (Math.random()<0.5) {edx+=1} else {edy-=1}}
else if (entities[i][j].x<px&&entities[i][j].y<py) {if (Math.random()<0.5) {edx+=1} else {edy+=1}}
else if (entities[i][j].x<px) edx=1
else if (entities[i][j].y>py) edy=-1
else if (entities[i][j].y<py) edy=1
else if (entities[i][j].x>px) edx=-1
}
}
}
entities[i][j].meta.dx=edx;
entities[i][j].meta.dy=edy;
entities[i][j].atk=true
break;
case "cryoapioform":
entities[i][j].meta.moved=false
var edx=0;
var edy=0;
entities[i][j].meta.clock++;
if (entities[i][j].meta.cooldown!=0){
entities[i][j].meta.cooldown--;
}else if (entities[i][j].meta.frozen!=0){
}else{
if (entities[i][j].x==px) {
entities[i][j].meta.cooldown=4
attacks.add(new Attack(entities[i][j].x,entities[i][j].y,"iceball",{"dx":1,"dy":0}))
}else if (entities[i][j].y==py){
entities[i][j].meta.cooldown=4
attacks.add(new Attack(entities[i][j].x,entities[i][j].y,"iceball",{"dx":0,"dy":1}))
} else {
if (entities[i][j].meta.clock%2==0){
if (entities[i][j].x>px&&entities[i][j].y>py) {if (Math.random()<0.5) {edx-=1} else {edy-=1}}
else if (entities[i][j].x>px&&entities[i][j].y<py) {if (Math.random()<0.5) {edx-=1} else {edy+=1}}
else if (entities[i][j].x<px&&entities[i][j].y>py) {if (Math.random()<0.5) {edx+=1} else {edy-=1}}
else if (entities[i][j].x<px&&entities[i][j].y<py) {if (Math.random()<0.5) {edx+=1} else {edy+=1}}
else if (entities[i][j].x<px) edx=1
else if (entities[i][j].y>py) edy=-1
else if (entities[i][j].y<py) edy=1
else if (entities[i][j].x>px) edx=-1
}
}
}
entities[i][j].meta.dx=edx;
entities[i][j].meta.dy=edy;
entities[i][j].atk=true
break;
case "apiopariform":
entities[i][j].meta.moved=false
var edx=0;
var edy=0;
if (entities[i][j].x>px&&entities[i][j].y>py) {if (Math.random()<0.5) {edx-=2} else {edy-=2}}
else if (entities[i][j].x>px&&entities[i][j].y<py) {if (Math.random()<0.5) {edx-=2} else {edy+=2}}
else if (entities[i][j].x<px&&entities[i][j].y>py) {if (Math.random()<0.5) {edx+=2} else {edy-=2}}
else if (entities[i][j].x<px&&entities[i][j].y<py) {if (Math.random()<0.5) {edx+=2} else {edy+=2}}
else if (entities[i][j].x<px) edx=2
else if (entities[i][j].y>py) edy=-2
else if (entities[i][j].y<py) edy=2
else if (entities[i][j].x>px) edx=-2
entities[i][j].meta.dx=edx;
entities[i][j].meta.dy=edy;
entities[i][j].atk=true
break;
}
if (entities[i][j].meta.frozen>0) entities[i][j].meta.frozen--
}
}
for (i in entities){
for (j in entities[i]){
if (entities[i][j].meta.dx!==undefined){
if (entities[i][j].meta.moved==false){
entities[i][j].meta.moved=true
if (entities[i][j].atk) move_atk({"x":entities[i][j].x,"y":entities[i][j].y},j,entities[i][j].meta.dx,entities[i][j].meta.dy)
else move({"x":entities[i][j].x,"y":entities[i][j].y},j,entities[i][j].meta.dx,entities[i][j].meta.dy)
}
}
}
}
attacks.forEach(call_turn)
if (localStorage.tutorial=="true"&&!frigidmode&&!paritychallenge&&((Math.random()<0.1&&kills<15)||(Math.random()<0.2&&kills>14)||(Math.random()<0.35&&kills>24))){
try_spawn()
}
if (localStorage.tutorial=="false"&&!frigidmode&&!paritychallenge&&(Math.random()<0.35)){
try_spawn()
}
if (frigidmode){
while (true){
let cx=Math.floor(Math.random()*48)+1
let cy=Math.floor(Math.random()*48)+1
let s=issolid(cx+" "+cy)
if (!s){
makeent(cx,cy,"cryoapioform",{})
} else continue
break
}
}
if (paritychallenge){
if (prevkilled){
prevkilled=false
}else{
while (true){
let cx=Math.floor(Math.random()*48)+1
let cy=Math.floor(Math.random()*48)+1
let s=issolid(cx+" "+cy)
if (!s){
makeent(cx,cy,"apiopariform",{})
} else continue
break
}
}
}
if (php<=0||px<0||px>49||py<0||py>49){
for (i in entities[px+" "+py]){
if (entities[px+" "+py][i].type=="player"){
entities[px+" "+py].splice(i,1)
spawneffect("death",px,py)
break;
}
}
}
}
console.log(kills)
if (localStorage.tutorial=="true"&&kills>30){
if ("points" in window) {
points.then(points => points.unlockAchievement("apioformGame"))
}
localStorage.tutorial=false
kills=0
}
let k=document.getElementById("kills")
k.innerHTML=`Kills: ${paritychallenge?kills:(localStorage.tutorial=="true"?"[TUTORIAL]":kills)}`
}
function call_tick(a){
a.tick()
}
function draw(){
requestAnimationFrame(draw)
ctx.fillStyle="#bbbbbb"
ctx.fillRect(0,0,500,500)
particles.forEach(partrender)
attacks.forEach(call_tick)
for (i in entities){
for (j in entities[i]){
render(entities[i][j])
}
}
}
function try_spawn(){
while (true){
let cx=Math.floor(Math.random()*48)+1
let cy=Math.floor(Math.random()*48)+1
let s=issolid(cx+" "+cy)
if (!s){
if (localStorage.tutorial=="true"){
if (kills<5){
makeent(cx,cy,"bee",{"clock":Math.floor(Math.random()*2)})
}
if (kills>4&&kills<15){
makeent(cx,cy,some(["bee","bee","apioform","apioform","apiodiagoform"]),{})
}
if (kills>14&&kills<25){
makeent(cx,cy,some(["bee","apioform","apioform","apiodiagoform","apiokinetoform","apiokinetoform"]),{})
}
if (kills>24){
makeent(cx,cy,some(["apioform","apioform","apiodiagoform","apiodiagoform","apiokinetoform","apiokinetoform","apioform","apioform","apiodiagoform","apiodiagoform","apiokinetoform","apiokinetoform","apiopyroform"]),{})
}
} else {
makeent(cx,cy,some(["apioform","apiodiagoform","apioform","apiodiagoform","apioform","apiodiagoform","apiokinetoform","apiopyroform","cryoapioform","apiopariform","apiopariform"]),{})
}
}
if (Math.random()<0.1||s){continue;}
break
}
}
function spawneffect(e,x,y){
switch (e){
case "death":
for (var i=0;i<30;i++){particles.add(new Particle(x*10+5,y*10+5,some([40,0]),some([40,0]),some([40,0]),100,Math.random()-0.5,Math.random()-0.5,some(["basic","basic","big"])))}
break;
case "frigid":
for (var i=0;i<4;i++){particles.add(new Particle(x*10+5,y*10+5,0,0,some([255,128,128,0]),70,Math.random()/2-0.25,Math.random()/2-0.25,some(["basic","big","big"])))}
break;
}
}
turn({"keyCode":82})
requestAnimationFrame(draw)
return turn
})()
document.body.addEventListener("keydown", turn)
</script>