commit 4918e72f7ec5c82ed0579e12aee9262dda6d9aef Author: Mark Date: Wed Feb 15 19:23:30 2023 -0800 Added pico-8 files diff --git a/celeste/bin/carts/celeste.p8 b/celeste/bin/carts/celeste.p8 new file mode 100755 index 0000000..0ea0b2d --- /dev/null +++ b/celeste/bin/carts/celeste.p8 @@ -0,0 +1,1835 @@ +pico-8 cartridge // http://www.pico-8.com +version 16 +__lua__ +-- ~celeste~ +-- matt thorson + noel berry + +-- globals -- +------------- + +room = { x=0, y=0 } +objects = {} +types = {} +freeze=0 +shake=0 +will_restart=false +delay_restart=0 +got_fruit={} +has_dashed=false +sfx_timer=0 +has_key=false +pause_player=false +flash_bg=false +music_timer=0 + +k_left=0 +k_right=1 +k_up=2 +k_down=3 +k_jump=4 +k_dash=5 + +-- entry point -- +----------------- + +function _init() + title_screen() +end + +function title_screen() + got_fruit = {} + for i=0,29 do + add(got_fruit,false) end + frames=0 + deaths=0 + max_djump=1 + start_game=false + start_game_flash=0 + music(40,0,7) + + load_room(7,3) +end + +function begin_game() + frames=0 + seconds=0 + minutes=0 + music_timer=0 + start_game=false + music(0,0,7) + load_room(0,0) +end + +function level_index() + return room.x%8+room.y*8 +end + +function is_title() + return level_index()==31 +end + +-- effects -- +------------- + +clouds = {} +for i=0,16 do + add(clouds,{ + x=rnd(128), + y=rnd(128), + spd=1+rnd(4), + w=32+rnd(32) + }) +end + +particles = {} +for i=0,24 do + add(particles,{ + x=rnd(128), + y=rnd(128), + s=0+flr(rnd(5)/4), + spd=0.25+rnd(5), + off=rnd(1), + c=6+flr(0.5+rnd(1)) + }) +end + +dead_particles = {} + +-- player entity -- +------------------- + +player = +{ + init=function(this) + this.p_jump=false + this.p_dash=false + this.grace=0 + this.jbuffer=0 + this.djump=max_djump + this.dash_time=0 + this.dash_effect_time=0 + this.dash_target={x=0,y=0} + this.dash_accel={x=0,y=0} + this.hitbox = {x=1,y=3,w=6,h=5} + this.spr_off=0 + this.was_on_ground=false + create_hair(this) + end, + update=function(this) + if (pause_player) return + + local input = btn(k_right) and 1 or (btn(k_left) and -1 or 0) + + -- spikes collide + if spikes_at(this.x+this.hitbox.x,this.y+this.hitbox.y,this.hitbox.w,this.hitbox.h,this.spd.x,this.spd.y) then + kill_player(this) end + + -- bottom death + if this.y>128 then + kill_player(this) end + + local on_ground=this.is_solid(0,1) + local on_ice=this.is_ice(0,1) + + -- smoke particles + if on_ground and not this.was_on_ground then + init_object(smoke,this.x,this.y+4) + end + + local jump = btn(k_jump) and not this.p_jump + this.p_jump = btn(k_jump) + if (jump) then + this.jbuffer=4 + elseif this.jbuffer>0 then + this.jbuffer-=1 + end + + local dash = btn(k_dash) and not this.p_dash + this.p_dash = btn(k_dash) + + if on_ground then + this.grace=6 + if this.djump 0 then + this.grace-=1 + end + + this.dash_effect_time -=1 + if this.dash_time > 0 then + init_object(smoke,this.x,this.y) + this.dash_time-=1 + this.spd.x=appr(this.spd.x,this.dash_target.x,this.dash_accel.x) + this.spd.y=appr(this.spd.y,this.dash_target.y,this.dash_accel.y) + else + + -- move + local maxrun=1 + local accel=0.6 + local deccel=0.15 + + if not on_ground then + accel=0.4 + elseif on_ice then + accel=0.05 + if input==(this.flip.x and -1 or 1) then + accel=0.05 + end + end + + if abs(this.spd.x) > maxrun then + this.spd.x=appr(this.spd.x,sign(this.spd.x)*maxrun,deccel) + else + this.spd.x=appr(this.spd.x,input*maxrun,accel) + end + + --facing + if this.spd.x!=0 then + this.flip.x=(this.spd.x<0) + end + + -- gravity + local maxfall=2 + local gravity=0.21 + + if abs(this.spd.y) <= 0.15 then + gravity*=0.5 + end + + -- wall slide + if input!=0 and this.is_solid(input,0) and not this.is_ice(input,0) then + maxfall=0.4 + if rnd(10)<2 then + init_object(smoke,this.x+input*6,this.y) + end + end + + if not on_ground then + this.spd.y=appr(this.spd.y,maxfall,gravity) + end + + -- jump + if this.jbuffer>0 then + if this.grace>0 then + -- normal jump + psfx(1) + this.jbuffer=0 + this.grace=0 + this.spd.y=-2 + init_object(smoke,this.x,this.y+4) + else + -- wall jump + local wall_dir=(this.is_solid(-3,0) and -1 or this.is_solid(3,0) and 1 or 0) + if wall_dir!=0 then + psfx(2) + this.jbuffer=0 + this.spd.y=-2 + this.spd.x=-wall_dir*(maxrun+1) + if not this.is_ice(wall_dir*3,0) then + init_object(smoke,this.x+wall_dir*6,this.y) + end + end + end + end + + -- dash + local d_full=5 + local d_half=d_full*0.70710678118 + + if this.djump>0 and dash then + init_object(smoke,this.x,this.y) + this.djump-=1 + this.dash_time=4 + has_dashed=true + this.dash_effect_time=10 + local v_input=(btn(k_up) and -1 or (btn(k_down) and 1 or 0)) + if input!=0 then + if v_input!=0 then + this.spd.x=input*d_half + this.spd.y=v_input*d_half + else + this.spd.x=input*d_full + this.spd.y=0 + end + elseif v_input!=0 then + this.spd.x=0 + this.spd.y=v_input*d_full + else + this.spd.x=(this.flip.x and -1 or 1) + this.spd.y=0 + end + + psfx(3) + freeze=2 + shake=6 + this.dash_target.x=2*sign(this.spd.x) + this.dash_target.y=2*sign(this.spd.y) + this.dash_accel.x=1.5 + this.dash_accel.y=1.5 + + if this.spd.y<0 then + this.dash_target.y*=.75 + end + + if this.spd.y!=0 then + this.dash_accel.x*=0.70710678118 + end + if this.spd.x!=0 then + this.dash_accel.y*=0.70710678118 + end + elseif dash and this.djump<=0 then + psfx(9) + init_object(smoke,this.x,this.y) + end + + end + + -- animation + this.spr_off+=0.25 + if not on_ground then + if this.is_solid(input,0) then + this.spr=5 + else + this.spr=3 + end + elseif btn(k_down) then + this.spr=6 + elseif btn(k_up) then + this.spr=7 + elseif (this.spd.x==0) or (not btn(k_left) and not btn(k_right)) then + this.spr=1 + else + this.spr=1+this.spr_off%4 + end + + -- next level + if this.y<-4 and level_index()<30 then next_room() end + + -- was on the ground + this.was_on_ground=on_ground + + end, --121 then + this.x=clamp(this.x,-1,121) + this.spd.x=0 + end + + set_hair_color(this.djump) + draw_hair(this,this.flip.x and -1 or 1) + spr(this.spr,this.x,this.y,1,1,this.flip.x,this.flip.y) + unset_hair_color() + end +} + +psfx=function(num) + if sfx_timer<=0 then + sfx(num) + end +end + +create_hair=function(obj) + obj.hair={} + for i=0,4 do + add(obj.hair,{x=obj.x,y=obj.y,size=max(1,min(2,3-i))}) + end +end + +set_hair_color=function(djump) + pal(8,(djump==1 and 8 or djump==2 and (7+flr((frames/3)%2)*4) or 12)) +end + +draw_hair=function(obj,facing) + local last={x=obj.x+4-facing*2,y=obj.y+(btn(k_down) and 4 or 3)} + foreach(obj.hair,function(h) + h.x+=(last.x-h.x)/1.5 + h.y+=(last.y+0.5-h.y)/1.5 + circfill(h.x,h.y,h.size,8) + last=h + end) +end + +unset_hair_color=function() + pal(8,8) +end + +player_spawn = { + tile=1, + init=function(this) + sfx(4) + this.spr=3 + this.target= {x=this.x,y=this.y} + this.y=128 + this.spd.y=-4 + this.state=0 + this.delay=0 + this.solids=false + create_hair(this) + end, + update=function(this) + -- jumping up + if this.state==0 then + if this.y < this.target.y+16 then + this.state=1 + this.delay=3 + end + -- falling + elseif this.state==1 then + this.spd.y+=0.5 + if this.spd.y>0 and this.delay>0 then + this.spd.y=0 + this.delay-=1 + end + if this.spd.y>0 and this.y > this.target.y then + this.y=this.target.y + this.spd = {x=0,y=0} + this.state=2 + this.delay=5 + shake=5 + init_object(smoke,this.x,this.y+4) + sfx(5) + end + -- landing + elseif this.state==2 then + this.delay-=1 + this.spr=6 + if this.delay<0 then + destroy_object(this) + init_object(player,this.x,this.y) + end + end + end, + draw=function(this) + set_hair_color(max_djump) + draw_hair(this,1) + spr(this.spr,this.x,this.y,1,1,this.flip.x,this.flip.y) + unset_hair_color() + end +} +add(types,player_spawn) + +spring = { + tile=18, + init=function(this) + this.hide_in=0 + this.hide_for=0 + end, + update=function(this) + if this.hide_for>0 then + this.hide_for-=1 + if this.hide_for<=0 then + this.spr=18 + this.delay=0 + end + elseif this.spr==18 then + local hit = this.collide(player,0,0) + if hit ~=nil and hit.spd.y>=0 then + this.spr=19 + hit.y=this.y-4 + hit.spd.x*=0.2 + hit.spd.y=-3 + hit.djump=max_djump + this.delay=10 + init_object(smoke,this.x,this.y) + + -- breakable below us + local below=this.collide(fall_floor,0,1) + if below~=nil then + break_fall_floor(below) + end + + psfx(8) + end + elseif this.delay>0 then + this.delay-=1 + if this.delay<=0 then + this.spr=18 + end + end + -- begin hiding + if this.hide_in>0 then + this.hide_in-=1 + if this.hide_in<=0 then + this.hide_for=60 + this.spr=0 + end + end + end +} +add(types,spring) + +function break_spring(obj) + obj.hide_in=15 +end + +balloon = { + tile=22, + init=function(this) + this.offset=rnd(1) + this.start=this.y + this.timer=0 + this.hitbox={x=-1,y=-1,w=10,h=10} + end, + update=function(this) + if this.spr==22 then + this.offset+=0.01 + this.y=this.start+sin(this.offset)*2 + local hit = this.collide(player,0,0) + if hit~=nil and hit.djump0 then + this.timer-=1 + else + psfx(7) + init_object(smoke,this.x,this.y) + this.spr=22 + end + end, + draw=function(this) + if this.spr==22 then + spr(13+(this.offset*8)%3,this.x,this.y+6) + spr(this.spr,this.x,this.y) + end + end +} +add(types,balloon) + +fall_floor = { + tile=23, + init=function(this) + this.state=0 + this.solid=true + end, + update=function(this) + -- idling + if this.state == 0 then + if this.check(player,0,-1) or this.check(player,-1,0) or this.check(player,1,0) then + break_fall_floor(this) + end + -- shaking + elseif this.state==1 then + this.delay-=1 + if this.delay<=0 then + this.state=2 + this.delay=60--how long it hides for + this.collideable=false + end + -- invisible, waiting to reset + elseif this.state==2 then + this.delay-=1 + if this.delay<=0 and not this.check(player,0,0) then + psfx(7) + this.state=0 + this.collideable=true + init_object(smoke,this.x,this.y) + end + end + end, + draw=function(this) + if this.state!=2 then + if this.state!=1 then + spr(23,this.x,this.y) + else + spr(23+(15-this.delay)/5,this.x,this.y) + end + end + end +} +add(types,fall_floor) + +function break_fall_floor(obj) + if obj.state==0 then + psfx(15) + obj.state=1 + obj.delay=15--how long until it falls + init_object(smoke,obj.x,obj.y) + local hit=obj.collide(spring,0,-1) + if hit~=nil then + break_spring(hit) + end + end +end + +smoke={ + init=function(this) + this.spr=29 + this.spd.y=-0.1 + this.spd.x=0.3+rnd(0.2) + this.x+=-1+rnd(2) + this.y+=-1+rnd(2) + this.flip.x=maybe() + this.flip.y=maybe() + this.solids=false + end, + update=function(this) + this.spr+=0.2 + if this.spr>=32 then + destroy_object(this) + end + end +} + +fruit={ + tile=26, + if_not_fruit=true, + init=function(this) + this.start=this.y + this.off=0 + end, + update=function(this) + local hit=this.collide(player,0,0) + if hit~=nil then + hit.djump=max_djump + sfx_timer=20 + sfx(13) + got_fruit[1+level_index()] = true + init_object(lifeup,this.x,this.y) + destroy_object(this) + end + this.off+=1 + this.y=this.start+sin(this.off/40)*2.5 + end +} +add(types,fruit) + +fly_fruit={ + tile=28, + if_not_fruit=true, + init=function(this) + this.start=this.y + this.fly=false + this.step=0.5 + this.solids=false + this.sfx_delay=8 + end, + update=function(this) + --fly away + if this.fly then + if this.sfx_delay>0 then + this.sfx_delay-=1 + if this.sfx_delay<=0 then + sfx_timer=20 + sfx(14) + end + end + this.spd.y=appr(this.spd.y,-3.5,0.25) + if this.y<-16 then + destroy_object(this) + end + -- wait + else + if has_dashed then + this.fly=true + end + this.step+=0.05 + this.spd.y=sin(this.step)*0.5 + end + -- collect + local hit=this.collide(player,0,0) + if hit~=nil then + hit.djump=max_djump + sfx_timer=20 + sfx(13) + got_fruit[1+level_index()] = true + init_object(lifeup,this.x,this.y) + destroy_object(this) + end + end, + draw=function(this) + local off=0 + if not this.fly then + local dir=sin(this.step) + if dir<0 then + off=1+max(0,sign(this.y-this.start)) + end + else + off=(off+0.25)%3 + end + spr(45+off,this.x-6,this.y-2,1,1,true,false) + spr(this.spr,this.x,this.y) + spr(45+off,this.x+6,this.y-2) + end +} +add(types,fly_fruit) + +lifeup = { + init=function(this) + this.spd.y=-0.25 + this.duration=30 + this.x-=2 + this.y-=4 + this.flash=0 + this.solids=false + end, + update=function(this) + this.duration-=1 + if this.duration<= 0 then + destroy_object(this) + end + end, + draw=function(this) + this.flash+=0.5 + + print("1000",this.x-2,this.y,7+this.flash%2) + end +} + +fake_wall = { + tile=64, + if_not_fruit=true, + update=function(this) + this.hitbox={x=-1,y=-1,w=18,h=18} + local hit = this.collide(player,0,0) + if hit~=nil and hit.dash_effect_time>0 then + hit.spd.x=-sign(hit.spd.x)*1.5 + hit.spd.y=-1.5 + hit.dash_time=-1 + sfx_timer=20 + sfx(16) + destroy_object(this) + init_object(smoke,this.x,this.y) + init_object(smoke,this.x+8,this.y) + init_object(smoke,this.x,this.y+8) + init_object(smoke,this.x+8,this.y+8) + init_object(fruit,this.x+4,this.y+4) + end + this.hitbox={x=0,y=0,w=16,h=16} + end, + draw=function(this) + spr(64,this.x,this.y) + spr(65,this.x+8,this.y) + spr(80,this.x,this.y+8) + spr(81,this.x+8,this.y+8) + end +} +add(types,fake_wall) + +key={ + tile=8, + if_not_fruit=true, + update=function(this) + local was=flr(this.spr) + this.spr=9+(sin(frames/30)+0.5)*1 + local is=flr(this.spr) + if is==10 and is!=was then + this.flip.x=not this.flip.x + end + if this.check(player,0,0) then + sfx(23) + sfx_timer=10 + destroy_object(this) + has_key=true + end + end +} +add(types,key) + +chest={ + tile=20, + if_not_fruit=true, + init=function(this) + this.x-=4 + this.start=this.x + this.timer=20 + end, + update=function(this) + if has_key then + this.timer-=1 + this.x=this.start-1+rnd(3) + if this.timer<=0 then + sfx_timer=20 + sfx(16) + init_object(fruit,this.x,this.y-4) + destroy_object(this) + end + end + end +} +add(types,chest) + +platform={ + init=function(this) + this.x-=4 + this.solids=false + this.hitbox.w=16 + this.last=this.x + end, + update=function(this) + this.spd.x=this.dir*0.65 + if this.x<-16 then this.x=128 + elseif this.x>128 then this.x=-16 end + if not this.check(player,0,0) then + local hit=this.collide(player,0,-1) + if hit~=nil then + hit.move_x(this.x-this.last,1) + end + end + this.last=this.x + end, + draw=function(this) + spr(11,this.x,this.y-1) + spr(12,this.x+8,this.y-1) + end +} + +message={ + tile=86, + last=0, + draw=function(this) + this.text="-- celeste mountain --#this memorial to those# perished on the climb" + if this.check(player,4,0) then + if this.index<#this.text then + this.index+=0.5 + if this.index>=this.last+1 then + this.last+=1 + sfx(35) + end + end + this.off={x=8,y=96} + for i=1,this.index do + if sub(this.text,i,i)~="#" then + rectfill(this.off.x-2,this.off.y-2,this.off.x+7,this.off.y+6 ,7) + print(sub(this.text,i,i),this.off.x,this.off.y,0) + this.off.x+=5 + else + this.off.x=8 + this.off.y+=7 + end + end + else + this.index=0 + this.last=0 + end + end +} +add(types,message) + +big_chest={ + tile=96, + init=function(this) + this.state=0 + this.hitbox.w=16 + end, + draw=function(this) + if this.state==0 then + local hit=this.collide(player,0,8) + if hit~=nil and hit.is_solid(0,1) then + music(-1,500,7) + sfx(37) + pause_player=true + hit.spd.x=0 + hit.spd.y=0 + this.state=1 + init_object(smoke,this.x,this.y) + init_object(smoke,this.x+8,this.y) + this.timer=60 + this.particles={} + end + spr(96,this.x,this.y) + spr(97,this.x+8,this.y) + elseif this.state==1 then + this.timer-=1 + shake=5 + flash_bg=true + if this.timer<=45 and count(this.particles)<50 then + add(this.particles,{ + x=1+rnd(14), + y=0, + h=32+rnd(32), + spd=8+rnd(8) + }) + end + if this.timer<0 then + this.state=2 + this.particles={} + flash_bg=false + new_bg=true + init_object(orb,this.x+4,this.y+4) + pause_player=false + end + foreach(this.particles,function(p) + p.y+=p.spd + line(this.x+p.x,this.y+8-p.y,this.x+p.x,min(this.y+8-p.y+p.h,this.y+8),7) + end) + end + spr(112,this.x,this.y+8) + spr(113,this.x+8,this.y+8) + end +} +add(types,big_chest) + +orb={ + init=function(this) + this.spd.y=-4 + this.solids=false + this.particles={} + end, + draw=function(this) + this.spd.y=appr(this.spd.y,0,0.5) + local hit=this.collide(player,0,0) + if this.spd.y==0 and hit~=nil then + music_timer=45 + sfx(51) + freeze=10 + shake=10 + destroy_object(this) + max_djump=2 + hit.djump=2 + end + + spr(102,this.x,this.y) + local off=frames/30 + for i=0,7 do + circfill(this.x+4+cos(off+i/8)*8,this.y+4+sin(off+i/8)*8,1,7) + end + end +} + +flag = { + tile=118, + init=function(this) + this.x+=5 + this.score=0 + this.show=false + for i=1,count(got_fruit) do + if got_fruit[i] then + this.score+=1 + end + end + end, + draw=function(this) + this.spr=118+(frames/5)%3 + spr(this.spr,this.x,this.y) + if this.show then + rectfill(32,2,96,31,0) + spr(26,55,6) + print("x"..this.score,64,9,7) + draw_time(49,16) + print("deaths:"..deaths,48,24,7) + elseif this.check(player,0,0) then + sfx(55) + sfx_timer=30 + this.show=true + end + end +} +add(types,flag) + +room_title = { + init=function(this) + this.delay=5 + end, + draw=function(this) + this.delay-=1 + if this.delay<-30 then + destroy_object(this) + elseif this.delay<0 then + + rectfill(24,58,104,70,0) + --rect(26,64-10,102,64+10,7) + --print("---",31,64-2,13) + if room.x==3 and room.y==1 then + print("old site",48,62,7) + elseif level_index()==30 then + print("summit",52,62,7) + else + local level=(1+level_index())*100 + print(level.." m",52+(level<1000 and 2 or 0),62,7) + end + --print("---",86,64-2,13) + + draw_time(4,4) + end + end +} + +-- object functions -- +----------------------- + +function init_object(type,x,y) + if type.if_not_fruit~=nil and got_fruit[1+level_index()] then + return + end + local obj = {} + obj.type = type + obj.collideable=true + obj.solids=true + + obj.spr = type.tile + obj.flip = {x=false,y=false} + + obj.x = x + obj.y = y + obj.hitbox = { x=0,y=0,w=8,h=8 } + + obj.spd = {x=0,y=0} + obj.rem = {x=0,y=0} + + obj.is_solid=function(ox,oy) + if oy>0 and not obj.check(platform,ox,0) and obj.check(platform,ox,oy) then + return true + end + return solid_at(obj.x+obj.hitbox.x+ox,obj.y+obj.hitbox.y+oy,obj.hitbox.w,obj.hitbox.h) + or obj.check(fall_floor,ox,oy) + or obj.check(fake_wall,ox,oy) + end + + obj.is_ice=function(ox,oy) + return ice_at(obj.x+obj.hitbox.x+ox,obj.y+obj.hitbox.y+oy,obj.hitbox.w,obj.hitbox.h) + end + + obj.collide=function(type,ox,oy) + local other + for i=1,count(objects) do + other=objects[i] + if other ~=nil and other.type == type and other != obj and other.collideable and + other.x+other.hitbox.x+other.hitbox.w > obj.x+obj.hitbox.x+ox and + other.y+other.hitbox.y+other.hitbox.h > obj.y+obj.hitbox.y+oy and + other.x+other.hitbox.x < obj.x+obj.hitbox.x+obj.hitbox.w+ox and + other.y+other.hitbox.y < obj.y+obj.hitbox.y+obj.hitbox.h+oy then + return other + end + end + return nil + end + + obj.check=function(type,ox,oy) + return obj.collide(type,ox,oy) ~=nil + end + + obj.move=function(ox,oy) + local amount + -- [x] get move amount + obj.rem.x += ox + amount = flr(obj.rem.x + 0.5) + obj.rem.x -= amount + obj.move_x(amount,0) + + -- [y] get move amount + obj.rem.y += oy + amount = flr(obj.rem.y + 0.5) + obj.rem.y -= amount + obj.move_y(amount) + end + + obj.move_x=function(amount,start) + if obj.solids then + local step = sign(amount) + for i=start,abs(amount) do + if not obj.is_solid(step,0) then + obj.x += step + else + obj.spd.x = 0 + obj.rem.x = 0 + break + end + end + else + obj.x += amount + end + end + + obj.move_y=function(amount) + if obj.solids then + local step = sign(amount) + for i=0,abs(amount) do + if not obj.is_solid(0,step) then + obj.y += step + else + obj.spd.y = 0 + obj.rem.y = 0 + break + end + end + else + obj.y += amount + end + end + + add(objects,obj) + if obj.type.init~=nil then + obj.type.init(obj) + end + return obj +end + +function destroy_object(obj) + del(objects,obj) +end + +function kill_player(obj) + sfx_timer=12 + sfx(0) + deaths+=1 + shake=10 + destroy_object(obj) + dead_particles={} + for dir=0,7 do + local angle=(dir/8) + add(dead_particles,{ + x=obj.x+4, + y=obj.y+4, + t=10, + spd={ + x=sin(angle)*3, + y=cos(angle)*3 + } + }) + restart_room() + end +end + +-- room functions -- +-------------------- + +function restart_room() + will_restart=true + delay_restart=15 +end + +function next_room() + if room.x==2 and room.y==1 then + music(30,500,7) + elseif room.x==3 and room.y==1 then + music(20,500,7) + elseif room.x==4 and room.y==2 then + music(30,500,7) + elseif room.x==5 and room.y==3 then + music(30,500,7) + end + + if room.x==7 then + load_room(0,room.y+1) + else + load_room(room.x+1,room.y) + end +end + +function load_room(x,y) + has_dashed=false + has_key=false + + --remove existing objects + foreach(objects,destroy_object) + + --current room + room.x = x + room.y = y + + -- entities + for tx=0,15 do + for ty=0,15 do + local tile = mget(room.x*16+tx,room.y*16+ty); + if tile==11 then + init_object(platform,tx*8,ty*8).dir=-1 + elseif tile==12 then + init_object(platform,tx*8,ty*8).dir=1 + else + foreach(types, + function(type) + if type.tile == tile then + init_object(type,tx*8,ty*8) + end + end) + end + end + end + + if not is_title() then + init_object(room_title,0,0) + end +end + +-- update function -- +----------------------- + +function _update() + frames=((frames+1)%30) + if frames==0 and level_index()<30 then + seconds=((seconds+1)%60) + if seconds==0 then + minutes+=1 + end + end + + if music_timer>0 then + music_timer-=1 + if music_timer<=0 then + music(10,0,7) + end + end + + if sfx_timer>0 then + sfx_timer-=1 + end + + -- cancel if freeze + if freeze>0 then freeze-=1 return end + + -- screenshake + if shake>0 then + shake-=1 + camera() + if shake>0 then + camera(-2+rnd(5),-2+rnd(5)) + end + end + + -- restart (soon) + if will_restart and delay_restart>0 then + delay_restart-=1 + if delay_restart<=0 then + will_restart=false + load_room(room.x,room.y) + end + end + + -- update each object + foreach(objects,function(obj) + obj.move(obj.spd.x,obj.spd.y) + if obj.type.update~=nil then + obj.type.update(obj) + end + end) + + -- start game + if is_title() then + if not start_game and (btn(k_jump) or btn(k_dash)) then + music(-1) + start_game_flash=50 + start_game=true + sfx(38) + end + if start_game then + start_game_flash-=1 + if start_game_flash<=-30 then + begin_game() + end + end + end +end + +-- drawing functions -- +----------------------- +function _draw() + if freeze>0 then return end + + -- reset all palette values + pal() + + -- start game flash + if start_game then + local c=10 + if start_game_flash>10 then + if frames%10<5 then + c=7 + end + elseif start_game_flash>5 then + c=2 + elseif start_game_flash>0 then + c=1 + else + c=0 + end + if c<10 then + pal(6,c) + pal(12,c) + pal(13,c) + pal(5,c) + pal(1,c) + pal(7,c) + end + end + + -- clear screen + local bg_col = 0 + if flash_bg then + bg_col = frames/5 + elseif new_bg~=nil then + bg_col=2 + end + rectfill(0,0,128,128,bg_col) + + -- clouds + if not is_title() then + foreach(clouds, function(c) + c.x += c.spd + rectfill(c.x,c.y,c.x+c.w,c.y+4+(1-c.w/64)*12,new_bg~=nil and 14 or 1) + if c.x > 128 then + c.x = -c.w + c.y=rnd(128-8) + end + end) + end + + -- draw bg terrain + map(room.x * 16,room.y * 16,0,0,16,16,4) + + -- platforms/big chest + foreach(objects, function(o) + if o.type==platform or o.type==big_chest then + draw_object(o) + end + end) + + -- draw terrain + local off=is_title() and -4 or 0 + map(room.x*16,room.y * 16,off,0,16,16,2) + + -- draw objects + foreach(objects, function(o) + if o.type~=platform and o.type~=big_chest then + draw_object(o) + end + end) + + -- draw fg terrain + map(room.x * 16,room.y * 16,0,0,16,16,8) + + -- particles + foreach(particles, function(p) + p.x += p.spd + p.y += sin(p.off) + p.off+= min(0.05,p.spd/32) + rectfill(p.x,p.y,p.x+p.s,p.y+p.s,p.c) + if p.x>128+4 then + p.x=-4 + p.y=rnd(128) + end + end) + + -- dead particles + foreach(dead_particles, function(p) + p.x += p.spd.x + p.y += p.spd.y + p.t -=1 + if p.t <= 0 then del(dead_particles,p) end + rectfill(p.x-p.t/5,p.y-p.t/5,p.x+p.t/5,p.y+p.t/5,14+p.t%2) + end) + + -- draw outside of the screen for screenshake + rectfill(-5,-5,-1,133,0) + rectfill(-5,-5,133,-1,0) + rectfill(-5,128,133,133,0) + rectfill(128,-5,133,133,0) + + -- credits + if is_title() then + print("x+c",58,80,5) + print("matt thorson",42,96,5) + print("noel berry",46,102,5) + end + + if level_index()==30 then + local p + for i=1,count(objects) do + if objects[i].type==player then + p = objects[i] + break + end + end + if p~=nil then + local diff=min(24,40-abs(p.x+4-64)) + rectfill(0,0,diff,128,0) + rectfill(128-diff,0,128,128,0) + end + end + +end + +function draw_object(obj) + + if obj.type.draw ~=nil then + obj.type.draw(obj) + elseif obj.spr > 0 then + spr(obj.spr,obj.x,obj.y,1,1,obj.flip.x,obj.flip.y) + end + +end + +function draw_time(x,y) + + local s=seconds + local m=minutes%60 + local h=flr(minutes/60) + + rectfill(x,y,x+32,y+6,0) + print((h<10 and "0"..h or h)..":"..(m<10 and "0"..m or m)..":"..(s<10 and "0"..s or s),x+1,y+1,7) + +end + +-- helper functions -- +---------------------- + +function clamp(val,a,b) + return max(a, min(b, val)) +end + +function appr(val,target,amount) + return val > target + and max(val - amount, target) + or min(val + amount, target) +end + +function sign(v) + return v>0 and 1 or + v<0 and -1 or 0 +end + +function maybe() + return rnd(1)<0.5 +end + +function solid_at(x,y,w,h) + return tile_flag_at(x,y,w,h,0) +end + +function ice_at(x,y,w,h) + return tile_flag_at(x,y,w,h,4) +end + +function tile_flag_at(x,y,w,h,flag) + for i=max(0,flr(x/8)),min(15,(x+w-1)/8) do + for j=max(0,flr(y/8)),min(15,(y+h-1)/8) do + if fget(tile_at(i,j),flag) then + return true + end + end + end + return false +end + +function tile_at(x,y) + return mget(room.x * 16 + x, room.y * 16 + y) +end + +function spikes_at(x,y,w,h,xspd,yspd) + for i=max(0,flr(x/8)),min(15,(x+w-1)/8) do + for j=max(0,flr(y/8)),min(15,(y+h-1)/8) do + local tile=tile_at(i,j) + if tile==17 and ((y+h-1)%8>=6 or y+h==j*8+8) and yspd>=0 then + return true + elseif tile==27 and y%8<=2 and yspd<=0 then + return true + elseif tile==43 and x%8<=2 and xspd<=0 then + return true + elseif tile==59 and ((x+w-1)%8>=6 or x+w==i*8+8) and xspd>=0 then + return true + end + end + end + return false +end +__gfx__ +000000000000000000000000088888800000000000000000000000000000000000aaaaa0000aaa000000a0000007707770077700000060000000600000060000 +000000000888888008888880888888880888888008888800000000000888888000a000a0000a0a000000a0000777777677777770000060000000600000060000 +000000008888888888888888888ffff888888888888888800888888088f1ff1800a909a0000a0a000000a0007766666667767777000600000000600000060000 +00000000888ffff8888ffff888f1ff18888ffff88ffff8808888888888fffff8009aaa900009a9000000a0007677766676666677000600000000600000060000 +0000000088f1ff1888f1ff1808fffff088f1ff1881ff1f80888ffff888fffff80000a0000000a0000000a0000000000000000000000600000006000000006000 +0000000008fffff008fffff00033330008fffff00fffff8088fffff8083333800099a0000009a0000000a0000000000000000000000600000006000000006000 +00000000003333000033330007000070073333000033337008f1ff10003333000009a0000000a0000000a0000000000000000000000060000006000000006000 +000000000070070000700070000000000000070000007000077333700070070000aaa0000009a0000000a0000000000000000000000060000006000000006000 +555555550000000000000000000000000000000000000000008888004999999449999994499909940300b0b0666566650300b0b0000000000000000070000000 +55555555000000000000000000000000000000000000000008888880911111199111411991140919003b330067656765003b3300007700000770070007000007 +550000550000000000000000000000000aaaaaa00000000008788880911111199111911949400419028888206770677002888820007770700777000000000000 +55000055007000700499994000000000a998888a1111111108888880911111199494041900000044089888800700070078988887077777700770000000000000 +55000055007000700050050000000000a988888a1000000108888880911111199114094994000000088889800700070078888987077777700000700000000000 +55000055067706770005500000000000aaaaaaaa1111111108888880911111199111911991400499088988800000000008898880077777700000077000000000 +55555555567656760050050000000000a980088a1444444100888800911111199114111991404119028888200000000002888820070777000007077007000070 +55555555566656660005500004999940a988888a1444444100000000499999944999999444004994002882000000000000288200000000007000000000000000 +5777777557777777777777777777777577cccccccccccccccccccc77577777755555555555555555555555555500000007777770000000000000000000000000 +77777777777777777777777777777777777cccccccccccccccccc777777777775555555555555550055555556670000077777777000777770000000000000000 +777c77777777ccccc777777ccccc7777777cccccccccccccccccc777777777775555555555555500005555556777700077777777007766700000000000000000 +77cccc77777cccccccc77cccccccc7777777cccccccccccccccc7777777cc7775555555555555000000555556660000077773377076777000000000000000000 +77cccc7777cccccccccccccccccccc777777cccccccccccccccc777777cccc775555555555550000000055555500000077773377077660000777770000000000 +777cc77777cc77ccccccccccccc7cc77777cccccccccccccccccc77777cccc775555555555500000000005556670000073773337077770000777767007700000 +7777777777cc77cccccccccccccccc77777cccccccccccccccccc77777c7cc77555555555500000000000055677770007333bb37000000000000007700777770 +5777777577cccccccccccccccccccc7777cccccccccccccccccccc7777cccc77555555555000000000000005666000000333bb30000000000000000000077777 +77cccc7777cccccccccccccccccccc77577777777777777777777775777ccc775555555550000000000000050000066603333330000000000000000000000000 +777ccc7777cccccccccccccccccccc77777777777777777777777777777cc7775055555555000000000000550007777603b333300000000000ee0ee000000000 +777ccc7777cc7cccccccccccc77ccc777777ccc7777777777ccc7777777cc77755550055555000000000055500000766033333300000000000eeeee000000030 +77ccc77777ccccccccccccccc77ccc77777ccccc7c7777ccccccc77777ccc777555500555555000000005555000000550333b33000000000000e8e00000000b0 +77ccc777777cccccccc77cccccccc777777ccccccc7777c7ccccc77777cccc7755555555555550000005555500000666003333000000b00000eeeee000000b30 +777cc7777777ccccc777777ccccc77777777ccc7777777777ccc777777cccc775505555555555500005555550007777600044000000b000000ee3ee003000b00 +777cc777777777777777777777777777777777777777777777777777777cc7775555555555555550055555550000076600044000030b00300000b00000b0b300 +77cccc77577777777777777777777775577777777777777777777775577777755555555555555555555555550000005500999900030330300000b00000303300 +5777755777577775077777777777777777777770077777700000000000000000cccccccc00000000000000000000000000000000000000000000000000000000 +7777777777777777700007770000777000007777700077770000000000000000c77ccccc00000000000000000000000000000000000000000000000000000000 +7777cc7777cc777770cc777cccc777ccccc7770770c777070000000000000000c77cc7cc00000000000000000000000000000000000000000000000000000000 +777cccccccccc77770c777cccc777ccccc777c0770777c070000000000000000cccccccc00000000000000000000000000006000000000000000000000000000 +77cccccccccccc77707770000777000007770007777700070002eeeeeeee2000cccccccc00000000000000000000000000060600000000000000000000000000 +57cc77ccccc7cc7577770000777000007770000777700007002eeeeeeeeee200cc7ccccc00000000000000000000000000d00060000000000000000000000000 +577c77ccccccc7757000000000000000000c000770000c0700eeeeeeeeeeee00ccccc7cc0000000000000000000000000d00000c000000000000000000000000 +777cccccccccc7777000000000000000000000077000000700e22222e2e22e00cccccccc000000000000000000000000d000000c000000000000000000000000 +777cccccccccc7777000000000000000000000077000000700eeeeeeeeeeee000000000000000000000000000000000c0000000c000600000000000000000000 +577cccccccccc7777000000c000000000000000770cc000700e22e2222e22e00000000000000000000000000000000d000000000c060d0000000000000000000 +57cc7cccc77ccc7570000000000cc0000000000770cc000700eeeeeeeeeeee0000000000000000000000000000000c00000000000d000d000000000000000000 +77ccccccc77ccc7770c00000000cc00000000c0770000c0700eee222e22eee0000000000000000000000000000000c0000000000000000000000000000000000 +777cccccccccc7777000000000000000000000077000000700eeeeeeeeeeee005555555506666600666666006600c00066666600066666006666660066666600 +7777cc7777cc777770000000000000000000000770c0000700eeeeeeeeeeee00555555556666666066666660660c000066666660666666606666666066666660 +777777777777777770000000c0000000000000077000000700ee77eee7777e005555555566000660660000006600000066000000660000000066000066000000 +57777577775577757000000000000000000000077000c007077777777777777055555555dd000000dddd0000dd000000dddd0000ddddddd000dd0000dddd0000 +000000000000000070000000000000000000000770000007007777005000000000000005dd000dd0dd000000dd0000d0dd000000000000d000dd0000dd000000 +00aaaaaaaaaaaa00700000000000000000000007700c0007070000705500000000000055ddddddd0dddddd00ddddddd0dddddd00ddddddd000dd0000dddddd00 +0a999999999999a0700000000000c00000000007700000077077000755500000000005550ddddd00ddddddd0ddddddd0ddddddd00ddddd0000dd0000ddddddd0 +a99aaaaaaaaaa99a7000000cc0000000000000077000cc077077bb07555500000000555500000000000000000000000000000000000000000000000000000000 +a9aaaaaaaaaaaa9a7000000cc0000000000c00077000cc07700bbb0755555555555555550000000000000c000000000000000000000000000000c00000000000 +a99999999999999a70c00000000000000000000770c00007700bbb075555555555555555000000000000c00000000000000000000000000000000c0000000000 +a99999999999999a700000000000000000000007700000070700007055555555555555550000000000cc0000000000000000000000000000000000c000000000 +a99999999999999a07777777777777777777777007777770007777005555555555555555000000000c000000000000000000000000000000000000c000000000 +aaaaaaaaaaaaaaaa07777777777777777777777007777770004bbb00004b000000400bbb00000000c0000000000000000000000000000000000000c000000000 +a49494a11a49494a70007770000077700000777770007777004bbbbb004bb000004bbbbb0000000100000000000000000000000000000000000000c00c000000 +a494a4a11a4a494a70c777ccccc777ccccc7770770c7770704200bbb042bbbbb042bbb00000000c0000000000000000000000000000000000000001010c00000 +a49444aaaa44494a70777ccccc777ccccc777c0770777c07040000000400bbb004000000000001000000000000000000000000000000000000000001000c0000 +a49999aaaa99994a7777000007770000077700077777000704000000040000000400000000000100000000000000000000000000000000000000000000010000 +a49444999944494a77700000777000007770000777700c0742000000420000004200000000000100000000000000000000000000000000000000000000001000 +a494a444444a494a7000000000000000000000077000000740000000400000004000000000000000000000000000000000000000000000000000000000000000 +a49499999999494a0777777777777777777777700777777040000000400000004000000000010000000000000000000000000000000000000000000000000010 +00000000000000008242525252528452339200001323232352232323232352230000000000000000b302000013232352526200a2828342525223232323232323 +00000000000000a20182920013232352363636462535353545550000005525355284525262b20000000000004252525262828282425284525252845252525252 +00000000000085868242845252525252b1006100b1b1b1b103b1b1b1b1b103b100000000000000111102000000a282425233000000a213233300009200008392 +000000000000110000a2000000a28213000000002636363646550000005525355252528462b2a300000000004252845262828382132323232323232352528452 +000000000000a201821323525284525200000000000000007300000000007300000000000000b343536300410000011362b2000000000000000000000000a200 +0000000000b302b2002100000000a282000000000000000000560000005526365252522333b28292001111024252525262019200829200000000a28213525252 +0000000000000000a2828242525252840000000000000000b10000000000b1000000000000000000b3435363930000b162273737373737373737374711000061 +000000110000b100b302b20000006182000000000000000000000000005600005252338282828201a31222225252525262820000a20011111100008283425252 +0000000000000093a382824252525252000061000011000000000011000000001100000000000000000000020182001152222222222222222222222232b20000 +0000b302b200000000b10000000000a200000000000000009300000000000000846282828283828282132323528452526292000000112434440000a282425284 +00000000000000a2828382428452525200000000b302b2936100b302b20061007293a30000000000000000b1a282931252845252525252232323232362b20000 +000000b10000001100000000000000000000000093000086820000a3000000005262828201a200a282829200132323236211111111243535450000b312525252 +00000000000000008282821323232323820000a300b1a382930000b100000000738283931100000000000011a382821323232323528462829200a20173b20061 +000000000000b302b2000061000000000000a385828286828282828293000000526283829200000000a20000000000005222222232263636460000b342525252 +00000011111111a3828201b1b1b1b1b182938282930082820000000000000000b100a282721100000000b372828283b122222232132333610000869200000000 +00100000000000b1000000000000000086938282828201920000a20182a37686526282829300000000000000000000005252845252328283920000b342845252 +00008612222232828382829300000000828282828283829200000000000061001100a382737200000000b373a2829211525284628382a2000000a20000000000 +00021111111111111111111111110061828282a28382820000000000828282825262829200000000000000000000000052525252526201a2000000b342525252 +00000113235252225353536300000000828300a282828201939300001100000072828292b1039300000000b100a282125223526292000000000000a300000000 +0043535353535353535353535363b2008282920082829200061600a3828382a28462000000000000000000000000000052845252526292000011111142525252 +0000a28282132362b1b1b1b1000000009200000000a28282828293b372b2000073820100110382a3000000110082821362101333610000000000008293000000 +0002828382828202828282828272b20083820000a282d3000717f38282920000526200000000000093000000000000005252525284620000b312223213528452 +000000828392b30300000000002100000000000000000082828282b303b20000b1a282837203820193000072a38292b162710000000000009300008382000000 +00b1a282820182b1a28283a28273b200828293000082122232122232820000a3233300000000000082920000000000002323232323330000b342525232135252 +000000a28200b37300000000a37200000010000000111111118283b373b200a30000828273039200828300738283001162930000000000008200008282920000 +0000009261a28200008261008282000001920000000213233342846282243434000000000000000082000085860000008382829200000000b342528452321323 +0000100082000082000000a2820300002222321111125353630182829200008300009200b1030000a28200008282001262829200000000a38292008282000000 +00858600008282a3828293008292610082001000001222222252525232253535000000f3100000a3820000a2010000008292000000009300b342525252522222 +0400122232b200839321008683039300528452222262c000a28282820000a38210000000a3738000008293008292001362820000000000828300a38201000000 +00a282828292a2828283828282000000343434344442528452525252622535350000001263000083829300008200c1008210d3e300a38200b342525252845252 +1232425262b28682827282820103820052525252846200000082829200008282320000008382930000a28201820000b162839300000000828200828282930000 +0000008382000000a28201820000000035353535454252525252528462253535000000032444008282820000829300002222223201828393b342525252525252 +525252525262b2b1b1b1132323526200845223232323232352522323233382825252525252525252525284522333b2822323232323526282820000b342525252 +52845252525252848452525262838242528452522333828292425223232352520000000000000000000000000000000000000000000000000000000000000000 +525252845262b2000000b1b1b142620023338276000000824233b2a282018283525252845252232323235262b1b10083921000a382426283920000b342232323 +2323232323232323232323526201821352522333b1b1018241133383828242840000000000000000000000000000000000000000000000000000000000000000 +525252525262b20000000000a242627682828392000011a273b200a382729200525252525233b1b1b1b11333000000825353536382426282410000b30382a2a2 +a1829200a2828382820182426200a2835262b1b10000831232b2000080014252000000000000a300000000000000000000000000000000000000000000000000 +528452232333b20000001100824262928201a20000b3720092000000830300002323525262b200000000b3720000a382828283828242522232b200b373928000 +000100110092a2829211a2133300a3825262b2000000a21333b20000868242520000000000000100009300000000000000000000000000000000000000000000 +525262122232b200a37672b2a24262838292000000b30300000000a3820300002232132333b200000000b303829300a2838292019242845262b2000000000000 +00a2b302b2a36182b302b200110000825262b200000000b1b10000a283a2425200000000a30082000083000000000000000000000094a4b4c4d4e4f400000000 +525262428462b200a28303b2214262928300000000b3030000000000a203e3415252222232b200000000b30392000000829200000042525262b2000000000000 +000000b100a2828200b100b302b211a25262b200000000000000000092b3428400000000827682000001009300000000000000000095a5b5c5d5e5f500000000 +232333132362b221008203b2711333008293858693b3031111111111114222225252845262b200001100b303b2000000821111111142528462b2000000000000 +000000000000110176851100b1b3026184621111111100000061000000b3135200000000828382670082768200000000000000000096a6b6c6d6e6f600000000 +82000000a203117200a203b200010193828283824353235353535353535252845252525262b200b37200b303b2000000824353535323235262b2000011000000 +0000000000b30282828372b26100b100525232122232b200000000000000b14200000000a28282123282839200000000000000000097a7b7c7d7e7f700000000 +9200110000135362b2001353535353539200a2000001828282829200b34252522323232362b261b30300b3030000000092b1b1b1b1b1b34262b200b372b20000 +001100000000b1a2828273b200000000232333132333b200001111000000b342000000868382125252328293a300000000000000000000000000000000000000 +00b372b200a28303b2000000a28293b3000000000000a2828382827612525252b1b1b1b173b200b30393b30361000000000000000000b34262b271b303b20000 +b302b211000000110092b100000000a3b1b1b1b1b1b10011111232110000b342000000a282125284525232828386000000000000000000000000000000000000 +80b303b20000820311111111008283b311111111110000829200928242528452000000a3820000b30382b37300000000000000000000b3426211111103b20000 +00b1b302b200b372b200000000000082b21000000000b31222522363b200b3138585868292425252525262018282860000000000000000000000000000000000 +00b373b20000a21353535363008292b32222222232111102b20000a21323525200000001839200b3038282820000000011111111930011425222222233b20000 +100000b10000b303b200000000858682b27100000000b3425233b1b1000000b182018283001323525284629200a2820000000000000000000000000000000000 +9300b100000000b1b1b1b1b100a200b323232323235363b100000000b1b1135200000000820000b30382839200000000222222328283432323232333b2000000 +329300000000b373b200000000a20182111111110000b31333b100a30061000000a28293f3123242522333020000820000000000000000000000000000000000 +829200001000410000000000000000b39310d30000a28200000000000000824200000086827600b30300a282760000005252526200828200a30182a2006100a3 +62820000000000b100000093a382838222222232b20000b1b1000083000000860000122222526213331222328293827600000000000000000000000000000000 +017685a31222321111111111002100b322223293000182930000000080a301131000a383829200b373000083920000005284526200a282828283920000000082 +62839321000000000000a3828282820152845262b261000093000082a300a3821000135252845222225252523201838200000000000000000000000000000000 +828382824252522222222232007100b352526282a38283820000000000838282320001828200000083000082010000005252526271718283820000000000a382 +628201729300000000a282828382828252528462b20000a38300a382018283821222324252525252525284525222223200000000000000000000000000000000 +__label__ +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000700000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000770000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000770000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000007000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000006000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000006000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000070000000000000000006000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000060600000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000d00060000000000000066000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000000d00000c000000000000066000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000000d000000c000000000000000000000000000000000000000000000000060000000000 +00000000000000000000000000000000000000000000000000000000000c0000000c000600000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000000000000d000000000c060d0000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000c00000000000d000d000000000000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000000000000c0000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000006666600666666006600c00066666600066666006666660066666600000000000000000000000000000000000000 +0000000000000000000000000000000000006666666066666660660c000066666660666666606666666066666660000000000000000000000000000000000000 +00000000000000000000000000000000000066000660660000006600000066000000660000000066000066000000000000000000000000000000000000000000 +000000000000000000000000000000000000dd000000dddd0000dd000000dddd0000ddddddd000dd0000dddd0000000000000000000000000000000000000000 +000000000000000000000000000000000000dd000dd0dd000000dd0000d0dd000000000000d000dd0000dd000000000000000000000000000000000000000000 +000000000000000000000000000000000000ddddddd0dddddd00ddddddd0dddddd00ddddddd000dd0000dddddd00000000000000000000000000000000000000 +0000000000000000000000000000000000000ddddd00ddddddd0ddddddd0ddddddd00ddddd0000dd0000ddddddd0000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000000c000000000000000000000000000000c00000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000000c00000000000000000000000000000000c0000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000000cc0000000000000000000000000000000000c000000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000000c000000000000000000000000000000000000c000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000c0000000000000000000000000000000000000c000000000000000000000000000000000000000000000 +0000000000000000000000000000000000000000000100000000000000000000000000000000000000c00c000000000000000000000000000000000000000000 +000000000000000000000000000000000000000000c0000000000000000000000000000000000000001010c00000000000000000000000000000000000000000 +000000000000000000000000000000000000000001000000000000000000000000000000000000000001000c0000000000000000000000000000000000000000 +00000000000000000000000000000000000000000100000000000000000000000000000000000000000000010000000600000000000000000000000000000000 +00000000000000000000000000000000000000000100000000000000000000000000000000000000000000001000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000010000000000000000000000000000000000000000000000000010000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000070000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000060000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000005050000005500000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000005050050050006000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000500555050000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000005050050050000000000000600000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000005050000005500000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000070000000000660000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000660000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000007000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000055505550555055500000555050500550555005500550550000000000000000000000000000000000000000 +00000000000000000000000000000000000000000055505050050005000000050050505050505050005050505000000000000000000000000000000000000000 +00000000000000000000000000000000000000000050505550050005000000050055505050550055505050505000000000000000000000000000000000000000 +00000000000000000000000000000000000000000050505050050005000000050050505050505000505050505000000000000000000000000000000000000000 +00000000000000000000000000000000000000000050505050050005000000050050505500505055005500505000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000605500055055505000000055505550555055505050000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000005050505050005000000050505000505050505050000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000005050505055005000000055005500550055005550000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000005050505050005000000050505000505050500050000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000005050550055505550000055505550505050505550000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000600000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000600000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 + +__gff__ +0000000000000000000000000000000004020000000000000000000200000000030303030303030304040402020000000303030303030303040404020202020200001313131302020302020202020002000013131313020204020202020202020000131313130004040202020202020200001313131300000002020202020202 +0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +__map__ +2331252548252532323232323300002425262425252631323232252628282824252525252525323328382828312525253232323233000000313232323232323232330000002432323233313232322525252525482525252525252526282824252548252525262828282824254825252526282828283132323225482525252525 +252331323232332900002829000000242526313232332828002824262a102824254825252526002a2828292810244825282828290000000028282900000000002810000000372829000000002a2831482525252525482525323232332828242525254825323338282a283132252548252628382828282a2a2831323232322525 +252523201028380000002a0000003d24252523201028292900282426003a382425252548253300002900002a0031252528382900003a676838280000000000003828393e003a2800000000000028002425253232323232332122222328282425252532332828282900002a283132252526282828282900002a28282838282448 +3232332828282900000000003f2020244825262828290000002a243300002a2425322525260000000000000000003125290000000021222328280000000000002a2828343536290000000000002839242526212223202123313232332828242548262b000000000000001c00003b242526282828000000000028282828282425 +2340283828293a2839000000343522252548262900000000000030000000002433003125333d3f00000000000000003100001c3a3a31252620283900000000000010282828290000000011113a2828313233242526103133202828282838242525262b000000000000000000003b2425262a2828670016002a28283828282425 +263a282828102829000000000000312525323300000000110000370000003e2400000037212223000000000000000000395868282828242628290000000000002a2828290000000000002123283828292828313233282829002a002a2828242525332b0c00000011110000000c3b314826112810000000006828282828282425 +252235353628280000000000003a282426003d003a3900270000000000002125001a000024252611111111000000002c28382828283831332800000017170000002a000000001111000024261028290028281b1b1b282800000000002a2125482628390000003b34362b000000002824252328283a67003a28282829002a3132 +25333828282900000000000000283824252320201029003039000000005824480000003a31323235353536675800003c282828281028212329000000000000000000000000003436003a2426282800003828390000002a29000000000031323226101000000000282839000000002a2425332828283800282828390000001700 +2600002a28000000003a283a2828282425252223283900372858390068283132000000282828282820202828283921222829002a28282426000000000000000000000000000020382828312523000000282828290000000000163a67682828003338280b00000010382800000b00003133282828282868282828280000001700 +330000002867580000281028283422252525482628286720282828382828212200003a283828102900002a28382824252a0000002838242600000017170000000000000000002728282a283133390000282900000000000000002a28282829002a2839000000002a282900000000000028282838282828282828290000000000 +0000003a2828383e3a2828283828242548252526002a282729002a28283432250000002a282828000000002810282425000000002a282426000000000000000000000000000037280000002a28283900280000003928390000000000282800000028290000002a2828000000000000002a282828281028282828675800000000 +0000002838282821232800002a28242532322526003a2830000000002a28282400000000002a281111111128282824480000003a28283133000000000000171700013f0000002029000000003828000028013a28281028580000003a28290000002a280c0000003a380c00000000000c00002a2828282828292828290000003a +00013a2123282a313329001111112425002831263a3829300000000000002a310000000000002834222236292a0024253e013a3828292a00000000000000000035353536000020000000003d2a28671422222328282828283900582838283d00003a290000000028280000000000000000002a28282a29000058100012002a28 +22222225262900212311112122222525002a3837282900301111110000003a2800013f0000002a282426290000002425222222232900000000000000171700002a282039003a2000003a003435353535252525222222232828282810282821220b10000000000b28100000000b0000002c00002838000000002a283917000028 +2548252526111124252222252525482500012a2828673f242222230000003828222223000012002a24260000001224252525252600000000171700000000000000382028392827080028676820282828254825252525262a28282122222225253a28013d0000006828390000000000003c0168282800171717003a2800003a28 +25252525252222252525252525252525222222222222222525482667586828282548260000270000242600000021252525254826171700000000000000000000002a2028102830003a282828202828282525252548252600002a2425252548252821222300000028282800000000000022222223286700000000282839002838 +2532330000002432323232323232252525252628282828242532323232254825253232323232323225262828282448252525253300000000000000000000005225253232323233313232323233282900262829286700000000002828313232322525253233282800312525482525254825254826283828313232323232322548 +26282800000030402a282828282824252548262838282831333828290031322526280000163a28283133282838242525482526000000000000000000000000522526000016000000002a10282838390026281a3820393d000000002a3828282825252628282829003b2425323232323232323233282828282828102828203125 +3328390000003700002a3828002a2425252526282828282028292a0000002a313328111111282828000028002a312525252526000000000000000000000000522526000000001111000000292a28290026283a2820102011111121222328281025252628382800003b24262b002a2a38282828282829002a2800282838282831 +28281029000000000000282839002448252526282900282067000000000000003810212223283829003a1029002a242532323367000000000000000000004200252639000000212300000000002122222522222321222321222324482628282832323328282800003b31332b00000028102829000000000029002a2828282900 +2828280016000000162a2828280024252525262700002a2029000000000000002834252533292a0000002a00111124252223282800002c46472c00000042535325262800003a242600001600002425252525482631323331323324252620283822222328292867000028290000000000283800111100001200000028292a1600 +283828000000000000003a28290024254825263700000029000000000000003a293b2426283900000000003b212225252526382867003c56573c4243435363633233283900282426111111111124252525482526201b1b1b1b1b24252628282825252600002a28143a2900000000000028293b21230000170000112867000000 +2828286758000000586828380000313232323320000000000000000000272828003b2426290000000000003b312548252533282828392122222352535364000029002a28382831323535353522254825252525252300000000003132332810284825261111113435361111111100000000003b3133111111111127282900003b +2828282810290000002a28286700002835353536111100000000000011302838003b3133000000000000002a28313225262a282810282425252662636400000000160028282829000000000031322525252525252667580000002000002a28282525323535352222222222353639000000003b34353535353536303800000017 +282900002a0000000000382a29003a282828283436200000000000002030282800002a29000011110000000028282831260029002a282448252523000000000039003a282900000000000000002831322525482526382900000017000058682832331028293b2448252526282828000000003b201b1b1b1b1b1b302800000017 +283a0000000000000000280000002828283810292a000000000000002a3710281111111111112136000000002a28380b2600000000212525252526001c0000002828281000000000001100002a382829252525252628000000001700002a212228282908003b242525482628282912000000001b00000000000030290000003b +3829000000000000003a102900002838282828000000000000000000002a2828223535353535330000000000002828393300000000313225252533000000000028382829000000003b202b00682828003232323233290000000000000000312528280000003b3132322526382800170000000000000000110000370000000000 +290000000000000000002a000000282928292a0000000000000000000000282a332838282829000000000000001028280000000042434424252628390000000028002a0000110000001b002a2010292c1b1b1b1b0000000000000000000010312829160000001b1b1b313328106700000000001100003a2700001b0000000000 +00000100000011111100000000002a3a2a0000000000000000000000002a2800282829002a000000000000000028282800000000525354244826282800000000290000003b202b39000000002900003c000000000000000000000000000028282800000000000000001b1b2a2829000001000027390038300000000000000000 +1111201111112122230000001212002a00010000000000000000000000002900290000000000000000002a6768282900003f01005253542425262810673a3900013f0000002a3829001100000000002101000000000000003a67000000002a382867586800000100000000682800000021230037282928300000000000000000 +22222222222324482611111120201111002739000017170000001717000000000001000000001717000000282838393a0021222352535424253328282838290022232b00000828393b27000000001424230000001200000028290000000000282828102867001717171717282839000031333927101228370000000000000000 +254825252526242526212222222222223a303800000000000000000000000000001717000000000000003a28282828280024252652535424262828282828283925262b00003a28103b30000000212225260000002700003a28000000000000282838282828390000005868283828000022233830281728270000000000000000 +__sfx__ +0002000036370234702f3701d4702a37017470273701347023370114701e3700e4701a3600c46016350084401233005420196001960019600196003f6003f6003f6003f6003f6003f6003f6003f6003f6003f600 +0002000011070130701a0702407000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000300000d07010070160702207000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000200000642008420094200b420224402a4503c6503b6503b6503965036650326502d6502865024640216401d6401a64016630116300e6300b62007620056100361010600106000060000600006000060000600 +000400000f0701e070120702207017070260701b0602c060210503105027040360402b0303a030300203e02035010000000000000000000000000000000000000000000000000000000000000000000000000000 +000300000977009770097600975008740077300672005715357003470034700347003470034700347003570035700357003570035700347003470034700337003370033700337000070000700007000070000700 +00030000241700e1702d1701617034170201603b160281503f1402f120281101d1101011003110001000010000100001000010000100001000010000100001000010000100001000010000100001000010000100 +00020000101101211014110161101a120201202613032140321403410000100001000010000100001000010000100001000010000100001000010000100001000010000100001000010000100001000010000100 +00030000070700a0700e0701007016070220702f0702f0602c0602c0502f0502f0402c0402c0302f0202f0102c000000000000000000000000000000000000000000000000000000000000000000000000000000 +0003000005110071303f6403f6403f6303f6203f6103f6153f6003f6003f600006000060000600006000060000600006000060000600006000060000600006000060000600006000060000600006000060000600 +011000200177500605017750170523655017750160500605017750060501705076052365500605017750060501775017050177500605236550177501605006050177500605256050160523655256050177523655 +002000001d0401d0401d0301d020180401804018030180201b0301b02022040220461f0351f03016040160401d0401d0401d002130611803018030180021f061240502202016040130201d0401b0221804018040 +00100000070700706007050110000707007060030510f0700a0700a0600a0500a0000a0700a0600505005040030700306003000030500c0700c0601105016070160600f071050500a07005050030510a0700a060 +000400000c5501c5601057023570195702c5702157037570285703b5702c5703e560315503e540315303e530315203f520315203f520315103f510315103f510315103f510315103f50000500005000050000500 +000400002f7402b760267701d7701577015770197701c750177300170015700007000070000700007000070000700007000070000700007000070000700007000070000700007000070000700007000070000700 +00030000096450e655066550a6550d6550565511655076550c655046550965511645086350d615006050060500605006050060500605006050060500605006050060500605006050060500605006050060500605 +011000001f37518375273752730027300243001d300263002a3001c30019300003000030000300003000030000300003000030000300003000030000300003000030000300003000030000300003000030000300 +011000002953429554295741d540225702256018570185701856018500185701856000500165701657216562275142753427554275741f5701f5601f500135201b55135530305602454029570295602257022560 +011000200a0700a0500f0710f0500a0600a040110701105007000070001107011050070600704000000000000a0700a0500f0700f0500a0600a0401307113050000000000013070130500f0700f0500000000000 +002000002204022030220201b0112404024030270501f0202b0402202027050220202904029030290201601022040220302b0401b030240422403227040180301d0401d0301f0521f0421f0301d0211d0401d030 +0108002001770017753f6253b6003c6003b6003f6253160023650236553c600000003f62500000017750170001770017753f6003f6003f625000003f62500000236502365500000000003f625000000000000000 +002000200a1400a1300a1201113011120111101b1401b13018152181421813213140131401313013120131100f1400f1300f12011130111201111016142161321315013140131301312013110131101311013100 +001000202e750377502e730377302e720377202e71037710227502b750227302b7301d750247501d730247301f750277501f730277301f7202772029750307502973030730297203072029710307102971030710 +000600001877035770357703576035750357403573035720357103570000700007000070000700007000070000700007000070000700007000070000700007000070000700007000070000700007000070000700 +001800202945035710294403571029430377102942037710224503571022440274503c710274403c710274202e450357102e440357102e430377102e420377102e410244402b45035710294503c710294403c710 +0018002005570055700557005570055700000005570075700a5700a5700a570000000a570000000a5700357005570055700557000000055700557005570000000a570075700c5700c5700f570000000a57007570 +010c00103b6352e6003b625000003b61500000000003360033640336303362033610336103f6003f6150000000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000c002024450307102b4503071024440307002b44037700244203a7102b4203a71024410357102b410357101d45033710244503c7101d4403771024440337001d42035700244202e7101d4102e7102441037700 +011800200c5700c5600c550000001157011560115500c5000c5700c5600f5710f56013570135600a5700a5600c5700c5600c550000000f5700f5600f550000000a5700a5600a5500f50011570115600a5700a560 +001800200c5700c5600c55000000115701156011550000000c5700c5600f5710f56013570135600f5700f5600c5700c5700c5600c5600c5500c5300c5000c5000c5000a5000a5000a50011500115000a5000a500 +000c0020247712477024762247523a0103a010187523a0103501035010187523501018750370003700037000227712277222762227001f7711f7721f762247002277122772227620070027771277722776200700 +000c0020247712477024762247523a0103a010187503a01035010350101875035010187501870018700007001f7711f7701f7621f7521870000700187511b7002277122770227622275237012370123701237002 +000c0000247712477024772247722476224752247422473224722247120070000700007000070000700007002e0002e0002e0102e010350103501033011330102b0102b0102b0102b00030010300123001230012 +000c00200c3320c3320c3220c3220c3120c3120c3120c3020c3320c3320c3220c3220c3120c3120c3120c30207332073320732207322073120731207312073020a3320a3320a3220a3220a3120a3120a3120a302 +000c00000c3300c3300c3200c3200c3100c3100c3103a0000c3300c3300c3200c3200c3100c3100c3103f0000a3300a3201333013320073300732007310113000a3300a3200a3103c0000f3300f3200f3103a000 +00040000336251a605000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005000050000500005 +000c00000c3300c3300c3300c3200c3200c3200c3100c3100c3100c31000000000000000000000000000000000000000000000000000000000000000000000000a3000a3000a3000a3000a3310a3300332103320 +001000000c3500c3400c3300c3200f3500f3400f3300f320183501834013350133401835013350163401d36022370223702236022350223402232013300133001830018300133001330016300163001d3001d300 +000c0000242752b27530275242652b26530265242552b25530255242452b24530245242352b23530235242252b22530225242152b21530215242052b20530205242052b205302053a2052e205002050020500205 +001000102f65501075010753f615010753f6152f65501075010753f615010753f6152f6553f615010753f61500005000050000500005000050000500005000050000500005000050000500005000050000500005 +0010000016270162701f2711f2701f2701f270182711827013271132701d2711d270162711627016270162701b2711b2701b2701b270000001b200000001b2000000000000000000000000000000000000000000 +00080020245753057524545305451b565275651f5752b5751f5452b5451f5352b5351f5252b5251f5152b5151b575275751b545275451b535275351d575295751d545295451d535295351f5752b5751f5452b545 +002000200c2650c2650c2550c2550c2450c2450c2350a2310f2650f2650f2550f2550f2450f2450f2351623113265132651325513255132451324513235132351322507240162701326113250132420f2600f250 +00100000072750726507255072450f2650f2550c2750c2650c2550c2450c2350c22507275072650725507245072750726507255072450c2650c25511275112651125511245132651325516275162651625516245 +000800201f5702b5701f5402b54018550245501b570275701b540275401857024570185402454018530245301b570275701b540275401d530295301d520295201f5702b5701f5402b5401f5302b5301b55027550 +00100020112751126511255112451326513255182751826518255182451d2651d2550f2651824513275162550f2750f2650f2550f2451126511255162751626516255162451b2651b255222751f2451826513235 +00100010010752f655010753f6152f6553f615010753f615010753f6152f655010752f6553f615010753f61500005000050000500005000050000500005000050000500005000050000500005000050000500005 +001000100107501075010753f6152f6553f6153f61501075010753f615010753f6152f6553f6152f6553f61500005000050000500005000050000500005000050000500005000050000500005000050000500005 +002000002904029040290302b031290242b021290142b01133044300412e0442e03030044300302b0412b0302e0442e0402e030300312e024300212e024300212b0442e0412b0342e0212b0442b0402903129022 +000800202451524515245252452524535245352454524545245552455524565245652457500505245750050524565005052456500505245550050524555005052454500505245350050524525005052451500505 +000800201f5151f5151f5251f5251f5351f5351f5451f5451f5551f5551f5651f5651f575000051f575000051f565000051f565000051f555000051f555000051f545000051f535000051f525000051f51500005 +000500000373005731077410c741137511b7612437030371275702e5712437030371275702e5712436030361275602e5612435030351275502e5512434030341275402e5412433030331275202e5212431030311 +002000200c2750c2650c2550c2450c2350a2650a2550a2450f2750f2650f2550f2450f2350c2650c2550c2450c2750c2650c2550c2450c2350a2650a2550a2450f2750f2650f2550f2450f235112651125511245 +002000001327513265132551324513235112651125511245162751626516255162451623513265132551324513275132651325513245132350f2650f2550f2450c25011231162650f24516272162520c2700c255 +000300001f3302b33022530295301f3202b32022520295201f3102b31022510295101f3002b300225002950000000000000000000000000000000000000000000000000000000000000000000000000000000000 +000b00002935500300293453037030360303551330524300243050030013305243002430500300003002430024305003000030000300003000030000300003000030000300003000030000300003000030000300 +001000003c5753c5453c5353c5253c5153c51537555375453a5753a5553a5453a5353a5253a5253a5153a51535575355553554535545355353553535525355253551535515335753355533545335353352533515 +00100000355753555535545355353552535525355153551537555375353357533555335453353533525335253a5753a5453a5353a5253a5153a51533575335553354533545335353353533525335253351533515 +001000200c0600c0300c0500c0300c0500c0300c0100c0000c0600c0300c0500c0300c0500c0300c0100f0001106011030110501103011010110000a0600a0300a0500a0300a0500a0300a0500a0300a01000000 +001000000506005030050500503005010050000706007030070500703007010000000f0600f0300f010000000c0600c0300c0500c0300c0500c0300c0500c0300c0500c0300c010000000c0600c0300c0100c000 +0010000003625246150060503615246251b61522625036150060503615116253361522625006051d6250a61537625186152e6251d615006053761537625186152e6251d61511625036150060503615246251d615 +00100020326103261032610326103161031610306102e6102a610256101b610136100f6100d6100c6100c6100c6100c6100c6100f610146101d610246102a6102e61030610316103361033610346103461034610 +00400000302453020530235332252b23530205302253020530205302253020530205302153020530205302152b2452b2052b23527225292352b2052b2252b2052b2052b2252b2052b2052b2152b2052b2052b215 +__music__ +01 150a5644 +00 0a160c44 +00 0a160c44 +00 0a0b0c44 +00 14131244 +00 0a160c44 +00 0a160c44 +02 0a111244 +00 41424344 +00 41424344 +01 18191a44 +00 18191a44 +00 1c1b1a44 +00 1d1b1a44 +00 1f211a44 +00 1f1a2144 +00 1e1a2244 +02 201a2444 +00 41424344 +00 41424344 +01 2a272944 +00 2a272944 +00 2f2b2944 +00 2f2b2c44 +00 2f2b2944 +00 2f2b2c44 +00 2e2d3044 +00 34312744 +02 35322744 +00 41424344 +01 3d7e4344 +00 3d7e4344 +00 3d4a4344 +02 3d3e4344 +00 41424344 +00 41424344 +00 41424344 +00 41424344 +00 41424344 +00 41424344 +01 383a3c44 +02 393b3c44 + diff --git a/celeste/bin/pico-8/linux/lexaloffle-pico8.png b/celeste/bin/pico-8/linux/lexaloffle-pico8.png new file mode 100755 index 0000000..0d11f85 Binary files /dev/null and b/celeste/bin/pico-8/linux/lexaloffle-pico8.png differ diff --git a/celeste/bin/pico-8/linux/pico8 b/celeste/bin/pico-8/linux/pico8 new file mode 100755 index 0000000..e862f61 Binary files /dev/null and b/celeste/bin/pico-8/linux/pico8 differ diff --git a/celeste/bin/pico-8/linux/pico8.dat b/celeste/bin/pico-8/linux/pico8.dat new file mode 100755 index 0000000..200075c Binary files /dev/null and b/celeste/bin/pico-8/linux/pico8.dat differ diff --git a/celeste/bin/pico-8/linux/pico8_dyn b/celeste/bin/pico-8/linux/pico8_dyn new file mode 100755 index 0000000..c342893 Binary files /dev/null and b/celeste/bin/pico-8/linux/pico8_dyn differ diff --git a/celeste/bin/pico-8/osx/PICO-8.app/Contents/Frameworks/SDL2.framework/Versions/A/SDL2 b/celeste/bin/pico-8/osx/PICO-8.app/Contents/Frameworks/SDL2.framework/Versions/A/SDL2 new file mode 100755 index 0000000..6ca5919 Binary files /dev/null and b/celeste/bin/pico-8/osx/PICO-8.app/Contents/Frameworks/SDL2.framework/Versions/A/SDL2 differ diff --git a/celeste/bin/pico-8/osx/PICO-8.app/Contents/Info.plist b/celeste/bin/pico-8/osx/PICO-8.app/Contents/Info.plist new file mode 100644 index 0000000..2e5adcc --- /dev/null +++ b/celeste/bin/pico-8/osx/PICO-8.app/Contents/Info.plist @@ -0,0 +1,28 @@ + + + + + CFBundleExecutable + pico8 + CFBundleGetInfoString + pico8 + CFBundleIconFile + pico8.icns + CFBundleIdentifier + com.Lexaloffle.pico8 + CFBundleInfoDictionaryVersion + 6.0 + CFBundleName + pico8 + CFBundlePackageType + APPL + CFBundleShortVersionString + pico8 + CFBundleSignature + ???? + CFBundleVersion + pico8 + LSMinimumSystemVersion + 10.1 + + diff --git a/celeste/bin/pico-8/osx/PICO-8.app/Contents/MacOS/pico8 b/celeste/bin/pico-8/osx/PICO-8.app/Contents/MacOS/pico8 new file mode 100755 index 0000000..1c71fb0 Binary files /dev/null and b/celeste/bin/pico-8/osx/PICO-8.app/Contents/MacOS/pico8 differ diff --git a/celeste/bin/pico-8/osx/PICO-8.app/Contents/MacOS/pico8.dat b/celeste/bin/pico-8/osx/PICO-8.app/Contents/MacOS/pico8.dat new file mode 100755 index 0000000..200075c Binary files /dev/null and b/celeste/bin/pico-8/osx/PICO-8.app/Contents/MacOS/pico8.dat differ diff --git a/celeste/bin/pico-8/osx/PICO-8.app/Contents/Resources/pico8.icns b/celeste/bin/pico-8/osx/PICO-8.app/Contents/Resources/pico8.icns new file mode 100755 index 0000000..5c94b9c Binary files /dev/null and b/celeste/bin/pico-8/osx/PICO-8.app/Contents/Resources/pico8.icns differ diff --git a/celeste/bin/pico-8/pico-8.txt b/celeste/bin/pico-8/pico-8.txt new file mode 100755 index 0000000..e0f7981 --- /dev/null +++ b/celeste/bin/pico-8/pico-8.txt @@ -0,0 +1,2355 @@ +============================================================================================ + + PICO-8 v0.1.11g + https://www.pico-8.com + (c) Copyright 2014-2018 Lexaloffle Games LLP + Author: Joseph White // hey@lexaloffle.com + + PICO-8 is built with: + SDL2 http://www.libsdl.org + Lua 5.2 http://www.lua.org // see license.txt + GIFLIB http://giflib.sourceforge.net/ + WiringPi http://wiringpi.com/ + +============================================================================================ + +Welcome to PICO-8! + + PICO-8 is a fantasy console for making, sharing and playing tiny games and other computer + programs. When you turn it on, the machine greets you with a shell for typing in Lua programs + and provides simple built-in tools for creating sprites, maps and sound. + + The harsh limitations of PICO-8 are carefully chosen to be fun to work with, encourage small + but expressive designs and hopefully to give PICO-8 cartridges their own particular look and + feel. + + +:: Keys + + Toggle Fullscreen: Alt+Enter + Quit: Alt+F4 or command-Q + Reload/Run/Restart cart: Ctrl+R + Quick-Save: Ctrl+S + Mute/Unmute: Ctrl+M + Player 1 defaults: Cursors + ZX / NM / CV + Player 2 defaults: SDFE + tab,Q / shift A + Enter or P for pause menu (while running) + // use KEYCONFIG to change the defaults. + + +:: Specs + + Display: 128x128, fixed 16 colour palette + Input: 6-button controllers + Cartridge size: 32k + Sound: 4 channel, 64 definable chip blerps + Code: Lua (max 8192 tokens of code) + Sprites: Single bank of 128 8x8 sprites (+128 shared) + Map: 128x32 8-bit cels (+128x32 shared) + + +:: Hello World + + After PICO-8 boots, try typing some of these commands followed by enter: + + PRINT("HELLO WORLD") + RECTFILL(80,80,120,100,12) + CIRCFILL(70,90,20,14) + FOR I=1,4 DO PRINT(I) END + + (Note: PICO-8 only displays upper-case characters -- just type normally without capslock!) + + You can build up an interactive program by using commands like this in the code editing + mode along with two special callback functions _UPDATE and _DRAW. For example, the following + program allows you to move a circle around with the cursor keys. Press escape to switch + to the code editor and type or copy & paste the following code: + + X = 64 Y = 64 + FUNCTION _UPDATE() + IF (BTN(0)) THEN X=X-1 END + IF (BTN(1)) THEN X=X+1 END + IF (BTN(2)) THEN Y=Y-1 END + IF (BTN(3)) THEN Y=Y+1 END + END + + FUNCTION _DRAW() + RECTFILL(0,0,127,127,5) + CIRCFILL(X,Y,7,14) + END + + Now press escape to return to the console and type RUN (or press CTRL-R) to see it + in action. See the example cartridges for more complex programs. + + If you want to store your program for later, use the SAVE command: + + > SAVE PINKCIRC + + And load it again: + + > LOAD PINKCIRC + + +:: Example Cartridges + + These cartridges are included with PICO-8 and can be installed by typing: + + INSTALL_DEMOS + CD DEMOS + + HELLO Greetings from PICO-8 + API Demonstrates most PICO-8 functions + JELPI Platform game demo w/ 2p support + CAST 2.5D Raycaster demo + MANDEL Mandelbrot explorer + COLLIDE Example wall and actor collisions + BUTTERFLY Serpinsky triangles thing + DRIPPY Draw a drippy squiggle + STOMPY Music cart + + To run a cartridge, open PICO-8 and type: + + LOAD JELPI + RUN + + Press escape to stop the program, and once more to enter editing mode. + + +:: File System + + These commands can be used to manage files and directories (folders): + + DIR list the current directory + CD BLAH change directory + CD .. go up a directory + CD / change back to top directory (on PICO-8's virtual drive) + MKDIR BLAH make a directory + FOLDER open the current directory in the host operating system's file browser + + LOAD BLAH load a cart from the current directory + SAVE BLAH save a cart to the current directory + + If you want to move files around, duplicate them or delete them, use the FOLDER + command and do it in the host operating system. + + The default location for PICO-8's drive is: + + Windows: C:/Users/Yourname/AppData/Roaming/pico-8/carts + OSX: /Users/Yourname/Library/Application Support/pico-8/carts + Linux: ~/.lexaloffle/pico-8/carts + + You can change this and other settings in pico-8/config.txt + + Tip: The drive directory can be mapped to a cloud drive (provided by Dropbox, Google + Drive or similar) in order to provide a single disk shared between PICO-8 machines + spread across different host machines. + + +:: Loading and Saving + + When using LOAD and SAVE, the .P8 extention can be omitted and is added automatically. + + Saving to a .p8.png extention will save the cartridge in a special image format that + looks like a cartridge. + + Use a filename of "@CLIP" to load or save to the clipboard. + + Once a cartridge has been loaded or saved, it can also be quick-saved with CTRL-S + + :: Saving .p8.png carts with a text label and preview image + + To generate a label image saved with the cart, run the program first and press F7 to grab + whatever is on the screen. The first two lines of the program starting with '--' are also + drawn to the cart's label. + + e.g. + -- OCEAN DIVER LEGENDS + -- BY LOOPY + + + :: Code size restrictions for .png format + + When saving in .png format, the compressed size of the code must be less than 15360 bytes. + To find out the current size of your code, use the INFO command. The compressed size limit + is not enforced for saving in .p8 format. + + +:: Using an External Text Editor + + It is possible to edit .p8 files directly with a separate text editor. Using CTRL-R to run a + cartridge will automatically re-load the file if: + + 1. There are no unsaved changes in the PICO-8 editors, AND + 2. The file differs in content from the last loaded version + + If there are changes to the cart on disk /and/ in the editor, a notification is displayed: + + DIDN'T RELOAD; UNSAVED CHANGES + + PICO-8 does not fully support upper-case characters, and they are automatically converted to + lower-case when viewed in the code editor. Note that this also causes unsaved changes to exist, + which means that CTRL-R will stop automatically re-loading the version on disk until it is + manually LOAD()ed. + + Glyph characters (normally typed with shift-A..Z) are stored in .p8 format and in the + host operating system's clipboard as rough unicode equivalents. + + +:: Backups + + If you quit without saving changes, or overwrite an existing file, a backup of the + cartridge is saved to {appdata}/pico-8/backup. + + +:: Configuration + + :: config.txt + + You can find some settings in config.txt. Edit the file when PICO-8 is not running. + + Windows: C:/Users/Yourname/AppData/Roaming/pico-8/config.txt + OSX: /Users/Yourname/Library/Application Support/pico-8/config.txt + Linux: ~/.lexaloffle/pico-8/config.txt + + Use the -home switch (below) to use a different path to store config.txt and other data. + + + :: Commandline parameters + + // note: these override settings found in config.txt + + pico-8 [switches] [filename.p8] + + -width n set the window width + -height n set the window height + -windowed n set windowed mode off (0) or on (1) + -sound n sound volume 0..256 + -music n sound volume 0..256 + -joystick n joystick controls starts at player n (0..7) + -pixel_perfect n 1 for unfiltered screen stretching at integer scales (on by default) + -draw_rect x,y,w,h absolute window coordinates and size to draw pico-8's screen + -run filename load and run a cartridge + -x filename execute a PICO-8 cart headless and then quit + -p param_str pass a parameter string to the specified cartridge + -splore boot in splore mode + -home path set the path to store config.txt and other user data files + -desktop path set a location for screenshots and gifs to be saved + -screenshot_scale n scale of screenshots. default: 3 (368x368 pixels) + -gif_scale n scale of gif captures. default: 2 (256x256 pixels) + -gif_len n set the maximum gif length in seconds (1..120) + -gui_theme n use 1 for a higher contrast editor colour scheme + -timeout n how many seconds to wait before downloads timeout (default: 30) + -software_blit n use software blitting mode off (0) or on (1) + -foreground_sleep_ms n how many milliseconds to sleep between frames. + -background_sleep_ms n how many milliseconds to sleep between frames when running in background + + +:: Controller Setup + + PICO-8 uses the SDL2 controller configuration scheme. It will detect common controllers + on startup and also looks for custom mappings in sdl_controllers.txt in the same directory + as config.txt. sdl_controllers.txt has one mapping per line. + + To generate a custom mapping string for your controller, use either the controllermap + program that comes with SDL2, or try http://www.generalarcade.com/gamepadtool/ + + To set up which keyboard keys trigger joystick buttons presses, use KEYCONFIG. + + + +:: Screenshots, Videos and Cartridge Labels + + While a cartridge is running use: + + F6 Save a screenshot to desktop + F7 Capture cartridge label image + F8 Start recording a video + F9 Save GIF video to desktop (max: 8 seconds by default) + + // if F6..F9 are not available on your system, use CTRL-6..9 + + You can save a video at any time (it is always recording) -- use F8 just to reset + the video starting point if you want something less than 8 seconds long. + + To change the maximum gif length, edit gif_len in config.txt to specify the number + of seconds to record for. The gif format can not match 30fps exactly, so PICO-8 + instead uses the closest match: 33.3fps. + + + +:: Sharing Cartridges + + There are three ways to share carts made in PICO-8: + + 1. Share the .p8 or .p8.png file directly with other PICO-8 users + + Type FOLDER to open the current folder in your host operating system. + + 2. Post the cart on the Lexaloffe BBS to get a web-playable version + + http://www.lexaloffle.com/pico-8.php?page=submit + + 3. Export the cartridge to a stand-alone html/js or native binary player + (see the exporters section for details) + + +:: Exporters / Importers + + The EXPORT command can be used to generate png, wav files and stand-alone html and native + binary cartridge players. The output format is inferred from the filename extention (e.g. + .png). + + You are free to distribute and use exported cartridges and data as you please, provided + that you have permission from the author and contributors. + + :: Sprite Sheet (.png) + + IMPORT BLAH.PNG -- expects 128x128 png and colour-fits to the pico-8 palette + EXPORT BLAH.PNG -- use folder() to locate the exported png + + :: SFX and Music (.wav) + + EXPORT BLAH.WAV -- export music from the current pattern (when editor mode is MUSIC) + EXPORT BLAH.WAV -- export the current SFX (when editor mode is SFX) + EXPORT BLAH%D.WAV -- exports all of the SFXs as blah0.wav, blah1.wav .. blah63.wav + + :: HTML Player (.html) + + To generate a stand-alone html player (foo.html and foo.js): + > EXPORT FOO.HTML + + Or just the .js file: + > EXPORT FOO.JS + + Optionally provide a custom html template with the -p switch: + > EXPORT FOO.HTML -P ONE_BUTTON + + This will use the file {application data}/pico-8/plates/one_button.html as the + html shell, replacing a special string, ##js_file##, with the .js filename. + + + :: Binary Player (.bin) + + To generate stand-alone executables for Windows, Linux (64-bit) and Mac OSX: + + > EXPORT FOO.BIN + + By default, the cartridge label is used as an icon with no transparency. To + specificy an icon from the sprite sheet, use -i and optionally -s and/or -c + to control the size and transparency. + + -I N Icon index N with a default transparent colour of 0 (black). + -S N Size NxN sprites. Size 3 would be produce a 24x24 icon. + -C N Treat colour N as transparent. Use 16 for no transparency. + + For example, to use a 2x2 sprite starting at index 32 in the spritesheet, + using colour 12 as transparent, and bundling an extra cartrige C0.P8: + + > EXPORT FOO.BIN -I 32 -S 2 -C 12 C0.P8 + + +:: Exporting Multiple Cartridges + + Up to 16 cartridges can be bundled together by passing them to EXPORT, when generating + stand-alone html or native binary players + + EXPORT FOO.HTML DAT1.P8 DAT2.P8 GAME2.P8 + + During runtime, the extra carts can be accessed as if they were local files: + + RELOAD(0,0,0x2000, "DAT1.P8") -- load spritesheet from DAT1.P8 + LOAD("GAME2.P8") -- load and run another cart + + +:: Splore + + SPLORE is a built-in utility for browsing and organising both local and bbs (online) + cartridges. Type SPLORE [enter] to launch it, or launch PICO-8 with -splore. + + It is possible to control SPLORE entirely with a joystick: + LEFT and RIGHT to navigate lists of cartridges + UP AND DOWN to select items in each list + X,O or MENU to launch the cartridge + + While inside a cart, press MENU to favourite a cartridge or exit to splore. + If you're using a keyboard, it's also possible to press F to favourite an item + while it is selected in the cartridge list view. + + When viewing a list of BBS carts, use the top list item to re-download a list of + cartridges. If you are offline, the last downloaded list is displayed, and it is + still possible to play any cartridges you have downloaded. + + If you have installed PICO-8 on a machine with no internet access, you can also + use INSTALL_GAMES to add a small selection of pre-installed BBS carts to your + favourites list. + + + +:: Quirks of PICO-8 + + Common gotchas to watch out for: + + - The bottom half of the spritesheet and bottom half of the map occupy the same memory. + // Best use only one or the other if you're unsure how this works. + - PICO-8 numbers only go up to 32767.99. + // If you add 1 to a counter each frame, it will overflow after around 18 minutes! + - Lua arrays are 1-based by default, not 0-based. FOREACH starts at T[1], not T[0]. + - cos() and sin() take 0..1 instead of 0..PI*2, and sin() is inverted. + - sgn(0) returns 1. + - Toggle fullscreen: use alt-enter on OSX (command-F is used for searching text). + - When you want to export a .png cartridge, use SAVE, not EXPORT. EXPORT will save only the spritesheet! + + + +============================================================================================ + Editor Modes +============================================================================================ + + Press escape to toggle between console and editor + Click editing mode tabs at top right to switch or press ALT+LEFT/RIGHT + + + ** WARNING: The second half of the sprite sheet (banks 2 and 3), and the bottom half + of the map share the same cartridge space. It's up to you how you use the data, but + be aware that drawing on the second half of the sprite sheet could clobber data on + the map and vice versa. + + +:: Code Editor + + Hold shift to select (or click and drag with mouse) + CTRL-X, C, V to cut copy or paste selected + CTRL-Z, Y to undo, redo + CTRL-F to search for text in the current tab + CTRL-G to repeat the last search again + CTRL-L to jump to a line number + CTRL-UP, DOWN to jump to start or end + ALT-UP, DOWN to navigate to the previous, next function + CTRL-LEFT, RIGHT to jump by word + CTRL-D to duplicate current line + TAB to indent a selection (shift to un-indent) + + To enter special characters that represent buttons, use SHIFT-L,R,U,D,O,X + Or press CTRL-K to toggle glyph mode + + :: Tabs + + Click the [+] button at the top to add a new tab. + Navigate tabs by left-clicking, or with ctrl-tab, shift-ctrl-tab. + To remove the last tab, delete any contents and then moving off it (CTRL-A, del, ctrl-tab) + When running a cart, a single program is generated by concatenating all tabs in order. + + :: Code limits + + The current number of code tokens is shown at the bottom right. One program can have a + maximum of 8192 tokens. Each token is a word (e.g. variable name) or operator. Pairs of + brackets, and strings each count as 1 token. commas, periods, LOCALs, semi-colons, ENDs, + and comments are not counted. + + Right click to toggle through other stats (character count, compressed size). + If a limit is reached, a warning light will flash. This can be disabled by right-clicking. + + +:: Sprite Editor + + The sprite editor is designed to be used both for sprite-wise editing and for freeform + pixel-level editing. The sprite navigator at the bottom of the screen provides an 8x8-wise + view into the sprite-sheet, but it is possible to use freeform tools (pan, select) when + dealing with larger or oddly sized areas. + + Draw Tool + Click and drag on the sprite to plot pixels + Applies to visible area + Hold CTRL to search and replace a colour + Use right mouse button to select colour + + Stamp Tool + Click to stamp whatever is in the copy buffer + Hold LCONTROL to treat colour 0 (black) as transparent + + Select Tool // shortcut: LSHIFT or S + Create a selection + Enter or click to select none. + + If a pixel-wise selection is not present, many operations are instead applied + to a sprite-wise selection. To select sprites, shift-drag in the sprite navigator. + + Pan Tool // shortcut: space + View the spritesheet. + + Fill Tool + Fill with the current colour + Applies to the current selection + If no selection, applies to visible area + + Extra keys + CTRL-Z to undo // single step only in 0.2.0 + CTRL-C to copy selected area or selected sprites + CTRL-V to paste to current sprite location + Q,W to switch to previous/next sprite + 1,2 to switch to previous/next colour + Tab to toggle fullscreen view + Mousewheel or < and > to zoom (centered in fullscreen) + + + Operations on selected area or selected sprites: + f to flip + v to flip vertically + r to rotate (must be square selection) + Cursor keys to move (loops if sprite selection) + + Sprite flags + The 8 coloured circles are sprite flags for the current sprite. + Each one can be true (on) or false (off), and are accessed by + using the FSET and FGET functions. They are indexed from 0, from + the left (0,1,2..7). See fset() for more information. + + +:: Map Editor + + The pico-8 map is a 128x32 (or 128x64 using shared space) block of 8-bit values. + Each value is shown in the editor as a reference to a sprite (0..255), but you can + of course use the data to represent whatever you like. + + The tools are similar to the ones used in sprite editing mode. Select a sprite + and click and drag to paint values into the map. + + To draw multiple sprites, select from sprite navigator with shift+drag + To copy a block of values, use the selection tool and then stamp tool to paste + To pan around the map, use the pan tool or hold space + Q,W to switch to previous/next sprite + Mousewheel or < and > to zoom (centered in fullscreen) + + +:: SFX Editor + + There are 64 SFX ("sound effects") in a cartridge, used for both sound and music. + + Each SFX has 32 notes, and each note has: + A frequency (C0..C5) + An instrument (0..7) + A volume (0..7) + An effect (0..7) + + Each SFX also has these properties: + + A play speed (SPD) : the number of 'ticks' to play each note for. + // This means that 1 is fastest, 3 is 3x as slow, etc. + + Loop start and end : this is the note index to loop back and to + // Looping is turned off when the start index >= end index + + There are 2 modes for editing/viewing a SFX: Pitch mode (more suitable + for sound effects) and tracker mode (more suitable for music). The mode + can be changed using the top-left buttons, or toggled with TAB. + + + 1. Pitch Mode + + Click and drag on the pitch area to set the frequency for each note, + using the currently selected instrument (indicated by colour). + + Hold shift to apply only the selected instrument + Hold CTRL to snap entered notes to the C minor pentatonic scale + + + 2. Tracker Mode + + Each note shows: frequency octave instrument volume effect + To enter a note, use q2w3er5t6y7ui zsxdcvgbhnjm (piano-like layout) + Hold shift when entering a note to transpose -1 octave .. +1 octave + New notes are given the selected instrument/effect values + To delete a note, use backspace or set the volume to 0 + + Click and then shift-click to select a range that can be copied + (CTRL-C) and pasted (CTRL-V) + + Navigation: + PAGEUP/DOWN or CTRL-UP/DOWN to skip up or down 4 notes + HOME/END to jump to the first or last note + CTRL-LEFT/RIGHT to jump across columns + + + 3. Controls for both modes + + - + to navigate the current SFX + < > to change the speed. + SPACE to play/stop + SHIFT-SPACE to play from the current SFX quarter (group of 8 notes) + A to release a looping sample + Left click or right click to increase / decrease the SPD or LOOP values + // Hold shift when clicking to increase / decrease by 4 + // Alternatively, click and drag left/right or up/down + Shift-click an instrument, effect, or volume to apply to all notes. + + + :: Effects + + 0 none + 1 slide // Slide to the next note and volume + 2 vibrato // Rapidly vary the pitch within one quarter-tone + 3 drop // Rapidly drop the frequency to very low values + 4 fade in // Ramp the volume up from 0 + 5 fade out // Ramp the volume down to 0 + 6 arpeggio fast // Iterate over groups of 4 notes at speed of 4 + 7 arpeggio slow // Iterate over groups of 4 notes at speed of 8 + + If the SFX speed is <= 8, arpeggio speeds are halved to 2, 4 + + +:: Music Editor + + Music in PICO-8 is controlled by a sequence of 'patterns'. Each pattern is a list of + 4 numbers indicating which SFX will be played on that channel. + + + :: Flow control + + Playback flow can be controlled using the 3 buttons at the top right. + + When a pattern has finished playing, the next pattern is played unless: + + - there is no data left to play (music stops) + - a STOP command is set on that pattern (the third button) + - a LOOP BACK command is set (the 2nd button), in which case the music player searches + back for a pattern with the LOOP START command set (the first button) or returns to + pattern 0 if none is found. + + When a pattern has SFXes with different speeds, the pattern finishes playing when + the left-most non-looping channel has finished playing. This can be used to set up + time signatures that don't divide into 32, or double-time drum beats etc. + + + :: Copying music between or within cartridges + + To select a range of patterns: click once on the first pattern in the pattern + navigator, then shift-click on the last pattern. Selected patterns can be copied + and pasted with CTRL-C and CTRL-V. When pasting into another cartridge, the SFX + that each pattern points to will also be pasted (possibly with a different index) + if it does not already exist. + + + :: SFX Instruments + + In addition to the 8 built-in instruments, custom instruments can be defined using + the first 8 SFX. Use the toggle button to the right of the instruments to select an + index, which will show up in the instrument channel as green instead of pink. + + When an SFX instrument note is played, it essentially triggers that SFX, but alters + the note's attributes: + + Pitch is added relative to C2 + Volume is multiplied + Effects are applied on top of the SFX instrument's effects + + For example, a simple tremolo effect could be implemented by defining an instrument + in SFX 0 that rapidly alternates between volume 5 and 2. When using this instrument + to play a note, the volume can further be altered as usual (via the volume channel + or using the fade in/out effects). In this way, SFX instruments can be used to control + combinations of detailed changes in volume, pitch and texture. + + SFX instruments are only retriggered when the pitch changes, or the previous note + has zero volume. This is useful for instruments that change more slowly over time. + For example: a bell that gradually fades out. To invert this behaviour, effect 3 + (normally 'drop') can be used when triggering the note. All other effect values have + their usual meaning when triggering SFX instruments. + + +============================================================================================ + Lua Syntax Primer +============================================================================================ + + PICO-8 programs are written using Lua syntax, but do not use the standard Lua library. + The following is a brief summary of essential Lua syntax. + + For more details, or to find out about proper Lua, see www.lua.org. + + :: Comments + + -- use two hyphens like this to ignore everything until the end of the line + --[[ multi-line + comments ]] + + + :: Types and assignment + + Types in Lua are numbers, strings, booleans and tables; + + NUM = 12/100 + S = "THIS IS A STRING" + B = FALSE + T = {1,2,3} + + Numbers in PICO-8 are all 16:16 fixed point. They range from -32768.0 to 32767.99999 + + Hexadecimal notation with optional fractional parts can be used: + 0x11 -- 17 + 0x11.4000 -- 17.25 + + Numbers written in decimal are rounded to the closest fixed point value. To see the + 32-bit hexadecimal representation, use PRINT(TOSTR(VAL,TRUE)): + + ?TOSTR(-32768,TRUE) -- 0x8000.0000 + ?TOSTR(32767.99999,TRUE) -- 0x7fff.ffff + + Dividing by zero evaluates to 0x7fff.ffff if positive, or -0x7fff.ffff if negative. + + + :: Conditionals + + IF NOT B THEN + PRINT("B IS FALSE") + ELSE + PRINT("B IS NOT FALSE") + END + + -- with ELSEIF + + IF X == 0 THEN + PRINT("X IS 0") + ELSEIF X < 0 THEN + PRINT("X IS NEGATIVE") + ELSEIF X > 0 THEN + PRINT("X IS POSITIVE") + ELSE + PRINT("THIS IS LINE IS NEVER REACHED") + END + + IF (4 == 4) THEN PRINT("EQUAL") END + IF (4 ~= 3) THEN PRINT("NOT EQUAL") END + IF (4 <= 4) THEN PRINT("LESS THAN OR EQUAL") END + IF (4 > 3) THEN PRINT("MORE THAN") END + + :: Loops + + FOR X=1,5 DO + PRINT(X) + END + -- prints 1,2,3,4,5 + + X = 1 + WHILE(X <= 5) DO + PRINT(X) + X = X + 1 + END + + FOR X=1,10,3 DO PRINT(X) END -- 1,4,7,10 + + FOR X=5,1,-2 DO PRINT(X) END -- 5,3,1 + + + :: Functions and Local Variables + + Y=0 + FUNCTION PLUSONE(X) + LOCAL Y = X+1 + RETURN Y + END + PRINT(PLUSONE(2)) -- 3 + PRINT(Y) -- 0 + + + :: Tables + + In Lua, tables are a collection of key-value pairs where the key and value types can both + be mixed. They can be used as arrays by indexing them with integers. + + A={} -- create an empty table + A[1] = "BLAH" + A[2] = 42 + A["FOO"] = {1,2,3} + + -- Arrays use 1-based indexing by default + + A = {11,12,13,14} + PRINT(A[2]) -- 12 + + -- The size of a table indexed with sequential 1-based integers: + + PRINT(#A) -- 4 + + -- Indexes that are strings can be written using dot notation + + PLAYER = {} + PLAYER.X = 2 -- is equivalent to PLAYER["X"] + PLAYER.Y = 3 + + -- see also the tables section in the api reference below. + + + :: PICO-8 Shorthand + + PICO-8 also allows several non-standard, shorter ways to write common patterns. + + 1. IF THEN END statements on a single line can be expressed without the THEN & END + + IF (NOT B) I=1 J=2 + + -- is equivalent to: IF (NOT B) THEN I=1 J=2 END + -- everything must be written on the same line, and with the condition in brackets + + + 2. unary math operators + + a += 2 -- equivalent to: a = a + 2 + a -= 2 -- equivalent to: a = a - 2 + a *= 2 -- equivalent to: a = a * 2 + a /= 2 -- equivalent to: a = a / 2 + a %= 2 -- equivalent to: a = a % 2 + + + 3. != operator + + Not shorthand, but pico-8 also accepts != instead of ~= for "not equal to" + + +============================================================================================ + API +============================================================================================ + + PICO-8 is built on the Lua programming language, but does not include the Lua standard library. + Instead, a small api is offered in keeping with PICO-8's minimal design and limited screen + space. For an example program that uses most of the api functions, see /DEMOS/API.P8 + + Functions are written here as: + function_name parameter [optional_parameter] + + System functions called from commandline can omit the usual brackets and string quotes: + load blah.p8 --> load("blah.p8") + + +-------------------------------------------------------------------------------------------------------- + System +-------------------------------------------------------------------------------------------------------- + + + load filename [breadcrumb [param_str]] + save filename + + Load or save a cartridge + + When loading from a running cartridge, the loaded cartridge is immediately run with + parameter string param_str, and a menu item is inserted and named breadcrumb, that + returns the user to the loading cartridge. + + Filenames that start with '#' are taken to be a BBS cart followed by its id: + load("#1234") -- download [and run] cart number 1234 + + If the id is of the cart's parent post, then the latest version is downloaded. + BBS carts can be loaded from other BBS carts or local carts, but not from exported carts. + + + folder + + Open the carts folder in the host operating system. + + dir (also aliased as ls) + + List files in the current directory. When called from a running program, returns a list + of all .p8 and .p8.png files in the same directory. + + run + + Run from the start of the program + Can be called from inside a program to reset program. + + stop [message] + + Stop the cart and optionally print a message + + resume + + Run from the existing cart state (flakey) + + reboot + + Reboot the machine + Useful for starting a new project + + info + + Print out some information about the cartridge: + Code size, tokens, compressed size + + Also displayed: + + UNSAVED CHANGES When the cartridge in memory differs to the one on disk + EXTERNAL CHANGES When the cartridge on disk has changed since it was loaded + (e.g. by editing the program using a separate text editor) + + flip + + Flip the back buffer to screen and wait for next frame (30fps) + Don't normally need to do this -- _draw() calls it for you. + + If your program does not call flip before a frame is up, and a _draw() callback + is not in progress, the current contents of the back buffer are copied to screen. + + printh str [filename] [overwrite] + + Print a string to host operating system's console for debugging. + + If filename is set, append the string to a file on the host operating system + // (in the current directory -- use FOLDER to view) + Setting overwrite to true causes that file to be overwritten rather than appended. + Use a filename of "@clip" to write to the host's clipboard. + // use stat(4) to read the clipboard, but the contents of the clipboard are only + // available after pressing CTRL-V during runtime (for security reasons). + + stat x + + Get system status where x is: + + 0 Memory usage (0..2048) + 1 CPU used since last flip (1.0 == 100% CPU at 30fps) + 4 Clipboard contents (after user has pressed CTRL-V) + 6 Parameter string + 7 Current framerate + + 16..19 Index of currently playing SFX on channels 0..3 + 20..23 Note number (0..31) on channel 0..3 + 24 Currently playing pattern index + 25 Total patterns played + 26 Ticks played on current pattern + + 80..85 UTC time: year, month, day, hour, minute, second + 90..95 Local time + + 100 Current breadcrumb label, or nil + + + extcmd x + + Special system command, where x is a string: + + "pause" request the pause menu be opened + "reset" request a cart reset + "go_back" follow the current breadcrumb (if there is one) + + Additional commands that are ignored when running as a BBS cart: + + "label" set cart label + "screen" save a screenshot + "rec" set video start point + "video" save a .gif to desktop + "audio_rec" start recording audio + "audio_end" save recorded audio to desktop + + +-------------------------------------------------------------------------------------------- + Program Structure +-------------------------------------------------------------------------------------------- + + There are 3 special functions that, if defined by the user, are called during program + execution: + + _update() + Called once per update at 30fps + + _draw() + Called once per visible frame + + _init() + Called once on program startup + + + _draw() is normally called at 30fps, but if it can not complete in time, PICO-8 will + attempt to run at 15fps and call _update() twice per visible frame to compensate. + + + :: Running PICO-8 at 60fps + + If _update60() is defined instead of _update(), PICO-8 will run in 60fps mode: + + - both _update60() and _draw() are called at 60fps + - half the PICO-8 CPU is available per frame before dropping down to 30fps + + Note that not all host machines are capable of running at 60fps. Older machines, + and / or web versions might also request PICO-8 to run at 30 fps (or 15 fps), even + when the PICO-8 CPU is not over capacity. In this case, multiple _update60 calls + are made for every _draw call in the same way. + + +-------------------------------------------------------------------------------------------- + Graphics +-------------------------------------------------------------------------------------------- + + PICO-8 has a fixed capacity of 128 8x8 sprites, plus another 128 that overlap with the + bottom half of the map data ("shared data"). These 256 sprites are collectively called + the sprite sheet, and can be thought of as a 128x128 pixel image. + + All of PICO-8's drawing operations are subject to the current draw-state. The draw-state + includes a camera position (for adding an offset to all coordinates), palette mapping + (for recolouring sprites), clipping rectangle, a drawing colour, and a fill pattern. + + The draw state is reset each time a program is run. This is equivalent to calling: + clip() camera() pal() color(6) + + Colours indexes: + + 0 black 1 dark_blue 2 dark_purple 3 dark_green + 4 brown 5 dark_gray 6 light_gray 7 white + 8 red 9 orange 10 yellow 11 green + 12 blue 13 indigo 14 pink 15 peach + + + clip [x y w h] + + Sets the screen's clipping region in pixels + clip() to reset + + + pget x y + pset x y [c] + + Get or set the colour (c) of a pixel at x, y. + + + sget x y + sset x y [c] + + Get or set the colour (c) of a spritesheet pixel. + + + fget n [f] + fset n [f] v + + Get or set the value (v) of a sprite's flag + f is the flag index 0..7 + v is boolean and can be true or false + + The initial state of flags 0..7 are settable in the sprite editor, + using the line of little colourful buttons. + + The meaning of sprite flags is up to the user, or can be used to + indicate which group ('layer') of sprites should be drawn by map. + + If the flag index is omitted, all flags are retrieved/set as a bitfield + fset(2, 1+2+8) -- sets bits 0,1 and 3 + fset(2, 4, true) -- sets bit 4 + print(fget(2)) -- 27 (1+2+8+16) + + + print str [x y [col]] + + Print a string + If only str is supplied, and the cursor reaches the end of the screen, + a carriage return and vertical scroll is automatically applied. + + + cursor x y + + Set the cursor position and carriage return margin + + + color col + + Set the default color to be used by drawing functions + + + cls [col] + + Clear the screen and reset the clipping rectangle + + + camera [x y] + + Set a screen offset of -x, -y for all drawing operations + camera() to reset + + + circ x y r [col] + circfill x y r [col] + + Draw a circle or filled circle at x,y with radius r + If r is negative, the circle is not drawn + + line x0 y0 x1 y1 [col] + + draw line + + + rect x0 y0 x1 y1 [col] + rectfill x0 y0 x1 y1 [col] + + Draw a rectangle or filled rectangle + + + pal c0 c1 [p] + + Draw all instances of colour c0 as c1 in subsequent draw calls + + pal() to reset to system defaults (including transparency values and fill pattern) + + Two types of palette (p; defaults to 0) + 0 draw palette : colours are remapped on draw // e.g. to re-colour sprites + 1 screen palette : colours are remapped on display // e.g. for fades + c0 colour index 0..15 + c1 colour index to map to + + + palt c t + + Set transparency for colour index to t (boolean) + Transparency is observed by spr(), sspr() and map() + e.g. palt(8, true) -- red pixels not drawn + palt() resets to default: all colours opaque except colour 0 + + + + spr n x y [w h] [flip_x] [flip_y] + + draw sprite n (0..255) at position x,y + width and height are 1,1 by default and specify how many sprites wide to blit. + Colour 0 drawn as transparent by default (see palt()) + flip_x=true to flip horizontally + flip_y=true to flip vertically + + + sspr sx sy sw sh dx dy [dw dh] [flip_x] [flip_y] + + Stretch rectangle from sprite sheet (sx, sy, sw, sh) // given in pixels + and draw in rectangle (dx, dy, dw, dh) + Colour 0 drawn as transparent by default (see palt()) + dw, dh defaults to sw, sh + flip_x=true to flip horizontally + flip_y=true to flip vertically + + + fillp p + + The PICO-8 fill pattern is a 4x4 2-colour tiled pattern observed by: + circ() circfill() rect() rectfill() pset() line() + + p is a bitfield in reading order starting from the highest bit. To calculate the value + of p for a desired pattern, add the bit values together: + + .-----------------------. + |32768|16384| 8192| 4096| + |-----|-----|-----|-----| + | 2048| 1024| 512 | 256 | + |-----|-----|-----|-----| + | 128 | 64 | 32 | 16 | + |-----|-----|-----|-----| + | 8 | 4 | 2 | 1 | + '-----------------------' + + For example, FILLP(4+8+64+128+ 256+512+4096+8192) would create a checkerboard pattern. + + This can be more neatly expressed in binary: FILLP(0b0011001111001100) + The default fill pattern is 0, which means a single solid colour is drawn. + + To specify a second colour for the pattern, use the high bits of any colour parameter: + + FILLP(0b0011010101101000) + CIRCFILL(64,64,20, 0x4E) -- brown and pink + + An additional bit 0b0.1 can be set to indicate that the second colour is not drawn. + + FILLP(0b0011001111001100.1) -- checkboard with transparent squares + + The fill pattern can also be set by setting bits in any colour parameter: + + POKE(0x5F34, 1) -- sets integrated fillpattern + colour mode + CIRCFILL(64,64,20, 0x114E.ABCD) -- sets fill pattern to ABCD + + -- bit 0x1000.0000 means the non-colour bits should be observed + -- bit 0x0100.0000 transparency bit + -- bits 0x00FF.0000 are the usual colour bits + -- bits 0x0000.FFFF are interpreted as the fill pattern + +-------------------------------------------------------------------------------------------- + Tables +-------------------------------------------------------------------------------------------- + + + add t v + + Add value v to the end of table t. + Equivalent to t[#t+1] = v + + FOO={} -- create empty table + ADD(FOO, 11) + ADD(FOO, 22) + PRINT(FOO[2]) -- 22 + + del t v + + Delete the first instance of value v in table t + The remaining entries are shifted left one index to avoid holes. + Note that v is the value of the item to be deleted, not the index into the table! + del() can be called safely on a table's item while iterating over that table. + + A={1,10,2,11,3,12} + FOR ITEM IN ALL(A) DO + IF (ITEM < 10) THEN DEL(A, ITEM) END + END + FOREACH(A, PRINT) -- 10,11,12 + PRINT(A[3]) -- 12 + + + all t + + Used in FOR loops to iterate over all items in a table (that have a 1-based integer index), + in the order they were added. + + T = {11,12,13}; + ADD(T,14) + ADD(T,"HI") + FOR V IN ALL(T) DO PRINT(V) END -- 11 12 13 14 HI + PRINT(#T) -- 5 + + + foreach t f + + For each item in table t, call function f with the item as a single parameter. + + FOREACH(T, PRINT) + + + pairs t + + Used in FOR loops to iterate over table t, providing both the key and value for each item. + Unlike all(), pairs() iterates over every item regardless of indexing scheme. + Order is not guaranteed. + + T = {["HELLO"]=3, [10]="BLAH"} + T.BLUE = 5; + FOR K,V IN PAIRS(T) DO + PRINT("K: "..K.." V:"..V) + END + + Output: + + K: 10 v:BLAH + K: HELLO v:3 + K: BLUE v:5 + + +-------------------------------------------------------------------------------------------- + Input +-------------------------------------------------------------------------------------------- + + btn [i [p]] + + get button i state for player p (default 0) + i: 0..5: left right up down button_o button_x + p: player index 0..7 + + If no parameters supplied, returns a bitfield of all 12 button states for player 0 & 1 + // P0: bits 0..5 P1: bits 8..13 + + Default keyboard mappings to player buttons: + player 0: cursors, Z,X / C,V / N,M + player 1: ESDF, LSHIFT,A / TAB,Q,E + + + btnp [i [p]] + + btnp is short for "Button Pressed"; Instead of being true when a button is held down, + btnp returns true when a button is down AND it was not down the last frame. It also + repeats after 15 frames, returning true every 4 frames after that (at 30fps -- double + that at 60fp). This can be used for things like menu navigation or grid-wise player + movement. + + + +-------------------------------------------------------------------------------------------- + Audio +-------------------------------------------------------------------------------------------- + + sfx n [channel [offset [length]]] + + play sfx n on channel (0..3) from note offset (0..31) for length notes + n -1 to stop sound on that channel + n -2 to release sound on that channel from looping + Any music playing on the channel will be halted + offset in number of notes (0..31) + + channel -1 (default) to automatically choose a channel that is not being used + channel -2 to stop the sound from playing on any channel + + + music [n [fade_len [channel_mask]]] + + play music starting from pattern n (0..63) + n -1 to stop music + fade_len in ms (default: 0) + channel_mask specifies which channels to reserve for music only + e.g. to play on channels 0..2: 1+2+4 = 7 + + Reserved channels can still be used to play sound effects on, but only when that + channel index is explicitly requested by sfx(). + + +-------------------------------------------------------------------------------------------------------- + Map +-------------------------------------------------------------------------------------------------------- + + The PICO-8 map is a 128x32 grid of 8-bit cels, or 128x64 when using the shared memory. When + using the map editor, the meaning of each cel is taken to be an index into the spritesheet + (0..255). However, it can instead be used as a general block of data. + + + mget x y + mset x y v + + get or set map value (v) at x,y + + map cel_x cel_y sx sy cel_w cel_h [layer] + + draw section of map (in cels) at screen position sx, sy (pixels) + if layer is specified, only cels with the same flag number set are drawn + // Bitfield. So 0x5 means draw sprites with bit 0 and bit 2 set. + // defaults to all sprites + + exception: sprite 0 is always taken to mean empty. + + e.g. map(0,0, 20,20, 4,2) + -> draws a 4x2 blocks of cels starting from 0,0 in the map, to the screen at 20,20 + + If cel_w and cel_h are not specified, defaults to 128,32 + (the top half of the map -- use 128,64 for the full map including shared memory) + + +-------------------------------------------------------------------------------------------------------- + Memory +-------------------------------------------------------------------------------------------------------- + + PICO-8 has 3 types of memory: + + 1. Base RAM (32k): see layout below. Access with peek() poke() memcpy() memset() + 2. Cart ROM (32k): same layout as base ram until 0x4300 + 3. Lua RAM (2MB): compiled program + variables + + Technical note: // you probably don't need to know this + + While using the editor, the data being modified is in cart rom, but api functions such as spr() + and sfx() only operate on base ram. PICO-8 automatically copies cart rom to base ram (i.e. + calls reload()) in 3 cases: + + 1. When a cartridge is loaded + 2. When a cartridge is run + 3. When exiting any of the editor modes + + + :: Base ram memory layout + 0x0 gfx + 0x1000 gfx2/map2 (shared) + 0x2000 map + 0x3000 gfx_props + 0x3100 song + 0x3200 sfx + 0x4300 user data + 0x5e00 persistent cart data (256 bytes) + 0x5f00 draw state + 0x5f40 hardware state + 0x5f80 gpio pins (128 bytes) + 0x6000 screen (8k) + + User data has no particular meaning and can be used for anything via memcpy(), peek() & poke(). + Persistent cart data is mapped to 0x5e00..0x5eff but only stored if cartdata() has been called. + Colour format (gfx/screen) is 2 pixels per byte: low bits encode the left pixel of each pair. + Map format is one byte per cel, where each byte normally encodes a sprite index. + + + peek addr + poke addr val + + Read and write one byte to an address in base ram. + Legal addresses are 0x0..0x7fff + Reading out of range returns 0 + Writing out of range causes a fault + + peek4 addr + poke4 addr val + + 32-bit versions. Read and write one number (val) in little-endian format. + addr does not need to be aligned to 4-byte boundaries. + + memcpy dest_addr source_addr len + + Copy len bytes of base ram from source to dest + Sections can be overlapping + + reload dest_addr source_addr len [filename] + + Same as memcpy, but copies from cart rom + The code section ( >= 0x4300) is protected and can not be read. + If filename specified, load data from a different cartridge. + // (must be local -- bbs cartridges can not be read in this way) + + cstore dest_addr source_addr len [filename] + + Same as memcpy, but copies from base ram to cart rom + cstore() is equivalent to cstore(0, 0, 0x4300) + Can use for writing tools to construct carts or to visualize the state + of the map / spritesheet using the map editor / gfx editor. + The code section ( >= 0x4300) is protected and can not be written to. + + If a filename is specified, the data is written directly to that + cartridge on disk. Up to 64 cartridges can be written in one session. + See the 'Cartridge Data' section for additional notes on using cstore. + + + memset dest_addr val len + + Set len bytes to val + (quite fast -- can use to draw unclipped horizonal scanlines etc) + + +-------------------------------------------------------------------------------------------------------- + Math +-------------------------------------------------------------------------------------------------------- + + max x y + min x y + mid x y z + + Returns the maximum, minimum, or middle value of parameters + For example, mid(7,5,10) returns 7 + + flr x + ceil x + + Returns the closest integer that is equal to or below / above x + + ?flr ( 4.1) --> 4 + ?ceil( 4.1) --> 5 + ?flr (-2.3) --> -3 + ?ceil(-2.3) --> -2 + + + cos x + sin x + + Returns the cosine of x, where 1.0 indicates a full circle + sin is inverted to suit screenspace + e.g. sin(0.25) returns -1 + + If you'd prefer radian-based trig functions without the y inversion, + paste the following snippet near the start of your program: + + cos1 = cos function cos(angle) return cos1(angle/(3.1415*2)) end + sin1 = sin function sin(angle) return sin1(-angle/(3.1415*2)) end + + + atan2 dx dy + + Converts dx, dy into an angle from 0..1 + As with cos/sin, angle is taken to run anticlockwise in screenspace + e.g. atan(1, -1) returns 0.125 + + sqrt x + + Return the square root of x + + abs x + + Returns the absolute (positive) value of x + + rnd x + Returns a random number n, where 0 <= n < x + If you want an integer, use flr(rnd(x)) + + srand x + Sets the random number seed + The seed is automatically randomized on cart startup + + + Binary Operations + + band x y + bor x y + bxor x y + bnot x + rotl x y + rotr x y + shl x n -- shift left n bits + shr x n -- arithmetic right shift + lshr x n -- logical right shift + + +-------------------------------------------------------------------------------------------------------- + Custom Menu Items +-------------------------------------------------------------------------------------------------------- + + menuitem index [label callback] + + Add an extra item to the pause menu + + Index should be 1..5 and determines the order each menu item is displayed + label should be a string up to 16 characters long + callback is a function called when the item is selected by the users + + When no label or function is supplied, the menu item is removed + + example: + menuitem(1, "restart puzzle", function() reset_puzzle() sfx(10) end) + + +-------------------------------------------------------------------------------------------------------- + Strings +-------------------------------------------------------------------------------------------------------- + + s = "the quick brown fox" + + -- length + + print(#s) --> 19 + + + -- joining strings + + print("three "..4) --> "three 4" + + + -- sub() to grab substrings + + print(sub(s,5,9)) --> "quick" + print(sub(s,5)) --> "quick brown fox" + + +-------------------------------------------------------------------------------------------------------- + Types +-------------------------------------------------------------------------------------------------------- + + type val + + returns the name of the type of value x as a string + + tostr val [hex] + + returns val as a string + + if hex is true and val is a number, an unsigned hexadecimal writing of + the number is returned in the format "0x0000.0000". You can use this to + inspect the internal representation of PICO-8 numbers. + + if val is a boolean, it is written as "true" or "false" + + all other val types are written as "[typename]" + + tonum val + + converts val to a number + if val is a string, the number is taken to be decimal unless prefixed with "0x" + if the conversion fails, tonum returns no value. + +-------------------------------------------------------------------------------------------- + Cartridge Data +-------------------------------------------------------------------------------------------- + + Using cartdata(), dset(), and dget(), 64 numbers (256 bytes) of persistent data + can be stored on the user's PICO-8 that persists after the cart is unloaded or + PICO-8 is shutdown. This can be used as a lightweight way to store things like + high scores or to save player progress. It can also be used to share data across + cartridges / cartridge versions. + + If you need more than 256 bytes, it is also possible to write directly to the + cartridge using cstore(). The disadvantage is that the data is tied to that + particular version of the cartridge. e.g. if a game is updated, players will + lose their savegames. Also, some space in the data sections of the cartridge + need to be left available. + + Another alternative is to write directly to a second cartridge by specifying + a fourth parameter to cstore(). This requires a cart swap (which in reality + only means the user needs to watch a spinny cart animation for 1 second). + + CSTORE(0,0,0x2000, "spritesheet.p8") + -- later: + RELOAD(0,0,0x2000, "spritesheet.p8") -- restore the saved data + + + cartdata id + + cartdata() opens a permanent data storage slot indexed by id, that can be + used to store and retrieve up to 256 bytes (64 numbers) worth of data using + DSET() and DGET(). + + CARTDATA("zep_dark_forest") -- can only be set once per session + -- later in the program.. + DSET(0, score) + + id is a string up to 64 characters long, and should be unusual enough that + other cartridges do not accidentally use the same id. + + e.g. cartdata("zep_jelpi") + + legal characters are a..z, 0..9 and underscore (_) + + returns true if data was loaded, otherwise false + + cartdata can not be called more than once per cartridge execution. + + Once a cartdata id has been set, the area of memory 0x5e00..0x5eff is mapped + to permanent storage, and can either be accessed directly or via dget/dset. + + + dget index + + Get the number stored at index (0..63) + Use this only after you have called cartdata() + + dset index value + + Set the number stored at index (0..63) + Use this only after you have called cartdata() + + There is no need to flush written data -- it is automatically + saved to permanent storage even if POKE()'ed directly. + + +-------------------------------------------------------------------------------------------- + GPIO +-------------------------------------------------------------------------------------------- + + GPIO stands for "General Purpose Input Output", and allows machines to comunicate with + each other. PICO-8 maps bytes in the range 0x5f80..0x5fff to gpio pins that can be + poke()ed (to output a value -- e.g. to make an LED light up) or peek()ed (e.g. to read + the state of a switch). + + GPIO means different things for different host platforms: + + CHIP: 0x5f80..0x5f87 mapped to xio-p0..xio-p7 + Pocket CHIP: 0x5f82..0x5f87 mapped to GPIO1..GPIO6 + // xio-p0 & p1 are exposed inside the prototyping area inside the case. + Raspberry Pi: 0x5f80..0x5f8f mapped to wiringPi pins 0..7 + // see http://wiringpi.com/pins/ for mappings on different models + + CHIP and Raspberry Pi values are all digital: 0 (LOW) and 255 (HIGH) + + Note that to have access to gpio pins, you may need to run pico8 as root: + + sudo pico8 + + A simple program to blink any LEDs attached on and off: + + t = 0 + function _draw() + cls(5) + for i=0,7 do + val = 0 + if (t % 2 < 1) val = 255 + poke(0x5f80 + i, val) + circfill(20+i*12,64,4,val/11) + end + t += 0.1 + end + + :: HTML + + Cartridges exported as HTML / .js use a global array of integers (pico8_gpio) to + represent gpio pins. The shell HTML should define the array: + + var pico8_gpio = Array(128); + + +-------------------------------------------------------------------------------------------- + Mouse and Keyboard Input +-------------------------------------------------------------------------------------------- + + // experimental! The html implementation is still limited & buggy. + + Mouse and keyboard input can be achieved by enabling devkit input mode: + + POKE(0x5F2D, 1) + + Note that not every PICO-8 will have a keyboard or mouse attached to it, so when posting + carts to the Lexaloffle BBS, it is encouraged to make keyboard and/or mouse control + optional and off by default, if possible. When devkit input mode is enabled, a message is + displayed to BBS users warning them that the program is expecting input beyond the + standard 6-button controllers. + + The state of the mouse and keyboard can be found in stat(x): + + STAT(30) -- (Boolean) True when a key + STAT(31) -- (String) character returned by keyboard + STAT(32) -- Mouse X + STAT(33) -- Mouse Y + STAT(34) -- Mouse buttons (bitfield) + STAT(36) -- Mouse wheel event + + +-------------------------------------------------------------------------------------------- + Additional Lua Features +-------------------------------------------------------------------------------------------- + + PICO-8 also exposes 2 features of Lua for advanced users: Metatables and Coroutines. + + For more information, please refer to the Lua 5.2 manual. + + :: Metatables + + Metatables can be used to define the behaviour of objects under particular operations. + For example, to use tables to represent 2D vectors that can be added together, the + '+' operator is redefined by defining an "__add" function for the metatable: + + vec2d={ + __add=function(a,b) + return {x=(a.x+b.x), y=(a.y+b.y)} + end + } + + v1={x=2,y=9} setmetatable(v1, vec2d) + v2={x=1,y=5} setmetatable(v2, vec2d) + v3 = v1+v2 + print(v3.x..","..v3.y) -- 3,14 + + + setmetatable t, m + + set table t metatable to m + + getmetatable t + + return the current metatable for table t, or nil if none is set + + :: Coroutines + + Coroutines offer a way to run different parts of a program in a somewhat concurrent + way, similar to threads. A function can be called as a coroutine, suspended with + yield() any number of times, and then resumed again at the same point. + + function hey() + print("doing something") + yield() + print("doing the next thing") + yield() + print("finished") + end + + c = cocreate(hey) + for i=1,3 do coresume(c) end + + + cocreate f + + Create a coroutine for function f. + + coresume c [p0 p1 ..] + + Run or continue the coroutine c. Parameters p0, p1.. are passed to the + coroutine's function. + + Returns true if the coroutine completes without any errors + Returns false, error_message if there is an error. + + ** Runtime errors that occur inside coroutines do not cause the program + to stop running. It is a good idea to wrap coresume() inside an assert(). + If the assert fails, it will print the error message generated by + coresume. + + assert(coresume(c)) + + + costatus c + + Return the status of coroutine c as a string: + "running" + "suspended" + "dead" + + yield + + Suspend execution and return to the caller. + + +-------------------------------------------------------------------------------------------- + VERSION HISTORY +-------------------------------------------------------------------------------------------- + + v0.1.11g + + Added: CTRL-C to copy contents of commandline + Added: stat(100..102) for current breadcrumb label, bbs cart id, and hostname (web) + Added: content_filter in config.txt + Added: Cartverse cart id support (not live server-side yet though) + Fixed: Tab preview does not show on mouseover + Fixed: Can't paste uppercase characters into commandline + Fixed: Preprocessor can't handle glyphs in form: "♥.x += 1" + Fixed: Unsaved changes sometimes reported when filename is not set + Fixed: Pause menu doesn't open inside infinite loop inside _draw + Fixed: load() crashes when "parameter string" parameter is not a string + Fixed: cstore(),reload() crash when external cart filename is not a string + Fixed: printh(str, "@clip") fails for glyph characters in str + + + v0.1.11f + + Fixed: Pause menu doesn't open inside an infinite loop + Fixed: Binary and hex string digits outside of 0xffff.ffff alter result + + + v0.1.11e + + Added: stat(30..31) for devkit keyboard input + Added: extcmd("pause") extcmd("reset") extcmd("breadcrumb") + Added: lshr(), ceil(), rotl(), rotr(), peek4(), poke4() + Added: stat(12..15) to grab the position of the pause menu (x0,y0,y1,y1) + Added: DPAD game controller buttons mapped to LRUD + Added: CTRL-click on song navigator to scroll by 4 patterns + Added: Can type and paste glyphs in commandline + Added: Notification when CTRL-R fails to reload because of unsaved changes + Added: Notification when code automatically converted to lower-case + Added: INFO() checks for "external changes" (e.g. when using a separate text editor) + Added: .p8.png format can be used with cstore() and carts bundled in multicarts + Added: Can optionally set fill pattern using colour parameter + Changed: Glyphs can be used as variable names + Changed: Glyphs stored in clipboard and .p8 format as roughly corresponding unicode + Changed: .p8 format skips storing tailing rows of data that match default state + Changed/Fixed: shr(x,n) is now equivalent to calling shr(x,1) n times when n >= 32 + Fixed: Error message and stack trace line numbers 0 or slightly out + Fixed: Unclosed block error navigates cursor to rather than start of block + Fixed: Exported binaries can load carts outside of bundle + Fixed: BBS cart loaded from a local cart loses data cstore()ed during previous run + Fixed: btn() returns same as btnp() + Fixed: btnp(6) always returns false + Fixed: Missing mask pixels in cart download animation frame + Fixed: Crash when try to load a directory as a cart + Fixed: Sometimes cursor position set by keyboard mouse emulation in code editor + + + v0.1.11d + + Added: t() aliased to time() + Fixed: time() always returns 0 when there is no _update function + Fixed: (raspi) Keyboard stops responding after pressing CTRL-F, CTRL-Z + Fixed: (raspi) Double keypresses in sound editor when entering notes + Fixed: stat(6) pads parameter string with spaces + + + v0.1.11c + + Added: Local and UT time queries using stat() + Added: host_framerate_control (config.txt) to improve performance on slower machines and web + Added: Control over cpu usage when running in background (-background_sleep_ms / config.txt) + Added: Windows icon in exported exe + Added: F11 to toggle fullscreen + Added: export -c switch to indicate transparent icon colour + Added: show_backup_messages (config.txt) to turn off backup notifications + Added: SFX instruments documentation in pico8.txt + Added: Error message when trying to export carts with code size over the compressed limit + Changed: If config.txt is not found, the same directory as the executable is searched + Changed: If sdl_controllers.txt exists in the same directory as the executeable, it is processed first + Changed: Shorthand if () statements must be written on a single line + Fixed: reload() from bundled, non-primary cart in exported html multicart reads only original data + Fixed: Exported binaries wrongly observe F7 (capture label) + Fixed: Loading carts from earlier versions alters SFX data not intended for audio + Fixed: Old version of fill patterns documentation near end of pico8.txt + Fixed: 'backed up unsaved changes' message displayed during runtime for cstored() carts + Fixed: PICO-8 runs too slowly when in background (new default background_sleep_ms: 20) + Fixed: Saving screenshots and videos from exported binaries are named 0_* + Fixed: Compressed size limit warning on save doesn't mention exported carts + Fixed: btn(), btnp() don't work in infinite loops + Fixed: btnp() timing inconsistent between 30fps / 60fps / during frame-skipping / with no _update + Fixed: Can't move between channels while music is playing in song mode + + + v0.1.11b + + Fixed: Preprocessor bug regressions: "if (..) or", "a.b -= c - d" + Fixed: Crash when pressing menu button on an empty favourites list + + + v0.1.11 + + Added: Binary exporters (Windows, Linux, Mac OSX) + Added: Code tabs + Added: Splore cart menu + Added: Fill patterns + Added: Custom sfx instruments + Added: load("#1234") to load [and run] a BBS cart + Added: -x switch // execute a cart headless, for making command-line tools + Added: Compressed size display and limit warning lights in code editor + Added: CTRL-L to jump to a line number in code editor + Added: numbers can be written in binary: 0b10100010 + Added: tostr(), tonum() + Added: extcmd(): audio_rec, audio_end to record all audio output. + Added: ls() returns a list of local files if called while running + Added: getmetatable() + Added: coroutine error reporting // wrap coresume() in assert() + Added: sfx() can take a 4th parameter: number of notes to play + Added: Live sfx and music editing + better navigation controls + Added: Transpose selected sfx notes relative to C by entering a note w/ SHIFT held + Added: Insert and delete sfx rows with enter and backspace + Added: Hidden note data is shown in sfx editor when relevant (slide, arps) + Added: Warning displayed when unsaved changes backed up + Added: Separate animation for downloading vs. loading a cart + Added: export -p switch to supply a customized html template + Added: Mousewheel when devkit mouse enabled: stat(36) // not supported in web + Added: < > to change zoom level in gfx and map editors + Changed: Rebalanced / fixed api cpu costs + Changed: Screenshot and gif filenames based on current cart if available + Changed: add() returns the added object + Changed: removed global hpf on audio + Changed: (sfx) can slide to volume 0 + Changed: removed master low pass filter + Changed: assert() can take an optional error_message parameter + Changed: ? (shorthand for print()) can be prefixed by whitespace + Changed: shl(), shr() return 0 if second parameter >= 32 + Changed: Automatically drop down to software blitting mode if opengl fails + Changed: Lua memory limit set to 2MB (was 1MB) + Changed: Some options (-width, -show_fps) apply only to the session; not saved to config.txt + Updated: Internal game controller mappings from SDL_GameControllerDB + Fixed: Pops & clicks in audio when switching between playing SFX + Fixed: Crash in audio mixer because of bad locking + Fixed: Crash when loading .p8 files with more than 64k of code + Fixed: Indexing of sparse tables fails after removing n/2 elements + Fixed: Calling stat() inside an infinite loop crashes + Fixed: Resetting cartridge corrupts cartridge data in range 0x5e00..0x5eff + Fixed: Can not recover from a cart error caused by glitchy data on resetting + Fixed: String->negative number conversion off by 0x0.0001 (-1 --> 0xffff0001) + Fixed: Crash when running cart closed to 64k char limit + Fixed: Cursor can't move to the right of last character in code editor + Fixed: Missing highlighted keywords: in, add, del, menuitem + Fixed: Preprocessor bugs: "a+=1+2\n*3", "a+=(1)ba=42", "a[(1)]+=1" + Fixed: Preprocessor performs replacements inside a string printed with ? + Fixed: Display freezes when terminating a program running at >100% cpu + Fixed: Quick-running (CTRL-R) clobbers some editor state (e.g. current sprite page) + Fixed: Loading a .p8 file with a future version reports a generic failure + Fixed: alt-enter to toggle fullscreen also triggers pause menu + Fixed: Splore scrolling jumps around when list gets too long + + + v0.1.10c + + Fixed: atan flips sign for very negative values of x close to zero + + + v0.1.10b + Fixed: HTML exporter carts don't run + Fixed: HTML export 60fps support broken + Fixed: HTML export when path has a space in it (common for OSX) + Fixed: atan2 ignores sign of y + Fixed: (Raspberry Pi) Crash when access gpio not as root + + + v0.1.10 + + Added: Multi-cart export in html + Added: Cart reset glitch + Added: Demo carts: bounce, sort + Added: .p8 format can now store cart labels + Added: Splore navigation keys: pageup/down, home, end + Added: Splore usage hint shown on empty favourites list + Added: Warning on boot when data folder is read-only or can't be created + Added: Pressing tab with code selected indents those lines (shift-tab to un-indent) + Added: Double click word to select it + Added: Trigger screenshot/video/label capture from inside program: extcmd() + Changed: CTRL+left/right in code editor skips to end of word or span of non-whitespace + Changed: When a cart terminates from splore, button press is required to continue + Changed: load("@clip") can only be called from commandline (security) + Fixed: Can over-allocate host memory if exceed it within one frame + Fixed: atan2(-1, -32768) crash, and error for small values of dy + Fixed: (Web) using cstore() on self causes unloadable cart (bug introduced in 0.1.8?) + Fixed: (web) Pressing ctrl-v crashes the player (should do nothing) + Fixed: (Raspberry Pi) WiringPi library required in static build + Fixed: (Raspberry Pi) Crash on exit when launching via desktop icon + Fixed: (Raspberry Pi) keyboard input broken (observed on raspi2s) + + + v0.1.9b + + Added: Alternative function key mapping: ctrl-6..9 for F6..F9 + Added: Alternative glyph entry method: (ctrl-k) to toggle glyph mode + Changed: Enter glyphs with shift a..z, but can be disabled in config.txt + Changed: Increased emscripten ram to 128MB (some carts at risk of running out) + Fixed: Crash when window size is tiny or minified + Fixed: Crash on toggling fullscreen mode + Fixed: printh can write files outside filetree (security issue) + Fixed: show_fps (can also now be toggled with ctrl-1) + Fixed: Shorthand if/then syntax error when using the form: (functionname)(param) + Fixed: log.txt not saved in path specified by -home switch + Fixed: Default application data folder created even when -home specified + Fixed: Missing dynamic builds (pico8_dyn) from linux archives + Fixed: Removed unneeded RPATH from linux binaries + Fixed: export foo%d.wav fails to write multiple files + + v0.1.9 + + Added: Copy and paste sprites and whole cartridges directly to BBS posts + Added: JAM category in splore + Added: GPIO support for Raspberry Pi + Added: Read clipboard using stat(4) after user presses CTRL-V + Added: printh() can optionally write to a file or the host clipboard + Added: Editor tool information and tips shown on mouseover + Added: Set desktop path with -desktop (screenshots and gifs are saved here) + Added: Warning on saving .p8 when compressed code size exceeds .p8.png limit + Added: Alternative editor colours // config.txt: gui_theme 1 + Added: Dotted line every 8 rows in song view + Added: -screenshot_scale (default: 3) and -gif_scale (default: 2) + Added: Can use ctrl-up, ctrl-down to jump to start and end of code + Added: CTRL-M to mute/unmute sound + Added: HTML5-exported carts support 60fps + Added: Timeout switch for splore downloads: -timeout + Changed: Glyph characters typed with alt + a..z + Changed: stat(0) does not include allocations waiting to be garbage collected + Changed: Unfiltered screen stretching at integer scales by default + Changed: Removed -aspect and -scale settings (use draw_rect instead) + Fixed: -home has no effect under Windows + Fixed: Sometimes frame skipping starts before CPU usage has reached 100% + Fixed: Double-speed BTNP() timing in 60fps mode + Fixed: Exported HTML fails when _update60 is used instead of _update + Fixed: Can't copy and paste button glyphs + Fixed: Lines containing glyphs do not scroll far enough horizontally + Fixed: Loading .p8 renamed as .p8.png from splore freezes + Fixed: Bucketfill in map doesn't sync to shared memory + Fixed: fset fails when de-setting flags + Fixed: Syntax error when beginning with the form: IF (..) [OR|AND]\n + Fixed: cls() costs twice as much cpu as it should + Fixed: wav file exporter missing some data / writing truncated buffers + Fixed: Entering new notes in song view doesn't observe current volume, instrument + Fixed: alt-tab sometimes generates alt character text entry event + Fixed: Resuming a cancelled download in splore causes crash + Fixed: Controller attributes in log.txt always shown as -1 + + + v0.1.8 + + Added: 60fps support + Added: Music exporter + Added: Custom GIF length (maximum 120 seconds) + Added: -,+ to navigate sprite tabs, sfx, music patterns + Added: sfx editor: navigate with home, end, pageup/down, mousewheel + Added: <, > to modify sfx speed, or click and drag + Added: Middle mouse button to pan around spritesheet / map + Added: Shortcut command for splore: S + Added: Pre-installed selection of BBS cart (use INSTALL_GAMES) + Added: Warning when saving .p8.png with no label + Added: (OSX) logging to ~/Library/Logs (viewable with Console.app) + Added: -pixel_perfect switch (on by default) + Added: -draw_rect switch + Changed: Can not CTRL-S save over a loaded bbs cart + Changed: Only .p8 files listed by dir() and by splore + Changed: Command history increased to 256 + Changed: exit() / shutdown() have no effect while running cart + Fixed: Memory usage (stat(0)) inconsistent across host platforms + Fixed: Spinny disks shows when reloading current cart with load() + Fixed: GIF saver does not respect 64x64 / mirrored modes + Fixed: Miscellaneous multi-line comments / strings issues + Fixed: Empty map cels cost cpu in mapdraw() + Fixed: mapdraw() slowdown when drawing bottom half of map + Fixed: preprocess changes semantics when += and : operators on same line + Fixed: Identifiers starting with underscore counted as extra token + Fixed: Saving .png exceeding compressed code limit fails silently + Fixed: Right-clicking a sprite does not set the currently edited sprite + Fixed: (Windows) extra space added to pasted lines + Fixed: spr() expensive when drawn with low negative coordinates + Fixed: pipe character identical to colon character + Fixed: (Raspberry Pi) shift key appends a character when entering text + Fixed: Editor mode buttons are still clickable during cart runtime + Fixed: When loading a .p8.png file, label is reset and needs to be re-captured + Fixed: export() does not report failure + Fixed: mset()'d changes in shared memory not readable via peek() / sget() + Fixed: cstore() saving edited code + Fixed: audio pop between patterns during music playback + + v0.1.7 + + Added: menuitem() + Added: button glyphs in code (shift-L, R, U, D, X, O) + Added: Customisable data directory (e.g. pico8 -home mydata) + Added: Web gpio pins: read and write pico8_gpio[] in javscript + Fixed: SPLORE search doesn't reset + Fixed: Splore skipping 33rd cart listing after loading more items + Fixed: Crash when selecting a local binary file in splore + Fixed: Semicolon can't be used as a list or statement separator + Fixed: Exported html can not cstore self + + + v0.1.6 + + Added: SPLORE local & bbs cartridge explorer + Added: setmetatable(), cocreate(), coresume(), costatus(), yield() + Added: Spinning cart icon to show when a cart is swapped / written to + Added: Permanent storage when carts played in a browser + Added: Adjustable aspect ratio (-aspect 420 for 1:1) + Changed: Lua memory limit: 1024k (was 512k) + Changed: Music channel now resumes after being clobbered by an sfx + Changed: Arpeggios double speed when SFX speed <= 8 + Changed: Exceeding compressed code limit does not block saving in .p8 format + Changed: spr() half as expensive, to be consistent with map() + Changed: Fractional hex number notation: 0x0.3 == 0x0.3000, (was 0x0.0003) + Changed: : operator doesn't count as an extra token (same as .) + Changed: cstore() writes directly to disk + Changed: cstore(), reload() return number of bytes read / written + Changed: save() while running does nothing. (use cstore() instead) + Changed: load() while running loads and runs the specified cartridge + Fixed: Small pops in audio mixer caused by sound wave discontinuities + Fixed: HTML5-exported sound clicks badly under Chrome + Fixed: Display palette is not oberserved when exporting GIFs + Fixed: Rapid keypresses causes duplicate readings in tracker & text editor + Fixed: += inside comments breaks preprocessor + Fixed: sspr() cpu cost the same when clipped + Fixed: cartdata() with bad parameters crashes + Fixed: EXPORT from commandline can not be used without brackets and quotes + + + v0.1.5 + + Added: Raspberry Pi Build + Added: Keyboard configuration for player buttons (KEYCONFIG) + Added: Music tracker select / copy / paste + Added: Single-level undo in audio tools + Added: Live preview of frequencies in sound editor + Fixed: Command history extends past last reboot + Fixed: Sfx exporter broken + Fixed: Slashes at end of path resolve to double slashes + Fixed: Load cart from commandline under Windows + + + v0.1.4d + v0.1.4c + + Fixed: International character entry inserting extra characters + Fixed: Lines with tabs have broken cursor placement and display boundary + + v0.1.4b + + Fixed: OSX command-key combinations broken + + v0.1.4 + + Added: spritesheet importing and exporting with import("blah.png"), export("blah.png") + Added: sfx exporting with export("blah%d.wav") + Added: External cartridge parameter for reload() and cstore() + Added: Persistent cartridge data mapped to 0x5e00 + Added: Click token limit to toggle token & char limit display + Added: assert(), type() + Added: P to pause + Changed: code char limit: 64k (was 32k) + Changed: local declarations and semicolons not counted as tokens + Changed: Pairs of brackets and block delimitations count as one token + Changed: Only _update() or _draw() need to exist to enter main loop + Changed: Allow forward-slash in code editor + Changed: info() reports current (last loaded or saved) filename + Changed: html5 version compiled with NO_DYNAMIC_EXECUTION + Changed: can only cstore up to 64 different files in one session + Changed: load() automatically copies data section of cart to base ram + Fixed: Shift-drag-copy sprites -> paste only pastes 1x1 + Fixed: ".." should count as one token + Fixed: Tracker displaying D instead of . + Fixed: Multi-line comments + Fixed: Crash on run when code close to char limit + Fixed: When over token limit, can not run any command + Fixed: Unused high bits in SFX section not saved in .p8 format + Fixed: Camera position memory mapping out of sync + Fixed: pico8.txt link broken in windows installer + Fixed: print() crashes when parameter is not a string or numbers + Fixed: Multi-line strings & escape chars mess up tokenizer and print() + Fixed: Joystick not responding when left stick is up to the left + Fixed: Alt-F4 saves screenshot before quitting + Fixed: Sprite editor mode button doesn't show fullscreen mode + Fixed: -sound parameter not working in html5 version + + + v0.1.3 + + Added: paste into commandline + Fixed: lua standard libraries accessible + Fixed: command-line loading doesn't work + Fixed: music pattern finished too early when all tracks set to looping + Fixed: peek()ing odd bytes in sfx address space masks bit 7 + Fixed: cstore and reload from code space should have no effect + + v0.1.2 + + Added: html5 cartridge exporter + Added: Cartridge save data (64 fixed point numbers) + Added: 8-player input + Added: Demo carts: COLLIDE and BUTTERFLY + Added: Command-line parameters // load cart, -run, settings + Added: Alternative function keys (F6..F9 aliased as F1..F4) + Added: pairs() + Added: printh() for debugging + Added: Tab completion for filenames in console + Added: stack trace on runtime error + Changed: music pattern length taken to be first non-looping channel's length + Changed: noise instrument (6) has low frequency white noise scaled by volume + Changed: screenshot captures whole window contents at display resolution + Changed: del() moves remaining items up one index to maintain a packed table + Changed: add(),del(),count(),all() no longer store extra fields + Changed: removed count() from docs -- now just a legacy function. Use # operator instead. + Changed: cursor only blinks while window is active + Changed: peek(), poke() and binary operations (band()..) have no function call overhead + Changed: yellow slightly warmer + Changed: No camera snapping after pan in map mode + Fixed: sqrt() crashing for 0 or >= 32761 + Fixed: Semi-colon characters in text editor + Fixed: Long lines split when saving in .p8 format + Fixed: pget() does not respect camera position + Fixed: Error message when peeking or poking outside of legal address space + Fixed: Search replace colour fills one pixel outside of selected region + Fixed: Playing an empty music pattern breaks subsequent music playback + Fixed: Invalid sfx editing state on startup + Fixed: Painting instruments values in frequency view also sets volumes + Fixed: Inconsistent gif recording speeds + Fixed: Unmapped joystick support + Fixed: Compressed code size sometimes larger than uncompressed + Fixed: mid() fails when first argument is not smallest + Fixed: Scroll wheel changes sprite/map zoom while in code editor + Fixed: CTRL-R (quick-run) drawing over current line in command mode + Fixed: Label capture (F7) does not respect screen palette state + Fixed: Syntax highlighting of api functions and hex numbers + Fixed: Looping to 0 with negative step finishes at 1 + Fixed: nil values printed as false instead of nil + Fixed: Hexadecimal fractional parts + Fixed: btnp() unresponsive when skipping frames + Fixed: Editing mode is lost when using ctrl-r to run + Fixed: Tracker note entry keys mapped, messing up piano-like layout + Fixed: Shared gfx/map memory out of sync after some editor operations + Fixed: Alt-gr character entry + Fixed: Can map display palette to entries >= 16 using poke() + Fixed: Using shift to select in code editor has wrong selection range + Fixed: Dragging above top of text causes selection to flip to end + Fixed: Duplicate at end of file listing + + + v0.1.1 + + Added: Token-based code limiting (8192 tokens, 32k ascii text) + Added: Freeform move, pan and selection in sprite and map editors + Added: Flood-fill tool (sprite and map) + Added: .GIF saver + Added: CTRL-Stamp to stamp with transparency + Added: Single-step undo for map and sprites + Added: 2x2 brush + Added: sqrt(), atan2() + Added: CTRL-S to quick-save + Added: CTRL-R reloads .p8 file and runs (useful for external text editing) + Added: Automatic backups on overwriting or quitting without saving + Added: Scroll wheel zooms in sprite editor + Added: Customisable resolution // e.g. pico8 -width 580 + Added: Strings highlighted as green + Added: ALT-click can optionally simulate right click (see config.txt) + Added: palt() to control transparency for spr(), sspr() + Added: info() + Changed: load() tries adding .p8.png, .png if file doesn't exist + Changed: Draw operations apply only to selection when active + Changed: Move operations (cursors) apply to selection if present + Changed: Removed time() + Changed: Random seed is random on cart startup + Changed: api functions never read directly from cart rom + Changed: sspr() can take negative values for dw, dh + Fixed: Sparse table indexing with integers fails + Fixed: Assignment operators and shortform if-then-else failing + Fixed: sspr() failed when w0 == 128 + Fixed: Circle drawing broken when camera not (0,0) + Fixed: CPU hogging + Fixed: Noise instrument clobbers rnd() sequence + Fixed: Audio system not resetting on program reset + Fixed: % operator sometimes wrong for negative values + Fixed: Length operator (#) + Fixed: Power operator (^) + Fixed: Line clipping bug on right and bottom edges + Fixed: print() precision for whole numbers + Fixed: print() broken for negative y values + Fixed: tokenization and keyword highlighting + Fixed: sprite properties not copied/pasted + Fixed: Only sfx 0..32 could be used as music patterns + Fixed: Saving and loading a .p8 file adds newline to end of code + Fixed: Drag selection to left margin in code editor -> selects all + + + v0.1.0 + + Added: demo cart: hello.p8 (use install_demos) + Added: CTRL-R from anywhere to run cart or restart cart + Added: use a,s to select colour in gfx editor + Added: consistent operation cpu costs + Added: btn(), btnp() with no arguments returns bitfield + Added: fget(id) returns bitfield of that sprite's flags + Changed: renamed mapdraw() to map() for consistency + Changed: default sleep time is 5ms (better cpu consumption for laptops) + Fixed: memory limiter + Fixed: wonky line and circle drawing + Fixed: shift-click volume in sfx editor to set all + Fixed: number formatting is now never in scientific notation + Fixed: clipped error messages in console + Fixed: text undo stores rollback points when chaning line number + Fixed: print(str) carriage returns to previous x + + + v0.0.5 + + Added: help() + Added: Ctrl+F / Ctrl+G to search for text, repeat search + Added: del key in code editor + Added: Short-hand single-line IF statements + Added: Unary operators += -= /= *= %= + Added: srand(), time(), added rnd() to docs + Added: Ctrl+D to duplicate line + Added: interactive ls() for multi-page file listings + Added: band() bor() bxor() bnot() shl() shr() + Added: runtime error line number + Added: dir() (aliased to ls()) + Changed: print() only autoscrolls when called with no parameters + Changed: alt+up/down to skip between function definitions (was ctrl) + Changed: sspr() dw, dh defaults to sw, sh + Fixed: Load crashes on files that are not .p8 format or directories + Fixed: Misc editor cursor position glitches + Fixed: Crash when syntax error occurs before viewing code + Fixed: Broken newlines after rebooting + Fixed: mkdir() called with no parameters creating "(null)" directory + Fixed: scrolling past top of code with scrollwheel + Fixed: alt-f4 to fastquit + + + v0.0.4 + + Added: Jelpi demo cart + Added: Internal carts // use install_demos() + Added: Joystick support + Added: Undo/redo in code editor + Added: Scroll wheel in code editor + Added: LCTRL + UP/DOWN to navigate functions in code editor + Added: LALT + LEFT/RIGHT to switch editing modes + Added: btnp() + Added: Release looping sample (a in editor , sfx(-2, channel) in code) + Changed: Music stops when pausing program execution + Changed: Allow 8 settable sprite flags + Changed: Made noise instrument more bassy + Fixed: Home, end keys + Fixed: Sprite flags 4,5 not saved + Fixed: mset() discarding 4 high bits + Fixed: Crash when highlighting long strings + + + v0.0.3 + + Added: Palette mapping type 1 (on display) + Added: Collections can be initialized with c={1,2,..} + Added: holdframe() // used automatically by _draw(), update() + Added: Sprite selections and operations across selections + Added: Map selection and stamp tool + Added: Immediate mode screen buffer preserved while switching views + Added: Channel mask for music playback + Added: Memory mapping for live sound data + Added: .png cart format + Added: Sprite navigation by keyboard (-, +) + Fixed: Strict 4-channel sound + Fixed: Automatic sfx channel selection (channel index: -1) + + + v0.0.2 + + Added: Command history + Added: P2 keys + Added: Boot sequence + Added: Windows, 64-bit linux builds + Added: CPU cost of internal api functions + Added: Separate song channel index and mute status + Added: Memory mapping + Added: Search/replace colour in sprite editor + Added: Copy/paste sprites and map regions + Improved: Immediate mode command editing + Improved: Editor cursor behaviour + Fixed: Automatic audio channel selection + + + v0.0.1 + + First Alpha + + + diff --git a/celeste/bin/pico-8/windows/SDL2.dll b/celeste/bin/pico-8/windows/SDL2.dll new file mode 100755 index 0000000..15ad52e Binary files /dev/null and b/celeste/bin/pico-8/windows/SDL2.dll differ diff --git a/celeste/bin/pico-8/windows/pico8.dat b/celeste/bin/pico-8/windows/pico8.dat new file mode 100755 index 0000000..200075c Binary files /dev/null and b/celeste/bin/pico-8/windows/pico8.dat differ diff --git a/celeste/bin/pico-8/windows/pico8.exe b/celeste/bin/pico-8/windows/pico8.exe new file mode 100755 index 0000000..423a782 Binary files /dev/null and b/celeste/bin/pico-8/windows/pico8.exe differ