LWMActivityTracker

This script tracks your daily activities by monitoring experience, guilds, and faction points

  1. // ==UserScript==
  2. // @name LWMActivityTracker
  3. // @author Theatre Of Pain (http://www.lordswm.com/pl_info.php?id=4821925)
  4. // @version 2.0.161216
  5. // @description This script tracks your daily activities by monitoring experience, guilds, and faction points
  6. // @include http://www.lordswm.com/home.php
  7. // @grant GM_getValue
  8. // @grant GM_setValue
  9. // @grant GM_log
  10. // @namespace https://greasyfork.org/users/86247
  11. // ==/UserScript==
  12.  
  13. var debug = false; //turn to true to display debug messages in the error console
  14.  
  15. const COMPARTMENT_SIZE = 7; // grouping per date
  16. const MAX_COMPARTMENTS = 8; // maximum number of groups
  17. const GRAPH_RECORDS = COMPARTMENT_SIZE * MAX_COMPARTMENTS; // number of tracker records
  18. const GRAPH_COLOR = 'blue';
  19. const INVERT_GRAPH_COLOR = 'orange';
  20. const LIGHT_BG = '#FFFFFF';
  21. const DARK_BG = '#DDD9CD';
  22. const DATESTAMP_SIZE = 8;
  23.  
  24. const EXPERIENCE_RECORD = 26;
  25. const DATESTAMP = 0;
  26. const EXP = 1;
  27. const FSP = 2;
  28. const KNIGHT = 3;
  29. const NECRO = 4;
  30. const WIZARD = 5;
  31. const ELF = 6;
  32. const BARBARIAN = 7;
  33. const DARK_ELF = 8;
  34. const DEMON = 9;
  35. const DWARF = 10;
  36. const TRIBAL = 11;
  37. const XX = 12; // reserved for future expansion
  38. const YY = 13; // reserved for future expansion
  39. const ZZ = 14; // reserved for future expansion
  40. const HG = 15;
  41. const LG = 16;
  42. const GG = 17;
  43. const TG = 18;
  44. const MG = 19;
  45. const CG = 20;
  46. const SG = 21;
  47. const EG = 22;
  48. const RG = 23;
  49. const WG = 24;
  50. const AG = 25;
  51.  
  52. // list labels
  53. const EXP_L = 'Experience';
  54. const FSP_L = 'Faction Skill Points';
  55. const KNIGHT_L = 'Knight FSP';
  56. const NECRO_L = 'Necromancer FSP';
  57. const WIZARD_L = 'Wizard FSP';
  58. const ELF_L = 'Elf FSP';
  59. const BARBARIAN_L = 'Barbarian FSP';
  60. const DARK_ELF_L = 'Dark Elf FSP';
  61. const DEMON_L = 'Demon FSP';
  62. const DWARF_L = 'Dwarf FSP';
  63. const TRIBAL_L = 'Tribal FSP';
  64. const XX_L = '- Reserved for future expansion -';
  65. const YY_L = '- Reserved for future expansion -';
  66. const ZZ_L = '- Reserved for future expansion -';
  67. const HG_L = 'Hunters\' guild';
  68. const LG_L = 'Laborers\' guild';
  69. const GG_L = 'Gamblers\' guild';
  70. const TG_L = 'Thieves\' guild';
  71. const RG_L = 'Rangers\' guild';
  72. const MG_L = 'Mercenaries\' guild';
  73. const CG_L = 'Commanders\' guild';
  74. const SG_L = 'Smiths\' guild';
  75. const EG_L = 'Enchanters\' guild';
  76. const WG_L = 'Watchers\' guild';
  77. const AG_L = 'Adventurers\' guild';
  78.  
  79. // graph labels
  80. var labels = new Array();
  81. labels[DATESTAMP] = 'Date';
  82. labels[EXP] = 'Experience';
  83. labels[FSP] = 'Total FSP';
  84. labels[KNIGHT] = 'Knight';
  85. labels[NECRO] = 'Necromancer';
  86. labels[WIZARD] = 'Wizard';
  87. labels[ELF] = 'Elf';
  88. labels[BARBARIAN] = 'Barbarian';
  89. labels[DARK_ELF] = 'Dark Elf';
  90. labels[DEMON] = 'Demon';
  91. labels[DWARF] = 'Dwarf';
  92. labels[TRIBAL] = 'Tribal';
  93. labels[XX] = 'RESERVED';
  94. labels[YY] = 'RESERVED';
  95. labels[ZZ] = 'RESERVED';
  96. labels[HG] = 'HG';
  97. labels[LG] = 'LG';
  98. labels[GG] = 'GG';
  99. labels[TG] = 'TG';
  100. labels[RG] = 'RG';
  101. labels[MG] = 'MG';
  102. labels[CG] = 'CG';
  103. labels[SG] = 'SG';
  104. labels[EG] = 'EG';
  105. labels[WG] = 'WG';
  106. labels[AG] = 'AG';
  107.  
  108. var experience = new Array();
  109. var tracker = new Array();
  110. var experience_record = new Array(EXPERIENCE_RECORD);
  111. var graph_width = 100;
  112. var empty_cell_size = 3;
  113. var date_cell_width = 60;
  114. var graph_div, backup_div, options_div;
  115. var graph;
  116. var select;
  117. var player_name;
  118. var server_name;
  119.  
  120. main();
  121.  
  122. function main() {
  123. getPlayerAndServer();
  124. getExperienceData();
  125. experience_record = getExperienceRecord();
  126. createExperienceRecord(experience_record);
  127. setExperienceData();
  128. buildTracker();
  129. tooltipStyle();
  130. displayTracker();
  131. }
  132.  
  133. function getPlayerAndServer() {
  134. var all_params = document.getElementsByTagName('param');
  135. for (var i = 0; i < all_params.length; i++) {
  136. if (all_params[i].name == 'FlashVars') {
  137. player_name = all_params[i].value.split('|')[3];
  138. break;
  139. }
  140. }
  141.  
  142. if (location.href.indexOf('.com') != -1) {
  143. server_name = '.com';
  144. } else {
  145. server_name = '.ru';
  146. }
  147.  
  148. if (debug) {GM_log(
  149. 'Server name = ' + server_name +
  150. '\nPlayer name = ' + player_name
  151. )}
  152.  
  153. }
  154.  
  155. function getExperienceData() {
  156. var temp_data;
  157.  
  158. // migrate earlier version that didn't store experience by player name
  159. temp_data = GM_getValue('Experience', -1);
  160. if (temp_data != -1) {
  161. GM_setValue(player_name + server_name + ' Experience', temp_data);
  162. GM_deleteValue('Experience');
  163. document.cookie = 'ActivityTrackerBackup=0;expires=' + new Date('1999');
  164. }
  165.  
  166. temp_data = GM_getValue(player_name + server_name + ' Experience', -1);
  167. if (temp_data != -1) {
  168. experience = temp_data.split(',');
  169. // migrate earlier version that didn't store watchers and adventurers data
  170. if (experience[0].split('#').length != EXPERIENCE_RECORD) {
  171. var experience_record = new Array(EXPERIENCE_RECORD);
  172. for (var x = 0; x < experience.length; x++) {
  173. experience[x] = experience[x] + '#0#0';
  174. }
  175. document.cookie = player_name + server_name + 'ActivityTrackerBackup=0'
  176. + ';expires=' + new Date('1999');
  177. } else {
  178. var backup_data = getCookie(player_name + server_name + 'ActivityTrackerBackup');
  179. if (backup_data != 0) {
  180. var backup_array = backup_data.split(',');
  181. for (var z = 0; z < backup_array.length; z++) {
  182. var updated = false;
  183. for (var y = 0; y < experience.length; y++) {
  184. if (experience[y].substring(0,DATESTAMP_SIZE) == backup_array[z].substring(0,DATESTAMP_SIZE)) {
  185. experience[y] = backup_array[z];
  186. updated = true;
  187. }
  188. }
  189. if (!updated) {
  190. experience.push(backup_array[z]);
  191. }
  192. }
  193. experience.sort();
  194. experience.reverse();
  195. }
  196. }
  197. } else {
  198. experience = new Array();
  199. }
  200. }
  201.  
  202. // this function returns the value of a stored cookie
  203. function getCookie(cookie_key) {
  204. var i,x,y,ARRcookies=document.cookie.split(';');
  205. for (i=0;i<ARRcookies.length;i++) {
  206. x=ARRcookies[i].substr(0,ARRcookies[i].indexOf('='));
  207. y=ARRcookies[i].substr(ARRcookies[i].indexOf('=')+1);
  208. x=x.replace(/^\s+|\s+$/g,'');
  209. if (x==cookie_key) {
  210. return unescape(y);
  211. }
  212. }
  213. return 0;
  214. }
  215.  
  216. function setExperienceData() {
  217. experience.sort();
  218. experience.reverse();
  219. GM_setValue(player_name + server_name + ' Experience', experience.toString());
  220.  
  221. // keep last n days of data as cookie to recover from broswer crashes
  222. // n is determined by COMPARTMENT_SIZE
  223. var backup_data = new Array();
  224. var days_to_keep;
  225. (experience.length > COMPARTMENT_SIZE) ? (days_to_keep = COMPARTMENT_SIZE) : (days_to_keep = experience.length);
  226. var z = 0;
  227. while (z < days_to_keep) {
  228. backup_data.push(experience[z]);
  229. z++;
  230. }
  231. document.cookie = player_name + server_name + 'ActivityTrackerBackup=' + backup_data.toString()
  232. + ';expires=' + new Date('2050');
  233. }
  234.  
  235. function createExperienceRecord(passed_experience_record) {
  236. new_record = passed_experience_record.toString().replace(/,/g,'#');
  237. for (var z = 0; z < experience.length; z++) {
  238. if (experience[z].substring(0,DATESTAMP_SIZE) == new_record.substring(0,DATESTAMP_SIZE)) {
  239. if (experience[z] != new_record) {
  240. experience[z] = new_record;
  241. }
  242. return;
  243. }
  244. }
  245. if (experience.length == 0) {
  246. var first_record = (parseInt(new_record.substring(0,DATESTAMP_SIZE)) - 1) + new_record.substring(DATESTAMP_SIZE);
  247. experience.push(first_record);
  248. }
  249. experience.push(new_record);
  250. }
  251.  
  252. // parse experience, faction, and guild points and return as an array
  253. function getExperienceRecord() {
  254. var all_tables = document.getElementsByTagName('table');
  255. var main_table;
  256. var matched;
  257. var combat_level;
  258. var experience_td, faction_td;
  259. var faction_array = new Array();
  260. var temp_experience_record = new Array(EXPERIENCE_RECORD);
  261. for (var i = 0; i < all_tables.length; i++) {
  262. if ((all_tables[i].innerHTML.indexOf('Combat level') != -1)
  263. && (all_tables[i].innerHTML.indexOf('Necromancer') != -1)
  264. && (all_tables[i].innerHTML.indexOf('Laborers') != -1)) {
  265. main_table = all_tables[i];
  266. }
  267. }
  268.  
  269. var all_tds = main_table.getElementsByTagName('td');
  270. for (var i = 0; i < all_tds.length; i++) {
  271. if ((all_tds[i].innerHTML.indexOf('Necromancer') != -1)
  272. && (all_tds[i].innerHTML.indexOf('Laborers') != -1)) {
  273. faction_td = all_tds[i];
  274. }
  275. if (all_tds[i].innerHTML.indexOf('Combat level') != -1) {
  276. experience_td = all_tds[i];
  277. }
  278. }
  279.  
  280. matched = experience_td.innerHTML.replace(/,/g, '').match(/\((\d*)\)/);
  281. temp_experience_record[EXP] = RegExp.$1;
  282.  
  283. faction_array = faction_td.innerHTML.split('&nbsp;&nbsp;');
  284.  
  285. for (var i = 0; i < faction_array.length; i++) {
  286. // faction points
  287. matched = faction_array[i].match(/Knight: (\d*)/);
  288. if (matched != null) {
  289. matched = faction_array[i].match(/\((\d*.\d*)\)/);
  290. temp_experience_record[KNIGHT] = RegExp.$1;
  291. }
  292. matched = faction_array[i].match(/Necromancer: (\d*)/);
  293. if (matched != null) {
  294. matched = faction_array[i].match(/\((\d*.\d*)\)/);
  295. temp_experience_record[NECRO] = RegExp.$1;
  296. }
  297. matched = faction_array[i].match(/Wizard: (\d*)/);
  298. if (matched != null) {
  299. matched = faction_array[i].match(/\((\d*.\d*)\)/);
  300. temp_experience_record[WIZARD] = RegExp.$1;
  301. }
  302. matched = faction_array[i].match(/Elf: (\d*)/);
  303. if (matched != null) {
  304. matched = faction_array[i].match(/\((\d*.\d*)\)/);
  305. temp_experience_record[ELF] = RegExp.$1;
  306. }
  307. matched = faction_array[i].match(/Barbarian: (\d*)/);
  308. if (matched != null) {
  309. matched = faction_array[i].match(/\((\d*.\d*)\)/);
  310. temp_experience_record[BARBARIAN] = RegExp.$1;
  311. }
  312. matched = faction_array[i].match(/Dark elf: (\d*)/);
  313. if (matched != null) {
  314. matched = faction_array[i].match(/\((\d*.\d*)\)/);
  315. temp_experience_record[DARK_ELF] = RegExp.$1;
  316. }
  317. matched = faction_array[i].match(/Demon: (\d*)/);
  318. if (matched != null) {
  319. matched = faction_array[i].match(/\((\d*.\d*)\)/);
  320. temp_experience_record[DEMON] = RegExp.$1;
  321. }
  322. matched = faction_array[i].match(/Dwarf: (\d*)/);
  323. if (matched != null) {
  324. matched = faction_array[i].match(/\((\d*.\d*)\)/);
  325. temp_experience_record[DWARF] = RegExp.$1;
  326. }
  327. matched = faction_array[i].match(/Tribal: (\d*)/);
  328. if (matched != null) {
  329. matched = faction_array[i].match(/\((\d*.\d*)\)/);
  330. temp_experience_record[TRIBAL] = RegExp.$1;
  331. }
  332.  
  333. //guilds
  334. matched = faction_array[i].match(/Hunters' guild:/);
  335. if (matched != null) {
  336. matched = faction_array[i].match(/\((\d*.\d*)\)/);
  337. temp_experience_record[HG] = RegExp.$1;
  338. }
  339. matched = faction_array[i].match(/Laborers' guild: (\d*)/);
  340. if (matched != null) {
  341. matched = faction_array[i].match(/\((\d*.\d*)\)/);
  342. temp_experience_record[LG] = RegExp.$1;
  343. }
  344. matched = faction_array[i].match(/Gamblers' guild: (\d*)/);
  345. if (matched != null) {
  346. matched = faction_array[i].match(/\((\d*.\d*)\)/);
  347. temp_experience_record[GG] = RegExp.$1;
  348. }
  349. matched = faction_array[i].match(/Thieves' guild: (\d*)/);
  350. if (matched != null) {
  351. matched = faction_array[i].match(/\((\d*.\d*)\)/);
  352. temp_experience_record[TG] = RegExp.$1;
  353. }
  354. matched = faction_array[i].match(/Rangers' Guild: (\d*)/);
  355. if (matched != null) {
  356. matched = faction_array[i].match(/\((\d*.\d*)\)/);
  357. temp_experience_record[RG] = RegExp.$1;
  358. }
  359. matched = faction_array[i].match(/Mercenaries' guild: (\d*)/);
  360. if (matched != null) {
  361. matched = faction_array[i].match(/\((\d*.\d*)\)/);
  362. temp_experience_record[MG] = RegExp.$1;
  363. }
  364. matched = faction_array[i].match(/Commanders' guild: (\d*)/);
  365. if (matched != null) {
  366. matched = faction_array[i].match(/\((\d*.\d*)\)/);
  367. temp_experience_record[CG] = RegExp.$1;
  368. }
  369. matched = faction_array[i].match(/Smiths' guild: (\d*)/);
  370. if (matched != null) {
  371. matched = faction_array[i].match(/\((\d*.\d*)\)/);
  372. temp_experience_record[SG] = RegExp.$1;
  373. }
  374. matched = faction_array[i].match(/Watchers' guild: (\d*)/);
  375. if (matched != null) {
  376. matched = faction_array[i].match(/\((\d*.\d*)\)/);
  377. temp_experience_record[WG] = RegExp.$1;
  378. }
  379. matched = faction_array[i].match(/Adventurers' guild: (\d*)/);
  380. if (matched != null) {
  381. matched = faction_array[i].match(/\((\d*.\d*)\)/);
  382. temp_experience_record[AG] = RegExp.$1;
  383. }
  384. }
  385.  
  386. matched = document.getElementById('home_2').innerHTML.match(/\((\d*.\d*)\)/);
  387. temp_experience_record[EG] = RegExp.$1;
  388.  
  389. var localDate = new Date();
  390. var utcDate = localDate.getTime() + (localDate.getTimezoneOffset() * 60000); //in ms
  391. var serverDate = new Date(utcDate + (3600000*4)); //GMT+4
  392.  
  393. var year = serverDate.getFullYear();
  394. var month = serverDate.getMonth() + 1;
  395. if (month.toString().length == 1) {
  396. month = '0' + month;
  397. }
  398. var day = serverDate.getDate();
  399. if (day.toString().length == 1) {
  400. day = '0' + day;
  401. }
  402. temp_experience_record[DATESTAMP] = '' + year + month + day;
  403. temp_experience_record[FSP] = roundNumber((parseFloat(temp_experience_record[KNIGHT])
  404. + parseFloat(temp_experience_record[NECRO])
  405. + parseFloat(temp_experience_record[WIZARD])
  406. + parseFloat(temp_experience_record[ELF])
  407. + parseFloat(temp_experience_record[BARBARIAN])
  408. + parseFloat(temp_experience_record[DARK_ELF])
  409. + parseFloat(temp_experience_record[DEMON])
  410. + parseFloat(temp_experience_record[DWARF])
  411. + parseFloat(temp_experience_record[TRIBAL])), 2);
  412.  
  413. temp_experience_record[XX] = 0;
  414. temp_experience_record[YY] = 0;
  415. temp_experience_record[ZZ] = 0;
  416.  
  417. if (debug) {GM_log(
  418. '\nServer timestamp = ' + serverDate +
  419. '\n\nKnight FSP = ' + temp_experience_record[KNIGHT] +
  420. '\nNecromancer FSP = ' + temp_experience_record[NECRO] +
  421. '\nWizard FSP = ' + temp_experience_record[WIZARD] +
  422. '\nElf FSP = ' + temp_experience_record[ELF] +
  423. '\nBarbarian FSP = ' + temp_experience_record[BARBARIAN] +
  424. '\nDark elf FSP = ' + temp_experience_record[DARK_ELF] +
  425. '\nDemon FSP = ' + temp_experience_record[DEMON] +
  426. '\nDwarf FSP = ' + temp_experience_record[DWARF] +
  427. '\nTribal FSP = ' + temp_experience_record[TRIBAL] +
  428. '\n\n\nHunters\' guild = ' + temp_experience_record[HG] +
  429. '\nLaborers\' guild = ' + temp_experience_record[LG] +
  430. '\nGamblers\' guild = ' + temp_experience_record[GG] +
  431. '\nThieves\' guild = ' + temp_experience_record[TG] +
  432. '\nRangers\' guild = ' + temp_experience_record[RG] +
  433. '\nMercenaries\' guild = ' + temp_experience_record[MG] +
  434. '\nCommanders\' guild = ' + temp_experience_record[CG] +
  435. '\nSmiths\' guild = ' + temp_experience_record[SG] +
  436. '\nWatchers\' guild = ' + temp_experience_record[WG] +
  437. '\nAdventurers\' guild = ' + temp_experience_record[AG]
  438. )}
  439.  
  440. return temp_experience_record;
  441. }
  442.  
  443. function buildTracker() {
  444. var record1, record2;
  445. for (var z = 0; z < experience.length - 1; z++) {
  446. var difference_record = new Array();
  447. record1 = experience[z].split('#');
  448. record2 = experience[z + 1].split('#');
  449. difference_record[DATESTAMP] = record1[DATESTAMP];
  450. for (var y = 1; y < record1.length; y++) {
  451. if (record1[y] != record2[y]) {
  452. difference_record[y] = record1[y] - record2[y];
  453. } else {
  454. difference_record[y] = '';
  455. }
  456. }
  457. tracker.push(difference_record);
  458.  
  459. // no need to track historical data that will not be displayed on the graph
  460. if (tracker.length == GRAPH_RECORDS) {
  461. break;
  462. }
  463. }
  464. }
  465.  
  466. function displayTracker() {
  467. var all_tables = document.getElementsByTagName('tbody');
  468. var main_table;
  469. var experience_td, faction_td;
  470. for (var i = 0; i < all_tables.length; i++) {
  471. if ((all_tables[i].innerHTML.indexOf('Combat level') != -1)
  472. && (all_tables[i].innerHTML.indexOf('Necromancer') != -1)
  473. && (all_tables[i].innerHTML.indexOf('Laborers') != -1)) {
  474. main_table = all_tables[i];
  475. }
  476. }
  477. faction_td = main_table.getElementsByTagName('td')[1];
  478. faction_td.rowSpan = 2;
  479. var tr = document.createElement('tr');
  480. var td = document.createElement('td');
  481. graph_div = document.createElement('div');
  482. graph_div.id = 'graph_div';
  483. td.appendChild(graph_div);
  484.  
  485. select = document.createElement('select');
  486. select.id = 'select';
  487. addOption(select, EXP, EXP_L);
  488. addOption(select, FSP, FSP_L);
  489. addOption(select, KNIGHT, KNIGHT_L);
  490. addOption(select, NECRO, NECRO_L);
  491. addOption(select, WIZARD, WIZARD_L);
  492. addOption(select, ELF, ELF_L);
  493. addOption(select, BARBARIAN, BARBARIAN_L);
  494. addOption(select, DARK_ELF, DARK_ELF_L);
  495. addOption(select, DEMON, DEMON_L);
  496. addOption(select, DWARF, DWARF_L);
  497. addOption(select, TRIBAL, TRIBAL_L);
  498. addOption(select, HG, HG_L);
  499. addOption(select, LG, LG_L);
  500. addOption(select, GG, GG_L);
  501. addOption(select, TG, TG_L);
  502. addOption(select, MG, MG_L);
  503. addOption(select, CG, CG_L);
  504. addOption(select, SG, SG_L);
  505. addOption(select, EG, EG_L);
  506. addOption(select, RG, RG_L);
  507. addOption(select, WG, WG_L);
  508. addOption(select, AG, AG_L);
  509. select.onchange = function() {
  510. if (document.getElementById('graph') != null) {
  511. document.getElementById('graph_div').removeChild(document.getElementById('graph'));
  512. }
  513. GM_setValue('default activity', parseInt(select.options[select.selectedIndex].value));
  514. if(debug) {GM_log('Display tracking for: ' + select.options[select.selectedIndex].text)}
  515. document.getElementById('graph_div').appendChild(getActivityGraph(parseInt(select.options[select.selectedIndex].value)));
  516. }
  517.  
  518. td.insertBefore(document.createElement('br'), td.firstChild);
  519. td.insertBefore(document.createElement('br'), td.firstChild);
  520. td.insertBefore(select, td.firstChild);
  521. var temp_activity = GM_getValue('default activity', -1);
  522. if (temp_activity != -1) {
  523. graph_div.appendChild(getActivityGraph(temp_activity));
  524. for(var i=0; i < select.options.length; i++){
  525. if(select.options[i].value == temp_activity)
  526. select.selectedIndex = i;
  527. }
  528. } else {
  529. GM_setValue('default activity', EXP);
  530. graph_div.appendChild(getActivityGraph(EXP));
  531. }
  532. td.appendChild(createOptionsDiv());
  533. tr.appendChild(td);
  534. main_table.appendChild(tr);
  535.  
  536. function addOption(optionList, value, text) {
  537. var option;
  538. option = document.createElement('option');
  539. option.value = value;
  540. option.text = text;
  541. optionList.appendChild(option);
  542. }
  543. }
  544.  
  545. function createOptionsDiv(){
  546. options_div = document.createElement('div');
  547. var button_div = document.createElement('div');
  548. options_div.appendChild(button_div);
  549. var el = document.createElement('input');
  550. el.type = 'button';
  551. el.addEventListener('click', backupActivityData, false);
  552. el.setAttribute('value', 'Backup');
  553. button_div.appendChild(el);
  554. el = document.createElement('input');
  555. el.type = 'button';
  556. el.addEventListener('click', updateActivityData, false);
  557. el.setAttribute('value', 'Update');
  558. button_div.appendChild(el);
  559. el = document.createElement('input');
  560. el.type = 'button';
  561. el.addEventListener('click', restoreActivityData, false);
  562. el.setAttribute('value', 'Restore');
  563. button_div.appendChild(el);
  564. button_div.appendChild(document.createElement('br'));
  565. backup_div = document.createElement('div');
  566. backup_div.id = 'activityTrackerDataDiv';
  567. backup_div.style.display = 'none';
  568. options_div.appendChild(backup_div);
  569. backup_div.appendChild(document.createTextNode('Paste modified data below and click Update to update graph or Restore to restore last backup of data'));
  570. el = document.createElement('textarea');
  571. el.id = 'activityTrackerData';
  572. el.style.width = graph_width * empty_cell_size + date_cell_width;
  573. el.style.height = graph_width;
  574. el.style.resize = 'none';
  575. backup_div.appendChild(el);
  576. return options_div;
  577. }
  578.  
  579. function getActivityGraph(activity_type) {
  580. var max_value = 0;
  581. var second_max_value = 0;
  582. var activity_value;
  583. var header_sections = 5;
  584.  
  585. // find maximum value
  586. for (var z = 0; z < tracker.length; z++) {
  587. if (tracker[z][activity_type] > max_value) {
  588. second_max_value = max_value;
  589. max_value = tracker[z][activity_type];
  590. } else if (tracker[z][activity_type] > second_max_value) {
  591. second_max_value = tracker[z][activity_type];
  592. }
  593. }
  594. max_value = roundUp(max_value);
  595. second_max_value = roundUp(second_max_value);
  596.  
  597. if (second_max_value != 0) {
  598. // prevent value spikes from distorting the look of the graph
  599. if (max_value/2 > second_max_value) {
  600. max_value = second_max_value;
  601. }
  602. }
  603.  
  604. // graph values
  605. var tr, td;
  606. var bgcolor = DARK_BG;
  607. graph = document.createElement('table');
  608. graph.id = 'graph';
  609. graph.className='wblight';
  610. graph.align = 'center';
  611. graph.border = 0;
  612. graph.cellSpacing = 0;
  613.  
  614. tr = document.createElement('tr');
  615. tr.className = 'wb';
  616. tr.bgColor = DARK_BG;
  617. td = document.createElement('td');
  618. td.width = date_cell_width;
  619. td.className = 'wb';
  620. td.style.fontSize = 8;
  621. td.innerHTML = labels[activity_type].bold();
  622. td.align = 'center';
  623. tr.appendChild(td);
  624.  
  625. if (max_value != 0) {
  626. if (max_value <= 5) {
  627. max_value = 5;
  628. } else if (max_value <=10) {
  629. max_value = 10;
  630. }
  631. for (var z = 0; z < header_sections; z++) {
  632. td = document.createElement('td');
  633. td.className = 'wb';
  634. td.colSpan = graph_width / header_sections;
  635. td.align = 'right';
  636. td.style.fontSize = 8;
  637. td.innerHTML = roundNumber((max_value * (z + 1)) / header_sections , 2);
  638. tr.appendChild(td);
  639. }
  640. } else {
  641. td = document.createElement('td');
  642. td.className = 'wb';
  643. td.colSpan = graph_width;
  644. tr.appendChild(td);
  645. }
  646.  
  647. graph.appendChild(tr);
  648. var line_counter = COMPARTMENT_SIZE;
  649. var class_name = 'wblight';
  650. for (var z = 0; z < lineCount(tracker.length); z++) {
  651. if (z == GRAPH_RECORDS) {
  652. break;
  653. }
  654. tr = document.createElement('tr');
  655. tr.bgColor = GRAPH_COLOR;
  656. tr.onmouseover = invertColor;
  657. tr.onmouseout = restoreColor;
  658. if (line_counter == COMPARTMENT_SIZE) {
  659. line_counter = 0;
  660. td = document.createElement('td');
  661. td.width = date_cell_width;
  662. td.align = 'center';
  663. td.style.fontSize = 8;
  664. if (z < tracker.length) {
  665. td.innerHTML = tracker[z][DATESTAMP].substr(0,4) + '-' + tracker[z][DATESTAMP].substr(4,2) + '-' + tracker[z][DATESTAMP].substr(6,2);
  666. }
  667. (bgcolor == LIGHT_BG) ? bgcolor = DARK_BG : bgcolor = LIGHT_BG;
  668. td.className = 'wb';
  669. td.bgColor = bgcolor;
  670. td.rowSpan = COMPARTMENT_SIZE;
  671. tr.appendChild(td);
  672. tr.style.borderTop = '1px solid black';
  673. }
  674. line_counter++;
  675. if (z < tracker.length) {
  676. activity_value = roundNumber(tracker[z][activity_type]*graph_width/max_value, 0);
  677. if (tracker[z][activity_type] > 0) {
  678. tr.id = tracker[z][DATESTAMP].substr(0,4) + '-' + tracker[z][DATESTAMP].substr(4,2) + '-' + tracker[z][DATESTAMP].substr(6,2) + ':\u00a0\u00a0\u00a0' + roundNumber(tracker[z][activity_type], 2);
  679. }
  680. } else {
  681. activity_value = 0;
  682. }
  683. for (var y = 0; y < graph_width; y++) {
  684. td = document.createElement('td');
  685. td.style.height = empty_cell_size;
  686. td.style.width = empty_cell_size;
  687. activity_value--;
  688. if (activity_value >= 0) {
  689. td.className = 'NormalColor';
  690. } else {
  691. td.bgColor = bgcolor;
  692. }
  693. tr.appendChild(td);
  694. }
  695. graph.appendChild(tr);
  696. }
  697.  
  698. if (tracker.length > COMPARTMENT_SIZE) {
  699. var average_points = getAveragePoints(activity_type);
  700. if (average_points != -1) {
  701. var estimate = provideEstimate(average_points, activity_type);
  702. if (estimate != -1) {
  703. tr = document.createElement('tr');
  704. tr.className = 'wb';
  705. (bgcolor == LIGHT_BG) ? tr.bgColor = DARK_BG : tr.bgColor = LIGHT_BG;
  706. td = document.createElement('td');
  707. td.colSpan = graph_width + 1;
  708. td.className = 'wb';
  709. td.style.fontSize = 8;
  710. td.innerHTML = estimate;
  711. td.align = 'center';
  712. tr.appendChild(td);
  713. graph.appendChild(tr);
  714. }
  715. }
  716. }
  717. return graph;
  718. }
  719.  
  720. function getAveragePoints(activity_type) {
  721. var points_total = 0;
  722. for (var z = 1; z < COMPARTMENT_SIZE + 1; z++) {
  723. if (tracker[z][activity_type] != '') {
  724. points_total += roundNumber(parseFloat(tracker[z][activity_type]), 2);
  725. }
  726. }
  727. if (points_total == 0) {
  728. return -1;
  729. } else {
  730. return roundNumber(points_total / COMPARTMENT_SIZE, 2); //daily average
  731. }
  732. }
  733.  
  734. function provideEstimate(average_points, activity_type) {
  735. //define experience, faction, and guild levels
  736. var combat_lvl = [0,1500,4500,15000,32000,90000,190000,400000,860000,1650000,3000000,
  737. 5000000,8500000,14500000,25000000,43000000,70000000,108000000,
  738. 160000000,230000000,325000000];
  739. var faction_lvl = [20,50,90,160,280,500,900,1600,2900,5300,9600,17300];
  740. var hg_lvl = [16,60,180,400,700,1200,2000,3000,4300,6000,8000,10500];
  741. var lg_lvl = [90,180,360,720,1500,3000,5000,8000,12000,17000,23000,30000,38000,47000,57000];
  742. var gg_lvl = [10,30,60,100,150,210,280,360,450,550,660,800,1000,1300,2000];
  743. var tg_lvl = [50,120,240,400,600,840,1200,2000,3000,4300,6000,8000,10800,14000,17600,21600,26000];
  744. var rg_lvl = [100,240,480,800,1200,1680,2400,4000,6000,8600,12000];
  745. var mg_lvl = [50,120,300,600,1000,1500,2200,3000,4000,5500,7800,11000,14500,18200,22200];
  746. var cg_lvl = [150, 350, 750, 1400,2200,3200,4300,5600,7000,8500];
  747. var sg_lvl = [30,80,165,310,555,970,1680,2885,5770];
  748. var eg_lvl = [104,588,2200,7000,10000];
  749. var wg_lvl = [60,200,450,850,1500];
  750. var working_array = new Array();
  751.  
  752. switch(activity_type) {
  753. case EXP:
  754. working_array = combat_lvl;
  755. break;
  756. case FSP:
  757. return -1;
  758. case KNIGHT:
  759. case NECRO:
  760. case WIZARD:
  761. case ELF:
  762. case BARBARIAN:
  763. case DARK_ELF:
  764. case DEMON:
  765. case DWARF:
  766. case TRIBAL:
  767. working_array = faction_lvl;
  768. break;
  769. case HG:
  770. working_array = hg_lvl;
  771. break;
  772. case LG:
  773. working_array = lg_lvl;
  774. break;
  775. case GG:
  776. working_array = gg_lvl;
  777. break;
  778. case TG:
  779. working_array = tg_lvl;
  780. break;
  781. case RG:
  782. working_array = rg_lvl;
  783. break;
  784. case MG:
  785. working_array = mg_lvl;
  786. break;
  787. case CG:
  788. working_array = cg_lvl;
  789. break;
  790. case SG:
  791. working_array = sg_lvl;
  792. break;
  793. case EG:
  794. working_array = eg_lvl;
  795. break;
  796. case WG:
  797. working_array = wg_lvl;
  798. break;
  799. default:
  800. return -1;
  801. }
  802. var current_points = experience[0].split('#')[activity_type];
  803. if (current_points >= working_array[working_array.length - 1]) { // player has reached the maximum already
  804. return -1;
  805. }
  806. var points_required;
  807. var next_level;
  808. if (current_points < working_array[0]) {
  809. points_required = working_array[0] - current_points;
  810. } else {
  811. for (var x = 0; x < working_array.length; x++) {
  812. if ((current_points >= working_array[x]) && (current_points < working_array[x + 1])) {
  813. points_required = working_array[x + 1] - current_points;
  814. next_level = x + 2;
  815. break;
  816. }
  817. }
  818. }
  819.  
  820. var message = 'In the past ' + COMPARTMENT_SIZE + ' days you averaged ' + average_points + ' per day. ';
  821. message += 'If you maintain your daily average, you will reach ';
  822. message += 'level ' + next_level;
  823. if (roundNumber(points_required / average_points, 0) == 0){
  824. message += ' today.'
  825. } else if (roundNumber(points_required / average_points, 0) == 1){
  826. message += ' tomorrow.'
  827. } else {
  828. message += ' in ' + roundNumber(points_required / average_points, 0) + ' days.';
  829. }
  830. return message;
  831. }
  832.  
  833. function backupActivityData() {
  834. var backup_value = GM_getValue(player_name + server_name + ' Experience Backup', -1);
  835. if (backup_value != -1) {
  836. var backup_value_date = GM_getValue(player_name + server_name + ' Experience Backup Date', -1);
  837. var response = confirm('The script has detected a backup dated:\n' + backup_value_date + '\nIf you proceed, the script will overwrite it.\nAre you sure you want to continue?');
  838. if (!response) {return;}
  839. }
  840. GM_setValue(player_name + server_name + ' Experience Backup', experience.toString());
  841. GM_setValue(player_name + server_name + ' Experience Backup Date', new Date().toString());
  842. backup_div.style.display = 'block';
  843. var header = '';
  844. for (var z = 0; z < labels.length; z++) {
  845. header += labels[z];
  846. if (z < labels.length - 1) {
  847. header += '\t';
  848. }
  849. }
  850. header += '\n';
  851. document.getElementById('activityTrackerData').value = header + experience.toString().replace(/#/g, '\t').replace(/,/g, '\n');
  852. document.getElementById('activityTrackerData').select();
  853. }
  854.  
  855. function updateActivityData() {
  856. if (backup_div.style.display == 'none') {return;}
  857. var temp_data = document.getElementById('activityTrackerData').value.replace(/\t/g, '#').replace(/\n/g, ',');
  858. if (temp_data.substring(temp_data.length - 1) == ',') {temp_data = temp_data.substring(0, temp_data.length - 1);}
  859. var temp_array = new Array();
  860. temp_array = temp_data.split(',');
  861. for (var z = 1; z < temp_array.length; z++) {
  862. var temp_record = temp_array[z].split('#');
  863. for (var y = 0; y < temp_record.length; y++) {
  864. if (!isNumber(temp_record[y])) {
  865. alert('Encountered an invalid value: ' + temp_record[y] + '\nFound in Row: ' + z + ' Col: ' + (y + 1) + '\nPlease correct the value and try again.');
  866. return;
  867. }
  868. }
  869. }
  870. temp_array.splice(0, 1); // remove column names
  871. experience = temp_array;
  872. setExperienceData();
  873. window.location.reload();
  874. }
  875.  
  876. function restoreActivityData() {
  877. var backup_value = GM_getValue(player_name + server_name + ' Experience Backup', -1);
  878. if (backup_value != -1) {
  879. var backup_value_date = GM_getValue(player_name + server_name + ' Experience Backup Date', -1);
  880. var response = confirm('The script has detected a backup dated:\n' + backup_value_date + '\nIf you proceed, the script will replace current data with this backup.\nAre you sure you want to continue?');
  881. if (!response) {return;}
  882. experience = backup_value.split(',');
  883. setExperienceData();
  884. window.location.reload();
  885. } else {
  886. alert('The script didn\'t find any backup to restore.');
  887. }
  888. }
  889.  
  890. function invertColor() {
  891. if (this.id) {
  892. this.bgColor = INVERT_GRAPH_COLOR;
  893. tooltip.show(this.id);
  894. }
  895. }
  896.  
  897. function restoreColor() {
  898. if (this.id) {
  899. this.bgColor = GRAPH_COLOR;
  900. tooltip.hide();
  901. }
  902. }
  903.  
  904. function roundNumber(unrounded_number, decimals) {
  905. var rounded_number = Math.round(unrounded_number*Math.pow(10,decimals))/Math.pow(10,decimals);
  906. return rounded_number;
  907. }
  908.  
  909. function roundUp(unrounded_number){
  910. var float_number, int_number, rounded_number, without_round_up;
  911. if (parseInt(unrounded_number) != unrounded_number) { //float
  912. if (roundNumber(unrounded_number, 0) != roundNumber(unrounded_number + 0.5, 0)) { //need to prevent rounding down
  913. unrounded_number += 0.5;
  914. }
  915. }
  916. unrounded_number = roundNumber(unrounded_number, 0);
  917. rounded_number = (parseInt(unrounded_number.toString().substring(0,1)) + 1);
  918. without_round_up = parseInt(unrounded_number.toString().substring(0,1));
  919. for (var z = 1; z < unrounded_number.toString().length; z++) {
  920. rounded_number *= 10;
  921. without_round_up *= 10;
  922. }
  923. return (without_round_up == unrounded_number) ? without_round_up : rounded_number;
  924. }
  925.  
  926. function isNumber(n) {
  927. return !isNaN(parseFloat(n)) && isFinite(n);
  928. }
  929.  
  930. function lineCount(data_lines) {
  931. return (data_lines < COMPARTMENT_SIZE) ? COMPARTMENT_SIZE : Math.ceil(parseInt(data_lines)/COMPARTMENT_SIZE)*COMPARTMENT_SIZE;
  932. }
  933.  
  934. function tooltipStyle() {
  935. var style = document.createElement('style');
  936. style.type = 'text/css';
  937. style.innerHTML = '#tt { position:absolute; display:block;}';
  938. style.innerHTML += '#ttcont { display:block; padding:2px 12px 3px 7px; margin-left:5px; background:#666; color:#fff; }';
  939. document.body.appendChild(style);
  940. }
  941.  
  942. var tooltip = function(){
  943. var id = 'tt';
  944. var top = 3;
  945. var left = 3;
  946. var speed = 10;
  947. var timer = 20;
  948. var endalpha = 95;
  949. var alpha = 0;
  950. var tt,t,c,b,h;
  951. return{
  952. show:function(v,w){
  953. if(tt == null){
  954. tt = document.createElement('div');
  955. tt.setAttribute('id',id);
  956. c = document.createElement('div');
  957. c.setAttribute('id',id + 'cont');
  958. tt.appendChild(c);
  959. document.body.appendChild(tt);
  960. tt.style.opacity = 0;
  961. tt.style.filter = 'alpha(opacity=0)';
  962. document.onmousemove = this.pos;
  963. }
  964. tt.style.display = 'block';
  965. c.innerHTML = v;
  966. tt.style.width = v.length * 8;
  967. h = parseInt(tt.offsetHeight) + top;
  968. clearInterval(tt.timer);
  969. tt.timer = setInterval(function(){tooltip.fade(1)},timer);
  970. },
  971. pos:function(e){
  972. var u = e.pageY;
  973. var l = e.pageX;
  974. tt.style.top = (u + 5) + 'px';
  975. tt.style.left = (l + left) + 'px';
  976. },
  977. fade:function(d){
  978. var a = alpha;
  979. if((a != endalpha && d == 1) || (a != 0 && d == -1)){
  980. var i = speed;
  981. if(endalpha - a < speed && d == 1){
  982. i = endalpha - a;
  983. }else if(alpha < speed && d == -1){
  984. i = a;
  985. }
  986. alpha = a + (i * d);
  987. tt.style.opacity = alpha * .01;
  988. tt.style.filter = 'alpha(opacity=' + alpha + ')';
  989. }else{
  990. clearInterval(tt.timer);
  991. if(d == -1){tt.style.display = 'none'}
  992. }
  993. },
  994. hide:function(){
  995. clearInterval(tt.timer);
  996. tt.timer = setInterval(function(){tooltip.fade(-1)},timer);
  997. }
  998. };
  999. }();
  1000.  
  1001. function supportsHTML5Storage() {
  1002. try {
  1003. return 'localStorage' in window && window['localStorage'] !== null;
  1004. } catch (e) {
  1005. if (debug) GM_log('HTML5 Storage is not supported');
  1006. return false;
  1007. }
  1008. }