commit f720fa90b022c43782e4f303dea1c6ed77526ad7 Author: Víctor Hernández Molpeceres Date: Sat Nov 21 17:29:35 2015 +0100 first project upload diff --git a/images/ball.png b/images/ball.png new file mode 100644 index 0000000..deb5fb1 Binary files /dev/null and b/images/ball.png differ diff --git a/images/cerbero.jpg b/images/cerbero.jpg new file mode 100644 index 0000000..24c9ff8 Binary files /dev/null and b/images/cerbero.jpg differ diff --git a/images/cerdo.png b/images/cerdo.png new file mode 100644 index 0000000..f063179 Binary files /dev/null and b/images/cerdo.png differ diff --git a/images/dream_forest_background.png b/images/dream_forest_background.png new file mode 100644 index 0000000..2a3645f Binary files /dev/null and b/images/dream_forest_background.png differ diff --git a/images/dream_forest_background2.png b/images/dream_forest_background2.png new file mode 100644 index 0000000..84b87ef Binary files /dev/null and b/images/dream_forest_background2.png differ diff --git a/images/enemy1_anim.png b/images/enemy1_anim.png new file mode 100644 index 0000000..47d77e0 Binary files /dev/null and b/images/enemy1_anim.png differ diff --git a/images/fairy_anim.png b/images/fairy_anim.png new file mode 100644 index 0000000..7ed4caa Binary files /dev/null and b/images/fairy_anim.png differ diff --git a/images/fairy_anim2.png b/images/fairy_anim2.png new file mode 100644 index 0000000..3a7fde6 Binary files /dev/null and b/images/fairy_anim2.png differ diff --git a/images/game_over_screen.png b/images/game_over_screen.png new file mode 100644 index 0000000..eed455c Binary files /dev/null and b/images/game_over_screen.png differ diff --git a/images/help.jpg b/images/help.jpg new file mode 100644 index 0000000..bf2d0db Binary files /dev/null and b/images/help.jpg differ diff --git a/images/interfaz.png b/images/interfaz.png new file mode 100644 index 0000000..9b7f7d9 Binary files /dev/null and b/images/interfaz.png differ diff --git a/images/pearl_anim.png b/images/pearl_anim.png new file mode 100644 index 0000000..67a482d Binary files /dev/null and b/images/pearl_anim.png differ diff --git a/images/punch.png b/images/punch.png new file mode 100644 index 0000000..29d242c Binary files /dev/null and b/images/punch.png differ diff --git a/images/rayman_anim.png b/images/rayman_anim.png new file mode 100644 index 0000000..8ea64a4 Binary files /dev/null and b/images/rayman_anim.png differ diff --git a/images/rayman_anim_w_cols.png b/images/rayman_anim_w_cols.png new file mode 100644 index 0000000..77e016a Binary files /dev/null and b/images/rayman_anim_w_cols.png differ diff --git a/images/room.jpg b/images/room.jpg new file mode 100644 index 0000000..e5f01fa Binary files /dev/null and b/images/room.jpg differ diff --git a/images/shield_anim.png b/images/shield_anim.png new file mode 100644 index 0000000..4011d89 Binary files /dev/null and b/images/shield_anim.png differ diff --git a/images/test_sprite.png b/images/test_sprite.png new file mode 100644 index 0000000..030019f Binary files /dev/null and b/images/test_sprite.png differ diff --git a/images/vaca.jpg b/images/vaca.jpg new file mode 100644 index 0000000..1e9bfc0 Binary files /dev/null and b/images/vaca.jpg differ diff --git a/images/water_particle.png b/images/water_particle.png new file mode 100644 index 0000000..d4b53bb Binary files /dev/null and b/images/water_particle.png differ diff --git a/images/win_screen.png b/images/win_screen.png new file mode 100644 index 0000000..22be579 Binary files /dev/null and b/images/win_screen.png differ diff --git a/maps/dream_forest_background.png b/maps/dream_forest_background.png new file mode 100644 index 0000000..97c8f4b Binary files /dev/null and b/maps/dream_forest_background.png differ diff --git a/maps/level1.json b/maps/level1.json new file mode 100644 index 0000000..e552c05 --- /dev/null +++ b/maps/level1.json @@ -0,0 +1,2010 @@ +{ "backgroundcolor":"#bbfaff", + "height":64, + "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, 2112, 2113, 2114, 2115, 2116, 2117, 2118, 2119, 2120, 2121, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2170, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2402, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2113, 2114, 2115, 2116, 2117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2460, 2461, 0, 2463, 2464, 2465, 2466, 2467, 2468, 2469, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2170, 2171, 2172, 2173, 2174, 2175, 2176, 2177, 2178, 2179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2228, 2229, 2230, 2231, 2232, 2233, 2234, 2235, 2236, 2237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2286, 2287, 2288, 2289, 2290, 2291, 2292, 2293, 2294, 2295, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2113, 2114, 2115, 2116, 2117, 2118, 2119, 2120, 2121, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2344, 2345, 2346, 2347, 2348, 2349, 2350, 2351, 2352, 2353, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2410, 2411, 0, 0, 0, 0, 0, 0, 2171, 2172, 2173, 2174, 2175, 2176, 2177, 2178, 2179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2402, 2403, 2404, 2405, 2406, 2407, 2408, 2409, 2410, 2411, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2461, 0, 2463, 2464, 0, 0, 2467, 2468, 2469, 0, 0, 0, 0, 0, 0, 2229, 2230, 2231, 2232, 2233, 2234, 2235, 2236, 2237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2460, 2461, 2462, 2463, 2464, 2465, 2466, 2467, 2468, 2469, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2287, 2288, 2289, 2290, 2291, 2292, 2293, 2294, 2295, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2170, 2171, 2172, 2173, 2174, 2175, 2176, 2177, 2178, 2179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2345, 2346, 2347, 2348, 2349, 2350, 2351, 2352, 2353, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2228, 2229, 2230, 2231, 2232, 2233, 2234, 2235, 2236, 2237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2403, 2404, 2405, 2406, 2407, 2408, 2409, 2410, 2411, 0, 0, 0, 0, 0, 0, 0, 2113, 2114, 2115, 2116, 2117, 2118, 2119, 2120, 2121, 0, 0, 0, 0, 0, 3293, 3294, 3295, 3296, 3297, 3298, 3299, 3300, 3301, 3302, 3303, 3304, 3305, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2286, 2287, 2288, 2289, 2290, 2291, 2292, 2293, 2294, 2295, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2461, 2462, 2463, 2464, 2465, 2466, 2467, 2468, 2469, 0, 0, 0, 0, 0, 0, 0, 2171, 2172, 2173, 2174, 2175, 2176, 2177, 2178, 2179, 0, 0, 0, 0, 0, 3351, 3352, 3353, 3354, 3355, 3356, 3357, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2344, 2345, 2346, 2347, 2348, 2349, 2350, 2351, 2352, 2353, 0, 0, 3318, 3319, 3320, 3321, 3322, 3323, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2229, 2230, 2231, 2232, 2233, 2234, 2235, 2236, 2237, 0, 0, 0, 0, 0, 3409, 3410, 3411, 3412, 3413, 3414, 3415, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2402, 2403, 2404, 2405, 2406, 2407, 2408, 2409, 2410, 2411, 0, 0, 3376, 3377, 3378, 3379, 3380, 3381, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2287, 2288, 2289, 2290, 2291, 2292, 2293, 2294, 2295, 0, 0, 0, 0, 0, 3467, 3468, 3469, 3470, 3471, 3472, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2460, 2461, 2462, 2463, 2464, 2465, 2466, 2467, 2468, 2469, 0, 0, 3434, 3435, 3436, 3437, 3438, 3439, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2345, 2346, 2347, 2348, 2349, 2350, 2351, 2352, 2353, 0, 0, 0, 0, 0, 3525, 3526, 3527, 3528, 3529, 3530, 3531, 3532, 0, 0, 0, 0, 3537, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2170, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3492, 3493, 3494, 3495, 3496, 3497, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2403, 2404, 2405, 2406, 2407, 2408, 2409, 2410, 2411, 0, 0, 0, 0, 0, 3583, 3584, 3585, 3586, 3587, 3588, 3589, 3590, 3591, 3592, 3593, 3594, 3595, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2228, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3550, 3551, 3552, 3553, 3554, 3555, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2461, 2462, 2463, 2464, 2465, 2466, 2467, 2468, 2469, 0, 0, 0, 0, 0, 3641, 3642, 3643, 3644, 3645, 3646, 3647, 3648, 3649, 3650, 3651, 3652, 3653, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2286, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3608, 3609, 3610, 3611, 3612, 3613, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3699, 3700, 3701, 3702, 3703, 3704, 3705, 3706, 3707, 3708, 3709, 3710, 3711, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2344, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3666, 3667, 3668, 3669, 3670, 3671, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3757, 3758, 3759, 3760, 3761, 3762, 3763, 3764, 3765, 3766, 3767, 3768, 3769, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2402, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3724, 3725, 3726, 3727, 3728, 3729, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3815, 3816, 3817, 3818, 3819, 3820, 3821, 3822, 3823, 3824, 3825, 3826, 3827, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2460, 0, 0, 0, 2464, 2465, 2466, 2467, 2468, 2469, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3293, 3294, 3295, 3296, 3297, 3298, 3299, 3300, 3301, 3302, 3303, 3304, 3305, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3873, 3874, 3875, 3876, 3877, 3878, 3879, 3880, 3881, 3882, 3883, 3884, 3885, 0, 0, 0, 0, 0, 3293, 3294, 3295, 3296, 3297, 3298, 3299, 3300, 3301, 3302, 3303, 3304, 3305, 0, 0, 0, 0, 0, 2170, 2171, 2172, 2173, 2174, 2175, 2176, 2177, 2178, 2179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3351, 3352, 3353, 3354, 3355, 3356, 3357, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3931, 3932, 3933, 3934, 3935, 3936, 3937, 3938, 3939, 3940, 3941, 3942, 3943, 0, 0, 0, 0, 0, 3351, 3352, 3353, 3354, 3355, 3356, 3357, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2228, 2229, 2230, 2231, 2232, 2233, 2234, 2235, 2236, 2237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3409, 3410, 3411, 3412, 3413, 3414, 3415, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3989, 3990, 3991, 3992, 3993, 3994, 3995, 3996, 3997, 3998, 3999, 4000, 4001, 0, 0, 0, 0, 0, 3409, 3410, 3411, 3412, 3413, 3414, 3415, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2286, 2287, 2288, 2289, 2290, 2291, 2292, 2293, 2294, 2295, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3467, 3468, 3469, 3470, 3471, 3472, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4047, 4048, 4049, 4050, 4051, 4052, 4053, 4054, 4055, 4056, 4057, 4058, 4059, 0, 0, 0, 0, 0, 3467, 3468, 3469, 3470, 3471, 3472, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2344, 2345, 2346, 2347, 2348, 2349, 2350, 2351, 2352, 2353, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3525, 3526, 3527, 3528, 3529, 3530, 3531, 3532, 0, 0, 0, 0, 3537, 0, 0, 0, 0, 2634, 2635, 2636, 2637, 2638, 2639, 2640, 2641, 2642, 2643, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4105, 4106, 4107, 4108, 4109, 4110, 4111, 4112, 4113, 4114, 4115, 4116, 4117, 0, 0, 0, 0, 0, 3525, 3526, 3527, 3528, 3529, 3530, 3531, 3532, 0, 0, 0, 0, 3537, 0, 0, 0, 0, 0, 2402, 2403, 2404, 2405, 2406, 2407, 2408, 2409, 2410, 2411, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3583, 3584, 3585, 3586, 3587, 3588, 3589, 3590, 3591, 3592, 3593, 3594, 3595, 0, 0, 0, 0, 2692, 2693, 2694, 2695, 2696, 2697, 2698, 2699, 2700, 2701, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4163, 4164, 4165, 4166, 4167, 4168, 4169, 4170, 4171, 4172, 4173, 4174, 4175, 0, 0, 0, 0, 0, 3583, 3584, 3585, 3586, 3587, 3588, 3589, 3590, 3591, 3592, 3593, 3594, 3595, 0, 0, 0, 0, 0, 2460, 2461, 2462, 2463, 2464, 2465, 2466, 2467, 2468, 2469, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3641, 3642, 3643, 3644, 3645, 3646, 3647, 3648, 3649, 3650, 3651, 3652, 3653, 0, 0, 0, 0, 2750, 2751, 2752, 2753, 2754, 2755, 2756, 2757, 2758, 2759, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4221, 4222, 4223, 4224, 4225, 4226, 4227, 4228, 4229, 4230, 4231, 4232, 4233, 0, 0, 0, 0, 0, 3641, 3642, 3643, 3644, 3645, 3646, 3647, 3648, 3649, 3650, 3651, 3652, 3653, 0, 0, 0, 0, 0, 2170, 2171, 2172, 2173, 2174, 2175, 2176, 2177, 2178, 2179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3699, 3700, 3701, 3702, 3703, 3704, 3705, 3706, 3707, 3708, 3709, 3710, 3711, 0, 0, 0, 0, 2808, 2809, 2810, 2811, 2812, 2813, 2814, 2815, 2816, 2817, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4279, 4280, 4281, 4282, 4283, 4284, 4285, 4286, 4287, 4288, 4289, 4290, 4291, 0, 0, 0, 0, 0, 3699, 3700, 3701, 3702, 3703, 3704, 3705, 3706, 3707, 3708, 3709, 3710, 3711, 0, 0, 0, 0, 0, 2228, 2229, 2230, 2231, 2232, 2233, 2234, 2235, 2236, 2237, 0, 0, 0, 0, 2635, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3757, 3758, 3759, 3760, 3761, 3762, 3763, 3764, 3765, 3766, 3767, 3768, 3769, 0, 0, 0, 0, 2866, 2867, 2868, 2869, 2870, 2871, 2872, 2873, 2874, 2875, 0, 0, 3318, 3319, 3320, 3321, 3322, 3323, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3757, 3758, 3759, 3760, 3761, 3762, 3763, 3764, 3765, 3766, 3767, 3768, 3769, 0, 0, 0, 0, 0, 2286, 2287, 2288, 2289, 2290, 2291, 2292, 2293, 2294, 2295, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3815, 3816, 3817, 3818, 3819, 3820, 3821, 3822, 3823, 3824, 3825, 3826, 3827, 0, 0, 0, 0, 2924, 2925, 2926, 2927, 2928, 2929, 2930, 2931, 2932, 2933, 0, 0, 3376, 3377, 3378, 3379, 3380, 3381, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3815, 3816, 3817, 3818, 3819, 3820, 3821, 3822, 3823, 3824, 3825, 3826, 3827, 0, 0, 0, 0, 0, 2344, 2345, 2346, 2347, 2348, 2349, 2350, 2351, 2352, 2353, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3873, 3874, 3875, 3876, 3877, 3878, 3879, 3880, 3881, 3882, 3883, 3884, 3885, 0, 0, 0, 0, 2982, 2983, 2984, 2985, 2986, 2987, 2988, 2989, 2990, 2991, 0, 0, 3434, 3435, 3436, 3437, 3438, 3439, 0, 0, 0, 0, 0, 0, 3283, 3284, 3285, 3286, 3287, 3288, 3289, 3290, 3291, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3873, 3874, 3875, 3876, 3877, 3878, 3879, 3880, 3881, 3882, 3883, 3884, 3885, 0, 0, 0, 0, 0, 2402, 2403, 2404, 2405, 2406, 2407, 2408, 2409, 2410, 2411, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3931, 3932, 3933, 3934, 3935, 3936, 3937, 3938, 3939, 3940, 3941, 3942, 3943, 0, 0, 0, 0, 0, 0, 3318, 3319, 3320, 3321, 3322, 3323, 0, 0, 0, 0, 3492, 3493, 3494, 3495, 3496, 3497, 0, 0, 0, 0, 0, 0, 3341, 3342, 3343, 3344, 3345, 3346, 3347, 3348, 3349, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3931, 3932, 3933, 3934, 3935, 3936, 3937, 3938, 3939, 3940, 3941, 3942, 3943, 0, 0, 0, 0, 0, 2460, 2461, 2462, 2463, 2464, 2465, 2466, 2467, 2468, 2469, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3989, 3990, 3991, 3992, 3993, 3994, 3995, 3996, 3997, 3998, 3999, 4000, 4001, 0, 0, 0, 0, 0, 0, 3376, 3377, 3378, 3379, 3380, 3381, 0, 0, 0, 0, 3550, 3551, 3552, 3553, 3554, 3555, 0, 0, 0, 0, 0, 0, 3399, 3400, 3401, 3402, 3403, 3404, 3405, 3406, 3407, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3989, 3990, 3991, 3992, 3993, 3994, 3995, 3996, 3997, 3998, 3999, 4000, 4001, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4047, 4048, 4049, 4050, 4051, 4052, 4053, 4054, 4055, 4056, 4057, 4058, 4059, 0, 0, 0, 0, 0, 0, 3434, 3435, 3436, 3437, 3438, 3439, 0, 0, 0, 0, 3608, 3609, 3610, 3611, 3612, 3613, 0, 0, 0, 0, 0, 0, 3457, 3458, 3459, 3460, 3461, 3462, 3463, 3464, 3465, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4047, 4048, 4049, 4050, 4051, 4052, 4053, 4054, 4055, 4056, 4057, 4058, 4059, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4105, 4106, 4107, 4108, 4109, 4110, 4111, 4112, 4113, 4114, 4115, 4116, 4117, 0, 0, 0, 0, 0, 0, 3492, 3493, 3494, 3495, 3496, 3497, 0, 0, 0, 0, 3666, 3667, 3668, 3669, 3670, 3671, 0, 0, 0, 0, 0, 0, 3515, 3516, 3517, 3518, 3519, 3520, 3521, 3522, 3523, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4105, 4106, 4107, 4108, 4109, 4110, 4111, 4112, 4113, 4114, 4115, 4116, 4117, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4163, 4164, 4165, 4166, 4167, 4168, 4169, 4170, 4171, 4172, 4173, 4174, 4175, 3321, 3322, 3323, 0, 0, 0, 3550, 3551, 3552, 3553, 3554, 3555, 0, 0, 0, 0, 3724, 3725, 3726, 3727, 3728, 3729, 0, 0, 0, 0, 0, 0, 3573, 3574, 3575, 3576, 3577, 3578, 3579, 3580, 3581, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4163, 4164, 4165, 4166, 4167, 4168, 4169, 4170, 4171, 4172, 4173, 4174, 4175, 0, 0, 0, 0, 0, 0, 2112, 2113, 2114, 2115, 2116, 2117, 2118, 2119, 2120, 2121, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4221, 4222, 4223, 4224, 4225, 4226, 4227, 4228, 4229, 4230, 4231, 4232, 4233, 3379, 3380, 3381, 0, 0, 0, 3608, 3609, 3610, 3611, 3612, 3613, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3631, 3632, 3633, 3634, 3635, 3636, 3637, 3638, 3639, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4221, 4222, 4223, 4224, 4225, 4226, 4227, 4228, 4229, 4230, 4231, 4232, 4233, 0, 0, 0, 0, 0, 0, 2170, 2171, 2172, 2173, 2174, 2175, 2176, 2177, 2178, 2179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4279, 4280, 4281, 4282, 4283, 4284, 4285, 4286, 4287, 4288, 4289, 4290, 4291, 3437, 3438, 3439, 0, 0, 0, 3666, 3667, 3668, 3669, 3670, 3671, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3689, 3690, 3691, 3692, 3693, 3694, 3695, 3696, 3697, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4279, 4280, 4281, 4282, 4283, 4284, 4285, 4286, 4287, 4288, 4289, 4290, 4291, 0, 0, 0, 0, 0, 0, 2228, 2229, 2230, 2231, 2232, 2233, 2234, 2235, 2236, 2237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3492, 3493, 3494, 3495, 3496, 3497, 0, 0, 0, 3724, 3725, 3726, 3727, 3728, 3729, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3747, 3748, 3749, 3750, 3751, 3752, 3753, 3754, 3755, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2286, 2287, 2288, 2289, 2290, 2291, 2292, 2293, 2294, 2295, 0, 0, 0, 2635, 2636, 2637, 2638, 2639, 2640, 2641, 2642, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3550, 3551, 3552, 3553, 3554, 3555, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3805, 3806, 3807, 3808, 3809, 3810, 3811, 3812, 3813, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2344, 2345, 2346, 2347, 2348, 2349, 2350, 2351, 2352, 2353, 0, 0, 0, 2693, 2694, 2695, 2696, 2697, 2698, 2699, 2700, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3608, 3609, 3610, 3611, 3612, 3613, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3863, 3864, 3865, 3866, 3867, 3868, 3869, 3870, 3871, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2402, 2403, 2404, 2405, 2406, 2407, 2408, 2409, 2410, 2411, 0, 0, 0, 2751, 2752, 2753, 2754, 2755, 2756, 2757, 2758, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3666, 3667, 3668, 3669, 3670, 3671, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3921, 3922, 3923, 3924, 3925, 3926, 3927, 3928, 3929, 3318, 3319, 3320, 3321, 3322, 3323, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2460, 2461, 2462, 2463, 2464, 2465, 2466, 2467, 2468, 2469, 0, 0, 0, 2809, 2810, 2811, 2812, 2813, 2814, 2815, 2816, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3724, 3725, 3726, 3727, 3728, 3729, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3979, 3980, 3981, 3982, 3983, 3984, 3985, 3986, 3987, 3376, 3377, 3378, 3379, 3380, 3381, 0, 0, 0, 0, 0, 0, 534, 535, 536, 537, 538, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2867, 2868, 2869, 2870, 2871, 2872, 2873, 2874, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4037, 4038, 4039, 4040, 4041, 4042, 4043, 4044, 4045, 3434, 3435, 3436, 3437, 3438, 3439, 0, 0, 0, 0, 0, 0, 593, 594, 595, 596, 597, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2113, 2114, 2115, 2116, 2117, 2118, 2119, 2120, 2121, 0, 0, 2925, 2926, 2927, 2928, 2929, 2930, 2931, 2932, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1172, 1173, 1174, 1175, 1176, 1177, 0, 1179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3492, 3493, 3494, 3495, 3496, 3497, 0, 0, 0, 0, 0, 0, 652, 653, 654, 655, 656, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2171, 2172, 2173, 2174, 2175, 2176, 2177, 2178, 2179, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1230, 1231, 1232, 1233, 1234, 1235, 1236, 1237, 1238, 1239, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3550, 3551, 3552, 3553, 3554, 3555, 0, 0, 0, 0, 0, 710, 711, 712, 713, 714, 715, 716, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2229, 2230, 2231, 2232, 2233, 2234, 2235, 2236, 2237, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1287, 1288, 1289, 1290, 1291, 1292, 1293, 1294, 1295, 1296, 1297, 1298, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3608, 3609, 3610, 3611, 3612, 3613, 0, 0, 0, 0, 0, 769, 770, 771, 772, 773, 774, 775, 776, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2287, 2288, 2289, 2290, 2291, 2292, 2293, 2294, 2295, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1344, 1345, 1346, 1347, 1348, 1349, 1350, 1351, 1352, 1353, 1354, 1355, 1356, 1357, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3666, 3667, 3668, 3669, 3670, 3671, 0, 0, 0, 0, 0, 0, 829, 830, 831, 832, 833, 0, 835, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2345, 2346, 2347, 2348, 2349, 2350, 2351, 2352, 2353, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1403, 1404, 1405, 1406, 1407, 1408, 1409, 1410, 1411, 1412, 1413, 1414, 1415, 1416, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 43, 44, 0, 0, 0, 0, 3724, 3725, 3726, 3727, 3728, 3729, 0, 0, 0, 0, 0, 0, 888, 889, 890, 891, 892, 893, 894, 895, 896, 897, 898, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2403, 2404, 2405, 2406, 2407, 2408, 2409, 2410, 2411, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1465, 1466, 1467, 1468, 1469, 1470, 1471, 1472, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 102, 103, 104, 105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 945, 946, 947, 948, 949, 950, 951, 952, 953, 954, 955, 956, 957, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2461, 2462, 2463, 2464, 2465, 2466, 2467, 2468, 2469, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1525, 1526, 1527, 1528, 1529, 1530, 1531, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 161, 162, 163, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1004, 1005, 1006, 1007, 1008, 1009, 1010, 1011, 1012, 1013, 1014, 1015, 1016, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1586, 1587, 1588, 1589, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 217, 218, 219, 220, 221, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1063, 1064, 1065, 1066, 1067, 1068, 1069, 1070, 1071, 1072, 1073, 1074, 1075, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1645, 1646, 1647, 1648, 0, 0, 0, 0, 0, 0, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 274, 275, 276, 277, 278, 279, 280, 281, 282, 0, 0, 0, 286, 287, 288, 289, 290, 0, 0, 0, 0, 1122, 1123, 1124, 1125, 1126, 1127, 1128, 1129, 1130, 1131, 1132, 1133, 1134, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1702, 1703, 1704, 1705, 1706, 1707, 1708, 1709, 0, 0, 0, 0, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 321, 322, 0, 0, 0, 0, 0, 0, 0, 0, 331, 332, 333, 334, 335, 336, 337, 338, 339, 340, 341, 342, 343, 0, 345, 346, 347, 348, 349, 0, 0, 0, 0, 0, 0, 1183, 1184, 1185, 1186, 1187, 1188, 1189, 1190, 1191, 1192, 1193, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1712, 1713, 1714, 1715, 1716, 1717, 1718, 1719, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 60, 61, 62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1761, 1762, 1763, 1764, 1765, 1766, 1767, 1768, 0, 0, 0, 0, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 140, 141, 142, 143, 0, 380, 381, 382, 383, 384, 385, 386, 0, 0, 389, 390, 391, 392, 393, 394, 395, 396, 397, 398, 399, 400, 401, 402, 403, 404, 405, 406, 407, 408, 409, 410, 411, 412, 0, 0, 1242, 1243, 1244, 1245, 1246, 1247, 1248, 1249, 0, 0, 0, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 136, 137, 138, 136, 137, 138, 138, 139, 140, 141, 142, 143, 138, 139, 140, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 1771, 1772, 1773, 1774, 1775, 1776, 1777, 1778, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 119, 120, 121, 122, 123, 124, 125, 126, 127, 128, 129, 130, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 1819, 1820, 1821, 1822, 1823, 1824, 1825, 1826, 1827, 139, 140, 141, 142, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 199, 200, 201, 202, 438, 439, 440, 441, 442, 443, 444, 445, 446, 447, 448, 449, 450, 451, 452, 453, 454, 455, 456, 457, 458, 459, 460, 461, 462, 463, 464, 465, 466, 467, 468, 469, 470, 471, 0, 0, 0, 1302, 1303, 1304, 1305, 1306, 1307, 1308, 1309, 1310, 1311, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 195, 196, 197, 195, 196, 197, 197, 198, 199, 200, 201, 202, 197, 198, 199, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 1830, 1831, 1832, 1833, 1834, 1835, 1836, 1837, 1838, 1839, 1840, 1841, 1837, 1838, 1839, 1840, 1841, 1837, 1838, 1839, 1840, 1841, 1837, 1838, 1839, 1840, 1841, 1837, 1838, 1839, 1840, 1841, 1837, 1838, 1839, 1840, 1841, 1837, 1838, 1839, 1840, 1841, 1837, 1838, 1839, 1840, 1841, 1837, 1838, 1839, 1840, 1841, 1837, 1838, 1839, 1840, 1841, 1837, 1838, 1839, 1840, 1841, 1837, 1838, 1839, 1840, 1841, 1837, 1838, 1839, 1840, 1841, 1837, 1838, 1839, 1840, 1841, 1837, 1838, 178, 179, 180, 181, 182, 183, 184, 185, 186, 187, 188, 189, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 201, 202, 190, 191, 192, 193, 194, 195, 196, 197, 198, 199, 200, 1878, 1879, 1880, 1881, 1882, 1883, 1884, 1885, 1886, 198, 199, 200, 201, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 258, 259, 260, 261, 497, 498, 499, 500, 501, 502, 503, 504, 505, 506, 507, 508, 509, 510, 511, 512, 513, 514, 515, 516, 517, 518, 519, 520, 521, 522, 523, 524, 525, 526, 527, 528, 529, 530, 531, 1359, 1360, 1361, 1362, 1363, 1364, 1365, 1366, 1367, 1368, 1369, 1370, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 254, 255, 256, 254, 255, 256, 256, 257, 258, 259, 260, 261, 256, 257, 258, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 1889, 1890, 1891, 1892, 1893, 1894, 1895, 1896, 1897, 1898, 1899, 1900, 1896, 1897, 1898, 1899, 1900, 1896, 1897, 1898, 1899, 1900, 1896, 1897, 1898, 1899, 1900, 1896, 1897, 1898, 1899, 1900, 1896, 1897, 1898, 1899, 1900, 1896, 1897, 1898, 1899, 1900, 1896, 1897, 1898, 1899, 1900, 1896, 1897, 1898, 1899, 1900, 1896, 1897, 1898, 1899, 1900, 1896, 1897, 1898, 1899, 1900, 1896, 1897, 1898, 1899, 1900, 1896, 1897, 1898, 1899, 1900, 1896, 1897, 1898, 1899, 1900, 1896, 1897, 237, 238, 239, 240, 241, 242, 243, 244, 245, 246, 247, 248, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 249, 250, 251, 252, 253, 254, 255, 256, 257, 258, 259, 260, 261, 256, 257, 258, 259, 260, 261, 256, 257, 258, 259, 260, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 317, 318, 319, 320, 556, 557, 558, 559, 560, 561, 562, 563, 564, 565, 566, 567, 568, 569, 570, 571, 572, 573, 574, 575, 576, 577, 578, 579, 580, 581, 582, 583, 584, 585, 586, 587, 588, 589, 590, 1418, 1419, 1420, 1421, 1422, 1423, 1424, 1425, 1426, 1427, 1428, 1429, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 313, 314, 315, 313, 314, 315, 315, 316, 317, 318, 319, 320, 315, 316, 317, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 1948, 1949, 1950, 1951, 1952, 1953, 1954, 1955, 1956, 1957, 1958, 1959, 1955, 1956, 1957, 1958, 1959, 1955, 1956, 1957, 1958, 1959, 1955, 1956, 1957, 1958, 1959, 1955, 1956, 1957, 1958, 1959, 1955, 1956, 1957, 1958, 1959, 1955, 1956, 1957, 1958, 1959, 1955, 1956, 1957, 1958, 1959, 1955, 1956, 1957, 1958, 1959, 1955, 1956, 1957, 1958, 1959, 1955, 1956, 1957, 1958, 1959, 1955, 1956, 1957, 1958, 1959, 1955, 1956, 1957, 1958, 1959, 1955, 1956, 1957, 1958, 1959, 1955, 1956, 296, 297, 298, 299, 300, 301, 302, 303, 304, 305, 306, 307, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 308, 309, 310, 311, 312, 313, 314, 315, 316, 317, 318, 319, 320, 315, 316, 317, 318, 319, 320, 315, 316, 317, 318, 319], + "height":64, + "name":"Fondo", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":256, + "x":0, + "y":0 + }, + { + "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, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2634, 2635, 2636, 2637, 2638, 2639, 2640, 2641, 2642, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2634, 2635, 2636, 2637, 2638, 2639, 2640, 2641, 2642, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2692, 2693, 2694, 2695, 2696, 2697, 2698, 2699, 2700, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2692, 2693, 2694, 2695, 2696, 2697, 2698, 2699, 2700, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2750, 2751, 2752, 2753, 2754, 2755, 2756, 2757, 2758, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2750, 2751, 2752, 2753, 2754, 2755, 2756, 2757, 2758, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2808, 2809, 2810, 2811, 2812, 2813, 2814, 2815, 2816, 0, 0, 0, 0, 0, 3318, 3319, 3320, 3321, 3322, 3323, 0, 0, 0, 0, 0, 2808, 2809, 2810, 2811, 2812, 2813, 2814, 2815, 2816, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2866, 2867, 2868, 2869, 2870, 2871, 2872, 2873, 2874, 0, 0, 0, 0, 0, 3376, 3377, 3378, 3379, 3380, 3381, 0, 0, 0, 0, 0, 2866, 2867, 2868, 2869, 2870, 2871, 2872, 2873, 2874, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2924, 2925, 2926, 2927, 2928, 2929, 2930, 2931, 2932, 0, 0, 0, 0, 0, 3434, 3435, 3436, 3437, 3438, 3439, 0, 0, 0, 0, 0, 2924, 2925, 2926, 2927, 2928, 2929, 2930, 2931, 2932, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3492, 3493, 3494, 3495, 3496, 3497, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3550, 3551, 3552, 3553, 3554, 3555, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3608, 3609, 3610, 3611, 3612, 3613, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3293, 3294, 3295, 3296, 3297, 3298, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3666, 3667, 3668, 3669, 3670, 3671, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3351, 3352, 3353, 3354, 3355, 3356, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3724, 3725, 3726, 3727, 3728, 3729, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3409, 3410, 3411, 3412, 3413, 3414, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1041, 1042, 1043, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3283, 3284, 3285, 3286, 3287, 3288, 3289, 3290, 3291, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3467, 3468, 3469, 3470, 3471, 3472, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2577, 2578, 2579, 2580, 2581, 2582, 2583, 2584, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1100, 1101, 1102, 1103, 1104, 1105, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3341, 3342, 3343, 3344, 3345, 3346, 3347, 3348, 3349, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3525, 3526, 3527, 3528, 3529, 3530, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2635, 2636, 2637, 2638, 2639, 2640, 2641, 2642, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1159, 1160, 1161, 1162, 1163, 1164, 1165, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3399, 3400, 3401, 3402, 3403, 3404, 3405, 3406, 3407, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3583, 3584, 3585, 3586, 3587, 3588, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2693, 2694, 2695, 2696, 2697, 2698, 2699, 2700, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1217, 1218, 1219, 1220, 1221, 1222, 1223, 1224, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3457, 3458, 3459, 3460, 3461, 3462, 3463, 3464, 3465, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2049, 2050, 2051, 2052, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2751, 2752, 2753, 2754, 2755, 2756, 2757, 2758, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1258, 1259, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1275, 1276, 1277, 1278, 1279, 1280, 1281, 1282, 1283, 1284, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3515, 3516, 3517, 3518, 3519, 3520, 3521, 3522, 3523, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2107, 2108, 2109, 2110, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2809, 2810, 2811, 2812, 2813, 2814, 2815, 2816, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1316, 1317, 1318, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1334, 1335, 1336, 1337, 1338, 1339, 1340, 1341, 1342, 1343, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3573, 3574, 3575, 3576, 3577, 3578, 3579, 3580, 3581, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2165, 2166, 2167, 2168, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2867, 2868, 2869, 2870, 2871, 2872, 2873, 2874, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1374, 1375, 1376, 1377, 1378, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1392, 1393, 1394, 1395, 1396, 1397, 1398, 1399, 1400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3631, 3632, 3633, 3634, 3635, 3636, 3637, 3638, 3639, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2223, 2224, 2225, 2226, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2925, 2926, 2927, 2928, 2929, 2930, 2931, 2932, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1433, 1434, 1435, 1436, 1437, 1438, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1452, 1453, 1454, 1455, 1456, 1457, 1458, 1459, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3689, 3690, 3691, 3692, 3693, 3694, 3695, 3696, 3697, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2281, 2282, 2283, 2284, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1491, 1492, 1493, 1494, 1495, 1496, 1497, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1513, 1514, 1515, 1516, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3747, 3748, 3749, 3750, 3751, 3752, 3753, 3754, 3755, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2339, 2340, 2341, 2342, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1546, 1547, 1548, 1549, 1550, 1551, 1552, 1553, 1554, 1555, 1556, 1557, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1572, 1573, 1574, 1575, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3805, 3806, 3807, 3808, 3809, 3810, 3811, 3812, 3813, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2397, 2398, 2399, 2400, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 871, 872, 873, 874, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1605, 1606, 1607, 1608, 1609, 1610, 1611, 1612, 1613, 1614, 1615, 0, 0, 1618, 1619, 1620, 1621, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1633, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3293, 3294, 3295, 3296, 3297, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3863, 3864, 3865, 3866, 3867, 3868, 3869, 3870, 3871, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2455, 2456, 2457, 2458, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 929, 930, 931, 932, 933, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1666, 1667, 1668, 1669, 1670, 1671, 1672, 1673, 1674, 0, 0, 1677, 1678, 1679, 1680, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1691, 1692, 1693, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3351, 3352, 3353, 3354, 3355, 3356, 0, 0, 0, 0, 0, 0, 0, 0, 3921, 3922, 3923, 3924, 3925, 3926, 3927, 3928, 3929, 0, 0, 0, 2035, 2036, 2037, 2038, 2039, 2040, 2041, 2042, 2043, 2044, 2045, 2046, 2047, 2048, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3318, 3319, 3320, 3321, 3322, 3323, 0, 0, 0, 0, 0, 0, 0, 0, 2513, 2514, 2515, 2516, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 988, 989, 990, 991, 992, 993, 994, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1725, 1726, 1727, 1728, 1729, 1730, 1731, 1732, 1733, 1734, 1735, 1736, 1737, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1750, 1751, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3409, 3410, 3411, 3412, 3413, 3414, 0, 0, 0, 0, 0, 0, 0, 0, 3979, 3980, 3981, 3982, 3983, 3984, 3985, 3986, 3987, 0, 0, 0, 2093, 2094, 2095, 2096, 2097, 2098, 2099, 2100, 2101, 2102, 2103, 2104, 2105, 2106, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3376, 3377, 3378, 3379, 3380, 3381, 0, 0, 0, 0, 0, 0, 0, 0, 2571, 2572, 2573, 2574, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4012, 4013, 0, 0, 0, 0, 0, 4019, 4020, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1047, 1048, 1049, 1050, 1051, 1052, 1053, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1787, 1788, 1789, 1790, 1791, 1792, 1793, 1794, 1795, 1796, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1809, 1810, 1811, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3467, 3468, 3469, 3470, 3471, 3472, 0, 0, 0, 0, 0, 0, 0, 0, 4037, 4038, 4039, 4040, 4041, 4042, 4043, 4044, 4045, 0, 0, 0, 2151, 2152, 2153, 2154, 2155, 2156, 2157, 2158, 2159, 2160, 2161, 2162, 2163, 2164, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3434, 3435, 3436, 3437, 3438, 3439, 0, 0, 0, 0, 0, 0, 0, 0, 2629, 2630, 2631, 2632, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4070, 4071, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1106, 1107, 1108, 1109, 1110, 1111, 1112, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1846, 1847, 1848, 1849, 1850, 1851, 1852, 1853, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1868, 1869, 1870, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3525, 3526, 3527, 3528, 3529, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4095, 4096, 4097, 4098, 4099, 4100, 4101, 4102, 4103, 0, 0, 0, 2209, 2210, 2211, 2212, 2213, 2214, 2215, 2216, 2217, 2218, 2219, 2220, 2221, 2222, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3492, 3493, 3494, 3495, 3496, 3497, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2688, 2689, 2690, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 4128, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1473, 1474, 1475, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1166, 1167, 1168, 1169, 1170, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1904, 1905, 1906, 1907, 1908, 1909, 1910, 1911, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1927, 1928, 1929, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3583, 3584, 3585, 3586, 3587, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2267, 2268, 2269, 2270, 2271, 2272, 2273, 2274, 2275, 2276, 2277, 2278, 2279, 2280, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3550, 3551, 3552, 3553, 3554, 3555, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2746, 2747, 2748, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1532, 1533, 1534, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1225, 1226, 1227, 1228, 1229, 1230, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1963, 1964, 1965, 1966, 1967, 1968, 1969, 1970, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1985, 1986, 1987, 1988, 1989, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3641, 3642, 3643, 3644, 3645, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2325, 2326, 2327, 2328, 2329, 2330, 2331, 2332, 2333, 2334, 2335, 2336, 2337, 2338, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3608, 3609, 3610, 3611, 3612, 3613, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2804, 2805, 2806, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1591, 1592, 1593, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3699, 3700, 3701, 3702, 3703, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2383, 2384, 2385, 2386, 2387, 2388, 2389, 2390, 2391, 2392, 2393, 2394, 2395, 2396, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3666, 3667, 3668, 3669, 3670, 3671, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2862, 2863, 2864, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3757, 3758, 3759, 3760, 3761, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2441, 2442, 2443, 2444, 2445, 2446, 2447, 2448, 2449, 2450, 2451, 2452, 2453, 2454, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 3724, 3725, 3726, 3727, 3728, 3729, 0, 0, 0, 0, 0, 0, 0, 0, 0, 2920, 2921, 2922, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + "height":64, + "name":"Fondo2", + "opacity":1, + "type":"tilelayer", + "visible":true, + "width":256, + "x":0, + "y":0 + }, + { + "color":"#000000", + "draworder":"topdown", + "height":0, + "name":"Platforms", + "objects":[ + { + "height":13, + "id":3, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":443, + "x":2, + "y":987 + }, + { + "height":16, + "id":4, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":42, + "x":483, + "y":979 + }, + { + "height":13, + "id":5, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":75, + "x":529, + "y":985 + }, + { + "height":14, + "id":7, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":33, + "x":606, + "y":978 + }, + { + "height":12, + "id":8, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":39, + "x":630, + "y":970 + }, + { + "height":13, + "id":9, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":37, + "x":647, + "y":960 + }, + { + "height":12, + "id":10, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":43, + "x":662, + "y":950 + }, + { + "height":14, + "id":11, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":83, + "x":683, + "y":941 + }, + { + "height":18, + "id":12, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":27, + "x":757, + "y":949 + }, + { + "height":17, + "id":13, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":32, + "x":775, + "y":956 + }, + { + "height":20, + "id":14, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":24, + "x":801, + "y":965 + }, + { + "height":15, + "id":15, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":40, + "x":813, + "y":977 + }, + { + "height":14, + "id":16, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":125, + "x":848, + "y":983 + }, + { + "height":13, + "id":17, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":35, + "x":881, + "y":944 + }, + { + "height":13, + "id":18, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":195, + "x":997, + "y":915 + }, + { + "height":12, + "id":19, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":165, + "x":1014, + "y":903 + }, + { + "height":13, + "id":20, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":119, + "x":1030, + "y":893 + }, + { + "height":12, + "id":21, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":71, + "x":843, + "y":836 + }, + { + "height":13, + "id":22, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":61, + "x":704, + "y":753 + }, + { + "height":12, + "id":23, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":121, + "x":702, + "y":674 + }, + { + "height":14, + "id":24, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":80, + "x":715, + "y":617 + }, + { + "height":13, + "id":25, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":80, + "x":199, + "y":737 + }, + { + "height":9, + "id":26, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":82, + "x":342, + "y":675 + }, + { + "height":17, + "id":27, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":77, + "x":505, + "y":623 + }, + { + "height":14, + "id":28, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":116, + "x":323, + "y":528 + }, + { + "height":12.6667, + "id":30, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":43.3333, + "x":191.333, + "y":611.333 + }, + { + "height":10, + "id":31, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":28, + "x":165.333, + "y":615.333 + }, + { + "height":14, + "id":32, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":60, + "x":48.6667, + "y":606 + }, + { + "height":13.3333, + "id":33, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":36, + "x":96, + "y":598 + }, + { + "height":10.6667, + "id":34, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":32.6667, + "x":124, + "y":605.333 + }, + { + "height":12.6667, + "id":35, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":21.3333, + "x":147.333, + "y":610 + }, + { + "height":11.3333, + "id":36, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":22.6667, + "x":82, + "y":601.333 + }, + { + "height":12.6667, + "id":37, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":65.3333, + "x":48.6667, + "y":460 + }, + { + "height":13.3333, + "id":39, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":121.333, + "x":496.667, + "y":228 + }, + { + "height":15, + "id":40, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":121, + "x":753, + "y":307 + }, + { + "height":14, + "id":41, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":68, + "x":992, + "y":295 + }, + { + "height":16, + "id":42, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":50, + "x":992, + "y":443 + }, + { + "height":13, + "id":43, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":39, + "x":1138, + "y":446 + }, + { + "height":12, + "id":44, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":34, + "x":1109, + "y":454 + }, + { + "height":14, + "id":45, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":46, + "x":1033, + "y":436 + }, + { + "height":10, + "id":46, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":27, + "x":1074, + "y":444 + }, + { + "height":14, + "id":47, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":21, + "x":1095, + "y":450 + }, + { + "height":12, + "id":48, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":64, + "x":1281, + "y":459 + }, + { + "height":13, + "id":49, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":52, + "x":1280, + "y":606 + }, + { + "height":17, + "id":50, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":32, + "x":1313, + "y":595 + }, + { + "height":15, + "id":51, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":33, + "x":1340, + "y":597 + }, + { + "height":15, + "id":52, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":37, + "x":1365, + "y":604 + }, + { + "height":15, + "id":53, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":35, + "x":1397, + "y":614 + }, + { + "height":16, + "id":54, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":42, + "x":1424, + "y":604 + }, + { + "height":10, + "id":56, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":122, + "x":1570, + "y":262 + }, + { + "height":14, + "id":60, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":124, + "x":1569, + "y":450 + }, + { + "height":12, + "id":62, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":124, + "x":1567, + "y":550 + }, + { + "height":17, + "id":64, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":122, + "x":1585, + "y":707 + }, + { + "height":14, + "id":65, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":121, + "x":1777, + "y":746 + }, + { + "height":12, + "id":66, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":121, + "x":1601, + "y":836 + }, + { + "height":11, + "id":67, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":47, + "x":1265, + "y":881 + }, + { + "height":15, + "id":68, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":46, + "x":1486, + "y":895 + }, + { + "height":13, + "id":70, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":90, + "x":1349, + "y":873 + }, + { + "height":17, + "id":71, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":847, + "x":1199, + "y":991 + }, + { + "height":15, + "id":88, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":113, + "x":1573, + "y":163 + }, + { + "height":9, + "id":92, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":190, + "x":486, + "y":985 + }, + { + "height":20, + "id":93, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":62, + "x":784, + "y":978 + }, + { + "height":18, + "id":94, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":148, + "x":663, + "y":970 + }, + { + "height":16, + "id":109, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":776.667, + "x":3314.67, + "y":995.333 + }, + { + "height":14, + "id":122, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":67, + "x":2224, + "y":922 + }, + { + "height":16, + "id":123, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":64, + "x":2448, + "y":896 + }, + { + "height":16, + "id":124, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":120, + "x":2445, + "y":813 + }, + { + "height":16, + "id":125, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":83, + "x":2458, + "y":760 + }, + { + "height":17, + "id":126, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":119, + "x":2481, + "y":590 + }, + { + "height":21, + "id":127, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":81, + "x":2695, + "y":674 + }, + { + "height":16, + "id":128, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":78, + "x":2704, + "y":967 + }, + { + "height":13, + "id":129, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":57, + "x":2727, + "y":960 + }, + { + "height":13, + "id":130, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":43, + "x":2743, + "y":952 + }, + { + "height":17, + "id":131, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":42, + "x":2635, + "y":1003 + }, + { + "height":17, + "id":132, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":83, + "x":2051, + "y":994 + }, + { + "height":15, + "id":134, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":69, + "x":2050, + "y":981 + }, + { + "height":10, + "id":135, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":42, + "x":2062, + "y":974 + }, + { + "height":14, + "id":136, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":79, + "x":3015, + "y":979 + }, + { + "height":15, + "id":138, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":67, + "x":3231, + "y":714 + }, + { + "height":16, + "id":139, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":122, + "x":2881, + "y":588 + }, + { + "height":20, + "id":140, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":121, + "x":3586, + "y":780 + }, + { + "height":19, + "id":141, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":52, + "x":3858, + "y":843 + }, + { + "height":19, + "id":142, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":49, + "x":3899, + "y":824 + }, + { + "height":21, + "id":143, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":110, + "x":3940, + "y":811 + }, + { + "height":12, + "id":157, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":80, + "x":1751, + "y":353 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "width":0, + "x":0, + "y":0 + }, + { + "color":"#37ff00", + "draworder":"topdown", + "height":0, + "name":"Player", + "objects":[ + { + "height":72, + "id":72, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":178, + "y":867 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "width":0, + "x":0, + "y":0 + }, + { + "color":"#002eff", + "draworder":"topdown", + "height":0, + "name":"PickableObjects", + "objects":[ + { + "height":72, + "id":75, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":843, + "y":751 + }, + { + "height":72, + "id":77, + "name":"ETERNAL_FLY", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":1592, + "y":185 + }, + { + "height":72, + "id":78, + "name":"SHIELD", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":1283, + "y":355 + }, + { + "height":72, + "id":79, + "name":"PUNCH_SPEED", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":779, + "y":208 + }, + { + "height":72, + "id":95, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":341, + "y":435 + }, + { + "height":72, + "id":96, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":46, + "y":361 + }, + { + "height":72, + "id":97, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":524, + "y":890 + }, + { + "height":72, + "id":98, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":1060, + "y":800 + }, + { + "height":72, + "id":99, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":1610, + "y":624 + }, + { + "height":72, + "id":100, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":1358, + "y":779 + }, + { + "height":72, + "id":102, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":1608, + "y":371 + }, + { + "height":72, + "id":103, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":1075, + "y":351 + }, + { + "height":72, + "id":104, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":53, + "y":899 + }, + { + "height":72, + "id":111, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":2219, + "y":833.333 + }, + { + "height":72, + "id":112, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":2460.33, + "y":674.667 + }, + { + "height":72, + "id":113, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":2504.33, + "y":500 + }, + { + "height":72, + "id":114, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":2709.67, + "y":861.333 + }, + { + "height":72, + "id":115, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":3020.33, + "y":889.333 + }, + { + "height":72, + "id":116, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":3224.33, + "y":624 + }, + { + "height":72, + "id":117, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":2908.33, + "y":502.667 + }, + { + "height":72, + "id":118, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":3929.67, + "y":713.333 + }, + { + "height":72, + "id":119, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":4007, + "y":908 + }, + { + "height":72, + "id":120, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":3549.67, + "y":912 + }, + { + "height":72, + "id":121, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":3611, + "y":689.333 + }, + { + "height":72, + "id":155, + "name":"SHIELD", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":2699, + "y":576 + }, + { + "height":72, + "id":156, + "name":"SHIELD", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":3813.67, + "y":756 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "width":0, + "x":0, + "y":0 + }, + { + "color":"#ff4000", + "draworder":"topdown", + "height":0, + "name":"Enemys", + "objects":[ + { + "height":72, + "id":82, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":1603, + "y":898 + }, + { + "height":72, + "id":83, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":1383, + "y":485 + }, + { + "height":72, + "id":84, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":520, + "y":142 + }, + { + "height":72, + "id":86, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":688, + "y":847 + }, + { + "height":72, + "id":87, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":720, + "y":521 + }, + { + "height":72, + "id":147, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":2698, + "y":568 + }, + { + "height":72, + "id":148, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":2451, + "y":809 + }, + { + "height":72, + "id":149, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":3369, + "y":905 + }, + { + "height":72, + "id":150, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":3942, + "y":903 + }, + { + "height":72, + "id":151, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":3634, + "y":663 + }, + { + "height":72, + "id":152, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":3732.33333333333, + "y":913 + }, + { + "height":72, + "id":153, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":3957, + "y":721 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "width":0, + "x":0, + "y":0 + }, + { + "color":"#ffff00", + "draworder":"topdown", + "height":64, + "name":"Win", + "objects":[ + { + "height":51.3333333333334, + "id":159, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":37.6666666666665, + "x":3813.66666666667, + "y":941.666666666667 + }], + "opacity":1, + "type":"objectgroup", + "visible":true, + "width":256, + "x":0, + "y":0 + }], + "nextobjectid":160, + "orientation":"orthogonal", + "properties": + { + + }, + "renderorder":"right-down", + "tileheight":16, + "tilesets":[ + { + "firstgid":1, + "image":"..\/images\/tilesets\/RA_DreamForestTileset.png", + "imageheight":583, + "imagewidth":1006, + "margin":1, + "name":"RA_DreamForestTileset", + "properties": + { + + }, + "spacing":1, + "tileheight":16, + "tilewidth":16, + "transparentcolor":"#f800f8" + }, + { + "firstgid":2007, + "image":"..\/images\/tilesets\/RA_DreamForestTileset_3.png", + "imageheight":1023, + "imagewidth":943, + "margin":0, + "name":"RA_DreamForestTileset_3", + "properties": + { + + }, + "spacing":0, + "tileheight":16, + "tilewidth":16, + "transparentcolor":"#709ad1" + }], + "tilewidth":16, + "version":1, + "width":256 +} \ No newline at end of file diff --git a/maps/level1.png b/maps/level1.png new file mode 100644 index 0000000..80d936c Binary files /dev/null and b/maps/level1.png differ diff --git a/maps/level1.tmx b/maps/level1.tmx new file mode 100644 index 0000000..d4b3782 --- /dev/null +++ b/maps/level1.tmx @@ -0,0 +1,154 @@ + + + + + + + + + + + eJzt3Qe0VNWhBuChXHoTG1WjeYn0jh3pvUm3Ji8WkKp5SV5Uegepdo1YkK4xiUrvRaomdo0aC5ZoXpQq3ZJvHrjW9XoRZpgCl/2v9S3Gw71nzpyZfzjnzJ5tJBISEhISkq40KBCJNKQRjWlCU5rRnBa0LJDurQwJCUlGbg/dDgkJCQkJCQkJCTlpUqFgurcgJCQkXbku9D/kBE12161DYssU/X/40HvAo/58jKk8zjSmMyO8R4SE5MhEr//3ZwADGcRghjCUYQwP76shITkyc3V7HvNZwEIWsZglLGVZ6H9ISI7MFt3eyja2s4OdfMkudrMn9D8khyWMeTuY6PX/ilSiMlWoSjWqU4Oa4fw/5ARLL6/Z3j/yug3nvAcTvf5/PTdwI93pwU30LHjk/RgSkq5kvW79XY7munU45z2Y767/P1IwXP8POXkSznkPJlz/DzkZE855DyZc/w85GXOs57zxXj98t0gk8h7v8wGb+ZCP+JhP+Cef8hn/KpL4x5454fp/yMmYYz3njfeY+cyikUgpSlOGspSjfNHEP8ajSazX/3d7P9rDXvaxnwNJfo8KCTneEu8xcwc970gnOtOFrnRLU/9jvf5fw3bWpBa1qUPdNG17SEi6Eu8x8zhdGc8EJjKJyWnsT6zX/3vZ1t70oS/9uDn0P+QkS7zXD9fqyjrWs4GNbOJ5XsimRy8nuVuxzv8z3fbMYCazmM2c0P+QkyzxXj/8NtqVYpFILnKTh7xkkI/8FKAghShcLLmPY26M/X/P9r/PB2zmQz4K/Q85yRLv9cOL9PliLuFS6nEZ9WlAQxrRmCY0TXL/t8TY/1K2pzRlKEs5yid5G0NCckp+oyu/5Xf8L7/nVm7jdvozgIEMYnCSuxXr/D8dbU8nOtOFrnQL/Q8JOao8pSt/4s/8had5hmeZyzzms4CFLEpyt2Kd/2e87ZnARCYxmTtD/0NCjiqf6spn/Iv/4998zhdsYSvb2M4Odia5W1Oy9D+M/w9JdY63MXHJzDnFI5Fz+Sn/xc/4OedRgYpUojJVqFo8+/Ukap+F8f8h6c7xNiYumblan6/hWn7BL/lvfsV1XM8N3Eh3ehym/4naZ2H8f0i6c7yNiUtm7tXn+7ifB3iQP/AQU3iYR3iUx5h6mP4nap+F8f8h6c7xNiYumXlRn1/iZV7hVV7jdd7gTf7OW7zNO4fpf6L2WZj/JyTdScSYuFaFIpHWtKEt7WjP5XSgI50KJf+xHCkFS0QihShMEYpSjOKU4BRKciqncXqJ7NeTqHGEYf6fkHQnEWPiRuj2SEYxmjGM5Q7GMZ4Jx0H/G+tzE5rSjOa0oCWtaE0b2tKO9ofpf6LGEYb5f0LSnUSMiVuu2ytYySpWs4bnWMs61h8H/R+oz4MYzBCGMozhjGAkoxjNGMYepv+JGkcYrv+HpDuJGBO3V7f3sZ8DfMXXfMO30d4X9m9l4ZQ/tB9kgT4vZBGLWcJSlrGcFaxkFatZc5j+J2ocYbzX/1sfB++lITkjiRgTV0u3a1OHupzPBVzIRVzMJZn6f6LPY5GocYTh+n9IupOIMXF9dLsv/biZW/g1/8Nv+C2/y9T/E30ei0SNIwzX/0PSnUSMiZup27OYzRye4En+yFP8iT9n6n+s81i86tjgNV7nDd7k77zF27yT4mOHRI0jDNf/Q9KdRI2Ji+Zoj+tjnceiqL8rRnFKcAolOZXTOD3Fxw6J2mfh+n9IupOoMXHRHO1xfazzWDT3dy1oSSta04a2tKN9ivufyH0WEpLOJGpMXDRHe1wf6zwWQ61jGMMZwUhGMZoxjE1x/xO5z0JC0plEjYmL5miP62Odx2KJdSxlGctZwUpWsZo1Ke5/IvdZSEg6E8+YuMOd2x/tcX2s81jsso7d7GEv+9jPAb7i6xT3P1HjCKNpUCD8/5BD0pd4xsQd7tw+WfPTVbeOGtSkFrWpQ13O54IE3EcsSdQ4wmjCGMCQdCaeMXGHO7dP1vx0Pa2jF73pQ1/6cTO38OsU9z9R4wijCXMAhJwIOZpz+2TNTzfNOqYzg5nMYjZzeIInU9z/RCaeMYBH+q5lSEiik86559/V7/d4nw/YzId8xMd8cgL3P54xgEf6rmVISKKTzrnnzyzu/ilNGcpSjvKcxdkn8Odr8YwBPNJ3LUNCEp10zj3fQb870onOdKEr3biCK4ufuN8pimcM4JG+axkSkuikc+75cfo9nglMZBKTuZO7uLt47N8pOiO34wpKUZoyuVPzWBKRI33XMiQkJ2Wtfq9jPRvYyCae5wX+Wjz27xR10PeOdKIzXdLc/1jGABzpu5YhJ2fuyRuJ3Mt93M8DPJj34N89lDe925bsxPqdovH6PoGJTGJymvsfxgCEHEv+pt8v8hIv8wqv8hqv8wZv5uD3gFg+n1in6+vZwEY28TwvpPE9IIwBCIkn+TMikQIUpBCFKUJRilGcEpxCyYx0b23yEsvnE7nyRCK5yUNeMshHfgrkSe12f5cwD1BILGmgyw1pRGOa0JRmNKcFLWlFa9rQNgf3P9bPJ+rp+WXUpwEND/W+cZr6H+YBCokl/XV5AAMZxGCGMJRhDGcEIxnFaMbkgP5Xpko2y2P9fOJWPb+N2+nPAAYyiMEMYSjDUvR+EOYBCok3i/R6MUtYyjKWs4KVOaDzmdOdHtxEzzh+/2l9foZnmcs85rOAhSxiMUtYyrIU9T/MAxRyLNml57vZw172sZ8DOaz/U3mcaXH+/uf6/AVb2Mo2trODnXzJLnazh71pOh8ICYkntfJFIrWpQ9186d6axOQt3uYd/sG7x7Cu8/JGIhWoSCUqU4WqVKM6NahJLWrn4M9MQnJe+up8P27mliP0P/pxV/Sft+hLPHqYEP3x/EQvNUcPN78bThodRpviKTb+PyVzRSKnchqncwZnUorSlMn1/Z8/y3+fzU84h3Nz/XCd13mw13MDN9KdHtxET3rRmz70pd+h/qd6Xx3vz83JnuPt+ZlpA2Yxmzk8wZP8kaeyeR+4lHpcRn0a0JBGNKYJTWlGc1okYBsb6mOjbDqZNa39TBva0o72XE4HOtKJznShK90OrfNKf17F1VzDtT9yX4964h5jKo8zjenMYCazmM2cvKnfV6m4v794TTzNMzzLXOYxnwU55LgxWUlHd46UzZ6zD/mIj/mEf/Ipn2XzfP6eW7mN2+nPAAYyiMEMYSjDGM4IRjKK0YxhLHcwjvFMYGKW25MO3ecAfRzIIAYzhKEMy9TTkW6PYjRjGMsdjGM8E5jIJCZzJ3dxN/dwL/dxPw/wIH/gIaZkup+39fod/sG7vMf7fMDmLMf88eyrzPsm8+3s9tWkLMuT/dxE7+/fXhOf8wVb2Mo2trMj9P9Hk4rnJ5bfKevAoxzlOYuz+QnncC4/zf/D+3iGZ5nLPOazgIUsYjFLWMoylrOClaxiNWt4jrWsYz0b2Jjl9qbo+nVvAQtZxGKWsJRlLGcFK1nFatbwHGtZx3o2sJFNPM8L/JW/8SIv8TKv8Cqv8Tpv8GaW44EzHLidSSlKU4aylKM8Z3F2Rnz7KvO+yXw7u321KcvyZD830fv7udfEeVSgIpWoTBWqUo3q1KBmWPa9Zal4fmL5na62qRtXcCVXcTXXcC2/yP/D+/iCLWxlG9vZwU6+ZBe72cNe9rGfA3zF13zDt9Ei6VUucpOHvFluZ7CdHezkS3axmz3sZR/7OcBXfM03fBvtrJOtXOQmD3nJIB/5KUBBClGYIhSlGMUpwSmU5FTa6/TldKAjnehMF7rSjSu4kqsy4ttXmfdN5tvZ7auMLMuT/dxE7+9XXhPXcT03cCPd6cFN9KQXvekTln1vWSqen3h+J5blFahIJSpThapUozo1qEktalOHupzPBVzIRVzMJVxKPS6jfpbbDaLr17uqVKM6NahJLWpTh7qczwVcyEVczCVcSj0uoz4NaEgjGtOEpjSjOS1oSSta04a2tOMOnR7HeCYwkUlM5k7u4m7u4d6M+PZV5n2T+XZ2+6pBluXJfm6i9zfF6/hhHuFRHmMqjzON6cxgJrPCsu8tS8XzE8/vxLL8P6LQ/Y0= + + + + + eJzt3GlQlHUAx/FHwQsFQVROu7VX5YFyqfXKm0NOtUOtNyoCguDxMk9ATu1Oa6YEjxSvepWmAoKg2Uxp2qFy2OXxLm+uvrxohgyqZXefZeH3nfnMOI31f5z4LbuyzxqGUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllFJKKaWUUkoppZRSSimllLJHs90MYw4iEIkoRGMuYhDr5hxnKKUsbyPb24TNyEI2crAFucizwTbNOEMpZXnH2d4JnEQZylGBU6hElQ22acYZSinLu8/2HuAhGtGEZrSgtW2Xgzv+9+4OMYx7uI8HeIjGIbY9Qyll3yawvSBMxCQEIwShCEN4J9sc524Y4zEBQZiISe62PUMpZd+S2V4KUrECaUjHSmQgs5NtJrH15UhGClKxopP9d/UMpVT3rJitl2AXdmMP9nayf6VUz+oqW69FHerRgGvav1K9Il8Pw/CDPwIQiFEe5l7DlSE8DqEWdahHQyd/B6mUsl2xbD0O8UhAIuaZvH8fnm/4wg/+CECgnoMoZffy2Ho+ClCIImw1ef8xbD0WcYhHAhK1f+UEebkaxjB4uzrm/PM8T76A73ARl/A9fsCP+MkJnkfnsvU85KMAhSiy0f693Pj/A28MxwiMhA989X4lZWUR7D4SUYjGXMSY+Fjgzk48MBSe8MIweGM4RjjB99FKrrEKp1GNGpyx0XXrfgVlz7LYejZysAW5yEO+SY8BM9jJTMzCbMxBBCIRhWgn2H9r2zXymqMP+sIFrjZ6DaL7FZS9KmPj5ajAKVSiCqdRbdL+17Gd9diAjdiEzchCNnKcYP9t9RnI9uEC14G2++/qfoWe2Q32ddNBr7nbauTsJjSjBa1t19KPr2P0hQtc+9n/Oo6y72P4EsdxAidRhnJUOMn+J7P5KZiKF2y4f92v0PN6hl2NxhgT9tVZwZwdglCEIRyTMQVT8QJeNOH67rDvu7iH+3iAh2hEE5qdZP+r2PxqrMFaG+5f9yv0rBayqUVYjNfwugMeA9I4Mx0rkYFMrMJqrMFaE69pLK+Tx2E8JiAIEzEJwQgx+Wd5Xe0gmz+Ewzhiw/3rfoWe1fts6wNsxw58iI8c8BiwnzNLcQAHcQiHcQSfmXg9y9h3EpYjGSlIxQqkId1J9n+dzd/ATdyy4f5Vz+k8u7qA73ARl/A9fnDg64DrnH0DN3HLAdexk30XowS7sBt7sBefYp+T7P/pQbyuw2iMGeToq1HdIbf+hjEYQ+AODwyFJ7wwDN4YjhH9HXONz3DuaIzBsw64hivs+ypqUYd6NOAafsYvTrL/V9n8QizCYu2/w5a4GMZSLEOSi6Ovxv5NY0/TMQMzMQuzMQcRiEQUotvtLpZfxyEeCSbu8TUrz+roHpj/k89Qw/CFH/wRgECMwmN4fKh112VW77L59/A+PtD+/9HH7P0T7EQxSnrB/v9qPdvagI3YhM3IQjZysKXd9vL5dQEKUWTS/rdzzg58aMV5Xb0HJoZ9xyIO8UhAIuZhPhY8sv8/BhjGbdzBXdzDfTzAQzSiCc1oQSsMC16PW/J5Yu37hs1/i/O4oP3/o8vs/QquohZ1qEdDL3gc+JJdHccJnEQZylGBU6hEFU6jGjUmPw+/yHmXrDyzq/fA5LLvPOSjAIUowlZsw5uP7P85tvw8xmIcxmMCgjARkxCMEIQiDOEW7N+SzxNr32A3XufBHR42fF/Ofv78pZ08B/qMf/65kzw/8nHl+wP84I8ABGKUA98D44ga2VkTmtGC1rbd8T2qD/rCBa4DzL0mL84bBm8rzu3qPTCVfP1W4TSqUYMzOIuvcO6Rr+8lbHkpliEJy5GMFKRiBdKQjpXIQKYF+7fk88TaN43NT8cMzLTh/n/lz/+bk2z834pl53GIRwISMQ/ze9n+g9lYCEIRhnBMxhRMNXn3fxXBuZGIsuL8ju6B+T+1tn1te/L4h75wgSv6oT8GeP7993/Mlj/BThSjBLuwG3uwF59iH/ajFAcs2L81nyf2Brtfh/U23P8Tnv/9ezqqrB/PMVHhwJ8tPVoBWy9EEbZiWy/bfhr7SsdKZCATq7Aaaxy0/bayODsbOVZcQ0f3wNijn9jyZVzBVdSiDvVowDX8jF/wK37D7xbs35rPE/uC3R/FsW7wvvwmdt+Mlm60/xr2fgZn8RXO4ete9Biwj33tRykO4CAO4TCOOGj/ZZxbjgqcQmUXryOMvYdjMqZgqp32P2KQYYyED3zhB38EIBCj8BgexxN4Ek9Z8Pdx1nye2G12fwd3u8H+Q3hdGYowB/1cWfWuMthIJlZhNdbYaf/RbHkuYhCLOMQjAYmYh/lYgJfwMl6xYP/WfJ7Y84MNYyzG6X25qpdVykYO4CAO4bCd9p/DlrcgF3nIRwEKUYSt2IY38RbexjsW7N+azxNbyu6XIakH7f9POCvieg== + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/sounds/Rayman/enemy_hitted.wav b/sounds/Rayman/enemy_hitted.wav new file mode 100644 index 0000000..1168aae Binary files /dev/null and b/sounds/Rayman/enemy_hitted.wav differ diff --git a/sounds/Rayman/flying.wav b/sounds/Rayman/flying.wav new file mode 100644 index 0000000..5e69747 Binary files /dev/null and b/sounds/Rayman/flying.wav differ diff --git a/sounds/Rayman/game_over.mp3 b/sounds/Rayman/game_over.mp3 new file mode 100644 index 0000000..555cfc1 Binary files /dev/null and b/sounds/Rayman/game_over.mp3 differ diff --git a/sounds/Rayman/ground_hit.wav b/sounds/Rayman/ground_hit.wav new file mode 100644 index 0000000..0841cc0 Binary files /dev/null and b/sounds/Rayman/ground_hit.wav differ diff --git a/sounds/Rayman/idle.wav b/sounds/Rayman/idle.wav new file mode 100644 index 0000000..6022b44 Binary files /dev/null and b/sounds/Rayman/idle.wav differ diff --git a/sounds/Rayman/pearl_picked.wav b/sounds/Rayman/pearl_picked.wav new file mode 100644 index 0000000..80ad109 Binary files /dev/null and b/sounds/Rayman/pearl_picked.wav differ diff --git a/sounds/Rayman/power_picked.wav b/sounds/Rayman/power_picked.wav new file mode 100644 index 0000000..62e6d72 Binary files /dev/null and b/sounds/Rayman/power_picked.wav differ diff --git a/sounds/Rayman/punch_thrown.wav b/sounds/Rayman/punch_thrown.wav new file mode 100644 index 0000000..0c453d2 Binary files /dev/null and b/sounds/Rayman/punch_thrown.wav differ diff --git a/sounds/Rayman/rayman_hitted.wav b/sounds/Rayman/rayman_hitted.wav new file mode 100644 index 0000000..e41baaf Binary files /dev/null and b/sounds/Rayman/rayman_hitted.wav differ diff --git a/sounds/Rayman/shield_picked.wav b/sounds/Rayman/shield_picked.wav new file mode 100644 index 0000000..2b0d145 Binary files /dev/null and b/sounds/Rayman/shield_picked.wav differ diff --git a/sounds/Rayman/song.mp3 b/sounds/Rayman/song.mp3 new file mode 100644 index 0000000..08f41e7 Binary files /dev/null and b/sounds/Rayman/song.mp3 differ diff --git a/sounds/Rayman/win_level.wav b/sounds/Rayman/win_level.wav new file mode 100644 index 0000000..3b41f81 Binary files /dev/null and b/sounds/Rayman/win_level.wav differ diff --git a/sounds/test_song.mp3 b/sounds/test_song.mp3 new file mode 100644 index 0000000..fba2f66 Binary files /dev/null and b/sounds/test_song.mp3 differ diff --git a/sounds/test_sound1.wav b/sounds/test_sound1.wav new file mode 100644 index 0000000..9388432 Binary files /dev/null and b/sounds/test_sound1.wav differ diff --git a/sounds/test_sound2.WAV b/sounds/test_sound2.WAV new file mode 100644 index 0000000..67c2db1 Binary files /dev/null and b/sounds/test_sound2.WAV differ diff --git a/sounds/test_sound3.WAV b/sounds/test_sound3.WAV new file mode 100644 index 0000000..3e73844 Binary files /dev/null and b/sounds/test_sound3.WAV differ diff --git a/src/HTML/Demo_Balls.html b/src/HTML/Demo_Balls.html new file mode 100644 index 0000000..c232971 --- /dev/null +++ b/src/HTML/Demo_Balls.html @@ -0,0 +1,50 @@ + + + +Ball physics simulation + + + + No canvas supported + + +
+ +
+ Gravedad +
+ Down +
+ Up +
+ Left +
+ Right +
+ +
+ + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/HTML/Rayman.html b/src/HTML/Rayman.html new file mode 100644 index 0000000..76f5d05 --- /dev/null +++ b/src/HTML/Rayman.html @@ -0,0 +1,44 @@ + + + +Rayman Demo XgameJS + + + + No canvas supported on this browser :( + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/HTML/Test_GraphicsDevice_AnimatedSprite.html b/src/HTML/Test_GraphicsDevice_AnimatedSprite.html new file mode 100644 index 0000000..7bd746a --- /dev/null +++ b/src/HTML/Test_GraphicsDevice_AnimatedSprite.html @@ -0,0 +1,32 @@ + + + +Test for GraphicsDevice and AnimatedSprite + + + + No canvas supported + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/HTML/Test_Mouse_Keyboard.html b/src/HTML/Test_Mouse_Keyboard.html new file mode 100644 index 0000000..02f58f3 --- /dev/null +++ b/src/HTML/Test_Mouse_Keyboard.html @@ -0,0 +1,23 @@ + + + +Test Mouse and Keyboard + + + + No canvas supported + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/HTML/Test_Point_Vector2_Rectangle.html b/src/HTML/Test_Point_Vector2_Rectangle.html new file mode 100644 index 0000000..02e3e64 --- /dev/null +++ b/src/HTML/Test_Point_Vector2_Rectangle.html @@ -0,0 +1,25 @@ + + + +Test for Point, Vector2 and Rectangle classes + + + + No canvas supported + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/HTML/Test_Song_SoundEffect.html b/src/HTML/Test_Song_SoundEffect.html new file mode 100644 index 0000000..a1f55b8 --- /dev/null +++ b/src/HTML/Test_Song_SoundEffect.html @@ -0,0 +1,30 @@ + + + +Test for Song and SoundEffect + + + + No canvas supported + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/JS/Demo_Balls.js b/src/JS/Demo_Balls.js new file mode 100644 index 0000000..266e776 --- /dev/null +++ b/src/JS/Demo_Balls.js @@ -0,0 +1,248 @@ +/** + * Provides basic graphics device initialization, game logic, and rendering code. + */ +function Game() { + "use strict"; + /*globals ContentManager, GraphicsDevice, document, SpriteBatch, GameStates, GravityDirections*/ + this.Content = new ContentManager(); + this.GraphicsDevice = new GraphicsDevice(document); + this.spriteBatch = null; + this.gameState = GameStates.Initializing; + + //The HTML elements + this.generateButton = document.querySelector("#generate"); + this.gravityCheckBox = document.querySelector("#gravity"); + this.gravityDirRadioButtons = document.querySelectorAll("#gravityDir"); + this.removeAllBallsButton = document.querySelector("#reset"); + + //The ball image + this.ballTexture = null; + + //The room image + this.roomImage = null; + + //The balls array + this.balls = []; + + //The room Sprite + this.roomSprite = null; + + //Gravity properties + this.gravityActivated = false; + this.gravityDir = GravityDirections.G_DOWN; + this.gravityForce = 0.4; + + //Other + this.preloading = true; +} + +/** + * Allows the game to perform any initialization it needs to before starting to run. + * This is where it can query for any required services and load any non-graphic + * related content. + * @name Initialize + * @function + * @memberOf Game + */ +Game.prototype.Initialize = function () { + "use strict"; + /*globals GenerateBall*/ + var self = this, + len, + i; + + //Add the event listener to the generate ball button + self.generateButton.addEventListener("mousedown", self.GenerateBall.bind(self), false); + + //Remove all the balls in the room if this button is pressed + self.removeAllBallsButton.addEventListener("mousedown", function (event) { + self.balls.splice(0, self.balls.length); + }, false); + + //Enable or disable the radiobuttons depending on the gravity checkbox + self.gravityCheckBox.addEventListener("mousedown", function (event) { + + if (self.gravityCheckBox.checked) { + self.gravityActivated = false; + for (i = 0, len = self.gravityDirRadioButtons.length; i < len; i += 1) { + self.gravityDirRadioButtons[i].disabled = true; + } + } else { + self.gravityActivated = true; + for (i = 0, len = self.gravityDirRadioButtons.length; i < len; i += 1) { + self.gravityDirRadioButtons[i].disabled = false; + } + } + + }, false); + + //Depending on which radiobutton is checked the gravity direction changes + for (i = 0, len = self.gravityDirRadioButtons.length; i < len; i += 1) { + + self.gravityDirRadioButtons[i].addEventListener("mousedown", function (event) { + self.gravityDir = parseInt(this.value, 10); + }, false); + } + + self.gameState = GameStates.Loading; +}; + +/** + * LoadContent will be called once per game and is the place to load + * all of your content. + * @name LoadContent + * @function + * @memberOf Game + */ +Game.prototype.LoadContent = function () { + "use strict"; + /*globals Sprite, Rectangle, Point, Vector2*/ + var self = this; + + if (self.preloading) { + // Create a new SpriteBatch, which can be used to draw textures. + self.spriteBatch = new SpriteBatch(self.GraphicsDevice); + + // TODO: use this.Content.Load... to load your game content here + self.ballTexture = self.Content.LoadTexture2D("../../images/ball.png"); + self.roomImage = self.Content.LoadTexture2D("../../images/room.jpg"); + self.preloading = false; + } + + if (self.Content.AllContentLoaded()) { + //Create the room sprite and add it to the sprites list + self.roomSprite = new Sprite(self.roomImage, Vector2.One(), + new Rectangle(0, 0, self.roomImage.Width(), self.roomImage.Height()), + Point.Zero(), true + ); + + self.gameState = GameStates.Playing; + } +}; + +/** + * Allows the game to run logic such as updating the world, + * checking for collisions, gathering input, and playing audio. + * @name Update + * @function + * @memberOf Game + */ +Game.prototype.Update = function () { + "use strict"; + var self = this, + len = self.balls.length, + i; + + // TODO: Add your update logic here + if (len > 0) { + for (i = 0; i < len; i += 1) { + self.balls[i].Update( + self.GraphicsDevice.PreferredBackBufferWidth(), + self.GraphicsDevice.PreferredBackBufferHeight(), + self.balls, + self.gravityActivated, + self.gravityDir, + self.gravityForce + ); + } + } +}; + +/** + * This is called when the game should draw itself. + * @name Draw + * @function + * @memberOf Game + */ +Game.prototype.Draw = function () { + "use strict"; + /*globals Vector2, SpriteEffects*/ + var self = this, + len = self.balls.length, + i, + auxSprite = null; + + self.GraphicsDevice.Clear(); + + //Draw the room + self.spriteBatch.Draw(self.roomSprite.Texture, + Vector2.Zero(), + new Rectangle(0, 0, self.roomSprite.Width(), self.roomSprite.Height()), 0, self.roomSprite.Scale, SpriteEffects.None); + + //Draw the balls + if (len > 0) { + for (i = 0; i < len; i += 1) { + auxSprite = self.balls[i].Sprite; + //console.log(self.balls[i].Sprite.Scale);console.log(auxSprite.Position.Y); + if (auxSprite.IsVisible) { + self.spriteBatch.Draw( + auxSprite.Texture, + auxSprite.Position, + new Rectangle(0, 0, auxSprite.Texture.Width(), auxSprite.Texture.Height()), + auxSprite.Rotation, + auxSprite.Scale, + SpriteEffects.None + ); + } + } + } +}; + +Game.prototype.GenerateBall = function () { + "use strict"; + /*globals Sprite, Ball, Rectangle, Point*/ + + //Create a ball with random scale + var self = this, + scale = (Math.floor(Math.random() * 20) + 10) / 100, + canvasWidth = self.GraphicsDevice.PreferredBackBufferWidth(), + canvasHeight = self.GraphicsDevice.PreferredBackBufferHeight(), + sprite = new Sprite( + self.ballTexture, + new Vector2(scale, scale), + new Rectangle(0, 0, self.ballTexture.Width(), self.ballTexture.Height()), + Point.Zero(), + true + ), + position = new Point((canvasWidth / 2 - sprite.HalfWidth()), (canvasHeight / 2 - sprite.HalfHeight())), + ball = new Ball( + sprite, + sprite.HalfWidth(), + position, + self.balls.length, + true, + true + ); + + self.balls.push(ball); +}; + +/** + * Call this method to initialize the game, begin running the game loop, and + * start processing events for the game. + * @name Run + * @function + * @memberOf Game + */ +Game.prototype.Run = function () { + "use strict"; + /*globals requestAnimationFrame*/ + var self = this; + + //Call the game loop + requestAnimationFrame(self.Run.bind(self), self.GraphicsDevice.canvas); + + //Choose the method to run according to the game state + switch (self.gameState) { + case GameStates.Initializing: + self.Initialize(); + break; + case GameStates.Loading: + self.LoadContent(); + break; + case GameStates.Playing: + self.Update(); + self.Draw(); + break; + } +}; \ No newline at end of file diff --git a/src/JS/Rayman.js b/src/JS/Rayman.js new file mode 100644 index 0000000..adda4d1 --- /dev/null +++ b/src/JS/Rayman.js @@ -0,0 +1,784 @@ +/** + * Provides basic graphics device initialization, game logic, and rendering code. + */ +function Game() { + "use strict"; + /*globals ContentManager, GraphicsDevice, document, SpriteBatch, GameStates, setInterval, clearInterval, Mouse, SpriteEffects*/ + this.Content = new ContentManager(); + this.GraphicsDevice = new GraphicsDevice(document); + this.spriteBatch = null; + this.gameState = GameStates.Initializing; + this.preloading = true; + + this.level = null; + this.sprites = []; + + this.gravityForce = 0.3; + + this.pearlsToCollect = 0; + + //The images + this.levelTexture = null; + this.distantBackgroundTexture = null; + this.raymanTexture = null; + this.enemyTexture = null; + this.punchTexture = null; + this.flyPowerTexture = null; + this.punchSpeedTexture = null; + this.pearlTexture = null; + this.shieldTexture = null; + this.helpTexture = null; + this.gameOverTexture = null; + this.winTexture = null; + this.hudTexture = null; + + //The song + this.song = null; + + //Sound effects + this.soundEffects = []; + + //Create the platforms, pickable objects and enemys arrays + this.platforms = []; + this.pickableObjects = []; + this.enemys = []; + + //Create the player + this.player = null; + + //Create the game camera + this.camera = null; + + //The win zone rectangle + this.winRect = null; + + //The help screen sprite + this.helpSprite = null; + + //The game over screen sprite + this.gameOverSprite = null; + + //The win screen sprite + this.winSprite = null; + + //The win screen sprite + this.hudSprite = null; + + //Flags + this.moveRight = false; + this.moveLeft = false; + this.jump = false; + this.punch = false; + this.showCollisions = false; + + this.interval = null; +} + +/** + * Allows the game to perform any initialization it needs to before starting to run. + * This is where it can query for any required services and load any non-graphic + * related content. + * @name Initialize + * @function + * @memberOf Game + */ +Game.prototype.Initialize = function () { + "use strict"; + var self = this; + + self.gameState = GameStates.Loading; +}; + +/** + * LoadContent will be called once per game and is the place to load + * all of your content. + * @name LoadContent + * @function + * @memberOf Game + */ +Game.prototype.LoadContent = function () { + "use strict"; + /*globals Level, Sprite, Point, Rectangle, Vector2, PickableObject, AnimationTypes, PickableObjectTypes, AnimatedSprite, Enemy, Player, Projectile, Camera*/ + var self = this, + distantBackgroundRepeats = 0, + i = 0, + len = 0, + currentPlatform = null, + currentObject = null, + currentEnemy = null, + objSprite = null, + type = null, + aux = 0; + + if (self.preloading) { + // Create a new SpriteBatch, which can be used to draw textures. + self.spriteBatch = new SpriteBatch(self.GraphicsDevice); + + //Textures + self.levelTexture = self.Content.LoadTexture2D("../../maps/level1.png"); + self.distantBackgroundTexture = self.Content.LoadTexture2D("../../images/dream_forest_background.png"); + self.raymanTexture = self.Content.LoadTexture2D("../../images/rayman_anim.png"); + self.enemyTexture = self.Content.LoadTexture2D("../../images/enemy1_anim.png"); + self.punchTexture = self.Content.LoadTexture2D("../../images/punch.png"); + self.flyPowerTexture = self.Content.LoadTexture2D("../../images/fairy_anim.png"); + self.punchSpeedTexture = self.Content.LoadTexture2D("../../images/fairy_anim2.png"); + self.pearlTexture = self.Content.LoadTexture2D("../../images/pearl_anim.png"); + self.shieldTexture = self.Content.LoadTexture2D("../../images/shield_anim.png"); + self.helpTexture = self.Content.LoadTexture2D("../../images/help.jpg"); + self.gameOverTexture = self.Content.LoadTexture2D("../../images/game_over_screen.png"); + self.winTexture = self.Content.LoadTexture2D("../../images/win_screen.png"); + self.hudTexture = self.Content.LoadTexture2D("../../images/interfaz.png"); + + //The song + self.song = self.Content.LoadSong("../../sounds/Rayman/song.mp3"); + + //Sound Effects + self.soundEffects.push(["enemy_hitted", self.Content.LoadSoundEffect("../../sounds/Rayman/enemy_hitted.wav")]); + self.soundEffects.push(["flying", self.Content.LoadSoundEffect("../../sounds/Rayman/flying.wav")]); + self.soundEffects.push(["game_over", self.Content.LoadSoundEffect("../../sounds/Rayman/game_over.mp3")]); + self.soundEffects.push(["pearl_picked", self.Content.LoadSoundEffect("../../sounds/Rayman/pearl_picked.wav")]); + self.soundEffects.push(["power_picked", self.Content.LoadSoundEffect("../../sounds/Rayman/power_picked.wav")]); + self.soundEffects.push(["punch_thrown", self.Content.LoadSoundEffect("../../sounds/Rayman/punch_thrown.wav")]); + self.soundEffects.push(["rayman_hitted", self.Content.LoadSoundEffect("../../sounds/Rayman/rayman_hitted.wav")]); + self.soundEffects.push(["shield_picked", self.Content.LoadSoundEffect("../../sounds/Rayman/shield_picked.wav")]); + self.soundEffects.push(["win_level", self.Content.LoadSoundEffect("../../sounds/Rayman/win_level.wav")]); + self.soundEffects.push(["idle", self.Content.LoadSoundEffect("../../sounds/Rayman/idle.wav")]); + self.soundEffects.push(["ground_hit", self.Content.LoadSoundEffect("../../sounds/Rayman/ground_hit.wav")]); + + self.preloading = false; + } + + if (self.Content.AllContentLoaded()) { + + //Create the level + self.level = new Level( + new Sprite( + self.levelTexture, + Vector2.One(), + new Rectangle(0, 0, self.levelTexture.Width(), self.levelTexture.Height()), + Point.Zero(), + true + ) + ); + distantBackgroundRepeats = Math.ceil(self.levelTexture.Width() / self.distantBackgroundTexture.Width()); + + for (i = 0; i < distantBackgroundRepeats; i += 1) { + self.level.DistantBackgroundsSprites.push( + new Sprite( + self.distantBackgroundTexture, + Vector2.One(), + new Rectangle(0, 0, self.distantBackgroundTexture.Width(), self.distantBackgroundTexture.Height()), + new Point(self.distantBackgroundTexture.Width() * i, 0), + true + ) + ); + } + + /////////////////////// + /// Build the level /// + /////////////////////// + for (i = 0, len = self.level.DistantBackgroundsSprites.length; i < len; i += 1) { + self.sprites.push(self.level.DistantBackgroundsSprites[i]); + } + self.sprites.push(self.level.Sprite); + + //Create all the platforms and add them to the platforms array + for (i = 0, len = self.level.Platforms.length; i < len; i += 1) { + + currentPlatform = self.level.Platforms[i]; + self.platforms.push( + new Rectangle( + currentPlatform.x, + currentPlatform.y, + currentPlatform.width, + currentPlatform.height + ) + ); + } + + //Create all the pickable objects and add them to the pickable objects array + for (i = 0, len = self.level.PickableObjects.length; i < len; i += 1) { + + currentObject = self.level.PickableObjects[i]; + + switch (currentObject.name) { + case "PEARL": + objSprite = new AnimatedSprite( + self.pearlTexture, + new Vector2(1.35, 1.35), + new Rectangle(0, 0, 24, 24), + new Point(currentObject.x, currentObject.y), + true, + AnimationTypes.PingPongLoop, + 8, + 90 + ); + type = PickableObjectTypes.PEARL; + self.pearlsToCollect += 1; + break; + + case "LIFE": + objSprite = new AnimatedSprite( + self.flyPowerTexture, + Vector2.One(), + new Rectangle(0, 0, 64, 64), + new Point(currentObject.x, currentObject.y), + true, + AnimationTypes.PingPongLoop, + 10, + 25 + ); + type = PickableObjectTypes.LIFE; + break; + + case "MINI_SHIELD": + objSprite = new AnimatedSprite( + self.flyPowerTexture, + Vector2.One(), + new Rectangle(0, 0, 64, 64), + new Point(currentObject.x, currentObject.y), + true, + AnimationTypes.PingPongLoop, + 10, + 25 + ); + type = PickableObjectTypes.MINI_SHIELD; + break; + + case "SHIELD": + objSprite = new AnimatedSprite( + self.shieldTexture, + new Vector2(2.1, 1.7), + new Rectangle(0, 0, 24, 19), + new Point(currentObject.x, currentObject.y), + true, + AnimationTypes.PingPongLoop, + 4, + 120 + ); + type = PickableObjectTypes.SHIELD; + break; + + case "PUNCH_SPEED": + objSprite = new AnimatedSprite( + self.punchSpeedTexture, + new Vector2(1.2, 1.2), + new Rectangle(0, 0, 64, 64), + new Point(currentObject.x, currentObject.y), + true, + AnimationTypes.PingPongLoop, + 10, + 35 + ); + type = PickableObjectTypes.PUNCH_SPEED; + break; + + case "PUNCH_POWER": + objSprite = new AnimatedSprite( + self.flyPowerTexture, + Vector2.One(), + new Rectangle(0, 0, 64, 64), + new Point(currentObject.x, currentObject.y), + true, + AnimationTypes.PingPongLoop, + 10, + 25 + ); + type = PickableObjectTypes.PUNCH_POWER; + break; + + case "ETERNAL_FLY": + objSprite = new AnimatedSprite( + self.flyPowerTexture, + new Vector2(1.2, 1.2), + new Rectangle(0, 0, 64, 64), + new Point(currentObject.x, currentObject.y), + true, + AnimationTypes.PingPongLoop, + 10, + 30 + ); + type = PickableObjectTypes.ETERNAL_FLY; + break; + + } + + if (objSprite !== null && type !== null) { + self.sprites.push(objSprite); + self.pickableObjects.push(new PickableObject(objSprite, type)); + } + } + + //Create all the enemys and add them to the enemys array + for (i = 0, len = self.level.Enemys.length; i < len; i += 1) { + + currentEnemy = self.level.Enemys[i]; + + self.enemys.push( + new Enemy( + new AnimatedSprite( + self.enemyTexture, + new Vector2(0.3, 0.3), + new Rectangle(0, 0, 80, 80), + new Point(currentEnemy.x, currentEnemy.y), + true, + AnimationTypes.Loop, + 20, + 35 + ) + ) + ); + + self.sprites.push(self.enemys[i].Sprite); + } + + //Create the player (Rayman) and his punch + self.player = new Player( + new AnimatedSprite( + self.raymanTexture, + new Vector2(0.1, 0.1), + new Rectangle(0, 0, 80, 80), + new Point(self.level.Player.x, self.level.Player.y), + true, + AnimationTypes.Loop, + 11, + 45 + ) + ); + + self.player.Punch = new Projectile( + new Sprite( + self.punchTexture, + new Vector2(1.2, 1.2), + new Rectangle(0, 0, self.punchTexture.HalfWidth(), self.punchTexture.Height()), + Point.Zero(), + false + ) + ); + + self.sprites.push(self.player.Sprite); + self.sprites.push(self.player.Punch.Sprite); + + //Instanciate the game camera + self.camera = new Camera( + self.GraphicsDevice.DefaultBackBufferWidth(), + self.GraphicsDevice.DefaultBackBufferHeight(), + self.levelTexture.Width(), + self.levelTexture.Height(), + 1.2 + ); + + //Initialize the win zone rectangle + self.winRect = new Rectangle(self.level.WinRect.x, self.level.WinRect.y, self.level.WinRect.width, self.level.WinRect.height); + + //Initialize the help screen sprite + self.helpSprite = new Sprite( + self.helpTexture, + Vector2.One(), + new Rectangle(0, 0, self.helpTexture.Width(), self.helpTexture.Height()), + Point.Zero(), + true + ); + + //Initialize the game over screen sprite + self.gameOverSprite = new Sprite( + self.gameOverTexture, + Vector2.One(), + new Rectangle(0, 0, self.gameOverTexture.Width(), self.gameOverTexture.Height()), + Point.Zero(), + true + ); + + //Initialize the win screen sprite + self.winSprite = new Sprite( + self.winTexture, + Vector2.One(), + new Rectangle(0, 0, self.winTexture.Width(), self.winTexture.Height()), + Point.Zero(), + true + ); + + //Initialize the hud sprite + self.hudSprite = new Sprite( + self.hudTexture, + Vector2.One(), + new Rectangle(0, 0, self.hudTexture.Width(), self.hudTexture.Height()), + Point.Zero(), + true + ); + + ///////////////////////// + + //If mouse left button clicked enter full screen mode + self.GraphicsDevice.canvas.addEventListener("click", self.GraphicsDevice.ToggleFullScreen.bind(self.GraphicsDevice)); + + //Play the game song + self.song.Play(); + + self.interval = setInterval(function () { + if (self.gameState === GameStates.Playing && self.player.CurrentState === self.player.IDLE) { + self.soundEffects[9][1].Play(); + } + }, 3500); + + //Change game state to "playing" + self.gameState = GameStates.Paused; + } +}; + +/** + * Allows the game to run logic such as updating the world, + * checking for collisions, gathering input, and playing audio. + * @name Update + * @function + * @memberOf Game + */ +Game.prototype.Update = function () { + "use strict"; + /*globals Keyboard, Keys*/ + var self = this, + i = 0, + len = 0, + playerPunch = null, + levelWidth = self.level.Sprite.Width(); + + //Show help screen if 'h' key pressed + if (Keyboard.IsKeyPressed(Keys.h)) { + self.gameState = GameStates.Paused; + } + + //Toggle full page mode if mouse right button pressed + if (Mouse.IsButtonClicked(Mouse.RightButton)) { + self.GraphicsDevice.ToggleFullPage(); + } + + //Catch the Mouse and Keyboard buttons + self.moveLeft = Keyboard.IsKeyDown(Keys.a) || Keyboard.IsKeyDown(Keys.left_arrow); + self.moveRight = Keyboard.IsKeyDown(Keys.d) || Keyboard.IsKeyDown(Keys.right_arrow); + self.jump = Keyboard.IsKeyDown(Keys.w) || Keyboard.IsKeyDown(Keys.up_arrow); + if ((!self.showCollisions && Keyboard.IsKeyPressed(Keys.c)) || + (self.showCollisions && !Keyboard.IsKeyPressed(Keys.c))) { + self.showCollisions = true; + } else { + self.showCollisions = false; + } + if (!self.punch && Keyboard.IsKeyUp(Keys.space)) { + self.punch = true; + self.soundEffects[5][1].Play(); + } + if (Keyboard.IsKeyPressed(Keys.add)) { + self.camera.IncreaseZoom(); + } + if (Keyboard.IsKeyPressed(Keys.subtract)) { + self.camera.DecreaseZoom(); + } + + //Update the player + self.player.Update(self.moveLeft, self.moveRight, self.jump, self.punch, self.platforms, levelWidth, self.pickableObjects, self.sprites, self.gravityForce, self.soundEffects, self.enemys); + + //Check if the player have all pearls and is in the win zone + if (self.player.Pearls === self.pearlsToCollect && self.player.Bounds().Intersects(self.winRect) !== false) { + self.song.Stop(); + self.soundEffects[8][1].Play(); + self.gameState = GameStates.GameWin; + return; + } + + //If player dies go to game over game state + if (self.player.Shield <= 0 || self.player.Sprite.Position.Y > self.level.Sprite.Height()) { + self.song.Stop(); + self.soundEffects[2][1].Play(); + self.gameState = GameStates.GameOver; + return; + } + + //Control the punch collision with Rayman + playerPunch = self.player.Punch; + if (self.punch && + playerPunch.IsReturning && + (self.player.Bounds().Intersects(playerPunch.Sprite.Bounds()) !== false)) { + playerPunch.Sprite.IsVisible = false; + playerPunch.IsReturning = false; + self.punch = false; + } + + //Update the camera + self.camera.Update(self.player); + + //Update the enemys + for (i = 0, len = self.enemys.length; i < len; i += 1) { + self.enemys[i].Update(levelWidth, self.platforms, self.gravityForce); + } + + //Move the distantBackground at half the speed of the camera + for (i = 0, len = self.level.DistantBackgroundsSprites.length; i < len; i += 1) { + self.level.DistantBackgroundsSprites[i].Position.X += self.camera.SpeedV.X / 2; + } + + //Capture the camera's current x position so we can use it as the + //previousX value in the next frame + self.camera.PreviousSpeedX = self.camera.Position.X; +}; + +/** + * This is called when the game should draw itself. + * @name Draw + * @function + * @memberOf Game + */ +Game.prototype.Draw = function () { + "use strict"; + var self = this, + len = self.sprites.length, + i = 0, + auxSprite = null, + hudSprite = self.hudSprite; + + self.GraphicsDevice.Clear(); + + self.spriteBatch.ctx.save(); + + self.spriteBatch.ctx.scale(self.camera.Zoom, self.camera.Zoom); + self.spriteBatch.ctx.translate(-self.camera.Position.X, -self.camera.Position.Y); + + //Draw the sprites if visibles + if (len > 0) { + for (i = 0; i < len; i += 1) { + auxSprite = self.sprites[i]; + if (auxSprite.IsVisible) { + self.spriteBatch.Draw( + auxSprite.Texture, + auxSprite.Position, + new Rectangle(auxSprite.SourceRect.X, auxSprite.SourceRect.Y, auxSprite.SourceRect.Width, auxSprite.SourceRect.Height), + auxSprite.Rotation, + auxSprite.Scale, + auxSprite.SpriteEffects + ); + } + } + } + + //Display the collision rectangles if requested + if (self.showCollisions) { + for (i = 0, len = self.platforms.length; i < len; i += 1) { + self.spriteBatch.DrawRectangle(self.platforms[i], "2", null); + } + + //Draw the player bounds + self.spriteBatch.DrawRectangle(self.player.Bounds(), "2", "#00FF00"); + + //Draw the Rayman's punch + if (self.player.Punch.Sprite.IsVisible) { + self.spriteBatch.DrawRectangle(self.player.Punch.Sprite.Bounds(), "2", "#0000FF"); + } + + //Draw the enemy bounds + for (i = 0, len = self.enemys.length; i < len; i += 1) { + self.spriteBatch.DrawRectangle(self.enemys[i].Bounds(), "2", "#FF0000"); + } + + //Draw the pickable objects bounds + for (i = 0, len = self.pickableObjects.length; i < len; i += 1) { + self.spriteBatch.DrawRectangle(self.pickableObjects[i].Bounds(), "2", "#FF00FF"); + } + + //Draw the win zone bounds + self.spriteBatch.DrawRectangle(self.winRect, "2", "#ffee00"); + } + + self.spriteBatch.ctx.restore(); + + //Draw the hud + self.spriteBatch.Draw( + hudSprite.Texture, + hudSprite.Position, + new Rectangle(hudSprite.SourceRect.X, hudSprite.SourceRect.Y, hudSprite.SourceRect.Width, hudSprite.SourceRect.Height), + hudSprite.Rotation, + hudSprite.Scale, + hudSprite.SpriteEffects + ); + + self.spriteBatch.DrawString( + "normal bold 24px Helvetica", + self.player.Shield + " / 5", + new Point(77, 25), + "#000000", + Vector2.One() + ); + + self.spriteBatch.DrawString( + "normal bold 20px Helvetica", + self.player.Pearls + " / " + self.pearlsToCollect, + new Point(735, 28), + "#000000", + Vector2.One() + ); + + if (self.player.CanFly) { + self.spriteBatch.Draw( + self.flyPowerTexture, + new Point(348, -2), + new Rectangle(0, 0, 64, 64), + 0, + new Vector2(1.3, 1.21), + SpriteEffects.None + ); + } + + if (self.player.PunchImproved) { + self.spriteBatch.Draw( + self.punchSpeedTexture, + new Point(404, -2), + new Rectangle(0, 0, 64, 64), + 0, + new Vector2(1.3, 1.21), + SpriteEffects.None + ); + } +}; + +/** + * Call this method to initialize the game, begin running the game loop, and + * start processing events for the game. + * @name Run + * @function + * @memberOf Game + */ +Game.prototype.Run = function () { + "use strict"; + /*globals requestAnimationFrame*/ + var self = this, + helpSprite = self.helpSprite, + gameOverSprite = self.gameOverSprite, + winSprite = self.winSprite; + + //Call the game loop + requestAnimationFrame(self.Run.bind(self), self.GraphicsDevice.canvas); + + //Choose the method to run according to the game state + switch (self.gameState) { + + case GameStates.Initializing: + self.Initialize(); + break; + + case GameStates.Loading: + self.LoadContent(); + break; + + case GameStates.Playing: + self.Update(); + self.Draw(); + break; + + case GameStates.Paused: + self.spriteBatch.Draw( + helpSprite.Texture, + helpSprite.Position, + new Rectangle(helpSprite.SourceRect.X, helpSprite.SourceRect.Y, helpSprite.SourceRect.Width, helpSprite.SourceRect.Height), + helpSprite.Rotation, + helpSprite.Scale, + helpSprite.SpriteEffects + ); + + //Go back to game if 'h' key pressed + if (Keyboard.IsKeyPressed(Keys.h)) { + self.gameState = GameStates.Playing; + } + + //Toggle full page mode if mouse right button pressed + if (Mouse.IsButtonClicked(Mouse.RightButton)) { + self.GraphicsDevice.ToggleFullPage(); + } + break; + + case GameStates.GameOver: + self.spriteBatch.Draw( + gameOverSprite.Texture, + gameOverSprite.Position, + new Rectangle(gameOverSprite.SourceRect.X, gameOverSprite.SourceRect.Y, gameOverSprite.SourceRect.Width, gameOverSprite.SourceRect.Height), + gameOverSprite.Rotation, + gameOverSprite.Scale, + gameOverSprite.SpriteEffects + ); + + //Go reset the game if 'r' key pressed + if (Keyboard.IsKeyPressed(Keys.r)) { + self.Reset(); + self.gameState = GameStates.Loading; + } + break; + + case GameStates.GameWin: + self.spriteBatch.Draw( + winSprite.Texture, + winSprite.Position, + new Rectangle(winSprite.SourceRect.X, winSprite.SourceRect.Y, winSprite.SourceRect.Width, winSprite.SourceRect.Height), + winSprite.Rotation, + winSprite.Scale, + winSprite.SpriteEffects + ); + + //Go reset the game if 'r' key pressed + if (Keyboard.IsKeyPressed(Keys.r)) { + self.Reset(); + self.gameState = GameStates.Loading; + } + break; + } +}; + +/** + * Reset the game + */ +Game.prototype.Reset = function () { + "use strict"; + var self = this; + + self.Content = new ContentManager(); + self.GraphicsDevice = new GraphicsDevice(document); + self.spriteBatch = null; + self.gameState = GameStates.Initializing; + self.preloading = true; + + self.level = null; + self.sprites = []; + + self.pearlsToCollect = 0; + + //Create the platforms, pickable objects and enemys arrays + self.platforms = []; + self.pickableObjects = []; + self.enemys = []; + + //Create the player + self.player = null; + + //Create the game camera + self.camera = null; + + //The win zone rectangle + self.winRect = null; + + //The help screen sprite + self.helpSprite = null; + + //The game over screen sprite + self.gameOverSprite = null; + + //The win screen sprite + self.winSprite = null; + + //Flags + self.moveRight = false; + self.moveLeft = false; + self.jump = false; + self.punch = false; + self.showCollisions = false; + + clearInterval(self.interval); + + /*if (self.GraphicsDevice.IsFullScreen()) { + self.GraphicsDevice.ToggleFullScreen(); + }*/ +}; \ No newline at end of file diff --git a/src/JS/Rayman_Classes/Ball.js b/src/JS/Rayman_Classes/Ball.js new file mode 100644 index 0000000..5084750 --- /dev/null +++ b/src/JS/Rayman_Classes/Ball.js @@ -0,0 +1,348 @@ +/** + * Defines a Ball. + * @constructor + * @param {Sprite} sprite - The sprite that represents the ball. + * @param {Number} radius - The radius of the circle of the ball. + * @param {Point} position - The position of the ball. + * @param {Number} position - The position of the ball. + * @param {Boolean} bounce - Determines if the ball can bounce or not. + */ +function Ball(sprite, radius, position, index, bounce, rotate) { + "use strict"; + /*global Vector2, Circle*/ + this.Sprite = sprite; + this.Circle = new Circle(radius, position.X, position.Y); + + //Physics properties + this.SpeedV = Vector2.Zero(); + this.GroundFriction = 0.975; //balls 0.975 fluid 0.99 + this.BallBounceFriction = 0.85; //balls 0.85 fluid 0.0 + this.WallBounceFriction = 0.7; //balls 0.7 fluid 0.4 + this.MaxRotationSpeedTransmision = 25; + this.CurrentRotationSpeed = 0; + + //Platform game properties + this.IsOnGround = false; + + //Drag & Drop properties + this.IsDraggable = true; + this.IsBeenDragged = false; + + //Other properties + this.RandomDir = [-0.1, 0.1]; + this.Index = index; + this.IsBounceOn = bounce; + this.IsRotationOn = rotate; +} + +/** + * Updates the ball. + * @name Update + * @function + * @param {Number} worldWidth - The width of the game world. + * @param {Number} worldHeight - The height of the game world. + * @param {Array} balls - Array of existing balls. + * @param {Boolean} isGravityOn - Determines if the gravity is activated or not. + * @param {GravityDirections} gravityDir - The gravity direction of the game world. + * @param {Number} gravityForce - The gravity force value. + * @memberOf Ball + */ +Ball.prototype.Update = function (worldWidth, worldHeight, balls, isGravityOn, gravityDir, gravityForce) { + "use strict"; + /*global GravityDirections, Mouse, Point, hitTestPoint*/ + var self = this, + randomDirImpulse = 0, + len = 0, + i = 0, + j = 0; + + //Check if the mouse clicked a ball to drag it + if (self.Circle.Contains(new Point(Mouse.X, Mouse.Y)) && self.IsDraggable && Mouse.LeftButtonPressed && !Mouse.IsDraggingSomething) { //Si quitamos IsDraggingSom... ocurren cosas divertidas + //Assign the sprite to the dragSprite variable + self.IsBeenDragged = true; + Mouse.IsDraggingSomething = true; + self.CurrentRotationSpeed = 0; + self.SpeedV.X = 0; + self.SpeedV.Y = 0; + i = self.Index; + len = balls.length; + + //push the dragSprite to the end of the sprites + //array so that it's displayed last + self.Index = balls.length - 1; + balls.push(self); + + //Splice the dragSprite from its previous + //position in the sprites array + balls.splice(i, 1); + + for (j = i; j < len - 1; j += 1) { + balls[j].Index -= 1; + } + } + + //Update the Circle position with the mouse position + if (Mouse.IsMoving && self.IsBeenDragged) { + self.Circle.X = Mouse.X - self.Circle.Radius; + self.Circle.Y = Mouse.Y - self.Circle.Radius; + } + + //If the mouse left button was released drop the ball + if (self.IsBeenDragged && !Mouse.LeftButtonPressed) { + self.IsBeenDragged = false; + Mouse.IsDraggingSomething = false; + } + + //Apply gravity depending on the gravity direction + if (isGravityOn && !self.IsBeenDragged) { + + //Random impulse when the balls are generated + if (!self.IsOnGround && self.SpeedV.X === 0 && self.SpeedV.Y === 0) { + randomDirImpulse = self.RandomDir[Math.floor(Math.random() * 2)]; + } + + switch (gravityDir) { + + //Gravity down + case GravityDirections.G_DOWN: + self.SpeedV.Y += gravityForce; + self.SpeedV.X += randomDirImpulse; + if (self.Circle.Bottom() >= worldHeight) { + self.SpeedV.X *= self.GroundFriction; + self.IsOnGround = true; + } + break; + + //Gravity up + case GravityDirections.G_UP: + self.SpeedV.Y -= gravityForce; + self.SpeedV.X += randomDirImpulse; + if (self.Circle.Top() <= 0) { + self.SpeedV.X *= self.GroundFriction; + self.IsOnGround = true; + } + break; + + //Gravity left + case GravityDirections.G_LEFT: + self.SpeedV.X -= gravityForce; + self.SpeedV.Y += randomDirImpulse; + if (self.Circle.Left() <= 0) { + self.SpeedV.Y *= self.GroundFriction; + self.IsOnGround = true; + } + break; + + //Gravity right + case GravityDirections.G_RIGHT: + self.SpeedV.X += gravityForce; + self.SpeedV.Y += randomDirImpulse; + if (self.Circle.Right() >= worldWidth) { + self.SpeedV.Y *= self.GroundFriction; + self.IsOnGround = true; + } + break; + } + + } + + //Move the ball if it isn't dragged + if (!self.IsBeenDragged) { + self.Circle.X += self.SpeedV.X; + self.Circle.Y += self.SpeedV.Y; + } + + //Collision with balls + len = balls.length; + if (len > 1 && !self.IsBeenDragged) { + for (i = 0; i < len; i += 1) { + if (self.Index !== i) { + self.CollisionWithBall(balls[i], self.IsBounceOn, self.IsRotationOn); + } + } + } + + //Screen boundaries + //Left + if (self.Circle.Left() < 0) { + if (self.IsBounceOn) { + self.SpeedV.X *= -self.WallBounceFriction; + } + self.Circle.X = 0; + } + //Up + if (self.Circle.Top() < 0) { + if (self.IsBounceOn) { + self.SpeedV.Y *= -self.WallBounceFriction; + } + self.Circle.Y = 0; + } + //Right + if (self.Circle.Right() > worldWidth) { + if (self.IsBounceOn) { + self.SpeedV.X *= -self.WallBounceFriction; + } + self.Circle.X = worldWidth - self.Circle.Diameter(); + } + //Down + if (self.Circle.Bottom() > worldHeight) { + if (self.IsBounceOn) { + self.SpeedV.Y *= -self.WallBounceFriction; + } + self.Circle.Y = worldHeight - self.Circle.Diameter(); + } + + //Update the sprite + self.Sprite.Position.X = self.Circle.X; + self.Sprite.Position.Y = self.Circle.Y; + + //Update the sprite rotation + self.Sprite.Rotation += self.CurrentRotationSpeed; + self.CurrentRotationSpeed *= self.GroundFriction; + //console.log(self.CurrentRotationSpeed); +}; + +/** + * Check if a ball collide with other ball. Besides, bounce and rotate the balls if needed. + * @name CollisionWithBall + * @function + * @param {Ball} ball - The ball which will be checked to find a collision. + * @memberOf Ball + */ +Ball.prototype.CollisionWithBall = function (ball) { + "use strict"; + var self = this, + overlapV = self.Circle.IsInsideCircle(ball.Circle), + vector = null, + d = null, + angle = 0, + b1Magnitude = 0, + b2Magnitude = 0, + s = null; + + //If the other ball is inside the other + if (overlapV !== false) { + self.Circle.X += overlapV.X; + self.Circle.Y += overlapV.Y; + return true; + } + + //Check if this ball is inside the other + overlapV = self.Circle.Intersects(ball.Circle); + + //If there is a collision with the other ball move it away of the other + if (overlapV !== false) { + + vector = overlapV.Y; //the vector between the balls centers + d = vector.Normalize(); + angle = Math.atan2(d.X, d.X) * 180 / Math.PI; + b1Magnitude = self.SpeedV.Length(); + b2Magnitude = ball.SpeedV.Length(); + + //If rotation is activated then rotate the ball + if (self.IsRotationOn) { + if ( + (angle >= 0 && angle <= 90 && self.SpeedV.X > 0) || + (angle > 90 && angle <= 180 && self.SpeedV.X >= 0) || + (angle < 0 && angle >= -90 && self.SpeedV.X <= 0) || + (angle < -90 && angle >= -180 && self.SpeedV.X < 0) + ) { + self.CurrentRotationSpeed = Math.min(Math.abs(b1Magnitude), self.MaxRotationSpeedTransmision); + ball.CurrentRotationSpeed = -Math.min(Math.abs(b2Magnitude), ball.MaxRotationSpeedTransmision); + } else { + self.CurrentRotationSpeed = -Math.min(Math.abs(b1Magnitude), self.MaxRotationSpeedTransmision); + ball.CurrentRotationSpeed = Math.min(Math.abs(b2Magnitude), ball.MaxRotationSpeedTransmision); + } + + //Limit the rotation speeds + if (Math.abs(self.CurrentRotationSpeed) < 1) { + self.CurrentRotationSpeed = 0; + } + if (Math.abs(ball.CurrentRotationSpeed) < 1) { + ball.CurrentRotationSpeed = 0; + } + } + + //Move circle 1 out of the collision by multiplying + //the overlap with the normalized vector and add it to + //ball 1's position + self.Circle.X += overlapV.X * d.X; + self.Circle.Y += overlapV.X * d.Y; + //Ocurren cosas diver al poner esto + //ball.Circle.X += overlapV.X * overlapV.Y[0]; + //ball.Circle.Y += overlapV.X * overlapV.Y[1]; + + if (self.IsBounceOn) { + //Create a collision vector object to represent the bounce surface + //Find the bounce surface's X and Y properties + //(This represents the normal of the distance vector between the circles) + s = new Vector2(vector.Y, -vector.X); + //var s = {}; + //s.X = vector.Y; + //s.Y = -vector.X; + + //Bounce b1 off the surface + self.BounceOffSurface(ball, s); + } + + return true; + } + + return false; +}; + +/** + * Bounces the current ball with other ball given the virtual surface between them. + * @name BounceOffSurface + * @function + * @param {Ball} ball - The ball which will bounced. + * @param {Vector2} s - The surface to bounce off. + * @memberOf Ball + */ +Ball.prototype.BounceOffSurface = function (ball, s) { + "use strict"; + //1. Calculate the collision surface's properties + + + var self = this, + //Find the surface vector's left normal + leftNormalV = new Vector2(s.Y, -s.X), + //s.lx = s.Y; + //s.ly = -s.X; + + //Find its magnitude + sLength = s.Length(), + + //Find its normalized/unit vector values + dV = s.Normalize(), + + //2. Bounce the ball off the surface (s) + + //Find the dot product between the object and the surface + dp1 = self.SpeedV.X * dV.X + self.SpeedV.Y * dV.Y, + + //Project the object's velocity onto the collision surface + p1V = new Vector2(dp1 * dV.X, dp1 * dV.Y), + + //Find the dot product of the object and the surface's left normal (s.lx and s.ly) + dp2 = self.SpeedV.X * (leftNormalV.X / sLength) + self.SpeedV.Y * (leftNormalV.Y / sLength), + + //Project the object's velocity onto the surface's left normal + p2V = new Vector2(dp2 * (leftNormalV.X / sLength), dp2 * (leftNormalV.Y / sLength)), + bounceV = null; + + //Reverse the projection on the surface's left normal + p2V.X *= -1; + p2V.Y *= -1; + + //Add up the projections to create a new bounce vector + bounceV = new Vector2(p1V.X + p2V.X, p1V.Y + p2V.Y); + + //Assign the bounce vector to the object's velocity + self.SpeedV.X = bounceV.X * self.BallBounceFriction; + self.SpeedV.Y = bounceV.Y * self.BallBounceFriction; + if (!ball.IsBeenDragged) { + ball.SpeedV.X = -bounceV.X * ball.BallBounceFriction; + ball.SpeedV.Y = -bounceV.Y * ball.BallBounceFriction; + } +}; \ No newline at end of file diff --git a/src/JS/Rayman_Classes/Enemy.js b/src/JS/Rayman_Classes/Enemy.js new file mode 100644 index 0000000..932bf1f --- /dev/null +++ b/src/JS/Rayman_Classes/Enemy.js @@ -0,0 +1,186 @@ +/** + * Represents one enemy. + * @constructor + * @param {AnimatedSprite|Sprite} sprite - The enemys's sprite. + */ +function Enemy(sprite) { + "use strict"; + /*globals Vector2, setInterval, AnimatedSprite, SpriteEffects*/ + + this.Sprite = sprite; + + //Physics properties + this.SpeedV = Vector2.Zero(); + this.Speed = 0; + + //Platform game properties + this.IsOnGround = undefined; + + //Enemy States + this.IDLE = 0; + this.MOVING = 1; + this.HITTED = 2; + //this.TURNING = 3; + //[...] + this.CurrentState = 0; + + //Enemy attributtes + //this.life = 2; + + //If the sprite is animated starts the sprite animation + if (this.Sprite instanceof AnimatedSprite) { + this.Sprite.StartAnimation(); + } + + //Change the enemy state every 1,8 seconds + this.interval = setInterval(this.ChangeEnemyState.bind(this), 1800); +} + +/** + * Updates de enemy. + * @name Update + * @function + * @param {Number} levelWidth - The width of the level. + * @param {Array} platforms - The platforms array. + * @param {Number} gravityForce - The gravity force. + * @memberOf Enemy + */ +Enemy.prototype.Update = function (levelWidth, platforms, gravityForce) { + "use strict"; + var self = this, + enemySprite = self.Sprite, + bounds = null, + i = 0, + overlapV = null, + currentPlatform = null, + len = 0; + + //If the enemy was hitted stop it + if (self.CurrentState !== self.HITTED) { + + switch (self.CurrentState) { + case self.IDLE: + //enemySprite.currentFrame = 0; + enemySprite.NumberOfFrames = 20; + self.Speed = 0; + break; + case self.MOVING: + //enemySprite.currentFrame = 0; + enemySprite.NumberOfFrames = 14; + self.Speed = 1.5; + break; + } + + //Apply the acceleration + self.SpeedV.X = self.Speed; + if (enemySprite.SpriteEffects === SpriteEffects.FlipHorizontally) { + self.SpeedV.X *= -1; + } + + //Apply gravityForce + self.SpeedV.Y += gravityForce; + + //Check for a collision between the enemy and the platforms + bounds = self.Bounds(); + + for (i = 0, len = platforms.length; i < len; i += 1) { + + currentPlatform = platforms[i]; + overlapV = bounds.Intersects(currentPlatform); + + if (overlapV !== false && self.SpeedV.Y >= 0) { + + if (bounds.Bottom() >= currentPlatform.Top() && + bounds.Bottom() <= currentPlatform.Bottom()) { + + //Move the rectangle out of the collision + enemySprite.Position.Y -= overlapV.Y; + + //Tell the game that the player is on the ground if + //it's standing on top of a platform + self.IsOnGround = true; + + //Neutralize gravity by applying its + //exact opposite force to the character's vy + self.SpeedV.Y = -gravityForce; + } + + } else if (overlapV === false && self.SpeedV.Y > 0) { + self.IsOnGround = false; + } + } + + //Screen boundaries + //Left + if (bounds.X < 0) { + self.SpeedV.X = 0; + enemySprite.Position.X = enemySprite.Position.X - bounds.Position.X; + } + //Up + if (bounds.Y < 0) { + self.SpeedV.Y = 0; + enemySprite.Position.Y = enemySprite.Position.Y - bounds.Position.Y; + } + //Right + if (bounds.X + bounds.Width > levelWidth) { + self.SpeedV.X = 0; + enemySprite.Position.X = levelWidth - (enemySprite.Right() - bounds.Right()) - bounds.Width; + } + } + + //Move the enemy + enemySprite.Position.X += self.SpeedV.X; + enemySprite.Position.Y += self.SpeedV.Y; + + //If the sprite is animated change its vertical offset depending on the player's state + if (self.Sprite instanceof AnimatedSprite) { + self.Sprite.VerticalOffset = self.CurrentState; + } +}; + +/** + * Changes the enemy state randomly + * @name ChangeEnemysState + * @function + * @memberOf Enemy + */ +Enemy.prototype.ChangeEnemyState = function () { + "use strict"; + /*globals SpriteEffects*/ + var self = this, + enemySprite = self.Sprite; + + self.CurrentState = Math.floor((Math.random() * 2)); + if (self.CurrentState === self.MOVING) { + if (enemySprite.SpriteEffects === SpriteEffects.FlipHorizontally) { + enemySprite.SpriteEffects = SpriteEffects.None; + } else { + enemySprite.SpriteEffects = SpriteEffects.FlipHorizontally; + } + } + + //Reset the current frame if is an animated sprite + if (enemySprite instanceof AnimatedSprite) { + enemySprite.CurrentFrame = 0; + } +}; + +/** + * The enemys's collision rectangle. + * @name Bounds + * @function + * @memberOf Enemy + */ +Enemy.prototype.Bounds = function () { + "use strict"; + /*globals Rectangle*/ + var self = this, + spriteBounds = self.Sprite.Bounds(); + + return new Rectangle( + spriteBounds.X + spriteBounds.HalfWidth() / 2, + spriteBounds.Y + 20, + spriteBounds.HalfWidth(), + spriteBounds.Height - 20 + ); +}; \ No newline at end of file diff --git a/src/JS/Rayman_Classes/Enums.js b/src/JS/Rayman_Classes/Enums.js new file mode 100644 index 0000000..ad432e5 --- /dev/null +++ b/src/JS/Rayman_Classes/Enums.js @@ -0,0 +1,27 @@ +/** + * Defines the types of the pickable objects. + * @readonly + * @enum {number} + */ +var PickableObjectTypes = Object.freeze({ + "PEARL": 0, + "LIFE": 1, + "MINI_SHIELD": 2, + "SHIELD": 3, + "PUNCH_SPEED": 4, + "PUNCH_POWER": 5, + "ETERNAL_FLY": 6 +}); + +/** + * Defines the powers. + * @readonly + * @enum {number} + */ +var Powers = Object.freeze({ + "PUNCH": 0, + "HOLD": 1, + "FLY": 2, + "ENGAGE": 3, + "RUN": 4 +}); \ No newline at end of file diff --git a/src/JS/Rayman_Classes/Level.js b/src/JS/Rayman_Classes/Level.js new file mode 100644 index 0000000..732e153 --- /dev/null +++ b/src/JS/Rayman_Classes/Level.js @@ -0,0 +1,1886 @@ +function Level (sprite) +{ + "use strict"; + this.Sprite = sprite; + this.DistantBackgroundsSprites = []; + this.PickableObjects = [ + { + "height":72, + "id":75, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":843, + "y":751 + }, + { + "height":72, + "id":77, + "name":"ETERNAL_FLY", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":1592, + "y":185 + }, + { + "height":72, + "id":78, + "name":"SHIELD", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":1283, + "y":355 + }, + { + "height":72, + "id":79, + "name":"PUNCH_SPEED", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":779, + "y":208 + }, + { + "height":72, + "id":95, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":341, + "y":435 + }, + { + "height":72, + "id":96, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":46, + "y":361 + }, + { + "height":72, + "id":97, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":524, + "y":890 + }, + { + "height":72, + "id":98, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":1060, + "y":800 + }, + { + "height":72, + "id":99, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":1610, + "y":624 + }, + { + "height":72, + "id":100, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":1358, + "y":779 + }, + { + "height":72, + "id":102, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":1608, + "y":371 + }, + { + "height":72, + "id":103, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":1075, + "y":351 + }, + { + "height":72, + "id":104, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":53, + "y":899 + }, + { + "height":72, + "id":111, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":2219, + "y":833.333333333333 + }, + { + "height":72, + "id":112, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":2460.33333333333, + "y":674.666666666667 + }, + { + "height":72, + "id":113, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":2504.33333333333, + "y":500 + }, + { + "height":72, + "id":114, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":2709.66666666667, + "y":861.333333333333 + }, + { + "height":72, + "id":115, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":3020.33333333333, + "y":889.333333333333 + }, + { + "height":72, + "id":116, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":3224.33333333333, + "y":624 + }, + { + "height":72, + "id":117, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":2908.33333333333, + "y":502.666666666667 + }, + { + "height":72, + "id":118, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":3929.66666666667, + "y":713.333333333333 + }, + { + "height":72, + "id":119, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":4007, + "y":908 + }, + { + "height":72, + "id":120, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":3549.66666666667, + "y":912 + }, + { + "height":72, + "id":121, + "name":"PEARL", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":3611, + "y":689.333333333333 + }, + { + "height":72, + "id":155, + "name":"SHIELD", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":2699, + "y":576 + }, + { + "height":72, + "id":156, + "name":"SHIELD", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":3813.66666666667, + "y":756 + }]; + this.Player = + { + "height":72, + "id":72, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":178, + "y":867 + } + this.Enemys = [ + { + "height":72, + "id":82, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":1603, + "y":898 + }, + { + "height":72, + "id":83, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":1383, + "y":485 + }, + { + "height":72, + "id":84, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":520, + "y":142 + }, + { + "height":72, + "id":86, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":688, + "y":847 + }, + { + "height":72, + "id":87, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":720, + "y":521 + }, + { + "height":72, + "id":147, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":2698, + "y":568 + }, + { + "height":72, + "id":148, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":2451, + "y":809 + }, + { + "height":72, + "id":149, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":3369, + "y":905 + }, + { + "height":72, + "id":150, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":3942, + "y":903 + }, + { + "height":72, + "id":151, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":3634, + "y":663 + }, + { + "height":72, + "id":152, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":3766, + "y":901 + }, + { + "height":72, + "id":153, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":74, + "x":3957, + "y":721 + }]; + this.Platforms = [ + { + "height":13, + "id":3, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":443, + "x":2, + "y":987 + }, + { + "height":16, + "id":4, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":42, + "x":483, + "y":979 + }, + { + "height":13, + "id":5, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":75, + "x":529, + "y":985 + }, + { + "height":14, + "id":7, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":33, + "x":606, + "y":978 + }, + { + "height":12, + "id":8, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":39, + "x":630, + "y":970 + }, + { + "height":13, + "id":9, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":37, + "x":647, + "y":960 + }, + { + "height":12, + "id":10, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":43, + "x":662, + "y":950 + }, + { + "height":14, + "id":11, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":83, + "x":683, + "y":941 + }, + { + "height":18, + "id":12, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":27, + "x":757, + "y":949 + }, + { + "height":17, + "id":13, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":32, + "x":775, + "y":956 + }, + { + "height":20, + "id":14, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":24, + "x":801, + "y":965 + }, + { + "height":15, + "id":15, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":40, + "x":813, + "y":977 + }, + { + "height":14, + "id":16, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":125, + "x":848, + "y":983 + }, + { + "height":13, + "id":17, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":35, + "x":881, + "y":944 + }, + { + "height":13, + "id":18, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":195, + "x":997, + "y":915 + }, + { + "height":12, + "id":19, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":165, + "x":1014, + "y":903 + }, + { + "height":13, + "id":20, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":119, + "x":1030, + "y":893 + }, + { + "height":12, + "id":21, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":71, + "x":843, + "y":836 + }, + { + "height":13, + "id":22, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":61, + "x":704, + "y":753 + }, + { + "height":12, + "id":23, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":121, + "x":702, + "y":674 + }, + { + "height":14, + "id":24, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":80, + "x":715, + "y":617 + }, + { + "height":13, + "id":25, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":80, + "x":199, + "y":737 + }, + { + "height":9, + "id":26, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":82, + "x":342, + "y":675 + }, + { + "height":17, + "id":27, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":77, + "x":505, + "y":623 + }, + { + "height":14, + "id":28, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":116, + "x":323, + "y":528 + }, + { + "height":12.6667, + "id":30, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":43.3333, + "x":191.333, + "y":611.333 + }, + { + "height":10, + "id":31, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":28, + "x":165.333, + "y":615.333 + }, + { + "height":14, + "id":32, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":60, + "x":48.6667, + "y":606 + }, + { + "height":13.3333, + "id":33, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":36, + "x":96, + "y":598 + }, + { + "height":10.6667, + "id":34, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":32.6667, + "x":124, + "y":605.333 + }, + { + "height":12.6667, + "id":35, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":21.3333, + "x":147.333, + "y":610 + }, + { + "height":11.3333, + "id":36, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":22.6667, + "x":82, + "y":601.333 + }, + { + "height":12.6667, + "id":37, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":65.3333, + "x":48.6667, + "y":460 + }, + { + "height":13.3333, + "id":39, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":121.333, + "x":496.667, + "y":228 + }, + { + "height":15, + "id":40, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":121, + "x":753, + "y":307 + }, + { + "height":14, + "id":41, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":68, + "x":992, + "y":295 + }, + { + "height":16, + "id":42, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":50, + "x":992, + "y":443 + }, + { + "height":13, + "id":43, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":39, + "x":1138, + "y":446 + }, + { + "height":12, + "id":44, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":34, + "x":1109, + "y":454 + }, + { + "height":14, + "id":45, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":46, + "x":1033, + "y":436 + }, + { + "height":10, + "id":46, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":27, + "x":1074, + "y":444 + }, + { + "height":14, + "id":47, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":21, + "x":1095, + "y":450 + }, + { + "height":12, + "id":48, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":64, + "x":1281, + "y":459 + }, + { + "height":13, + "id":49, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":52, + "x":1280, + "y":606 + }, + { + "height":17, + "id":50, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":32, + "x":1313, + "y":595 + }, + { + "height":15, + "id":51, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":33, + "x":1340, + "y":597 + }, + { + "height":15, + "id":52, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":37, + "x":1365, + "y":604 + }, + { + "height":15, + "id":53, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":35, + "x":1397, + "y":614 + }, + { + "height":16, + "id":54, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":42, + "x":1424, + "y":604 + }, + { + "height":10, + "id":56, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":122, + "x":1570, + "y":262 + }, + { + "height":14, + "id":60, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":124, + "x":1569, + "y":450 + }, + { + "height":12, + "id":62, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":124, + "x":1567, + "y":550 + }, + { + "height":17, + "id":64, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":122, + "x":1585, + "y":707 + }, + { + "height":14, + "id":65, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":121, + "x":1777, + "y":746 + }, + { + "height":12, + "id":66, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":121, + "x":1601, + "y":836 + }, + { + "height":11, + "id":67, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":47, + "x":1265, + "y":881 + }, + { + "height":15, + "id":68, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":46, + "x":1486, + "y":895 + }, + { + "height":13, + "id":70, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":90, + "x":1349, + "y":873 + }, + { + "height":17, + "id":71, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":847, + "x":1199, + "y":991 + }, + { + "height":15, + "id":88, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":113, + "x":1573, + "y":163 + }, + { + "height":9, + "id":92, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":190, + "x":486, + "y":985 + }, + { + "height":20, + "id":93, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":62, + "x":784, + "y":978 + }, + { + "height":18, + "id":94, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":148, + "x":663, + "y":970 + }, + { + "height":16, + "id":109, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":776.667, + "x":3314.67, + "y":995.333 + }, + { + "height":14, + "id":122, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":67, + "x":2224, + "y":922 + }, + { + "height":16, + "id":123, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":64, + "x":2448, + "y":896 + }, + { + "height":16, + "id":124, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":120, + "x":2445, + "y":813 + }, + { + "height":16, + "id":125, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":83, + "x":2458, + "y":760 + }, + { + "height":17, + "id":126, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":119, + "x":2481, + "y":590 + }, + { + "height":21, + "id":127, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":81, + "x":2695, + "y":674 + }, + { + "height":16, + "id":128, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":78, + "x":2704, + "y":967 + }, + { + "height":13, + "id":129, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":57, + "x":2727, + "y":960 + }, + { + "height":13, + "id":130, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":43, + "x":2743, + "y":952 + }, + { + "height":17, + "id":131, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":42, + "x":2635, + "y":1003 + }, + { + "height":17, + "id":132, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":83, + "x":2051, + "y":994 + }, + { + "height":15, + "id":134, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":69, + "x":2050, + "y":981 + }, + { + "height":10, + "id":135, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":42, + "x":2062, + "y":974 + }, + { + "height":14, + "id":136, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":79, + "x":3015, + "y":979 + }, + { + "height":15, + "id":138, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":67, + "x":3231, + "y":714 + }, + { + "height":16, + "id":139, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":122, + "x":2881, + "y":588 + }, + { + "height":20, + "id":140, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":121, + "x":3586, + "y":780 + }, + { + "height":19, + "id":141, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":52, + "x":3858, + "y":843 + }, + { + "height":19, + "id":142, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":49, + "x":3899, + "y":824 + }, + { + "height":21, + "id":143, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":110, + "x":3940, + "y":811 + }, + { + "height":12, + "id":157, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":80, + "x":1751, + "y":353 + }]; + this.WinRect = + { + "height":51.33, + "id":159, + "name":"", + "properties": + { + + }, + "rotation":0, + "type":"", + "visible":true, + "width":37.67, + "x":3813.67, + "y":941.67 + } +} \ No newline at end of file diff --git a/src/JS/Rayman_Classes/Player.js b/src/JS/Rayman_Classes/Player.js new file mode 100644 index 0000000..4e92fc3 --- /dev/null +++ b/src/JS/Rayman_Classes/Player.js @@ -0,0 +1,342 @@ +/** + * Represents the player, in this case, Rayman. + * @constructor + * @param {AnimatedSprite|Sprite} sprite - The player's sprite. + */ +function Player(sprite) { + "use strict"; + /*globals Vector2, AnimatedSprite*/ + this.Sprite = sprite; //The player sprite + + //Physics properties + this.SpeedV = Vector2.Zero(); + this.AccelerationV = Vector2.Zero(); + this.SpeedLimit = 3; + this.GroundFriction = 1; //0.96 + //this.bounce = -0.7; + + //Platform game properties + this.IsOnGround = undefined; + this.JumpForce = -8; + + //Player States + this.IDLE = 0; + this.MOVING = 3; + this.JUMPING = 4; + this.FLYING = 10; + this.HITTED = 5; + //this.CROUCHED = 4; + //[...] + this.CurrentState = 0; + + //Player attributtes (Rayman) + this.Pearls = 0; + //this.Life = 3; + this.Shield = 5; + this.CanFly = false; + this.PunchImproved = false; + + //The punch (Rayman) + this.Punch = null; + + //If the sprite is animated starts the sprite animation + if (this.Sprite instanceof AnimatedSprite) { + this.Sprite.StartAnimation(); + } +} + +/** + * Updates de player. + * @name Update + * @function + * @param {Boolean} moveLeft - Tells if the player moved left or not. + * @param {Boolean} moveRight - Tells if the player moved right or not. + * @param {Boolean} jump - Tells if the player jumped or not. + * @param {Boolean} punchPressed - Tells if the player shoot the punch or not. + * @param {Array} platforms - The platforms array. + * @param {Number} levelWidth - The width of the level. + * @param {Array} pickableObjects - The pickable objects array. + * @param {Array} sprites - The sprites array. + * @param {Number} gravityForce - The gravity force. + * @memberOf Player + */ +Player.prototype.Update = function (moveLeft, moveRight, jump, punchPressed, platforms, levelWidth, pickableObjects, sprites, gravityForce, soundEffects, enemys) { + "use strict"; + /*globals SpriteEffects, Keyboard, Keys*/ + var self = this, + playerSprite = self.Sprite, + bounds = null, + i = 0, + len = 0, + overlapV = null, + currentPlatform = null, + currentPickableObject = null, + currentEnemy = null, + index = 0; + + //If rayman was hitted remove any control + if (self.CurrentState !== self.HITTED) { + //Left + if (moveLeft && !moveRight) { + self.AccelerationV.X = -2.8; //0.2 + self.GroundFriction = 1; + self.CurrentState = self.MOVING; + playerSprite.SpriteEffects = SpriteEffects.FlipHorizontally; + } + //Right + if (moveRight && !moveLeft) { + self.AccelerationV.X = 2.8; //0.2 + self.GroundFriction = 1; + self.CurrentState = self.MOVING; + playerSprite.SpriteEffects = SpriteEffects.None; + } + //Space + if (jump && self.IsOnGround) { + self.SpeedV.Y += self.JumpForce; + self.IsOnGround = false; + self.GroundFriction = 1; + } + + //Set the player's acceleration, friction and gravity + //to zero if none of the arrow keys are being pressed + if (!moveLeft && !moveRight) { + self.AccelerationV.X = 0; + self.GroundFriction = 0.1; //0.96 + gravityForce = 0.3; + self.CurrentState = self.IDLE; + } + + //If player is in the air set the state to "jumping" + if (!self.IsOnGround) { + self.CurrentState = self.JUMPING; + self.hitGroundCounter = 0; + } + + //Apply the acceleration + self.SpeedV.X += self.AccelerationV.X; + self.SpeedV.Y += self.AccelerationV.Y; + + //Apply friction + if (self.IsOnGround) { + self.SpeedV.X *= self.GroundFriction; + } + + //If space pressed and is not on ground then fly + //If not apply gravity + if (self.CanFly && (Keyboard.IsKeyDown(Keys.w) || Keyboard.IsKeyDown(Keys.up_arrow)) && !self.IsOnGround && self.SpeedV.Y > 0) { + self.CurrentState = self.FLYING; + self.SpeedV.X /= 2; + self.SpeedV.Y = self.SpeedLimit / 3.2; + soundEffects[1][1].Play(); + } else { + self.SpeedV.Y += gravityForce; + } + + //Limit the speed + //Don't limit the upward speed because it will choke the jump effect + if (self.SpeedV.X > self.SpeedLimit) { + self.SpeedV.X = self.SpeedLimit; + } + if (self.SpeedV.X < -self.SpeedLimit) { + self.SpeedV.X = -self.SpeedLimit; + } + if (self.SpeedV.Y > self.SpeedLimit * 2) { + self.SpeedV.Y = self.SpeedLimit * 2; + } + + } + + //Move the player + playerSprite.Position.X += self.SpeedV.X; + playerSprite.Position.Y += self.SpeedV.Y; + + //Update the punch + if (punchPressed) { + self.Punch.Update(playerSprite, levelWidth, sprites, enemys, soundEffects[0][1]); + } + + bounds = self.Bounds(); + + //Check for a collision between the player and the platforms + for (i = 0, len = platforms.length; i < len; i += 1) { + + currentPlatform = platforms[i]; + overlapV = bounds.Intersects(currentPlatform); + + if (overlapV !== false && self.SpeedV.Y >= 0) { + + if (bounds.Bottom() >= currentPlatform.Top() && + bounds.Bottom() <= currentPlatform.Bottom()) { + + //Move the rectangle out of the collision + playerSprite.Position.Y -= overlapV.Y; + + //Tell the game that the player is on the ground if + //it's standing on top of a platform + self.IsOnGround = true; + + //Neutralize gravity by applying its + //exact opposite force to the character's vy + self.SpeedV.Y = -gravityForce; + + //Play the hit the ground sound effect if rayman is not moving in the Y axis + if (self.hitGroundCounter === 0) { + soundEffects[10][1].Play(); + self.hitGroundCounter += 1; + } + } + + } else if (overlapV === false && self.SpeedV.Y > 0) { + self.IsOnGround = false; + } + } + + //Check for a collision between the player and the pickable objects + for (i = 0, len = pickableObjects.length; i < len; i += 1) { + + currentPickableObject = pickableObjects[i]; + + overlapV = bounds.Intersects(currentPickableObject.Bounds()); + + //If the collision occurs pick the object and delete the object from the level + if (overlapV !== false) { + + self.PickObject(currentPickableObject, soundEffects); + index = sprites.indexOf(currentPickableObject.Sprite); + if (index !== -1) { + sprites.splice(index, 1); + } + index = pickableObjects.indexOf(currentPickableObject); + if (index !== -1) { + pickableObjects.splice(index, 1); + len -= 1; + } + } + } + + //Check for a collision between the player and the enemys if the player wasn't hitted + //in one second + if (self.CurrentState !== self.HITTED) { + for (i = 0, len = enemys.length; i < len; i += 1) { + + currentEnemy = enemys[i]; + + overlapV = bounds.Intersects(currentEnemy.Bounds()); + + //If the collision occurs throw rayman away + if (currentEnemy.CurrentState !== currentEnemy.HITTED && overlapV !== false) { + + self.SpeedV.Y += self.JumpForce / 3; + if (playerSprite.SpriteEffects === SpriteEffects.FlipHorizontally) { + self.SpeedV.X += self.SpeedLimit * 2; + } else { + self.SpeedV.X -= self.SpeedLimit * 2; + } + self.IsOnGround = false; + self.GroundFriction = 1; + self.CurrentState = self.HITTED; + //Set timeout to avoid many hits in a row + setTimeout(function () { + self.CurrentState = self.IDLE; + }, 600); + //Play the hitted sound + soundEffects[6][1].Play(); + //Decrement the shield by 1 point + self.Shield -= 1; + } + } + } + + //Screen boundaries + bounds = self.Bounds(); + //Left + if (bounds.X < 0) { + self.SpeedV.X = 0; + playerSprite.Position.X = playerSprite.Position.X - bounds.X; + } + //Up + if (bounds.Y < 0) { + self.SpeedV.Y = 0; + playerSprite.Position.Y = playerSprite.Position.Y - bounds.Y; + } + //Right + if (bounds.X + bounds.Width > levelWidth) { + self.SpeedV.X = 0; + playerSprite.Position.X = levelWidth - (playerSprite.Right() - bounds.Right()) - bounds.Width; + } + + //If the sprite is animated change its vertical offset depending on the player's state + if (self.Sprite instanceof AnimatedSprite) { + self.Sprite.VerticalOffset = self.CurrentState; + } +}; + +Player.prototype.PickObject = function (object, soundEffects) { + "use strict"; + /*globals PickableObjectTypes*/ + var self = this; + + switch (object.Type) { + case PickableObjectTypes.PEARL: + self.Pearls += 1; + if (self.Pearls >= 100) { + self.Pearls = 0; + self.Life += 1; + } + soundEffects[3][1].Play(); + break; + + case PickableObjectTypes.LIFE: + self.Life += 1; + break; + + case PickableObjectTypes.MINI_SHIELD: + self.Shield += 1; + if (self.Shield > 5) { + self.Shield = 5; + } + break; + + case PickableObjectTypes.SHIELD: + self.Shield = 5; + soundEffects[7][1].Play(); + break; + + case PickableObjectTypes.PUNCH_SPEED: + self.Punch.Speed = 8; + self.Punch.MaxScope = 290; + self.Punch.Sprite.SourceRect.X += 20; + self.PunchImproved = true; + soundEffects[4][1].Play(); + break; + + case PickableObjectTypes.PUNCH_POWER: + self.Punch.Power = 1.5; + break; + + case PickableObjectTypes.ETERNAL_FLY: + self.CanFly = true; + soundEffects[4][1].Play(); + break; + } +}; + +/** + * The player's collision rectangle. + * @name Bounds + * @function + * @memberOf Player + */ +Player.prototype.Bounds = function () { + "use strict"; + /*globals Rectangle*/ + var self = this, + spriteBounds = self.Sprite.Bounds(); + + return new Rectangle( + spriteBounds.X + spriteBounds.HalfWidth() / 2, + spriteBounds.Y + 20, + spriteBounds.HalfWidth(), + spriteBounds.Height - 20 + ); +}; \ No newline at end of file diff --git a/src/JS/Rayman_Classes/Projectile.js b/src/JS/Rayman_Classes/Projectile.js new file mode 100644 index 0000000..5b407c8 --- /dev/null +++ b/src/JS/Rayman_Classes/Projectile.js @@ -0,0 +1,133 @@ +/** + * Represents the Rayman's punch. + * @constructor + * @param {Sprite} sprite - The sprite of the punch. + */ +function Projectile(sprite) { + "use strict"; + /*globals Vector2*/ + this.Sprite = sprite; + this.Speed = 6; + this.MaxScope = 200; + this.ScopeCounter = 0; + this.IsReturning = false; + this.Power = 1; + this.SpeedV = Vector2.Zero(); +} + +/** + * Updates de player's (Rayman) punch. + * @name Update + * @function + * @param {Sprite} playerSprite - The player's sprite. + * @param {Number} levelWidth - The width of the level. + * @memberOf Projectile + */ +Projectile.prototype.Update = function (playerSprite, levelWidth, sprites, enemys, enemyHittedSound) { + "use strict"; + /*globals SpriteEffects*/ + var self = this, + moveDistance = 0, + moveVector = null, + d = null, + punchSprite = self.Sprite, + bounds = punchSprite.Bounds(), + currentEnemy = null, + i = 0, + len = 0, + overlapV = null, + aux = 0, + aux2 = null; + + //If the punch isn't visible update its position with the player position + if (!punchSprite.IsVisible) { + + punchSprite.IsVisible = true; + punchSprite.Position.X = playerSprite.Position.X + playerSprite.HalfWidth() - punchSprite.HalfWidth(); + punchSprite.Position.Y = playerSprite.Position.Y + playerSprite.HalfHeight() - punchSprite.HalfHeight(); + punchSprite.SpriteEffects = playerSprite.SpriteEffects; + + } else { + + //Control the scope + if (self.ScopeCounter >= self.MaxScope || + bounds.X < 0 || + bounds.Y < 0 || + bounds.X + bounds.Width > levelWidth) { + + self.ScopeCounter = 0; + self.IsReturning = true; + if (punchSprite.SpriteEffects === SpriteEffects.FlipHorizontally) { + punchSprite.SpriteEffects = SpriteEffects.None; + } else { + punchSprite.SpriteEffects = SpriteEffects.FlipHorizontally; + } + } + + //If the punch is returning to the player update the movement + if (self.IsReturning) { + + moveVector = new Vector2(playerSprite.Center().X - punchSprite.Center().X, playerSprite.Center().Y - punchSprite.Center().Y); + d = moveVector.Normalize(); + + //Increase the punch's velocity + self.SpeedV.X += d.X; + self.SpeedV.Y += d.Y; + + d = self.SpeedV.Normalize(); + + //Apply easing + self.SpeedV.X = self.Speed * d.X; + self.SpeedV.Y = self.Speed * d.Y; + punchSprite.Position.X += self.SpeedV.X; + punchSprite.Position.Y += self.SpeedV.Y; + + //If not update the position with the speed + } else { + + if (punchSprite.SpriteEffects === SpriteEffects.FlipHorizontally) { + punchSprite.Position.X += self.Speed * -1; + } else { + punchSprite.Position.X += self.Speed; + } + self.ScopeCounter += self.Speed; + } + + //Check for a collision between the punch and the enemys + for (i = 0, len = enemys.length; i < len; i += 1) { + + currentEnemy = enemys[i]; + + overlapV = self.Sprite.Bounds().Intersects(currentEnemy.Bounds()); + + //If the collision occurs throw rayman away + if (currentEnemy.CurrentState !== currentEnemy.HITTED && overlapV !== false) { + + //Set the punch returning + self.ScopeCounter = 0; + self.IsReturning = true; + if (punchSprite.SpriteEffects === SpriteEffects.FlipHorizontally) { + punchSprite.SpriteEffects = SpriteEffects.None; + } else { + punchSprite.SpriteEffects = SpriteEffects.FlipHorizontally; + } + + currentEnemy.CurrentState = currentEnemy.HITTED; + currentEnemy.SpeedV.Y = -4; + clearInterval(currentEnemy.interval); + + //Set timeout to avoid many hits in a row + aux = i; + aux2 = currentEnemy; + setTimeout(function () { + aux2.Sprite.IsVisible = false; + enemys.splice(aux, 1); + }, 600); + + //Play the hitted sound + enemyHittedSound.Play(); + } + } + } + +}; \ No newline at end of file diff --git a/src/JS/Unit_Testing/Test_GraphicsDevice_AnimatedSprite.js b/src/JS/Unit_Testing/Test_GraphicsDevice_AnimatedSprite.js new file mode 100644 index 0000000..e0d9963 --- /dev/null +++ b/src/JS/Unit_Testing/Test_GraphicsDevice_AnimatedSprite.js @@ -0,0 +1,338 @@ +/** + * Provides basic graphics device initialization, game logic, and rendering code. + */ +function Game() { + "use strict"; + /*globals ContentManager, GraphicsDevice, document, SpriteBatch, GameStates, Vector2, Point, Sprite, AnimatedSprite, Rectangle, AnimationTypes, Segment, SpriteEffects, Mouse, Keys, Keyboard*/ + this.Content = new ContentManager(); + this.GraphicsDevice = new GraphicsDevice(document); + this.spriteBatch = null; + this.gameState = GameStates.Initializing; + this.preloading = true; + + //Constants + this.FONT_LITTLE = "normal bold 15px Helvetica"; + this.FONT_BIG = "normal bold 18px Helvetica"; + this.BLACK = "#000000"; + this.GREEN = "#00FF00"; + this.RED = "#FF0000"; + this.BLUE = "#0000FF"; + this.SPEED = 3; + + //The animated sprite + this.image = null; + this.sprite = null; + + //Flags + this.showBounds = false; + this.animStarted = false; + + //Other variables + this.animTypeIndex = 1; +} + +/** + * Allows the game to perform any initialization it needs to before starting to run. + * This is where it can query for any required services and load any non-graphic + * related content. + * @name Initialize + * @function + * @memberOf Game + */ +Game.prototype.Initialize = function () { + "use strict"; + var self = this; + + // TODO: Add your initialization logic here + + self.gameState = GameStates.Loading; +}; + +/** + * LoadContent will be called once per game and is the place to load + * all of your content. + * @name LoadContent + * @function + * @memberOf Game + */ +Game.prototype.LoadContent = function () { + "use strict"; + var self = this; + + if (self.preloading) { + // Create a new SpriteBatch, which can be used to draw textures. + self.spriteBatch = new SpriteBatch(self.GraphicsDevice); + + self.image = self.Content.LoadTexture2D("../../images/test_sprite.png"); + + self.preloading = false; + } + + if (self.Content.AllContentLoaded()) { + //texture, scale, sourceRect, position, isVisible, animationType, numberOfFrames, millisecondsPerFrame + self.sprite = new AnimatedSprite( + self.image, + new Vector2(0.5, 0.5), + new Rectangle(0, 0, 128, 128), + new Point(500, 200), + true, + AnimationTypes.Loop, + 14, + 100 + ); + + self.GraphicsDevice.canvas.addEventListener("click", self.GraphicsDevice.ToggleFullScreen.bind(self.GraphicsDevice)); + self.gameState = GameStates.Playing; + } +}; + +/** + * Allows the game to run logic such as updating the world, + * checking for collisions, gathering input, and playing audio. + * @name Update + * @function + * @memberOf Game + */ +Game.prototype.Update = function () { + "use strict"; + var self = this; + + //GraphicsDevice + if (Mouse.IsButtonClicked(Mouse.RightButton)) { + self.GraphicsDevice.ToggleFullPage(); + } + + //AnimatedSprite + if (Keyboard.IsKeyDown(Keys.left_arrow)) { + self.sprite.Position.X -= self.SPEED; + } + if (Keyboard.IsKeyDown(Keys.right_arrow)) { + self.sprite.Position.X += self.SPEED; + + } + if (Keyboard.IsKeyDown(Keys.up_arrow)) { + self.sprite.Position.Y -= self.SPEED; + + } + if (Keyboard.IsKeyDown(Keys.down_arrow)) { + self.sprite.Position.Y += self.SPEED; + + } + if (Keyboard.IsKeyPressed(Keys.a)) { + self.animTypeIndex += 1; + if (self.animTypeIndex > 2) { + self.animTypeIndex = 0; + } + self.sprite.AnimationType = self.animTypeIndex; + self.sprite.CurrentFrame = 0; + self.sprite.Forward = true; + } + if (Keyboard.IsKeyPressed(Keys.b)) { + if (self.showBounds) { + self.showBounds = false; + } else { + self.showBounds = true; + } + } + if (Keyboard.IsKeyPressed(Keys.h)) { + if (self.sprite.SpriteEffects === SpriteEffects.FlipHorizontally) { + self.sprite.SpriteEffects = SpriteEffects.None; + } else { + self.sprite.SpriteEffects = SpriteEffects.FlipHorizontally; + } + } + if (Keyboard.IsKeyPressed(Keys.v)) { + if (self.sprite.SpriteEffects === SpriteEffects.FlipVertically) { + self.sprite.SpriteEffects = SpriteEffects.None; + } else { + self.sprite.SpriteEffects = SpriteEffects.FlipVertically; + } + } + if (Keyboard.IsKeyPressed(Keys.s)) { + if (self.animStarted) { + self.sprite.StopAnimation(); + self.animStarted = false; + } else { + self.sprite.RunAnimation = true; + if (self.sprite.AnimationType === AnimationTypes.PlayOneTime) { + self.sprite.CurrentFrame = 0; + self.sprite.Forward = true; + } + self.sprite.StartAnimation(); + self.animStarted = true; + } + } + if (Keyboard.IsKeyPressed(Keys.m)) { + self.sprite.MillisecondsPerFrame += 20; + //It's compulsory to restart animation + self.sprite.StopAnimation(); + if (self.animStarted) { + self.sprite.StartAnimation(); + } + } + if (Keyboard.IsKeyPressed(Keys.l)) { + self.sprite.MillisecondsPerFrame -= 20; + if (self.sprite.MillisecondsPerFrame < 0) { + self.sprite.MillisecondsPerFrame = 0; + } + //It's compulsory to restart animation + self.sprite.StopAnimation(); + if (self.animStarted) { + self.sprite.StartAnimation(); + } + } + if (Keyboard.IsKeyPressed(Keys.add)) { + self.sprite.Scale.X += 0.1; + self.sprite.Scale.Y += 0.1; + if (self.sprite.Scale.X > 1.1 || self.sprite.Scale.Y > 1.1) { + self.sprite.Scale.X = 1.1; + self.sprite.Scale.Y = 1.1; + } + } + if (Keyboard.IsKeyPressed(Keys.subtract)) { + self.sprite.Scale.X -= 0.1; + self.sprite.Scale.Y -= 0.1; + if (self.sprite.Scale.X < 0.1 || self.sprite.Scale.Y < 0.1) { + self.sprite.Scale.X = 0.1; + self.sprite.Scale.Y = 0.1; + } + } + + //Map bounds + if (self.sprite.Position.X < 335) { + self.sprite.Position.X = 335; + } + if (self.sprite.Position.X + self.sprite.Width() > 800) { + self.sprite.Position.X = 800 - self.sprite.Width(); + } + if (self.sprite.Position.Y < 0) { + self.sprite.Position.Y = 0; + } + if (self.sprite.Position.Y + self.sprite.Height() > 420) { + self.sprite.Position.Y = 420 - self.sprite.Height(); + } + + self.sprite.Rotation = Mouse.ScrollWheelValue * 10; +}; + +/** + * This is called when the game should draw itself. + * @name Draw + * @function + * @memberOf Game + */ +Game.prototype.Draw = function () { + "use strict"; + var self = this, + position = self.sprite.Position, + scale = self.sprite.Scale, + center = self.sprite.Center(); + + self.GraphicsDevice.Clear(); + + //GraphicsDevice + self.spriteBatch.DrawString(self.FONT_BIG, "------ GraphicsDevice ------", new Point(30, 20), self.BLACK, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "PreferredBackBufferWidth: " + self.GraphicsDevice.PreferredBackBufferWidth() + " pixels", new Point(30, 45), self.BLACK, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "PreferredBackBufferHeight: " + self.GraphicsDevice.PreferredBackBufferHeight() + " pixels", new Point(30, 70), self.BLACK, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Is canvas in full page mode? " + self.GraphicsDevice.IsFullPage(), new Point(30, 95), self.BLACK, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Is canvas in full screen mode: " + self.GraphicsDevice.IsFullScreen(), new Point(30, 120), self.BLACK, Vector2.One()); + + self.spriteBatch.DrawString(self.FONT_BIG, "------ AnimatedSprite ------", new Point(30, 160), self.BLACK, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "X: " + position.X.toFixed(2) + " Y: " + position.Y.toFixed(2), new Point(30, 185), self.BLACK, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Scale (width): " + scale.X.toFixed(2) + " Scale (height): " + scale.Y.toFixed(2), new Point(30, 210), self.BLACK, Vector2.One()); + switch (self.sprite.SpriteEffects) { + case SpriteEffects.None: + self.spriteBatch.DrawString(self.FONT_LITTLE, "Sprite effects: None", new Point(30, 235), self.BLACK, Vector2.One()); + break; + case SpriteEffects.FlipHorizontally: + self.spriteBatch.DrawString(self.FONT_LITTLE, "Sprite effects: FlipHorizontally", new Point(30, 235), self.BLACK, Vector2.One()); + break; + case SpriteEffects.FlipVertically: + self.spriteBatch.DrawString(self.FONT_LITTLE, "Sprite effects: FlipVertically", new Point(30, 235), self.BLACK, Vector2.One()); + break; + } + self.spriteBatch.DrawString(self.FONT_LITTLE, "Rotation: " + self.sprite.Rotation, new Point(30, 260), self.BLACK, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Top: " + self.sprite.Top().toFixed(2), new Point(30, 285), self.BLACK, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Bottom: " + self.sprite.Bottom().toFixed(2), new Point(30, 310), self.BLACK, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Left: " + self.sprite.Left().toFixed(2), new Point(30, 335), self.BLACK, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Right: " + self.sprite.Right().toFixed(2), new Point(30, 360), self.BLACK, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Half width: " + self.sprite.HalfWidth().toFixed(2), new Point(30, 385), self.BLACK, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Half height: " + self.sprite.HalfHeight().toFixed(2), new Point(30, 410), self.BLACK, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Center X: " + center.X.toFixed(2) + " Center Y: " + center.Y.toFixed(2), new Point(30, 435), self.BLACK, Vector2.One()); + switch (self.sprite.AnimationType) { + case AnimationTypes.Loop: + self.spriteBatch.DrawString(self.FONT_LITTLE, "Animation type: Loop", new Point(30, 460), self.BLACK, Vector2.One()); + break; + case AnimationTypes.PingPongLoop: + self.spriteBatch.DrawString(self.FONT_LITTLE, "Animation type: PingPongLoop", new Point(30, 460), self.BLACK, Vector2.One()); + break; + case AnimationTypes.PlayOneTime: + self.spriteBatch.DrawString(self.FONT_LITTLE, "Animation type: PlayOneTime", new Point(30, 460), self.BLACK, Vector2.One()); + break; + } + self.spriteBatch.DrawString(self.FONT_LITTLE, "Milliseconds per frame: " + self.sprite.MillisecondsPerFrame, new Point(30, 485), self.BLACK, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Current frame / Number of frames: " + self.sprite.CurrentFrame + "/" + self.sprite.NumberOfFrames, new Point(30, 510), self.BLACK, Vector2.One()); + + //Draw the separating lines + self.spriteBatch.DrawSegment(new Segment(new Point(335, 0), new Point(335, 600)), "3", self.BLACK); + self.spriteBatch.DrawSegment(new Segment(new Point(335, 420), new Point(800, 420)), "3", self.BLACK); + + //Instructions + self.spriteBatch.DrawString(self.FONT_LITTLE, "Left click to enter full screen", new Point(347, 440), self.BLUE, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Press B to show bounds", new Point(347, 465), self.BLUE, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Press arrow keys to move it", new Point(347, 490), self.BLUE, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Press M to increase milliseconds", new Point(347, 515), self.BLUE, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Press L to decrease milliseconds", new Point(347, 540), self.BLUE, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Press S to start/stop anim.", new Point(347, 565), self.BLUE, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Right click to enter full page", new Point(592, 440), self.BLUE, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Press A to change anim. type", new Point(592, 465), self.BLUE, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Press H to flip horizontally", new Point(592, 490), self.BLUE, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Press V to flip vertically", new Point(592, 515), self.BLUE, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "+/- to incr./decr. scale", new Point(592, 540), self.BLUE, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Mouse wheel to rotate sprite", new Point(592, 565), self.BLUE, Vector2.One()); + + //The sprite + self.spriteBatch.Draw( + self.sprite.Texture, + self.sprite.Position, + self.sprite.SourceRect, + self.sprite.Rotation, + self.sprite.Scale, + self.sprite.SpriteEffects + ); + + //Bounds + if (self.showBounds) { + self.spriteBatch.DrawRectangle(self.sprite.Bounds(), "3", self.GREEN); + } +}; + +/** + * Call this method to initialize the game, begin running the game loop, and + * start processing events for the game. + * @name Run + * @function + * @memberOf Game + */ +Game.prototype.Run = function () { + "use strict"; + /*globals requestAnimationFrame*/ + var self = this; + + //Call the game loop + requestAnimationFrame(self.Run.bind(self), self.GraphicsDevice.canvas); + + //Choose the method to run according to the game state + switch (self.gameState) { + case GameStates.Initializing: + self.Initialize(); + break; + case GameStates.Loading: + self.LoadContent(); + break; + case GameStates.Playing: + self.Update(); + self.Draw(); + break; + } +}; \ No newline at end of file diff --git a/src/JS/Unit_Testing/Test_Mouse_Keyboard.js b/src/JS/Unit_Testing/Test_Mouse_Keyboard.js new file mode 100644 index 0000000..1b660c0 --- /dev/null +++ b/src/JS/Unit_Testing/Test_Mouse_Keyboard.js @@ -0,0 +1,183 @@ +/** + * Provides basic graphics device initialization, game logic, and rendering code. + */ +function Game() { + "use strict"; + /*globals ContentManager, GraphicsDevice, document, SpriteBatch, GameStates*/ + this.Content = new ContentManager(); + this.GraphicsDevice = new GraphicsDevice(document); + this.spriteBatch = null; + this.gameState = GameStates.Initializing; + this.preloading = true; +} + +/** + * Allows the game to perform any initialization it needs to before starting to run. + * This is where it can query for any required services and load any non-graphic + * related content. + * @name Initialize + * @function + * @memberOf Game + */ +Game.prototype.Initialize = function () { + "use strict"; + var self = this; + + // TODO: Add your initialization logic here + + self.gameState = GameStates.Loading; +}; + +/** + * LoadContent will be called once per game and is the place to load + * all of your content. + * @name LoadContent + * @function + * @memberOf Game + */ +Game.prototype.LoadContent = function () { + "use strict"; + var self = this; + + if (self.preloading) { + // Create a new SpriteBatch, which can be used to draw textures. + self.spriteBatch = new SpriteBatch(self.GraphicsDevice); + + // TODO: use this.Content.Load... to load your game content here + + self.preloading = false; + } + + if (self.Content.AllContentLoaded) { + // TODO: create the objects that will use the content previously loaded + + self.gameState = GameStates.Playing; + } +}; + +/** + * Allows the game to run logic such as updating the world, + * checking for collisions, gathering input, and playing audio. + * @name Update + * @function + * @memberOf Game + */ +Game.prototype.Update = function () { + "use strict"; + var self = this; + + // TODO: Add your update logic here +}; + +/** + * This is called when the game should draw itself. + * @name Draw + * @function + * @memberOf Game + */ +Game.prototype.Draw = function () { + "use strict"; + var self = this; + + self.GraphicsDevice.Clear(); + + // TODO: Add your drawing code here + self.GraphicsDevice.Clear(); + + self.spriteBatch.DrawString( + "normal bold 18px Helvetica", + "------ MOUSE ------", + new Point(30, 20), + "#000000", + Vector2.One() + ); + self.spriteBatch.DrawString( + "normal bold 16px Helvetica", + "X: "+Mouse.X+" Y: "+Mouse.Y, + new Point(30, 50), + "#000000", + Vector2.One() + ); + self.spriteBatch.DrawString( + "normal bold 16px Helvetica", + "Wheel: "+Mouse.ScrollWheelValue, + new Point(30, 80), + "#000000", + Vector2.One() + ); + self.spriteBatch.DrawString( + "normal bold 16px Helvetica", + "LeftButtonPressed: "+Mouse.LeftButtonPressed, + new Point(30, 110), + "#000000", + Vector2.One() + ); + self.spriteBatch.DrawString( + "normal bold 16px Helvetica", + "RightButtonPressed: "+Mouse.RightButtonPressed, + new Point(30, 140), + "#000000", + Vector2.One() + ); + self.spriteBatch.DrawString( + "normal bold 16px Helvetica", + "MiddleButtonPressed: "+Mouse.MiddleButtonPressed, + new Point(30, 170), + "#000000", + Vector2.One() + ); + + self.spriteBatch.DrawString( + "normal bold 18px Helvetica", + "------ KEYBOARD ------", + new Point(30, 230), + "#000000", + Vector2.One() + ); + + self.spriteBatch.DrawString( + "normal bold 16px Helvetica", + "Teclas que están siendo pulsadas: "+Keyboard.keyDownList, + new Point(30, 260), + "#000000", + Vector2.One() + ); + + self.spriteBatch.DrawString( + "normal bold 16px Helvetica", + "Teclas pulsadas: "+Keyboard.keyUpList, + new Point(30, 290), + "#000000", + Vector2.One() + ); +}; + +/** + * Call this method to initialize the game, begin running the game loop, and + * start processing events for the game. + * @name Run + * @function + * @memberOf Game + */ +Game.prototype.Run = function () { + "use strict"; + /*globals requestAnimationFrame*/ + var self = this; + + //Call the game loop + requestAnimationFrame(self.Run.bind(self), self.GraphicsDevice.canvas); + + //Choose the method to run according to the game state + switch (self.gameState) { + case GameStates.Initializing: + self.Initialize(); + break; + case GameStates.Loading: + self.LoadContent(); + break; + case GameStates.Playing: + self.Update(); + self.Draw(); + break; + } +}; \ No newline at end of file diff --git a/src/JS/Unit_Testing/Test_Point_Vector2_Rectangle.js b/src/JS/Unit_Testing/Test_Point_Vector2_Rectangle.js new file mode 100644 index 0000000..6ba71e6 --- /dev/null +++ b/src/JS/Unit_Testing/Test_Point_Vector2_Rectangle.js @@ -0,0 +1,377 @@ +/** + * Provides basic graphics device initialization, game logic, and rendering code. + */ +function Game() { + "use strict"; + /*globals ContentManager, GraphicsDevice, document, SpriteBatch, GameStates, Point, Vector2, Rectangle, Keyboard, Keys, Mouse, Segment*/ + this.Content = new ContentManager(); + this.GraphicsDevice = new GraphicsDevice(document); + this.spriteBatch = null; + this.gameState = GameStates.Initializing; + this.preloading = true; + + //Constants + this.FONT_LITTLE = "normal bold 15px Helvetica"; + this.FONT_BIG = "normal bold 18px Helvetica"; + this.BLACK = "#000000"; + this.GREEN = "#00FF00"; + this.RED = "#FF0000"; + this.BLUE = "#0000FF"; + this.RECT_VEL = 3; + this.RECT_INFLATE_VALUE = 2; + + /***** TEST VARIABLES *****/ + this.testingRectangle = false; + //Point + this.pointZero_OK = false; + this.pointOne_OK = false; + this.pointsAreEqual = false; + this.pointsAreDifferent = false; + //Vector2 + this.vectorZero_OK = false; + this.vectorOne_OK = false; + this.vectorAdd_OK = false; + this.vectorSubstract_OK = false; + this.vectorDivide_OK = false; + this.vectorMultiply_OK = false; + this.vectorDistance_OK = false; + this.vectorLength_OK = false; + this.vectorsAreEqual = false; + this.vectorsAreDifferent = false; + //Rectangle + this.r1 = null; + this.r2 = null; + +} + +/** + * Allows the game to perform any initialization it needs to before starting to run. + * This is where it can query for any required services and load any non-graphic + * related content. + * @name Initialize + * @function + * @memberOf Game + */ +Game.prototype.Initialize = function () { + "use strict"; + var self = this; + + self.r1 = new Rectangle(430, 315, 20, 40); + self.r2 = new Rectangle(690, 30, 80, 50); + + self.gameState = GameStates.Loading; +}; + +/** + * LoadContent will be called once per game and is the place to load + * all of your content. + * @name LoadContent + * @function + * @memberOf Game + */ +Game.prototype.LoadContent = function () { + "use strict"; + var self = this; + + if (self.preloading) { + // Create a new SpriteBatch, which can be used to draw textures. + self.spriteBatch = new SpriteBatch(self.GraphicsDevice); + + // TODO: use this.Content.Load... to load your game content here + + self.preloading = false; + } + + if (self.Content.AllContentLoaded) { + // TODO: create the objects that will use the content previously loaded + + self.gameState = GameStates.Playing; + } +}; + +/** + * Allows the game to run logic such as updating the world, + * checking for collisions, gathering input, and playing audio. + * @name Update + * @function + * @memberOf Game + */ +Game.prototype.Update = function () { + "use strict"; + var self = this, + p1 = null, + p2 = null, + v1 = null, + v2 = null; + + if (!self.testingRectangle && Keyboard.IsKeyPressed(Keys.r)) { + self.testingRectangle = true; + } + + if (self.testingRectangle) { + //Rectangle + if (Keyboard.IsKeyDown(Keys.a) || Keyboard.IsKeyDown(Keys.left_arrow)) { + self.r1.X -= self.RECT_VEL; + } + if (Keyboard.IsKeyDown(Keys.d) || Keyboard.IsKeyDown(Keys.right_arrow)) { + self.r1.X += self.RECT_VEL; + + } + if (Keyboard.IsKeyDown(Keys.w) || Keyboard.IsKeyDown(Keys.up_arrow)) { + self.r1.Y -= self.RECT_VEL; + + } + if (Keyboard.IsKeyDown(Keys.s) || Keyboard.IsKeyDown(Keys.down_arrow)) { + self.r1.Y += self.RECT_VEL; + + } + if (Keyboard.IsKeyDown(Keys.add)) { + self.r1.Inflate(self.RECT_INFLATE_VALUE, self.RECT_INFLATE_VALUE); + if (self.r1.Width > 400) { + self.r1.Width = 400; + } + if (self.r1.Height > 600) { + self.r1.Height = 600; + } + } + if (Keyboard.IsKeyDown(Keys.subtract)) { + self.r1.Inflate(-self.RECT_INFLATE_VALUE, -self.RECT_INFLATE_VALUE); + } + + //Map bounds + if (self.r1.X < 400) { + self.r1.X = 400; + } + if (self.r1.X + self.r1.Width > 800) { + self.r1.X = 800 - self.r1.Width; + } + if (self.r1.Y < 0) { + self.r1.Y = 0; + } + if (self.r1.Y + self.r1.Height > 600) { + self.r1.Y = 600 - self.r1.Height; + } + + } else { + + //Point + p1 = Point.Zero(); + p2 = Point.One(); + if (p1.X === 0 && p1.Y === 0) { + self.pointZero_OK = true; + } + if (p2.X === 1 && p2.Y === 1) { + self.pointOne_OK = true; + } + p2 = new Point(25, 150); + self.pointsAreDifferent = !Point.Equals(p1, p2); + p2 = new Point(0, 0); + self.pointsAreEqual = Point.Equals(p1, p2); + + //Vector2 + v1 = Vector2.Zero(); + v2 = Vector2.One(); + if (v1.X === 0 && v1.Y === 0) { + self.vectorZero_OK = true; + } + if (v2.X === 1 && v2.Y === 1) { + self.vectorOne_OK = true; + } + v1 = new Vector2(100, 150); + self.vectorsAreDifferent = !Vector2.Equals(v1, v2); + v2 = new Vector2(100, 150); + self.vectorsAreEqual = Vector2.Equals(v1, v2); + v2 = new Vector2(20, 25); + self.vectorAdd_OK = Vector2.Equals(Vector2.Add(v1, v2), new Vector2(120, 175)); + self.vectorSubstract_OK = Vector2.Equals(Vector2.Substract(v1, v2), new Vector2(80, 125)); + self.vectorDivide_OK = Vector2.Equals(Vector2.Divide(v1, v2), new Vector2(5, 6)); + self.vectorMultiply_OK = Vector2.Equals(Vector2.Multiply(v1, v2), new Vector2(2000, 3750)); + self.vectorDistance_OK = Math.floor(Vector2.Distance(v1, v2)) === 148; + self.vectorLength_OK = Math.floor(v2.Length()) === 32; + } +}; + +/** + * This is called when the game should draw itself. + * @name Draw + * @function + * @memberOf Game + */ +Game.prototype.Draw = function () { + "use strict"; + var self = this, + location = self.r1.Location(), + center = self.r1.Center(), + collision = (self.r2.Intersects(self.r1) !== false); + + self.GraphicsDevice.Clear(); + + if (self.testingRectangle) { + + //Rectangle data + self.spriteBatch.DrawString(self.FONT_BIG, "------ RECTANGLE ------", new Point(30, 20), self.BLACK, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "X: " + location.X + " Y: " + location.Y, new Point(30, 50), self.BLACK, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Top: " + self.r1.Top(), new Point(30, 80), self.BLACK, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Bottom: " + self.r1.Bottom(), new Point(30, 110), self.BLACK, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Left: " + self.r1.Left(), new Point(30, 140), self.BLACK, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Right: " + self.r1.Right(), new Point(30, 170), self.BLACK, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Half width: " + self.r1.HalfWidth(), new Point(30, 200), self.BLACK, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Half height: " + self.r1.HalfHeight(), new Point(30, 230), self.BLACK, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Center X: " + center.X + " Center Y: " + center.Y, new Point(30, 260), self.BLACK, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Is empty? (width and height = 0): " + self.r1.IsEmpty(), new Point(30, 290), self.BLACK, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Red rectangle contains the upper-left vertex", new Point(30, 320), self.BLACK, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "of the green one?: " + self.r2.Contains(self.r1.Location()), new Point(30, 340), self.BLACK, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Is there a collision between the rectangles?: " + collision, new Point(30, 370), self.BLACK, Vector2.One()); + + self.spriteBatch.DrawString(self.FONT_BIG, "Use A, W, S, D or arrow keys to move", new Point(30, 450), self.BLUE, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_BIG, "the green rectangle", new Point(30, 470), self.BLUE, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_BIG, "Use + key to inflate the rectangle", new Point(30, 510), self.BLUE, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_BIG, "Use - key to deflate the rectangle", new Point(30, 540), self.BLUE, Vector2.One()); + + //Draw the separating line + self.spriteBatch.DrawSegment(new Segment(new Point(400, 0), new Point(400, 600)), "3", self.BLACK); + + //Rectangle + self.spriteBatch.DrawRectangle(self.r1, "3", self.GREEN); + self.spriteBatch.DrawRectangle(self.r2, "3", self.RED); + + } else { + + //Point + self.spriteBatch.DrawString(self.FONT_BIG, "------ POINT ------", new Point(30, 20), self.BLACK, Vector2.One()); + + self.spriteBatch.DrawString(self.FONT_LITTLE, "Testing static method Point.Zero()...", new Point(30, 50), self.BLACK, Vector2.One()); + if (self.pointZero_OK) { + self.spriteBatch.DrawString(self.FONT_BIG, "OK", new Point(300, 50), self.GREEN, Vector2.One()); + } else { + self.spriteBatch.DrawString(self.FONT_BIG, "ERROR", new Point(300, 50), self.RED, Vector2.One()); + } + + self.spriteBatch.DrawString(self.FONT_LITTLE, "Testing static method Point.One()...", new Point(30, 80), self.BLACK, Vector2.One()); + if (self.pointOne_OK) { + self.spriteBatch.DrawString(self.FONT_BIG, "OK", new Point(300, 80), self.GREEN, Vector2.One()); + } else { + self.spriteBatch.DrawString(self.FONT_BIG, "ERROR", new Point(300, 80), self.RED, Vector2.One()); + } + + self.spriteBatch.DrawString(self.FONT_LITTLE, "Testing static method Point.Equals(). Are p1(0,0) and p2(25,150) different?", new Point(30, 110), self.BLACK, Vector2.One()); + if (self.pointsAreDifferent) { + self.spriteBatch.DrawString(self.FONT_BIG, "YES", new Point(570, 110), self.GREEN, Vector2.One()); + } else { + self.spriteBatch.DrawString(self.FONT_BIG, "NO", new Point(570, 110), self.RED, Vector2.One()); + } + + self.spriteBatch.DrawString(self.FONT_LITTLE, "Testing static method Point.Equals(). Are p1(0,0) and p2(0,0) equals?", new Point(30, 140), self.BLACK, Vector2.One()); + if (self.pointsAreEqual) { + self.spriteBatch.DrawString(self.FONT_BIG, "YES", new Point(570, 140), self.GREEN, Vector2.One()); + } else { + self.spriteBatch.DrawString(self.FONT_BIG, "NO", new Point(570, 140), self.RED, Vector2.One()); + } + + //Vector2 + self.spriteBatch.DrawString(self.FONT_BIG, "----- VECTOR2 -----", new Point(30, 200), self.BLACK, Vector2.One()); + + self.spriteBatch.DrawString(self.FONT_LITTLE, "Testing static method Vector2.Zero()...", new Point(30, 230), self.BLACK, Vector2.One()); + if (self.vectorZero_OK) { + self.spriteBatch.DrawString(self.FONT_BIG, "OK", new Point(320, 230), self.GREEN, Vector2.One()); + } else { + self.spriteBatch.DrawString(self.FONT_BIG, "ERROR", new Point(320, 230), self.RED, Vector2.One()); + } + + self.spriteBatch.DrawString(self.FONT_LITTLE, "Testing static method Vector2.One()...", new Point(30, 260), self.BLACK, Vector2.One()); + if (self.vectorOne_OK) { + self.spriteBatch.DrawString(self.FONT_BIG, "OK", new Point(320, 260), self.GREEN, Vector2.One()); + } else { + self.spriteBatch.DrawString(self.FONT_BIG, "ERROR", new Point(320, 260), self.RED, Vector2.One()); + } + + self.spriteBatch.DrawString(self.FONT_LITTLE, "Testing static method Vector2.Equals(). Are v1(100,150) and v2(1,1) different?", new Point(30, 290), self.BLACK, Vector2.One()); + if (self.vectorsAreDifferent) { + self.spriteBatch.DrawString(self.FONT_BIG, "YES", new Point(600, 290), self.GREEN, Vector2.One()); + } else { + self.spriteBatch.DrawString(self.FONT_BIG, "NO", new Point(600, 290), self.RED, Vector2.One()); + } + + self.spriteBatch.DrawString(self.FONT_LITTLE, "Testing static method Vector2.Equals(). Are v1(100,150) and v2(100,150) equals?", new Point(30, 320), self.BLACK, Vector2.One()); + if (self.vectorsAreEqual) { + self.spriteBatch.DrawString(self.FONT_BIG, "YES", new Point(600, 320), self.GREEN, Vector2.One()); + } else { + self.spriteBatch.DrawString(self.FONT_BIG, "NO", new Point(600, 320), self.RED, Vector2.One()); + } + + self.spriteBatch.DrawString(self.FONT_LITTLE, "Testing static method Vector2.Add(). v1(100,150) + v2(20,25) = v(120,175)?", new Point(30, 350), self.BLACK, Vector2.One()); + if (self.vectorAdd_OK) { + self.spriteBatch.DrawString(self.FONT_BIG, "YES", new Point(600, 350), self.GREEN, Vector2.One()); + } else { + self.spriteBatch.DrawString(self.FONT_BIG, "NO", new Point(600, 350), self.RED, Vector2.One()); + } + + self.spriteBatch.DrawString(self.FONT_LITTLE, "Testing static method Vector2.Substract(). v1(100,150) - v2(20,25) = v(80,125)?", new Point(30, 380), self.BLACK, Vector2.One()); + if (self.vectorSubstract_OK) { + self.spriteBatch.DrawString(self.FONT_BIG, "YES", new Point(600, 380), self.GREEN, Vector2.One()); + } else { + self.spriteBatch.DrawString(self.FONT_BIG, "NO", new Point(600, 380), self.RED, Vector2.One()); + } + + self.spriteBatch.DrawString(self.FONT_LITTLE, "Testing static method Vector2.Divide(). v1(100,150) / v2(20,25) = v(5,6)?", new Point(30, 410), self.BLACK, Vector2.One()); + if (self.vectorDivide_OK) { + self.spriteBatch.DrawString(self.FONT_BIG, "YES", new Point(600, 410), self.GREEN, Vector2.One()); + } else { + self.spriteBatch.DrawString(self.FONT_BIG, "NO", new Point(600, 410), self.RED, Vector2.One()); + } + + self.spriteBatch.DrawString(self.FONT_LITTLE, "Testing static method Vector2.Multiply(). v1(100,150) * v2(20,25) = v(2000,3750)?", new Point(30, 440), self.BLACK, Vector2.One()); + if (self.vectorMultiply_OK) { + self.spriteBatch.DrawString(self.FONT_BIG, "YES", new Point(600, 440), self.GREEN, Vector2.One()); + } else { + self.spriteBatch.DrawString(self.FONT_BIG, "NO", new Point(600, 440), self.RED, Vector2.One()); + } + + self.spriteBatch.DrawString(self.FONT_LITTLE, "Testing static method Vector2.Distance() between v1(100,150) and v2(20,25)...", new Point(30, 470), self.BLACK, Vector2.One()); + if (self.vectorMultiply_OK) { + self.spriteBatch.DrawString(self.FONT_BIG, "148", new Point(600, 470), self.GREEN, Vector2.One()); + } else { + self.spriteBatch.DrawString(self.FONT_BIG, "NOT 148", new Point(600, 470), self.RED, Vector2.One()); + } + + self.spriteBatch.DrawString(self.FONT_LITTLE, "Testing static method Vector2.Length() of v2(20,25)...", new Point(30, 500), self.BLACK, Vector2.One()); + if (self.vectorMultiply_OK) { + self.spriteBatch.DrawString(self.FONT_BIG, "32", new Point(600, 500), self.GREEN, Vector2.One()); + } else { + self.spriteBatch.DrawString(self.FONT_BIG, "NOT 32", new Point(600, 500), self.RED, Vector2.One()); + } + + self.spriteBatch.DrawString(self.FONT_BIG, "Press R to test Rectangle methods...", new Point(30, 550), self.BLUE, Vector2.One()); + } + +}; + +/** + * Call this method to initialize the game, begin running the game loop, and + * start processing events for the game. + * @name Run + * @function + * @memberOf Game + */ +Game.prototype.Run = function () { + "use strict"; + /*globals requestAnimationFrame*/ + var self = this; + + //Call the game loop + requestAnimationFrame(self.Run.bind(self), self.GraphicsDevice.canvas); + + //Choose the method to run according to the game state + switch (self.gameState) { + case GameStates.Initializing: + self.Initialize(); + break; + case GameStates.Loading: + self.LoadContent(); + break; + case GameStates.Playing: + self.Update(); + self.Draw(); + break; + } +}; \ No newline at end of file diff --git a/src/JS/Unit_Testing/Test_Song_SoundEffect.js b/src/JS/Unit_Testing/Test_Song_SoundEffect.js new file mode 100644 index 0000000..ae054f9 --- /dev/null +++ b/src/JS/Unit_Testing/Test_Song_SoundEffect.js @@ -0,0 +1,281 @@ +/** + * Provides basic graphics device initialization, game logic, and rendering code. + */ +function Game() { + "use strict"; + /*globals ContentManager, GraphicsDevice, document, SpriteBatch, GameStates, Point, Vector2, Rectangle, Keyboard, Keys, Mouse, Segment, SpriteEffects, Sprite, Texture2D, setTimeout*/ + this.Content = new ContentManager(); + this.GraphicsDevice = new GraphicsDevice(document); + this.spriteBatch = null; + this.gameState = GameStates.Initializing; + this.preloading = true; + + //Constants + this.FONT_LITTLE = "normal bold 15px Helvetica"; + this.FONT_BIG = "normal bold 18px Helvetica"; + this.BLACK = "#000000"; + this.GREEN = "#00FF00"; + this.RED = "#FF0000"; + this.BLUE = "#0000FF"; + + /***** TEST VARIABLES *****/ + //Song + this.song = null; + + //SoundEffects + this.vacaSound = null; + this.cerdoSound = null; + this.cerberoSound = null; + + //Images + this.vaca = null; + this.cerdo = null; + this.cerbero = null; + + //Sprites + this.vacaSprite = null; + this.cerdoSprite = null; + this.cerberoSprite = null; + + //Flags + this.playing = false; +} + +/** + * Allows the game to perform any initialization it needs to before starting to run. + * This is where it can query for any required services and load any non-graphic + * related content. + * @name Initialize + * @function + * @memberOf Game + */ +Game.prototype.Initialize = function () { + "use strict"; + var self = this; + + // TODO: Add your initialization logic here + + self.gameState = GameStates.Loading; +}; + +/** + * LoadContent will be called once per game and is the place to load + * all of your content. + * @name LoadContent + * @function + * @memberOf Game + */ +Game.prototype.LoadContent = function () { + "use strict"; + var self = this; + + if (self.preloading) { + // Create a new SpriteBatch, which can be used to draw textures. + self.spriteBatch = new SpriteBatch(self.GraphicsDevice); + + self.song = self.Content.LoadSong("../../sounds/test_song.mp3"); + self.vacaSound = self.Content.LoadSoundEffect("../../sounds/test_sound2.wav"); + self.cerdoSound = self.Content.LoadSoundEffect("../../sounds/test_sound3.wav"); + self.cerberoSound = self.Content.LoadSoundEffect("../../sounds/test_sound1.wav"); + self.vaca = self.Content.LoadTexture2D("../../images/vaca.jpg"); + self.cerdo = self.Content.LoadTexture2D("../../images/cerdo.png"); + self.cerbero = self.Content.LoadTexture2D("../../images/cerbero.jpg"); + + self.preloading = false; + } + + if (self.Content.AllContentLoaded()) { + + self.vacaSprite = new Sprite( + self.vaca, + new Vector2(0.75, 0.75), + new Rectangle(0, 0, self.vaca.Width(), self.vaca.Height()), + new Point(500, 30), + false + ); + + self.cerdoSprite = new Sprite( + self.cerdo, + new Vector2(0.70, 0.70), + new Rectangle(0, 0, self.cerdo.Width(), self.cerdo.Height()), + new Point(540, 210), + false + ); + + self.cerberoSprite = new Sprite( + self.cerbero, + new Vector2(0.75, 0.75), + new Rectangle(0, 0, self.cerbero.Width(), self.cerbero.Height()), + new Point(500, 380), + false + ); + + self.gameState = GameStates.Playing; + } +}; + +/** + * Allows the game to run logic such as updating the world, + * checking for collisions, gathering input, and playing audio. + * @name Update + * @function + * @memberOf Game + */ +Game.prototype.Update = function () { + "use strict"; + var self = this; + + //Song + if (Keyboard.IsKeyPressed(Keys.p)) { + if (self.playing) { + self.song.Pause(); + self.playing = false; + } else { + self.song.Play(); + self.playing = true; + } + } + if (Keyboard.IsKeyPressed(Keys.s)) { + self.song.Stop(); + self.playing = false; + } + if (Keyboard.IsKeyPressed(Keys.m)) { + if (self.song.IsMuted()) { + self.song.IsMuted(false); + } else { + self.song.IsMuted(true); + } + } + if (Keyboard.IsKeyPressed(Keys.l)) { + if (self.song.IsRepeating()) { + self.song.IsRepeating(false); + } else { + self.song.IsRepeating(true); + } + } + if (Keyboard.IsKeyPressed(Keys.add)) { + self.song.Volume(self.song.Volume() + 0.05); + } + if (Keyboard.IsKeyPressed(Keys.subtract)) { + self.song.Volume(self.song.Volume() - 0.05); + } + + //Sounds + if (Keyboard.IsKeyPressed(Keys.num1) || Keyboard.IsKeyPressed(Keys.numpad_1)) { + self.vacaSound.Play(); + self.vacaSprite.IsVisible = true; + setTimeout(function () { self.vacaSprite.IsVisible = false; }, self.vacaSound.Duration() * 1000); + } + if (Keyboard.IsKeyPressed(Keys.num2) || Keyboard.IsKeyPressed(Keys.numpad_2)) { + self.cerdoSound.Play(); + self.cerdoSprite.IsVisible = true; + setTimeout(function () { self.cerdoSprite.IsVisible = false; }, self.cerdoSound.Duration() * 1000); + } + if (Keyboard.IsKeyPressed(Keys.num3) || Keyboard.IsKeyPressed(Keys.numpad_3)) { + self.cerberoSound.Play(); + self.cerberoSprite.IsVisible = true; + setTimeout(function () { self.cerberoSprite.IsVisible = false; }, self.cerberoSound.Duration() * 1000); + } +}; + +/** + * This is called when the game should draw itself. + * @name Draw + * @function + * @memberOf Game + */ +Game.prototype.Draw = function () { + "use strict"; + var self = this; + + self.GraphicsDevice.Clear(); + + //Song attributes + self.spriteBatch.DrawString(self.FONT_BIG, "------ SONG ------", new Point(30, 20), self.BLACK, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Duration (in seconds): " + self.song.Duration(), new Point(30, 50), self.BLACK, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Is muted? " + self.song.IsMuted(), new Point(30, 80), self.BLACK, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Play in loop? " + self.song.IsRepeating(), new Point(30, 110), self.BLACK, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Current time (in seconds): " + self.song.PlayPosition(), new Point(30, 140), self.BLACK, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_LITTLE, "Volume: " + (Math.round(self.song.Volume() * 100) / 100), new Point(30, 170), self.BLACK, Vector2.One()); + + self.spriteBatch.DrawString(self.FONT_BIG, "Press M to mute the song", new Point(30, 350), self.BLUE, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_BIG, "Press L to activate loop", new Point(30, 390), self.BLUE, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_BIG, "Press + to increase volume", new Point(30, 430), self.BLUE, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_BIG, "Press - to decrease volume", new Point(30, 470), self.BLUE, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_BIG, "Press P to play/pause the song", new Point(30, 510), self.BLUE, Vector2.One()); + self.spriteBatch.DrawString(self.FONT_BIG, "Press S to stop the song", new Point(30, 550), self.BLUE, Vector2.One()); + + //Draw the separating line + self.spriteBatch.DrawSegment(new Segment(new Point(400, 0), new Point(400, 600)), "3", self.BLACK); + + //Draw the images + if (self.vacaSprite.IsVisible) { + self.spriteBatch.Draw( + self.vacaSprite.Texture, + self.vacaSprite.Position, + self.vacaSprite.SourceRect, + self.vacaSprite.Rotation, + self.vacaSprite.Scale, + SpriteEffects.None + ); + } else { + self.spriteBatch.DrawString(self.FONT_BIG, "Press 1 to play sound effect 1", new Point(470, 60), self.BLUE, Vector2.One()); + } + + if (self.cerdoSprite.IsVisible) { + self.spriteBatch.Draw( + self.cerdoSprite.Texture, + self.cerdoSprite.Position, + self.cerdoSprite.SourceRect, + self.cerdoSprite.Rotation, + self.cerdoSprite.Scale, + SpriteEffects.None + ); + } else { + self.spriteBatch.DrawString(self.FONT_BIG, "Press 2 to play sound effect 2", new Point(470, 260), self.BLUE, Vector2.One()); + } + + if (self.cerberoSprite.IsVisible) { + self.spriteBatch.Draw( + self.cerberoSprite.Texture, + self.cerberoSprite.Position, + self.cerberoSprite.SourceRect, + self.cerberoSprite.Rotation, + self.cerberoSprite.Scale, + SpriteEffects.None + ); + } else { + self.spriteBatch.DrawString(self.FONT_BIG, "Press 3 to play sound effect 3", new Point(470, 460), self.BLUE, Vector2.One()); + } + +}; + +/** + * Call this method to initialize the game, begin running the game loop, and + * start processing events for the game. + * @name Run + * @function + * @memberOf Game + */ +Game.prototype.Run = function () { + "use strict"; + /*globals requestAnimationFrame*/ + var self = this; + + //Call the game loop + requestAnimationFrame(self.Run.bind(self), self.GraphicsDevice.canvas); + + //Choose the method to run according to the game state + switch (self.gameState) { + case GameStates.Initializing: + self.Initialize(); + break; + case GameStates.Loading: + self.LoadContent(); + break; + case GameStates.Playing: + self.Update(); + self.Draw(); + break; + } +}; \ No newline at end of file diff --git a/src/JS/XNA_Classes/ContentManager.js b/src/JS/XNA_Classes/ContentManager.js new file mode 100644 index 0000000..5ddc2e6 --- /dev/null +++ b/src/JS/XNA_Classes/ContentManager.js @@ -0,0 +1,108 @@ +/** + * The ContentManager loads sound and images of the game into memory. + * @constructor + */ +function ContentManager() { + "use strict"; + this.assetsToLoad = []; + this.assetsLoaded = 0; + this.allLoaded = false; +} + + +/** + * Function called when a content was loaded in memory. + * @name loadHandler + * @function + * @private + * @memberOf ContentManager + */ +ContentManager.prototype.loadHandler = function () { + "use strict"; + var self = this, + len = self.assetsToLoad.length, + i; + + self.assetsLoaded += 1; + + //If all contents were loaded then remove listeners and reset variables + if (self.assetsLoaded === len) { + + //Remove the load handlers + for (i = 0; i < len; i += 1) { + self.assetsToLoad[i].removeEventListener("load", self.loadHandler.bind(self), false); + } + + self.allLoaded = true; + //self.assetsToLoad.splice(0, len); + //self.assetsLoaded = 0; + } +}; + +/** + * Loads an image and return a Texture2D instance. + * @name LoadTexture2D + * @function + * @param {String} src - The path to the image. + * @memberOf ContentManager + */ +ContentManager.prototype.LoadTexture2D = function (src) { + "use strict"; + /*global Texture2D*/ + var self = this, + texture = new Texture2D(src); + + //Add load handler + texture.Image.addEventListener("load", self.loadHandler.bind(self), false); + self.assetsToLoad.push(texture.Image); + return texture; +}; + +/** + * Loads a song and return a Song instance. + * @name LoadSong + * @function + * @param {String} src - The path to the song. + * @memberOf ContentManager + */ +ContentManager.prototype.LoadSong = function (src) { + "use strict"; + /*global Song*/ + var self = this, + song = new Song(src); + + //Add load handler + song.Audio.addEventListener("loadedmetadata", self.loadHandler.bind(self), false); + self.assetsToLoad.push(song.Audio); + return song; +}; + +/** + * Loads a sound effect and return a SoundEffect instance. + * @name LoadSoundEffect + * @function + * @param {String} src - The path to the sound effect. + * @memberOf ContentManager + */ +ContentManager.prototype.LoadSoundEffect = function (src) { + "use strict"; + /*global SoundEffect*/ + var self = this, + soundEffect = new SoundEffect(src); + + //Add load handler + soundEffect.Audio.addEventListener("loadedmetadata", self.loadHandler.bind(self), false); + self.assetsToLoad.push(soundEffect.Audio); + return soundEffect; +}; + +/** + * Check if all contents were loaded or not. + * @name AllContentLoaded + * @function + * @memberOf ContentManager + */ +ContentManager.prototype.AllContentLoaded = function () { + "use strict"; + return this.allLoaded; +}; \ No newline at end of file diff --git a/src/JS/XNA_Classes/Game.js b/src/JS/XNA_Classes/Game.js new file mode 100644 index 0000000..2f6712b --- /dev/null +++ b/src/JS/XNA_Classes/Game.js @@ -0,0 +1,115 @@ +/** + * Provides basic graphics device initialization, game logic, and rendering code. + */ +function Game() { + "use strict"; + /*global ContentManager, GraphicsDevice, document, SpriteBatch, GameStates*/ + this.Content = new ContentManager(); + this.GraphicsDevice = new GraphicsDevice(document); + this.spriteBatch = null; + this.gameState = GameStates.Initializing; + this.preloading = true; +} + +/** + * Allows the game to perform any initialization it needs to before starting to run. + * This is where it can query for any required services and load any non-graphic + * related content. + * @name Initialize + * @function + * @memberOf Game + */ +Game.prototype.Initialize = function () { + "use strict"; + var self = this; + + // TODO: Add your initialization logic here + + self.gameState = GameStates.Loading; +}; + +/** + * LoadContent will be called once per game and is the place to load + * all of your content. + * @name LoadContent + * @function + * @memberOf Game + */ +Game.prototype.LoadContent = function () { + "use strict"; + var self = this; + + if (self.preloading) { + // Create a new SpriteBatch, which can be used to draw textures. + self.spriteBatch = new SpriteBatch(self.GraphicsDevice); + + // TODO: use self.Content.Load... to load your game content here + + self.preloading = false; + } + + if (self.Content.AllContentLoaded()) { + // TODO: create the objects that will use the content previously loaded, like sprites or sounds + + self.gameState = GameStates.Playing; + } +}; + +/** + * Allows the game to run logic such as updating the world, + * checking for collisions, gathering input, and playing audio. + * @name Update + * @function + * @memberOf Game + */ +Game.prototype.Update = function () { + "use strict"; + var self = this; + + // TODO: Add your update logic here +}; + +/** + * This is called when the game should draw itself. + * @name Draw + * @function + * @memberOf Game + */ +Game.prototype.Draw = function () { + "use strict"; + var self = this; + + self.GraphicsDevice.Clear(); + + // TODO: Add your drawing code here +}; + +/** + * Call this method to initialize the game, begin running the game loop, and + * start processing events for the game. + * @name Run + * @function + * @memberOf Game + */ +Game.prototype.Run = function () { + "use strict"; + /*globals requestAnimationFrame*/ + var self = this; + + //Call the game loop + requestAnimationFrame(self.Run.bind(self), self.GraphicsDevice.canvas); + + //Choose the method to run according to the game state + switch (self.gameState) { + case GameStates.Initializing: + self.Initialize(); + break; + case GameStates.Loading: + self.LoadContent(); + break; + case GameStates.Playing: + self.Update(); + self.Draw(); + break; + } +}; \ No newline at end of file diff --git a/src/JS/XNA_Classes/GraphicsDevice.js b/src/JS/XNA_Classes/GraphicsDevice.js new file mode 100644 index 0000000..94cf401 --- /dev/null +++ b/src/JS/XNA_Classes/GraphicsDevice.js @@ -0,0 +1,172 @@ +/** + * Creates an instance of the canvas. Also handles the configuration of the canvas. + * @constructor + * @param {HTML} document - The descriptor of the HTML. + */ +function GraphicsDevice(document) { + "use strict"; + /*global Element*/ + this.canvas = document.querySelector("canvas"); +} + +/** + * Gets the preferred back-buffer height. + * @name PreferredBackBufferHeight + * @function + * @memberOf GraphicsDevice + */ +GraphicsDevice.prototype.PreferredBackBufferHeight = function () { + "use strict"; + return this.canvas.height; +}; + +/** + * Gets the preferred back-buffer width. + * @name PreferredBackBufferWidth + * @function + * @memberOf GraphicsDevice + */ +GraphicsDevice.prototype.PreferredBackBufferWidth = function () { + "use strict"; + return this.canvas.width; +}; + +/** + * Specifies the default minimum back-buffer height (600). + * @name DefaultBackBufferHeight + * @function + * @memberOf GraphicsDevice + * @static + */ +GraphicsDevice.prototype.DefaultBackBufferHeight = function () { + "use strict"; + return 600; +}; + +/** + * Specifies the default minimum back-buffer width (800). + * @name DefaultBackBufferWidth + * @function + * @memberOf GraphicsDevice + * @static + */ +GraphicsDevice.prototype.DefaultBackBufferWidth = function () { + "use strict"; + return 800; +}; + +/** + * Toggles between full page and windowed mode. + * @name ToggleFullPage + * @function + * @memberOf GraphicsDevice + */ +GraphicsDevice.prototype.ToggleFullPage = function () { + "use strict"; + var self = this, + canvas = self.canvas, + scaleX = 0, + scaleY = 0; + + //Don't go to full page if full screen is activated + if (!self.IsFullScreen()) { + if (self.IsFullPage()) { + canvas.width = self.DefaultBackBufferWidth(); + canvas.height = self.DefaultBackBufferHeight(); + } else { + scaleX = window.innerWidth / canvas.width; + scaleY = window.innerHeight / canvas.height; + canvas.width = window.innerWidth; + canvas.height = window.innerHeight; + canvas.getContext("2d").scale(scaleX, scaleY); + } + } +}; + +/** + * Toggles between full screen and windowed mode. + * @name ToggleFullScreen + * @function + * @memberOf GraphicsDevice + */ +GraphicsDevice.prototype.ToggleFullScreen = function () { + "use strict"; + /*global setTimeout*/ + var self = this, + canvas = self.canvas, + scaleX = 0, + scaleY = 0; + + if (!self.IsFullScreen()) { + + //If canvas is full page turn it normal + if (self.IsFullPage()) { + self.ToggleFullPage(); + } + + if (canvas.requestFullScreen) { + canvas.requestFullScreen(); + } else if (canvas.mozRequestFullScreen) { + canvas.mozRequestFullScreen(); + } else if (canvas.webkitRequestFullScreen) { + canvas.webkitRequestFullScreen(Element.ALLOW_KEYBOARD_INPUT); + } + + scaleX = window.innerWidth / canvas.width; + canvas.width = window.innerWidth; + //For some reason (that I dunno), setTimeout is compulsory for the correct resizing + setTimeout(function () { + scaleY = window.innerHeight / canvas.height; + canvas.height = window.innerHeight; + canvas.getContext("2d").scale(scaleX, scaleY); + }, 150); + + } else { + if (document.cancelFullScreen) { + document.cancelFullScreen(); + } else if (document.mozCancelFullScreen) { + document.mozCancelFullScreen(); + } else if (document.webkitCancelFullScreen) { + document.webkitCancelFullScreen(); + } + canvas.width = self.DefaultBackBufferWidth(); + canvas.height = self.DefaultBackBufferHeight(); + } +}; + +/** + * Gets a value that indicates whether the device should start in full-page mode. + * @name IsFullPage + * @function + * @memberOf GraphicsDevice + */ +GraphicsDevice.prototype.IsFullPage = function () { + "use strict"; + /*global window */ + return (this.canvas.width === window.innerWidth && this.canvas.height === window.innerHeight); +}; + +/** + * Gets a value that indicates whether the device should start in full-screen mode. + * @name IsFullScreen + * @function + * @memberOf GraphicsDevice + */ +GraphicsDevice.prototype.IsFullScreen = function () { + "use strict"; + /*global document */ + return !((document.fullScreenElement && document.fullScreenElement !== null) || (!document.mozFullScreen && !document.webkitIsFullScreen)); +}; + +/** + * Clear the canvas rectangle. + * @name Clear + * @function + * @memberOf GraphicsDevice + */ +GraphicsDevice.prototype.Clear = function () { + "use strict"; + var canvas = this.canvas; + + canvas.getContext("2d").clearRect(0, 0, canvas.width, canvas.height); +}; \ No newline at end of file diff --git a/src/JS/XNA_Classes/Keyboard.js b/src/JS/XNA_Classes/Keyboard.js new file mode 100644 index 0000000..d8b0288 --- /dev/null +++ b/src/JS/XNA_Classes/Keyboard.js @@ -0,0 +1,153 @@ +/** + * Allows retrieval of keystrokes from a keyboard input device. + * @global + */ +var Keyboard = { + + keyDownList: [], + keyUpList: [], + keyPressList: [], + + /** + * Add a key to the list of pressed down keys. + * @name addKeyDown + * @function + * @param {Event} event - This parameter represents a keyboard event. + * @memberOf Keyboard + * @static + */ + addKeyDown: function (event) { + "use strict"; + var keyCode = event.keyCode, + indexOfKey = Keyboard.keyDownList.indexOf(keyCode); + + if (indexOfKey === -1) { + Keyboard.removeKeyUp(keyCode); + Keyboard.keyDownList.push(keyCode); + } + + event.preventDefault(); + }, + + /** + * Add a key to the list of released keys. + * @name addKeyUp + * @function + * @param {Event} event - This parameter represents a keyboard event. + * @memberOf Keyboard + * @static + */ + addKeyUp: function (event) { + "use strict"; + var keyCode = event.keyCode, + indexOfKey = Keyboard.keyUpList.indexOf(keyCode); + + if (indexOfKey === -1) { + Keyboard.removeKeyDown(keyCode); + Keyboard.keyUpList.push(keyCode); + } + + indexOfKey = Keyboard.keyPressList.indexOf(keyCode); + + if (indexOfKey !== -1) { + Keyboard.keyPressList.splice(indexOfKey, 1); + } else { + Keyboard.keyPressList.push(keyCode); + } + + event.preventDefault(); + }, + + /** + * Remove a key of the list of pressed down keys. + * @name removeKeyDown + * @function + * @param {Number} key - The key code. + * @memberOf Keyboard + * @static + */ + removeKeyDown: function (key) { + "use strict"; + var indexOfKey = Keyboard.keyDownList.indexOf(key); + + if (indexOfKey !== -1) { + Keyboard.keyDownList.splice(indexOfKey, 1); + } + }, + + /** + * Remove a key of the list of released keys. + * @name removeKeyUp + * @function + * @param {Number} key - The key code. + * @memberOf Keyboard + * @static + */ + removeKeyUp: function (key) { + "use strict"; + var indexOfKey = Keyboard.keyUpList.indexOf(key); + + if (indexOfKey !== -1) { + Keyboard.keyUpList.splice(indexOfKey, 1); + } + }, + + /** + * Returns whether a specified key is currently being pressed. + * @name IsKeyDown + * @function + * @param {Keys} key - Enumerated value that specifies the key to query. + * @memberOf Keyboard + * @static + */ + IsKeyDown: function (key) { + "use strict"; + var indexOfKey = Keyboard.keyDownList.indexOf(key); + + if (indexOfKey !== -1) { + return true; + } else { + return false; + } + }, + + /** + * Returns whether a specified key is currently not pressed. + * @name IsKeyUp + * @function + * @param {Keys} key - Enumerated value that specifies the key to query. + * @memberOf Keyboard + * @static + */ + IsKeyUp: function (key) { + "use strict"; + var indexOfKey = Keyboard.keyUpList.indexOf(key); + + if (indexOfKey !== -1) { + Keyboard.removeKeyUp(key); + return true; + } else { + return false; + } + }, + + /** + * Returns whether a specified key was pressed and released. + * @name IsKeyPressed + * @function + * @param {Keys} key - Enumerated value that specifies the key to query. + * @memberOf Keyboard + * @static + */ + IsKeyPressed: function (key) { + "use strict"; + var indexOfKey = Keyboard.keyPressList.indexOf(key); + + if (indexOfKey !== -1) { + Keyboard.keyPressList.splice(indexOfKey, 1); + return true; + } else { + return false; + } + } +}; \ No newline at end of file diff --git a/src/JS/XNA_Classes/Keys.js b/src/JS/XNA_Classes/Keys.js new file mode 100644 index 0000000..c870343 --- /dev/null +++ b/src/JS/XNA_Classes/Keys.js @@ -0,0 +1,106 @@ +/** + * Identifies a particular key on a keyboard. + * @readonly + * @enum {number} + */ +var Keys = Object.freeze({ + backspace: 8, + tab: 9, + enter: 13, + shift: 16, + ctrl: 17, + alt: 18, + pause_break: 19, + caps_lock: 20, + escape: 27, + space: 32, + page_up: 33, + page_down: 34, + end: 35, + home: 36, + left_arrow: 37, + up_arrow: 38, + right_arrow: 39, + down_arrow: 40, + insert: 45, + supr: 46, + num0: 48, + num1: 49, + num2: 50, + num3: 51, + num4: 52, + num5: 53, + num6: 54, + num7: 55, + num8: 56, + num9: 57, + a: 65, + b: 66, + c: 67, + d: 68, + e: 69, + f: 70, + g: 71, + h: 72, + i: 73, + j: 74, + k: 75, + l: 76, + m: 77, + n: 78, + o: 79, + p: 80, + q: 81, + r: 82, + s: 83, + t: 84, + u: 85, + v: 86, + w: 87, + x: 88, + y: 89, + z: 90, + left_window_key: 91, + right_window_key: 92, + select_key: 93, + numpad_0: 96, + numpad_1: 97, + numpad_2: 98, + numpad_3: 99, + numpad_4: 100, + numpad_5: 101, + numpad_6: 102, + numpad_7: 103, + numpad_8: 104, + numpad_9: 105, + multiply: 106, + add: 107, + subtract: 109, + decimal_point: 110, + divide: 111, + f1: 112, + f2: 113, + f3: 114, + f4: 115, + f5: 116, + f6: 117, + f7: 118, + f8: 119, + f9: 120, + f10: 121, + f11: 122, + f12: 123, + num_lock: 144, + scroll_lock: 145, + semi_colon: 186, + equal_sign: 187, + comma: 188, + dash: 189, + period: 190, + forward_slash: 191, + grave_accent: 192, + open_bracket: 219, + back_slash: 220, + close_braket: 221, + single_quote: 222 +}); \ No newline at end of file diff --git a/src/JS/XNA_Classes/Mouse.js b/src/JS/XNA_Classes/Mouse.js new file mode 100644 index 0000000..f784b44 --- /dev/null +++ b/src/JS/XNA_Classes/Mouse.js @@ -0,0 +1,124 @@ +/** + * Allows retrieval of position and button clicks from a mouse input device. + * @global + */ +var Mouse = { + + X: 0, + Y: 0, + PreviousX: 0, + PreviousY: 0, + LeftButtonPressed: false, + MiddleButtonPressed: false, + RightButtonPressed: false, + LeftButtonClicked: false, + MiddleButtonClicked: false, + RightButtonClicked: false, + LeftButton: 0, + MiddleButton: 1, + RightButton: 2, + ScrollWheelValue: 0, + IsMoving: false, + IsDraggingSomething: false, + + /** + * Determine which mouse button was pressed. + * @name mouseDownHandler + * @function + * @param {Event} event - This parameter represents a mouse event. + * @memberOf Mouse + * @static + */ + mouseDownHandler: function (event) { + "use strict"; + switch (event.button) { + case 0: + this.LeftButtonPressed = true; + break; + case 1: + this.MiddleButtonPressed = true; + break; + case 2: + this.RightButtonPressed = true; + break; + } + }, + + /** + * Determine which mouse button was released. + * @name mouseUpHandler + * @function + * @param {Event} event - This parameter represents a mouse event. + * @memberOf Mouse + * @static + */ + mouseUpHandler: function (event) { + "use strict"; + switch (event.button) { + case 0: + this.LeftButtonPressed = false; + this.LeftButtonClicked = true; + break; + case 1: + this.MiddleButtonPressed = false; + this.MiddleButtonClicked = true; + break; + case 2: + this.RightButtonPressed = false; + this.RightButtonClicked = true; + break; + } + }, + + /** + * Returns whether a specified mouse button was clicked (down and up). + * @name IsButtonClicked + * @function + * @param {Number} buttonCode - Enumerated value that specifies the button to query. + * @memberOf Mouse + * @static + */ + IsButtonClicked: function (buttonCode) { + "use strict"; + switch (buttonCode) { + case 0: + if (this.LeftButtonClicked) { + this.LeftButtonClicked = false; + return true; + } + break; + case 1: + if (this.MiddleButtonClicked) { + this.MiddleButtonClicked = false; + return true; + } + break; + case 2: + if (this.RightButtonClicked) { + this.RightButtonClicked = false; + return true; + } + break; + default: + return false; + } + }, + + /** + * Increments or decrements the ScrollWheelValue property according to the mouse wheel event. + * @name mouseWheelHandler + * @function + * @param {Event} event - This parameter represents a mouse event. + * @memberOf Mouse + * @static + */ + mouseWheelHandler: function (event) { + "use strict"; + /*global window*/ + + // cross-browser wheel delta + var e = window.event || event; // old IE support + + this.ScrollWheelValue += Math.max(-1, Math.min(1, (e.wheelDelta || -e.detail))); + } +}; \ No newline at end of file diff --git a/src/JS/XNA_Classes/Point.js b/src/JS/XNA_Classes/Point.js new file mode 100644 index 0000000..b44681c --- /dev/null +++ b/src/JS/XNA_Classes/Point.js @@ -0,0 +1,49 @@ +/** + * Defines a point in 2D space. + * @constructor + * @param {Number} x - The x-coordinate of the point. + * @param {Number} y - The y-coordinate of the point. + */ +function Point(x, y) { + "use strict"; + this.X = x; + this.Y = y; +} + +/** + * Returns the point (0,0). + * @name Zero + * @function + * @memberOf Point + * @static + */ +Point.Zero = function () { + "use strict"; + return new Point(0, 0); +}; + +/** + * Returns the point (1,1). + * @name One + * @function + * @memberOf Point + * @static + */ +Point.One = function () { + "use strict"; + return new Point(1, 1); +}; + +/** + * Check if the points are equal. + * @name Equals + * @function + * @param {Point} p1 - point 1. + * @param {Point} p2 - point 2. + * @memberOf Point + * @static + */ +Point.Equals = function (p1, p2) { + "use strict"; + return (p1.X === p2.X && p1.Y === p2.Y); +}; \ No newline at end of file diff --git a/src/JS/XNA_Classes/Program.js b/src/JS/XNA_Classes/Program.js new file mode 100644 index 0000000..9e335be --- /dev/null +++ b/src/JS/XNA_Classes/Program.js @@ -0,0 +1,51 @@ +/** + * The main entry point for the application. + */ +(function () { + "use strict"; + /*global Game, Keyboard, Mouse, window*/ + + //Create the game object and start running it + var game = new Game(), + canvas = game.GraphicsDevice.canvas; + game.Run(); + + /***************************************************/ + /*** Keyboard and Mouse listeners initialization ***/ + /***************************************************/ + //Add keyboard event listeners + window.addEventListener("keydown", Keyboard.addKeyDown, false); + window.addEventListener("keyup", Keyboard.addKeyUp, false); + + //Add mouse event listeners + canvas.addEventListener("mousedown", Mouse.mouseDownHandler.bind(Mouse), false); + window.addEventListener("mouseup", Mouse.mouseUpHandler.bind(Mouse), false); + canvas.addEventListener("mousemove", function (event) { + + //Find the new mouse's x and y position on the canvas + Mouse.X = event.pageX - canvas.offsetLeft; + Mouse.Y = event.pageY - canvas.offsetTop; + + //If the mouse position changed then set the previous mouse's x and + //y position on the canvas + if (Mouse.PreviousX !== Mouse.X || Mouse.PreviousY !== Mouse.Y) { + Mouse.IsMoving = true; + Mouse.PreviousX = Mouse.X; + Mouse.PreviousY = Mouse.Y; + } else if (Mouse.IsMoving) { + Mouse.IsMoving = false; + } + + }, false); + + //The mouse wheel listener + canvas.addEventListener("wheel", Mouse.mouseWheelHandler.bind(Mouse), false); + + //Disable the context menu when pressing right button of the mouse + canvas.addEventListener("contextmenu", function (e) { + if (e.button === 2) { + e.preventDefault(); + return false; + } + }, false); +}()); \ No newline at end of file diff --git a/src/JS/XNA_Classes/Rectangle.js b/src/JS/XNA_Classes/Rectangle.js new file mode 100644 index 0000000..05a5908 --- /dev/null +++ b/src/JS/XNA_Classes/Rectangle.js @@ -0,0 +1,197 @@ +/** + * Defines a rectangle. + * @constructor + * @param {Number} x - The x-coordinate of the rectangle. + * @param {Number} y - The y-coordinate of the rectangle. + * @param {Number} width - Width of the rectangle. + * @param {Number} height - Height of the rectangle. + */ +function Rectangle(x, y, width, height) { + "use strict"; + this.Height = height; + this.Width = width; + this.X = x; + this.Y = y; +} + +/** + * Gets the upper-left value of the Rectangle. + * @name Location + * @function + * @memberOf Rectangle + */ +Rectangle.prototype.Location = function () { + "use strict"; + /*global Point */ + return new Point(this.X, this.Y); +}; + +/** + * Returns the y-coordinate of the top of the rectangle. + * @name Top + * @function + * @memberOf Rectangle + */ +Rectangle.prototype.Top = function () { + "use strict"; + return this.Y; +}; + +/** + * Returns the y-coordinate of the bottom of the rectangle. + * @name Bottom + * @function + * @memberOf Rectangle + */ +Rectangle.prototype.Bottom = function () { + "use strict"; + return this.Y + this.Height; +}; + +/** + * Returns the x-coordinate of the left side of the rectangle. + * @name Left + * @function + * @memberOf Rectangle + */ +Rectangle.prototype.Left = function () { + "use strict"; + return this.X; +}; + +/** + * Returns the x-coordinate of the right of the rectangle. + * @name Right + * @function + * @memberOf Rectangle + */ +Rectangle.prototype.Right = function () { + "use strict"; + return this.X + this.Width; +}; + +/** + * Gets the Point that specifies the center of the rectangle. + * @name Center + * @function + * @memberOf Rectangle + */ +Rectangle.prototype.Center = function () { + "use strict"; + /*global Point */ + var self = this; + return new Point(self.X + (self.Width / 2), self.Y + (self.Height / 2)); +}; + +/** + * Gets half of the width of the rectangle. + * @name HalfWidth + * @function + * @memberOf Rectangle + */ +Rectangle.prototype.HalfWidth = function () { + "use strict"; + return this.Width / 2; +}; + +/** + * Gets half of the height of the rectangle. + * @name HalfHeight + * @function + * @memberOf Rectangle + */ +Rectangle.prototype.HalfHeight = function () { + "use strict"; + return this.Height / 2; +}; + +/** + * Returns a Rectangle with all of its values set to zero. + * @name Empty + * @function + * @memberOf Rectangle + * @static + */ +Rectangle.Empty = function () { + "use strict"; + return new Rectangle(0, 0, 0, 0); +}; + +/** + * Gets a value that indicates whether the Rectangle is empty. + * @name IsEmpty + * @function + * @memberOf Rectangle + */ +Rectangle.prototype.IsEmpty = function () { + "use strict"; + return (this.Width <= 0 && this.Height <= 0); +}; + +/** + * Determines whether this Rectangle contains a specified Point. + * @name Contains + * @function + * @param {Point} point - The Point to evaluate. + * @memberOf Rectangle + */ +Rectangle.prototype.Contains = function (value) { + "use strict"; + var self = this; + return (value.X >= self.X && value.X <= self.Right()) && (value.Y >= self.Y && value.Y <= self.Bottom()); +}; + +/** + * Pushes the edges of the Rectangle out by the horizontal and vertical values specified. + * @name Inflate + * @function + * @param {Number} horizontalAmount - Value to push the sides out by. + * @param {Number} verticalAmount - Value to push the top and bottom out by. + * @memberOf Rectangle + */ +Rectangle.prototype.Inflate = function (horizontalAmount, verticalAmount) { + "use strict"; + var self = this; + + self.Width += horizontalAmount; + if (self.Width < 0) { + self.Width = 0; + } + self.Height += verticalAmount; + if (self.Height < 0) { + self.Height = 0; + } +}; + +/** + * Determines whether a specified Rectangle intersects with this Rectangle, and by how much. + * @name Intersects + * @function + * @param {Rectangle} value - The Rectangle to evaluate. + * @memberOf Rectangle + */ +Rectangle.prototype.Intersects = function (value) { + "use strict"; + /*global Vector2*/ + var self = this, + //Calculate the distance vector and the combined half widths and heights + distance = new Vector2( + self.Center().X - value.Center().X, + self.Center().Y - value.Center().Y + ), + combinedHalfWidths = self.HalfWidth() + value.HalfWidth(), + combinedHalfHeights = self.HalfHeight() + value.HalfHeight(); + + //Check whether distance.X is less than the combined half widths + if (Math.abs(distance.X) < combinedHalfWidths) { + //An intersection might be occurring! + //Check whether distance.y is less than the combined half heights + if (Math.abs(distance.Y) < combinedHalfHeights) { + //An intersection has occurred! return the overlap vector + return new Vector2(combinedHalfWidths - Math.abs(distance.X), + combinedHalfHeights - Math.abs(distance.Y)); + } + } + + return false; +}; \ No newline at end of file diff --git a/src/JS/XNA_Classes/Song.js b/src/JS/XNA_Classes/Song.js new file mode 100644 index 0000000..f539bca --- /dev/null +++ b/src/JS/XNA_Classes/Song.js @@ -0,0 +1,138 @@ +/** + * A song. + * @constructor + * @param {String} name - the path to the resource. + */ +function Song(name) { + "use strict"; + /*global Audio*/ + this.Name = name; + this.Audio = new Audio(); + this.Audio.src = name; + this.Audio.loop = true; + this.Audio.muted = false; + this.Audio.volume = 0.8; +} + +/** + * Gets the duration of the song. + * @name Duration + * @function + * @memberOf Song + */ +Song.prototype.Duration = function () { + "use strict"; + return this.Audio.duration; +}; + +/** + * Gets or set the muted setting for the song. + * @name IsMuted + * @function + * @param {Boolean|Undefined} mute - The mute property (true, false or undefined) + * @memberOf Song + */ +Song.prototype.IsMuted = function (mute) { + "use strict"; + if (typeof mute === "undefined") { + return this.Audio.muted; + } + + this.Audio.muted = mute; +}; + +/** + * Gets or set the loop setting for the song. + * @name IsRepeating + * @function + * @param {Boolean|Undefined} loop - The loop property (true, false or undefined) + * @memberOf Song + */ +Song.prototype.IsRepeating = function (loop) { + "use strict"; + if (typeof loop === "undefined") { + return this.Audio.loop; + } + + this.Audio.loop = loop; +}; + +/** + * Gets the play position within the currently playing song. + * @name PlayPosition + * @function + * @memberOf Song + */ +Song.prototype.PlayPosition = function () { + "use strict"; + return this.Audio.currentTime; +}; + +/** + * Gets or sets the media player volume. + * @name Volume + * @function + * @param {Number} volume - The loop volume. + * @memberOf Song + */ +Song.prototype.Volume = function (volume) { + "use strict"; + var self = this; + + if (typeof volume === "undefined") { + return self.Audio.volume; + } + + if (volume < 0) { + self.Audio.volume = 0; + } else if (volume > 1) { + self.Audio.volume = 1; + } else { + self.Audio.volume = volume; + } +}; + +/** + * Plays the Song. + * @name Play + * @function + * @memberOf Song + */ +Song.prototype.Play = function () { + "use strict"; + this.Audio.play(); +}; + +/** + * Pauses the Song. + * @name Pause + * @function + * @memberOf Song + */ +Song.prototype.Pause = function () { + "use strict"; + this.Audio.pause(); +}; + +/** + * Resumes the Song. + * @name Resume + * @function + * @memberOf Song + */ +Song.prototype.Resume = function () { + "use strict"; + this.Audio.play(); +}; + +/** + * Stops the Song. + * @name Stop + * @function + * @memberOf Song + */ +Song.prototype.Stop = function () { + "use strict"; + this.Audio.pause(); + this.Audio.currentTime = 0.0; +}; \ No newline at end of file diff --git a/src/JS/XNA_Classes/SoundEffect.js b/src/JS/XNA_Classes/SoundEffect.js new file mode 100644 index 0000000..6e10944 --- /dev/null +++ b/src/JS/XNA_Classes/SoundEffect.js @@ -0,0 +1,40 @@ +/** + * A sound effect. + * @constructor + * @param {String} name - the path to the resource. + */ +function SoundEffect(name) { + "use strict"; + /*global Audio*/ + this.Name = name; + this.Audio = new Audio(); + this.Audio.src = name; + this.Audio.loop = false; + this.Audio.muted = false; + this.Audio.volume = 0.85; +} + +/** + * Plays the Sound Effect. + * @name Play + * @function + * @memberOf SoundEffect + */ +SoundEffect.prototype.Play = function () { + "use strict"; + var self = this; + + self.Audio.currentTime = 0.0; + self.Audio.play(); +}; + +/** + * Gets the duration of the sound effect. + * @name Duration + * @function + * @memberOf SoundEffect + */ +SoundEffect.prototype.Duration = function () { + "use strict"; + return this.Audio.duration; +}; \ No newline at end of file diff --git a/src/JS/XNA_Classes/SpriteBatch.js b/src/JS/XNA_Classes/SpriteBatch.js new file mode 100644 index 0000000..371eae3 --- /dev/null +++ b/src/JS/XNA_Classes/SpriteBatch.js @@ -0,0 +1,186 @@ +/** + * Enables a group of sprites to be drawn using the same settings. + * @constructor + * @param {GraphicsDevice} graphicsDevice - The graphics device where sprites will be drawn. + */ +function SpriteBatch(graphicsDevice) { + "use strict"; + this.ctx = graphicsDevice.canvas.getContext("2d"); +} + +/** + * Adds a sprite to a batch of sprites for rendering using the specified texture, position, and source rectangle. + * @name Draw + * @function + * @param {Texture2D} texture - A texture. + * @param {Vector2} position - The location (in screen coordinates) to draw the sprite. + * @param {Rectangle} sourceRectangle - A rectangle that specifies (in texels) the source texels from a texture. + * @param {Number} rotation - Specifies the angle (in radians) to rotate the sprite about its center. + * @param {Vector2} scale - Scale factor. + * @param {SpriteEffects} effects - Effects to apply. + * @memberOf SpriteBatch + */ +SpriteBatch.prototype.Draw = function (texture, position, sourceRectangle, rotation, scale, effects) { + "use strict"; + /*global SpriteEffects*/ + var self = this, + flipHorizontally = 1, + flipVertically = 1, + aspectRatio = texture.Width() / texture.Height(), + sourceAspectRatio = sourceRectangle.Width / sourceRectangle.Height, + textureWidth = texture.Width(), + posX = 0, + posY = 0; + + //Save the context to restore later + self.ctx.save(); + + //Rotate the image if required + if (rotation !== 0) { + self.ctx.translate(Math.floor(position.X + texture.HalfWidth() * scale.X), Math.floor(position.Y + texture.HalfHeight() * scale.Y)); + self.ctx.rotate(rotation * Math.PI / 180); + posX = -texture.HalfWidth() * scale.X; + posY = -texture.HalfHeight() * scale.Y; + } else { + posX = position.X; + posY = position.Y; + } + + //Apply sprite effects if needed + if (effects === SpriteEffects.FlipHorizontally) { + flipHorizontally = -1; + } else if (effects === SpriteEffects.FlipVertically) { + flipVertically = -1; + } + + //Scale the image + self.ctx.scale(scale.X * flipHorizontally, scale.Y * flipVertically); + + if (aspectRatio !== sourceAspectRatio) { + textureWidth /= aspectRatio; + } + + //Draw the image + self.ctx.drawImage(texture.Image, + sourceRectangle.X, sourceRectangle.Y, + sourceRectangle.Width, sourceRectangle.Height, + Math.floor(posX) * flipHorizontally / scale.X, Math.floor(posY) * flipVertically / scale.Y, + textureWidth * flipHorizontally, texture.Height() * flipVertically + ); + + //Restore the canvas context + self.ctx.restore(); +}; + +/** + * Adds a string to a batch of sprites for rendering using the specified font, text, position, color and scale. + * @name DrawString + * @function + * @param {String} font - A string representing the font for displaying text (example: "normal bold 20px Helvetica"). + * @param {String} text - A text string. + * @param {Vector2} position - The location (in screen coordinates) to draw the sprite. + * @param {String} color - A string representing the color (example: "#FF00F0"). + * @param {Vector2} scale - Scale factor. + * @memberOf SpriteBatch + */ +SpriteBatch.prototype.DrawString = function (font, text, position, color, scale) { + "use strict"; + var self = this; + + //Save the context to restore later + self.ctx.save(); + + //Scale the image + self.ctx.scale(scale.X, scale.Y); + + //Determine the font, color and baseline, and then draw the given text + self.ctx.font = font; + self.ctx.fillStyle = color; + self.ctx.textBaseline = "top"; + self.ctx.fillText(text, position.X, position.Y); + + //Restore the canvas context + self.ctx.restore(); +}; + +/** + * Draw a given rectangle. + * @name DrawRectangle + * @function + * @param {Rectangle} rectangle - The rectangle to draw. + * @param {String} lineWidth - the width of the line to be drawn. + * @param {String} color - A string representing the color (example: "#FF00F0"). + * @memberOf SpriteBatch + */ +SpriteBatch.prototype.DrawRectangle = function (rectangle, lineWidth, color) { + "use strict"; + var self = this; + + //If the line width is null or undefined set a default value + if (lineWidth === null || typeof lineWidth === "undefined") { + lineWidth = "1"; + } + + //If the color is null or undefined set a default color (black) + if (color === null || typeof color === "undefined") { + color = "#000000"; + } + + //Save the context to restore later + self.ctx.save(); + + //Set the line width and the line color + self.ctx.lineWidth = lineWidth; + self.ctx.strokeStyle = color; + + //Draw the rectangle + self.ctx.strokeRect( + rectangle.X, + rectangle.Y, + rectangle.Width, + rectangle.Height + ); + + //Restore the canvas context + self.ctx.restore(); +}; + +/** + * Draw a given segment. + * @name DrawSegment + * @function + * @param {Segment} segment - The segment to draw. + * @param {String} lineWidth - the width of the line to be drawn. + * @param {String} color - A string representing the color (example: "#FF00F0"). + * @memberOf SpriteBatch + */ +SpriteBatch.prototype.DrawSegment = function (segment, lineWidth, color) { + "use strict"; + var self = this; + + //If the line width is null or undefined set a default value + if (lineWidth === null || typeof lineWidth === "undefined") { + lineWidth = "1"; + } + + //If the color is null or undefined set a default color (black) + if (color === null || typeof color === "undefined") { + color = "#000000"; + } + + //Save the context to restore later + self.ctx.save(); + + //Set the line width and the line color + self.ctx.lineWidth = lineWidth; + self.ctx.strokeStyle = color; + + //Draw the segment + self.ctx.beginPath(); + self.ctx.moveTo(segment.pointA.X, segment.pointA.Y); + self.ctx.lineTo(segment.pointB.X, segment.pointB.Y); + self.ctx.stroke(); + + //Restore the canvas context + self.ctx.restore(); +}; \ No newline at end of file diff --git a/src/JS/XNA_Classes/SpriteEffects.js b/src/JS/XNA_Classes/SpriteEffects.js new file mode 100644 index 0000000..82a3bea --- /dev/null +++ b/src/JS/XNA_Classes/SpriteEffects.js @@ -0,0 +1,10 @@ +/** + * Defines sprite mirroring options. + * @readonly + * @enum {number} + */ +var SpriteEffects = Object.freeze({ + None: 0, + FlipHorizontally: 1, + FlipVertically: 2 +}); \ No newline at end of file diff --git a/src/JS/XNA_Classes/Texture2D.js b/src/JS/XNA_Classes/Texture2D.js new file mode 100644 index 0000000..493d838 --- /dev/null +++ b/src/JS/XNA_Classes/Texture2D.js @@ -0,0 +1,67 @@ +/** + * Represents a 2D grid of texels. + * @constructor + * @param {String} name - The path to the resource. + */ +function Texture2D(name) { + "use strict"; + /*global Rectangle, Image*/ + this.Name = name; + this.Image = new Image(); + this.Image.src = name; +} + +/** + * Gets the width of the texture. + * @name Height + * @function + * @memberOf Texture2D + */ +Texture2D.prototype.Height = function () { + "use strict"; + return this.Image.height; +}; + +/** + * Gets the height of the texture. + * @name Width + * @function + * @memberOf Texture2D + */ +Texture2D.prototype.Width = function () { + "use strict"; + return this.Image.width; +}; + +/** + * Gets the bounds of the texture. + * @name Bounds + * @function + * @memberOf Texture2D + */ +Texture2D.prototype.Bounds = function () { + "use strict"; + return new Rectangle(0, 0, this.Width(), this.Height()); +}; + +/** + * Gets half of the width of the texture. + * @name HalfWidth + * @function + * @memberOf Texture2D + */ +Texture2D.prototype.HalfWidth = function () { + "use strict"; + return this.Width() / 2; +}; + +/** + * Gets half of the height of the texture. + * @name HalfHeight + * @function + * @memberOf Texture2D + */ +Texture2D.prototype.HalfHeight = function () { + "use strict"; + return this.Height() / 2; +}; \ No newline at end of file diff --git a/src/JS/XNA_Classes/Vector2.js b/src/JS/XNA_Classes/Vector2.js new file mode 100644 index 0000000..5f4444a --- /dev/null +++ b/src/JS/XNA_Classes/Vector2.js @@ -0,0 +1,153 @@ +/** + * Defines a vector with two components. + * @constructor + * @param {Number} x - Initial value for the x-component of the vector. + * @param {Number} y - Initial value for the y-component of the vector. + */ +function Vector2(x, y) { + "use strict"; + this.X = x; + this.Y = y; +} + +/** + * Returns a Vector2 with both of its components set to zero. + * @name Zero + * @function + * @memberOf Vector2 + * @static + */ +Vector2.Zero = function () { + "use strict"; + return new Vector2(0, 0); +}; + +/** + * Returns a Vector2 with both of its components set to one. + * @name One + * @function + * @memberOf Vector2 + * @static + */ +Vector2.One = function () { + "use strict"; + return new Vector2(1, 1); +}; + +/** + * Adds two vectors. + * @name Add + * @function + * @param {Vector2} value1 - Source vector 1 + * @param {Vector2} value2 - Source vector 2 + * @memberOf Vector2 + * @static + */ +Vector2.Add = function (value1, value2) { + "use strict"; + return new Vector2(value1.X + value2.X, value1.Y + value2.Y); +}; + +/** + * Substract two vectors. + * @name Substract + * @function + * @param {Vector2} value1 - Source vector 1 + * @param {Vector2} value2 - Source vector 2 + * @memberOf Vector2 + * @static + */ +Vector2.Substract = function (value1, value2) { + "use strict"; + return new Vector2(value1.X - value2.X, value1.Y - value2.Y); +}; + +/** + * Divides the components of a vector by a scalar value or the components of another vector. + * @name Divide + * @function + * @param {Vector2} value1 - Source vector 1 + * @param {Vector2} value2 - A scalar value or a source vector 2 + * @memberOf Vector2 + * @static + */ +Vector2.Divide = function (value1, value2) { + "use strict"; + if (typeof (value2) === "number") { + return new Vector2(value1.X / value2, value1.Y / value2); + } else { + return new Vector2(value1.X / value2.X, value1.Y / value2.Y); + } +}; + +/** + * Multiplies the components of a vector by a scalar value or the components of another vector. + * @name Multiply + * @function + * @param {Vector2} value1 - Source vector 1 + * @param {Vector2} value2 - A scalar value or a source vector 2 + * @memberOf Vector2 + * @static + */ +Vector2.Multiply = function (value1, value2) { + "use strict"; + if (typeof (value2) === "number") { + return new Vector2(value1.X * value2, value1.Y * value2); + } else { + return new Vector2(value1.X * value2.X, value1.Y * value2.Y); + } +}; + +/** + * Calculates the distance between two vectors. + * @name Distance + * @function + * @param {Vector2|Point} value1 - Source vector 1 + * @param {Vector2|Point} value2 - Source vector 2 + * @memberOf Vector2 + * @static + */ +Vector2.Distance = function (value1, value2) { + "use strict"; + return (Math.sqrt(Math.pow(value2.X - value1.X, 2) + Math.pow(value2.Y - value1.Y, 2))); +}; + +/** + * Calculates the length of the vector. + * @name Length + * @function + * @memberOf Vector2 + */ +Vector2.prototype.Length = function () { + "use strict"; + return (Math.sqrt(Math.pow(this.X, 2) + Math.pow(this.Y, 2))); +}; + +/** + * Turns the current vector into a unit vector. The result is a vector one unit + * in length pointing in the same direction as the original vector. + * @name Normalize + * @function + * @memberOf Vector2 + */ +Vector2.prototype.Normalize = function () { + "use strict"; + var self = this, + length = self.Length(); + + return (new Vector2(self.X / length, self.Y / length)); +}; + +/** + * Check if the vectors are equal. + * @name Equals + * @function + * @param {Vector2} v1 - vector 1. + * @param {Vector2} v2 - vector 2. + * @memberOf Vector2 + * @static + */ +Vector2.Equals = function (v1, v2) { + "use strict"; + return (v1.X === v2.X && v1.Y === v2.Y); +}; \ No newline at end of file diff --git a/src/JS/XgameJS/AnimatedSprite.js b/src/JS/XgameJS/AnimatedSprite.js new file mode 100644 index 0000000..31d6953 --- /dev/null +++ b/src/JS/XgameJS/AnimatedSprite.js @@ -0,0 +1,119 @@ +/** + * Represents an animated sprite, which is composed of various frames. + * @constructor + * @param {Texture2D} texture - The texture image. + * @param {Vector2} scale - The scale of the image. + * @param {Rectangle} sourceRect - The image source rectangle. + * @param {Point} position - The sprite position in the canvas. + * @param {Boolean} isVisible - Determines if the sprite is visible or not. + * @param {Boolean} loop - Determines if the animation has to animate in loop or not (one time). + * @param {Boolean} pingPongLoop - Determines if the animation should run in reverse when reachs the last + * frame or not (reset to initial frame). + * @param {Number} millisecondsPerFrame - A number representing the milliseconds between each frame. + * @param {Number} numberOfFrames - The number of frames in the sprite sheet. + */ +function AnimatedSprite(texture, scale, sourceRect, position, isVisible, animationType, numberOfFrames, millisecondsPerFrame) { + "use strict"; + /*global Sprite, AnimationTypes, setInterval, clearInterval*/ + + //Call the father constructor (super) + Sprite.call(this, texture, scale, sourceRect, position, isVisible); + + this.AnimationType = animationType; + this.NumberOfFrames = numberOfFrames; + this.MillisecondsPerFrame = millisecondsPerFrame; + this.CurrentFrame = 0; + this.Forward = true; //to control the direction of the loop + this.Columns = Math.floor(texture.Width() / sourceRect.Width); + this.RunAnimation = true; + this.VerticalOffset = 0; //(optional) used when the animation sheet has different + //animations representing different states of the object + //which owns the sprite + this.interval = null; +} + +//Create the AnimatedSprite.prototype object, which inherits from Sprite.prototype. +//Then stablish the "constructor" property to reference to AnimatedSprite +AnimatedSprite.prototype = Object.create(Sprite.prototype); +AnimatedSprite.prototype.constructor = AnimatedSprite; + +/** + * Starts the update animation timer. + * @name StartAnimation + * @function + * @memberof AnimatedSprite + */ +AnimatedSprite.prototype.StartAnimation = function () { + "use strict"; + var self = this; + + self.interval = setInterval(self.UpdateAnimation.bind(self), self.MillisecondsPerFrame); +}; + +/** + * Stops the update animation timer. + * @name StopAnimation + * @function + * @memberof AnimatedSprite + */ +AnimatedSprite.prototype.StopAnimation = function () { + "use strict"; + clearInterval(this.interval); +}; + +/** + * Update the animation depending on the number of frames + * @name UpdateAnimation + * @function + * @memberof AnimatedSprite + */ +AnimatedSprite.prototype.UpdateAnimation = function () { + "use strict"; + var self = this, + sourceRect = self.SourceRect; + + sourceRect.X = Math.floor(self.CurrentFrame % self.Columns) * sourceRect.Width; + sourceRect.Y = Math.floor(self.CurrentFrame / self.Columns) * sourceRect.Height; + + if (self.RunAnimation) { + + //Do different actions depending on the animation type + switch (self.AnimationType) { + + case AnimationTypes.PlayOneTime: + //It the last frame has been reached, stop the run + if (self.CurrentFrame === self.NumberOfFrames - 1) { + self.RunAnimation = false; + } + break; + + case AnimationTypes.Loop: + //If the last frame has been reached, reset to the initial frame + if (self.CurrentFrame === self.NumberOfFrames - 1) { + self.CurrentFrame = 0; + } + break; + + case AnimationTypes.PingPongLoop: + //If the last frame has been reached, reverse the animation + if (self.CurrentFrame === self.NumberOfFrames - 1) { + self.Forward = false; + } + //If the first frame has been reached, set forward to true + if (self.CurrentFrame === 0) { + self.Forward = true; + } + break; + } + + //Add 1 to currentFrame if forward is true, subtract 1 if it's false + if (self.Forward) { + self.CurrentFrame += 1; + } else { + self.CurrentFrame -= 1; + } + + //Apply vertical offset + sourceRect.Y += sourceRect.Height * self.VerticalOffset; + } +}; \ No newline at end of file diff --git a/src/JS/XgameJS/AnimationTypes.js b/src/JS/XgameJS/AnimationTypes.js new file mode 100644 index 0000000..3b2b097 --- /dev/null +++ b/src/JS/XgameJS/AnimationTypes.js @@ -0,0 +1,10 @@ +/** + * Defines the animation types. + * @readonly + * @enum {number} + */ +var AnimationTypes = Object.freeze({ + PlayOneTime: 0, + Loop: 1, //when the animation reaches the last frame then reset to the initial frame + PingPongLoop: 2 //when the animation reaches the last frame then reverse the animation +}); \ No newline at end of file diff --git a/src/JS/XgameJS/Ball.js b/src/JS/XgameJS/Ball.js new file mode 100644 index 0000000..c5a2941 --- /dev/null +++ b/src/JS/XgameJS/Ball.js @@ -0,0 +1,344 @@ +/** + * Defines a Ball. + * @constructor + * @param {Sprite} sprite - The sprite that represents the ball. + * @param {Number} radius - The radius of the circle of the ball. + * @param {Point} position - The position of the ball. + * @param {Number} position - The position of the ball. + * @param {Boolean} bounce - Determines if the ball can bounce or not. + */ +function Ball(sprite, radius, position, index, bounce, rotate) { + "use strict"; + /*global Vector2, Circle*/ + this.Sprite = sprite; + this.Circle = new Circle(radius, position.X, position.Y); + + //Physics properties + this.SpeedV = Vector2.Zero(); + this.GroundFriction = 0.975; + this.BallBounceFriction = 0.85; + this.WallBounceFriction = 0.7; + this.MaxRotationSpeedTransmision = 25; + this.CurrentRotationSpeed = 0; + + //Platform game properties + this.IsOnGround = false; + + //Drag & Drop properties + this.IsDraggable = true; + this.IsBeenDragged = false; + + //Other properties + this.RandomDir = [-0.1, 0.1]; + this.Index = index; + this.IsBounceOn = bounce; + this.IsRotationOn = rotate; +} + +/** + * Updates the ball. + * @name Update + * @function + * @param {Number} worldWidth - The width of the game world. + * @param {Number} worldHeight - The height of the game world. + * @param {Array} balls - Array of existing balls. + * @param {Boolean} isGravityOn - Determines if the gravity is activated or not. + * @param {GravityDirections} gravityDir - The gravity direction of the game world. + * @param {Number} gravityForce - The gravity force value. + * @memberOf Ball + */ +Ball.prototype.Update = function (worldWidth, worldHeight, balls, isGravityOn, gravityDir, gravityForce) { + "use strict"; + /*global GravityDirections, Mouse, Point, hitTestPoint*/ + var self = this, + randomDirImpulse = 0, + len = 0, + i = 0, + j = 0; + + //Check if the mouse clicked a ball to drag it + if (self.Circle.Contains(new Point(Mouse.X, Mouse.Y)) && self.IsDraggable && Mouse.LeftButtonPressed && !Mouse.IsDraggingSomething) { //Si quitamos IsDraggingSom... ocurren cosas divertidas + //Assign the sprite to the dragSprite variable + self.IsBeenDragged = true; + Mouse.IsDraggingSomething = true; + self.CurrentRotationSpeed = 0; + self.SpeedV.X = 0; + self.SpeedV.Y = 0; + i = self.Index; + len = balls.length; + + //push the dragSprite to the end of the sprites + //array so that it's displayed last + self.Index = balls.length - 1; + balls.push(self); + + //Splice the dragSprite from its previous + //position in the sprites array + balls.splice(i, 1); + + for (j = i; j < len - 1; j += 1) { + balls[j].Index -= 1; + } + } + + //Update the Circle position with the mouse position + if (Mouse.IsMoving && self.IsBeenDragged) { + self.Circle.X = Mouse.X - self.Circle.Radius; + self.Circle.Y = Mouse.Y - self.Circle.Radius; + } + + //If the mouse left button was released drop the ball + if (self.IsBeenDragged && !Mouse.LeftButtonPressed) { + self.IsBeenDragged = false; + Mouse.IsDraggingSomething = false; + } + + //Apply gravity depending on the gravity direction + if (isGravityOn && !self.IsBeenDragged) { + + //Random impulse when the balls are generated + if (!self.IsOnGround && self.SpeedV.X === 0 && self.SpeedV.Y === 0) { + randomDirImpulse = self.RandomDir[Math.floor(Math.random() * 2)]; + } + + switch (gravityDir) { + + //Gravity down + case GravityDirections.G_DOWN: + self.SpeedV.Y += gravityForce; + self.SpeedV.X += randomDirImpulse; + if (self.Circle.Bottom() >= worldHeight) { + self.SpeedV.X *= self.GroundFriction; + self.IsOnGround = true; + } + break; + + //Gravity up + case GravityDirections.G_UP: + self.SpeedV.Y -= gravityForce; + self.SpeedV.X += randomDirImpulse; + if (self.Circle.Top() <= 0) { + self.SpeedV.X *= self.GroundFriction; + self.IsOnGround = true; + } + break; + + //Gravity left + case GravityDirections.G_LEFT: + self.SpeedV.X -= gravityForce; + self.SpeedV.Y += randomDirImpulse; + if (self.Circle.Left() <= 0) { + self.SpeedV.Y *= self.GroundFriction; + self.IsOnGround = true; + } + break; + + //Gravity right + case GravityDirections.G_RIGHT: + self.SpeedV.X += gravityForce; + self.SpeedV.Y += randomDirImpulse; + if (self.Circle.Right() >= worldWidth) { + self.SpeedV.Y *= self.GroundFriction; + self.IsOnGround = true; + } + break; + } + + } + + //Move the ball if it isn't dragged + if (!self.IsBeenDragged) { + self.Circle.X += self.SpeedV.X; + self.Circle.Y += self.SpeedV.Y; + } + + //Collision with balls + len = balls.length; + if (len > 1 && !self.IsBeenDragged) { + for (i = 0; i < len; i += 1) { + if (self.Index !== i) { + self.CollisionWithBall(balls[i], self.IsBounceOn, self.IsRotationOn); + } + } + } + + //Screen boundaries + //Left + if (self.Circle.Left() < 0) { + if (self.IsBounceOn) { + self.SpeedV.X *= -self.WallBounceFriction; + } + self.Circle.X = 0; + } + //Up + if (self.Circle.Top() < 0) { + if (self.IsBounceOn) { + self.SpeedV.Y *= -self.WallBounceFriction; + } + self.Circle.Y = 0; + } + //Right + if (self.Circle.Right() > worldWidth) { + if (self.IsBounceOn) { + self.SpeedV.X *= -self.WallBounceFriction; + } + self.Circle.X = worldWidth - self.Circle.Diameter(); + } + //Down + if (self.Circle.Bottom() > worldHeight) { + if (self.IsBounceOn) { + self.SpeedV.Y *= -self.WallBounceFriction; + } + self.Circle.Y = worldHeight - self.Circle.Diameter(); + } + + //Update the sprite + self.Sprite.Position.X = self.Circle.X; + self.Sprite.Position.Y = self.Circle.Y; + + //Update the sprite rotation + self.Sprite.Rotation += self.CurrentRotationSpeed; + self.CurrentRotationSpeed *= self.GroundFriction; +}; + +/** + * Check if a ball collide with other ball. Besides, bounce and rotate the balls if needed. + * @name CollisionWithBall + * @function + * @param {Ball} ball - The ball which will be checked to find a collision. + * @memberOf Ball + */ +Ball.prototype.CollisionWithBall = function (ball) { + "use strict"; + var self = this, + overlapV = self.Circle.IsInsideCircle(ball.Circle), + vector = null, + d = null, + angle = 0, + b1Magnitude = 0, + b2Magnitude = 0, + s = null; + + //If the other ball is inside the other + if (overlapV !== false) { + self.Circle.X += overlapV.X; + self.Circle.Y += overlapV.Y; + return true; + } + + //Check if this ball is inside the other + overlapV = self.Circle.Intersects(ball.Circle); + + //If there is a collision with the other ball move it away of the other + if (overlapV !== false) { + + vector = overlapV.Y; //the vector between the balls centers + d = vector.Normalize(); + angle = Math.atan2(d.X, d.X) * 180 / Math.PI; + b1Magnitude = self.SpeedV.Length(); + b2Magnitude = ball.SpeedV.Length(); + + //If rotation is activated then rotate the ball + if (self.IsRotationOn) { + if ( + (angle >= 0 && angle <= 90 && self.SpeedV.X > 0) || + (angle > 90 && angle <= 180 && self.SpeedV.X >= 0) || + (angle < 0 && angle >= -90 && self.SpeedV.X <= 0) || + (angle < -90 && angle >= -180 && self.SpeedV.X < 0) + ) { + self.CurrentRotationSpeed = Math.min(Math.abs(b1Magnitude), self.MaxRotationSpeedTransmision); + ball.CurrentRotationSpeed = -Math.min(Math.abs(b2Magnitude), ball.MaxRotationSpeedTransmision); + } else { + self.CurrentRotationSpeed = -Math.min(Math.abs(b1Magnitude), self.MaxRotationSpeedTransmision); + ball.CurrentRotationSpeed = Math.min(Math.abs(b2Magnitude), ball.MaxRotationSpeedTransmision); + } + + //Limit the rotation speeds + if (Math.abs(self.CurrentRotationSpeed) < 1) { + self.CurrentRotationSpeed = 0; + } + if (Math.abs(ball.CurrentRotationSpeed) < 1) { + ball.CurrentRotationSpeed = 0; + } + } + + //Move circle 1 out of the collision by multiplying + //the overlap with the normalized vector and add it to + //ball 1's position + self.Circle.X += overlapV.X * d.X; + self.Circle.Y += overlapV.X * d.Y; + //Ocurren cosas diver al poner esto + //ball.Circle.X += overlapV.X * overlapV.Y[0]; + //ball.Circle.Y += overlapV.X * overlapV.Y[1]; + + if (self.IsBounceOn) { + //Create a collision vector object to represent the bounce surface + //Find the bounce surface's X and Y properties + //(This represents the normal of the distance vector between the circles) + s = new Vector2(vector.Y, -vector.X); + + //Bounce b1 off the surface + self.BounceOffSurface(ball, s); + } + + return true; + } + + return false; +}; + +/** + * Bounces the current ball with other ball given the virtual surface between them. + * @name BounceOffSurface + * @function + * @param {Ball} ball - The ball which will bounced. + * @param {Vector2} s - The surface to bounce off. + * @memberOf Ball + */ +Ball.prototype.BounceOffSurface = function (ball, s) { + "use strict"; + //1. Calculate the collision surface's properties + + + var self = this, + //Find the surface vector's left normal + leftNormalV = new Vector2(s.Y, -s.X), + //s.lx = s.Y; + //s.ly = -s.X; + + //Find its magnitude + sLength = s.Length(), + + //Find its normalized/unit vector values + dV = s.Normalize(), + + //2. Bounce the ball off the surface (s) + + //Find the dot product between the object and the surface + dp1 = self.SpeedV.X * dV.X + self.SpeedV.Y * dV.Y, + + //Project the object's velocity onto the collision surface + p1V = new Vector2(dp1 * dV.X, dp1 * dV.Y), + + //Find the dot product of the object and the surface's left normal (s.lx and s.ly) + dp2 = self.SpeedV.X * (leftNormalV.X / sLength) + self.SpeedV.Y * (leftNormalV.Y / sLength), + + //Project the object's velocity onto the surface's left normal + p2V = new Vector2(dp2 * (leftNormalV.X / sLength), dp2 * (leftNormalV.Y / sLength)), + bounceV = null; + + //Reverse the projection on the surface's left normal + p2V.X *= -1; + p2V.Y *= -1; + + //Add up the projections to create a new bounce vector + bounceV = new Vector2(p1V.X + p2V.X, p1V.Y + p2V.Y); + + //Assign the bounce vector to the object's velocity + self.SpeedV.X = bounceV.X * self.BallBounceFriction; + self.SpeedV.Y = bounceV.Y * self.BallBounceFriction; + if (!ball.IsBeenDragged) { + ball.SpeedV.X = -bounceV.X * ball.BallBounceFriction; + ball.SpeedV.Y = -bounceV.Y * ball.BallBounceFriction; + } +}; \ No newline at end of file diff --git a/src/JS/XgameJS/Camera.js b/src/JS/XgameJS/Camera.js new file mode 100644 index 0000000..dfdd666 --- /dev/null +++ b/src/JS/XgameJS/Camera.js @@ -0,0 +1,150 @@ +/** + * Defines the game camera. + * @constructor + * @param {Number} width - The width of the camera. + * @param {Number} height - The height of the camera. + * @param {Number} levelWidth - The width of the level. + * @param {Number} levelHeight - The height of the level. + * @param {Number} zoom - The zoom of the camera. + */ +function Camera(width, height, levelWidth, levelHeight, zoom) { + "use strict"; + /*global Point, Vector2*/ + this.Width = width; + this.Height = height; + this.LevelWidth = levelWidth; + this.LevelHeight = levelHeight; + this.Zoom = zoom; + this.Position = Point.Zero(); + this.SpeedV = Vector2.Zero(); //For parallax scrolling + this.PreviousSpeedX = 0; //For parallax scrolling + + //Camera constants + this.upLeftMarginPercentage = 0.3; + this.downRightMarginPercentage = 0.7; + this.MaxZoom = 2.5; + this.MinZoom = 1.0; +} + +/** + * The camera's inner right scroll boundaries. + * @name RightInnerBoundary + * @function + * @memberOf Camera + */ +Camera.prototype.RightInnerBoundary = function () { + "use strict"; + var self = this; + return self.Position.X + (self.Width * self.downRightMarginPercentage / self.Zoom); +}; + +/** + * The camera's inner left scroll boundaries. + * @name LeftInnerBoundary + * @function + * @memberOf Camera + */ +Camera.prototype.LeftInnerBoundary = function () { + "use strict"; + var self = this; + return self.Position.X + (self.Width * self.upLeftMarginPercentage / self.Zoom); +}; + +/** + * The camera's inner top scroll boundaries. + * @name TopInnerBoundary + * @function + * @memberOf Camera + */ +Camera.prototype.TopInnerBoundary = function () { + "use strict"; + var self = this; + return self.Position.Y + (self.Height * self.upLeftMarginPercentage / self.Zoom); +}; + +/** + * The camera's inner bottom scroll boundaries. + * @name BottomInnerBoundary + * @function + * @memberOf Camera + */ +Camera.prototype.BottomInnerBoundary = function () { + "use strict"; + var self = this; + return self.Position.Y + (self.Height * self.downRightMarginPercentage / self.Zoom); +}; + +/** + * Increases the zoom by 0.1. + * @name IncreaseZoom + * @function + * @memberOf Camera + */ +Camera.prototype.IncreaseZoom = function () { + "use strict"; + var self = this; + + if (self.Zoom < self.MaxZoom) { + self.Zoom += 0.1; + } +}; + +/** + * Decreases the zoom by 0.1. + * @name DecreaseZoom + * @function + * @memberOf Camera + */ +Camera.prototype.DecreaseZoom = function () { + "use strict"; + var self = this; + + if (self.Zoom > self.MinZoom) { + self.Zoom -= 0.1; + } +}; + +/** + * Updates de camera depending on the player's position. + * @name Update + * @function + * @param {Player} player - the player of the game. + * @memberOf Camera + */ +Camera.prototype.Update = function (player) { + "use strict"; + var self = this, + playerSprite = player.Sprite; + + //Scroll the camera + if (playerSprite.Position.X < self.LeftInnerBoundary()) { + self.Position.X = Math.floor(playerSprite.Position.X - (self.Width * self.upLeftMarginPercentage / self.Zoom)); + } + if (playerSprite.Position.X + playerSprite.Width() > self.RightInnerBoundary()) { + self.Position.X = Math.floor(playerSprite.Position.X + playerSprite.Width() - (self.Width * self.downRightMarginPercentage / self.Zoom)); + } + if (playerSprite.Position.Y < self.TopInnerBoundary()) { + self.Position.Y = Math.floor(playerSprite.Position.Y - (self.Height * self.upLeftMarginPercentage / self.Zoom)); + } + if (playerSprite.Position.Y + playerSprite.Height() > self.BottomInnerBoundary()) { + self.Position.Y = Math.floor(playerSprite.Position.Y + playerSprite.Height() - (self.Height * self.downRightMarginPercentage / self.Zoom)); + } + + //The camera's world boundaries + if (self.Position.X < 0) { + self.Position.X = 0; + } + if (self.Position.X * self.Zoom + self.Width > self.LevelWidth * self.Zoom) { + self.Position.X = (self.LevelWidth * self.Zoom - self.Width) / self.Zoom; + } + if (self.Position.Y < 0) { + self.Position.Y = 0; + } + if (self.Position.Y * self.Zoom + self.Height > (self.LevelHeight * self.Zoom)) { + self.Position.Y = (self.LevelHeight * self.Zoom - self.Height) / self.Zoom; + } + + //Figure out the camera's velocity by subtracting its position in the + //previous frame from its position in this frame + self.SpeedV.X = self.Position.X - self.PreviousSpeedX; +}; \ No newline at end of file diff --git a/src/JS/XgameJS/Circle.js b/src/JS/XgameJS/Circle.js new file mode 100644 index 0000000..cd7b17c --- /dev/null +++ b/src/JS/XgameJS/Circle.js @@ -0,0 +1,300 @@ +/** + * Defines a circle. + * @constructor + * @param {Number} radius - The radius of the circle. + * @param {Number} x - The x-coordinate of the circle. + * @param {Number} y - The y-coordinate of the circle. + */ +function Circle(radius, x, y) { + "use strict"; + this.Radius = radius; + this.X = x; + this.Y = y; +} + +/** + * Gets the diameter of the circle. + * @name Diameter + * @function + * @memberOf Circle + */ +Circle.prototype.Diameter = function () { + "use strict"; + return this.Radius * 2; +}; + +/** + * Gets the upper-left value of the circle. + * @name Location + * @function + * @memberOf Circle + */ +Circle.prototype.Location = function () { + "use strict"; + /*global Point */ + return new Point(this.X, this.Y); +}; + +/** + * Returns the y-coordinate of the top of the circle. + * @name Top + * @function + * @memberOf Circle + */ +Circle.prototype.Top = function () { + "use strict"; + return this.Y; +}; + +/** + * Returns the y-coordinate of the bottom of the circle. + * @name Bottom + * @function + * @memberOf Circle + */ +Circle.prototype.Bottom = function () { + "use strict"; + return this.Y + this.Diameter(); +}; + +/** + * Returns the x-coordinate of the left side of the circle. + * @name Left + * @function + * @memberOf Circle + */ +Circle.prototype.Left = function () { + "use strict"; + return this.X; +}; + +/** + * Returns the x-coordinate of the right of the circle. + * @name Right + * @function + * @memberOf Circle + */ +Circle.prototype.Right = function () { + "use strict"; + return this.X + this.Diameter(); +}; + + +/** + * Gets the Point that specifies the center of the circle. + * @name Center + * @function + * @memberOf Circle + */ +Circle.prototype.Center = function () { + "use strict"; + var self = this; + //console.log(self.X); + return new Point(self.X + self.Radius, self.Y + self.Radius); +}; + +/** + * Determines whether this circle contains a specified Point. + * @name Contains + * @function + * @param {Point} point - The Point to evaluate. + * @memberOf Circle + */ +Circle.prototype.Contains = function (value) { + "use strict"; + /*global Vector2*/ + return (Vector2.Distance(this.Center(), value) <= this.Radius); +}; + +/** + * Pushes the edges of the circle out by the amount specified. + * @name Inflate + * @function + * @param {Number} amount - Value to push the radius out by. + * @memberOf Circle + */ +Circle.prototype.Inflate = function (amount) { + "use strict"; + var self = this; + + self.Radius += amount; + if (self.Radius < 0) { + self.Radius = 0; + } +}; + +/** + * Determines whether a specified Circle is inside this Circle, and by how much. + * @name IsInsideCircle + * @function + * @param {Circle} circle - The Circle to evaluate. + * @memberOf Circle + */ +Circle.prototype.IsInsideCircle = function (circle) { + "use strict"; + var self = this, + centerA = self.Center(), + centerB = circle.Center(), + vector = null, + d = null, + surfacePoint = null, + distanceToSurface = 0; + + //Check if circles have the same center + if (Point.Equals(centerA, centerB)) { + distanceToSurface = (self.Radius + circle.Radius); + return new Vector2(0, distanceToSurface); + + //Check if self circle is inside the other circle + } else if (self.Radius < circle.Radius) { + if (Vector2.Distance(centerA, centerB) <= Math.abs(circle.Radius - self.Radius)) { + vector = new Vector2(centerA.X - centerB.X, centerA.Y - centerB.Y); + d = vector.Normalize(); + surfacePoint = new Point((centerB.X + self.Radius) * d.X, (centerB.Y + self.Radius) * d.Y); + distanceToSurface = Vector2.Distance(centerA, surfacePoint) + self.Radius; + return new Vector2(distanceToSurface * d.X, distanceToSurface * d.Y); + } + } + + return false; +}; + +/** + * Determines whether a specified Circle intersects with this Circle, and by how much. + * @name Intersects + * @function + * @param {Circle} value - The Circle to evaluate. + * @memberOf Circle + */ +Circle.prototype.Intersects = function (value) { + "use strict"; + /*global Vector2 */ + var self = this, + //Calculate the vector between the circles center points + vector = new Vector2( + self.Center().X - value.Center().X, + self.Center().Y - value.Center().Y + ), + //Find the distance between the circles + magnitude = vector.Length(), + //Add together the circles combined radius + combinedRadius = self.Radius + value.Radius, + overlap = 0, + d = null; + + //Figure out if there's a collision + if (magnitude < combinedRadius) { + //Yes, a collision is happening. + //Find the amount of overlap between the circles + overlap = combinedRadius - magnitude; + + //Normalize the vector, these numbers tell us the direction of the collision. + //d = vector.Normalize(); + + //Return the overlap and the vector between the circles center points + return new Vector2(overlap, vector); + } + + return false; +}; + +/** + * Determines whether a specified Segment intersects with this Circle, and by how much. + * @name IntersectsSegment + * @function + * @param {Segment} segment - The Segment to evaluate. + * @memberOf Circle + */ +Circle.prototype.IntersectsSegment = function (segment) { + "use strict"; + /*global Vector2*/ + var self = this, + pointA = new Point(segment.pointA.X - self.Radius, segment.pointA.Y - self.Radius), + pointB = new Point(segment.pointB.X - self.Radius, segment.pointB.Y - self.Radius), + // Calculate the euclidean distance between a & b + distance = Vector2.Distance(pointA, pointB), + // Compute the direction vector d from a to b + dir = new Vector2((pointB.X - pointA.X) / distance, (pointB.Y - pointA.Y) / distance), + // Now the line equation is x = dx*t + ax, y = dy*t + ay with 0 <= t <= 1. + // compute the value t of the closest point to the circle center (cx, cy) + t = (dir.X * (self.X - pointA.X)) + (dir.Y * (self.Y - pointA.Y)), + // compute the coordinates of the point e on line and closest to c + e = new Point((t * dir.X) + pointA.X, (t * dir.Y) + pointA.Y), + // Calculate the euclidean distance between c & e + eDistCtoE = Vector2.Distance(self, e); + + Vector2.Add(e, self.Radius); + + // test if the line intersects the circle + if (eDistCtoE < self.Radius) { + + // compute distance from t to circle intersection point + var dt = Math.sqrt(Math.pow(self.Radius, 2) - Math.pow(eDistCtoE, 2)); + + // compute first intersection point + var f = new Point(((t - dt) * dir.X) + pointA.X, ((t - dt) * dir.Y) + pointA.Y); + // check if f lies on the line + f.onLine = (Vector2.Distance(pointA, f) + Vector2.Distance(f, pointB) === Vector2.Distance(pointA, pointB)); + + // compute second intersection point + var g = new Point(((t + dt) * dir.X) + pointA.X, ((t + dt) * dir.Y) + pointA.Y); + // check if g lies on the line + g.onLine = (Vector2.Distance(pointA, g) + Vector2.Distance(g, pointB) === Vector2.Distance(pointA, pointB)); + + Vector2.Add(f, self.Radius); + Vector2.Add(g, self.Radius); + + //return {points: {intersection1:f, intersection2:g}, pointOnLine: e}; + //console.log("Two intersections"); + var circleCenter = self.Center(), + vectorAux1 = new Vector2(circleCenter.X - e.X, circleCenter.Y - e.Y), + magnitude1 = vectorAux1.Length(), + d = vectorAux1.Normalize(), + vectorAux3 = new Vector2(circleCenter.X - pointA.X - self.Radius, circleCenter.Y - pointA.Y - self.Radius), + magnitude3 = vectorAux3.Length(), + vectorAux4 = new Vector2(circleCenter.X - pointB.X - self.Radius, circleCenter.Y - pointB.Y - self.Radius), + magnitude4 = vectorAux4.Length(), + overlap = 1; + + if (magnitude1 < self.Radius && (f.onLine || g.onLine)) { + + var pOnLine = null; + + if ((f.onLine && !g.onLine) || (!f.onLine && g.onLine)) { + + if (f.onLine) { + pOnLine = f; + } else { + pOnLine = g; + } + + var vectorAux2 = new Vector2(circleCenter.X - pOnLine.X, circleCenter.Y - pOnLine.Y), + magnitude2 = vectorAux2.Length(); + + d = vectorAux2.Normalize(); + + if (magnitude3 < self.Radius) { + overlap = (new Vector2(pOnLine.X - pointA.X - self.Radius, pOnLine.Y - pointA.Y - self.Radius)).Length(); + } else if (magnitude4 < self.Radius) { + overlap = (new Vector2(pOnLine.X - pointB.X - self.Radius, pOnLine.Y - pointB.Y - self.Radius)).Length(); + } else { + overlap = (self.Radius - magnitude1); + } + + } else if (g.onLine && f.onLine) { + + overlap = (self.Radius - magnitude1); + + } + + return new Vector2(overlap * d.X, overlap * d.Y); + } + } + /*else if (parseInt(eDistCtoE) === parseInt(self.Radius)) { + console.log("Only one intersection"); + //return {points: false, pointOnLine: e}; + return true; + }*/ + + return false; +}; \ No newline at end of file diff --git a/src/JS/XgameJS/Enemy.js b/src/JS/XgameJS/Enemy.js new file mode 100644 index 0000000..7793be9 --- /dev/null +++ b/src/JS/XgameJS/Enemy.js @@ -0,0 +1,108 @@ +/** + * Represents one enemy. + * @constructor + * @param {AnimatedSprite|Sprite} sprite - The enemys's sprite. + */ +function Enemy(sprite) { + "use strict"; + /*globals Vector2, setInterval, AnimatedSprite, SpriteEffects*/ + + this.Sprite = sprite; + + //Physics properties + this.SpeedV = Vector2.Zero(); + this.Speed = 0; + + //Platform game properties + this.IsOnGround = undefined; + + //Enemy States + this.IDLE = 0; + this.MOVING = 1; + this.HITTED = 2; + //this.TURNING = 3; + //[...] + this.CurrentState = 0; + + //Enemy attributtes + this.Life = 5; + + //If the sprite is animated starts the sprite animation + if (this.Sprite instanceof AnimatedSprite) { + this.Sprite.StartAnimation(); + } + + //Change the enemy state every 2 seconds + setInterval(this.ChangeEnemyState.bind(this), 2000); +} + +/** + * Updates de enemy. + * @name Update + * @function + * @param {Number} levelWidth - The width of the level. + * @param {Array} platforms - The platforms array. + * @param {Number} gravityForce - The gravity force. + * @memberOf Enemy + */ +Enemy.prototype.Update = function (levelWidth, platforms, gravityForce) { + "use strict"; + var self = this, + enemySprite = self.Sprite, + bounds = self.Bounds(); + + //TODO: Add your enemy's update logic here. Change this function arguments as you need + + //Screen boundaries + //Left + if (bounds.X < 0) { + self.SpeedV.X = 0; + enemySprite.Position.X = enemySprite.Position.X - bounds.Position.X; + } + //Up + if (bounds.Y < 0) { + self.SpeedV.Y = 0; + enemySprite.Position.Y = enemySprite.Position.Y - bounds.Position.Y; + } + //Right + if (bounds.X + bounds.Width > levelWidth) { + self.SpeedV.X = 0; + enemySprite.Position.X = levelWidth - (enemySprite.Right() - bounds.Right()) - bounds.Width; + } + +}; + +/** + * Changes the enemy state randomly + * @name ChangeEnemysState + * @function + * @memberOf Enemy + */ +Enemy.prototype.ChangeEnemyState = function () { + "use strict"; + /*globals SpriteEffects*/ + var self = this, + enemySprite = self.Sprite; + + //TODO: Change your enemy state logic here +}; + +/** + * The enemys's collision rectangle. + * @name Bounds + * @function + * @memberOf Enemy + */ +Enemy.prototype.Bounds = function () { + "use strict"; + /*globals Rectangle*/ + var self = this, + spriteBounds = self.Sprite.Bounds(); + + return new Rectangle( + spriteBounds.X + spriteBounds.HalfWidth() / 2, + spriteBounds.Y, + spriteBounds.HalfWidth(), + spriteBounds.Height + ); +}; \ No newline at end of file diff --git a/src/JS/XgameJS/GameStates.js b/src/JS/XgameJS/GameStates.js new file mode 100644 index 0000000..bb72ecd --- /dev/null +++ b/src/JS/XgameJS/GameStates.js @@ -0,0 +1,13 @@ +/** + * Defines the Game object states. + * @readonly + * @enum {number} + */ +var GameStates = Object.freeze({ + Initializing: 0, + Loading: 1, + Playing: 2, + Paused: 3, + GameWin: 4, + GameOver: 5 +}); \ No newline at end of file diff --git a/src/JS/XgameJS/GravityDirections.js b/src/JS/XgameJS/GravityDirections.js new file mode 100644 index 0000000..f4ab9c3 --- /dev/null +++ b/src/JS/XgameJS/GravityDirections.js @@ -0,0 +1,11 @@ +/** + * Defines the gravity directions. + * @readonly + * @enum {number} + */ +var GravityDirections = Object.freeze({ + "G_DOWN": 0, + "G_UP": 1, + "G_LEFT": 2, + "G_RIGHT": 3 +}); \ No newline at end of file diff --git a/src/JS/XgameJS/PickableObject.js b/src/JS/XgameJS/PickableObject.js new file mode 100644 index 0000000..9356c16 --- /dev/null +++ b/src/JS/XgameJS/PickableObject.js @@ -0,0 +1,37 @@ +/** + * Defines a pickable object. + * @constructor + * @param {Sprite|AnimatedSprite} sprite - The sprite of the object. + * @param {PickableObjectTypes} type - The object type. + */ +function PickableObject(sprite, type) { + "use strict"; + /*globals AnimatedSprite*/ + this.Sprite = sprite; + this.Type = type; + + //If th sprite is animated starts the sprite animation + if (this.Sprite instanceof AnimatedSprite) { + this.Sprite.StartAnimation(); + } +} + +/** + * The collision rectangle of the pickable object. + * @name Update + * @function + * @memberOf PickableObject + */ +PickableObject.prototype.Bounds = function () { + "use strict"; + /*globals Rectangle*/ + var self = this, + spriteBounds = self.Sprite.Bounds(); + + return new Rectangle( + spriteBounds.X + spriteBounds.HalfWidth() / 2, + spriteBounds.Y + spriteBounds.HalfHeight() / 2, + spriteBounds.HalfWidth(), + spriteBounds.HalfHeight() + ); +}; \ No newline at end of file diff --git a/src/JS/XgameJS/Player.js b/src/JS/XgameJS/Player.js new file mode 100644 index 0000000..e1c01af --- /dev/null +++ b/src/JS/XgameJS/Player.js @@ -0,0 +1,93 @@ +/** + * Represents the player. + * @constructor + * @param {AnimatedSprite|Sprite} sprite - The player's sprite. + */ +function Player(sprite) { + "use strict"; + /*globals Vector2, AnimatedSprite*/ + this.Sprite = sprite; //The player sprite + + //Physics properties + this.SpeedV = Vector2.Zero(); + this.AccelerationV = Vector2.Zero(); + this.SpeedLimit = 4; + this.GroundFriction = 1; + + //Platform game properties + this.IsOnGround = undefined; + this.JumpForce = -8; + + //Player States + this.IDLE = 0; + this.MOVING = 3; + this.JUMPING = 4; + //this.CROUCHED = 4; + //[...] + this.CurrentState = 0; + + this.Life = 10; + + //If the sprite is animated starts the sprite animation + if (this.Sprite instanceof AnimatedSprite) { + this.Sprite.StartAnimation(); + } +} + +/** + * Updates de player. + * @name Update + * @function + * @param {Boolean} moveLeft - Tells if the player moved left or not. + * @param {Boolean} moveRight - Tells if the player moved right or not. + * @param {Boolean} jump - Tells if the player jumped or not. + * @param {Number} levelWidth - The width of the level. + * @param {Number} gravityForce - The gravity force. + * @memberOf Player + */ +Player.prototype.Update = function (moveLeft, moveRight, jump, levelWidth, gravityForce) { + "use strict"; + /*globals SpriteEffects*/ + var self = this, + playerSprite = self.Sprite, + bounds = self.Bounds(); + + //TODO: Add your player's update logic here. Change this function arguments as you need + + //Screen boundaries + //Left + if (bounds.X < 0) { + self.SpeedV.X = 0; + playerSprite.Position.X = playerSprite.Position.X - bounds.X; + } + //Up + if (bounds.Y < 0) { + self.SpeedV.Y = 0; + playerSprite.Position.Y = playerSprite.Position.Y - bounds.Y; + } + //Right + if (bounds.X + bounds.Width > levelWidth) { + self.SpeedV.X = 0; + playerSprite.Position.X = levelWidth - (playerSprite.Right() - bounds.Right()) - bounds.Width; + } +}; + +/** + * The player's collision rectangle. + * @name Bounds + * @function + * @memberOf Player + */ +Player.prototype.Bounds = function () { + "use strict"; + /*globals Rectangle*/ + var self = this, + spriteBounds = self.Sprite.Bounds(); + + return new Rectangle( + spriteBounds.X + spriteBounds.HalfWidth() / 2, + spriteBounds.Y, + spriteBounds.HalfWidth(), + spriteBounds.Height + ); +}; \ No newline at end of file diff --git a/src/JS/XgameJS/Polygon.js b/src/JS/XgameJS/Polygon.js new file mode 100644 index 0000000..ea09744 --- /dev/null +++ b/src/JS/XgameJS/Polygon.js @@ -0,0 +1,21 @@ +/** + * Defines a polygon. + * @constructor + * @param {Array} segments - An array with the segments that conform the polygon. + */ +function Polygon(segments) { + "use strict"; + this.Segments = segments; +} + +/** + * Gets the number of vertex of the polygon. + * @name NumberOfVertex + * @function + * @memberOf Polygon + */ +Polygon.prototype.NumberOfVertex = function () { + "use strict"; + return this.Segments.length; +}; + diff --git a/src/JS/XgameJS/Projectile.js b/src/JS/XgameJS/Projectile.js new file mode 100644 index 0000000..206c705 --- /dev/null +++ b/src/JS/XgameJS/Projectile.js @@ -0,0 +1,31 @@ +/** + * Represents a projectile. + * @constructor + * @param {Sprite} sprite - The sprite of the punch. + */ +function Projectile(sprite) { + "use strict"; + /*globals Vector2*/ + this.Sprite = sprite; + this.Speed = 6; + this.Power = 1; + this.SpeedV = Vector2.Zero(); +} + +/** + * Updates de projectile. + * @name Update + * @function + * @param {Sprite} playerSprite - The player's sprite. + * @param {Number} levelWidth - The width of the level. + * @memberOf Projectile + */ +Projectile.prototype.Update = function () { + "use strict"; + /*globals SpriteEffects*/ + var self = this, + projectileSprite = self.Sprite, + bounds = projectileSprite.Bounds(); + + //TODO: Add your projectile's update logic here. Change this function arguments as you need +}; \ No newline at end of file diff --git a/src/JS/XgameJS/Segment.js b/src/JS/XgameJS/Segment.js new file mode 100644 index 0000000..51a8842 --- /dev/null +++ b/src/JS/XgameJS/Segment.js @@ -0,0 +1,39 @@ +/** + * Represents a 2D segment, which is composed of two points. + * @constructor + * @param {Point} pointA - The A point of the segment. + * @param {Point} pointB - The B point of the segment. + */ +function Segment(pointA, pointB) { + "use strict"; + /*global Vector2*/ + this.pointA = pointA; + this.pointB = pointB; +} + +/** + * Gets the distance of the segment. + * @name Distance + * @function + * @memberOf Segment + */ +Segment.prototype.Distance = function () { + "use strict"; + var self = this; + + return Math.sqrt(Math.pow((self.pointB.X - self.pointA.X), 2) + Math.pow((self.pointB.Y - self.pointA.Y), 2)); +}; + +/** + * Gets the direction vector of the segment. + * @name DirectionVector + * @function + * @memberOf Segment + */ +Segment.prototype.DirectionVector = function () { + "use strict"; + var self = this, + distance = self.Distance(); + + return new Vector2((self.pointB.X - self.pointA.X) / distance, (self.pointB.Y - self.pointA.Y) / distance); +}; \ No newline at end of file diff --git a/src/JS/XgameJS/Sprite.js b/src/JS/XgameJS/Sprite.js new file mode 100644 index 0000000..d1539a7 --- /dev/null +++ b/src/JS/XgameJS/Sprite.js @@ -0,0 +1,145 @@ +/** + * Represents a sprite, which is composed of a Texture2D and other properties. + * @constructor + * @param {Texture2D} texture - The texture image. + * @param {Vector2} scale - The scale vector of the image. + * @param {Rectangle} sourceRect - The image source rectangle. + * @param {Point} position - The sprite position in the canvas. + * @param {Boolean} isVisible - Determines if the sprite is visible or not. + */ +function Sprite(texture, scale, sourceRect, position, isVisible) { + "use strict"; + /*global SpriteEffects*/ + this.Texture = texture; + this.Scale = scale; + this.SourceRect = sourceRect; + this.Position = position; + this.IsVisible = isVisible; + this.SpriteEffects = SpriteEffects.None; + this.Rotation = 0; +} + +/** + * Gets the width of the sprite. + * @name Width + * @function + * @memberOf Sprite + */ +Sprite.prototype.Width = function () { + "use strict"; + var self = this, + aspectRatio = self.Texture.Width() / self.Texture.Height(), + sourceAspectRatio = self.SourceRect.Width / self.SourceRect.Height; + + if (aspectRatio !== sourceAspectRatio) { + return (self.Texture.Width() * self.Scale.X) / aspectRatio; + } else { + return self.Texture.Width() * self.Scale.X; + } + //return this.Texture.Width() * this.Scale.X; +}; + +/** + * Gets the height of the sprite. + * @name Height + * @function + * @memberOf Sprite + */ +Sprite.prototype.Height = function () { + "use strict"; + return this.Texture.Height() * this.Scale.Y; +}; + +/** + * Gets half of the width of the texture. + * @name HalfWidth + * @function + * @memberOf Sprite + */ +Sprite.prototype.HalfWidth = function () { + "use strict"; + return this.Width() / 2; +}; + +/** + * Gets half of the height of the texture. + * @name HalfHeight + * @function + * @memberOf Sprite + */ +Sprite.prototype.HalfHeight = function () { + "use strict"; + return this.Height() / 2; +}; + +/** + * Gets the Point that specifies the center of the sprite. + * @name Center + * @function + * @memberOf Sprite + */ +Sprite.prototype.Center = function () { + "use strict"; + /*global Point*/ + var self = this; + + return new Point(self.Position.X + self.HalfWidth(), self.Position.Y + self.HalfHeight()); +}; + +/** + * Returns the y-coordinate of the top of the sprite. + * @name Top + * @function + * @memberOf Sprite + */ +Sprite.prototype.Top = function () { + "use strict"; + return this.Position.Y; +}; + +/** + * Returns the y-coordinate of the bottom of the sprite. + * @name Bottom + * @function + * @memberOf Sprite + */ +Sprite.prototype.Bottom = function () { + "use strict"; + return this.Position.Y + this.Height(); +}; + +/** + * Returns the x-coordinate of the left side of the sprite. + * @name Left + * @function + * @memberOf Sprite + */ +Sprite.prototype.Left = function () { + "use strict"; + return this.Position.X; +}; + +/** + * Returns the x-coordinate of the right side of the sprite. + * @name Right + * @function + * @memberOf Sprite + */ +Sprite.prototype.Right = function () { + "use strict"; + return this.Position.X + this.Width(); +}; + +/** + * Returns the rectangle bounds of the sprite. + * @name Bounds + * @function + * @memberOf Sprite + */ +Sprite.prototype.Bounds = function () { + "use strict"; + /*global Rectangle*/ + var self = this; + + return new Rectangle(self.Position.X, self.Position.Y, self.Width(), self.Height()); +}; \ No newline at end of file diff --git a/src/JS/XgameJS/requestAnimationFramePolyfill.js b/src/JS/XgameJS/requestAnimationFramePolyfill.js new file mode 100644 index 0000000..fba09ca --- /dev/null +++ b/src/JS/XgameJS/requestAnimationFramePolyfill.js @@ -0,0 +1,38 @@ +// http://paulirish.com/2011/requestanimationframe-for-smart-animating/ +// http://my.opera.com/emoller/blog/2011/12/20/requestanimationframe-for-smart-er-animating + +// requestAnimationFrame polyfill by Erik Möller +// fixes from Paul Irish and Tino Zijdel +// JSLint and JSHint fixes by Víctor Hernández Molpeceres + +(function () { + "use strict"; + /*global window, clearTimeout*/ + var lastTime = 0, + vendors = ['ms', 'moz', 'webkit', 'o'], + x; + + for (x = 0; x < vendors.length && !window.requestAnimationFrame; x += 1) { + window.requestAnimationFrame = window[vendors[x] + 'RequestAnimationFrame']; + window.cancelAnimationFrame = window[vendors[x] + 'CancelAnimationFrame'] || window[vendors[x] + 'CancelRequestAnimationFrame']; + } + + if (!window.requestAnimationFrame) { + window.requestAnimationFrame = function (callback, element) { + var currTime = new Date().getTime(), + timeToCall = Math.max(0, 16 - (currTime - lastTime)), + id = window.setTimeout(function () { + callback(currTime + timeToCall); + }, timeToCall); + lastTime = currTime + timeToCall; + return id; + }; + } + + if (!window.cancelAnimationFrame) { + window.cancelAnimationFrame = function (id) { + clearTimeout(id); + }; + } + +}()); \ No newline at end of file