Created
July 31, 2017 06:43
-
-
Save egordorichev/5f96027c36214ca030f184852650ddcd to your computer and use it in GitHub Desktop.
Revisions
-
egordorichev created this gist
Jul 31, 2017 .There are no files selected for viewing
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters. Learn more about bidirectional Unicode charactersOriginal file line number Diff line number Diff line change @@ -0,0 +1,917 @@ -- spacy adventure -- by @egordorichev -- -- main callbacks -- cartdata("ld39") t=1 dmg=5 hscore=dget(0) or 0 function _init() music(-1) music(5,1) -- init engine record=false drk=parse"0=0,0,1,1,2,1,5,13,2,4,9,3,1,1,2,4" t,shx,shy,cx,cy=0,0,0,0,0 menu=true -- \145\132\152\148\144\145\132 nt=0 objs=parse[[ to_update={}, collidable={}, enemies={} ]] for i=0,4 do objs["to_draw"..i]={} end -- init game prc={50,30,30} local sc={1,1,13,13} for i=0,30 do local n=flr(rnd(#sc)+1) def([[ regs={to_draw1} ]],{ x=rnd(128), y=rnd(128), c=sc[n], vy=n*1.5, draw=draw_star }) end energy=60 lenergy=60 pdmg=1 pimt=60 local fcc={10,8,11,13,15} local n=flr(rnd(#fcc))+1 local fc=fcc[n] local scc={9,2,3,1,14} local sc=scc[n] player=def([[ at=0, x=60, f=0, y=88, pl=true, w=8, h=8, st=0, s=0.5, t=0, slc=11, it=0, vx=0, vy=0, health=3, regs={to_update,to_draw3,collidable} ]],{ update=update_player, draw=draw_player, fc=fc, sc=sc }) stt=0 end function _update() t=(t+1)%180 if energy~=lenergy then local d=(lenergy-energy) lenergy-=d*0.1 end if menu then for obj in all(objs.to_update) do obj.update(obj) end -- update menu if btn(4) then menu=false music(-1) --music(0,1) shake_screen(10) energy=60 score=0 lenergy=energy gameover=false distance=0 pdmg=1 player.it=pimt spef=false cb="get ready!" cbt=0 t=0 shop=false end return end -- update game if abs(shx)+abs(shy)<0.5 then shx,shy=0,0 end shx*=-0.7 shy*=-0.7 -- update objects for obj in all(objs.to_update) do obj.update(obj) end -- game stuff if player.hidden then return end if(not shop and not menu) energy-=0.03 if energy<=0 then energy=0 -- todo: gameover player.hidden=true new_explosion(player.x+4,player.y+4) return end if shop then if btnp(0) or btnp(2) then sae-=1 if(sae<=0) sae=3 sfx(10) end if btnp(1) or btnp(3) then sae+=1 if(sae>=4) sae=1 sfx(10) end if btnp(4) then shop=false end if btnp(5) then if score<prc[sae] then sfx(9) else sfx(7) score-=prc[sae] spawn_particles(player.x+4,player.y+4,8) prc[sae]=flr(prc[sae]*1.8) if sae==1 then pimt+=30 elseif sae==2 then pdmg+=1 elseif sae==3 then player.s+=0.2 player.pc=9 end end end return end if(not bsa and btnp(4)) sfx(10) sae=1 shop=true stt=max(0,stt-1) if gameover then return end distance+=0.1 if t>=40 and not spef then spef=true spawn_enemies() end --if bsa then return end if t==0 then nt=(nt+1)%60 local r=rnd() local x=rnd(116)+8 if r>0.6 or (energy<21 and rnd()<0.6) then new_pickup("bat",x,-8) elseif not bsa and r>0.5 then new_pickup("bmb",x,-8) elseif not bsa and r>0.4 then new_pickup("clk",x,-8) else new_pickup("sld",x,-8) end end if not bsa and #objs.enemies==0 and spef then spawn_enemies() end if #objs.enemies<6 and not bsa and t==0 and spef then spawn_enemies(1) end end function _draw() cls() if menu then -- draw menu draw_objects() printc("spacy adventure",10) printc("by @egordorichev",20) printc("\139\145 - move ",40) printc("\151 - shoot ",50) printc("\142 - shop ",60) text("press \142 to start",32,110) return end camera(cx+shx,cy+shy) -- draw game draw_objects() camera(0,0) -- draw ui print("energy",2,2,7) print(score.." $",127-#(score.." $")*4,2,7) print(flr(distance).." p",127-#(flr(distance).." p")*4,8,7) if(max(lenergy,0)>0) rectfill(2,8,max(lenergy,0)+2,8,14) if(max(energy,0)>0) rectfill(2,8,max(energy,0)+2,8,7) if gameover then printc("new score: "..flr(distance),30) if record then printc("new record!",40) else printc("high score: "..hscore,40) end printc("out of power!",70) if(t%30>10) printc("press \142 to retry ",80) if btnp(4) then sfx(10) _init() end end if shop then -- \145\148\136\142\132\145 printc("shop",22) -- dont forget to change if values here, if you change price printc("upgrade shield "..prc[1].."$",50,sae==1 and 14 or (score>=prc[1] and 1 or 5)) printc("upgrade cannon "..prc[2].."$",60,sae==2 and 14 or (score>=prc[2] and 1 or 5)) printc("upgrade engine "..prc[3].."$",70,sae==3 and 14 or (score>=prc[3] and 1 or 5)) printc("\151 - buy, \142 - exit ",90) return end if not gameover and energy<11 and t%30>15 then printc("!!!low energy!!!",12,8) end if distance>10 and distance%50<1 and cb==nil then cb="passed "..flr(distance).." p" cbt=0 end if cb~=nil then cbt+=1 printc(cb,60) if cbt>60 then cbt=0 if cb=="passed 150 p" then cb="boss stage!" cbt=0 for e in all(objs.enemies) do e.mva=true e.tx=rnd()<0.5 and -30 or 150 end elseif cb=="boss stage!" then cb=nil new_enemy(4) else cb=nil end end end end function printc(t,y,c) text(t,(128-#t*4)/2,y,c) end -- -- game stuff -- -- player function update_player(p) if gameover or shop then return end if p.hidden then gameover=true sfx(1) if flr(distance)>hscore then hscore=flr(distance) record=true end dset(0,hscore) cls(7) flip() flip() return end p.st=max(0,p.st-1) p.it=max(0,p.it-1) if(p.it==0) p.slc=11 if(btn(0)) p.vx-=p.s if(btn(1)) p.vx+=p.s if(btn(2)) p.vy-=p.s if(btn(3)) p.vy+=p.s if btnp(5) then new_bullet(p.x,p.y) p.st=2 end p.x+=p.vx p.y+=p.vy --if abs(p.vx)+abs(p.vy)<0.5 then -- energy-=0.1 --end p.vx*=0.8 p.vy*=0.8 if p.x<0 then p.x=0 end if p.x>120 then p.x=120 end if p.y<0 then p.y=0 end if p.y>120 then p.y=120 end --p.at=(p.at+1)%5 --if(p.at==0) p.f=(p.f+1)%3 p.t=(p.t+1)%2 if p.t==0 then new_particle(p.x+2+rnd(3),p.y+6+rnd(2),p.pc or 2,0,rnd(2),2) end end function draw_player(p) if p.it%4>1 and p.it<60 then for i=0,15 do pal(i,7) end else pal(8,p.fc) pal(2,p.sc) end spr(48,p.x,p.y) if p.it%4>1 and p.it<60 then for i=0,15 do pal(i,i) end else pal(8,8) pal(2,2) end if p.st>0 then spr(3,p.x,p.y-4) end if p.it>0 then for i=0,15 do circ(sin(i/15+t/90)*10+player.x+4, cos(i/15+t/90)*10+player.y+4,1,p.slc) end end end -- enemies function spawn_enemies(c) lst={} if(distance<75) add(lst,1) if(distance>=50) add(lst,2) if(distance>=160) add(lst,3) for i=0,(c or 3)-1 do new_enemy(lst[flr(rnd(#lst))+1]) end end function new_enemy(t) t=t or 1 local boss=false if t==1 then dmg=dmg h=1 s=1 sp=rnd()>0.5 and 16 or 32 shp=20 up=function(e) e.tx=rnd(128) e.ty=10+rnd(48) end elseif t==2 then dmg=dmg+2 h=2 s=0.7 sp=rnd()>0.5 and 18 or 34 shp=14 up=function(e) if abs(e.x-player.x)<10 then e.tx=20+rnd(108) else e.tx=player.x-8+rnd(16) end e.ty=10+rnd(48) end elseif t==3 then dmg=dmg+3 h=3 s=0.7 sp=rnd()<0.5 and 20 or 37 shp=14 up=function(e) if abs(e.x-player.x)<10 then e.tx=20+rnd(108) else e.tx=player.x-8+rnd(16) end e.ty=e.y end elseif t==4 then -- boss! \132\132\148\136\150\132\150 dmg=dmg+2 lbt=t h=10 s=0.6 sp=6 shp=36 boss=true he=16 we=16 bsa=true up=function(e) if abs(e.x-player.x)<10 then e.tx=20+rnd(108) else e.tx=player.x-8+rnd(16) end e.ty=e.y if e.rt%shp==0 and rnd()<0.5 then new_bullet(e.x+4,e.y+4,-1,e) e.st=2 end if (t-lbt)<30 then lbt=t new_pickup("bmb",e.x,e.y) end end end local d=1 if(rnd()<0.5) d=-1 return def([[ en=true, it=0, t=0, af=0, at=0, st=0, rt=0, regs={enemies,to_update,to_draw3,collidable} ]],{ x=rnd(128), d=d, health=h, s=s, w=we or 8, h=he or 8, boss=boss or false, dmg=dmg, sp=sp, y=-28, up=up, tx=rnd(128), ty=8, r=rnd(20)+40, update=update_enemy, draw=draw_enemy, shp=shp }) end function update_enemy(e) e.st=max(0,e.st-1) e.it=max(0,e.it-1) e.t=(e.t+1)%2 e.rt=(e.rt+1)%60 if(stt~=0 or shop) return if e.rt%shp==0 and rnd()<0.5 then if e.boss then new_bullet(e.x+4,e.y+4,-1,e) else new_bullet(e.x,e.y,-1,e) end e.st=2 end if e.t==0 then new_particle(e.x+2+rnd(3),e.y-1+rnd(2),2,0,-rnd(2),2) end if not mva and abs(e.x-e.tx)+abs(e.y-e.ty)<3 then e.up(e) else e.x+=mid(e.s,e.tx-e.x,-e.s) e.y+=mid(e.s,e.ty-e.y,-e.s) end if e.x<-10 or e.x>130 then deregister(e) return end e.at=(e.at+1)%8 if(e.at==0) e.af=(e.af+1)%2 if not player.hidden and collide(e.x,e.y,e.w,e.h, player.x,player.y,player.w,player.h) then shake_screen(4) if player.it>0 and not e.boss then e.health=0 deregister(e) new_explosion(e.x+4,e.y+4) score+=5 else energy=0 end end end function draw_enemy(e) if e.it%4>1 then for i=0,15 do pal(i,7) end end if e.boss then sspr(48+e.af*16,0,16,16,e.x,e.y) else spr(e.sp+e.af,e.x,e.y) end if e.it%4>1 then for i=0,15 do pal(i,i) end end if e.boss then if(e.st>0) spr(0,e.x+4,e.y+12) else if(e.st>0) spr(0,e.x,e.y+4) end end -- bullets function new_bullet(x,y,s,b) sfx(2) if(not b and not menu) energy-=1 return def([[ regs={to_update,to_draw2} ]],{ x=x, y=y, dmg=b and b.dmg or pdmg, vy=-9*(s or 1), d=s or 1, bad=b or false, update=update_bullet, draw=draw_bullet }) end function update_bullet(b) if b.hidden or shop then return end b.y+=b.vy if b.x<=-8 or b.x>=136 or b.y<=-8 or b.y>=136 then deregister(b) b.hidden=true sfx(8) for i=0,5 do new_particle(b.x+4,b.y+10,rnd(2)+9,rnd(2)-1,rnd(1)+0.5) end return end for o in all(objs.collidable) do if o.en and not b.bad or o.pl and b.bad then if collide(o.x,o.y,o.w,o.h, b.x+3,b.y+1,2,5) then deregister(b) b.hidden=true shake_screen(4) sfx(8) if o.en then if o.it==0 then o.health-=b.dmg o.it=15 if o.health<=0 then if(o.boss) shake_screen(4) bsa=false cb="boss defeated!" cbt=0 deregister(o) new_explosion(b.x+4,b.y+4) if(not b.bad) score+=5 end end -- todo: feed back else if o.it==0 then energy-=b.dmg o.it=pimt end -- todo: feed back end end end end end function draw_bullet(b) spr(1,b.x,b.y) --print(b.dmg,b.x,b.y,7) if(t%3) new_particle(b.x+3+rnd(2),b.y+4+b.d*4,9,0,b.d*rnd(2),1) end -- pickups function new_pickup(t,x,y) if t=="bat" then s=2 elseif t=="sld" then s=4 elseif t=="clk" then s=5 elseif t=="bmb" then s=36 end return def([[ regs={to_draw2}, w=8, h=8 ]],{ t=t, s=s, x=x, y=y, draw=draw_pickup }) end function draw_pickup(p) if shop then return end p.y+=2 if (p.y>136) deregister(p) return if not player.hidden and collide(p.x,p.y,p.w,p.h, player.x,player.y,player.w,player.h) then deregister(p) spawn_particles(p.x+4,p.y+4,10) sfx(7) if p.t=="bat" then energy=min(energy+40,60) elseif p.t=="sld" then player.it=90+pimt player.slc=12 elseif p.t=="clk" then stt=180 elseif p.t=="bmb" then energy-=dmg*2 new_explosion(player.x+4,player.y+4) end end if(t%2) new_particle(p.x+3+rnd(2),p.y-1,7,0,-rnd(2),2) spr(p.s,p.x,p.y) end -- explosions function new_explosion(x,y) sfx(3) spawn_particles(x,y) for i=0,5 do new_particle(x,y,rnd(2)+5,rnd(10)-5,rnd(10)-5,2) end for i=0,5 do new_particle(x,y,5,rnd(5)-2.5,rnd(5)-2.5,rnd(2)+4) end return def([[ regs={to_draw4}, r=0 ]],{ x=x, y=y, draw=draw_explosion }) end function draw_explosion(e) e.r+=2--todo: better way if(e.r>=29) deregister(e) circ(e.x,e.y,e.r,min(e.r/10+8,10)) end -- particles function new_particle(x,y,cl,vx,vy,r) return def([[ regs={to_draw4} ]],{ draw=draw_particle, x=x, y=y, vx=vx or (rnd(2)-1), vy=vy or (rnd(2)-1-1), r=r or (rnd(4)+2), cl=cl or rnd(16) }) end function draw_particle(p) p.x+=p.vx p.y+=p.vy p.vx*=0.95 p.vy*=0.95 p.r-=0.1 circfill(p.x,p.y,p.r,p.cl) if p.r<=0 then deregister(p) end end function spawn_particles(x,y,c) for i=0,5+rnd(10) do new_particle(x,y,c or (rnd(2)+5)) end end -- stars function draw_star(s) s.y+=s.vy if s.y>128 then s.x=rnd(128) s.y=-1 end rect(s.x,s.y,s.x,s.y+s.vy/1.5,s.c) end -- -- engine -- -- graphics function darken(double,scrn) if double then for i=0,15 do pal(i,drk[drk[i]],scrn) end else for i=0,15 do pal(i,drk[i],scrn) end end end function darkout() darken(false,1) flip() flip() darken(true,1) flip() flip() cls() flip() flip() end function darkin() _draw() flip() flip() darken(false,1) flip() flip() for i=0,15 do pal(i,i,1) end end function shake_screen(am) local a=rnd() shx=am*cos(a or 1) shy=am*sin(a or 1) end function text(s,x,y,c) for ty=y+2,y-1,-1 do for tx=x-1,x+1 do print(s,tx,ty,ty==y+2 and 6 or 7) end end print(s,x,y,c or 1) end -- objects function draw_objects() for i=0,4 do local dobjs=objs["to_draw"..i] -- sort by y for i=2,#dobjs do if dobjs[i-1].y>dobjs[i].y then local k=i while(k>1 and dobjs[k-1].y>dobjs[k].y) do local s=dobjs[k] dobjs[k],dobjs[k-1]=dobjs[k-1],s k-=1 end end end for obj in all(dobjs) do if not obj.hidden then obj.draw(obj) end end end end -- collisions function collide(x1,y1,w1,h1, x2,y2,w2,h2) return x1<x2+w2 and x2<x1+w1 and y1<y2+h2 and y2<y1+h1 end function collide_map(o) -- 70 tokens! local x1=o.x//8 local y1=o.y//8 local x2=(o.x+7)//8 local y2=(o.y+7)//8 local a=fget(mget(x1,y1),0) local b=fget(mget(x1,y2),0) local c=fget(mget(x2,y2),0) local d=fget(mget(x2,y1),0) return a or b or c or d end -- objects function register(o) for r in all(o.regs) do add(objs[r],o) end end function deregister(o) for r in all(o.regs) do del(objs[r],o) end end -- string tricks (~300 tokens) nums={} for i=0,9 do nums[""..i]=true end function parse(str,ar) local c,lc,ar,field=1,1,{} while c<=#str do local char=sub(str,c,c) if char=='{' then local sc,k=c+1,0 while sub(str,c,c)~='}' or k>1 do char=sub(str,c,c) if char=='{' then k+=1 elseif char=='}' then k-=1 end c+=1 end local v=parse(sub(str,sc,c-1)) if field then ar[field]=v else add(ar,v) end lc=c+2 c+=1 elseif char=='=' then field,lc=sub(str,lc,c-1),c+1 elseif char==',' or c==#str then if c==#str then c+=1 end local v,vb=sub(str,lc,c-1),sub(str,lc+1,c-1) local fc=sub(v,1,1) if nums[fc] then v=v*1 elseif fc=='%' then v=rnd(vb) elseif v=='true' then v=true elseif v=='false' then v=false end if field then if nums[sub(field,1,1)] then field=field*1 end ar[field]=v else add(ar,v) end field,lc=nil,c+1 elseif char=='\n' then lc+=1 end c+=1 end return ar end function merge(a,b) for k,v in pairs(b) do a[k]=v end return a end function def(s,p) local o=merge(parse(s),p) register(o) return o end