Advertisement
Guest User

Untitled

a guest
Mar 29th, 2017
117
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 45.05 KB | None | 0 0
  1. /*Sadye's report analyzer(=custom farm assistant)*/
  2. var settings = {
  3. worldSpeed: 1.5,
  4. unitSpeed: 0.6,
  5. sortOn: "distance", //also timesinceattack
  6. ignoreTooLittleScouts: true,
  7.  
  8. minTroops: 0.01,
  9. discountFactor: 1.01,
  10. filterIgnoreTypes: "none",
  11. filterIgnoreIfTroops: false,
  12. filterMaxWall: 20,
  13. filterMaxDistance: 20,
  14. filterMaxReadAge: 24,
  15. filterMaxUseAge: 6,
  16. }
  17.  
  18. // Script dat reports analyseert en sorteert op afstand en wall
  19. "undefined" == typeof window.$.twAjax && (window.$.twAjax = function() {
  20. var a = function(a, b) {
  21. this.options = a, this.promise = b
  22. },
  23. b = function() {
  24. var a = [],
  25. b = !1,
  26. c = function() {
  27. var b = a[0];
  28. $.ajax(b.options).done(function() {
  29. b.promise.resolve.apply(null, arguments), a.splice(b, 1), d()
  30. }).fail(function() {
  31. b.promise.reject.apply(null, arguments), d()
  32. })
  33. },
  34. d = function() {
  35. a.length ? (b = !0, c()) : b = !1
  36. },
  37. e = function(c) {
  38. a.push(c), b || d()
  39. };
  40. return {
  41. push: e
  42. }
  43. }();
  44. return function(c) {
  45. var d = $.Deferred();
  46. return b.push(new a(c, d)), d
  47. }
  48. }());
  49.  
  50. // Indien coordinaten gegeven -> Lees muur level uit rapporten of schat muur a.d.h. verloren troepen
  51. // Anders -> Vind dorpen in omgeving en sorteer op afstand/muur (allebei instelbaar met min, max)
  52.  
  53. var data = {};
  54. var currentAttacks = {};
  55. var unitTypes = ["spear", "sword", "axe", "archer", "spy", "light", "marcher", "heavy", "ram", "catapult", "snob", "knight", ];
  56. var buildingTypes = ["main", "hide", "market", "storage", "stable", "smith", "barracks", "place", "wall", "iron", "clay", "wood", "farm", "church", "watchtower", "statue", "garage", "snob"];
  57. var minLight = [1, 4, 32, 87, 170, 281];
  58.  
  59. function init() {
  60. $('#content_value').html('<h3> .Sadye&#39;s coordinate grabber </h3> <div id="request_data" class="vis"><h4>Press load new reports to retrieve all new reports!</h4></div> <div id="am_widget_Farm" data-widget="Farm" class="am_widget vis spaced"> <h4> <img src="https://dsnl.innogamescdn.com/8.71/32187/graphic/icons/configuration.png" title="" alt="" class=""> Filter and sort settings </h4> <div class="body"> <div id="plunder_list_filters" style="display:inline-block;background-color:#f4e4bc;margin:2px 2px 0 2px"> <div style="padding:2px 5px 2px 8px;float:left"> <div> <label for="sort">Sort on</label> <select id="sort" name="sort"> <option value="distance">Distance</option> <option value="wall">Wall</option> <option value="time">Time</option> <option value="expected_res">Expected res</option> <option value="expected_res_per_field">Expected res per field</option> </select> </div> <div> <label title="Dicounts the expected gs with this factor each hour" for="discount_factor">Discount factor (if unsure, set to 1)</label> <br> <input type="text" maxlength="5" name="discount_factor" id="discount_factor" value="1.00"> </div> <div> <input style="width:20px" type="text" maxlength="2" name="filter_distance_max" id="filter_distance_max" value="20"><label for="filter_distance_max">Max distance</label> </div> </div> <div style="padding:2px 5px 2px 8px;float:left"> <div> <label for="ignore_types">Ignore: </label> <select id="ignore_types" name="ignore_types"> <option value="none">None</option> <option value="players">Players</option> <option value="barbs">Barbs</option> </select> </div> <div> <input type="checkbox" name="filter_troops_in_village" id="filter_troops_in_village"><label for="filter_troops_in_village">Ignore if troops in village</label> <br> </div> <div> <input style="width:20px" type="text" maxlength="2" name="filter_wall_level_max" id="filter_wall_level_max" value="21"><label for="filter_wall_level_max">Max wall level</label> </div> </div> <div style="padding:2px 5px 2px 8px;float:left"> <div> <input style="width:20px" type="text" maxlength="2" name="filter_max_read_age" id="filter_max_read_age" value="24"><label for="filter_max_read_age">Max interpret age of report</label> </div><div> <input style="width:20px" type="text" maxlength="2" name="filter_max_use_age" id="filter_max_use_age" value="6"><label for="filter_max_use_age">Max age of report for res calculation </label> </div> </div> <div style="width:100%;padding:2px 5px 2px 5px;float:left"><button id="apply_settings" class="btn">Apply settings</button><button id="load_new_reports" class="btn">Load new reports</button></div> </div> <div class="vis"> <form id="farm_units"> <table id="units_home" style="width:100%"> <tbody><tr><th class="vis"><h4>Available</h4></th> <th style="width:50px;text-align:center" class="fm_unit"> <img src="https://dsnl.innogamescdn.com/8.71/32187/graphic/unit/unit_spear.png" title="" alt="" class=""> </th> <th style="width:50px;text-align:center" class="fm_unit"> <img src="https://dsnl.innogamescdn.com/8.71/32187/graphic/unit/unit_sword.png" title="" alt="" class=""> </th> <th style="width:50px;text-align:center" class="fm_unit"> <img src="https://dsnl.innogamescdn.com/8.71/32187/graphic/unit/unit_axe.png" title="" alt="" class=""> </th> <th style="width:50px;text-align:center" class="fm_unit"> <img src="https://dsnl.innogamescdn.com/8.71/32187/graphic/unit/unit_archer.png" title="" alt="" class=""> </th> <th style="width:50px;text-align:center" class="fm_unit"> <img src="https://dsnl.innogamescdn.com/8.71/32187/graphic/unit/unit_spy.png" title="" alt="" class=""> </th> <th style="width:50px;text-align:center" class="fm_unit"> <img src="https://dsnl.innogamescdn.com/8.71/32187/graphic/unit/unit_light.png" title="" alt="" class=""> </th> <th style="width:50px;text-align:center" class="fm_unit"> <img src="https://dsnl.innogamescdn.com/8.71/32187/graphic/unit/unit_marcher.png" title="" alt="" class=""> </th> <th style="width:50px;text-align:center" class="fm_unit"> <img src="https://dsnl.innogamescdn.com/8.71/32187/graphic/unit/unit_heavy.png" title="" alt="" class=""> </th> </tr><tr> <td>This village</td> <td style="text-align:center" class="unit-item unit-item-spear hidden" id="spear">0</td><td style="text-align:center" class="unit-item unit-item-sword hidden" id="sword">0</td><td style="text-align:center" class="unit-item unit-item-axe hidden" id="axe">0</td><td style="text-align:center" class="unit-item unit-item-archer hidden" id="archer">0</td><td style="text-align:center" class="unit-item unit-item-spy hidden" id="spy">0</td><td style="text-align:center" class="unit-item unit-item-light" id="light">3</td><td style="text-align:center" class="unit-item unit-item-marcher hidden" id="marcher">0</td><td style="text-align:center" class="unit-item unit-item-heavy hidden" id="heavy">0</td> </tr> </tbody></table> </form> </div> <table id="plunder_list" style="width:100%"> <tbody><tr> <th>&nbsp;</th><th>&nbsp;</th> <th>&nbsp;</th> <th title="is a Player?"><span class="icon header knight"></span></th> <th>Dorp</th> <th>Time</th> <th><span class="icon header ressources"> </span></th> <th><img src="https://dsnl.innogamescdn.com/8.71/32187/graphic/buildings/wall.png" class=""></th> <th><img src="https://dsnl.innogamescdn.com/8.71/32187/graphic/rechts.png" class=""></th> <th colspan="2"> <img src="https://dsnl.innogamescdn.com/8.71/32187/graphic/questionmark.png" title="Send the minimum amount of light" width="13" height="13" class=""> </th> <th><img src="https://dsnl.innogamescdn.com/8.71/32187/graphic/questionmark.png" width="13" height="13" class=""></th> <th><img src="https://dsnl.innogamescdn.com/8.71/32187/graphic/questionmark.png" width="13" height="13" class=""></th> <th><img src="https://dsnl.innogamescdn.com/8.71/32187/graphic/buildings/place.png" class=""></th> </tr> </tbody> </table> </div>');
  61. retrieveOldReports();
  62. //analyzeReports();
  63. populateTable();
  64. applySettings();
  65. updateHomeUnits(true);
  66. updateCurrentAttacks(true);
  67.  
  68. $('#apply_settings').click(function() {
  69. applySettings();
  70. });
  71.  
  72. $('#load_new_reports').click(function() {
  73. analyzeReports();
  74. applySettings();
  75. });
  76. }
  77.  
  78. function updateHomeUnits(autorefresh) {
  79. $.twAjax({
  80. url: "game.php?village=" + game_data.village.id + "&screen=place&ajax=home_units&client_time=" + Math.round(new Date().getTime() / 1000),
  81. }).done(function(result) {
  82. var units = JSON.parse(result);
  83. for (var unit in units) {
  84. if (parseInt(units[unit])) {
  85. $('#' + unit).removeClass('hidden').text(units[unit]);
  86. } else {
  87. $('#' + unit).addClass('hidden').text('0');
  88. }
  89. }
  90. if (autorefresh) {
  91. window.setTimeout(function() {
  92. updateHomeUnits(true);
  93. }, 10 * 1000);
  94. }
  95. });
  96. }
  97.  
  98. function updateCurrentAttacks(autorefresh) {
  99. currentAttacks = {};
  100.  
  101. $.twAjax({
  102. url: "game.php?village=" + game_data.village.id + "&screen=place"
  103. }).done(function(result) {
  104. // read current attacjs
  105. $(result).find('tr.command-row td:first-child').each(function(i, e) {
  106. var type = $(e).find('span').data('command-type');
  107. var coords = $(e).text().match(/\d{2,3}\|\d{2,3}/)[0];
  108. if (!currentAttacks[coords]) {
  109. currentAttacks[coords] = {};
  110. }
  111. currentAttacks[coords][type] = true;
  112. });
  113. // update in table
  114. console.log("Removing attack images");
  115. $('td a:contains("|") img').remove(); // remove all current attack images
  116. $('td a:contains("|")').each(function(i, e) {
  117. var coords = $(e).text().trim().match(/\d{2,3}\|\d{2,3}/);
  118. //console.log("Calculating attack images for " + coords);
  119. var attackImages = $(e).text();
  120. if (currentAttacks[coords]) {
  121. if (currentAttacks[coords].attack) {
  122. attackImages += '<img src="https://dsnl.innogamescdn.com/8.71/32187/graphic/command/attack_small.png">';
  123. }
  124. if (currentAttacks[coords].return) {
  125. attackImages += '<img src="https://dsnl.innogamescdn.com/8.71/32187/graphic/command/return_attack_small.png">';
  126. }
  127. }
  128. $(e).html(attackImages);
  129. });
  130.  
  131. if (autorefresh) {
  132. window.setTimeout(function() {
  133. updateCurrentAttacks(true);
  134. }, 10 * 1000);
  135. }
  136. });
  137. }
  138.  
  139. function applySettings() {
  140. settings.sortOn = $('#sort').val();
  141. settings.filterIgnoreTypes = $('#ignore_types').val();
  142.  
  143. settings.filterIgnoreIfTroops = $('#filter_troops_in_village').is(':checked');
  144.  
  145. settings.filterMaxWall = parseInt($('#filter_wall_level_max').val());
  146. settings.filterMaxDistance = parseInt($('#filter_distance_max').val());
  147.  
  148. settings.filterMaxReadAge = parseInt($('#filter_max_read_age').val());
  149. settings.filterMaxUseAge = parseInt($('#filter_max_use_age').val());
  150.  
  151. settings.discountFactor = parseFloat($('#discount_factor').val());
  152. console.log(settings.discountFactor);
  153.  
  154. updateCurrentAttacks(false);
  155. populateTable();
  156. }
  157.  
  158. function sendAttack(frameId, url, coords, expectedRes, overrideReport, justScouts) {
  159.  
  160. var callback = function(frameId, overrideReport, justScouts) {
  161. var frame = $('#frame_' + frameId).contents();
  162. var targetAttack = frame.find("#target_attack");
  163. var error = frame.find('.error_box');
  164.  
  165. if (error.length > 0) {
  166. console.warn("Error: " + error);
  167. alert("Error: " + error.text());
  168. $('#frame_' + frameId).remove();
  169. return;
  170. }
  171. else if (targetAttack.length > 0) {
  172. // some calculations to send min or max amount
  173. var lc = parseInt(frame.find('#unit_input_light').data('all-count'));
  174. var spy = parseInt(frame.find('#unit_input_spy').data('all-count'));
  175. var spyToSend = Math.min(spy, 1);
  176. if (spy === 0 && !settings.ignoreTooLittleScouts || (justScouts && spy < justScouts)) {
  177. //alert("Not enough spy!");
  178. console.warn("Not enough spy for " + coords);
  179. $('#frame_' + frameId).remove();
  180. return;
  181. }
  182. if (justScouts) {
  183. // we know from previous if that we have enough spy
  184. frame.find("#unit_input_spy").val(justScouts);
  185. targetAttack.click();
  186. return;
  187. }
  188. var minLc = 1;
  189. var maxLc = Math.ceil(expectedRes / 80);
  190. if (data[coords].buildingData && minLight[data[coords].buildingData.wall]) {
  191. minLc = minLight[data[coords].buildingData.wall];
  192. }
  193. if (lc < minLc && !overrideReport) {
  194. alert("Not enough LC!");
  195. console.warn("Not enough LC for " + coords);
  196. $('#frame_' + frameId).remove();
  197. return;
  198. }
  199. var lcToSend = Math.max(minLc, Math.min(maxLc, lc));
  200. if (!overrideReport) {
  201. frame.find('#unit_input_light').val(lcToSend);
  202. } else {
  203. console.log("spy: " + spyToSend + " LC: " + minLc + " p: " + game_data.village.points * settings.minTroops);
  204. if (minLc/4 + spyToSend/2 < Math.floor(game_data.village.points * settings.minTroops)) {
  205. minLc = Math.ceil((Math.floor(game_data.village.points * settings.minTroops) - 2*spyToSend) / 4);
  206. }
  207. console.log("spy: " + spyToSend + " LC: " + minLc + " p: " + game_data.village.points * settings.minTroops);
  208. frame.find('#unit_input_light').val(minLc);
  209. }
  210. frame.find("#unit_input_spy").val(spyToSend);
  211. targetAttack.click();
  212. } else {
  213. frame.find('#troop_confirm_go').click();
  214. updateHomeUnits();
  215. $('#frame_' + frameId).load(function() {
  216. $(this).remove();
  217. })
  218. }
  219. }
  220.  
  221. $('<iframe id="frame_' + frameId + '" src="' + url + '" />').load(function(event) {
  222. return callback(frameId, overrideReport, justScouts);
  223. }).css({
  224. width: '100px',
  225. height: '100px',
  226. position: 'absolute',
  227. left: '-100px',
  228. top: '-100px',
  229. }).appendTo('body').hide();
  230. }
  231.  
  232. function populateTable() {
  233. $('#plunder_list tr:gt(0)').remove();
  234. var sortedData = [];
  235. for (var key in data) {
  236. sortedData.push(data[key]);
  237. }
  238. //console.log(sortedData);
  239. var serverTime = getServerTime(document);
  240. sortedData = sortedData.filter(function(e, i, arr) {
  241. if (e.isPlayer && settings.filterIgnoreTypes == "players" || !e.isPlayer && settings.filterIgnoreTypes == "barbs") {
  242. return false;
  243. }
  244. if (settings.filterIgnoreIfTroops) {
  245. for (var i in e.enemyHome) {
  246. if (e.enemyHome[i] != 0) return false;
  247. }
  248. }
  249. var d = getDistance(game_data.village.coord, e.coords);
  250. if (d >= settings.filterMaxDistance) {
  251. return false;
  252. }
  253. if (e.buildingData && e.buildingData.wall >= settings.filterMaxWall) {
  254. return false;
  255. }
  256. return true;
  257. });
  258. sortedData.sort(function(a, b) {
  259. if (settings.sortOn == "wall") {
  260. if (a.buildingData && b.buildingData) {
  261. if (a.buildingData.wall !== b.buildingData.wall) {
  262. return a.buildingData.wall - b.buildingData.wall;
  263. } else {
  264. return getDistance(a.coords, game_data.village.coord) - getDistance(b.coords, game_data.village.coord);
  265. }
  266. } else if (a.buildingData) {
  267. return -1;
  268. } else {
  269. return 1;
  270. }
  271. } else if (settings.sortOn == "expected_res") {
  272. if (a.buildingData && b.buildingData) {
  273. //var serverTime = getServerTime(document);
  274. return getExpectedRes(b.coords, serverTime, false, false) - getExpectedRes(a.coords, serverTime, false, false);
  275. } else if (a.buildingData) {
  276. return -1;
  277. } else {
  278. return 1;
  279. }
  280. } else if (settings.sortOn == "expected_res_per_field") {
  281. if (a.buildingData && b.buildingData) {
  282. //var serverTime = getServerTime(document);
  283. return getExpectedRes(b.coords, serverTime, false, false) / getDistance(b.coords, game_data.village.coord) - getExpectedRes(a.coords, serverTime, false, false) / getDistance(a.coords, game_data.village.coord);
  284. } else if (a.buildingData) {
  285. return -1;
  286. } else {
  287. return 1;
  288. }
  289. }
  290. else if (settings.sortOn == "time") {
  291. return b.lastAttack.getTime() - a.lastAttack.getTime();
  292. }
  293. return getDistance(a.coords, game_data.village.coord) - getDistance(b.coords, game_data.village.coord);
  294. });
  295.  
  296. for (var i in sortedData) {
  297. var resLeft = 0; // res left (assuming no hauls since our last haul)
  298. var resLeftString = ""; // ? if we etimate buildings, ?? if we estimate buildings and res left
  299.  
  300. if (sortedData[i].scoutRes) {
  301. if (sortedData[i].scoutBuilding) {
  302. // all data
  303. resLeft = Math.round(getExpectedRes(sortedData[i].coords, getServerTime(document), false, false), 0);
  304. } else {
  305. resLeftString = "~";
  306. resLeft = Math.round(getExpectedRes(sortedData[i].coords, getServerTime(document), false, {
  307. storage: 5,
  308. hide: 3,
  309. wood: 2,
  310. clay: 2,
  311. iron: 2
  312. }), 0);
  313. }
  314. } else if (!sortedData[i].fullHaul) {
  315. resLeftString = "~~";
  316. resLeft = Math.round(getExpectedRes(sortedData[i].coords, getServerTime(document), 0, {
  317. storage: 5,
  318. hide: 3,
  319. wood: 2,
  320. clay: 2,
  321. iron: 2
  322. }), 0);
  323. } else {
  324. resLeftString = "~~";
  325. resLeft = Math.round(getExpectedRes(sortedData[i].coords, getServerTime(document), 50, {
  326. storage: 5,
  327. hide: 3,
  328. wood: 2,
  329. clay: 2,
  330. iron: 2
  331. }), 0);
  332. }
  333.  
  334. if (resLeft < 0) {
  335. resLeft = 0;
  336. resLeftString = "";
  337. }
  338.  
  339. // build attack images
  340. var attackImages = "";
  341. if (currentAttacks[sortedData[i].coords]) {
  342. if (currentAttacks[sortedData[i].coords].attack) {
  343. attackImages += '<img src="https://dsnl.innogamescdn.com/8.71/32187/graphic/command/attack_small.png">';
  344. }
  345. if (currentAttacks[sortedData[i].coords].return) {
  346. attackImages += '<img src="https://dsnl.innogamescdn.com/8.71/32187/graphic/command/return_attack_small.png">';
  347. }
  348. }
  349. var dateString = leadingZero(sortedData[i].lastAttack.getUTCHours()) + ":" + leadingZero(sortedData[i].lastAttack.getUTCMinutes()) + ":" + leadingZero(sortedData[i].lastAttack.getUTCSeconds());
  350. if (serverTime.getDate() == sortedData[i].lastAttack.getDate()) {
  351. dateString = "Today, " + dateString;
  352. } else {
  353. dateString = leadingZero(sortedData[i].lastAttack.getUTCDate()) + "-" + leadingZero(sortedData[i].lastAttack.getUTCMonth() + 1) + "-" + sortedData[i].lastAttack.getUTCFullYear() + " " + dateString;
  354. }
  355.  
  356. $('#plunder_list tbody').append('<tr class="row_' + (i % 2 == 1 ? 'a' : 'b') + '">\
  357. <td><a href="#/" onclick="deleteVillage(\''+ sortedData[i].coords +'\');"><img src="https://dsnl.innogamescdn.com/8.72/32238/graphic/delete.png"></a></td>\
  358. <td><img src="https://dsnl.innogamescdn.com/8.71/32187/graphic/dots/' + sortedData[i].dots + '.png"></td>\
  359. <td><img src="https://dsnl.innogamescdn.com/8.71/32187/graphic/max_loot/' + (sortedData[i].fullHaul ? 1 : 0) + '.png" class=""></td>\
  360. <td>' + (sortedData[i].isPlayer ? '<a target="_blank" href="game.php?village=' + game_data.village.id + '&screen=info_player&id=' + sortedData[i].playerId + '" title="' + sortedData[i].playerName + '" class="icon header knight">&nbsp;<a>' : '&nbsp;') + '</td>\
  361. <td><a target="_blank" href="game.php?village=' + game_data.village.id + '&screen=report&mode=all&group_id=0&view=' + sortedData[i].reportId + '">(' + sortedData[i].coords + ') ' + attackImages + '</a></td>\
  362. <td>' + dateString + '</td>\
  363. <td title="Best estimate of res at arrival"><img src="https://dsnl.innogamescdn.com/8.71/32187/graphic/max_loot/1.png">' + (resLeftString + resLeft) + ' <span style="float:right;" title="Per field of travel">(' + resLeftString + Math.round(resLeft / getDistance(sortedData[i].coords, game_data.village.coord)) + ')</span></td>\
  364. <td>' + (sortedData[i].buildingData ? sortedData[i].buildingData.wall : "?") + '</td>\
  365. <td>' + Math.round(getDistance(game_data.village.coord, sortedData[i].coords) * 10) / 10 + '</td>\
  366. <td><a target="_blank" href="game.php?village=' + game_data.village.id + '&screen=info_village&id=' + sortedData[i].villageId + '"><span class="icon header village"></span></a></td>\
  367. <td><a class="farm_icon_a farm_icon" href="#/" onclick="javascript:sendAttack(\'' + sortedData[i].villageId + '\', \'' + 'game.php?village=' + game_data.village.id + '&screen=place&target=' + sortedData[i].villageId + '\', \'' + sortedData[i].coords + '\', ' + resLeft + ', true, false);$(this).css({opacity: \'0.5\'});"></a></td>\
  368. <td><a class="farm_icon_c farm_icon" href="#/" onclick="javascript:sendAttack(\'' + sortedData[i].villageId + '\', \'' + 'game.php?village=' + game_data.village.id + '&screen=place&target=' + sortedData[i].villageId + '\', \'' + sortedData[i].coords + '\', ' + resLeft + ', false, false);$(this).css({opacity: \'0.5\'});"></a></td>\
  369. <td><a href="#/" onclick="javascript:sendAttack(\'' + sortedData[i].villageId + '\', \'' + 'game.php?village=' + game_data.village.id + '&screen=place&target=' + sortedData[i].villageId + '\', \'' + sortedData[i].coords + '\', ' + resLeft + ', true, '+ (sortedData[i].isPlayer ? 5 : 1)+');$(this).css({opacity: \'0.5\'});"><img src="https://dsnl.innogamescdn.com/8.71/32187/graphic/unit/unit_spy.png"></a></td>\
  370. <td><a target="_blank" href="game.php?village=' + game_data.village.id + '&screen=place&target=' + sortedData[i].villageId + '"><img src="https://dsnl.innogamescdn.com/8.71/32187/graphic/buildings/place.png"></a></td>\
  371. </tr>');
  372. //console.log(sortedData[i].scoutRes, sortedData[i].scoutBuilding, sortedData[i].coords, getServerTime(document));
  373. // -> OLD SEND ATTACK CODE//<a target="_blank" href="game.php?village=' + game_data.village.id + '&screen=place&target=' + sortedData[i].villageId + '&light=' + Math.max((sortedData[i].buildingData && minLight[sortedData[i].buildingData.wall] ? minLight[sortedData[i].buildingData.wall] : 0), Math.ceil(resLeft / 80)) + '&spy=1" class="farm_icon farm_icon_c" onclick="$(this).css({opacity:\'.5\'});sendAttack()"></a>
  374. //frameId, url, coords, expectedRes
  375. //sendAttack(sortedData[i].villageId, 'game.php?village=' + game_data.village.id + '&screen=place&target=' + sortedData[i].villageId, sortedData[i].coords, resLeft)
  376. }
  377. }
  378.  
  379. var deleteVillage = function(coords) {
  380. if (window.confirm("Are you sure?")) {
  381. delete data[coords];
  382.  
  383. // store in localstorage
  384. localStorage.setItem(game_data.world + "_sadye_rep_data", JSON.stringify(data));
  385. populateTable();
  386. }
  387. }
  388.  
  389. var leadingZero = function(string) {
  390. if (parseInt(string) < 10) {
  391. return "0" + string;
  392. }
  393. return string;
  394. }
  395.  
  396. var getExpectedRes = function(coords, serverTime, assumeRes, assumeBuildings) {
  397. let lastReport = data[coords];
  398.  
  399. let distance = getDistance(game_data.village.coord, coords);
  400. // travel time for LC/
  401. let travelTimeInHours = distance / 10 / settings.worldSpeed / settings.unitSpeed;
  402. // max 6 hours
  403. let timePassedInHours = Math.min((serverTime.getTime() - lastReport.lastAttack.getTime()) / (1000 * 60 * 60), settings.filterMaxUseAge);
  404.  
  405. //console.debug(coords + ". Distance: " + distance + ". Travel time: " + travelTimeInHours + ". Time since attack: " + timePassedInHours);
  406.  
  407. let maxStorage = null;
  408. let maxHide = null
  409. let resOver = null;
  410. let resPerHour = null;
  411.  
  412. if (assumeBuildings !== false) {
  413. //console.debug("Assuming buildings!");
  414. maxStorage = getMaxStorage(assumeBuildings.storage);
  415. //console.log(maxStorage);
  416. maxHide = getMaxHiding(assumeBuildings.hide);
  417. //console.log(maxHide);
  418. resPerHour = getResPerHour(assumeBuildings.wood) + getResPerHour(assumeBuildings.clay) + getResPerHour(assumeBuildings.iron);
  419. //console.log(resPerHour);
  420. } else {
  421. maxStorage = getMaxStorage(lastReport.buildingData.storage);
  422. maxHide = getMaxHiding(lastReport.buildingData.hide);
  423. resPerHour = getResPerHour(lastReport.buildingData.wood) + getResPerHour(lastReport.buildingData.clay) + getResPerHour(lastReport.buildingData.iron);
  424. }
  425.  
  426. //console.debug("maxStorage: " + maxStorage + ". maxHide: " + maxHide + ". resPerHour: " + resPerHour);
  427. if (assumeRes !== false) {
  428. console.debug("Assuming res left")
  429. resOver = assumeRes;
  430. } else {
  431. resOver = lastReport.resLeft;
  432. }
  433.  
  434.  
  435. let maxLoot = maxStorage - maxHide;
  436. let tempRes = resOver + (timePassedInHours) * resPerHour;
  437.  
  438. let expectedRes = Math.min(maxLoot, tempRes)
  439.  
  440. //console.debug("Expected res for " + coords + "@" + unit + ": " + expectedRes);
  441.  
  442. if (settings.discountFactor != 1) {
  443. expectedRes = expectedRes / (Math.pow(settings.discountFactor, timePassedInHours + travelTimeInHours));
  444. //console.log(timePassedInHours, travelTimeInHours);
  445.  
  446. }
  447.  
  448. //console.debug("Expected discounted res for " + coords + "@" + unit + ": " + expectedRes);
  449.  
  450. return expectedRes;
  451.  
  452. }
  453.  
  454. function analyzeReports() {
  455. $('#load_new_reports').prop('disabled', true).addClass('btn-disabled');
  456. var reportsToAnalyze = [];
  457.  
  458. var listUrl = ["/game.php?village=" + game_data.village.id + "&screen=report&mode=attack&group_id=0&from=", "/game.php?village=" + game_data.village.id + "&screen=report&mode=attack&group_id="];
  459. var reportUrl = "/game.php?village=" + game_data.village.id + "&screen=report&mode=attack&view=";
  460. var currentRun = getServerTime(document);
  461. var lastRun = JSON.parse(localStorage.getItem(game_data.world + "_sadye_rep_lastrun"));
  462. var lastRun = lastRun ? new Date(lastRun) : null;
  463. console.log(lastRun);
  464. var maxPages = [-1, -1]; // first one is normal, second one farmAssistant
  465. var currentPage = [0, 0];
  466. var totalReports;
  467. var reportsLeft;
  468. var parsingTwoLists;
  469. let finished = [false, false];
  470. var newReports = true;
  471.  
  472.  
  473.  
  474. $.twAjax({
  475. url: listUrl[0] + currentPage[0],
  476. }).done(function(result) {
  477. parsingTwoLists = $(result).find('a:contains("[Farm")').attr('href').match(/id=(\d+)/)[1]; // contains the id of the fa-map or nothing
  478.  
  479. console.log("Interpreting normal list")
  480. handleList(result, false);
  481.  
  482. console.log("Parsing two lists: ", parsingTwoLists);
  483. if (parsingTwoLists) {
  484. listUrl[1] = listUrl[1] + parsingTwoLists + "&from=";
  485. // if we have fa, also load that one
  486. $.twAjax({
  487. url: listUrl[1] + currentPage[1],
  488. }).done(function(result) {
  489. handleList(result, parsingTwoLists);
  490. });
  491. }
  492. });
  493.  
  494. $(document).ajaxStop(function() {
  495. $(this).unbind("ajaxStop");
  496. localStorage.setItem(game_data.world + "_sadye_rep_lastrun", JSON.stringify(currentRun));
  497. console.log("Ajaxstop!");
  498. if (newReports) {
  499. populateTable();
  500. newReports = false;
  501. }
  502. $('#load_new_reports').prop('disabled', false).removeClass('btn-disabled');
  503. $()
  504. });
  505.  
  506. var handleList = function(result, farmAssistantMap) {
  507. if (farmAssistantMap) {
  508. if (maxPages[1] === -1) {
  509. maxPages[1] = getMaxPages(result);
  510. console.log("Set maxpages in FA-map: " + maxPages[1]);
  511. }
  512. } else {
  513. if (maxPages[0] === -1) {
  514. maxPages[0] = getMaxPages(result);
  515. }
  516. }
  517. $('#request_data h4').text("Updating data. Retrieving scannable reports. Current page: " + ((farmAssistantMap ? currentPage[1] + currentPage[0] : currentPage[0]) + 1) + "/" + (farmAssistantMap ? maxPages[0] + maxPages[1] : maxPages[0]));
  518. $(result).find('#report_list tr td:nth-of-type(3)').each(function(i, e) {
  519. // retrieve some info
  520. let coords = $(e).siblings().find('.quickedit-label').text().match(/\d{1,3}\|\d{1,3}/g);
  521. coords = coords[coords.length - 1];
  522. let id = $(e).siblings().find("[data-id]").attr('data-id');
  523.  
  524. let dateTime = $(e).text().split(" ");
  525. let dateString = "20" + dateTime[0].split(".").reverse().join("-");
  526. let receivedAt = new Date(dateString + "T" + dateTime[1] + "Z");
  527.  
  528. let now = getServerTime(result);
  529.  
  530. if (now.getTime() - receivedAt.getTime() >= 1000 * 60 * 60 * settings.filterMaxReadAge) {
  531. // older than 24 -> we can immediately stop
  532. console.debug("Skipped " + coords + " received at " + receivedAt.toUTCString() + " because > " + settings.filterMaxReadAge + " hours.");
  533. if (farmAssistantMap) { // denote whuch loop is finished
  534. finished[1] = true;
  535. } else {
  536. finished[0] = true;
  537. }
  538. return false; //break out of each-loop
  539. } else if (lastRun && lastRun.getTime() - receivedAt.getTime() >= 1000 * 60) {
  540. // the report was already caught in the last run
  541. console.debug("Skipped " + coords + " received at " + receivedAt.toUTCString() + " because we caught it last run. (Start of last run: " + lastRun + ")");
  542. if (farmAssistantMap) { // denote whuch loop is finished
  543. finished[1] = true;
  544. } else {
  545. finished[0] = true;
  546. }
  547. return false;
  548.  
  549. } else if (data[coords] && data[coords].scoutBuilding && receivedAt.getTime() - data[coords].scoutBuilding.getTime() <= 60 * 1000) {
  550. // we already have data from less than a minute later
  551. console.debug("Skipped " + coords + " received at " + receivedAt.toUTCString() + " last building scout is more recent (" + data[coords].scoutBuilding.toUTCString() + ")");
  552. } else {
  553. // valid report
  554. console.debug("Added! Lastrun: " + (lastRun ? lastRun.toUTCString() : "--no such run--") + ". Received: " + receivedAt.toUTCString());
  555. reportsToAnalyze.push(id);
  556. }
  557.  
  558. });
  559. if (parsingTwoLists) { // we are running two in parallel
  560. if (farmAssistantMap) { // we are in the farm assistant map part
  561. if (finished[1] || currentPage[1] == maxPages[1] - 1) { // fa map is done
  562. finished[1] = true; // set this to true, so the other one can also check this
  563. if (finished[0]) { // all are finished, so handle the finished list
  564. listFinished();
  565. }
  566. } else {
  567. // we are not done reading reports in the FA-map, so open next page
  568. currentPage[1]++;
  569. console.debug("Going to next page in FA-map: " + (currentPage[1] + 1));
  570.  
  571. $.twAjax({
  572. url: listUrl[1] + (currentPage[1] * 12),
  573. }).done(function(result) {
  574. handleList(result, farmAssistantMap);
  575. });
  576. }
  577. } else {
  578. // we are in the normal map
  579. if (finished[0] || currentPage[0] == maxPages[0] - 1) {
  580. finished[0] = true;
  581. if (finished[1]) {
  582. listFinished();
  583. }
  584. } else {
  585. currentPage[0]++;
  586. console.debug("Going to next page in normal map: " + (currentPage[0] + 1));
  587. $.twAjax({
  588. url: listUrl[0] + (currentPage[0] * 12),
  589. }).done(function(result) {
  590. handleList(result, false);
  591. });
  592. }
  593. }
  594. } else { // no farm assistant map
  595. if (finished[0] || currentPage[0] == maxPages[0] - 1) {
  596. // all is done
  597. listFinished();
  598. } else {
  599. // load the next page
  600. currentPage[0]++;
  601. console.debug("Going to next page: " + (currentPage[0] + 1));
  602.  
  603. $.twAjax({
  604. url: listUrl[0] + (currentPage[0] * 12),
  605. }).done(function(result) {
  606. handleList(result, false);
  607. });
  608. }
  609. }
  610. }
  611.  
  612. var listFinished = function() {
  613. console.log("Finished reading list of reports!");
  614. totalReports = reportsToAnalyze.length;
  615. reportsLeft = totalReports;
  616. $('#request_data h4').text("Updating data. " + Math.round((totalReports - reportsLeft) / totalReports * 100, 0) + "% (" + (reportsLeft) + " reports left)");
  617. // start interpreting
  618. while (reportsToAnalyze.length > 0) {
  619. var id = reportsToAnalyze.shift();
  620. $.twAjax({
  621. url: reportUrl + id,
  622. async: true
  623. }).done(function(result) {
  624. reportsLeft--;
  625. handleReport(result, id);
  626. $('#request_data h4').text("Updating data. " + Math.round((totalReports - reportsLeft) / totalReports * 100, 0) + "% (" + (reportsLeft) + " reports left)");
  627. if (reportsLeft === 0) {
  628. $('#request_data h4').text("Ready! (read " + totalReports + " reports)");
  629. $('#load_new_reports').removeClass('btn-disabled').prop('disabled', false);
  630. }
  631. });
  632. }
  633. $.twAjax({
  634. url: listUrl[0] // so that we don't end up in farm assistant map
  635. });
  636. if (reportsLeft === 0) {
  637. $('#request_data h4').text("Ready! (read " + totalReports + " reports)");
  638. $('#load_new_reports').removeClass('btn-disabled').prop('disabled', false);
  639. }
  640. }
  641.  
  642. var handleReport = function(result) {
  643. let reportHolder = $(result);
  644. let coords = reportHolder.find('span.quickedit-label').text().trim().match(/\d{1,3}\|\d{1,3}/g);
  645. coords = coords[coords.length - 1];
  646.  
  647. // arrival time
  648. let arrival = reportHolder.find('.small.grey').parent().text().trim().split(" ");
  649. arrival[0] = arrival[0].split(".").reverse().join("-"); //fixes date
  650. arrival[1] = arrival[1].replace(/:([^:]*)$/, "." + '$1'); //fixes time (replace last : with .)
  651. arrival = new Date("20" + arrival[0] + "T" + arrival[1] + "Z"); // sets the date
  652.  
  653. if (data[coords] && data[coords].scoutBuilding && arrival.getTime() <= data[coords].scoutBuilding.getTime()) {
  654. // if we have already scouted the buildings here and this report is older than our most recent building reports
  655. // we have nothing to gain from it, so we can ignore it
  656. console.debug("Skipping " + coords + " because we have fresher building data. Current: " + arrival.toUTCString() + ", in db: " + data[coords].scoutBuilding.toUTCString());
  657. return;
  658. }
  659.  
  660. // luck
  661. let luck = parseFloat(reportHolder.find('.nobg b').text().trim().replace("%", ""));
  662.  
  663. // report id
  664. let reportId = reportHolder.find('th span.quickedit').data('id');
  665.  
  666. // dots
  667. let dots = reportHolder.find('.vis th img').eq(4).attr('src').match(/dots\/(.+)\.png/)[1];
  668.  
  669. // send from
  670. let sentFromId = parseInt(reportHolder.find('[data-id].village_anchor').eq(0).attr('data-id'));
  671. let villageId = parseInt(reportHolder.find('[data-id].village_anchor').eq(1).attr('data-id'));
  672. let sentFromCoords = reportHolder.find('[data-id].village_anchor').eq(0).text().trim().match(/\d{1,3}\|\d{1,3}/g);
  673. sentFromCoords = sentFromCoords[sentFromCoords.length - 1];
  674.  
  675. // units send and lost
  676. let unitsSent = {};
  677. let unitsDied = {};
  678. for (let i in unitTypes) { // i is a string, wtf
  679. unitsSent[unitTypes[i]] = parseInt(reportHolder.find('#attack_info_att_units .unit-item').eq(i).text().trim());
  680. unitsDied[unitTypes[i]] = parseInt(reportHolder.find('#attack_info_att_units .unit-item').eq(unitTypes.length + parseInt(i)).text().trim());
  681. if (isNaN(unitsDied[unitTypes[i]])) {
  682. unitsDied[unitTypes[i]] = -1;
  683. }
  684. }
  685.  
  686. // is player
  687. let isPlayer = reportHolder.find('#attack_info_def th').eq(1).text().trim() !== "---";
  688. let playerName = reportHolder.find('#attack_info_def th').eq(1).text().trim();
  689. let playerId = isPlayer ? reportHolder.find('#attack_info_def th a').attr('href').match(/id=(\d+)/)[1] : null;
  690.  
  691. let enemyHome = null;
  692. let enemyDied = null;
  693.  
  694. // if atleast on troop survived, we have data on their troops
  695. for (let i in unitsSent) {
  696. if (unitsSent[i] != unitsDied[i]) {
  697. // we have at least one surviving troop
  698. // instantiate objects
  699. enemyHome = {};
  700. enemyDied = {};
  701.  
  702. // parse their units
  703. // this ignores militia
  704. for (let i in unitTypes) { // i is a string, wtf
  705. enemyHome[unitTypes[i]] = parseInt(reportHolder.find('#attack_info_def_units .unit-item').eq(i).text().trim());
  706. // note the length + 1 (because we ignore the mob)
  707. enemyDied[unitTypes[i]] = parseInt(reportHolder.find('#attack_info_def_units .unit-item').eq(unitTypes.length + 1 + parseInt(i)).text().trim());
  708. if (isNaN(enemyDied[unitTypes[i]])) {
  709. enemyDied[unitTypes[i]] = -1;
  710. }
  711. }
  712. break;
  713. }
  714. }
  715.  
  716. // results
  717. let resTaken = reportHolder.find('#attack_results tr td').eq(1).text().trim().split("/");
  718. let maxResTaken = parseInt(resTaken[1]);
  719. resTaken = parseInt(resTaken[0]);
  720. // keep track of what level we scouted
  721. let scoutLevel = 0;
  722. // res left (if no data == null)
  723. let resLeft = null;
  724. // buildings scouted (no data -> null)
  725. let buildingData = null;
  726. // troops outside village
  727. let enemyAway = null;
  728. // scout info
  729. if (reportHolder.find("#attack_spy_resources").length > 0) {
  730. // we have scouted resources
  731. scoutLevel = 1;
  732. let resArray = reportHolder.find('#attack_spy_resources tr:first .nowrap').text().trim().split(" ");
  733. for (let i in resArray) {
  734. let p = parseInt(resArray[i].replace(".", ""));
  735. if (!isNaN(p)) {
  736. resLeft += p;
  737. }
  738. }
  739. } else if (resTaken < maxResTaken) {
  740. // if we didnt have full haul we can assume no res left
  741. resLeft = 0;
  742. } else {
  743. // if we did have full haul we have no info, so signify with -1
  744. resLeft = -1;
  745. }
  746. if (reportHolder.find('#attack_spy_building_data').length > 0) {
  747. // we have scouted buildings
  748. scoutLevel = 2;
  749. // init buildingData
  750. buildingData = {};
  751. // parse them to array
  752. let parsedData = JSON.parse(reportHolder.find('#attack_spy_building_data').val());
  753. // parse them in a new array
  754. for (let i in parsedData) {
  755. // for all data that we have, store them in buildingdata as building:level
  756. buildingData[parsedData[i].id] = parseInt(parsedData[i].level);
  757. }
  758. // then run over all buildings and set them to 0 if they don't exist yet
  759. for (let i in buildingTypes) {
  760. if (buildingData[buildingTypes[i]] == undefined) {
  761. buildingData[buildingTypes[i]] = 0;
  762. }
  763. }
  764. }
  765. if (reportHolder.find('#attack_spy_away').length > 0) {
  766. // we have data on troops away
  767. scoutLevel = 3;
  768. // init enemy away
  769. enemyAway = {};
  770. for (let i in unitTypes) { // i is a string, wtf
  771. enemyAway[unitTypes[i]] = parseInt(reportHolder.find('#attack_spy_away .unit-item').eq(i).text().trim());
  772. }
  773. }
  774.  
  775. // we have interpreted all there is,
  776. // now store it
  777.  
  778. // first retrieve the old report (to overwrite it)
  779. let report = {};
  780. if (data[coords]) {
  781. report = data[coords];
  782. }
  783. report['playerId'] = playerId;
  784. report['reportId'] = reportId;
  785. report['playerName'] = playerName;
  786. report['villageId'] = villageId;
  787. report['dots'] = dots;
  788. report['coords'] = coords;
  789. report['lastAttack'] = arrival;
  790. report['luck'] = luck;
  791. report['sentFromId'] = sentFromId;
  792. report['sentFromCoords'] = sentFromCoords;
  793. report['isPlayer'] = isPlayer;
  794. report['unitsSent'] = unitsSent;
  795. report['unitsDied'] = unitsDied;
  796. if (enemyHome) {
  797. report['enemyHome'] = enemyHome;
  798. report['enemyDied'] = enemyDied;
  799. }
  800. // do not save resTaken and maxResTaken because we can infer all we need to know from resLeft
  801. //report['resTaken'] = resTaken;
  802. //report['maxResTaken'] = maxResTaken;
  803. report['fullHaul'] = resTaken == maxResTaken;
  804. report['resLeft'] = resLeft; //-1 signifies no data
  805. if (buildingData) {
  806. report['buildingData'] = buildingData;
  807. }
  808. if (enemyAway) {
  809. report['enemyAway'] = enemyAway;
  810. }
  811.  
  812. // store when the last scout was
  813. if (scoutLevel) {
  814. if (scoutLevel >= 1) {
  815. report['scoutRes'] = arrival;
  816. }
  817. if (scoutLevel >= 2) {
  818. report['scoutBuilding'] = arrival;
  819. }
  820. if (scoutLevel >= 3) {
  821. report['scoutAway'] = arrival;
  822. }
  823. }
  824.  
  825. // store to data object
  826. data[coords] = report;
  827.  
  828. // store in localstorage
  829. localStorage.setItem(game_data.world + "_sadye_rep_data", JSON.stringify(data));
  830. console.debug(report);
  831. }
  832.  
  833. var getMaxPages = function(result) {
  834. let t = $(result).find('.paged-nav-item:last');
  835. if (t && t.length > 0) {
  836. // found atleast one page
  837. t = t.text().trim(); //yields "[xx]"
  838. t = parseInt(t.substring(1, t.length - 1));
  839. } else {
  840. // no extra pages found
  841. t = 1;
  842. }
  843. return t;
  844. }
  845.  
  846. }
  847.  
  848. var getServerTime = function(result) {
  849. let serverTime = $(result).find('#serverTime').text().split(":"); //[7; 14; 05] for example
  850. serverTime[0] = parseInt(serverTime[0]) < 10 ? "0" + serverTime[0] : serverTime[0];
  851. let serverDate = $(result).find('#serverDate').text().split("/").reverse().join("-");
  852. return new Date(serverDate + "T" + serverTime.join(":") + "Z");
  853. }
  854.  
  855. var getResPerHour = function(level) {
  856. if (level == 0) {
  857. return 5;
  858. }
  859. return settings.worldSpeed * 30 * Math.pow(1.163118, level - 1);
  860. }
  861.  
  862. var getDistance = function(opp, me) {
  863. let a = opp.split("|");
  864. let b = me.split("|");
  865. return Math.sqrt((a[0] - b[0]) * (a[0] - b[0]) + (a[1] - b[1]) * (a[1] - b[1]));
  866. }
  867. var getMaxStorage = function(level) {
  868. return Math.round(1000 * Math.pow(1.2294934, (level - 1)));
  869. }
  870. var getMaxHiding = function(level) {
  871. return Math.round(150 * Math.pow((4 / 3), (level - 1)));
  872. }
  873.  
  874. var retrieveOldReports = function() {
  875. let tempReports = JSON.parse(localStorage.getItem(game_data.world + "_sadye_rep_data"));
  876. console.log(tempReports);
  877. if (tempReports) {
  878. // parse dates as objects
  879. for (let i in tempReports) {
  880. if (tempReports[i].scoutRes) {
  881. tempReports[i].scoutRes = new Date(tempReports[i].scoutRes);
  882. }
  883. if (tempReports[i].scoutBuilding) {
  884. tempReports[i].scoutBuilding = new Date(tempReports[i].scoutBuilding);
  885. }
  886. if (tempReports[i].scoutAway) {
  887. tempReports[i].scoutAway = new Date(tempReports[i].scoutAway);
  888. }
  889. if (tempReports[i].lastAttack) {
  890. tempReports[i].lastAttack = new Date(tempReports[i].lastAttack);
  891. }
  892.  
  893. }
  894. console.log("Reports succesfully loaded.");
  895. data = tempReports;
  896. } else {
  897. console.warn("Failed to load reports. Maybe none yet?");
  898. }
  899. }
  900.  
  901. init();
Advertisement
Add Comment
Please, Sign In to add comment
Advertisement