Trimps tools

Trimps tools (visual)

目前為 2017-06-22 提交的版本,檢視 最新版本

// ==UserScript==
// @name         Trimps tools
// @namespace    trimps.github.io
// @version      1.240
// @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();
					}
				} else {
				    if (game.global.currentMapId !== '') {
				        var lastMapCell = game.global.mapGridArray[game.global.mapGridArray.length - 1];
				        var specialGift = '';
				        if (lastMapCell.special !== '') {
				            specialGift = game.mapUnlocks[lastMapCell.special];
				        }
				        var needExitMap = (specialGift === '' || specialGift.prestige !== true) &&
				            lastMapCell.special !== 'Heirloom' &&
				            lastMapCell.name !== 'Warden' &&
				            lastMapCell.name !== 'Robotrimp' &&
				            specialGift.canRunOnce !== true;
				        if (needExitMap) {
			                mapsClicked(true); // go to maps
			                recycleMap(-1, true);
			                mapsClicked(); // go to world
				        }
				    }
				}
			}
		}
	};

    var _mapDeleter = function() {
        if (game.global.currentMapId === '') {
            for (var x in game.global.mapsOwnedArray) {
                var map = game.global.mapsOwnedArray[x];
                if (map.level < (game.global.world - 10) && map.noRecycle !== true) {
                    game.global.lookingAtMap = map['id'];
                	_log('Deleting map ' + map.name + ' (' + map.level + ')');
                    recycleMap(-1, true);
                    break;
                }
            }
        }
    }

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

	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 / 6);
				    var minWaprstation = Math.floor(game.global.world / 6) + minAddon + game.upgrades.Gigastation.done * 2;
				    if (minWaprstation < 6 + minAddon) minWaprstation = 6 + 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;
			if (game.upgrades.Gigastation.done >= 10 && item == 'Collector') 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 * 1000000000 && (breeding - 10000000000 > minBreeding)) {
				game.global.buyAmt = 10000000000;
				cnt = 10000000000;
			}
			else if (unemployed > needAllMax * 100000000 && (breeding - 1000000000 > minBreeding)) {
				game.global.buyAmt = 1000000000;
				cnt = 1000000000;
			}
			else if (unemployed > needAllMax * 10000000 && (breeding - 100000000 > minBreeding)) {
				game.global.buyAmt = 100000000;
				cnt = 100000000;
			}
			else if (unemployed > needAllMax * 1000000 && (breeding - 10000000 > minBreeding)) {
				game.global.buyAmt = 10000000;
				cnt = 10000000;
			}
			else 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);

})();