I am very new to scripting .. but i was playing with the same Balloon tour script you have.
i found an easy way to get it to face the direction of travel was to use the
llLookAt(target, 1, .5); command.
You only need to becareful to place the script in an object linked to the balloon that can be rotated propery so the whole balloon does not tilt in the direction you are traveling.
// From the book:
//
// Introduction to Linden Scripting Language for Second Life
// by Jeff Heaton (Encog Dod in SL)
// ISBN: 1604390042
// Copyright 2007 by Heaton Research, Inc.
//
// This script may be freely copied and modified so long as this header
// remains unmodified.
//
// For more information about this book visit the following web site:
//
//
http://www.heatonresearch.com/articles/series/24/float dir;
float SPEED = 1;
vector target; // 182.461.70.566,21.079
list waypoints;
integer currentWaypoint;
string message;
// for loading notecard
string notecardName = "Configure balloon";
key notecardQuery;
integer notecardIndex;
integer nextWayPoint()
{
if( currentWaypoint>= llGetListLength(waypoints) )
{
llSay(0,"Ride over"

;
return TRUE;
}
else
{
target = llList2Vector(waypoints,currentWaypoint);
message = llList2String(waypoints,currentWaypoint+1);
currentWaypoint+=2;
llLookAt(target, 1, .5);
return FALSE;
}
}
default
{
state_entry()
{
llSay(0,"Touring balloon loading waypoints..."

;
notecardIndex = 0;
notecardQuery = llGetNotecardLine(notecardName,notecardIndex++);
}
dataserver(key query_id, string data)
{
if ( notecardQuery == query_id)
{
// this is a line of our notecard
if (data == EOF)
{
llSay(0,"Data loaded, touring balloon ready..."

;
state waiting;
} else
{
list temp = llCSV2List(data);
vector vec = (vector)llList2String(temp,0);
string str = llList2String(temp,1);
waypoints+=[vec,str];
notecardQuery = llGetNotecardLine(notecardName,notecardIndex++);
}
}
}
}
state running
{
state_entry()
{
currentWaypoint = 0;
llSitTarget(<0,-0.5,0.5>, llEuler2Rot(<0,0,-90>

);
llSetText("",<255,0,0>,1.0);
nextWayPoint();
llSetTimerEvent(0.1);
}
timer()
{
vector pos = llGetPos();
integer match = 0;
if( llFabs(pos.x - target.x) < SPEED )
{
pos.x = target.x;
match++;
}
else
{
if( pos.x > target.x )
pos.x-=SPEED;
else
pos.x+=SPEED;
}
if( llFabs(pos.y - target.y) < SPEED )
{
pos.y = target.y;
match++;
}
else
{
if( pos.y > target.y )
pos.y-=SPEED;
else
pos.y+=SPEED;
}
if( llFabs(pos.z - target.z) < SPEED )
{
pos.z = target.z;
match++;
}
else
{
if( pos.z > target.z )
pos.z-=SPEED;
else
pos.z+=SPEED;
}
llSetPos(pos);
if( match==3 )
{
string hold = message;
if( nextWayPoint() )
state waiting;
llSay(0,hold);
}
}
}
state waiting
{
state_entry()
{
llSay(0,"Touring balloon is waiting."

;
}
link_message(integer sender_num, integer num, string str, key id)
{
if( str=="go" )
{
state countdown;
}
}
}
state countdown
{
state_entry()
{
llSetTimerEvent(20);
llSay(0,"Welcome to the touring balloon ride. The balloon will take flight in 20 seconds. Please take your seats!"

;
}
timer()
{
state running;
}
}