R00t Success Chance

Calculates success chance for r00t field actions.

目前為 2014-09-28 提交的版本,檢視 最新版本

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

QingJ © 2025

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