Skip to content
Snippets Groups Projects
explorer.js 7.73 KiB
/*
 * @licstart
 * This program handles the navigation of a planet provided by an xml file
 * 
 * Copyright (C) 2011 Vincent Nivoliers
 *
 * This program is free software: you can redistribute it and/or modify it under
 * the terms of the GNU General Public License as published by the Free Software
 * Foundation, either version 3 of the License, or (at your option) any later
 * version.
 *
 * This program is distributed in the hope that it will be useful, but WITHOUT
 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
 * FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details.
 *
 * You should have received a copy of the GNU General Public License along with
 * this program.  If not, see http://www.gnu.org/licenses/gpl.html.
 * @licend
*/

(function(factory) {
  //namespacing
  if(!window["Explosurf"]) {
    window["Explosurf"] = {} ;
  }
  if(!window["Explosurf"]["explorer"]) {
    window["Explosurf"]["explorer"] = {} ;
  }
  factory(window["Explosurf"]["explorer"]) ;
})(function(Xpl) { //namespace Explosurf.notes

/* data structures for a tile */

function Tile(XmlElement) {
  this.name = XmlElement.getAttribute('id') ;
  this.neighbours = new Array(null,null,null,null) ;
  this.neighbour_edges = new Array(null,null,null,null) ;
  this.orientations = new Array(null,null,null,null) ;
  this.image = null ;
  
  var children = XmlElement.childNodes ;
  for(var i=0; i<children.length; i++) {
    var child = children[i] ;
    if(child.nodeName == 'image') {
      this.image = child.getAttribute('name') ;
    } else if (child.nodeName == 'edge') {
      var index = parseInt(child.getAttribute('origin_index')) ;
      var neighbour = child.getAttribute('neighbour') ;
      if(neighbour != '') {
        this.neighbours[index] = neighbour ;
        var neighbour_edge = parseInt(child.getAttribute('opposite_index')) ;
        this.neighbour_edges[index] = neighbour_edge ;
        var orientation = child.getAttribute('orientation') ;
        this.orientations[index] = (orientation != "switch") ;
      }
    }
  }
}

function Map(planet,key) {
  this.planet = planet ;
  this.key = key ;
  this.tile = planet[key] ;
  this.rotation = 0 ;
  this.orientation = true ;

  this.tile_edge = function(edge) {
    if(this.orientation) {
      return (this.rotation+edge)%4 ;
    } else {
      return (this.rotation+4-edge)%4 ;
    }
  }

  this.transformation = function() {
    var trans = "r"+this.rotation ;
    if(!this.orientation) {
      trans += "_flip" ;
    }
    return trans ;
  }

  this.transformed_image = function() {
    var img = this.tile.image ;
    var image_base = img.substr(0, img.lastIndexOf('.')) || img ;
    var url = window.location.href ;
    var base_dir = url.substr(0,url.lastIndexOf('/')) ;
    return base_dir+"/"+image_base+"_"+this.transformation()+".png" ;
  }

  this.neighbour_map = function(edge) {
    var tedge = this.tile_edge(edge) ;
    var neighbour = this.tile.neighbours[tedge] ;
    if(neighbour) {
      var neighbour_edge = this.tile.neighbour_edges[tedge] ;
      var orientation = this.tile.orientations[tedge] ;
      var neigh_map = new Map(this.planet,neighbour) ;
      neigh_map.orientation = orientation ? this.orientation : !this.orientation ;
      if(neigh_map.orientation) {
        neigh_map.rotation = (neighbour_edge+6-edge)%4 ;
      } else {
        neigh_map.rotation = (neighbour_edge+2+edge)%4 ;
      }
      return neigh_map ;
    } else {
      return null ;
    }
  }
}

Map.prototype.toString = function() {
  var buffer = "" ;
  buffer += "Name: " + this.tile.name + "<br />" ;
  buffer += "Rotation: " + this.rotation + "<br />" ;
  buffer += "Orientation: " + this.orientation ;
  return buffer ;
}

handle_request_error = function(evt) {
}

/* planet loading from xml */

function openXML(filename, handler) {
  var xhttp ;
  if (window.XMLHttpRequest) {
    xhttp=new XMLHttpRequest() ;
  } else {// IE 5/6
    xhttp=new ActiveXObject("Microsoft.XMLHTTP") ;
  }
  xhttp.addEventListener("error", handle_request_error);
  //xhttp.addEventListener("readystatechange", function() {handler(this);});
  xhttp.open("GET",filename, false) ;
  xhttp.overrideMimeType('text/xml');
  xhttp.send(null) ;
  handler(xhttp) ;
}

/* exploration */

var planet = {} ;
var center_map = null ;

var storage_prefix = 'Explosurf:' 
    + document.getElementById('planet-name').innerText.toLowerCase() 
    + ':explorer'
  ;

function save_position() {
  var position = center_map.key ;
  position += ":" + center_map.rotation ;
  position += ":" + center_map.orientation ;
  localStorage.setItem(storage_prefix + ":position" ,position) ;
}

window.addEventListener('beforeunload', save_position) ;

function load_position() {
  var position = localStorage.getItem(storage_prefix + ":position" ) ;
  if(position) {
    /* load position from local storage */
    var parsed = position.split(":") ;
    center_map = new Map(planet,parsed[0]) ;
    center_map.rotation = parseInt(parsed[1]) ;
    center_map.orientation = (parsed[2] == "true") ;
  } else {
    /* generate random position */
    var tile_size = 0 ;
    var can_switch = false ;
    for(var key in planet) {
      tile_size++ ;
      var tile = planet[key] ;
      for(var i=0; i<4; i++) {
        if(!tile.orientations[i]) {
          can_switch = true ;
        }
      }
    }
    var rand_tile_index = Math.floor(Math.random()*tile_size) ;
    var tile_index = 0 ;
    for(var key in planet) {
      if(tile_index == rand_tile_index) {
        center_map = new Map(planet,key) ;
        break ;
      }
      tile_index++ ;
    }
    if(can_switch) {
      center_map.orientation = (Math.random() > 0.5) ;
    }
    save_position() ;
  }
}

/* export */
Xpl.load = load_position ;

function load_planet(Xmldoc) {
  var children = Xmldoc.childNodes ;
  for(var i=0; i<children.length; i++) {
    var child = children[i] ;
    if(child.nodeName == 'planet') {
      var tiles = child.childNodes
      for(var j=0; j<tiles.length; j++) {
        tileNode = tiles[j] ;
        if(tileNode.nodeName == 'tile') {
          var tile = new Tile(tileNode) ;
          planet[tile.name] = tile ;
        }
      }
    }
  }
}

var center_elem = document.getElementById("tile_center") ;
var compass_elem = document.getElementById("boussole") ;
var neighbour_elem = ["bottom", "right", "top", "left"].map(function (dir) {
  return document.getElementById("tile_"+dir) ;
}) ;

function redraw() {
  center_elem.src = center_map.transformed_image() ;
  compass_elem.setAttribute("transform", center_map.transformation()) ;
  for(var i=0; i<4; i++) {
    var map = center_map.neighbour_map(i) ;
    var img = neighbour_elem[i] ;
    if(map) {
      img.src = map.transformed_image() ;
      img.style.opacity = 1 ;
    } else {
      img.src = "" ;
      img.style.opacity = 0 ;
    }
  }
  Explosurf.notes.load() ;
}

function go(edge) {
  var new_map = center_map.neighbour_map(edge) ;
  if(new_map) {
    Explosurf.notes.save() ;
    center_map = new_map ;
    redraw() ;
    save_position() ;
  }
}

function go_func(edge) {
  return function() {go(edge) ;} ;
}

/* export */
Xpl.go = go ;

document.getElementById("go-down").addEventListener('click', go_func(0)) ;
document.getElementById("go-right").addEventListener('click', go_func(1)) ;
document.getElementById("go-up").addEventListener('click', go_func(2)) ;
document.getElementById("go-left").addEventListener('click', go_func(3)) ;

function check_boundary(edge) {
  var neighbour = center_map.neighbour_map(edge) ;
  return neighbour === null ;
}

/*export*/
Xpl.check_boundary = check_boundary ;

function init(filename) {
  openXML(filename, function(response) {
    if (response.readyState == 4 && response.status == 200) {
      load_planet(response.responseXML) ;
      load_position() ;
      redraw() ;
    }
  }) ;
}

Xpl.init = init
}) //end of namespace