// ==UserScript==
// @name IdleScape - Lootify
// @namespace D4IS
// @version 1.4.1
// @description IdleScape Statistics Tracker
// @author D4M4G3X
// @match *://*.idlescape.com/*
// @grant none
// @require https://code.jquery.com/jquery-3.4.1.min.js
// @run-at document-start
// ==/UserScript==
(function() {
/* INITIATE APPLICATION */
let lib = {};
let app = {};
let initInterval = setInterval(()=> {
if (window.D4IS) {
clearInterval(initInterval);
lib = window.D4IS.init('lootify', '1.4');
app = lib['lootify'];
lib.app.setUpdateLocation(lib.game.getMenuItem('Lootify Settings'));
main();
}
}, 100);
function main() {
/* SET DEFAULT VALUES */
app.runs = [{}];
let total = {};
let totalLoot = {};
let headers = {};
/* ############## INTERVALS ############## */
let mainInterval = setInterval(()=> {
if (app.ready && $('.status-bar').length) {
if(is()) {
if(!app.setup) {
app.setup = true;
setupSettings();
lib.app.updateUser(app.name);
app.getKills();
setupLogs();
}
renderErrors();
renderStatus();
saveLogs();
mergeLogs();
renderLogs();
renderTimer();
renderKPH();
renderGPH();
renderXPH();
}
}
}, 500);
let pasteInterval = setInterval(()=> {
if (app.ready && $('.status-bar').length) {
if(lib.general.getStorage('AutoPaster') == 'true') {
reset('single');
}
}
}, getPasteInterval() * 60 * 1000);
let adInterval = setInterval(()=> {
if (app.ready && $('.status-bar').length) {
lib.game.chat({
'msg': 'Lootify - Please report bugs to D4M4G3X#6263 on Discord!',
'color': '#00a0fd',
});
}
}, 20 * 60 * 1000);
let updateInterval = setInterval(()=> {
if (app.ready && $('.status-bar').length) {
lib.app.getData();
lib.app.updateUser(app.name);
app.getKills();
}
}, 15 * 60 * 1000);
let quickInterval = setInterval(()=> {
if (app.ready && $('.status-bar').length) {
addConfirmations();
checkRemovals();
}
}, 100);
function addConfirmations() {
// #### GATHERING CONFIRMATIONS #### //
$('.resource-container-button').each(function() {
if(lib.app.data) {
if (!lib.app.data.active.skills.includes($(this).parents('.play-area').attr('class').split('theme-')[1])) {
return false;
}
let $parent = $(this).parents('.resource-container');
if( !$(this).next('.resource-button-overlay').length && !~$(this).text().indexOf('Stop')) {
let $btn = $(this).find('.resource-button').hide();
let $btnClone = $('<div>', {
'class': 'resource-button-overlay resource-button'
}).text($btn.text()).insertAfter($(this));
$btnClone.click(function() {
let includes = false;
// Game Start
if ((lib.user.isStatus('idling') && !app.prevStatus) || isLogEmpty()) {
$parent.find('.resource-button:not(.resource-button-overlay)').click();
return false;
}
// Is Logged
if (isLogged('skill', $parent.find('.resource-container-title').text())) {
$parent.find('.resource-button:not(.resource-button-overlay)').click();
return false;
}
lib.game.dialog({
'title': 'Lootify warning!',
'text': 'Going to a different location will paste and reset your Lootify statistics, are you sure you want to do this?',
'img': true,
'cbyes': function() {
reset();
$parent.find('.resource-button:not(.resource-button-overlay)').click();
}
});
});
}
if (~$(this).text().indexOf('Stop')) {
$(this).next('.resource-button-overlay').remove();
$(this).find('.resource-button').show();
}
}
});
// #### COOKING CONFIRMATIONS #### //
if ($('.cooking-item').find('img').length) {
if(!$('.cooking-start-clone').length && !lib.user.isStatus('cooking')) {
let $cookBtn = $('.cooking-start-button').css('visibility', 'hidden');
let $cloneBtn = $('<div>', {
'class': 'cooking-start-button cooking-start-clone'
}).text('Start Cooking').insertAfter($cookBtn);
$(window).resize(function() {
let pos = $cookBtn.position();
$cloneBtn.width($cookBtn.width());
$cloneBtn.css({
'position': 'absolute',
'z-index': '1000',
'top': pos.top,
'left': pos.left,
});
}).resize();
$cloneBtn.click(function() {
// Game Start
if ((lib.user.isStatus('idling') && !app.prevStatus) || isLogEmpty()) {
$cookBtn.click();
$cookBtn.css('visibility', 'visible');
$cloneBtn.hide();
return false;
}
// Is Previous Status
if (lib.user.isPrevStatus('cooking')) {
$cookBtn.click();
$cookBtn.css('visibility', 'visible');
$cloneBtn.hide();
return false;
}
lib.game.dialog({
'title': 'Lootify warning!',
'text': 'Cooking now will paste and reset your current Lootify statistics, are you sure you want to do this?',
'img': true,
'cbyes': function() {
reset();
$cloneBtn.hide();
$cookBtn.css('visibility', 'visible');
$cookBtn.click();
}
});
});
}
} else {
$('.cooking-start-button').css('visibility', 'visible');
$('.cooking-start-clone').remove();
}
// #### COMBAT CONFIRMATIONS #### //
if ($('.combat-zones').length && !$('.zone-button-overlay').length) {
let $overlay = $('<div>', {
'class': 'zone-button-overlay'
}).appendTo($('.combat-zones'));
$('.combat-zone').each(function() {
let $zoneBtn = $('<div>', {
'class':'combat-zone-clone'
}).text($(this).text()).appendTo($overlay);
$zoneBtn.click(function(e) {
let $parent = $(this).parents('.combat-zones');
let $that = $(this);
let includes = false;
// Game Start
if ((lib.user.isStatus('idling') && !app.prevStatus) || isLogEmpty()) {
$parent.find('.combat-zone').each(function() {
if($(this).text() === $that.text()) {
$(this).click();
}
});
return false;
}
// Is Logged
if (isLogged('combat', $(this).text())) {
$parent.find('.combat-zone').each(function() {
if($(this).text() === $that.text()) {
$(this).click();
}
});
return false;
}
// Is an event mob
if (lib.game.isEventMob(app.currentMob)) {
$parent.find('.combat-zone').each(function() {
if($(this).text() === $that.text()) {
$(this).click();
}
});
return false;
}
lib.game.dialog({
'title': 'Lootify warning!',
'text': 'Going to a different zone will paste and reset your Lootify statistics, are you sure you want to do this?',
'img': true,
'cbyes': function() {
$parent.find('.combat-zone').each(function() {
if($(this).text() === $that.text()) {
reset();
$(this).click();
}
});
},
});
});
});
$(window).resize(function() {
$overlay.width($('.combat-zones').width());
}).resize();
}
}
function checkRemovals() {
if(!lib.user.isStatus('foraging')) { return; }
if ($('.recipe-item').length) {
$('.recipe-item').each(function() {
if($(this).find('img').attr('src') === '/images/foraging/log.png') {
$(this).remove();
}
});
}
}
// #### SETUP SETTINGS ####
function setupSettings() {
if(!lib.game.getMenuItem('Lootify', 'category')) {
lib.game.setMenuItem({
'text': 'Lootify',
'clone': 'Gathering',
'class': 'hdr-lootify',
'before': lib.game.getMenuItem('Gathering', 'category'),
}, 'category');
$('<i/>').text(' (v'+app.ver+')').appendTo(lib.game.getMenuItem('Lootify', 'category'));
}
// ### PRIVACY SETTINGS ###
lib.game.addSetting({
'app': 'lootify',
'text': 'Allow Lootify to publicly use your username for personal highscores and kill statistics',
'name': 'UserPublic',
'type': 'checkbox',
'default': 'false',
'change': function() {
setUserPublic($(this).prop('checked'));
lib.general.setStorage('UserPublic', $(this).prop('checked'));
}
});
if (!lib.general.getStorage('Terms')) {
let msg = "";
msg += "By using Lootify you agree to allow us saving your username and ID in our database for statistical purposes.";
msg += "These will be used for setting up personal statistics and highscores. (coming soon...) ";
msg += "If you don't want your username to be on public highscore lists then you can opt-out in the settings";
lib.game.dialog({
'title': 'Terms of service',
'text': msg,
'type': 'confirm',
'img': true,
'cbconfirm': function() {
lib.general.setStorage('Terms', 'true');
},
});
}
// ### SETTING AUTO PASTER ###
lib.game.addSetting({
'app': 'lootify',
'text': 'Enable Auto Paster',
'name': 'AutoPaster',
'type': 'checkbox',
'default': 'false',
'change': function() {
lib.general.setStorage('AutoPaster', $(this).prop('checked'));
}
});
// ### SETTING PASTE INTERVAL ###
lib.game.addSetting({
'app': 'lootify',
'text': 'Paste Interval (minutes)',
'name': 'AutoPasterInterval',
'type': 'number',
'min': 15,
'max': 60,
'default': 30,
'change': function() {
if($(this).val() >= $(this).attr('min') && $(this).val() <= $(this).attr('max')) {
lib.general.setStorage('AutoPasterInterval', $(this).val());
}
}
});
// ### SETTING CHAT MESSAGES ###
lib.game.addSetting({
'app': 'lootify',
'text': 'Enable Chat Messages',
'name': 'ChatMessage',
'type': 'checkbox',
'default': 'true',
'change': function() {
lib.general.setStorage('ChatMessage', $(this).prop('checked'));
}
});
}
function renderErrors() {
if (!app.disabled || !app.enabled) {
$('.lootify-error').remove();
}
if (!$('.lootify-error.error-paster').length && app.disabled) { // TODO: Create Error Message Function
let $error = $('<div/>', {
'class': 'lootify-error error-paster'
}).css({
'color': 'red',
'width': '80%',
'margin': '0 auto',
}).html('Paster is disabled!<br>Reset log to Enable again.').insertAfter(lib.game.getMenuItem('Lootify', 'category'));
lib.game.tooltip($error, 'Pasting is disabled on market usage, you can still use the counters.<br> This is done to prevent skewing the statistics.');
}
if (!$('.lootify-error.error-disabled').length && (app.enabled && app.enabled === 'false')) { // TODO: Create Error Message Function
$('<div/>', {
'class': 'lootify-error error-disabled'
}).css({
'color': 'red',
'width': '80%',
'margin': '0 auto',
}).html('Paster is globally disabled!').insertAfter(lib.game.getMenuItem('Lootify', 'category'));
}
}
function renderStatus() {
if (!lib.user.isFighting() && !lib.user.isActiveSkill() && !lib.user.isStatus('idling')) {
$('.ltf-status').remove();
return false;
}
if (!lib.game.getMenuItem('Status:')) {
lib.game.setMenuItem({
'class': 'ltf-status',
'text': 'Status: ' + lib.user.getStatus(),
'icon': '/images/combat/combat_level.png',
'after': lib.game.getMenuItem('Lootify', 'category'),
'click': function() {
$('[data-for="'+lib.user.getStatus()+'Header"]').click();
}
});
}
let status = lib.user.getStatus();
status += lib.user.isFighting() ? ' '+lib.user.currentMob : '';
$('.ltf-status').find('span').text('Status: ' + lib.general.ucfirst(status));
}
function setupLogs() {
if ($('.btn-loot-log').length) {
$('.btn-loot-log').remove();
}
let $logBtn = lib.game.getMenuItem('Loot Log');
if (($logBtn && $logBtn.text() === 'Loot Log') && !$logBtn.hasClass('btn-loot-log')) {
lib.game.editMenuItem('Loot Log');
}
if(!lib.game.getMenuItem('Loot Log')) {
lib.game.setMenuItem({
'icon': '/images/ui/inventory_icon.png',
'text': 'Loot Log',
'class': 'btn-loot-log',
'before': lib.game.getMenuItem('Gathering', 'category'),
'click': function() {
$('.item-log-clone').toggle();
},
});
}
let $logwrap = $('.item-log-window');
$logwrap.hide();
let $clone = $logwrap.clone();
$clone.addClass('item-log-clone').removeClass('hidden');
$clone.find('.item-log-timer').remove();
$clone.find('.item-log-info').remove();
$clone.find('.drawer-setting-large').addClass('clone').unbind().click(function() {
reset();
}).text('Paste and Reset');
if (app.disabled || lib.user.isStatus('fishing') || lib.user.isStatus('smithing') || lib.user.isStatus('cooking')) {
$clone.find('.drawer-setting-large').text('Reset');
}
lib.game.getMenuItem('Loot Log').after($clone);
}
function renderTimer() {
if (!lib.user.isFighting() && !lib.user.isActiveSkill() && !lib.user.isStatus('idling')) {
$('.time-stats').remove();
return false;
}
if (!lib.game.getMenuItem('Elapsed:')) {
let $timeStats = lib.game.setMenuItem({
'class': 'time-stats',
'text': 'Elapsed: 0S',
'icon': '/images/clock.png',
'after': $('.ltf-status')
});
}
setTimeout(()=> {
!lib['lootify'].timers ? lib['lootify'].timers = {} : 1;
if(!lib['lootify'].timers[lib.user.getStatus()]) {
new lib.general.Timer(app.name, lib.user.getStatus());
}
}, 100);
}
function renderKPH() {
if (!lib.user.isFighting()) {
$('.kph-stats').remove();
$('.kph-wrap').remove();
return false;
}
if (!lib.game.getMenuItem('Kills:')) {
let $kphStats = lib.game.setMenuItem({
'class': 'kph-stats',
'text': 'Kills: 0 p/h',
'icon': '/images/combat/combat_level.png',
'after': $('.time-stats'),
'click': function() {
$('.kph-wrap').toggle();
}
});
$kphStats.after($('<div/>', {
'class': 'kph-wrap ltf-submenu'
}).hide());
}
let mobkills = {};
$.each(total, function(mob, mobinfo) {
mobkills[mob] = mobinfo.count;
});
let totalkills = function() {
let c = 0;
$.each(mobkills, function(mob, kills) {
c += kills;
});
return c;
};
let kph = 0;
let time = lib.general.getTimerTime('lootify', lib.user.getStatus());
kph = lib.general.addCommas(Math.floor((totalkills()/time)*3600));
$('.kph-stats').find('span').text('Kills: ' + kph + ' p/h');
$('.kph-wrap').empty();
$.each(lib.general.sortObject(mobkills), function(mob, count) {
let $mobwrap = $('<div/>', {
'class': 'ltf-header mob-header'
}).appendTo($('.kph-wrap'));
kph = lib.general.addCommas(Math.floor((count/time)*3600));
let $mobinfo = $('<span/>').css('display','block').text(mob + ': ' + kph + ' p/h');
$mobinfo.prepend($('<img>').attr('src', lib.game.getMobIcon(mob)));
$mobwrap.append($mobinfo);
});
}
function renderGPH() {
if((!lib.user.isActiveSkill() && !lib.user.isFighting()) || lib.user.isIron() || lib.user.isStatus('cooking')) {
$('.gph-stats').remove();
$('.gph-wrap').remove();
return false;
}
if (!lib.game.getMenuItem('Gold:')) {
let $gphStats = lib.game.setMenuItem({
'class': 'gph-stats',
'text': 'Gold: 0 p/h',
'icon': '/images/ui/shop_icon.png',
'after': $('.time-stats'),
'click': function() {
$('.gph-wrap').toggle();
}
});
$gphStats.after($('<div/>', {
'class': 'gph-wrap ltf-submenu'
}).hide());
}
let totalGold = 0;
if (lib.game.marketPrices) {
$.each(totalLoot, function(item, count) {
if (item === 'Gold') {
totalGold += count;
} else {
if (lib.user.isStatus('smithing')) {
let ore = item.split(' ')[0] + ' Ore';
totalGold += (lib.game.marketPrices[item] - lib.game.marketPrices[ore])* count;
} else {
totalGold += lib.game.marketPrices[item] * count;
}
}
});
} else {
totalGold = 'n/a';
}
let time = lib.general.getTimerTime('lootify', lib.user.getStatus());
if (time) {
let gph = lib.general.addCommas(Math.floor((totalGold/time)*3600));
$('.gph-stats').find('span').text('Gold: ' + gph + ' p/h');
}
$('.gph-wrap').empty();
let $lootwrap = $('<div/>', {
'class': 'ltf-header mob-header'
}).appendTo($('.gph-wrap'));
let lootval = lib.general.addCommas(Math.floor(totalGold));
let $lootInfo = $('<span/>').css('display','block').text('Loot value: ' + lootval);
$lootInfo.prepend($('<img>').attr('src', '/images/money_icon.png'));
$lootwrap.append($lootInfo);
}
function renderXPH() {
if(!lib.user.isActiveSkill() && !lib.user.isFighting()) {
$('.mxph-stats').remove();
$('.mxph-wrap').remove();
$('.xph-stats').remove();
$('.xph-wrap').remove();
return false;
}
let currentLevel = {};
let approxTime = {};
let totalExp = {};
let skillExp = {};
let combatSkills = ['attack', 'defense', 'strength', 'constitution'];
let expTypes = ['exp', 'mexp'];
let time = lib.general.getTimerTime('lootify', lib.user.getStatus());
!lib.user.levelGoal ? lib.user.levelGoal = {} : 1;
$.each(expTypes, function(k, type) {
if (lib.user[type]) {
// CALCULATE EXP FOR COMBAT SKILLS
if (lib.user.isFighting()) {
$.each(combatSkills, function(k, skill) {
!skillExp[type] ? skillExp[type] = [] : 1;
!totalExp[type] ? totalExp[type] = 0 : 1;
!currentLevel[type] ? currentLevel[type] = [] : 1;
// GET THE CURRENT SKILL EXP GAINED
skillExp[type][skill] = lib.user[type][skill].current - lib.user[type][skill].init;
// GET TOTAL EXP GAINED OF ALL COMBAT SKILLS
totalExp[type] += (lib.user[type][skill].current - lib.user[type][skill].init);
currentLevel[type][skill] = lib.game.getLevel(lib.user[type][skill].current);
!lib.user.levelGoal[skill] ? lib.user.levelGoal[skill] = currentLevel[type][skill] + 1 : 1;
});
}
// CALCULATE EXP FOR GATHERING SKILLS
$.each(lib.app.data.active.skills, function(k, skill) {
if(lib.user.isStatus(skill)) {
totalExp[type] = lib.user[type][skill].current - lib.user[type][skill].init;
currentLevel[type] = lib.game.getLevel(lib.user[type][skill].current);
!lib.user.levelGoal[skill] ? lib.user.levelGoal[skill] = currentLevel[type] + 1 : 1;
}
});
}
});
// EXP COUNTERS
$.each(expTypes, function(k, type) {
let menuItem = (type === 'exp') ? 'Experience:' : 'Mastery:';
let menuClass = (type === 'exp') ? 'xph' : 'mxph:';
let menuIcon = (type === 'exp') ? '/images/total_level.png' : '/images/total_level_mastery_icon.png';
if (!lib.game.getMenuItem(menuItem) && totalExp[type] > 1) {
let $xphStats = lib.game.setMenuItem({
'class': menuClass+'-stats',
'text': menuItem+' 0 p/h',
'icon': menuIcon,
'after': $('.time-stats'),
'click': function() {
$('.'+menuClass+'-wrap').toggle();
}
});
$xphStats.after($('<div/>', {
'class': menuClass+'-wrap ltf-submenu'
}).hide());
}
let xph = lib.general.addCommas(Math.floor((totalExp[type]/time)*3600));
$('.'+menuClass+'-stats').find('span').text(menuItem + ' ' + xph + ' p/h');
$('.'+menuClass+'-wrap').empty();
// XP Earned since activity start
let xpearned = lib.general.addCommas(Math.floor(totalExp[type]));
let $expwrap = $('<div/>', {
'class': 'ltf-header mob-header'
});
$expwrap.appendTo($('.'+menuClass+'-wrap'));
let $expEarnedInfo = $('<span/>').css('display','block').text('Exp earned: ' + xpearned);
$expEarnedInfo.prepend($('<img>').attr('src', 'https://digimol.net/idlescape/assets/img/plus_sign.png'));
$expwrap.append($expEarnedInfo);
// Time Left For Next Level
let $expTimeWrap, $expTimeInfo;
if (lib.user[type]) {
if(!lib.user.isFighting()) {
let skill = lib.user.getStatus();
approxTime = lib.user.getTimeToLevel(lib.user.levelGoal[skill], lib.user[type][skill].current, totalExp[type], time);
$expTimeWrap = $expwrap.clone().empty().appendTo($('.'+menuClass+'-wrap'));
$expTimeInfo = $('<div>').css('display','flex')
$expTimeInfo.append($('<img>').attr('src', lib.game.getSkillIcon(skill)));
$expTimeInfo.append($('<span>').text('to '+lib.user.levelGoal[skill]));
let $arrows = $('<div>', {
'class': 'd4is-control-arrows'
}).appendTo($expTimeInfo);
$('<span>').text('▲').click(function() {
if(lib.user.levelGoal[skill] < 200) {
lib.user.levelGoal[skill]++;
}
}).appendTo($arrows);
$('<span>').text('▼').click(function() {
if(lib.user.levelGoal[skill] > currentLevel[type]+1) {
lib.user.levelGoal[skill]--;
}
}).appendTo($arrows);
$expTimeInfo.append($('<span>').text(approxTime));
$expTimeWrap.append($expTimeInfo);
} else {
$.each(combatSkills, function(k, skill) {
if(skillExp[type][skill] > 0) {
approxTime = lib.user.getTimeToLevel(lib.user.levelGoal[skill], lib.user[type][skill].current, skillExp[type][skill], time);
$expTimeWrap = $expwrap.clone().empty().appendTo($('.'+menuClass+'-wrap'));
$expTimeInfo = $('<div>').css('display','flex');
$expTimeInfo.append($('<img>').attr('src', lib.game.getSkillIcon(skill)));
$expTimeInfo.append($('<span>').text('to '+lib.user.levelGoal[skill]));
let $arrows = $('<div>', {
'class': 'd4is-control-arrows'
}).appendTo($expTimeInfo);
$('<span>').text('▲').click(function() {
if(lib.user.levelGoal[skill] < 200) {
lib.user.levelGoal[skill]++;
}
}).appendTo($arrows);
$('<span>').text('▼').click(function() {
if(lib.user.levelGoal[skill] > currentLevel[type][skill]+1) {
lib.user.levelGoal[skill]--;
}
}).appendTo($arrows);
$expTimeInfo.append($('<span>').text(approxTime));
$expTimeWrap.append($expTimeInfo);
}
});
}
}
});
}
function saveLogs() {
if (!lib.user.isFighting()) { return false; }
let $logcats = $('.item-log-window:not(.item-log-clone)').find('.item-log-cateogry');
if ($logcats.length) {
$logcats.each(function() {
if( $(this).find('.item-log-category-closed').length ) {
$(this).find('.item-log-category-closed').click();
}
let mobs = $(this).find('.item-log-category-open').text().split(" x ");
!app.runs[0][mobs[0]] ? app.runs[0][mobs[0]] = {} : 1;
app.runs[0][mobs[0]].count = parseInt(mobs[1]);
$(this).find('.item-log-item').each(function() {
if ($(this).text() !== "None") {
let loot = $(this).text().split(" x ");
!app.runs[0][mobs[0]].loot ? app.runs[0][mobs[0]].loot = {} : 1;
!app.runs[0][mobs[0]].loot[loot[0]] ? app.runs[0][mobs[0]].loot[loot[0]] = {} : 1;
app.runs[0][mobs[0]].loot[loot[0]].count = parseInt(loot[1]);
}
});
});
}
}
function mergeLogs() {
if(app.runs) {
total = {};
totalLoot = {};
$.each(app.runs, function(num, run) {
$.each(run, function(mobname, mobinfo) {
!total[mobname] ? total[mobname] = {} : 1;
!total[mobname].count ? total[mobname].count = 0 : 1;
total[mobname].count += mobinfo.count;
$.each(mobinfo.loot, function(lootname, lootinfo) {
/* SET TOTAL LOOT PER MOB */
!total[mobname].loot ? total[mobname].loot = {} : 1;
!total[mobname].loot[lootname] ? total[mobname].loot[lootname] = {} : 1;
!total[mobname].loot[lootname].count ? total[mobname].loot[lootname].count = 0 : 1;
!total[mobname].loot[lootname].procs ? total[mobname].loot[lootname].procs = 0 : 1;
total[mobname].loot[lootname].count += lootinfo.count;
total[mobname].loot[lootname].procs += lootinfo.procs;
/* SET TOTAL LOOT OVERALL */
let procs = lootinfo.procs ? lootinfo.procs : 0;
!totalLoot[lootname] ? totalLoot[lootname] = 0 : 1;
totalLoot[lootname] += lootinfo.count + procs;
});
});
});
delete total[''];
}
}
function renderLogs() {
if(!app.runs) { return false; }
let $logEntry, $logHeader, $lootWrap, $lootEntry;
$('.item-log-clone').find('.item-log-cateogry').remove();
$.each(lib.general.sortObject(total), function(mob, mobinfo) {
if (!$('.log-entry-'+mob.toLowerCase().split(' ').join('_')).length) {
// Log Wrapper
$logEntry = $('<div/>', {
'class':'ltf-log-entry log-entry-'+mob.toLowerCase().split(' ').join('_')
});
$logHeader = $('<div/>', {
'class':'ltf-log-header noselect'
}).appendTo($logEntry);
$lootWrap = $('<div/>', {
'class': 'ltf-loot-wrap'
}).appendTo($logEntry);
$logHeader.click(function() {
headers[mob] = headers[mob] == false ? true : false;
$lootWrap.toggle();
});
if (lib.user.isStatus('smithing')) {
$.each(mobinfo.loot, function(loot, info) {
if(~loot.indexOf('Bar')) {
mob = loot;
}
});
}
// HEADER
$logHeader.append($('<div/>').text(mob + ' x ' + mobinfo.count));
let icon = !lib.user.isFighting() ? lib.game.getLocationIcon(lib.game.getLocationID(mob)) : lib.game.getMobIcon(mob);
icon = lib.user.isStatus('smithing') ? '/images/smithing/'+ mob.toLowerCase().split(' ').join('_')+'.png' : icon;
$logHeader.append($('<img/>').addClass('drawer-item-icon').attr('src', icon));
$('.drawer-setting-large.clone').before($logEntry);
addLogEntry(mob, mobinfo.loot);
} else {
$logEntry = $('.log-entry-'+mob.toLowerCase().split(' ').join('_'));
$logHeader = $logEntry.find('.ltf-log-header');
$logHeader.find('div').text(mob + ' x ' + mobinfo.count);
if (lib.user.isStatus('smithing')) {
mob = mobinfo.loot[0];
}
addLogEntry(mob, mobinfo.loot);
}
$logEntry.sort(function (a, b) {
return $(a).find('.ltf-log-header').text() - $(b).find('.ltf-log-header').text();
}).each(function (_, container) {
$(container).parent().find('.drawer-setting-large.clone').before(container);
});
});
}
function addLogEntry(entry, info) {
if (!entry) { return false; }
let $logEntry = $('.log-entry-'+entry.toLowerCase().split(' ').join('_'));
$.each(lib.general.sortObject(info), function(loot, lootinfo) {
let lootEntryClass = 'loot-entry-'+entry.toLowerCase().split(' ').join('_')+'-'+loot.toLowerCase().split(' ').join('_');
let $lootEntry = $('.'+lootEntryClass);
let lootText = loot + ' x ' + lootinfo.count;
lootText += (lootinfo.procs >= 1) ? ' (+'+lootinfo.procs+')' : '';
if(!$lootEntry.length) {
$lootEntry = $('<div/>', {
'class': 'ltf-loot-entry '+lootEntryClass
}).text(lootText).appendTo($logEntry.find('.ltf-loot-wrap'));
if(lib.game.isRareItem(loot)) {
$lootEntry.addClass('loot-rare');
} else if(lib.game.isEventItem(loot)) {
$lootEntry.addClass('loot-event');
} else if(lib.game.isUniversalItem(loot)) {
$lootEntry.addClass('loot-universal');
}
} else {
$lootEntry.text(lootText);
}
$lootEntry.sort(function (a, b) {
return $(a).text() - $(b).text();
}).each(function (_, container) {
$(container).parent().append(container);
});
});
}
/* ############## ACTIONS ############## */
function getLogs() {
let logs = [];
let $logcats = $('.item-log-window:not(.item-log-clone)').find('.item-log-cateogry');
if ($logcats.length) {
$logcats.each(function(k,v) {
if( $(this).find('.item-log-category-closed').length ) {
$(this).find('.item-log-category-closed').click();
}
if( $(this).find('.item-log-category-open').length ) {
logs.push($(this).find('.item-log-category-open').text());
$(this).find('.item-log-item').each(function() {
if( $(this).text() !== "None" ) {
logs.push($(this).text());
}
});
}
});
}
return logs;
}
function clearLogs(m = 'all') {
if (m == 'single') {
app.runs.unshift({});
} else if (m == 'all') {
if (lib.user.exp && lib.user.mexp) {
$.each(lib.app.data.active.skills, function(k, skill) {
lib.user.exp[skill].init = lib.user.exp[skill].current;
lib.user.mexp[skill].init = lib.user.mexp[skill].current;
});
}
if (Object.keys(lib['lootify'].timers).length !== 0) {
$.each(lib['lootify'].timers, function(k, t) {
t.reset();
});
}
app.runs = [{}];
total = {};
app.disabled = false;
app.setup = false;
$('.item-log-clone').remove();
}
$('.item-log-window').find('.drawer-setting-large.active:not(.clone)').click();
}
function reset(m = 'all') {
submitStats(getLogs(), lib.user.getEnchantment('32'));
clearLogs(m);
}
/* ############## GAME LIBRARY ############## */
function is() {
return lib.general.getStorage('Terms') === 'true';
}
function isLogged(type, txt) {
let includes = false;
if(getLogMobs()) {
$.each(getLogMobs(), function(key, mob) {
if (type === 'combat') {
if (lib.game.getZoneMobs(txt).includes(mob)) {
includes = true;
}
} else if (type === 'skill') {
if (txt == mob) {
includes = true;
}
}
});
}
return includes;
}
function isLogEmpty() {
return Object.keys(app.runs[0]).length === 0;
}
function getLogMobs() {
let mobs = [];
$.each(total, function(mob, info) {
mobs.push(mob);
});
return mobs;
}
function getPasteInterval() {
let interval = parseInt($('.AutoPasterInterval').val());
interval = interval ? interval : 30;
interval = interval < 15 ? 15 : interval;
interval = interval > 60 ? 60 : interval;
return interval;
}
/* ############## API INTERACTION ############## */
function setUserPublic(s) {
lib.app.getRequest(app.name, 'https://digimol.net/idlescape/assets/api.php?a=userpublic&id='+lib.user.id+'&state='+s);
}
function canSubmit(logs) {
let can = true;
if (lib.user.getEnchantment('7') > 0) {
can = false;
}
if ((lib.user.isFighting() && logs.length < 1) || Object.keys(app.runs[0]).length === 0 || app.disabled) {
can = false;
}
return can;
}
function submitStats(logs, th) {
if (!canSubmit(logs)) {
return false;
}
lib.user.updateStatus();
let targetUrl = 'https://docs.google.com/forms/u/0/d/e/1FAIpQLSch3eG9Tqts0tIvnkk-C5JZeTwfbkWXhxkIpFnxyyaNO26h4Q/formResponse';
let logEntryId = 'entry.558332813';
let thEntryId = 'entry.22586929';
let noteEntryId = 'entry.1726819066';
let finalTH = (parseInt(th) > 0) ? 'TH '+th : 'None';
let fullUrl = targetUrl + '?'+ noteEntryId + '=Lootify-' + app.ver + '&' + thEntryId + '=' + encodeURIComponent(finalTH) + '&' + logEntryId + '=' + encodeURIComponent(logs.join('\n'));
if (!lib.user.isFighting()) {
th = 0;
} else {
$.get(fullUrl);
}
lib.app.getRequest(app.name, 'https://digimol.net/idlescape/assets/api.php?a=paste&th='+th+'&user='+lib.user.id+'&log='+encodeURIComponent(JSON.stringify(app.runs[0])));
lib.game.chat({
'msg': 'Lootify - Loot log pasted!',
'color': '#00a0fd',
});
}
app.getKills = function() {
if (!lib.user.id || lib.user.id == 0) { return false; }
lib.app.getRequest(app.name, 'https://digimol.net/idlescape/assets/api.php?a=getkills&id='+lib.user.id, function(d) {
lib.user.kills = d;
});
}
/* ############## SOCKET RESPONSES ############## */
app.initExp = function(d) {
let e = setInterval(()=> {
if (app.ready) {
clearInterval(e);
$.each(lib.app.data.active.skills, function(k, skill) {
!lib.user.exp ? lib.user.exp = {} : 1;
!lib.user.mexp ? lib.user.mexp = {} : 1;
!lib.user.exp[skill] ? lib.user.exp[skill] = {} : 1;
lib.user.exp[skill].init = parseInt(d.value.skills[skill].experience);
lib.user.exp[skill].current = parseInt(d.value.skills[skill].experience);
!lib.user.mexp[skill] ? lib.user.mexp[skill] = {} : 1;
lib.user.mexp[skill].init = parseInt(d.value.skills[skill].masteryExperience);
lib.user.mexp[skill].current = parseInt(d.value.skills[skill].masteryExperience);
});
}
});
}
app.updateExp = function(msg) {
let d = JSON.parse(msg)[1];
if (app.ready) {
$.each(lib.app.data.active.skills, function(k, skill) {
!lib.user.exp ? lib.user.exp = {} : 1;
!lib.user.exp[skill] ? lib.user.exp[skill] = {} : 1;
!lib.user.mexp ? lib.user.mexp = {} : 1;
!lib.user.mexp[skill] ? lib.user.mexp[skill] = {} : 1;
if (~msg.indexOf('"'+skill+'"')) {
lib.user.exp[skill].current = parseInt(d.value.experience);
lib.user.mexp[skill].current = parseInt(d.value.masteryExperience);
}
});
}
}
app.addLogMob = function(d) {
if (lib.user.lastAction === 'craft') {
lib.user.lastAction = '';
return false;
}
if (lib.game.isAllowedItem(lib.user.getStatus(), d.item.name)) {
let loc = lib.game.getLocationName(lib.user.location);
let item = lib.user.getStockpile(d.item.name);
let diff = item ? d.item.stackSize - item.stackSize : d.item.stackSize;
if (diff >= 3 && d.item.name !== 'Gold') { return false; }
!app.runs[0] ? app.runs[0] = {} : 1;
!app.runs[0][loc] ? app.runs[0][loc] = {} : 1;
!app.runs[0][loc].count ? app.runs[0][loc].count = 0 : 1;
app.runs[0][loc].count++;
!app.runs[0][loc].loot ? app.runs[0][loc].loot = {} : 1;
!app.runs[0][loc].loot[d.item.name] ? app.runs[0][loc].loot[d.item.name] = {} : 1;
!app.runs[0][loc].loot[d.item.name].count ? app.runs[0][loc].loot[d.item.name].count = 0 : 1;
!app.runs[0][loc].loot[d.item.name].procs ? app.runs[0][loc].loot[d.item.name].procs = 0 : 1;
if(d.item.name == 'Gold') {
app.runs[0][loc].loot[d.item.name].count += diff;
} else {
app.runs[0][loc].loot[d.item.name].count++;
diff >= 2 ? app.runs[0][loc].loot[d.item.name].procs++ : 1;
}
}
}
app.disablePaster = function() {
if (!app.disabled) {
app.disabled = true;
$('.drawer-setting-large.clone').text('Reset Log');
lib.game.chat({
'msg': "Lootify - Paster has been disabled to prevent skewed statistics. You can still use Lootify, but won't be able to paste your data to our server. Please reset your log to enable the paster again!",
'color': 'red',
'date': false
});
}
}
lib.app.setCommand('killcount', function() {
app.getKills();
let e = setInterval(()=> {
if(lib.user.kills) {
clearInterval(e);
let msg = '';
let $html = $('<div>');
let $wrap = $('<div>',{
'class': 'ltf-killcount-wrap'
}).appendTo($html);
$.each(lib.user.kills, function(mob, count) {
let $killcount = $('<div>', {
'class': 'ltf-killcount'
}).appendTo($wrap);
let $icon = $('<img>', {
'class': 'dialog-icon ltf-killcount-icon'
}).attr({
'src': lib.game.getMobIcon(mob)
}).appendTo($killcount);
let $text = $('<span>', {
'class': 'dialog-text-medium lft-killcount-text'
}).html(mob+': '+count).appendTo($killcount);
});
$('<div>', {
'class': 'dialog-disclaimer'
}).text('These are statistics submitted to Lootify only (updates every 15 minutes)').appendTo($html);
msg += $html.html();
lib.game.dialog({
'title': lib.user.name+' Kill Count',
'text': msg,
'class': 'ltf-killcount',
'type': 'close',
});
}
}, 100);
});
}
})();
if (!window.D4IS_Socket) {
window.D4IS_Socket = true;
const sockets = [];
const nativeWebSocket = window.WebSocket;
window.WebSocket = function(...args){
const socket = new nativeWebSocket(...args);
sockets.push(socket);
return socket;
};
let setupSocket = setInterval(()=> {
let lib = window.D4IS;
if(sockets.length != 0){
clearInterval(setupSocket);
sockets[0].addEventListener('message', (e) => socketMessageHandler(e));
}
}, 10);
}
function socketMessageHandler(e) {
let lib = window.D4IS;
let getHandler = setInterval(()=> {
if (lib) {
clearInterval(getHandler);
lib.app.messageHandler(e);
}
}, 10)
}
function includeJS(file) {
var script = document.createElement('script');
script.src = file;
script.type = 'text/javascript';
script.defer = false;
document.getElementsByTagName('head').item(0).appendChild(script);
}
function includeCSS(file) {
var style = document.createElement('link');
style.rel = 'stylesheet';
style.href = file;
style.type = 'text/css';
document.getElementsByTagName('head').item(0).appendChild(style);
}
if (typeof window.D4IS_JS == 'undefined') {
window.D4IS_JS = true;
includeJS('https://digimol.net/idlescape/assets/js/lib.js');
}
if (typeof window.D4IS_CSS == 'undefined') {
window.D4IS_CSS = true;
includeCSS('https://digimol.net/idlescape/assets/css/game.css');
}