> HV Encounter Clock

 
post Apr 25 2022, 19:55
Post #1
arxfemme



Lurker
Group: Gold Star Club
Posts: 2
Joined: 30-October 14
Level 257 (Godslayer)


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 biggrin.gif

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
User is offlineProfile CardPM
Report PostGo to the top of the page
+Quote Post

 
Reply to this topicStart new topic
Replies(1 - 1)
 
post Apr 25 2022, 22:57
Post #2
puppydoll



Casual Poster
****
Group: Members
Posts: 478
Joined: 7-August 13
Level 425 (Godslayer)


ty for writing this script, but there is HV Ulti script already and there is time clock on encountering monster already.

User is offlineProfile CardPM
Report PostGo to the top of the page
+Quote Post


Fast ReplyReply to this topicStart new topic
1 User(s) are reading this topic (0 Guests and 0 Anonymous Users)
1 Members: k999k99

 


Lo-Fi Version Time is now: 27th September 2022 - 17:49