diff --git a/src/ATC/tower.cxx b/src/ATC/tower.cxx
index b99825461..d499ff026 100644
--- a/src/ATC/tower.cxx
+++ b/src/ATC/tower.cxx
@@ -3,6 +3,7 @@
 // Written by David Luff, started March 2002.
 //
 // Copyright (C) 2002  David C. Luff - david.luff@nottingham.ac.uk
+// Copyright (C) 2008  Daniyar Atadjanov (ground clearance, gear check, weather, etc.)
 //
 // This program is free software; you can redistribute it and/or
 // modify it under the terms of the GNU General Public License as
@@ -28,10 +29,16 @@
 #  include <string.h>    // MSVC doesn't have strings.h
 #endif
 
+#include <sstream>
+#include <iomanip>
+
+#include <simgear/debug/logstream.hxx>
+#include <simgear/math/sg_geodesy.hxx>
+#include <simgear/math/sg_random.h>
+#include <simgear/misc/sg_path.hxx>
+
 #include <Main/globals.hxx>
 #include <Airports/runways.hxx>
-#include <simgear/math/sg_geodesy.hxx>
-#include <simgear/debug/logstream.hxx>
 
 #include "tower.hxx"
 #include "ATCmgr.hxx"
@@ -40,6 +47,7 @@
 #include "commlist.hxx"
 #include "AILocalTraffic.hxx"
 
+
 SG_USING_STD(cout);
 
 // TowerPlaneRec
@@ -50,6 +58,7 @@ TowerPlaneRec::TowerPlaneRec() :
 	clearedToLineUp(false),
 	clearedToTakeOff(false),
 	holdShortReported(false),
+	lineUpReported(false),
 	downwindReported(false),
 	longFinalReported(false),
 	longFinalAcknowledged(false),
@@ -66,6 +75,8 @@ TowerPlaneRec::TowerPlaneRec() :
 	opType(TTT_UNKNOWN),
 	leg(LEG_UNKNOWN),
 	landingType(AIP_LT_UNKNOWN),
+	gearWasUp(false),
+	gearUpReported(false),
 	isUser(false)
 {
 	plane.callsign = "UNKNOWN";
@@ -77,6 +88,7 @@ TowerPlaneRec::TowerPlaneRec(const PlaneRec& p) :
 	clearedToLineUp(false),
 	clearedToTakeOff(false),
 	holdShortReported(false),
+	lineUpReported(false),
 	downwindReported(false),
 	longFinalReported(false),
 	longFinalAcknowledged(false),
@@ -93,6 +105,8 @@ TowerPlaneRec::TowerPlaneRec(const PlaneRec& p) :
 	opType(TTT_UNKNOWN),
 	leg(LEG_UNKNOWN),
 	landingType(AIP_LT_UNKNOWN),
+	gearWasUp(false),
+	gearUpReported(false),
 	isUser(false)
 {
 	plane = p;
@@ -104,6 +118,7 @@ TowerPlaneRec::TowerPlaneRec(const Point3D& pt) :
 	clearedToLineUp(false),
 	clearedToTakeOff(false),
 	holdShortReported(false),
+	lineUpReported(false),
 	downwindReported(false),
 	longFinalReported(false),
 	longFinalAcknowledged(false),
@@ -120,6 +135,8 @@ TowerPlaneRec::TowerPlaneRec(const Point3D& pt) :
 	opType(TTT_UNKNOWN),
 	leg(LEG_UNKNOWN),
 	landingType(AIP_LT_UNKNOWN),
+	gearWasUp(false),
+	gearUpReported(false),
 	isUser(false)
 {
 	plane.callsign = "UNKNOWN";
@@ -132,6 +149,7 @@ TowerPlaneRec::TowerPlaneRec(const PlaneRec& p, const Point3D& pt) :
 	clearedToLineUp(false),
 	clearedToTakeOff(false),
 	holdShortReported(false),
+	lineUpReported(false),
 	downwindReported(false),
 	longFinalReported(false),
 	longFinalAcknowledged(false),
@@ -148,6 +166,8 @@ TowerPlaneRec::TowerPlaneRec(const PlaneRec& p, const Point3D& pt) :
 	opType(TTT_UNKNOWN),
 	leg(LEG_UNKNOWN),
 	landingType(AIP_LT_UNKNOWN),
+	gearWasUp(false),
+	gearUpReported(false),
 	isUser(false)
 {
 	plane = p;
@@ -288,6 +308,8 @@ void FGTower::Init() {
 		}
 	}
 	
+	RemoveAllUserDialogOptions();
+	
 	// TODO - attempt to get a departure control pointer to see if we need to hand off departing traffic to departure.
 	
 	// Get the airport elevation
@@ -298,7 +320,13 @@ void FGTower::Init() {
 	
 	// TODO - this currently assumes only one active runway.
 	rwyOccupied = OnActiveRunway(Point3D(user_lon_node->getDoubleValue(), user_lat_node->getDoubleValue(), 0.0));
-	if(rwyOccupied) {
+	
+	if(!OnAnyRunway(Point3D(user_lon_node->getDoubleValue(), user_lat_node->getDoubleValue(), 0.0), false)) {
+		//cout << ident << "  ADD 0\n";
+		current_atcdialog->add_entry(ident, "@AP Tower, @CS @MI miles @CD of the airport for full stop@AT",
+				"Contact tower for VFR arrival (full stop)", TOWER,
+				(int)USER_REQUEST_VFR_ARRIVAL_FULL_STOP);
+	} else {
 		//cout << "User found on active runway\n";
 		// Assume the user is started at the threshold ready to take-off
 		TowerPlaneRec* t = new TowerPlaneRec;
@@ -309,18 +337,12 @@ void FGTower::Init() {
 		t->leg = TAKEOFF_ROLL;
 		t->isUser = true;
 		t->planePtr = NULL;
-		t->clearedToTakeOff = true;
+		t->clearedToTakeOff = false;
 		rwyList.push_back(t);
 		rwyListItr = rwyList.begin();
 		departed = false;
-	} else {
-		//cout << "User not on active runway\n";
-		// For now assume that this means the user is not at the airport and is in the air.
-		// TODO FIXME - this will break when user starts on apron, at hold short, etc.
-		if(!OnAnyRunway(Point3D(user_lon_node->getDoubleValue(), user_lat_node->getDoubleValue(), 0.0))) {
-			//cout << ident << "  ADD 0\n";
-			current_atcdialog->add_entry(ident, "@AP Tower, @CS @MI miles @CD of the airport for full stop with ATIS", "Contact tower for VFR arrival (full stop)", TOWER, (int)USER_REQUEST_VFR_ARRIVAL_FULL_STOP);
-		}
+		current_atcdialog->add_entry(ident, "@CS @TO", "Request departure / take-off clearance",
+				TOWER, (int)USER_REQUEST_TAKE_OFF);
 	}
 }
 
@@ -446,7 +468,7 @@ void FGTower::Update(double dt) {
 
 void FGTower::ReceiveUserCallback(int code) {
 	if(code == (int)USER_REQUEST_VFR_DEPARTURE) {
-		//cout << "User requested departure\n";
+		RequestDepartureClearance("USER");
 	} else if(code == (int)USER_REQUEST_VFR_ARRIVAL) {
 		VFRArrivalContact("USER");
 	} else if(code == (int)USER_REQUEST_VFR_ARRIVAL_FULL_STOP) {
@@ -462,6 +484,8 @@ void FGTower::ReceiveUserCallback(int code) {
 		ReportRunwayVacated("USER");
 	} else if(code == (int)USER_REPORT_GOING_AROUND) {
 		ReportGoingAround("USER");
+	} else if(code == (int)USER_REQUEST_TAKE_OFF) {
+		RequestTakeOffClearance("USER");
 	}
 }
 
@@ -483,11 +507,14 @@ void FGTower::Respond() {
 			// For now we'll clear straight in if greater than 1km from a line drawn through the threshold perpendicular to the rwy.
 			// Later on we might check the actual heading and direct some of those to enter on downwind or base.
 			Point3D op = ortho.ConvertToLocal(t->pos);
+			float gp = fgGetFloat("/gear/gear/position-norm");
+			if(gp < 1)
+				t->gearWasUp = true; // This will be needed on final to tell "Gear down, ready to land."
 			if(op.y() < -1000) {
 				trns += " Report three mile straight-in runway ";
 				t->opType = STRAIGHT_IN;
 				if(t->isUser) {
-					current_atcdialog->add_entry(ident, "@AP Tower, @CS @MI mile final Runway @RW", "Report Final", TOWER, (int)USER_REPORT_3_MILE_FINAL);
+					current_atcdialog->add_entry(ident, "@CS @MI mile final runway @RW@GR", "Report Final", TOWER, (int)USER_REPORT_3_MILE_FINAL);
 				} else {
 					t->planePtr->RegisterTransmission(14);
 				}
@@ -519,6 +546,41 @@ void FGTower::Respond() {
 			//cout << "Tower " << ident << " is responding to downwind reported...\n";
 			ProcessDownwindReport(t);
 			t->downwindReported = false;
+		} else if(t->lineUpReported) {
+			string trns = t->plane.callsign;
+			if(rwyOccupied) {
+				double f = globals->get_ATC_mgr()->GetFrequency(ident, ATIS) / 100.0;
+				string wtr;
+				if(!f) {
+					wtr = ", " + GetWeather();
+				}
+				trns += " Cleared for take-off" + wtr;
+				t->clearedToTakeOff = true;
+			} else {
+				if(!OnAnyRunway(Point3D(user_lon_node->getDoubleValue(), user_lat_node->getDoubleValue(), 0.0), true)) {
+					// TODO: Check if any AI Planes on final and tell something like: "After the landing CALLSIGN line up runway two eight right"
+					trns += " Line up runway " + ConvertRwyNumToSpokenString(activeRwy);
+					t->clearedToTakeOff = false;
+					current_atcdialog->add_entry(ident, "@CS @TO", "Report ready for take-off", TOWER, (int)USER_REQUEST_TAKE_OFF);
+
+				} else {
+					sg_srandom_time();
+					if((int(sg_random() * 10) + 1) != 3) {
+						t->clearedToTakeOff = true;
+						trns += " Cleared immediate take-off ";
+					} else {
+						t->clearedToTakeOff = false;
+						trns += " Negative, departure runway " + ConvertRwyNumToSpokenString(activeRwy);
+					}
+				}
+			}
+			if(_display) {
+				pending_transmission = trns;
+				Transmit();
+			} else {
+				//cout << "Not displaying, trns was " << trns << '\n';
+			}
+			t->lineUpReported = false;
 		} else if(t->holdShortReported) {
 			//cout << "Tower " << ident << " is reponding to holdShortReported...\n";
 			if(t->nextOnRwy) {
@@ -562,7 +624,14 @@ void FGTower::Respond() {
 				if(t->landingType == FULL_STOP) {
 					trns += " cleared to land ";
 				} else {
-					trns += " cleared for the option ";
+					double f = globals->get_ATC_mgr()->GetFrequency(ident, ATIS) / 100.0;
+					string wtr;
+					if(!f) {
+						wtr = ", " + GetWeather();
+					} else {
+						wtr = ", runway " + ConvertRwyNumToSpokenString(activeRwy);
+					}
+					trns += " cleared to land" + wtr;
 				}
 				// TODO - add winds
 				t->clearedToLand = true;
@@ -582,6 +651,15 @@ void FGTower::Respond() {
 				disp = false;
 			} else {
 				trns += " continue approach";
+				trns += " and report ";
+				trns += ((rwy.patternDirection == 1) ? "right " : "left ");
+				trns += "downwind runway " + ConvertRwyNumToSpokenString(activeRwy);
+				t->opType = CIRCUIT;
+				if(t->isUser) {
+					current_atcdialog->add_entry(ident, "@AP Tower, @CS Downwind @RW", "Report Downwind", TOWER, (int)USER_REPORT_DOWNWIND);
+				} else {
+					t->planePtr->RegisterTransmission(15);
+				}
 				t->clearedToLand = false;
 			}
 			if(_display && disp) {
@@ -616,7 +694,7 @@ void FGTower::ProcessDownwindReport(TowerPlaneRec* t) {
 	doThresholdETACalc();
 	TowerPlaneRec* tf = NULL;
 	for(tower_plane_rec_list_iterator twrItr = appList.begin(); twrItr != appList.end(); twrItr++) {
-		if((*twrItr)->eta < (t->eta + 45)) {
+		if((*twrItr)->eta < (t->eta + 45) && strcmp((*twrItr)->plane.callsign.c_str(), t->plane.callsign.c_str()) != 0) { // don't let ATC ask you to follow yourself
 			a++;
 			tf = *twrItr;
 			cf = true;
@@ -733,7 +811,7 @@ void FGTower::ClearHoldingPlane(TowerPlaneRec* t) {
 	//if(departed plane < some threshold in time away) {
 	if(0) {		// FIXME
 	//if(timeSinceLastDeparture <= 60.0 && departed == true) {
-		trns += " line up";
+		trns += " line up runway " + ConvertRwyNumToSpokenString(activeRwy);
 		t->clearedToLineUp = true;
 		t->planePtr->RegisterTransmission(3);	// cleared to line-up
 	//} else if(arriving plane < some threshold away) {
@@ -855,7 +933,8 @@ void FGTower::CheckHoldList(double dt) {
 				//cout << "departed = " << departed << '\n';
 				//cout << "timeSinceLastDeparture = " << timeSinceLastDeparture << '\n';
 				if(rwyOccupied) {
-					// Do nothing
+					RemoveAllUserDialogOptions();
+					current_atcdialog->add_entry(ident, "@CS Ready for take-off", "Request take-off clearance", TOWER, (int)USER_REQUEST_TAKE_OFF);
 				} else if(timeSinceLastDeparture <= 60.0 && departed == true) {
 					// Do nothing - this is a bit of a hack - should maybe do line up be ready here
 				} else {
@@ -1060,18 +1139,29 @@ void FGTower::CheckCircuitList(double dt) {
 				// eg. is the plane accelerating down the runway taking off [OK],
 				// or stationary near the start [V. BAD!!].
 				// For now this should stop the AI plane landing on top of the user.
-				string trns = t->plane.callsign;
-				trns += " GO AROUND TRAFFIC ON RUNWAY I REPEAT GO AROUND";
-				pending_transmission = trns;
-				ImmediateTransmit();
-				t->instructedToGoAround = true;
-				t->clearedToLand = false;
-				// Assume it complies!!!
-				t->opType = CIRCUIT;
-				t->leg = CLIMBOUT;
-				if(t->planePtr) {
-					//cout << "Registering Go-around transmission with AI plane\n";
-					t->planePtr->RegisterTransmission(13);
+				tower_plane_rec_list_iterator twrItr;
+				twrItr = rwyList.begin();
+				TowerPlaneRec* tpr = *twrItr;
+				if(strcmp(tpr->plane.callsign.c_str(), t->plane.callsign.c_str()) == 0
+						&& rwyList.size() == 1) {
+					// Fixing bug when ATC says that we must go around because of traffic on rwy
+					// but that traffic is our plane! In future we can use this expression
+					// for other ATC-messages like "On ground at 46, vacate left."
+
+				} else {
+					string trns = t->plane.callsign;
+					trns += " GO AROUND TRAFFIC ON RUNWAY I REPEAT GO AROUND";
+					pending_transmission = trns;
+					ImmediateTransmit();
+					t->instructedToGoAround = true;
+					t->clearedToLand = false;
+					// Assume it complies!!!
+					t->opType = CIRCUIT;
+					t->leg = CLIMBOUT;
+					if(t->planePtr) {
+						//cout << "Registering Go-around transmission with AI plane\n";
+						t->planePtr->RegisterTransmission(13);
+					}
 				}
 			} else if(!t->clearedToLand) {
 				// The whip through the appList is a hack since currently t->nextOnRwy doesn't always work
@@ -1205,29 +1295,56 @@ void FGTower::CheckApproachList(double dt) {
 		}
 		doThresholdETACalc();	// We need this here because planes in the lists are not guaranteed to *always* have the correct ETA
 		//cout << "eta is " << t->eta << ", rwy is " << (rwyList.size() ? "occupied " : "clear ") << '\n';
+		Point3D tortho = ortho.ConvertToLocal(t->pos);
 		if(t->eta < 12 && rwyList.size() && !(t->instructedToGoAround)) {
 			// TODO - need to make this more sophisticated 
 			// eg. is the plane accelerating down the runway taking off [OK],
 			// or stationary near the start [V. BAD!!].
 			// For now this should stop the AI plane landing on top of the user.
-			string trns = t->plane.callsign;
-			trns += " GO AROUND TRAFFIC ON RUNWAY I REPEAT GO AROUND";
-			pending_transmission = trns;
-			ImmediateTransmit();
-			t->instructedToGoAround = true;
-			t->clearedToLand = false;
-			t->nextOnRwy = false;	// But note this is recalculated so don't rely on it
-			// Assume it complies!!!
-			t->opType = CIRCUIT;
-			t->leg = CLIMBOUT;
-			if(!t->isUser) {
-				if(t->planePtr) {
-					//cout << "Registering Go-around transmission with AI plane\n";
-					t->planePtr->RegisterTransmission(13);
-				}
+			tower_plane_rec_list_iterator twrItr;
+			twrItr = rwyList.begin();
+			TowerPlaneRec* tpr = *twrItr;
+			if(strcmp ( tpr->plane.callsign.c_str(), t->plane.callsign.c_str() ) == 0 && rwyList.size() == 1) {
+					// Fixing bug when ATC says that we must go around because of traffic on rwy
+					// but that traffic is we! In future we can use this expression
+					// for other ATC-messages like "On ground at 46, vacate left."
+
 			} else {
-				// TODO - add Go-around ack to comm options,
-				// remove report rwy vacated. (possibly).
+				string trns = t->plane.callsign;
+				trns += " GO AROUND TRAFFIC ON RUNWAY I REPEAT GO AROUND";
+				pending_transmission = trns;
+				ImmediateTransmit();
+				t->instructedToGoAround = true;
+				t->clearedToLand = false;
+				t->nextOnRwy = false;	// But note this is recalculated so don't rely on it
+				// Assume it complies!!!
+				t->opType = CIRCUIT;
+				t->leg = CLIMBOUT;
+				if(!t->isUser) {
+					if(t->planePtr) {
+						//cout << "Registering Go-around transmission with AI plane\n";
+						t->planePtr->RegisterTransmission(13);
+					}
+				} else {
+					// TODO - add Go-around ack to comm options,
+					// remove report rwy vacated. (possibly).
+				}
+			}
+		} else if(t->isUser && t->eta < 90 && tortho.y() > -2500 && t->clearedToLand && t->gearUpReported == false) {
+			// Check if gear up or down
+			double gp = fgGetFloat("/gear/gear/position-norm");
+			if(gp < 1) {
+				string trnsm = t->plane.callsign;
+				sg_srandom_time();
+				int rnd = int(sg_random() * 2) + 1;
+				if(rnd == 2) {				// Random message for more realistic ATC ;)
+					trnsm += ", LANDING GEAR APPEARS UP!";
+				} else {
+					trnsm += ", Check wheels down and locked.";
+				}
+				pending_transmission = trnsm;
+				ImmediateTransmit();
+				t->gearUpReported = true;
 			}
 		} else if(t->eta < 90 && !t->clearedToLand) {
 			//doThresholdETACalc();
@@ -1310,6 +1427,12 @@ void FGTower::CheckDepartureList(double dt) {
 		if(t->isUser) distout = dclGetHorizontalSeparation(Point3D(lon, lat, elev), Point3D(user_lon_node->getDoubleValue(), user_lat_node->getDoubleValue(), user_elev_node->getDoubleValue()));
 		else distout = dclGetHorizontalSeparation(Point3D(lon, lat, elev), t->planePtr->GetPos());
 		//cout << " distout = " << distout << '\n';
+		if(t->isUser && !(t->clearedToTakeOff)) {	// HACK - we use clearedToTakeOff to check if ATC already contacted with plane (and cleared take-off) or not
+			if(!OnAnyRunway(Point3D(user_lon_node->getDoubleValue(), user_lat_node->getDoubleValue(), 0.0), false)) {
+				current_atcdialog->remove_entry(ident, USER_REQUEST_TAKE_OFF, TOWER);
+				t->clearedToTakeOff = true;	// FIXME
+			}
+		}
 		if(distout > 10000) {
 			string trns = t->plane.callsign;
 			trns += " You are now clear of my airspace, good day";
@@ -1319,7 +1442,7 @@ void FGTower::CheckDepartureList(double dt) {
 				// Change the communication options
 				RemoveAllUserDialogOptions();
 				//cout << "ADD A\n";
-				current_atcdialog->add_entry(ident, "@AP Tower, @CS @MI miles @CD of the airport for full stop with ATIS", "Contact tower for VFR arrival (full stop)", TOWER, (int)USER_REQUEST_VFR_ARRIVAL_FULL_STOP);
+				current_atcdialog->add_entry(ident, "@AP Tower, @CS @MI miles @CD of the airport for full stop@AT", "Contact tower for VFR arrival (full stop)", TOWER, (int)USER_REQUEST_VFR_ARRIVAL_FULL_STOP);
 			} else {
 				// Send a clear-of-airspace signal
 				// TODO - implement this once we actually have departing AI traffic (currently all circuits or arrivals).
@@ -1345,6 +1468,7 @@ void FGTower::RemoveAllUserDialogOptions() {
 	current_atcdialog->remove_entry(ident, USER_REPORT_DOWNWIND, TOWER);
 	current_atcdialog->remove_entry(ident, USER_REPORT_RWY_VACATED, TOWER);
 	current_atcdialog->remove_entry(ident, USER_REPORT_GOING_AROUND, TOWER);	
+	current_atcdialog->remove_entry(ident, USER_REQUEST_TAKE_OFF, TOWER);
 }
 
 // Returns true if positions of crosswind/downwind/base leg turns should be constrained by previous traffic
@@ -1460,17 +1584,17 @@ bool FGTower::OnActiveRunway(const Point3D& pt) {
 	double wdiff = fabs(xyp.x() - xyc.x());
 
 	return((ldiff < rlen) && (wdiff < rwidth));
-}	
-
+}
 
 // Figure out if a given position lies on any runway or not
 // Only call this at startup - reading the runways database is expensive and needs to be fixed!
-bool FGTower::OnAnyRunway(const Point3D& pt) {
+bool FGTower::OnAnyRunway(const Point3D& pt, bool onGround) {
 	ATCData ad;
-	double dist = current_commlist->FindClosest(lon, lat, elev, ad, TOWER, 10.0);
+	double dist = current_commlist->FindClosest(lon, lat, elev, ad, TOWER, 7.0);
 	if(dist < 0.0) {
 		return(false);
 	}
+	
 	// Based on the airport-id, go through all the runways and check for a point in them
 	
 	// TODO - do we actually need to search for the airport - surely we already know our ident and
@@ -1482,11 +1606,16 @@ bool FGTower::OnAnyRunway(const Point3D& pt) {
 		SG_LOG(SG_ATC, SG_WARN, "Unable to find any runways for airport ID " << ad.ident << " in FGTower");
 	}
 	bool on = false;
-	while(runway._id == ad.ident) {		
+	while(runway._id == ad.ident) {
 		on = OnRunway(pt, runway);
 		//cout << "Runway " << runway._rwy_no << ": On = " << (on ? "true\n" : "false\n");
-		if(on) return(true);
-		globals->get_runways()->next(&runway);		
+		if(on) {
+			if(onGround == false)
+				return(true);
+			if(runway._rwy_no != "xx")
+				return(true);
+		}
+		globals->get_runways()->next(&runway);
 	}
 	return(on);
 }
@@ -1684,6 +1813,15 @@ void FGTower::AddToVacatedList(TowerPlaneRec* t) {
 	vacatedList.push_back(t);
 }
 
+void FGTower::AddToHoldingList(TowerPlaneRec* t) {
+	tower_plane_rec_list_iterator it, end = holdList.end();
+	for (it = holdList.begin(); it != end; ++it) {
+		if ((*it)->plane.callsign == t->plane.callsign)
+			return;
+	
+		holdList.push_back(t);
+	}
+}
 
 // Calculate the eta of a plane to the threshold.
 // For ground traffic this is the fastest they can get there.
@@ -2057,6 +2195,25 @@ void FGTower::VFRArrivalContact(const PlaneRec& plane, FGAIPlane* requestee, con
 void FGTower::RequestDepartureClearance(const string& ID) {
 	//cout << "Request Departure Clearance called...\n";
 }
+
+void FGTower::RequestTakeOffClearance(const string& ID) {
+	string uid=ID;
+	if(ID == "USER") {
+		uid = fgGetString("/sim/user/callsign");
+		current_atcdialog->remove_entry(ident, USER_REQUEST_TAKE_OFF, TOWER);
+	}
+	TowerPlaneRec* t = FindPlane(uid);
+	if(t) {
+		if(!(t->clearedToTakeOff)) {
+			departed = false;
+			t->lineUpReported=true;
+			responseReqd = true;
+		}
+	}
+	else {
+		SG_LOG(SG_ATC, SG_WARN, "WARNING: Unable to find plane " << ID << " in FGTower::RequestTakeOffClearance(...)");
+	}
+}
 	
 void FGTower::ReportFinal(const string& ID) {
 	//cout << "Report Final Called at tower " << ident << " by plane " << ID << '\n';
@@ -2297,6 +2454,7 @@ string FGTower::GenText(const string& m, int c) {
 	int len;
 	//FGTransmission t;
 	string usercall = fgGetString("/sim/user/callsign");
+	TowerPlaneRec* t = FindPlane(responseID);
 	
 	//transmission_list_type     tmissions = transmissionlist_station[station];
 	//transmission_list_iterator current   = tmissions.begin();
@@ -2313,6 +2471,7 @@ string FGTower::GenText(const string& m, int c) {
 			
 			// Replace all the '@' parameters with the actual text.
 			int check = 0;	// If mes gets overflowed the while loop can go infinite
+			double gp = fgGetFloat("/gear/gear/position-norm");
 			while ( strchr(&mes[0], crej) != NULL  ) {	// ie. loop until no more occurances of crej ('@') found
 				pos = strchr( &mes[0], crej );
 				memmove(&tag[0], pos, 3);
@@ -2356,6 +2515,19 @@ string FGTower::GenText(const string& m, int c) {
 					strcat( &dum[0], &buf[0] );
 					*/
 				}
+				else if ( strcmp ( tag, "@AT" ) == 0 ) {	// ATIS ID
+					/*
+					char buf[10];
+					sprintf( buf, "%i", (int)(tpars.heading) );
+					strcat( &dum[0], &buf[0] );
+					*/
+					double f = globals->get_ATC_mgr()->GetFrequency(ident, ATIS) / 100.0;
+					if(f) {
+						string atis_id;
+						atis_id = ", information " + GetATISID();
+						strcat( &dum[0], atis_id.c_str() );
+					}
+				}
 				else if ( strcmp ( tag, "@VD" ) == 0 ) {
 					/*
 					if ( tpars.VDir == 1 ) {
@@ -2379,6 +2551,20 @@ string FGTower::GenText(const string& m, int c) {
 					strcat( &dum[0], &buf[0] );
 					*/
 				}
+				else if ( strcmp ( tag, "@TO" ) == 0 ) {      // Requesting take-off or departure clearance
+					string tmp;
+					if (rwyOccupied) {
+						tmp = "Ready for take-off";
+					} else {
+						if (OnAnyRunway(Point3D(user_lon_node->getDoubleValue(),
+								user_lat_node->getDoubleValue(), 0.0),true)) {
+							tmp = "Request take-off clearance";
+						} else {
+							tmp = "Request departure clearance";
+						}
+					}
+					strcat(&dum[0], tmp.c_str());
+				}
 				else if ( strcmp ( tag, "@MI" ) == 0 ) {
 					char buf[10];
 					//sprintf( buf, "%3.1f", tpars.miles );
@@ -2395,7 +2581,13 @@ string FGTower::GenText(const string& m, int c) {
 				}
 				else if ( strcmp ( tag, "@RW" ) == 0 ) {
 					strcat(&dum[0], ConvertRwyNumToSpokenString(activeRwy).c_str());
-				} else if(strcmp(tag, "@CD") == 0) {	// @CD = compass direction
+				}
+				else if ( strcmp ( tag, "@GR" ) == 0 ) {	// Gear position (on final)
+					if(t->gearWasUp && gp > 0.99) {
+						strcat(&dum[0], ", gear down, ready to land.");
+					}
+				}
+				else if(strcmp(tag, "@CD") == 0) {	// @CD = compass direction
 					double h = GetHeadingFromTo(Point3D(lon, lat, elev), Point3D(user_lon_node->getDoubleValue(), user_lat_node->getDoubleValue(), user_elev_node->getDoubleValue()));
 					while(h < 0.0) h += 360.0;
 					while(h > 360.0) h -= 360.0;
@@ -2434,8 +2626,36 @@ string FGTower::GenText(const string& m, int c) {
 			//break;
 		//}
 	//}
-	if ( mes[0] ) return mes;
-	else return "No transmission found";
+	return mes[0] ? mes : "No transmission found";
+}
+
+string FGTower::GetWeather() {
+	std::ostringstream msg;
+
+	// wind
+	double hdg = wind_from_hdg->getDoubleValue();
+	double speed = wind_speed_knots->getDoubleValue();
+	if (speed==0)
+		msg << "wind calm";
+	else
+		msg << "wind " << int(hdg) << " degrees at " << int(speed) << " knots";
+
+	// visibility
+	double visibility = fgGetDouble("/environment/visibility-m");
+	if (visibility < 10000)
+		msg << ", visibility " << int(visibility / 1609) << " miles";
+
+	// pressure / altimeter
+	double pressure = fgGetDouble("/environment/pressure-sea-level-inhg");
+	msg << ", QFE " << fixed << setprecision(2) << pressure << ".";
+
+	return msg.str();
+}
+
+string FGTower::GetATISID() {
+	int hours = fgGetInt("/sim/time/utc/hour");
+	int phonetic_id = current_commlist->GetCallSign(ident, hours, 0);
+	return GetPhoneticIdent(phonetic_id);
 }
 
 ostream& operator << (ostream& os, tower_traffic_type ttt) {
diff --git a/src/ATC/tower.hxx b/src/ATC/tower.hxx
index 562f08ed5..0fe4103a7 100644
--- a/src/ATC/tower.hxx
+++ b/src/ATC/tower.hxx
@@ -60,7 +60,8 @@ enum tower_callback_type {
 	USER_REPORT_3_MILE_FINAL = 5,
 	USER_REPORT_DOWNWIND = 6,
 	USER_REPORT_RWY_VACATED = 7,
-	USER_REPORT_GOING_AROUND = 8
+	USER_REPORT_GOING_AROUND = 8,
+	USER_REQUEST_TAKE_OFF = 9
 };
 
 // TODO - need some differentiation of IFR and VFR traffic in order to give the former priority.
@@ -87,6 +88,7 @@ public:
 	bool clearedToTakeOff;
 	// ought to add time cleared to depart so we can nag if necessary
 	bool holdShortReported;
+	bool lineUpReported;
 	bool downwindReported;
 	bool longFinalReported;
 	bool longFinalAcknowledged;
@@ -98,6 +100,8 @@ public:
 	bool instructedToGoAround;	// set true if plane told by tower to go around.
 	bool onRwy;		// is physically on the runway
 	bool nextOnRwy;		// currently projected by tower to be the next on the runway
+	bool gearWasUp;          // Tell to ATC about gear
+	bool gearUpReported;     // Tell to pilot about landing gear
 	
 	bool vfrArrivalReported;
 	bool vfrArrivalAcknowledged;
@@ -139,6 +143,7 @@ public:
 	void VFRArrivalContact(const PlaneRec& plane, FGAIPlane* requestee, const LandingType& lt = AIP_LT_UNKNOWN);
 	
 	void RequestDepartureClearance(const string& ID);
+	void RequestTakeOffClearance(const string& ID);
 	void ReportFinal(const string& ID);
 	void ReportLongFinal(const string& ID);
 	void ReportOuterMarker(const string& ID);
@@ -177,9 +182,11 @@ public:
 	bool GetBaseConstraint(double& bpos);
 	
 	string GenText(const string& m, int c);
+	string GetWeather();
+	string GetATISID();
 
 private:
-	FGATCMgr* ATCmgr;	
+	FGATCMgr* ATCmgr;
 	// This is purely for synactic convienience to avoid writing globals->get_ATC_mgr()-> all through the code!
 	
 	// Respond to a transmission
@@ -213,7 +220,7 @@ private:
 	bool OnActiveRunway(const Point3D& pt);
 	
 	// Figure out if a given position lies on a runway or not
-	bool OnAnyRunway(const Point3D& pt);
+	bool OnAnyRunway(const Point3D& pt, bool onGround);
 	
 	// Calculate the eta of a plane to the threshold.
 	// For ground traffic this is the fastest they can get there.
@@ -255,6 +262,7 @@ private:
 	RunwayDetails rwy;	// Assumed to be the active one for now.
 	bool rwyOccupied;	// Active runway occupied flag.  For now we'll disregard land-and-hold-short operations.
 	FGATCAlignedProjection ortho;	// Orthogonal mapping of the local area with the active runway threshold at the origin
+	FGATCAlignedProjection ortho_temp;	// Ortho for any runway (needed to get plane position in airport)
 	
 	// Figure out which runways are active.
 	// For now we'll just be simple and do one active runway - eventually this will get much more complex
@@ -319,6 +327,8 @@ private:
 	
 	// Add to vacated list only if not already present
 	void AddToVacatedList(TowerPlaneRec* t);
+	
+	void AddToHoldingList(TowerPlaneRec* t);
 
 	// Ground can be separate or handled by tower in real life.
 	// In the program we will always use a separate FGGround class, but we need to know