
var params=new Array();params['delay']=80;params['friction']=0.1;params['start']=new GLatLng(0,0);params['inProgress']=false;params['lenience']=20;params['routes']=[{"id":0,"description":"Sydney, Australia: The Bondi Beach Run","from":"Sydney, Australia","to":"Bondi Beach, Australia","fulltext":"Fast and long straights mean lots of speed in this easy beginner's course.","latlng":new GLatLng(-33.868333,151.208611)},{"id":1,"description":"Paris, France: Landmarks and long straights","from":"Arc de Triomphe, 75008 Paris, Paris, Ile-de-France, France","to":"Eiffel Tower, France","fulltext":"High speeds with some dangerous hairpin turns, from the Arc de Triomphe to the Eiffel Tower.","latlng":new GLatLng(48.8667,2.3331)},{"id":2,"description":"Swindon, UK: Magic roundabouts","from":"Medgbury Road, Swindon, UK","to":"Marsh Farm Lane, Swindon, UK","fulltext":"It's a short run, but it goes through the greatest piece of traffic engineering in history: a roundabout, surrounded by five other mini-roundabouts.","latlng":new GLatLng(51.558333,-1.781111)},{"id":3,"description":"Gibraltar: Round the ragged Rock","from":"Rock Gun Road, Gibraltar","to":"Ragged Staff Road, Gibraltar","fulltext":"Sharp turns and mountain passes in this race to the waterfront.","latlng":new GLatLng(36.139690,-5.347720)},{"id":4,"description":"Boston, USA: Race to the Quay","from":"Hull St, Boston, MA","to":"Long Wharf, Boston, Suffolk, Massachusetts, United States","fulltext":"Warning: this route is not recommended for real life.","latlng":new GLatLng(42.360130,-71.048600)},{"id":5,"description":"Cork, Ireland: Twisty Island Dash","from":"N22/Western Rd @51.893450, -8.501260","to":"Lower Oliver Plunkett St @51.898970, -8.465690 to:Father Matthew Quay @51.895330, -8.469810","fulltext":"Long straights let you pick up speed, but prepare to brake hard: the second section of this course requires some tricky manoeuvring.  <small>submitted by Will Knott</small>","latlng":new GLatLng(51.893450,-8.501260)},{"id":6,"description":"Seaton Sluice, UK: To the Beach!","from":"B1325/Hartley Ln @55.060750, -1.483230","to":"Unknown road @55.086580, -1.479190","fulltext":"Quite a long one, with hairpin turns, a long home straight &mdash; but brake for the roundabout at the end! Genuinely used by boy racers, and the scene of many an accident.  <small>submitted by Richard Bosson</small>","latlng":new GLatLng(55.060750,-1.483230)},{"id":7,"description":"Rome, Italy: In the Avenues and Alleyways","from":"65 Via del Corso, Rome, Italy","to":"Via Pompeo Magno @41.909680, 12.465790","fulltext":"&quot;Where a man's got to work out which side he's on<br>Any way he chooses, chances are he loses<br>No-one gets to live too long&quot;<br>&mdash; Tony Christie, <i>Avenues and Alleyways</i><br><small>route submitted by Theo D. Williams</small>","latlng":new GLatLng(41.909680,12.465790)},{"id":8,"description":"A Coruņa, Spain: Blue Seas and High Speed","from":"Calle Dique de Abrigo Barrie de la Maza @43.365080, -8.374791","to":"Plaza de Lugo @43.365832, -8.406626","fulltext":"A long straight down a spit of coastline turns into a fast street race down the seafront.","latlng":new GLatLng(43.365080,-8.374791)}]
function carObject(human,lat,lng,dir,spd,acc,brk,turn,turnslow){this.human=human;this.lat=lat;this.lng=lng;this.dir=dir;this.spd=spd;this.acc=acc;this.brk=brk;this.turn=turn;this.turnslow=turnslow;this.marker=new GMarker(0,icons[0]);this.checkpointID=0;}
var cars=new Array();function loadCars(){cars[0]=new carObject(true,0,0,0,0,9,22,150,10);cars[1]=new carObject(false,0,0,0,0,7.8,22,150,10);cars[2]=new carObject(false,0,0,0,0,7.2,21,140,10);cars[3]=new carObject(false,0,0,0,0,6.9,20,110,10);}
var keys=new Array();function resetKeys(){keys['up']=false;keys['down']=false;keys['left']=false;keys['right']=false;}
var map;var icons=new Array();function load(){if(GBrowserIsCompatible()){map=new GMap2(document.getElementById("map"));icons[0]=new GIcon();icons[0].image="car0.png";icons[0].iconSize=new GSize(28,28);icons[0].iconAnchor=new GPoint(10,14);icons[0].infoWindowAnchor=new GPoint(10,14);params['checkpointIcon']=new GIcon();params['checkpointIcon'].image="checkpoint.png";params['checkpointIcon'].iconSize=new GSize(32,32);params['checkpointIcon'].iconAnchor=new GPoint(16,16);params['checkpointIcon'].infoWindowAnchor=new GPoint(16,16);params['finishIcon']=new GIcon(params['checkpointIcon']);params['finishIcon'].image="star.png";loadMenu();params['directions']=new GDirections();GEvent.addListener(params['directions'],"load",gotDirections);GEvent.addListener(params['directions'],"error",gotDirections);}
tick();}
function loadMenu(){params['inProgress']=false;map.setCenter(params['start'],2,G_SATELLITE_MAP);resetGame();document.getElementById('stats').style.display='none';document.getElementById('router').style.display='none';document.getElementById('title').style.display='block';}
function chooseRoute(){resetGame();document.getElementById('title').style.display='none';document.getElementById('router').style.display='block';for(i=0;i<params['routes'].length;i++){map.addOverlay(params['routes'][i].marker=new GMarker(params['routes'][i].latlng));GEvent.addListener(params['routes'][i].marker,"click",createRouteMarkerClickFunction(i));}}
function createRouteMarkerClickFunction(i){return function(){this.openInfoWindowHtml('<p><a href="#" onClick="startDirRequest(\''+params['routes'][i].from+'\',\''+params['routes'][i].to+'\')">'+params['routes'][i].description+'</a></p><p>'+params['routes'][i].fulltext+'</p>');}}
function resetGame(){map.clearOverlays();document.controlForm.speedo.value=0;document.controlForm.time.value='0:00';document.controlForm.checkpoints.value=0;loadCars();resetKeys();params['tick']=0;}
function dealwithRequest(){startDirRequest(document.controlForm.from.value,document.controlForm.to.value);}
function startDirRequest(from,to){params['directions'].load("from: "+from+" to: "+to,{"getPolyline":true,"locale":"en_GB","preserveViewport":true});}
function getNextCheckpoint(car){car['checkpointID']++;if(car['checkpointID']<params['route'].getVertexCount()){if(car.human){document.controlForm.checkpoints.value=params['route'].getVertexCount()-car['checkpointID'];nextCheckpoint=params['route'].getVertex(car['checkpointID']);params['checkpoint'].setPoint(nextCheckpoint);}}else{gameComplete(car);}}
function gameComplete(car){document.controlForm.checkpoints.value=0;map.removeOverlay(params['route']);map.removeOverlay(params['checkpoint']);params['inProgress']=false;document.getElementById('stats').style.display='block';var distance=params['directions'].getDistance();if(car.human){document.getElementById('stats').innerHTML='<h2>You win!</h2><p>You travelled '+Math.round(distance['meters']/16.09344)/100+' miles in '+getTime()+', an average of '+Math.round((distance['meters']/((params['tick']*params['delay'])/1000))*2.23693629)+' mph!</p><p><a href="#" onClick="loadMenu()">Back to main menu</a></p>';}else{document.getElementById('stats').innerHTML='<h2>You lose.</h2><p>One of your opponents reached the finish line before you.</p><p><a href="#" onClick="loadMenu()">Back to main menu</a></p>';}}
function gotDirections(){document.playForm.play.focus();document.getElementById('routerText').innerHTML='Choose a route by clicking on a marker, or enter your own.<br>Don\'t make it longer than about two miles.';document.routeform.go.disabled=false;if(params['route']=params['directions'].getPolyline()){if(params['route'].getVertexCount()>1){resetGame();document.getElementById('router').style.display='none';document.getElementById('title').style.display='none';params['checkpoint']=new GMarker(0,params['checkpointIcon']);map.addOverlay(params['route']);params['finishMarker']=new GMarker(params['route'].getVertex(params['route'].getVertexCount()-1),params['finishIcon']);map.addOverlay(params['finishMarker']);for(var i=0;i<cars.length;i++){getNextCheckpoint(cars[i]);map.addOverlay(params['checkpoint']);var startPoint=params['route'].getVertex(0);cars[i].lat=startPoint.lat();cars[i].lng=startPoint.lng();cars[i].marker=new GMarker(new GLatLng(cars[i].lat,cars[i].lng),icons[0]);map.addOverlay(cars[i].marker);cars[i].dir=getBearing(startPoint,params['route'].getVertex(1));cars[i].marker.setImage(pickImage(cars[i]));}
map.setCenter(startPoint,17,G_SATELLITE_MAP);params['inProgress']=true;}else{failDirections();}}else{failDirections();}}
function pickImage(car){var dir=Math.floor(((car.dir+11.25)%360)/22.5);if(car.human){return'carh'+dir+'.png';}else{return'car'+dir+'.png';}}
function failDirections(){document.getElementById('routerText').innerHTML='Google couldn\'t understand those directions.<br>Make sure you\'re giving full directions, like "High Street, Sometown, UK".';document.routeform.go.disabled=false;}
function handleKeyDown(code){switch(code){case 38:case 87:keys['up']=true;break;case 40:case 83:keys['down']=true;break;case 39:case 68:keys['right']=true;break;case 37:case 65:keys['left']=true;break;}}
function handleKeyUp(code){switch(code){case 38:keys['up']=false;break;case 40:keys['down']=false;break;case 39:keys['right']=false;break;case 37:keys['left']=false;break;}}
function getTime(){var minutes=Math.floor((params['tick']*params['delay'])/60000);var seconds=Math.round((params['tick']*params['delay'])/1000)%60;if(seconds<10){seconds='0'+seconds;}
return minutes+":"+seconds;}
function updateCar(car){if(params['inProgress']){if(car.human){if(keys['left']){car.dir-=car.turn/(1000/params['delay']);if(car.dir<0){car.dir+=360;}}
if(keys['right']){car.dir+=car.turn/(1000/params['delay']);if(car.dir>360){car.dir-=360;}}
if(keys['left']||keys['right']){car.marker.setImage(pickImage(car));car.spd-=(car.turnslow)/(1000/params['delay']);}
if(keys['up']){car.spd+=(car.acc/(1000/params['delay']));}
if(keys['down']){car.spd-=(car.brk/(1000/params['delay']));}
if(car.spd<0){car.spd=0;}
car.spd-=car.spd*(params['friction']/(1000/params['delay']));var mph=2.23693629*(car.spd);document.controlForm.speedo.value=Math.round(mph);}else{car.spd+=(car.acc/(1000/params['delay']));var rightNeeded=((car.dir-getBearing(car.marker.getPoint(),params['route'].getVertex(car['checkpointID'])))+360)%360;var leftNeeded=((getBearing(car.marker.getPoint(),params['route'].getVertex(car['checkpointID']))-car.dir)+360)%360;if(leftNeeded>rightNeeded){if(rightNeeded>7){car.dir-=car.turn/(1000/params['delay']);car.marker.setImage(pickImage(car));car.spd-=(car.turnslow)/(1000/params['delay']);if(car.dir<0){car.dir+=360;}
if(rightNeeded>90){car.spd-=(car.brk/(1000/params['delay']));}}}
if(leftNeeded<rightNeeded){if(leftNeeded>7){car.dir+=car.turn/(1000/params['delay']);car.marker.setImage(pickImage(car));car.spd-=(car.turnslow)/(1000/params['delay']);if(car.dir>360){car.dir-=360;}
if(rightNeeded>90){car.spd-=(car.brk/(1000/params['delay']));}}}
car.spd-=car.spd*(params['friction']/(1000/params['delay']));}
if(car['checkpointID']){if(car.marker.getPoint().distanceFrom(params['route'].getVertex(car['checkpointID']))<params['lenience']){getNextCheckpoint(car);}}}else{if(car.spd>0){car.spd-=(car.brk/(1000/params['delay']));if(car.spd<0){car.spd=0;}}}}
function moveCar(car){var nsVel=Math.cos((car.dir*-1).toRad())*car.spd;var ewVel=Math.sin(car.dir.toRad())*car.spd;var latVel=nsVel/78846.80572*(Math.cos(car.lat.toRad()));var lngVel=ewVel/78846.80572;var latSpd=latVel>=0?latVel:latVel*-1;var lngSpd=lngVel>=0?lngVel:lngVel*-1;car.lat=car.lat+latVel/(1000/params['delay']);car.lng=car.lng+lngVel/(1000/params['delay']);car.marker.setPoint(new GLatLng(car.lat,car.lng));}
function tick(){if(document.getElementById('title').style.display=='none'){if(params['inProgress']){params['tick']++;if(params['tick']>0){document.controlForm.time.value=getTime();}
for(var i=0;i<cars.length;i++){updateCar(cars[i]);moveCar(cars[i]);}}
var currentViewport=map.getBounds();var markerSafeAreaS=cars[0].lat-(map.getZoom()/20000);var markerSafeAreaN=cars[0].lat+(map.getZoom()/20000);var markerSafeAreaE=cars[0].lng+(map.getZoom()/20000);var markerSafeAreaW=cars[0].lng-(map.getZoom()/20000);var markerSafeAreaSW=new GLatLng(markerSafeAreaS,markerSafeAreaW);var markerSafeAreaNE=new GLatLng(markerSafeAreaN,markerSafeAreaE);var markerSafeArea=new GLatLngBounds(markerSafeAreaSW,markerSafeAreaNE);if(!currentViewport.containsBounds(markerSafeArea)){map.setCenter(cars[0].marker.getPoint());}}
setTimeout('tick()',params['delay']);}
function getZoomFor(mph){if(mph<30){return 20;}
if(mph<70){return 19;}
if(mph<120){return 18;}
return 17;}
function getBearing(LatLng1,LatLng2){lat1=LatLng1.lat();lat2=LatLng2.lat();lon1=LatLng1.lng();lon2=LatLng2.lng();lat1=lat1.toRad();lat2=lat2.toRad();var dLon=(lon2-lon1).toRad();var y=Math.sin(dLon)*Math.cos(lat2);var x=Math.cos(lat1)*Math.sin(lat2)-
Math.sin(lat1)*Math.cos(lat2)*Math.cos(dLon);return Math.atan2(y,x).toBrng();}
Number.prototype.toRad=function(){return this*Math.PI/180;}
Number.prototype.toDeg=function(){return this*180/Math.PI;}
Number.prototype.toBrng=function(){return(this.toDeg()+360)%360;}