From 28807ae0ebfab51e435fbe98d516018244f2c528 Mon Sep 17 00:00:00 2001
From: SilenceFactor <149717374+SilenceFactor@users.noreply.github.com>
Date: Tue, 16 Apr 2024 21:26:33 +0200
Subject: [PATCH] Sorting and favorite system
- Kittens can be sorted
- There are pages in the census
- Kittens can be favorited, and favorite kittens are prioritized when you reset with cryochambers
- If a kitten is an engineer census now also lists what they are crafting.
---
game.js | 2 +
js/village.js | 237 +++++++++++++++++++++++++++++++++++++++++++++--
res/i18n/en.json | 10 +-
3 files changed, 239 insertions(+), 10 deletions(-)
diff --git a/game.js b/game.js
index 49fd6bfb92..570b5945d4 100644
--- a/game.js
+++ b/game.js
@@ -4854,10 +4854,12 @@ dojo.declare("com.nuclearunicorn.game.ui.GamePage", null, {
if (cryochambers > 0) {
this.village.sim.sortKittensByExp();
+ this.village.sim.sortKittensByFavorite();
newKittens = this.village.sim.kittens.slice(-cryochambers);
for (var i in newKittens) {
delete newKittens[i].job;
delete newKittens[i].engineerSpeciality;
+ newKittens[i].favorite = true;
}
var usedCryochambers_reset = this.time.filterMetadata([this.time.getVSU("usedCryochambers")], ["name", "val", "on"]);
usedCryochambers_reset[0]["val"] = cryochambers;
diff --git a/js/village.js b/js/village.js
index 2ead1392be..05bb5dfee0 100644
--- a/js/village.js
+++ b/js/village.js
@@ -1083,6 +1083,7 @@ dojo.declare("com.nuclearunicorn.game.village.Kitten", null, {
//obsolete
isSenator: false,
+ favorite: false,
constructor: function(){
this.name = this.names[this.rand(this.names.length)];
@@ -1145,6 +1146,7 @@ dojo.declare("com.nuclearunicorn.game.village.Kitten", null, {
this.color = data.color || 0;
this.variety = data.variety || 0;
this.rarity = data.rarity || 0;
+ this.favorite = data.favorite || false;
for (var job in this.skills) {
if (this.skills[job] > 20001) {
@@ -1181,6 +1183,7 @@ dojo.declare("com.nuclearunicorn.game.village.Kitten", null, {
this.isLeader = data.isLeader || false;
this.isSenator = false;
this.isAdopted = data.isAdopted || false;
+ this.favorite = data.favorite || false;
},
/**
@@ -1224,7 +1227,8 @@ dojo.declare("com.nuclearunicorn.game.village.Kitten", null, {
engineerSpeciality: this.engineerSpeciality || undefined,
rank: this.rank || undefined,
isLeader: this.isLeader || undefined,
- isAdopted: this.isAdopted || undefined
+ isAdopted: this.isAdopted || undefined,
+ favorite: this.favorite || undefined
};
},
@@ -1260,7 +1264,8 @@ dojo.declare("com.nuclearunicorn.game.village.Kitten", null, {
engineerSpeciality: this.engineerSpeciality || undefined,
rank: this.rank || undefined,
isLeader: this.isLeader || undefined,
- isAdopted: this.isAdopted || undefined
+ isAdopted: this.isAdopted || undefined,
+ favorite: this.favorite || undefined
};
// Custom sur/names
if (nameIndex <= 0 || surnameIndex <= 0) {
@@ -2257,6 +2262,41 @@ dojo.declare("classes.village.KittenSim", null, {
});
},
+ sortKittensByFavorite: function(){
+ this.sortKittensByExp();
+ this.kittens.sort(function(a,b) {
+ if(a.favorite == b.favorite){
+ return 0;
+ } else {
+ return a.favorite? 1 : -1;
+ }
+ });
+ },
+
+ sortKittensByColor: function(){
+ this.sortKittensByExp();
+ this.kittens.sort(function(a,b) {
+ if(a.color || b.color){
+ if(a.color && b.color){
+ return 0;
+ }
+ return a.color? 1 : -1;
+ }
+ });
+ },
+
+ sortKittensByVariety: function(){
+ this.sortKittensByExp();
+ this.kittens.sort(function(a,b) {
+ if(a.variety || b.variety) {
+ if(a.variety && b.variety){
+ return 0;
+ }
+ return a.variety? 1 : -1;
+ }
+ });
+ },
+
getKittens: function(){
return this.kittens.length;
},
@@ -3436,6 +3476,21 @@ dojo.declare("classes.ui.village.Census", null, {
filterJob: null,
filterTrait: null,
+ startKitten: 0,
+ sortKittens: null,
+ sortOptions: [{
+ name: "exp",
+ title: $I("village.census.sort.exp")
+ },{
+ name: "favorite",
+ title: $I("village.census.sort.favorite")
+ },{
+ name: "color",
+ title: $I("village.census.sort.color")
+ },{
+ name: "variety",
+ title: $I("village.census.sort.variety")
+ }],
constructor: function(game){
this.game = game;
@@ -3474,6 +3529,7 @@ dojo.declare("classes.ui.village.Census", null, {
dojo.connect(traitSelect, "onchange", this, function (event) {
this.filterTrait = event.target.value;
+ this.startKitten = 0;
this.render(this.container);
});
@@ -3495,22 +3551,80 @@ dojo.declare("classes.ui.village.Census", null, {
dojo.connect(jobSelect, "onchange", this, function(event){
var job = event.target.value;
+ this.startKitten = 0;
this.filterJob = job;
this.render(this.container);
});
- var kittensLimit = 0;
+ //--------------- sorting -----------------
+
+ var selectSorting = dojo.create("select", { style: {float: "right" }}, navbar);
+
+ for (var i = 0; i < this.sortOptions.length; i++){
+ var option = this.sortOptions[i];
+ dojo.create("option", { value: option.name, innerHTML: option.title, selected: (option.name == this.sortKittens)}, selectSorting);
+ }
+
+ dojo.connect(selectSorting, "onchange", this, function(event){
+ var sorting = event.target.value;
+ this.sortKittens = sorting;
+ this.startKitten = 0;
+ this.render(this.container);
+ });
var sim = this.game.village.sim;
- sim.sortKittensByExp();
+ if(!this.sortKittens){
+ sim.sortKittensByExp(); //When switching to this tab, the default sorting is used.
+ }
+
+ switch (this.sortKittens) {
+ case "exp":
+ sim.sortKittensByExp();
+ break;
+ case "favorite":
+ sim.sortKittensByFavorite();
+ break;
+ case "color":
+ sim.sortKittensByColor();
+ break;
+ case "variety":
+ sim.sortKittensByVariety();
+ }
+
+ var filterKittens = 0;
+ var start = this.startKitten;
+ // Filters work differently from sorting as they skip kittens, because of this a workaround is used
+ if(this.filterJob || this.filterTrait){
+ filterKittens = sim.kittens.length;
+ for(var i in sim.kittens){
+ var kitten = sim.kittens[i];
+ if ((this.filterJob && kitten.job !== this.filterJob) || (this.filterTrait && kitten.trait.name !== this.filterTrait)) {
+ filterKittens--;
+ }
+ }
+
+ var maxStart = Math.floor(filterKittens / 10) * 10;
+ filterKittens = Math.floor(Math.min(this.startKitten, filterKittens) / 10) * 10;
+ if (filterKittens == maxStart && filterKittens > 0){ //Used to prevent empty pages
+ filterKittens -= 10;
+ }
+ this.startKitten = filterKittens;
+ start = 0;
+ }
- for (var i = sim.kittens.length - 1; i >= 0 && kittensLimit < 10; i--) {
+ var kittensLimit = 0;
+
+ for (var i = sim.kittens.length - (1 + start); i >= 0 && kittensLimit < 10; i--) {
var kitten = sim.kittens[i];
if ((this.filterJob && kitten.job !== this.filterJob) || (this.filterTrait && kitten.trait.name !== this.filterTrait)) {
continue;
}
+ if(filterKittens > 0){
+ filterKittens--;
+ continue;
+ }
kittensLimit++;
@@ -3548,6 +3662,15 @@ dojo.declare("classes.ui.village.Census", null, {
}, linksDiv);
}
+ var favoriteHref = dojo.create("a", {
+ href: "#", innerHTML: "",
+ className: "favoriteHref",
+ style: {
+ float: "right"
+ },
+ title: "Favorite kitten"
+ }, linksDiv);
+
var unassignHref = dojo.create("a", {
href: "#", innerHTML: $I("village.btn.unassign.job"),
className: "unassignHref",
@@ -3565,6 +3688,12 @@ dojo.declare("classes.ui.village.Census", null, {
}, this.game, i));
+ dojo.connect(favoriteHref, "onclick", this, dojo.partial(function(game, i){
+ var kitten = game.village.sim.kittens[i];
+ kitten.favorite = !kitten.favorite;
+ this.render(this.container);
+ }, this.game, i));
+
if (!this.game.challenges.isActive("anarchy")) {
dojo.connect(leaderHref, "onclick", this, dojo.partial(function(census, i, event){
event.preventDefault();
@@ -3589,9 +3718,86 @@ dojo.declare("classes.ui.village.Census", null, {
kitten: kitten,
unassignHref: unassignHref,
/*senatorHref: senatorHref,*/
- leaderHref: leaderHref
+ leaderHref: leaderHref,
+ favoriteHref: favoriteHref
});
}
+
+ //--------------- Page Switching -----------------
+
+ var pageNumber = Math.floor(this.startKitten / 10) + 1;
+
+ var pageSwitchDiv = dojo.create("div", {
+ innerHTML: pageNumber,
+ style: {
+ display: "inline-block",
+ width: "100%",
+ textAlign: "center",
+ margin: "0 auto"
+ }
+ }, container);
+ //--------------- Last page -----------------
+ var lastHref = dojo.create("a", {
+ href: "#", innerHTML: ">>",
+ className: "lastHref",
+ style: {
+ float: "right"
+ }
+ }, pageSwitchDiv);
+
+ dojo.connect(lastHref, "onclick", this, dojo.partial(function(){
+ this.startKitten = sim.kittens.length / 10;
+ if (Math.floor(this.startKitten) == this.startKitten){
+ this.startKitten -= 1;
+ }
+ this.startKitten = Math.floor(this.startKitten) * 10;
+ this.render(this.container);
+ }));
+ //--------------- Next page -----------------
+ var nextHref = dojo.create("a", {
+ href: "#", innerHTML: $I("village.btn.next"),
+ className: "nextHref",
+ style: {
+ float: "right"
+ }
+ }, pageSwitchDiv);
+
+ dojo.connect(nextHref, "onclick", this, dojo.partial(function(){
+ if(sim.kittens.length - 10 > this.startKitten){
+ this.startKitten += 10;
+ }
+ this.render(this.container);
+ }));
+ //--------------- First Page -----------------
+ var firstHref = dojo.create("a", {
+ href: "#", innerHTML: "<<",
+ className: "firstHref",
+ style: {
+ float: "left"
+ }
+ }, pageSwitchDiv);
+
+ dojo.connect(firstHref, "onclick", this, dojo.partial(function(){
+ this.startKitten = 0;
+ this.render(this.container);
+ }));
+ //--------------- Previous page -----------------
+ var previousHref = dojo.create("a", {
+ href: "#", innerHTML: $I("village.btn.previous"),
+ className: "previousHref",
+ style: {
+ float: "left"
+ }
+ }, pageSwitchDiv);
+
+ dojo.connect(previousHref, "onclick", this, dojo.partial(function(){
+ this.startKitten -= 10;
+ if(this.startKitten < 0){
+ this.startKitten = 0;
+ }
+ this.render(this.container);
+ }));
+
},
makeLeader: function(kitten){
@@ -3644,6 +3850,7 @@ dojo.declare("classes.ui.village.Census", null, {
: this.game.village.sim.getSkillsSorted(kitten.skills);
var info = "";
+ var craftInfo = "";
for (var j = 0; j < Math.min(skillsArr.length,3) ; j++) {
@@ -3678,11 +3885,22 @@ dojo.declare("classes.ui.village.Census", null, {
bonus = bonus * 100;
bonus = bonus > 0 ? " +" + bonus.toFixed(0) + "%" : "";
}
+ if(kitten.job == "engineer" && j == 0){
+ craftInfo = $I("village.census.crafting") + " ";
+ if (kitten.engineerSpeciality){
+ craftInfo += this.game.workshop.getCraft(kitten.engineerSpeciality).label;
+ } else{
+ craftInfo += $I("village.census.crafting.nothing");
+ }
+ } else{
+ craftInfo = "";
+ }
+
info += ""
+ this.game.village.getJob(skillsArr[j].name).title + bonus
- + " (" + this.game.villageTab.skillToText(exp) + " " + expPercent.toFixed() + "%)"
- + "
";
+ + " (" + this.game.villageTab.skillToText(exp) + " " + expPercent.toFixed() + "%) "
+ + craftInfo + "
";
}
return info;
@@ -3821,8 +4039,9 @@ dojo.declare("classes.ui.village.Census", null, {
record.content.innerHTML += skillInfo;
if (!this.game.challenges.isActive("anarchy")) {
- record.leaderHref.innerHTML = kitten.isLeader ? "★" : "☆"; //star-shaped link to reduce visual noise
+ record.leaderHref.innerHTML = kitten.isLeader ? "⚑" : "⚐"; //flag-shaped link to reduce visual noise
}
+ record.favoriteHref.innerHTML = kitten.favorite ? "★" : "☆"; //star-shaped link to reduce visual noise
}
}
diff --git a/res/i18n/en.json b/res/i18n/en.json
index bd77335e44..de9f5d7a41 100644
--- a/res/i18n/en.json
+++ b/res/i18n/en.json
@@ -1865,8 +1865,12 @@
"village.btn.loadout.delete": "X",
"village.btn.loadout.delete.confirm": "Are you sure you want to delete the {0} loadout?",
"village.btn.loadout.empty": "Empty",
-
+ "village.btn.next": "Next Page",
+ "village.btn.previous": "Previous Page",
+
"village.census.age": "years old",
+ "village.census.crafting": "Crafting: ",
+ "village.census.crafting.nothing": "Nothing",
"village.census.filter.all": "All jobs",
"village.census.lbl.festival.duration": "Festival duration",
"village.census.lbl.happiness": "Happiness",
@@ -1874,6 +1878,10 @@
"village.census.leader.propmote": "Promote ({0} exp, {1} gold)",
"village.census.page": "Page {0} of {1}",
"village.census.rank": "rank",
+ "village.census.sort.exp": "Sort by Exp",
+ "village.census.sort.favorite": "Favorites",
+ "village.census.sort.color": "Color",
+ "village.census.sort.variety": "Variety",
"village.census.trait.none": "No trait :< ",
"village.festival.msg.start": "The cultural festival has started",
"village.festival.msg.ext": "The cultural festival has been extended",