Harem Heroes++

Adding things here and there in Harem Heroes game.

  1. // ==UserScript==
  2. // @name Harem Heroes++
  3. // @namespace haremheroes.com
  4. // @description Adding things here and there in Harem Heroes game.
  5. // @version 0.05.1
  6. // @match http://nutaku.haremheroes.com/*
  7. // @match https://www.hentaiheroes.com/*
  8. // @match https://www.gayharem.com/*
  9. // @run-at document-end
  10. // @grant none
  11. // @author Raphael
  12. // ==/UserScript==
  13.  
  14. /* ==================
  15. localStorage
  16. ==================
  17. - lsMarket (updated each time you enter the Market / click buttons in Market)
  18. .buyable
  19. .potion.Nb = number of buyable books
  20. .potion.Xp = total xp of buyable books
  21. .potion.Value = cost of buyable books
  22. .gift.Nb = number of owned gifts
  23. .gift.Xp = total affection of buyable gifts
  24. .gift.Value = cost of buyable gifts
  25. .stocks
  26. .armor.Nb = number of owned equipments
  27. .booster.Nb = number of owned boosters
  28. .potion.Nb = number of owned books
  29. .potion.Xp = total xp you can give to your girls
  30. .gift.Nb = number of owned gifts
  31. .gift.Xp = total affection you can give to your girls
  32. .restock
  33. .herolvl = hero level before restock
  34. .time = next market restock time
  35. ================== */
  36.  
  37. var CurrentPage = window.location.pathname;
  38.  
  39. // css define
  40. var sheet = (function() {
  41. var style = document.createElement('style');
  42. document.head.appendChild(style);
  43. return style.sheet;
  44. })();
  45.  
  46. // verify localstorage
  47. var lsAvailable = (lsTest() === true) ? 'yes' : 'no';
  48.  
  49. FightATroll(); // added everywhere
  50. if (CurrentPage.indexOf('shop') != -1) ModifyMarket(); // Current page: Market
  51. else if (CurrentPage.indexOf('harem') != -1) ModifyHarem(); // Current page: Harem
  52. else if (CurrentPage.indexOf('quest') != -1) ModifyScenes(); // Current page: Haremettes' Scenes
  53.  
  54.  
  55. /* ======================
  56. Fight A Troll Menu
  57. ====================== */
  58.  
  59. function FightATroll() {
  60. // Trolls' database
  61. var Trolls = ['Dark Lord', 'Ninja Spy', 'Gruntt', 'Edwarda', 'Donatien', 'Silvanus', 'Bremen', 'Finalmecia'];
  62.  
  63. // get current world of player
  64. var CurrentWorld = Hero.infos.questing.id_world - 1,
  65. TrollName = '',
  66. TrollsMenu = '';
  67.  
  68. // generate troll list
  69. for (var i = 0; i < CurrentWorld; i++) {
  70. if (typeof Trolls[i] !== typeof undefined && Trolls[i] !== false) {
  71. TrollName = Trolls[i];
  72. } else TrollName = 'World ' + (i+1) + ' troll';
  73. TrollsMenu += '<a href="/battle.html?id_troll=' + (i+1) + '">' + TrollName + '</a><br />';
  74. }
  75.  
  76. // display: 'Fight a troll' menu
  77. $('#contains_all > header').children('[type=energy_fight]').append('<div id="FightTroll">Fight a Troll<span class="Arrow"></span><div class="TrollsMenu">' + TrollsMenu + '</div></div>');
  78.  
  79. // -----------------
  80. // CSS RULES
  81. // -----------------
  82.  
  83. sheet.insertRule('#FightTroll {'
  84. + 'position: absolute;'
  85. + 'z-index: 99;'
  86. + 'width: 90%;'
  87. + 'margin:21px 0 0 13px;'
  88. + 'border-radius: 8px 10px 10px 8px;'
  89. + 'background: rgba(102,136,153,0.67);'
  90. + 'box-shadow: 0 0 0 1px rgba(255,255,255,0.73);'
  91. + 'text-align: center; }');
  92.  
  93. sheet.insertRule('#FightTroll > .Arrow {'
  94. + 'float:right;'
  95. + 'background-image: url("http://i.harem-battle.club/images/2017/09/19/Fmo.png");'
  96. + 'background-size: 18px 18px;'
  97. + 'background-repeat: no-repeat;'
  98. + 'width: 18px;'
  99. + 'height: 18px; }');
  100.  
  101. sheet.insertRule('#FightTroll > .TrollsMenu {'
  102. + 'position: absolute;'
  103. + 'width: 88%;'
  104. + 'margin-left:6px;'
  105. + 'border-radius: 0px 0 8px 8px;'
  106. + 'background: rgba(102,136,153,0.67);'
  107. + 'line-height: 15px;'
  108. + 'opacity: 0;'
  109. + 'visibility: hidden;'
  110. + 'transition: opacity 400ms, visibility 400ms; }');
  111.  
  112. sheet.insertRule('#FightTroll:hover > .TrollsMenu {'
  113. + 'opacity: 1;'
  114. + 'visibility: visible; }');
  115.  
  116. sheet.insertRule('#FightTroll a {'
  117. + 'color: rgb(255, 255, 255);'
  118. + 'text-decoration: none; }');
  119.  
  120. sheet.insertRule('#FightTroll a:hover {'
  121. + 'color: rgb(255, 247, 204);'
  122. + 'text-decoration: underline; }');
  123. }
  124.  
  125.  
  126. /* ==========
  127. Market
  128. ========== */
  129.  
  130. function ModifyMarket() {
  131. var lsMarket = {};
  132. lsMarket.buyable = {};
  133. lsMarket.stocks = {};
  134. lsMarket.restock = {};
  135.  
  136. setTimeout( function() {
  137. // save time of restock
  138. var RestockTimer = $('#shop > .shop_count > span').text().split(':'),
  139. s = 0, m = 1;
  140. // convert HH:MM:SS or MM:SS or SS to seconds
  141. while (RestockTimer.length > 0) {
  142. s += m * parseInt(RestockTimer.pop(), 10);
  143. m *= 60;
  144. }
  145. lsMarket.restock.herolvl = Hero.infos.level;
  146. lsMarket.restock.time = (new Date()).getTime() + s*1000;
  147.  
  148. // first load
  149. get_buyableStocks('potion');
  150. get_buyableStocks('gift');
  151. equipments_shop(0);
  152. boosters_shop(0);
  153. books_shop(0);
  154. gifts_shop(0);
  155. }, 500 );
  156.  
  157.  
  158. // catch click on Buy, Restock, Equip/Offer or Sell > update tooltip after 500ms
  159. var timer;
  160. $('#shop > button, #inventory > button').click(function() {
  161. var clickedButton = $(this).attr('rel'),
  162. opened_shop = $('#shop').children('.selected');
  163. clearTimeout(timer); // kill previous update
  164. timer = setTimeout( function() {
  165. if (opened_shop.hasClass('armor')) {
  166. equipments_shop(1);
  167. } else if (opened_shop.hasClass('booster')) {
  168. boosters_shop(1);
  169. } else if (opened_shop.hasClass('potion')) {
  170. if (clickedButton == 'buy' || clickedButton == 'shop_reload') get_buyableStocks('potion');
  171. books_shop(1);
  172. } else if (opened_shop.hasClass('gift')) {
  173. if (clickedButton == 'buy' || clickedButton == 'shop_reload') get_buyableStocks('gift');
  174. gifts_shop(1);
  175. }
  176. }, 500 );
  177. });
  178.  
  179. function get_buyableStocks(loc_class) {
  180. // initialize
  181. var itemsNb = 0,
  182. itemsXp = 0,
  183. itemsPrice = 0,
  184. loc = $('#shop').children('.' + loc_class);
  185. // get stats
  186. loc.find('.slot').each(function() {
  187. if ($(this).hasClass('empty')) return false;
  188. var item = $(this).data('d');
  189. itemsNb++;
  190. itemsXp += parseInt(item.value, 10);
  191. itemsPrice += parseInt(item.price, 10);
  192. });
  193. // save
  194. lsMarket.buyable[loc_class] = {'Nb':itemsNb, 'Xp':itemsXp, 'Value':itemsPrice};
  195. }
  196.  
  197. function equipments_shop(update) {
  198. tt_create(update, 'armor', 'EquipmentsTooltip', 'equipments', '');
  199. }
  200. function boosters_shop(update) {
  201. tt_create(update, 'booster', 'BoostersTooltip', 'boosters', '');
  202. }
  203. function books_shop(update) {
  204. tt_create(update, 'potion', 'BooksTooltip', 'books', 'Xp');
  205. }
  206. function gifts_shop(update) {
  207. tt_create(update, 'gift', 'GiftsTooltip', 'gifts', 'affection');
  208. }
  209.  
  210. // create/update tooltip & save to localstorage
  211. function tt_create(update, loc_class, tt_class, itemName, itemUnit) {
  212. // initialize
  213. var itemsNb = 0,
  214. itemsXp = (itemUnit === '') ? -1 : 0,
  215. itemsSell = 0,
  216. loc = $('#inventory').children('.' + loc_class);
  217.  
  218. // get stats
  219. loc.find('.slot').each(function() {
  220. if ($(this).hasClass('empty')) return false;
  221. var item = $(this).data('d'),
  222. Nb = parseInt(item.count, 10);
  223. itemsNb += Nb;
  224. itemsSell += Nb * parseInt(item.price_sell, 10);
  225. if (itemsXp != -1) itemsXp += Nb * parseInt(item.value, 10);
  226. });
  227.  
  228. var tooltip = 'You own <b>' + NbCommas(itemsNb) + '</b> ' + itemName + '.<br />'
  229. + (itemsXp == -1 ? '' : 'You can give a total of <b>' + NbCommas(itemsXp) + '</b> ' + itemUnit + '.<br />')
  230. + 'You can sell everything for <b>' + NbCommas(itemsSell) + '</b> <span class="imgMoney"></span>.';
  231.  
  232. // save to localstorage
  233. lsMarket.stocks[loc_class] = (loc_class == 'potion' || loc_class == 'gift') ? {'Nb':itemsNb, 'Xp':itemsXp} : {'Nb':itemsNb};
  234. localStorage.setItem('lsMarket', JSON.stringify(lsMarket));
  235.  
  236. // create or update tooltip
  237. if (update === 0) {
  238. loc.prepend('<span class="CustomTT"></span><div class="' + tt_class + '">' + tooltip + '</div>');
  239. } else {
  240. loc.children('.' + tt_class).html(tooltip);
  241. }
  242. }
  243.  
  244. // -----------------
  245. // CSS RULES
  246. // -----------------
  247.  
  248. sheet.insertRule('#inventory .CustomTT {'
  249. + 'float: right;'
  250. + 'margin: 11px 1px 0 0;'
  251. + 'background-image: url("http://i.harem-battle.club/images/2017/09/13/FPE.png");'
  252. + 'background-size: 20px 20px;'
  253. + 'width: 20px;'
  254. + 'height: 20px; }');
  255.  
  256. sheet.insertRule('#inventory .CustomTT:hover {'
  257. + 'cursor: help; }');
  258.  
  259. sheet.insertRule('#inventory .CustomTT:hover + div {'
  260. + 'opacity: 1;'
  261. + 'visibility: visible; }');
  262.  
  263. sheet.insertRule('#inventory .EquipmentsTooltip, #inventory .BoostersTooltip, #inventory .BooksTooltip, #inventory .GiftsTooltip {'
  264. + 'position: absolute;'
  265. + 'z-index: 99;'
  266. + 'width: 240px;'
  267. + 'border: 1px solid rgb(162, 195, 215);'
  268. + 'border-radius: 8px;'
  269. + 'box-shadow: 0px 0px 4px 0px rgba(0,0,0,0.1);'
  270. + 'padding: 3px 7px 4px 7px;'
  271. + 'background-color: #F2F2F2;'
  272. + 'font: normal 10px/17px Tahoma, Helvetica, Arial, sans-serif;'
  273. + 'color: #057;'
  274. + 'opacity: 0;'
  275. + 'visibility: hidden;'
  276. + 'transition: opacity 400ms, visibility 400ms; }');
  277.  
  278. sheet.insertRule('#inventory .EquipmentsTooltip, #inventory .BoostersTooltip {'
  279. + 'margin: -33px 0 0 210px;'
  280. + 'height: 43px; }');
  281.  
  282. sheet.insertRule('#inventory .BooksTooltip, #inventory .GiftsTooltip {'
  283. + 'margin: -50px 0 0 210px;'
  284. + 'height: 60px; }');
  285.  
  286. sheet.insertRule('#inventory .EquipmentsTooltip b, #inventory .BoostersTooltip b, #inventory .BooksTooltip b, #inventory .GiftsTooltip b {'
  287. + 'font-weight:bold; }');
  288.  
  289. sheet.insertRule('#inventory .imgMoney {'
  290. + 'background-size: 12px 12px;'
  291. + 'background-repeat: no-repeat;'
  292. + 'width: 12px;'
  293. + 'height: 14px;'
  294. + 'vertical-align: text-bottom;'
  295. + 'background-image: url("http://i.harem-battle.club/images/2017/01/07/0Gsvn.png");'
  296. + 'display: inline-block; }');
  297. }
  298.  
  299.  
  300. /* =========
  301. Harem
  302. ========= */
  303.  
  304. function ModifyHarem() {
  305. // initialize
  306. var i = 0,
  307. GirlId = '',
  308. GirlName = '',
  309. Anchor = '',
  310. Specialty = [0, 0, 0], // [Hardcore, Charm, Know-how]
  311. UnlockedSc = 0,
  312. AvailableSc = 0,
  313. IncHourly = 0,
  314. IncCollect = 0,
  315. HList = [],
  316. Saffection = 0, // S= Stats tab
  317. Smoney = 0,
  318. Skobans = 0,
  319. ScenesLink = '';
  320.  
  321. var EvoReq = [];
  322. EvoReq.push({ affection: 15, money: 3150, kobans: 30 });
  323. EvoReq.push({ affection: 50, money: 6750, kobans: 90 });
  324. EvoReq.push({ affection: 150, money: 18000, kobans: 150 });
  325. EvoReq.push({ affection: 700, money: 135000, kobans: 240 });
  326. EvoReq.push({ affection: 1750, money: 968000, kobans: 300 });
  327.  
  328. // parse haremettes list
  329. $('#harem_left').find('div[girl]').each( function(){
  330. i++;
  331.  
  332. GirlId = $(this).attr('girl');
  333. GirlName = $(this).find('h4').text();
  334. IncCollect += parseInt($(this).find('.sal').text(), 10);
  335. HList.push({Id: GirlId, Order: i, Name: GirlName});
  336.  
  337. // add anchor
  338. $(this).attr('id', GirlName);
  339. // is opened girl?
  340. if ($(this).hasClass('opened')) Anchor = GirlName;
  341.  
  342. // display: haremette number
  343. $(this).find('h4').append('<div class="HaremetteNb">' + i + '</div>');
  344. });
  345. var HaremBottom = '<a href="#' + GirlName + '">Bottom</a>';
  346.  
  347. // auto-scroll to anchor
  348. location.hash = '#' + Anchor;
  349.  
  350. // get haremettes stats & display wiki link
  351. i = 0;
  352. $('#harem_right').children('[girl]').each( function() {
  353. // display: wiki link
  354. $(this).append('<div class="WikiLink"><a href="http://harem-battle.club/wiki/Harem-Heroes/HH:' + HList[i].Name + '" target="_blank"> her wiki page </a></div>');
  355. i++;
  356.  
  357. var j = 0,
  358. Taffection = 0, // T= Total requirements (right tooltip)
  359. Tmoney = 0,
  360. Tkobans = 0,
  361. FirstLockedScene = 1,
  362. AffectionTT = 'She is your <b>' + i + '</b>th haremette. Her evolution costs are:<br />',
  363. girl_quests = $(this).find('.girl_quests');
  364.  
  365. // get stats: specialty
  366. Spe = parseInt($(this).find('h3 > span').attr('carac'), 10) - 1;
  367. Specialty[Spe]++;
  368.  
  369. // get stats: hourly income
  370. IncHourly += parseInt($(this).find('.salary').text(), 10);
  371.  
  372. girl_quests.find('g').each( function() {
  373. // prepare affection tooltip
  374. var Raffection = EvoReq[j].affection * i, // R= Required for this star (right tooltip)
  375. Rmoney = EvoReq[j].money * i,
  376. Rkobans = EvoReq[j].kobans * i;
  377. Taffection += Raffection;
  378. Tmoney += Rmoney;
  379. Tkobans += Rkobans;
  380. j++;
  381. AffectionTT += '<b>' + j + '</b><span class="imgStar"></span> : '
  382. + NbCommas(Raffection) + ' affection, '
  383. + NbCommas(Rmoney) + ' <span class="imgMoney"></span> or '
  384. + NbCommas(Rkobans) + ' <span class="imgKobans"></span><br />';
  385.  
  386. // get stats: unlocked/available scenes & prepare scenes link
  387. AvailableSc++;
  388. ScenesLink += (ScenesLink === '') ? 'hh_scenes=' : ',';
  389. var SceneHref = $(this).parent().attr('href');
  390. if ($(this).hasClass('grey')) {
  391. if (FirstLockedScene === 0) {
  392. Saffection += Raffection;
  393. ScenesLink += '0';
  394. } else {
  395. FirstLockedScene = 0;
  396. var XpLeft = girl_quests.parent().children('.girl_exp_left');
  397. var isUpgradable = girl_quests.parent().children('.green_text_button');
  398. // girl has Xp left
  399. Saffection += (XpLeft.length) ? parseInt(XpLeft.text().match(/^.+: (.*)$/)[1].replace(',',''), 10) : 0;
  400. // girl is upgradable
  401. ScenesLink += (isUpgradable.length) ? '0.' + isUpgradable.attr('href').substr(7) : '0';
  402. }
  403. Smoney += Rmoney;
  404. Skobans += Rkobans;
  405. } else {
  406. UnlockedSc++;
  407. ScenesLink += $(this).parent().attr('href').substr(7);
  408. }
  409. });
  410.  
  411. // change scene links
  412. girl_quests.children('a').each(function() {
  413. var attr = $(this).attr('href');
  414. if (typeof attr !== typeof undefined && attr !== false) {
  415. $(this).attr('href', attr + '?' + ScenesLink);
  416. }
  417. });
  418. ScenesLink = '';
  419.  
  420. AffectionTT += '<b>Total:</b> '
  421. + NbCommas(Taffection) + ' affection, '
  422. + NbCommas(Tmoney) + ' <span class="imgMoney"></span> or '
  423. + NbCommas(Tkobans) + ' <span class="imgKobans"></span>';
  424.  
  425. // display: Affection costs tooltip
  426. girl_quests.parent().children('h4').prepend('<span class="CustomTT"></span><div class="AffectionTooltip">' + AffectionTT + '</div>');
  427. });
  428.  
  429. // ### TAB: Quick List ###
  430.  
  431. // order haremettes alphabetically
  432. HList.sort(function(a, b) {
  433. var textA = a.Name.toUpperCase(),
  434. textB = b.Name.toUpperCase();
  435. return (textA < textB) ? -1 : (textA > textB) ? 1 : 0;
  436. });
  437. // html quick list
  438. var len = HList.length,
  439. QListString = '<div class="QListContent"><span class="Title">Quick List:</span>';
  440. for (i = 0; i < len; i++) {
  441. QListString += '<br /><a f="ql_girl" girl="' + HList[i].Id + '" href="#' + HList[i].Name + '">' + HList[i].Name + '</a> (#' + HList[i].Order + ')';
  442. }
  443. QListString += '</div>';
  444.  
  445. // ### TAB: Stats ###
  446.  
  447. // Market stocks
  448. try {
  449. var lsMarket = JSON.parse(localStorage.getItem('lsMarket')),
  450. d = new Date(lsMarket.restock.time);
  451. console.log(lsMarket);
  452.  
  453. // buyable stocks
  454. if (new Date() > lsMarket.restock.time || Hero.infos.level > lsMarket.restock.herolvl) {
  455. var RestockInfo = '> The <a href="../shop.html">Market</a> restocked since your last visit.';
  456. } else {
  457. var marketBookTxt = lsMarket.buyable.potion.Nb + ' book' + (lsMarket.buyable.potion.Nb > 1 ? 's' : '') + ' (' + NbCommas(lsMarket.buyable.potion.Xp) + ' Xp)',
  458. marketGiftTxt = lsMarket.buyable.gift.Nb + ' gift' + (lsMarket.buyable.gift.Nb > 1 ? 's' : '') + ' (' + NbCommas(lsMarket.buyable.gift.Xp) + ' Aff)',
  459. RestockInfo = '- ' + marketBookTxt + ' for ' + NbCommas(lsMarket.buyable.potion.Value) + ' <img src="http://i.harem-battle.club/images/2017/01/07/0Gsvn.png">'
  460. + '<br />- ' + marketGiftTxt + ' for ' + NbCommas(lsMarket.buyable.gift.Value) + ' <img src="http://i.harem-battle.club/images/2017/01/07/0Gsvn.png">'
  461. + '<br /><font style="color:gray;">Restock: ' + d.toLocaleString() + ' (or level ' + (Hero.infos.level+1) + ')</font>';
  462. }
  463.  
  464. // my stocks
  465. var myArmorTxt = NbCommas(lsMarket.stocks.armor.Nb) + (lsMarket.stocks.armor.Nb > 99 ? '+ ' : ' ') + 'equipment' + (lsMarket.stocks.armor.Nb > 1 ? 's' : ''),
  466. myBoosterTxt = NbCommas(lsMarket.stocks.booster.Nb) + ' booster' + (lsMarket.stocks.booster.Nb > 1 ? 's' : ''),
  467. myBookTxt = NbCommas(lsMarket.stocks.potion.Nb) + ' book' + (lsMarket.stocks.potion.Nb > 1 ? 's' : '') + ' (' + NbCommas(lsMarket.stocks.potion.Xp) + ' Xp)',
  468. myGiftTxt = NbCommas(lsMarket.stocks.gift.Nb) + ' gift' + (lsMarket.stocks.gift.Nb > 1 ? 's' : '') + ' (' + NbCommas(lsMarket.stocks.gift.Xp) + ' Aff)',
  469. MarketStocks = '- ' + myArmorTxt + ', ' + myBoosterTxt
  470. + '<br />- ' + myBookTxt
  471. + '<br />- ' + myGiftTxt
  472. + '<span class="subTitle">Currently Buyable Stocks:</span>'
  473. + RestockInfo;
  474. } catch(e) {
  475. var MarketStocks = (lsAvailable == 'yes') ? '> Visit the <a href="../shop.html">Market</a> first.' : '> Your webbrowser is not compatible.';
  476. }
  477.  
  478. var StatsString = '<div class="StatsContent"><span class="Title">Harem Stats:</span>'
  479. + '<span class="subTitle" style="margin-top:-10px;">' + i + ' haremettes:</span>'
  480. + '- ' + Specialty[0] + ' Hardcore, ' + Specialty[1] + ' Charm, ' + Specialty[2] + ' Know-how'
  481. + '<br />- ' + UnlockedSc + '/' + AvailableSc + ' unlocked scenes'
  482. + '<span class="subTitle">Money incomes:</span>'
  483. + '~' + NbCommas(IncHourly) + ' <img src="http://i.harem-battle.club/images/2017/01/07/0Gsvn.png"> per hour'
  484. + '<br />' + NbCommas(IncCollect) + ' <img src="http://i.harem-battle.club/images/2017/01/07/0Gsvn.png"> when all collectable'
  485. + '<span class="subTitle">Required to unlock all locked scenes:</span>'
  486. + '- ' + NbCommas(Saffection) + ' affection'
  487. + '<br />- ' + NbCommas(Smoney) + ' <img src="http://i.harem-battle.club/images/2017/01/07/0Gsvn.png">'
  488. + ' or ' + NbCommas(Skobans) + ' <img src="http://i.harem-battle.club/images/2016/08/30/gNUo3XdY.png">'
  489. + '<span class="subTitle">My Stocks:</span>'
  490. + MarketStocks
  491. + '</div>';
  492.  
  493. // add custom bar buttons/links & quick list div & stats div
  494. $('#harem_left').append('<div id="CustomBar">'
  495. + '<img f="list" src="http://i.harem-battle.club/images/2017/09/10/FRW.png">'
  496. + '<img f="stats" src="http://i.harem-battle.club/images/2017/09/11/FRh.png">'
  497. + '<div class="TopBottomLinks"><a href="#Bunny">Top</a>&nbsp;&nbsp;|&nbsp;&nbsp;' + HaremBottom + '</div>'
  498. + '</div>'
  499. + '<div id="TabsContainer">' + QListString + StatsString + '</div>');
  500.  
  501. // cache
  502. TabsContainer = $('#TabsContainer');
  503. QList = TabsContainer.children('.QListContent');
  504. Stats = TabsContainer.children('.StatsContent');
  505.  
  506. // catch clicks
  507. $('body').click(function(e) {
  508. var clickOn = e.target.getAttribute('f');
  509. switch (clickOn) {
  510. // on quick list button
  511. case 'list':
  512. toggleTabs(QList, Stats);
  513. break;
  514. // on stats button
  515. case 'stats':
  516. toggleTabs(Stats, QList);
  517. break;
  518. // on a girl in quick list
  519. case 'ql_girl':
  520. var clickedGirl = e.target.getAttribute('girl');
  521. $('#harem_left').find('[girl=' + clickedGirl + ']').triggerHandler('click');
  522. break;
  523. // somewhere else except custom containers
  524. default:
  525. var clickedContainer = $(e.target).closest('[id]').attr('id');
  526. if (clickedContainer == 'TabsContainer') return;
  527. TabsContainer.fadeOut(400);
  528. }
  529. });
  530.  
  531. // tabs switching animations
  532. function toggleTabs(tabIn, tabOut) {
  533. if (TabsContainer.css('display') == 'block') {
  534. if (tabOut.css('display') == 'block') {
  535. tabOut.fadeOut(200);
  536. setTimeout( function(){ tabIn.fadeIn(300); }, 205 );
  537. } else {
  538. TabsContainer.fadeOut(400);
  539. }
  540. } else {
  541. tabOut.toggle(false);
  542. tabIn.toggle(true);
  543. TabsContainer.fadeIn(400);
  544. }
  545. }
  546.  
  547. // -----------------
  548. // CSS RULES
  549. // -----------------
  550.  
  551. sheet.insertRule('#harem_left .HaremetteNb {'
  552. + 'float: right;'
  553. + 'line-height: 14px;'
  554. + 'font-size: 12px; }');
  555.  
  556. sheet.insertRule('#CustomBar {'
  557. + 'position: absolute;'
  558. + 'z-index: 99;'
  559. + 'width: 100%;'
  560. + 'padding: 3px 10px 0 3px;'
  561. + 'font: bold 10px Tahoma, Helvetica, Arial, sans-serif; }');
  562.  
  563. sheet.insertRule('#CustomBar img {'
  564. + 'width: 20px;'
  565. + 'height: 20px;'
  566. + 'margin-right: 3px;'
  567. + 'opacity: 0.5; }');
  568.  
  569. sheet.insertRule('#CustomBar img:hover {'
  570. + 'opacity: 1;'
  571. + 'cursor: pointer; }');
  572.  
  573. sheet.insertRule('#CustomBar .TopBottomLinks {'
  574. + 'float: right;'
  575. + 'margin-top: 2px; }');
  576.  
  577. sheet.insertRule('#CustomBar a, #TabsContainer a, #harem_right .WikiLink a {'
  578. + 'color: #057;'
  579. + 'text-decoration: none; }');
  580.  
  581. sheet.insertRule('#CustomBar a:hover, #TabsContainer a:hover, #harem_right .WikiLink a:hover {'
  582. + 'color: #B14;'
  583. + 'text-decoration: underline; }');
  584.  
  585. sheet.insertRule('#TabsContainer {'
  586. + 'position: absolute;'
  587. + 'z-index: 99;'
  588. + 'margin: -270px 0 0 -1px;'
  589. + 'width: 240px;'
  590. + 'height: 270px;'
  591. + 'overflow-y: scroll;'
  592. + 'border: 1px solid rgb(156, 182, 213);'
  593. + 'box-shadow: 1px -1px 1px 0px rgba(0,0,0,0.3);'
  594. + 'font: normal 10px/16px Tahoma, Helvetica, Arial, sans-serif;'
  595. + 'color: #000000;'
  596. + 'background-color: #ffffff;'
  597. + 'display: none; }');
  598.  
  599. sheet.insertRule('#TabsContainer > div {'
  600. + 'padding: 1px 0 8px 10px; }');
  601.  
  602. sheet.insertRule('#TabsContainer .Title {'
  603. + 'margin-left: -5px;'
  604. + 'font: bold 12px/22px Tahoma, Helvetica, Arial, sans-serif;'
  605. + 'color: #B14; }');
  606.  
  607. sheet.insertRule('#TabsContainer .subTitle {'
  608. + 'padding-top: 10px;;'
  609. + 'font-weight: bold;'
  610. + 'display: block; }');
  611.  
  612. sheet.insertRule('#TabsContainer img {'
  613. + 'width: 14px;'
  614. + 'height: 14px;'
  615. + 'vertical-align: text-bottom; }');
  616.  
  617. sheet.insertRule('#harem_right .CustomTT {'
  618. + 'float: right;'
  619. + 'margin-left: -25px;'
  620. + 'background-image: url("http://i.harem-battle.club/images/2017/09/13/FPE.png");'
  621. + 'background-size: 18px 18px;'
  622. + 'width: 18px;'
  623. + 'height: 18px; }');
  624.  
  625. sheet.insertRule('#harem_right .CustomTT:hover {'
  626. + 'cursor: help; }');
  627.  
  628. sheet.insertRule('#harem_right .CustomTT:hover + div {'
  629. + 'opacity: 1;'
  630. + 'visibility: visible; }');
  631.  
  632. sheet.insertRule('#harem_right .AffectionTooltip {'
  633. + 'position: absolute;'
  634. + 'z-index: 99;'
  635. + 'margin: -130px 0 0 -28px;'
  636. + 'width: 280px;'
  637. + 'height: 127px;'
  638. + 'border: 1px solid rgb(162, 195, 215);'
  639. + 'border-radius: 8px;'
  640. + 'box-shadow: 0px 0px 4px 0px rgba(0,0,0,0.1);'
  641. + 'padding: 3px 7px 4px 7px;'
  642. + 'background-color: #F2F2F2;'
  643. + 'font: normal 10px/17px Tahoma, Helvetica, Arial, sans-serif;;'
  644. + 'text-align: left;'
  645. + 'opacity: 0;'
  646. + 'visibility: hidden;'
  647. + 'transition: opacity 400ms, visibility 400ms; }');
  648.  
  649. sheet.insertRule('#harem_right .AffectionTooltip b {'
  650. + 'font-weight: bold; }');
  651.  
  652. sheet.insertRule('#harem_right .WikiLink {'
  653. + 'float: right;'
  654. + 'margin: -13px 7px 0 0;'
  655. + 'font-size: 12px; }');
  656.  
  657. sheet.insertRule('#harem_right .imgStar, #harem_right .imgMoney, #harem_right .imgKobans {'
  658. + 'background-size: 10px 10px;'
  659. + 'background-repeat: no-repeat;'
  660. + 'width: 10px;'
  661. + 'height: 14px;'
  662. + 'display: inline-block; }');
  663.  
  664. sheet.insertRule('#harem_right .imgStar {'
  665. + 'background-image: url("http://i.harem-battle.club/images/2016/12/29/R9HWCKEtD.png"); }');
  666.  
  667. sheet.insertRule('#harem_right .imgMoney {'
  668. + 'background-image: url("http://i.harem-battle.club/images/2017/01/07/0Gsvn.png"); }');
  669.  
  670. sheet.insertRule('#harem_right .imgKobans {'
  671. + 'background-image: url("http://i.harem-battle.club/images/2016/08/30/gNUo3XdY.png"); }');
  672. }
  673.  
  674.  
  675. /* ==========
  676. Scenes
  677. ========== */
  678.  
  679. function ModifyScenes() {
  680. // parse GET hh_scenes variable
  681. var currentScene = CurrentPage.substr(7),
  682. hh_scenesParams = new URL(window.location.href).searchParams.get('hh_scenes'),
  683. hh_scenes = hh_scenesParams.split(','),
  684. len = hh_scenes.length;
  685.  
  686. // no scenes, less than 3 or more than 5 (human manipulation)
  687. if (!len || len < 3 || len > 5) {
  688. return false;
  689. } else {
  690. var ScenesNavigate = '<div class="Scenes" style="display:block;">Navigate:<br/>',
  691. SceneLink = '';
  692.  
  693. for (var i = 0; i < len; i++ ) {
  694. // string format certification
  695. if (/^(0\.)?[0-9]{1,5}$/.test(hh_scenes[i]) === true) {
  696. if (hh_scenes[i] == currentScene) {
  697. SceneLink = '<span class="current">current</span>';
  698. } else if (hh_scenes[i] == '0') {
  699. SceneLink = '<span class="locked">locked</span>';
  700. } else if (parseInt(hh_scenes[i], 10) < 1) {
  701. SceneLink = '<a href="/quest/' + hh_scenes[i].substr(2) + '">unlock it!</a>';
  702. } else {
  703. SceneLink = '<a href="/quest/' + hh_scenes[i] + '?hh_scenes=' + hh_scenesParams + '">scene</a>';
  704. }
  705. ScenesNavigate += (i+1) + '<span class="imgStar"></span> ' + SceneLink + '<br />';
  706. }
  707. // string error: doesn't match (human manipulation)
  708. else return false;
  709. }
  710. ScenesNavigate += '<span class="backToHarem">< <a href="' + $('#breadcrumbs').children('a').eq(2).attr('href') + '">Harem</a></span></div>';
  711.  
  712. // insert navigate interface
  713. $('#controls').append(ScenesNavigate);
  714. }
  715.  
  716. // -----------------
  717. // CSS RULES
  718. // -----------------
  719.  
  720. sheet.insertRule('#controls .Scenes {'
  721. + 'height:200px;'
  722. + 'box-shadow: 3px 3px 0px 0px rgba(0,0,0,0.3);'
  723. + 'background-color:#000000;'
  724. + 'background: linear-gradient(to bottom, rgba(196,3,35,1) 0%,rgba(132,2,30,1) 51%,rgba(79,0,14,1) 100%);'
  725. + 'text-shadow: 2px 2px 2px rgba(0, 0, 0, 0.4);'
  726. + 'display: block !important; }');
  727.  
  728. sheet.insertRule('#controls .current {'
  729. + 'color: rgb(251, 255, 108); }');
  730.  
  731. sheet.insertRule('#controls .locked {'
  732. + 'color: rgb(150, 99, 99); }');
  733.  
  734. sheet.insertRule('#controls .Scenes a {'
  735. + 'color: rgb(233, 142, 228);'
  736. + 'text-decoration: none; }');
  737.  
  738. sheet.insertRule('#controls .Scenes a:hover {'
  739. + 'color: rgb(254, 202, 255);'
  740. + 'text-decoration: underline; }');
  741.  
  742. sheet.insertRule('#controls .backToHarem {'
  743. + 'position: absolute;'
  744. + 'bottom: 0;'
  745. + 'left: 0;'
  746. + 'width: 100%; }');
  747.  
  748. sheet.insertRule('#controls .imgStar {'
  749. + 'background-image: url("http://i.harem-battle.club/images/2016/12/29/R9HWCKEtD.png");'
  750. + 'background-size: 10px 10px;'
  751. + 'background-repeat: no-repeat;'
  752. + 'width: 10px;'
  753. + 'height: 18px;'
  754. + 'display: inline-block; }');
  755. }
  756.  
  757. // is localstorage available?
  758. function lsTest() {
  759. try {
  760. localStorage.setItem('test', 'test');
  761. localStorage.removeItem('test');
  762. return true;
  763. } catch(e) {
  764. return false;
  765. }
  766. }
  767.  
  768. // adds thousands commas
  769. function NbCommas(x) {
  770. return x.toString().replace(/\B(?=(\d{3})+(?!\d))/g, ",");
  771. }
  772.