 |
 |
 |
[Script] Hentaiverse Battle Stats, A modern replacement for old statistic tracking tools (v 1.1.3) |
|
Nov 26 2020, 09:39
|
Firew
Group: Gold Star Club
Posts: 258
Joined: 22-February 11

|
Hentaiverse Battle StatsVer. 1.1.3 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 TampermonkeyDownload:
Battle_Stats.js.txt ( 73.02k )
Number of downloads: 11198 Features:- Saves everything about your battles using monsterbation and hvutils data.
- Runs only at the end of every battle, so no performance impact.
- Ultra-fast Querying using the browser's built-in IndexedDB database.
- Advanced Table view with filters, highlights, tooltips, averages, totals, and min/max statistics.
- Highly customizable column system allows you to see what you want to see.
- DRILL DOWN and view each battle or DRILL UP and view totals per day.
- Accessible in a drop-down integrated with the other menus OR on a separate page (loads even in battle).
- Export your data to JSON files to save or share.
 Installation Instructions (also included in the script):- Install this script, Monsterbation, and HVUtils
- In Monsterbation settings, set trackDrops, trackProficiency, trackSpeed, trackDamage, trackUsage to on
- 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
|
|
|
|
 |
|
Nov 26 2020, 09:39
|
Firew
Group: Gold Star Club
Posts: 258
Joined: 22-February 11

|
reserved
|
|
|
Nov 26 2020, 09:39
|
Firew
Group: Gold Star Club
Posts: 258
Joined: 22-February 11

|
reserved
|
|
|
|
 |
|
Jan 8 2021, 11:44
|
what_is_name
Group: Gold Star Club
Posts: 1,024
Joined: 5-May 19

|
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
|
|
|
|
 |
|
Jan 26 2021, 07:07
|
Firew
Group: Gold Star Club
Posts: 258
Joined: 22-February 11

|
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.
|
|
|
|
 |
|
Jan 26 2021, 07:41
|
what_is_name
Group: Gold Star Club
Posts: 1,024
Joined: 5-May 19

|
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
|
|
|
|
 |
|
Feb 10 2021, 04:45
|
Firew
Group: Gold Star Club
Posts: 258
Joined: 22-February 11

|
Updated to 1.1.3
Battle_Stats.js.txt ( 73.02k )
Number of downloads: 2022 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.  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.
|
|
|
|
 |
|
Feb 15 2021, 16:46
|
OnceForAll
Group: Catgirl Camarilla
Posts: 1,629
Joined: 3-January 21

|
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
|
|
|
|
 |
|
Feb 18 2021, 13:28
|
aWeirdo
Lurker
Group: Recruits
Posts: 4
Joined: 9-February 21

|
Interesting!!
|
|
|
|
 |
|
May 29 2021, 22:39
|
OnceForAll
Group: Catgirl Camarilla
Posts: 1,629
Joined: 3-January 21

|
[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
|
|
|
|
 |
|
May 29 2021, 23:15
|
Firew
Group: Gold Star Club
Posts: 258
Joined: 22-February 11

|
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
|
|
|
|
 |
|
Jun 8 2021, 02:36
|
little_wuke
Newcomer
 Group: Members
Posts: 39
Joined: 20-June 17

|
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
|
|
|
Nov 7 2022, 14:53
|
a6080160801
Newcomer
 Group: Members
Posts: 36
Joined: 4-September 22

|
Is it possible to move the "average,total,max,min" data to the bottom or to make them become a hide/show switch? 
|
|
|
Oct 28 2023, 06:38
|
hujiko555
Group: Catgirl Camarilla
Posts: 134
Joined: 11-July 11

|
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'); 
|
|
|
|
 |
|
Nov 9 2023, 11:17
|
Byza
Group: Gold Star Club
Posts: 758
Joined: 2-July 16

|
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
|
|
|
|
 |
|
Mar 5 2024, 23:28
|
l13763824039
Group: Gold Star Club
Posts: 1,216
Joined: 6-July 21

|
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.isekai ? 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.isekai ? localStorage.hvuti_equipset : localStorage.hvut_equipset);
000000000000000000000000000000000000000000000000000000000000000000000000000000 After changing these, it works fine. This post has been edited by l13763824039: May 28 2024, 03:20
|
|
|
|
 |
|
Apr 13 2024, 14:58
|
ccnan23
Group: Gold Star Club
Posts: 267
Joined: 23-January 23

|
Wrote a version compatible with both HVUT2 and HVUT3 (the changes are basically the same as those written by l13763824039)
Battle_Stats.js.txt ( 73.1k )
Number of downloads: 370
|
|
|
|
 |
|
Apr 18 2024, 06:27
|
l13763824039
Group: Gold Star Club
Posts: 1,216
Joined: 6-July 21

|
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'];
Edit in 5/2024: One month later I realized I had a typo. I wrote "iseka" instead of "isekai" in the previous post..... (already corrected the typo currently, the equipment link are associated with the web address if your address start with "https://hentaiverse.org/", you can't click isekai gear with the correct response. Vice versa here is my change from code CODE equip_link.href = 'equip/' + holder[i];
change to CODE equip_link.href = (holder[i].length > 18 ? 'equip/' : 'isekai/equip/') + holder[i];
This is ID length based This post has been edited by l13763824039: May 28 2024, 03:34
|
|
|
|
 |
|
Oct 12 2024, 12:08
|
qqnumd
Group: Members
Posts: 460
Joined: 26-January 12

|
To be compatible with the stop timer at idle time feature wrote by what_is_name (really a great feature, it not only makes the results more reliable but also helps me feel less nervous about the timer when I’m playing) Around line 246 CODE this.seconds = Math.round((Date.now() - bs_timeLog.startTime) / 10) / 100; //precise to the 100's place. change to: CODE this.seconds = Math.round((Date.now() - bs_timeLog.startTime - (bs_timeLog.pauseTime || 0)) / 10) / 100; //precise to the 100's place.
|
|
|
Jan 5 2025, 01:16
|
l13763824039
Group: Gold Star Club
Posts: 1,216
Joined: 6-July 21

|
Hentaiverse_Battle_Stats.txt ( 76.19k )
Number of downloads: 78 My version of battle stats not compatible with the stop timer at idle time feature Why? Cause I'm lazy and somebody is asking for it now
|
|
|
1 User(s) are reading this topic (1 Guests and 0 Anonymous Users)
0 Members:
|
 |
 |
 |
|