Kitten Extrapolation

A script for outputting information about kitten survival (Other features may come later)

  1. // ==UserScript==
  2. // @name Kitten Extrapolation
  3. // @namespace https://greasyfork.org/en/scripts/10234-kitten-extrapolation
  4. // @version 0.7.7
  5. // @description A script for outputting information about kitten survival (Other features may come later)
  6. // @author Lily
  7. // @match http://bloodrizer.ru/games/kittens/*
  8. // @match https://bloodrizer.ru/games/kittens/*
  9. // @exclude http://bloodrizer.ru/games/kittens/wiki*
  10. // @exclude https://bloodrizer.ru/games/kittens/wiki*
  11. // @grant none
  12. // ==/UserScript==
  13.  
  14. var KE_seasons = {
  15. "Spring": 1.5,
  16. "Summer": 1,
  17. "Autumn": 1,
  18. "Winter": 0.25
  19. };
  20.  
  21. var KE_weathers = {
  22. "Warm": 0.15,
  23. "Norm": 0.0,
  24. "Cold": -0.15
  25. };
  26.  
  27. var KE_seasons_reverse_Lookup = {
  28. 0 : "Spring",
  29. 1 : "Summer",
  30. 2 : "Autumn",
  31. 3 : "Winter"
  32. };
  33.  
  34. function KE_calcTitaniumChance()
  35. {
  36. if(0.35*gamePage.resPool.get("ship").value+15>100){
  37. return 100;
  38. }else{
  39. return 0.35*gamePage.resPool.get("ship").value+15;
  40. }
  41. }
  42.  
  43. var KE_seasonal_trading = {
  44. "Lizards" : {
  45. "wood" : {
  46. "Spring": "<font color=red>↓↓</font>",
  47. "Summer": "<font color=limegreen>↑↑</font>",
  48. "Autumn": "<font color=limegreen>↑</font>",
  49. "Winter": "<font color=red>↓</font>",
  50. "Best": "Summer",
  51. "Chance": 100
  52. }
  53. },
  54. "Sharks" : {
  55. "catnip" : {
  56. "Spring": "<font color=limegreen>↑</font>",
  57. "Summer": "<font color=red>↓↓</font>",
  58. "Autumn": "<font color=red>↓</font>",
  59. "Winter": "<font color=limegreen>↑↑</font>",
  60. "Best": "Winter",
  61. "Chance": 100
  62. }
  63. },
  64. "Griffins" : {
  65. "iron" : {
  66. "Spring": "<font color=red>↓↓</font>",
  67. "Summer": "<font color=limegreen>↑</font>",
  68. "Autumn": "<font color=limegreen>↑↑</font>",
  69. "Winter": "<font color=red>↓</font>",
  70. "Best": "Autumn",
  71. "Chance": 100
  72. }
  73. },
  74. "Nagas" : {
  75. "minerals" : {
  76. "Spring": "<font color=limegreen>↑↑</font>",
  77. "Summer": "<font color=limegreen>↑</font>",
  78. "Autumn": "<font color=red>↓↓</font>",
  79. "Winter": "<font color=red>↓</font>",
  80. "Best": "Spring",
  81. "Chance": 100
  82. }
  83. },
  84. "Zebras" : {
  85. "iron" : {
  86. "Spring": "<font color=limegreen>↑</font>",
  87. "Summer": "<font color=limegreen>↑↑</font>",
  88. "Autumn": "<font color=red>↓</font>",
  89. "Winter": "<font color=red>↓↓</font>",
  90. "Best": "Summer",
  91. "Chance": 100
  92. },
  93. "plate" : {
  94. "Spring": "<font color=yellow>=</font>",
  95. "Summer": "<font color=red>↓↓</font>",
  96. "Autumn": "<font color=yellow>=</font>",
  97. "Winter": "<font color=limegreen>↑↑</font>",
  98. "Best": "Winter",
  99. "Chance": 65
  100. },
  101. "titanium" : {
  102. "Chance": KE_calcTitaniumChance
  103. }
  104. },
  105. "Spiders" : {
  106. "coal" : {
  107. "Spring": "<font color=red>↓</font>",
  108. "Summer": "<font color=limegreen>↑</font>",
  109. "Autumn": "<font color=limegreen>↑↑</font>",
  110. "Winter": "<font color=red>↓↓</font>",
  111. "Best": "Autumn",
  112. "Chance": 100
  113. }
  114. },
  115. "Dragons" : {
  116. "uranium" : {
  117. // "Spring": "<font color=red>↓</font>",
  118. // "Summer": "<font color=limegreen>↑</font>",
  119. // "Autumn": "<font color=limegreen>↑↑</font>",
  120. // "Winter": "<font color=red>↓↓</font>",
  121. // "Best": "Autumn",
  122. "Chance": 95
  123. }
  124. },
  125. "Leviathans" : {
  126. "time crystal" : {
  127. "Chance": 98
  128. },
  129. "sorrow" : {
  130. "Chance": 15
  131. },
  132. "starchart" : {
  133. "Chance": 50
  134. },
  135. "relic" : {
  136. "Chance": 5
  137. }
  138. }
  139. };
  140.  
  141. function KE_generate_food_table_cell(tag="", contents = "", colspan = 1){
  142. var cell = document.createElement("td");
  143. if(tag != ""){
  144. cell.setAttribute("id",tag);
  145. }
  146. cell.style.textAlign="text-align:center";
  147. cell.append(contents)
  148. if(colspan != 1){
  149. cell.setAttribute("colspan","4")
  150. }
  151. return cell;
  152. }
  153.  
  154. function KE_generate_food_table_line(line_name, line_tag) {
  155. var line = document.createElement("tr");
  156. var cell = document.createElement("td");
  157. cell.style.textAlign="text-align:center";
  158. cell.append(line_name);
  159. line.append(cell);
  160. line.append(KE_generate_food_table_cell(line_tag+'Sp'));
  161. line.append(KE_generate_food_table_cell(line_tag+'Su'));
  162. line.append(KE_generate_food_table_cell(line_tag+'A'));
  163. line.append(KE_generate_food_table_cell(line_tag+'W'));
  164. return line;
  165. }
  166.  
  167. function KE_generate_food_table() {
  168. //Creating the enclosing div for the table
  169. var enclosing_div = document.createElement("div");
  170. enclosing_div.setAttribute("width","340px");
  171. //Making the table itself
  172. var table = document.createElement("table");
  173. table.setAttribute("id","food_table_season");
  174. table.setAttribute("table-layout","fixed");
  175. //create/define the columns in the tables
  176. var column = document.createElement("col");
  177. column.setAttribute("width",60);
  178. table.append(column);
  179. for (var i = 0; i < 4; i++) {
  180. var column2 = document.createElement("col");
  181. column2.setAttribute("width",70);
  182. table.append(column2);
  183. }
  184. //create the top line of the table
  185. var topline = document.createElement("tr");
  186. topline.append(KE_generate_food_table_cell("cycle_warning"));
  187. topline.append(KE_generate_food_table_cell("","Food during seasons (/season)",4));
  188. table.append(topline);
  189. //Create second line of table
  190. var line2 = document.createElement("tr");
  191. line2.append(KE_generate_food_table_cell("","Weather"));
  192. line2.append(KE_generate_food_table_cell("KE_Spring","Spring"));
  193. line2.append(KE_generate_food_table_cell("KE_Summer","Summer"));
  194. line2.append(KE_generate_food_table_cell("KE_Autumn","Autumn"));
  195. line2.append(KE_generate_food_table_cell("KE_Winter","Winter"));
  196. table.append(line2);
  197. //Create the table's main cells/liens
  198. table.append(KE_generate_food_table_line('Warm', 'WS'));
  199. table.append(KE_generate_food_table_line('Norm', 'NS'));
  200. table.append(KE_generate_food_table_line('Cold', 'CS'));
  201. //append the table to the enclosing div
  202. enclosing_div.append(table);
  203. //Yearly food production calculation
  204. var yearly_food_produced = document.createElement("p");
  205. yearly_food_produced.setAttribute("id","yearly_food_produced");
  206. yearly_food_produced.style.marginBlockStart="2px";
  207. yearly_food_produced.style.marginBlockEnd="2px";
  208. enclosing_div.append(yearly_food_produced);
  209. return enclosing_div;
  210. }
  211.  
  212. //Calculates the reasource production for a season other then the current one.
  213. function KE_calcResourcePerTick_NCW(resName, season, weather)
  214. {
  215. if(resName == "catnip"){
  216. //Get data for the current weather
  217. var realWeatherMod = gamePage.calendar.getWeatherMod();
  218. //invert it
  219. var realWeatherModInverse = 0-realWeatherMod;
  220. //get the effective season+weather
  221. var mockSeasonWeatherMod = KE_seasons[season]+KE_weathers[weather];
  222. //Apply the inveser of the real weather to it to counter that it is going to be applied in the function
  223. mockSeasonWeatherMod = mockSeasonWeatherMod + realWeatherModInverse;
  224. return (gamePage.calcResourcePerTick(resName,{"modifiers" : {"catnip" : mockSeasonWeatherMod}})+gamePage.getResourcePerTickConvertion(resName));
  225. } else{
  226. return gamePage.calcResourcePerTick(resName)+gamePage.getResourcePerTickConvertion(resName);
  227. }
  228. }
  229.  
  230. function KE_update_food_table_cell(lable, season, weather)
  231. {
  232. var element_to_update = document.getElementById(lable);
  233. //Clear labeled element
  234. element_to_update.innerHTML = ""
  235. var updated_text = document.createElement("font");
  236. //Bold the current season/weather combo
  237. if(season == KE_seasons_reverse_Lookup[gamePage.calendar.season] && ((weather=="Norm" && gamePage.calendar.weather == null) || weather.toLowerCase() == gamePage.calendar.weather)){
  238. updated_text.setAttribute("class","msg type_date");
  239. updated_text.style.fontWeight = "bold";
  240. updated_text.style.borderBottomWidth = "0px";
  241. updated_text.style.fontSize = "14px";
  242. }
  243. //Get updated value
  244. updated_text.append(gamePage.getDisplayValueExt(KE_calcResourcePerTick_NCW("catnip",season,weather)*1000,true));
  245. //Close out font
  246. element_to_update.append(updated_text);
  247. return true;
  248. }
  249.  
  250. function KE_update_trade_screen()
  251. {
  252.  
  253. ///////////////////////////////////////////////////
  254. //Adding trade calculations, purely experimental //
  255. ///////////////////////////////////////////////////
  256. //Panel container is the class of all trade containers
  257. var trade_containers = document.getElementsByClassName("panelContainer")
  258. //Cycle through all trade containers
  259. for (var i = 0; i < trade_containers.length; i++) {
  260. //for every container
  261. if(typeof(trade_containers[i]) === 'object' && trade_containers[i].getElementsByClassName("title").length > 0)
  262. {
  263. try
  264. {
  265. var trade_partner = trade_containers[i].getElementsByClassName("title")[0].childNodes[0].nodeValue.trim()
  266. //////////////////////////////////////
  267. //Chance of success/bonus for trades//
  268. //////////////////////////////////////
  269. for (var j = 0; j<gamePage.diplomacy.races.length; j++){
  270. if(gamePage.diplomacy.races[j]["title"] == trade_partner){
  271. if(gamePage.diplomacy.races[j]["attitude"] != "neutral")
  272. {
  273. var standingRatio = gamePage.getEffect("standingRatio");
  274. standingRatio = standingRatio ? standingRatio : 0;
  275.  
  276. if (gamePage.prestige.getPerk("diplomacy").researched){
  277. standingRatio += 10;
  278. }
  279.  
  280. if(gamePage.diplomacy.races[j]["attitude"] == "friendly")
  281. {
  282. standingRatio = standingRatio/2;
  283. }
  284.  
  285. standingRatio += gamePage.diplomacy.races[j]["standing"]*100
  286. if (standingRatio > 100){
  287. standingRatio = 100;
  288. }
  289.  
  290. var append_string = "";
  291.  
  292. if(gamePage.diplomacy.races[j]["attitude"] == "friendly")
  293. {
  294. append_string = "(+"+gamePage.getDisplayValueExt(standingRatio)+"%)";
  295. }
  296.  
  297. if(gamePage.diplomacy.races[j]["attitude"] == "hostile")
  298. {
  299. append_string = "(-"+gamePage.getDisplayValueExt(100-standingRatio)+"%)";
  300. }
  301.  
  302. //Add standing info to the trade window.
  303. if(trade_containers[i].getElementsByClassName("title")[0].getElementsByClassName("attitude")[0].getElementsByClassName("trade-seasonal-appeal").length == 0){
  304. //If the block does not exist yet
  305. var appendnode = document.createElement("span");
  306. appendnode.setAttribute("class", "trade-seasonal-appeal");
  307. trade_containers[i].getElementsByClassName("title")[0].getElementsByClassName("attitude")[0].appendChild(appendnode);
  308. }
  309.  
  310. trade_containers[i].getElementsByClassName("title")[0].getElementsByClassName("attitude")[0].getElementsByClassName("trade-seasonal-appeal")[0].innerHTML = append_string;
  311. }
  312.  
  313. break;
  314. }
  315. }
  316.  
  317. //////////////////////////////////////////////
  318. //Colored arrows for race season prefrences.//
  319. //Should probobly be redone using the game's//
  320. //internal code //
  321. //////////////////////////////////////////////
  322. //Check if the trade partner is in seasonal_trading
  323. if(Object.keys(KE_seasonal_trading).indexOf(trade_partner) != -1){
  324. //get the list of all reasources for trade
  325. var reasource_containers = trade_containers[i].getElementsByClassName("trade-race")[0].getElementsByClassName("left")[0].children
  326. //cycle through them
  327. for (var j = 0; j < reasource_containers.length; j++) {
  328. //if this is a 'sell' type container (as opposed to the 'buy' containers)
  329. if(reasource_containers[j].getElementsByClassName("sells").length > 0)
  330. {
  331. //find out if this is a reasource that the race being looked at has a variable deal on based on seasons
  332. var trade_reasource = reasource_containers[j].childNodes[1].nodeValue.trim();
  333. if(Object.keys(KE_seasonal_trading[trade_partner]).indexOf(trade_reasource) != -1)
  334. {
  335. //Add the addjustment appearence to it.
  336. if(reasource_containers[j].getElementsByClassName("trade-seasonal").length == 0){
  337. //If the block does not exist yet
  338. var appendnode = document.createElement("span");
  339. appendnode.setAttribute("class", "trade-seasonal");
  340. reasource_containers[j].appendChild(appendnode);
  341. }
  342. var append_string = "";
  343. if(KE_seasonal_trading[trade_partner][trade_reasource]["Chance"]!=100){
  344. var string_add = document.createElement("span")
  345. if(typeof(KE_seasonal_trading[trade_partner][trade_reasource]["Chance"]) != 'function'){
  346. string_add.innerHTML = gamePage.getDisplayValueExt(KE_seasonal_trading[trade_partner][trade_reasource]["Chance"]) + "%";
  347. }else{
  348. string_add.innerHTML = gamePage.getDisplayValueExt(KE_seasonal_trading[trade_partner][trade_reasource]["Chance"]()) + "%";
  349. }
  350. string_add.setAttribute("class", "ammount");
  351. append_string += string_add.outerHTML;
  352. }
  353. if(KE_seasonal_trading[trade_partner][trade_reasource][KE_seasons_reverse_Lookup[gamePage.calendar.season]])
  354. {
  355. append_string += KE_seasonal_trading[trade_partner][trade_reasource][KE_seasons_reverse_Lookup[gamePage.calendar.season]];
  356. if(KE_seasons_reverse_Lookup[gamePage.calendar.season] != KE_seasonal_trading[trade_partner][trade_reasource]["Best"]){
  357. append_string += " (+" + KE_seasonal_trading[trade_partner][trade_reasource]["Best"] + ")";
  358. }
  359. }
  360. reasource_containers[j].getElementsByClassName("trade-seasonal")[0].innerHTML = append_string;
  361. }
  362. }
  363. }
  364. }
  365. }
  366. catch(err) {
  367. console.error("Error in adding trade container. ",err.message);
  368. }
  369. }else{
  370. console.log(typeof(trade_containers[i]), trade_containers[i]);
  371. }
  372.  
  373.  
  374. }
  375. }
  376.  
  377. function KE_update(){
  378. //Update all the food cells
  379. KE_update_food_table_cell("WSSp", "Spring", "Warm");
  380. KE_update_food_table_cell("WSSu", "Summer", "Warm");
  381. KE_update_food_table_cell("WSA", "Autumn", "Warm");
  382. KE_update_food_table_cell("WSW", "Winter", "Warm");
  383. KE_update_food_table_cell("NSSp", "Spring", "Norm");
  384. KE_update_food_table_cell("NSSu", "Summer", "Norm");
  385. KE_update_food_table_cell("NSA", "Autumn", "Norm");
  386. KE_update_food_table_cell("NSW", "Winter", "Norm");
  387. KE_update_food_table_cell("CSSp", "Spring", "Cold");
  388. KE_update_food_table_cell("CSSu", "Summer", "Cold");
  389. KE_update_food_table_cell("CSA", "Autumn", "Cold");
  390. KE_update_food_table_cell("CSW", "Winter", "Cold");
  391.  
  392. //Yearly production
  393. document.getElementById('yearly_food_produced').innerHTML = "Yearly food balance (avg): " + gamePage.getDisplayValueExt((KE_calcResourcePerTick_NCW("catnip", "Spring", "Norm")*1000) + (KE_calcResourcePerTick_NCW("catnip", "Summer", "Norm")*1000) + (KE_calcResourcePerTick_NCW("catnip", "Autumn", "Norm")*1000) + (KE_calcResourcePerTick_NCW("catnip", "Winter", "Norm")*1000), true);
  394.  
  395. var cycle = gamePage.calendar.cycles[gamePage.calendar.cycle];
  396. var element_to_update;
  397. element_to_update = document.getElementById("cycle_warning");
  398. if(cycle["name"]=="piscine"){
  399. element_to_update.innerHTML = '<font color="red">↑Piscine</font>'
  400. }else{
  401. element_to_update.innerHTML = ""
  402. }
  403.  
  404. //
  405.  
  406. //Trading
  407. KE_update_trade_screen();
  408.  
  409. //console.log(trade_reasource, Object.keys(seasonal_trading[trade_partner]).indexOf(trade_reasource));
  410.  
  411. return true;
  412. }
  413.  
  414. function KE_initiate_script() {
  415. var data_out = document.createElement('div');
  416. data_out.id = 'kitten_extrapolation_container';
  417. data_out.style.width = '100%';
  418. data_out.style.bottom = '0px';
  419. data_out.style.verticalAlign = 'bottom';
  420. data_out.innerHTML = "";
  421. data_out.append(KE_generate_food_table());
  422. var right_col = document.getElementById('rightColumn')
  423. right_col.style.width = '360px';
  424. var before_child = document.getElementsByClassName("right-tab-header")[0];
  425. right_col.insertBefore(data_out, before_child);
  426. setInterval(KE_update, 500);
  427. return true;
  428. }
  429.  
  430. function KE_initiate() {
  431. if (typeof gamePage == "object") {
  432. if (!document.getElementById('kitten_extrapolation_container')) {
  433. KE_initiate_script();
  434. }
  435. } else if(typeof gamePage == "undefined") {
  436. setTimeout(function(){
  437. KE_initiate();
  438. }, 100);
  439. }else{
  440. window.alert("Error E1 occured in Kitten Extrapolation! \nThis is most likely to occure if the game's code has been radically changed and Kitten Extrapolation needs updating or if the script is run on something other then the Kittens game.");
  441. }
  442. }
  443.  
  444. KE_initiate();
  445.  
  446. //Function for trimming strings.
  447. //Credit: David Andres (https://stackoverflow.com/questions/1418050/string-strip-for-javascript)
  448. if(typeof(String.prototype.trim) === "undefined")
  449. {
  450. String.prototype.trim = function()
  451. {
  452. return String(this).replace(/^\s+|\s+$/g, '');
  453. };
  454. }