/Trunk/TerrariaMapTool/TerrariaMapTool/Resources/Terraria.js

# · JavaScript · 621 lines · 454 code · 129 blank · 38 comment · 25 complexity · 1579d591e2868579daf3a7af43bcf8b6 MD5 · raw file

  1. var blocksPerTile = 16;
  2. var pixelsPerBlock = 16;
  3. var inversePixelsPerBlock = 1 / pixelsPerBlock;
  4. var mapPixelWidth = mapBlockWidth * pixelsPerBlock;
  5. var mapPixelHeight = mapBlockHeight * pixelsPerBlock;
  6. var mapTileWidth = mapBlockWidth / 16;
  7. var mapTileHeight = mapBlockHeight / 16;
  8. // 6 zoom levels, 2^5 = 32.
  9. var zoomScaling = 32;
  10. var inverseZoomScaling = 1 / zoomScaling;
  11. // We need the map dimensions at the lowest zoom level as the base for
  12. // world coordinates.
  13. var baseZoomWidth = mapPixelWidth * inverseZoomScaling;
  14. var baseZoomHeight = mapPixelHeight * inverseZoomScaling;
  15. // Constant value. Do not change.
  16. var tileSize = 256;
  17. ///////////////////////////////////////////////////////////////////
  18. // Utility Functions
  19. ///////////////////////////////////////////////////////////////////
  20. function bound(value, optionalMin, optionalMax) {
  21. if (optionalMin != null)
  22. {
  23. value = Math.max(value,optionalMin);
  24. }
  25. if (optionalMax != null)
  26. {
  27. value = Math.min(value, optionalMax);
  28. }
  29. return value;
  30. }
  31. function degreesToRadians(deg) {
  32. return deg * (Math.PI / 180);
  33. }
  34. function radiansToDegrees(rad) {
  35. return rad / (Math.PI / 180);
  36. }
  37. ///////////////////////////////////////////////////////////////////
  38. // TerrariaProjection
  39. ///////////////////////////////////////////////////////////////////
  40. // This project allows the conversion from Terraria to an artificial lat/lng
  41. // and back for the google maps API.
  42. function TerrariaProjection() {
  43. this.worldOrigin = new google.maps.Point(baseZoomWidth / 2, baseZoomHeight / 2);
  44. this.worldCoordinatePerLonDegree = baseZoomWidth / 360;
  45. this.worldCoordinateLatRange = baseZoomHeight / 2;
  46. }
  47. TerrariaProjection.prototype.fromBlockToPoint = function(blockPoint) {
  48. return new google.maps.Point(blockPoint.x * pixelsPerBlock * inverseZoomScaling, blockPoint.y * pixelsPerBlock * inverseZoomScaling);
  49. }
  50. TerrariaProjection.prototype.fromPointToBlock = function(blockPoint) {
  51. return new google.maps.Point(blockPoint.x * inversePixelsPerBlock * zoomScaling, blockPoint.y * inversePixelsPerBlock * zoomScaling);
  52. }
  53. TerrariaProjection.prototype.fromLatLngToPoint = function(latLng, optionalPoint) {
  54. var origin = this.worldOrigin;
  55. var x = origin.x + this.worldCoordinatePerLonDegree * latLng.lng();
  56. var latRadians = degreesToRadians(latLng.lat());
  57. var y = origin.y - this.worldCoordinateLatRange * Math.sin(latRadians);
  58. return new google.maps.Point(x, y);
  59. };
  60. TerrariaProjection.prototype.fromPointToLatLng = function(point, noWrap) {
  61. var y = point.y;
  62. var x = point.x;
  63. if (y < 0) {
  64. y = 0;
  65. }
  66. if (y >= baseZoomHeight) {
  67. y = baseZoomHeight;
  68. }
  69. var origin = this.worldOrigin;
  70. var lng = (x - origin.x) / this.worldCoordinatePerLonDegree;
  71. var latRadians = Math.asin((origin.y - y) / this.worldCoordinateLatRange);
  72. var lat = radiansToDegrees(latRadians);
  73. return new google.maps.LatLng(lat, lng, noWrap);
  74. };
  75. TerrariaProjection.prototype.fromBlockToLatLng = function(blockPoint) {
  76. return this.fromPointToLatLng(this.fromBlockToPoint(blockPoint));
  77. }
  78. TerrariaProjection.prototype.fromLatLngToBlock = function(blockPoint) {
  79. return this.fromPointToBlock(this.fromLatLngToPoint(blockPoint));
  80. }
  81. // The projection for coordinate translations.
  82. var projection = new TerrariaProjection();
  83. ///////////////////////////////////////////////////////////////////
  84. // TerrariaMapType
  85. ///////////////////////////////////////////////////////////////////
  86. // The map type for the Terraria Map
  87. function TerrariaMapType() {
  88. }
  89. TerrariaMapType.prototype.name = "Terraria";
  90. TerrariaMapType.prototype.alt = "Tile Coordinate Map Type";
  91. TerrariaMapType.prototype.tileSize = new google.maps.Size(tileSize, tileSize);
  92. TerrariaMapType.prototype.minZoom = 0;
  93. TerrariaMapType.prototype.maxZoom = 5;
  94. TerrariaMapType.prototype.isPng = true;
  95. TerrariaMapType.prototype.projection = projection;
  96. TerrariaMapType.prototype.getTile = function(coord, zoom, ownerDocument) {
  97. var zoomLevel;
  98. switch (zoom) {
  99. case 0:
  100. zoomLevel = 0.03125;
  101. break;
  102. case 1:
  103. zoomLevel = 0.0625;
  104. break;
  105. case 2:
  106. zoomLevel = 0.125;
  107. break;
  108. case 3:
  109. zoomLevel = 0.25;
  110. break;
  111. case 4:
  112. zoomLevel = 0.5;
  113. break;
  114. case 5:
  115. zoomLevel = 1;
  116. break;
  117. case 6:
  118. zoomLevel = 2;
  119. break;
  120. }
  121. var div = ownerDocument.createElement('DIV');
  122. div.style.background = "black url(" + basePath + "Zoom%20" + zoomLevel.toString() + "/Layer%200/" + coord.x.toString() + "/" + coord.y.toString() + ".png)";
  123. //div.innerHTML = coord + "," + zoomLevel.toString() + "<br/><br/>Zoom " + zoomLevel.toString() + "/Layer 0/" + coord.x.toString() + "/" + coord.y.toString() + ".png)";
  124. //div.style.border = "1px solid gray";
  125. div.style.color = "white";
  126. div.style.width = this.tileSize.width + 'px';
  127. div.style.height = this.tileSize.height + 'px';
  128. div.style.fontSize = '10';
  129. return div;
  130. };
  131. ///////////////////////////////////////////////////////////////////
  132. // MapObject
  133. ///////////////////////////////////////////////////////////////////
  134. function MapObject(location) {
  135. this.location = location;
  136. }
  137. function Npc(location, name) {
  138. this.location = location;
  139. this.name = name;
  140. }
  141. function Item(name, count) {
  142. this.name = name;
  143. this.count = count;
  144. }
  145. function Chest(location) {
  146. this.location = location;
  147. this.contents = new Array();
  148. this.type = 0;
  149. }
  150. Chest.prototype.onClick = function() {
  151. var contentsBubble = new google.maps.InfoWindow();
  152. var contentsTable = "<table class='Chest'><tr><th class='Item'>Item</th><th class='Count'>#</th></tr>";
  153. $(this.contents).sort(function(a, b) {
  154. return a.name.localeCompare(b.name);
  155. });
  156. $.each(this.contents, function() {
  157. contentsTable += "<tr><td class='Item'>" + this.name + "</td><td class='Count'>" + this.count + "</td></tr>";
  158. });
  159. contentsTable += "</table>";
  160. contentsBubble.setContent("<span style='font-family: verdana'>Chest</span><br/><br/>" + contentsTable);
  161. contentsBubble.setPosition(this.location);
  162. ShowInfoWindow(contentsBubble);
  163. }
  164. Chest.prototype.getMarkerIcon = function() {
  165. switch (this.type) {
  166. case 0:
  167. return "Images/NormalChestMarker.png";
  168. case 1:
  169. return "Images/GoldChestMarker.png";
  170. case 2:
  171. return "Images/LockedGoldChestMarker.png";
  172. case 3:
  173. return "Images/ShadowChestMarker.png";
  174. case 4:
  175. return "Images/LockedShadowChestMarker.png";
  176. case 5:
  177. return "Images/BarrelMarker.png";
  178. case 6:
  179. return "Images/TrashCanMarker.png";
  180. }
  181. }
  182. function Sign(location, text) {
  183. this.location = location;
  184. this.text = text;
  185. }
  186. Sign.prototype.onClick = function() {
  187. var contentsBubble = new google.maps.InfoWindow();
  188. contentsBubble.setContent("<p style='font-family: verdana'>" + this.text + "</p>");
  189. contentsBubble.setPosition(this.location);
  190. ShowInfoWindow(contentsBubble);
  191. }
  192. function Banner(location, type) {
  193. this.location = location;
  194. this.type = type;
  195. }
  196. Banner.prototype.getMarkerIcon = function() {
  197. switch (this.type) {
  198. case 0:
  199. return "Images/RedBannerMarker.png";
  200. case 1:
  201. return "Images/GreenBannerMarker.png";
  202. case 2:
  203. return "Images/BlueBannerMarker.png";
  204. case 3:
  205. return "Images/YellowBannerMarker.png";
  206. }
  207. }
  208. ///////////////////////////////////////////////////////////////////
  209. // Info Windows
  210. ///////////////////////////////////////////////////////////////////
  211. var activeInfoWindow = null;
  212. function ShowInfoWindow(infoWindow) {
  213. if (activeInfoWindow != null) {
  214. activeInfoWindow.close();
  215. }
  216. activeInfoWindow = infoWindow;
  217. if (activeInfoWindow != null) {
  218. infoWindow.open(map);
  219. }
  220. }
  221. ///////////////////////////////////////////////////////////////////
  222. // Controls
  223. ///////////////////////////////////////////////////////////////////
  224. function GoToSpawnControl(map) {
  225. // Set CSS for the control border
  226. var controlUI = document.createElement('DIV');
  227. controlUI.style.backgroundColor = '#CCDDFF';
  228. controlUI.style.borderStyle = 'solid';
  229. controlUI.style.borderWidth = '1px';
  230. controlUI.style.cursor = 'pointer';
  231. controlUI.style.textAlign = 'center';
  232. controlUI.style.margin = '3px';
  233. controlUI.title = 'Spawn Point';
  234. // Set CSS for the control interior
  235. var controlText = document.createElement('DIV');
  236. controlText.style.fontFamily = 'Verdana,sans-serif';
  237. controlText.style.fontSize = '12px';
  238. controlText.style.padding = '4px';
  239. controlText.innerHTML = 'Go to Spawn Point';
  240. controlUI.appendChild(controlText);
  241. google.maps.event.addDomListener(controlUI, 'click', function() {
  242. ShowInfoWindow(spawnPointInfoWindow);
  243. });
  244. this.element = controlUI;
  245. }
  246. function ToggleControl(map, markerType, name) {
  247. var text = markerType;
  248. if (name != null) {
  249. text = name;
  250. }
  251. // Set CSS for the control border
  252. var controlUI = document.createElement('DIV');
  253. controlUI.style.backgroundColor = '#7799DD';
  254. controlUI.style.borderStyle = 'solid';
  255. controlUI.style.borderWidth = '1px';
  256. controlUI.style.cursor = 'pointer';
  257. controlUI.style.textAlign = 'center';
  258. controlUI.style.width = '120px';
  259. controlUI.style.margin = '3px';
  260. // Set CSS for the control interior
  261. var controlText = document.createElement('DIV');
  262. controlText.style.fontFamily = 'Verdana,sans-serif';
  263. controlText.style.fontSize = '12px';
  264. controlText.style.padding = '4px';
  265. controlText.innerHTML = text;
  266. controlUI.appendChild(controlText);
  267. var self = this;
  268. google.maps.event.addDomListener(controlUI, 'click', function() {
  269. self.visible = !self.visible;
  270. var markerVisible = self.visible;
  271. if (self.visible) {
  272. self.element.style.backgroundColor = '#CCDDFF';
  273. } else {
  274. self.element.style.backgroundColor = '#7799DD';
  275. }
  276. $.each(mapObjects[markerType], function(mapObject) {
  277. this.marker.setVisible( markerVisible );
  278. });
  279. });
  280. this.label = controlText;
  281. this.text = text;
  282. this.element = controlUI;
  283. this.visible = false;
  284. }
  285. ///////////////////////////////////////////////////////////////////
  286. // Initialization
  287. ///////////////////////////////////////////////////////////////////
  288. var map;
  289. var spawnPoint = projection.fromBlockToLatLng(new google.maps.Point(2102, 180));
  290. var spawnPointInfoWindow = new google.maps.InfoWindow();
  291. var terrariaMapType = new TerrariaMapType();
  292. var mapObjects = {};
  293. mapObjects['Npc'] = new Array();
  294. mapObjects['Chest'] = new Array();
  295. mapObjects['Sign'] = new Array();
  296. mapObjects['HeartContainer'] = new Array();
  297. mapObjects['Anvil'] = new Array();
  298. mapObjects['Forge'] = new Array();
  299. mapObjects['Workbench'] = new Array();
  300. mapObjects['ShadowOrb'] = new Array();
  301. mapObjects['HellForge'] = new Array();
  302. mapObjects['Sawmill'] = new Array();
  303. mapObjects['Banner'] = new Array();
  304. mapObjects['Altar'] = new Array();
  305. mapObjects['Bed'] = new Array();
  306. var mapObjectImages = {};
  307. mapObjectImages['Npc'] = "Images/NpcMarker.png";
  308. mapObjectImages['Chest'] = "Images/NormalChestMarker.png";
  309. mapObjectImages['Sign'] = "Images/SignMarker.png";
  310. mapObjectImages['HeartContainer'] = "Images/HeartContainerMarker.png";
  311. mapObjectImages['Anvil'] = "Images/AnvilMarker.png";
  312. mapObjectImages['Forge'] = "Images/ForgeMarker.png";
  313. mapObjectImages['Workbench'] = "Images/WorkbenchMarker.png";
  314. mapObjectImages['ShadowOrb'] = "Images/ShadowOrbMarker.png";
  315. mapObjectImages['HellForge'] = "Images/HellForgeMarker.png";
  316. mapObjectImages['Sawmill'] = "Images/SawmillMarker.png";
  317. mapObjectImages['Banner'] = "Images/BlueBannerMarker.png";
  318. mapObjectImages['Altar'] = "Images/AltarMarker.png";
  319. mapObjectImages['Bed'] = "Images/BedMarker.png";
  320. function parsePosition(blockPosition) {
  321. var parts = blockPosition.split(",", 2);
  322. var x = parseInt(parts[0]);
  323. var y = parseInt(parts[1]);
  324. return new google.maps.Point(x, y);
  325. }
  326. function parsePixelPositionToLatLng(pixelPosition, offset) {
  327. var blockPosition = parsePosition(pixelPosition);
  328. // Convert from pixel to block.
  329. blockPosition.x /= 16;
  330. blockPosition.y /= 16;
  331. if (offset != null) {
  332. blockPosition.x += offset.x;
  333. blockPosition.y += offset.y;
  334. }
  335. return projection.fromBlockToLatLng(blockPosition, true);
  336. }
  337. function parsePositionToLatLng(blockPosition, offset) {
  338. var blockPosition = parsePosition(blockPosition);
  339. if (offset != null) {
  340. blockPosition.x += offset.x;
  341. blockPosition.y += offset.y;
  342. }
  343. return projection.fromBlockToLatLng(blockPosition, true);
  344. }
  345. function createSpawnPointInfoPanel() {
  346. return '<span style="font-family: verdana">Spawn Point</span>';
  347. }
  348. function loadMapData(xml) {
  349. var world = $(xml).find('World');
  350. spawnPoint = parsePositionToLatLng(world.attr('Spawn'));
  351. $(xml).find('Npc').each(loadNpc);
  352. $(xml).find('Chest').each(loadChest);
  353. $(xml).find('Sign').each(loadSign);
  354. $(xml).find('HeartContainer').each(loadHeartContainer);
  355. $(xml).find('Anvil').each(loadAnvil);
  356. $(xml).find('Forge').each(loadForge);
  357. $(xml).find('Workbench').each(loadWorkbench);
  358. $(xml).find('ShadowOrb').each(loadShadowOrb);
  359. $(xml).find('HellForge').each(loadHellForge);
  360. $(xml).find('Sawmill').each(loadSawmill);
  361. $(xml).find('Banner').each(loadBanner);
  362. $(xml).find('Altar').each(loadAltar);
  363. $(xml).find('Bed').each(loadBed);
  364. spawnPointInfoWindow.setContent(createSpawnPointInfoPanel());
  365. spawnPointInfoWindow.setPosition(spawnPoint);
  366. ShowInfoWindow(spawnPointInfoWindow);
  367. map.setCenter(spawnPoint);
  368. $.each(mapObjects, function(index, value) {
  369. $.each(value, function(mapObject) {
  370. var self = this;
  371. var markerImage = mapObjectImages[index];
  372. if (this.getMarkerIcon != null) {
  373. markerImage = this.getMarkerIcon();
  374. }
  375. self.marker = new google.maps.Marker({
  376. position: self.location,
  377. map: map,
  378. title: index,
  379. visible: false,
  380. icon: basePath + markerImage
  381. });
  382. if (self.onClick != null) {
  383. var marker = self.marker;
  384. google.maps.event.addListener(marker, 'click', function() {
  385. self.onClick();
  386. });
  387. }
  388. });
  389. });
  390. }
  391. function loadNpc() {
  392. var npc = new Npc(parsePixelPositionToLatLng($(this).attr('Location')), $(this).attr('Name'));
  393. mapObjects['Npc'].push(npc);
  394. }
  395. function loadChest() {
  396. var chest = new Chest(parsePositionToLatLng($(this).attr('Location'), new google.maps.Point(1, 0)));
  397. chest.type = parseInt($(this).attr('Type'));
  398. $(this).find('Item').each(function() {
  399. chest.contents.push(new Item($(this).attr('Name'), parseInt($(this).attr('Count'))));
  400. });
  401. chest.contents.sort( function(a, b) {
  402. return a.name.localeCompare(b.name);
  403. });
  404. mapObjects['Chest'].push(chest);
  405. }
  406. function loadSign() {
  407. var sign = new Sign(parsePositionToLatLng($(this).attr('Location'), new google.maps.Point(1, 0)), $(this).text());
  408. mapObjects['Sign'].push(sign);
  409. }
  410. function loadHeartContainer() {
  411. mapObjects['HeartContainer'].push(new MapObject(parsePositionToLatLng($(this).attr('Location'), new google.maps.Point(1, 0))));
  412. }
  413. function loadAnvil() {
  414. mapObjects['Anvil'].push(new MapObject(parsePositionToLatLng($(this).attr('Location'), new google.maps.Point(1, 0))));
  415. }
  416. function loadForge() {
  417. mapObjects['Forge'].push(new MapObject(parsePositionToLatLng($(this).attr('Location'), new google.maps.Point(1.5, 0))));
  418. }
  419. function loadWorkbench() {
  420. mapObjects['Workbench'].push(new MapObject(parsePositionToLatLng($(this).attr('Location'), new google.maps.Point(1, 0))));
  421. }
  422. function loadShadowOrb() {
  423. mapObjects['ShadowOrb'].push(new MapObject(parsePositionToLatLng($(this).attr('Location'), new google.maps.Point(1, 0))));
  424. }
  425. function loadHellForge() {
  426. mapObjects['HellForge'].push(new MapObject(parsePositionToLatLng($(this).attr('Location'), new google.maps.Point(1.5, 0))));
  427. }
  428. function loadSawmill() {
  429. mapObjects['Sawmill'].push(new MapObject(parsePositionToLatLng($(this).attr('Location'), new google.maps.Point(1.5, 0))));
  430. }
  431. function loadBanner() {
  432. var banner = new Banner(parsePositionToLatLng($(this).attr('Location'), new google.maps.Point(0.5, 0)), parseInt($(this).attr('Type')));
  433. mapObjects['Banner'].push(banner);
  434. }
  435. function loadAltar() {
  436. mapObjects['Altar'].push(new MapObject(parsePositionToLatLng($(this).attr('Location'), new google.maps.Point(1.5, 0))));
  437. }
  438. function loadBed() {
  439. mapObjects['Bed'].push(new MapObject(parsePositionToLatLng($(this).attr('Location'), new google.maps.Point(2, 0))));
  440. }
  441. function initialize() {
  442. var mapOptions = {
  443. zoom: 6,
  444. mapTypeControlOptions: {
  445. mapTypeIds: ['Terraria'],
  446. style: google.maps.MapTypeControlStyle.HORIZONTAL_BAR
  447. }
  448. };
  449. map = new google.maps.Map(document.getElementById("map_canvas"), mapOptions);
  450. map.mapTypes.set('terraria', terrariaMapType);
  451. map.setMapTypeId('terraria');
  452. //map.setZoom(1);
  453. var controlDiv = document.createElement('DIV');
  454. controlDiv.style.padding = '5px';
  455. var goToSpawnControl = new GoToSpawnControl(map);
  456. var altarToggleControl = new ToggleControl(map, 'Altar', 'Altars');
  457. var anvilToggleControl = new ToggleControl(map, 'Anvil', 'Anvils');
  458. var bannersToggleControl = new ToggleControl(map, 'Banner', 'Banners');
  459. var bedToggleControl = new ToggleControl(map, 'Bed', 'Beds');
  460. var chestToggleControl = new ToggleControl(map, 'Chest', 'Chests');
  461. var forgeToggleControl = new ToggleControl(map, 'Forge', 'Forges');
  462. var heartContainerToggleControl = new ToggleControl(map, 'HeartContainer', 'Heart Containers');
  463. var hellForgeToggleControl = new ToggleControl(map, 'HellForge', 'Hell Forges');
  464. var npcToggleControl = new ToggleControl(map, 'Npc', 'NPCs');
  465. var sawmillToggleControl = new ToggleControl(map, 'Sawmill', 'Sawmills');
  466. var shadowOrbToggleControl = new ToggleControl(map, 'ShadowOrb', 'Shadow Orbs');
  467. var signToggleControl = new ToggleControl(map, 'Sign', 'Signs');
  468. var workbenchToggleControl = new ToggleControl(map, 'Workbench', 'Workbenches');
  469. controlDiv.appendChild(goToSpawnControl.element);
  470. controlDiv.appendChild(document.createElement('BR'));
  471. controlDiv.appendChild(altarToggleControl.element);
  472. controlDiv.appendChild(anvilToggleControl.element);
  473. controlDiv.appendChild(bannersToggleControl.element);
  474. controlDiv.appendChild(bedToggleControl.element);
  475. controlDiv.appendChild(chestToggleControl.element);
  476. controlDiv.appendChild(forgeToggleControl.element);
  477. controlDiv.appendChild(heartContainerToggleControl.element);
  478. controlDiv.appendChild(hellForgeToggleControl.element);
  479. controlDiv.appendChild(npcToggleControl.element);
  480. controlDiv.appendChild(sawmillToggleControl.element);
  481. controlDiv.appendChild(shadowOrbToggleControl.element);
  482. controlDiv.appendChild(signToggleControl.element);
  483. controlDiv.appendChild(workbenchToggleControl.element);
  484. map.controls[google.maps.ControlPosition.TOP_RIGHT].push(controlDiv);
  485. // Load the map data file.
  486. $.ajax({
  487. type: "GET",
  488. url: basePath + "MapData.xml",
  489. dataType: "xml",
  490. success: loadMapData
  491. });
  492. }