1- // noinspection JSUnusedGlobalSymbols
1+ /**
2+ * @typedef {function } LoadScript
3+ */
4+ /**
5+ * @typedef {Object } Building
6+ * @property {number } price
7+ * @property {DocumentFragment } l
8+ */
9+ /**
10+ * @function l
11+ * @param {string } id
12+ */
13+ /**
14+ * @function Beautify
15+ * @param {number } number
16+ * @param {number } decimalPlaces
17+ */
18+ /**
19+ * @function PlaySound
20+ */
21+ /**
22+ * @typedef {Object } Game
23+ * @property {function } registerMod
24+ * @property {function } Has
25+ * @property {Object[] } GrandmaSynergies
26+ * @property {Object } GrandmaSynergies.buildingTie
27+ * @property {number } GrandmaSynergies.buildingTie.storedTotalCps
28+ * @property {Object.<string, Building> } Objects
29+ * @property {Building[] } ObjectsById
30+ * @property {Array } customOptionsMenu
31+ * @property {Array } Upgrades
32+ * @property {string } clickStr
33+ * @property {number } unbuffedCps
34+ * @property {number } globalCpsMult
35+ * @property {number } storedCps
36+ */
37+ /**
38+ * @typedef {Object } App
39+ * @property {Array } mods
40+ */
41+ /**
42+ * @typedef {Object } CCSE
43+ * @property {function } AppendCollapsibleOptionsMenu
44+ */
45+ LoadScript ( App . mods [ "Best Deal Helper" ] . dir + "/chroma.min.js" ) ;
246
347let BestDealHelper = {
448 name : "BestDealHelper" ,
549
650 config : {
7- sortbuildings : 0
51+ sortbuildings : 0 ,
852 } ,
953
1054 isLoaded : false ,
55+ load_chroma : false ,
1156
12- init : function ( ) {
57+ register : function ( ) {
58+ Game . registerMod ( this . name , this ) ;
59+ } ,
60+
61+ "init" : function ( ) {
1362 MOD = this ;
1463 Game . customOptionsMenu . push ( MOD . addOptionsMenu ) ;
1564 MOD . last_cps = 0 ;
@@ -22,34 +71,31 @@ let BestDealHelper = {
2271 MOD . isLoaded = true ;
2372 } ,
2473
25- load : function ( str ) {
74+ " load" : function ( str ) {
2675 const config = JSON . parse ( str ) ;
2776 for ( const c in config ) MOD . config [ c ] = config [ c ] ;
2877 MOD . sortBuildings ( ) ;
2978 } ,
3079
31- save : function ( ) {
80+ " save" : function ( ) {
3281 return JSON . stringify ( MOD . config ) ;
3382 } ,
3483
35- register : function ( ) {
36- Game . registerMod ( this . name , this ) ;
37- } ,
3884
3985 addOptionsMenu : function ( ) {
4086 const body = `
4187 <div class="listing">
42- ${ MOD . button ( ' sortbuildings' , ' Sort Buildings ON (default)' , ' Sort Buildings OFF' ) }
88+ ${ MOD . button ( " sortbuildings" , " Sort Buildings ON (default)" , " Sort Buildings OFF" ) }
4389 </div>` ;
4490
45- CCSE . AppendCollapsibleOptionsMenu ( MOD . name , body )
91+ CCSE . AppendCollapsibleOptionsMenu ( MOD . name , body ) ;
4692 } ,
4793
4894 logicLoop : function ( ) {
4995 if (
5096 MOD . last_cps !== Game . unbuffedCps
5197 || MOD . config . sortbuildings !== MOD . last_config_sortbuildings
52- || ! document . querySelector ( ' #normalizedCpspb0' )
98+ || ! document . querySelector ( " #normalizedCpspb0" )
5399 ) {
54100 MOD . sortBuildings ( ) ;
55101 MOD . last_config_sortbuildings = MOD . config . sortbuildings ;
@@ -60,7 +106,7 @@ let BestDealHelper = {
60106 let boost ;
61107 let other ;
62108 let synergyBoost = 0 ;
63- if ( me . name === ' Grandma' ) {
109+ if ( me . name === " Grandma" ) {
64110 for ( const i in Game . GrandmaSynergies ) {
65111 if ( Game . Has ( Game . GrandmaSynergies [ i ] ) ) {
66112 other = Game . Upgrades [ Game . GrandmaSynergies [ i ] ] . buildingTie ;
@@ -69,21 +115,35 @@ let BestDealHelper = {
69115 synergyBoost += boost ;
70116 }
71117 }
72- } else if ( me . name === ' Portal' && Game . Has ( ' Elder Pact' ) ) {
73- other = Game . Objects [ ' Grandma' ] ;
118+ } else if ( me . name === " Portal" && Game . Has ( " Elder Pact" ) ) {
119+ other = Game . Objects [ " Grandma" ] ;
74120 boost = ( me . amount * 0.05 * other . amount ) * Game . globalCpsMult ;
75121 synergyBoost += boost ;
76122 }
77123 return me . storedCps * Game . globalCpsMult + synergyBoost / Math . max ( me . amount , 1 ) ;
78124 } ,
125+ median : function ( values ) {
126+ if ( values . length === 0 ) return 0 ;
127+
128+ values . sort ( function ( a , b ) {
129+ return a - b ;
130+ } ) ;
79131
132+ const half = Math . floor ( values . length / 2 ) ;
133+
134+ if ( values . length % 2 ) {
135+ return values [ half ] ;
136+ }
137+
138+ return ( values [ half - 1 ] + values [ half ] ) / 2.0 ;
139+ } ,
80140 insertAfter : function ( newNode , referenceNode ) {
81141 referenceNode . parentNode . insertBefore ( newNode , referenceNode . nextSibling ) ;
82142 } ,
83143
84144 sortBuildings : function ( ) {
85- let buildings = [ ...Game . ObjectsById ]
86- buildings . forEach ( e => e . cpsPerCookie = MOD . boosted ( e ) / e . price )
145+ let buildings = [ ...Game . ObjectsById ] ;
146+ buildings . forEach ( e => e . cpsPerCookie = MOD . boosted ( e ) / e . price ) ;
87147
88148 // Sort buildings or leave them to default
89149 if ( MOD . config . sortbuildings ) {
@@ -94,50 +154,62 @@ let BestDealHelper = {
94154 }
95155
96156 // Sort buildings only if the order has changed
97- let buildings_order = buildings . map ( e => e . id )
157+ let buildings_order = buildings . map ( e => e . id ) ;
98158 if ( ! buildings_order . every ( ( value , index ) => value === MOD . last_buildings_order [ index ] ) ) {
99- let store = document . querySelector ( ' #products' )
159+ let store = document . querySelector ( " #products" ) ;
100160 for ( let i = 0 ; i < buildings . length ; ++ i ) {
101161 store . appendChild ( buildings [ i ] . l ) ;
102162 }
103- MOD . last_buildings_order = buildings_order
163+ MOD . last_buildings_order = buildings_order ;
104164 // Game.Notify(`Buildings are sorted!`, ``, [16, 5], 1.5, 1);
105165 }
106166
107167 // Normalization by Mean
108- buildings = buildings . filter ( o => o . locked === 0 )
109- const avg = buildings . map ( e => e . cpsPerCookie ) . reduce ( ( a , b ) => a + b , 0 ) / buildings . length ;
110- buildings . forEach ( e => e . cpsPerCookieDelta = e . cpsPerCookie / avg )
168+ buildings = buildings . filter ( o => o . locked === 0 ) ;
169+ const cpsPerCookieArr = buildings . map ( e => e . cpsPerCookie ) ;
170+ const avg = cpsPerCookieArr . reduce ( ( a , b ) => a + b , 0 ) / buildings . length ;
171+ let color = (
172+ chroma . scale ( [ "red" , "yellow" , "lightgreen" ] )
173+ . mode ( "lrgb" )
174+ . domain ( [ Math . min ( ...cpsPerCookieArr ) , MOD . median ( cpsPerCookieArr ) , Math . max ( ...cpsPerCookieArr ) ] )
175+ ) ;
176+
111177 for ( const i in buildings ) {
112178 let me = buildings [ i ] ;
113- let cpspb = document . querySelector ( "#normalizedCpspb" + me . id )
179+ let cpspb = document . querySelector ( "#normalizedCpspb" + me . id ) ;
114180 if ( ! cpspb ) {
115181 cpspb = document . createElement ( "span" ) ;
116182 cpspb . setAttribute ( "id" , "normalizedCpspb" + me . id ) ;
117- MOD . insertAfter ( cpspb , l ( 'productPrice' + me . id ) )
183+ cpspb . style . fontWeight = "bolder" ;
184+ MOD . insertAfter ( cpspb , l ( "productPrice" + me . id ) ) ;
118185 }
119- cpspb . textContent = "(💹" + Beautify ( me . cpsPerCookieDelta * 100 , 1 ) + "%)"
186+ cpspb . textContent = "(💹" + Beautify ( me . cpsPerCookie * 100 / avg , 1 ) + "%)" ;
187+ cpspb . style . color = color ( me . cpsPerCookie ) ;
188+
120189 }
121190 } ,
122191
123192 button : function ( config , texton , textoff ) {
124193 const name = `BestDealHelper${ config } button` ;
125- const callback = `BestDealHelper.buttonCallback('${ config } ', '${ name } ', '${ texton } ', '${ textoff } ');`
194+ const callback = `BestDealHelper.buttonCallback('${ config } ', '${ name } ', '${ texton } ', '${ textoff } ');` ;
126195 const value = MOD . config [ config ] ;
127- return `<a class="${ value ? ' option' : ' option off' } " id="${ name } " ${ Game . clickStr } ="${ callback } ">${ value ? texton : textoff } </a>`
196+ return `<a class="${ value ? " option" : " option off" } " id="${ name } " ${ Game . clickStr } ="${ callback } ">${ value ? texton : textoff } </a>` ;
128197 } ,
129198
130- buttonCallback : function ( config , button , texton , textoff ) {
199+ " buttonCallback" : function ( config , button , texton , textoff ) {
131200 const value = ! MOD . config [ config ] ;
132201 MOD . config [ config ] = value ;
133- l ( button ) . innerHTML = value ? texton : textoff
134- l ( button ) . className = value ? ' option' : ' option off'
135- PlaySound ( ' snd/tick.mp3' ) ;
202+ l ( button ) . innerHTML = value ? texton : textoff ;
203+ l ( button ) . className = value ? " option" : " option off" ;
204+ PlaySound ( " snd/tick.mp3" ) ;
136205 } ,
137206} ;
138207
139208// Bind methods
140- for ( func of Object . getOwnPropertyNames ( BestDealHelper ) . filter ( m => typeof BestDealHelper [ m ] === 'function' ) ) {
209+ for ( func of Object . getOwnPropertyNames ( BestDealHelper ) . filter ( m => typeof BestDealHelper [ m ] === "function" ) ) {
210+ /**
211+ * @typedef {string } func
212+ */
141213 BestDealHelper [ func ] = BestDealHelper [ func ] . bind ( BestDealHelper ) ;
142214}
143215
@@ -146,7 +218,9 @@ if (!BestDealHelper.isLoaded) {
146218 if ( CCSE && CCSE . isLoaded ) {
147219 BestDealHelper . register ( ) ;
148220 } else {
149- if ( ! CCSE ) var CCSE = { } ;
221+ if ( ! CCSE ) { // noinspection JSUnusedLocalSymbols
222+ let CCSE = { } ;
223+ }
150224 if ( ! CCSE . postLoadHooks ) CCSE . postLoadHooks = [ ] ;
151225 CCSE . postLoadHooks . push ( BestDealHelper . register ) ;
152226 }
0 commit comments