// Levels
// 1 - NE, 4 - SE, 5 - SW, 2 - NW, 6 - NS, 3 - WE
var _tracks = [
  { s: {x: 1, y: 2}, length: 6, m:
    [ [ {t:0,n:  0}, {t:0,n:  0}, {t:0,n:  0}, {t:0,n:  0}, {t:0,n:  0}, {t:0,n:  0} ],
      [ {t:0,n:  0}, {t:4,n:  2}, {t:5,n:  3}, {t:0,n:  0}, {t:0,n:  0}, {t:0,n:  0} ],
      [ {t:0,n:  0}, {t:6,n:  1}, {t:6,n:  4}, {t:0,n:  0}, {t:0,n:  0}, {t:0,n:  0} ],
      [ {t:0,n:  0}, {t:1,n:  6}, {t:2,n:  5}, {t:0,n:  0}, {t:0,n:  0}, {t:0,n:  0} ],
      [ {t:0,n:  0}, {t:0,n:  0}, {t:0,n:  0}, {t:0,n:  0}, {t:0,n:  0}, {t:0,n:  0} ],
      [ {t:0,n:  0}, {t:0,n:  0}, {t:0,n:  0}, {t:0,n:  0}, {t:0,n:  0}, {t:0,n:  0} ]
    ]
  },

  { s: {x: 4, y: 3}, length: 12, m:
    [ [ {t:0,n:  0}, {t:0,n:  0}, {t:0,n:  0}, {t:0,n:  0}, {t:0,n:  0}, {t:0,n:  0} ],
      [ {t:0,n:  0}, {t:4,n:  6}, {t:3,n:  5}, {t:5,n:  4}, {t:0,n:  0}, {t:0,n:  0} ],
      [ {t:0,n:  0}, {t:1,n:  7}, {t:5,n:  8}, {t:1,n:  3}, {t:5,n:  2}, {t:0,n:  0} ],
      [ {t:0,n:  0}, {t:0,n:  0}, {t:1,n:  9}, {t:5,n: 10}, {t:6,n:  1}, {t:0,n:  0} ],
      [ {t:0,n:  0}, {t:0,n:  0}, {t:0,n:  0}, {t:1,n: 11}, {t:2,n: 12}, {t:0,n:  0} ],
      [ {t:0,n:  0}, {t:0,n:  0}, {t:0,n:  0}, {t:0,n:  0}, {t:0,n:  0}, {t:0,n:  0} ]
    ]
  },

  { s: {x: 2, y: 2}, length: 20, m:
    [ [ {t:0,n:  0}, {t:0,n:  0}, {t:0,n:  0}, {t:0,n:  0}, {t:0,n:  0}, {t:0,n:  0} ],
      [ {t:4,n:  4}, {t:3,n:  3}, {t:5,n:  2}, {t:0,n:  0}, {t:0,n:  0}, {t:0,n:  0} ],
      [ {t:6,n:  5}, {t:0,n:  0}, {t:6,n:  1}, {t:4,n: 18}, {t:5,n: 17}, {t:0,n:  0} ],
      [ {t:6,n:  6}, {t:0,n:  0}, {t:1,n: 20}, {t:2,n: 19}, {t:6,n: 16}, {t:0,n:  0} ],
      [ {t:6,n:  7}, {t:4,n: 10}, {t:5,n: 11}, {t:4,n: 14}, {t:2,n: 15}, {t:0,n:  0} ],
      [ {t:1,n:  8}, {t:2,n:  9}, {t:1,n: 12}, {t:2,n: 13}, {t:0,n:  0}, {t:0,n:  0} ]
    ]
  },

  { s: {x: 2, y: 3}, length: 34, m:
    [ [ {t:4,n: 20}, {t:3,n: 21}, {t:3,n: 22}, {t:3,n: 23}, {t:3,n: 24}, {t:5,n: 25} ],
      [ {t:6,n: 19}, {t:4,n: 10}, {t:3,n:  9}, {t:3,n:  8}, {t:5,n:  7}, {t:6,n: 26} ],
      [ {t:6,n: 18}, {t:6,n: 11}, {t:4,n:  2}, {t:5,n:  3}, {t:6,n:  6}, {t:6,n: 27} ],
      [ {t:6,n: 17}, {t:6,n: 12}, {t:6,n:  1}, {t:1,n:  4}, {t:2,n:  5}, {t:6,n: 28} ],
      [ {t:6,n: 16}, {t:6,n: 13}, {t:1,n: 34}, {t:5,n: 33}, {t:4,n: 30}, {t:2,n: 29} ],
      [ {t:1,n: 15}, {t:2,n: 14}, {t:0,n:  0}, {t:1,n: 32}, {t:2,n: 31}, {t:0,n:  0} ]
    ]
  },

  { s: {x: 0, y: 1}, length: 36, m:
    [ [ {t:4,n:  2}, {t:5,n:  3}, {t:4,n:  6}, {t:5,n:  7}, {t:4,n: 10}, {t:5,n: 11} ],
      [ {t:6,n:  1}, {t:1,n:  4}, {t:2,n:  5}, {t:1,n:  8}, {t:2,n:  9}, {t:6,n: 12} ],
      [ {t:1,n: 36}, {t:5,n: 35}, {t:4,n: 16}, {t:3,n: 15}, {t:3,n: 14}, {t:2,n: 13} ],
      [ {t:4,n: 33}, {t:2,n: 34}, {t:1,n: 17}, {t:3,n: 18}, {t:3,n: 19}, {t:5,n: 20} ],
      [ {t:6,n: 32}, {t:4,n: 29}, {t:5,n: 28}, {t:4,n: 25}, {t:5,n: 24}, {t:6,n: 21} ],
      [ {t:1,n: 31}, {t:2,n: 30}, {t:1,n: 27}, {t:2,n: 26}, {t:1,n: 23}, {t:2,n: 22} ]
    ]
  }
];

// Helpers: Cookie access.
function createCookie(name,value,days) { name = "racer" + name; var expires = ""; if (days) { var date = new Date(); date.setDate(date.getDate() + days); expires = "; expires=" + date.toGMTString(); } document.cookie = name + "=" + value + expires + "; path=/"; }
function readCookie(name) { name = "racer" + name; var nameEQ = name + "="; var ca = document.cookie.split(';'); for(var i = 0; i < ca.length; i++) { var c = ca[i]; while (c.charAt(0) == ' ') c = c.substring(1, c.length); if (c.indexOf(nameEQ) == 0) { var v = c.substring(nameEQ.length, c.length); return v; } } return null; }
function eraseCookie(name) { createCookie(name, "" , -1); }

// Helpers: String builder.
function StringBuilder(value) { this.strings = [""]; if (value) this.append(value); }
StringBuilder.prototype.append = function(v) { this.strings.push(v); }
StringBuilder.prototype.appendList = function() { for (var i = 0; i < arguments.length; i++) this.strings.push(arguments[i]); }
StringBuilder.prototype.clear = function() { this.strings.length = 1; }
StringBuilder.prototype.toString = function() { return this.strings.join(""); }

String.prototype.reverse = function() { splitext = this.split(""); revertext = splitext.reverse(); reversed = revertext.join(""); return reversed; }

// Trace.js

function trace() { }

// Physics.js

function v_(x, y) { return {x:x, y:y}; }
function v_c(a) { return {x:a.x, y:a.y}; }
function v_add(a, b) { return {x:a.x + b.x, y:a.y + b.y}; }
function v_sub(a, b) { return {x:a.x - b.x, y:a.y - b.y}; }
function v_mul(a, b) { return {x:a.x * b, y:a.y * b}; }
function v_madd(a, b, c) { return {x:a.x + b.x * c, y: a.y + b.y * c}; }
function v_dot(a, b) { return a.x * b.x + a.y * b.y; }
function v_len(a) { return Math.sqrt(v_dot(a, a)); }
function v_nor(a) { var inv_len = 1.0 / Math.sqrt(a.x * a.x + a.y * a.y); return {x:a.x * inv_len, y:a.y * inv_len}; }
function v_nor_2(a, b) { var inv_len = 1.0 / Math.sqrt(a * a + b * b); return {x:a * inv_len, y:b * inv_len}; }
function p_(x, y, z) { return {x:x, y:y, z:z}; }
function p_dot(p, v) { return p.x * v.x + p.y * v.y + p.z; }
function v_crs(a) { return {x:-a.y, y:a.x}; }
function v_dist(a, b) { return Math.sqrt((a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y)); }
function v_dist_sq(a, b) { return (a.x - b.x) * (a.x - b.x) + (a.y - b.y) * (a.y - b.y); }
function v_dir(a, b, c) { return v_mul(v_nor_2(b.x - a.x, b.y - a.y), c); }
function v_madd_ref(a, b, c) { a.x += b.x * c; a.y += b.y * c; }
function v_add_ref(a, b) { a.x += b.x; a.y += b.y; }
function v_mul_ref(a, b) { a.x *= b; a.y *= b; }
function v_sub_ref(a, b) { a.x -= b.x; a.y -= b.y; }
function v_plane_dist(a, x, y) { return a.a * x + a.b * y + a.c; }
function v_plane_distance(a, b, c) { var d = Math.sqrt((b.x - c.x) * (b.x - c.x) + (b.y - c.y) * (b.y - c.y)); return ((b.y - c.y) * a.x + (c.x - b.x) * a.y + (b.x * c.y - b.y * c.x)) / d; }

var ph = ph || {};

// Game logic.
var _help_stage = 0;
var _help_start_game = false;
var _track = 0;
var _ajax_seed = 0;
var _cars = null;
var _last_finished = 3;
var _screen_offset = null;
var _in_turn_choice = true;
var _in_turn_speed_choice = 0;
var _in_turn_turn_choice = 0;
var _championship_time = 0;
var _championship_crashed = 0;
var _lap_time = 0;
var _crashed = 0;
var _time_element = null;
var _current_track = null;
var _check_end = false;
var _race_ended = false;
var _finished_order = 0;

var _adjust_turn = 0.45;
var _minimal_speed = 15;
var _speed_multiplier = 10;
var _car_radius_squared = 300;

var _name_set = false;

function game_start() {
  window.scrollTo(0, 1);

  _track = 0;
  _last_finished = 3;
  _championship_crashed = 0;
  _championship_time = 0;


  if (_name_set && $("#name-name").val() != "nickname") {
    $("#logo").animate({opacity: 0}, 400, function() {
      $("#logo").css("display", "none");     
      game_begin();
    });
  } else {
    $("#name-inner").css("opacity", "0").animate({opacity: 1}, 400);
    $("#name-dark").css("opacity", "0").animate({opacity: 0.95}, 400);
    $("#name-container").css("opacity", "1").css("display", "block");      

    _name_set = true;
  }
}

function game_begin() {    
  _in_turn_choice = false;

  game_initialize();

  $("#game-container").css("opacity", "0").css("display", "block");
  $("#game-container").animate({opacity: 1}, 400, function() {
    game_begin_continue();
  });
}

function game_begin_continue() {
  if (readCookie("rulesShown") != "1") {

    _help_stage = 0;
    _help_start_game = true;

    $("#help-outer").css("background", "transparent url(imgs/help1.png) no-repeat 0px 0px");

    $("#help-container").css("opacity", "0").css("display", "block").animate(
      {opacity: 1}, 400);

    createCookie("rulesShown", "1", 365);
  } else {
    game_begin_turn();
  }
}

function game_begin_turn() {
  _in_turn_choice = true;
  _in_turn_speed_choice = 0;
  _in_turn_turn_choice = 0;

  for (var i = 0; i < _cars.length; ++i)
    if (_cars[i].halt && !_cars[i].skip_turn) {
      var c = _cars[i];

      // If went on the grass, orient the car towards the center of the next tile.
      var px = _cars[i].x;
      var py = _cars[i].y;
      px /= 160;
      py /= 160;
      var cx = Math.floor(px);
      var cy = Math.floor(py);

      var cell = _current_track.m[cy][cx];
      
      var next = null;
      var next_number = (cell.n == _current_track.length) ? 1 : (cell.n + 1);
      // Find the cell with the next number.
      var l = _current_track.m.length;
      for (var u = 0; u < l; ++u)
        for (var v = 0; v < l; ++v)
          if (_current_track.m[u][v].n == next_number) {
            var aim_x = (cx * 160 + 80 + v * 160 + 80) * 0.5;
            var aim_y = (cy * 160 + 80 + u * 160 + 80) * 0.5;

            c.a = Math.atan2(aim_y - c.y, aim_x - c.x);
          }

      c.halt = false;
      if (i == 0)
        c.skip_turn = false;
      c.s = 1;
      c.grass_free = 8;
    }  

  if (_cars[0].halt && _cars[0].skip_turn) {
    _cars[0].halt = false;
    _cars[0].skip_turn = false;
  }

  if (!_cars[0].halt && _cars[0].skip_turn) {
    _cars[0].halt = true;

    _in_turn_choice = false;

    ++ _crashed;
    _lap_time += 25;

    start_simulator();
  } else {
    draw_ui();
  }
}

function game_initialize() {
  ++_ajax_seed;

  _lap_time = 0;
  _crashed = 0;

  _time_element = $("#game-score").get(0);

  _time_element.innerHTML = "";

  // Build level map.
  var sb = new StringBuilder();

  var track = _tracks[_track];
  if (!track)
    track = _tracks[0];

  _current_track = track;
  _check_end = false;
  _race_ended = false;
  _finished_order = 0;

  var map = track.m;
  var size = map[0].length;

  for (var i = 0; i < size; ++i)
    for (var j = 0; j < size; ++j)
    { 
      var type = map[j][i].t;
      var sprite;
      if (type == 0)
        continue;
      if (type == 1)
        sprite = _ui.road_sprites.road_ne.style;
      if (type == 2)
        sprite = _ui.road_sprites.road_nw.style;
      if (type == 4)
        sprite = _ui.road_sprites.road_se.style;
      if (type == 5)
        sprite = _ui.road_sprites.road_sw.style;
      if (type == 6)
        sprite = _ui.road_sprites.road_ns.style;
      if (type == 3)
        sprite = _ui.road_sprites.road_we.style;
      
      sb.appendList("<div style=\"position: absolute; width: 160px; height: 160px; left: ", i * 160, "px; top: ", j * 160, 
        "px; background: transparent url(imgs/ui.road.atlas.optimized.png) no-repeat ", sprite, "\">&nbsp;</div>"); 
    }
    
  $("#game-field-inner").css("width", (size * 160) + "px").css("height", (size * 160) + "px");
  $("#game-field-inner").get(0).innerHTML = sb.toString();

  var cars = [
    {x: track.s.x * 160 + 40 + 19.5, y: track.s.y * 160 + 30 + 20.5, a: - 90 * Math.PI / 180, s: 1, halt: false, grass_free: 0, skip_turn: false, check_end: false, finished: -1 },
    {x: track.s.x * 160 + 81 + 19.5, y: track.s.y * 160 + 45 + 20.5, a: - 90 * Math.PI / 180, s: 1, halt: false, grass_free: 0, skip_turn: false, check_end: false, finished: -1 },
    {x: track.s.x * 160 + 40 + 19.5, y: track.s.y * 160 + 72 + 20.5, a: - 90 * Math.PI / 180, s: 1, halt: false, grass_free: 0, skip_turn: false, check_end: false, finished: -1 },
    {x: track.s.x * 160 + 81 + 19.5, y: track.s.y * 160 + 87 + 20.5, a: - 90 * Math.PI / 180, s: 1, halt: false, grass_free: 0, skip_turn: false, check_end: false, finished: -1 }
  ];

  _cars = [];

  if (_last_finished == 0) {
    _cars[0] = cars[3]; _cars[0].t = 0;
    _cars[1] = cars[0]; _cars[1].t = 1;
    _cars[2] = cars[1]; _cars[2].t = 2;
    _cars[3] = cars[2]; _cars[3].t = 3;
  } else if (_last_finished == 1) {
    _cars[0] = cars[2]; _cars[0].t = 0;
    _cars[1] = cars[0]; _cars[1].t = 1;
    _cars[2] = cars[1]; _cars[2].t = 2;
    _cars[3] = cars[3]; _cars[3].t = 3;
  } else if (_last_finished == 2) {
    _cars[0] = cars[1]; _cars[0].t = 0;
    _cars[1] = cars[0]; _cars[1].t = 1;
    _cars[2] = cars[2]; _cars[2].t = 2;
    _cars[3] = cars[3]; _cars[3].t = 3;
  } else if (_last_finished == 3) {
    _cars[0] = cars[0]; _cars[0].t = 0;
    _cars[1] = cars[1]; _cars[1].t = 1;
    _cars[2] = cars[2]; _cars[2].t = 2;
    _cars[3] = cars[3]; _cars[3].t = 3;
  }

  for (var i = 0; i < 4; ++i) {
    var c = _cars[i];

    var car_sprite = null;
    if (c.t == 0)
      c.sprite = _ui.sprites.car_red;
    else if (c.t == 1)
      c.sprite = _ui.sprites.car_blue;
    else if (c.t == 2)
      c.sprite = _ui.sprites.car_pink;
    else if (c.t == 3)
      c.sprite = _ui.sprites.car_yellow;
  }

  center_screen();

  draw_ui();
}

function center_screen()
{
  if (!_screen_offset)
    _screen_offset = {};

  _screen_offset.x = Math.floor(- _cars[0].x + 160);
  _screen_offset.y = Math.floor(- _cars[0].y + 160);
  _screen_offset.u = _screen_offset.x;
  _screen_offset.v = _screen_offset.y;

  $("#game-field-inner").css("left", _screen_offset.x + "px").css("top", _screen_offset.y + "px");
}

function center_screen_slow()
{
  var dx = - _cars[0].x + 160 - _screen_offset.u;
  var dy = - _cars[0].y + 160 - _screen_offset.v;

  if (Math.abs(dx) < 1 && Math.abs(dy) < 1) {
    center_screen();

    return true;
  }

  _screen_offset.u = _screen_offset.u + dx * 0.2;
  _screen_offset.v = _screen_offset.v + dy * 0.2;
  _screen_offset.x = Math.floor(_screen_offset.u);
  _screen_offset.y = Math.floor(_screen_offset.v);
  
  $("#game-field-inner").css("left", _screen_offset.x + "px").css("top", _screen_offset.y + "px");

  return false;
}

function hit_test_image_c(s, x, y, tx, ty) {
  if (tx >= x - s / 2 && ty >= y - s / 2 - 36 && tx < x + s / 2 && ty < y + s / 2 - 36) 
    return true;

  return false;
}

function draw_image_c(canvas, img, x, y, selected) {
  canvas.drawImage(_img_combined_obj,
    img.x, img.y, img.width, img.height, x - Math.floor(img.width / 2), y - Math.floor(img.height / 2) - 36, img.width, img.height);

  if (selected) {
    canvas.strokeStyle = "#333333";  
    canvas.lineWidth = 2;    
    canvas.beginPath();
    canvas.arc(x + 1, y - 36, Math.floor(img.width / 2) + 4, 0, Math.PI * 2, true);
    canvas.closePath();
    canvas.stroke();

    canvas.strokeStyle = "#ffcc00";  
    canvas.lineWidth = 2;    
    canvas.beginPath();
    canvas.arc(x, y - 37, Math.floor(img.width / 2) + 4, 0, Math.PI * 2, true);
    canvas.closePath();
    canvas.stroke();    
  }    
}

function draw_arrow(canvas, x, y, a, color, s) {
  canvas.fillStyle = color;
  canvas.beginPath();

  var nx = - Math.sin(a);
  var ny = Math.cos(a);

  x = x + _screen_offset.x;
  y = y + _screen_offset.y;

  x += ny * 20;
  y -= nx * 20;  

  var w = 4;
  var l = 10;

  for (var i = 0; i <= s; ++i)
  {
    canvas.moveTo(x, y);
    canvas.lineTo(x + nx * w, y + ny * w);
    canvas.lineTo(x + nx * (w + 1) + ny * l, y + ny * (w + 1) - nx * l);
    canvas.lineTo(x - nx * (w + 1) + ny * l, y - ny * (w + 1) - nx * l);
    canvas.lineTo(x - nx * w, y - ny * w);
    canvas.moveTo(x, y);

    x += ny * (l + 5);
    y -= nx * (l + 5);

    w += 1;

    l = 7;
  }

  w += 3

  canvas.moveTo(x, y);
  canvas.lineTo(x + nx * w, y + ny * w);
  canvas.lineTo(x + ny * w, y - nx * w);
  canvas.lineTo(x - nx * w, y - ny * w);
  canvas.moveTo(x, y);

  canvas.closePath();
  canvas.fill();
}

function draw_ui()
{
  var canvas = $("#game-canvas").get(0).getContext("2d");

  canvas.clearRect(0, 0, 320, 320);

  canvas.drawImage(_img_combined_obj,
    _ui.sprites.checkers.x, _ui.sprites.checkers.y, 80, 40, _current_track.s.x * 160 + 40 + _screen_offset.x, _current_track.s.y * 160 + 60 + _screen_offset.y, 80, 40);

  if (_in_turn_choice) {
    // Draw arrow.
    var c = _cars[0];

    var v = c.s + _in_turn_speed_choice;
    if (v < 1) v = 1;
    if (v > 6) v = 6;  

    var a = c.a - Math.PI / 8 * _in_turn_turn_choice / (v * 0.5 + _adjust_turn);

    draw_arrow(canvas, c.x + 1.3, c.y + 1.34, a, "rgb(0, 0, 0)", v);
    draw_arrow(canvas, c.x, c.y, a, "rgb(255, 0, 90)", v);
  }

  for (var i = 0; i < _cars.length; ++i) {
    var c = _cars[i];

    canvas.save();

    canvas.translate(c.x + _screen_offset.u, c.y + _screen_offset.v);
    canvas.rotate(c.a + Math.PI * 0.5);
    canvas.translate(-18.5, -19.5);

    canvas.drawImage(_img_combined_obj,
      c.sprite.x + 1, c.sprite.y + 1, c.sprite.width - 2, c.sprite.height - 2, 0, 0, c.sprite.width - 2, c.sprite.height - 2);

    canvas.restore();
  }

  if (_in_turn_choice) {    
    draw_image_c(canvas, _ui.sprites.ui_turn_p2, 23, 227 - 20, _in_turn_turn_choice == 2);
    draw_image_c(canvas, _ui.sprites.ui_p1, 34, 267 - 20, _in_turn_turn_choice == 1);
    draw_image_c(canvas, _ui.sprites.ui_0, 56, 296 - 20, _in_turn_turn_choice == 0);
    draw_image_c(canvas, _ui.sprites.ui_n1, 84, 315 - 20, _in_turn_turn_choice == -1);
    draw_image_c(canvas, _ui.sprites.ui_turn_n2, 123, 322 - 20, _in_turn_turn_choice == -2);

    draw_image_c(canvas, _ui.sprites.ui_speed_p2, 320 - 34, 267 - 20, _in_turn_speed_choice == 1);
    draw_image_c(canvas, _ui.sprites.ui_0, 320 - 56, 296 - 20, _in_turn_speed_choice == 0);
    draw_image_c(canvas, _ui.sprites.ui_speed_n2, 320 - 84, 315 - 20, _in_turn_speed_choice == -1);
    
    draw_image_c(canvas, _ui.sprites.turn, 30, 336);
    draw_image_c(canvas, _ui.sprites.speed, 290, 336);

    draw_image_c(canvas, _ui.sprites.go, 169, 63);
  }
}

// Simulation.
var _time_left = 0;
var _simulator_running = null;

function bot_step(level, d, max_level, x, y, speed, angle, final, last_cell) {
  var max_d = -100000;
  var max_speed = speed;
  var max_angle = angle;

  var max_size = _current_track.m.length * 160;  

  for (var speed_choice = -1; speed_choice <= 1; ++speed_choice) {
    var v = speed + speed_choice;
    if (v < 1) continue;
    if (v > 6) continue;

    for (var angle_choice = -2; angle_choice <= 2; ++angle_choice) {
      var a = angle - Math.PI / 8 * angle_choice / (v * 0.5 + _adjust_turn);

      var vs = _minimal_speed + (v * _speed_multiplier);

      var cos_a = Math.cos(a);
      var sin_a = Math.sin(a);

      var rx = x + cos_a * vs * 2.500;
      var ry = y + sin_a * vs * 2.500;      

      // Skip choice if went out of bounds.
      if (rx <= 0 || ry <= 0 || rx >= max_size || ry >= max_size) {
        continue;
      }      

      var rx1 = x + cos_a * vs * 0.300;
      var ry1 = y + sin_a * vs * 0.300;
      var rx2 = x + cos_a * vs * 1.000;
      var ry2 = y + sin_a * vs * 1.000;

      var dd = d + Math.sqrt((rx - x) * (rx - x) + (ry - y) * (ry - y));

      // If car went on grass, penalize and exit immediately.
      if (car_on_grass(rx1, ry1) || car_on_grass(rx, ry) || car_on_grass(rx2, ry2)) {        
        dd = dd - 10000;

        if (dd > max_d) {
          max_d = dd;
          max_speed = v;
          max_angle = a;
        }

        continue;
      }        

      // Penalize if car is going in the wrong direction.
      var cell = _current_track.m[Math.floor(ry / 160)][Math.floor(rx / 160)].n;
      if (cell > 0 && last_cell > 0 && last_cell - cell > 0 && last_cell - cell < 3) {
        dd = dd - 50000;

        if (dd > max_d) {
          max_d = dd;
          max_speed = v;
          max_angle = a;
        }

        continue;
      }

      if (level < max_level) {
        var level_dd = bot_step(level + 1, dd, max_level, rx, ry, v, a, false, cell);

        if (level_dd > max_d) {
          max_d = level_dd;
          max_speed = v;
          max_angle = a;
        }         
      } else {
        if (dd > max_d) {
          max_d = dd;
          max_speed = v;
          max_angle = a;
        }
      }    
    }
  }

  return final ? { d: max_d, speed: max_speed, angle: max_angle } : max_d;
}

function car_on_grass(x, y) {
  var px = x / 160;
  var py = y / 160;
  var cx = Math.floor(px);
  var cy = Math.floor(py);
  px = px - cx;
  py = py - cy;

  var cell = _current_track.m[cy][cx];
  if (!cell)
    return true;

  cell = cell.t;

  if (cell == 0) {
    return true;
  } else if (cell == 1) {
    var d = (1 - px) * (1 - px) + py * py;
    if (d < 0.0625 || d > 0.5625)
      return true;
  } else if (cell == 2) {
    var d = px * px + py * py;
    if (d < 0.0625 || d > 0.5625)
      return true;
  } else if (cell == 4) {
    var d = (1 - px) * (1 - px) + (1 - py) * (1 - py);
    if (d < 0.0625 || d > 0.5625)
      return true;
  } else if (cell == 5) {
    var d = px * px + (1 - py) * (1 - py);
    if (d < 0.0625 || d > 0.5625)
      return true;
  } else if (cell == 6) {
    if (px < 0.25 || px > 0.75)
      return true;
  } else if (cell == 3) {
    if (py < 0.25 || py > 0.75)
      return true;
  }

  return false;
}

function bot_think(car, max_level) {
  var cell = _current_track.m[Math.floor(car.y / 160)][Math.floor(car.x / 160)].n;

  var d = bot_step(0, 0, max_level, car.x, car.y, car.s, car.a, true, cell);

  car.s = d.speed;
  car.a = d.angle;      
}

function start_simulator() {
  if (_track == 0) {
    for (var i = 1; i < _cars.length; ++i) {
      bot_think(_cars[i], 1);
    }
  } else {
    for (var i = 1; i < _cars.length; ++i) {
      var c = _cars[i];

      if (i == 1)
        bot_think(c, 2);
      else if (i == 2)
        bot_think(c, 2);
      else 
        bot_think(c, 1);
    }
  }

  for (var i = 0; i < _cars.length; ++i) {
    var c = _cars[i];

    c.v = v_mul(v_(Math.cos(c.a), Math.sin(c.a)), (_minimal_speed + (c.s * _speed_multiplier)) * (c.skip_turn ? 0 : 1));
  }

  _time_left = 25;

  _simulator_running = setTimeout(process_simulator, 50);
}

function stop_simulator() {
  if (_simulator_running) {
    clearTimeout(_simulator_running);
  
    _simulator_running = null;
  }
}

var _time_sb = new StringBuilder();

function format_time(lap_time, crashed) {
  var seconds = lap_time / 10;
  var minutes = Math.floor(seconds / 60);  
  var full_seconds = Math.floor(seconds);
  var part_seconds = Math.floor((seconds - full_seconds) * 10);
  full_seconds -= minutes * 60;

  _time_sb.clear();
  _time_sb.appendList("Crash:&nbsp;", crashed, "&nbsp;&nbsp;Time:&nbsp;",
    minutes < 10 ? "0" : "", minutes, ":", full_seconds < 10 ? "0" : "", full_seconds, ".", part_seconds, "&nbsp;");

  return _time_sb.toString();
}

function format_time_short(lap_time, crashed) {
  var seconds = lap_time / 10;
  var minutes = Math.floor(seconds / 60);  
  var full_seconds = Math.floor(seconds);
  var part_seconds = Math.floor((seconds - full_seconds) * 10);
  full_seconds -= minutes * 60;

  _time_sb.clear();
  _time_sb.appendList(minutes < 10 ? "0" : "", minutes, ":", full_seconds < 10 ? "0" : "", full_seconds, ".", part_seconds, "&nbsp;", "/&nbsp;crash&nbsp;", crashed);

  return _time_sb.toString();
}

function sync_simulator() { 
  _time_element.innerHTML = format_time(_lap_time, _crashed);
  
  draw_ui();
}

function root(a, b, c, bound) {
  var determinant = b * b - 4.0 * a * c;
  if (determinant < 0.0)
    return null;

  var q = -0.5 * (b + (b < 0.0 ? -1.0 : 1.0) * Math.sqrt(determinant));

  var x1 = q / a;
  var x2 = c / q;

  if (x2 < x1) { var x3 = x1; x1 = x2; x2 = x3; }

  if (x1 >= 0.0 && x1 <= bound)
    return x1;
  if (x2 >= 0.0 && x2 <= bound)
    return x2;

  return null;
}


function ph_moving_spheres(begin_a, delta_a, radius_a, begin_b, delta_b, radius_b) {
  var a_to_b_x = begin_b.x - begin_a.x;
  var a_to_b_y = begin_b.y - begin_a.y;
  var delta_ab_x = delta_b.x - delta_a.x;
  var delta_ab_y = delta_b.y - delta_a.y;
  
  var radius = radius_a + radius_b;

  var c = a_to_b_x * a_to_b_x + a_to_b_y * a_to_b_y - radius * radius;

  if (c <= 0.0) {
    var t = radius_a / radius;
    return v_(0.0, v_(begin_a.x * (1.0 - t) + begin_b.x * t, begin_a.y * (1.0 - t) + begin_b.y * t));
  }

  var b = 2.0 * (delta_ab_x * a_to_b_x + delta_ab_y * a_to_b_y);
  if (b >= 0.0)
    return null;

  var a = delta_ab_x * delta_ab_x + delta_ab_y * delta_ab_y;

  var t = root(a, b, c, 1.0);	
  if (t) {
    var begin_a_time_x = begin_a.x + delta_a.x * t;
    var begin_a_time_y = begin_a.y + delta_a.y * t;
    var begin_b_time_x = begin_b.x + delta_b.x * t;
    var begin_b_time_y = begin_b.y + delta_b.y * t;

    var f = radius_a / radius;

    return v_(t, v_(begin_a_time_x * (1.0 - f) + begin_b_time_x * f, begin_a_time_y * (1.0 - f) + begin_b_time_y * f));
  }
  
  return null;
}


var _pairs = [];

function step_simulation(step) {
  var target = step;
  var time = 0;

  _pairs.length = 0;

  while (time < target) {
    var was_collision = false;  

    var obj_one = null;
    var obj_two = null;
  
    var seconds = target - time;

    for (var i = 0; i < _cars.length; ++i) {
      _cars[i].delta = v_mul(_cars[i].v, seconds);
    }

    var collision_time = null;

    for (var current_car = 0; current_car < _cars.length; ++current_car) {
      var car = _cars[current_car];      

      var stopped = car.v.x == 0.0 && car.v.y == 0.0;
                  
      var delta = car.delta;

      for (var i = current_car + 1; i < _cars.length; ++i) {
        var another_car = _cars[i];

        if (stopped && another_car.v.x == 0 && another_car.v.y == 0)
          continue;

        var center_x = another_car.x - car.x;        
        var center_y = another_car.y - car.y;
        if (center_x * center_x + center_y * center_y > 1600)
          continue;

        var t = ph_moving_spheres(car, delta, 18, another_car, another_car.delta, 18);
        if (t) {
          var valid = false;

          var intersection_time = t.x * seconds;
          if (intersection_time == 0.0) {
            var a_to_b_x = car.x - another_car.x;
            var a_to_b_y = car.y - another_car.y;
            var rel_v_x = car.v.x - another_car.v.x;
            var rel_v_y = car.v.y - another_car.v.y;           

            if ((a_to_b_x * rel_v_x + a_to_b_y * rel_v_y) < - 0.01)
              valid = true;
          } else
            valid = true;

          if (valid) {
            if (!collision_time || intersection_time <= collision_time) {
              if (collision_time != intersection_time)
                _pairs.length = 0;

              collision_time = intersection_time;

              _pairs.push({one: car, two: another_car, v_one: v_c(car.v), v_two: v_c(another_car.v), point: t.y, normal: v_nor_2(car.x + car.v.x * collision_time - another_car.x - another_car.v.x * collision_time, car.y + car.v.y * collision_time - another_car.y - another_car.v.y * collision_time) });
            }
          }
        }
      }      
    }

    if (collision_time != null)
      was_collision = true;

    // Integrate up to the moment of collision.
    var step_time = collision_time != null ? collision_time : seconds;

    for (var i = 0; i < _cars.length; ++i) {
      var car = _cars[i];

      v_madd_ref(car, car.v, step_time);
    }

    if (collision_time != null && _pairs.length > 0) {
      // Check for identical points.
      for (var i = 0; i < _pairs.length; ++i) {
        var a = _pairs[i];
        for (var j = i + 1; j < _pairs.length; ++j) {
          var b = _pairs[j];

          if (b.skip)
            continue;
          if (a.point.x == b.point.x && a.point.y == b.point.y && a.normal.x == b.normal.x && a.normal.y == b.normal.y)
            b.skip = true;
        }
      }

      for (var i = 0; i < _pairs.length; ++i) {
        var v = _pairs[i];
        if (v.skip)
          continue;
           
        var obj_one = v.one;
        var obj_two = v.two;

        var c = -1.2;

        var m_one = obj_one.halt || obj_one.skip_turn ? 0.05 : 1;
        var m_two = obj_two.halt || obj_two.skip_turn ? 0.05 : 1;

        var impulse = v_mul(v.normal, c * v_dot(v_sub(v.v_one, v.v_two), v.normal) / (m_one + m_two));

        v_madd_ref(obj_one.v, impulse, m_one);
        v_madd_ref(obj_two.v, impulse, - m_two);
      }
    }

    time += step_time;
  }  

  for (var i = 0; i < _cars.length; ++i) {
    var c = _cars[i];
    if (c.halt)
      continue;

    if (c.grass_free > 0)
      c.grass_free = c.grass_free - 1;

    if (c.grass_free == 0 && car_on_grass(c.x, c.y)) {
      c.halt = true;
      c.v = v_(0, 0);

      if (i == 0) {
        ++ _crashed;
        _lap_time += 25;
      }
    }
    
    if (c.v.x > 0 || c.v.y > 0) {
      c.a = Math.atan2(c.v.y, c.v.x);
    }

    var px = c.x;
    var py = c.y;
    px /= 160;
    py /= 160;
    var cx = Math.floor(px);
    var cy = Math.floor(py);
    var cell = _current_track.m[cy][cx];

    if (cell.n == _current_track.length - 2)
      c.check_end = true;

    if (c.check_end && c.finished < 0) {
      if (c.x > _current_track.s.x * 160 + 40 && c.x < _current_track.s.x * 160 + 120 && c.y > _current_track.s.y * 160 + 60 && c.y < _current_track.s.y * 160 + 100) {
        c.finished = _finished_order ++;
        if (i == 0)
          _race_ended = true;
      }
    }
  }
}

function process_simulator() {
  if (!_simulator_running)
    return;
  
  if (_time_left > 0) {
    ++_lap_time;

    step_simulation(0.1);
  }

  var condition_time = (-- _time_left) <= 0;
  var condition_center = center_screen_slow();

  sync_simulator();

  if (condition_time && condition_center) {
    if (_race_ended) {
      show_results();
    } else {
      for (var i = 0; i < _cars.length; ++i) {
        var a = _cars[i];
        var l = (Math.floor(v_len(a.v)) - _minimal_speed) / _speed_multiplier;
        if (l < 1)
          l = 1;
        if (l > 6)
          l = 6;

        a.s = l;

        if ((a.v.x > 0 || a.v.y > 0) && !(a.halt || a.skip_turn)) {
          a.v = v_nor(a.v);
          a.a = Math.atan2(a.v.y, a.v.x);
        }
      }
      game_begin_turn();
    }
  }
  else {
    if (_lap_time % 2 == 0)
      process_simulator();
    else 
      setTimeout(process_simulator, 50); 
  }
}

// Game results.

var _show_lap_results = false;

function show_championship_results() {
  set_image("#btn-cup", _ui.sprites.medal_gold).css("display", "inline");
  $("#grats-text").get(0).innerHTML = "";

  var sb = new StringBuilder();

  sb.appendList("<span class=\"txt-smaller-2\">Championship Result</span><br/>");
  sb.appendList("<span class=\"txt-sml\">", format_time(_championship_time, _championship_crashed), "</span>");
  sb.append("<br/><br/>");
  sb.append("<span class=\"txt-sml\">Championship Records:</span><br/><span class=\"txt-smaller\">Loading...</span>"); 

  $("#grats-times").get(0).innerHTML = sb.toString();

  $("#btn-lap-retry").css("display", "none");
  $("#btn-lap-continue").css("display", "block");

  $("#grats-inner").css("opacity", "0").animate({opacity: 1}, 400);
  $("#grats-dark").css("opacity", "0").animate({opacity: 0.8}, 400);

  $.post("score_championship.php", 
    { seed: ++_ajax_seed, time: _championship_time, crashed: _championship_crashed, name: $("#name-name").val() }, function(xml) {

      var seed = $(xml).attr("s") * 1;

      if (seed == _ajax_seed) {        
        var sb = new StringBuilder();

        sb.appendList("<span class=\"txt-smaller-2\">Championship Result</span><br/>");
        sb.appendList("<span class=\"txt-sml\">", format_time(_championship_time, _championship_crashed), "</span>");
        sb.append("<br/><br/>");          
        sb.append("<span class=\"txt-sml\">Championship Records:</span><br/><br/>"); 

        $("r", xml).each(function() {
          var n = $("<div/>").text($(this).attr("n")).html();

          sb.appendList("<span class=\"txt-smaller\">", n, "&nbsp;//&nbsp;", format_time_short($(this).attr("t") * 1, $(this).attr("c") * 1), "</span><div style=\"height: 3px;overflow:hiden;\">&nbsp;</div>");
        });

        $("#grats-times").get(0).innerHTML = sb.toString();
      }
    });
}

function show_results() {
  _show_lap_results = true;

  var grats_text = "";

  if (_cars[0].finished == 0) {
    set_image("#btn-cup", _ui.sprites.gold).css("display", "inline");
    grats_text = "First place!";
  } else if (_cars[0].finished == 1) {
    set_image("#btn-cup", _ui.sprites.silver).css("display", "inline");
    grats_text = "Second place!";

    _lap_time += 25;

  } else if (_cars[0].finished == 2) {
    set_image("#btn-cup", _ui.sprites.bronze).css("display", "inline");
    grats_text = "Third place!";

    _lap_time += 50;

  } else {
    $("#btn-cup").css("display", "none");
    grats_text = "Last place. Keep trying!";

    _lap_time += 75;
  }
  $("#grats-text").get(0).innerHTML = grats_text;

  var sb = new StringBuilder();

  sb.appendList("<span class=\"txt-smaller-2\">", format_time(_lap_time, _crashed), "</span><br/><br/>");
  sb.appendList("<span class=\"txt-smaller-2\">Total ", format_time(_championship_time + _lap_time, _championship_crashed + _crashed), "</span>");
  sb.append("<br/><br/>");
  sb.append("<span class=\"txt-sml\">Record laps:</span><br/><span class=\"txt-smaller\">Loading...</span>"); 

  var player_name = _cars[0].finished == 3 ? "" : $("#name-name").val();

  $.post("score.php", 
    { seed: ++_ajax_seed, track: _track, time: _lap_time, crashed: _crashed, name: player_name }, function(xml) {

      var seed = $(xml).attr("s") * 1;

      if (seed == _ajax_seed) {
        var sb = new StringBuilder();

        sb.appendList("<span class=\"txt-smaller-2\">", format_time(_lap_time, _crashed), "</span><br/>");
        sb.appendList("<span class=\"txt-smaller-2\">Total: ", format_time(_championship_time + _lap_time, _championship_crashed + _crashed), "</span>");
        sb.append("<br/><br/>");
        sb.append("<span class=\"txt-sml\">Record laps:</span><br/><br/>"); 

        $("r", xml).each(function() {
          var n = $("<div/>").text($(this).attr("n")).html();

          sb.appendList("<span class=\"txt-smaller\">", n, "&nbsp;//&nbsp;", format_time_short($(this).attr("t") * 1, $(this).attr("c") * 1), "</span><div style=\"height: 3px;overflow:hiden;\">&nbsp;</div>");
        });

        $("#grats-times").get(0).innerHTML = sb.toString();
      }
    });

  $("#grats-times").get(0).innerHTML = sb.toString();

  $("#btn-lap-retry").css("display", "block");
  $("#btn-lap-continue").css("display", _cars[0].finished == 3 ? "none" : "block");

  $("#grats-inner").css("opacity", "0").animate({opacity: 1}, 400);
  $("#grats-dark").css("opacity", "0").animate({opacity: 0.8}, 400);
  $("#grats-container").css("opacity", "1").css("display", "block");
}

// Preloading and initialization.
function make_img(v, force) {
  return "imgs/" + v;
}

var _img_combined = make_img("ui.alpha.atlas.optimized.png");
var _img_combined_obj;

var _preload_init = [ "imgs/underclouds.png", "imgs/back.jpg" ];
var _preload_continue = [ "imgs/ui.alpha.atlas.optimized.png", "imgs/ui.road.atlas.optimized.png", "imgs/road.png", "imgs/help1.png" ];
var _preload_continue_count = _preload_continue.length;

function fixup_logo() {
  $("#logo-inner").css("background", "transparent url(imgs/back.jpg) no-repeat center");  
}

function set_image(id, style) {
  return $(id).attr("width", style.width).attr("height", style.height).css("background",
    "transparent url(" + _img_combined + ") no-repeat " + style.style);
}

function fixup_preload() {
  _img_combined_obj = new Image();
  _img_combined_obj.src = _img_combined;

  set_image("#btn-start", _ui.sprites.championship).css("left", "48px").css("top", "116px");
  set_image("#btn-scores", _ui.sprites.hiscores).css("left", "95px").css("top", "174px");
  set_image("#btn-help", _ui.sprites.help).css("left", "132px").css("top", "222px");
  set_image("#btn-more", _ui.sprites.more).css("left", "93px").css("top", "276px");

  $("#game-field-inner").css("background", "transparent url(imgs/road.png)");

  set_image("#btn-finished", _ui.sprites.finished).css("left", "79px").css("top", "40px");

  set_image("#btn-lap-retry", _ui.sprites.retry).css("left", "40px").css("top", "315px");
  set_image("#btn-lap-continue", _ui.sprites.cont).css("left", "185px").css("top", "315px");

  set_image("#btn-scores-continue", _ui.sprites.cont);

  set_image("#btn-name-continue", _ui.sprites.cont);
  set_image("#name-caption", _ui.sprites.yourname);

  set_image("#img-best", _ui.sprites.best_championship);
}  

function mouse_position(current, event) {
  var x = 0, y = 0;
  for (; current != null; current = current.offsetParent) {
    x += current.offsetLeft;
    y += current.offsetTop;
  }
 
 return {x: event.pageX - x, y: event.pageY - y };
}

function process_scores(xml) {
  var sb = new StringBuilder();

  sb.appendList("<div class='scores-header'>All Time Best</div>");

  $("a", xml).each(function() {
    var n = $("<div/>").text($(this).attr("n")).html();

    sb.append("<div class='score-line'>");
    sb.appendList("<span class=\"txt-smaller-2\" style=\"color: #fc0;\">", n, "</span><br/><span class=\"txt-smaller\" style=\"font-size: 1.2em\">", format_time_short($(this).attr("t") * 1, $(this).attr("c") * 1), "</span>");
    sb.append("</div>");
  });

  $("#scores-all").get(0).innerHTML = sb.toString();

  sb = new StringBuilder();

  sb.appendList("<div class='scores-header'>Today's Best</div>");

  $("t", xml).each(function() {
    var n = $("<div/>").text($(this).attr("n")).html();

    sb.append("<div class='score-line'>");
    sb.appendList("<span class=\"txt-smaller-2\" style=\"color: #fc0;\">", n, "</span><br/><span class=\"txt-smaller\" style=\"font-size: 1.2em\">", format_time_short($(this).attr("t") * 1, $(this).attr("c") * 1), "</span>");
    sb.append("</div>");
  });

  $("#scores-today").get(0).innerHTML = sb.toString();

  $("#scores-loading").css("display", "none");
  $("#scores-table").css("display", "block");
}

function setup_click_handlers() {
  var _ph = ph;

  $("#btn-start").click(function() {
    game_start();

    return false;
  });

  $("#btn-help").click(function() {

    _help_stage = 0;
    $("#help-outer").css("background", "transparent url(imgs/help1.png) no-repeat 0px 0px");

    $("#help-container").css("opacity", "0").css("display", "block").animate(
      {opacity: 1}, 400);

    return false;
  });

  $("#btn-menu").click(function() {
    stop_simulator();

    $("#logo").css("opacity", "0").css("display", "block");
    $("#game-container").animate({opacity: 0}, 400, function() {
      $("#game-container").css("display", "none");

      $("#logo").animate({opacity: 1}, 400, function() { });
    });
    
    return false;
  });

  $("#btn-restart").click(function() {
    _race_ended = true;
    _cars[0].finished = 3;
    _cars[1].finished = 1;
    _cars[2].finished = 2;
    _cars[3].finished = 0;

    stop_simulator();

    show_results();

    return false;
  });

  $("#btn-lap-retry").click(function() {
    ++ _ajax_seed;

    $("#grats-inner").animate({opacity: 0}, 400);
    $("#grats-dark").animate({opacity: 0}, 400);
    $("#game-container").animate({opacity: 0}, 400, function() {
      $("#grats-container").css("opacity", "0").css("display", "none");

      game_begin();
    });
    return false;
  });  

  $("#btn-lap-continue").click(function() {
    if (_show_lap_results) {
      ++ _ajax_seed;

      _last_finished = _cars[0].finished;

      _championship_time += _lap_time;
      _championship_crashed += _crashed;
 
      ++ _track;

      _show_lap_results = false;

      if (_track >= _tracks.length) {
        $("#grats-inner").animate({opacity: 0}, 400);
        $("#grats-dark").animate({opacity: 0}, 400, function() {
          show_championship_results();
        });
      } else {
        $("#grats-inner").animate({opacity: 0}, 400);
        $("#grats-dark").animate({opacity: 0}, 400);
        $("#game-container").animate({opacity: 0}, 400, function() {
          $("#grats-container").css("opacity", "0").css("display", "none");
          game_begin();
        });
      }
    } else {
      $("#grats-inner").animate({opacity: 0}, 400);
      $("#grats-dark").animate({opacity: 0}, 400);
      $("#logo").css("opacity", "0").css("display", "block");
      $("#game-container").animate({opacity: 0}, 400, function() {
        $("#game-container").css("display", "none");
        $("#grats-container").css("opacity", "0").css("display", "none");

        $("#logo").animate({opacity: 1}, 400, function() { });
      });
    }
    
    return false;
  });

  $("#btn-name-continue").click(function() {
    $("#name-inner").animate({opacity: 0}, 400);
    $("#name-dark").animate({opacity: 0}, 400);    

    $("#logo").animate({opacity: 0}, 400, function() {
      $("#logo").css("display", "none");     
      $("#name-container").css("opacity", "0").css("display", "none");

      createCookie("name", $("#name-name").val(), 365);

      game_begin();
    });  

    return false;
  });

  $("#btn-scores").click(function() {
    $("#scores-loading").css("display", "block");
    $("#scores-table").css("display", "none");
    $("#scores-container").css("display", "block").css("opacity", "0").animate({opacity: 1}, 400, function() {

      $.post("score_table.php", { seed: ++_ajax_seed }, process_scores);
    });

    return false;
  });

  $("#btn-scores-continue").click(function() {
    $("#scores-container").animate({opacity: 0}, 400, function() {
      $("#scores-container").css("display", "none");
    });

    return false;
  });

  $("#help-outer").click(function() {
    createCookie("rulesShown", "1", 365);    

    $("#help-container").animate({opacity: 0}, 400, function() {
      $("#help-container").css("display", "none");

      if (_help_start_game) {
        game_begin_turn();

        _help_start_game = false;
      }
    });

    return false;
  });

  $("#game-canvas-clicker").click(function(event) {
    if (!_in_turn_choice) 
      return false;     
    
    var c = mouse_position(this, event);

    if (hit_test_image_c(30, 23, 227 - 20, c.x, c.y))
      _in_turn_turn_choice = 2;      
    if (hit_test_image_c(30, 34, 267 - 20, c.x, c.y))
      _in_turn_turn_choice = 1;
    if (hit_test_image_c(30, 56, 296 - 20, c.x, c.y))
      _in_turn_turn_choice = 0;
    if (hit_test_image_c(30, 84, 315 - 20, c.x, c.y))      
      _in_turn_turn_choice = -1;
    if (hit_test_image_c(30, 123, 322 - 20, c.x, c.y))
      _in_turn_turn_choice = -2;

    if (hit_test_image_c(30, 320 - 34, 267 - 20, c.x, c.y))
      _in_turn_speed_choice = 1;
    if (hit_test_image_c(30, 320 - 56, 296 - 20, c.x, c.y))
      _in_turn_speed_choice = 0;
    if (hit_test_image_c(30, 320 - 84, 315 - 20, c.x, c.y))
      _in_turn_speed_choice = -1;

    if (hit_test_image_c(40, 169, 63, c.x, c.y)) {
      var c = _cars[0];

      var v = c.s + _in_turn_speed_choice;
      if (v < 1) v = 1;
      if (v > 6) v = 6;  

      var a = c.a - Math.PI / 8 * _in_turn_turn_choice / (v * 0.5 + _adjust_turn);

      c.a = a;
      c.s = v;

      _in_turn_choice = false;

      start_simulator();
    }

    draw_ui();    

    return false;
  });
}

$(function() {
  // Begin images preloading.
  $(document.createElement('img')).bind('load', function() {
    if(_preload_init[0]) {
      this.src = _preload_init.shift();

      trace("preloading [1] ", this.src);                                         
    } else {
      $("#preloading").css("display", "none");

      fixup_logo();

      $("#brand").animate({opacity: 1}, 1500, function() {
        setTimeout(function() {
          $("#brand").animate({opacity: 0}, 1500, function() {
            $("#logo").animate({opacity: 1}, 1000, function() {
              $("#brand").css("display", "none");
            });
          });
        }, 2000);
      });
        
      $(document.createElement('img')).bind('load', function() {
        if(_preload_continue[0]) {
          this.src = _preload_continue.shift();

          trace("preloading [2] ", this.src);
        } else {
          fixup_preload();          
          
          $("#logo-loading").css("display", "none");
          $("#logo-loaded").css("display", "inline");

          setTimeout(function() {
            window.scrollTo(0, 1);
          }, 300);
        }
      }).trigger('load');
    }
  }).trigger('load');

  setup_click_handlers();

  var agent = navigator && navigator.userAgent ? navigator.userAgent.toLowerCase() : "";
  var is_iphone = agent && (agent.indexOf('iphone') != -1 || agent.indexOf('ipod') != -1);

  if (is_iphone) {
    ph.multiplier = 0.5;
  }

  if (!is_iphone) {
    $("#pc-padding").css("display", "block");
  }

  var name = readCookie("name");

  if (name && name.length > 0)
    $("#name-name").val(name);  
  else
    $("#name-name").val("nickname");
});