Greasy Fork is available in English.

Pendoria - Chance to die

Implements some extra information per finished fight in the battle view on pendoria.

  1. // ==UserScript==
  2. // @name Pendoria - Chance to die
  3. // @description Implements some extra information per finished fight in the battle view on pendoria.
  4. // @namespace http://pendoria.net/
  5. // @version 0.0.33
  6. // @author Xortrox
  7. // @contributor Tester: euphone
  8. // @contributor Tester: fourkade
  9. // @contributor Coder: Kidel
  10. // @match http://pendoria.net/game
  11. // @match https://pendoria.net/game
  12. // @match http://www.pendoria.net/game
  13. // @match https://www.pendoria.net/game
  14. // @grant none
  15. // ==/UserScript==
  16.  
  17. (function () {
  18. function showChanceToDie(data) {
  19. let playerHealth = $('#php-value')[0];
  20.  
  21. if (!playerHealth) {
  22. return console.log('playerHealth element was not found.');
  23. }
  24.  
  25. let fightDiv = $('#fight')[0];
  26.  
  27. if (!fightDiv) {
  28. return console.log('fightDiv element was not found.');
  29. }
  30.  
  31. let playerHPBackground = $('#php-background')[0];
  32.  
  33. if (!playerHPBackground) {
  34. return console.log('playerHPBackground element was not found.');
  35. }
  36.  
  37. function createHistoricallyLowestHealthTrackerIfNotExists() {
  38. let historicallyLowestHPTracker = $('#ctdInfoHistoriallyLowestDiv')[0];
  39.  
  40. if(!historicallyLowestHPTracker) {
  41. let infoDiv = document.createElement('div');
  42. infoDiv.id = 'ctdInfoHistoriallyLowestDiv';
  43. playerHPBackground.parentElement.prepend(infoDiv);
  44. }
  45.  
  46. return historicallyLowestHPTracker;
  47. }
  48.  
  49. function createInfoDivIfNotExists() {
  50. let ctdInfoDiv = $('#ctdInfoDiv')[0];
  51.  
  52. if (!ctdInfoDiv) {
  53. let infoDiv = document.createElement('div');
  54. infoDiv.id = 'ctdInfoDiv';
  55. fightDiv.parentElement.appendChild(infoDiv);
  56. }
  57.  
  58. return ctdInfoDiv;
  59. }
  60.  
  61. let enemyHitChanceFactor = data.monsterChanceToHit / 100.0;
  62.  
  63. let playerMaxHealth = data.playerMaxLife;
  64. let enemyAverageDamage = data.damageTaken / data.hitsTaken;
  65.  
  66. let enemyHitsToKill = Math.ceil(playerMaxHealth / enemyAverageDamage);
  67.  
  68. let playerChanceFactorDeath = enemyHitChanceFactor ** enemyHitsToKill;
  69.  
  70. let playerHitChanceFactor = data.playerChanceToHit / 100.0;
  71.  
  72.  
  73. let playerAverageDamage = data.damageDone / data.timesHit;
  74.  
  75. let enemyMaxHealth = data.monsterMaxLife;
  76.  
  77. let enemyMaxHealthWithChanceFactor = (enemyMaxHealth / playerHitChanceFactor);
  78. let playerHitsToKillEnemy = Math.ceil(enemyMaxHealthWithChanceFactor / playerAverageDamage);
  79. let playerHitsToKillEnemyNoChanceFactor = Math.ceil(enemyMaxHealth / playerAverageDamage);
  80.  
  81. // console.log('enemyHitsToKill:', enemyHitsToKill);
  82. // console.log('playerHitChanceFactor:', playerHitChanceFactor);
  83. // console.log('(1 - (1 - playerHitChanceFactor) ** enemyHitsToKill) * 100');
  84. // let playerWinChance = (1 - (1 - playerHitChanceFactor) ** playerHitsToKillEnemyNoChanceFactor) * 100
  85.  
  86. let enemyChanceFactorDeath = playerHitChanceFactor ** playerHitsToKillEnemy;
  87.  
  88. let likelinessPrediction = ``;
  89.  
  90. // TODO: Make this based on some amount of % within proximity of max healths and damages.
  91. if (playerHitsToKillEnemy < enemyHitsToKill) {
  92. likelinessPrediction +=
  93. `It seems <b style="color:lightgreen">unlikely</b> that you will die as the enemy is required to hit you ${enemyHitsToKill} times, but you need to hit it roughly ${playerHitsToKillEnemy} times.<br>
  94. <br>
  95. `;
  96. } else if (playerHitsToKillEnemy >= enemyHitsToKill){
  97. likelinessPrediction +=
  98. `It seems <b style="color:red">likely</b> that you will die as the enemy needs to hit you ${enemyHitsToKill} times, but you need to hit it roughly ${playerHitsToKillEnemy} times.<br>
  99. <br>
  100. `;
  101. }
  102.  
  103. let ctdInfoDiv = createInfoDivIfNotExists();
  104.  
  105. let diffHits = enemyHitsToKill - playerHitsToKillEnemy;
  106.  
  107. if (ctdInfoDiv){
  108. ctdInfoDiv.innerHTML =
  109. `
  110. <div style="border-bottom: 1px solid white; margin-bottom: 3px;">
  111. Chance to die<button id="ctdClearHistoricalTracker" style="padding-top: 0; padding-bottom: 0; height:21px; border: 1px solid white; background: transparent; border-radius: 0; float:right; line-height: 21px;">Reset lowest health tracker</button>
  112. </div>
  113. ${likelinessPrediction}
  114. You would die after <b style="color:red;">${enemyHitsToKill}</b>~ rounds of battle if the enemy is still alive.<br>
  115. You would win after <b style="color:lightgreen;">${playerHitsToKillEnemy}</b>~ rounds of battle.<br>
  116. <br>
  117. You have a chance of ${(((1 - playerHitChanceFactor) ** diffHits) * 100).toPrecision(3)}%~ to miss enough in order to receive ${enemyHitsToKill} hits from this enemy, which would kill you.<br>
  118. `
  119. }
  120.  
  121. /**
  122. * Bind click event of ctdClearHistoricalTracker
  123. * */
  124. $('#ctdClearHistoricalTracker').click(() => {
  125. let pendCtdSettings = window.localStorage.getItem('PendoriaChanceToDie');
  126. if (pendCtdSettings) {
  127. pendCtdSettings = JSON.parse(pendCtdSettings);
  128. }
  129.  
  130. delete(pendCtdSettings.historiallyLowestHealth);
  131.  
  132. localStorage.setItem('PendoriaChanceToDie', JSON.stringify(pendCtdSettings));
  133. });
  134.  
  135. playerCurrentHealth = data.playerLife;
  136. if (playerCurrentHealth < 0) {
  137. playerCurrentHealth = 0;
  138. }
  139.  
  140. // console.log('playerCurrentHealth:', playerCurrentHealth);
  141.  
  142. let ctdInfoHistoriallyLowestDiv = createHistoricallyLowestHealthTrackerIfNotExists();
  143.  
  144. // TODO: Also show how many hits you took and for what average damage the hits were, in the tooltip
  145. if(ctdInfoHistoriallyLowestDiv) {
  146. let pendCtdSettings = window.localStorage.getItem('PendoriaChanceToDie');
  147. if (!pendCtdSettings) {
  148. pendCtdSettings = {
  149. historiallyLowestHealth: playerCurrentHealth
  150. };
  151.  
  152. localStorage.setItem('PendoriaChanceToDie', JSON.stringify(pendCtdSettings));
  153. } else {
  154. pendCtdSettings = JSON.parse(pendCtdSettings);
  155.  
  156. if (pendCtdSettings.historiallyLowestHealth === undefined) {
  157. pendCtdSettings.historiallyLowestHealth = playerCurrentHealth
  158. localStorage.setItem('PendoriaChanceToDie', JSON.stringify(pendCtdSettings));
  159. }
  160. }
  161.  
  162. if (playerCurrentHealth < pendCtdSettings.historiallyLowestHealth) {
  163. pendCtdSettings.historiallyLowestHealth = playerCurrentHealth;
  164. localStorage.setItem('PendoriaChanceToDie', JSON.stringify(pendCtdSettings))
  165. }
  166.  
  167. let playerHealthPercentage = (pendCtdSettings.historiallyLowestHealth / playerMaxHealth * 100);
  168.  
  169. /**
  170. * Only update qtip if the contents changed.
  171. **/
  172. if (ctdInfoHistoriallyLowestDiv.innerText !== commarize(pendCtdSettings.historiallyLowestHealth)) {
  173. setTimeout(() => {
  174. $('#php-value').qtip({
  175. style: {
  176. classes: 'qtip-dark'
  177. },
  178. position: {
  179. target: $('#ctdInfoHistoriallyLowestDiv'),
  180. at: 'bottom left'
  181. },
  182. content: {
  183. text: pendCtdSettings.historiallyLowestHealth,
  184. // title: 'Historically lowest health'
  185. }
  186. });
  187. })
  188. }
  189.  
  190. ctdInfoHistoriallyLowestDiv.innerText = commarize(pendCtdSettings.historiallyLowestHealth);
  191. ctdInfoHistoriallyLowestDiv.style =
  192. `
  193. z-index: 9999;
  194. position: absolute;
  195. background-color: #14723c;
  196. height: 25px;
  197. line-height: 26px;
  198. padding-left: 5px;
  199. border-radius: 10px;
  200. font-size: 12px;
  201. width: ${playerHealthPercentage}%;
  202. `;
  203.  
  204. playerHealth.style.zIndex = '9999';
  205. }
  206. }
  207.  
  208. $(function () {
  209. function load() {
  210. if(window.socket) {
  211. socket.on('battle data', (data) => {
  212. showChanceToDie(data);
  213. });
  214. } else {
  215. setTimeout(load, 500);
  216. }
  217. }
  218. load();
  219. });
  220.  
  221.  
  222. /**
  223. * Appends a suffix to the number and shortens it generally.
  224. * */
  225. function commarize(number) {
  226. if(number < 999999) { return number; }
  227. var sizes = [
  228. '',
  229. '',
  230. 'Mill',
  231. 'Bill',
  232. 'Trill',
  233. 'Quad',
  234. 'Quint',
  235. 'Sext',
  236. 'Sept',
  237. 'Oct'
  238. ];
  239. if (number == 0) return '0 Byte';
  240. var i = parseInt(Math.floor(Math.log(number) / Math.log(1000)));
  241. return (number / Math.pow(1000, i)).toPrecision(4) + ' ' + sizes[i];
  242. }
  243.  
  244. /**
  245. * Shows the full precision of a number up to 100 digits.
  246. * */
  247. function fullZeroes(number) {
  248. return number.toFixed(100).replace(/.?0+$/,"") // 0.0000005
  249. }
  250.  
  251. /**
  252. * Takes a number string
  253. * */
  254. function fourLastDigits(numberString) {
  255. let index = 0;
  256. let theValAfterDot = numberString.substr(numberString.indexOf('.') + 1);
  257.  
  258. while(theValAfterDot[index] === '0'){
  259. index++;
  260. }
  261. return '0.' + theValAfterDot.substr(0, index + 3)
  262. }
  263. }());