// ==UserScript== // @name ktns // @version 1.0.0 // @author jonrhall // @description A kittens visualization engine // @match http://bloodrizer.ru/games/kittens/ // @namespace https://github.com/jonrhall // @grant GM_addStyle // @require https://d3js.org/d3.v3.min.js // @require https://gist.githubusercontent.com/jonrhall/9fb5f6f0a820763704c6635e57602eb5/raw/6eb742223b9795260ba62150196ed0ae4a461e39/bullet.js // ==/UserScript== !function(e){var t={};function n(r){if(t[r])return t[r].exports;var a=t[r]={i:r,l:!1,exports:{}};return e[r].call(a.exports,a,a.exports,n),a.l=!0,a.exports}n.m=e,n.c=t,n.d=function(e,t,r){n.o(e,t)||Object.defineProperty(e,t,{enumerable:!0,get:r})},n.r=function(e){"undefined"!=typeof Symbol&&Symbol.toStringTag&&Object.defineProperty(e,Symbol.toStringTag,{value:"Module"}),Object.defineProperty(e,"__esModule",{value:!0})},n.t=function(e,t){if(1&t&&(e=n(e)),8&t)return e;if(4&t&&"object"==typeof e&&e&&e.__esModule)return e;var r=Object.create(null);if(n.r(r),Object.defineProperty(r,"default",{enumerable:!0,value:e}),2&t&&"string"!=typeof e)for(var a in e)n.d(r,a,function(t){return e[t]}.bind(null,a));return r},n.n=function(e){var t=e&&e.__esModule?function(){return e.default}:function(){return e};return n.d(t,"a",t),t},n.o=function(e,t){return Object.prototype.hasOwnProperty.call(e,t)},n.p="",n(n.s=0)}([function(e,t,n){"use strict";n.r(t);const r={positive:"green",negative:"red",text:"#bbb",highlight:"white",marker:"red"};GM_addStyle(`\n #ktns-button {\n position: absolute;\n bottom: 3rem;\n right: 2rem;\n width: 50px;\n height: 50px;\n border-radius: 30px;\n cursor: pointer;\n border:1px solid #495267; display:inline-block;text-shadow: -1px -1px 0 rgba(0,0,0,0.3);\n background-color: #606c88; background-image: -webkit-gradient(linear, left top, left bottom, from(#606c88), to(#3f4c6b));\n background-image: -webkit-linear-gradient(top, #606c88, #3f4c6b);\n background-image: -moz-linear-gradient(top, #606c88, #3f4c6b);\n background-image: -ms-linear-gradient(top, #606c88, #3f4c6b);\n background-image: -o-linear-gradient(top, #606c88, #3f4c6b);\n background-image: linear-gradient(to bottom, #606c88, #3f4c6b);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr=#606c88, endColorstr=#3f4c6b);\n }\n\n #ktns-button:hover {\n border:1px solid #363d4c;\n background-color: #4b546a; background-image: -webkit-gradient(linear, left top, left bottom, from(#4b546a), to(#2c354b));\n background-image: -webkit-linear-gradient(top, #4b546a, #2c354b);\n background-image: -moz-linear-gradient(top, #4b546a, #2c354b);\n background-image: -ms-linear-gradient(top, #4b546a, #2c354b);\n background-image: -o-linear-gradient(top, #4b546a, #2c354b);\n background-image: linear-gradient(to bottom, #4b546a, #2c354b);filter:progid:DXImageTransform.Microsoft.gradient(GradientType=0,startColorstr=#4b546a, endColorstr=#2c354b);\n }\n\n #ktns-button img {\n position: relative;\n left: 9px;\n top: 9px;\n }\n\n #ktns-hook {\n position: absolute;\n bottom: 7rem;\n right: 5rem;\n padding: 1rem 0;\n border: 1px solid #737373;\n background-color: #1a1815;\n font-family: "Arial", sans-serif;\n width: 400px;\n overflow: hidden;\n display: none;\n }\n\n #ktns-hook.active {\n display: block;\n }\n\n .bullet { font: 10px sans-serif; }\n .bullet .marker { stroke: transparent; stroke-width: 2px; transition: stroke 0.2s; transition-delay: 0.4s }\n .bullet .marker.selected { stroke: ${r.marker}; transition: stroke 0.2s; }\n .bullet .tick line { stroke: #666; stroke-width: .5px; }\n .bullet .tick text { fill: ${r.text}; }\n .bullet:hover .tick text, .bullet.selected .tick text { fill: ${r.highlight}; }\n .bullet .range.s0 { fill: #eee; }\n .bullet .range.s1 { fill: #c9c9c9; }\n .bullet .range.s2 { fill: #a2a2a2; }\n .bullet .measure.s0 { fill: lightsteelblue; }\n .bullet .measure.s1 { fill: steelblue; }\n .bullet .title { font-size: 14px; font-weight: bold; fill: ${r.text}; letter-spacing: 0.5px; }\n .bullet:hover .title, .bullet.selected .title { fill: ${r.highlight}; }\n .bullet .subtitle { fill: ${r.text}; }\n .bullet:hover .subtitle, .bullet.selected .subtitle { fill: ${r.highlight}; }\n`);var a={colors:r};const l=e=>e>999?`${Math.round(e/1e3*100)/100}k`:`${e}`;var o={formatNumber:l,generateSubtitle:e=>`${Math.round(100*e.value)/100} / ${l(e.maxValue)}`,generateRate:e=>Math.round(game.getResourcePerTick(e.type,!0)*game.getTicksPerSecondUI()*100)/100,generateRange:(e,t)=>{const n=e.maxValue,r=60*t.rate;let a=e.value+5*r,l=e.value+15*r;return a<0&&(a=0),l<0&&(l=0),[d3.min([a,n]),d3.min([l,n]),n]},displayRate:({rate:e})=>e>0?`+${e}/s`:e<0?`${e}/s`:"0/s"};const i=()=>{const e=document.createElement("div");return e.setAttribute("id","ktns-button"),e.innerHTML='\n \n ',document.body.appendChild(e),e},s=()=>{const e=document.createElement("div");return e.setAttribute("id","ktns-hook"),document.body.appendChild(e),e},c=(e,t)=>d3.bullet().width(e).height(t).tickFormat(o.formatNumber),u=(e,t)=>n=>{const r=e[n.type];n.subtitle=o.generateSubtitle(r),n.measures=[r.value,r.value];const a=t.find(e=>e.name===n.type);return n.markers[0]=a?r.value-a.val<0?1:r.value-a.val:0,n.rate=o.generateRate(n),n.ranges=o.generateRange(r,n),n},d=(e,t)=>e.map(({title:e,name:n})=>({title:e.charAt(0).toUpperCase()+e.substr(1).toLowerCase(),type:n,subtitle:o.generateSubtitle(t[n]),ranges:[0,0,t[n].maxValue],measures:[t[n].value,t[n].value],markers:[0],rate:o.generateRate({type:n})}));var b=function(e){const t=i(),n=s(),r=d3.select("#ktns-hook"),l={top:5,right:100,bottom:20,left:100},b=440-l.left-l.right,g=50-l.top-l.bottom,m=c(b,g);let p=gamePage.resPool.resources.filter(e=>e.maxValue>0&&!e.isHidden&&e.unlocked&&e.visible),f=!1,k=[];const h=()=>{gamePage.tabs[0].buttons.forEach(e=>{$(e.domNode).hover(()=>{k=e.model.prices},()=>{k=[]})})},A=$("#gameContainerId")[0],v={attributes:!0,childList:!0,subtree:!1},x=new MutationObserver(e=>{for(let t of e)"childList"==t.type&&h()}),y=e=>n.setAttribute("class",e?"active":"");let M;function w(){y(!0),f=!0;const t=d(p,e),n=r.selectAll("svg").data(t).enter().append("svg").attr("class","bullet").attr("width",b+l.left+l.right-40).attr("height",g+l.top+l.bottom).append("g").attr("transform","translate("+l.left+","+l.top+")").call(m),i=n.append("g").style("text-anchor","end").attr("transform","translate(-6,"+g/2+")"),s=n.append("g").attr("transform",`translate(${b+5},${g/2+1})`),c=()=>s.append("text").attr("class","rate").attr("fill",e=>e.rate>-1?a.colors.positive:a.colors.negative).text(o.displayRate),h=()=>i.append("text").attr("class","subtitle").attr("dy","1em").text(function(e){return e.subtitle});c(),(()=>i.append("text").attr("class","title").text(function(e){return e.title}))(),h(),M=setInterval(()=>{n.datum(u(e,k)).call(m.duration(400)),n.selectAll(".bullet .marker").attr("class",e=>`marker ${e>0?"selected":""}`),r.selectAll("svg").attr("class",e=>k.find(t=>t.name===e.type)?"bullet selected":"bullet"),i.selectAll(".subtitle").remove(),h(),s.selectAll(".rate").remove(),c()},400)}t.onclick=()=>{f?(r.selectAll("svg").remove(),f=!1,y(!1)):(M&&(clearInterval(M),M=null),w())},setInterval(()=>{if(M&&f){const e=gamePage.resPool.resources.filter(e=>e.maxValue>0&&!e.isHidden&&e.unlocked&&e.visible);e.length!==p.length&&(clearInterval(M),p=e,r.selectAll("svg").remove(),w())}},1e3),h(),x.observe(A,v),w()};(()=>{!function(){let e;const t=setInterval(()=>{try{e=game.resPool.resourceMap}catch(e){return}clearInterval(t),setTimeout(()=>{b(e),console.log("KTNS loaded")},300)},100)}()})()}]);