Skip to content

Commit

Permalink
Tame infinite prices (#76)
Browse files Browse the repository at this point in the history
* Tame infinite prices

* Tame really, really large--but still finite--toDisplaySeconds

* Update expected outputs from toDisplaySeconds to match new behavior
  • Loading branch information
Brent-Call authored Aug 4, 2024
1 parent 782a6bd commit c13778f
Show file tree
Hide file tree
Showing 4 changed files with 55 additions and 25 deletions.
13 changes: 7 additions & 6 deletions core.js
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down Expand Up @@ -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;
}

Expand Down
47 changes: 35 additions & 12 deletions game.js
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -4091,19 +4107,26 @@ dojo.declare("com.nuclearunicorn.game.ui.GamePage", null, {
if ( seconds ) { timeFormated += seconds + $I("unit.s") + " "; }
}

return timeFormated;
return timeFormated.trim();
},

/**
* The same as toDisplaySeconds, but converts ingame days into xYears xDays
* 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);
Expand All @@ -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) {
Expand Down
10 changes: 8 additions & 2 deletions js/village.js
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
10 changes: 5 additions & 5 deletions test/game.test.js
Original file line number Diff line number Diff line change
Expand Up @@ -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, "&infin;"]
]
for (const [seconds,display] of tdsVector) {
Expand Down

0 comments on commit c13778f

Please sign in to comment.