You want to use a camera object. The idea is that the camera has coordinates for the currently viewed portion of the map (imagine the map being a lot bigger, and your player only ever sees a small rectangle within it). When drawing, you grab the top-left tile of the currently visible section to figure out where to start drawing (you definitely don't want to draw all the map each frame, since most of it probably won't be visible). You also need to know the offset for the first time (easiest way to visualise this: think about a tile in the top-left corner. You move slightly to the right, the tile moves slightly off-screen to the left - the value to move a tile off the screen is the offset you need).

I'll post some code now - it's from a camera class I use in my tiled graphics tutorial (work in progress, ho hum). You need to supply some constants to use it, but they should be self-evident:

[pascal]unit Camera;

interface

////////////////////////////////////////////////////////////////////////////////
// //
// camera //
// //
// This contains the TCamera class, which is used to move around the tiled //
// world in an efficient manner (plus enabling other sorts of trickery later //
// on!). //
// //
// It's important to note that we will be using this class to draw __only__ //
// what is visible on the screen (a screen's worth of the tiled world). This //
// is in major contrast to many code snippets I've seen that draw the whole //
// world every frame! Don't do that -- using a camera means that your world //
// can be any size (up to a reasonable limit, of course) without changing //
// the framerate //
// //
////////////////////////////////////////////////////////////////////////////////

type
TCamera = class
private
FPixelX : Integer;
FPixelY : Integer;
FMaxWidth : Integer;
FMaxHeight: Integer;

procedure Clip;

function GetOffsetX: Integer;
function GetOffsetY: Integer;
function GetTileX : Integer;
function GetTileY : Integer;
public
constructor Create(MaxX, MaxY: Integer;
StartX: Integer = 0;
StartY: Integer = 0);

procedure CentreOnTile(TileX, TileY: Integer);
procedure CentreOnPosition(PixX, PixY: Integer);
procedure Scroll(DeltaX, DeltaY: Integer);
procedure GoToPosition(PixX, PixY: Integer);

property PixelX : Integer read FPixelX;
property PixelY : Integer read FPixelY;
property OffsetX : Integer read GetOffsetX;
property OffsetY : Integer read GetOffsetY;
property TileX : Integer read GetTileX;
property TileY : Integer read GetTileY;
property MaxWidth : Integer read FMaxWidth write FMaxWidth;
property MaxHeight: Integer read FMaxHeight write FMaxHeight;
end;

implementation

uses
Globals;

//------------------------------------------------------------------------------

//
// Create
//
// Standard constructor. This initialises the map, centring it on the pixel
// coordinates supplied
//
constructor TCamera.Create(MaxX, MaxY: Integer;
StartX: Integer = 0;
StartY: Integer = 0);
begin
inherited Create;
FPixelX := StartX;
FPixelY := StartY;
FMaxWidth := MaxX;
FMaxHeight := MaxY;

Clip;
end;

//------------------------------------------------------------------------------

//
// CentreOnTile
//
// Centres on the given **tile coordinates**
//
procedure TCamera.CentreOnTile(TileX, TileY: Integer);
begin
FPixelX := ((TileX * TILE_SIZE) + HALF_TILE_SIZE) - HALF_SCREEN_WIDTH;
FPixelY := ((TileY * TILE_SIZE) + HALF_TILE_SIZE) - HALF_SCREEN_HEIGHT;
Clip;
end;

//------------------------------------------------------------------------------

//
// Clip
//
// Ensures that the camera doesn't go out of the level's bounds
//
procedure TCamera.Clip;
begin
if FPixelX < 0 then
FPixelX := 0;

if FPixelY < 0 then
FPixelY := 0;

// gotta make sure we're not dealing with
// smaller-than-screen-size maps!
if FPixelX >= FMaxWidth - SCREEN_WIDTH then
begin
if FMaxWidth <= SCREEN_WIDTH then
FPixelX := 0
else
FPixelX := FMaxWidth - SCREEN_WIDTH - 1;
end;

// same deal for the y axis
if FPixelY >= FMaxHeight - SCREEN_HEIGHT then
begin
if FMaxHeight <= SCREEN_HEIGHT then
FPixelY := 0
else
FPixelY := FMaxHeight - SCREEN_HEIGHT - 1;
end;
end;

//------------------------------------------------------------------------------

//
// CentreOnPosition
//
// This centres on the pixel coordinates
//
procedure TCamera.CentreOnPosition(PixX, PixY: Integer);
begin
FPixelX := PixX - HALF_SCREEN_WIDTH;
FPixelY := PixY - HALF_SCREEN_HEIGHT;
Clip;
end;

//------------------------------------------------------------------------------

//
// Scroll
//
// Scrolls the view by the given pixel amounts. Negative x = left, positive
// x = right, negative y = up, positive y = down. E.g. the values
// DeltaX = -2, DeltaY = 3 would scroll the map two pixels left and
// 3 pixels down
//
procedure TCamera.Scroll(DeltaX, DeltaY: Integer);
begin
Inc(FPixelX, DeltaX);
Inc(FPixelY, DeltaY);
Clip;
end;

//------------------------------------------------------------------------------

//
// GoToPosition
//
// Moves the camera so that its top-left is at the specified pixel coordinates
//
procedure TCamera.GoToPosition(PixX, PixY: Integer);
begin
FPixelX := PixX;
FPixelY := PixY;
Clip;
end;

//------------------------------------------------------------------------------

//
// GetOffsetX
//
// Returns the "extra bit" to the left, in pixels. Imagine that we start with
// a tile directly against the left edge. If we scroll the map left or right,
// we **won't** have a tile directly against the edge. This is the offset
// that we want - same applies for the y value
//
function TCamera.GetOffsetX: Integer;
begin
Result := FPixelX mod TILE_SIZE;
end;

//------------------------------------------------------------------------------

//
// GetOffsetY
//
// See the comment for GetOffsetX - same deal here, but for the y axis
//
function TCamera.GetOffsetY: Integer;
begin
Result := FPixelY mod TILE_SIZE;
end;

//------------------------------------------------------------------------------

//
// GetTileX
//
// Returns the left-most tile index that's visible on the screen
//
function TCamera.GetTileX: Integer;
begin
Result := FPixelX div TILE_SIZE;
end;

//------------------------------------------------------------------------------

//
// GetTileY
//
// Returns the top-most tile index that's visible
//
function TCamera.GetTileY: Integer;
begin
Result := FPixelY div TILE_SIZE;
end;

end.[/pascal]
Create a camera object that stores the maximum size (in pixels) for your map. For example, if your map was 100 * 100, with tile size of 32, you'd pass in the values (3200, 3200) when creating the camera (remember to free it later, once you're done with it).

Now, when moving, you tell the camera object to centre on the player's current position. The camera class will plonk itself in the right position (and will be careful to avoid scrolling off of edge boundaries too - it only scrolls until it wedges against a side of the whole map).

[pascal]YourCamera.CentreOnPosition(Player.X, Player.Y);[/pascal]

The real trick, of course, is integrating the camera into your map drawing. Unfortunately, I don't know anything about how you're currently drawing your map, so the best I can do here is to post example code for how I do it:

[pascal]//
// Draw
//
// The interesting bit!
//
procedure TLevel.Draw;
var
x : Integer;
y : Integer;
DrawHere: TRect;
FirstX : Integer;
FirstY : Integer;
LastX : Integer;
LastY : Integer;
begin
FirstX := FCamera.TileX;
FirstY := FCamera.TileY;

// figure out the right-most tile we need to display
// the if..else catches smaller-than-screen-size maps
if FirstX >= FMapWidth - HORIZONTAL_TILES_ON_SCREEN then
LastX := FMapWidth - 1
else
LastX := FirstX + HORIZONTAL_TILES_ON_SCREEN;

// figure out the bottom-most tile we need to draw
if FirstY >= FMapHeight - VERTICAL_TILES_ON_SCREEN then
LastY := FMapHeight - 1
else
LastY := FirstY + VERTICAL_TILES_ON_SCREEN;

// now we draw all the tiles on the screen
DrawHere.Top := -FCamera.OffsetY; // y position on screen of current tile
DrawHere.Bottom := DrawHere.Top + TILE_SIZE;

// for every row we need...
for y := FirstY to LastY do
begin
DrawHere.Left := -FCamera.OffsetX; // x position on screen of current tile
DrawHere.Right := DrawHere.Left + TILE_SIZE;

// for every tile on this row...
for x := FirstX to LastX do
begin
// splat down the tile
ddraw_utils.Draw(Secondary, FTileset[FMap[y,x].PictureIndex], @DrawHere);

// we move one tile's width to the right on the screen for the next tile
Inc(DrawHere.Left, TILE_SIZE);
Inc(DrawHere.Right, TILE_SIZE);
end;

// move one tile's height down on the screen for the next row
Inc(DrawHere.Top, TILE_SIZE);
Inc(DrawHere.Bottom, TILE_SIZE);
end;
end;[/pascal]
The draw_utils.draw is where you'd splat down the actual tile to be drawn (depends on your map). The code there will change depending on what API you use (the VCL, DirectDraw, OpenGL, or whatever). It basically translates to "draw a tile picture from the tileset at the wanted rectangle".

If you don't understand anything above then please let me know. I realise that I've dumped down a lot of code, but it's the best I could manage without knowing more info about how you're doing things.

Also, I have some example projects (work in progress). If you want any (they're using DirectDraw) then drop your email address and I'll mail them to you - assuming I'm still connected to the Internet by the time I read the email (I'm living on borrowed time here and will probably lose my home net connection sometime this week for a while).