2020-10-11 20:16:36 +00:00
// ************ Big Feature related ************
function respecBuyables ( layer ) {
if ( ! layers [ layer ] . buyables ) return
if ( ! layers [ layer ] . buyables . respec ) return
2021-04-29 22:03:51 +00:00
if ( ! player [ layer ] . noRespecConfirm && ! confirm ( tmp [ layer ] . buyables . respecMessage || "Are you sure you want to respec? This will force you to do a \"" + ( tmp [ layer ] . name ? tmp [ layer ] . name : layer ) + "\" reset as well!" ) ) return
2020-12-13 04:32:55 +00:00
run ( layers [ layer ] . buyables . respec , layers [ layer ] . buyables )
2020-10-11 20:16:36 +00:00
updateBuyableTemp ( layer )
2020-12-07 04:40:06 +00:00
document . activeElement . blur ( )
2020-10-11 20:16:36 +00:00
}
2020-10-13 03:08:19 +00:00
function canAffordUpgrade ( layer , id ) {
2020-10-16 15:39:39 +00:00
let upg = tmp [ layer ] . upgrades [ id ]
2021-05-15 16:31:58 +00:00
if ( tmp [ layer ] . deactivated ) return false
2020-11-29 21:28:24 +00:00
if ( tmp [ layer ] . upgrades [ id ] . canAfford !== undefined ) return tmp [ layer ] . upgrades [ id ] . canAfford
2020-10-11 20:16:36 +00:00
let cost = tmp [ layer ] . upgrades [ id ] . cost
2021-01-06 20:56:06 +00:00
return canAffordPurchase ( layer , upg , cost )
2020-10-11 20:16:36 +00:00
}
2021-05-01 02:40:59 +00:00
function canBuyBuyable ( layer , id ) {
let b = temp [ layer ] . buyables [ id ]
2021-05-15 16:31:58 +00:00
return ( b . unlocked && run ( b . canAfford , b ) && player [ layer ] . buyables [ id ] . lt ( b . purchaseLimit ) && ! tmp [ layer ] . deactivated )
2021-05-01 02:40:59 +00:00
}
2021-05-12 02:13:14 +00:00
2020-10-11 20:16:36 +00:00
function canAffordPurchase ( layer , thing , cost ) {
2020-10-16 15:39:39 +00:00
2021-01-06 20:56:06 +00:00
if ( thing . currencyInternalName ) {
2020-10-11 20:16:36 +00:00
let name = thing . currencyInternalName
2021-01-06 20:56:06 +00:00
if ( thing . currencyLocation ) {
return ! ( thing . currencyLocation [ name ] . lt ( cost ) )
2020-10-16 15:39:39 +00:00
}
2021-01-06 20:56:06 +00:00
else if ( thing . currencyLayer ) {
2020-10-11 20:16:36 +00:00
let lr = thing . currencyLayer
2021-01-06 20:56:06 +00:00
return ! ( player [ lr ] [ name ] . lt ( cost ) )
2020-10-11 20:16:36 +00:00
}
else {
return ! ( player [ name ] . lt ( cost ) )
}
}
else {
return ! ( player [ layer ] . points . lt ( cost ) )
}
}
2020-10-19 23:52:52 +00:00
function buyUpgrade ( layer , id ) {
buyUpg ( layer , id )
}
2020-10-11 20:16:36 +00:00
function buyUpg ( layer , id ) {
2020-12-01 03:36:54 +00:00
if ( ! tmp [ layer ] . upgrades || ! tmp [ layer ] . upgrades [ id ] ) return
2020-11-29 21:28:24 +00:00
let upg = tmp [ layer ] . upgrades [ id ]
2020-10-13 03:08:19 +00:00
if ( ! player [ layer ] . unlocked ) return
2020-10-16 22:45:44 +00:00
if ( ! tmp [ layer ] . upgrades [ id ] . unlocked ) return
2020-10-11 20:16:36 +00:00
if ( player [ layer ] . upgrades . includes ( id ) ) return
2020-11-29 21:28:24 +00:00
if ( upg . canAfford === false ) return
let pay = layers [ layer ] . upgrades [ id ] . pay
if ( pay !== undefined )
2020-12-13 04:32:55 +00:00
run ( pay , layers [ layer ] . upgrades [ id ] )
2021-01-06 20:56:06 +00:00
else {
2020-11-29 21:28:24 +00:00
let cost = tmp [ layer ] . upgrades [ id ] . cost
2021-01-06 20:56:06 +00:00
if ( upg . currencyInternalName ) {
2020-11-29 21:28:24 +00:00
let name = upg . currencyInternalName
2021-01-06 20:56:06 +00:00
if ( upg . currencyLocation ) {
2020-11-29 21:28:24 +00:00
if ( upg . currencyLocation [ name ] . lt ( cost ) ) return
upg . currencyLocation [ name ] = upg . currencyLocation [ name ] . sub ( cost )
}
2021-01-06 20:56:06 +00:00
else if ( upg . currencyLayer ) {
2020-11-29 21:28:24 +00:00
let lr = upg . currencyLayer
if ( player [ lr ] [ name ] . lt ( cost ) ) return
player [ lr ] [ name ] = player [ lr ] [ name ] . sub ( cost )
}
else {
if ( player [ name ] . lt ( cost ) ) return
player [ name ] = player [ name ] . sub ( cost )
}
2020-10-11 20:16:36 +00:00
}
else {
2020-11-29 21:28:24 +00:00
if ( player [ layer ] . points . lt ( cost ) ) return
2021-01-06 20:56:06 +00:00
player [ layer ] . points = player [ layer ] . points . sub ( cost )
2020-10-11 20:16:36 +00:00
}
}
player [ layer ] . upgrades . push ( id ) ;
if ( upg . onPurchase != undefined )
2020-12-13 02:43:22 +00:00
run ( upg . onPurchase , upg )
2020-10-11 20:16:36 +00:00
}
function buyMaxBuyable ( layer , id ) {
2020-10-13 03:08:19 +00:00
if ( ! player [ layer ] . unlocked ) return
if ( ! tmp [ layer ] . buyables [ id ] . unlocked ) return
2021-05-15 16:31:58 +00:00
if ( ! tmp [ layer ] . buyables [ id ] . canBuy ) return
2020-10-11 20:16:36 +00:00
if ( ! layers [ layer ] . buyables [ id ] . buyMax ) return
2020-12-13 04:32:55 +00:00
run ( layers [ layer ] . buyables [ id ] . buyMax , layers [ layer ] . buyables [ id ] )
2020-10-11 20:16:36 +00:00
updateBuyableTemp ( layer )
}
function buyBuyable ( layer , id ) {
2020-10-13 03:08:19 +00:00
if ( ! player [ layer ] . unlocked ) return
if ( ! tmp [ layer ] . buyables [ id ] . unlocked ) return
2021-05-01 02:40:59 +00:00
if ( ! tmp [ layer ] . buyables [ id ] . canBuy ) return
2020-10-11 20:16:36 +00:00
2020-12-13 04:32:55 +00:00
run ( layers [ layer ] . buyables [ id ] . buy , layers [ layer ] . buyables [ id ] )
2020-10-11 20:16:36 +00:00
updateBuyableTemp ( layer )
}
function clickClickable ( layer , id ) {
2021-05-15 16:31:58 +00:00
if ( ! player [ layer ] . unlocked || tmp [ layer ] . deactivated ) return
2020-10-13 03:08:19 +00:00
if ( ! tmp [ layer ] . clickables [ id ] . unlocked ) return
2021-05-12 04:45:56 +00:00
if ( ! tmp [ layer ] . clickables [ id ] . canClick ) return
2020-10-11 20:16:36 +00:00
2020-12-13 04:32:55 +00:00
run ( layers [ layer ] . clickables [ id ] . onClick , layers [ layer ] . clickables [ id ] )
2020-10-11 20:16:36 +00:00
updateClickableTemp ( layer )
}
2021-05-11 06:27:50 +00:00
function clickGrid ( layer , id ) {
2021-05-15 16:31:58 +00:00
if ( ! player [ layer ] . unlocked || tmp [ layer ] . deactivated ) return
2021-05-11 06:27:50 +00:00
if ( ! run ( layers [ layer ] . grid . getUnlocked , layers [ layer ] . grid , id ) ) return
if ( ! gridRun ( layer , 'getCanClick' , player [ layer ] . grid [ id ] , id ) ) return
gridRun ( layer , 'onClick' , player [ layer ] . grid [ id ] , id )
}
2020-10-11 22:38:54 +00:00
// Function to determine if the player is in a challenge
2021-01-06 20:56:06 +00:00
function inChallenge ( layer , id ) {
2020-10-14 23:46:35 +00:00
let challenge = player [ layer ] . activeChallenge
2020-11-07 20:29:39 +00:00
if ( ! challenge ) return false
2020-10-17 21:04:38 +00:00
id = toNumber ( id )
2021-01-06 20:56:06 +00:00
if ( challenge == id ) return true
2020-10-11 22:38:54 +00:00
2020-10-13 03:08:19 +00:00
if ( layers [ layer ] . challenges [ challenge ] . countsAs )
2020-10-30 00:33:39 +00:00
return tmp [ layer ] . challenges [ challenge ] . countsAs . includes ( id )
2020-10-11 22:38:54 +00:00
}
2020-10-03 21:52:51 +00:00
// ************ Misc ************
var onTreeTab = true
function showTab ( name ) {
2020-10-13 03:08:19 +00:00
if ( LAYERS . includes ( name ) && ! layerunlocked ( name ) ) return
2021-05-14 19:43:10 +00:00
if ( player . tab !== name ) clearParticles ( function ( p ) { return p . layer === player . tab } )
2020-12-07 04:01:24 +00:00
if ( player . tab === name && isPlainObject ( tmp [ name ] . tabFormat ) ) {
2020-12-04 04:19:14 +00:00
player . subtabs [ name ] . mainTabs = Object . keys ( layers [ name ] . tabFormat ) [ 0 ]
}
2020-10-27 23:25:03 +00:00
var toTreeTab = name == "none"
2020-10-03 21:52:51 +00:00
player . tab = name
2020-11-01 03:05:50 +00:00
if ( player . navTab == "none" && ( tmp [ name ] . row !== "side" ) && ( tmp [ name ] . row !== "otherside" ) ) player . lastSafeTab = name
2020-10-03 21:52:51 +00:00
delete player . notify [ name ]
2021-05-10 01:39:15 +00:00
updateTabFormats ( )
2020-10-30 23:40:48 +00:00
needCanvasUpdate = true
2020-12-07 04:40:06 +00:00
document . activeElement . blur ( )
2021-05-10 01:39:15 +00:00
2020-10-30 23:40:48 +00:00
}
2020-11-07 20:29:39 +00:00
function showNavTab ( name ) {
if ( LAYERS . includes ( name ) && ! layerunlocked ( name ) ) return
2021-05-14 19:43:10 +00:00
if ( player . navTab !== name ) clearParticles ( function ( p ) { return p . layer === player . navTab } )
2020-11-07 20:29:39 +00:00
var toTreeTab = name == "tree"
player . navTab = name
player . notify [ name ] = false
2021-05-10 01:39:15 +00:00
updateTabFormats ( )
2020-11-07 20:29:39 +00:00
needCanvasUpdate = true
}
2020-10-30 23:40:48 +00:00
function goBack ( ) {
if ( player . navTab !== "none" ) showTab ( "none" )
2020-11-01 03:05:50 +00:00
else showTab ( player . lastSafeTab )
2020-10-03 21:52:51 +00:00
}
2020-11-02 23:44:36 +00:00
function layOver ( obj1 , obj2 ) {
for ( let x in obj2 ) {
2021-01-17 20:15:52 +00:00
if ( obj2 [ x ] instanceof Decimal ) obj1 [ x ] = new Decimal ( obj2 [ x ] )
else if ( obj2 [ x ] instanceof Object ) layOver ( obj1 [ x ] , obj2 [ x ] ) ;
2020-11-02 23:44:36 +00:00
else obj1 [ x ] = obj2 [ x ] ;
}
}
2020-11-08 04:34:53 +00:00
function prestigeNotify ( layer ) {
if ( layers [ layer ] . prestigeNotify ) return layers [ layer ] . prestigeNotify ( )
2021-04-29 22:33:12 +00:00
if ( isPlainObject ( tmp [ layer ] . tabFormat ) ) {
for ( subtab in tmp [ layer ] . tabFormat ) {
if ( subtabResetNotify ( layer , 'mainTabs' , subtab ) )
return true
}
}
for ( family in tmp [ layer ] . microtabs ) {
for ( subtab in tmp [ layer ] . microtabs [ family ] ) {
if ( subtabResetNotify ( layer , family , subtab ) )
return true
}
}
if ( tmp [ layer ] . autoPrestige || tmp [ layer ] . passiveGeneration ) return false
2020-11-08 04:34:53 +00:00
else if ( tmp [ layer ] . type == "static" ) return tmp [ layer ] . canReset
else if ( tmp [ layer ] . type == "normal" ) return ( tmp [ layer ] . canReset && ( tmp [ layer ] . resetGain . gte ( player [ layer ] . points . div ( 10 ) ) ) )
else return false
}
2020-10-03 21:52:51 +00:00
function notifyLayer ( name ) {
2020-10-13 03:08:19 +00:00
if ( player . tab == name || ! layerunlocked ( name ) ) return
2020-10-03 21:52:51 +00:00
player . notify [ name ] = 1
}
2021-01-06 20:56:06 +00:00
function subtabShouldNotify ( layer , family , id ) {
2020-10-30 01:06:37 +00:00
let subtab = { }
if ( family == "mainTabs" ) subtab = tmp [ layer ] . tabFormat [ id ]
else subtab = tmp [ layer ] . microtabs [ family ] [ id ]
2020-12-22 03:09:33 +00:00
if ( subtab . embedLayer ) return tmp [ subtab . embedLayer ] . notify
2020-10-30 01:06:37 +00:00
else return subtab . shouldNotify
}
2021-01-06 20:56:06 +00:00
function subtabResetNotify ( layer , family , id ) {
2020-11-08 04:34:53 +00:00
let subtab = { }
if ( family == "mainTabs" ) subtab = tmp [ layer ] . tabFormat [ id ]
else subtab = tmp [ layer ] . microtabs [ family ] [ id ]
if ( subtab . embedLayer ) return tmp [ subtab . embedLayer ] . prestigeNotify
2021-04-29 22:33:12 +00:00
else return subtab . prestigeNotify
2020-11-08 04:34:53 +00:00
}
2020-10-03 21:52:51 +00:00
function nodeShown ( layer ) {
2020-12-14 03:23:12 +00:00
if ( layerShown ( layer ) ) return true
2021-01-06 20:56:06 +00:00
switch ( layer ) {
2020-10-03 21:52:51 +00:00
case "idk" :
2020-10-27 23:25:03 +00:00
return player . idk . unlocked
2020-10-03 21:52:51 +00:00
break ;
}
return false
}
2020-10-13 03:08:19 +00:00
function layerunlocked ( layer ) {
2020-10-28 02:04:16 +00:00
if ( tmp [ layer ] && tmp [ layer ] . type == "none" ) return ( player [ layer ] . unlocked )
2020-12-22 03:09:33 +00:00
return LAYERS . includes ( layer ) && ( player [ layer ] . unlocked || ( tmp [ layer ] . canReset && tmp [ layer ] . layerShown ) )
2020-10-03 21:52:51 +00:00
}
function keepGoing ( ) {
player . keepGoing = true ;
2020-10-30 23:40:48 +00:00
needCanvasUpdate = true ;
2021-05-06 19:45:03 +00:00
goBack ( )
2020-10-03 21:52:51 +00:00
}
function toNumber ( x ) {
if ( x . mag !== undefined ) return x . toNumber ( )
if ( x + 0 !== x ) return parseFloat ( x )
return x
}
2021-01-06 20:56:06 +00:00
function updateMilestones ( layer ) {
for ( id in layers [ layer ] . milestones ) {
if ( ! ( hasMilestone ( layer , id ) ) && layers [ layer ] . milestones [ id ] . done ( ) ) {
2020-10-03 21:52:51 +00:00
player [ layer ] . milestones . push ( id )
2020-12-10 06:31:42 +00:00
if ( tmp [ layer ] . milestonePopups || tmp [ layer ] . milestonePopups === undefined ) doPopup ( "milestone" , tmp [ layer ] . milestones [ id ] . requirementDescription , "Milestone Gotten!" , 3 , tmp [ layer ] . color ) ;
2021-05-06 20:26:44 +00:00
player [ layer ] . lastMilestone = id
2020-12-07 05:40:30 +00:00
}
2020-10-03 21:52:51 +00:00
}
}
2021-01-06 20:56:06 +00:00
function updateAchievements ( layer ) {
for ( id in layers [ layer ] . achievements ) {
2020-12-22 03:09:33 +00:00
if ( isPlainObject ( layers [ layer ] . achievements [ id ] ) && ! ( hasAchievement ( layer , id ) ) && layers [ layer ] . achievements [ id ] . done ( ) ) {
2020-10-15 01:43:16 +00:00
player [ layer ] . achievements . push ( id )
if ( layers [ layer ] . achievements [ id ] . onComplete ) layers [ layer ] . achievements [ id ] . onComplete ( )
2020-12-10 06:31:42 +00:00
if ( tmp [ layer ] . achievementPopups || tmp [ layer ] . achievementPopups === undefined ) doPopup ( "achievement" , tmp [ layer ] . achievements [ id ] . name , "Achievement Gotten!" , 3 , tmp [ layer ] . color ) ;
2020-10-15 01:43:16 +00:00
}
}
}
2020-10-03 21:52:51 +00:00
function addTime ( diff , layer ) {
let data = player
let time = data . timePlayed
if ( layer ) {
data = data [ layer ]
time = data . time
}
//I am not that good to perfectly fix that leak. ~ DB Aarex
if ( time + 0 !== time ) {
console . log ( "Memory leak detected. Trying to fix..." )
time = toNumber ( time )
if ( isNaN ( time ) || time == 0 ) {
console . log ( "Couldn't fix! Resetting..." )
time = layer ? player . timePlayed : 0
if ( ! layer ) player . timePlayedReset = true
}
}
time += toNumber ( diff )
if ( layer ) data . time = time
else data . timePlayed = time
}
2021-04-27 05:26:07 +00:00
shiftDown = false
ctrlDown = false
2021-01-06 20:56:06 +00:00
document . onkeydown = function ( e ) {
if ( player === undefined ) return ;
if ( gameEnded && ! player . keepGoing ) return ;
2021-04-27 05:26:07 +00:00
shiftDown = e . shiftKey
ctrlDown = e . ctrlKey
2020-10-03 21:52:51 +00:00
let key = e . key
if ( ctrlDown ) key = "ctrl+" + key
if ( onFocused ) return
2020-10-16 15:39:39 +00:00
if ( ctrlDown && hotkeys [ key ] ) e . preventDefault ( )
2021-01-06 20:56:06 +00:00
if ( hotkeys [ key ] ) {
2021-04-27 06:01:02 +00:00
let k = hotkeys [ key ]
if ( player [ k . layer ] . unlocked && tmp [ k . layer ] . hotkeys [ k . id ] . unlocked )
k . onPress ( )
2020-10-03 21:52:51 +00:00
}
}
2021-04-28 06:48:14 +00:00
document . onkeyup = function ( e ) {
shiftDown = e . shiftKey
ctrlDown = e . ctrlKey
}
2020-10-03 21:52:51 +00:00
var onFocused = false
function focused ( x ) {
onFocused = x
2020-10-09 03:13:15 +00:00
}
2020-10-10 03:16:29 +00:00
2020-10-09 03:13:15 +00:00
function isFunction ( obj ) {
return ! ! ( obj && obj . constructor && obj . call && obj . apply ) ;
2021-01-06 20:56:06 +00:00
} ;
2020-11-29 02:25:53 +00:00
function isPlainObject ( obj ) {
return ( ! ! obj ) && ( obj . constructor === Object )
}
2020-10-09 23:42:30 +00:00
document . title = modInfo . name
2020-12-07 03:56:37 +00:00
2021-04-27 02:43:36 +00:00
// Converts a string value to whatever it's supposed to be
function toValue ( value , oldValue ) {
2021-05-18 22:36:17 +00:00
if ( oldValue instanceof Decimal ) {
value = new Decimal ( value )
if ( value . eq ( decimalNaN ) ) return decimalZero
return value
}
2021-05-18 18:27:11 +00:00
if ( ! isNaN ( oldValue ) )
2021-05-18 22:36:17 +00:00
return parseFloat ( value ) || 0
2021-05-18 18:27:11 +00:00
return value
2021-04-27 02:43:36 +00:00
}
2020-12-07 03:56:37 +00:00
// Variables that must be defined to display popups
var activePopups = [ ] ;
var popupID = 0 ;
// Function to show popups
2021-01-06 20:56:06 +00:00
function doPopup ( type = "none" , text = "This is a test popup." , title = "" , timer = 3 , color = "" ) {
switch ( type ) {
2020-12-07 03:56:37 +00:00
case "achievement" :
popupTitle = "Achievement Unlocked!" ;
popupType = "achievement-popup"
break ;
case "challenge" :
popupTitle = "Challenge Complete" ;
popupType = "challenge-popup"
break ;
default :
popupTitle = "Something Happened?" ;
popupType = "default-popup"
break ;
}
2021-01-06 20:56:06 +00:00
if ( title != "" ) popupTitle = title ;
2020-12-07 03:56:37 +00:00
popupMessage = text ;
2021-01-06 20:56:06 +00:00
popupTimer = timer ;
2020-12-07 03:56:37 +00:00
2021-01-06 20:56:06 +00:00
activePopups . push ( { "time" : popupTimer , "type" : popupType , "title" : popupTitle , "message" : ( popupMessage + "\n" ) , "id" : popupID , "color" : color } )
2020-12-07 03:56:37 +00:00
popupID ++ ;
}
//Function to reduce time on active popups
function adjustPopupTime ( diff ) {
2021-01-06 20:56:06 +00:00
for ( popup in activePopups ) {
2020-12-07 03:56:37 +00:00
activePopups [ popup ] . time -= diff ;
2021-01-06 20:56:06 +00:00
if ( activePopups [ popup ] [ "time" ] < 0 ) {
activePopups . splice ( popup , 1 ) ; // Remove popup when time hits 0
2020-12-07 03:56:37 +00:00
}
}
2020-12-13 02:43:22 +00:00
}
2021-01-06 20:56:06 +00:00
function run ( func , target , args = null ) {
2021-05-10 01:39:15 +00:00
if ( isFunction ( func ) ) {
2021-01-06 20:56:06 +00:00
let bound = func . bind ( target )
2020-12-13 02:43:22 +00:00
return bound ( args )
}
else
return func ;
2021-05-11 06:27:50 +00:00
}
function gridRun ( layer , func , data , id ) {
if ( isFunction ( layers [ layer ] . grid [ func ] ) ) {
let bound = layers [ layer ] . grid [ func ] . bind ( layers [ layer ] . grid )
return bound ( data , id )
}
else
return layers [ layer ] . grid [ func ] ;
2020-12-07 03:56:37 +00:00
}