Sleazy Fork is available in English.

HaremHeroes Automatic

Open the menu in HaremHeroes(topright) to toggle AutoControlls. Supports AutoSalary, AutoQuest, AutoTrollBattle and AutoArenaBattle. Messages are printed in local console.

06.07.2018 itibariyledir. En son verisyonu görün.

// ==UserScript==
// @name         HaremHeroes Automatic
// @namespace    JDscripts
// @version      2.91
// @description  Open the menu in HaremHeroes(topright) to toggle AutoControlls. Supports AutoSalary, AutoQuest, AutoTrollBattle and AutoArenaBattle. Messages are printed in local console.
// @author       JD
// @match        http*://nutaku.haremheroes.com/*
// @match        http*://*.hentaiheroes.com/*
// @require      https://cdn.jsdelivr.net/js-cookie/2.2.0/js.cookie.js
// @grant        GM_addStyle
// @license      MIT
// ==/UserScript==

GM_addStyle('/* The switch - the box around the slider */ .switch { position: relative; display: inline-block; width: 60px; height: 34px; } /* Hide default HTML checkbox */ .switch input {display:none;} /* The slider */ .slider { position: absolute; cursor: pointer; top: 0; left: 0; right: 0; bottom: 0; background-color: #ccc; -webkit-transition: .4s; transition: .4s; } .slider:before { position: absolute; content: ""; height: 26px; width: 26px; left: 4px; bottom: 4px; background-color: white; -webkit-transition: .4s; transition: .4s; } input:checked + .slider { background-color: #2196F3; } input:focus + .slider { box-shadow: 0 0 1px #2196F3; } input:checked + .slider:before { -webkit-transform: translateX(26px); -ms-transform: translateX(26px); transform: translateX(26px); } /* Rounded sliders */ .slider.round { border-radius: 34px; } .slider.round:before { border-radius: 50%; }');

function getHero()
{
    if(unsafeWindow.Hero === undefined)
    {
        setTimeout(autoLoop, Number(sessionStorage.autoLoopTimeMili))
        //console.log(window.wrappedJSObject)
    }
    return unsafeWindow.Hero;
}

function getGirlsMap()
{
    return unsafeWindow.GirlSalaryManager.girlsMap;
}

var proceedQuest = function () {
    //console.log("Starting auto quest.");
    var currentQuestURL = getHero().infos.questing.current_url;
    // Check if at correct page.
    if (currentQuestURL !== window.location.pathname) {
        // Click on current quest to naviagte to it.
        console.log("Navigating to current quest. ("+currentQuestURL+")");
        sessionStorage.autoLoop = "false";
        window.location = window.location.origin + currentQuestURL;
        return;
    }

    // Get the proceed button type
    var proceedButtonMatch = $("#controls button:not([style='display: none;'])");
    var proceedCostEnergy = Number($("#controls .cost span[cur='*']").text());
    var proceedCostMoney = Number($("#controls .cost span[cur='$']").text().trim().replace(',', ''));
    var proceedType = proceedButtonMatch.attr("act");

    if (proceedButtonMatch.length === 0) console.log("Could not find resume button.");
    else if (proceedType === "free") {
        console.log("Proceeding for free.");
        proceedButtonMatch.click();
    }
    else if (proceedType === "pay") {
        var energyCurrent = getHero().infos.energy_quest;
        var moneyCurrent = getHero().infos.soft_currency;
        if(proceedCostEnergy <= energyCurrent)
        {
            // We have energy.
            console.log("Spending "+proceedCostEnergy+" Energy to proceed.");
        }
        else
        {
            console.log("Quest requires "+proceedCostEnergy+" Energy to proceed.");
            sessionStorage.questRequirement = "*"+proceedCostEnergy;
            return;
        }
        if(proceedCostMoney <= moneyCurrent)
        {
            // We have money.
            console.log("Spending "+proceedCostMoney+" Money to proceed.");
        }
        else
        {
            console.log("Spending "+proceedCostEnergy+" Money to proceed.");
            sessionStorage.questRequirement = "$"+proceedCostMoney;
            return;
        }
        proceedButtonMatch.click();
        sessionStorage.autoLoop = "false";
        location.reload();
    }
    else if (proceedType === "use_item") {
        console.log("Proceeding by using X" + Number($("#controls .item span").text()) + " of the required item.");
        proceedButtonMatch.click();
    }
    else if (proceedType === "battle") {
        console.log("Proceeding to battle troll...");
        sessionStorage.questRequirement = "battle";
        // Proceed to battle troll.
        proceedButtonMatch.click();
        sessionStorage.autoLoop = "false";
        location.reload();
    }
    else if (proceedType === "end_archive") {
        console.log("Reached end of current archive. Proceeding to next archive.");
        sessionStorage.autoLoop = "false";
        proceedButtonMatch.click();
    }
    else if (proceedType === "end_play") {
        console.log("Reached end of current play. Proceeding to next play.");
        sessionStorage.autoLoop = "false";
        proceedButtonMatch.click();
    }
    else {
        console.log("Could not identify given resume button.");
        sessionStorage.questRequirement = "unknownQuestButton";
    }
};

function getPage()
{
    try{
        var ob = document.getElementById("hh_nutaku");
        if(ob===undefined || ob === null)
        {
            ob = document.getElementById("hh_hentai");
        }
        return ob.className.match(/.*page-(.*) .*/i)[1];
    }
    catch(err)
    {
        return ""
    }
}

/**
* Recieves a list of mission objects and returns the mission object to use.
* A mission object looks similar to this :-
*     {cost:"3",duration:"267", id_member_mission:"256160092", id_mission:"35", remaining_cost:0, remaining_time:"102"}
* cost is the koban price for instant complete.
*/
function getSuitableMission()
{
}

// returns boolean to set busy
function doMissionStuff()
{
    if(getPage() !== "missions")
    {
        console.log("Navigating to activities page.");
        sessionStorage.autoLoop = "false";
        window.location = window.location.origin + $("nav div[rel='content'] a:has(.activities)").attr("href");
        // return busy
        return true;
    }
    else
    {
        console.log("On activities page.");
        console.log("Collecting finished mission's reward.");
        $(".mission_button button:visible[rel='claim']").click();
        // TODO: select new missions and parse reward data from HTML, it's there in data attributes of tags
        var missions = [];
        $(".mission_object").each(function(idx,data){
            missions.push($.data(data).d);
        });

        // not busy
        return false;
    }
}

// returns boolean to set busy
function doContestStuff()
{
    if(getPage() !== "missions")
    {
        console.log("Navigating to activities page.");
        sessionStorage.autoLoop = "false";
        window.location = window.location.origin + $("nav div[rel='content'] a:has(.activities)").attr("href");
        // return busy
        return true;
    }
    else
    {
        console.log("On activities page.");
        console.log("Collecting finished contests's reward.");
        $(".contest .ended button[rel='claim']").click();
        // need to get next contest timer data
        var time = 0;
        for(var e in unsafeWindow.HHTimers.timers){
            if(unsafeWindow.HHTimers.timers[e].$elm.selector.includes(".contest_timer"))
                time=unsafeWindow.HHTimers.timers[e];
        }
        time = time.remainingTime;
        Cookies.set('nextContestTime',time,{expires:new Date(new Date().getTime() + time * 1000)});
        console.log("Next contest time stored in nextContestTime cookie.(+" + time + " sec.)");
        // Not busy
        return false;
    }
}

var getSalary = function () {
    try {
        if (getPage() === "harem") {
            console.log("Detected Harem Screen. Fetching Salary");
            $("#harem_whole #harem_left .salary:not('.loads') button").each(function (index) {
                $(this).click();
            });
            console.log("Salary fetched. Getting next fetch time");
            // In seconds
            var closestTime = undefined;
            var gMap = getGirlsMap();
            if(gMap === undefined)
            {
                // error
                console.log("Girls Map was undefined...! Error, manually setting salary time to 2 min.");
                closestTime = 2*60;
            }
            else
            {
                try{
                    // Calc. closest time
                    for(var key in gMap)
                    {
                        // undefined comparision is always false so first iteration is false, hence the not(!)
                        if(!(closestTime<gMap[key].gData.pay_in))
                        {
                            closestTime = gMap[key].gData.pay_in;
                        }
                    }
                }
                catch(exp){
                    // error
                    console.log("Girls Map had undefined property...! Error, manually setting salary time to 2 min.");
                    closestTime = 2*60;
                }
            }
            if(closestTime === undefined)
            {
                console.log("closestTime was undefined...! Error, manually setting salary time to 2 min.");
                closestTime = 2*60;
            }
            if(closestTime <= 2)
            {
                console.log("closestTime is less than/equal to 2 sec. Staying on this page.");
                // return busy
                return true;
            }
            Cookies.set('nextSalaryTime',closestTime,{expires:new Date(new Date().getTime() + closestTime * 1000)});
            console.log("New fetch time stored in nextSalaryTime cookie.(+" + closestTime + " sec.)");
            // return not busy
            return false;
        }
        else {
            // Not at Harem screen then goto the Harem screen.
            console.log("Navigating to Harem window.");
            sessionStorage.autoLoop = "false";
            window.location = window.location.origin + $("nav div[rel='content'] a:has(.harem)").attr("href");
            // return busy
            return true;
        }
    }
    catch (ex) {
        console.log("Could not collect salary... " + ex);
        // return not busy
        return false;
    }
};

var doBossBattle = function()
{
    var currentPower = getHero().infos.energy_fight;
    if(currentPower < 1)
    {
        //console.log("No power for battle.");
        return;
    }
    // Battles the latest boss.
    // Navigate to latest boss.
    if(window.location.pathname.startsWith("/battle.html"))
    {
        // On the battle screen.
        doBattle();
    }
    else if(window.location.pathname.startsWith("/quest"))
    {
        // On some quest screen.
        // Goto this area's screen.
        console.log("Navigating to latest Troll.");
        sessionStorage.autoLoop = "false";
        window.location = window.location.origin + $("#breadcrumbs a[class='back']").last().attr("href");
        return;
    }
    else if(window.location.pathname.startsWith("/world"))
    {
        // On some world screen.
        // Click on the local Boss's battle button.
        console.log("Entering battle with this troll.");
        sessionStorage.autoLoop = "false";
        window.location = window.location.origin + $("#worldmap a[class='troll_world']").attr("href");
        return;
    }
    else{
        console.log("Navigating to latest Troll.");
        sessionStorage.autoLoop = "false";
        window.location = window.location.origin + $("nav div[rel='content'] a:has(.continue_quest)").attr("href");
        return;
    }
};

var doBattle = function () {
    //console.log("Performing auto battle.");
    // Confirm if on correct screen.
    var page = getPage();
    if(page === "arena")
    {
        if ($("#arena[class='canvas']").length === 1) {
            // Oponent choose screen
            console.log("On opponent choose screen.");
            // Fight the first opponent in list.
            var selbutton = $(".opponents_arena .sub_block button:contains('Select')");
            if(selbutton.length<1)
            {
                console.log("No arena opponents found, storing nextArenaTime...")
                var arenatime = 0;
                for(var e in unsafeWindow.HHTimers.timers){
                    if(unsafeWindow.HHTimers.timers[e].$elm.selector.startsWith(".arena_refresh_counter"))
                        arenatime=unsafeWindow.HHTimers.timers[e];
                }
                arenatime = arenatime.remainingTime;
                Cookies.set('nextArenaTime',arenatime,{expires:new Date(new Date().getTime() + arenatime * 1000)});
                console.log("New arena time stored in nextArenaTime cookie.(+" + arenatime + " sec.)");
                return;
            }
            selbutton[0].click();
            sessionStorage.autoLoop = "false";
        }
    }
    else if (page === "battle") {
        // On battle page.
        //console.log("On Battle Page.");
        if ($("#battle[class='canvas']").length === 1) {
            // Battle screen
            console.log("On battle screen.");
            // get button with no autofight, i.e. no koban
            var battleButton = $("#battle_middle button[rel='launch']:not(.autofight)");
            var currentPower = getHero().infos.energy_fight;
            if(battleButton === undefined){
                console.log("Battle Button was undefined. Disabling all auto-battle.");
                document.getElementById("autoBattleCheckbox").checked = false;
                document.getElementById("autoArenaCheckbox").checked = false;
                if (sessionStorage.questRequirement === "battle")
                {
                    document.getElementById("autoQuestCheckbox").checked = false;
                    console.log("Auto-quest disabled since it requires battle and auto-battle has errors.");
                }
                return;
            }
            var battle_price = battleButton.attr("price_fe");
            if(battle_price === undefined){
                console.log("Could not detect battle button price. Error.");
                console.log("Disabling all auto-battle.");
                document.getElementById("autoBattleCheckbox").checked = false;
                document.getElementById("autoArenaCheckbox").checked = false;
                if (sessionStorage.questRequirement === "battle")
                {
                    document.getElementById("autoQuestCheckbox").checked = false;
                    console.log("Auto-quest disabled since it requires battle and auto-battle has errors.");
                }
                return;
            }
            console.log("battle price: "+battle_price+"P")
            if(currentPower >= battle_price)
            {
                // We have the power.
                battleButton.click();
                // Skip
                setTimeout(function(){$("#battle_middle button[rel='skip']").click();},1000);
                setTimeout(function(){$("#battle_end div[style*='display: block;'] .blue_text_button").click();},2500);

                if (sessionStorage.questRequirement === "battle") {
                    // Battle Done.
                    sessionStorage.questRequirement = "none";
                }
            }
            else
            {
                // We need more power.
                console.log("Battle requires "+battle_price+" power.");
                sessionStorage.battlePowerRequired = battle_price;
                if(sessionStorage.questRequirement === "battle")sessionStorage.questRequirement = "P"+battle_price;
            }
        }
        else {
            console.log("Could not identify battle screen.");
            if (sessionStorage.questRequirement === "battle") sessionStorage.questRequirement = "errorInAutoBattle";
            return;
        }
    }
    else
    {
        // Switch to the correct screen
        console.log("Switching to battle screen.");
        window.location = window.location.origin + $("nav div[rel='content'] a:has(.battle)").attr("href");
        sessionStorage.autoLoop = "false";
        return;
    }
};

var updateData = function () {
    //console.log("updating UI");
    sessionStorage.autoSalary = document.getElementById("autoSalaryCheckbox").checked;
    sessionStorage.autoContest = document.getElementById("autoContestCheckbox").checked;
    sessionStorage.autoQuest = document.getElementById("autoQuestCheckbox").checked;
    sessionStorage.autoTrollBattle = document.getElementById("autoBattleCheckbox").checked;
    sessionStorage.autoArenaBattle = document.getElementById("autoArenaCheckbox").checked;
    sessionStorage.autoFreePachinko = document.getElementById("autoFreePachinko").checked;
};

var getPachinko = function(){
    try {
        if (getPage() === "pachinko") {
            console.log("Detected Pachinko Screen. Fetching Pachinko");
            $("#pachinko button[free=1]")[0].click();
            var npach;
            for(var e in unsafeWindow.HHTimers.timersListMin){
                if(unsafeWindow.HHTimers.timersListMin[e].$elm.selector.startsWith(".pachinko_change"))
                    npach=unsafeWindow.HHTimers.timersListMin[e].remainingTime;
            }
            if(npach !== undefined || npach !== 0)
            {
                Cookies.set('nextPachinkoTime',npach,{expires:new Date(new Date().getTime() + npach * 1000)});
            }
            else
            {
                Cookies.remove('nextPachinkoTime');
            }
        }
        else {
            // Not at Pachinko screen then goto the Pachinko screen.
            console.log("Navigating to Pachinko window.");
            sessionStorage.autoLoop = "false";
            window.location = window.location.origin + $("nav div[rel='content'] a:has(.pachinko)").attr("href");
            return;
        }
    }
    catch (ex) {
        console.log("Could not collect pachinko... " + ex);
    }
};

var autoLoop = function () {
    updateData();
    var busy = false;
    var page = window.location.href;
    var currentPower = getHero().infos.energy_fight;
    //console.log("sal="+sessionStorage.autoSalary);
    if(sessionStorage.autoFreePachinko === "true" && busy === false){
        // Navigate to pachinko
        if (Cookies.get("nextPachinkoTime") === undefined) {
            console.log("Time to fetch Pachinko.");
            getPachinko();
            busy = true;
        }
    }
    if(sessionStorage.autoContest === "true" && busy === false){
        if (Cookies.get("nextContestTime") === undefined){
            console.log("Time to get contest rewards.");
            busy = doContestStuff();
        }
    }
    if (sessionStorage.autoSalary === "true" && busy === false) {
        if (Cookies.get("nextSalaryTime") === undefined) {
            console.log("Time to fetch salary.");
            busy = getSalary();
        }
    }
    if (sessionStorage.autoQuest === "true" && busy === false) {
        if (sessionStorage.questRequirement === "battle") {
            console.log("Quest requires battle.");
            doBossBattle();
            busy = true;
        }
        else if (sessionStorage.questRequirement[0] === '$') {
            if (Number(sessionStorage.questRequirement.substr(1)) < getHero().infos.soft_currency) {
                // We have enough money... requirement fulfilled.
                console.log("Continuing quest, required money obtained.");
                sessionStorage.questRequirement = "none";
                proceedQuest();
                busy = true;
            }
            else {
                if(isNaN(sessionStorage.questRequirement.substr(1)))
                {
                    sessionStorage.questRequirement = "none";
                    console.log("Invalid money in session storage quest requirement !");
                }
                else{
                    // Else we need more money.
                    //console.log("Need money for quest, cannot continue. Turning ON AutoSalary.");
                    sessionStorage.autoQuest = "true";
                }
                busy = false;
            }
        }
        else if (sessionStorage.questRequirement[0] === '*') {
            var energyNeeded = Number(sessionStorage.questRequirement.substr(1));
            var energyCurrent = getHero().infos.energy_quest;
            if (energyNeeded <= energyCurrent) {
                // We have enough energy... requirement fulfilled.
                console.log("Continuing quest, required energy obtained.");
                sessionStorage.questRequirement = "none";
                proceedQuest();
                busy = true;
            }
            // Else we need energy, just wait.
            else {
                busy = false;
                //console.log("Replenishing energy for quest.(" + energyNeeded + " needed)");
            }
        }
        else if (sessionStorage.questRequirement[0] === 'P')
        {
            // Battle power required.
            var neededPower = Number(sessionStorage.questRequirement.substr(1));
            if(currentPower < neededPower)
            {
                console.log("Quest requires "+neededPower+" Battle Power for advancement. Waiting...");
                busy = false;
            }
            else
            {
                console.log("Battle Power obtained, resuming quest...");
                sessionStorage.questRequirement = "none";
                proceedQuest();
                busy = true;
            }
        }
        else if (sessionStorage.questRequirement === "unknownQuestButton") {
            console.log("AutoQuest disabled.AutoQuest cannot be performed due to unknown quest button. Please manually proceed the current quest screen.");
            document.getElementById("autoQuestCheckbox").checked = false;
            sessionStorage.autoQuest = "false";
            sessionStorage.questRequirement = "none";
            busy = false;
        }
        else if (sessionStorage.questRequirement === "errorInAutoBattle") {
            console.log("AutoQuest disabled.AutoQuest cannot be performed due errors in AutoBattle. Please manually proceed the current quest screen.");
            document.getElementById("autoQuestCheckbox").checked = false;
            sessionStorage.autoQuest = "false";
            sessionStorage.questRequirement = "none";
            busy = false;
        }
        else if(sessionStorage.questRequirement === "none")
        {
            //console.log("NONE req.");
            busy = true;
            proceedQuest();
        }
        else
        {
            console.log("Invalid quest requirement : "+sessionStorage.questRequirement);
            busy=false;
        }
    }
    else if(sessionStorage.autoQuest === "false"){sessionStorage.questRequirement = "none";}

    if(sessionStorage.autoArenaBattle === "true" && busy === false)
    {
        if(Cookies.get("nextArenaTime") === undefined)
        {
            console.log("Time to fight in arena.");
            doBattle();
            busy = true;
        }
    }

    if(sessionStorage.autoTrollBattle === "true")
    {
        if(busy === false && currentPower >= Number(sessionStorage.battlePowerRequired) && currentPower > 0)
        {
            sessionStorage.battlePowerRequired = "0";
            busy = true;
            if(sessionStorage.autoQuest === "true")
            {
                if(sessionStorage.questRequirement[0] === 'P')
                {
                    console.log("AutoBattle disabled for power collection for AutoQuest.");
                    document.getElementById("autoBattleCheckbox").checked = false;
                    sessionStorage.autoTrollBattle = "false";
                    busy = false;
                }
                else
                {
                    doBossBattle();
                }
            }
            else
            {
                doBossBattle();
            }
        }
    }
    else{sessionStorage.battlePowerRequired = "0";}

    if(busy === true && sessionStorage.userLink==="none" && !window.location.pathname.startsWith("/quest"))
    {
        sessionStorage.userLink = page;
    }
    else if(sessionStorage.userLink !=="none" && busy === false)
    {
        console.log("Restoring page "+sessionStorage.userLink);
        window.location = sessionStorage.userLink;
        sessionStorage.userLink = "none";
    }

    if(isNaN(sessionStorage.autoLoopTimeMili)){
        console.log("AutoLoopTimeMili is not a number.");
        setDefaults();
    }
    else{
        if (sessionStorage.autoLoop === "true") setTimeout(autoLoop, Number(sessionStorage.autoLoopTimeMili));
        else console.log("autoLoop Disabled");
    }
};

var setDefaults = function () {
    console.log("Setting Defaults.");
    sessionStorage.autoSalary = "false";
    sessionStorage.autoContest = "false";
    sessionStorage.autoFreePachinko = "false";
    sessionStorage.autoLoop = "true";
    sessionStorage.userLink = "none";
    sessionStorage.autoLoopTimeMili = "200";
    sessionStorage.autoQuest = "false";
    sessionStorage.autoTrollBattle = "false";
    sessionStorage.autoArenaBattle = "false";
    sessionStorage.battlePowerRequired = "0";
    sessionStorage.questRequirement = "none";
    sessionStorage.freshStart = "no";
};

var start = function () {
    //console.log("script started");
    // Add UI buttons.
    var UIcontainer = $("#contains_all nav div[rel='content']");
    UIcontainer.html('<div style="position: absolute;right: -16.475%; padding: 10px;width: inherit;text-align: center;display:flex;flex-direction:column;">'
                     + '<span>AutoSal.</span><div><label class=\"switch\"><input id=\"autoSalaryCheckbox\" type=\"checkbox\"><span class=\"slider round\"></span></label></div>'
                     + '<span>AutoContest</span><div><label class=\"switch\"><input id=\"autoContestCheckbox\" type=\"checkbox\"><span class=\"slider round\"></span></label></div>'
                     +'<span>AutoQuest</span><div><label class=\"switch\"><input id=\"autoQuestCheckbox\" type=\"checkbox\"><span class=\"slider round\"></span></label></div>'
                     +'<span>AutoTrollBattle</span><div><label class=\"switch\"><input id=\"autoBattleCheckbox\" type=\"checkbox\"><span class=\"slider round\"></span></label></div>'
                     +'<span>AutoArenaBattle</span><div><label class=\"switch\"><input id=\"autoArenaCheckbox\" type=\"checkbox\"><span class=\"slider round\"></span></label></div>'
                     +'<span>AutoPachinko(Free)</span><div><label class=\"switch\"><input id=\"autoFreePachinko\" type=\"checkbox\"><span class=\"slider round\"></span></label></div>'
                     +'</div>'+UIcontainer.html());
    document.getElementById("autoSalaryCheckbox").checked = sessionStorage.autoSalary === "true";
    document.getElementById("autoContestCheckbox").checked = sessionStorage.autoContest === "true";
    document.getElementById("autoQuestCheckbox").checked = sessionStorage.autoQuest === "true";
    document.getElementById("autoBattleCheckbox").checked = sessionStorage.autoTrollBattle === "true";
    document.getElementById("autoArenaCheckbox").checked = sessionStorage.autoArenaBattle === "true";
    document.getElementById("autoFreePachinko").checked = sessionStorage.autoFreePachinko === "true";
    sessionStorage.autoLoop = "true";
    if (typeof sessionStorage.freshStart == "undefined" || isNaN(Number(sessionStorage.autoLoopTimeMili))) {
        setDefaults();
    }
    autoLoop();
};
$("document").ready(start);