Compare commits
1 Commits
dev
...
dependabot
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
8747da2c11 |
2
dist/CookieMonster.js
vendored
2
dist/CookieMonster.js
vendored
File diff suppressed because one or more lines are too long
2
dist/CookieMonster.js.map
vendored
2
dist/CookieMonster.js.map
vendored
File diff suppressed because one or more lines are too long
2
dist/CookieMonsterDev.js
vendored
2
dist/CookieMonsterDev.js
vendored
File diff suppressed because one or more lines are too long
2
dist/CookieMonsterDev.js.map
vendored
2
dist/CookieMonsterDev.js.map
vendored
File diff suppressed because one or more lines are too long
24
package-lock.json
generated
24
package-lock.json
generated
@@ -1,19 +1,19 @@
|
|||||||
{
|
{
|
||||||
"name": "@cookiemonsterteam/cookiemonster-mod",
|
"name": "@cookiemonsterteam/cookiemonster-mod",
|
||||||
"version": "2.058.0",
|
"version": "2.053.10",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@cookiemonsterteam/cookiemonster-mod",
|
"name": "@cookiemonsterteam/cookiemonster-mod",
|
||||||
"version": "2.058.0",
|
"version": "2.053.10",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@cookiemonsterteam/cookiemonsterframework": "0.2.3",
|
"@cookiemonsterteam/cookiemonsterframework": "0.2.3",
|
||||||
"@eastdesire/jscolor": "^2.5.1",
|
"@eastdesire/jscolor": "^2.5.1",
|
||||||
"@eslint/compat": "^1.2.7",
|
"@eslint/compat": "^1.2.7",
|
||||||
"@eslint/eslintrc": "^3.2.0",
|
"@eslint/eslintrc": "^3.2.0",
|
||||||
"@eslint/js": "^9.20.0",
|
"@eslint/js": "^9.27.0",
|
||||||
"chai": "^5.2.0",
|
"chai": "^5.2.0",
|
||||||
"eslint": "^9.21.0",
|
"eslint": "^9.21.0",
|
||||||
"eslint-config-airbnb-base": "^15.0.0",
|
"eslint-config-airbnb-base": "^15.0.0",
|
||||||
@@ -171,12 +171,15 @@
|
|||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/js": {
|
"node_modules/@eslint/js": {
|
||||||
"version": "9.21.0",
|
"version": "9.27.0",
|
||||||
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.21.0.tgz",
|
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.27.0.tgz",
|
||||||
"integrity": "sha512-BqStZ3HX8Yz6LvsF5ByXYrtigrV5AXADWLAGc7PH/1SxOb7/FIYYMszZZWiUou/GB9P2lXWk2SV4d+Z8h0nknw==",
|
"integrity": "sha512-G5JD9Tu5HJEu4z2Uo4aHY2sLV64B7CDMXxFzqzjl3NKd6RVzSXNoE80jk7Y0lJkTTkjiIhBAqmlYwjuBY3tvpA==",
|
||||||
"license": "MIT",
|
"license": "MIT",
|
||||||
"engines": {
|
"engines": {
|
||||||
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
},
|
||||||
|
"funding": {
|
||||||
|
"url": "https://eslint.org/donate"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"node_modules/@eslint/object-schema": {
|
"node_modules/@eslint/object-schema": {
|
||||||
@@ -1881,6 +1884,15 @@
|
|||||||
"url": "https://opencollective.com/eslint"
|
"url": "https://opencollective.com/eslint"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
|
"node_modules/eslint/node_modules/@eslint/js": {
|
||||||
|
"version": "9.21.0",
|
||||||
|
"resolved": "https://registry.npmjs.org/@eslint/js/-/js-9.21.0.tgz",
|
||||||
|
"integrity": "sha512-BqStZ3HX8Yz6LvsF5ByXYrtigrV5AXADWLAGc7PH/1SxOb7/FIYYMszZZWiUou/GB9P2lXWk2SV4d+Z8h0nknw==",
|
||||||
|
"license": "MIT",
|
||||||
|
"engines": {
|
||||||
|
"node": "^18.18.0 || ^20.9.0 || >=21.1.0"
|
||||||
|
}
|
||||||
|
},
|
||||||
"node_modules/espree": {
|
"node_modules/espree": {
|
||||||
"version": "10.3.0",
|
"version": "10.3.0",
|
||||||
"resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz",
|
"resolved": "https://registry.npmjs.org/espree/-/espree-10.3.0.tgz",
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@cookiemonsterteam/cookiemonster-mod",
|
"name": "@cookiemonsterteam/cookiemonster-mod",
|
||||||
"version": "2.058.0",
|
"version": "2.053.10",
|
||||||
"description": "Cookie Monster is an add-on that you can load into Cookie Clicker which offers a wide range of tools and statistics to enhance the game. It is not a cheat interface – although it does offer helpers for golden cookies and such, everything can be toggled off at will to only leave how much information you want. This is a helper and everything is an option.",
|
"description": "Cookie Monster is an add-on that you can load into Cookie Clicker which offers a wide range of tools and statistics to enhance the game. It is not a cheat interface – although it does offer helpers for golden cookies and such, everything can be toggled off at will to only leave how much information you want. This is a helper and everything is an option.",
|
||||||
"main": "CookieMonster.js",
|
"main": "CookieMonster.js",
|
||||||
"keywords": [
|
"keywords": [
|
||||||
@@ -59,7 +59,7 @@
|
|||||||
"@eastdesire/jscolor": "^2.5.1",
|
"@eastdesire/jscolor": "^2.5.1",
|
||||||
"@eslint/compat": "^1.2.7",
|
"@eslint/compat": "^1.2.7",
|
||||||
"@eslint/eslintrc": "^3.2.0",
|
"@eslint/eslintrc": "^3.2.0",
|
||||||
"@eslint/js": "^9.20.0",
|
"@eslint/js": "^9.27.0",
|
||||||
"chai": "^5.2.0",
|
"chai": "^5.2.0",
|
||||||
"eslint": "^9.21.0",
|
"eslint": "^9.21.0",
|
||||||
"eslint-config-airbnb-base": "^15.0.0",
|
"eslint-config-airbnb-base": "^15.0.0",
|
||||||
|
|||||||
@@ -104,11 +104,6 @@ export let CacheDoRemakeBuildPrices;
|
|||||||
|
|
||||||
export let CacheHadBuildAura;
|
export let CacheHadBuildAura;
|
||||||
|
|
||||||
export let CacheFarmLevel = -1;
|
|
||||||
export let CacheGardenSoil = -1;
|
|
||||||
export let CacheSupremeIntellect = -1;
|
|
||||||
export let CachePlotChances = [[], [], [], [], [], []];
|
|
||||||
|
|
||||||
/** Store the CPS effect of each god if it was put into each slot */
|
/** Store the CPS effect of each god if it was put into each slot */
|
||||||
export let CacheGods = {
|
export let CacheGods = {
|
||||||
0: [0, 0, 0],
|
0: [0, 0, 0],
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ export function AddAuraInfo(aura) {
|
|||||||
if (Game.cookiesPs === 0) bonusCPSPercentage = Beautify(Infinity);
|
if (Game.cookiesPs === 0) bonusCPSPercentage = Beautify(Infinity);
|
||||||
else bonusCPSPercentage = Beautify((bonusCPS / Game.cookiesPs) * 100);
|
else bonusCPSPercentage = Beautify((bonusCPS / Game.cookiesPs) * 100);
|
||||||
|
|
||||||
l('dragonAuraInfo').style.minHeight = '120px';
|
l('dragonAuraInfo').style.minHeight = '60px';
|
||||||
l('dragonAuraInfo').style.margin = '8px';
|
l('dragonAuraInfo').style.margin = '8px';
|
||||||
l('dragonAuraInfo').appendChild(document.createElement('div')).className = 'line';
|
l('dragonAuraInfo').appendChild(document.createElement('div')).className = 'line';
|
||||||
const div = document.createElement('div');
|
const div = document.createElement('div');
|
||||||
|
|||||||
@@ -1,162 +0,0 @@
|
|||||||
/* eslint-disable no-continue */
|
|
||||||
|
|
||||||
import { CachePlotChances } from '../../Cache/VariablesAndData.js';
|
|
||||||
import CalculateSingleTileChances from './CalculateSingleTileChances.js';
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the possible plants for the next garden tick and updates **`CachePlotChances`** accordingly (expensive.)
|
|
||||||
*
|
|
||||||
* @param {Object} minigame a reference to the garden minigame
|
|
||||||
* @param {number} auraMult the current value of the "Supreme Intellect" dragon aura multiplier
|
|
||||||
*/
|
|
||||||
export default function CalculateAllPlotChances(minigame, auraMult) {
|
|
||||||
const { plantsById, soilsById, soil, isTileUnlocked, getTile } = minigame;
|
|
||||||
const dragonBoost = 1 + 0.05 * auraMult;
|
|
||||||
|
|
||||||
// calculate boosts from neighbors for next tick
|
|
||||||
const boosts = [];
|
|
||||||
for (let y = 0; y < 6; y++) {
|
|
||||||
boosts[y] = [];
|
|
||||||
for (let x = 0; x < 6; x++) boosts[y].push([1, 1]); // [aging, weed]
|
|
||||||
}
|
|
||||||
|
|
||||||
const ApplyMultsToNearbyTiles = function (x, y, range, mults) {
|
|
||||||
for (let dy = -range; dy <= range; dy++) {
|
|
||||||
for (let dx = -range; dx <= range; dx++) {
|
|
||||||
if ((dx !== 0 || dy !== 0) && isTileUnlocked(x + dx, y + dy)) {
|
|
||||||
boosts[y + dy][x + dx][0] *= mults[0];
|
|
||||||
boosts[y + dy][x + dx][1] *= mults[1];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
};
|
|
||||||
|
|
||||||
for (let y = 0; y < 6; y++) {
|
|
||||||
for (let x = 0; x < 6; x++) {
|
|
||||||
const tile = getTile(x, y);
|
|
||||||
if (tile[0] === 0) continue;
|
|
||||||
|
|
||||||
let ageMult;
|
|
||||||
let weedMult;
|
|
||||||
let range;
|
|
||||||
const id = tile[0] - 1;
|
|
||||||
switch (id) {
|
|
||||||
case 7:
|
|
||||||
ageMult = 1.03;
|
|
||||||
weedMult = 1;
|
|
||||||
range = 1;
|
|
||||||
break;
|
|
||||||
case 31:
|
|
||||||
ageMult = 1;
|
|
||||||
weedMult = 0;
|
|
||||||
range = 2;
|
|
||||||
break;
|
|
||||||
case 32:
|
|
||||||
ageMult = 1;
|
|
||||||
weedMult = 0;
|
|
||||||
range = 1;
|
|
||||||
break;
|
|
||||||
case 33:
|
|
||||||
ageMult = 0.5;
|
|
||||||
weedMult = 1;
|
|
||||||
range = 1;
|
|
||||||
break;
|
|
||||||
default:
|
|
||||||
continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
let mult = soilsById[soil].effMult;
|
|
||||||
const matureAge = plantsById[id].mature;
|
|
||||||
const stage = 1 + (tile[1] >= matureAge ? 3 : Math.floor(tile[1] / (matureAge * 0.333)));
|
|
||||||
|
|
||||||
// eslint-disable-next-line default-case
|
|
||||||
switch (stage) {
|
|
||||||
case 1:
|
|
||||||
mult *= 0.1;
|
|
||||||
break;
|
|
||||||
case 2:
|
|
||||||
mult *= 0.25;
|
|
||||||
break;
|
|
||||||
case 3:
|
|
||||||
mult *= 0.5;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (ageMult > 1 || mult < 1) ageMult = (ageMult - 1) * mult + 1;
|
|
||||||
else ageMult /= mult;
|
|
||||||
|
|
||||||
ApplyMultsToNearbyTiles(x, y, range, [ageMult, weedMult]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// initialize all probabilities to current state
|
|
||||||
const plotOutcomes = [[], [], [], [], [], []];
|
|
||||||
|
|
||||||
for (let y = 0; y < 6; y++) {
|
|
||||||
for (let x = 0; x < 6; x++) {
|
|
||||||
if (!isTileUnlocked(x, y)) continue;
|
|
||||||
|
|
||||||
const tile = getTile(x, y);
|
|
||||||
if (tile[0] === 0) plotOutcomes[y][x] = [{ plantId: -1, isMature: false, p: 1 }];
|
|
||||||
else {
|
|
||||||
const plantId = tile[0] - 1;
|
|
||||||
plotOutcomes[y][x] = [{ plantId, isMature: tile[1] >= plantsById[plantId].mature, p: 1 }];
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
// update each tile's chances
|
|
||||||
for (let y = 0; y < 6; y++) {
|
|
||||||
for (let x = 0; x < 6; x++) {
|
|
||||||
if (!isTileUnlocked(x, y)) continue;
|
|
||||||
|
|
||||||
// collect neighbor probabilities
|
|
||||||
const neighResults = [];
|
|
||||||
const cardinals = [];
|
|
||||||
for (let dy = -1; dy <= 1; dy++)
|
|
||||||
for (let dx = -1; dx <= 1; dx++) {
|
|
||||||
if ((dx !== 0 || dy !== 0) && isTileUnlocked(x + dx, y + dy)) {
|
|
||||||
neighResults.push(plotOutcomes[y + dy][x + dx]);
|
|
||||||
if (dx === 0 || dy === 0) cardinals.push(neighResults.length - 1); // save indices of cardinal neighbors
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const tile = getTile(x, y);
|
|
||||||
|
|
||||||
plotOutcomes[y][x] = CalculateSingleTileChances(
|
|
||||||
minigame,
|
|
||||||
tile[0] - 1,
|
|
||||||
tile[1],
|
|
||||||
neighResults,
|
|
||||||
cardinals,
|
|
||||||
boosts[y][x],
|
|
||||||
dragonBoost,
|
|
||||||
);
|
|
||||||
|
|
||||||
// save results
|
|
||||||
CachePlotChances[y][x] = [];
|
|
||||||
|
|
||||||
const emptyP = plotOutcomes[y][x]
|
|
||||||
.filter((o) => o.plantId === -1)
|
|
||||||
.reduce((s, o) => s + o.p, 0);
|
|
||||||
if (emptyP > 0) CachePlotChances[y][x].push({ plantId: -1, maturityP: 0, p: emptyP });
|
|
||||||
|
|
||||||
for (let id = 0; id < plantsById.length; id++) {
|
|
||||||
const matches = plotOutcomes[y][x].filter((o) => o.plantId === id);
|
|
||||||
if (matches.length > 1) {
|
|
||||||
const plantP = matches.reduce((s, o) => s + o.p, 0);
|
|
||||||
const maturityP =
|
|
||||||
matches.filter((o) => o.isMature === true).reduce((s, o) => s + o.p, 0) / plantP;
|
|
||||||
CachePlotChances[y][x].push({ plantId: id, maturityP, p: plantP });
|
|
||||||
} else if (matches.length === 1)
|
|
||||||
CachePlotChances[y][x].push({
|
|
||||||
plantId: id,
|
|
||||||
maturityP: matches[0].isMature ? 1 : 0,
|
|
||||||
p: matches[0].p,
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
CachePlotChances[y][x].sort((a, b) => a.plantId - b.plantId);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@@ -1,240 +0,0 @@
|
|||||||
/* eslint-disable guard-for-in */
|
|
||||||
/* eslint-disable no-continue */
|
|
||||||
/* eslint-disable no-restricted-syntax */
|
|
||||||
/* eslint-disable no-param-reassign */
|
|
||||||
|
|
||||||
/**
|
|
||||||
* Calculates the possible plants for a tile after the next garden tick.
|
|
||||||
*
|
|
||||||
* @param {Object} minigame A reference to the garden minigame
|
|
||||||
* @param {number} plantId The ID of the tile's current plant (-1 if empty)
|
|
||||||
* @param {number} age The age of the tile's current plant (ignored if empty)
|
|
||||||
* @param {Object[][]} neighResults The calculated results of each neighboring tile
|
|
||||||
* @param {number[]} cardinals The indices of orthogonally adjacent tiles in `neighResults`
|
|
||||||
* @param {number[]} tileBoosts The boosts to aging and weed spawning this tile is recieving from nearby tiles in the format `[ageMult, weedMult]`
|
|
||||||
* @param {number} dragonBoost The current calculated value of the boost from the "Supreme Intellect" dragon aura
|
|
||||||
* @returns {{plantId: number, isMature: boolean, p: number}[]} The possible resulting tile states and their probabilities
|
|
||||||
*/
|
|
||||||
export default function CalculateSingleTileChances(
|
|
||||||
minigame,
|
|
||||||
plantId,
|
|
||||||
age,
|
|
||||||
neighResults,
|
|
||||||
cardinals,
|
|
||||||
tileBoosts,
|
|
||||||
dragonBoost,
|
|
||||||
) {
|
|
||||||
const { getMuts, plants, plantsById, plantContam, soilsById, soil } = minigame;
|
|
||||||
const soilWeedMult = soilsById[soil].weedMult;
|
|
||||||
|
|
||||||
const epsilon = 1e-12;
|
|
||||||
const futureStates = [];
|
|
||||||
const AddOutcome = function (outcome) {
|
|
||||||
if (outcome.p < epsilon) return;
|
|
||||||
|
|
||||||
const existing = futureStates.find(
|
|
||||||
(o) =>
|
|
||||||
o.plantId === outcome.plantId &&
|
|
||||||
(outcome.plantId === -1 || o.isMature === outcome.isMature),
|
|
||||||
);
|
|
||||||
if (existing) existing.p += outcome.p;
|
|
||||||
else futureStates.push(outcome);
|
|
||||||
};
|
|
||||||
let runningP = 1;
|
|
||||||
|
|
||||||
if (plantId !== -1) {
|
|
||||||
// tile has plant
|
|
||||||
const currentPlant = plantsById[plantId];
|
|
||||||
|
|
||||||
const AgeThresholdP = function (multiplier, threshold) {
|
|
||||||
// probability that plant's age increases by at least threshold
|
|
||||||
const minAge = currentPlant.ageTick * multiplier;
|
|
||||||
const maxAge = minAge + currentPlant.ageTickR * multiplier;
|
|
||||||
|
|
||||||
if (Math.abs(maxAge - minAge) < epsilon) {
|
|
||||||
if (minAge >= threshold) return 1;
|
|
||||||
if (minAge < threshold - 1) return 0;
|
|
||||||
return minAge - (threshold - 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (threshold <= minAge) return 1;
|
|
||||||
if (threshold - 1 >= maxAge) return 0;
|
|
||||||
|
|
||||||
const lower = Math.max(minAge, threshold - 1);
|
|
||||||
const upper = Math.min(maxAge, threshold);
|
|
||||||
|
|
||||||
const a = 0.5 * (upper - (threshold - 1)) ** 2 - 0.5 * (lower - (threshold - 1)) ** 2;
|
|
||||||
const b = Math.max(0, maxAge - Math.max(minAge, threshold));
|
|
||||||
|
|
||||||
return (a + b) / (maxAge - minAge);
|
|
||||||
};
|
|
||||||
|
|
||||||
// death
|
|
||||||
if (!currentPlant.immortal) {
|
|
||||||
const deathP = AgeThresholdP(tileBoosts[0] * dragonBoost, 100 - age);
|
|
||||||
AddOutcome({ plantId: -1, isMature: false, p: deathP * runningP });
|
|
||||||
runningP -= deathP * runningP;
|
|
||||||
}
|
|
||||||
|
|
||||||
// contamination
|
|
||||||
if (!currentPlant.noContam) {
|
|
||||||
const contamChances = [];
|
|
||||||
|
|
||||||
for (const key in plantContam) {
|
|
||||||
let inclusionP = plantContam[key];
|
|
||||||
if (plants[key].weed) inclusionP *= soilWeedMult;
|
|
||||||
contamChances.push([key, inclusionP]);
|
|
||||||
}
|
|
||||||
|
|
||||||
let totalContamP = 0;
|
|
||||||
for (const [key1, inclusionP1] of contamChances) {
|
|
||||||
if (plants[key1].id === plantId || inclusionP1 === 0) continue;
|
|
||||||
|
|
||||||
let hasNeighborP = 0;
|
|
||||||
for (const i of cardinals) {
|
|
||||||
let isNeighborP = 0;
|
|
||||||
for (const o of neighResults[i]) {
|
|
||||||
if (o.plantId === key1 && o.isMature) isNeighborP += o.p;
|
|
||||||
}
|
|
||||||
hasNeighborP += isNeighborP * (1 - hasNeighborP);
|
|
||||||
}
|
|
||||||
if (hasNeighborP < epsilon) continue;
|
|
||||||
|
|
||||||
let q = [1];
|
|
||||||
for (const [key2, inclusionP2] of contamChances) {
|
|
||||||
if (key1 !== key2) {
|
|
||||||
const newQ = Array(q.length + 1).fill(0);
|
|
||||||
for (let k = 0; k < q.length; k++) {
|
|
||||||
newQ[k] += q[k] * (1 - inclusionP2);
|
|
||||||
newQ[k + 1] += q[k] * inclusionP2;
|
|
||||||
}
|
|
||||||
q = newQ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const E = q.reduce((acc, probXk, k) => acc + probXk / (1 + k), 0);
|
|
||||||
const contamP = inclusionP1 * E * hasNeighborP * runningP;
|
|
||||||
AddOutcome({ plantId: plants[key1].id, isMature: false, p: contamP });
|
|
||||||
totalContamP += contamP;
|
|
||||||
}
|
|
||||||
runningP -= totalContamP;
|
|
||||||
}
|
|
||||||
|
|
||||||
// survival (remaining probability)
|
|
||||||
const maturityP = AgeThresholdP(tileBoosts[0] * dragonBoost, currentPlant.mature - age);
|
|
||||||
AddOutcome({ plantId, isMature: true, p: maturityP * runningP });
|
|
||||||
AddOutcome({ plantId, isMature: false, p: (1 - maturityP) * runningP });
|
|
||||||
} else {
|
|
||||||
// tile is empty
|
|
||||||
let noNeighborsChance = 1;
|
|
||||||
neighResults.forEach((neighbor) => {
|
|
||||||
let emptyChance = 0;
|
|
||||||
const emptyOutcome = neighbor.find((outcome) => outcome.plantId === -1);
|
|
||||||
if (emptyOutcome) emptyChance = emptyOutcome.p;
|
|
||||||
noNeighborsChance *= emptyChance;
|
|
||||||
});
|
|
||||||
|
|
||||||
// weeds
|
|
||||||
const weedChance = 0.002 * soilWeedMult * tileBoosts[1];
|
|
||||||
AddOutcome({ plantId: 13, isMature: false, p: weedChance * noNeighborsChance });
|
|
||||||
AddOutcome({ plantId: -1, isMature: false, p: (1 - weedChance) * noNeighborsChance });
|
|
||||||
|
|
||||||
runningP -= noNeighborsChance;
|
|
||||||
|
|
||||||
// mutation
|
|
||||||
if (noNeighborsChance < 1) {
|
|
||||||
let totalMutationP = 0;
|
|
||||||
|
|
||||||
const CombineNeighbors = function (i = 0, current = [], comboP = 1, results = []) {
|
|
||||||
if (i >= neighResults.length) {
|
|
||||||
results.push({ tiles: current.slice(), comboP });
|
|
||||||
return results;
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const state of neighResults[i])
|
|
||||||
CombineNeighbors(i + 1, [...current, state], comboP * state.p, results);
|
|
||||||
|
|
||||||
return results;
|
|
||||||
};
|
|
||||||
|
|
||||||
const loopsBase = (soilsById[soil].key === 'woodchips' ? 3 : 1) * dragonBoost;
|
|
||||||
for (const combo of CombineNeighbors()) {
|
|
||||||
// possible combinations of neighboring tiles
|
|
||||||
const neighs = {};
|
|
||||||
const neighsM = {};
|
|
||||||
|
|
||||||
for (const tile of combo.tiles) {
|
|
||||||
if (tile.plantId === -1) continue;
|
|
||||||
const { key } = plantsById[tile.plantId];
|
|
||||||
neighs[key] = (neighs[key] || 0) + 1;
|
|
||||||
if (tile.isMature) neighsM[key] = (neighsM[key] || 0) + 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
const muts = getMuts(neighs, neighsM);
|
|
||||||
|
|
||||||
let perLoopMutationP = 0; // probability that any mutation occurs on a single loop with this combo
|
|
||||||
const mutationChances = [];
|
|
||||||
for (const [key, mutValue] of muts) {
|
|
||||||
let inclusionP = mutValue;
|
|
||||||
if (plants[key].weed) inclusionP *= soilWeedMult;
|
|
||||||
if (plants[key].weed || plants[key].fungus) inclusionP *= tileBoosts[1];
|
|
||||||
if (inclusionP > 0) mutationChances.push([key, inclusionP]);
|
|
||||||
}
|
|
||||||
|
|
||||||
const perLoopMutations = [];
|
|
||||||
for (const [key1, inclusionP1] of mutationChances) {
|
|
||||||
let q = [1];
|
|
||||||
for (const [key2, inclusionP2] of mutationChances) {
|
|
||||||
if (key1 !== key2) {
|
|
||||||
const newQ = Array(q.length + 1).fill(0);
|
|
||||||
for (let k = 0; k < q.length; k++) {
|
|
||||||
newQ[k] += q[k] * (1 - inclusionP2);
|
|
||||||
newQ[k + 1] += q[k] * inclusionP2;
|
|
||||||
}
|
|
||||||
q = newQ;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const E = q.reduce((acc, probXk, k) => acc + probXk / (1 + k), 0);
|
|
||||||
const mutationP = inclusionP1 * E;
|
|
||||||
perLoopMutationP += mutationP;
|
|
||||||
perLoopMutations.push([key1, mutationP * combo.comboP * runningP]);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (perLoopMutationP === 0) continue;
|
|
||||||
|
|
||||||
let loopsBoost = 1;
|
|
||||||
if (loopsBase > 1) {
|
|
||||||
if (Number.isInteger(loopsBase)) {
|
|
||||||
loopsBoost = (1 - (1 - perLoopMutationP) ** loopsBase) / perLoopMutationP;
|
|
||||||
} else {
|
|
||||||
const loopsFloor = Math.floor(loopsBase);
|
|
||||||
const loopsFrac = loopsBase % 1;
|
|
||||||
const boostN = (1 - (1 - perLoopMutationP) ** loopsFloor) / perLoopMutationP;
|
|
||||||
const boostNp1 = (1 - (1 - perLoopMutationP) ** (loopsFloor + 1)) / perLoopMutationP;
|
|
||||||
loopsBoost = (1 - loopsFrac) * boostN + loopsFrac * boostNp1;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
for (const [key, mutationP] of perLoopMutations) {
|
|
||||||
AddOutcome({ plantId: plants[key].id, maturityP: 0, p: mutationP * loopsBoost });
|
|
||||||
totalMutationP += mutationP * loopsBoost;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
runningP -= totalMutationP;
|
|
||||||
}
|
|
||||||
|
|
||||||
// nothing (remaining probability)
|
|
||||||
AddOutcome({ plantId: -1, isMature: false, p: runningP });
|
|
||||||
}
|
|
||||||
|
|
||||||
const total = futureStates.reduce((sum, o) => sum + o.p, 0);
|
|
||||||
if (Math.abs(total - 1) > 1e-9) {
|
|
||||||
futureStates.forEach((o) => {
|
|
||||||
o.p /= total;
|
|
||||||
});
|
|
||||||
}
|
|
||||||
|
|
||||||
return futureStates;
|
|
||||||
}
|
|
||||||
@@ -1,154 +1,42 @@
|
|||||||
/* eslint-disable guard-for-in */
|
|
||||||
/* eslint-disable no-restricted-syntax */
|
|
||||||
|
|
||||||
import Beautify from '../../BeautifyAndFormatting/Beautify.js';
|
import Beautify from '../../BeautifyAndFormatting/Beautify.js';
|
||||||
import { TooltipName } from '../../VariablesAndData.js';
|
import { TooltipName } from '../../VariablesAndData.js';
|
||||||
import * as Create from '../CreateTooltip.js';
|
import * as Create from '../CreateTooltip.js';
|
||||||
import {
|
|
||||||
CacheFarmLevel,
|
|
||||||
CacheGardenSoil,
|
|
||||||
CachePlotChances,
|
|
||||||
CacheSupremeIntellect,
|
|
||||||
} from '../../../Cache/VariablesAndData.js';
|
|
||||||
import CalculateAllPlotChances from '../../HelperFunctions/CalculateAllPlotChances.js';
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This function adds extra info to the garden plot tooltips
|
* This function adds extra info to the Garden plots tooltips
|
||||||
* It adds to the additional information to l('CMTooltipArea')
|
* It adds to the additional information to l('CMTooltipArea')
|
||||||
*/
|
*/
|
||||||
export default function GardenPlots() {
|
export default function GardenPlots() {
|
||||||
const { minigame } = Game.Objects.Farm;
|
const { minigame } = Game.Objects.Farm;
|
||||||
if (Game.mods.cookieMonsterFramework.saveData.cookieMonsterMod.settings.TooltipPlots) {
|
if (
|
||||||
const tooltipBorder = l('CMTooltipBorder');
|
Game.mods.cookieMonsterFramework.saveData.cookieMonsterMod.settings.TooltipPlots &&
|
||||||
|
minigame.plot[TooltipName[1]][TooltipName[0]][0] !== 0
|
||||||
if (minigame.plot[TooltipName[1]][TooltipName[0]][0] !== 0) {
|
) {
|
||||||
const rewardTooltip = document.createElement('div');
|
|
||||||
rewardTooltip.appendChild(Create.TooltipCreateHeader('Reward (Current / Maximum)'));
|
|
||||||
const mature =
|
const mature =
|
||||||
minigame.plot[TooltipName[1]][TooltipName[0]][1] >=
|
minigame.plot[TooltipName[1]][TooltipName[0]][1] >
|
||||||
minigame.plantsById[minigame.plot[TooltipName[1]][TooltipName[0]][0] - 1].mature;
|
minigame.plantsById[minigame.plot[TooltipName[1]][TooltipName[0]][0] - 1].mature;
|
||||||
const plantName =
|
const plantName =
|
||||||
minigame.plantsById[minigame.plot[TooltipName[1]][TooltipName[0]][0] - 1].name;
|
minigame.plantsById[minigame.plot[TooltipName[1]][TooltipName[0]][0] - 1].name;
|
||||||
|
l('CMTooltipBorder').appendChild(Create.TooltipCreateHeader('Reward (Current / Maximum)'));
|
||||||
const reward = document.createElement('div');
|
const reward = document.createElement('div');
|
||||||
reward.id = 'CMTooltipPlantReward';
|
reward.id = 'CMTooltipPlantReward';
|
||||||
rewardTooltip.appendChild(reward);
|
l('CMTooltipBorder').appendChild(reward);
|
||||||
if (plantName === 'Chocoroot' || plantName === 'White chocoroot') {
|
if (plantName === 'Chocoroot' || plantName === 'White chocoroot') {
|
||||||
reward.textContent = `${
|
l('CMTooltipPlantReward').textContent = `${
|
||||||
mature ? Beautify(Math.min(Game.cookies * 0.03, Game.cookiesPs * 60 * 3)) : '0'
|
mature ? Beautify(Math.min(Game.cookies * 0.03, Game.cookiesPs * 60 * 3)) : '0'
|
||||||
} / ${Beautify(Game.cookiesPs * 60 * 3)}`;
|
} / ${Beautify(Game.cookiesPs * 60 * 3)}`;
|
||||||
} else if (plantName === 'Bakeberry') {
|
} else if (plantName === 'Bakeberry') {
|
||||||
reward.textContent = `${
|
l('CMTooltipPlantReward').textContent = `${
|
||||||
mature ? Beautify(Math.min(Game.cookies * 0.03, Game.cookiesPs * 60 * 30)) : '0'
|
mature ? Beautify(Math.min(Game.cookies * 0.03, Game.cookiesPs * 60 * 30)) : '0'
|
||||||
} / ${Beautify(Game.cookiesPs * 60 * 30)}`;
|
} / ${Beautify(Game.cookiesPs * 60 * 30)}`;
|
||||||
} else if (plantName === 'Queenbeet') {
|
} else if (plantName === 'Queenbeet') {
|
||||||
reward.textContent = `${
|
l('CMTooltipPlantReward').textContent = `${
|
||||||
mature ? Beautify(Math.min(Game.cookies * 0.04, Game.cookiesPs * 60 * 60)) : '0'
|
mature ? Beautify(Math.min(Game.cookies * 0.04, Game.cookiesPs * 60 * 60)) : '0'
|
||||||
} / ${Beautify(Game.cookiesPs * 60 * 60)}`;
|
} / ${Beautify(Game.cookiesPs * 60 * 60)}`;
|
||||||
} else if (plantName === 'Duketater') {
|
} else if (plantName === 'Duketater') {
|
||||||
reward.textContent = `${
|
l('CMTooltipPlantReward').textContent = `${
|
||||||
mature ? Beautify(Math.min(Game.cookies * 0.08, Game.cookiesPs * 60 * 120)) : '0'
|
mature ? Beautify(Math.min(Game.cookies * 0.08, Game.cookiesPs * 60 * 120)) : '0'
|
||||||
} / ${Beautify(Game.cookiesPs * 60 * 120)}`;
|
} / ${Beautify(Game.cookiesPs * 60 * 120)}`;
|
||||||
} else rewardTooltip.style.display = 'none';
|
} else l('CMTooltipArea').style.display = 'none';
|
||||||
|
|
||||||
if (rewardTooltip.style.display !== 'none') tooltipBorder.appendChild(rewardTooltip);
|
|
||||||
}
|
|
||||||
|
|
||||||
if (
|
|
||||||
minigame.parent.level !== CacheFarmLevel ||
|
|
||||||
minigame.soil !== CacheGardenSoil ||
|
|
||||||
Game.auraMult('Supreme Intellect') !== CacheSupremeIntellect
|
|
||||||
) {
|
|
||||||
CacheFarmLevel = minigame.parent.level;
|
|
||||||
CacheGardenSoil = minigame.soil;
|
|
||||||
CacheSupremeIntellect = Game.auraMult('Supreme Intellect');
|
|
||||||
CalculateAllPlotChances(minigame, CacheSupremeIntellect);
|
|
||||||
}
|
|
||||||
const plotChances = CachePlotChances[TooltipName[1]][TooltipName[0]];
|
|
||||||
|
|
||||||
const plotTooltip = document.createElement('div');
|
|
||||||
if (l('CMTooltipPlantReward')) plotTooltip.style.marginTop = '5px';
|
|
||||||
plotTooltip.appendChild(Create.TooltipCreateHeader('After Next Tick:'));
|
|
||||||
|
|
||||||
const showIcon = [];
|
|
||||||
for (const id in minigame.plantsById) {
|
|
||||||
showIcon[id] = minigame.plantsById[id].unlocked !== 0;
|
|
||||||
for (let y = 0; y < 6 && !showIcon[id]; y++) {
|
|
||||||
for (let x = 0; x < 6; x++) {
|
|
||||||
// eslint-disable-next-line eqeqeq
|
|
||||||
if (minigame.plot[y][x][0] - 1 == id) {
|
|
||||||
showIcon[id] = true;
|
|
||||||
break;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
const tooltipOutcomes = document.createElement('div');
|
|
||||||
const ConvertToPercentage = function (x) {
|
|
||||||
if (x <= 0) return '0%';
|
|
||||||
if (x >= 1) return '100%';
|
|
||||||
|
|
||||||
const decimals =
|
|
||||||
Game.mods.cookieMonsterFramework.saveData.cookieMonsterMod.settings.ScaleDecimals + 1;
|
|
||||||
const delta = 10 ** -decimals;
|
|
||||||
|
|
||||||
const xH = x * 100;
|
|
||||||
if (xH < delta) return `<${Beautify(delta)}%`;
|
|
||||||
if (xH > 100 - delta) return `>${Beautify(100 - delta)}%`;
|
|
||||||
|
|
||||||
return `${Beautify(xH)}%`;
|
|
||||||
};
|
|
||||||
for (const outcome of plotChances) {
|
|
||||||
const outcomeInfo = document.createElement('div');
|
|
||||||
outcomeInfo.style.height = '48px';
|
|
||||||
outcomeInfo.style.display = 'flex';
|
|
||||||
outcomeInfo.style.alignItems = 'center';
|
|
||||||
|
|
||||||
const outcomeIcon = document.createElement('img');
|
|
||||||
outcomeIcon.style.float = 'left';
|
|
||||||
outcomeIcon.style.objectFit = 'none';
|
|
||||||
if (outcome.plantId === -1) {
|
|
||||||
outcomeIcon.style.width = '40px';
|
|
||||||
outcomeIcon.style.height = '40px';
|
|
||||||
outcomeIcon.style.margin = '4px';
|
|
||||||
outcomeIcon.src = `${Game.resPath}img/gardenPlots.png`;
|
|
||||||
outcomeIcon.style.objectPosition = `${0 * -40}px ${0 * -40}px`;
|
|
||||||
|
|
||||||
// add brown colour
|
|
||||||
outcomeIcon.style.background = 'saddlebrown';
|
|
||||||
outcomeIcon.style.maskImage = `url(${Game.resPath}img/gardenPlots.png)`;
|
|
||||||
} else {
|
|
||||||
outcomeIcon.style.width = '48px';
|
|
||||||
outcomeIcon.style.height = '48px';
|
|
||||||
outcomeIcon.style.margin = '0px';
|
|
||||||
|
|
||||||
if (!showIcon[outcome.plantId]) {
|
|
||||||
outcomeIcon.src = `${Game.resPath}img/icons.png?v=${Game.version}`;
|
|
||||||
outcomeIcon.style.objectPosition = `${0 * -48}px ${7 * -48}px`; // question mark
|
|
||||||
} else {
|
|
||||||
outcomeIcon.src = `${Game.resPath}img/gardenPlants.png?v=${Game.version}`;
|
|
||||||
outcomeIcon.style.objectPosition = `${4 * -48}px ${minigame.plantsById[outcome.plantId].icon * -48}px`;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
outcomeInfo.appendChild(outcomeIcon);
|
|
||||||
|
|
||||||
const outcomeInfoText = document.createElement('div');
|
|
||||||
outcomeInfoText.style.marginLeft = '5px';
|
|
||||||
|
|
||||||
const outcomeProbability = document.createElement('div');
|
|
||||||
outcomeProbability.textContent = ConvertToPercentage(outcome.p);
|
|
||||||
outcomeInfoText.appendChild(outcomeProbability);
|
|
||||||
|
|
||||||
if (outcome.plantId !== -1) {
|
|
||||||
const outcomeMaturityChance = document.createElement('small');
|
|
||||||
outcomeMaturityChance.innerHTML = `<small>${ConvertToPercentage(outcome.maturityP)} chance of being mature</small>`;
|
|
||||||
outcomeInfoText.appendChild(outcomeMaturityChance);
|
|
||||||
}
|
|
||||||
|
|
||||||
outcomeInfo.appendChild(outcomeInfoText);
|
|
||||||
tooltipOutcomes.appendChild(outcomeInfo);
|
|
||||||
}
|
|
||||||
plotTooltip.appendChild(tooltipOutcomes);
|
|
||||||
tooltipBorder.appendChild(plotTooltip);
|
|
||||||
} else l('CMTooltipArea').style.display = 'none';
|
} else l('CMTooltipArea').style.display = 'none';
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,6 +1,5 @@
|
|||||||
/** Functions related to replacing tooltips */
|
/** Functions related to replacing tooltips */
|
||||||
|
|
||||||
import CalculateAllPlotChances from '../../Disp/HelperFunctions/CalculateAllPlotChances.js';
|
|
||||||
import { CreateTooltip } from '../../Disp/Tooltips/Tooltip.js';
|
import { CreateTooltip } from '../../Disp/Tooltips/Tooltip.js';
|
||||||
import { LoadMinigames, TooltipBuildBackup, TooltipLumpBackup } from '../VariablesAndData.js'; // eslint-disable-line no-unused-vars
|
import { LoadMinigames, TooltipBuildBackup, TooltipLumpBackup } from '../VariablesAndData.js'; // eslint-disable-line no-unused-vars
|
||||||
import ReplaceNativeGrimoire from './NativeGrimoire.js';
|
import ReplaceNativeGrimoire from './NativeGrimoire.js';
|
||||||
@@ -38,7 +37,7 @@ function ReplaceTooltipLump() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Replaces functions for the garden minigame
|
* This function replaces the original .onmouseover functions of all garden plants
|
||||||
*/
|
*/
|
||||||
function ReplaceTooltipGarden() {
|
function ReplaceTooltipGarden() {
|
||||||
if (Game.Objects.Farm.minigameLoaded) {
|
if (Game.Objects.Farm.minigameLoaded) {
|
||||||
@@ -56,13 +55,6 @@ function ReplaceTooltipGarden() {
|
|||||||
Game.tooltip.wobble();
|
Game.tooltip.wobble();
|
||||||
};
|
};
|
||||||
});
|
});
|
||||||
|
|
||||||
// overwrite the harvesting function to allow CachePlotChances to be updated
|
|
||||||
const OldBuildPlot = Game.Objects.Farm.minigame.buildPlot;
|
|
||||||
Game.Objects.Farm.minigame.buildPlot = function () {
|
|
||||||
OldBuildPlot(arguments); // eslint-disable-line prefer-rest-params
|
|
||||||
CalculateAllPlotChances(Game.Objects.Farm.minigame, Game.auraMult('Supreme Intellect'));
|
|
||||||
};
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@@ -76,8 +76,6 @@ export default function CalculateGains() {
|
|||||||
|
|
||||||
if (SimHas('Dragon scale')) mult *= 1.03;
|
if (SimHas('Dragon scale')) mult *= 1.03;
|
||||||
|
|
||||||
if (SimHas('Wrinkler ambergris')) mult *= 1.06;
|
|
||||||
|
|
||||||
// Check effect of chosen Gods
|
// Check effect of chosen Gods
|
||||||
let buildMult = 1;
|
let buildMult = 1;
|
||||||
if (SimHasGod) {
|
if (SimHasGod) {
|
||||||
|
|||||||
Reference in New Issue
Block a user