diff --git a/.gitignore b/.gitignore
index 3fd0032..b1a72d6 100644
--- a/.gitignore
+++ b/.gitignore
@@ -4,4 +4,5 @@ emu
*_Output.txt
src/GTETestApp
*.2mg
-Tool160.SHK
\ No newline at end of file
+Tool160.SHK
+src/Tool160
\ No newline at end of file
diff --git a/demos/kfest-2022/demo-1/App.Main.s b/demos/kfest-2022/demo-1/App.Main.s
index 2f76025..d4d740f 100644
--- a/demos/kfest-2022/demo-1/App.Main.s
+++ b/demos/kfest-2022/demo-1/App.Main.s
@@ -58,9 +58,11 @@ appTmp0 equ 28
; Load a tileset
- pea #^tiledata
- pea #tiledata
- _GTELoadTileSet
+; pea 0
+; pea 256
+; pea #^tiledata
+; pea #tiledata
+; _GTELoadTileSet
pea $0000
pea #^TileSetPalette
diff --git a/demos/tf4/.gitignore b/demos/tf4/.gitignore
new file mode 100644
index 0000000..6289069
--- /dev/null
+++ b/demos/tf4/.gitignore
@@ -0,0 +1 @@
+GTETF4
\ No newline at end of file
diff --git a/demos/tf4/App.Main.s b/demos/tf4/App.Main.s
new file mode 100644
index 0000000..1b530b0
--- /dev/null
+++ b/demos/tf4/App.Main.s
@@ -0,0 +1,126 @@
+; Test driver to exercise graphics routines.
+
+ REL
+ DSK MAINSEG
+
+ use Locator.Macs
+ use Load.Macs
+ use Mem.Macs
+ use Misc.Macs
+ use Util.Macs
+ use EDS.GSOS.Macs
+ use GTE.Macs
+
+ mx %00
+
+tiledata EXT ; tileset buffer
+;TileSetPalette EXT
+
+; Keycodes
+LEFT_ARROW equ $08
+RIGHT_ARROW equ $15
+UP_ARROW equ $0B
+DOWN_ARROW equ $0A
+
+; Direct page space
+MyUserId equ 0
+BankLoad equ 2
+StartX equ 4
+StartY equ 6
+TileMapWidth equ 8
+TileMapHeight equ 10
+ScreenWidth equ 12
+ScreenHeight equ 14
+MaxGlobalX equ 16
+MaxGlobalY equ 18
+MaxBG0X equ 20
+MaxBG0Y equ 22
+OldOneSecondCounter equ 26
+appTmp0 equ 28
+appTmp1 equ 30
+appTmp2 equ 32
+
+ phk
+ plb
+
+ sta MyUserId ; GS/OS passes the memory manager user ID for the application into the program
+ tdc
+ sta MyDirectPage ; Keep a copy for the overlay callback
+
+ _MTStartUp ; GTE requires the miscellaneous toolset to be running
+
+ lda #ENGINE_MODE_USER_TOOL+ENGINE_MODE_TWO_LAYER
+ jsr GTEStartUp ; Load and install the GTE User Tool
+
+ pea $0000 ; Set the first two tiles
+ pea $0002
+ pea #^TileData
+ pea #TileData
+ _GTELoadTileSet
+
+ pea $0000
+ pea #^TileSetPalette
+ pea #TileSetPalette
+ _GTESetPalette
+
+; Fill in the field with a checkboard pattern
+
+ stz appTmp1
+
+:tloop0 stz appTmp0
+:tloop1 lda appTmp0 ; X
+ pha
+ pei appTmp1 ; Y
+ eor appTmp1
+ and #$0001
+ pha ; tile ID
+ _GTESetTile
+
+ inc appTmp0
+ lda #40
+ cmp appTmp0
+ bcs :tloop1
+
+ inc appTmp1
+ lda #25
+ cmp appTmp1
+ bcs :tloop0
+
+; Set up a very specific test. First, we draw a sprite into the sprite plane, and then
+; leave it alone. We are just testing the ability to merge sprite plane data into
+; the play field tiles.
+EvtLoop
+ pha
+ _GTEReadControl
+ pla
+
+ jsr HandleKeys ; Do the generic key handlers
+
+ pea #RENDER_PER_SCANLINE ; Scanline rendering
+; pea $0000
+ _GTERender
+
+ brl EvtLoop
+
+; Exit code
+Exit
+ _GTEShutDown
+Quit
+ _QuitGS qtRec
+
+ bcs Fatal
+Fatal brk $00
+
+qtRec adrl $0000
+ da $00
+
+; Color palette
+TileSetPalette dw $0000,$0FFF,$0FFF,$0FFF,$0FFF,$0FFF,$0FFF,$0FFF,$0FFF,$0FFF,$0FFF,$0FFF,$0FFF,$0FFF,$0FFF,$0FFF
+
+MyDirectPage ds 2
+
+; Stub
+SetLimits rts
+
+ PUT ../kfest-2022/StartUp.s
+ PUT Tiles.s
diff --git a/demos/tf4/App.s b/demos/tf4/App.s
new file mode 100644
index 0000000..8e8c7c6
--- /dev/null
+++ b/demos/tf4/App.s
@@ -0,0 +1,10 @@
+; Thunder Force IV Demo
+
+ TYP $B3 ; S16 file
+ DSK GTETF4
+ XPL
+
+; Segment #1 -- Main execution block
+
+ ASM App.Main.s
+ SNA Main
diff --git a/demos/tf4/GTETF4 b/demos/tf4/GTETF4
new file mode 100644
index 0000000..1fa8df1
Binary files /dev/null and b/demos/tf4/GTETF4 differ
diff --git a/demos/tf4/README.txt b/demos/tf4/README.txt
new file mode 100644
index 0000000..8319771
--- /dev/null
+++ b/demos/tf4/README.txt
@@ -0,0 +1,3 @@
+Thunder Force IV scanline demo
+ - q to quit; arrows to scroll, numbers to select screen size
+ - make sure Overlay is present
\ No newline at end of file
diff --git a/demos/tf4/Tiles.s b/demos/tf4/Tiles.s
new file mode 100644
index 0000000..6030d7d
--- /dev/null
+++ b/demos/tf4/Tiles.s
@@ -0,0 +1,41 @@
+
+TileData
+; Reserved space (tile 0 is special...
+ ds 128
+; Tile ID 1
+; From image coordinates 0, 0
+ hex ffffffff
+ hex ffffffff
+ hex ffffffff
+ hex ffffffff
+ hex ffffffff
+ hex ffffffff
+ hex ffffffff
+ hex ffffffff
+
+ hex 00000000
+ hex 00000000
+ hex 00000000
+ hex 00000000
+ hex 00000000
+ hex 00000000
+ hex 00000000
+ hex 00000000
+
+ hex ffffffff
+ hex ffffffff
+ hex ffffffff
+ hex ffffffff
+ hex ffffffff
+ hex ffffffff
+ hex ffffffff
+ hex ffffffff
+
+ hex 00000000
+ hex 00000000
+ hex 00000000
+ hex 00000000
+ hex 00000000
+ hex 00000000
+ hex 00000000
+ hex 00000000
\ No newline at end of file
diff --git a/demos/tf4/_FileInformation.txt b/demos/tf4/_FileInformation.txt
new file mode 100644
index 0000000..85f69d9
--- /dev/null
+++ b/demos/tf4/_FileInformation.txt
@@ -0,0 +1 @@
+GTETF4=Type(B3),AuxType(0000),VersionCreate(70),MinVersion(BE),Access(E3),FolderInfo1(000000000000000000000000000000000000),FolderInfo2(000000000000000000000000000000000000)
diff --git a/demos/tf4/assets/tiled/Overworld.tsx b/demos/tf4/assets/tiled/Overworld.tsx
new file mode 100644
index 0000000..4753af2
--- /dev/null
+++ b/demos/tf4/assets/tiled/Overworld.tsx
@@ -0,0 +1,37 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/demos/tf4/assets/tiled/world_1-1.json b/demos/tf4/assets/tiled/world_1-1.json
new file mode 100644
index 0000000..9f73813
--- /dev/null
+++ b/demos/tf4/assets/tiled/world_1-1.json
@@ -0,0 +1,32 @@
+{ "compressionlevel":-1,
+ "height":30,
+ "infinite":false,
+ "layers":[
+ {
+ "data":[0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 154, 153, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 154, 153, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 154, 153, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 154, 153, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 185, 186, 186, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 185, 186, 186, 186, 186, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 185, 186, 186, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 185, 186, 186, 186, 186, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 185, 186, 186, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 185, 186, 186, 186, 186, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 185, 186, 186, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 185, 186, 186, 186, 186, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 59, 60, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 155, 156, 157, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 154, 153, 154, 153, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 155, 156, 157, 156, 157, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 155, 156, 157, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 154, 153, 154, 153, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 155, 156, 157, 156, 157, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 155, 156, 157, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 154, 153, 154, 153, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 155, 156, 157, 156, 157, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 155, 156, 157, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 153, 154, 153, 154, 153, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 155, 156, 157, 156, 157, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 56, 10, 0, 0, 0, 0, 0, 153, 154, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 185, 186, 186, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 185, 186, 186, 186, 186, 186, 186, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 185, 186, 186, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 185, 186, 186, 186, 186, 186, 186, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 185, 186, 186, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 185, 186, 186, 186, 186, 186, 186, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 185, 186, 186, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 185, 186, 186, 186, 186, 186, 186, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 55, 10, 0, 0, 0, 0, 185, 186, 186, 187, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 155, 156, 157, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 155, 156, 157, 156, 157, 156, 157, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 155, 156, 157, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 155, 156, 157, 156, 157, 156, 157, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 155, 156, 157, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 155, 156, 157, 156, 157, 156, 157, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 155, 156, 157, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 155, 156, 157, 156, 157, 156, 157, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 155, 156, 157, 158, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 159, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 188, 0, 0, 0, 0, 0, 0, 188, 188, 188, 188, 188, 188, 159, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 159, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 188, 188, 188, 188, 188, 188, 0, 0, 0, 0, 0, 0, 0, 0, 188, 188, 159, 160, 159, 160, 188, 188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 191, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 191, 192, 191, 192, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, 5, 6, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 7, 8, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, 5, 6, 5, 6, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 7, 8, 7, 8, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 31, 32, 31, 32, 31, 32, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 159, 160, 0, 0, 0, 0, 0, 188, 188, 159, 160, 188, 188, 159, 160, 188, 188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 12, 13, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 12, 13, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 188, 188, 159, 160, 188, 188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 188, 188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 188, 188, 188, 188, 0, 0, 0, 0, 0, 0, 0, 0, 159, 160, 0, 0, 0, 0, 159, 160, 0, 0, 0, 0, 159, 160, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 188, 188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 188, 188, 188, 188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, 5, 6, 0, 0, 0, 0, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 188, 188, 188, 188, 159, 160, 188, 188, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 191, 192, 0, 0, 0, 0, 0, 26, 26, 191, 192, 26, 26, 191, 192, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 16, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 16, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 191, 192, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 191, 192, 0, 0, 0, 0, 191, 192, 0, 0, 0, 0, 191, 192, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 0, 0, 0, 0, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 7, 8, 0, 0, 0, 0, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 191, 192, 26, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 26, 64, 26, 26, 64, 26, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 12, 13, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, 5, 6, 0, 0, 0, 0, 5, 6, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, 5, 6, 5, 6, 0, 0, 0, 0, 5, 6, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 0, 0, 26, 64, 26, 26, 64, 26, 0, 0, 0, 0, 0, 0, 0, 0, 49, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 16, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 20, 21, 22, 0, 0, 0, 0, 49, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 50, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 7, 8, 0, 0, 0, 0, 7, 8, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 49, 50, 0, 0, 0, 0, 0, 0, 7, 8, 7, 8, 7, 8, 0, 0, 0, 0, 7, 8, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 0, 0, 0, 0, 0, 0, 0, 0, 49, 50, 0, 0, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 31, 32, 24, 25, 24, 25, 24, 25, 31, 32, 0, 0, 0, 0, 0, 48, 21, 54, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 12, 13, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 20, 21, 22, 0, 0, 0, 48, 21, 54, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 21, 54, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, 5, 6, 5, 6, 0, 0, 0, 0, 5, 6, 5, 6, 5, 6, 0, 0, 0, 0, 0, 48, 21, 54, 51, 0, 0, 0, 5, 6, 5, 6, 5, 6, 5, 6, 0, 0, 0, 0, 5, 6, 5, 6, 5, 6, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 12, 13, 14, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 11, 12, 13, 14, 0, 0, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 0, 0, 0, 0, 0, 0, 0, 48, 21, 54, 51, 0, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 57, 58, 26, 26, 26, 26, 0, 0, 0, 0, 48, 21, 21, 21, 21, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 2147483697, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 16, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 20, 21, 22, 0, 0, 48, 21, 21, 21, 21, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 2147483697, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 21, 21, 21, 21, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 49, 2147483697, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 7, 8, 7, 8, 0, 0, 0, 0, 7, 8, 7, 8, 7, 8, 0, 0, 0, 0, 48, 21, 21, 21, 21, 51, 0, 0, 7, 8, 7, 8, 7, 8, 7, 8, 0, 0, 0, 0, 7, 8, 7, 8, 7, 8, 0, 0, 0, 0, 0, 0, 49, 2147483697, 0, 0, 15, 16, 17, 18, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 15, 16, 17, 18, 0, 0, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 0, 0, 0, 0, 0, 0, 48, 21, 21, 21, 21, 51, 0, 0, 0, 0, 9, 10, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 64, 64, 26, 26, 26, 26, 0, 0, 0, 48, 21, 54, 21, 21, 54, 21, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 35, 34, 35, 34, 35, 0, 0, 0, 48, 21, 54, 2147483696, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 35, 0, 0, 0, 0, 0, 0, 19, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 20, 21, 22, 0, 0, 0, 0, 34, 35, 34, 35, 0, 0, 0, 0, 19, 20, 21, 22, 0, 48, 21, 54, 21, 21, 54, 21, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 20, 21, 22, 0, 0, 34, 35, 34, 35, 34, 35, 0, 0, 0, 48, 21, 54, 2147483696, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 35, 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 48, 21, 54, 21, 21, 54, 21, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 35, 34, 35, 34, 35, 0, 0, 0, 48, 21, 54, 2147483696, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 5, 6, 5, 6, 5, 6, 5, 6, 34, 35, 34, 35, 5, 6, 5, 6, 5, 6, 5, 6, 0, 48, 21, 54, 21, 21, 54, 21, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 0, 0, 0, 0, 5, 6, 5, 6, 5, 6, 5, 6, 0, 0, 0, 48, 21, 54, 2147483696, 0, 19, 20, 21, 22, 0, 0, 0, 0, 0, 0, 34, 35, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 20, 21, 22, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 5, 6, 0, 0, 0, 0, 0, 48, 21, 54, 21, 21, 54, 21, 51, 0, 0, 0, 5, 6, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 64, 64, 26, 26, 26, 26, 0, 0, 48, 21, 21, 21, 21, 21, 21, 21, 21, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 37, 37, 37, 37, 37, 37, 38, 0, 48, 21, 21, 21, 21, 2147483696, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 37, 37, 38, 0, 0, 0, 0, 0, 19, 20, 21, 22, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 20, 21, 22, 0, 0, 0, 36, 37, 37, 37, 37, 38, 0, 0, 0, 19, 20, 21, 22, 48, 21, 21, 21, 21, 21, 21, 21, 21, 51, 0, 0, 0, 0, 0, 0, 0, 0, 19, 20, 21, 22, 0, 36, 37, 37, 37, 37, 37, 37, 38, 0, 48, 21, 21, 21, 21, 2147483696, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 37, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 37, 37, 37, 37, 38, 0, 0, 0, 0, 0, 0, 0, 48, 21, 21, 21, 21, 21, 21, 21, 21, 51, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 37, 37, 37, 37, 37, 37, 38, 0, 48, 21, 21, 21, 21, 2147483696, 0, 0, 0, 0, 0, 0, 0, 0, 0, 36, 37, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 7, 8, 7, 8, 7, 8, 7, 8, 37, 37, 37, 37, 7, 8, 7, 8, 7, 8, 7, 8, 48, 21, 21, 21, 21, 21, 21, 21, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 0, 0, 0, 0, 7, 8, 7, 8, 7, 8, 7, 8, 38, 0, 48, 21, 21, 21, 21, 2147483696, 19, 20, 21, 22, 0, 0, 0, 0, 0, 36, 37, 37, 38, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 19, 20, 21, 22, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 7, 8, 0, 0, 0, 0, 48, 21, 21, 21, 21, 21, 21, 21, 21, 51, 0, 0, 7, 8, 0, 0, 0, 0, 0, 0, 26, 26, 26, 26, 64, 64, 26, 26, 26, 26, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 0, 0, 0, 0, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 0, 0, 0, 0, 0, 0, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 0, 0, 0, 0, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 0, 0, 0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 0, 0, 0, 0, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 0, 0, 0, 0, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 0, 0, 0, 0, 0, 0, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 0, 0, 0, 0, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4, 3, 4],
+ "height":30,
+ "id":1,
+ "name":"App.TileMapBG0",
+ "opacity":1,
+ "type":"tilelayer",
+ "visible":true,
+ "width":416,
+ "x":0,
+ "y":0
+ }],
+ "nextlayerid":4,
+ "nextobjectid":2,
+ "orientation":"orthogonal",
+ "renderorder":"right-down",
+ "tiledversion":"1.7.2",
+ "tileheight":8,
+ "tilesets":[
+ {
+ "firstgid":1,
+ "source":"Overworld.tsx"
+ }],
+ "tilewidth":8,
+ "type":"map",
+ "version":"1.6",
+ "width":416
+}
\ No newline at end of file
diff --git a/demos/tf4/assets/tiled/world_1-1.tmx b/demos/tf4/assets/tiled/world_1-1.tmx
new file mode 100644
index 0000000..693a851
--- /dev/null
+++ b/demos/tf4/assets/tiled/world_1-1.tmx
@@ -0,0 +1,41 @@
+
+
diff --git a/demos/tf4/assets/tilesets/smb-256-128-4bpp.png b/demos/tf4/assets/tilesets/smb-256-128-4bpp.png
new file mode 100644
index 0000000..82de535
Binary files /dev/null and b/demos/tf4/assets/tilesets/smb-256-128-4bpp.png differ
diff --git a/demos/tf4/build-image.bat b/demos/tf4/build-image.bat
new file mode 100644
index 0000000..99b8d70
--- /dev/null
+++ b/demos/tf4/build-image.bat
@@ -0,0 +1,17 @@
+echo off
+
+REM Copy all of the assets into the ProDOS image for emulator testing
+REM
+REM Pass the path of the Cadius tool as the first argument (%1)
+
+set CADIUS="%1"
+set IMAGE="..\\..\\emu\\Target.2mg"
+set FOLDER="/GTEDEV/TF4"
+
+REM Cadius does not overwrite files, so clear the root folder first
+%CADIUS% DELETEFOLDER %IMAGE% %FOLDER%
+%CADIUS% CREATEFOLDER %IMAGE% %FOLDER%
+
+REM Now copy files and folders as needed
+%CADIUS% ADDFILE %IMAGE% %FOLDER% .\GTETF4
+%CADIUS% ADDFILE %IMAGE% %FOLDER% ..\..\src\Tool160
diff --git a/demos/tf4/package.json b/demos/tf4/package.json
new file mode 100644
index 0000000..040b62c
--- /dev/null
+++ b/demos/tf4/package.json
@@ -0,0 +1,44 @@
+{
+ "name": "tf4-demo",
+ "version": "1.0.0",
+ "description": "",
+ "main": "index.js",
+ "config": {
+ "merlin32": "C:\\Programs\\IIgsXDev\\bin\\Merlin32-1.1.10.exe",
+ "cadius": "C:\\Programs\\IIgsXDev\\bin\\Cadius.exe",
+ "gsport": "C:\\Programs\\gsport\\gsport_0.31\\GSPort.exe",
+ "macros": "../../macros",
+ "crossrunner": "C:\\Programs\\Crossrunner\\Crossrunner.exe",
+ "png2iigs": "../../tools/png2iigs.js",
+ "tiled2iigs": "../../tools/tiled2iigs.js"
+ },
+ "scripts": {
+ "test": "npm run build && npm run build:image && npm run gsport",
+ "gsport": "%npm_package_config_gsport%",
+ "debug": "%npm_package_config_crossrunner% GTETestSprites -Source GTETestSprites_S02_MAINSEG_Output.txt -Debug -CompatibilityLayer",
+ "build:all": "npm run build:tiles && npm run build:map && npm run build:tool && npm run build:sys16 && npm run build:image",
+ "build:map": "node %npm_package_config_tiled2iigs% ./assets/tiled/world_1-1.json --empty-tile 33 --no-gen-tiles --output-dir ./gen",
+ "build:map:masked": "node %npm_package_config_tiled2iigs% ./assets/tiled/world_1-1.json --force-masked --empty-tile 33 --no-gen-tiles --output-dir ./gen",
+ "build:tiles": "node %npm_package_config_png2iigs% ./assets/tilesets/smb-256-128-4bpp.png --max-tiles 360 --as-tile-data --transparent-color FF00FF --background-color 6B8CFF --verbose > ./gen/App.TileSet.s",
+ "build:sys16": "%npm_package_config_merlin32% -V %npm_package_config_macros% App.s",
+ "build": "npm run build:tool && npm run build:sys16",
+ "build:tool": "%npm_package_config_merlin32% -V %npm_package_config_macros% ../../src/Master.s",
+ "build:image": "build-image.bat %npm_package_config_cadius%"
+ },
+ "repository": {
+ "type": "git",
+ "url": "git+https://github.com/lscharen/iigs-game-engine.git"
+ },
+ "author": "Lucas Scharenbroich",
+ "license": "Apache-2.0",
+ "bugs": {
+ "url": "https://github.com/lscharen/iigs-game-engine/issues"
+ },
+ "homepage": "https://github.com/lscharen/iigs-game-engine#readme",
+ "devDependencies": {
+ "pngjs": "^6.0.0",
+ "string-builder": "^0.1.8",
+ "watch": "latest",
+ "xml2json": "^0.12.0"
+ }
+}
diff --git a/macros/GTE.Macs.s b/macros/GTE.Macs.s
index 4313f90..f217d4f 100644
--- a/macros/GTE.Macs.s
+++ b/macros/GTE.Macs.s
@@ -126,6 +126,9 @@ _GTEClearBG1Buffer MAC
_GTESetBG1Scale MAC
UserTool $2B00+GTEToolNum
<<<
+_GTEGetAddress MAC
+ UserTool $2C00+GTEToolNum
+ <<<
; EngineMode definitions
; Script definition
@@ -153,6 +156,10 @@ RENDER_ALT_BG1 equ $0001
RENDER_BG1_HORZ_OFFSET equ $0002
RENDER_BG1_VERT_OFFSET equ $0004
RENDER_BG1_ROTATION equ $0008
+RENDER_PER_SCANLINE equ $0010
+
+; GetAddress table IDs
+scanlineHorzOffset equ $0001
; Tile constants
; TILE_RESERVED_BIT equ $8000
diff --git a/src/CoreImpl.s b/src/CoreImpl.s
index 537c836..ff6651f 100644
--- a/src/CoreImpl.s
+++ b/src/CoreImpl.s
@@ -233,6 +233,7 @@ EngineReset
sta tmp15
stz tmp14
+; Rebuild all of the bank blitters
:loop
ldx #BlitBuff
lda #^BlitBuff
@@ -247,6 +248,15 @@ EngineReset
dec tmp15
bne :loop
+; Set the scanline tables to reasonable default values
+ ldx #{416*2}-2
+ lda #0
+:sxm_loop
+ sta StartXMod164Arr,x
+ dex
+ dex
+ bpl :sxm_loop
+
rts
diff --git a/src/Defs.s b/src/Defs.s
index 9457df8..5297648 100644
--- a/src/Defs.s
+++ b/src/Defs.s
@@ -173,6 +173,7 @@ RENDER_ALT_BG1 equ $0001
RENDER_BG1_HORZ_OFFSET equ $0002
RENDER_BG1_VERT_OFFSET equ $0004
RENDER_BG1_ROTATION equ $0008
+RENDER_PER_SCANLINE equ $0010
; DirtyBits definitions
DIRTY_BIT_BG0_X equ $0001
@@ -183,6 +184,9 @@ DIRTY_BIT_BG0_REFRESH equ $0010
DIRTY_BIT_BG1_REFRESH equ $0020
DIRTY_BIT_SPRITE_ARRAY equ $0040
+; GetAddress table IDs
+scanlineHorzOffset equ $0001 ; table of 416 wors, a double-array of scanline offset values. Must be 0, 163
+
; Script definition
YIELD equ $8000
JUMP equ $4000
@@ -268,5 +272,8 @@ Overlays EXT
BG1YCache EXT
ScalingTables EXT
+StartXMod164Arr EXT
+LastPatchOffsetArr EXT
+
; Tool error codes
NO_TIMERS_AVAILABLE equ 10
diff --git a/src/FastCopies.s b/src/FastCopies.s
new file mode 100644
index 0000000..e401540
--- /dev/null
+++ b/src/FastCopies.s
@@ -0,0 +1,271 @@
+; Large, unrolled loops for setting values in the code field that would be used by the Horz.s
+; and Vert.s code.
+;
+; The utility of these functions is that they do not need to do any sort of bank switching and
+; can update all of the play field lines in a single call. The downside is that they take up
+; significantly more space, need large auxiliary tables, and must be patched after the code
+; field memory is allocated.
+;
+; Probably still worth it....
+
+BlitBuff EXT
+
+; Patch the fast copy routines with the allocated memory addresses
+InitFastCopies
+
+; Fist, patch the cttc routine
+
+ ldy #0
+ ldx #0
+
+:loop1
+ lda BlitBuff+2,y ; Get the bank of each in the accumulatow low byte
+
+ sep #$20
+]line equ 0
+ lup 16
+ stal cttc_start+{]line*7}+4,x
+ stal cttc_start+{{]line+208}*7}+4,x
+]line equ ]line+1
+ --^
+ rep #$20
+
+ txa
+ clc
+ adc #7*16
+ tax
+
+ tya
+ clc
+ adc #4
+ tay
+
+ cpy #13*4
+ bcs *+5
+ brl :loop1
+
+; Next, patch the two store routines
+
+ ldy #0
+ ldx #0
+
+:loop2
+ lda BlitBuff+2,y ; Get the bank of each in the accumulatow low byte
+
+ sep #$20
+]line equ 0
+ lup 16
+ stal store_start+{]line*4}+1,x
+ stal store_start+{{]line+208}*4}+1,x
+]line equ ]line+1
+ --^
+ rep #$20
+
+ txa
+ clc
+ adc #4*16
+ tax
+
+ tya
+ clc
+ adc #4
+ tay
+
+ cpy #13*4
+ bcs *+5
+ brl :loop2
+
+ rtl
+
+
+; Function to load data from an array and store in the code field. Assume that the
+; bank register is already set to the bank of the srcAddr data
+srcAddr equ 0
+destOffset equ 2
+
+CopyTblToCode
+ ldal entry_7,x ; This is the entry point
+ stal cttc_jump+1
+
+ txa ; Set the Y register to srcAddr - 2*start to compensate for the
+ eor #$FFFF ; offset in the code. This does mean that the array we are copying
+ sec ; cannot by near the beginning of the bank
+ adc srcAddr
+ tyx ; put the ending offset in X
+ tay
+
+ ldal entry_7,x
+ tax
+ lda #$0060
+ stal {cttc_start&$FF0000}+3,x ; patch at the next STAL instruction because the high byte is always zero
+
+ ldx destOffset ; byte offset within each line
+cttc_jump jsr $0000
+
+ lda #$009F ; restore the STAL opcode
+ stal {cttc_start&$FF0000}+3,x
+
+ rtl
+
+; Define the 416 addresses for each copy
+entry_7
+]line equ 0
+ lup 416
+ da cttc_start+{]line*7}
+]line equ ]line+1
+ --^
+
+; Generate the code that performs the copy.
+cttc_unit mac
+ lda: {]1*32}+{]2*2},y
+ stal $000000+{]2*$1000},x
+ <<<
+
+cttc_start
+]bank equ 0
+ lup 26
+ cttc_unit ]bank;0
+ cttc_unit ]bank;1
+ cttc_unit ]bank;2
+ cttc_unit ]bank;3
+ cttc_unit ]bank;4
+ cttc_unit ]bank;5
+ cttc_unit ]bank;6
+ cttc_unit ]bank;7
+ cttc_unit ]bank;8
+ cttc_unit ]bank;9
+ cttc_unit ]bank;10
+ cttc_unit ]bank;11
+ cttc_unit ]bank;12
+ cttc_unit ]bank;13
+ cttc_unit ]bank;14
+ cttc_unit ]bank;15
+]bank equ ]bank+1
+ --^
+ rts
+
+Store8Bits
+ txa
+ asl
+ adc #store_start
+ stal s8b_jump+1
+
+ tya
+ asl
+ tax
+ lda #$0060
+ stal {store_start&$FF0000},x
+
+ ldx destOffset ; byte offset within each line
+ lda srcAddr
+ sep #$20
+s8b_jump jsr $0000
+
+ lda #$9F ; restore the STAL opcode
+ stal {store_start&$FF0000},x
+ rep #$20
+
+ rtl
+
+Store16Bits
+ txa
+ asl
+ adc #store_start
+ stal s16b_jump+1
+
+ tya
+ asl
+ tax
+ lda #$0060
+ stal {store_start&$FF0000},x
+
+ ldx destOffset ; byte offset within each line
+ lda srcAddr
+s16b_jump jsr $0000
+
+ lda #$009F ; restore the STAL opcode
+ stal {store_start&$FF0000},x
+ rtl
+
+store_start
+ lup 26
+ stal $000000,x
+ stal $001000,x
+ stal $002000,x
+ stal $003000,x
+ stal $004000,x
+ stal $005000,x
+ stal $006000,x
+ stal $007000,x
+ stal $008000,x
+ stal $009000,x
+ stal $00A000,x
+ stal $00B000,x
+ stal $00C000,x
+ stal $00D000,x
+ stal $00E000,x
+ stal $00F000,x
+ --^
+ rts
+
+
+CodeCopy8
+ txa
+ asl
+ adc #store_start
+ stal cc8_jump+1
+
+ tya
+ asl
+ tax
+ lda #$0060
+ stal {store8_start&$FF0000},x
+
+ ldx destOffset ; byte offset within each line
+ lda srcAddr
+cc8_jump jsr $0000
+
+ lda #$009F ; restore the STAL opcode
+ stal {store8_start&$FF0000},x
+ rtl
+
+store8_start
+ lup 26
+ pea $0000
+ plb
+ plb
+
+ lda $0000,y
+ stal $000000,x
+ lda $0000,y
+ stal $001000,x
+ lda $0000,y
+ stal $002000,x
+ lda $0000,y
+ stal $003000,x
+ lda $0000,y
+ stal $004000,x
+ lda $0000,y
+ stal $005000,x
+ lda $0000,y
+ stal $006000,x
+ lda $0000,y
+ stal $007000,x
+ lda $0000,y
+ stal $008000,x
+ lda $0000,y
+ stal $009000,x
+ lda $0000,y
+ stal $00A000,x
+ lda $0000,y
+ stal $00B000,x
+ lda $0000,y
+ stal $00C000,x
+ lda $C000,y
+ stal $00D000,x
+ lda $E000,y
+ stal $00E000,x
+ lda $F000,y
+ stal $00F000,x
+ --^
+ rts
\ No newline at end of file
diff --git a/src/Master.s b/src/Master.s
index 637d4a5..f4b7581 100644
--- a/src/Master.s
+++ b/src/Master.s
@@ -43,3 +43,10 @@
KND #$1001 ; Type and Attributes ($11=Static+Bank Relative,$01=Data)
ALI BANK
SNA ROTDATA
+
+; Additional code
+
+ ASM FastCopies.s
+ KND #$1001 ; Type and Attributes ($11=Static+Bank Relative,$01=Data)
+ ALI BANK
+ SNA FASTCPY
diff --git a/src/Render.s b/src/Render.s
index 1836d9a..289fd7f 100644
--- a/src/Render.s
+++ b/src/Render.s
@@ -32,6 +32,13 @@ _Render
stz SpriteRemovedFlag ; If we remove a sprite, then we need to flag a rebuild for the next frame
+; If we are doing per-scanline rendering, use the alternate renderer
+
+ lda #RENDER_PER_SCANLINE
+ bit RenderFlags
+ beq *+5
+ jmp _RenderScanlines ; Do the scanline-based renderer
+
jsr _ApplyBG0YPos ; Set stack addresses for the virtual lines to the physical screen
lda #RENDER_BG1_ROTATION
@@ -147,6 +154,98 @@ _DoOverlay
:disp jsl $000000
rts
+
+; Use the per-scanline tables to set the screen. This is really meant to be used without the built-in tilemap
+; support and is more of a low-level way to control the background rendering
+_RenderScanlines
+
+ jsr _ApplyBG0YPos ; Set stack addresses for the virtual lines to the physical screen
+ jsr _ApplyBG1YPos ; Set the y-register values of the blitter
+
+; _ApplyBG0Xpos need to be split because we have to set the offsets, then draw in any updated tiles, and
+; finally patch out the code field. Right now, the BRA operand is getting overwritten by tile data.
+
+ jsr _ApplyBG0XPosPre
+ jsr _ApplyBG1XPosPre
+
+; jsr _RenderSprites ; Once the BG0 X and Y positions are committed, update sprite data
+
+; jsr _ApplyTiles ; This function actually draws the new tiles into the code field
+
+ jsr _ScanlineBG0XPos ; Patch the code field instructions with exit BRA opcode
+
+; jsr _ApplyBG1XPos ; Update the direct page value based on the horizontal position
+
+; The code fields are locked in now and ready to be rendered. See if there is an overlay or any
+; other reason to render with shadowing off. Otherwise, just do things quickly.
+
+; lda Overlays
+; beq :no_ovrly
+
+; jsr _ShadowOff
+
+; Shadowing is turned off. Render all of the scan lines that need a second pass. One
+; optimization that can be done here is that the lines can be rendered in any order
+; since it is not shown on-screen yet.
+
+; ldx Overlays+2 ; Blit the full virtual buffer to the screen
+; ldy Overlays+4
+; jsr _BltRange
+
+; Turn shadowing back on
+
+; jsr _ShadowOn
+
+; Now render all of the remaining lines in top-to-bottom (or bottom-to-top) order
+
+; ldx #0
+; ldy Overlays+2
+; beq :skip
+; jsr _BltRange
+:skip
+; jsr _DoOverlay
+
+; ldx Overlays+4
+; cpx ScreenHeight
+; beq :done
+; ldy ScreenHeight
+; jsr _BltRange
+; bra :done
+
+:no_ovrly
+ ldx #0 ; Blit the full virtual buffer to the screen
+ ldy ScreenHeight
+ jsr _BltRange
+:done
+
+; ldx #0
+; ldy ScreenHeight
+; jsr _BltSCB
+
+ lda StartYMod208 ; Restore the fields back to their original state
+ ldx ScreenHeight
+ jsr _RestoreScanlineBG0Opcodes
+
+ lda StartY
+ sta OldStartY
+ lda StartX
+ sta OldStartX
+
+ lda BG1StartY
+ sta OldBG1StartY
+ lda BG1StartX
+ sta OldBG1StartX
+
+ stz DirtyBits
+ stz LastRender ; Mark that a full render was just performed
+
+ lda SpriteRemovedFlag ; If any sprite was removed, set the rebuild flag
+ beq :no_removal
+ lda #DIRTY_BIT_SPRITE_ARRAY
+ sta DirtyBits
+:no_removal
+ rts
+
; Run through all of the tiles on the DirtyTile list and render them
_ApplyTiles
ldx DirtyTileCount
diff --git a/src/SpriteV1.s b/src/SpriteV1.s
deleted file mode 100644
index 6d24dbb..0000000
--- a/src/SpriteV1.s
+++ /dev/null
@@ -1,226 +0,0 @@
-; Old code the was in Version 1, but is not needed. May be adapted for Verions 2.
-
-; Y = _Sprites array offset
-_EraseSpriteY
- lda _Sprites+OLD_VBUFF_ADDR,y
- beq :noerase
- ldx _Sprites+SPRITE_DISP,y ; get the dispatch index for this sprite (32 values)
- jmp (:do_erase,x)
-:noerase rts
-:do_erase dw _EraseTileSprite8x8,_EraseTileSprite8x8,_EraseTileSprite8x8,_EraseTileSprite8x8
- dw _EraseTileSprite8x16,_EraseTileSprite8x16,_EraseTileSprite8x16,_EraseTileSprite8x16
- dw _EraseTileSprite16x8,_EraseTileSprite16x8,_EraseTileSprite16x8,_EraseTileSprite16x8
- dw _EraseTileSprite16x16,_EraseTileSprite16x16,_EraseTileSprite16x16,_EraseTileSprite16x16
- dw _EraseTileSprite8x8,_EraseTileSprite8x8,_EraseTileSprite8x8,_EraseTileSprite8x8
- dw _EraseTileSprite8x16,_EraseTileSprite8x16,_EraseTileSprite8x16,_EraseTileSprite8x16
- dw _EraseTileSprite16x8,_EraseTileSprite16x8,_EraseTileSprite16x8,_EraseTileSprite16x8
- dw _EraseTileSprite16x16,_EraseTileSprite16x16,_EraseTileSprite16x16,_EraseTileSprite16x16
-
-; A = bank address
-_EraseTileSprite8x8
- tax
- phb ; Save the bank to switch to the sprite plane
-
- pei SpriteBanks
- plb ; pop the data bank (low byte)
-
-]line equ 0
- lup 8
- stz: {]line*SPRITE_PLANE_SPAN}+0,x
- stz: {]line*SPRITE_PLANE_SPAN}+2,x
-]line equ ]line+1
- --^
-
- plb ; pop the mask bank (high byte)
- lda #$FFFF
-]line equ 0
- lup 8
- sta: {]line*SPRITE_PLANE_SPAN}+0,x
- sta: {]line*SPRITE_PLANE_SPAN}+2,x
-]line equ ]line+1
- --^
-
- plb
- rts
-
-_EraseTileSprite8x16
- tax
- phb ; Save the bank to switch to the sprite plane
-
- pei SpriteBanks
- plb ; pop the data bank (low byte)
-
-]line equ 0
- lup 16
- stz: {]line*SPRITE_PLANE_SPAN}+0,x
- stz: {]line*SPRITE_PLANE_SPAN}+2,x
-]line equ ]line+1
- --^
-
- plb ; pop the mask bank (high byte)
- lda #$FFFF
-]line equ 0
- lup 16
- sta: {]line*SPRITE_PLANE_SPAN}+0,x
- sta: {]line*SPRITE_PLANE_SPAN}+2,x
-]line equ ]line+1
- --^
-
- plb
- rts
-
-_EraseTileSprite16x8
- tax
- phb ; Save the bank to switch to the sprite plane
-
- pei SpriteBanks
- plb ; pop the data bank (low byte)
-
-]line equ 0
- lup 8
- stz: {]line*SPRITE_PLANE_SPAN}+0,x
- stz: {]line*SPRITE_PLANE_SPAN}+2,x
- stz: {]line*SPRITE_PLANE_SPAN}+4,x
- stz: {]line*SPRITE_PLANE_SPAN}+6,x
-]line equ ]line+1
- --^
-
- plb ; pop the mask bank (high byte)
- lda #$FFFF
-]line equ 0
- lup 8
- sta: {]line*SPRITE_PLANE_SPAN}+0,x
- sta: {]line*SPRITE_PLANE_SPAN}+2,x
- sta: {]line*SPRITE_PLANE_SPAN}+4,x
- sta: {]line*SPRITE_PLANE_SPAN}+6,x
-]line equ ]line+1
- --^
-
- plb
- rts
-
-_EraseTileSprite16x16
- tax
- phb ; Save the bank to switch to the sprite plane
-
- pei SpriteBanks
- plb ; pop the data bank (low byte)
-
-]line equ 0
- lup 16
- stz: {]line*SPRITE_PLANE_SPAN}+0,x
- stz: {]line*SPRITE_PLANE_SPAN}+2,x
- stz: {]line*SPRITE_PLANE_SPAN}+4,x
- stz: {]line*SPRITE_PLANE_SPAN}+6,x
-]line equ ]line+1
- --^
-
- plb ; pop the mask bank (high byte)
-
- lda #$FFFF
-]line equ 0
- lup 16
- sta: {]line*SPRITE_PLANE_SPAN}+0,x
- sta: {]line*SPRITE_PLANE_SPAN}+2,x
- sta: {]line*SPRITE_PLANE_SPAN}+4,x
- sta: {]line*SPRITE_PLANE_SPAN}+6,x
-]line equ ]line+1
- --^
-
- plb
- rts
-
-
-; First, if there is only one sprite, then we can skip any overhead and do a single lda/and/ora/sta to put the
-; sprite data on the screen.
-;
-; Second, if there are 4 or less, then we "stack" the sprite data using an unrolled loop that allows each
-; sprite to just be a single and/ora pair and the final result is not written to any intermediate memory buffer.
-;
-; Third, if there are 5 or more sprites, then we assume that the sprites are "dense" and that there will be a
-; non-trivial amount of overdraw. In this case we do a series of optimized copies of the sprite data *and*
-; masks into a direct page buffer in *reverse order*. Once a mask value becomes zero, then nothing else can
-; show through and that value can be skipped. Once all of the mask values are zero, then the render is terminated
-; and the data buffer copied to the final destination.
-;
-; Note that these rendering algorithms impose a priority ordering on the sprites where lower sprite IDs are drawn
-; underneath higher sprite IDs.
-RenderActiveSpriteTiles
- cmp #0 ; Is there only one active sprite? If so optimise
- bne :many
-
- ldx vbuff ; load the address to the (adjusted) sprite tile
- lda TileStore+TS_SCREEN_ADDR,y
- tay
-
- lda tiledata+0,y
- andl spritemask,x
- oral spritedata,x
- sta 00,s
-
- lda tiledata+2,y
- andl spritemask+2,x
- oral spritedata+2,x
- sta 02,s
-
- ...
- tsc
- adc #320
- tcs
- ...
-
- lda tiledata+{line*4},y
- andl spritemask+{line*SPAN},x
- oral spritedata+{line*SPAN},x
- sta 160,s
-
- lda tiledata+{line*4}+2,y
- andl spritemask+{line*SPAN}+2,x
- oral spritedata+{line*SPAN}+2,x
- sta 162,s
-
- rts
-
-
-:many
- lda TileStore+TS_SCREEN_ADDR,y
- tcs
- lda TileStore+TS_TILE_ADDR,y
- tay
-
- ldx count
- jmp (:arr,x)
- lda tiledata+0,y
- ldx vbuff
- andl spritemask,x
- oral spritedata,x
- ldx vbuff+2
- andl spritemask,x
- oral spritedata,x
- ldx vbuff+4
- andl spritemask,x
- oral spritedata,x
- ...
- sta 00,s
-
- ldx count
- jmp (:arr,x)
- lda tiledata+0,y
- ldx vbuff
- andl spritemask,x
- oral spritedata,x
- ldx vbuff+2
- andl spritemask,x
- oral spritedata,x
- ldx vbuff+4
- andl spritemask,x
- oral spritedata,x
- ...
- sta 02,s
-
- sta 160,s
-
- sta 162,s
-
- tsc
- adc #320
\ No newline at end of file
diff --git a/src/Tiles.s b/src/Tiles.s
index f5ec35d..741720e 100644
--- a/src/Tiles.s
+++ b/src/Tiles.s
@@ -1,20 +1,29 @@
; Basic tile functions
; Copy tileset data from a pointer in memory to the tiledata back
-; X = high word
-; A = low word
+;
+; tmp0 = Pointer to tile data
+; X = first tile
+; Y = last tile
+;
+; To copy in three tiles starting at tile 5, for example, X = 5 and Y = 9
_LoadTileSet
- sta tmp0
- stx tmp1
+ txa
+ _Mul128 ; Jump to the target location
+ tax
+ tya
+ _Mul128
+ sta tmp2 ; This is the terminating byte
+
ldy #0
- tyx
:loop lda [tmp0],y
stal tiledata,x
- dex
- dex
- dey
- dey
- bne :loop
+ inx
+ inx
+ iny
+ iny
+ cpx tmp2
+ bne :loop ; Use BNE so when Y=512 => $0000, we wait for wrap-around
rts
diff --git a/src/Tool.s b/src/Tool.s
index 548783d..741f674 100644
--- a/src/Tool.s
+++ b/src/Tool.s
@@ -96,6 +96,7 @@ _CallTable
adrl _TSClearBG1Buffer-1
adrl _TSSetBG1Scale-1
+ adrl _TSGetAddress-1
_CTEnd
_GTEAddSprite MAC
UserTool $1000+GTEToolNum
@@ -183,7 +184,7 @@ _TSShutDown
jsr _CoreShutDown ; Shut down the library
plb
- lda EngineMode
+ lda EngineMode ; $0000 = system tool, $8000 = user tool set
and #$8000
pha
pei ToolNum
@@ -305,18 +306,27 @@ _TSRenderDirty
jsr _RenderDirty
_TSExit #0;#2
-; LoadTileSet(Pointer)
+; LoadTileSet(Start, Finish, Pointer)
_TSLoadTileSet
-TSPtr equ FirstParam
+:TSPtr equ FirstParam
+:finish equ FirstParam+4
+:start equ FirstParam+6
_TSEntry
- lda TSPtr+2,s
+ lda :TSPtr+2,s ; stuff the pointer in the direct page
+ sta tmp1
+ lda :TSPtr,s
+ sta tmp0
+
+ lda :start,s ; put the range in the registers
tax
- lda TSPtr,s
+ lda :finish,s
+ tay
+
jsr _LoadTileSet
- _TSExit #0;#4
+ _TSExit #0;#8
; CreateSpriteStamp(spriteDescriptor: Word, vbuffAddr: Word)
_TSCreateSpriteStamp
@@ -807,6 +817,27 @@ _TSSetBG1Scale
sta BG1Scaling
_TSExit #0;#2
+_TSGetAddress
+:output equ FirstParam+0
+:tblId equ FirstParam+4
+
+ _TSEntry
+ lda #0
+ sta :output,s
+ sta :output+2,s
+
+ lda :value,s
+ cmp #scanlineHorzOffset
+ bne :out
+
+ lda #StartXMod164Arr
+ sta :output,s
+ lda #^StartXMod164Arr
+ sta :output+2,s
+
+:out
+ _TSExit #0;#2
+
; Insert the GTE code
put Math.s
@@ -821,6 +852,7 @@ _TSSetBG1Scale
put Sprite2.s
put SpriteRender.s
put Render.s
+ put blitter/Scanline.s
put render/Render.s
put render/Fast.s
put render/Slow.s
diff --git a/src/blitter/Blitter.s b/src/blitter/Blitter.s
index b71c0b3..c005369 100644
--- a/src/blitter/Blitter.s
+++ b/src/blitter/Blitter.s
@@ -57,7 +57,9 @@ _BltRange
lda EngineMode
bit #ENGINE_MODE_TWO_LAYER
beq :skip_bank
-
+
+; TODO: Switch to loading the selected BG1 bank. No special "Alt" bank
+
lda RenderFlags
bit #RENDER_ALT_BG1
beq :primary
@@ -81,7 +83,7 @@ _BltRange
_R0W1
tsc ; save the stack pointer
stal stk_save+1
-
+
blt_entry jml $000000 ; Jump into the blitter code $XX/YY00
blt_return _R0W0
diff --git a/src/blitter/Horz.s b/src/blitter/Horz.s
index 75840de..55384fc 100644
--- a/src/blitter/Horz.s
+++ b/src/blitter/Horz.s
@@ -205,9 +205,8 @@ _ApplyBG0XPos
; where the exit will be patched in
dec ; (a - 1) % 164
- bpl :hop1
+ bpl *+5
lda #163
-:hop1
; If the exit byte is odd, then the left edge is even-aligned and we round down and exit at at
; that word.
@@ -243,7 +242,7 @@ _ApplyBG0XPos
dec ; to get the index of the first on-screen byte
cmp #164 ; Keep the value in range
- bcc :hop2
+ bcc *+5
sbc #164
:hop2
@@ -321,7 +320,7 @@ _ApplyBG0XPos
adc :virt_line_x2 ; filled in
sta :virt_line_x2
- lda :exit_address ; Save from this location
+ lda :exit_address ; Save from this location (not needed in fast mode)
SaveOpcode ; X = :exit_address on return
txy ; ldy :exit_address -- starting at this address
@@ -336,7 +335,7 @@ _ApplyBG0XPos
lda :entry_offset
ldy :base_address
- SetCodeEntry ; All registers are preserved
+ SetCodeEntry ; All registers are preserved
; Now, patch in the opcode
diff --git a/src/blitter/Scanline.s b/src/blitter/Scanline.s
new file mode 100644
index 0000000..15f0ed1
--- /dev/null
+++ b/src/blitter/Scanline.s
@@ -0,0 +1,257 @@
+; This support an alternate engine mode. When in scanline mode the renderer does not use the
+; global StartX and StartY parameters to set up the code field. Instead, an array of scanline
+; parameters must be provided to the blitter.
+;
+; This is a low-level mode and it is assumed that the arrays will contain valid values. This
+; process is quite a bit slower that the normal setup because it must calculate code field
+; entry points for each line, instead of once for the entire frame.
+
+_ScanlineBG0XPos
+
+:stk_save equ tmp0
+:virt_line_x2 equ tmp1
+:last_line_x2 equ tmp2
+:src_bank equ tmp3
+:exit_offset equ tmp4
+:entry_offset equ tmp5
+:exit_bra equ tmp6
+:exit_address equ tmp7
+:base_address equ tmp8
+:opcode equ tmp9
+:odd_entry_offset equ tmp10
+
+ brk $AB
+ lda StartYMod208 ; This is the base line of the virtual screen
+ asl
+ sta :virt_line_x2 ; Keep track of it
+
+ lda ScreenHeight
+ asl
+ clc
+ adc :virt_line_x2
+ sta :last_line_x2
+
+ phb
+ phb
+ pla
+ and #$FF00
+ sta :src_bank
+
+:loop
+ ldx :virt_line_x2
+
+ lda StartXMod164Arr,x ; Get the offset for this line
+ dec ; The exit point is one byte sooner
+ bpl *+5
+ lda #163
+
+ bit #$0001 ; if odd, then original number was even
+ beq :odd_exit ; if even, the original number was odd
+
+ ; This is the even code path
+ and #$FFFE
+ tay
+ lda CodeFieldEvenBRA,y
+ sta :exit_bra
+ lda Col2CodeOffset,y
+ sta :exit_offset
+ sta LastPatchOffsetArr,x ; Cache afor later
+ bra :do_entry
+
+; This is the odd code path
+:odd_exit tay
+ lda CodeFieldOddBRA,y
+ sta :exit_bra
+ lda Col2CodeOffset,y
+ sta :exit_offset
+ sta LastPatchOffsetArr,x
+
+; Handle the entry point calculations
+:do_entry
+ lda StartXMod164Arr,x
+ clc
+ adc ScreenWidth ; move to the right edge and back up a byte
+ dec ; to get the index of the first on-screen byte
+
+ cmp #164 ; Keep the value in range
+ bcc *+5
+ sbc #164
+
+; Same logic as before
+
+ bit #$0001
+ beq :odd_entry
+
+ and #$FFFE
+ tay
+ lda Col2CodeOffset,y
+ sta :entry_offset
+ lda #$004C ; set the entry_jmp opcode to JMP
+ sta :opcode
+ stz :odd_entry_offset ; mark as an even case
+ bra :prep_complete
+
+:odd_entry
+ tay
+ lda Col2CodeOffset,y
+ sta :entry_offset ; Will be used to load the data
+ lda Col2CodeOffset-2,y
+ sta :odd_entry_offset ; will the the actual location to jump to
+ lda #$00AF ; set the entry_jmp opcode to LDAL
+ sta :opcode
+:prep_complete
+
+; Now patch in the code field line
+
+ ldy BTableLow,x ; Get the address of the first code field line
+ clc
+ adc :exit_offset ; Add some offsets to get the base address in the code field line
+ sta :exit_address
+ sty :base_address
+
+ lda BTableHigh,x
+ ora :src_bank
+ pha
+ plb
+
+; First step is to set the BRA instruction to exit the code field at the proper location. There
+; are two sub-steps to do here; we need to save the 16-bit value that exists at the location and
+; then overwrite it with the branch instruction.
+
+; SaveOpcode
+ ; y is already set to :base_address
+ ldx :exit_address ; Save from this location
+ lda: $0000,x
+ sta: OPCODE_SAVE+$0000,y
+
+;SetConst
+; txy ; ldy :exit_address -- starting at this address
+ lda :exit_bra ; Copy this value into all of the lines
+ sta: $0000,x
+
+; Next, patch in the CODE_ENTRY value, which is the low byte of a JMP instruction. This is an
+; 8-bit operation and, since the PEA code is bank aligned, we use the entry_offset value directly
+
+ sep #$20
+
+; SetCodeEntry
+ lda :entry_offset
+; ldy :base_address
+ sta: CODE_ENTRY+$0000,y
+
+; SetCodeEntryOpcode
+
+ lda :opcode
+ sta: CODE_ENTRY_OPCODE+$0000,y
+
+; If this is an odd entry, also set the odd_entry low byte and save the operand high byte
+
+ lda :odd_entry_offset
+ beq :not_odd
+
+; SetOddCodeEntry
+ sta: ODD_ENTRY+$0000,y
+; SaveHighOperand
+; ldx :exit_address
+ lda: $0002,x
+ sta: OPCODE_HIGH_SAVE+$0000,y
+:not_odd
+ rep #$20 ; clear the carry
+
+; Do the end of the loop -- update the virtual line counter and reduce the number
+; of lines left to render
+
+ plb ; restore the bank
+
+ lda :virt_line_x2
+ inc
+ inc
+ sta :virt_line_x2
+ cmp :last_line_x2
+ jne :loop
+
+ rts
+
+
+_RestoreScanlineBG0Opcodes
+
+:virt_line_x2 equ tmp1
+:lines_left_x2 equ tmp2
+:src_bank equ tmp6
+
+ asl
+ sta :virt_line_x2 ; Keep track of it
+
+ phb
+ phb
+ pla
+ and #$FF00
+ sta :src_bank
+
+ txa
+ asl
+ sta :lines_left_x2
+
+:loop
+ ldx :virt_line_x2
+
+ lda BTableHigh,x
+ ora :src_bank
+ pha
+
+ lda BTableLow,x ; Get the address of the first code field line
+ clc
+ adc LastPatchOffsetArr,x
+ tax
+
+ plb
+ lda: OPCODE_SAVE+$0000,y
+ sta: $0000,x
+
+; Do the end of the loop -- update the virtual line counter and reduce the number
+; of lines left to render
+
+ plb ; restore the bank
+
+ lda :virt_line_x2
+ inc
+ inc
+ sta :virt_line_x2
+ cmp :last_line_x2
+ jne :loop
+
+ stz LastPatchOffset ; Clear the value once completed
+ rts
+
+; Unrolled copy routine to move BankTable entries into BNK_ADDR position. This is a bit different than the
+; other routines, because we don't need to put values into the code fields, but just copy one-byte values
+; into an internal array in bank 00 space. The reason for this is because the code sequence
+;
+; lda #ADDR
+; tcs
+; plb
+;
+; Take only 9 cycles, but the alternative is slower
+;
+; pea #$BBBB
+; plb
+; plb = 13 cycles
+;
+; If for some reason it becomes important to preserve the accumulator, or save the 208 bytes of
+; bank 00 memory, then we can change it. The advantage right now is that updating the array can
+; be done 16-bits at a time and without having to chunk up the writes across multiple banks. This
+; is quite a bit faster than the other routines.
+CopyTableToBankBytes
+
+ tsx ; save the stack
+ sei
+ jmp $0000
+
+ lda: 2,y
+ pha
+ lda: 0,y
+ pha
+bottom
+ txs ; restore the stack
+ cli ; turn interrupts back on
+ rts
diff --git a/src/blitter/Template.s b/src/blitter/Template.s
index 332b534..427249e 100644
--- a/src/blitter/Template.s
+++ b/src/blitter/Template.s
@@ -5,10 +5,12 @@
DP_ADDR equ entry_1-base+1 ; offset to patch in the direct page for dynamic tiles
BG1_ADDR equ entry_2-base+1 ; offset to patch in the Y-reg for BG1 (dp),y addressing
STK_ADDR equ entry_3-base+1 ; offset to patch in the stack (SHR) right edge address
+; BNK_ADDR equ entry_0-base+1 ; offset to patch in the address of a Bank 0 memory location to load the bank register
DP_ENTRY equ entry_1-base
TWO_LYR_ENTRY equ entry_2-base
ONE_LYR_ENTRY equ entry_3-base
+; BANK_ENTRY equ entry_0-base
CODE_ENTRY_OPCODE equ entry_jmp-base
CODE_ENTRY equ entry_jmp-base+1 ; low byte of the page-aligned jump address
@@ -66,6 +68,9 @@ BankPatchNum equ *-BankPatches
; the code is assembled on a page boundary to help with alignment
ds \,$00 ; pad to the next page boundary
base
+;entry_0 lda #0000 ; Used to set per-scanline bank register
+; tcs
+; plb
entry_1 ldx #0000 ; Used for LDA 00,x addressing (Dynamic Tiles)
entry_2 ldy #0000 ; Used for LDA (00),y addressing (Second Layer; BG1)
entry_3 lda #0000 ; Sets screen address (right edge)
diff --git a/src/blitter/TemplateUtils.s b/src/blitter/TemplateUtils.s
index 534b19e..a027127 100644
--- a/src/blitter/TemplateUtils.s
+++ b/src/blitter/TemplateUtils.s
@@ -245,8 +245,8 @@ BuildBank
plb
plb
-; Change the patched value to one of DP_ENTRY, TWO_LYR_ENTRY or ONE_LYR_ENTRY based on the capabilities
-; that the engine needs.
+; Change the patched value to one of BANK_ENTRY, DP_ENTRY, TWO_LYR_ENTRY or ONE_LYR_ENTRY based
+; on the capabilities that the engine needs.
lda #DP_ENTRY
sta :entryOffset
diff --git a/src/blitter/Vert.s b/src/blitter/Vert.s
index e949b73..b31f2f6 100644
--- a/src/blitter/Vert.s
+++ b/src/blitter/Vert.s
@@ -5,7 +5,7 @@
; Based on the current value of StartY in the direct page. Set up the dispatch
; information so that the BltRange driver will render the correct code field
; lines in the correct order
-_ApplyBG0YPos
+_ApplyBG0YPosOld
:rtbl_idx_x2 equ tmp0
:virt_line_x2 equ tmp1
@@ -51,7 +51,7 @@ _ApplyBG0YPos
ldal BTableLow,x ; Get the address of the first code field line
tay
- ldal BTableHigh,x ; Target bank in low byte, current bank in high
+ ldal BTableHigh,x ; Target bank in low byte
pha
txa
@@ -69,7 +69,8 @@ _ApplyBG0YPos
sta :virt_line_x2
plb
- CopyRTableToStkAddr :rtbl_idx_x2 ; X = rtbl_idx_x2 on return
+ jsr _CopyRTableToStkAddr
+; CopyRTableToStkAddr :rtbl_idx_x2 ; X = rtbl_idx_x2 on return
txa ; carry flag is unchanged
adc :draw_count_x2 ; advance the index into the RTable
@@ -87,9 +88,162 @@ _ApplyBG0YPos
plb
rts
+; This is an optimized version of _ApplyBG0YPos. We pre-compute the breakdown across the bank
+; boundries in order to eliminate the the minimum calculation and some loop variable updates
+; from the inner loop.
+
+_ApplyBG0YPos
+
+:rtbl_idx_x2 equ tmp0
+:virt_line_x2 equ tmp1
+:lines_left_x2 equ tmp2
+:draw_count_x2 equ tmp3
+:stk_save equ tmp4
+:line_count equ tmp5
+
+; First task is to fill in the STK_ADDR values by copying them from the RTable array. We
+; copy from RTable[i] into BlitField[StartY+i]. As with all of this code, the difficult part
+; is decomposing the update across banks
+
+ stz :rtbl_idx_x2 ; Start copying from the first entry in the table
+
+ lda StartY ; This is the base line of the virtual screen
+ jsr Mod208
+ sta StartYMod208
+
+ asl
+ sta :virt_line_x2 ; Keep track of it
+
+ phb ; Save the current bank
+ tsc ; we intentionally leak one byte of stack in each loop
+ sta :stk_save ; iteration, so save the stack to repair at the end
+
+; copy a range of address from the table into the destination bank. If we restrict ourselves to
+; rectangular playfields, this can be optimized to just subtracting a constant value. See the
+; Templates::SetScreenAddrs subroutine.
+
+ lda ScreenHeight
+ asl
+ sta :lines_left_x2
+
+; This is the verbose part -- figure out how many lines to draw. We don't want to artificially limit
+; the height of the visible screen (for example, doing an animated wipe while scrolling), so the screen
+; height could be anything from 1 to 200.
+;
+; For larger values, we want to break things up on 16-line boundaries based on the virt_line value. So,
+;
+; draw_count = min(lines_left, (16 - (virt_line % 16))
+
+; Pre-loop: Calculate the number of lines to copy to get the loop into a bank-aligned state
+;
+; lines_in_bank = 16 - (virt_line % 16)
+:pre
+ ldx :virt_line_x2
+ ldal BTableLow,x ; Get the address of the first code field line
+ tay
+
+ ldal BTableHigh,x ; Target bank in low byte
+ pha
+
+ txa
+ and #$001E
+ eor #$FFFF
+ sec
+ adc #32
+ min :lines_left_x2
+
+ sta :draw_count_x2 ; Do this many lines
+ tax
+
+ clc ; pre-advance virt_line_2 because we have the value
+ adc :virt_line_x2
+ sta :virt_line_x2
+
+ plb
+ jsr _CopyRTableToStkAddr
+
+ txa ; carry flag is unchanged
+ adc :draw_count_x2 ; advance the index into the RTable
+ sta :rtbl_idx_x2
+
+ lda :lines_left_x2 ; subtract the number of lines we just completed
+ sec
+ sbc :draw_count_x2
+ sta :lines_left_x2
+
+ jeq :done ; if there are no lines left, we're done!
+ cmp #33
+ jcc :post ; if there are 16 lines or less left, jump to post
+
+; Now we are in the main loop. We know that the virt_line is a multiple of 16, but the number
+; of remaining lines could be any number greater than 0. we test to see if the lines_left are
+; less than 16. If so, we can jump straight to the post-loop update. Otherwise we caculate
+; the number of 16-line iterations and but that in an auxiliary count variable and simplify
+; the loop update.
+
+ tax
+ and #$001E ; this is the number of lines in post
+ sta :lines_left_x2
+ txa
+ lsr
+ lsr
+ lsr
+ lsr
+ lsr
+ sta :line_count ; single byte count, saves 9 cycles per loop iteration
+
+:loop
+ ldx :virt_line_x2
+ ldal BTableLow,x ; Get the address of the first code field line
+ tay
+
+ ldal BTableHigh,x ; Target bank in low byte
+ pha
+
+ lda #32 ; Do this many lines (x2)
+ tax
+
+ clc ; pre-advance virt_line_2 because we have the value
+ adc :virt_line_x2
+ sta :virt_line_x2
+
+ plb
+ CopyRTableToStkAddr :rtbl_idx_x2
+
+ txa ; carry flag is unchanged
+ adc #32 ; advance the index into the RTable
+ sta :rtbl_idx_x2
+
+ dec :line_count
+ jne :loop
+
+ lda :lines_left_x2
+ beq :done
+
+; Draw some number of lines that are less that 16. No need to update loop variabls because we
+; know we are in the last iteration
+
+:post
+ ldx :virt_line_x2
+ ldal BTableLow,x ; Get the address of the first code field line
+ tay
+
+ ldal BTableHigh,x ; Target bank in low byte
+ pha
+
+ ldx :lines_left_x2 ; Do this many lines
+ plb
+ jsr _CopyRTableToStkAddr
+
+:done
+ lda :stk_save
+ tcs
+ plb
+ rts
+
; Unrolled copy routine to move RTable intries into STK_ADDR position.
;
-; A = intect into the RTable array (x2)
+; A = index into the RTable array (x2)
; Y = starting line * $1000
; X = number of lines (x2)
CopyRTableToStkAddr mac
@@ -163,4 +317,8 @@ x02 ldal RTable+02,x
x01 ldal RTable+00,x
sta: STK_ADDR+$0000,y
bottom
- <<<
\ No newline at end of file
+ <<<
+
+_CopyRTableToStkAddr
+ CopyRTableToStkAddr tmp0
+ rts
\ No newline at end of file
diff --git a/src/static/TileStore.s b/src/static/TileStore.s
index 6783380..74e733b 100644
--- a/src/static/TileStore.s
+++ b/src/static/TileStore.s
@@ -535,4 +535,9 @@ Scale14 dw $0038,$003A,$003A,$003A,$003C,$003C,$003C,$003C,$003E,$003E,$003E,$
Scale15 dw $003C,$003C,$003C,$003E,$003E,$003E,$003E,$0040,$0040,$0040,$0040,$0042,$0042,$0042,$0042,$0044,$0044,$0044,$0044,$0046,$0046,$0046,$0046,$0048,$0048,$0048,$0048,$004A,$004A,$004A,$004A,$004C,$004C,$004C,$004C,$004E,$004E,$004E,$004E,$0050,$0050,$0050,$0050,$0052,$0052,$0052,$0052,$0054,$0054,$0054,$0054,$0056,$0056,$0056,$0056,$0058,$0058,$0058,$0058,$005A,$005A,$005A,$005A,$005C,$005C,$005C,$005C,$005E,$005E,$005E,$005E,$0060,$0060,$0060,$0060,$0062,$0062,$0062,$0062,$0064,$0064,$0064
blt_return
-stk_save
\ No newline at end of file
+stk_save
+
+StartXMod164Arr ENT
+ ds 416*2
+LastPatchOffsetArr ENT
+ ds 416*2