Trimps tools

Trimps tools (visual)

当前为 2017-06-08 提交的版本,查看 最新版本

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Greasemonkey 油猴子Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Violentmonkey 暴力猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴Userscripts ,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展,例如 Tampermonkey 篡改猴,才能安装此脚本。

您需要先安装一款用户脚本管理器扩展后才能安装此脚本。

(我已经安装了用户脚本管理器,让我安装!)

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展,比如 Stylus,才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

您需要先安装一款用户样式管理器扩展后才能安装此样式。

(我已经安装了用户样式管理器,让我安装!)

// ==UserScript==
// @name         Trimps tools
// @namespace    trimps.github.io
// @version      1.223
// @description  Trimps tools (visual)
// @author       Anton
// @match        https://trimps.github.io
// @require      http://ajax.googleapis.com/ajax/libs/jquery/1.9.1/jquery.min.js
// ==/UserScript==

(function () {
	'use strict';

	var tAutoBuy, tStyleFix, tPassiveWatcher, $ = jQuery, isStarted = false,
		version = typeof GM_info == 'function' ? GM_info().script.version :
			(typeof GM_info == 'object' ? GM_info.script.version : '?');

	var _isPortal = function () {
		return portalWindowOpen;
	};

	var _getJobPrice = function (jobName, resource) {
		return game.jobs[jobName].cost[resource][0] * Math.pow(game.jobs[jobName].cost[resource][1], game.jobs[jobName].owned);
	};

    var _hasFormation = function(what) {
        if (!game.global.preMapsActive && !game.global.lockTooltip) {
    		if (game.upgrades.Formations.done && what === 0) return true;
    		if (game.upgrades.Formations.done && what == 1) return true;
    		if (game.upgrades.Dominance.done && what == 2) return true;
    		if (game.upgrades.Barrier.done && what == 3) return true;
    		if (game.upgrades.Formations.done && game.global.highestLevelCleared >= 180 && what == 4) return true;
        }
        return false;
    };

    var _getEnemyAttack = function() {
        var cellNum, cell;
        if (game.global.mapsActive) {
            cellNum = game.global.lastClearedMapCell + 1;
            cell = game.global.mapGridArray[cellNum];
        } else {
            cellNum = game.global.lastClearedCell + 1;
            cell = game.global.gridArray[cellNum];
        }
        return calculateDamage(cell.attack, false, false, false, cell);
    };

    var _middleGameStrategy = function() {
        if (game.global.world < 60) return;
        
        if (game.global.formation === 0) {
            if (_hasFormation(1)) setFormation('1');
        }
        
        var enemy = _getEnemyAttack();
        var me = game.global.soldierCurrentBlock + game.global.soldierHealthMax;
        if (enemy >= me && game.global.formation != 1) {
            if (_hasFormation(1)) setFormation('1');
        }
        
        if (game.global.formation != 2 && _hasFormation(2)) {
            var formation2health = game.global.soldierHealthMax / 8;
            var me2 = formation2health + game.global.soldierCurrentBlock;
            if (me2 > enemy) {
                setFormation('2');
            }
        }
    };

	var _log = function (mes, type) {
		if (typeof type === 'undefined') type = "Story";
		message("BOT: " + mes, type);
	};

	var _getBreedingBaseSpeed = function () {
		if (game.global.challengeActive == "Trapper") return 0;
		var trimps = game.resources.trimps;
		var base = 0.0085;
		var breeding = trimps.owned - trimps.employed;
		var currentCalc = breeding * base;
		if (game.upgrades.Potency.done > 0) {
			var potencyStrength = Math.pow(1.1, game.upgrades.Potency.done);
			currentCalc *= potencyStrength;
		}
		return currentCalc;
	};

	var _autoEquipment = function () {
		var maxEquipLevel = game.global.challengeActive=='Frugal' ? 10000 : 7;
		for (var x in game.equipment) {
			if (game.equipment.hasOwnProperty(x) && game.equipment[x].locked === 0) {
				var maxLevel = game.equipment[x].prestige > maxEquipLevel ? 1 : (maxEquipLevel + 1 - game.equipment[x].prestige) * 2;
				if (game.equipment[x].level < maxLevel && canAffordBuilding(x, null, null, true)) {
					buyEquipment(x, true, true);
					_log('Upgrading equipment ' + x);
				}
			}
		}
	};

	var _getMinimumBreeding = function () {
		if (game.resources.trimps.maxSoldiers < 5) return 5; else return game.resources.trimps.maxSoldiers + 1;
	};

	var _buyStorage = function () {
		var barnThreshold = 0.8;
		/*percentage at which minimum*/
		var shedThreshold = 0.8;
		/*to buy storage*/
		var forgeThreshold = 0.8;
		/*from 0 (min) to 1 (max)*/
		var canAfford;

		if (game.resources.food.owned / (game.resources.food.max * (1 + game.portal.Packrat.level * (game.portal.Packrat.modifier * 100) / 100)) >= barnThreshold) {
			canAfford = canAffordBuilding("Barn", false, false, false, true);
			if (canAfford) {
				buyBuilding("Barn", true, true);
				_log('Building Barn');
			}
		}
		if (game.resources.wood.owned / (game.resources.wood.max * (1 + game.portal.Packrat.level * (game.portal.Packrat.modifier * 100) / 100)) >= shedThreshold) {
			canAfford = canAffordBuilding("Shed", false, false, false, true);
			if (canAfford) {
				buyBuilding("Shed", true, true);
				_log('Building Shed');
			}
		}
		if (game.resources.metal.owned / (game.resources.metal.max * (1 + game.portal.Packrat.level * (game.portal.Packrat.modifier * 100) / 100)) >= forgeThreshold) {
			canAfford = canAffordBuilding("Forge", false, false, false, true);
			if (canAfford) {
				buyBuilding("Forge", true, true);
				_log('Building Forge');
			}
		}
	}

	var _hasInQueue = function (item) {
		for (var x in game.global.buildingsQueue) {
			var queueItem = game.global.buildingsQueue[x].split('.')[0];
			if (queueItem == item) {
				return true;
			}
		}
		return false;
	};

	var _earlyGameStrategy = function () {
		if (_isPortal()) return;

		var playerStrength = getPlayerModifier();
		var minimumSpeedToHelp = 1 + playerStrength;

		if (game.global.eggLoc != -1) {
			_log('Destroying Easter Egg');
			easterEggClicked();
		}

		_buyStorage();
		_autoJobs();

		var trimps = game.resources.trimps;
		var breeding = game.global.challengeActive == "Trapper" ? 0 : trimps.owned - trimps.employed;
		var unemployed = Math.ceil(game.resources.trimps.realMax() / 2) - game.resources.trimps.employed;

		if (game.buildings.Trap.owned >= 1 && game.resources.trimps.owned < game.resources.trimps.realMax() &&
			(breeding < _getMinimumBreeding() || unemployed > 0) &&
			_getBreedingBaseSpeed() < 1) {
			setGather('trimps');
			return;
		}

		var canGetScience = game.global.challengeActive != "Scientist";

		var hasTrap = _hasInQueue('Trap');
		var cnt = game.global.challengeActive == "Trapper" ? 100 : (breeding < unemployed ? 25 : 1);
		if (!hasTrap && game.buildings.Trap.owned < 1 && game.resources.food.owned >= 10 && game.resources.wood.owned >= 10) {
			buyBuilding('Trap', true, true, cnt);
			return;
		}

		if ((game.global.buildingsQueue.length > 0 && game.global.autoCraftModifier < 1) || (game.global.buildingsQueue.length > 5)) {
			setGather('buildings');
			return;
		}

		if (getPsString('food', true) < minimumSpeedToHelp && game.resources.food.owned < 10) {
			setGather('food');
			return;
		}

		if (getPsString('wood', true) < minimumSpeedToHelp && game.resources.wood.owned < 10) {
			setGather('wood');
			return;
		}

		if (canGetScience && getPsString('science', true) < minimumSpeedToHelp && game.resources.science.owned < 10) {
			setGather('science');
			return;
		}

		if (getPsString('metal', true) < minimumSpeedToHelp && game.resources.metal.owned < 100) {
			setGather('metal');
			return;
		}

		var needScientist = game.upgrades.Scientists.done === 0 && game.upgrades.Scientists.allowed === 1;
		if (canGetScience && getPsString('science', true) < minimumSpeedToHelp && (game.resources.science.owned < 60 || needScientist)) {
			setGather('science');
			return;
		}

		if ((game.global.playerGathering == 'trimps' && (game.buildings.Trap.owned === 0 || _getBreedingBaseSpeed() > 1)) ||
			(game.global.playerGathering == 'buildings' && game.global.buildingsQueue.length === 0)) {
			_selectAutoJob();
		}
	}

	var _selectAutoJob = function () {
		var canGetScience = game.global.challengeActive != "Scientist";
		var upgradePrice = _getMaximumResourceUpgradePrice();
		var scienceNeeded = _getUpgradePriceSumForRes('science');
		if (scienceNeeded > game.resources.science.owned && canGetScience) {
			setGather('science');
		} else {
			if (upgradePrice !== false) {
				for (var x in upgradePrice) {
					if (upgradePrice.hasOwnProperty(x)) {
						if (x == 'wood' || x == 'metal' || x == 'science' || x == 'food') {
							setGather(x);
						} else {
							if (canGetScience) {
								setGather('science');
							} else {
								setGather('food');
							}
						}
						break;
					}
				}
			} else {
				if (canGetScience) {
					setGather('science');
				} else {
					setGather('food');
				}
			}
		}
	}

	var _passiveWatcher = function () {
		if (_isPortal()) return;

		_earlyGameStrategy();

		var canAfford = canAffordBuilding("Tribute", false, false, false, true);
		if (canAfford && game.buildings.Tribute.locked !== 1) {
			buyBuilding("Tribute", true, true);
			_log('Building ' + "Tribute");
		}

		canAfford = canAffordBuilding("Gym", false, false, false, true);
		if (canAfford && game.buildings.Gym.locked !== 1) {
			buyBuilding("Gym", true, true);
			_log('Building ' + "Gym");
		}
		
		_middleGameStrategy();
	}

	var _needAttackCurrentMap = function () {
		return (typeof game.mapsAttacked[game.global.world] === 'undefined');
	};
	
	var _hasMapOfCurrentLevel = function () {
		for (var x in game.global.mapsOwnedArray) {
			if (game.global.mapsOwnedArray.hasOwnProperty(x)) {
				var mapObj = game.global.mapsOwnedArray[x];
				if (mapObj.level == game.global.world) return true;
			}
		}
		return false;
	};

	var _mapAttackStrategy = function () {
		if (game.global.world < 6) return;
		if (game.global.preMapsActive) return;
		//if (!game.global.mapsUnlocked) return;
		if (game.global.pauseFight) {
			_log('Enabling auto attack!');
			fightManual();
			game.global.pauseFight = false;
			pauseFight(true); // update only
		} else {
			if (_needAttackCurrentMap()) {
				document.getElementById("mapLevelInput").value = game.global.world;
				var currentMapPrice = updateMapCost(true);
				var money = game.resources.fragments.owned;
				if (!_hasMapOfCurrentLevel()) {
					if (money >= currentMapPrice) {
						var result = buyMap();
						if (result == 1) {
							_log('Bought new map level ' + game.global.world);
						} else {
							console.log('Buy map result = ' + result);
						}
					} else {
						console.log('No fragments (' + money + ') to buy map for ' + currentMapPrice);
					}
				}

				if (_hasMapOfCurrentLevel()) {
					game.global.lookingAtMap = '';
					for (var x in game.global.mapsOwnedArray) {
						if (game.global.mapsOwnedArray.hasOwnProperty(x)) {
							var mapObj = game.global.mapsOwnedArray[x];
							if (mapObj.level == game.global.world) {
								game.global.lookingAtMap = mapObj.id;
								break;
							}
						}
					}

					if (game.global.lookingAtMap !== '') {
						_log('Attacking map ' + game.global.lookingAtMap);
						game.options.menu.alwaysAbandon.enabled = 1; // GO TO MAPS!
						mapsClicked(true);
						game.mapsAttacked[game.global.world] = true;
						game.global.repeatMap = true; // REPEAT
						repeatClicked(true);
						runMap();
						var breeding = trimps.owned - trimps.employed;
		                if (breeding < (_getMinimumBreeding() + 1)) fightManual();
					} else {
						console.log('where is my map?');
					}
				} else {
					console.log('no map of current level ' + game.global.world);
				}
			} else {
				if (_hasMapOfCurrentLevel() && game.global.currentMapId === '') {
					game.global.lookingAtMap = '';
					var map_id, map_name = '';
					for (var x in game.global.mapsOwnedArray) {
						if (game.global.mapsOwnedArray.hasOwnProperty(x)) {
							var mapObj = game.global.mapsOwnedArray[x];
							if (mapObj.level <= game.global.world && mapObj.noRecycle === true && mapObj.clears === 0) {
								game.global.lookingAtMap = mapObj.id;
								map_id = x;
								map_name = mapObj.name;
								break;
							}
						}
					}
					if (game.global.lookingAtMap !== '' && typeof map_id !== 'undefined') {
						_log('Attacking prestige map ' + map_name + ' level (' + game.global.mapsOwnedArray[map_id].level + ')');
						game.options.menu.alwaysAbandon.enabled = 1; // GO TO MAPS!
						mapsClicked(true);
						game.global.repeatMap = true; // REPEAT
						repeatClicked(true);
						game.global.mapsOwnedArray[map_id].clears = 1;
						runMap();
						var breeding = trimps.owned - trimps.employed;
		                if (breeding < (_getMinimumBreeding() + 1)) fightManual();
					}
				}
			}
		}
	};

	var _auto = function () {
		if (_isPortal()) return;
		_earlyGameStrategy();
		_autoUpgrade();
		_autoBuy();
		_autoEquipment();
		_mapAttackStrategy();
		_middleGameStrategy();
	};

	var _onStartButton = function () {
		if (isStarted) {
			_stop();
			_log('Stop.');
			isStarted = false;
		} else {
			_start();
			_log('Started!');
			isStarted = true;
		}
	};

	var _styleUpdate = function () {
		// remove counts
		$('head').append('<style type="text/css">' +
			'span.thingName{font-size:85%;}.queueItem,.btn{padding:0}' +
			'.thingColorCanNotAfford.upgradeThing{background-color:#530053;}' +
			'#battleSideTitle{padding:0}' +
			'.battleSideBtnContainer{margin-top:0;}' +
			'#logBtnGroup{display:none}' +
			'#log{height:100%;}' +
			'.glyphicon-apple{color:orangered;}' +
			'.glyphicon-tree-deciduous{color:limegreen;}'+
			'.icomoon.icon-cubes{color:silver;}'+
			'.icomoon.icon-diamond{color:white;'+
			'</style>');
		// remove tabs
		$('#buyTabs').hide();
		filterTabs('all');
		// remove captions
		$('#buildingsTitleDiv,#upgradesTitleDiv,#equipmentTitleDiv').hide();
		// fix height
		$('#topRow,#queueContainer').css('margin-bottom', '0');
		$('#jobsTitleDiv').css('padding', '0').css('font-size', 'smaller');
		$('#buyHere').css('margin', '0').css('padding', '0').css('overflow-x', 'hidden');
		$('#queueContainer').css('height', '70px');
		$('#numTabs').css('margin', '0');
		$('#buyContainer').css('height', 'calc(99vh - 20vw - 96px)');
		// add button
		$('#settingsTable tr').append('<td class="btn btn-info" id="botStart" title="' + version + '">Bot start</td>');
		$('#botStart').click(_onStartButton);
		// add grid
		var $grid = $('<table style="width:100%;margin-top:4px;font-size:smaller;"><tr>' +
			'<td id="magnimp-cell"><span class="glyphicon glyphicon-magnet"></span><label style="margin-left:4px" title="Magimp">...</label></td>' +
			'<td id="venimp-cell"><span class="glyphicon glyphicon-glass"></span><label style="margin-left:4px" title="Venimp">...</label></td>' +
			'</tr><tr>' +
			'<td id="whipimp-cell"><span class="glyphicon glyphicon-star"></span><label style="margin-left:4px" title="Whipimp">...</label></td>' +
			'<td id="titimp-cell"><span class="icomoon icon-hammer"></span><label style="margin-left:4px" title="Titimp">' + prettify(game.global.titimpLeft) + '</label></td>' +
			'</tr></table>');
		$('#battleBtnsColumn').append($grid);
		_updateSuperTrimps();
	}

	var _autoUpgrade = function () {
		for (var item in game.upgrades) {
			var upgrade = game.upgrades[item];
			if (upgrade.locked == 1) continue;
			var canAfford = canAffordTwoLevel(upgrade);
			if (canAfford) {
				if (item == "Coordination") {
					if (!canAffordCoordinationTrimps()) continue;
				}
				if (item == "Gigastation") {
				    var minAddon = Math.floor(game.global.highestLevelCleared / 15);
				    var minWaprstation = Math.floor(game.global.world / 7) + minAddon;
				    if (minWaprstation < 7 + minAddon) minWaprstation = 7 + minAddon;
					if (game.buildings.Warpstation.owned < minWaprstation) continue;
				}
				buyUpgrade(item, true, true);
				_log('Upgrading ' + item);
				_selectAutoJob();
				return 1;
			}
		}
		return 0;
	};

	var getUpgradePrice = function (upgradeObject) {
		var price, result = {};
		for (var cost in upgradeObject.cost) {
			if (typeof upgradeObject.cost[cost] === 'object' && typeof upgradeObject.cost[cost][1] === 'undefined') {
				var costItem = upgradeObject.cost[cost];
				for (var item in costItem) {
					price = costItem[item];
					if (upgradeObject.prestiges && (item == "metal" || item == "wood")) {
						if (game.global.challengeActive == "Daily" && typeof game.global.dailyChallenge.metallicThumb !== 'undefined') {
							price *= dailyModifiers.metallicThumb.getMult(game.global.dailyChallenge.metallicThumb.strength);
						}
						price *= Math.pow(1 - game.portal.Artisanistry.modifier, game.portal.Artisanistry.level);
					}
					if (typeof price === 'function') price = price();
					if (typeof price[1] !== 'undefined') price = resolvePow(price, upgradeObject);
					result[item] = price;
				}
			}
		}
		return result;
	};

	var _getAllUpgradePrice = function () {
		var totalPrice = {};
		for (var item in game.upgrades) {
			var upgrade = game.upgrades[item];
			if (upgrade.locked == 1) continue;
			var price = getUpgradePrice(upgrade);
			for (var res in price) {
				if (price.hasOwnProperty(res)) {
					if (typeof totalPrice[res] === 'undefined') totalPrice[res] = 0;
					totalPrice[res] += price[res];
				}
			}
		}
		return totalPrice;
	};

	var _getUpgradePriceSumForRes = function (res) {
		var totalPrice = _getAllUpgradePrice();
		if (typeof totalPrice[res] !== 'undefined') {
			return totalPrice[res];
		} else {
			return 0;
		}
	};

	var _getMaximumResourceUpgradePrice = function () {
		var totalPrice = _getAllUpgradePrice(), maxPriceName = '', maxPrice = 0;
		for (var res in totalPrice) {
			if (totalPrice.hasOwnProperty(res)) {
				if (totalPrice[res] > maxPrice) {
					maxPrice = totalPrice[res];
					maxPriceName = res;
				}
			}
		}
		var result = {};
		if (maxPriceName !== '') {
			result[maxPriceName] = maxPrice;
			return result;
		} else {
			return false;
		}
	};

	var _autoBuy = function () {
		var toBuy;
		for (var item in game.buildings) {
			if (item == 'Barn' || item == 'Shed' || item == 'Forge' || item == 'Wormhole' || item == 'Trap') continue;
			if (!game.buildings.Collector.locked &&
				(item == 'Mansion' || item == 'Hotel' || item == 'Resort' || item == 'House' || item == 'Hut')) continue;
			building = game.buildings[item];
			if (building.locked == 1) continue;
			var canAfford = canAffordBuilding(item, false, false, false, true);
			if (canAfford) {
				if (item == 'Nursery') {
				    var isElectro = game.global.challengeActive == "Electricity";
				    var mult = game.global.brokenPlanet ? (game.global.world >= 80 ? 2 : 1.5) : 1;
				    
					if (!isElectro && (game.buildings.Nursery.owned >= (game.buildings.Tribute.owned * mult) ||
						game.buildings.Nursery.owned >= (game.buildings.Gym.owned * mult)))
					{
						continue;
					} else {
						if (!_hasInQueue('Nursery')) {
							toBuy = item;
						} else {
							continue;
						}
					}
				} else {
					toBuy = item;
				}
			}
		}
		if (typeof toBuy !== 'undefined') {
			buyBuilding(toBuy, true, true);
			_log('Building ' + toBuy);
			return 1;
		} else {
			return 0;
		}
	}

	var needFarmer = 25, needLumber = 25, needMiner = 25, needScientist = 1;
	var needAllMax = needFarmer + needLumber + needMiner + needScientist;

	var _buyJobs = function ($obj, unemployed, objName, jobId) {
		if ($obj.length > 0) {
			var trimps = game.resources.trimps;
			var breeding = game.global.challengeActive == "Trapper" ? unemployed : trimps.owned - trimps.employed;
			var cnt = 1;
			var minBreeding = _getMinimumBreeding();
			if (unemployed > needAllMax * 100000 && (breeding - 1000000 > minBreeding)) {
				game.global.buyAmt = 1000000;
				cnt = 1000000;
			}
			else if (unemployed > needAllMax * 10000 && (breeding - 100000 > minBreeding)) {
				game.global.buyAmt = 100000;
				cnt = 100000;
			}
			else if (unemployed > needAllMax * 1000 && (breeding - 10000 > minBreeding)) {
				game.global.buyAmt = 10000;
				cnt = 10000;
			}
			else if (unemployed > needAllMax * 100 && (breeding - 1000 > minBreeding)) {
				game.global.buyAmt = 1000;
				cnt = 1000;
			}
			else if (unemployed > needAllMax * 10 && (breeding - 100 > minBreeding)) {
				numTab(4);
				cnt = 100;
			}
			else if (unemployed > needAllMax * 2.5 && (breeding - 25 > minBreeding)) {
				numTab(3);
				cnt = 25;
			}
			else if (unemployed > needAllMax && (breeding - 10 > minBreeding)) {
				numTab(2);
				cnt = 10;
			}
			else {
				numTab(1);
				cnt = 1;
			}
			buyJob(jobId, true, true); // confirmed, noTip
			numTab(1); // +1
			_log('New ' + objName + (cnt > 1 ? " x" + cnt : ''), 'Combat');
			return cnt;
		} else {
			return 0;
		}
	};

	var _autoJobs = function () {
		var trimps = game.resources.trimps;
		var breeding = trimps.owned - trimps.employed;
		if (breeding < (_getMinimumBreeding() + 1) && game.global.challengeActive !== 'Trapper') return;

		var jobsTotal =
			game.jobs.Farmer.owned +
			game.jobs.Lumberjack.owned +
			game.jobs.Miner.owned +
			game.jobs.Scientist.owned;

		var unemployed = Math.ceil(game.resources.trimps.realMax() / 2) - game.resources.trimps.employed;

		var trainerCost = _getJobPrice('Trainer', 'food');
		if ((trainerCost < game.resources.food.owned) && unemployed <= 0 && game.jobs.Farmer.owned > 1 && game.jobs.Trainer.locked === 0) {
			game.global.firing = true;
			_log('Fire farmer, sorry');
			buyJob('Farmer', true, true);
			game.global.firing = false;
		}

		if (unemployed <= 0) return;

		if (trainerCost <= game.resources.food.owned && game.jobs.Trainer.locked === 0) {
			buyJob('Trainer', true, true);
			_log('New trainer');
			return 1;
		}

		var cnt = 0;

		var $explorer = $('#jobsHere').find('.thingColorCanAfford[id=Explorer]');
		if ($explorer.length > 0) {
			buyJob('Explorer', true, true);
			_log('New explorer');
			return ++cnt;
		}

		var hasFarmer = game.jobs.Farmer.locked === 0;
		var hasLumber = game.jobs.Lumberjack.locked === 0;
		var hasMiner = game.jobs.Miner.locked === 0;
		var hasScientist = game.jobs.Scientist.locked === 0;
		var needAll =
			(hasFarmer ? needFarmer : 0) +
			(hasLumber ? needLumber : 0) +
			(hasMiner ? needMiner : 0) +
			(hasScientist ? needScientist : 0);
		if (needAll < 1) needAll = 1;

		var minOwned = Math.min(
			game.jobs.Farmer.owned,
			game.jobs.Lumberjack.owned,
			game.jobs.Miner.owned);
		if (minOwned > 30) minOwned = 30; // for science

		if (hasScientist && game.jobs.Scientist.owned < minOwned) {
			var $science = $('#jobsHere').find('.thingColorCanAfford[id=Scientist]');
			cnt += _buyJobs($science, unemployed, 'scientist', 'Scientist');
		} else if (hasFarmer && game.jobs.Farmer.owned < (jobsTotal * needFarmer / needAll)) {
			var $farmer = $('#jobsHere').find('.thingColorCanAfford[id=Farmer]');
			cnt += _buyJobs($farmer, unemployed, 'farmer', 'Farmer');
		} else if (hasLumber && game.jobs.Lumberjack.owned < (jobsTotal * needLumber / needAll)) {
			var $lumber = $('#jobsHere').find('.thingColorCanAfford[id=Lumberjack]');
			cnt += _buyJobs($lumber, unemployed, 'lumberjack', 'Lumberjack');
		} else if (hasMiner && game.jobs.Miner.owned < (jobsTotal * needMiner / needAll)) {
			var $miner = $('#jobsHere').find('.thingColorCanAfford[id=Miner]');
			cnt += _buyJobs($miner, unemployed, 'miner', 'Miner');
		} else if (hasScientist && game.jobs.Scientist.owned < (jobsTotal * needScientist / needAll)) {
			var $science = $('#jobsHere').find('.thingColorCanAfford[id=Scientist]');
			cnt += _buyJobs($science, unemployed, 'scientist', 'Scientist');
		}

		if (unemployed > 0 && cnt === 0) {
			var $farmer = $('#jobsHere').find('.thingColorCanAfford[id=Farmer]');
			cnt += _buyJobs($farmer, unemployed, 'farmer', 'Farmer');
		}

		return cnt;
	};

	var _styleFix = function () {
		_disableLog();

		$('.buyBox').find('.thing').find('br').remove();
		$('.buyBox').find('.thing').find('.thingOwned').css('margin-left', '4px');
		$('#buyHere').find('.alert.badge').text('');
		$('#buildingsQueue').css('height', '30px');
		for (var x in game.upgrades) if (game.upgrades[x].alert && game.upgrades[x].locked === 0) game.upgrades[x].alert = false;
		for (x in game.buildings) if (game.buildings[x].alert && game.buildings[x].locked === 0) game.buildings[x].alert = false;
		for (x in game.jobs) if (game.jobs[x].alert && game.jobs[x].locked === 0) game.jobs[x].alert = false;

		if (typeof game.passedMaps === 'undefined') game.passedMaps = {};
		if (typeof game.mapsAttacked === 'undefined') game.mapsAttacked = {};

		for (x in game.passedMaps) if (x > game.global.world) {
			// Game restart?
			game.passedMaps = {};
			game.mapsAttacked = {};
			$('#venimp-cell').find('label').text('...');
			$('#magnimp-cell').find('label').text('...');
			$('#whipimp-cell').find('label').text('...');
			$('#buildingsTitleDiv,#upgradesTitleDiv,#equipmentTitleDiv').hide(); // remove captions
			break;
		}

		var hasItem = false;
		if (typeof game.mapUnlocks === 'undefined') {
			clearInterval(tStyleFix);
			tStyleFix = setInterval(_styleFix, 2000);
		} else {
			for (x in game.mapUnlocks) {
				var notPass = game.mapUnlocks[x].startAt <= game.global.world && (typeof game.passedMaps[game.mapUnlocks[x].startAt] === 'undefined' || game.passedMaps[game.mapUnlocks[x].startAt] < 1);
				if (notPass) {
					$('#battleSideTitle').css('background-color', notPass ? '#A00' : '#600');
					hasItem = true;
					break;
				}
			}
		}
		if (!hasItem) {
			$('#battleSideTitle').css('background-color', 'transparent');
		}
		game.passedMaps[game.global.world] = game.global.mapBonus;
		if (game.global.mapBonus > 0) {
			for (x in game.mapUnlocks) {
				if (game.mapUnlocks[x].startAt < game.global.world) {
					game.passedMaps[game.mapUnlocks[x].startAt] = 1;
				}
			}
		}
	};

	var _start = function () {
		_log('Passive watcher stop');
		clearInterval(tPassiveWatcher);

		_log('BOT start version ' + version);
		tAutoBuy = setInterval(_auto, 1000);

		$('#botStart').text('Bot stop');
	};

	var _stop = function () {
		_log('BOT stop');
		clearInterval(tAutoBuy);

		tPassiveWatcher = setInterval(_passiveWatcher, 1000);
		_log('Passive watcher started');

		$('#botStart').text('Bot start');
	};

	var logEnabled = true, $oldLog, tTitimp;

	var _updateSuperTrimps = function () {
		var whipStrength = Math.pow(1.003, game.unlocks.impCount.Whipimp);
		whipStrength = prettify((whipStrength - 1) * 100) + "%";
		var magimpStrength = Math.pow(1.003, game.unlocks.impCount.Magnimp);
		magimpStrength = prettify((magimpStrength - 1) * 100) + "%";
		var venimpStrength = Math.pow(1.003, game.unlocks.impCount.Venimp);
		venimpStrength = prettify((venimpStrength - 1) * 100) + "%";

		var mag = $('#magnimp-cell').find('label');
		if (mag.text() != magimpStrength) mag.text(magimpStrength);
		var whip = $('#whipimp-cell').find('label');
		if (whip.text() != whipStrength) whip.text(whipStrength);
		var ven = $('#venimp-cell').find('label');
		if (ven.text() != venimpStrength) ven.text(venimpStrength);
	};

	var _disableLog = function () {
		if (logEnabled) {
			message = function (messageString, type, lootIcon, extraClass, extraTag, htmlPrefix) {
				if (type == 'Loot' && lootIcon === null) return;
				if (type == 'Combat' && (lootIcon === null || typeof lootIcon === 'undefined')) return;
				if (type == 'Loot' &&
					(messageString.indexOf('You just found') > -1 ||
						messageString.indexOf('You found') > -1 ||
						messageString.indexOf('That guy just left') > -1 ||
						(messageString.indexOf(' dropped ') > -1 && messageString.indexOf('That ') > -1) ||
						messageString.indexOf(' manage to ') > -1 ||
						messageString.indexOf('Then he died') > -1 ||
						messageString.indexOf(' popped out!') > -1 ||
						messageString.indexOf('That Feyimp gave you') > -1 ||
						messageString.indexOf('in that dead Tauntimp') > -1 ||
						messageString.indexOf('fragments from that Flutimp') > -1 ||
						messageString.indexOf('That Jestimp gave you') > -1 ||
						messageString.indexOf('That Titimp made your Trimps super strong') > -1 ||
						messageString.indexOf('You scored ') > -1
					)) return;
				if (type == 'Story' && typeof lootIcon === 'undefined' &&
					messageString.indexOf('BOT: New ') > -1) return;
				if (type == 'Notices' && messageString == 'Game Saved!') {
					var t = ((game.options.menu.timestamps.enabled == 1) ? getCurrentTime() : updatePortalTimer(true));
					$('#saveIndicator').find('.autosaving').text(t);
					return;
				}
				if (messageString.indexOf('The ground up Venimp now increases your Trimps') > -1) {
					_updateSuperTrimps();
					return;
				}
				if (messageString.indexOf('You killed a Magnimp! The strong magnetic forces now increase your loot by') > -1) {
					_updateSuperTrimps();
					return;
				}
				if (messageString.indexOf('Seeing the Whipimps fall is causing all of your Trimps to work') > -1) {
					_updateSuperTrimps();
					return;
				}

				var log = document.getElementById("log");
				var displayType = "block";
				var prefix = "";
				var addId = "";
				if (messageString == "Game Saved!" || extraClass == 'save') {
					addId = " id='saveGame'";
					if (document.getElementById('saveGame') !== null) {
						log.removeChild(document.getElementById('saveGame'));
					}
				}
				if (game.options.menu.timestamps.enabled) {
					messageString = ((game.options.menu.timestamps.enabled == 1) ? getCurrentTime() : updatePortalTimer(true)) + " " + messageString;
				}
				if (!htmlPrefix) {
					if (lootIcon && lootIcon.charAt(0) == "*") {
						lootIcon = lootIcon.replace("*", "");
						prefix = "icomoon icon-";
					}
					else prefix = "glyphicon glyphicon-";
					if (type == "Story") messageString = "<span class='glyphicon glyphicon-star'></span> " + messageString;
					if (type == "Combat") messageString = "<span class='glyphicon glyphicon-flag'></span> " + messageString;
					if (type == "Loot" && lootIcon) messageString = "<span class='" + prefix + lootIcon + "'></span> " + messageString;
					if (type == "Notices") {
						messageString = "<span class='glyphicon glyphicon-off'></span> " + messageString;
					}
				} else {
					messageString = htmlPrefix + " " + messageString;
				}
				var messageHTML = "<span" + addId + " class='" + type + "Message message" + " " + extraClass + "' style='display: " + displayType + "'>" + messageString + "</span>";
				pendingLogs.all.push(messageHTML);
				postMessages();

				var $allLogs = $('#log').find('span');
				$allLogs.slice(0, -30).remove();
			};
			logEnabled = false;
		}
	};

	var _titimpUpdate = function () {
		$('#titimp-cell').find('label').text(prettify(game.global.titimpLeft > 0 ? game.global.titimpLeft : 0));
	};

	setTimeout(function () {

		_log('Trimps BOT version ' + version);

		tStyleFix = setInterval(_styleFix, 2000);
		tTitimp = setInterval(_titimpUpdate, 500);

		_styleUpdate();
		_styleFix();

		_disableLog();

		_stop(); // start passive watcher

	}, 1000);

})();