// ==UserScript==
// @name DH3 KindaSafe Cheat
// @namespace http://tampermonkey.net/
// @version 1.2.1
// @description The cheat script for DH3
// @author Lasse Brustad
// @match https://dh3.diamondhunt.co/
// @grant none
// ==/UserScript==
/* jshint esversion:6 */
(function() {
'use strict';
// config for cheats
const cheats = {
// auto fight, configs starting at line 45
autoCombat: !true,
// auto smelt ores, click the ore under the mining tab to choose
// will automatically fill the furnace to it's maximum capacity
// configs starting at line 70
autoSmelt: !true,
// auto chop trees, it's fully automated with a tiny issue that doesn't matter
autoChop: !true,
// auto farm, configs starting at line 76 - not ready yet
autoFarm: !true,
// auto consume stardust potions you have
autoDrinkSD: !true,
// auto send/collect the Oxygen Tank, you can't get any fish at all with this on
autoOxy: !true,
// auto send/collect the Row Boat, this is forced off if autoOxy is on
autoRowBoat: !true,
// auto send/collect the Canoe Boat, this is forced off if autoOxy or autoRowBoat is on
autoCanoeBoat: !true
};
const combatConfig = {
areas: {
// area name : energy cost
// this shouldn't be a problem
fields: 50,
// don't forget your weapon
forest: 200,
// be prepared with armor and weapon
caves: 500,
// you might lose against the alien!
lavaDungeon: 2e3,
// this script will lose most likely 99% of all attempts
northernFields: 5e3
},
// the area you want to fight automatically from the "areas" list
area: 'fields' // prefer stored value, later changing the string here have no effect
}
// additional config for autoSmelt
const smeltConfig = {
// smelt all resources that can be smelted (not ready yet)
smeltAllAvaliable: true
}
// additional configs for autoFarm
const farmConfig = {
// plant seeds even if they require bonemeal
allowBonemealUsage: false,
// fill bonemeal bin with fishbones, ashes, or bones when possible
autoFillBonemealBin: false,
// allow planting seeds that can die
allowDyingPlants: false
};
// config for legal mods
const mods = {
// right click the axe to chop down all fully grown trees
chopTrees: true,
// right click the rake to harvest all the ready farms
harvestCrops: true
};
/**
* Code below here is functional code, but you can enable/disable everything in the configs above
*
* Remember, cheats is safe to use as it is, but if you mess with the code,
* don't blame me if you get banned! Cheats is ofc not allowed, but who cares?
*/
// logging / debugging
const debugLevels = [
'silent',
'normal logging',
'additional logging',
'debugging'
];
let debugLevel = parseInt(localStorage.getItem('lbdata-debug')) || 1;
window.setDebugLevel = (lvl = debugLevel) => {
if (typeof lvl !== 'number' || (lvl < 0 && lvl > (debugLevels.length - 1))) {
console.log(`Didn't change the logging level, it has to be a number between 0 and 3.`);
return;
}
const previous = debugLevel;
debugLevel = lvl;
if (previous === debugLevel) {
console.log(`Current debug level is: ${lvl} ~ ${debugLevels[lvl]}`);
} else {
console.log(`Debug level is now set to: ${lvl} ~ ${debugLevels[lvl]}`);
}
}
// auto combat
let willFightSoon = false;
let fightingError = JSON.parse(localStorage.getItem('lbdata-combatError')) || false;
function autoCombat() {
// damn, didn't expect this function to require that much anti-fail testing
if (fightingError) return;
if (willFightSoon || window.getItem('heroCooldown') !== 0) return debug(3, `Combat isn't ready yet`);
if (!Object.keys(combatConfig.areas).includes(combatConfig.area)) {
fightingError = true;
debug(2, `The script has no area called ${combatConfig.area} registered!`);
return;
}
if (combatConfig.areas[combatConfig.area] > window.getItem('energy')) return debug(2, `You're low on energy! Eat some food to continue fighting!`);;
// FIGHT!!!
willFightSoon = true;
safeDelay(() => {
setTimeout(() => {
willFightSoon = false;
}, 30e3);
if (window.getItem('heroCooldown') !== 0) return debug(3, `Combat isn't ready yet`);
window.sendBytes(`FIGHT=${combatConfig.area}`);
})
}
// settings for autoCombat while playing
window.setCombatStatus = (state = null) => {
if (typeof state === 'boolean') {
fightingError = !state;
console.log(`Set the state to ${state ? 'active' : 'inactive'}`);
} else if (typeof state === 'string' && typeof combatConfig.areas[state] === 'number') {
combatConfig.area = state;
console.log(`Set the area to ${state}`);
} else if (state === null) {
console.log(`Current state: Fighting ${combatConfig.area} is ${!fightingError ? 'active' : 'inactive'}`);
}
}
unload(e => {
localStorage.setItem('lbdata-combatError', JSON.stringify(fightingError));
localStorage.setItem('lbdata-combatArea', combatConfig.area);
});
// auto smelt ores
if (cheats.autoSmelt) {
window.smeltOre = localStorage.getItem('lbdata-smeltOre') || 'copper'; // the ore to smelt
unload(e => {
localStorage.setItem('lbdata-smeltOre', window.smeltOre);
});
}
const ores = {
sand: {
oil: 1,
time: 1
},
copper: {
oil: 1,
time: 1
},
iron: {
oil: 5,
time: 5
},
silver: {
oil: 20,
time: 20
},
gold: {
oil: 100,
time: 60
},
promethium: {
oil: 1000,
time: 200
}
};
function cheatSmelt() {
if (typeof ores[window.smeltOre] !== 'object') return debug(1, `Cheat - Unknown ore: "${window.smeltOre}"`);
function doit() {
if (window.isSmelting()) {
// wait till current smelting is over
const estimated = (window.var_smeltingRequestedAmount - window.var_smeltingCurrentAmount) * window.var_smeltingNeededTimer;
debug(3, `isSmelting() === true, estimated time: ${estimated}s`);
safeDelay(doit, estimated * 1e3 / 3);
return;
}
const hasAmount = parseInt(window['var_' + window.smeltOre]),
furnaceCapacity = parseInt(window.var_furnaceCapacity);
if (isNaN(hasAmount) || hasAmount < furnaceCapacity || (ores[window.smeltOre].oil * furnaceCapacity) > parseInt(window.var_oil)) {
debug(3, `have ${hasAmount} ${window.smeltOre} and ${window.var_oil} oil`);
// wait even longer when stuff is missing
safeDelay(doit, 6e3);
return;
}
debug(2, `Starts smelting ${window.var_furnaceCapacity} ${window.smeltOre}!`);
window.smelt(window.smeltOre, window.var_furnaceCapacity);
safeDelay(cheatSmelt, ores[window.smeltOre].time * window.var_furnaceCapacity * 1e3);
}
safeDelay(doit);
}
function clicksItemMod() {
const orig = window.clicksItem;
window.clicksItem = (item, ...args) => {
if (typeof ores[item] === 'object') {
window.smeltOre = item;
}
orig(item, ...args);
};
}
// auto chop trees
function cheatChop() {
const treeData = {
click(n) {
debug(2, `Auto Chop - Chopping patch ${n}`);
document.getElementById(`tree-section-${n}`).click();
setTimeout(() => window.closeDialogue('dialogue-confirm'), 1e3);
},
timer(n) {
return window[`var_treeTimer${n}`] * 1;
},
isActive(n) {
return window[`var_tree${n}`] !== 'none';
}
};
const tasks = [null, false, false, false, false, false, false];
function chop(num, waitMinSec = 0) {
if (tasks[num]) return;
tasks[num] = true;
safeDelay(() => {
tasks[num] = false;
if (!treeData.isActive(num)) return;
treeData.click(num);
}, waitMinSec * 1e3);
}
function loop() {
for (let i = 1; i < tasks.length; i++) {
const timeLeft = treeData.timer(i);
if (timeLeft < 10) chop(i, timeLeft);
}
}
setInterval(loop, 1e4);
}
// auto farm
const seeds = { // named window.var_${key}Seeds
// data found at https://anwinity.com/DH3/#farmingBrewing
redMushroom: {
// required level to plant
lvlRequired: 1,
// stops dying level
stopsDying: 0,
// bonemeal required
bonemeal: 0,
// time in minutes
time: 15
},
stardust: {
lvlRequired: 15,
stopsDying: 0,
bonemeal: 5,
time: 30
},
dottedGreenLeaf: {
lvlRequired: 1,
stopsDying: 15,
bonemeal: 0,
time: 15
},
greenLeaf: {
lvlRequired: 10,
stopsDying: 25,
bonemeal: 0,
time: 30
},
limeLeaf: {
lvlRequired: 30,
stopsDying: 40,
bonemeal: 5,
time: 60
},
goldLeaf: {
lvlRequired: 45,
stopsDying: 55,
bonemeal: 20,
time: 120
},
crystalLeaf: {
lvlRequired: 70,
stopsDying: 80,
bonemeal: 50,
time: 300
},
// stripedGoldLeaf: {
// lvlRequired: 80,
// stopsDying: 88,
// bonemeal: 120,
// time: 600
// },
// stripedCrystalLeaf: {
// lvlRequired: 90,
// stopsDying: 95,
// bonemeal: 200,
// time: 960
// },
tree: {
lvlRequired: 1,
stopsDying: 10,
bonemeal: 0,
time: 60
},
oakTree: {
lvlRequired: 15,
stopsDying: 0,
bonemeal: 5,
time: 90
},
willowTree: {
lvlRequired: 30,
stopsDying: 40,
bonemeal: 10,
time: 120
},
bambooTree: {
lvlRequired: 40,
stopsDying: 50,
bonemeal: 20,
time: 140
},
mapleTree: {
lvlRequired: 50,
stopsDying: 60,
bonemeal: 50,
time: 220
},
lavaTree: {
lvlRequired: 60,
stopsDying: 70,
bonemeal: 60,
time: 300
},
pineTree: {
lvlRequired: 65,
stopsDying: 75,
bonemeal: 75,
time: 320
},
stardustTree: {
lvlRequired: 70,
stopsDying: 80,
bonemeal: 100,
time: 360
}
// appleTree: {
// lvlRequired: 45,
// stopsDying: 55,
// bonemeal: 30,
// time: 163
// },
// bananaTree: {
// lvlRequired: 63,
// stopsDying: 73,
// bonemeal: 65,
// time: 175
// }
};
const plots = [
window.getItem('plotTimer1') || null,
window.getItem('plotTimer2') || null,
window.getItem('plotTimer3') || null,
window.getItem('plotTimer4') || null,
window.getItem('plotTimer5') || null,
window.getItem('plotTimer6') || null
];
function autoFarm() {
function sortedSeeds() {
const _seeds = [];
for (let name of Object.keys(seeds)) {
const owned = window.getItem(`${name}Seeds`);
if (owned < 1) continue;
_seeds.push({name, owned});
}
return _seeds.sort((a, b) => a.name.localeCompare(b.name));
}
}
// auto drink stardust potion
let willConsumeSDPot = false;
function autoSDPot() {
const timeLeft = parseInt(window.var_stardustPotionTimer);
if (timeLeft <= (5 * 60) && parseInt(window.var_stardustPotion) > 0 && !willConsumeSDPot) {
willConsumeSDPot = true;
safeDelay(() => {
window.sendBytes('DRINK=stardustPotion');
setTimeout(() => {
willConsumeSDPot = false;
}, 3e3);
});
}
}
// auto boat
let willUseBoat = false;
function cheatAnyBoat(str = 'oxygenTank') {
if (willUseBoat) return;
const tLeft = window.getItem(str + "Timer");
if (tLeft > 2) return;
let task = () => {};
switch (tLeft) {
case 0:
willUseBoat = true;
task = () => window.sendBytes("SEND_BOAT=" + str);
break;
case 1:
willUseBoat = true;
task = () => window.sendBytes("COLLECT_BOAT=" + str);
break;
}
safeDelay(() => {
const timeLeft = window.getItem(str + "Timer");
if (timeLeft === tLeft) task();
willUseBoat = false;
});
}
function initCheats() {
// combat
if (cheats.autoCombat) {
setInterval(autoCombat, 1e3);
debug(1, 'Cheat - Initialized Auto Combat');
}
// mining/crafting
if (cheats.autoSmelt) {
cheatSmelt();
clicksItemMod();
debug(1, 'Cheat - Initialized Auto Smelt');
}
// woodcutting
if (cheats.autoChop) {
cheatChop();
debug(1, 'Cheat - Initialized Auto Chop');
}
// farming
if (cheats.autoFarm) {
autoFarm();
debug(1, 'Cheat - Initialized Auto Farm');
}
// brewing
if (cheats.autoDrinkSD) {
setInterval(autoSDPot, 2e3);
debug(1, 'Cheat - Initialized Auto Drink Stardust Potion');
}
// fishing
if (cheats.autoOxy) {
setInterval(cheatAnyBoat, 1e3);
debug(1, 'Cheat - Initialized Auto Oxygen Tank');
} else if (cheats.autoRowBoat) {
setInterval(() => cheatAnyBoat('rowBoat'), 1e3);
debug(1, 'Cheat - Initialized Auto Row Boat');
} else if (cheats.autoCanoeBoat) {
setInterval(() => cheatAnyBoat('canoeBoat'), 1e3);
debug(1, 'Cheat - Initialized Auto Canoe Boat');
}
}
// mod 1 - RightClick axe to chop all trees
function chopTrees(e) {
const trees = getEls('#tree-section-woodcutting > center > div');
e.preventDefault();
trees.each(el => {
const timeEl = el.querySelector('.tree-secton-timer');
const time = timeEl !== null ? timeEl.innerText : '';
if (time === 'READY') el.click();
});
debug(2, 'Chopped all trees');
}
// mod 2 - RightClick rake to harvest the crops
function harvestCrops(e) {
const trees = getEls('#plot-section-farming > center > div');
e.preventDefault();
trees.each(el => {
const timeEl = el.querySelector('.tree-secton-timer');
const time = timeEl !== null ? timeEl.innerText : '';
if (time === 'READY') el.click();
});
debug(2, 'Harvested all crops');
}
function initMods() {
if (mods.chopTrees) {
// init mod 1
getEls('#item-section-woodcutting-1 [data-tooltip-id=tooltip-axe]')
.each(el => el.addEventListener('contextmenu', chopTrees));
debug(1, 'Mod - Initialized Right Click Axe');
}
if (mods.harvestCrops) {
// init mod 2
getEls('#item-section-farming-1 [data-tooltip-id=tooltip-rake]')
.each(el => el.addEventListener('contextmenu', harvestCrops));
debug(1, 'Mod - Initialized Right Click Rake');
}
}
function init() {
if (typeof window.var_username === "string" && window.var_username.length >= 3) {
initMods();
debug(1, 'Initialized Mods');
initCheats();
debug(1, 'Initialized Cheats');
} else {
setTimeout(init, 2e3);
}
}
setTimeout(init, 2e3);
/**
* minor functions for this script to work well with clean code
*/
function getEls(qSel) {
let els = document.querySelectorAll(qSel);
return {
getRaw() {
return els;
},
getNum(x) {
return els[x];
},
each(fn) {
els.forEach(fn);
},
ids() {
let res = [];
for (let key of els) res.push(key.id || 'none');
return res;
}
}
}
function debug(lvl, ...msg) {
if (lvl > debugLevel) {
return;
}
switch (lvl) {
case 0: // silent
return;
case 1: // standard logging
case 2: // additional logging
return console.log('DH3 KindaSafe:', ...msg);
case 3: // debugging
return console.log('DH3 KindaSafe Debugging:', ...msg);
}
}
function unload(fn) {
window.addEventListener('unload', fn);
}
// A safe cheat delayer
function safeDelay(fn, minTime = 0) {
setTimeout(fn, Math.floor(Math.random() * 9e3) + 1e3 + minTime);
}
function smeltMax(resource) {
if (window.isSmelting()) return `Your furnace in unavaliable!`;
const cost = window.getOilCost(resource);
if (cost === 0) return `Can't smelt "${resource}"`;
let cap = window.getItem('furnaceCapacity'),
max = window.getItem(resource) > cap ? cap : window.getItem(resource);
if (max === 0) return `You don't have any ${resource}!`;
const oil = window.getItem('oil');
max = (max * cost) < oil ? max : Math.min(oil / (max * cost));
if (max === 0) return `You don't have enought oil to smelt ${resource}`;
window.smelt(resource, max); // will smelt maximum possible of resource
}
window.smeltMax = smeltMax;
function smeltableResources() {
const result = [];
const _ores = Object.keys(ores).reverse();
for (let ore of _ores) {
if (ore === window.smeltOre && cheats.autoSmelt) continue;
if (window.getItem(ore) !== 0) result.push(ore);
}
return result;
}
window.smeltableResources = smeltableResources;
function smeltAvaliable() {
if (window.isSmelting()) return `Your furnace in unavaliable!`;
const avaliable = smeltableResources();
if (avaliable.length === 0) return `You don't have any smeltable resources!`;
smeltMax(avaliable[0]);
}
window.smeltAvaliable = smeltAvaliable;
})();