diff --git a/images/distillRune.webp b/images/distillRune.webp
new file mode 100644
index 0000000..a390a8f
Binary files /dev/null and b/images/distillRune.webp differ
diff --git a/images/flowersRune.webp b/images/flowersRune.webp
new file mode 100644
index 0000000..29e7668
Binary files /dev/null and b/images/flowersRune.webp differ
diff --git a/images/generatorsRune.webp b/images/generatorsRune.webp
new file mode 100644
index 0000000..433676f
Binary files /dev/null and b/images/generatorsRune.webp differ
diff --git a/images/sandsRune.webp b/images/sandsRune.webp
new file mode 100644
index 0000000..7196462
Binary files /dev/null and b/images/sandsRune.webp differ
diff --git a/images/studyRune.webp b/images/studyRune.webp
new file mode 100644
index 0000000..dbd7fe5
Binary files /dev/null and b/images/studyRune.webp differ
diff --git a/js/Layers/flowers.js b/js/Layers/flowers.js
index a224621..9a0e89c 100644
--- a/js/Layers/flowers.js
+++ b/js/Layers/flowers.js
@@ -326,7 +326,8 @@ addLayer("flowers", {
selectFlowers: {
title: "Collecting",
color: flowersColor,
- style: { minHeight: "50px" },
+ class: { 'candypop-selector': true },
+ style: { minHeight: "50px", color: "black", backgroundColor: flowersColor },
canClick: () => player.flowers.sacrificeType !== "flowers",
onClick: () => player.flowers.sacrificeType = "flowers",
unlocked: () => tmp.flowers.layerShown
@@ -334,7 +335,8 @@ addLayer("flowers", {
selectDistill: {
title: "Distilling",
color: distillColor,
- style: { minHeight: "50px" },
+ class: { 'candypop-selector': true },
+ style: { minHeight: "50px", color: "black", backgroundColor: distillColor },
canClick: () => player.flowers.sacrificeType !== "distill",
onClick: () => player.flowers.sacrificeType = "distill",
unlocked: () => tmp.distill.layerShown
@@ -342,7 +344,8 @@ addLayer("flowers", {
selectStudy: {
title: "Studying",
color: studyColor,
- style: { minHeight: "50px" },
+ class: { 'candypop-selector': true },
+ style: { minHeight: "50px", color: "black", backgroundColor: studyColor },
canClick: () => player.flowers.sacrificeType !== "study",
onClick: () => player.flowers.sacrificeType = "study",
unlocked: () => tmp.study.layerShown
@@ -350,7 +353,8 @@ addLayer("flowers", {
selectSands: {
title: "Experimenting",
color: sandsColor,
- style: { minHeight: "50px" },
+ class: { 'candypop-selector': true },
+ style: { minHeight: "50px", color: "black", backgroundColor: sandsColor },
canClick: () => player.flowers.sacrificeType !== "sands",
onClick: () => player.flowers.sacrificeType = "sands",
unlocked: () => tmp.sands.layerShown
@@ -358,7 +362,8 @@ addLayer("flowers", {
selectGenerators: {
title: "Generating",
color: electricColor,
- style: { minHeight: "50px" },
+ class: { 'candypop-selector': true },
+ style: { minHeight: "50px", color: "black", backgroundColor: electricColor },
canClick: () => player.flowers.sacrificeType !== "generators",
onClick: () => player.flowers.sacrificeType = "generators",
unlocked: () => tmp.generators.layerShown
@@ -366,7 +371,8 @@ addLayer("flowers", {
selectRituals: {
title: "Rituals",
color: ritualsColor,
- style: { minHeight: "50px" },
+ class: { 'candypop-selector': true },
+ style: { minHeight: "50px", color: "white", backgroundColor: ritualsColor },
canClick: () => player.flowers.sacrificeType !== "rituals",
onClick: () => player.flowers.sacrificeType = "rituals",
unlocked: () => tmp.rituals.layerShown
diff --git a/js/Layers/generators.js b/js/Layers/generators.js
index 85d3a95..4badc03 100644
--- a/js/Layers/generators.js
+++ b/js/Layers/generators.js
@@ -402,9 +402,12 @@ addLayer("generators", {
// TODO ritual charger,
"perc1": {
title: "1%",
+ class: { 'generator-selector': true },
style: {
width: "60px",
- minHeight: "60px"
+ minHeight: "60px",
+ color: "black",
+ backgroundColor: electricColor
},
canClick: () => player.generators.allocPerc.neq(0.01),
onClick: () => {
@@ -413,9 +416,12 @@ addLayer("generators", {
},
"perc10": {
title: "10%",
+ class: { 'generator-selector': true },
style: {
width: "60px",
- minHeight: "60px"
+ minHeight: "60px",
+ color: "black",
+ backgroundColor: electricColor
},
canClick: () => player.generators.allocPerc.neq(0.1),
onClick: () => {
@@ -424,9 +430,12 @@ addLayer("generators", {
},
"perc50": {
title: "50%",
+ class: { 'generator-selector': true },
style: {
width: "60px",
- minHeight: "60px"
+ minHeight: "60px",
+ color: "black",
+ backgroundColor: electricColor
},
canClick: () => player.generators.allocPerc.neq(0.5),
onClick: () => {
@@ -435,9 +444,12 @@ addLayer("generators", {
},
"perc100": {
title: "100%",
+ class: { 'generator-selector': true },
style: {
width: "60px",
- minHeight: "60px"
+ minHeight: "60px",
+ color: "black",
+ backgroundColor: electricColor
},
canClick: () => player.generators.allocPerc.neq(1),
onClick: () => {
diff --git a/js/Layers/rituals.js b/js/Layers/rituals.js
index 4b72bc9..4a78eb7 100644
--- a/js/Layers/rituals.js
+++ b/js/Layers/rituals.js
@@ -1,12 +1,47 @@
+Vue.component("rune", {
+ props: ["layer", "data"],
+ template: `
+
+
`
+})
+
+const rituals = {
+ xp: {
+ title: "Ritual of Doctrina",
+ pattern: [ [ 0, 1 ], [ 1, 0 ] ],
+ effect: amount => new Decimal(amount),
+ effectDisplay: () => format(ritualEffect("xp")) + " xp/s",
+ unlocked: () => true
+ }
+};
+
+function ritualEffect(id) {
+ let effect = rituals[id].effect(player.rituals.rituals[id] || 0);
+ if (player.generators.ritualsActive && (player.tab === "generators" || player.generators.timeLoopActive)) {
+ effect = effect.sqrt();
+ }
+ return effect;
+}
+
// Note: id is the corresponding *buyable* ID
function createRuneSelector(id, rune) {
// TODO image based on rune
return {
- color: layers[rune]?.color,
+ color: layers[rune]?.color || ritualsColor,
+ class: {
+ rune: true
+ },
style: {
width: "60px",
minHeight: "60px",
- "--count": () => (getBuyableAmount("rituals", id)?.toNumber() || 0) - Object.values(player.rituals.board).filter(r => r === rune).length
+ background: rune ? 'url(images/' + rune + 'Rune.webp) no-repeat center / contain' : '',
+ backgroundColor: layers[rune]?.color || ritualsColor,
+ "--count": rune === null ? "" : () => (getBuyableAmount("rituals", id)?.toNumber() || 0) - Object.values(player.rituals.board).filter(r => r === rune).length
},
canClick: () => player.rituals.selectedRune !== rune,
onClick: () => player.rituals.selectedRune = rune
@@ -19,6 +54,7 @@ function createRuneBuyable(id, title) {
display() {
return `Craft another rune
Currently: ${formatWhole(getBuyableAmount("rituals", this.id))}
Cost: ${format(this.cost())} ${layers[id].resource}`;
},
+ runeType: id,
color: layers[id].color,
style: {
width: '160px',
@@ -39,6 +75,75 @@ function createRuneBuyable(id, title) {
};
}
+function getRows() {
+ let rows = 3;
+ if (hasMilestone("rituals", 1)) {
+ rows++;
+ }
+ if (hasMilestone("rituals", 4)) {
+ rows++;
+ }
+ return rows;
+}
+
+function getCols() {
+ let cols = 3;
+ if (hasMilestone("rituals", 0)) {
+ cols++;
+ }
+ if (hasMilestone("rituals", 3)) {
+ cols++;
+ }
+ return cols;
+}
+
+function setRune([row, col]) {
+ if (player.rituals.selectedRune == null || (getBuyableAmount("rituals", Object.values(layers.rituals.buyables).find(b => b.runeType === player.rituals.selectedRune).id)?.toNumber() || 0) - Object.values(player.rituals.board).filter(r => r === player.rituals.selectedRune).length > 0) {
+ player.rituals.board[`${row}${col}`] = player.rituals.selectedRune;
+ player.rituals.rituals = getRituals();
+ }
+}
+
+function checkRitual(ritual, top, left) {
+ // Store a lookup table of what runes this pattern is using
+ const types = {};
+
+ for (let r = 0; r < ritual.pattern.length; r++) {
+ for (let c = 0; c < ritual.pattern[r].length; c++) {
+ let patternTile = ritual.pattern[r][c];
+ let tile = player.rituals.board[`${top + r}${left + c}`];
+ if ((patternTile in types && types[patternTile] !== tile) ||
+ tile == null) {
+ return false;
+ }
+ types[patternTile] = tile;
+ }
+ }
+ return true;
+}
+
+function getRituals() {
+ const rows = getRows();
+ const cols = getCols();
+ const ritualCounts = {};
+ Object.entries(rituals).forEach(([id, ritual]) => {
+ let ritualCount = 0;
+ for (let row = 0; row < rows && row <= rows - ritual.pattern.length; row++) {
+ for (let col = 0; col < cols && col <= cols - ritual.pattern[0].length; col++) {
+ // [row, col] is the top left of the ritual
+ // TODO allow negative numbers to represent "not this type"
+ if (checkRitual(ritual, row, col)) {
+ ritualCount++;
+ }
+ }
+ }
+ if (ritualCount > 0) {
+ ritualCounts[id] = ritualCount;
+ }
+ });
+ return ritualCounts;
+}
+
addLayer("rituals", {
name: "rituals",
image: "images/bright-72804.jpg",
@@ -54,7 +159,8 @@ addLayer("rituals", {
lastLevel: new Decimal(0),
timeLoopActive: false,
board: {},
- selectedRune: null
+ selectedRune: null,
+ rituals: {}
};
},
tabFormat: () => player.tab !== "rituals" ? [] : [
@@ -64,6 +170,10 @@ addLayer("rituals", {
"blank",
["sticky", ["36px", ["clickables"]]],
"blank",
+ ...new Array(getRows()).fill(0).map((_,row) => ["row", new Array(getCols()).fill(0).map((_,col) => ["rune", [row, col]])]),
+ "blank",
+ ...Object.keys(rituals).filter(id => ritualEffect(id).gt(0)).map(id => ["display-text", `${rituals[id].title} (${player.rituals.rituals[id]}): ${rituals[id].effectDisplay()}`]),
+ "blank",
["milestones-filtered", [2, 5, 6]]
],
update(diff) {
@@ -71,6 +181,9 @@ addLayer("rituals", {
if (player.generators.ritualsActive && (player.tab === "generators" || player.generators.timeLoopActive)) {
diff = diff / 10;
}
+ let xpGain = ritualEffect("xp");
+ player[this.layer].xp = player[this.layer].xp.add(xpGain);
+ checkJobXP(this.layer);
}
},
milestones: {
@@ -99,7 +212,7 @@ addLayer("rituals", {
5: {
title: "You must not be seen.",
requirementDescription: "Level 10",
- "effectDescription": "Unlock the Ritual of Ascent",
+ "effectDescription": "Unlock the Ritual of Ascensio",
done: () => player.rituals.xp.gte(1e9),
unlocked: () => hasMilestone("rituals", 2)
},
@@ -112,6 +225,8 @@ addLayer("rituals", {
}
},
clickables: {
+ rows: 1,
+ cols: 7,
11: {
title: "Clear All",
style: {
diff --git a/js/components.js b/js/components.js
index 691dec6..341fbe7 100644
--- a/js/components.js
+++ b/js/components.js
@@ -349,7 +349,7 @@ function loadVue() {
`
})
-
+
// data = button size, in px
Vue.component("clickables", {
props: ["layer", "data"],
@@ -381,7 +381,7 @@ function loadVue() {