// ==UserScript==
// @name Hentaiverse Monsterbation
// @namespace hvmonsterbate
// @version 1.4.1.1
// @description M-M-M-MONSTERBATE!!
// @match *://*.hentaiverse.org/*
// @exclude *hentaiverse.org/equip/*
// @grant none
// ==/UserScript==
// vvv SETTINGS vvv //
const settings = {
cfgInterface: true, // add link under character to configure settings
profileAutoswitch: true, // automatically switch profile when changing persona or equipment set
isekaiInherit: true, // use persistent persona/equipment profiles in isekai
// ui settings
cfgButton: true, // show button to access settings and switch profiles during battle
mpboost: 100, spboost: 100, // set to match player stats. add up all bonuses from abilities and capacitor
mppot: 75, sppot: 75, // set to percentages restored by mana/spirit potions
showCooldowns: true, // show cooldowns on the quickbar
effectsAboveMonsters: false, // move player effects to above monsters
vitalsAboveMonsters: false, // move vitals and spirit button to above monsters
quickbarBesideMonsters: false, // move quickbar to the right of monsters
riddleRight: false, // shrink riddlemaster to the right
condenseLeft: false, // activate the above four options with everything moved to the left
compactQuickbar: false, // eliminate whitespace on quickbar and monster bars
expireNoblink: false, // disable blinking of expiring effects
showDurations: true, // show effect durations
stackBorder: true, // show effect stacks as border thickness rather than numbers
alertColours: true, // change background colours according to alert conditions
alertBackground: false, // whole background instead of relevant area for alert colours
alertBuffs: '/(healthpot.png|manapot.png|scroll.png|infusion.png|regen.png|heartseeker.png|arcanemeditation.png)/',
// change colour of player effects area if any of these buffs has less than 2 turns left
// add the icon filename of any critical buff. this also affects stopOnBuffsExpiring
// to get the filename, activate the buff in battle, right click its icon and inspect element
// some examples: spiritpot.png darkinfusion.png protection_scroll.png flowers.png gum.png
// spiritshield.png sparklife.png shadowveil.png haste.png protection.png
colours: { default: '#EDEBDF', // alert colours
spark: 'magenta', // set to any valid html colour, or false to disable
lowhp: 'deeppink',
lowmp: 'darkslateblue',
lowsp: 'indigo',
ocfull: 'mediumspringgreen',
expiring: 'lightblue',
channelling: 'aquamarine',
usable: 'mediumspringgreen',
miss: 'gray', // log colours
damage: 'red',
item: '#00B000',
attack: 'blue',
spell: 'darkslateblue',
recovery: 'mediumseagreen',
effect: 'seagreen',
spirit: 'indigo',
proficiency: 'darkolivegreen',
monster: 'springgreen', // monsters that match your keywords
stun: 'darkseagreen', // stunned monsters, set to false to disable
imperil: 'lightsteelblue', // imperilled monsters
stunimperil: 'cadetblue' }, // stunned and imperilled monsters
usableBlink: true, // mana and spirit gems and potions on the quickbar blink when usable to their full effect
logColours: false, // add colour highlights to the battle log
turnDividers: false, // add horizontal row between turns
logPasteover: false, // add last turn of previous round to new round log. requires ajaxRound
hideLog: false, // hide the battle log
maxVitals: false, // show maximum player vitals
showMonsterHP: false, // display current and max hp of monsters
shortenHPbars: false, // shorten monster hp bars relative to their max hp
monsterNumbers: false, // show monster numbers instead of letters
monsterInfo: true, // show monster data from decondelite's database
monsterKeywords: false, // highlight monsters where the name, id or max hp match this expression, set to false to disable
// example: '/(Meiling|MID=70699|HP=243060)/'
ajaxRound: true, // advance to next round using ajax. set to false if you use other scripts that do not support this
ajaxIntervals: 100, // set to 0 or a higher number if you experience weird flashing of expiring effects
noPopup: true, // skip end of round popup
stopAtBattleEnd: true, // do not dismiss popup at end of battle
stopOnEquipDrop: false, // do not dismiss popup if equipment drops, quality specified by cutoff below
clickableRiddlemaster: true, // add links to the riddlemaster to directly submit an answer
edConfirm: false, // ask for confirmation before using energy drink
fleeConfirm: false, // ask for confirmation before fleeing
raiseGem: false, // raise gem icon above quickbar
hoverGem: false, // activate gem by hovering over the icon
hoverSpirit: false, // activate spirit stance by hovering over the icon
quickbarExtend: [ 1,'ikey_1','ikey_2','ikey_3','ikey_4','ikey_7','ikey_8','ikey_9','ikey_10',
'ikey_s1','ikey_s2','ikey_s4','ikey_n1','ikey_n5','ikey_n6','ikey_6','ikey_5' ],
// ID for skills/spells/items (in quotes), 0 for space, 1 for gem
// set to [1] if you just want the gem icon or [] to disable
// IDs:
// 1001 Flee 1011 Scan 1101 FUS RO DAH 1111 Orbital Friendship Cannon
// 2201 Shield Bash 2202 Vital Strike 2203 Merciful Blow
// 2301 Great Cleave 2302 Rending Blow 2303 Shatter Strike
// 2401 Iris Strike 2402 Backstab 2403 Frenzied Blows
// 2101 Skyward Sword 2501 Concussive Strike
// 111 Fiery Blast 112 Inferno 113 Flames of Loki
// 121 Freeze 122 Blizzard 123 Fimbulvetr
// 131 Shockblast 132 Chained Lightning 133 Wrath of Thor
// 141 Gale 142 Downburst 143 Storms of Njord
// 151 Smite 152 Banishment 153 Paradise Lost
// 161 Corruption 162 Disintegrate 163 Ragnarok
// 211 Drain 212 Weaken 213 Imperil
// 221 Slow 222 Sleep 223 Confuse
// 231 Blind 232 Silence 233 MagNet
// 311 Cure 312 Regen 313 Full-Cure
// 411 Protection 412 Haste 413 Shadow Veil
// 421 Absorb 422 Spark of Life 423 Spirit Shield
// 431 Heartseeker 432 Arcane Focus
// ikey_1-ikey_15 items ikey_s1-ikey_s6 scrolls ikey_n1-ikey_n6 infusions
// mouse binding and hover settings
// it is best to use mouse bindings in conjunction with hoverArea, as mouse actions always target the whole monster
clickEverywhere: false, // by default, click actions are only performed when the cursor is over a live monster
// setting this to true will enable middle and right click bindings and disable the context menu everywhere
wheelEverywhere: false, // same as above, but for the wheel
mouseEngage: false, // hold mouse buttons to modify hover behaviour, rather than performing the bound action only once
clickLeft: false, // unused. set to "Nothing" to attack with mouseEngage
clickMiddle: "Cast('Scan')",
clickRight: "Strongest([Cast('FUS RO DAH'), Cast('Orbital Friendship Cannon'), Cast('Ragnarok'), Cast('Disintegrate'), Cast('Corruption')])",
wheelUp: "Impulse(Cast('Imperil'))",
wheelDown: "Impulse(Cast('Weaken'))",
wheelLeft: "Impulse(Strongest([Cast('Silence'), Cast('Sleep')]))",
wheelRight: "Impulse(Strongest([Cast('Vital Strike'), Cast('Frenzied Blows'), Cast('MagNet')]))",
hoverAction: "Nothing", // Attack
hoverShiftAction: "Strongest([Cast('Ragnarok'), Cast('Disintegrate'), Cast('Corruption')])", // alternate hover action when holding shift
hoverCtrlAction: "Strongest([Cast('Paradise Lost'), Cast('Banishment'), Cast('Smite')])", // alternate hover action when holding ctrl
hoverAltAction: "Strongest([Cast('Flames of Loki'), Cast('Inferno'), Cast('Fiery Blast')])", // alternate hover action when holding alt
// these can be set to any bindable action that can be followed up with targeting a monster,
// as explained in the keybind section, or to false to disable
// examples:
// hoverAction: false, // disable hover
// hoverAction: "Nothing", // attack
// hoverAction: "Strongest([Cast('Ragnarok'), Cast('Disintegrate'), Cast('Corruption')])", // dark spell rotation
// hoverShiftAction: "Strongest([ToggleHover, Cast('Imperil')])", // single cast of imperil
// with the above example, you can hold shift, hover and hit Z to cast imperil while being protected by the usual hover safeguards
hoverArea: 6, // part of the monster that activates hover
// 1: whole box, 2: icon, 3: name, 4: vitals, 6: status effects
// hoverplay interrupt settings
startRoundWithHover: true, // have hoverplay active at the beginning of each round
// or require a kepress to start, in case you want to imperil first
hoverAutoresume: false, // reactivate hover after releasing any key
minHP: 0.3,
minMP: 0.1,
minSP: 'auto', // formula when set to 'auto': 0.5-0.5*spboost/(spboost+100)
stopOnEmergency: true, // sparked or low vitals
stopOnBuffsExpiring: true, // critical buff expiring in 1 turn or less
// mobile settings
clearRound: false, // clear target and reset hoverAction at round transition, to avoid lingering taps and make monsterBar safer
spacedBar: false, // increase spacing of quickbar and monster bar
monsterBar: [], // add skill/spell icons next to monsters, for single use or tap to engage/tap elsewhere to disengage, single skills and spell rotations
// example: first parameter is false for single use or true to engage, followed by skill/spell IDs or leave empty for attack
// monsterBar: [ [true], // engage attack
// [false,'213'], // single cast of imperil
// [false,'212'], // single cast of weaken
// [true,'163','162','161'] ], // engage dark spell rotation
// tracking settings
trackDrops: true, // show total numbers of drops and exp at end of battle
detailedDroplog: true, // list each drop type individually, excluding crystals and equipment below your quality cutoff
detailedCrystlog: false, // list each crystal type individually
equipmentCutoff: 3, // 0 to track all equipment combined,
// 1 to track Peerless separateley,
// 2 to track Peerless and Legendary separateley, etc.
selectLog: false, // limit end-of-battle onclick to icon, allowing for easier selecting of log
terseLog: false, // format log for easier pasting into spreadsheets
trackProficiency: false, // show total proficiency gains at end of battle
proficiencySidebar: false, // show live proficiency gains during battle
profbarInMainpane: false, // set to false to avoid overlap with showMonsterHP
deleteDropLog: 2, // delete drop log, 0: never, 1: when navigating away from battle section, 2: at end of battle
dropFontSize: 100, // adjust font size of drop and proficiency log
trackSpeed: true, // show turn count and speed statistic at end of battle
speedFontSize: 100, // adjust font size of speed statistic
trackDamage: true, // show damage dealt and taken at end of battle
damageFontSize: 100, // adjust font size of damage log
trackUsage: true, // show attack/skill/spell/item usage at end of battle
deleteCombatLog: 2, // delete damage and usage logs, 0: never, 1: when navigating away from battle section, 2: at end of battle
consoleLog: false, // output raw machine-readable log data to console when showing the drop log
showRound: true, // show the current round number during battle
bigRoundCounter: false, // bigger round counter, placed in top right
// key bindings
bind: "\
Bind(KEY_SPACE, Any, Strongest([Cast('Cure'), HoverAction(Cast('Cure'), true)]));\
Bind(KEY_Z, Any, ToggleHover);\
Bind(KEY_S, Any, Impulse(Toggle('Spirit')));\
Bind(KEY_A, Strongest([Use(4), Cast('Full-Cure'), Cast('Cure')]));\
Bind(KEY_A, Shift, Strongest([Use(7), Use(4), Cast('Full-Cure'), Cast('Cure')]));\
Bind(KEY_A, Ctrl, Strongest([Use(7), Use(4), Cast('Full-Cure'), Cast('Cure')]));\
Bind(KEY_A, Alt, Strongest([Use(7), Use(4), Cast('Full-Cure'), Cast('Cure')]));\
Bind(KEY_X, Strongest([Use('s1'), Use('s4'), Use('s2'), Use(2), Use(1)]));\
Bind(KEY_X, Shift, Strongest([Use('s1'), Use('s4'), Use('s2'), Use('n6'), Use(2), Use(1)]));\
Bind(KEY_X, Ctrl, Strongest([Use('s1'), Use('s4'), Use('s2'), Use('n5'), Use(2), Use(1)]));\
Bind(KEY_X, Alt, Strongest([Use('s1'), Use('s4'), Use('s2'), Use('n1'), Use(2), Use(1)]));\
Bind(KEY_C, Any, Cast('Regen'));\
Bind(KEY_V, Any, Cast(damage));\
Bind(KEY_Q, Impulse(Use(5)));\
Bind(KEY_Q, Shift, Impulse(Strongest([Use(8), Use(5)])));\
Bind(KEY_Q, Ctrl, Impulse(Strongest([Use(8), Use(5)])));\
Bind(KEY_Q, Alt, Impulse(Strongest([Use(8), Use(5)])));\
Bind(KEY_W, Any, Impulse(Use(3)));\
Bind(KEY_E, Impulse(Use(6)));\
Bind(KEY_E, Shift, Impulse(Strongest([Use(9), Use(6)])));\
Bind(KEY_E, Ctrl, Impulse(Strongest([Use(9), Use(6)])));\
Bind(KEY_E, Alt, Impulse(Strongest([Use(9), Use(6)])));\
Bind(KEY_P, Settings);\
Bind(KEY_1, Any, Strongest([TargetMonster(1), Cast('Imperil')]));\
Bind(KEY_2, Any, Strongest([TargetMonster(4), Cast('Imperil')]));\
Bind(KEY_3, Any, Strongest([TargetMonster(7), Cast('Imperil')]));\
",
// Add this for as many bindings as you want:
// Bind(KeyCode, Modifier, Action);\
// KeyCode = From http://www.javascripter.net/faq/keycodes.htm or any of the following:
// KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, KEY_M,
// KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z,
// KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0,
// KEY_SPACE, KEY_ENTER, KEY_PAGEUP, KEY_PAGEDOWN, KEY_END, KEY_HOME, KEY_LEFT, KEY_UP, KEY_RIGHT, KEY_DOWN,
// KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12,
// KEY_COMMA, KEY_PERIOD, KEY_SLASH, KEY_FORWARDSLASH, KEY_GRAVE, KEY_TILDE, KEY_LBRACKET, KEY_BACKSLASH,
// KEY_SEMI, KEY_RBRACKET, KEY_APOSTROPHE, KEY_SHIFT, KEY_CTRL, KEY_ALT
// Modifier = This is OPTIONAL. Valid mods are NoMod, Shift, Ctrl, Alt, CtrlShift, AltShift, CtrlAlt, CtrlAltShift, Any
// Action = Valid actions:
// Cast('Spell Name')
// Spell Name.
// Use('Item ID')
// Valid Item IDs are 'p' for Gem, 1-15 for Items, 's1'-'s6' for Scrolls and 'n1'-'n6' for Infusions.
// Toggle('Type')
// Attack, Focus, Defend or Spirit.
// Nothing
// Use this to unbind a default key or use the default attack when targeting a monster.
// TargetMonster(Number)
// Targets the specified monster, starting at 0 for A up to 9 for J.
// NextRound
// Enters next round. Using this overrides both Space and Enter for next round. If you still want to use one of those, add it manually.
// Strongest([Action Array])
// Picks the most desired action.
// For targeted spells or skills, put the most desired action first.
// For untargeted spells or items, put the most desired action last.
// HoverAction(Action, true/false)
// Point mouse at target monster, hit key to perform action, Nothing for default attack. Set second parameter to true to respect alerts.
// Impulse(Action)
// Perform an action once.
// ToggleHover
// Turn hoverplay on or off.
// Drops
// Show drop log.
// CursorUp, CursorDown
// Move the targeting cursor.
// CursorTarget
// Target selected monster. Use with Strongest to specify action.
// CursorHover
// Engage hover at cursor location.
// ClearTarget
// Unset hover target.
// Settings.
// Access configuration interface.
//
// Examples:
// Bind(KEY_M, Shift, Use(1));\ -- Shift + M = Use Item 1
// Bind(KEY_LBRACKET, Cast('WRATH OF THOR'));\ -- Case insensitive. Key [ = cast Wrath of Thor.
// Bind(KEY_A, Nothing);\ -- You can unbind a default key.
// Bind(KEY_I, Use('p'));\ -- I uses Powerup Gem.
// Bind(KEY_F, Toggle('Focus'));\ -- Toggle focus.
// Bind(KEY_S, Toggle('Spirit'));\ -- Toggle spirit stance.
// Bind(KEY_T, Strongest([Cast('Ragnarok'), Cast('Disintegrate'), Cast('Corruption')]));\ -- Strongest Dark spell.
// Bind(KEY_B, Strongest([Cast('Full-Cure'), Cast('Cure')]));\ -- Use available Cure spell.
// Bind(KEY_N, Strongest([Use(3), Use(2), Use(1)]));\ -- Use available item.
// Bind(KEY_A, HoverAction(Nothing));\ -- Attack selected monster by holding A, to be used with hoverAction = false.
// Bind(KEY_I, HoverAction(Cast('Imperil')));\ -- Cast Imperil on selected monster, ignore alerts.
// Bind(KEY_I, HoverAction(Strongest([ToggleHover, Cast('Imperil')]), true));\ -- Single cast of Imperil, respect alerts.
// Bind(KEY_I, Impulse(Cast('Imperil'))); -- Inject Imperil into hover rotation.
// Bind(KEY_1, Strongest([TargetMonster(0), Cast('Imperil')]));\ -- Cast Imperil on monster A.
// Bind(KEY_Z, Any, ToggleHover);\ -- Toggle hoverplay, regardless of modifier keys.
// Bind(KEY_F, Drops);\ -- Show drops.
// Bind(KEY_UP, CursorUp); -- Move cursor up.
// Bind(KEY_DOWN, Strongest([CursorDown, ClearTarget]));\ -- Move cursor down, stop hover.
// Bind(KEY_LEFT, Strongest([CursorTarget, Cast('Imperil')]));\ -- Cast Imperil on selected monster.
// Bind(KEY_RIGHT, CursorHover);\ -- Hover on selected monster, recommended use with clearRound = true.
// custom profiles
// to override defaults, add elements to 'settings' sections
name: '[persistent]',
persona: [ { name: 'persona 1', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
{ name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
{ name: 'persona 2', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
{ name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
{ name: 'persona 3', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
{ name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
{ name: 'persona 4', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
{ name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
{ name: 'persona 5', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
{ name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
{ name: 'persona 6', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
{ name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
{ name: 'persona 7', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
{ name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
{ name: 'persona 8', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
{ name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
{ name: 'persona 9', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
{ name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] } ],
isekai: { name: '[isekai]', settings: {},
persona: [ { name: 'persona 1', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
{ name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
{ name: 'persona 2', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
{ name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
{ name: 'persona 3', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
{ name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
{ name: 'persona 4', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
{ name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
{ name: 'persona 5', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
{ name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
{ name: 'persona 6', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
{ name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
{ name: 'persona 7', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
{ name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
{ name: 'persona 8', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
{ name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
{ name: 'persona 9', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
{ name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] } ] }
};
// ^^^ SETTINGS ^^^ //
// bindable functions
function Toggle(name) {
return function() {
var state;
if ( (state = document.getElementById('ckey_' + name.toLowerCase())) ) {
dummy.setAttribute('onclick', state.getAttribute('onmouseover'));
dummy.click();
state.click(); }};}
function Cast(name) {
return function() {
var spell;
if ( document.getElementsByClassName('btii')[0].innerHTML != name &&
(spell = document.querySelector('.bts > div[onclick][onmouseover*="\'' + name + '\'"]')) ) {
dummy.setAttribute('onclick', spell.getAttribute('onmouseover'));
dummy.click();
spell.click(); }};}
function Use(id) {
return function() {
var item;
if ( (item = document.getElementById('ikey_' + id)) ) {
dummy.setAttribute('onclick', item.getAttribute('onmouseover'));
dummy.click();
item.click(); }};}
function Nothing() {}
function NextRound() { var btcp; if ( (btcp = document.getElementById('btcp')) ) btcp.click(); document.querySelector('img[src$="finishbattle.png"]').click(); }
function TargetMonster(num) { return function() { if ( monsters[num] && monsters[num].hasAttribute('onclick') ) monsters[num].click(); };}
function Strongest(actions) { return function() { var n = actions.length; while ( n-- > 0 ) actions[n](); };}
function HoverAction(action, alert) {
return function() {
override = action;
if ( (cfg.hoverAction || override) && !interruptHover && (!alert || !interruptAlert) && monsters[target] && monsters[target].hasAttribute('onclick') ) {
Hover(); }};}
function Impulse(action) {
return function() {
if ( done ) return;
impulse = action;
if ( interruptHover || interruptAlert || !monsters[target] || !monsters[target].hasAttribute('onclick') ) {
action(); done = true; impulse = false; }};}
function ToggleHover() {
interruptHover = !interruptHover;
if ( (cfg.hoverAction || override) && !interruptHover && !interruptAlert && monsters[target] && monsters[target].hasAttribute('onclick') ) {
Hover(); }}
function Drops() { ShowDrops(false); }
function CursorUp() { if ( --cursor < 0 ) cursor = 0; Cursor(); }
function CursorDown() { if ( ++cursor >= monsters.length ) cursor = monsters.length - 1; Cursor(); }
function CursorTarget() { TargetMonster(cursor)(); }
function CursorHover() { if ( cursor >= 0 ) SetTarget(cursor)(); }
function ClearTarget() { target = false; }
function Settings() {
var mainpane, style, form, div, changed = false, p = 0, s = 0, isk = '', select, option, index = 0;
if ( !(mainpane = document.getElementById('mainpane')) ) return;
bindings = [];
mainpane.innerHTML = '';
if ( !document.getElementById('hvcfgstyle') ) {
style = document.head.appendChild(document.createElement('style'));
style.id = 'hvcfgstyle';
style.innerHTML =
'.mbar, #cfgbutton { display: none !important; } #mainpane { height: ' + (document.getElementById('navbar') ? '644' : '671') +
'px; overflow: auto; } #mbcfg div { display: flex; margin: 2px; } #mbcfg input { margin: 0 2px 0 0; } #mbcfg input[type="text"] { width: 30px; }' +
'#mbcfgbt { display: flex; position: absolute; bottom: 0; left: 0; height: 27px; width: inherit; } #mbcfgbt select { margin: 0; }' +
'#mbcfgbt div { margin: 4px 0; } #mbcfgbt input[type="checkbox"] { margin-left: 10px; } .help { cursor: pointer; }' +
'.help .helptext { visibility: hidden; text-align: left; position: absolute; z-index: 2; bottom: 0; right: 0; background-color: #EDEBDF;' +
'padding: 4px; border: 1px solid #5C0D11; } .help:hover .helptext { visibility: visible; }'; }
form = mainpane.appendChild(document.createElement('form'));
form.id = 'mbcfg';
const Change = function(i, e) {
return function() {
changed = true;
var prf = s ? (isk ? cfg.isekai : cfg).persona[p-1].set[s-1].settings : (p ? (isk ? cfg.isekai : cfg).persona[p-1].settings : (isk ? cfg.isekai.settings : cfg)),
setting = settingsData[i][0], input = form.querySelector('[name="' + setting + (e ? '-' + e : '') + '"]'), value, inputs, j, above = Above(setting);
switch ( settingsData[i][1][0] ) {
case 'b': prf[setting] = input.checked; break;
case 'o': if ( !prf[setting] ) {
prf[setting] = JSON.parse(JSON.stringify(above)); }
prf[setting][e] = (value = input.value) == '' ? above[e] : (value == 'false' ? false : value); break;
case 'a': prf[setting] = (value = input.value) == '' ? above : JSON.parse(value); break;
case 'i': prf[setting] = (value = parseInt(input.value)) || value === 0 ? value : above; break;
case 'f': prf[setting] = parseFloat(value = input.value) || parseFloat(value) === 0 ? parseFloat(value) :
settingsData[i][1][1] == 's' && value != '' ? 'auto' : above; break;
case 's': if ( setting.indexOf('Action') > -1 && regexp.itemuse.test(input.value) ) {
alert('Fearsome powers thrust Laputa into orbit. Their dreaded empire once ruled the earth!'); return; }
case 't': if ( regexp.hoveruse.test(input.value) ) {
alert('Fearsome powers thrust Laputa into orbit. Their dreaded empire once ruled the earth!'); return; }
prf[setting] = (value = input.value.replace(regexp.whitespace,'')) == '' ? above : value; break; }
if ( (isk || p) && JSON.stringify(above) === JSON.stringify(prf[setting]) ) {
if ( e ) {
form.querySelector('#' + setting).parentNode.style.opacity = '0.5';
inputs = form.querySelectorAll('[name*="' + setting + '-"]');
for ( j = 0; j < inputs.length; j++ ) {
inputs[j].parentNode.style.opacity = '0.5'; }}
else {
input.parentNode.style.opacity = '0.5'; }
delete prf[setting]; }
else {
if ( e ) {
form.querySelector('#' + setting).parentNode.style.opacity = '1';
inputs = form.querySelectorAll('[name*="' + setting + '-"]');
for ( j = 0; j < inputs.length; j++ ) {
inputs[j].parentNode.style.opacity = '1'; }}
else {
input.parentNode.style.opacity = '1'; }}};},
Load = function(d) {
LoadCfg();
form.innerHTML = '';
var input, value;
if ( d ) {
input = form.appendChild(document.createElement('div')).appendChild(document.createElement('textarea'));
input.name = 'dump';
input.style.width = '1205px';
input.style.height = '631px';
input.style.resize = 'none';
input.value = JSON.stringify(cfg);
input.onchange = function() {
changed = true;
var dump = JSON.parse(input.value);
for ( var setting in settings ) {
cfg[setting] = (value = dump[setting]) || value === false || value === 0 ? value : settings[setting]; }
var option = select.querySelector('[value="00"]');
option.innerHTML = cfg.name;
for ( var i = 0; i < cfg.persona.length; i++ ) {
option = select.querySelector('[value="' + (i+1) + '0"]');
option.innerHTML = '- ' + cfg.persona[i].name;
for ( var j = 0; j < cfg.persona[i].set.length; j++ ) {
option = select.querySelector('[value="' + (i+1) + (j+1) + '"]');
option.innerHTML = '-- ' + cfg.persona[i].set[j].name; }}};
return; }
for ( var i = 0; i < settingsData.length; i++ ) {
value = (s ? (isk ? cfg.isekai : cfg).persona[p-1].set[s-1].settings :
(p ? (isk ? cfg.isekai : cfg).persona[p-1].settings :
(isk ? cfg.isekai.settings : cfg)))[settingsData[i][0]];
var none = !(value || value === false || value === 0), above = Above(settingsData[i][0]);
if ( none ) {
value = above; }
var grey = (isk || p) && (none || JSON.stringify(value) === JSON.stringify(above)),
div = form.appendChild(document.createElement('div'));
div.style.opacity = grey ? '0.5' : '1';
switch ( settingsData[i][1][0] ) {
case 'h': div.appendChild(document.createElement('div')).innerHTML = settingsData[i][0];
div.style.opacity = '1'; break;
case 'b': input = div.appendChild(document.createElement('input'));
input.name = settingsData[i][0];
input.type = 'checkbox';
input.checked = value;
input.onchange = Change(i);
div.appendChild(document.createElement('div')).innerHTML = settingsData[i][2]; break;
case 'o': input = div.appendChild(document.createElement('div'));
input.id = settingsData[i][0];
input.innerHTML = settingsData[i][2];
for ( var element in value ) {
var dv = form.appendChild(document.createElement('div'));
dv.style.opacity = grey ? '0.5' : '1';
input = dv.appendChild(document.createElement('input'));
input.name = settingsData[i][0] + '-' + element;
input.type = 'text';
input.value = value[element];
if ( settingsData[i][4] ) {
input.style.width = settingsData[i][4] + 'px'; }
input.onchange = Change(i,element);
dv.appendChild(document.createElement('div')).innerHTML = element; } break;
case 'a': input = div.appendChild(document.createElement('input'));
input.name = settingsData[i][0];
input.type = 'text';
input.value = JSON.stringify(value);
input.onchange = Change(i);
div.appendChild(document.createElement('div')).innerHTML = settingsData[i][2]; break;
case 't': input = div.appendChild(document.createElement('textarea'));
input.name = settingsData[i][0];
input.rows = 30;
input.style.resize = 'none';
input.value = value.replace(regexp.break,';\n');
input.onchange = Change(i); break;
default: input = div.appendChild(document.createElement('input'));
input.name = settingsData[i][0];
input.type = 'text';
input.value = value;
input.onchange = Change(i);
div.appendChild(document.createElement('div')).innerHTML = settingsData[i][2]; break; }
if ( settingsData[i][4] ) {
input.style.width = settingsData[i][4] + 'px'; }
if ( p == 0 && settingsData[i][3] ) {
var help = div.appendChild(document.createElement('div'));
help.className = 'help';
help.innerHTML = '?';
var helptext = help.appendChild(document.createElement('span'));
helptext.className = 'helptext';
helptext.innerHTML = settingsData[i][3]; }}},
Above = function(setting) {
var value;
if ( !isk ) {
return s && ((value = cfg.persona[p-1].settings[setting]) || value === false || value === 0) ? value : (p ? cfg[setting] : settings[setting]); }
else if ( !cfg.isekaiInherit ) {
return s && ((value = cfg.isekai.persona[p-1].settings[setting]) || value === false || value === 0) ? value :
(p && ((value = cfg.isekai.settings[setting]) || value === false || value === 0) ? value : cfg[setting]); }
else {
return s && ((value = cfg.persona[p-1].set[s-1].settings[setting]) || value === false || value === 0) ? value :
(s && ((value = cfg.isekai.persona[p-1].settings[setting]) || value === false || value === 0) ? value :
(p && ((value = cfg.persona[p-1].settings[setting]) || value === false || value === 0) ? value :
(p && ((value = cfg.isekai.settings[setting]) || value === false || value === 0) ? value : cfg[setting]))); }},
Save = function() { if ( changed ) { changed = false; localStorage.HVmbcfg = JSON.stringify(cfg); }},
Exit = function() { location.href = location.href; },
Reset = function() {
if ( p == 0 && s == 0 && !isk && confirm('Reset to defaults?') ) {
localStorage.removeItem('HVmbcfg');
cfg = JSON.parse(JSON.stringify(settings));
Settings(); }
else if ( p == 0 && s == 0 && isk && confirm('Reset this profile?') ) {
cfg.isekai.settings = {};
Save();
Load(); }
else if ( p != 0 && confirm('Reset this profile?') ) {
(s ? (isk ? cfg.isekai : cfg).persona[p-1].set[s-1] : (isk ? cfg.isekai : cfg).persona[p-1]).settings = {};
Save();
Load(); }},
Switch = function(persona, set, ise) {
if ( p === persona && s === set && isk === ise ) return true;
if ( !changed || confirm('Save and change profile?') ) {
Save();
p = persona;
s = set;
isk = ise;
Load();
return true; }
return false; };
Load();
if ( (div = document.getElementById('mbcfgbt')) ) {
div.parentNode.removeChild(div); }
div = mainpane.appendChild(document.createElement('div'));
div.id = 'mbcfgbt';
var button = div.appendChild(document.createElement('button'));
button.innerHTML = 'Save';
button.onclick = function() { Save(); Load(); };
button = div.appendChild(document.createElement('button'));
button.innerHTML = 'S&E';
button.onclick = function() { if ( !changed || confirm('Save and exit?') ) { Save(); Exit(); }};
button = div.appendChild(document.createElement('button'));
button.innerHTML = 'Exit';
button.onclick = function() { if ( !changed || confirm('Exit without saving?') ) { Exit(); }};
button = div.appendChild(document.createElement('button'));
button.innerHTML = 'Dump';
button.onclick = function() { if ( !changed || confirm('Save and dump to text?') ) { Save(); Load(true); }};
button = div.appendChild(document.createElement('button'));
button.innerHTML = 'Reset';
button.onclick = Reset;
select = div.appendChild(document.createElement('select'));
select.onchange = function() {
if ( Switch(parseInt(select.value[0]), parseInt(select.value[1]), select.value[2] ? 'i' : '') ) {
index = select.selectedIndex; }
else {
select.selectedIndex = index; }};
option = select.appendChild(document.createElement('option'));
option.value = '00';
option.innerHTML = cfg.name;
if ( '' + profile.p + (profile.p ? profile['s' + profile.p] : '0') == option.value ) {
option.style.color = 'blue'; }
for ( var i = 0; i < cfg.persona.length; i++ ) {
option = select.appendChild(document.createElement('option'));
option.value = (i+1) + '0';
option.innerHTML = '- ' + cfg.persona[i].name;
if ( '' + profile.p + (profile.p ? profile['s' + profile.p] : '0') == option.value ) {
option.style.color = 'blue'; }
for ( var j = 0; j < cfg.persona[i].set.length; j++ ) {
option = select.appendChild(document.createElement('option'));
option.value = '' + (i+1) + (j+1);
option.innerHTML = '-- ' + cfg.persona[i].set[j].name;
if ( '' + profile.p + (profile.p ? profile['s' + profile.p] : '0') == option.value ) {
option.style.color = 'blue'; }}}
option = select.appendChild(document.createElement('option'));
option.value = '00i';
option.innerHTML = cfg.isekai.name;
if ( '' + profile.ip + (profile.ip ? profile['is' + profile.ip] : '0') + 'i' == option.value ) {
option.style.color = 'red'; }
for ( i = 0; i < cfg.isekai.persona.length; i++ ) {
option = select.appendChild(document.createElement('option'));
option.value = (i+1) + '0i';
option.innerHTML = '- ' + cfg.isekai.persona[i].name;
if ( '' + profile.ip + (profile.ip ? profile['is' + profile.ip] : '0') + 'i' == option.value ) {
option.style.color = 'red'; }
for ( j = 0; j < cfg.isekai.persona[i].set.length; j++ ) {
option = select.appendChild(document.createElement('option'));
option.value = '' + (i+1) + (j+1) + 'i';
option.innerHTML = '-- ' + cfg.isekai.persona[i].set[j].name;
if ( '' + profile.ip + (profile.ip ? profile['is' + profile.ip] : '0') + 'i' == option.value ) {
option.style.color = 'red'; }}}
button = div.appendChild(document.createElement('button'));
button.innerHTML = 'Name';
button.onclick = function() {
var prf = s ? (isk ? cfg.isekai : cfg).persona[p-1].set[s-1] : (p ? (isk ? cfg.isekai : cfg).persona[p-1] : (isk ? cfg.isekai : cfg)),
opt = select.options[index], name;
if ( (name = prompt('Name this profile?', prf.name)) && name != prf.name ) {
changed = true;
prf.name = name;
opt.innerHTML = (p ? (s ? '-- ' : '- ') : '') + prf.name; }};
button = div.appendChild(document.createElement('button'));
button.innerHTML = 'Set';
button.onclick = function() {
select.querySelector('[style*="' + (isk ? 'red' : 'blue') + '"]').style.color = '';
profile[isk + p] = p;
if (p) {
profile[isk + 's' + p] = s; }
if ( JSON.stringify(profile) != localStorage.HVmbp ) {
localStorage.HVmbp = JSON.stringify(profile); }
select.querySelector('[value="' + p + s + isk + '"]').style.color = isk ? 'red' : 'blue'; };
var auto = div.appendChild(document.createElement('input'));
auto.name = 'profileAutoswitch';
auto.type = 'checkbox';
auto.checked = cfg.profileAutoswitch;
auto.onchange = function() {
changed = true;
cfg.profileAutoswitch = auto.checked; };
var help = div.appendChild(document.createElement('div'));
help.className = 'help';
help.innerHTML = 'auto';
var helptext = help.appendChild(document.createElement('span'));
helptext.className = 'helptext';
helptext.innerHTML = 'automatically switch profile when changing persona or equipment set';
var inherit = div.appendChild(document.createElement('input'));
inherit.name = 'isekaiInherit';
inherit.type = 'checkbox';
inherit.checked = cfg.isekaiInherit;
inherit.onchange = function() {
changed = true;
cfg.isekaiInherit = inherit.checked; };
help = div.appendChild(document.createElement('div'));
help.className = 'help';
help.innerHTML = 'inherit';
helptext = help.appendChild(document.createElement('span'));
helptext.className = 'helptext';
helptext.innerHTML = 'use persistent persona/equipment profiles in isekai'; }
// keybind helper functions
function handleKeys(e) {
if ( release ) {
done = false;
release = false; }
saveKeyDown();
shiftHeld = e.shiftKey;
ctrlHeld = e.ctrlKey;
altHeld = e.altKey;
var bind;
for ( var i = 0; i < bindings.length; i++ ) {
bind = bindings[i];
if ( e.keyCode == bind.keyCode && bind.modifier(e) ) {
bind.action();
return; }}
loadKeyDown(); }
function handleKeyup(e) {
shiftHeld = e.shiftKey;
ctrlHeld = e.ctrlKey;
altHeld = e.altKey;
override = false;
release = true;
if ( cfg.hoverAutoresume ) {
interruptHover = false;
if ( (cfg.hoverAction || override) && !interruptAlert && monsters[target] && monsters[target].hasAttribute('onclick') ) {
Hover(); }}
}
function saveKeyDown() { runScript('var oldkeydown = document.onkeydown ? document.onkeydown : oldkeydown; document.onkeydown = null;'); }
function loadKeyDown() { runScript('document.onkeydown = oldkeydown;'); }
function runScript(code) {
var scriptElement = document.createElement('script');
scriptElement.type = 'text/javascript';
scriptElement.textContent = code;
document.body.appendChild(scriptElement);
scriptElement.remove(); }
function Bind(key, mod, command) {
if ( !command ) {
command = mod;
mod = NoMod; }
if ( command ) {
bindings.push(new Keybind(key,mod,command)); }}
function Keybind(key, mod, action) {
this.keyCode = key;
this.modifier = mod;
this.action = action; }
function NoMod(e) { return !e.shiftKey && !e.altKey && !e.ctrlKey && !e.metaKey; }
function CtrlAltShift(e) { return e.shiftKey && e.altKey && e.ctrlKey && !e.metaKey; }
function CtrlShift(e) { return !e.altKey && e.shiftKey && e.ctrlKey && !e.metaKey; }
function AltShift(e) { return !e.ctrlKey && e.altKey && e.shiftKey && !e.metaKey; }
function CtrlAlt(e) { return !e.shiftKey && e.ctrlKey && e.altKey && !e.metaKey; }
function Ctrl(e) { return e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey; }
function Shift(e) { return e.shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey; }
function Alt(e) { return e.altKey && !e.shiftKey && !e.ctrlKey && !e.metaKey; }
function Any(e) { return !e.metaKey; }
// global variables and constants
var cfg = {}, profile = JSON.parse(localStorage.HVmbp || '{}'), isekai = document.URL.indexOf('isekai') > -1 ? 'i' : '',
bindings = [], gem = [], target = false, cursor = localStorage['HVcursor' + isekai] ? parseInt(localStorage['HVcursor' + isekai]) : -1,
interruptHover, interruptAlert = false, hovering = false, override = false, impulse = false, done = false,
release = false, shiftHeld = false, ctrlHeld = false, altHeld = false, bg, dummy = document.createElement('div'),
mp = 1, sp = 1, monsters = [], monsterData = {}, log, turn, timelog = JSON.parse(localStorage['HVtimelog' + isekai] || '{ "turn":0,"action":0,"round":1,"lastuse":{} }'),
combatlog = JSON.parse(localStorage['HVcombatlog' + isekai] || '{ "pdealt":{"hit":0,"crit":0,"miss":0,"evade":0,"parry":0,"resist":0,"r50":0,"r75":0,"r90":0},' +
'"mdealt":{"hit":0,"crit":0,"miss":0,"evade":0,"parry":0,"resist":0,"r50":0,"r75":0,"r90":0},' +
'"ptaken":{"hit":0,"shit":0,"crit":0,"scrit":0,"miss":0,"evade":0,"parry":0,"block":0,"r50":0,"r75":0,"r90":0},' +
'"mtaken":{"hit":0,"shit":0,"crit":0,"scrit":0,"miss":0,"evade":0,"parry":0,"block":0,"r50":0,"r75":0,"r90":0},' +
'"used":{} }'),
vitals = JSON.parse(localStorage['HVvitals' + isekai] || '{ "hp":0,"mp":0,"sp":0 }'),
droplog = JSON.parse(localStorage['HVtrackdrops' + isekai] ||
'{ "Crystals":{}, "Equips":{}, "Mats":{}, "Artifacts":{}, "Figurines":{}, "Trophies":{}, "Consumables":{}, "Foods":{}, "proficiency":{} }'),
csp = false;
const damage = document.getElementById('2501') ? 'Arcane Focus' : 'Heartseeker',
KEY_A = 65, KEY_B = 66, KEY_C = 67, KEY_D = 68, KEY_E = 69, KEY_F = 70, KEY_G = 71, KEY_H = 72, KEY_I = 73, KEY_J = 74, KEY_K = 75, KEY_L = 76, KEY_M = 77,
KEY_N = 78, KEY_O = 79, KEY_P = 80, KEY_Q = 81, KEY_R = 82, KEY_S = 83, KEY_T = 84, KEY_U = 85, KEY_V = 86, KEY_W = 87, KEY_X = 88, KEY_Y = 89, KEY_Z = 90,
KEY_1 = 49, KEY_2 = 50, KEY_3 = 51, KEY_4 = 52, KEY_5 = 53, KEY_6 = 54, KEY_7 = 55, KEY_8 = 56, KEY_9 = 57, KEY_0 = 48,
KEY_SPACE = 32, KEY_ENTER = 13, KEY_PAGEUP = 33, KEY_PAGEDOWN = 34, KEY_END = 35, KEY_HOME = 36, KEY_LEFT = 37, KEY_UP = 38, KEY_RIGHT = 39, KEY_DOWN = 40,
KEY_F1 = 112, KEY_F2 = 113, KEY_F3 = 114, KEY_F4 = 115, KEY_F5 = 116, KEY_F6 = 117, KEY_F7 = 118, KEY_F8 = 119, KEY_F9 = 120, KEY_F10 = 121, KEY_F11 = 122, KEY_F12 = 123,
KEY_COMMA = 188, KEY_PERIOD = 190, KEY_SLASH = 191, KEY_FORWARDSLASH = 191, KEY_GRAVE = 192, KEY_TILDE = 192, KEY_LBRACKET = 219, KEY_BACKSLASH = 220,
KEY_SEMI = 186, KEY_RBRACKET = 221, KEY_APOSTROPHE = 222, KEY_SHIFT = 16, KEY_CTRL = 17, KEY_ALT = 18,
regexp = { gem:/\w(\w+) Gem/, defaultgem:/\w(\w+).gem/, duration:/(x(\d))*[^\(]*, (\d+)/,
monsters:/MID=\d+[^<>]+HP=\d+/g, monster:/MID=(\d+) \((.+)\) .+ HP=(\d+)/, spellicon:/, '(\w+)'/, defaultfont:/"c\d\w"/,
turn:/(.+?)<tr><td class="tls">/, action:/>([^<>]+)<\/td><\/tr>(<tr><td class="tlb">Spirit Stance Exhausted<\/td><\/tr>)*<tr><td class="tls"/,
zeroturn:/You use\s*\w* (Gem|Draught|Potion|Elixir|Drink|Candy|Infusion|Scroll|Vase|Gum)/, use:/You (cast|use) ([\w\s-]+)/,
damage:/[^<>]+damage( \([^<>]+\))*(<\/td><\/tr><tr><td class="tlb">Your spirit shield absorbs \d+ |<|\.)/g,
type:/for (\d+) (\w+) damage/, shield:/absorbs (\d+)/, strike:/(Fire|Cold|Wind|Elec|Holy|Dark|Void) Strike hits/,
dot:/for (\d+) damage/, pdot:/(Bleeding Wound|Spreading Poison)/, points:/for (\d+) points of (\w+) damage/,
mdmiss:/to connect./g, mdevade:/evades your spell./g, md50:/ hits [^y][^<>]+50%/g, md75:/ hits [^y][^<>]+75%/g, md90:/ hits [^y][^<>]+90%/g,
mdresist:/resists your spell./g, pdmiss:/its mark./g, pdevade:/evades your attack./g, pdparry:/parries your attack./g, mtevade:/ casts [^<>]+evade the attack./g,
mtblock:/ casts [^<>]+block the attack./g, mt50:/ hits y[^<>]+50%/g, mt75:/ hits y[^<>]+75%/g, mt90:/ hits y[^<>]+90%/g, ptmiss:/misses the attack against you./g,
ptevade:/(>You evade| uses [^<>]+evade the attack.)/g, ptparry:/(>You parry| uses [^<>]+parry the attack.)/g, ptblock:/(>You block| uses [^<>]+block the attack.)/g,
counter:/>You counter/g, spellinfo:/\('([\w\s-]+)'.*, (\d+)\)/, crit:/(You crit| crits | blasts )/,
miss:/(You evade|You block|You parry| evades | parries | resists | misses | fails )/, attack:/(You hit|You crit|Arcane Blow)/,
spell:/(You cast| hits | crits | blasts |gains the effect)/, recovery:/(You are healed|Recovered | restores |You drain)/,
round:/Round (\d+) \/ (\d+)/, drops: /\S+ <span style="color:.{7}">\[[^<>]+\](<\/span><\/td><\/tr><tr><td class="tlb">A t)*/g,
drop:/(\S+) \<.*#(.{6}).*\[(.*)\](.)*/, crystal:/(?:(\d+)x )?Crystal/, crystals:/Crystal of (\w+)/, credit:/(\d+) Credit/, reward: /gain (\d+) Credit/,
exp:/You gain (\d+) EXP/, proficiencies:/\d+\.\d+ points of [^<>]+ proficiency/g, proficiency:/(\d+\.\d+) points of ([^<>]+) proficiency/,
quality:[/\[\]/,/\[Peerless/,/\[(Legendary|Peerless)/,/\[(Magnificent|Legendary|Peerless)/,/\[(Exquisite|Magnificent|Legendary|Peerless)/,
/\[(Superior|Exquisite|Magnificent|Legendary|Peerless)/,/\[(Average|Superior|Exquisite|Magnificent|Legendary|Peerless)/,
/\[(Fair|Average|Superior|Exquisite|Magnificent|Legendary|Peerless)/,/\[(Crude|Fair|Average|Superior|Exquisite|Magnificent|Legendary|Peerless)/],
defaultstring:/"c\d\w"/g, defaultletter:/"c\d(\w)"/, whitespace:/(\s{2,}|\n)/g, break:/;/g, number:/\d+/, profile:/settings":{"/,
itemuse:/Use\(/, hoveruse:/HoverAction\([^;]*Use\(/ },
settingsData = [
['ui settings','h'],
['cfgButton','b','show button to access settings and switch profiles during battle'],
['mpboost','f','mp boost from abilities and capacitor'],
['spboost','f','sp boost from sp tank'],
['mppot','i','percentage of base mp restored by mana potion'],
['sppot','i','percentage of base sp restored by spirit potion'],
['showCooldowns','b','show cooldowns on the quickbar'],
['effectsAboveMonsters','b','move player effects to above monsters'],
['vitalsAboveMonsters','b','move vitals and spirit button to above monsters'],
['quickbarBesideMonsters','b','move quickbar to the right of monsters'],
['riddleRight','b','shrink riddlemaster to the right'],
['condenseLeft','b','activate the above four options with everything moved to the left'],
['compactQuickbar','b','eliminate whitespace on quickbar and monster bars'],
['expireNoblink','b','disable blinking of expiring effects'],
['showDurations','b','show effect durations'],
['stackBorder','b','show effect stacks as border thickness rather than numbers'],
['alertColours','b','change background colours according to alert conditions'],
['alertBackground','b','whole background instead of relevant area for alert colours'],
['alertBuffs','s','critical buffs',
'change colour of player effects area if any of these buffs has less than 2 turns left<br>' +
'add the icon filename of any critical buff. this also affects interrupting hover on expiring buffs<br>' +
'to get the filename, activate the buff in battle, right click its icon and inspect element',750],
['colours','o','alert and log colours','set to any valid html colour, or false to disable',120],
['usableBlink','b','mana and spirit gems and potions on the quickbar blink when usable to their full effect'],
['logColours','b','add colour highlights to the battle log'],
['turnDividers','b','add horizontal row between turns'],
['logPasteover','b','add last turn of previous round to new round log. requires round advance via ajax'],
['hideLog','b','hide the battle log'],
['maxVitals','b','show maximum player vitals'],
['showMonsterHP','b','display current and max hp of monsters'],
['shortenHPbars','b','shorten monster hp bars relative to their max hp'],
['monsterNumbers','b','show monster numbers instead of letters'],
['monsterKeywords','s','monster keywords',
'highlight monsters where the name, id or max hp match this expression, set to false to disable<br>' +
'example: /(Meiling|MID=70699|HP=243060)/',750],
['ajaxRound','b','advance to next round using ajax. set to false if you use other scripts that do not support this'],
['ajaxIntervals','i','set to 0 or a higher number if you experience weird flashing of expiring effects'],
['noPopup','b','skip end of round popup'],
['stopAtBattleEnd','b','do not dismiss popup at end of battle'],
['stopOnEquipDrop','b','do not dismiss popup if equipment drops, quality specified by cutoff below'],
['clickableRiddlemaster','b','add links to the riddlemaster to directly submit an answer'],
['edConfirm','b','ask for confirmation before using energy drink'],
['fleeConfirm','b','ask for confirmation before fleeing'],
['raiseGem','b','raise gem icon above quickbar'],
['hoverGem','b','activate gem by hovering over the icon'],
['hoverSpirit','b','activate spirit stance by hovering over the icon'],
['quickbarExtend','a','extend quickbar',
'id for skills/spells/items (in quotes), 0 for space, 1 for gem<br>' +
'set to [1] if you just want the gem icon or [] to disable<br>' +
'IDs:<br>' +
'1001 Flee 1011 Scan 1101 FUS RO DAH 1111 Orbital Friendship Cannon<br>' +
'2201 Shield Bash 2202 Vital Strike 2203 Merciful Blow<br>' +
'2301 Great Cleave 2302 Rending Blow 2303 Shatter Strike<br>' +
'2401 Iris Strike 2402 Backstab 2403 Frenzied Blows<br>' +
'2101 Skyward Sword 2501 Concussive Strike<br>' +
'111 Fiery Blast 112 Inferno 113 Flames of Loki<br>' +
'121 Freeze 122 Blizzard 123 Fimbulvetr<br>' +
'131 Shockblast 132 Chained Lightning 133 Wrath of Thor<br>' +
'141 Gale 142 Downburst 143 Storms of Njord<br>' +
'151 Smite 152 Banishment 153 Paradise Lost<br>' +
'161 Corruption 162 Disintegrate 163 Ragnarok<br>' +
'211 Drain 212 Weaken 213 Imperil<br>' +
'221 Slow 222 Sleep 223 Confuse<br>' +
'231 Blind 232 Silence 233 MagNet<br>' +
'311 Cure 312 Regen 313 Full-Cure<br>' +
'411 Protection 412 Haste 413 Shadow Veil<br>' +
'421 Absorb 422 Spark of Life 423 Spirit Shield<br>' +
'431 Heartseeker 432 Arcane Focus<br>' +
'ikey_1-ikey_15 items ikey_s1-ikey_s6 scrolls ikey_n1-ikey_n6 infusions',750],
['mouse binding and hover settings','h'],
['clickEverywhere','b','enable middle and right click bindings and disable the context menu everywhere'],
['wheelEverywhere','b','enable wheel bindings everywhere'],
['mouseEngage','b','hold mouse buttons to modify hover behaviour'],
['clickLeft','s','left click',
'set to false to leave at default, or Nothing to attack with the above option',750],
['clickMiddle','s','middle click',,750],
['clickRight','s','right click',,750],
['wheelUp','s','wheel up',,750],
['wheelDown','s','wheel down',,750],
['wheelLeft','s','wheel left',,750],
['wheelRight','s','wheel right',,750],
['hoverAction','s','hover action',,750],
['hoverShiftAction','s','shift hover action',,750],
['hoverCtrlAction','s','ctrl hover action',,750],
['hoverAltAction','s','alt hover action',
'these can be set to any bindable action that can be followed up with targeting a monster,<br>' +
'as explained in the keybind section, or to false to disable<br>' +
'examples:<br>' +
'hover action: false - disable hover<br>' +
'hover action: Nothing - attack<br>' +
"hover action: Strongest([Cast('Ragnarok'), Cast('Disintegrate'), Cast('Corruption')]) - dark spell rotation<br>" +
"shift hover action: Strongest([ToggleHover, Cast('Imperil')]) - single cast of imperil<br>" +
'with the above example, you can hold shift, hover and hit Z to cast imperil while being protected by the usual hover safeguards',750],
['hoverArea','i','part of the monster that activates hover',
'1: whole box, 2: icon, 3: name, 4: vitals, 6: status effects'],
['hoverplay interrupt settings','h'],
['startRoundWithHover','b','have hoverplay active at the beginning of each round'],
['hoverAutoresume','b','reactivate hover after releasing any key'],
['minHP','f','hp threshold'],
['minMP','f','mp threshold'],
['minSP','fs','sp threshold',
"formula when set to auto: 0.5-0.5*spboost/(spboost+100)"],
['stopOnEmergency','b','stop on spark or low vitals'],
['stopOnBuffsExpiring','b','stop on critical buff expiring in 1 turn or less'],
['mobile settings','h'],
['clearRound','b','clear target and reset hover action at round transition, to avoid lingering taps and make monster bar safer'],
['spacedBar','b','increase spacing of quickbar and monster bar'],
['monsterBar','a','monster bar',
'add skill/spell icons next to monsters, for single use or tap to engage/tap elsewhere to disengage, single skills and spell rotations<br>' +
'leave empty to disable. example: first parameter is false for single use or true to engage, followed by skill/spell IDs or leave empty for attack<br>' +
'[ [true], - engage attack<br>' +
" [false,'213'], - single cast of imperil<br>" +
" [false,'212'], - single cast of weaken<br>" +
" [true,'163','162','161'] ] - engage dark spell rotation",750],
['tracking settings','h'],
['trackDrops','b','show total numbers of drops and exp at end of battle'],
['detailedDroplog','b','list each drop type individually, excluding crystals and equipment below your quality cutoff'],
['detailedCrystlog','b','list each crystal type individually'],
['equipmentCutoff','i','equipment quality cutoff',
'0 to track all equipment combined,<br>' +
'1 to track Peerless separateley,<br>' +
'2 to track Peerless and Legendary separateley, etc.'],
['selectLog','b','limit end-of-battle onclick to icon, allowing for easier selecting of log'],
['terseLog','b','format log for easier pasting into spreadsheets'],
['trackProficiency','b','show total proficiency gains at end of battle'],
['proficiencySidebar','b','show live proficiency gains during battle'],
['profbarInMainpane','b','proficiency sidebar in mainpane'],
['deleteDropLog','i','delete drop log, 0: never, 1: when navigating away from battle section, 2: at end of battle'],
['dropFontSize','i','adjust font size of drop and proficiency log'],
['trackSpeed','b','show turn count and speed statistic at end of battle'],
['speedFontSize','i','adjust font size of speed statistic'],
['trackDamage','b','show damage dealt and taken at end of battle'],
['damageFontSize','i','adjust font size of damage log'],
['trackUsage','b','show attack/skill/spell/item usage at end of battle'],
['deleteCombatLog','i','delete damage and usage logs, 0: never, 1: when navigating away from battle section, 2: at end of battle'],
['consoleLog','b','output raw machine-readable log data to console when showing the drop log'],
['showRound','b','show the current round number during battle'],
['bigRoundCounter','b','bigger round counter, placed in top right'],
['key bindings','h',,
'Add this for as many bindings as you want:<br>' +
'Bind(KeyCode, Modifier, Action);<br>' +
' KeyCode = From http://www.javascripter.net/faq/keycodes.htm or any of the following:<br>' +
' KEY_A, KEY_B, KEY_C, KEY_D, KEY_E, KEY_F, KEY_G, KEY_H, KEY_I, KEY_J, KEY_K, KEY_L, KEY_M,<br>' +
' KEY_N, KEY_O, KEY_P, KEY_Q, KEY_R, KEY_S, KEY_T, KEY_U, KEY_V, KEY_W, KEY_X, KEY_Y, KEY_Z,<br>' +
' KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0,<br>' +
' KEY_SPACE, KEY_ENTER, KEY_PAGEUP, KEY_PAGEDOWN, KEY_END, KEY_HOME, KEY_LEFT, KEY_UP, KEY_RIGHT, KEY_DOWN,<br>' +
' KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12,<br>' +
' KEY_COMMA, KEY_PERIOD, KEY_SLASH, KEY_FORWARDSLASH, KEY_GRAVE, KEY_TILDE, KEY_LBRACKET, KEY_BACKSLASH,<br>' +
' KEY_SEMI, KEY_RBRACKET, KEY_APOSTROPHE, KEY_SHIFT, KEY_CTRL, KEY_ALT<br>' +
' Modifier = This is OPTIONAL. Valid mods are NoMod, Shift, Ctrl, Alt, CtrlShift, AltShift, CtrlAlt, CtrlAltShift, Any<br>' +
' Action = Valid actions:<br>' +
" Cast('Spell Name')<br>" +
' Spell Name.<br>' +
" Use('Item ID')<br>" +
" Valid Item IDs are 'p' for Gem, 1-15 for Items, 's1'-'s6' for Scrolls and 'n1'-'n6' for Infusions.<br>" +
" Toggle('Type')<br>" +
' Attack, Focus, Defend or Spirit.<br>' +
' Nothing<br>' +
' Use this to unbind a default key or use the default attack when targeting a monster.<br>' +
' TargetMonster(Number)<br>' +
' Targets the specified monster, starting at 0 for A up to 9 for J.<br>' +
' NextRound<br>' +
' Enters next round. Using this overrides both Space and Enter for next round. If you still want to use one of those, add it manually.<br>' +
' Strongest([Action Array])<br>' +
' Picks the most desired action.<br>' +
' For targeted spells or skills, put the most desired action first.<br>' +
' For untargeted spells or items, put the most desired action last.<br>' +
' HoverAction(Action, true/false)<br>' +
' Point mouse at target monster, hit key to perform action, Nothing for default attack. Set second parameter to true to respect alerts.<br>' +
' Impulse(Action)<br>' +
' Perform an action once.<br>' +
' ToggleHover<br>' +
' Turn hoverplay on or off.<br>' +
' Drops<br>' +
' Show drop log.<br>' +
' CursorUp, CursorDown<br>' +
' Move the targeting cursor.<br>' +
' CursorTarget<br>' +
' Target selected monster. Use with Strongest to specify action.<br>' +
' CursorHover<br>' +
' Engage hover at cursor location.<br>' +
' ClearTarget<br>' +
' Unset hover target.<br>' +
' Settings.<br>' +
' Access configuration interface.'],
['bind','t',,,750]
];
// main function triggered on page load
function Enhance() {
if ( document.getElementById('gay_sex') ) return;
Riddlemaster();
if ( !(log = document.getElementById('textlog')) ) return;
if ( cfg.logPasteover && turn ) {
log.firstChild.innerHTML += '<tr><td class="tls"></td></tr>' + turn; }
monsters = document.getElementsByClassName('btm1');
if ( cfg.alertBackground ) {
csp = document.getElementById('csp'); }
interruptHover = !cfg.startRoundWithHover;
if ( cursor >= 0 ) ClearTarget();
if ( cursor >= monsters.length ) cursor = monsters.length - 1;
document.addEventListener('keydown', handleKeys, true);
document.addEventListener('keyup', handleKeyup, true);
if ( cfg.clearRound ) {
Disengage(); }
document.addEventListener('mouseover', ClearTarget, true);
if ( cfg.clickEverywhere ) {
document.addEventListener('mousedown', HandleClick(), true);
document.addEventListener('contextmenu', function(e) { e.preventDefault(); }); }
if ( cfg.wheelEverywhere ) {
document.addEventListener('wheel', HandleWheel(), true); }
if ( cfg.mouseEngage ) {
document.addEventListener('mousedown', MouseEngage, true);
document.addEventListener('mouseup', function() { override = false; release = true; }, true); }
else {
document.addEventListener('mouseup', function() { release = true; }, true); }
var obs = new MutationObserver(Observe);
obs.observe(log.firstChild, {childList: true});
if ( !document.getElementById('homosex') ) {
if ( (cfg.mouseEngage && (regexp.itemuse.test(cfg.clickLeft) || regexp.itemuse.test(cfg.clickMiddle) || regexp.itemuse.test(cfg.clickRight))) ||
regexp.itemuse.test(cfg.hoverAction) || regexp.itemuse.test(cfg.hoverShiftAction) || regexp.itemuse.test(cfg.hoverCtrlAction) ||
regexp.itemuse.test(cfg.hoverAltAction) || regexp.hoveruse.test(cfg.bind) ) {
alert('You have transgressed against your God and your fellow Man. God has charged me with your redemption. ' +
'You are hereby Exiled to Wraeclast where, it is hoped, you shall come to repent your Sins, and make your peace with your beloved Father.'); return; }
cfg.minSP = cfg.minSP == 'auto' ? 0.5-0.5*cfg.spboost/(cfg.spboost+100) : cfg.minSP;
var evals = ['alertBuffs', 'monsterKeywords', 'clickLeft', 'clickMiddle', 'clickRight', 'wheelUp', 'wheelDown', 'wheelLeft', 'wheelRight',
'hoverAction', 'hoverShiftAction', 'hoverCtrlAction', 'hoverAltAction'];
for ( var i = 0; i < evals.length; i++ ) {
try {
cfg[evals[i]] = eval(cfg[evals[i]]); }
catch ( error ) {
cfg[evals[i]] = false;
alert('invalid ' + evals[i] + ' format. option disabled'); }}
try {
eval(cfg.bind); }
catch ( error ) {
bindings = [];
alert('invalid key bindings. option disabled'); }
var style = document.createElement('style');
style.id = 'homosex';
style.innerHTML = '.btm6 { min-width: 195px; top: 0 !important; padding: 18px 3px 3px 1px !important; }' +
(cfg.condenseLeft ? '#pane_effects { position: relative; left: -92px; } #pane_completion { left: -688px; } #battle_left { left: 550px; }' +
'#pane_vitals { position: absolute; top: 3px; left: ' + (document.querySelector('img[src$="bar_orange.png"]') ?
'-556px; } #ckey_spirit { left: -411px; top: 45px;' : '-548px; } #ckey_spirit { left: -459px; top: 2px;') +
'position: absolute; z-index: 1; } #battle_right { left: -7px !important; top: 107px !important; }' +
'#pane_quickbar { display: flex; position: absolute; left: -212px; top: 69px; width: 203px; }' :
(cfg.effectsAboveMonsters ? '#pane_effects { max-width: 534px; position: relative; left: 596px; }' : '') +
(cfg.vitalsAboveMonsters ? '#pane_vitals { position: absolute; top: 3px; left: ' + (document.querySelector('img[src$="bar_orange.png"]') ?
'672px; } #ckey_spirit { left: 817px; top: 45px;' : '690px; } #ckey_spirit { left: 779px; top: 2px;') +
'position: absolute; z-index: 1; } #battle_right { top: 107px !important; }' : '') +
(cfg.quickbarBesideMonsters ? '#pane_quickbar { display: flex; position: absolute; left: 1026px; top: ' + (cfg.vitalsAboveMonsters ? '69' : '4') +
'px; width: 203px; }' : '')) + (cfg.compactQuickbar ? '.btqs { width: 30px !important; height: 32px !important; padding: 0 !important;' +
'border: 1px solid black; } .btqs:not(.mbs):not([onmouseover]) { opacity: 0; } .btqi { left: 0 !important; top: 0 !important; }' +
'.btqs:not(.extend):not(.mbs):not([onmouseover]), .btqb { display:none; }' : '.btqi { top: 3px !important; }') +
(cfg.expireNoblink ? '#pane_effects > img, .btm6 > img { opacity: 1 !important; }' : '') +
'.effect_duration { display: inline-block; width: 30px; margin-right: -30px; position: relative; text-align: center; z-index: 1; }' +
'.effect_duration > div { display: inline-block; min-width: 16px; padding: 0 2px; background: #EDEBDF; color: black; font-weight: bold; }' +
'.effect_duration > div { border: 1px solid black; } .cooldown {' + (cfg.compactQuickbar ? 'width: 30px; margin-top: 4px;' :
'width: 37px; margin-top: 7px;') + 'position: relative; z-index: 3; color: black; font-size: 20px; font-weight: bold; }' +
'#infopane, .bttp, .btm1 { background: ' + cfg.colours.default + '; }' + (cfg.hideLog ? '#textlog { display: none; }' : '') +
(cfg.noPopup ? '#btcp { display: none; }' : '') + '.drop { font-size: ' + cfg.dropFontSize + '%; } .speed { font-size: ' + cfg.speedFontSize + '%; }' +
'.crystal { color: #BA05B4; } .credit { color: #A89000; } .equipment { color: #FF0000; } .token { color: #254117; }' +
'.artifact { color: #0000FF; } .trophy { color: #461B7E; } .consumable { color: #00B000; } .food { color: #489EFF; } ' +
'#pane_effects, #ckey_spirit { border-radius: 5px; }' + (cfg.spacedBar ? '.btqs { margin: 0 20px 20px 0 !important; }' : '') +
(cfg.colours.usable ? '.usable { background: ' + cfg.colours.usable + ';' + (cfg.compactQuickbar ? 'border: 1px solid ' + cfg.colours.usable :
'border-radius: 5px') + '; } .usable > .btqb { display: none; }' : '') + '.monsterhp { display: inline-block; position: relative; left: 204px; top: -20px; }' +
(cfg.usableBlink ? '@keyframes blink { 50% { opacity: 0; }} .usable > .btqi { animation: blink 1s linear infinite; }' : '') +
'#battle_right { position: absolute; left: 681px; top: 42px; width: 364px; overflow: visible; }' +
(cfg.monsterNumbers ? '.btm2 img { display: none; } .btm2 > div:nth-child(1) { font-size: 250%; }' +
'#mkey_1 > .btm2 > div:nth-child(1):after { content: "1"; } #mkey_2 > .btm2 > div:nth-child(1):after { content: "2"; }' +
'#mkey_3 > .btm2 > div:nth-child(1):after { content: "3"; } #mkey_4 > .btm2 > div:nth-child(1):after { content: "4"; }' +
'#mkey_5 > .btm2 > div:nth-child(1):after { content: "5"; } #mkey_6 > .btm2 > div:nth-child(1):after { content: "6"; }' +
'#mkey_7 > .btm2 > div:nth-child(1):after { content: "7"; } #mkey_8 > .btm2 > div:nth-child(1):after { content: "8"; }' +
'#mkey_9 > .btm2 > div:nth-child(1):after { content: "9"; } #mkey_0 > .btm2 > div:nth-child(1):after { content: "10"; }' : '') +
(cfg.colours.miss ? '.miss { color: ' + cfg.colours.miss + '; }' : '') + (cfg.colours.damage ? '.damage { color: ' + cfg.colours.damage + '; }' : '') +
(cfg.colours.item ? '.item { color: ' + cfg.colours.item + '; }' : '') + (cfg.colours.attack ? '.attack { color: ' + cfg.colours.attack + '; }' : '') +
(cfg.colours.spell ? '.spell { color: ' + cfg.colours.spell + '; }' : '') + (cfg.colours.recovery ? '.recovery { color: ' + cfg.colours.recovery + '; }' : '') +
(cfg.colours.effect ? '.effect { color: ' + cfg.colours.effect + '; }' : '') + (cfg.colours.spirit ? '.spirit { color: ' + cfg.colours.spirit + '; }' : '') +
(cfg.colours.proficiency ? '.proficiency { color: ' + cfg.colours.proficiency + '; }' : '') +
'#profbar { position: absolute; left: ' + (cfg.profbarInMainpane ? '1140' : '1240') + 'px; top: 50px; z-index: 1; }' +
'#profbar td:nth-child(1) { text-align: right; } #profbar td:nth-child(2) { text-align: left; } .mbar { display: flex; position: absolute; left: 1075px; }' +
'.mbar > div { cursor: pointer; } #cfgbutton { position: absolute; top: 686px; left: ' + (cfg.condenseLeft ? '529' : '1220') +
'px; cursor: pointer; background: ' + cfg.colours.default + '; z-index: 3; width: 18px; height: 18px; font-size: 17px; }' +
'#cfgbutton:hover #mbprofile { visibility: visible; } #mbprofile { visibility: hidden; position: absolute; right: 0; bottom: 18px;' +
'width: max-content; height: max-content; padding: 5px; background: ' + cfg.colours.default + '; border: 1px solid #5C0D11; }' +
'#mbar_0 { top: ' + ((cfg.showMonsterHP ? 61 : 58)+(cfg.vitalsAboveMonsters ? 65 : 0)) + 'px; }' +
'#mbar_1 { top: ' + ((cfg.showMonsterHP ? 119 : 116)+(cfg.vitalsAboveMonsters ? 65 : 0)) + 'px; }' +
'#mbar_2 { top: ' + ((cfg.showMonsterHP ? 177 : 174)+(cfg.vitalsAboveMonsters ? 65 : 0)) + 'px; }' +
'#mbar_3 { top: ' + ((cfg.showMonsterHP ? 235 : 232)+(cfg.vitalsAboveMonsters ? 65 : 0)) + 'px; }' +
'#mbar_4 { top: ' + ((cfg.showMonsterHP ? 293 : 290)+(cfg.vitalsAboveMonsters ? 65 : 0)) + 'px; }' +
'#mbar_5 { top: ' + ((cfg.showMonsterHP ? 351 : 348)+(cfg.vitalsAboveMonsters ? 65 : 0)) + 'px; }' +
'#mbar_6 { top: ' + ((cfg.showMonsterHP ? 409 : 406)+(cfg.vitalsAboveMonsters ? 65 : 0)) + 'px; }' +
'#mbar_7 { top: ' + ((cfg.showMonsterHP ? 467 : 464)+(cfg.vitalsAboveMonsters ? 65 : 0)) + 'px; }' +
'#mbar_8 { top: ' + ((cfg.showMonsterHP ? 525 : 522)+(cfg.vitalsAboveMonsters ? 65 : 0)) + 'px; }' +
'#mbar_9 { top: ' + ((cfg.showMonsterHP ? 583 : 580)+(cfg.vitalsAboveMonsters ? 65 : 0)) + 'px; }' +
(cfg.maxVitals ? '#dvrhd, #dvrhb, #dvrm, #dvrs { left: -45px; width: 100px; } #vrm { left: -63px; width: 100px; }' : '') +
'#table_magic .fc2 { font-size: 7pt; } #dropbox { position: absolute; top: 35px; left: 583px; width: 360px;' +
'margin: 2px 0 0 15px; padding: 5px 1px 1px; border: 2px ridge #5C0D12; background: #F2EFDF; opacity: 0.95; z-index: 9; }' +
'#damagelog { border: 1px solid; border-collapse: collapse; } #damagelog tr:nth-child(1) > td, #damagelog tr:nth-child(2) > td { text-align: center; }' +
'#damagelog td:nth-child(1) { text-align: left; } #damagelog td { min-width: 50px; padding: 2px 4px; border-left: 1px solid; text-align: right; font-size: ' +
cfg.damageFontSize + '%; }';
document.head.appendChild(style); }
Gems();
Alerts();
Durations();
GetMonsterData();
Monsters();
Confirm();
ExtendQuickbar();
MonsterBar();
ShowCooldowns();
MaxVitals();
Profbar();
ShowRound();
CfgButton(); }
// 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 CustomEvent("battleEnd", {"detail":{timelog,combatlog,droplog}}));
window.removeEventListener('beforeunload', StoreTmp);
var btcp, equip = document.querySelector('span[style$="#FF0000"]');
localStorage.removeItem('HVmonsterData' + isekai);
localStorage.removeItem('HVtimelog' + isekai);
localStorage.removeItem('HVvitals' + isekai);
localStorage.removeItem('HVcursor' + isekai);
if ( cfg.deleteDropLog == 2 ) {
localStorage.removeItem('HVtrackdrops' + isekai); }
else if ( cfg.trackDrops || cfg.trackProficiency || cfg.proficiencySidebar ) {
localStorage['HVtrackdrops' + isekai] = JSON.stringify(droplog); }
if ( cfg.deleteCombatLog == 2 ) {
localStorage.removeItem('HVcombatlog' + isekai); }
else if ( cfg.trackDamage || cfg.trackUsage ) {
localStorage['HVcombatlog' + isekai] = JSON.stringify(combatlog); }
document.getElementById('homosex').innerHTML += '.mbar, #cfgbutton { display: none !important; }';
if ( cfg.noPopup && (btcp = document.getElementById('btcp')) && !cfg.stopAtBattleEnd &&
(!cfg.stopOnEquipDrop || !equip) ) {
btcp.click();
document.querySelector('img[src$="finishbattle.png"]').click(); }
return; }
hovering = false;
Gems();
Alerts();
Durations();
Monsters();
Confirm();
ExtendQuickbar();
ProcessLog();
ShowCooldowns();
MaxVitals();
FormatLog();
TrackDrops();
Profbar();
NoPopup(); }
// combat helper functions
function Riddlemaster() {
var bot;
if ( !cfg.clickableRiddlemaster || !(bot = document.getElementById('riddlebot')) ) return;
if ( cfg.trackSpeed ) {
timelog.horse = (timelog.horse ? timelog.horse : 0) + 1;}
if ( !document.getElementById('buttsex') ) {
var style = document.createElement('style');
style.id = 'buttsex';
style.innerHTML =
(cfg.condenseLeft || cfg.riddleRight ? '#riddlemaster { left: ' + (cfg.condenseLeft ? '-370' : '340') + 'px; }' +
'#riddlebot > img { width: 500px; } .riddlelink { display: inline-block; position: absolute; top: 44px; }' +
'.riddlelink:nth-child(2) { left: 128px; } .riddlelink:nth-child(3) { left: 288px; } .riddlelink:nth-child(4) { left: 448px; }' :
'.riddlelink { display: inline-block; position: relative; top: -585px; }' +
'.riddlelink:nth-child(2) { left: -80px; } .riddlelink:nth-child(4) { left: 80px; }') +
'.riddlelink > div { width: 0; height: 0; border-left: 20px solid transparent;' +
'border-right: 20px solid transparent; border-bottom: 20px solid #5C0D11; margin: 20px 50px 0; }';
document.head.appendChild(style); }
var a = document.createElement('a');
a.id = 'gay_sex';
a.className = 'riddlelink';
a.href = 'javascript:void(0)';
a.appendChild(document.createElement('div'));
a.setAttribute('onclick', 'document.getElementById("riddleanswer").value="A";document.getElementById("riddleform").submit()');
bot.appendChild(a);
a = document.createElement('a');
a.className = 'riddlelink';
a.href = 'javascript:void(0)';
a.appendChild(document.createElement('div'));
a.setAttribute('onclick', 'document.getElementById("riddleanswer").value="B";document.getElementById("riddleform").submit()');
bot.appendChild(a);
a = document.createElement('a');
a.className = 'riddlelink';
a.href = 'javascript:void(0)';
a.appendChild(document.createElement('div'));
a.setAttribute('onclick', 'document.getElementById("riddleanswer").value="C";document.getElementById("riddleform").submit()');
bot.appendChild(a); }
function Gems() {
var ikeyp;
if ( (ikeyp = document.getElementById('ikey_p')) ) {
gem[0] = ikeyp.getAttribute('onclick');
gem[1] = ikeyp.getAttribute('onmouseover');
var name = ikeyp.innerHTML.match(regexp.gem) || ParseDefault(ikeyp).match(regexp.defaultgem);
switch ( name[1] ) {
case 'ystic': gem[2] = '/y/e/channeling.png'; break;
case 'ealth': gem[2] = '/y/e/healthpot.png'; break;
case 'ana' : gem[2] = '/y/e/manapot.png'; gem[3] = 0; break;
case 'pirit': gem[2] = '/y/e/spiritpot.png'; gem[3] = 1; break; }}
else gem = []; }
function Alerts() {
var alert = false, ocfull = false, omo, oc, vcp,
spirit = document.querySelector('img[src$="spirit_n.png"]') || document.querySelector('img[src$="spirit_s.png"]');
bg = cfg.colours.default;
if ( cfg.hoverSpirit && spirit && (omo = spirit.getAttribute('onmouseover')) && omo.indexOf('lock') < 0 ) {
spirit.setAttribute('onmouseover', omo + ';' + spirit.getAttribute('onclick')); }
if ( (oc = document.querySelector('img[src$="bar_orange.png"]')) ) {
mp = parseInt(document.querySelector('img[src$="bar_blue.png"]').style.width)/414;
sp = parseInt(document.querySelector('img[src$="bar_red.png"]').style.width)/414;
if ( spirit && parseInt(oc.style.width) >= 414 ) {
ocfull = true; }
if ( (gem[3] === 0 && mp < 0.5+0.5*cfg.mpboost/(cfg.mpboost+100)) ||
(gem[3] === 1 && sp < 0.75+0.25*cfg.spboost/(cfg.spboost+100)) ) {
gem[4] = true; }
else gem[4] = false;
if ( sp <= cfg.minSP && cfg.colours.lowsp ) {
bg = cfg.colours.lowsp; if ( cfg.stopOnEmergency ) alert = true; }
if ( mp <= cfg.minMP && cfg.colours.lowmp ) {
bg = cfg.colours.lowmp; if ( cfg.stopOnEmergency ) alert = true; }
if ( parseInt(document.querySelector('img[src$="green.png"]').style.width) <= 414 * cfg.minHP && cfg.colours.lowhp ) {
bg = cfg.colours.lowhp; if ( cfg.stopOnEmergency ) alert = true; }
if ( !document.querySelector('img[src$="bar_dgreen.png"]') && document.querySelector('img[src$="fallenshield.png"]') && cfg.colours.spark ) {
bg = cfg.colours.spark; if ( cfg.stopOnEmergency ) alert = true; }}
else {
mp = parseInt(document.querySelector('img[src$="bar_blue.png"]').style.width)/207;
sp = parseInt(document.querySelector('img[src$="bar_red.png"]').style.width)/207;
if ( spirit && (vcp = document.querySelector('#vcp > div')) && parseInt(vcp.style.width) >= 190 ) {
ocfull = true; }
if ( (gem[3] === 0 && mp < 0.5+0.5*cfg.mpboost/(cfg.mpboost+100)) ||
(gem[3] === 1 && sp < 0.75+0.25*cfg.spboost/(cfg.spboost+100)) ) {
gem[4] = true; }
else gem[4] = false;
if ( sp <= cfg.minSP && cfg.colours.lowsp ) {
bg = cfg.colours.lowsp; if ( cfg.stopOnEmergency ) alert = true; }
if ( mp <= cfg.minMP && cfg.colours.lowmp ) {
bg = cfg.colours.lowmp; if ( cfg.stopOnEmergency ) alert = true; }
if ( parseInt(document.querySelector('img[src$="green.png"]').style.width) <= 496 * cfg.minHP && cfg.colours.lowhp ) {
bg = cfg.colours.lowhp; if ( cfg.stopOnEmergency ) alert = true; }
if ( !document.querySelector('img[src$="bar_dgreen.png"]') && document.querySelector('img[src$="fallenshield.png"]') && cfg.colours.spark ) {
bg = cfg.colours.spark; if ( cfg.stopOnEmergency ) alert = true; }}
interruptAlert = alert;
if ( cfg.alertColours ) {
if ( csp ) {
if ( bg == cfg.colours.default && ocfull && cfg.colours.ocfull ) {
bg = cfg.colours.ocfull; }
csp.style.background = bg; }
else {
if ( spirit && cfg.colours.ocfull ) {
spirit.style.background = ocfull ? cfg.colours.ocfull : cfg.colours.default; }
document.getElementById('pane_vitals').style.background = bg; }}}
function Durations() {
if ( !cfg.showDurations && !cfg.alertColours && !cfg.stopOnBuffsExpiring ) return;
var pane = document.getElementById('pane_effects'), alert = false, div, dur, duration, stack,
effects = pane.getElementsByTagName('img'), n = effects.length;
while ( n-- > 0 ) {
if ( (duration = effects[n].getAttribute('onmouseover').match(regexp.duration)) ) {
if ( cfg.alertBuffs && duration[3] < 2 && effects[n].src.indexOf('channeling.png') < 0 && cfg.alertBuffs.test(effects[n].src) ) {
alert = true; }
if ( cfg.showDurations ) {
div = document.createElement('div');
dur = document.createElement('div');
div.className = 'effect_duration';
if ( duration[3] < 9 ) {
dur.style.background = duration[3] < 4 ? 'aquamarine' : 'lavender'; }
dur.innerHTML = duration[3];
if ( (stack = duration[2]) ) {
if ( cfg.stackBorder ) {
dur.style.border = Math.ceil(stack/2)+1 + 'px solid black'; }
else {
dur.innerHTML += ' x' + stack; }}
div.appendChild(dur);
pane.insertBefore(div, effects[n]); }}}
if ( cfg.alertColours ) {
var colour = alert && cfg.colours.expiring ? cfg.colours.expiring :
(document.querySelector('#pane_effects > img[src$="channeling.png"]') && cfg.colours.channelling ? cfg.colours.channelling : cfg.colours.default);
if ( csp ) {
csp.style.background = bg != cfg.colours.default ? bg : colour; }
else {
pane.style.background = colour; }}
interruptAlert = interruptAlert || (cfg.stopOnBuffsExpiring && alert);
if ( cfg.showDurations ) {
effects = document.querySelectorAll('.btm6 > img[onmouseover]'); n = effects.length;
while ( n-- > 0 ) {
if ( (duration = effects[n].getAttribute('onmouseover').match(regexp.duration)) ) {
div = document.createElement('div');
dur = document.createElement('div');
div.className = 'effect_duration';
if ( duration[3] < 9 ) {
dur.style.background = duration[3] < 4 ? 'aquamarine' : 'lavender'; }
dur.innerHTML = duration[3];
if ( (stack = duration[2]) ) {
if ( cfg.stackBorder ) {
dur.style.border = Math.ceil(stack/2)+1 + 'px solid black'; }
else {
dur.innerHTML += ' x' + stack; }}
div.appendChild(dur);
effects[n].parentNode.insertBefore(div, effects[n]); }}}}
function GetMonsterData() {
if ( !cfg.showMonsterHP && !cfg.shortenHPbars && !cfg.monsterKeywords ) return;
var local, data, monster;
if ( (local = localStorage['HVmonsterData' + isekai]) ) {
monsterData = JSON.parse(local); }
else {
monsterData.info = [];
monsterData.id = [];
monsterData.name = [];
monsterData.hp = [];
monsterData.highlight = [];
monsterData.hp[10] = 0;
if ( (data = log.innerHTML.match(regexp.monsters)) ) {
for ( var i = 0; i < monsters.length; i++ ) {
monster = data[monsters.length-i-1].match(regexp.monster);
monsterData.info[i] = monster[0];
monsterData.id[i] = parseInt(monster[1]);
monsterData.name[i] = monster[2];
monsterData.hp[i] = parseInt(monster[3]);
monsterData.highlight[i] = cfg.monsterKeywords && monsters[i].hasAttribute('onclick') && cfg.monsterKeywords.test(monster[0]);
if ( !monsters[i].querySelector('.btm2[style]') ) {
monsterData.hp[10] = monsterData.hp[i] > monsterData.hp[10] ? monsterData.hp[i] : monsterData.hp[10]; }}}}}
function Monsters() {
var monster;
for ( var i = 0; i < monsters.length; i++ ) {
if ( (monster = monsters[i]) && monster.hasAttribute('onclick') ) {
var area = monster.querySelector('.btm' + cfg.hoverArea) || monster;
area.addEventListener('mouseout', ClearTarget, true);
area.addEventListener('mouseover', SetTarget(i), true);
monster.addEventListener('mousedown', HandleClick(i), true);
monster.addEventListener('contextmenu', function(e) { e.preventDefault(); });
monster.addEventListener('wheel', HandleWheel(i), true);
if ( cursor >= 0 ) Cursor();
if ( target === i && (cfg.hoverAction || override) && !interruptHover && !interruptAlert ) {
Hover(); }
if ( monsterData.highlight && monsterData.highlight[i] ) {
monster.querySelector('.btm2').style.background = cfg.colours.monster; }
if ( (cfg.showMonsterHP || cfg.shortenHPbars) && monsterData.hp[i] ) {
var bar = monster.querySelector('img[src$="nbargreen.png"]'),
ratio = parseInt(bar.style.width) / 120;
if ( cfg.showMonsterHP && !cfg.quickbarBesideMonsters && !cfg.condenseLeft ) {
var div = monster.appendChild(document.createElement('div'));
div.className = 'monsterhp';
div.innerHTML = 'HP: ' + Math.round(ratio * monsterData.hp[i]).toLocaleString() + ' / ' + monsterData.hp[i].toLocaleString(); }
if ( cfg.shortenHPbars && monsterData.hp[i] < monsterData.hp[10] ) {
var factor = monsterData.hp[i] / monsterData.hp[10],
border = monster.querySelector('img[src$="nbarfg.png"]'),
bg = monster.querySelector('.chbd');
bar.style.width = Math.round(ratio * factor * 120) + 'px';
border.style.width = Math.round(factor * 120) + 'px';
border.style.height = '12px';
bg.style.width = Math.round(factor * 120) + 'px'; }}
if ( cfg.colours.stun || cfg.colours.imperil || cfg.colours.stunimperil ) {
var status = monster.querySelector('.btm6'),
stun = status.innerHTML.indexOf('wpn_stun.png') > -1,
imperil = status.innerHTML.indexOf('imperil.png') > -1;
if ( cfg.colours.stunimperil && stun && imperil ) {
monster.style.background = cfg.colours.stunimperil; }
else if ( cfg.colours.stun && stun ) {
monster.style.background = cfg.colours.stun; }
else if ( cfg.colours.imperil && imperil ) {
monster.style.background = cfg.colours.imperil; }}}}}
function Hover() {
if ( hovering ) return;
hovering = true;
if ( override ) {
override(); }
else if ( shiftHeld && cfg.hoverShiftAction ) {
cfg.hoverShiftAction(); }
else if ( ctrlHeld && cfg.hoverCtrlAction ) {
cfg.hoverCtrlAction(); }
else if ( altHeld && cfg.hoverAltAction ) {
cfg.hoverAltAction(); }
else {
cfg.hoverAction(); }
if ( impulse ) {
impulse();
done = true;
impulse = false; }
monsters[target].click(); }
function SetTarget(i) { return function() {
target = i;
if ( (cfg.hoverAction || override) && !interruptHover && !interruptAlert && monsters[target].hasAttribute('onclick') ) {
Hover(); }};}
function HandleClick(i) {
return function(e) {
var action;
if ( (i || i === 0) && e.which == 1 ) action = cfg.clickLeft;
else if ( e.which == 2 ) action = cfg.clickMiddle;
else if ( e.which == 3 ) action = cfg.clickRight;
if ( action ) {
e.preventDefault();
if ( release ) {
done = false;
release = false; }
action();
if ( i || i === 0 ) {
monsters[i].click(); }}};}
function HandleWheel(i) {
return function(e) {
var action;
if ( e.deltaY < 0 ) action = cfg.wheelUp;
else if ( e.deltaY > 0 ) action = cfg.wheelDown;
else if ( e.deltaX < 0 ) action = cfg.wheelLeft;
else if ( e.deltaX > 0 ) action = cfg.wheelRight;
if ( action ) {
e.preventDefault();
done = false;
action();
if ( i || i === 0 ) {
monsters[i].click(); }}};}
function MouseEngage(e) {
if ( e.which == 1 ) override = cfg.clickLeft;
else if ( e.which == 2 ) override = cfg.clickMiddle;
else if ( e.which == 3 ) override = cfg.clickRight; }
function Cursor() {
this.battle.hover_target(monsters[cursor]); }
function Confirm() {
var ed, flee;
if ( cfg.edConfirm && (ed = document.querySelector('div[onclick][onmouseover*="item(11401)"]')) ) {
ed.setAttribute('onclick', 'if ( confirm("Are you sure you want to use Energy Drink?") ) {' + ed.getAttribute('onclick') + '}'); }
if ( cfg.fleeConfirm && (flee = document.getElementById('1001')) ) {
flee.setAttribute('onclick', 'if ( confirm("Tired already? I guess we can play forever some other time...") ) {' + flee.getAttribute('onclick') + '}'); }
if ( cfg.fleeConfirm && (flee = document.querySelector('.btqs[onclick][onmouseover*="Flee"]')) ) {
flee.setAttribute('onclick', 'if ( confirm("Tired already? I guess we can play forever some other time...") ) {' + flee.getAttribute('onclick') + '}'); }}
function ExtendQuickbar() {
var quickbar = document.getElementById('quickbar'), div, img, spell, action;
for ( var i = 0; i < cfg.quickbarExtend.length; i++ ) {
div = document.createElement('div');
div.className = 'btqs extend';
switch ( cfg.quickbarExtend[i] ) {
case 0: break;
case 1: if ( gem[0] ) {
if ( cfg.raiseGem ) {
div.setAttribute('style', 'position: absolute;' + (cfg.condenseLeft ? 'top: -55px; left: 165px;' :
(cfg.vitalsAboveMonsters ? 'top: 15px; left: 1191px;' :
'top: 50px; left: 622px;'))); }
div.setAttribute('onclick', gem[0]);
if ( cfg.hoverGem ) {
div.setAttribute('onmouseover', gem[1] + ';' + gem[0]); }
else {
div.setAttribute('onmouseover', gem[1]); }
if ( cfg.alertColours && gem[4] ) {
div.className += ' usable'; }
img = document.createElement('img');
img.src = gem[2];
img.className = 'btqi';
div.appendChild(img);
img = document.createElement('img');
img.src = '/y/ab/b.png';
img.className = 'btqb';
div.appendChild(img); } break;
default: if ( (spell = document.getElementById(cfg.quickbarExtend[i])) ) {
img = document.createElement('img');
var info = spell.getAttribute('onmouseover');
if ( (action = spell.getAttribute('onclick')) ) {
div.setAttribute('onclick', action); }
else {
img.style.opacity = 0.5; }
div.setAttribute('onmouseover', info);
if ( cfg.quickbarExtend[i].indexOf('ikey') < 0 ) {
img.src = '/y/a/' + info.match(regexp.spellicon)[1] + '.png'; }
else {
var name = spell.innerHTML;
if ( regexp.defaultfont.test(name) ) name = ParseDefault(spell);
switch ( true ) {
case name.indexOf('ealth') > -1: img.src = '/y/e/healthpot.png'; break;
case name.indexOf('ana') > -1: img.src = '/y/e/manapot.png';
if ( cfg.alertColours && name.indexOf('otion') > -1 && mp < (100-cfg.mppot+cfg.mppot*cfg.mpboost/(cfg.mpboost+100))/100 ) {
div.className += ' usable'; } break;
case name.indexOf('pirit') > -1: img.src = '/y/e/spiritpot.png';
if ( cfg.alertColours && name.indexOf('otion') > -1 && sp < (100-cfg.sppot+cfg.sppot*cfg.spboost/(cfg.spboost+100))/100 ) {
div.className += ' usable'; } break;
case name.indexOf('lixir') > -1: img.src = '/y/e/healthpot.png'; break;
case name.indexOf('rink') > -1: img.src = '/y/e/soulstone.png'; break;
case name.indexOf('andy') > -1: img.src = '/y/e/soulstone.png'; break;
case name.indexOf('lames') > -1: img.src = '/y/e/fireinfusion.png'; break;
case name.indexOf('rost') > -1: img.src = '/y/e/coldinfusion.png'; break;
case name.indexOf('ightning') > -1: img.src = '/y/e/elecinfusion.png'; break;
case name.indexOf('torms') > -1: img.src = '/y/e/windinfusion.png'; break;
case name.indexOf('ivinity') > -1: img.src = '/y/e/holyinfusion.png'; break;
case name.indexOf('arkness') > -1: img.src = '/y/e/darkinfusion.png'; break;
case name.indexOf('wiftness') > -1: img.src = '/y/e/haste_scroll.png'; break;
case name.indexOf('rotection') > -1: img.src = '/y/e/protection_scroll.png'; break;
case name.indexOf('vatar') > -1: img.src = '/y/e/protection_scroll.png'; break;
case name.indexOf('bsorption') > -1: img.src = '/y/e/absorb_scroll.png'; break;
case name.indexOf('hadows') > -1: img.src = '/y/e/shadowveil_scroll.png'; break;
case name.indexOf('ife') > -1: img.src = '/y/e/sparklife_scroll.png'; break;
case name.indexOf('ods') > -1: img.src = '/y/e/sparklife_scroll.png'; break;
case name.indexOf('ase') > -1: img.src = '/y/e/flowers.png'; break;
case name.indexOf('um') > -1: img.src = '/y/e/gum.png'; break;
default: img.src = '/y/e/channeling.png'; break; }}
img.className = 'btqi';
div.appendChild(img);
img = document.createElement('img');
img.src = '/y/ab/b.png';
img.className = 'btqb';
div.appendChild(img); } break; }
quickbar.appendChild(div); }}
function MonsterBar() {
if ( !cfg.monsterBar[0] || cfg.quickbarBesideMonsters || cfg.condenseLeft ) return;
var mbar, div, img;
for ( var i = 0; i < monsters.length; i++ ) {
mbar = document.createElement('div');
mbar.id = 'mbar_' + i;
mbar.className = 'mbar';
for ( var j = 0; (j < 3 || (j < 4 && !cfg.spacedBar)) && j < cfg.monsterBar.length; j++ ) {
div = document.createElement('div');
div.className = 'btqs mbs';
img = document.createElement('img');
img.src = cfg.monsterBar[j][1] ?
'/y/a/' + document.getElementById(cfg.monsterBar[j][1]).getAttribute('onmouseover').match(regexp.spellicon)[1] + '.png' :
'/y/e/wpn_bleed.png';
img.className = 'btqi';
div.appendChild(img);
img = document.createElement('img');
img.src = '/y/ab/b.png';
img.className = 'btqb';
div.appendChild(img);
if ( cfg.monsterBar[j][0] ) {
div.onmouseout = Disengage;
div.onmouseover = BarEngage(i, cfg.monsterBar[j]); }
else {
div.onclick = BarAction(i, cfg.monsterBar[j]); }
mbar.appendChild(div); }
document.body.appendChild(mbar); }}
function Disengage() { target = false; override = false; }
function BarEngage(i, actions) {
return function() {
if ( !monsters[i].hasAttribute('onclick') ) return;
override = StrongestBar(actions);
SetTarget(i)(); };}
function BarAction(i, actions) {
return function() {
if ( !monsters[i].hasAttribute('onclick') ) return;
StrongestBar(actions)();
monsters[i].click(); };}
function StrongestBar(actions) { return function() { var n = actions.length; while ( n-- > 1 ) document.getElementById(actions[n]).click(); };}
function ProcessLog() {
turn = log.innerHTML.match(regexp.turn);
if ( turn ) turn = turn[0]; else return;
if ( !cfg.showCooldowns && !cfg.trackSpeed && !cfg.trackDamage && !cfg.trackUsage ) return;
if ( !timelog.startTime && cfg.trackSpeed ) timelog.startTime = Date.now();
var action = turn.match(regexp.action);
if ( action ) action = action[1]; else return;
timelog.action++;
if ( !regexp.zeroturn.test(action) ) timelog.turn++;
var use = action.match(regexp.use), miss, counter;
if ( use ) {
use = use[2];
if ( cfg.showCooldowns ) timelog.lastuse[use] = timelog.turn;
if ( cfg.trackUsage ) combatlog.used[use] = (combatlog.used[use] ? combatlog.used[use] : 0) + 1; }
else if ( !cfg.trackUsage ) {}
else if ( action.indexOf('Spirit Stance') > -1 ) combatlog.used.Spirit = (combatlog.used.Spirit ? combatlog.used.Spirit : 0) + 1;
else if ( action.indexOf('Defending.') > -1 ) combatlog.used.Defend = (combatlog.used.Defend ? combatlog.used.Defend : 0) + 1;
else if ( action.indexOf('Focusing.') > -1 ) combatlog.used.Focus = (combatlog.used.Focus ? combatlog.used.Focus : 0) + 1;
else combatlog.used.Attack = (combatlog.used.Attack ? combatlog.used.Attack : 0) + 1;
if ( cfg.trackDamage ) {
var dmg;
if ( (dmg = turn.match(regexp.damage)) ) {
var cast = action.indexOf('You cast') > -1, data, shield;
for ( var i = 0; i < dmg.length; i++ ) {
if ( (data = dmg[i].match(regexp.type)) ) {
if ( dmg[i].indexOf('its you for') > -1 ) {
var crit = dmg[i].indexOf(' crits ') > -1;
if ( dmg[i].indexOf(' casts ') > -1 ) {
combatlog.mtaken.hit++;
if ( crit ) combatlog.mtaken.crit++;
combatlog.mtaken[data[2]] = (combatlog.mtaken[data[2]] ? combatlog.mtaken[data[2]] : 0) + parseInt(data[1]);
if ( (shield = dmg[i].match(regexp.shield)) ) {
combatlog.mtaken.shit++;
if ( crit ) combatlog.mtaken.scrit++;
combatlog.mtaken['s'+data[2]] = (combatlog.mtaken['s'+data[2]] ? combatlog.mtaken['s'+data[2]] : 0) + parseInt(shield[1]); }}
else {
combatlog.ptaken.hit++;
if ( crit ) combatlog.ptaken.crit++;
combatlog.ptaken[data[2]] = (combatlog.ptaken[data[2]] ? combatlog.ptaken[data[2]] : 0) + parseInt(data[1]);
if ( (shield = dmg[i].match(regexp.shield)) ) {
combatlog.ptaken.shit++;
if ( crit ) combatlog.ptaken.scrit++;
combatlog.ptaken['s'+data[2]] = (combatlog.ptaken['s'+data[2]] ? combatlog.ptaken['s'+data[2]] : 0) + parseInt(shield[1]); }}}
else {
if ( cast ) {
if ( dmg[i].indexOf(' explodes ') < 0 ) {
combatlog.mdealt.hit++;
if ( dmg[i].indexOf(' blasts ') > -1 ) combatlog.mdealt.crit++; }
combatlog.mdealt[data[2]] = (combatlog.mdealt[data[2]] ? combatlog.mdealt[data[2]] : 0) + parseInt(data[1]); }
else {
if ( !regexp.strike.test(dmg[i]) ) {
combatlog.pdealt.hit++;
if ( regexp.crit.test(dmg[i]) ) combatlog.pdealt.crit++; }
combatlog.pdealt[data[2]] = (combatlog.pdealt[data[2]] ? combatlog.pdealt[data[2]] : 0) + parseInt(data[1]); }}}
else if ( (data = dmg[i].match(regexp.dot)) ) {
if ( regexp.pdot.test(dmg[i]) ) combatlog.pdealt.dot = (combatlog.pdealt.dot ? combatlog.pdealt.dot : 0) + parseInt(data[1]);
else combatlog.mdealt.dot = (combatlog.mdealt.dot ? combatlog.mdealt.dot : 0) + parseInt(data[1]); }
else if ( (data = dmg[i].match(regexp.points)) ) {
if ( dmg[i].indexOf('You counter') > -1 ) {
combatlog.pdealt.hit++;
combatlog.pdealt[data[2]] = (combatlog.pdealt[data[2]] ? combatlog.pdealt[data[2]] : 0) + parseInt(data[1]); }
else {
combatlog.mdealt[data[2]] = (combatlog.mdealt[data[2]] ? combatlog.mdealt[data[2]] : 0) + parseInt(data[1]); }}}}
if ( (miss = turn.match(regexp.mdmiss)) ) combatlog.mdealt.miss += miss.length;
if ( (miss = turn.match(regexp.mdevade)) ) combatlog.mdealt.evade += miss.length;
if ( (miss = turn.match(regexp.mdresist)) ) combatlog.mdealt.resist += miss.length;
if ( (miss = turn.match(regexp.md50)) ) combatlog.mdealt.r50 += miss.length;
if ( (miss = turn.match(regexp.md75)) ) combatlog.mdealt.r75 += miss.length;
if ( (miss = turn.match(regexp.md90)) ) combatlog.mdealt.r90 += miss.length;
if ( (miss = turn.match(regexp.pdmiss)) ) combatlog.pdealt.miss += miss.length;
if ( (miss = turn.match(regexp.pdevade)) ) combatlog.pdealt.evade += miss.length;
if ( (miss = turn.match(regexp.pdparry)) ) combatlog.pdealt.parry += miss.length;
if ( (miss = turn.match(regexp.mtevade)) ) combatlog.mtaken.evade += miss.length;
if ( (miss = turn.match(regexp.mtblock)) ) combatlog.mtaken.block += miss.length;
if ( (miss = turn.match(regexp.mt50)) ) combatlog.mtaken.r50 += miss.length;
if ( (miss = turn.match(regexp.mt75)) ) combatlog.mtaken.r75 += miss.length;
if ( (miss = turn.match(regexp.mt90)) ) combatlog.mtaken.r90 += miss.length;
if ( (miss = turn.match(regexp.ptmiss)) ) combatlog.ptaken.miss += miss.length;
if ( (miss = turn.match(regexp.ptevade)) ) combatlog.ptaken.evade += miss.length;
if ( (miss = turn.match(regexp.ptparry)) ) combatlog.ptaken.parry += miss.length;
if ( (miss = turn.match(regexp.ptblock)) ) combatlog.ptaken.block += miss.length; }
if ( cfg.trackUsage && (counter = turn.match(regexp.counter)) ) combatlog.used.Counter = (combatlog.used.Counter ? combatlog.used.Counter : 0) + counter.length; }
function ShowCooldowns() {
if ( !cfg.showCooldowns ) return;
var quickbar = document.getElementById('quickbar'), info, used, cooldown, div,
buttons = quickbar.querySelectorAll('.btqs[onmouseover]:not([onclick])'), n = buttons.length;
while ( n-- > 0 ) {
if ( (info = buttons[n].getAttribute('onmouseover').match(regexp.spellinfo)) &&
(used = timelog.lastuse[info[1]]) && (cooldown = info[2] - timelog.turn + used) > 0 ) {
div = document.createElement('div');
div.className = 'cooldown';
div.innerHTML = cooldown;
buttons[n].appendChild(div); }}}
function MaxVitals() {
if ( !cfg.maxVitals ) return;
var hpd, mpd, spd, changed = false;
if ( (hpd = document.getElementById('dvrhd') || document.getElementById('dvrhb')) ) {
mpd = document.getElementById('dvrm');
spd = document.getElementById('dvrs'); }
else {
hpd = document.getElementById('vrhd') || document.getElementById('vrhb');
mpd = document.getElementById('vrm');
spd = document.getElementById('vrs'); }
var hpv = parseInt(hpd.innerHTML), mpv = parseInt(mpd.innerHTML), spv = parseInt(spd.innerHTML);
if ( hpv > vitals.hp ) { vitals.hp = hpv; changed = true; }
if ( mpv > vitals.mp ) { vitals.mp = mpv; changed = true; }
if ( spv > vitals.sp ) { vitals.sp = spv; changed = true; }
hpd.innerHTML = hpv + '/' + vitals.hp;
mpd.innerHTML = mpv + '/' + vitals.mp;
spd.innerHTML = spv + '/' + vitals.sp; }
function FormatLog() {
if ( !cfg.logColours && !cfg.turnDividers ) return;
var rows = log.getElementsByTagName('td');
for ( var i = 0; i < rows.length; i++ ) {
if ( rows[i].className == 'tls' ) {
if ( cfg.turnDividers ) {
rows[i].innerHTML = '<hr>'; }
break; }
var text = rows[i].innerHTML;
if ( cfg.logColours ) {
if ( regexp.crit.test(text) ) {
rows[i].className = 'tlb'; }
if ( regexp.miss.test(text) ) {
rows[i].className += ' miss'; }
else if ( text.indexOf('its you for') > -1 ) {
rows[i].className += ' damage'; }
else if ( regexp.zeroturn.test(text) ) {
rows[i].className += ' item'; }
else if ( regexp.attack.test(text) ) {
rows[i].className += ' attack'; }
else if ( regexp.spell.test(text) ) {
rows[i].className += ' spell'; }
else if ( regexp.recovery.test(text) ) {
rows[i].className += ' recovery'; }
else if ( text.indexOf('You gain the effect') > -1 ) {
rows[i].className += ' effect'; }
else if ( text.indexOf('Spirit Stance') > -1 ) {
rows[i].className += ' spirit'; }
else if ( text.indexOf('proficiency') > -1 ) {
rows[i].className += ' proficiency'; }}}}
function ShowRound() {
var div = document.getElementById(cfg.bigRoundCounter ? 'mainpane' : 'battle_right').appendChild(document.createElement('div')), rounds;
div.id = 'gay_sex';
if ( !cfg.showRound ) return;
if ( !timelog.rounds && (rounds = log.innerHTML.match(regexp.round)) ) {
timelog.round = rounds[1];
timelog.rounds = rounds[2]; }
if ( timelog.rounds ) {
div.innerHTML = (cfg.bigRoundCounter ? '' : 'Round ') + timelog.round.toLocaleString() + ' / ' + timelog.rounds.toLocaleString();
if ( cfg.bigRoundCounter ) {
div.setAttribute('style', 'position: absolute; left: 1110px; top: 10px; font-size: 200%; font-weight: bold'); }}}
function CfgButton() {
if ( !cfg.cfgButton ) return;
var div = document.createElement('div');
div.id = 'cfgbutton';
div.innerHTML = '\u2699';
div.onclick = Settings;
document.body.appendChild(div);
var hasper = regexp.profile.test(JSON.stringify(cfg.persona));
var hasisk = regexp.profile.test(JSON.stringify(cfg.isekai.persona)) || (hasper && cfg.isekaiInherit);
if ( (!isekai && hasper) || (isekai && hasisk) ) {
var menu = div.appendChild(document.createElement('div'));
const Set = function(i, p, s) {
return function(e) {
e.stopPropagation();
var blue;
if ( (blue = menu.querySelector('[style*="' + (isekai ? 'red' : 'blue') + '"')) ) {
blue.style.color = ''; }
profile[isekai + 'p'] = p;
if (p) {
profile[isekai + 's' + profile[isekai + 'p']] = s; }
if ( JSON.stringify(profile) != localStorage.HVmbp ) {
localStorage.HVmbp = JSON.stringify(profile);
location.href = location.href; }
i.style.color = isekai ? 'red' : 'blue'; };};
menu.id = 'mbprofile';
menu.className = 'fc4 fal fcb';
var base = menu.appendChild(document.createElement('div')), blue = false;
base.onclick = Set(base, 0, 0);
if ( !isekai ) {
base.innerHTML = cfg.name;
for ( var i = 0; i < cfg.persona.length; i++ ) {
if ( regexp.profile.test(JSON.stringify(cfg.persona[i])) ) {
var persona = menu.appendChild(document.createElement('div'));
persona.innerHTML = '- ' + cfg.persona[i].name;
persona.onclick = Set(persona, i+1, 0);
for ( var j = 0; j < cfg.persona[i].set.length; j++ ) {
if ( regexp.profile.test(JSON.stringify(cfg.persona[i].set[j])) ) {
var set = menu.appendChild(document.createElement('div'));
set.innerHTML = '-- ' + cfg.persona[i].set[j].name;
set.onclick = Set(set, i+1, j+1);
if ( profile.p == i+1 && profile['s' + profile.p] == j+1 ) {
set.style.color = 'blue';
blue = true; }}}
if ( profile.p == i+1 && (!blue || profile['s' + profile.p] == 0) ) {
persona.style.color = 'blue';
blue = true; }}}
if ( !blue || profile.p == 0 ) {
base.style.color = 'blue'; }}
else {
base.innerHTML = cfg.isekai.name;
for ( i = 0; i < cfg.isekai.persona.length; i++ ) {
hasisk = regexp.profile.test(JSON.stringify(cfg.isekai.persona[i]));
hasper = regexp.profile.test(JSON.stringify(cfg.persona[i])) && cfg.isekaiInherit;
if ( hasisk || hasper ) {
persona = menu.appendChild(document.createElement('div'));
persona.innerHTML = '- ' + (hasisk ? cfg.isekai.persona[i].name : cfg.persona[i].name);
persona.onclick = Set(persona, i+1, 0);
for ( j = 0; j < cfg.isekai.persona[i].set.length; j++ ) {
hasisk = regexp.profile.test(JSON.stringify(cfg.isekai.persona[i].set[j]));
hasper = regexp.profile.test(JSON.stringify(cfg.persona[i].set[j])) && cfg.isekaiInherit;
if ( hasisk || hasper ) {
set = menu.appendChild(document.createElement('div'));
set.innerHTML = '-- ' + (hasisk ? cfg.isekai.persona[i].set[j].name : cfg.persona[i].set[j].name);
set.onclick = Set(set, i+1, j+1);
if ( profile.ip == i+1 && profile['is' + profile.ip] == j+1 ) {
set.style.color = 'red';
blue = true; }}}
if ( profile.ip == i+1 && (!blue || profile['is' + profile.ip] == 0) ) {
persona.style.color = 'red';
blue = true; }}}
if ( !blue || profile.ip == 0 ) {
base.style.color = 'red'; }}}}
function TrackDrops() {
if ( (!cfg.trackDrops && !cfg.trackProficiency && !cfg.proficiencySidebar) || !document.getElementById('btcp') ) return;
if ( cfg.trackDrops ) {
var reward = turn.match(regexp.reward);
if ( reward && (reward = parseInt(reward[1])) ) {
droplog.Credit = (droplog.Credit ? droplog.Credit : 0) + reward; }
var drops = turn.match(regexp.drops);
if ( !drops ) drops = [];
var n = drops.length, crystal, crystals, credit, exp, proficiencies, proficiency, prof;
while ( n-- > 0 ) {
var drop = drops[n].match(regexp.drop);
if ( drop[2] == 'BA05B4' && (crystal = drop[3].match(regexp.crystal)) ) {
droplog.Crystal = (droplog.Crystal ? droplog.Crystal : 0) + (parseInt(crystal[1]) || 1);
if ( cfg.detailedCrystlog && (crystals = drop[3].match(regexp.crystals)) ) {
droplog.Crystals[crystals[0]] = (droplog.Crystals[crystals[0]] ? droplog.Crystals[crystals[0]] : 0) + (parseInt(crystal[1]) || 1); }}
else if (drop[2] == 'A89000' && (credit = drop[3].match(regexp.credit)) ) {
droplog.Credit = (droplog.Credit ? droplog.Credit : 0) + (parseInt(credit[1]) || 1); }
else if ( drop[2] == 'FF0000' && !drop[4] && regexp.quality[8].test(drop[0]) ) {
var tracked = false;
if ( (tracked = cfg.equipmentCutoff > 0 && drop[3].indexOf('Peerless') > -1) ) {
droplog.Peerless = (droplog.Peerless ? droplog.Peerless : 0) + 1; }
else if ( (tracked = cfg.equipmentCutoff > 1 && drop[3].indexOf('Legendary') > -1) ) {
droplog.Legendary = (droplog.Legendary ? droplog.Legendary : 0) + 1; }
else if ( (tracked = cfg.equipmentCutoff > 2 && drop[3].indexOf('Magnificent') > -1) ) {
droplog.Magnificent = (droplog.Magnificent ? droplog.Magnificent : 0) + 1; }
else if ( (tracked = cfg.equipmentCutoff > 3 && drop[3].indexOf('Exquisite') > -1) ) {
droplog.Exquisite = (droplog.Exquisite ? droplog.Exquisite : 0) + 1; }
else if ( (tracked = cfg.equipmentCutoff > 4 && drop[3].indexOf('Superior') > -1) ) {
droplog.Superior = (droplog.Superior ? droplog.Superior : 0) + 1; }
else if ( (tracked = cfg.equipmentCutoff > 5 && drop[3].indexOf('Average') > -1) ) {
droplog.Average = (droplog.Average ? droplog.Average : 0) + 1; }
else if ( (tracked = cfg.equipmentCutoff > 6 && drop[3].indexOf('Fair') > -1) ) {
droplog.Fair = (droplog.Fair ? droplog.Fair : 0) + 1; }
else if ( (tracked = cfg.equipmentCutoff > 7 && drop[3].indexOf('Crude') > -1) ) {
droplog.Crude = (droplog.Crude ? droplog.Crude : 0) + 1; }
else {
droplog.Equipment = (droplog.Equipment ? droplog.Equipment : 0) + 1; }
if ( cfg.detailedDroplog && tracked ) {
droplog.Equips[drop[3]] = (droplog.Equips[drop[3]] ? droplog.Equips[drop[3]] : 0) + 1; }}
else if ( drop[2] == 'FF0000' && !drop[4] ) {
droplog.Material = (droplog.Material ? droplog.Material : 0) + (parseInt(drop[1]) || 1);
if ( cfg.detailedDroplog ) {
droplog.Mats[drop[3]] = (droplog.Mats[drop[3]] ? droplog.Mats[drop[3]] : 0) + (parseInt(drop[1]) || 1); }}
else if ( drop[3].indexOf('Chaos') > -1 ) {
droplog.Chaos = (droplog.Chaos ? droplog.Chaos : 0) + 1; }
else if ( drop[3].indexOf('Blood') > -1 ) {
droplog.Blood = (droplog.Blood ? droplog.Blood : 0) + 1; }
else if ( drop[3].indexOf('Soul') > -1 ) {
droplog.Soul = (droplog.Soul ? droplog.Soul : 0) + (drop[1] == 'five' ? 5 : (parseInt(drop[1]) || 1)); }
else if ( drop[3].indexOf('Figurine') > -1 ) {
droplog.Figurine = (droplog.Figurine ? droplog.Figurine : 0) + 1;
if ( cfg.detailedDroplog ) {
droplog.Figurines[drop[3]] = (droplog.Figurines[drop[3]] ? droplog.Figurines[drop[3]] : 0) + 1; }}
else if ( drop[2] == '0000FF' ) {
droplog.Artifact = (droplog.Artifact ? droplog.Artifact : 0) + 1;
if ( cfg.detailedDroplog ) {
droplog.Artifacts[drop[3]] = (droplog.Artifacts[drop[3]] ? droplog.Artifacts[drop[3]] : 0) + 1; }}
else if ( drop[2] == '461B7E' ) {
droplog.Trophy = (droplog.Trophy ? droplog.Trophy : 0) + 1;
if ( cfg.detailedDroplog ) {
droplog.Trophies[drop[3]] = (droplog.Trophies[drop[3]] ? droplog.Trophies[drop[3]] : 0) + 1; }}
else if ( drop[2] == '00B000' && drop[3].indexOf('Gem') < 0 ) {
droplog.Consumable = (droplog.Consumable ? droplog.Consumable : 0) + 1;
if ( cfg.detailedDroplog ) {
droplog.Consumables[drop[3]] = (droplog.Consumables[drop[3]] ? droplog.Consumables[drop[3]] : 0) + 1; }}
else if ( drop[2] == '489EFF' ) {
droplog.Food = (droplog.Food ? droplog.Food : 0) + 1;
if ( cfg.detailedDroplog ) {
droplog.Foods[drop[3]] = (droplog.Foods[drop[3]] ? droplog.Foods[drop[3]] : 0) + 1; }}}
if ( (exp = log.innerHTML.match(regexp.exp)) ) {
droplog.EXP = (droplog.EXP ? droplog.EXP : 0) + parseInt(exp[1]); }}
if ( (cfg.trackProficiency || cfg.proficiencySidebar) && (proficiencies = log.innerHTML.match(regexp.proficiencies)) ) {
for ( var i = 0; i < proficiencies.length; i++ ) {
if ( (proficiency = proficiencies[i].match(regexp.proficiency)) && (prof = parseFloat(proficiency[1])) && prof > 0 ) {
droplog.proficiency[proficiency[2]] = (droplog.proficiency[proficiency[2]] ? droplog.proficiency[proficiency[2]] : 0) + prof; }}}}
function Profbar() {
if ( !cfg.proficiencySidebar ) return;
var profbar = document.getElementById('profbar');
if ( !profbar ) {
profbar = document.createElement('table');
profbar.id = 'profbar';
document.getElementById('csp').appendChild(profbar); }
profbar.innerHTML = '<tbody>' +
(droplog.proficiency['one-handed weapon'] ? '<tr><td>' + droplog.proficiency['one-handed weapon'].toFixed(3) + '</td><td>1H</td></tr>' : '') +
(droplog.proficiency['two-handed weapon'] ? '<tr><td>' + droplog.proficiency['two-handed weapon'].toFixed(3) + '</td><td>2H</td></tr>' : '') +
(droplog.proficiency['dual wielding'] ? '<tr><td>' + droplog.proficiency['dual wielding'].toFixed(3) + '</td><td>DW</td></tr>' : '') +
(droplog.proficiency['cloth armor'] ? '<tr><td>' + droplog.proficiency['cloth armor'].toFixed(3) + '</td><td>cloth</td></tr>' : '') +
(droplog.proficiency['light armor'] ? '<tr><td>' + droplog.proficiency['light armor'].toFixed(3) + '</td><td>light</td></tr>' : '') +
(droplog.proficiency['heavy armor'] ? '<tr><td>' + droplog.proficiency['heavy armor'].toFixed(3) + '</td><td>heavy</td></tr>' : '') +
(droplog.proficiency.staff ? '<tr><td>' + droplog.proficiency.staff.toFixed(3) + '</td><td>staff</td></tr>' : '') +
(droplog.proficiency['elemental magic'] ? '<tr><td>' + droplog.proficiency['elemental magic'].toFixed(3) + '</td><td>elem</td></tr>' : '') +
(droplog.proficiency['divine magic'] ? '<tr><td>' + droplog.proficiency['divine magic'].toFixed(3) + '</td><td>holy</td></tr>' : '') +
(droplog.proficiency['forbidden magic'] ? '<tr><td>' + droplog.proficiency['forbidden magic'].toFixed(3) + '</td><td>dark</td></tr>' : '') +
(droplog.proficiency['deprecating magic'] ? '<tr><td>' + droplog.proficiency['deprecating magic'].toFixed(3) + '</td><td>dep</td></tr>' : '') +
(droplog.proficiency['supportive magic'] ? '<tr><td>' + droplog.proficiency['supportive magic'].toFixed(3) + '</td><td>sup</td></tr>' : '') +
'</tbody>'; }
function ShowDrops(end) {
var btcp = document.getElementById('btcp');
if ( end && !btcp ) return;
if ( !end && !btcp ) {
if ( (btcp = document.getElementById('dropbox')) ) {
btcp.parentNode.removeChild(btcp);
return; }
btcp = document.createElement('div');
btcp.id = 'dropbox';
document.getElementById('pane_completion').appendChild(btcp); }
if ( end && cfg.selectLog ) {
document.querySelector('img[src$="finishbattle.png"]').setAttribute('onclick', btcp.getAttribute('onclick'));
btcp.removeAttribute('onclick'); }
var span, crystal, credit, peerless, legendary, magnificent, exquisite, superior, average, fair, crude, equipment,
material, chaos, blood, soul, artifact, figurine, trophy, consumable, food, exp, turns, startTime;
if ( cfg.consoleLog ) {
console.log(JSON.stringify(combatlog));
console.log(JSON.stringify(droplog)); }
btcp.setAttribute('style', 'display: block; height: auto; min-height: 120px; max-height: 621px; overflow: auto');
if ( (crystal = droplog.Crystal) ) {
btcp.appendChild(document.createElement('br'));
span = btcp.appendChild(document.createElement('span'));
span.className = 'drop crystal';
span.innerHTML = crystal.toLocaleString() + (cfg.terseLog ? '\t' : ' ') + 'Crystal' + (crystal > 1 || cfg.terseLog ? 's' : '');
if ( cfg.detailedCrystlog ) {
for ( var crystals in droplog.Crystals ) {
btcp.appendChild(document.createElement('br'));
span = btcp.appendChild(document.createElement('span'));
span.className = 'drop crystal';
span.innerHTML = droplog.Crystals[crystals].toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + crystals; }}}
if ( (credit = droplog.Credit) ) {
btcp.appendChild(document.createElement('br'));
span = btcp.appendChild(document.createElement('span'));
span.className = 'drop credit';
span.innerHTML = credit.toLocaleString() + (cfg.terseLog ? '\t' : ' ') + 'Credit' + (credit > 1 || cfg.terseLog ? 's' : ''); }
if ( cfg.detailedDroplog ) {
for ( var equips in droplog.Equips ) {
btcp.appendChild(document.createElement('br'));
span = btcp.appendChild(document.createElement('span'));
span.className = 'drop equipment';
span.innerHTML = droplog.Equips[equips].toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + equips; }}
else {
if ( (peerless = droplog.Peerless) ) {
btcp.appendChild(document.createElement('br'));
span = btcp.appendChild(document.createElement('span'));
span.className = 'drop equipment';
span.innerHTML = peerless.toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + 'Peerless Equipment'; }
if ( (legendary = droplog.Legendary) ) {
btcp.appendChild(document.createElement('br'));
span = btcp.appendChild(document.createElement('span'));
span.className = 'drop equipment';
span.innerHTML = legendary.toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + 'Legendary Equipment'; }
if ( (magnificent = droplog.Magnificent) ) {
btcp.appendChild(document.createElement('br'));
span = btcp.appendChild(document.createElement('span'));
span.className = 'drop equipment';
span.innerHTML = magnificent.toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + 'Magnificent Equipment'; }
if ( (exquisite = droplog.Exquisite) ) {
btcp.appendChild(document.createElement('br'));
span = btcp.appendChild(document.createElement('span'));
span.className = 'drop equipment';
span.innerHTML = exquisite.toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + 'Exquisite Equipment'; }
if ( (superior = droplog.Superior) ) {
btcp.appendChild(document.createElement('br'));
span = btcp.appendChild(document.createElement('span'));
span.className = 'drop equipment';
span.innerHTML = superior.toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + 'Superior Equipment'; }
if ( (average = droplog.Average) ) {
btcp.appendChild(document.createElement('br'));
span = btcp.appendChild(document.createElement('span'));
span.className = 'drop equipment';
span.innerHTML = average.toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + 'Average Equipment'; }
if ( (fair = droplog.Fair) ) {
btcp.appendChild(document.createElement('br'));
span = btcp.appendChild(document.createElement('span'));
span.className = 'drop equipment';
span.innerHTML = fair.toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + 'Fair Equipment'; }
if ( (crude = droplog.Crude) ) {
btcp.appendChild(document.createElement('br'));
span = btcp.appendChild(document.createElement('span'));
span.className = 'drop equipment';
span.innerHTML = crude.toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + 'Crude Equipment'; }}
if ( (equipment = droplog.Equipment) ) {
btcp.appendChild(document.createElement('br'));
span = btcp.appendChild(document.createElement('span'));
span.className = 'drop equipment';
span.innerHTML = equipment.toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + (cfg.equipmentCutoff > 0 ? 'Lesser ' : '') + 'Equipment'; }
if ( cfg.detailedDroplog ) {
for ( var mats in droplog.Mats ) {
btcp.appendChild(document.createElement('br'));
span = btcp.appendChild(document.createElement('span'));
span.className = 'drop equipment';
span.innerHTML = droplog.Mats[mats].toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + mats; }}
else {
if ( (material = droplog.Material) ) {
btcp.appendChild(document.createElement('br'));
span = btcp.appendChild(document.createElement('span'));
span.className = 'drop equipment';
span.innerHTML = material.toLocaleString() + (cfg.terseLog ? '\t' : ' ') + 'Material' + (material > 1 && !cfg.terseLog ? 's' : ''); }}
if ( (chaos = droplog.Chaos) ) {
btcp.appendChild(document.createElement('br'));
span = btcp.appendChild(document.createElement('span'));
span.className = 'drop token';
span.innerHTML = chaos.toLocaleString() + (cfg.terseLog ? '\t' : ' ') + 'Chaos Token' + (chaos > 1 && !cfg.terseLog ? 's' : ''); }
if ( (blood = droplog.Blood) ) {
btcp.appendChild(document.createElement('br'));
span = btcp.appendChild(document.createElement('span'));
span.className = 'drop token';
span.innerHTML = blood.toLocaleString() + (cfg.terseLog ? '\t' : ' ') + 'Token' + (blood > 1 && !cfg.terseLog ? 's' : '') + ' of Blood'; }
if ( (soul = droplog.Soul) ) {
btcp.appendChild(document.createElement('br'));
span = btcp.appendChild(document.createElement('span'));
span.className = 'drop token';
span.innerHTML = soul.toLocaleString() + (cfg.terseLog ? '\t' : ' ') + ' Soul Fragment' + (cfg.terseLog ? '' : 's'); }
if ( cfg.detailedDroplog ) {
for ( var artifacts in droplog.Artifacts ) {
btcp.appendChild(document.createElement('br'));
span = btcp.appendChild(document.createElement('span'));
span.className = 'drop artifact';
span.innerHTML = droplog.Artifacts[artifacts].toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + artifacts; }
for ( var figurines in droplog.Figurines ) {
btcp.appendChild(document.createElement('br'));
span = btcp.appendChild(document.createElement('span'));
span.className = 'drop artifact';
span.innerHTML = droplog.Figurines[figurines].toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + figurines; }
for ( var trophies in droplog.Trophies ) {
btcp.appendChild(document.createElement('br'));
span = btcp.appendChild(document.createElement('span'));
span.className = 'drop trophy';
span.innerHTML = droplog.Trophies[trophies].toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + trophies; }
for ( var consumables in droplog.Consumables ) {
btcp.appendChild(document.createElement('br'));
span = btcp.appendChild(document.createElement('span'));
span.className = 'drop consumable';
span.innerHTML = droplog.Consumables[consumables].toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + consumables; }
for ( var foods in droplog.Foods ) {
btcp.appendChild(document.createElement('br'));
span = btcp.appendChild(document.createElement('span'));
span.className = 'drop food';
span.innerHTML = droplog.Foods[foods].toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + foods; }}
else {
if ( (artifact = droplog.Artifact) ) {
btcp.appendChild(document.createElement('br'));
span = btcp.appendChild(document.createElement('span'));
span.className = 'drop artifact';
span.innerHTML = artifact.toLocaleString() + (cfg.terseLog ? '\t' : ' ') + 'Artifact' + (artifact > 1 && !cfg.terseLog ? 's' : ''); }
if ( (figurine = droplog.Figurine) ) {
btcp.appendChild(document.createElement('br'));
span = btcp.appendChild(document.createElement('span'));
span.className = 'drop artifact';
span.innerHTML = figurine.toLocaleString() + (cfg.terseLog ? '\t' : ' ') + 'Figurine' + (figurine > 1 && !cfg.terseLog ? 's' : ''); }
if ( (trophy = droplog.Trophy) ) {
btcp.appendChild(document.createElement('br'));
span = btcp.appendChild(document.createElement('span'));
span.className = 'drop trophy';
span.innerHTML = trophy.toLocaleString() + (cfg.terseLog ? '\t' : ' ') + 'Troph' + (trophy > 1 && !cfg.terseLog ? 'ies' : 'y'); }
if ( (consumable = droplog.Consumable) ) {
btcp.appendChild(document.createElement('br'));
span = btcp.appendChild(document.createElement('span'));
span.className = 'drop consumable';
span.innerHTML = consumable.toLocaleString() + (cfg.terseLog ? '\t' : ' ') + 'Consumable' + (consumable > 1 && !cfg.terseLog ? 's' : ''); }
if ( (food = droplog.Food) ) {
btcp.appendChild(document.createElement('br'));
span = btcp.appendChild(document.createElement('span'));
span.className = 'drop food';
span.innerHTML = food.toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + 'Food'; }}
if ( (exp = droplog.EXP) ) {
btcp.appendChild(document.createElement('br'));
span = btcp.appendChild(document.createElement('span'));
span.className = 'drop';
span.innerHTML = exp.toLocaleString() + (cfg.terseLog ? '\t' : ' ') + 'EXP'; }
if ( cfg.trackProficiency ) {
for ( var prof in droplog.proficiency ) {
btcp.appendChild(document.createElement('br'));
span = btcp.appendChild(document.createElement('span'));
span.className = 'drop';
span.innerHTML = droplog.proficiency[prof].toFixed(3) + (cfg.terseLog ? '\t' : ' ') + prof; }}
if ( cfg.trackSpeed && (turns = timelog.action) && (startTime = timelog.startTime) ) {
btcp.appendChild(document.createElement('br'));
btcp.appendChild(document.createElement('br'));
var time = Math.round((Date.now() - startTime) / 1000.0),
hours = Math.floor(time / 3600),
minutes = Math.floor(time / 60) % 60,
seconds = time % 60,
tps = turns / time;
span = btcp.appendChild(document.createElement('span'));
span.className = 'speed';
span.innerHTML = turns.toLocaleString() + ' turn' + (turns == 1 ? '' : 's') + ' ' +
hours + ':' +
(minutes < 10 ? '0' : '') + minutes + ':' +
(seconds < 10 ? '0' : '') + seconds + ' (' +
tps.toLocaleString() + ' t/s)' +
(timelog.horse ? ' ' + timelog.horse + ' horse' + (timelog.horse > 1 ? 's' : '') : ''); }}
function ShowDamage() {
if ( !cfg.trackDamage ) return;
var any = { fire: combatlog.pdealt.fire || combatlog.mdealt.fire || combatlog.ptaken.fire || combatlog.mtaken.fire,
cold: combatlog.pdealt.cold || combatlog.mdealt.cold || combatlog.ptaken.cold || combatlog.mtaken.cold,
elec: combatlog.pdealt.elec || combatlog.mdealt.elec || combatlog.ptaken.elec || combatlog.mtaken.elec,
wind: combatlog.pdealt.wind || combatlog.mdealt.wind || combatlog.ptaken.wind || combatlog.mtaken.wind,
holy: combatlog.pdealt.holy || combatlog.mdealt.holy || combatlog.ptaken.holy || combatlog.mtaken.holy,
dark: combatlog.pdealt.dark || combatlog.mdealt.dark || combatlog.ptaken.dark || combatlog.mtaken.dark,
crushing: combatlog.pdealt.crushing || combatlog.mdealt.crushing || combatlog.ptaken.crushing || combatlog.mtaken.crushing,
slashing: combatlog.pdealt.slashing || combatlog.mdealt.slashing || combatlog.ptaken.slashing || combatlog.mtaken.slashing,
piercing: combatlog.pdealt.piercing || combatlog.mdealt.piercing || combatlog.ptaken.piercing || combatlog.mtaken.piercing,
void: combatlog.pdealt.void || combatlog.mdealt.void || combatlog.ptaken.void || combatlog.mtaken.void,
dot: combatlog.pdealt.dot || combatlog.mdealt.dot,
pdealt: combatlog.pdealt.dot || combatlog.pdealt.hit || combatlog.pdealt.miss || combatlog.pdealt.evade || combatlog.pdealt.parry,
mdealt: combatlog.mdealt.fire || combatlog.mdealt.cold || combatlog.mdealt.elec || combatlog.mdealt.wind ||
combatlog.mdealt.dot || combatlog.mdealt.hit || combatlog.mdealt.miss || combatlog.mdealt.evade || combatlog.mdealt.resist,
ptaken: combatlog.ptaken.hit || combatlog.ptaken.miss || combatlog.ptaken.evade || combatlog.ptaken.parry || combatlog.ptaken.block,
mtaken: combatlog.mtaken.hit || combatlog.mtaken.evade || combatlog.mtaken.block,
pspirit: combatlog.ptaken.sfire || combatlog.ptaken.scold || combatlog.ptaken.selec || combatlog.ptaken.swind || combatlog.ptaken.sholy ||
combatlog.ptaken.sdark || combatlog.ptaken.scrushing || combatlog.ptaken.sslashing || combatlog.ptaken.spiercing || combatlog.ptaken.svoid,
mspirit: combatlog.mtaken.sfire || combatlog.mtaken.scold || combatlog.mtaken.selec || combatlog.mtaken.swind || combatlog.mtaken.sholy ||
combatlog.mtaken.sdark || combatlog.mtaken.scrushing || combatlog.mtaken.sslashing || combatlog.mtaken.spiercing || combatlog.mtaken.svoid,
hit: combatlog.pdealt.hit || combatlog.mdealt.hit || combatlog.ptaken.hit || combatlog.mtaken.hit,
r50: combatlog.mdealt.r50 || combatlog.mtaken.r50,
r75: combatlog.mdealt.r75 || combatlog.mtaken.r75,
r90: combatlog.mdealt.r90 || combatlog.mtaken.r90,
miss: combatlog.pdealt.miss || combatlog.mdealt.miss || combatlog.ptaken.miss,
evade: combatlog.pdealt.evade || combatlog.mdealt.evade || combatlog.ptaken.evade || combatlog.mtaken.evade,
parry: combatlog.pdealt.parry || combatlog.ptaken.parry,
resist: combatlog.mdealt.resist,
block: combatlog.ptaken.block || combatlog.mtaken.block };
if ( !any.pdealt && !any.mdealt && !any.ptaken && !any.mtaken ) return;
any.dtotal = any.pdealt && any.mdealt;
any.ttotal = any.ptaken && any.mtaken || any.pspirit || any.mspirit;
any.none = any.miss || any.evade || any.parry || any.resist || any.block;
const Row = function(type) {
return any[type] ? '</tr><tr><td>' + type + '</td>' +
(any.pdealt ? '<td>' + (combatlog.pdealt[type] ? combatlog.pdealt[type].toLocaleString() : '') + '</td>' : '') +
(any.mdealt ? '<td>' + (combatlog.mdealt[type] ? combatlog.mdealt[type].toLocaleString() : '') + '</td>' : '') +
(any.dtotal ? '<td>' + (combatlog.pdealt[type] || combatlog.mdealt[type] ?
((combatlog.pdealt[type] ? combatlog.pdealt[type] : 0) + (combatlog.mdealt[type] ? combatlog.mdealt[type] : 0)).toLocaleString() : '') + '</td>' : '') +
(any.ptaken ? '<td>' + (combatlog.ptaken[type] ? combatlog.ptaken[type].toLocaleString() : '') + '</td>' : '') +
(any.pspirit ? '<td>' + (combatlog.ptaken['s'+type] ? combatlog.ptaken['s'+type].toLocaleString() : '') + '</td>' : '') +
(any.mtaken ? '<td>' + (combatlog.mtaken[type] ? combatlog.mtaken[type].toLocaleString() : '') + '</td>' : '') +
(any.mspirit ? '<td>' + (combatlog.mtaken['s'+type] ? combatlog.mtaken['s'+type].toLocaleString() : '') + '</td>' : '') +
(any.ttotal ? '<td>' + (combatlog.ptaken[type] || combatlog.mtaken[type] ?
((combatlog.ptaken[type] ? combatlog.ptaken[type] : 0) + (combatlog.ptaken['s'+type] ? combatlog.ptaken['s'+type]: 0) +
(combatlog.mtaken[type] ? combatlog.mtaken[type] : 0) + (combatlog.mtaken['s'+type] ? combatlog.mtaken['s'+type] : 0)).toLocaleString() : '') +
'</td>' : '') : ''; },
Column = function(type, s) {
return (combatlog[type][s+'fire'] ? combatlog[type][s+'fire'] : 0) + (combatlog[type][s+'cold'] ? combatlog[type][s+'cold'] : 0) +
(combatlog[type][s+'elec'] ? combatlog[type][s+'elec'] : 0) + (combatlog[type][s+'wind'] ? combatlog[type][s+'wind'] : 0) +
(combatlog[type][s+'holy'] ? combatlog[type][s+'holy'] : 0) + (combatlog[type][s+'dark'] ? combatlog[type][s+'dark'] : 0) +
(combatlog[type][s+'crushing'] ? combatlog[type][s+'crushing'] : 0) + (combatlog[type][s+'slashing'] ? combatlog[type][s+'slashing'] : 0) +
(combatlog[type][s+'piercing'] ? combatlog[type][s+'piercing'] : 0) + (combatlog[type][s+'void'] ? combatlog[type][s+'void'] : 0) +
(combatlog[type][s+'dot'] ? combatlog[type][s+'dot'] : 0); },
ColumnNone = function(type) {
return (combatlog[type].miss ? combatlog[type].miss : 0) + (combatlog[type].evade ? combatlog[type].evade : 0) +
(combatlog[type].parry ? combatlog[type].parry : 0) + (combatlog[type].resist ? combatlog[type].resist : 0) +
(combatlog[type].block ? combatlog[type].block : 0); },
Count = function(type) {
return '<td>' + type + '</td>' +
(any.pdealt ? '<td>' + (combatlog.pdealt[type] ? combatlog.pdealt[type].toLocaleString() : '') + '</td>' : '') +
(any.mdealt ? '<td>' + (combatlog.mdealt[type] ? combatlog.mdealt[type].toLocaleString() : '') + '</td>' : '') +
(any.dtotal ? '<td>' + (combatlog.pdealt[type] || combatlog.mdealt[type] ?
(combatlog.pdealt[type] + combatlog.mdealt[type]).toLocaleString() : '') + '</td>' : '') +
(any.ptaken ? '<td>' + (combatlog.ptaken[type] ? combatlog.ptaken[type].toLocaleString() : '') + '</td>' : '') +
(any.pspirit ? '<td>' + (combatlog.ptaken['s'+type] ? combatlog.ptaken['s'+type].toLocaleString() : '') + '</td>' : '') +
(any.mtaken ? '<td>' + (combatlog.mtaken[type] ? combatlog.mtaken[type].toLocaleString() : '') + '</td>' : '') +
(any.mspirit ? '<td>' + (combatlog.mtaken['s'+type] ? combatlog.mtaken['s'+type].toLocaleString() : '') + '</td>' : '') +
(any.ttotal ? '<td>' + (combatlog.ptaken[type] || combatlog.mtaken[type] ?
(combatlog.ptaken[type] + combatlog.mtaken[type]).toLocaleString() : '') + '</td>' : ''); };
var total = { pdealt: Column('pdealt', ''), mdealt: Column('mdealt', ''),
ptaken: Column('ptaken', ''), pspirit: Column('ptaken', 's'),
mtaken: Column('mtaken', ''), mspirit: Column('mtaken', 's'),
pdnone: ColumnNone('pdealt'), mdnone: ColumnNone('mdealt'),
ptnone: ColumnNone('ptaken'), mtnone: ColumnNone('mtaken'), };
total.dealt = total.pdealt + total.mdealt;
total.taken = total.ptaken + total.pspirit + total.mtaken + total.mspirit;
total.dnone = total.pdnone + total.mdnone;
total.tnone = total.ptnone + total.mtnone;
var damagelog = log.parentNode.insertBefore(document.createElement('table'), log);
damagelog.id = 'damagelog';
damagelog.innerHTML = '<tbody><tr><td></td>' +
(any.pdealt || any.mdealt ? '<td' + (any.dtotal ? ' colspan="3"' : '') + '>damage dealt</td>' : '') +
(any.ptaken || any.mtaken ? '<td' + (any.ttotal ? ' colspan="' +
((any.ptaken ? 1 : 0) + (any.mtaken ? 1 : 0) + (any.pspirit ? 1 : 0) + (any.mspirit ? 1 : 0) + 1) + '"' : '') + '>damage taken</td>' : '') +
'</tr><tr><td></td>' +
(any.pdealt ? '<td>physical</td>' : '') + (any.mdealt ? '<td>magical</td>' : '') +
(any.dtotal ? '<td>total</td>' : '') +
(any.ptaken ? '<td>physical</td>' : '') + (any.pspirit ? '<td style="border-left:none">spirit</td>' : '') +
(any.mtaken ? '<td>magical</td>' : '') + (any.mspirit ? '<td style="border-left:none">spirit</td>' : '') +
(any.ttotal ? '<td>total</td>' : '') +
Row('fire') + Row('cold') + Row('elec') + Row('wind') + Row('holy') + Row('dark') + Row('crushing') + Row('slashing') + Row('piercing') + Row('void') + Row('dot') +
'</tr><tr><td>total</td>' +
(any.pdealt ? '<td>' + total.pdealt.toLocaleString() + '</td>' : '') + (any.mdealt ? '<td>' + total.mdealt.toLocaleString() + '</td>' : '') +
(any.dtotal ? '<td>' + total.dealt.toLocaleString() + '</td>' : '') +
(any.ptaken ? '<td>' + total.ptaken.toLocaleString() + '</td>' : '') + (any.pspirit ? '<td>' + total.pspirit.toLocaleString() + '</td>' : '') +
(any.mtaken ? '<td>' + total.mtaken.toLocaleString() + '</td>' : '') + (any.mspirit ? '<td>' + total.mspirit.toLocaleString() + '</td>' : '') +
(any.ttotal ? '<td>' + total.taken.toLocaleString() + '</td>' : '') +
(any.hit ? '</tr><tr style="border-top:1px solid">' + Count('hit') + '</tr><tr>' + Count('crit') +
(any.r50 ? '</tr><tr>' + Count('r50') : '') + (any.r75 ? '</tr><tr>' + Count('r75') : '') + (any.r90 ? '</tr><tr>' + Count('r90') : '') : '') +
(any.none ? '</tr><tr style="border-top:1px solid">' + (any.miss ? '</tr><tr>' + Count('miss') : '') + (any.evade ? '</tr><tr>' + Count('evade') : '') +
(any.parry ? '</tr><tr>' + Count('parry') : '') + (any.resist ? '</tr><tr>' + Count('resist') : '') + (any.block ? '</tr><tr>' + Count('block') : ''): '') +
(any.none ? '</tr><tr><td>total</td>' +
(any.pdealt ? '<td>' + total.pdnone.toLocaleString() + '</td>' : '') + (any.mdealt ? '<td>' + total.mdnone.toLocaleString() + '</td>' : '') +
(any.dtotal ? '<td>' + total.dnone.toLocaleString() + '</td>' : '') +
(any.ptaken ? '<td>' + total.ptnone.toLocaleString() + '</td>' : '') + (any.pspirit ? '<td></td>' : '') +
(any.mtaken ? '<td>' + total.mtnone.toLocaleString() + '</td>' : '') + (any.mspirit ? '<td></td>' : '') +
(any.ttotal ? '<td>' + total.tnone.toLocaleString() + '</td>' : '') : '') + '</tr></tbody>'; }
function ShowUsage() {
if ( !cfg.trackUsage || JSON.stringify(combatlog.used) == '{}' ) return;
var td = log.insertBefore(document.createElement('tbody'), log.firstChild).appendChild(document.createElement('tr')).appendChild(document.createElement('td'));
td.className = 'tlb';
td.innerHTML = 'Used: ' + JSON.stringify(combatlog.used).replace('{','').replace('}','').replace(/"/g,'').replace(/:/g,': ').replace(/,/g,', '); }
function NoPopup() {
var btcp;
if ( !(btcp = document.getElementById('btcp')) ) return;
if ( cfg.ajaxRound ) {
btcp.onclick = function() {
var x = new XMLHttpRequest();
x.onreadystatechange = function() {
if ( x.readyState == XMLHttpRequest.DONE ) {
if ( x.status == 200 ) {
var doc = (new DOMParser()).parseFromString(x.responseText, 'text/html');
document.body.innerHTML = doc.body.innerHTML;
var script = document.createElement('script');
script.type = 'text/javascript';
if ( doc.getElementById('riddlemaster') ) {
script.innerHTML = document.getElementsByTagName('script')[2].innerHTML.replace(
'e("riddleanswer").value = "?";', '').replace('e("riddleform").submit();', ''); }
else {
script.innerHTML = 'var t = setTimeout(function(){}, 0); for ( var i = t; i > 0' +
(cfg.ajaxIntervals ? ' && i > t - ' + cfg.ajaxIntervals : '') +
'; i-- ) clearInterval(i); battle = new Battle();'; }
document.getElementById('mainpane').appendChild(script);
var event = new Event('DOMContentLoaded');
document.dispatchEvent(event); }
else {
alert('error during round transition: code ' + x.status); }}};
x.open('GET', document.location.href, true);
x.send(); };}
monsterData = {};
localStorage.removeItem('HVmonsterData');
if ( cfg.showRound ) {
timelog.round++; }
if ( cfg.noPopup && (!cfg.stopOnEquipDrop || !regexp.quality[cfg.equipmentCutoff].test(log.innerHTML)) ) {
btcp.click(); }
else {
btcp.setAttribute('style', 'display: block'); }}
// main function running out of combat
function OutOfCombat() {
DeleteLog();
ProfileSwitch();
SettingsLink(); }
// out-of-combat helper functions
function DeleteLog() {
localStorage.removeItem('HVmonsterData' + isekai);
localStorage.removeItem('HVtimelog' + isekai);
localStorage.removeItem('HVvitals' + isekai);
localStorage.removeItem('HVcursor' + isekai);
if ( cfg.deleteDropLog == 2 || (cfg.deleteDropLog == 1 && document.URL.indexOf('Battle') < 0) ) {
localStorage.removeItem('HVtrackdrops' + isekai); }
if ( cfg.deleteCombatLog == 2 || (cfg.deleteCombatLog == 1 && document.URL.indexOf('Battle') < 0) ) {
localStorage.removeItem('HVcombatlog' + isekai); }}
function ProfileSwitch() {
if ( !cfg.profileAutoswitch ) return;
var choice;
if ( (choice = document.querySelector('[name="persona_set"] [selected]')) ) {
profile[(isekai ? 'i' : '') + 'p'] = choice.value; }
if ( (choice = document.querySelector(['[src*="equip/set"][src$="_on.png"]'])) ) {
profile[(isekai ? 'i' : '') + 's' + profile[(isekai ? 'i' : '') + 'p']] = parseInt(choice.src.match(regexp.number)); }
if ( JSON.stringify(profile) != localStorage.HVmbp ) {
localStorage.HVmbp = JSON.stringify(profile); }}
function SettingsLink() {
var character;
if ( !cfg.cfgInterface || !(character = document.getElementById('child_Character')) ) return;
var div = character.firstChild.appendChild(document.createElement('div')),
link = div.appendChild(document.createElement('div')),
def = regexp.defaultletter.test(character.innerHTML);
document.head.appendChild(document.createElement('style')).innerHTML = '#mbsettings { cursor: pointer; }' +
'#mbsettings:hover #mbprofile { visibility: visible; } #mbprofile { visibility: hidden; position: relative; left: ' + (def ? '223' : '175') +
'px; top: -' + (def ? '9' : '25') + 'px; display: block; width: max-content; height: max-content; padding: 5px; background: #EDEBDF; border: 1px solid #5C0D11; }';
div.id = 'mbsettings';
link.onclick = Settings;
link.className = def ? 'fl f4b' : 'fc4 fal fcb';
if ( def ) {
character.style.width = '228px';
link.appendChild(document.createElement('div')).className = 'c5m';
link.appendChild(document.createElement('div')).className = 'c5o';
link.appendChild(document.createElement('div')).className = 'c5n';
link.appendChild(document.createElement('div')).className = 'c5s';
link.appendChild(document.createElement('div')).className = 'c5t';
link.appendChild(document.createElement('div')).className = 'c5e';
link.appendChild(document.createElement('div')).className = 'c5r';
link.appendChild(document.createElement('div')).className = 'c5b';
link.appendChild(document.createElement('div')).className = 'c5a';
link.appendChild(document.createElement('div')).className = 'c5t';
link.appendChild(document.createElement('div')).className = 'c5i';
link.appendChild(document.createElement('div')).className = 'c5o';
link.appendChild(document.createElement('div')).className = 'c5n';
link.appendChild(document.createElement('div')).className = 'c59';
link.appendChild(document.createElement('div')).className = 'c5s';
link.appendChild(document.createElement('div')).className = 'c5e';
link.appendChild(document.createElement('div')).className = 'c5t';
link.appendChild(document.createElement('div')).className = 'c5t';
link.appendChild(document.createElement('div')).className = 'c5i';
link.appendChild(document.createElement('div')).className = 'c5n';
link.appendChild(document.createElement('div')).className = 'c5g';
link.appendChild(document.createElement('div')).className = 'c5s'; }
else {
link.appendChild(document.createElement('div')).innerHTML = 'Monsterbation Settings'; }
var hasper = regexp.profile.test(JSON.stringify(cfg.persona));
var hasisk = regexp.profile.test(JSON.stringify(cfg.isekai.persona)) || (hasper && cfg.isekaiInherit);
if ( (!isekai && hasper) || (isekai && hasisk) ) {
var menu = div.appendChild(document.createElement('div'));
const Set = function(i, p, s) {
return function() {
var blue;
if ( (blue = menu.querySelector('[style*="' + (isekai ? 'red' : 'blue') + '"')) ) {
blue.style.color = ''; }
profile[isekai + 'p'] = p;
if (p) {
profile[isekai + 's' + profile[isekai + 'p']] = s; }
if ( JSON.stringify(profile) != localStorage.HVmbp ) {
localStorage.HVmbp = JSON.stringify(profile); }
i.style.color = isekai ? 'red' : 'blue'; };};
menu.id = 'mbprofile';
menu.className = 'fc4 fal fcb';
var base = menu.appendChild(document.createElement('div')), blue = false;
base.onclick = Set(base, 0, 0);
if ( !isekai ) {
base.innerHTML = cfg.name;
for ( var i = 0; i < cfg.persona.length; i++ ) {
if ( regexp.profile.test(JSON.stringify(cfg.persona[i])) ) {
var persona = menu.appendChild(document.createElement('div'));
persona.innerHTML = '- ' + cfg.persona[i].name;
persona.onclick = Set(persona, i+1, 0);
for ( var j = 0; j < cfg.persona[i].set.length; j++ ) {
if ( regexp.profile.test(JSON.stringify(cfg.persona[i].set[j])) ) {
var set = menu.appendChild(document.createElement('div'));
set.innerHTML = '-- ' + cfg.persona[i].set[j].name;
set.onclick = Set(set, i+1, j+1);
if ( profile.p == i+1 && profile['s' + profile.p] == j+1 ) {
set.style.color = 'blue';
blue = true; }}}
if ( profile.p == i+1 && (!blue || profile['s' + profile.p] == 0) ) {
persona.style.color = 'blue';
blue = true; }}}
if ( !blue || profile.p == 0 ) {
base.style.color = 'blue'; }}
else {
base.innerHTML = cfg.isekai.name;
for ( i = 0; i < cfg.isekai.persona.length; i++ ) {
hasisk = regexp.profile.test(JSON.stringify(cfg.isekai.persona[i]));
hasper = regexp.profile.test(JSON.stringify(cfg.persona[i])) && cfg.isekaiInherit;
if ( hasisk || hasper ) {
persona = menu.appendChild(document.createElement('div'));
persona.innerHTML = '- ' + (hasisk ? cfg.isekai.persona[i].name : cfg.persona[i].name);
persona.onclick = Set(persona, i+1, 0);
for ( j = 0; j < cfg.isekai.persona[i].set.length; j++ ) {
hasisk = regexp.profile.test(JSON.stringify(cfg.isekai.persona[i].set[j]));
hasper = regexp.profile.test(JSON.stringify(cfg.persona[i].set[j])) && cfg.isekaiInherit;
if ( hasisk || hasper ) {
set = menu.appendChild(document.createElement('div'));
set.innerHTML = '-- ' + (hasisk ? cfg.isekai.persona[i].set[j].name : cfg.persona[i].set[j].name);
set.onclick = Set(set, i+1, j+1);
if ( profile.ip == i+1 && profile['is' + profile.ip] == j+1 ) {
set.style.color = 'red';
blue = true; }}}
if ( profile.ip == i+1 && (!blue || profile['is' + profile.ip] == 0) ) {
persona.style.color = 'red';
blue = true; }}}
if ( !blue || profile.ip == 0 ) {
base.style.color = 'red'; }}}}
function LoadCfg(p, s, i) {
var local, value;
if ( settings.cfgInterface && (local = localStorage.HVmbcfg) ) {
local = JSON.parse(local); }
var persona = local && local.persona ? local.persona : settings.persona;
var isk = local && local.isekai ? local.isekai : settings.isekai;
for ( var setting in settings ) {
cfg[setting] = i && p && s && ((value = isk.persona[p-1].set[s-1].settings[setting]) || value === false || value === 0) ? value :
((!i || cfg.isekaiInherit) && p && s && ((value = persona[p-1].set[s-1].settings[setting]) || value === false || value === 0) ? value :
(i && p && ((value = isk.persona[p-1].settings[setting]) || value === false || value === 0) ? value :
((!i || cfg.isekaiInherit) && p && ((value = persona[p-1].settings[setting]) || value === false || value === 0) ? value :
(i && ((value = isk.settings[setting]) || value === false || value === 0) ? value :
(local && ((value = local[setting]) || value === false || value === 0) ? value : settings[setting])))));
if ( typeof(settings[setting]) == 'object' && !(settings[setting] instanceof Array) ) {
for ( var item in settings[setting] ) {
if ( !cfg[setting][item] && !(cfg[setting][item] === false) ) {
cfg[setting][item] = settings[setting][item]; }}}}
cfg.bind = cfg.bind.replace(regexp.whitespace,''); }
function StoreTmp() {
if ( (cfg.showMonsterHP || cfg.shortenHPbars || cfg.monsterKeywords) && JSON.stringify(monsterData) != '{}' ) {
localStorage['HVmonsterData' + isekai] = JSON.stringify(monsterData); }
if ( cfg.showCooldowns || cfg.trackSpeed || cfg.showRound ) {
localStorage['HVtimelog' + isekai] = JSON.stringify(timelog); }
if ( cfg.trackDamage || cfg.trackUsage ) {
localStorage['HVcombatlog' + isekai] = JSON.stringify(combatlog); }
if ( cfg.maxVitals && JSON.stringify(vitals) != localStorage['HVvitals' + isekai] ) {
localStorage['HVvitals' + isekai] = JSON.stringify(vitals); }
if ( cfg.trackDrops || cfg.trackProficiency || cfg.proficiencySidebar ) {
localStorage['HVtrackdrops' + isekai] = JSON.stringify(droplog); }
if ( cursor >= 0 ) localStorage['HVcursor' + isekai] = cursor; }
// default font parser
function ParseDefault(div) {
var string = '', letters = div.innerHTML.match(regexp.defaultstring);
for ( var j = 0; j < letters.length; j++ ) {
string += letters[j].match(regexp.defaultletter)[1]; }
return string; }
if ( !profile.p ) { profile.p = 0; }
if ( !profile.ip ) { profile.ip = 0; }
for ( var i = 1; i < 10; i++ ) {
if ( !profile['s' + i] ) { profile['s' + i] = 0; }
if ( !profile['is' + i] ) { profile['is' + i] = 0; }}
if ( !droplog.Mats ) { droplog.Mats = {}; }
LoadCfg(profile[isekai + 'p'], profile[isekai + 's' + profile[isekai + 'p']], isekai);
if ( document.getElementById('textlog') || document.getElementById('riddlemaster') ) {
Enhance();
document.addEventListener('DOMContentLoaded', Enhance);
window.addEventListener('beforeunload', StoreTmp); }
else { OutOfCombat(); }