pico-8 cartridge // http://www.pico-8.com version 16 __lua__ hiscore=0 function _init() --state=0 cartdata("konwoj") hiscore = dget(0) frame=0 menu_init() -- 0: menu -- 1: game --game_init() end function _update() frame+=1 if(state==0) then menu_update() elseif(state==1) then game_update() elseif(state==2) then gameover_update() elseif(state==3) then intro_update() end end function _draw() if(state==0) then menu_draw() elseif(state==1) then game_draw() elseif(state==2) then gameover_draw() elseif(state==3) then intro_draw() end end -->8 -- menu and gameover function menu_init() frame=0 state=0 music(0) end function menu_update() if(btnp(4) and frame>30) then intro_init() end end function menu_draw() cls(1) map(0,48,0,0,16,16) pset(0,0,11) end function gameover_init() frame=0 state=2 newhiscore=false if score > hiscore then newhiscore = true hiscore = score dset(0, hiscore) end end function gameover_update() if (btnp(4) and frame>30) then menu_init() end end function gameover_draw() cls(5) print("game over", 48, 58, 8) print("your score:", 48, 64, 8) print(score, 48, 70, 8) if newhiscore and flr(frame/10%2)==0 then print("new hi-score!", 48, 76, 8) end end function intro_init() state=3 frame=0 convx=0 convy=tank_y bgdx=0 cavex=128 intro_update() end function intro_update() if btnp(4) and frame>30 then game_init() return end if frame < 90 then convx = 20-(90-frame) elseif frame < 180 then bgdx = frame%8 elseif frame < 180+7*8 then bgdx = frame%8 cavex -= 1 elseif frame < 300+7*8 then convx += 1 else --elseif frame==180 then game_init() end end function intro_draw() cls(0) rectfill( 0,0,cavex,128,12 ) circfill( 30-frame/100, 90+frame/20, 17, 9 ) -- earth for i=0,18 do spr(2, i*8-bgdx, bottom_y) spr(18, i*8-bgdx, bottom_y+8) spr(19, i*8-bgdx, bottom_y+16) spr(18, i*8-bgdx, bottom_y+24) end --cave map( 121, 52, cavex, 0, 5, 12 ) --tanks for i=0,2 do spr( anim_spr(32,2,frame/4,2), convx+i*20, convy, 2, 2 ) line( convx+i*20+8, tank_y+4, convx+i*20+14, tank_y+4, 3 ) line( convx+i*20+6, tank_y+4, convx+i*20+9, tank_y+4, tankcol[1+i] ) end --cave map( 126, 52, cavex+5*8, 0, 2, 12 ) --print( -- hiscore, -- cavex+19, 33, -- 0 --) print( hiscore, cavex+4*8-(#tostr(hiscore)*2), 33, 0 ) end -->8 tmpval=0 tiles_top=4 tiles_bottom=4 bottom_y=128-tiles_bottom*8 tank_x=10 tank_y=bottom_y-16 gun_x=tank_x+8 gun_y=tank_y+4 gun_len=10 bat_spr=7 bg_speed=0.7 maxammo=6 tankcol={8, 9, 10} function game_init() lives=3 state=1 frame=0 stopf=0 ammo=maxammo reloadstartframe=0 score=0 tank_angle=0.0 enemies={} bullets={} frame=0 cavea_dx=0 caveb_dx=0 cavec_dx=0 music(5) game_update() lastupdated=0 --spawn_enemy() end function game_update() if (frame-stopf)%30==0 and (frame-stopf) != lastupdated then score += 10 lastupdated = frame-stopf end -- logic if (btn(4)) then stopf+=1 if (ammo0 and not stopped) then ammo-=1 add(bullets, bullet_build()) sfx(63) else sfx(61) end end -- gun angle if (btn(2)) then tank_angle=min(90, tank_angle+3) elseif (btn(3)) then tank_angle=max(-20, tank_angle-3) end -- bullets move foreach(bullets, bullet_update) -- bullets cleanup for b in all(bullets) do if (not bullet_alive(b)) then del(bullets, b) end end -- bullet-enemy collision for b in all(bullets) do tmp_bullet_hit=false for e in all(enemies) do if be_coll(b, e) then tmp_bullet_hit=true enemy_destroy(e) sfx(59) break end end if tmp_bullet_hit then del(bullets, b) end end -- player-enemy collision for e in all(enemies) do if pe_coll(e) then del(enemies, e) lives-=1 sfx(60) end end if lives<=0 then gameover_init() end -- enemies foreach(enemies, update_enemy) -- enemy spawner enemyspawner() end function draw_bg() for i=0,18 do spr(2, i*8-bgdx, bottom_y) spr(18, i*8-bgdx, bottom_y+8) spr(19, i*8-bgdx, bottom_y+16) spr(18, i*8-bgdx, bottom_y+24) end for i=0,18 do spr(2, i*8-bgdx, 24, 1, 1, false, true) spr(18, i*8-bgdx, 16) spr(19, i*8-bgdx, 8) spr(18, i*8-bgdx, 0) end map(32,0,cavea_dx,32,16,8) map(32,0,128+cavea_dx,32,16,8) map(16,0,caveb_dx,32,16,8) map(16,0,128+caveb_dx,32,16,8) map(0,0,cavec_dx,32,16,8) map(0,0,128+cavec_dx,32,16,8) --rectfill(0,0,128,tiles_top*8,4) --rectfill(0,(16-tiles_bottom)*8,128,128,4) end function draw_tanks() for i=0,lives-1 do spr( anim_spr(32,2,framem/3,2), tank_x-i*20, tank_y, 2, 2) end -- gun pset(gun_x, gun_y, 11) -- line(gun_x, gun_y, gun_x+cos(tank_angle/360)*200, gun_y+sin(tank_angle/360)*200, 5) line( gun_x, gun_y, gun_x+cos(tank_angle/360)*gun_len, gun_y+sin(tank_angle/360)*gun_len, 3 ) line( tank_x+6, tank_y+4, tank_x+9, tank_y+4, tankcol[lives] ) end function draw_enemies() -- enemies foreach(enemies, draw_enemy) --draw_bat(100,40+sin(frame/100)*5) end function draw_bullets() for b in all(bullets) do pset(b.x, b.y, 10) end end function draw_ui() rectfill(0,0,128,8,0) rectfill(0,120,128,128,0) --print(tank_angle, 100, 0, 3) for i=0,lives-1 do spr(1,i*9,0) end for i=0,ammo-1 do spr(16,30+i*4,0) end print(score,0,120,7) --print(tmpval,100,120,7) --print(frame-reloadstartframe, 120,0,3) end function game_draw() cls(0) draw_bg() draw_tanks() draw_bullets() draw_enemies() draw_ui() end -->8 -- utils function anim_spr(basespr, sprw, count, animtotal) return basespr+flr(count)%animtotal*sprw end function reload_ammo() if frame-1 != reloadlastframe then reloadstartframe = frame end reloadlastframe=frame if ((frame-reloadstartframe+1)%20==0) then ammo+=1 sfx(62) end end function bullet_build() return { x=gun_x, y=gun_y, dx=cos(tank_angle/360)*3, dy=sin(tank_angle/360)*3 } end function bullet_update(b) b.x+=b.dx b.y+=b.dy end function bullet_alive(b) return b.x<128 end -->8 -- bat function build_bat() basey=16+rnd(64) amp=rnd(min(basey-8,24)) return { type="bat", x=128, y=64, w=8, h=8, basey=basey, amp=amp, speedx=.2, speedy=.01, startframe=frame, anim_sprite=0, thresh_x=64, alive=true, rushx=0, rushy=0, } end function update_bat(e) f=frame-e.startframe e.x-=e.speedx if (e.x>e.thresh_x) then -- fly e.y=e.basey+sin(f*e.speedy)*e.amp else --attack if (e.rushx==0) then e.rushx = (gun_x - e.x)/30 e.rushy = (gun_y - e.y)/30 end e.x+=e.rushx e.y+=e.rushy end e.anim_sprite=anim_spr(7,1,f/4,2) end function draw_bat(e) spr(e.anim_sprite,e.x,e.y) end -- spider function build_spider() fallx=gun_x+5+rnd(128-gun_x-10) return { type="spider", x=128, y=32, w=16, h=8, speedx=1.5, speedy=0, startframe=frame, anim_sprite=20, ontop=1, fallx=fallx, floorboost=1.5 } end function update_spider(e) f=frame-e.startframe if e.ontop == 1 then e.x-=e.speedx elseif e.speedy == 0 then e.x-=e.speedx*e.floorboost else if not stopped then e.x-=bg_speed end end if e.x= bottom_y then e.speedy = 0 e.y = bottom_y-e.h end e.anim_sprite=anim_spr(20,2,f/2,2) --tmpval=e.anim_sprite end function draw_spider(e) spr(e.anim_sprite, e.x, e.y, 2, 1, false, e.ontop==1) end -- stone function build_stone() return { type="stone", x=128, y=bottom_y-16, w=8, h=16, } end function update_stone(e) if not stopped then e.x-=bg_speed end end function draw_stone(e) spr(9, e.x, e.y, 1, 2) end -- general function draw_enemy(e) if (e.type=="bat") then draw_bat(e) elseif (e.type=="spider") then draw_spider(e) elseif (e.type=="stone") then draw_stone(e) end end function update_enemy(e) if (e.type=="bat") then update_bat(e) elseif (e.type=="spider") then update_spider(e) elseif (e.type=="stone") then update_stone(e) end end function spawn_enemy() tmp_r = rnd(3) --tmp_r=7 if tmp_r < 1 then add(enemies, build_bat()) elseif tmp_r < 2 then add(enemies, build_spider()) else add(enemies, build_stone()) end end function enemy_destroy(e) del(enemies, e) if e.type=="bat" then score+=100 elseif e.type=="spider" then score+=200 end end function enemyspawner() if (frame%85==0) then spawn_enemy() end end -->8 --collisions function be_coll(b, e) if b.x>=e.x and b.x=e.y and b.y