// ==UserScript==
// @name DH2 Fixed
// @namespace FileFace
// @description Improve Diamond Hunt 2
// @version 0.9.0
// @author Zorbing
// @grant none
// @run-at document-start
// @include http://www.diamondhunt.co/game.php
// ==/UserScript==
(function ()
{
'use strict';
/**
* observer
*/
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 (key instanceof Array)
{
for (let k of key)
{
observe(k, fn);
}
}
else
{
if (!observedKeys.has(key))
{
observedKeys.set(key, new Set());
}
observedKeys.get(key).add(fn);
}
return fn;
}
function unobserve(key, fn)
{
if (key instanceof Array)
{
let ret = [];
for (let k of key)
{
ret.push(unobserve(k, fn));
}
return ret;
}
if (!observedKeys.has(key))
{
return false;
}
return observedKeys.get(key).delete(fn);
}
function updateValue(key, newValue)
{
const oldValue = window[key];
window[key] = newValue;
if (oldValue !== newValue)
{
(observedKeys.get(key) || []).forEach(fn => fn(key, oldValue, newValue));
}
}
/**
* general functions
*/
let styleElement = null;
function addStyle(styleCode)
{
if (styleElement === null)
{
styleElement = document.createElement('style');
document.head.appendChild(styleElement);
}
styleElement.innerHTML += styleCode;
}
function getBoundKey(key)
{
return 'bound' + key[0].toUpperCase() + key.substr(1);
}
/**
* hide crafting recipes of lower tiers or of maxed machines
*/
const furnaceLevels = ['stone', 'bronze', 'iron', 'silver', 'gold'];
const ovenLevels = ['bronze', 'iron', 'silver', 'gold'];
function hideTierRecipes(max, getKey, init)
{
const keys2Observe = [];
let maxLevel = 0;
for (let i = max-1; i >= 0; i--)
{
const level = i+1;
const key = getKey(i);
const boundKey = getBoundKey(key);
keys2Observe.push(key);
keys2Observe.push(boundKey);
if (window[key] > 0 || window[boundKey] > 0)
{
maxLevel = Math.max(maxLevel, level);
}
const recipeRow = document.getElementById('crafting-' + key);
if (recipeRow)
{
const hide = level <= maxLevel;
recipeRow.style.display = hide ? 'none' : '';
}
}
if (init)
{
observe(keys2Observe, () => hideTierRecipes(max, getKey, false));
}
}
function hideRecipe(key, max, init)
{
const maxValue = typeof max === 'function' ? max() : max;
const boundKey = getBoundKey(key);
const unbound = parseInt(window[key], 10);
const bound = parseInt(window[boundKey], 10);
const recipeRow = document.getElementById('crafting-' + key);
if (recipeRow)
{
const hide = (bound + unbound) >= maxValue;
recipeRow.style.display = hide ? 'none' : '';
}
if (init)
{
observe([key, boundKey], () => hideRecipe(key, max, false));
}
}
function hideCraftedRecipes()
{
function processRecipes(init)
{
// furnace
hideTierRecipes(
furnaceLevels.length
, i => furnaceLevels[i] + 'Furnace'
, init
);
// oil storage
hideTierRecipes(
7
, i => 'oilStorage' + (i+1)
, init
);
// oven recipes
hideTierRecipes(
ovenLevels.length
, i => ovenLevels[i] + 'Oven'
, init
);
// drills
hideRecipe('drills', 10, init);
// crushers
hideRecipe('crushers', 10, init);
// oil pipe
hideRecipe('oilPipe', 1, init);
// row boat
hideRecipe('rowBoat', 1, init);
}
processRecipes(true);
const oldProcessCraftingTab = window.processCraftingTab;
window.processCraftingTab = () =>
{
const reinit = !!window.refreshLoadCraftingTable;
oldProcessCraftingTab();
if (reinit)
{
processRecipes(true);
}
};
}
/**
* fix wood cutting
*/
function fixWoodcutting()
{
addStyle(`
img.woodcutting-tree-img
{
border: 1px solid transparent;
}
`);
}
/**
* fix chat
*/
function fixChat()
{
const oldAddToChatBox = window.addToChatBox;
const lastMsg = new Map();
window.addToChatBox = (userChatting, iconSet, tagSet, msg, isPM) =>
{
if (lastMsg.get(userChatting) == msg)
{
return;
}
lastMsg.set(userChatting, msg);
oldAddToChatBox(userChatting, iconSet, tagSet, msg, isPM);
};
}
/**
* init
*/
function init()
{
hideCraftedRecipes();
fixWoodcutting();
fixChat();
}
document.addEventListener('DOMContentLoaded', () =>
{
const oldDoCommand = window.doCommand;
window.doCommand = (data) =>
{
if (data.startsWith('REFRESH_ITEMS='))
{
const itemDataValues = data.split('=')[1].split(';');
const itemArray = [];
for (var i = 0; i < itemDataValues.length; i++)
{
const [key, newValue] = itemDataValues[i].split('~');
itemArray.push(key);
updateValue(key, newValue);
}
window.refreshItemValues(itemArray, false);
if (window.firstLoadGame)
{
window.loadInitial();
window.firstLoadGame = false;
init();
}
else
{
window.clientGameLoop();
}
return;
}
return oldDoCommand(data);
};
});
/**
* fix web socket errors
*/
function webSocketLoaded(event)
{
if (window.webSocket == null)
{
console.error('no webSocket instance found!');
return;
}
const messageQueue = [];
const oldOnMessage = webSocket.onmessage;
webSocket.onmessage = (event) => messageQueue.push(event);
document.addEventListener('DOMContentLoaded', () =>
{
messageQueue.forEach(event => onMessage(event));
webSocket.onmessage = oldOnMessage;
});
const commandQueue = [];
const oldSendBytes = window.sendBytes;
window.sendBytes = (command) => commandQueue.push(command);
const oldOnOpen = webSocket.onopen;
webSocket.onopen = (event) =>
{
window.sendBytes = oldSendBytes;
commandQueue.forEach(command => window.sendBytes(command));
return oldOnOpen(event);
};
}
function isWebSocketScript(script)
{
return script.src.includes('socket.js');
}
function fixWebSocketScript()
{
if (!document.head)
{
return;
}
const scripts = document.head.querySelectorAll('script');
let found = false;
for (let i = 0; i < scripts.length; i++)
{
if (isWebSocketScript(scripts[i]))
{
// does this work?
scripts[i].onload = webSocketLoaded;
return;
}
}
// create an observer instance
const mutationObserver = new MutationObserver((mutationList) =>
{
mutationList.forEach((mutation) =>
{
if (mutation.addedNodes.length === 0)
{
return;
}
for (let i = 0; i < mutation.addedNodes.length; i++)
{
const node = mutation.addedNodes[i];
if (node.tagName == 'SCRIPT' && isWebSocketScript(node))
{
mutationObserver.disconnect();
node.onload = webSocketLoaded;
return;
}
}
});
});
mutationObserver.observe(document.head, {
childList: true
});
}
fixWebSocketScript();
})();