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() {