Sprite mapMaximSprite(mapMaximImg, 32, 64);
                Entity mapMaxim;
                mapMaxim.SetSprite(&mapMaximSprite);
-               mapMaxim.Position() = Vector<float>(80, 160);
+               mapMaxim.Position() = Vector<float>(80, 128);
 
                InitScreen screen(width, height);
 
 
 #include "Tile.h"
 #include "../graphics/Sprite.h"
 
+#include <stdexcept>
+
 using geometry::Vector;
 
 namespace map {
 
 }
 
+
+const Tile &Area::TileAt(const geometry::Vector<int> &offset) const {
+       int tileIndex(offset.Y() * width + offset.X());
+       if (tileIndex < numTiles) {
+               return tiles[tileIndex];
+       } else {
+               throw std::out_of_range("tile index out of range");
+       }
+}
+
+
 void Area::Render(SDL_Surface *dest, const graphics::Sprite *tileset, const Vector<int> &inOffset) const {
        for (int i(0); i < numTiles; ++i) {
                Vector<int> offset(
 
 
 #include "fwd.h"
 #include "../geometry/Vector.h"
-#include "../graphics/fwd.h"
+#include "../graphics/Sprite.h"
 
 #include <SDL.h>
 
 public:
        int Width() const { return width; }
        int Height() const { return numTiles / width + (numTiles % width ? 1 : 0); }
+       const Tile &TileAt(const geometry::Vector<int> &) const;
 
        void Render(SDL_Surface *dest, const graphics::Sprite *tileset, const geometry::Vector<int> &offset) const;
 
 
 bool Entity::TileLock(int width, int height) const {
        Vector<int> tilePosition(
                        position.X() - (width / 2),
-                       position.Y() - height);
+                       position.Y());
        return (tilePosition.X() % width == 0) && (tilePosition.Y() % height == 0);
 }
 
 
 
 void Entity::Render(SDL_Surface *dest, const Vector<int> &offset) const {
+       // TODO: configurable sprite offsets
        if (animation.Running()) {
-               animation.DrawCenterBottom(dest, offset + position);
+               animation.DrawCenter(dest, offset + position);
        } else {
-               sprite->DrawCenterBottom(dest, offset + position, orientation);
+               sprite->DrawCenter(dest, offset + position, orientation);
        }
 }
 
 
        const graphics::AnimationRunner &Animation() const { return animation; }
 
        void SetOrientation(Orientation);
+       Orientation GetOrientation() const { return orientation; }
        void SetSpeed(float);
 
        bool TileLock(int width, int height) const;
 
 #include "Area.h"
 #include "../graphics/Sprite.h"
 
+#include <stdexcept>
+
 using geometry::Vector;
 
 namespace map {
 }
 
 
+const Area &Map::AreaAt(const Vector<int> &offset) const {
+       if (numAreas > 0) {
+               Vector<int> tileOffset(offset.X() / tileset->Width(), offset.Y() / tileset->Height());
+               Vector<int> areaOffset(tileOffset.X() / areas[0].Width(), tileOffset.Y() / areas[0].Height());
+               int areaIndex(areaOffset.Y() * width + areaOffset.X());
+               if (areaIndex < numAreas) {
+                       return areas[areaIndex];
+               }
+       }
+       throw std::out_of_range("area offset out of bounds");
+}
+
+const Tile &Map::TileAt(const Vector<int> &offset) const {
+       const Area &area(AreaAt(offset));
+       Vector<int> tileOffset((offset.X() / tileset->Width()) % area.Width(), (offset.Y() / tileset->Height()) % area.Height());
+       return area.TileAt(tileOffset);
+}
+
+
 void Map::Render(SDL_Surface *dest, const Vector<int> &inOffset) const {
        // TODO: skip invisible areas
        for (int i(0); i < numAreas; ++i) {
 
 
 public:
        const graphics::Sprite *Tileset() const { return tileset; }
+       const Area &AreaAt(const geometry::Vector<int> &) const;
+       const Tile &TileAt(const geometry::Vector<int> &) const;
 
        void Render(SDL_Surface *dest, const geometry::Vector<int> &offset) const;
 
 
 #include "MapState.h"
 
 #include "Map.h"
+#include "Tile.h"
 #include "../app/Application.h"
 #include "../app/Input.h"
 
        if (!controlled) return;
        if (!controlled->TileLock(map->Tileset()->Width(), map->Tileset()->Height())) return;
 
+       bool down(false);
        if (input.IsDown(Input::PAD_UP)) {
                controlled->SetOrientation(Entity::ORIENTATION_NORTH);
-               controlled->SetSpeed(walkingSpeed);
+               down = true;
        } else if (input.IsDown(Input::PAD_RIGHT)) {
                controlled->SetOrientation(Entity::ORIENTATION_EAST);
-               controlled->SetSpeed(walkingSpeed);
+               down = true;
        } else if (input.IsDown(Input::PAD_DOWN)) {
                controlled->SetOrientation(Entity::ORIENTATION_SOUTH);
-               controlled->SetSpeed(walkingSpeed);
+               down = true;
        } else if (input.IsDown(Input::PAD_LEFT)) {
                controlled->SetOrientation(Entity::ORIENTATION_WEST);
-               controlled->SetSpeed(walkingSpeed);
+               down = true;
+       }
+
+       if (down) {
+               const Tile &tile(map->TileAt(controlled->Position()));
+               bool blocked(false);
+               switch (controlled->GetOrientation()) {
+                       case Entity::ORIENTATION_NORTH:
+                               blocked = tile.BlocksNorth();
+                               break;
+                       case Entity::ORIENTATION_EAST:
+                               blocked = tile.BlocksEast();
+                               break;
+                       case Entity::ORIENTATION_SOUTH:
+                               blocked = tile.BlocksSouth();
+                               break;
+                       case Entity::ORIENTATION_WEST:
+                               blocked = tile.BlocksWest();
+                               break;
+               }
+               if (!blocked) {
+                       controlled->SetSpeed(walkingSpeed);
+               } else {
+                       controlled->SetSpeed(0.0f);
+               }
        } else {
                controlled->SetSpeed(0.0f);
        }