Hello HentaiVerse,
my account is very old but I only started playing HentaiVerse a week ago (with a gigantic XP bonus due to being donor, so I leveled pretty fast in the beginning). I really like the random encounters but I'm stressed when I have to look at the clock all the time. So I wrote a simple userscript that displays a 30 minute alarm whenever there is an encounter (or dawn of the day) so you know when to refresh the page. It plays a very atmospheric monster sound so you know you are attacked by monsters
I hope someone can enjoy this as well :-)
PS: I found an "Annoying Gun" and a "Barrel" in my inventory, maybe someone wants to buy them? I can't really use them with my low level.
CODE
// ==UserScript==
// @name HV Encounter Clock
// @namespace arxfemme
// @version 1.0
// @description Show 30 minutes Encounter Clock for HentaiVerse
// @author arxfemme
// @match https://e-hentai.org/news.php
// @match https://e-hentai.org/g/*
// @icon https://www.google.com/s2/favicons?sz=64&domain=e-hentai.org
// @grant GM_setValue
// @grant GM_getValue
// ==/UserScript==
(function() {
'use strict';
// Including Count-Down timer by Ezequiel Rabinovich
// https://gist.github.com/warseph/69a3332d9268b9e98ad3bda5d8e72ed5
class Emitter {
constructor() {
this.handlers = {};
}
on(event, handler) {
this.handlers[event] = (this.handlers[event]||[]).concat(handler);
return this;
}
emit(event,...data) {
(this.handlers[event] || []).forEach(handler => handler(...data));
}
}
class CountdownTimer extends Emitter {
constructor(alarm, handlers = () => {}) {
super();
this.time = undefined;
this.current = undefined;
this.interval = undefined;
this.alarm = new Audio(alarm);
this.alarm.loop = true;
this.state = new StateMachine('stopped', ['running'])
.add('running', ['paused', 'done', 'stopped'])
.add('paused', ['running', 'stopped'])
.add('done', ['stopped'])
;
this.startHandlers();
handlers(this.state);
}
startHandlers() {
this.state
.on('stopped', () => {
this.clearInterval();
this.alarm.pause();
this.resetTime();
})
.on('running', () => {
this.resume();
this.tick();
})
.on('paused', () => {
this.clearInterval();
})
.on('done', () => {
this.clearInterval();
this.alarm.play()
.catch(error => console.error(error));
})
;
}
setTime(time) {
this.state.transition('stopped');
this.current = this.time = time;
this.emit('new-time', time);
return this;
}
resetTime() {
this.current = this.time;
this.emit('tick', this.current);
}
tick() {
this.current = Math.max(0, this.current - 1000);
GM_setValue('hv_timer_remaining_time', this.current);
this.emit('tick', this.current);
if (this.current === 0) this.state.transition('done');
}
clearInterval() {
clearInterval(this.interval);
this.interval = undefined;
}
resume() {
this.interval = setInterval(() => this.tick(), 1000);
}
reset() {
this.state.transition('stopped');
}
start() {
this.state.transition('running');
}
pause() {
this.state.transition('paused');
}
mute() {
this.alarm.pause();
}
}
class StateMachine extends Emitter {
constructor(initial, transitions) {
super();
this.states = {
[initial]: transitions
};
this.current = initial;
this.handlers = {};
}
add(name, transitions) {
this.states[name] = transitions;
return this;
}
transition(name) {
if (!this.states[this.current].includes(name)) return false;
this.emit(name, this.current);
this.current = name;
return true;
}
start() {
this.emit(this.current, null);
}
}
const id = name => `tamper-monkey-userscript-timer-${name}`;
const elem = name => document.getElementById(id(name));
const defaultTime = 30 * 60 * 1000;
const sound = 'https://freesound.org/data/previews/195/195572_3624347-lq.mp3';
// CC BY 3.0
// (https://freesound.org/people/jacobalcook/sounds/195572/)
const timer = new CountdownTimer(sound, state => state
.on('running', () => showControl('pause'))
.on('stopped', () => showControl('start'))
.on('stopped', () => stopShaking())
.on('paused', () => stopShaking())
.on('paused', () => showControl('start'))
.on('done', () => shake())
.on('done', () => showControl('mute'))
)
.on('tick', (timeValue) => { time(timeValue); })
.on('new-time', (time) => GM_setValue('hv_timer_remaining_time', time))
.setTime(GM_getValue('hv_timer_remaining_time', defaultTime))
;
const html = `
<style>
@keyframes tamper-monkey-userscript-timer-shake {
0% { -webkit-transform: translate(calc(-50% + 2px), 1px) rotate(0deg); }
10% { -webkit-transform: translate(calc(-50% + -1px), -2px) rotate(-1deg); }
20% { -webkit-transform: translate(calc(-50% + -3px), 0px) rotate(1deg); }
30% { -webkit-transform: translate(calc(-50% + 0px), 2px) rotate(0deg); }
40% { -webkit-transform: translate(calc(-50% + 1px), -1px) rotate(1deg); }
50% { -webkit-transform: translate(calc(-50% + -1px), 2px) rotate(-1deg); }
60% { -webkit-transform: translate(calc(-50% + -3px), 1px) rotate(0deg); }
70% { -webkit-transform: translate(calc(-50% + 2px), 1px) rotate(-1deg); }
80% { -webkit-transform: translate(calc(-50% + -1px), -1px) rotate(1deg); }
90% { -webkit-transform: translate(calc(-50% + 2px), 2px) rotate(0deg); }
100% { -webkit-transform: translate(calc(-50% + 1px), -2px) rotate(-1deg); }
}
.tamper-monkey-userscript-timer-shake {
animation-name: tamper-monkey-userscript-timer-shake;
animation-duration: 0.5s;
animation-iteration-count: infinite;
}
#tamper-monkey-userscript-timer-base {
border: 1px solid #999;
width: 245px;
height: 50px;
border-radius: 20px;
box-shadow: 0 0 15px 0 rgba(0,0,0,0.75);
background-color: rgba(255,255,255,0.8);
position: fixed;
bottom: 5px;
left: 50%;
transform: translate(-50%,0);
z-index: 9999;
font: 400 18px Arial;
}
#tamper-monkey-userscript-timer-time {
background: none;
margin: 15px 10px;
padding: initial;
width: 115px;
border: none;
text-align: left;
font: 400 18px Arial;
color: #333;
display: inline-block;
transform: initial;
align-items: initial;
box-sizing: initial;
word-spacing: initial;
text-indent: initial;
text-transform: initial;
letter-spacing: initial;
text-rendering: initial;
text-shadow: initial;
appearance: initial;
writing-mode: initial;
transition: initial;
outline: initial;
border-radius: initial;
box-shadow: initial;
}
#tamper-monkey-userscript-timer-base button {
border: none;
background: none;
font: 400 18px Arial;
margin: 0 4px;
padding: 0;
transform: initial;
align-items: initial;
box-sizing: initial;
word-spacing: initial;
text-indent: initial;
text-transform: initial;
display: initial;
text-align: initial;
color: initial;
letter-spacing: initial;
text-rendering: initial;
text-shadow: initial;
appearance: initial;
writing-mode: initial;
transition: initial;
outline: initial;
border-radius: initial;
box-shadow: initial;
}
#tamper-monkey-userscript-timer-base #tamper-monkey-userscript-timer-pause {
display: none;
}
#tamper-monkey-userscript-timer-base #tamper-monkey-userscript-timer-mute {
display: none;
}
</style>
<div id="tamper-monkey-userscript-timer-base">
<input id="tamper-monkey-userscript-timer-time" type="time" step="1" value="00:30:00" required>
<button id="tamper-monkey-userscript-timer-start">▶️</button>
<button id="tamper-monkey-userscript-timer-pause">⏸</button>
<button id="tamper-monkey-userscript-timer-mute">������</button>
<button id="tamper-monkey-userscript-timer-reset">⏮</button>
<button id="tamper-monkey-userscript-timer-close">❎</button>
</div>`;
const controls = ['start', 'pause', 'mute'];
function instrument() {
if (elem('base')) return;
document.body.insertAdjacentHTML('beforeend', html);
const event_el = document.getElementById('eventpane');
const event_text = event_el ? event_el.textContent : "";
if (event_text.includes('encounter') || event_text.includes('dawn')) {
let new_time = 30 * 60 * 1000 - (1 * 1000);
time(new_time);
timer.setTime(new_time);
}
else {
time(timer.time);
}
window.requestAnimationFrame(function() {
timer.start();
});
elem('close').addEventListener('click', () => timer.reset());
elem('reset').addEventListener('click', () => timer.reset());
elem('start').addEventListener('click', () => timer.start());
elem('pause').addEventListener('click', () => timer.pause());
elem('mute').addEventListener('click', () => timer.mute());
elem('time').addEventListener('change', () => timer.setTime(time()));
elem('close').addEventListener('click', () => elem('base').remove());
}
function showControl(name) {
controls.forEach(control =>
(elem(control).style.display = control === name ? 'initial' : 'none')
);
}
function shake() {
elem('base').className = 'tamper-monkey-userscript-timer-shake';
}
function stopShaking() {
elem('base').className = '';
}
function time(newValue = undefined) {
if (newValue !== undefined) {
elem('time').valueAsNumber = newValue;
} else {
return elem('time').valueAsNumber;
}
}
instrument();
})();
This post has been edited by arxfemme: Apr 25 2022, 20:40