// On-screen objects:
var Loady, Map, Dais, Rotor, Star, You, Congrat, Glow

var Locus, Path  // Locations and paths
var Bank  // Image bank
var Viewscreen
var Whereabouts
var Wanna, WalkCounter

var ViewX = 248, ViewY = 248  // Half main viewscreen dimensions
var Zfactor = 256  // Overall zoom factor (times 256)
var FramesPerSecond = 40
var tFrame = Math.round(1000 / FramesPerSecond)

var Ready = false  // Ready to take user input?
var Dancing = true, Roting = true  // Dancing stars? Roting rotors?
var Red = true  // Current mode
var DanceMove = [ 2, 3, 4, 4, 3, 4, 4, 3, 2, 1, 0, 0, 1, 0, 0, 1 ]
var Gameover

var DaisX = [ -24, -184, 136, 20 ]
var DaisY = [ -184, -48, -40, 180 ]
var DaisR = 16
var Daistheta = [ 6, 4, 6, 5 ]
var RotorX = [ 16, -160, 176, 16 ]
var RotorY = [ -144, 0, 0, 144 ]
var StellaX = [ -96, 0, 96 ]
var StellaY = [ 0, 88, 0 ]
var JunctionX = [ -160, -24 ]
var JunctionY = [ 48, 208 ]
var QuadX = [ 0, -160, -160, 160, 160, 0 ]
var QuadY = [ -240, 80, -80, 80, -80, 240 ]

var PathStart = [ 34,0,12,28, 30,55,52,25, 21,22,16,32, 26,11,4,57,
      24,53,56,17,5,3,54,9,8,58,1,10,23,59,59,59,59,60,60,60,61 ]
var PathEnd = [ 36,37,38,39, 40,41,42,43, 44,45,46,47, 48,49,50,51,
      53,56,33,55,57,54,35,52,58,15,18,13,29,27,2,14,7,31,20,19,6 ]
var PData = [ 2,1349,288,1385,313, 2,1248,381,1267,424,
      3,1824,350,1793,407,1740,432, 2,1347,576,1388,552, 0,
      7,1056,1824,962,1749,877,1728,558,1728,498,1714,445,1658,432,1565,
      8,1536,672,1465,693,1408,741,1224,1045,1145,1091,1079,1104,470,1105,436,1127,
      8,1956,2496,1788,2447,1699,2324,1680,2177,1680,1397,1654,1308,1581,1257,1510,1248,
      9,1814,864,1754,897,1728,959,1728,1023,1770,1086,1816,1104,2222,1104,2296,1121,2343,1163,
      8,1371,864,1452,875,1527,904,1580,952,1698,1181,1769,1240,1875,1282,1984,1296,
      4,2784,1142,2769,1214,2739,1259,2648,1296,
      11,1094,2208,1192,2187,1296,2112,1488,1920,1599,1853,1700,1824,
        1900,1824,1960,1812,2044,1749,2304,1496,2340,1430,
      2,1457,2496,1536,2512,
      2,1536,2820,1553,2744,
      8,2208,1200,2180,1286,2112,1382,1920,1594,1859,1680,1824,1788,1824,2342,1790,2448,
      7,1852,2064,1920,2088,1968,2160,1968,2640,1947,2688,1896,2708,1764,2708, 0, 0,
      9,1035,1523,1104,1488,1601,987,1680,864,1716,768,1728,672,1728,336,1742,299,1776,288,
      3,1824,2653,1800,2592,1754,2523,
      6,1248,2420,1263,2336,1305,2235,1352,2160,1426,2099,1515,2064,
      2,2227,1920,2269,1862,
      2,2841,1296,2904,1259,
      9,2496,1844,2471,1776,2400,1680,1890,1170,1843,1104,1824,1026,1824,792,1799,720,1728,672,
      7,576,1230,593,1284,637,1328,693,1344,1776,1344,1904,1364,1978,1409,
      6,2460,1884,2514,1912,2558,1920,2702,1920,2736,1932,2774,1968,
      4,288,1968,271,1904,227,1849,132,1824,
      8,2496,1359,2466,1440,2400,1536,2112,1824,1984,1897,1872,1920,949,1920,887,1956,
      6,2916,1824,2864,1794,2832,1728,2832,1632,2857,1584,2916,1536,
      10,576,1741,624,1655,705,1632,1658,1632,1748,1602,1834,1536,
        1897,1440,1920,1344,1920,690,1950,609,
      4,507,1824,396,1794,319,1720,288,1602,
      4,720,1824,795,1805,849,1749,864,1671, 0,
      6,1392,2496,1412,2387,1461,2295,1521,2247,1604,2219,1700,2208,
      0, 0, 0 ]

// Let the games.................. BEGIN!
function Commence() {

  // Image bank! It's a bank of images!
  Bank = new Object()
  Bank.Star = new Object()
  Bank.Star.Red = new Array()
  Bank.Star.Blue = new Array()
  Bank.Rotor = new Array()
  Bank.Dais = new Array()
  for (j = 0; j < 5; ++j) {
    (Bank.Star.Red[j] = new Image()).src = "star-red-" + j + ".png";
    (Bank.Star.Blue[j] = new Image()).src = "star-blue-" + j + ".png"; 
  }
  for (j = 0; j < 12; ++j)
    (Bank.Rotor[j] = new Image()).src = "arrow-purple-" + j + ".png"; 
  for (j = 0; j < 16; ++j)
    (Bank.Dais[j] = new Image()).src = "dais-purple-" + j + ".png"; 
  Bank.Map = new Object();
  (Bank.Map.Red = new Image()).src = "mega-red.png";
  (Bank.Map.Blue = new Image()).src = "mega-blue.png"
  Bank.You = new Array(4);
  for (j = 0; j < 4; ++j)
    (Bank.You[j] = new Image()).src = "you-" + j + ".png"; 
  Bank.Glow = new Array(5);
  for (j = 0; j < 7; ++j)
    (Bank.Glow[j] = new Image()).src = "glow-" + j + ".png"; 

  // Lay out the map! Locations (nodes) and paths!
  Locus = new Array(62)
  for (j = 0; j < 6; ++j) for (k = -1, p = j; k < 2; ++k, p += 6) {
    Locus[p] = [QuadX[j] + k * 48, QuadY[j]]
    Locus[18+p] = [QuadY[j], -QuadX[j] - k * 48]
  }
  for (j = 0, p = 36; j < 4; ++j) {
    Angle = Daistheta[j] * Math.PI / 4
    for (k = 0; k < 4; ++k, Angle += (4-k)*Math.PI/2, ++p)
       Locus[p] = [Math.round(DaisX[j] + DaisR * Math.cos(Angle)),
         Math.round(DaisY[j] + DaisR * Math.sin(Angle))]
    Locus[52+j] = [RotorX[j], RotorY[j]]
  }
  for (j = 0; j < 3; ++j) Locus[56+j] = [StellaX[j], StellaY[j]]
  for (j = 52; j < 59; ++j) Locus[j].PathSum = 0
  for (j = 0; j < 2; ++j) Locus[59+j] = [JunctionX[j], JunctionY[j]]
  Locus[61] = [0, 0]

  Path = new Array(37)
  for (j = 0; j < 37; ++j) {
    Path[j] = new Array()
    Path[j].Start = PathStart[j]
    Path[j].End = PathEnd[j]
    for (w in Path[j]) {
      if (Path[j][w] < 52) Locus[Path[j][w]].Path = j
      else if (Path[j][w] < 59) Locus[Path[j][w]].PathSum += j }
    Path[j].ID = j
  }
  tick = 0
  for (j = 0; j < 37; ++j) {
    p = Path[j].length = PData[tick++]
    for (k = 0; k < p; ++k)
      Path[j][k] = [(PData[tick++] - 1536) / 6, (PData[tick++] - 1536) / 6]
  }

  // Define the on-screen objects!
  (Viewscreen = new Object()).Cell = document.getElementById("viewscreen");
  Viewscreen.Size = [ViewX, ViewY];

  (Loady = new Object()).Cell = document.getElementById("loady");

  (Map = new Object()).Cell = document.getElementById("map")
  Map.Size = [1120, 1120] ; Map.Size0 = [1120, 1120]
  Map.Offset = [0, 496]
  Map.Pos = [0, 0]
  Map.Pursue = { Cursor: true, Ztarget: 256, Ptarget: [0, 0] };

  (You = new Object()).Cell = document.getElementById("cursor")
  You.Size = [32, 32] ; You.Size0 = [32, 32]
  You.Offset = [0, 496+2400]
  You.Pos = [0, 0]
  You.Frame = 0

  Star = new Array(3)
  for (j = 0; j < Star.length; ++j) {
    (Star[j] = new Object()).Cell = document.getElementById("star" + j)
    Star[j].Size = [32, 32] ; Star[j].Size0 = [32, 32]
    Star[j].Offset = [0, 496 + 2400 + 72 + j * 72]
    Star[j].Pos = [StellaX[j], StellaY[j]]
    Star[j].Frame = 2
  }
  Dais = new Array(4)
  for (j = 0, p = 0; j < 4; ++j) {
    Dais[j] = new Array(10)
    for (k = 0; k < Dais[j].length; ++k, ++p) {
      (Dais[j][k] = new Object()).Cell = document.getElementById("dais" + j + "-" + k)
      Dais[j][k].Size = [36, 36] ; Dais[j][k].Size0 = [36, 36]
      Dais[j][k].Offset = [0, 496 + 2400 + 72 + 7 * 72 + p * 80]
      Dais[j][k].OnScreen = true
    }
    qx = (j == 2) - (j == 1) ; qy = (j == 3) - (j == 0)
    for (kx = -3, kred = kblue = 0; kx <= 3; ++kx) for (ky = -3; ky <= 3; ++ky) {
      dx = 2 * kx - ky ; dy = 2 * ky + kx
      if (Math.abs(dx + qx) <= 3 && Math.abs(dy + qy) <= 3)
	Dais[j][kred++].RedPos = [DaisX[j] + 160 * dx, DaisY[j] + 160 * dy]
      dx = 2 * kx + ky ; dy = 2 * ky - kx
      if (Math.abs(dx + qx) <= 3 && Math.abs(dy + qy) <= 3)
	Dais[j][kblue++].BluePos = [DaisX[j] + 160 * dx, DaisY[j] + 160 * dy]
    }
    for (k = 0; k < Dais[j].length; ++k) Dais[j][k].Pos = Dais[j][k].RedPos
    Dais[j].Rotato = false
    Dais[j].Frame = (Daistheta[j] * 4 + 8) % 16
  }

  Rotor = new Array(4)
  for (j = 0; j < 4; ++j) {
    (Rotor[j] = new Object()).Cell = document.getElementById("rotor" + j)
    Rotor[j].Size = [32, 32] ; Rotor[j].Size0 = [32, 32]
    Rotor[j].Offset = [0, 496 + 2400 + 72 + (j + 3) * 72]
    Rotor[j].Pos = [RotorX[j], RotorY[j]]
    Rotor[j].Frame = 0
  }
  (Congrat = new Object()).Cell = document.getElementById("congratulate")
  Congrat.Offset = [0, 496 + 2400 + 8 * 72 + 40 * 80];

  (Glow = new Object()).Cell = document.getElementById("glow")
  Glow.Offset = [0, 496 + 2400 + 8 * 72 + 40 * 80 + 80]
  Glow.Size = [120, 120] ; Glow.Size0 = [120, 120]
  Glow.Pos = [0, 999]

  Wanna = new Object()
  if (document.getElementById("wannapan")) {
    Wanna.control = new Object()
    Wanna.control.Pan = document.getElementById("wannapan")
    Wanna.control.Zoom = document.getElementById("wannazoom")
    Wanna.control.Pause = document.getElementById("wannapause")
    Wanna.control.Glow = document.getElementById("wannaglow")
    unfixwanna()
  } else {
    Wanna.control = false
    Wanna.Pan = Wanna.Zoom = false
    Wanna.Pause = Wanna.Glow = true
  }
  Wanna.Speed = 200

  Posmax = 0
  Disappear(Glow)
  Canvas()
  Rote() ; Dance(0) ; Flame()
  Disappear(Loady)
  Whereabouts = 2
  Ready = true ; Freewheeling = false
  Gameover = false
  document.onkeydown = Punch
  document.onkeypress = returnfalse
  if (WalkCounter = document.getElementById("walkcount"))
    WalkCounter.value = Walk = 0
  Map.Pursue.Ptarget = [0,0]
  Map.Pursue.Cursor = false
  Map.Pursue.Ztarget = 512
  PursuitSettle()
  // setTimeout("Peregrinate(Path[" + (Math.random() * 37 | 0) + "])", 1000);
  // setTimeout("Peregrinate(ReversePath(Path[36]))", 1000);
}
function returnfalse() {
  return false
}

// What to do after reaching the end of a path.
function NowWhat(Whence, Where) {
  if (Where < 36) {  // Wrap around the edge of the map
    // It took me like two hours to come up with this formula...
    NewWhere = Red ? Where ^ 1 : Where + (Where % 6 < 3 ? 3 : -3)
    NewPath = Path[Locus[NewWhere].Path]
    if (Wanna.Pan) for (var j in Map.Pos) Map.Pos[j] += Locus[Where][j] - Locus[NewWhere][j]
    Peregrinate(NewWhere == NewPath.Start ? NewPath : ReversePath(NewPath))
  } else if (Where < 52) {  // Travel over/from a dais
    if (Whence >= 0) {
      Quad = (Where - 36) >> 2
      CrossPath = new Array(2)
      CrossPath.ID = -1
      CrossPath.Start = Where
      CrossPath.End = Where ^ (Dais[Quad].Rotato ? 1 : 2)
      CrossPath[0] = new Array(2) ; CrossPath[1] = new Array(2)
      for (j in Locus[0]) {
        CrossPath[0][j] = ((j == 0 ? DaisX : DaisY)[Quad] * 4 + Locus[Where][j] * 3 + Locus[CrossPath.End][j]) / 8
        CrossPath[1][j] = ((j == 0 ? DaisX : DaisY)[Quad] * 4 + Locus[Where][j] + Locus[CrossPath.End][j] * 3) / 8
      }
      Peregrinate(CrossPath)
    } else {
      Peregrinate(ReversePath(Path[Locus[Where].Path]))
    }
  } else if (Where < 56) {  // Cross a rotor
    Rotify(Where - 52)
    NewPath = Path[Locus[Where].PathSum - Whence]
    NewPath = Where == NewPath.Start ? NewPath : ReversePath(NewPath)
    setTimeout("Peregrinate(NewPath)", Wanna.Pause ? 1000 : 0)
  } else if (Where < 59) {  // Cross a star
    FlipSide()
    NewPath = Path[Locus[Where].PathSum - Whence]
    Peregrinate(Where == NewPath.Start ? NewPath : ReversePath(NewPath))
  } else {  // Intersection - wait for input
    Whereabouts = Where - 59
    Ready = true
    PursuitSettle()
    if (Whereabouts == 2 && !Red) Congratulate()
    if (WalkCounter) WalkCounter.value = ++Walk
  }
}

// Swap between red and blue mode!
function FlipSide() {
  Red = !Red
  Map.Cell.src = Bank.Map[Red ? "Red" : "Blue"].src
  StarBank = Bank.Star[Red ? "Blue" : "Red"]
  for (var j in Star) Star[j].Cell.src = StarBank[Star[j].Frame].src
  for (j in Dais) for (k = 0; k < Dais[j].length; ++k) {
    Dais[j][k].Pos = Dais[j][k][Red ? "RedPos" : "BluePos"]
    MayPosition(Dais[j][k]) }
  if (Viewscreen.Cell)
    Viewscreen.Cell.style.borderColor = Red ? "red" : "blue"
}

// Rotate a dais!
function Rotify(Quad) {
  Dais[Quad].Rotato = !Dais[Quad].Rotato
  dt = 120
  Freewheeling = true
  for (j = 0, t = dt; j < 8; ++j, t += dt) {
    f = Dais[Quad].Frame = (Dais[Quad].Frame + 1) % 16
    for (k = 0; k < Dais[Quad].length; ++k) if (Dais[Quad][k].OnScreen)
      setTimeout("Dais[" + Quad + "][" + k + "].Cell.src = Bank.Dais[" + f + "].src", t)
  }
  for (k = 0; k < Dais[Quad].length; ++k) if (!Dais[Quad][k].OnScreen)
    Dais[Quad][k].Cell.src = Bank.Dais[f].src
  setTimeout("Freewheeling = false", t)
  if (Wanna.Glow) {
    Glow.Pos = [DaisX[Quad], DaisY[Quad]]
    Glow.Cell.src = Bank.Glow[0].src
    Position(Glow)
    Appear(Glow)
    for (j = 0, t = 60; j < 16; ++j, t += 60) {
      gFrame = Array(0, 1, 2, 3, 4, 5, 6, 4, 5, 6, 4, 5, 3, 2, 1, 0)[j]
      setTimeout("Glow.Cell.src = Bank.Glow[" + gFrame + "].src", t)
    }
    setTimeout("Disappear(Glow)", t)
  }
  PursuitSettle()
}

// Put the map and all on-screen objects in their place
function Canvas() {
  for (var j in Map.Offset)
    Map.Cell.style[j == 0 ? "left" : "top"] = 
      Math.round(-Map.Offset[j] + Viewscreen.Size[j] + 
        Map.Pos[j] * Zfactor / 256 - Map.Size[j] / 2) + "px"
  for (j in Star) Position(Star[j])
  for (j in Rotor) Position(Rotor[j])
  for (j in Dais) for (k = 0; k < Dais[j].length; ++k) Position(Dais[j][k])
  Position(Glow)
  Position(You)
}

// Put a single object in its place
function Position(Thingy) {
  for (var j in Thingy.Offset)
    Thingy.Cell.style[j == 0 ? "left" : "top"] =
      Math.round(-Thingy.Offset[j] + Viewscreen.Size[j] - Thingy.Size[j] / 2
        + (Thingy.Pos[j] + Map.Pos[j]) * Zfactor / 256) + "px";
}

// Put an object in its place only if it's visibile
function MayPosition(Thingy) {
  WasOn = Thingy.OnScreen ; Thingy.OnScreen = false
  var p = new Array(2), q = new Array(2)
  for (var j in Thingy.Offset) {
    p[j] = Math.round((Thingy.Pos[j] + Map.Pos[j]) * Zfactor / 256)
    q[j] = Viewscreen.Size[j] + Thingy.Size[j] / 2
    Thingy.OnScreen |= Math.abs(p[j]) < q[j] }
  if (WasOn || Thingy.OnScreen)
    for (var j in Thingy.Offset)
      Thingy.Cell.style[j == 0 ? "left" : "top"] =
        Math.round(-Thingy.Offset[j] + q[j] + p[j] - Thingy.Size[j]) + "px";
}

function Appear(Thingy) { Thingy.Cell.style.visibility = "visible" }
function Disappear(Thingy) { Thingy.Cell.style.visibility = "hidden" }

// Stay in the lines. Lines are your friends.
function Peregrinate(Via) {
  if (Array.concat)
    Loc = Array.concat(Array(Locus[Via.Start]), Via, Array(Locus[Via.End]))
  else {
    Loc = new Array()
    Loc[0] = Locus[Via.Start]
    for (j = 0; j < Via.length; ++j) Loc[j+1] = Via[j]
    Loc[Loc.length] = Locus[Via.End]
  }
  n = Loc.length
  SetPursuit(Via.End)

  dFrame = Math.max(Wanna.Speed / FramesPerSecond, 2)

  Leg = -1 ; Len = 0 ; del = [0, 0] ; p = [0, 0]

  for (t = tFrame, d = dFrame; Leg < n - 1; t += tFrame, d += dFrame) {
    while (d > Len && ++Leg < n - 1) {
      d -= Len
      for (j in del) del[j] = Loc[Leg+1][j] - Loc[Leg][j]
      Len = Math.sqrt(del[0] * del[0] + del[1] * del[1]) }
    if (Leg == n - 1) p = Loc[n-1]
    else for (j in p) p[j] = Math.round(Loc[Leg][j] + d * del[j] / Len)
    setTimeout("Plop(" + p + ")", t)
  }
  setTimeout("NowWhat(" + Via.ID + "," + Via.End + ")", t)
}

// Change the zoom/pan settings depending on where you're going
function SetPursuit(Node) {
  if (Node < 36) {
    Map.Pursue.Cursor = true
    Map.Pursue.Ztarget = 256
  } else if (Node < 52) {
    Map.Pursue.Cursor = true
    Map.Pursue.Ztarget = 256
  } else if (Node < 56) {
    //Map.Pursue.Cursor = false
    //Map.Pursue.Ptarget = [-DaisX[Node-52], -DaisY[Node-52]]
    Map.Pursue.Cursor = true
    Map.Pursue.Ztarget = 512
  } else if (Node < 59) {
    //Map.Pursue.Cursor = false
    //Map.Pursue.Ptarget = [0,0]
    Map.Pursue.Cursor = true
    Map.Pursue.Ztarget = 256
  } else if (Node < 61) {
    Map.Pursue.Cursor = false
    Map.Pursue.Ptarget = [0,0]
    Map.Pursue.Ztarget = 256
  } else {
    Map.Pursue.Cursor = false
    Map.Pursue.Ptarget = [0,0]
    Map.Pursue.Ztarget = 512
  }
}


function Zoomify(Thingy) {
  NewWidth = Math.round(Thingy.Size0[0] * Zfactor / 256)
  if (NewWidth != Thingy.Size[0]) {
    Thingy.Size[0] = NewWidth
    Thingy.Size[1] = Math.round(Thingy.Size0[1] * Zfactor / 256)
    Thingy.Cell.style.width = Thingy.Size[0] + "px"
    Thingy.Cell.style.height = Thingy.Size[1] + "px"
  }
}

// Zoom/pan the map to pursue a specific zoom factor or position
function HotPursuit() {
  NewMap = false
  if (Zfactor != (Wanna.Zoom ? Map.Pursue.Ztarget : 256)) {
    if (Wanna.Zoom) {
      dz = Map.Pursue.Ztarget - Zfactor
      fZoom = dz > 0 ? 0.8 : 0.95
      ndz = Math.round(fZoom * dz)
      Zfactor = Map.Pursue.Ztarget - (ndz == dz ? dz - (dz > 0 ? 1 : -1) : ndz)
    } else {
      Zfactor = 256
    }
    NewMap = true
    Zoomify(Map)
    Zoomify(You)
    for (var j in Star) Zoomify(Star[j])
    for (j in Rotor) Zoomify(Rotor[j])
    for (j in Dais) for (k = 0; k < Dais[j].length; ++k) Zoomify(Dais[j][k])
    Zoomify(Glow)
  }

  if (Wanna.Pan) {
    var target = Map.Pursue.Cursor ? [-You.Pos[0], -You.Pos[1]] : Map.Pursue.Ptarget
    var d = [target[0] - Map.Pos[0], target[1] - Map.Pos[1]]
    if (d[0] || d[1]) {
      fPan = Math.min(1 - Wanna.Speed / 4000., 0.95)
      var nd = [Math.round(fPan * d[0]), Math.round(fPan * d[1])]
      if (nd[0] == d[0] && nd[1] == d[1]) {
        if (d[0] * d[0] < d[1] * d[1]) d[1] -= d[1] > 0 ? 1 : -1
        else d[0] -= d[0] > 0 ? 1 : -1
      } else {
        d = nd
      }
      for (var j in Map.Pos) Map.Pos[j] = target[j] - d[j]
      NewMap = true
    }
  } else {
    if (Map.Pos[0] || Map.Pos[1]) {
      Map.Pos = [0, 0]
      NewMap = true
    }
  }
  return NewMap
}

// Continue pursuing as long as we're waiting for input
function PursuitSettle() {
  if ((Ready || Freewheeling) && HotPursuit()) {
    setTimeout("PursuitSettle()", tFrame)
    Canvas()
  }
}

// Reposition You and update the map if necessary
function Plop(px, py) {
  You.Pos = [px, py]
  if (HotPursuit()) Canvas(); else Position(You)
}

// You're a mighty fine function. Won't you back that path up?
function ReversePath(Pathos) {
  var Backward = new Array(Pathos.length)
  for (j = 0, k = Pathos.length-1; k >= 0; ++j, --k) Backward[j] = Pathos[k]
  Backward.ID = Pathos.ID
  Backward.Start = Pathos.End
  Backward.End = Pathos.Start
  return Backward
}

function Dance(Step) {
  if (Dancing) setTimeout("Dance(" + (Step + 1) % 16 + ")", 80)
  NewFrame = DanceMove[Step]
  if (NewFrame != Star[0].Frame) {
    for (j = 0; j < 3; ++j) {
      Star[j].Frame = NewFrame
      Star[j].Cell.src = Bank.Star[Red ? "Blue" : "Red"][NewFrame].src
    }
  }
}

function Rote() {
  if (Roting) setTimeout("Rote()", 80)
  for (j = 0; j < 4; ++j) {
    Rotor[j].Frame = (Rotor[j].Frame + 1) % 12
    Rotor[j].Cell.src = Bank.Rotor[Rotor[j].Frame].src
  }
}

function Flame() {
  setTimeout("Flame()", 80)
  You.Frame = (You.Frame + 1) % 4
  You.Cell.src = Bank.You[You.Frame].src
}

function RandomStep() {
  if (Ready && !Gameover) {
    Ready = false
    switch (Whereabouts) {
      case 0: Peregrinate(Path[29 + Math.random() * 4 | 0]) ; break
      case 1: Peregrinate(Path[33 + Math.random() * 3 | 0]) ; break
      case 2: Peregrinate(Path[36]) ; break
    }
  }
}

function Congratulate() {
  Gameover = true
  window.status = "Congratulations!"
  for (t = j = 0; j < 40; ++j, t += 10)
    setTimeout("pCon(" + j / 40. + ")", t)
  setTimeout("pCon(1)", t)
}
function pCon(x) {
  Congrat.Pos = [0, Math.floor(-200 * x)]
  Congrat.Size = [Math.floor(496 * x), Math.floor(68 * x)]
  Congrat.Cell.style.width = Congrat.Size[0] + "px"
  Congrat.Cell.style.height = Congrat.Size[1] + "px"
  for (var j in Congrat.Offset)
    Congrat.Cell.style[j == 0 ? "left" : "top"] =
      Math.round(-Congrat.Offset[j] + Viewscreen.Size[j] - Congrat.Size[j] / 2
        + Congrat.Pos[j]) + "px";
}

function Punch(Tiktak) {
  Key = ((typeof event != "undefined") ? event.keyCode : Tiktak.which)
  switch(Key) {
    case 80: case 112: // P
      Wanna.Pan = !Wanna.Pan; fixwanna(); return false
    case 90: case 122: // Z
      Wanna.Zoom = !Wanna.Zoom; fixwanna(); return false
    case 82: case 114: // R
      Wanna.Pause = !Wanna.Pause; fixwanna(); return false
    case 71: case 103: // G
      Wanna.Glow = !Wanna.Glow; fixwanna(); return false
    case 78: case 110: // N
      Wanna.Speed -= 50; fixwanna(); return false
    case 77: case 109: // M
      Wanna.Speed += 50; fixwanna(); return false
  }
  if (Ready && !Gameover) {
    Ready = false
    switch(Key) {
      case 37: case 57387: case 65: case 97: Directo = 1 ; break
      case 38: case 57385: case 87: case 119: Directo = 0 ; break
      case 39: case 57388: case 68: case 100: Directo = 2 ; break
      case 40: case 57386: case 83: case 115: Directo = 3 ; break
      default: Ready = true ; return false
    }
    switch (Whereabouts) {
      case 0: Peregrinate(Path[29 + Directo]) ; return false
      case 1: if (Directo < 3) { Peregrinate(Path[33 + Directo]) ; return false } break;
      case 2: if (Directo == 0) { Peregrinate(Path[36]) ; return false } break;
    }
    Ready = true
  }
  return false
}

function fixwanna() {
  Wanna.Zoom &= Wanna.Pan
  if (Wanna.Speed < 50) Wanna.Speed = 50
  if (Wanna.Speed > 1000) Wanna.Speed = 1000
  if (Wanna.control) {
    Wanna.control.Zoom.disabled = !Wanna.Pan
    Wanna.control.Pan.checked = Wanna.Pan
    Wanna.control.Zoom.checked = Wanna.Zoom
    Wanna.control.Pause.checked = Wanna.Pause
    Wanna.control.Glow.checked = Wanna.Glow
  }
  PursuitSettle()
  Ready = true
}
function unfixwanna() {
  Wanna.Pan = Wanna.control.Pan.checked
  Wanna.control.Zoom.disabled = !Wanna.Pan
  Wanna.Zoom = Wanna.control.Zoom.checked
  Wanna.Pause = Wanna.control.Pause.checked
  Wanna.Glow = Wanna.control.Glow.checked
}
function wannacheck() {
  setTimeout("unfixwanna(); fixwanna()", 100)
  return true
}
function wannaclick(x) {
  Wanna.Speed += x
  fixwanna()
}
