aboutsummaryrefslogtreecommitdiff
path: root/V3
diff options
context:
space:
mode:
authorThomas Leyh <leyh.thomas@web.de>2016-07-24 08:14:18 +0200
committerThomas Leyh <leyh.thomas@web.de>2016-07-24 08:14:18 +0200
commitced3d03bdb3ce866d832e03fb212865140905a9a (patch)
tree2a16c2063a46d3c354ce1585029dda3124f6ad93 /V3
parent0394dccaf06e1009e591a6ff4d645895574724c1 (diff)
downloadV3-ced3d03bdb3ce866d832e03fb212865140905a9a.tar.gz
V3-ced3d03bdb3ce866d832e03fb212865140905a9a.tar.bz2
Add project files.v1.0release
Diffstat (limited to 'V3')
-rw-r--r--V3/AI/ActionState.cs25
-rw-r--r--V3/AI/AiState.cs27
-rw-r--r--V3/AI/IAction.cs24
-rw-r--r--V3/AI/IAiPlayer.cs51
-rw-r--r--V3/AI/IStrategy.cs17
-rw-r--r--V3/AI/IWorldView.cs21
-rw-r--r--V3/AI/Internal/AbstractAction.cs38
-rw-r--r--V3/AI/Internal/AiPlayer.cs244
-rw-r--r--V3/AI/Internal/AttackStrategy.cs48
-rw-r--r--V3/AI/Internal/IActionFactory.cs27
-rw-r--r--V3/AI/Internal/MoveAction.cs53
-rw-r--r--V3/AI/Internal/SpawnAction.cs42
-rw-r--r--V3/AI/Internal/WorldView.cs19
-rw-r--r--V3/AchievementsAndStatistics.cs31
-rw-r--r--V3/Bindings.cs75
-rw-r--r--V3/CONTROLS.md37
-rw-r--r--V3/CREDITS.md51
-rw-r--r--V3/Camera/CameraCentered.cs57
-rw-r--r--V3/Camera/CameraManager.cs71
-rw-r--r--V3/Camera/CameraScrolling.cs96
-rw-r--r--V3/Camera/CameraType.cs8
-rw-r--r--V3/Camera/ICamera.cs18
-rw-r--r--V3/ClassDiagram1.cd2
-rw-r--r--V3/Content/Buttons/Button-01.pngbin0 -> 99135 bytes
-rw-r--r--V3/Content/Buttons/Button-01_Pressed.pngbin0 -> 112006 bytes
-rw-r--r--V3/Content/Buttons/Button-02.pngbin0 -> 55248 bytes
-rw-r--r--V3/Content/Buttons/Button-02_Pressed.pngbin0 -> 66371 bytes
-rw-r--r--V3/Content/Buttons/Button-03.pngbin0 -> 64359 bytes
-rw-r--r--V3/Content/Buttons/Button-03_Pressed.pngbin0 -> 75343 bytes
-rw-r--r--V3/Content/Buttons/Button-04.pngbin0 -> 56617 bytes
-rw-r--r--V3/Content/Buttons/Button-04_Pressed.pngbin0 -> 67959 bytes
-rw-r--r--V3/Content/Buttons/Button-05.pngbin0 -> 70658 bytes
-rw-r--r--V3/Content/Buttons/Button-05_Pressed.pngbin0 -> 82438 bytes
-rw-r--r--V3/Content/Buttons/Button-06.pngbin0 -> 54510 bytes
-rw-r--r--V3/Content/Buttons/Button-06_Pressed.pngbin0 -> 66074 bytes
-rw-r--r--V3/Content/Buttons/Button-07.pngbin0 -> 72189 bytes
-rw-r--r--V3/Content/Buttons/Button-07_Pressed.pngbin0 -> 84575 bytes
-rw-r--r--V3/Content/Content.mgcb1092
-rw-r--r--V3/Content/Effects/blood_hit_01.pngbin0 -> 109054 bytes
-rw-r--r--V3/Content/Effects/blood_hit_02.pngbin0 -> 38081 bytes
-rw-r--r--V3/Content/Effects/blood_hit_03.pngbin0 -> 41343 bytes
-rw-r--r--V3/Content/Effects/blood_hit_04.pngbin0 -> 91450 bytes
-rw-r--r--V3/Content/Effects/blood_hit_05.pngbin0 -> 71750 bytes
-rw-r--r--V3/Content/Effects/blood_hit_06.pngbin0 -> 36776 bytes
-rw-r--r--V3/Content/Effects/blood_hit_08.pngbin0 -> 115643 bytes
-rw-r--r--V3/Content/Effects/explosion.pngbin0 -> 2623088 bytes
-rw-r--r--V3/Content/Effects/particlefx_03.pngbin0 -> 972652 bytes
-rw-r--r--V3/Content/Effects/particlefx_04.pngbin0 -> 821590 bytes
-rw-r--r--V3/Content/Effects/particlefx_05.pngbin0 -> 544650 bytes
-rw-r--r--V3/Content/Effects/quake.pngbin0 -> 122179 bytes
-rw-r--r--V3/Content/Fonts/Blutschrift.ttfbin0 -> 256596 bytes
-rw-r--r--V3/Content/Fonts/DeathFont.spritefont50
-rw-r--r--V3/Content/Fonts/DejaVuSans.ttfbin0 -> 756072 bytes
-rw-r--r--V3/Content/Fonts/MenuFont.spritefont50
-rw-r--r--V3/Content/Fonts/Siegesschriftzug.ttfbin0 -> 1081476 bytes
-rw-r--r--V3/Content/Fonts/UnitFont.spritefont50
-rw-r--r--V3/Content/Fonts/VictoryFont.spritefont50
-rw-r--r--V3/Content/Fonts/grabstein.ttfbin0 -> 21676 bytes
-rw-r--r--V3/Content/Maps/map_grassland.tmx988
-rw-r--r--V3/Content/Maps/techdemo.tmx1170
-rw-r--r--V3/Content/Maps/work_in_progress.tmx1258
-rw-r--r--V3/Content/Menu/Titel.pngbin0 -> 91996 bytes
-rw-r--r--V3/Content/Menu/arrow_white.pngbin0 -> 3981 bytes
-rw-r--r--V3/Content/Menu/mainscreen.jpgbin0 -> 3376885 bytes
-rw-r--r--V3/Content/Sounds/Afraid_to_Go.mp3bin0 -> 6975318 bytes
-rw-r--r--V3/Content/Sounds/Knight.wavbin0 -> 1947210 bytes
-rw-r--r--V3/Content/Sounds/Kosta_T_-_06.mp3bin0 -> 11340892 bytes
-rw-r--r--V3/Content/Sounds/Monster_Gigante-Doberman-1334685792.wavbin0 -> 1175132 bytes
-rw-r--r--V3/Content/Sounds/Mummy_Zombie-SoundBible.wavbin0 -> 357466 bytes
-rw-r--r--V3/Content/Sounds/SkeletonHorse.wavbin0 -> 2759074 bytes
-rw-r--r--V3/Content/Sounds/explode.wavbin0 -> 303992 bytes
-rw-r--r--V3/Content/Sounds/explodemini.wavbin0 -> 277340 bytes
-rw-r--r--V3/Content/Sounds/explosion1.oggbin0 -> 37165 bytes
-rw-r--r--V3/Content/Sounds/horse.wavbin0 -> 14032 bytes
-rw-r--r--V3/Content/Sounds/impactsplat01.oggbin0 -> 21825 bytes
-rw-r--r--V3/Content/Sounds/punch.wavbin0 -> 140058 bytes
-rw-r--r--V3/Content/Sounds/walking.wavbin0 -> 2102948 bytes
-rw-r--r--V3/Content/Sounds/zonk2.wavbin0 -> 95374 bytes
-rw-r--r--V3/Content/Sources/Horse.blendbin0 -> 11055184 bytes
-rw-r--r--V3/Content/Sources/Skeleton.blendbin0 -> 1101828 bytes
-rw-r--r--V3/Content/Sources/SkeletonHorse.blendbin0 -> 2900188 bytes
-rw-r--r--V3/Content/Sources/SkeletonHorse.pngbin0 -> 1013788 bytes
-rw-r--r--V3/Content/Sources/SkeletonRider.blendbin0 -> 4551660 bytes
-rw-r--r--V3/Content/Sources/SkeletonRider.pngbin0 -> 734006 bytes
-rw-r--r--V3/Content/Sources/ZombieWithClub.pngbin0 -> 921761 bytes
-rw-r--r--V3/Content/Sources/castle.xcfbin0 -> 525634 bytes
-rw-r--r--V3/Content/Sources/create_spritesheet.sh7
-rw-r--r--V3/Content/Sources/fleischklops.blendbin0 -> 2307520 bytes
-rw-r--r--V3/Content/Sources/fleischklops.xcfbin0 -> 1387154 bytes
-rw-r--r--V3/Content/Sources/horse_paint.pngbin0 -> 898326 bytes
-rw-r--r--V3/Content/Sources/horse_paint_sc.pngbin0 -> 1460647 bytes
-rw-r--r--V3/Content/Sources/horse_tack.pngbin0 -> 879871 bytes
-rw-r--r--V3/Content/Sources/houses_front.xcfbin0 -> 221614 bytes
-rw-r--r--V3/Content/Sources/houses_rear.xcfbin0 -> 205943 bytes
-rw-r--r--V3/Content/Sources/human_construction_set.xcfbin0 -> 10007151 bytes
-rw-r--r--V3/Content/Sources/human_construction_set_female.xcfbin0 -> 6728872 bytes
-rw-r--r--V3/Content/Sources/king.blendbin0 -> 4472284 bytes
-rw-r--r--V3/Content/Sources/king_head.pngbin0 -> 131639 bytes
-rw-r--r--V3/Content/Sources/necromancer.xcfbin0 -> 5307898 bytes
-rw-r--r--V3/Content/Sources/pathfinder.xcfbin0 -> 2470 bytes
-rw-r--r--V3/Content/Sources/prince.blendbin0 -> 3927028 bytes
-rw-r--r--V3/Content/Sources/prince.xcfbin0 -> 2523537 bytes
-rw-r--r--V3/Content/Sources/selection.xcfbin0 -> 151080 bytes
-rw-r--r--V3/Content/Sources/skeleton_horse.pngbin0 -> 1083757 bytes
-rw-r--r--V3/Content/Sources/the_triumph_of_death.jpgbin0 -> 3376885 bytes
-rw-r--r--V3/Content/Sources/zombie.blendbin0 -> 1563140 bytes
-rw-r--r--V3/Content/Sprites/WhiteRectangle.pngbin0 -> 67 bytes
-rw-r--r--V3/Content/Sprites/arrows.pngbin0 -> 4218 bytes
-rw-r--r--V3/Content/Sprites/buckler.pngbin0 -> 189331 bytes
-rw-r--r--V3/Content/Sprites/buckler_female.pngbin0 -> 150081 bytes
-rw-r--r--V3/Content/Sprites/chain.pngbin0 -> 680942 bytes
-rw-r--r--V3/Content/Sprites/chain_female.pngbin0 -> 594899 bytes
-rw-r--r--V3/Content/Sprites/cloth.pngbin0 -> 627879 bytes
-rw-r--r--V3/Content/Sprites/cloth_female.pngbin0 -> 560029 bytes
-rw-r--r--V3/Content/Sprites/cloud.pngbin0 -> 54576 bytes
-rw-r--r--V3/Content/Sprites/ellipse.pngbin0 -> 10943 bytes
-rw-r--r--V3/Content/Sprites/fleischklops.pngbin0 -> 2466843 bytes
-rw-r--r--V3/Content/Sprites/fog.pngbin0 -> 44834 bytes
-rw-r--r--V3/Content/Sprites/head.pngbin0 -> 105453 bytes
-rw-r--r--V3/Content/Sprites/head_bald.pngbin0 -> 107161 bytes
-rw-r--r--V3/Content/Sprites/head_chain.pngbin0 -> 145589 bytes
-rw-r--r--V3/Content/Sprites/head_chain_female.pngbin0 -> 134925 bytes
-rw-r--r--V3/Content/Sprites/head_female.pngbin0 -> 120410 bytes
-rw-r--r--V3/Content/Sprites/head_plate.pngbin0 -> 158766 bytes
-rw-r--r--V3/Content/Sprites/head_plate_female.pngbin0 -> 146096 bytes
-rw-r--r--V3/Content/Sprites/king.pngbin0 -> 822995 bytes
-rw-r--r--V3/Content/Sprites/longsword.pngbin0 -> 145022 bytes
-rw-r--r--V3/Content/Sprites/longsword_female.pngbin0 -> 156551 bytes
-rw-r--r--V3/Content/Sprites/necromancer.pngbin0 -> 705759 bytes
-rw-r--r--V3/Content/Sprites/necromancer_female.pngbin0 -> 659280 bytes
-rw-r--r--V3/Content/Sprites/nude.pngbin0 -> 632199 bytes
-rw-r--r--V3/Content/Sprites/nude_female.pngbin0 -> 567054 bytes
-rw-r--r--V3/Content/Sprites/plate.pngbin0 -> 702344 bytes
-rw-r--r--V3/Content/Sprites/plate_female.pngbin0 -> 623813 bytes
-rw-r--r--V3/Content/Sprites/prince.pngbin0 -> 855383 bytes
-rw-r--r--V3/Content/Sprites/selection.pngbin0 -> 1327 bytes
-rw-r--r--V3/Content/Sprites/shield.pngbin0 -> 253328 bytes
-rw-r--r--V3/Content/Sprites/shield_female.pngbin0 -> 257298 bytes
-rw-r--r--V3/Content/Sprites/shortsword.pngbin0 -> 91334 bytes
-rw-r--r--V3/Content/Sprites/shortsword_female.pngbin0 -> 99034 bytes
-rw-r--r--V3/Content/Sprites/skeleton.pngbin0 -> 950304 bytes
-rw-r--r--V3/Content/Sprites/skeleton_archer.pngbin0 -> 1082133 bytes
-rw-r--r--V3/Content/Sprites/skeleton_elite.pngbin0 -> 1191913 bytes
-rw-r--r--V3/Content/Sprites/skeleton_horse.pngbin0 -> 1013788 bytes
-rw-r--r--V3/Content/Sprites/skeleton_rider.pngbin0 -> 734006 bytes
-rw-r--r--V3/Content/Sprites/staff.pngbin0 -> 324639 bytes
-rw-r--r--V3/Content/Sprites/staff_female.pngbin0 -> 336664 bytes
-rw-r--r--V3/Content/Sprites/zombie.pngbin0 -> 801160 bytes
-rw-r--r--V3/Content/Sprites/zombie_club.pngbin0 -> 921761 bytes
-rw-r--r--V3/Content/Textures/EmptyPixel.pngbin0 -> 169 bytes
-rw-r--r--V3/Content/Textures/castle.pngbin0 -> 1668329 bytes
-rw-r--r--V3/Content/Textures/grassland.pngbin0 -> 430934 bytes
-rw-r--r--V3/Content/Textures/grassland_trees.pngbin0 -> 445999 bytes
-rw-r--r--V3/Content/Textures/grassland_water.pngbin0 -> 254809 bytes
-rw-r--r--V3/Content/Textures/houses_front.pngbin0 -> 287910 bytes
-rw-r--r--V3/Content/Textures/houses_rear.pngbin0 -> 302161 bytes
-rw-r--r--V3/Content/Textures/medieval_building_tiles.pngbin0 -> 515727 bytes
-rw-r--r--V3/Content/Textures/pathfinder.pngbin0 -> 289 bytes
-rw-r--r--V3/Data/DebugMode.cs21
-rw-r--r--V3/Data/GameState.cs64
-rw-r--r--V3/Data/IGameStateManager.cs20
-rw-r--r--V3/Data/IOptionsManager.cs18
-rw-r--r--V3/Data/IPathManager.cs30
-rw-r--r--V3/Data/ISaveGame.cs25
-rw-r--r--V3/Data/ISaveGameManager.cs25
-rw-r--r--V3/Data/Internal/GameStateManager.cs81
-rw-r--r--V3/Data/Internal/OptionsManager.cs65
-rw-r--r--V3/Data/Internal/PathManager.cs51
-rw-r--r--V3/Data/Internal/SaveGame.cs65
-rw-r--r--V3/Data/Internal/SaveGameManager.cs88
-rw-r--r--V3/Data/Options.cs105
-rw-r--r--V3/Effects/AbstractEffect.cs74
-rw-r--r--V3/Effects/BloodBang.cs8
-rw-r--r--V3/Effects/BloodExplosion.cs11
-rw-r--r--V3/Effects/BloodFountain.cs11
-rw-r--r--V3/Effects/EffectsManager.cs54
-rw-r--r--V3/Effects/Explosion.cs14
-rw-r--r--V3/Effects/HorseEffect.cs11
-rw-r--r--V3/Effects/IEffect.cs44
-rw-r--r--V3/Effects/IEffectsManager.cs31
-rw-r--r--V3/Effects/Quake.cs11
-rw-r--r--V3/Effects/SmokeBig.cs10
-rw-r--r--V3/Effects/SmokeMedium.cs13
-rw-r--r--V3/Effects/SmokeSmall.cs10
-rw-r--r--V3/Ellipse.cs31
-rw-r--r--V3/Faction.cs7
-rw-r--r--V3/Icon.icobin0 -> 32038 bytes
-rw-r--r--V3/Input/IInputManager.cs34
-rw-r--r--V3/Input/IKeyEvent.cs20
-rw-r--r--V3/Input/IMouseEvent.cs34
-rw-r--r--V3/Input/IMouseEventHandler.cs14
-rw-r--r--V3/Input/Internal/InputManager.cs141
-rw-r--r--V3/Input/Internal/KeyEvent.cs32
-rw-r--r--V3/Input/Internal/MouseEvent.cs57
-rw-r--r--V3/Input/MouseButton.cs9
-rw-r--r--V3/Map/AbstractLayer.cs259
-rw-r--r--V3/Map/Area.cs119
-rw-r--r--V3/Map/Constants.cs12
-rw-r--r--V3/Map/FloorLayer.cs21
-rw-r--r--V3/Map/FogOfWar.cs107
-rw-r--r--V3/Map/IMapManager.cs88
-rw-r--r--V3/Map/MapManager.cs97
-rw-r--r--V3/Map/ObjectLayer.cs16
-rw-r--r--V3/Map/Pathfinder.cs455
-rw-r--r--V3/Map/PathfindingGrid.cs125
-rw-r--r--V3/Map/SearchNode.cs31
-rw-r--r--V3/Map/TiledParser.cs256
-rw-r--r--V3/Map/Tileset.cs89
-rw-r--r--V3/Node.cs467
-rw-r--r--V3/Objects/AbstractBuilding.cs110
-rw-r--r--V3/Objects/AbstractCreature.cs911
-rw-r--r--V3/Objects/Arrow.cs109
-rw-r--r--V3/Objects/BuildingState.cs8
-rw-r--r--V3/Objects/Castle.cs15
-rw-r--r--V3/Objects/CreatureFactory.cs127
-rw-r--r--V3/Objects/FemalePeasant.cs50
-rw-r--r--V3/Objects/Forge.cs19
-rw-r--r--V3/Objects/IBasicCreatureFactory.cs28
-rw-r--r--V3/Objects/IBuilding.cs20
-rw-r--r--V3/Objects/ICreature.cs120
-rw-r--r--V3/Objects/IGameObject.cs43
-rw-r--r--V3/Objects/IObjectsManager.cs131
-rw-r--r--V3/Objects/IdGenerator.cs59
-rw-r--r--V3/Objects/King.cs33
-rw-r--r--V3/Objects/KingsGuard.cs62
-rw-r--r--V3/Objects/Knight.cs65
-rw-r--r--V3/Objects/MalePeasant.cs49
-rw-r--r--V3/Objects/Meatball.cs36
-rw-r--r--V3/Objects/Movement.cs20
-rw-r--r--V3/Objects/Movement/CountStepsMovement.cs16
-rw-r--r--V3/Objects/Movement/IMovable.cs43
-rw-r--r--V3/Objects/Movement/PlayerMovement.cs155
-rw-r--r--V3/Objects/Necromancer.cs61
-rw-r--r--V3/Objects/ObjectsManager.cs314
-rw-r--r--V3/Objects/Prince.cs33
-rw-r--r--V3/Objects/Selection.cs483
-rw-r--r--V3/Objects/Skeleton.cs65
-rw-r--r--V3/Objects/SkeletonElite.cs19
-rw-r--r--V3/Objects/SkeletonHorse.cs87
-rw-r--r--V3/Objects/Sprite/AbstractSpriteCreature.cs201
-rw-r--r--V3/Objects/Sprite/ArrowSprite.cs42
-rw-r--r--V3/Objects/Sprite/BucklerFemaleSprite.cs7
-rw-r--r--V3/Objects/Sprite/BucklerSprite.cs7
-rw-r--r--V3/Objects/Sprite/ChainFemaleSprite.cs7
-rw-r--r--V3/Objects/Sprite/ChainSprite.cs7
-rw-r--r--V3/Objects/Sprite/ClothFemaleSprite.cs7
-rw-r--r--V3/Objects/Sprite/ClothSprite.cs7
-rw-r--r--V3/Objects/Sprite/EquipmentType.cs10
-rw-r--r--V3/Objects/Sprite/HeadBaldSprite.cs10
-rw-r--r--V3/Objects/Sprite/HeadChainFemaleSprite.cs7
-rw-r--r--V3/Objects/Sprite/HeadChainSprite.cs7
-rw-r--r--V3/Objects/Sprite/HeadFemaleSprite.cs7
-rw-r--r--V3/Objects/Sprite/HeadPlateFemaleSprite.cs7
-rw-r--r--V3/Objects/Sprite/HeadPlateSprite.cs7
-rw-r--r--V3/Objects/Sprite/HeadSprite.cs7
-rw-r--r--V3/Objects/Sprite/ISpriteCreature.cs53
-rw-r--r--V3/Objects/Sprite/KingSprite.cs7
-rw-r--r--V3/Objects/Sprite/LongswordFemaleSprite.cs7
-rw-r--r--V3/Objects/Sprite/LongswordSprite.cs7
-rw-r--r--V3/Objects/Sprite/MeatballSprite.cs11
-rw-r--r--V3/Objects/Sprite/NecromancerFemaleSprite.cs7
-rw-r--r--V3/Objects/Sprite/NecromancerSprite.cs7
-rw-r--r--V3/Objects/Sprite/NudeFemaleSprite.cs7
-rw-r--r--V3/Objects/Sprite/NudeSprite.cs7
-rw-r--r--V3/Objects/Sprite/PlateFemaleSprite.cs7
-rw-r--r--V3/Objects/Sprite/PlateSprite.cs7
-rw-r--r--V3/Objects/Sprite/PrinceSprite.cs7
-rw-r--r--V3/Objects/Sprite/ShieldFemaleSprite.cs7
-rw-r--r--V3/Objects/Sprite/ShieldSprite.cs7
-rw-r--r--V3/Objects/Sprite/ShortswordFemaleSprite.cs7
-rw-r--r--V3/Objects/Sprite/ShortswordSprite.cs7
-rw-r--r--V3/Objects/Sprite/SkeletonArcherSprite.cs10
-rw-r--r--V3/Objects/Sprite/SkeletonEliteSprite.cs9
-rw-r--r--V3/Objects/Sprite/SkeletonHorseSprite.cs7
-rw-r--r--V3/Objects/Sprite/SkeletonRiderSprite.cs10
-rw-r--r--V3/Objects/Sprite/SkeletonSprite.cs9
-rw-r--r--V3/Objects/Sprite/StaffFemaleSprite.cs7
-rw-r--r--V3/Objects/Sprite/StaffSprite.cs7
-rw-r--r--V3/Objects/Sprite/ZombieSprite.cs11
-rw-r--r--V3/Objects/Sprite/ZombieWithClubSprite.cs11
-rw-r--r--V3/Objects/TextureObject.cs76
-rw-r--r--V3/Objects/Transformation.cs102
-rw-r--r--V3/Objects/Woodhouse.cs16
-rw-r--r--V3/Objects/Zombie.cs45
-rw-r--r--V3/OpenTK.dll.config25
-rw-r--r--V3/Program.cs20
-rw-r--r--V3/Properties/AssemblyInfo.cs35
-rw-r--r--V3/Quadtree.cs87
-rw-r--r--V3/Screens/AbstractScreen.cs57
-rw-r--r--V3/Screens/AchievementsScreen.cs221
-rw-r--r--V3/Screens/DeathScreen.cs140
-rw-r--r--V3/Screens/DebugScreen.cs92
-rw-r--r--V3/Screens/FpsCounter.cs46
-rw-r--r--V3/Screens/GameScreen.cs306
-rw-r--r--V3/Screens/HudScreen.cs349
-rw-r--r--V3/Screens/IDrawable.cs19
-rw-r--r--V3/Screens/IScreen.cs39
-rw-r--r--V3/Screens/IScreenFactory.cs27
-rw-r--r--V3/Screens/IScreenManager.cs35
-rw-r--r--V3/Screens/IUpdatable.cs16
-rw-r--r--V3/Screens/LoadScreen.cs124
-rw-r--r--V3/Screens/MainScreen.cs195
-rw-r--r--V3/Screens/MenuActions.cs208
-rw-r--r--V3/Screens/OptionsScreen.cs197
-rw-r--r--V3/Screens/PauseScreen.cs140
-rw-r--r--V3/Screens/ScreenManager.cs164
-rw-r--r--V3/Screens/StatisticsScreen.cs186
-rw-r--r--V3/Screens/TechdemoScreen.cs325
-rw-r--r--V3/Screens/VictoryScreen.cs76
-rw-r--r--V3/UpdatesPerSecond.cs55
-rw-r--r--V3/V3.csproj498
-rw-r--r--V3/V3Game.cs78
-rw-r--r--V3/Widgets/AbstractMenu.cs96
-rw-r--r--V3/Widgets/AbstractTextWidget.cs113
-rw-r--r--V3/Widgets/AchievementBox.cs91
-rw-r--r--V3/Widgets/Button.cs111
-rw-r--r--V3/Widgets/EmptyWidget.cs41
-rw-r--r--V3/Widgets/FormMenu.cs75
-rw-r--r--V3/Widgets/HorizontalOrientation.cs9
-rw-r--r--V3/Widgets/IBasicWidgetFactory.cs38
-rw-r--r--V3/Widgets/IClickable.cs14
-rw-r--r--V3/Widgets/IImageWidget.cs15
-rw-r--r--V3/Widgets/IMenu.cs33
-rw-r--r--V3/Widgets/IMenuFactory.cs9
-rw-r--r--V3/Widgets/ISelectable.cs27
-rw-r--r--V3/Widgets/ITextWidget.cs43
-rw-r--r--V3/Widgets/IWidget.cs34
-rw-r--r--V3/Widgets/Label.cs14
-rw-r--r--V3/Widgets/SelectButton.cs108
-rw-r--r--V3/Widgets/VerticalMenu.cs42
-rw-r--r--V3/Widgets/WidgetFactory.cs78
-rw-r--r--V3/packages.config6
332 files changed, 18155 insertions, 0 deletions
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
+{
+ /// <summary>
+ /// The state of an action taken by the computer player.
+ /// </summary>
+ public enum ActionState
+ {
+ /// <summary>
+ /// The action is waiting to be executed.
+ /// </summary>
+ Waiting,
+ /// <summary>
+ /// The action is currently being executed.
+ /// </summary>
+ Executing,
+ /// <summary>
+ /// The action has been done successfully.
+ /// </summary>
+ Done,
+ /// <summary>
+ /// The action failed.
+ /// </summary>
+ 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
+{
+ /// <summary>
+ /// 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).
+ /// </summary>
+ public enum AiState
+ {
+ /// <summary>
+ /// Waiting for the player actions.
+ /// </summary>
+ Idle,
+ /// <summary>
+ /// Defend peasants so that they don't become zombies.
+ /// </summary>
+ DefendPeasants,
+ /// <summary>
+ /// Attack enemy creatures.
+ /// </summary>
+ AttackCreatures,
+ /// <summary>
+ /// Attack the necromancer directly.
+ /// </summary>
+ 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
+{
+ /// <summary>
+ /// An action that can be taken by the computer player.
+ /// </summary>
+ public interface IAction
+ {
+ /// <summary>
+ /// The current state of the action.
+ /// </summary>
+ ActionState State { get; }
+
+ /// <summary>
+ /// Start the execution of the action.
+ /// </summary>
+ void Start();
+
+ /// <summary>
+ /// Update the execution state. This method should be repateatingly
+ /// called as long as State is Executing.
+ /// </summary>
+ 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
+{
+ /// <summary>
+ /// A computer player that takes actions according to a specified strategy.
+ /// </summary>
+ public interface IAiPlayer
+ {
+ /// <summary>
+ /// The current world view of the player. It stores the knowledge of
+ /// the computer player based on the previous percepts.
+ /// </summary>
+ IWorldView WorldView { get; }
+ /// <summary>
+ /// The strategy of the player. The strategy is a state machine that
+ /// defines the current state.
+ /// </summary>
+ IStrategy Strategy { get; }
+ /// <summary>
+ /// The current state of the player. The state is one step of the
+ /// strategy, and defines the specific actions to take.
+ /// </summary>
+ AiState State { get; set; }
+ /// <summary>
+ /// The actions that the player wants to be executed. Updated by
+ /// Act.
+ /// </summary>
+ IList<IAction> Actions { get; }
+
+ /// <summary>
+ /// Executes one update cycle -- perception, acting and the execution
+ /// of actions.
+ /// </summary>
+ /// <param name="gameTime">the time since the last update</param>
+ void Update(GameTime gameTime);
+
+ /// <summary>
+ /// Update the AI's view of the game world.
+ /// </summary>
+ void Percept();
+
+ /// <summary>
+ /// 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.
+ /// </summary>
+ 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
+{
+ /// <summary>
+ /// A strategy for the computer player. A strategy is a finite state
+ /// machine.
+ /// </summary>
+ public interface IStrategy
+ {
+ /// <summary>
+ /// Updates the current state according to the game situtation.
+ /// </summary>
+ /// <param name="state">the current state</param>
+ /// <param name="worldView">the current view of the game world</param>
+ /// <returns>the next state indicated by this strategy</returns>
+ 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
+{
+ /// <summary>
+ /// 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.
+ /// </summary>
+ public interface IWorldView
+ {
+ int EnemyCount { get; set; }
+ int InitialPlebsCount { get; set; }
+ int PlebsCount { get; set; }
+ float NecromancerHealth { get; set; }
+ List<ICreature> IdlingKnights { get; }
+ List<ICreature> Targets { get; }
+ List<ICreature> 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
+{
+ /// <summary>
+ /// Abstract implementation of IAction.
+ /// </summary>
+ public abstract class AbstractAction : IAction
+ {
+ /// <summary>
+ /// The current state of the action.
+ /// </summary>
+ public ActionState State { get; private set; } = ActionState.Waiting;
+
+ /// <summary>
+ /// Start the execution of the action.
+ /// </summary>
+ public virtual void Start()
+ {
+ State = ActionState.Executing;
+ }
+
+ /// <summary>
+ /// Update the execution state. This method should be repateatingly
+ /// called as long as State is Executing.
+ /// </summary>
+ public virtual void Update()
+ {
+ if (State != ActionState.Executing)
+ return;
+ State = GetNextState();
+ }
+
+ /// <summary>
+ /// Returns the next state of this action. It is guaranteed that the
+ /// current state is Executing.
+ /// </summary>
+ 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
+{
+ /// <summary>
+ /// Default implementation of IAiPlayer.
+ /// </summary>
+ // ReSharper disable once ClassNeverInstantiated.Global
+ public class AiPlayer : IAiPlayer
+ {
+ /// <summary>
+ /// The current world view of the player. It stores the knowledge of
+ /// the computer player based on the previous percepts.
+ /// </summary>
+ public IWorldView WorldView { get; } = new WorldView();
+ /// <summary>
+ /// The strategy of the player. The strategy is a state machine that
+ /// defines the current state.
+ /// </summary>
+ public IStrategy Strategy { get; } = new AttackStrategy();
+ /// <summary>
+ /// The current state of the player. The state is one step of the
+ /// strategy, and defines the specific actions to take.
+ /// </summary>
+ public AiState State { get; set; } = AiState.Idle;
+ /// <summary>
+ /// The actions that the player wants to be executed. Updated by
+ /// Act.
+ /// </summary>
+ public IList<IAction> Actions { get; } = new List<IAction>();
+
+ 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;
+
+ /// <summary>
+ /// Creates a new AI player.
+ /// </summary>
+ public AiPlayer(IActionFactory actionFactory, IBasicCreatureFactory creatureFactory,
+ IObjectsManager objectsManager)
+ {
+ mActionFactory = actionFactory;
+ mCreatureFactory = creatureFactory;
+ mObjectsManager = objectsManager;
+ }
+
+ /// <summary>
+ /// Executes one update cycle -- perception, acting and the execution
+ /// of actions.
+ /// </summary>
+ /// <param name="gameTime">the time since the last update</param>
+ 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();
+ }
+ }
+
+ /// <summary>
+ /// Update the AI's view of the game world.
+ /// </summary>
+ 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));
+ }
+
+ /// <summary>
+ /// Take actions based on the previous percepts, the current strategy
+ /// and state.
+ /// </summary>
+ 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<Knight>().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
+{
+ /// <summary>
+ /// A simple strategy for the computer player that tells him to attack the
+ /// enemy creatures.
+ /// </summary>
+ internal class AttackStrategy : IStrategy
+ {
+ /// <summary>
+ /// Updates the current state according to the game situtation.
+ /// </summary>
+ /// <param name="state">the current state</param>
+ /// <param name="worldView">the current view of the game world</param>
+ /// <returns>the next state indicated by this strategy</returns>
+ 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
+{
+ /// <summary>
+ /// Creates IAction instances. Automatically implemented by Ninject.
+ /// </summary>
+ public interface IActionFactory
+ {
+ /// <summary>
+ /// Creates a new MoveAction to move the given creature to the given
+ /// destination.
+ /// </summary>
+ /// <param name="creature">the creature to mvoe</param>
+ /// <param name="destination">the destination of the creature</param>
+ MoveAction CreateMoveAction(ICreature creature, Vector2 destination);
+
+ /// <summary>
+ /// Creates a new SpawnAction that spawns the given creature at the
+ /// given position.
+ /// </summary>
+ /// <param name="creature">the creature to spawn</param>
+ /// <param name="position">the spawn position</param>
+ 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
+{
+ /// <summary>
+ /// Moves a creature to a destination point.
+ /// </summary>
+ // ReSharper disable once ClassNeverInstantiated.Global
+ public class MoveAction : AbstractAction
+ {
+ private ICreature mCreature;
+ private Vector2 mDestination;
+
+ /// <summary>
+ /// Creates a new MoveAction to move the given creature to the given
+ /// destination.
+ /// </summary>
+ /// <param name="creature">the creature to mvoe</param>
+ /// <param name="destination">the destination of the creature</param>
+ public MoveAction(ICreature creature, Vector2 destination)
+ {
+ mCreature = creature;
+ mDestination = destination;
+ }
+
+ /// <summary>
+ /// Start the execution of the action.
+ /// </summary>
+ 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
+{
+ /// <summary>
+ /// Spawns a creature at a given position.
+ /// </summary>
+ // ReSharper disable once ClassNeverInstantiated.Global
+ public class SpawnAction : AbstractAction
+ {
+ private readonly IObjectsManager mObjectsManager;
+ private ICreature mCreature;
+ private Vector2 mPosition;
+
+ /// <summary>
+ /// Creates a new SpawnAction that spawns the given creature at the
+ /// given position.
+ /// </summary>
+ /// <param name="objectsManager">the linked objects manager</param>
+ /// <param name="creature">the creature to spawn</param>
+ /// <param name="position">the spawn position</param>
+ 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
+{
+ /// <summary>
+ /// Default implementation of IWorldView.
+ /// </summary>
+ 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<ICreature> IdlingKnights { get; } = new List<ICreature>();
+ public List<ICreature> Targets { get; } = new List<ICreature>();
+ public List<ICreature> Plebs { get; } = new List<ICreature>();
+ }
+}
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
+{
+ /// <summary>
+ /// This is a class for all datas of the achievementsand the statistics.
+ /// </summary>
+ // 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
+{
+ /// <summary>
+ /// Defines the bindings of constants, factories and singletons for the
+ /// Ninject dependency injection framework.
+ /// </summary>
+ public sealed class Bindings : NinjectModule
+ {
+ private readonly V3Game mGame;
+ private readonly GraphicsDeviceManager mGraphicsDeviceManager;
+
+ /// <summary>
+ /// Creates a new Bindings instance for the given game and graphics
+ /// device manager.
+ /// </summary>
+ /// <param name="game">the game that uses this instance</param>
+ /// <param name="graphicsDeviceManager">the graphics device manager
+ /// instance to use in this instance</param>
+ public Bindings(V3Game game, GraphicsDeviceManager graphicsDeviceManager)
+ {
+ mGame = game;
+ mGraphicsDeviceManager = graphicsDeviceManager;
+ }
+
+ public override void Load()
+ {
+ // constants
+ Bind<ContentManager>().ToConstant(mGame.Content);
+ Bind<Game>().ToConstant(mGame);
+ Bind<GraphicsDeviceManager>().ToConstant(mGraphicsDeviceManager);
+
+ // factories
+ Bind<IActionFactory>().ToFactory();
+ Bind<IBasicCreatureFactory>().ToFactory();
+ Bind<IBasicWidgetFactory>().ToFactory();
+ Bind<IMenuFactory>().ToFactory();
+ Bind<IScreenFactory>().ToFactory();
+
+ // singletons
+ Bind<IGameStateManager>().To<GameStateManager>().InSingletonScope();
+ Bind<IInputManager>().To<InputManager>().InSingletonScope();
+ Bind<IOptionsManager>().To<OptionsManager>().InSingletonScope();
+ Bind<IScreenManager>().To<ScreenManager>().InSingletonScope();
+ Bind<CameraManager>().ToSelf().InSingletonScope();
+ Bind<IMapManager>().To<MapManager>().InSingletonScope();
+ Bind<IObjectsManager>().To<ObjectsManager>().InSingletonScope();
+ Bind<Pathfinder>().ToSelf().InSingletonScope();
+ Bind<Selection>().ToSelf().InSingletonScope();
+ Bind<IEffectsManager>().To<EffectsManager>().InSingletonScope();
+ Bind<AchievementsAndStatistics>().ToSelf().InSingletonScope();
+
+ // regular bindings
+ Bind<IAiPlayer>().To<AiPlayer>();
+ Bind<IPathManager>().To<PathManager>();
+ Bind<ISaveGameManager>().To<SaveGameManager>();
+ }
+ }
+}
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 <http://www.mapeditor.org/>.
+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)
+ <http://opengameart.org/content/western-european-castle-isometric-25d>
+* Animated particle effects #1 and #2 by para (CC0)
+ <http://opengameart.org/content/animated-particle-effects-1>
+ <http://opengameart.org/content/animated-particle-effects-2>
+* Explosion animation and sound by WrathGames Studio <http://wrathgames.com/blog> (CC-BY 3.0)
+ <http://opengameart.org/content/wgstudio-explosion-animation>
+ <http://opengameart.org/content/wgs-sound-fx-explosion-1>
+* 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)
+ <https://pixabay.com/en/oil-painting-death-classical-1178909/>
+
+Music:
+------
+* Title screen music by Kosta T / Konstantin Trokay (CC BY-NC 4.0)
+ <http://freemusicarchive.org/music/kosta_t/>
+* Game screen music
+ <http://freemusicarchive.org/music/Unheard_Music_Concepts/Harbour/UnheardMusicConcepts__04_Afraid_to_Go>
+
+Sounds:
+-------
+* Wet squish, slurp impacts by Independent.nu (CC0):
+ <http://opengameart.org/content/8-wet-squish-slurp-impacts>
+* High Quality Explosions by Michel Baradari (CC-BY 3.0):
+ <http://opengameart.org/content/2-high-quality-explosions>
+* The Skeleton Horse sound
+ <http://soundbible.com/254-Horses-Galloping-Off.html>
+* The Knight sound
+ <http://soundbible.com/1329-Soldiers-Marching.html>
+* The Meatball sound
+ <http://soundbible.com/1963-Giant-Monster.html>
+* The walking sound of the remaining creatures
+ <http://soundbible.com/1432-Walking-On-Gravel.html> \ 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
+{
+ /// <summary>
+ /// This is the Camera Class for a player-centered camera mode. Does not go outside the map.
+ /// </summary>
+ // 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;
+ }
+
+ /// <summary>
+ /// Updates the position of the camera related to the player's position.
+ /// </summary>
+ 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
+{
+ /// <summary>
+ /// Stores and provides access to the possible cameras.
+ /// </summary>
+ // ReSharper disable once ClassNeverInstantiated.Global
+ public sealed class CameraManager
+ {
+ private readonly IOptionsManager mOptionsManager;
+ private readonly CameraCentered mCameraCentered;
+ private readonly CameraScrolling mCameraScrolling;
+
+ /// <summary>
+ /// Creates a new CameraManager.
+ /// </summary>
+ public CameraManager(CameraCentered cameraCentered,
+ CameraScrolling cameraScrolling, IOptionsManager optionsManager)
+ {
+ mCameraCentered = cameraCentered;
+ mCameraScrolling = cameraScrolling;
+ mOptionsManager = optionsManager;
+ }
+
+ /// <summary>
+ /// Initializes the cameras with the given map data.
+ /// </summary>
+ 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<ICamera> { mCameraCentered, mCameraScrolling };
+ foreach (var camera in cameras)
+ {
+ camera.MapPixelHeight = mapPixelHeight;
+ camera.MapPixelWidth = mapPixelWidth;
+ }
+ }
+
+ /// <summary>
+ /// Updates the cameras.
+ /// </summary>
+ public void Update(ICreature creature)
+ {
+ GetCamera().Update(creature);
+ if (mOptionsManager.Options.CameraType != CameraType.Scrolling)
+ mCameraScrolling.Location = GetCamera().Location;
+ }
+
+ /// <summary>
+ /// Returns the currently selected camera.
+ /// </summary>
+ 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
+{
+ /// <summary>
+ /// This is the camera class for a map-scrolling camera mode. Does not move over the map.
+ /// </summary>
+ // 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));
+ }
+
+ /// <summary>
+ /// Move the Camera to the left. Does not go outside the map.
+ /// </summary>
+ private void MoveCameraLeft()
+ {
+ mLocation.X = MathHelper.Clamp(mLocation.X - CameraSpeed, 0, mMaxX);
+ }
+
+ /// <summary>
+ /// Move the Camera to the right. Does not go outside the map.
+ /// </summary>
+ private void MoveCameraRight()
+ {
+ mLocation.X = MathHelper.Clamp(mLocation.X + CameraSpeed, 0, mMaxX);
+ }
+
+ /// <summary>
+ /// Move the Camera up. Does not go outside the map.
+ /// </summary>
+ private void MoveCameraUp()
+ {
+ mLocation.Y = MathHelper.Clamp(mLocation.Y + CameraSpeed, 0, mMaxY);
+ }
+
+
+ /// <summary>
+ /// Move the Camera down. Does not go outside the map.
+ /// </summary>
+ 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 @@
+<?xml version="1.0" encoding="utf-8"?>
+<ClassDiagram /> \ 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
--- /dev/null
+++ b/V3/Content/Buttons/Button-01.png
Binary files 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
--- /dev/null
+++ b/V3/Content/Buttons/Button-01_Pressed.png
Binary files differ
diff --git a/V3/Content/Buttons/Button-02.png b/V3/Content/Buttons/Button-02.png
new file mode 100644
index 0000000..123a375
--- /dev/null
+++ b/V3/Content/Buttons/Button-02.png
Binary files 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
--- /dev/null
+++ b/V3/Content/Buttons/Button-02_Pressed.png
Binary files differ
diff --git a/V3/Content/Buttons/Button-03.png b/V3/Content/Buttons/Button-03.png
new file mode 100644
index 0000000..a06547d
--- /dev/null
+++ b/V3/Content/Buttons/Button-03.png
Binary files 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
--- /dev/null
+++ b/V3/Content/Buttons/Button-03_Pressed.png
Binary files differ
diff --git a/V3/Content/Buttons/Button-04.png b/V3/Content/Buttons/Button-04.png
new file mode 100644
index 0000000..42a60da
--- /dev/null
+++ b/V3/Content/Buttons/Button-04.png
Binary files 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
--- /dev/null
+++ b/V3/Content/Buttons/Button-04_Pressed.png
Binary files differ
diff --git a/V3/Content/Buttons/Button-05.png b/V3/Content/Buttons/Button-05.png
new file mode 100644
index 0000000..3a2d99c
--- /dev/null
+++ b/V3/Content/Buttons/Button-05.png
Binary files 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
--- /dev/null
+++ b/V3/Content/Buttons/Button-05_Pressed.png
Binary files differ
diff --git a/V3/Content/Buttons/Button-06.png b/V3/Content/Buttons/Button-06.png
new file mode 100644
index 0000000..1bc3448
--- /dev/null
+++ b/V3/Content/Buttons/Button-06.png
Binary files 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
--- /dev/null
+++ b/V3/Content/Buttons/Button-06_Pressed.png
Binary files differ
diff --git a/V3/Content/Buttons/Button-07.png b/V3/Content/Buttons/Button-07.png
new file mode 100644
index 0000000..422e445
--- /dev/null
+++ b/V3/Content/Buttons/Button-07.png
Binary files 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
--- /dev/null
+++ b/V3/Content/Buttons/Button-07_Pressed.png
Binary files 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
--- /dev/null
+++ b/V3/Content/Effects/blood_hit_01.png
Binary files 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
--- /dev/null
+++ b/V3/Content/Effects/blood_hit_02.png
Binary files 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
--- /dev/null
+++ b/V3/Content/Effects/blood_hit_03.png
Binary files 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
--- /dev/null
+++ b/V3/Content/Effects/blood_hit_04.png
Binary files 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
--- /dev/null
+++ b/V3/Content/Effects/blood_hit_05.png
Binary files 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
--- /dev/null
+++ b/V3/Content/Effects/blood_hit_06.png
Binary files 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
--- /dev/null
+++ b/V3/Content/Effects/blood_hit_08.png
Binary files differ
diff --git a/V3/Content/Effects/explosion.png b/V3/Content/Effects/explosion.png
new file mode 100644
index 0000000..0f4f3e9
--- /dev/null
+++ b/V3/Content/Effects/explosion.png
Binary files differ
diff --git a/V3/Content/Effects/particlefx_03.png b/V3/Content/Effects/particlefx_03.png
new file mode 100644
index 0000000..2649c85
--- /dev/null
+++ b/V3/Content/Effects/particlefx_03.png
Binary files differ
diff --git a/V3/Content/Effects/particlefx_04.png b/V3/Content/Effects/particlefx_04.png
new file mode 100644
index 0000000..346695e
--- /dev/null
+++ b/V3/Content/Effects/particlefx_04.png
Binary files differ
diff --git a/V3/Content/Effects/particlefx_05.png b/V3/Content/Effects/particlefx_05.png
new file mode 100644
index 0000000..d046357
--- /dev/null
+++ b/V3/Content/Effects/particlefx_05.png
Binary files differ
diff --git a/V3/Content/Effects/quake.png b/V3/Content/Effects/quake.png
new file mode 100644
index 0000000..6fe7ad0
--- /dev/null
+++ b/V3/Content/Effects/quake.png
Binary files differ
diff --git a/V3/Content/Fonts/Blutschrift.ttf b/V3/Content/Fonts/Blutschrift.ttf
new file mode 100644
index 0000000..da803c1
--- /dev/null
+++ b/V3/Content/Fonts/Blutschrift.ttf
Binary files 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 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
+ <Asset Type="Graphics:FontDescription">
+ <FontName>Blutschrift</FontName>
+ <Size>50</Size>
+ <Spacing>3</Spacing>
+ <Style>Regular</Style>
+ <CharacterRegions>
+ <CharacterRegion>
+ <Start>&#32;</Start>
+ <End>&#126;</End>
+ </CharacterRegion>
+ <!-- Character Region for the letter "ä" -->
+ <CharacterRegion>
+ <Start>&#228;</Start>
+ <End>&#228;</End>
+ </CharacterRegion>
+ <!-- Character Region for the letter "ö" -->
+ <CharacterRegion>
+ <Start>&#246;</Start>
+ <End>&#246;</End>
+ </CharacterRegion>
+ <!-- Character Region for the letter "ü" -->
+ <CharacterRegion>
+ <Start>&#252;</Start>
+ <End>&#252;</End>
+ </CharacterRegion>
+ <!-- Character Region for the letter "Ä" -->
+ <CharacterRegion>
+ <Start>&#196;</Start>
+ <End>&#196;</End>
+ </CharacterRegion>
+ <!-- Character Region for the letter "Ö" -->
+ <CharacterRegion>
+ <Start>&#214;</Start>
+ <End>&#214;</End>
+ </CharacterRegion>
+ <!-- Character Region for the letter "Ü" -->
+ <CharacterRegion>
+ <Start>&#220;</Start>
+ <End>&#220;</End>
+ </CharacterRegion>
+ <!-- Character Region for the letter "ß" -->
+ <CharacterRegion>
+ <Start>&#223;</Start>
+ <End>&#223;</End>
+ </CharacterRegion>
+ </CharacterRegions>
+ </Asset>
+</XnaContent> \ 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
--- /dev/null
+++ b/V3/Content/Fonts/DejaVuSans.ttf
Binary files 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 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
+ <Asset Type="Graphics:FontDescription">
+ <FontName>grabstein</FontName>
+ <Size>20</Size>
+ <Spacing>3</Spacing>
+ <Style>Regular</Style>
+ <CharacterRegions>
+ <CharacterRegion>
+ <Start>&#32;</Start>
+ <End>&#126;</End>
+ </CharacterRegion>
+ <!-- Character Region for the letter "ä" -->
+ <CharacterRegion>
+ <Start>&#228;</Start>
+ <End>&#228;</End>
+ </CharacterRegion>
+ <!-- Character Region for the letter "ö" -->
+ <CharacterRegion>
+ <Start>&#246;</Start>
+ <End>&#246;</End>
+ </CharacterRegion>
+ <!-- Character Region for the letter "ü" -->
+ <CharacterRegion>
+ <Start>&#252;</Start>
+ <End>&#252;</End>
+ </CharacterRegion>
+ <!-- Character Region for the letter "Ä" -->
+ <CharacterRegion>
+ <Start>&#196;</Start>
+ <End>&#196;</End>
+ </CharacterRegion>
+ <!-- Character Region for the letter "Ö" -->
+ <CharacterRegion>
+ <Start>&#214;</Start>
+ <End>&#214;</End>
+ </CharacterRegion>
+ <!-- Character Region for the letter "Ü" -->
+ <CharacterRegion>
+ <Start>&#220;</Start>
+ <End>&#220;</End>
+ </CharacterRegion>
+ <!-- Character Region for the letter "ß" -->
+ <CharacterRegion>
+ <Start>&#223;</Start>
+ <End>&#223;</End>
+ </CharacterRegion>
+ </CharacterRegions>
+ </Asset>
+</XnaContent> \ 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
--- /dev/null
+++ b/V3/Content/Fonts/Siegesschriftzug.ttf
Binary files 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 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
+ <Asset Type="Graphics:FontDescription">
+ <FontName>grabstein</FontName>
+ <Size>12</Size>
+ <Spacing>3</Spacing>
+ <Style>Regular</Style>
+ <CharacterRegions>
+ <CharacterRegion>
+ <Start>&#32;</Start>
+ <End>&#126;</End>
+ </CharacterRegion>
+ <!-- Character Region for the letter "ä" -->
+ <CharacterRegion>
+ <Start>&#228;</Start>
+ <End>&#228;</End>
+ </CharacterRegion>
+ <!-- Character Region for the letter "ö" -->
+ <CharacterRegion>
+ <Start>&#246;</Start>
+ <End>&#246;</End>
+ </CharacterRegion>
+ <!-- Character Region for the letter "ü" -->
+ <CharacterRegion>
+ <Start>&#252;</Start>
+ <End>&#252;</End>
+ </CharacterRegion>
+ <!-- Character Region for the letter "Ä" -->
+ <CharacterRegion>
+ <Start>&#196;</Start>
+ <End>&#196;</End>
+ </CharacterRegion>
+ <!-- Character Region for the letter "Ö" -->
+ <CharacterRegion>
+ <Start>&#214;</Start>
+ <End>&#214;</End>
+ </CharacterRegion>
+ <!-- Character Region for the letter "Ü" -->
+ <CharacterRegion>
+ <Start>&#220;</Start>
+ <End>&#220;</End>
+ </CharacterRegion>
+ <!-- Character Region for the letter "ß" -->
+ <CharacterRegion>
+ <Start>&#223;</Start>
+ <End>&#223;</End>
+ </CharacterRegion>
+ </CharacterRegions>
+ </Asset>
+</XnaContent> \ 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 @@
+<?xml version="1.0" encoding="iso-8859-1"?>
+<XnaContent xmlns:Graphics="Microsoft.Xna.Framework.Content.Pipeline.Graphics">
+ <Asset Type="Graphics:FontDescription">
+ <FontName>Siegesschriftzug</FontName>
+ <Size>50</Size>
+ <Spacing>3</Spacing>
+ <Style>Regular</Style>
+ <CharacterRegions>
+ <CharacterRegion>
+ <Start>&#32;</Start>
+ <End>&#126;</End>
+ </CharacterRegion>
+ <!-- Character Region for the letter "ä" -->
+ <CharacterRegion>
+ <Start>&#228;</Start>
+ <End>&#228;</End>
+ </CharacterRegion>
+ <!-- Character Region for the letter "ö" -->
+ <CharacterRegion>
+ <Start>&#246;</Start>
+ <End>&#246;</End>
+ </CharacterRegion>
+ <!-- Character Region for the letter "ü" -->
+ <CharacterRegion>
+ <Start>&#252;</Start>
+ <End>&#252;</End>
+ </CharacterRegion>
+ <!-- Character Region for the letter "Ä" -->
+ <CharacterRegion>
+ <Start>&#196;</Start>
+ <End>&#196;</End>
+ </CharacterRegion>
+ <!-- Character Region for the letter "Ö" -->
+ <CharacterRegion>
+ <Start>&#214;</Start>
+ <End>&#214;</End>
+ </CharacterRegion>
+ <!-- Character Region for the letter "Ü" -->
+ <CharacterRegion>
+ <Start>&#220;</Start>
+ <End>&#220;</End>
+ </CharacterRegion>
+ <!-- Character Region for the letter "ß" -->
+ <CharacterRegion>
+ <Start>&#223;</Start>
+ <End>&#223;</End>
+ </CharacterRegion>
+ </CharacterRegions>
+ </Asset>
+</XnaContent> \ 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
--- /dev/null
+++ b/V3/Content/Fonts/grabstein.ttf
Binary files 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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<map version="1.0" orientation="staggered" renderorder="right-down" width="50" height="100" tilewidth="64" tileheight="32" staggeraxis="y" staggerindex="odd" nextobjectid="10">
+ <properties>
+ <property name="gridsize" type="int" value="16"/>
+ </properties>
+ <tileset firstgid="1" name="grassland" tilewidth="64" tileheight="128" tilecount="128" columns="16">
+ <image source="../Textures/grassland.png" width="1024" height="1024"/>
+ <tile id="32">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100100"/>
+ </properties>
+ </tile>
+ <tile id="33">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100010"/>
+ </properties>
+ </tile>
+ <tile id="34">
+ <properties>
+ <property name="collision" value="00000000000000000000001101100000"/>
+ </properties>
+ </tile>
+ <tile id="35">
+ <properties>
+ <property name="collision" value="00000000000000000000110001100000"/>
+ </properties>
+ </tile>
+ <tile id="36">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100100"/>
+ </properties>
+ </tile>
+ <tile id="37">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100010"/>
+ </properties>
+ </tile>
+ <tile id="38">
+ <properties>
+ <property name="collision" value="00000000000000000000001101100000"/>
+ </properties>
+ </tile>
+ <tile id="39">
+ <properties>
+ <property name="collision" value="00000000000000000000110001100000"/>
+ </properties>
+ </tile>
+ <tile id="40">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100110"/>
+ </properties>
+ </tile>
+ <tile id="41">
+ <properties>
+ <property name="collision" value="00000000000000000000010001000100"/>
+ </properties>
+ </tile>
+ <tile id="42">
+ <properties>
+ <property name="collision" value="00000000000000000000000011110000"/>
+ </properties>
+ </tile>
+ <tile id="43">
+ <properties>
+ <property name="collision" value="00000000000000000000001000100010"/>
+ </properties>
+ </tile>
+ <tile id="44">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100110"/>
+ </properties>
+ </tile>
+ <tile id="45">
+ <properties>
+ <property name="collision" value="00000000000000000000010001000100"/>
+ </properties>
+ </tile>
+ <tile id="46">
+ <properties>
+ <property name="collision" value="00000000000000000000000011110000"/>
+ </properties>
+ </tile>
+ <tile id="47">
+ <properties>
+ <property name="collision" value="00000000000000000000001000100010"/>
+ </properties>
+ </tile>
+ <tile id="48">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="49">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100110"/>
+ </properties>
+ </tile>
+ <tile id="50">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100110"/>
+ </properties>
+ </tile>
+ <tile id="51">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100110"/>
+ </properties>
+ </tile>
+ <tile id="52">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="53">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100110"/>
+ </properties>
+ </tile>
+ <tile id="54">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100110"/>
+ </properties>
+ </tile>
+ <tile id="55">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100110"/>
+ </properties>
+ </tile>
+ <tile id="56">
+ <properties>
+ <property name="collision" value="00000000000000000000011111110000"/>
+ </properties>
+ </tile>
+ <tile id="57">
+ <properties>
+ <property name="collision" value="00000000000000000000001000110010"/>
+ </properties>
+ </tile>
+ <tile id="58">
+ <properties>
+ <property name="collision" value="00000000000000000000010011000100"/>
+ </properties>
+ </tile>
+ <tile id="59">
+ <properties>
+ <property name="collision" value="00000000000000000000111011110000"/>
+ </properties>
+ </tile>
+ <tile id="60">
+ <properties>
+ <property name="collision" value="00000000000000000000001011110100"/>
+ </properties>
+ </tile>
+ <tile id="61">
+ <properties>
+ <property name="collision" value="00000000000000000000010011110010"/>
+ </properties>
+ </tile>
+ <tile id="75">
+ <properties>
+ <property name="collision" value="00000000000000001111111111111111"/>
+ </properties>
+ </tile>
+ <tile id="80">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="81">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="82">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="83">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="84">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="85">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="86">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100110"/>
+ </properties>
+ </tile>
+ <tile id="87">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100110"/>
+ </properties>
+ </tile>
+ <tile id="88">
+ <properties>
+ <property name="collision" value="00000000000000000000000101100000"/>
+ </properties>
+ </tile>
+ <tile id="89">
+ <properties>
+ <property name="collision" value="00000000000000000000000000100000"/>
+ </properties>
+ </tile>
+ <tile id="90">
+ <properties>
+ <property name="collision" value="00000000000000000000000001000000"/>
+ </properties>
+ </tile>
+ <tile id="91">
+ <properties>
+ <property name="collision" value="00000000000000000000100001100000"/>
+ </properties>
+ </tile>
+ <tile id="92">
+ <properties>
+ <property name="collision" value="00000000000000000000000001110000"/>
+ </properties>
+ </tile>
+ <tile id="93">
+ <properties>
+ <property name="collision" value="00000000000000000000000000100000"/>
+ </properties>
+ </tile>
+ <tile id="94">
+ <properties>
+ <property name="collision" value="00000000000000000000000001000000"/>
+ </properties>
+ </tile>
+ <tile id="95">
+ <properties>
+ <property name="collision" value="00000000000000000000100001100000"/>
+ </properties>
+ </tile>
+ <tile id="112">
+ <properties>
+ <property name="collision" value="00000000000000000000000011100000"/>
+ </properties>
+ </tile>
+ <tile id="113">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="114">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="115">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="116">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="117">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="118">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="119">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="120">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="121">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="122">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="123">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="124">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="125">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="126">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="127">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ </tileset>
+ <tileset firstgid="129" name="grassland_trees" tilewidth="128" tileheight="256" tilecount="16" columns="8">
+ <tileoffset x="-32" y="0"/>
+ <image source="../Textures/grassland_trees.png" width="1024" height="512"/>
+ <tile id="0">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="1">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="2">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="3">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="4">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="5">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="6">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="7">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="8">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="9">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="10">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="11">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="12">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="13">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="14">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="15">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ </tileset>
+ <tileset firstgid="145" name="grassland_water" tilewidth="64" tileheight="64" tilecount="64" columns="16">
+ <tileoffset x="0" y="32"/>
+ <image source="../Textures/grassland_water.png" width="1024" height="256"/>
+ <tile id="0">
+ <properties>
+ <property name="collision" value="0010011000000000"/>
+ </properties>
+ </tile>
+ <tile id="1">
+ <properties>
+ <property name="collision" value="0100011000000000"/>
+ </properties>
+ </tile>
+ <tile id="2">
+ <properties>
+ <property name="collision" value="0110010000000000"/>
+ </properties>
+ </tile>
+ <tile id="3">
+ <properties>
+ <property name="collision" value="0110001000000000"/>
+ </properties>
+ </tile>
+ <tile id="4">
+ <properties>
+ <property name="collision" value="0010011000000000"/>
+ </properties>
+ </tile>
+ <tile id="5">
+ <properties>
+ <property name="collision" value="0100011000000000"/>
+ </properties>
+ </tile>
+ <tile id="6">
+ <properties>
+ <property name="collision" value="0110010000000000"/>
+ </properties>
+ </tile>
+ <tile id="7">
+ <properties>
+ <property name="collision" value="0110001000000000"/>
+ </properties>
+ </tile>
+ <tile id="8">
+ <properties>
+ <property name="collision" value="0000011000000000"/>
+ </properties>
+ </tile>
+ <tile id="9">
+ <properties>
+ <property name="collision" value="0100010000000000"/>
+ </properties>
+ </tile>
+ <tile id="10">
+ <properties>
+ <property name="collision" value="1111000000000000"/>
+ </properties>
+ </tile>
+ <tile id="11">
+ <properties>
+ <property name="collision" value="0010001000000000"/>
+ </properties>
+ </tile>
+ <tile id="12">
+ <properties>
+ <property name="collision" value="0000011000000000"/>
+ </properties>
+ </tile>
+ <tile id="13">
+ <properties>
+ <property name="collision" value="0100010000000000"/>
+ </properties>
+ </tile>
+ <tile id="14">
+ <properties>
+ <property name="collision" value="1111000000000000"/>
+ </properties>
+ </tile>
+ <tile id="15">
+ <properties>
+ <property name="collision" value="0010001000000000"/>
+ </properties>
+ </tile>
+ <tile id="16">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="17">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="18">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="19">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="20">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="21">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="22">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="23">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="32">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="33">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="34">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="35">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="36">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="37">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="38">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="39">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="40">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="41">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="42">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="43">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="44">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="45">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="46">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="47">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ </tileset>
+ <tileset firstgid="209" name="houses_rear" tilewidth="192" tileheight="192" tilecount="12" columns="3">
+ <tileoffset x="-64" y="32"/>
+ <image source="../Textures/houses_rear.png" width="576" height="768"/>
+ <tile id="0">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="1">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="2">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="3">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="4">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="5">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="6">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="7">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="8">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="9">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="10">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="11">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ </tileset>
+ <tileset firstgid="221" name="houses_front" tilewidth="192" tileheight="192" tilecount="12" columns="3">
+ <tileoffset x="-32" y="32"/>
+ <image source="../Textures/houses_front.png" width="576" height="768"/>
+ <tile id="0">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="1">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="2">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="3">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="4">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="5">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="6">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="7">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="8">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="9">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="10">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="11">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ </tileset>
+ <tileset firstgid="233" name="castle" tilewidth="1008" tileheight="848" tilecount="3" columns="3">
+ <tileoffset x="-504" y="224"/>
+ <image source="../Textures/castle.png" width="3024" height="848"/>
+ <tile id="0">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011000000000000000000000000000000000000000000000000000000000000111100000000000000000000000000000000000000000000000000000000011111111000000000000000000000000000000000000000000000000000001111111111110000000000000000000000000000000000000000000000000111111111111111100000000000000000000000000000000000000000000011111111111111111111000000000000000000000000000000000000000001111111111111111111111110000000000000000000000000000000000000111111111111111111111111111100000000000000000000000000000000011111111111111111111111111111111000000000000000000000000000001111111111111111111111111111111111110000000000000000000000000111111111111111111111111111111111111111100000000000000000000011111111111111111111111111111111111111111111000000000000000001111111111111111111111111111111111111111111111110000000000000111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111110000000001111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111100000000000011111111111111111111111111111111111111111000000000000000000000011111111111111111111111111111111111111111000000000000000000000001111111111111111111111111111111111111111000000000000000000000000011111111111111111111111111111111111111000000000000000000000000000111111111111111111111111111110111000000000000000000000000000000001111111111111111111111110001100000000000000000000000000000000000011111111111111111111000000000000000000000000000000000000000000000111100001111111100000000000000000000000000000000000000000000000011000001111111100000000000000000000000000000000000000000000000000000001111111100000000000000000000000000000000000000000000000000000000011110000000000000000000000000000"/>
+ </properties>
+ </tile>
+ <tile id="1">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011000000000000000000000000000000000000000000000000000000000000111100000000000000000000000000000000000000000000000000000000011111111000000000000000000000000000000000000000000000000000001111111111110000000000000000000000000000000000000000000000000111111111111111100000000000000000000000000000000000000000000011111111111111111111000000000000000000000000000000000000000001111111111111111111111110000000000000000000000000000000000000111111111111111111111111111100000000000000000000000000000000011111111111111111111111111111111000000000000000000000000000001111111111111111111111111111111111110000000000000000000000000111111111111111111111111111111111111111100000000000000000000011111111111111111111111111111111111111111111000000000000000001111111111111111111111111111111111111111111111110000000000000111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111110000000001111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111100000000000011111111111111111111111111111111111111111000000000000000000000011111111111111111111111111111111111111111000000000000000000000001111111111111111111111111111111111111111000000000000000000000000011111111111111111111111111111111111111000000000000000000000000000111111111111111111111111111110111000000000000000000000000000000001111111111111111111111110001100000000000000000000000000000000000011111111111111111111000000000000000000000000000000000000000000000111100001111111100000000000000000000000000000000000000000000000011000001111111100000000000000000000000000000000000000000000000000000001111111100000000000000000000000000000000000000000000000000000000011110000000000000000000000000000"/>
+ </properties>
+ </tile>
+ <tile id="2">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011000000000000000000000000000000000000000000000000000000000000111100000000000000000000000000000000000000000000000000000000011111111000000000000000000000000000000000000000000000000000001111111111110000000000000000000000000000000000000000000000000111111111111111100000000000000000000000000000000000000000000011111111111111111111000000000000000000000000000000000000000001111111111111111111111110000000000000000000000000000000000000111111111111111111111111111100000000000000000000000000000000011111111111111111111111111111111000000000000000000000000000001111111111111111111111111111111111110000000000000000000000000111111111111111111111111111111111111111100000000000000000000011111111111111111111111111111111111111111111000000000000000001111111111111111111111111111111111111111111111110000000000000111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111110000000001111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111100000000000011111111111111111111111111111111111111111000000000000000000000011111111111111111111111111111111111111111000000000000000000000001111111111111111111111111111111111111111000000000000000000000000011111111111111111111111111111111111111000000000000000000000000000111111111111111111111111111110111000000000000000000000000000000001111111111111111111111110001100000000000000000000000000000000000011111111111111111111000000000000000000000000000000000000000000000111100001111111100000000000000000000000000000000000000000000000011000001111111100000000000000000000000000000000000000000000000000000001111111100000000000000000000000000000000000000000000000000000000011110000000000000000000000000000"/>
+ </properties>
+ </tile>
+ </tileset>
+ <layer name="floor" width="50" height="100">
+ <data encoding="csv">
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
+1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,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
+</data>
+ </layer>
+ <layer name="objects" width="50" height="100">
+ <data encoding="csv">
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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
+</data>
+ </layer>
+ <objectgroup name="area">
+ <object id="4" type="village" x="129" y="434" width="791" height="561">
+ <properties>
+ <property name="chance" type="float" value="0.5"/>
+ <property name="density" type="float" value="0.5"/>
+ </properties>
+ </object>
+ <object id="5" type="village" x="2130" y="79" width="980" height="537">
+ <properties>
+ <property name="chance" type="float" value="0.5"/>
+ <property name="density" type="float" value="0.10000000000000001"/>
+ </properties>
+ </object>
+ <object id="8" name="Burg Leutstein" type="castle" x="1832" y="1012" width="1136" height="572">
+ <properties>
+ <property name="chance" type="float" value="0.050000000000000003"/>
+ <property name="density" type="float" value="0.5"/>
+ </properties>
+ </object>
+ <object id="9" type="graveyard" x="51" y="29" width="392" height="233"/>
+ </objectgroup>
+</map>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<map version="1.0" orientation="staggered" renderorder="right-down" width="50" height="200" tilewidth="64" tileheight="32" staggeraxis="y" staggerindex="odd" nextobjectid="4">
+ <properties>
+ <property name="gridsize" type="int" value="16"/>
+ </properties>
+ <tileset firstgid="1" name="grassland" tilewidth="64" tileheight="128" tilecount="128" columns="16">
+ <image source="../Textures/grassland.png" width="1024" height="1024"/>
+ <tile id="32">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100100"/>
+ </properties>
+ </tile>
+ <tile id="33">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100010"/>
+ </properties>
+ </tile>
+ <tile id="34">
+ <properties>
+ <property name="collision" value="00000000000000000000001101100000"/>
+ </properties>
+ </tile>
+ <tile id="35">
+ <properties>
+ <property name="collision" value="00000000000000000000110001100000"/>
+ </properties>
+ </tile>
+ <tile id="36">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100100"/>
+ </properties>
+ </tile>
+ <tile id="37">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100010"/>
+ </properties>
+ </tile>
+ <tile id="38">
+ <properties>
+ <property name="collision" value="00000000000000000000001101100000"/>
+ </properties>
+ </tile>
+ <tile id="39">
+ <properties>
+ <property name="collision" value="00000000000000000000110001100000"/>
+ </properties>
+ </tile>
+ <tile id="40">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100110"/>
+ </properties>
+ </tile>
+ <tile id="41">
+ <properties>
+ <property name="collision" value="00000000000000000000010001000100"/>
+ </properties>
+ </tile>
+ <tile id="42">
+ <properties>
+ <property name="collision" value="00000000000000000000000011110000"/>
+ </properties>
+ </tile>
+ <tile id="43">
+ <properties>
+ <property name="collision" value="00000000000000000000001000100010"/>
+ </properties>
+ </tile>
+ <tile id="44">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100110"/>
+ </properties>
+ </tile>
+ <tile id="45">
+ <properties>
+ <property name="collision" value="00000000000000000000010001000100"/>
+ </properties>
+ </tile>
+ <tile id="46">
+ <properties>
+ <property name="collision" value="00000000000000000000000011110000"/>
+ </properties>
+ </tile>
+ <tile id="47">
+ <properties>
+ <property name="collision" value="00000000000000000000001000100010"/>
+ </properties>
+ </tile>
+ <tile id="48">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="49">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100110"/>
+ </properties>
+ </tile>
+ <tile id="50">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100110"/>
+ </properties>
+ </tile>
+ <tile id="51">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100110"/>
+ </properties>
+ </tile>
+ <tile id="52">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="53">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100110"/>
+ </properties>
+ </tile>
+ <tile id="54">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100110"/>
+ </properties>
+ </tile>
+ <tile id="55">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100110"/>
+ </properties>
+ </tile>
+ <tile id="56">
+ <properties>
+ <property name="collision" value="00000000000000000000011111110000"/>
+ </properties>
+ </tile>
+ <tile id="57">
+ <properties>
+ <property name="collision" value="00000000000000000000001000110010"/>
+ </properties>
+ </tile>
+ <tile id="58">
+ <properties>
+ <property name="collision" value="00000000000000000000010011000100"/>
+ </properties>
+ </tile>
+ <tile id="59">
+ <properties>
+ <property name="collision" value="00000000000000000000111011110000"/>
+ </properties>
+ </tile>
+ <tile id="60">
+ <properties>
+ <property name="collision" value="00000000000000000000001011110100"/>
+ </properties>
+ </tile>
+ <tile id="61">
+ <properties>
+ <property name="collision" value="00000000000000000000010011110010"/>
+ </properties>
+ </tile>
+ <tile id="75">
+ <properties>
+ <property name="collision" value="00000000000000001111111111111111"/>
+ </properties>
+ </tile>
+ <tile id="80">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="81">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="82">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="83">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="84">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="85">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="86">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100110"/>
+ </properties>
+ </tile>
+ <tile id="87">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100110"/>
+ </properties>
+ </tile>
+ <tile id="88">
+ <properties>
+ <property name="collision" value="00000000000000000000000101100000"/>
+ </properties>
+ </tile>
+ <tile id="89">
+ <properties>
+ <property name="collision" value="00000000000000000000000000100000"/>
+ </properties>
+ </tile>
+ <tile id="90">
+ <properties>
+ <property name="collision" value="00000000000000000000000001000000"/>
+ </properties>
+ </tile>
+ <tile id="91">
+ <properties>
+ <property name="collision" value="00000000000000000000100001100000"/>
+ </properties>
+ </tile>
+ <tile id="92">
+ <properties>
+ <property name="collision" value="00000000000000000000000001110000"/>
+ </properties>
+ </tile>
+ <tile id="93">
+ <properties>
+ <property name="collision" value="00000000000000000000000000100000"/>
+ </properties>
+ </tile>
+ <tile id="94">
+ <properties>
+ <property name="collision" value="00000000000000000000000001000000"/>
+ </properties>
+ </tile>
+ <tile id="95">
+ <properties>
+ <property name="collision" value="00000000000000000000100001100000"/>
+ </properties>
+ </tile>
+ <tile id="112">
+ <properties>
+ <property name="collision" value="00000000000000000000000011100000"/>
+ </properties>
+ </tile>
+ <tile id="113">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="114">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="115">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="116">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="117">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="118">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="119">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="120">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="121">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="122">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="123">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="124">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="125">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="126">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="127">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ </tileset>
+ <tileset firstgid="129" name="grassland_trees" tilewidth="128" tileheight="256" tilecount="16" columns="8">
+ <tileoffset x="-32" y="0"/>
+ <image source="../Textures/grassland_trees.png" width="1024" height="512"/>
+ <tile id="0">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="1">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="2">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="3">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="4">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="5">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="6">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="7">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="8">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="9">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="10">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="11">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="12">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="13">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="14">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="15">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ </tileset>
+ <tileset firstgid="145" name="grassland_water" tilewidth="64" tileheight="64" tilecount="64" columns="16">
+ <tileoffset x="0" y="32"/>
+ <image source="../Textures/grassland_water.png" width="1024" height="256"/>
+ <tile id="0">
+ <properties>
+ <property name="collision" value="0010011000000000"/>
+ </properties>
+ </tile>
+ <tile id="1">
+ <properties>
+ <property name="collision" value="0100011000000000"/>
+ </properties>
+ </tile>
+ <tile id="2">
+ <properties>
+ <property name="collision" value="0110010000000000"/>
+ </properties>
+ </tile>
+ <tile id="3">
+ <properties>
+ <property name="collision" value="0110001000000000"/>
+ </properties>
+ </tile>
+ <tile id="4">
+ <properties>
+ <property name="collision" value="0010011000000000"/>
+ </properties>
+ </tile>
+ <tile id="5">
+ <properties>
+ <property name="collision" value="0100011000000000"/>
+ </properties>
+ </tile>
+ <tile id="6">
+ <properties>
+ <property name="collision" value="0110010000000000"/>
+ </properties>
+ </tile>
+ <tile id="7">
+ <properties>
+ <property name="collision" value="0110001000000000"/>
+ </properties>
+ </tile>
+ <tile id="8">
+ <properties>
+ <property name="collision" value="0000011000000000"/>
+ </properties>
+ </tile>
+ <tile id="9">
+ <properties>
+ <property name="collision" value="0100010000000000"/>
+ </properties>
+ </tile>
+ <tile id="10">
+ <properties>
+ <property name="collision" value="1111000000000000"/>
+ </properties>
+ </tile>
+ <tile id="11">
+ <properties>
+ <property name="collision" value="0010001000000000"/>
+ </properties>
+ </tile>
+ <tile id="12">
+ <properties>
+ <property name="collision" value="0000011000000000"/>
+ </properties>
+ </tile>
+ <tile id="13">
+ <properties>
+ <property name="collision" value="0100010000000000"/>
+ </properties>
+ </tile>
+ <tile id="14">
+ <properties>
+ <property name="collision" value="1111000000000000"/>
+ </properties>
+ </tile>
+ <tile id="15">
+ <properties>
+ <property name="collision" value="0010001000000000"/>
+ </properties>
+ </tile>
+ <tile id="16">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="17">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="18">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="19">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="20">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="21">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="22">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="23">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="32">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="33">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="34">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="35">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="36">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="37">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="38">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="39">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="40">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="41">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="42">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="43">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="44">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="45">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="46">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="47">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ </tileset>
+ <tileset firstgid="209" name="houses_rear" tilewidth="192" tileheight="192" tilecount="12" columns="3">
+ <tileoffset x="-64" y="32"/>
+ <image source="../Textures/houses_rear.png" width="576" height="768"/>
+ <tile id="0">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="1">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="2">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="3">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="4">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="5">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="6">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="7">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="8">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="9">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="10">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="11">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ </tileset>
+ <tileset firstgid="221" name="houses_front" tilewidth="192" tileheight="192" tilecount="12" columns="3">
+ <tileoffset x="-32" y="32"/>
+ <image source="../Textures/houses_front.png" width="576" height="768"/>
+ <tile id="0">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="1">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="2">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="3">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="4">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="5">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="6">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="7">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="8">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="9">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="10">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="11">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ </tileset>
+ <tileset firstgid="233" name="castle" tilewidth="1008" tileheight="848" tilecount="3" columns="3">
+ <tileoffset x="-504" y="224"/>
+ <image source="../Textures/castle.png" width="3024" height="848"/>
+ <tile id="0">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011000000000000000000000000000000000000000000000000000000000000111100000000000000000000000000000000000000000000000000000000011111111000000000000000000000000000000000000000000000000000001111111111110000000000000000000000000000000000000000000000000111111111111111100000000000000000000000000000000000000000000011111111111111111111000000000000000000000000000000000000000001111111111111111111111110000000000000000000000000000000000000111111111111111111111111111100000000000000000000000000000000011111111111111111111111111111111000000000000000000000000000001111111111111111111111111111111111110000000000000000000000000111111111111111111111111111111111111111100000000000000000000011111111111111111111111111111111111111111111000000000000000001111111111111111111111111111111111111111111111110000000000000111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111110000000001111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111100000000000011111111111111111111111111111111111111111000000000000000000000011111111111111111111111111111111111111111000000000000000000000001111111111111111111111111111111111111111000000000000000000000000011111111111111111111111111111111111111000000000000000000000000000111111111111111111111111111110111000000000000000000000000000000001111111111111111111111110001100000000000000000000000000000000000011111111111111111111000000000000000000000000000000000000000000000111100001111111100000000000000000000000000000000000000000000000011000001111111100000000000000000000000000000000000000000000000000000001111111100000000000000000000000000000000000000000000000000000000011110000000000000000000000000000"/>
+ </properties>
+ </tile>
+ <tile id="1">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011000000000000000000000000000000000000000000000000000000000000111100000000000000000000000000000000000000000000000000000000011111111000000000000000000000000000000000000000000000000000001111111111110000000000000000000000000000000000000000000000000111111111111111100000000000000000000000000000000000000000000011111111111111111111000000000000000000000000000000000000000001111111111111111111111110000000000000000000000000000000000000111111111111111111111111111100000000000000000000000000000000011111111111111111111111111111111000000000000000000000000000001111111111111111111111111111111111110000000000000000000000000111111111111111111111111111111111111111100000000000000000000011111111111111111111111111111111111111111111000000000000000001111111111111111111111111111111111111111111111110000000000000111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111110000000001111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111100000000000011111111111111111111111111111111111111111000000000000000000000011111111111111111111111111111111111111111000000000000000000000001111111111111111111111111111111111111111000000000000000000000000011111111111111111111111111111111111111000000000000000000000000000111111111111111111111111111110111000000000000000000000000000000001111111111111111111111110001100000000000000000000000000000000000011111111111111111111000000000000000000000000000000000000000000000111100001111111100000000000000000000000000000000000000000000000011000001111111100000000000000000000000000000000000000000000000000000001111111100000000000000000000000000000000000000000000000000000000011110000000000000000000000000000"/>
+ </properties>
+ </tile>
+ <tile id="2">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011000000000000000000000000000000000000000000000000000000000000111100000000000000000000000000000000000000000000000000000000011111111000000000000000000000000000000000000000000000000000001111111111110000000000000000000000000000000000000000000000000111111111111111100000000000000000000000000000000000000000000011111111111111111111000000000000000000000000000000000000000001111111111111111111111110000000000000000000000000000000000000111111111111111111111111111100000000000000000000000000000000011111111111111111111111111111111000000000000000000000000000001111111111111111111111111111111111110000000000000000000000000111111111111111111111111111111111111111100000000000000000000011111111111111111111111111111111111111111111000000000000000001111111111111111111111111111111111111111111111110000000000000111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111110000000001111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111100000000000011111111111111111111111111111111111111111000000000000000000000011111111111111111111111111111111111111111000000000000000000000001111111111111111111111111111111111111111000000000000000000000000011111111111111111111111111111111111111000000000000000000000000000111111111111111111111111111110111000000000000000000000000000000001111111111111111111111110001100000000000000000000000000000000000011111111111111111111000000000000000000000000000000000000000000000111100001111111100000000000000000000000000000000000000000000000011000001111111100000000000000000000000000000000000000000000000000000001111111100000000000000000000000000000000000000000000000000000000011110000000000000000000000000000"/>
+ </properties>
+ </tile>
+ </tileset>
+ <layer name="floor" width="50" height="200">
+ <data encoding="csv">
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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
+</data>
+ </layer>
+ <layer name="objects" width="50" height="200">
+ <data encoding="csv">
+0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,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
+</data>
+ </layer>
+ <objectgroup name="area">
+ <object id="3" name="Insel des Wahns" type="graveyard" x="1329" y="1388" width="729" height="339"/>
+ </objectgroup>
+</map>
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 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<map version="1.0" orientation="staggered" renderorder="right-down" width="101" height="201" tilewidth="64" tileheight="32" staggeraxis="y" staggerindex="odd" backgroundcolor="#000000" nextobjectid="40">
+ <properties>
+ <property name="gridsize" type="int" value="16"/>
+ </properties>
+ <tileset firstgid="1" name="grassland" tilewidth="64" tileheight="128" tilecount="128" columns="16">
+ <image source="../Textures/grassland.png" width="1024" height="1024"/>
+ <tile id="32">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100100"/>
+ </properties>
+ </tile>
+ <tile id="33">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100010"/>
+ </properties>
+ </tile>
+ <tile id="34">
+ <properties>
+ <property name="collision" value="00000000000000000000001101100000"/>
+ </properties>
+ </tile>
+ <tile id="35">
+ <properties>
+ <property name="collision" value="00000000000000000000110001100000"/>
+ </properties>
+ </tile>
+ <tile id="36">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100100"/>
+ </properties>
+ </tile>
+ <tile id="37">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100010"/>
+ </properties>
+ </tile>
+ <tile id="38">
+ <properties>
+ <property name="collision" value="00000000000000000000001101100000"/>
+ </properties>
+ </tile>
+ <tile id="39">
+ <properties>
+ <property name="collision" value="00000000000000000000110001100000"/>
+ </properties>
+ </tile>
+ <tile id="40">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100110"/>
+ </properties>
+ </tile>
+ <tile id="41">
+ <properties>
+ <property name="collision" value="00000000000000000000010001000100"/>
+ </properties>
+ </tile>
+ <tile id="42">
+ <properties>
+ <property name="collision" value="00000000000000000000000011110000"/>
+ </properties>
+ </tile>
+ <tile id="43">
+ <properties>
+ <property name="collision" value="00000000000000000000001000100010"/>
+ </properties>
+ </tile>
+ <tile id="44">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100110"/>
+ </properties>
+ </tile>
+ <tile id="45">
+ <properties>
+ <property name="collision" value="00000000000000000000010001000100"/>
+ </properties>
+ </tile>
+ <tile id="46">
+ <properties>
+ <property name="collision" value="00000000000000000000000011110000"/>
+ </properties>
+ </tile>
+ <tile id="47">
+ <properties>
+ <property name="collision" value="00000000000000000000001000100010"/>
+ </properties>
+ </tile>
+ <tile id="48">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="49">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100110"/>
+ </properties>
+ </tile>
+ <tile id="50">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100110"/>
+ </properties>
+ </tile>
+ <tile id="51">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100110"/>
+ </properties>
+ </tile>
+ <tile id="52">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="53">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100110"/>
+ </properties>
+ </tile>
+ <tile id="54">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100110"/>
+ </properties>
+ </tile>
+ <tile id="55">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100110"/>
+ </properties>
+ </tile>
+ <tile id="56">
+ <properties>
+ <property name="collision" value="00000000000000000000011111110000"/>
+ </properties>
+ </tile>
+ <tile id="57">
+ <properties>
+ <property name="collision" value="00000000000000000000001000110010"/>
+ </properties>
+ </tile>
+ <tile id="58">
+ <properties>
+ <property name="collision" value="00000000000000000000010011000100"/>
+ </properties>
+ </tile>
+ <tile id="59">
+ <properties>
+ <property name="collision" value="00000000000000000000111011110000"/>
+ </properties>
+ </tile>
+ <tile id="60">
+ <properties>
+ <property name="collision" value="00000000000000000000001011110100"/>
+ </properties>
+ </tile>
+ <tile id="61">
+ <properties>
+ <property name="collision" value="00000000000000000000010011110010"/>
+ </properties>
+ </tile>
+ <tile id="75">
+ <properties>
+ <property name="collision" value="00000000000000001111111111111111"/>
+ </properties>
+ </tile>
+ <tile id="80">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="81">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="82">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="83">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="84">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="85">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="86">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100110"/>
+ </properties>
+ </tile>
+ <tile id="87">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100110"/>
+ </properties>
+ </tile>
+ <tile id="88">
+ <properties>
+ <property name="collision" value="00000000000000000000000101100000"/>
+ </properties>
+ </tile>
+ <tile id="89">
+ <properties>
+ <property name="collision" value="00000000000000000000000000100000"/>
+ </properties>
+ </tile>
+ <tile id="90">
+ <properties>
+ <property name="collision" value="00000000000000000000000001000000"/>
+ </properties>
+ </tile>
+ <tile id="91">
+ <properties>
+ <property name="collision" value="00000000000000000000100001100000"/>
+ </properties>
+ </tile>
+ <tile id="92">
+ <properties>
+ <property name="collision" value="00000000000000000000000001110000"/>
+ </properties>
+ </tile>
+ <tile id="93">
+ <properties>
+ <property name="collision" value="00000000000000000000000000100000"/>
+ </properties>
+ </tile>
+ <tile id="94">
+ <properties>
+ <property name="collision" value="00000000000000000000000001000000"/>
+ </properties>
+ </tile>
+ <tile id="95">
+ <properties>
+ <property name="collision" value="00000000000000000000100001100000"/>
+ </properties>
+ </tile>
+ <tile id="112">
+ <properties>
+ <property name="collision" value="00000000000000000000000011100000"/>
+ </properties>
+ </tile>
+ <tile id="113">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="114">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="115">
+ <properties>
+ <property name="collision" value="00000000000000000000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="116">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="117">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="118">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="119">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="120">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="121">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="122">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="123">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="124">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="125">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="126">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ <tile id="127">
+ <properties>
+ <property name="collision" value="00000000000000000000011001100000"/>
+ </properties>
+ </tile>
+ </tileset>
+ <tileset firstgid="129" name="grassland_trees" tilewidth="128" tileheight="256" tilecount="16" columns="8">
+ <tileoffset x="-32" y="0"/>
+ <image source="../Textures/grassland_trees.png" width="1024" height="512"/>
+ <tile id="0">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="1">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="2">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="3">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="4">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="5">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="6">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="7">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="8">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="9">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="10">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="11">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="12">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="13">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="14">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ <tile id="15">
+ <properties>
+ <property name="collision" value="00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001100000000000"/>
+ </properties>
+ </tile>
+ </tileset>
+ <tileset firstgid="145" name="grassland_water" tilewidth="64" tileheight="64" tilecount="64" columns="16">
+ <tileoffset x="0" y="32"/>
+ <image source="../Textures/grassland_water.png" width="1024" height="256"/>
+ <tile id="0">
+ <properties>
+ <property name="collision" value="0010011000000000"/>
+ </properties>
+ </tile>
+ <tile id="1">
+ <properties>
+ <property name="collision" value="0100011000000000"/>
+ </properties>
+ </tile>
+ <tile id="2">
+ <properties>
+ <property name="collision" value="0110010000000000"/>
+ </properties>
+ </tile>
+ <tile id="3">
+ <properties>
+ <property name="collision" value="0110001000000000"/>
+ </properties>
+ </tile>
+ <tile id="4">
+ <properties>
+ <property name="collision" value="0010011000000000"/>
+ </properties>
+ </tile>
+ <tile id="5">
+ <properties>
+ <property name="collision" value="0100011000000000"/>
+ </properties>
+ </tile>
+ <tile id="6">
+ <properties>
+ <property name="collision" value="0110010000000000"/>
+ </properties>
+ </tile>
+ <tile id="7">
+ <properties>
+ <property name="collision" value="0110001000000000"/>
+ </properties>
+ </tile>
+ <tile id="8">
+ <properties>
+ <property name="collision" value="0000011000000000"/>
+ </properties>
+ </tile>
+ <tile id="9">
+ <properties>
+ <property name="collision" value="0100010000000000"/>
+ </properties>
+ </tile>
+ <tile id="10">
+ <properties>
+ <property name="collision" value="1111000000000000"/>
+ </properties>
+ </tile>
+ <tile id="11">
+ <properties>
+ <property name="collision" value="0010001000000000"/>
+ </properties>
+ </tile>
+ <tile id="12">
+ <properties>
+ <property name="collision" value="0000011000000000"/>
+ </properties>
+ </tile>
+ <tile id="13">
+ <properties>
+ <property name="collision" value="0100010000000000"/>
+ </properties>
+ </tile>
+ <tile id="14">
+ <properties>
+ <property name="collision" value="1111000000000000"/>
+ </properties>
+ </tile>
+ <tile id="15">
+ <properties>
+ <property name="collision" value="0010001000000000"/>
+ </properties>
+ </tile>
+ <tile id="16">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="17">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="18">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="19">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="20">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="21">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="22">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="23">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="32">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="33">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="34">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="35">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="36">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="37">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="38">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="39">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="40">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="41">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="42">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="43">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="44">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="45">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="46">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ <tile id="47">
+ <properties>
+ <property name="collision" value="0110011000000000"/>
+ </properties>
+ </tile>
+ </tileset>
+ <tileset firstgid="209" name="houses_rear" tilewidth="192" tileheight="192" tilecount="12" columns="3">
+ <tileoffset x="-64" y="32"/>
+ <image source="../Textures/houses_rear.png" width="576" height="768"/>
+ <tile id="0">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="1">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="2">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="3">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="4">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="5">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="6">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="7">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="8">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="9">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="10">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ <tile id="11">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000011000000000011110000000011111100000011111111000000111111000000001100000"/>
+ </properties>
+ </tile>
+ </tileset>
+ <tileset firstgid="221" name="houses_front" tilewidth="192" tileheight="192" tilecount="12" columns="3">
+ <tileoffset x="-32" y="32"/>
+ <image source="../Textures/houses_front.png" width="576" height="768"/>
+ <tile id="0">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="1">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="2">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="3">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="4">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="5">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="6">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="7">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="8">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="9">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="10">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ <tile id="11">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000011000000001111000000111111000011111111000011111100000000110000000"/>
+ </properties>
+ </tile>
+ </tileset>
+ <tileset firstgid="233" name="castle" tilewidth="1008" tileheight="848" tilecount="3" columns="3">
+ <tileoffset x="-504" y="224"/>
+ <image source="../Textures/castle.png" width="3024" height="848"/>
+ <tile id="0">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011000000000000000000000000000000000000000000000000000000000000111100000000000000000000000000000000000000000000000000000000011111111000000000000000000000000000000000000000000000000000001111111111110000000000000000000000000000000000000000000000000111111111111111100000000000000000000000000000000000000000000011111111111111111111000000000000000000000000000000000000000001111111111111111111111110000000000000000000000000000000000000111111111111111111111111111100000000000000000000000000000000011111111111111111111111111111111000000000000000000000000000001111111111111111111111111111111111110000000000000000000000000111111111111111111111111111111111111111100000000000000000000011111111111111111111111111111111111111111111000000000000000001111111111111111111111111111111111111111111111110000000000000111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111110000000001111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111100000000000011111111111111111111111111111111111111111000000000000000000000011111111111111111111111111111111111111111000000000000000000000001111111111111111111111111111111111111111000000000000000000000000011111111111111111111111111111111111111000000000000000000000000000111111111111111111111111111110111000000000000000000000000000000001111111111111111111111110001100000000000000000000000000000000000011111111111111111111000000000000000000000000000000000000000000000111100001111111100000000000000000000000000000000000000000000000011000001111111100000000000000000000000000000000000000000000000000000001111111100000000000000000000000000000000000000000000000000000000011110000000000000000000000000000"/>
+ </properties>
+ </tile>
+ <tile id="1">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011000000000000000000000000000000000000000000000000000000000000111100000000000000000000000000000000000000000000000000000000011111111000000000000000000000000000000000000000000000000000001111111111110000000000000000000000000000000000000000000000000111111111111111100000000000000000000000000000000000000000000011111111111111111111000000000000000000000000000000000000000001111111111111111111111110000000000000000000000000000000000000111111111111111111111111111100000000000000000000000000000000011111111111111111111111111111111000000000000000000000000000001111111111111111111111111111111111110000000000000000000000000111111111111111111111111111111111111111100000000000000000000011111111111111111111111111111111111111111111000000000000000001111111111111111111111111111111111111111111111110000000000000111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111110000000001111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111100000000000011111111111111111111111111111111111111111000000000000000000000011111111111111111111111111111111111111111000000000000000000000001111111111111111111111111111111111111111000000000000000000000000011111111111111111111111111111111111111000000000000000000000000000111111111111111111111111111110111000000000000000000000000000000001111111111111111111111110001100000000000000000000000000000000000011111111111111111111000000000000000000000000000000000000000000000111100001111111100000000000000000000000000000000000000000000000011000001111111100000000000000000000000000000000000000000000000000000001111111100000000000000000000000000000000000000000000000000000000011110000000000000000000000000000"/>
+ </properties>
+ </tile>
+ <tile id="2">
+ <properties>
+ <property name="collision" value="000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000011000000000000000000000000000000000000000000000000000000000000111100000000000000000000000000000000000000000000000000000000011111111000000000000000000000000000000000000000000000000000001111111111110000000000000000000000000000000000000000000000000111111111111111100000000000000000000000000000000000000000000011111111111111111111000000000000000000000000000000000000000001111111111111111111111110000000000000000000000000000000000000111111111111111111111111111100000000000000000000000000000000011111111111111111111111111111111000000000000000000000000000001111111111111111111111111111111111110000000000000000000000000111111111111111111111111111111111111111100000000000000000000011111111111111111111111111111111111111111111000000000000000001111111111111111111111111111111111111111111111110000000000000111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111110000000001111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000111111111111111111111111111111111111111111111111111111110000000011111111111111111111111111111111111111111111111111111110000000000011111111111111111111111111111111111111111111111111100000000000011111111111111111111111111111111111111111000000000000000000000011111111111111111111111111111111111111111000000000000000000000001111111111111111111111111111111111111111000000000000000000000000011111111111111111111111111111111111111000000000000000000000000000111111111111111111111111111110111000000000000000000000000000000001111111111111111111111110001100000000000000000000000000000000000011111111111111111111000000000000000000000000000000000000000000000111100001111111100000000000000000000000000000000000000000000000011000001111111100000000000000000000000000000000000000000000000000000001111111100000000000000000000000000000000000000000000000000000000011110000000000000000000000000000"/>
+ </properties>
+ </tile>
+ </tileset>
+ <tileset firstgid="236" name="grassland" tilewidth="64" tileheight="128" tilecount="128" columns="16">
+ <image source="../Textures/grassland.png" width="1024" height="1024"/>
+ </tileset>
+ <layer name="floor" width="101" height="201" offsetx="-5" offsety="-3">
+ <data encoding="csv">
+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
+</data>
+ </layer>
+ <layer name="objects" width="101" height="201">
+ <data encoding="csv">
+64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,64,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
+</data>
+ </layer>
+ <objectgroup name="area" visible="0">
+ <object id="5" name="Köhlersgrund" type="village" x="196" y="751" width="1148" height="590">
+ <properties>
+ <property name="chance" type="float" value="0.5"/>
+ <property name="density" type="float" value="0.5"/>
+ </properties>
+ </object>
+ <object id="6" name="Friedhof der Köhler" type="graveyard" x="212" y="1490" width="369" height="190">
+ <properties>
+ <property name="chance" type="float" value="0"/>
+ <property name="density" type="float" value="0"/>
+ </properties>
+ </object>
+ <object id="12" name="Schloss Eulenstein" type="castle" x="5156" y="728" width="1136" height="776">
+ <properties>
+ <property name="chance" type="float" value="0.20000000000000001"/>
+ <property name="density" type="float" value="0.69999999999999996"/>
+ </properties>
+ </object>
+ <object id="14" name="Hippielager" type="village" x="1742" y="122" width="238" height="136">
+ <properties>
+ <property name="chance" type="float" value="1"/>
+ <property name="density" type="float" value="0.5"/>
+ </properties>
+ </object>
+ <object id="15" name="Bastis Holzfällerstube" type="village" x="1436" y="672" width="404" height="162">
+ <properties>
+ <property name="chance" type="float" value="0.80000000000000004"/>
+ <property name="density" type="float" value="0.69999999999999996"/>
+ </properties>
+ </object>
+ <object id="17" name="Güldene Ruh" type="graveyard" x="2830" y="34" width="772" height="356">
+ <properties>
+ <property name="chance" type="float" value="0"/>
+ <property name="density" type="float" value="0"/>
+ </properties>
+ </object>
+ <object id="21" name="Sommerhaid" type="village" x="3272" y="366" width="1092" height="466">
+ <properties>
+ <property name="chance" type="float" value="0.40000000000000002"/>
+ <property name="density" type="float" value="1"/>
+ </properties>
+ </object>
+ <object id="23" name="Sommerhaid, Bettlerviertel" type="village" x="3778" y="134" width="814" height="230">
+ <properties>
+ <property name="chance" type="float" value="0.29999999999999999"/>
+ <property name="density" type="float" value="0.80000000000000004"/>
+ </properties>
+ </object>
+ <object id="25" name="Stillswasser" type="village" x="4746" y="2176" width="1664" height="772">
+ <properties>
+ <property name="chance" type="float" value="0.5"/>
+ <property name="density" type="float" value="0.34999999999999998"/>
+ </properties>
+ </object>
+ <object id="28" name="Lindenwäldle" type="village" x="622" y="1516" width="1470" height="1032">
+ <properties>
+ <property name="chance" type="float" value="0.29999999999999999"/>
+ <property name="density" type="float" value="0.29999999999999999"/>
+ </properties>
+ </object>
+ <object id="30" name="Säuferstal" type="village" x="180" y="2641" width="508" height="336">
+ <properties>
+ <property name="chance" type="float" value="1"/>
+ <property name="density" type="float" value="0.5"/>
+ </properties>
+ </object>
+ <object id="32" name="Lager der armen Holzfäller" type="village" x="2678" y="2749" width="950" height="338">
+ <properties>
+ <property name="chance" type="float" value="0.69999999999999996"/>
+ <property name="density" type="float" value="0.40000000000000002"/>
+ </properties>
+ </object>
+ <object id="37" name="Sommerhaid, Haidenviertel" type="village" x="2888" y="832" width="1044" height="460">
+ <properties>
+ <property name="chance" type="float" value="0.29999999999999999"/>
+ <property name="density" type="float" value="0.59999999999999998"/>
+ </properties>
+ </object>
+ <object id="39" name="Der ebene Wald" type="village" x="2100" y="1518" width="652" height="1570">
+ <properties>
+ <property name="chance" type="float" value="0.40000000000000002"/>
+ <property name="density" type="float" value="0.29999999999999999"/>
+ </properties>
+ </object>
+ </objectgroup>
+</map>
diff --git a/V3/Content/Menu/Titel.png b/V3/Content/Menu/Titel.png
new file mode 100644
index 0000000..d22295f
--- /dev/null
+++ b/V3/Content/Menu/Titel.png
Binary files differ
diff --git a/V3/Content/Menu/arrow_white.png b/V3/Content/Menu/arrow_white.png
new file mode 100644
index 0000000..8e4d2e2
--- /dev/null
+++ b/V3/Content/Menu/arrow_white.png
Binary files differ
diff --git a/V3/Content/Menu/mainscreen.jpg b/V3/Content/Menu/mainscreen.jpg
new file mode 100644
index 0000000..654eaa6
--- /dev/null
+++ b/V3/Content/Menu/mainscreen.jpg
Binary files 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
--- /dev/null
+++ b/V3/Content/Sounds/Afraid_to_Go.mp3
Binary files differ
diff --git a/V3/Content/Sounds/Knight.wav b/V3/Content/Sounds/Knight.wav
new file mode 100644
index 0000000..cb088af
--- /dev/null
+++ b/V3/Content/Sounds/Knight.wav
Binary files 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
--- /dev/null
+++ b/V3/Content/Sounds/Kosta_T_-_06.mp3
Binary files 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
--- /dev/null
+++ b/V3/Content/Sounds/Monster_Gigante-Doberman-1334685792.wav
Binary files 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
--- /dev/null
+++ b/V3/Content/Sounds/Mummy_Zombie-SoundBible.wav
Binary files differ
diff --git a/V3/Content/Sounds/SkeletonHorse.wav b/V3/Content/Sounds/SkeletonHorse.wav
new file mode 100644
index 0000000..7804c61
--- /dev/null
+++ b/V3/Content/Sounds/SkeletonHorse.wav
Binary files differ
diff --git a/V3/Content/Sounds/explode.wav b/V3/Content/Sounds/explode.wav
new file mode 100644
index 0000000..8c1d089
--- /dev/null
+++ b/V3/Content/Sounds/explode.wav
Binary files differ
diff --git a/V3/Content/Sounds/explodemini.wav b/V3/Content/Sounds/explodemini.wav
new file mode 100644
index 0000000..bcad45b
--- /dev/null
+++ b/V3/Content/Sounds/explodemini.wav
Binary files differ
diff --git a/V3/Content/Sounds/explosion1.ogg b/V3/Content/Sounds/explosion1.ogg
new file mode 100644
index 0000000..64c1ab6
--- /dev/null
+++ b/V3/Content/Sounds/explosion1.ogg
Binary files differ
diff --git a/V3/Content/Sounds/horse.wav b/V3/Content/Sounds/horse.wav
new file mode 100644
index 0000000..5715ad1
--- /dev/null
+++ b/V3/Content/Sounds/horse.wav
Binary files differ
diff --git a/V3/Content/Sounds/impactsplat01.ogg b/V3/Content/Sounds/impactsplat01.ogg
new file mode 100644
index 0000000..731cf83
--- /dev/null
+++ b/V3/Content/Sounds/impactsplat01.ogg
Binary files differ
diff --git a/V3/Content/Sounds/punch.wav b/V3/Content/Sounds/punch.wav
new file mode 100644
index 0000000..395bb5c
--- /dev/null
+++ b/V3/Content/Sounds/punch.wav
Binary files differ
diff --git a/V3/Content/Sounds/walking.wav b/V3/Content/Sounds/walking.wav
new file mode 100644
index 0000000..894dff4
--- /dev/null
+++ b/V3/Content/Sounds/walking.wav
Binary files differ
diff --git a/V3/Content/Sounds/zonk2.wav b/V3/Content/Sounds/zonk2.wav
new file mode 100644
index 0000000..77e37b4
--- /dev/null
+++ b/V3/Content/Sounds/zonk2.wav
Binary files differ
diff --git a/V3/Content/Sources/Horse.blend b/V3/Content/Sources/Horse.blend
new file mode 100644
index 0000000..017b12c
--- /dev/null
+++ b/V3/Content/Sources/Horse.blend
Binary files differ
diff --git a/V3/Content/Sources/Skeleton.blend b/V3/Content/Sources/Skeleton.blend
new file mode 100644
index 0000000..0a8fd5d
--- /dev/null
+++ b/V3/Content/Sources/Skeleton.blend
Binary files differ
diff --git a/V3/Content/Sources/SkeletonHorse.blend b/V3/Content/Sources/SkeletonHorse.blend
new file mode 100644
index 0000000..3520f1e
--- /dev/null
+++ b/V3/Content/Sources/SkeletonHorse.blend
Binary files differ
diff --git a/V3/Content/Sources/SkeletonHorse.png b/V3/Content/Sources/SkeletonHorse.png
new file mode 100644
index 0000000..e0fc808
--- /dev/null
+++ b/V3/Content/Sources/SkeletonHorse.png
Binary files differ
diff --git a/V3/Content/Sources/SkeletonRider.blend b/V3/Content/Sources/SkeletonRider.blend
new file mode 100644
index 0000000..24d7161
--- /dev/null
+++ b/V3/Content/Sources/SkeletonRider.blend
Binary files differ
diff --git a/V3/Content/Sources/SkeletonRider.png b/V3/Content/Sources/SkeletonRider.png
new file mode 100644
index 0000000..681af75
--- /dev/null
+++ b/V3/Content/Sources/SkeletonRider.png
Binary files differ
diff --git a/V3/Content/Sources/ZombieWithClub.png b/V3/Content/Sources/ZombieWithClub.png
new file mode 100644
index 0000000..bea8eb3
--- /dev/null
+++ b/V3/Content/Sources/ZombieWithClub.png
Binary files differ
diff --git a/V3/Content/Sources/castle.xcf b/V3/Content/Sources/castle.xcf
new file mode 100644
index 0000000..50a7f8a
--- /dev/null
+++ b/V3/Content/Sources/castle.xcf
Binary files 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
--- /dev/null
+++ b/V3/Content/Sources/fleischklops.blend
Binary files differ
diff --git a/V3/Content/Sources/fleischklops.xcf b/V3/Content/Sources/fleischklops.xcf
new file mode 100644
index 0000000..322f745
--- /dev/null
+++ b/V3/Content/Sources/fleischklops.xcf
Binary files differ
diff --git a/V3/Content/Sources/horse_paint.png b/V3/Content/Sources/horse_paint.png
new file mode 100644
index 0000000..74e4dd5
--- /dev/null
+++ b/V3/Content/Sources/horse_paint.png
Binary files 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
--- /dev/null
+++ b/V3/Content/Sources/horse_paint_sc.png
Binary files differ
diff --git a/V3/Content/Sources/horse_tack.png b/V3/Content/Sources/horse_tack.png
new file mode 100644
index 0000000..4f6a0b8
--- /dev/null
+++ b/V3/Content/Sources/horse_tack.png
Binary files differ
diff --git a/V3/Content/Sources/houses_front.xcf b/V3/Content/Sources/houses_front.xcf
new file mode 100644
index 0000000..680596d
--- /dev/null
+++ b/V3/Content/Sources/houses_front.xcf
Binary files differ
diff --git a/V3/Content/Sources/houses_rear.xcf b/V3/Content/Sources/houses_rear.xcf
new file mode 100644
index 0000000..d711b47
--- /dev/null
+++ b/V3/Content/Sources/houses_rear.xcf
Binary files 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
--- /dev/null
+++ b/V3/Content/Sources/human_construction_set.xcf
Binary files 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
--- /dev/null
+++ b/V3/Content/Sources/human_construction_set_female.xcf
Binary files differ
diff --git a/V3/Content/Sources/king.blend b/V3/Content/Sources/king.blend
new file mode 100644
index 0000000..3bc5379
--- /dev/null
+++ b/V3/Content/Sources/king.blend
Binary files differ
diff --git a/V3/Content/Sources/king_head.png b/V3/Content/Sources/king_head.png
new file mode 100644
index 0000000..9bbc3c9
--- /dev/null
+++ b/V3/Content/Sources/king_head.png
Binary files differ
diff --git a/V3/Content/Sources/necromancer.xcf b/V3/Content/Sources/necromancer.xcf
new file mode 100644
index 0000000..dad43ad
--- /dev/null
+++ b/V3/Content/Sources/necromancer.xcf
Binary files differ
diff --git a/V3/Content/Sources/pathfinder.xcf b/V3/Content/Sources/pathfinder.xcf
new file mode 100644
index 0000000..7833cea
--- /dev/null
+++ b/V3/Content/Sources/pathfinder.xcf
Binary files differ
diff --git a/V3/Content/Sources/prince.blend b/V3/Content/Sources/prince.blend
new file mode 100644
index 0000000..c7c35a8
--- /dev/null
+++ b/V3/Content/Sources/prince.blend
Binary files differ
diff --git a/V3/Content/Sources/prince.xcf b/V3/Content/Sources/prince.xcf
new file mode 100644
index 0000000..14bbcf9
--- /dev/null
+++ b/V3/Content/Sources/prince.xcf
Binary files differ
diff --git a/V3/Content/Sources/selection.xcf b/V3/Content/Sources/selection.xcf
new file mode 100644
index 0000000..bbe3202
--- /dev/null
+++ b/V3/Content/Sources/selection.xcf
Binary files differ
diff --git a/V3/Content/Sources/skeleton_horse.png b/V3/Content/Sources/skeleton_horse.png
new file mode 100644
index 0000000..ed78f4a
--- /dev/null
+++ b/V3/Content/Sources/skeleton_horse.png
Binary files 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
--- /dev/null
+++ b/V3/Content/Sources/the_triumph_of_death.jpg
Binary files differ
diff --git a/V3/Content/Sources/zombie.blend b/V3/Content/Sources/zombie.blend
new file mode 100644
index 0000000..0ae1de3
--- /dev/null
+++ b/V3/Content/Sources/zombie.blend
Binary files differ
diff --git a/V3/Content/Sprites/WhiteRectangle.png b/V3/Content/Sprites/WhiteRectangle.png
new file mode 100644
index 0000000..7d3a386
--- /dev/null
+++ b/V3/Content/Sprites/WhiteRectangle.png
Binary files differ
diff --git a/V3/Content/Sprites/arrows.png b/V3/Content/Sprites/arrows.png
new file mode 100644
index 0000000..61a2db9
--- /dev/null
+++ b/V3/Content/Sprites/arrows.png
Binary files differ
diff --git a/V3/Content/Sprites/buckler.png b/V3/Content/Sprites/buckler.png
new file mode 100644
index 0000000..1253a60
--- /dev/null
+++ b/V3/Content/Sprites/buckler.png
Binary files differ
diff --git a/V3/Content/Sprites/buckler_female.png b/V3/Content/Sprites/buckler_female.png
new file mode 100644
index 0000000..3dd42a1
--- /dev/null
+++ b/V3/Content/Sprites/buckler_female.png
Binary files differ
diff --git a/V3/Content/Sprites/chain.png b/V3/Content/Sprites/chain.png
new file mode 100644
index 0000000..375f887
--- /dev/null
+++ b/V3/Content/Sprites/chain.png
Binary files differ
diff --git a/V3/Content/Sprites/chain_female.png b/V3/Content/Sprites/chain_female.png
new file mode 100644
index 0000000..e3b9c59
--- /dev/null
+++ b/V3/Content/Sprites/chain_female.png
Binary files differ
diff --git a/V3/Content/Sprites/cloth.png b/V3/Content/Sprites/cloth.png
new file mode 100644
index 0000000..3787867
--- /dev/null
+++ b/V3/Content/Sprites/cloth.png
Binary files differ
diff --git a/V3/Content/Sprites/cloth_female.png b/V3/Content/Sprites/cloth_female.png
new file mode 100644
index 0000000..f4d68b8
--- /dev/null
+++ b/V3/Content/Sprites/cloth_female.png
Binary files differ
diff --git a/V3/Content/Sprites/cloud.png b/V3/Content/Sprites/cloud.png
new file mode 100644
index 0000000..1e20701
--- /dev/null
+++ b/V3/Content/Sprites/cloud.png
Binary files differ
diff --git a/V3/Content/Sprites/ellipse.png b/V3/Content/Sprites/ellipse.png
new file mode 100644
index 0000000..c3e0c2c
--- /dev/null
+++ b/V3/Content/Sprites/ellipse.png
Binary files differ
diff --git a/V3/Content/Sprites/fleischklops.png b/V3/Content/Sprites/fleischklops.png
new file mode 100644
index 0000000..b040c76
--- /dev/null
+++ b/V3/Content/Sprites/fleischklops.png
Binary files differ
diff --git a/V3/Content/Sprites/fog.png b/V3/Content/Sprites/fog.png
new file mode 100644
index 0000000..abb5572
--- /dev/null
+++ b/V3/Content/Sprites/fog.png
Binary files differ
diff --git a/V3/Content/Sprites/head.png b/V3/Content/Sprites/head.png
new file mode 100644
index 0000000..ff497fa
--- /dev/null
+++ b/V3/Content/Sprites/head.png
Binary files differ
diff --git a/V3/Content/Sprites/head_bald.png b/V3/Content/Sprites/head_bald.png
new file mode 100644
index 0000000..51796a4
--- /dev/null
+++ b/V3/Content/Sprites/head_bald.png
Binary files differ
diff --git a/V3/Content/Sprites/head_chain.png b/V3/Content/Sprites/head_chain.png
new file mode 100644
index 0000000..9565715
--- /dev/null
+++ b/V3/Content/Sprites/head_chain.png
Binary files 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
--- /dev/null
+++ b/V3/Content/Sprites/head_chain_female.png
Binary files differ
diff --git a/V3/Content/Sprites/head_female.png b/V3/Content/Sprites/head_female.png
new file mode 100644
index 0000000..3849fae
--- /dev/null
+++ b/V3/Content/Sprites/head_female.png
Binary files differ
diff --git a/V3/Content/Sprites/head_plate.png b/V3/Content/Sprites/head_plate.png
new file mode 100644
index 0000000..5c7f5b7
--- /dev/null
+++ b/V3/Content/Sprites/head_plate.png
Binary files 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
--- /dev/null
+++ b/V3/Content/Sprites/head_plate_female.png
Binary files differ
diff --git a/V3/Content/Sprites/king.png b/V3/Content/Sprites/king.png
new file mode 100644
index 0000000..18b5ea7
--- /dev/null
+++ b/V3/Content/Sprites/king.png
Binary files differ
diff --git a/V3/Content/Sprites/longsword.png b/V3/Content/Sprites/longsword.png
new file mode 100644
index 0000000..7e12f43
--- /dev/null
+++ b/V3/Content/Sprites/longsword.png
Binary files differ
diff --git a/V3/Content/Sprites/longsword_female.png b/V3/Content/Sprites/longsword_female.png
new file mode 100644
index 0000000..34f4480
--- /dev/null
+++ b/V3/Content/Sprites/longsword_female.png
Binary files differ
diff --git a/V3/Content/Sprites/necromancer.png b/V3/Content/Sprites/necromancer.png
new file mode 100644
index 0000000..65258d5
--- /dev/null
+++ b/V3/Content/Sprites/necromancer.png
Binary files differ
diff --git a/V3/Content/Sprites/necromancer_female.png b/V3/Content/Sprites/necromancer_female.png
new file mode 100644
index 0000000..6d34095
--- /dev/null
+++ b/V3/Content/Sprites/necromancer_female.png
Binary files differ
diff --git a/V3/Content/Sprites/nude.png b/V3/Content/Sprites/nude.png
new file mode 100644
index 0000000..88f1588
--- /dev/null
+++ b/V3/Content/Sprites/nude.png
Binary files differ
diff --git a/V3/Content/Sprites/nude_female.png b/V3/Content/Sprites/nude_female.png
new file mode 100644
index 0000000..fdd5b33
--- /dev/null
+++ b/V3/Content/Sprites/nude_female.png
Binary files differ
diff --git a/V3/Content/Sprites/plate.png b/V3/Content/Sprites/plate.png
new file mode 100644
index 0000000..f4d49c8
--- /dev/null
+++ b/V3/Content/Sprites/plate.png
Binary files differ
diff --git a/V3/Content/Sprites/plate_female.png b/V3/Content/Sprites/plate_female.png
new file mode 100644
index 0000000..570afff
--- /dev/null
+++ b/V3/Content/Sprites/plate_female.png
Binary files differ
diff --git a/V3/Content/Sprites/prince.png b/V3/Content/Sprites/prince.png
new file mode 100644
index 0000000..9a8e5d9
--- /dev/null
+++ b/V3/Content/Sprites/prince.png
Binary files differ
diff --git a/V3/Content/Sprites/selection.png b/V3/Content/Sprites/selection.png
new file mode 100644
index 0000000..4ce0e93
--- /dev/null
+++ b/V3/Content/Sprites/selection.png
Binary files differ
diff --git a/V3/Content/Sprites/shield.png b/V3/Content/Sprites/shield.png
new file mode 100644
index 0000000..a5b1068
--- /dev/null
+++ b/V3/Content/Sprites/shield.png
Binary files differ
diff --git a/V3/Content/Sprites/shield_female.png b/V3/Content/Sprites/shield_female.png
new file mode 100644
index 0000000..d4b074b
--- /dev/null
+++ b/V3/Content/Sprites/shield_female.png
Binary files differ
diff --git a/V3/Content/Sprites/shortsword.png b/V3/Content/Sprites/shortsword.png
new file mode 100644
index 0000000..e10adf8
--- /dev/null
+++ b/V3/Content/Sprites/shortsword.png
Binary files differ
diff --git a/V3/Content/Sprites/shortsword_female.png b/V3/Content/Sprites/shortsword_female.png
new file mode 100644
index 0000000..d1f097e
--- /dev/null
+++ b/V3/Content/Sprites/shortsword_female.png
Binary files differ
diff --git a/V3/Content/Sprites/skeleton.png b/V3/Content/Sprites/skeleton.png
new file mode 100644
index 0000000..09d6464
--- /dev/null
+++ b/V3/Content/Sprites/skeleton.png
Binary files differ
diff --git a/V3/Content/Sprites/skeleton_archer.png b/V3/Content/Sprites/skeleton_archer.png
new file mode 100644
index 0000000..5bdbc02
--- /dev/null
+++ b/V3/Content/Sprites/skeleton_archer.png
Binary files differ
diff --git a/V3/Content/Sprites/skeleton_elite.png b/V3/Content/Sprites/skeleton_elite.png
new file mode 100644
index 0000000..982c031
--- /dev/null
+++ b/V3/Content/Sprites/skeleton_elite.png
Binary files differ
diff --git a/V3/Content/Sprites/skeleton_horse.png b/V3/Content/Sprites/skeleton_horse.png
new file mode 100644
index 0000000..e0fc808
--- /dev/null
+++ b/V3/Content/Sprites/skeleton_horse.png
Binary files differ
diff --git a/V3/Content/Sprites/skeleton_rider.png b/V3/Content/Sprites/skeleton_rider.png
new file mode 100644
index 0000000..681af75
--- /dev/null
+++ b/V3/Content/Sprites/skeleton_rider.png
Binary files differ
diff --git a/V3/Content/Sprites/staff.png b/V3/Content/Sprites/staff.png
new file mode 100644
index 0000000..0200876
--- /dev/null
+++ b/V3/Content/Sprites/staff.png
Binary files differ
diff --git a/V3/Content/Sprites/staff_female.png b/V3/Content/Sprites/staff_female.png
new file mode 100644
index 0000000..3a526d5
--- /dev/null
+++ b/V3/Content/Sprites/staff_female.png
Binary files differ
diff --git a/V3/Content/Sprites/zombie.png b/V3/Content/Sprites/zombie.png
new file mode 100644
index 0000000..a68091a
--- /dev/null
+++ b/V3/Content/Sprites/zombie.png
Binary files differ
diff --git a/V3/Content/Sprites/zombie_club.png b/V3/Content/Sprites/zombie_club.png
new file mode 100644
index 0000000..bea8eb3
--- /dev/null
+++ b/V3/Content/Sprites/zombie_club.png
Binary files differ
diff --git a/V3/Content/Textures/EmptyPixel.png b/V3/Content/Textures/EmptyPixel.png
new file mode 100644
index 0000000..626a832
--- /dev/null
+++ b/V3/Content/Textures/EmptyPixel.png
Binary files differ
diff --git a/V3/Content/Textures/castle.png b/V3/Content/Textures/castle.png
new file mode 100644
index 0000000..e19dd45
--- /dev/null
+++ b/V3/Content/Textures/castle.png
Binary files differ
diff --git a/V3/Content/Textures/grassland.png b/V3/Content/Textures/grassland.png
new file mode 100644
index 0000000..0a56056
--- /dev/null
+++ b/V3/Content/Textures/grassland.png
Binary files differ
diff --git a/V3/Content/Textures/grassland_trees.png b/V3/Content/Textures/grassland_trees.png
new file mode 100644
index 0000000..b2bced3
--- /dev/null
+++ b/V3/Content/Textures/grassland_trees.png
Binary files differ
diff --git a/V3/Content/Textures/grassland_water.png b/V3/Content/Textures/grassland_water.png
new file mode 100644
index 0000000..2083506
--- /dev/null
+++ b/V3/Content/Textures/grassland_water.png
Binary files differ
diff --git a/V3/Content/Textures/houses_front.png b/V3/Content/Textures/houses_front.png
new file mode 100644
index 0000000..94513d4
--- /dev/null
+++ b/V3/Content/Textures/houses_front.png
Binary files differ
diff --git a/V3/Content/Textures/houses_rear.png b/V3/Content/Textures/houses_rear.png
new file mode 100644
index 0000000..64012e1
--- /dev/null
+++ b/V3/Content/Textures/houses_rear.png
Binary files 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
--- /dev/null
+++ b/V3/Content/Textures/medieval_building_tiles.png
Binary files differ
diff --git a/V3/Content/Textures/pathfinder.png b/V3/Content/Textures/pathfinder.png
new file mode 100644
index 0000000..ae86dfb
--- /dev/null
+++ b/V3/Content/Textures/pathfinder.png
Binary files 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
+{
+ /// <summary>
+ /// A debug level that can be set by the player.
+ /// </summary>
+ public enum DebugMode
+ {
+ /// <summary>
+ /// Disable all debug utils.
+ /// </summary>
+ Off,
+ /// <summary>
+ /// Show the FPS counter.
+ /// </summary>
+ Fps,
+ /// <summary>
+ /// Show all debug information.
+ /// </summary>
+ 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
+{
+ /// <summary>
+ /// Stores the current state of the game (the data that must be stored in
+ /// a save game). All members should be public and serializable.
+ /// </summary>
+ [Serializable]
+ public sealed class GameState
+ {
+ public List<CreatureData> mCreatures = new List<CreatureData>();
+ public List<Rectangle> mFog = new List<Rectangle>();
+ 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<Vector2> 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
+{
+ /// <summary>
+ /// Stores the current game state.
+ /// </summary>
+ public interface IGameStateManager
+ {
+ /// <summary>
+ /// Stores the current game state and returns it.
+ /// </summary>
+ /// <returns>the current game state</returns>
+ GameState GetGameState();
+
+ /// <summary>
+ /// Restores the given game state.
+ /// </summary>
+ /// <param name="gameState">the game state to restore</param>
+ 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
+{
+ /// <summary>
+ /// Handles the storing and loading of game options to the hard disk.
+ /// </summary>
+ public interface IOptionsManager
+ {
+ /// <summary>
+ /// The current options.
+ /// </summary>
+ Options Options { get; }
+
+ /// <summary>
+ /// Saves the current options to the hard disk.
+ /// </summary>
+ 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
+{
+ /// <summary>
+ /// Provides access to the default applications path, i. e. the
+ /// directories where save games, achievements and other persistent data
+ /// can be stored.
+ /// </summary>
+ public interface IPathManager
+ {
+ /// <summary>
+ /// The base directory for persistent application data.
+ /// </summary>
+ string AppDirectory { get; }
+
+ /// <summary>
+ /// The directory for save games.
+ /// </summary>
+ string SaveGameDirectory { get; }
+
+ /// <summary>
+ /// The file to store the options in.
+ /// </summary>
+ string OptionsFile { get; }
+
+ /// <summary>
+ /// Creates the application directories that do not already exist.
+ /// </summary>
+ 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
+{
+ /// <summary>
+ /// Stores a game state with some metadata.
+ /// </summary>
+ public interface ISaveGame : IComparable<ISaveGame>
+ {
+ /// <summary>
+ /// The creation time of this save game in local time.
+ /// </summary>
+ DateTime Timestamp { get; set; }
+
+ /// <summary>
+ /// The compability version of this save game.
+ /// </summary>
+ int Version { get; set; }
+
+ /// <summary>
+ /// The data stored in this save game.
+ /// </summary>
+ 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
+{
+ /// <summary>
+ /// Stores and manages the game state in save games.
+ /// </summary>
+ public interface ISaveGameManager
+ {
+ /// <summary>
+ /// Creates and persists a new save game of the given data with the
+ /// title.
+ /// </summary>
+ /// <param name="gameState">the data to store</param>
+ void CreateSaveGame(GameState gameState);
+
+ /// <summary>
+ /// Loads all available save games and returns them ordered by the
+ /// creation date.
+ /// </summary>
+ /// <returns>a list of all available save games, orderd by creation
+ /// data</returns>
+ List<ISaveGame> 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
+{
+ /// <summary>
+ /// Default implementation of IGameStateManager.
+ /// </summary>
+ // 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;
+ }
+
+ /// <summary>
+ /// Restores the given game state.
+ /// </summary>
+ 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;
+ }
+
+ /// <summary>
+ /// Restores the given game state.
+ /// </summary>
+ /// <param name="gameState">the game state to restore</param>
+ public void LoadGameState(GameState gameState)
+ {
+ mObjectsManager.Clear();
+ mObjectsManager.ImportMapObjects(mMapManager.GetObjects());
+ var creatures = new Dictionary<int, ICreature>();
+
+ // 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
+{
+ /// <summary>
+ /// Default implementation of IOptionsManager.
+ /// </summary>
+ // ReSharper disable once ClassNeverInstantiated.Global
+ internal sealed class OptionsManager : IOptionsManager, IInitializable
+ {
+ /// <summary>
+ /// The current options.
+ /// </summary>
+ public Options Options { get; private set; }
+
+ private readonly IPathManager mPathManager;
+ private readonly XmlSerializer mSerializer = new XmlSerializer(typeof(Options));
+
+ /// <summary>
+ /// Creates a new OptionsManager.
+ /// </summary>
+ public OptionsManager(IPathManager pathManager)
+ {
+ mPathManager = pathManager;
+ }
+
+ public void Initialize()
+ {
+ Options = LoadOptions();
+ }
+
+ /// <summary>
+ /// Saves the current options to the hard disk.
+ /// </summary>
+ 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 {
+ /// <summary>
+ /// Default implementation of IPathManager.
+ /// </summary>
+ // ReSharper disable once ClassNeverInstantiated.Global
+ internal sealed class PathManager : IPathManager
+ {
+ /// <summary>
+ /// The base directory for persistent application data.
+ /// </summary>
+ public string AppDirectory { get; }
+
+ /// <summary>
+ /// The file to store the options in.
+ /// </summary>
+ public string OptionsFile { get; }
+
+ /// <summary>
+ /// The directory for save games.
+ /// </summary>
+ public string SaveGameDirectory { get; }
+
+ /// <summary>
+ /// Creates a new path manager and initializes the paths, but does not
+ /// create the directories if they don’t already exist.
+ /// </summary>
+ public PathManager()
+ {
+ var localAppDir = Environment.GetFolderPath(Environment.SpecialFolder.LocalApplicationData);
+ AppDirectory = $"{localAppDir}/V3";
+ SaveGameDirectory = $"{AppDirectory}/SaveGames";
+ OptionsFile = $"{AppDirectory}/Options.xml";
+ }
+
+ /// <summary>
+ /// Creates the application directories that do not already exist.
+ /// </summary>
+ 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.
+
+ /// <summary>
+ /// A save game that has a timestamp and a title, and that can store
+ /// the game state.
+ /// </summary>
+ [Serializable]
+ public sealed class SaveGame : ISaveGame
+ {
+ /// <summary>
+ /// The creation time of this save game in local time.
+ /// </summary>
+ public DateTime Timestamp { get; set; }
+
+ /// <summary>
+ /// The compability version of this save game.
+ /// </summary>
+ public int Version { get; set; }
+
+ /// <summary>
+ /// The data stored in this save game.
+ /// </summary>
+ public GameState GameState { get; set; }
+
+ /// <summary>
+ /// Empty constructor for serialization.
+ /// </summary>
+ private SaveGame()
+ {
+ }
+
+ /// <summary>
+ /// Creates a new save game from the given data.
+ /// </summary>
+ /// <param name="timestamp">the creation time of the save game</param>
+ /// <param name="version">the compability version of the save game</param>
+ /// <param name="gameState">the game state to store in the save game</param>
+ internal SaveGame(DateTime timestamp, int version, GameState gameState)
+ {
+ Timestamp = timestamp;
+ Version = version;
+ GameState = gameState;
+ }
+
+ /// <summary>
+ /// Compares this save game object to another save game object based
+ /// on the creation time.
+ /// </summary>
+ /// <param name="saveGame">the save game to compare this save game
+ /// with</param>
+ /// <returns>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</returns>
+ 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
+{
+ /// <summary>
+ /// Default implementation if ISaveGameManager.
+ /// </summary>
+ // 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));
+
+ /// <summary>
+ /// Creates a new SaveGameManager. The save game directory must already
+ /// be created.
+ /// </summary>
+ public SaveGameManager(IPathManager pathManager)
+ {
+ mPathManager = pathManager;
+ }
+
+ /// <summary>
+ /// Creates and persists a new save game of the given data with the
+ /// title.
+ /// </summary>
+ /// <param name="gameState">the data to store</param>
+ 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();
+ }
+
+ /// <summary>
+ /// Loads all available save games and returns them ordered by the
+ /// creation date.
+ /// </summary>
+ /// <returns>a list of all available save games, orderd by creation
+ /// data</returns>
+ public List<ISaveGame> GetSaveGames()
+ {
+ var saveGames = new List<ISaveGame>();
+ 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
+{
+ /// <summary>
+ /// The graphics options.
+ /// </summary>
+ [Serializable]
+ public sealed class Options
+ {
+ /// <summary>
+ /// All available screen resolutions.
+ /// </summary>
+ public static List<Point> Resolutions { get; } = new List<Point>
+ {
+ 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)
+ };
+
+ /// <summary>
+ /// All available camera types.
+ /// </summary>
+ public static List<CameraType> CameraTypes { get; } =
+ Enum.GetValues(typeof (CameraType)).Cast<CameraType>().ToList();
+
+ /// <summary>
+ /// All available debug modes.
+ /// </summary>
+ public static List<DebugMode> DebugModes { get; } =
+ Enum.GetValues(typeof (DebugMode)).Cast<DebugMode>().ToList();
+
+ /// <summary>
+ /// All available volume settings.
+ /// </summary>
+ public static List<int> Volumes { get; } = new List<int>()
+ {
+ 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;
+
+ /// <summary>
+ /// The current screen resolution.
+ /// </summary>
+ public Point Resolution { get; set; } = sDefaultResolution;
+
+ /// <summary>
+ /// True if the game should be run in full screen, otherwise false.
+ /// </summary>
+ public bool IsFullScreen { get; set; } = sDefaultIsFullScreen;
+
+ /// <summary>
+ /// The current debug mode.
+ /// </summary>
+ public DebugMode DebugMode { get; set; } = sDefaultDebugMode;
+
+ /// <summary>
+ /// The current camera type.
+ /// </summary>
+ public CameraType CameraType { get; set; } = sDefaultCameraType;
+
+ /// <summary>
+ /// True if the sound is muted, otherwise false.
+ /// </summary>
+ public bool IsMuted { get; set; } = sDefaultIsMuted;
+
+ /// <summary>
+ /// The volume to use for the sound (if the sound is not muted), range
+ /// 0 .. 100.
+ /// </summary>
+ public int Volume { get; set; } = sDefaultVolume;
+
+ /// <summary>
+ /// Returns the effective volume with regard to the mute and volume
+ /// settings.
+ /// </summary>
+ /// <returns>the effective volume that should be used for sound</returns>
+ 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<Texture2D>("Effects/" + TextureFile);
+ mSpritesPerRow = mTexture.Width / SpriteSize.X;
+ mTotalSprites = mSpritesPerRow * (mTexture.Height / SpriteSize.Y);
+ if (SoundFile.Length != 0)
+ {
+ mSoundEffect = contentManager.Load<SoundEffect>("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
+{
+ /// <summary>
+ /// A round explosion of blood.
+ /// </summary>
+ 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
+{
+ /// <summary>
+ /// A small fountain of blood.
+ /// </summary>
+ 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<IEffect> mActiveEffects = new List<IEffect>();
+
+ public EffectsManager(ContentManager contentManager, IOptionsManager optionsManager)
+ {
+ mContentManager = contentManager;
+ mOptionsManager = optionsManager;
+ }
+
+ public void Update(GameTime gameTime)
+ {
+ var doneEffects = new List<IEffect>();
+ 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
+{
+ /// <summary>
+ /// A large explosion with sound.
+ /// </summary>
+ 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
+{
+ /// <summary>
+ /// Interface for a single effect.
+ /// </summary>
+ public interface IEffect
+ {
+ /// <summary>
+ /// Is the effect playing at the moment?
+ /// </summary>
+ bool IsPlaying { get; }
+
+ /// <summary>
+ /// Play the specific effect once, do not loop.
+ /// </summary>
+ /// <param name="position">Position where effect should be played. Points to the middle of the effect animation.</param>
+ /// <param name="size">Size of the effect.</param>
+ /// <param name="optionsManager">For checking the volume of the sound if there is one.</param>
+ void PlayOnce(Point position, Point size, IOptionsManager optionsManager);
+
+ /// <summary>
+ /// Update the effect.
+ /// </summary>
+ /// <param name="gameTime">Game time used for checking animation duration.</param>
+ void Update(GameTime gameTime);
+
+ /// <summary>
+ /// Draw the effect.
+ /// </summary>
+ /// <param name="spriteBatch">Sprite batch used.</param>
+ void Draw(SpriteBatch spriteBatch);
+
+ /// <summary>
+ /// Load graphics and possibly sound for the effect.
+ /// </summary>
+ /// <param name="contentManager">Content manager used.</param>
+ 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
+{
+ /// <summary>
+ /// Interface for managing visual effects like explosions and stuff.
+ /// </summary>
+ public interface IEffectsManager
+ {
+ /// <summary>
+ /// Update all effects.
+ /// </summary>
+ /// <param name="gameTime">Game time used for calculation effects duration.</param>
+ void Update(GameTime gameTime);
+
+ /// <summary>
+ /// Draw all effects.
+ /// </summary>
+ /// <param name="spriteBatch">Sprite batch used.</param>
+ void Draw(SpriteBatch spriteBatch);
+
+ /// <summary>
+ /// Play an effect once, then delete it.
+ /// </summary>
+ /// <param name="effect">Which effect to play.</param>
+ /// <param name="position">Position where effect should be played. Points to the middle of the effect animation.</param>
+ /// <param name="size">Size of the effect.</param>
+ 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
+{
+ /// <summary>
+ /// A large ring of smoke, spreading over some area.
+ /// </summary>
+ 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
+{
+ /// <summary>
+ /// A medium sized ring of smoke, spreading over some area.
+ /// </summary>
+ [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
+{
+ /// <summary>
+ /// A small ring of smoke, spreading over some area.
+ /// </summary>
+ 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
--- /dev/null
+++ b/V3/Icon.ico
Binary files 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
+{
+ /// <summary>
+ /// 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.
+ /// </summary>
+ public interface IInputManager
+ {
+ /// <summary>
+ /// The key events that were generated during the last update. Reset
+ /// in the next update.
+ /// </summary>
+ ICollection<IKeyEvent> KeyEvents { get; }
+
+ /// <summary>
+ /// The mouse events that were generated during the last update. Reset in
+ /// the next update.
+ /// </summary>
+ ICollection<IMouseEvent> MouseEvents { get; }
+
+ /// <summary>
+ /// 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.
+ /// </summary>
+ 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
+{
+ /// <summary>
+ /// An event that is triggered if a key is pressed or released on the
+ /// keyboard.
+ /// </summary>
+ public interface IKeyEvent
+ {
+ /// <summary>
+ /// The key that was pressed or released.
+ /// </summary>
+ Keys Key { get; }
+ /// <summary>
+ /// The type of the event (key pressed or released?).
+ /// </summary>
+ 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
+{
+ /// <summary>
+ /// An event that is sent when a mouse button is pressed or released.
+ /// </summary>
+ public interface IMouseEvent
+ {
+ /// <summary>
+ /// The mouse button that was pressed or released.
+ /// </summary>
+ MouseButton MouseButton { get; }
+ /// <summary>
+ /// The state of the mouse button (pressed or released?).
+ /// </summary>
+ ButtonState ButtonState { get; }
+ /// <summary>
+ /// The position where the mouse button was pressed the last time.
+ /// </summary>
+ Point PositionPressed { get; }
+ /// <summary>
+ /// The position where the mouse button was released if this is a
+ /// release event, null otherwise.
+ /// </summary>
+ Point? PositionReleased { get; }
+ /// <summary>
+ /// True if PositionReleased is a valid on-screen position, otherwise
+ /// false.
+ /// </summary>
+ 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
+{
+ /// <summary>
+ /// Handles mouse events.
+ /// </summary>
+ public interface IMouseEventHandler
+ {
+ /// <summary>
+ /// Handle the given mouse event, if applicable.
+ /// </summary>
+ /// <param name="mouseEvent">the mouse event to handle</param>
+ 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
+{
+ /// <summary>
+ /// 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.
+ /// </summary>
+ // ReSharper disable once ClassNeverInstantiated.Global
+ internal sealed class InputManager : IInputManager, IInitializable
+ {
+ /// <summary>
+ /// The key events that were generated during the last update. Reset
+ /// in the next update.
+ /// </summary>
+ public ICollection<IKeyEvent> KeyEvents { get; } = new HashSet<IKeyEvent>();
+ /// <summary>
+ /// The mouse events that were generated during the last update. Reset in
+ /// the next update.
+ /// </summary>
+ public ICollection<IMouseEvent> MouseEvents { get; } = new HashSet<IMouseEvent>();
+
+ private static readonly ICollection<Keys> sWatchedKeys = new List<Keys> { 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<MouseButton> sWatchedButtons = new List<MouseButton> { MouseButton.Left, MouseButton.Right, MouseButton.Middle };
+
+ private readonly GraphicsDeviceManager mGraphicsDeviceManager;
+
+ private readonly IDictionary<Keys, KeyState> mKeyStates = new Dictionary<Keys, KeyState>();
+
+ private readonly IDictionary<MouseButton, ButtonState> mButtonStates = new Dictionary<MouseButton, ButtonState>();
+
+ private readonly IDictionary<MouseButton, Point?> mButtonPositions = new Dictionary<MouseButton, Point?>();
+
+ /// <summary>
+ /// Creates a new input manager.
+ /// </summary>
+ 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);
+ }
+ }
+
+ /// <summary>
+ /// 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.
+ /// </summary>
+ 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
+{
+ /// <summary>
+ /// Default implementation of an event that is triggered if a key is
+ /// pressed or released on the keyboard.
+ /// </summary>
+ internal sealed class KeyEvent : IKeyEvent
+ {
+ /// <summary>
+ /// The key that was pressed or released.
+ /// </summary>
+ public Keys Key { get; }
+ /// <summary>
+ /// The type of the event (key pressed or released?).
+ /// </summary>
+ public KeyState KeyState { get; }
+
+ /// <summary>
+ /// Creates a new key event with the given data.
+ /// </summary>
+ /// <param name="key">the key that was pressed or released</param>
+ /// <param name="keyState">the type of the event (presesd or
+ /// released?)</param>
+ 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
+{
+ /// <summary>
+ /// Default implementation of an event that is sent when a mouse button is
+ /// pressed or released.
+ /// </summary>
+ internal sealed class MouseEvent : IMouseEvent
+ {
+ /// <summary>
+ /// The mouse button that was pressed or released.
+ /// </summary>
+ public MouseButton MouseButton { get; }
+ /// <summary>
+ /// The state of the mouse button (pressed or released?).
+ /// </summary>
+ public ButtonState ButtonState { get; }
+ /// <summary>
+ /// The position where the mouse button was pressed the last time.
+ /// </summary>
+ public Point PositionPressed { get; }
+ /// <summary>
+ /// The position where the mouse button was released if this is a
+ /// release event, null otherwise.
+ /// </summary>
+ public Point? PositionReleased { get; }
+ /// <summary>
+ /// True if PositionReleased is a valid on-screen position, otherwise
+ /// false.
+ /// </summary>
+ public bool ReleasedOnScreen { get; }
+
+ /// <summary>
+ /// Creates a new mouse event with the given data.
+ /// </summary>
+ /// <param name="mouseButton">the mouse button that was pressed or
+ /// released</param>
+ /// <param name="buttonState">the type of the event (pressed or
+ /// released?)</param>
+ /// <param name="positionPressed">the position of the last press of
+ /// the button</param>
+ /// <param name="positionReleased">the position of the release of the
+ /// button if this is a release event, or null otherwise</param>
+ /// <param name="releasedOnScreen">true if positionReleased is a valid
+ /// on-screen position.</param>
+ 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
+{
+ /// <summary>
+ /// A drawable map layer usually created from a Tiled map file.
+ /// </summary>
+ 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<IGameObject> mTextureObjects = new List<IGameObject>();
+ private readonly int[,] mTileArray;
+ private readonly SortedList<int, Tileset> mTilesets;
+
+ protected AbstractLayer(int tileWidth,
+ int tileHeight,
+ int mapWidth,
+ int mapHeight,
+ int[,] tileArray,
+ SortedList<int, Tileset> 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.");
+ }
+ }
+
+ /// <summary>
+ /// Create the map objects according to the given map array.
+ /// </summary>
+ 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;
+ }
+
+ /// <summary>
+ /// Loads the image files needed for drawing the tilesets.
+ /// </summary>
+ /// <param name="contentManager">Content manager used for loading the ressources.</param>
+ public void LoadContent(ContentManager contentManager)
+ {
+ mTextureObjects.ForEach(o => o.LoadContent(contentManager));
+ }
+
+ /// <summary>
+ /// 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.
+ /// </summary>
+ /// <param name="spriteBatch">Sprite batch used.</param>
+ /// <param name="camera">Needed to tell which objects of the map are looked upon.</param>
+ 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);
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// Extract a collision grid from the map layer. Used in pathfinding.
+ /// </summary>
+ /// <returns>A two dimensional boolean collision grid.</returns>
+ 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<IGameObject> 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
+ }
+
+ /// <summary>
+ /// Holding area data of the map. Later used for generating enemies.
+ /// </summary>
+ 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;
+
+ /// <summary>
+ /// Gets the area type.
+ /// </summary>
+ public AreaType Type => mType;
+
+ /// <summary>
+ /// Creates a new area for generating population.
+ /// </summary>
+ /// <param name="type">Which type of area. Determines which population is spawned.</param>
+ /// <param name="data">The size and position of the area.</param>
+ /// <param name="density">The population density. Together with chance.</param>
+ /// <param name="chance">The chance that a creature is actually created.</param>
+ /// <param name="name">Name of the area as shown in the game.</param>
+ // 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;
+ }
+
+ /// <summary>
+ /// Creates the initial population for this area.
+ /// </summary>
+ /// <param name="creatureFactory">The factory used for creating creatures.</param>
+ /// <param name="pathfinder">Used for checking collisions when creating population.</param>
+ /// <returns></returns>
+ public List<ICreature> GetPopulation(CreatureFactory creatureFactory, Pathfinder pathfinder)
+ {
+ var population = new List<ICreature>();
+ 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;
+ }
+
+ /// <summary>
+ /// Is a given creature standing in the area?
+ /// </summary>
+ /// <param name="creature">Check for this creature.</param>
+ /// <returns></returns>
+ 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
+{
+ /// <summary>
+ /// Constants for describing the size of the cells of the collision grid.
+ /// Important for pathfinding.
+ /// </summary>
+ 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
+{
+ /// <summary>
+ /// The floor of the map consisting of the ground to walk on, grass or water.
+ /// </summary>
+ public sealed class FloorLayer : AbstractLayer
+ {
+ public FloorLayer(int tileWidth, int tileHeight, int mapWidth, int mapHeight, int[,] tileArray, SortedList<int, Tileset> 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<Rectangle> mFogRectangle = new List<Rectangle>();
+
+ /// <summary>
+ /// Get the size of the map and create an boolean array
+ /// </summary>
+ /// <param name="size">the size of the map</param>
+ public void LoadGrid(Point size)
+ {
+ mMapSize = size;
+ CreateArray();
+ }
+
+ /// <summary>
+ /// An array so save whether the sprites already walked on this area
+ /// </summary>
+ 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));
+ }
+ }
+ }
+
+ /// <summary>
+ /// The position from creatures which can open the fog
+ /// </summary>
+ /// <param name="creature">creatures which are able to open the fog</param>
+ public void Update(ICreature creature)
+ {
+ Ellipse creatureEllipse = new Ellipse(creature.Position, SightRadius, SightRadius);
+ var markedForDeletion = new List<Rectangle>();
+ foreach (var fog in mFogRectangle)
+ {
+ if (!creature.IsDead && creatureEllipse.Contains(fog.Center.ToVector2()))
+ {
+ markedForDeletion.Add(fog);
+ }
+ }
+ foreach (var fogToDelete in markedForDeletion)
+ {
+ mFogRectangle.Remove(fogToDelete);
+ }
+ }
+
+ /// <summary>
+ /// The sprite for the fog
+ /// </summary>
+ /// <param name="content"></param>
+ public void LoadContent(ContentManager content)
+ {
+ mFog = content.Load<Texture2D>("Sprites/cloud");
+ }
+
+ /// <summary>
+ /// Try to draw fog of war efficiently.
+ /// </summary>
+ /// <param name="spriteBatch">Sprite batch used.</param>
+ 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<Rectangle> fog)
+ {
+ mFogRectangle.Clear();
+ mFogRectangle.AddRange(fog);
+ }
+
+ public List<Rectangle> 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
+{
+ /// <summary>
+ /// Manager for loading and drawing game maps. Also holds information about map attributes.
+ /// </summary>
+ [SuppressMessage("ReSharper", "UnusedMember.Global")]
+ public interface IMapManager
+ {
+ /// <summary>
+ /// A list of map areas (rectangle-sized).
+ /// </summary>
+ List<Area> Areas { get; }
+
+ /// <summary>
+ /// Size of the shown map in pixels.
+ /// </summary>
+ Point SizeInPixel { get; }
+ /// <summary>
+ /// Size of the map in tiles. (Some tiles are cut off at the edges.)
+ /// </summary>
+ Point SizeInTiles { get; }
+ /// <summary>
+ /// Size of a single tile in pixels.
+ /// </summary>
+ Point TileSize { get; }
+ /// <summary>
+ /// Number of cells the pathfinding grid consists of.
+ /// </summary>
+ Point PathfindingGridSize { get; }
+ /// <summary>
+ /// Size of a single cell of the pathfinding grid in pixels.
+ /// </summary>
+ Point PathfindingCellSize { get; }
+ /// <summary>
+ /// File name of the loaded map (without suffix).
+ /// </summary>
+ string FileName { get; }
+ /// <summary>
+ /// Efficiently draw the floor layer. Only draw the tiles seen by the camera.
+ /// </summary>
+ /// <param name="spriteBatch"></param>
+ /// <param name="camera"></param>
+ void DrawFloor(SpriteBatch spriteBatch, ICamera camera);
+ /// <summary>
+ /// Load a map file and create the map layers and pathfinding information.
+ /// </summary>
+ /// <param name="fileName">Name of the map file (without suffix).</param>
+ void Load(string fileName);
+ /// <summary>
+ /// Returns all objects in the objects layer.
+ /// </summary>
+ /// <returns>List of all static game objects imported from the map.</returns>
+ List<IGameObject> GetObjects();
+ /// <summary>
+ /// Returns the pathfinding grid for passing to the pathfinder.
+ /// </summary>
+ /// <returns>A grid used for pathfinding.</returns>
+ PathfindingGrid GetPathfindingGrid();
+ /// <summary>
+ /// Efficiently draw the pathfinding grid. For debugging purposes.
+ /// </summary>
+ /// <param name="spriteBatch">Sprite batch used.</param>
+ /// <param name="camera">Current camera for calculating the shown screen.</param>
+ void DrawPathfindingGrid(SpriteBatch spriteBatch, ICamera camera);
+
+ /// <summary>
+ /// Draws the minimap to specified position.
+ /// </summary>
+ /// <param name="spriteBatch">Sprite batch used.</param>
+ /// <param name="position">Where to draw the minimap and which size.</param>
+ void DrawMinimap(SpriteBatch spriteBatch, Rectangle position);
+
+ /// <summary>
+ /// Automatically creates an initial population from the map data and returns it.
+ /// </summary>
+ /// <param name="creatureFactory">Factory for creating creatues.</param>
+ /// <param name="pathfinder">Pathfinder is used for checking collisions when creating creatures.</param>
+ /// <returns>Initial population in a list.</returns>
+ List<ICreature> 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<Area> mAreas;
+ private PathfindingGrid mPathfindingGrid;
+ private readonly ContentManager mContentManager;
+ private readonly GraphicsDeviceManager mGraphicsDeviceManager;
+
+ public List<Area> 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<IGameObject> GetObjects()
+ {
+ return mObjectLayer.ExtractObjects();
+ }
+
+ public List<ICreature> 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
+{
+ /// <summary>
+ /// The map objects which are the same layer as the moving creatutes.
+ /// Buildings, flowers, trees etc.
+ /// </summary>
+ public sealed class ObjectLayer : AbstractLayer
+ {
+ public ObjectLayer(int tileWidth, int tileHeight, int mapWidth, int mapHeight, int[,] tileArray, SortedList<int, Tileset> 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<SearchNode> mOpenList = new List<SearchNode>();
+
+ // List for nodes that are NOT available to search
+ private readonly List<SearchNode> mClosedList = new List<SearchNode>();
+
+ //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<Vector2> FindFinalPath(SearchNode startNode, SearchNode endNode)
+ {
+ int counter = 0;
+
+ if (startNode == endNode)
+ {
+ return new List<Vector2>();
+ }
+
+ 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<Vector2> betaPath = new List<Vector2>();
+
+ // Final path after RayCasting
+ List<Vector2> finalPath = new List<Vector2>();
+
+ // 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<Vector2> FindPath(Vector2 startPoint, Vector2 endPoint)
+ {
+ // Start to find path if startpoint and endpoint are different
+ if (startPoint == endPoint)
+ {
+ return new List<Vector2>();
+ }
+
+ // 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<Vector2>();
+ }
+
+ // 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<Vector2>();
+ }
+
+ // 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
+{
+ /// <summary>
+ /// Tells the pathfinder where you can walk.
+ /// </summary>
+ 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];
+ }
+
+ /// <summary>
+ /// 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.
+ /// </summary>
+ /// <param name="collisionGrid">A grid of the same size as the pathfinding grid.</param>
+ 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.");
+ }
+ }
+
+ /// <summary>
+ /// Load content for visual representation of the pathfinding grid.
+ /// </summary>
+ /// <param name="contentManager">Use this content manager.</param>
+ public void LoadContent(ContentManager contentManager)
+ {
+ mTexture = contentManager.Load<Texture2D>("Textures/pathfinder");
+ //mOnePixelTexture = contentManager.Load<Texture2D>("Sprites/WhiteRectangle");
+ }
+
+ /// <summary>
+ /// A visual representation of the pathfinding grid. Drawn efficiently.
+ /// </summary>
+ /// <param name="spriteBatch">Sprite batch used for drawing.</param>
+ /// <param name="camera">For only drawing on the shown part of the map.</param>
+ 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);
+ }
+ }
+ }
+
+ /// <summary>
+ /// Gets the value at the specified position of the collision array.
+ /// </summary>
+ /// <param name="cellX">Position at the horizontal axis.</param>
+ /// <param name="cellY">Position at the vertical axis.</param>
+ /// <returns>Returns 0 if you can walk at the specified position, 1 otherwise.</returns>
+ 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;
+ }
+
+ /// <summary>
+ /// Draws a small version of the pathfinding grid to the screen.
+ /// Useful for the minimap.
+ /// </summary>
+ /// <param name="spriteBatch">Sprite batch used.</param>
+ /// <param name="position">Where to draw in pixel coordinates and which size. In pixels.</param>
+ 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
+{
+ /// <summary>
+ /// Parser for the tmx format of the Tiled Map Editor.
+ /// Reads XML file and returns corresponding data objects.
+ /// </summary>
+ 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<int, Tileset> TileSets { get; } = new SortedList<int, Tileset>();
+ public List<int[,]> MapLayers { get; } = new List<int[,]>();
+ public List<Area> Areas { get; } = new List<Area>();
+
+ /// <summary>
+ /// Parse the tmx file and hold data in instance properties.
+ /// </summary>
+ 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<string> tilesetAttributes = new List<string>();
+ // 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
+{
+ /// <summary>
+ /// Class for holding information needed of Tilesets. Needed to draw the map.
+ /// </summary>
+ public sealed class Tileset
+ {
+ private const int CellHeight = Constants.CellHeight;
+ private const int CellWidth = Constants.CellWidth;
+
+ /// <summary>
+ /// Name of the tileset, often the filename.
+ /// </summary>
+ public string Name { get; }
+ /// <summary>
+ /// Tile width of each tile in pixel.
+ /// </summary>
+ public int TileWidth { get; }
+ /// <summary>
+ /// Tile height of each tile in pixel.
+ /// </summary>
+ public int TileHeight { get; }
+
+ /// <summary>
+ /// Columns of tiles of the tileset image.
+ /// </summary>
+ public int Columns { get; private set; }
+ /// <summary>
+ /// When tile is drawn, is there an offset needed on the X axis for correct display.
+ /// </summary>
+ public int OffsetX { get; private set; }
+ /// <summary>
+ ///
+ /// When tile is drawn, is there an offset needed on the Y axis for correct display.
+ /// </summary>
+ public int OffsetY { get; private set; }
+ /// <summary>
+ /// 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.
+ /// </summary>
+ public Dictionary<int, bool[,]> 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<int, bool[,]>();
+ }
+
+ /// <summary>
+ /// Add an entry to the collision dictionary for the specific tile.
+ /// </summary>
+ /// <param name="tileId">The tile ID in the tileset.</param>
+ /// <param name="collisionData">The corresponding collision data as string of '0' and '1'.</param>
+ 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
+ {
+ /// <summary>
+ /// Represents the Rectangle if a Quad gets split
+ /// </summary>
+ 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;
+
+ /// <summary>
+ /// The list of each node where the objects in each rectangle are saved
+ /// </summary>
+ private List<IGameObject> mObjectList = new List<IGameObject>();
+ private int Count => ObjectCount();
+
+ /// <summary>
+ /// initialize the Node
+ /// </summary>
+ /// <param name="currentRectangle">the current Rectangle/size of the Node</param>
+ /// <param name="p">the parent of the node</param>
+ 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;
+ }
+
+ /// <summary>
+ /// divided the rectangle in 4 small rectangles locaded in it self
+ /// </summary>
+ 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);
+ }
+ }
+
+ /// <summary>
+ /// 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.
+ /// </summary>
+ /// <param name="item">Type of Creature including their position.</param>
+ 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;
+ }
+ }
+ }
+ }
+
+ /// <summary>
+ /// checks if the Objects in the same Quad are intersecting
+ /// </summary>
+ /// <param name="objectList">list with the objects in the same quad</param>
+ //void CheckCollission(List<AbstractCreature> objectList)
+ void CheckCollission(List<IGameObject> 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;
+ // }
+ // }
+ // }
+ //}
+ }
+
+ /// <summary>
+ /// If collsion is detected the object gets moved away so there is no collision anymore
+ /// </summary>
+ /// <param name="item">the object which collid with another object</param>
+ /// <param name="item2">the other object</param>
+ //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);
+ }
+ }
+
+ /// <summary>
+ /// Clears the QuadTree of all objects, including any objects living in its children.
+ /// </summary>
+ 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;
+ }
+
+ /// <summary>
+ /// Get the total for all objects in this QuadTree, including children.
+ /// </summary>
+ /// <returns>The number of objects contained within this QuadTree and its children.</returns>
+ 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;
+ }
+
+
+ /// <summary>
+ /// 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.
+ /// </summary>
+ /// <param name="item"></param>
+ 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;
+ }
+ }
+
+ /// <summary>
+ /// 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
+ /// </summary>
+ /// <param name="item">Actuell Creature</param>
+ 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);
+ }
+
+ }
+
+ /// <summary>
+ /// If four Subnodes are empty the get deleted
+ /// </summary>
+ 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();
+ }
+
+
+ /// <summary>
+ /// Gibt einem alle Argumente die Innerhalb des rectangles sind zurück in der Liste objectInRecList
+ /// </summary>
+ /// <param name="rectangle">Der Bereich aus dem man alle Objecte haben möchte</param>
+ /// <param name="objectInRecList">Die Liste, in der alle Objekte enthalten sind, die sich im gefragten Rectangle aufhalten</param>
+ /// <returns></returns>
+ public List<IGameObject> GetObjectsInRectangle(Rectangle rectangle, List<IGameObject> 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;
+ }
+
+
+ /// <summary>
+ /// Updates the position of the object in the Quadtree. If they changed their position
+ /// they get deleted and added again at the correct position.
+ /// </summary>
+ public void Update1()
+ {
+ List<IGameObject> copyList = new List<IGameObject>(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();
+ }
+
+ /// <summary>
+ /// Makes the Quadtree visible
+ /// </summary>
+ /// <param name="spriteBatch">to draw the Rectangles</param>
+ /// <param name="texture"></param>
+ 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<Texture2D>("Textures/" + mTextureName);
+ //mOnePixelTexture = contentManager.Load<Texture2D>("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
+{
+ /// <summary>
+ /// Abstract class for deriving all moving objects in the game,
+ /// be it the player, his minions or the enemy.
+ /// </summary>
+ 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);
+ /// <summary>
+ /// Array of sprites for drawing the creature. Can have up to four entries for (ordered): Body, Head, Weapon, Offhand
+ /// </summary>
+ 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<Arrow> mArrowList = new List<Arrow>();
+
+#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; }
+
+ /// <summary>
+ /// Color of the rectangle displayed when creature is selected.
+ /// </summary>
+ 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);
+ }
+
+ /// <summary>
+ /// The specific creature takes damage. If its life falls below zero it dies.
+ /// </summary>
+ /// <param name="damage">Amount of received damage.</param>
+ public void TakeDamage(int damage)
+ {
+ if (Life > 0)
+ {
+ Life -= damage;
+ }
+
+ if (Life <= 0)
+ {
+ Die();
+ }
+ }
+
+ /// <summary>
+ /// Loads content files needed for drawing the creature.
+ /// </summary>
+ /// <param name="contentManager">Content manager used.</param>
+ public void LoadContent(ContentManager contentManager)
+ {
+ Sprite.ForEach(e => e?.Load(contentManager));
+ mOnePixelTexture = contentManager.Load<Texture2D>("Sprites/WhiteRectangle");
+ mSelectionTexture = contentManager.Load<Texture2D>("Sprites/selection");
+#if NO_AUDIO
+#else
+ try
+ {
+ mSoundEffect = contentManager.Load<SoundEffect>("Sounds/walking");
+ mSoundEffectInstance = mSoundEffect.CreateInstance();
+ mSoundEffectHorse = contentManager.Load<SoundEffect>("Sounds/SkeletonHorse");
+ mSoundEffectInstanceHorse = mSoundEffectHorse.CreateInstance();
+ mSoundEffectKnight = contentManager.Load<SoundEffect>("Sounds/Knight");
+ mSoundEffectInstanceKnight = mSoundEffectKnight.CreateInstance();
+ mSoundEffectFight = contentManager.Load<SoundEffect>("Sounds/punch");
+ mSoundEffectInstanceFight = mSoundEffectFight.CreateInstance();
+ mSoundEffectMeatball = contentManager.Load<SoundEffect>("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
+ }
+
+ /// <summary>
+ /// The creature should move to the specified destination if possible.
+ /// </summary>
+ /// <param name="destination">The desired destination.</param>
+ 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<Vector2> randomMoveVector = new List<Vector2>();
+
+
+ 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<IGameObject> defenders = new List<IGameObject>();
+ 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<ICreature> creatures = new List<ICreature>();
+ 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));
+ }
+
+ /// <summary>
+ /// Draw the creature on the screen.
+ /// </summary>
+ /// <param name="spriteBatch">Sprite batch used for drawing.</param>
+ 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);
+ }
+
+ /// <summary>
+ /// Change the equipment/sprite of the creature to something other.
+ /// </summary>
+ /// <param name="equipmentType">Which part of the equipment should be changed.</param>
+ /// <param name="sprite">Which sprite to use instead.</param>
+ 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
+ }
+
+ /// <summary>
+ /// Returns the object instance without modifications.
+ /// </summary>
+ /// <returns>This object.</returns>
+ public virtual IGameObject GetSelf()
+ {
+ return this;
+ }
+
+ public void ResetPosition()
+ {
+ Position = InitialPosition;
+ }
+
+ #region Compute Move Distance
+ /// <summary>
+ /// Returns vector for the moving distance to attack.
+ /// </summary>
+ /// <returns>Vector.</returns>
+ 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;
+ }
+
+ /// <summary>
+ /// Returns synchronized random value.
+ /// </summary>
+ /// <returns>Vector.</returns>
+ /// <param name="min">Lower bound for random value.</param>
+ /// <param name="max">Upper bound +1 for random value.</param>
+ 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);
+ }
+
+ /// <summary>
+ /// Save this creature’s data to a CreatureData object.
+ /// </summary>
+ /// <returns>the CreatureData object with the status of this creature</returns>
+ 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;
+ }
+
+ /// <summary>
+ /// Restore the creature's state from the given data.
+ /// </summary>
+ /// <param name="creatureData">the state of the creature to restore</param>
+ 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();
+ }
+
+ /// <summary>
+ /// Restore the creature's references to other creatures from the given data.
+ /// </summary>
+ /// <param name="data">the state of the creature to restore</param>
+ /// <param name="creatures">the list of all creatures by ID</param>
+ public virtual void LoadReferences(CreatureData data, Dictionary<int, ICreature> 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);
+ }
+
+ /// <summary>
+ /// The moving for arrow
+ /// </summary>
+ public void UpdateArrow()
+ {
+ if (mArrowDraw)
+ mArrowPosition += mDirection * SpeedModifier;
+
+ if (Vector2.Distance(mArrowPosition, mArrowGoal) < 1f * SpeedModifier)
+ mArrowDraw = false;
+ }
+
+ /// <summary>
+ /// Calculates the direction the creature is looking when moving.
+ /// Method copied from PlayerMovement class.
+ /// </summary>
+ 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>(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
+{
+ /// <summary>
+ /// Class for simple peasants which will be transformed into zombies.
+ /// </summary>
+ 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
+{
+ /// <summary>
+ /// A Forge which can be attacked.
+ /// </summary>
+ 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; }
+
+ /// <summary>
+ /// Building takes specific amount of damage. Substracted from Robustness.
+ /// </summary>
+ /// <param name="damage">TakeDamage taken</param>
+ void TakeDamage(int damage);
+
+ /// <summary>
+ /// Building can give a fixed amount of upgrades.
+ /// </summary>
+ 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
+{
+ /// <summary>
+ /// A moving game object.
+ /// </summary>
+ 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; }
+ /// <summary>
+ /// Area where the creature is standing. Used for collisions.
+ /// </summary>
+ /// <summary>
+ /// Where you can click to select the creature.
+ /// </summary>
+ 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; }
+
+ /// <summary>
+ /// Creature takes specific amount of damage. Substracted from Life.
+ /// </summary>
+ /// <param name="damage">TakeDamage taken.</param>
+ void TakeDamage(int damage);
+
+ /// <summary>
+ /// Give command to move to desired destination. Not instant movement.
+ /// </summary>
+ /// <param name="destination">Destination in pixels.</param>
+ void Move (Vector2 destination);
+
+ //void ImportentMove(IGameObject creature);
+
+ /// <summary>
+ /// Draws a static non-animated sprite (for HUD) at specified position.
+ /// </summary>
+ /// <param name="spriteBatch">Sprite batch used for drawing.</param>
+ /// <param name="position">Position where to draw the sprite.</param>
+ void DrawStatic(SpriteBatch spriteBatch, Point position);
+
+ /// <summary>
+ /// Update the creature behaviour and animation.
+ /// </summary>
+ void Update(GameTime gameTime, ICreature playerCharacter,
+ bool rightButtonPressed, Vector2 rightButtonPosition, Quadtree quadtree, ICamera camera);
+
+ /// <summary>
+ /// 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.
+ /// </summary>
+ /// <param name="equipmentType">Which part of the equipment should be changed.</param>
+ /// <param name="sprite">Which sprite to use instead.</param>
+ void ChangeEquipment(EquipmentType equipmentType, ISpriteCreature sprite);
+
+ /// <summary>
+ /// Sets back the position of the creature to its state when created.
+ /// </summary>
+ void ResetPosition();
+
+ /// <summary>
+ /// Plays the specified animation fully, but only once.
+ /// </summary>
+ /// <param name="animation">For which movement state the animation should be played.</param>
+ /// <param name="duration">How long (or how slow) should the animation be?</param>
+ void PlayAnimationOnce(MovementState animation, TimeSpan duration);
+
+ /// <summary>
+ /// Heals the creature. Can not go over MaxLife.
+ /// </summary>
+ /// <param name="amount">How much HP the creature gains.</param>
+ void Heal(int amount);
+
+ /// <summary>
+ /// Creature gets more life and maxlife. Used for testing in Techdemo.
+ /// </summary>
+ /// <param name="modifier">Multiplyier for Life.</param>
+ void Empower(int modifier);
+
+ /// <summary>
+ /// Save this creature’s data to a CreatureData object.
+ /// </summary>
+ /// <returns>the CreatureData object with the status of this creature</returns>
+ CreatureData SaveData();
+
+ /// <summary>
+ /// Restore the creature's state from the given data.
+ /// </summary>
+ /// <param name="data">the state of the creature to restore</param>
+ void LoadData(CreatureData data);
+
+ /// <summary>
+ /// Restore the creature's references to other creatures from the given data.
+ /// </summary>
+ /// <param name="data">the state of the creature to restore</param>
+ /// <param name="creatures">the list of all creatures by ID</param>
+ void LoadReferences(CreatureData data, Dictionary<int, ICreature> 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
+{
+ /// <summary>
+ /// A game object which is placed on the map.
+ /// </summary>
+ public interface IGameObject
+ {
+ Vector2 Position { get; set; }
+
+ /// <summary>
+ /// A unique ID for this game object, with which it can be identified.
+ /// All implementations should use the IdGenerator to generate this ID.
+ /// </summary>
+ int Id { get; }
+
+ /// <summary>
+ /// Draws the game object on the screen.
+ /// </summary>
+ /// <param name="spriteBatch">Sprite batch used for drawing.</param>
+ void Draw(SpriteBatch spriteBatch);
+
+ /// <summary>
+ /// The size of the object.
+ /// </summary>
+ Rectangle BoundaryRectangle { get; }
+
+ /// <summary>
+ /// Loads needed graphics.
+ /// </summary>
+ /// <param name="contentManager">Content manager used. </param>
+ void LoadContent(ContentManager contentManager);
+
+ /// <summary>
+ /// Returns the object instance without modifications.
+ /// </summary>
+ /// <returns>This object.</returns>
+ 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
+{
+ /// <summary>
+ /// Objects manager for all game objects, be is creatures or buildings or even simple landscape objects.
+ /// </summary>
+ public interface IObjectsManager
+ {
+ //***** FOR TESTING PURPOSES!
+ List<ICreature> AddToSelectables { get; }
+ List<ICreature> CreatureList { get; }
+ List<ICreature> UndeadCreatures { get; }
+ //List<ICreature> KingdromCreatures { get; }
+ //List<ICreature> PlebCreatures { get; }
+ //***** NOT FOR TESTING PURPOSES ANYMORE!
+
+ /// <summary>
+ /// Gets the current player character. Usually the necromancer.
+ /// Do not set directly! Use CreatePlayerCharacter() instead!
+ /// </summary>
+ ICreature PlayerCharacter { get; }
+
+ ICreature Boss { get; }
+
+ ICreature Prince { get; }
+
+ Castle Castle { get; }
+
+ /// <summary>
+ /// 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.)
+ /// </summary>
+ /// <param name="mapManager"></param>
+ void Initialize(IMapManager mapManager);
+
+ /// <summary>
+ /// Removes all objects from the object manager.
+ /// </summary>
+ void Clear();
+
+ /// <summary>
+ /// Creates the player character. This should be the first thing you do
+ /// after you created or initialized the objects manager.
+ /// </summary>
+ /// <param name="necromancer"></param>
+ void CreatePlayerCharacter(Necromancer necromancer);
+
+ /// <summary>
+ /// Creates the boss of the level. Game is won if the boss is killed.
+ /// </summary>
+ /// <param name="boss">Some ICreature to kill for winning.</param>
+ void CreateBoss(ICreature boss);
+
+ /// <summary>
+ /// Create the prince, a small boss.
+ /// </summary>
+ /// <param name="prince">Some hard ICreature to kill.</param>
+ void CreatePrince(ICreature prince);
+
+ /// <summary>
+ /// Creates a creature for the game and inserts it in the appropriate data structures.
+ /// </summary>
+ /// <param name="creature"></param>
+ void CreateCreature(ICreature creature);
+
+ /// <summary>
+ /// Removes specified creature from the game.
+ /// </summary>
+ /// <param name="creature">The creature to be removed.</param>
+ void RemoveCreature(ICreature creature);
+
+ /// <summary>
+ /// Draws all currently shown objects on the map.
+ /// </summary>
+ /// <param name="spriteBatch">The sprite batch used.</param>
+ /// <param name="camera">Camera for calculating which objects need to be drawn.</param>
+ void Draw(SpriteBatch spriteBatch, ICamera camera);
+
+ /// <summary>
+ /// Draws a visual representation of the Quadtree. For debugging purposes.
+ /// </summary>
+ /// <param name="spriteBatch"></param>
+ void DrawQuadtree(SpriteBatch spriteBatch);
+
+ /// <summary>
+ /// Update the behaviour of all creatures on the map.
+ /// </summary>
+ /// <param name="gameTime">Current game time.</param>
+ /// <param name="rightButtonPressed">Did the player press the right mouse button?</param>
+ /// <param name="rightButtonPosition">Where is the mouse currently?</param>
+ /// <param name="camera">Camera for checking where to do important updates.</param>
+ void Update(GameTime gameTime, bool rightButtonPressed, Vector2 rightButtonPosition, ICamera camera);
+
+ /// <summary>
+ /// Imports the TextureObjects from the objects map layer for drawing things in the right order.
+ /// </summary>
+ /// <param name="textureObjects"></param>
+ void ImportMapObjects(List<IGameObject> textureObjects);
+
+ /// <summary>
+ /// Get all objects in the given rectangles.
+ /// </summary>
+ /// <param name="rectangle">The rectangle which defines the area of the returnes objects.</param>
+ /// <returns>Game objects in the rectangle.</returns>
+ List<IGameObject> GetObjectsInRectangle(Rectangle rectangle);
+
+ /// <summary>
+ /// Gets all creatures which are in the given ellipse area.
+ /// </summary>
+ /// <param name="ellipse">To check if creature is in ellipse area.</param>
+ /// <returns></returns>
+ List<ICreature> GetCreaturesInEllipse(Ellipse ellipse);
+
+ /// <summary>
+ /// Playing around with some cheating codes.
+ /// </summary>
+ void ExposeTheLiving();
+
+ /// <summary>
+ /// Checks if a creature is standing in a graveyard area.
+ /// </summary>
+ /// <param name="creature">Check for this creature.</param>
+ /// <returns>True when standing in graveyard area.</returns>
+ 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
+{
+ /// <summary>
+ /// Static helper class that generates unique IDs for game objects.
+ /// </summary>
+ // ReSharper disable once ClassNeverInstantiated.Global
+ public sealed class IdGenerator
+ {
+ private static int sCurrentId;
+
+ private static int? sIdOnce;
+
+ private IdGenerator()
+ {
+ throw new NotImplementedException();
+ }
+
+ /// <summary>
+ /// Get an ID for a new game object.
+ /// </summary>
+ /// <returns>the ID to use for a new game object</returns>
+ public static int GetNextId()
+ {
+ int id;
+ if (sIdOnce.HasValue)
+ {
+ id = sIdOnce.Value;
+ ClearIdOnce();
+ }
+ else
+ {
+ id = sCurrentId;
+ sCurrentId++;
+ }
+
+ return id;
+ }
+
+ /// <summary>
+ /// Sets the ID to use only for the next object that is created.
+ /// </summary>
+ /// <param name="id">the id for the next object</param>
+ public static void SetIdOnce(int id)
+ {
+ sIdOnce = id;
+ }
+
+ /// <summary>
+ /// Clear the ID stored by SetIdOnce that is used only for the
+ /// next object.
+ /// </summary>
+ 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
+{
+ /// <summary>
+ /// A knight which fights against the necromancer.
+ /// </summary>
+ 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
+{
+ /// <summary>
+ /// Class for simple peasants which will be transformed into zombies.
+ /// </summary>
+ 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
+{
+ /// <summary>
+ /// Cardinal directions to show where the specific creature is facing.
+ /// Because of the isometric viewpoint N(orth) is the upper right.
+ /// </summary>
+ public enum MovementDirection
+ {
+ W, NW, N, NO, O, SO, S, SW
+ }
+
+ /// <summary>
+ /// The basic movement states a creature must hold.
+ /// </summary>
+ 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
+ {
+ /// <summary>
+ /// Calculates a path without collisions to desired destination.
+ /// </summary>
+ /// <param name="pathfinder">Pathfinder to use.</param>
+ /// <param name="position">Current position in pixel.</param>
+ /// <param name="destination">Destination in pixel.</param>
+ void FindPath(Pathfinder pathfinder, Vector2 position, Vector2 destination);
+
+ /// <summary>
+ /// Uses pathfinder to for steady movement to new transition.
+ /// </summary>
+ /// <param name="currentPosition">Current position in pixel.</param>
+ /// <param name="speed">Movement speed of the creature.</param>
+ /// <returns>Normalized vector * speed which represents a small step in the direction of desired destination.(</returns>
+ Vector2 GiveNewPosition(Vector2 currentPosition, int speed);
+
+ /// <summary>
+ /// Calculates the direction the creature is looking when moving.
+ /// </summary>
+ MovementDirection GiveMovementDirection();
+ bool IsMoving { get; }
+
+ /// <summary>
+ /// Save the movement data to a MovementData object.
+ /// </summary>
+ /// <returns>the MovementData object with the current status</returns>
+ MovementData SaveData();
+
+ /// <summary>
+ /// Restore the movement state from the given data.
+ /// </summary>
+ /// <param name="movementData">the state of the movement to restore</param>
+ 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?)
+ /// <summary>
+ /// Movement scheme for moving an object with the pathfinder.
+ /// </summary>
+ public class PlayerMovement : IMovable
+ {
+ private const int CellHeight = Constants.CellHeight;
+ private const int CellWidth = Constants.CellWidth;
+ private const float SpeedModifier = 0.25f;
+
+ private List<Vector2> mPath;
+ private int mStep;
+ private Vector2 mLastMovement;
+
+ public bool IsMoving { get; private set; }
+
+ /// <summary>
+ /// Calculates a path without collisions to desired destination.
+ /// </summary>
+ /// <param name="pathfinder">Pathfinder to use.</param>
+ /// <param name="position">Current position in pixel.</param>
+ /// <param name="destination">Destination in pixel.</param>
+ 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;
+ }
+
+ /// <summary>
+ /// Uses pathfinder to for steady movement to new transition.
+ /// </summary>
+ /// <param name="currentPosition">Current position in pixel.</param>
+ /// <param name="speed">Movement speed of the creature.</param>
+ /// <returns>Normalized vector * speed which represents a small step in the direction of desired destination.(</returns>
+ 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;
+ }
+
+ /// <summary>
+ /// Calculates the direction the creature is looking when moving.
+ /// </summary>
+ 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;
+ }
+ /// <summary>
+ /// Save the movement data to a MovementData object.
+ /// </summary>
+ /// <returns>the MovementData object with the current status</returns>
+ public MovementData SaveData()
+ {
+ var data = new MovementData();
+ data.IsMoving = IsMoving;
+ if (IsMoving)
+ {
+ data.Path = mPath;
+ data.Step = mStep;
+ data.LastMovement = mLastMovement;
+ }
+ return data;
+ }
+
+ /// <summary>
+ /// Restore the movement state from the given data.
+ /// </summary>
+ /// <param name="movementData">the state of the movement to restore</param>
+ 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
+{
+ /// <summary>
+ /// A class for the player character: The Necromancer.
+ /// </summary>
+ // 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
+{
+ /// <summary>
+ /// Objects manager for all game objects, be is creatures or buildings or even simple landscape objects.
+ /// </summary>
+ // ReSharper disable once ClassNeverInstantiated.Global
+ public class ObjectsManager : IObjectsManager
+ {
+ private List<List<ICreature>> mCreaturesByFactions;
+ private List<ICreature> mCreatureList;
+ private List<ICreature> mAddToSelectables;
+ private Quadtree mTextureQuadtree;
+ private Quadtree mInteractableQuadtree;
+ private readonly ContentManager mContentManager;
+ private readonly CreatureFactory mCreatureFactory;
+ private readonly IEffectsManager mEffectsManager;
+ private Rectangle mMapRectangle;
+ private List<Area> mAreas;
+ private readonly UpdatesPerSecond mFewerUpdates = new UpdatesPerSecond(15);
+ private readonly UpdatesPerSecond mEffectsCounter = new UpdatesPerSecond(0.2);
+
+ public List<ICreature> AddToSelectables => mAddToSelectables;
+ public List<ICreature> CreatureList => mCreatureList;
+ public List<ICreature> UndeadCreatures => mCreaturesByFactions[(int) Faction.Undead];
+ //public List<ICreature> KingdromCreatures => mCreaturesByFactions[(int) Faction.Kingdom];
+ //public List<ICreature> 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<ICreature>();
+ mCreatureList = new List<ICreature>();
+ mCreaturesByFactions = new List<List<ICreature>>();
+ // Make three lists because we have three factions.
+ for (int i = 0; i < 3; i++)
+ {
+ mCreaturesByFactions.Add(new List<ICreature>());
+ }
+ // 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<ICreature>());
+ }
+ 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<IGameObject> 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<IGameObject> 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<IGameObject> GetObjectsInRectangle(Rectangle rectangle)
+ {
+ return mInteractableQuadtree.GetObjectsInRectangle(rectangle);
+ }
+
+ public List<ICreature> GetCreaturesInEllipse(Ellipse ellipse)
+ {
+ var setToReturn = new List<ICreature>();
+ 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
+{
+ /// <summary>
+ /// Class for selecting creatures, holding the selection and drawing the selection rectangle on the screen.
+ /// </summary>
+ // 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<ICreature> SelectedCreatures { get; private set; } = new List<ICreature>();
+ private List<ICreature> TransformList { get; } = new List<ICreature>();
+ 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<Texture2D>("Sprites/WhiteRectangle");
+ mSoundEffect = contentManager.Load<SoundEffect>("Sounds/zonk2");
+ mSoundEffectInstance = mSoundEffect.CreateInstance();
+ }
+
+ /// <summary>
+ /// Select all objects in the area of the rectangle between origin and destination.
+ /// </summary>
+ /// <param name="origin">Position in pixels where the mouse button was pressed down.</param>
+ /// <param name="destination">Position in pixels where the mouse button was released.</param>
+ 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<ICreature>();
+ var undeadCreatures = new List<ICreature>();
+
+ 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;
+ }
+ }
+
+ /// <summary>
+ /// Draw the selection rectangle on the screen.
+ /// </summary>
+ /// <param name="spriteBatch">Sprite batch used.</param>
+ /// <param name="origin">Position in pixels where the mouse button was pressed down.</param>
+ /// <param name="destination">Position in pixels where the mouse button was released.</param>
+ 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);
+ }
+ }
+
+ /// <summary>
+ /// 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
+ /// </summary>
+ 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;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Press 2 to create zombies from dead bodies
+ /// At least one dead body should be in necromancers area
+ /// </summary>
+ 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;
+ }
+
+ /// <summary>
+ /// Press 3 to create a meatball in exchange for five zombie
+ /// At least five zombies should be selected
+ /// </summary>
+ 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();
+ }
+ }
+
+
+ /// <summary>
+ /// Press 4 to create an skeleton in exchange for an zombie
+ /// At least one zombie should be selected
+ /// </summary>
+ 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;
+ }
+ }
+ }
+
+ /// <summary>
+ /// Press 5 to create an skeletonhorse in exchange for three skeletons
+ /// At least three skeletons should be selected
+ /// </summary>
+ 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();
+ }
+ }
+
+ /// <summary>
+ /// If creature leaves area og the necromancer, he gets disselected
+ /// </summary>
+ 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();
+ }
+ }
+
+ /// <summary>
+ /// Give movement command to selected creatures.
+ /// </summary>
+ /// <param name="destination">Desired destination in pixels.</param>
+ 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
+{
+ /// <summary>
+ /// A skeleton controlled by the necromancer.
+ /// </summary>
+ public class Skeleton : AbstractCreature
+ {
+ /// <summary>
+ /// If the skeleton is mounted, it is not updated and drawn anymore because
+ /// instead the horse sprite is moved.
+ /// </summary>
+ 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);
+
+ /// <summary>
+ /// A skeleton mounts a horse, becoming a skeleton rider.
+ /// </summary>
+ /// <param name="skeleton">The skeleton which mounts the horse.</param>
+ 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<int, ICreature> 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; }
+
+ /// <summary>
+ /// Loads the texture file and prepares animations.
+ /// </summary>
+ /// <param name="contentManager"></param>
+ public void Load(ContentManager contentManager)
+ {
+ mTexture = contentManager.Load<Texture2D>("Sprites/" + TextureFile);
+ mMaxAnimationSteps = IdleFrames;
+ }
+
+ /// <summary>
+ /// Draws the sprite on the screen.
+ /// </summary>
+ /// <param name="spriteBatch">Sprite batch used for drawing.</param>
+ /// <param name="position">Position on the screen where sprite is drawn to.</param>
+ /// <param name="movementState">What moveset will be used? (Moving, Attacking...)</param>
+ /// <param name="movementDirection">Where does the sprite face?</param>
+ 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);
+ }
+
+ /// <summary>
+ /// Change the sprite to show an animation.
+ /// </summary>
+ /// <param name="gameTime">Elapsed game time is used for calculating FPS.</param>
+ 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;
+ }
+ }
+
+ /// <summary>
+ /// Plays the specified animation fully, but only once.
+ /// </summary>
+ /// <param name="animation">For which movement state the animation should be played.</param>
+ /// <param name="duration">How long (or how slow) should the animation be?</param>
+ 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
+{
+ /// <summary>
+ /// A simple arrow from different directions without animations.
+ /// </summary>
+ public sealed class ArrowSprite : ISpriteCreature
+ {
+ private Texture2D mTexture;
+ private const int Size = 64;
+
+ public void Load(ContentManager contentManager)
+ {
+ mTexture = contentManager.Load<Texture2D>("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
+{
+ /// <summary>
+ /// Different types of equipment slots.
+ /// </summary>
+ 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
+{
+ /// <summary>
+ ///
+ /// </summary>
+ public interface ISpriteCreature
+ {
+ /// <summary>
+ /// Loads the texture file and prepares animations.
+ /// </summary>
+ /// <param name="contentManager">Content manager used.</param>
+ void Load(ContentManager contentManager);
+
+ /// <summary>
+ /// Draws the sprite on the screen.
+ /// </summary>
+ /// <param name="spriteBatch">Sprite batch used for drawing.</param>
+ /// <param name="position">Position on the screen in pixels where the sprite should stand.</param>
+ /// <param name="movementState">What moveset will be used? (Moving, Attacking...)</param>
+ /// <param name="movementDirection">Where does the sprite face to?</param>
+ void Draw(SpriteBatch spriteBatch, Vector2 position, MovementState movementState, MovementDirection movementDirection);
+
+ /// <summary>
+ /// Draws a static image of the sprite. No animations.
+ /// </summary>
+ /// <param name="spriteBatch">Sprite batch used for drawing.</param>
+ /// <param name="position">Position of the sprite in pixels. (Where are the feet of the sprite placed.</param>
+ /// <param name="movementState">What moveset will be used? (Moving, Attacking...)</param>
+ /// <param name="movementDirection">Where does the sprite face to?</param>
+ void DrawStatic(SpriteBatch spriteBatch,
+ Point position,
+ MovementState movementState,
+ MovementDirection movementDirection);
+
+ /// <summary>
+ /// Change the sprite to show an animation.
+ /// </summary>
+ /// <param name="gameTime">Elapsed game time is used for calculating FPS.</param>
+ void PlayAnimation(GameTime gameTime);
+
+ /// <summary>
+ /// Plays the specified animation fully, but only once.
+ /// </summary>
+ /// <param name="animation">For which movement state the animation should be played.</param>
+ /// <param name="duration">How long (or how slow) should the animation be?</param>
+ 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
+{
+ /// <summary>
+ /// Texture objects represent map data like tiles and map objects which are placed on the screen.
+ /// </summary>
+ 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;
+
+ /// <summary>
+ /// Creates an empty TextureObject.
+ /// </summary>
+ 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<Texture2D>("Textures/" + mTextureName);
+ //mOnePixelTexture = contentManager.Load<Texture2D>("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;
+
+ /// <summary>
+ /// Call for transformations
+ /// </summary>
+ 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)
+ /// <summary>
+ /// Load the selection and ellipse sprites for necromancers area
+ /// </summary>
+ /// <param name="contentManager">the content manager</param>
+ public void LoadArea(ContentManager contentManager)
+ {
+ //mNecroArea = contentManager.Load<Texture2D>("Sprites/selection");
+ mNecroArea = contentManager.Load<Texture2D>("Sprites/ellipse");
+ }
+
+ /// <summary>
+ /// Draw the area for necromancer
+ /// </summary>
+ /// <param name="spriteBatch">the sprite batch to use for drawing the object</param>
+ 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
+{
+ /// <summary>
+ /// A simple zombie controlled by the necromancer.
+ /// </summary>
+ 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 @@
+<configuration>
+ <dllmap os="linux" dll="opengl32.dll" target="libGL.so.1"/>
+ <dllmap os="linux" dll="glu32.dll" target="libGLU.so.1"/>
+ <dllmap os="linux" dll="openal32.dll" target="libopenal.so.1"/>
+ <dllmap os="linux" dll="alut.dll" target="libalut.so.0"/>
+ <dllmap os="linux" dll="opencl.dll" target="libOpenCL.so"/>
+ <dllmap os="linux" dll="libX11" target="libX11.so.6"/>
+ <dllmap os="linux" dll="libXi" target="libXi.so.6"/>
+ <dllmap os="linux" dll="SDL2.dll" target="libSDL2-2.0.so.0.disabled"/>
+ <dllmap os="osx" dll="opengl32.dll" target="/System/Library/Frameworks/OpenGL.framework/OpenGL"/>
+ <dllmap os="osx" dll="openal32.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
+ <dllmap os="osx" dll="alut.dll" target="/System/Library/Frameworks/OpenAL.framework/OpenAL" />
+ <dllmap os="osx" dll="libGLES.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
+ <dllmap os="osx" dll="libGLESv1_CM.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
+ <dllmap os="osx" dll="libGLESv2.dll" target="/System/Library/Frameworks/OpenGLES.framework/OpenGLES" />
+ <dllmap os="osx" dll="opencl.dll" target="/System/Library/Frameworks/OpenCL.framework/OpenCL"/>
+ <dllmap os="osx" dll="SDL2.dll" target="libSDL2.dylib"/>
+ <!-- XQuartz compatibility (X11 on Mac) -->
+ <dllmap os="osx" dll="libGL.so.1" target="/usr/X11/lib/libGL.dylib"/>
+ <dllmap os="osx" dll="libX11" target="/usr/X11/lib/libX11.dylib"/>
+ <dllmap os="osx" dll="libXcursor.so.1" target="/usr/X11/lib/libXcursor.dylib"/>
+ <dllmap os="osx" dll="libXi" target="/usr/X11/lib/libXi.dylib"/>
+ <dllmap os="osx" dll="libXinerama" target="/usr/X11/lib/libXinerama.dylib"/>
+ <dllmap os="osx" dll="libXrandr.so.2" target="/usr/X11/lib/libXrandr.dylib"/>
+</configuration>
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
+{
+ /// <summary>
+ /// The main class.
+ /// </summary>
+ public static class Program
+ {
+ /// <summary>
+ /// The main entry point for the application.
+ /// </summary>
+ [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;
+
+ /// <summary>
+ /// Generates Quadtree
+ /// </summary>
+ /// <param name="maxSize">Gives the biggest/first Rectangle of the Quadtree. This should be the sice of the howl map.</param>
+ public Quadtree(Point maxSize)
+ {
+ mRoot = new Node(new Rectangle(new Point(-128, -128), maxSize), null);
+ mMaxSize = maxSize;
+ }
+
+ /// <summary>
+ /// Updates the Quadtree. This is importent for the movements of the Objects.
+ /// </summary>
+ public void Update()
+ {
+ mRoot.Update1();
+ }
+
+ /// <summary>
+ /// You call this method if you want to Inster an Object to the Quadtree.
+ /// </summary>
+ /// <param name="item">Type of Creature including their position.</param>
+ public void Insert(IGameObject item)
+ {
+ mRoot.AddtoSubNode(item);
+ }
+
+ /// <summary>
+ /// DMakes the Rectangles of the Quadtree visible.
+ /// </summary>
+ /// <param name="spriteBatch"></param>
+ public void Draw(SpriteBatch spriteBatch)
+ {
+ mRoot.DrawQuadtree(spriteBatch, Texture);
+ }
+
+ public List<IGameObject> GetObjectsInRectangle(Rectangle rectangle)
+ {
+ List<IGameObject> objectList = new List<IGameObject>();
+ return mRoot.GetObjectsInRectangle(rectangle, objectList);
+ }
+
+ /// <summary>
+ /// Deletes an Object out of the Quadtree.
+ /// </summary>
+ /// <param name="item">Type of Creature including their position.</param>
+ public void RemoveItem(IGameObject item)
+ {
+ mRoot.Delete(item);
+ }
+
+ /// <summary>
+ /// Loads the content to draw the Rectangels of the Quadtree.
+ /// </summary>
+ /// <param name="contentManager"></param>
+ public void LoadContent(ContentManager contentManager)
+ {
+ mContentManager = contentManager;
+ Texture = mContentManager.Load<Texture2D>("Sprites/WhiteRectangle");
+ }
+
+ /// <summary>
+ /// Deletes all elements from the quadtree.
+ /// </summary>
+ 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
+ {
+ /// <summary>
+ /// Indicates whether screens below this one should be updated.
+ /// </summary>
+ public bool UpdateLower { get; }
+
+ /// <summary>
+ /// Indicates whether screens below this one should be drawn.
+ /// </summary>
+ public bool DrawLower { get; }
+
+ protected AbstractScreen(bool updateLower, bool drawLower)
+ {
+ UpdateLower = updateLower;
+ DrawLower = drawLower;
+ }
+
+ /// <summary>
+ /// Handles the given key event and returns whether it should be passed
+ /// to the screens below this one.
+ /// </summary>
+ /// <param name="keyEvent">the key event that occurred</param>
+ /// <returns>true if the event has been handeled by this screen and
+ /// should not be passed to the lower screens, false otherwise</returns>
+ public virtual bool HandleKeyEvent(IKeyEvent keyEvent)
+ {
+ return false;
+ }
+
+ /// <summary>
+ /// Handles the given mouse event and returns whether it should be passed
+ /// to the screens below this one.
+ /// </summary>
+ /// <param name="mouseEvent">the mouse event that occurred</param>
+ /// <returns>true if the event has been handeled by this screen and
+ /// should not be passed to the lower screens, false otherwise</returns>
+ 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
+{
+ /// <summary>
+ /// The screen for the AchievementsAndStatistics.
+ /// </summary>
+ // 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<IMenu> mMenuList = new List<IMenu>();
+ 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<Texture2D>("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;
+
+ /// <summary>
+ /// Creates a death screen if the players health reaches 0.
+ /// </summary>
+
+ 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<Texture2D>("Sprites/WhiteRectangle");
+ mDeathFont = mContentManager.Load<SpriteFont>("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
+{
+ /// <summary>
+ /// 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.
+ /// </summary>
+ // 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;
+
+ /// <summary>
+ /// Creates a new debug screen.
+ /// </summary>
+ 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
+{
+ /// <summary>
+ /// 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.
+ /// </summary>
+ public sealed class FpsCounter
+ {
+ /// <summary>
+ /// The current frames per second.
+ /// </summary>
+ public int Fps { get; private set; }
+
+ private int mFrameCount;
+ private TimeSpan mTimeSpan = TimeSpan.Zero;
+
+ /// <summary>
+ /// Updates the elapsed time and -- once every second -- the fps value.
+ /// </summary>
+ /// <param name="gameTime">the elapsed game time</param>
+ public void Update(GameTime gameTime)
+ {
+ mTimeSpan += gameTime.ElapsedGameTime;
+
+ if (mTimeSpan > TimeSpan.FromSeconds(1))
+ {
+ mTimeSpan -= TimeSpan.FromSeconds(1);
+ Fps = mFrameCount;
+ mFrameCount = 0;
+ }
+ }
+
+ /// <summary>
+ /// Registers that a frame has been drawn. Should be called once for
+ /// every Draw.
+ /// </summary>
+ 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
+{
+ /// <summary>
+ /// The main game screen.
+ /// </summary>
+ // 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;
+
+ /// <summary>
+ /// Creates a new game screen.
+ /// </summary>
+ 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<Texture2D>("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;
+ }
+
+ /// <summary>
+ /// Create the initial population as designated by the map manager,
+ /// the player character, and possibly other creatures.
+ /// </summary>
+ 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;
+ }
+
+ /// <summary>
+ /// Updates the status of this object.
+ /// </summary>
+ /// <param name="gameTime">a snapshot of the game time</param>
+ 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
+ }
+
+ /// <summary>
+ /// Draws this object using the given sprite batch.
+ /// </summary>
+ /// <param name="gameTime">a snapshot of the game time</param>
+ /// <param name="spriteBatch">the sprite batch to use for drawing
+ /// this object</param>
+ 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<Rectangle> fog)
+ {
+ mFog.SetFog(fog);
+ }
+
+ public List<Rectangle> 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
+{
+ /// <summary>
+ /// Creates a new HUD screen.
+ /// </summary>
+ // 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<Button> mButtons = new List<Button>();
+ private Button mPauseButton;
+ private Button mCameraButton;
+ private Button mButton1;
+ private Button mButton2;
+ private Button mButton3;
+ private Button mButton4;
+ private Button mButton5;
+
+ private Rectangle mLifeBarRectangle;
+ private Rectangle mBackgroundRectangle;
+ private Rectangle mUnitRectangle;
+ private Rectangle mUnitInformationRectangle;
+ private Rectangle mMiniMapRectangle;
+ private Rectangle mMiniMapCamera;
+
+ private Texture2D mRectangle;
+
+ private Point mRectanglePos;
+ private Point mRectangleSize;
+ private int mCurrentHealth;
+ private int mMaxHealth;
+ private int mCounter;
+
+ private Vector2 mCreatureNamePosition;
+ private readonly Selection mSelection;
+ private int mScaleFactorX;
+ private int mScaleFactorY;
+
+ public HudScreen(ContentManager contentManager, GraphicsDeviceManager graphicsDeviceManager,
+ IOptionsManager optionsManager, MenuActions menuActions,
+ WidgetFactory widgetFactory, Selection selection, CameraManager cameraManager,
+ IMapManager mapManager, IObjectsManager objectsManager,
+ AchievementsAndStatistics achievementsAndStatistics): base(true, true)
+ {
+ mGraphicsDeviceManager = graphicsDeviceManager;
+ mContentManager = contentManager;
+ mOptionsManager = optionsManager;
+ mMenuActions = menuActions;
+ mWidgetFactory = widgetFactory;
+ mSelection = selection;
+ mCameraManager = cameraManager;
+ mMapManager = mapManager;
+ mObjectsManager = objectsManager;
+ mAchievementsAndStatistics = achievementsAndStatistics;
+ }
+
+ public void Initialize()
+ {
+ mRectangle = mContentManager.Load<Texture2D>("Sprites/WhiteRectangle");
+ mFont = mContentManager.Load<SpriteFont>("Fonts/UnitFont");
+
+ mPauseButton = CreateButton("Buttons/Button-06",
+ "Pause",
+ "Pausiert das Spiel und \n" +
+ "öffnet das Pausemenü.");
+ mCameraButton = CreateButton("Buttons/Button-07",
+ "Kamera",
+ "Ändert die Kameraeinstellung zu \n" +
+ "zentrierter oder schiebender Kamera. ");
+ mButton1 = CreateButton("Buttons/Button-01",
+ "Explosion",
+ "Lasst den Fleischklops explodieren \n" +
+ "und fügt im Umkreis Schaden zu.");
+ mButton2 = CreateButton("Buttons/Button-02",
+ "Zombie beschwören",
+ "Wiederbelebt alle toten Gegner im Umkreis \n" +
+ "und lasst sie für euch kämpfen.");
+ mButton3 = CreateButton("Buttons/Button-03",
+ "Zombies verwandeln",
+ "Verschmelzt 5 ausgewählte Zombies \n" +
+ "zu einem Fleischklops.");
+ mButton4 = CreateButton("Buttons/Button-04",
+ "Skelett erschaffen",
+ "Verwandelt einen Zombie zu einem \n" +
+ "Skelett.");
+ mButton5 = CreateButton("Buttons/Button-05",
+ "Totenpferd beschwören",
+ "Vereinigt 3 Skelette zu einem \n" +
+ "Totenpferd.");
+
+ if (mObjectsManager.PlayerCharacter != null)
+ {
+ mCurrentHealth = mObjectsManager.PlayerCharacter.Life;
+ mMaxHealth = mObjectsManager.PlayerCharacter.MaxLife;
+ }
+ }
+
+ public override bool HandleMouseEvent(IMouseEvent mouseEvent)
+ {
+ mButtons.ForEach(b => b.HandleMouseEvent(mouseEvent));
+ if (mMiniMapRectangle.Contains(mouseEvent.PositionPressed))
+ {
+ return true;
+ }
+ foreach (var button in mButtons)
+ {
+ if (button.Rectangle.Contains(mouseEvent.PositionPressed))
+ return true;
+ if (mouseEvent.PositionReleased.HasValue && button.Rectangle.Contains(mouseEvent.PositionReleased.Value))
+ return true;
+ }
+
+ return false;
+ }
+
+ public override void Update(GameTime gameTime)
+ {
+ var viewport = mGraphicsDeviceManager.GraphicsDevice.Viewport;
+ mRectanglePos = new Point(viewport.Width / 2 - viewport.Width / 8, viewport.Height - viewport.Height / 20 - 2);
+ mRectangleSize = new Point(viewport.Width / 4, viewport.Height / 20);
+ mCurrentHealth = mObjectsManager.PlayerCharacter.Life;
+
+ mLifeBarRectangle = new Rectangle(mRectanglePos.X, mRectanglePos.Y, mRectangleSize.X * mCurrentHealth / mMaxHealth, mRectangleSize.Y);
+ mBackgroundRectangle = new Rectangle(mRectanglePos - new Point(2, 2), mRectangleSize + new Point(4, 4));
+ mUnitInformationRectangle = new Rectangle(viewport.Width * 2/3, viewport.Height * 7/8, viewport.Width / 3, viewport.Height / 8);
+ mUnitRectangle = new Rectangle(mUnitInformationRectangle.X + mUnitInformationRectangle.Width * 2 / 3, mUnitInformationRectangle.Y + 5, mUnitInformationRectangle.Width / 3 - 15, mUnitInformationRectangle.Height - 10);
+ mCreatureNamePosition = new Vector2(mUnitInformationRectangle.X + mUnitInformationRectangle.Width / 20, mUnitInformationRectangle.Y + mUnitInformationRectangle.Height / 20);
+
+ // Logic for camera toggle
+ mPreviousState = mCurrentState;
+ mCurrentState = Keyboard.GetState();
+
+ if (mCameraButton.IsClicked || (mCurrentState.IsKeyDown(Keys.C) && mPreviousState.IsKeyUp(Keys.C)))
+ {
+ if (mOptionsManager.Options.CameraType == CameraType.Centered)
+ {
+ mOptionsManager.Options.CameraType = CameraType.Scrolling;
+ }
+ else if (mOptionsManager.Options.CameraType == CameraType.Scrolling)
+ {
+ mOptionsManager.Options.CameraType = CameraType.Centered;
+ }
+ mMenuActions.SaveOptions();
+ mMenuActions.ApplyOptions();
+ }
+
+ // Logic for opening the death screen if the player's life reaches 0 or the victory screen if the boss is defeated.
+ if (mObjectsManager.PlayerCharacter.IsDead)
+ {
+ mCounter++;
+ if (mCounter == 120)
+ {
+ mMenuActions.OpenDeathScreen();
+ mCounter = 0;
+ }
+ }
+
+ else if (mObjectsManager.Boss != null && mObjectsManager.Boss.IsDead)
+ {
+ mCounter++;
+ if (mCounter == 120)
+ {
+ mAchievementsAndStatistics.mUsedTime -= TimeSpan.FromSeconds(2);
+ if (gameTime.TotalGameTime <= TimeSpan.FromMinutes(5))
+ mAchievementsAndStatistics.mHellsNotWaiting = true;
+ mMenuActions.OpenVictoryScreen();
+ mCounter = 0;
+ }
+ }
+
+ // Define the Minimap into the upper right corner and the scale factors needed.
+
+ mMiniMapRectangle = new Rectangle(viewport.Width * 3 / 4, 0, viewport.Width * 1 / 4, viewport.Height * 1 / 4);
+ mScaleFactorX = mCameraManager.GetCamera().MapPixelWidth / mMiniMapRectangle.Width;
+ mScaleFactorY = mCameraManager.GetCamera().MapPixelHeight / 2 / mMiniMapRectangle.Height;
+ mMiniMapCamera = new Rectangle(mMiniMapRectangle.X + (int)mCameraManager.GetCamera().Location.X / mScaleFactorX,
+ mMiniMapRectangle.Y + (int)mCameraManager.GetCamera().Location.Y / mScaleFactorY,
+ viewport.Width / mScaleFactorX, viewport.Height / mScaleFactorY);
+
+ if (mMiniMapRectangle.Contains(Mouse.GetState().Position))
+ {
+ if (Mouse.GetState().LeftButton == ButtonState.Pressed)
+ {
+ float newCameraLocationX = MathHelper.Clamp(((float) Mouse.GetState().Position.X - mMiniMapRectangle.X) * mScaleFactorX -
+ mMiniMapCamera.Width / 2f * mScaleFactorX, 0, mCameraManager.GetCamera().MapPixelWidth - viewport.Width);
+ float newCameraLocationY = MathHelper.Clamp(((float) Mouse.GetState().Position.Y - mMiniMapRectangle.Y) * mScaleFactorY -
+ mMiniMapCamera.Height / 2f * mScaleFactorY, 0, mCameraManager.GetCamera().MapPixelHeight / 2f - viewport.Height);
+ mCameraManager.GetCamera().Location = new Vector2(newCameraLocationX, newCameraLocationY);
+ }
+ }
+
+ // Call for transformations
+ if (mButton1.IsClicked)
+ mSelection.Specialattack();
+ if (mButton2.IsClicked)
+ mSelection.TransformZombie();
+ if (mButton3.IsClicked)
+ mSelection.TransformMeatball();
+ if (mButton4.IsClicked)
+ mSelection.TransformSkeleton();
+ if (mButton5.IsClicked)
+ mSelection.TransformSkeletonHorse();
+
+ UpdateButtons();
+
+ foreach (var unit in mSelection.SelectedCreatures)
+ {
+ if (unit is Meatball)
+ mAchievementsAndStatistics.mMeatballCompany += 1;
+ else if (unit is SkeletonHorse)
+ mAchievementsAndStatistics.mSkeletonHorseCavalry += 1;
+ }
+
+ mAchievementsAndStatistics.mWalkedDistance += ((Necromancer)mObjectsManager.PlayerCharacter).WalkedPixels / 64;
+ mAchievementsAndStatistics.mMarathonRunner += ((Necromancer)mObjectsManager.PlayerCharacter).WalkedPixels / 64;
+ mAchievementsAndStatistics.mIronMan += ((Necromancer)mObjectsManager.PlayerCharacter).WalkedPixels / 64;
+ mAchievementsAndStatistics.mUsedTime += gameTime.ElapsedGameTime;
+ }
+
+ public override void Draw(GameTime gameTime, SpriteBatch spriteBatch)
+ {
+ spriteBatch.Begin();
+ mButtons.ForEach(b => b.Draw(spriteBatch));
+ spriteBatch.Draw(mRectangle, mBackgroundRectangle, Color.Black * 0.7f);
+ spriteBatch.Draw(mRectangle, mLifeBarRectangle, Color.Firebrick);
+ spriteBatch.Draw(mRectangle, mUnitInformationRectangle, Color.Chocolate * 0.7f);
+ spriteBatch.Draw(mRectangle, mUnitRectangle, Color.Gainsboro * 0.6f);
+
+ // Draw the minimap.
+ mMapManager.DrawMinimap(spriteBatch, mMiniMapRectangle);
+
+ // Draw a rectangle on the part of the MiniMap that is shown by the camera.
+ // Upper line
+ spriteBatch.Draw(mRectangle, new Rectangle(mMiniMapCamera.X, mMiniMapCamera.Y, mMiniMapCamera.Width, 1), Color.White);
+ // Left line
+ spriteBatch.Draw(mRectangle, new Rectangle(mMiniMapCamera.X, mMiniMapCamera.Y, 1, mMiniMapCamera.Height), Color.White);
+ // Right line
+ spriteBatch.Draw(mRectangle, new Rectangle(mMiniMapCamera.X + mMiniMapCamera.Width, mMiniMapCamera.Y, 1, mMiniMapCamera.Height), Color.White);
+ // Bottom line
+ spriteBatch.Draw(mRectangle, new Rectangle(mMiniMapCamera.X, mMiniMapCamera.Y + mMiniMapCamera.Height, mMiniMapCamera.Width, 1), Color.White);
+
+ foreach (var creature in mSelection.SelectedCreatures)
+ {
+ if (creature.IsSelected && mSelection.SelectedCreatures.Count == 1)
+ {
+ spriteBatch.DrawString(mFont, creature.Name, mCreatureNamePosition, Color.Black);
+ spriteBatch.DrawString(mFont,
+ "Leben: " + creature.Life,
+ mCreatureNamePosition + new Vector2(0, 20),
+ Color.Black);
+ spriteBatch.DrawString(mFont,
+ "Kraft: " + creature.Attack,
+ mCreatureNamePosition + new Vector2(0, 40),
+ Color.Black);
+ creature.DrawStatic(spriteBatch,
+ new Point(mUnitRectangle.X + mUnitRectangle.Width / 2, mUnitRectangle.Y + mUnitRectangle.Height * 3/4));
+ }
+ else if (mSelection.SelectedCreatures.Count > 1)
+ {
+ var showedCreature = mSelection.SelectedCreatures[0];
+ spriteBatch.DrawString(mFont, showedCreature.Name, mCreatureNamePosition, Color.Black);
+ spriteBatch.DrawString(mFont,
+ "Leben: " + showedCreature.Life,
+ mCreatureNamePosition + new Vector2(0, 20),
+ Color.Black);
+ spriteBatch.DrawString(mFont,
+ "Kraft: " + showedCreature.Attack,
+ mCreatureNamePosition + new Vector2(0, 40),
+ Color.Black);
+ showedCreature.DrawStatic(spriteBatch,
+ new Point(mUnitRectangle.X + mUnitRectangle.Width / 2, mUnitRectangle.Y + mUnitRectangle.Height * 3 / 4));
+ }
+ }
+ spriteBatch.End();
+ }
+
+ private void UpdateButtons()
+ {
+ var viewport = mGraphicsDeviceManager.GraphicsDevice.Viewport;
+ // Button Size
+ var buttonLength = viewport.Height / 12;
+ var buttonSize = new Vector2(buttonLength, buttonLength);
+ mButtons.ForEach(b => b.Size = buttonSize);
+
+ // Rectangles for the buttons
+ var buttonXVector = new Vector2(buttonLength + 2, 0);
+ mPauseButton.Position = new Vector2(5, 5);
+ mCameraButton.Position = new Vector2(mPauseButton.Position.X + mPauseButton.Size.X + 5, 5);
+ mButton1.Position = new Vector2(2, viewport.Height - buttonLength);
+ mButton2.Position = mButton1.Position + buttonXVector;
+ mButton3.Position = mButton2.Position + buttonXVector;
+ mButton4.Position = mButton3.Position + buttonXVector;
+ mButton5.Position = mButton4.Position + buttonXVector;
+
+ if (mPauseButton.IsClicked)
+ mMenuActions.OpenPauseScreen();
+
+ var mousePosition = Mouse.GetState().Position;
+ mButtons.ForEach(b => b.IsSelected = b.CheckSelected(mousePosition));
+ mButtons.ForEach(b => b.IsClicked = false);
+ }
+
+ private Button CreateButton(string textureName, string tooltipTitle, string tooltip)
+ {
+ return CreateButton(mContentManager.Load<Texture2D>(textureName), tooltipTitle, tooltip);
+ }
+
+ private Button CreateButton(Texture2D texture, string tooltipTitle, string tooltip)
+ {
+ var button = mWidgetFactory.CreateButton("");
+ button.Position = Vector2.Zero;
+ button.PaddingX = 15;
+ button.PaddingY = 5;
+ button.Size = button.GetMinimumSize();
+ button.Image = texture;
+ button.Tooltip = tooltip;
+ button.TooltipTitle = tooltipTitle;
+ mButtons.Add(button);
+ return button;
+ }
+ }
+}
diff --git a/V3/Screens/IDrawable.cs b/V3/Screens/IDrawable.cs
new file mode 100644
index 0000000..b940d94
--- /dev/null
+++ b/V3/Screens/IDrawable.cs
@@ -0,0 +1,19 @@
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace V3.Screens
+{
+ /// <summary>
+ /// An object that can be drawn using a sprite batch.
+ /// </summary>
+ public interface IDrawable
+ {
+ /// <summary>
+ /// Draws this object using the given sprite batch.
+ /// </summary>
+ /// <param name="gameTime">a snapshot of the game time</param>
+ /// <param name="spriteBatch">the sprite batch to use for drawing
+ /// this object</param>
+ void Draw(GameTime gameTime, SpriteBatch spriteBatch);
+ }
+}
diff --git a/V3/Screens/IScreen.cs b/V3/Screens/IScreen.cs
new file mode 100644
index 0000000..197aaec
--- /dev/null
+++ b/V3/Screens/IScreen.cs
@@ -0,0 +1,39 @@
+using V3.Input;
+
+namespace V3.Screens
+{
+ /// <summary>
+ /// A screen that can be handled by a screen manager and that provides
+ /// information on how to deal with other screens below this one.
+ /// </summary>
+ public interface IScreen : IDrawable, IUpdateable
+ {
+ /// <summary>
+ /// Indicates whether screens below this one should be updated.
+ /// </summary>
+ bool UpdateLower { get; }
+
+ /// <summary>
+ /// Indicates whether screens below this one should be drawn.
+ /// </summary>
+ bool DrawLower { get; }
+
+ /// <summary>
+ /// Handles the given key event and returns whether it should be passed
+ /// to the screens below this one.
+ /// </summary>
+ /// <param name="keyEvent">the key event that occurred</param>
+ /// <returns>true if the event has been handeled by this screen and
+ /// should not be passed to the lower screens, false otherwise</returns>
+ bool HandleKeyEvent(IKeyEvent keyEvent);
+
+ /// <summary>
+ /// Handles the given mouse event and returns whether it should be passed
+ /// to the screens below this one.
+ /// </summary>
+ /// <param name="mouseEvent">the mouse event that occurred</param>
+ /// <returns>true if the event has been handeled by this screen and
+ /// should not be passed to the lower screens, false otherwise</returns>
+ bool HandleMouseEvent(IMouseEvent mouseEvent);
+ }
+}
diff --git a/V3/Screens/IScreenFactory.cs b/V3/Screens/IScreenFactory.cs
new file mode 100644
index 0000000..a2d844b
--- /dev/null
+++ b/V3/Screens/IScreenFactory.cs
@@ -0,0 +1,27 @@
+namespace V3.Screens
+{
+ public interface IScreenFactory
+ {
+ GameScreen CreateGameScreen();
+
+ HudScreen CreateHudScreen();
+
+ LoadScreen CreateLoadScreen();
+
+ MainScreen CreateMainScreen();
+
+ PauseScreen CreatePauseScreen();
+
+ OptionsScreen CreateOptionsScreen();
+
+ DeathScreen CreateDeathScreen();
+
+ VictoryScreen CreateVictoryScreen();
+
+ TechdemoScreen CreaTechdemoScreen();
+
+ StatisticsScreen CreateStatisticsScreen();
+
+ AchievementsScreen CreateAchievementsScreen();
+ }
+}
diff --git a/V3/Screens/IScreenManager.cs b/V3/Screens/IScreenManager.cs
new file mode 100644
index 0000000..e61c49c
--- /dev/null
+++ b/V3/Screens/IScreenManager.cs
@@ -0,0 +1,35 @@
+namespace V3.Screens
+{
+ /// <summary>
+ /// Handles screens using a screen stack. You can add screens to the
+ /// foreground using the AddScreen method, remove screens from the
+ /// foreground using the RemoveScreen method and remove all screens using
+ /// the Clear method. The top screen is always drawn and updated, and
+ /// it can decide whether lower screens should be drawn and/or updated
+ /// too. The screens are updated from top to bottom, and drawn from
+ /// bottom to top.
+ /// </summary>
+ public interface IScreenManager : IDrawable, IUpdateable
+ {
+ /// <summary>
+ /// Adds a screen to the foreground.
+ /// </summary>
+ /// <param name="screen">the screen to add in the foreground</param>
+ void AddScreen(IScreen screen);
+
+ /// <summary>
+ /// Removes the given screen if it is on the top of the screen stack.
+ /// </summary>
+ /// <param name="screen">the screen to remove</param>
+ /// <returns>true if the screen was on top and has been removed,
+ /// false otherwise</returns>
+ void RemoveScreen(IScreen screen);
+
+ /// <summary>
+ /// Clears the screen stack.
+ /// </summary>
+ void Clear();
+
+ GameScreen GetGameScreen();
+ }
+}
diff --git a/V3/Screens/IUpdatable.cs b/V3/Screens/IUpdatable.cs
new file mode 100644
index 0000000..61972e7
--- /dev/null
+++ b/V3/Screens/IUpdatable.cs
@@ -0,0 +1,16 @@
+using Microsoft.Xna.Framework;
+
+namespace V3.Screens
+{
+ /// <summary>
+ /// An object that can be updated.
+ /// </summary>
+ public interface IUpdateable
+ {
+ /// <summary>
+ /// Updates the status of this object.
+ /// </summary>
+ /// <param name="gameTime">a snapshot of the game time</param>
+ void Update(GameTime gameTime);
+ }
+}
diff --git a/V3/Screens/LoadScreen.cs b/V3/Screens/LoadScreen.cs
new file mode 100644
index 0000000..0e58147
--- /dev/null
+++ b/V3/Screens/LoadScreen.cs
@@ -0,0 +1,124 @@
+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.Input;
+using V3.Widgets;
+
+namespace V3.Screens
+{
+ /// <summary>
+ /// The screen for the load menu.
+ /// </summary>
+ // ReSharper disable once ClassNeverInstantiated.Global
+ public sealed class LoadScreen : AbstractScreen, IInitializable
+ {
+ private readonly ContentManager mContentManager;
+ private readonly IMenu mMenu;
+ private readonly ISaveGameManager mSaveGameManager;
+ private readonly MenuActions mMenuActions;
+ private readonly WidgetFactory mWidgetFactory;
+
+ private Texture2D mRectangle;
+ private Button mButtonBack;
+ private SelectButton mButtonSaveGame;
+ private Button mButtonLoad;
+ private List<ISaveGame> mSaveGames;
+
+ /// <summary>
+ /// Creates a new load screen.
+ /// </summary>
+ public LoadScreen(ContentManager contentManager, FormMenu menu,
+ ISaveGameManager saveGameManager, MenuActions menuActions,
+ WidgetFactory widgetFactory)
+ : base(false, true)
+ {
+ mContentManager = contentManager;
+ mMenu = menu;
+ mSaveGameManager = saveGameManager;
+ mMenuActions = menuActions;
+ mWidgetFactory = widgetFactory;
+ }
+
+ public void Initialize()
+ {
+ mRectangle = mContentManager.Load<Texture2D>("Sprites/WhiteRectangle");
+
+ mButtonBack = mWidgetFactory.CreateButton("Zurück");
+ mButtonLoad = mWidgetFactory.CreateButton("Laden");
+ mButtonSaveGame = mWidgetFactory.CreateSelectButton();
+ mSaveGames = mSaveGameManager.GetSaveGames();
+ foreach (var saveGame in mSaveGames)
+ {
+ mButtonSaveGame.Values.Add(GetSaveGameString(saveGame));
+ }
+ mButtonSaveGame.SelectedIndex = mSaveGames.Count - 1;
+
+ mMenu.Widgets.Add(mWidgetFactory.CreateEmptyWidget());
+ mMenu.Widgets.Add(mButtonBack);
+ mMenu.Widgets.Add(mWidgetFactory.CreateLabel("Spielstand"));
+ mMenu.Widgets.Add(mButtonSaveGame);
+ mMenu.Widgets.Add(mWidgetFactory.CreateEmptyWidget());
+ mMenu.Widgets.Add(mButtonLoad);
+ }
+
+ 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)
+ {
+ mMenu.HandleMouseEvent(mouseEvent);
+ return true;
+ }
+
+ /// <summary>
+ /// Draws this object using the given sprite batch.
+ /// </summary>
+ /// <param name="gameTime">a snapshot of the game time</param>
+ /// <param name="spriteBatch">the sprite batch to use for drawing
+ /// this object</param>
+ public override void Draw(GameTime gameTime, SpriteBatch spriteBatch)
+ {
+ var backgroundRectangle = new Rectangle((int)mMenu.Position.X,
+ (int)mMenu.Position.Y, (int)mMenu.Size.X, (int)mMenu.Size.Y);
+ backgroundRectangle.X -= 30;
+ backgroundRectangle.Y -= 30;
+ backgroundRectangle.Width += 60;
+ backgroundRectangle.Height += 60;
+
+ spriteBatch.Begin();
+ spriteBatch.Draw(mRectangle, backgroundRectangle, Color.LightGray);
+ spriteBatch.End();
+
+ mMenu.Draw(spriteBatch);
+ }
+
+ public override void Update(GameTime gameTime)
+ {
+ if (mButtonBack.IsClicked)
+ {
+ mMenuActions.Close(this);
+ }
+ else if (mButtonLoad.IsClicked)
+ {
+ var saveGame = mSaveGames[mButtonSaveGame.SelectedIndex];
+ mMenuActions.LoadGame(saveGame);
+ }
+
+ mMenu.Update();
+ }
+
+ private static string GetSaveGameString(ISaveGame saveGame)
+ {
+ return saveGame.Timestamp.ToString("s");
+ }
+ }
+}
diff --git a/V3/Screens/MainScreen.cs b/V3/Screens/MainScreen.cs
new file mode 100644
index 0000000..b7932bf
--- /dev/null
+++ b/V3/Screens/MainScreen.cs
@@ -0,0 +1,195 @@
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
+using Ninject;
+using V3.Input;
+using V3.Widgets;
+
+namespace V3.Screens
+{
+ /// <summary>
+ /// The screen for the main menu.
+ /// </summary>
+ // ReSharper disable once ClassNeverInstantiated.Global
+ public class MainScreen : AbstractScreen, IInitializable
+ {
+ private readonly GraphicsDeviceManager mGraphicsDeviceManager;
+ private readonly IMenu mMenu;
+ private readonly MenuActions mMenuActions;
+ private readonly WidgetFactory mWidgetFactory;
+ private readonly ContentManager mContentManager;
+
+ private Button mButtonStart;
+ private Button mButtonLoad;
+ private Button mButtonOptions;
+ private Button mButtonTechDemo;
+ private Button mButtonExit;
+ private Button mButtonStatistics;
+ private Button mButtonAchievements;
+
+ private Texture2D mTitleImage;
+ private Texture2D mBackgroundImage;
+ private Vector2 mImagePosition;
+ private Random mRandom;
+ private Vector2 mImageScrollDirection;
+ private Rectangle TitleImageBounds => mTitleImage.Bounds;
+ private Rectangle BackgroundImageBounds => mBackgroundImage.Bounds;
+ private Rectangle ScreenBounds => mGraphicsDeviceManager.GraphicsDevice.Viewport.Bounds;
+
+ /// <summary>
+ /// Creates a new main screen.
+ /// </summary>
+ public MainScreen(GraphicsDeviceManager graphicsDeviceManager,
+ VerticalMenu menu, MenuActions menuActions,
+ WidgetFactory widgetFactory, ContentManager contentManager) : base(false, false)
+ {
+ mGraphicsDeviceManager = graphicsDeviceManager;
+ mMenu = menu;
+ mMenuActions = menuActions;
+ mWidgetFactory = widgetFactory;
+ mContentManager = contentManager;
+ }
+
+ public void Initialize()
+ {
+ mMenuActions.ApplyOptions();
+
+ mButtonStart = mWidgetFactory.CreateButton("Neues Spiel");
+ mButtonLoad = mWidgetFactory.CreateButton("Spiel laden");
+ mButtonLoad.IsEnabled = mMenuActions.CanLoadGame();
+ mButtonOptions = mWidgetFactory.CreateButton("Optionen");
+ mButtonStatistics = mWidgetFactory.CreateButton("Statistiken");
+ mButtonAchievements = mWidgetFactory.CreateButton("Erfolge");
+ mButtonTechDemo = mWidgetFactory.CreateButton("Tech-Demo");
+ mButtonExit = mWidgetFactory.CreateButton("Spiel schließen");
+
+ mMenu.Widgets.Add(mButtonStart);
+ mMenu.Widgets.Add(mButtonLoad);
+ mMenu.Widgets.Add(mButtonOptions);
+ mMenu.Widgets.Add(mButtonStatistics);
+ mMenu.Widgets.Add(mButtonAchievements);
+ mMenu.Widgets.Add(mButtonTechDemo);
+ mMenu.Widgets.Add(mButtonExit);
+
+ mTitleImage = mContentManager.Load<Texture2D>("Menu/Titel");
+ mBackgroundImage = mContentManager.Load<Texture2D>("Menu/mainscreen");
+ mRandom = new Random();
+ mImagePosition = RandomPosition();
+ mImageScrollDirection = RandomScrollDirection();
+ mButtonStart.BackgroundColor = Color.Red;
+ mButtonLoad.BackgroundColor = Color.Red;
+ mButtonOptions.BackgroundColor = Color.Red;
+ mButtonStatistics.BackgroundColor = Color.Red;
+ mButtonAchievements.BackgroundColor = Color.Red;
+ mButtonTechDemo.BackgroundColor = Color.Red;
+ mButtonExit.BackgroundColor = Color.Red;
+ }
+
+ public override bool HandleKeyEvent(IKeyEvent keyEvent)
+ {
+ return true;
+ }
+
+ public override bool HandleMouseEvent(IMouseEvent mouseEvent)
+ {
+ mMenu.HandleMouseEvent(mouseEvent);
+ return true;
+ }
+
+ public override void Update(GameTime gameTime)
+ {
+ if (mButtonStart.IsClicked)
+ mMenuActions.StartNewGame();
+ else if (mButtonLoad.IsClicked)
+ mMenuActions.OpenLoadScreen();
+ else if (mButtonOptions.IsClicked)
+ mMenuActions.OpenOptionsScreen();
+ else if (mButtonTechDemo.IsClicked)
+ mMenuActions.OpenTechDemo();
+ else if (mButtonStatistics.IsClicked)
+ mMenuActions.OpenStatisticsScreen();
+ else if (mButtonAchievements.IsClicked)
+ mMenuActions.OpenAchievementsScreen();
+ else if (mButtonExit.IsClicked)
+ mMenuActions.Exit();
+
+ mMenu.Update();
+ UpdateBackgroundPosition();
+ }
+
+ /// <summary>
+ /// Draws this object using the given sprite batch.
+ /// </summary>
+ /// <param name="gameTime">a snapshot of the game time</param>
+ /// <param name="spriteBatch">the sprite batch to use for drawing
+ /// this object</param>
+ public override void Draw(GameTime gameTime, SpriteBatch spriteBatch)
+ {
+ spriteBatch.Begin();
+ spriteBatch.Draw(mBackgroundImage, mImagePosition, Color.White);
+ Point titleSize = new Point(ScreenBounds.Width * 9 / 10, ScreenBounds.Width * TitleImageBounds.Height * 9 / 10 / TitleImageBounds.Width);
+ Point titlePosition = new Point(ScreenBounds.Width / 2 - titleSize.X / 2, ScreenBounds.Height / 20);
+ spriteBatch.Draw(mTitleImage,
+ new Rectangle(titlePosition, titleSize),
+ Color.White);
+ spriteBatch.End();
+
+ mMenu.Draw(spriteBatch);
+ }
+
+ /// <summary>
+ /// Calculate a random section of the background image to show.
+ /// If the screen is larger than the image, just draw it to the upper left corner.
+ /// </summary>
+ /// <returns>A random Vector2 fitting the image to the screen.</returns>
+ private Vector2 RandomPosition()
+ {
+ Vector2 position;
+ try
+ {
+ var randomX = mRandom.Next(-BackgroundImageBounds.Width + ScreenBounds.Width, 0);
+ var randomY = mRandom.Next(-BackgroundImageBounds.Height + ScreenBounds.Height, 0);
+ position = new Vector2(randomX, randomY);
+ }
+ catch (ArgumentOutOfRangeException)
+ {
+ position = Vector2.Zero;
+ }
+ return position;
+ }
+
+ private Vector2 RandomScrollDirection()
+ {
+ var imageScrollDirection = new Vector2((float)mRandom.NextDouble(), (float)mRandom.NextDouble());
+ imageScrollDirection.Normalize();
+ switch (mRandom.Next(4))
+ {
+ case 0:
+ return imageScrollDirection;
+ case 1:
+ return new Vector2(imageScrollDirection.X, -imageScrollDirection.Y);
+ case 2:
+ return new Vector2(-imageScrollDirection.X, imageScrollDirection.Y);
+ case 3:
+ return new Vector2(-imageScrollDirection.X, -imageScrollDirection.Y);
+ default:
+ return imageScrollDirection;
+ }
+ }
+
+ private void UpdateBackgroundPosition()
+ {
+ if (mImagePosition.X < 0 && mImagePosition.X > -BackgroundImageBounds.Width + ScreenBounds.Width
+ && mImagePosition.Y < 0 && mImagePosition.Y > -BackgroundImageBounds.Height + ScreenBounds.Height)
+ {
+ mImagePosition += mImageScrollDirection;
+ }
+ else
+ {
+ mImagePosition = RandomPosition();
+ mImageScrollDirection = RandomScrollDirection();
+ }
+ }
+ }
+}
diff --git a/V3/Screens/MenuActions.cs b/V3/Screens/MenuActions.cs
new file mode 100644
index 0000000..6de9e15
--- /dev/null
+++ b/V3/Screens/MenuActions.cs
@@ -0,0 +1,208 @@
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Media;
+using V3.Camera;
+using V3.Data;
+
+namespace V3.Screens
+{
+ /// <summary>
+ /// Provides common actions for the main and pause menu, like saving and
+ /// loading the game or removing and adding a screen to the screen stack.
+ /// </summary>
+ // ReSharper disable once ClassNeverInstantiated.Global
+ public sealed class MenuActions
+ {
+ private readonly Game mGame;
+ private readonly GraphicsDeviceManager mGraphicsDeviceManager;
+ private readonly IGameStateManager mGameStateManager;
+ private readonly IOptionsManager mOptionsManager;
+ private readonly ISaveGameManager mSaveGameManager;
+ private readonly IScreenManager mScreenManager;
+ private readonly IScreenFactory mScreenFactory;
+ private readonly CameraManager mCameraManager;
+
+ /// <summary>
+ /// Creates a new menu actions instance.
+ /// </summary>
+ public MenuActions(Game game, GraphicsDeviceManager graphicsDeviceManager,
+ IGameStateManager gameStateManager, IOptionsManager optionsManager,
+ ISaveGameManager saveGameManager, IScreenManager screenManager,
+ IScreenFactory screenFactory, CameraManager cameraManager)
+ {
+ mGame = game;
+ mGraphicsDeviceManager = graphicsDeviceManager;
+ mGameStateManager = gameStateManager;
+ mOptionsManager = optionsManager;
+ mSaveGameManager = saveGameManager;
+ mScreenManager = screenManager;
+ mScreenFactory = screenFactory;
+ mCameraManager = cameraManager;
+ }
+
+ /// <summary>
+ /// Checks whether it is possible to load a game, i. e. whether there
+ /// are save games.
+ /// </summary>
+ /// <returns>true if there are save games to load, false otherwise
+ /// </returns>
+ public bool CanLoadGame()
+ {
+ return mSaveGameManager.GetSaveGames().Count > 0;
+ }
+
+ /// <summary>
+ /// Removes the given screen from the screen manager.
+ /// </summary>
+ /// <param name="screen">the screen to remove</param>
+ public void Close(IScreen screen)
+ {
+ // TODO: something like RemoveUntil
+ mScreenManager.RemoveScreen(screen);
+ }
+
+ /// <summary>
+ /// Quits the game.
+ /// </summary>
+ public void Exit()
+ {
+ mGame.Exit();
+ }
+
+ public void LoadGame(ISaveGame saveGame)
+ {
+ mScreenManager.Clear();
+ var gameScreen = mScreenFactory.CreateGameScreen();
+ var gameState = saveGame.GameState;
+ mGameStateManager.LoadGameState(gameState);
+ gameScreen.SetFog(gameState.mFog);
+ gameScreen.SetAiState(gameState.mAiState);
+ mScreenManager.AddScreen(gameScreen);
+ mScreenManager.AddScreen(mScreenFactory.CreateHudScreen());
+ }
+
+ /// <summary>
+ /// Opens the main screen and removes all other screens.
+ /// </summary>
+ public void OpenMainScreen()
+ {
+ mScreenManager.Clear();
+ mScreenManager.AddScreen(mScreenFactory.CreateMainScreen());
+ }
+
+ /// <summary>
+ /// Opens the options screen in the front.
+ /// </summary>
+ public void OpenOptionsScreen()
+ {
+ mScreenManager.AddScreen(mScreenFactory.CreateOptionsScreen());
+ }
+
+ public void OpenLoadScreen()
+ {
+ mScreenManager.AddScreen(mScreenFactory.CreateLoadScreen());
+ }
+
+ /// <summary>
+ /// Opens the pause screen in the front.
+ /// </summary>
+ public void OpenPauseScreen()
+ {
+ mScreenManager.AddScreen(mScreenFactory.CreatePauseScreen());
+ }
+
+ /// <summary>
+ /// Opens the death screen in the front.
+ /// </summary>
+ public void OpenDeathScreen()
+ {
+ mScreenManager.AddScreen(mScreenFactory.CreateDeathScreen());
+ }
+
+ /// <summary>
+ /// Opens the victory screen in the front.
+ /// </summary>
+ public void OpenVictoryScreen()
+ {
+ mScreenManager.AddScreen(mScreenFactory.CreateVictoryScreen());
+ }
+
+ /// <summary>
+ /// Opens the statistics screen in the front.
+ /// </summary>
+ public void OpenStatisticsScreen()
+ {
+ mScreenManager.AddScreen(mScreenFactory.CreateStatisticsScreen());
+ }
+
+ /// <summary>
+ /// Opens the achievements screen in the front.
+ /// </summary>
+ public void OpenAchievementsScreen()
+ {
+ mScreenManager.AddScreen(mScreenFactory.CreateAchievementsScreen());
+ }
+
+ /// <summary>
+ /// Opens the tech demo.
+ /// </summary>
+ public void OpenTechDemo()
+ {
+ mScreenManager.Clear();
+ mScreenManager.AddScreen(mScreenFactory.CreaTechdemoScreen());
+ mScreenManager.AddScreen(mScreenFactory.CreateHudScreen());
+ }
+
+ /// <summary>
+ /// Creates a new save game from the current game state.
+ /// </summary>
+ public void SaveGame()
+ {
+ var gameState = mGameStateManager.GetGameState();
+ var gameScreen = mScreenManager.GetGameScreen();
+ if (gameScreen != null)
+ {
+ gameState.mFog = gameScreen.GetFog();
+ gameState.mAiState = gameScreen.GetAiState();
+ }
+ mSaveGameManager.CreateSaveGame(gameState);
+ }
+
+ /// <summary>
+ /// Apply the current graphics options.
+ /// </summary>
+ public void ApplyOptions()
+ {
+ mGraphicsDeviceManager.PreferredBackBufferWidth = mOptionsManager.Options.Resolution.X;
+ mGraphicsDeviceManager.PreferredBackBufferHeight = mOptionsManager.Options.Resolution.Y;
+ mGraphicsDeviceManager.IsFullScreen = mOptionsManager.Options.IsFullScreen;
+ mGraphicsDeviceManager.ApplyChanges();
+
+#if NO_AUDIO
+#else
+ MediaPlayer.Volume = mOptionsManager.Options.GetEffectiveVolume();
+#endif
+ }
+
+ /// <summary>
+ /// Save the current graphics options.
+ /// </summary>
+ public void SaveOptions()
+ {
+ mOptionsManager.SaveOptions();
+ }
+
+ /// <summary>
+ /// Opens the game screen with a new game.
+ /// </summary>
+ public void StartNewGame()
+ {
+ mScreenManager.Clear();
+ var gameScreen = mScreenFactory.CreateGameScreen();
+ gameScreen.CreateInitialPopulation();
+ mScreenManager.AddScreen(gameScreen);
+ mScreenManager.AddScreen(mScreenFactory.CreateHudScreen());
+ if (mCameraManager.GetCamera() is CameraScrolling)
+ mCameraManager.GetCamera().Location = Vector2.Zero;
+ }
+ }
+}
diff --git a/V3/Screens/OptionsScreen.cs b/V3/Screens/OptionsScreen.cs
new file mode 100644
index 0000000..b23e1fe
--- /dev/null
+++ b/V3/Screens/OptionsScreen.cs
@@ -0,0 +1,197 @@
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input;
+using Ninject;
+using V3.Camera;
+using V3.Data;
+using V3.Input;
+using V3.Widgets;
+
+namespace V3.Screens
+{
+ /// <summary>
+ /// The screen for the options menu.
+ /// </summary>
+ // ReSharper disable once ClassNeverInstantiated.Global
+ public sealed class OptionsScreen : AbstractScreen, IInitializable
+ {
+ private readonly ContentManager mContentManager;
+ private readonly IMenu mMenu;
+ private readonly IOptionsManager mOptionsManager;
+ private readonly MenuActions mMenuActions;
+ private readonly WidgetFactory mWidgetFactory;
+
+ private Texture2D mRectangle;
+ private Button mButtonBack;
+ private SelectButton mButtonSize;
+ private SelectButton mButtonFullscreen;
+ private SelectButton mButtonCamera;
+ private SelectButton mButtonDebug;
+ private SelectButton mButtonMute;
+ private SelectButton mButtonVolume;
+ private Button mButtonApply;
+
+ /// <summary>
+ /// Creates a new options screen.
+ /// </summary>
+ public OptionsScreen(ContentManager contentManager, FormMenu menu,
+ IOptionsManager optionsManager, MenuActions menuActions,
+ WidgetFactory widgetFactory)
+ : base(false, true)
+ {
+ mContentManager = contentManager;
+ mMenu = menu;
+ mOptionsManager = optionsManager;
+ mMenuActions = menuActions;
+ mWidgetFactory = widgetFactory;
+ }
+
+ public void Initialize()
+ {
+ mRectangle = mContentManager.Load<Texture2D>("Sprites/WhiteRectangle");
+
+ mButtonBack = mWidgetFactory.CreateButton("Zurück");
+ mButtonApply = mWidgetFactory.CreateButton("Bestätigen");
+ mButtonSize = mWidgetFactory.CreateSelectButton();
+ foreach (var resolution in Options.Resolutions)
+ {
+ mButtonSize.Values.Add(GetResolutionString(resolution));
+ }
+ mButtonSize.SelectedIndex = Options.Resolutions.IndexOf(mOptionsManager.Options.Resolution);
+ mButtonFullscreen = mWidgetFactory.CreateSelectButton(new[] { "aus", "an" });
+ mButtonFullscreen.SelectedIndex = mOptionsManager.Options.IsFullScreen ? 1 : 0;
+ mButtonCamera = mWidgetFactory.CreateSelectButton();
+ Options.CameraTypes.ForEach(t => mButtonCamera.Values.Add(GetCameraTypeString(t)));
+ mButtonCamera.SelectedIndex = Options.CameraTypes.IndexOf(mOptionsManager.Options.CameraType);
+ mButtonDebug = mWidgetFactory.CreateSelectButton();
+ Options.DebugModes.ForEach(m => mButtonDebug.Values.Add(GetDebugModeString(m)));
+ mButtonDebug.SelectedIndex = Options.DebugModes.IndexOf(mOptionsManager.Options.DebugMode);
+ mButtonMute = mWidgetFactory.CreateSelectButton(new[] { "aus", "an" });
+ mButtonMute.SelectedIndex = mOptionsManager.Options.IsMuted ? 0 : 1;
+ mButtonVolume = mWidgetFactory.CreateSelectButton();
+ foreach (var volume in Options.Volumes)
+ {
+ mButtonVolume.Values.Add(GetVolumeString(volume));
+ }
+ mButtonVolume.SelectedIndex = Options.Volumes.IndexOf(mOptionsManager.Options.Volume);
+
+ mMenu.Widgets.Add(mWidgetFactory.CreateEmptyWidget());
+ mMenu.Widgets.Add(mButtonBack);
+ mMenu.Widgets.Add(mWidgetFactory.CreateLabel("Auflösung"));
+ mMenu.Widgets.Add(mButtonSize);
+ mMenu.Widgets.Add(mWidgetFactory.CreateLabel("Fullscreen"));
+ mMenu.Widgets.Add(mButtonFullscreen);
+ mMenu.Widgets.Add(mWidgetFactory.CreateLabel("Kamera"));
+ mMenu.Widgets.Add(mButtonCamera);
+ mMenu.Widgets.Add(mWidgetFactory.CreateLabel("Debug"));
+ mMenu.Widgets.Add(mButtonDebug);
+ mMenu.Widgets.Add(mWidgetFactory.CreateLabel("Sound"));
+ mMenu.Widgets.Add(mButtonMute);
+ mMenu.Widgets.Add(mWidgetFactory.CreateLabel("Lautstärke"));
+ mMenu.Widgets.Add(mButtonVolume);
+ mMenu.Widgets.Add(mWidgetFactory.CreateEmptyWidget());
+ mMenu.Widgets.Add(mButtonApply);
+ }
+
+ 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)
+ {
+ mMenu.HandleMouseEvent(mouseEvent);
+ return true;
+ }
+
+ /// <summary>
+ /// Draws this object using the given sprite batch.
+ /// </summary>
+ /// <param name="gameTime">a snapshot of the game time</param>
+ /// <param name="spriteBatch">the sprite batch to use for drawing
+ /// this object</param>
+ public override void Draw(GameTime gameTime, SpriteBatch spriteBatch)
+ {
+ var backgroundRectangle = new Rectangle((int)mMenu.Position.X,
+ (int)mMenu.Position.Y, (int)mMenu.Size.X, (int)mMenu.Size.Y);
+ backgroundRectangle.X -= 30;
+ backgroundRectangle.Y -= 30;
+ backgroundRectangle.Width += 60;
+ backgroundRectangle.Height += 60;
+
+ spriteBatch.Begin();
+ spriteBatch.Draw(mRectangle, backgroundRectangle, Color.LightGray);
+ spriteBatch.End();
+
+ mMenu.Draw(spriteBatch);
+ }
+
+ public override void Update(GameTime gameTime)
+ {
+ if (mButtonBack.IsClicked)
+ {
+ mMenuActions.Close(this);
+ }
+ else if (mButtonApply.IsClicked)
+ {
+ UpdateOptions();
+ mMenuActions.SaveOptions();
+ mMenuActions.ApplyOptions();
+ }
+
+ mMenu.Update();
+ }
+
+ private void UpdateOptions()
+ {
+ mOptionsManager.Options.IsFullScreen = mButtonFullscreen.SelectedIndex != 0;
+ mOptionsManager.Options.DebugMode = Options.DebugModes[mButtonDebug.SelectedIndex];
+ mOptionsManager.Options.Resolution = Options.Resolutions[mButtonSize.SelectedIndex];
+ mOptionsManager.Options.CameraType = Options.CameraTypes[mButtonCamera.SelectedIndex];
+ mOptionsManager.Options.IsMuted = mButtonMute.SelectedIndex == 0;
+ mOptionsManager.Options.Volume = Options.Volumes[mButtonVolume.SelectedIndex];
+ }
+
+ private static string GetCameraTypeString(CameraType cameraType)
+ {
+ switch (cameraType)
+ {
+ case CameraType.Centered:
+ return "Zentriert";
+ case CameraType.Scrolling:
+ return "Schiebend";
+ default:
+ return "Unkown";
+ }
+ }
+
+ private static string GetDebugModeString(DebugMode debugMode)
+ {
+ switch (debugMode)
+ {
+ case DebugMode.Off:
+ return "Aus";
+ case DebugMode.Fps:
+ return "FPS Zähler";
+ case DebugMode.Full:
+ return "An";
+ default:
+ return "Unknown";
+ }
+ }
+
+ private static string GetResolutionString(Point resolution)
+ {
+ return $"{resolution.X}x{resolution.Y}";
+ }
+
+ private static string GetVolumeString(int volume)
+ {
+ return $"{volume} %";
+ }
+ }
+}
diff --git a/V3/Screens/PauseScreen.cs b/V3/Screens/PauseScreen.cs
new file mode 100644
index 0000000..e7b679f
--- /dev/null
+++ b/V3/Screens/PauseScreen.cs
@@ -0,0 +1,140 @@
+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
+{
+ /// <summary>
+ /// The screen for the pause menu.
+ /// </summary>
+ // ReSharper disable once ClassNeverInstantiated.Global
+ public sealed class PauseScreen : AbstractScreen, IInitializable
+ {
+ private readonly ContentManager mContentManager;
+ private readonly GraphicsDeviceManager mGraphicsDeviceManager;
+ private readonly IMenu mMenu;
+ private readonly MenuActions mMenuActions;
+ private readonly WidgetFactory mWidgetFactory;
+
+ private Texture2D mRectangle;
+ private Button mButtonBack;
+ private Button mButtonSave;
+ private Button mButtonLoad;
+ private Button mButtonOptions;
+ private Button mButtonStatistics;
+ private Button mButtonAchievements;
+ private Button mButtonMain;
+ private Button mButtonExit;
+
+ /// <summary>
+ /// Creates a new pause screen.
+ /// </summary>
+ public PauseScreen(ContentManager contentManager,
+ GraphicsDeviceManager graphicsDeviceManager, VerticalMenu menu,
+ MenuActions menuActions, WidgetFactory widgetFactory)
+ : base(false, true)
+ {
+ mContentManager = contentManager;
+ mGraphicsDeviceManager = graphicsDeviceManager;
+ mMenu = menu;
+ mMenuActions = menuActions;
+ mWidgetFactory = widgetFactory;
+ }
+
+ public void Initialize()
+ {
+ mRectangle = mContentManager.Load<Texture2D>("Sprites/WhiteRectangle");
+
+ mButtonBack = mWidgetFactory.CreateButton("Zurück zum Spiel");
+ mButtonSave = mWidgetFactory.CreateButton("Spiel speichern");
+ mButtonLoad = mWidgetFactory.CreateButton("Spiel laden");
+ mButtonLoad.IsEnabled = mMenuActions.CanLoadGame();
+ mButtonStatistics = mWidgetFactory.CreateButton("Statistiken");
+ mButtonAchievements = mWidgetFactory.CreateButton("Erfolge");
+ mButtonOptions = mWidgetFactory.CreateButton("Optionen");
+ mButtonMain = mWidgetFactory.CreateButton("Hauptmenü");
+ mButtonExit = mWidgetFactory.CreateButton("Spiel schließen");
+
+ mMenu.Widgets.Add(mButtonBack);
+ mMenu.Widgets.Add(mButtonSave);
+ mMenu.Widgets.Add(mButtonLoad);
+ mMenu.Widgets.Add(mButtonOptions);
+ mMenu.Widgets.Add(mButtonStatistics);
+ mMenu.Widgets.Add(mButtonAchievements);
+ mMenu.Widgets.Add(mButtonMain);
+ mMenu.Widgets.Add(mButtonExit);
+ }
+
+ 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)
+ {
+ mMenu.HandleMouseEvent(mouseEvent);
+ return true;
+ }
+
+ /// <summary>
+ /// Draws this object using the given sprite batch.
+ /// </summary>
+ /// <param name="gameTime">a snapshot of the game time</param>
+ /// <param name="spriteBatch">the sprite batch to use for drawing
+ /// this object</param>
+ public override void Draw(GameTime gameTime, SpriteBatch spriteBatch)
+ {
+ spriteBatch.Begin();
+ spriteBatch.Draw(mRectangle, mGraphicsDeviceManager.GraphicsDevice.Viewport.Bounds, Color.Black * 0.7f);
+ spriteBatch.End();
+
+ mMenu.Draw(spriteBatch);
+ }
+
+ public override void Update(GameTime gameTime)
+ {
+ if (mButtonBack.IsClicked)
+ {
+ mMenuActions.Close(this);
+ }
+ else if (mButtonSave.IsClicked)
+ {
+ mMenuActions.SaveGame();
+ mMenuActions.Close(this);
+ }
+ else if (mButtonLoad.IsClicked)
+ {
+ mMenuActions.OpenLoadScreen();
+ }
+ else if (mButtonOptions.IsClicked)
+ {
+ mMenuActions.OpenOptionsScreen();
+ }
+ else if (mButtonStatistics.IsClicked)
+ {
+ mMenuActions.OpenStatisticsScreen();
+ }
+ else if (mButtonAchievements.IsClicked)
+ {
+ mMenuActions.OpenAchievementsScreen();
+ }
+ else if (mButtonMain.IsClicked)
+ {
+ mMenuActions.OpenMainScreen();
+ }
+ else if (mButtonExit.IsClicked)
+ {
+ mMenuActions.Exit();
+ }
+
+ mMenu.Update();
+ }
+ }
+}
diff --git a/V3/Screens/ScreenManager.cs b/V3/Screens/ScreenManager.cs
new file mode 100644
index 0000000..97c4e28
--- /dev/null
+++ b/V3/Screens/ScreenManager.cs
@@ -0,0 +1,164 @@
+using System.Collections.Generic;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Media;
+using V3.Input;
+
+namespace V3.Screens
+{
+ /// <summary>
+ /// Default implementation of IScreenManager.
+ /// </summary>
+ // ReSharper disable once ClassNeverInstantiated.Global
+ internal sealed class ScreenManager : IScreenManager
+ {
+ private readonly IInputManager mInputManager;
+ private readonly DebugScreen mDebugScreen;
+ private readonly ContentManager mContentManager;
+
+ private readonly Stack<IScreen> mScreens = new Stack<IScreen>();
+
+ /// <summary>
+ /// Creates a new screen manager using the given input manager.
+ /// </summary>
+ public ScreenManager(IInputManager inputManager, DebugScreen debugScreen, ContentManager contentManager)
+ {
+ mInputManager = inputManager;
+ mDebugScreen = debugScreen;
+ mContentManager = contentManager;
+ }
+
+ /// <summary>
+ /// Adds a screen to the foreground.
+ /// </summary>
+ /// <param name="screen">the screen to add in the foreground</param>
+ public void AddScreen(IScreen screen)
+ {
+ mScreens.Push(screen);
+#if NO_AUDIO
+#else
+ if (screen is MainScreen)
+ {
+ MediaPlayer.IsRepeating = true;
+ MediaPlayer.Play(mContentManager.Load<Song>("Sounds/Kosta_T_-_06"));
+ }
+ else if (screen is GameScreen)
+ {
+ MediaPlayer.IsRepeating = true;
+ MediaPlayer.Play(mContentManager.Load<Song>("Sounds/Afraid_to_Go"));
+
+ }
+ //else if (screen is PauseScreen)
+ //{
+ // mAbstractCreature.GetSelf();
+ // mAbstractCreature.mSoundEffectInstance.Stop();
+ // mAbstractCreature.mSoundEffectInstanceFight.Stop();
+ // mAbstractCreature.mSoundEffectInstanceHorse.Stop();
+ // mAbstractCreature.mSoundEffectInstanceKnight.Stop();
+ // mAbstractCreature.mSoundEffectInstanceMeatball.Stop();
+ //}
+#endif
+ }
+
+ /// <summary>
+ /// Removes the given screen if it is on the top of the screen stack.
+ /// </summary>
+ /// <param name="screen">the screen to remove</param>
+ public void RemoveScreen(IScreen screen)
+ {
+ if (mScreens.Count > 0 && screen.Equals(mScreens.Peek()))
+ {
+ mScreens.Pop();
+ }
+ }
+
+ /// <summary>
+ /// Clears the screen stack.
+ /// </summary>
+ public void Clear()
+ {
+ mScreens.Clear();
+ }
+
+ /// <summary>
+ /// Draws the top screen and, if enabled, the lower screens. The draw
+ /// order is from bottom to top, i. e. the lowest enabled screen is
+ /// drawn first, and the top screen is drawn last.
+ /// </summary>
+ /// <param name="gameTime">a snapshot of the game time</param>
+ /// <param name="spriteBatch">the sprite batch to use for drawing
+ /// </param>
+ public void Draw(GameTime gameTime, SpriteBatch spriteBatch)
+ {
+ var drawScreens = new Stack<IScreen>();
+ foreach (var screen in mScreens)
+ {
+ drawScreens.Push(screen);
+ if (!screen.DrawLower)
+ break;
+ }
+
+ foreach (var screen in drawScreens)
+ {
+ screen.Draw(gameTime, spriteBatch);
+ }
+ mDebugScreen.Draw(gameTime, spriteBatch);
+ }
+
+ /// <summary>
+ /// Updates the top screen and, if enabled, the lower screens. The
+ /// update order is from top to bottom, i. e. the lowest enabled screen
+ /// is drawn first, and the top screen is drawn last.
+ /// </summary>
+ /// <param name="gameTime">a snapshot of the game time</param>
+ public void Update(GameTime gameTime)
+ {
+ mInputManager.Update();
+ HandleInputEvents();
+
+ mDebugScreen.Update(gameTime);
+ var currentScreens = new Stack<IScreen>(new Stack<IScreen>(mScreens));
+ foreach (var screen in currentScreens)
+ {
+ screen.Update(gameTime);
+ if (!screen.UpdateLower)
+ break;
+ }
+ }
+
+ private void HandleInputEvents()
+ {
+ // We need to clone the stack as the input management methods
+ // might want to modify the screen stack. We need two stacks as
+ // each stack reverses the order.
+ var currentScreens = new Stack<IScreen>(new Stack<IScreen>(mScreens));
+ foreach (var keyEvent in mInputManager.KeyEvents)
+ {
+ foreach (var screen in currentScreens)
+ {
+ if (screen.HandleKeyEvent(keyEvent))
+ break;
+ }
+ }
+ foreach (var mouseEvent in mInputManager.MouseEvents)
+ {
+ foreach (var screen in currentScreens)
+ {
+ if (screen.HandleMouseEvent(mouseEvent))
+ break;
+ }
+ }
+ }
+
+ public GameScreen GetGameScreen()
+ {
+ foreach (var screen in mScreens)
+ {
+ if (screen is GameScreen)
+ return (GameScreen) screen;
+ }
+ return null;
+ }
+ }
+}
diff --git a/V3/Screens/StatisticsScreen.cs b/V3/Screens/StatisticsScreen.cs
new file mode 100644
index 0000000..90e0ff4
--- /dev/null
+++ b/V3/Screens/StatisticsScreen.cs
@@ -0,0 +1,186 @@
+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.Widgets;
+
+namespace V3.Screens
+{
+ /// <summary>
+ /// The screen for the statistics.
+ /// </summary>
+ // ReSharper disable once ClassNeverInstantiated.Global
+ public sealed class StatisticsScreen : AbstractScreen, IInitializable
+ {
+ private readonly ContentManager mContentManager;
+ private readonly IMenuFactory mMenuFactory;
+ private readonly MenuActions mMenuActions;
+ private readonly WidgetFactory mWidgetFactory;
+ private readonly AchievementsAndStatistics mAchievementsAndStatistics;
+
+ private Button mButtonBack;
+ private SelectButton mSelectMission;
+
+ private List<IMenu> mMenuList = new List<IMenu>();
+ private Texture2D mRectangle;
+
+ public StatisticsScreen(ContentManager contentManager, MenuActions menuActions, WidgetFactory widgetFactory,
+ IMenuFactory menuFactory, AchievementsAndStatistics achievementsAndStatistics)
+ : base(false, true)
+ {
+ mContentManager = contentManager;
+ mMenuActions = menuActions;
+ mWidgetFactory = widgetFactory;
+ mMenuFactory = menuFactory;
+ mAchievementsAndStatistics = achievementsAndStatistics;
+ }
+
+ public void Initialize()
+ {
+ mRectangle = mContentManager.Load<Texture2D>("Sprites/WhiteRectangle");
+
+ mButtonBack = mWidgetFactory.CreateButton("Zurück");
+ mSelectMission = mWidgetFactory.CreateSelectButton();
+
+ var menu = mMenuFactory.CreateFormMenu();
+ mMenuList.Add(menu);
+
+ menu.Widgets.Add(mWidgetFactory.CreateLabel("Auswahl"));
+ menu.Widgets.Add(mSelectMission);
+
+ menu.Widgets.Add(mWidgetFactory.CreateLabel("Zeit"));
+ menu.Widgets.Add(mWidgetFactory.CreateLabel(" " + string.Format("{0:T}",mAchievementsAndStatistics.mUsedTime)));
+
+ menu.Widgets.Add(mWidgetFactory.CreateLabel("Getötete Gegner"));
+ menu.Widgets.Add(mWidgetFactory.CreateLabel(" " + string.Format("{0:00000}", mAchievementsAndStatistics.mKilledCreatures)));
+
+ menu.Widgets.Add(mWidgetFactory.CreateLabel("Verlorene Einheiten"));
+ menu.Widgets.Add(mWidgetFactory.CreateLabel(" " + string.Format("{0:00000}", mAchievementsAndStatistics.mLostServants)));
+
+ menu.Widgets.Add(mWidgetFactory.CreateLabel("zurückgelegte Entfernung"));
+ menu.Widgets.Add(mWidgetFactory.CreateLabel(" " + string.Format("{0:00000}", mAchievementsAndStatistics.mWalkedDistance) + " m"));
+
+ menu.Widgets.Add(mWidgetFactory.CreateEmptyWidget());
+ menu.Widgets.Add(mButtonBack);
+
+ menu = mMenuFactory.CreateFormMenu();
+
+ mMenuList.Add(menu);
+
+ menu.Widgets.Add(mWidgetFactory.CreateLabel("Auswahl"));
+ menu.Widgets.Add(mSelectMission);
+
+ menu.Widgets.Add(mWidgetFactory.CreateLabel("Zeit"));
+ menu.Widgets.Add(mWidgetFactory.CreateLabel(" " + "00:00:00"));
+
+ menu.Widgets.Add(mWidgetFactory.CreateLabel("Getötete Gegner"));
+ menu.Widgets.Add(mWidgetFactory.CreateLabel(" " + "000000"));
+
+ menu.Widgets.Add(mWidgetFactory.CreateLabel("Verlorene Einheiten"));
+ menu.Widgets.Add(mWidgetFactory.CreateLabel(" " + "000000"));
+
+ menu.Widgets.Add(mWidgetFactory.CreateLabel("zurückgelegte Entfernung"));
+ menu.Widgets.Add(mWidgetFactory.CreateLabel(" " + "000000"));
+
+ menu.Widgets.Add(mWidgetFactory.CreateEmptyWidget());
+ menu.Widgets.Add(mButtonBack);
+
+ menu = mMenuFactory.CreateFormMenu();
+
+ mMenuList.Add(menu);
+
+ menu.Widgets.Add(mWidgetFactory.CreateLabel("Auswahl"));
+ menu.Widgets.Add(mSelectMission);
+
+ menu.Widgets.Add(mWidgetFactory.CreateLabel("Zeit"));
+ menu.Widgets.Add(mWidgetFactory.CreateLabel(" " + "00:00:00"));
+
+ menu.Widgets.Add(mWidgetFactory.CreateLabel("Getötete Gegner"));
+ menu.Widgets.Add(mWidgetFactory.CreateLabel(" " + "000000"));
+
+ menu.Widgets.Add(mWidgetFactory.CreateLabel("Verlorene Einheiten"));
+ menu.Widgets.Add(mWidgetFactory.CreateLabel(" " + "000000"));
+
+ menu.Widgets.Add(mWidgetFactory.CreateLabel("zurückgelegte Entfernung"));
+ menu.Widgets.Add(mWidgetFactory.CreateLabel(" " + "000000"));
+
+ menu.Widgets.Add(mWidgetFactory.CreateEmptyWidget());
+ menu.Widgets.Add(mButtonBack);
+
+ for (var i = 0; i < mMenuList.Count; i++)
+ mSelectMission.Values.Add($"Mission {i + 1}");
+
+ menu = mMenuFactory.CreateFormMenu();
+
+ mMenuList.Add(menu);
+
+ menu.Widgets.Add(mWidgetFactory.CreateLabel("Auswahl"));
+ menu.Widgets.Add(mSelectMission);
+
+ menu.Widgets.Add(mWidgetFactory.CreateLabel("Zeit"));
+ menu.Widgets.Add(mWidgetFactory.CreateLabel(" " + "00:00:00"));
+
+ menu.Widgets.Add(mWidgetFactory.CreateLabel("Getötete Gegner"));
+ menu.Widgets.Add(mWidgetFactory.CreateLabel(" " + "000000"));
+
+ menu.Widgets.Add(mWidgetFactory.CreateLabel("Verlorene Einheiten"));
+ menu.Widgets.Add(mWidgetFactory.CreateLabel(" " + "000000"));
+
+ menu.Widgets.Add(mWidgetFactory.CreateLabel("zurückgelegte Entfernung"));
+ menu.Widgets.Add(mWidgetFactory.CreateLabel(" " + "000000"));
+
+ menu.Widgets.Add(mWidgetFactory.CreateEmptyWidget());
+ menu.Widgets.Add(mButtonBack);
+
+ mSelectMission.Values.Add("Gesamt");
+ }
+
+ 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();
+ }
+
+ 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.LightGray);
+ spriteBatch.End();
+
+ GetCurrentMenu().Draw(spriteBatch);
+ }
+
+ private IMenu GetCurrentMenu()
+ {
+ return mMenuList[mSelectMission.SelectedIndex];
+ }
+ }
+}
diff --git a/V3/Screens/TechdemoScreen.cs b/V3/Screens/TechdemoScreen.cs
new file mode 100644
index 0000000..748c9a1
--- /dev/null
+++ b/V3/Screens/TechdemoScreen.cs
@@ -0,0 +1,325 @@
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input;
+using Ninject;
+using V3.Camera;
+using V3.Data;
+using V3.Effects;
+using V3.Input;
+using V3.Map;
+using V3.Objects;
+
+namespace V3.Screens
+{
+ // ReSharper disable once ClassNeverInstantiated.Global
+ public class TechdemoScreen : AbstractScreen, IInitializable
+ {
+ private enum Creatures
+ {
+ Empty, Zombie, Skeleton, Peasant, Knight
+ }
+
+ private Creatures mCreatePerKey;
+
+ 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 IEffectsManager mEffectsManager;
+ private readonly Selection mSelection;
+ private readonly Transformation mTransformation;
+ private readonly IMapManager mMapManager;
+ private readonly IObjectsManager mObjectsManager;
+ private readonly Pathfinder mPathfinder;
+ private readonly Texture2D mOnePixelTexture;
+ // Fields for handling mouse input.
+ private Point mInitialClickPosition;
+ private bool mLeftButtonPressed;
+ private bool mRightButtonPressed;
+ private Vector2 mRightButtonPosition;
+
+ /// <summary>
+ /// Creates a new game screen.
+ /// </summary>
+ public TechdemoScreen(IOptionsManager optionsManager, CameraManager cameraManager,
+ ContentManager contentManager, CreatureFactory creatureFactory,
+ GraphicsDeviceManager graphicsDeviceManager, IMapManager mapManager,
+ MenuActions menuActions, IObjectsManager objectsManager,
+ Pathfinder pathfinder, Selection selection, Transformation transformation,
+ IEffectsManager effectsManager) : base(false, false)
+ {
+ mMapManager = mapManager;
+ mObjectsManager = objectsManager;
+ mCameraManager = cameraManager;
+ mOptionsManager = optionsManager;
+ mContentManager = contentManager;
+ mCreatureFactory = creatureFactory;
+ mEffectsManager = effectsManager;
+ mTransformation = transformation;
+ mGraphicsDeviceManager = graphicsDeviceManager;
+ mMenuActions = menuActions;
+ mPathfinder = pathfinder;
+ mSelection = selection;
+ mOnePixelTexture = contentManager.Load<Texture2D>("Sprites/WhiteRectangle");
+ }
+
+
+ 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);
+ }
+ }
+ if (mouseEvent.ReleasedOnScreen)
+ {
+ var position = mouseEvent.PositionPressed.ToVector2() + mCameraManager.GetCamera().Location;
+ switch (mCreatePerKey)
+ {
+ case Creatures.Zombie:
+ mObjectsManager.CreateCreature(mCreatureFactory.CreateZombie(position, MovementDirection.S));
+ break;
+ case Creatures.Skeleton:
+ mObjectsManager.CreateCreature(mCreatureFactory.CreateSkeleton(position, MovementDirection.S));
+ break;
+ case Creatures.Peasant:
+ mObjectsManager.CreateCreature(mCreatureFactory.CreateMalePeasant(position, MovementDirection.S));
+ break;
+ case Creatures.Knight:
+ mObjectsManager.CreateCreature(mCreatureFactory.CreateKnight(position, MovementDirection.S));
+ break;
+ }
+ }
+ return true;
+ }
+
+ public void Initialize()
+ {
+ mMapManager.Load("techdemo");
+ mObjectsManager.Initialize(mMapManager);
+ mCameraManager.Initialize(mMapManager.SizeInPixel);
+ mPathfinder.LoadGrid(mMapManager.GetPathfindingGrid());
+ mTransformation.mSelection = mSelection;
+ mTransformation.LoadArea(mContentManager);
+
+ // Add creatures for testing purposes.
+ var necromancer = mCreatureFactory.CreateNecromancer(new Vector2(1592, 1609), MovementDirection.S);
+ var king = mCreatureFactory.CreateKing(new Vector2(1500, 200), MovementDirection.S);
+ mObjectsManager.CreatePlayerCharacter(necromancer);
+ mObjectsManager.CreateBoss(king);
+ int makeCreatureStrongerModifier = 100;
+ int makePeasantsNotSoMuchStrongerModifier = 10;
+ AddCreature<MalePeasant>(new Point(4), new Point(200, 2000), new Point(2800, 3000), makePeasantsNotSoMuchStrongerModifier);
+ AddCreature<FemalePeasant>(new Point(4), new Point(232, 2032), new Point(2800, 3000), makePeasantsNotSoMuchStrongerModifier);
+ AddCreature<Knight>(new Point(4), new Point(200, 200), new Point(2800, 1000), makeCreatureStrongerModifier);
+ AddCreature<KingsGuard>(new Point(4), new Point(232, 232), new Point(2800, 1000), makeCreatureStrongerModifier);
+ AddCreature<Zombie>(new Point(3), new Point(264, 264), new Point(2800, 1000), makeCreatureStrongerModifier);
+ AddCreature<Skeleton>(new Point(3), new Point(290, 290), new Point(2800, 1000), makeCreatureStrongerModifier);
+ AddCreature<Zombie>(new Point(4), new Point(264, 2064), new Point(2800, 3000), makeCreatureStrongerModifier);
+
+ mTransformation.ObjectsManager = mObjectsManager;
+ }
+
+ /// <summary>
+ /// Add a generic creature to Techdemo.
+ /// Using pixel coordinates for calculating start and end point of map.
+ /// </summary>
+ /// <typeparam name="T"></typeparam>
+ /// <param name="density">Density on X and Y axis. More creatures when lower.</param>
+ /// <param name="start">Start point for creating the creature batallion.</param>
+ /// <param name="end">At which point to stop creating creatures.</param>
+ /// <param name="makeStronger">Give more HP. Better for testing.</param>
+ private void AddCreature<T>(Point density, Point start, Point end, int makeStronger) where T:ICreature
+ {
+ var type = typeof(T);
+ for (int i = start.Y; i < end.Y; i += 32 * density.Y)
+ {
+ for (int j = start.X; j < end.X; j += 32 * density.X)
+ {
+ Vector2 position = new Vector2(j, i);
+ ICreature creature;
+ if (type == typeof(MalePeasant))
+ {
+ creature = mCreatureFactory.CreateMalePeasant(position, MovementDirection.S);
+ }
+ else if (type == typeof(FemalePeasant))
+ {
+ creature = mCreatureFactory.CreateFemalePeasant(position, MovementDirection.S);
+ }
+ else if (type == typeof(Skeleton))
+ {
+ creature = mCreatureFactory.CreateSkeleton(position, MovementDirection.S);
+ }
+ else if (type == typeof(Zombie))
+ {
+ creature = mCreatureFactory.CreateZombie(position, MovementDirection.S);
+ }
+ else if (type == typeof(Knight))
+ {
+ creature = mCreatureFactory.CreateKnight(position, MovementDirection.S);
+ }
+ else if (type == typeof(SkeletonHorse))
+ {
+ creature = mCreatureFactory.CreateSkeletonHorse(position, MovementDirection.S);
+ }
+ else if (type == typeof(Meatball))
+ {
+ creature = mCreatureFactory.CreateMeatball(position, MovementDirection.S);
+ }
+ else if (type == typeof(KingsGuard))
+ {
+ creature = mCreatureFactory.CreateKingsGuard(position, MovementDirection.S);
+ }
+ else if (type == typeof(SkeletonElite))
+ {
+ creature = mCreatureFactory.CreateSkeletonElite(position, MovementDirection.S);
+ }
+ else
+ {
+ creature = mCreatureFactory.CreateZombie(position, MovementDirection.S);
+ }
+ creature.Empower(makeStronger);
+ mObjectsManager.CreateCreature(creature);
+ }
+ }
+
+ }
+
+ public override bool HandleKeyEvent(IKeyEvent keyEvent)
+ {
+ if (keyEvent.KeyState == KeyState.Down)
+ {
+ Creatures createPerKey = Creatures.Empty;
+ switch (keyEvent.Key)
+ {
+ case Keys.Escape:
+ mMenuActions.OpenPauseScreen();
+ break;
+ case Keys.F1:
+ createPerKey = Creatures.Zombie;
+ break;
+ case Keys.F2:
+ createPerKey = Creatures.Skeleton;
+ break;
+ case Keys.F3:
+ createPerKey = Creatures.Peasant;
+ break;
+ case Keys.F4:
+ createPerKey = Creatures.Knight;
+ break;
+ case Keys.F5:
+ Rectangle cameraRectangle = mCameraManager.GetCamera().ScreenRectangle;
+ mEffectsManager.PlayOnce(new SmokeBig(), cameraRectangle.Center, cameraRectangle.Size);
+ mObjectsManager.ExposeTheLiving();
+ break;
+ case Keys.F6:
+ (mObjectsManager.PlayerCharacter as Necromancer)?.ChangeSex();
+ mEffectsManager.PlayOnce(new SmokeSmall(), mObjectsManager.PlayerCharacter.Position.ToPoint(), new Point(256));
+ break;
+ }
+ if (createPerKey == mCreatePerKey)
+ {
+ mCreatePerKey = Creatures.Empty;
+ }
+ else
+ {
+ mCreatePerKey = createPerKey;
+ }
+ }
+ return true;
+ }
+
+ /// <summary>
+ /// Updates the status of this object.
+ /// </summary>
+ /// <param name="gameTime">a snapshot of the game time</param>
+ public override void Update(GameTime gameTime)
+ {
+#if DEBUG
+#else
+ try
+ {
+#endif
+ mObjectsManager.Update(gameTime, mRightButtonPressed, mRightButtonPosition, mCameraManager.GetCamera());
+ mCameraManager.Update(mObjectsManager.PlayerCharacter);
+ mEffectsManager.Update(gameTime);
+
+ // Call for Transformations
+ mTransformation.Transform();
+
+ mSelection.UpdateSelection();
+#if DEBUG
+#else
+ }
+ catch (System.Exception e)
+ {
+ System.Console.WriteLine(e.Message);
+ }
+#endif
+ }
+
+ /// <summary>
+ /// Draws this object using the given sprite batch.
+ /// </summary>
+ /// <param name="gameTime">a snapshot of the game time</param>
+ /// <param name="spriteBatch">the sprite batch to use for drawing
+ /// this object</param>
+ 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);
+ if (mLeftButtonPressed)
+ mSelection.Draw(spriteBatch, mInitialClickPosition + mCameraManager.GetCamera().Location.ToPoint(), Mouse.GetState().Position + mCameraManager.GetCamera().Location.ToPoint());
+ if (mOptionsManager.Options.DebugMode == DebugMode.Full)
+ {
+ mMapManager.DrawPathfindingGrid(spriteBatch, mCameraManager.GetCamera());
+ mObjectsManager.DrawQuadtree(spriteBatch);
+ DrawLastSelection(spriteBatch, mSelection.LastSelection);
+ }
+ // Draws the selection rectangle when left mouse button is pressed.
+ spriteBatch.End();
+ }
+
+ private void DrawLastSelection(SpriteBatch spriteBatch, Rectangle selection)
+ {
+ spriteBatch.Draw(mOnePixelTexture, selection, new Color(Color.Black, 100));
+ }
+ }
+} \ No newline at end of file
diff --git a/V3/Screens/VictoryScreen.cs b/V3/Screens/VictoryScreen.cs
new file mode 100644
index 0000000..ffb2406
--- /dev/null
+++ b/V3/Screens/VictoryScreen.cs
@@ -0,0 +1,76 @@
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
+using Ninject;
+using V3.Input;
+
+namespace V3.Screens
+{
+ // ReSharper disable once ClassNeverInstantiated.Global
+ public sealed class VictoryScreen : AbstractScreen, IInitializable
+ {
+ private static TimeSpan sTotalDelay = TimeSpan.FromSeconds(1);
+
+ private readonly ContentManager mContentManager;
+ private readonly GraphicsDeviceManager mGraphicsDeviceManager;
+
+ private Rectangle mVictoryRectangle;
+ private Vector2 mFontCenter;
+ private Vector2 mCenter;
+ private SpriteFont mVictoryFont;
+ private Texture2D mRectangle;
+
+ private TimeSpan mDelayTimer = sTotalDelay;
+
+ /// <summary>
+ /// Creates a victory screen if the player defeats the boss enemy.
+ /// </summary>
+
+ public VictoryScreen(ContentManager contentManager,
+ GraphicsDeviceManager graphicsDeviceManager
+ )
+ : base(false, true)
+ {
+ mContentManager = contentManager;
+ mGraphicsDeviceManager = graphicsDeviceManager;
+ }
+
+ public override bool HandleKeyEvent(IKeyEvent keyEvent)
+ {
+ return false;
+ }
+
+ public void Initialize()
+ {
+ mRectangle = mContentManager.Load<Texture2D>("Sprites/WhiteRectangle");
+ mVictoryFont = mContentManager.Load<SpriteFont>("Fonts/VictoryFont");
+ }
+
+ public override void Update(GameTime gameTime)
+ {
+ var viewport = mGraphicsDeviceManager.GraphicsDevice.Viewport;
+ if (mDelayTimer > TimeSpan.Zero)
+ mDelayTimer -= gameTime.ElapsedGameTime;
+
+ mCenter = new Vector2(viewport.Width / 2f, viewport.Height / 2f);
+ mFontCenter = mVictoryFont.MeasureString("Die Rache ist euer!") / 2;
+ mVictoryRectangle = new Rectangle(0, (int)mCenter.Y - (int)mFontCenter.Y - 10, viewport.Width, (int)mFontCenter.Y * 2 - 10);
+ }
+
+ public override void Draw(GameTime gameTime, SpriteBatch spriteBatch)
+ {
+ float displayRatio = (float)(1 - mDelayTimer.TotalMilliseconds / sTotalDelay.TotalMilliseconds);
+ spriteBatch.Begin();
+ spriteBatch.Draw(mRectangle,
+ mVictoryRectangle,
+ Color.Black * 0.8f * displayRatio);
+
+ spriteBatch.DrawString(mVictoryFont,
+ "Die Rache ist euer!",
+ mCenter,
+ Color.DarkGoldenrod * displayRatio, 0, mFontCenter, 1.0f, SpriteEffects.None, 0.5f);
+ spriteBatch.End();
+ }
+ }
+ }
diff --git a/V3/UpdatesPerSecond.cs b/V3/UpdatesPerSecond.cs
new file mode 100644
index 0000000..e180be1
--- /dev/null
+++ b/V3/UpdatesPerSecond.cs
@@ -0,0 +1,55 @@
+using Microsoft.Xna.Framework;
+
+namespace V3
+{
+ /// <summary>
+ /// A class for telling when to do an update for events with a constant frequency.
+ /// </summary>
+ public sealed class UpdatesPerSecond
+ {
+ private double mTimeBetweenUpdates;
+ private double mTimeSinceLastUpdate;
+
+ /// <summary>
+ /// Initializes class.
+ /// </summary>
+ /// <param name="frequency">How many updates should be done per second.</param>
+ public UpdatesPerSecond(double frequency)
+ {
+ ChangeFrequency(frequency);
+ }
+
+ /// <summary>
+ /// Change update frequency.
+ /// </summary>
+ /// <param name="frequency">How many updates should be done per second.</param>
+ private void ChangeFrequency(double frequency)
+ {
+ mTimeBetweenUpdates = 1d / frequency;
+ }
+
+ /// <summary>
+ /// Tells if it is time to do an update.
+ /// </summary>
+ /// <param name="gameTime">Current game time.</param>
+ /// <returns></returns>
+ public bool IsItTime(GameTime gameTime)
+ {
+ mTimeSinceLastUpdate += gameTime.ElapsedGameTime.TotalSeconds;
+ if (mTimeSinceLastUpdate >= mTimeBetweenUpdates)
+ {
+ Reset();
+ return true;
+ }
+ return false;
+ }
+
+ /// <summary>
+ /// Reset internal timer for checking if update should be done.
+ /// </summary>
+ private void Reset()
+ {
+ mTimeSinceLastUpdate = 0;
+ }
+ }
+} \ No newline at end of file
diff --git a/V3/V3.csproj b/V3/V3.csproj
new file mode 100644
index 0000000..56f7461
--- /dev/null
+++ b/V3/V3.csproj
@@ -0,0 +1,498 @@
+<?xml version="1.0" encoding="utf-8"?>
+<Project ToolsVersion="4.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
+ <Import Project="$(MSBuildExtensionsPath)\MonoGame\v3.0\MonoGame.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\MonoGame\v3.0\MonoGame.Common.props')" />
+ <PropertyGroup>
+ <Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
+ <Platform Condition=" '$(Platform)' == '' ">x86</Platform>
+ <ProductVersion>8.0.30703</ProductVersion>
+ <SchemaVersion>2.0</SchemaVersion>
+ <ProjectGuid>{4C475FE4-ECB6-4D25-B7E6-0B773A736A24}</ProjectGuid>
+ <OutputType>WinExe</OutputType>
+ <AppDesignerFolder>Properties</AppDesignerFolder>
+ <RootNamespace>V3</RootNamespace>
+ <AssemblyName>V3</AssemblyName>
+ <FileAlignment>512</FileAlignment>
+ <MonoGamePlatform>DesktopGL</MonoGamePlatform>
+ <TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
+ <PublishUrl>publish\</PublishUrl>
+ <Install>true</Install>
+ <InstallFrom>Disk</InstallFrom>
+ <UpdateEnabled>false</UpdateEnabled>
+ <UpdateMode>Foreground</UpdateMode>
+ <UpdateInterval>7</UpdateInterval>
+ <UpdateIntervalUnits>Days</UpdateIntervalUnits>
+ <UpdatePeriodically>false</UpdatePeriodically>
+ <UpdateRequired>false</UpdateRequired>
+ <MapFileExtensions>true</MapFileExtensions>
+ <ApplicationRevision>0</ApplicationRevision>
+ <ApplicationVersion>1.0.0.%2a</ApplicationVersion>
+ <IsWebBootstrapper>false</IsWebBootstrapper>
+ <UseApplicationTrust>false</UseApplicationTrust>
+ <BootstrapperEnabled>true</BootstrapperEnabled>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|x86' ">
+ <PlatformTarget>x86</PlatformTarget>
+ <DebugSymbols>true</DebugSymbols>
+ <DebugType>full</DebugType>
+ <Optimize>false</Optimize>
+ <OutputPath>bin\$(MonoGamePlatform)\$(Platform)\$(Configuration)\</OutputPath>
+ <DefineConstants>TRACE;DEBUG;LINUX</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|x86' ">
+ <PlatformTarget>x86</PlatformTarget>
+ <DebugType>pdbonly</DebugType>
+ <Optimize>true</Optimize>
+ <OutputPath>bin\$(MonoGamePlatform)\$(Platform)\$(Configuration)\</OutputPath>
+ <DefineConstants>TRACE;LINUX NEWMAP</DefineConstants>
+ <ErrorReport>prompt</ErrorReport>
+ <WarningLevel>4</WarningLevel>
+ </PropertyGroup>
+ <PropertyGroup>
+ <ApplicationIcon>Icon.ico</ApplicationIcon>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Pool|x86'">
+ <DebugSymbols>true</DebugSymbols>
+ <OutputPath>bin\x86\Pool\</OutputPath>
+ <DefineConstants>TRACE;DEBUG;LINUX NO_AUDIO</DefineConstants>
+ <DebugType>full</DebugType>
+ <PlatformTarget>x86</PlatformTarget>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+ <Prefer32Bit>true</Prefer32Bit>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Feature|x86'">
+ <DebugSymbols>true</DebugSymbols>
+ <OutputPath>bin\x86\Feature\</OutputPath>
+ <DefineConstants>TRACE;DEBUG;LINUX TEST_OBJECTSMANAGER NEW_MUSIC</DefineConstants>
+ <DebugType>full</DebugType>
+ <PlatformTarget>x86</PlatformTarget>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+ <Prefer32Bit>true</Prefer32Bit>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Old Debug|x86'">
+ <DebugSymbols>true</DebugSymbols>
+ <OutputPath>bin\x86\Old Debug\</OutputPath>
+ <DefineConstants>TRACE;DEBUG;LINUX</DefineConstants>
+ <DebugType>full</DebugType>
+ <PlatformTarget>x86</PlatformTarget>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+ <Prefer32Bit>true</Prefer32Bit>
+ </PropertyGroup>
+ <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Larger Map|x86'">
+ <DebugSymbols>true</DebugSymbols>
+ <OutputPath>bin\x86\Larger Map\</OutputPath>
+ <DefineConstants>TRACE;DEBUG;LINUX NEWMAP</DefineConstants>
+ <DebugType>full</DebugType>
+ <PlatformTarget>x86</PlatformTarget>
+ <ErrorReport>prompt</ErrorReport>
+ <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet>
+ <Prefer32Bit>true</Prefer32Bit>
+ </PropertyGroup>
+ <ItemGroup>
+ <Compile Include="AchievementsAndStatistics.cs" />
+ <Compile Include="Bindings.cs" />
+ <Compile Include="AI\ActionState.cs" />
+ <Compile Include="AI\AiState.cs" />
+ <Compile Include="AI\IAction.cs" />
+ <Compile Include="AI\IAiPlayer.cs" />
+ <Compile Include="AI\IStrategy.cs" />
+ <Compile Include="AI\IWorldView.cs" />
+ <Compile Include="AI\Internal\AbstractAction.cs" />
+ <Compile Include="AI\Internal\AiPlayer.cs" />
+ <Compile Include="AI\Internal\AttackStrategy.cs" />
+ <Compile Include="AI\Internal\IActionFactory.cs" />
+ <Compile Include="AI\Internal\MoveAction.cs" />
+ <Compile Include="AI\Internal\SpawnAction.cs" />
+ <Compile Include="AI\Internal\WorldView.cs" />
+ <Compile Include="Camera\CameraCentered.cs" />
+ <Compile Include="Camera\CameraManager.cs" />
+ <Compile Include="Camera\CameraScrolling.cs" />
+ <Compile Include="Camera\CameraType.cs" />
+ <Compile Include="Camera\ICamera.cs" />
+ <Compile Include="Data\DebugMode.cs" />
+ <Compile Include="Data\IGameStateManager.cs" />
+ <Compile Include="Data\Internal\GameStateManager.cs" />
+ <Compile Include="Data\Internal\OptionsManager.cs" />
+ <Compile Include="Data\Internal\PathManager.cs" />
+ <Compile Include="Data\Internal\SaveGame.cs" />
+ <Compile Include="Data\Internal\SaveGameManager.cs" />
+ <Compile Include="Data\IOptionsManager.cs" />
+ <Compile Include="Data\Options.cs" />
+ <Compile Include="Data\ISaveGame.cs" />
+ <Compile Include="Data\ISaveGameManager.cs" />
+ <Compile Include="Effects\AbstractEffect.cs" />
+ <Compile Include="Effects\BloodBang.cs" />
+ <Compile Include="Effects\BloodExplosion.cs" />
+ <Compile Include="Effects\BloodFountain.cs" />
+ <Compile Include="Effects\EffectsManager.cs" />
+ <Compile Include="Effects\Explosion.cs" />
+ <Compile Include="Effects\HorseEffect.cs" />
+ <Compile Include="Effects\IEffect.cs" />
+ <Compile Include="Effects\IEffectsManager.cs" />
+ <Compile Include="Effects\Quake.cs" />
+ <Compile Include="Effects\SmokeBig.cs" />
+ <Compile Include="Effects\SmokeMedium.cs" />
+ <Compile Include="Effects\SmokeSmall.cs" />
+ <Compile Include="Ellipse.cs" />
+ <Compile Include="Faction.cs" />
+ <Compile Include="Input\IInputManager.cs" />
+ <Compile Include="Input\IKeyEvent.cs" />
+ <Compile Include="Input\IMouseEvent.cs" />
+ <Compile Include="Data\IPathManager.cs" />
+ <Compile Include="Input\Internal\InputManager.cs" />
+ <Compile Include="Input\Internal\KeyEvent.cs" />
+ <Compile Include="Input\Internal\MouseEvent.cs" />
+ <Compile Include="Map\AbstractLayer.cs" />
+ <Compile Include="Map\Area.cs" />
+ <Compile Include="Map\Constants.cs" />
+ <Compile Include="Map\FloorLayer.cs" />
+ <Compile Include="Map\FogOfWar.cs" />
+ <Compile Include="Map\IMapManager.cs" />
+ <Compile Include="Map\MapManager.cs" />
+ <Compile Include="Map\ObjectLayer.cs" />
+ <Compile Include="Map\Pathfinder.cs" />
+ <Compile Include="Map\PathfindingGrid.cs" />
+ <Compile Include="Map\SearchNode.cs" />
+ <Compile Include="Map\TiledParser.cs" />
+ <Compile Include="Map\Tileset.cs" />
+ <Compile Include="Node.cs" />
+ <Compile Include="Objects\AbstractBuilding.cs" />
+ <Compile Include="Objects\Arrow.cs" />
+ <Compile Include="Objects\BuildingState.cs" />
+ <Compile Include="Objects\Castle.cs" />
+ <Compile Include="Objects\FemalePeasant.cs" />
+ <Compile Include="Objects\Forge.cs" />
+ <Compile Include="Objects\IBuilding.cs" />
+ <Compile Include="Objects\IObjectsManager.cs" />
+ <Compile Include="Objects\King.cs" />
+ <Compile Include="Objects\KingsGuard.cs" />
+ <Compile Include="Objects\Knight.cs" />
+ <Compile Include="Objects\Meatball.cs" />
+ <Compile Include="Objects\Movement\CountStepsMovement.cs" />
+ <Compile Include="Objects\Movement\IMovable.cs" />
+ <Compile Include="Objects\Movement\PlayerMovement.cs" />
+ <Compile Include="Objects\ObjectsManager.cs" />
+ <Compile Include="Objects\Prince.cs" />
+ <Compile Include="Objects\IdGenerator.cs" />
+ <Compile Include="Objects\Selection.cs" />
+ <Compile Include="Objects\SkeletonElite.cs" />
+ <Compile Include="Objects\SkeletonHorse.cs" />
+ <Compile Include="Objects\Sprite\ArrowSprite.cs" />
+ <Compile Include="Objects\Sprite\BucklerFemaleSprite.cs" />
+ <Compile Include="Objects\Sprite\BucklerSprite.cs" />
+ <Compile Include="Objects\Sprite\ChainFemaleSprite.cs" />
+ <Compile Include="Objects\Sprite\ChainSprite.cs" />
+ <Compile Include="Objects\Sprite\ClothFemaleSprite.cs" />
+ <Compile Include="Objects\Sprite\ClothSprite.cs" />
+ <Compile Include="Objects\Sprite\EquipmentType.cs" />
+ <Compile Include="Objects\Sprite\HeadBaldSprite.cs" />
+ <Compile Include="Objects\Sprite\HeadChainFemaleSprite.cs" />
+ <Compile Include="Objects\Sprite\HeadChainSprite.cs" />
+ <Compile Include="Objects\Sprite\HeadFemaleSprite.cs" />
+ <Compile Include="Objects\Sprite\HeadPlateFemaleSprite.cs" />
+ <Compile Include="Objects\Sprite\HeadPlateSprite.cs" />
+ <Compile Include="Objects\Sprite\HeadSprite.cs" />
+ <Compile Include="Objects\Sprite\KingSprite.cs" />
+ <Compile Include="Objects\Sprite\LongswordFemaleSprite.cs" />
+ <Compile Include="Objects\Sprite\LongswordSprite.cs" />
+ <Compile Include="Objects\Sprite\MeatballSprite.cs" />
+ <Compile Include="Objects\Sprite\NecromancerFemaleSprite.cs" />
+ <Compile Include="Objects\Sprite\NudeFemaleSprite.cs" />
+ <Compile Include="Objects\Sprite\NudeSprite.cs" />
+ <Compile Include="Objects\Sprite\PlateFemaleSprite.cs" />
+ <Compile Include="Objects\Sprite\PlateSprite.cs" />
+ <Compile Include="Objects\Sprite\PrinceSprite.cs" />
+ <Compile Include="Objects\Sprite\ShieldFemaleSprite.cs" />
+ <Compile Include="Objects\Sprite\ShieldSprite.cs" />
+ <Compile Include="Objects\Sprite\ShortswordFemaleSprite.cs" />
+ <Compile Include="Objects\Sprite\ShortswordSprite.cs" />
+ <Compile Include="Objects\Sprite\SkeletonArcherSprite.cs" />
+ <Compile Include="Objects\Sprite\SkeletonEliteSprite.cs" />
+ <Compile Include="Objects\Sprite\SkeletonHorseSprite.cs" />
+ <Compile Include="Objects\Sprite\SkeletonRiderSprite.cs" />
+ <Compile Include="Objects\Sprite\StaffFemaleSprite.cs" />
+ <Compile Include="Objects\Sprite\StaffSprite.cs" />
+ <Compile Include="Objects\Sprite\ZombieWithClubSprite.cs" />
+ <Compile Include="Objects\TextureObject.cs" />
+ <Compile Include="Objects\Transformation.cs" />
+ <Compile Include="Objects\Woodhouse.cs" />
+ <Compile Include="Program.cs" />
+ <Compile Include="Quadtree.cs" />
+ <Compile Include="Screens\AchievementsScreen.cs" />
+ <Compile Include="Screens\DeathScreen.cs" />
+ <Compile Include="Screens\DebugScreen.cs" />
+ <Compile Include="Screens\FpsCounter.cs" />
+ <Compile Include="Screens\HudScreen.cs" />
+ <Compile Include="Screens\IScreenManager.cs" />
+ <Compile Include="Screens\LoadScreen.cs" />
+ <Compile Include="Screens\StatisticsScreen.cs" />
+ <Compile Include="Screens\TechdemoScreen.cs" />
+ <Compile Include="Screens\VictoryScreen.cs" />
+ <Compile Include="UpdatesPerSecond.cs" />
+ <Compile Include="V3Game.cs" />
+ <Compile Include="Data\GameState.cs" />
+ <Compile Include="Input\IMouseEventHandler.cs" />
+ <Compile Include="Input\MouseButton.cs" />
+ <Compile Include="Objects\AbstractCreature.cs" />
+ <Compile Include="Objects\Sprite\AbstractSpriteCreature.cs" />
+ <Compile Include="Objects\CreatureFactory.cs" />
+ <Compile Include="Objects\IBasicCreatureFactory.cs" />
+ <Compile Include="Objects\ICreature.cs" />
+ <Compile Include="Objects\IGameObject.cs" />
+ <Compile Include="Objects\Sprite\ISpriteCreature.cs" />
+ <Compile Include="Objects\Movement.cs" />
+ <Compile Include="Objects\Necromancer.cs" />
+ <Compile Include="Objects\MalePeasant.cs" />
+ <Compile Include="Objects\Sprite\NecromancerSprite.cs" />
+ <Compile Include="Objects\Skeleton.cs" />
+ <Compile Include="Objects\Sprite\SkeletonSprite.cs" />
+ <Compile Include="Objects\Zombie.cs" />
+ <Compile Include="Objects\Sprite\ZombieSprite.cs" />
+ <Compile Include="Screens\AbstractScreen.cs" />
+ <Compile Include="Screens\GameScreen.cs" />
+ <Compile Include="Screens\IDrawable.cs" />
+ <Compile Include="Screens\IScreen.cs" />
+ <Compile Include="Screens\IScreenFactory.cs" />
+ <Compile Include="Screens\IUpdatable.cs" />
+ <Compile Include="Screens\MainScreen.cs" />
+ <Compile Include="Screens\MenuActions.cs" />
+ <Compile Include="Screens\OptionsScreen.cs" />
+ <Compile Include="Screens\PauseScreen.cs" />
+ <Compile Include="Screens\ScreenManager.cs" />
+ <Compile Include="Properties\AssemblyInfo.cs" />
+ <Compile Include="Widgets\AbstractMenu.cs" />
+ <Compile Include="Widgets\AbstractTextWidget.cs" />
+ <Compile Include="Widgets\AchievementBox.cs" />
+ <Compile Include="Widgets\Button.cs" />
+ <Compile Include="Widgets\EmptyWidget.cs" />
+ <Compile Include="Widgets\FormMenu.cs" />
+ <Compile Include="Widgets\HorizontalOrientation.cs" />
+ <Compile Include="Widgets\IBasicWidgetFactory.cs" />
+ <Compile Include="Widgets\IClickable.cs" />
+ <Compile Include="Widgets\IImageWidget.cs" />
+ <Compile Include="Widgets\IMenu.cs" />
+ <Compile Include="Widgets\IMenuFactory.cs" />
+ <Compile Include="Widgets\ISelectable.cs" />
+ <Compile Include="Widgets\ITextWidget.cs" />
+ <Compile Include="Widgets\IWidget.cs" />
+ <Compile Include="Widgets\Label.cs" />
+ <Compile Include="Widgets\SelectButton.cs" />
+ <Compile Include="Widgets\VerticalMenu.cs" />
+ <Compile Include="Widgets\WidgetFactory.cs" />
+ </ItemGroup>
+ <ItemGroup>
+ <Reference Include="Castle.Core, Version=3.2.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL">
+ <HintPath>..\packages\Castle.Core.3.2.0\lib\net45\Castle.Core.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="Ninject, Version=3.2.0.0, Culture=neutral, PublicKeyToken=c7192dc5380945e7, processorArchitecture=MSIL">
+ <HintPath>..\packages\Ninject.3.2.2.0\lib\net45-full\Ninject.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="Ninject.Extensions.Factory, Version=3.2.0.0, Culture=neutral, PublicKeyToken=c7192dc5380945e7, processorArchitecture=MSIL">
+ <HintPath>..\packages\Ninject.Extensions.Factory.3.2.1.0\lib\net45-full\Ninject.Extensions.Factory.dll</HintPath>
+ <Private>True</Private>
+ </Reference>
+ <Reference Include="OpenTK">
+ <HintPath>$(MonoGameInstallDirectory)\MonoGame\v3.0\Assemblies\DesktopGL\OpenTK.dll</HintPath>
+ </Reference>
+ <Reference Include="NVorbis">
+ <HintPath>$(MonoGameInstallDirectory)\MonoGame\v3.0\Assemblies\DesktopGL\NVorbis.dll</HintPath>
+ </Reference>
+ <Reference Include="MonoGame.Framework">
+ <HintPath>$(MonoGameInstallDirectory)\MonoGame\v3.0\Assemblies\DesktopGL\MonoGame.Framework.dll</HintPath>
+ </Reference>
+ <Reference Include="System" />
+ <Reference Include="System.Xml" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="CONTROLS.md">
+ <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+ </None>
+ <EmbeddedResource Include="Icon.ico" />
+ <Content Include="Content\Buttons\Button-01.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="Content\Buttons\Button-01_Pressed.png" />
+ <Content Include="Content\Buttons\Button-02.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="Content\Buttons\Button-02_Pressed.png" />
+ <Content Include="Content\Buttons\Button-03.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="Content\Buttons\Button-03_Pressed.png" />
+ <Content Include="Content\Buttons\Button-04.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="Content\Buttons\Button-04_Pressed.png" />
+ <Content Include="Content\Buttons\Button-05.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="Content\Buttons\Button-05_Pressed.png" />
+ <Content Include="Content\Buttons\Button-06.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="Content\Buttons\Button-06_Pressed.png" />
+ <Content Include="Content\Buttons\Button-07.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="Content\Buttons\Button-07_Pressed.png" />
+ <Content Include="Content\Effects\blood_hit_01.png" />
+ <Content Include="Content\Effects\blood_hit_02.png" />
+ <Content Include="Content\Effects\blood_hit_03.png" />
+ <Content Include="Content\Effects\blood_hit_04.png" />
+ <Content Include="Content\Effects\blood_hit_05.png" />
+ <Content Include="Content\Effects\blood_hit_06.png" />
+ <Content Include="Content\Effects\blood_hit_08.png" />
+ <Content Include="Content\Effects\explosion.png" />
+ <Content Include="Content\Effects\particlefx_03.png" />
+ <Content Include="Content\Effects\particlefx_04.png" />
+ <Content Include="Content\Effects\particlefx_05.png" />
+ <Content Include="Content\Effects\quake.png" />
+ <Content Include="Content\Menu\arrow_white.png">
+ <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+ </Content>
+ <Content Include="Content\Menu\mainscreen.jpg" />
+ <Content Include="Content\Menu\Titel.png" />
+ <Content Include="Content\Sounds\Afraid_to_Go.mp3" />
+ <Content Include="Content\Sounds\explode.wav" />
+ <Content Include="Content\Sounds\explodemini.wav" />
+ <Content Include="Content\Sounds\horse.wav" />
+ <Content Include="Content\Sounds\Knight.wav" />
+ <Content Include="Content\Sounds\Kosta_T_-_06.mp3" />
+ <Content Include="Content\Sounds\Monster_Gigante-Doberman-1334685792.wav" />
+ <Content Include="Content\Sounds\Mummy_Zombie-SoundBible.wav" />
+ <Content Include="Content\Sounds\punch.wav" />
+ <Content Include="Content\Sounds\SkeletonHorse.wav" />
+ <Content Include="Content\Sounds\walking.wav" />
+ <Content Include="Content\Sources\horse_paint.png" />
+ <Content Include="Content\Sources\horse_paint_sc.png" />
+ <Content Include="Content\Sources\horse_tack.png" />
+ <Content Include="Content\Sources\king_head.png" />
+ <Content Include="Content\Sources\SkeletonHorse.png" />
+ <Content Include="Content\Sources\SkeletonRider.png" />
+ <Content Include="Content\Sources\skeleton_horse.png" />
+ <Content Include="Content\Sources\the_triumph_of_death.jpg" />
+ <Content Include="Content\Sources\ZombieWithClub.png" />
+ <Content Include="Content\Sprites\arrows.png" />
+ <Content Include="Content\Sprites\buckler.png" />
+ <Content Include="Content\Sprites\buckler_female.png" />
+ <Content Include="Content\Sprites\chain.png" />
+ <Content Include="Content\Sprites\chain_female.png" />
+ <Content Include="Content\Sprites\cloth.png" />
+ <Content Include="Content\Sprites\cloth_female.png" />
+ <Content Include="Content\Sprites\cloud.png" />
+ <Content Include="Content\Sprites\Ellipse.png" />
+ <Content Include="Content\Sprites\fleischklops.png" />
+ <Content Include="Content\Sprites\fog.png" />
+ <Content Include="Content\Sprites\head.png" />
+ <Content Include="Content\Sprites\head_bald.png" />
+ <Content Include="Content\Sprites\head_chain.png" />
+ <Content Include="Content\Sprites\head_chain_female.png" />
+ <Content Include="Content\Sprites\head_female.png" />
+ <Content Include="Content\Sprites\head_plate.png" />
+ <Content Include="Content\Sprites\head_plate_female.png" />
+ <Content Include="Content\Sprites\king.png" />
+ <Content Include="Content\Sprites\longsword.png" />
+ <Content Include="Content\Sprites\longsword_female.png" />
+ <Content Include="Content\Sprites\necromancer.png" />
+ <Content Include="Content\Sprites\necromancer_female.png" />
+ <Content Include="Content\Sprites\nude.png" />
+ <Content Include="Content\Sprites\nude_female.png" />
+ <Content Include="Content\Sprites\plate.png" />
+ <Content Include="Content\Sprites\plate_female.png" />
+ <Content Include="Content\Sprites\prince.png" />
+ <Content Include="Content\Sprites\selection.png" />
+ <Content Include="Content\Sprites\shield.png" />
+ <Content Include="Content\Sprites\shield_female.png" />
+ <Content Include="Content\Sprites\shortsword.png" />
+ <Content Include="Content\Sprites\shortsword_female.png" />
+ <Content Include="Content\Sprites\skeleton.png" />
+ <Content Include="Content\Sprites\skeleton_archer.png" />
+ <Content Include="Content\Sprites\skeleton_elite.png" />
+ <Content Include="Content\Sprites\skeleton_horse.png" />
+ <Content Include="Content\Sprites\skeleton_rider.png" />
+ <Content Include="Content\Sprites\staff.png" />
+ <Content Include="Content\Sprites\staff_female.png" />
+ <Content Include="Content\Sprites\WhiteRectangle.png" />
+ <Content Include="Content\Sprites\zombie.png" />
+ <Content Include="Content\Sprites\zombie_club.png" />
+ <Content Include="Content\Textures\castle.png" />
+ <Content Include="Content\Textures\EmptyPixel.png" />
+ <Content Include="Content\Textures\grassland.png" />
+ <Content Include="Content\Textures\grassland_trees.png" />
+ <Content Include="Content\Textures\grassland_water.png" />
+ <Content Include="Content\Textures\houses_front.png" />
+ <Content Include="Content\Textures\houses_rear.png" />
+ <Content Include="Content\Textures\medieval_building_tiles.png" />
+ <Content Include="Content\Textures\pathfinder.png" />
+ <None Include="CREDITS.md">
+ <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+ </None>
+ <Content Include="OpenTK.dll.config">
+ <CopyToOutputDirectory>Always</CopyToOutputDirectory>
+ </Content>
+ </ItemGroup>
+ <ItemGroup>
+ <MonoGameContentReference Include="Content\Content.mgcb" />
+ </ItemGroup>
+ <ItemGroup>
+ <None Include="ClassDiagram1.cd" />
+ <None Include="Content\Fonts\Blutschrift.ttf" />
+ <None Include="Content\Fonts\DeathFont.spritefont" />
+ <None Include="Content\Fonts\DejaVuSans.ttf" />
+ <None Include="Content\Fonts\grabstein.ttf" />
+ <None Include="Content\Fonts\MenuFont.spritefont" />
+ <None Include="Content\Fonts\Siegesschriftzug.ttf" />
+ <None Include="Content\Fonts\UnitFont.spritefont" />
+ <None Include="Content\Fonts\VictoryFont.spritefont" />
+ <None Include="Content\Maps\map_grassland.tmx">
+ <SubType>Designer</SubType>
+ </None>
+ <None Include="Content\Maps\techdemo.tmx" />
+ <None Include="Content\Maps\work_in_progress.tmx">
+ <SubType>Designer</SubType>
+ </None>
+ <None Include="Content\Sounds\explosion1.ogg" />
+ <None Include="Content\Sounds\impactsplat01.ogg" />
+ <None Include="Content\Sources\castle.xcf" />
+ <None Include="Content\Sources\create_spritesheet.sh" />
+ <None Include="Content\Sources\fleischklops.blend" />
+ <None Include="Content\Sources\fleischklops.xcf" />
+ <None Include="Content\Sources\Horse.blend" />
+ <None Include="Content\Sources\houses_front.xcf" />
+ <None Include="Content\Sources\houses_rear.xcf" />
+ <None Include="Content\Sources\human_construction_set.xcf" />
+ <None Include="Content\Sources\human_construction_set_female.xcf" />
+ <None Include="Content\Sources\king.blend" />
+ <None Include="Content\Sources\necromancer.xcf" />
+ <None Include="Content\Sources\pathfinder.xcf" />
+ <None Include="Content\Sources\prince.blend" />
+ <None Include="Content\Sources\prince.xcf" />
+ <None Include="Content\Sources\selection.xcf" />
+ <None Include="Content\Sources\Skeleton.blend" />
+ <None Include="Content\Sources\SkeletonHorse.blend" />
+ <None Include="Content\Sources\SkeletonRider.blend" />
+ <None Include="Content\Sources\zombie.blend" />
+ <None Include="packages.config" />
+ </ItemGroup>
+ <ItemGroup>
+ <BootstrapperPackage Include=".NETFramework,Version=v4.5">
+ <Visible>False</Visible>
+ <ProductName>Microsoft .NET Framework 4.5 %28x86 and x64%29</ProductName>
+ <Install>true</Install>
+ </BootstrapperPackage>
+ <BootstrapperPackage Include="Microsoft.Net.Framework.3.5.SP1">
+ <Visible>False</Visible>
+ <ProductName>.NET Framework 3.5 SP1</ProductName>
+ <Install>false</Install>
+ </BootstrapperPackage>
+ </ItemGroup>
+ <Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
+ <Import Project="$(MSBuildExtensionsPath)\MonoGame\v3.0\MonoGame.Content.Builder.targets" />
+</Project> \ No newline at end of file
diff --git a/V3/V3Game.cs b/V3/V3Game.cs
new file mode 100644
index 0000000..ea7abbf
--- /dev/null
+++ b/V3/V3Game.cs
@@ -0,0 +1,78 @@
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using Ninject;
+using V3.Data;
+using V3.Screens;
+
+namespace V3
+{
+ /// <summary>
+ /// This is the main type for your game.
+ /// </summary>
+ public sealed class V3Game : Game
+ {
+ private readonly IKernel mKernel;
+ private SpriteBatch mSpriteBatch;
+ private IScreenManager mScreenManager;
+ private IScreen mMainScreen;
+ //private float mReculate = 1.0f;
+ /// <summary>
+ /// Creates a new V3 game instance.
+ /// </summary>
+ public V3Game()
+ {
+ mKernel = new StandardKernel(new Bindings(this, new GraphicsDeviceManager(this)));
+ IsMouseVisible = true;
+ }
+
+ /// <summary>
+ /// Allows the game to perform any initialization it needs to before starting to run.
+ /// This is where it can query for any required services and load any non-graphic
+ /// related content. Calling base.Initialize will enumerate through any components
+ /// and initialize them as well.
+ /// </summary>
+ protected override void Initialize()
+ {
+ Content.RootDirectory = "Content";
+ mKernel.Get<IPathManager>().CreateMissingDirectories();
+ mScreenManager = mKernel.Get<IScreenManager>();
+ base.Initialize();
+ }
+
+ /// <summary>
+ /// LoadContent will be called once per game and is the place to load
+ /// all of your content.
+ /// </summary>
+ protected override void LoadContent()
+ {
+ // Create a new SpriteBatch, which can be used to draw textures.
+ mSpriteBatch = new SpriteBatch(GraphicsDevice);
+ mMainScreen = mKernel.Get<IScreenFactory>().CreateMainScreen();
+ mScreenManager.AddScreen(mMainScreen);
+
+ }
+
+ /// <summary>
+ /// Allows the game to run logic such as updating the world,
+ /// checking for collisions, gathering input, and playing audio.
+ /// It delegates the update to the screen manager.
+ /// </summary>
+ /// <param name="gameTime">Provides a snapshot of timing values.</param>
+ protected override void Update(GameTime gameTime)
+ {
+ mScreenManager.Update(gameTime);
+ base.Update(gameTime);
+ }
+
+ /// <summary>
+ /// This is called when the game should draw itself. It delegates the
+ /// drawing to the screen manager.
+ /// </summary>
+ /// <param name="gameTime">Provides a snapshot of timing values.</param>
+ protected override void Draw(GameTime gameTime)
+ {
+ mScreenManager.Draw(gameTime, mSpriteBatch);
+ base.Draw(gameTime);
+ }
+ }
+}
diff --git a/V3/Widgets/AbstractMenu.cs b/V3/Widgets/AbstractMenu.cs
new file mode 100644
index 0000000..f179b5e
--- /dev/null
+++ b/V3/Widgets/AbstractMenu.cs
@@ -0,0 +1,96 @@
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input;
+using System.Collections.Generic;
+using System.Linq;
+using V3.Input;
+
+namespace V3.Widgets
+{
+ /// <summary>
+ /// An abstract menu that handles the updating and drawing of widgtes.
+ /// </summary>
+ public abstract class AbstractMenu : IMenu
+ {
+ public List<IWidget> Widgets { get; } = new List<IWidget>();
+ public Vector2 Size { get; private set; }
+ public Vector2 Position { get; private set; }
+
+ private readonly GraphicsDeviceManager mGraphicsDeviceManager;
+
+ protected AbstractMenu(GraphicsDeviceManager graphicsDeviceManager)
+ {
+ mGraphicsDeviceManager = graphicsDeviceManager;
+ }
+
+ public void HandleMouseEvent(IMouseEvent mouseEvent)
+ {
+ foreach (var clickable in Widgets.OfType<IClickable>())
+ clickable.HandleMouseEvent(mouseEvent);
+ }
+
+ public void Draw(SpriteBatch spriteBatch)
+ {
+ UpdateWidgetRelativePositions();
+ UpdateWidgetAbsolutePositions();
+ spriteBatch.Begin();
+ Widgets.ForEach(w => w.Draw(spriteBatch));
+ spriteBatch.End();
+ }
+
+ public void Update()
+ {
+ ResetClicked();
+ UpdateMouseSelection();
+ UpdateWidgetSizes();
+ }
+
+ protected abstract void UpdateWidgetSizes();
+
+ protected abstract void UpdateWidgetRelativePositions();
+
+ protected abstract Vector2 GetTotalSize();
+
+ private void UpdateWidgetAbsolutePositions()
+ {
+ var viewport = mGraphicsDeviceManager.GraphicsDevice.Viewport;
+ Size = GetTotalSize();
+ var viewportSize = new Vector2(viewport.Bounds.Width, viewport.Bounds.Height);
+ Position = (viewportSize - Size) / 2;
+ Widgets.ForEach(w => w.Position = w.Position + Position);
+ }
+
+ private void ResetClicked()
+ {
+ foreach (var clickable in Widgets.OfType<IClickable>())
+ clickable.IsClicked = false;
+ }
+
+ private void UpdateMouseSelection()
+ {
+ var position = Mouse.GetState().Position;
+ foreach (var selectable in Widgets.OfType<ISelectable>())
+ selectable.IsSelected = selectable.CheckSelected(position);
+ }
+
+ protected static void MakeWidgetsSameSize(IEnumerable<IWidget> widgets)
+ {
+ var xMax = 0f;
+ var yMax = 0f;
+
+ var widgetsCopy = widgets as IList<IWidget> ?? widgets.ToList();
+ foreach (var widget in widgetsCopy)
+ {
+ var size = widget.GetMinimumSize();
+ if (size.X > xMax)
+ xMax = size.X;
+ if (size.Y > yMax)
+ yMax = size.Y;
+ }
+
+ var sizeMax = new Vector2(xMax, yMax);
+ foreach (var widget in widgetsCopy)
+ widget.Size = sizeMax;
+ }
+ }
+}
diff --git a/V3/Widgets/AbstractTextWidget.cs b/V3/Widgets/AbstractTextWidget.cs
new file mode 100644
index 0000000..1f28742
--- /dev/null
+++ b/V3/Widgets/AbstractTextWidget.cs
@@ -0,0 +1,113 @@
+using System;
+using System.Text;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
+using Ninject;
+
+namespace V3.Widgets
+{
+ public abstract class AbstractTextWidget : ITextWidget, IInitializable
+ {
+ private string mText;
+
+ public Vector2 Position { get; set; }
+
+ public Vector2 Size { get; set; }
+
+ public string Text
+ {
+ get { return mText; }
+ set { mText = ReplaceUmlauteWhenOnUnix(value); }
+ }
+
+ public float PaddingX { get; set; } = 80;
+
+ public float PaddingY { get; set; } = 5;
+
+ public Color Color { get; set; } = Color.Black;
+
+ public HorizontalOrientation HorizontalOrientation { get; set; } = HorizontalOrientation.Center;
+
+ public SpriteFont Font { get; set; }
+
+ private readonly ContentManager mContentManager;
+
+ public AbstractTextWidget(ContentManager contentManager)
+ {
+ mContentManager = contentManager;
+ Text = "";
+ }
+
+ public virtual void Initialize()
+ {
+ Font = mContentManager.Load<SpriteFont>("Fonts/MenuFont");
+ }
+
+ public virtual void Draw(SpriteBatch spriteBatch)
+ {
+ var calculatedSize = Font.MeasureString(Text);
+ var position = Position;
+ switch (HorizontalOrientation)
+ {
+ case HorizontalOrientation.Left:
+ position.X += PaddingX;
+ break;
+ case HorizontalOrientation.Center:
+ position.X += (Size - calculatedSize).X / 2;
+ break;
+ case HorizontalOrientation.Right:
+ position.X += (Size - calculatedSize).X;
+ position.X -= PaddingX;
+ break;
+ }
+ position.Y += (Size - calculatedSize).Y / 2;
+ spriteBatch.DrawString(Font, Text, position, GetColor());
+ }
+
+ public virtual Vector2 GetMinimumSize()
+ {
+ var size = Font.MeasureString(Text);
+ size.X += 2 * PaddingX;
+ size.Y += 2 * PaddingY;
+ return size;
+ }
+
+ public bool CheckSelected(Point position)
+ {
+ var rectangle = new Rectangle((int) Position.X, (int) Position.Y, (int) Size.X, (int) Size.Y);
+ return rectangle.Contains(position);
+ }
+
+ protected virtual Color GetColor()
+ {
+ return Color;
+ }
+
+ /// <summary>
+ /// Test if execution platform is UNIX and replace german Umlaute
+ /// accordingly because a strange ArgumentException is thrown otherwise.
+ /// </summary>
+ /// <param name="originalString">The original input string.</param>
+ /// <returns></returns>
+ private string ReplaceUmlauteWhenOnUnix(string originalString)
+ {
+ // Taken from <http://mono.wikia.com/wiki/Detecting_the_execution_platform>.
+ int p = (int) Environment.OSVersion.Platform;
+ if ((p == 4) || (p == 6) || (p == 128)) // Running on Unix
+ {
+ var sb = new StringBuilder();
+ foreach (char c in originalString)
+ {
+ if (c < 128)
+ {
+ sb.Append(c);
+ }
+ }
+ return sb.ToString();
+ }
+ // NOT running on Unix.
+ return originalString;
+ }
+ }
+}
diff --git a/V3/Widgets/AchievementBox.cs b/V3/Widgets/AchievementBox.cs
new file mode 100644
index 0000000..000894a
--- /dev/null
+++ b/V3/Widgets/AchievementBox.cs
@@ -0,0 +1,91 @@
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace V3.Widgets
+{
+ // ReSharper disable once ClassNeverInstantiated.Global
+ public sealed class AchievementBox : AbstractTextWidget
+ {
+ public bool IsEnabled { private get; set; }
+ private Color BackgroundColor { get; } = Color.Gray;
+
+ private readonly ContentManager mContentManager;
+ private readonly WidgetFactory mWidgetFactory;
+ private SpriteFont mTitleFont;
+ private SpriteFont mDescriptionFont;
+
+ private Label mButtonTitle;
+ private Label mButtonDescription;
+
+ private Texture2D mRectangle;
+
+ public AchievementBox(ContentManager contentManager, WidgetFactory widgetFactory) : base(contentManager)
+ {
+ mContentManager = contentManager;
+ mWidgetFactory = widgetFactory;
+ }
+
+ public override void Initialize()
+ {
+ mRectangle = mContentManager.Load<Texture2D>("Sprites/WhiteRectangle");
+ mTitleFont = mContentManager.Load<SpriteFont>("Fonts/MenuFont");
+ mDescriptionFont = mContentManager.Load<SpriteFont>("Fonts/UnitFont");
+
+ mButtonTitle = mWidgetFactory.CreateLabel("");
+ mButtonTitle.PaddingY = 0;
+ mButtonTitle.PaddingX = 10;
+ mButtonTitle.HorizontalOrientation = HorizontalOrientation.Left;
+ mButtonDescription = mWidgetFactory.CreateLabel("");
+ mButtonDescription.PaddingX = 10;
+ mButtonDescription.PaddingY = 0;
+ mButtonDescription.HorizontalOrientation = HorizontalOrientation.Left;
+
+ base.Initialize();
+ }
+
+ public override void Draw(SpriteBatch spriteBatch)
+ {
+ var rectangle = new Rectangle((int)Position.X, (int)Position.Y, (int)Size.X, (int)Size.Y);
+
+ if (IsEnabled)
+ {
+ var borderRectangle = new Rectangle((int)Position.X - 2, (int)Position.Y - 2, (int)Size.X + 4, (int)Size.Y + 4);
+ spriteBatch.Draw(mRectangle, borderRectangle, Color.Gray);
+ }
+
+ mButtonTitle.Color = IsEnabled ? Color.Black : Color.Gray;
+ mButtonDescription.Color = IsEnabled ? Color.Black : Color.Gray;
+
+ spriteBatch.Draw(mRectangle, rectangle, GetBackgroundColor());
+ mButtonTitle.Position = Position + new Vector2(0, 10);
+ mButtonDescription.Position = mButtonTitle.Position + new Vector2(0, mButtonDescription.Size.Y);
+ mButtonDescription.Draw(spriteBatch);
+ mButtonTitle.Draw(spriteBatch);
+ base.Draw(spriteBatch);
+ }
+
+ public override Vector2 GetMinimumSize()
+ {
+ var titleSize = mButtonTitle.GetMinimumSize();
+ var descriptionSize = mButtonDescription.GetMinimumSize();
+
+ return new Vector2(MathHelper.Max(titleSize.X, descriptionSize.X), titleSize.Y + descriptionSize.Y + 20);
+ }
+
+ private Color GetBackgroundColor()
+ {
+ return IsEnabled ? BackgroundColor : Color.LightGray;
+ }
+
+ public void SetText(string title, string description)
+ {
+ mButtonTitle.Text = title;
+ mButtonDescription.Text = description;
+ mButtonTitle.Size = mButtonTitle.GetMinimumSize();
+ mButtonDescription.Size = mButtonDescription.GetMinimumSize();
+ mButtonTitle.Font = mTitleFont;
+ mButtonDescription.Font = mDescriptionFont;
+ }
+ }
+}
diff --git a/V3/Widgets/Button.cs b/V3/Widgets/Button.cs
new file mode 100644
index 0000000..04307d0
--- /dev/null
+++ b/V3/Widgets/Button.cs
@@ -0,0 +1,111 @@
+using Castle.Core.Internal;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input;
+using V3.Input;
+
+namespace V3.Widgets
+{
+ // ReSharper disable once ClassNeverInstantiated.Global
+ public sealed class Button : AbstractTextWidget, IClickable, IImageWidget, ISelectable
+ {
+ public bool IsClicked { get; set; }
+
+ public bool IsEnabled { get; set; } = true;
+
+ public bool IsSelected { get; set; }
+
+ public Color BackgroundColor { private get; set; } = Color.Gray;
+
+ public Texture2D Image { get; set; }
+
+ public string Tooltip { get; set; }
+ public string TooltipTitle { private get; set; }
+
+ public Rectangle Rectangle
+ {
+ get { return new Rectangle((int)Position.X, (int)Position.Y, (int)Size.X, (int)Size.Y); }
+ }
+
+ private readonly ContentManager mContentManager;
+ private readonly WidgetFactory mWidgetFactory;
+
+ private Texture2D mRectangle;
+ private AchievementBox mTooltipBox;
+
+ public Button(ContentManager contentManager, WidgetFactory widgetFactory) : base(contentManager)
+ {
+ mContentManager = contentManager;
+ mWidgetFactory = widgetFactory;
+ }
+
+ public override void Initialize()
+ {
+ mRectangle = mContentManager.Load<Texture2D>("Sprites/WhiteRectangle");
+ mTooltipBox = mWidgetFactory.CreateAchievementBox();
+
+ base.Initialize();
+ }
+
+ public void HandleMouseEvent(IMouseEvent mouseEvent)
+ {
+ if (!IsEnabled)
+ return;
+ if (mouseEvent.MouseButton == MouseButton.Left && mouseEvent.ButtonState == ButtonState.Released)
+ {
+ if (!mouseEvent.PositionReleased.HasValue)
+ return;
+ if (Rectangle.Contains(mouseEvent.PositionReleased.Value))
+ IsClicked = true;
+ }
+ }
+
+ public override void Draw(SpriteBatch spriteBatch)
+ {
+ var rectangle = new Rectangle((int)Position.X, (int)Position.Y, (int)Size.X, (int)Size.Y);
+
+ if (IsSelected && IsEnabled)
+ {
+ var borderRectangle = new Rectangle((int)Position.X - 2, (int)Position.Y - 2, (int)Size.X + 4, (int)Size.Y + 4);
+ spriteBatch.Draw(mRectangle, borderRectangle, Color.Red);
+ }
+
+ if (Image == null)
+ {
+ spriteBatch.Draw(mRectangle, rectangle, GetBackgroundColor());
+ }
+ else
+ {
+ spriteBatch.Draw(Image, rectangle, Color.White);
+ if (!IsEnabled)
+ {
+ spriteBatch.Draw(mRectangle, rectangle, Color.Black * 0.7f);
+ }
+ }
+
+ if (IsSelected && !TooltipTitle.IsNullOrEmpty() && !Tooltip.IsNullOrEmpty())
+ {
+ mTooltipBox.SetText(TooltipTitle, Tooltip);
+ mTooltipBox.Size = mTooltipBox.GetMinimumSize();
+ mTooltipBox.Position = Position - new Vector2(0, mTooltipBox.Size.Y);
+ mTooltipBox.IsEnabled = true;
+ if (mTooltipBox.Position.Y < 0)
+ mTooltipBox.Position = Position + new Vector2(0, Size.Y);
+ mTooltipBox.Draw(spriteBatch);
+ }
+
+ base.Draw(spriteBatch);
+ }
+
+ protected override Color GetColor()
+ {
+ return IsEnabled ? Color : Color.Gray;
+ }
+
+ private Color GetBackgroundColor()
+ {
+ return IsEnabled ? BackgroundColor : Color.LightGray;
+ }
+ }
+}
diff --git a/V3/Widgets/EmptyWidget.cs b/V3/Widgets/EmptyWidget.cs
new file mode 100644
index 0000000..d9ad8d8
--- /dev/null
+++ b/V3/Widgets/EmptyWidget.cs
@@ -0,0 +1,41 @@
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace V3.Widgets
+{
+ /// <summary>
+ /// A placeholder widget.
+ /// </summary>
+ // ReSharper disable once ClassNeverInstantiated.Global
+ public sealed class EmptyWidget : IWidget
+ {
+ /// <summary>
+ /// The current position of this widget on the screen.
+ /// </summary>
+ public Vector2 Position { get; set; }
+
+ /// <summary>
+ /// The size of this widget on the screen. The widget should try to
+ /// fill this size. Should not be smaller than the value returned by
+ /// GetMinimumSize().
+ /// </summary>
+ public Vector2 Size { get; set; }
+
+ /// <summary>
+ /// Returns the minimum size this widgets needs.
+ /// </summary>
+ public Vector2 GetMinimumSize()
+ {
+ return new Vector2(0, 0);
+ }
+
+ /// <summary>
+ /// Draws this widget on the given sprite batch. It is assumed that
+ /// spriteBatch.Begin() has already been called.
+ /// </summary>
+ public void Draw(SpriteBatch spriteBatch)
+ {
+ }
+ }
+}
+
diff --git a/V3/Widgets/FormMenu.cs b/V3/Widgets/FormMenu.cs
new file mode 100644
index 0000000..746f8f4
--- /dev/null
+++ b/V3/Widgets/FormMenu.cs
@@ -0,0 +1,75 @@
+using Microsoft.Xna.Framework;
+using System;
+using System.Linq;
+
+namespace V3.Widgets
+{
+ /// <summary>
+ /// A menu that arranges widgets in two columns. All widgets in on column
+ /// are made the same size (the maximum widget size).
+ /// </summary>
+ // ReSharper disable once ClassNeverInstantiated.Global
+ public sealed class FormMenu : AbstractMenu
+ {
+ private const float PaddingInnerX = 10;
+ private const float PaddingOuterX = 10;
+ private const float PaddingInnerY = 10;
+ private const float PaddingOuterY = 10;
+
+ public FormMenu(GraphicsDeviceManager graphicsDeviceManager) : base(graphicsDeviceManager)
+ {
+ }
+
+ protected override Vector2 GetTotalSize()
+ {
+ var size = new Vector2(2 * PaddingOuterX, 2 * PaddingOuterY);
+ var maxXLeft = 0f;
+ var maxXRight = 0f;
+ for (var i = 0; i < Widgets.Count; i += 2)
+ {
+ maxXLeft = Math.Max(maxXLeft, Widgets[i].Size.X);
+ if (i + 1 < Widgets.Count)
+ {
+ maxXRight = Math.Max(maxXRight, Widgets[i + 1].Size.X);
+ size.Y += Math.Max(Widgets[i].Size.Y, Widgets[i + 1].Size.Y);
+ }
+ else
+ {
+ size.Y += Widgets[i].Size.Y;
+ }
+ if (i + 2 < Widgets.Count)
+ size.Y += PaddingInnerY;
+ }
+ size.X += maxXLeft + maxXRight + PaddingInnerX;
+ return size;
+ }
+
+ protected override void UpdateWidgetRelativePositions()
+ {
+ var y = PaddingOuterY;
+ for (var i = 0; i < Widgets.Count; i += 2)
+ {
+ var x = PaddingOuterX;
+ Widgets[i].Position = new Vector2(x, y);
+ if (i + 1 < Widgets.Count)
+ {
+ x += Widgets[i].Size.X;
+ x += PaddingInnerX;
+ Widgets[i + 1].Position = new Vector2(x, y);
+ y += Math.Max(Widgets[i].Size.Y, Widgets[i + 1].Size.Y);
+ }
+ else
+ {
+ y += Widgets[i].Size.Y;
+ }
+ y += PaddingInnerY;
+ }
+ }
+
+ protected override void UpdateWidgetSizes()
+ {
+ MakeWidgetsSameSize(Widgets.Where((w, i) => i % 2 == 0));
+ MakeWidgetsSameSize(Widgets.Where((w, i) => i % 2 == 1));
+ }
+ }
+}
diff --git a/V3/Widgets/HorizontalOrientation.cs b/V3/Widgets/HorizontalOrientation.cs
new file mode 100644
index 0000000..489667a
--- /dev/null
+++ b/V3/Widgets/HorizontalOrientation.cs
@@ -0,0 +1,9 @@
+namespace V3.Widgets
+{
+ public enum HorizontalOrientation
+ {
+ Left,
+ Center,
+ Right
+ }
+}
diff --git a/V3/Widgets/IBasicWidgetFactory.cs b/V3/Widgets/IBasicWidgetFactory.cs
new file mode 100644
index 0000000..dd0a28d
--- /dev/null
+++ b/V3/Widgets/IBasicWidgetFactory.cs
@@ -0,0 +1,38 @@
+namespace V3.Widgets
+{
+ /// <summary>
+ /// A widget factory that is automatically implemented by Ninject.
+ /// </summary>
+ public interface IBasicWidgetFactory
+ {
+ /// <summary>
+ /// Creates a new button widget.
+ /// </summary>
+ /// <returns>a new button widget</returns>
+ Button CreateButton();
+
+ /// <summary>
+ /// Creates a new empty widget.
+ /// </summary>
+ /// <returns>a new empty widget</returns>
+ EmptyWidget CreateEmptyWidget();
+
+ /// <summary>
+ /// Creates a new select button widget.
+ /// </summary>
+ /// <returns>a new select button widget</returns>
+ SelectButton CreateSelectButton();
+
+ /// <summary>
+ /// Creates a new label widget.
+ /// </summary>
+ /// <returns>a new label widget</returns>
+ Label CreateLabel();
+
+ /// <summary>
+ /// Creates a new Achievement Box.
+ /// </summary>
+ /// <returns>a new achievement box widget.</returns>
+ AchievementBox CreateAchievementBox();
+ }
+}
diff --git a/V3/Widgets/IClickable.cs b/V3/Widgets/IClickable.cs
new file mode 100644
index 0000000..276c4a1
--- /dev/null
+++ b/V3/Widgets/IClickable.cs
@@ -0,0 +1,14 @@
+using V3.Input;
+
+namespace V3.Widgets
+{
+ /// <summary>
+ /// An element that can be clicked on.
+ /// </summary>
+ public interface IClickable : IMouseEventHandler
+ {
+ bool IsClicked { get; set; }
+
+ bool IsEnabled { get; set; }
+ }
+}
diff --git a/V3/Widgets/IImageWidget.cs b/V3/Widgets/IImageWidget.cs
new file mode 100644
index 0000000..5a5b368
--- /dev/null
+++ b/V3/Widgets/IImageWidget.cs
@@ -0,0 +1,15 @@
+using Microsoft.Xna.Framework.Graphics;
+
+namespace V3.Widgets
+{
+ /// <summary>
+ /// A widget that displays an image.
+ /// </summary>
+ public interface IImageWidget : IWidget
+ {
+ /// <summary>
+ /// The image to display.
+ /// </summary>
+ Texture2D Image { get; set; }
+ }
+}
diff --git a/V3/Widgets/IMenu.cs b/V3/Widgets/IMenu.cs
new file mode 100644
index 0000000..ad121e0
--- /dev/null
+++ b/V3/Widgets/IMenu.cs
@@ -0,0 +1,33 @@
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+using System.Collections.Generic;
+using V3.Input;
+
+namespace V3.Widgets
+{
+ /// <summary>
+ /// A menu that displays a list of widgets.
+ /// </summary>
+ public interface IMenu : IMouseEventHandler
+ {
+ /// <summary>
+ /// The widgets in this menu. The order of the widgets in this list
+ /// is the order in which they are displayed.
+ /// </summary>
+ List<IWidget> Widgets { get; }
+
+ /// <summary>
+ /// The total size of the widgets in this menu.
+ /// </summary>
+ Vector2 Size { get; }
+
+ /// <summary>
+ /// The current position of the widgets.
+ /// </summary>
+ Vector2 Position { get; }
+
+ void Draw(SpriteBatch spriteBatch);
+
+ void Update();
+ }
+}
diff --git a/V3/Widgets/IMenuFactory.cs b/V3/Widgets/IMenuFactory.cs
new file mode 100644
index 0000000..24ed311
--- /dev/null
+++ b/V3/Widgets/IMenuFactory.cs
@@ -0,0 +1,9 @@
+namespace V3.Widgets
+{
+ public interface IMenuFactory
+ {
+ FormMenu CreateFormMenu();
+
+ VerticalMenu CreateVerticalMenu();
+ }
+} \ No newline at end of file
diff --git a/V3/Widgets/ISelectable.cs b/V3/Widgets/ISelectable.cs
new file mode 100644
index 0000000..6eb78dc
--- /dev/null
+++ b/V3/Widgets/ISelectable.cs
@@ -0,0 +1,27 @@
+using Microsoft.Xna.Framework;
+
+namespace V3.Widgets
+{
+ /// <summary>
+ /// An element that can be selected.
+ /// </summary>
+ public interface ISelectable
+ {
+ bool IsSelected { get; set; }
+
+ /// <summary>
+ /// The tooltip to show if this widget is selected. Can be null or
+ /// empty if no tooltip should be shown.
+ /// </summary>
+ string Tooltip { get; set; }
+
+ /// <summary>
+ /// Checks whether this element is selected by a mouse click at the
+ /// given position.
+ /// </summary>
+ /// <param name="position">the position of the mouse click</param>
+ /// <returns>true if the element is selected by the mouse click at
+ /// that position, otherwise false</returns>
+ bool CheckSelected(Point position);
+ }
+}
diff --git a/V3/Widgets/ITextWidget.cs b/V3/Widgets/ITextWidget.cs
new file mode 100644
index 0000000..e5f8203
--- /dev/null
+++ b/V3/Widgets/ITextWidget.cs
@@ -0,0 +1,43 @@
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace V3.Widgets
+{
+ /// <summary>
+ /// A widget that contains some text.
+ /// </summary>
+ public interface ITextWidget : IWidget
+ {
+ /// <summary>
+ /// The text of this widget.
+ /// </summary>
+ string Text { get; set; }
+
+ /// <summary>
+ /// The space that is added before and after the text in the
+ /// horizontal direction.
+ /// </summary>
+ float PaddingX { get; set; }
+
+ /// <summary>
+ /// The space that is added before and after the text in the
+ /// vertical direction.
+ /// </summary>
+ float PaddingY { get; set; }
+
+ /// <summary>
+ /// The horizontal orientation of the text within the size.
+ /// </summary>
+ HorizontalOrientation HorizontalOrientation { get; set; }
+
+ /// <summary>
+ /// The default color of the text.
+ /// </summary>
+ Color Color { get; set; }
+
+ /// <summary>
+ /// The font for text rendering.
+ /// </summary>
+ SpriteFont Font { get; set; }
+ }
+}
diff --git a/V3/Widgets/IWidget.cs b/V3/Widgets/IWidget.cs
new file mode 100644
index 0000000..23466fe
--- /dev/null
+++ b/V3/Widgets/IWidget.cs
@@ -0,0 +1,34 @@
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Graphics;
+
+namespace V3.Widgets
+{
+ /// <summary>
+ /// A simple widget that has a size and a position and that can be drawn.
+ /// </summary>
+ public interface IWidget
+ {
+ /// <summary>
+ /// The current position of this widget on the screen.
+ /// </summary>
+ Vector2 Position { get; set; }
+
+ /// <summary>
+ /// The size of this widget on the screen. The widget should try to
+ /// fill this size. Should not be smaller than the value returned by
+ /// GetMinimumSize().
+ /// </summary>
+ Vector2 Size { get; set; }
+
+ /// <summary>
+ /// Returns the minimum size this widgets needs.
+ /// </summary>
+ Vector2 GetMinimumSize();
+
+ /// <summary>
+ /// Drawst this widget on the given sprite batch. It is assumed that
+ /// spriteBatch.Begin() has already been called.
+ /// </summary>
+ void Draw(SpriteBatch spriteBatch);
+ }
+}
diff --git a/V3/Widgets/Label.cs b/V3/Widgets/Label.cs
new file mode 100644
index 0000000..6b60d4b
--- /dev/null
+++ b/V3/Widgets/Label.cs
@@ -0,0 +1,14 @@
+using Microsoft.Xna.Framework.Content;
+
+namespace V3.Widgets
+{
+ // ReSharper disable once ClassNeverInstantiated.Global
+ public sealed class Label : AbstractTextWidget
+ {
+ public Label(ContentManager contentManager) : base(contentManager)
+ {
+ HorizontalOrientation = HorizontalOrientation.Left;
+ PaddingX = 20;
+ }
+ }
+}
diff --git a/V3/Widgets/SelectButton.cs b/V3/Widgets/SelectButton.cs
new file mode 100644
index 0000000..9079c6d
--- /dev/null
+++ b/V3/Widgets/SelectButton.cs
@@ -0,0 +1,108 @@
+using System;
+using Microsoft.Xna.Framework;
+using Microsoft.Xna.Framework.Content;
+using Microsoft.Xna.Framework.Graphics;
+using Microsoft.Xna.Framework.Input;
+using System.Collections.Generic;
+using System.Linq;
+using V3.Input;
+
+namespace V3.Widgets
+{
+ // ReSharper disable once ClassNeverInstantiated.Global
+ public sealed class SelectButton : AbstractTextWidget, IClickable
+ {
+ public List<string> Values { get; } = new List<string>();
+
+ public int SelectedIndex { get; set; }
+
+ public bool IsClicked { get; set; }
+
+ public bool IsEnabled { get; set; } = true;
+
+ private readonly ContentManager mContentManager;
+
+ private Texture2D mTriangle;
+ private Rectangle mBoxArrowLeft;
+ private Rectangle mBoxArrowRight;
+
+ public SelectButton(ContentManager contentManager) : base(contentManager)
+ {
+ mContentManager = contentManager;
+ }
+
+ public override void Initialize()
+ {
+ mTriangle = mContentManager.Load<Texture2D>("Menu/arrow_white");
+ base.Initialize();
+ }
+
+ public void HandleMouseEvent(IMouseEvent mouseEvent)
+ {
+ if (mouseEvent.MouseButton == MouseButton.Left && mouseEvent.ButtonState == ButtonState.Released)
+ {
+ if (!mouseEvent.PositionReleased.HasValue)
+ return;
+ var rectangle = new Rectangle((int)Position.X, (int)Position.Y, (int)Size.X, (int)Size.Y);
+ var position = mouseEvent.PositionReleased.Value;
+ if (rectangle.Contains(position))
+ IsClicked = true;
+
+ int change;
+ if (mBoxArrowLeft.Contains(position))
+ change = -1;
+ else if (mBoxArrowRight.Contains(position))
+ change = 1;
+ else
+ return;
+
+ SelectedIndex += change;
+ if (SelectedIndex < 0)
+ SelectedIndex += Values.Count;
+ if (SelectedIndex >= Values.Count)
+ SelectedIndex -= Values.Count;
+ }
+ }
+
+ public override void Draw(SpriteBatch spriteBatch)
+ {
+ UpdateSelection();
+
+ var arrowPadding = 30;
+ var arrowLength = 20;
+ var arrowY = (int)Position.Y + (int)(Size.Y / 2) - arrowLength / 2;
+ mBoxArrowLeft = new Rectangle((int)Position.X + arrowPadding,
+ arrowY, arrowLength, arrowLength);
+ mBoxArrowRight = new Rectangle((int)Position.X + (int)Size.X - arrowPadding,
+ arrowY, arrowLength, arrowLength);
+
+
+ spriteBatch.Draw(mTriangle, mBoxArrowLeft, null, Color.Gray, 0, new Vector2(0, 0), SpriteEffects.FlipHorizontally, 0);
+ spriteBatch.Draw(mTriangle, mBoxArrowRight, Color.Gray);
+
+ base.Draw(spriteBatch);
+ }
+
+ public override Vector2 GetMinimumSize()
+ {
+ Vector2 size;
+ try
+ {
+ size = new Vector2(Values.Max(v => Font.MeasureString(v).X), Font.MeasureString(Text).Y);
+ }
+ catch (ArgumentException)
+ {
+ // Return whatever.
+ size = new Vector2(100, 40);
+ }
+ size.X += 2 * PaddingX;
+ size.Y += 2 * PaddingY;
+ return size;
+ }
+
+ private void UpdateSelection()
+ {
+ Text = Values[SelectedIndex];
+ }
+ }
+}
diff --git a/V3/Widgets/VerticalMenu.cs b/V3/Widgets/VerticalMenu.cs
new file mode 100644
index 0000000..bc18439
--- /dev/null
+++ b/V3/Widgets/VerticalMenu.cs
@@ -0,0 +1,42 @@
+using Microsoft.Xna.Framework;
+using System.Linq;
+
+namespace V3.Widgets
+{
+ /// <summary>
+ /// A simple menu with vertically arranged widgets. All widgets are made
+ /// the same size (the maximum widget size).
+ /// </summary>
+ // ReSharper disable once ClassNeverInstantiated.Global
+ public sealed class VerticalMenu : AbstractMenu
+ {
+ private float mPadding = 10;
+
+ public VerticalMenu(GraphicsDeviceManager graphicsDeviceManager) : base(graphicsDeviceManager)
+ {
+ }
+
+ protected override void UpdateWidgetRelativePositions()
+ {
+ var y = 0f;
+ foreach (var widget in Widgets)
+ {
+ widget.Position = new Vector2(0, y);
+ y += widget.Size.Y;
+ y += mPadding;
+ }
+ }
+
+ protected override Vector2 GetTotalSize()
+ {
+ var totalX = Widgets.Max(w => w.Size.X);
+ var totalY = (Widgets.Count - 1) * mPadding + Widgets.Sum(w => w.Size.Y);
+ return new Vector2(totalX, totalY);
+ }
+
+ protected override void UpdateWidgetSizes()
+ {
+ MakeWidgetsSameSize(Widgets);
+ }
+ }
+}
diff --git a/V3/Widgets/WidgetFactory.cs b/V3/Widgets/WidgetFactory.cs
new file mode 100644
index 0000000..35e8e1b
--- /dev/null
+++ b/V3/Widgets/WidgetFactory.cs
@@ -0,0 +1,78 @@
+namespace V3.Widgets
+{
+ /// <summary>
+ /// A widget factory.
+ /// </summary>
+ // ReSharper disable once ClassNeverInstantiated.Global
+ public sealed class WidgetFactory
+ {
+ private IBasicWidgetFactory mFactory;
+
+ public WidgetFactory(IBasicWidgetFactory factory)
+ {
+ mFactory = factory;
+ }
+
+ /// <summary>
+ /// Creates a new button with the given text.
+ /// </summary>
+ /// <param name="text">the text of the button</param>
+ /// <returns>the created button</returns>
+ public Button CreateButton(string text)
+ {
+ return CreateTextWidget(mFactory.CreateButton(), text);
+ }
+
+ /// <summary>
+ /// Creates a new empty widget.
+ /// </summary>
+ /// <returns>the created widget</returns>
+ public EmptyWidget CreateEmptyWidget()
+ {
+ return mFactory.CreateEmptyWidget();
+ }
+
+ /// <summary>
+ /// Creates a new select button with the given text options.
+ /// </summary>
+ /// <param name="values">the values of the button</param>
+ /// <returns>the created button</returns>
+ public SelectButton CreateSelectButton(string[] values)
+ {
+ var widget = CreateTextWidget(mFactory.CreateSelectButton(), "");
+ foreach (var val in values)
+ widget.Values.Add(val);
+ return widget;
+ }
+
+ /// <summary>
+ /// Creates a new select button without options.
+ /// </summary>
+ /// <returns>the created button</returns>
+ public SelectButton CreateSelectButton()
+ {
+ return mFactory.CreateSelectButton();
+ }
+
+ /// <summary>
+ /// Creates a new label with the given text.
+ /// </summary>
+ /// <param name="text">the text of the label</param>
+ /// <returns>the created label</returns>
+ public Label CreateLabel(string text)
+ {
+ return CreateTextWidget(mFactory.CreateLabel(), text);
+ }
+
+ private T CreateTextWidget<T>(T widget, string text) where T : ITextWidget
+ {
+ widget.Text = text;
+ return widget;
+ }
+
+ public AchievementBox CreateAchievementBox()
+ {
+ return mFactory.CreateAchievementBox();
+ }
+ }
+}
diff --git a/V3/packages.config b/V3/packages.config
new file mode 100644
index 0000000..8839ef8
--- /dev/null
+++ b/V3/packages.config
@@ -0,0 +1,6 @@
+<?xml version="1.0" encoding="utf-8"?>
+<packages>
+ <package id="Castle.Core" version="3.2.0" targetFramework="net45" />
+ <package id="Ninject" version="3.2.2.0" targetFramework="net45" />
+ <package id="Ninject.Extensions.Factory" version="3.2.1.0" targetFramework="net45" />
+</packages> \ No newline at end of file