This is a wiki for a reason. Anyone can contribute. If you see something that is inaccurate or can be improved, don't ask that it be fixed--just improve it.
[ Disclaimer, Create new user --- Wiki markup help, Install P99 ]

MediaWiki:LocMaps.js

From Project 1999 Wiki
Revision as of 15:54, 23 August 2019 by Loramin (Talk | contribs)

Jump to: navigation, search

Note: After saving, you may have to bypass your browser's cache to see the changes.

  • Firefox / Safari: Hold Shift while clicking Reload, or press either Ctrl-F5 or Ctrl-R (⌘-R on a Mac)
  • Google Chrome: Press Ctrl-Shift-R (⌘-Shift-R on a Mac)
  • Internet Explorer: Hold Ctrl while clicking Refresh, or press Ctrl-F5
  • Opera: Clear the cache in Tools → Preferences
(function() {

  // TODO: Add support for cropping maps that have multiple maps.
  // For instance, the following CSS styles show only one of the three maps for 
  // Erudin Palace:
  // background-image:url(/images/Erudinpalace.jpg); 
  // background-position: 250px 0px; width: 275px; height: 272px
  // Figure out how to make the Xs line up with those styles added

  var locIsWithinAlternateData = function(loc, alternateData) {
    return loc.x < alternateData.maxX &&
        loc.x > alternateData.minX &&
        loc.y < alternateData.maxY &&
        loc.y > alternateData.minY;
  };

  /**
   * Determines if the provided name contains any of the provided words
   */
  // TODO: Add a some polyfill to make this a lot simpler
  var containsAny = function(name/* word1, word2, etc. */) {
    for(var arg = 1; arg < arguments.length; ++ arg) {
      var word = arguments[arg];
      if (name.includes(word)) return true;
    }
    return false;
  };

  var getZoneLevelData = function(zone, text) {
    // Check for part "level" aliases (eg. "1st floor" vs. "Level One")
    text = text.toLowerCase();
    if (containsAny(text, '0', 'basement', 'underground')) return zone[0];
    if (containsAny(text, '1', 'first', 'ground')) return zone[1];
    if (containsAny(text, '2', 'second')) return zone[2];
    if (containsAny(text, '3', 'third')) return zone[3];
    if (containsAny(text, '4', 'fourth')) return zone[4];
    if (containsAny(text, '5', 'fifth')) return zone[5];
    if (containsAny(text, '6', 'sixth')) return zone[6];
    if (containsAny(text, '7', 'seventh')) return zone[7];
    if (containsAny(text, '8', 'eighth')) return zone[8];
    if (containsAny(text, '9', 'ninth')) return zone[9];

    // If we still couldn't match, and there is a ground/1st floor, use it
    return zone[1];
  };

  var getZoneData = function(zoneName, locs, nonLocParts) {
    var zone = zoneData[zoneName];

    // Handle aliases (eg. "North Ro" instead of "Northern Desert of Ro")
    if (typeof(zone) === 'string') zone = zoneData[zone];

    // Handle Multi-Level Zones (with different maps for 1st, 2nd, etc. floor)
    if (typeof(zone) === 'object') return getZoneLevelData(zone, nonLocParts);

    // Handle Zones with alternate maps on the same level (eg. Kelethin in GFay)
    if (!zone.alternateMaps) return zone;

    for (var i = 0; i < zone.alternateMaps.length; i++) {
      var alternateData = zone.alternateMaps[i];
      var allLocsAreWithin = true;
      // wish I had ES6 [].every
      $.each(locs, function(i, loc) {
        allLocsAreWithin = allLocsAreWithin && locIsWithinAlternateData(loc, alternateData);
      });
      if (allLocsAreWithin) return alternateData;
    };
    return zone;
  };

  var isLoc = function(locBit) {
    // If we can't split the string by its comma and find a number on either side, it's not a loc
    try {
      return locBit.split(',')[0].match(/\d+/) && locBit.split(',')[1].match(/\d+/);
    } catch (err) {
      return false;
    }
  }

  /**
   * Extracts all of the locs (objects with x and y properties) from a provided
   * string such as:
   * "500, 200"
   * "(200, 300), (300, 200)"
   */
  var getLocs = function(locString) {
    var nonLocParts = '';
    return locString
      .split(/([\+\-]?\d+\.?\d*\D*,\D*[\+\-]?\d+\.?\d*)/g)
      .filter(function(part) {
        // Filter out the non-loc parts, but save them
        if (isLoc(part)) return true;
        nonLocParts += part; // save as it might be something like "1st floor"
      })
      .map(function(locText) {
        var match = locText.match(
            /\(? *([\+\-]?\d+\.?\d*), *([\+\-]?\d+\.?\d*)\)?/);
        return {x: parseFloat(match[2]), y: parseFloat(match[1]) };
      })
      .concat(nonLocParts);
  };

  /**
   * Draws a red "X" on the map at the provided coordinate
   */
  var makeX = function(x, y, zone, $img) {
    var left = (zone.zeroX || 0) + x * -1 * (zone.zoomX || 0.1);
    var top = (zone.zeroY || 0) + y * -1 * (zone.zoomY || 0.1);
    //console.log('x of ' + x + ' became ' + left);
    //console.log('y of ' + y + ' became ' + top);
    //console.log(zone);
    $img
    .parent()
    .css({position: 'absolute'})
    .append(
        $('<div class="x">x</div>')
        .css({
          color: 'red',
          fontSize: '2em',
          fontWeight: 'bold',
          left: left,
          position: 'absolute',
          top: top
        }));
  };

  /**
   * Adds a loc map to the page (presumably in response to a user
   * mousing over a loc map link)
   */
  var addMap = function($locTd, imageName, width, height) {
    if ($('.map-wrapper').length) return;

    var imageUrl = '/images/'+ imageName;
    // Allow local files for testing purposes
    if (imageName.indexOf('file') === 0) imageUrl = imageName;

    var $img = $('<img alt="' + imageName + '" ' +
        'src="' + imageUrl + '" ' +
        'width="' + width + '" ' +
        'height="'+ height + '" ' +
        'class="thumbborder" ' +
        'title="' + imageName + '">' );
    $locTd.append(
        $('<div class="map-wrapper" style="position:relative"></div>')
        .append($img)
    );
  };

  // Define two helper functions for building new zone definitions

  // 1) Use this function to find the correct 0,0 point
  window.testZeroZero = function(zone) {
    var $locTd = $('b:contains("Location:")').parent();
    $('.x').remove();
    var $img = $('img[alt="' + zone.image + '"]').show()
    addMap($locTd, zone.image, zone.width, zone.height);
    makeX(0, 0, zone, $img);
  };

  // 1.5) Use this function to find a different point (when the map doesn't show zero, zero)
  window.testPoint = function(zone, y, x) {
    var $locTd = $('b:contains("Location:")').parent();
    $('.x').remove();
    var $img = $('img[alt="' + zone.image + '"]').show()
    addMap($locTd, zone.image, zone.width, zone.height);
    makeX(x, y, zone, $img);
  };

  // 2) Use this function to generate a grid of alignment of X's
  window.testGrid = function(zone) {
    var $locTd = $('b:contains("Location:")').parent();
    $('.x').remove();
    addMap($locTd, zone.image, zone.width, zone.height);
    var $img = $('img[alt="' + zone.image + '"]').show()
    for (var x = zone.maxX; x >= zone.minX; x -= zone.interval) {
      for (var y = zone.maxY; y >= zone.minY; y -= zone.interval) {
        makeX(x, y, zone, $img);
      }
    };
  };

  try {
    // Get the mob's loc(s)
    var $locTd = $('b:contains("Location:")').parent();
    var locs = getLocs($locTd.text());
    if (locs.length <= 1) return;
    var nonLocParts = locs[locs.length - 1];
    locs = locs.slice(0, locs.length - 2);


    // Find the zone name
    var $zoneTd = $('b:contains("Zone:")').parent().text();
    var zoneName = $zoneTd.split('Zone:')[1].trim();

    // Do we have data for that zone's map?
    var zone = getZoneData(zoneName, locs, nonLocParts);
    if (!zone) return;  // If not, stop here

    // Add the mouseover link
    var $link = $(' <a href="#">(Show on Map)</a>');

    // When it's moused-over, show the map
    $link
    .on('mouseover', function(e) {
      addMap($locTd, zone.image, zone.width, zone.height);
      $.each(locs, function(i, loc) {
        makeX(loc.x, loc.y, zone, $('img[alt="' + zone.image + '"]'));
      });
    })
    .on('mouseleave', function(e) {
      if (this.wasClicked) {
        this.wasClicked = false;
      } else {
        $('.map-wrapper').remove();
      }
      return false;
    })
    .on('click', function(e) {
      if ($(e.target).text() === '(Hide Map)') {
        $(e.target).text('(Show on Map)');
        $('.map-wrapper').remove();
      } else  {
        $(e.target).text('(Hide Map)');
        addMap($locTd, zone.image, zone.width, zone.height);
        $.each(locs, function(i, loc) {
          makeX(loc.x, loc.y, zone, $('img[alt="' + zone.image + '"]'));
        });
        this.wasClicked = true;
      }
      return false;
    });

    $locTd.append($link)
  } catch (err) {/* Didn't work, move on */}


})();