Ikariam Auto Builder HACK lets you add your building to an upgrading queue (YES! NOW YOU CAN DO IT FOR FREE!).
// ==UserScript== // @name Ikariam Auto Builder script // @namespace http://google.com/ // @version 3.3.2 // @description Ikariam Auto Builder HACK lets you add your building to an upgrading queue (YES! NOW YOU CAN DO IT FOR FREE!). // @unwrap // @include *://s*.ikariam.gameforge.com/* // @match *://s*.ikariam.gameforge.com/* // @copyright 2017-2026, Daniels Šatcs, [email protected] // @grant unsafeWindow // @run-at document-idle // ==/UserScript== this.$ = this.jQuery = jQuery.noConflict(true); iframe = document.createElement('iframe'); document.body.appendChild(iframe); console = { error: iframe.contentWindow.console.log, log: function() {}}; var key_currentUpdateInterval = "current_update_interval"; let key_state = "script_state"; var updateInterval = getValue(key_currentUpdateInterval, 600000); var timerUpdateInterval = 1000; //In ms (1000 ms = 1s). This indicates how often will be the timer refreshed. RECOMMENDED: 1000 //TRANSLATIONS// var addToQueueText = "Add to queue"; //This appears on the button var queueEmptyText = "The building queue is empty in the selected city"; //This appears when the queue is empty var VERBOSE = true; //Set to true to print (to console) information about what is going on. var queuePrefix = "IAcity_"; //do NOT change this! var separator = ";"; ////do NOT change this! class ScriptState { constructor(data = {}) { this.cityIds = data.cityIds ?? []; this.cityCount = this.cityIds.length; // This ensures lastProcessed is ALWAYS at least an empty object this.lastProcessed = data.lastProcessed ?? {}; } save() { // alert("Saving " + JSON.stringify(this)); setValue(key_state, JSON.stringify(this)); } } function setProcessed(state, cityId) { if (state.lastProcessed === undefined) { state.lastProcessed = {}; } state.lastProcessed[cityId] = Date.now(); state.save(); } function getLastProcessed(state, cityId) { return state.lastProcessed[cityId] ?? 0; } function getState() { let value = getValue(key_state); if (value === undefined) { return undefined; } else { const parsedData = JSON.parse(value); return new ScriptState(parsedData); } } function initUI() { // Append queue table immediately when the specific container is found waitForElement("div.city_water_bottom").then(() => { if ($("#IA_queue").length === 0) { $("div.city_water_bottom").append('<div id="IA_queue" style="background-color: #DDD; width: 300px; position: absolute; left: 810px; border-radius: 4px; border: 1px solid #555"></div>'); setTimeout(updateQueueView, 200); } }); } //Script entry point: initUI(); setTimeout(start, 1000); function changeUpdateInterval(){ updateInterval = Math.floor((Math.random() * (900000-600000+1)) + 600000); //Math.round((Math.random() * (Max-Min)) + Min); setValue(key_currentUpdateInterval, updateInterval); return updateInterval; } function callFunc(f,params){ f.apply(this, params); } window.doAfterLoading = doAfterLoading; function doAfterLoading(f){ if(!isLoading()){ var params = Array.prototype.slice.call(arguments); params.shift(); f.apply(this,params); } else setTimeout(callFunc, 100, doAfterLoading, arguments); } function goToCity(id) { const url = new URL(window.location.href); const params = new URLSearchParams(url.search); params.set("cityId", id); params.set("currentCityId", id); url.search = params.toString(); window.location.href = url.toString(); // $("div#js_citySelectContainer span").click(); // setTimeout(clickCityInDropDown, 100, id, callback); //Must wait here a little, bacause city drop down doesn't open immediately } function getCityName(){ return $("div#js_citySelectContainer span a").text(); } function getCityId() { const params = new URLSearchParams($("#js_CityPosition0Link").attr("href")); // const url = new URL(window.location.href); // const params = new URLSearchParams(url.search); return params.get('cityId'); } function getQueue(){ var raw = getValue(queuePrefix + getCityId()); if(raw === undefined) return []; return raw.split(separator); } function canUpgrade() { return enoughResources() && !isUpgrading() } function inBuildingView() { return $("#buildingUpgrade").length > 0; // The building upgrade window is open } function enoughResources() { return inBuildingView() && $("div#buildingUpgrade ul.resources li.red").length === 0; // No resource is displayed as red (i.e. enough resources) } function addToQueue(id) { if (canUpgrade()) { $("ul.actions li.upgrade a").click(); } else { var before = getValue(queuePrefix + getCityId()); if(before === undefined){ setValue(queuePrefix + getCityId(), id); } else setValue(queuePrefix + getCityId(), before + separator + id); updateQueueView(); } } function removeFromQueue(number){ console.error("Removing building " + number + " from update queue of city " + getCityName()); var before = getValue(queuePrefix + getCityId()); if(before !== undefined){ var after = ""; var items = before.split(separator); for(var i = 0; i < items.length; i++){ if(i != number) after = after + items[i] + separator; } after = after.substring(0,after.length-1); if(after === ""){ deleteValue(queuePrefix + getCityId()); } else { setValue(queuePrefix + getCityId(), after); } } updateQueueView(); } function upgradeBuilding(){ if($("div#buildingUpgrade ul.resources li.red").length === 0){ //If the city has enough resources for an upgrade $("ul.actions li.upgrade a").click(); //Clicks upgrade button doAfterLoading(closeWindow); removeFromQueue(0); if (VERBOSE) console.error("Upgrading and removing from queue!") } else { if (VERBOSE) console.error("Not enough resources, skipping"); setTimeout(closeWindow, 100); } } function closeWindow(){ $("div.close").click(); } function getCitySkipDelay(){ return Math.floor(Math.random() * (1000 - 500 + 1)) + 500; //Math.floor(Math.random() * (max - min + 1)) + min; Time to pause before going to the next city. Just for aesthetic purposes. } function isLoading(){ return $("div#loadingPreview").css("display") != "none"; } function isUpgrading(){ return $("div.buildingUpgradeIcon:visible").length > 0; } function countdownPopupClose() { var el = $("#closePopupButton"); timeLeft = el.text().substring(6); timeLeft -= 1; el.text("Close " + timeLeft); if (timeLeft <= 0) { hideUpgradePopup(); } else setTimeout(countdownPopupClose, 1000); } function doWorkInCity(onDone) { let cityId = getCityId(); var info = "<li style='list-style: unset;'>" + getCityName() + ": "; if (VERBOSE) console.error(" ========== CITY = " + (cityId + " ========== ")); var q = getQueue(); var upgrading = isUpgrading(); if(q.length === 0 || upgrading) { //Can't upgrade anything in this city. Go to the next city in that case. if(VERBOSE) { causes = []; if (q.length === 0) causes.push("queue is empty"); if (upgrading) causes.push("something is upgrading"); info += "Nothing to do because " + causes.join(", ") + "</li>"; console.error("Skipping city " + cityId + ": " + causes.join(", ")); } onDone() } else { if (VERBOSE) console.error("Trying to upgrade... (since queue not empty and nothing upgrading a.t.m."); var enoughResources = $("#js_CityPosition" + q[0] + "ScrollName").css("color") != "rgb(170, 3, 3)" info += "Next in queue: " + getBuildingTitle(q[0]) + (enoughResources ? " <span style='color: green;'>Upgrading!</span>" : " <span style='color: red;'>Not enough resources, not removing from queue</span>"); openBuilding(q[0]); doAfterLoading(upgradeBuilding); } $("#upgradeProgressList").append(info); } function anyWindowOpen(){ return $("div.accordionContent").length !== 0; } function processCity(onDone){ if(anyWindowOpen()){ closeWindow(); setTimeout(processCity, 100, onDone); return; } setTimeout(doWorkInCity, getCitySkipDelay(), onDone) } function getBuildingTitle(id){ return $("a#js_CityPosition" + id + "Link").attr('title'); } function updateQueueView() { $("div#IA_queue").text(""); var queue = getQueue(); if(queue.length !== 0){ for(var i = 0; i < queue.length; i++){ $("div#IA_queue").append('<p align="center" style="cursor:default; padding: 8px;">' + getBuildingTitle(queue[i]) + '<a onclick="removeFromQueue('+i+')" style="cursor:pointer;">✖</a></p>'); } } else $("div#IA_queue").append('<p align="center">' + queueEmptyText + '</p>'); } function update(){ var dialogCss = `position: fixed; width: 500px; height: 200px; top: 50%; left: 50%; margin-top: -100px; /* Negative half of height. */ margin-left: -250px; /* Negative half of width. */ background-color: rgb(250, 243, 215); z-index: 100; padding: 20px; overflow: scroll;`; // $("body").append(` // <div id="IAB-upgrade-popup" style="${dialogCss}"> // <h2 style="font-size: 120%; font-weight: 700;"> Trying to upgrade buildings from the queue ... </h2> // <ol id="upgradeProgressList"> // // </ol> // </div> // `); let state = getState(); let currentCity = getCityId(); for (let cityId of state.cityIds) { if (getLastProcessed(state, cityId) < parseInt(Date.now()) - parseInt(updateInterval)) { if (cityId != currentCity) { goToCity(cityId); return; } else { break; } } } if (getLastProcessed(state, currentCity) < parseInt(Date.now()) - parseInt(updateInterval)) { if($("div.close").length > 0) $("div.close").click(); setValue("IA_lastUpdate", Date.now()); changeUpdateInterval(); processCity(function() { setProcessed(state, currentCity); state.save(); setTimeout(update, getCitySkipDelay()); }); return; } else { // let idx = state.cityIds.indexOf(currentCity); // let nextIdx = idx + 1 // if (nextIdx < state.cityCount) { // goToCity(state.cityIds[nextIdx]); // } else { // console.log("Done, nextIdx = " + nextIds); // } } } function hideUpgradePopup() { $("#IAB-upgrade-popup").remove(); } function openBuilding(id){ $("a#js_CityPosition" + id + "Link").click(); } function getCityCount(){ return $("#dropDown_js_citySelectContainer li.ownCity").length; } function getCityIds() { return $("#dropDown_js_citySelectContainer li.ownCity").map(function() { return $(this).attr("selectvalue"); }).get(); } function setValue(key,value) { localStorage[key]=value; } function getValue(key,def) { return localStorage[key] || def; } function deleteValue(key) { return delete localStorage[key]; } function timerUpdateFunc() { var time = parseInt(getValue("IA_lastUpdate")) + parseInt(updateInterval) - parseInt(Date.now()); time = Math.floor(time / 1000); //seconds let secondsLeft = time; if (secondsLeft % 5 == 0) { setTimeout(update, 200); } var minutes = Math.floor(time / 60); time -= minutes * 60; if (time < 10) time = "0" + time; //replace 2:9 with 2:09 $("li#IA_timer").text(minutes + ":" + time); if(minutes < 0){ update(); } } function addButton(buildingId) { var canUpgradeImmediately = canUpgrade(); console.error("Can upgrade " + canUpgradeImmediately); var buttonText = addToQueueText; if(anyWindowOpen() && inBuildingView() && $("div#IAButtonContainer").length === 0) { if($("ul.actions li.upgrade a").length > 0) { if (!canUpgradeImmediately) $("div#buildingUpgrade").append('<div style="margin: 20px;" id="IAButtonContainer"><a class="button" id="IAButton" onclick="addToQueue('+ buildingId + ');">' + buttonText + '</a></div>'); if (!canUpgradeImmediately && !enoughResources()) $("div#buildingUpgrade").append('<div style="margin: 20px;"><i>Upgrade will stay in the queue until you collect necessary resources or you remove it from the queue.</i></div>'); } } else setTimeout(addButton, 100, buildingId); } function addAdvisor() { $("div#advisors ul").prepend('<li class="advisor_bubble">' + '<a id="js_GlobalMenu_builder" href="javascript:advisorWindow()" title="Overview of towns and finances" class="normalactive">' + '<span class="smallFont">Auto builder</span>' + '</a>' + '<a id="js_GlobalMenu_builderPremium" class="plus_button plusteaser" title="View building queues"></a>' + '</li>'); var container = $("div#advisors"); container.width(container.width() / 4 * 5); } function advisorWindow() { var html = '<div id="architect_c" class="templateView focusable focus" style="left: 725px; top: -56px; right: auto; z-index: 98;">' + '<div id="architect" class="mainContentBox contentBox01h toggleMenu"><div class="hd header mainHeader draggable"><h3 id="js_mainBoxHeaderTitle">Auto Builder`s Office</h3><div id="js_backlinkButton" class="back" title="Hideout"></div><div class="close"></div></div><div class="bd mainContentScroll" style="height: 350px;"><div class="scroll_area scroll_disabled"><div class="scroll_arrow_top"></div><div class="scroller" style="width: 5px; top: 0px; left: 0px;"></div><div class="scroll_arrow_bottom"></div></div><div class="mainContent minimizableContent" style="top: 0px;"><div class="center" style="height: 60px; padding-bottom: 8px;"><a onclick="ajaxHandlerCall(\'?view=premium\');return false;"><img class="clickable" src="//gf1.geo.gfsrv.net/cdn0f/d3040171fefe8f8a0bbc75f6c8b344.jpg"></a></div>' + ' <div id="reductionBuilding">' + ' <div class="buildingDescription">' + ' <h1>Auto Builder\`s Office</h1>' + ' <p></p>' + ' </div>' + ' <div class="contentBox01h">' + ' <div class="buildingPictureImg"><img src="//gf1.geo.gfsrv.net/cdn6b/898c4f2181909413623c079be63094.png"></div>' + ' <h3 class="header">Building queues in your cities</h3>' + ' <div class="content">' + ' </div>' + ' <div class="footer"></div>' + ' </div> </div>' + ' </div></div><div class="ft footer"></div></div></div>'; $("div#container").append(html); } function waitForElement(selector) { return new Promise(resolve => { if (document.querySelector(selector)) { return resolve(document.querySelector(selector)); } const observer = new MutationObserver(mutations => { if (document.querySelector(selector)) { observer.disconnect(); resolve(document.querySelector(selector)); } }); observer.observe(document.body, { childList: true, subtree: true }); }); } function start(){ if($("#btn-login").length > 0) return; //addAdvisor(); try { getCityCount(); } catch(e){ alert("Sorry, Ikariam Auto Builder Hack won't work in this browser. Please use Chrome or Opera!"); } waitForElement("#dropDown_js_citySelectContainer li.ownCity").then((el) => { let state = getState(); if (state === undefined) { new ScriptState(getCityIds()).save(); } else { // Not the first run. Just check if any new cities were added. state.cityIds = getCityIds(); state.cityCount = state.cityIds.length; state.save(); } }); // alert("Updating...") update(); $("a[id^='js_CityPosition']").click(function(){ var htmlID = $(this).attr('id'); var id = htmlID.split("Link")[0].substring(15,htmlID.length + 1 - 4); doAfterLoading(addButton, id); }); //Add CSS styling for add to queue button $("head").append("<style>div.addToQueueCityButton {z-index: 9000; cursor: pointer; position: absolute;right: 0px;bottom: 0px;border-top-left-radius: 3px;border-top-right-radius: 3px;border-bottom-left-radius: 3px;border-bottom-right-radius: 3px; background-color: rgba(200,200,200, 1); -webkit-transition: background-color 300ms linear;-moz-transition: background-color 300ms linear;-o-transition: background-color 300ms linear;-ms-transition: background-color 300ms linear;transition: background-color 300ms linear;} div.addToQueueCityButton:hover { background-color: rgba(200,100,100,1);}</style>"); //Append queue table $("div.city_water_bottom").append('<div id="IA_queue" style="background-color: #DDD; width: 300px; position: absolute; left: 810px; border-radius: 4px; border: 1px solid #555"></div>'); //Append timer $("DIV#GF_toolbar ul").append('<li id="IA_timer"></li> <img id="doCheckButton" alt="Check upgrades now" src="https://res.cloudinary.com/dshatz/image/upload/v1505664588/refresh_etrdy3.png" style="height: 1em; cursor:pointer;">'); $("DIV#GF_toolbar ul").append('<li id="IA_script_feedback"><a target="_blank" href="https://greasyfork.org/en/scripts/8254-ikariam-auto-builder-hack">Auto-Builder</a></li>'); $("#doCheckButton").click(function() { let state = getState(); state.lastProcessed = {}; state.save(); update(); }); timerUpdateFunc(); setInterval(timerUpdateFunc, timerUpdateInterval); }