... and shadows for the level tiles. It costs about 15 fps on my pc adding shadows for the level, but I've added in a timer system for all moving objects, so things should all move at a constant speed regardless of changes in frame rate.
As for the doodads casting shadows over the edges of tiles, I'm afraid my simple solution for that is to keep them all to the same, lower height. I know this counters some of the work already done, but as I mentioned before, it also solves the problem of having to change height to kill the doodads. From a top down perspective, I think it's too difficult to gauge the height, besides the fact that with one hand on the arrow keys and one on the fire button, there is no spare hand for adjusting height anyway! I'd suggest if we want to have just two different heights, like one for doodads and ground patrols, and another for enemy aircraft, we have a 'toggle height' key, as they did in Xenon, which makes it easy to switch between the two heights.
For 'ground' units, I'd suggest adding some more larger areas of tiles for them to patrol, and keeping the background as a background. Getting sprites to move underneath the level tiles would mean converting all pasted sprites back to active sprites, which would kill the frame rate again.
I've toned down the enemy fire somewhat, and think it's probably now close to the right difficulty.
Here's the new code:
sync on:sync rate 0:hide mouse
`set display mode 800,600,32
set image colorkey 255,0,255
disect("player ship.bmp",4,2,1)
disect("player weapons.bmp",5,4,10)
disect("explosion32.png",16,1,50)
disect("numbers.bmp",10,1,30)
load image "uibar.bmp",5001
load image "building1.bmp",6000
load music "ng1975.mp3",1
for a = 8 to 15
sprite a,-100,-100,19
next a
type ship
xpos as integer
ypos as integer
height as integer
animation_time as integer
animation_step as integer
animation_frame as integer
start_frame as integer
end_frame as integer
next_move as integer
shadow as integer
next_fire as integer
fire_speed as integer
sprite_number as integer
shadow_number as integer
gun_strength as integer
vulnerable as integer
endtype
type tile
spritenumber as integer
imagetype as integer
imagename as string
y as float
occupied as integer
endtype
type tileimage
imagenumber as integer
imagetype as string
spriteID as integer
endtype
type doodad
xpos as integer
image as integer
ypos as float
height as integer
sprite_number as integer
shadow as integer
points as integer
endtype
type effect
xpos as integer
ypos as integer
frame as integer
start_frame as integer
end_frame as integer
next_frame as integer
sprite_number as integer
endtype
type bullettype
active as integer
spritenumber as integer
xpos as float
ypos as float
angle as float
heatseeking as integer
life as integer
endtype
dim explosion(-1) as effect
dim object_tile(-1) as doodad
dim perm_object_tile(-1) as doodad
global player as ship
dim player_missile(-1) as ship
#CONSTANT BACKGROUND_IMAGE=5000
#CONSTANT CLOUD_IMAGE=5002
#CONSTANT TREES_IMAGE=5003
global background_scroll as float
global background_scroll_rate as float
background_scroll_rate=0.6
global cloud_scroll as float
global cloud_scroll_rate as float
cloud_scroll_rate=1.22
global tree_scroll as float
global tree_scroll_rate as float
tree_scroll_rate=0.6
level=1
global spriteseed
spriteseed=10
global numberofrows
global tilespeed#
global SCORE
tilespeed#=1 `best to keep this as an integer, as it represents the number of pixels to scroll each loop
global shipspeed#
shipspeed#=3
global numberofbullets as integer
global bulletimage as integer
global bulletspeed# as float
bulletspeed#=2
global tileshadow
global dt as float
global missilespeed#
missilespeed#=3
make_tile_shadow()
make_bullet()
set_player()
make_temp_background()
load_level(level)
player.vulnerable=timer()+2000
loop music 1
starttime=timer()
do
newtime=timer()-starttime
dt=(newtime-oldtime)*.05
oldtime=newtime
`display fps - update once every 10 loops to reduce hit
fps=screen fps()
inc textcounter
if textcounter=10 then textcounter=0
if textcounter=0 then text_sprite(2000,0,0,str$(fps))
cls
draw_background()
scroll_tiles()
player_state()
if array count(object_tile())>=0 then scroll_doodads()
if array count(perm_object_tile())>=0 then scroll_perm_doodads()
if array count(explosion())>=0 then draw_explosions()
animate_player()
draw_player()
test_features()
if array count(player_missile())>=0 then draw_missiles()
`if timer()>player.next_move
controls()
player.next_move=timer()+3
`endif
doodad_attack()
move_bullets()
sync
loop
function text_sprite(entity,x,y,text$)
if text$="" then text$=" "
If Bitmap Exist(2)=0
create bitmap 2,screen width()/2,screen height()/8
Else
Set Current Bitmap 2
cls
Endif
ink rgb(1,250,1),0
set text size 14
set text font "Arial"
text 0,0,text$
if image exist(entity) then delete image entity
if sprite exist(entity) then delete sprite entity
get image entity,0,0,text width(text$),text height(text$),1
sprite entity,x,y,entity
set sprite entity,0,0
set sprite priority entity,300
Set Current Bitmap 0
`endif
endfunction
function make_tile_shadow()
tileshadow=free_sprite()
load image "shadow.png",tileshadow
sprite tileshadow,-100,-100,tileshadow
set sprite tileshadow,0,1
set sprite alpha tileshadow,150
endfunction
function load_level(level)
`The level is made up of tiles. Each tile is a 64x64 sprite, and has a sprite number
`which links to the array 'tile(column,row).spritenumber'.
`Each sprite also has an image identifier, which is made of two characters, stored
`in 'tile(column,row).imagetype'.
`for example, if it has the tile image "t2.png", then the identifier is tile(column,row)="t2"
`The level file "level1.txt", where the '1' can be any level number is a text file with the following format:
`1st line is a header, and contains the names of all the images it need to load
`All other lines represent the tiles' column, row and image. If it is 't0' it is an empty space.
`A comma is used to separate tiles - including a comma at the end of each row.
open to read 1,"level"+str$(level)+".txt"
`Read header. The header contains the image types used in the level
read string 1,header$
numberoftileimages=len(header$)/3
dim tileimage(numberoftileimages) as tileimage
for n=1 to numberoftileimages
chunk=n*3
image$=left$(right$(left$(header$,chunk),3),2) `parse the string: this takes the left 2 characters (to get rid of the comma) of the right 3 (ie. the end bit) of the left 'chunk' (the chunk is increased in steps of 3)
if image$<>"" and image$<>"t0"
tileimage(n).imagenumber=free_image()
tileimage(n).spriteID=free_sprite()
tileimage(n).imagetype=image$
load image image$+".png",tileimage(n).imagenumber,1
sprite tileimage(n).spriteID,-100,-100,tileimage(n).imagenumber
endif
next n
row=0
repeat
`scan through each subsequent row of the text file to get tile type and position
inc row
numberofrows=row
dim tile(13,row) as tile
read string 1,string$
`scan through each column of the text file
for column=1 to 13 `there are 13 columns, made up of 3 characters each (2 letters and a comma)
chunk=column*3
image$=left$(right$(left$(string$,chunk),3),2) `Parse the string: this takes the left 2 characters (to get rid of the comma) of the right 3 (ie. the end bit) of the left 'chunk' (the chunk is increased in steps of 3)
if image$<>"" and image$<>"t0"
tile(column,row).spritenumber=free_sprite()
image=0
for n=1 to numberoftileimages
if image$=tileimage(n).imagetype
imagenumber=tileimage(n).imagenumber
image=n
Exit
Endif
next n
`as we don't know how big the level is until this loop has finished, we don't know where to position the tiles yet,
`so we'll put them at 0,0 for the time being
`sprite tile(column,row).spritenumber,0,0,imagenumber
tile(column,row).imagetype=image
tile(column,row).imagename=image$
endif
next column$
until file end(1)=1
`go through tiles again. This time, now that we know the total number of rows, we can position the tiles correctly
for column=1 to 13
for row=1 to numberofrows
`if there is a tile at that coordinate
if (tile(column,row).spritenumber)>0
tile(column,row).y=(row-1)*64-(numberofrows*64)+(9*64)
`sprite tile(column,row).spritenumber,(column-1)*64-13,tile(column,row).y,sprite image(tile(column,row).spritenumber)
`set sprite tile(column,row).spritenumber,1,0
endif
next row
next column
endfunction
function scroll_tiles()
for row=1 to numberofrows
for column=1 to 13
spriteID=tileimage(tile(column,row).imagetype).spriteID
if spriteID>0
`imageID=tileimage(tile(column,row).imagetype).imagenumber
tile(column,row).y=tile(column,row).y+tilespeed#*dt
if tile(column,row).y>-114 and tile(column,row).y<screen height()-114
paste sprite tileshadow,(column-1)*64-16+50,tile(column,row).y+50
endif
if tile(column,row).y>-64 and tile(column,row).y<screen height()-64
Paste sprite SpriteID,(column-1)*64-16,tile(column,row).y
if left$(tile(column,row).imagename,1)="d" and tile(column,row).occupied=0
tile(column,row).occupied=1
make_new_object((column-1)*64,tile(column,row).y+16,6,100,6000)
endif
endif
endif
next column
next row
endfunction
function set_player()
player.xpos=(screen width()-32)/2
player.ypos= screen height()-115
player.height =6
player.animation_step=50
player.animation_time=timer()+player.animation_step
player.animation_frame=1
player.start_frame=1
player.end_frame=4
player.next_move=timer()+3
player.shadow=5
player.next_fire=timer()
player.fire_speed=100
endfunction
function animate_player()
if timer()>player.animation_time
inc player.animation_frame
if player.animation_frame>player.end_frame then player.animation_frame=player.start_frame
player.animation_time=timer()+player.animation_step
endif
endfunction
function draw_player()
sprite 1,player.xpos,player.ypos,player.animation_frame
sprite 2,player.xpos+(player.height/2)+2,player.ypos+player.height+2,player.shadow
set sprite priority 1,5+player.height
set sprite priority 2,4+player.height
set sprite alpha 2,80-player.height
scale sprite 1,85+player.height/2
scale sprite 2,85+player.height/1.5
if sprite collision(1,0)>2 then check_player_collision()
endfunction
function disect(filename as string,across,down,imagestart)
load bitmap filename,1
x=bitmap width(1)/across
y=bitmap height(1)/down
for a = 0 to down-1
for b = 0 to across-1
get image imagestart+a*across+b,x*b,y*a,x*b+x,y*a+y
next b:next a
delete bitmap 1
endfunction
function controls()
if upkey()=1 then dec player.ypos,shipspeed#*dt
if downkey()=1 then inc player.ypos,shipspeed#*dt
if leftkey()=1 then dec player.xpos,shipspeed#*dt
if rightkey()=1 then inc player.xpos,shipspeed#*dt
if keystate(31)=1 then inc player.height,1
if keystate(17)=1 then dec player.height,1
if spacekey()=1 and timer()>player.next_fire then add_missile(8)
if player.height<6 then player.height=6
if player.height>30 then player.height=30
if player.xpos<5 then player.xpos=5
if player.xpos>screen width()-37 then player.xpos=screen width()-37
if player.ypos>screen height()-115 then player.ypos=screen height()-115
if player.ypos<128 then player.ypos=128
endfunction
function make_temp_background()
load image "BackGround.png",BACKGROUND_IMAGE,1
load image "Clouds.png",CLOUD_IMAGE,1
load image "Trees.png",TREES_IMAGE,1
endfunction
function draw_background()
paste image BACKGROUND_IMAGE,0,background_scroll
paste image BACKGROUND_IMAGE,0,background_scroll+screen height()*2
inc background_scroll,background_scroll_rate*dt
if background_scroll>screen_height*2 then dec background_scroll,screen height()*2
paste image TREES_IMAGE,0,tree_scroll,1
paste image TREES_IMAGE,0,tree_scroll+screen height()*1.5,1
inc tree_scroll,tree_scroll_rate*dt
if tree_scroll>screen_height*1.5 then dec tree_scroll,screen height()*1.5
sprite CLOUD_IMAGE,0,cloud_scroll,CLOUD_IMAGE
sprite CLOUD_IMAGE+1,0,cloud_scroll+screen height()*1.5,CLOUD_IMAGE
set sprite priority CLOUD_IMAGE,30
set sprite priority CLOUD_IMAGE+1,30
inc cloud_scroll,cloud_scroll_rate*dt
if cloud_scroll>screen_height*1.5 then dec cloud_scroll,screen height()*1.5
sprite 3,0,522,5001
set sprite 3,0,1
set sprite priority 3,100
score$=str$(score)
for a = len(score$) to 1 step -1
value=val(mid$(score$,a))
if value=0 then value=10
sprite 8+a,751-((len(score$)-a)*16),554,29+value
set sprite priority 8+a,110
next a
endfunction
function add_missile(offset)
array insert at top player_missile()
player_missile(0).xpos=player.xpos+offset
player_missile(0).ypos=player.ypos-16
player_missile(0).height=player.height
player_missile(0).start_frame=10
player_missile(0).end_frame=13
player_missile(0).animation_step=50
player_missile(0).animation_time=timer()+50
player_missile(0).animation_frame=10
player_missile(0).shadow=14
player_missile(0).sprite_number=free_sprite()
sprite player_missile(0).sprite_number,player_missile(0).xpos,player_missile(0).ypos,player_missile(0).animation_frame
player_missile(0).shadow_number=free_sprite()
sprite player_missile(0).shadow_number,player_missile(0).xpos+(player_missile(0).height/2),player_missile(0).ypos+player_missile(0).height,player_missile(0).shadow
set sprite alpha player_missile(0).shadow_number,80-player_missile(0).height
set sprite priority player_missile(0).sprite_number,50
set sprite priority player_missile(0).shadow_number,40
player.next_fire=timer()+player.fire_speed
endfunction
function draw_missiles()
for a = array count(player_missile()) to 0 step -1
dec player_missile(a).ypos,missilespeed#*dt
if timer()>player_missile(a).animation_time
inc player_missile(a).animation_frame
if player_missile(a).animation_frame>player_missile(a).end_frame then player_missile(a).animation_frame=player_missile(a).start_frame
player_missile(a).animation_time=timer()+player_missile(a).animation_step
endif
sprite player_missile(a).sprite_number,player_missile(a).xpos,player_missile(a).ypos,player_missile(a).animation_frame
sprite player_missile(a).shadow_number,player_missile(a).xpos+(player_missile(a).height/2),player_missile(a).ypos+player_missile(a).height,player_missile(a).shadow
set sprite alpha player_missile(a).shadow_number,80-player_missile(a).height
set sprite priority player_missile(a).sprite_number,player_missile(a).height+5
set sprite priority player_missile(a).shadow_number,player_missile(a).height+4
if player_missile(a).ypos<-16
kill_missile(a)
else
if array count(perm_object_tile())>=0 then check_shot_object_collision(a)
endif
next a
endfunction
function check_shot_object_collision(count)
hit=sprite collision(player_missile(count).sprite_number,0)
if hit=0 then exitfunction
for a = array count(perm_object_tile()) to 0 step -1
if sprite collision(player_missile(count).sprite_number,perm_object_tile(a).sprite_number)=1 and player_missile(count).height<=perm_object_tile(a).height
add_explosion(player_missile(count).xpos-8,player_missile(count).ypos-8)
kill_missile(count)
inc score,perm_object_tile(a).points
kill_doodad(a)
exitfunction
endif
next a
endfunction
function doodad_attack()
count=array count(perm_object_tile())
for n=1 to count
bearing#=get_bearing(perm_object_tile(n).xpos,perm_object_tile(n).ypos,player.xpos,player.ypos)
firingangle#=bearing#+rnd(20)-10
if rnd(400)=0 then fire_bullet(perm_object_tile(n).xpos,perm_object_tile(n).ypos,firingangle#)
if rnd(2000)=0 then fire_heatseeker(perm_object_tile(n).xpos,perm_object_tile(n).ypos,firingangle#)
next n
endfunction
function make_bullet()
bulletimage=free_image()
load image "bullet.png",bulletimage,1
endfunction
function fire_bullet(startx,starty,angle#)
inc numberofbullets
bulletnumber=numberofbullets
dim bullet(numberofbullets) as bullettype
bullet(bulletnumber).spritenumber=free_sprite()
sprite bullet(bulletnumber).spritenumber,startx,starty,bulletimage
offset sprite bullet(bulletnumber).spritenumber,sprite width(bullet(bulletnumber).spritenumber)/2,sprite height(bullet(bulletnumber).spritenumber)/2
bullet(bulletnumber).active=1
bullet(bulletnumber).xpos=startx
bullet(bulletnumber).ypos=starty
bullet(bulletnumber).angle=angle#
bullet(bulletnumber).life=200
endfunction
function fire_heatseeker(startx,starty,angle#)
inc numberofbullets
bulletnumber=numberofbullets
dim bullet(numberofbullets) as bullettype
bullet(bulletnumber).spritenumber=free_sprite()
sprite bullet(bulletnumber).spritenumber,startx,starty,bulletimage
set sprite diffuse bullet(bulletnumber).spritenumber,255,0,0
offset sprite bullet(bulletnumber).spritenumber,sprite width(bullet(bulletnumber).spritenumber)/2,sprite height(bullet(bulletnumber).spritenumber)/2
bullet(bulletnumber).active=1
bullet(bulletnumber).xpos=startx
bullet(bulletnumber).ypos=starty
bullet(bulletnumber).angle=angle#
bullet(bulletnumber).heatseeking=1
bullet(bulletnumber).life=200
endfunction
function move_bullets()
for bulletnumber=1 to numberofbullets
if bullet(bulletnumber).active=1
`if heatseeking, update direction and move along new path
if bullet(bulletnumber).heatseeking=1
bullet(bulletnumber).angle=get_bearing(bullet(bulletnumber).xpos,bullet(bulletnumber).ypos,player.xpos,player.ypos)
inc bullet(bulletnumber).xpos,bulletspeed#*1.2*sin(bullet(bulletnumber).angle)*dt
inc bullet(bulletnumber).ypos,bulletspeed#*1.2*cos(bullet(bulletnumber).angle)*dt
else
`otherwise, update position along same path
inc bullet(bulletnumber).xpos,bulletspeed#*sin(bullet(bulletnumber).angle)*dt
inc bullet(bulletnumber).ypos,bulletspeed#*cos(bullet(bulletnumber).angle)*dt
endif
`move all bullets down to account for background scrolling
inc bullet(bulletnumber).ypos,tilespeed#
`draw the bullet in its new position
sprite bullet(bulletnumber).spritenumber,bullet(bulletnumber).xpos,bullet(bulletnumber).ypos,bulletimage
`decrease the lifespan of the bullet and fade accordingly
dec bullet(bulletnumber).life,1.0*dt
set sprite alpha bullet(bulletnumber).spritenumber,int(bullet(bulletnumber).life*255/200.0)
`kill bullet if lifespan over
if bullet(bulletnumber).life<=10
delete sprite bullet(bulletnumber).spritenumber
bullet(bulletnumber).active=0
endif
`kill bullet if outside of screen range
if bullet(bulletnumber).active=1
if bullet(bulletnumber).ypos>screen height() or bullet(bulletnumber).ypos<0 or bullet(bulletnumber).xpos>screen width() or bullet(bulletnumber).xpos<0
delete sprite bullet(bulletnumber).spritenumber
bullet(bulletnumber).active=0
endif
endif
`check for collision between bullet and player
if bullet(bulletnumber).active=1
if sprite collision(1,bullet(bulletnumber).spritenumber)=1
add_explosion(player.xpos,player.ypos)
kill_player()
delete sprite bullet(bulletnumber).spritenumber
bullet(bulletnumber).active=0
endif
endif
endif
next bulletnumber
endfunction
function kill_missile(count)
delete sprite player_missile(count).sprite_number
delete sprite player_missile(count).shadow_number
array delete element player_missile(),count
endfunction
`temporary function to test added features
function test_features()
if inkey$()="1" then player.gun_strength=1
if inkey$()="2" then player.gun_strength=2
if inkey$()="3" then player.gun_strength=3
if inkey$()="=" then add_explosion(rnd(screen width()),rnd(screen height())):add_explosion(rnd(screen width()),rnd(screen height()))
endfunction
function add_doodad(xpos,ypos,image)
array insert at bottom object_tile()
count=array count(object_tile())
object_tile(count).xpos=xpos
object_tile(count).ypos=ypos
object_tile(count).image=image
endfunction
function scroll_doodads()
for a = array count(object_tile()) to 0 step -1
if object_tile(a).ypos<=DISTANCE_TRAVELLED-32
make_new_object(object_tile(a).xpos,object_tile(a).ypos-DISTANCE_TRAVELLED-32,object_tile(a).height,object_tile(a).points,object_tile(a).image)
array delete element object_tile(),a
endif
next a
endfunction
function make_new_object(xpos,ypos,height,points,image)
array insert at bottom perm_object_tile()
count=array count(perm_object_tile())
perm_object_tile(count).xpos=xpos
perm_object_tile(count).ypos=ypos
perm_object_tile(count).image=image
perm_object_tile(count).height=height
perm_object_tile(count).points=points
perm_object_tile(count).sprite_number=free_sprite()
sprite perm_object_tile(count).sprite_number,perm_object_tile(count).xpos,perm_object_tile(count).ypos,perm_object_tile(count).image
Set Sprite Priority perm_object_tile(count).sprite_number,perm_object_tile(count).height
perm_object_tile(count).shadow=free_sprite()
Sprite perm_object_tile(count).shadow,perm_object_tile(count).xpos,perm_object_tile(count).ypos,perm_object_tile(count).image
Set Sprite Diffuse perm_object_tile(count).shadow,0,0,0
Set Sprite Alpha perm_object_tile(count).shadow,50
Set Sprite Priority perm_object_tile(count).shadow,perm_object_tile(count).height-1
endfunction
function scroll_perm_doodads()
for a = array count(perm_object_tile()) to 0 step -1
h=perm_object_tile(a).height
sprite perm_object_tile(a).sprite_number,perm_object_tile(a).xpos,perm_object_tile(a).ypos,perm_object_tile(a).image
Scale Sprite perm_object_tile(a).sprite_number,85+h
sprite perm_object_tile(a).shadow,perm_object_tile(a).xpos+4,perm_object_tile(a).ypos+4,perm_object_tile(a).image
Scale Sprite perm_object_tile(a).shadow,85+h*2
inc perm_object_tile(a).ypos,tilespeed#*dt
if perm_object_tile(a).ypos>screen height() then kill_doodad(a)
next a
endfunction
function kill_doodad(count)
if sprite exist(perm_object_tile(count).sprite_number)=1 then delete sprite perm_object_tile(count).sprite_number
if sprite exist(perm_object_tile(count).shadow)=1 then delete sprite perm_object_tile(count).shadow
array delete element perm_object_tile(),count
endfunction
function free_sprite()
count=spriteseed
repeat
inc count
until sprite exist(count)=0
endfunction count
function free_image()
repeat
inc count
until image exist(count)=0
endfunction count
function add_explosion(xpos,ypos)
array insert at bottom explosion()
count=array count(explosion())
explosion(count).xpos=xpos
explosion(count).ypos=ypos
explosion(count).frame=50
explosion(count).start_frame=50
explosion(count).end_frame=65
explosion(count).next_frame=timer()+50
explosion(count).sprite_number=free_sprite()
sprite explosion(count).sprite_number,explosion(count).xpos,explosion(count).ypos,explosion(count).frame
endfunction
function draw_explosions()
for a = array count(explosion()) to 0 step -1
if timer()>explosion(a).next_frame
inc explosion(a).frame
explosion(a).next_frame=timer()+50
endif
sprite explosion(a).sprite_number,explosion(a).xpos,explosion(a).ypos,explosion(a).frame
if explosion(a).frame>=explosion(a).end_frame then kill_explosion(a)
next a
endfunction
function kill_explosion(count)
if sprite exist(explosion(count).sprite_number) then delete sprite explosion(count).sprite_number
array delete element explosion(),count
endfunction
function check_player_collision()
if player.vulnerable<=timer()
if array count(perm_object_tile())>=0
for a = array count(perm_object_tile()) to 0 step -1
if player.height<=perm_object_tile(a).height
if sprite collision(1,perm_object_tile(a).sprite_number)=1
kill_doodad(a)
add_explosion(player.xpos,player.ypos)
kill_player()
exitfunction
endif
endif
next a
endif
endif
endfunction
function player_state()
if player.vulnerable>timer()
player.start_frame=6:player.end_frame=8
else
player.start_frame=1:player.end_frame=4
endif
endfunction
function kill_player()
player.xpos=(screen width()-32)/2
player.ypos= screen height()-115
player.vulnerable=timer()+3000
endfunction
function get_bearing(x1#,y1#,x2#,y2#)
ang#=atanfull((x2#-x1#),(y2#-y1#))
endfunction ang#
and the new level:
t0,t1,t2,d1,r1,
t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,
t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
t0,d1,d1,d1,d1,d1,t0,d1,d1,d1,d1,d1,t0,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
t1,d1,d1,d1,d1,d1,t0,d1,d1,d1,d1,d1,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,d1,d1,d1,d1,d1,t0,d1,d1,d1,d1,d1,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t0,t0,t1,t0,t0,t0,t1,t0,t0,t0,t1,t0,t0,
t0,t0,t1,t0,t0,t0,t1,t0,t0,t0,t1,t0,t0,
d1,t0,t1,t0,t0,t0,t1,t0,t0,t0,t1,t0,d1,
t0,t0,t1,t0,t0,t0,t2,t0,t0,t0,t1,t0,t0,
d1,t0,t1,t0,t0,t0,t1,t0,t0,t0,t1,t0,d1,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
d1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,d1,
t0,t0,t1,d1,t0,t0,t2,t0,t0,d1,t1,t0,t0,
t0,t0,t1,d1,t0,t0,t1,t0,t0,d1,t1,t0,t0,
t0,t0,t1,d1,t0,t0,t2,t0,t0,d1,t1,t0,t0,
t0,t0,t1,d1,t0,t0,t1,t0,t0,d1,t1,t0,t0,
t0,t0,t1,d1,t0,t0,t2,t0,t0,d1,t1,t0,t0,
t0,t0,t0,t0,t0,t1,t1,t1,t0,t0,t0,t0,t0,
t0,d1,d1,t0,t0,t1,t2,t1,t0,t0,d1,d1,t0,
t0,d1,d1,t0,t0,t1,t1,t1,t0,t0,d1,d1,t0,
t0,d1,d1,t0,t0,t0,t0,t0,t0,t0,d1,d1,t0,
t0,t0,t0,t0,d1,d1,d1,d1,d1,t0,t0,t0,t0,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
t0,t0,t0,t0,d1,d1,d1,d1,d1,t0,t0,t0,t0,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
t0,t0,t0,t0,t0,t1,t1,t1,t0,t0,t0,t0,t0,
t0,t0,d1,t0,t0,t1,t2,t1,t0,t0,d1,t0,t0,
t0,t0,t0,t0,t0,t1,t1,t1,t0,t0,t0,t0,t0,
t1,t0,t0,t0,t0,t1,t1,t1,t0,t0,t0,t0,t1,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
t0,d1,d1,t0,t0,t0,t0,t0,t0,t0,d1,d1,t0,
t0,d1,d1,t0,t0,t0,t0,t0,t0,t0,d1,d1,t0,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
t1,t0,t0,t0,t0,t1,t1,t1,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,d1,d1,d1,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t1,t0,t0,t1,t1,t1,t1,t1,t0,t0,t1,t1,
t1,t0,t0,t0,t1,t2,t2,t2,t1,t0,t0,t1,t1,
t1,t0,t0,t0,t1,t1,t1,t1,t1,t0,t0,t1,t1,
t1,t0,d1,t0,t0,t0,t0,t0,t0,t0,d1,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,
t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,
t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,
t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
t0,d1,d1,d1,d1,d1,t0,d1,d1,d1,d1,d1,t0,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
t1,d1,d1,d1,d1,d1,t0,d1,d1,d1,d1,d1,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,d1,d1,d1,d1,d1,t0,d1,d1,d1,d1,d1,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t0,t0,t1,t0,t0,t0,t1,t0,t0,t0,t1,t0,t0,
t0,t0,t1,t0,t0,t0,t1,t0,t0,t0,t1,t0,t0,
d1,t0,t1,t0,t0,t0,t1,t0,t0,t0,t1,t0,d1,
t0,t0,t1,t0,t0,t0,t2,t0,t0,t0,t1,t0,t0,
d1,t0,t1,t0,t0,t0,t1,t0,t0,t0,t1,t0,d1,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
d1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,d1,
t0,t0,t1,d1,t0,t0,t2,t0,t0,d1,t1,t0,t0,
t0,t0,t1,d1,t0,t0,t1,t0,t0,d1,t1,t0,t0,
t0,t0,t1,d1,t0,t0,t2,t0,t0,d1,t1,t0,t0,
t0,t0,t1,d1,t0,t0,t1,t0,t0,d1,t1,t0,t0,
t0,t0,t1,d1,t0,t0,t2,t0,t0,d1,t1,t0,t0,
t0,t0,t0,t0,t0,t1,t1,t1,t0,t0,t0,t0,t0,
t0,d1,d1,t0,t0,t1,t2,t1,t0,t0,d1,d1,t0,
t0,d1,d1,t0,t0,t1,t1,t1,t0,t0,d1,d1,t0,
t0,d1,d1,t0,t0,t0,t0,t0,t0,t0,d1,d1,t0,
t0,t0,t0,t0,d1,d1,d1,d1,d1,t0,t0,t0,t0,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
t0,t0,t0,t0,d1,d1,d1,d1,d1,t0,t0,t0,t0,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
t0,t0,t0,t0,t0,t1,t1,t1,t0,t0,t0,t0,t0,
t0,t0,d1,t0,t0,t1,t2,t1,t0,t0,d1,t0,t0,
t0,t0,t0,t0,t0,t1,t1,t1,t0,t0,t0,t0,t0,
t1,t0,t0,t0,t0,t1,t1,t1,t0,t0,t0,t0,t1,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
t0,d1,d1,t0,t0,t0,t0,t0,t0,t0,d1,d1,t0,
t0,d1,d1,t0,t0,t0,t0,t0,t0,t0,d1,d1,t0,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
t1,t0,t0,t0,t0,t1,t1,t1,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,d1,d1,d1,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t1,t0,t0,t1,t1,t1,t1,t1,t0,t0,t1,t1,
t1,t0,t0,t0,t1,t2,t2,t2,t1,t0,t0,t1,t1,
t1,t0,t0,t0,t1,t1,t1,t1,t1,t0,t0,t1,t1,
t1,t0,d1,t0,t0,t0,t0,t0,t0,t0,d1,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,
t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,
t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,
t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
t0,d1,d1,d1,d1,d1,t0,d1,d1,d1,d1,d1,t0,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
t1,d1,d1,d1,d1,d1,t0,d1,d1,d1,d1,d1,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,d1,d1,d1,d1,d1,t0,d1,d1,d1,d1,d1,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t0,t0,t1,t0,t0,t0,t1,t0,t0,t0,t1,t0,t0,
t0,t0,t1,t0,t0,t0,t1,t0,t0,t0,t1,t0,t0,
d1,t0,t1,t0,t0,t0,t1,t0,t0,t0,t1,t0,d1,
t0,t0,t1,t0,t0,t0,t2,t0,t0,t0,t1,t0,t0,
d1,t0,t1,t0,t0,t0,t1,t0,t0,t0,t1,t0,d1,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
d1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,d1,
t0,t0,t1,d1,t0,t0,t2,t0,t0,d1,t1,t0,t0,
t0,t0,t1,d1,t0,t0,t1,t0,t0,d1,t1,t0,t0,
t0,t0,t1,d1,t0,t0,t2,t0,t0,d1,t1,t0,t0,
t0,t0,t1,d1,t0,t0,t1,t0,t0,d1,t1,t0,t0,
t0,t0,t1,d1,t0,t0,t2,t0,t0,d1,t1,t0,t0,
t0,t0,t0,t0,t0,t1,t1,t1,t0,t0,t0,t0,t0,
t0,d1,d1,t0,t0,t1,t2,t1,t0,t0,d1,d1,t0,
t0,d1,d1,t0,t0,t1,t1,t1,t0,t0,d1,d1,t0,
t0,d1,d1,t0,t0,t0,t0,t0,t0,t0,d1,d1,t0,
t0,t0,t0,t0,d1,d1,d1,d1,d1,t0,t0,t0,t0,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
t0,t0,t0,t0,d1,d1,d1,d1,d1,t0,t0,t0,t0,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
t0,t0,t0,t0,t0,t1,t1,t1,t0,t0,t0,t0,t0,
t0,t0,d1,t0,t0,t1,t2,t1,t0,t0,d1,t0,t0,
t0,t0,t0,t0,t0,t1,t1,t1,t0,t0,t0,t0,t0,
t1,t0,t0,t0,t0,t1,t1,t1,t0,t0,t0,t0,t1,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
t0,d1,d1,t0,t0,t0,t0,t0,t0,t0,d1,d1,t0,
t0,d1,d1,t0,t0,t0,t0,t0,t0,t0,d1,d1,t0,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
t1,t0,t0,t0,t0,t1,t1,t1,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,d1,d1,d1,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t1,t0,t0,t1,t1,t1,t1,t1,t0,t0,t1,t1,
t1,t0,t0,t0,t1,t2,t2,t2,t1,t0,t0,t1,t1,
t1,t0,t0,t0,t1,t1,t1,t1,t1,t0,t0,t1,t1,
t1,t0,d1,t0,t0,t0,t0,t0,t0,t0,d1,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,
t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,
t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,
t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,t1,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
t0,d1,d1,d1,d1,d1,t0,d1,d1,d1,d1,d1,t0,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
t1,d1,d1,d1,d1,d1,t0,d1,d1,d1,d1,d1,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,d1,d1,d1,d1,d1,t0,d1,d1,d1,d1,d1,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t0,t0,t1,t0,t0,t0,t1,t0,t0,t0,t1,t0,t0,
t0,t0,t1,t0,t0,t0,t1,t0,t0,t0,t1,t0,t0,
d1,t0,t1,t0,t0,t0,t1,t0,t0,t0,t1,t0,d1,
t0,t0,t1,t0,t0,t0,t2,t0,t0,t0,t1,t0,t0,
d1,t0,t1,t0,t0,t0,t1,t0,t0,t0,t1,t0,d1,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
d1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,d1,
t0,t0,t1,d1,t0,t0,t2,t0,t0,d1,t1,t0,t0,
t0,t0,t1,d1,t0,t0,t1,t0,t0,d1,t1,t0,t0,
t0,t0,t1,d1,t0,t0,t2,t0,t0,d1,t1,t0,t0,
t0,t0,t1,d1,t0,t0,t1,t0,t0,d1,t1,t0,t0,
t0,t0,t1,d1,t0,t0,t2,t0,t0,d1,t1,t0,t0,
t0,t0,t0,t0,t0,t1,t1,t1,t0,t0,t0,t0,t0,
t0,d1,d1,t0,t0,t1,t2,t1,t0,t0,d1,d1,t0,
t0,d1,d1,t0,t0,t1,t1,t1,t0,t0,d1,d1,t0,
t0,d1,d1,t0,t0,t0,t0,t0,t0,t0,d1,d1,t0,
t0,t0,t0,t0,d1,d1,d1,d1,d1,t0,t0,t0,t0,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
t0,t0,t0,t0,d1,d1,d1,d1,d1,t0,t0,t0,t0,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
t0,t0,t0,t0,t0,t1,t1,t1,t0,t0,t0,t0,t0,
t0,t0,d1,t0,t0,t1,t2,t1,t0,t0,d1,t0,t0,
t0,t0,t0,t0,t0,t1,t1,t1,t0,t0,t0,t0,t0,
t1,t0,t0,t0,t0,t1,t1,t1,t0,t0,t0,t0,t1,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
t0,d1,d1,t0,t0,t0,t0,t0,t0,t0,d1,d1,t0,
t0,d1,d1,t0,t0,t0,t0,t0,t0,t0,d1,d1,t0,
t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,
t1,t0,t0,t0,t0,t1,t1,t1,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,d1,d1,d1,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t1,t0,t0,t1,t1,t1,t1,t1,t0,t0,t1,t1,
t1,t0,t0,t0,t1,t2,t2,t2,t1,t0,t0,t1,t1,
t1,t0,t0,t0,t1,t1,t1,t1,t1,t0,t0,t1,t1,
t1,t0,d1,t0,t0,t0,t0,t0,t0,t0,d1,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t0,t1,
t1,t0,t0,t0,t1,t1,r1,t1,t1,t0,t0,t1,t1,
t1,t0,t0,t0,t1,t1,r1,t1,t1,t0,t0,t1,t1,
t1,t0,t0,t0,t1,t1,r1,t1,t1,t0,t0,t1,t1,
t1,t0,t0,t0,t1,t1,r1,t1,t1,t0,t0,t1,t1,
t1,t1,t1,t1,t1,t1,r1,t1,t1,t1,t1,t1,t1,
t1,t0,t0,t0,t0,t0,t1,t0,t0,t0,t0,t0,t1,
