From ced3d03bdb3ce866d832e03fb212865140905a9a Mon Sep 17 00:00:00 2001 From: Thomas Leyh Date: Sun, 24 Jul 2016 08:14:18 +0200 Subject: Add project files. --- GDD.pdf | Bin 0 -> 1782703 bytes LICENCE.txt | 23 + README.en.md | 27 + README.md | 52 + Screenshots/screen1.jpg | Bin 0 -> 402109 bytes Screenshots/screen1_s.jpg | Bin 0 -> 61808 bytes Screenshots/screen2.jpg | Bin 0 -> 344205 bytes Screenshots/screen2_s.jpg | Bin 0 -> 58565 bytes Screenshots/screen3.jpg | Bin 0 -> 366165 bytes Screenshots/screen3_s.jpg | Bin 0 -> 53758 bytes V3.sln | 43 + V3/AI/ActionState.cs | 25 + V3/AI/AiState.cs | 27 + V3/AI/IAction.cs | 24 + V3/AI/IAiPlayer.cs | 51 + V3/AI/IStrategy.cs | 17 + V3/AI/IWorldView.cs | 21 + V3/AI/Internal/AbstractAction.cs | 38 + V3/AI/Internal/AiPlayer.cs | 244 ++++ V3/AI/Internal/AttackStrategy.cs | 48 + V3/AI/Internal/IActionFactory.cs | 27 + V3/AI/Internal/MoveAction.cs | 53 + V3/AI/Internal/SpawnAction.cs | 42 + V3/AI/Internal/WorldView.cs | 19 + V3/AchievementsAndStatistics.cs | 31 + V3/Bindings.cs | 75 ++ V3/CONTROLS.md | 37 + V3/CREDITS.md | 51 + V3/Camera/CameraCentered.cs | 57 + V3/Camera/CameraManager.cs | 71 ++ V3/Camera/CameraScrolling.cs | 96 ++ V3/Camera/CameraType.cs | 8 + V3/Camera/ICamera.cs | 18 + V3/ClassDiagram1.cd | 2 + V3/Content/Buttons/Button-01.png | Bin 0 -> 99135 bytes V3/Content/Buttons/Button-01_Pressed.png | Bin 0 -> 112006 bytes V3/Content/Buttons/Button-02.png | Bin 0 -> 55248 bytes V3/Content/Buttons/Button-02_Pressed.png | Bin 0 -> 66371 bytes V3/Content/Buttons/Button-03.png | Bin 0 -> 64359 bytes V3/Content/Buttons/Button-03_Pressed.png | Bin 0 -> 75343 bytes V3/Content/Buttons/Button-04.png | Bin 0 -> 56617 bytes V3/Content/Buttons/Button-04_Pressed.png | Bin 0 -> 67959 bytes V3/Content/Buttons/Button-05.png | Bin 0 -> 70658 bytes V3/Content/Buttons/Button-05_Pressed.png | Bin 0 -> 82438 bytes V3/Content/Buttons/Button-06.png | Bin 0 -> 54510 bytes V3/Content/Buttons/Button-06_Pressed.png | Bin 0 -> 66074 bytes V3/Content/Buttons/Button-07.png | Bin 0 -> 72189 bytes V3/Content/Buttons/Button-07_Pressed.png | Bin 0 -> 84575 bytes V3/Content/Content.mgcb | 1092 +++++++++++++++++ V3/Content/Effects/blood_hit_01.png | Bin 0 -> 109054 bytes V3/Content/Effects/blood_hit_02.png | Bin 0 -> 38081 bytes V3/Content/Effects/blood_hit_03.png | Bin 0 -> 41343 bytes V3/Content/Effects/blood_hit_04.png | Bin 0 -> 91450 bytes V3/Content/Effects/blood_hit_05.png | Bin 0 -> 71750 bytes V3/Content/Effects/blood_hit_06.png | Bin 0 -> 36776 bytes V3/Content/Effects/blood_hit_08.png | Bin 0 -> 115643 bytes V3/Content/Effects/explosion.png | Bin 0 -> 2623088 bytes V3/Content/Effects/particlefx_03.png | Bin 0 -> 972652 bytes V3/Content/Effects/particlefx_04.png | Bin 0 -> 821590 bytes V3/Content/Effects/particlefx_05.png | Bin 0 -> 544650 bytes V3/Content/Effects/quake.png | Bin 0 -> 122179 bytes V3/Content/Fonts/Blutschrift.ttf | Bin 0 -> 256596 bytes V3/Content/Fonts/DeathFont.spritefont | 50 + V3/Content/Fonts/DejaVuSans.ttf | Bin 0 -> 756072 bytes V3/Content/Fonts/MenuFont.spritefont | 50 + V3/Content/Fonts/Siegesschriftzug.ttf | Bin 0 -> 1081476 bytes V3/Content/Fonts/UnitFont.spritefont | 50 + V3/Content/Fonts/VictoryFont.spritefont | 50 + V3/Content/Fonts/grabstein.ttf | Bin 0 -> 21676 bytes V3/Content/Maps/map_grassland.tmx | 988 +++++++++++++++ V3/Content/Maps/techdemo.tmx | 1170 ++++++++++++++++++ V3/Content/Maps/work_in_progress.tmx | 1258 ++++++++++++++++++++ V3/Content/Menu/Titel.png | Bin 0 -> 91996 bytes V3/Content/Menu/arrow_white.png | Bin 0 -> 3981 bytes V3/Content/Menu/mainscreen.jpg | Bin 0 -> 3376885 bytes V3/Content/Sounds/Afraid_to_Go.mp3 | Bin 0 -> 6975318 bytes V3/Content/Sounds/Knight.wav | Bin 0 -> 1947210 bytes V3/Content/Sounds/Kosta_T_-_06.mp3 | Bin 0 -> 11340892 bytes .../Sounds/Monster_Gigante-Doberman-1334685792.wav | Bin 0 -> 1175132 bytes V3/Content/Sounds/Mummy_Zombie-SoundBible.wav | Bin 0 -> 357466 bytes V3/Content/Sounds/SkeletonHorse.wav | Bin 0 -> 2759074 bytes V3/Content/Sounds/explode.wav | Bin 0 -> 303992 bytes V3/Content/Sounds/explodemini.wav | Bin 0 -> 277340 bytes V3/Content/Sounds/explosion1.ogg | Bin 0 -> 37165 bytes V3/Content/Sounds/horse.wav | Bin 0 -> 14032 bytes V3/Content/Sounds/impactsplat01.ogg | Bin 0 -> 21825 bytes V3/Content/Sounds/punch.wav | Bin 0 -> 140058 bytes V3/Content/Sounds/walking.wav | Bin 0 -> 2102948 bytes V3/Content/Sounds/zonk2.wav | Bin 0 -> 95374 bytes V3/Content/Sources/Horse.blend | Bin 0 -> 11055184 bytes V3/Content/Sources/Skeleton.blend | Bin 0 -> 1101828 bytes V3/Content/Sources/SkeletonHorse.blend | Bin 0 -> 2900188 bytes V3/Content/Sources/SkeletonHorse.png | Bin 0 -> 1013788 bytes V3/Content/Sources/SkeletonRider.blend | Bin 0 -> 4551660 bytes V3/Content/Sources/SkeletonRider.png | Bin 0 -> 734006 bytes V3/Content/Sources/ZombieWithClub.png | Bin 0 -> 921761 bytes V3/Content/Sources/castle.xcf | Bin 0 -> 525634 bytes V3/Content/Sources/create_spritesheet.sh | 7 + V3/Content/Sources/fleischklops.blend | Bin 0 -> 2307520 bytes V3/Content/Sources/fleischklops.xcf | Bin 0 -> 1387154 bytes V3/Content/Sources/horse_paint.png | Bin 0 -> 898326 bytes V3/Content/Sources/horse_paint_sc.png | Bin 0 -> 1460647 bytes V3/Content/Sources/horse_tack.png | Bin 0 -> 879871 bytes V3/Content/Sources/houses_front.xcf | Bin 0 -> 221614 bytes V3/Content/Sources/houses_rear.xcf | Bin 0 -> 205943 bytes V3/Content/Sources/human_construction_set.xcf | Bin 0 -> 10007151 bytes .../Sources/human_construction_set_female.xcf | Bin 0 -> 6728872 bytes V3/Content/Sources/king.blend | Bin 0 -> 4472284 bytes V3/Content/Sources/king_head.png | Bin 0 -> 131639 bytes V3/Content/Sources/necromancer.xcf | Bin 0 -> 5307898 bytes V3/Content/Sources/pathfinder.xcf | Bin 0 -> 2470 bytes V3/Content/Sources/prince.blend | Bin 0 -> 3927028 bytes V3/Content/Sources/prince.xcf | Bin 0 -> 2523537 bytes V3/Content/Sources/selection.xcf | Bin 0 -> 151080 bytes V3/Content/Sources/skeleton_horse.png | Bin 0 -> 1083757 bytes V3/Content/Sources/the_triumph_of_death.jpg | Bin 0 -> 3376885 bytes V3/Content/Sources/zombie.blend | Bin 0 -> 1563140 bytes V3/Content/Sprites/WhiteRectangle.png | Bin 0 -> 67 bytes V3/Content/Sprites/arrows.png | Bin 0 -> 4218 bytes V3/Content/Sprites/buckler.png | Bin 0 -> 189331 bytes V3/Content/Sprites/buckler_female.png | Bin 0 -> 150081 bytes V3/Content/Sprites/chain.png | Bin 0 -> 680942 bytes V3/Content/Sprites/chain_female.png | Bin 0 -> 594899 bytes V3/Content/Sprites/cloth.png | Bin 0 -> 627879 bytes V3/Content/Sprites/cloth_female.png | Bin 0 -> 560029 bytes V3/Content/Sprites/cloud.png | Bin 0 -> 54576 bytes V3/Content/Sprites/ellipse.png | Bin 0 -> 10943 bytes V3/Content/Sprites/fleischklops.png | Bin 0 -> 2466843 bytes V3/Content/Sprites/fog.png | Bin 0 -> 44834 bytes V3/Content/Sprites/head.png | Bin 0 -> 105453 bytes V3/Content/Sprites/head_bald.png | Bin 0 -> 107161 bytes V3/Content/Sprites/head_chain.png | Bin 0 -> 145589 bytes V3/Content/Sprites/head_chain_female.png | Bin 0 -> 134925 bytes V3/Content/Sprites/head_female.png | Bin 0 -> 120410 bytes V3/Content/Sprites/head_plate.png | Bin 0 -> 158766 bytes V3/Content/Sprites/head_plate_female.png | Bin 0 -> 146096 bytes V3/Content/Sprites/king.png | Bin 0 -> 822995 bytes V3/Content/Sprites/longsword.png | Bin 0 -> 145022 bytes V3/Content/Sprites/longsword_female.png | Bin 0 -> 156551 bytes V3/Content/Sprites/necromancer.png | Bin 0 -> 705759 bytes V3/Content/Sprites/necromancer_female.png | Bin 0 -> 659280 bytes V3/Content/Sprites/nude.png | Bin 0 -> 632199 bytes V3/Content/Sprites/nude_female.png | Bin 0 -> 567054 bytes V3/Content/Sprites/plate.png | Bin 0 -> 702344 bytes V3/Content/Sprites/plate_female.png | Bin 0 -> 623813 bytes V3/Content/Sprites/prince.png | Bin 0 -> 855383 bytes V3/Content/Sprites/selection.png | Bin 0 -> 1327 bytes V3/Content/Sprites/shield.png | Bin 0 -> 253328 bytes V3/Content/Sprites/shield_female.png | Bin 0 -> 257298 bytes V3/Content/Sprites/shortsword.png | Bin 0 -> 91334 bytes V3/Content/Sprites/shortsword_female.png | Bin 0 -> 99034 bytes V3/Content/Sprites/skeleton.png | Bin 0 -> 950304 bytes V3/Content/Sprites/skeleton_archer.png | Bin 0 -> 1082133 bytes V3/Content/Sprites/skeleton_elite.png | Bin 0 -> 1191913 bytes V3/Content/Sprites/skeleton_horse.png | Bin 0 -> 1013788 bytes V3/Content/Sprites/skeleton_rider.png | Bin 0 -> 734006 bytes V3/Content/Sprites/staff.png | Bin 0 -> 324639 bytes V3/Content/Sprites/staff_female.png | Bin 0 -> 336664 bytes V3/Content/Sprites/zombie.png | Bin 0 -> 801160 bytes V3/Content/Sprites/zombie_club.png | Bin 0 -> 921761 bytes V3/Content/Textures/EmptyPixel.png | Bin 0 -> 169 bytes V3/Content/Textures/castle.png | Bin 0 -> 1668329 bytes V3/Content/Textures/grassland.png | Bin 0 -> 430934 bytes V3/Content/Textures/grassland_trees.png | Bin 0 -> 445999 bytes V3/Content/Textures/grassland_water.png | Bin 0 -> 254809 bytes V3/Content/Textures/houses_front.png | Bin 0 -> 287910 bytes V3/Content/Textures/houses_rear.png | Bin 0 -> 302161 bytes V3/Content/Textures/medieval_building_tiles.png | Bin 0 -> 515727 bytes V3/Content/Textures/pathfinder.png | Bin 0 -> 289 bytes V3/Data/DebugMode.cs | 21 + V3/Data/GameState.cs | 64 + V3/Data/IGameStateManager.cs | 20 + V3/Data/IOptionsManager.cs | 18 + V3/Data/IPathManager.cs | 30 + V3/Data/ISaveGame.cs | 25 + V3/Data/ISaveGameManager.cs | 25 + V3/Data/Internal/GameStateManager.cs | 81 ++ V3/Data/Internal/OptionsManager.cs | 65 + V3/Data/Internal/PathManager.cs | 51 + V3/Data/Internal/SaveGame.cs | 65 + V3/Data/Internal/SaveGameManager.cs | 88 ++ V3/Data/Options.cs | 105 ++ V3/Effects/AbstractEffect.cs | 74 ++ V3/Effects/BloodBang.cs | 8 + V3/Effects/BloodExplosion.cs | 11 + V3/Effects/BloodFountain.cs | 11 + V3/Effects/EffectsManager.cs | 54 + V3/Effects/Explosion.cs | 14 + V3/Effects/HorseEffect.cs | 11 + V3/Effects/IEffect.cs | 44 + V3/Effects/IEffectsManager.cs | 31 + V3/Effects/Quake.cs | 11 + V3/Effects/SmokeBig.cs | 10 + V3/Effects/SmokeMedium.cs | 13 + V3/Effects/SmokeSmall.cs | 10 + V3/Ellipse.cs | 31 + V3/Faction.cs | 7 + V3/Icon.ico | Bin 0 -> 32038 bytes V3/Input/IInputManager.cs | 34 + V3/Input/IKeyEvent.cs | 20 + V3/Input/IMouseEvent.cs | 34 + V3/Input/IMouseEventHandler.cs | 14 + V3/Input/Internal/InputManager.cs | 141 +++ V3/Input/Internal/KeyEvent.cs | 32 + V3/Input/Internal/MouseEvent.cs | 57 + V3/Input/MouseButton.cs | 9 + V3/Map/AbstractLayer.cs | 259 ++++ V3/Map/Area.cs | 119 ++ V3/Map/Constants.cs | 12 + V3/Map/FloorLayer.cs | 21 + V3/Map/FogOfWar.cs | 107 ++ V3/Map/IMapManager.cs | 88 ++ V3/Map/MapManager.cs | 97 ++ V3/Map/ObjectLayer.cs | 16 + V3/Map/Pathfinder.cs | 455 +++++++ V3/Map/PathfindingGrid.cs | 125 ++ V3/Map/SearchNode.cs | 31 + V3/Map/TiledParser.cs | 256 ++++ V3/Map/Tileset.cs | 89 ++ V3/Node.cs | 467 ++++++++ V3/Objects/AbstractBuilding.cs | 110 ++ V3/Objects/AbstractCreature.cs | 911 ++++++++++++++ V3/Objects/Arrow.cs | 109 ++ V3/Objects/BuildingState.cs | 8 + V3/Objects/Castle.cs | 15 + V3/Objects/CreatureFactory.cs | 127 ++ V3/Objects/FemalePeasant.cs | 50 + V3/Objects/Forge.cs | 19 + V3/Objects/IBasicCreatureFactory.cs | 28 + V3/Objects/IBuilding.cs | 20 + V3/Objects/ICreature.cs | 120 ++ V3/Objects/IGameObject.cs | 43 + V3/Objects/IObjectsManager.cs | 131 ++ V3/Objects/IdGenerator.cs | 59 + V3/Objects/King.cs | 33 + V3/Objects/KingsGuard.cs | 62 + V3/Objects/Knight.cs | 65 + V3/Objects/MalePeasant.cs | 49 + V3/Objects/Meatball.cs | 36 + V3/Objects/Movement.cs | 20 + V3/Objects/Movement/CountStepsMovement.cs | 16 + V3/Objects/Movement/IMovable.cs | 43 + V3/Objects/Movement/PlayerMovement.cs | 155 +++ V3/Objects/Necromancer.cs | 61 + V3/Objects/ObjectsManager.cs | 314 +++++ V3/Objects/Prince.cs | 33 + V3/Objects/Selection.cs | 483 ++++++++ V3/Objects/Skeleton.cs | 65 + V3/Objects/SkeletonElite.cs | 19 + V3/Objects/SkeletonHorse.cs | 87 ++ V3/Objects/Sprite/AbstractSpriteCreature.cs | 201 ++++ V3/Objects/Sprite/ArrowSprite.cs | 42 + V3/Objects/Sprite/BucklerFemaleSprite.cs | 7 + V3/Objects/Sprite/BucklerSprite.cs | 7 + V3/Objects/Sprite/ChainFemaleSprite.cs | 7 + V3/Objects/Sprite/ChainSprite.cs | 7 + V3/Objects/Sprite/ClothFemaleSprite.cs | 7 + V3/Objects/Sprite/ClothSprite.cs | 7 + V3/Objects/Sprite/EquipmentType.cs | 10 + V3/Objects/Sprite/HeadBaldSprite.cs | 10 + V3/Objects/Sprite/HeadChainFemaleSprite.cs | 7 + V3/Objects/Sprite/HeadChainSprite.cs | 7 + V3/Objects/Sprite/HeadFemaleSprite.cs | 7 + V3/Objects/Sprite/HeadPlateFemaleSprite.cs | 7 + V3/Objects/Sprite/HeadPlateSprite.cs | 7 + V3/Objects/Sprite/HeadSprite.cs | 7 + V3/Objects/Sprite/ISpriteCreature.cs | 53 + V3/Objects/Sprite/KingSprite.cs | 7 + V3/Objects/Sprite/LongswordFemaleSprite.cs | 7 + V3/Objects/Sprite/LongswordSprite.cs | 7 + V3/Objects/Sprite/MeatballSprite.cs | 11 + V3/Objects/Sprite/NecromancerFemaleSprite.cs | 7 + V3/Objects/Sprite/NecromancerSprite.cs | 7 + V3/Objects/Sprite/NudeFemaleSprite.cs | 7 + V3/Objects/Sprite/NudeSprite.cs | 7 + V3/Objects/Sprite/PlateFemaleSprite.cs | 7 + V3/Objects/Sprite/PlateSprite.cs | 7 + V3/Objects/Sprite/PrinceSprite.cs | 7 + V3/Objects/Sprite/ShieldFemaleSprite.cs | 7 + V3/Objects/Sprite/ShieldSprite.cs | 7 + V3/Objects/Sprite/ShortswordFemaleSprite.cs | 7 + V3/Objects/Sprite/ShortswordSprite.cs | 7 + V3/Objects/Sprite/SkeletonArcherSprite.cs | 10 + V3/Objects/Sprite/SkeletonEliteSprite.cs | 9 + V3/Objects/Sprite/SkeletonHorseSprite.cs | 7 + V3/Objects/Sprite/SkeletonRiderSprite.cs | 10 + V3/Objects/Sprite/SkeletonSprite.cs | 9 + V3/Objects/Sprite/StaffFemaleSprite.cs | 7 + V3/Objects/Sprite/StaffSprite.cs | 7 + V3/Objects/Sprite/ZombieSprite.cs | 11 + V3/Objects/Sprite/ZombieWithClubSprite.cs | 11 + V3/Objects/TextureObject.cs | 76 ++ V3/Objects/Transformation.cs | 102 ++ V3/Objects/Woodhouse.cs | 16 + V3/Objects/Zombie.cs | 45 + V3/OpenTK.dll.config | 25 + V3/Program.cs | 20 + V3/Properties/AssemblyInfo.cs | 35 + V3/Quadtree.cs | 87 ++ V3/Screens/AbstractScreen.cs | 57 + V3/Screens/AchievementsScreen.cs | 221 ++++ V3/Screens/DeathScreen.cs | 140 +++ V3/Screens/DebugScreen.cs | 92 ++ V3/Screens/FpsCounter.cs | 46 + V3/Screens/GameScreen.cs | 306 +++++ V3/Screens/HudScreen.cs | 349 ++++++ V3/Screens/IDrawable.cs | 19 + V3/Screens/IScreen.cs | 39 + V3/Screens/IScreenFactory.cs | 27 + V3/Screens/IScreenManager.cs | 35 + V3/Screens/IUpdatable.cs | 16 + V3/Screens/LoadScreen.cs | 124 ++ V3/Screens/MainScreen.cs | 195 +++ V3/Screens/MenuActions.cs | 208 ++++ V3/Screens/OptionsScreen.cs | 197 +++ V3/Screens/PauseScreen.cs | 140 +++ V3/Screens/ScreenManager.cs | 164 +++ V3/Screens/StatisticsScreen.cs | 186 +++ V3/Screens/TechdemoScreen.cs | 325 +++++ V3/Screens/VictoryScreen.cs | 76 ++ V3/UpdatesPerSecond.cs | 55 + V3/V3.csproj | 498 ++++++++ V3/V3Game.cs | 78 ++ V3/Widgets/AbstractMenu.cs | 96 ++ V3/Widgets/AbstractTextWidget.cs | 113 ++ V3/Widgets/AchievementBox.cs | 91 ++ V3/Widgets/Button.cs | 111 ++ V3/Widgets/EmptyWidget.cs | 41 + V3/Widgets/FormMenu.cs | 75 ++ V3/Widgets/HorizontalOrientation.cs | 9 + V3/Widgets/IBasicWidgetFactory.cs | 38 + V3/Widgets/IClickable.cs | 14 + V3/Widgets/IImageWidget.cs | 15 + V3/Widgets/IMenu.cs | 33 + V3/Widgets/IMenuFactory.cs | 9 + V3/Widgets/ISelectable.cs | 27 + V3/Widgets/ITextWidget.cs | 43 + V3/Widgets/IWidget.cs | 34 + V3/Widgets/Label.cs | 14 + V3/Widgets/SelectButton.cs | 108 ++ V3/Widgets/VerticalMenu.cs | 42 + V3/Widgets/WidgetFactory.cs | 78 ++ V3/packages.config | 6 + 343 files changed, 18300 insertions(+) create mode 100644 GDD.pdf create mode 100644 LICENCE.txt create mode 100644 README.en.md create mode 100644 README.md create mode 100644 Screenshots/screen1.jpg create mode 100644 Screenshots/screen1_s.jpg create mode 100644 Screenshots/screen2.jpg create mode 100644 Screenshots/screen2_s.jpg create mode 100644 Screenshots/screen3.jpg create mode 100644 Screenshots/screen3_s.jpg create mode 100644 V3.sln create mode 100644 V3/AI/ActionState.cs create mode 100644 V3/AI/AiState.cs create mode 100644 V3/AI/IAction.cs create mode 100644 V3/AI/IAiPlayer.cs create mode 100644 V3/AI/IStrategy.cs create mode 100644 V3/AI/IWorldView.cs create mode 100644 V3/AI/Internal/AbstractAction.cs create mode 100644 V3/AI/Internal/AiPlayer.cs create mode 100644 V3/AI/Internal/AttackStrategy.cs create mode 100644 V3/AI/Internal/IActionFactory.cs create mode 100644 V3/AI/Internal/MoveAction.cs create mode 100644 V3/AI/Internal/SpawnAction.cs create mode 100644 V3/AI/Internal/WorldView.cs create mode 100644 V3/AchievementsAndStatistics.cs create mode 100644 V3/Bindings.cs create mode 100644 V3/CONTROLS.md create mode 100644 V3/CREDITS.md create mode 100644 V3/Camera/CameraCentered.cs create mode 100644 V3/Camera/CameraManager.cs create mode 100644 V3/Camera/CameraScrolling.cs create mode 100644 V3/Camera/CameraType.cs create mode 100644 V3/Camera/ICamera.cs create mode 100644 V3/ClassDiagram1.cd create mode 100644 V3/Content/Buttons/Button-01.png create mode 100644 V3/Content/Buttons/Button-01_Pressed.png create mode 100644 V3/Content/Buttons/Button-02.png create mode 100644 V3/Content/Buttons/Button-02_Pressed.png create mode 100644 V3/Content/Buttons/Button-03.png create mode 100644 V3/Content/Buttons/Button-03_Pressed.png create mode 100644 V3/Content/Buttons/Button-04.png create mode 100644 V3/Content/Buttons/Button-04_Pressed.png create mode 100644 V3/Content/Buttons/Button-05.png create mode 100644 V3/Content/Buttons/Button-05_Pressed.png create mode 100644 V3/Content/Buttons/Button-06.png create mode 100644 V3/Content/Buttons/Button-06_Pressed.png create mode 100644 V3/Content/Buttons/Button-07.png create mode 100644 V3/Content/Buttons/Button-07_Pressed.png create mode 100644 V3/Content/Content.mgcb create mode 100644 V3/Content/Effects/blood_hit_01.png create mode 100644 V3/Content/Effects/blood_hit_02.png create mode 100644 V3/Content/Effects/blood_hit_03.png create mode 100644 V3/Content/Effects/blood_hit_04.png create mode 100644 V3/Content/Effects/blood_hit_05.png create mode 100644 V3/Content/Effects/blood_hit_06.png create mode 100644 V3/Content/Effects/blood_hit_08.png create mode 100644 V3/Content/Effects/explosion.png create mode 100644 V3/Content/Effects/particlefx_03.png create mode 100644 V3/Content/Effects/particlefx_04.png create mode 100644 V3/Content/Effects/particlefx_05.png create mode 100644 V3/Content/Effects/quake.png create mode 100644 V3/Content/Fonts/Blutschrift.ttf create mode 100644 V3/Content/Fonts/DeathFont.spritefont create mode 100644 V3/Content/Fonts/DejaVuSans.ttf create mode 100644 V3/Content/Fonts/MenuFont.spritefont create mode 100644 V3/Content/Fonts/Siegesschriftzug.ttf create mode 100644 V3/Content/Fonts/UnitFont.spritefont create mode 100644 V3/Content/Fonts/VictoryFont.spritefont create mode 100644 V3/Content/Fonts/grabstein.ttf create mode 100644 V3/Content/Maps/map_grassland.tmx create mode 100644 V3/Content/Maps/techdemo.tmx create mode 100644 V3/Content/Maps/work_in_progress.tmx create mode 100644 V3/Content/Menu/Titel.png create mode 100644 V3/Content/Menu/arrow_white.png create mode 100644 V3/Content/Menu/mainscreen.jpg create mode 100644 V3/Content/Sounds/Afraid_to_Go.mp3 create mode 100644 V3/Content/Sounds/Knight.wav create mode 100644 V3/Content/Sounds/Kosta_T_-_06.mp3 create mode 100644 V3/Content/Sounds/Monster_Gigante-Doberman-1334685792.wav create mode 100644 V3/Content/Sounds/Mummy_Zombie-SoundBible.wav create mode 100644 V3/Content/Sounds/SkeletonHorse.wav create mode 100644 V3/Content/Sounds/explode.wav create mode 100644 V3/Content/Sounds/explodemini.wav create mode 100644 V3/Content/Sounds/explosion1.ogg create mode 100644 V3/Content/Sounds/horse.wav create mode 100644 V3/Content/Sounds/impactsplat01.ogg create mode 100644 V3/Content/Sounds/punch.wav create mode 100644 V3/Content/Sounds/walking.wav create mode 100644 V3/Content/Sounds/zonk2.wav create mode 100644 V3/Content/Sources/Horse.blend create mode 100644 V3/Content/Sources/Skeleton.blend create mode 100644 V3/Content/Sources/SkeletonHorse.blend create mode 100644 V3/Content/Sources/SkeletonHorse.png create mode 100644 V3/Content/Sources/SkeletonRider.blend create mode 100644 V3/Content/Sources/SkeletonRider.png create mode 100644 V3/Content/Sources/ZombieWithClub.png create mode 100644 V3/Content/Sources/castle.xcf create mode 100644 V3/Content/Sources/create_spritesheet.sh create mode 100644 V3/Content/Sources/fleischklops.blend create mode 100644 V3/Content/Sources/fleischklops.xcf create mode 100644 V3/Content/Sources/horse_paint.png create mode 100644 V3/Content/Sources/horse_paint_sc.png create mode 100644 V3/Content/Sources/horse_tack.png create mode 100644 V3/Content/Sources/houses_front.xcf create mode 100644 V3/Content/Sources/houses_rear.xcf create mode 100644 V3/Content/Sources/human_construction_set.xcf create mode 100644 V3/Content/Sources/human_construction_set_female.xcf create mode 100644 V3/Content/Sources/king.blend create mode 100644 V3/Content/Sources/king_head.png create mode 100644 V3/Content/Sources/necromancer.xcf create mode 100644 V3/Content/Sources/pathfinder.xcf create mode 100644 V3/Content/Sources/prince.blend create mode 100644 V3/Content/Sources/prince.xcf create mode 100644 V3/Content/Sources/selection.xcf create mode 100644 V3/Content/Sources/skeleton_horse.png create mode 100644 V3/Content/Sources/the_triumph_of_death.jpg create mode 100644 V3/Content/Sources/zombie.blend create mode 100644 V3/Content/Sprites/WhiteRectangle.png create mode 100644 V3/Content/Sprites/arrows.png create mode 100644 V3/Content/Sprites/buckler.png create mode 100644 V3/Content/Sprites/buckler_female.png create mode 100644 V3/Content/Sprites/chain.png create mode 100644 V3/Content/Sprites/chain_female.png create mode 100644 V3/Content/Sprites/cloth.png create mode 100644 V3/Content/Sprites/cloth_female.png create mode 100644 V3/Content/Sprites/cloud.png create mode 100644 V3/Content/Sprites/ellipse.png create mode 100644 V3/Content/Sprites/fleischklops.png create mode 100644 V3/Content/Sprites/fog.png create mode 100644 V3/Content/Sprites/head.png create mode 100644 V3/Content/Sprites/head_bald.png create mode 100644 V3/Content/Sprites/head_chain.png create mode 100644 V3/Content/Sprites/head_chain_female.png create mode 100644 V3/Content/Sprites/head_female.png create mode 100644 V3/Content/Sprites/head_plate.png create mode 100644 V3/Content/Sprites/head_plate_female.png create mode 100644 V3/Content/Sprites/king.png create mode 100644 V3/Content/Sprites/longsword.png create mode 100644 V3/Content/Sprites/longsword_female.png create mode 100644 V3/Content/Sprites/necromancer.png create mode 100644 V3/Content/Sprites/necromancer_female.png create mode 100644 V3/Content/Sprites/nude.png create mode 100644 V3/Content/Sprites/nude_female.png create mode 100644 V3/Content/Sprites/plate.png create mode 100644 V3/Content/Sprites/plate_female.png create mode 100644 V3/Content/Sprites/prince.png create mode 100644 V3/Content/Sprites/selection.png create mode 100644 V3/Content/Sprites/shield.png create mode 100644 V3/Content/Sprites/shield_female.png create mode 100644 V3/Content/Sprites/shortsword.png create mode 100644 V3/Content/Sprites/shortsword_female.png create mode 100644 V3/Content/Sprites/skeleton.png create mode 100644 V3/Content/Sprites/skeleton_archer.png create mode 100644 V3/Content/Sprites/skeleton_elite.png create mode 100644 V3/Content/Sprites/skeleton_horse.png create mode 100644 V3/Content/Sprites/skeleton_rider.png create mode 100644 V3/Content/Sprites/staff.png create mode 100644 V3/Content/Sprites/staff_female.png create mode 100644 V3/Content/Sprites/zombie.png create mode 100644 V3/Content/Sprites/zombie_club.png create mode 100644 V3/Content/Textures/EmptyPixel.png create mode 100644 V3/Content/Textures/castle.png create mode 100644 V3/Content/Textures/grassland.png create mode 100644 V3/Content/Textures/grassland_trees.png create mode 100644 V3/Content/Textures/grassland_water.png create mode 100644 V3/Content/Textures/houses_front.png create mode 100644 V3/Content/Textures/houses_rear.png create mode 100644 V3/Content/Textures/medieval_building_tiles.png create mode 100644 V3/Content/Textures/pathfinder.png create mode 100644 V3/Data/DebugMode.cs create mode 100644 V3/Data/GameState.cs create mode 100644 V3/Data/IGameStateManager.cs create mode 100644 V3/Data/IOptionsManager.cs create mode 100644 V3/Data/IPathManager.cs create mode 100644 V3/Data/ISaveGame.cs create mode 100644 V3/Data/ISaveGameManager.cs create mode 100644 V3/Data/Internal/GameStateManager.cs create mode 100644 V3/Data/Internal/OptionsManager.cs create mode 100644 V3/Data/Internal/PathManager.cs create mode 100644 V3/Data/Internal/SaveGame.cs create mode 100644 V3/Data/Internal/SaveGameManager.cs create mode 100644 V3/Data/Options.cs create mode 100644 V3/Effects/AbstractEffect.cs create mode 100644 V3/Effects/BloodBang.cs create mode 100644 V3/Effects/BloodExplosion.cs create mode 100644 V3/Effects/BloodFountain.cs create mode 100644 V3/Effects/EffectsManager.cs create mode 100644 V3/Effects/Explosion.cs create mode 100644 V3/Effects/HorseEffect.cs create mode 100644 V3/Effects/IEffect.cs create mode 100644 V3/Effects/IEffectsManager.cs create mode 100644 V3/Effects/Quake.cs create mode 100644 V3/Effects/SmokeBig.cs create mode 100644 V3/Effects/SmokeMedium.cs create mode 100644 V3/Effects/SmokeSmall.cs create mode 100644 V3/Ellipse.cs create mode 100644 V3/Faction.cs create mode 100644 V3/Icon.ico create mode 100644 V3/Input/IInputManager.cs create mode 100644 V3/Input/IKeyEvent.cs create mode 100644 V3/Input/IMouseEvent.cs create mode 100644 V3/Input/IMouseEventHandler.cs create mode 100644 V3/Input/Internal/InputManager.cs create mode 100644 V3/Input/Internal/KeyEvent.cs create mode 100644 V3/Input/Internal/MouseEvent.cs create mode 100644 V3/Input/MouseButton.cs create mode 100644 V3/Map/AbstractLayer.cs create mode 100644 V3/Map/Area.cs create mode 100644 V3/Map/Constants.cs create mode 100644 V3/Map/FloorLayer.cs create mode 100644 V3/Map/FogOfWar.cs create mode 100644 V3/Map/IMapManager.cs create mode 100644 V3/Map/MapManager.cs create mode 100644 V3/Map/ObjectLayer.cs create mode 100644 V3/Map/Pathfinder.cs create mode 100644 V3/Map/PathfindingGrid.cs create mode 100644 V3/Map/SearchNode.cs create mode 100644 V3/Map/TiledParser.cs create mode 100644 V3/Map/Tileset.cs create mode 100644 V3/Node.cs create mode 100644 V3/Objects/AbstractBuilding.cs create mode 100644 V3/Objects/AbstractCreature.cs create mode 100644 V3/Objects/Arrow.cs create mode 100644 V3/Objects/BuildingState.cs create mode 100644 V3/Objects/Castle.cs create mode 100644 V3/Objects/CreatureFactory.cs create mode 100644 V3/Objects/FemalePeasant.cs create mode 100644 V3/Objects/Forge.cs create mode 100644 V3/Objects/IBasicCreatureFactory.cs create mode 100644 V3/Objects/IBuilding.cs create mode 100644 V3/Objects/ICreature.cs create mode 100644 V3/Objects/IGameObject.cs create mode 100644 V3/Objects/IObjectsManager.cs create mode 100644 V3/Objects/IdGenerator.cs create mode 100644 V3/Objects/King.cs create mode 100644 V3/Objects/KingsGuard.cs create mode 100644 V3/Objects/Knight.cs create mode 100644 V3/Objects/MalePeasant.cs create mode 100644 V3/Objects/Meatball.cs create mode 100644 V3/Objects/Movement.cs create mode 100644 V3/Objects/Movement/CountStepsMovement.cs create mode 100644 V3/Objects/Movement/IMovable.cs create mode 100644 V3/Objects/Movement/PlayerMovement.cs create mode 100644 V3/Objects/Necromancer.cs create mode 100644 V3/Objects/ObjectsManager.cs create mode 100644 V3/Objects/Prince.cs create mode 100644 V3/Objects/Selection.cs create mode 100644 V3/Objects/Skeleton.cs create mode 100644 V3/Objects/SkeletonElite.cs create mode 100644 V3/Objects/SkeletonHorse.cs create mode 100644 V3/Objects/Sprite/AbstractSpriteCreature.cs create mode 100644 V3/Objects/Sprite/ArrowSprite.cs create mode 100644 V3/Objects/Sprite/BucklerFemaleSprite.cs create mode 100644 V3/Objects/Sprite/BucklerSprite.cs create mode 100644 V3/Objects/Sprite/ChainFemaleSprite.cs create mode 100644 V3/Objects/Sprite/ChainSprite.cs create mode 100644 V3/Objects/Sprite/ClothFemaleSprite.cs create mode 100644 V3/Objects/Sprite/ClothSprite.cs create mode 100644 V3/Objects/Sprite/EquipmentType.cs create mode 100644 V3/Objects/Sprite/HeadBaldSprite.cs create mode 100644 V3/Objects/Sprite/HeadChainFemaleSprite.cs create mode 100644 V3/Objects/Sprite/HeadChainSprite.cs create mode 100644 V3/Objects/Sprite/HeadFemaleSprite.cs create mode 100644 V3/Objects/Sprite/HeadPlateFemaleSprite.cs create mode 100644 V3/Objects/Sprite/HeadPlateSprite.cs create mode 100644 V3/Objects/Sprite/HeadSprite.cs create mode 100644 V3/Objects/Sprite/ISpriteCreature.cs create mode 100644 V3/Objects/Sprite/KingSprite.cs create mode 100644 V3/Objects/Sprite/LongswordFemaleSprite.cs create mode 100644 V3/Objects/Sprite/LongswordSprite.cs create mode 100644 V3/Objects/Sprite/MeatballSprite.cs create mode 100644 V3/Objects/Sprite/NecromancerFemaleSprite.cs create mode 100644 V3/Objects/Sprite/NecromancerSprite.cs create mode 100644 V3/Objects/Sprite/NudeFemaleSprite.cs create mode 100644 V3/Objects/Sprite/NudeSprite.cs create mode 100644 V3/Objects/Sprite/PlateFemaleSprite.cs create mode 100644 V3/Objects/Sprite/PlateSprite.cs create mode 100644 V3/Objects/Sprite/PrinceSprite.cs create mode 100644 V3/Objects/Sprite/ShieldFemaleSprite.cs create mode 100644 V3/Objects/Sprite/ShieldSprite.cs create mode 100644 V3/Objects/Sprite/ShortswordFemaleSprite.cs create mode 100644 V3/Objects/Sprite/ShortswordSprite.cs create mode 100644 V3/Objects/Sprite/SkeletonArcherSprite.cs create mode 100644 V3/Objects/Sprite/SkeletonEliteSprite.cs create mode 100644 V3/Objects/Sprite/SkeletonHorseSprite.cs create mode 100644 V3/Objects/Sprite/SkeletonRiderSprite.cs create mode 100644 V3/Objects/Sprite/SkeletonSprite.cs create mode 100644 V3/Objects/Sprite/StaffFemaleSprite.cs create mode 100644 V3/Objects/Sprite/StaffSprite.cs create mode 100644 V3/Objects/Sprite/ZombieSprite.cs create mode 100644 V3/Objects/Sprite/ZombieWithClubSprite.cs create mode 100644 V3/Objects/TextureObject.cs create mode 100644 V3/Objects/Transformation.cs create mode 100644 V3/Objects/Woodhouse.cs create mode 100644 V3/Objects/Zombie.cs create mode 100644 V3/OpenTK.dll.config create mode 100644 V3/Program.cs create mode 100644 V3/Properties/AssemblyInfo.cs create mode 100644 V3/Quadtree.cs create mode 100644 V3/Screens/AbstractScreen.cs create mode 100644 V3/Screens/AchievementsScreen.cs create mode 100644 V3/Screens/DeathScreen.cs create mode 100644 V3/Screens/DebugScreen.cs create mode 100644 V3/Screens/FpsCounter.cs create mode 100644 V3/Screens/GameScreen.cs create mode 100644 V3/Screens/HudScreen.cs create mode 100644 V3/Screens/IDrawable.cs create mode 100644 V3/Screens/IScreen.cs create mode 100644 V3/Screens/IScreenFactory.cs create mode 100644 V3/Screens/IScreenManager.cs create mode 100644 V3/Screens/IUpdatable.cs create mode 100644 V3/Screens/LoadScreen.cs create mode 100644 V3/Screens/MainScreen.cs create mode 100644 V3/Screens/MenuActions.cs create mode 100644 V3/Screens/OptionsScreen.cs create mode 100644 V3/Screens/PauseScreen.cs create mode 100644 V3/Screens/ScreenManager.cs create mode 100644 V3/Screens/StatisticsScreen.cs create mode 100644 V3/Screens/TechdemoScreen.cs create mode 100644 V3/Screens/VictoryScreen.cs create mode 100644 V3/UpdatesPerSecond.cs create mode 100644 V3/V3.csproj create mode 100644 V3/V3Game.cs create mode 100644 V3/Widgets/AbstractMenu.cs create mode 100644 V3/Widgets/AbstractTextWidget.cs create mode 100644 V3/Widgets/AchievementBox.cs create mode 100644 V3/Widgets/Button.cs create mode 100644 V3/Widgets/EmptyWidget.cs create mode 100644 V3/Widgets/FormMenu.cs create mode 100644 V3/Widgets/HorizontalOrientation.cs create mode 100644 V3/Widgets/IBasicWidgetFactory.cs create mode 100644 V3/Widgets/IClickable.cs create mode 100644 V3/Widgets/IImageWidget.cs create mode 100644 V3/Widgets/IMenu.cs create mode 100644 V3/Widgets/IMenuFactory.cs create mode 100644 V3/Widgets/ISelectable.cs create mode 100644 V3/Widgets/ITextWidget.cs create mode 100644 V3/Widgets/IWidget.cs create mode 100644 V3/Widgets/Label.cs create mode 100644 V3/Widgets/SelectButton.cs create mode 100644 V3/Widgets/VerticalMenu.cs create mode 100644 V3/Widgets/WidgetFactory.cs create mode 100644 V3/packages.config diff --git a/GDD.pdf b/GDD.pdf new file mode 100644 index 0000000..7a16f49 Binary files /dev/null and b/GDD.pdf differ diff --git a/LICENCE.txt b/LICENCE.txt new file mode 100644 index 0000000..4f8f342 --- /dev/null +++ b/LICENCE.txt @@ -0,0 +1,23 @@ +MIT License + +Copyright (c) 2016 + Anna Windbühler, Alexander Steinmark, Fabrizio Costea, + Thomas Leyh, Denis Veil, Robin Krahl + +Permission is hereby granted, free of charge, to any person obtaining a copy +of this software and associated documentation files (the "Software"), to deal +in the Software without restriction, including without limitation the rights +to use, copy, modify, merge, publish, distribute, sublicense, and/or sell +copies of the Software, and to permit persons to whom the Software is +furnished to do so, subject to the following conditions: + +The above copyright notice and this permission notice shall be included in all +copies or substantial portions of the Software. + +THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR +IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, +FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE +AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER +LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, +OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE +SOFTWARE. \ No newline at end of file diff --git a/README.en.md b/README.en.md new file mode 100644 index 0000000..2aa3cb2 --- /dev/null +++ b/README.en.md @@ -0,0 +1,27 @@ +Vagram's Vicious Vengeance +====================== + +This video game was created at the [University of Freiburg](http://www.uni-freiburg.de/) during a lecture of the [Chair of Software Engineering](http://swt.informatik.uni-freiburg.de/). Six people with varying degrees of programming experience were randomly thrown together. They somehow made a game during summer 2016 which you can see here. + +You are playing the necromancer Vagram, former personal wizard of King Harry. But when he was shamefully banished from the kingdom he swore fierce revenge. Now he is back with his dark arts to bring death and ruin to the whole kingdom. + +The game is in german but there are no dialogs or anything like that. Most things should be self-explanatory. + +* [For basic controls see here.](V3/CONTROLS.md) +* [See here for credits](V3/CREDITS.md) to the many talented people we used sounds and graphics from. + +Dependencies +------------ + +* [MonoGame 3.5](http://www.monogame.net/) +* .Net 4.5 / alternatively [Mono 4.4](http://www.mono-project.com/) +* [OpenAL](http://www.openal.org/) + +Screenshots +----------------- + +[![Screenshot 1](Screenshots/screen1_s.jpg)](Screenshots/screen1.jpg) + +[![Screenshot 2](Screenshots/screen2_s.jpg)](Screenshots/screen2.jpg) + +[![Screenshot 3](Screenshots/screen3_s.jpg)](Screenshots/screen3.jpg) \ No newline at end of file diff --git a/README.md b/README.md new file mode 100644 index 0000000..0068c6d --- /dev/null +++ b/README.md @@ -0,0 +1,52 @@ +Vagram's Vicious Vengeance +====================== + +[For an english version see here.](README.en.md) + +Dieses Videospiel ist im Rahmen des [Softwarepraktikums](https://sopra.informatik.uni-freiburg.de/) des [Lehrstuhls für Softwaretechnik](http://swt.informatik.uni-freiburg.de/) an der [Albert-Ludwigs-Universität Freiburg](http://www.uni-freiburg.de/) entstanden. Sechs zufällig zusammengewürfelte Leute mit unterschiedlicher Erfahrung saßen im Sommersemester 2016 zusammen und haben irgendwas zurechtgehackt. + +Verwendet wurde das [MonoGame-Framework](http://www.monogame.net/) und eine Menge freier Sounds und Grafiken, die gesondert [in den CREDITS](V3/CREDITS.md) gelistet werden. + +Die Steuerung erfolgt vorwiegend über die Maus und ist ziemlich konservativ. Dennoch gibt es eine [Übersicht über die möglichen Befehle hier](V3/CONTROLS.md). + +Zusammenfassung des Spiels +-------------------------- + +*"Pest und Verderben! Seid verflucht! Wie konntet Ihr mir das antun? Den Tod über eure Sippe! Über euer Land! Mit eigenen Händen werde ich dieses Königreich vernichten, und wenn es mich meine Seele kosten mag."* + +Als ehemaliger Hofzauberer Vagrant kennt Ihr nur noch ein Ziel: Rache an König Harry, der verantwortlich für den Tod Eurer Familie ist. Auf Euch allein gestellt ohne auch nur einen Verbündeten bleibt euch dazu nur ein Mittel: Die verbotene Kunst der Totenbeschwörung. + +Pilgert durch das Königreich und hinterlasst eine Spur des Verwüstung. Entvölkert ganze Dörfer und fügt die wiederbelebten Kadaver Eurer Zombiearmee hinzu. Zerstört wo und was Ihr nur könnt und nutzt die Überbleibsel zur Verstärkung Eurer willenlosen Streitkräfte. Verschmelzt in unheiligen Ritualen Eure Kreaturen zu noch mächtigeren Monstrositäten. Überrennt die verblendeten Vasallen des Königs mit euren Dienern aus Knochen und verwesendem Fleisch, denn sie haben es verdient. Jeder Nachkomme des verhassten Königs muss ausgemerzt werden um Euren Durst nach Rache zu stillen. + +In dieser Mischung aus Action-RPG und Echtzeitstrategie geht es nicht um Aufbau und Eroberung. Kein Stein darf auf dem anderen bleiben, wollt Ihr Erfolg haben. Im Rahmen der Kampagne führt ihr Kapitel für Kapitel das Königreich seinem Untergang entgegen. Und nun legt alle Skrupel ab, denn für Erlösung ist es längst zu spät. + +Alleinstellungsmerkmale +----------------------- + +Bei Vagrant's Vicious Vengeance soll eine offensive und risikoreiche Spielweise gefördert werden. Aus diesem Grund wird einerseits auf Aufbauelemente verzichtet. Einheiten werden aus Kadavern erschaffen, die durch die menschliche Bevölkerung einer Karte begrenzt sind. Einheiten können ebenfalls verstärkt werden, lässt man sie Gebäude zertrümmern und die Überreste plündern. Auch diese sind nur begrenzt vorhanden. + +Andererseits ist der Totenbeschwörer selbst von zentraler Bedeutung: Ist er nicht anwesend, können die erschaffenen Einheiten nicht kontrolliert werden. Nur in seiner Gegenwart können Befehle erteilt und Spezialfähigkeiten aktiviert werden. Außerdem können Einheiten kombiniert werden, um noch mächtigere Zombies zu erschaffen. Für sich selbst genommen besitzt der Totenbeschwörer jedoch keine Angriffsmöglichkeiten, somit ist er also ohne beschworene Einheiten komplett wehrlos. + +*Weiteres langweiliges Palaver darf gerne dem [Game Design Document](GDD.pdf) entnommen werden.* + +Abhängigkeiten +------------------- + +* [MonoGame 3.5](http://www.monogame.net/) +* .Net 4.5 / alternativ [Mono 4.4](http://www.mono-project.com/) +* [OpenAL](http://www.openal.org/) + +Screenshots +----------------- + +[![Screenshot 1](Screenshots/screen1_s.jpg)](Screenshots/screen1.jpg) + +[![Screenshot 2](Screenshots/screen2_s.jpg)](Screenshots/screen2.jpg) + +[![Screenshot 3](Screenshots/screen3_s.jpg)](Screenshots/screen3.jpg) + +Bekannte Probleme +-------------------- + +* Unter Linux werden keine Umlaute angezeigt. +* Temporärer Framerateeinbruch, wenn man sehr vielen Einheiten auf einmal den Laufbefehl gibt. diff --git a/Screenshots/screen1.jpg b/Screenshots/screen1.jpg new file mode 100644 index 0000000..5a550fa Binary files /dev/null and b/Screenshots/screen1.jpg differ diff --git a/Screenshots/screen1_s.jpg b/Screenshots/screen1_s.jpg new file mode 100644 index 0000000..2c5355b Binary files /dev/null and b/Screenshots/screen1_s.jpg differ diff --git a/Screenshots/screen2.jpg b/Screenshots/screen2.jpg new file mode 100644 index 0000000..d7a200c Binary files /dev/null and b/Screenshots/screen2.jpg differ diff --git a/Screenshots/screen2_s.jpg b/Screenshots/screen2_s.jpg new file mode 100644 index 0000000..6ebe2fb Binary files /dev/null and b/Screenshots/screen2_s.jpg differ diff --git a/Screenshots/screen3.jpg b/Screenshots/screen3.jpg new file mode 100644 index 0000000..9c48639 Binary files /dev/null and b/Screenshots/screen3.jpg differ diff --git a/Screenshots/screen3_s.jpg b/Screenshots/screen3_s.jpg new file mode 100644 index 0000000..5b1560c Binary files /dev/null and b/Screenshots/screen3_s.jpg differ diff --git a/V3.sln b/V3.sln new file mode 100644 index 0000000..e9965be --- /dev/null +++ b/V3.sln @@ -0,0 +1,43 @@ + +Microsoft Visual Studio Solution File, Format Version 12.00 +# Visual Studio 14 +VisualStudioVersion = 14.0.25123.0 +MinimumVisualStudioVersion = 10.0.40219.1 +Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "V3", "V3\V3.csproj", "{4C475FE4-ECB6-4D25-B7E6-0B773A736A24}" +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Solution Items", "Solution Items", "{A47C7086-4DF1-4BBC-885B-9CC9EA3D78F8}" + ProjectSection(SolutionItems) = preProject + GDD.pdf = GDD.pdf + LICENCE.txt = LICENCE.txt + README.en.md = README.en.md + README.md = README.md + EndProjectSection +EndProject +Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Screenshots", "Screenshots", "{1D632156-7EC9-4DBD-A79D-2E4686D35FBA}" + ProjectSection(SolutionItems) = preProject + Screenshots\screen1.jpg = Screenshots\screen1.jpg + Screenshots\screen1_s.jpg = Screenshots\screen1_s.jpg + Screenshots\screen2.jpg = Screenshots\screen2.jpg + Screenshots\screen2_s.jpg = Screenshots\screen2_s.jpg + Screenshots\screen3.jpg = Screenshots\screen3.jpg + Screenshots\screen3_s.jpg = Screenshots\screen3_s.jpg + EndProjectSection +EndProject +Global + GlobalSection(SolutionConfigurationPlatforms) = preSolution + Debug|x86 = Debug|x86 + Larger Map|x86 = Larger Map|x86 + Release|x86 = Release|x86 + EndGlobalSection + GlobalSection(ProjectConfigurationPlatforms) = postSolution + {4C475FE4-ECB6-4D25-B7E6-0B773A736A24}.Debug|x86.ActiveCfg = Debug|x86 + {4C475FE4-ECB6-4D25-B7E6-0B773A736A24}.Debug|x86.Build.0 = Debug|x86 + {4C475FE4-ECB6-4D25-B7E6-0B773A736A24}.Larger Map|x86.ActiveCfg = Larger Map|x86 + {4C475FE4-ECB6-4D25-B7E6-0B773A736A24}.Larger Map|x86.Build.0 = Larger Map|x86 + {4C475FE4-ECB6-4D25-B7E6-0B773A736A24}.Release|x86.ActiveCfg = Release|x86 + {4C475FE4-ECB6-4D25-B7E6-0B773A736A24}.Release|x86.Build.0 = Release|x86 + EndGlobalSection + GlobalSection(SolutionProperties) = preSolution + HideSolutionNode = FALSE + EndGlobalSection +EndGlobal diff --git a/V3/AI/ActionState.cs b/V3/AI/ActionState.cs new file mode 100644 index 0000000..18996c8 --- /dev/null +++ b/V3/AI/ActionState.cs @@ -0,0 +1,25 @@ +namespace V3.AI +{ + /// + /// The state of an action taken by the computer player. + /// + public enum ActionState + { + /// + /// The action is waiting to be executed. + /// + Waiting, + /// + /// The action is currently being executed. + /// + Executing, + /// + /// The action has been done successfully. + /// + Done, + /// + /// The action failed. + /// + Failed + } +} diff --git a/V3/AI/AiState.cs b/V3/AI/AiState.cs new file mode 100644 index 0000000..1bc0ab0 --- /dev/null +++ b/V3/AI/AiState.cs @@ -0,0 +1,27 @@ +namespace V3.AI +{ + /// + /// An action state for the AI player that is part of a strategy. A state + /// defines the specific actions to take (for example, defend peasants, or + /// attack enemy creatures). + /// + public enum AiState + { + /// + /// Waiting for the player actions. + /// + Idle, + /// + /// Defend peasants so that they don't become zombies. + /// + DefendPeasants, + /// + /// Attack enemy creatures. + /// + AttackCreatures, + /// + /// Attack the necromancer directly. + /// + AttackNecromancer + } +} diff --git a/V3/AI/IAction.cs b/V3/AI/IAction.cs new file mode 100644 index 0000000..b68355f --- /dev/null +++ b/V3/AI/IAction.cs @@ -0,0 +1,24 @@ +namespace V3.AI +{ + /// + /// An action that can be taken by the computer player. + /// + public interface IAction + { + /// + /// The current state of the action. + /// + ActionState State { get; } + + /// + /// Start the execution of the action. + /// + void Start(); + + /// + /// Update the execution state. This method should be repateatingly + /// called as long as State is Executing. + /// + void Update(); + } +} diff --git a/V3/AI/IAiPlayer.cs b/V3/AI/IAiPlayer.cs new file mode 100644 index 0000000..7f5f81b --- /dev/null +++ b/V3/AI/IAiPlayer.cs @@ -0,0 +1,51 @@ +using System.Collections.Generic; +using Microsoft.Xna.Framework; + +namespace V3.AI +{ + /// + /// A computer player that takes actions according to a specified strategy. + /// + public interface IAiPlayer + { + /// + /// The current world view of the player. It stores the knowledge of + /// the computer player based on the previous percepts. + /// + IWorldView WorldView { get; } + /// + /// The strategy of the player. The strategy is a state machine that + /// defines the current state. + /// + IStrategy Strategy { get; } + /// + /// The current state of the player. The state is one step of the + /// strategy, and defines the specific actions to take. + /// + AiState State { get; set; } + /// + /// The actions that the player wants to be executed. Updated by + /// Act. + /// + IList Actions { get; } + + /// + /// Executes one update cycle -- perception, acting and the execution + /// of actions. + /// + /// the time since the last update + void Update(GameTime gameTime); + + /// + /// Update the AI's view of the game world. + /// + void Percept(); + + /// + /// Take actions based on the previous percepts, the current strategy + /// and state. Updates the list of actions stored in Actions. These + /// should be executed by the caller. + /// + void Act(); + } +} diff --git a/V3/AI/IStrategy.cs b/V3/AI/IStrategy.cs new file mode 100644 index 0000000..4bfb99c --- /dev/null +++ b/V3/AI/IStrategy.cs @@ -0,0 +1,17 @@ +namespace V3.AI +{ + /// + /// A strategy for the computer player. A strategy is a finite state + /// machine. + /// + public interface IStrategy + { + /// + /// Updates the current state according to the game situtation. + /// + /// the current state + /// the current view of the game world + /// the next state indicated by this strategy + AiState Update(AiState state, IWorldView worldView); + } +} diff --git a/V3/AI/IWorldView.cs b/V3/AI/IWorldView.cs new file mode 100644 index 0000000..b47322f --- /dev/null +++ b/V3/AI/IWorldView.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using V3.Objects; + +namespace V3.AI +{ + /// + /// Stores the knowledge of the computer player about the game world, and + /// is used for the evaluation of the strategy. It is also used to decide + /// which actions to take based on the current state. + /// + public interface IWorldView + { + int EnemyCount { get; set; } + int InitialPlebsCount { get; set; } + int PlebsCount { get; set; } + float NecromancerHealth { get; set; } + List IdlingKnights { get; } + List Targets { get; } + List Plebs { get; } + } +} diff --git a/V3/AI/Internal/AbstractAction.cs b/V3/AI/Internal/AbstractAction.cs new file mode 100644 index 0000000..1b5f73e --- /dev/null +++ b/V3/AI/Internal/AbstractAction.cs @@ -0,0 +1,38 @@ +namespace V3.AI.Internal +{ + /// + /// Abstract implementation of IAction. + /// + public abstract class AbstractAction : IAction + { + /// + /// The current state of the action. + /// + public ActionState State { get; private set; } = ActionState.Waiting; + + /// + /// Start the execution of the action. + /// + public virtual void Start() + { + State = ActionState.Executing; + } + + /// + /// Update the execution state. This method should be repateatingly + /// called as long as State is Executing. + /// + public virtual void Update() + { + if (State != ActionState.Executing) + return; + State = GetNextState(); + } + + /// + /// Returns the next state of this action. It is guaranteed that the + /// current state is Executing. + /// + protected abstract ActionState GetNextState(); + } +} diff --git a/V3/AI/Internal/AiPlayer.cs b/V3/AI/Internal/AiPlayer.cs new file mode 100644 index 0000000..6040348 --- /dev/null +++ b/V3/AI/Internal/AiPlayer.cs @@ -0,0 +1,244 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Xna.Framework; +using V3.Objects; + +namespace V3.AI.Internal +{ + /// + /// Default implementation of IAiPlayer. + /// + // ReSharper disable once ClassNeverInstantiated.Global + public class AiPlayer : IAiPlayer + { + /// + /// The current world view of the player. It stores the knowledge of + /// the computer player based on the previous percepts. + /// + public IWorldView WorldView { get; } = new WorldView(); + /// + /// The strategy of the player. The strategy is a state machine that + /// defines the current state. + /// + public IStrategy Strategy { get; } = new AttackStrategy(); + /// + /// The current state of the player. The state is one step of the + /// strategy, and defines the specific actions to take. + /// + public AiState State { get; set; } = AiState.Idle; + /// + /// The actions that the player wants to be executed. Updated by + /// Act. + /// + public IList Actions { get; } = new List(); + + private readonly IActionFactory mActionFactory; + private readonly IBasicCreatureFactory mCreatureFactory; + private readonly IObjectsManager mObjectsManager; + private readonly UpdatesPerSecond mUpS = new UpdatesPerSecond(1); + private readonly Random mRandom = new Random(); + private TimeSpan mTimeSpan = TimeSpan.Zero; + private TimeSpan mTimeSpanSpawn = TimeSpan.Zero; + private int mMaxWaitBaseMs = (int) TimeSpan.FromSeconds(20).TotalMilliseconds; + private int mMaxWaitAddMs = (int) TimeSpan.FromSeconds(60).TotalMilliseconds; + + /// + /// Creates a new AI player. + /// + public AiPlayer(IActionFactory actionFactory, IBasicCreatureFactory creatureFactory, + IObjectsManager objectsManager) + { + mActionFactory = actionFactory; + mCreatureFactory = creatureFactory; + mObjectsManager = objectsManager; + } + + /// + /// Executes one update cycle -- perception, acting and the execution + /// of actions. + /// + /// the time since the last update + public void Update(GameTime gameTime) + { + mTimeSpan += gameTime.ElapsedGameTime; + if (!mUpS.IsItTime(gameTime)) + return; + Percept(); + Act(); + foreach (var action in Actions) + { + if (action.State == ActionState.Waiting) + action.Start(); + action.Update(); + } + } + + /// + /// Update the AI's view of the game world. + /// + public void Percept() + { + WorldView.EnemyCount = 0; + WorldView.PlebsCount = 0; + WorldView.NecromancerHealth = 0; + WorldView.IdlingKnights.Clear(); + WorldView.Targets.Clear(); + WorldView.Plebs.Clear(); + + foreach (var creature in mObjectsManager.CreatureList) + { + if (creature.Faction == Faction.Kingdom) + { + if (!creature.IsDead) + { + if (creature is Knight) + { + if (creature.MovementState == MovementState.Idle && creature.IsAttacking == null) + WorldView.IdlingKnights.Add(creature); + } + } + } + else if (creature.Faction == Faction.Undead) + { + if (!creature.IsDead) + { + if (!(creature is Necromancer)) + WorldView.EnemyCount++; + else + WorldView.NecromancerHealth = (float) creature.Life / creature.MaxLife; + WorldView.Targets.Add(creature); + } + } + else if (creature.Faction == Faction.Plebs) + { + if (!creature.IsDead) + { + WorldView.Plebs.Add(creature); + } + } + + WorldView.PlebsCount = WorldView.Plebs.Count; + if (WorldView.InitialPlebsCount < WorldView.PlebsCount) + WorldView.InitialPlebsCount = WorldView.PlebsCount; + } + } + + private TimeSpan GetRandomTimeSpanSpawn() + { + var factor = Math.Max(0, 500 - WorldView.EnemyCount) / 500; + return TimeSpan.FromMilliseconds(mRandom.Next(mMaxWaitBaseMs)) + + TimeSpan.FromSeconds(mRandom.Next(factor * mMaxWaitAddMs)); + } + + /// + /// Take actions based on the previous percepts, the current strategy + /// and state. + /// + public void Act() + { + State = Strategy.Update(State, WorldView); + + var completedActions = Actions.Where( + a => a.State == ActionState.Done || a.State == ActionState.Failed).ToList(); + completedActions.ForEach(a => Actions.Remove(a)); + + if (State != AiState.Idle) + { + if (mTimeSpan >= mTimeSpanSpawn) + { + mTimeSpan -= mTimeSpanSpawn; + mTimeSpanSpawn = GetRandomTimeSpanSpawn(); + SpawnKnight(); + } + } + + switch (State) + { + case AiState.Idle: + // nothing do to when idling + return; + case AiState.AttackCreatures: + // let all idling soldiers attack some creatures + if (WorldView.Targets.Count > 0) + { + foreach (var creature in WorldView.IdlingKnights) + { + ICreature target = null; + var distance = float.MaxValue; + foreach (var c in WorldView.Targets) + { + var d = Vector2.Distance(c.Position, creature.Position); + if (d < distance) + { + distance = d; + target = c; + } + } + creature.IsAttacking = target; + } + } + break; + case AiState.DefendPeasants: + if (WorldView.Plebs.Count > 0) + { + foreach (var creature in WorldView.IdlingKnights) + { + ICreature target = null; + var distance = float.MaxValue; + var threshold = (int) (creature.AttackRadius * 0.8); + foreach (var c in WorldView.Plebs) + { + var d = Vector2.Distance(c.Position, creature.Position); + if (d <= threshold) + { + target = null; + break; + } + // attempt to avoid clustering + /*if (mObjectsManager.GetObjectsInRectangle(c.SelectionRectangle).OfType().Count() > 0) + { + continue; + }*/ + if (d < distance) + { + distance = d; + target = c; + } + } + if (target != null) + { + var offset = target.Position - creature.Position; + offset.Normalize(); + offset *= threshold; + Move(creature, target.Position + offset); + } + } + } + break; + case AiState.AttackNecromancer: + foreach (var c in WorldView.IdlingKnights) + { + c.IsAttacking = mObjectsManager.PlayerCharacter; + } + break; + } + } + + private void SpawnKnight() + { + var knight = mCreatureFactory.CreateKnight(); + var position = new Vector2(500, 500); + if (mObjectsManager.Castle != null) + position = mObjectsManager.Castle.Position; + var spawnAction = mActionFactory.CreateSpawnAction(knight, position); + Actions.Add(spawnAction); + } + + private void Move(ICreature creature, Vector2 destination) + { + var moveAction = mActionFactory.CreateMoveAction(creature, destination); + Actions.Add(moveAction); + } + } +} diff --git a/V3/AI/Internal/AttackStrategy.cs b/V3/AI/Internal/AttackStrategy.cs new file mode 100644 index 0000000..d108b1f --- /dev/null +++ b/V3/AI/Internal/AttackStrategy.cs @@ -0,0 +1,48 @@ +namespace V3.AI.Internal +{ + /// + /// A simple strategy for the computer player that tells him to attack the + /// enemy creatures. + /// + internal class AttackStrategy : IStrategy + { + /// + /// Updates the current state according to the game situtation. + /// + /// the current state + /// the current view of the game world + /// the next state indicated by this strategy + public AiState Update(AiState state, IWorldView worldView) + { + switch (state) + { + case AiState.Idle: + if (worldView.InitialPlebsCount - worldView.PlebsCount > 3) + { + return AiState.DefendPeasants; + } + break; + case AiState.DefendPeasants: + if (worldView.PlebsCount < worldView.InitialPlebsCount * 0.75 || worldView.EnemyCount > 20) + { + return AiState.AttackCreatures; + } + break; + case AiState.AttackCreatures: + if (worldView.NecromancerHealth < 0.1) + { + return AiState.AttackNecromancer; + } + break; + case AiState.AttackNecromancer: + if (worldView.NecromancerHealth >= 0.1) + { + return AiState.AttackCreatures; + } + break; + } + + return state; + } + } +} diff --git a/V3/AI/Internal/IActionFactory.cs b/V3/AI/Internal/IActionFactory.cs new file mode 100644 index 0000000..eb62222 --- /dev/null +++ b/V3/AI/Internal/IActionFactory.cs @@ -0,0 +1,27 @@ +using Microsoft.Xna.Framework; +using V3.Objects; + +namespace V3.AI.Internal +{ + /// + /// Creates IAction instances. Automatically implemented by Ninject. + /// + public interface IActionFactory + { + /// + /// Creates a new MoveAction to move the given creature to the given + /// destination. + /// + /// the creature to mvoe + /// the destination of the creature + MoveAction CreateMoveAction(ICreature creature, Vector2 destination); + + /// + /// Creates a new SpawnAction that spawns the given creature at the + /// given position. + /// + /// the creature to spawn + /// the spawn position + SpawnAction CreateSpawnAction(ICreature creature, Vector2 position); + } +} diff --git a/V3/AI/Internal/MoveAction.cs b/V3/AI/Internal/MoveAction.cs new file mode 100644 index 0000000..fcbba54 --- /dev/null +++ b/V3/AI/Internal/MoveAction.cs @@ -0,0 +1,53 @@ +using Microsoft.Xna.Framework; +using V3.Objects; + +namespace V3.AI.Internal +{ + /// + /// Moves a creature to a destination point. + /// + // ReSharper disable once ClassNeverInstantiated.Global + public class MoveAction : AbstractAction + { + private ICreature mCreature; + private Vector2 mDestination; + + /// + /// Creates a new MoveAction to move the given creature to the given + /// destination. + /// + /// the creature to mvoe + /// the destination of the creature + public MoveAction(ICreature creature, Vector2 destination) + { + mCreature = creature; + mDestination = destination; + } + + /// + /// Start the execution of the action. + /// + public override void Start() + { + mCreature.Move(mDestination); + base.Start(); + } + + protected override ActionState GetNextState() + { + switch (mCreature.MovementState) + { + case MovementState.Idle: + return ActionState.Done; + case MovementState.Attacking: + case MovementState.Dying: + return ActionState.Failed; + case MovementState.Moving: + return ActionState.Executing; + default: + return ActionState.Failed; + } + } + + } +} diff --git a/V3/AI/Internal/SpawnAction.cs b/V3/AI/Internal/SpawnAction.cs new file mode 100644 index 0000000..4df6225 --- /dev/null +++ b/V3/AI/Internal/SpawnAction.cs @@ -0,0 +1,42 @@ +using Microsoft.Xna.Framework; +using V3.Objects; + +namespace V3.AI.Internal +{ + /// + /// Spawns a creature at a given position. + /// + // ReSharper disable once ClassNeverInstantiated.Global + public class SpawnAction : AbstractAction + { + private readonly IObjectsManager mObjectsManager; + private ICreature mCreature; + private Vector2 mPosition; + + /// + /// Creates a new SpawnAction that spawns the given creature at the + /// given position. + /// + /// the linked objects manager + /// the creature to spawn + /// the spawn position + public SpawnAction(IObjectsManager objectsManager, ICreature creature, Vector2 position) + { + mObjectsManager = objectsManager; + mCreature = creature; + mPosition = position; + } + + public override void Start() + { + mCreature.Position = mPosition; + mObjectsManager.CreateCreature(mCreature); + base.Start(); + } + + protected override ActionState GetNextState() + { + return ActionState.Done; + } + } +} diff --git a/V3/AI/Internal/WorldView.cs b/V3/AI/Internal/WorldView.cs new file mode 100644 index 0000000..cedd0ae --- /dev/null +++ b/V3/AI/Internal/WorldView.cs @@ -0,0 +1,19 @@ +using System.Collections.Generic; +using V3.Objects; + +namespace V3.AI.Internal +{ + /// + /// Default implementation of IWorldView. + /// + internal class WorldView : IWorldView + { + public int EnemyCount { get; set; } + public int InitialPlebsCount { get; set; } + public int PlebsCount { get; set; } + public float NecromancerHealth { get; set; } + public List IdlingKnights { get; } = new List(); + public List Targets { get; } = new List(); + public List Plebs { get; } = new List(); + } +} diff --git a/V3/AchievementsAndStatistics.cs b/V3/AchievementsAndStatistics.cs new file mode 100644 index 0000000..65419d7 --- /dev/null +++ b/V3/AchievementsAndStatistics.cs @@ -0,0 +1,31 @@ +using System; + +namespace V3 +{ + /// + /// This is a class for all datas of the achievementsand the statistics. + /// + // ReSharper disable once ClassNeverInstantiated.Global + public sealed class AchievementsAndStatistics + { + public bool mKillPrince = false; + public bool mKillKing = false; + public bool mHellsNotWaiting = false; + public bool mKaboom = false; + + public float mMarathonRunner = 0; + public float mIronMan = 0; + public int mMeatballCompany = 0; + public int mSkeletonHorseCavalry = 0; + public int mRightHandOfDeath = 0; + public int mMinimalist = 0; + public int mHundredDeadCorpses = 0; + public int mUndeadArmy = 0; + + public int mKilledCreatures = 00000; + public int mLostServants = 00000; + public float mWalkedDistance = 00000; + + public DateTime mUsedTime; + } +} diff --git a/V3/Bindings.cs b/V3/Bindings.cs new file mode 100644 index 0000000..cc9b193 --- /dev/null +++ b/V3/Bindings.cs @@ -0,0 +1,75 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Content; +using Ninject.Extensions.Factory; +using Ninject.Modules; +using V3.AI; +using V3.AI.Internal; +using V3.Camera; +using V3.Data; +using V3.Data.Internal; +using V3.Effects; +using V3.Input; +using V3.Input.Internal; +using V3.Map; +using V3.Screens; +using V3.Objects; +using V3.Widgets; + +namespace V3 +{ + /// + /// Defines the bindings of constants, factories and singletons for the + /// Ninject dependency injection framework. + /// + public sealed class Bindings : NinjectModule + { + private readonly V3Game mGame; + private readonly GraphicsDeviceManager mGraphicsDeviceManager; + + /// + /// Creates a new Bindings instance for the given game and graphics + /// device manager. + /// + /// the game that uses this instance + /// the graphics device manager + /// instance to use in this instance + public Bindings(V3Game game, GraphicsDeviceManager graphicsDeviceManager) + { + mGame = game; + mGraphicsDeviceManager = graphicsDeviceManager; + } + + public override void Load() + { + // constants + Bind().ToConstant(mGame.Content); + Bind().ToConstant(mGame); + Bind().ToConstant(mGraphicsDeviceManager); + + // factories + Bind().ToFactory(); + Bind().ToFactory(); + Bind().ToFactory(); + Bind().ToFactory(); + Bind().ToFactory(); + + // singletons + Bind().To().InSingletonScope(); + Bind().To().InSingletonScope(); + Bind().To().InSingletonScope(); + Bind().To().InSingletonScope(); + Bind().ToSelf().InSingletonScope(); + Bind().To().InSingletonScope(); + Bind().To().InSingletonScope(); + Bind().ToSelf().InSingletonScope(); + Bind().ToSelf().InSingletonScope(); + Bind().To().InSingletonScope(); + Bind().ToSelf().InSingletonScope(); + + // regular bindings + Bind().To(); + Bind().To(); + Bind().To(); + } + } +} diff --git a/V3/CONTROLS.md b/V3/CONTROLS.md new file mode 100644 index 0000000..335f298 --- /dev/null +++ b/V3/CONTROLS.md @@ -0,0 +1,37 @@ +Controls +======== + +Mouse +----- + +* Clicking left mouse button: Selecting the clicked unit when in range +* Holding down left mouse button: Drawing a rectangle for selecting several units inside +* Clicking right mouse button: Move selected units to mouse position + +Keyboard +-------- + +* ESC : Open menu and pause game +* C : Toggle camera between scrolling and centered mode +* 1 : Trigger meatball explosion +* 2 : Summon zombies from corpses (or from a graveyard if you have no more minions) +* 3 : Transform five zombies to a meatball +* 4 : Transform one zombie to a skeleton +* 5 : Transform three skeletons to a horse + +Techdemo +-------- + +When pressing a specific key once and klicking on the map you can create one unit. + +* F1 : Create zombie +* F2 : Create skeleton +* F3 : Create peasant +* F4 : Create knight + +Cheats +------ + +* F5 : "Hippie mode" +* F6 : Change necromancer gender +* F8 : Toggle Fog of War on/off \ No newline at end of file diff --git a/V3/CREDITS.md b/V3/CREDITS.md new file mode 100644 index 0000000..c0e01e0 --- /dev/null +++ b/V3/CREDITS.md @@ -0,0 +1,51 @@ +Credits +======= + +Most of the content - especially sprites and map textures - is taken from the FLARE game. +http://flarerpg.org/ +https://github.com/clintbellanger/flare-game +"All of Flare's art and data files are released under CC-BY-SA 3.0. Later versions are permitted." + +The maps were created with the Tiled Map Editor . +Special thanks to Sabrina for pulling an all nighter and creating the large map for the main mission. + +Further content: +---------------- +* Castle sprite from Feudal Wars (CC0) + +* Animated particle effects #1 and #2 by para (CC0) + + +* Explosion animation and sound by WrathGames Studio (CC-BY 3.0) + + +* The Fleischklops / Meatball sprite is licenced under CC BY 3.0. + It was created using Clint Bellanger's Zombie (CC BY 3.0) + http://opengameart.org/content/zombie-0 + +Title screen: +------------- +* "The Triumph of Death" by Pieter Bruegel the Elder (1525 - 1569) + + +Music: +------ +* Title screen music by Kosta T / Konstantin Trokay (CC BY-NC 4.0) + +* Game screen music + + +Sounds: +------- +* Wet squish, slurp impacts by Independent.nu (CC0): + +* High Quality Explosions by Michel Baradari (CC-BY 3.0): + +* The Skeleton Horse sound + +* The Knight sound + +* The Meatball sound + +* The walking sound of the remaining creatures + \ No newline at end of file diff --git a/V3/Camera/CameraCentered.cs b/V3/Camera/CameraCentered.cs new file mode 100644 index 0000000..cd04209 --- /dev/null +++ b/V3/Camera/CameraCentered.cs @@ -0,0 +1,57 @@ +using Microsoft.Xna.Framework; +using V3.Objects; + +namespace V3.Camera +{ + /// + /// This is the Camera Class for a player-centered camera mode. Does not go outside the map. + /// + // ReSharper disable once ClassNeverInstantiated.Global + public sealed class CameraCentered : ICamera + { + public int MapPixelWidth { get; set; } + public int MapPixelHeight { get; set; } + private int mMaxX; + private int mMaxY; + public Matrix Transform { get; set; } + private Point mCamCenter; + public Vector2 Location { get { return mCamCenter.ToVector2(); } set { mCamCenter = value.ToPoint(); } } + public Point ScreenSize => new Point(mGraphicsDeviceManager.GraphicsDevice.Viewport.Width, mGraphicsDeviceManager.GraphicsDevice.Viewport.Height); + public Rectangle ScreenRectangle => new Rectangle(mCamCenter, ScreenSize); + + private readonly GraphicsDeviceManager mGraphicsDeviceManager; + + public CameraCentered(GraphicsDeviceManager graphicsDeviceManager) + { + mGraphicsDeviceManager = graphicsDeviceManager; + } + + private int ScreenWidth() + { + return mGraphicsDeviceManager.GraphicsDevice.Viewport.Width; + } + + private int ScreenHeight() + { + return mGraphicsDeviceManager.GraphicsDevice.Viewport.Height; + } + + /// + /// Updates the position of the camera related to the player's position. + /// + public void Update(ICreature player) + { + /*The center of the camera is by default in the upper left corner. To get the player in center, + simply substract the half of the screen values. Does not go outside the map. + */ + mMaxX = MapPixelWidth - ScreenWidth(); + mMaxY = MapPixelHeight / 2 - ScreenHeight(); + + mCamCenter = new Point(MathHelper.Clamp((int)(player.Position.X - ScreenWidth() * 0.5f), 0, mMaxX), + MathHelper.Clamp((int)(player.Position.Y - ScreenHeight() * 0.5f), 0, mMaxY)); + + //Transform matrix for the camera to make sure it is moving. + Transform = Matrix.CreateTranslation(new Vector3(-mCamCenter.ToVector2(), 0)); + } + } +} \ No newline at end of file diff --git a/V3/Camera/CameraManager.cs b/V3/Camera/CameraManager.cs new file mode 100644 index 0000000..b4d502e --- /dev/null +++ b/V3/Camera/CameraManager.cs @@ -0,0 +1,71 @@ +using Microsoft.Xna.Framework; +using System.Collections.Generic; +using V3.Data; +using V3.Objects; + +namespace V3.Camera +{ + /// + /// Stores and provides access to the possible cameras. + /// + // ReSharper disable once ClassNeverInstantiated.Global + public sealed class CameraManager + { + private readonly IOptionsManager mOptionsManager; + private readonly CameraCentered mCameraCentered; + private readonly CameraScrolling mCameraScrolling; + + /// + /// Creates a new CameraManager. + /// + public CameraManager(CameraCentered cameraCentered, + CameraScrolling cameraScrolling, IOptionsManager optionsManager) + { + mCameraCentered = cameraCentered; + mCameraScrolling = cameraScrolling; + mOptionsManager = optionsManager; + } + + /// + /// Initializes the cameras with the given map data. + /// + public void Initialize(Point mapPixelSize) + { + // TODO: Warum *2? Irgendwas stimmt bei der Interpretation hier nicht. + var mapPixelHeight = mapPixelSize.Y * 2; + var mapPixelWidth = mapPixelSize.X; + var cameras = new List { mCameraCentered, mCameraScrolling }; + foreach (var camera in cameras) + { + camera.MapPixelHeight = mapPixelHeight; + camera.MapPixelWidth = mapPixelWidth; + } + } + + /// + /// Updates the cameras. + /// + public void Update(ICreature creature) + { + GetCamera().Update(creature); + if (mOptionsManager.Options.CameraType != CameraType.Scrolling) + mCameraScrolling.Location = GetCamera().Location; + } + + /// + /// Returns the currently selected camera. + /// + public ICamera GetCamera() + { + switch (mOptionsManager.Options.CameraType) + { + case CameraType.Centered: + return mCameraCentered; + case CameraType.Scrolling: + return mCameraScrolling; + default: + return mCameraScrolling; + } + } + } +} diff --git a/V3/Camera/CameraScrolling.cs b/V3/Camera/CameraScrolling.cs new file mode 100644 index 0000000..72e4911 --- /dev/null +++ b/V3/Camera/CameraScrolling.cs @@ -0,0 +1,96 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Input; +using V3.Objects; +using MathHelper = Microsoft.Xna.Framework.MathHelper; +using Vector2 = Microsoft.Xna.Framework.Vector2; + +namespace V3.Camera +{ + /// + /// This is the camera class for a map-scrolling camera mode. Does not move over the map. + /// + // ReSharper disable once ClassNeverInstantiated.Global + public sealed class CameraScrolling : ICamera + { + public int MapPixelWidth { get; set; } + public int MapPixelHeight { get; set; } + private const int MinOffset = 10; + private const int CameraSpeed = 10; + private readonly GraphicsDeviceManager mGraphicsDeviceManager; + private Point mLocation; + public Matrix Transform { get; set; } + private int mMaxX; + private int mMaxY; + public Vector2 Location {get {return mLocation.ToVector2();} set { mLocation = value.ToPoint(); } } + public Point ScreenSize => new Point(mGraphicsDeviceManager.GraphicsDevice.Viewport.Width, mGraphicsDeviceManager.GraphicsDevice.Viewport.Height); + public Rectangle ScreenRectangle => new Rectangle(mLocation, ScreenSize); + + public CameraScrolling(GraphicsDeviceManager graphicsDeviceManager) + { + mGraphicsDeviceManager = graphicsDeviceManager; + } + + public void Update(ICreature player) + { + var viewport = mGraphicsDeviceManager.GraphicsDevice.Viewport; + + mMaxX = MapPixelWidth - viewport.Width; + mMaxY = MapPixelHeight / 2 - viewport.Height; + + var mouse = Mouse.GetState(); + if (mouse.X < MinOffset) + { + MoveCameraLeft(); + } + + if (mouse.X > viewport.Width - MinOffset) + { + MoveCameraRight(); + } + + if (mouse.Y < MinOffset) + { + MoveCameraDown(); + } + + if (mouse.Y > viewport.Height - MinOffset) + { + MoveCameraUp(); + } + Transform = Matrix.CreateTranslation(new Vector3(-mLocation.ToVector2(), 0)); + } + + /// + /// Move the Camera to the left. Does not go outside the map. + /// + private void MoveCameraLeft() + { + mLocation.X = MathHelper.Clamp(mLocation.X - CameraSpeed, 0, mMaxX); + } + + /// + /// Move the Camera to the right. Does not go outside the map. + /// + private void MoveCameraRight() + { + mLocation.X = MathHelper.Clamp(mLocation.X + CameraSpeed, 0, mMaxX); + } + + /// + /// Move the Camera up. Does not go outside the map. + /// + private void MoveCameraUp() + { + mLocation.Y = MathHelper.Clamp(mLocation.Y + CameraSpeed, 0, mMaxY); + } + + + /// + /// Move the Camera down. Does not go outside the map. + /// + private void MoveCameraDown() + { + mLocation.Y = MathHelper.Clamp(mLocation.Y - CameraSpeed, 0, mMaxY); + } + } +} \ No newline at end of file diff --git a/V3/Camera/CameraType.cs b/V3/Camera/CameraType.cs new file mode 100644 index 0000000..4e373d9 --- /dev/null +++ b/V3/Camera/CameraType.cs @@ -0,0 +1,8 @@ +namespace V3.Camera +{ + public enum CameraType + { + Centered, + Scrolling + } +} diff --git a/V3/Camera/ICamera.cs b/V3/Camera/ICamera.cs new file mode 100644 index 0000000..4a8bbcd --- /dev/null +++ b/V3/Camera/ICamera.cs @@ -0,0 +1,18 @@ +using Microsoft.Xna.Framework; +using V3.Objects; + +namespace V3.Camera +{ + public interface ICamera + { + Matrix Transform { get; set; } + Vector2 Location { get; set; } + Point ScreenSize { get; } + Rectangle ScreenRectangle { get; } + + void Update(ICreature player); + + int MapPixelWidth { get; set; } + int MapPixelHeight { get; set; } + } + } diff --git a/V3/ClassDiagram1.cd b/V3/ClassDiagram1.cd new file mode 100644 index 0000000..7b89419 --- /dev/null +++ b/V3/ClassDiagram1.cd @@ -0,0 +1,2 @@ + + \ No newline at end of file diff --git a/V3/Content/Buttons/Button-01.png b/V3/Content/Buttons/Button-01.png new file mode 100644 index 0000000..7c1f22d Binary files /dev/null and b/V3/Content/Buttons/Button-01.png differ diff --git a/V3/Content/Buttons/Button-01_Pressed.png b/V3/Content/Buttons/Button-01_Pressed.png new file mode 100644 index 0000000..c67cf34 Binary files /dev/null and b/V3/Content/Buttons/Button-01_Pressed.png differ diff --git a/V3/Content/Buttons/Button-02.png b/V3/Content/Buttons/Button-02.png new file mode 100644 index 0000000..123a375 Binary files /dev/null and b/V3/Content/Buttons/Button-02.png differ diff --git a/V3/Content/Buttons/Button-02_Pressed.png b/V3/Content/Buttons/Button-02_Pressed.png new file mode 100644 index 0000000..a017676 Binary files /dev/null and b/V3/Content/Buttons/Button-02_Pressed.png differ diff --git a/V3/Content/Buttons/Button-03.png b/V3/Content/Buttons/Button-03.png new file mode 100644 index 0000000..a06547d Binary files /dev/null and b/V3/Content/Buttons/Button-03.png differ diff --git a/V3/Content/Buttons/Button-03_Pressed.png b/V3/Content/Buttons/Button-03_Pressed.png new file mode 100644 index 0000000..a2fe634 Binary files /dev/null and b/V3/Content/Buttons/Button-03_Pressed.png differ diff --git a/V3/Content/Buttons/Button-04.png b/V3/Content/Buttons/Button-04.png new file mode 100644 index 0000000..42a60da Binary files /dev/null and b/V3/Content/Buttons/Button-04.png differ diff --git a/V3/Content/Buttons/Button-04_Pressed.png b/V3/Content/Buttons/Button-04_Pressed.png new file mode 100644 index 0000000..0cca164 Binary files /dev/null and b/V3/Content/Buttons/Button-04_Pressed.png differ diff --git a/V3/Content/Buttons/Button-05.png b/V3/Content/Buttons/Button-05.png new file mode 100644 index 0000000..3a2d99c Binary files /dev/null and b/V3/Content/Buttons/Button-05.png differ diff --git a/V3/Content/Buttons/Button-05_Pressed.png b/V3/Content/Buttons/Button-05_Pressed.png new file mode 100644 index 0000000..86b8b9e Binary files /dev/null and b/V3/Content/Buttons/Button-05_Pressed.png differ diff --git a/V3/Content/Buttons/Button-06.png b/V3/Content/Buttons/Button-06.png new file mode 100644 index 0000000..1bc3448 Binary files /dev/null and b/V3/Content/Buttons/Button-06.png differ diff --git a/V3/Content/Buttons/Button-06_Pressed.png b/V3/Content/Buttons/Button-06_Pressed.png new file mode 100644 index 0000000..5a6cc1e Binary files /dev/null and b/V3/Content/Buttons/Button-06_Pressed.png differ diff --git a/V3/Content/Buttons/Button-07.png b/V3/Content/Buttons/Button-07.png new file mode 100644 index 0000000..422e445 Binary files /dev/null and b/V3/Content/Buttons/Button-07.png differ diff --git a/V3/Content/Buttons/Button-07_Pressed.png b/V3/Content/Buttons/Button-07_Pressed.png new file mode 100644 index 0000000..5cbe2b9 Binary files /dev/null and b/V3/Content/Buttons/Button-07_Pressed.png differ diff --git a/V3/Content/Content.mgcb b/V3/Content/Content.mgcb new file mode 100644 index 0000000..bbaf13b --- /dev/null +++ b/V3/Content/Content.mgcb @@ -0,0 +1,1092 @@ + +#----------------------------- Global Properties ----------------------------# + +/outputDir:bin/$(Platform) +/intermediateDir:obj/$(Platform) +/platform:DesktopGL +/config: +/profile:Reach +/compress:False + +#-------------------------------- References --------------------------------# + + +#---------------------------------- Content ---------------------------------# + +#begin Fonts/MenuFont.spritefont +/importer:FontDescriptionImporter +/processor:FontDescriptionProcessor +/processorParam:TextureFormat=Color +/build:Fonts/MenuFont.spritefont + +#begin Sprites/zombie.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/zombie.png + +#begin Textures/grassland.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Textures/grassland.png + +#begin Textures/grassland_trees.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Textures/grassland_trees.png + +#begin Textures/grassland_water.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Textures/grassland_water.png + +#begin Textures/houses_front.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Textures/houses_front.png + +#begin Textures/houses_rear.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Textures/houses_rear.png + +#begin Sprites/skeleton.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/skeleton.png + +#begin Sprites/necromancer.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/necromancer.png + +#begin Sounds/walking.wav +/importer:WavImporter +/processor:SoundEffectProcessor +/processorParam:Quality=Best +/build:Sounds/walking.wav + +#begin Maps/map_grassland.tmx +/copy:Maps/map_grassland.tmx + +#begin Textures/pathfinder.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Textures/pathfinder.png + +#begin Sprites/WhiteRectangle.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/WhiteRectangle.png + +#begin Fonts/UnitFont.spritefont +/importer:FontDescriptionImporter +/processor:FontDescriptionProcessor +/processorParam:TextureFormat=Color +/build:Fonts/UnitFont.spritefont + +#begin Maps/work_in_progress.tmx +/copy:Maps/work_in_progress.tmx + +#begin Sprites/shield.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/shield.png + +#begin Sprites/longsword.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/longsword.png + +#begin Sprites/head_plate.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/head_plate.png + +#begin Sprites/head_plate_female.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/head_plate_female.png + +#begin Sprites/plate.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/plate.png + +#begin Sprites/cloth.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/cloth.png + +#begin Sprites/shield_female.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/shield_female.png + +#begin Sprites/longsword_female.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/longsword_female.png + +#begin Sprites/plate_female.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/plate_female.png + +#begin Sprites/cloth_female.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/cloth_female.png + +#begin Sprites/head_female.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/head_female.png + +#begin Sprites/nude_female.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/nude_female.png + +#begin Sprites/head_bald.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/head_bald.png + +#begin Sprites/head.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/head.png + +#begin Sprites/nude.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/nude.png + +#begin Sprites/selection.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/selection.png + +#begin Sprites/skeleton_horse.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/skeleton_horse.png + +#begin Sprites/fleischklops.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/fleischklops.png + +#begin Sprites/cloud.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/cloud.png + +#begin Sprites/prince.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/prince.png + +#begin Buttons/Button-01.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Buttons/Button-01.png + +#begin Buttons/Button-02.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Buttons/Button-02.png + +#begin Buttons/Button-03.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Buttons/Button-03.png + +#begin Buttons/Button-04.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Buttons/Button-04.png + +#begin Buttons/Button-05.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Buttons/Button-05.png + +#begin Buttons/Button-06.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Buttons/Button-06.png + +#begin Buttons/Button-07.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Buttons/Button-07.png + +#begin Textures/castle.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Textures/castle.png + +#begin Menu/arrow_white.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Menu/arrow_white.png + +#begin Menu/mainscreen.jpg +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Menu/mainscreen.jpg + +#begin Sounds/Kosta_T_-_06.mp3 +/importer:Mp3Importer +/processor:SongProcessor +/processorParam:Quality=Best +/build:Sounds/Kosta_T_-_06.mp3 + +#begin Maps/techdemo.tmx +/copy:Maps/techdemo.tmx + +#begin Textures/EmptyPixel.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Textures/EmptyPixel.png + +#begin Sounds/Knight.wav +/importer:WavImporter +/processor:SoundEffectProcessor +/processorParam:Quality=Best +/build:Sounds/Knight.wav + +#begin Sounds/SkeletonHorse.wav +/importer:WavImporter +/processor:SoundEffectProcessor +/processorParam:Quality=Best +/build:Sounds/SkeletonHorse.wav + +#begin Sounds/punch.wav +/importer:WavImporter +/processor:SoundEffectProcessor +/processorParam:Quality=Best +/build:Sounds/punch.wav + +#begin Sounds/Mummy_Zombie-SoundBible.wav +/importer:WavImporter +/processor:SoundEffectProcessor +/processorParam:Quality=Best +/build:Sounds/Mummy_Zombie-SoundBible.wav + +#begin Sounds/Monster_Gigante-Doberman-1334685792.wav +/importer:WavImporter +/processor:SoundEffectProcessor +/processorParam:Quality=Best +/build:Sounds/Monster_Gigante-Doberman-1334685792.wav + +#begin Menu/Titel.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Menu/Titel.png + +#begin Sprites/skeleton_rider.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/skeleton_rider.png + +#begin Effects/particlefx_03.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Effects/particlefx_03.png + +#begin Effects/particlefx_04.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Effects/particlefx_04.png + +#begin Effects/particlefx_05.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Effects/particlefx_05.png + +#begin Effects/blood_hit_01.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Effects/blood_hit_01.png + +#begin Effects/blood_hit_02.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Effects/blood_hit_02.png + +#begin Effects/blood_hit_03.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Effects/blood_hit_03.png + +#begin Effects/blood_hit_04.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Effects/blood_hit_04.png + +#begin Effects/blood_hit_05.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Effects/blood_hit_05.png + +#begin Effects/blood_hit_06.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Effects/blood_hit_06.png + +#begin Effects/blood_hit_08.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Effects/blood_hit_08.png + +#begin Effects/explosion.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Effects/explosion.png + +#begin Sounds/explosion1.ogg +/importer:OggImporter +/processor:SoundEffectProcessor +/processorParam:Quality=Best +/build:Sounds/explosion1.ogg + +#begin Sounds/impactsplat01.ogg +/importer:OggImporter +/processor:SoundEffectProcessor +/processorParam:Quality=Best +/build:Sounds/impactsplat01.ogg + +#begin Sprites/skeleton_elite.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/skeleton_elite.png + +#begin Sprites/staff_female.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/staff_female.png + +#begin Sprites/staff.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/staff.png + +#begin Sprites/necromancer_female.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/necromancer_female.png + +#begin Sprites/ellipse.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/ellipse.png + +#begin Sprites/fog.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/fog.png + +#begin Buttons/Button-01_Pressed.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Buttons/Button-01_Pressed.png + +#begin Buttons/Button-02_Pressed.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Buttons/Button-02_Pressed.png + +#begin Buttons/Button-03_Pressed.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Buttons/Button-03_Pressed.png + +#begin Buttons/Button-04_Pressed.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Buttons/Button-04_Pressed.png + +#begin Buttons/Button-05_Pressed.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Buttons/Button-05_Pressed.png + +#begin Buttons/Button-06_Pressed.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Buttons/Button-06_Pressed.png + +#begin Buttons/Button-07_Pressed.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Buttons/Button-07_Pressed.png + +#begin Sprites/chain_female.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/chain_female.png + +#begin Sprites/head_chain_female.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/head_chain_female.png + +#begin Sprites/buckler_female.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/buckler_female.png + +#begin Sprites/shortsword_female.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/shortsword_female.png + +#begin Sprites/buckler.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/buckler.png + +#begin Sprites/shortsword.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/shortsword.png + +#begin Sprites/head_chain.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/head_chain.png + +#begin Sprites/chain.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/chain.png + +#begin Sprites/arrows.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/arrows.png + +#begin Effects/quake.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Effects/quake.png + +#begin Sprites/skeleton_archer.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/skeleton_archer.png + +#begin Sprites/zombie_club.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/zombie_club.png + +#begin Sprites/king.png +/importer:TextureImporter +/processor:TextureProcessor +/processorParam:ColorKeyColor=255,0,255,255 +/processorParam:ColorKeyEnabled=True +/processorParam:GenerateMipmaps=False +/processorParam:PremultiplyAlpha=True +/processorParam:ResizeToPowerOfTwo=False +/processorParam:MakeSquare=False +/processorParam:TextureFormat=Color +/build:Sprites/king.png + +#begin Fonts/DeathFont.spritefont +/importer:FontDescriptionImporter +/processor:FontDescriptionProcessor +/processorParam:TextureFormat=Color +/build:Fonts/DeathFont.spritefont + +#begin Sounds/Afraid_to_Go.mp3 +/importer:Mp3Importer +/processor:SongProcessor +/processorParam:Quality=Best +/build:Sounds/Afraid_to_Go.mp3 + +#begin Fonts/VictoryFont.spritefont +/importer:FontDescriptionImporter +/processor:FontDescriptionProcessor +/processorParam:TextureFormat=Color +/build:Fonts/VictoryFont.spritefont + +#begin Sounds/explode.wav +/importer:WavImporter +/processor:SoundEffectProcessor +/processorParam:Quality=Best +/build:Sounds/explode.wav + +#begin Sounds/explodemini.wav +/importer:WavImporter +/processor:SoundEffectProcessor +/processorParam:Quality=Best +/build:Sounds/explodemini.wav + +#begin Sounds/horse.wav +/importer:WavImporter +/processor:SoundEffectProcessor +/processorParam:Quality=Best +/build:Sounds/horse.wav + +#begin Sounds/zonk2.wav +/importer:WavImporter +/processor:SoundEffectProcessor +/processorParam:Quality=Best +/build:Sounds/zonk2.wav + diff --git a/V3/Content/Effects/blood_hit_01.png b/V3/Content/Effects/blood_hit_01.png new file mode 100644 index 0000000..4ce41d8 Binary files /dev/null and b/V3/Content/Effects/blood_hit_01.png differ diff --git a/V3/Content/Effects/blood_hit_02.png b/V3/Content/Effects/blood_hit_02.png new file mode 100644 index 0000000..b4ce9ba Binary files /dev/null and b/V3/Content/Effects/blood_hit_02.png differ diff --git a/V3/Content/Effects/blood_hit_03.png b/V3/Content/Effects/blood_hit_03.png new file mode 100644 index 0000000..0f827f4 Binary files /dev/null and b/V3/Content/Effects/blood_hit_03.png differ diff --git a/V3/Content/Effects/blood_hit_04.png b/V3/Content/Effects/blood_hit_04.png new file mode 100644 index 0000000..bf122a2 Binary files /dev/null and b/V3/Content/Effects/blood_hit_04.png differ diff --git a/V3/Content/Effects/blood_hit_05.png b/V3/Content/Effects/blood_hit_05.png new file mode 100644 index 0000000..a177ce9 Binary files /dev/null and b/V3/Content/Effects/blood_hit_05.png differ diff --git a/V3/Content/Effects/blood_hit_06.png b/V3/Content/Effects/blood_hit_06.png new file mode 100644 index 0000000..51aa729 Binary files /dev/null and b/V3/Content/Effects/blood_hit_06.png differ diff --git a/V3/Content/Effects/blood_hit_08.png b/V3/Content/Effects/blood_hit_08.png new file mode 100644 index 0000000..87b6794 Binary files /dev/null and b/V3/Content/Effects/blood_hit_08.png differ diff --git a/V3/Content/Effects/explosion.png b/V3/Content/Effects/explosion.png new file mode 100644 index 0000000..0f4f3e9 Binary files /dev/null and b/V3/Content/Effects/explosion.png differ diff --git a/V3/Content/Effects/particlefx_03.png b/V3/Content/Effects/particlefx_03.png new file mode 100644 index 0000000..2649c85 Binary files /dev/null and b/V3/Content/Effects/particlefx_03.png differ diff --git a/V3/Content/Effects/particlefx_04.png b/V3/Content/Effects/particlefx_04.png new file mode 100644 index 0000000..346695e Binary files /dev/null and b/V3/Content/Effects/particlefx_04.png differ diff --git a/V3/Content/Effects/particlefx_05.png b/V3/Content/Effects/particlefx_05.png new file mode 100644 index 0000000..d046357 Binary files /dev/null and b/V3/Content/Effects/particlefx_05.png differ diff --git a/V3/Content/Effects/quake.png b/V3/Content/Effects/quake.png new file mode 100644 index 0000000..6fe7ad0 Binary files /dev/null and b/V3/Content/Effects/quake.png differ diff --git a/V3/Content/Fonts/Blutschrift.ttf b/V3/Content/Fonts/Blutschrift.ttf new file mode 100644 index 0000000..da803c1 Binary files /dev/null and b/V3/Content/Fonts/Blutschrift.ttf differ diff --git a/V3/Content/Fonts/DeathFont.spritefont b/V3/Content/Fonts/DeathFont.spritefont new file mode 100644 index 0000000..8cbab91 --- /dev/null +++ b/V3/Content/Fonts/DeathFont.spritefont @@ -0,0 +1,50 @@ + + + + Blutschrift + 50 + 3 + + + + + ~ + + + + ä + ä + + + + ö + ö + + + + ü + ü + + + + Ä + Ä + + + + Ö + Ö + + + + Ü + Ü + + + + ß + ß + + + + \ No newline at end of file diff --git a/V3/Content/Fonts/DejaVuSans.ttf b/V3/Content/Fonts/DejaVuSans.ttf new file mode 100644 index 0000000..de12789 Binary files /dev/null and b/V3/Content/Fonts/DejaVuSans.ttf differ diff --git a/V3/Content/Fonts/MenuFont.spritefont b/V3/Content/Fonts/MenuFont.spritefont new file mode 100644 index 0000000..e6362fb --- /dev/null +++ b/V3/Content/Fonts/MenuFont.spritefont @@ -0,0 +1,50 @@ + + + + grabstein + 20 + 3 + + + + + ~ + + + + ä + ä + + + + ö + ö + + + + ü + ü + + + + Ä + Ä + + + + Ö + Ö + + + + Ü + Ü + + + + ß + ß + + + + \ No newline at end of file diff --git a/V3/Content/Fonts/Siegesschriftzug.ttf b/V3/Content/Fonts/Siegesschriftzug.ttf new file mode 100644 index 0000000..59dd36d Binary files /dev/null and b/V3/Content/Fonts/Siegesschriftzug.ttf differ diff --git a/V3/Content/Fonts/UnitFont.spritefont b/V3/Content/Fonts/UnitFont.spritefont new file mode 100644 index 0000000..fa4bf9f --- /dev/null +++ b/V3/Content/Fonts/UnitFont.spritefont @@ -0,0 +1,50 @@ + + + + grabstein + 12 + 3 + + + + + ~ + + + + ä + ä + + + + ö + ö + + + + ü + ü + + + + Ä + Ä + + + + Ö + Ö + + + + Ü + Ü + + + + ß + ß + + + + \ No newline at end of file diff --git a/V3/Content/Fonts/VictoryFont.spritefont b/V3/Content/Fonts/VictoryFont.spritefont new file mode 100644 index 0000000..28d695a --- /dev/null +++ b/V3/Content/Fonts/VictoryFont.spritefont @@ -0,0 +1,50 @@ + + + + Siegesschriftzug + 50 + 3 + + + + + ~ + + + + ä + ä + + + + ö + ö + + + + ü + ü + + + + Ä + Ä + + + + Ö + Ö + + + + Ü + Ü + + + + ß + ß + + + + \ No newline at end of file diff --git a/V3/Content/Fonts/grabstein.ttf b/V3/Content/Fonts/grabstein.ttf new file mode 100644 index 0000000..711b3a1 Binary files /dev/null and b/V3/Content/Fonts/grabstein.ttf differ diff --git a/V3/Content/Maps/map_grassland.tmx b/V3/Content/Maps/map_grassland.tmx new file mode 100644 index 0000000..9162f2a --- /dev/null +++ b/V3/Content/Maps/map_grassland.tmx @@ -0,0 +1,988 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,153,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,145,146,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,156,177,154,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,152,151,1,1,1,1,1,1,1,1,1,1,1,1,1,24,31,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,155,1,1,1,1,1,1,1,1,1,1,1,1,1,24,24,24,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,24,23,24,24,24,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,24,23,23,23,24,24,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,24,23,23,23,23,23,32,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +153,153,153,1,1,1,153,1,1,1,1,1,1,1,24,23,29,29,29,23,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +165,165,150,153,153,149,154,1,1,1,1,1,1,24,23,1,1,1,1,1,1,1,1,1,153,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +177,163,163,165,165,165,151,1,1,1,1,1,1,24,23,1,1,1,1,1,1,1,1,1,145,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +155,155,155,148,177,151,1,1,1,1,1,1,24,23,1,1,1,1,1,1,1,1,1,145,187,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,155,155,1,1,1,1,1,1,1,24,1,1,1,1,1,1,1,1,1,145,187,187,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,24,1,1,1,1,1,1,1,1,1,145,187,187,187,194,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,24,1,1,1,1,1,1,1,1,1,145,187,187,187,198,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,24,1,1,1,1,1,1,1,1,1,149,187,187,187,208,187,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,24,1,1,1,1,1,1,1,1,1,156,187,187,187,206,187,187,154,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,24,1,1,1,1,1,1,1,1,1,152,187,187,198,187,187,151,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,24,1,1,1,1,1,1,1,1,1,1,152,187,187,187,187,151,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,24,1,1,1,1,1,1,1,1,1,1,1,164,187,187,187,151,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,24,1,1,1,1,1,1,1,1,1,1,160,187,187,187,151,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,24,1,1,1,1,1,1,1,1,1,1,1,152,187,187,151,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,24,1,1,1,1,1,1,1,1,1,1,1,164,187,166,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,24,1,1,1,1,1,1,1,1,1,1,160,187,187,146,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,24,1,1,1,1,1,1,1,1,1,1,1,152,187,187,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,24,1,1,1,1,1,1,1,1,1,1,1,1,152,187,187,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,24,1,1,1,1,1,1,1,1,1,1,1,1,1,152,187,187,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,24,1,1,1,1,1,1,1,1,1,1,1,1,1,1,164,187,187,158,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,24,1,1,1,1,1,1,1,1,1,1,1,1,1,1,145,187,187,166,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,31,24,1,1,1,1,1,1,1,1,1,1,1,1,1,1,160,187,187,187,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,23,23,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,187,187,187,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,23,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,187,187,187,150,1,1,1,1,1,1,1,1,153,1,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,187,187,187,150,1,1,1,1,1,1,1,149,146,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,187,187,187,154,1,1,1,1,1,1,149,181,146,1,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,187,187,166,1,1,1,1,1,1,149,177,181,146,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,192,187,150,1,1,1,1,1,156,177,177,181,150,1,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,148,187,187,154,1,1,1,1,1,164,177,181,181,150,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,164,187,166,1,1,1,1,1,145,177,181,181,181,150,1,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,160,187,187,150,1,1,1,1,145,177,181,181,181,181,150,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,187,187,150,1,1,1,145,177,181,181,181,181,181,146,1,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,187,187,150,1,1,145,177,181,181,181,181,181,177,146,1,1,1,1,1,1,1, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,187,187,150,1,145,177,180,167,163,163,163,163,163,154,1,1,1,1,1,1,1, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,148,180,180,146,145,180,180,151,155,155,155,155,155,155,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,148,180,180,165,180,180,166,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,164,180,180,180,180,180,154,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,156,180,180,180,180,180,166,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,148,180,180,180,180,180,154,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,148,180,180,180,180,166,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,148,180,180,180,180,154,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,148,180,180,167,151,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,148,167,151,159,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,159,159,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11, +11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11,11 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,128,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,106,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,128,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,104,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,135,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,216,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,123,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,106,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,135,0,0,0,0, +0,0,0,0,0,0,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,133,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,83,0,0,0,0,83,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,127,0,226,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,221,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +126,109,0,0,0,106,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,109,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,117,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,133,0,0,99,0,0,99,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,135,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,106,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,144,0,0,0,0,0,0,0,133,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,125,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,106,0,0,0,0,133,0,99,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,117,0,0,0,0,0,0,0,0,0,0,0,0,135,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,214,0,0,0,0,0,0,0,135,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,144,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,125,0,0,0,127,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,223,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,133,113,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,130,0,0,0,0,0,0,0,0,0,0,129,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,210,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,88,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,125,0,103,0,0,0,225,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,125,0,0,0,0,0,0,99,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,130,0,0,144,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,99,0,0, +0,0,0,0,88,0,0,0,0,0,0,0,0,0,0,130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,218,110,110,110,110,0,0,0,0,103,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,99,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,117,0,0,0,0,130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,98,117,0,0,0,0,99,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,130,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,88,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,218,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,211,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,227,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,209,0,210,0,211,0,0,0,224,0,225,0,226,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,233,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,212,0,213,0,214,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,221,0,222,0,223,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,215,0,216,0,217,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,227,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,228,0,229,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,218,0,219,0,220,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,232,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,230,0,231,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0 + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/V3/Content/Maps/techdemo.tmx b/V3/Content/Maps/techdemo.tmx new file mode 100644 index 0000000..b26a064 --- /dev/null +++ b/V3/Content/Maps/techdemo.tmx @@ -0,0 +1,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,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +0,0,9,8,3,3,3,7,16,9,16,1,10,7,8,7,10,3,4,5,7,1,11,8,8,6,2,10,16,4,11,5,2,9,9,1,15,7,13,3,8,10,6,16,11,13,16,11,4,0, +0,0,11,10,1,13,16,11,16,14,10,15,6,16,2,11,13,4,2,11,2,15,12,14,8,10,4,8,7,4,3,1,10,16,8,8,1,4,5,12,16,13,1,5,2,11,7,13,3,3, +0,3,3,15,8,16,7,7,6,5,3,8,4,1,7,2,9,5,2,9,14,6,8,1,15,10,12,2,12,11,8,8,4,3,5,14,13,3,1,5,11,9,10,15,7,10,3,15,12,0, +0,4,1,3,13,2,11,9,8,9,12,7,8,1,14,15,11,9,4,15,10,7,9,8,2,13,2,7,14,2,12,1,14,7,11,3,10,6,13,2,6,1,8,14,11,2,10,11,11,11, +3,7,10,12,10,5,9,9,5,2,16,4,7,14,2,10,6,16,9,12,1,7,8,3,12,6,5,16,3,9,16,7,6,16,14,7,15,3,8,16,12,16,3,14,1,13,5,15,11,0, +0,2,7,5,4,4,2,2,16,2,10,13,14,14,7,9,9,7,11,1,13,8,7,15,15,7,6,7,1,9,3,13,4,13,2,15,3,1,5,7,6,15,11,14,1,11,15,7,6,8, +16,16,2,9,13,14,16,1,12,14,4,12,14,16,11,13,16,11,16,3,8,4,7,5,9,8,14,8,13,16,16,9,11,14,14,16,4,2,8,16,4,2,6,7,16,16,12,12,9,0, +0,1,16,2,16,3,6,8,8,7,7,3,3,6,10,11,15,9,6,10,12,8,2,8,9,15,8,1,7,8,14,15,8,13,15,13,11,10,4,7,3,11,8,9,3,13,4,1,14,12, +8,14,16,5,10,15,1,11,6,13,1,2,5,2,16,3,15,9,13,7,9,7,5,5,8,4,3,1,16,4,3,16,16,10,11,4,10,7,5,14,11,11,4,12,1,6,14,13,7,0, +0,10,15,4,10,6,14,5,3,15,13,10,1,10,1,11,3,15,16,3,11,12,9,16,16,2,12,8,13,9,14,3,1,10,9,14,2,6,12,11,7,16,10,16,15,1,11,7,11,5, +12,4,5,3,12,2,8,1,3,11,16,13,9,5,6,6,9,10,6,1,16,6,15,1,14,7,1,14,5,14,1,2,9,14,3,10,2,13,16,5,10,3,4,4,12,11,11,12,8,0, +0,7,16,1,11,2,14,16,9,7,7,1,7,4,6,8,9,3,8,2,10,4,8,3,16,15,6,8,8,6,13,7,8,4,13,15,14,11,2,7,2,6,16,13,3,8,1,9,8,14, +8,8,7,13,15,7,2,4,15,13,6,16,10,14,1,11,8,5,5,3,8,6,13,13,16,8,10,7,10,12,2,2,9,7,2,7,7,6,15,7,1,11,3,7,14,16,16,4,11,0, +0,4,14,16,13,6,3,6,7,1,14,6,4,8,11,11,16,12,6,12,2,9,3,11,14,9,6,9,6,3,13,1,6,8,4,13,9,7,3,2,5,12,15,16,12,15,9,8,15,4, +8,10,16,11,1,11,10,11,13,8,12,10,3,9,2,13,6,1,4,4,1,12,3,9,13,3,11,1,10,7,3,11,5,5,12,2,3,5,3,10,7,7,13,1,11,9,12,1,5,0, +0,7,16,9,7,7,14,5,11,6,10,9,5,16,1,10,3,16,16,12,4,4,8,3,6,8,7,6,9,9,13,10,13,7,11,5,2,16,16,14,10,3,14,13,6,14,7,9,8,4, +12,9,9,14,3,15,13,7,11,1,16,9,1,16,11,12,15,11,8,7,13,2,16,15,2,1,7,10,4,2,3,8,6,16,8,10,12,3,6,1,6,16,15,11,4,15,1,2,4,0, +0,4,8,13,6,9,13,7,2,1,7,14,5,10,9,13,7,10,11,3,16,10,10,5,1,9,8,9,12,9,10,14,10,2,9,3,6,13,5,16,2,13,2,14,3,4,5,13,3,13, +5,11,11,3,9,12,2,11,3,7,14,5,3,15,10,4,12,9,16,14,2,13,15,13,13,4,7,10,6,11,12,5,10,1,3,13,8,7,3,5,1,1,9,3,9,6,15,13,6,0, +0,14,3,15,7,13,11,7,14,14,6,16,9,15,11,1,4,5,12,13,4,13,2,14,9,14,1,6,7,6,2,15,15,12,10,14,8,1,3,13,2,12,3,2,5,14,5,10,3,16, +7,9,4,8,16,5,5,3,7,15,4,15,3,6,11,5,1,14,12,5,5,2,11,5,7,4,8,1,9,11,4,14,1,6,10,4,12,10,10,3,15,2,13,4,3,1,15,2,11,0, +0,11,11,9,16,15,16,6,5,16,12,13,16,10,5,7,15,3,15,7,12,14,11,16,12,11,4,15,4,6,5,15,3,7,3,5,4,3,16,7,16,13,11,3,11,1,15,6,8,12, +8,4,11,13,11,14,9,14,11,15,11,14,9,11,14,7,16,4,13,14,6,5,11,4,13,1,5,2,15,10,3,15,2,10,10,9,6,4,5,11,6,9,13,9,6,2,4,1,7,0, +0,10,3,13,10,8,15,2,12,14,12,10,4,16,2,8,2,15,11,16,8,16,1,6,7,7,14,14,4,9,14,14,16,11,10,11,16,3,1,11,6,7,12,4,9,14,11,13,14,14, +7,11,4,11,7,6,5,12,11,7,14,10,3,8,10,1,2,5,14,10,6,7,3,12,12,3,14,16,2,2,16,9,1,5,13,11,3,1,5,8,15,7,7,1,12,6,15,5,14,0, +0,13,6,10,12,13,1,16,11,3,2,5,12,16,2,14,16,9,11,2,14,9,16,12,1,13,5,13,10,8,4,10,11,16,12,12,13,2,15,2,14,14,5,12,14,9,9,4,4,11, +6,6,10,16,10,2,6,5,8,6,1,15,12,3,5,9,5,16,4,2,1,3,15,8,6,5,9,16,6,3,9,14,12,11,10,11,1,14,5,16,2,15,10,11,14,6,10,10,8,0, +0,4,13,6,16,1,6,4,8,1,2,1,14,2,14,15,10,10,2,8,16,9,12,1,11,5,4,3,14,14,9,4,6,13,4,16,8,2,7,12,16,7,9,6,4,14,14,3,3,16, +16,8,16,11,4,3,3,11,6,1,7,4,5,11,5,4,6,4,15,15,5,3,11,15,5,5,8,8,15,16,9,15,1,14,10,4,3,2,11,11,1,3,5,16,13,15,5,4,1,0, +0,12,6,2,12,12,1,13,1,16,16,10,5,12,6,4,13,1,6,2,8,12,15,6,4,6,10,2,8,6,16,2,11,14,4,14,15,15,6,13,2,2,4,15,16,2,6,4,16,1, +10,3,7,7,5,14,13,7,15,12,15,8,8,5,16,15,8,10,15,12,3,8,5,8,8,5,5,7,15,4,15,7,11,15,9,2,11,14,7,12,6,1,7,2,15,4,16,14,4,0, +0,16,4,9,14,12,13,8,13,3,10,9,8,3,1,2,9,10,12,10,7,7,3,7,12,9,15,1,2,16,12,1,3,13,3,14,9,1,15,3,1,12,11,8,5,1,5,8,2,2, +14,9,13,8,12,1,8,1,1,10,10,1,10,1,15,11,1,12,2,14,1,5,12,8,2,16,4,8,10,2,1,8,16,14,7,4,6,6,9,2,15,9,8,12,12,5,5,6,11,0, +0,4,2,12,14,2,13,6,12,2,2,4,3,8,2,4,5,14,1,10,7,1,8,14,5,4,5,12,15,13,9,6,10,8,10,1,12,4,4,7,5,6,6,6,4,7,4,2,2,3, +16,14,8,1,1,6,5,7,7,2,1,6,11,8,14,4,13,16,3,12,12,6,11,10,11,5,1,11,14,15,3,16,14,4,2,14,4,11,1,9,13,9,6,12,8,9,10,15,6,0, +0,15,5,8,15,3,16,12,4,14,8,11,3,4,4,5,7,16,4,3,4,6,16,4,6,2,7,16,1,10,5,9,4,11,9,9,3,10,14,2,14,6,7,15,10,6,14,2,8,10, +8,1,13,10,3,12,16,9,15,1,10,15,7,12,10,2,11,14,5,16,7,15,7,11,7,15,3,15,3,1,16,11,5,3,15,6,1,6,5,14,16,3,15,7,1,10,16,11,10,0, +0,9,7,12,16,2,8,4,13,9,8,5,14,16,1,16,2,5,6,2,2,4,6,3,5,5,16,12,15,13,13,13,15,11,2,7,1,13,3,4,15,14,13,13,12,3,13,6,12,16, +15,15,14,14,11,11,14,2,3,11,14,16,9,11,11,10,6,2,12,14,16,3,6,2,7,10,4,8,6,14,15,13,16,16,8,7,7,13,13,8,3,12,4,11,8,12,15,7,7,0, +0,16,8,1,10,8,1,10,2,4,11,3,3,1,16,11,2,13,13,14,2,6,12,11,7,10,12,16,7,8,8,14,7,15,15,2,12,16,15,15,13,12,6,4,1,2,4,4,15,5, +15,7,7,15,1,1,14,3,9,6,8,7,1,3,8,7,5,4,16,14,11,3,15,6,12,7,3,5,13,10,8,2,2,15,11,3,12,11,4,10,13,16,12,9,5,16,10,16,1,0, +0,6,5,2,1,5,3,10,8,12,8,13,1,6,16,11,16,7,12,6,16,2,16,8,2,4,7,12,7,10,13,4,10,8,6,5,7,6,9,11,14,1,1,2,6,9,15,15,9,4, +5,5,10,8,3,13,15,14,6,5,11,3,13,11,12,12,8,14,5,4,11,1,11,6,14,8,6,16,7,11,16,2,3,4,5,15,15,15,3,14,12,10,13,6,11,8,7,1,3,0, +0,1,16,13,16,4,6,12,12,4,9,15,14,13,13,7,6,4,16,11,15,6,6,15,9,8,13,10,13,9,11,1,16,15,15,12,10,8,16,16,1,13,14,9,15,14,1,11,10,2, +10,13,11,1,2,2,16,15,7,7,15,16,6,10,2,9,3,2,5,3,5,12,14,13,14,11,7,15,2,10,1,5,15,8,5,4,8,12,1,4,7,4,10,7,12,3,11,5,14,0, +0,3,6,7,11,13,5,1,16,7,10,15,14,6,16,11,1,11,2,11,3,3,6,5,7,9,1,7,15,2,1,15,8,2,2,6,14,8,13,1,7,1,7,4,6,3,2,12,11,6, +9,6,2,9,2,12,2,14,16,9,3,12,9,4,15,7,13,14,12,13,7,2,11,8,13,7,7,10,14,13,4,2,6,16,2,7,8,4,12,14,5,11,6,2,7,14,15,13,2,0, +0,2,8,13,4,7,1,16,14,12,1,16,2,3,9,5,2,12,13,8,2,8,15,3,3,8,4,16,12,14,16,8,15,14,7,7,2,11,15,9,11,7,13,8,15,7,8,1,6,16, +13,3,5,7,15,4,7,13,11,14,15,3,14,5,11,3,4,11,5,8,9,2,10,8,6,8,16,10,3,11,1,4,7,7,16,8,6,7,4,9,5,4,13,6,5,5,15,16,7,0, +0,14,5,12,14,12,11,9,11,6,1,2,8,6,3,11,3,9,2,12,14,2,3,1,2,6,15,11,10,1,6,14,7,3,9,6,13,15,15,16,5,14,5,14,15,13,10,9,12,13, +7,3,7,16,15,4,16,3,4,2,1,13,12,6,9,8,16,10,11,1,11,14,10,7,12,2,15,11,2,8,2,3,16,5,16,4,12,3,7,8,14,11,8,10,15,10,8,9,13,0, +0,10,9,10,8,13,10,11,1,1,11,15,11,15,3,13,14,8,14,3,13,7,3,7,3,14,16,7,2,8,14,12,6,10,12,5,3,15,2,10,5,12,1,13,2,15,3,7,7,12, +14,16,15,1,8,8,7,9,3,9,5,9,16,12,13,7,6,1,11,10,3,11,15,6,11,9,1,16,9,10,15,7,15,10,13,14,4,7,7,1,6,7,15,1,12,7,11,5,15,0, +0,10,7,7,11,9,8,2,8,10,13,2,9,8,13,1,12,9,13,4,12,16,13,12,15,15,10,8,8,2,15,2,9,1,1,3,13,3,4,13,13,8,5,1,14,1,2,12,3,8, +16,16,9,4,4,5,16,5,1,9,6,6,7,3,9,15,16,15,16,4,16,9,12,5,6,2,10,10,12,10,16,7,7,10,1,9,4,4,8,9,13,6,12,11,6,10,12,11,13,0, +0,5,3,12,16,8,15,7,9,9,13,7,11,16,11,2,11,4,6,1,16,14,14,11,16,6,15,10,2,6,11,8,14,8,16,14,12,4,16,8,5,7,11,15,1,12,2,15,11,14, +2,15,11,5,12,16,5,15,16,9,7,8,2,6,13,15,6,5,1,16,12,1,13,5,7,4,8,6,3,5,8,12,14,12,1,13,5,15,6,13,16,16,9,15,9,2,9,4,7,0, +0,9,13,4,1,5,15,1,2,8,12,11,14,11,5,14,15,12,13,9,4,13,14,16,16,4,6,14,12,14,8,14,4,9,10,3,9,9,7,4,1,7,15,10,5,1,6,7,5,8, +4,6,5,6,1,9,5,11,12,7,10,2,6,8,6,15,4,8,16,4,14,4,14,10,12,12,13,8,10,3,9,12,7,14,3,3,4,4,11,14,4,16,7,16,13,14,14,16,8,0, +0,10,5,13,15,9,3,4,5,7,4,6,16,14,5,14,5,1,6,6,5,12,4,12,5,2,3,8,8,16,14,12,5,10,12,15,14,14,9,4,11,1,11,4,1,2,1,3,8,8, +12,10,16,15,8,7,16,2,6,7,1,3,16,15,10,12,4,11,3,10,10,12,16,4,15,12,8,5,6,9,11,15,9,9,13,11,8,9,11,9,11,10,5,15,15,6,6,8,7,0, +0,14,6,10,12,2,5,7,8,12,8,10,13,1,3,13,15,3,10,8,14,14,11,14,7,14,2,15,5,8,7,10,12,16,13,7,16,6,6,12,16,6,14,12,7,9,1,6,13,3, +1,3,11,16,5,7,8,5,3,10,2,7,9,2,12,9,14,1,4,9,5,16,16,16,10,5,3,15,5,1,9,5,7,13,10,7,13,14,6,10,14,4,9,9,9,9,11,12,13,0, +0,1,1,12,9,9,5,4,12,10,9,14,4,7,10,6,12,2,5,5,3,16,7,8,7,3,14,11,5,16,9,11,12,12,7,4,12,12,8,4,3,7,10,10,4,2,15,3,13,5, +2,13,10,10,11,3,14,5,4,4,4,10,14,13,12,13,5,9,1,16,7,2,1,4,14,1,5,10,3,12,5,15,15,9,8,16,7,11,4,8,15,6,14,16,13,10,6,2,16,0, +0,2,11,13,7,15,6,12,5,7,13,11,10,7,9,4,15,1,7,1,5,12,8,3,14,2,2,16,2,3,15,16,15,1,15,2,6,6,4,8,11,15,7,10,10,12,5,3,1,3, +7,5,3,9,14,3,16,15,13,14,9,8,6,16,10,2,13,9,15,13,8,10,9,12,1,6,10,2,2,4,6,9,10,13,6,9,10,11,2,15,5,12,7,11,15,1,4,13,2,0, +0,12,11,1,12,4,11,16,8,1,14,15,3,4,9,10,5,4,9,5,14,1,16,13,6,4,13,8,16,15,5,1,4,12,6,1,6,13,6,5,16,13,5,5,5,16,10,16,1,1, +5,9,13,16,7,12,12,10,3,3,1,2,14,4,5,10,5,12,7,9,12,13,15,13,11,16,9,10,4,4,9,11,12,1,7,2,16,3,6,7,5,13,10,8,4,9,3,10,14,0, +0,3,7,1,7,8,8,10,10,15,16,11,9,13,8,4,3,15,6,2,2,3,8,1,14,16,14,5,11,12,16,3,8,7,6,10,2,15,2,5,3,15,4,15,16,14,8,11,12,15, +10,9,4,7,7,13,11,8,14,8,13,14,14,4,8,9,1,8,2,5,9,4,11,7,6,3,1,16,16,11,8,10,11,12,1,11,5,16,9,3,6,13,3,11,1,1,16,9,3,0, +0,16,3,10,14,6,9,3,11,11,13,16,1,1,14,5,9,9,13,4,11,5,11,14,15,9,8,8,16,9,7,5,7,7,8,9,15,9,15,9,2,4,16,11,12,13,13,3,8,10, +4,1,6,8,4,14,12,7,11,10,16,12,8,6,7,5,7,14,6,15,2,16,15,7,3,7,153,7,2,13,14,7,6,8,2,14,3,16,8,3,13,11,13,11,6,10,8,6,13,0, +0,16,1,7,3,10,7,4,1,1,6,14,6,12,4,15,2,4,9,1,7,8,4,6,153,153,149,150,2,2,3,16,5,12,10,13,11,8,9,12,15,11,4,4,14,15,4,2,12,1, +8,2,8,11,10,2,11,4,9,3,15,8,11,7,11,2,6,6,8,3,6,8,153,149,165,165,189,150,8,6,3,13,11,15,14,5,4,8,13,7,9,6,7,1,5,16,6,5,2,0, +0,4,1,15,5,8,2,15,1,13,1,6,11,12,15,16,15,6,6,3,4,4,149,165,181,167,167,188,150,14,9,2,9,7,7,6,15,1,11,12,15,13,1,14,3,10,14,10,11,12, +2,15,5,7,6,4,14,12,11,15,3,2,8,10,6,7,10,8,15,15,4,149,179,151,155,155,152,183,150,6,4,16,15,6,12,13,4,13,6,3,6,4,1,13,15,8,4,12,1,0, +0,11,4,9,16,4,1,11,3,9,6,13,12,1,16,10,5,12,10,10,9,149,180,151,11,2,7,152,184,150,14,5,2,1,11,9,16,10,9,1,15,6,13,2,3,13,9,9,13,6, +7,10,7,14,4,2,8,6,9,14,5,3,11,4,8,9,10,4,4,5,149,188,151,13,12,4,15,152,189,150,11,6,11,13,10,10,7,7,6,1,7,5,2,7,1,1,11,3,10,0, +0,3,7,9,16,10,13,13,8,13,11,11,5,16,8,15,14,9,11,8,149,177,151,3,6,1,3,14,152,179,150,8,16,9,8,1,3,10,9,9,7,11,6,15,6,2,10,5,12,10, +2,4,5,12,12,10,2,5,12,12,4,10,2,3,11,10,15,2,4,156,183,166,13,8,16,6,2,8,152,183,150,10,7,13,1,2,15,9,11,6,7,9,14,8,5,8,14,10,11,0, +0,7,4,16,6,2,5,3,5,1,14,14,8,6,4,14,6,8,16,2,168,180,154,16,4,13,3,1,8,168,182,150,15,12,12,7,7,1,12,5,2,6,6,8,5,14,4,16,12,5, +4,2,4,14,8,8,4,6,9,7,8,4,5,15,7,9,11,2,8,156,188,151,7,10,15,12,1,3,156,179,184,150,1,7,9,12,7,4,16,9,7,12,16,8,2,3,6,15,12,0, +0,5,2,7,10,5,1,8,4,4,16,2,12,8,1,6,7,14,14,15,168,151,9,15,12,5,15,3,12,148,184,181,150,6,16,14,16,7,13,5,13,3,6,2,7,3,2,12,7,8, +12,6,14,15,2,6,14,14,10,9,11,13,14,2,3,9,2,10,12,149,151,2,16,5,14,15,2,16,10,148,181,182,150,4,8,14,10,11,1,3,9,1,1,16,10,16,12,7,3,0, +0,10,1,11,15,5,13,6,13,10,14,7,2,4,13,6,12,10,15,149,166,16,4,6,5,7,11,7,16,12,148,189,180,150,3,5,6,4,14,14,7,14,14,6,1,9,15,8,4,14, +5,8,1,1,1,11,8,15,4,11,13,16,12,10,11,12,4,6,156,184,154,6,3,8,4,14,8,14,4,8,148,182,189,150,1,16,13,16,15,1,12,11,11,10,12,5,5,9,10,0, +0,4,10,3,4,3,6,1,15,15,13,12,15,3,3,16,14,13,9,152,166,9,2,6,4,4,2,2,2,12,12,148,180,179,150,3,16,11,1,5,10,1,7,2,8,16,11,9,7,8, +14,4,7,13,13,11,16,2,3,1,8,15,7,6,12,6,14,9,11,168,154,8,14,7,7,16,1,9,12,11,12,148,177,179,158,4,7,13,2,13,7,3,7,4,8,8,6,15,4,0, +0,5,1,11,2,5,11,13,5,9,1,6,7,3,12,9,13,8,9,156,166,4,9,3,2,5,4,9,15,15,3,5,168,178,166,2,6,5,2,16,8,14,14,16,15,11,6,12,4,8, +1,5,14,15,4,13,5,15,3,13,1,10,5,4,11,9,6,5,1,168,154,1,20,15,12,2,11,4,4,15,4,156,189,188,154,13,4,15,13,12,15,16,1,16,11,12,11,4,7,0, +0,3,2,6,12,14,2,11,14,5,8,5,12,14,10,13,9,9,7,149,166,13,9,17,7,11,14,12,8,11,16,8,164,180,166,9,11,1,10,15,16,2,14,14,9,14,7,6,11,8, +11,12,16,9,13,13,9,8,3,1,4,11,1,6,15,3,2,3,156,185,154,4,4,17,5,12,13,12,13,5,4,145,180,179,154,13,16,1,3,16,7,8,13,3,1,7,12,12,11,0, +0,16,16,4,6,4,1,11,11,5,11,14,6,9,4,10,12,1,15,152,166,11,10,4,18,27,2,8,7,14,15,156,189,177,166,2,4,13,8,9,6,14,3,5,1,13,2,7,12,15, +7,11,3,7,1,7,13,1,3,1,9,7,8,14,8,11,7,14,6,168,146,8,9,4,17,32,2,1,11,10,11,164,181,181,154,9,15,15,14,10,9,15,2,10,13,15,13,14,8,0, +0,10,3,10,5,2,1,10,16,10,5,6,1,9,1,13,7,7,5,156,187,150,5,10,30,17,2,1,3,7,15,156,181,178,166,4,1,8,8,5,1,3,13,7,15,14,3,16,14,4, +16,10,14,12,2,6,13,13,7,13,2,16,14,13,12,11,9,4,11,168,189,150,13,16,18,17,15,15,13,12,13,164,182,184,154,8,9,8,12,16,13,13,13,5,11,16,6,2,10,0, +0,9,16,4,5,2,5,3,4,12,5,13,4,13,1,2,8,15,13,156,180,189,150,6,13,17,17,11,12,6,2,156,188,183,166,5,10,13,2,12,2,10,1,12,1,14,6,11,16,7, +4,15,15,8,8,16,15,14,2,14,5,12,11,13,2,7,13,1,10,152,188,186,150,16,2,29,25,1,7,8,2,164,184,187,154,5,13,14,1,10,14,12,8,14,8,10,12,7,10,0, +0,4,7,16,12,3,4,13,15,5,12,15,7,8,15,14,8,15,8,11,168,182,184,150,1,6,2,12,12,10,16,149,178,185,151,1,15,2,1,7,12,13,4,1,15,9,4,12,15,15, +8,8,2,4,5,16,8,7,2,5,16,13,2,7,16,4,11,13,1,156,184,179,189,150,5,16,15,9,5,12,156,179,178,166,1,8,16,9,6,10,1,15,3,2,3,15,15,15,16,0, +0,12,6,11,14,7,9,5,4,16,1,8,3,9,6,6,10,3,12,14,148,178,179,179,194,5,1,14,11,12,8,164,186,179,154,4,13,14,16,16,3,3,5,1,6,4,13,12,8,7, +3,1,11,1,11,12,2,8,12,3,4,1,5,1,12,11,13,8,16,15,148,179,185,206,150,13,1,3,13,8,149,186,189,151,3,13,13,7,10,8,2,7,8,4,3,8,11,6,13,0, +0,15,6,11,8,9,13,12,11,6,9,16,16,10,13,13,3,12,14,10,2,148,184,208,189,150,12,15,8,1,156,178,178,151,1,1,3,3,10,2,13,15,5,6,11,5,12,7,12,15, +16,4,5,14,7,8,13,15,13,6,5,2,4,1,4,8,10,9,2,1,12,148,206,180,180,150,9,2,4,14,164,177,151,1,12,7,9,14,8,5,14,12,7,6,1,16,5,15,4,0, +0,7,15,16,6,2,5,15,1,15,4,12,7,11,10,6,15,8,7,3,6,13,196,180,186,188,150,12,3,3,156,186,151,7,4,6,6,13,12,1,1,16,3,9,16,4,11,1,13,15, +14,5,2,5,9,11,11,13,3,11,12,3,9,16,2,13,9,8,11,1,3,16,152,179,181,186,150,7,8,14,164,151,15,14,5,10,13,6,1,13,14,2,3,3,3,15,10,2,13,0, +0,3,3,10,5,5,6,2,9,13,10,2,3,16,11,6,12,11,15,13,6,5,5,148,178,177,189,150,153,153,149,151,14,5,10,5,10,15,13,7,16,5,7,11,5,16,10,13,7,2, +1,15,7,8,16,14,3,8,2,10,10,4,7,7,7,5,8,2,14,9,3,12,9,148,178,189,180,165,165,161,151,12,15,7,14,1,2,1,7,4,7,4,5,10,4,11,7,15,4,0, +0,16,5,16,2,8,12,4,3,14,1,8,8,8,4,11,14,7,15,2,14,11,10,4,148,183,187,184,185,189,151,8,9,13,1,2,11,13,1,6,2,5,3,8,2,14,8,6,11,15, +6,12,12,5,14,8,16,3,5,9,14,7,15,3,14,2,8,4,2,14,9,5,8,3,148,182,184,178,177,151,4,15,11,8,8,7,14,15,12,7,15,14,2,11,4,14,5,5,15,0, +0,12,6,4,6,16,7,16,13,2,10,11,14,13,11,6,5,9,6,5,13,1,6,8,4,148,179,179,167,151,12,9,16,11,12,14,1,1,8,7,6,13,15,7,16,11,15,6,14,10, +13,14,14,10,3,13,15,6,2,4,9,2,15,12,16,15,12,12,5,10,7,10,5,2,15,148,163,151,159,14,1,2,11,8,4,13,5,7,1,8,7,10,1,9,8,13,9,4,15,0, +0,16,9,16,1,13,16,13,4,4,4,11,11,13,1,14,6,8,10,16,9,7,4,14,12,2,159,155,11,5,11,7,10,1,11,4,12,10,2,14,14,10,12,10,13,15,12,16,13,11, +9,10,13,8,14,7,8,11,12,5,14,16,7,9,10,13,4,12,14,11,13,8,9,8,11,12,16,2,12,7,9,10,15,12,15,4,8,15,11,6,11,9,13,8,15,2,4,6,13,0, +0,14,15,14,2,7,7,12,15,14,15,8,8,5,4,15,15,6,15,10,16,5,13,6,13,12,8,13,4,2,15,15,8,1,11,4,7,15,13,14,6,11,16,7,4,9,5,2,6,10, +9,9,3,14,8,15,1,2,8,1,15,11,15,10,8,2,8,16,10,5,8,13,12,10,7,1,11,14,5,4,9,3,8,4,16,2,14,6,16,12,9,5,16,6,4,1,13,14,15,0, +0,12,7,3,13,12,4,9,15,2,14,9,13,9,12,13,8,10,5,11,10,9,9,6,11,8,8,14,16,3,11,15,10,5,10,16,6,5,9,6,15,6,7,3,10,6,2,5,10,3, +1,10,14,13,15,6,3,12,6,14,6,5,3,3,1,12,12,1,9,4,4,13,11,9,7,10,2,15,10,1,1,7,16,9,7,13,4,1,13,6,11,6,6,2,7,11,15,12,3,0, +0,14,12,8,1,12,3,16,6,15,8,7,4,6,3,14,11,3,9,4,9,6,2,12,14,1,6,7,10,8,13,8,13,11,16,2,10,16,9,8,1,8,1,15,4,10,3,11,6,8, +5,9,1,6,14,16,10,3,3,3,15,8,11,6,15,8,15,10,12,4,7,16,2,11,6,6,15,11,1,10,12,1,10,8,3,8,1,10,13,10,6,9,15,15,6,12,16,12,14,0, +0,9,16,6,4,5,3,12,8,15,16,14,13,16,7,8,16,7,15,12,15,7,2,14,16,9,15,9,12,7,8,11,16,3,6,6,14,3,5,2,13,14,5,12,7,5,13,3,13,9, +15,16,16,9,4,9,13,13,13,2,11,16,8,16,10,15,6,12,12,13,12,16,7,13,1,9,2,6,12,7,8,1,10,12,5,8,8,12,8,9,8,14,3,6,11,13,10,16,7,0, +0,10,9,2,7,2,14,13,7,2,10,7,10,15,16,7,2,2,13,14,5,1,6,4,4,9,6,9,10,14,4,9,6,15,13,4,4,2,8,5,7,5,3,15,8,1,7,15,13,4, +3,9,6,12,10,4,7,5,5,15,8,3,5,3,2,4,12,2,5,13,8,1,9,6,9,16,9,2,9,1,11,7,6,16,7,3,6,14,16,11,4,2,12,9,4,10,9,16,14,0, +0,7,5,8,9,15,1,7,1,16,15,14,1,16,6,10,15,16,9,1,10,15,8,10,3,10,15,6,2,6,8,3,16,9,7,11,15,3,14,6,1,1,12,6,1,14,11,11,9,15, +10,6,11,9,14,1,15,1,10,11,12,6,7,8,2,7,12,6,12,15,6,13,13,3,16,14,4,3,14,7,11,10,15,15,7,11,12,8,5,6,8,14,14,4,2,8,7,10,4,0, +0,13,9,8,1,6,14,14,6,14,8,2,9,1,13,6,16,11,2,16,16,8,13,3,16,5,7,5,7,16,6,11,14,6,2,11,13,5,4,12,12,13,5,6,4,13,14,15,15,5, +15,2,5,13,6,6,14,16,6,10,4,5,2,16,11,3,15,9,5,4,13,2,2,13,12,11,1,3,10,13,16,8,4,5,11,15,5,11,12,8,7,6,12,1,3,12,4,8,14,0, +0,11,13,12,6,14,8,7,7,5,9,4,16,13,8,12,12,11,4,12,12,4,15,5,3,5,16,13,11,14,2,15,2,4,5,10,10,16,15,2,10,16,6,14,12,6,9,11,16,9, +6,9,9,15,12,6,14,4,1,13,13,2,4,6,14,2,5,15,12,2,8,5,2,1,4,8,1,16,1,13,9,6,10,8,16,7,12,2,12,15,7,5,7,8,15,15,12,2,8,0, +0,10,6,2,13,6,12,4,13,4,6,16,7,15,1,12,14,5,1,3,10,2,3,12,12,6,15,5,16,12,3,5,8,8,5,10,15,4,6,13,10,4,12,13,4,6,10,4,2,13, +6,13,8,9,3,10,2,2,7,11,11,4,15,10,1,5,11,10,8,1,4,2,13,11,8,15,1,12,13,7,12,5,13,6,14,12,12,12,11,14,2,1,16,14,13,6,14,7,4,0, +0,10,16,15,6,2,2,16,5,5,10,1,14,8,15,5,1,11,8,9,8,10,7,10,12,16,9,14,3,2,11,9,12,2,3,13,6,16,5,5,11,5,2,13,2,11,6,10,14,6, +8,2,2,3,9,11,10,16,6,7,15,14,12,1,10,11,16,10,15,14,5,15,13,12,4,10,11,16,4,13,12,3,6,4,16,7,4,7,12,9,3,8,5,16,4,4,8,13,1,0, +0,13,4,1,1,14,15,1,8,11,13,10,3,1,7,6,1,9,5,16,4,15,2,5,15,16,7,16,4,7,14,14,4,3,4,12,5,15,3,9,9,10,8,2,5,3,16,6,14,9, +15,6,10,12,15,16,2,1,13,5,3,10,14,11,6,12,1,4,4,8,7,2,4,16,14,6,13,2,3,13,1,12,2,5,4,11,5,9,7,10,3,3,9,1,4,12,9,8,13,0, +0,11,15,15,2,1,14,16,2,7,3,9,12,5,3,5,2,5,6,15,7,6,13,11,3,13,10,14,5,1,5,2,14,16,9,7,5,11,7,16,3,8,4,7,8,1,10,6,9,6, +5,14,9,5,11,4,2,3,13,10,2,1,15,16,14,8,6,11,12,5,8,15,3,9,15,4,16,3,7,7,15,8,15,4,16,15,9,10,6,1,7,13,5,9,1,1,6,5,14,0, +0,7,14,12,4,10,1,5,12,7,5,10,2,16,6,1,13,1,5,10,10,10,13,9,1,7,1,16,16,12,14,5,1,4,6,9,3,5,6,5,15,11,5,9,7,11,15,1,4,5, +15,1,11,4,10,9,9,4,7,3,16,10,3,14,5,10,15,16,6,12,6,5,8,16,4,16,4,11,2,10,12,11,10,4,8,3,15,3,4,12,11,5,7,6,13,12,10,8,12,0, +0,3,2,1,8,3,6,9,12,6,5,9,8,4,13,12,10,14,10,12,12,4,5,13,3,1,1,2,4,12,1,9,12,12,16,12,9,15,11,2,2,5,6,16,12,6,6,5,8,9, +3,13,11,1,5,7,10,1,16,9,3,9,5,6,13,8,16,9,9,8,7,10,3,13,12,10,1,7,10,7,4,14,7,5,7,7,4,7,15,16,11,7,14,1,3,13,14,15,11,0, +0,13,16,6,12,4,7,13,2,6,3,1,16,16,5,8,4,1,11,8,16,6,8,9,5,15,12,1,4,12,9,9,14,12,2,9,8,1,8,10,3,11,15,4,3,12,12,3,12,6, +13,15,5,16,14,7,12,8,3,8,9,11,3,13,16,12,2,1,5,12,1,11,10,9,2,2,14,2,5,11,2,3,7,10,1,7,6,16,8,8,11,16,1,13,1,7,5,13,16,0, +0,13,9,11,7,3,2,6,14,4,9,8,8,1,2,13,11,1,9,6,4,16,11,9,3,13,13,1,15,14,5,12,1,11,15,13,8,1,13,13,6,4,4,7,2,9,13,12,10,11, +3,16,2,9,14,5,9,15,8,13,12,10,12,3,14,9,5,7,4,13,2,9,7,6,4,14,1,12,1,13,16,4,12,13,2,11,1,12,11,12,9,6,14,6,3,12,2,11,15,0, +0,10,9,15,10,14,9,12,1,15,8,11,3,10,3,8,15,9,12,7,11,10,15,2,8,5,16,16,16,11,12,12,1,5,9,12,7,6,4,15,4,6,3,9,1,10,6,11,2,11, +5,8,7,16,12,6,8,10,2,6,13,13,7,15,10,10,2,15,9,13,16,11,10,6,4,16,4,10,11,15,6,8,3,16,2,3,5,2,4,5,15,12,13,16,4,8,4,10,16,0, +0,15,2,10,4,4,1,14,3,16,8,4,11,15,15,9,10,9,12,2,12,4,1,2,11,2,14,10,11,15,12,7,13,7,5,16,16,1,11,11,13,1,1,10,13,6,2,11,2,13, +3,15,5,13,7,6,12,8,8,11,4,5,16,12,5,8,6,4,3,1,10,8,10,10,6,7,3,8,15,11,16,10,6,8,14,9,3,12,3,9,13,2,3,9,1,13,9,1,10,0, +0,12,14,16,16,9,9,8,3,11,13,8,13,5,5,5,1,14,12,6,2,11,15,15,5,2,10,8,14,10,9,8,3,10,11,5,8,9,12,8,4,1,12,10,14,10,9,3,13,13, +15,12,13,5,4,6,2,1,13,16,6,10,7,2,11,7,12,14,5,11,6,9,3,8,11,2,5,14,3,11,7,12,2,1,6,16,11,2,12,6,15,7,2,9,16,12,16,1,11,0, +0,2,12,2,4,2,10,11,8,6,11,1,12,16,10,11,4,7,5,1,9,7,13,1,7,15,12,14,16,5,12,15,9,2,13,14,15,3,5,12,14,11,13,14,12,15,2,12,16,12, +6,5,6,3,6,10,10,3,13,1,4,15,15,7,11,12,5,8,9,2,8,8,8,11,6,9,8,4,15,2,8,13,3,10,13,7,8,14,11,7,4,10,11,2,2,15,8,4,12,0, +0,6,9,10,6,15,8,6,10,14,16,14,11,2,3,3,4,3,7,4,11,4,15,5,12,12,3,4,14,13,5,6,15,3,16,10,4,15,7,8,14,13,5,15,4,1,14,6,7,7, +13,3,14,5,11,16,9,5,13,8,16,13,13,16,7,3,9,3,9,7,8,3,7,12,6,8,9,15,7,16,13,1,3,1,8,11,11,6,6,11,5,1,6,6,14,11,3,10,9,0, +0,1,7,9,1,11,13,8,15,13,4,14,11,14,1,10,11,1,11,3,16,5,15,16,10,6,12,1,4,11,11,6,5,10,2,10,1,3,3,3,9,5,12,7,9,9,9,5,12,7, +5,11,8,1,14,16,9,5,16,10,14,9,6,10,4,10,1,11,4,4,1,4,16,8,12,6,6,5,6,12,15,5,13,13,12,9,7,7,11,16,8,7,3,1,11,2,6,16,8,0, +0,11,8,15,15,2,14,4,12,16,15,1,8,5,7,14,12,2,15,3,5,8,2,9,13,7,12,9,15,3,9,15,8,12,5,4,6,7,13,4,4,6,16,10,1,13,10,2,11,1, +5,3,11,8,6,12,6,6,12,16,13,10,16,6,6,1,7,15,6,4,4,14,15,12,9,1,4,1,8,7,4,8,15,14,13,4,13,1,14,10,14,9,16,10,12,15,15,3,1,0, +0,16,3,5,10,12,16,9,16,10,10,2,16,2,2,2,16,15,14,15,7,16,11,1,4,10,6,8,6,6,4,7,6,16,14,4,12,11,16,13,9,13,12,2,16,1,7,8,9,6, +13,16,16,4,8,1,11,6,6,3,15,11,11,5,10,2,15,10,13,1,12,7,10,12,14,2,9,12,6,5,16,12,3,13,11,10,10,7,8,5,3,6,5,16,5,14,6,16,12,0, +0,8,14,11,8,12,15,14,13,2,13,1,4,16,16,4,11,3,10,3,6,1,5,14,5,8,4,2,14,15,2,16,16,6,2,4,4,4,16,3,9,10,1,9,8,1,2,12,3,10, +9,12,4,3,14,16,2,5,1,14,9,3,6,10,2,12,9,2,12,9,14,6,13,6,13,16,1,7,6,14,11,8,15,8,5,8,5,8,14,16,10,1,13,12,9,14,15,3,1,0, +0,3,13,14,11,4,2,5,1,3,2,8,8,6,6,10,13,12,4,8,14,4,13,15,4,8,2,8,2,13,14,5,12,6,8,9,15,4,5,2,6,16,7,8,8,5,9,3,8,7, +15,4,5,16,15,6,4,8,1,7,6,3,14,14,16,14,13,12,6,14,12,14,3,5,5,9,16,15,12,15,13,3,1,11,7,16,13,3,4,2,3,8,6,16,2,5,8,8,3,0, +0,11,3,9,5,15,16,11,11,5,8,4,14,11,7,2,3,1,10,7,16,7,16,1,10,12,8,2,10,4,16,10,6,13,9,13,6,12,1,11,2,2,11,8,4,2,6,7,5,15, +6,12,9,11,13,4,11,16,8,16,4,3,13,7,16,10,14,14,11,10,16,10,14,5,2,13,2,15,3,8,12,6,3,10,3,10,13,2,10,8,12,13,3,13,10,4,14,1,14,0, +0,4,4,12,4,12,8,12,16,2,9,14,4,3,5,3,8,4,15,16,9,12,13,16,7,7,12,2,10,7,12,8,10,1,16,11,8,14,2,6,5,13,16,9,10,2,11,11,4,3, +12,12,6,11,13,13,3,6,4,13,4,12,8,3,2,12,6,10,10,11,10,13,10,14,6,12,5,12,11,7,13,1,15,3,10,9,10,6,3,4,5,9,6,4,14,6,16,13,3,0, +0,3,6,9,12,12,7,1,9,5,14,10,13,13,16,5,11,10,12,14,14,10,9,8,8,7,7,14,7,15,14,5,14,12,14,10,10,14,2,2,16,14,10,11,16,16,1,11,14,13, +10,4,16,16,4,6,3,9,15,13,10,16,1,3,6,4,8,8,16,7,7,4,5,4,6,2,11,12,8,7,13,5,2,14,13,13,1,8,3,8,10,11,15,1,6,5,6,10,6,0, +0,2,2,14,4,11,15,6,9,1,8,16,16,13,11,9,5,1,4,10,4,11,13,8,3,10,10,7,5,3,12,4,10,14,3,11,15,10,8,4,13,7,2,2,8,14,6,7,3,7, +6,8,5,16,8,16,14,4,14,7,4,4,8,11,13,14,2,8,7,10,15,3,14,12,15,14,5,1,12,1,13,16,12,4,14,12,12,4,14,3,6,13,11,10,15,3,14,5,4,0, +0,8,16,7,13,7,5,9,14,4,10,13,12,2,4,16,11,3,8,12,16,11,11,12,16,13,2,12,3,14,4,9,13,1,7,14,6,11,3,11,6,4,16,12,5,16,6,16,11,6, +15,6,12,7,5,16,7,1,1,11,9,7,11,5,11,15,10,10,2,10,1,3,3,12,6,12,15,4,9,10,9,1,12,5,15,2,13,1,2,1,11,1,12,9,16,7,10,4,9,0, +0,8,2,2,3,15,9,1,2,13,11,7,12,13,5,12,3,14,11,7,9,5,4,7,10,11,11,15,3,11,1,6,6,7,10,9,10,7,15,7,10,3,14,5,7,12,9,12,5,4, +6,11,3,15,10,8,6,12,13,4,1,14,1,16,13,10,7,3,6,5,6,5,11,10,5,16,13,4,14,16,16,2,15,6,9,3,6,3,1,12,5,11,4,1,1,6,14,12,16,0, +0,9,1,3,6,12,12,3,4,12,8,13,11,4,13,6,7,7,9,16,13,1,6,3,8,7,4,15,14,7,12,15,12,6,16,3,9,2,12,7,2,1,16,13,15,4,9,1,16,1, +6,13,8,1,7,7,6,3,3,6,10,16,5,14,2,4,15,8,1,6,7,2,4,14,12,4,12,14,3,8,1,15,8,3,1,14,12,14,2,16,8,9,16,16,11,10,12,15,9,0, +0,13,9,7,15,1,3,4,15,1,4,1,6,10,5,11,5,5,12,7,9,7,13,11,10,3,7,5,13,7,4,4,6,14,14,16,1,15,9,16,11,16,6,5,11,16,4,14,4,13, +9,12,6,1,12,6,9,8,2,1,3,12,4,11,10,1,8,13,16,4,10,10,1,14,5,16,2,1,13,7,6,12,15,3,7,6,3,15,11,2,14,5,3,13,13,6,9,14,7,0, +0,4,6,3,14,13,9,10,1,3,8,12,16,15,3,3,2,10,11,8,1,15,14,6,5,8,15,8,7,1,15,10,15,5,15,7,10,1,1,12,1,1,10,6,15,3,11,2,15,5, +4,9,16,9,15,3,7,5,14,10,6,12,2,6,4,5,6,12,4,6,6,4,11,4,13,16,8,1,4,2,12,16,1,12,6,16,10,13,3,16,3,3,13,13,16,9,15,3,16,0, +0,16,12,16,15,14,7,11,4,2,12,2,4,6,13,3,11,11,1,16,11,5,4,16,8,12,5,12,13,14,8,6,8,12,7,16,12,12,14,4,1,8,15,13,3,1,1,13,3,10, +11,8,1,12,16,2,9,14,9,10,8,5,16,4,10,11,4,5,16,15,7,4,12,1,12,10,2,6,9,5,10,3,6,4,14,15,14,9,9,7,14,6,10,7,8,4,3,16,12,0, +0,7,6,13,11,9,10,13,14,15,10,3,6,4,4,16,14,14,12,13,5,10,16,12,5,14,5,7,1,7,9,16,3,13,5,2,15,15,7,1,16,5,6,9,10,16,5,15,10,7, +13,2,12,3,6,10,4,13,2,8,3,14,3,11,8,8,4,9,8,3,5,13,15,16,13,11,15,4,10,12,16,12,15,14,3,10,7,9,12,7,4,8,8,4,11,15,10,7,13,0, +0,10,16,8,7,11,9,5,5,8,5,16,12,10,12,4,2,3,1,12,10,3,6,14,3,6,9,11,8,4,2,3,2,4,8,2,4,6,15,14,1,9,4,14,6,8,6,16,13,0, +0,9,10,2,12,13,4,7,9,13,12,16,11,7,1,13,6,6,8,3,5,16,4,6,16,2,16,2,6,8,3,14,5,6,13,12,1,10,11,8,13,14,3,8,3,5,4,14,0,0, +0,0,3,7,1,5,15,2,15,11,6,7,6,13,7,2,4,16,1,2,9,10,4,2,4,16,15,2,6,9,2,1,15,11,16,12,16,15,9,4,12,11,15,9,4,8,5,12,0,0, +0,0,10,9,1,14,10,3,5,2,10,16,12,11,5,13,15,15,1,9,4,3,4,13,16,9,1,3,6,1,11,4,8,12,4,7,6,6,10,15,15,13,12,2,16,11,6,0,0,0, +0,0,0,2,9,7,5,12,5,9,15,12,12,8,5,11,11,9,4,7,2,3,16,2,8,4,1,3,6,12,2,6,11,1,6,12,10,15,2,8,11,3,14,3,10,16,11,0,0,0, +0,0,0,15,14,1,7,10,1,15,10,12,16,5,3,12,8,13,10,5,11,1,8,2,11,14,10,3,13,6,14,9,11,11,6,9,14,1,6,7,3,2,4,15,11,6,0,0,0,0 + + + + +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64, +0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64, +0,0,0,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,64,64,64, +0,0,0,37,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,49,38,64,64, +0,0,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,38,64,64, +0,0,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,38,64, +0,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,38,64, +0,37,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,0,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,0,0,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,0,0,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,0,0,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,0,0,0,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,0,0,0,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,0,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,0,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,0,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,133,0,94,0,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,93,91,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,92,0,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,90,0,104,92,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,89,0,0,0,92,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,125,0,98,92,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,109,0,0,0,92,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,92,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,125,0,0,0,134,92,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,109,0,0,125,0,0,92,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,109,125,98,0,0,99,92,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,125,0,99,92,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,125,101,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,103,0,101,125,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,125,0,0,0,0,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,50,64, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,127,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,135,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,50,0, +0,52,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,42, +44,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,0, +0,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,0, +0,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,0,0, +0,0,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,0,0, +0,0,40,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,39,0,0,0, +0,0,0,40,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,55,39,0,0,0, +0,0,0,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,43,0,0,0,0 + + + + + + diff --git a/V3/Content/Maps/work_in_progress.tmx b/V3/Content/Maps/work_in_progress.tmx new file mode 100644 index 0000000..d521185 --- /dev/null +++ b/V3/Content/Maps/work_in_progress.tmx @@ -0,0 +1,1258 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + +177,177,177,189,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,76,76,0,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,63,63,63,63,63,1,1,1,1,1,1,1,76,76,76,76,76,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,76,76,76,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,63,63,63,63,63,1,1,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,76,76,76,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,63,63,63,63,1,1,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +177,177,177,177,177,177,177,177,177,177,177,177,177,151,152,177,177,177,177,177,177,76,0,1,1,1,1,1,1,1,1,0,76,76,76,76,76,76,76,76,76,76,76,76,76,76,1,63,63,63,63,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +177,177,177,177,177,177,177,177,177,177,177,177,147,155,4,152,177,177,177,177,177,76,76,0,1,1,1,1,1,1,1,76,0,0,76,76,76,76,76,76,76,76,76,76,76,76,1,1,63,63,63,0,1,1,1,1,1,1,1,1,1,76,76,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +177,177,177,177,177,177,177,177,177,177,177,147,4,4,4,152,177,177,177,177,177,76,0,1,1,1,1,1,1,1,1,76,0,76,76,0,76,76,76,76,76,76,76,76,76,1,1,1,63,63,63,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +177,177,177,177,177,177,177,177,177,177,177,147,4,4,4,4,168,177,177,177,177,76,76,76,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,1,1,1,1,63,63,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,0,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +177,177,177,177,177,177,177,177,177,177,151,4,4,4,4,149,177,177,177,177,177,76,76,76,76,1,1,1,1,1,1,1,76,1,1,76,76,76,76,76,76,76,76,76,1,1,1,1,1,63,63,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,0,0,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +177,177,177,177,177,177,177,177,177,177,166,4,4,4,4,156,177,177,177,155,148,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,1,1,1,1,1,1,63,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,0,0,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +177,177,177,177,177,177,177,177,177,177,154,4,4,4,4,164,177,177,154,1,148,76,76,76,1,1,1,1,1,1,1,1,1,1,1,0,76,76,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1,248,260,254,253,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,0,0,0,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +177,177,177,177,177,177,177,177,177,177,166,4,4,4,4,145,177,177,162,1,1,155,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,0,1,1,1,1,1,1,1,1,1,266,263,1,266,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,0,0,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +177,177,177,177,177,177,167,177,177,177,146,4,4,4,149,177,177,177,154,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,21,1,1,1,1,1,1,1,1,1,1,1,1,76,1,1,0,0,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +177,177,177,177,177,167,151,164,177,177,177,150,4,4,145,177,177,155,155,1,153,1,1,1,1,1,1,1,255,1,1,1,1,1,1,1,76,76,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,21,21,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +177,177,177,177,147,159,160,177,177,177,177,150,153,149,177,177,154,1,1,149,154,1,1,1,1,1,1,1,255,1,1,1,1,1,1,76,76,76,76,76,76,76,76,1,1,1,1,248,260,254,253,1,1,1,1,1,1,1,21,21,21,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,0,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +177,177,177,177,147,1,1,148,177,177,177,177,165,165,177,177,162,1,1,145,166,1,1,1,1,1,1,1,250,1,1,1,1,1,1,1,76,0,76,76,76,76,76,1,1,1,1,248,260,2,253,1,1,1,1,1,1,1,21,21,21,21,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +177,177,177,147,1,1,1,155,177,177,177,177,177,177,177,177,154,1,149,177,154,1,1,1,1,1,1,1,238,255,1,1,1,1,1,1,76,76,76,76,76,76,1,1,1,1,1,2,2,1,266,1,1,1,1,1,1,21,21,1,21,21,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +177,177,177,147,1,1,1,1,156,0,177,177,177,177,177,177,155,1,145,177,166,157,1,1,1,1,1,1,242,1,1,254,253,1,1,1,1,76,76,76,76,76,1,1,1,1,1,2,2,1,1,1,1,1,1,1,1,21,21,21,1,21,21,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +177,177,147,1,1,1,1,1,159,155,152,177,177,177,177,158,1,156,177,177,161,154,1,1,1,1,1,1,246,1,256,1,266,1,1,1,1,76,1,1,1,1,1,1,1,1,2,1,1,1,1,1,1,1,1,1,21,21,21,21,1,21,21,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +177,177,147,1,1,1,1,1,1,1,1,152,177,177,177,162,1,1,152,177,177,166,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,2,1,1,1,1,1,1,1,1,21,21,1,21,21,1,21,21,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +177,147,1,1,1,1,1,1,1,1,1,168,177,177,177,154,1,1,152,177,177,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,0,1,1,1,248,260,2,253,1,1,1,1,1,1,1,21,21,1,1,21,21,1,21,21,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +177,162,1,1,1,1,1,1,1,1,1,156,177,177,177,162,1,1,1,152,177,151,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,63,1,1,266,263,1,266,1,1,1,1,1,1,1,21,21,1,1,1,21,21,1,21,21,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +177,154,1,1,1,1,1,1,1,1,1,168,177,177,177,154,1,153,1,155,155,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,1,1,1,21,1,1,1,1,1,1,1,1,1,21,21,1,1,1,1,21,21,1,21,21,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +177,151,1,1,241,242,243,1,1,1,1,149,177,177,177,162,1,156,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,1,1,21,21,1,1,1,1,1,1,1,1,21,21,21,1,1,1,1,21,21,1,21,21,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +151,1,1,1,245,266,247,1,1,1,149,177,177,177,177,154,1,168,146,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,64,1,21,1,1,1,1,1,1,1,1,21,21,21,21,1,1,1,1,21,21,1,21,21,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +166,153,1,1,249,267,1,1,1,1,149,177,177,177,177,151,1,156,167,146,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,63,1,1,21,1,1,1,1,1,1,1,21,21,1,21,21,1,1,1,1,21,21,1,21,21,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +165,150,1,1,237,238,1,1,1,1,152,177,177,177,162,1,1,159,168,154,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,1,1,21,1,1,1,1,1,1,21,21,21,1,21,21,1,1,1,1,21,21,1,21,21,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +183,183,150,1,241,255,1,242,243,1,1,168,177,177,177,146,1,1,156,151,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,1,1,1,21,1,1,1,1,1,21,21,21,21,1,21,21,1,1,1,1,21,21,1,21,21,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +183,162,1,1,245,255,1,266,247,1,149,177,177,177,177,150,1,1,159,1,1,153,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,1,1,1,21,1,1,1,1,21,21,1,21,21,1,21,21,1,1,1,1,21,21,1,21,21,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,177,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +183,183,154,1,249,250,1,267,1,1,1,177,177,177,177,192,150,1,1,1,1,149,146,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,21,1,1,1,21,21,1,1,21,21,1,21,21,1,1,1,1,21,21,1,21,21,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,177,177,76,76,76,76,76,76,76,76,76,76,76,76,76,76, +183,162,1,1,237,238,255,238,1,1,145,177,177,177,192,177,150,1,1,1,149,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,1,1,1,1,21,1,1,21,21,1,1,1,21,21,1,21,21,1,1,1,1,21,21,1,21,21,1,1,1,1,1,1,1,1,1,1,76,76,76,76,177,177,177,1,1,1,1,1,76,76,76,76,76,76,76,1,1,76, +183,183,154,1,241,242,1,255,1,1,149,177,177,177,177,177,177,154,1,1,156,177,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,21,1,21,21,1,1,1,1,21,21,1,21,21,1,1,1,1,21,21,1,21,21,1,1,1,1,1,1,1,1,1,1,1,1,1,177,177,177,177,1,1,1,1,76,76,1,1,76,76,76,1,1,1, +183,147,1,1,1,1,245,255,1,1,148,177,177,177,177,177,166,1,1,1,168,177,177,154,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,1,1,1,1,1,21,21,21,21,1,1,1,1,21,21,1,21,21,1,1,1,1,21,21,1,21,21,1,1,1,1,1,1,1,1,1,1,1,1,1,177,177,177,154,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +183,147,1,1,1,1,249,250,1,1,1,148,177,177,177,177,177,150,1,1,1,177,177,151,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,21,21,21,21,1,1,1,1,21,21,1,21,21,1,1,1,1,21,21,1,21,21,1,1,1,1,1,1,1,1,1,1,1,1,177,177,177,151,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +162,1,1,1,1,1,237,238,255,1,1,164,177,151,155,177,177,150,1,1,152,177,151,1,1,1,1,1,1,1,255,1,1,1,1,1,1,1,1,1,1,76,76,1,1,1,1,1,1,21,1,21,21,1,1,1,1,21,21,1,21,21,1,1,1,1,21,21,1,21,21,1,1,1,1,1,1,1,1,1,1,1,1,164,177,151,1,4,4,4,1,4,1,4,4,4,4,1,1,4,1, +177,150,1,1,1,1,241,242,1,1,1,149,177,151,1,160,177,192,8,1,1,152,151,1,1,1,1,1,1,1,255,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,21,21,1,21,21,1,1,1,1,21,21,1,21,21,1,1,1,1,21,21,21,21,1,1,1,1,1,1,1,1,1,1,1,1,145,177,151,1,4,4,4,4,4,4,4,4,4,4,4,4,1,1, +177,150,157,1,1,1,1,1,1,1,145,177,166,1,1,148,177,151,1,1,1,159,1,1,1,1,1,1,1,1,250,1,1,1,1,1,1,1,1,1,1,76,76,1,1,1,1,1,1,21,21,1,21,21,1,1,1,1,21,21,1,21,21,1,1,1,1,21,21,21,1,1,1,1,1,1,1,1,1,1,1,1,145,177,151,4,1,4,4,4,4,4,4,4,4,4,4,4,4,1,1, +177,177,165,158,1,1,1,1,1,1,145,177,177,146,1,1,152,162,1,1,1,1,1,1,1,1,1,1,1,1,238,255,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,21,21,1,21,21,1,1,1,1,21,21,1,21,21,1,1,1,1,21,21,1,1,1,1,1,1,1,1,1,1,1,1,149,177,166,4,1,4,4,4,4,4,4,4,4,4,4,4,4,4,1, +177,177,147,1,1,1,1,1,1,149,177,177,147,1,1,1,152,146,1,1,1,1,1,1,1,1,1,1,1,1,242,1,1,1,1,1,1,1,1,1,1,76,76,1,1,1,1,1,1,1,21,21,1,21,21,1,1,1,1,21,21,1,21,21,1,1,1,21,21,1,1,1,1,1,1,1,1,1,1,1,1,149,177,177,154,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,1, +177,177,162,1,1,1,1,1,1,149,177,177,162,1,1,1,157,168,146,1,1,1,1,1,1,1,1,1,1,1,246,1,256,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,21,21,1,21,21,1,1,1,1,21,21,1,21,21,1,1,21,21,1,1,1,1,1,1,1,1,1,1,1,1,156,177,177,166,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,1, +177,177,154,1,1,1,157,1,1,177,177,177,146,1,1,160,165,177,154,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,63,76,76,76,1,1,1,1,1,1,1,21,21,1,21,21,1,1,1,1,21,21,1,21,21,1,21,21,1,1,1,1,1,1,1,1,1,1,1,1,1,148,177,177,154,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +177,177,162,153,1,1,149,146,1,149,177,177,177,1,1,1,148,177,166,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,21,21,1,21,21,1,1,1,1,21,21,1,21,21,21,21,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,177,151,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +177,177,165,1,1,145,192,146,193,177,177,177,147,1,1,1,159,177,154,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,1,1,1,21,21,1,21,21,1,1,1,1,21,21,1,21,21,21,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,151,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +177,177,177,146,1,149,192,192,161,197,177,177,162,1,1,1,1,160,166,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,21,21,1,21,21,1,1,1,1,21,21,1,21,21,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,166,1,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +177,177,177,146,145,177,177,177,177,201,177,177,158,1,1,1,1,164,154,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,1,1,1,1,21,21,1,21,21,1,1,1,1,21,21,21,21,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,149,177,154,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +177,177,177,177,165,177,177,177,177,177,201,177,147,1,1,1,1,145,166,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,21,21,1,21,21,1,1,1,1,21,21,21,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,149,177,166,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +177,177,177,177,177,177,177,177,177,177,205,147,1,1,1,1,156,177,154,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,1,1,1,1,1,21,21,1,21,21,1,1,1,1,21,21,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,149,177,177,154,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +177,177,177,177,177,177,177,177,177,177,177,195,1,1,1,1,1,168,166,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,1,21,21,1,21,21,1,1,1,21,21,1,1,1,248,260,254,253,1,1,1,1,1,1,1,1,1,177,177,166,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +177,177,177,177,177,177,177,177,177,177,147,1,1,1,1,1,160,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,21,21,1,21,21,1,1,21,21,1,1,1,1,266,263,1,266,1,1,1,1,1,1,1,1,156,177,177,154,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +177,177,177,177,177,177,177,177,177,177,162,1,1,1,1,1,1,152,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,21,21,1,21,21,1,21,21,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,177,166,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +177,177,177,177,177,177,177,177,177,177,146,1,251,248,249,250,1,164,177,158,1,1,8,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,21,21,1,21,21,21,21,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,177,177,154,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +177,177,177,177,177,177,177,177,177,177,177,146,260,254,253,261,1,160,177,147,1,8,157,153,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,21,21,1,21,21,21,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,166,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +177,177,177,177,177,177,177,177,177,155,177,154,263,253,266,242,1,148,162,153,153,149,165,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,21,21,1,21,21,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,177,154,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +177,177,177,177,177,159,159,159,177,154,160,147,1,1,1,1,1,1,148,161,165,165,177,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,21,21,21,21,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,166,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +176,177,177,177,158,1,1,160,151,1,159,1,1,1,1,1,1,1,164,177,177,177,177,177,146,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,1,1,248,260,254,253,1,1,1,21,21,21,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,177,154,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +176,176,177,177,167,1,1,1,159,1,1,1,1,1,1,1,1,1,156,177,177,167,177,177,177,154,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,1,1,266,263,1,266,1,1,1,1,21,21,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,166,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +64,176,177,151,1,1,1,1,1,1,1,1,1,1,1,1,1,1,164,177,151,152,167,177,166,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,21,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,177,154,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +0,176,176,151,1,1,1,1,1,1,1,1,1,1,1,1,1,1,160,177,151,1,159,152,177,154,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,149,177,166,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +1,176,159,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,164,166,1,1,1,152,166,1,157,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,177,154,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +0,176,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,154,1,1,1,168,154,145,146,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,177,166,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,148,166,1,1,1,156,166,149,177,146,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,177,154,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +0,1,1,1,1,1,241,242,243,240,1,1,1,1,1,1,1,1,1,168,154,1,1,1,168,165,177,177,154,1,248,260,254,253,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,177,166,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +1,1,1,1,1,1,245,266,247,244,251,248,249,250,1,1,1,1,160,162,153,1,1,145,177,177,177,151,1,1,266,263,1,266,1,1,1,1,1,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,177,177,154,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +0,1,1,1,1,1,249,267,1,248,260,254,253,261,1,1,1,1,1,168,161,146,1,149,177,177,177,162,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,166,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +1,1,1,1,1,1,237,238,1,266,263,1,266,242,1,1,1,1,156,177,177,146,145,177,177,177,177,146,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,177,154,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +76,1,1,1,1,1,241,255,1,1,1,1,1,1,1,1,1,1,1,168,163,177,165,177,177,177,177,177,150,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,166,4,4,32,28,24,4,4,4,4,4,4,1,4,4,4,4,4, +76,1,1,1,1,1,245,255,1,1,1,1,1,1,1,1,1,1,160,151,155,177,177,177,163,163,177,177,194,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,177,146,4,4,4,23,4,4,4,4,4,4,4,4,4,4,4,4,4, +76,0,1,1,1,1,249,250,1,1,1,1,1,1,1,1,1,1,1,159,1,156,177,177,155,155,148,177,198,146,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,177,146,4,23,24,32,4,4,4,4,4,4,4,4,4,4,4,4, +76,1,1,1,1,1,237,238,255,1,1,1,1,1,1,1,1,1,1,1,1,152,163,150,1,1,152,200,177,150,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,177,177,150,4,4,4,32,4,4,4,4,4,4,4,4,4,4,4,4, +76,76,1,1,1,1,241,242,1,1,1,1,1,1,1,1,1,1,1,1,1,1,155,152,150,1,1,196,177,177,150,1,1,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,177,177,194,23,32,28,4,4,4,4,4,4,4,4,4,4,4,4, +76,76,1,1,1,1,245,246,1,256,242,243,240,241,242,243,240,241,1,243,240,241,242,159,240,241,242,148,177,177,150,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,177,177,200,194,4,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +76,76,76,1,1,1,1,1,1,1,246,247,244,245,246,247,244,261,1,247,244,245,246,247,244,245,246,247,152,177,177,150,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,177,202,200,194,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +76,76,76,1,1,1,250,251,248,249,250,251,248,249,250,251,248,1,1,1,248,249,250,251,248,249,250,251,148,177,177,150,1,1,1,1,1,1,1,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,63,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,148,202,202,200,146,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +76,76,76,76,1,1,238,239,236,237,238,239,236,237,238,239,236,1,1,1,1,1,1,1,255,1,1,239,1,148,177,177,150,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,200,202,202,178,158,4,4,4,4,4,4,4,4,4,4,4,4,4, +76,76,76,76,1,1,242,243,240,241,242,243,240,241,242,243,240,1,1,1,1,1,1,243,255,1,1,243,1,148,177,177,150,1,1,1,1,1,1,1,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,196,200,202,178,147,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +76,76,76,76,76,1,246,247,244,245,266,247,244,245,246,247,244,1,1,1,1,1,1,1,250,1,1,1,1,1,148,177,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,196,200,177,162,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +76,76,76,76,1,1,250,251,248,249,267,1,248,267,250,251,248,1,1,1,1,1,1,1,238,255,1,1,1,1,148,177,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,196,177,177,146,4,4,4,4,4,4,4,4,4,4,4,4,4,4, +76,76,76,76,1,1,238,239,236,237,238,1,266,237,238,239,236,237,262,239,236,1,1,1,242,1,1,1,1,1,1,152,177,177,146,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,177,177,146,4,4,4,4,4,4,4,4,4,4,4,4,4, +76,76,76,1,1,1,242,243,240,241,255,1,1,241,242,243,240,241,242,1,1,1,1,243,246,1,256,1,1,1,1,152,177,177,154,1,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,177,177,146,4,4,4,4,4,4,4,4,4,4,4,4,4, +76,76,76,1,1,1,267,247,244,245,255,1,1,245,246,247,244,263,1,247,244,1,1,1,244,245,246,1,1,1,1,1,168,177,166,1,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,177,177,177,150,4,4,4,4,4,4,4,4,4,4,4,4, +76,76,1,1,1,1,250,251,248,249,250,1,1,249,250,251,248,1,1,1,1,1,1,248,260,254,253,251,1,1,1,156,177,177,154,1,250,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,248,260,254,253,1,1,1,1,1,1,1,1,1,1,1,152,177,177,177,146,4,4,4,4,4,4,4,4,4,4,4,4, +76,76,0,1,1,1,238,239,236,237,238,255,1,1,255,239,236,237,238,239,236,1,1,266,263,1,266,1,1,1,1,1,152,177,166,1,238,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,1,266,263,1,266,1,1,1,1,1,1,1,1,1,1,1,1,152,177,177,177,146,4,4,4,4,4,4,4,4,4,4,4, +76,76,1,1,1,1,242,243,240,241,242,1,1,253,242,243,240,241,242,243,1,1,1,1,1,1,1,243,1,1,1,1,168,177,150,1,242,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,177,177,177,146,4,4,4,4,4,4,4,4,4,4,4, +76,76,76,1,1,1,246,247,244,245,246,1,256,1,246,247,257,245,262,247,244,245,246,247,244,245,1,247,1,1,1,1,156,177,177,150,246,1,256,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,160,177,177,177,177,146,4,157,4,4,4,4,4,4,4,4, +76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,177,177,154,1,4,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,248,260,254,253,1,1,1,1,152,177,177,177,177,150,149,146,4,4,4,4,4,4,4,4, +76,76,76,76,76,1,1,1,1,1,1,1,241,242,243,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,177,151,1,1,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,266,263,1,266,1,1,1,1,1,152,177,177,177,177,161,178,150,4,4,4,4,4,4,4, +76,76,76,76,76,1,1,1,1,1,1,1,245,266,247,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,166,1,1,1,250,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,177,177,177,177,177,177,146,4,4,153,153,153,153,149, +76,76,76,76,76,76,76,1,1,1,1,1,249,267,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,177,150,1,1,238,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,177,177,177,177,178,177,146,153,149,165,165,165,165, +76,76,76,76,76,76,76,1,1,1,1,1,237,238,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,177,154,1,1,242,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,177,177,177,177,177,177,165,165,177,177,177,177,177, +76,76,76,76,76,76,76,76,1,1,1,241,242,243,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,151,1,1,246,1,256,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,177,177,177,177,177,177,177,177,177,177,177,177, +76,76,76,76,76,1,76,76,1,1,1,245,266,247,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,166,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,177,177,177,177,177,177,177,177,177,177,177,177, +76,76,76,76,76,76,76,76,1,1,1,249,267,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,154,1,1,1,1,1,1,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,177,177,177,177,177,177,177,177,177,177,177, +76,76,76,76,76,76,76,1,1,1,1,237,238,1,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,166,1,1,1,1,1,1,1,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,167,167,167,177,177,177,177,177,177,177,177, +76,76,76,76,76,1,1,1,1,1,1,241,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,150,1,1,1,1,1,1,250,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,159,159,155,152,177,177,177,177,177,177,177, +76,76,76,76,1,1,1,1,241,242,243,245,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,150,1,1,1,1,1,1,238,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,177,177,177,177,177,177,177, +76,76,76,76,1,241,242,243,245,266,247,249,250,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,177,150,1,1,1,1,1,242,1,1,1,1,1,248,260,254,253,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,177,177,177,177,177,177, +76,76,1,1,1,245,266,247,249,267,1,237,238,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,177,150,1,1,1,1,1,246,1,256,1,1,1,266,263,1,266,1,1,1,1,1,1,1,1,63,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,177,177,177,177,177,177, +76,76,1,241,242,243,267,1,237,238,1,241,242,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,177,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,1,1,63,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,167,167,167,167,167, +76,0,1,245,266,247,238,1,241,255,1,249,267,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,177,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,155,155,155,155,155,155, +76,76,1,249,267,1,255,1,245,255,1,237,238,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,177,177,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +76,76,1,237,238,1,255,1,249,250,1,241,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,177,177,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,63,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +76,76,76,241,255,1,250,1,237,238,255,245,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,177,167,177,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +76,76,76,245,255,1,238,255,241,242,1,249,250,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,151,152,177,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,63,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +76,76,76,249,250,1,241,242,243,255,1,237,238,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,151,1,152,177,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,63,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +76,76,0,237,238,255,245,266,247,255,1,241,242,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,166,1,1,152,177,177,158,1,1,1,1,1,1,1,1,1,1,1,1,63,76,76,76,76,1,63,76,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +76,76,76,241,242,1,249,267,1,242,243,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,1,1,1,1,1,1,1,1,168,150,1,1,152,177,166,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,76,0,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +76,76,76,1,1,1,237,238,1,266,247,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,156,177,154,1,1,152,177,146,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,76,64,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +76,76,76,76,1,1,241,255,1,267,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,168,166,1,1,1,168,177,146,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,63,0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +76,76,76,76,1,76,245,255,1,238,1,1,1,248,260,254,253,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,156,177,154,1,1,160,177,177,146,1,1,1,1,1,1,1,1,1,1,1,1,76,76,1,1,1,63,63,1,1,1,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +76,76,76,76,76,76,249,250,1,255,1,1,1,266,263,1,266,1,1,1,1,1,76,76,76,76,76,1,1,1,1,1,1,1,168,166,1,1,1,152,177,177,146,1,1,1,1,1,1,1,1,1,1,1,1,76,1,1,1,1,63,0,1,1,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1, +76,76,76,76,76,76,237,238,255,255,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,1,1,1,1,1,1,1,156,177,154,1,1,1,152,177,177,146,1,1,1,1,1,1,1,1,1,1,1,76,76,1,1,1,1,64,1,1,1,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,1,1,1,1,1,1,1,1,1, +76,76,76,76,76,76,241,242,1,250,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,1,1,1,1,1,1,1,168,166,1,1,1,1,152,177,177,146,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,64,1,1,1,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,1,1,1,1,1,1,1,1, +76,76,76,76,76,76,1,1,237,238,255,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,1,1,1,1,1,1,156,177,154,1,1,1,1,152,177,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,1,1,1,1,1,1,1,1,1, +76,76,76,76,76,76,1,1,241,242,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,1,1,1,1,1,1,1,168,151,1,1,1,1,1,152,177,177,146,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,1,1,1,1,1,1,1,1, +76,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,1,1,1,1,1,1,156,166,1,1,1,1,1,1,168,177,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,1,1,1,1,1,1,1,1,1, +76,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,1,1,1,1,1,1,1,168,154,1,1,1,1,1,156,177,177,177,146,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,4,1,1,1,1,1,1,1, +76,76,1,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,1,1,1,1,1,1,156,166,1,1,1,1,1,1,152,177,177,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,4,1,1,1,1,1,1,1,1, +76,76,1,1,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,1,1,1,1,1,1,1,168,154,1,1,1,1,1,1,152,177,177,177,146,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,1,4,1,1,1,1,1,1, +76,1,1,1,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,1,1,1,1,1,1,1,156,166,1,1,1,1,1,1,1,152,177,177,177,146,1,1,1,1,1,1,1,1,255,1,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,1,1,1,1,1,1,1,1,1, +76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,1,1,1,1,1,1,1,1,168,154,1,1,1,1,1,1,1,152,177,177,177,150,1,1,1,1,1,1,1,255,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,1,1,1,1,1,1,1,1,1, +76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,1,1,1,156,166,1,1,1,1,1,1,1,1,152,177,177,177,146,153,1,1,1,1,1,1,250,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1, +76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,1,1,1,1,168,154,1,1,1,1,1,1,1,1,152,177,177,177,165,150,1,1,1,1,1,238,255,1,1,1,1,1,1,1,1,76,76,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1, +0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,160,166,1,1,1,1,1,1,1,1,1,152,177,177,177,177,150,1,1,1,1,1,242,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1, +76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,1,1,168,154,1,1,1,1,1,1,1,1,1,152,177,177,177,177,146,1,1,1,1,246,1,256,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,1,1,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,1,1,1,1,1,1,1,1,1,145,166,1,1,1,1,1,1,1,1,1,1,152,177,177,177,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,1,1,1, +76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,1,1,1,1,1,1,1,1,4,145,177,154,1,1,1,1,1,1,1,1,1,1,152,177,177,177,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1, +76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,166,1,1,1,1,1,1,1,1,1,1,1,152,177,177,177,177,150,1,1,1,1,1,1,1,1,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1, +76,0,1,1,1,1,248,260,254,253,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,177,154,1,255,1,1,1,1,1,255,1,1,1,168,177,177,177,177,146,1,1,1,1,1,1,1,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76, +76,1,1,1,1,1,266,263,1,266,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,151,1,1,255,1,1,1,1,1,255,1,1,156,177,177,177,177,177,150,1,1,1,1,1,1,1,250,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76, +76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,166,1,1,250,1,1,1,1,1,250,1,1,1,168,177,177,177,177,177,150,1,1,1,1,1,1,238,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76, +76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,154,1,1,238,255,1,1,1,1,238,255,1,156,177,177,177,177,177,177,150,1,1,1,1,1,1,242,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76, +76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,166,1,1,242,1,1,1,1,1,242,1,1,1,148,167,177,177,177,177,177,150,1,1,1,1,1,246,1,256,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76, +76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,145,177,154,1,1,246,1,256,1,1,1,246,1,256,1,159,152,177,177,177,177,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76, +76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,145,177,151,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,177,177,177,177,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76, +76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,151,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,177,177,177,177,177,194,1,1,1,1,1,1,1,1,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76, +76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,166,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,163,177,177,177,206,150,1,1,1,1,1,1,1,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76, +76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,149,177,154,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,159,148,177,177,208,177,150,1,1,1,1,1,1,1,250,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76, +76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,149,177,151,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,148,177,208,177,177,150,157,153,1,1,1,1,238,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,166,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,148,206,177,177,177,165,165,150,1,1,1,1,242,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,64, +76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,177,154,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,196,177,177,177,177,177,177,150,1,1,1,246,1,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,160,177,151,1,1,1,1,1,1,1,1,1,1,1,76,1,1,1,1,1,1,1,1,148,177,177,177,177,177,177,150,1,1,1,1,1,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,64, +76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,151,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,1,1,148,177,177,177,177,177,177,150,1,1,1,1,250,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,145,166,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,1,1,148,167,167,177,177,177,177,150,1,1,1,1,238,255,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76, +76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,149,177,154,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,1,1,159,159,152,177,177,177,177,150,1,1,1,242,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76, +76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,151,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,1,1,1,2,152,177,177,177,177,150,1,1,1,246,1,256,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76, +76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,166,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,1,1,1,1,1,1,1,1,1,152,177,177,177,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76, +76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,154,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1,152,177,177,177,177,154,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76, +80,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,168,151,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,1,1,1,1,1,1,1,1,1,2,152,177,177,177,162,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,145,151,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,1,1,1,1,1,1,255,1,1,1,152,177,177,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,64, +76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,153,145,166,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,1,1,1,1,1,255,1,1,1,1,152,177,177,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,161,177,154,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,1,1,1,1,1,250,1,1,1,1,152,177,177,177,154,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,64, +76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,177,151,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,1,1,1,1,238,255,1,1,1,1,152,177,177,166,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,151,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,1,1,1,1,242,1,1,1,1,1,152,177,177,154,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,64, +76,76,1,1,1,1,1,1,248,260,254,253,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,166,1,1,1,1,1,1,255,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,1,1,1,246,1,256,1,1,1,1,152,177,166,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +76,76,1,1,1,1,1,1,266,263,1,266,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,158,1,1,1,1,1,1,255,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1,152,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,64, +76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,149,147,1,1,1,1,1,1,250,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,0,1,1,1,1,1,1,1,1,1,1,152,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,149,147,1,1,1,1,1,1,1,238,255,1,1,1,1,1,76,76,76,76,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,152,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,64, +76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,153,1,1,1,145,162,1,1,1,1,1,1,1,242,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,0,1,1,1,1,1,1,1,1,1,1,1,168,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,149,146,1,1,145,177,154,1,1,1,1,1,1,1,246,1,256,1,1,1,1,76,76,76,76,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,156,177,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,64, +76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,145,177,150,2,149,177,166,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,148,177,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,149,177,177,146,145,177,177,154,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,148,177,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,64, +64,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,145,177,177,177,165,177,177,166,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,148,177,177,154,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,177,177,177,177,177,177,154,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,168,177,166,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,64, +76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,177,177,177,177,177,177,166,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,177,154,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,2,168,177,177,177,177,177,177,154,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,177,166,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,153,149,177,177,177,177,177,177,166,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,161,177,177,177,177,177,177,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,148,177,177,177,177,177,177,177,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1, +76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,164,177,177,177,177,177,177,177,177,154,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,152,177,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,149, +76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,149,177,177,177,177,177,177,177,177,166,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,177,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,149, +76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,145,177,177,177,177,177,177,177,177,177,154,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,76,1,1,1,1,1,1,1,1,1,1,1,1,1,156,167,177,177,158,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,149,177, +76,1,1,1,1,1,1,1,17,1,1,1,1,1,1,1,1,1,1,160,177,177,177,177,177,177,177,177,177,166,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,64,1,1,1,1,1,1,1,1,1,1,1,1,1,155,152,177,162,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,160,177, +76,1,1,1,1,153,153,153,1,1,1,1,1,1,1,1,1,1,1,148,177,177,177,177,177,177,177,177,177,154,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,2,152,177,158,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,177, +76,11,1,1,1,156,165,165,154,1,1,1,1,1,1,1,1,1,1,157,168,177,177,177,177,177,177,177,177,166,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,1,1,1,1,255,1,1,1,1,1,1,1,76,76,76,1,1,1,2,168,162,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,145,177, +76,11,1,1,1,168,177,166,1,1,1,1,1,1,1,1,1,1,156,165,177,177,177,177,177,177,177,177,177,154,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,255,1,1,1,1,1,1,76,76,76,76,1,1,1,156,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,149,177,177, +76,11,1,1,1,156,177,177,154,1,1,1,1,1,1,1,1,1,1,168,177,177,177,177,177,177,177,177,177,166,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,250,1,1,1,1,1,1,1,76,76,76,76,1,1,2,168,177,158,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,145,177,177, +76,11,1,17,1,168,177,166,1,1,1,1,1,1,1,1,1,1,156,177,177,177,177,177,177,177,177,177,177,154,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,238,255,1,1,1,1,1,76,76,76,76,76,1,1,156,177,162,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,149,177,177,177, +76,1,11,1,1,156,177,177,154,1,1,1,1,1,1,1,1,1,1,168,177,177,177,177,177,177,177,177,177,166,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,242,1,1,1,1,1,1,1,76,76,76,76,1,1,2,168,177,150,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,177,177, +1,11,4,1,1,167,167,151,1,1,1,1,1,1,1,1,1,1,156,177,177,177,177,177,177,177,177,177,177,154,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,246,1,256,255,1,1,1,76,76,76,76,76,1,1,156,177,177,158,1,1,1,1,1,1,153,1,1,1,1,1,1,157,157,157,1,1,1,1,1,1,1,1,1,168,177,177,177, +0,11,11,1,1,1,159,155,1,1,1,1,1,1,1,1,1,1,1,168,177,177,177,177,177,177,177,177,177,166,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,255,1,1,1,76,76,76,76,76,1,1,2,148,177,162,157,157,157,157,157,153,149,150,153,1,1,1,1,149,165,165,150,1,1,1,1,1,1,1,1,193,177,177,177, +0,11,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,177,177,177,177,177,177,177,177,177,154,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,250,1,1,1,76,76,76,76,76,1,1,1,148,177,165,165,165,165,165,165,165,177,165,146,1,1,1,145,177,177,177,150,1,1,1,1,1,1,1,145,197,177,177,177, +0,11,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,177,177,177,177,177,177,177,177,177,166,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,238,255,1,1,76,76,76,76,76,1,1,1,1,148,177,181,181,181,181,181,181,181,177,177,150,1,1,149,177,177,177,177,194,1,1,1,1,1,1,149,177,207,177,177, +0,11,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,177,177,177,177,177,177,177,177,177,177,154,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,242,1,1,1,76,76,76,76,76,1,1,1,1,148,181,181,181,181,181,181,181,177,177,177,194,157,145,177,177,177,177,198,150,1,1,153,153,153,145,177,177,203,177,177, +76,11,1,1,1,1,1,1,1,1,1,1,1,76,1,1,1,1,1,152,177,177,177,177,177,177,177,177,177,151,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,246,1,256,1,76,76,76,76,76,1,1,1,1,1,164,181,181,181,181,181,181,177,177,177,198,161,165,177,177,177,177,202,177,150,157,193,165,165,165,177,177,177,203,177, +76,11,1,1,1,1,1,1,1,1,1,1,1,76,1,1,1,1,1,152,177,177,198,177,177,177,177,177,151,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,1,1,1,1,149,181,181,181,181,181,181,181,177,177,204,177,177,177,177,177,177,202,177,177,165,165,197,177,177,177,177,177,177,205,177, +76,0,11,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,1,168,177,202,177,177,177,177,177,151,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,1,1,1,1,145,181,181,181,181,181,181,181,177,177,204,177,177,177,177,177,177,202,177,177,177,177,177,201,177,177,177,177,177,177,177, +0,0,11,1,1,1,1,1,1,1,1,76,76,76,76,76,1,1,1,156,177,202,177,177,177,177,177,151,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,1,1,1,149,181,181,181,181,181,181,181,181,177,204,177,177,177,177,177,177,202,177,177,177,177,177,177,201,177,177,177,177,177,177,177, +0,0,1,1,1,1,1,1,1,1,1,76,76,76,76,0,1,1,1,1,152,198,177,177,177,177,177,151,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,1,1,1,156,181,181,181,181,181,181,181,181,181,204,177,177,177,177,177,177,202,177,177,177,177,177,177,177,201,177,177,177,177,177,177, +0,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,196,177,177,177,177,177,151,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,1,1,1,168,181,181,181,177,181,181,181,181,206,177,177,177,177,177,177,200,177,177,177,177,177,177,177,177,201,177,177,177,177,177,177, +0,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,1,1,1,1,1,152,167,177,177,177,166,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,1,1,156,181,181,181,177,177,181,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,201,177,177,177,177,177, +0,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,1,1,1,1,1,155,152,167,167,167,158,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,181,181,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,201,177,177,177,177,177, +0,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,1,1,1,1,1,1,155,155,155,155,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,156,181,181,181,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,199,177,177,177,177, +0,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,168,181,181,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +0,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,149,181,181,181,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,145,177,181,181,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +76,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,1,1,1,1,1,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,145,177,181,181,181,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +76,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,1,1,1,1,1,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,149,177,177,181,181,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +76,76,0,0,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,1,1,1,1,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,1,1,1,1,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,149,177,177,181,177,181,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +76,76,0,0,0,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,1,1,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,1,1,1,76,76,76,76,76,76,1,76,76,1,1,1,1,1,1,1,1,1,76,76,76,76,1,149,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +76,76,76,0,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,1,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,1,1,76,76,76,76,76,76,76,76,76,76,76,1,1,1,1,76,1,1,76,76,76,76,76,156,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,1,76,76,76,76,76,76,76,76,76,76,76,1,1,1,1,76,76,1,76,76,76,76,76,1,168,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177, +76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,1,1,1,1,1,1,1,1,1,1,1,1,1,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,76,156,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177,177 + + + + +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,45,64,64,49,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,63,64,63,64,63,64,64,64,64,64,45,64,64,64,64,64,64,64,45,64,64,64,64,64,64,64,64,64,64,64,64,64,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,54,64,64,64,37,34,45,41,45,45,64,63,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,63,63,63,63,63,63,41,45,45,64,33,38,64,64,64,64,64,64,33,38,64,64,64,64,64,64,64,64,64,64,64,64,63,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,174,64,38,64,64,37,64,53,53,49,49,34,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,63,63,63,63,63,37,53,53,38,37,64,38,64,64,64,64,64,33,64,38,64,64,64,64,64,64,64,64,64,64,64,63,63,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,173,64,64,38,64,44,64,64,111,64,64,64,38,63,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,63,63,63,64,64,33,64,137,64,53,64,64,38,64,64,64,64,37,64,64,38,41,41,41,64,64,64,64,64,64,63,63,63,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +64,64,64,64,64,64,64,64,64,64,64,64,111,109,108,64,64,172,64,64,64,46,64,36,64,64,64,64,64,64,42,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,45,63,63,63,64,37,64,64,64,64,64,127,64,38,64,64,64,37,64,64,209,53,49,53,46,64,64,64,64,64,63,63,63,63,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +64,64,64,64,64,64,64,64,64,64,64,64,116,111,109,64,64,64,64,64,64,39,64,64,36,64,64,64,138,64,50,63,64,64,41,64,64,64,64,64,64,64,64,64,64,64,33,38,63,63,64,44,64,125,109,64,64,64,64,137,38,64,64,33,137,64,64,64,129,64,35,64,64,64,64,63,63,63,63,63,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +64,64,64,64,64,64,64,64,64,64,64,64,64,113,64,64,64,64,64,64,39,64,64,63,36,64,59,64,111,64,34,45,64,37,38,64,64,64,64,64,64,64,64,64,64,33,64,34,63,63,64,56,64,64,64,127,64,64,64,64,38,41,37,64,64,64,64,86,64,35,64,64,64,64,64,63,63,63,63,64,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +64,64,64,64,64,64,64,64,64,64,64,64,0,64,64,64,64,64,64,64,54,64,64,64,63,52,64,60,64,64,58,53,34,37,64,34,64,64,64,64,64,64,64,64,64,33,125,64,38,63,64,33,64,64,109,104,64,64,64,64,64,53,53,64,111,88,64,64,64,50,64,64,64,64,64,63,63,63,63,64,0,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +64,64,64,64,64,64,64,64,64,64,64,64,64,109,108,64,64,64,64,64,38,64,64,63,37,64,64,64,64,57,64,64,53,64,64,42,64,64,64,64,64,64,64,64,33,103,64,64,34,63,48,64,64,64,64,64,64,64,64,64,64,64,64,108,64,64,64,64,64,34,64,64,64,64,63,0,64,63,64,64,0,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +64,64,64,64,64,64,64,64,64,64,64,134,61,109,64,64,64,64,64,64,142,38,41,45,33,64,111,64,64,64,64,64,106,64,134,54,63,64,64,64,64,64,64,64,33,125,64,125,64,34,41,52,127,64,64,64,64,64,227,64,64,64,64,64,64,64,64,64,64,64,38,64,64,64,64,0,0,63,64,64,0,0,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,53,49,44,64,64,64,64,87,64,64,106,64,111,64,46,64,64,64,64,64,64,64,37,64,64,64,109,64,49,49,64,64,64,64,125,64,64,64,64,144,64,64,64,64,108,64,64,64,209,34,64,64,64,63,0,0,64,64,64,0,0,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +64,64,64,64,64,64,64,64,64,64,64,64,115,111,64,64,64,64,64,64,0,116,64,38,36,138,64,64,64,64,64,111,64,104,64,35,64,64,64,64,64,64,64,44,125,64,125,64,109,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,88,64,64,64,34,64,64,64,0,63,64,64,64,0,0,63,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +64,64,64,64,64,64,129,64,64,64,64,64,64,64,64,64,64,0,0,0,0,109,64,42,52,64,64,64,64,64,64,64,104,64,54,64,64,64,64,64,64,64,64,56,64,64,64,109,64,64,64,109,64,125,64,64,64,64,64,64,64,64,215,64,64,108,64,64,64,64,209,38,64,64,64,0,64,64,64,64,0,63,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,0,0,0,0,0,64,39,37,111,64,58,111,64,104,103,104,64,64,42,64,64,64,64,64,64,64,37,64,125,64,64,64,0,64,109,64,64,64,64,227,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,34,45,45,45,56,64,64,64,63,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +64,64,64,64,64,64,0,64,64,64,64,64,64,64,64,64,64,0,0,0,0,0,39,37,64,104,57,64,111,104,64,64,104,64,54,64,64,64,64,64,64,64,44,64,103,64,64,0,0,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,108,64,64,86,53,49,49,34,64,64,64,63,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +64,64,64,64,129,345,346,347,64,64,64,64,64,64,64,64,64,113,0,0,0,0,64,44,64,64,64,64,111,111,64,64,104,64,64,42,64,64,64,64,64,64,64,56,64,64,64,0,0,64,64,64,64,64,64,64,64,64,64,64,143,64,64,61,64,64,64,64,64,111,64,86,64,64,64,64,38,64,64,64,63,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +64,64,64,64,64,64,116,64,64,64,64,64,64,64,64,64,64,0,0,0,0,0,42,52,64,64,64,64,64,111,64,64,111,54,43,45,64,64,64,64,64,64,33,137,64,64,0,64,64,125,64,137,64,64,64,144,64,64,64,64,64,64,64,64,64,64,64,64,64,111,64,64,64,64,129,64,38,64,64,63,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +64,64,64,64,64,64,64,64,346,64,64,64,64,64,64,64,64,109,0,0,0,0,54,44,64,64,106,64,64,103,106,64,104,64,46,37,38,64,64,64,64,64,33,64,64,64,0,0,64,105,64,64,64,64,64,64,64,64,64,64,64,64,64,64,144,64,64,64,64,111,64,64,64,64,64,108,64,34,64,63,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +64,64,64,64,64,64,64,64,345,347,64,64,64,64,64,64,109,0,0,0,0,114,34,36,64,104,64,103,64,64,64,103,104,50,33,64,38,41,45,45,0,33,64,92,64,109,0,64,125,64,125,64,64,227,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,209,64,64,64,38,64,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +64,64,64,64,64,64,64,64,345,108,346,64,64,64,64,64,0,0,0,0,0,0,113,34,43,56,104,64,64,64,111,103,64,64,53,64,64,53,49,53,46,48,64,64,92,64,64,64,64,64,64,64,64,64,64,64,64,64,64,218,64,64,64,64,64,64,215,64,64,111,87,64,64,64,64,64,138,64,38,63,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +64,64,64,64,64,64,64,64,64,108,113,64,64,64,64,64,0,0,0,0,0,0,64,34,37,104,104,111,64,111,64,64,106,64,111,103,64,64,64,54,64,40,64,64,0,64,64,125,64,125,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,42,63,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +64,64,113,64,0,0,83,64,64,64,64,64,64,64,64,64,0,0,0,0,0,0,64,64,53,64,64,104,64,103,64,64,64,64,64,64,64,64,64,64,42,64,40,64,0,0,64,103,64,103,64,64,64,64,64,64,64,64,215,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,39,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +64,64,129,0,221,64,64,64,132,64,64,64,64,64,64,64,0,0,0,0,109,109,64,64,64,64,64,106,64,64,104,104,111,64,64,64,64,64,114,54,64,64,40,64,64,64,64,64,125,64,64,64,144,64,64,64,64,64,64,64,64,64,64,143,64,64,64,64,64,64,64,64,64,64,64,111,64,39,64,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +64,64,64,108,0,64,64,64,64,64,64,64,64,64,64,64,0,0,0,0,0,109,64,64,64,64,103,64,64,64,104,104,64,111,64,64,64,138,64,64,46,64,64,56,64,64,92,64,64,64,64,227,64,64,64,64,64,64,64,64,144,64,64,64,64,64,64,64,64,64,64,64,64,64,64,111,129,39,64,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +64,64,64,108,64,64,64,64,64,64,64,64,64,64,64,64,0,0,0,0,0,64,64,109,64,64,64,64,111,64,104,104,103,142,111,64,64,106,64,54,64,64,37,64,64,64,92,64,64,64,64,64,64,64,64,64,64,64,83,64,64,64,64,64,64,64,64,144,64,64,64,64,114,64,64,111,50,64,64,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +64,64,64,64,0,64,64,87,64,64,64,64,64,64,64,64,0,0,0,0,116,0,0,140,109,64,64,111,104,64,104,111,104,64,64,104,64,64,64,64,38,64,44,64,64,64,64,92,64,64,64,64,64,64,64,64,143,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,108,64,64,38,64,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,140,0,0,0,0,0,0,0,109,103,111,104,64,111,64,111,64,64,104,121,64,64,64,64,38,64,40,64,64,64,64,92,64,64,85,64,64,64,64,64,64,64,64,106,64,64,218,64,64,64,64,64,64,215,64,64,64,111,64,64,64,38,64,64,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0, +64,64,64,64,0,64,64,64,64,64,64,64,64,64,64,64,64,64,0,0,0,0,0,0,64,103,64,64,104,111,64,111,64,64,64,64,64,64,64,64,64,42,64,40,64,106,64,64,92,227,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,108,64,121,64,64,42,64,64,64,64,64,64,41,41,41,41,41,41,41,41,41,41,41,41,41,41,41,4, +64,64,64,0,64,64,64,64,64,64,64,64,64,64,64,64,64,64,0,64,0,0,0,0,111,64,64,64,64,104,64,111,103,104,64,64,104,64,64,64,39,64,64,56,64,64,64,64,64,64,64,64,64,64,218,64,64,64,64,64,64,215,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,54,64,64,64,64,64,64,33,53,49,53,49,49,53,49,53,49,53,49,53,49,53,38,4, +64,64,64,345,108,121,64,0,64,64,108,64,64,64,64,64,64,64,111,64,0,0,0,0,64,64,64,64,64,64,106,111,103,64,64,114,104,64,104,138,54,64,64,44,64,116,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,143,64,64,64,64,64,64,64,64,64,64,34,64,64,64,64,64,33,64,0,4,4,4,4,4,4,4,4,4,4,4,4,4,38, +64,64,64,108,64,0,64,345,347,64,64,64,64,64,64,64,64,111,64,64,0,0,0,0,106,64,104,64,64,64,103,111,64,64,64,64,104,64,104,64,42,64,64,56,64,64,64,64,64,64,64,64,64,215,64,64,64,64,64,64,64,64,85,144,64,64,64,64,64,64,64,64,64,64,64,64,64,64,34,64,64,64,64,33,100,64,0,64,116,64,64,64,64,64,64,64,64,64,64,64,46, +64,64,64,64,64,64,64,345,64,346,64,64,64,64,64,64,64,64,64,64,160,0,0,0,64,64,104,64,64,104,64,111,64,104,64,64,64,64,111,64,54,64,64,44,64,64,64,144,64,64,64,64,64,64,64,64,64,64,64,143,64,64,85,64,64,64,64,64,64,64,64,64,64,64,64,111,64,64,64,34,45,45,45,33,64,64,64,0,111,64,64,64,64,64,64,64,64,64,64,64,54, +64,64,64,113,64,64,64,64,64,132,64,64,64,64,64,64,64,64,64,64,0,0,0,0,64,111,64,104,64,64,64,64,111,104,64,64,64,64,111,64,42,64,64,56,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,106,64,64,64,64,64,64,64,64,64,64,64,111,64,64,64,53,53,53,53,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,42, +64,64,64,64,64,64,64,64,113,64,64,64,64,64,64,64,64,64,64,64,0,0,0,0,64,64,64,104,64,106,64,104,64,104,64,64,64,64,64,116,54,64,64,44,64,64,64,64,64,64,64,64,64,64,64,144,64,64,64,64,64,64,64,64,64,64,218,64,64,64,230,64,64,64,64,111,64,64,64,64,64,64,64,64,100,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,54, +64,64,64,64,1,64,108,64,64,64,64,64,64,129,115,64,64,0,0,141,0,0,0,111,0,103,64,64,64,64,64,64,64,64,64,64,103,64,64,64,42,64,64,56,64,64,64,64,106,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,138,64,64,64,64,64,64,64,64,64,64,64,64,138,64,64,64,64,64,64,64,64,64,64,64,64,64,46, +64,64,64,64,345,347,64,64,64,64,64,64,64,64,64,109,64,0,0,0,0,0,0,0,0,64,64,142,64,64,64,64,64,64,64,64,64,64,64,64,54,64,64,44,64,64,64,64,64,64,64,64,64,64,64,106,64,64,218,64,64,64,64,64,64,215,64,64,64,64,64,64,64,64,64,64,108,114,64,64,64,64,64,64,64,111,64,108,64,64,64,64,64,64,64,64,64,64,64,64,54, +64,64,64,108,345,64,346,64,64,64,64,64,64,64,64,109,64,0,0,0,0,0,0,0,0,104,64,64,64,106,64,64,103,106,64,64,64,64,64,64,42,64,64,56,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,114,64,105,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,42, +64,64,64,64,64,64,64,64,64,64,64,64,64,109,118,114,64,0,0,0,0,0,0,0,0,64,104,64,64,64,103,64,64,106,64,142,64,116,64,64,39,64,64,44,64,64,64,64,64,64,218,64,64,143,64,64,64,215,64,64,64,64,64,64,64,64,64,64,230,64,64,64,64,64,111,64,64,64,64,64,64,64,64,64,64,116,64,64,64,64,64,64,64,64,64,64,64,64,64,64,54, +64,64,64,64,132,64,64,64,64,64,64,64,64,115,109,64,64,0,111,0,0,0,134,90,0,64,64,103,104,64,64,64,64,64,64,64,64,64,64,39,64,64,64,56,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,104,64,64,64,64,64,64,64,64,64,64,64,64,111,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,42, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,103,64,0,0,0,0,0,0,89,0,209,64,64,64,64,64,64,64,64,104,64,64,64,64,54,64,64,64,44,64,64,212,64,64,64,64,144,64,64,64,64,64,64,64,64,64,64,64,143,64,64,64,64,64,64,64,64,108,64,64,121,64,64,64,98,64,64,100,64,111,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,54, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,0,0,0,0,0,89,0,0,64,92,64,64,104,111,104,64,64,64,64,111,64,64,42,64,64,64,40,64,64,64,64,64,115,64,64,64,64,64,64,64,82,144,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,111,108,64,64,64,64,64,64,64,64,64,64,64,64,64,64,46, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,0,0,0,0,0,0,116,0,64,82,92,64,64,64,104,64,111,64,64,111,64,138,54,64,64,64,64,40,64,64,85,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,116,64,64,64,64,64,64,111,108,64,64,64,64,64,64,64,64,64,64,64,64,64,64,54, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,0,0,0,0,90,0,0,0,64,64,112,111,64,64,64,111,64,64,64,103,64,64,38,64,64,64,64,56,64,88,64,64,64,64,64,64,64,64,64,64,64,64,64,64,218,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,42, +64,64,64,64,64,64,64,64,64,64,64,64,64,108,64,64,64,0,0,0,0,89,0,111,0,64,64,64,111,64,64,64,64,64,114,64,64,103,64,64,38,64,64,64,44,64,64,64,64,106,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,230,64,64,64,114,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,0,64,64,64,64,54, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,0,0,0,212,0,111,0,0,112,64,64,64,64,106,64,64,121,64,134,64,64,111,64,42,64,64,64,56,64,64,64,64,106,64,64,64,218,64,64,64,64,64,64,215,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,111,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,0,64,64,64,64,64,42, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,209,64,0,0,0,0,0,0,0,112,64,64,64,64,92,64,64,142,64,64,64,64,64,64,64,35,64,64,64,37,64,64,64,64,109,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,224,64,64,111,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,0,64,64,64,64,54, +64,64,64,64,64,64,64,64,64,64,64,64,116,64,64,64,64,0,0,0,0,86,0,0,0,64,64,115,88,92,64,64,64,64,106,64,64,64,64,54,64,64,64,37,64,64,64,64,64,64,109,64,64,64,144,64,64,143,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,138,64,64,100,100,64,64,64,64,64,64,64,64,64,64,64,64,0,64,64,64,64,46, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,0,0,0,0,86,0,113,0,64,64,64,64,64,64,64,64,64,104,64,64,64,64,64,46,64,64,44,64,64,64,64,64,64,109,64,64,64,64,64,64,64,64,64,64,64,64,64,64,144,64,64,98,64,64,64,64,64,64,64,64,90,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,0,64,64,64,64,64,54, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,0,0,0,0,0,0,0,122,64,64,64,64,90,104,64,64,64,64,64,64,64,64,54,41,45,64,40,64,64,64,64,64,64,64,109,116,64,64,64,64,64,64,64,64,64,64,230,64,64,64,64,64,64,111,64,64,64,64,64,89,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,0,64,64,64,64,64,46, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,108,0,0,0,143,0,0,0,0,64,64,64,64,89,64,104,64,64,64,64,64,64,64,103,53,53,46,64,40,116,64,64,64,64,64,138,64,64,64,122,64,64,64,64,64,64,64,64,64,64,64,64,64,64,111,64,111,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,0,64,64,64,64,64,54, +64,64,64,64,64,64,64,64,64,64,64,64,64,109,64,64,64,0,0,0,0,0,0,0,0,64,212,64,89,64,64,111,64,111,64,64,64,64,64,64,64,39,64,45,56,64,64,64,64,64,64,64,114,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,89,64,114,64,64,64,64,64,64,64,64,64,64,64,64,64,64,233,64,0,0,64,64,64,64,42, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,109,64,64,0,0,0,0,0,0,0,0,64,64,64,64,64,64,111,64,64,111,64,64,64,138,64,64,39,64,48,53,64,64,64,212,64,64,64,109,64,64,64,64,218,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,90,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,0,0,64,64,64,64,54, +64,64,64,64,64,64,64,64,64,64,64,64,64,109,64,64,64,0,0,0,0,0,0,0,0,64,64,64,64,64,114,111,64,64,64,64,129,64,64,64,39,64,64,40,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,230,64,64,64,64,64,64,64,64,64,64,64,64,93,105,64,64,64,105,64,64,64,64,138,64,64,64,64,64,64,64,64,0,64,0,64,64,64,64,42, +35,36,64,64,64,64,64,64,64,64,64,113,64,64,64,64,64,0,0,0,0,0,0,0,0,64,64,64,64,64,64,111,129,64,64,64,64,64,111,64,54,64,64,64,56,64,64,64,64,122,64,64,64,64,64,64,64,64,64,64,64,64,64,64,116,64,64,64,64,64,64,64,64,64,64,64,64,64,64,111,64,64,64,64,64,64,64,64,64,64,64,64,64,0,64,0,64,64,64,64,54, +64,36,64,64,64,64,109,132,64,129,64,64,64,64,64,64,64,108,0,0,0,0,0,0,0,64,64,64,112,64,64,111,64,64,64,103,106,64,111,64,42,64,64,44,64,121,64,64,86,104,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,224,64,64,64,64,64,64,64,64,64,64,111,64,64,64,64,64,64,64,64,64,64,64,64,64,0,64,64,0,64,64,64,46, +64,64,36,64,64,221,64,70,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,112,64,64,111,64,104,64,64,64,111,64,64,39,64,64,64,56,64,64,64,64,64,104,64,64,106,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,224,64,64,111,64,108,64,64,64,64,64,64,108,64,111,64,64,64,64,64,64,0,64,64,0,64,64,64,54, +64,64,52,108,64,64,70,64,0,209,64,108,64,113,64,224,64,64,64,64,113,64,109,64,64,64,64,64,64,143,64,111,64,104,142,64,64,104,116,39,64,64,64,48,64,64,64,64,64,64,64,64,64,109,64,64,64,64,144,64,144,64,64,106,64,64,64,64,64,64,64,64,64,64,64,111,64,64,64,64,64,64,64,64,64,115,64,64,64,64,64,64,64,0,64,64,0,64,64,64,46, +64,64,37,108,108,64,64,64,64,0,64,64,64,64,64,64,64,64,64,64,64,109,109,116,64,143,64,64,64,64,64,106,121,104,64,64,64,64,64,39,64,64,64,64,56,64,64,64,64,64,64,64,64,64,109,64,64,64,64,64,64,64,64,109,106,64,121,64,64,64,64,64,64,64,64,111,111,64,64,64,64,64,64,64,64,111,64,64,64,64,64,64,0,64,64,64,0,64,108,64,54, +41,37,95,108,89,64,64,64,64,64,64,64,64,64,64,64,108,92,64,64,109,134,109,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,50,64,64,64,64,48,64,106,109,109,64,64,64,64,64,64,109,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,111,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,0,64,64,0,64,116,64,64,46, +44,53,64,96,89,64,64,87,64,64,84,64,64,64,64,89,108,108,64,64,64,109,115,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,46,64,64,64,64,56,106,109,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,111,64,64,64,64,64,64,99,64,64,111,64,64,64,64,64,64,0,64,64,0,64,64,64,64,54, +52,64,64,89,64,64,83,64,64,64,63,64,64,64,89,108,108,121,64,64,64,64,109,64,64,64,64,64,141,64,64,64,64,111,64,64,64,64,50,64,64,64,64,48,64,106,109,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,116,64,143,64,138,64,64,64,64,64,64,119,64,64,64,64,64,64,64,0,64,0,64,64,64,64,64,46, +44,64,64,64,64,64,64,64,64,64,63,64,64,64,64,92,108,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,111,64,64,64,106,46,64,64,64,64,56,64,106,64,64,64,64,64,212,64,64,64,64,212,64,64,64,64,64,64,115,64,64,64,64,64,64,64,64,64,64,64,64,64,64,108,64,64,64,64,64,64,64,64,64,64,64,64,0,0,64,0,64,64,64,64,54, +36,64,64,64,64,64,64,64,64,63,63,64,64,64,64,92,93,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,111,129,64,64,50,64,64,64,64,48,64,64,106,64,64,64,64,64,64,64,64,64,64,64,64,104,64,64,106,64,64,98,64,64,111,64,114,64,64,64,64,64,64,64,108,64,64,64,64,64,64,64,64,64,64,64,64,64,0,64,116,64,64,64,64,64,46, +64,36,130,115,64,64,64,64,64,63,63,64,64,64,64,64,92,64,64,64,64,64,64,64,64,64,64,64,64,64,69,64,64,64,64,103,64,64,64,46,64,64,64,45,56,64,138,64,64,64,64,64,64,83,64,64,64,64,64,64,64,98,106,64,64,64,64,64,111,64,64,64,64,64,64,64,64,64,64,108,64,64,99,64,64,64,64,64,64,64,64,64,64,64,64,111,64,64,64,138,54, +64,52,64,64,64,64,64,64,64,346,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,111,64,64,50,64,64,64,48,53,64,64,106,64,64,64,111,64,64,64,64,64,84,82,64,64,64,64,64,64,64,64,64,105,64,64,64,64,64,64,64,64,64,64,64,98,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,46, +64,44,64,64,64,212,67,64,64,345,347,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,111,64,64,138,64,46,64,64,64,40,64,116,64,106,92,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,114,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,54, +64,36,64,86,64,64,67,64,64,116,64,346,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,129,64,64,116,64,64,64,54,45,64,64,64,40,64,116,64,106,64,64,64,64,64,64,64,64,64,64,64,109,64,64,64,39,56,64,64,64,64,64,64,64,64,64,64,64,64,64,111,64,64,64,64,64,64,64,64,64,64,111,64,64,64,64,64,64,64,64,64,64,46, +64,64,40,64,64,64,73,108,64,64,64,64,64,64,64,64,64,109,64,64,64,64,64,64,64,64,124,64,64,64,64,64,64,64,64,64,64,64,64,53,46,64,64,45,52,64,64,64,64,92,64,64,64,64,64,64,64,116,64,64,64,64,64,39,44,64,64,64,64,64,64,64,64,64,64,98,64,64,111,64,64,64,64,64,64,64,64,64,64,111,64,64,64,64,64,64,64,64,64,108,54, +64,64,40,64,64,67,64,108,64,64,64,64,64,64,64,64,64,64,115,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,104,64,64,64,39,64,64,37,53,64,64,64,64,64,115,64,64,109,64,64,64,64,116,64,64,143,64,39,64,40,56,64,64,64,64,64,64,138,64,64,64,64,64,143,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,111,64,138,64,64,64,46, +64,64,64,40,64,64,88,64,64,109,64,93,64,209,134,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,116,64,64,104,111,64,64,39,64,64,37,64,64,64,64,64,64,64,64,64,64,109,64,64,64,64,64,64,64,64,39,64,64,48,64,64,64,64,64,64,64,138,64,64,105,64,64,111,64,64,64,99,64,64,64,64,64,119,64,64,64,64,64,111,115,64,64,64,54, +64,64,64,40,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,138,64,64,111,64,39,64,64,44,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,109,54,64,64,64,56,138,64,64,64,143,64,64,64,64,64,105,64,64,111,64,64,64,64,64,64,64,64,64,64,64,64,138,64,111,64,64,64,64,64,46, +64,64,64,64,40,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,111,64,50,45,64,64,56,64,64,64,64,109,109,64,64,64,64,64,121,64,64,64,64,121,64,109,42,64,64,48,64,64,116,64,64,64,64,64,64,64,105,64,115,111,64,64,64,64,64,64,64,64,111,116,64,64,64,64,111,64,64,64,64,64,54, +64,64,64,64,56,64,66,64,64,64,64,64,64,64,114,64,64,108,64,64,108,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,135,64,53,34,64,37,64,64,64,121,64,64,64,109,64,92,64,64,64,64,64,64,64,64,64,54,64,64,64,56,64,64,64,64,64,64,64,64,64,64,64,64,64,111,64,124,64,64,64,64,64,64,111,64,64,64,64,64,64,64,64,64,64,64,46, +64,64,64,64,44,64,64,64,109,64,64,64,64,64,64,64,64,64,64,64,108,64,64,64,108,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,34,37,64,64,64,64,64,64,64,106,64,64,92,64,64,64,64,64,64,64,64,64,42,64,64,37,64,64,108,64,64,64,108,64,131,64,64,64,111,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,111,64,64,64,54, +64,64,64,64,56,66,66,64,109,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,103,64,64,64,64,53,64,64,64,64,64,64,64,64,64,64,64,92,64,64,64,138,64,93,64,64,54,64,64,44,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,108,64,64,111,64,64,64,46, +64,64,64,64,37,64,66,66,109,108,64,64,64,64,116,346,64,64,64,64,64,64,140,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,143,64,64,64,111,96,64,64,64,64,94,64,64,54,46,64,64,56,64,64,64,64,64,64,64,64,64,64,64,105,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,115,111,64,64,64,54, +64,64,64,33,116,64,66,64,64,64,108,64,64,64,64,345,347,64,64,140,64,64,64,108,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,89,64,106,64,38,64,64,48,64,64,64,64,64,111,64,116,64,64,64,64,105,64,64,64,64,64,64,64,64,64,64,64,64,138,64,64,64,64,64,64,64,64,64,46, +64,64,64,37,64,64,64,64,64,64,64,64,64,64,64,345,64,346,109,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,121,64,64,103,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,106,64,115,64,38,64,64,36,64,64,64,64,64,111,64,64,64,64,105,64,64,64,64,64,116,64,64,99,64,64,64,64,64,64,64,64,64,64,64,64,64,64,54, +64,64,33,64,64,64,212,64,66,114,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,140,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,106,64,115,64,42,64,64,36,64,64,108,64,64,64,64,64,105,108,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,108,64,138,64,46, +64,64,44,64,63,64,64,64,64,64,64,64,64,64,64,64,64,64,108,64,64,116,64,64,64,64,64,64,64,141,64,64,64,64,64,64,64,64,64,64,64,64,64,64,111,64,64,64,64,115,64,64,64,116,64,64,64,106,64,64,64,64,39,64,64,64,52,64,108,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,111,64,64,64,64,64,54, +64,64,36,129,64,108,64,64,66,64,66,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,108,64,64,64,64,64,64,64,64,64,64,64,64,64,39,64,64,64,37,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,99,99,64,64,64,64,64,64,64,111,64,64,64,64,64,46, +64,64,64,36,63,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,108,64,64,64,64,64,129,64,64,64,129,64,139,64,64,64,64,64,64,64,64,64,64,64,143,64,64,64,64,64,39,64,64,64,37,64,64,64,64,64,64,111,64,64,64,64,64,64,64,64,64,111,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,54, +64,64,64,43,40,64,64,64,64,108,64,64,64,64,64,64,64,64,64,64,64,64,64,64,139,116,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,104,64,64,64,64,39,64,64,64,44,64,64,64,64,64,64,135,111,64,64,64,64,64,64,64,64,64,111,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,53, +64,64,64,64,64,40,64,64,64,0,64,64,64,64,109,64,115,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,106,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,108,64,64,54,64,64,64,64,56,64,64,64,64,64,64,111,64,64,64,64,64,64,115,64,64,64,111,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,63,52,64,64,0,0,64,64,64,141,64,64,64,64,64,64,64,64,64,64,64,143,64,64,64,114,64,64,64,64,64,64,106,64,64,64,64,64,64,64,64,106,64,64,64,64,64,64,64,64,64,64,64,64,64,64,46,64,64,64,37,64,64,64,64,64,64,64,111,64,64,64,64,64,64,64,64,64,64,111,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,44,35,52,64,0,64,64,64,64,64,64,140,64,64,64,64,64,64,64,64,121,346,64,64,64,64,64,64,64,64,64,106,103,64,64,64,64,104,64,64,106,64,64,64,64,64,64,64,64,64,64,64,64,64,131,54,64,64,64,37,64,121,64,64,64,64,64,111,64,64,64,64,64,64,64,64,64,64,111,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,43,44,64,64,0,108,64,64,64,64,64,64,121,64,64,64,64,64,132,64,64,64,64,64,64,64,64,64,64,64,64,106,64,64,64,64,64,64,64,106,64,64,64,64,64,64,64,64,108,64,64,64,64,64,64,42,64,64,44,64,64,64,64,138,64,64,64,111,64,64,64,64,64,64,64,64,64,64,115,64,64,64,64,99,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,40,64,64,64,64,64,64,108,64,346,64,64,136,64,64,133,64,64,64,64,64,64,64,140,64,64,64,64,64,64,64,64,64,64,64,64,64,106,64,64,131,64,64,64,64,64,108,64,64,64,64,64,64,54,64,64,64,40,64,64,64,64,64,64,64,115,64,64,64,64,64,64,64,64,64,64,64,108,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,40,64,64,64,64,64,64,108,64,64,64,64,64,335,64,332,64,347,64,64,64,64,64,64,64,64,64,64,64,64,111,64,64,64,64,64,64,106,64,64,64,64,108,138,64,64,108,64,64,64,64,64,64,38,64,64,64,40,64,64,64,64,64,64,64,111,64,105,116,64,64,64,64,64,98,64,108,111,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,40,55,64,64,64,64,64,64,64,64,64,140,64,346,64,64,344,64,64,64,129,64,64,64,64,64,64,64,64,111,64,64,111,111,64,106,64,64,64,64,64,64,64,64,64,108,64,106,64,64,64,64,64,38,64,64,64,56,64,64,64,64,64,64,64,64,105,64,64,64,64,64,64,64,64,64,64,111,64,64,64,64,64,64,64,100,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,63,47,40,64,64,64,64,64,64,64,64,64,64,64,64,64,339,64,64,64,64,344,0,64,64,64,64,64,64,64,64,64,64,64,64,64,106,64,64,64,64,64,64,64,64,64,64,64,106,64,64,64,64,64,46,64,64,37,64,64,64,64,64,108,108,64,64,64,64,64,64,64,64,64,64,64,64,64,111,64,64,64,64,64,64,64,64,64,64,64,64,64,100,64, +64,64,64,64,64,45,45,45,45,63,40,64,64,64,347,347,0,347,64,64,142,64,336,64,346,64,64,346,347,64,140,64,64,137,64,64,64,64,64,64,64,64,64,64,64,64,64,111,64,64,64,64,64,64,64,143,64,64,104,64,64,35,64,64,33,64,64,64,64,64,64,64,64,64,64,64,64,108,64,64,64,64,64,111,64,111,64,105,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,37,53,53,53,38,64,56,64,64,64,64,64,0,340,64,64,64,64,64,64,64,64,64,64,133,342,64,64,64,64,64,64,64,64,64,139,64,108,64,64,64,123,64,64,64,64,64,64,64,64,64,64,64,64,64,64,35,64,64,37,64,64,64,64,64,116,64,64,64,64,64,64,64,108,64,64,64,64,111,64,64,111,64,109,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,37,64,106,64,64,38,37,64,64,347,64,333,64,0,342,347,64,64,345,137,64,64,64,64,0,64,64,64,344,345,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,35,64,64,33,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,111,64,64,111,64,109,64,64,64,64,64,64,64,64,64,100,64,64,64, +64,64,64,33,64,126,64,109,136,53,64,64,64,64,64,64,64,64,347,0,64,140,64,64,0,64,64,0,64,64,64,64,64,64,66,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,104,64,64,64,64,64,35,64,64,44,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,98,64,64,109,64,64,64,64,64,64,64,64,64,64,64,0, +64,63,41,33,126,109,64,126,64,64,136,64,142,64,64,116,64,64,64,346,346,0,64,64,0,334,135,140,64,64,64,132,64,64,175,66,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,106,64,64,64,64,64,64,64,35,64,64,64,40,64,64,64,64,64,64,64,105,64,64,64,64,64,64,64,111,64,64,64,64,64,64,64,64,109,64,64,64,64,115,64,64,64,64,64,64,64, +64,48,53,64,106,64,64,64,64,109,64,64,64,64,64,64,64,64,64,142,64,0,64,64,0,64,64,64,64,64,64,64,64,64,66,64,64,64,64,106,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,54,36,64,50,64,64,64,64,52,64,131,64,64,64,64,64,64,64,64,64,111,64,64,64,64,64,116,64,64,105,64,64,64,109,64,105,64,64,64,64,64,64,64,64,64,0, +64,63,36,136,109,64,128,64,128,64,64,64,64,64,64,64,64,133,64,64,0,0,64,136,64,0,64,64,64,129,64,64,64,64,66,66,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,111,64,64,64,46,36,64,38,64,64,64,37,64,64,64,64,64,64,64,64,64,64,64,111,64,64,64,64,64,64,64,64,64,64,64,64,64,109,64,121,64,64,64,64,64,64,64,64,50, +64,63,36,64,126,64,64,64,104,64,64,64,64,114,64,345,64,64,64,64,0,64,64,64,65,64,133,64,335,64,64,64,64,64,66,175,64,64,64,64,64,64,64,104,64,64,64,143,64,64,64,64,111,64,64,35,64,36,64,38,64,64,37,64,64,64,64,64,64,64,64,64,64,64,111,64,64,64,64,64,64,64,64,64,64,64,64,105,64,98,64,64,64,64,64,64,64,64,64,64,42, +64,64,64,52,64,104,64,64,64,64,64,64,140,64,64,344,137,64,345,141,64,64,139,64,65,65,64,337,64,0,64,64,64,64,66,64,64,64,64,64,64,64,64,64,64,64,111,64,64,64,64,64,111,64,64,35,64,64,36,64,42,64,33,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,108,64,64,64,64,64,64,64,64,64,115,64,64,64,64,105,64,64,64,64,64,64,50, +64,64,44,64,64,64,106,109,64,64,64,64,64,64,64,64,333,64,64,64,0,64,65,64,65,65,64,64,64,64,64,343,346,64,64,64,64,64,64,64,64,108,64,64,64,106,111,64,64,64,64,64,64,39,43,64,64,64,52,35,64,37,64,64,64,64,64,64,104,64,64,64,64,64,108,64,64,64,108,64,98,64,64,64,133,64,64,64,64,64,64,64,105,64,64,64,64,64,115,64,42, +64,64,64,56,128,109,64,64,64,64,64,64,64,64,64,64,64,64,347,141,0,64,65,344,65,65,65,64,64,64,64,64,347,64,175,64,64,64,64,64,139,64,64,64,64,64,111,64,64,64,64,64,64,39,64,64,64,64,48,50,64,44,64,64,121,64,64,143,64,104,64,64,64,64,108,64,64,64,64,64,64,64,64,64,109,64,64,64,64,64,64,64,64,64,64,64,64,109,64,109,50, +64,64,44,64,64,126,64,64,64,64,64,64,64,64,137,64,64,345,347,64,64,64,65,345,65,64,65,0,131,144,116,142,64,64,64,64,64,64,64,64,64,64,64,64,64,64,111,64,64,64,111,64,54,64,64,64,63,64,52,42,64,40,64,64,64,64,64,64,64,104,64,64,64,64,64,108,64,64,64,64,109,64,64,109,64,64,64,64,64,98,105,64,64,64,64,64,64,64,64,109,42, +64,64,64,36,64,64,64,64,64,64,64,64,64,121,64,64,140,64,64,64,64,65,65,54,43,43,56,65,0,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,111,64,64,108,64,64,64,64,46,64,64,63,63,37,39,64,64,40,64,63,64,64,64,64,104,64,64,64,64,64,108,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,109,50, +64,64,64,36,64,63,64,64,64,64,64,64,64,108,64,64,64,64,64,64,64,65,65,42,65,44,64,65,347,340,64,64,64,64,64,64,98,64,64,64,64,64,64,64,64,111,64,108,64,64,64,64,54,64,64,64,63,33,39,64,64,64,52,63,63,63,63,63,64,64,64,64,64,111,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,98,64,64,64,109,42, +64,64,64,64,36,63,64,64,64,64,64,64,64,64,0,64,116,64,133,64,64,65,65,39,64,64,40,65,64,64,64,64,64,64,64,64,133,64,64,64,64,64,64,111,64,111,64,64,64,64,64,64,64,46,64,64,63,37,54,64,64,64,33,63,63,63,63,63,63,64,64,64,64,111,64,64,64,64,64,109,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,109,50, +64,64,64,64,47,47,40,64,64,64,64,64,64,64,0,64,64,64,64,64,143,65,39,64,65,64,40,65,141,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,139,64,64,64,64,64,139,64,54,64,64,64,37,64,42,64,64,33,63,63,1,63,63,63,64,64,64,64,64,64,111,64,64,64,64,109,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,139,64,109,42, +64,64,64,64,64,64,64,40,64,64,64,140,64,64,0,64,64,64,64,64,64,39,43,64,65,64,65,56,64,64,64,114,64,108,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,38,64,64,48,64,54,64,64,37,63,63,1,1,63,63,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,50, +64,64,64,64,64,64,64,56,64,64,64,64,64,64,0,64,64,64,132,64,39,65,65,64,65,65,44,121,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,34,64,64,52,64,38,64,48,64,63,63,35,1,63,63,64,64,64,64,64,64,64,64,105,64,64,64,39,43,43,43,43,40,64,39,43,40,64,64,64,64,64,109,64,64,64,64,42, +64,64,64,64,64,64,64,44,64,64,64,346,64,64,0,64,0,133,64,64,54,65,65,64,65,65,64,40,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,34,64,33,64,64,38,41,56,63,63,35,48,1,63,63,64,64,116,64,64,64,64,64,64,64,64,39,64,64,64,64,64,40,39,64,64,40,64,64,139,116,109,64,64,64,64,50, +64,64,64,64,64,64,41,56,64,64,64,64,347,347,0,335,0,332,64,347,42,65,64,64,65,65,41,56,64,64,64,137,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,131,64,111,64,64,64,111,38,37,64,64,64,53,53,64,63,35,64,36,1,63,64,64,64,64,64,64,64,116,64,64,64,39,64,64,64,64,64,64,43,64,64,64,43,40,64,64,64,109,64,64,64,64,42, +64,64,64,64,64,64,37,53,64,64,64,64,64,64,0,64,0,64,64,344,39,65,65,65,65,65,37,53,64,64,64,64,64,64,64,64,98,64,210,64,64,64,64,64,64,64,64,111,64,64,111,64,64,111,64,49,64,64,64,64,64,64,63,50,41,64,36,63,63,143,64,64,64,133,64,64,64,64,64,39,64,64,64,64,64,64,64,64,64,64,64,64,40,64,64,64,64,98,64,64,50, +64,64,64,64,64,44,64,140,64,64,64,347,64,64,0,64,64,0,339,39,0,65,65,65,65,44,64,64,64,64,344,345,64,64,64,64,64,64,64,64,64,64,64,64,64,111,111,111,111,64,64,64,64,111,64,64,64,64,64,64,64,63,63,49,42,64,36,63,64,64,64,64,64,64,105,64,64,64,39,64,64,64,64,64,64,64,64,64,64,64,64,64,40,64,64,64,64,64,64,64,42, +64,64,64,64,64,64,40,64,64,64,64,129,347,64,0,142,347,0,64,54,41,65,65,65,65,65,36,64,64,64,64,64,345,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,106,64,111,64,64,64,64,64,64,64,104,63,64,39,64,64,36,63,64,64,64,64,64,64,64,64,64,39,64,64,64,64,64,64,64,64,64,64,64,64,64,64,56,64,105,64,64,64,64,50, +64,64,64,64,64,64,52,346,64,64,136,64,340,133,0,64,64,346,64,53,38,65,65,65,65,65,36,64,64,64,64,64,347,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,111,64,64,64,64,64,64,64,63,63,39,64,64,64,56,64,64,64,64,64,64,64,64,64,39,64,64,64,64,64,64,64,64,64,64,64,64,64,64,44,64,64,64,64,64,64,64,42, +64,64,64,45,64,64,44,64,64,64,333,335,64,332,0,347,64,345,64,64,64,42,65,65,65,64,65,36,64,140,64,64,64,64,64,64,64,64,64,122,64,64,64,64,64,64,64,64,64,64,64,64,105,64,64,64,64,108,64,64,64,64,63,39,64,64,64,48,64,64,64,64,64,64,64,64,64,39,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,56,64,98,64,64,139,64,50, +64,64,33,38,45,41,56,64,64,64,64,64,346,64,0,344,64,64,137,0,35,65,65,65,64,64,41,56,116,64,64,64,64,64,64,64,107,64,64,64,64,64,64,64,64,64,64,64,64,64,64,104,64,64,64,64,64,108,64,131,64,63,54,64,64,64,64,56,64,64,64,64,64,64,64,64,54,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,33,64,64,98,64,64,64,64,42, +64,64,33,64,53,53,53,64,64,64,64,64,64,345,0,346,64,64,64,64,35,64,65,65,64,64,37,53,64,64,64,64,138,347,64,64,111,121,105,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,108,64,64,64,63,38,64,64,64,37,64,64,64,64,64,64,64,64,64,42,64,64,64,64,64,64,64,64,64,64,64,64,64,64,37,64,64,64,64,64,64,64,50, +64,33,64,64,64,64,64,129,347,64,64,142,64,336,142,346,345,64,64,54,64,65,65,65,64,33,65,345,64,64,64,64,64,64,64,64,111,121,105,98,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,108,64,64,64,63,38,63,64,37,63,64,64,64,64,64,64,64,64,54,64,64,64,64,64,64,64,64,64,64,64,64,64,64,33,64,64,64,64,64,64,64,64,42, +64,37,64,59,64,64,64,64,340,64,64,64,133,64,0,64,64,64,136,133,38,64,64,64,64,37,65,0,64,343,346,64,64,64,64,64,111,64,64,105,64,133,64,64,64,64,64,64,64,64,64,121,64,64,64,64,108,108,64,64,64,64,63,64,38,63,37,64,63,64,64,64,64,64,64,64,64,38,64,64,64,64,64,64,64,64,64,64,64,64,64,33,64,64,64,64,64,64,64,64,50, +44,64,64,60,64,64,333,64,64,342,64,64,64,345,64,64,347,65,64,64,34,64,64,335,33,64,64,64,64,64,347,64,345,64,64,64,111,64,64,111,64,107,64,64,64,64,64,64,64,64,64,64,64,64,64,108,64,64,64,64,64,64,63,64,38,37,64,63,64,64,64,64,64,64,109,64,64,38,64,64,64,64,64,64,45,64,64,64,41,64,37,64,64,64,64,64,64,64,64,64,42, +64,36,64,64,64,64,64,64,64,64,64,137,137,64,141,64,64,64,65,64,64,38,64,64,33,64,64,64,64,64,64,64,64,64,64,64,64,111,64,111,64,64,107,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,108,64,63,64,63,53,64,63,64,64,64,139,64,64,109,109,64,64,46,64,64,64,64,64,37,38,64,64,33,34,33,64,64,64,64,64,39,47,36,64,50, +64,36,122,64,87,64,64,64,64,64,64,346,0,64,64,342,334,65,64,64,64,34,64,44,64,64,64,64,64,64,64,64,64,64,64,64,64,111,111,111,64,105,64,64,64,64,64,64,64,64,64,64,143,111,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,54,45,45,41,41,41,37,64,38,64,37,64,53,64,98,109,64,64,39,64,64,36,64,64, +64,64,52,64,64,64,64,64,64,64,142,64,64,64,64,114,64,64,64,64,64,64,38,64,64,64,64,64,64,114,64,108,64,64,64,64,102,64,64,111,64,105,105,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,107,64,64,64,64,64,64,64,64,64,53,53,53,53,53,53,64,64,34,33,64,64,64,64,64,64,64,39,64,64,64,36,50, +64,37,64,64,64,64,64,64,133,116,64,64,345,114,114,0,64,64,64,64,64,64,38,41,56,64,142,64,114,64,64,108,64,64,64,64,64,64,105,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,117,64,64,64,64,64,64,64,64,64,64,49,64,64,64,64,64,64,64,39,64,64,64,64,36,42, +64,44,64,64,64,64,64,64,64,64,64,114,64,64,64,64,142,133,64,335,64,64,64,53,53,64,64,64,64,64,129,64,64,64,64,64,64,64,105,64,111,64,107,111,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,109,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,39,64,64,64,64,64,47, +64,40,64,64,64,64,64,137,64,64,114,64,64,64,64,64,64,347,64,64,64,64,64,347,340,64,64,64,64,64,106,64,64,64,64,64,64,64,105,64,111,64,107,111,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,111,64,64,64,64,64,64,64,64,64,109,109,64,64,64,64,64,64,64,64,107,64,64,64,64,64,64,64,64,64,64,64,104,64,54,64,64,64,64,64,64,64, +64,64,40,64,64,64,64,333,64,64,64,342,64,133,64,142,64,64,64,64,64,64,334,64,64,64,64,64,64,106,110,64,64,64,64,64,64,64,105,64,111,64,107,111,64,64,64,64,64,64,64,64,64,64,64,64,64,64,104,139,64,64,64,64,64,64,64,64,64,109,109,64,64,106,116,64,64,64,64,107,64,64,64,64,64,64,64,64,64,64,64,64,64,64,42,64,64,64,64,64,64, +64,64,40,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,106,110,64,64,64,64,64,64,64,64,105,64,111,64,121,111,64,102,64,64,64,64,64,64,64,64,64,64,111,111,64,64,64,64,64,64,64,64,64,64,64,109,64,64,64,64,107,64,64,64,64,107,64,64,64,140,64,64,64,109,109,107,64,64,64,50,41,64,64,64,64,64,64, +64,41,41,56,64,64,64,64,345,347,64,64,64,64,64,64,64,337,64,131,144,64,142,64,64,64,64,110,64,110,64,64,64,64,64,64,64,105,111,64,64,64,64,111,111,64,102,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,116,64,109,117,64,64,64,107,64,106,64,64,64,64,64,109,64,64,106,64,64,64,107,64,64,116,64,53,38,64,64,64,64,64, +37,53,53,64,64,64,64,64,64,64,64,64,142,64,64,64,64,64,64,64,64,64,64,64,64,64,64,110,64,64,64,64,64,64,64,111,64,64,111,64,64,64,111,64,111,107,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,131,64,64,116,64,109,64,64,64,64,64,106,64,64,64,64,64,109,64,64,64,64,106,106,107,64,64,64,64,64,64,34,64,64,64,64,64, +44,64,64,64,64,64,64,64,64,64,64,134,64,347,121,64,116,64,64,347,340,64,64,64,64,64,64,64,64,64,64,64,64,64,64,111,64,64,111,64,64,102,98,64,111,64,105,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,109,64,64,64,64,64,109,106,64,64,64,64,109,64,64,64,64,64,64,64,64,64,64,64,64,64,64,34,64,64,64,64, +36,64,64,64,64,64,64,64,64,133,64,64,64,64,64,64,64,64,334,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,111,64,64,98,64,64,102,98,64,64,64,105,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,109,106,64,64,64,109,64,64,64,64,64,64,104,64,106,116,64,64,114,64,64,64,64,64,64,64,64,38,64,64,64,64, +64,36,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,111,64,111,64,64,102,98,64,64,64,121,105,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,106,64,64,64,109,64,64,64,64,64,64,109,64,106,109,64,64,64,64,64,64,107,106,64,64,64,64,38,64,64,64, +41,56,64,64,64,64,64,64,110,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,142,64,64,64,108,64,64,64,64,64,64,111,64,111,64,102,64,98,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,114,64,64,106,64,64,64,64,109,64,114,64,64,64,64,64,106,109,64,64,64,64,64,64,107,106,64,64,64,64,34,64,64,64, +44,53,64,64,141,142,64,144,64,110,64,64,64,64,64,64,64,64,64,64,64,64,116,129,64,64,64,64,64,64,64,64,64,64,64,121,111,64,64,121,102,64,111,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,104,64,64,64,64,64,64,107,64,64,109,64,64,64,64,109,64,64,64,64,64,64,64,106,64,109,64,64,64,109,109,64,64,106,64,64,109,64,38,64,64, +36,64,64,64,64,64,64,64,110,64,64,64,64,64,64,64,64,64,64,64,108,64,115,64,64,64,64,64,64,64,64,64,64,64,64,64,111,107,64,64,102,64,111,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,109,64,64,64,104,64,109,64,64,64,64,64,64,64,64,109,64,64,64,64,64,64,64,106,64,64,109,64,38,64,64, +64,36,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,102,64,64,64,64,64,64,64,64,107,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,104,64,109,64,64,64,64,109,64,107,64,64,64,64,64,64,64,106,64,64,64,64,107,64,106,64,107,64,64,64,38,64, +64,36,64,64,64,64,64,64,64,64,64,64,134,64,64,64,64,129,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,111,111,64,64,64,64,64,39,36,64,64,64,121,102,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,109,64,64,64,64,109,64,107,64,109,64,64,64,64,106,90,91,64,64,64,64,64,64,116,64,64,64,64,38,64, +64,64,36,55,64,64,64,64,64,64,64,64,64,108,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,107,64,111,64,64,64,64,64,64,39,64,36,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,107,64,109,109,64,107,64,109,64,64,109,64,107,93,64,92,64,140,64,109,64,64,64,64,64,64,64,42, +64,64,47,36,64,64,64,64,64,64,64,64,64,106,64,142,64,64,64,64,64,64,64,64,64,64,64,64,110,64,64,64,64,64,64,107,111,64,64,64,64,64,64,39,64,64,36,64,64,64,136,105,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,109,64,107,64,109,109,109,64,64,64,64,64,64,64,64,109,64,104,64,64,64,64,64,39,64, +64,64,45,64,52,64,64,64,64,64,64,64,64,64,64,64,64,64,64,114,64,64,64,64,64,114,64,138,110,64,64,64,64,64,105,107,98,135,64,64,64,121,64,39,64,64,64,36,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,123,64,64,64,64,64,64,109,107,64,64,109,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,39,64, +63,37,38,44,64,64,64,64,64,64,64,64,64,110,64,64,64,64,64,64,64,64,64,64,64,64,64,110,64,64,64,64,64,105,64,98,111,102,111,111,64,64,54,64,64,64,64,36,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,107,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,39,64,64, +64,33,64,38,52,64,106,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,134,64,64,64,64,64,107,105,64,64,64,64,111,111,64,64,64,42,64,64,64,64,36,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,89,92,93,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,109,64,39,64,64, +37,63,64,53,64,64,64,64,64,64,64,64,64,64,64,64,64,64,106,64,64,64,64,64,64,134,64,64,64,64,64,64,64,64,64,64,64,64,64,111,64,64,50,64,64,64,64,64,40,64,64,64,64,64,64,107,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,109,64,107,64,116,89,64,92,64,64,64,64,64,64,64,107,64,64,64,64,64,64,64,64,109,54,41,64,63, +44,63,64,64,64,64,64,64,64,64,64,64,116,64,64,64,64,64,64,106,108,64,64,64,134,64,64,64,64,64,64,64,64,64,64,64,64,64,64,111,107,64,64,38,64,64,64,64,64,40,64,64,64,102,121,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,109,64,64,64,64,89,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,109,53,38,63, +36,64,64,64,64,64,64,134,64,64,138,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,107,111,64,64,38,64,64,64,64,64,40,64,64,64,111,64,64,64,64,64,64,64,64,64,64,64,64,109,109,64,64,64,104,109,117,64,64,93,64,106,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,38,63, +64,36,64,116,64,64,64,64,132,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,111,64,121,64,64,111,98,64,64,38,64,64,64,64,64,40,64,64,64,111,64,64,64,64,64,64,64,64,64,64,64,64,64,109,107,64,64,64,64,64,64,64,64,64,64,64,64,64,104,64,64,64,64,106,64,64,64,64,64,64,64,64,64,64,64,46, +64,36,64,64,64,64,64,64,64,64,64,64,64,106,64,64,64,114,64,64,64,64,64,64,64,64,64,64,64,64,64,64,121,64,111,64,111,64,105,64,98,64,64,64,38,64,64,64,64,64,40,64,64,64,64,111,64,64,64,64,64,64,64,64,64,64,64,64,107,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,39,63, +64,64,36,64,64,64,64,64,64,64,64,64,64,64,64,64,64,142,64,64,64,64,138,64,64,106,64,64,64,64,64,64,64,64,64,64,111,64,105,64,64,64,64,64,64,42,64,64,64,64,64,40,64,64,64,111,64,64,64,64,64,64,64,64,64,64,64,64,64,109,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,221,64,64,64,64,39,64, +64,64,56,64,138,64,64,64,64,64,64,123,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,111,64,64,111,64,111,121,64,64,64,64,35,64,64,64,64,64,64,40,64,64,64,64,111,64,105,64,64,64,64,64,64,64,64,64,64,64,109,64,64,64,64,106,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,54,41,64, +64,64,44,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,110,64,64,64,64,64,64,64,64,64,64,111,64,105,64,64,111,105,64,64,64,64,35,64,64,64,64,64,64,64,40,64,64,64,64,111,105,64,64,64,64,64,64,64,64,117,64,64,114,64,64,64,64,64,64,64,64,64,64,64,64,109,64,221,64,64,64,64,64,64,64,64,64,64,64,64,64,53,42, +64,64,56,64,64,64,64,64,114,64,64,64,64,64,64,110,110,64,64,106,110,110,64,64,64,64,64,64,64,64,64,64,64,111,121,105,64,107,111,64,64,64,64,35,64,64,64,64,64,64,64,64,56,64,105,64,64,111,121,64,64,64,64,64,64,64,64,106,64,64,64,64,64,64,64,64,64,114,64,64,64,64,64,109,64,64,82,64,64,64,209,64,109,64,64,64,64,64,64,54,64, +64,64,37,64,64,64,64,64,64,64,64,64,64,64,64,107,64,110,64,106,64,64,64,64,110,106,64,64,64,64,64,64,64,64,105,64,64,64,64,64,64,64,64,35,64,64,64,64,64,64,64,64,48,64,105,64,64,98,64,105,64,64,64,64,64,64,64,64,64,64,64,106,64,64,64,64,64,64,64,64,64,64,64,109,64,64,64,64,64,64,64,64,109,64,64,64,64,64,64,64,42, +64,33,64,64,64,64,64,64,64,64,64,64,64,64,107,64,64,110,64,64,64,64,64,64,110,64,64,64,64,64,64,105,64,111,105,64,64,64,107,64,64,64,35,64,64,64,64,64,64,64,64,64,56,64,105,64,64,64,64,105,64,64,64,64,64,64,64,64,64,64,64,106,64,64,64,64,64,64,64,64,221,64,64,109,64,64,64,64,64,64,64,64,109,106,64,106,64,64,64,54,64, +64,37,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,105,105,105,107,64,111,111,64,102,64,64,50,64,64,64,64,64,64,64,64,64,48,64,105,111,64,64,64,64,107,64,64,64,64,64,64,64,64,64,64,106,64,64,114,64,64,109,64,64,64,64,64,64,109,64,64,106,64,64,64,84,64,109,106,64,107,64,64,64,42, +44,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,102,64,64,105,107,64,64,111,64,102,64,64,34,64,64,64,64,64,64,64,64,64,56,64,105,102,111,111,64,107,64,64,64,64,64,64,64,64,64,64,64,109,64,64,64,64,109,64,64,83,64,64,64,64,64,64,64,64,107,64,64,64,64,64,64,64,107,64,209,54,64, +64,36,64,64,64,64,64,64,64,64,64,64,64,138,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,105,64,111,107,111,64,64,64,64,64,64,34,64,64,64,64,64,64,64,64,48,64,105,64,64,64,111,111,64,64,64,64,64,64,64,64,64,64,64,109,64,64,64,64,109,64,64,64,83,64,64,64,64,64,64,64,107,64,64,64,64,64,64,64,107,64,64,64,42, +64,36,64,64,64,64,138,64,64,64,142,64,64,64,64,64,64,64,113,64,64,64,64,64,64,64,64,64,64,64,64,64,107,111,64,64,64,64,64,64,64,64,64,34,64,64,64,64,64,64,64,64,56,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,109,64,64,109,64,107,64,64,64,64,64,64,64,106,64,64,107,64,64,64,64,64,64,64,64,64,64,54,64, +64,64,36,64,134,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,99,99,64,64,64,64,111,64,102,111,111,121,64,105,64,64,64,34,41,41,64,64,64,64,64,48,64,64,64,64,135,107,64,111,64,64,64,64,64,64,64,64,64,64,64,109,64,64,64,64,64,64,64,64,64,64,64,64,106,64,64,64,104,64,64,64,64,64,64,64,64,64,64,42, +64,64,36,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,99,99,64,64,64,64,64,64,109,64,64,64,64,102,64,111,64,64,105,64,64,64,53,53,38,64,64,64,64,64,56,64,64,64,64,107,64,64,111,64,64,64,64,64,64,64,64,64,107,64,109,64,64,64,64,106,64,107,64,64,64,64,64,106,64,64,64,64,64,64,64,64,64,64,64,64,64,54,64, +64,64,64,56,64,103,109,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,99,99,64,64,64,64,64,64,109,64,64,98,111,102,111,111,64,64,64,64,64,64,64,64,64,38,64,64,64,64,37,64,98,64,111,64,107,121,111,64,64,64,64,64,64,64,64,64,64,107,109,64,64,64,64,64,106,107,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,122,42, +64,64,44,116,64,103,109,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,99,99,64,64,64,64,102,64,64,111,64,102,64,64,64,98,64,64,64,64,127,64,42,64,64,64,37,64,64,121,64,111,64,64,64,111,64,64,64,64,64,64,64,64,64,64,64,64,109,64,104,64,64,109,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,54,64, +64,64,64,56,64,103,64,64,64,64,64,64,64,64,113,64,64,64,64,64,64,64,99,64,99,64,64,64,64,64,64,102,64,64,111,64,102,64,64,64,98,64,105,64,64,64,64,39,64,64,64,37,64,64,64,64,105,111,64,64,111,105,121,64,64,64,64,64,64,64,64,64,64,109,64,64,64,104,109,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,42, +64,64,33,64,64,64,64,64,64,64,64,64,64,64,64,64,129,64,109,64,64,64,64,99,99,64,64,64,64,64,64,102,121,64,64,111,102,64,64,64,98,136,64,64,64,64,39,64,64,64,44,64,64,64,64,105,111,64,64,111,64,105,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,109,64,64,64,64,64,64,64,64,64,64,88,64,64,64,64,64,209,64,109,64,54,45, +64,64,37,64,64,64,117,64,64,64,64,64,64,64,64,64,64,64,109,64,64,99,64,64,64,64,64,64,64,64,64,109,102,64,64,111,111,64,64,64,98,64,64,64,64,64,39,64,64,64,64,40,64,64,64,64,64,64,64,111,105,64,64,64,64,64,64,64,64,64,64,64,64,64,117,64,64,64,109,64,64,64,64,64,64,64,64,209,64,64,64,221,64,64,64,64,64,109,64,64,53, +64,33,64,64,64,64,109,64,64,64,64,64,64,64,64,64,64,64,64,64,64,99,64,64,64,64,99,99,64,64,64,109,102,64,64,64,64,107,111,98,64,64,107,64,64,54,64,64,64,64,64,40,64,64,64,64,64,98,64,111,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,109,64,64,221,64,64,64,64,64,64,64,64,64,64,64,64,64,64,109,64,64,64, +64,37,64,64,64,64,64,64,64,209,64,64,64,64,64,64,64,64,64,64,64,99,64,64,64,64,64,64,64,64,64,109,102,64,64,64,64,64,107,98,64,64,107,64,64,64,38,64,64,64,64,64,40,64,64,64,64,64,64,111,64,64,64,64,64,64,64,64,64,64,64,64,64,116,64,64,64,64,64,109,64,64,64,64,64,64,64,64,64,64,64,64,64,104,64,64,64,64,64,64,64, +44,64,64,64,64,64,64,64,64,64,64,64,64,64,109,64,134,64,64,64,99,64,64,64,64,64,64,64,64,64,64,109,64,64,64,64,64,64,111,98,64,64,102,64,64,64,38,64,64,64,64,41,40,64,64,64,64,64,105,111,64,64,64,64,64,64,64,64,64,64,64,64,116,64,64,64,64,64,64,109,64,85,64,64,64,64,64,64,64,64,64,64,64,109,64,64,64,87,64,64,64, +64,40,64,64,64,64,64,64,64,64,64,134,64,64,107,64,64,64,64,64,64,64,64,64,64,64,64,99,99,64,64,109,64,64,64,64,64,64,64,111,64,64,64,102,121,64,64,38,64,64,64,37,38,40,64,64,64,64,64,111,64,64,64,64,64,55,64,64,64,64,64,64,64,107,64,64,64,64,64,109,64,64,85,64,64,64,64,64,64,64,64,64,64,109,64,64,64,64,64,64,64, +64,56,64,64,64,64,64,64,64,64,64,64,64,64,109,116,64,64,64,64,64,64,64,64,64,64,64,99,64,64,64,109,64,107,64,111,121,64,64,111,64,64,64,121,64,64,63,38,64,64,37,64,38,56,64,64,111,64,111,64,64,64,64,39,43,56,64,64,64,64,64,64,64,64,64,106,64,64,64,109,64,64,64,64,109,64,64,64,104,64,64,64,64,64,109,64,64,64,64,64,64, +64,37,64,221,64,64,64,64,64,64,64,64,64,64,109,64,64,64,64,64,64,64,99,64,64,64,64,99,64,64,64,64,109,105,64,111,121,105,64,111,105,64,64,111,64,64,64,63,38,41,37,64,64,53,64,64,102,111,111,64,64,64,64,39,64,44,64,64,64,64,64,64,64,64,64,106,64,64,64,64,106,64,64,64,64,106,64,64,64,109,64,64,64,64,109,64,106,64,64,64,100, +44,64,64,64,64,64,64,64,64,64,64,64,64,64,64,109,64,64,64,64,99,64,64,64,64,64,64,64,64,64,64,64,109,105,64,111,121,105,64,111,105,64,64,111,64,64,64,64,53,53,64,58,64,64,64,64,102,64,111,64,64,39,43,64,64,56,64,64,64,64,64,64,64,64,64,64,64,64,64,64,106,64,64,64,64,106,107,64,64,64,64,64,64,64,109,106,64,64,64,64,64, +64,56,64,64,64,64,64,64,64,64,64,64,64,64,64,109,64,64,64,64,64,64,64,64,64,64,64,64,99,64,64,64,109,105,64,111,64,105,64,102,102,111,111,64,98,64,64,64,64,64,82,57,64,64,64,64,111,111,111,64,64,39,64,64,64,37,64,64,64,64,64,64,0,0,0,0,0,104,64,64,64,109,64,64,64,106,107,64,64,64,64,64,64,64,107,64,64,64,64,64,64, +44,64,64,64,64,64,64,64,64,64,117,64,64,64,64,109,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,102,64,111,64,64,64,64,111,64,64,111,98,111,107,64,59,64,64,64,64,64,64,107,107,64,111,64,54,64,64,64,37,64,64,64,64,64,64,64,0,0,0,87,0,0,64,64,64,109,107,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,100,64, +64,40,64,64,64,64,64,64,64,64,109,64,64,64,64,109,103,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,102,64,111,64,64,64,111,111,64,64,64,98,111,111,107,64,60,64,64,87,64,64,111,107,64,64,64,64,46,64,64,48,55,55,64,64,64,64,64,0,0,0,0,0,0,64,64,64,64,109,64,64,64,64,64,64,64,64,106,64,109,64,64,64,64,64,64,64, +1,56,64,109,64,64,64,64,64,64,109,64,64,64,64,109,64,64,64,64,64,64,64,64,64,64,64,64,99,64,64,64,64,64,64,111,64,64,64,64,111,111,64,64,64,64,111,64,64,64,64,64,64,58,111,64,64,64,64,136,54,64,64,64,43,47,56,64,64,64,64,64,0,0,0,0,0,0,64,64,64,64,87,64,64,64,64,64,64,64,109,109,109,64,64,64,64,64,169,64,64, +1,37,64,64,64,64,64,64,64,64,64,64,138,64,64,64,64,64,109,64,64,99,174,64,64,64,64,64,64,64,64,102,64,64,64,64,111,64,64,64,64,111,64,64,64,64,102,59,102,64,64,64,64,57,111,64,64,64,64,64,64,38,64,64,64,64,48,64,64,64,64,64,0,0,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,170,64, +37,64,122,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,99,64,173,64,64,64,64,64,64,64,64,64,64,64,64,64,64,111,64,64,64,107,111,64,64,107,64,102,60,64,64,107,64,64,111,64,64,64,64,64,64,64,42,64,64,64,64,56,64,64,64,64,64,0,0,0,0,0,0,64,64,64,64,64,64,64,175,64,175,64,64,87,64,64,64,64,64,64,64,64,171,64, +44,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,106,64,64,64,172,64,64,64,64,64,64,99,64,64,64,64,64,133,64,111,98,64,64,64,107,64,64,64,102,64,64,64,64,64,64,64,121,64,64,64,64,64,107,64,35,64,64,64,64,37,64,64,64,64,64,0,0,0,0,0,0,64,174,64,64,64,64,64,175,174,64,175,64,64,64,64,64,64,64,64,64,64,64,64, +36,64,64,64,64,113,64,64,224,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,99,64,64,64,64,64,64,64,64,111,107,64,64,64,111,64,64,64,102,64,105,64,122,64,59,111,64,64,98,121,64,64,107,35,64,64,64,64,37,64,64,64,64,64,64,0,0,0,0,0,0,173,64,64,64,64,64,175,173,64,175,64,64,64,64,64,64,64,64,64,169,64,64,64, +63,36,64,64,64,64,64,64,64,64,64,64,64,35,36,64,64,64,64,64,99,64,64,64,64,99,64,64,64,64,64,64,64,64,64,64,121,107,64,64,64,64,111,64,64,102,111,105,64,64,64,64,60,64,64,98,98,64,102,64,54,64,64,64,64,48,64,64,64,64,64,64,0,0,0,0,100,0,172,64,64,64,64,64,175,172,64,64,64,64,64,175,176,64,64,64,64,64,170,64,64, +64,56,64,64,64,64,109,64,64,64,64,64,35,64,36,64,113,106,64,64,64,64,64,64,64,64,64,99,64,64,64,64,64,64,64,121,111,111,111,111,111,111,111,111,111,64,64,133,64,64,64,64,64,64,64,64,64,102,64,64,42,64,64,64,64,36,64,121,64,64,64,64,0,0,100,0,100,0,64,64,64,64,174,175,64,64,64,64,64,174,64,175,175,64,64,64,100,64,171,64,64, +64,44,64,64,64,64,64,109,64,64,64,64,35,64,64,36,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,121,111,64,64,64,64,64,64,64,64,64,111,105,121,64,64,64,64,64,64,64,64,64,64,64,64,64,64,54,64,64,64,64,64,36,64,136,64,64,64,0,0,0,0,100,0,64,64,64,64,173,175,64,64,64,64,64,173,64,175,64,175,64,169,64,64,64,64,64, +64,36,64,64,64,64,64,64,64,64,64,35,64,64,64,52,64,64,64,64,64,64,64,64,64,64,99,64,64,64,107,64,64,105,64,64,64,64,64,64,64,64,111,102,64,121,64,64,58,64,59,64,64,64,64,64,64,64,64,64,42,64,64,64,64,64,36,0,0,0,0,64,0,100,0,0,0,0,64,64,64,172,175,64,64,64,64,64,172,64,64,64,64,175,64,170,64,64,64,64,64, +64,1,56,64,64,64,64,64,64,64,64,35,64,64,64,48,64,64,64,64,64,64,64,64,99,64,99,64,64,64,64,64,64,105,64,107,64,64,64,64,64,64,111,102,121,64,64,64,57,64,64,60,64,105,64,64,64,64,64,64,54,64,64,64,64,64,64,56,0,0,0,64,64,64,64,64,64,64,64,64,64,175,175,64,64,64,64,64,64,64,64,64,64,64,175,64,171,100,64,64,64, +1,44,64,64,212,64,64,64,64,64,35,64,64,64,64,40,64,64,64,64,64,64,99,99,64,64,64,64,64,64,64,109,111,105,111,111,64,64,64,64,111,111,64,102,121,64,64,64,64,64,64,64,105,107,107,64,64,64,64,64,34,64,64,64,64,41,48,64,0,0,0,64,64,64,64,64,64,64,64,64,174,175,64,100,64,64,64,174,64,64,100,64,169,64,175,64,64,64,64,64,64, +1,1,56,64,64,64,64,64,64,64,35,64,64,64,64,64,56,64,64,64,64,64,64,64,64,99,64,64,64,64,64,109,64,105,64,64,111,105,64,64,64,105,64,102,64,64,64,64,64,121,64,64,64,64,64,102,64,64,111,121,64,34,64,45,64,33,38,56,0,0,0,100,64,64,64,100,100,64,64,64,173,175,64,64,64,64,64,173,64,64,64,64,64,170,64,175,64,64,64,64,64, +1,37,64,64,64,64,117,64,39,47,64,64,64,64,64,48,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,105,64,64,64,105,64,64,64,105,105,102,64,64,64,64,64,64,64,64,64,64,64,102,64,64,64,64,64,64,34,37,38,37,64,53,64,0,0,0,64,64,64,64,64,64,64,64,172,64,64,64,64,100,64,172,64,64,64,64,64,64,171,64,175,175,64,64,64,64, +1,37,64,64,64,64,64,64,39,64,64,64,64,64,64,64,36,64,64,212,64,64,64,64,63,64,64,64,64,102,64,64,102,64,64,105,105,64,64,64,64,64,64,64,64,64,64,64,64,98,64,64,64,64,64,64,64,64,64,64,64,64,49,64,49,64,64,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,64,64,100,64,64,64,64,64,64,100,64,64,64,64,175,175,64,64,64, +37,64,138,64,64,64,64,39,64,64,64,64,64,64,64,64,36,64,64,64,64,64,64,64,64,102,109,109,109,64,107,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,121,64,64,64,64,64,64,64,64,64,64,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,100,64,64,64,64,169,64,64,64,64,64,64, +44,1,64,114,64,64,64,39,64,64,64,64,64,64,64,64,64,36,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,51,64,64,64,64,107,64,64,64,64,64,64,64,64,64,64,64,64,64,64,121,121,0,0,0,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,170,64,64,64,64,64, +40,1,64,64,134,64,39,64,64,64,64,64,64,64,64,64,64,36,64,64,64,64,64,39,40,64,102,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,51,35,43,52,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,171,64,64,64,64,64, +64,40,64,64,64,64,39,64,64,64,64,64,64,64,64,64,64,64,36,64,64,64,64,39,63,52,64,102,64,64,64,64,64,64,64,64,64,64,64,51,64,64,64,64,35,43,64,44,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,0,0,0,0,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,40,1,64,1,35,64,64,64,64,64,64,64,64,64,64,64,64,36,64,64,64,39,64,48,64,64,64,64,64,64,64,64,64,64,64,64,64,35,36,64,64,64,35,64,64,64,36,64,64,51,51,64,64,64,64,64,64,64,64,64,39,43,43,40,64,64,0,0,100,100,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,40,1,1,35,64,64,64,64,64,64,64,64,64,64,64,64,64,36,64,64,39,64,64,56,64,64,64,64,64,64,64,64,64,64,64,64,35,64,36,64,64,35,64,64,64,64,36,64,35,47,40,64,64,64,64,64,35,56,64,39,64,64,64,40,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,40,35,47,64,64,64,64,64,64,64,64,64,64,64,64,64,63,36,55,39,64,64,37,64,64,64,64,64,64,64,64,64,64,64,64,35,64,64,36,64,35,64,64,64,64,64,36,35,64,64,40,64,64,64,64,35,44,64,39,64,64,64,64,56,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,43,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,43,43,64,64,37,64,64,64,64,64,64,64,64,64,64,64,64,35,64,64,64,36,35,64,64,64,64,64,64,43,64,64,64,40,64,64,64,35,64,40,39,64,64,64,64,48,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,44,55,55,55,55,55,55,55,55,55,55,55,55,35,64,64,64,64,43,64,64,64,64,64,64,64,64,64,64,64,43,43,40,35,64,64,43,64,64,64,64,64,40,64,64,100,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64, +64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,43,43,47,43,43,43,43,43,43,43,43,43,43,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,43,64,64,64,64,64,64,64,64,64,43,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/V3/Content/Menu/Titel.png b/V3/Content/Menu/Titel.png new file mode 100644 index 0000000..d22295f Binary files /dev/null and b/V3/Content/Menu/Titel.png differ diff --git a/V3/Content/Menu/arrow_white.png b/V3/Content/Menu/arrow_white.png new file mode 100644 index 0000000..8e4d2e2 Binary files /dev/null and b/V3/Content/Menu/arrow_white.png differ diff --git a/V3/Content/Menu/mainscreen.jpg b/V3/Content/Menu/mainscreen.jpg new file mode 100644 index 0000000..654eaa6 Binary files /dev/null and b/V3/Content/Menu/mainscreen.jpg differ diff --git a/V3/Content/Sounds/Afraid_to_Go.mp3 b/V3/Content/Sounds/Afraid_to_Go.mp3 new file mode 100644 index 0000000..beb828b Binary files /dev/null and b/V3/Content/Sounds/Afraid_to_Go.mp3 differ diff --git a/V3/Content/Sounds/Knight.wav b/V3/Content/Sounds/Knight.wav new file mode 100644 index 0000000..cb088af Binary files /dev/null and b/V3/Content/Sounds/Knight.wav differ diff --git a/V3/Content/Sounds/Kosta_T_-_06.mp3 b/V3/Content/Sounds/Kosta_T_-_06.mp3 new file mode 100644 index 0000000..3d4ac62 Binary files /dev/null and b/V3/Content/Sounds/Kosta_T_-_06.mp3 differ diff --git a/V3/Content/Sounds/Monster_Gigante-Doberman-1334685792.wav b/V3/Content/Sounds/Monster_Gigante-Doberman-1334685792.wav new file mode 100644 index 0000000..4bfe6a4 Binary files /dev/null and b/V3/Content/Sounds/Monster_Gigante-Doberman-1334685792.wav differ diff --git a/V3/Content/Sounds/Mummy_Zombie-SoundBible.wav b/V3/Content/Sounds/Mummy_Zombie-SoundBible.wav new file mode 100644 index 0000000..cd3630c Binary files /dev/null and b/V3/Content/Sounds/Mummy_Zombie-SoundBible.wav differ diff --git a/V3/Content/Sounds/SkeletonHorse.wav b/V3/Content/Sounds/SkeletonHorse.wav new file mode 100644 index 0000000..7804c61 Binary files /dev/null and b/V3/Content/Sounds/SkeletonHorse.wav differ diff --git a/V3/Content/Sounds/explode.wav b/V3/Content/Sounds/explode.wav new file mode 100644 index 0000000..8c1d089 Binary files /dev/null and b/V3/Content/Sounds/explode.wav differ diff --git a/V3/Content/Sounds/explodemini.wav b/V3/Content/Sounds/explodemini.wav new file mode 100644 index 0000000..bcad45b Binary files /dev/null and b/V3/Content/Sounds/explodemini.wav differ diff --git a/V3/Content/Sounds/explosion1.ogg b/V3/Content/Sounds/explosion1.ogg new file mode 100644 index 0000000..64c1ab6 Binary files /dev/null and b/V3/Content/Sounds/explosion1.ogg differ diff --git a/V3/Content/Sounds/horse.wav b/V3/Content/Sounds/horse.wav new file mode 100644 index 0000000..5715ad1 Binary files /dev/null and b/V3/Content/Sounds/horse.wav differ diff --git a/V3/Content/Sounds/impactsplat01.ogg b/V3/Content/Sounds/impactsplat01.ogg new file mode 100644 index 0000000..731cf83 Binary files /dev/null and b/V3/Content/Sounds/impactsplat01.ogg differ diff --git a/V3/Content/Sounds/punch.wav b/V3/Content/Sounds/punch.wav new file mode 100644 index 0000000..395bb5c Binary files /dev/null and b/V3/Content/Sounds/punch.wav differ diff --git a/V3/Content/Sounds/walking.wav b/V3/Content/Sounds/walking.wav new file mode 100644 index 0000000..894dff4 Binary files /dev/null and b/V3/Content/Sounds/walking.wav differ diff --git a/V3/Content/Sounds/zonk2.wav b/V3/Content/Sounds/zonk2.wav new file mode 100644 index 0000000..77e37b4 Binary files /dev/null and b/V3/Content/Sounds/zonk2.wav differ diff --git a/V3/Content/Sources/Horse.blend b/V3/Content/Sources/Horse.blend new file mode 100644 index 0000000..017b12c Binary files /dev/null and b/V3/Content/Sources/Horse.blend differ diff --git a/V3/Content/Sources/Skeleton.blend b/V3/Content/Sources/Skeleton.blend new file mode 100644 index 0000000..0a8fd5d Binary files /dev/null and b/V3/Content/Sources/Skeleton.blend differ diff --git a/V3/Content/Sources/SkeletonHorse.blend b/V3/Content/Sources/SkeletonHorse.blend new file mode 100644 index 0000000..3520f1e Binary files /dev/null and b/V3/Content/Sources/SkeletonHorse.blend differ diff --git a/V3/Content/Sources/SkeletonHorse.png b/V3/Content/Sources/SkeletonHorse.png new file mode 100644 index 0000000..e0fc808 Binary files /dev/null and b/V3/Content/Sources/SkeletonHorse.png differ diff --git a/V3/Content/Sources/SkeletonRider.blend b/V3/Content/Sources/SkeletonRider.blend new file mode 100644 index 0000000..24d7161 Binary files /dev/null and b/V3/Content/Sources/SkeletonRider.blend differ diff --git a/V3/Content/Sources/SkeletonRider.png b/V3/Content/Sources/SkeletonRider.png new file mode 100644 index 0000000..681af75 Binary files /dev/null and b/V3/Content/Sources/SkeletonRider.png differ diff --git a/V3/Content/Sources/ZombieWithClub.png b/V3/Content/Sources/ZombieWithClub.png new file mode 100644 index 0000000..bea8eb3 Binary files /dev/null and b/V3/Content/Sources/ZombieWithClub.png differ diff --git a/V3/Content/Sources/castle.xcf b/V3/Content/Sources/castle.xcf new file mode 100644 index 0000000..50a7f8a Binary files /dev/null and b/V3/Content/Sources/castle.xcf differ diff --git a/V3/Content/Sources/create_spritesheet.sh b/V3/Content/Sources/create_spritesheet.sh new file mode 100644 index 0000000..eda0bd3 --- /dev/null +++ b/V3/Content/Sources/create_spritesheet.sh @@ -0,0 +1,7 @@ +#!/bin/bash +rows=8 # Possible directions (== 8 in isometric view) +columns=32 # Number of sprites per direction +cd out +montage *.png -mode concatenate -tile ${columns}x${rows} -background none out.png +mv out.png ../ +cd .. diff --git a/V3/Content/Sources/fleischklops.blend b/V3/Content/Sources/fleischklops.blend new file mode 100644 index 0000000..ce145da Binary files /dev/null and b/V3/Content/Sources/fleischklops.blend differ diff --git a/V3/Content/Sources/fleischklops.xcf b/V3/Content/Sources/fleischklops.xcf new file mode 100644 index 0000000..322f745 Binary files /dev/null and b/V3/Content/Sources/fleischklops.xcf differ diff --git a/V3/Content/Sources/horse_paint.png b/V3/Content/Sources/horse_paint.png new file mode 100644 index 0000000..74e4dd5 Binary files /dev/null and b/V3/Content/Sources/horse_paint.png differ diff --git a/V3/Content/Sources/horse_paint_sc.png b/V3/Content/Sources/horse_paint_sc.png new file mode 100644 index 0000000..453703a Binary files /dev/null and b/V3/Content/Sources/horse_paint_sc.png differ diff --git a/V3/Content/Sources/horse_tack.png b/V3/Content/Sources/horse_tack.png new file mode 100644 index 0000000..4f6a0b8 Binary files /dev/null and b/V3/Content/Sources/horse_tack.png differ diff --git a/V3/Content/Sources/houses_front.xcf b/V3/Content/Sources/houses_front.xcf new file mode 100644 index 0000000..680596d Binary files /dev/null and b/V3/Content/Sources/houses_front.xcf differ diff --git a/V3/Content/Sources/houses_rear.xcf b/V3/Content/Sources/houses_rear.xcf new file mode 100644 index 0000000..d711b47 Binary files /dev/null and b/V3/Content/Sources/houses_rear.xcf differ diff --git a/V3/Content/Sources/human_construction_set.xcf b/V3/Content/Sources/human_construction_set.xcf new file mode 100644 index 0000000..d0fb838 Binary files /dev/null and b/V3/Content/Sources/human_construction_set.xcf differ diff --git a/V3/Content/Sources/human_construction_set_female.xcf b/V3/Content/Sources/human_construction_set_female.xcf new file mode 100644 index 0000000..8c29a55 Binary files /dev/null and b/V3/Content/Sources/human_construction_set_female.xcf differ diff --git a/V3/Content/Sources/king.blend b/V3/Content/Sources/king.blend new file mode 100644 index 0000000..3bc5379 Binary files /dev/null and b/V3/Content/Sources/king.blend differ diff --git a/V3/Content/Sources/king_head.png b/V3/Content/Sources/king_head.png new file mode 100644 index 0000000..9bbc3c9 Binary files /dev/null and b/V3/Content/Sources/king_head.png differ diff --git a/V3/Content/Sources/necromancer.xcf b/V3/Content/Sources/necromancer.xcf new file mode 100644 index 0000000..dad43ad Binary files /dev/null and b/V3/Content/Sources/necromancer.xcf differ diff --git a/V3/Content/Sources/pathfinder.xcf b/V3/Content/Sources/pathfinder.xcf new file mode 100644 index 0000000..7833cea Binary files /dev/null and b/V3/Content/Sources/pathfinder.xcf differ diff --git a/V3/Content/Sources/prince.blend b/V3/Content/Sources/prince.blend new file mode 100644 index 0000000..c7c35a8 Binary files /dev/null and b/V3/Content/Sources/prince.blend differ diff --git a/V3/Content/Sources/prince.xcf b/V3/Content/Sources/prince.xcf new file mode 100644 index 0000000..14bbcf9 Binary files /dev/null and b/V3/Content/Sources/prince.xcf differ diff --git a/V3/Content/Sources/selection.xcf b/V3/Content/Sources/selection.xcf new file mode 100644 index 0000000..bbe3202 Binary files /dev/null and b/V3/Content/Sources/selection.xcf differ diff --git a/V3/Content/Sources/skeleton_horse.png b/V3/Content/Sources/skeleton_horse.png new file mode 100644 index 0000000..ed78f4a Binary files /dev/null and b/V3/Content/Sources/skeleton_horse.png differ diff --git a/V3/Content/Sources/the_triumph_of_death.jpg b/V3/Content/Sources/the_triumph_of_death.jpg new file mode 100644 index 0000000..654eaa6 Binary files /dev/null and b/V3/Content/Sources/the_triumph_of_death.jpg differ diff --git a/V3/Content/Sources/zombie.blend b/V3/Content/Sources/zombie.blend new file mode 100644 index 0000000..0ae1de3 Binary files /dev/null and b/V3/Content/Sources/zombie.blend differ diff --git a/V3/Content/Sprites/WhiteRectangle.png b/V3/Content/Sprites/WhiteRectangle.png new file mode 100644 index 0000000..7d3a386 Binary files /dev/null and b/V3/Content/Sprites/WhiteRectangle.png differ diff --git a/V3/Content/Sprites/arrows.png b/V3/Content/Sprites/arrows.png new file mode 100644 index 0000000..61a2db9 Binary files /dev/null and b/V3/Content/Sprites/arrows.png differ diff --git a/V3/Content/Sprites/buckler.png b/V3/Content/Sprites/buckler.png new file mode 100644 index 0000000..1253a60 Binary files /dev/null and b/V3/Content/Sprites/buckler.png differ diff --git a/V3/Content/Sprites/buckler_female.png b/V3/Content/Sprites/buckler_female.png new file mode 100644 index 0000000..3dd42a1 Binary files /dev/null and b/V3/Content/Sprites/buckler_female.png differ diff --git a/V3/Content/Sprites/chain.png b/V3/Content/Sprites/chain.png new file mode 100644 index 0000000..375f887 Binary files /dev/null and b/V3/Content/Sprites/chain.png differ diff --git a/V3/Content/Sprites/chain_female.png b/V3/Content/Sprites/chain_female.png new file mode 100644 index 0000000..e3b9c59 Binary files /dev/null and b/V3/Content/Sprites/chain_female.png differ diff --git a/V3/Content/Sprites/cloth.png b/V3/Content/Sprites/cloth.png new file mode 100644 index 0000000..3787867 Binary files /dev/null and b/V3/Content/Sprites/cloth.png differ diff --git a/V3/Content/Sprites/cloth_female.png b/V3/Content/Sprites/cloth_female.png new file mode 100644 index 0000000..f4d68b8 Binary files /dev/null and b/V3/Content/Sprites/cloth_female.png differ diff --git a/V3/Content/Sprites/cloud.png b/V3/Content/Sprites/cloud.png new file mode 100644 index 0000000..1e20701 Binary files /dev/null and b/V3/Content/Sprites/cloud.png differ diff --git a/V3/Content/Sprites/ellipse.png b/V3/Content/Sprites/ellipse.png new file mode 100644 index 0000000..c3e0c2c Binary files /dev/null and b/V3/Content/Sprites/ellipse.png differ diff --git a/V3/Content/Sprites/fleischklops.png b/V3/Content/Sprites/fleischklops.png new file mode 100644 index 0000000..b040c76 Binary files /dev/null and b/V3/Content/Sprites/fleischklops.png differ diff --git a/V3/Content/Sprites/fog.png b/V3/Content/Sprites/fog.png new file mode 100644 index 0000000..abb5572 Binary files /dev/null and b/V3/Content/Sprites/fog.png differ diff --git a/V3/Content/Sprites/head.png b/V3/Content/Sprites/head.png new file mode 100644 index 0000000..ff497fa Binary files /dev/null and b/V3/Content/Sprites/head.png differ diff --git a/V3/Content/Sprites/head_bald.png b/V3/Content/Sprites/head_bald.png new file mode 100644 index 0000000..51796a4 Binary files /dev/null and b/V3/Content/Sprites/head_bald.png differ diff --git a/V3/Content/Sprites/head_chain.png b/V3/Content/Sprites/head_chain.png new file mode 100644 index 0000000..9565715 Binary files /dev/null and b/V3/Content/Sprites/head_chain.png differ diff --git a/V3/Content/Sprites/head_chain_female.png b/V3/Content/Sprites/head_chain_female.png new file mode 100644 index 0000000..f016527 Binary files /dev/null and b/V3/Content/Sprites/head_chain_female.png differ diff --git a/V3/Content/Sprites/head_female.png b/V3/Content/Sprites/head_female.png new file mode 100644 index 0000000..3849fae Binary files /dev/null and b/V3/Content/Sprites/head_female.png differ diff --git a/V3/Content/Sprites/head_plate.png b/V3/Content/Sprites/head_plate.png new file mode 100644 index 0000000..5c7f5b7 Binary files /dev/null and b/V3/Content/Sprites/head_plate.png differ diff --git a/V3/Content/Sprites/head_plate_female.png b/V3/Content/Sprites/head_plate_female.png new file mode 100644 index 0000000..709d24e Binary files /dev/null and b/V3/Content/Sprites/head_plate_female.png differ diff --git a/V3/Content/Sprites/king.png b/V3/Content/Sprites/king.png new file mode 100644 index 0000000..18b5ea7 Binary files /dev/null and b/V3/Content/Sprites/king.png differ diff --git a/V3/Content/Sprites/longsword.png b/V3/Content/Sprites/longsword.png new file mode 100644 index 0000000..7e12f43 Binary files /dev/null and b/V3/Content/Sprites/longsword.png differ diff --git a/V3/Content/Sprites/longsword_female.png b/V3/Content/Sprites/longsword_female.png new file mode 100644 index 0000000..34f4480 Binary files /dev/null and b/V3/Content/Sprites/longsword_female.png differ diff --git a/V3/Content/Sprites/necromancer.png b/V3/Content/Sprites/necromancer.png new file mode 100644 index 0000000..65258d5 Binary files /dev/null and b/V3/Content/Sprites/necromancer.png differ diff --git a/V3/Content/Sprites/necromancer_female.png b/V3/Content/Sprites/necromancer_female.png new file mode 100644 index 0000000..6d34095 Binary files /dev/null and b/V3/Content/Sprites/necromancer_female.png differ diff --git a/V3/Content/Sprites/nude.png b/V3/Content/Sprites/nude.png new file mode 100644 index 0000000..88f1588 Binary files /dev/null and b/V3/Content/Sprites/nude.png differ diff --git a/V3/Content/Sprites/nude_female.png b/V3/Content/Sprites/nude_female.png new file mode 100644 index 0000000..fdd5b33 Binary files /dev/null and b/V3/Content/Sprites/nude_female.png differ diff --git a/V3/Content/Sprites/plate.png b/V3/Content/Sprites/plate.png new file mode 100644 index 0000000..f4d49c8 Binary files /dev/null and b/V3/Content/Sprites/plate.png differ diff --git a/V3/Content/Sprites/plate_female.png b/V3/Content/Sprites/plate_female.png new file mode 100644 index 0000000..570afff Binary files /dev/null and b/V3/Content/Sprites/plate_female.png differ diff --git a/V3/Content/Sprites/prince.png b/V3/Content/Sprites/prince.png new file mode 100644 index 0000000..9a8e5d9 Binary files /dev/null and b/V3/Content/Sprites/prince.png differ diff --git a/V3/Content/Sprites/selection.png b/V3/Content/Sprites/selection.png new file mode 100644 index 0000000..4ce0e93 Binary files /dev/null and b/V3/Content/Sprites/selection.png differ diff --git a/V3/Content/Sprites/shield.png b/V3/Content/Sprites/shield.png new file mode 100644 index 0000000..a5b1068 Binary files /dev/null and b/V3/Content/Sprites/shield.png differ diff --git a/V3/Content/Sprites/shield_female.png b/V3/Content/Sprites/shield_female.png new file mode 100644 index 0000000..d4b074b Binary files /dev/null and b/V3/Content/Sprites/shield_female.png differ diff --git a/V3/Content/Sprites/shortsword.png b/V3/Content/Sprites/shortsword.png new file mode 100644 index 0000000..e10adf8 Binary files /dev/null and b/V3/Content/Sprites/shortsword.png differ diff --git a/V3/Content/Sprites/shortsword_female.png b/V3/Content/Sprites/shortsword_female.png new file mode 100644 index 0000000..d1f097e Binary files /dev/null and b/V3/Content/Sprites/shortsword_female.png differ diff --git a/V3/Content/Sprites/skeleton.png b/V3/Content/Sprites/skeleton.png new file mode 100644 index 0000000..09d6464 Binary files /dev/null and b/V3/Content/Sprites/skeleton.png differ diff --git a/V3/Content/Sprites/skeleton_archer.png b/V3/Content/Sprites/skeleton_archer.png new file mode 100644 index 0000000..5bdbc02 Binary files /dev/null and b/V3/Content/Sprites/skeleton_archer.png differ diff --git a/V3/Content/Sprites/skeleton_elite.png b/V3/Content/Sprites/skeleton_elite.png new file mode 100644 index 0000000..982c031 Binary files /dev/null and b/V3/Content/Sprites/skeleton_elite.png differ diff --git a/V3/Content/Sprites/skeleton_horse.png b/V3/Content/Sprites/skeleton_horse.png new file mode 100644 index 0000000..e0fc808 Binary files /dev/null and b/V3/Content/Sprites/skeleton_horse.png differ diff --git a/V3/Content/Sprites/skeleton_rider.png b/V3/Content/Sprites/skeleton_rider.png new file mode 100644 index 0000000..681af75 Binary files /dev/null and b/V3/Content/Sprites/skeleton_rider.png differ diff --git a/V3/Content/Sprites/staff.png b/V3/Content/Sprites/staff.png new file mode 100644 index 0000000..0200876 Binary files /dev/null and b/V3/Content/Sprites/staff.png differ diff --git a/V3/Content/Sprites/staff_female.png b/V3/Content/Sprites/staff_female.png new file mode 100644 index 0000000..3a526d5 Binary files /dev/null and b/V3/Content/Sprites/staff_female.png differ diff --git a/V3/Content/Sprites/zombie.png b/V3/Content/Sprites/zombie.png new file mode 100644 index 0000000..a68091a Binary files /dev/null and b/V3/Content/Sprites/zombie.png differ diff --git a/V3/Content/Sprites/zombie_club.png b/V3/Content/Sprites/zombie_club.png new file mode 100644 index 0000000..bea8eb3 Binary files /dev/null and b/V3/Content/Sprites/zombie_club.png differ diff --git a/V3/Content/Textures/EmptyPixel.png b/V3/Content/Textures/EmptyPixel.png new file mode 100644 index 0000000..626a832 Binary files /dev/null and b/V3/Content/Textures/EmptyPixel.png differ diff --git a/V3/Content/Textures/castle.png b/V3/Content/Textures/castle.png new file mode 100644 index 0000000..e19dd45 Binary files /dev/null and b/V3/Content/Textures/castle.png differ diff --git a/V3/Content/Textures/grassland.png b/V3/Content/Textures/grassland.png new file mode 100644 index 0000000..0a56056 Binary files /dev/null and b/V3/Content/Textures/grassland.png differ diff --git a/V3/Content/Textures/grassland_trees.png b/V3/Content/Textures/grassland_trees.png new file mode 100644 index 0000000..b2bced3 Binary files /dev/null and b/V3/Content/Textures/grassland_trees.png differ diff --git a/V3/Content/Textures/grassland_water.png b/V3/Content/Textures/grassland_water.png new file mode 100644 index 0000000..2083506 Binary files /dev/null and b/V3/Content/Textures/grassland_water.png differ diff --git a/V3/Content/Textures/houses_front.png b/V3/Content/Textures/houses_front.png new file mode 100644 index 0000000..94513d4 Binary files /dev/null and b/V3/Content/Textures/houses_front.png differ diff --git a/V3/Content/Textures/houses_rear.png b/V3/Content/Textures/houses_rear.png new file mode 100644 index 0000000..64012e1 Binary files /dev/null and b/V3/Content/Textures/houses_rear.png differ diff --git a/V3/Content/Textures/medieval_building_tiles.png b/V3/Content/Textures/medieval_building_tiles.png new file mode 100644 index 0000000..154be4e Binary files /dev/null and b/V3/Content/Textures/medieval_building_tiles.png differ diff --git a/V3/Content/Textures/pathfinder.png b/V3/Content/Textures/pathfinder.png new file mode 100644 index 0000000..ae86dfb Binary files /dev/null and b/V3/Content/Textures/pathfinder.png differ diff --git a/V3/Data/DebugMode.cs b/V3/Data/DebugMode.cs new file mode 100644 index 0000000..b93ae7a --- /dev/null +++ b/V3/Data/DebugMode.cs @@ -0,0 +1,21 @@ +namespace V3.Data +{ + /// + /// A debug level that can be set by the player. + /// + public enum DebugMode + { + /// + /// Disable all debug utils. + /// + Off, + /// + /// Show the FPS counter. + /// + Fps, + /// + /// Show all debug information. + /// + Full + } +} diff --git a/V3/Data/GameState.cs b/V3/Data/GameState.cs new file mode 100644 index 0000000..b38ec46 --- /dev/null +++ b/V3/Data/GameState.cs @@ -0,0 +1,64 @@ +using Microsoft.Xna.Framework; +using System; +using System.Collections.Generic; +using V3.AI; +using V3.Objects; + +namespace V3.Data +{ + /// + /// Stores the current state of the game (the data that must be stored in + /// a save game). All members should be public and serializable. + /// + [Serializable] + public sealed class GameState + { + public List mCreatures = new List(); + public List mFog = new List(); + public Vector2 mCameraPosition; + public AiState mAiState = AiState.Idle; + } + + public enum CreatureType + { + FemalePeasant, + King, + KingsGuard, + Knight, + MalePeasant, + Meatball, + Necromancer, + Prince, + Skeleton, + SkeletonHorse, + Zombie + } + + public sealed class CreatureData + { + public CreatureType Type { get; set; } + public int Id { get; set; } + public int Life { get; set; } + public int MaxLife { get; set; } + public int Attack { get; set; } + public TimeSpan Recovery { get; set; } + public bool IsUpgraded { get; set; } + public float PositionX { get; set; } + public float PositionY { get; set; } + public MovementDirection MovementDirection { get; set; } + public MovementState MovementState { get; set; } + public MovementData MovementData { get; set; } + public int IsAttackingId { get; set; } + public bool Mounted { get; set; } + public int SkeletonId { get; set; } + // IsAttackingBuilding + } + + public sealed class MovementData + { + public List Path { get; set; } + public int Step { get; set; } + public Vector2 LastMovement { get; set; } + public bool IsMoving { get; set; } + } +} diff --git a/V3/Data/IGameStateManager.cs b/V3/Data/IGameStateManager.cs new file mode 100644 index 0000000..3a7f901 --- /dev/null +++ b/V3/Data/IGameStateManager.cs @@ -0,0 +1,20 @@ +namespace V3.Data +{ + /// + /// Stores the current game state. + /// + public interface IGameStateManager + { + /// + /// Stores the current game state and returns it. + /// + /// the current game state + GameState GetGameState(); + + /// + /// Restores the given game state. + /// + /// the game state to restore + void LoadGameState(GameState gameState); + } +} diff --git a/V3/Data/IOptionsManager.cs b/V3/Data/IOptionsManager.cs new file mode 100644 index 0000000..6910107 --- /dev/null +++ b/V3/Data/IOptionsManager.cs @@ -0,0 +1,18 @@ +namespace V3.Data +{ + /// + /// Handles the storing and loading of game options to the hard disk. + /// + public interface IOptionsManager + { + /// + /// The current options. + /// + Options Options { get; } + + /// + /// Saves the current options to the hard disk. + /// + void SaveOptions(); + } +} diff --git a/V3/Data/IPathManager.cs b/V3/Data/IPathManager.cs new file mode 100644 index 0000000..5574b35 --- /dev/null +++ b/V3/Data/IPathManager.cs @@ -0,0 +1,30 @@ +namespace V3.Data +{ + /// + /// Provides access to the default applications path, i. e. the + /// directories where save games, achievements and other persistent data + /// can be stored. + /// + public interface IPathManager + { + /// + /// The base directory for persistent application data. + /// + string AppDirectory { get; } + + /// + /// The directory for save games. + /// + string SaveGameDirectory { get; } + + /// + /// The file to store the options in. + /// + string OptionsFile { get; } + + /// + /// Creates the application directories that do not already exist. + /// + void CreateMissingDirectories(); + } +} \ No newline at end of file diff --git a/V3/Data/ISaveGame.cs b/V3/Data/ISaveGame.cs new file mode 100644 index 0000000..6f954e1 --- /dev/null +++ b/V3/Data/ISaveGame.cs @@ -0,0 +1,25 @@ +using System; + +namespace V3.Data +{ + /// + /// Stores a game state with some metadata. + /// + public interface ISaveGame : IComparable + { + /// + /// The creation time of this save game in local time. + /// + DateTime Timestamp { get; set; } + + /// + /// The compability version of this save game. + /// + int Version { get; set; } + + /// + /// The data stored in this save game. + /// + GameState GameState { get; set; } + } +} \ No newline at end of file diff --git a/V3/Data/ISaveGameManager.cs b/V3/Data/ISaveGameManager.cs new file mode 100644 index 0000000..f4e810f --- /dev/null +++ b/V3/Data/ISaveGameManager.cs @@ -0,0 +1,25 @@ +using System.Collections.Generic; + +namespace V3.Data +{ + /// + /// Stores and manages the game state in save games. + /// + public interface ISaveGameManager + { + /// + /// Creates and persists a new save game of the given data with the + /// title. + /// + /// the data to store + void CreateSaveGame(GameState gameState); + + /// + /// Loads all available save games and returns them ordered by the + /// creation date. + /// + /// a list of all available save games, orderd by creation + /// data + List GetSaveGames(); + } +} \ No newline at end of file diff --git a/V3/Data/Internal/GameStateManager.cs b/V3/Data/Internal/GameStateManager.cs new file mode 100644 index 0000000..53ef3de --- /dev/null +++ b/V3/Data/Internal/GameStateManager.cs @@ -0,0 +1,81 @@ +using System.Collections.Generic; +using V3.Camera; +using V3.Map; +using V3.Objects; + +namespace V3.Data.Internal +{ + /// + /// Default implementation of IGameStateManager. + /// + // ReSharper disable once ClassNeverInstantiated.Global + internal sealed class GameStateManager : IGameStateManager + { + private readonly CameraManager mCameraManager; + private readonly CreatureFactory mCreatureFactory; + private readonly IMapManager mMapManager; + private readonly IObjectsManager mObjectsManager; + + public GameStateManager(CameraManager cameraManager, CreatureFactory creatureFactory, + IMapManager mapManager, IObjectsManager objectsManager) + { + mCameraManager = cameraManager; + mCreatureFactory = creatureFactory; + mMapManager = mapManager; + mObjectsManager = objectsManager; + } + + /// + /// Restores the given game state. + /// + public GameState GetGameState() + { + var gameState = new GameState(); + foreach (var obj in mObjectsManager.CreatureList) + { + gameState.mCreatures.Add(obj.SaveData()); + } + gameState.mCameraPosition = mCameraManager.GetCamera().Location; + return gameState; + } + + /// + /// Restores the given game state. + /// + /// the game state to restore + public void LoadGameState(GameState gameState) + { + mObjectsManager.Clear(); + mObjectsManager.ImportMapObjects(mMapManager.GetObjects()); + var creatures = new Dictionary(); + + // load creatures + foreach (var creatureData in gameState.mCreatures) + { + ICreature creature = mCreatureFactory.CreateCreature(creatureData.Type, creatureData.Id); + if (creature == null) + continue; + creature.LoadData(creatureData); + if (creature is Necromancer) + mObjectsManager.CreatePlayerCharacter((Necromancer) creature); + else if (creature is King) // || creature is Prince + mObjectsManager.CreateBoss(creature); + else + mObjectsManager.CreateCreature(creature); + + creatures.Add(creature.Id, creature); + } + + // fix references + foreach (var creatureData in gameState.mCreatures) + { + if (!creatures.ContainsKey(creatureData.Id)) + continue; + creatures[creatureData.Id].LoadReferences(creatureData, creatures); + } + + if (mCameraManager.GetCamera() is CameraScrolling) + mCameraManager.GetCamera().Location = gameState.mCameraPosition; + } + } +} diff --git a/V3/Data/Internal/OptionsManager.cs b/V3/Data/Internal/OptionsManager.cs new file mode 100644 index 0000000..d581ba5 --- /dev/null +++ b/V3/Data/Internal/OptionsManager.cs @@ -0,0 +1,65 @@ +using System.IO; +using System.Runtime.Serialization; +using System.Xml.Serialization; +using Ninject; + +namespace V3.Data.Internal +{ + /// + /// Default implementation of IOptionsManager. + /// + // ReSharper disable once ClassNeverInstantiated.Global + internal sealed class OptionsManager : IOptionsManager, IInitializable + { + /// + /// The current options. + /// + public Options Options { get; private set; } + + private readonly IPathManager mPathManager; + private readonly XmlSerializer mSerializer = new XmlSerializer(typeof(Options)); + + /// + /// Creates a new OptionsManager. + /// + public OptionsManager(IPathManager pathManager) + { + mPathManager = pathManager; + } + + public void Initialize() + { + Options = LoadOptions(); + } + + /// + /// Saves the current options to the hard disk. + /// + public void SaveOptions() + { + var stream = new FileStream(mPathManager.OptionsFile, FileMode.Create, FileAccess.Write); + mSerializer.Serialize(stream, Options); + stream.Close(); + } + + private Options LoadOptions() + { + if (!File.Exists(mPathManager.OptionsFile)) + return new Options(); + var stream = new FileStream(mPathManager.OptionsFile, FileMode.Open, FileAccess.Read); + try + { + return (Options)mSerializer.Deserialize(stream); + } + catch (SerializationException) + { + // ignore so far + } + finally + { + stream.Close(); + } + return new Options(); + } + } +} diff --git a/V3/Data/Internal/PathManager.cs b/V3/Data/Internal/PathManager.cs new file mode 100644 index 0000000..3f4ad9d --- /dev/null +++ b/V3/Data/Internal/PathManager.cs @@ -0,0 +1,51 @@ +using System; +using System.IO; + +namespace V3.Data.Internal { + /// + /// Default implementation of IPathManager. + /// + // ReSharper disable once ClassNeverInstantiated.Global + internal sealed class PathManager : IPathManager + { + /// + /// The base directory for persistent application data. + /// + public string AppDirectory { get; } + + /// + /// The file to store the options in. + /// + public string OptionsFile { get; } + + /// + /// The directory for save games. + /// + public string SaveGameDirectory { get; } + + /// + /// Creates a new path manager and initializes the paths, but does not + /// create the directories if they don’t already exist. + /// + public PathManager() + { + var localAppDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData); + AppDirectory = $"{localAppDir}/V3"; + SaveGameDirectory = $"{AppDirectory}/SaveGames"; + OptionsFile = $"{AppDirectory}/Options.xml"; + } + + /// + /// Creates the application directories that do not already exist. + /// + public void CreateMissingDirectories() + { + string[] directories = { AppDirectory, SaveGameDirectory }; + foreach (var directory in directories) + { + if (!Directory.Exists(directory)) + Directory.CreateDirectory(directory); + } + } + } +} diff --git a/V3/Data/Internal/SaveGame.cs b/V3/Data/Internal/SaveGame.cs new file mode 100644 index 0000000..9ff3586 --- /dev/null +++ b/V3/Data/Internal/SaveGame.cs @@ -0,0 +1,65 @@ +using System; + +namespace V3.Data.Internal +{ + // TODO: once the game state is getting larger, we have to separate the + // save game metadata from the game state. + + /// + /// A save game that has a timestamp and a title, and that can store + /// the game state. + /// + [Serializable] + public sealed class SaveGame : ISaveGame + { + /// + /// The creation time of this save game in local time. + /// + public DateTime Timestamp { get; set; } + + /// + /// The compability version of this save game. + /// + public int Version { get; set; } + + /// + /// The data stored in this save game. + /// + public GameState GameState { get; set; } + + /// + /// Empty constructor for serialization. + /// + private SaveGame() + { + } + + /// + /// Creates a new save game from the given data. + /// + /// the creation time of the save game + /// the compability version of the save game + /// the game state to store in the save game + internal SaveGame(DateTime timestamp, int version, GameState gameState) + { + Timestamp = timestamp; + Version = version; + GameState = gameState; + } + + /// + /// Compares this save game object to another save game object based + /// on the creation time. + /// + /// the save game to compare this save game + /// with + /// a value less than zero if this save game has been saved + /// before the given save game, zero if they have been saved at the + /// same time and a value greater than zero if the given save game has + /// been saved before the given one + public int CompareTo(ISaveGame saveGame) + { + return Timestamp.CompareTo(saveGame.Timestamp); + } + } +} diff --git a/V3/Data/Internal/SaveGameManager.cs b/V3/Data/Internal/SaveGameManager.cs new file mode 100644 index 0000000..1c52b50 --- /dev/null +++ b/V3/Data/Internal/SaveGameManager.cs @@ -0,0 +1,88 @@ +using System; +using System.Collections.Generic; +using System.IO; +using System.Runtime.Serialization; +using System.Xml.Serialization; + +namespace V3.Data.Internal +{ + /// + /// Default implementation if ISaveGameManager. + /// + // ReSharper disable once ClassNeverInstantiated.Global + internal sealed class SaveGameManager : ISaveGameManager + { + private readonly IPathManager mPathManager; + + private const int CurrentVersion = 1; + private readonly XmlSerializer mFormatter = new XmlSerializer(typeof(SaveGame)); + + /// + /// Creates a new SaveGameManager. The save game directory must already + /// be created. + /// + public SaveGameManager(IPathManager pathManager) + { + mPathManager = pathManager; + } + + /// + /// Creates and persists a new save game of the given data with the + /// title. + /// + /// the data to store + public void CreateSaveGame(GameState gameState) + { + var saveGame = new SaveGame(DateTime.Now, CurrentVersion, gameState); + var fileName = GetUniqueFileName(); + var stream = new FileStream(fileName, FileMode.Create, FileAccess.Write); + mFormatter.Serialize(stream, saveGame); + stream.Close(); + } + + /// + /// Loads all available save games and returns them ordered by the + /// creation date. + /// + /// a list of all available save games, orderd by creation + /// data + public List GetSaveGames() + { + var saveGames = new List(); + foreach (var file in Directory.GetFiles(mPathManager.SaveGameDirectory)) + { + var stream = new FileStream(file, FileMode.Open, FileAccess.Read); + try + { + var saveGame = (ISaveGame)mFormatter.Deserialize(stream); + if (saveGame.Version == CurrentVersion) + saveGames.Add(saveGame); + } + catch (SerializationException) + { + // ignore so far + } + stream.Close(); + } + saveGames.Sort(); + return saveGames; + } + + private string GetUniqueFileName() + { + var index = 1; + var fileName = GetFileName(index); + while (File.Exists(fileName)) + { + index++; + fileName = GetFileName(index); + } + return fileName; + } + + private string GetFileName(int index) + { + return $"{mPathManager.SaveGameDirectory}/{index:000}.xml"; + } + } +} diff --git a/V3/Data/Options.cs b/V3/Data/Options.cs new file mode 100644 index 0000000..38670dc --- /dev/null +++ b/V3/Data/Options.cs @@ -0,0 +1,105 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Xna.Framework; +using V3.Camera; + +namespace V3.Data +{ + /// + /// The graphics options. + /// + [Serializable] + public sealed class Options + { + /// + /// All available screen resolutions. + /// + public static List Resolutions { get; } = new List + { + new Point(800, 480), + new Point(800, 600), + new Point(1024, 768), + new Point(1280, 800), + new Point(1280, 1024), + new Point(1366, 768), + new Point(1920, 1080) + }; + + /// + /// All available camera types. + /// + public static List CameraTypes { get; } = + Enum.GetValues(typeof (CameraType)).Cast().ToList(); + + /// + /// All available debug modes. + /// + public static List DebugModes { get; } = + Enum.GetValues(typeof (DebugMode)).Cast().ToList(); + + /// + /// All available volume settings. + /// + public static List Volumes { get; } = new List() + { + 10, + 20, + 30, + 40, + 50, + 60, + 70, + 80, + 90, + 100 + }; + private static readonly Point sDefaultResolution = Resolutions[0]; + private static readonly bool sDefaultIsFullScreen = false; + private static readonly DebugMode sDefaultDebugMode = DebugMode.Off; + private static readonly CameraType sDefaultCameraType = CameraType.Scrolling; + private static readonly bool sDefaultIsMuted = false; + private static readonly int sDefaultVolume = 100; + + /// + /// The current screen resolution. + /// + public Point Resolution { get; set; } = sDefaultResolution; + + /// + /// True if the game should be run in full screen, otherwise false. + /// + public bool IsFullScreen { get; set; } = sDefaultIsFullScreen; + + /// + /// The current debug mode. + /// + public DebugMode DebugMode { get; set; } = sDefaultDebugMode; + + /// + /// The current camera type. + /// + public CameraType CameraType { get; set; } = sDefaultCameraType; + + /// + /// True if the sound is muted, otherwise false. + /// + public bool IsMuted { get; set; } = sDefaultIsMuted; + + /// + /// The volume to use for the sound (if the sound is not muted), range + /// 0 .. 100. + /// + public int Volume { get; set; } = sDefaultVolume; + + /// + /// Returns the effective volume with regard to the mute and volume + /// settings. + /// + /// the effective volume that should be used for sound + public float GetEffectiveVolume() + { + return IsMuted ? 0 : ((float) Volume) / 100; + } + } +} diff --git a/V3/Effects/AbstractEffect.cs b/V3/Effects/AbstractEffect.cs new file mode 100644 index 0000000..c3468c0 --- /dev/null +++ b/V3/Effects/AbstractEffect.cs @@ -0,0 +1,74 @@ +using System; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Audio; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.Graphics; +using V3.Data; + +namespace V3.Effects +{ + public abstract class AbstractEffect : IEffect + { + private Texture2D mTexture; + private int mSpritesPerRow; + private int mTotalSprites; + private int mAnimationState; + private Rectangle mAnimationRectangle; + private SoundEffect mSoundEffect; + private SoundEffectInstance mSoundEffectInstance; + + public bool IsPlaying { get; private set; } + protected virtual UpdatesPerSecond UpdatesPerSecond { get; } = new UpdatesPerSecond(24); + protected abstract string TextureFile { get; } + protected virtual Point SpriteSize { get; } = new Point(128, 128); + protected virtual string SoundFile { get; } = String.Empty; + + public void LoadContent(ContentManager contentManager) + { + mTexture = contentManager.Load("Effects/" + TextureFile); + mSpritesPerRow = mTexture.Width / SpriteSize.X; + mTotalSprites = mSpritesPerRow * (mTexture.Height / SpriteSize.Y); + if (SoundFile.Length != 0) + { + mSoundEffect = contentManager.Load("Sounds/" + SoundFile); + mSoundEffectInstance = mSoundEffect.CreateInstance(); + } + } + + public void PlayOnce(Point position, Point size, IOptionsManager optionsManager) + { + mAnimationRectangle = new Rectangle(position - size / new Point(2, 2), size); + IsPlaying = true; + if (SoundFile.Length != 0) + { + mSoundEffectInstance.Volume = optionsManager.Options.GetEffectiveVolume(); + mSoundEffectInstance.Play(); + } + } + + public void Update(GameTime gameTime) + { + if (!IsPlaying) return; + if (UpdatesPerSecond.IsItTime(gameTime)) + { + if (mAnimationState < mTotalSprites) + { + mAnimationState++; + } + else + { + mAnimationState = 0; + IsPlaying = false; + } + } + } + + public void Draw(SpriteBatch spriteBatch) + { + if (!IsPlaying) return; + spriteBatch.Draw(mTexture, mAnimationRectangle, + new Rectangle(new Point(mAnimationState % mSpritesPerRow * SpriteSize.X, mAnimationState / mSpritesPerRow * SpriteSize.Y), SpriteSize), + Color.White); + } + } +} \ No newline at end of file diff --git a/V3/Effects/BloodBang.cs b/V3/Effects/BloodBang.cs new file mode 100644 index 0000000..f5e1f3c --- /dev/null +++ b/V3/Effects/BloodBang.cs @@ -0,0 +1,8 @@ +namespace V3.Effects +{ + public class BloodBang : AbstractEffect + { + protected override string TextureFile { get; } = "blood_hit_04"; + protected override string SoundFile { get; } = "impactsplat01"; + } +} \ No newline at end of file diff --git a/V3/Effects/BloodExplosion.cs b/V3/Effects/BloodExplosion.cs new file mode 100644 index 0000000..baa38d4 --- /dev/null +++ b/V3/Effects/BloodExplosion.cs @@ -0,0 +1,11 @@ +namespace V3.Effects +{ + /// + /// A round explosion of blood. + /// + public sealed class BloodExplosion : AbstractEffect + { + protected override string TextureFile { get; } = "blood_hit_08"; + protected override string SoundFile { get; } = "impactsplat01"; + } +} \ No newline at end of file diff --git a/V3/Effects/BloodFountain.cs b/V3/Effects/BloodFountain.cs new file mode 100644 index 0000000..5684e34 --- /dev/null +++ b/V3/Effects/BloodFountain.cs @@ -0,0 +1,11 @@ +namespace V3.Effects +{ + /// + /// A small fountain of blood. + /// + public sealed class BloodFountain : AbstractEffect + { + protected override string TextureFile { get; } = "blood_hit_02"; + protected override string SoundFile { get; } = "impactsplat01"; + } +} \ No newline at end of file diff --git a/V3/Effects/EffectsManager.cs b/V3/Effects/EffectsManager.cs new file mode 100644 index 0000000..a175e34 --- /dev/null +++ b/V3/Effects/EffectsManager.cs @@ -0,0 +1,54 @@ +using System.Collections.Generic; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.Graphics; +using V3.Data; + +namespace V3.Effects +{ + // ReSharper disable once ClassNeverInstantiated.Global + public sealed class EffectsManager : IEffectsManager + { + private readonly ContentManager mContentManager; + private readonly IOptionsManager mOptionsManager; + private readonly List mActiveEffects = new List(); + + public EffectsManager(ContentManager contentManager, IOptionsManager optionsManager) + { + mContentManager = contentManager; + mOptionsManager = optionsManager; + } + + public void Update(GameTime gameTime) + { + var doneEffects = new List(); + foreach (var effect in mActiveEffects) + { + effect.Update(gameTime); + if (!effect.IsPlaying) + { + doneEffects.Add(effect); + } + } + foreach (var doneEffect in doneEffects) + { + mActiveEffects.Remove(doneEffect); + } + } + + public void Draw(SpriteBatch spriteBatch) + { + foreach (var effect in mActiveEffects) + { + effect.Draw(spriteBatch); + } + } + + public void PlayOnce(IEffect effect, Point position, Point size) + { + effect.LoadContent(mContentManager); + mActiveEffects.Add(effect); + effect.PlayOnce(position, size, mOptionsManager); + } + } +} \ No newline at end of file diff --git a/V3/Effects/Explosion.cs b/V3/Effects/Explosion.cs new file mode 100644 index 0000000..afcfdf4 --- /dev/null +++ b/V3/Effects/Explosion.cs @@ -0,0 +1,14 @@ +using Microsoft.Xna.Framework; + +namespace V3.Effects +{ + /// + /// A large explosion with sound. + /// + public class Explosion : AbstractEffect + { + protected override string TextureFile { get; } = "explosion"; + protected override Point SpriteSize { get; } = new Point(320, 240); + protected override string SoundFile { get; } = "explosion1"; + } +} \ No newline at end of file diff --git a/V3/Effects/HorseEffect.cs b/V3/Effects/HorseEffect.cs new file mode 100644 index 0000000..a09fe60 --- /dev/null +++ b/V3/Effects/HorseEffect.cs @@ -0,0 +1,11 @@ +using Microsoft.Xna.Framework; + +namespace V3.Effects +{ + public sealed class HorseEffect : AbstractEffect + { + protected override string TextureFile { get; } = "quake"; + protected override Point SpriteSize { get; } = new Point(256, 128); + protected override string SoundFile { get; } = "horse"; + } +} diff --git a/V3/Effects/IEffect.cs b/V3/Effects/IEffect.cs new file mode 100644 index 0000000..73cf1ef --- /dev/null +++ b/V3/Effects/IEffect.cs @@ -0,0 +1,44 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.Graphics; +using V3.Data; + +namespace V3.Effects +{ + /// + /// Interface for a single effect. + /// + public interface IEffect + { + /// + /// Is the effect playing at the moment? + /// + bool IsPlaying { get; } + + /// + /// Play the specific effect once, do not loop. + /// + /// Position where effect should be played. Points to the middle of the effect animation. + /// Size of the effect. + /// For checking the volume of the sound if there is one. + void PlayOnce(Point position, Point size, IOptionsManager optionsManager); + + /// + /// Update the effect. + /// + /// Game time used for checking animation duration. + void Update(GameTime gameTime); + + /// + /// Draw the effect. + /// + /// Sprite batch used. + void Draw(SpriteBatch spriteBatch); + + /// + /// Load graphics and possibly sound for the effect. + /// + /// Content manager used. + void LoadContent(ContentManager contentManager); + } +} \ No newline at end of file diff --git a/V3/Effects/IEffectsManager.cs b/V3/Effects/IEffectsManager.cs new file mode 100644 index 0000000..3ea6154 --- /dev/null +++ b/V3/Effects/IEffectsManager.cs @@ -0,0 +1,31 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; + +namespace V3.Effects +{ + /// + /// Interface for managing visual effects like explosions and stuff. + /// + public interface IEffectsManager + { + /// + /// Update all effects. + /// + /// Game time used for calculation effects duration. + void Update(GameTime gameTime); + + /// + /// Draw all effects. + /// + /// Sprite batch used. + void Draw(SpriteBatch spriteBatch); + + /// + /// Play an effect once, then delete it. + /// + /// Which effect to play. + /// Position where effect should be played. Points to the middle of the effect animation. + /// Size of the effect. + void PlayOnce(IEffect effect, Point position, Point size); + } +} \ No newline at end of file diff --git a/V3/Effects/Quake.cs b/V3/Effects/Quake.cs new file mode 100644 index 0000000..c08825d --- /dev/null +++ b/V3/Effects/Quake.cs @@ -0,0 +1,11 @@ +using Microsoft.Xna.Framework; + +namespace V3.Effects +{ + public class Quake : AbstractEffect + { + protected override string TextureFile { get; } = "quake"; + protected override Point SpriteSize { get; } = new Point(256, 128); + protected override string SoundFile { get; } = "explodemini"; + } +} \ No newline at end of file diff --git a/V3/Effects/SmokeBig.cs b/V3/Effects/SmokeBig.cs new file mode 100644 index 0000000..3dfce2a --- /dev/null +++ b/V3/Effects/SmokeBig.cs @@ -0,0 +1,10 @@ +namespace V3.Effects +{ + /// + /// A large ring of smoke, spreading over some area. + /// + public sealed class SmokeBig : AbstractEffect + { + protected override string TextureFile { get; } = "particlefx_03"; + } +} \ No newline at end of file diff --git a/V3/Effects/SmokeMedium.cs b/V3/Effects/SmokeMedium.cs new file mode 100644 index 0000000..09447fa --- /dev/null +++ b/V3/Effects/SmokeMedium.cs @@ -0,0 +1,13 @@ +using System.Diagnostics.CodeAnalysis; + +namespace V3.Effects +{ + /// + /// A medium sized ring of smoke, spreading over some area. + /// + [SuppressMessage("ReSharper", "UnusedMember.Global")] + public sealed class SmokeMedium : AbstractEffect + { + protected override string TextureFile { get; } = "particlefx_04"; + } +} \ No newline at end of file diff --git a/V3/Effects/SmokeSmall.cs b/V3/Effects/SmokeSmall.cs new file mode 100644 index 0000000..f2f2dce --- /dev/null +++ b/V3/Effects/SmokeSmall.cs @@ -0,0 +1,10 @@ +namespace V3.Effects +{ + /// + /// A small ring of smoke, spreading over some area. + /// + public sealed class SmokeSmall : AbstractEffect + { + protected override string TextureFile { get; } = "particlefx_05"; + } +} \ No newline at end of file diff --git a/V3/Ellipse.cs b/V3/Ellipse.cs new file mode 100644 index 0000000..076aff0 --- /dev/null +++ b/V3/Ellipse.cs @@ -0,0 +1,31 @@ +using System; +using Microsoft.Xna.Framework; + +namespace V3 +{ + public struct Ellipse + { + private Vector2 Center { get; } + private float Width { get; } + private float Height { get; } + + public Rectangle BoundaryRectangle => new Rectangle((Center - new Vector2(Width / 2, Height / 2)).ToPoint(), new Vector2(Width, Height).ToPoint()); + + internal Ellipse(Vector2 center, float width, float height) + { + Center = center; + Width = width; + Height = height; + } + + internal bool Contains(Vector2 position) + { + if (Math.Pow(position.X - Center.X, 2) / Math.Pow(Width/2, 2) + + Math.Pow(position.Y - Center.Y, 2) / Math.Pow(Height/2, 2) <= 1) + { + return true; + } + return false; + } + } +} diff --git a/V3/Faction.cs b/V3/Faction.cs new file mode 100644 index 0000000..96b2f9b --- /dev/null +++ b/V3/Faction.cs @@ -0,0 +1,7 @@ +namespace V3 +{ + public enum Faction + { + Undead, Kingdom, Plebs + } +} \ No newline at end of file diff --git a/V3/Icon.ico b/V3/Icon.ico new file mode 100644 index 0000000..38c64b5 Binary files /dev/null and b/V3/Icon.ico differ diff --git a/V3/Input/IInputManager.cs b/V3/Input/IInputManager.cs new file mode 100644 index 0000000..b092ebb --- /dev/null +++ b/V3/Input/IInputManager.cs @@ -0,0 +1,34 @@ +using System.Collections.Generic; + +namespace V3.Input +{ + /// + /// Watches the state of the mouse and keyboard and creates events if a + /// change (key pressed or released) is detected. To use this class, call + /// Update in every update round. After the update, you may access the + /// generated events in KeyEvents and MouseEvents. The input manager only + /// watches the mouse buttons and keys listed in sWatchedKeys and + /// sWatchedButtons. + /// + public interface IInputManager + { + /// + /// The key events that were generated during the last update. Reset + /// in the next update. + /// + ICollection KeyEvents { get; } + + /// + /// The mouse events that were generated during the last update. Reset in + /// the next update. + /// + ICollection MouseEvents { get; } + + /// + /// Updates the keyboard and mouse status and generates the key and mouse + /// events in KeyEvents and MouseEvents if changes were detected. Should + /// be called once every update, before doing something else. + /// + void Update(); + } +} \ No newline at end of file diff --git a/V3/Input/IKeyEvent.cs b/V3/Input/IKeyEvent.cs new file mode 100644 index 0000000..42b99c6 --- /dev/null +++ b/V3/Input/IKeyEvent.cs @@ -0,0 +1,20 @@ +using Microsoft.Xna.Framework.Input; + +namespace V3.Input +{ + /// + /// An event that is triggered if a key is pressed or released on the + /// keyboard. + /// + public interface IKeyEvent + { + /// + /// The key that was pressed or released. + /// + Keys Key { get; } + /// + /// The type of the event (key pressed or released?). + /// + KeyState KeyState { get; } + } +} \ No newline at end of file diff --git a/V3/Input/IMouseEvent.cs b/V3/Input/IMouseEvent.cs new file mode 100644 index 0000000..37b221d --- /dev/null +++ b/V3/Input/IMouseEvent.cs @@ -0,0 +1,34 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Input; + +namespace V3.Input +{ + /// + /// An event that is sent when a mouse button is pressed or released. + /// + public interface IMouseEvent + { + /// + /// The mouse button that was pressed or released. + /// + MouseButton MouseButton { get; } + /// + /// The state of the mouse button (pressed or released?). + /// + ButtonState ButtonState { get; } + /// + /// The position where the mouse button was pressed the last time. + /// + Point PositionPressed { get; } + /// + /// The position where the mouse button was released if this is a + /// release event, null otherwise. + /// + Point? PositionReleased { get; } + /// + /// True if PositionReleased is a valid on-screen position, otherwise + /// false. + /// + bool ReleasedOnScreen { get; } + } +} diff --git a/V3/Input/IMouseEventHandler.cs b/V3/Input/IMouseEventHandler.cs new file mode 100644 index 0000000..7c8701c --- /dev/null +++ b/V3/Input/IMouseEventHandler.cs @@ -0,0 +1,14 @@ +namespace V3.Input +{ + /// + /// Handles mouse events. + /// + public interface IMouseEventHandler + { + /// + /// Handle the given mouse event, if applicable. + /// + /// the mouse event to handle + void HandleMouseEvent(IMouseEvent mouseEvent); + } +} diff --git a/V3/Input/Internal/InputManager.cs b/V3/Input/Internal/InputManager.cs new file mode 100644 index 0000000..8e6ce2e --- /dev/null +++ b/V3/Input/Internal/InputManager.cs @@ -0,0 +1,141 @@ +using System.Collections.Generic; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Input; +using Ninject; + +namespace V3.Input.Internal +{ + /// + /// Watches the state of the mouse and keyboard and creates events if a + /// change (key pressed or released) is detected. To use this class, call + /// Update in every update round. After the update, you may access the + /// generated events in KeyEvents and MouseEvents. The input manager only + /// watches the mouse buttons and keys listed in sWatchedKeys and + /// sWatchedButtons. + /// + // ReSharper disable once ClassNeverInstantiated.Global + internal sealed class InputManager : IInputManager, IInitializable + { + /// + /// The key events that were generated during the last update. Reset + /// in the next update. + /// + public ICollection KeyEvents { get; } = new HashSet(); + /// + /// The mouse events that were generated during the last update. Reset in + /// the next update. + /// + public ICollection MouseEvents { get; } = new HashSet(); + + private static readonly ICollection sWatchedKeys = new List { Keys.Enter, Keys.Escape, Keys.E, Keys.L, Keys.Q, Keys.S, Keys.F1, Keys.F2 , Keys.F3, Keys.F4, Keys.F5, Keys.F6, Keys.F7, Keys.F8 }; + + private static readonly ICollection sWatchedButtons = new List { MouseButton.Left, MouseButton.Right, MouseButton.Middle }; + + private readonly GraphicsDeviceManager mGraphicsDeviceManager; + + private readonly IDictionary mKeyStates = new Dictionary(); + + private readonly IDictionary mButtonStates = new Dictionary(); + + private readonly IDictionary mButtonPositions = new Dictionary(); + + /// + /// Creates a new input manager. + /// + public InputManager(GraphicsDeviceManager graphicsDeviceManager) + { + mGraphicsDeviceManager = graphicsDeviceManager; + } + + public void Initialize() + { + foreach (var key in sWatchedKeys) + mKeyStates.Add(key, KeyState.Up); + foreach (var button in sWatchedButtons) + { + mButtonStates.Add(button, ButtonState.Released); + mButtonPositions.Add(button, null); + } + } + + /// + /// Updates the keyboard and mouse status and generates the key and mouse + /// events in KeyEvents and MouseEvents if changes were detected. Should + /// be called once every update, before doing something else. + /// + public void Update() + { + UpdateKeyboard(); + UpdateMouse(); + } + + private void UpdateKeyboard() + { + KeyEvents.Clear(); + + var state = Keyboard.GetState(); + foreach (var key in sWatchedKeys) + { + var newState = state[key]; + if (newState != mKeyStates[key]) + { + mKeyStates[key] = newState; + KeyEvents.Add(new KeyEvent(key, newState)); + } + } + } + + private void UpdateMouse() + { + MouseEvents.Clear(); + + var state = Mouse.GetState(); + foreach (var button in sWatchedButtons) + { + var newState = GetButtonState(state, button); + if (newState != mButtonStates[button]) + { + var position = new Point(state.X, state.Y); + var positionPressed = position; + Point? positionReleased = null; + if (newState == ButtonState.Released) + { + if (mButtonPositions[button].HasValue) + positionPressed = mButtonPositions[button].Value; + positionReleased = position; + } + + mButtonStates[button] = newState; + mButtonPositions[button] = position; + + var releasedOnScreen = false; + if (positionReleased.HasValue) + releasedOnScreen = IsPointOnScreen(positionReleased.Value); + + MouseEvents.Add(new MouseEvent(button, newState, positionPressed, positionReleased, releasedOnScreen)); + } + } + } + + private bool IsPointOnScreen(Point point) + { + var viewport = mGraphicsDeviceManager.GraphicsDevice.Viewport; + return point.X >= 0 && point.X <= viewport.Width && point.Y >= 0 && point.Y <= viewport.Height; + } + + private static ButtonState GetButtonState(MouseState state, MouseButton button) + { + switch (button) + { + case MouseButton.Left: + return state.LeftButton; + case MouseButton.Right: + return state.RightButton; + case MouseButton.Middle: + return state.MiddleButton; + default: + return state.LeftButton; + } + } + } +} diff --git a/V3/Input/Internal/KeyEvent.cs b/V3/Input/Internal/KeyEvent.cs new file mode 100644 index 0000000..b4a450e --- /dev/null +++ b/V3/Input/Internal/KeyEvent.cs @@ -0,0 +1,32 @@ +using Microsoft.Xna.Framework.Input; + +namespace V3.Input.Internal +{ + /// + /// Default implementation of an event that is triggered if a key is + /// pressed or released on the keyboard. + /// + internal sealed class KeyEvent : IKeyEvent + { + /// + /// The key that was pressed or released. + /// + public Keys Key { get; } + /// + /// The type of the event (key pressed or released?). + /// + public KeyState KeyState { get; } + + /// + /// Creates a new key event with the given data. + /// + /// the key that was pressed or released + /// the type of the event (presesd or + /// released?) + public KeyEvent(Keys key, KeyState keyState) + { + Key = key; + KeyState = keyState; + } + } +} diff --git a/V3/Input/Internal/MouseEvent.cs b/V3/Input/Internal/MouseEvent.cs new file mode 100644 index 0000000..f8024aa --- /dev/null +++ b/V3/Input/Internal/MouseEvent.cs @@ -0,0 +1,57 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Input; + +namespace V3.Input.Internal +{ + /// + /// Default implementation of an event that is sent when a mouse button is + /// pressed or released. + /// + internal sealed class MouseEvent : IMouseEvent + { + /// + /// The mouse button that was pressed or released. + /// + public MouseButton MouseButton { get; } + /// + /// The state of the mouse button (pressed or released?). + /// + public ButtonState ButtonState { get; } + /// + /// The position where the mouse button was pressed the last time. + /// + public Point PositionPressed { get; } + /// + /// The position where the mouse button was released if this is a + /// release event, null otherwise. + /// + public Point? PositionReleased { get; } + /// + /// True if PositionReleased is a valid on-screen position, otherwise + /// false. + /// + public bool ReleasedOnScreen { get; } + + /// + /// Creates a new mouse event with the given data. + /// + /// the mouse button that was pressed or + /// released + /// the type of the event (pressed or + /// released?) + /// the position of the last press of + /// the button + /// the position of the release of the + /// button if this is a release event, or null otherwise + /// true if positionReleased is a valid + /// on-screen position. + public MouseEvent(MouseButton mouseButton, ButtonState buttonState, Point positionPressed, Point? positionReleased, bool releasedOnScreen) + { + MouseButton = mouseButton; + ButtonState = buttonState; + PositionPressed = positionPressed; + PositionReleased = positionReleased; + ReleasedOnScreen = releasedOnScreen; + } + } +} diff --git a/V3/Input/MouseButton.cs b/V3/Input/MouseButton.cs new file mode 100644 index 0000000..616872b --- /dev/null +++ b/V3/Input/MouseButton.cs @@ -0,0 +1,9 @@ +namespace V3.Input +{ + public enum MouseButton + { + Left, + Right, + Middle + } +} diff --git a/V3/Map/AbstractLayer.cs b/V3/Map/AbstractLayer.cs new file mode 100644 index 0000000..efc626d --- /dev/null +++ b/V3/Map/AbstractLayer.cs @@ -0,0 +1,259 @@ +using System; +using System.Collections.Generic; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.Graphics; +using V3.Camera; +using V3.Objects; + +namespace V3.Map +{ + /// + /// A drawable map layer usually created from a Tiled map file. + /// + public abstract class AbstractLayer + { + private const int CellHeight = Constants.CellHeight; + private const int CellWidth = Constants.CellWidth; + + private readonly int mTileWidth; + private readonly int mTileHeight; + private readonly int mMapWidth; + private readonly int mMapHeight; + private readonly List mTextureObjects = new List(); + private readonly int[,] mTileArray; + private readonly SortedList mTilesets; + + protected AbstractLayer(int tileWidth, + int tileHeight, + int mapWidth, + int mapHeight, + int[,] tileArray, + SortedList tilesets) + { + mTileWidth = tileWidth; + mTileHeight = tileHeight; + mMapWidth = mapWidth; + mMapHeight = mapHeight; + mTilesets = tilesets; + if (tileArray.Length == mapWidth * mapHeight) + { + mTileArray = tileArray; + } + else + { + throw new Exception("Error constructing map layer. Map size does not fit the map description."); + } + } + + /// + /// Create the map objects according to the given map array. + /// + public void CreateObjects() + { + var firstgridList = mTilesets.Keys; + for (int i = 0; i < mMapHeight; i++) + { + int horizontalOffset = (i % 2 == 0) ? (-mTileWidth / 2) : 0; + for (int j = 0; j < mMapWidth; j++) + { + int tileId = mTileArray[i, j]; + // Checks which tileset needs to be used for the specific tile ID at position [i, j] + for (int k = firstgridList.Count - 1; k >= 0; k--) + { + if (tileId == 0) + { + // This does generally nothing. But you can overwrite GenerateNullObject() for other behaviour. + TextureObject objectToInsert = GenerateNullObject(); + if (objectToInsert != null) + { + mTextureObjects.Add(objectToInsert); + } + break; + } + else if (tileId >= firstgridList[k]) + { + Tileset tileset = mTilesets.Values[k]; + int firstgrid = firstgridList[k]; + Point position = SelectPosition(j, i, horizontalOffset); + Point textureSize = new Point(tileset.TileWidth, tileset.TileHeight); + Point destination = SelectDestination(j, i, horizontalOffset, tileset.OffsetX, tileset.TileHeight, tileset.OffsetY); + Point source = SelectSource(tileId, firstgrid, tileset.TileWidth, tileset.TileHeight, tileset.Columns); + IGameObject objectToInsert; + if (tileset.Name == "houses_rear" || tileset.Name == "houses_front") + { + if (source.Y < textureSize.Y * 2) + { + int initialDamage = 0; + if (source.X / textureSize.X == 1) + { + initialDamage = 50; + } + else if (source.X / textureSize.X == 2) + { + initialDamage = 80; + } + IBuilding building = new Woodhouse(position.ToVector2(), new Rectangle(destination, textureSize), tileset.Name, source.Y % 384 == 0 ? BuildingFace.SW : BuildingFace.NO); + building.TakeDamage(initialDamage); + objectToInsert = building; + } + else + { + int initialDamage = 0; + if (source.X / textureSize.X == 1) + { + initialDamage = 60; + } + else if (source.X / textureSize.X == 2) + { + initialDamage = 100; + } + IBuilding building = new Forge(position.ToVector2(), new Rectangle(destination, textureSize), tileset.Name, source.Y % 384 == 0 ? BuildingFace.SW : BuildingFace.NO); + building.TakeDamage(initialDamage); + objectToInsert = building; + } + } + else if (tileset.Name == "castle") + { + IBuilding building = new Objects.Castle(position.ToVector2(), new Rectangle(destination, textureSize), tileset.Name, BuildingFace.SW); + objectToInsert = building; + } + else + { + objectToInsert = new TextureObject(position, + destination, + textureSize, + source, + tileset.Name); + } + mTextureObjects.Add(objectToInsert); + break; + } + } + } + } + } + + protected virtual TextureObject GenerateNullObject() + { + return null; + } + + /// + /// Loads the image files needed for drawing the tilesets. + /// + /// Content manager used for loading the ressources. + public void LoadContent(ContentManager contentManager) + { + mTextureObjects.ForEach(o => o.LoadContent(contentManager)); + } + + /// + /// Draws only the parts of the map which are visible. More efficient than the other Draw-Method. + /// Not very robust and maybe does not work correctly most layers. + /// This is because of gaps in the list of game objects. + /// + /// Sprite batch used. + /// Needed to tell which objects of the map are looked upon. + public void Draw(SpriteBatch spriteBatch, ICamera camera) + { + int tilesHorizontal = camera.ScreenSize.X / mTileWidth; + int tilesVertical = camera.ScreenSize.Y * 2 / mTileHeight; + int horizontalStart = camera.ScreenRectangle.X / mTileWidth; + int verticalStart = camera.ScreenRectangle.Y * 2 / mTileHeight; + /* + for (int i = 0; i < tilesVertical; i++) + { + for (int j = 0; j < tilesHorizontal; j++) + { + mTextureObjects[horizontalStart + j].Draw(spriteBatch); + } + } + */ + for (int j = 0; j < tilesVertical + 2; j++) + { + for (int i = 0; i < tilesHorizontal + 2; i++) + { + int index = i + horizontalStart + (j + verticalStart) * mMapWidth; + if (index < mTextureObjects.Count) + { + mTextureObjects[index].Draw(spriteBatch); + } + } + } + } + + /// + /// Extract a collision grid from the map layer. Used in pathfinding. + /// + /// A two dimensional boolean collision grid. + public bool[,] ExtractCollisions() + { + int gridHeight = (mMapHeight - 1) * mTileHeight/ CellHeight / 2; + int gridWidth = (mMapWidth - 1) * mTileWidth / CellWidth; + bool[,] collisionGrid = new bool[gridHeight, gridWidth]; + var firstgridList = mTilesets.Keys; + for (int i = 0; i < mMapHeight; i++) + { + for (int j = 0; j < mMapWidth; j++) + { + int tileId = mTileArray[i, j]; + for (int k = firstgridList.Count - 1; k >= 0; k--) + { + if (tileId >= firstgridList[k]) + { + Tileset tileset = mTilesets.Values[k]; + int firstgrid = firstgridList[k]; + tileId -= firstgrid; + bool[,] collisionData; + // Is there even collision data for the specific tile ID? + if (tileset.TileCollisions.TryGetValue(tileId, out collisionData)) + { + int cellOffset = (i % 2 == 0 ? -mTileWidth / 2 : 0) / CellWidth; + int cellsHorizontal = mTileWidth / CellWidth; + int cellsVertical = mTileHeight / CellHeight; + int iStart = (i - 1) * cellsVertical / 2 + cellsVertical - tileset.CollisionHeight + tileset.OffsetY / CellHeight; + int jStart = j * cellsHorizontal + cellOffset + tileset.OffsetX / CellWidth; + for (int iData = 0; iData < tileset.CollisionHeight; iData++) + { + for (int jData = 0; jData < tileset.CollisionWidth; jData++) + { + // Do we even need to update collisionGrid? + if (iStart + iData >= 0 && iStart + iData < gridHeight && jStart + jData >= 0 && jStart + jData < gridWidth && + collisionData[iData, jData] && !collisionGrid[iStart + iData, jStart + jData]) + { + collisionGrid[iStart + iData, jStart + jData] = collisionData[iData, jData]; + } + } + } + } + break; + } + } + } + } + return collisionGrid; + } + + public List ExtractObjects() + { + return mTextureObjects; + } + + private Point SelectDestination(int x, int y, int xOffset, int tileXOffset, int tileHeight, int tileYOffset) + { + return new Point(x * mTileWidth + xOffset + tileXOffset, + (y - 1) * (mTileHeight / 2) - tileHeight + mTileHeight + tileYOffset); + } + + private Point SelectSource(int tileId, int firstgrid, int tileWidth, int tileHeight, int tilesPerRow) + { + return new Point((tileId - firstgrid) % tilesPerRow * tileWidth, (tileId - firstgrid) / tilesPerRow * tileHeight); + } + + private Point SelectPosition(int x, int y, int xOffset) + { + return new Point(x * mTileWidth + xOffset + mTileWidth / 2, y * (mTileHeight / 2)); + } + } +} \ No newline at end of file diff --git a/V3/Map/Area.cs b/V3/Map/Area.cs new file mode 100644 index 0000000..5712c6e --- /dev/null +++ b/V3/Map/Area.cs @@ -0,0 +1,119 @@ +using System; +using System.Collections.Generic; +using Microsoft.Xna.Framework; +using V3.Objects; + +namespace V3.Map +{ + public enum AreaType + { + Village, // has no soldiers or knights, only peasants + Castle, // many knights patrolling around + Graveyard // here you can respawn zombies + } + + /// + /// Holding area data of the map. Later used for generating enemies. + /// + public sealed class Area + { + private const int DistanceHorizontal = 64; + private const int DistanceVertical = 32; + private readonly AreaType mType; + private Rectangle mArea; + private readonly double mDensity; + private readonly double mChance; + + /// + /// Gets the area type. + /// + public AreaType Type => mType; + + /// + /// Creates a new area for generating population. + /// + /// Which type of area. Determines which population is spawned. + /// The size and position of the area. + /// The population density. Together with chance. + /// The chance that a creature is actually created. + /// Name of the area as shown in the game. + // ReSharper disable once UnusedParameter.Local + public Area(string type, Rectangle data, double density = 0d, double chance = 0d, string name = "") + { + switch (type) + { + case "village": + mType = AreaType.Village; + break; + case "castle": + mType = AreaType.Castle; + break; + case "graveyard": + mType = AreaType.Graveyard; + break; + default: + throw new Exception("Error parsing the map. There is no behaviour defined for objects of type " + type + "."); + } + if (density > 1d || chance > 1d || density < 0d || chance < 0d) + { + throw new Exception("Error when parsing area data from map. Density and/or chance is not in range 0.0 to 1.0."); + } + mArea = data; + mDensity = density; + mChance = chance; + } + + /// + /// Creates the initial population for this area. + /// + /// The factory used for creating creatures. + /// Used for checking collisions when creating population. + /// + public List GetPopulation(CreatureFactory creatureFactory, Pathfinder pathfinder) + { + var population = new List(); + if (mDensity <= 0) return population; // Catch division by zero. + var rndInt = new Random(); + var rnd = new Random(); + for (double i = DistanceVertical / mDensity + mArea.Y; i < mArea.Height + mArea.Y; i += DistanceVertical / mDensity ) + { + for (double j = DistanceHorizontal / mDensity + mArea.X; j < mArea.Width + mArea.X; j += DistanceHorizontal / mDensity ) + { + if (mChance < rnd.NextDouble()) continue; + var position = new Vector2((float) j, (float) i); + if (mType == AreaType.Village) + { + ICreature peasant; + if (rnd.NextDouble() < 0.5d) + { + peasant = creatureFactory.CreateMalePeasant(position, (MovementDirection)rndInt.Next(8)); + } + else + { + peasant = creatureFactory.CreateFemalePeasant(position, (MovementDirection)rndInt.Next(8)); + } + if (!pathfinder.AllWalkable(peasant.BoundaryRectangle)) continue; + population.Add(peasant); + } + else if (mType == AreaType.Castle) + { + ICreature guard = creatureFactory.CreateKingsGuard(position, (MovementDirection)rndInt.Next(8)); + if (!pathfinder.AllWalkable(guard.BoundaryRectangle)) continue; + population.Add(guard); + } + } + } + return population; + } + + /// + /// Is a given creature standing in the area? + /// + /// Check for this creature. + /// + public bool Contains(ICreature creature) + { + return mArea.Contains(creature.Position.ToPoint()); + } + } +} \ No newline at end of file diff --git a/V3/Map/Constants.cs b/V3/Map/Constants.cs new file mode 100644 index 0000000..2de2e25 --- /dev/null +++ b/V3/Map/Constants.cs @@ -0,0 +1,12 @@ +namespace V3.Map +{ + /// + /// Constants for describing the size of the cells of the collision grid. + /// Important for pathfinding. + /// + public static class Constants + { + public const int CellHeight = 16; + public const int CellWidth = 16; + } +} \ No newline at end of file diff --git a/V3/Map/FloorLayer.cs b/V3/Map/FloorLayer.cs new file mode 100644 index 0000000..ebe05f0 --- /dev/null +++ b/V3/Map/FloorLayer.cs @@ -0,0 +1,21 @@ +using System.Collections.Generic; +using V3.Objects; + +namespace V3.Map +{ + /// + /// The floor of the map consisting of the ground to walk on, grass or water. + /// + public sealed class FloorLayer : AbstractLayer + { + public FloorLayer(int tileWidth, int tileHeight, int mapWidth, int mapHeight, int[,] tileArray, SortedList tilesets) + : base(tileWidth, tileHeight, mapWidth, mapHeight, tileArray, tilesets) + { + } + + protected override TextureObject GenerateNullObject() + { + return new TextureObject(); + } + } +} diff --git a/V3/Map/FogOfWar.cs b/V3/Map/FogOfWar.cs new file mode 100644 index 0000000..a243b60 --- /dev/null +++ b/V3/Map/FogOfWar.cs @@ -0,0 +1,107 @@ +using System.Collections.Generic; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.Graphics; +using V3.Objects; + +namespace V3.Map +{ + // ReSharper disable once ClassNeverInstantiated.Global + public sealed class FogOfWar + { + private const int FogRange = 64; + private const int SightRadius = 1000; + private Point mMapSize; + private Texture2D mFog; + private readonly List mFogRectangle = new List(); + + /// + /// Get the size of the map and create an boolean array + /// + /// the size of the map + public void LoadGrid(Point size) + { + mMapSize = size; + CreateArray(); + } + + /// + /// An array so save whether the sprites already walked on this area + /// + private void CreateArray() + { + for (int i = -FogRange; i < mMapSize.Y; i += FogRange) + { + for (int j = -FogRange * 2; j < mMapSize.X; j += FogRange) + { + mFogRectangle.Add(new Rectangle(j, i, mFog.Width, mFog.Height)); + } + } + } + + /// + /// The position from creatures which can open the fog + /// + /// creatures which are able to open the fog + public void Update(ICreature creature) + { + Ellipse creatureEllipse = new Ellipse(creature.Position, SightRadius, SightRadius); + var markedForDeletion = new List(); + foreach (var fog in mFogRectangle) + { + if (!creature.IsDead && creatureEllipse.Contains(fog.Center.ToVector2())) + { + markedForDeletion.Add(fog); + } + } + foreach (var fogToDelete in markedForDeletion) + { + mFogRectangle.Remove(fogToDelete); + } + } + + /// + /// The sprite for the fog + /// + /// + public void LoadContent(ContentManager content) + { + mFog = content.Load("Sprites/cloud"); + } + + /// + /// Try to draw fog of war efficiently. + /// + /// Sprite batch used. + public void DrawFog(SpriteBatch spriteBatch) + { + /* + var screen = camera.ScreenRectangle; + int fogPerRow = (mMapSize.X + FogRange) / FogRange; + int fogPerColumn = (mMapSize.Y + FogRange) / FogRange; + for (int i = screen.Y / FogRange; i < (screen.Y + screen.Height) / FogRange; i++) + { + for (int j = screen.X / FogRange; j < (screen.X + screen.Width) / FogRange; j++) + { + spriteBatch.Draw(mFog, mFogRectangle[i * fogPerRow], Color.Black); + } + } + */ + foreach (var fog in mFogRectangle) + { + spriteBatch.Draw(mFog, fog, Color.Black); + } + } + + public void SetFog(List fog) + { + mFogRectangle.Clear(); + mFogRectangle.AddRange(fog); + } + + public List GetFog() + { + return mFogRectangle; + } + } +} diff --git a/V3/Map/IMapManager.cs b/V3/Map/IMapManager.cs new file mode 100644 index 0000000..9333d63 --- /dev/null +++ b/V3/Map/IMapManager.cs @@ -0,0 +1,88 @@ +using System.Collections.Generic; +using System.Diagnostics.CodeAnalysis; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using V3.Camera; +using V3.Objects; + +namespace V3.Map +{ + /// + /// Manager for loading and drawing game maps. Also holds information about map attributes. + /// + [SuppressMessage("ReSharper", "UnusedMember.Global")] + public interface IMapManager + { + /// + /// A list of map areas (rectangle-sized). + /// + List Areas { get; } + + /// + /// Size of the shown map in pixels. + /// + Point SizeInPixel { get; } + /// + /// Size of the map in tiles. (Some tiles are cut off at the edges.) + /// + Point SizeInTiles { get; } + /// + /// Size of a single tile in pixels. + /// + Point TileSize { get; } + /// + /// Number of cells the pathfinding grid consists of. + /// + Point PathfindingGridSize { get; } + /// + /// Size of a single cell of the pathfinding grid in pixels. + /// + Point PathfindingCellSize { get; } + /// + /// File name of the loaded map (without suffix). + /// + string FileName { get; } + /// + /// Efficiently draw the floor layer. Only draw the tiles seen by the camera. + /// + /// + /// + void DrawFloor(SpriteBatch spriteBatch, ICamera camera); + /// + /// Load a map file and create the map layers and pathfinding information. + /// + /// Name of the map file (without suffix). + void Load(string fileName); + /// + /// Returns all objects in the objects layer. + /// + /// List of all static game objects imported from the map. + List GetObjects(); + /// + /// Returns the pathfinding grid for passing to the pathfinder. + /// + /// A grid used for pathfinding. + PathfindingGrid GetPathfindingGrid(); + /// + /// Efficiently draw the pathfinding grid. For debugging purposes. + /// + /// Sprite batch used. + /// Current camera for calculating the shown screen. + void DrawPathfindingGrid(SpriteBatch spriteBatch, ICamera camera); + + /// + /// Draws the minimap to specified position. + /// + /// Sprite batch used. + /// Where to draw the minimap and which size. + void DrawMinimap(SpriteBatch spriteBatch, Rectangle position); + + /// + /// Automatically creates an initial population from the map data and returns it. + /// + /// Factory for creating creatues. + /// Pathfinder is used for checking collisions when creating creatures. + /// Initial population in a list. + List GetPopulation(CreatureFactory creatureFactory, Pathfinder pathfinder); + } +} \ No newline at end of file diff --git a/V3/Map/MapManager.cs b/V3/Map/MapManager.cs new file mode 100644 index 0000000..f62278c --- /dev/null +++ b/V3/Map/MapManager.cs @@ -0,0 +1,97 @@ +using System.Collections.Generic; +using System.Linq; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.Graphics; +using V3.Camera; +using V3.Objects; + +namespace V3.Map +{ + // ReSharper disable once ClassNeverInstantiated.Global + public class MapManager : IMapManager + { + private TiledParser mTiledParser; + private FloorLayer mFloorLayer; + private ObjectLayer mObjectLayer; + private List mAreas; + private PathfindingGrid mPathfindingGrid; + private readonly ContentManager mContentManager; + private readonly GraphicsDeviceManager mGraphicsDeviceManager; + + public List Areas => mAreas; + + public Point SizeInPixel { get; private set; } + public Point SizeInTiles { get; private set; } + public Point TileSize { get; private set; } + public Point PathfindingGridSize { get; private set; } + public Point PathfindingCellSize { get; private set; } + public string FileName { get; private set; } + + public MapManager(ContentManager contentManager, GraphicsDeviceManager graphicsDeviceManager) + { + mContentManager = contentManager; + mGraphicsDeviceManager = graphicsDeviceManager; + } + + public void DrawFloor(SpriteBatch spriteBatch, ICamera camera) + { + mFloorLayer.Draw(spriteBatch, camera); + } + + public void Load(string fileName) + { + mTiledParser = new TiledParser(); + // Parse map data. + mTiledParser.Parse(fileName); + FileName = fileName; + TileSize = new Point(mTiledParser.TileWidth, mTiledParser.TileHeight); + SizeInTiles = new Point(mTiledParser.MapWidth, mTiledParser.MapHeight); + SizeInPixel = new Point((SizeInTiles.X - 1) * TileSize.X, SizeInTiles.Y / 2 * TileSize.Y - TileSize.Y / 2); + // Create floor layer of the map. + mFloorLayer = new FloorLayer(mTiledParser.TileWidth, mTiledParser.TileHeight, mTiledParser.MapWidth, mTiledParser.MapHeight, mTiledParser.MapLayers[0], mTiledParser.TileSets); + mFloorLayer.CreateObjects(); + mFloorLayer.LoadContent(mContentManager); + // Create object layer of the map. + mObjectLayer = new ObjectLayer(mTiledParser.TileWidth, mTiledParser.TileHeight, mTiledParser.MapWidth, mTiledParser.MapHeight, mTiledParser.MapLayers[1], mTiledParser.TileSets); + mObjectLayer.CreateObjects(); + mObjectLayer.LoadContent(mContentManager); + // Get areas from the map + mAreas = mTiledParser.Areas; + // Create pathfinding grid used in the pathfinder. + mPathfindingGrid = new PathfindingGrid(mTiledParser.MapWidth, mTiledParser.MapHeight, mTiledParser.TileWidth, mTiledParser.TileHeight); + mPathfindingGrid.LoadContent(mContentManager); + mPathfindingGrid.CreateCollisions(mFloorLayer.ExtractCollisions()); + mPathfindingGrid.CreateCollisions(mObjectLayer.ExtractCollisions()); + PathfindingGridSize = new Point(mPathfindingGrid.mGridWidth, mPathfindingGrid.mGridHeight); + PathfindingCellSize = new Point(Constants.CellWidth, Constants.CellHeight); + // Create Minimap texture from pathfinding grid. + mPathfindingGrid.CreateMinimap(mGraphicsDeviceManager.GraphicsDevice); + } + + public List GetObjects() + { + return mObjectLayer.ExtractObjects(); + } + + public List GetPopulation(CreatureFactory creatureFactory, Pathfinder pathfinder) + { + return mAreas.SelectMany(area => area.GetPopulation(creatureFactory, pathfinder)).ToList(); + } + + public PathfindingGrid GetPathfindingGrid() + { + return mPathfindingGrid; + } + + public void DrawPathfindingGrid(SpriteBatch spriteBatch, ICamera camera) + { + mPathfindingGrid.Draw(spriteBatch, camera); + } + + public void DrawMinimap(SpriteBatch spriteBatch, Rectangle position) + { + mPathfindingGrid.DrawSmallGrid(spriteBatch, position); + } + } +} \ No newline at end of file diff --git a/V3/Map/ObjectLayer.cs b/V3/Map/ObjectLayer.cs new file mode 100644 index 0000000..0e9d13c --- /dev/null +++ b/V3/Map/ObjectLayer.cs @@ -0,0 +1,16 @@ +using System.Collections.Generic; + +namespace V3.Map +{ + /// + /// The map objects which are the same layer as the moving creatutes. + /// Buildings, flowers, trees etc. + /// + public sealed class ObjectLayer : AbstractLayer + { + public ObjectLayer(int tileWidth, int tileHeight, int mapWidth, int mapHeight, int[,] tileArray, SortedList tilesets) + : base(tileWidth, tileHeight, mapWidth, mapHeight, tileArray, tilesets) + { + } + } +} \ No newline at end of file diff --git a/V3/Map/Pathfinder.cs b/V3/Map/Pathfinder.cs new file mode 100644 index 0000000..3874d0b --- /dev/null +++ b/V3/Map/Pathfinder.cs @@ -0,0 +1,455 @@ +using System.Collections.Generic; +using Microsoft.Xna.Framework; + +namespace V3.Map +{ + // ReSharper disable once ClassNeverInstantiated.Global + public class Pathfinder + { + private const int CellHeight = Constants.CellHeight; + private const int CellWidth = Constants.CellWidth; + + // An array of walkable search nodes + private SearchNode[,] mSearchNodes; + + // The width of the map + private int mLevelWidth; + + // the height of the map + private int mLevelHeight; + + // List for nodes that are available to search + private readonly List mOpenList = new List(); + + // List for nodes that are NOT available to search + private readonly List mClosedList = new List(); + + //Calculates the distance between two (vector)points + private float Heuristic(Vector2 position, Vector2 goal) + { + return (goal - position).Length(); // Manhattan distance + } + + public void LoadGrid(PathfindingGrid map) + { + mLevelWidth = map.mGridWidth; + mLevelHeight = map.mGridHeight; + InitializeSearchNodes(map); + } + + private void InitializeSearchNodes(PathfindingGrid map) + { + mSearchNodes = new SearchNode[mLevelWidth, mLevelHeight]; + + // Creates a searchnode for each tile + for (int x = 0; x < mLevelWidth; x++) + { + for (int y = 0; y < mLevelHeight; y++) + { + SearchNode node = new SearchNode(); + + node.mPosition = new Vector2(x, y); + + // Walk only on walkable tiles + node.mWalkable = map.GetIndex(x, y) == 0; + + // Stores nodes that can be walked on + if (node.mWalkable) + { + node.mNeighbors = new SearchNode[4]; + mSearchNodes[x, y] = node; + } + } + } + + for (int x = 0; x < mLevelWidth; x++) + { + for (int y = 0; y < mLevelHeight; y++) + { + SearchNode node = mSearchNodes[x, y]; + + // Note only walkable nodes + if (node == null || node.mWalkable == false) + continue; + + + // The neighbors for every node + Vector2[] neighbors = + { + new Vector2(x, y - 1), // Node above the current + new Vector2(x, y + 1), // Node below the current + new Vector2(x - 1, y), // Node to the left + new Vector2(x + 1, y) // Node to the right + }; + + for (int i = 0; i < neighbors.Length; i++) + { + Vector2 position = neighbors[i]; + + // Test whether this neighbor is part of the map + if (position.X < 0 || position.X > mLevelWidth - 1 || position.Y < 0 || + position.Y > mLevelHeight - 1) + continue; + + SearchNode neighbor = mSearchNodes[(int)position.X, (int)position.Y]; + + // Keep a reference to the nodes that can be walked on + if (neighbor == null || neighbor.mWalkable == false) + continue; + + // A reference to the neighbor + node.mNeighbors[i] = neighbor; + } + } + } + } + + // Reset the state of the search node + private void ResetSearchNodes() + { + mOpenList.Clear(); + mClosedList.Clear(); + + for (int x = 0; x < mLevelWidth; x++) + { + for (int y = 0; y < mLevelHeight; y++) + { + SearchNode node = mSearchNodes[x, y]; + + if (node == null) + continue; + + node.mInOpenList = false; + node.mInClosedList = false; + node.mDistanceTraveled = float.MaxValue; + node.mDistanceToGoal = float.MaxValue; + } + } + } + + // Returns the node with the smallest distance + private SearchNode FindBestNode() + { + SearchNode currentTile = mOpenList[0]; + + float smallestDistanceToGoal = float.MaxValue; + + // Find the closest node to the goal + for (int i = 0; i < mOpenList.Count; i++) + { + if (mOpenList[i].mDistanceToGoal < smallestDistanceToGoal) + { + currentTile = mOpenList[i]; + smallestDistanceToGoal = currentTile.mDistanceToGoal; + } + } + return currentTile; + } + + // Use parent field to trace a path from search node to start node + private List FindFinalPath(SearchNode startNode, SearchNode endNode) + { + int counter = 0; + + if (startNode == endNode) + { + return new List(); + } + + mClosedList.Add(endNode); + + SearchNode parentTile = endNode.mParent; + + // Find the best path + while (parentTile != startNode) + { + mClosedList.Add(parentTile); + parentTile = parentTile.mParent; + } + + // Path from position to goal (from tile to tile) + List betaPath = new List(); + + // Final path after RayCasting + List finalPath = new List(); + + // Reverse the path and transform into the map + for (int i = mClosedList.Count - 1; i >= 0; i--) + { + betaPath.Add(new Vector2(mClosedList[i].mPosition.X * CellWidth + 8, mClosedList[i].mPosition.Y * CellHeight + 8)); + } + + // Short the path via RayCasting + for (int i = 1; i < betaPath.Count;) + { + if (!RayCast(betaPath[counter], betaPath[i])) + { + finalPath.Add(betaPath[i - 1]); + counter = i - 1; + } + else + { + i++; + } + } + finalPath.Add(betaPath[betaPath.Count - 1]); + return finalPath; + } + + //Test Points + private Vector2 CheckStartNode(Vector2 startNode) + { + var start = startNode; + + var startXPos = startNode; + var startXNeg = startNode; + var startYPos = startNode; + var startYNeg = startNode; + + // When sprite is blocked out of map, he returns to the edge of the map + if (startNode.X > mLevelWidth - 2) + startNode.X = mLevelWidth - 2; + if (startNode.X < 2) + startNode.X = 2; + if (startNode.Y < 4) + startNode.Y = 4; + if (startNode.Y > mLevelHeight - 2) + startNode.Y = mLevelHeight - 2; + + // When sprite stays on a null-position, he goes to the nearest non null-position around that null-position + while (mSearchNodes[(int)start.X, (int)start.Y] == null) + { + if (startXPos.X < mLevelWidth) + startXPos.X++; + if (startXNeg.X > 0) + startXNeg.X--; + if (startYPos.Y < mLevelHeight) + startYPos.Y++; + if (startYNeg.Y > 0) + startYNeg.Y--; + + if (mSearchNodes[(int)startXPos.X, (int)start.Y] != null) + { + start.X = startXPos.X; + return start; + } + if (mSearchNodes[(int)startXNeg.X, (int)start.Y] != null) + { + start.X = startXNeg.X; + return start; + } + if (mSearchNodes[(int)start.X, (int)startYPos.Y] != null) + { + start.Y = startYPos.Y; + return start; + } + if (mSearchNodes[(int)start.X, (int)startYNeg.Y] != null) + { + start.Y = startYNeg.Y; + return start; + } + } + return start; + } + + private Vector2 CheckEndNode(Vector2 endNode) + { + var end = endNode; + + var endXPos = endNode; + var endXNeg = endNode; + var endYPos = endNode; + var endYNeg = endNode; + + // When goal is null-position, the goal will be the nearest non null-position around that null-position + while (mSearchNodes[(int) end.X, (int) end.Y] == null) + { + if(endXPos.X < mLevelWidth - 3) + endXPos.X++; + if(endXNeg.X > 0) + endXNeg.X--; + if(endYPos.Y < mLevelHeight - 3) + endYPos.Y++; + if(endYNeg.Y > 0) + endYNeg.Y--; + + if (endXPos.X > mLevelWidth - 3) + break; + if (endXNeg.X < 0) + break; + if (endYPos.Y > mLevelHeight - 3) + break; + if (endYNeg.Y < 0) + break; + + if (mSearchNodes[(int)endXPos.X, (int)end.Y] != null) + { + end.X = endXPos.X; + return end; + } + if (mSearchNodes[(int)endXNeg.X, (int)end.Y] != null) + { + end.X = endXNeg.X; + return end; + } + if (mSearchNodes[(int)end.X, (int)endYPos.Y] != null) + { + end.Y = endYPos.Y; + return end; + } + if (mSearchNodes[(int)end.X, (int)endYNeg.Y] != null) + { + end.Y = endYNeg.Y; + return end; + } + } + return end; + } + + // Finds the best path + public List FindPath(Vector2 startPoint, Vector2 endPoint) + { + // Start to find path if startpoint and endpoint are different + if (startPoint == endPoint) + { + return new List(); + } + + // Sprite don't walk out of the map + if (endPoint.Y > mLevelHeight - 2 || endPoint.Y < 4 || endPoint.X > mLevelWidth - 2 || endPoint.X < 2) + { + return new List(); + } + + // Test nodes for their validity + startPoint = CheckStartNode(startPoint); + endPoint = CheckEndNode(endPoint); + + /* + * Clear the open and closed lists. + * reset each's node F and G values + */ + ResetSearchNodes(); + + // Store references to the start and end nodes for convenience + SearchNode startNode = mSearchNodes[(int)startPoint.X, (int)startPoint.Y]; + SearchNode endNode = mSearchNodes[(int)endPoint.X, (int)endPoint.Y]; + + /* + * Set the start node’s G value to 0 and its F value to the + * estimated distance between the start node and goal node + * (this is where our H function comes in) and add it to the open list + */ + if (startNode != null) + { + startNode.mInOpenList = true; + + startNode.mDistanceToGoal = Heuristic(startPoint, endPoint); + startNode.mDistanceTraveled = 0; + + mOpenList.Add(startNode); + } + + /* + * While the OpenList is not empty: + */ + while (mOpenList.Count > 0) + { + // Loop the open list and find the node with the smallest F value + SearchNode currentNode = FindBestNode(); + + // If the open list ist empty or a node can't be found + if (currentNode == null) + break; + + // If the active node ist the goal node, we will find and return the path + if (currentNode == endNode) + return FindFinalPath(startNode, endNode); // Trace our path back to the start + + // Else, for each of the active node's neighbors + for (int i = 0; i < currentNode.mNeighbors.Length; i++) + { + SearchNode neighbor = currentNode.mNeighbors[i]; + + // Make sure that the neighbor can be walked on + if (neighbor == null || !neighbor.mWalkable) + continue; + + // Calculate a new G Value for the neighbors node + float distanceTraveled = currentNode.mDistanceTraveled + 1; + + // An estimate of t he distance from this node to the end node + float heuristic = Heuristic(neighbor.mPosition, endPoint); + + if (!neighbor.mInOpenList && !neighbor.mInClosedList) + { + // Set the neighbors node G value to the G value + neighbor.mDistanceTraveled = distanceTraveled; + + // Set the neighboring node's F value to the new G value + the estimated + // distance between the neighbouring node and goal node + neighbor.mDistanceToGoal = distanceTraveled + heuristic; + + // The neighbouring node's mParent property to point at the active node + neighbor.mParent = currentNode; + + // Add the neighboring node to the open list + neighbor.mInOpenList = true; + mOpenList.Add(neighbor); + } + + // Else if the neighboring node is in open or closed list + else if (neighbor.mInOpenList || neighbor.mInClosedList) + { + if (neighbor.mDistanceTraveled > distanceTraveled) + { + neighbor.mDistanceTraveled = distanceTraveled; + neighbor.mDistanceToGoal = distanceTraveled + heuristic; + + neighbor.mParent = currentNode; + } + } + } + + // Remove active node from the open list and add to the closed list + mOpenList.Remove(currentNode); + currentNode.mInOpenList = true; + + } + + // No path could be found + return new List(); + } + + // Check whether an area is completely walkable in given rectangle + public bool AllWalkable(Rectangle rectangle) + { + for (int x = rectangle.X; x <= rectangle.X + rectangle.Width; x++) + { + for (int y = rectangle.Y; y <= rectangle.Y + rectangle.Height; y++) + { + if (mSearchNodes[x / 16, y / 16] == null) + return false; + } + } + return true; + } + + //Raycasting + private bool RayCast(Vector2 start, Vector2 goal) + { + var direction = goal - start; + var currentPos = start; + direction.Normalize(); + //direction = direction * 8; + + while (Vector2.Distance(currentPos, goal) > 1f) + { + if (mSearchNodes[(int)currentPos.X / 16, (int)currentPos.Y / 16] == null) + return false; + currentPos += direction; + } + return true; + } + } +} diff --git a/V3/Map/PathfindingGrid.cs b/V3/Map/PathfindingGrid.cs new file mode 100644 index 0000000..266ea02 --- /dev/null +++ b/V3/Map/PathfindingGrid.cs @@ -0,0 +1,125 @@ +using System; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.Graphics; +using V3.Camera; + +namespace V3.Map +{ + /// + /// Tells the pathfinder where you can walk. + /// + public sealed class PathfindingGrid + { + private const int CellHeight = Constants.CellHeight; + private const int CellWidth = Constants.CellWidth; + + private readonly bool[,] mArray; + public readonly int mGridWidth; + public readonly int mGridHeight; + private Texture2D mTexture; + private Texture2D mMinimapTexture; + + public PathfindingGrid(int mapWidth, int mapHeight, int tileWidth, int tileHeight) + { + mGridHeight = (mapHeight - 1) * tileHeight / CellHeight / 2; + mGridWidth = (mapWidth - 1) * tileWidth / CellWidth; + mArray = new bool[mGridHeight, mGridWidth]; + } + + /// + /// Compares the pathfinding grid with the given collision grid and adjusts the former. + /// If a cell of the pathfinding grid is false and the cell at the same position of the + /// collision grid is true, switch false to true. + /// + /// A grid of the same size as the pathfinding grid. + public void CreateCollisions(bool[,] collisionGrid) + { + if (collisionGrid.Length == mGridWidth * mGridHeight) + { + for (int i = 0; i < mGridHeight; i++) + { + for (int j = 0; j < mGridWidth; j++) + { + if (!mArray[i, j]) + { + mArray[i, j] = collisionGrid[i, j]; + } + } + } + } + else + { + throw new Exception("Error creating the collision grid. Object layer data and collision grid data do not fit."); + } + } + + /// + /// Load content for visual representation of the pathfinding grid. + /// + /// Use this content manager. + public void LoadContent(ContentManager contentManager) + { + mTexture = contentManager.Load("Textures/pathfinder"); + //mOnePixelTexture = contentManager.Load("Sprites/WhiteRectangle"); + } + + /// + /// A visual representation of the pathfinding grid. Drawn efficiently. + /// + /// Sprite batch used for drawing. + /// For only drawing on the shown part of the map. + public void Draw(SpriteBatch spriteBatch, ICamera camera) + { + Point startPosition = camera.Location.ToPoint() / new Point(CellWidth, CellHeight); + Point tilesOnScreen = camera.ScreenSize / new Point(CellWidth, CellHeight) + new Point(1, 1) + startPosition; + for (int i = startPosition.Y; i < tilesOnScreen.Y && i < mGridHeight; i++) + { + for (int j = startPosition.X; j < tilesOnScreen.X && j < mGridWidth; j++) + { + Rectangle destinationRectangle = new Rectangle(j * CellWidth, i * CellHeight, CellWidth, CellHeight); + Rectangle sourceRectangle = new Rectangle(mArray[i, j] ? CellWidth : 0, 0, CellWidth, CellHeight); + spriteBatch.Draw(mTexture, destinationRectangle, sourceRectangle, Color.White); + } + } + } + + /// + /// Gets the value at the specified position of the collision array. + /// + /// Position at the horizontal axis. + /// Position at the vertical axis. + /// Returns 0 if you can walk at the specified position, 1 otherwise. + public int GetIndex(int cellX, int cellY) + { + //if (cellX < 0 || cellX > mGridWidth - 1 || cellY < 0 || cellY > mGridHeight - 1) + // return 0; + return mArray[cellY, cellX] ? 1 : 0; + } + + /// + /// Draws a small version of the pathfinding grid to the screen. + /// Useful for the minimap. + /// + /// Sprite batch used. + /// Where to draw in pixel coordinates and which size. In pixels. + public void DrawSmallGrid(SpriteBatch spriteBatch, Rectangle position) + { + spriteBatch.Draw(mMinimapTexture, position, Color.White); + } + + public void CreateMinimap(GraphicsDevice device) + { + Color[] colors = new Color[mGridWidth * mGridHeight]; + for (int i = 0; i < mGridHeight; i++) + { + for (int j = 0; j < mGridWidth; j++) + { + colors[i * mGridWidth + j ] = mArray[i, j] ? Color.DarkGray : Color.Green; + } + } + mMinimapTexture = new Texture2D(device, mGridWidth, mGridHeight); + mMinimapTexture.SetData(colors); + } + } +} \ No newline at end of file diff --git a/V3/Map/SearchNode.cs b/V3/Map/SearchNode.cs new file mode 100644 index 0000000..db49f14 --- /dev/null +++ b/V3/Map/SearchNode.cs @@ -0,0 +1,31 @@ +using Microsoft.Xna.Framework; + +namespace V3.Map +{ + class SearchNode + { + // Location on the map + public Vector2 mPosition; + + // If true, the sprite can walk on + public bool mWalkable; + + // + public SearchNode[] mNeighbors; + + // Previous node + public SearchNode mParent; + + // Check whether a node is in the open list + public bool mInOpenList; + + // Check whether a node is in the closed list + public bool mInClosedList; + + // DIstance from the start node to the goal node (F value) + public float mDistanceToGoal; + + // Distance traveled from the spawn point (G value) + public float mDistanceTraveled; + } +} \ No newline at end of file diff --git a/V3/Map/TiledParser.cs b/V3/Map/TiledParser.cs new file mode 100644 index 0000000..8171ecf --- /dev/null +++ b/V3/Map/TiledParser.cs @@ -0,0 +1,256 @@ +using System; +using System.Collections.Generic; +using System.Globalization; +using System.Xml; +using Microsoft.Xna.Framework; + +namespace V3.Map +{ + /// + /// Parser for the tmx format of the Tiled Map Editor. + /// Reads XML file and returns corresponding data objects. + /// + public sealed class TiledParser + { + private string mFileName; + // Map Data: + public int MapWidth { get; private set; } + public int MapHeight { get; private set; } + public int TileWidth { get; private set; } + public int TileHeight { get; private set; } + public SortedList TileSets { get; } = new SortedList(); + public List MapLayers { get; } = new List(); + public List Areas { get; } = new List(); + + /// + /// Parse the tmx file and hold data in instance properties. + /// + public void Parse(string fileName) + { + mFileName = fileName; + string directory = System.IO.Path.GetDirectoryName(System.Reflection.Assembly.GetExecutingAssembly().GetName().CodeBase); + string fullPath = directory + "/Content/Maps/" + mFileName + ".tmx"; + int p = (int)Environment.OSVersion.Platform; + if ((p == 4) || (p == 6) || (p == 128)) // Running on Unix + fullPath = fullPath.Substring(5); +#if DEBUG + Console.WriteLine("Loading Map: " + fullPath); +#endif + XmlReader reader = XmlReader.Create(fullPath); + while (reader.Read()) + { + if (reader.IsStartElement()) + { + switch (reader.Name) + { + case "map": + ParseMapData(reader); + break; + case "tileset": + ParseTilesetData(reader); + break; + case "layer": + ParseLayerData(reader); + break; + case "objectgroup": + ParseObjectgroup(reader); + break; + } + } + } + } + + private void ParseMapData(XmlReader reader) + { + while (reader.MoveToNextAttribute()) + { + switch (reader.Name) + { + case "width": + MapWidth = reader.ReadContentAsInt(); + break; + case "height": + MapHeight = reader.ReadContentAsInt(); + break; + case "tilewidth": + TileWidth = reader.ReadContentAsInt(); + break; + case "tileheight": + TileHeight = reader.ReadContentAsInt(); + break; + } + } + reader.MoveToElement(); + } + + private void ParseTilesetData(XmlReader reader) + { + if (reader.HasAttributes) + { + List tilesetAttributes = new List(); + // Read attributes firstgid, name, tilewidth, tileheight, tilecount, columns. + for (int i = 0; i < reader.AttributeCount; i++) + { + tilesetAttributes.Add(reader[i]); + } + reader.MoveToElement(); + // Read attributes for tileoffset x and y if existing. + while (reader.Read()) + { + if (reader.Name == "tileoffset") + { + if (reader.IsStartElement()) + { + for (int i = 0; i < reader.AttributeCount; i++) + { + tilesetAttributes.Add(reader[i]); + } + } + else + { + break; + } + } + else if (reader.Name == "tile" || reader.Name == "tileset") + { + break; + } + } + if (tilesetAttributes.Count == 6) + { + TileSets.Add(int.Parse(tilesetAttributes[0]), new Tileset(tilesetAttributes[1], int.Parse(tilesetAttributes[2]), + int.Parse(tilesetAttributes[3]), int.Parse(tilesetAttributes[5]))); + } + else if (tilesetAttributes.Count == 8) + { + TileSets.Add(int.Parse(tilesetAttributes[0]), new Tileset(tilesetAttributes[1], int.Parse(tilesetAttributes[2]), + int.Parse(tilesetAttributes[3]), int.Parse(tilesetAttributes[5]), + int.Parse(tilesetAttributes[6]), int.Parse(tilesetAttributes[7]))); + } + else + { + throw new Exception("Error parsing tileset element in " + mFileName + ".tmx. Does not contain necessary attributes."); + } + ParseCollisionData(reader, int.Parse(tilesetAttributes[0])); + } + } + + private void ParseLayerData(XmlReader reader) + { + while (reader.MoveToNextAttribute()) + { + if (reader.Name == "width") + { + // TODO: Try catching exceptions and throw specific ones. + int width = reader.ReadContentAsInt(); + reader.MoveToNextAttribute(); + int height = reader.ReadContentAsInt(); + reader.MoveToElement(); + reader.ReadToDescendant("data"); + MapLayers.Add(new int[height, width]); + int currentLayerIndex = MapLayers.Count - 1; + // Map data is in CSV format, therefore split at comma. + string[] layerData = reader.ReadString().Split(','); + for (int i = 0; i < height; i++) + { + for (int j = 0; j < width; j++) + { + MapLayers[currentLayerIndex][i, j] = int.Parse(layerData[i * width + j]); + } + } + } + } + reader.MoveToElement(); + } + + private void ParseCollisionData(XmlReader reader, int currentTileset) + { + do + { + if (!reader.IsStartElement() && reader.Name == "tileset") + { + // If the end of the tileset note is reached, leave loop. + break; + } + if (reader.IsStartElement() && reader.Name == "tile" && reader.HasAttributes) + { + string tileId = reader[0]; + reader.MoveToElement(); + while (reader.ReadToDescendant("property")) + { + if (reader.MoveToAttribute("name") && reader.Value == "collision") + { + reader.MoveToNextAttribute(); + string collisionData = reader.Value; + Tileset tileset = TileSets[currentTileset]; + if (tileId != null) tileset.AddCollisionData(int.Parse(tileId), collisionData); + } + } + } + } + while (reader.Read()) ; + } + + private void ParseObjectgroup(XmlReader reader) + { + do + { + if (!reader.IsStartElement() && reader.Name == "objectgroup") + break; + if (reader.IsStartElement() && reader.Name == "object") + { + ParseAreaData(reader); + } + } while (reader.Read()); + } + + private void ParseAreaData(XmlReader reader) + { + string type; + string name = ""; + double density = 0; + double chance = 0; + Rectangle rectangle; + if (reader.AttributeCount == 7) + { + name = reader[1]; + type = reader[2]; + if (!(reader[3] != null && reader[4] != null && reader[5] != null && reader[6] != null)) + return; + rectangle = new Rectangle(int.Parse(reader[3]), int.Parse(reader[4]), int.Parse(reader[5]), int.Parse(reader[6])); + } + else if (reader.AttributeCount == 6) + { + type = reader[1]; + if (!(reader[2] != null && reader[3] != null && reader[4] != null && reader[5] != null)) + return; + rectangle = new Rectangle(int.Parse(reader[2]), int.Parse(reader[3]), int.Parse(reader[4]), int.Parse(reader[5])); + } + else + { + throw new Exception("Error parsing the map. One of the objects has not the right number of attributes, specifically: " + reader.AttributeCount); + } + reader.MoveToElement(); + while (reader.Read()) + { + if (!reader.IsStartElement() && reader.Name == "properties") + break; + if (reader.Name == "property" && reader.HasAttributes) + { + if (reader[2] == null) return; + if (reader[0] == "chance") + { + chance = double.Parse(reader[2], CultureInfo.InvariantCulture); + } + else if (reader[0] == "density") + { + density = double.Parse(reader[2], CultureInfo.InvariantCulture); + } + reader.MoveToElement(); + } + } + Area area = new Area(type, rectangle, density, chance, name); + Areas.Add(area); + } + } +} diff --git a/V3/Map/Tileset.cs b/V3/Map/Tileset.cs new file mode 100644 index 0000000..aa12885 --- /dev/null +++ b/V3/Map/Tileset.cs @@ -0,0 +1,89 @@ +using System; +using System.Collections.Generic; + +namespace V3.Map +{ + /// + /// Class for holding information needed of Tilesets. Needed to draw the map. + /// + public sealed class Tileset + { + private const int CellHeight = Constants.CellHeight; + private const int CellWidth = Constants.CellWidth; + + /// + /// Name of the tileset, often the filename. + /// + public string Name { get; } + /// + /// Tile width of each tile in pixel. + /// + public int TileWidth { get; } + /// + /// Tile height of each tile in pixel. + /// + public int TileHeight { get; } + + /// + /// Columns of tiles of the tileset image. + /// + public int Columns { get; private set; } + /// + /// When tile is drawn, is there an offset needed on the X axis for correct display. + /// + public int OffsetX { get; private set; } + /// + /// + /// When tile is drawn, is there an offset needed on the Y axis for correct display. + /// + public int OffsetY { get; private set; } + /// + /// Each tile of the tileset, represented by an integer, can hold collision data consisting of a two dimensional + /// array of boolean values. Its size is described by CollisionWidth and CollisionHeight. + /// + public Dictionary TileCollisions { get; } + public int CollisionWidth => TileWidth / CellWidth; + public int CollisionHeight => TileHeight / CellHeight; + + public Tileset(string name, int tileWidth, int tileHeight, int columns, int offsetX = 0, int offsetY = 0) + { + Name = name; + TileWidth = tileWidth; + TileHeight = tileHeight; + Columns = columns; + OffsetX = offsetX; + OffsetY = offsetY; + // TODO: Fill dictionary with TiledParser. + TileCollisions = new Dictionary(); + } + + /// + /// Add an entry to the collision dictionary for the specific tile. + /// + /// The tile ID in the tileset. + /// The corresponding collision data as string of '0' and '1'. + public void AddCollisionData(int tileId, string collisionData) + { + int gridWidth = CollisionWidth; + int gridHeight = CollisionHeight; + bool[,] dataArray = new bool[gridHeight, gridWidth]; + for (int i = 0; i < gridHeight; i++) + { + for (int j = 0; j < gridWidth; j++) + { + try + { + dataArray[i, j] = collisionData[i * gridWidth + j] == '1'; + } + catch (IndexOutOfRangeException e) + { + throw new IndexOutOfRangeException("Inconsistencies with the collision data of Tile " + + tileId + " in tileset " + Name + ". Check corresponding tmx file or" + + "contact the programmer: Thomas.", e); + } + } + } + TileCollisions.Add(tileId, dataArray); + } + } +} \ No newline at end of file diff --git a/V3/Node.cs b/V3/Node.cs new file mode 100644 index 0000000..7c01820 --- /dev/null +++ b/V3/Node.cs @@ -0,0 +1,467 @@ +using System.Collections.Generic; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using V3.Objects; +using Rectangle = Microsoft.Xna.Framework.Rectangle; + +namespace V3 +{ + public sealed class Node + { + /// + /// Represents the Rectangle if a Quad gets split + /// + private Node mRt; // The rectangle on the right top + private Node mLt; // The rectangle on the left top + private Node mRb; // The rectangle on the right bottom + private Node mLb; // The rectangle on the left bottom + private readonly Node mParent; // the parent of a node + private Rectangle mRectangle; + private readonly int mPositionX; // X position of the current rectangle + private readonly int mPositionY; // Y position of the current rectangle + private readonly int mSizeX; // length of the current rectangle + private readonly int mSizeY; // width of the current rectangle + private readonly int mCenterX; // center of the current rectangle + private readonly int mCenterY; + private int mCount; + private Rectangle mCreatureRectangle; + private MovementDirection mMovementDirectionItem2; + private MovementState mMovementStateItem; + private MovementState mMovementStateItem2; + + /// + /// The list of each node where the objects in each rectangle are saved + /// + private List mObjectList = new List(); + private int Count => ObjectCount(); + + /// + /// initialize the Node + /// + /// the current Rectangle/size of the Node + /// the parent of the node + public Node(Rectangle currentRectangle, Node p) + { + mParent = p; + mRectangle = currentRectangle; + mPositionY = mRectangle.Y; + mPositionX = mRectangle.X; + mSizeX = mRectangle.Width; + mSizeY = mRectangle.Height; + mCenterY = mRectangle.Y + mRectangle.Height / 2; + mCenterX = mRectangle.X + mRectangle.Width / 2; + } + + /// + /// divided the rectangle in 4 small rectangles locaded in it self + /// + private void CreateSubnodes() + { + if (mLt == null) + { + mLt = new Node(new Rectangle(mPositionX - 1, mPositionY - 1, mSizeX / 2 + 2, mSizeY / 2 + 2), + this); + mRt = new Node(new Rectangle(mPositionX + mSizeX / 2, mPositionY - 1, mSizeX / 2 + 1, mSizeY / 2 + 2), + this); + mLb = new Node(new Rectangle(mPositionX - 1, mPositionY + mSizeY / 2, mSizeX / 2 + 2, mSizeY / 2 + 1), + this); + mRb = new Node( new Rectangle(mPositionX + mSizeX / 2, mPositionY + mSizeY / 2, mSizeX / 2 + 1, mSizeY / 2 + 1), + this); + } + } + + /// + /// This method is looking in which rectangle the object is located. + /// At first it checks in which part (right top, left top...) of the rectangle the object is + /// and if its posibible the rectangle gets split in for new rectangles the same is happening again. + /// + /// Type of Creature including their position. + public void AddtoSubNode(IGameObject item) + { + mCreatureRectangle = item.BoundaryRectangle; + + if (mRectangle.Contains(mCreatureRectangle)) + { + if (mCreatureRectangle.Right < mCenterX && (mCreatureRectangle.Y + mCreatureRectangle.Height) < mCenterY) + { + CreateSubnodes(); // splits subnode in more subnodes + mLt.AddtoSubNode(item); + } + else if (mCreatureRectangle.X > mCenterX && (mCreatureRectangle.Y + mCreatureRectangle.Height) < mCenterY) + { + CreateSubnodes(); + mRt.AddtoSubNode(item); + } + else if (mCreatureRectangle.Right < mCenterX && mCreatureRectangle.Y > mCenterY) + { + CreateSubnodes(); + mLb.AddtoSubNode(item); + } + else if (mCreatureRectangle.X > mCenterX && mCreatureRectangle.Y > mCenterY) + { + CreateSubnodes(); + mRb.AddtoSubNode(item); + } + else + { + mObjectList.Add(item); // the object gets added to the objectlist of the current node/subnode + //CheckCollission(mObjectList); + mCount++; + if (mCount == 8) + { + CheckCollission(mObjectList); + } + else if (mCount > 8) + { + mCount = 0; + } + } + } + } + + /// + /// checks if the Objects in the same Quad are intersecting + /// + /// list with the objects in the same quad + //void CheckCollission(List objectList) + void CheckCollission(List objectList) + { + // if (mParent != null) + // { + // mList2 = mParent.mObjectList; + // } + + foreach (var obj in objectList) + { + foreach (var obj2 in objectList) + { + if (Equals(obj, obj2)) + { + continue; + } + if (obj.BoundaryRectangle.Intersects(obj2.BoundaryRectangle)) + //if (obj.BoundaryRectangle.X < obj2.BoundaryRectangle.X + obj2.BoundaryRectangle.Width && + //obj.BoundaryRectangle.X + obj.BoundaryRectangle.Width > obj2.BoundaryRectangle.X && + //obj.BoundaryRectangle.Y < obj2.BoundaryRectangle.Y + obj2.BoundaryRectangle.Height && + //obj.BoundaryRectangle.Height + obj.BoundaryRectangle.Y > obj2.BoundaryRectangle.Y) + { + + if (!(obj is ICreature)) return; + if (!(obj2 is ICreature)) return; + ICreature creature = (ICreature)obj; + mMovementStateItem = creature.MovementState; + ICreature creature2 = (ICreature)obj2; + mMovementStateItem2 = creature2.MovementState; + if (mMovementStateItem != MovementState.Dying && (mMovementStateItem2 != MovementState.Dying)) + { + HandleCollision(obj, obj2); + } + } + } + } + + //if (mParent != null) + //{ + // foreach (var obj in mList2) + // { + // foreach (var obj2 in objectList) + // { + // if (obj == obj2) + // { + // continue; + // } + // if (obj.BoundaryRectangle.Intersects(obj2.BoundaryRectangle)) + // //if (obj.BoundaryRectangle.X < obj2.BoundaryRectangle.X + obj2.BoundaryRectangle.Width && + // // obj.BoundaryRectangle.X + obj.BoundaryRectangle.Width > obj2.BoundaryRectangle.X && + // // obj.BoundaryRectangle.Y < obj2.BoundaryRectangle.Y + obj2.BoundaryRectangle.Height && + // // obj.BoundaryRectangle.Height + obj.BoundaryRectangle.Y > obj2.BoundaryRectangle.Y) + // { + // if (!(obj is ICreature)) return; + // if (!(obj2 is ICreature)) return; + // //if (obj.GetType() != typeof(ICreature)) return; + // ICreature creature = (ICreature)obj; + // mMovementStateItem = creature.MovementState; + // ICreature creature2 = (ICreature)obj2; + // mMovementStateItem2 = creature2.MovementState; + // if (mMovementStateItem != MovementState.Dying && (mMovementStateItem2 != MovementState.Dying)) + // { + // HandleCollision(obj, obj2); + // } + // //mCollision = true; + // } + // } + // } + //} + } + + /// + /// If collsion is detected the object gets moved away so there is no collision anymore + /// + /// the object which collid with another object + /// the other object + //void HandleCollision(AbstractCreature item, AbstractCreature item2) + void HandleCollision(IGameObject item, IGameObject item2) + { + ICreature creature = (ICreature)item; + ICreature creature2 = (ICreature)item2; + mMovementDirectionItem2 = creature2.MovementDirection; + + if (mMovementDirectionItem2 == MovementDirection.S) + { + creature.Position = new Vector2(item.Position.X + 1, item.Position.Y); + } + if (mMovementDirectionItem2 == MovementDirection.N) + { + creature.Position = new Vector2(item.Position.X + 1, item.Position.Y); + } + else if (mMovementDirectionItem2 == MovementDirection.O) + { + creature.Position = new Vector2(item.Position.X, item.Position.Y + 1); + } + else if (mMovementDirectionItem2 == MovementDirection.W) + { + creature.Position = new Vector2(item.Position.X, item.Position.Y + 1); + } + else if (mMovementDirectionItem2 == MovementDirection.SO) + { + creature.Position = new Vector2(item.Position.X - 1, item.Position.Y); + } + else if (mMovementDirectionItem2 == MovementDirection.NO) + { + creature.Position = new Vector2(item.Position.X + 1, item.Position.Y - 1); + } + else if (mMovementDirectionItem2 == MovementDirection.NW) + { + creature.Position = new Vector2(item.Position.X - 1, item.Position.Y + 1); + } + else if (mMovementDirectionItem2 == MovementDirection.SW) + { + creature.Position = new Vector2(item.Position.X + 1, item.Position.Y); + } + else + { + creature.Position = new Vector2(item.Position.X + 1, item.Position.Y + 1); + } + } + + /// + /// Clears the QuadTree of all objects, including any objects living in its children. + /// + public void Clear() + { + // Clear out the children, if we have any + if (mLt != null) + { + mLt.Clear(); + mRt.Clear(); + mLb.Clear(); + mRb.Clear(); + } + + // Clear any objects at this level + if (mObjectList != null) + { + mObjectList.Clear(); + mObjectList = null; + } + + // Set the children to null + mLt = null; + mRt = null; + mLb = null; + mRb = null; + } + + /// + /// Get the total for all objects in this QuadTree, including children. + /// + /// The number of objects contained within this QuadTree and its children. + private int ObjectCount() + { + int count = 0; + + // Add the objects at this level + if (mObjectList != null) count += mObjectList.Count; + + // Add the objects that are contained in the children + if (mLt != null) + { + count += mLt.ObjectCount(); + count += mRt.ObjectCount(); + count += mLb.ObjectCount(); + count += mRb.ObjectCount(); + } + + return count; + } + + + /// + /// Deletes an item from this QuadTree. If the object is removed causes this Quad to have no objects in its children, + /// it's children will be removed as well. + /// + /// + public void Delete(IGameObject item) + { + if (mObjectList.Contains(item)) + { + mObjectList.Remove(item); + } + // If we didn't find the object in this tree, try to delete from its children + else if (mLt != null) + { + mLt.Delete(item); + mRt.Delete(item); + mLb.Delete(item); + mRb.Delete(item); + } + + // If all the children are empty, delete all the children + if (mLt?.Count == 0 && + mRt.Count == 0 && + mLb.Count == 0 && + mRb.Count == 0) + { + mLt = null; + mRt = null; + mLb = null; + mRb = null; + } + } + + /// + /// If the Object isnt in his old Rectangle anymore it have to move + /// the object to the parent(s) Rectangle until it fits, and optionally going back down into children + /// + /// Actuell Creature + private void Move(IGameObject item) + { + if (mParent != null && mParent.mRectangle.Contains(item.BoundaryRectangle)) + { + mParent.AddtoSubNode(item); + } + else if (mParent == null) + { + AddtoSubNode(item); + } + else + { + mParent.Move(item); + } + + } + + /// + /// If four Subnodes are empty the get deleted + /// + private void RemoveEmptyNodes() + { + // If all the children are empty, delete all the children + if (mLt?.Count == 0 && + mRt.Count == 0 && + mLb.Count == 0 && + mRb.Count == 0) + { + mLt = null; + mRt = null; + mLb = null; + mRb = null; + } + mLt?.RemoveEmptyNodes(); + mRt?.RemoveEmptyNodes(); + mLb?.RemoveEmptyNodes(); + mRb?.RemoveEmptyNodes(); + } + + + /// + /// Gibt einem alle Argumente die Innerhalb des rectangles sind zurück in der Liste objectInRecList + /// + /// Der Bereich aus dem man alle Objecte haben möchte + /// Die Liste, in der alle Objekte enthalten sind, die sich im gefragten Rectangle aufhalten + /// + public List GetObjectsInRectangle(Rectangle rectangle, List objectInRecList) + { + if (rectangle.Intersects(mRectangle)) + { + if (mObjectList != null) + { + foreach (var obj in mObjectList) + { + if (obj.GetSelf() != null) + { + objectInRecList.Add(obj); + } + } + } + if (mLt != null) + { + mLt.GetObjectsInRectangle(rectangle, objectInRecList); + mRt.GetObjectsInRectangle(rectangle, objectInRecList); + mLb.GetObjectsInRectangle(rectangle, objectInRecList); + mRb.GetObjectsInRectangle(rectangle, objectInRecList); + } + } + return objectInRecList; + } + + + /// + /// Updates the position of the object in the Quadtree. If they changed their position + /// they get deleted and added again at the correct position. + /// + public void Update1() + { + List copyList = new List(mObjectList); + //CheckCollission(mObjectList); + foreach (IGameObject obj in copyList) + { + if (!(obj is ICreature)) + continue; + Delete(obj); + if (mRectangle.Contains(obj.BoundaryRectangle)) + { + AddtoSubNode(obj); + } + // if Creature isnt there anymore -> move + else + { + Move(obj); + break; + } + } + mLt?.Update1(); + mRt?.Update1(); + mRb?.Update1(); + mLb?.Update1(); + RemoveEmptyNodes(); + } + + /// + /// Makes the Quadtree visible + /// + /// to draw the Rectangles + /// + public void DrawQuadtree(SpriteBatch spriteBatch, Texture2D texture) + { + //spriteBatch.Draw(mQuadtree.Texture, mRectangle, Color.Black); + spriteBatch.Draw(texture, new Rectangle(mPositionX, mPositionY, mSizeX, 2), Color.Black); + spriteBatch.Draw(texture, new Rectangle(mPositionX, mPositionY, 2, mSizeY), Color.Black); + spriteBatch.Draw(texture, new Rectangle(mPositionX + mSizeX, mPositionY, 2, mSizeY), Color.Black); + spriteBatch.Draw(texture, new Rectangle(mPositionX, mPositionY + mSizeY, mSizeX, 2), Color.Black); + mLt?.DrawQuadtree(spriteBatch, texture); + mRt?.DrawQuadtree(spriteBatch, texture); + mLb?.DrawQuadtree(spriteBatch, texture); + mRb?.DrawQuadtree(spriteBatch, texture); + + // Draws the rectangle of each Creature + //foreach (var obj in mObjectList) + //{ + // spriteBatch.Draw(mQuadtree.Texture, new Rectangle(obj.BoundaryRectangle.X, obj.BoundaryRectangle.Y, obj.BoundaryRectangle.Width, 5), Color.Red); + // spriteBatch.Draw(mQuadtree.Texture, new Rectangle(obj.BoundaryRectangle.X, obj.BoundaryRectangle.Y, 5, obj.BoundaryRectangle.Height), Color.Red); + // spriteBatch.Draw(mQuadtree.Texture, new Rectangle(obj.BoundaryRectangle.X + obj.BoundaryRectangle.Width, obj.BoundaryRectangle.Y, 5, obj.BoundaryRectangle.Height), Color.Red); + // spriteBatch.Draw(mQuadtree.Texture, new Rectangle(obj.BoundaryRectangle.X, obj.BoundaryRectangle.Y + obj.BoundaryRectangle.Height, obj.BoundaryRectangle.Width, 5), Color.Red); + //} + } + } +} diff --git a/V3/Objects/AbstractBuilding.cs b/V3/Objects/AbstractBuilding.cs new file mode 100644 index 0000000..bc6061c --- /dev/null +++ b/V3/Objects/AbstractBuilding.cs @@ -0,0 +1,110 @@ +using System; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.Graphics; + +namespace V3.Objects +{ + public abstract class AbstractBuilding : IBuilding + { + private readonly string mTextureName; + private Texture2D mTexture; + private readonly BuildingFace mFacing; + private Rectangle mTilesetRectangle; + + public Vector2 Position { get; set; } + protected abstract int MaxRobustness { get; } + public abstract int Robustness { get; protected set; } + public abstract string Name { get; } + public virtual int MaxGivesWeapons { get; protected set; } + private bool mIsDestroyed; + public Rectangle BoundaryRectangle { get; } + public int Id { get; } + + protected AbstractBuilding(Vector2 position, Rectangle size, string textureName, BuildingFace facing) + { + Position = position; + Id = IdGenerator.GetNextId(); + // TODO: Hella ugly code + mTilesetRectangle = size; + // Boundary rectangle is smaller than the texture size: + if (this is Castle) + { + BoundaryRectangle = new Rectangle(size.X + 96, size.Y + 296, 900, 500); + } + else + { + BoundaryRectangle = new Rectangle(size.X, size.Y + size.Height / 2, size.Width * 4 / 5, size.Height / 2); + } + mTextureName = textureName; + mFacing = facing; + } + + public void Draw(SpriteBatch spriteBatch) + { + int status = 0; + if (mIsDestroyed) + { + status = 2; + } + else if (Robustness < MaxRobustness / 2) + { + status = 1; + } + Rectangle source = new Rectangle(status * mTilesetRectangle.Width, (mFacing == BuildingFace.SW ? 0 : 1) * mTilesetRectangle.Height + (this is Forge ? 384 : 0), mTilesetRectangle.Width, mTilesetRectangle.Height); + spriteBatch.Draw(mTexture, mTilesetRectangle, source, Color.White); + } + + + public void LoadContent(ContentManager contentManager) + { + mTexture = contentManager.Load("Textures/" + mTextureName); + //mOnePixelTexture = contentManager.Load("Sprites/WhiteRectangle"); + } + + public void TakeDamage(int damage) + { + if (Robustness > 0) + { + Robustness -= damage; + } + + if (Robustness <= 0) + { + Destroyed(); + } + } + + public void UpgradeCounter() + { + MaxGivesWeapons -= 1; + } + + + private void Destroyed() + { + mIsDestroyed = true; + } + + public IGameObject GetSelf() + { + return this; + } + + public override bool Equals(Object obj) + { + if (obj == null) + return false; + if (obj == this) + return true; + if (!(obj is IGameObject)) + return false; + return Id.Equals(((IGameObject) obj).Id); + } + + public override int GetHashCode() + { + return Id; + } + } +} diff --git a/V3/Objects/AbstractCreature.cs b/V3/Objects/AbstractCreature.cs new file mode 100644 index 0000000..a4ac419 --- /dev/null +++ b/V3/Objects/AbstractCreature.cs @@ -0,0 +1,911 @@ +using System; +using System.Collections.Generic; +using Castle.Core.Internal; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Audio; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.Graphics; +using V3.Camera; +using V3.Data; +using V3.Map; +using V3.Objects.Movement; +using V3.Objects.Sprite; + +namespace V3.Objects +{ + /// + /// Abstract class for deriving all moving objects in the game, + /// be it the player, his minions or the enemy. + /// + public abstract class AbstractCreature : ICreature + { + // ************************************************** + // Internal variables, managers and values. + protected virtual Point CreatureSize { get; } = new Point(24); + protected virtual Point BoundaryShift { get; } = new Point(-12, -16); + protected virtual Point SelectionSize { get; } = new Point(48, 64); + protected virtual Point SelectionShift { get; } = new Point(-24, -40); + /// + /// Array of sprites for drawing the creature. Can have up to four entries for (ordered): Body, Head, Weapon, Offhand + /// + protected abstract ISpriteCreature[] Sprite { get; } + protected abstract IMovable MovementScheme { get; } + protected abstract CreatureType Type { get; } + private Texture2D mOnePixelTexture; + private Texture2D mSelectionTexture; + private readonly Pathfinder mPathfinder; + private readonly ContentManager mContentManager; + private readonly IOptionsManager mOptionsManager; + private AchievementsAndStatistics mAchievementsAndStatistics; + private static readonly Random sRandom = new Random(); + private static readonly object sYncLock = new object(); + private List mArrowList = new List(); + +#if NO_AUDIO +#else + private SoundEffect mSoundEffect; + private SoundEffectInstance mSoundEffectInstance; + private SoundEffect mSoundEffectHorse; + private SoundEffectInstance mSoundEffectInstanceHorse; + private SoundEffect mSoundEffectKnight; + private SoundEffectInstance mSoundEffectInstanceKnight; + private SoundEffect mSoundEffectFight; + private SoundEffectInstance mSoundEffectInstanceFight; + private SoundEffect mSoundEffectMeatball; + private SoundEffectInstance mSoundEffectInstanceMeatball; +#endif + private bool mIsDead; + //private float mReculate = 1.0f; + + // ************************************************** + // Public variables and important attributes of the creature: + public abstract string Name { get; protected set; } + public abstract int Life { get; protected set; } + public abstract int MaxLife { get; protected set; } + public abstract int Speed { get; } + public abstract int Attack { get; protected set; } + public abstract int AttackRadius { get; protected set; } + public abstract int SightRadius { get; protected set; } + public abstract TimeSpan TotalRecovery { get;} + public abstract TimeSpan Recovery { get; set; } + public Vector2 Position { get; set; } + public Vector2 InitialPosition { private get; set; } + public abstract Faction Faction { get; } + public int Id { get; } + + public bool IsDead + { + get { return Life <= 0; } + } + + public bool IsUpgraded { get; set; } + + public abstract IBuilding IsAttackingBuilding { get; set; } + public MovementDirection MovementDirection { get; set; } + public MovementState MovementState { get; set; } = MovementState.Idle; + public Rectangle SelectionRectangle => new Rectangle(Position.ToPoint() + SelectionShift, SelectionSize); + public Rectangle BoundaryRectangle => new Rectangle(Position.ToPoint() + BoundaryShift, CreatureSize); + public bool IsSelected { get; set; } + private static int sMaxNumberOfSoundHorse; + private static int sMaxNumberOfSoundMeatball; + private static int sMaxNumberOfSoundZombie; + private static int sMaxNumberOfSoundKnight; + + public abstract ICreature IsAttacking { get; set; } + + /// + /// Color of the rectangle displayed when creature is selected. + /// + protected virtual Color SelectionColor + { + get + { + switch (Faction) + { + case Faction.Undead: + return Color.Red; + case Faction.Kingdom: + return Color.Blue; + case Faction.Plebs: + return Color.Green; + default: + return Color.Gray; + } + } + } + + protected AbstractCreature(ContentManager contentManager, Pathfinder pathfinder, IOptionsManager optionsManager, AchievementsAndStatistics achievementsAndStatistics) + { + mPathfinder = pathfinder; + mContentManager = contentManager; + mOptionsManager = optionsManager; + mAchievementsAndStatistics = achievementsAndStatistics; + Id = IdGenerator.GetNextId(); + LoadContent(mContentManager); + } + + /// + /// The specific creature takes damage. If its life falls below zero it dies. + /// + /// Amount of received damage. + public void TakeDamage(int damage) + { + if (Life > 0) + { + Life -= damage; + } + + if (Life <= 0) + { + Die(); + } + } + + /// + /// Loads content files needed for drawing the creature. + /// + /// Content manager used. + public void LoadContent(ContentManager contentManager) + { + Sprite.ForEach(e => e?.Load(contentManager)); + mOnePixelTexture = contentManager.Load("Sprites/WhiteRectangle"); + mSelectionTexture = contentManager.Load("Sprites/selection"); +#if NO_AUDIO +#else + try + { + mSoundEffect = contentManager.Load("Sounds/walking"); + mSoundEffectInstance = mSoundEffect.CreateInstance(); + mSoundEffectHorse = contentManager.Load("Sounds/SkeletonHorse"); + mSoundEffectInstanceHorse = mSoundEffectHorse.CreateInstance(); + mSoundEffectKnight = contentManager.Load("Sounds/Knight"); + mSoundEffectInstanceKnight = mSoundEffectKnight.CreateInstance(); + mSoundEffectFight = contentManager.Load("Sounds/punch"); + mSoundEffectInstanceFight = mSoundEffectFight.CreateInstance(); + mSoundEffectMeatball = contentManager.Load("Sounds/Monster_Gigante-Doberman-1334685792"); + mSoundEffectInstanceMeatball = mSoundEffectMeatball.CreateInstance(); + } + catch (DllNotFoundException) + { + // HACK: ignore sound-related errors as the sound is currently + // not working on the pool computers + } + catch (NoAudioHardwareException) + { + // HACK: ignore sound-related errors as the sound is currently + // not working on the pool computers + } +#endif + } + + /// + /// The creature should move to the specified destination if possible. + /// + /// The desired destination. + public void Move(Vector2 destination) + { + MovementScheme.FindPath(mPathfinder, Position, destination); + } + + public void Update(GameTime gameTime, ICreature playerCharacter, + bool rightButtonPressed, Vector2 rightButtonPosition, Quadtree quadtree, ICamera camera) + { + // If Creature is dead, don't update anymore. + Sprite.ForEach(e => e?.PlayAnimation(gameTime)); + if (mIsDead) + { + return; + } + bool showedByCamera = camera.ScreenRectangle.Contains(Position); +#if NO_AUDIO +#else + + // update the volume according to the current setting + if (mSoundEffectInstance != null) + mSoundEffectInstance.Volume = mOptionsManager.Options.GetEffectiveVolume()*0.1f; + if (mSoundEffectInstanceHorse != null) + mSoundEffectInstanceHorse.Volume = mOptionsManager.Options.GetEffectiveVolume() * 0.07f; + if (mSoundEffectInstanceKnight != null) + mSoundEffectInstanceKnight.Volume = mOptionsManager.Options.GetEffectiveVolume() * 0.07f; + if (mSoundEffectInstanceFight != null) + mSoundEffectInstanceFight.Volume = mOptionsManager.Options.GetEffectiveVolume() * 0.07f; + if (mSoundEffectInstanceMeatball != null) + mSoundEffectInstanceMeatball.Volume = mOptionsManager.Options.GetEffectiveVolume() * 0.07f; +#endif + if (MovementScheme.IsMoving) + { + MovementState = MovementState.Moving; + Position += MovementScheme.GiveNewPosition(Position, Speed); + MovementDirection = MovementScheme.GiveMovementDirection(); +#if NO_AUDIO +#else + try + { + if (showedByCamera) + { + if ((this is Zombie || this is FemalePeasant || this is MalePeasant || this is Necromancer) && + sMaxNumberOfSoundZombie < 3) + { + if (mSoundEffectInstance != null) + { + mSoundEffectInstance.Play(); + sMaxNumberOfSoundZombie++; + } + + } + if (this is SkeletonHorse && sMaxNumberOfSoundHorse < 3) + { + if (mSoundEffectInstanceHorse != null) + { + mSoundEffectInstanceHorse.Play(); + sMaxNumberOfSoundHorse++; + } + + } + if (this is Knight && sMaxNumberOfSoundKnight < 3) + { + if (mSoundEffectInstanceKnight != null) + { + mSoundEffectInstanceKnight.Play(); + sMaxNumberOfSoundKnight++; + } + + } + if (this is Meatball && sMaxNumberOfSoundMeatball < 3) + { + if (mSoundEffectInstanceMeatball != null) + { + mSoundEffectInstanceMeatball.Play(); + sMaxNumberOfSoundMeatball++; + } + + } + } + } + catch (InstancePlayLimitException) + { + // HACK: ignore sound-related errors as the sound is currently + // not working on the pool computers + } +#endif + } + else + { +#if NO_AUDIO +#else + if (mSoundEffectInstance != null) + { + mSoundEffectInstance.Stop(); + sMaxNumberOfSoundZombie--; + } + if (mSoundEffectInstanceHorse != null) + { + mSoundEffectInstanceHorse.Stop(); + sMaxNumberOfSoundHorse--; + } + if (mSoundEffectInstanceKnight != null) + { + mSoundEffectInstanceKnight.Stop(); + sMaxNumberOfSoundKnight--; + } + + if (mSoundEffectInstanceMeatball != null) + { + mSoundEffectInstanceMeatball.Stop(); + sMaxNumberOfSoundMeatball--; + } +#endif + MovementState = MovementState.Idle; + } + if (IsDead) + { + if (mSoundEffectInstance != null) + { + mSoundEffectInstance.Stop(); + sMaxNumberOfSoundZombie--; + } + if (mSoundEffectInstanceHorse != null) + { + mSoundEffectInstanceHorse.Stop(); + sMaxNumberOfSoundHorse--; + } + if (mSoundEffectInstanceKnight != null) + { + mSoundEffectInstanceKnight.Stop(); + sMaxNumberOfSoundKnight--; + } + + if (mSoundEffectInstanceMeatball != null) + { + mSoundEffectInstanceMeatball.Stop(); + sMaxNumberOfSoundMeatball--; + } + } + + /* + * + * Random movement of Zombies + * + */ + #region Random Movement + Ellipse necroArea = new Ellipse(new Vector2((int)playerCharacter.Position.X, (int)playerCharacter.Position.Y), 1280, 640); + float necroDistance = Vector2.Distance(Position, playerCharacter.Position); + List randomMoveVector = new List(); + + + int rndX = RandomNumber(0, 20); + int rndY = RandomNumber(0, 20); + + randomMoveVector.Add(new Vector2(rndX, rndY)); + randomMoveVector.Add(new Vector2(-rndX, -rndY)); + randomMoveVector.Add(new Vector2(rndX, -rndY)); + randomMoveVector.Add(new Vector2(-rndX, rndY)); + + int rndNumber; + + if (!(this is Necromancer) && + Faction.Equals(Faction.Undead) && + MovementState == MovementState.Idle && + !necroArea.Contains(Position)) + { + rndNumber = RandomNumber(1, 60); + if (rndNumber == 7) + { + int rndMoveVector = RandomNumber(0, 400); + Move(Position + randomMoveVector[rndMoveVector%4]); + } + } + if (Faction.Equals(Faction.Plebs)) + { + rndNumber = RandomNumber(1, 60); + if (rndNumber == 7) + { + int rndMoveVector = RandomNumber(0, 400); + Move(Position + randomMoveVector[rndMoveVector%4]); + } + + } + #endregion + + List defenders = new List(); + if (IsAttacking == null) + { + // Get the quadtree of the sight radius. + defenders = quadtree.GetObjectsInRectangle(new Rectangle((int) Position.X - SightRadius/2, (int) Position.Y - SightRadius/2, SightRadius, SightRadius)); + // Returns if nothing is in sight. + if (defenders.Count == 0) return; + } + + bool attacking = false; + + /* + * + * COMMAND ATTACKING OF BUILDINGS + * + */ + #region Command Attack + + // Distance between Undead and Necromancer + if (Faction.Equals(Faction.Undead) && !(this is Necromancer)) + { + // If Undead are in sight distance of the Necromancer, do stuff. + if (IsSelected && (int)necroDistance <= playerCharacter.AttackRadius) + { + // Get all the objects of the quadtree of the sightradius of the Necromancer + if (rightButtonPressed) + { + IsAttackingBuilding = null; + var objectsUnderMouse = quadtree.GetObjectsInRectangle(new Rectangle(rightButtonPosition.ToPoint(), new Point(1, 1))); + foreach (var obj in objectsUnderMouse) + { + var building = obj as IBuilding; + if (building == null || !building.BoundaryRectangle.Contains(rightButtonPosition) || building.Robustness == 0) continue; + IsAttackingBuilding = building; + } + } + } + if (IsAttackingBuilding != null ) + { + if ((int)Vector2.Distance(Position, ComputeMoVector(IsAttackingBuilding)) <= AttackRadius && IsAttackingBuilding.Robustness >= 0) // (int)Vector2.Distance(Position, IsAttackingBuilding.Position) <= AttackRadius * 2 + { + //var building = IsAttacking as IBuilding; + // Attacking + Recovery -= gameTime.ElapsedGameTime; + if (Recovery < TimeSpan.Zero) + { + Recovery = TimeSpan.Zero; + } + MovementState = MovementState.Attacking; // PlayAnimationOnce(MovementState.Attacking, TotalRecovery); + if (Recovery <= TimeSpan.Zero) + { + IsAttackingBuilding.TakeDamage(Attack); + Recovery = TotalRecovery; // Cooldown + + // Throw an arrow + if (AttackRadius > 300) + CreateArrow(Position, IsAttackingBuilding.Position); + } + // If house is dead. + if (IsAttackingBuilding.Robustness <= 20) + { + MovementState = MovementState.Idle; + + // Undead getting stronger if building is dead. + switch (IsAttackingBuilding.Name) + { + case "Schmiede": + if (IsAttackingBuilding.MaxGivesWeapons > 0 && !IsUpgraded) + { + MaxLife += 20; + Life += 20; + IsUpgraded = true; + IsAttackingBuilding.UpgradeCounter(); + } + break; + case "Holzhaus": + if (IsAttackingBuilding.MaxGivesWeapons > 0) + { + if (this is Skeleton && !IsUpgraded) + { + ChangeEquipment(EquipmentType.Body, new SkeletonArcherSprite()); + AttackRadius += 500; + SightRadius += 500; + IsUpgraded = true; + IsAttackingBuilding.UpgradeCounter(); + } + if (this is Zombie && !IsUpgraded) + { + ChangeEquipment(EquipmentType.Body, new ZombieWithClubSprite()); + Attack += 10; + IsUpgraded = true; + IsAttackingBuilding.UpgradeCounter(); + } + } + break; + } + + if (IsAttackingBuilding.Robustness <= 0) IsAttackingBuilding = null; + } + } + else + { + Move(ComputeMoVector(IsAttackingBuilding)); + } + } + } + + #endregion + foreach (var arrow in mArrowList) + { + arrow.UpdateArrow(); + } + /* + * + * AUTO ATTACKING OF CREATURES + * + */ + #region Auto-Attack + + // Don't auto attack if Zombie got command from Necromancer. + if (IsAttackingBuilding != null) return; + + if (IsAttacking == null) + { + List creatures = new List(); + foreach (var defender in defenders) + { + var creature = defender as ICreature; + if (creature == null) continue; + creatures.Add(creature); + } + + ICreature attackableCreature = null; + float sightDistance = SightRadius; + + // Compute the nearest enemy. + foreach (var defender in creatures) + { + // Zombies and Knights only. + if (Faction.Equals(Faction.Undead) || Faction.Equals(Faction.Kingdom)) + { + // If attacker-type == defender-type go to next possible defender. + if ((Faction.Equals(Faction.Undead) && !defender.Faction.Equals(Faction.Undead)) || + (Faction.Equals(Faction.Kingdom) && defender.Faction.Equals(Faction.Undead))) + { + if (defender.Life > 0) + { + // Compute the distance of attacker and possible defender. + float distanceTest = Vector2.Distance(Position, defender.Position); + + if (distanceTest <= sightDistance) + { + sightDistance = distanceTest; + attackableCreature = defender; + } + // IsAttacking = defender; + if (attackableCreature != null) + { + IsAttacking = defender; + + } + } + } + } + } + if (attackableCreature == null) + { + IsAttacking = null; + } + } + + if (IsAttacking == null) return; + /* + * + * ATTACKING OF CREATURES + * + */ + if ((int)Vector2.Distance(Position, IsAttacking.Position) > AttackRadius && + !MovementScheme.IsMoving) + { + // Do not move if attacker is already in attackrange + if (!attacking) + { + Move(ComputeMoVector(IsAttacking)); + } + } + + if (IsAttacking.IsDead || (int)Vector2.Distance(Position, IsAttacking.Position) > SightRadius) + { + IsAttacking = null; + MovementState = MovementState.Idle; + return; + } + // Attacking + Recovery -= gameTime.ElapsedGameTime; + if (Recovery < TimeSpan.Zero) + { + Recovery = TimeSpan.Zero; + } + + // If attacker is in the attack radius of defender + if ((int)Vector2.Distance(Position, IsAttacking.Position) <= AttackRadius) + { + if (Recovery <= TimeSpan.Zero) + { + IsAttacking.TakeDamage(Attack); + PlayAnimationOnce(MovementState.Attacking, TotalRecovery); + Recovery = TotalRecovery; // Cooldown + + // Throw an arrow + if (AttackRadius > 300 && IsAttacking != null) + CreateArrow(Position, IsAttacking.Position); + } + } + + #endregion + } + + public void PlayAnimationOnce(MovementState animation, TimeSpan duration) + { + Sprite.ForEach(e => e.PlayOnce(animation, duration)); + } + + /// + /// Draw the creature on the screen. + /// + /// Sprite batch used for drawing. + public void Draw(SpriteBatch spriteBatch) + { + if (IsSelected) DrawSelection(spriteBatch); + Sprite.ForEach(e => e?.Draw(spriteBatch, Position, MovementState, MovementDirection)); + if (IsSelected) DrawLifeRectangle(spriteBatch); + foreach (var arrow in mArrowList) + { + arrow.DrawArrow(spriteBatch); + } + } + + public void DrawStatic(SpriteBatch spriteBatch, Point position) + { + Sprite.ForEach(e => e?.DrawStatic(spriteBatch, position, MovementState.Idle, MovementDirection.S)); + } + + protected virtual void Die() + { + if (Faction == Faction.Plebs || Faction == Faction.Kingdom) + { + mAchievementsAndStatistics.mHundredDeadCorpses += 1; + mAchievementsAndStatistics.mUndeadArmy += 1; + mAchievementsAndStatistics.mRightHandOfDeath += 1; + mAchievementsAndStatistics.mKilledCreatures += 1; + } + else if (Faction == Faction.Undead) + { + mAchievementsAndStatistics.mLostServants += 1; + } + mIsDead = true; + Life = 0; + MovementState = MovementState.Dying; + } + + private void DrawSelection(SpriteBatch spriteBatch) + { + // TODO: Remove the magic vector and adjust position. + spriteBatch.Draw(mSelectionTexture, Position - new Vector2(32, 16), SelectionColor); + /* + spriteBatch.Draw(mOnePixelTexture, new Rectangle(BoundaryRectangle.X, BoundaryRectangle.Y, BoundaryRectangle.Width, 2), SelectionColor); + spriteBatch.Draw(mOnePixelTexture, new Rectangle(BoundaryRectangle.X, BoundaryRectangle.Y + BoundaryRectangle.Height, BoundaryRectangle.Width, 2), SelectionColor); + spriteBatch.Draw(mOnePixelTexture, new Rectangle(BoundaryRectangle.X, BoundaryRectangle.Y, 2, BoundaryRectangle.Height), SelectionColor); + spriteBatch.Draw(mOnePixelTexture, new Rectangle(BoundaryRectangle.X + BoundaryRectangle.Width, BoundaryRectangle.Y, 2, BoundaryRectangle.Height), SelectionColor); + */ + } + + private void DrawLifeRectangle(SpriteBatch spriteBatch) + { + var backgroundRectangle = new Rectangle(SelectionRectangle.X, SelectionRectangle.Y - 12, SelectionRectangle.Width, SelectionRectangle.Height / 10); + var lifeBarRectangle = new Rectangle(SelectionRectangle.X + 2, SelectionRectangle.Y - 11, SelectionRectangle.Width - 3, SelectionRectangle.Height / 10 - 2); + spriteBatch.Draw(mOnePixelTexture, backgroundRectangle, Color.Black * 0.7f); + spriteBatch.Draw(mOnePixelTexture, new Rectangle(lifeBarRectangle.X, lifeBarRectangle.Y, lifeBarRectangle.Width * Life / MaxLife, lifeBarRectangle.Height), Color.Firebrick); + } + + /// + /// Change the equipment/sprite of the creature to something other. + /// + /// Which part of the equipment should be changed. + /// Which sprite to use instead. + public void ChangeEquipment(EquipmentType equipmentType, ISpriteCreature sprite) + { + if (Sprite.Length > (int) equipmentType) + { + sprite.Load(mContentManager); + Sprite[(int)equipmentType] = sprite; + } +#if DEBUG + else + { + throw new Exception("Creature does not have a " + equipmentType.ToString() + " slot. For further information talk to Thomas."); + } +#endif + } + + /// + /// Returns the object instance without modifications. + /// + /// This object. + public virtual IGameObject GetSelf() + { + return this; + } + + public void ResetPosition() + { + Position = InitialPosition; + } + + #region Compute Move Distance + /// + /// Returns vector for the moving distance to attack. + /// + /// Vector. + private Vector2 ComputeMoVector(IGameObject gameObject) + { + Vector2 goToPosition = new Vector2(Position.X, Position.Y); + + /* + * P + * D + * + */ + if (Position.X <= gameObject.BoundaryRectangle.Left && + Position.Y <= gameObject.BoundaryRectangle.Top) + { + goToPosition = + new Vector2(gameObject.BoundaryRectangle.Left - AttackRadius * 0.5f, + gameObject.BoundaryRectangle.Top - AttackRadius * 0.5f); + } + /* + * P + * D + * + */ + if (Position.X >= gameObject.BoundaryRectangle.Left && + Position.X <= gameObject.BoundaryRectangle.Right && + Position.Y <= gameObject.BoundaryRectangle.Top) + { + goToPosition = new Vector2(Position.X, + gameObject.BoundaryRectangle.Top - AttackRadius * 0.5f); + } + /* + * P + * D + * + */ + if (Position.X >= gameObject.BoundaryRectangle.Right && + Position.Y <= gameObject.BoundaryRectangle.Top) + { + goToPosition = + new Vector2(gameObject.BoundaryRectangle.Right - AttackRadius * 0.5f, + gameObject.BoundaryRectangle.Top - AttackRadius * 0.5f); + } + /* + * + * D P + * + */ + if (Position.X >= gameObject.BoundaryRectangle.Right && + Position.Y <= gameObject.BoundaryRectangle.Bottom && + Position.Y >= gameObject.BoundaryRectangle.Top) + { + goToPosition = + new Vector2(gameObject.BoundaryRectangle.Right - AttackRadius * 0.5f, + Position.Y); + } + /* + * + * D + * P + */ + if (Position.X >= gameObject.BoundaryRectangle.Right && + Position.Y >= gameObject.BoundaryRectangle.Bottom) + { + goToPosition = + new Vector2(gameObject.BoundaryRectangle.Right - AttackRadius * 0.5f, + gameObject.BoundaryRectangle.Bottom - AttackRadius * 0.5f); + } + /* + * + * D + * P + */ + if (Position.X >= gameObject.BoundaryRectangle.Left && + Position.X <= gameObject.BoundaryRectangle.Right && + Position.Y >= gameObject.BoundaryRectangle.Bottom) + { + goToPosition = new Vector2(Position.X, + gameObject.BoundaryRectangle.Bottom - AttackRadius * 0.5f); + } + /* + * + * D + * P + */ + if (Position.X <= gameObject.BoundaryRectangle.Left && + Position.Y >= gameObject.BoundaryRectangle.Bottom) + { + goToPosition = + new Vector2(gameObject.BoundaryRectangle.Left - AttackRadius * 0.5f, + gameObject.BoundaryRectangle.Bottom - AttackRadius * 0.5f); + } + /* + * + * P D + * + */ + if (Position.X <= gameObject.BoundaryRectangle.Left && + Position.Y <= gameObject.BoundaryRectangle.Bottom && + Position.Y >= gameObject.BoundaryRectangle.Top) + { + goToPosition = + new Vector2(gameObject.BoundaryRectangle.Left - AttackRadius * 0.5f, + Position.Y); + } + + return goToPosition; + } + #endregion + + public override bool Equals(Object obj) + { + if (obj == null) + return false; + if (obj == this) + return true; + if (!(obj is IGameObject)) + return false; + return Id.Equals(((IGameObject) obj).Id); + } + + public override int GetHashCode() + { + return Id; + } + + /// + /// Returns synchronized random value. + /// + /// Vector. + /// Lower bound for random value. + /// Upper bound +1 for random value. + private static int RandomNumber(int min, int max) + { + // synchronize + lock (sYncLock) + { + return sRandom.Next(min, max); + } + } + + public void Heal(int amount) + { + if (Life + amount < MaxLife) + { + Life += amount; + } + else + { + Life = MaxLife; + } + } + + public void Empower(int modifier) + { + MaxLife *= modifier; + Life *= modifier; + } + + private void CreateArrow(Vector2 start, Vector2 goal) + { + if (mArrowList.Count >= 60) mArrowList.Clear(); + Arrow arrow = new Arrow(start, goal); + arrow.LoadArrow(mContentManager); + mArrowList.Add(arrow); + } + + /// + /// Save this creature’s data to a CreatureData object. + /// + /// the CreatureData object with the status of this creature + public virtual CreatureData SaveData() + { + var creatureData = new CreatureData(); + creatureData.Type = Type; + creatureData.Id = Id; + creatureData.Life = Life; + creatureData.MaxLife = MaxLife; + creatureData.Attack = Attack; + creatureData.Recovery = Recovery; + creatureData.IsUpgraded = IsUpgraded; + creatureData.PositionX = Position.X; + creatureData.PositionY = Position.Y; + creatureData.MovementDirection = MovementDirection; + creatureData.MovementState = MovementState; + creatureData.MovementData = MovementScheme.SaveData(); + // references + if (IsAttacking != null) + creatureData.IsAttackingId = IsAttacking.Id; + return creatureData; + } + + /// + /// Restore the creature's state from the given data. + /// + /// the state of the creature to restore + public virtual void LoadData(CreatureData creatureData) + { + // ID is set by IdGenerator.SetIdOnce + Life = creatureData.Life; + MaxLife = creatureData.MaxLife; + Attack = creatureData.Attack; + Recovery = creatureData.Recovery; + IsUpgraded = creatureData.IsUpgraded; + Position = new Vector2(creatureData.PositionX, creatureData.PositionY); + MovementDirection = creatureData.MovementDirection; + MovementState = creatureData.MovementState; + MovementScheme.LoadData(creatureData.MovementData); + + if (Life <= 0) + Die(); + } + + /// + /// Restore the creature's references to other creatures from the given data. + /// + /// the state of the creature to restore + /// the list of all creatures by ID + public virtual void LoadReferences(CreatureData data, Dictionary creatures) + { + if (creatures.ContainsKey(data.IsAttackingId)) + IsAttacking = creatures[data.IsAttackingId]; + } + } +} diff --git a/V3/Objects/Arrow.cs b/V3/Objects/Arrow.cs new file mode 100644 index 0000000..57200b2 --- /dev/null +++ b/V3/Objects/Arrow.cs @@ -0,0 +1,109 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.Graphics; +using V3.Objects.Sprite; + +namespace V3.Objects +{ + public sealed class Arrow + { + //Drawing an arrow + private const int SpeedModifier = 10; + private readonly ArrowSprite mArrow; + private Vector2 mArrowPosition; + private Vector2 mArrowGoal; + private Vector2 mDirection; + private bool mArrowDraw; + private readonly MovementDirection mMovementDirection; + + public Arrow(Vector2 start, Vector2 goal) + { + mArrowPosition = start; + mArrowGoal = goal; + mDirection = goal - start; + mDirection.Normalize(); + mMovementDirection = GiveMovementDirection(mDirection); + mArrow = new ArrowSprite(); + mArrowDraw = true; + } + + public void LoadArrow(ContentManager contentManager) + { + mArrow.Load(contentManager); + } + + public void DrawArrow(SpriteBatch spriteBatch) + { + if (mArrowDraw) + mArrow.Draw(spriteBatch, mArrowPosition, MovementState.Idle, mMovementDirection); + } + + /// + /// The moving for arrow + /// + public void UpdateArrow() + { + if (mArrowDraw) + mArrowPosition += mDirection * SpeedModifier; + + if (Vector2.Distance(mArrowPosition, mArrowGoal) < 1f * SpeedModifier) + mArrowDraw = false; + } + + /// + /// Calculates the direction the creature is looking when moving. + /// Method copied from PlayerMovement class. + /// + private MovementDirection GiveMovementDirection(Vector2 direction) + { + // |\ + // |α\ α == 22.5° + // b| \ 1 β == 67.5° + // | β\ + // ────── + // a + const float b = 0.92f; // b == sin β + const float a = 0.38f; // a == sin α + MovementDirection movementDirection; + if (direction.X < -b) + { + movementDirection = MovementDirection.W; + } + else if (direction.X > b) + { + movementDirection = MovementDirection.O; + } + else if (direction.Y > 0) + { + if (direction.X < -a) + { + movementDirection = MovementDirection.SW; + } + else if (direction.X > a) + { + movementDirection = MovementDirection.SO; + } + else + { + movementDirection = MovementDirection.S; + } + } + else + { + if (direction.X < -a) + { + movementDirection = MovementDirection.NW; + } + else if (direction.X > a) + { + movementDirection = MovementDirection.NO; + } + else + { + movementDirection = MovementDirection.N; + } + } + return movementDirection; + } + } +} diff --git a/V3/Objects/BuildingState.cs b/V3/Objects/BuildingState.cs new file mode 100644 index 0000000..79c621e --- /dev/null +++ b/V3/Objects/BuildingState.cs @@ -0,0 +1,8 @@ +// ReSharper disable InconsistentNaming +namespace V3.Objects +{ + public enum BuildingFace + { + SW, NO + } +} \ No newline at end of file diff --git a/V3/Objects/Castle.cs b/V3/Objects/Castle.cs new file mode 100644 index 0000000..fd04ddd --- /dev/null +++ b/V3/Objects/Castle.cs @@ -0,0 +1,15 @@ +using Microsoft.Xna.Framework; + +namespace V3.Objects +{ + public sealed class Castle : AbstractBuilding + { + public override string Name { get; } = "Burg"; + protected override int MaxRobustness { get; } = 800; + public override int Robustness { get; protected set; } = 800; + + public Castle(Vector2 position, Rectangle size, string textureName, BuildingFace facing) : base(position, size, textureName, facing) + { + } + } +} diff --git a/V3/Objects/CreatureFactory.cs b/V3/Objects/CreatureFactory.cs new file mode 100644 index 0000000..238ea41 --- /dev/null +++ b/V3/Objects/CreatureFactory.cs @@ -0,0 +1,127 @@ +using System; +using Microsoft.Xna.Framework; +using V3.Data; + +namespace V3.Objects +{ + // ReSharper disable once ClassNeverInstantiated.Global + public sealed class CreatureFactory + { + private readonly IBasicCreatureFactory mFactory; + private readonly Random mRnd = new Random(); + + public CreatureFactory(IBasicCreatureFactory factory) + { + mFactory = factory; + } + + public ICreature CreateCreature(CreatureType type, int id) + { + IdGenerator.SetIdOnce(id); + switch (type) + { + case CreatureType.FemalePeasant: + return mFactory.CreateFemalePeasant(); + case CreatureType.King: + return mFactory.CreateKing(); + case CreatureType.KingsGuard: + return mFactory.CreateKingsGuard(); + case CreatureType.Knight: + return mFactory.CreateKnight(); + case CreatureType.MalePeasant: + return mFactory.CreateMalePeasant(); + case CreatureType.Meatball: + return mFactory.CreateMeatball(); + case CreatureType.Necromancer: + return mFactory.CreateNecromancer(); + case CreatureType.Prince: + return mFactory.CreatePrince(); + case CreatureType.Skeleton: + return mFactory.CreateSkeleton(); + case CreatureType.Zombie: + return mFactory.CreateZombie(); + default: + IdGenerator.ClearIdOnce(); + return null; + } + } + + public MalePeasant CreateMalePeasant(Vector2 position, MovementDirection movementDirection) + { + return CreateCreature(mFactory.CreateMalePeasant(), position, movementDirection); + } + + public FemalePeasant CreateFemalePeasant(Vector2 position, MovementDirection movementDirection) + { + return CreateCreature(mFactory.CreateFemalePeasant(), position, movementDirection); + } + + public Necromancer CreateNecromancer(Vector2 position, MovementDirection movementDirection) + { + return CreateCreature(mFactory.CreateNecromancer(), position, movementDirection); + } + + public Skeleton CreateSkeleton(Vector2 position, MovementDirection movementDirection) + { + return CreateCreature(mFactory.CreateSkeleton(), position, movementDirection); + } + + public SkeletonElite CreateSkeletonElite(Vector2 position, MovementDirection movementDirection) + { + return CreateCreature(mFactory.CreateSkeletonElite(), position, movementDirection); + } + + public Zombie CreateZombie(Vector2 position, MovementDirection movementDirection) + { + return CreateCreature(mFactory.CreateZombie(), position, movementDirection); + } + + public Knight CreateKnight(Vector2 position, MovementDirection movementDirection) + { + Knight knight = CreateCreature(mFactory.CreateKnight(), position, movementDirection); + if (mRnd.Next(3) == 0) + { + knight.MakeFemale(); + } + return knight; + } + + public KingsGuard CreateKingsGuard(Vector2 position, MovementDirection movementDirection) + { + KingsGuard guard = CreateCreature(mFactory.CreateKingsGuard(), position, movementDirection); + if (mRnd.Next(3) == 0) + { + guard.MakeFemale(); + } + return guard; + } + + public SkeletonHorse CreateSkeletonHorse(Vector2 position, MovementDirection movementDirection) + { + return CreateCreature(mFactory.CreateSkeletonHorse(), position, movementDirection); + } + + public Meatball CreateMeatball(Vector2 position, MovementDirection movementDirection) + { + return CreateCreature(mFactory.CreateMeatball(), position, movementDirection); + } + + public Prince CreatePrince(Vector2 position, MovementDirection movementDirection) + { + return CreateCreature(mFactory.CreatePrince(), position, movementDirection); + } + + public King CreateKing(Vector2 position, MovementDirection movementDirection) + { + return CreateCreature(mFactory.CreateKing(), position, movementDirection); + } + + private T CreateCreature(T creature, Vector2 position, MovementDirection movementDirection) where T: ICreature + { + creature.Position = position; + creature.InitialPosition = position; + creature.MovementDirection = movementDirection; + return creature; + } + } +} diff --git a/V3/Objects/FemalePeasant.cs b/V3/Objects/FemalePeasant.cs new file mode 100644 index 0000000..855685c --- /dev/null +++ b/V3/Objects/FemalePeasant.cs @@ -0,0 +1,50 @@ +using System; +using Microsoft.Xna.Framework.Content; +using V3.Data; +using V3.Map; +using V3.Objects.Movement; +using V3.Objects.Sprite; + +namespace V3.Objects +{ + /// + /// Class for simple peasants which will be transformed into zombies. + /// + public sealed class FemalePeasant : AbstractCreature + { + public override string Name { get; protected set; } = "Dorfbewohnerin"; + public override int Life { get; protected set; } = 20; + public override int MaxLife { get; protected set; } = 20; + public override int Speed { get; } = 10; + public override int Attack { get; protected set; } = 5; + public override int AttackRadius { get; protected set; } = 0; + public override int SightRadius { get; protected set; } = 20; + public override TimeSpan TotalRecovery { get; } = TimeSpan.FromSeconds(0.3); + public override TimeSpan Recovery { get; set; } + protected override ISpriteCreature[] Sprite { get; } = {new ClothFemaleSprite(), new HeadFemaleSprite(), null}; + protected override IMovable MovementScheme { get; } = new PlayerMovement(); + protected override CreatureType Type { get; } = CreatureType.FemalePeasant; + public override Faction Faction { get; } = Faction.Plebs; + public override ICreature IsAttacking { get; set; } + public override IBuilding IsAttackingBuilding { get; set; } + + + public FemalePeasant(ContentManager contentManager, + Pathfinder pathfinder, IOptionsManager optionsManager, AchievementsAndStatistics achievementsAndStatistics) + : base(contentManager, pathfinder, optionsManager, achievementsAndStatistics) + { + } + + public void RemoveArmor() + { + if (Sprite[0] is NudeFemaleSprite) + { + ChangeEquipment(EquipmentType.Body, new ClothFemaleSprite()); + } + else if (Sprite[0] is ClothFemaleSprite) + { + ChangeEquipment(EquipmentType.Body, new NudeFemaleSprite()); + } + } + } +} diff --git a/V3/Objects/Forge.cs b/V3/Objects/Forge.cs new file mode 100644 index 0000000..1da3970 --- /dev/null +++ b/V3/Objects/Forge.cs @@ -0,0 +1,19 @@ +using Microsoft.Xna.Framework; + +namespace V3.Objects +{ + /// + /// A Forge which can be attacked. + /// + public sealed class Forge : AbstractBuilding + { + public override string Name { get; } = "Schmiede"; + protected override int MaxRobustness { get; } = 200; + public override int Robustness { get; protected set; } = 200; + public override int MaxGivesWeapons { get; protected set; } = 10; + + public Forge(Vector2 position, Rectangle size, string textureName, BuildingFace facing) : base(position, size, textureName, facing) + { + } + } +} diff --git a/V3/Objects/IBasicCreatureFactory.cs b/V3/Objects/IBasicCreatureFactory.cs new file mode 100644 index 0000000..9b7a88b --- /dev/null +++ b/V3/Objects/IBasicCreatureFactory.cs @@ -0,0 +1,28 @@ +namespace V3.Objects +{ + public interface IBasicCreatureFactory + { + MalePeasant CreateMalePeasant(); + + FemalePeasant CreateFemalePeasant(); + + Necromancer CreateNecromancer(); + + Skeleton CreateSkeleton(); + SkeletonElite CreateSkeletonElite(); + + Zombie CreateZombie(); + + Knight CreateKnight(); + + SkeletonHorse CreateSkeletonHorse(); + + Meatball CreateMeatball(); + + Prince CreatePrince(); + + King CreateKing(); + + KingsGuard CreateKingsGuard(); + } +} diff --git a/V3/Objects/IBuilding.cs b/V3/Objects/IBuilding.cs new file mode 100644 index 0000000..0fdd0aa --- /dev/null +++ b/V3/Objects/IBuilding.cs @@ -0,0 +1,20 @@ +namespace V3.Objects +{ + public interface IBuilding : IGameObject + { + int Robustness { get; } + string Name { get; } + int MaxGivesWeapons { get; } + + /// + /// Building takes specific amount of damage. Substracted from Robustness. + /// + /// TakeDamage taken + void TakeDamage(int damage); + + /// + /// Building can give a fixed amount of upgrades. + /// + void UpgradeCounter(); + } +} diff --git a/V3/Objects/ICreature.cs b/V3/Objects/ICreature.cs new file mode 100644 index 0000000..891ada7 --- /dev/null +++ b/V3/Objects/ICreature.cs @@ -0,0 +1,120 @@ +using System; +using System.Collections.Generic; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using V3.Camera; +using V3.Data; +using V3.Objects.Sprite; + +namespace V3.Objects +{ + /// + /// A moving game object. + /// + public interface ICreature : IGameObject + { + string Name { get; } + Vector2 InitialPosition { set; } + int Life { get; } + int MaxLife { get; } + int Speed { get; } + int Attack { get; } + int AttackRadius { get; } + int SightRadius { get; } + TimeSpan TotalRecovery { get; } + TimeSpan Recovery { get; set; } + /// + /// Area where the creature is standing. Used for collisions. + /// + /// + /// Where you can click to select the creature. + /// + Rectangle SelectionRectangle { get; } + bool IsSelected { get; set; } + ICreature IsAttacking { get; set; } + IBuilding IsAttackingBuilding { get; set; } + MovementDirection MovementDirection { get; set; } + MovementState MovementState { get; set; } + Faction Faction { get; } + bool IsDead { get; } + bool IsUpgraded { get; set; } + + /// + /// Creature takes specific amount of damage. Substracted from Life. + /// + /// TakeDamage taken. + void TakeDamage(int damage); + + /// + /// Give command to move to desired destination. Not instant movement. + /// + /// Destination in pixels. + void Move (Vector2 destination); + + //void ImportentMove(IGameObject creature); + + /// + /// Draws a static non-animated sprite (for HUD) at specified position. + /// + /// Sprite batch used for drawing. + /// Position where to draw the sprite. + void DrawStatic(SpriteBatch spriteBatch, Point position); + + /// + /// Update the creature behaviour and animation. + /// + void Update(GameTime gameTime, ICreature playerCharacter, + bool rightButtonPressed, Vector2 rightButtonPosition, Quadtree quadtree, ICamera camera); + + /// + /// Change the equipment/sprite of the creature to something other. + /// If in debug mode the function throws an exception if the creature does not have the specified equipment slots. + /// + /// Which part of the equipment should be changed. + /// Which sprite to use instead. + void ChangeEquipment(EquipmentType equipmentType, ISpriteCreature sprite); + + /// + /// Sets back the position of the creature to its state when created. + /// + void ResetPosition(); + + /// + /// Plays the specified animation fully, but only once. + /// + /// For which movement state the animation should be played. + /// How long (or how slow) should the animation be? + void PlayAnimationOnce(MovementState animation, TimeSpan duration); + + /// + /// Heals the creature. Can not go over MaxLife. + /// + /// How much HP the creature gains. + void Heal(int amount); + + /// + /// Creature gets more life and maxlife. Used for testing in Techdemo. + /// + /// Multiplyier for Life. + void Empower(int modifier); + + /// + /// Save this creature’s data to a CreatureData object. + /// + /// the CreatureData object with the status of this creature + CreatureData SaveData(); + + /// + /// Restore the creature's state from the given data. + /// + /// the state of the creature to restore + void LoadData(CreatureData data); + + /// + /// Restore the creature's references to other creatures from the given data. + /// + /// the state of the creature to restore + /// the list of all creatures by ID + void LoadReferences(CreatureData data, Dictionary creatures); + } +} diff --git a/V3/Objects/IGameObject.cs b/V3/Objects/IGameObject.cs new file mode 100644 index 0000000..556e918 --- /dev/null +++ b/V3/Objects/IGameObject.cs @@ -0,0 +1,43 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.Graphics; + +namespace V3.Objects +{ + /// + /// A game object which is placed on the map. + /// + public interface IGameObject + { + Vector2 Position { get; set; } + + /// + /// A unique ID for this game object, with which it can be identified. + /// All implementations should use the IdGenerator to generate this ID. + /// + int Id { get; } + + /// + /// Draws the game object on the screen. + /// + /// Sprite batch used for drawing. + void Draw(SpriteBatch spriteBatch); + + /// + /// The size of the object. + /// + Rectangle BoundaryRectangle { get; } + + /// + /// Loads needed graphics. + /// + /// Content manager used. + void LoadContent(ContentManager contentManager); + + /// + /// Returns the object instance without modifications. + /// + /// This object. + IGameObject GetSelf(); + } +} diff --git a/V3/Objects/IObjectsManager.cs b/V3/Objects/IObjectsManager.cs new file mode 100644 index 0000000..e8fa17b --- /dev/null +++ b/V3/Objects/IObjectsManager.cs @@ -0,0 +1,131 @@ +using System.Collections.Generic; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using V3.Camera; +using V3.Map; + +namespace V3.Objects +{ + /// + /// Objects manager for all game objects, be is creatures or buildings or even simple landscape objects. + /// + public interface IObjectsManager + { + //***** FOR TESTING PURPOSES! + List AddToSelectables { get; } + List CreatureList { get; } + List UndeadCreatures { get; } + //List KingdromCreatures { get; } + //List PlebCreatures { get; } + //***** NOT FOR TESTING PURPOSES ANYMORE! + + /// + /// Gets the current player character. Usually the necromancer. + /// Do not set directly! Use CreatePlayerCharacter() instead! + /// + ICreature PlayerCharacter { get; } + + ICreature Boss { get; } + + ICreature Prince { get; } + + Castle Castle { get; } + + /// + /// If you load a new map with new objects you need to initialize the objects manager again. + /// (Or else you have all the current objects on the new map.) + /// + /// + void Initialize(IMapManager mapManager); + + /// + /// Removes all objects from the object manager. + /// + void Clear(); + + /// + /// Creates the player character. This should be the first thing you do + /// after you created or initialized the objects manager. + /// + /// + void CreatePlayerCharacter(Necromancer necromancer); + + /// + /// Creates the boss of the level. Game is won if the boss is killed. + /// + /// Some ICreature to kill for winning. + void CreateBoss(ICreature boss); + + /// + /// Create the prince, a small boss. + /// + /// Some hard ICreature to kill. + void CreatePrince(ICreature prince); + + /// + /// Creates a creature for the game and inserts it in the appropriate data structures. + /// + /// + void CreateCreature(ICreature creature); + + /// + /// Removes specified creature from the game. + /// + /// The creature to be removed. + void RemoveCreature(ICreature creature); + + /// + /// Draws all currently shown objects on the map. + /// + /// The sprite batch used. + /// Camera for calculating which objects need to be drawn. + void Draw(SpriteBatch spriteBatch, ICamera camera); + + /// + /// Draws a visual representation of the Quadtree. For debugging purposes. + /// + /// + void DrawQuadtree(SpriteBatch spriteBatch); + + /// + /// Update the behaviour of all creatures on the map. + /// + /// Current game time. + /// Did the player press the right mouse button? + /// Where is the mouse currently? + /// Camera for checking where to do important updates. + void Update(GameTime gameTime, bool rightButtonPressed, Vector2 rightButtonPosition, ICamera camera); + + /// + /// Imports the TextureObjects from the objects map layer for drawing things in the right order. + /// + /// + void ImportMapObjects(List textureObjects); + + /// + /// Get all objects in the given rectangles. + /// + /// The rectangle which defines the area of the returnes objects. + /// Game objects in the rectangle. + List GetObjectsInRectangle(Rectangle rectangle); + + /// + /// Gets all creatures which are in the given ellipse area. + /// + /// To check if creature is in ellipse area. + /// + List GetCreaturesInEllipse(Ellipse ellipse); + + /// + /// Playing around with some cheating codes. + /// + void ExposeTheLiving(); + + /// + /// Checks if a creature is standing in a graveyard area. + /// + /// Check for this creature. + /// True when standing in graveyard area. + bool InGraveyardArea(ICreature creature); + } +} diff --git a/V3/Objects/IdGenerator.cs b/V3/Objects/IdGenerator.cs new file mode 100644 index 0000000..08976ca --- /dev/null +++ b/V3/Objects/IdGenerator.cs @@ -0,0 +1,59 @@ +using System; + +namespace V3.Objects +{ + /// + /// Static helper class that generates unique IDs for game objects. + /// + // ReSharper disable once ClassNeverInstantiated.Global + public sealed class IdGenerator + { + private static int sCurrentId; + + private static int? sIdOnce; + + private IdGenerator() + { + throw new NotImplementedException(); + } + + /// + /// Get an ID for a new game object. + /// + /// the ID to use for a new game object + public static int GetNextId() + { + int id; + if (sIdOnce.HasValue) + { + id = sIdOnce.Value; + ClearIdOnce(); + } + else + { + id = sCurrentId; + sCurrentId++; + } + + return id; + } + + /// + /// Sets the ID to use only for the next object that is created. + /// + /// the id for the next object + public static void SetIdOnce(int id) + { + sIdOnce = id; + } + + /// + /// Clear the ID stored by SetIdOnce that is used only for the + /// next object. + /// + public static void ClearIdOnce() + { + sIdOnce = null; + } + } +} diff --git a/V3/Objects/King.cs b/V3/Objects/King.cs new file mode 100644 index 0000000..b1c9713 --- /dev/null +++ b/V3/Objects/King.cs @@ -0,0 +1,33 @@ +using System; +using Microsoft.Xna.Framework.Content; +using V3.Data; +using V3.Map; +using V3.Objects.Movement; +using V3.Objects.Sprite; + +namespace V3.Objects +{ + // ReSharper disable once ClassNeverInstantiated.Global + public class King : AbstractCreature + { + public override string Name { get; protected set; } = "König Harry"; + public override int Life { get; protected set; } = 10000; + public override int MaxLife { get; protected set; } = 10000; + public override int Speed { get; } = 10; + public override int Attack { get; protected set; } = 45; + public override int AttackRadius { get; protected set; } = 48; + public override int SightRadius { get; protected set; } = 500; + public override TimeSpan TotalRecovery { get; } = TimeSpan.FromSeconds(0.8); + public override TimeSpan Recovery { get; set; } + protected override ISpriteCreature[] Sprite { get; } = { new KingSprite() }; + protected override IMovable MovementScheme { get; } = new PlayerMovement(); + protected override CreatureType Type { get; } = CreatureType.King; + public override Faction Faction { get; } = Faction.Kingdom; + public override ICreature IsAttacking { get; set; } + public override IBuilding IsAttackingBuilding { get; set; } + + public King(ContentManager contentManager, Pathfinder pathfinder, IOptionsManager optionsManager, AchievementsAndStatistics achievementsAndStatistics) : base(contentManager, pathfinder, optionsManager, achievementsAndStatistics) + { + } + } +} diff --git a/V3/Objects/KingsGuard.cs b/V3/Objects/KingsGuard.cs new file mode 100644 index 0000000..a0f3bc5 --- /dev/null +++ b/V3/Objects/KingsGuard.cs @@ -0,0 +1,62 @@ +using System; +using Microsoft.Xna.Framework.Content; +using V3.Data; +using V3.Map; +using V3.Objects.Movement; +using V3.Objects.Sprite; + +namespace V3.Objects +{ + public sealed class KingsGuard : AbstractCreature + { + public override string Name { get; protected set; } = "Königliche Garde"; + public override int Life { get; protected set; } = 200; + public override int MaxLife { get; protected set; } = 200; + public override int Speed { get; } = 7; + public override int Attack { get; protected set; } = 25; + public override int AttackRadius { get; protected set; } = 48; + public override int SightRadius { get; protected set; } = 200; + public override TimeSpan TotalRecovery { get; } = TimeSpan.FromSeconds(0.5); + public override TimeSpan Recovery { get; set; } + protected override ISpriteCreature[] Sprite { get; } = { new PlateSprite(), new HeadPlateSprite(), new LongswordSprite(), new ShieldSprite() }; + protected override IMovable MovementScheme { get; } = new PlayerMovement(); + protected override CreatureType Type { get; } = CreatureType.KingsGuard; + public override Faction Faction { get; } = Faction.Kingdom; + public override ICreature IsAttacking { get; set; } + public override IBuilding IsAttackingBuilding { get; set; } + + public KingsGuard(ContentManager contentManager, + Pathfinder pathfinder, IOptionsManager optionsManager, AchievementsAndStatistics achievementsAndStatistics) + : base(contentManager, pathfinder, optionsManager,achievementsAndStatistics) + { + } + + public void MakeFemale() + { + ChangeEquipment(EquipmentType.Body, new PlateFemaleSprite()); + ChangeEquipment(EquipmentType.Head, new HeadPlateFemaleSprite()); + ChangeEquipment(EquipmentType.Weapon, new LongswordFemaleSprite()); + ChangeEquipment(EquipmentType.Offhand, new ShieldFemaleSprite()); + } + + public void RemoveArmor() + { + if (Sprite[(int)EquipmentType.Body] is PlateSprite) + { + ChangeEquipment(EquipmentType.Body, new NudeSprite()); + } + else if (Sprite[(int)EquipmentType.Body] is PlateFemaleSprite) + { + ChangeEquipment(EquipmentType.Body, new NudeFemaleSprite()); + } + else if (Sprite[(int)EquipmentType.Body] is NudeSprite) + { + ChangeEquipment(EquipmentType.Body, new PlateSprite()); + } + else if (Sprite[(int)EquipmentType.Body] is NudeFemaleSprite) + { + ChangeEquipment(EquipmentType.Body, new PlateFemaleSprite()); + } + } + } +} diff --git a/V3/Objects/Knight.cs b/V3/Objects/Knight.cs new file mode 100644 index 0000000..ef31f2a --- /dev/null +++ b/V3/Objects/Knight.cs @@ -0,0 +1,65 @@ +using System; +using Microsoft.Xna.Framework.Content; +using V3.Data; +using V3.Map; +using V3.Objects.Movement; +using V3.Objects.Sprite; + +namespace V3.Objects +{ + /// + /// A knight which fights against the necromancer. + /// + public sealed class Knight : AbstractCreature + { + public override string Name { get; protected set; } = "Ritter"; + public override int Life { get; protected set; } = 120; + public override int MaxLife { get; protected set; } = 120; + public override int Speed { get; } = 8; + public override int Attack { get; protected set; } = 15; + public override int AttackRadius { get; protected set; } = 48; + public override int SightRadius { get; protected set; } = 200; + public override TimeSpan TotalRecovery { get; } = TimeSpan.FromSeconds(0.5); + public override TimeSpan Recovery { get; set; } + protected override ISpriteCreature[] Sprite { get; } = {new ChainSprite(), new HeadChainSprite(), new ShortswordSprite(), new BucklerSprite()}; + protected override IMovable MovementScheme { get; } = new PlayerMovement(); + protected override CreatureType Type { get; } = CreatureType.Knight; + public override Faction Faction { get; } = Faction.Kingdom; + public override ICreature IsAttacking { get; set; } + public override IBuilding IsAttackingBuilding { get; set; } + + public Knight(ContentManager contentManager, + Pathfinder pathfinder, IOptionsManager optionsManager, AchievementsAndStatistics achievementsAndStatistics) + : base(contentManager, pathfinder, optionsManager, achievementsAndStatistics) + { + } + + public void MakeFemale() + { + ChangeEquipment(EquipmentType.Body, new ChainFemaleSprite()); + ChangeEquipment(EquipmentType.Head, new HeadChainFemaleSprite()); + ChangeEquipment(EquipmentType.Weapon, new ShortswordFemaleSprite()); + ChangeEquipment(EquipmentType.Offhand, new BucklerFemaleSprite()); + } + + public void RemoveArmor() + { + if (Sprite[(int) EquipmentType.Body] is ChainSprite) + { + ChangeEquipment(EquipmentType.Body, new NudeSprite()); + } + else if (Sprite[(int) EquipmentType.Body] is ChainFemaleSprite) + { + ChangeEquipment(EquipmentType.Body, new NudeFemaleSprite()); + } + else if (Sprite[(int)EquipmentType.Body] is NudeSprite) + { + ChangeEquipment(EquipmentType.Body, new ChainSprite()); + } + else if (Sprite[(int)EquipmentType.Body] is NudeFemaleSprite) + { + ChangeEquipment(EquipmentType.Body, new ChainFemaleSprite()); + } + } + } +} diff --git a/V3/Objects/MalePeasant.cs b/V3/Objects/MalePeasant.cs new file mode 100644 index 0000000..1250412 --- /dev/null +++ b/V3/Objects/MalePeasant.cs @@ -0,0 +1,49 @@ +using System; +using Microsoft.Xna.Framework.Content; +using V3.Data; +using V3.Map; +using V3.Objects.Movement; +using V3.Objects.Sprite; + +namespace V3.Objects +{ + /// + /// Class for simple peasants which will be transformed into zombies. + /// + public sealed class MalePeasant : AbstractCreature + { + public override string Name { get; protected set; } = "Dorfbewohner"; + public override int Life { get; protected set; } = 24; + public override int MaxLife { get; protected set; } = 24; + public override int Speed { get; } = 10; + public override int Attack { get; protected set; } = 5; + public override int AttackRadius { get; protected set; } = 0; + public override int SightRadius { get; protected set; } = 20; + public override TimeSpan TotalRecovery { get; } = TimeSpan.FromSeconds(0.3); + public override TimeSpan Recovery { get; set; } + protected override ISpriteCreature[] Sprite { get; } = {new ClothSprite(), new HeadSprite(), null}; + protected override IMovable MovementScheme { get; } = new PlayerMovement(); + protected override CreatureType Type { get; } = CreatureType.MalePeasant; + public override Faction Faction { get; } = Faction.Plebs; + public override ICreature IsAttacking { get; set; } + public override IBuilding IsAttackingBuilding { get; set; } + + public MalePeasant(ContentManager contentManager, + Pathfinder pathfinder, IOptionsManager optionsManager, AchievementsAndStatistics achievementsAndStatistics) + : base(contentManager, pathfinder, optionsManager, achievementsAndStatistics) + { + } + + public void RemoveArmor() + { + if (Sprite[0] is NudeSprite) + { + ChangeEquipment(EquipmentType.Body, new ClothSprite()); + } + else if (Sprite[0] is ClothSprite) + { + ChangeEquipment(EquipmentType.Body, new NudeSprite()); + } + } + } +} diff --git a/V3/Objects/Meatball.cs b/V3/Objects/Meatball.cs new file mode 100644 index 0000000..144ef90 --- /dev/null +++ b/V3/Objects/Meatball.cs @@ -0,0 +1,36 @@ +using System; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Content; +using V3.Data; +using V3.Map; +using V3.Objects.Movement; +using V3.Objects.Sprite; + +namespace V3.Objects +{ + public sealed class Meatball : AbstractCreature + { + public Meatball(ContentManager contentManager, Pathfinder pathfinder, IOptionsManager optionsManager, AchievementsAndStatistics achievementsAndStatistics) : base(contentManager, pathfinder, optionsManager, achievementsAndStatistics) + { + } + + protected override ISpriteCreature[] Sprite { get; } = { new MeatballSprite() }; + protected override IMovable MovementScheme { get; } = new PlayerMovement(); + protected override CreatureType Type { get; } = CreatureType.Meatball; + public override string Name { get; protected set; } = "Fleischball"; + public override int Life { get; protected set; } = 200; + public override int MaxLife { get; protected set; } = 200; + public override int Speed { get; } = 5; + public override int Attack { get; protected set; } = 70; + public override int AttackRadius { get; protected set; } = 60; + public override int SightRadius { get; protected set; } = 100; + public override TimeSpan TotalRecovery { get; } = TimeSpan.FromSeconds(1); + public override TimeSpan Recovery { get; set; } + public override Faction Faction { get; } = Faction.Undead; + public override ICreature IsAttacking { get; set; } + public override IBuilding IsAttackingBuilding { get; set; } + + protected override Point CreatureSize { get; } = new Point(36); + protected override Point BoundaryShift { get; } = new Point(-18, -24); + } +} diff --git a/V3/Objects/Movement.cs b/V3/Objects/Movement.cs new file mode 100644 index 0000000..3dfa01b --- /dev/null +++ b/V3/Objects/Movement.cs @@ -0,0 +1,20 @@ +// ReSharper disable InconsistentNaming +namespace V3.Objects +{ + /// + /// Cardinal directions to show where the specific creature is facing. + /// Because of the isometric viewpoint N(orth) is the upper right. + /// + public enum MovementDirection + { + W, NW, N, NO, O, SO, S, SW + } + + /// + /// The basic movement states a creature must hold. + /// + public enum MovementState + { + Idle, Moving, Attacking, Dying, Special + } +} \ No newline at end of file diff --git a/V3/Objects/Movement/CountStepsMovement.cs b/V3/Objects/Movement/CountStepsMovement.cs new file mode 100644 index 0000000..e8c24c4 --- /dev/null +++ b/V3/Objects/Movement/CountStepsMovement.cs @@ -0,0 +1,16 @@ +using Microsoft.Xna.Framework; + +namespace V3.Objects.Movement +{ + public class CountStepsMovement : PlayerMovement + { + public float WalkedPixels { get; private set; } + + public override Vector2 GiveNewPosition(Vector2 currentPosition, int speed) + { + var movedDistance = base.GiveNewPosition(currentPosition, speed); + WalkedPixels += Vector2.Distance(currentPosition, currentPosition + movedDistance); + return movedDistance; + } + } +} \ No newline at end of file diff --git a/V3/Objects/Movement/IMovable.cs b/V3/Objects/Movement/IMovable.cs new file mode 100644 index 0000000..659708b --- /dev/null +++ b/V3/Objects/Movement/IMovable.cs @@ -0,0 +1,43 @@ +using Microsoft.Xna.Framework; +using V3.Data; +using V3.Map; + +namespace V3.Objects.Movement +{ + public interface IMovable + { + /// + /// Calculates a path without collisions to desired destination. + /// + /// Pathfinder to use. + /// Current position in pixel. + /// Destination in pixel. + void FindPath(Pathfinder pathfinder, Vector2 position, Vector2 destination); + + /// + /// Uses pathfinder to for steady movement to new transition. + /// + /// Current position in pixel. + /// Movement speed of the creature. + /// Normalized vector * speed which represents a small step in the direction of desired destination.( + Vector2 GiveNewPosition(Vector2 currentPosition, int speed); + + /// + /// Calculates the direction the creature is looking when moving. + /// + MovementDirection GiveMovementDirection(); + bool IsMoving { get; } + + /// + /// Save the movement data to a MovementData object. + /// + /// the MovementData object with the current status + MovementData SaveData(); + + /// + /// Restore the movement state from the given data. + /// + /// the state of the movement to restore + void LoadData(MovementData movementData); + } +} diff --git a/V3/Objects/Movement/PlayerMovement.cs b/V3/Objects/Movement/PlayerMovement.cs new file mode 100644 index 0000000..326503f --- /dev/null +++ b/V3/Objects/Movement/PlayerMovement.cs @@ -0,0 +1,155 @@ +using System.Collections.Generic; +using Microsoft.Xna.Framework; +using V3.Data; +using V3.Map; + +namespace V3.Objects.Movement +{ + // TODO: Rename the class. Current name is unfitting. (But what is fitting?) + /// + /// Movement scheme for moving an object with the pathfinder. + /// + public class PlayerMovement : IMovable + { + private const int CellHeight = Constants.CellHeight; + private const int CellWidth = Constants.CellWidth; + private const float SpeedModifier = 0.25f; + + private List mPath; + private int mStep; + private Vector2 mLastMovement; + + public bool IsMoving { get; private set; } + + /// + /// Calculates a path without collisions to desired destination. + /// + /// Pathfinder to use. + /// Current position in pixel. + /// Destination in pixel. + public void FindPath(Pathfinder pathfinder, Vector2 position, Vector2 destination) + { + mStep = 0; + mPath = pathfinder.FindPath(new Vector2((int)(position.X / CellWidth), (int)(position.Y / CellHeight)), + new Vector2((int)(destination.X / CellWidth), (int)(destination.Y / CellHeight))); + IsMoving = mPath.Count > 0; + } + + /// + /// Uses pathfinder to for steady movement to new transition. + /// + /// Current position in pixel. + /// Movement speed of the creature. + /// Normalized vector * speed which represents a small step in the direction of desired destination.( + public virtual Vector2 GiveNewPosition(Vector2 currentPosition, int speed) + { + Vector2 nextPosition = mPath[mStep]; + Vector2 newPosition = nextPosition - currentPosition; + newPosition.Normalize(); + float distanceToDestination = Vector2.Distance(nextPosition, currentPosition); + if (distanceToDestination < SpeedModifier * speed) + { + if (mStep == mPath.Count - 1) + { + IsMoving = false; + } + else + { + mStep++; + } + } + mLastMovement = newPosition; + return newPosition * SpeedModifier * speed; + } + + /// + /// Calculates the direction the creature is looking when moving. + /// + public MovementDirection GiveMovementDirection() + { + // |\ + // |α\ α == 22.5° + // b| \ 1 β == 67.5° + // | β\ + // ────── + // a + const float b = 0.92f; // b == sin β + const float a = 0.38f; // a == sin α + Vector2 direction = mLastMovement; + MovementDirection movementDirection; + if (direction.X < -b) + { + movementDirection = MovementDirection.W; + } + else if (direction.X > b) + { + movementDirection = MovementDirection.O; + } + else if (direction.Y > 0) + { + if (direction.X < -a) + { + movementDirection = MovementDirection.SW; + } + else if (direction.X > a) + { + movementDirection = MovementDirection.SO; + } + else + { + movementDirection = MovementDirection.S; + } + } + else + { + if (direction.X < -a) + { + movementDirection = MovementDirection.NW; + } + else if (direction.X > a) + { + movementDirection = MovementDirection.NO; + } + else + { + movementDirection = MovementDirection.N; + } + } + return movementDirection; + } + /// + /// Save the movement data to a MovementData object. + /// + /// the MovementData object with the current status + public MovementData SaveData() + { + var data = new MovementData(); + data.IsMoving = IsMoving; + if (IsMoving) + { + data.Path = mPath; + data.Step = mStep; + data.LastMovement = mLastMovement; + } + return data; + } + + /// + /// Restore the movement state from the given data. + /// + /// the state of the movement to restore + public void LoadData(MovementData movementData) + { + if (movementData == null) + return; + + IsMoving = movementData.IsMoving; + if (IsMoving) + { + mPath = movementData.Path; + mStep = movementData.Step; + mLastMovement = movementData.LastMovement; + } + } + } +} diff --git a/V3/Objects/Necromancer.cs b/V3/Objects/Necromancer.cs new file mode 100644 index 0000000..b13650d --- /dev/null +++ b/V3/Objects/Necromancer.cs @@ -0,0 +1,61 @@ +using System; +using Microsoft.Xna.Framework.Content; +using V3.Data; +using V3.Map; +using V3.Objects.Movement; +using V3.Objects.Sprite; + +namespace V3.Objects +{ + /// + /// A class for the player character: The Necromancer. + /// + // ReSharper disable once ClassNeverInstantiated.Global + public sealed class Necromancer : AbstractCreature + { + public override string Name { get; protected set; } = "Vagram der Grausame"; + public override int Life { get; protected set; } = 500; + public override int MaxLife { get; protected set; } = 500; + public override int Speed { get; } = 12; + public override int Attack { get; protected set; } = 0; + public override int AttackRadius { get; protected set; } = 500; + public override int SightRadius { get; protected set; } = 0; + public override TimeSpan TotalRecovery { get; } = TimeSpan.FromSeconds(1); + public override TimeSpan Recovery { get; set; } + protected override ISpriteCreature[] Sprite { get; } = {new NecromancerSprite(), new StaffSprite()}; + protected override IMovable MovementScheme { get; } = new CountStepsMovement(); + protected override CreatureType Type { get; } = CreatureType.Necromancer; + public override Faction Faction { get; } = Faction.Undead; + public override ICreature IsAttacking { get; set; } + public override IBuilding IsAttackingBuilding { get; set; } + public float WalkedPixels => ((CountStepsMovement) MovementScheme).WalkedPixels; + + public Necromancer(ContentManager contentManager, + Pathfinder pathfinder, IOptionsManager optionsManager, AchievementsAndStatistics achievementsAndStatistics) + : base(contentManager, pathfinder, optionsManager, achievementsAndStatistics) + { + } + + public void ChangeSex() + { + ISpriteCreature sprite0; + ISpriteCreature sprite1; + if (Sprite[0] is NecromancerSprite) + { + sprite0 = new NecromancerFemaleSprite(); + sprite1 = new StaffFemaleSprite(); + } + else + { + sprite0 = new NecromancerSprite(); + sprite1 = new StaffSprite(); + } + + ChangeEquipment(EquipmentType.Body, sprite0); + if (Sprite.Length >= 2 && Sprite[(int) EquipmentType.Head] != null) + { + ChangeEquipment(EquipmentType.Head, sprite1); + } + } + } +} diff --git a/V3/Objects/ObjectsManager.cs b/V3/Objects/ObjectsManager.cs new file mode 100644 index 0000000..e3ef568 --- /dev/null +++ b/V3/Objects/ObjectsManager.cs @@ -0,0 +1,314 @@ +using System; +using System.Collections.Generic; +using System.Linq; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.Graphics; +using V3.Camera; +using V3.Effects; +using V3.Map; + +namespace V3.Objects +{ + /// + /// Objects manager for all game objects, be is creatures or buildings or even simple landscape objects. + /// + // ReSharper disable once ClassNeverInstantiated.Global + public class ObjectsManager : IObjectsManager + { + private List> mCreaturesByFactions; + private List mCreatureList; + private List mAddToSelectables; + private Quadtree mTextureQuadtree; + private Quadtree mInteractableQuadtree; + private readonly ContentManager mContentManager; + private readonly CreatureFactory mCreatureFactory; + private readonly IEffectsManager mEffectsManager; + private Rectangle mMapRectangle; + private List mAreas; + private readonly UpdatesPerSecond mFewerUpdates = new UpdatesPerSecond(15); + private readonly UpdatesPerSecond mEffectsCounter = new UpdatesPerSecond(0.2); + + public List AddToSelectables => mAddToSelectables; + public List CreatureList => mCreatureList; + public List UndeadCreatures => mCreaturesByFactions[(int) Faction.Undead]; + //public List KingdromCreatures => mCreaturesByFactions[(int) Faction.Kingdom]; + //public List PlebCreatures => mCreaturesByFactions[(int) Faction.Plebs]; + public ICreature PlayerCharacter { get; private set; } + public ICreature Boss { get; private set; } + public ICreature Prince { get; private set; } + public Castle Castle { get; private set; } + + public ObjectsManager(ContentManager contentManager, CreatureFactory creatureFactory, + IEffectsManager effectsManager) + { + mContentManager = contentManager; + mCreatureFactory = creatureFactory; + mEffectsManager = effectsManager; + } + + public void Initialize(IMapManager mapManager) + { + Clear(); + mAddToSelectables = new List(); + mCreatureList = new List(); + mCreaturesByFactions = new List>(); + // Make three lists because we have three factions. + for (int i = 0; i < 3; i++) + { + mCreaturesByFactions.Add(new List()); + } + // Gets the initial values for the Quad Tree from the current map. + mInteractableQuadtree = new Quadtree(mapManager.SizeInPixel + new Point(128, 128)); + mTextureQuadtree = new Quadtree(mapManager.SizeInPixel + new Point(128, 128)); + mInteractableQuadtree.LoadContent(mContentManager); + mTextureQuadtree.LoadContent(mContentManager); + + // Import map objects for drawing. + ImportMapObjects(mapManager.GetObjects()); + + // Save Map size in ObjectsManager. + mMapRectangle = new Rectangle(new Point(0), mapManager.SizeInPixel); + + mAreas = mapManager.Areas; + } + + public void Clear() + { + CreatureList?.Clear(); + mCreaturesByFactions?.Clear(); + for (int i = 0; i < 3; i++) + { + mCreaturesByFactions?.Add(new List()); + } + PlayerCharacter = null; + Boss = null; + Prince = null; + Castle = null; + mInteractableQuadtree?.Clear(); + mTextureQuadtree?.Clear(); + } + + public void CreatePlayerCharacter(Necromancer necromancer) + { + PlayerCharacter = necromancer; + AddCreature(necromancer); + } + + public void CreateBoss(ICreature boss) + { + Boss = boss; + AddCreature(boss); + } + + public void CreatePrince(ICreature prince) + { + Prince = prince; + AddCreature(prince); + } + + public void CreateCreature(ICreature creature) + { + AddCreature(creature); + } + + public void RemoveCreature(ICreature creature) + { + mCreatureList.Remove(creature); + mCreaturesByFactions[(int) creature.Faction].Remove(creature); + mInteractableQuadtree.RemoveItem(creature); + } + + public void Draw(SpriteBatch spriteBatch, ICamera camera) + { + var objectsToDraw = mInteractableQuadtree.GetObjectsInRectangle(camera.ScreenRectangle); + var texturesToDraw = mTextureQuadtree.GetObjectsInRectangle(camera.ScreenRectangle); + IEnumerable ordered = from obj in objectsToDraw.Concat(texturesToDraw) orderby obj.Position.Y select obj; + foreach (var obj in ordered) + { + obj.Draw(spriteBatch); + } + } + + public void DrawQuadtree(SpriteBatch spriteBatch) + { + mInteractableQuadtree.Draw(spriteBatch); + mTextureQuadtree.Draw(spriteBatch); + } + + public void Update(GameTime gameTime, bool rightButtonPressed, Vector2 rightButtonPosition, ICamera camera) + { + foreach (var creature in mCreatureList) + { + if (creature.GetSelf() == null) continue; + creature.Update(gameTime, PlayerCharacter, rightButtonPressed, rightButtonPosition, mInteractableQuadtree, camera); + + + // Create a boss if castle is down + if (creature.IsAttackingBuilding != null && creature.IsAttackingBuilding.Name == "Burg") + { + if (creature.IsAttackingBuilding.Robustness <= 50 && Boss == null) + { + var king = mCreatureFactory.CreateKing(new Vector2(creature.IsAttackingBuilding.Position.X - 300, creature.IsAttackingBuilding.Position.Y + 130), MovementDirection.S); // + var knight1 = mCreatureFactory.CreateKnight(new Vector2(creature.IsAttackingBuilding.Position.X - 320, creature.IsAttackingBuilding.Position.Y + 110), MovementDirection.S); // + var knight2 = mCreatureFactory.CreateKnight(new Vector2(creature.IsAttackingBuilding.Position.X - 280, creature.IsAttackingBuilding.Position.Y + 150), MovementDirection.S); // + CreateBoss(king); + AddCreature(knight1); + AddCreature(knight2); + break; + } + //break; + } + // Checks if the creature moved out of the map and resets its position as appropriate. + if (!mMapRectangle.Contains(creature.Position)) + { + creature.ResetPosition(); + } + } + if (mFewerUpdates.IsItTime(gameTime)) + { + mInteractableQuadtree.Update(); + } + + #region Boss Special Attack + // Play some cool effects when boss is spawned so he looks cooler. + // Added a small special attack which does at bit AoE damage. + if (mEffectsCounter.IsItTime(gameTime)) + { + if (Boss != null && camera.ScreenRectangle.Contains(Boss.Position)) + { + mEffectsManager.PlayOnce(new Quake(), Boss.Position.ToPoint(), new Point(256, 128)); + var aoeRadius = new Rectangle(Boss.Position.ToPoint() - new Point(128), new Point(256)); + var effectedCreatures = mInteractableQuadtree.GetObjectsInRectangle(aoeRadius); + foreach (var obj in effectedCreatures) + { + var creature = obj as ICreature; + if (creature != null && creature.Faction == Faction.Undead && creature.BoundaryRectangle.Intersects(aoeRadius)) + { + creature.TakeDamage(10); + } + } + } + } + #endregion + + #region Necromancer stuff + if (PlayerCharacter.IsSelected && rightButtonPressed) + { + var objectsUnderMouse = + mInteractableQuadtree.GetObjectsInRectangle(new Rectangle(rightButtonPosition.ToPoint(), new Point(1, 1))); + foreach (var obj in objectsUnderMouse) + { + var creature = obj as ICreature; + if (creature == null || !creature.SelectionRectangle.Contains(rightButtonPosition) || !creature.IsDead || creature.Faction == Faction.Undead) continue; + if (Vector2.Distance(PlayerCharacter.Position, creature.Position) > PlayerCharacter.AttackRadius) continue; + RemoveCreature(creature); + if (creature is KingsGuard || creature is King || creature is Prince) + { + CreateCreature(mCreatureFactory.CreateSkeletonElite(creature.Position, creature.MovementDirection)); + } + else + { + CreateCreature(mCreatureFactory.CreateZombie(creature.Position, creature.MovementDirection)); + } + PlayerCharacter.PlayAnimationOnce(MovementState.Special, TimeSpan.FromSeconds(0.5d)); + mEffectsManager.PlayOnce(new BloodBang(), creature.Position.ToPoint(), new Point(128)); + break; + } + } + #endregion Necromancer stuff + + #region SkeletonRider + + var recMouse = new Rectangle(rightButtonPosition.ToPoint(), new Point(1, 1)); + foreach (var creature in UndeadCreatures) + { + Skeleton skeleton = creature as Skeleton; + if (skeleton != null) + { + if(skeleton.IsSelected && rightButtonPressed) + { + var atMousPosition = mInteractableQuadtree.GetObjectsInRectangle(recMouse); + foreach (var wannabehorse in atMousPosition) + { + var horse = wannabehorse as SkeletonHorse; + if (horse != null && Vector2.Distance(skeleton.Position, horse.Position) < 32) + { + horse.Mount(skeleton); + horse.IsSelected = true; + mAddToSelectables.Add(horse); + } + } + } + } + } + #endregion SkeletonRider + } + + private void AddCreature(ICreature creature) + { + if (!mMapRectangle.Contains(creature.BoundaryRectangle)) return; + mCreatureList.Add(creature); + mCreaturesByFactions[(int) creature.Faction].Add(creature); + mInteractableQuadtree.Insert(creature); + } + + public void ImportMapObjects(List textureObjects) + { + foreach (var obj in textureObjects) + { + if (obj is IBuilding) + { + mInteractableQuadtree.Insert(obj); + if (obj is Castle) + Castle = (Castle) obj; + } + else + { + mTextureQuadtree.Insert(obj); + } + } + } + + public List GetObjectsInRectangle(Rectangle rectangle) + { + return mInteractableQuadtree.GetObjectsInRectangle(rectangle); + } + + public List GetCreaturesInEllipse(Ellipse ellipse) + { + var setToReturn = new List(); + foreach (var obj in mInteractableQuadtree.GetObjectsInRectangle(ellipse.BoundaryRectangle)) + { + ICreature creature = obj as ICreature; + if (creature != null && ellipse.Contains(creature.Position)) + { + setToReturn.Add(creature); + } + } + return setToReturn; + } + + public void ExposeTheLiving() + { + foreach (var creature in mCreatureList) + { + if (creature.Faction == Faction.Plebs) + { + (creature as MalePeasant)?.RemoveArmor(); + (creature as FemalePeasant)?.RemoveArmor(); + } + else if (creature.Faction == Faction.Kingdom) + { + (creature as Knight)?.RemoveArmor(); + (creature as KingsGuard)?.RemoveArmor(); + } + } + } + + public bool InGraveyardArea(ICreature creature) + { + return mAreas.Where(area => area.Type == AreaType.Graveyard).Select(area => area.Contains(creature)).Any(contains => contains); + } + } +} diff --git a/V3/Objects/Prince.cs b/V3/Objects/Prince.cs new file mode 100644 index 0000000..b806f41 --- /dev/null +++ b/V3/Objects/Prince.cs @@ -0,0 +1,33 @@ +using System; +using Microsoft.Xna.Framework.Content; +using V3.Data; +using V3.Map; +using V3.Objects.Movement; +using V3.Objects.Sprite; + +namespace V3.Objects +{ + // ReSharper disable once ClassNeverInstantiated.Global + public sealed class Prince : AbstractCreature + { + public override string Name { get; protected set; } = "Prinz Erhard"; + public override int Life { get; protected set; } = 6000; + public override int MaxLife { get; protected set; } = 6000; + public override int Speed { get; } = 10; + public override int Attack { get; protected set; } = 35; + public override int AttackRadius { get; protected set; } = 48; + public override int SightRadius { get; protected set; } = 500; + public override TimeSpan TotalRecovery { get; } = TimeSpan.FromSeconds(0.5); + public override TimeSpan Recovery { get; set; } + protected override ISpriteCreature[] Sprite { get; } = { new PrinceSprite() }; + protected override IMovable MovementScheme { get; } = new PlayerMovement(); + protected override CreatureType Type { get; } = CreatureType.Prince; + public override Faction Faction { get; } = Faction.Kingdom; + public override ICreature IsAttacking { get; set; } + public override IBuilding IsAttackingBuilding { get; set; } + + public Prince(ContentManager contentManager, Pathfinder pathfinder, IOptionsManager optionsManager, AchievementsAndStatistics achievementsAndStatistics) : base(contentManager, pathfinder, optionsManager, achievementsAndStatistics) + { + } + } +} diff --git a/V3/Objects/Selection.cs b/V3/Objects/Selection.cs new file mode 100644 index 0000000..4ec7ccc --- /dev/null +++ b/V3/Objects/Selection.cs @@ -0,0 +1,483 @@ +using System; +using System.Collections.Generic; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Audio; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.Graphics; +using V3.Data; +using V3.Effects; + +namespace V3.Objects +{ + /// + /// Class for selecting creatures, holding the selection and drawing the selection rectangle on the screen. + /// + // ReSharper disable once ClassNeverInstantiated.Global + public sealed class Selection + { + private IObjectsManager mObjectsManager; + private IEffectsManager mEffectsManager; + private readonly Color mColor = Color.Black; + private Texture2D mTexture; + public List SelectedCreatures { get; private set; } = new List(); + private List TransformList { get; } = new List(); + private readonly CreatureFactory mCreatureFactory; + private int mDeadBodies; + private int mExplosionDeaths; + private Ellipse NecroArea { get; set; } + public Rectangle LastSelection { get; private set; } + private SoundEffect mSoundEffect; + private SoundEffectInstance mSoundEffectInstance; + private IOptionsManager mOptionsManager; + private AchievementsAndStatistics mAchievementsAndStatistics; + + public Selection(ContentManager contentManager, CreatureFactory creatureFactory, IObjectsManager objectsManager, + IEffectsManager effectsManager, IOptionsManager optionsmanager, AchievementsAndStatistics achievementsAndStatistics) + { + mCreatureFactory = creatureFactory; + mObjectsManager = objectsManager; + mEffectsManager = effectsManager; + mOptionsManager = optionsmanager; + mAchievementsAndStatistics = achievementsAndStatistics; + LoadContent(contentManager); + } + + private void LoadContent(ContentManager contentManager) + { + mTexture = contentManager.Load("Sprites/WhiteRectangle"); + mSoundEffect = contentManager.Load("Sounds/zonk2"); + mSoundEffectInstance = mSoundEffect.CreateInstance(); + } + + /// + /// Select all objects in the area of the rectangle between origin and destination. + /// + /// Position in pixels where the mouse button was pressed down. + /// Position in pixels where the mouse button was released. + public void Select(Point origin, Point destination) + { + // Clean last selection + SelectedCreatures.ForEach(e => e.IsSelected=false); + SelectedCreatures.Clear(); + + // New selection + int x, y, width, height; + if (origin.X > destination.X) + { + x = destination.X; + width = origin.X - destination.X; + } + else + { + x = origin.X; + width = destination.X - origin.X; + } + if (origin.Y > destination.Y) + { + y = destination.Y; + height = origin.Y - destination.Y; + } + else + { + y = origin.Y; + height = destination.Y - origin.Y; + } + + // Creates area for necromancer + var necroPos = mObjectsManager.PlayerCharacter; + NecroArea = new Ellipse(new Vector2((int)necroPos.Position.X, (int)necroPos.Position.Y), 1280, 640); + + // List for all objects in the current selection + LastSelection = new Rectangle(x, y, width, height); + var selectedObjects = mObjectsManager.GetObjectsInRectangle(LastSelection); + + // Lists to seperate undead from enemy creatures + var enemyCreatures = new List(); + var undeadCreatures = new List(); + + foreach (var obj in selectedObjects) + { + var creature = obj as ICreature; + // Give priority when selecting undead creatures. + if (creature != null && !creature.IsDead && LastSelection.Intersects(creature.SelectionRectangle) && NecroArea.Contains(creature.Position)) + { + if (creature.Faction != Faction.Undead) + { + enemyCreatures.Add(creature); + } + else + { + undeadCreatures.Add(creature); + } + } + } + SelectedCreatures = undeadCreatures.Count == 0 ? enemyCreatures : undeadCreatures; + + // Make all selectable creatures selected + foreach (var selectedCreature in SelectedCreatures) + { + selectedCreature.IsSelected = true; + } + } + + /// + /// Draw the selection rectangle on the screen. + /// + /// Sprite batch used. + /// Position in pixels where the mouse button was pressed down. + /// Position in pixels where the mouse button was released. + public void Draw(SpriteBatch spriteBatch, Point origin, Point destination) + { + if (origin.X > destination.X) + { + spriteBatch.Draw(mTexture, new Rectangle(destination.X, origin.Y, origin.X - destination.X, 2), mColor); + spriteBatch.Draw(mTexture, new Rectangle(destination.X, destination.Y, origin.X - destination.X, 2), mColor); + } + else + { + spriteBatch.Draw(mTexture, new Rectangle(origin.X, origin.Y, destination.X - origin.X, 2), mColor); + spriteBatch.Draw(mTexture, new Rectangle(origin.X, destination.Y, destination.X - origin.X, 2), mColor); + } + if (origin.Y > destination.Y) + { + spriteBatch.Draw(mTexture, new Rectangle(origin.X, destination.Y, 2, origin.Y - destination.Y), mColor); + spriteBatch.Draw(mTexture, new Rectangle(destination.X, destination.Y, 2, origin.Y - destination.Y), mColor); + } + else + { + spriteBatch.Draw(mTexture, new Rectangle(origin.X, origin.Y, 2, destination.Y - origin.Y), mColor); + spriteBatch.Draw(mTexture, new Rectangle(destination.X, origin.Y, 2, destination.Y - origin.Y), mColor); + } + } + + /// + /// Press 1 to trigger the specialattack of the meatball + /// All non undead creatures at the distance of 200 pixels take damage + /// After the attack the meatball disappears and three zombies will be created + /// + public void Specialattack() + { + foreach (var creature in SelectedCreatures) + { + var meatball = creature as Meatball; + if (meatball != null) + { + // Creates radius for meatballs explosion + var explosionRadius = new Rectangle((int)meatball.Position.X - 200, (int)meatball.Position.Y - 200, 400, 400); + var objectsInMeatballArea = mObjectsManager.GetObjectsInRectangle(explosionRadius); + + // Plays sounds and effects + mObjectsManager.PlayerCharacter.PlayAnimationOnce(MovementState.Special, TimeSpan.FromSeconds(0.5d)); + mEffectsManager.PlayOnce(new Explosion(), meatball.Position.ToPoint(), explosionRadius.Size * new Point(3, 2)); + + // All attackable creatures take damage (own undead creatures won't take damage) + foreach (var attackable in objectsInMeatballArea) + { + var toAttack = attackable as ICreature; + if (toAttack != null && toAttack.Faction != Faction.Undead) + { + toAttack.TakeDamage(meatball.Attack); + if (toAttack.IsDead) + mExplosionDeaths += 1; + } + } + + if (mExplosionDeaths >= 10) + mAchievementsAndStatistics.mKaboom = true; + mExplosionDeaths = 0; + + // The new zombies after explosion + var zombie1 = mCreatureFactory.CreateZombie(meatball.Position, meatball.MovementDirection); + var zombie2 = mCreatureFactory.CreateZombie(new Vector2(meatball.Position.X + 50, meatball.Position.Y + 50), meatball.MovementDirection); + var zombie3 = mCreatureFactory.CreateZombie(new Vector2(meatball.Position.X - 50, meatball.Position.Y - 50), meatball.MovementDirection); + + // Makes zombies be selected after explosion + zombie1.IsSelected = true; + zombie2.IsSelected = true; + zombie3.IsSelected = true; + meatball.IsSelected = false; + SelectedCreatures.Add(zombie1); + SelectedCreatures.Add(zombie2); + SelectedCreatures.Add(zombie3); + SelectedCreatures.Remove(meatball); + + // Remove meatball from game + mObjectsManager.RemoveCreature(meatball); + + // Add zombies to game + mObjectsManager.CreateCreature(zombie1); + mObjectsManager.CreateCreature(zombie2); + mObjectsManager.CreateCreature(zombie3); + + // For every zombie the necromancer gets healed + var heal = mObjectsManager.PlayerCharacter.Life * 0.12; + mObjectsManager.PlayerCharacter.Heal((int)heal); + + break; + } + } + } + + /// + /// Press 2 to create zombies from dead bodies + /// At least one dead body should be in necromancers area + /// + public void TransformZombie() + { + // Creates area for necromancer + var necroPos = mObjectsManager.PlayerCharacter; + NecroArea = new Ellipse(new Vector2((int) necroPos.Position.X, (int) necroPos.Position.Y), 1280, 640); + + // Get all creatures in necromancers area + var necroArea = mObjectsManager.GetCreaturesInEllipse(NecroArea); + + // Every dead body in necromancer area will be transformed to an zombie + // The prince will be transformed to an elite zombie + foreach (var creature in necroArea) + { + if (creature.Faction == Faction.Plebs || creature.Faction == Faction.Kingdom) + { + if (creature.IsDead) + { + ICreature zombie; + if (creature is KingsGuard || creature is King || creature is Prince) + zombie = mCreatureFactory.CreateSkeletonElite(creature.Position, creature.MovementDirection); + else + zombie = mCreatureFactory.CreateZombie(creature.Position, creature.MovementDirection); + + // Add zombie to game + mObjectsManager.CreateCreature(zombie); + + // Remove dead body from game + mObjectsManager.RemoveCreature(creature); + + // Play sounds and effects + mEffectsManager.PlayOnce(new BloodBang(), zombie.Position.ToPoint(), new Point(128)); + mObjectsManager.PlayerCharacter.PlayAnimationOnce(MovementState.Special, + TimeSpan.FromSeconds(0.5d)); + + // The number of dead bodies + mDeadBodies++; + + // For every zombie the necromancer gets healed + var heal = mObjectsManager.PlayerCharacter.Life * 0.04; + mObjectsManager.PlayerCharacter.Heal((int)heal); + } + } + } + + // Counts dead bodies in necromancers area and undead creatures + var set = mDeadBodies + mObjectsManager.UndeadCreatures.Count; + if (mObjectsManager.InGraveyardArea(mObjectsManager.PlayerCharacter) && set < 6) + { + mObjectsManager.PlayerCharacter.PlayAnimationOnce(MovementState.Special, TimeSpan.FromSeconds(0.5d)); + for (int i = 1; i <= 6 - set; i++) + { + var positionX = mObjectsManager.PlayerCharacter.Position.X + (float)Math.Sin(i) * 75; + var positionY = mObjectsManager.PlayerCharacter.Position.Y + (float)Math.Cos(i) * 75; + var zombie = mCreatureFactory.CreateZombie(new Vector2(positionX, positionY), mObjectsManager.PlayerCharacter.MovementDirection); + mObjectsManager.CreateCreature(zombie); + zombie.PlayAnimationOnce(MovementState.Special, TimeSpan.FromSeconds(1)); + } + } + mDeadBodies = 0; + } + + /// + /// Press 3 to create a meatball in exchange for five zombie + /// At least five zombies should be selected + /// + public void TransformMeatball() + { + // The cost for this transformation + var cost = mObjectsManager.PlayerCharacter.MaxLife * 0.12; + + // Transform only when necromancer life minus the transformations cost is not lower than 1 + if (mObjectsManager.PlayerCharacter.Life - (int)cost >= 1) + { + // Puts all zombies in a seperate list called TransformList + foreach (var creature in SelectedCreatures) + { + var zombie = creature as Zombie; + if (zombie != null && TransformList.Count < 5) + { + TransformList.Add(zombie); + } + } + + // Creates the meatball and makes him selected + if (TransformList.Count >= 5) + { + // Delete zombies from game and SelectedCratures + foreach (var zombie in TransformList) + { + SelectedCreatures.Remove(zombie); + mObjectsManager.RemoveCreature(zombie); + } + + // Add meatball to game + // Position will be randomly chosen from one of the zombies + var randomNumber = new Random(); + var positionMeatball = randomNumber.Next(5); + var meatball = mCreatureFactory.CreateMeatball(TransformList[positionMeatball].Position, + TransformList[positionMeatball].MovementDirection); + meatball.IsSelected = true; + SelectedCreatures.Add(meatball); + mObjectsManager.CreateCreature(meatball); + + // Plays sounds and effects + mObjectsManager.PlayerCharacter.PlayAnimationOnce(MovementState.Special, TimeSpan.FromSeconds(0.5d)); + mEffectsManager.PlayOnce(new BloodExplosion(), meatball.Position.ToPoint(), new Point(256)); + + // Necromancer takes damage + mObjectsManager.PlayerCharacter.TakeDamage((int)cost); + } + TransformList.Clear(); + } + else + { + // Play sound when transformation not possible + mSoundEffectInstance.Volume = mOptionsManager.Options.GetEffectiveVolume(); + mSoundEffectInstance.Play(); + } + } + + + /// + /// Press 4 to create an skeleton in exchange for an zombie + /// At least one zombie should be selected + /// + public void TransformSkeleton() + { + // Iterates through SelectedCreatures and takes the first zombie + foreach (var creature in SelectedCreatures) + { + var zombie = creature as Zombie; + if (zombie != null) + { + // Delete zombie + SelectedCreatures.Remove(zombie); + mObjectsManager.RemoveCreature(zombie); + + // Add skeleton + var skeleton = mCreatureFactory.CreateSkeleton(zombie.Position, zombie.MovementDirection); + skeleton.IsSelected = true; + SelectedCreatures.Add(skeleton); + mObjectsManager.CreateCreature(skeleton); + + // Plays sounds and effects + mObjectsManager.PlayerCharacter.PlayAnimationOnce(MovementState.Special, TimeSpan.FromSeconds(0.5d)); + mEffectsManager.PlayOnce(new BloodFountain(), zombie.Position.ToPoint() - new Point(0, 64), new Point(128)); + + break; + } + } + } + + /// + /// Press 5 to create an skeletonhorse in exchange for three skeletons + /// At least three skeletons should be selected + /// + public void TransformSkeletonHorse() + { + // The cost for this transformation + var cost = mObjectsManager.PlayerCharacter.MaxLife * 0.06; + + // Transform only when necromancer life minus the transformations cost is not lower than 1 + if (mObjectsManager.PlayerCharacter.Life - (int)cost >= 1) + { + + // Puts all skeletons in a seperate list called TransformList + foreach (var creature in SelectedCreatures) + { + var skeleton = creature as Skeleton; + if (skeleton != null && TransformList.Count < 3) + { + TransformList.Add(skeleton); + } + } + + // Creates the skeletonhorse and makes him selected + if (TransformList.Count >= 3) + { + // Delete zombies from game and SelectedCratures + foreach (var skeleton in TransformList) + { + SelectedCreatures.Remove(skeleton); + mObjectsManager.RemoveCreature(skeleton); + } + + // Add skeletonhorse to game + // Position will be randomly chosen from one of the skeletons + var randomNumber = new Random(); + var positionHorse = randomNumber.Next(3); + var skeletonHorse = mCreatureFactory.CreateSkeletonHorse(TransformList[positionHorse].Position, + TransformList[positionHorse].MovementDirection); + skeletonHorse.IsSelected = true; + SelectedCreatures.Add(skeletonHorse); + mObjectsManager.CreateCreature(skeletonHorse); + + // Plays sounds and effects + mObjectsManager.PlayerCharacter.PlayAnimationOnce(MovementState.Special, TimeSpan.FromSeconds(0.5d)); + mEffectsManager.PlayOnce(new HorseEffect(), skeletonHorse.Position.ToPoint() - new Point(0, 16), new Point(128)); + + + // Necromancer takes damage + mObjectsManager.PlayerCharacter.TakeDamage((int)cost); + } + TransformList.Clear(); + } + else + { + // Play sound when transformation not possible + mSoundEffectInstance.Volume = mOptionsManager.Options.GetEffectiveVolume(); + mSoundEffectInstance.Play(); + } + } + + /// + /// If creature leaves area og the necromancer, he gets disselected + /// + public void UpdateSelection() + { + // Creates area for necromancer + var necroPos = mObjectsManager.PlayerCharacter; + NecroArea = new Ellipse(new Vector2((int)necroPos.Position.X, (int)necroPos.Position.Y), 1280, 640); + + foreach (var creature in SelectedCreatures) + { + if (!NecroArea.Contains(creature.Position) || creature.IsDead) + creature.IsSelected = false; + } + + if (mObjectsManager.AddToSelectables.Count > 0) + { + SelectedCreatures.Add(mObjectsManager.AddToSelectables[0]); + mObjectsManager.AddToSelectables.Clear(); + } + } + + /// + /// Give movement command to selected creatures. + /// + /// Desired destination in pixels. + public void Move(Vector2 destination) + { + if (SelectedCreatures.Count == 0) return; + var centreCreature = SelectedCreatures[0]; + // You can not move enemy creatures. + if (centreCreature.Faction != Faction.Undead) return; + centreCreature.Move(destination); + + for (int i = 1; i < SelectedCreatures.Count; i++) + { + Vector2 flockDestination = destination; + Vector2 distance = centreCreature.Position - SelectedCreatures[i].Position; + distance.Normalize(); + distance *= 70; + flockDestination -= distance; + SelectedCreatures[i].Move(flockDestination); + } + } + } +} diff --git a/V3/Objects/Skeleton.cs b/V3/Objects/Skeleton.cs new file mode 100644 index 0000000..58eda62 --- /dev/null +++ b/V3/Objects/Skeleton.cs @@ -0,0 +1,65 @@ +using System; +using Microsoft.Xna.Framework.Content; +using V3.Data; +using V3.Map; +using V3.Objects.Movement; +using V3.Objects.Sprite; + +namespace V3.Objects +{ + /// + /// A skeleton controlled by the necromancer. + /// + public class Skeleton : AbstractCreature + { + /// + /// If the skeleton is mounted, it is not updated and drawn anymore because + /// instead the horse sprite is moved. + /// + public bool Mounted { private get; set; } + + public override string Name { get; protected set; } = "Skelett"; + public override int Life { get; protected set; } = 100; + public override int MaxLife { get; protected set; } = 100; + public override int Speed { get; } = 10; + public override int Attack { get; protected set; } = 10; + public override int AttackRadius { get; protected set; } = 48; + public override int SightRadius { get; protected set; } = 150; + public override TimeSpan TotalRecovery { get; } = TimeSpan.FromSeconds(0.5); + public override TimeSpan Recovery { get; set; } + protected override ISpriteCreature[] Sprite { get; } = {new SkeletonSprite()}; + protected override IMovable MovementScheme { get; } = new PlayerMovement(); + protected override CreatureType Type { get; } = CreatureType.Skeleton; + public override Faction Faction { get; } = Faction.Undead; + public override ICreature IsAttacking { get; set; } + public override IBuilding IsAttackingBuilding { get; set; } + + // ReSharper disable once MemberCanBeProtected.Global + public Skeleton(ContentManager contentManager, + Pathfinder pathfinder, IOptionsManager optionsManager, AchievementsAndStatistics achievementsAndStatistics) + : base(contentManager, pathfinder, optionsManager,achievementsAndStatistics) + { + } + + public override IGameObject GetSelf() + { + return Mounted ? null : base.GetSelf(); + } + + public override CreatureData SaveData() + { + var data = base.SaveData(); + data.Mounted = Mounted; + return data; + } + + public override void LoadData(CreatureData data) + { + base.LoadData(data); + Mounted = data.Mounted; + + if (IsUpgraded) + ChangeEquipment(EquipmentType.Body, new SkeletonArcherSprite()); + } + } +} diff --git a/V3/Objects/SkeletonElite.cs b/V3/Objects/SkeletonElite.cs new file mode 100644 index 0000000..ac3c6c4 --- /dev/null +++ b/V3/Objects/SkeletonElite.cs @@ -0,0 +1,19 @@ +using Microsoft.Xna.Framework.Content; +using V3.Data; +using V3.Map; +using V3.Objects.Sprite; + +namespace V3.Objects +{ + public sealed class SkeletonElite : Skeleton + { + public override int Life { get; protected set; } = 200; + public override int MaxLife { get; protected set; } = 200; + public override int Attack { get; protected set; } = 30; + protected override ISpriteCreature[] Sprite { get; } = { new SkeletonEliteSprite() }; + + public SkeletonElite(ContentManager contentManager, Pathfinder pathfinder, IOptionsManager optionsManager, AchievementsAndStatistics achievementsAndStatistics) : base(contentManager, pathfinder, optionsManager, achievementsAndStatistics) + { + } + } +} \ No newline at end of file diff --git a/V3/Objects/SkeletonHorse.cs b/V3/Objects/SkeletonHorse.cs new file mode 100644 index 0000000..6cd441d --- /dev/null +++ b/V3/Objects/SkeletonHorse.cs @@ -0,0 +1,87 @@ +using System; +using System.Collections.Generic; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Content; +using V3.Data; +using V3.Map; +using V3.Objects.Movement; +using V3.Objects.Sprite; + +namespace V3.Objects +{ + public sealed class SkeletonHorse : AbstractCreature + { + public SkeletonHorse(ContentManager contentManager, Pathfinder pathfinder, IOptionsManager optionsManager, AchievementsAndStatistics achievementsAndStatistics) : base(contentManager, pathfinder, optionsManager, achievementsAndStatistics) + { + } + + private Skeleton mSkeleton; + + protected override ISpriteCreature[] Sprite { get; } = {new SkeletonHorseSprite()}; + protected override IMovable MovementScheme { get; } = new PlayerMovement(); + protected override CreatureType Type { get; } = CreatureType.SkeletonHorse; + public override string Name { get; protected set; } = "Totenpferd"; + public override int Life { get; protected set; } = 150; + public override int MaxLife { get; protected set; } = 150; + public override int Speed { get; } = 20; + public override int Attack { get; protected set; } + public override int AttackRadius { get; protected set; } + public override int SightRadius { get; protected set; } + public override TimeSpan TotalRecovery { get; } = TimeSpan.FromSeconds(0.5); + public override TimeSpan Recovery { get; set; } + public override Faction Faction { get; } = Faction.Undead; + public override ICreature IsAttacking { get; set; } + public override IBuilding IsAttackingBuilding { get; set; } + + protected override Point CreatureSize { get; } = new Point(36); + protected override Point BoundaryShift { get; } = new Point(-18, -24); + + /// + /// A skeleton mounts a horse, becoming a skeleton rider. + /// + /// The skeleton which mounts the horse. + public void Mount(Skeleton skeleton) + { + if (IsDead || skeleton.IsDead || mSkeleton != null) return; + skeleton.Mounted = true; + mSkeleton = skeleton; + ChangeEquipment(EquipmentType.Body, new SkeletonRiderSprite()); + Attack = skeleton.Attack; + AttackRadius = skeleton.AttackRadius * 2; + // Sight radius is higher because skeleton is mounted. + SightRadius = skeleton.SightRadius * 2; + Name = "Skelettreiter"; + } + + protected override void Die() + { + if (mSkeleton != null) + { + mSkeleton.Position = Position; + mSkeleton.Mounted = false; + mSkeleton = null; + ChangeEquipment(EquipmentType.Body, new SkeletonHorseSprite()); + } + base.Die(); + } + + public override CreatureData SaveData() + { + var data = base.SaveData(); + if (mSkeleton != null) + data.SkeletonId = mSkeleton.Id; + return data; + } + + public override void LoadReferences(CreatureData data, Dictionary creatures) + { + base.LoadReferences(data, creatures); + if (creatures.ContainsKey(data.SkeletonId)) + { + var creature = creatures[data.SkeletonId]; + if (creature is Skeleton) + Mount((Skeleton) creature); + } + } + } +} diff --git a/V3/Objects/Sprite/AbstractSpriteCreature.cs b/V3/Objects/Sprite/AbstractSpriteCreature.cs new file mode 100644 index 0000000..bde139e --- /dev/null +++ b/V3/Objects/Sprite/AbstractSpriteCreature.cs @@ -0,0 +1,201 @@ +using System; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.Graphics; + +namespace V3.Objects.Sprite +{ + public abstract class AbstractSpriteCreature : ISpriteCreature + { + // How many frames are there for each animation type? + protected virtual int IdleFrames { get; } = 4; + protected virtual int MovingFrames { get; } = 8; + protected virtual int AttackingFrames { get; } = 4; + protected virtual int DyingFrames { get; } = 6; + protected virtual int SpecialFrames { get; } = 4; + + /// The row of the specific textures in the texture file. + protected virtual int IdleTextureIndex { get; } = 0; + protected virtual int MovingTextureIndex { get; } = 4; + protected virtual int AttackingTextureIndex { get; } = 12; + protected virtual int DyingTextureIndex { get; } = 18; + protected virtual int SpecialTextureIndex { get; } = 24; + + + // Specify the size of a single animation frame in pixel. + private const int SpriteWidth = 128; + private const int SpriteHeight = 128; + private readonly Point mSpriteShift = new Point(-SpriteWidth / 2, -SpriteHeight * 3 / 4); + private readonly Point mSpriteSize = new Point(SpriteWidth, SpriteHeight); + + private double mTimeSinceUpdate; + private Texture2D mTexture; + // How much time until animation frame is changed (in milliseconds). + private const int UpdatesPerMSec = 125; // 8 FPS + private MovementState mLastMovementState = MovementState.Idle; + private MovementState mCurrentMovementState = MovementState.Idle; + private int mMaxAnimationSteps; + private int mMovementStateRow; + private bool mIdleBackwardsLoop; + private int mAnimationState; + + // Fields for PlayOnce method. + private bool mPriorityAnimation; + private UpdatesPerSecond mUpS; + + protected abstract string TextureFile { get; } + + /// + /// Loads the texture file and prepares animations. + /// + /// + public void Load(ContentManager contentManager) + { + mTexture = contentManager.Load("Sprites/" + TextureFile); + mMaxAnimationSteps = IdleFrames; + } + + /// + /// Draws the sprite on the screen. + /// + /// Sprite batch used for drawing. + /// Position on the screen where sprite is drawn to. + /// What moveset will be used? (Moving, Attacking...) + /// Where does the sprite face? + public void Draw(SpriteBatch spriteBatch, Vector2 position, MovementState movementState, MovementDirection movementDirection) + { + mCurrentMovementState = movementState; + Point sourceLocation = new Point((mMovementStateRow + mAnimationState) * SpriteWidth, + (int) movementDirection * SpriteHeight); + Rectangle sourceRectangle = new Rectangle(sourceLocation, mSpriteSize); + spriteBatch.Draw(mTexture, position + new Vector2(mSpriteShift.X, mSpriteShift.Y), sourceRectangle, Color.White); + } + + public void DrawStatic(SpriteBatch spriteBatch, Point position, MovementState movementState, MovementDirection movementDirection) + { + Point sourceLocation = new Point((int)movementState * SpriteWidth, (int)movementDirection * SpriteHeight); + Rectangle destinationRectangle = new Rectangle(position + mSpriteShift, mSpriteSize); + Rectangle sourceRectangle = new Rectangle(sourceLocation, mSpriteSize); + spriteBatch.Draw(mTexture, destinationRectangle, sourceRectangle, Color.White); + } + + /// + /// Change the sprite to show an animation. + /// + /// Elapsed game time is used for calculating FPS. + public void PlayAnimation(GameTime gameTime) + { + // Playing a single animation cycle just once with higher priority. + if (mPriorityAnimation) + { + if (mAnimationState < mMaxAnimationSteps - 1) + { + if (mUpS.IsItTime(gameTime)) + { + mAnimationState++; + } + return; + } + mAnimationState = 0; + mCurrentMovementState = mLastMovementState; + SelectFrames(mCurrentMovementState); + mPriorityAnimation = false; + return; + } + + // Change texture for showing animations according to elapsed game time. + mTimeSinceUpdate += gameTime.ElapsedGameTime.TotalMilliseconds; + if (mTimeSinceUpdate < UpdatesPerMSec) + { + return; + } + mTimeSinceUpdate = 0; + + // Check which specific animation sprites need to be used. + // Only check if movement state is changed. + if (mCurrentMovementState != mLastMovementState) + { + SelectFrames(mCurrentMovementState); + mAnimationState = 0; + mLastMovementState = mCurrentMovementState; + } + + // Idle animation is looped back and forth. + if (mIdleBackwardsLoop) + { + mAnimationState--; + if (mAnimationState <= 0) + { + mIdleBackwardsLoop = false; + } + return; + } + + if (mAnimationState < mMaxAnimationSteps - 1) + { + mAnimationState++; + } + else + { + if (mLastMovementState == MovementState.Idle) + { + mIdleBackwardsLoop = true; + mAnimationState--; + } + else if (mLastMovementState == MovementState.Dying) + { + } + else + { + mAnimationState = 0; + } + } + } + + private void SelectFrames(MovementState currentMovementState) + { + switch (currentMovementState) + { + case MovementState.Idle: + mMaxAnimationSteps = IdleFrames; + mMovementStateRow = IdleTextureIndex; + mIdleBackwardsLoop = false; + break; + case MovementState.Moving: + mMaxAnimationSteps = MovingFrames; + mMovementStateRow = MovingTextureIndex; + break; + case MovementState.Attacking: + mMaxAnimationSteps = AttackingFrames; + mMovementStateRow = AttackingTextureIndex; + break; + case MovementState.Dying: + mMaxAnimationSteps = DyingFrames; + mMovementStateRow = DyingTextureIndex; + break; + case MovementState.Special: + mMaxAnimationSteps = SpecialFrames; + mMovementStateRow = SpecialTextureIndex; + break; + default: + mMaxAnimationSteps = 1; // No Animation if default case is reached. + break; + } + } + + /// + /// Plays the specified animation fully, but only once. + /// + /// For which movement state the animation should be played. + /// How long (or how slow) should the animation be? + public void PlayOnce(MovementState animation, TimeSpan duration) + { + mLastMovementState = mCurrentMovementState; + mCurrentMovementState = animation; + mPriorityAnimation = true; + SelectFrames(animation); + mAnimationState = 0; + mUpS = new UpdatesPerSecond(1d / (duration.TotalSeconds / mMaxAnimationSteps)); + } + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/ArrowSprite.cs b/V3/Objects/Sprite/ArrowSprite.cs new file mode 100644 index 0000000..76e34b7 --- /dev/null +++ b/V3/Objects/Sprite/ArrowSprite.cs @@ -0,0 +1,42 @@ +using System; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.Graphics; + +namespace V3.Objects.Sprite +{ + /// + /// A simple arrow from different directions without animations. + /// + public sealed class ArrowSprite : ISpriteCreature + { + private Texture2D mTexture; + private const int Size = 64; + + public void Load(ContentManager contentManager) + { + mTexture = contentManager.Load("Sprites/arrows"); + } + + public void Draw(SpriteBatch spriteBatch, Vector2 position, MovementState movementState, MovementDirection movementDirection) + { + spriteBatch.Draw(mTexture, position - new Vector2(Size / 2f), new Rectangle(0, Size * (int) movementDirection, Size, Size), Color.White); + } + + public void DrawStatic(SpriteBatch spriteBatch, + Point position, + MovementState movementState, + MovementDirection movementDirection) + { + Draw(spriteBatch, position.ToVector2(), movementState, movementDirection); + } + + public void PlayAnimation(GameTime gameTime) + { + } + + public void PlayOnce(MovementState animation, TimeSpan duration) + { + } + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/BucklerFemaleSprite.cs b/V3/Objects/Sprite/BucklerFemaleSprite.cs new file mode 100644 index 0000000..7d72869 --- /dev/null +++ b/V3/Objects/Sprite/BucklerFemaleSprite.cs @@ -0,0 +1,7 @@ +namespace V3.Objects.Sprite +{ + public class BucklerFemaleSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "buckler_female"; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/BucklerSprite.cs b/V3/Objects/Sprite/BucklerSprite.cs new file mode 100644 index 0000000..c55ed81 --- /dev/null +++ b/V3/Objects/Sprite/BucklerSprite.cs @@ -0,0 +1,7 @@ +namespace V3.Objects.Sprite +{ + public class BucklerSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "buckler"; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/ChainFemaleSprite.cs b/V3/Objects/Sprite/ChainFemaleSprite.cs new file mode 100644 index 0000000..eddfe9d --- /dev/null +++ b/V3/Objects/Sprite/ChainFemaleSprite.cs @@ -0,0 +1,7 @@ +namespace V3.Objects.Sprite +{ + public sealed class ChainFemaleSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "chain_female"; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/ChainSprite.cs b/V3/Objects/Sprite/ChainSprite.cs new file mode 100644 index 0000000..33e7042 --- /dev/null +++ b/V3/Objects/Sprite/ChainSprite.cs @@ -0,0 +1,7 @@ +namespace V3.Objects.Sprite +{ + public sealed class ChainSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "chain"; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/ClothFemaleSprite.cs b/V3/Objects/Sprite/ClothFemaleSprite.cs new file mode 100644 index 0000000..3edaec1 --- /dev/null +++ b/V3/Objects/Sprite/ClothFemaleSprite.cs @@ -0,0 +1,7 @@ +namespace V3.Objects.Sprite +{ + public sealed class ClothFemaleSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "cloth_female"; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/ClothSprite.cs b/V3/Objects/Sprite/ClothSprite.cs new file mode 100644 index 0000000..b3aaff0 --- /dev/null +++ b/V3/Objects/Sprite/ClothSprite.cs @@ -0,0 +1,7 @@ +namespace V3.Objects.Sprite +{ + public sealed class ClothSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "cloth"; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/EquipmentType.cs b/V3/Objects/Sprite/EquipmentType.cs new file mode 100644 index 0000000..611c35d --- /dev/null +++ b/V3/Objects/Sprite/EquipmentType.cs @@ -0,0 +1,10 @@ +namespace V3.Objects.Sprite +{ + /// + /// Different types of equipment slots. + /// + public enum EquipmentType + { + Body, Head, Weapon, Offhand + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/HeadBaldSprite.cs b/V3/Objects/Sprite/HeadBaldSprite.cs new file mode 100644 index 0000000..7b01e16 --- /dev/null +++ b/V3/Objects/Sprite/HeadBaldSprite.cs @@ -0,0 +1,10 @@ +using System.Diagnostics.CodeAnalysis; + +namespace V3.Objects.Sprite +{ + [SuppressMessage("ReSharper", "UnusedMember.Global")] + public sealed class HeadBaldSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "head_bald"; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/HeadChainFemaleSprite.cs b/V3/Objects/Sprite/HeadChainFemaleSprite.cs new file mode 100644 index 0000000..8d8ed90 --- /dev/null +++ b/V3/Objects/Sprite/HeadChainFemaleSprite.cs @@ -0,0 +1,7 @@ +namespace V3.Objects.Sprite +{ + public class HeadChainFemaleSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "head_chain_female"; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/HeadChainSprite.cs b/V3/Objects/Sprite/HeadChainSprite.cs new file mode 100644 index 0000000..31476f1 --- /dev/null +++ b/V3/Objects/Sprite/HeadChainSprite.cs @@ -0,0 +1,7 @@ +namespace V3.Objects.Sprite +{ + public class HeadChainSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "head_chain"; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/HeadFemaleSprite.cs b/V3/Objects/Sprite/HeadFemaleSprite.cs new file mode 100644 index 0000000..b8649aa --- /dev/null +++ b/V3/Objects/Sprite/HeadFemaleSprite.cs @@ -0,0 +1,7 @@ +namespace V3.Objects.Sprite +{ + public sealed class HeadFemaleSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "head_female"; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/HeadPlateFemaleSprite.cs b/V3/Objects/Sprite/HeadPlateFemaleSprite.cs new file mode 100644 index 0000000..8ad7917 --- /dev/null +++ b/V3/Objects/Sprite/HeadPlateFemaleSprite.cs @@ -0,0 +1,7 @@ +namespace V3.Objects.Sprite +{ + public sealed class HeadPlateFemaleSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "head_plate_female"; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/HeadPlateSprite.cs b/V3/Objects/Sprite/HeadPlateSprite.cs new file mode 100644 index 0000000..fa237b3 --- /dev/null +++ b/V3/Objects/Sprite/HeadPlateSprite.cs @@ -0,0 +1,7 @@ +namespace V3.Objects.Sprite +{ + public sealed class HeadPlateSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "head_plate"; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/HeadSprite.cs b/V3/Objects/Sprite/HeadSprite.cs new file mode 100644 index 0000000..303bb8a --- /dev/null +++ b/V3/Objects/Sprite/HeadSprite.cs @@ -0,0 +1,7 @@ +namespace V3.Objects.Sprite +{ + public sealed class HeadSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "head"; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/ISpriteCreature.cs b/V3/Objects/Sprite/ISpriteCreature.cs new file mode 100644 index 0000000..1339b2a --- /dev/null +++ b/V3/Objects/Sprite/ISpriteCreature.cs @@ -0,0 +1,53 @@ +using System; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.Graphics; + +namespace V3.Objects.Sprite +{ + /// + /// + /// + public interface ISpriteCreature + { + /// + /// Loads the texture file and prepares animations. + /// + /// Content manager used. + void Load(ContentManager contentManager); + + /// + /// Draws the sprite on the screen. + /// + /// Sprite batch used for drawing. + /// Position on the screen in pixels where the sprite should stand. + /// What moveset will be used? (Moving, Attacking...) + /// Where does the sprite face to? + void Draw(SpriteBatch spriteBatch, Vector2 position, MovementState movementState, MovementDirection movementDirection); + + /// + /// Draws a static image of the sprite. No animations. + /// + /// Sprite batch used for drawing. + /// Position of the sprite in pixels. (Where are the feet of the sprite placed. + /// What moveset will be used? (Moving, Attacking...) + /// Where does the sprite face to? + void DrawStatic(SpriteBatch spriteBatch, + Point position, + MovementState movementState, + MovementDirection movementDirection); + + /// + /// Change the sprite to show an animation. + /// + /// Elapsed game time is used for calculating FPS. + void PlayAnimation(GameTime gameTime); + + /// + /// Plays the specified animation fully, but only once. + /// + /// For which movement state the animation should be played. + /// How long (or how slow) should the animation be? + void PlayOnce(MovementState animation, TimeSpan duration); + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/KingSprite.cs b/V3/Objects/Sprite/KingSprite.cs new file mode 100644 index 0000000..0640514 --- /dev/null +++ b/V3/Objects/Sprite/KingSprite.cs @@ -0,0 +1,7 @@ +namespace V3.Objects.Sprite +{ + public class KingSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "king"; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/LongswordFemaleSprite.cs b/V3/Objects/Sprite/LongswordFemaleSprite.cs new file mode 100644 index 0000000..fc10b7c --- /dev/null +++ b/V3/Objects/Sprite/LongswordFemaleSprite.cs @@ -0,0 +1,7 @@ +namespace V3.Objects.Sprite +{ + public sealed class LongswordFemaleSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "longsword_female"; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/LongswordSprite.cs b/V3/Objects/Sprite/LongswordSprite.cs new file mode 100644 index 0000000..7ac1850 --- /dev/null +++ b/V3/Objects/Sprite/LongswordSprite.cs @@ -0,0 +1,7 @@ +namespace V3.Objects.Sprite +{ + public sealed class LongswordSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "longsword"; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/MeatballSprite.cs b/V3/Objects/Sprite/MeatballSprite.cs new file mode 100644 index 0000000..eeafbe9 --- /dev/null +++ b/V3/Objects/Sprite/MeatballSprite.cs @@ -0,0 +1,11 @@ +namespace V3.Objects.Sprite +{ + public sealed class MeatballSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "fleischklops"; + protected override int AttackingFrames { get; } = 12; + protected override int DyingFrames { get; } = 8; + protected override int AttackingTextureIndex { get; } = 12; + protected override int DyingTextureIndex { get; } = 24; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/NecromancerFemaleSprite.cs b/V3/Objects/Sprite/NecromancerFemaleSprite.cs new file mode 100644 index 0000000..ffecd74 --- /dev/null +++ b/V3/Objects/Sprite/NecromancerFemaleSprite.cs @@ -0,0 +1,7 @@ +namespace V3.Objects.Sprite +{ + public class NecromancerFemaleSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "necromancer_female"; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/NecromancerSprite.cs b/V3/Objects/Sprite/NecromancerSprite.cs new file mode 100644 index 0000000..494ba13 --- /dev/null +++ b/V3/Objects/Sprite/NecromancerSprite.cs @@ -0,0 +1,7 @@ +namespace V3.Objects.Sprite +{ + public sealed class NecromancerSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "necromancer"; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/NudeFemaleSprite.cs b/V3/Objects/Sprite/NudeFemaleSprite.cs new file mode 100644 index 0000000..e2aaa2f --- /dev/null +++ b/V3/Objects/Sprite/NudeFemaleSprite.cs @@ -0,0 +1,7 @@ +namespace V3.Objects.Sprite +{ + public sealed class NudeFemaleSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "nude_female"; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/NudeSprite.cs b/V3/Objects/Sprite/NudeSprite.cs new file mode 100644 index 0000000..1056335 --- /dev/null +++ b/V3/Objects/Sprite/NudeSprite.cs @@ -0,0 +1,7 @@ +namespace V3.Objects.Sprite +{ + public sealed class NudeSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "nude"; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/PlateFemaleSprite.cs b/V3/Objects/Sprite/PlateFemaleSprite.cs new file mode 100644 index 0000000..af3bd79 --- /dev/null +++ b/V3/Objects/Sprite/PlateFemaleSprite.cs @@ -0,0 +1,7 @@ +namespace V3.Objects.Sprite +{ + public sealed class PlateFemaleSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "plate_female"; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/PlateSprite.cs b/V3/Objects/Sprite/PlateSprite.cs new file mode 100644 index 0000000..c8495a0 --- /dev/null +++ b/V3/Objects/Sprite/PlateSprite.cs @@ -0,0 +1,7 @@ +namespace V3.Objects.Sprite +{ + public sealed class PlateSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "plate"; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/PrinceSprite.cs b/V3/Objects/Sprite/PrinceSprite.cs new file mode 100644 index 0000000..efe9d18 --- /dev/null +++ b/V3/Objects/Sprite/PrinceSprite.cs @@ -0,0 +1,7 @@ +namespace V3.Objects.Sprite +{ + public sealed class PrinceSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "prince"; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/ShieldFemaleSprite.cs b/V3/Objects/Sprite/ShieldFemaleSprite.cs new file mode 100644 index 0000000..0e70545 --- /dev/null +++ b/V3/Objects/Sprite/ShieldFemaleSprite.cs @@ -0,0 +1,7 @@ +namespace V3.Objects.Sprite +{ + public sealed class ShieldFemaleSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "shield_female"; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/ShieldSprite.cs b/V3/Objects/Sprite/ShieldSprite.cs new file mode 100644 index 0000000..5830a45 --- /dev/null +++ b/V3/Objects/Sprite/ShieldSprite.cs @@ -0,0 +1,7 @@ +namespace V3.Objects.Sprite +{ + public sealed class ShieldSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "shield"; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/ShortswordFemaleSprite.cs b/V3/Objects/Sprite/ShortswordFemaleSprite.cs new file mode 100644 index 0000000..a046bb0 --- /dev/null +++ b/V3/Objects/Sprite/ShortswordFemaleSprite.cs @@ -0,0 +1,7 @@ +namespace V3.Objects.Sprite +{ + public class ShortswordFemaleSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "shortsword_female"; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/ShortswordSprite.cs b/V3/Objects/Sprite/ShortswordSprite.cs new file mode 100644 index 0000000..352631f --- /dev/null +++ b/V3/Objects/Sprite/ShortswordSprite.cs @@ -0,0 +1,7 @@ +namespace V3.Objects.Sprite +{ + public class ShortswordSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "shortsword"; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/SkeletonArcherSprite.cs b/V3/Objects/Sprite/SkeletonArcherSprite.cs new file mode 100644 index 0000000..1891939 --- /dev/null +++ b/V3/Objects/Sprite/SkeletonArcherSprite.cs @@ -0,0 +1,10 @@ +namespace V3.Objects.Sprite +{ + public class SkeletonArcherSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "skeleton_archer"; + protected override int AttackingFrames { get; } = 4; + protected override int AttackingTextureIndex { get; } = 28; + protected override int DyingTextureIndex { get; } = 22; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/SkeletonEliteSprite.cs b/V3/Objects/Sprite/SkeletonEliteSprite.cs new file mode 100644 index 0000000..99aa94b --- /dev/null +++ b/V3/Objects/Sprite/SkeletonEliteSprite.cs @@ -0,0 +1,9 @@ +namespace V3.Objects.Sprite +{ + public class SkeletonEliteSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "skeleton_elite"; + protected override int AttackingFrames { get; } = 4; + protected override int DyingTextureIndex { get; } = 22; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/SkeletonHorseSprite.cs b/V3/Objects/Sprite/SkeletonHorseSprite.cs new file mode 100644 index 0000000..f26b58b --- /dev/null +++ b/V3/Objects/Sprite/SkeletonHorseSprite.cs @@ -0,0 +1,7 @@ +namespace V3.Objects.Sprite +{ + public class SkeletonHorseSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "skeleton_horse"; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/SkeletonRiderSprite.cs b/V3/Objects/Sprite/SkeletonRiderSprite.cs new file mode 100644 index 0000000..278d8c7 --- /dev/null +++ b/V3/Objects/Sprite/SkeletonRiderSprite.cs @@ -0,0 +1,10 @@ +namespace V3.Objects.Sprite +{ + public class SkeletonRiderSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "skeleton_rider"; + protected override int AttackingFrames { get; } = 5; + protected override int DyingTextureIndex { get; } = 0; + protected override int DyingFrames { get; } = 0; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/SkeletonSprite.cs b/V3/Objects/Sprite/SkeletonSprite.cs new file mode 100644 index 0000000..15f7246 --- /dev/null +++ b/V3/Objects/Sprite/SkeletonSprite.cs @@ -0,0 +1,9 @@ +namespace V3.Objects.Sprite +{ + public sealed class SkeletonSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "skeleton"; + protected override int AttackingFrames { get; } = 4; + protected override int DyingTextureIndex { get; } = 22; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/StaffFemaleSprite.cs b/V3/Objects/Sprite/StaffFemaleSprite.cs new file mode 100644 index 0000000..5e4120c --- /dev/null +++ b/V3/Objects/Sprite/StaffFemaleSprite.cs @@ -0,0 +1,7 @@ +namespace V3.Objects.Sprite +{ + public class StaffFemaleSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "staff_female"; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/StaffSprite.cs b/V3/Objects/Sprite/StaffSprite.cs new file mode 100644 index 0000000..aac7bed --- /dev/null +++ b/V3/Objects/Sprite/StaffSprite.cs @@ -0,0 +1,7 @@ +namespace V3.Objects.Sprite +{ + public class StaffSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "staff"; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/ZombieSprite.cs b/V3/Objects/Sprite/ZombieSprite.cs new file mode 100644 index 0000000..0cd1a19 --- /dev/null +++ b/V3/Objects/Sprite/ZombieSprite.cs @@ -0,0 +1,11 @@ +namespace V3.Objects.Sprite +{ + public sealed class ZombieSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "zombie"; + protected override int AttackingFrames { get; } = 8; + protected override int DyingTextureIndex { get; } = 22; + protected override int SpecialTextureIndex { get; } = 36; + protected override int SpecialFrames { get; } = 8; + } +} \ No newline at end of file diff --git a/V3/Objects/Sprite/ZombieWithClubSprite.cs b/V3/Objects/Sprite/ZombieWithClubSprite.cs new file mode 100644 index 0000000..60abc24 --- /dev/null +++ b/V3/Objects/Sprite/ZombieWithClubSprite.cs @@ -0,0 +1,11 @@ +namespace V3.Objects.Sprite +{ + public sealed class ZombieWithClubSprite : AbstractSpriteCreature + { + protected override string TextureFile { get; } = "zombie_club"; + protected override int AttackingFrames { get; } = 8; + protected override int DyingTextureIndex { get; } = 22; + protected override int SpecialTextureIndex { get; } = 36; + protected override int SpecialFrames { get; } = 8; + } +} \ No newline at end of file diff --git a/V3/Objects/TextureObject.cs b/V3/Objects/TextureObject.cs new file mode 100644 index 0000000..b7da6c0 --- /dev/null +++ b/V3/Objects/TextureObject.cs @@ -0,0 +1,76 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.Graphics; +using System; + +namespace V3.Objects +{ + /// + /// Texture objects represent map data like tiles and map objects which are placed on the screen. + /// + public sealed class TextureObject : IGameObject + { + public Vector2 Position { get; set; } + public int Id { get; } + public Rectangle BoundaryRectangle => new Rectangle(mDrawPosition, mTextureSize); + private readonly string mTextureName; + private readonly Point mDrawPosition; + private readonly Point mTextureSize; + private Texture2D mTexture; + private readonly Point mTextureSource; + + /// + /// Creates an empty TextureObject. + /// + public TextureObject() + { + Id = IdGenerator.GetNextId(); + Position = Vector2.Zero; + mDrawPosition = Point.Zero; + mTextureSize = Point.Zero; + mTextureName = "EmptyPixel"; + mTextureSource = Point.Zero; + } + + public TextureObject(Point position, Point drawPosition, Point textureSize, Point textureSource, string textureName) + { + Position = position.ToVector2(); + mDrawPosition = drawPosition; + mTextureSize = textureSize; + mTextureName = textureName; + mTextureSource = textureSource; + } + + public void LoadContent(ContentManager contentManager) + { + mTexture = contentManager.Load("Textures/" + mTextureName); + //mOnePixelTexture = contentManager.Load("Sprites/WhiteRectangle"); + } + + public void Draw(SpriteBatch spriteBatch) + { + spriteBatch.Draw(mTexture, BoundaryRectangle, new Rectangle(mTextureSource, mTextureSize), Color.White); + } + + public IGameObject GetSelf() + { + return this; + } + + public override bool Equals(Object obj) + { + if (obj == null) + return false; + if (obj == this) + return true; + if (!(obj is IGameObject)) + return false; + return Id.Equals(((IGameObject) obj).Id); + } + + public override int GetHashCode() + { + return Id; + } + } +} diff --git a/V3/Objects/Transformation.cs b/V3/Objects/Transformation.cs new file mode 100644 index 0000000..1b1cf86 --- /dev/null +++ b/V3/Objects/Transformation.cs @@ -0,0 +1,102 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework.Input; + +namespace V3.Objects +{ + // ReSharper disable once ClassNeverInstantiated.Global + public sealed class Transformation + { + public IObjectsManager ObjectsManager { private get; set; } + private KeyboardState mOldStateSpecialattack; + private KeyboardState mOldStateZombie; + private KeyboardState mOldStateMeatball; + private KeyboardState mOldStateSkeleton; + private KeyboardState mOldStateHorse; + internal Selection mSelection; + private Texture2D mNecroArea; + + /// + /// Call for transformations + /// + public void Transform() + { + KeyboardState newState = Keyboard.GetState(); + + // Specialattack for Meatball (press 1) + if (newState.IsKeyDown(Keys.D1)) + { + if (!mOldStateSpecialattack.IsKeyDown(Keys.D1)) + { + mSelection.Specialattack(); + } + } + mOldStateSpecialattack = newState; + + // Transform Zombie (press 2) + if (newState.IsKeyDown(Keys.D2)) + { + if (!mOldStateZombie.IsKeyDown(Keys.D2)) + { + mSelection.TransformZombie(); + } + } + mOldStateZombie = newState; + + // Transform Meatball (press 3) + // Nneed five zombies + if (newState.IsKeyDown(Keys.D3)) + { + if (!mOldStateMeatball.IsKeyDown(Keys.D3)) + { + mSelection.TransformMeatball(); + } + } + mOldStateMeatball = newState; + + // Transform Skeleton (press 4) + // Need one zombie + if (newState.IsKeyDown(Keys.D4)) + { + if (!mOldStateSkeleton.IsKeyDown(Keys.D4)) + { + mSelection.TransformSkeleton(); + } + } + mOldStateSkeleton = newState; + + // Transform SkeletonHorse (press 5) + // Nneed 3 skeletons + if (newState.IsKeyDown(Keys.D5)) + { + if (!mOldStateHorse.IsKeyDown(Keys.D5)) + { + mSelection.TransformSkeletonHorse(); + } + } + mOldStateHorse = newState; + } + + //Draw(SpriteBatch spriteBatch, Vector2 position, MovementState movementState, MovementDirection movementDirection) + /// + /// Load the selection and ellipse sprites for necromancers area + /// + /// the content manager + public void LoadArea(ContentManager contentManager) + { + //mNecroArea = contentManager.Load("Sprites/selection"); + mNecroArea = contentManager.Load("Sprites/ellipse"); + } + + /// + /// Draw the area for necromancer + /// + /// the sprite batch to use for drawing the object + public void DrawNecroArea(SpriteBatch spriteBatch) + { + //spriteBatch.Draw(mNecroArea, ObjectsManager.PlayerCharacter.Position - new Vector2(800, 400), null, Color.Red*0.3f, 0, Vector2.Zero, 25, SpriteEffects.None, 0); + spriteBatch.Draw(mNecroArea, ObjectsManager.PlayerCharacter.Position - new Vector2(640, 320), null, Color.Red*0.5f, 0, Vector2.Zero, 2.5f, SpriteEffects.None, 0); + } + } +} \ No newline at end of file diff --git a/V3/Objects/Woodhouse.cs b/V3/Objects/Woodhouse.cs new file mode 100644 index 0000000..82c961b --- /dev/null +++ b/V3/Objects/Woodhouse.cs @@ -0,0 +1,16 @@ +using Microsoft.Xna.Framework; + +namespace V3.Objects +{ + public sealed class Woodhouse : AbstractBuilding + { + public override string Name { get; } = "Holzhaus"; + protected override int MaxRobustness { get; } = 130; + public override int Robustness { get; protected set; } = 130; + public override int MaxGivesWeapons { get; protected set; } = 10; + + public Woodhouse(Vector2 position, Rectangle size, string textureName, BuildingFace facing) : base(position, size, textureName, facing) + { + } + } +} diff --git a/V3/Objects/Zombie.cs b/V3/Objects/Zombie.cs new file mode 100644 index 0000000..635634c --- /dev/null +++ b/V3/Objects/Zombie.cs @@ -0,0 +1,45 @@ +using System; +using Microsoft.Xna.Framework.Content; +using V3.Data; +using V3.Map; +using V3.Objects.Movement; +using V3.Objects.Sprite; + +namespace V3.Objects +{ + /// + /// A simple zombie controlled by the necromancer. + /// + public sealed class Zombie : AbstractCreature + { + public override string Name { get; protected set; } = "Zombie"; + public override int Life { get; protected set; } = 150; + public override int MaxLife { get; protected set; } = 150; + public override int Speed { get; } = 5; + public override int Attack { get; protected set; } = 8; + public override int AttackRadius { get; protected set; } = 48; + public override int SightRadius { get; protected set; } = 150; + public override TimeSpan TotalRecovery { get; } = TimeSpan.FromSeconds(1); + public override TimeSpan Recovery { get; set; } + protected override ISpriteCreature[] Sprite { get; } = {new ZombieSprite()}; + protected override IMovable MovementScheme { get; } = new PlayerMovement(); + protected override CreatureType Type { get; } = CreatureType.Zombie; + public override Faction Faction { get; } = Faction.Undead; + public override ICreature IsAttacking { get; set; } + public override IBuilding IsAttackingBuilding { get; set; } + + public Zombie(ContentManager contentManager, + Pathfinder pathfinder, IOptionsManager optionsManager, AchievementsAndStatistics achievementsAndStatistics) + : base(contentManager, pathfinder, optionsManager,achievementsAndStatistics) + { + } + + public override void LoadData(CreatureData data) + { + base.LoadData(data); + + if (IsUpgraded) + ChangeEquipment(EquipmentType.Body, new ZombieWithClubSprite()); + } + } +} diff --git a/V3/OpenTK.dll.config b/V3/OpenTK.dll.config new file mode 100644 index 0000000..3f888cc --- /dev/null +++ b/V3/OpenTK.dll.config @@ -0,0 +1,25 @@ + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/V3/Program.cs b/V3/Program.cs new file mode 100644 index 0000000..aa1fdcd --- /dev/null +++ b/V3/Program.cs @@ -0,0 +1,20 @@ +using System; + +namespace V3 +{ + /// + /// The main class. + /// + public static class Program + { + /// + /// The main entry point for the application. + /// + [STAThread] + static void Main() + { + using (var game = new V3Game()) + game.Run(); + } + } +} diff --git a/V3/Properties/AssemblyInfo.cs b/V3/Properties/AssemblyInfo.cs new file mode 100644 index 0000000..4f905d4 --- /dev/null +++ b/V3/Properties/AssemblyInfo.cs @@ -0,0 +1,35 @@ +using System.Reflection; +using System.Runtime.InteropServices; + +// General Information about an assembly is controlled through the following +// set of attributes. Change these attribute values to modify the information +// associated with an assembly. +[assembly: AssemblyTitle("V3")] +[assembly: AssemblyProduct("V3")] +[assembly: AssemblyConfiguration("")] +[assembly: AssemblyDescription("")] +[assembly: AssemblyCompany("")] +[assembly: AssemblyCopyright("Copyright © 2016")] +[assembly: AssemblyTrademark("")] +[assembly: AssemblyCulture("")] + +// Setting ComVisible to false makes the types in this assembly not visible +// to COM components. If you need to access a type in this assembly from +// COM, set the ComVisible attribute to true on that type. +[assembly: ComVisible(false)] + +// The following GUID is for the ID of the typelib if this project is exposed to COM +[assembly: Guid("0c41bf76-037f-47fb-b16a-0c32567c6067")] + +// Version information for an assembly consists of the following four values: +// +// Major Version +// Minor Version +// Build Number +// Revision +// +// You can specify all the values or you can default the Build and Revision Numbers +// by using the '*' as shown below: +// [assembly: AssemblyVersion("1.0.*")] +[assembly: AssemblyVersion("1.0.0.0")] +[assembly: AssemblyFileVersion("1.0.0.0")] diff --git a/V3/Quadtree.cs b/V3/Quadtree.cs new file mode 100644 index 0000000..dfc088f --- /dev/null +++ b/V3/Quadtree.cs @@ -0,0 +1,87 @@ +using System.Collections.Generic; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.Graphics; +using V3.Objects; + +namespace V3 +{ + public sealed class Quadtree + { + private Node mRoot; // The first "Node" of the Quadtree + private ContentManager mContentManager; + private readonly Point mMaxSize; + + /// + /// Generates Quadtree + /// + /// Gives the biggest/first Rectangle of the Quadtree. This should be the sice of the howl map. + public Quadtree(Point maxSize) + { + mRoot = new Node(new Rectangle(new Point(-128, -128), maxSize), null); + mMaxSize = maxSize; + } + + /// + /// Updates the Quadtree. This is importent for the movements of the Objects. + /// + public void Update() + { + mRoot.Update1(); + } + + /// + /// You call this method if you want to Inster an Object to the Quadtree. + /// + /// Type of Creature including their position. + public void Insert(IGameObject item) + { + mRoot.AddtoSubNode(item); + } + + /// + /// DMakes the Rectangles of the Quadtree visible. + /// + /// + public void Draw(SpriteBatch spriteBatch) + { + mRoot.DrawQuadtree(spriteBatch, Texture); + } + + public List GetObjectsInRectangle(Rectangle rectangle) + { + List objectList = new List(); + return mRoot.GetObjectsInRectangle(rectangle, objectList); + } + + /// + /// Deletes an Object out of the Quadtree. + /// + /// Type of Creature including their position. + public void RemoveItem(IGameObject item) + { + mRoot.Delete(item); + } + + /// + /// Loads the content to draw the Rectangels of the Quadtree. + /// + /// + public void LoadContent(ContentManager contentManager) + { + mContentManager = contentManager; + Texture = mContentManager.Load("Sprites/WhiteRectangle"); + } + + /// + /// Deletes all elements from the quadtree. + /// + public void Clear() + { + mRoot?.Clear(); + mRoot = new Node(new Rectangle(new Point(-50, -50), mMaxSize), null); + } + + private Texture2D Texture { get; set; } + } +} diff --git a/V3/Screens/AbstractScreen.cs b/V3/Screens/AbstractScreen.cs new file mode 100644 index 0000000..becd38d --- /dev/null +++ b/V3/Screens/AbstractScreen.cs @@ -0,0 +1,57 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using V3.Input; + +namespace V3.Screens +{ + public abstract class AbstractScreen : IScreen + { + /// + /// Indicates whether screens below this one should be updated. + /// + public bool UpdateLower { get; } + + /// + /// Indicates whether screens below this one should be drawn. + /// + public bool DrawLower { get; } + + protected AbstractScreen(bool updateLower, bool drawLower) + { + UpdateLower = updateLower; + DrawLower = drawLower; + } + + /// + /// Handles the given key event and returns whether it should be passed + /// to the screens below this one. + /// + /// the key event that occurred + /// true if the event has been handeled by this screen and + /// should not be passed to the lower screens, false otherwise + public virtual bool HandleKeyEvent(IKeyEvent keyEvent) + { + return false; + } + + /// + /// Handles the given mouse event and returns whether it should be passed + /// to the screens below this one. + /// + /// the mouse event that occurred + /// true if the event has been handeled by this screen and + /// should not be passed to the lower screens, false otherwise + public virtual bool HandleMouseEvent(IMouseEvent mouseEvent) + { + return true; + } + + public virtual void Update(GameTime gameTime) + { + } + + public virtual void Draw(GameTime gameTime, SpriteBatch spriteBatch) + { + } + } +} diff --git a/V3/Screens/AchievementsScreen.cs b/V3/Screens/AchievementsScreen.cs new file mode 100644 index 0000000..096fb81 --- /dev/null +++ b/V3/Screens/AchievementsScreen.cs @@ -0,0 +1,221 @@ +using System.Collections.Generic; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework.Input; +using Ninject; +using V3.Input; +using V3.Objects; +using V3.Widgets; + +namespace V3.Screens +{ + /// + /// The screen for the AchievementsAndStatistics. + /// + // ReSharper disable once ClassNeverInstantiated.Global + public sealed class AchievementsScreen : AbstractScreen, IInitializable + { + //private AchievementBox mFirstSteps; + private AchievementBox mKillPrince; + private AchievementBox mKillKing; + //private AchievementBox mWarmasterAndWizard; + private AchievementBox mKaboom; + private AchievementBox mMarathonRunner; + private AchievementBox mIronMan; + private AchievementBox mMeatballCompany; + private AchievementBox mSkeletonHorseCavalry; + private AchievementBox mRightHandOfDeath; + private AchievementBox mMinimalist; + private AchievementBox mHundredDeadCorpses; + private AchievementBox mUndeadArmy; + private AchievementBox mHellsNotWaiting; + + + private readonly ContentManager mContentManager; + private readonly IMenuFactory mMenuFactory; + private readonly MenuActions mMenuActions; + private readonly WidgetFactory mWidgetFactory; + private readonly AchievementsAndStatistics mAchievementsAndStatistics; + private readonly ObjectsManager mObjectsManager; + + private Button mButtonBack; + private SelectButton mSelectPage; + + private List mMenuList = new List(); + private Texture2D mRectangle; + + public AchievementsScreen(ContentManager contentManager, MenuActions menuActions, WidgetFactory widgetFactory, + IMenuFactory menuFactory, AchievementsAndStatistics achievementsAndStatistics, ObjectsManager objectsManager) + : base(false, true) + { + mContentManager = contentManager; + mMenuFactory = menuFactory; + mMenuActions = menuActions; + mWidgetFactory = widgetFactory; + mAchievementsAndStatistics = achievementsAndStatistics; + mObjectsManager = objectsManager; + } + + public void Initialize() + { + mRectangle = mContentManager.Load("Sprites/WhiteRectangle"); + + mButtonBack = mWidgetFactory.CreateButton("Zurück"); + mSelectPage = mWidgetFactory.CreateSelectButton(); + + var menu = mMenuFactory.CreateVerticalMenu(); + mMenuList.Add(menu); + + menu.Widgets.Add(mSelectPage); + + mKillPrince = mWidgetFactory.CreateAchievementBox(); + mKillPrince.SetText("Erbfolge aufgehalten", "Vernichtet Prinz Erhard."); + menu.Widgets.Add(mKillPrince); + + mKaboom = mWidgetFactory.CreateAchievementBox(); + mKaboom.SetText("KABUMM!!!", "Tötet mindestens 10 Gegner mit einer einzigen Fleischklops-Explosion."); + menu.Widgets.Add(mKaboom); + + mKillKing = mWidgetFactory.CreateAchievementBox(); + mKillKing.SetText("Königsmord", "Nehmt eure Vergeltung am König und tötet ihn."); + menu.Widgets.Add(mKillKing); + + menu.Widgets.Add(mButtonBack); + + menu = mMenuFactory.CreateVerticalMenu(); + mMenuList.Add(menu); + + menu.Widgets.Add(mSelectPage); + + mHundredDeadCorpses = mWidgetFactory.CreateAchievementBox(); + mHundredDeadCorpses.SetText("Leichenfledderer", "Tötet in einer Mission mindestens 100 Gegner."); + menu.Widgets.Add(mHundredDeadCorpses); + + mUndeadArmy = mWidgetFactory.CreateAchievementBox(); + mUndeadArmy.SetText("Untote Armee", "Tötet in einer Mission mindestens 1000 Gegner."); + menu.Widgets.Add(mUndeadArmy); + + mRightHandOfDeath = mWidgetFactory.CreateAchievementBox(); + mRightHandOfDeath.SetText("Die erbarmungslose rechte Hand des Todes", "Tötet insgesamt 10 000 Gegner."); + menu.Widgets.Add(mRightHandOfDeath); + + menu.Widgets.Add(mButtonBack); + + menu = mMenuFactory.CreateVerticalMenu(); + mMenuList.Add(menu); + + menu.Widgets.Add(mSelectPage); + + mMeatballCompany = mWidgetFactory.CreateAchievementBox(); + mMeatballCompany.SetText("Fleischpanzer-Kompanie", "Erschafft und befehligt in einer Mission 10 Fleischklopse gleichzeitig."); + menu.Widgets.Add(mMeatballCompany); + + mSkeletonHorseCavalry = mWidgetFactory.CreateAchievementBox(); + mSkeletonHorseCavalry.SetText("Klappernde Kavallerie", "Erschafft und befehligt in einer Mission 25 Skelettpferde gleichzeitig."); + menu.Widgets.Add(mSkeletonHorseCavalry); + + mMinimalist = mWidgetFactory.CreateAchievementBox(); + mMinimalist.SetText("Minimalist", "Beendet eine Mission und setzt dabei weniger als 100 Einheiten ein."); + menu.Widgets.Add(mMinimalist); + + menu.Widgets.Add(mButtonBack); + + menu = mMenuFactory.CreateVerticalMenu(); + mMenuList.Add(menu); + + menu.Widgets.Add(mSelectPage); + + mHellsNotWaiting = mWidgetFactory.CreateAchievementBox(); + mHellsNotWaiting.SetText("Die Hölle wartet nicht", "Beendet eine Mission in weniger als 5 Minuten."); + menu.Widgets.Add(mHellsNotWaiting); + + mMarathonRunner = mWidgetFactory.CreateAchievementBox(); + mMarathonRunner.SetText("Marathonläufer", "Legt in einer Mission mindestens 1000m zurück."); + menu.Widgets.Add(mMarathonRunner); + + mIronMan = mWidgetFactory.CreateAchievementBox(); + mIronMan.SetText("Der Iron Man", "Legt insgesamt eine Strecke von 10 000m zurück."); + menu.Widgets.Add(mIronMan); + + menu.Widgets.Add(mButtonBack); + + for (var i = 0; i < mMenuList.Count; i++) + mSelectPage.Values.Add($"Seite {i + 1}"); + } + + public override bool HandleKeyEvent(IKeyEvent keyEvent) + { + if (keyEvent.KeyState == KeyState.Down && keyEvent.Key == Keys.Escape) + mMenuActions.Close(this); + + return true; + } + + public override bool HandleMouseEvent(IMouseEvent mouseEvent) + { + GetCurrentMenu().HandleMouseEvent(mouseEvent); + return true; + } + + public override void Update(GameTime gameTime) + { + if (mButtonBack.IsClicked) + { + mMenuActions.Close(this); + } + GetCurrentMenu().Update(); + + // achievement datas. if one value becomes a given value, the corresponding achievement will be enabled. + + if (mAchievementsAndStatistics.mKillPrince) + mKillPrince.IsEnabled = true; + if (mAchievementsAndStatistics.mKillKing) + mKillKing.IsEnabled = true; + if (mAchievementsAndStatistics.mHellsNotWaiting) + mHellsNotWaiting.IsEnabled = true; + if (mAchievementsAndStatistics.mKaboom) + mKaboom.IsEnabled = true; + + if (mAchievementsAndStatistics.mMarathonRunner >= 1000) + mMarathonRunner.IsEnabled = true; + if (mAchievementsAndStatistics.mIronMan >= 10000) + mIronMan.IsEnabled = true; + if (mAchievementsAndStatistics.mMeatballCompany >= 10) + mMeatballCompany.IsEnabled = true; + if (mAchievementsAndStatistics.mSkeletonHorseCavalry >= 25) + mSkeletonHorseCavalry.IsEnabled = true; + if (mAchievementsAndStatistics.mRightHandOfDeath >= 10000) + mRightHandOfDeath.IsEnabled = true; + if (mAchievementsAndStatistics.mMinimalist <= 100 && mObjectsManager.Boss != null && mObjectsManager.Boss.IsDead) + mMinimalist.IsEnabled = true; + if (mAchievementsAndStatistics.mHundredDeadCorpses >= 100) + mHundredDeadCorpses.IsEnabled = true; + if (mAchievementsAndStatistics.mUndeadArmy >= 1000) + mUndeadArmy.IsEnabled = true; + } + + public override void Draw(GameTime gameTime, SpriteBatch spriteBatch) + { + var menu = GetCurrentMenu(); + var backgroundRectangle = new Rectangle((int)menu.Position.X, + (int)menu.Position.Y, (int)menu.Size.X, + (int)menu.Size.Y); + backgroundRectangle.X -= 30; + backgroundRectangle.Y -= 30; + backgroundRectangle.Width += 60; + backgroundRectangle.Height += 60; + + spriteBatch.Begin(); + spriteBatch.Draw(mRectangle, backgroundRectangle, Color.WhiteSmoke); + spriteBatch.End(); + + menu.Draw(spriteBatch); + } + + private IMenu GetCurrentMenu() + { + return mMenuList[mSelectPage.SelectedIndex]; + } + } +} diff --git a/V3/Screens/DeathScreen.cs b/V3/Screens/DeathScreen.cs new file mode 100644 index 0000000..230d40a --- /dev/null +++ b/V3/Screens/DeathScreen.cs @@ -0,0 +1,140 @@ +using System; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework.Input; +using Ninject; +using V3.Input; +using V3.Widgets; + +namespace V3.Screens +{ + // ReSharper disable once ClassNeverInstantiated.Global + public sealed class DeathScreen : AbstractScreen, IInitializable + { + private static TimeSpan sTotalDelay = TimeSpan.FromSeconds(2); + + private readonly ContentManager mContentManager; + private readonly GraphicsDeviceManager mGraphicsDeviceManager; + private readonly MenuActions mMenuActions; + private readonly WidgetFactory mWidgetFactory; + + private Button mMenuButton; + private Button mCloseGameButton; + private Vector2 mButtonPosition; + private Vector2 mCenter; + private Vector2 mFontCenter; + private SpriteFont mDeathFont; + private Texture2D mRectangle; + + private TimeSpan mDelayTimer = sTotalDelay; + + /// + /// Creates a death screen if the players health reaches 0. + /// + + public DeathScreen(ContentManager contentManager, + GraphicsDeviceManager graphicsDeviceManager, + MenuActions menuActions, + WidgetFactory widgetFactory) + : base(false, true) + { + mContentManager = contentManager; + mGraphicsDeviceManager = graphicsDeviceManager; + mMenuActions = menuActions; + mWidgetFactory = widgetFactory; + } + + public override bool HandleKeyEvent(IKeyEvent keyEvent) + { + return false; + } + + public override bool HandleMouseEvent(IMouseEvent mouseEvent) + { + if (mDelayTimer <= TimeSpan.Zero) + { + mMenuButton.HandleMouseEvent(mouseEvent); + mCloseGameButton.HandleMouseEvent(mouseEvent); + } + return false; + } + + public void Initialize() + { + mRectangle = mContentManager.Load("Sprites/WhiteRectangle"); + mDeathFont = mContentManager.Load("Fonts/DeathFont"); + + mMenuButton = mWidgetFactory.CreateButton("Zum Hauptmenü"); + mMenuButton.Position = Vector2.Zero; + mMenuButton.PaddingX = 10; + mMenuButton.PaddingY = 0; + mMenuButton.Size = mMenuButton.GetMinimumSize(); + mMenuButton.BackgroundColor = Color.Gray * 0.7f; + + mCloseGameButton = mWidgetFactory.CreateButton("Spiel schließen"); + mCloseGameButton.Position = Vector2.Zero; + mCloseGameButton.PaddingX = 10; + mCloseGameButton.PaddingY = 0; + mCloseGameButton.Size = mCloseGameButton.GetMinimumSize(); + mCloseGameButton.BackgroundColor = Color.Gray * 0.7f; + } + + public override void Update(GameTime gameTime) + { + var viewport = mGraphicsDeviceManager.GraphicsDevice.Viewport; + + mCenter = new Vector2(viewport.Width / 2f, viewport.Height / 2f); + mFontCenter = mDeathFont.MeasureString("Ihr seid tot") / 2; + mButtonPosition = new Vector2(mCenter.X - mFontCenter.X * 2/3, mCenter.Y + mFontCenter.Y * 2); + + if (mDelayTimer > TimeSpan.Zero) + mDelayTimer -= gameTime.ElapsedGameTime; + + mMenuButton.Position = mButtonPosition; + mCloseGameButton.Position = mMenuButton.Position + new Vector2(mFontCenter.X * 3/ 4, 0); + + if (mMenuButton.IsClicked) + { + mMenuActions.OpenMainScreen(); + } + else if (mCloseGameButton.IsClicked) + { + mMenuActions.Exit(); + } + + mMenuButton.IsSelected = mMenuButton.CheckSelected(Mouse.GetState().Position); + mMenuButton.IsClicked = false; + + mCloseGameButton.IsSelected = mCloseGameButton.CheckSelected(Mouse.GetState().Position); + mCloseGameButton.IsClicked = false; + } + + public override void Draw(GameTime gameTime, SpriteBatch spriteBatch) + { + float displayRatio = (float) (1 - mDelayTimer.TotalMilliseconds / sTotalDelay.TotalMilliseconds); + + spriteBatch.Begin(); + spriteBatch.Draw(mRectangle, + mGraphicsDeviceManager.GraphicsDevice.Viewport.Bounds, + Color.Black * 0.5f * displayRatio); + + spriteBatch.DrawString(mDeathFont, + "Ihr seid tot", + mCenter, + Color.Firebrick * displayRatio, + 0, + mFontCenter, + 1.0f, + SpriteEffects.None, + 0.5f); + + if (mDelayTimer <= TimeSpan.Zero) + { + mMenuButton.Draw(spriteBatch); + mCloseGameButton.Draw(spriteBatch); + } + spriteBatch.End(); + } + } +} diff --git a/V3/Screens/DebugScreen.cs b/V3/Screens/DebugScreen.cs new file mode 100644 index 0000000..a1e0820 --- /dev/null +++ b/V3/Screens/DebugScreen.cs @@ -0,0 +1,92 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Graphics; +using Ninject; +using V3.Data; +using V3.Input; +using V3.Objects; +using V3.Widgets; + +namespace V3.Screens +{ + /// + /// A special screen that counts and show the number of frames per + /// second (if debug is enabled). This screen is not added to the + /// screen stack, but is always drawn and updated by the screen manager. + /// + // ReSharper disable once ClassNeverInstantiated.Global + public sealed class DebugScreen : AbstractScreen, IInitializable + { + private readonly GraphicsDeviceManager mGraphicsDeviceManager; + private readonly IObjectsManager mObjectsManager; + private readonly IOptionsManager mOptionsManager; + private readonly WidgetFactory mWidgetFactory; + private FpsCounter mFpsCounter; + private Label mFpsLabel; + private Label mUnitCountLabel; + private int mUnitCount; + + /// + /// Creates a new debug screen. + /// + public DebugScreen(GraphicsDeviceManager graphicsDeviceManager, + IObjectsManager objectsManager, IOptionsManager optionsManager, + WidgetFactory widgetFactory) : base(true, true) + { + mGraphicsDeviceManager = graphicsDeviceManager; + mObjectsManager = objectsManager; + mOptionsManager = optionsManager; + mWidgetFactory = widgetFactory; + } + + public void Initialize() + { + mFpsCounter = new FpsCounter(); + + mFpsLabel = mWidgetFactory.CreateLabel(""); + mFpsLabel.PaddingX = 10; + mFpsLabel.PaddingY = 0; + mFpsLabel.HorizontalOrientation = HorizontalOrientation.Left; + mFpsLabel.Color = Color.Red; + + mUnitCountLabel = mWidgetFactory.CreateLabel(""); + mUnitCountLabel.PaddingX = 10; + mUnitCountLabel.PaddingY = 0; + mUnitCountLabel.HorizontalOrientation = HorizontalOrientation.Left; + mUnitCountLabel.Color = Color.Red; + } + + public override bool HandleMouseEvent(IMouseEvent mouseEvent) + { + return false; + } + + public override void Update(GameTime gameTime) + { + mFpsCounter.Update(gameTime); + mUnitCount = mObjectsManager.CreatureList?.Count ?? 0; + } + + public override void Draw(GameTime gameTime, SpriteBatch spriteBatch) + { + mFpsCounter.AddFrame(); + + if (mOptionsManager.Options.DebugMode == DebugMode.Off) + return; + + var viewport = mGraphicsDeviceManager.GraphicsDevice.Viewport; + + mFpsLabel.Text = $"FPS: {mFpsCounter.Fps} " + (gameTime.IsRunningSlowly ? "!" : ""); + mFpsLabel.Size = mFpsLabel.GetMinimumSize(); + mFpsLabel.Position = new Vector2(0, viewport.Height - mFpsLabel.Size.Y); + + mUnitCountLabel.Text = $"# units: {mUnitCount}"; + mUnitCountLabel.Size = mUnitCountLabel.GetMinimumSize(); + mUnitCountLabel.Position = mFpsLabel.Position - new Vector2(0, mFpsLabel.Size.Y); + + spriteBatch.Begin(); + mFpsLabel.Draw(spriteBatch); + mUnitCountLabel.Draw(spriteBatch); + spriteBatch.End(); + } + } +} diff --git a/V3/Screens/FpsCounter.cs b/V3/Screens/FpsCounter.cs new file mode 100644 index 0000000..5c3ac0c --- /dev/null +++ b/V3/Screens/FpsCounter.cs @@ -0,0 +1,46 @@ +using System; +using Microsoft.Xna.Framework; + +namespace V3.Screens +{ + /// + /// Counts the frames per second based on the elapsed time and the number + /// of frames that have been drawn. Call Update in each Update, and + /// AddFrame in each Draw. + /// + public sealed class FpsCounter + { + /// + /// The current frames per second. + /// + public int Fps { get; private set; } + + private int mFrameCount; + private TimeSpan mTimeSpan = TimeSpan.Zero; + + /// + /// Updates the elapsed time and -- once every second -- the fps value. + /// + /// the elapsed game time + public void Update(GameTime gameTime) + { + mTimeSpan += gameTime.ElapsedGameTime; + + if (mTimeSpan > TimeSpan.FromSeconds(1)) + { + mTimeSpan -= TimeSpan.FromSeconds(1); + Fps = mFrameCount; + mFrameCount = 0; + } + } + + /// + /// Registers that a frame has been drawn. Should be called once for + /// every Draw. + /// + public void AddFrame() + { + mFrameCount++; + } + } +} diff --git a/V3/Screens/GameScreen.cs b/V3/Screens/GameScreen.cs new file mode 100644 index 0000000..e37b100 --- /dev/null +++ b/V3/Screens/GameScreen.cs @@ -0,0 +1,306 @@ +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework.Input; +using Ninject; +using System.Collections.Generic; +using V3.AI; +using V3.Camera; +using V3.Data; +using V3.Effects; +using V3.Input; +using V3.Map; +using V3.Objects; + +namespace V3.Screens +{ + /// + /// The main game screen. + /// + // ReSharper disable once ClassNeverInstantiated.Global + public sealed class GameScreen : AbstractScreen, IInitializable + { + private readonly CameraManager mCameraManager; + private readonly ContentManager mContentManager; + private readonly CreatureFactory mCreatureFactory; + private readonly GraphicsDeviceManager mGraphicsDeviceManager; + private readonly MenuActions mMenuActions; + private readonly IOptionsManager mOptionsManager; + private readonly Selection mSelection; + private readonly Transformation mTransformation; + private readonly IAiPlayer mAiPlayer; + private readonly IMapManager mMapManager; + private readonly IEffectsManager mEffectsManager; + private readonly IObjectsManager mObjectsManager; + private readonly Pathfinder mPathfinder; + private readonly Texture2D mOnePixelTexture; + private readonly FogOfWar mFog; + private bool mFogOfWarActivaded = true; + private AchievementsAndStatistics mAchievementsAndStatistics; + private int mFogCounter; + // Fields for handling mouse input. + private Point mInitialClickPosition; + private bool mLeftButtonPressed; + private bool mRightButtonPressed; + private Vector2 mRightButtonPosition; + + /// + /// Creates a new game screen. + /// + public GameScreen(IOptionsManager optionsManager, CameraManager cameraManager, + ContentManager contentManager, CreatureFactory creatureFactory, + GraphicsDeviceManager graphicsDeviceManager, IMapManager mapManager, + MenuActions menuActions, IAiPlayer aiPlayer, IObjectsManager objectsManager, + Pathfinder pathfinder, Selection selection, FogOfWar fog, Transformation transformation, + IEffectsManager effectsManager, AchievementsAndStatistics achievementsAndStatistics) : base(false, false) + { + mMapManager = mapManager; + mObjectsManager = objectsManager; + mCameraManager = cameraManager; + mOptionsManager = optionsManager; + mContentManager = contentManager; + mCreatureFactory = creatureFactory; + mEffectsManager = effectsManager; + mTransformation = transformation; + mGraphicsDeviceManager = graphicsDeviceManager; + mMenuActions = menuActions; + mAiPlayer = aiPlayer; + mPathfinder = pathfinder; + mSelection = selection; + mFog = fog; + mOnePixelTexture = contentManager.Load("Sprites/WhiteRectangle"); + mAchievementsAndStatistics = achievementsAndStatistics; + } + + + public override bool HandleMouseEvent(IMouseEvent mouseEvent) + { + if (mouseEvent.MouseButton == MouseButton.Left && mouseEvent.ButtonState == ButtonState.Pressed) + { + if (!mLeftButtonPressed) + { + mLeftButtonPressed = true; + mInitialClickPosition = mouseEvent.PositionPressed; + } + } + else + { + if (mLeftButtonPressed) + { + mSelection.Select(mInitialClickPosition + mCameraManager.GetCamera().Location.ToPoint(), + mouseEvent.PositionReleased.GetValueOrDefault() + mCameraManager.GetCamera().Location.ToPoint()); + mLeftButtonPressed = false; + } + } + if (mouseEvent.MouseButton == MouseButton.Right && mouseEvent.ButtonState == ButtonState.Pressed) + { + if (!mRightButtonPressed) + { + mRightButtonPressed = true; + mInitialClickPosition = mouseEvent.PositionPressed; + } + } + if (mouseEvent.MouseButton == MouseButton.Right && mouseEvent.ButtonState == ButtonState.Released) + { + if (mouseEvent.PositionReleased != null && mouseEvent.ReleasedOnScreen) + { + mRightButtonPressed = false; + mRightButtonPosition = mouseEvent.PositionReleased.Value.ToVector2() + mCameraManager.GetCamera().Location; + mSelection.Move(mouseEvent.PositionReleased.Value.ToVector2() + + mCameraManager.GetCamera().Location); + } + } + return true; + } + + public void Initialize() + { +#if NEWMAP + mMapManager.Load("work_in_progress"); +#else + mMapManager.Load("map_grassland"); +#endif + mObjectsManager.Initialize(mMapManager); + mCameraManager.Initialize(mMapManager.SizeInPixel); + mPathfinder.LoadGrid(mMapManager.GetPathfindingGrid()); + mFog.LoadContent(mContentManager); + mFog.LoadGrid(mMapManager.SizeInPixel); + mTransformation.mSelection = mSelection; + mTransformation.LoadArea(mContentManager); + mTransformation.ObjectsManager = mObjectsManager; + } + + /// + /// Create the initial population as designated by the map manager, + /// the player character, and possibly other creatures. + /// + public void CreateInitialPopulation() + { + // Create initial population. + foreach (var creature in mMapManager.GetPopulation(mCreatureFactory, mPathfinder)) + { + mObjectsManager.CreateCreature(creature); + } + +#if NEWMAP + var necromancer = mCreatureFactory.CreateNecromancer(new Vector2(385, 420), MovementDirection.S); + mObjectsManager.CreatePlayerCharacter(necromancer); + // Create Prince and his guard. + mObjectsManager.CreatePrince(mCreatureFactory.CreatePrince(new Vector2(6139, 3039), MovementDirection.SO)); + mObjectsManager.CreateCreature(mCreatureFactory.CreateKingsGuard(new Vector2(5794, 2900), MovementDirection.N)); + mObjectsManager.CreateCreature(mCreatureFactory.CreateKingsGuard(new Vector2(5858, 2900), MovementDirection.N)); + mObjectsManager.CreateCreature(mCreatureFactory.CreateKingsGuard(new Vector2(5936, 2885), MovementDirection.NW)); + mObjectsManager.CreateCreature(mCreatureFactory.CreateKingsGuard(new Vector2(6000, 2885), MovementDirection.NW)); + mObjectsManager.CreateCreature(mCreatureFactory.CreateKingsGuard(new Vector2(6064, 2885), MovementDirection.NW)); +#else + // Add creatures for testing purposes. + var necromancer = mCreatureFactory.CreateNecromancer(new Vector2(300, 150), MovementDirection.S); + var zombie1 = mCreatureFactory.CreateZombie(new Vector2(800, 200), MovementDirection.S); + var zombie2 = mCreatureFactory.CreateZombie(new Vector2(850, 250), MovementDirection.S); + var zombie3 = mCreatureFactory.CreateZombie(new Vector2(900, 200), MovementDirection.S); + var zombie4 = mCreatureFactory.CreateZombie(new Vector2(950, 250), MovementDirection.S); + var zombie5 = mCreatureFactory.CreateZombie(new Vector2(1000, 200), MovementDirection.S); + var zombieToGo = mCreatureFactory.CreateZombie(new Vector2(400, 400), MovementDirection.S); + var knight = mCreatureFactory.CreateKnight(new Vector2(1500, 210), MovementDirection.W); + var horse = mCreatureFactory.CreateSkeletonHorse(new Vector2(1300, 500), MovementDirection.SW); + var prince = mCreatureFactory.CreatePrince(new Vector2(1800, 1000), MovementDirection.S); + var meatball = mCreatureFactory.CreateMeatball(new Vector2(350, 150), MovementDirection.S); + // Add creatures to obects manager. + mObjectsManager.CreatePlayerCharacter(necromancer); + mObjectsManager.CreatePrince(prince); + mObjectsManager.CreateCreature(zombie1); + mObjectsManager.CreateCreature(zombie2); + mObjectsManager.CreateCreature(zombie3); + mObjectsManager.CreateCreature(zombie4); + mObjectsManager.CreateCreature(zombie5); + mObjectsManager.CreateCreature(zombieToGo); + mObjectsManager.CreateCreature(knight); + mObjectsManager.CreateCreature(horse); + mObjectsManager.CreateCreature(meatball); +#endif + } + + public override bool HandleKeyEvent(IKeyEvent keyEvent) + { + if (keyEvent.KeyState == KeyState.Down && keyEvent.Key == Keys.Escape) + mMenuActions.OpenPauseScreen(); + if (keyEvent.KeyState == KeyState.Down && keyEvent.Key == Keys.F5) + { + Rectangle cameraRectangle = mCameraManager.GetCamera().ScreenRectangle; + mEffectsManager.PlayOnce(new SmokeBig(), cameraRectangle.Center, cameraRectangle.Size); + mObjectsManager.ExposeTheLiving(); + } + if (keyEvent.KeyState == KeyState.Down && keyEvent.Key == Keys.F6) + { + (mObjectsManager.PlayerCharacter as Necromancer)?.ChangeSex(); + mEffectsManager.PlayOnce(new SmokeSmall(), mObjectsManager.PlayerCharacter.Position.ToPoint(), new Point(256)); + } + if (keyEvent.KeyState == KeyState.Down && keyEvent.Key == Keys.F8) + { + mFogOfWarActivaded = !mFogOfWarActivaded; + } + + return true; + } + + /// + /// Updates the status of this object. + /// + /// a snapshot of the game time + public override void Update(GameTime gameTime) + { +#if DEBUG +#else + try + { +#endif + if (mObjectsManager.Boss != null && mObjectsManager.Boss.IsDead) + mAchievementsAndStatistics.mKillKing = true; + if (mObjectsManager.Prince != null && mObjectsManager.Prince.IsDead) + mAchievementsAndStatistics.mKillPrince = true; + mObjectsManager.Update(gameTime, mRightButtonPressed, mRightButtonPosition, mCameraManager.GetCamera()); + mCameraManager.Update(mObjectsManager.PlayerCharacter); + mEffectsManager.Update(gameTime); + mAiPlayer.Update(gameTime); + + // Call for Transformations + mTransformation.Transform(); + + // Check whether creature is in Necromancers Radius + mSelection.UpdateSelection(); + + // Update for FogOfWar. + for (int i = mFogCounter; i < mObjectsManager.UndeadCreatures.Count; i += 30) + { + mFog.Update(mObjectsManager.UndeadCreatures[i]); + } + if (mFogCounter < 30) + mFogCounter++; + else + mFogCounter = 0; + +#if DEBUG +#else + } + catch (System.Exception e) + { + System.Console.WriteLine(e.Message); + } +#endif + } + + /// + /// Draws this object using the given sprite batch. + /// + /// a snapshot of the game time + /// the sprite batch to use for drawing + /// this object + public override void Draw(GameTime gameTime, SpriteBatch spriteBatch) + { + mGraphicsDeviceManager.GraphicsDevice.Clear(Color.Black); + spriteBatch.Begin(SpriteSortMode.Deferred, BlendState.AlphaBlend, + null, null, null, null, mCameraManager.GetCamera().Transform); + mMapManager.DrawFloor(spriteBatch, mCameraManager.GetCamera()); + mObjectsManager.Draw(spriteBatch, mCameraManager.GetCamera()); + mTransformation.DrawNecroArea(spriteBatch); + mEffectsManager.Draw(spriteBatch); + // Draws the selection rectangle when left mouse button is pressed. + if (mLeftButtonPressed) + mSelection.Draw(spriteBatch, mInitialClickPosition + mCameraManager.GetCamera().Location.ToPoint(), + Mouse.GetState().Position + mCameraManager.GetCamera().Location.ToPoint()); + if (mFogOfWarActivaded) mFog.DrawFog(spriteBatch); + if (mOptionsManager.Options.DebugMode == DebugMode.Full) + { + mMapManager.DrawPathfindingGrid(spriteBatch, mCameraManager.GetCamera()); + mObjectsManager.DrawQuadtree(spriteBatch); + DrawLastSelection(spriteBatch, mSelection.LastSelection); + } + spriteBatch.End(); + } + + private void DrawLastSelection(SpriteBatch spriteBatch, Rectangle selection) + { + spriteBatch.Draw(mOnePixelTexture, selection, new Color(Color.Black, 100)); + } + + public void SetFog(List fog) + { + mFog.SetFog(fog); + } + + public List GetFog() + { + return mFog.GetFog(); + } + + public void SetAiState(AiState state) + { + mAiPlayer.State = state; + } + + public AiState GetAiState() + { + return mAiPlayer.State; + } + } +} diff --git a/V3/Screens/HudScreen.cs b/V3/Screens/HudScreen.cs new file mode 100644 index 0000000..123ba8a --- /dev/null +++ b/V3/Screens/HudScreen.cs @@ -0,0 +1,349 @@ +using System; +using Microsoft.Xna.Framework; +using Microsoft.Xna.Framework.Content; +using Microsoft.Xna.Framework.Graphics; +using Microsoft.Xna.Framework.Input; +using Ninject; +using System.Collections.Generic; +using V3.Data; +using V3.Camera; +using V3.Input; +using V3.Map; +using V3.Objects; +using V3.Widgets; + +namespace V3.Screens +{ + /// + /// Creates a new HUD screen. + /// + // ReSharper disable once ClassNeverInstantiated.Global + public sealed class HudScreen : AbstractScreen, IInitializable + { + private readonly MenuActions mMenuActions; + private readonly GraphicsDeviceManager mGraphicsDeviceManager; + private readonly ContentManager mContentManager; + private readonly WidgetFactory mWidgetFactory; + private readonly IOptionsManager mOptionsManager; + private readonly CameraManager mCameraManager; + private readonly IMapManager mMapManager; + private readonly IObjectsManager mObjectsManager; + private AchievementsAndStatistics mAchievementsAndStatistics; + + private KeyboardState mCurrentState; + private KeyboardState mPreviousState; + private SpriteFont mFont; + + private List