Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Reserves UI Panel #27

Merged
merged 4 commits into from
Dec 19, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
303 changes: 267 additions & 36 deletions js/challenges.js
Original file line number Diff line number Diff line change
Expand Up @@ -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)){
Expand Down Expand Up @@ -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){
Expand Down Expand Up @@ -738,22 +747,264 @@ 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){
var button = new com.nuclearunicorn.game.ui.BuildingBtn({id: challenge.name, controller: controller}, self.game);
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: "<hr />" }, 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: "",
Expand Down Expand Up @@ -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"),
Expand Down Expand Up @@ -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();
Expand Down
12 changes: 12 additions & 0 deletions res/i18n/en.json
Original file line number Diff line number Diff line change
Expand Up @@ -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",
Expand Down Expand Up @@ -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": "<br>Gain: {0}<br><br>Your game will be reset in order to enable this challenge. {1}",
"challendge.btn.desc.new": "<br>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",
Expand Down