2020-10-03 21:52:51 +00:00
// ************ Number formatting ************
2020-12-01 02:58:42 +00:00
function exponentialFormat ( num , precision , mantissa = true ) {
2020-10-03 21:52:51 +00:00
let e = num . log10 ( ) . floor ( )
let m = num . div ( Decimal . pow ( 10 , e ) )
2020-10-17 21:04:38 +00:00
if ( m . toStringWithDecimalPlaces ( precision ) == 10 ) {
m = new Decimal ( 1 )
e = e . add ( 1 )
}
2020-10-29 18:57:42 +00:00
e = ( e . gte ( 10000 ) ? commaFormat ( e , 0 ) : e . toStringWithDecimalPlaces ( 0 ) )
2020-12-01 02:58:42 +00:00
if ( mantissa )
return m . toStringWithDecimalPlaces ( precision ) + "e" + e
else return "e" + e
}
2020-10-03 21:52:51 +00:00
function commaFormat ( num , precision ) {
if ( num === null || num === undefined ) return "NaN"
if ( num . mag < 0.001 ) return ( 0 ) . toFixed ( precision )
2020-12-01 02:58:42 +00:00
return num . toStringWithDecimalPlaces ( precision ) . replace ( /(\d)(?=(\d\d\d)+(?!\d))/g , "$1," )
2020-10-03 21:52:51 +00:00
}
2020-10-21 17:03:39 +00:00
function regularFormat ( num , precision ) {
if ( num === null || num === undefined ) return "NaN"
if ( num . mag < 0.001 ) return ( 0 ) . toFixed ( precision )
return num . toStringWithDecimalPlaces ( precision )
}
2020-10-03 21:52:51 +00:00
function fixValue ( x , y = 0 ) {
return x || new Decimal ( y )
}
function sumValues ( x ) {
x = Object . values ( x )
if ( ! x [ 0 ] ) return new Decimal ( 0 )
return x . reduce ( ( a , b ) => Decimal . add ( a , b ) )
}
2020-12-01 02:58:42 +00:00
function format ( decimal , precision = 2 , ) {
2020-10-03 21:52:51 +00:00
decimal = new Decimal ( decimal )
if ( isNaN ( decimal . sign ) || isNaN ( decimal . layer ) || isNaN ( decimal . mag ) ) {
player . hasNaN = true ;
return "NaN"
}
if ( decimal . sign < 0 ) return "-" + format ( decimal . neg ( ) , precision )
if ( decimal . mag == Number . POSITIVE _INFINITY ) return "Infinity"
if ( decimal . gte ( "eeee1000" ) ) {
var slog = decimal . slog ( )
if ( slog . gte ( 1e6 ) ) return "F" + format ( slog . floor ( ) )
else return Decimal . pow ( 10 , slog . sub ( slog . floor ( ) ) ) . toStringWithDecimalPlaces ( 3 ) + "F" + commaFormat ( slog . floor ( ) , 0 )
2020-12-01 02:58:42 +00:00
}
else if ( decimal . gte ( "1e100000" ) ) return exponentialFormat ( decimal , 0 , false )
else if ( decimal . gte ( "1e1000" ) ) return exponentialFormat ( decimal , 0 )
2020-10-03 21:52:51 +00:00
else if ( decimal . gte ( 1e9 ) ) return exponentialFormat ( decimal , precision )
else if ( decimal . gte ( 1e3 ) ) return commaFormat ( decimal , 0 )
2020-10-21 17:03:39 +00:00
else return regularFormat ( decimal , precision )
2020-10-03 21:52:51 +00:00
}
function formatWhole ( decimal ) {
2020-10-22 01:18:39 +00:00
decimal = new Decimal ( decimal )
if ( decimal . gte ( 1e9 ) ) return format ( decimal , 2 )
2020-12-14 03:23:12 +00:00
if ( decimal . lte ( 0.98 ) && ! decimal . eq ( 0 ) ) return format ( decimal , 2 )
2020-10-03 21:52:51 +00:00
return format ( decimal , 0 )
}
function formatTime ( s ) {
if ( s < 60 ) return format ( s ) + "s"
else if ( s < 3600 ) return formatWhole ( Math . floor ( s / 60 ) ) + "m " + format ( s % 60 ) + "s"
2020-10-29 18:57:42 +00:00
else if ( s < 86400 ) return formatWhole ( Math . floor ( s / 3600 ) ) + "h " + formatWhole ( Math . floor ( s / 60 ) % 60 ) + "m " + format ( s % 60 ) + "s"
else if ( s < 31536000 ) return formatWhole ( Math . floor ( s / 84600 ) % 365 ) + "d " + formatWhole ( Math . floor ( s / 3600 ) % 24 ) + "h " + formatWhole ( Math . floor ( s / 60 ) % 60 ) + "m " + format ( s % 60 ) + "s"
else return formatWhole ( Math . floor ( s / 31536000 ) ) + "y " + formatWhole ( Math . floor ( s / 84600 ) % 365 ) + "d " + formatWhole ( Math . floor ( s / 3600 ) % 24 ) + "h " + formatWhole ( Math . floor ( s / 60 ) % 60 ) + "m " + format ( s % 60 ) + "s"
2020-10-03 21:52:51 +00:00
}
2020-10-05 01:36:03 +00:00
function toPlaces ( x , precision , maxAccepted ) {
x = new Decimal ( x )
let result = x . toStringWithDecimalPlaces ( precision )
if ( new Decimal ( result ) . gte ( maxAccepted ) ) {
result = new Decimal ( maxAccepted - Math . pow ( 0.1 , precision ) ) . toStringWithDecimalPlaces ( precision )
}
return result
}
2020-10-03 21:52:51 +00:00
// ************ Save stuff ************
function save ( ) {
localStorage . setItem ( modInfo . id , btoa ( JSON . stringify ( player ) ) )
}
2020-10-04 17:10:04 +00:00
function startPlayerBase ( ) {
return {
2020-10-29 18:57:42 +00:00
tab : layoutInfo . startTab ,
2020-10-30 23:40:48 +00:00
navTab : ( layoutInfo . showTree ? "tree-tab" : "none" ) ,
2020-10-04 17:10:04 +00:00
time : Date . now ( ) ,
autosave : true ,
notify : { } ,
msDisplay : "always" ,
offlineProd : true ,
2020-10-07 15:03:32 +00:00
versionType : modInfo . id ,
2020-10-04 17:10:04 +00:00
version : VERSION . num ,
beta : VERSION . beta ,
timePlayed : 0 ,
keepGoing : false ,
hasNaN : false ,
2020-10-13 03:08:19 +00:00
hideChallenges : false ,
2020-10-24 16:40:56 +00:00
showStory : true ,
2020-10-17 04:21:59 +00:00
points : modInfo . initialStartPoints ,
2020-10-07 04:57:41 +00:00
subtabs : { } ,
2020-11-08 23:47:17 +00:00
lastSafeTab : ( layoutInfo . showTree ? "none" : layoutInfo . startTab )
2020-10-04 17:10:04 +00:00
}
}
function getStartPlayer ( ) {
playerdata = startPlayerBase ( )
2020-10-17 22:02:27 +00:00
if ( addedPlayerData ) {
extradata = addedPlayerData ( )
for ( thing in extradata )
playerdata [ thing ] = extradata [ thing ]
}
2020-10-25 22:21:02 +00:00
playerdata . infoboxes = { }
2020-10-04 17:10:04 +00:00
for ( layer in layers ) {
2020-11-29 21:28:24 +00:00
playerdata [ layer ] = getStartLayerData ( layer )
2020-10-07 03:11:36 +00:00
if ( layers [ layer ] . tabFormat && ! Array . isArray ( layers [ layer ] . tabFormat ) ) {
2020-10-07 04:57:41 +00:00
playerdata . subtabs [ layer ] = { }
playerdata . subtabs [ layer ] . mainTabs = Object . keys ( layers [ layer ] . tabFormat ) [ 0 ]
2020-10-07 03:11:36 +00:00
}
if ( layers [ layer ] . microtabs ) {
2020-10-07 04:57:41 +00:00
if ( playerdata . subtabs [ layer ] == undefined ) playerdata . subtabs [ layer ] = { }
2020-10-07 03:11:36 +00:00
for ( item in layers [ layer ] . microtabs )
2020-10-07 04:57:41 +00:00
playerdata . subtabs [ layer ] [ item ] = Object . keys ( layers [ layer ] . microtabs [ item ] ) [ 0 ]
2020-10-07 03:11:36 +00:00
}
2020-10-25 22:21:02 +00:00
if ( layers [ layer ] . infoboxes ) {
if ( playerdata . infoboxes [ layer ] == undefined ) playerdata . infoboxes [ layer ] = { }
for ( item in layers [ layer ] . infoboxes )
playerdata . infoboxes [ layer ] [ item ] = false
}
2020-11-29 21:28:24 +00:00
2020-10-04 17:10:04 +00:00
}
return playerdata
}
2020-11-29 21:28:24 +00:00
function getStartLayerData ( layer ) {
layerdata = { }
if ( layers [ layer ] . startData )
layerdata = layers [ layer ] . startData ( )
if ( layerdata . unlocked === undefined ) layerdata . unlocked = true
if ( layerdata . total === undefined ) layerdata . total = new Decimal ( 0 )
if ( layerdata . best === undefined ) layerdata . best = new Decimal ( 0 )
2020-12-22 03:09:33 +00:00
if ( layerdata . resetTime === undefined ) layerdata . resetTime = 0
2020-11-29 21:28:24 +00:00
layerdata . buyables = getStartBuyables ( layer )
if ( layerdata . clickables == undefined ) layerdata . clickables = getStartClickables ( layer )
layerdata . spentOnBuyables = new Decimal ( 0 )
layerdata . upgrades = [ ]
layerdata . milestones = [ ]
layerdata . achievements = [ ]
layerdata . challenges = getStartChallenges ( layer )
return layerdata
}
2020-10-11 20:42:32 +00:00
function getStartBuyables ( layer ) {
let data = { }
if ( layers [ layer ] . buyables ) {
for ( id in layers [ layer ] . buyables )
2020-11-29 02:25:53 +00:00
if ( isPlainObject ( layers [ layer ] . buyables [ id ] ) )
2020-10-11 20:42:32 +00:00
data [ id ] = new Decimal ( 0 )
}
return data
}
function getStartClickables ( layer ) {
let data = { }
if ( layers [ layer ] . clickables ) {
2020-12-01 01:40:53 +00:00
for ( id in layers [ layer ] . clickables )
2020-11-30 20:03:26 +00:00
if ( isPlainObject ( layers [ layer ] . clickables [ id ] ) )
data [ id ] = ""
2020-10-11 20:42:32 +00:00
}
return data
}
2020-10-13 03:08:19 +00:00
function getStartChallenges ( layer ) {
2020-10-11 20:42:32 +00:00
let data = { }
2020-10-13 03:08:19 +00:00
if ( layers [ layer ] . challenges ) {
for ( id in layers [ layer ] . challenges )
2020-11-30 20:03:26 +00:00
if ( isPlainObject ( layers [ layer ] . challenges [ id ] ) )
data [ id ] = 0
2020-10-11 20:42:32 +00:00
}
return data
}
2020-10-03 21:52:51 +00:00
function fixSave ( ) {
2020-10-08 23:42:26 +00:00
defaultData = getStartPlayer ( )
fixData ( defaultData , player )
2020-10-03 21:52:51 +00:00
2020-10-08 23:42:26 +00:00
for ( layer in layers )
{
if ( player [ layer ] . best !== undefined ) player [ layer ] . best = new Decimal ( player [ layer ] . best )
if ( player [ layer ] . total !== undefined ) player [ layer ] . total = new Decimal ( player [ layer ] . total )
2020-10-20 00:04:53 +00:00
if ( layers [ layer ] . tabFormat && ! Array . isArray ( layers [ layer ] . tabFormat ) ) {
if ( ! Object . keys ( layers [ layer ] . tabFormat ) . includes ( player . subtabs [ layer ] . mainTabs ) ) player . subtabs [ layer ] . mainTabs = Object . keys ( layers [ layer ] . tabFormat ) [ 0 ]
}
if ( layers [ layer ] . microtabs ) {
for ( item in layers [ layer ] . microtabs )
if ( ! Object . keys ( layers [ layer ] . microtabs [ item ] ) . includes ( player . subtabs [ layer ] [ item ] ) ) player . subtabs [ layer ] [ item ] = Object . keys ( layers [ layer ] . microtabs [ item ] ) [ 0 ]
}
2020-10-08 23:42:26 +00:00
}
}
2020-10-03 21:52:51 +00:00
2020-10-08 23:42:26 +00:00
function fixData ( defaultData , newData ) {
for ( item in defaultData ) {
if ( defaultData [ item ] == null ) {
if ( newData [ item ] === undefined )
newData [ item ] = null
2020-10-03 21:52:51 +00:00
}
2020-10-08 23:42:26 +00:00
else if ( Array . isArray ( defaultData [ item ] ) ) {
if ( newData [ item ] === undefined )
newData [ item ] = defaultData [ item ]
else
fixData ( defaultData [ item ] , newData [ item ] )
2020-10-07 03:11:36 +00:00
}
2020-10-08 23:42:26 +00:00
else if ( defaultData [ item ] instanceof Decimal ) { // Convert to Decimal
if ( newData [ item ] === undefined )
newData [ item ] = defaultData [ item ]
else
newData [ item ] = new Decimal ( newData [ item ] )
2020-10-07 03:11:36 +00:00
}
2020-12-01 02:58:42 +00:00
else if ( ( ! ! defaultData [ item ] ) && ( typeof defaultData [ item ] === "object" ) ) {
if ( newData [ item ] === undefined || ( typeof defaultData [ item ] !== "object" ) )
2020-10-08 23:42:26 +00:00
newData [ item ] = defaultData [ item ]
else
fixData ( defaultData [ item ] , newData [ item ] )
}
else {
if ( newData [ item ] === undefined )
newData [ item ] = defaultData [ item ]
}
}
2020-10-03 21:52:51 +00:00
}
function load ( ) {
let get = localStorage . getItem ( modInfo . id ) ;
if ( get === null || get === undefined ) player = getStartPlayer ( )
else player = Object . assign ( getStartPlayer ( ) , JSON . parse ( atob ( get ) ) )
fixSave ( )
if ( player . offlineProd ) {
if ( player . offTime === undefined ) player . offTime = { remain : 0 }
player . offTime . remain += ( Date . now ( ) - player . time ) / 1000
}
player . time = Date . now ( ) ;
versionCheck ( ) ;
changeTheme ( ) ;
changeTreeQuality ( ) ;
2020-10-21 20:14:42 +00:00
updateLayers ( )
2020-12-05 19:52:29 +00:00
setupModInfo ( )
2020-10-21 20:14:42 +00:00
2020-10-07 22:41:03 +00:00
setupTemp ( ) ;
2020-10-03 21:52:51 +00:00
updateTemp ( ) ;
updateTemp ( ) ;
loadVue ( ) ;
}
2020-12-05 19:52:29 +00:00
function setupModInfo ( ) {
modInfo . changelog = changelog
modInfo . winText = winText ? winText : ` Congratulations! You have reached the end and beaten this game, but for now... `
}
2020-10-27 21:41:35 +00:00
function fixNaNs ( ) {
NaNcheck ( player )
}
function NaNcheck ( data ) {
for ( item in data ) {
if ( data [ item ] == null ) {
}
else if ( Array . isArray ( data [ item ] ) ) {
NaNcheck ( data [ item ] )
}
else if ( data [ item ] !== data [ item ] || data [ item ] === decimalNaN ) {
2020-10-27 23:25:03 +00:00
if ( NaNalert === true || confirm ( "Invalid value found in player, named '" + item + "'. Please let the creator of this mod know! Would you like to try to auto-fix the save and keep going?" ) ) {
2020-10-27 21:41:35 +00:00
NaNalert = true
data [ item ] = ( data [ item ] !== data [ item ] ? 0 : decimalZero )
}
else {
clearInterval ( interval ) ;
player . autosave = false ;
NaNalert = true ;
}
}
else if ( data [ item ] instanceof Decimal ) { // Convert to Decimal
}
else if ( ( ! ! data [ item ] ) && ( data [ item ] . constructor === Object ) ) {
NaNcheck ( data [ item ] )
}
}
}
2020-10-03 21:52:51 +00:00
function exportSave ( ) {
let str = btoa ( JSON . stringify ( player ) )
const el = document . createElement ( "textarea" ) ;
el . value = str ;
document . body . appendChild ( el ) ;
el . select ( ) ;
el . setSelectionRange ( 0 , 99999 ) ;
document . execCommand ( "copy" ) ;
document . body . removeChild ( el ) ;
}
function importSave ( imported = undefined , forced = false ) {
if ( imported === undefined ) imported = prompt ( "Paste your save here" )
try {
tempPlr = Object . assign ( getStartPlayer ( ) , JSON . parse ( atob ( imported ) ) )
2020-10-07 15:03:32 +00:00
if ( tempPlr . versionType != modInfo . id && ! forced && ! confirm ( "This save appears to be for a different mod! Are you sure you want to import?" ) ) // Wrong save (use "Forced" to force it to accept.)
2020-10-03 21:52:51 +00:00
return
player = tempPlr ;
player . versionType = modInfo . id
fixSave ( )
2020-11-29 01:10:13 +00:00
versionCheck ( )
2020-10-03 21:52:51 +00:00
save ( )
window . location . reload ( )
} catch ( e ) {
return ;
}
}
function versionCheck ( ) {
let setVersion = true
if ( player . versionType === undefined || player . version === undefined ) {
2020-10-04 17:10:04 +00:00
player . versionType = modInfo . id
2020-10-03 21:52:51 +00:00
player . version = 0
}
if ( setVersion ) {
2020-11-29 01:10:13 +00:00
if ( player . versionType == modInfo . id && VERSION . num > player . version ) {
player . keepGoing = false
if ( fixOldSave ) fixOldSave ( player . version )
}
2020-10-03 21:52:51 +00:00
player . versionType = getStartPlayer ( ) . versionType
player . version = VERSION . num
player . beta = VERSION . beta
}
}
var saveInterval = setInterval ( function ( ) {
if ( player === undefined ) return ;
if ( gameEnded && ! player . keepGoing ) return ;
if ( player . autosave ) save ( ) ;
} , 5000 )
// ************ Themes ************
const themes = {
1 : "aqua"
}
const theme _names = {
aqua : "Aqua"
}
function changeTheme ( ) {
let aqua = player . theme == "aqua"
colors _theme = colors [ player . theme || "default" ]
document . body . style . setProperty ( '--background' , aqua ? "#001f3f" : "#0f0f0f" )
document . body . style . setProperty ( '--background_tooltip' , aqua ? "rgba(0, 15, 31, 0.75)" : "rgba(0, 0, 0, 0.75)" )
document . body . style . setProperty ( '--color' , aqua ? "#bfdfff" : "#dfdfdf" )
document . body . style . setProperty ( '--points' , aqua ? "#dfefff" : "#ffffff" )
2020-10-05 01:36:03 +00:00
document . body . style . setProperty ( "--locked" , aqua ? "#c4a7b3" : "#bf8f8f" )
2020-10-03 21:52:51 +00:00
}
function getThemeName ( ) {
return player . theme ? theme _names [ player . theme ] : "Default"
}
function switchTheme ( ) {
if ( player . theme === undefined ) player . theme = themes [ 1 ]
else {
player . theme = themes [ Object . keys ( themes ) [ player . theme ] + 1 ]
if ( ! player . theme ) delete player . theme
}
changeTheme ( )
resizeCanvas ( )
}
// ************ Options ************
function toggleOpt ( name ) {
2020-10-05 01:36:03 +00:00
if ( name == "oldStyle" && styleCooldown > 0 ) return ;
2020-10-03 21:52:51 +00:00
player [ name ] = ! player [ name ]
if ( name == "hqTree" ) changeTreeQuality ( )
2020-10-05 01:36:03 +00:00
if ( name == "oldStyle" ) updateStyle ( )
}
var styleCooldown = 0 ;
function updateStyle ( ) {
styleCooldown = 1 ;
let css = document . getElementById ( "styleStuff" )
css . href = player . oldStyle ? "oldStyle.css" : "style.css"
needCanvasUpdate = true ;
2020-10-03 21:52:51 +00:00
}
function changeTreeQuality ( ) {
var on = player . hqTree
document . body . style . setProperty ( '--hqProperty1' , on ? "2px solid" : "4px solid" )
document . body . style . setProperty ( '--hqProperty2a' , on ? "-4px -4px 4px rgba(0, 0, 0, 0.25) inset" : "-4px -4px 4px rgba(0, 0, 0, 0) inset" )
document . body . style . setProperty ( '--hqProperty2b' , on ? "0px 0px 20px var(--background)" : "" )
document . body . style . setProperty ( '--hqProperty3' , on ? "2px 2px 4px rgba(0, 0, 0, 0.25)" : "none" )
}
function toggleAuto ( toggle ) {
player [ toggle [ 0 ] ] [ toggle [ 1 ] ] = ! player [ toggle [ 0 ] ] [ toggle [ 1 ] ]
}
function adjustMSDisp ( ) {
let displays = [ "always" , "automation" , "incomplete" , "never" ] ;
player . msDisplay = displays [ ( displays . indexOf ( player . msDisplay ) + 1 ) % 4 ]
}
function milestoneShown ( layer , id ) {
complete = player [ layer ] . milestones . includes ( id )
auto = layers [ layer ] . milestones [ id ] . toggles
switch ( player . msDisplay ) {
case "always" :
return true ;
break ;
case "automation" :
return ( auto ) || ! complete
break ;
case "incomplete" :
return ! complete
break ;
case "never" :
return false ;
break ;
}
return false ;
}
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
2020-10-16 22:45:44 +00:00
if ( ! confirm ( "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 ]
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
return canAffordPurchase ( layer , upg , cost )
}
2020-10-13 03:08:19 +00:00
function hasUpgrade ( layer , id ) {
2020-10-11 20:16:36 +00:00
return ( player [ layer ] . upgrades . includes ( toNumber ( id ) ) || player [ layer ] . upgrades . includes ( id . toString ( ) ) )
}
function hasMilestone ( layer , id ) {
return ( player [ layer ] . milestones . includes ( toNumber ( id ) ) || player [ layer ] . milestones . includes ( id . toString ( ) ) )
}
2020-10-15 01:43:16 +00:00
function hasAchievement ( layer , id ) {
return ( player [ layer ] . achievements . includes ( toNumber ( id ) ) || player [ layer ] . achievements . includes ( id . toString ( ) ) )
}
2020-10-13 03:08:19 +00:00
function hasChallenge ( layer , id ) {
return ( player [ layer ] . challenges [ id ] )
2020-10-11 20:42:32 +00:00
}
2020-10-30 00:33:39 +00:00
function maxedChallenge ( layer , id ) {
return ( player [ layer ] . challenges [ id ] >= tmp [ layer ] . challenges [ id ] . completionLimit )
}
2020-10-13 03:08:19 +00:00
function challengeCompletions ( layer , id ) {
return ( player [ layer ] . challenges [ id ] )
2020-10-11 20:16:36 +00:00
}
2020-10-13 03:08:19 +00:00
function getBuyableAmount ( layer , id ) {
2020-10-11 20:16:36 +00:00
return ( player [ layer ] . buyables [ id ] )
}
2020-10-13 03:08:19 +00:00
function setBuyableAmount ( layer , id , amt ) {
2020-10-11 20:16:36 +00:00
player [ layer ] . buyables [ id ] = amt
}
function getClickableState ( layer , id ) {
return ( player [ layer ] . clickables [ id ] )
}
function setClickableState ( layer , id , state ) {
player [ layer ] . clickables [ id ] = state
}
2020-10-13 03:08:19 +00:00
function upgradeEffect ( layer , id ) {
2020-10-11 20:16:36 +00:00
return ( tmp [ layer ] . upgrades [ id ] . effect )
}
2020-10-13 03:08:19 +00:00
function challengeEffect ( layer , id ) {
2020-11-07 20:29:39 +00:00
return ( tmp [ layer ] . challenges [ id ] . rewardEffect )
2020-10-11 20:16:36 +00:00
}
function buyableEffect ( layer , id ) {
return ( tmp [ layer ] . buyables [ id ] . effect )
}
2020-10-16 22:45:44 +00:00
function clickableEffect ( layer , id ) {
return ( tmp [ layer ] . clickables [ id ] . effect )
}
2020-10-15 01:43:16 +00:00
function achievementEffect ( layer , id ) {
return ( tmp [ layer ] . achievements [ id ] . effect )
}
2020-10-11 20:16:36 +00:00
function canAffordPurchase ( layer , thing , cost ) {
2020-10-16 15:39:39 +00:00
2020-10-11 20:16:36 +00:00
if ( thing . currencyInternalName ) {
let name = thing . currencyInternalName
2020-10-16 15:39:39 +00:00
if ( thing . currencyLocation ) {
return ! ( thing . currencyLocation [ name ] . lt ( cost ) )
}
else if ( thing . currencyLayer ) {
2020-10-11 20:16:36 +00:00
let lr = thing . currencyLayer
return ! ( player [ lr ] [ name ] . lt ( cost ) )
}
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 ] )
2020-11-29 21:28:24 +00:00
else
{
let cost = tmp [ layer ] . upgrades [ id ] . cost
if ( upg . currencyInternalName ) {
let name = upg . currencyInternalName
if ( upg . currencyLocation ) {
if ( upg . currencyLocation [ name ] . lt ( cost ) ) return
upg . currencyLocation [ name ] = upg . currencyLocation [ name ] . sub ( cost )
}
else if ( upg . currencyLayer ) {
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
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
2020-10-11 20:16:36 +00:00
if ( ! tmp [ layer ] . buyables [ id ] . canAfford ) return
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
2020-10-11 20:16:36 +00:00
if ( ! tmp [ layer ] . buyables [ id ] . canAfford ) return
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 ) {
2020-10-13 03:08:19 +00:00
if ( ! player [ layer ] . unlocked ) return
if ( ! tmp [ layer ] . clickables [ id ] . unlocked ) return
2020-10-11 20:16:36 +00:00
if ( ! tmp [ layer ] . clickables [ id ] . canClick ) return
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 )
}
2020-10-11 22:38:54 +00:00
// Function to determine if the player is in a challenge
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 )
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
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 ]
2020-10-30 23:40:48 +00:00
needCanvasUpdate = true
2020-12-07 04:40:06 +00:00
document . activeElement . blur ( )
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
var toTreeTab = name == "tree"
player . navTab = name
player . notify [ name ] = false
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 ( )
else if ( tmp [ layer ] . autoPrestige || tmp [ layer ] . passiveGeneration ) return false
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
}
2020-10-30 01:06:37 +00:00
function subtabShouldNotify ( layer , family , id ) {
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
}
2020-11-08 04:34:53 +00:00
function subtabResetNotify ( layer , family , id ) {
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
else return false
}
2020-10-03 21:52:51 +00:00
function nodeShown ( layer ) {
2020-12-14 03:23:12 +00:00
if ( layerShown ( layer ) ) return true
2020-10-03 21:52:51 +00:00
switch ( layer ) {
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 ;
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
}
function updateMilestones ( layer ) {
for ( id in layers [ layer ] . milestones ) {
2020-12-22 03:09:33 +00:00
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 ) ;
2020-12-07 05:40:30 +00:00
}
2020-10-03 21:52:51 +00:00
}
}
2020-10-15 01:43:16 +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
}
document . onkeydown = function ( e ) {
if ( player === undefined ) return ;
if ( gameEnded && ! player . keepGoing ) return ;
let shiftDown = e . shiftKey
let ctrlDown = e . ctrlKey
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 ( )
2020-10-03 21:52:51 +00:00
if ( hotkeys [ key ] ) {
2020-10-13 03:08:19 +00:00
if ( player [ hotkeys [ key ] . layer ] . unlocked )
2020-10-03 21:52:51 +00:00
hotkeys [ key ] . onPress ( )
}
}
var onFocused = false
function focused ( x ) {
onFocused = x
2020-10-09 03:13:15 +00:00
}
2020-10-10 03:16:29 +00:00
function prestigeButtonText ( layer )
{
2020-12-14 18:51:19 +00:00
if ( layers [ layer ] . prestigeButtonText !== undefined )
2020-12-14 03:23:12 +00:00
return layers [ layer ] . prestigeButtonText ( )
else if ( tmp [ layer ] . type == "normal" )
2020-10-13 22:56:17 +00:00
return ` ${ player [ layer ] . points . lt ( 1e3 ) ? ( tmp [ layer ] . resetDescription !== undefined ? tmp [ layer ] . resetDescription : "Reset for " ) : "" } +<b> ${ formatWhole ( tmp [ layer ] . resetGain ) } </b> ${ tmp [ layer ] . resource } ${ tmp [ layer ] . resetGain . lt ( 100 ) && player [ layer ] . points . lt ( 1e3 ) ? ` <br><br>Next at ${ ( tmp [ layer ] . roundUpCost ? formatWhole ( tmp [ layer ] . nextAt ) : format ( tmp [ layer ] . nextAt ) ) } ${ tmp [ layer ] . baseResource } ` : "" } `
2020-10-10 03:16:29 +00:00
else if ( tmp [ layer ] . type == "static" )
2020-10-16 20:24:35 +00:00
return ` ${ tmp [ layer ] . resetDescription !== undefined ? tmp [ layer ] . resetDescription : "Reset for " } +<b> ${ formatWhole ( tmp [ layer ] . resetGain ) } </b> ${ tmp [ layer ] . resource } <br><br> ${ player [ layer ] . points . lt ( 30 ) ? ( tmp [ layer ] . baseAmount . gte ( tmp [ layer ] . nextAt ) && ( tmp [ layer ] . canBuyMax !== undefined ) && tmp [ layer ] . canBuyMax ? "Next:" : "Req:" ) : "" } ${ formatWhole ( tmp [ layer ] . baseAmount ) } / ${ ( tmp [ layer ] . roundUpCost ? formatWhole ( tmp [ layer ] . nextAtDisp ) : format ( tmp [ layer ] . nextAtDisp ) ) } ${ tmp [ layer ] . baseResource }
2020-10-10 03:16:29 +00:00
`
2020-10-15 03:09:30 +00:00
else if ( tmp [ layer ] . type == "none" )
return ""
2020-10-10 03:16:29 +00:00
else
2020-12-14 03:23:12 +00:00
return "You need prestige button text"
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 ) ;
} ;
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
// Variables that must be defined to display popups
var activePopups = [ ] ;
var popupID = 0 ;
// Function to show popups
2020-12-09 06:13:20 +00:00
function doPopup ( type = "none" , text = "This is a test popup." , title = "" , timer = 3 , color = "" ) {
2020-12-07 03:56:37 +00:00
switch ( type ) {
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 ;
}
if ( title != "" ) popupTitle = title ;
popupMessage = text ;
popupTimer = timer ;
2020-12-07 05:40:30 +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 ) {
for ( popup in activePopups ) {
activePopups [ popup ] . time -= diff ;
if ( activePopups [ popup ] [ "time" ] < 0 ) {
activePopups . splice ( popup , 1 ) ; // Remove popup when time hits 0
}
}
2020-12-13 02:43:22 +00:00
}
function run ( func , target , args = null ) {
if ( ! ! ( func && func . constructor && func . call && func . apply ) ) {
let bound = func . bind ( target )
return bound ( args )
}
else
return func ;
2020-12-07 03:56:37 +00:00
}