Welcome Guest ( Log In | Register )

 
Reply to this topicStart new topic
> [Script] Hentaiverse Battle Stats, A modern replacement for old statistic tracking tools (v 1.1.3)

 
post Nov 26 2020, 09:39
Post #1
Firew



Casual Poster
****
Group: Gold Star Club
Posts: 258
Joined: 22-February 11
Level 500 (Ponyslayer)



Hentaiverse Battle Stats
Ver. 1.1.3
Attached Image



I've seen some requests for an updated stats tracker. I've been using mine for a while, so I finally polished it up enough to release.

Requirements:
Monsterbation
HVUtils
Firefox or Chrome with Tampermonkey


Download:
Attached File  Battle_Stats.js.txt ( 73.02k ) Number of downloads: 7799


Features:
  1. Saves everything about your battles using monsterbation and hvutils data.
  2. Runs only at the end of every battle, so no performance impact.
  3. Ultra-fast Querying using the browser's built-in IndexedDB database.
  4. Advanced Table view with filters, highlights, tooltips, averages, totals, and min/max statistics.
  5. Highly customizable column system allows you to see what you want to see.
  6. DRILL DOWN and view each battle or DRILL UP and view totals per day.
  7. Accessible in a drop-down integrated with the other menus OR on a separate page (loads even in battle).
  8. Export your data to JSON files to save or share.
Attached ImageAttached Image

Installation Instructions (also included in the script):
  1. Install this script, Monsterbation, and HVUtils
  2. In Monsterbation settings, set trackDrops, trackProficiency, trackSpeed, trackDamage, trackUsage to on
  3. In Monsterbation settings, set deleteDropLog and deleteCombatLog to 2.


Acknowledgements:
Members of the Discord Server for preliminary testing.


Feedback is welcome. Please post in this topic for any bugs or feedback.

--------------------
This looks really weird with a sig, so I'm making a fake one.

This post has been edited by Firew: Feb 10 2021, 04:52
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post Nov 26 2020, 09:39
Post #2
Firew



Casual Poster
****
Group: Gold Star Club
Posts: 258
Joined: 22-February 11
Level 500 (Ponyslayer)


reserved
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post Nov 26 2020, 09:39
Post #3
Firew



Casual Poster
****
Group: Gold Star Club
Posts: 258
Joined: 22-February 11
Level 500 (Ponyslayer)


reserved
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post Jan 8 2021, 11:44
Post #4
what_is_name



Regular Poster
******
Group: Gold Star Club
Posts: 780
Joined: 5-May 19
Level 500 (Ponyslayer)


some advices:
combatlog/timelog and etc. in Hentaiverse Monsterbation are global variables, and both scripts dirctly run in browser as they grant none permission, so you don't need to transfer them via localStorage, just use window.combatlog/window.timelog to reach them. Ignore this now, it not work, I may messed up different test
Beside that, you only need to dispatch an event after battle end. Change the event name to battleEnd and add it to the main function of hvmb should be more reasonable and clear:

CODE

// main function triggered on new turn
function Observe() {
    // check for battle end
    if ( document.querySelector('img[src$="finishbattle.png"]') ) {
        if ( cfg.alertColours ) {
            document.getElementById(cfg.alertBackground ? 'csp' : 'pane_vitals').style.background = cfg.colours.default;
            document.getElementById('pane_effects').style.background = cfg.colours.default;
            document.getElementById('ckey_spirit').style.background = cfg.colours.default; }
        ProcessLog();
        FormatLog();
        TrackDrops();
        Profbar();
        ShowDrops(true);
        ShowUsage();
        ShowDamage();
        window.dispatchEvent(new Event('battleEnd')); // Used for Battle Stats or maybe other scripts



This post has been edited by what_is_name: Jan 26 2021, 08:00
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post Jan 26 2021, 07:07
Post #5
Firew



Casual Poster
****
Group: Gold Star Club
Posts: 258
Joined: 22-February 11
Level 500 (Ponyslayer)


I am having trouble getting it to work the way you describe.

I am not seeing the window.combatlog or window.timelog variables when I load a battle with monsterbation.

CODE
// ==UserScript==
// @name         Testing
// @namespace    http://tampermonkey.net/
// @version      0.1
// @description  try to take over the world!
// @author       You
// @match        *://*.hentaiverse.org/*
// @grant        none
// ==/UserScript==

console.log(window.timelog);
console.log(window.combatlog);


Both return
CODE
undefined
undefined


It cannot see the monsterbation variables.
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post Jan 26 2021, 07:41
Post #6
what_is_name



Regular Poster
******
Group: Gold Star Club
Posts: 780
Joined: 5-May 19
Level 500 (Ponyslayer)


That's strange, I assume the global variables auto assign to window if they run without sandbox and I remember I tested it before I post, but I get same result as your test now, I may messed up different test when I posted it. Anyway the describe above is not work, so as result you need to contact sickentide about HVMB change now. A window global variables is fine, beside another way the CustomEvent can transfer datas also, like
CODE
window.dispatchEvent(new CustomEvent("battleEnd", {"detail":{timelog,combatlog,droplog}}));

Of couse it up to you and sickentide's choose, ignore my post above now

This post has been edited by what_is_name: Feb 1 2021, 08:19
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post Feb 10 2021, 04:45
Post #7
Firew



Casual Poster
****
Group: Gold Star Club
Posts: 258
Joined: 22-February 11
Level 500 (Ponyslayer)


Updated to 1.1.3

Attached File  Battle_Stats.js.txt ( 73.02k ) Number of downloads: 1157


This update properly integrates changes in monsterbation and HVUtils. You do not need to modify monsterbation anymore. This works out of the box thanks to some changes by sickentide.

Please use the following checkboxes to select Persistent data, Isekai data, or both (or none?). You can also specify the default within the script.

Attached Image

In the interest of time, I have not updated some parts of the script listed below. These will be fixed at a later point when I have more time to work on this:

1. there is no option to separate prices between isekai/persistent. If you really need this now, please use two copies of the script and modify the @exclude statement to make it work.

2. Modified Arena and Ring of Blood pages will show aggregate data from both isekai and persistent. There is no easy fix for users to make the data show properly.

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

 
post Feb 15 2021, 16:46
Post #8
OnceForAll



Fluffy Tail Fox
*******
Group: Catgirl Camarilla
Posts: 1,575
Joined: 3-January 21
Level 500 (Ponyslayer)


CODE
//Secret code to access automatically updating prices. Only needs to trigger once per page load.
        if (!document.prices_updated) {
            let bs_prices = JSON.parse(localStorage.getItem("bs_prices"));
            if (bs_prices) {
                for (let item in prices) {
                    if (item in bs_prices) {
                        //console.log(item + ': replacing ' + prices[item] + ' with ' + bs_prices[item])
                        prices[item] = bs_prices[item]
                    } else {
                        console.log("Couldn't find " + item + ": " + prices[item])
                    }
                }
                console.log("prices automatically loaded");
                console.log(prices)
            }
            document.prices_updated = true
        }


Find this "secret code" inside your script. I am very interested in how you generate the "bs_prices" value.

Maybe I could ask Nezu to see if he would like to provide an API in his HVMarket and all users would have the exciting feature.

---------------------------

Update: Asked.

QUOTE(OnceForAll @ Feb 15 2021, 22:58) *

Thanks for your reply!

BTW, I find every utility HV script (HV Util, Battle Stat, HVToolBox) requires the user to manually configure material prices. Would you mind adding a RESTful API to HVMarket so that userscripts could update material prices automatically?


This post has been edited by OnceForAll: Feb 15 2021, 17:12
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post Feb 18 2021, 13:28
Post #9
aWeirdo



Lurker
Group: Recruits
Posts: 4
Joined: 9-February 21


Interesting!!
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post May 29 2021, 22:39
Post #10
OnceForAll



Fluffy Tail Fox
*******
Group: Catgirl Camarilla
Posts: 1,575
Joined: 3-January 21
Level 500 (Ponyslayer)


[Feature Request] Add the "formatter" key to table_column configuration.

E.g.

CODE
let table_columns = {
  'Details': [
    {column_name: 'Level', field: 'level'},
    {column_name: 'Persona', field: 'persona', tooltip: 'equipped'},
    {column_name: 'Prof', presence: 'proficiency', tooltip: 'proficiency'},
    {column_name: 'EXP', drops: 'EXP', formatter: (value) => value.toLocaleString()}
  ]
};


Alternative: Add a new format option, e.g.

CODE
let table_columns = {
  'Details': [
    {column_name: 'Level', field: 'level'},
    {column_name: 'Persona', field: 'persona', tooltip: 'equipped'},
    {column_name: 'Prof', presence: 'proficiency', tooltip: 'proficiency'},
    {column_name: 'EXP', drops: 'EXP', format: 'numberLocalString'}
  ]
};


Implementation:

CODE

} else if ('presence' in columns[j]) {
  cell_content = columns[j].presence in data ? "True" : "False"
} else if ('formatter' in columns[j] && typeof columns[j].formatter === 'function') {
  cell_content = columns[j].formatter(cell_content);
} else {
  console.log('Invalid Format',columns[j]);
}

if ('format' in columns[j]) {
  if (columns[j].format === 'time_string') {
    cell_content = getTimeString(cell_content)
  } else if (columns[j].format === 'local_number_string') {
    const number = Number(cell_content);
    if (!Number.isNaN(number)) {
      cell_content = number.toLocaleString();
    }
  }
}


This post has been edited by OnceForAll: May 29 2021, 22:44
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post May 29 2021, 23:15
Post #11
Firew



Casual Poster
****
Group: Gold Star Club
Posts: 258
Joined: 22-February 11
Level 500 (Ponyslayer)


Yes, thank you for the idea. I think I will implement both format and formatter and use it exclusively (getting rid of else if statement)

This is all psuedo-code as an outline, apologies if it doesn't work or if I made mistakes

CODE


const default_column: {
  formatter: x => x //Maybe add in "if x is a number, format to 2 decimals as a default
}

// Enum for ease of use for non-coders
const format_options = {
  PRESENCE: (x) -> x in data
  TWO_DIGITS:  (x) -> Math.round(x * 100) / 100
  etc.
}

//Example colums
let table_columns = {
  'Details': [
    {column_name: 'Level', field: 'level'},
    {column_name: 'Persona', field: 'persona', tooltip: 'equipped'},
    {column_name: 'Prof', field: 'proficiency', format: 'PRESENCE', tooltip: 'proficiency'},
    {column_name: 'EXP', drops: 'EXP', formatter: (value) => value.toLocaleString()}
  ]
};

//Preprocessing, by using default then merge in values
for (let j=0, j<columns.length; j++) {

  column_config = {
    ...default_column,
    ...columns[j]
  }
  
  let value
  
  //get raw value
  if ('field' in column_config) {
     value = data[column_config.field]
  } else if ('drops' in column_config) {
     value = data.drops[column_config.drops] || 0
  } else etc.

  //format value
  let formatter = column_config.formatter
  if ('format' in column_config) {
    //Look up formatter in format_options enumerable and use this instead
   formatter = <format from enum>
  }

  cell_content = <apply formatter>
  
}
//



I can then remove most of the hard-coded format code.

This post has been edited by Firew: May 29 2021, 23:17
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post Jun 8 2021, 02:36
Post #12
little_wuke



Newcomer
*
Group: Members
Posts: 39
Joined: 20-June 17
Level 375 (Godslayer)


Can't get it to work on mobile
Environment: Android 11, Kiwi Browser(which uses Chrome Tampermonkey), newest HVUtils and Monsterbation
Settings are as suggested and at the end of battle it says "added to battle stats" but when I go to check it it's always "querying". Is there any more information I need to provide to locate the problem?

Edit: I tried exporting data it looks like proper json, it just can't display as it should be.

This post has been edited by little_wuke: Jun 8 2021, 03:06
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post Nov 7 2022, 14:53
Post #13
a6080160801



Newcomer
*
Group: Members
Posts: 36
Joined: 4-September 22
Level 388 (Dovahkiin)


Is it possible to move the "average,total,max,min" data to the bottom or to make them become a hide/show switch?

Attached Image
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post Oct 28 2023, 06:38
Post #14
hujiko555



Newcomer
*
Group: Catgirl Camarilla
Posts: 19
Joined: 11-July 11
Level 500 (Ponyslayer)


Found a bug in the script, when grabbing the monster level after finishing a battle, if the user uses different persona configs, it doesn't grab the level becuase the class used for switching persona is the same as the one for parsing the level.

The remedy to this is you restrict the search to the 'pane_monster' element. at line ~261
change
CODE
let level_divs = document.getElementsByClassName('fc4');

to
CODE
let level_divs = document.getElementById('pane_monster').getElementsByClassName('fc4');


Attached Image
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post Nov 9 2023, 11:17
Post #15
Byza



Adequate
*****
Group: Gold Star Club
Posts: 641
Joined: 2-July 16
Level 499 (Dovahkiin)


idk if anyone cares, but since I did it for myself why not share it

updated the prices, except stamina and crystals to numbers similar to market/what I sell stuff at.

starts in line 120

CODE

    let prices = {
        Stamina: 8800, //This is used in cost calculations.

        Equipment: {PFUDOR: 508, //Equipment prices are estimates (only PFUDOR's value is founded on any statistical aggregation. the rest are guesses. Ignores mag+ cloth)
            IWBTH: 460,
            Nintendo: 400,
            Hell: 375,
            Nightmare: 350,
            Hard: 325,
            Normal: 300},

        //Special
        Crystal: 20500/12000,
        'Precursor Artifact': 6000,
        Figurine: 13000,
        'Amnesia Shard': 7000,
        'Aether Shard': 2500,
        'Featherweight Shard': 100,
        'Voidseeker Shard': 100,

        //Trophies
        'ManBearPig Tail': 1500,
        'Holy Hand Grenade of Antioch': 1500,
        "Mithra's Flower": 1500,
        'Dalek Voicebox': 1500,
        'Lock of Blue Hair': 1500,
        'Bunny-Girl Costume':  3200,
        'Hinamatsuri Doll': 3200,
        'Broken Glasses': 3200,
        'Black T-Shirt': 5500,
        Sapling: 5500,
        'Unicorn Horn': 10000,
        'Noodly Appendage': 60000,

        //Draughts/Potions/Elixirs
        'Health Draught': 1,
        'Health Potion': 30,
        'Health Elixir': 350,
        'Mana Draught': 4,
        'Mana Potion': 90,
        'Mana Elixir': 280,
        'Spirit Draught': 15,
        'Spirit Potion': 90,
        'Spirit Elixir': 900,

        'Bubble-Gum': 5000,
        'Flower Vase': 5000,

        //Infusions/Scrolls
        'Infusion of Flames': 0, // 140,
        'Infusion of Frost': 0, // 140,
        'Infusion of Lightning': 0, // 140,
        'Infusion of Storms': 0, // 265,
        'Infusion of Darkness': 0, // 160,
        'Infusion of Divinity': 0, // 3000,
        'Scroll of Life': 200,
        'Scroll of Absorption': 20,
        'Scroll of Shadows': 120,
        'Scroll of Swiftness': 100,
        'Scroll of Protection': 250,
        'Scroll of the Gods': 350,
        'Scroll of the Avatar': 700,

        //Food
        'Monster Chow': 0, //3,
        'Monster Edibles': 0, //5,
        'Monster Cuisine': 0, //6,
        'Happy Pills': 0, //550,

        //Materials
        'Scrap Metal': 89,
        'Scrap Leather': 89,
        'Scrap Cloth': 89,
        'Scrap Wood': 89,
        'Energy Cell': 180,

        'High-Grade Metals': 200,
        'High-Grade Leather': 80,
        'High-Grade Cloth': 5900,
        'High-Grade Wood': 1000,

        'Mid-Grade Metals': 40,
        'Mid-Grade Leather': 20,
        'Mid-Grade Cloth': 140,
        'Mid-Grade Wood': 50,

        'Low-Grade Metals': 10,
        'Low-Grade Leather': 10,
        'Low-Grade Cloth': 10,
        'Low-Grade Wood': 10,

        //Tokens
        Blood: 0,
        Chaos: 0,
        Soul: 0,
    };




This post has been edited by Byza: Nov 9 2023, 11:24
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post Mar 5 2024, 23:28
Post #16
l13763824039



Casual Poster
****
Group: Gold Star Club
Posts: 396
Joined: 6-July 21
Level 432 (Dovahkiin)


Error found and some fixes
000000000000000000000000000000000000000000000000000000000000000000000000000000
line 225
CODE

if (window.location.href.includes("/isekai/")) {
                    this.isekai = true
                }

this.isekai = null if window.location.href.includes("/isekai/") = false
Fix:
CODE

this.isekai =window.location.href.includes("/isekai/")

000000000000000000000000000000000000000000000000000000000000000000000000000000
line 234
CODE

this.persona = persona.plist[persona.pidx].name;

In line 233, we have
CODE

let persona = JSON.parse(this.isekai ? localStorage.hvuti_persona : localStorage.hvut_persona);

But persona has no attribute of plist anymore in current Monsterbation version
Fix:
CODE

this.persona = persona[persona.pidx].name;

000000000000000000000000000000000000000000000000000000000000000000000000000000
line 235
CODE

let equip_set = JSON.parse(this.iseka ? localStorage.hvuti_eq_set : localStorage.hvut_eq_set);

In current Monsterbation version, "eq_set" is changed to "equipset".
Fix:
CODE

let equip_set = JSON.parse(this.iseka ? localStorage.hvuti_equipset : localStorage.hvut_equipset);

000000000000000000000000000000000000000000000000000000000000000000000000000000
After changing these, it works fine.
User is online!Profile CardPM
Go to the top of the page
+Quote Post

 
post Apr 13 2024, 14:58
Post #17
ccnan23



Sensei nante Daikirai
***
Group: Gold Star Club
Posts: 242
Joined: 23-January 23
Level 483 (Dovahkiin)


Wrote a version compatible with both HVUT2 and HVUT3
(the changes are basically the same as those written by l13763824039)
Attached File  Battle_Stats.js.txt ( 73.1k ) Number of downloads: 30
User is offlineProfile CardPM
Go to the top of the page
+Quote Post

 
post Apr 18 2024, 06:27
Post #18
l13763824039



Casual Poster
****
Group: Gold Star Club
Posts: 396
Joined: 6-July 21
Level 432 (Dovahkiin)


I'm using modified Battle_stat.js
So, the line number will not be correct comparing to the original

Fixed Level display. (Guess this only helps on ISK for old birds)
Around line 302
CODE

this.level = parseInt(level_divs[level_divs.length - 1].innerText);

Fixed:
CODE

this.level = parseInt(level_divs[level_divs.length - 2].innerText);

-------------------------------------
Strongly recommend

"Timestamp" without hours and minutes.
This does not affect "Time". I believe that somebody wants a more precise SPEED RUN time.
Original code line 1128:
CODE

stats[i].timestamp = stats[i].timestamp.substring(0, 19);

Shorter Timestamp:
CODE

stats[i].timestamp = stats[i].timestamp.substring(0, 10);


Weekday with the "Day of the Week"
Around line 70, change the default day to these
CODE

const default_days = ['Monday-Dark','Tuesday-Fire','Wednesday-Cold','Thursday-Wind','Friday','Saturday-Elec','Sunday-Holy'];
User is online!Profile CardPM
Go to the top of the page
+Quote Post


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

 


Lo-Fi Version Time is now: 12th May 2024 - 23:59