diff --git a/.gitignore b/.gitignore index 6fd0a37..3f10bf6 100644 --- a/.gitignore +++ b/.gitignore @@ -39,3 +39,8 @@ luac.out *.x86_64 *.hex +# Playdate +*.pdx +*.psd +Support/audio +*.sublime-* diff --git a/README.md b/README.md index a904999..4c3cef2 100644 --- a/README.md +++ b/README.md @@ -1,2 +1,5 @@ -# celeste -A port of Celeste Classic to Playdate +# Celeste + +A port of Celeste Classic from PICO-8 to Playdate. + +[Celeste Classic](https://mattmakesgames.itch.io/celesteclassic) is an original game on PICO-8 by Noel Berry and Matt Thorson. \ No newline at end of file diff --git a/Source/Assets/pico.fnt b/Source/Assets/pico.fnt new file mode 100644 index 0000000..28b9e07 --- /dev/null +++ b/Source/Assets/pico.fnt @@ -0,0 +1,104 @@ +--metrics={"baseline":2,"xHeight":3,"capHeight":0,"pairs":{},"left":[],"right":[]} +datalen=900 +data=iVBORw0KGgoAAAANSUhEUgAAAB4AAAAyCAYAAABLXmvvAAACaElEQVRYR61Xi27CMBCD//9oRisSOT7blzCQpnVpOd/D9nXPx+Pxev/w52nOx3Pu/nV+fVTMBWMEUL/Hg1cQDojAeG9c43eva37+lYAx664DqmOx8g5YVaAqHEliPAQu56eVjLZ1c3SznudcEbbMEUQlmwrge/ffHXAhxSczbje2enTDjSQCd9U6YMlgoYopE9fiX1a8ENDpLhnFLiETwaaOhXndR84oTnTLkp2BHRmGYyniIHAaB+t7FhOZBwxm29wBc8nd4B2wa/UOMM94abkjipwLlOCAkRdI3OL7jnmK1btVsgdIk8LKcJWpik+AlcEsZ9xqBuzA3EhUQYsEeQ67wIqxikzcxSndxFq3T9UM06sOz/iWppKTczF3jkazq5ICzLTn5aEk4sCGtLDd0bn4wa4DioDubMZS/UcNq4qVfSIfVKJFy7+aMRuOU8dMQOk4kYhlNOXxuZE22pKM0nGaaXq3UtxQHS1yYhaqBL4FLklJAw8lnwA727QGwnOa2qOEbBvfzzk/mLFdxSgZboD7J04Rjck4E1LASaepSsdwPI8Vs/d2JuLuI1nLEvlvBd0YOH6pOFWZDEWuPDATNeOb7cq5Tvbtzvc58QU4vRAk7br3bdZw2dlpfXV6VsHVsmBW36TjLcJMTJ2QAT/mcVSxcyhFLmSrNQnhdAurlRNxsFGdJMrVOmGT7gWwkEsFVxzgzqRnRqKWXEroCSC111VfXgScJLrKsENMUutYYyycXVel2rG8AtVKLDxyckLTUNeoV2ep8fwbYLVYjsETsLqHo+AFcQTugifrQ3c7AnPm0BEtOdhxAn8WJ3giA/0TGQAAAABJRU5ErkJggg== +width=3 +height=5 + +tracking=1 + +0 3 +1 3 +2 3 +3 3 +4 3 +5 3 +6 3 +7 3 +8 3 +9 3 +space 3 +� 3 +A 3 +B 3 +C 3 +D 3 +E 3 +F 3 +G 3 +H 3 +I 3 +J 3 +K 3 +L 3 +M 3 +N 3 +O 3 +P 3 +Q 3 +R 3 +S 3 +T 3 +U 3 +V 3 +W 3 +X 3 +Y 3 +Z 3 +: 2 +; 2 +! 2 += 3 +- 3 ++ 3 +~ 3 +@ 3 +# 3 +$ 3 +% 3 +^ 3 +? 3 +. 2 +_ 3 +] 3 +[ 2 +( 2 +) 3 +& 3 +' 2 +* 3 +, 2 +/ 3 +< 2 +> 3 +\ 3 +` 2 +| 2 +{ 3 +} 3 +a 3 +b 3 +c 3 +d 3 +e 3 +f 3 +g 3 +h 3 +i 3 +j 3 +k 3 +l 3 +m 3 +n 3 +o 3 +p 3 +q 3 +r 3 +s 3 +t 3 +u 3 +v 3 +w 3 +x 3 +y 3 +z 3 + diff --git a/Source/Assets/sprites-table-8-8.png b/Source/Assets/sprites-table-8-8.png new file mode 100644 index 0000000..41a88b8 Binary files /dev/null and b/Source/Assets/sprites-table-8-8.png differ diff --git a/Source/Scripts/celeste.lua b/Source/Scripts/celeste.lua new file mode 100644 index 0000000..f980b01 --- /dev/null +++ b/Source/Scripts/celeste.lua @@ -0,0 +1,1431 @@ +-- 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=playdate.kButtonLeft +k_right=playdate.kButtonRight +k_up=playdate.kButtonUp +k_down=playdate.kButtonDown +k_jump=playdate.kButtonA +k_dash=playdate.kButtonB + +-- 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) then return end + + 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) + 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 + + 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 + previousColor = playdate.graphics.getColor() + playdate.graphics.setColor(playdate.graphics.kColorWhite) + 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 + playdate.graphics.setColor(previousColor) + + -- 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 + previousColor = playdate.graphics.getColor() + playdate.graphics.setColor(playdate.graphics.kColorWhite) + 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) + playdate.graphics.setColor(previousColor) + + -- 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("a+b",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 \ No newline at end of file diff --git a/Source/Scripts/map.lua b/Source/Scripts/map.lua new file mode 100644 index 0000000..a025d67 --- /dev/null +++ b/Source/Scripts/map.lua @@ -0,0 +1,66 @@ +mapData = { + 0x23, 0x31, 0x25, 0x25, 0x48, 0x25, 0x25, 0x32, 0x32, 0x32, 0x32, 0x32, 0x33, 0x00, 0x00, 0x24, 0x25, 0x26, 0x24, 0x25, 0x25, 0x26, 0x31, 0x32, 0x32, 0x32, 0x25, 0x26, 0x28, 0x28, 0x28, 0x24, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x32, 0x33, 0x28, 0x38, 0x28, 0x28, 0x31, 0x25, 0x25, 0x25, 0x32, 0x32, 0x32, 0x32, 0x33, 0x00, 0x00, 0x00, 0x31, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x33, 0x00, 0x00, 0x00, 0x24, 0x32, 0x32, 0x32, 0x33, 0x31, 0x32, 0x32, 0x32, 0x25, 0x25, 0x25, 0x25, 0x25, 0x48, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x26, 0x28, 0x28, 0x24, 0x25, 0x25, 0x48, 0x25, 0x25, 0x25, 0x26, 0x28, 0x28, 0x28, 0x28, 0x24, 0x25, 0x48, 0x25, 0x25, 0x25, 0x26, 0x28, 0x28, 0x28, 0x28, 0x31, 0x32, 0x32, 0x32, 0x25, 0x48, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x23, 0x31, 0x32, 0x32, 0x32, 0x33, 0x29, 0x00, 0x00, 0x28, 0x29, 0x00, 0x00, 0x00, 0x24, 0x25, 0x26, 0x31, 0x32, 0x32, 0x33, 0x28, 0x28, 0x00, 0x28, 0x24, 0x26, 0x2a, 0x10, 0x28, 0x24, 0x25, 0x48, 0x25, 0x25, 0x25, 0x26, 0x00, 0x2a, 0x28, 0x28, 0x29, 0x28, 0x10, 0x24, 0x48, 0x25, 0x28, 0x28, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x28, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x10, 0x00, 0x00, 0x00, 0x37, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x31, 0x48, 0x25, 0x25, 0x25, 0x25, 0x25, 0x48, 0x25, 0x25, 0x32, 0x32, 0x32, 0x33, 0x28, 0x28, 0x24, 0x25, 0x25, 0x25, 0x48, 0x25, 0x32, 0x33, 0x38, 0x28, 0x2a, 0x28, 0x31, 0x32, 0x25, 0x25, 0x48, 0x25, 0x26, 0x28, 0x38, 0x28, 0x28, 0x28, 0x2a, 0x2a, 0x28, 0x31, 0x32, 0x32, 0x32, 0x32, 0x25, 0x25, + 0x25, 0x25, 0x23, 0x20, 0x10, 0x28, 0x38, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x3d, 0x24, 0x25, 0x25, 0x23, 0x20, 0x10, 0x28, 0x29, 0x29, 0x00, 0x28, 0x24, 0x26, 0x00, 0x3a, 0x38, 0x24, 0x25, 0x25, 0x25, 0x48, 0x25, 0x33, 0x00, 0x00, 0x29, 0x00, 0x00, 0x2a, 0x00, 0x31, 0x25, 0x25, 0x28, 0x38, 0x29, 0x00, 0x00, 0x3a, 0x67, 0x68, 0x38, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x28, 0x39, 0x3e, 0x00, 0x3a, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x24, 0x25, 0x25, 0x32, 0x32, 0x32, 0x32, 0x32, 0x33, 0x21, 0x22, 0x22, 0x23, 0x28, 0x28, 0x24, 0x25, 0x25, 0x25, 0x32, 0x33, 0x28, 0x28, 0x28, 0x29, 0x00, 0x00, 0x2a, 0x28, 0x31, 0x32, 0x25, 0x25, 0x26, 0x28, 0x28, 0x28, 0x28, 0x29, 0x00, 0x00, 0x2a, 0x28, 0x28, 0x28, 0x38, 0x28, 0x24, 0x48, + 0x32, 0x32, 0x33, 0x28, 0x28, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3f, 0x20, 0x20, 0x24, 0x48, 0x25, 0x26, 0x28, 0x28, 0x29, 0x00, 0x00, 0x00, 0x2a, 0x24, 0x33, 0x00, 0x00, 0x2a, 0x24, 0x25, 0x32, 0x25, 0x25, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x25, 0x29, 0x00, 0x00, 0x00, 0x00, 0x21, 0x22, 0x23, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x28, 0x34, 0x35, 0x36, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x39, 0x24, 0x25, 0x26, 0x21, 0x22, 0x23, 0x20, 0x21, 0x23, 0x31, 0x32, 0x32, 0x33, 0x28, 0x28, 0x24, 0x25, 0x48, 0x26, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1c, 0x00, 0x00, 0x3b, 0x24, 0x25, 0x26, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x28, 0x28, 0x28, 0x28, 0x24, 0x25, + 0x23, 0x40, 0x28, 0x38, 0x28, 0x29, 0x3a, 0x28, 0x39, 0x00, 0x00, 0x00, 0x34, 0x35, 0x22, 0x25, 0x25, 0x48, 0x26, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x00, 0x00, 0x00, 0x00, 0x24, 0x33, 0x00, 0x31, 0x25, 0x33, 0x3d, 0x3f, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x00, 0x00, 0x1c, 0x3a, 0x3a, 0x31, 0x25, 0x26, 0x20, 0x28, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x28, 0x28, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x3a, 0x28, 0x28, 0x31, 0x32, 0x33, 0x24, 0x25, 0x26, 0x10, 0x31, 0x33, 0x20, 0x28, 0x28, 0x28, 0x28, 0x38, 0x24, 0x25, 0x25, 0x26, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x24, 0x25, 0x26, 0x2a, 0x28, 0x28, 0x67, 0x00, 0x16, 0x00, 0x2a, 0x28, 0x28, 0x38, 0x28, 0x28, 0x24, 0x25, + 0x26, 0x3a, 0x28, 0x28, 0x28, 0x10, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x25, 0x25, 0x32, 0x33, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x3e, 0x24, 0x00, 0x00, 0x00, 0x37, 0x21, 0x22, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x58, 0x68, 0x28, 0x28, 0x28, 0x24, 0x26, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x23, 0x28, 0x38, 0x28, 0x29, 0x28, 0x28, 0x31, 0x32, 0x33, 0x28, 0x28, 0x29, 0x00, 0x2a, 0x00, 0x2a, 0x28, 0x28, 0x24, 0x25, 0x25, 0x33, 0x2b, 0x0c, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x0c, 0x3b, 0x31, 0x48, 0x26, 0x11, 0x28, 0x10, 0x00, 0x00, 0x00, 0x00, 0x68, 0x28, 0x28, 0x28, 0x28, 0x28, 0x24, 0x25, + 0x25, 0x22, 0x35, 0x35, 0x36, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x28, 0x24, 0x26, 0x00, 0x3d, 0x00, 0x3a, 0x39, 0x00, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x25, 0x00, 0x1a, 0x00, 0x00, 0x24, 0x25, 0x26, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x2c, 0x28, 0x38, 0x28, 0x28, 0x28, 0x38, 0x31, 0x33, 0x28, 0x00, 0x00, 0x00, 0x17, 0x17, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x24, 0x26, 0x10, 0x28, 0x29, 0x00, 0x28, 0x28, 0x1b, 0x1b, 0x1b, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x21, 0x25, 0x48, 0x26, 0x28, 0x39, 0x00, 0x00, 0x00, 0x3b, 0x34, 0x36, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x28, 0x24, 0x25, 0x23, 0x28, 0x28, 0x3a, 0x67, 0x00, 0x3a, 0x28, 0x28, 0x28, 0x29, 0x00, 0x2a, 0x31, 0x32, + 0x25, 0x33, 0x38, 0x28, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x38, 0x24, 0x25, 0x23, 0x20, 0x20, 0x10, 0x29, 0x00, 0x30, 0x39, 0x00, 0x00, 0x00, 0x00, 0x58, 0x24, 0x48, 0x00, 0x00, 0x00, 0x3a, 0x31, 0x32, 0x32, 0x35, 0x35, 0x35, 0x36, 0x67, 0x58, 0x00, 0x00, 0x3c, 0x28, 0x28, 0x28, 0x28, 0x10, 0x28, 0x21, 0x23, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x36, 0x00, 0x3a, 0x24, 0x26, 0x28, 0x28, 0x00, 0x00, 0x38, 0x28, 0x39, 0x00, 0x00, 0x00, 0x2a, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x32, 0x32, 0x26, 0x10, 0x10, 0x00, 0x00, 0x00, 0x00, 0x28, 0x28, 0x39, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x24, 0x25, 0x33, 0x28, 0x28, 0x28, 0x38, 0x00, 0x28, 0x28, 0x28, 0x39, 0x00, 0x00, 0x00, 0x17, 0x00, + 0x26, 0x00, 0x00, 0x2a, 0x28, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x28, 0x3a, 0x28, 0x28, 0x28, 0x24, 0x25, 0x25, 0x22, 0x23, 0x28, 0x39, 0x00, 0x37, 0x28, 0x58, 0x39, 0x00, 0x68, 0x28, 0x31, 0x32, 0x00, 0x00, 0x00, 0x28, 0x28, 0x28, 0x28, 0x28, 0x20, 0x20, 0x28, 0x28, 0x28, 0x39, 0x21, 0x22, 0x28, 0x29, 0x00, 0x2a, 0x28, 0x28, 0x24, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x38, 0x28, 0x28, 0x31, 0x25, 0x23, 0x00, 0x00, 0x00, 0x28, 0x28, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x3a, 0x67, 0x68, 0x28, 0x28, 0x00, 0x33, 0x38, 0x28, 0x0b, 0x00, 0x00, 0x00, 0x10, 0x38, 0x28, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x31, 0x33, 0x28, 0x28, 0x28, 0x28, 0x28, 0x68, 0x28, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x17, 0x00, + 0x33, 0x00, 0x00, 0x00, 0x28, 0x67, 0x58, 0x00, 0x00, 0x28, 0x10, 0x28, 0x28, 0x34, 0x22, 0x25, 0x25, 0x25, 0x48, 0x26, 0x28, 0x28, 0x67, 0x20, 0x28, 0x28, 0x28, 0x38, 0x28, 0x28, 0x21, 0x22, 0x00, 0x00, 0x3a, 0x28, 0x38, 0x28, 0x10, 0x29, 0x00, 0x00, 0x2a, 0x28, 0x38, 0x28, 0x24, 0x25, 0x2a, 0x00, 0x00, 0x00, 0x28, 0x38, 0x24, 0x26, 0x00, 0x00, 0x00, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x28, 0x28, 0x2a, 0x28, 0x31, 0x33, 0x39, 0x00, 0x00, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x28, 0x28, 0x29, 0x00, 0x2a, 0x28, 0x39, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x28, 0x28, 0x38, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x3a, 0x28, 0x28, 0x38, 0x3e, 0x3a, 0x28, 0x28, 0x28, 0x38, 0x28, 0x24, 0x25, 0x48, 0x25, 0x25, 0x26, 0x00, 0x2a, 0x28, 0x27, 0x29, 0x00, 0x2a, 0x28, 0x28, 0x34, 0x32, 0x25, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x28, 0x10, 0x28, 0x24, 0x25, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x24, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x28, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x28, 0x39, 0x00, 0x28, 0x00, 0x00, 0x00, 0x39, 0x28, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x28, 0x00, 0x00, 0x00, 0x28, 0x29, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x10, 0x28, 0x28, 0x28, 0x28, 0x67, 0x58, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x28, 0x38, 0x28, 0x28, 0x21, 0x23, 0x28, 0x00, 0x00, 0x2a, 0x28, 0x24, 0x25, 0x32, 0x32, 0x25, 0x26, 0x00, 0x3a, 0x28, 0x30, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x28, 0x24, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x11, 0x11, 0x11, 0x11, 0x28, 0x28, 0x28, 0x24, 0x48, 0x00, 0x00, 0x00, 0x3a, 0x28, 0x28, 0x31, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, 0x00, 0x01, 0x3f, 0x00, 0x00, 0x00, 0x20, 0x29, 0x00, 0x00, 0x00, 0x00, 0x38, 0x28, 0x00, 0x00, 0x28, 0x01, 0x3a, 0x28, 0x28, 0x10, 0x28, 0x58, 0x00, 0x00, 0x00, 0x3a, 0x28, 0x29, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x0c, 0x00, 0x00, 0x00, 0x3a, 0x38, 0x0c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x0c, 0x00, 0x00, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x29, 0x28, 0x28, 0x29, 0x00, 0x00, 0x00, 0x3a, + 0x00, 0x01, 0x3a, 0x21, 0x23, 0x28, 0x2a, 0x31, 0x33, 0x29, 0x00, 0x11, 0x11, 0x11, 0x24, 0x25, 0x00, 0x28, 0x31, 0x26, 0x3a, 0x38, 0x29, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x31, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x34, 0x22, 0x22, 0x36, 0x29, 0x2a, 0x00, 0x24, 0x25, 0x3e, 0x01, 0x3a, 0x38, 0x28, 0x29, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x35, 0x35, 0x35, 0x36, 0x00, 0x00, 0x20, 0x00, 0x00, 0x00, 0x00, 0x3d, 0x2a, 0x28, 0x67, 0x14, 0x22, 0x22, 0x23, 0x28, 0x28, 0x28, 0x28, 0x28, 0x39, 0x00, 0x58, 0x28, 0x38, 0x28, 0x3d, 0x00, 0x00, 0x3a, 0x29, 0x00, 0x00, 0x00, 0x00, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x28, 0x2a, 0x29, 0x00, 0x00, 0x58, 0x10, 0x00, 0x12, 0x00, 0x2a, 0x28, + 0x22, 0x22, 0x22, 0x25, 0x26, 0x29, 0x00, 0x21, 0x23, 0x11, 0x11, 0x21, 0x22, 0x22, 0x25, 0x25, 0x00, 0x2a, 0x38, 0x37, 0x28, 0x29, 0x00, 0x30, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x3a, 0x28, 0x00, 0x01, 0x3f, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x24, 0x26, 0x29, 0x00, 0x00, 0x00, 0x24, 0x25, 0x22, 0x22, 0x22, 0x23, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, 0x00, 0x00, 0x2a, 0x28, 0x20, 0x39, 0x00, 0x3a, 0x20, 0x00, 0x00, 0x3a, 0x00, 0x34, 0x35, 0x35, 0x35, 0x35, 0x25, 0x25, 0x25, 0x22, 0x22, 0x22, 0x23, 0x28, 0x28, 0x28, 0x28, 0x10, 0x28, 0x28, 0x21, 0x22, 0x0b, 0x10, 0x00, 0x00, 0x00, 0x00, 0x0b, 0x28, 0x10, 0x00, 0x00, 0x00, 0x0b, 0x00, 0x00, 0x00, 0x2c, 0x00, 0x00, 0x28, 0x38, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x39, 0x17, 0x00, 0x00, 0x28, + 0x25, 0x48, 0x25, 0x25, 0x26, 0x11, 0x11, 0x24, 0x25, 0x22, 0x22, 0x25, 0x25, 0x25, 0x48, 0x25, 0x00, 0x01, 0x2a, 0x28, 0x28, 0x67, 0x3f, 0x24, 0x22, 0x22, 0x23, 0x00, 0x00, 0x00, 0x38, 0x28, 0x22, 0x22, 0x23, 0x00, 0x00, 0x12, 0x00, 0x2a, 0x24, 0x26, 0x00, 0x00, 0x00, 0x12, 0x24, 0x25, 0x25, 0x25, 0x25, 0x26, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x20, 0x28, 0x39, 0x28, 0x27, 0x08, 0x00, 0x28, 0x67, 0x68, 0x20, 0x28, 0x28, 0x28, 0x25, 0x48, 0x25, 0x25, 0x25, 0x25, 0x26, 0x2a, 0x28, 0x28, 0x21, 0x22, 0x22, 0x22, 0x25, 0x25, 0x3a, 0x28, 0x01, 0x3d, 0x00, 0x00, 0x00, 0x68, 0x28, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3c, 0x01, 0x68, 0x28, 0x28, 0x00, 0x17, 0x17, 0x17, 0x00, 0x3a, 0x28, 0x00, 0x00, 0x3a, 0x28, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x22, 0x22, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x25, 0x25, 0x48, 0x26, 0x67, 0x58, 0x68, 0x28, 0x28, 0x25, 0x48, 0x26, 0x00, 0x00, 0x27, 0x00, 0x00, 0x24, 0x26, 0x00, 0x00, 0x00, 0x21, 0x25, 0x25, 0x25, 0x25, 0x48, 0x26, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x20, 0x28, 0x10, 0x28, 0x30, 0x00, 0x3a, 0x28, 0x28, 0x28, 0x20, 0x28, 0x28, 0x28, 0x25, 0x25, 0x25, 0x25, 0x48, 0x25, 0x26, 0x00, 0x00, 0x2a, 0x24, 0x25, 0x25, 0x25, 0x48, 0x25, 0x28, 0x21, 0x22, 0x23, 0x00, 0x00, 0x00, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x23, 0x28, 0x67, 0x00, 0x00, 0x00, 0x00, 0x28, 0x28, 0x39, 0x00, 0x28, 0x38, + 0x25, 0x32, 0x33, 0x00, 0x00, 0x00, 0x24, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x25, 0x25, 0x25, 0x25, 0x26, 0x28, 0x28, 0x28, 0x28, 0x24, 0x25, 0x32, 0x32, 0x32, 0x32, 0x25, 0x48, 0x25, 0x25, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x25, 0x26, 0x28, 0x28, 0x28, 0x24, 0x48, 0x25, 0x25, 0x25, 0x25, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x25, 0x25, 0x32, 0x32, 0x32, 0x32, 0x33, 0x31, 0x32, 0x32, 0x32, 0x32, 0x33, 0x28, 0x29, 0x00, 0x26, 0x28, 0x29, 0x28, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x28, 0x31, 0x32, 0x32, 0x32, 0x25, 0x25, 0x25, 0x32, 0x33, 0x28, 0x28, 0x00, 0x31, 0x25, 0x25, 0x48, 0x25, 0x25, 0x25, 0x48, 0x25, 0x25, 0x48, 0x26, 0x28, 0x38, 0x28, 0x31, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x25, 0x48, + 0x26, 0x28, 0x28, 0x00, 0x00, 0x00, 0x30, 0x40, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x24, 0x25, 0x25, 0x48, 0x26, 0x28, 0x38, 0x28, 0x28, 0x31, 0x33, 0x38, 0x28, 0x29, 0x00, 0x31, 0x32, 0x25, 0x26, 0x28, 0x00, 0x00, 0x16, 0x3a, 0x28, 0x28, 0x31, 0x33, 0x28, 0x28, 0x38, 0x24, 0x25, 0x25, 0x48, 0x25, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x25, 0x26, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x10, 0x28, 0x28, 0x38, 0x39, 0x00, 0x26, 0x28, 0x1a, 0x38, 0x20, 0x39, 0x3d, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x38, 0x28, 0x28, 0x28, 0x25, 0x25, 0x26, 0x28, 0x28, 0x28, 0x29, 0x00, 0x3b, 0x24, 0x25, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x33, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x10, 0x28, 0x28, 0x20, 0x31, 0x25, + 0x33, 0x28, 0x39, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x2a, 0x38, 0x28, 0x00, 0x2a, 0x24, 0x25, 0x25, 0x25, 0x26, 0x28, 0x28, 0x28, 0x28, 0x20, 0x28, 0x29, 0x2a, 0x00, 0x00, 0x00, 0x2a, 0x31, 0x33, 0x28, 0x11, 0x11, 0x11, 0x28, 0x28, 0x28, 0x00, 0x00, 0x28, 0x00, 0x2a, 0x31, 0x25, 0x25, 0x25, 0x25, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x52, 0x25, 0x26, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x29, 0x2a, 0x28, 0x29, 0x00, 0x26, 0x28, 0x3a, 0x28, 0x20, 0x10, 0x20, 0x11, 0x11, 0x11, 0x21, 0x22, 0x23, 0x28, 0x28, 0x10, 0x25, 0x25, 0x26, 0x28, 0x38, 0x28, 0x00, 0x00, 0x3b, 0x24, 0x26, 0x2b, 0x00, 0x2a, 0x2a, 0x38, 0x28, 0x28, 0x28, 0x28, 0x28, 0x29, 0x00, 0x2a, 0x28, 0x00, 0x28, 0x28, 0x38, 0x28, 0x28, 0x31, + 0x28, 0x28, 0x10, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x28, 0x39, 0x00, 0x24, 0x48, 0x25, 0x25, 0x26, 0x28, 0x29, 0x00, 0x28, 0x20, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x10, 0x21, 0x22, 0x23, 0x28, 0x38, 0x29, 0x00, 0x3a, 0x10, 0x29, 0x00, 0x2a, 0x24, 0x25, 0x32, 0x32, 0x33, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x42, 0x00, 0x25, 0x26, 0x39, 0x00, 0x00, 0x00, 0x21, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x22, 0x22, 0x25, 0x22, 0x22, 0x23, 0x21, 0x22, 0x23, 0x21, 0x22, 0x23, 0x24, 0x48, 0x26, 0x28, 0x28, 0x28, 0x32, 0x32, 0x33, 0x28, 0x28, 0x28, 0x00, 0x00, 0x3b, 0x31, 0x33, 0x2b, 0x00, 0x00, 0x00, 0x28, 0x10, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x00, 0x2a, 0x28, 0x28, 0x28, 0x29, 0x00, + 0x28, 0x28, 0x28, 0x00, 0x16, 0x00, 0x00, 0x00, 0x16, 0x2a, 0x28, 0x28, 0x28, 0x00, 0x24, 0x25, 0x25, 0x25, 0x26, 0x27, 0x00, 0x00, 0x2a, 0x20, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x34, 0x25, 0x25, 0x33, 0x29, 0x2a, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x11, 0x11, 0x24, 0x25, 0x22, 0x23, 0x28, 0x28, 0x00, 0x00, 0x2c, 0x46, 0x47, 0x2c, 0x00, 0x00, 0x00, 0x42, 0x53, 0x53, 0x25, 0x26, 0x28, 0x00, 0x00, 0x3a, 0x24, 0x26, 0x00, 0x00, 0x16, 0x00, 0x00, 0x24, 0x25, 0x25, 0x25, 0x25, 0x48, 0x26, 0x31, 0x32, 0x33, 0x31, 0x32, 0x33, 0x24, 0x25, 0x26, 0x20, 0x28, 0x38, 0x22, 0x22, 0x23, 0x28, 0x29, 0x28, 0x67, 0x00, 0x00, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x38, 0x00, 0x11, 0x11, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x28, 0x29, 0x2a, 0x16, 0x00, + 0x28, 0x38, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x28, 0x29, 0x00, 0x24, 0x25, 0x48, 0x25, 0x26, 0x37, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x29, 0x3b, 0x24, 0x26, 0x28, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x21, 0x22, 0x25, 0x25, 0x25, 0x26, 0x38, 0x28, 0x67, 0x00, 0x3c, 0x56, 0x57, 0x3c, 0x42, 0x43, 0x43, 0x53, 0x63, 0x63, 0x32, 0x33, 0x28, 0x39, 0x00, 0x28, 0x24, 0x26, 0x11, 0x11, 0x11, 0x11, 0x11, 0x24, 0x25, 0x25, 0x25, 0x48, 0x25, 0x26, 0x20, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x24, 0x25, 0x26, 0x28, 0x28, 0x28, 0x25, 0x25, 0x26, 0x00, 0x00, 0x2a, 0x28, 0x14, 0x3a, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x29, 0x3b, 0x21, 0x23, 0x00, 0x00, 0x17, 0x00, 0x00, 0x11, 0x28, 0x67, 0x00, 0x00, 0x00, + 0x28, 0x28, 0x28, 0x67, 0x58, 0x00, 0x00, 0x00, 0x58, 0x68, 0x28, 0x38, 0x00, 0x00, 0x31, 0x32, 0x32, 0x32, 0x33, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x27, 0x28, 0x28, 0x00, 0x3b, 0x24, 0x26, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x31, 0x25, 0x48, 0x25, 0x25, 0x33, 0x28, 0x28, 0x28, 0x39, 0x21, 0x22, 0x22, 0x23, 0x52, 0x53, 0x53, 0x64, 0x00, 0x00, 0x29, 0x00, 0x2a, 0x28, 0x38, 0x28, 0x31, 0x32, 0x35, 0x35, 0x35, 0x35, 0x22, 0x25, 0x48, 0x25, 0x25, 0x25, 0x25, 0x25, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x32, 0x33, 0x28, 0x10, 0x28, 0x48, 0x25, 0x26, 0x11, 0x11, 0x11, 0x34, 0x35, 0x36, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x31, 0x33, 0x11, 0x11, 0x11, 0x11, 0x11, 0x27, 0x28, 0x29, 0x00, 0x00, 0x3b, + 0x28, 0x28, 0x28, 0x28, 0x10, 0x29, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x28, 0x67, 0x00, 0x00, 0x28, 0x35, 0x35, 0x35, 0x36, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x30, 0x28, 0x38, 0x00, 0x3b, 0x31, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x31, 0x32, 0x25, 0x26, 0x2a, 0x28, 0x28, 0x10, 0x28, 0x24, 0x25, 0x25, 0x26, 0x62, 0x63, 0x64, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x28, 0x28, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x32, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x26, 0x67, 0x58, 0x00, 0x00, 0x00, 0x20, 0x00, 0x00, 0x2a, 0x28, 0x28, 0x25, 0x25, 0x32, 0x35, 0x35, 0x35, 0x22, 0x22, 0x22, 0x22, 0x22, 0x35, 0x36, 0x39, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x34, 0x35, 0x35, 0x35, 0x35, 0x35, 0x36, 0x30, 0x38, 0x00, 0x00, 0x00, 0x17, + 0x28, 0x29, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x2a, 0x29, 0x00, 0x3a, 0x28, 0x28, 0x28, 0x28, 0x34, 0x36, 0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x30, 0x28, 0x28, 0x00, 0x00, 0x2a, 0x29, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x28, 0x28, 0x28, 0x31, 0x26, 0x00, 0x29, 0x00, 0x2a, 0x28, 0x24, 0x48, 0x25, 0x25, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x3a, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x31, 0x32, 0x25, 0x25, 0x48, 0x25, 0x26, 0x38, 0x29, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x58, 0x68, 0x28, 0x32, 0x33, 0x10, 0x28, 0x29, 0x3b, 0x24, 0x48, 0x25, 0x25, 0x26, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x20, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x30, 0x28, 0x00, 0x00, 0x00, 0x17, + 0x28, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x28, 0x28, 0x28, 0x38, 0x10, 0x29, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x37, 0x10, 0x28, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x21, 0x36, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x38, 0x0b, 0x26, 0x00, 0x00, 0x00, 0x00, 0x21, 0x25, 0x25, 0x25, 0x25, 0x26, 0x00, 0x1c, 0x00, 0x00, 0x00, 0x28, 0x28, 0x28, 0x10, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x2a, 0x38, 0x28, 0x29, 0x25, 0x25, 0x25, 0x25, 0x26, 0x28, 0x00, 0x00, 0x00, 0x00, 0x17, 0x00, 0x00, 0x2a, 0x21, 0x22, 0x28, 0x28, 0x29, 0x08, 0x00, 0x3b, 0x24, 0x25, 0x25, 0x48, 0x26, 0x28, 0x28, 0x29, 0x12, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x30, 0x29, 0x00, 0x00, 0x00, 0x3b, + 0x38, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x10, 0x29, 0x00, 0x00, 0x28, 0x38, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x28, 0x22, 0x35, 0x35, 0x35, 0x35, 0x35, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x28, 0x39, 0x33, 0x00, 0x00, 0x00, 0x00, 0x31, 0x32, 0x25, 0x25, 0x25, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x38, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x20, 0x2b, 0x00, 0x68, 0x28, 0x28, 0x00, 0x32, 0x32, 0x32, 0x32, 0x33, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x31, 0x25, 0x28, 0x28, 0x00, 0x00, 0x00, 0x3b, 0x31, 0x32, 0x32, 0x25, 0x26, 0x38, 0x28, 0x00, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x28, 0x29, 0x28, 0x29, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x2a, 0x33, 0x28, 0x38, 0x28, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x42, 0x43, 0x44, 0x24, 0x25, 0x26, 0x28, 0x39, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x2a, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x2a, 0x20, 0x10, 0x29, 0x2c, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x31, 0x28, 0x29, 0x16, 0x00, 0x00, 0x00, 0x1b, 0x1b, 0x1b, 0x31, 0x33, 0x28, 0x10, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x3a, 0x27, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x3a, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x00, 0x28, 0x28, 0x29, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x52, 0x53, 0x54, 0x24, 0x48, 0x26, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x3b, 0x20, 0x2b, 0x39, 0x00, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x3c, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x1b, 0x2a, 0x28, 0x29, 0x00, 0x00, 0x01, 0x00, 0x00, 0x27, 0x39, 0x00, 0x38, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x11, 0x11, 0x20, 0x11, 0x11, 0x11, 0x21, 0x22, 0x23, 0x00, 0x00, 0x00, 0x12, 0x12, 0x00, 0x2a, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x67, 0x68, 0x28, 0x29, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x52, 0x53, 0x54, 0x24, 0x25, 0x26, 0x28, 0x10, 0x67, 0x3a, 0x39, 0x00, 0x01, 0x3f, 0x00, 0x00, 0x00, 0x2a, 0x38, 0x29, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x21, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x67, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x38, 0x28, 0x67, 0x58, 0x68, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x68, 0x28, 0x00, 0x00, 0x00, 0x21, 0x23, 0x00, 0x37, 0x28, 0x29, 0x28, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x24, 0x48, 0x26, 0x11, 0x11, 0x11, 0x20, 0x20, 0x11, 0x11, 0x00, 0x27, 0x39, 0x00, 0x00, 0x17, 0x17, 0x00, 0x00, 0x00, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, 0x00, 0x00, 0x00, 0x28, 0x28, 0x38, 0x39, 0x3a, 0x00, 0x21, 0x22, 0x23, 0x52, 0x53, 0x54, 0x24, 0x25, 0x33, 0x28, 0x28, 0x28, 0x38, 0x29, 0x00, 0x22, 0x23, 0x2b, 0x00, 0x00, 0x08, 0x28, 0x39, 0x3b, 0x27, 0x00, 0x00, 0x00, 0x00, 0x14, 0x24, 0x23, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x28, 0x28, 0x10, 0x28, 0x67, 0x00, 0x17, 0x17, 0x17, 0x17, 0x17, 0x28, 0x28, 0x39, 0x00, 0x00, 0x31, 0x33, 0x39, 0x27, 0x10, 0x12, 0x28, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x25, 0x48, 0x25, 0x25, 0x25, 0x26, 0x24, 0x25, 0x26, 0x21, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x3a, 0x30, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x28, 0x28, 0x28, 0x28, 0x28, 0x00, 0x24, 0x25, 0x26, 0x52, 0x53, 0x54, 0x24, 0x26, 0x28, 0x28, 0x28, 0x28, 0x28, 0x28, 0x39, 0x25, 0x26, 0x2b, 0x00, 0x00, 0x3a, 0x28, 0x10, 0x3b, 0x30, 0x00, 0x00, 0x00, 0x21, 0x22, 0x25, 0x26, 0x00, 0x00, 0x00, 0x27, 0x00, 0x00, 0x3a, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x28, 0x38, 0x28, 0x28, 0x28, 0x39, 0x00, 0x00, 0x00, 0x58, 0x68, 0x28, 0x38, 0x28, 0x00, 0x00, 0x22, 0x23, 0x38, 0x30, 0x28, 0x17, 0x28, 0x27, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x24, 0x25, 0x25, 0x25, 0x25, 0x48, 0x25, 0x33, 0x29, 0x00, 0x00, 0x31, 0x32, 0x32, 0x32, 0x25, 0x32, 0x32, 0x32, 0x32, 0x32, 0x25, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x20, 0x00, 0x00, 0x31, 0x32, 0x32, 0x25, 0x25, 0x26, 0x00, 0x2a, 0x28, 0x38, 0x24, 0x25, 0x25, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x10, 0x28, 0x29, 0x00, 0x31, 0x32, 0x32, 0x25, 0x63, 0x63, 0x63, 0x64, 0x52, 0x53, 0x53, 0x53, 0x54, 0x55, 0x00, 0x00, 0x00, 0x55, 0x52, 0x53, 0x25, 0x48, 0x25, 0x25, 0x26, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x25, 0x25, 0x25, 0x26, 0x28, 0x28, 0x28, 0x24, 0x25, 0x48, 0x25, 0x25, 0x25, 0x48, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x58, 0x68, 0x28, 0x24, 0x48, 0x25, 0x25, 0x25, 0x25, 0x25, 0x1b, 0x00, 0x16, 0x00, 0x1b, 0x1b, 0x1b, 0x1b, 0x30, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x30, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x20, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x24, 0x25, 0x33, 0x00, 0x00, 0x00, 0x2a, 0x31, 0x32, 0x33, 0x00, 0x00, 0x29, 0x00, 0x00, 0x38, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x31, 0x00, 0x00, 0x00, 0x00, 0x62, 0x63, 0x63, 0x63, 0x64, 0x55, 0x00, 0x00, 0x00, 0x55, 0x52, 0x53, 0x25, 0x25, 0x25, 0x48, 0x26, 0x2b, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x24, 0x25, 0x48, 0x25, 0x26, 0x28, 0x38, 0x28, 0x31, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x25, 0x25, 0x48, 0x25, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x10, 0x28, 0x31, 0x32, 0x25, 0x25, 0x48, 0x25, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x34, 0x35, 0x36, 0x00, 0x14, 0x00, 0x00, 0x10, 0x31, 0x26, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x20, 0x2b, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x00, 0x55, 0x62, 0x63, 0x25, 0x25, 0x25, 0x32, 0x33, 0x2b, 0x28, 0x29, 0x00, 0x11, 0x11, 0x20, 0x24, 0x25, 0x25, 0x25, 0x26, 0x10, 0x29, 0x00, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x31, 0x25, 0x25, 0x25, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x28, 0x24, 0x25, 0x25, 0x25, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x34, 0x35, 0x36, 0x39, 0x00, 0x00, 0x1b, 0x26, 0x72, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x73, 0x74, 0x11, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x1b, 0x00, 0x3b, 0x20, 0x2b, 0x00, 0x00, 0x00, 0x16, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x65, 0x00, 0x00, 0x25, 0x25, 0x33, 0x28, 0x28, 0x28, 0x28, 0x10, 0x3a, 0x21, 0x22, 0x22, 0x25, 0x25, 0x25, 0x25, 0x26, 0x28, 0x00, 0x00, 0x2a, 0x00, 0x11, 0x11, 0x11, 0x00, 0x00, 0x28, 0x38, 0x24, 0x25, 0x25, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x3a, 0x28, 0x28, 0x24, 0x25, 0x25, 0x25, 0x25, 0x00, 0x00, 0x16, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x10, 0x28, 0x00, 0x11, 0x25, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x22, 0x23, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x20, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x48, 0x26, 0x28, 0x28, 0x28, 0x38, 0x28, 0x28, 0x28, 0x31, 0x32, 0x32, 0x25, 0x48, 0x25, 0x25, 0x26, 0x29, 0x00, 0x00, 0x00, 0x11, 0x42, 0x43, 0x44, 0x00, 0x00, 0x2a, 0x28, 0x24, 0x25, 0x48, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x38, 0x28, 0x24, 0x48, 0x25, 0x25, 0x25, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x20, 0x2b, 0x39, 0x16, 0x00, 0x3b, 0x20, 0x2b, 0x00, 0x16, 0x00, 0x27, 0x39, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x2a, 0x28, 0x39, 0x21, 0x25, 0x48, 0x25, 0x25, 0x25, 0x25, 0x25, 0x32, 0x32, 0x32, 0x32, 0x32, 0x26, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x68, 0x28, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x25, 0x26, 0x28, 0x28, 0x10, 0x2a, 0x00, 0x2a, 0x28, 0x28, 0x29, 0x00, 0x31, 0x32, 0x32, 0x32, 0x26, 0x11, 0x11, 0x11, 0x11, 0x42, 0x53, 0x53, 0x54, 0x00, 0x00, 0x3b, 0x21, 0x25, 0x25, 0x25, + 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x28, 0x28, 0x31, 0x32, 0x32, 0x32, 0x32, 0x28, 0x00, 0x00, 0x3a, 0x00, 0x1b, 0x3a, 0x28, 0x39, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x37, 0x28, 0x38, 0x39, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x3a, 0x28, 0x28, 0x31, 0x32, 0x32, 0x32, 0x32, 0x25, 0x48, 0x26, 0x28, 0x29, 0x00, 0x2a, 0x10, 0x37, 0x2b, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x20, 0x2b, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x58, 0x28, 0x28, 0x68, 0x28, 0x28, 0x28, 0x28, 0x28, 0x39, 0x00, 0x00, 0x00, 0x25, 0x26, 0x38, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x22, 0x22, 0x22, 0x23, 0x62, 0x63, 0x63, 0x64, 0x00, 0x00, 0x3b, 0x24, 0x25, 0x25, 0x25, + 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x3a, 0x28, 0x28, 0x10, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x28, 0x39, 0x28, 0x28, 0x39, 0x00, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x2a, 0x28, 0x27, 0x11, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x27, 0x28, 0x28, 0x38, 0x1b, 0x22, 0x22, 0x22, 0x23, 0x31, 0x32, 0x33, 0x16, 0x00, 0x00, 0x68, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x68, 0x39, 0x28, 0x28, 0x28, 0x28, 0x10, 0x29, 0x00, 0x00, 0x2a, 0x10, 0x28, 0x3a, 0x67, 0x68, 0x25, 0x26, 0x28, 0x28, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x25, 0x48, 0x25, 0x25, 0x23, 0x28, 0x38, 0x29, 0x00, 0x00, 0x3b, 0x24, 0x48, 0x25, 0x25, + 0x00, 0x00, 0x68, 0x21, 0x22, 0x22, 0x23, 0x28, 0x38, 0x28, 0x28, 0x39, 0x00, 0x00, 0x00, 0x00, 0x28, 0x28, 0x28, 0x28, 0x28, 0x38, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x16, 0x00, 0x11, 0x00, 0x3a, 0x28, 0x37, 0x27, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x37, 0x2a, 0x28, 0x29, 0x11, 0x25, 0x25, 0x48, 0x26, 0x38, 0x28, 0x2a, 0x00, 0x00, 0x00, 0x2a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x20, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00, 0x16, 0x28, 0x28, 0x28, 0x2a, 0x38, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x28, 0x28, 0x28, 0x25, 0x26, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x25, 0x25, 0x25, 0x25, 0x26, 0x10, 0x2a, 0x00, 0x00, 0x00, 0x3b, 0x24, 0x25, 0x25, 0x25, + 0x00, 0x00, 0x10, 0x31, 0x32, 0x25, 0x25, 0x22, 0x35, 0x35, 0x35, 0x36, 0x00, 0x00, 0x00, 0x00, 0x28, 0x38, 0x00, 0x2a, 0x28, 0x28, 0x28, 0x10, 0x39, 0x39, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x27, 0x28, 0x28, 0x29, 0x1b, 0x30, 0x39, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x2a, 0x28, 0x21, 0x25, 0x32, 0x25, 0x26, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x34, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x36, 0x2b, 0x00, 0x28, 0x28, 0x29, 0x00, 0x28, 0x28, 0x29, 0x00, 0x60, 0x61, 0x00, 0x3a, 0x28, 0x38, 0x28, 0x2a, 0x48, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x48, 0x25, 0x25, 0x25, 0x26, 0x29, 0x00, 0x00, 0x11, 0x11, 0x11, 0x24, 0x25, 0x25, 0x25, + 0x00, 0x00, 0x2a, 0x28, 0x28, 0x31, 0x32, 0x26, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x29, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x28, 0x28, 0x28, 0x39, 0x3b, 0x27, 0x2b, 0x00, 0x00, 0x37, 0x28, 0x10, 0x00, 0x11, 0x30, 0x28, 0x3a, 0x00, 0x00, 0x00, 0x11, 0x00, 0x28, 0x28, 0x31, 0x26, 0x01, 0x31, 0x33, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x39, 0x00, 0x00, 0x00, 0x00, 0x20, 0x28, 0x38, 0x28, 0x28, 0x28, 0x20, 0x28, 0x28, 0x28, 0x28, 0x28, 0x27, 0x2b, 0x00, 0x38, 0x28, 0x00, 0x00, 0x2a, 0x28, 0x3d, 0x00, 0x70, 0x71, 0x3f, 0x28, 0x28, 0x29, 0x00, 0x00, 0x25, 0x26, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x25, 0x25, 0x25, 0x25, 0x48, 0x26, 0x00, 0x00, 0x3b, 0x21, 0x22, 0x23, 0x31, 0x25, 0x48, 0x25, + 0x00, 0x00, 0x00, 0x28, 0x38, 0x29, 0x3b, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x28, 0x28, 0x28, 0x3b, 0x30, 0x2b, 0x00, 0x00, 0x1b, 0x2a, 0x28, 0x38, 0x27, 0x30, 0x28, 0x10, 0x39, 0x00, 0x00, 0x27, 0x3a, 0x28, 0x29, 0x1b, 0x26, 0x17, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x00, 0x38, 0x28, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x2a, 0x28, 0x28, 0x10, 0x28, 0x1b, 0x2a, 0x28, 0x38, 0x2a, 0x28, 0x37, 0x2b, 0x00, 0x28, 0x28, 0x39, 0x00, 0x00, 0x28, 0x21, 0x22, 0x23, 0x21, 0x22, 0x23, 0x28, 0x00, 0x00, 0x3a, 0x32, 0x33, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x32, 0x32, 0x32, 0x32, 0x32, 0x33, 0x00, 0x00, 0x3b, 0x24, 0x25, 0x25, 0x23, 0x31, 0x25, 0x25, + 0x00, 0x00, 0x00, 0x2a, 0x28, 0x00, 0x3b, 0x37, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x27, 0x00, 0x00, 0x00, 0x01, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x28, 0x38, 0x3b, 0x37, 0x2b, 0x00, 0x3a, 0x00, 0x00, 0x28, 0x28, 0x37, 0x30, 0x29, 0x00, 0x28, 0x38, 0x00, 0x37, 0x28, 0x38, 0x00, 0x11, 0x26, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x28, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x16, 0x2a, 0x28, 0x00, 0x00, 0x28, 0x16, 0x00, 0x28, 0x28, 0x00, 0x00, 0x10, 0x29, 0x00, 0x00, 0x00, 0x20, 0x31, 0x32, 0x33, 0x24, 0x48, 0x26, 0x28, 0x42, 0x43, 0x43, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x58, 0x68, 0x00, 0x00, 0x00, 0x38, 0x28, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x24, 0x25, 0x48, 0x25, 0x23, 0x31, 0x32, + 0x00, 0x00, 0x01, 0x00, 0x28, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x30, 0x00, 0x00, 0x22, 0x22, 0x23, 0x11, 0x11, 0x21, 0x35, 0x35, 0x36, 0x10, 0x28, 0x28, 0x29, 0x00, 0x00, 0x38, 0x00, 0x00, 0x29, 0x00, 0x1b, 0x30, 0x00, 0x00, 0x2a, 0x28, 0x00, 0x00, 0x28, 0x28, 0x00, 0x21, 0x26, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x28, 0x29, 0x00, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x58, 0x68, 0x00, 0x00, 0x28, 0x28, 0x3a, 0x28, 0x28, 0x39, 0x00, 0x28, 0x29, 0x16, 0x00, 0x28, 0x00, 0x01, 0x00, 0x00, 0x21, 0x22, 0x22, 0x22, 0x25, 0x25, 0x25, 0x23, 0x52, 0x53, 0x53, 0x00, 0x00, 0x00, 0x3f, 0x01, 0x00, 0x00, 0x3a, 0x28, 0x00, 0x00, 0x2a, 0x10, 0x00, 0x00, 0x00, 0x28, 0x29, 0x00, 0x00, 0x00, 0x00, 0x39, 0x00, 0x3b, 0x24, 0x25, 0x25, 0x25, 0x25, 0x22, 0x22, + 0x40, 0x00, 0x21, 0x22, 0x23, 0x2b, 0x00, 0x38, 0x39, 0x12, 0x00, 0x68, 0x38, 0x30, 0x39, 0x00, 0x25, 0x48, 0x25, 0x22, 0x22, 0x26, 0x0c, 0x00, 0x2a, 0x28, 0x28, 0x28, 0x00, 0x00, 0x3a, 0x28, 0x01, 0x00, 0x00, 0x00, 0x3a, 0x37, 0x08, 0x00, 0x00, 0x28, 0x39, 0x00, 0x28, 0x29, 0x00, 0x31, 0x26, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x38, 0x00, 0x3a, 0x28, 0x10, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x28, 0x28, 0x29, 0x2a, 0x28, 0x28, 0x38, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x43, 0x43, 0x43, 0x43, 0x44, 0x24, 0x25, 0x48, 0x25, 0x25, 0x25, 0x25, 0x26, 0x52, 0x53, 0x53, 0x00, 0x00, 0x00, 0x21, 0x36, 0x00, 0x00, 0x38, 0x28, 0x39, 0x00, 0x00, 0x28, 0x00, 0x1c, 0x00, 0x28, 0x01, 0x3d, 0x3e, 0x00, 0x3a, 0x28, 0x00, 0x3b, 0x24, 0x25, 0x25, 0x25, 0x48, 0x25, 0x25, + 0x21, 0x23, 0x24, 0x25, 0x26, 0x2b, 0x68, 0x28, 0x28, 0x27, 0x28, 0x28, 0x10, 0x30, 0x28, 0x00, 0x25, 0x25, 0x25, 0x25, 0x48, 0x26, 0x00, 0x00, 0x00, 0x28, 0x28, 0x29, 0x00, 0x00, 0x28, 0x28, 0x23, 0x00, 0x00, 0x00, 0x38, 0x28, 0x39, 0x00, 0x00, 0x2a, 0x28, 0x10, 0x28, 0x00, 0x00, 0x1b, 0x26, 0x38, 0x39, 0x00, 0x00, 0x00, 0x00, 0x28, 0x28, 0x00, 0x28, 0x28, 0x28, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x28, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x10, 0x28, 0x00, 0x00, 0x00, 0x00, 0x53, 0x53, 0x53, 0x53, 0x54, 0x24, 0x25, 0x25, 0x25, 0x25, 0x25, 0x48, 0x26, 0x52, 0x53, 0x53, 0x00, 0x00, 0x00, 0x30, 0x42, 0x44, 0x00, 0x28, 0x28, 0x28, 0x00, 0x00, 0x28, 0x39, 0x00, 0x00, 0x22, 0x22, 0x22, 0x23, 0x10, 0x28, 0x38, 0x39, 0x3b, 0x24, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x26, 0x2b, 0x1b, 0x1b, 0x1b, 0x31, 0x32, 0x32, 0x25, 0x26, 0x00, 0x48, 0x25, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x25, 0x25, 0x32, 0x32, 0x32, 0x33, 0x28, 0x28, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x48, 0x25, 0x32, 0x33, 0x2b, 0x28, 0x32, 0x32, 0x32, 0x32, 0x32, 0x25, 0x26, 0x28, 0x28, 0x00, 0x00, 0x3b, 0x24, 0x25, 0x25, 0x25, 0x25, 0x48, 0x25, 0x25, 0x25, 0x25, 0x25, 0x48, 0x48, 0x25, 0x25, 0x25, 0x26, 0x38, 0x28, 0x24, 0x25, 0x48, 0x25, 0x25, 0x32, 0x33, 0x28, 0x28, 0x29, 0x24, 0x25, 0x32, 0x32, 0x32, 0x25, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x25, 0x25, 0x25, 0x48, 0x25, 0x26, 0x2b, 0x00, 0x00, 0x00, 0x1b, 0x1b, 0x1b, 0x24, 0x26, 0x00, 0x32, 0x33, 0x28, 0x67, 0x00, 0x00, 0x00, 0x28, 0x24, 0x33, 0x2b, 0x2a, 0x28, 0x10, 0x28, 0x38, 0x25, 0x25, 0x25, 0x48, 0x25, 0x25, 0x32, 0x32, 0x32, 0x32, 0x25, 0x26, 0x1b, 0x1b, 0x00, 0x38, 0x29, 0x01, 0x00, 0x3a, 0x28, 0x24, 0x26, 0x38, 0x29, 0x00, 0x00, 0x3b, 0x24, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x32, 0x25, 0x26, 0x10, 0x28, 0x31, 0x25, 0x25, 0x32, 0x33, 0x1b, 0x1b, 0x10, 0x28, 0x14, 0x31, 0x33, 0x38, 0x28, 0x28, 0x24, 0x48, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x25, 0x25, 0x25, 0x25, 0x25, 0x26, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x24, 0x26, 0x67, 0x28, 0x28, 0x38, 0x29, 0x00, 0x00, 0x11, 0x2a, 0x37, 0x2b, 0x00, 0x3a, 0x28, 0x27, 0x29, 0x00, 0x25, 0x25, 0x25, 0x25, 0x25, 0x33, 0x1b, 0x1b, 0x1b, 0x1b, 0x31, 0x33, 0x00, 0x00, 0x00, 0x28, 0x35, 0x35, 0x35, 0x36, 0x28, 0x24, 0x26, 0x28, 0x14, 0x00, 0x00, 0x3b, 0x30, 0x28, 0x2a, 0x2a, 0x1a, 0x28, 0x29, 0x00, 0x2a, 0x28, 0x38, 0x28, 0x28, 0x10, 0x28, 0x24, 0x26, 0x00, 0x2a, 0x38, 0x25, 0x26, 0x1b, 0x1b, 0x00, 0x00, 0x38, 0x21, 0x23, 0x2b, 0x00, 0x00, 0x08, 0x10, 0x24, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x25, 0x48, 0x25, 0x32, 0x32, 0x33, 0x2b, 0x00, 0x00, 0x00, 0x11, 0x00, 0x28, 0x24, 0x26, 0x29, 0x28, 0x10, 0x2a, 0x00, 0x00, 0x3b, 0x27, 0x00, 0x29, 0x00, 0x00, 0x00, 0x38, 0x30, 0x00, 0x00, 0x32, 0x32, 0x25, 0x25, 0x26, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x27, 0x00, 0x00, 0x3a, 0x28, 0x28, 0x28, 0x38, 0x28, 0x28, 0x24, 0x25, 0x22, 0x23, 0x2b, 0x00, 0x3b, 0x37, 0x29, 0x08, 0x00, 0x00, 0x10, 0x00, 0x11, 0x00, 0x29, 0x2a, 0x28, 0x29, 0x11, 0x2a, 0x31, 0x33, 0x00, 0x3a, 0x28, 0x25, 0x26, 0x2b, 0x00, 0x00, 0x00, 0x2a, 0x31, 0x33, 0x2b, 0x00, 0x00, 0x68, 0x28, 0x24, 0x25, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x10, 0x00, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x25, 0x25, 0x26, 0x21, 0x22, 0x23, 0x2b, 0x00, 0x3a, 0x67, 0x27, 0x2b, 0x2a, 0x24, 0x26, 0x38, 0x28, 0x29, 0x00, 0x00, 0x00, 0x3b, 0x30, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x28, 0x30, 0x00, 0x00, 0x22, 0x23, 0x31, 0x32, 0x33, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x30, 0x28, 0x39, 0x00, 0x2a, 0x38, 0x28, 0x29, 0x10, 0x29, 0x24, 0x48, 0x25, 0x26, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x3b, 0x20, 0x2b, 0x3a, 0x16, 0x28, 0x3b, 0x20, 0x2b, 0x00, 0x11, 0x00, 0x00, 0x28, 0x25, 0x26, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x1b, 0x00, 0x00, 0x2a, 0x38, 0x2a, 0x24, 0x25, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x00, 0x28, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x00, 0x00, 0x00, 0x00, + 0x25, 0x25, 0x26, 0x24, 0x48, 0x26, 0x2b, 0x00, 0x2a, 0x38, 0x30, 0x2b, 0x12, 0x24, 0x26, 0x29, 0x38, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x30, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x30, 0x3e, 0x14, 0x25, 0x25, 0x22, 0x22, 0x23, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x30, 0x29, 0x00, 0x00, 0x00, 0x28, 0x29, 0x00, 0x00, 0x00, 0x24, 0x25, 0x25, 0x26, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x2a, 0x28, 0x28, 0x00, 0x1b, 0x00, 0x3b, 0x20, 0x2b, 0x11, 0x2a, 0x25, 0x26, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x29, 0x3b, 0x24, 0x48, 0x00, 0x00, 0x00, 0x00, 0x28, 0x67, 0x28, 0x00, 0x00, 0x10, 0x00, 0x39, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x00, 0x00, 0x00, 0x00, + 0x32, 0x32, 0x33, 0x31, 0x32, 0x26, 0x2b, 0x12, 0x00, 0x28, 0x30, 0x2b, 0x17, 0x31, 0x33, 0x00, 0x28, 0x39, 0x58, 0x68, 0x39, 0x3b, 0x30, 0x11, 0x11, 0x11, 0x11, 0x11, 0x11, 0x24, 0x22, 0x22, 0x25, 0x25, 0x48, 0x25, 0x26, 0x2b, 0x00, 0x00, 0x11, 0x00, 0x3b, 0x30, 0x2b, 0x00, 0x00, 0x00, 0x28, 0x11, 0x11, 0x11, 0x11, 0x24, 0x25, 0x48, 0x26, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x11, 0x10, 0x67, 0x58, 0x11, 0x00, 0x1b, 0x3b, 0x20, 0x16, 0x48, 0x26, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x00, 0x16, 0x00, 0x00, 0x00, 0x3b, 0x31, 0x25, 0x00, 0x00, 0x00, 0x00, 0x28, 0x38, 0x28, 0x76, 0x00, 0x28, 0x67, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x00, 0x00, 0x00, 0x2a, 0x30, 0x11, 0x27, 0x00, 0x2a, 0x30, 0x2b, 0x00, 0x10, 0x10, 0x39, 0x28, 0x28, 0x38, 0x28, 0x34, 0x35, 0x32, 0x35, 0x35, 0x35, 0x35, 0x35, 0x35, 0x25, 0x25, 0x48, 0x25, 0x25, 0x25, 0x25, 0x26, 0x2b, 0x00, 0x3b, 0x27, 0x00, 0x3b, 0x30, 0x2b, 0x00, 0x00, 0x00, 0x28, 0x34, 0x35, 0x35, 0x35, 0x32, 0x32, 0x25, 0x26, 0x2b, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x20, 0x28, 0x28, 0x38, 0x27, 0x2b, 0x16, 0x00, 0x1b, 0x00, 0x25, 0x25, 0x23, 0x21, 0x22, 0x23, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x24, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x28, 0x21, 0x23, 0x28, 0x38, 0x29, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x00, 0x00, 0x00, 0x00, + 0x29, 0x00, 0x11, 0x00, 0x00, 0x31, 0x35, 0x26, 0x2b, 0x00, 0x31, 0x35, 0x35, 0x35, 0x35, 0x35, 0x29, 0x00, 0x2a, 0x00, 0x00, 0x10, 0x28, 0x28, 0x28, 0x28, 0x29, 0x00, 0x3b, 0x24, 0x25, 0x25, 0x32, 0x32, 0x32, 0x32, 0x26, 0x2b, 0x16, 0x3b, 0x30, 0x00, 0x3b, 0x30, 0x00, 0x00, 0x00, 0x00, 0x29, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x3b, 0x24, 0x26, 0x2b, 0x00, 0x3b, 0x27, 0x2b, 0x00, 0x00, 0x00, 0x11, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x2a, 0x28, 0x28, 0x37, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x32, 0x32, 0x33, 0x31, 0x32, 0x33, 0x2b, 0x00, 0x00, 0x11, 0x11, 0x00, 0x00, 0x00, 0x3b, 0x24, 0x00, 0x00, 0x00, 0x68, 0x38, 0x28, 0x21, 0x25, 0x25, 0x23, 0x28, 0x39, 0x3a, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3b, 0x27, 0x2b, 0x00, 0x2a, 0x38, 0x30, 0x2b, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x39, 0x3b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x38, 0x28, 0x28, 0x67, 0x21, 0x25, 0x25, 0x25, 0x1b, 0x1b, 0x1b, 0x1b, 0x37, 0x2b, 0x00, 0x3b, 0x30, 0x39, 0x3b, 0x30, 0x16, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x24, 0x26, 0x2b, 0x17, 0x3b, 0x30, 0x2b, 0x00, 0x00, 0x3b, 0x20, 0x2b, 0x11, 0x00, 0x00, 0x00, 0x11, 0x00, 0x29, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x11, 0x11, 0x21, 0x23, 0x11, 0x00, 0x00, 0x3b, 0x24, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x21, 0x25, 0x48, 0x25, 0x25, 0x23, 0x28, 0x38, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x08, 0x3b, 0x30, 0x2b, 0x00, 0x00, 0x28, 0x30, 0x11, 0x11, 0x11, 0x11, 0x00, 0x28, 0x38, 0x3b, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x28, 0x29, 0x00, 0x29, 0x28, 0x24, 0x25, 0x48, 0x25, 0x00, 0x00, 0x00, 0x3a, 0x28, 0x00, 0x00, 0x3b, 0x30, 0x28, 0x3b, 0x37, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x24, 0x26, 0x11, 0x11, 0x11, 0x30, 0x2b, 0x00, 0x00, 0x00, 0x1b, 0x3b, 0x20, 0x2b, 0x00, 0x3b, 0x27, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x2b, 0x01, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x21, 0x22, 0x25, 0x32, 0x36, 0x2b, 0x00, 0x3b, 0x31, 0x58, 0x58, 0x68, 0x28, 0x29, 0x24, 0x25, 0x25, 0x25, 0x25, 0x26, 0x10, 0x28, 0x28, 0x68, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x00, 0x3b, 0x37, 0x2b, 0x00, 0x00, 0x2a, 0x31, 0x35, 0x35, 0x35, 0x36, 0x00, 0x28, 0x29, 0x3b, 0x22, 0x22, 0x22, 0x22, 0x23, 0x11, 0x11, 0x20, 0x2b, 0x00, 0x00, 0x2a, 0x31, 0x32, 0x25, 0x25, 0x00, 0x00, 0x00, 0x10, 0x38, 0x29, 0x00, 0x3b, 0x30, 0x28, 0x28, 0x28, 0x00, 0x00, 0x00, 0x00, 0x11, 0x11, 0x11, 0x11, 0x39, 0x00, 0x11, 0x24, 0x25, 0x22, 0x22, 0x22, 0x33, 0x2b, 0x00, 0x00, 0x01, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x3b, 0x30, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x58, 0x68, 0x28, 0x2b, 0x17, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x24, 0x25, 0x33, 0x1b, 0x1b, 0x00, 0x00, 0x00, 0x1b, 0x28, 0x10, 0x28, 0x38, 0x00, 0x31, 0x32, 0x25, 0x25, 0x48, 0x26, 0x29, 0x00, 0x2a, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x39, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x1b, 0x1b, 0x1b, 0x1b, 0x00, 0x2a, 0x00, 0x3b, 0x32, 0x32, 0x32, 0x32, 0x32, 0x35, 0x36, 0x1b, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x1b, 0x31, 0x25, 0x00, 0x00, 0x00, 0x00, 0x28, 0x00, 0x00, 0x3b, 0x30, 0x28, 0x38, 0x29, 0x00, 0x00, 0x00, 0x00, 0x22, 0x22, 0x22, 0x23, 0x28, 0x38, 0x34, 0x32, 0x32, 0x32, 0x32, 0x33, 0x2b, 0x00, 0x00, 0x00, 0x23, 0x39, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x37, 0x2b, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x10, 0x28, 0x11, 0x11, 0x11, 0x11, 0x00, 0x00, 0x3b, 0x31, 0x33, 0x1b, 0x00, 0x3a, 0x00, 0x16, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x39, 0x3f, 0x21, 0x23, 0x24, 0x25, 0x32, 0x33, 0x20, 0x00, 0x00, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x29, 0x00, 0x00, 0x01, 0x00, 0x14, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3b, 0x39, 0x01, 0x3d, 0x00, 0x00, 0x2a, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x28, 0x24, 0x00, 0x00, 0x00, 0x68, 0x28, 0x67, 0x00, 0x3b, 0x30, 0x00, 0x2a, 0x28, 0x67, 0x00, 0x00, 0x00, 0x25, 0x25, 0x25, 0x26, 0x00, 0x28, 0x28, 0x00, 0x3a, 0x10, 0x28, 0x2a, 0x00, 0x16, 0x00, 0x3a, 0x26, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x1b, 0x00, 0x00, 0x00, 0x39, 0x3a, 0x28, 0x38, 0x28, 0x22, 0x22, 0x22, 0x23, 0x2b, 0x00, 0x00, 0x1b, 0x1b, 0x00, 0x00, 0x38, 0x00, 0x00, 0x00, 0x68, 0x00, 0x00, 0x21, 0x22, 0x22, 0x25, 0x26, 0x31, 0x33, 0x21, 0x22, 0x23, 0x28, 0x39, 0x28, 0x67, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x10, 0x67, 0x58, 0x3a, 0x21, 0x22, 0x23, 0x11, 0x11, 0x11, 0x11, 0x11, 0x00, 0x12, 0x00, 0x3b, 0x22, 0x22, 0x23, 0x39, 0x00, 0x10, 0x28, 0x39, 0x00, 0x00, 0x00, 0x00, 0x08, 0x3a, 0x10, 0x31, 0x01, 0x00, 0x3a, 0x38, 0x28, 0x29, 0x00, 0x3b, 0x37, 0x00, 0x00, 0x38, 0x29, 0x00, 0x00, 0x00, 0x25, 0x48, 0x25, 0x26, 0x00, 0x2a, 0x28, 0x28, 0x28, 0x38, 0x29, 0x00, 0x00, 0x00, 0x00, 0x28, 0x26, 0x38, 0x39, 0x12, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x28, 0x28, 0x28, 0x28, 0x10, 0x25, 0x48, 0x25, 0x26, 0x2b, 0x16, 0x00, 0x00, 0x39, 0x00, 0x00, 0x28, 0x3a, 0x00, 0x3a, 0x28, 0x01, 0x00, 0x31, 0x25, 0x25, 0x48, 0x25, 0x22, 0x22, 0x25, 0x25, 0x25, 0x23, 0x10, 0x38, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, + 0x28, 0x38, 0x28, 0x28, 0x24, 0x25, 0x25, 0x22, 0x22, 0x22, 0x22, 0x23, 0x00, 0x17, 0x00, 0x3b, 0x25, 0x25, 0x26, 0x28, 0x3a, 0x28, 0x38, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x38, 0x28, 0x28, 0x23, 0x00, 0x10, 0x28, 0x28, 0x00, 0x00, 0x00, 0x38, 0x00, 0x00, 0x28, 0x10, 0x00, 0x00, 0x00, 0x25, 0x25, 0x25, 0x26, 0x17, 0x17, 0x28, 0x38, 0x28, 0x00, 0x00, 0x00, 0x00, 0x00, 0x3a, 0x28, 0x26, 0x28, 0x10, 0x27, 0x39, 0x00, 0x00, 0x00, 0x00, 0x2a, 0x28, 0x28, 0x38, 0x28, 0x28, 0x28, 0x25, 0x25, 0x48, 0x26, 0x2b, 0x00, 0x00, 0x3a, 0x38, 0x00, 0x3a, 0x28, 0x10, 0x28, 0x38, 0x28, 0x21, 0x22, 0x23, 0x24, 0x25, 0x25, 0x25, 0x25, 0x25, 0x25, 0x48, 0x25, 0x25, 0x22, 0x22, 0x23, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 +} \ No newline at end of file diff --git a/Source/Scripts/pico-8.lua b/Source/Scripts/pico-8.lua new file mode 100644 index 0000000..c9f7be2 --- /dev/null +++ b/Source/Scripts/pico-8.lua @@ -0,0 +1,227 @@ +import "map.lua" + +local sprites = playdate.graphics.imagetable.new("Assets/sprites") +local spritesFlags = { + 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, + 0x4, 0x2, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x2, 0x0, 0x0, 0x0, 0x0, + 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x4, 0x4, 0x2, 0x2, 0x0, 0x0, 0x0, + 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x3, 0x4, 0x4, 0x4, 0x2, 0x2, 0x2, 0x2, 0x2, + 0x0, 0x0, 0x13, 0x13, 0x13, 0x13, 0x2, 0x2, 0x3, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, + 0x0, 0x0, 0x13, 0x13, 0x13, 0x13, 0x2, 0x2, 0x4, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, + 0x0, 0x0, 0x13, 0x13, 0x13, 0x13, 0x0, 0x4, 0x4, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, + 0x0, 0x0, 0x13, 0x13, 0x13, 0x13, 0x0, 0x0, 0x0, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2, 0x2 +} + +local font = playdate.graphics.font.new("Assets/pico") +playdate.graphics.setFont(font) + + +function add(t, value, index) + + index = index or #t+1 + table.insert(t, index, value) + +end + +function del(t, value) + + for i=1, #t do + if t[i] == value then + table.remove(t, i) + break + end + end + +end + +function flr(num) + + return math.floor(num) + +end + +function abs(num) + + return math.abs(num) + +end + +function rnd(arg) + + arg = arg or 1.0 + if type(arg) == "table" then + return arg[math.random(1, #arg)] + else + return math.random() * arg + end + +end + +function sin(angle) + + return math.sin(math.rad(angle * -1 * 360.0)) + +end + +function cos(angle) + + return math.cos(math.rad(angle * -1 * 360.0)) + +end + +function min(first, second) + + second = second or 0 + return math.min(first, second) + +end + +function max(first, second) + + second = second or 0 + return math.max(first, second) + +end + +function rectfill(x0, y0, x1, y1, col) + + if col == nil then + playdate.graphics.setBackgroundColor(playdate.graphics.kColorBlack) + end + playdate.graphics.fillRect(x0, y0, x1-x0, y1-y0) + +end + +function circfill(x, y, r, col) + + r = r or 4 + if col == nil then + playdate.graphics.setBackgroundColor(playdate.graphics.kColorBlack) + end + playdate.graphics.fillCircleAtPoint(x, y, r) + +end + +function foreach(tbl, func) + + for _, item in ipairs(tbl) do + func(item) + end + +end + +function btn(i, p) + + if i == nil then + return + end + p = p or 0 + return playdate.buttonIsPressed(i) + +end + +-- spr(n, [x,] [y,] [w,] [h,] [flip_x,] [flip_y]) +function spr(n, x, y, w, h, flip_x, flip_y) + + if n > #sprites or n < 0 then return end + n = flr(n) + 1 or 1 + x = x or 0 + y = y or 0 + w = w or 1.0 + h = h or 1.0 + flip_x = flip_x or false + flip_y = flip_y or false + local img = sprites:getImage(n) + local flip = playdate.graphics.kImageUnflipped + if flip_x and flip_y then + flip = playdate.graphics.kImageFlippedXY + elseif flip_x then + flip = playdate.graphics.kImageFlippedX + elseif flip_y then + flip = playdate.graphics.kImageFlippedY + end + img:draw(x, y, flip) + +end + +function mget(celx, cely) + + local i = (celx % 128) + (cely * 128) + 1 + return mapData[i] + +end + + +function fget(n, f) + + if f ~= nil then + return spritesFlags[n+1] == f + else + return spritesFlags[n+1] + end + +end + +function map(celx, cely, sx, sy, celw, celh, layer) + + for cx=0,celw-1 do + for cy=0,celh-1 do + local i = mget(celx + cx, cely + cy) + 1 + local img = sprites:getImage(i) + local x = sx + (cx * 8) + local y = sy + (cy * 8) + if layer ~= nil and fget(i) == layer then + img:draw(x, y) + else + img:draw(x, y) + end + end + end + +end + +function pal(c0, c1, p) + + -- TODO + +end + +function music() + + -- TODO + +end + +function sfx() + + -- TODO + +end + +function camera(x, y) + + x = x or 0 + y = y or 0 + playdate.display.setOffset(x, y) + +end + +function count(tbl) + + return #tbl + +end + +function _print(text, x, y, color) + + x = x or 0 + y = y or 0 + if col == nil then + playdate.graphics.setImageDrawMode(playdate.graphics.kDrawModeFillWhite) + end + playdate.graphics.drawText(text, x, y) + if col == nil then + playdate.graphics.setImageDrawMode(playdate.graphics.kDrawModeCopy) + end + +end \ No newline at end of file diff --git a/Source/main.lua b/Source/main.lua new file mode 100644 index 0000000..a6b625b --- /dev/null +++ b/Source/main.lua @@ -0,0 +1,31 @@ +import "CoreLibs/object" +import "CoreLibs/graphics" +import "CoreLibs/sprites" +import "CoreLibs/timer" +import "CoreLibs/ui" +import "CoreLibs/crank" + +import "Scripts/pico-8.lua" +import "Scripts/celeste.lua" + +math.randomseed(playdate.getSecondsSinceEpoch()) +playdate.display.setScale(2) + +-- playdate.graphics.sprite.setBackgroundDrawingCallback( +-- function(x, y, width, height) +-- _draw() +-- end +-- ) + +_init() + +function playdate.update() + + playdate.timer.updateTimers() + -- playdate.graphics.sprite.update() + _update() + -- playdate.graphics.clear(playdate.graphics.kColorBlack) + _draw() + playdate.drawFPS(0, 0) + +end \ No newline at end of file diff --git a/Support/classic.lua b/Support/classic.lua new file mode 100644 index 0000000..a38771b --- /dev/null +++ b/Support/classic.lua @@ -0,0 +1,1429 @@ +-- ~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 diff --git a/Support/map.png b/Support/map.png new file mode 100644 index 0000000..4607667 Binary files /dev/null and b/Support/map.png differ diff --git a/Support/spritesheet.png b/Support/spritesheet.png new file mode 100644 index 0000000..b369275 Binary files /dev/null and b/Support/spritesheet.png differ