Frontend for viewing Dungeon Defender layouts
選択できるのは25トピックまでです。 トピックは、先頭が英数字で、英数字とダッシュ('-')を使用した35文字以内のものにしてください。

viewer.js 11KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460
  1. $(function() {
  2. // Instructions
  3. (function() {
  4. var cookieName = 'hideinstructions';
  5. function showInstructions() {
  6. $.cookie(cookieName, null);
  7. $('#instructions').show();
  8. $('#showinstructions').hide();
  9. }
  10. function hideInstructions() {
  11. $.cookie(cookieName, 1, { expires: 365 });
  12. $('#instructions').hide();
  13. $('#showinstructions').show();
  14. }
  15. $('#hideinstructions').click(hideInstructions);
  16. $('#showinstructions').click(showInstructions);
  17. if ($.cookie(cookieName)) {
  18. hideInstructions();
  19. }
  20. })();
  21. // Saving
  22. (function() {
  23. function saveLayout() {
  24. _gaq.push(['_trackEvent', 'General', 'Save']);
  25. layout.notes = $('#notecontent').val();
  26. $('#save_inprogress').show();
  27. $('#save_done').hide();
  28. $('#savecontainer').show();
  29. $('#save_error').hide();
  30. $.ajax({
  31. type: 'POST',
  32. url: 'res/data/layouts/new',
  33. data: {layout: JSON.stringify(layout)},
  34. success: function(res) {
  35. window.location.hash = res;
  36. var url = window.location.href;
  37. $('#link').children().remove();
  38. $('<a>').attr('href', url).text(url).appendTo($('#link'));
  39. $('#save_inprogress').hide();
  40. $('#save_done').show();
  41. },
  42. error: function(xhr, status, error) {
  43. $('#save_error').text('Save failed! Server said: ' + error).show();
  44. }
  45. });
  46. }
  47. function closeSave() {
  48. $('#savecontainer').hide();
  49. }
  50. $('#savelayout').click(saveLayout);
  51. $('#savemask').click(closeSave);
  52. $('#saveclose').click(closeSave);
  53. })();
  54. // Layout picker
  55. (function() {
  56. $.each(levels, function(key) {
  57. var name = this.name;
  58. name && $('<button>')
  59. .append($('<img>').attr('src', this.image))
  60. .append($('<p>').text(name))
  61. .click(function() {
  62. window.location.hash = '';
  63. _gaq.push(['_trackEvent', 'Level picker', 'Picked', name]);
  64. showBlankLayout(key + 1);
  65. closePicker();
  66. })
  67. .appendTo($('#layoutpicker .container'));
  68. });
  69. function showPicker() {
  70. _gaq.push(['_trackEvent', 'Level picker', 'Shown']);
  71. $('#layoutcontainer').show();
  72. }
  73. function closePicker() {
  74. $('#layoutcontainer').hide();
  75. }
  76. $('#createlayout').click(showPicker);
  77. $('#layoutmask').click(closePicker);
  78. $('#layoutclose').click(closePicker);
  79. })();
  80. // Address management
  81. (function() {
  82. function updateFromHash() {
  83. var id = window.location.hash;
  84. if (id === '') {
  85. showBlankLayout(1);
  86. } else if (id.substr(0,7) == '#blank:') {
  87. showBlankLayout(parseInt(id.substr(7)));
  88. } else {
  89. getLayout(id.substr(1));
  90. }
  91. }
  92. $(window).bind('hashchange', updateFromHash);
  93. updateFromHash();
  94. })();
  95. // Palette
  96. (function() {
  97. $.each(towers, function(key) {
  98. createBaseElForTower(key, this).appendTo($('#palette'));
  99. });
  100. $('.tower,.core').draggable({
  101. helper: 'clone',
  102. containment: 'document',
  103. stop: function(evt, ui) {
  104. if (!$(this).data('type')) {
  105. return;
  106. }
  107. var tower = {
  108. type: $(this).data('type'),
  109. rotation: 0,
  110. position: adjustMapOffset(ui.helper.offsetFrom('#mapcontainer'), thisLevel, 1)
  111. };
  112. layout.towers.push(tower);
  113. createElForTower(tower).appendTo($('#mapcontainer'));
  114. updateDefenseUnits();
  115. }
  116. });
  117. })();
  118. // Searching
  119. (function() {
  120. $('#search_classes img').click(function() {
  121. var el = $(this);
  122. if (el.hasClass('disabled')) {
  123. el.removeClass('disabled');
  124. } else {
  125. el.addClass('disabled');
  126. }
  127. });
  128. var sel = $('select[name=search_map]');
  129. $.each(levels, function(key) {
  130. this.name && $('<option>').val(key + 1).text(this.name).appendTo(sel);
  131. });
  132. function showSearch() {
  133. $('#searchcontainer').show();
  134. }
  135. function hideSearch() {
  136. $('#searchcontainer').hide();
  137. }
  138. function clearSearchResults() {
  139. $('#searchresults tbody tr').remove();
  140. }
  141. function buildSearchQuery() {
  142. var query = {};
  143. var level = $('select[name=search_map]').val();
  144. if (level != 'any') {
  145. query.map = level;
  146. }
  147. var difficulty = $('select[name=search_difficulty]').val();
  148. if (difficulty != 'any') {
  149. query.difficulty = difficulty;
  150. }
  151. var type = $('select[name=search_type]').val();
  152. if (type != 'any') {
  153. query.type = type;
  154. }
  155. query.classes = '';
  156. $.each($('#search_classes img'), function() {
  157. if (!$(this).hasClass('disabled')) {
  158. if (query.classes.length > 0) { query.classes += ','; }
  159. query.classes += this.id.replace('search_', '');
  160. }
  161. });
  162. query.mode = '';
  163. if ($('input[name=search_hc]').is(':checked')) {
  164. query.mode += ',hardcore';
  165. }
  166. if ($('input[name=search_mm]').is(':checked')) {
  167. query.mode += ',mixed';
  168. }
  169. if ($('input[name=search_ps]').is(':checked')) {
  170. query.mode += ',strategy';
  171. }
  172. if (query.mode.length == 0) {
  173. delete query.mode;
  174. } else {
  175. query.mode = query.mode.substr(1);
  176. }
  177. query.limit = 100;
  178. doSearch(query);
  179. return false;
  180. }
  181. function doSearch(data) {
  182. clearSearchResults();
  183. $.ajax({
  184. url: 'res/data/layouts/search',
  185. data: data,
  186. success: handleSearch
  187. });
  188. }
  189. function handleSearch(data) {
  190. var body = $('#searchresults tbody');
  191. $.each(data, function() {
  192. this.difficulty = this.difficulty || 'unknown';
  193. this.type = (this.type && this.type != 'none') ? this.type : 'unknown';
  194. var tr = $('<tr>');
  195. tr.append($('<td>').append($('<a>').attr('href', '#' + this.id).text(this.id).click(hideSearch)));
  196. tr.append($('<td>').text(levels[this.level - 1] ? levels[this.level - 1].name : 'Unknown!'));
  197. tr.append($('<td>').addClass(this.difficulty).text(this.difficulty));
  198. tr.append($('<td>').addClass(this.type).text(this.type));
  199. tr.append($('<td>').html(getModesHTML(this.mode)));
  200. var classes = this.classes;
  201. var td = $('<td>');
  202. $.each(['huntress', 'apprentice', 'monk', 'squire'], function(k, v) {
  203. var url = v == 'apprentice' ? 'mage' : v;
  204. var img = $('<img>').attr('src', 'res/images/classes/' + url + '_icon.png')
  205. .attr('alt', v);
  206. if ($.inArray(v, classes) == -1) {
  207. img.addClass('disabled');
  208. }
  209. td.append(img);
  210. });
  211. tr.append(td);
  212. body.append(tr);
  213. });
  214. }
  215. $('#search_submit').click(buildSearchQuery);
  216. $('#search').click(showSearch);
  217. $('#searchmask').click(hideSearch);
  218. $('#searchclose').click(hideSearch);
  219. })();
  220. var thisLevel;
  221. var layout;
  222. function getModesHTML(modes) {
  223. var res = '';
  224. modes && $.each(modes, function() {
  225. if (this == "hardcore") {
  226. res = '<abbr title="Hardcore">hc</abbr> ' + res;
  227. } else if (this == "mixed") {
  228. res = '<abbr title="Mixed mode">mm</abbr> ' + res;
  229. } else if (this == "strategy") {
  230. res = '<abbr title="Pure strategy">ps</abbr> ' + res;
  231. } else if (this == "none") {
  232. res = 'none';
  233. }
  234. });
  235. return res || 'unknown';
  236. }
  237. function updateDefenseUnits() {
  238. var used = 0;
  239. $.each(layout.towers, function() {
  240. used += towers[this.type].units;
  241. });
  242. $('#du_used').text(used);
  243. var hasClass = $('#du_wrapper').hasClass('over');
  244. $('#du_wrapper').removeClass('over');
  245. if (used > thisLevel.du) {
  246. $('#du_wrapper').addClass('over');
  247. if (!hasClass) {
  248. $('#du_wrapper').effect('pulsate', {times: 2}, 'fast');
  249. }
  250. }
  251. }
  252. function createElForCore() {
  253. return $('<img>')
  254. .attr('src', 'res/images/coreIcon.png')
  255. .attr('alt', 'Core')
  256. .addClass('core')
  257. .css('position', 'absolute')
  258. .css('height', (40 * thisLevel.towerscale) + 'px')
  259. .css('width', (40 * thisLevel.towerscale) + 'px');
  260. }
  261. function createBaseElForTower(key) {
  262. var type = towers[key];
  263. return $('<img>')
  264. .attr('src', type.image)
  265. .attr('alt', type.name)
  266. .data('type', key)
  267. .addClass(type.class.toLowerCase())
  268. .addClass('tower');
  269. }
  270. function createElForTower(tower) {
  271. return createBaseElForTower(tower.type)
  272. .data('tower', tower)
  273. .draggable({
  274. containment: 'document',
  275. start: function(evt) {
  276. return !evt.shiftKey;
  277. },
  278. stop: function() {
  279. var el = $(this);
  280. el.data('tower').position = adjustMapOffset({top: parseInt(el.css('top')), left: parseInt(el.css('left'))}, thisLevel, 1);
  281. }
  282. })
  283. .css('position', 'absolute')
  284. .css('height', (40 * thisLevel.towerscale * towers[tower.type].defaultscale) + 'px')
  285. .css('width', (40 * thisLevel.towerscale * towers[tower.type].defaultscale) + 'px')
  286. .offset(adjustMapOffset(tower.position, thisLevel))
  287. .rotate(tower.rotation)
  288. .dblclick(function() {
  289. layout.towers = $.grep(layout.towers, function(value) { return value != tower; });
  290. $(this).remove();
  291. updateDefenseUnits();
  292. })
  293. .mousedown(function(e) {
  294. if (!e.shiftKey) {
  295. return;
  296. }
  297. var el = $(this);
  298. var centre = el.offsetCentre();
  299. var mouseX = e.pageX - centre.left, mouseY = e.pageY - centre.top;
  300. var initialMouseAngle = Math.atan2(mouseY, mouseX);
  301. var initialRotation = tower.rotation;
  302. var moveHandler = function(evt) {
  303. var mouseX = evt.pageX - centre.left, mouseY = evt.pageY - centre.top;
  304. var newMouseAngle = Math.atan2(mouseY, mouseX);
  305. var mouseDelta = newMouseAngle - initialMouseAngle;
  306. var rotation = initialRotation + newMouseAngle * (180 / Math.PI);
  307. tower.rotation = rotation;
  308. el.rotate(rotation);
  309. };
  310. var upHandler = function() {
  311. $(document).unbind('mousemove', moveHandler);
  312. $(document).unbind('mouseup', upHandler);
  313. };
  314. $(document).mousemove(moveHandler);
  315. $(document).mouseup(upHandler);
  316. return false;
  317. });
  318. }
  319. function adjustMapOffset(towerOffset, level, reverse) {
  320. var res = $.extend({}, towerOffset);
  321. if (level.offsets && !reverse) {
  322. res.left += level.offsets.left;
  323. res.top += level.offsets.top;
  324. }
  325. if (level.scale) {
  326. if (reverse) {
  327. res.left /= level.scale.left;
  328. res.top /= level.scale.top;
  329. } else {
  330. res.left *= level.scale.left;
  331. res.top *= level.scale.top;
  332. }
  333. }
  334. if (level.offsets && reverse) {
  335. res.left -= level.offsets.left;
  336. res.top -= level.offsets.top;
  337. }
  338. return res;
  339. }
  340. function clearLayout() {
  341. $('#mapcontainer .tower').remove();
  342. if (layout) {
  343. layout.towers = [];
  344. }
  345. }
  346. function clearCores() {
  347. $('#mapcontainer .core').remove();
  348. }
  349. function updateLayout(data) {
  350. clearLayout();
  351. clearCores();
  352. layout = data;
  353. thisLevel = levels[layout.level - 1];
  354. $.each(thisLevel.cores, function() {
  355. createElForCore().offset(adjustMapOffset(this, thisLevel)).appendTo($('#mapcontainer'));
  356. });
  357. _gaq.push(['_setCustomVar', 1, 'Level', thisLevel.name, 1]);
  358. $('#mapcontainer').css('background-image', 'url("' + thisLevel.minimap + '")');
  359. $('#notecontent').val(layout.notes);
  360. $.each(layout.towers, function() {
  361. createElForTower(this).appendTo($('#mapcontainer'));
  362. });
  363. updateDefenseUnits();
  364. var difficulty = layout.difficulty ? layout.difficulty : "unknown";
  365. $('#difficulty').text(difficulty).removeClass().addClass(difficulty);
  366. var type = layout.type && layout.type != 'none' ? layout.type : "unknown";
  367. $('#type').text(type);
  368. $('#modes').html(getModesHTML(layout.mode));
  369. $('#du_total').text(thisLevel.du);
  370. }
  371. function getLayout(id) {
  372. _gaq.push(['_trackPageview', '/view/' + id]);
  373. $.getJSON('res/data/layouts/' + id + '.js', updateLayout);
  374. }
  375. function showBlankLayout(id) {
  376. window.location.hash = 'blank:' + id;
  377. _gaq.push(['_trackPageview', '/view/blank:' + id]);
  378. updateLayout({level: id, towers:[]});
  379. }
  380. });