R00t Success Chance

Calculates success chance for r00t field actions.

目前为 2014-06-15 提交的版本。查看 最新版本

  1. // ==UserScript==
  2. // @name R00t Success Chance
  3. // @description Calculates success chance for r00t field actions.
  4. // @namespace http://userscripts.org/users/dtkarlsson
  5. // @include http://*animecubed.com/billy/bvs/villagefields*
  6. // @licence MIT; http://www.opensource.org/licenses/mit-license.php
  7. // @copyright 2009, Daniel Karlsson
  8. // @version 0.10.0
  9. // @history 0.10.0 Added rough estimate of max difficulty
  10. // @history 0.9.1 Text was supposed to be white, now it is
  11. // ==/UserScript==
  12.  
  13. var jutsuTypes = {
  14. gen: "Genjutsu",
  15. nin: "Ninjutsu",
  16. tai: "Taijutsu",
  17. dou: "Doujutsu"
  18. }
  19. var basicJutsuTypes = {
  20. gen: "Genjutsu",
  21. nin: "Ninjutsu",
  22. tai: "Taijutsu"
  23. }
  24.  
  25. function Ability()
  26. {
  27. this.lvl = 0;
  28. this.str = 0;
  29. this.rng = 0;
  30. this.suc = 0;
  31. }
  32.  
  33. function Ninja()
  34. {
  35. this.gen = new Ability();
  36. this.nin = new Ability();
  37. this.tai = new Ability();
  38. this.dou = new Ability();
  39. }
  40.  
  41. function Challenge()
  42. {
  43. this.dif = 0;
  44. this.suc = 0;
  45. }
  46.  
  47. function Mission()
  48. {
  49. this.gen = new Challenge();
  50. this.nin = new Challenge();
  51. this.tai = new Challenge();
  52. this.dou = new Challenge();
  53. this.order = [];
  54. this.crank = 0;
  55. }
  56.  
  57. // Math stuff below
  58.  
  59. function binomialCoefficient(n, k)
  60. {
  61. // n!/[k!(n-k)!]
  62. if (k > n || k < 0)
  63. return 0;
  64. k = Math.max(k, n - k);
  65. var i = 1;
  66. var j = k + 1;
  67. var c = 1;
  68. // i = 1 ... n-k => (n-k)!
  69. // j = k+1 ... n => n!/k!
  70. while (j <= n)
  71. c *= j++ / i++;
  72. return c;
  73. }
  74.  
  75. function binomdist(k, n, p, cumulative)
  76. {
  77. // Cumulative distribution, k or less successes in n trials
  78. if (cumulative) {
  79. var sum = 0;
  80. for (var i = 0; i <= k; i++)
  81. sum += binomdist(i, n, p, false);
  82. return sum;
  83. }
  84. // Exactly k successes in n trials with probability p
  85. return binomialCoefficient(n, k) * Math.pow(p, k) * Math.pow(1 - p, n - k);
  86. }
  87.  
  88. function successChance(challenge, ability, crank)
  89. {
  90. if (!crank)
  91. crank = 0;
  92.  
  93. // Successful rolls required
  94. var req = (challenge.suc + crank)- ability.suc;
  95. if (req > ability.lvl)
  96. return 0;
  97. else if (req <= 0)
  98. return 1;
  99.  
  100. if ((challenge.dif + crank) > ability.rng)
  101. return 0;
  102.  
  103. // Success probability per roll
  104. var prob = (ability.str + ability.rng - (challenge.dif + crank) + 1) / ability.rng;
  105.  
  106. if (prob >= 1)
  107. return 1;
  108.  
  109. return Math.min(0.9999, 1 - binomdist(req - 1, ability.lvl, prob, true));
  110. }
  111.  
  112. function expectedSuccesses(challenge, ability, crank)
  113. {
  114. if (!crank)
  115. crank = 0;
  116.  
  117. if ((challenge.dif + crank) > ability.rng)
  118. return 0;
  119.  
  120. // Success probability per roll
  121. var prob = (ability.str + ability.rng - (challenge.dif + crank) + 1) / ability.rng;
  122. return ability.suc + Math.min(1, prob) * ability.lvl;
  123. }
  124.  
  125. function percent(n)
  126. {
  127. if (n == 1.0)
  128. return "100%";
  129. else if (n == 0.0)
  130. return "0%";
  131. var p = Math.round(n * 1000) / 10;
  132. if (p > 99.9)
  133. return ">99.9%";
  134. else if (p < 0.1)
  135. return "<0.1%";
  136. return p + "%";
  137. }
  138.  
  139. // Parsing
  140.  
  141. function parseAbilities()
  142. {
  143. var ninja = new Ninja();
  144. var tables = document.evaluate("//table[count(descendant::table)=4]//table",
  145. document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
  146. for (var i = 0; i < tables.snapshotLength; i++) {
  147. var ab = new Ability();
  148. var type = "";
  149. var lines = tables.snapshotItem(i).textContent.split(/\n/);
  150. for (var l in lines) {
  151. var m;
  152. m = lines[l].match(/Suc: (\d+)( \(\+(\d+)\))?/);
  153. if (m) {
  154. ab.suc += parseInt(m[1]);
  155. if (m[3])
  156. ab.suc += parseInt(m[3]);
  157. continue;
  158. }
  159. m = lines[l].match(/Str: (\d+)( \(\+(\d+)\))?/);
  160. if (m) {
  161. ab.str += parseInt(m[1]);
  162. if (m[3])
  163. ab.str += parseInt(m[3]);
  164. continue;
  165. }
  166. m = lines[l].match(/Rng: (\d+)( \(\+(\d+)\))?/);
  167. if (m) {
  168. ab.rng += parseInt(m[1]);
  169. if (m[3])
  170. ab.rng += parseInt(m[3]);
  171. continue;
  172. }
  173. m = lines[l].match(/Lvl: (\d+)( \(\+(\d+)\))?/);
  174. if (m) {
  175. ab.lvl += parseInt(m[1]);
  176. if (m[3])
  177. ab.lvl += parseInt(m[3]);
  178. continue;
  179. }
  180. m = lines[l].match(/(\w{3}): (\d+)/);
  181. if (m) {
  182. type = m[1].toLowerCase();
  183. ab.lvl += parseInt(m[2]);
  184. continue;
  185. }
  186. }
  187. ninja[type] = ab;
  188. }
  189.  
  190. return ninja;
  191. }
  192.  
  193. function parseMission()
  194. {
  195. var tables = document.evaluate("//table[count(descendant::table)=0]",
  196. document, null, XPathResult.UNORDERED_NODE_SNAPSHOT_TYPE, null);
  197. var node = null;
  198. var mission = new Mission();
  199. for (var i = 0; i < tables.snapshotLength; i++) {
  200. var txt = tables.snapshotItem(i).textContent;
  201. if (/virus attack/i.test(txt)) {
  202. var lines = txt.split(/\n/);
  203. // Gen D: 15 S: 15
  204. for (var l in lines) {
  205. var line = lines[l].replace(/\s+/g, " ");
  206. var m = line.match(/(\w{3}) D: (\d+) S: (\d+)/);
  207. if (m) {
  208. var type = m[1].toLowerCase();
  209. mission[type].dif = parseInt(m[2]);
  210. mission[type].suc = parseInt(m[3]);
  211. node = tables.snapshotItem(i);
  212. }
  213. }
  214. break;
  215. }
  216. }
  217. if (node)
  218. return {mission: mission, node: node};
  219. }
  220.  
  221. var ninja = parseAbilities();
  222. var missionNode = parseMission();
  223.  
  224. if (missionNode) {
  225. var mission = missionNode.mission;
  226. var node = missionNode.node;
  227. var p = 1;
  228. for (var t in jutsuTypes) {
  229. p *= successChance(mission[t], ninja[t]);
  230. }
  231. var tr = document.createElement("tr");
  232. var td = document.createElement("td");
  233. td.textContent = "Success chance: " + percent(p);
  234. td.style.color = "white";
  235. tr.appendChild(td);
  236. node.firstChild.appendChild(tr);
  237. }
  238.  
  239. // Rough estimate of average field difficulty
  240. function fieldChallenge(diff)
  241. {
  242. diff = Math.min(230, diff);
  243. diff = Math.max(0, diff);
  244. var c = new Challenge();
  245. c.dif = Math.round(0.13 * diff + 15);
  246. c.suc = Math.round(0.11 * diff + 15);
  247. return c;
  248. }
  249.  
  250. // Calculate max difficulty a ninja can reliably handle
  251. var diff, p;
  252. for (diff = 230; diff >= 0; diff -= 5) {
  253. p = 1;
  254. for (var t in basicJutsuTypes)
  255. p = Math.min(p, successChance(fieldChallenge(diff), ninja[t]));
  256. if (p > 0.95)
  257. break;
  258. }
  259. var form = document.getElementsByName("field")[0];
  260. var div = document.createElement("div");
  261. div.textContent = "Recommended difficulty (estimate): " + diff + " (" + percent(p) + ")";
  262. form.parentNode.insertBefore(div, form);

QingJ © 2025

镜像随时可能失效,请加Q群300939539或关注我们的公众号极客氢云获取最新地址