DHO Fixed

Improve Diamond Hunt Online and fix some inconsistencies

当前为 2017-01-05 提交的版本,查看 最新版本

// ==UserScript==
// @name         DHO Fixed
// @namespace    FileFace
// @description  Improve Diamond Hunt Online and fix some inconsistencies
// @version      0.27.1
// @author       Zorbing
// @grant        none
// @run-at       document-start
// @include      http://www.diamondhunt.co/game.php
// ==/UserScript==

/**
 * TODO:
 *	- add repair option to machine dialog
 *	- improve chat (collapse multiple messages from the same person, show pms somewhere else, store the messages for some time)
 *	- restyle tabs (allow sub-tabs)
 *	- improve consistency of level bar (including the level-up animation)
 *	- improve items style in the achievement store
 *	- format numbers consistently (use a thousands seperator)
 */

(function ()
{
'use strict';

let observedKeys = new Map();
/**
 * Observes the given key for change
 * 
 * @param {string} key	The name of the variable
 * @param {Function} fn	The function which is called on change
 */
function observe(key, fn)
{
	if (!observedKeys.has(key))
	{
		observedKeys.set(key, []);
	}
	observedKeys.get(key).push(fn);
}
function initObservable()
{
	const oldLoadGlobals = window.loadGlobals;
	window.loadGlobals = (key, newValue) =>
	{
		if (key === undefined)
		{
			return;
		}

		const oldValue = window[key];
		const ret = oldLoadGlobals(key, newValue);
		if (oldValue !== newValue)
		{
			(observedKeys.get(key) || []).forEach(fn => fn(key, oldValue, newValue));
		}
		return ret;
	};
}



const settings = {
	reorderFarming: {
		title: 'Set seed orders coherent'
		, defaultValue: true
	}
	, applyNewItemStyle: {
		title: 'Apply a new item style'
		, defaultValue: true
	}
	, applyNewKeyItemStyle: {
		title: 'Apply a new key item and machinery style'
		, defaultValue: true
	}
	, improveDialogBtns: {
		title: 'Improve button captions in dialogs'
		, defaultValue: true
	}
	, improveMachineryDialog: {
		title: 'Improve the machinery dialog'
		, defaultValue: true
	}
	, hideSomeCraftRecipes: {
		title: 'Hide some crafting recipes'
		, defaultValue: true
	}
	, hideMaxRecipes: {
		title: 'Hide recipes of maxed machines'
		, defaultValue: true
	}
	, expandEquipment: {
		title: 'Expand crafting recipes of equipment'
		, defaultValue: true
	}
	, hideEquipment: {
		title: 'Hide inferiour equipment (only up to gold)'
		, defaultValue: true
	}
	, hideUnnecessaryPrice: {
		title: 'Hide unnecessary prices'
		, defaultValue: true
	}
	, useFastLevelCalculation: {
		title: 'Use fast level calculation'
		, defaultValue: true
	}
};
function getSetting(key)
{
	if (!settings.hasOwnProperty(key))
	{
		return;
	}
	const name = 'setting.' + key;
	return localStorage.hasOwnProperty(name) ? JSON.parse(localStorage.getItem(name)) : settings[key].defaultValue;
}
function setSetting(key, value)
{
	if (!settings.hasOwnProperty(key))
	{
		return;
	}
	localStorage.setItem('setting.' + key, JSON.stringify(value));
}
function initSettings()
{
	const table = document.getElementById('settings-tab').querySelector('table');
	if (!table)
	{
		return;
	}
	const headerRow = table.insertRow(-1);
	headerRow.innerHTML = `<th style="background-color:black;color:orange">
		Userscript "DHO Fixed"<br>
		<span style="font-size: 0.9rem;">(changes require reloading the tab)</span>
	</th>`;

	for (let key in settings)
	{
		let value = getSetting(key);
		const row = table.insertRow(-1);
		row.innerHTML = `<td id="fake-link-top">
			${settings[key].title}: <span style="color:cyan;" id="userscript-${key}">${value ? 'on' : 'off'}</span>
		</td>`;
		const indicator = document.getElementById('userscript-' + key);;
		row.addEventListener('click', () =>
		{
			value = !value;
			setSetting(key, value);
			indicator.textContent = value ? 'on' : 'off';
		});
	}

	const settingLink = document.querySelector('.top-menu td[onclick^="openTab"]');
	settingLink.addEventListener('click', function ()
	{
		const activeTab = document.querySelector('#tab-tr td[style^="background: linear-gradient(rgb"]');
		if (activeTab)
		{
			activeTab.style.background = 'linear-gradient(black, grey)';
		}
	});
}



/**
 * global constants
 */

const furnaceLevels = ['', 'stone', 'bronze', 'iron', 'silver', 'gold', 'ancient', 'promethium', 'runite', 'dragon'];
const ovenLevels = ['bronze', 'iron', 'silver', 'gold', 'ancient', 'promethium', 'runite', 'dragon'];
const barTypes = ['bronze', 'iron', 'silver', 'gold', 'promethium', 'runite'];



function fixKeyItems()
{
    // remove unnecessary br element
    const oilPump = document.getElementById('key-item-handheldOilPump-box');
    let br = oilPump && oilPump.nextElementSibling;
    if (!br)
    {
        br = document.createElement('br');
    }

    // add br element after img in oil pipe element
    const oilPipe = document.getElementById('key-item-bindedOilPipe-box');
    let img = oilPipe && oilPipe.children[0];
    img = img && img.children[0];
    img.parentNode.insertBefore(br, img.nextSibling);
}



const seedOrder = ['bloodLeafSeeds', 'dottedGreenLeafSeeds', 'redMushroomSeeds', 'potatoSeeds', 'greenLeafSeeds', 'strawberrySeeds', 'redMushroomTreeSeeds', 'blewitMushroomSeeds', 'wheatSeeds', 'starDustSeeds', 'blewitMushroomTreeSeeds', 'snapeGrassSeeds', 'limeLeafSeeds', 'appleTreeSeeds', 'iceBerrySeeds', 'goldLeafSeeds', 'starDustTreeSeeds', 'stripedLeafSeeds', 'essenceSeeds', 'crystalLeafSeeds', 'megaDottedGreenLeafSeeds', 'megaRedMushroomSeeds', 'megaGreenLeafSeeds', 'essenceTreeSeeds', 'megaBlewitMushroomSeeds', 'megaLimeLeafSeeds', 'stripedCrystalLeafSeeds'];
const seedTitle = {
	potatoSeeds: 'Potato Seeds'
	, strawberrySeeds: 'Strawberry Seeds'
	, wheatSeeds: 'Wheat Seeds'
	, dottedGreenLeafSeeds: 'Dotted Green Leaf Seeds'
	, greenLeafSeeds: 'Green Leaf Seeds'
	, limeLeafSeeds: 'Lime Leaf Seeds'
	, goldLeafSeeds: 'Gold Leaf Seeds'
	, stripedLeafSeeds: 'Striped Leaf Seeds'
	, crystalLeafSeeds: 'Crystal Leaf Seeds'
	, redMushroomSeeds: 'Red Mushroom Seeds'
	, blewitMushroomSeeds: 'Blewit Mushroom Seeds'
	, appleTreeSeeds: 'Apple Tree Seeds'
	, snapeGrassSeeds: 'Snape Grass Seeds'
	, redMushroomTreeSeeds: 'Red Mushroom Tree Seeds'
	, blewitMushroomTreeSeeds: 'Blewit Mushroom Tree Seeds'
	, starDustSeeds: 'Star Dust Seeds'
};
function fixFarming()
{
    const inputs = document.querySelectorAll('#dialog-planter input[type="image"]');
    for (let i = inputs.length-1; i >= 0; i--)
    {
        const input = inputs[i];
        const key = input.id.replace('planter-input-img-', '');
        input.title = seedTitle[key];
    }

	if (!getSetting('reorderFarming'))
	{
		return;
	}

	let planterEl = inputs[0];
	const planterParent = planterEl.parentNode;
	let boxEl = document.querySelector('#farming-tab .inventory-item-box-farming').parentNode;
	const boxParent = boxEl.parentNode;
	for (let i = seedOrder.length-1; i >= 0; i--)
	{
		const key = seedOrder[i];
		const input = document.getElementById('planter-input-img-' + key);
		if (input)
		{
			planterParent.insertBefore(input, planterEl);
			planterParent.insertBefore(document.createTextNode(' '), planterEl);
			planterEl = input;
		}
		const box = document.getElementById('item-' + key + '-box');
		if (box)
		{
			boxParent.insertBefore(box.parentNode, boxEl);
			boxParent.insertBefore(document.createTextNode(' '), boxEl);
			boxEl = box.parentNode;
		}
	}
}



function fixServerMsg()
{
	const serverMsgEl = document.querySelector('#server-inner-msg');
	if (!serverMsgEl)
	{
		return;
	}

	const serverMsg = serverMsgEl.textContent;
	const close = document.querySelector('#server-top-msg > *:last-child');
	if (localStorage.getItem('closedServerMsg') == serverMsg)
	{
		close.click();
		return;
	}

	close.addEventListener('click', function ()
	{
		localStorage.setItem('closedServerMsg', serverMsg);
	});
}



const bgColor = 'hsla(0, 100%, 90%, 1)';
const imgSrc2Key = {
	'bronzebar': 'bronzeBar'
	, 'ironbar': 'ironBar'
	, 'silverbar': 'silverBar'
	, 'goldbar': 'goldBar'
	, 'stonefurnace': 'stoneFurnace'
	, 'bronzefurnace': 'bronzeFurnace'
	, 'ironfurnace': 'ironFurnace'
	, 'silverfurnace': 'silverFurnace'
	, 'goldfurnace': 'goldFurnace'
	, 'pic_coin': 'coins'
	, 'stardust': 'starDust'
	, 'treasureKey': 'treasureChestKey'
	, 'dottedgreenleaf': 'dottedGreenLeaf'
	, 'redmushroom': 'redMushroom'
	, 'greenleaf': 'greenLeaf'
	, 'limeleaf': 'limeLeaf'
	, 'blewitmushroom': 'blewitMushroom'
	, 'goldleaf': 'goldLeaf'
	, 'pureWater': 'pureWaterPotion'
	, 'snapegrass': 'snapeGrass'
	, 'crystalleaf': 'crystalLeaf'
	, 'starDustConverter': 'starGemPotion'
	, 'superStargemPotion': 'superStarGemPotion'
	, 'superoilpotion': 'superOilPotion'
	, 'wooden_slave': 'miners'
	, 'fishingRodFarmer': 'achFishermen'
	, 'goldenStriper': 'goldenStriperPotion'
};
const imgSrc2LevelKey = {
	'watering-can': 'merchanting'
	, 'cookingskill': 'cooking'
	, 'archaeology': 'exploring'
	, 'wizardHatIcon': 'magic'
};
function amount2Int(str)
{
	return parseInt(str.replace(/M/i, '000000').replace(/B/i, '000000000').replace(/\D/g, ''), 10);
}
function checkRequirements(row, xpKey, init = true)
{
	const isRed = row.style.backgroundColor == 'rgb(255, 128, 128)';
	let everythingFulfilled = true;
	let keys2Observe = [];

	const levelEl = row.cells[2];
	const neededLevel = parseInt(levelEl.textContent, 10);
	const levelHighEnough = neededLevel <= window.getLevel(window[xpKey]);
	levelEl.style.color = levelHighEnough ? '' : 'red';
	everythingFulfilled = everythingFulfilled && levelHighEnough;
	keys2Observe.push(xpKey);

	const reqEl = row.cells[3];
	const children = reqEl.children;
	// check for each requirement if it is fulfilled
	for (let i = 0; i < children.length; i++)
	{
		const el = children[i];
		if (el.tagName != 'IMG')
		{
			continue;
		}
		const imgKey = el.src.replace(/^.+images\/.*?([^\/]+)\..+$/, '$1');
		const key = imgSrc2Key[imgKey] || imgKey;
		// wrap the amount with a span element
		let valueSpan = el.nextSibling;
		if (valueSpan.nodeType == Node.TEXT_NODE)
		{
			const valueTextNode = valueSpan;
			valueSpan = document.createElement('span');
			valueTextNode.parentNode.insertBefore(valueSpan, valueTextNode);
			valueSpan.appendChild(valueTextNode);
		}

		const amount = amount2Int(valueSpan.textContent);
		const has = parseInt(window[key] || '0', 10);
		const isSkill = imgSrc2LevelKey.hasOwnProperty(key);
		let fulfilled = has >= amount;
		if (isSkill)
		{
			const xpKey = imgSrc2LevelKey[key] + 'Xp';
			fulfilled = window.getLevel(window[xpKey]) >= amount;
			keys2Observe.push(xpKey);
		}
		else if (key == 'gem')
		{
			fulfilled = window.sapphire >= amount || window.emerald >= amount || window.ruby >= amount || window.diamond >= amount;
			keys2Observe.push(...['sapphire', 'emerald', 'ruby', 'diamond']);
		}
		else if (/furnace/i.test(key))
		{
			const furnaceLevel = furnaceLevels.indexOf(key.replace(/furnace/i, ''));
			fulfilled = fulfilled || parseInt(window.bindedFurnaceLevel, 10) >= furnaceLevel;
			keys2Observe.push(...[key, 'bindedFurnaceLevel']);
		}
		else if (key == 'anybar')
		{
			const amountArray = valueSpan.parentNode.getAttribute('tooltip').replace(/\D*$/, '').split('/')
				.map(str => amount2Int(str));
			fulfilled = false;
			for (let i = 0; i < barTypes.length; i++)
			{
				const bar = barTypes[i];
				fulfilled = fulfilled || window[bar + 'Bar'] >= amountArray[i];
				keys2Observe.push(bar);
			}
		}
		else if (/(?:wand|staff)$/i.test(key))
		{
			const bindedKey = 'binded' + key[0].toUpperCase() + key.substr(1);
			fulfilled = fulfilled || window[bindedKey] > 0;
			keys2Observe.push(...[key, bindedKey]);
		}
		else
		{
			if (!window.hasOwnProperty(imgKey) && !imgSrc2Key.hasOwnProperty(imgKey))
			{
				console.debug('missing key handling:', key, el);
			}
			keys2Observe.push(key);
		}
		valueSpan.style.color = fulfilled ? '' : 'red';
		everythingFulfilled = everythingFulfilled && (isSkill || fulfilled);
	}
	levelEl.style.backgroundColor = everythingFulfilled ? '' : bgColor;
	reqEl.style.backgroundColor = everythingFulfilled ? '' : bgColor;
	row.style.backgroundColor = everythingFulfilled ? 'rgb(194, 255, 133)' : 'rgb(255, 128, 128)';

	if (init)
	{
		for (let key of keys2Observe)
		{
			observe(key, (key, oldValue, newValue) => checkRequirements(row, xpKey, false));
		}
	}
}

function highlightRequirements()
{
	const craftingTables = {
		'crafting': {
			tabId: 'crafting'
			, xp: 'crafting'
		}
		, 'brewing': {
			tabId: 'brewing'
			, xp: 'brewing'
		}
		, 'achCraft': {
			tabId: 'archaeology-crafting'
			, xp: 'crafting'
		}
		, 'cooking': {
			tabId: 'cooking'
			, xp: 'cooking'
		}
		, 'magicCraft': {
			tabId: 'magiccrafting'
			, xp: 'crafting'
		}
		, 'spellbook': {
			tabId: 'spellbook'
			, xp: 'magic'
		}
	};
	for (let key in craftingTables)
	{
		const info = craftingTables[key];
		const xpName = info.xp + 'Xp';
		const table = document.querySelector('#' + info.tabId + '-tab table.table-stats');
		const rows = table.rows;
		for (let i = 0; i < rows.length; i++)
		{
			const row = rows[i];
			if (row.getElementsByTagName('th').length > 0)
			{
				continue;
			}

			checkRequirements(row, xpName, true);
		}
	}
	
	const seedBtns = document.querySelectorAll('#seed-menu-popup > div.dialogue-seed-btn');
	const redColor = 'hsla(0, 50%, 75%, 1)';
	for (let i = 0; i < seedBtns.length; i++)
	{
		const seedBtn = seedBtns[i];
		const table = seedBtn.firstElementChild;
		const levelCell = table.rows[0].cells[1];
		const level = parseInt(levelCell.textContent.replace(/\D/g, ''), 10);
		if (level > window.getLevel(window.merchantingXp))
		{
			seedBtn.style.backgroundColor = redColor;
			levelCell.style.color = 'red';
			levelCell.style.textShadow = '0 0 5px white';
		}
	}
}



function fixMarket()
{
	// create an observer instance
	const observer = new MutationObserver(function(mutations)
	{
		mutations.forEach(function(mutation)
		{
			// hide duplicate orb
			var orbs = mutation.target.querySelectorAll('input[alt="upgradeEnchantedRake"]');
			if (orbs.length > 1)
			{
				orbs[1].style.display = 'none';
			}
		});
	});
	// configuration of the observer:
	const config = {
		childList: true
	};

	const table = document.getElementById('selling-tradable-table');
	observer.observe(table, config);

	// fix loading icons
	const loadingImgs = document.querySelectorAll('[src="images/loading_statique.png"]');
	for (var i = 0; i < loadingImgs.length; i++)
	{
		loadingImgs[i].src = 'images/loading.gif';
	}

	const oldFilterBuyables = window.filterBuyables;
	let lastFilterText = null;
	window.filterBuyables = (text) =>
	{
		lastFilterText = text;
		return oldFilterBuyables(text);
	};
	const oldApplyToBuyingTable = window.applyToBuyingTable;
	window.applyToBuyingTable = (...args) =>
	{
		const ret = oldApplyToBuyingTable(...args);
		if (lastFilterText != null)
		{
			window.filterBuyables(lastFilterText);
		}
		return ret;
	};

	// add "clear search"-button
	const searchInput = document.querySelector('input[onkeyup^="filterBuyables"]');
	searchInput.id = 'market-search';
	const tmpWrapper = document.createElement('templateWrapper');
	tmpWrapper.innerHTML = `<input type="button" value="Clear search" style="float: left; margin-left: 10px;" onclick="$('#market-search').val('').keyup()">`;
	const parent = searchInput.parentNode;
	const el = searchInput.nextSibling;
	const childNodes = tmpWrapper.childNodes;
	for (let i = 0; i < childNodes.length; i++)
	{
		parent.insertBefore(childNodes[i], el);
	}

	// fix icon paths
	const oldGetImagePath = window.getImagePath;
	window.getImagePath = (itemVar) =>
	{
		if (itemVar == 'dragonFurnace')
		{
			return 'images/crafting/dragonFurnace.gif';
		}
		return oldGetImagePath(itemVar);
	};

	// auto focus the search input
	const oldSelectItemToTradeDialog = window.selectItemToTradeDialog;
	window.selectItemToTradeDialog = (sellOrBuy, slot) =>
	{
		oldSelectItemToTradeDialog(sellOrBuy, slot);
		window.$('#id_search').focus();
	};
}



const maxLevel = 100;
const maxLevelVirtual = 1000;
let levelXp = new Array(maxLevelVirtual+1);
function calcLevelXp(level)
{
	return level > 0 ? Math.round(Math.pow((level-1), 3 + ((level-1) / 200))) : 0;
}
function getLevelXp(level)
{
	return levelXp[level-1] || calcLevelXp(level);
}
const getDynamicLevel = (function ()
{
	const size = Math.pow(2, Math.ceil(Math.log2(maxLevel)));
	let xpTree = new Array(size);
	let levelTree = new Array(size);
	const sizeVirtual = Math.pow(2, Math.ceil(Math.log2(maxLevelVirtual)));
	let xpTreeVirtual = new Array(sizeVirtual);
	let levelTreeVirtual = new Array(sizeVirtual);
	createNode(xpTree, levelTree, 1, maxLevel, 0);
	createNode(xpTreeVirtual, levelTreeVirtual, 1, maxLevelVirtual, 0);

	function createNode(xpArray, levelArray, start, end, i)
	{
		const current = start + Math.pow(2, Math.floor(Math.log2(end - start + 1))) - 1;
		xpArray[i] = getLevelXp(current);
		levelArray[i] = current;

		if (current - start > 0)
		{
			createNode(xpArray, levelArray, start, current-1, 2*i + 1);
		}
		if (end - current > 0)
		{
			createNode(xpArray, levelArray, current+1, end, 2*i + 2);
		}
	}

	function getDynamicLevel(playerXP, useVirtual = false)
	{
		const isVirtual = window.virtualLevelsOn !== 0 && useVirtual === true;
		const xpArray = isVirtual ? xpTreeVirtual : xpTree;
		const levelArray = isVirtual ? levelTreeVirtual : levelTree;
		let i = 0;
		let level = 0;
		while (xpArray[i] != null)
		{
			if (playerXP == xpArray[i])
			{
				return levelArray[i];
			}
			else if (playerXP < xpArray[i])
			{
				i = 2*i+1;
			}
			else if (playerXP > xpArray[i])
			{
				level = levelArray[i];
				i = 2*i+2;
			}
		}
		return level;
	}

	return getDynamicLevel;
})();
function getLevel(playerXP)
{
	return getDynamicLevel(playerXP, false);
}
function getVirtualLevel(playerXP)
{
	return getDynamicLevel(playerXP, true);
}

function getGlobalLevel()
{
	return getDynamicGlobalLevel(false);
}
function getDynamicGlobalLevel(useVirtual = false)
{
	return Math.floor(getDynamicLevel(parseInt(window.miningXp, 10), useVirtual))
		+ Math.floor(getDynamicLevel(parseInt(window.craftingXp, 10), useVirtual))
		+ Math.floor(getDynamicLevel(parseInt(window.brewingXp, 10), useVirtual))
		+ Math.floor(getDynamicLevel(parseInt(window.merchantingXp, 10), useVirtual))
		+ Math.floor(getDynamicLevel(parseInt(window.exploringXp, 10), useVirtual))
		+ Math.floor(getDynamicLevel(parseInt(window.cookingXp, 10), useVirtual))
		+ Math.floor(getDynamicLevel(parseInt(window.magicXp, 10), useVirtual))
	;
}
function improveLevelCalculation()
{
	if (!getSetting('useFastLevelCalculation'))
	{
		return;
	}

	for (var i = 1; i < maxLevelVirtual; i++)
	{
		levelXp[i-1] = calcLevelXp(i);
	}
	window.getLevel = getLevel;
	window.getVirtualLevel = getVirtualLevel;
	window.getGlobalLevel = getGlobalLevel;
}



function fixInventory()
{
	if (!getSetting('hideUnnecessaryPrice'))
	{
		return;
	}

	const tab = document.getElementById('gatherings-tab');
	const coinImgs = tab.querySelectorAll('span[id^="item-"][id$="-box"] img[src="images/pic_coin.png"]');
	for (let i = 0; i < coinImgs.length; i++)
	{
		const coinImg = coinImgs[i];
		const price = coinImg.nextSibling;
		if (price.nodeType == Node.TEXT_NODE && !/\d/.test(price.textContent))
		{
			const parent = coinImg.parentNode;
			parent.removeChild(coinImg);
			parent.removeChild(price);
		}
	}
}



const oilConsumption = {
	'drill': 1
	, 'crusher': 15
	, 'giantDrill': 30
	, 'roadHeader': 50
	, 'bucketWheelExcavator': 150
	, 'giantBWE': 500
	, 'sandCollector': 5
};
const machineNames = {
	'drill': 'Mining Drill'
	, 'crusher': 'Crusher'
	, 'giantDrill': 'Giant Drill'
	, 'roadHeader': 'Road Header'
	, 'bucketWheelExcavator': 'Excavator'
	, 'giantBWE': 'Mega Excavator'
	, 'sandCollector': 'Sand Collector'
};
function getMachineCount(machine)
{
	return window['binded' + machine[0].toUpperCase() + machine.substr(1)];
}
function getOilValueFromMachine(machine)
{
	return (oilConsumption[machine] || 0) * getMachineCount(machine);
}
function openOilDialogue(varname)
{
	const gearOnPath = 'images/spinning-gear.gif';
	const gearOffPath = 'images/spinning-gear-off.gif';
	const oilArea = document.getElementById('oilUsage-area');
	const oilValue = document.getElementById('oilUsage-value');
	const repairArea = document.getElementById('machinery-repair-area');

	let machine = varname.replace(/key-item-binded([^-]+)-box/, '$1');
	machine = machine[0].toLowerCase() + machine.substr(1);

	// machine name + count
	const name = machineNames[machine];
	const count = getMachineCount(machine);
	const max = 10; // don't know if there is a machine with a different limit...
	let title = document.getElementById('machinery-name');
	if (!title)
	{
		title = document.createElement('h3');
		title.style.marginTop = 0;
		title.id = 'machinery-name';
		const parent = document.getElementById('machinery-dialog');
		parent.insertBefore(title, parent.firstChild);
	}
	title.innerHTML = `${name} <span style="float: right;font-size: 1.2rem;">${count}<span style="font-weight: normal;">/${max}</span><span></span></span>`;

	// PROGRESS BAR
	var hasRepair = window.bindedPromethiumWrench > 0;
	if (machine == 'sandCollector')
	{
		// hide repair part (ensure, it is hidden)
		repairArea.setAttribute('style', 'padding: 0; width: 0px; height: 0px; overflow: hidden; border: 0;');
	}
	else
	{
		// show repair part if available
		repairArea.setAttribute('style', 'display: ' + (hasRepair ? 'block' : 'none') + ';');

		const progressBar = document.getElementById('progress-bar-repair-opened');
		const percent = window[machine + 'Repair'];
		const bgColor = percent < 20 ? 'yellow' : (percent >= 50 ? 'lime' : 'yellow');
		progressBar.style.backgroundColor = bgColor;
		progressBar.style.width = percent + '%';
	}
	// END PROGRESS BAR

	oilValue.innerHTML = window.getOilValueFromMachine(machine);
	document.getElementById('machineryChosenPopup').value = machine;
	const isOn = window[machine + 'AreOn'] == 1;
	document.getElementById('myonoffswitch').checked = isOn;
	document.getElementById('myonoffswitch-gear').src = isOn ? gearOnPath : gearOffPath;
	oilArea.style.display = isOn ? '' : 'none';

	window.$('#machinery-dialog').dialog(
	{
		width: 400
	});
}
function fixMachinery()
{
	const oldChangeSmeltingValue = window.changeSmeltingValue;
	window.changeSmeltingValue = () =>
	{
		window.setSmeltingBarAgain(
			window.barTypeSelectedToSmeltGlobal
			, document.getElementById('smeltingAmountRequested')
		);
	};
	const oldOpenFurnaceDialogue = window.openFurnaceDialogue;
	window.openFurnaceDialogue = () =>
	{
		const ret = oldOpenFurnaceDialogue();
		if (furnacePerc == 0)
		{
			window.changeSmeltingValue();
		}
		return ret;
	};

	const oldRapairMachinery = window.rapairMachinery;
	window.rapairMachinery = () =>
	{
		oldRapairMachinery();
		document.getElementById('perc-all-cost').innerHTML = window.getRepairCost('all', 0).toString().replace(/\B(?=(\d{3})+(?!\d))/g, ',');
	};

	if (!getSetting('improveMachineryDialog'))
	{
		return;
	}

	window.getOilValueFromMachine = getOilValueFromMachine;
	window.openOilDialogue = openOilDialogue;
}



const potionRequirements = {
	'seedPotion': {
		level: 5
		, dottedGreenLeaf: 5
		, redMushroom: 100
		, greenLeaf: 1
	}
};
let oldCanBrewItem;
function canBrewItem(command)
{
	var requirements = potionRequirements[command];
	if (!requirements)
	{
		return oldCanBrewItem(command);
	}

	for (var key in requirements)
	{
		if (key == 'level')
		{
			if (getLevel(brewingXp) < requirements.level)
			{
				return false;
			}
		}
		else if (window[key] < requirements[key])
		{
			return false;
		}
	}
	return true;
}
function fixBrewing()
{
	oldCanBrewItem = window.canBrewItem;
	window.canBrewItem = canBrewItem;

	const marginFix = '5px 20px';
	const potionItems = document.querySelectorAll('#brewing-tab [id$="Potion-box"] img.item-box-img');
	for (let i = 0; i < potionItems.length; i++)
	{
		potionItems[i].style.margin = marginFix;
	}
	const smallImgItems = ['vial','enchantedVial','compost'];
	for (let item of smallImgItems)
	{
		document.querySelector('#item-' + item + '-box img.item-box-img').style.margin = marginFix;
	}
}



const tabs2Fix = {
	repair: {
		name: 'Machinery'
		, url: 'https://www.reddit.com/r/DiamondHunt/wiki/online/tabs/machinery'
	}
	, store: {
		name: 'Market'
		, url: 'https://www.reddit.com/r/DiamondHunt/wiki/online/tabs/market'
	}
	, 'npc-store': {
		name: 'Game Shop'
		, url: 'https://www.reddit.com/r/DiamondHunt/wiki/online/tabs/market/game'
	}
	, 'donor-store': {
		name: 'Donor Shop'
		, url: 'https://www.reddit.com/r/DiamondHunt/wiki/online/tabs/market/donor'
	}
	, 'player-store': {
		name: 'Player Market'
		, url: 'https://www.reddit.com/r/DiamondHunt/wiki/online/tabs/market/player'
	}
	, stats: {
		name: 'Leaderboards'
		, url: 'https://www.reddit.com/r/DiamondHunt/wiki/online/tabs/stats'
	}
	, coop: {
		name: 'Group Tasks'
		, url: 'https://www.reddit.com/r/DiamondHunt/wiki/online/tabs/coop'
	}
	, collectables: {
		name: 'Collectables'
	}
	, miningEngineer: {
		name: 'Mining Engineer'
	}
	, 'ach-explore': {
		name: 'Exploring — Equipment'
		, url: 'https://www.reddit.com/r/DiamondHunt/wiki/online/tabs/exploration#wiki_equipment'
	}
};
function tabTitleLink2Span(title)
{
	const span = title.parentNode;
	span.appendChild(title.firstChild);
	span.removeChild(title);
	span.setAttribute('tooltip', '');
	span.style.color = 'gold';
	span.style.fontSize = '24pt';
}
function fixTabs()
{
	function removeElement(el)
	{
		el.parentNode.removeChild(el);
	}
	/**
	 * some special treatment
	 */

	const achievementTitle = document.querySelector('#ach-tab a');
	tabTitleLink2Span(achievementTitle);

	const npcH1 = document.querySelector('#npc-store-tab h1');
	removeElement(npcH1);

	const vendorBr = document.querySelector('#vendor-tab > br:first-child');
	removeElement(vendorBr);
	const vendorTitle = document.querySelector('#vendor-tab a');
	tabTitleLink2Span(vendorTitle);

	const wizardBr = document.querySelector('#wizard-tab > br:first-child');
	removeElement(wizardBr);

	const achTitle = document.querySelector('#archaeology-tab a');
	achTitle.title = '';
	const achCraftTitle = document.querySelector('#archaeology-crafting-tab a');
	achCraftTitle.textContent = 'Exploring — Crafting'.toUpperCase();
	tabTitleLink2Span(achCraftTitle);
	const cookingTitle = document.querySelector('#cooking-tab a');
	cookingTitle.textContent = 'Exploring — Cooking'.toUpperCase();
	cookingTitle.title = '';
	cookingTitle.parentNode.setAttribute('tooltip', 'Open Wiki');

	const magicSpellbookTitle = document.querySelector('#spellbook-tab a');
	magicSpellbookTitle.textContent = 'Magic — spellbook'.toUpperCase();
	const magicCraftTitle = document.querySelector('#magiccrafting-tab a');
	magicCraftTitle.textContent = 'Magic — Crafting'.toUpperCase();
	tabTitleLink2Span(magicCraftTitle);

	removeElement(document.querySelector('#repair-tab > br:last-child'));
	removeElement(document.querySelector('#repair-tab > br:last-child'));
	removeElement(document.querySelector('#miningEngineer-tab br'));
	removeElement(document.querySelector('#brewing-tab br'));
	removeElement(document.querySelector('#archaeology-tab br'));
	removeElement(document.querySelector('#ach-explore-tab br'));
	removeElement(document.querySelector('#ach-explore-tab br'));
	const archCraftBr = document.querySelector('#archaeology-crafting-tab br');
	archCraftBr.parentNode.insertBefore(document.createElement('br'), archCraftBr);
	removeElement(document.querySelector('#cooking-tab br'));
	removeElement(document.querySelector('#cooking-tab br'));
	removeElement(document.querySelector('#cooking-tab br'));
	removeElement(document.querySelector('#magic-tab br'));
	removeElement(document.querySelector('#magiccrafting-tab br'));
	removeElement(document.querySelector('#magiccrafting-tab br'));
	for (let i = 0; i < 10; i++)
	{
		removeElement(document.querySelector('#magiccrafting-tab > span + br'));
	}
	removeElement(document.querySelector('#store-tab br'));
	removeElement(document.querySelector('#player-store-tab br'));
	removeElement(document.querySelector('#stats-tab br'));
	removeElement(document.querySelector('#stats-tab br'));
	removeElement(document.querySelector('#grouptasks-createorjoin br'));
	removeElement(document.querySelector('#grouptasks-notstarted br'));
	removeElement(document.querySelector('#grouptasks-notstarted br'));
	removeElement(document.querySelector('#grouptasks-started br'));


	for (let key in tabs2Fix)
	{
		const tab = tabs2Fix[key];
		const tabEl = document.getElementById(key + '-tab');
		const tmpEl = document.createElement('tmpWrapper');
		let html = '<center>';
		if (tab.url)
		{
			html += `<span class="activate-tooltip">
				<a class="title-link" href="${tab.url}" target="_blank" title="Open Wiki">${tab.name.toUpperCase()}</a>
			</span>`;
		}
		else
		{
			html += `<span class="activate-tooltip" style="color: gold; font-size: 24pt;">
				${tab.name.toUpperCase()}
			</span>`;
		}
		html += '</center><br>';
		tmpEl.innerHTML = html;
		let el = tabEl.firstElementChild;
		for (let i = tmpEl.children.length-1; i >= 0; i--)
		{
			const child = tmpEl.children[i];
			tabEl.insertBefore(child, el);
			el = child;
		}
	}
}



const recipes = {
	shovel: 'shovel'
	, promethiumWrench: 'bindedPromethiumWrench'
	, glassBlowingPipe: 'bindedGlassBlowingPipe'
	, oilPipe: 'bindedOilPipe'
	, planter: 'bindedPlanter'
	, trowel: 'bindedTrowel'
	, shootingStarCrystal: 'bindedShootingStarCrystal'
	, brewingKit: 'brewingKitBinded'
	, rocket: 'bindedRocket'
	, redPumpJack: 'bindedRedPumpJack'
	, explorersBrush: 'bindedExplorersBrush'
	, oilFactory: 'bindedOilFactory'
	, robot: 'bindedRobot'
	, oilRefinery: 'bindedOilRefinery'
	, superRobot: 'bindedSuperRobot'
	, fishingRod: 'fishingRod'
	, fishingBoat: 'bindedFishingBoat'
	, largeFishingBoat: 'bindedLargeFishingBoat'
};
function hideCraftingRecipes()
{
	if (!getSetting('hideSomeCraftRecipes'))
	{
		return;
	}

	const bindedFurnaceLevel = parseInt(window.bindedFurnaceLevel, 10);
	for (let i = 1; i <= bindedFurnaceLevel; i++)
	{
		const row = document.getElementById('craft-' + furnaceLevels[i] + 'Furnace');
		if (row)
		{
			row.style.display = 'none';
		}
	}

	for (let key in recipes)
	{
		if (window[recipes[key]] != 0)
		{
			document.getElementById('craft-' + key).style.display = 'none';
		}
	}

	// exploring - crafting
	let bindedOvenLevel = -1;
	for (let i = ovenLevels.length-1; i >= 0; i--)
	{
		const type = ovenLevels[i];
		if (bindedOvenLevel == -1 && window['binded' + type[0].toUpperCase() + type.substr(1) + 'Oven'] > 0)
		{
			bindedOvenLevel = i;
		}
		const row = document.getElementById('craft-' + type + 'Oven');
		if (row && bindedOvenLevel >= i)
		{
			row.style.display = 'none';
		}
	}
	const equipmentTypes = {
		'weapon': 'Sword'
		, 'helmet': 'Helmet'
		, 'body': 'Body'
		, 'leg': 'Legs'
	};
	for (let key in equipmentTypes)
	{
		const type = equipmentTypes[key];
		let highestLevel = parseInt(window[key + 'SlotId'], 10) - 1;
		for (let i = barTypes.length-1; i >= 0; i--)
		{
			const bar = barTypes[i];
			if (highestLevel < i && window[bar + type] > 0)
			{
				highestLevel = i;
			}
			const row = document.getElementById('craft-' + bar + type);
			if (row && highestLevel >= i)
			{
				row.style.display = 'none';
			}
		}
	}

	// magic - crafting
	const magicRodTypes = ['gold', 'promethium', 'runite', 'dragon'];
	let bindedWandLevel = -1;
	let bindedStaffLevel = -1;
	for (let i = magicRodTypes.length-1; i >= 0; i--)
	{
		const type = magicRodTypes[i];

		// check wand recipes
		if (bindedWandLevel == -1 && window['binded' + type[0].toUpperCase() + type.substr(1) + 'Wand'] > 0)
		{
			bindedWandLevel = i;
		}
		const wandRow = document.getElementById('craft-' + type + 'Wand');
		if (wandRow && bindedWandLevel >= i)
		{
			wandRow.style.display = 'none';
		}

		// check staff recipes
		if (bindedStaffLevel == -1 && window['binded' + type[0].toUpperCase() + type.substr(1) + 'Staff'] > 0)
		{
			bindedStaffLevel = i;
		}
		const staffRow = document.getElementById('craft-' + type + 'Staff');
		if (staffRow && bindedStaffLevel >= i)
		{
			staffRow.style.display = 'none';
		}
	}
}



function hideEquipment()
{
	if (!getSetting('hideEquipment'))
	{
		return;
	}

	const types = {
		'sword': 'weapon'
		, 'helmet': 'helmet'
		, 'body': 'body'
		, 'legs': 'leg'
	};
	const levels = ['bronze', 'iron', 'silver', 'gold', 'promethium', 'runite', 'dragon'];
	for (let type in types)
	{
		const typeName = type[0].toUpperCase() + type.substr(1);
		const currentLevel = parseInt(window[types[type] + 'SlotId'], 10);
		// hide not more than gold equipment
		for (let i = 0; i < currentLevel && i < 4; i++)
		{
			const el = document.getElementById('item-' + levels[i] + typeName + '-box');
			if (el)
			{
				el.parentNode.style.display = 'none';
			}
		}
	}
}



function improveDialogBtns()
{
	if (!getSetting('improveDialogBtns'))
	{
		return;
	}

	const oldOpenDialogue = window.openDialogue;
	window.openDialogue = (title, message, yesButtonVal) =>
	{
		const [okBtn, cancelBtn] = document.querySelectorAll('#dialog #buttonCommandYes ~ input[type="button"]');
		// restore default state
		const empty = yesButtonVal == null || yesButtonVal == '';
		okBtn.style.display = empty ? 'none' : '';
		okBtn.value = 'OK';
		cancelBtn.value = empty ? 'Close' : 'Cancel';
		if (/stardust/i.test(title))
		{
			okBtn.value = 'Smash it';
		}
		else if (/bind/i.test(title))
		{
			okBtn.value = 'Bind';
		}
		else if (/drink/i.test(title))
		{
			okBtn.value = 'Drink';
		}
		else if (/^EXPLORE/.test(yesButtonVal))
		{
			okBtn.value = 'Start expedition';
		}

		return oldOpenDialogue(title, message, yesButtonVal);
	};

	const oldClicksKeyItem = window.clicksKeyItem;
	window.clicksKeyItem = (varname) =>
 	{
		oldClicksKeyItem(varname);
		if (varname == 'key-item-bindedRocket-box' && rocketTimer == 0)
		{
			const [okBtn, cancelBtn] = document.querySelectorAll('#dialog #buttonCommandYes ~ input[type="button"]');
			okBtn.value = 'Start rocket';
			const textEl = document.querySelector('#dialog #dialog-text');
			textEl.removeChild(textEl.lastChild);
			textEl.removeChild(textEl.lastChild);
			textEl.removeChild(textEl.lastChild);
		}
	};

	const oldOpenFurnaceDialogue = window.openFurnaceDialogue;
	window.openFurnaceDialogue = () =>
	{
		oldOpenFurnaceDialogue();
		if (furnacePerc > 0)
		{
			const [okBtn, cancelBtn] = document.querySelectorAll('#dialog #buttonCommandYes ~ input[type="button"]');
			okBtn.value = 'Cancel smelting';
			cancelBtn.value = 'Close';
		}
	};

	const oldOpenAreaDialogue = window.openAreaDialogue;
	window.openAreaDialogue = () =>
	{
		oldOpenAreaDialogue();
		if (parseInt(exploringTimer) > 0)
		{
			const [okBtn, cancelBtn] = document.querySelectorAll('#dialog #buttonCommandYes ~ input[type="button"]');
			okBtn.value = 'Cancel trip';
			cancelBtn.value = 'Close';
		}
	};
}



function expandEquipment()
{
	if (!getSetting('expandEquipment'))
	{
		return;
	}

	const equipmentRows = document.querySelectorAll('tr[onclick^="openCraftSwordDialogue"]');
	const rowParent = equipmentRows[0].parentNode;
	let newRows = [];
	for (let i = 0; i < equipmentRows.length; i++)
	{
		const row = equipmentRows[i];
		const type = row.getAttribute('onclick').replace(/openCraftSwordDialogue\('([^']+)'\);/, '$1');
		const levels = row.cells[2].textContent.split('/');
		const barCosts = row.cells[3].getAttribute('tooltip').replace(/\D*$/, '').split('/');
		for (let i = 0; i < barTypes.length; i++)
		{
			const bar = barTypes[i];
			const newRow = row.cloneNode(true);
			newRow.id = 'craft-' + bar + type;
			newRow.setAttribute('onclick', '');
			newRow.cells[0].textContent = bar[0].toUpperCase() + bar.substr(1) + ' ' + type;
			newRow.cells[1].firstElementChild.src = 'images/exploring/equipement/' + bar + type + '.png';
			newRow.cells[2].textContent = levels[i];
			newRow.cells[3].firstElementChild.src = 'images/minerals/' + bar + 'Bar.png';
			newRow.cells[3].lastChild.textContent = ' ' + barCosts[i];
			((item) =>
			{
				newRow.addEventListener('click', () => window.craftItem(item));
			})(bar + type);
			newRows.push({
				level: parseInt(levels[i], 10)
				, row: newRow
			});
		}
		rowParent.removeChild(row);
	}
	newRows = newRows.sort((a, b) => a.level - b.level);

	// insert new rows into table
	const rows = rowParent.rows;
	let idx = 0;
	for (let i = 0; i < rows.length && idx < newRows.length; i++)
	{
		const row = rows[i];
		if (row.getElementsByTagName('th').length > 0)
		{
			continue;
		}

		const thisLevel = parseInt(row.cells[2].textContent, 10);
		while (newRows[idx] && newRows[idx].level < thisLevel)
		{
			rowParent.insertBefore(newRows[idx].row, row);
			idx++;
		}
	}
	for (; idx < newRows.length; idx++)
	{
		rowParent.appendChild(newRows[idx].row);
	}
}



function applyNewItemStyle()
{
	if (!getSetting('applyNewItemStyle'))
	{
		return;
	}

	// change how the items are styled
	const style = document.createElement('style');
	style.innerHTML = `
span[class^="inventory-item-box"],
#vendor-tab span.shop-box
{
	position: relative;
}
span[class^="inventory-item-box"] img.item-box-img,
#vendor-tab img[id^="vendor-item-img"]
{
	position: absolute;
	margin: 0 !important;
}
img.item-box-img[height="30px"]  { top: 52.5px; }
img.item-box-img[height="60px"]  { top: 37.5px; }
img.item-box-img[height="70px"]  { top: 32.5px; }
img.item-box-img[height="75px"]  { top: 30px; }
img.item-box-img[height="80px"]  { top: 27.5px; }
img.item-box-img[height="85px"]  { top: 25px; }
img.item-box-img[height="90px"]  { top: 20px; }
img.item-box-img[height="100px"] { top: 9px; }
span[id^="item-binded"] > img.item-box-img[height="100px"]  { top: 17.5px; }
img.item-box-img[height="110px"] { top: 12.5px; }
img.item-box-img[width="55px"]  { left: 42.5px; }
img.item-box-img[width="60px"]  { left: 40px; }
img.item-box-img[width="75px"]  { left: 32.5px; }
img.item-box-img[width="80px"]  { left: 30px; }
img.item-box-img[width="90px"]  { left: 25px; }
img.item-box-img[width="100px"] { left: 20px; }
img.item-box-img[width="110px"] { left: 15px; }
img.item-box-img[width="120px"] { left: 10px; }
span[class^="inventory-item-box"] img.item-box-img[height="60px"][width="60px"] { transform: scale(1.2); }
span[class^="inventory-item-box"] img.item-box-img[height="70px"][width="80px"] { transform: scale(1.2); }
/* this is a special case (converting items into stardust) */
#wizard-tab img.item-box-img[height="50px"] { top: 22px; }
#wizard-tab img.item-box-img[width="50px"] { left: 45px; }

#vendor-tab img[id^="vendor-item-img"]
{
	transform: scale(1.1);
}
/* height: 155px */
img[id^="vendor-item-img"][height="85x"]  { top: 35px; }
/* width: 150px (110px + 40px) */
img[id^="vendor-item-img"][width="80px"]  { left: 35px; }

span[class^="inventory-item-box"] span[id$="mount"],
#ancientCrystalChargesSpan,
#vendor-tab span.box-title
{
	background-color: black;
	border-top: 1px solid rgba(255, 255, 255, 0.5);
	color: white !important;
	font-weight: normal;
	margin: 0 !important;
	padding: 3px;
	padding-right: 9px;
	text-align: center;
	position: absolute;
	bottom: 0;
	left: 0;
	right: 0;
}
span[class^="inventory-item-box"] span[id$="mount"]:not(#energy-amount)::before
{
	content: '${String.fromCharCode(215)}';
	margin-right: 3px;
}
#fishfarmer-img
{
	top: 18px;
}
#hasMapOfTheSea-fishermen
{
	position: absolute;
	bottom: 3px;
	left: 3px;
}
span[class^="inventory-item-box"] span[id$="-price"],
#vendor-tab span[id^="vendor-item-cost"]
{
	font-weight: normal;
	padding-left: 20px;
	position: relative;
	top: 1px;
}
span[class^="inventory-item-box"] span[id$="-price"]:empty,
#brewingKitBinded-price,
span[id$="Potion-price"]
{
	visibility: hidden;
}
span[class^="inventory-item-box"] span[id$="-price"]::before,
#vendor-tab span[id^="vendor-item-cost"]::before
{
	content: '';
	display: inline-block;
	width: 20px;
	height: 20px;
	position: absolute;
	left: 0;
	background-image: url('images/pic_coin.png');
	background-size: 20px 20px;
}
span[class^="inventory-item-box"] img[src="images/pic_coin.png"],
#vendor-tab img[src="images/pic_coin.png"]
{
	display: none;
}
	`;
	document.head.appendChild(style);
	// remove line breaks
	const brs = document.querySelectorAll('[class^="inventory-item-box"] br, span.shop-box br');
	let i = 0;
	while (brs[i] != null)
	{
		brs[i++].parentNode && brs[--i].parentNode.removeChild(brs[i]);
	}
	// give the emerald image the correct class name
	const emeraldAmount = document.getElementById('emeraldAmount');
	const previous = emeraldAmount && emeraldAmount.previousElementSibling;
	previous && previous.classList.add('item-box-img');
}



function applyNewKeyItemStyle()
{
	if (!getSetting('applyNewKeyItemStyle'))
	{
		return;
	}

	// change how key items and machinery is styled
	const style = document.createElement('style');
	style.innerHTML = `
span[class$="-inventory-item-box"]
{
	position: relative;
}
span.item-box-title
{
	color: blue;
	font-weight: bold;
	padding: 4px 8px;
	position: absolute;
	top: 0;
	left: 0;
	right: 0;
	z-index: 10;
}
span.item-box-title > img[src="images/oil.png"]
{
	display: block;
	margin: 0 auto;
}
span.item-box-title > img[src^="images/spinning-gear"]
{
	margin-right: 3px;
	margin-left: -10px;
}
span[class$="-inventory-item-box"] > img
{
	position: absolute;
}
/* heights */
span[class$="-inventory-item-box"] > img[height="80px"]  { top: 60px; }
span[class$="-inventory-item-box"] > img[height="90px"]  { top: 55px; }
span[class$="-inventory-item-box"] > img[height="100px"]  { top: 50px; }
span[class$="-inventory-item-box"] > img[height="110px"]  { top: 45px; }
span[class$="-inventory-item-box"] > img[height="120px"]  { top: 40px; }
span[class$="-inventory-item-box"] > img[height="130px"]  { top: 35px; }
span[class$="-inventory-item-box"] > img[height="140px"]  { top: 30px; }
/* widths */
span[class$="-inventory-item-box"] > img[width="70px"]  { left: 35px; }
span[class$="-inventory-item-box"] > img[width="80px"]  { left: 30px; }
span[class$="-inventory-item-box"] > img[width="90px"]  { left: 25px; }
span[class$="-inventory-item-box"] > img[width="100px"]  { left: 20px; }
span[class$="-inventory-item-box"] > img[width="110px"]  { left: 15px; }
span[class$="-inventory-item-box"] > img[width="120px"]  { left: 10px; }
#key-item-bindedGlassBlowingPipe-box img
{
	top: 75px;
}
span.ghostPipe-wrapper
{
	display: flex;
	flex-wrap: wrap;
	position: absolute;
	top: 66px;
	left: 19px;
	width: 102px;
}
span.ghostPipe-wrapper > img
{
	box-shadow: 0 0 2px black;
	margin: 2px;
}
span.text-wrapper
{
	background-color: black;
	border-top: 1px solid rgba(255, 255, 255, 0.5);
	color: white;
	font-weight: normal;
	line-height: 22px;
	position: absolute;
	bottom: 0;
	left: 0;
	right: 0;
}
span.text-wrapper span[id$="Amount"],
#level-global-4
{
	font-weight: bold;
}
#key-item-handheldOilPump-box span.text-wrapper
{
	display: none;
}
span.text-wrapper img
{
	margin-right: 3px;
}
span.text-wrapper .small-perc-bar
{
	background-color: black;
	border: 0;
	margin: 0;
	padding: 0;
	position: absolute;
	top: -11px;
	left: 0;
	right: 0;
	width: auto;
}
span.text-wrapper .small-perc-bar-inner
{
	background-color: rgba(0, 210, 0, 1) !important;
}
	`;
	document.head.appendChild(style);

	const brs = document.querySelectorAll('span[class$="-inventory-item-box"] br');
	let i = 0;
	while (brs[i] != null)
	{
		const br = brs[i];
		const parent = br.parentNode;
		if (!parent)
		{
			i++;
			continue;
		}
		if (parent.classList.contains('item-box-title'))
		{
			parent.insertBefore(document.createTextNode(' '), br);
		}
		parent.removeChild(br);
	}

	const spans = document.querySelectorAll('span[class$="-inventory-item-box"]');
	let ghostWrapper;
	for (let i = 0; i < spans.length; i++)
	{
		const span = spans[i];
		const childs = span.childNodes;
		let wrapper;
		let foundImg = false;
		for (let j = 0; j < childs.length; j++)
		{
			const child = childs[j];
			if (!foundImg && child.tagName == 'IMG')
			{
				if (/ghostPipeHolder/.test(child.id))
				{
					if (!ghostWrapper)
					{
						ghostWrapper = document.createElement('span');
						ghostWrapper.className = 'ghostPipe-wrapper';
						child.parentNode.insertBefore(ghostWrapper, child);
						j++;
					}
					ghostWrapper.appendChild(child);
					j--;

					if (child.id == 'ghostPipeHolder6')
					{
						foundImg = true;
					}
				}
				else
				{
					foundImg = true;
				}
			}
			else if (foundImg)
			{
				if (!wrapper)
				{
					wrapper = document.createElement('span');
					wrapper.className = 'text-wrapper';
					span.insertBefore(wrapper, child);
					j++;
				}
				wrapper.appendChild(child);
				j--;
			}
		}
		if (wrapper && wrapper.textContent == '')
		{
			wrapper.parentNode.removeChild(wrapper);
		}
	}
}



function hideMaxRecipes()
{
	if (!getSetting('hideMaxRecipes'))
	{
		return;
	}

	const machinery = {
		'drill': 'bindedDrill'
		, 'crusher': 'bindedCrusher'
		, 'giantDrill': 'bindedGiantDrill'
		, 'sandCollector': 'bindedSandCollector'
		, 'roadHeader': 'bindedRoadHeader'
		, 'bucketWheelExcavator': 'bindedBucketWheelExcavator'
		, 'giantBWE': 'bindedGiantBWE'
	};
	for (let key in machinery)
	{
		if (window[machinery[key]] == 10)
		{
			document.getElementById('craft-' + key).style.display = 'none';
		}
	}
}



/**
 * init
 */

document.addEventListener('DOMContentLoaded', function ()
{
	initObservable();
	initSettings();

	fixKeyItems();
	fixFarming();
	fixServerMsg();
	applyNewItemStyle();
	applyNewKeyItemStyle();

	expandEquipment();
	highlightRequirements();
	fixMarket();
	improveLevelCalculation();
	fixInventory();
	fixMachinery();
	fixBrewing();
	fixTabs();
	hideCraftingRecipes();
	hideEquipment();
	improveDialogBtns();
	hideMaxRecipes();
});

})();

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址