Hentaiverse Monsterbation

M-M-M-MONSTERBATE!!

  1. // ==UserScript==
  2. // @name Hentaiverse Monsterbation
  3. // @namespace hvmonsterbate
  4. // @version 1.4.1.1
  5. // @description M-M-M-MONSTERBATE!!
  6. // @match *://*.hentaiverse.org/*
  7. // @exclude *hentaiverse.org/equip/*
  8. // @grant none
  9. // ==/UserScript==
  10.  
  11. // vvv SETTINGS vvv //
  12.  
  13. const settings = {
  14. cfgInterface: true, // add link under character to configure settings
  15. profileAutoswitch: true, // automatically switch profile when changing persona or equipment set
  16. isekaiInherit: true, // use persistent persona/equipment profiles in isekai
  17.  
  18. // ui settings
  19. cfgButton: true, // show button to access settings and switch profiles during battle
  20. mpboost: 100, spboost: 100, // set to match player stats. add up all bonuses from abilities and capacitor
  21. mppot: 75, sppot: 75, // set to percentages restored by mana/spirit potions
  22. showCooldowns: true, // show cooldowns on the quickbar
  23. effectsAboveMonsters: false, // move player effects to above monsters
  24. vitalsAboveMonsters: false, // move vitals and spirit button to above monsters
  25. quickbarBesideMonsters: false, // move quickbar to the right of monsters
  26. riddleRight: false, // shrink riddlemaster to the right
  27. condenseLeft: false, // activate the above four options with everything moved to the left
  28. compactQuickbar: false, // eliminate whitespace on quickbar and monster bars
  29. expireNoblink: false, // disable blinking of expiring effects
  30. showDurations: true, // show effect durations
  31. stackBorder: true, // show effect stacks as border thickness rather than numbers
  32. alertColours: true, // change background colours according to alert conditions
  33. alertBackground: false, // whole background instead of relevant area for alert colours
  34. alertBuffs: '/(healthpot.png|manapot.png|scroll.png|infusion.png|regen.png|heartseeker.png|arcanemeditation.png)/',
  35. // change colour of player effects area if any of these buffs has less than 2 turns left
  36. // add the icon filename of any critical buff. this also affects stopOnBuffsExpiring
  37. // to get the filename, activate the buff in battle, right click its icon and inspect element
  38. // some examples: spiritpot.png darkinfusion.png protection_scroll.png flowers.png gum.png
  39. // spiritshield.png sparklife.png shadowveil.png haste.png protection.png
  40. colours: { default: '#EDEBDF', // alert colours
  41. spark: 'magenta', // set to any valid html colour, or false to disable
  42. lowhp: 'deeppink',
  43. lowmp: 'darkslateblue',
  44. lowsp: 'indigo',
  45. ocfull: 'mediumspringgreen',
  46. expiring: 'lightblue',
  47. channelling: 'aquamarine',
  48. usable: 'mediumspringgreen',
  49. miss: 'gray', // log colours
  50. damage: 'red',
  51. item: '#00B000',
  52. attack: 'blue',
  53. spell: 'darkslateblue',
  54. recovery: 'mediumseagreen',
  55. effect: 'seagreen',
  56. spirit: 'indigo',
  57. proficiency: 'darkolivegreen',
  58. monster: 'springgreen', // monsters that match your keywords
  59. stun: 'darkseagreen', // stunned monsters, set to false to disable
  60. imperil: 'lightsteelblue', // imperilled monsters
  61. stunimperil: 'cadetblue' }, // stunned and imperilled monsters
  62. usableBlink: true, // mana and spirit gems and potions on the quickbar blink when usable to their full effect
  63. logColours: false, // add colour highlights to the battle log
  64. turnDividers: false, // add horizontal row between turns
  65. logPasteover: false, // add last turn of previous round to new round log. requires ajaxRound
  66. hideLog: false, // hide the battle log
  67. maxVitals: false, // show maximum player vitals
  68. showMonsterHP: false, // display current and max hp of monsters
  69. shortenHPbars: false, // shorten monster hp bars relative to their max hp
  70. monsterNumbers: false, // show monster numbers instead of letters
  71. monsterInfo: true, // show monster data from decondelite's database
  72. monsterKeywords: false, // highlight monsters where the name, id or max hp match this expression, set to false to disable
  73. // example: '/(Meiling|MID=70699|HP=243060)/'
  74. ajaxRound: true, // advance to next round using ajax. set to false if you use other scripts that do not support this
  75. ajaxIntervals: 100, // set to 0 or a higher number if you experience weird flashing of expiring effects
  76. noPopup: true, // skip end of round popup
  77. stopAtBattleEnd: true, // do not dismiss popup at end of battle
  78. stopOnEquipDrop: false, // do not dismiss popup if equipment drops, quality specified by cutoff below
  79. clickableRiddlemaster: true, // add links to the riddlemaster to directly submit an answer
  80. edConfirm: false, // ask for confirmation before using energy drink
  81. fleeConfirm: false, // ask for confirmation before fleeing
  82. raiseGem: false, // raise gem icon above quickbar
  83. hoverGem: false, // activate gem by hovering over the icon
  84. hoverSpirit: false, // activate spirit stance by hovering over the icon
  85. quickbarExtend: [ 1,'ikey_1','ikey_2','ikey_3','ikey_4','ikey_7','ikey_8','ikey_9','ikey_10',
  86. 'ikey_s1','ikey_s2','ikey_s4','ikey_n1','ikey_n5','ikey_n6','ikey_6','ikey_5' ],
  87. // ID for skills/spells/items (in quotes), 0 for space, 1 for gem
  88. // set to [1] if you just want the gem icon or [] to disable
  89. // IDs:
  90. // 1001 Flee 1011 Scan 1101 FUS RO DAH 1111 Orbital Friendship Cannon
  91. // 2201 Shield Bash 2202 Vital Strike 2203 Merciful Blow
  92. // 2301 Great Cleave 2302 Rending Blow 2303 Shatter Strike
  93. // 2401 Iris Strike 2402 Backstab 2403 Frenzied Blows
  94. // 2101 Skyward Sword 2501 Concussive Strike
  95. // 111 Fiery Blast 112 Inferno 113 Flames of Loki
  96. // 121 Freeze 122 Blizzard 123 Fimbulvetr
  97. // 131 Shockblast 132 Chained Lightning 133 Wrath of Thor
  98. // 141 Gale 142 Downburst 143 Storms of Njord
  99. // 151 Smite 152 Banishment 153 Paradise Lost
  100. // 161 Corruption 162 Disintegrate 163 Ragnarok
  101. // 211 Drain 212 Weaken 213 Imperil
  102. // 221 Slow 222 Sleep 223 Confuse
  103. // 231 Blind 232 Silence 233 MagNet
  104. // 311 Cure 312 Regen 313 Full-Cure
  105. // 411 Protection 412 Haste 413 Shadow Veil
  106. // 421 Absorb 422 Spark of Life 423 Spirit Shield
  107. // 431 Heartseeker 432 Arcane Focus
  108. // ikey_1-ikey_15 items ikey_s1-ikey_s6 scrolls ikey_n1-ikey_n6 infusions
  109.  
  110. // mouse binding and hover settings
  111. // it is best to use mouse bindings in conjunction with hoverArea, as mouse actions always target the whole monster
  112. clickEverywhere: false, // by default, click actions are only performed when the cursor is over a live monster
  113. // setting this to true will enable middle and right click bindings and disable the context menu everywhere
  114. wheelEverywhere: false, // same as above, but for the wheel
  115. mouseEngage: false, // hold mouse buttons to modify hover behaviour, rather than performing the bound action only once
  116. clickLeft: false, // unused. set to "Nothing" to attack with mouseEngage
  117. clickMiddle: "Cast('Scan')",
  118. clickRight: "Strongest([Cast('FUS RO DAH'), Cast('Orbital Friendship Cannon'), Cast('Ragnarok'), Cast('Disintegrate'), Cast('Corruption')])",
  119. wheelUp: "Impulse(Cast('Imperil'))",
  120. wheelDown: "Impulse(Cast('Weaken'))",
  121. wheelLeft: "Impulse(Strongest([Cast('Silence'), Cast('Sleep')]))",
  122. wheelRight: "Impulse(Strongest([Cast('Vital Strike'), Cast('Frenzied Blows'), Cast('MagNet')]))",
  123. hoverAction: "Nothing", // Attack
  124. hoverShiftAction: "Strongest([Cast('Ragnarok'), Cast('Disintegrate'), Cast('Corruption')])", // alternate hover action when holding shift
  125. hoverCtrlAction: "Strongest([Cast('Paradise Lost'), Cast('Banishment'), Cast('Smite')])", // alternate hover action when holding ctrl
  126. hoverAltAction: "Strongest([Cast('Flames of Loki'), Cast('Inferno'), Cast('Fiery Blast')])", // alternate hover action when holding alt
  127. // these can be set to any bindable action that can be followed up with targeting a monster,
  128. // as explained in the keybind section, or to false to disable
  129. // examples:
  130. // hoverAction: false, // disable hover
  131. // hoverAction: "Nothing", // attack
  132. // hoverAction: "Strongest([Cast('Ragnarok'), Cast('Disintegrate'), Cast('Corruption')])", // dark spell rotation
  133. // hoverShiftAction: "Strongest([ToggleHover, Cast('Imperil')])", // single cast of imperil
  134. // with the above example, you can hold shift, hover and hit Z to cast imperil while being protected by the usual hover safeguards
  135. hoverArea: 6, // part of the monster that activates hover
  136. // 1: whole box, 2: icon, 3: name, 4: vitals, 6: status effects
  137.  
  138. // hoverplay interrupt settings
  139. startRoundWithHover: true, // have hoverplay active at the beginning of each round
  140. // or require a kepress to start, in case you want to imperil first
  141. hoverAutoresume: false, // reactivate hover after releasing any key
  142. minHP: 0.3,
  143. minMP: 0.1,
  144. minSP: 'auto', // formula when set to 'auto': 0.5-0.5*spboost/(spboost+100)
  145. stopOnEmergency: true, // sparked or low vitals
  146. stopOnBuffsExpiring: true, // critical buff expiring in 1 turn or less
  147.  
  148. // mobile settings
  149. clearRound: false, // clear target and reset hoverAction at round transition, to avoid lingering taps and make monsterBar safer
  150. spacedBar: false, // increase spacing of quickbar and monster bar
  151. monsterBar: [], // add skill/spell icons next to monsters, for single use or tap to engage/tap elsewhere to disengage, single skills and spell rotations
  152. // example: first parameter is false for single use or true to engage, followed by skill/spell IDs or leave empty for attack
  153. // monsterBar: [ [true], // engage attack
  154. // [false,'213'], // single cast of imperil
  155. // [false,'212'], // single cast of weaken
  156. // [true,'163','162','161'] ], // engage dark spell rotation
  157.  
  158. // tracking settings
  159. trackDrops: true, // show total numbers of drops and exp at end of battle
  160. detailedDroplog: true, // list each drop type individually, excluding crystals and equipment below your quality cutoff
  161. detailedCrystlog: false, // list each crystal type individually
  162. equipmentCutoff: 3, // 0 to track all equipment combined,
  163. // 1 to track Peerless separateley,
  164. // 2 to track Peerless and Legendary separateley, etc.
  165. selectLog: false, // limit end-of-battle onclick to icon, allowing for easier selecting of log
  166. terseLog: false, // format log for easier pasting into spreadsheets
  167. trackProficiency: false, // show total proficiency gains at end of battle
  168. proficiencySidebar: false, // show live proficiency gains during battle
  169. profbarInMainpane: false, // set to false to avoid overlap with showMonsterHP
  170. deleteDropLog: 2, // delete drop log, 0: never, 1: when navigating away from battle section, 2: at end of battle
  171. dropFontSize: 100, // adjust font size of drop and proficiency log
  172. trackSpeed: true, // show turn count and speed statistic at end of battle
  173. speedFontSize: 100, // adjust font size of speed statistic
  174. trackDamage: true, // show damage dealt and taken at end of battle
  175. damageFontSize: 100, // adjust font size of damage log
  176. trackUsage: true, // show attack/skill/spell/item usage at end of battle
  177. deleteCombatLog: 2, // delete damage and usage logs, 0: never, 1: when navigating away from battle section, 2: at end of battle
  178. consoleLog: false, // output raw machine-readable log data to console when showing the drop log
  179. showRound: true, // show the current round number during battle
  180. bigRoundCounter: false, // bigger round counter, placed in top right
  181.  
  182. // key bindings
  183. bind: "\
  184. Bind(KEY_SPACE, Any, Strongest([Cast('Cure'), HoverAction(Cast('Cure'), true)]));\
  185. Bind(KEY_Z, Any, ToggleHover);\
  186. Bind(KEY_S, Any, Impulse(Toggle('Spirit')));\
  187. Bind(KEY_A, Strongest([Use(4), Cast('Full-Cure'), Cast('Cure')]));\
  188. Bind(KEY_A, Shift, Strongest([Use(7), Use(4), Cast('Full-Cure'), Cast('Cure')]));\
  189. Bind(KEY_A, Ctrl, Strongest([Use(7), Use(4), Cast('Full-Cure'), Cast('Cure')]));\
  190. Bind(KEY_A, Alt, Strongest([Use(7), Use(4), Cast('Full-Cure'), Cast('Cure')]));\
  191. Bind(KEY_X, Strongest([Use('s1'), Use('s4'), Use('s2'), Use(2), Use(1)]));\
  192. Bind(KEY_X, Shift, Strongest([Use('s1'), Use('s4'), Use('s2'), Use('n6'), Use(2), Use(1)]));\
  193. Bind(KEY_X, Ctrl, Strongest([Use('s1'), Use('s4'), Use('s2'), Use('n5'), Use(2), Use(1)]));\
  194. Bind(KEY_X, Alt, Strongest([Use('s1'), Use('s4'), Use('s2'), Use('n1'), Use(2), Use(1)]));\
  195. Bind(KEY_C, Any, Cast('Regen'));\
  196. Bind(KEY_V, Any, Cast(damage));\
  197. Bind(KEY_Q, Impulse(Use(5)));\
  198. Bind(KEY_Q, Shift, Impulse(Strongest([Use(8), Use(5)])));\
  199. Bind(KEY_Q, Ctrl, Impulse(Strongest([Use(8), Use(5)])));\
  200. Bind(KEY_Q, Alt, Impulse(Strongest([Use(8), Use(5)])));\
  201. Bind(KEY_W, Any, Impulse(Use(3)));\
  202. Bind(KEY_E, Impulse(Use(6)));\
  203. Bind(KEY_E, Shift, Impulse(Strongest([Use(9), Use(6)])));\
  204. Bind(KEY_E, Ctrl, Impulse(Strongest([Use(9), Use(6)])));\
  205. Bind(KEY_E, Alt, Impulse(Strongest([Use(9), Use(6)])));\
  206. Bind(KEY_P, Settings);\
  207. Bind(KEY_1, Any, Strongest([TargetMonster(1), Cast('Imperil')]));\
  208. Bind(KEY_2, Any, Strongest([TargetMonster(4), Cast('Imperil')]));\
  209. Bind(KEY_3, Any, Strongest([TargetMonster(7), Cast('Imperil')]));\
  210. ",
  211. // Add this for as many bindings as you want:
  212. // Bind(KeyCode, Modifier, Action);\
  213. // KeyCode = From http://www.javascripter.net/faq/keycodes.htm or any of the following:
  214. // 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,
  215. // 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,
  216. // KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0,
  217. // KEY_SPACE, KEY_ENTER, KEY_PAGEUP, KEY_PAGEDOWN, KEY_END, KEY_HOME, KEY_LEFT, KEY_UP, KEY_RIGHT, KEY_DOWN,
  218. // KEY_F1, KEY_F2, KEY_F3, KEY_F4, KEY_F5, KEY_F6, KEY_F7, KEY_F8, KEY_F9, KEY_F10, KEY_F11, KEY_F12,
  219. // KEY_COMMA, KEY_PERIOD, KEY_SLASH, KEY_FORWARDSLASH, KEY_GRAVE, KEY_TILDE, KEY_LBRACKET, KEY_BACKSLASH,
  220. // KEY_SEMI, KEY_RBRACKET, KEY_APOSTROPHE, KEY_SHIFT, KEY_CTRL, KEY_ALT
  221. // Modifier = This is OPTIONAL. Valid mods are NoMod, Shift, Ctrl, Alt, CtrlShift, AltShift, CtrlAlt, CtrlAltShift, Any
  222. // Action = Valid actions:
  223. // Cast('Spell Name')
  224. // Spell Name.
  225. // Use('Item ID')
  226. // Valid Item IDs are 'p' for Gem, 1-15 for Items, 's1'-'s6' for Scrolls and 'n1'-'n6' for Infusions.
  227. // Toggle('Type')
  228. // Attack, Focus, Defend or Spirit.
  229. // Nothing
  230. // Use this to unbind a default key or use the default attack when targeting a monster.
  231. // TargetMonster(Number)
  232. // Targets the specified monster, starting at 0 for A up to 9 for J.
  233. // NextRound
  234. // 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.
  235. // Strongest([Action Array])
  236. // Picks the most desired action.
  237. // For targeted spells or skills, put the most desired action first.
  238. // For untargeted spells or items, put the most desired action last.
  239. // HoverAction(Action, true/false)
  240. // Point mouse at target monster, hit key to perform action, Nothing for default attack. Set second parameter to true to respect alerts.
  241. // Impulse(Action)
  242. // Perform an action once.
  243. // ToggleHover
  244. // Turn hoverplay on or off.
  245. // Drops
  246. // Show drop log.
  247. // CursorUp, CursorDown
  248. // Move the targeting cursor.
  249. // CursorTarget
  250. // Target selected monster. Use with Strongest to specify action.
  251. // CursorHover
  252. // Engage hover at cursor location.
  253. // ClearTarget
  254. // Unset hover target.
  255. // Settings.
  256. // Access configuration interface.
  257. //
  258. // Examples:
  259. // Bind(KEY_M, Shift, Use(1));\ -- Shift + M = Use Item 1
  260. // Bind(KEY_LBRACKET, Cast('WRATH OF THOR'));\ -- Case insensitive. Key [ = cast Wrath of Thor.
  261. // Bind(KEY_A, Nothing);\ -- You can unbind a default key.
  262. // Bind(KEY_I, Use('p'));\ -- I uses Powerup Gem.
  263. // Bind(KEY_F, Toggle('Focus'));\ -- Toggle focus.
  264. // Bind(KEY_S, Toggle('Spirit'));\ -- Toggle spirit stance.
  265. // Bind(KEY_T, Strongest([Cast('Ragnarok'), Cast('Disintegrate'), Cast('Corruption')]));\ -- Strongest Dark spell.
  266. // Bind(KEY_B, Strongest([Cast('Full-Cure'), Cast('Cure')]));\ -- Use available Cure spell.
  267. // Bind(KEY_N, Strongest([Use(3), Use(2), Use(1)]));\ -- Use available item.
  268. // Bind(KEY_A, HoverAction(Nothing));\ -- Attack selected monster by holding A, to be used with hoverAction = false.
  269. // Bind(KEY_I, HoverAction(Cast('Imperil')));\ -- Cast Imperil on selected monster, ignore alerts.
  270. // Bind(KEY_I, HoverAction(Strongest([ToggleHover, Cast('Imperil')]), true));\ -- Single cast of Imperil, respect alerts.
  271. // Bind(KEY_I, Impulse(Cast('Imperil'))); -- Inject Imperil into hover rotation.
  272. // Bind(KEY_1, Strongest([TargetMonster(0), Cast('Imperil')]));\ -- Cast Imperil on monster A.
  273. // Bind(KEY_Z, Any, ToggleHover);\ -- Toggle hoverplay, regardless of modifier keys.
  274. // Bind(KEY_F, Drops);\ -- Show drops.
  275. // Bind(KEY_UP, CursorUp); -- Move cursor up.
  276. // Bind(KEY_DOWN, Strongest([CursorDown, ClearTarget]));\ -- Move cursor down, stop hover.
  277. // Bind(KEY_LEFT, Strongest([CursorTarget, Cast('Imperil')]));\ -- Cast Imperil on selected monster.
  278. // Bind(KEY_RIGHT, CursorHover);\ -- Hover on selected monster, recommended use with clearRound = true.
  279.  
  280. // custom profiles
  281. // to override defaults, add elements to 'settings' sections
  282. name: '[persistent]',
  283. persona: [ { name: 'persona 1', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
  284. { name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
  285. { name: 'persona 2', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
  286. { name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
  287. { name: 'persona 3', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
  288. { name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
  289. { name: 'persona 4', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
  290. { name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
  291. { name: 'persona 5', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
  292. { name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
  293. { name: 'persona 6', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
  294. { name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
  295. { name: 'persona 7', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
  296. { name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
  297. { name: 'persona 8', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
  298. { name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
  299. { name: 'persona 9', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
  300. { name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] } ],
  301. isekai: { name: '[isekai]', settings: {},
  302. persona: [ { name: 'persona 1', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
  303. { name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
  304. { name: 'persona 2', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
  305. { name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
  306. { name: 'persona 3', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
  307. { name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
  308. { name: 'persona 4', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
  309. { name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
  310. { name: 'persona 5', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
  311. { name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
  312. { name: 'persona 6', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
  313. { name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
  314. { name: 'persona 7', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
  315. { name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
  316. { name: 'persona 8', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
  317. { name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] },
  318. { name: 'persona 9', settings: {}, set: [ { name: 'set 1', settings: {} }, { name: 'set 2', settings: {} }, { name: 'set 3', settings: {} },
  319. { name: 'set 4', settings: {} }, { name: 'set 5', settings: {} }, { name: 'set 6', settings: {} }, { name: 'set 7', settings: {} } ] } ] }
  320. };
  321.  
  322. // ^^^ SETTINGS ^^^ //
  323.  
  324. // bindable functions
  325. function Toggle(name) {
  326. return function() {
  327. var state;
  328. if ( (state = document.getElementById('ckey_' + name.toLowerCase())) ) {
  329. dummy.setAttribute('onclick', state.getAttribute('onmouseover'));
  330. dummy.click();
  331. state.click(); }};}
  332.  
  333. function Cast(name) {
  334. return function() {
  335. var spell;
  336. if ( document.getElementsByClassName('btii')[0].innerHTML != name &&
  337. (spell = document.querySelector('.bts > div[onclick][onmouseover*="\'' + name + '\'"]')) ) {
  338. dummy.setAttribute('onclick', spell.getAttribute('onmouseover'));
  339. dummy.click();
  340. spell.click(); }};}
  341.  
  342. function Use(id) {
  343. return function() {
  344. var item;
  345. if ( (item = document.getElementById('ikey_' + id)) ) {
  346. dummy.setAttribute('onclick', item.getAttribute('onmouseover'));
  347. dummy.click();
  348. item.click(); }};}
  349.  
  350. function Nothing() {}
  351.  
  352. function NextRound() { var btcp; if ( (btcp = document.getElementById('btcp')) ) btcp.click(); document.querySelector('img[src$="finishbattle.png"]').click(); }
  353.  
  354. function TargetMonster(num) { return function() { if ( monsters[num] && monsters[num].hasAttribute('onclick') ) monsters[num].click(); };}
  355.  
  356. function Strongest(actions) { return function() { var n = actions.length; while ( n-- > 0 ) actions[n](); };}
  357.  
  358. function HoverAction(action, alert) {
  359. return function() {
  360. override = action;
  361. if ( (cfg.hoverAction || override) && !interruptHover && (!alert || !interruptAlert) && monsters[target] && monsters[target].hasAttribute('onclick') ) {
  362. Hover(); }};}
  363.  
  364. function Impulse(action) {
  365. return function() {
  366. if ( done ) return;
  367. impulse = action;
  368. if ( interruptHover || interruptAlert || !monsters[target] || !monsters[target].hasAttribute('onclick') ) {
  369. action(); done = true; impulse = false; }};}
  370.  
  371. function ToggleHover() {
  372. interruptHover = !interruptHover;
  373. if ( (cfg.hoverAction || override) && !interruptHover && !interruptAlert && monsters[target] && monsters[target].hasAttribute('onclick') ) {
  374. Hover(); }}
  375.  
  376. function Drops() { ShowDrops(false); }
  377.  
  378. function CursorUp() { if ( --cursor < 0 ) cursor = 0; Cursor(); }
  379.  
  380. function CursorDown() { if ( ++cursor >= monsters.length ) cursor = monsters.length - 1; Cursor(); }
  381.  
  382. function CursorTarget() { TargetMonster(cursor)(); }
  383.  
  384. function CursorHover() { if ( cursor >= 0 ) SetTarget(cursor)(); }
  385.  
  386. function ClearTarget() { target = false; }
  387.  
  388. function Settings() {
  389. var mainpane, style, form, div, changed = false, p = 0, s = 0, isk = '', select, option, index = 0;
  390. if ( !(mainpane = document.getElementById('mainpane')) ) return;
  391. bindings = [];
  392. mainpane.innerHTML = '';
  393. if ( !document.getElementById('hvcfgstyle') ) {
  394. style = document.head.appendChild(document.createElement('style'));
  395. style.id = 'hvcfgstyle';
  396. style.innerHTML =
  397. '.mbar, #cfgbutton { display: none !important; } #mainpane { height: ' + (document.getElementById('navbar') ? '644' : '671') +
  398. 'px; overflow: auto; } #mbcfg div { display: flex; margin: 2px; } #mbcfg input { margin: 0 2px 0 0; } #mbcfg input[type="text"] { width: 30px; }' +
  399. '#mbcfgbt { display: flex; position: absolute; bottom: 0; left: 0; height: 27px; width: inherit; } #mbcfgbt select { margin: 0; }' +
  400. '#mbcfgbt div { margin: 4px 0; } #mbcfgbt input[type="checkbox"] { margin-left: 10px; } .help { cursor: pointer; }' +
  401. '.help .helptext { visibility: hidden; text-align: left; position: absolute; z-index: 2; bottom: 0; right: 0; background-color: #EDEBDF;' +
  402. 'padding: 4px; border: 1px solid #5C0D11; } .help:hover .helptext { visibility: visible; }'; }
  403. form = mainpane.appendChild(document.createElement('form'));
  404. form.id = 'mbcfg';
  405. const Change = function(i, e) {
  406. return function() {
  407. changed = true;
  408. 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)),
  409. setting = settingsData[i][0], input = form.querySelector('[name="' + setting + (e ? '-' + e : '') + '"]'), value, inputs, j, above = Above(setting);
  410. switch ( settingsData[i][1][0] ) {
  411. case 'b': prf[setting] = input.checked; break;
  412. case 'o': if ( !prf[setting] ) {
  413. prf[setting] = JSON.parse(JSON.stringify(above)); }
  414. prf[setting][e] = (value = input.value) == '' ? above[e] : (value == 'false' ? false : value); break;
  415. case 'a': prf[setting] = (value = input.value) == '' ? above : JSON.parse(value); break;
  416. case 'i': prf[setting] = (value = parseInt(input.value)) || value === 0 ? value : above; break;
  417. case 'f': prf[setting] = parseFloat(value = input.value) || parseFloat(value) === 0 ? parseFloat(value) :
  418. settingsData[i][1][1] == 's' && value != '' ? 'auto' : above; break;
  419. case 's': if ( setting.indexOf('Action') > -1 && regexp.itemuse.test(input.value) ) {
  420. alert('Fearsome powers thrust Laputa into orbit. Their dreaded empire once ruled the earth!'); return; }
  421. case 't': if ( regexp.hoveruse.test(input.value) ) {
  422. alert('Fearsome powers thrust Laputa into orbit. Their dreaded empire once ruled the earth!'); return; }
  423. prf[setting] = (value = input.value.replace(regexp.whitespace,'')) == '' ? above : value; break; }
  424. if ( (isk || p) && JSON.stringify(above) === JSON.stringify(prf[setting]) ) {
  425. if ( e ) {
  426. form.querySelector('#' + setting).parentNode.style.opacity = '0.5';
  427. inputs = form.querySelectorAll('[name*="' + setting + '-"]');
  428. for ( j = 0; j < inputs.length; j++ ) {
  429. inputs[j].parentNode.style.opacity = '0.5'; }}
  430. else {
  431. input.parentNode.style.opacity = '0.5'; }
  432. delete prf[setting]; }
  433. else {
  434. if ( e ) {
  435. form.querySelector('#' + setting).parentNode.style.opacity = '1';
  436. inputs = form.querySelectorAll('[name*="' + setting + '-"]');
  437. for ( j = 0; j < inputs.length; j++ ) {
  438. inputs[j].parentNode.style.opacity = '1'; }}
  439. else {
  440. input.parentNode.style.opacity = '1'; }}};},
  441. Load = function(d) {
  442. LoadCfg();
  443. form.innerHTML = '';
  444. var input, value;
  445. if ( d ) {
  446. input = form.appendChild(document.createElement('div')).appendChild(document.createElement('textarea'));
  447. input.name = 'dump';
  448. input.style.width = '1205px';
  449. input.style.height = '631px';
  450. input.style.resize = 'none';
  451. input.value = JSON.stringify(cfg);
  452. input.onchange = function() {
  453. changed = true;
  454. var dump = JSON.parse(input.value);
  455. for ( var setting in settings ) {
  456. cfg[setting] = (value = dump[setting]) || value === false || value === 0 ? value : settings[setting]; }
  457. var option = select.querySelector('[value="00"]');
  458. option.innerHTML = cfg.name;
  459. for ( var i = 0; i < cfg.persona.length; i++ ) {
  460. option = select.querySelector('[value="' + (i+1) + '0"]');
  461. option.innerHTML = '- ' + cfg.persona[i].name;
  462. for ( var j = 0; j < cfg.persona[i].set.length; j++ ) {
  463. option = select.querySelector('[value="' + (i+1) + (j+1) + '"]');
  464. option.innerHTML = '-- ' + cfg.persona[i].set[j].name; }}};
  465. return; }
  466. for ( var i = 0; i < settingsData.length; i++ ) {
  467. value = (s ? (isk ? cfg.isekai : cfg).persona[p-1].set[s-1].settings :
  468. (p ? (isk ? cfg.isekai : cfg).persona[p-1].settings :
  469. (isk ? cfg.isekai.settings : cfg)))[settingsData[i][0]];
  470. var none = !(value || value === false || value === 0), above = Above(settingsData[i][0]);
  471. if ( none ) {
  472. value = above; }
  473. var grey = (isk || p) && (none || JSON.stringify(value) === JSON.stringify(above)),
  474. div = form.appendChild(document.createElement('div'));
  475. div.style.opacity = grey ? '0.5' : '1';
  476. switch ( settingsData[i][1][0] ) {
  477. case 'h': div.appendChild(document.createElement('div')).innerHTML = settingsData[i][0];
  478. div.style.opacity = '1'; break;
  479. case 'b': input = div.appendChild(document.createElement('input'));
  480. input.name = settingsData[i][0];
  481. input.type = 'checkbox';
  482. input.checked = value;
  483. input.onchange = Change(i);
  484. div.appendChild(document.createElement('div')).innerHTML = settingsData[i][2]; break;
  485. case 'o': input = div.appendChild(document.createElement('div'));
  486. input.id = settingsData[i][0];
  487. input.innerHTML = settingsData[i][2];
  488. for ( var element in value ) {
  489. var dv = form.appendChild(document.createElement('div'));
  490. dv.style.opacity = grey ? '0.5' : '1';
  491. input = dv.appendChild(document.createElement('input'));
  492. input.name = settingsData[i][0] + '-' + element;
  493. input.type = 'text';
  494. input.value = value[element];
  495. if ( settingsData[i][4] ) {
  496. input.style.width = settingsData[i][4] + 'px'; }
  497. input.onchange = Change(i,element);
  498. dv.appendChild(document.createElement('div')).innerHTML = element; } break;
  499. case 'a': input = div.appendChild(document.createElement('input'));
  500. input.name = settingsData[i][0];
  501. input.type = 'text';
  502. input.value = JSON.stringify(value);
  503. input.onchange = Change(i);
  504. div.appendChild(document.createElement('div')).innerHTML = settingsData[i][2]; break;
  505. case 't': input = div.appendChild(document.createElement('textarea'));
  506. input.name = settingsData[i][0];
  507. input.rows = 30;
  508. input.style.resize = 'none';
  509. input.value = value.replace(regexp.break,';\n');
  510. input.onchange = Change(i); break;
  511. default: input = div.appendChild(document.createElement('input'));
  512. input.name = settingsData[i][0];
  513. input.type = 'text';
  514. input.value = value;
  515. input.onchange = Change(i);
  516. div.appendChild(document.createElement('div')).innerHTML = settingsData[i][2]; break; }
  517. if ( settingsData[i][4] ) {
  518. input.style.width = settingsData[i][4] + 'px'; }
  519. if ( p == 0 && settingsData[i][3] ) {
  520. var help = div.appendChild(document.createElement('div'));
  521. help.className = 'help';
  522. help.innerHTML = '?';
  523. var helptext = help.appendChild(document.createElement('span'));
  524. helptext.className = 'helptext';
  525. helptext.innerHTML = settingsData[i][3]; }}},
  526. Above = function(setting) {
  527. var value;
  528. if ( !isk ) {
  529. return s && ((value = cfg.persona[p-1].settings[setting]) || value === false || value === 0) ? value : (p ? cfg[setting] : settings[setting]); }
  530. else if ( !cfg.isekaiInherit ) {
  531. return s && ((value = cfg.isekai.persona[p-1].settings[setting]) || value === false || value === 0) ? value :
  532. (p && ((value = cfg.isekai.settings[setting]) || value === false || value === 0) ? value : cfg[setting]); }
  533. else {
  534. return s && ((value = cfg.persona[p-1].set[s-1].settings[setting]) || value === false || value === 0) ? value :
  535. (s && ((value = cfg.isekai.persona[p-1].settings[setting]) || value === false || value === 0) ? value :
  536. (p && ((value = cfg.persona[p-1].settings[setting]) || value === false || value === 0) ? value :
  537. (p && ((value = cfg.isekai.settings[setting]) || value === false || value === 0) ? value : cfg[setting]))); }},
  538. Save = function() { if ( changed ) { changed = false; localStorage.HVmbcfg = JSON.stringify(cfg); }},
  539. Exit = function() { location.href = location.href; },
  540. Reset = function() {
  541. if ( p == 0 && s == 0 && !isk && confirm('Reset to defaults?') ) {
  542. localStorage.removeItem('HVmbcfg');
  543. cfg = JSON.parse(JSON.stringify(settings));
  544. Settings(); }
  545. else if ( p == 0 && s == 0 && isk && confirm('Reset this profile?') ) {
  546. cfg.isekai.settings = {};
  547. Save();
  548. Load(); }
  549. else if ( p != 0 && confirm('Reset this profile?') ) {
  550. (s ? (isk ? cfg.isekai : cfg).persona[p-1].set[s-1] : (isk ? cfg.isekai : cfg).persona[p-1]).settings = {};
  551. Save();
  552. Load(); }},
  553. Switch = function(persona, set, ise) {
  554. if ( p === persona && s === set && isk === ise ) return true;
  555. if ( !changed || confirm('Save and change profile?') ) {
  556. Save();
  557. p = persona;
  558. s = set;
  559. isk = ise;
  560. Load();
  561. return true; }
  562. return false; };
  563. Load();
  564. if ( (div = document.getElementById('mbcfgbt')) ) {
  565. div.parentNode.removeChild(div); }
  566. div = mainpane.appendChild(document.createElement('div'));
  567. div.id = 'mbcfgbt';
  568. var button = div.appendChild(document.createElement('button'));
  569. button.innerHTML = 'Save';
  570. button.onclick = function() { Save(); Load(); };
  571. button = div.appendChild(document.createElement('button'));
  572. button.innerHTML = 'S&E';
  573. button.onclick = function() { if ( !changed || confirm('Save and exit?') ) { Save(); Exit(); }};
  574. button = div.appendChild(document.createElement('button'));
  575. button.innerHTML = 'Exit';
  576. button.onclick = function() { if ( !changed || confirm('Exit without saving?') ) { Exit(); }};
  577. button = div.appendChild(document.createElement('button'));
  578. button.innerHTML = 'Dump';
  579. button.onclick = function() { if ( !changed || confirm('Save and dump to text?') ) { Save(); Load(true); }};
  580. button = div.appendChild(document.createElement('button'));
  581. button.innerHTML = 'Reset';
  582. button.onclick = Reset;
  583. select = div.appendChild(document.createElement('select'));
  584. select.onchange = function() {
  585. if ( Switch(parseInt(select.value[0]), parseInt(select.value[1]), select.value[2] ? 'i' : '') ) {
  586. index = select.selectedIndex; }
  587. else {
  588. select.selectedIndex = index; }};
  589. option = select.appendChild(document.createElement('option'));
  590. option.value = '00';
  591. option.innerHTML = cfg.name;
  592. if ( '' + profile.p + (profile.p ? profile['s' + profile.p] : '0') == option.value ) {
  593. option.style.color = 'blue'; }
  594. for ( var i = 0; i < cfg.persona.length; i++ ) {
  595. option = select.appendChild(document.createElement('option'));
  596. option.value = (i+1) + '0';
  597. option.innerHTML = '- ' + cfg.persona[i].name;
  598. if ( '' + profile.p + (profile.p ? profile['s' + profile.p] : '0') == option.value ) {
  599. option.style.color = 'blue'; }
  600. for ( var j = 0; j < cfg.persona[i].set.length; j++ ) {
  601. option = select.appendChild(document.createElement('option'));
  602. option.value = '' + (i+1) + (j+1);
  603. option.innerHTML = '-- ' + cfg.persona[i].set[j].name;
  604. if ( '' + profile.p + (profile.p ? profile['s' + profile.p] : '0') == option.value ) {
  605. option.style.color = 'blue'; }}}
  606. option = select.appendChild(document.createElement('option'));
  607. option.value = '00i';
  608. option.innerHTML = cfg.isekai.name;
  609. if ( '' + profile.ip + (profile.ip ? profile['is' + profile.ip] : '0') + 'i' == option.value ) {
  610. option.style.color = 'red'; }
  611. for ( i = 0; i < cfg.isekai.persona.length; i++ ) {
  612. option = select.appendChild(document.createElement('option'));
  613. option.value = (i+1) + '0i';
  614. option.innerHTML = '- ' + cfg.isekai.persona[i].name;
  615. if ( '' + profile.ip + (profile.ip ? profile['is' + profile.ip] : '0') + 'i' == option.value ) {
  616. option.style.color = 'red'; }
  617. for ( j = 0; j < cfg.isekai.persona[i].set.length; j++ ) {
  618. option = select.appendChild(document.createElement('option'));
  619. option.value = '' + (i+1) + (j+1) + 'i';
  620. option.innerHTML = '-- ' + cfg.isekai.persona[i].set[j].name;
  621. if ( '' + profile.ip + (profile.ip ? profile['is' + profile.ip] : '0') + 'i' == option.value ) {
  622. option.style.color = 'red'; }}}
  623. button = div.appendChild(document.createElement('button'));
  624. button.innerHTML = 'Name';
  625. button.onclick = function() {
  626. 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)),
  627. opt = select.options[index], name;
  628. if ( (name = prompt('Name this profile?', prf.name)) && name != prf.name ) {
  629. changed = true;
  630. prf.name = name;
  631. opt.innerHTML = (p ? (s ? '-- ' : '- ') : '') + prf.name; }};
  632. button = div.appendChild(document.createElement('button'));
  633. button.innerHTML = 'Set';
  634. button.onclick = function() {
  635. select.querySelector('[style*="' + (isk ? 'red' : 'blue') + '"]').style.color = '';
  636. profile[isk + p] = p;
  637. if (p) {
  638. profile[isk + 's' + p] = s; }
  639. if ( JSON.stringify(profile) != localStorage.HVmbp ) {
  640. localStorage.HVmbp = JSON.stringify(profile); }
  641. select.querySelector('[value="' + p + s + isk + '"]').style.color = isk ? 'red' : 'blue'; };
  642. var auto = div.appendChild(document.createElement('input'));
  643. auto.name = 'profileAutoswitch';
  644. auto.type = 'checkbox';
  645. auto.checked = cfg.profileAutoswitch;
  646. auto.onchange = function() {
  647. changed = true;
  648. cfg.profileAutoswitch = auto.checked; };
  649. var help = div.appendChild(document.createElement('div'));
  650. help.className = 'help';
  651. help.innerHTML = 'auto';
  652. var helptext = help.appendChild(document.createElement('span'));
  653. helptext.className = 'helptext';
  654. helptext.innerHTML = 'automatically switch profile when changing persona or equipment set';
  655. var inherit = div.appendChild(document.createElement('input'));
  656. inherit.name = 'isekaiInherit';
  657. inherit.type = 'checkbox';
  658. inherit.checked = cfg.isekaiInherit;
  659. inherit.onchange = function() {
  660. changed = true;
  661. cfg.isekaiInherit = inherit.checked; };
  662. help = div.appendChild(document.createElement('div'));
  663. help.className = 'help';
  664. help.innerHTML = 'inherit';
  665. helptext = help.appendChild(document.createElement('span'));
  666. helptext.className = 'helptext';
  667. helptext.innerHTML = 'use persistent persona/equipment profiles in isekai'; }
  668.  
  669. // keybind helper functions
  670. function handleKeys(e) {
  671. if ( release ) {
  672. done = false;
  673. release = false; }
  674. saveKeyDown();
  675. shiftHeld = e.shiftKey;
  676. ctrlHeld = e.ctrlKey;
  677. altHeld = e.altKey;
  678. var bind;
  679. for ( var i = 0; i < bindings.length; i++ ) {
  680. bind = bindings[i];
  681. if ( e.keyCode == bind.keyCode && bind.modifier(e) ) {
  682. bind.action();
  683. return; }}
  684. loadKeyDown(); }
  685.  
  686. function handleKeyup(e) {
  687. shiftHeld = e.shiftKey;
  688. ctrlHeld = e.ctrlKey;
  689. altHeld = e.altKey;
  690. override = false;
  691. release = true;
  692. if ( cfg.hoverAutoresume ) {
  693. interruptHover = false;
  694. if ( (cfg.hoverAction || override) && !interruptAlert && monsters[target] && monsters[target].hasAttribute('onclick') ) {
  695. Hover(); }}
  696. }
  697.  
  698. function saveKeyDown() { runScript('var oldkeydown = document.onkeydown ? document.onkeydown : oldkeydown; document.onkeydown = null;'); }
  699.  
  700. function loadKeyDown() { runScript('document.onkeydown = oldkeydown;'); }
  701.  
  702. function runScript(code) {
  703. var scriptElement = document.createElement('script');
  704. scriptElement.type = 'text/javascript';
  705. scriptElement.textContent = code;
  706. document.body.appendChild(scriptElement);
  707. scriptElement.remove(); }
  708.  
  709. function Bind(key, mod, command) {
  710. if ( !command ) {
  711. command = mod;
  712. mod = NoMod; }
  713. if ( command ) {
  714. bindings.push(new Keybind(key,mod,command)); }}
  715.  
  716. function Keybind(key, mod, action) {
  717. this.keyCode = key;
  718. this.modifier = mod;
  719. this.action = action; }
  720.  
  721. function NoMod(e) { return !e.shiftKey && !e.altKey && !e.ctrlKey && !e.metaKey; }
  722. function CtrlAltShift(e) { return e.shiftKey && e.altKey && e.ctrlKey && !e.metaKey; }
  723. function CtrlShift(e) { return !e.altKey && e.shiftKey && e.ctrlKey && !e.metaKey; }
  724. function AltShift(e) { return !e.ctrlKey && e.altKey && e.shiftKey && !e.metaKey; }
  725. function CtrlAlt(e) { return !e.shiftKey && e.ctrlKey && e.altKey && !e.metaKey; }
  726. function Ctrl(e) { return e.ctrlKey && !e.shiftKey && !e.altKey && !e.metaKey; }
  727. function Shift(e) { return e.shiftKey && !e.ctrlKey && !e.altKey && !e.metaKey; }
  728. function Alt(e) { return e.altKey && !e.shiftKey && !e.ctrlKey && !e.metaKey; }
  729. function Any(e) { return !e.metaKey; }
  730.  
  731. // global variables and constants
  732. var cfg = {}, profile = JSON.parse(localStorage.HVmbp || '{}'), isekai = document.URL.indexOf('isekai') > -1 ? 'i' : '',
  733. bindings = [], gem = [], target = false, cursor = localStorage['HVcursor' + isekai] ? parseInt(localStorage['HVcursor' + isekai]) : -1,
  734. interruptHover, interruptAlert = false, hovering = false, override = false, impulse = false, done = false,
  735. release = false, shiftHeld = false, ctrlHeld = false, altHeld = false, bg, dummy = document.createElement('div'),
  736. mp = 1, sp = 1, monsters = [], monsterData = {}, log, turn, timelog = JSON.parse(localStorage['HVtimelog' + isekai] || '{ "turn":0,"action":0,"round":1,"lastuse":{} }'),
  737. 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},' +
  738. '"mdealt":{"hit":0,"crit":0,"miss":0,"evade":0,"parry":0,"resist":0,"r50":0,"r75":0,"r90":0},' +
  739. '"ptaken":{"hit":0,"shit":0,"crit":0,"scrit":0,"miss":0,"evade":0,"parry":0,"block":0,"r50":0,"r75":0,"r90":0},' +
  740. '"mtaken":{"hit":0,"shit":0,"crit":0,"scrit":0,"miss":0,"evade":0,"parry":0,"block":0,"r50":0,"r75":0,"r90":0},' +
  741. '"used":{} }'),
  742. vitals = JSON.parse(localStorage['HVvitals' + isekai] || '{ "hp":0,"mp":0,"sp":0 }'),
  743. droplog = JSON.parse(localStorage['HVtrackdrops' + isekai] ||
  744. '{ "Crystals":{}, "Equips":{}, "Mats":{}, "Artifacts":{}, "Figurines":{}, "Trophies":{}, "Consumables":{}, "Foods":{}, "proficiency":{} }'),
  745. csp = false;
  746. const damage = document.getElementById('2501') ? 'Arcane Focus' : 'Heartseeker',
  747. 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,
  748. 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,
  749. 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,
  750. 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,
  751. 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,
  752. KEY_COMMA = 188, KEY_PERIOD = 190, KEY_SLASH = 191, KEY_FORWARDSLASH = 191, KEY_GRAVE = 192, KEY_TILDE = 192, KEY_LBRACKET = 219, KEY_BACKSLASH = 220,
  753. KEY_SEMI = 186, KEY_RBRACKET = 221, KEY_APOSTROPHE = 222, KEY_SHIFT = 16, KEY_CTRL = 17, KEY_ALT = 18,
  754. regexp = { gem:/\w(\w+) Gem/, defaultgem:/\w(\w+).gem/, duration:/(x(\d))*[^\(]*, (\d+)/,
  755. monsters:/MID=\d+[^<>]+HP=\d+/g, monster:/MID=(\d+) \((.+)\) .+ HP=(\d+)/, spellicon:/, '(\w+)'/, defaultfont:/"c\d\w"/,
  756. turn:/(.+?)<tr><td class="tls">/, action:/>([^<>]+)<\/td><\/tr>(<tr><td class="tlb">Spirit Stance Exhausted<\/td><\/tr>)*<tr><td class="tls"/,
  757. zeroturn:/You use\s*\w* (Gem|Draught|Potion|Elixir|Drink|Candy|Infusion|Scroll|Vase|Gum)/, use:/You (cast|use) ([\w\s-]+)/,
  758. damage:/[^<>]+damage( \([^<>]+\))*(<\/td><\/tr><tr><td class="tlb">Your spirit shield absorbs \d+ |<|\.)/g,
  759. type:/for (\d+) (\w+) damage/, shield:/absorbs (\d+)/, strike:/(Fire|Cold|Wind|Elec|Holy|Dark|Void) Strike hits/,
  760. dot:/for (\d+) damage/, pdot:/(Bleeding Wound|Spreading Poison)/, points:/for (\d+) points of (\w+) damage/,
  761. mdmiss:/to connect./g, mdevade:/evades your spell./g, md50:/ hits [^y][^<>]+50%/g, md75:/ hits [^y][^<>]+75%/g, md90:/ hits [^y][^<>]+90%/g,
  762. 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,
  763. 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,
  764. ptevade:/(>You evade| uses [^<>]+evade the attack.)/g, ptparry:/(>You parry| uses [^<>]+parry the attack.)/g, ptblock:/(>You block| uses [^<>]+block the attack.)/g,
  765. counter:/>You counter/g, spellinfo:/\('([\w\s-]+)'.*, (\d+)\)/, crit:/(You crit| crits | blasts )/,
  766. miss:/(You evade|You block|You parry| evades | parries | resists | misses | fails )/, attack:/(You hit|You crit|Arcane Blow)/,
  767. spell:/(You cast| hits | crits | blasts |gains the effect)/, recovery:/(You are healed|Recovered | restores |You drain)/,
  768. round:/Round (\d+) \/ (\d+)/, drops: /\S+ <span style="color:.{7}">\[[^<>]+\](<\/span><\/td><\/tr><tr><td class="tlb">A t)*/g,
  769. drop:/(\S+) \<.*#(.{6}).*\[(.*)\](.)*/, crystal:/(?:(\d+)x )?Crystal/, crystals:/Crystal of (\w+)/, credit:/(\d+) Credit/, reward: /gain (\d+) Credit/,
  770. exp:/You gain (\d+) EXP/, proficiencies:/\d+\.\d+ points of [^<>]+ proficiency/g, proficiency:/(\d+\.\d+) points of ([^<>]+) proficiency/,
  771. quality:[/\[\]/,/\[Peerless/,/\[(Legendary|Peerless)/,/\[(Magnificent|Legendary|Peerless)/,/\[(Exquisite|Magnificent|Legendary|Peerless)/,
  772. /\[(Superior|Exquisite|Magnificent|Legendary|Peerless)/,/\[(Average|Superior|Exquisite|Magnificent|Legendary|Peerless)/,
  773. /\[(Fair|Average|Superior|Exquisite|Magnificent|Legendary|Peerless)/,/\[(Crude|Fair|Average|Superior|Exquisite|Magnificent|Legendary|Peerless)/],
  774. defaultstring:/"c\d\w"/g, defaultletter:/"c\d(\w)"/, whitespace:/(\s{2,}|\n)/g, break:/;/g, number:/\d+/, profile:/settings":{"/,
  775. itemuse:/Use\(/, hoveruse:/HoverAction\([^;]*Use\(/ },
  776. settingsData = [
  777. ['ui settings','h'],
  778. ['cfgButton','b','show button to access settings and switch profiles during battle'],
  779. ['mpboost','f','mp boost from abilities and capacitor'],
  780. ['spboost','f','sp boost from sp tank'],
  781. ['mppot','i','percentage of base mp restored by mana potion'],
  782. ['sppot','i','percentage of base sp restored by spirit potion'],
  783. ['showCooldowns','b','show cooldowns on the quickbar'],
  784. ['effectsAboveMonsters','b','move player effects to above monsters'],
  785. ['vitalsAboveMonsters','b','move vitals and spirit button to above monsters'],
  786. ['quickbarBesideMonsters','b','move quickbar to the right of monsters'],
  787. ['riddleRight','b','shrink riddlemaster to the right'],
  788. ['condenseLeft','b','activate the above four options with everything moved to the left'],
  789. ['compactQuickbar','b','eliminate whitespace on quickbar and monster bars'],
  790. ['expireNoblink','b','disable blinking of expiring effects'],
  791. ['showDurations','b','show effect durations'],
  792. ['stackBorder','b','show effect stacks as border thickness rather than numbers'],
  793. ['alertColours','b','change background colours according to alert conditions'],
  794. ['alertBackground','b','whole background instead of relevant area for alert colours'],
  795. ['alertBuffs','s','critical buffs',
  796. 'change colour of player effects area if any of these buffs has less than 2 turns left<br>' +
  797. 'add the icon filename of any critical buff. this also affects interrupting hover on expiring buffs<br>' +
  798. 'to get the filename, activate the buff in battle, right click its icon and inspect element',750],
  799. ['colours','o','alert and log colours','set to any valid html colour, or false to disable',120],
  800. ['usableBlink','b','mana and spirit gems and potions on the quickbar blink when usable to their full effect'],
  801. ['logColours','b','add colour highlights to the battle log'],
  802. ['turnDividers','b','add horizontal row between turns'],
  803. ['logPasteover','b','add last turn of previous round to new round log. requires round advance via ajax'],
  804. ['hideLog','b','hide the battle log'],
  805. ['maxVitals','b','show maximum player vitals'],
  806. ['showMonsterHP','b','display current and max hp of monsters'],
  807. ['shortenHPbars','b','shorten monster hp bars relative to their max hp'],
  808. ['monsterNumbers','b','show monster numbers instead of letters'],
  809. ['monsterKeywords','s','monster keywords',
  810. 'highlight monsters where the name, id or max hp match this expression, set to false to disable<br>' +
  811. 'example: /(Meiling|MID=70699|HP=243060)/',750],
  812. ['ajaxRound','b','advance to next round using ajax. set to false if you use other scripts that do not support this'],
  813. ['ajaxIntervals','i','set to 0 or a higher number if you experience weird flashing of expiring effects'],
  814. ['noPopup','b','skip end of round popup'],
  815. ['stopAtBattleEnd','b','do not dismiss popup at end of battle'],
  816. ['stopOnEquipDrop','b','do not dismiss popup if equipment drops, quality specified by cutoff below'],
  817. ['clickableRiddlemaster','b','add links to the riddlemaster to directly submit an answer'],
  818. ['edConfirm','b','ask for confirmation before using energy drink'],
  819. ['fleeConfirm','b','ask for confirmation before fleeing'],
  820. ['raiseGem','b','raise gem icon above quickbar'],
  821. ['hoverGem','b','activate gem by hovering over the icon'],
  822. ['hoverSpirit','b','activate spirit stance by hovering over the icon'],
  823. ['quickbarExtend','a','extend quickbar',
  824. 'id for skills/spells/items (in quotes), 0 for space, 1 for gem<br>' +
  825. 'set to [1] if you just want the gem icon or [] to disable<br>' +
  826. 'IDs:<br>' +
  827. '1001 Flee 1011 Scan 1101 FUS RO DAH 1111 Orbital Friendship Cannon<br>' +
  828. '2201 Shield Bash 2202 Vital Strike 2203 Merciful Blow<br>' +
  829. '2301 Great Cleave 2302 Rending Blow 2303 Shatter Strike<br>' +
  830. '2401 Iris Strike 2402 Backstab 2403 Frenzied Blows<br>' +
  831. '2101 Skyward Sword 2501 Concussive Strike<br>' +
  832. '111 Fiery Blast 112 Inferno 113 Flames of Loki<br>' +
  833. '121 Freeze 122 Blizzard 123 Fimbulvetr<br>' +
  834. '131 Shockblast 132 Chained Lightning 133 Wrath of Thor<br>' +
  835. '141 Gale 142 Downburst 143 Storms of Njord<br>' +
  836. '151 Smite 152 Banishment 153 Paradise Lost<br>' +
  837. '161 Corruption 162 Disintegrate 163 Ragnarok<br>' +
  838. '211 Drain 212 Weaken 213 Imperil<br>' +
  839. '221 Slow 222 Sleep 223 Confuse<br>' +
  840. '231 Blind 232 Silence 233 MagNet<br>' +
  841. '311 Cure 312 Regen 313 Full-Cure<br>' +
  842. '411 Protection 412 Haste 413 Shadow Veil<br>' +
  843. '421 Absorb 422 Spark of Life 423 Spirit Shield<br>' +
  844. '431 Heartseeker 432 Arcane Focus<br>' +
  845. 'ikey_1-ikey_15 items ikey_s1-ikey_s6 scrolls ikey_n1-ikey_n6 infusions',750],
  846. ['mouse binding and hover settings','h'],
  847. ['clickEverywhere','b','enable middle and right click bindings and disable the context menu everywhere'],
  848. ['wheelEverywhere','b','enable wheel bindings everywhere'],
  849. ['mouseEngage','b','hold mouse buttons to modify hover behaviour'],
  850. ['clickLeft','s','left click',
  851. 'set to false to leave at default, or Nothing to attack with the above option',750],
  852. ['clickMiddle','s','middle click',,750],
  853. ['clickRight','s','right click',,750],
  854. ['wheelUp','s','wheel up',,750],
  855. ['wheelDown','s','wheel down',,750],
  856. ['wheelLeft','s','wheel left',,750],
  857. ['wheelRight','s','wheel right',,750],
  858. ['hoverAction','s','hover action',,750],
  859. ['hoverShiftAction','s','shift hover action',,750],
  860. ['hoverCtrlAction','s','ctrl hover action',,750],
  861. ['hoverAltAction','s','alt hover action',
  862. 'these can be set to any bindable action that can be followed up with targeting a monster,<br>' +
  863. 'as explained in the keybind section, or to false to disable<br>' +
  864. 'examples:<br>' +
  865. 'hover action: false - disable hover<br>' +
  866. 'hover action: Nothing - attack<br>' +
  867. "hover action: Strongest([Cast('Ragnarok'), Cast('Disintegrate'), Cast('Corruption')]) - dark spell rotation<br>" +
  868. "shift hover action: Strongest([ToggleHover, Cast('Imperil')]) - single cast of imperil<br>" +
  869. 'with the above example, you can hold shift, hover and hit Z to cast imperil while being protected by the usual hover safeguards',750],
  870. ['hoverArea','i','part of the monster that activates hover',
  871. '1: whole box, 2: icon, 3: name, 4: vitals, 6: status effects'],
  872. ['hoverplay interrupt settings','h'],
  873. ['startRoundWithHover','b','have hoverplay active at the beginning of each round'],
  874. ['hoverAutoresume','b','reactivate hover after releasing any key'],
  875. ['minHP','f','hp threshold'],
  876. ['minMP','f','mp threshold'],
  877. ['minSP','fs','sp threshold',
  878. "formula when set to auto: 0.5-0.5*spboost/(spboost+100)"],
  879. ['stopOnEmergency','b','stop on spark or low vitals'],
  880. ['stopOnBuffsExpiring','b','stop on critical buff expiring in 1 turn or less'],
  881. ['mobile settings','h'],
  882. ['clearRound','b','clear target and reset hover action at round transition, to avoid lingering taps and make monster bar safer'],
  883. ['spacedBar','b','increase spacing of quickbar and monster bar'],
  884. ['monsterBar','a','monster bar',
  885. 'add skill/spell icons next to monsters, for single use or tap to engage/tap elsewhere to disengage, single skills and spell rotations<br>' +
  886. '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>' +
  887. '[ [true], - engage attack<br>' +
  888. " [false,'213'], - single cast of imperil<br>" +
  889. " [false,'212'], - single cast of weaken<br>" +
  890. " [true,'163','162','161'] ] - engage dark spell rotation",750],
  891. ['tracking settings','h'],
  892. ['trackDrops','b','show total numbers of drops and exp at end of battle'],
  893. ['detailedDroplog','b','list each drop type individually, excluding crystals and equipment below your quality cutoff'],
  894. ['detailedCrystlog','b','list each crystal type individually'],
  895. ['equipmentCutoff','i','equipment quality cutoff',
  896. '0 to track all equipment combined,<br>' +
  897. '1 to track Peerless separateley,<br>' +
  898. '2 to track Peerless and Legendary separateley, etc.'],
  899. ['selectLog','b','limit end-of-battle onclick to icon, allowing for easier selecting of log'],
  900. ['terseLog','b','format log for easier pasting into spreadsheets'],
  901. ['trackProficiency','b','show total proficiency gains at end of battle'],
  902. ['proficiencySidebar','b','show live proficiency gains during battle'],
  903. ['profbarInMainpane','b','proficiency sidebar in mainpane'],
  904. ['deleteDropLog','i','delete drop log, 0: never, 1: when navigating away from battle section, 2: at end of battle'],
  905. ['dropFontSize','i','adjust font size of drop and proficiency log'],
  906. ['trackSpeed','b','show turn count and speed statistic at end of battle'],
  907. ['speedFontSize','i','adjust font size of speed statistic'],
  908. ['trackDamage','b','show damage dealt and taken at end of battle'],
  909. ['damageFontSize','i','adjust font size of damage log'],
  910. ['trackUsage','b','show attack/skill/spell/item usage at end of battle'],
  911. ['deleteCombatLog','i','delete damage and usage logs, 0: never, 1: when navigating away from battle section, 2: at end of battle'],
  912. ['consoleLog','b','output raw machine-readable log data to console when showing the drop log'],
  913. ['showRound','b','show the current round number during battle'],
  914. ['bigRoundCounter','b','bigger round counter, placed in top right'],
  915. ['key bindings','h',,
  916. 'Add this for as many bindings as you want:<br>' +
  917. 'Bind(KeyCode, Modifier, Action);<br>' +
  918. ' KeyCode = From http://www.javascripter.net/faq/keycodes.htm or any of the following:<br>' +
  919. ' 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>' +
  920. ' 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>' +
  921. ' KEY_1, KEY_2, KEY_3, KEY_4, KEY_5, KEY_6, KEY_7, KEY_8, KEY_9, KEY_0,<br>' +
  922. ' KEY_SPACE, KEY_ENTER, KEY_PAGEUP, KEY_PAGEDOWN, KEY_END, KEY_HOME, KEY_LEFT, KEY_UP, KEY_RIGHT, KEY_DOWN,<br>' +
  923. ' 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>' +
  924. ' KEY_COMMA, KEY_PERIOD, KEY_SLASH, KEY_FORWARDSLASH, KEY_GRAVE, KEY_TILDE, KEY_LBRACKET, KEY_BACKSLASH,<br>' +
  925. ' KEY_SEMI, KEY_RBRACKET, KEY_APOSTROPHE, KEY_SHIFT, KEY_CTRL, KEY_ALT<br>' +
  926. ' Modifier = This is OPTIONAL. Valid mods are NoMod, Shift, Ctrl, Alt, CtrlShift, AltShift, CtrlAlt, CtrlAltShift, Any<br>' +
  927. ' Action = Valid actions:<br>' +
  928. " Cast('Spell Name')<br>" +
  929. ' Spell Name.<br>' +
  930. " Use('Item ID')<br>" +
  931. " Valid Item IDs are 'p' for Gem, 1-15 for Items, 's1'-'s6' for Scrolls and 'n1'-'n6' for Infusions.<br>" +
  932. " Toggle('Type')<br>" +
  933. ' Attack, Focus, Defend or Spirit.<br>' +
  934. ' Nothing<br>' +
  935. ' Use this to unbind a default key or use the default attack when targeting a monster.<br>' +
  936. ' TargetMonster(Number)<br>' +
  937. ' Targets the specified monster, starting at 0 for A up to 9 for J.<br>' +
  938. ' NextRound<br>' +
  939. ' 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>' +
  940. ' Strongest([Action Array])<br>' +
  941. ' Picks the most desired action.<br>' +
  942. ' For targeted spells or skills, put the most desired action first.<br>' +
  943. ' For untargeted spells or items, put the most desired action last.<br>' +
  944. ' HoverAction(Action, true/false)<br>' +
  945. ' Point mouse at target monster, hit key to perform action, Nothing for default attack. Set second parameter to true to respect alerts.<br>' +
  946. ' Impulse(Action)<br>' +
  947. ' Perform an action once.<br>' +
  948. ' ToggleHover<br>' +
  949. ' Turn hoverplay on or off.<br>' +
  950. ' Drops<br>' +
  951. ' Show drop log.<br>' +
  952. ' CursorUp, CursorDown<br>' +
  953. ' Move the targeting cursor.<br>' +
  954. ' CursorTarget<br>' +
  955. ' Target selected monster. Use with Strongest to specify action.<br>' +
  956. ' CursorHover<br>' +
  957. ' Engage hover at cursor location.<br>' +
  958. ' ClearTarget<br>' +
  959. ' Unset hover target.<br>' +
  960. ' Settings.<br>' +
  961. ' Access configuration interface.'],
  962. ['bind','t',,,750]
  963. ];
  964.  
  965. // main function triggered on page load
  966. function Enhance() {
  967. if ( document.getElementById('gay_sex') ) return;
  968. Riddlemaster();
  969. if ( !(log = document.getElementById('textlog')) ) return;
  970. if ( cfg.logPasteover && turn ) {
  971. log.firstChild.innerHTML += '<tr><td class="tls"></td></tr>' + turn; }
  972. monsters = document.getElementsByClassName('btm1');
  973. if ( cfg.alertBackground ) {
  974. csp = document.getElementById('csp'); }
  975. interruptHover = !cfg.startRoundWithHover;
  976. if ( cursor >= 0 ) ClearTarget();
  977. if ( cursor >= monsters.length ) cursor = monsters.length - 1;
  978. document.addEventListener('keydown', handleKeys, true);
  979. document.addEventListener('keyup', handleKeyup, true);
  980. if ( cfg.clearRound ) {
  981. Disengage(); }
  982. document.addEventListener('mouseover', ClearTarget, true);
  983. if ( cfg.clickEverywhere ) {
  984. document.addEventListener('mousedown', HandleClick(), true);
  985. document.addEventListener('contextmenu', function(e) { e.preventDefault(); }); }
  986. if ( cfg.wheelEverywhere ) {
  987. document.addEventListener('wheel', HandleWheel(), true); }
  988. if ( cfg.mouseEngage ) {
  989. document.addEventListener('mousedown', MouseEngage, true);
  990. document.addEventListener('mouseup', function() { override = false; release = true; }, true); }
  991. else {
  992. document.addEventListener('mouseup', function() { release = true; }, true); }
  993. var obs = new MutationObserver(Observe);
  994. obs.observe(log.firstChild, {childList: true});
  995. if ( !document.getElementById('homosex') ) {
  996. if ( (cfg.mouseEngage && (regexp.itemuse.test(cfg.clickLeft) || regexp.itemuse.test(cfg.clickMiddle) || regexp.itemuse.test(cfg.clickRight))) ||
  997. regexp.itemuse.test(cfg.hoverAction) || regexp.itemuse.test(cfg.hoverShiftAction) || regexp.itemuse.test(cfg.hoverCtrlAction) ||
  998. regexp.itemuse.test(cfg.hoverAltAction) || regexp.hoveruse.test(cfg.bind) ) {
  999. alert('You have transgressed against your God and your fellow Man. God has charged me with your redemption. ' +
  1000. '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; }
  1001. cfg.minSP = cfg.minSP == 'auto' ? 0.5-0.5*cfg.spboost/(cfg.spboost+100) : cfg.minSP;
  1002. var evals = ['alertBuffs', 'monsterKeywords', 'clickLeft', 'clickMiddle', 'clickRight', 'wheelUp', 'wheelDown', 'wheelLeft', 'wheelRight',
  1003. 'hoverAction', 'hoverShiftAction', 'hoverCtrlAction', 'hoverAltAction'];
  1004. for ( var i = 0; i < evals.length; i++ ) {
  1005. try {
  1006. cfg[evals[i]] = eval(cfg[evals[i]]); }
  1007. catch ( error ) {
  1008. cfg[evals[i]] = false;
  1009. alert('invalid ' + evals[i] + ' format. option disabled'); }}
  1010. try {
  1011. eval(cfg.bind); }
  1012. catch ( error ) {
  1013. bindings = [];
  1014. alert('invalid key bindings. option disabled'); }
  1015. var style = document.createElement('style');
  1016. style.id = 'homosex';
  1017. style.innerHTML = '.btm6 { min-width: 195px; top: 0 !important; padding: 18px 3px 3px 1px !important; }' +
  1018. (cfg.condenseLeft ? '#pane_effects { position: relative; left: -92px; } #pane_completion { left: -688px; } #battle_left { left: 550px; }' +
  1019. '#pane_vitals { position: absolute; top: 3px; left: ' + (document.querySelector('img[src$="bar_orange.png"]') ?
  1020. '-556px; } #ckey_spirit { left: -411px; top: 45px;' : '-548px; } #ckey_spirit { left: -459px; top: 2px;') +
  1021. 'position: absolute; z-index: 1; } #battle_right { left: -7px !important; top: 107px !important; }' +
  1022. '#pane_quickbar { display: flex; position: absolute; left: -212px; top: 69px; width: 203px; }' :
  1023. (cfg.effectsAboveMonsters ? '#pane_effects { max-width: 534px; position: relative; left: 596px; }' : '') +
  1024. (cfg.vitalsAboveMonsters ? '#pane_vitals { position: absolute; top: 3px; left: ' + (document.querySelector('img[src$="bar_orange.png"]') ?
  1025. '672px; } #ckey_spirit { left: 817px; top: 45px;' : '690px; } #ckey_spirit { left: 779px; top: 2px;') +
  1026. 'position: absolute; z-index: 1; } #battle_right { top: 107px !important; }' : '') +
  1027. (cfg.quickbarBesideMonsters ? '#pane_quickbar { display: flex; position: absolute; left: 1026px; top: ' + (cfg.vitalsAboveMonsters ? '69' : '4') +
  1028. 'px; width: 203px; }' : '')) + (cfg.compactQuickbar ? '.btqs { width: 30px !important; height: 32px !important; padding: 0 !important;' +
  1029. 'border: 1px solid black; } .btqs:not(.mbs):not([onmouseover]) { opacity: 0; } .btqi { left: 0 !important; top: 0 !important; }' +
  1030. '.btqs:not(.extend):not(.mbs):not([onmouseover]), .btqb { display:none; }' : '.btqi { top: 3px !important; }') +
  1031. (cfg.expireNoblink ? '#pane_effects > img, .btm6 > img { opacity: 1 !important; }' : '') +
  1032. '.effect_duration { display: inline-block; width: 30px; margin-right: -30px; position: relative; text-align: center; z-index: 1; }' +
  1033. '.effect_duration > div { display: inline-block; min-width: 16px; padding: 0 2px; background: #EDEBDF; color: black; font-weight: bold; }' +
  1034. '.effect_duration > div { border: 1px solid black; } .cooldown {' + (cfg.compactQuickbar ? 'width: 30px; margin-top: 4px;' :
  1035. 'width: 37px; margin-top: 7px;') + 'position: relative; z-index: 3; color: black; font-size: 20px; font-weight: bold; }' +
  1036. '#infopane, .bttp, .btm1 { background: ' + cfg.colours.default + '; }' + (cfg.hideLog ? '#textlog { display: none; }' : '') +
  1037. (cfg.noPopup ? '#btcp { display: none; }' : '') + '.drop { font-size: ' + cfg.dropFontSize + '%; } .speed { font-size: ' + cfg.speedFontSize + '%; }' +
  1038. '.crystal { color: #BA05B4; } .credit { color: #A89000; } .equipment { color: #FF0000; } .token { color: #254117; }' +
  1039. '.artifact { color: #0000FF; } .trophy { color: #461B7E; } .consumable { color: #00B000; } .food { color: #489EFF; } ' +
  1040. '#pane_effects, #ckey_spirit { border-radius: 5px; }' + (cfg.spacedBar ? '.btqs { margin: 0 20px 20px 0 !important; }' : '') +
  1041. (cfg.colours.usable ? '.usable { background: ' + cfg.colours.usable + ';' + (cfg.compactQuickbar ? 'border: 1px solid ' + cfg.colours.usable :
  1042. 'border-radius: 5px') + '; } .usable > .btqb { display: none; }' : '') + '.monsterhp { display: inline-block; position: relative; left: 204px; top: -20px; }' +
  1043. (cfg.usableBlink ? '@keyframes blink { 50% { opacity: 0; }} .usable > .btqi { animation: blink 1s linear infinite; }' : '') +
  1044. '#battle_right { position: absolute; left: 681px; top: 42px; width: 364px; overflow: visible; }' +
  1045. (cfg.monsterNumbers ? '.btm2 img { display: none; } .btm2 > div:nth-child(1) { font-size: 250%; }' +
  1046. '#mkey_1 > .btm2 > div:nth-child(1):after { content: "1"; } #mkey_2 > .btm2 > div:nth-child(1):after { content: "2"; }' +
  1047. '#mkey_3 > .btm2 > div:nth-child(1):after { content: "3"; } #mkey_4 > .btm2 > div:nth-child(1):after { content: "4"; }' +
  1048. '#mkey_5 > .btm2 > div:nth-child(1):after { content: "5"; } #mkey_6 > .btm2 > div:nth-child(1):after { content: "6"; }' +
  1049. '#mkey_7 > .btm2 > div:nth-child(1):after { content: "7"; } #mkey_8 > .btm2 > div:nth-child(1):after { content: "8"; }' +
  1050. '#mkey_9 > .btm2 > div:nth-child(1):after { content: "9"; } #mkey_0 > .btm2 > div:nth-child(1):after { content: "10"; }' : '') +
  1051. (cfg.colours.miss ? '.miss { color: ' + cfg.colours.miss + '; }' : '') + (cfg.colours.damage ? '.damage { color: ' + cfg.colours.damage + '; }' : '') +
  1052. (cfg.colours.item ? '.item { color: ' + cfg.colours.item + '; }' : '') + (cfg.colours.attack ? '.attack { color: ' + cfg.colours.attack + '; }' : '') +
  1053. (cfg.colours.spell ? '.spell { color: ' + cfg.colours.spell + '; }' : '') + (cfg.colours.recovery ? '.recovery { color: ' + cfg.colours.recovery + '; }' : '') +
  1054. (cfg.colours.effect ? '.effect { color: ' + cfg.colours.effect + '; }' : '') + (cfg.colours.spirit ? '.spirit { color: ' + cfg.colours.spirit + '; }' : '') +
  1055. (cfg.colours.proficiency ? '.proficiency { color: ' + cfg.colours.proficiency + '; }' : '') +
  1056. '#profbar { position: absolute; left: ' + (cfg.profbarInMainpane ? '1140' : '1240') + 'px; top: 50px; z-index: 1; }' +
  1057. '#profbar td:nth-child(1) { text-align: right; } #profbar td:nth-child(2) { text-align: left; } .mbar { display: flex; position: absolute; left: 1075px; }' +
  1058. '.mbar > div { cursor: pointer; } #cfgbutton { position: absolute; top: 686px; left: ' + (cfg.condenseLeft ? '529' : '1220') +
  1059. 'px; cursor: pointer; background: ' + cfg.colours.default + '; z-index: 3; width: 18px; height: 18px; font-size: 17px; }' +
  1060. '#cfgbutton:hover #mbprofile { visibility: visible; } #mbprofile { visibility: hidden; position: absolute; right: 0; bottom: 18px;' +
  1061. 'width: max-content; height: max-content; padding: 5px; background: ' + cfg.colours.default + '; border: 1px solid #5C0D11; }' +
  1062. '#mbar_0 { top: ' + ((cfg.showMonsterHP ? 61 : 58)+(cfg.vitalsAboveMonsters ? 65 : 0)) + 'px; }' +
  1063. '#mbar_1 { top: ' + ((cfg.showMonsterHP ? 119 : 116)+(cfg.vitalsAboveMonsters ? 65 : 0)) + 'px; }' +
  1064. '#mbar_2 { top: ' + ((cfg.showMonsterHP ? 177 : 174)+(cfg.vitalsAboveMonsters ? 65 : 0)) + 'px; }' +
  1065. '#mbar_3 { top: ' + ((cfg.showMonsterHP ? 235 : 232)+(cfg.vitalsAboveMonsters ? 65 : 0)) + 'px; }' +
  1066. '#mbar_4 { top: ' + ((cfg.showMonsterHP ? 293 : 290)+(cfg.vitalsAboveMonsters ? 65 : 0)) + 'px; }' +
  1067. '#mbar_5 { top: ' + ((cfg.showMonsterHP ? 351 : 348)+(cfg.vitalsAboveMonsters ? 65 : 0)) + 'px; }' +
  1068. '#mbar_6 { top: ' + ((cfg.showMonsterHP ? 409 : 406)+(cfg.vitalsAboveMonsters ? 65 : 0)) + 'px; }' +
  1069. '#mbar_7 { top: ' + ((cfg.showMonsterHP ? 467 : 464)+(cfg.vitalsAboveMonsters ? 65 : 0)) + 'px; }' +
  1070. '#mbar_8 { top: ' + ((cfg.showMonsterHP ? 525 : 522)+(cfg.vitalsAboveMonsters ? 65 : 0)) + 'px; }' +
  1071. '#mbar_9 { top: ' + ((cfg.showMonsterHP ? 583 : 580)+(cfg.vitalsAboveMonsters ? 65 : 0)) + 'px; }' +
  1072. (cfg.maxVitals ? '#dvrhd, #dvrhb, #dvrm, #dvrs { left: -45px; width: 100px; } #vrm { left: -63px; width: 100px; }' : '') +
  1073. '#table_magic .fc2 { font-size: 7pt; } #dropbox { position: absolute; top: 35px; left: 583px; width: 360px;' +
  1074. 'margin: 2px 0 0 15px; padding: 5px 1px 1px; border: 2px ridge #5C0D12; background: #F2EFDF; opacity: 0.95; z-index: 9; }' +
  1075. '#damagelog { border: 1px solid; border-collapse: collapse; } #damagelog tr:nth-child(1) > td, #damagelog tr:nth-child(2) > td { text-align: center; }' +
  1076. '#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: ' +
  1077. cfg.damageFontSize + '%; }';
  1078. document.head.appendChild(style); }
  1079. Gems();
  1080. Alerts();
  1081. Durations();
  1082. GetMonsterData();
  1083. Monsters();
  1084. Confirm();
  1085. ExtendQuickbar();
  1086. MonsterBar();
  1087. ShowCooldowns();
  1088. MaxVitals();
  1089. Profbar();
  1090. ShowRound();
  1091. CfgButton(); }
  1092.  
  1093. // main function triggered on new turn
  1094. function Observe() {
  1095. // check for battle end
  1096. if ( document.querySelector('img[src$="finishbattle.png"]') ) {
  1097. if ( cfg.alertColours ) {
  1098. document.getElementById(cfg.alertBackground ? 'csp' : 'pane_vitals').style.background = cfg.colours.default;
  1099. document.getElementById('pane_effects').style.background = cfg.colours.default;
  1100. document.getElementById('ckey_spirit').style.background = cfg.colours.default; }
  1101. ProcessLog();
  1102. FormatLog();
  1103. TrackDrops();
  1104. Profbar();
  1105. ShowDrops(true);
  1106. ShowUsage();
  1107. ShowDamage();
  1108. window.dispatchEvent(new CustomEvent("battleEnd", {"detail":{timelog,combatlog,droplog}}));
  1109. window.removeEventListener('beforeunload', StoreTmp);
  1110. var btcp, equip = document.querySelector('span[style$="#FF0000"]');
  1111. localStorage.removeItem('HVmonsterData' + isekai);
  1112. localStorage.removeItem('HVtimelog' + isekai);
  1113. localStorage.removeItem('HVvitals' + isekai);
  1114. localStorage.removeItem('HVcursor' + isekai);
  1115. if ( cfg.deleteDropLog == 2 ) {
  1116. localStorage.removeItem('HVtrackdrops' + isekai); }
  1117. else if ( cfg.trackDrops || cfg.trackProficiency || cfg.proficiencySidebar ) {
  1118. localStorage['HVtrackdrops' + isekai] = JSON.stringify(droplog); }
  1119. if ( cfg.deleteCombatLog == 2 ) {
  1120. localStorage.removeItem('HVcombatlog' + isekai); }
  1121. else if ( cfg.trackDamage || cfg.trackUsage ) {
  1122. localStorage['HVcombatlog' + isekai] = JSON.stringify(combatlog); }
  1123. document.getElementById('homosex').innerHTML += '.mbar, #cfgbutton { display: none !important; }';
  1124. if ( cfg.noPopup && (btcp = document.getElementById('btcp')) && !cfg.stopAtBattleEnd &&
  1125. (!cfg.stopOnEquipDrop || !equip) ) {
  1126. btcp.click();
  1127. document.querySelector('img[src$="finishbattle.png"]').click(); }
  1128. return; }
  1129. hovering = false;
  1130. Gems();
  1131. Alerts();
  1132. Durations();
  1133. Monsters();
  1134. Confirm();
  1135. ExtendQuickbar();
  1136. ProcessLog();
  1137. ShowCooldowns();
  1138. MaxVitals();
  1139. FormatLog();
  1140. TrackDrops();
  1141. Profbar();
  1142. NoPopup(); }
  1143.  
  1144. // combat helper functions
  1145. function Riddlemaster() {
  1146. var bot;
  1147. if ( !cfg.clickableRiddlemaster || !(bot = document.getElementById('riddlebot')) ) return;
  1148. if ( cfg.trackSpeed ) {
  1149. timelog.horse = (timelog.horse ? timelog.horse : 0) + 1;}
  1150. if ( !document.getElementById('buttsex') ) {
  1151. var style = document.createElement('style');
  1152. style.id = 'buttsex';
  1153. style.innerHTML =
  1154. (cfg.condenseLeft || cfg.riddleRight ? '#riddlemaster { left: ' + (cfg.condenseLeft ? '-370' : '340') + 'px; }' +
  1155. '#riddlebot > img { width: 500px; } .riddlelink { display: inline-block; position: absolute; top: 44px; }' +
  1156. '.riddlelink:nth-child(2) { left: 128px; } .riddlelink:nth-child(3) { left: 288px; } .riddlelink:nth-child(4) { left: 448px; }' :
  1157. '.riddlelink { display: inline-block; position: relative; top: -585px; }' +
  1158. '.riddlelink:nth-child(2) { left: -80px; } .riddlelink:nth-child(4) { left: 80px; }') +
  1159. '.riddlelink > div { width: 0; height: 0; border-left: 20px solid transparent;' +
  1160. 'border-right: 20px solid transparent; border-bottom: 20px solid #5C0D11; margin: 20px 50px 0; }';
  1161. document.head.appendChild(style); }
  1162. var a = document.createElement('a');
  1163. a.id = 'gay_sex';
  1164. a.className = 'riddlelink';
  1165. a.href = 'javascript:void(0)';
  1166. a.appendChild(document.createElement('div'));
  1167. a.setAttribute('onclick', 'document.getElementById("riddleanswer").value="A";document.getElementById("riddleform").submit()');
  1168. bot.appendChild(a);
  1169. a = document.createElement('a');
  1170. a.className = 'riddlelink';
  1171. a.href = 'javascript:void(0)';
  1172. a.appendChild(document.createElement('div'));
  1173. a.setAttribute('onclick', 'document.getElementById("riddleanswer").value="B";document.getElementById("riddleform").submit()');
  1174. bot.appendChild(a);
  1175. a = document.createElement('a');
  1176. a.className = 'riddlelink';
  1177. a.href = 'javascript:void(0)';
  1178. a.appendChild(document.createElement('div'));
  1179. a.setAttribute('onclick', 'document.getElementById("riddleanswer").value="C";document.getElementById("riddleform").submit()');
  1180. bot.appendChild(a); }
  1181.  
  1182. function Gems() {
  1183. var ikeyp;
  1184. if ( (ikeyp = document.getElementById('ikey_p')) ) {
  1185. gem[0] = ikeyp.getAttribute('onclick');
  1186. gem[1] = ikeyp.getAttribute('onmouseover');
  1187. var name = ikeyp.innerHTML.match(regexp.gem) || ParseDefault(ikeyp).match(regexp.defaultgem);
  1188. switch ( name[1] ) {
  1189. case 'ystic': gem[2] = '/y/e/channeling.png'; break;
  1190. case 'ealth': gem[2] = '/y/e/healthpot.png'; break;
  1191. case 'ana' : gem[2] = '/y/e/manapot.png'; gem[3] = 0; break;
  1192. case 'pirit': gem[2] = '/y/e/spiritpot.png'; gem[3] = 1; break; }}
  1193. else gem = []; }
  1194.  
  1195. function Alerts() {
  1196. var alert = false, ocfull = false, omo, oc, vcp,
  1197. spirit = document.querySelector('img[src$="spirit_n.png"]') || document.querySelector('img[src$="spirit_s.png"]');
  1198. bg = cfg.colours.default;
  1199. if ( cfg.hoverSpirit && spirit && (omo = spirit.getAttribute('onmouseover')) && omo.indexOf('lock') < 0 ) {
  1200. spirit.setAttribute('onmouseover', omo + ';' + spirit.getAttribute('onclick')); }
  1201. if ( (oc = document.querySelector('img[src$="bar_orange.png"]')) ) {
  1202. mp = parseInt(document.querySelector('img[src$="bar_blue.png"]').style.width)/414;
  1203. sp = parseInt(document.querySelector('img[src$="bar_red.png"]').style.width)/414;
  1204. if ( spirit && parseInt(oc.style.width) >= 414 ) {
  1205. ocfull = true; }
  1206. if ( (gem[3] === 0 && mp < 0.5+0.5*cfg.mpboost/(cfg.mpboost+100)) ||
  1207. (gem[3] === 1 && sp < 0.75+0.25*cfg.spboost/(cfg.spboost+100)) ) {
  1208. gem[4] = true; }
  1209. else gem[4] = false;
  1210. if ( sp <= cfg.minSP && cfg.colours.lowsp ) {
  1211. bg = cfg.colours.lowsp; if ( cfg.stopOnEmergency ) alert = true; }
  1212. if ( mp <= cfg.minMP && cfg.colours.lowmp ) {
  1213. bg = cfg.colours.lowmp; if ( cfg.stopOnEmergency ) alert = true; }
  1214. if ( parseInt(document.querySelector('img[src$="green.png"]').style.width) <= 414 * cfg.minHP && cfg.colours.lowhp ) {
  1215. bg = cfg.colours.lowhp; if ( cfg.stopOnEmergency ) alert = true; }
  1216. if ( !document.querySelector('img[src$="bar_dgreen.png"]') && document.querySelector('img[src$="fallenshield.png"]') && cfg.colours.spark ) {
  1217. bg = cfg.colours.spark; if ( cfg.stopOnEmergency ) alert = true; }}
  1218. else {
  1219. mp = parseInt(document.querySelector('img[src$="bar_blue.png"]').style.width)/207;
  1220. sp = parseInt(document.querySelector('img[src$="bar_red.png"]').style.width)/207;
  1221. if ( spirit && (vcp = document.querySelector('#vcp > div')) && parseInt(vcp.style.width) >= 190 ) {
  1222. ocfull = true; }
  1223. if ( (gem[3] === 0 && mp < 0.5+0.5*cfg.mpboost/(cfg.mpboost+100)) ||
  1224. (gem[3] === 1 && sp < 0.75+0.25*cfg.spboost/(cfg.spboost+100)) ) {
  1225. gem[4] = true; }
  1226. else gem[4] = false;
  1227. if ( sp <= cfg.minSP && cfg.colours.lowsp ) {
  1228. bg = cfg.colours.lowsp; if ( cfg.stopOnEmergency ) alert = true; }
  1229. if ( mp <= cfg.minMP && cfg.colours.lowmp ) {
  1230. bg = cfg.colours.lowmp; if ( cfg.stopOnEmergency ) alert = true; }
  1231. if ( parseInt(document.querySelector('img[src$="green.png"]').style.width) <= 496 * cfg.minHP && cfg.colours.lowhp ) {
  1232. bg = cfg.colours.lowhp; if ( cfg.stopOnEmergency ) alert = true; }
  1233. if ( !document.querySelector('img[src$="bar_dgreen.png"]') && document.querySelector('img[src$="fallenshield.png"]') && cfg.colours.spark ) {
  1234. bg = cfg.colours.spark; if ( cfg.stopOnEmergency ) alert = true; }}
  1235. interruptAlert = alert;
  1236. if ( cfg.alertColours ) {
  1237. if ( csp ) {
  1238. if ( bg == cfg.colours.default && ocfull && cfg.colours.ocfull ) {
  1239. bg = cfg.colours.ocfull; }
  1240. csp.style.background = bg; }
  1241. else {
  1242. if ( spirit && cfg.colours.ocfull ) {
  1243. spirit.style.background = ocfull ? cfg.colours.ocfull : cfg.colours.default; }
  1244. document.getElementById('pane_vitals').style.background = bg; }}}
  1245.  
  1246. function Durations() {
  1247. if ( !cfg.showDurations && !cfg.alertColours && !cfg.stopOnBuffsExpiring ) return;
  1248. var pane = document.getElementById('pane_effects'), alert = false, div, dur, duration, stack,
  1249. effects = pane.getElementsByTagName('img'), n = effects.length;
  1250. while ( n-- > 0 ) {
  1251. if ( (duration = effects[n].getAttribute('onmouseover').match(regexp.duration)) ) {
  1252. if ( cfg.alertBuffs && duration[3] < 2 && effects[n].src.indexOf('channeling.png') < 0 && cfg.alertBuffs.test(effects[n].src) ) {
  1253. alert = true; }
  1254. if ( cfg.showDurations ) {
  1255. div = document.createElement('div');
  1256. dur = document.createElement('div');
  1257. div.className = 'effect_duration';
  1258. if ( duration[3] < 9 ) {
  1259. dur.style.background = duration[3] < 4 ? 'aquamarine' : 'lavender'; }
  1260. dur.innerHTML = duration[3];
  1261. if ( (stack = duration[2]) ) {
  1262. if ( cfg.stackBorder ) {
  1263. dur.style.border = Math.ceil(stack/2)+1 + 'px solid black'; }
  1264. else {
  1265. dur.innerHTML += ' x' + stack; }}
  1266. div.appendChild(dur);
  1267. pane.insertBefore(div, effects[n]); }}}
  1268. if ( cfg.alertColours ) {
  1269. var colour = alert && cfg.colours.expiring ? cfg.colours.expiring :
  1270. (document.querySelector('#pane_effects > img[src$="channeling.png"]') && cfg.colours.channelling ? cfg.colours.channelling : cfg.colours.default);
  1271. if ( csp ) {
  1272. csp.style.background = bg != cfg.colours.default ? bg : colour; }
  1273. else {
  1274. pane.style.background = colour; }}
  1275. interruptAlert = interruptAlert || (cfg.stopOnBuffsExpiring && alert);
  1276. if ( cfg.showDurations ) {
  1277. effects = document.querySelectorAll('.btm6 > img[onmouseover]'); n = effects.length;
  1278. while ( n-- > 0 ) {
  1279. if ( (duration = effects[n].getAttribute('onmouseover').match(regexp.duration)) ) {
  1280. div = document.createElement('div');
  1281. dur = document.createElement('div');
  1282. div.className = 'effect_duration';
  1283. if ( duration[3] < 9 ) {
  1284. dur.style.background = duration[3] < 4 ? 'aquamarine' : 'lavender'; }
  1285. dur.innerHTML = duration[3];
  1286. if ( (stack = duration[2]) ) {
  1287. if ( cfg.stackBorder ) {
  1288. dur.style.border = Math.ceil(stack/2)+1 + 'px solid black'; }
  1289. else {
  1290. dur.innerHTML += ' x' + stack; }}
  1291. div.appendChild(dur);
  1292. effects[n].parentNode.insertBefore(div, effects[n]); }}}}
  1293.  
  1294. function GetMonsterData() {
  1295. if ( !cfg.showMonsterHP && !cfg.shortenHPbars && !cfg.monsterKeywords ) return;
  1296. var local, data, monster;
  1297. if ( (local = localStorage['HVmonsterData' + isekai]) ) {
  1298. monsterData = JSON.parse(local); }
  1299. else {
  1300. monsterData.info = [];
  1301. monsterData.id = [];
  1302. monsterData.name = [];
  1303. monsterData.hp = [];
  1304. monsterData.highlight = [];
  1305. monsterData.hp[10] = 0;
  1306. if ( (data = log.innerHTML.match(regexp.monsters)) ) {
  1307. for ( var i = 0; i < monsters.length; i++ ) {
  1308. monster = data[monsters.length-i-1].match(regexp.monster);
  1309. monsterData.info[i] = monster[0];
  1310. monsterData.id[i] = parseInt(monster[1]);
  1311. monsterData.name[i] = monster[2];
  1312. monsterData.hp[i] = parseInt(monster[3]);
  1313. monsterData.highlight[i] = cfg.monsterKeywords && monsters[i].hasAttribute('onclick') && cfg.monsterKeywords.test(monster[0]);
  1314. if ( !monsters[i].querySelector('.btm2[style]') ) {
  1315. monsterData.hp[10] = monsterData.hp[i] > monsterData.hp[10] ? monsterData.hp[i] : monsterData.hp[10]; }}}}}
  1316.  
  1317. function Monsters() {
  1318. var monster;
  1319. for ( var i = 0; i < monsters.length; i++ ) {
  1320. if ( (monster = monsters[i]) && monster.hasAttribute('onclick') ) {
  1321. var area = monster.querySelector('.btm' + cfg.hoverArea) || monster;
  1322. area.addEventListener('mouseout', ClearTarget, true);
  1323. area.addEventListener('mouseover', SetTarget(i), true);
  1324. monster.addEventListener('mousedown', HandleClick(i), true);
  1325. monster.addEventListener('contextmenu', function(e) { e.preventDefault(); });
  1326. monster.addEventListener('wheel', HandleWheel(i), true);
  1327. if ( cursor >= 0 ) Cursor();
  1328. if ( target === i && (cfg.hoverAction || override) && !interruptHover && !interruptAlert ) {
  1329. Hover(); }
  1330. if ( monsterData.highlight && monsterData.highlight[i] ) {
  1331. monster.querySelector('.btm2').style.background = cfg.colours.monster; }
  1332. if ( (cfg.showMonsterHP || cfg.shortenHPbars) && monsterData.hp[i] ) {
  1333. var bar = monster.querySelector('img[src$="nbargreen.png"]'),
  1334. ratio = parseInt(bar.style.width) / 120;
  1335. if ( cfg.showMonsterHP && !cfg.quickbarBesideMonsters && !cfg.condenseLeft ) {
  1336. var div = monster.appendChild(document.createElement('div'));
  1337. div.className = 'monsterhp';
  1338. div.innerHTML = 'HP: ' + Math.round(ratio * monsterData.hp[i]).toLocaleString() + ' / ' + monsterData.hp[i].toLocaleString(); }
  1339. if ( cfg.shortenHPbars && monsterData.hp[i] < monsterData.hp[10] ) {
  1340. var factor = monsterData.hp[i] / monsterData.hp[10],
  1341. border = monster.querySelector('img[src$="nbarfg.png"]'),
  1342. bg = monster.querySelector('.chbd');
  1343. bar.style.width = Math.round(ratio * factor * 120) + 'px';
  1344. border.style.width = Math.round(factor * 120) + 'px';
  1345. border.style.height = '12px';
  1346. bg.style.width = Math.round(factor * 120) + 'px'; }}
  1347. if ( cfg.colours.stun || cfg.colours.imperil || cfg.colours.stunimperil ) {
  1348. var status = monster.querySelector('.btm6'),
  1349. stun = status.innerHTML.indexOf('wpn_stun.png') > -1,
  1350. imperil = status.innerHTML.indexOf('imperil.png') > -1;
  1351. if ( cfg.colours.stunimperil && stun && imperil ) {
  1352. monster.style.background = cfg.colours.stunimperil; }
  1353. else if ( cfg.colours.stun && stun ) {
  1354. monster.style.background = cfg.colours.stun; }
  1355. else if ( cfg.colours.imperil && imperil ) {
  1356. monster.style.background = cfg.colours.imperil; }}}}}
  1357.  
  1358. function Hover() {
  1359. if ( hovering ) return;
  1360. hovering = true;
  1361. if ( override ) {
  1362. override(); }
  1363. else if ( shiftHeld && cfg.hoverShiftAction ) {
  1364. cfg.hoverShiftAction(); }
  1365. else if ( ctrlHeld && cfg.hoverCtrlAction ) {
  1366. cfg.hoverCtrlAction(); }
  1367. else if ( altHeld && cfg.hoverAltAction ) {
  1368. cfg.hoverAltAction(); }
  1369. else {
  1370. cfg.hoverAction(); }
  1371. if ( impulse ) {
  1372. impulse();
  1373. done = true;
  1374. impulse = false; }
  1375. monsters[target].click(); }
  1376.  
  1377. function SetTarget(i) { return function() {
  1378. target = i;
  1379. if ( (cfg.hoverAction || override) && !interruptHover && !interruptAlert && monsters[target].hasAttribute('onclick') ) {
  1380. Hover(); }};}
  1381.  
  1382. function HandleClick(i) {
  1383. return function(e) {
  1384. var action;
  1385. if ( (i || i === 0) && e.which == 1 ) action = cfg.clickLeft;
  1386. else if ( e.which == 2 ) action = cfg.clickMiddle;
  1387. else if ( e.which == 3 ) action = cfg.clickRight;
  1388. if ( action ) {
  1389. e.preventDefault();
  1390. if ( release ) {
  1391. done = false;
  1392. release = false; }
  1393. action();
  1394. if ( i || i === 0 ) {
  1395. monsters[i].click(); }}};}
  1396.  
  1397. function HandleWheel(i) {
  1398. return function(e) {
  1399. var action;
  1400. if ( e.deltaY < 0 ) action = cfg.wheelUp;
  1401. else if ( e.deltaY > 0 ) action = cfg.wheelDown;
  1402. else if ( e.deltaX < 0 ) action = cfg.wheelLeft;
  1403. else if ( e.deltaX > 0 ) action = cfg.wheelRight;
  1404. if ( action ) {
  1405. e.preventDefault();
  1406. done = false;
  1407. action();
  1408. if ( i || i === 0 ) {
  1409. monsters[i].click(); }}};}
  1410.  
  1411. function MouseEngage(e) {
  1412. if ( e.which == 1 ) override = cfg.clickLeft;
  1413. else if ( e.which == 2 ) override = cfg.clickMiddle;
  1414. else if ( e.which == 3 ) override = cfg.clickRight; }
  1415.  
  1416. function Cursor() {
  1417. this.battle.hover_target(monsters[cursor]); }
  1418.  
  1419. function Confirm() {
  1420. var ed, flee;
  1421. if ( cfg.edConfirm && (ed = document.querySelector('div[onclick][onmouseover*="item(11401)"]')) ) {
  1422. ed.setAttribute('onclick', 'if ( confirm("Are you sure you want to use Energy Drink?") ) {' + ed.getAttribute('onclick') + '}'); }
  1423. if ( cfg.fleeConfirm && (flee = document.getElementById('1001')) ) {
  1424. flee.setAttribute('onclick', 'if ( confirm("Tired already? I guess we can play forever some other time...") ) {' + flee.getAttribute('onclick') + '}'); }
  1425. if ( cfg.fleeConfirm && (flee = document.querySelector('.btqs[onclick][onmouseover*="Flee"]')) ) {
  1426. flee.setAttribute('onclick', 'if ( confirm("Tired already? I guess we can play forever some other time...") ) {' + flee.getAttribute('onclick') + '}'); }}
  1427.  
  1428. function ExtendQuickbar() {
  1429. var quickbar = document.getElementById('quickbar'), div, img, spell, action;
  1430. for ( var i = 0; i < cfg.quickbarExtend.length; i++ ) {
  1431. div = document.createElement('div');
  1432. div.className = 'btqs extend';
  1433. switch ( cfg.quickbarExtend[i] ) {
  1434. case 0: break;
  1435. case 1: if ( gem[0] ) {
  1436. if ( cfg.raiseGem ) {
  1437. div.setAttribute('style', 'position: absolute;' + (cfg.condenseLeft ? 'top: -55px; left: 165px;' :
  1438. (cfg.vitalsAboveMonsters ? 'top: 15px; left: 1191px;' :
  1439. 'top: 50px; left: 622px;'))); }
  1440. div.setAttribute('onclick', gem[0]);
  1441. if ( cfg.hoverGem ) {
  1442. div.setAttribute('onmouseover', gem[1] + ';' + gem[0]); }
  1443. else {
  1444. div.setAttribute('onmouseover', gem[1]); }
  1445. if ( cfg.alertColours && gem[4] ) {
  1446. div.className += ' usable'; }
  1447. img = document.createElement('img');
  1448. img.src = gem[2];
  1449. img.className = 'btqi';
  1450. div.appendChild(img);
  1451. img = document.createElement('img');
  1452. img.src = '/y/ab/b.png';
  1453. img.className = 'btqb';
  1454. div.appendChild(img); } break;
  1455. default: if ( (spell = document.getElementById(cfg.quickbarExtend[i])) ) {
  1456. img = document.createElement('img');
  1457. var info = spell.getAttribute('onmouseover');
  1458. if ( (action = spell.getAttribute('onclick')) ) {
  1459. div.setAttribute('onclick', action); }
  1460. else {
  1461. img.style.opacity = 0.5; }
  1462. div.setAttribute('onmouseover', info);
  1463. if ( cfg.quickbarExtend[i].indexOf('ikey') < 0 ) {
  1464. img.src = '/y/a/' + info.match(regexp.spellicon)[1] + '.png'; }
  1465. else {
  1466. var name = spell.innerHTML;
  1467. if ( regexp.defaultfont.test(name) ) name = ParseDefault(spell);
  1468. switch ( true ) {
  1469. case name.indexOf('ealth') > -1: img.src = '/y/e/healthpot.png'; break;
  1470. case name.indexOf('ana') > -1: img.src = '/y/e/manapot.png';
  1471. if ( cfg.alertColours && name.indexOf('otion') > -1 && mp < (100-cfg.mppot+cfg.mppot*cfg.mpboost/(cfg.mpboost+100))/100 ) {
  1472. div.className += ' usable'; } break;
  1473. case name.indexOf('pirit') > -1: img.src = '/y/e/spiritpot.png';
  1474. if ( cfg.alertColours && name.indexOf('otion') > -1 && sp < (100-cfg.sppot+cfg.sppot*cfg.spboost/(cfg.spboost+100))/100 ) {
  1475. div.className += ' usable'; } break;
  1476. case name.indexOf('lixir') > -1: img.src = '/y/e/healthpot.png'; break;
  1477. case name.indexOf('rink') > -1: img.src = '/y/e/soulstone.png'; break;
  1478. case name.indexOf('andy') > -1: img.src = '/y/e/soulstone.png'; break;
  1479. case name.indexOf('lames') > -1: img.src = '/y/e/fireinfusion.png'; break;
  1480. case name.indexOf('rost') > -1: img.src = '/y/e/coldinfusion.png'; break;
  1481. case name.indexOf('ightning') > -1: img.src = '/y/e/elecinfusion.png'; break;
  1482. case name.indexOf('torms') > -1: img.src = '/y/e/windinfusion.png'; break;
  1483. case name.indexOf('ivinity') > -1: img.src = '/y/e/holyinfusion.png'; break;
  1484. case name.indexOf('arkness') > -1: img.src = '/y/e/darkinfusion.png'; break;
  1485. case name.indexOf('wiftness') > -1: img.src = '/y/e/haste_scroll.png'; break;
  1486. case name.indexOf('rotection') > -1: img.src = '/y/e/protection_scroll.png'; break;
  1487. case name.indexOf('vatar') > -1: img.src = '/y/e/protection_scroll.png'; break;
  1488. case name.indexOf('bsorption') > -1: img.src = '/y/e/absorb_scroll.png'; break;
  1489. case name.indexOf('hadows') > -1: img.src = '/y/e/shadowveil_scroll.png'; break;
  1490. case name.indexOf('ife') > -1: img.src = '/y/e/sparklife_scroll.png'; break;
  1491. case name.indexOf('ods') > -1: img.src = '/y/e/sparklife_scroll.png'; break;
  1492. case name.indexOf('ase') > -1: img.src = '/y/e/flowers.png'; break;
  1493. case name.indexOf('um') > -1: img.src = '/y/e/gum.png'; break;
  1494. default: img.src = '/y/e/channeling.png'; break; }}
  1495. img.className = 'btqi';
  1496. div.appendChild(img);
  1497. img = document.createElement('img');
  1498. img.src = '/y/ab/b.png';
  1499. img.className = 'btqb';
  1500. div.appendChild(img); } break; }
  1501. quickbar.appendChild(div); }}
  1502.  
  1503. function MonsterBar() {
  1504. if ( !cfg.monsterBar[0] || cfg.quickbarBesideMonsters || cfg.condenseLeft ) return;
  1505. var mbar, div, img;
  1506. for ( var i = 0; i < monsters.length; i++ ) {
  1507. mbar = document.createElement('div');
  1508. mbar.id = 'mbar_' + i;
  1509. mbar.className = 'mbar';
  1510. for ( var j = 0; (j < 3 || (j < 4 && !cfg.spacedBar)) && j < cfg.monsterBar.length; j++ ) {
  1511. div = document.createElement('div');
  1512. div.className = 'btqs mbs';
  1513. img = document.createElement('img');
  1514. img.src = cfg.monsterBar[j][1] ?
  1515. '/y/a/' + document.getElementById(cfg.monsterBar[j][1]).getAttribute('onmouseover').match(regexp.spellicon)[1] + '.png' :
  1516. '/y/e/wpn_bleed.png';
  1517. img.className = 'btqi';
  1518. div.appendChild(img);
  1519. img = document.createElement('img');
  1520. img.src = '/y/ab/b.png';
  1521. img.className = 'btqb';
  1522. div.appendChild(img);
  1523. if ( cfg.monsterBar[j][0] ) {
  1524. div.onmouseout = Disengage;
  1525. div.onmouseover = BarEngage(i, cfg.monsterBar[j]); }
  1526. else {
  1527. div.onclick = BarAction(i, cfg.monsterBar[j]); }
  1528. mbar.appendChild(div); }
  1529. document.body.appendChild(mbar); }}
  1530.  
  1531. function Disengage() { target = false; override = false; }
  1532.  
  1533. function BarEngage(i, actions) {
  1534. return function() {
  1535. if ( !monsters[i].hasAttribute('onclick') ) return;
  1536. override = StrongestBar(actions);
  1537. SetTarget(i)(); };}
  1538.  
  1539. function BarAction(i, actions) {
  1540. return function() {
  1541. if ( !monsters[i].hasAttribute('onclick') ) return;
  1542. StrongestBar(actions)();
  1543. monsters[i].click(); };}
  1544.  
  1545. function StrongestBar(actions) { return function() { var n = actions.length; while ( n-- > 1 ) document.getElementById(actions[n]).click(); };}
  1546.  
  1547. function ProcessLog() {
  1548. turn = log.innerHTML.match(regexp.turn);
  1549. if ( turn ) turn = turn[0]; else return;
  1550. if ( !cfg.showCooldowns && !cfg.trackSpeed && !cfg.trackDamage && !cfg.trackUsage ) return;
  1551. if ( !timelog.startTime && cfg.trackSpeed ) timelog.startTime = Date.now();
  1552. var action = turn.match(regexp.action);
  1553. if ( action ) action = action[1]; else return;
  1554. timelog.action++;
  1555. if ( !regexp.zeroturn.test(action) ) timelog.turn++;
  1556. var use = action.match(regexp.use), miss, counter;
  1557. if ( use ) {
  1558. use = use[2];
  1559. if ( cfg.showCooldowns ) timelog.lastuse[use] = timelog.turn;
  1560. if ( cfg.trackUsage ) combatlog.used[use] = (combatlog.used[use] ? combatlog.used[use] : 0) + 1; }
  1561. else if ( !cfg.trackUsage ) {}
  1562. else if ( action.indexOf('Spirit Stance') > -1 ) combatlog.used.Spirit = (combatlog.used.Spirit ? combatlog.used.Spirit : 0) + 1;
  1563. else if ( action.indexOf('Defending.') > -1 ) combatlog.used.Defend = (combatlog.used.Defend ? combatlog.used.Defend : 0) + 1;
  1564. else if ( action.indexOf('Focusing.') > -1 ) combatlog.used.Focus = (combatlog.used.Focus ? combatlog.used.Focus : 0) + 1;
  1565. else combatlog.used.Attack = (combatlog.used.Attack ? combatlog.used.Attack : 0) + 1;
  1566. if ( cfg.trackDamage ) {
  1567. var dmg;
  1568. if ( (dmg = turn.match(regexp.damage)) ) {
  1569. var cast = action.indexOf('You cast') > -1, data, shield;
  1570. for ( var i = 0; i < dmg.length; i++ ) {
  1571. if ( (data = dmg[i].match(regexp.type)) ) {
  1572. if ( dmg[i].indexOf('its you for') > -1 ) {
  1573. var crit = dmg[i].indexOf(' crits ') > -1;
  1574. if ( dmg[i].indexOf(' casts ') > -1 ) {
  1575. combatlog.mtaken.hit++;
  1576. if ( crit ) combatlog.mtaken.crit++;
  1577. combatlog.mtaken[data[2]] = (combatlog.mtaken[data[2]] ? combatlog.mtaken[data[2]] : 0) + parseInt(data[1]);
  1578. if ( (shield = dmg[i].match(regexp.shield)) ) {
  1579. combatlog.mtaken.shit++;
  1580. if ( crit ) combatlog.mtaken.scrit++;
  1581. combatlog.mtaken['s'+data[2]] = (combatlog.mtaken['s'+data[2]] ? combatlog.mtaken['s'+data[2]] : 0) + parseInt(shield[1]); }}
  1582. else {
  1583. combatlog.ptaken.hit++;
  1584. if ( crit ) combatlog.ptaken.crit++;
  1585. combatlog.ptaken[data[2]] = (combatlog.ptaken[data[2]] ? combatlog.ptaken[data[2]] : 0) + parseInt(data[1]);
  1586. if ( (shield = dmg[i].match(regexp.shield)) ) {
  1587. combatlog.ptaken.shit++;
  1588. if ( crit ) combatlog.ptaken.scrit++;
  1589. combatlog.ptaken['s'+data[2]] = (combatlog.ptaken['s'+data[2]] ? combatlog.ptaken['s'+data[2]] : 0) + parseInt(shield[1]); }}}
  1590. else {
  1591. if ( cast ) {
  1592. if ( dmg[i].indexOf(' explodes ') < 0 ) {
  1593. combatlog.mdealt.hit++;
  1594. if ( dmg[i].indexOf(' blasts ') > -1 ) combatlog.mdealt.crit++; }
  1595. combatlog.mdealt[data[2]] = (combatlog.mdealt[data[2]] ? combatlog.mdealt[data[2]] : 0) + parseInt(data[1]); }
  1596. else {
  1597. if ( !regexp.strike.test(dmg[i]) ) {
  1598. combatlog.pdealt.hit++;
  1599. if ( regexp.crit.test(dmg[i]) ) combatlog.pdealt.crit++; }
  1600. combatlog.pdealt[data[2]] = (combatlog.pdealt[data[2]] ? combatlog.pdealt[data[2]] : 0) + parseInt(data[1]); }}}
  1601. else if ( (data = dmg[i].match(regexp.dot)) ) {
  1602. if ( regexp.pdot.test(dmg[i]) ) combatlog.pdealt.dot = (combatlog.pdealt.dot ? combatlog.pdealt.dot : 0) + parseInt(data[1]);
  1603. else combatlog.mdealt.dot = (combatlog.mdealt.dot ? combatlog.mdealt.dot : 0) + parseInt(data[1]); }
  1604. else if ( (data = dmg[i].match(regexp.points)) ) {
  1605. if ( dmg[i].indexOf('You counter') > -1 ) {
  1606. combatlog.pdealt.hit++;
  1607. combatlog.pdealt[data[2]] = (combatlog.pdealt[data[2]] ? combatlog.pdealt[data[2]] : 0) + parseInt(data[1]); }
  1608. else {
  1609. combatlog.mdealt[data[2]] = (combatlog.mdealt[data[2]] ? combatlog.mdealt[data[2]] : 0) + parseInt(data[1]); }}}}
  1610. if ( (miss = turn.match(regexp.mdmiss)) ) combatlog.mdealt.miss += miss.length;
  1611. if ( (miss = turn.match(regexp.mdevade)) ) combatlog.mdealt.evade += miss.length;
  1612. if ( (miss = turn.match(regexp.mdresist)) ) combatlog.mdealt.resist += miss.length;
  1613. if ( (miss = turn.match(regexp.md50)) ) combatlog.mdealt.r50 += miss.length;
  1614. if ( (miss = turn.match(regexp.md75)) ) combatlog.mdealt.r75 += miss.length;
  1615. if ( (miss = turn.match(regexp.md90)) ) combatlog.mdealt.r90 += miss.length;
  1616. if ( (miss = turn.match(regexp.pdmiss)) ) combatlog.pdealt.miss += miss.length;
  1617. if ( (miss = turn.match(regexp.pdevade)) ) combatlog.pdealt.evade += miss.length;
  1618. if ( (miss = turn.match(regexp.pdparry)) ) combatlog.pdealt.parry += miss.length;
  1619. if ( (miss = turn.match(regexp.mtevade)) ) combatlog.mtaken.evade += miss.length;
  1620. if ( (miss = turn.match(regexp.mtblock)) ) combatlog.mtaken.block += miss.length;
  1621. if ( (miss = turn.match(regexp.mt50)) ) combatlog.mtaken.r50 += miss.length;
  1622. if ( (miss = turn.match(regexp.mt75)) ) combatlog.mtaken.r75 += miss.length;
  1623. if ( (miss = turn.match(regexp.mt90)) ) combatlog.mtaken.r90 += miss.length;
  1624. if ( (miss = turn.match(regexp.ptmiss)) ) combatlog.ptaken.miss += miss.length;
  1625. if ( (miss = turn.match(regexp.ptevade)) ) combatlog.ptaken.evade += miss.length;
  1626. if ( (miss = turn.match(regexp.ptparry)) ) combatlog.ptaken.parry += miss.length;
  1627. if ( (miss = turn.match(regexp.ptblock)) ) combatlog.ptaken.block += miss.length; }
  1628. if ( cfg.trackUsage && (counter = turn.match(regexp.counter)) ) combatlog.used.Counter = (combatlog.used.Counter ? combatlog.used.Counter : 0) + counter.length; }
  1629.  
  1630. function ShowCooldowns() {
  1631. if ( !cfg.showCooldowns ) return;
  1632. var quickbar = document.getElementById('quickbar'), info, used, cooldown, div,
  1633. buttons = quickbar.querySelectorAll('.btqs[onmouseover]:not([onclick])'), n = buttons.length;
  1634. while ( n-- > 0 ) {
  1635. if ( (info = buttons[n].getAttribute('onmouseover').match(regexp.spellinfo)) &&
  1636. (used = timelog.lastuse[info[1]]) && (cooldown = info[2] - timelog.turn + used) > 0 ) {
  1637. div = document.createElement('div');
  1638. div.className = 'cooldown';
  1639. div.innerHTML = cooldown;
  1640. buttons[n].appendChild(div); }}}
  1641.  
  1642. function MaxVitals() {
  1643. if ( !cfg.maxVitals ) return;
  1644. var hpd, mpd, spd, changed = false;
  1645. if ( (hpd = document.getElementById('dvrhd') || document.getElementById('dvrhb')) ) {
  1646. mpd = document.getElementById('dvrm');
  1647. spd = document.getElementById('dvrs'); }
  1648. else {
  1649. hpd = document.getElementById('vrhd') || document.getElementById('vrhb');
  1650. mpd = document.getElementById('vrm');
  1651. spd = document.getElementById('vrs'); }
  1652. var hpv = parseInt(hpd.innerHTML), mpv = parseInt(mpd.innerHTML), spv = parseInt(spd.innerHTML);
  1653. if ( hpv > vitals.hp ) { vitals.hp = hpv; changed = true; }
  1654. if ( mpv > vitals.mp ) { vitals.mp = mpv; changed = true; }
  1655. if ( spv > vitals.sp ) { vitals.sp = spv; changed = true; }
  1656. hpd.innerHTML = hpv + '/' + vitals.hp;
  1657. mpd.innerHTML = mpv + '/' + vitals.mp;
  1658. spd.innerHTML = spv + '/' + vitals.sp; }
  1659.  
  1660. function FormatLog() {
  1661. if ( !cfg.logColours && !cfg.turnDividers ) return;
  1662. var rows = log.getElementsByTagName('td');
  1663. for ( var i = 0; i < rows.length; i++ ) {
  1664. if ( rows[i].className == 'tls' ) {
  1665. if ( cfg.turnDividers ) {
  1666. rows[i].innerHTML = '<hr>'; }
  1667. break; }
  1668. var text = rows[i].innerHTML;
  1669. if ( cfg.logColours ) {
  1670. if ( regexp.crit.test(text) ) {
  1671. rows[i].className = 'tlb'; }
  1672. if ( regexp.miss.test(text) ) {
  1673. rows[i].className += ' miss'; }
  1674. else if ( text.indexOf('its you for') > -1 ) {
  1675. rows[i].className += ' damage'; }
  1676. else if ( regexp.zeroturn.test(text) ) {
  1677. rows[i].className += ' item'; }
  1678. else if ( regexp.attack.test(text) ) {
  1679. rows[i].className += ' attack'; }
  1680. else if ( regexp.spell.test(text) ) {
  1681. rows[i].className += ' spell'; }
  1682. else if ( regexp.recovery.test(text) ) {
  1683. rows[i].className += ' recovery'; }
  1684. else if ( text.indexOf('You gain the effect') > -1 ) {
  1685. rows[i].className += ' effect'; }
  1686. else if ( text.indexOf('Spirit Stance') > -1 ) {
  1687. rows[i].className += ' spirit'; }
  1688. else if ( text.indexOf('proficiency') > -1 ) {
  1689. rows[i].className += ' proficiency'; }}}}
  1690.  
  1691. function ShowRound() {
  1692. var div = document.getElementById(cfg.bigRoundCounter ? 'mainpane' : 'battle_right').appendChild(document.createElement('div')), rounds;
  1693. div.id = 'gay_sex';
  1694. if ( !cfg.showRound ) return;
  1695. if ( !timelog.rounds && (rounds = log.innerHTML.match(regexp.round)) ) {
  1696. timelog.round = rounds[1];
  1697. timelog.rounds = rounds[2]; }
  1698. if ( timelog.rounds ) {
  1699. div.innerHTML = (cfg.bigRoundCounter ? '' : 'Round ') + timelog.round.toLocaleString() + ' / ' + timelog.rounds.toLocaleString();
  1700. if ( cfg.bigRoundCounter ) {
  1701. div.setAttribute('style', 'position: absolute; left: 1110px; top: 10px; font-size: 200%; font-weight: bold'); }}}
  1702.  
  1703. function CfgButton() {
  1704. if ( !cfg.cfgButton ) return;
  1705. var div = document.createElement('div');
  1706. div.id = 'cfgbutton';
  1707. div.innerHTML = '\u2699';
  1708. div.onclick = Settings;
  1709. document.body.appendChild(div);
  1710. var hasper = regexp.profile.test(JSON.stringify(cfg.persona));
  1711. var hasisk = regexp.profile.test(JSON.stringify(cfg.isekai.persona)) || (hasper && cfg.isekaiInherit);
  1712. if ( (!isekai && hasper) || (isekai && hasisk) ) {
  1713. var menu = div.appendChild(document.createElement('div'));
  1714. const Set = function(i, p, s) {
  1715. return function(e) {
  1716. e.stopPropagation();
  1717. var blue;
  1718. if ( (blue = menu.querySelector('[style*="' + (isekai ? 'red' : 'blue') + '"')) ) {
  1719. blue.style.color = ''; }
  1720. profile[isekai + 'p'] = p;
  1721. if (p) {
  1722. profile[isekai + 's' + profile[isekai + 'p']] = s; }
  1723. if ( JSON.stringify(profile) != localStorage.HVmbp ) {
  1724. localStorage.HVmbp = JSON.stringify(profile);
  1725. location.href = location.href; }
  1726. i.style.color = isekai ? 'red' : 'blue'; };};
  1727. menu.id = 'mbprofile';
  1728. menu.className = 'fc4 fal fcb';
  1729. var base = menu.appendChild(document.createElement('div')), blue = false;
  1730. base.onclick = Set(base, 0, 0);
  1731. if ( !isekai ) {
  1732. base.innerHTML = cfg.name;
  1733. for ( var i = 0; i < cfg.persona.length; i++ ) {
  1734. if ( regexp.profile.test(JSON.stringify(cfg.persona[i])) ) {
  1735. var persona = menu.appendChild(document.createElement('div'));
  1736. persona.innerHTML = '- ' + cfg.persona[i].name;
  1737. persona.onclick = Set(persona, i+1, 0);
  1738. for ( var j = 0; j < cfg.persona[i].set.length; j++ ) {
  1739. if ( regexp.profile.test(JSON.stringify(cfg.persona[i].set[j])) ) {
  1740. var set = menu.appendChild(document.createElement('div'));
  1741. set.innerHTML = '-- ' + cfg.persona[i].set[j].name;
  1742. set.onclick = Set(set, i+1, j+1);
  1743. if ( profile.p == i+1 && profile['s' + profile.p] == j+1 ) {
  1744. set.style.color = 'blue';
  1745. blue = true; }}}
  1746. if ( profile.p == i+1 && (!blue || profile['s' + profile.p] == 0) ) {
  1747. persona.style.color = 'blue';
  1748. blue = true; }}}
  1749. if ( !blue || profile.p == 0 ) {
  1750. base.style.color = 'blue'; }}
  1751. else {
  1752. base.innerHTML = cfg.isekai.name;
  1753. for ( i = 0; i < cfg.isekai.persona.length; i++ ) {
  1754. hasisk = regexp.profile.test(JSON.stringify(cfg.isekai.persona[i]));
  1755. hasper = regexp.profile.test(JSON.stringify(cfg.persona[i])) && cfg.isekaiInherit;
  1756. if ( hasisk || hasper ) {
  1757. persona = menu.appendChild(document.createElement('div'));
  1758. persona.innerHTML = '- ' + (hasisk ? cfg.isekai.persona[i].name : cfg.persona[i].name);
  1759. persona.onclick = Set(persona, i+1, 0);
  1760. for ( j = 0; j < cfg.isekai.persona[i].set.length; j++ ) {
  1761. hasisk = regexp.profile.test(JSON.stringify(cfg.isekai.persona[i].set[j]));
  1762. hasper = regexp.profile.test(JSON.stringify(cfg.persona[i].set[j])) && cfg.isekaiInherit;
  1763. if ( hasisk || hasper ) {
  1764. set = menu.appendChild(document.createElement('div'));
  1765. set.innerHTML = '-- ' + (hasisk ? cfg.isekai.persona[i].set[j].name : cfg.persona[i].set[j].name);
  1766. set.onclick = Set(set, i+1, j+1);
  1767. if ( profile.ip == i+1 && profile['is' + profile.ip] == j+1 ) {
  1768. set.style.color = 'red';
  1769. blue = true; }}}
  1770. if ( profile.ip == i+1 && (!blue || profile['is' + profile.ip] == 0) ) {
  1771. persona.style.color = 'red';
  1772. blue = true; }}}
  1773. if ( !blue || profile.ip == 0 ) {
  1774. base.style.color = 'red'; }}}}
  1775.  
  1776. function TrackDrops() {
  1777. if ( (!cfg.trackDrops && !cfg.trackProficiency && !cfg.proficiencySidebar) || !document.getElementById('btcp') ) return;
  1778. if ( cfg.trackDrops ) {
  1779. var reward = turn.match(regexp.reward);
  1780. if ( reward && (reward = parseInt(reward[1])) ) {
  1781. droplog.Credit = (droplog.Credit ? droplog.Credit : 0) + reward; }
  1782. var drops = turn.match(regexp.drops);
  1783. if ( !drops ) drops = [];
  1784. var n = drops.length, crystal, crystals, credit, exp, proficiencies, proficiency, prof;
  1785. while ( n-- > 0 ) {
  1786. var drop = drops[n].match(regexp.drop);
  1787. if ( drop[2] == 'BA05B4' && (crystal = drop[3].match(regexp.crystal)) ) {
  1788. droplog.Crystal = (droplog.Crystal ? droplog.Crystal : 0) + (parseInt(crystal[1]) || 1);
  1789. if ( cfg.detailedCrystlog && (crystals = drop[3].match(regexp.crystals)) ) {
  1790. droplog.Crystals[crystals[0]] = (droplog.Crystals[crystals[0]] ? droplog.Crystals[crystals[0]] : 0) + (parseInt(crystal[1]) || 1); }}
  1791. else if (drop[2] == 'A89000' && (credit = drop[3].match(regexp.credit)) ) {
  1792. droplog.Credit = (droplog.Credit ? droplog.Credit : 0) + (parseInt(credit[1]) || 1); }
  1793. else if ( drop[2] == 'FF0000' && !drop[4] && regexp.quality[8].test(drop[0]) ) {
  1794. var tracked = false;
  1795. if ( (tracked = cfg.equipmentCutoff > 0 && drop[3].indexOf('Peerless') > -1) ) {
  1796. droplog.Peerless = (droplog.Peerless ? droplog.Peerless : 0) + 1; }
  1797. else if ( (tracked = cfg.equipmentCutoff > 1 && drop[3].indexOf('Legendary') > -1) ) {
  1798. droplog.Legendary = (droplog.Legendary ? droplog.Legendary : 0) + 1; }
  1799. else if ( (tracked = cfg.equipmentCutoff > 2 && drop[3].indexOf('Magnificent') > -1) ) {
  1800. droplog.Magnificent = (droplog.Magnificent ? droplog.Magnificent : 0) + 1; }
  1801. else if ( (tracked = cfg.equipmentCutoff > 3 && drop[3].indexOf('Exquisite') > -1) ) {
  1802. droplog.Exquisite = (droplog.Exquisite ? droplog.Exquisite : 0) + 1; }
  1803. else if ( (tracked = cfg.equipmentCutoff > 4 && drop[3].indexOf('Superior') > -1) ) {
  1804. droplog.Superior = (droplog.Superior ? droplog.Superior : 0) + 1; }
  1805. else if ( (tracked = cfg.equipmentCutoff > 5 && drop[3].indexOf('Average') > -1) ) {
  1806. droplog.Average = (droplog.Average ? droplog.Average : 0) + 1; }
  1807. else if ( (tracked = cfg.equipmentCutoff > 6 && drop[3].indexOf('Fair') > -1) ) {
  1808. droplog.Fair = (droplog.Fair ? droplog.Fair : 0) + 1; }
  1809. else if ( (tracked = cfg.equipmentCutoff > 7 && drop[3].indexOf('Crude') > -1) ) {
  1810. droplog.Crude = (droplog.Crude ? droplog.Crude : 0) + 1; }
  1811. else {
  1812. droplog.Equipment = (droplog.Equipment ? droplog.Equipment : 0) + 1; }
  1813. if ( cfg.detailedDroplog && tracked ) {
  1814. droplog.Equips[drop[3]] = (droplog.Equips[drop[3]] ? droplog.Equips[drop[3]] : 0) + 1; }}
  1815. else if ( drop[2] == 'FF0000' && !drop[4] ) {
  1816. droplog.Material = (droplog.Material ? droplog.Material : 0) + (parseInt(drop[1]) || 1);
  1817. if ( cfg.detailedDroplog ) {
  1818. droplog.Mats[drop[3]] = (droplog.Mats[drop[3]] ? droplog.Mats[drop[3]] : 0) + (parseInt(drop[1]) || 1); }}
  1819. else if ( drop[3].indexOf('Chaos') > -1 ) {
  1820. droplog.Chaos = (droplog.Chaos ? droplog.Chaos : 0) + 1; }
  1821. else if ( drop[3].indexOf('Blood') > -1 ) {
  1822. droplog.Blood = (droplog.Blood ? droplog.Blood : 0) + 1; }
  1823. else if ( drop[3].indexOf('Soul') > -1 ) {
  1824. droplog.Soul = (droplog.Soul ? droplog.Soul : 0) + (drop[1] == 'five' ? 5 : (parseInt(drop[1]) || 1)); }
  1825. else if ( drop[3].indexOf('Figurine') > -1 ) {
  1826. droplog.Figurine = (droplog.Figurine ? droplog.Figurine : 0) + 1;
  1827. if ( cfg.detailedDroplog ) {
  1828. droplog.Figurines[drop[3]] = (droplog.Figurines[drop[3]] ? droplog.Figurines[drop[3]] : 0) + 1; }}
  1829. else if ( drop[2] == '0000FF' ) {
  1830. droplog.Artifact = (droplog.Artifact ? droplog.Artifact : 0) + 1;
  1831. if ( cfg.detailedDroplog ) {
  1832. droplog.Artifacts[drop[3]] = (droplog.Artifacts[drop[3]] ? droplog.Artifacts[drop[3]] : 0) + 1; }}
  1833. else if ( drop[2] == '461B7E' ) {
  1834. droplog.Trophy = (droplog.Trophy ? droplog.Trophy : 0) + 1;
  1835. if ( cfg.detailedDroplog ) {
  1836. droplog.Trophies[drop[3]] = (droplog.Trophies[drop[3]] ? droplog.Trophies[drop[3]] : 0) + 1; }}
  1837. else if ( drop[2] == '00B000' && drop[3].indexOf('Gem') < 0 ) {
  1838. droplog.Consumable = (droplog.Consumable ? droplog.Consumable : 0) + 1;
  1839. if ( cfg.detailedDroplog ) {
  1840. droplog.Consumables[drop[3]] = (droplog.Consumables[drop[3]] ? droplog.Consumables[drop[3]] : 0) + 1; }}
  1841. else if ( drop[2] == '489EFF' ) {
  1842. droplog.Food = (droplog.Food ? droplog.Food : 0) + 1;
  1843. if ( cfg.detailedDroplog ) {
  1844. droplog.Foods[drop[3]] = (droplog.Foods[drop[3]] ? droplog.Foods[drop[3]] : 0) + 1; }}}
  1845. if ( (exp = log.innerHTML.match(regexp.exp)) ) {
  1846. droplog.EXP = (droplog.EXP ? droplog.EXP : 0) + parseInt(exp[1]); }}
  1847. if ( (cfg.trackProficiency || cfg.proficiencySidebar) && (proficiencies = log.innerHTML.match(regexp.proficiencies)) ) {
  1848. for ( var i = 0; i < proficiencies.length; i++ ) {
  1849. if ( (proficiency = proficiencies[i].match(regexp.proficiency)) && (prof = parseFloat(proficiency[1])) && prof > 0 ) {
  1850. droplog.proficiency[proficiency[2]] = (droplog.proficiency[proficiency[2]] ? droplog.proficiency[proficiency[2]] : 0) + prof; }}}}
  1851.  
  1852. function Profbar() {
  1853. if ( !cfg.proficiencySidebar ) return;
  1854. var profbar = document.getElementById('profbar');
  1855. if ( !profbar ) {
  1856. profbar = document.createElement('table');
  1857. profbar.id = 'profbar';
  1858. document.getElementById('csp').appendChild(profbar); }
  1859. profbar.innerHTML = '<tbody>' +
  1860. (droplog.proficiency['one-handed weapon'] ? '<tr><td>' + droplog.proficiency['one-handed weapon'].toFixed(3) + '</td><td>1H</td></tr>' : '') +
  1861. (droplog.proficiency['two-handed weapon'] ? '<tr><td>' + droplog.proficiency['two-handed weapon'].toFixed(3) + '</td><td>2H</td></tr>' : '') +
  1862. (droplog.proficiency['dual wielding'] ? '<tr><td>' + droplog.proficiency['dual wielding'].toFixed(3) + '</td><td>DW</td></tr>' : '') +
  1863. (droplog.proficiency['cloth armor'] ? '<tr><td>' + droplog.proficiency['cloth armor'].toFixed(3) + '</td><td>cloth</td></tr>' : '') +
  1864. (droplog.proficiency['light armor'] ? '<tr><td>' + droplog.proficiency['light armor'].toFixed(3) + '</td><td>light</td></tr>' : '') +
  1865. (droplog.proficiency['heavy armor'] ? '<tr><td>' + droplog.proficiency['heavy armor'].toFixed(3) + '</td><td>heavy</td></tr>' : '') +
  1866. (droplog.proficiency.staff ? '<tr><td>' + droplog.proficiency.staff.toFixed(3) + '</td><td>staff</td></tr>' : '') +
  1867. (droplog.proficiency['elemental magic'] ? '<tr><td>' + droplog.proficiency['elemental magic'].toFixed(3) + '</td><td>elem</td></tr>' : '') +
  1868. (droplog.proficiency['divine magic'] ? '<tr><td>' + droplog.proficiency['divine magic'].toFixed(3) + '</td><td>holy</td></tr>' : '') +
  1869. (droplog.proficiency['forbidden magic'] ? '<tr><td>' + droplog.proficiency['forbidden magic'].toFixed(3) + '</td><td>dark</td></tr>' : '') +
  1870. (droplog.proficiency['deprecating magic'] ? '<tr><td>' + droplog.proficiency['deprecating magic'].toFixed(3) + '</td><td>dep</td></tr>' : '') +
  1871. (droplog.proficiency['supportive magic'] ? '<tr><td>' + droplog.proficiency['supportive magic'].toFixed(3) + '</td><td>sup</td></tr>' : '') +
  1872. '</tbody>'; }
  1873.  
  1874. function ShowDrops(end) {
  1875. var btcp = document.getElementById('btcp');
  1876. if ( end && !btcp ) return;
  1877. if ( !end && !btcp ) {
  1878. if ( (btcp = document.getElementById('dropbox')) ) {
  1879. btcp.parentNode.removeChild(btcp);
  1880. return; }
  1881. btcp = document.createElement('div');
  1882. btcp.id = 'dropbox';
  1883. document.getElementById('pane_completion').appendChild(btcp); }
  1884. if ( end && cfg.selectLog ) {
  1885. document.querySelector('img[src$="finishbattle.png"]').setAttribute('onclick', btcp.getAttribute('onclick'));
  1886. btcp.removeAttribute('onclick'); }
  1887. var span, crystal, credit, peerless, legendary, magnificent, exquisite, superior, average, fair, crude, equipment,
  1888. material, chaos, blood, soul, artifact, figurine, trophy, consumable, food, exp, turns, startTime;
  1889. if ( cfg.consoleLog ) {
  1890. console.log(JSON.stringify(combatlog));
  1891. console.log(JSON.stringify(droplog)); }
  1892. btcp.setAttribute('style', 'display: block; height: auto; min-height: 120px; max-height: 621px; overflow: auto');
  1893. if ( (crystal = droplog.Crystal) ) {
  1894. btcp.appendChild(document.createElement('br'));
  1895. span = btcp.appendChild(document.createElement('span'));
  1896. span.className = 'drop crystal';
  1897. span.innerHTML = crystal.toLocaleString() + (cfg.terseLog ? '\t' : ' ') + 'Crystal' + (crystal > 1 || cfg.terseLog ? 's' : '');
  1898. if ( cfg.detailedCrystlog ) {
  1899. for ( var crystals in droplog.Crystals ) {
  1900. btcp.appendChild(document.createElement('br'));
  1901. span = btcp.appendChild(document.createElement('span'));
  1902. span.className = 'drop crystal';
  1903. span.innerHTML = droplog.Crystals[crystals].toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + crystals; }}}
  1904. if ( (credit = droplog.Credit) ) {
  1905. btcp.appendChild(document.createElement('br'));
  1906. span = btcp.appendChild(document.createElement('span'));
  1907. span.className = 'drop credit';
  1908. span.innerHTML = credit.toLocaleString() + (cfg.terseLog ? '\t' : ' ') + 'Credit' + (credit > 1 || cfg.terseLog ? 's' : ''); }
  1909. if ( cfg.detailedDroplog ) {
  1910. for ( var equips in droplog.Equips ) {
  1911. btcp.appendChild(document.createElement('br'));
  1912. span = btcp.appendChild(document.createElement('span'));
  1913. span.className = 'drop equipment';
  1914. span.innerHTML = droplog.Equips[equips].toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + equips; }}
  1915. else {
  1916. if ( (peerless = droplog.Peerless) ) {
  1917. btcp.appendChild(document.createElement('br'));
  1918. span = btcp.appendChild(document.createElement('span'));
  1919. span.className = 'drop equipment';
  1920. span.innerHTML = peerless.toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + 'Peerless Equipment'; }
  1921. if ( (legendary = droplog.Legendary) ) {
  1922. btcp.appendChild(document.createElement('br'));
  1923. span = btcp.appendChild(document.createElement('span'));
  1924. span.className = 'drop equipment';
  1925. span.innerHTML = legendary.toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + 'Legendary Equipment'; }
  1926. if ( (magnificent = droplog.Magnificent) ) {
  1927. btcp.appendChild(document.createElement('br'));
  1928. span = btcp.appendChild(document.createElement('span'));
  1929. span.className = 'drop equipment';
  1930. span.innerHTML = magnificent.toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + 'Magnificent Equipment'; }
  1931. if ( (exquisite = droplog.Exquisite) ) {
  1932. btcp.appendChild(document.createElement('br'));
  1933. span = btcp.appendChild(document.createElement('span'));
  1934. span.className = 'drop equipment';
  1935. span.innerHTML = exquisite.toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + 'Exquisite Equipment'; }
  1936. if ( (superior = droplog.Superior) ) {
  1937. btcp.appendChild(document.createElement('br'));
  1938. span = btcp.appendChild(document.createElement('span'));
  1939. span.className = 'drop equipment';
  1940. span.innerHTML = superior.toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + 'Superior Equipment'; }
  1941. if ( (average = droplog.Average) ) {
  1942. btcp.appendChild(document.createElement('br'));
  1943. span = btcp.appendChild(document.createElement('span'));
  1944. span.className = 'drop equipment';
  1945. span.innerHTML = average.toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + 'Average Equipment'; }
  1946. if ( (fair = droplog.Fair) ) {
  1947. btcp.appendChild(document.createElement('br'));
  1948. span = btcp.appendChild(document.createElement('span'));
  1949. span.className = 'drop equipment';
  1950. span.innerHTML = fair.toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + 'Fair Equipment'; }
  1951. if ( (crude = droplog.Crude) ) {
  1952. btcp.appendChild(document.createElement('br'));
  1953. span = btcp.appendChild(document.createElement('span'));
  1954. span.className = 'drop equipment';
  1955. span.innerHTML = crude.toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + 'Crude Equipment'; }}
  1956. if ( (equipment = droplog.Equipment) ) {
  1957. btcp.appendChild(document.createElement('br'));
  1958. span = btcp.appendChild(document.createElement('span'));
  1959. span.className = 'drop equipment';
  1960. span.innerHTML = equipment.toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + (cfg.equipmentCutoff > 0 ? 'Lesser ' : '') + 'Equipment'; }
  1961. if ( cfg.detailedDroplog ) {
  1962. for ( var mats in droplog.Mats ) {
  1963. btcp.appendChild(document.createElement('br'));
  1964. span = btcp.appendChild(document.createElement('span'));
  1965. span.className = 'drop equipment';
  1966. span.innerHTML = droplog.Mats[mats].toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + mats; }}
  1967. else {
  1968. if ( (material = droplog.Material) ) {
  1969. btcp.appendChild(document.createElement('br'));
  1970. span = btcp.appendChild(document.createElement('span'));
  1971. span.className = 'drop equipment';
  1972. span.innerHTML = material.toLocaleString() + (cfg.terseLog ? '\t' : ' ') + 'Material' + (material > 1 && !cfg.terseLog ? 's' : ''); }}
  1973. if ( (chaos = droplog.Chaos) ) {
  1974. btcp.appendChild(document.createElement('br'));
  1975. span = btcp.appendChild(document.createElement('span'));
  1976. span.className = 'drop token';
  1977. span.innerHTML = chaos.toLocaleString() + (cfg.terseLog ? '\t' : ' ') + 'Chaos Token' + (chaos > 1 && !cfg.terseLog ? 's' : ''); }
  1978. if ( (blood = droplog.Blood) ) {
  1979. btcp.appendChild(document.createElement('br'));
  1980. span = btcp.appendChild(document.createElement('span'));
  1981. span.className = 'drop token';
  1982. span.innerHTML = blood.toLocaleString() + (cfg.terseLog ? '\t' : ' ') + 'Token' + (blood > 1 && !cfg.terseLog ? 's' : '') + ' of Blood'; }
  1983. if ( (soul = droplog.Soul) ) {
  1984. btcp.appendChild(document.createElement('br'));
  1985. span = btcp.appendChild(document.createElement('span'));
  1986. span.className = 'drop token';
  1987. span.innerHTML = soul.toLocaleString() + (cfg.terseLog ? '\t' : ' ') + ' Soul Fragment' + (cfg.terseLog ? '' : 's'); }
  1988. if ( cfg.detailedDroplog ) {
  1989. for ( var artifacts in droplog.Artifacts ) {
  1990. btcp.appendChild(document.createElement('br'));
  1991. span = btcp.appendChild(document.createElement('span'));
  1992. span.className = 'drop artifact';
  1993. span.innerHTML = droplog.Artifacts[artifacts].toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + artifacts; }
  1994. for ( var figurines in droplog.Figurines ) {
  1995. btcp.appendChild(document.createElement('br'));
  1996. span = btcp.appendChild(document.createElement('span'));
  1997. span.className = 'drop artifact';
  1998. span.innerHTML = droplog.Figurines[figurines].toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + figurines; }
  1999. for ( var trophies in droplog.Trophies ) {
  2000. btcp.appendChild(document.createElement('br'));
  2001. span = btcp.appendChild(document.createElement('span'));
  2002. span.className = 'drop trophy';
  2003. span.innerHTML = droplog.Trophies[trophies].toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + trophies; }
  2004. for ( var consumables in droplog.Consumables ) {
  2005. btcp.appendChild(document.createElement('br'));
  2006. span = btcp.appendChild(document.createElement('span'));
  2007. span.className = 'drop consumable';
  2008. span.innerHTML = droplog.Consumables[consumables].toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + consumables; }
  2009. for ( var foods in droplog.Foods ) {
  2010. btcp.appendChild(document.createElement('br'));
  2011. span = btcp.appendChild(document.createElement('span'));
  2012. span.className = 'drop food';
  2013. span.innerHTML = droplog.Foods[foods].toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + foods; }}
  2014. else {
  2015. if ( (artifact = droplog.Artifact) ) {
  2016. btcp.appendChild(document.createElement('br'));
  2017. span = btcp.appendChild(document.createElement('span'));
  2018. span.className = 'drop artifact';
  2019. span.innerHTML = artifact.toLocaleString() + (cfg.terseLog ? '\t' : ' ') + 'Artifact' + (artifact > 1 && !cfg.terseLog ? 's' : ''); }
  2020. if ( (figurine = droplog.Figurine) ) {
  2021. btcp.appendChild(document.createElement('br'));
  2022. span = btcp.appendChild(document.createElement('span'));
  2023. span.className = 'drop artifact';
  2024. span.innerHTML = figurine.toLocaleString() + (cfg.terseLog ? '\t' : ' ') + 'Figurine' + (figurine > 1 && !cfg.terseLog ? 's' : ''); }
  2025. if ( (trophy = droplog.Trophy) ) {
  2026. btcp.appendChild(document.createElement('br'));
  2027. span = btcp.appendChild(document.createElement('span'));
  2028. span.className = 'drop trophy';
  2029. span.innerHTML = trophy.toLocaleString() + (cfg.terseLog ? '\t' : ' ') + 'Troph' + (trophy > 1 && !cfg.terseLog ? 'ies' : 'y'); }
  2030. if ( (consumable = droplog.Consumable) ) {
  2031. btcp.appendChild(document.createElement('br'));
  2032. span = btcp.appendChild(document.createElement('span'));
  2033. span.className = 'drop consumable';
  2034. span.innerHTML = consumable.toLocaleString() + (cfg.terseLog ? '\t' : ' ') + 'Consumable' + (consumable > 1 && !cfg.terseLog ? 's' : ''); }
  2035. if ( (food = droplog.Food) ) {
  2036. btcp.appendChild(document.createElement('br'));
  2037. span = btcp.appendChild(document.createElement('span'));
  2038. span.className = 'drop food';
  2039. span.innerHTML = food.toLocaleString() + (cfg.terseLog ? '\t' : 'x ') + 'Food'; }}
  2040. if ( (exp = droplog.EXP) ) {
  2041. btcp.appendChild(document.createElement('br'));
  2042. span = btcp.appendChild(document.createElement('span'));
  2043. span.className = 'drop';
  2044. span.innerHTML = exp.toLocaleString() + (cfg.terseLog ? '\t' : ' ') + 'EXP'; }
  2045. if ( cfg.trackProficiency ) {
  2046. for ( var prof in droplog.proficiency ) {
  2047. btcp.appendChild(document.createElement('br'));
  2048. span = btcp.appendChild(document.createElement('span'));
  2049. span.className = 'drop';
  2050. span.innerHTML = droplog.proficiency[prof].toFixed(3) + (cfg.terseLog ? '\t' : ' ') + prof; }}
  2051. if ( cfg.trackSpeed && (turns = timelog.action) && (startTime = timelog.startTime) ) {
  2052. btcp.appendChild(document.createElement('br'));
  2053. btcp.appendChild(document.createElement('br'));
  2054. var time = Math.round((Date.now() - startTime) / 1000.0),
  2055. hours = Math.floor(time / 3600),
  2056. minutes = Math.floor(time / 60) % 60,
  2057. seconds = time % 60,
  2058. tps = turns / time;
  2059. span = btcp.appendChild(document.createElement('span'));
  2060. span.className = 'speed';
  2061. span.innerHTML = turns.toLocaleString() + ' turn' + (turns == 1 ? '' : 's') + ' ' +
  2062. hours + ':' +
  2063. (minutes < 10 ? '0' : '') + minutes + ':' +
  2064. (seconds < 10 ? '0' : '') + seconds + ' (' +
  2065. tps.toLocaleString() + ' t/s)' +
  2066. (timelog.horse ? ' ' + timelog.horse + ' horse' + (timelog.horse > 1 ? 's' : '') : ''); }}
  2067.  
  2068. function ShowDamage() {
  2069. if ( !cfg.trackDamage ) return;
  2070. var any = { fire: combatlog.pdealt.fire || combatlog.mdealt.fire || combatlog.ptaken.fire || combatlog.mtaken.fire,
  2071. cold: combatlog.pdealt.cold || combatlog.mdealt.cold || combatlog.ptaken.cold || combatlog.mtaken.cold,
  2072. elec: combatlog.pdealt.elec || combatlog.mdealt.elec || combatlog.ptaken.elec || combatlog.mtaken.elec,
  2073. wind: combatlog.pdealt.wind || combatlog.mdealt.wind || combatlog.ptaken.wind || combatlog.mtaken.wind,
  2074. holy: combatlog.pdealt.holy || combatlog.mdealt.holy || combatlog.ptaken.holy || combatlog.mtaken.holy,
  2075. dark: combatlog.pdealt.dark || combatlog.mdealt.dark || combatlog.ptaken.dark || combatlog.mtaken.dark,
  2076. crushing: combatlog.pdealt.crushing || combatlog.mdealt.crushing || combatlog.ptaken.crushing || combatlog.mtaken.crushing,
  2077. slashing: combatlog.pdealt.slashing || combatlog.mdealt.slashing || combatlog.ptaken.slashing || combatlog.mtaken.slashing,
  2078. piercing: combatlog.pdealt.piercing || combatlog.mdealt.piercing || combatlog.ptaken.piercing || combatlog.mtaken.piercing,
  2079. void: combatlog.pdealt.void || combatlog.mdealt.void || combatlog.ptaken.void || combatlog.mtaken.void,
  2080. dot: combatlog.pdealt.dot || combatlog.mdealt.dot,
  2081. pdealt: combatlog.pdealt.dot || combatlog.pdealt.hit || combatlog.pdealt.miss || combatlog.pdealt.evade || combatlog.pdealt.parry,
  2082. mdealt: combatlog.mdealt.fire || combatlog.mdealt.cold || combatlog.mdealt.elec || combatlog.mdealt.wind ||
  2083. combatlog.mdealt.dot || combatlog.mdealt.hit || combatlog.mdealt.miss || combatlog.mdealt.evade || combatlog.mdealt.resist,
  2084. ptaken: combatlog.ptaken.hit || combatlog.ptaken.miss || combatlog.ptaken.evade || combatlog.ptaken.parry || combatlog.ptaken.block,
  2085. mtaken: combatlog.mtaken.hit || combatlog.mtaken.evade || combatlog.mtaken.block,
  2086. pspirit: combatlog.ptaken.sfire || combatlog.ptaken.scold || combatlog.ptaken.selec || combatlog.ptaken.swind || combatlog.ptaken.sholy ||
  2087. combatlog.ptaken.sdark || combatlog.ptaken.scrushing || combatlog.ptaken.sslashing || combatlog.ptaken.spiercing || combatlog.ptaken.svoid,
  2088. mspirit: combatlog.mtaken.sfire || combatlog.mtaken.scold || combatlog.mtaken.selec || combatlog.mtaken.swind || combatlog.mtaken.sholy ||
  2089. combatlog.mtaken.sdark || combatlog.mtaken.scrushing || combatlog.mtaken.sslashing || combatlog.mtaken.spiercing || combatlog.mtaken.svoid,
  2090. hit: combatlog.pdealt.hit || combatlog.mdealt.hit || combatlog.ptaken.hit || combatlog.mtaken.hit,
  2091. r50: combatlog.mdealt.r50 || combatlog.mtaken.r50,
  2092. r75: combatlog.mdealt.r75 || combatlog.mtaken.r75,
  2093. r90: combatlog.mdealt.r90 || combatlog.mtaken.r90,
  2094. miss: combatlog.pdealt.miss || combatlog.mdealt.miss || combatlog.ptaken.miss,
  2095. evade: combatlog.pdealt.evade || combatlog.mdealt.evade || combatlog.ptaken.evade || combatlog.mtaken.evade,
  2096. parry: combatlog.pdealt.parry || combatlog.ptaken.parry,
  2097. resist: combatlog.mdealt.resist,
  2098. block: combatlog.ptaken.block || combatlog.mtaken.block };
  2099. if ( !any.pdealt && !any.mdealt && !any.ptaken && !any.mtaken ) return;
  2100. any.dtotal = any.pdealt && any.mdealt;
  2101. any.ttotal = any.ptaken && any.mtaken || any.pspirit || any.mspirit;
  2102. any.none = any.miss || any.evade || any.parry || any.resist || any.block;
  2103. const Row = function(type) {
  2104. return any[type] ? '</tr><tr><td>' + type + '</td>' +
  2105. (any.pdealt ? '<td>' + (combatlog.pdealt[type] ? combatlog.pdealt[type].toLocaleString() : '') + '</td>' : '') +
  2106. (any.mdealt ? '<td>' + (combatlog.mdealt[type] ? combatlog.mdealt[type].toLocaleString() : '') + '</td>' : '') +
  2107. (any.dtotal ? '<td>' + (combatlog.pdealt[type] || combatlog.mdealt[type] ?
  2108. ((combatlog.pdealt[type] ? combatlog.pdealt[type] : 0) + (combatlog.mdealt[type] ? combatlog.mdealt[type] : 0)).toLocaleString() : '') + '</td>' : '') +
  2109. (any.ptaken ? '<td>' + (combatlog.ptaken[type] ? combatlog.ptaken[type].toLocaleString() : '') + '</td>' : '') +
  2110. (any.pspirit ? '<td>' + (combatlog.ptaken['s'+type] ? combatlog.ptaken['s'+type].toLocaleString() : '') + '</td>' : '') +
  2111. (any.mtaken ? '<td>' + (combatlog.mtaken[type] ? combatlog.mtaken[type].toLocaleString() : '') + '</td>' : '') +
  2112. (any.mspirit ? '<td>' + (combatlog.mtaken['s'+type] ? combatlog.mtaken['s'+type].toLocaleString() : '') + '</td>' : '') +
  2113. (any.ttotal ? '<td>' + (combatlog.ptaken[type] || combatlog.mtaken[type] ?
  2114. ((combatlog.ptaken[type] ? combatlog.ptaken[type] : 0) + (combatlog.ptaken['s'+type] ? combatlog.ptaken['s'+type]: 0) +
  2115. (combatlog.mtaken[type] ? combatlog.mtaken[type] : 0) + (combatlog.mtaken['s'+type] ? combatlog.mtaken['s'+type] : 0)).toLocaleString() : '') +
  2116. '</td>' : '') : ''; },
  2117. Column = function(type, s) {
  2118. return (combatlog[type][s+'fire'] ? combatlog[type][s+'fire'] : 0) + (combatlog[type][s+'cold'] ? combatlog[type][s+'cold'] : 0) +
  2119. (combatlog[type][s+'elec'] ? combatlog[type][s+'elec'] : 0) + (combatlog[type][s+'wind'] ? combatlog[type][s+'wind'] : 0) +
  2120. (combatlog[type][s+'holy'] ? combatlog[type][s+'holy'] : 0) + (combatlog[type][s+'dark'] ? combatlog[type][s+'dark'] : 0) +
  2121. (combatlog[type][s+'crushing'] ? combatlog[type][s+'crushing'] : 0) + (combatlog[type][s+'slashing'] ? combatlog[type][s+'slashing'] : 0) +
  2122. (combatlog[type][s+'piercing'] ? combatlog[type][s+'piercing'] : 0) + (combatlog[type][s+'void'] ? combatlog[type][s+'void'] : 0) +
  2123. (combatlog[type][s+'dot'] ? combatlog[type][s+'dot'] : 0); },
  2124. ColumnNone = function(type) {
  2125. return (combatlog[type].miss ? combatlog[type].miss : 0) + (combatlog[type].evade ? combatlog[type].evade : 0) +
  2126. (combatlog[type].parry ? combatlog[type].parry : 0) + (combatlog[type].resist ? combatlog[type].resist : 0) +
  2127. (combatlog[type].block ? combatlog[type].block : 0); },
  2128. Count = function(type) {
  2129. return '<td>' + type + '</td>' +
  2130. (any.pdealt ? '<td>' + (combatlog.pdealt[type] ? combatlog.pdealt[type].toLocaleString() : '') + '</td>' : '') +
  2131. (any.mdealt ? '<td>' + (combatlog.mdealt[type] ? combatlog.mdealt[type].toLocaleString() : '') + '</td>' : '') +
  2132. (any.dtotal ? '<td>' + (combatlog.pdealt[type] || combatlog.mdealt[type] ?
  2133. (combatlog.pdealt[type] + combatlog.mdealt[type]).toLocaleString() : '') + '</td>' : '') +
  2134. (any.ptaken ? '<td>' + (combatlog.ptaken[type] ? combatlog.ptaken[type].toLocaleString() : '') + '</td>' : '') +
  2135. (any.pspirit ? '<td>' + (combatlog.ptaken['s'+type] ? combatlog.ptaken['s'+type].toLocaleString() : '') + '</td>' : '') +
  2136. (any.mtaken ? '<td>' + (combatlog.mtaken[type] ? combatlog.mtaken[type].toLocaleString() : '') + '</td>' : '') +
  2137. (any.mspirit ? '<td>' + (combatlog.mtaken['s'+type] ? combatlog.mtaken['s'+type].toLocaleString() : '') + '</td>' : '') +
  2138. (any.ttotal ? '<td>' + (combatlog.ptaken[type] || combatlog.mtaken[type] ?
  2139. (combatlog.ptaken[type] + combatlog.mtaken[type]).toLocaleString() : '') + '</td>' : ''); };
  2140. var total = { pdealt: Column('pdealt', ''), mdealt: Column('mdealt', ''),
  2141. ptaken: Column('ptaken', ''), pspirit: Column('ptaken', 's'),
  2142. mtaken: Column('mtaken', ''), mspirit: Column('mtaken', 's'),
  2143. pdnone: ColumnNone('pdealt'), mdnone: ColumnNone('mdealt'),
  2144. ptnone: ColumnNone('ptaken'), mtnone: ColumnNone('mtaken'), };
  2145. total.dealt = total.pdealt + total.mdealt;
  2146. total.taken = total.ptaken + total.pspirit + total.mtaken + total.mspirit;
  2147. total.dnone = total.pdnone + total.mdnone;
  2148. total.tnone = total.ptnone + total.mtnone;
  2149. var damagelog = log.parentNode.insertBefore(document.createElement('table'), log);
  2150. damagelog.id = 'damagelog';
  2151. damagelog.innerHTML = '<tbody><tr><td></td>' +
  2152. (any.pdealt || any.mdealt ? '<td' + (any.dtotal ? ' colspan="3"' : '') + '>damage dealt</td>' : '') +
  2153. (any.ptaken || any.mtaken ? '<td' + (any.ttotal ? ' colspan="' +
  2154. ((any.ptaken ? 1 : 0) + (any.mtaken ? 1 : 0) + (any.pspirit ? 1 : 0) + (any.mspirit ? 1 : 0) + 1) + '"' : '') + '>damage taken</td>' : '') +
  2155. '</tr><tr><td></td>' +
  2156. (any.pdealt ? '<td>physical</td>' : '') + (any.mdealt ? '<td>magical</td>' : '') +
  2157. (any.dtotal ? '<td>total</td>' : '') +
  2158. (any.ptaken ? '<td>physical</td>' : '') + (any.pspirit ? '<td style="border-left:none">spirit</td>' : '') +
  2159. (any.mtaken ? '<td>magical</td>' : '') + (any.mspirit ? '<td style="border-left:none">spirit</td>' : '') +
  2160. (any.ttotal ? '<td>total</td>' : '') +
  2161. Row('fire') + Row('cold') + Row('elec') + Row('wind') + Row('holy') + Row('dark') + Row('crushing') + Row('slashing') + Row('piercing') + Row('void') + Row('dot') +
  2162. '</tr><tr><td>total</td>' +
  2163. (any.pdealt ? '<td>' + total.pdealt.toLocaleString() + '</td>' : '') + (any.mdealt ? '<td>' + total.mdealt.toLocaleString() + '</td>' : '') +
  2164. (any.dtotal ? '<td>' + total.dealt.toLocaleString() + '</td>' : '') +
  2165. (any.ptaken ? '<td>' + total.ptaken.toLocaleString() + '</td>' : '') + (any.pspirit ? '<td>' + total.pspirit.toLocaleString() + '</td>' : '') +
  2166. (any.mtaken ? '<td>' + total.mtaken.toLocaleString() + '</td>' : '') + (any.mspirit ? '<td>' + total.mspirit.toLocaleString() + '</td>' : '') +
  2167. (any.ttotal ? '<td>' + total.taken.toLocaleString() + '</td>' : '') +
  2168. (any.hit ? '</tr><tr style="border-top:1px solid">' + Count('hit') + '</tr><tr>' + Count('crit') +
  2169. (any.r50 ? '</tr><tr>' + Count('r50') : '') + (any.r75 ? '</tr><tr>' + Count('r75') : '') + (any.r90 ? '</tr><tr>' + Count('r90') : '') : '') +
  2170. (any.none ? '</tr><tr style="border-top:1px solid">' + (any.miss ? '</tr><tr>' + Count('miss') : '') + (any.evade ? '</tr><tr>' + Count('evade') : '') +
  2171. (any.parry ? '</tr><tr>' + Count('parry') : '') + (any.resist ? '</tr><tr>' + Count('resist') : '') + (any.block ? '</tr><tr>' + Count('block') : ''): '') +
  2172. (any.none ? '</tr><tr><td>total</td>' +
  2173. (any.pdealt ? '<td>' + total.pdnone.toLocaleString() + '</td>' : '') + (any.mdealt ? '<td>' + total.mdnone.toLocaleString() + '</td>' : '') +
  2174. (any.dtotal ? '<td>' + total.dnone.toLocaleString() + '</td>' : '') +
  2175. (any.ptaken ? '<td>' + total.ptnone.toLocaleString() + '</td>' : '') + (any.pspirit ? '<td></td>' : '') +
  2176. (any.mtaken ? '<td>' + total.mtnone.toLocaleString() + '</td>' : '') + (any.mspirit ? '<td></td>' : '') +
  2177. (any.ttotal ? '<td>' + total.tnone.toLocaleString() + '</td>' : '') : '') + '</tr></tbody>'; }
  2178.  
  2179. function ShowUsage() {
  2180. if ( !cfg.trackUsage || JSON.stringify(combatlog.used) == '{}' ) return;
  2181. var td = log.insertBefore(document.createElement('tbody'), log.firstChild).appendChild(document.createElement('tr')).appendChild(document.createElement('td'));
  2182. td.className = 'tlb';
  2183. td.innerHTML = 'Used: ' + JSON.stringify(combatlog.used).replace('{','').replace('}','').replace(/"/g,'').replace(/:/g,': ').replace(/,/g,', '); }
  2184.  
  2185. function NoPopup() {
  2186. var btcp;
  2187. if ( !(btcp = document.getElementById('btcp')) ) return;
  2188. if ( cfg.ajaxRound ) {
  2189. btcp.onclick = function() {
  2190. var x = new XMLHttpRequest();
  2191. x.onreadystatechange = function() {
  2192. if ( x.readyState == XMLHttpRequest.DONE ) {
  2193. if ( x.status == 200 ) {
  2194. var doc = (new DOMParser()).parseFromString(x.responseText, 'text/html');
  2195. document.body.innerHTML = doc.body.innerHTML;
  2196. var script = document.createElement('script');
  2197. script.type = 'text/javascript';
  2198. if ( doc.getElementById('riddlemaster') ) {
  2199. script.innerHTML = document.getElementsByTagName('script')[2].innerHTML.replace(
  2200. 'e("riddleanswer").value = "?";', '').replace('e("riddleform").submit();', ''); }
  2201. else {
  2202. script.innerHTML = 'var t = setTimeout(function(){}, 0); for ( var i = t; i > 0' +
  2203. (cfg.ajaxIntervals ? ' && i > t - ' + cfg.ajaxIntervals : '') +
  2204. '; i-- ) clearInterval(i); battle = new Battle();'; }
  2205. document.getElementById('mainpane').appendChild(script);
  2206. var event = new Event('DOMContentLoaded');
  2207. document.dispatchEvent(event); }
  2208. else {
  2209. alert('error during round transition: code ' + x.status); }}};
  2210. x.open('GET', document.location.href, true);
  2211. x.send(); };}
  2212. monsterData = {};
  2213. localStorage.removeItem('HVmonsterData');
  2214. if ( cfg.showRound ) {
  2215. timelog.round++; }
  2216. if ( cfg.noPopup && (!cfg.stopOnEquipDrop || !regexp.quality[cfg.equipmentCutoff].test(log.innerHTML)) ) {
  2217. btcp.click(); }
  2218. else {
  2219. btcp.setAttribute('style', 'display: block'); }}
  2220.  
  2221. // main function running out of combat
  2222. function OutOfCombat() {
  2223. DeleteLog();
  2224. ProfileSwitch();
  2225. SettingsLink(); }
  2226.  
  2227. // out-of-combat helper functions
  2228. function DeleteLog() {
  2229. localStorage.removeItem('HVmonsterData' + isekai);
  2230. localStorage.removeItem('HVtimelog' + isekai);
  2231. localStorage.removeItem('HVvitals' + isekai);
  2232. localStorage.removeItem('HVcursor' + isekai);
  2233. if ( cfg.deleteDropLog == 2 || (cfg.deleteDropLog == 1 && document.URL.indexOf('Battle') < 0) ) {
  2234. localStorage.removeItem('HVtrackdrops' + isekai); }
  2235. if ( cfg.deleteCombatLog == 2 || (cfg.deleteCombatLog == 1 && document.URL.indexOf('Battle') < 0) ) {
  2236. localStorage.removeItem('HVcombatlog' + isekai); }}
  2237.  
  2238. function ProfileSwitch() {
  2239. if ( !cfg.profileAutoswitch ) return;
  2240. var choice;
  2241. if ( (choice = document.querySelector('[name="persona_set"] [selected]')) ) {
  2242. profile[(isekai ? 'i' : '') + 'p'] = choice.value; }
  2243. if ( (choice = document.querySelector(['[src*="equip/set"][src$="_on.png"]'])) ) {
  2244. profile[(isekai ? 'i' : '') + 's' + profile[(isekai ? 'i' : '') + 'p']] = parseInt(choice.src.match(regexp.number)); }
  2245. if ( JSON.stringify(profile) != localStorage.HVmbp ) {
  2246. localStorage.HVmbp = JSON.stringify(profile); }}
  2247.  
  2248. function SettingsLink() {
  2249. var character;
  2250. if ( !cfg.cfgInterface || !(character = document.getElementById('child_Character')) ) return;
  2251. var div = character.firstChild.appendChild(document.createElement('div')),
  2252. link = div.appendChild(document.createElement('div')),
  2253. def = regexp.defaultletter.test(character.innerHTML);
  2254. document.head.appendChild(document.createElement('style')).innerHTML = '#mbsettings { cursor: pointer; }' +
  2255. '#mbsettings:hover #mbprofile { visibility: visible; } #mbprofile { visibility: hidden; position: relative; left: ' + (def ? '223' : '175') +
  2256. 'px; top: -' + (def ? '9' : '25') + 'px; display: block; width: max-content; height: max-content; padding: 5px; background: #EDEBDF; border: 1px solid #5C0D11; }';
  2257. div.id = 'mbsettings';
  2258. link.onclick = Settings;
  2259. link.className = def ? 'fl f4b' : 'fc4 fal fcb';
  2260. if ( def ) {
  2261. character.style.width = '228px';
  2262. link.appendChild(document.createElement('div')).className = 'c5m';
  2263. link.appendChild(document.createElement('div')).className = 'c5o';
  2264. link.appendChild(document.createElement('div')).className = 'c5n';
  2265. link.appendChild(document.createElement('div')).className = 'c5s';
  2266. link.appendChild(document.createElement('div')).className = 'c5t';
  2267. link.appendChild(document.createElement('div')).className = 'c5e';
  2268. link.appendChild(document.createElement('div')).className = 'c5r';
  2269. link.appendChild(document.createElement('div')).className = 'c5b';
  2270. link.appendChild(document.createElement('div')).className = 'c5a';
  2271. link.appendChild(document.createElement('div')).className = 'c5t';
  2272. link.appendChild(document.createElement('div')).className = 'c5i';
  2273. link.appendChild(document.createElement('div')).className = 'c5o';
  2274. link.appendChild(document.createElement('div')).className = 'c5n';
  2275. link.appendChild(document.createElement('div')).className = 'c59';
  2276. link.appendChild(document.createElement('div')).className = 'c5s';
  2277. link.appendChild(document.createElement('div')).className = 'c5e';
  2278. link.appendChild(document.createElement('div')).className = 'c5t';
  2279. link.appendChild(document.createElement('div')).className = 'c5t';
  2280. link.appendChild(document.createElement('div')).className = 'c5i';
  2281. link.appendChild(document.createElement('div')).className = 'c5n';
  2282. link.appendChild(document.createElement('div')).className = 'c5g';
  2283. link.appendChild(document.createElement('div')).className = 'c5s'; }
  2284. else {
  2285. link.appendChild(document.createElement('div')).innerHTML = 'Monsterbation Settings'; }
  2286. var hasper = regexp.profile.test(JSON.stringify(cfg.persona));
  2287. var hasisk = regexp.profile.test(JSON.stringify(cfg.isekai.persona)) || (hasper && cfg.isekaiInherit);
  2288. if ( (!isekai && hasper) || (isekai && hasisk) ) {
  2289. var menu = div.appendChild(document.createElement('div'));
  2290. const Set = function(i, p, s) {
  2291. return function() {
  2292. var blue;
  2293. if ( (blue = menu.querySelector('[style*="' + (isekai ? 'red' : 'blue') + '"')) ) {
  2294. blue.style.color = ''; }
  2295. profile[isekai + 'p'] = p;
  2296. if (p) {
  2297. profile[isekai + 's' + profile[isekai + 'p']] = s; }
  2298. if ( JSON.stringify(profile) != localStorage.HVmbp ) {
  2299. localStorage.HVmbp = JSON.stringify(profile); }
  2300. i.style.color = isekai ? 'red' : 'blue'; };};
  2301. menu.id = 'mbprofile';
  2302. menu.className = 'fc4 fal fcb';
  2303. var base = menu.appendChild(document.createElement('div')), blue = false;
  2304. base.onclick = Set(base, 0, 0);
  2305. if ( !isekai ) {
  2306. base.innerHTML = cfg.name;
  2307. for ( var i = 0; i < cfg.persona.length; i++ ) {
  2308. if ( regexp.profile.test(JSON.stringify(cfg.persona[i])) ) {
  2309. var persona = menu.appendChild(document.createElement('div'));
  2310. persona.innerHTML = '- ' + cfg.persona[i].name;
  2311. persona.onclick = Set(persona, i+1, 0);
  2312. for ( var j = 0; j < cfg.persona[i].set.length; j++ ) {
  2313. if ( regexp.profile.test(JSON.stringify(cfg.persona[i].set[j])) ) {
  2314. var set = menu.appendChild(document.createElement('div'));
  2315. set.innerHTML = '-- ' + cfg.persona[i].set[j].name;
  2316. set.onclick = Set(set, i+1, j+1);
  2317. if ( profile.p == i+1 && profile['s' + profile.p] == j+1 ) {
  2318. set.style.color = 'blue';
  2319. blue = true; }}}
  2320. if ( profile.p == i+1 && (!blue || profile['s' + profile.p] == 0) ) {
  2321. persona.style.color = 'blue';
  2322. blue = true; }}}
  2323. if ( !blue || profile.p == 0 ) {
  2324. base.style.color = 'blue'; }}
  2325. else {
  2326. base.innerHTML = cfg.isekai.name;
  2327. for ( i = 0; i < cfg.isekai.persona.length; i++ ) {
  2328. hasisk = regexp.profile.test(JSON.stringify(cfg.isekai.persona[i]));
  2329. hasper = regexp.profile.test(JSON.stringify(cfg.persona[i])) && cfg.isekaiInherit;
  2330. if ( hasisk || hasper ) {
  2331. persona = menu.appendChild(document.createElement('div'));
  2332. persona.innerHTML = '- ' + (hasisk ? cfg.isekai.persona[i].name : cfg.persona[i].name);
  2333. persona.onclick = Set(persona, i+1, 0);
  2334. for ( j = 0; j < cfg.isekai.persona[i].set.length; j++ ) {
  2335. hasisk = regexp.profile.test(JSON.stringify(cfg.isekai.persona[i].set[j]));
  2336. hasper = regexp.profile.test(JSON.stringify(cfg.persona[i].set[j])) && cfg.isekaiInherit;
  2337. if ( hasisk || hasper ) {
  2338. set = menu.appendChild(document.createElement('div'));
  2339. set.innerHTML = '-- ' + (hasisk ? cfg.isekai.persona[i].set[j].name : cfg.persona[i].set[j].name);
  2340. set.onclick = Set(set, i+1, j+1);
  2341. if ( profile.ip == i+1 && profile['is' + profile.ip] == j+1 ) {
  2342. set.style.color = 'red';
  2343. blue = true; }}}
  2344. if ( profile.ip == i+1 && (!blue || profile['is' + profile.ip] == 0) ) {
  2345. persona.style.color = 'red';
  2346. blue = true; }}}
  2347. if ( !blue || profile.ip == 0 ) {
  2348. base.style.color = 'red'; }}}}
  2349.  
  2350. function LoadCfg(p, s, i) {
  2351. var local, value;
  2352. if ( settings.cfgInterface && (local = localStorage.HVmbcfg) ) {
  2353. local = JSON.parse(local); }
  2354. var persona = local && local.persona ? local.persona : settings.persona;
  2355. var isk = local && local.isekai ? local.isekai : settings.isekai;
  2356. for ( var setting in settings ) {
  2357. cfg[setting] = i && p && s && ((value = isk.persona[p-1].set[s-1].settings[setting]) || value === false || value === 0) ? value :
  2358. ((!i || cfg.isekaiInherit) && p && s && ((value = persona[p-1].set[s-1].settings[setting]) || value === false || value === 0) ? value :
  2359. (i && p && ((value = isk.persona[p-1].settings[setting]) || value === false || value === 0) ? value :
  2360. ((!i || cfg.isekaiInherit) && p && ((value = persona[p-1].settings[setting]) || value === false || value === 0) ? value :
  2361. (i && ((value = isk.settings[setting]) || value === false || value === 0) ? value :
  2362. (local && ((value = local[setting]) || value === false || value === 0) ? value : settings[setting])))));
  2363. if ( typeof(settings[setting]) == 'object' && !(settings[setting] instanceof Array) ) {
  2364. for ( var item in settings[setting] ) {
  2365. if ( !cfg[setting][item] && !(cfg[setting][item] === false) ) {
  2366. cfg[setting][item] = settings[setting][item]; }}}}
  2367. cfg.bind = cfg.bind.replace(regexp.whitespace,''); }
  2368.  
  2369. function StoreTmp() {
  2370. if ( (cfg.showMonsterHP || cfg.shortenHPbars || cfg.monsterKeywords) && JSON.stringify(monsterData) != '{}' ) {
  2371. localStorage['HVmonsterData' + isekai] = JSON.stringify(monsterData); }
  2372. if ( cfg.showCooldowns || cfg.trackSpeed || cfg.showRound ) {
  2373. localStorage['HVtimelog' + isekai] = JSON.stringify(timelog); }
  2374. if ( cfg.trackDamage || cfg.trackUsage ) {
  2375. localStorage['HVcombatlog' + isekai] = JSON.stringify(combatlog); }
  2376. if ( cfg.maxVitals && JSON.stringify(vitals) != localStorage['HVvitals' + isekai] ) {
  2377. localStorage['HVvitals' + isekai] = JSON.stringify(vitals); }
  2378. if ( cfg.trackDrops || cfg.trackProficiency || cfg.proficiencySidebar ) {
  2379. localStorage['HVtrackdrops' + isekai] = JSON.stringify(droplog); }
  2380. if ( cursor >= 0 ) localStorage['HVcursor' + isekai] = cursor; }
  2381.  
  2382. // default font parser
  2383. function ParseDefault(div) {
  2384. var string = '', letters = div.innerHTML.match(regexp.defaultstring);
  2385. for ( var j = 0; j < letters.length; j++ ) {
  2386. string += letters[j].match(regexp.defaultletter)[1]; }
  2387. return string; }
  2388.  
  2389. if ( !profile.p ) { profile.p = 0; }
  2390. if ( !profile.ip ) { profile.ip = 0; }
  2391. for ( var i = 1; i < 10; i++ ) {
  2392. if ( !profile['s' + i] ) { profile['s' + i] = 0; }
  2393. if ( !profile['is' + i] ) { profile['is' + i] = 0; }}
  2394. if ( !droplog.Mats ) { droplog.Mats = {}; }
  2395. LoadCfg(profile[isekai + 'p'], profile[isekai + 's' + profile[isekai + 'p']], isekai);
  2396. if ( document.getElementById('textlog') || document.getElementById('riddlemaster') ) {
  2397. Enhance();
  2398. document.addEventListener('DOMContentLoaded', Enhance);
  2399. window.addEventListener('beforeunload', StoreTmp); }
  2400. else { OutOfCombat(); }