Skip to content

Instantly share code, notes, and snippets.

@toriningen
Last active June 29, 2024 20:54
Show Gist options
  • Save toriningen/e89bfb6dbb46fe86cbedde1c99cfbb75 to your computer and use it in GitHub Desktop.
Save toriningen/e89bfb6dbb46fe86cbedde1c99cfbb75 to your computer and use it in GitHub Desktop.
A Better Dark Room (QoL userscript)
// ==UserScript==
// @name A Better Dark Room
// @namespace http://tampermonkey.net/
// @version 2024-06-29
// @description quality of life improvements
// @author toriningen
// @match https://adarkroom.doublespeakgames.com/*
// @icon https://adarkroom.doublespeakgames.com/favicon.ico
// @grant none
// ==/UserScript==
(function() {
'use strict';
function addStyle(css) {
const id = 'trng-style';
const style = document.getElementById(id) || (() => {
const style = document.createElement('style');
style.id = id;
style.type = 'text/css';
document.head.appendChild(style);
return style;
})();
const sheet = style.sheet;
sheet.insertRule(css.trim(), (sheet.rules || sheet.cssRules || []).length);
}
const trngButtonCls = 'trng-button';
const trngWeaponCls = 'trng-weapon';
function addButtonStyle() {
addStyle(`
.${trngButtonCls}::before {
content: '';
position: absolute;
top: 0;
left: 0;
width: 100%;
height: 100%;
pointer-events: none;
box-sizing: border-box;
}
`);
addStyle(`
.${trngButtonCls}::before {
background: rgba(0,255,0,0.3);
}
`);
addStyle(`
.disabled.${trngButtonCls}::before {
background: rgba(0,255,0,0.1);
}
`);
}
function addWeaponStyle() {
addStyle(`
.${trngWeaponCls}::before {
content: '';
display: block;
position: absolute;
left: -1.1em;
top: -0.25em;
width: 100%;
height: calc(100% + 0.5em);
background: rgba(255,0,0,0.3);
pointer-events: none;
box-sizing: border-box;
}
`);
}
addWeaponStyle();
addButtonStyle();
const autoClickButtons = new Set();
const selectedWeapons = new Set(["fists"]);
function makeCooldownObserver() {
return new MutationObserver(
(mutations) => {
for (const mutation of mutations) {
if (mutation.type !== 'attributes') {
continue;
}
if (mutation.attributeName !== 'class') {
continue;
}
const $target = $(mutation.target);
if ($target.hasClass('disabled')) {
continue;
}
$target.trigger('cooldown');
}
}
);
}
const stateKey = 'trngSave';
function saveState() {
}
function loadState() {
}
function isAutoClickButton(btn) {
return autoClickButtons.has(btn);
// return $(btn).hasClass(trngButtonCls);
}
function addAutoClickButton(btn) {
autoClickButtons.add(btn);
const $btn = $(btn);
const cooldownObserver = makeCooldownObserver();
$btn.data('cooldownObserver', cooldownObserver);
$btn.on('cooldown', () => {
if (autoClickButtons.has(btn)) {
$btn.click();
}
});
$btn.addClass(trngButtonCls);
cooldownObserver.observe(btn, { attributes: true, attributeFilter: ['class'] });
if (!$btn.hasClass('disabled')) {
$btn.click();
}
saveState();
}
function removeAutoClickButton(btn) {
autoClickButtons.delete(btn);
const $btn = $(btn);
const cooldownObserver = $btn.data('cooldownObserver');
if (cooldownObserver != null) {
cooldownObserver.disconnect();
}
$btn.removeClass(trngButtonCls);
saveState();
}
function toggleWeapon(row) {
const $row = $(row);
const key = ($row.attr('key') || '').replace(/ /g, '-');
if (!key) {
return;
}
const wasActive = $row.hasClass(trngWeaponCls);
if (wasActive) {
selectedWeapons.delete(key);
$row.removeClass(trngWeaponCls);
} else {
selectedWeapons.add(key);
$row.addClass(trngWeaponCls);
}
saveState();
}
function waitForFight() {
function handleNode(node) {
for (const weapon of selectedWeapons) {
const sel = `#attack_${weapon}`;
const attackBtn = $(node).find(sel).addBack(sel).filter(sel)[0];
if (attackBtn != null) {
addAutoClickButton(attackBtn);
}
}
}
const observer = new MutationObserver(
(mutations) => {
for (const mutation of mutations) {
if (mutation.type !== 'childList') {
continue;
}
for (const node of mutation.addedNodes) {
if (node.nodeType !== Node.ELEMENT_NODE) {
continue;
}
handleNode(node);
}
}
}
);
observer.observe(document, { subtree: true, childList: true });
}
document.addEventListener('click', function(event) {
if (!event.altKey) {
return;
}
if (!event.target.matches('.button')) {
return;
}
event.stopImmediatePropagation();
event.preventDefault();
if (event.target.matches('.eventPanel .button')) {
// only top-level buttons supported
return;
}
const target = event.target;
const $target = $(target);
if (!isAutoClickButton(target)) {
addAutoClickButton(target);
} else {
removeAutoClickButton(target);
}
}, true);
$('#outfitting').on('click', '.outfitRow', (event) => {
if (!event.altKey) {
return;
}
event.stopImmediatePropagation();
event.preventDefault();
toggleWeapon(event.target);
});
loadState();
waitForFight();
})();
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment