diff --git a/core.js b/core.js index de0fdf15eb..8d96eb752d 100644 --- a/core.js +++ b/core.js @@ -1180,6 +1180,9 @@ dojo.declare("com.nuclearunicorn.game.ui.ButtonModernController", com.nuclearuni var hasRes = res.value >= price.val; var hasLimitIssue = res.maxValue && ((price.val > res.maxValue && !indent) || price.baseVal > res.maxValue); + if (price.val == Infinity && !indent) { + hasLimitIssue = true; //The player can't have infinite of any resource. + } var asterisk = hasLimitIssue ? "*" : ""; //mark limit issues with asterisk var displayValue = hasRes || simplePrices @@ -1209,24 +1212,22 @@ dojo.declare("com.nuclearunicorn.game.ui.ButtonModernController", com.nuclearuni hasLimitIssue: hasLimitIssue }; - //unroll prices to the raw resources if (!hasRes && res.craftable && !simplePrices && res.name != "wood") { var craft = this.game.workshop.getCraft(res.name); - if (craft.unlocked) { + var diff = price.val - res.value; + //Only unroll if we've unlocked the craft; don't unroll infinite prices + if (craft.unlocked && isFinite(diff)) { var craftRatio = this.game.getResCraftRatio(res.name); result.title = "+ " + result.title; result.children = []; var components = this.game.workshop.getCraftPrice(craft); for (var j in components) { - - var diff = price.val - res.value; - // Round up to the nearest craftable amount var val = Math.ceil(components[j].val * diff / (1 + craftRatio)); var remainder = val % components[j].val; - if (remainder != 0) { + if (remainder != 0 && isFinite(remainder)) { val += components[j].val - remainder; } diff --git a/game.js b/game.js index 01abc11298..ca3d213557 100644 --- a/game.js +++ b/game.js @@ -4063,20 +4063,36 @@ dojo.declare("com.nuclearunicorn.game.ui.GamePage", null, { return resString; }, + /** + * Outputs a formatted representation of time. If the input is negative or NaN, treats it as zero instead. + * @param secondsRaw Either a number or a string representing a number. + * @return A string. For the sake of consistency, all whitespace is trimmed from beginning & end. + */ toDisplaySeconds : function (secondsRaw) { if (secondsRaw == Infinity) { return "∞"; } + //We parseFloat because sometimes the numbers are so huge they end up being converted to scientific notation + var sec_num = Math.floor(parseFloat(secondsRaw)); + if (isNaN(sec_num) || sec_num < 1) { + return "0" + $I("unit.s"); + } - var sec_num = parseInt(secondsRaw, 10); // don't forget the second param - - var year_secs = 86400 * 365; + var year_secs = 86400 * 365; - var years = Math.floor(sec_num / year_secs); - var days = Math.floor((sec_num - (years * year_secs)) / 86400); - var hours = Math.floor((sec_num - (years * year_secs) - (days * 86400)) / 3600); - var minutes = Math.floor((sec_num - (years * year_secs) - (days * 86400 + hours * 3600)) / 60); - var seconds = sec_num - (years * year_secs) - (days * 86400) - (hours * 3600) - (minutes * 60); + var years = Math.floor(sec_num / year_secs); + var days = 0; + var hours = 0; + var minutes = 0; + var seconds = 0; + if (years < 1e6) { + //At certain large values, we get weird behavior caused by floating-point rounding errors. + //Avoid these by only calculating these if the number of years is small. + days = Math.floor((sec_num - (years * year_secs)) / 86400); + hours = Math.floor((sec_num - (years * year_secs) - (days * 86400)) / 3600); + minutes = Math.floor((sec_num - (years * year_secs) - (days * 86400 + hours * 3600)) / 60); + seconds = sec_num - (years * year_secs) - (days * 86400) - (hours * 3600) - (minutes * 60); + } if (years > 0){ years = this.getDisplayValueExt(years); @@ -4091,7 +4107,7 @@ dojo.declare("com.nuclearunicorn.game.ui.GamePage", null, { if ( seconds ) { timeFormated += seconds + $I("unit.s") + " "; } } - return timeFormated; + return timeFormated.trim(); }, /** @@ -4099,11 +4115,18 @@ dojo.declare("com.nuclearunicorn.game.ui.GamePage", null, { * Just for aestetical pleasness */ toDisplayDays: function(daysRaw){ - var daysNum = parseInt(daysRaw, 10); // don't forget the second param + var daysNum = Math.floor(parseFloat(daysRaw)); + if (isNaN(daysNum) || daysNum < 1) { + return "0" + $I("unit.d"); + } var daysPerYear = this.calendar.daysPerSeason * this.calendar.seasonsPerYear; var years = Math.floor(daysNum / daysPerYear); - var days = daysNum - years * daysPerYear; + var days = 0; + if (years < 1e9) { + //Avoid weird floating-point behavior by only calculating days if the number of years is small. + days = daysNum - years * daysPerYear; + } if (years > 0){ years = this.getDisplayValueExt(years); @@ -4113,7 +4136,7 @@ dojo.declare("com.nuclearunicorn.game.ui.GamePage", null, { if ( years ) { timeFormated = years + $I("unit.y") + " "; } if ( days ) { timeFormated += days + $I("unit.d") + " "; } - return timeFormated; + return timeFormated.trim(); }, toDisplayPercentage: function(percentage, precision, precisionFixed) { diff --git a/js/village.js b/js/village.js index 45e720d7c2..7fc0dd96d1 100644 --- a/js/village.js +++ b/js/village.js @@ -202,16 +202,22 @@ dojo.declare("classes.managers.VillageManager", com.nuclearunicorn.core.TabManag case "scientist": // Science prices bonus for (var i = 0; i < defaultObject.length; i++) { if (defaultObject[i].name == "science") { - defaultObject[i].val -= defaultObject[i].val + var amtDiscounted = defaultObject[i].val * this.game.getLimitedDR(0.05 * burnedParagonRatio * leaderRatio, 1.0); //5% before BP + if (isFinite(amtDiscounted)) { + defaultObject[i].val -= amtDiscounted; + } } } break; case "wise": // Religion bonus for (var i = 0; i < defaultObject.length; i++) { if (defaultObject[i].name == "faith" || defaultObject[i].name == "gold") { - defaultObject[i].val -= defaultObject[i].val + var amtDiscounted = defaultObject[i].val * this.game.getLimitedDR((0.09 + 0.01 * burnedParagonRatio) * leaderRatio, 1.0); //10% before BP + if (isFinite(amtDiscounted)) { + defaultObject[i].val -= amtDiscounted; + } } } break; diff --git a/test/game.test.js b/test/game.test.js index 0ff03fdea8..ad86420359 100644 --- a/test/game.test.js +++ b/test/game.test.js @@ -292,11 +292,11 @@ test("Reset should assign a correct ammount of paragon and preserve certain upgr test("Safe infinity tests", () => { // -------- toDisplaySeconds --------- const tdsVector = [ - [55, "55$unit.s$ "], - [100000, "1$unit.d$ 3$unit.h$ 46$unit.m$ 40$unit.s$ "], - [-5, "-1$unit.y$ 364$unit.d$ "], // we don't judge, we just want it to terminate - [1e20, "3.17T$unit.y$ 167$unit.d$ "], - [1e308, "1$unit.s$ "], // it's getting hard not to judge + [55, "55$unit.s$"], + [100000, "1$unit.d$ 3$unit.h$ 46$unit.m$ 40$unit.s$"], + [-5, "0$unit.s$"], // clamp at zero + [1e20, "3.17T$unit.y$"], // above a certain number of years, don't calculate days anymore + [1e308, "3.17QWWM$unit.y$"], // should at least be accurate to the correct order of magnitude [2e308, "∞"] ] for (const [seconds,display] of tdsVector) {