diff --git a/js/challenges.js b/js/challenges.js
index 67e68b8605..0a83b96b88 100644
--- a/js/challenges.js
+++ b/js/challenges.js
@@ -472,6 +472,16 @@ dojo.declare("classes.managers.ChallengesManager", com.nuclearunicorn.core.TabMa
isActive: function(name){
return !!this.getChallenge(name).active;
},
+ /**
+ * Returns the number of Challenges currently marked as pending.
+ */
+ getCountPending: function() {
+ var count = 0;
+ dojo.forEach(this.challenges, function(challenge) {
+ count += challenge.pending ? 1 : 0;
+ });
+ return count;
+ },
researchChallenge: function(challenge) {
if (this.isActive(challenge)){
@@ -677,13 +687,12 @@ dojo.declare("classes.ui.ChallengeBtnController", com.nuclearunicorn.game.ui.Bui
return model.metaCached;
},
- getDescription: function(model) {
- if (this.game.bld.get("chronosphere").val > 0) {
- var msgChronosphere = model.metadata.name == "ironWill" ? $I("challendge.btn.chronosphere.with.ironWill.desc") : $I("challendge.btn.chronosphere.desc");
- } else {
- var msgChronosphere = "";
+ getDescription: function(model) {
+ if (model.metadata.name == "ironWill") { //Show the "your game will be reset" bit for Iron Will only
+ var msgChronosphere = (this.game.bld.get("chronosphere").val > 0) ? $I("challendge.btn.chronosphere.with.ironWill.desc") : "";
+ return this.inherited(arguments) + $I("challendge.btn.desc", [model.metadata.effectDesc, msgChronosphere]);
}
- return this.inherited(arguments) + $I("challendge.btn.desc", [model.metadata.effectDesc, msgChronosphere]) ;
+ return this.inherited(arguments) + $I("challendge.btn.desc.new", [model.metadata.effectDesc]);
},
getName: function(model){
@@ -738,10 +747,13 @@ dojo.declare("classes.ui.ChallengePanel", com.nuclearunicorn.game.ui.Panel, {
game: null,
constructor: function(){
+ this.resetMessage = null;
},
- render: function(container){
+ render: function(container){
var content = this.inherited(arguments);
+ this.updateResetMessage();
+
var self = this;
var controller = new classes.ui.ChallengeBtnController(self.game);
dojo.forEach(this.game.challenges.challenges, function(challenge, i){
@@ -749,11 +761,250 @@ dojo.declare("classes.ui.ChallengePanel", com.nuclearunicorn.game.ui.Panel, {
button.render(content);
self.addChild(button);
});
+ },
+ update: function() {
+ this.inherited(arguments);
+ this.updateResetMessage();
+ },
+
+ updateResetMessage: function() {
+ var numPending = this.game.challenges.getCountPending();
+
+ if (!this.resetMessage) {
+ //Create the reset message if it doesn't exist.
+ this.resetMessage = dojo.create("span", { style: "display: inline-block; margin-bottom: 16px" }, this.contentDiv);
+ }
+
+ //Set the text inside the reset message.
+ var msgText = $I("challendge.panel.pending", [numPending]);
+ if (this.game.bld.get("chronosphere").val > 0) {
+ msgText += $I("challendge.btn.chronosphere.desc");
+ }
+
+ //Don't update every frame, just update if something has changed since last update:
+ if (this.resetMessage.innerHTML != msgText) {
+ this.resetMessage.innerHTML = msgText;
+ }
+
+ //Hide the reset message if zero Challenges are pending:
+ dojo.style(this.resetMessage, "display", numPending > 0 ? "inline-block" : "none");
}
});
+dojo.declare("classes.ui.ReservesPanel", com.nuclearunicorn.game.ui.Panel, {
+
+ statics: { //i.e. shared between all instances of this class
+ maxKittensToDisplayIndividually: 30 //If there are more than this many kittens, don't show any more.
+ },
+
+ constructor: function() {
+ this.reclaimReservesBtn = null;
+ this.reclaimInstructionsText = null;
+ },
+
+ render: function(container) {
+ var content = this.inherited(arguments);
+
+ this.reclaimInstructionsText = dojo.create("span", {
+ innerHTML: $I("challendge.reserves.panel.summary"), style: "display: inline-block; margin-bottom: 16px" }, content);
+
+ this.reclaimReservesBtn = new com.nuclearunicorn.game.ui.ButtonModern({
+ name: $I("challendge.reclaimReserves.label"),
+ description: $I("challendge.reclaimReserves.desc"),
+ handler: dojo.hitch(this, function(){
+ this.game.challenges.reserves.addReserves();
+ this.game.ui.render();
+ }),
+ controller: new com.nuclearunicorn.game.ui.ButtonController(this.game, {
+ updateVisible: function (model) {
+ model.visible = (!this.game.challenges.anyChallengeActive() && !this.game.ironWill &&
+ this.game.challenges.reserves.reservesExist());
+ },
+ })
+ }, this.game);
+ this.reclaimReservesBtn.render(content);
+
+ this.reclaimInstructionsText = dojo.create("span", {
+ innerHTML: $I("challendge.reserves.panel.reclaim.instructions"), style: "margin-bottom: 16px" }, content);
+ //Set visible if & only if we are in at least 1 challenge & have reserves to claim.
+ dojo.style(this.reclaimInstructionsText, "display",
+ (this.game.challenges.reserves.reservesExist() && (this.game.challenges.anyChallengeActive() || this.game.ironWill)) ?
+ "block" : "none");
+
+ var table = dojo.create("table", {}, content);
+ var resPanel = dojo.create("td", { className: "craftStuffPanel", style: "width: 40%" }, table);
+ var kittensPanel = dojo.create("td", { className: "craftStuffPanel", style: "width: 60%" }, table);
+
+ this.renderReservedResources(resPanel);
+ this.renderReservedKittens(kittensPanel);
+ },
+
+ //If there are no resources, displays a message saying as such.
+ renderReservedResources: function(panelContainer) {
+ var resRes = this.game.challenges.reserves.reserveResources;
+ var numReservedTypes = Object.keys(resRes).length; //How many different types of resources are in reserves.
+ if (numReservedTypes < 1) {
+ dojo.create("span", { innerHTML: $I("challendge.reserves.resources.none") }, panelContainer);
+ return;
+ }
+
+ //Create a list of all resources stored in reserves:
+ var label = dojo.create("span", { innerHTML: $I("challendge.reserves.resources.label") }, panelContainer);
+
+ if (!this.game.prestige.getPerk("ascoh").researched) {
+ //Give the player a vague sense of how many resources are in reserves based on how many *types* of resources there are:
+ var keyToUse = "challendge.reserves.resources.lessThan10";
+ if (numReservedTypes >= 30) {
+ var keyToUse = "challendge.reserves.resources.30orMore";
+ } else if (numReservedTypes >= 20) {
+ var keyToUse = "challendge.reserves.resources.20orMore";
+ } else if (numReservedTypes >= 10) {
+ var keyToUse = "challendge.reserves.resources.10orMore";
+ }
+ label.innerHTML += " " + $I(keyToUse);
+ return;
+ }
+
+ //Create a list of all resources stored in reserves:
+ var resTable = dojo.create("table", {}, panelContainer);
+ var numCraftables = 0;
+ var numNonCraftables = 0;
+ //Iterate through resources in the order that they're stored in the resource manager:
+ for (var i in this.game.resPool.resources) {
+ var resObj = this.game.resPool.resources[i]; //Object with all data about that resource
+ var resAmt = resRes[resObj.name] || 0; //Amount of that resource in reserves.
+ if (!resAmt) {
+ continue; //Skip resources whose value (stored in reserves) is zero
+ }
+ //The first time through, skip all craftable resources.
+ if (resObj.craftable && resObj.name != "wood") {
+ continue;
+ }
+ this.createSingleResourceRow(resObj, resAmt, resRes, resTable);
+ numNonCraftables += 1;
+ }
+ var breakRow = dojo.create("tr", {}, resTable);
+ dojo.create("td", { innerHTML: "
" }, breakRow);
+ for (var i in this.game.resPool.resources) {
+ var resObj = this.game.resPool.resources[i]; //Object with all data about that resource
+ var resAmt = resRes[resObj.name] || 0; //Amount of that resource in reserves.
+ if (!resAmt) {
+ continue; //Skip resources whose value (stored in reserves) is zero
+ }
+ //The second time through, skip all non-craftable resources.
+ if (!resObj.craftable || resObj.name == "wood") {
+ continue;
+ }
+ this.createSingleResourceRow(resObj, resAmt, resRes, resTable);
+ numCraftables += 1;
+ }
+
+ if (numCraftables == 0 || numNonCraftables == 0) {
+ //Show a horizontal line in the table ONLY IF there are craftables & non-craftables to separate from each other.
+ dojo.destroy(breakRow);
+ }
+ },
+
+ //Helper function for internal use.
+ createSingleResourceRow: function(resourceObj, resourceAmount, reservedResources, tableContainer) {
+ if (typeof(resourceAmount) !== "number") {
+ console.error("Invalid resourceAmount passed to createSingleResourceRow!");
+ }
+ //Shamelessly copied from left.jsx.js:
+ //This is the code that makes all resoruces be displayed in their color.
+ var resNameCss = {};
+ if (resourceObj.type == "uncommon"){
+ resNameCss = {
+ color: "Coral"
+ };
+ }
+ if (resourceObj.type == "rare"){
+ resNameCss = {
+ color: "orange",
+ textShadow: "1px 0px 10px Coral"
+ };
+ }
+ if (resourceObj.color){
+ resNameCss = {
+ color: resourceObj.color,
+ };
+ }
+ if (resourceObj.style){
+ for (var styleKey in resourceObj.style){
+ resNameCss[styleKey] = resourceObj.style[styleKey];
+ }
+ }
+
+ var tr = dojo.create("tr", {}, tableContainer);
+ dojo.create("td", { innerHTML: resourceObj.title || resourceObj.name + ":", style: resNameCss }, tr);
+ dojo.create("td", { innerHTML: this.game.getDisplayValueExt(resourceAmount) }, tr);
+ },
+
+ //If there are no kittens or cryochambers, displays nothing.
+ renderReservedKittens: function(panelContainer) {
+ var numResCryos = this.game.challenges.reserves.reserveCryochambers; //Number of cryochambers
+ var resKit = this.game.challenges.reserves.reserveKittens; //Array of kittens
+ var numDisplayedSoFar = 0;
+
+ if (numResCryos) {
+ dojo.create("span", { innerHTML: $I("challendge.reserves.cryochambers.label", [numResCryos]) }, panelContainer);
+ }
+
+ if (resKit.length && this.game.prestige.getPerk("ascoh").researched) {
+ //Create a list of all the cryochambers we have stored in reserved & all kittens in them:
+ var kittensTable = dojo.create("table", {}, panelContainer);
+ var census = new classes.ui.village.Census(this.game);
+ for (var i = 0; i < resKit.length; i += 1) {
+ var kitten = resKit[i];
+
+ var tr = dojo.create("tr", {}, kittensTable);
+ if (numDisplayedSoFar >= this.statics.maxKittensToDisplayIndividually) {
+ dojo.create("td", { innerHTML: "..." }, tr);
+ dojo.create("td", { innerHTML: "..." }, tr);
+ dojo.create("td", { innerHTML: "..." }, tr);
+ break;
+ }
+ //Otherwise, we still can display more kittens:
+ dojo.create("td", { innerHTML: census.getStyledName(kitten, false /*is leader panel*/), style: "padding-right: 8px" }, tr);
+ var traitLabel = kitten.trait.title;
+ var rank = kitten.rank;
+ //Note that if we are fractured, the name will be randomized, & we'll obscure other info as well.
+ if (this.game.religion.getPact("fractured").val && this.game.getFeatureFlag("MAUSOLEUM_PACTS")) {
+ traitLabel = "???"; //Unknown trait
+ rank = this.game.rand(4) * 2; //Random rank in range [0,7] with a bias towards even numbers.
+ if (this.game.rand(100) < 25) {
+ rank += 1;
+ }
+ }
+ dojo.create("td", { innerHTML: traitLabel, style: "white-space: nowrap; overflow: clip" }, tr);
+ dojo.create("td", { innerHTML: (rank == 0 ? "" : " (" + $I("village.census.rank") + " " + rank + ")"), style: "white-space: nowrap; overflow: clip" }, tr);
+ numDisplayedSoFar += 1;
+ }
+ }
+ },
+
+ update: function() {
+ var hasReserves = this.game.challenges.reserves.reservesExist();
+ this.inherited(arguments);
+
+ //If the player doesn't have Chronophysics, they probably don't have Chronospheres & therefore won't use reserves.
+ //But if they have reserves, show this panel anyways.
+ this.setVisible(Boolean(hasReserves || this.game.science.get("chronophysics").researched));
+
+ if (this.reclaimReservesBtn) {
+ this.reclaimReservesBtn.update();
+ }
+ if (this.reclaimInstructionsText) {
+ //Set visible if & only if we are in at least 1 challenge & have reserves to claim.
+ dojo.style(this.reclaimInstructionsText, "display",
+ (hasReserves && (this.game.challenges.anyChallengeActive() || this.game.ironWill)) ?
+ "block" : "none");
+ }
+ }
+});
+
dojo.declare("classes.ui.ChallengeEffectsPanel", com.nuclearunicorn.game.ui.Panel, {
//The name of the Challenge that this panel lists the effects of:
challengeName: "",
@@ -848,43 +1099,22 @@ dojo.declare("classes.tab.ChallengesTab", com.nuclearunicorn.game.ui.tab, {
}),
controller: new com.nuclearunicorn.game.ui.ButtonController(this.game, {
updateVisible: function (model) {
- model.visible = false;
- for (var i = 0; i < this.game.challenges.challenges.length; i++){
- if (this.game.challenges.challenges[i].pending){
- model.visible = true;
- }
- }
+ model.visible = this.game.challenges.getCountPending() > 0;
},
getName: function(){
- var numPending = 0;
- for (var i = 0; i < this.game.challenges.challenges.length; i++){
- if (this.game.challenges.challenges[i].pending){
- numPending++;
- }
- }
- return $I("challendge.applyPending.label", [numPending]);
+ return $I("challendge.applyPending.label", [this.game.challenges.getCountPending()]);
}
})
}, this.game);
applyPendingBtn.render(container);
this.applyPendingBtn = applyPendingBtn;
-
- var reclaimReservesBtn = new com.nuclearunicorn.game.ui.ButtonModern({
- name: $I("challendge.reclaimReserves.label"),
- description: $I("challendge.reclaimReserves.desc"),
- handler: dojo.hitch(this, function(){
- this.game.challenges.reserves.addReserves();
- }),
- controller: new com.nuclearunicorn.game.ui.ButtonController(this.game, {
- updateVisible: function (model) {
- model.visible = (!this.game.challenges.anyChallengeActive() && !this.game.ironWill &&
- this.game.challenges.reserves.reservesExist());
- },
- })
- }, this.game);
- reclaimReservesBtn.render(container);
- this.reclaimReservesBtn = reclaimReservesBtn;
+ this.reservesPanel = new classes.ui.ReservesPanel($I("challendge.reserves.panel.label"), this.game.challenges);
+ this.reservesPanel.game = this.game;
+ this.reservesPanel.render(container);
+ dojo.create("div", { style: {
+ marginBottom: "15px"
+ } }, container);
var showChallengeEffectsBtn = new com.nuclearunicorn.game.ui.ButtonModern({
name: $I("challendge.effects.show.label"),
@@ -927,6 +1157,7 @@ dojo.declare("classes.tab.ChallengesTab", com.nuclearunicorn.game.ui.tab, {
this.challengesPanel.update();
//this.conditionsPanel.update();
this.applyPendingBtn.update();
+ this.reservesPanel.update();
this.showChallengeEffectsBtn.update();
for (var i = 0; i < this.challengeEffects.length; i += 1) {
this.challengeEffects[i].update();
diff --git a/res/i18n/en.json b/res/i18n/en.json
index 170dfdcd75..b99f02bb57 100644
--- a/res/i18n/en.json
+++ b/res/i18n/en.json
@@ -288,6 +288,7 @@
"challendge.effects.hide.label": "Hide Challenge effects",
"challendge.effects.panel.label": "Effects of {0} Challenge",
"challendge.panel.label": "Challenges",
+ "challendge.panel.pending": "Pending challenges: {0}. Your game will be reset in order to enable the challenge.",
"challendge.pending": "Pending",
"challendge.reclaimReserves.label": "Reclaim reserves",
"challendge.reclaimReserves.desc": "Reclaim resources from the beyond",
@@ -329,9 +330,20 @@
"challendge.btn.confirmation.msg": "Are you sure you want to start this challenge by resetting the game ?",
"challendge.btn.confirmation_postApocalypse_winterIsComing.msg": "\nWARNING: Limited time to establish kitten housing!",
"challendge.btn.desc": "
Gain: {0}
Your game will be reset in order to enable this challenge. {1}",
+ "challendge.btn.desc.new": "
Gain: {0}",
"challendge.btn.log.message.on.complete": "Congratulations! You complete the challenge {0}.",
"challendge.btn.name.complete": "{0} (Complete)",
"challendge.btn.name.current": "{0} (Active)",
+ "challendge.reserves.cryochambers.label": "Cryochambers in reserve: {0}",
+ "challendge.reserves.panel.label": "Reserves: Store Resources in a Safe Place",
+ "challendge.reserves.panel.reclaim.instructions": "You can reclaim reserves when you are not in any challenge.",
+ "challendge.reserves.panel.summary": "When you reset into a challenge, any resources you would carry over using Chronospheres are instead put into reserves. Reserves persist through resets until you manually reclaim them.",
+ "challendge.reserves.resources.10orMore": "Some",
+ "challendge.reserves.resources.20orMore": "Many",
+ "challendge.reserves.resources.30orMore": "Tons",
+ "challendge.reserves.resources.label": "Resources in reserve:",
+ "challendge.reserves.resources.lessThan10": "A few",
+ "challendge.reserves.resources.none": "There are no resources in reserve.",
"common.collapse.all": "Collapse all",
"common.expand.all": "Expand all",