farming-weight 0.14.2 → 0.15.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +45 -18
- package/dist/constants/attributes.d.ts +12 -7
- package/dist/constants/attributes.js +17 -39
- package/dist/constants/attributes.js.map +1 -1
- package/dist/constants/chips.d.ts +1 -6
- package/dist/constants/chips.js +11 -15
- package/dist/constants/chips.js.map +1 -1
- package/dist/constants/crops.d.ts +28 -4
- package/dist/constants/crops.js +65 -2
- package/dist/constants/crops.js.map +1 -1
- package/dist/constants/enchants.d.ts +1 -1
- package/dist/constants/enchants.js +117 -68
- package/dist/constants/enchants.js.map +1 -1
- package/dist/constants/garden.js +152 -137
- package/dist/constants/garden.js.map +1 -1
- package/dist/constants/pests.d.ts +3 -2
- package/dist/constants/pests.js +5 -0
- package/dist/constants/pests.js.map +1 -1
- package/dist/constants/reforge-types.d.ts +57 -0
- package/dist/constants/reforge-types.js +40 -0
- package/dist/constants/reforge-types.js.map +1 -0
- package/dist/constants/reforges.d.ts +8 -55
- package/dist/constants/reforges.js +10 -635
- package/dist/constants/reforges.js.map +1 -1
- package/dist/constants/specific.js +11 -11
- package/dist/constants/specific.js.map +1 -1
- package/dist/constants/stats.d.ts +1 -0
- package/dist/constants/stats.js +2 -0
- package/dist/constants/stats.js.map +1 -1
- package/dist/constants/tempfortune.d.ts +5 -0
- package/dist/constants/tempfortune.js +36 -7
- package/dist/constants/tempfortune.js.map +1 -1
- package/dist/constants/upgrades.d.ts +36 -3
- package/dist/constants/upgrades.js +12 -0
- package/dist/constants/upgrades.js.map +1 -1
- package/dist/crops/special.d.ts +1 -1
- package/dist/crops/special.js.map +1 -1
- package/dist/effects/environment.d.ts +12 -0
- package/dist/effects/environment.js +33 -0
- package/dist/effects/environment.js.map +1 -0
- package/dist/effects/index.d.ts +4 -0
- package/dist/effects/index.js +5 -0
- package/dist/effects/index.js.map +1 -0
- package/dist/effects/matcher.d.ts +23 -0
- package/dist/effects/matcher.js +108 -0
- package/dist/effects/matcher.js.map +1 -0
- package/dist/effects/resolver.d.ts +63 -0
- package/dist/effects/resolver.js +239 -0
- package/dist/effects/resolver.js.map +1 -0
- package/dist/effects/summary.d.ts +5 -0
- package/dist/effects/summary.js +21 -0
- package/dist/effects/summary.js.map +1 -0
- package/dist/effects/types.d.ts +147 -0
- package/dist/effects/types.js +9 -0
- package/dist/effects/types.js.map +1 -0
- package/dist/features/composter/upgrades.js +5 -5
- package/dist/features/composter/upgrades.js.map +1 -1
- package/dist/fortune/farmingaccessory.d.ts +9 -1
- package/dist/fortune/farmingaccessory.js +24 -13
- package/dist/fortune/farmingaccessory.js.map +1 -1
- package/dist/fortune/farmingarmor.d.ts +21 -10
- package/dist/fortune/farmingarmor.js +89 -29
- package/dist/fortune/farmingarmor.js.map +1 -1
- package/dist/fortune/farmingequipment.d.ts +10 -1
- package/dist/fortune/farmingequipment.js +44 -11
- package/dist/fortune/farmingequipment.js.map +1 -1
- package/dist/fortune/farmingpet.d.ts +16 -0
- package/dist/fortune/farmingpet.js +207 -0
- package/dist/fortune/farmingpet.js.map +1 -1
- package/dist/fortune/farmingtool.d.ts +13 -6
- package/dist/fortune/farmingtool.js +60 -44
- package/dist/fortune/farmingtool.js.map +1 -1
- package/dist/fortune/lotuspiecebonus.d.ts +6 -0
- package/dist/fortune/lotuspiecebonus.js +20 -0
- package/dist/fortune/lotuspiecebonus.js.map +1 -0
- package/dist/fortune/upgradeable.d.ts +2 -4
- package/dist/fortune/upgradeablebase.d.ts +2 -4
- package/dist/fortune/upgradeablebase.js +4 -10
- package/dist/fortune/upgradeablebase.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/items/accessories/base.d.ts +3 -0
- package/dist/items/accessories/base.js +4 -0
- package/dist/items/accessories/base.js.map +1 -0
- package/dist/items/accessories/fermento-family.d.ts +91 -0
- package/dist/items/accessories/fermento-family.js +125 -0
- package/dist/items/accessories/fermento-family.js.map +1 -0
- package/dist/items/accessories/freshly-baked.d.ts +80 -0
- package/dist/items/accessories/freshly-baked.js +119 -0
- package/dist/items/accessories/freshly-baked.js.map +1 -0
- package/dist/items/accessories/index.d.ts +25 -0
- package/dist/items/accessories/index.js +25 -0
- package/dist/items/accessories/index.js.map +1 -0
- package/dist/items/accessories/power-relic.d.ts +18 -0
- package/dist/items/accessories/power-relic.js +37 -0
- package/dist/items/accessories/power-relic.js.map +1 -0
- package/dist/items/accessories/special.d.ts +24 -0
- package/dist/items/accessories/special.js +41 -0
- package/dist/items/accessories/special.js.map +1 -0
- package/dist/items/accessories.d.ts +2 -3
- package/dist/items/accessories.js +1 -137
- package/dist/items/accessories.js.map +1 -1
- package/dist/items/armor/biohazard.js +4 -4
- package/dist/items/armor/biohazard.js.map +1 -1
- package/dist/items/armor/cropie.d.ts +4 -0
- package/dist/items/armor/cropie.js +10 -4
- package/dist/items/armor/cropie.js.map +1 -1
- package/dist/items/armor/farm.js +4 -4
- package/dist/items/armor/farm.js.map +1 -1
- package/dist/items/armor/fermento.d.ts +4 -0
- package/dist/items/armor/fermento.js +10 -4
- package/dist/items/armor/fermento.js.map +1 -1
- package/dist/items/armor/groups.d.ts +2 -0
- package/dist/items/armor/groups.js +17 -0
- package/dist/items/armor/groups.js.map +1 -0
- package/dist/items/armor/helianthus.js +4 -4
- package/dist/items/armor/helianthus.js.map +1 -1
- package/dist/items/armor/melon.d.ts +4 -0
- package/dist/items/armor/melon.js +10 -4
- package/dist/items/armor/melon.js.map +1 -1
- package/dist/items/armor/mushroom.js +4 -4
- package/dist/items/armor/mushroom.js.map +1 -1
- package/dist/items/armor/rabbit.js +4 -4
- package/dist/items/armor/rabbit.js.map +1 -1
- package/dist/items/armor/special.js +4 -4
- package/dist/items/armor/special.js.map +1 -1
- package/dist/items/armor/squash.d.ts +4 -0
- package/dist/items/armor/squash.js +10 -4
- package/dist/items/armor/squash.js.map +1 -1
- package/dist/items/equipment/blossom.js +4 -4
- package/dist/items/equipment/blossom.js.map +1 -1
- package/dist/items/equipment/lotus.js +4 -4
- package/dist/items/equipment/lotus.js.map +1 -1
- package/dist/items/equipment/pesthunter.js +4 -4
- package/dist/items/equipment/pesthunter.js.map +1 -1
- package/dist/items/equipment/special.js +2 -2
- package/dist/items/equipment/special.js.map +1 -1
- package/dist/items/gems/base.d.ts +19 -0
- package/dist/items/gems/base.js +60 -0
- package/dist/items/gems/base.js.map +1 -0
- package/dist/items/gems/index.d.ts +1 -0
- package/dist/items/gems/index.js +2 -0
- package/dist/items/gems/index.js.map +1 -0
- package/dist/items/pets/bee.d.ts +9 -0
- package/dist/items/pets/bee.js +33 -1
- package/dist/items/pets/bee.js.map +1 -1
- package/dist/items/pets/chicken.js +1 -1
- package/dist/items/pets/chicken.js.map +1 -1
- package/dist/items/pets/elephant.js +1 -1
- package/dist/items/pets/elephant.js.map +1 -1
- package/dist/items/pets/hedgehog.d.ts +5 -0
- package/dist/items/pets/hedgehog.js +6 -1
- package/dist/items/pets/hedgehog.js.map +1 -1
- package/dist/items/pets/mooshroom-cow.js +1 -1
- package/dist/items/pets/mooshroom-cow.js.map +1 -1
- package/dist/items/pets/mosquito.js +1 -1
- package/dist/items/pets/mosquito.js.map +1 -1
- package/dist/items/pets/pig.d.ts +5 -0
- package/dist/items/pets/pig.js +19 -14
- package/dist/items/pets/pig.js.map +1 -1
- package/dist/items/pets/rabbit.js +1 -1
- package/dist/items/pets/rabbit.js.map +1 -1
- package/dist/items/pets/rose-dragon.js +12 -14
- package/dist/items/pets/rose-dragon.js.map +1 -1
- package/dist/items/pets/slug.js +1 -1
- package/dist/items/pets/slug.js.map +1 -1
- package/dist/items/pets.d.ts +1 -1
- package/dist/items/pets.js +18 -4
- package/dist/items/pets.js.map +1 -1
- package/dist/items/reforges/base.d.ts +18 -0
- package/dist/items/reforges/base.js +54 -0
- package/dist/items/reforges/base.js.map +1 -0
- package/dist/items/reforges/blessed.d.ts +7 -0
- package/dist/items/reforges/blessed.js +90 -0
- package/dist/items/reforges/blessed.js.map +1 -0
- package/dist/items/reforges/blooming.d.ts +4 -0
- package/dist/items/reforges/blooming.js +43 -0
- package/dist/items/reforges/blooming.js.map +1 -0
- package/dist/items/reforges/bountiful.d.ts +4 -0
- package/dist/items/reforges/bountiful.js +63 -0
- package/dist/items/reforges/bountiful.js.map +1 -0
- package/dist/items/reforges/bustling.d.ts +4 -0
- package/dist/items/reforges/bustling.js +26 -0
- package/dist/items/reforges/bustling.js.map +1 -0
- package/dist/items/reforges/deep-fried.d.ts +7 -0
- package/dist/items/reforges/deep-fried.js +38 -0
- package/dist/items/reforges/deep-fried.js.map +1 -0
- package/dist/items/reforges/earthy.d.ts +4 -0
- package/dist/items/reforges/earthy.js +26 -0
- package/dist/items/reforges/earthy.js.map +1 -0
- package/dist/items/reforges/green-thumb.d.ts +4 -0
- package/dist/items/reforges/green-thumb.js +43 -0
- package/dist/items/reforges/green-thumb.js.map +1 -0
- package/dist/items/reforges/index.d.ts +16 -0
- package/dist/items/reforges/index.js +43 -0
- package/dist/items/reforges/index.js.map +1 -0
- package/dist/items/reforges/mantid.d.ts +4 -0
- package/dist/items/reforges/mantid.js +43 -0
- package/dist/items/reforges/mantid.js.map +1 -0
- package/dist/items/reforges/mossy.d.ts +4 -0
- package/dist/items/reforges/mossy.js +44 -0
- package/dist/items/reforges/mossy.js.map +1 -0
- package/dist/items/reforges/overpriced.d.ts +4 -0
- package/dist/items/reforges/overpriced.js +43 -0
- package/dist/items/reforges/overpriced.js.map +1 -0
- package/dist/items/reforges/robust.d.ts +4 -0
- package/dist/items/reforges/robust.js +22 -0
- package/dist/items/reforges/robust.js.map +1 -0
- package/dist/items/reforges/rooted.d.ts +4 -0
- package/dist/items/reforges/rooted.js +43 -0
- package/dist/items/reforges/rooted.js.map +1 -0
- package/dist/items/reforges/squeaky.d.ts +4 -0
- package/dist/items/reforges/squeaky.js +47 -0
- package/dist/items/reforges/squeaky.js.map +1 -0
- package/dist/items/sources/attributes.d.ts +119 -0
- package/dist/items/sources/attributes.js +285 -0
- package/dist/items/sources/attributes.js.map +1 -0
- package/dist/items/sources/base.d.ts +33 -0
- package/dist/items/sources/base.js +13 -0
- package/dist/items/sources/base.js.map +1 -0
- package/dist/items/sources/chips.d.ts +54 -0
- package/dist/items/sources/chips.js +100 -0
- package/dist/items/sources/chips.js.map +1 -0
- package/dist/items/sources/effects-util.d.ts +10 -0
- package/dist/items/sources/effects-util.js +35 -0
- package/dist/items/sources/effects-util.js.map +1 -0
- package/dist/items/sources/enchants.d.ts +28 -0
- package/dist/items/sources/enchants.js +87 -0
- package/dist/items/sources/enchants.js.map +1 -0
- package/dist/items/sources/gems.d.ts +9 -0
- package/dist/items/sources/gems.js +35 -0
- package/dist/items/sources/gems.js.map +1 -0
- package/dist/items/sources/index.d.ts +6 -0
- package/dist/items/sources/index.js +7 -0
- package/dist/items/sources/index.js.map +1 -0
- package/dist/items/sources/reforges.d.ts +8 -0
- package/dist/items/sources/reforges.js +10 -0
- package/dist/items/sources/reforges.js.map +1 -0
- package/dist/items/tools/cactus-knife.js +6 -6
- package/dist/items/tools/cactus-knife.js.map +1 -1
- package/dist/items/tools/cocoa-chopper.js +6 -6
- package/dist/items/tools/cocoa-chopper.js.map +1 -1
- package/dist/items/tools/dicers.js +6 -6
- package/dist/items/tools/dicers.js.map +1 -1
- package/dist/items/tools/fungi-cutter.js +6 -6
- package/dist/items/tools/fungi-cutter.js.map +1 -1
- package/dist/items/tools/mathematical-hoes.d.ts +5 -5
- package/dist/items/tools/mathematical-hoes.js +26 -26
- package/dist/items/tools/mathematical-hoes.js.map +1 -1
- package/dist/items/tools/special.js +2 -2
- package/dist/items/tools/special.js.map +1 -1
- package/dist/items/types/pets.d.ts +0 -2
- package/dist/player/player.d.ts +60 -7
- package/dist/player/player.js +318 -128
- package/dist/player/player.js.map +1 -1
- package/dist/player/playeroptions.d.ts +25 -1
- package/dist/player/playeroptions.js.map +1 -1
- package/dist/upgrades/enchantupgrades.js +22 -8
- package/dist/upgrades/enchantupgrades.js.map +1 -1
- package/dist/upgrades/getsourceprogress.js +7 -0
- package/dist/upgrades/getsourceprogress.js.map +1 -1
- package/dist/upgrades/groups.d.ts +3 -0
- package/dist/upgrades/groups.js +86 -0
- package/dist/upgrades/groups.js.map +1 -0
- package/dist/upgrades/itemcatalog.d.ts +3 -0
- package/dist/upgrades/itemcatalog.js +21 -0
- package/dist/upgrades/itemcatalog.js.map +1 -0
- package/dist/upgrades/itemregistry.d.ts +1 -2
- package/dist/upgrades/itemregistry.js +23 -3
- package/dist/upgrades/itemregistry.js.map +1 -1
- package/dist/upgrades/sources/accessorysources.js +1 -1
- package/dist/upgrades/sources/accessorysources.js.map +1 -1
- package/dist/upgrades/sources/armorsetsources.js +16 -16
- package/dist/upgrades/sources/armorsetsources.js.map +1 -1
- package/dist/upgrades/sources/cropsources.js +10 -5
- package/dist/upgrades/sources/cropsources.js.map +1 -1
- package/dist/upgrades/sources/dynamicfortunesources.d.ts +5 -2
- package/dist/upgrades/sources/effectsources.d.ts +4 -0
- package/dist/upgrades/sources/effectsources.js +60 -0
- package/dist/upgrades/sources/effectsources.js.map +1 -0
- package/dist/upgrades/sources/gearsources.js +33 -8
- package/dist/upgrades/sources/gearsources.js.map +1 -1
- package/dist/upgrades/sources/generalsources.d.ts +3 -2
- package/dist/upgrades/sources/generalsources.js +313 -22
- package/dist/upgrades/sources/generalsources.js.map +1 -1
- package/dist/upgrades/sources/toolsources.js +64 -84
- package/dist/upgrades/sources/toolsources.js.map +1 -1
- package/dist/upgrades/upgradekeys.d.ts +2 -0
- package/dist/upgrades/upgradekeys.js +5 -0
- package/dist/upgrades/upgradekeys.js.map +1 -0
- package/dist/upgrades/upgrades.d.ts +5 -7
- package/dist/upgrades/upgrades.js +142 -43
- package/dist/upgrades/upgrades.js.map +1 -1
- package/dist/upgrades/upgradeutils.d.ts +2 -4
- package/dist/upgrades/upgradeutils.js +26 -6
- package/dist/upgrades/upgradeutils.js.map +1 -1
- package/dist/util/bestiary.d.ts +10 -0
- package/dist/util/bestiary.js +41 -0
- package/dist/util/bestiary.js.map +1 -0
- package/dist/util/enchants.d.ts +6 -0
- package/dist/util/enchants.js +20 -5
- package/dist/util/enchants.js.map +1 -1
- package/dist/util/gems.js +4 -30
- package/dist/util/gems.js.map +1 -1
- package/dist/util/itemstats.d.ts +3 -0
- package/dist/util/itemstats.js +20 -2
- package/dist/util/itemstats.js.map +1 -1
- package/dist/util/ratecalc-effects.d.ts +64 -0
- package/dist/util/ratecalc-effects.js +252 -0
- package/dist/util/ratecalc-effects.js.map +1 -0
- package/dist/util/ratecalc.d.ts +0 -33
- package/dist/util/ratecalc.js +0 -187
- package/dist/util/ratecalc.js.map +1 -1
- package/dist/util/skyblocktime.d.ts +1 -0
- package/dist/util/skyblocktime.js +4 -0
- package/dist/util/skyblocktime.js.map +1 -1
- package/package.json +2 -1
package/dist/player/player.js
CHANGED
|
@@ -1,22 +1,31 @@
|
|
|
1
1
|
import { normalizeAttributes } from '../constants/attributes.js';
|
|
2
2
|
import { getChipInputLevel, getChipLevel, getChipTempMultiplierPerLevel, normalizeChipId, normalizeChipLevels, } from '../constants/chips.js';
|
|
3
3
|
import { CROP_INFO } from '../constants/crops.js';
|
|
4
|
+
import { compareRarity } from '../constants/reforge-types.js';
|
|
4
5
|
import { getContributoryStats, Stat } from '../constants/stats.js';
|
|
5
6
|
import { TEMPORARY_FORTUNE } from '../constants/tempfortune.js';
|
|
6
|
-
import { UpgradeAction, UpgradeCategory } from '../constants/upgrades.js';
|
|
7
|
+
import { getQueryStats, UpgradeAction, UpgradeCategory, } from '../constants/upgrades.js';
|
|
8
|
+
import { buildEffectEnvironment } from '../effects/environment.js';
|
|
9
|
+
import { resolveOverbloomBreakdown, resolveStatBreakdown } from '../effects/resolver.js';
|
|
10
|
+
import { effectsToSummaries } from '../effects/summary.js';
|
|
7
11
|
import { FarmingAccessory } from '../fortune/farmingaccessory.js';
|
|
8
12
|
import { ArmorSet, FarmingArmor } from '../fortune/farmingarmor.js';
|
|
9
13
|
import { FarmingEquipment } from '../fortune/farmingequipment.js';
|
|
10
14
|
import { FarmingPet } from '../fortune/farmingpet.js';
|
|
11
15
|
import { FarmingTool } from '../fortune/farmingtool.js';
|
|
12
16
|
import { FarmingPets } from '../items/pets.js';
|
|
17
|
+
import { FARMING_ATTRIBUTE_SHARD_CLASSES } from '../items/sources/attributes.js';
|
|
18
|
+
import { GARDEN_CHIP_CLASSES } from '../items/sources/chips.js';
|
|
13
19
|
import { FARMING_TOOLS } from '../items/tools.js';
|
|
14
20
|
import { getSourceProgress } from '../upgrades/getsourceprogress.js';
|
|
21
|
+
import { withGroupedUpgrades } from '../upgrades/groups.js';
|
|
15
22
|
import { getFakeItem } from '../upgrades/itemregistry.js';
|
|
16
23
|
import { CROP_FORTUNE_SOURCES } from '../upgrades/sources/cropsources.js';
|
|
24
|
+
import { collectCropFortuneSourceEffects, collectGeneralFortuneSourceEffects, } from '../upgrades/sources/effectsources.js';
|
|
17
25
|
import { GENERAL_FORTUNE_SOURCES } from '../upgrades/sources/generalsources.js';
|
|
18
26
|
import { filterAndSortUpgrades } from '../upgrades/upgradeutils.js';
|
|
19
|
-
import {
|
|
27
|
+
import { nextRarity, previousRarity } from '../util/itemstats.js';
|
|
28
|
+
import { calculateDetailedDropsFromEffects } from '../util/ratecalc-effects.js';
|
|
20
29
|
import { createFarmingWeightCalculator } from '../weight/weightcalc.js';
|
|
21
30
|
export function createFarmingPlayer(options) {
|
|
22
31
|
return new FarmingPlayer(options);
|
|
@@ -125,9 +134,11 @@ export class FarmingPlayer {
|
|
|
125
134
|
let pool = [];
|
|
126
135
|
if (this.options.accessories[0] instanceof FarmingAccessory) {
|
|
127
136
|
pool = this.options.accessories.sort((a, b) => b.fortune - a.fortune);
|
|
137
|
+
for (const acc of pool)
|
|
138
|
+
acc.setOptions(this.options);
|
|
128
139
|
}
|
|
129
140
|
else {
|
|
130
|
-
pool = FarmingAccessory.fromArray(this.options.accessories);
|
|
141
|
+
pool = FarmingAccessory.fromArray(this.options.accessories, this.options);
|
|
131
142
|
}
|
|
132
143
|
// Filter by unique family (keep highest rarity/fortune)
|
|
133
144
|
const familyMap = new Map();
|
|
@@ -147,15 +158,21 @@ export class FarmingPlayer {
|
|
|
147
158
|
this.activeAccessories = [...familyMap.values(), ...others].sort((a, b) => b.fortune - a.fortune);
|
|
148
159
|
this.accessories = pool;
|
|
149
160
|
}
|
|
161
|
+
syncActiveAccessories() {
|
|
162
|
+
this.options.accessories = this.accessories;
|
|
163
|
+
this.populateActiveAccessories();
|
|
164
|
+
}
|
|
150
165
|
changeArmor(armor) {
|
|
151
166
|
this.armorSet = new ArmorSet(armor.sort((a, b) => b.fortune - a.fortune));
|
|
152
167
|
}
|
|
153
168
|
selectTool(tool) {
|
|
154
169
|
this.selectedTool = tool;
|
|
170
|
+
this.options.selectedTool = tool;
|
|
155
171
|
this.permFortune = this.getGeneralFortune();
|
|
156
172
|
}
|
|
157
173
|
selectPet(pet) {
|
|
158
174
|
this.selectedPet = pet;
|
|
175
|
+
this.options.selectedPet = pet;
|
|
159
176
|
this.permFortune = this.getGeneralFortune();
|
|
160
177
|
}
|
|
161
178
|
setStrength(strength) {
|
|
@@ -168,14 +185,47 @@ export class FarmingPlayer {
|
|
|
168
185
|
getProgress(stats) {
|
|
169
186
|
return getSourceProgress(this, GENERAL_FORTUNE_SOURCES, false, stats);
|
|
170
187
|
}
|
|
188
|
+
getPetProgress(stats) {
|
|
189
|
+
return this.pets.flatMap((pet) => pet.getProgress(stats, this));
|
|
190
|
+
}
|
|
171
191
|
getUpgrades(options) {
|
|
172
|
-
const
|
|
192
|
+
const hasExplicitStats = (options?.stats?.length ?? 0) > 0 || options?.stat !== undefined;
|
|
193
|
+
const stats = hasExplicitStats ? getQueryStats(options) : undefined;
|
|
173
194
|
const upgrades = getSourceProgress(this, GENERAL_FORTUNE_SOURCES, false, stats).flatMap((source) => source.upgrades ?? []);
|
|
174
195
|
const armorSetUpgrades = this.armorSet.getUpgrades(options);
|
|
175
196
|
if (armorSetUpgrades.length > 0) {
|
|
176
197
|
upgrades.push(...armorSetUpgrades);
|
|
177
198
|
}
|
|
178
|
-
|
|
199
|
+
// For non-FarmingFortune stats (e.g. Overbloom), tool upgrades aren't tied to a single
|
|
200
|
+
// crop and won't be surfaced by getCropUpgrades, so include them here.
|
|
201
|
+
if (stats?.some((stat) => stat !== Stat.FarmingFortune)) {
|
|
202
|
+
const tools = this.options.selectedCrop !== undefined
|
|
203
|
+
? [this.getSelectedCropTool(this.options.selectedCrop)].filter((tool) => tool !== undefined)
|
|
204
|
+
: this.tools;
|
|
205
|
+
for (const tool of tools) {
|
|
206
|
+
upgrades.push(...tool.getUpgrades(options));
|
|
207
|
+
}
|
|
208
|
+
}
|
|
209
|
+
const filtered = filterAndSortUpgrades(upgrades, options);
|
|
210
|
+
return options?.includeUpgradeGroups ? withGroupedUpgrades(filtered) : filtered;
|
|
211
|
+
}
|
|
212
|
+
getStatView(query) {
|
|
213
|
+
const stats = query.stats.length > 0 ? query.stats : [Stat.FarmingFortune];
|
|
214
|
+
const totals = {};
|
|
215
|
+
const breakdowns = {};
|
|
216
|
+
for (const stat of stats) {
|
|
217
|
+
totals[stat] = this.getStat(stat, query.crop);
|
|
218
|
+
breakdowns[stat] = this.getStatBreakdown(stat, query.crop);
|
|
219
|
+
}
|
|
220
|
+
const env = this.buildEnvironment(query.crop);
|
|
221
|
+
const effects = effectsToSummaries(this.collectEffects(env), stats);
|
|
222
|
+
const upgrades = this.getUpgrades({ stats });
|
|
223
|
+
return {
|
|
224
|
+
totals,
|
|
225
|
+
breakdowns,
|
|
226
|
+
effects,
|
|
227
|
+
upgrades,
|
|
228
|
+
};
|
|
179
229
|
}
|
|
180
230
|
getCropUpgrades(crop, tool) {
|
|
181
231
|
const upgrades = [];
|
|
@@ -196,16 +246,25 @@ export class FarmingPlayer {
|
|
|
196
246
|
const startingInfo = FARMING_TOOLS[CROP_INFO[crop].startingTool];
|
|
197
247
|
if (startingInfo) {
|
|
198
248
|
const fakeItem = getFakeItem(startingInfo.skyblockId, this.options);
|
|
249
|
+
const startingToolFortune = fakeItem?.getStat(CROP_INFO[crop].fortuneType, crop) ?? 0;
|
|
199
250
|
upgrades.push({
|
|
200
251
|
title: startingInfo.name,
|
|
201
252
|
action: UpgradeAction.Purchase,
|
|
202
|
-
increase:
|
|
253
|
+
increase: startingToolFortune,
|
|
254
|
+
stats: {
|
|
255
|
+
[CROP_INFO[crop].fortuneType]: startingToolFortune,
|
|
256
|
+
},
|
|
203
257
|
wiki: startingInfo.wiki,
|
|
258
|
+
purchase: startingInfo.skyblockId,
|
|
204
259
|
max: fakeItem?.getProgress()?.reduce((acc, p) => acc + p.max, 0) ?? 0,
|
|
205
260
|
category: UpgradeCategory.Item,
|
|
206
261
|
cost: {
|
|
207
262
|
copper: 250,
|
|
208
263
|
},
|
|
264
|
+
meta: {
|
|
265
|
+
type: 'buy_item',
|
|
266
|
+
id: startingInfo.skyblockId,
|
|
267
|
+
},
|
|
209
268
|
});
|
|
210
269
|
}
|
|
211
270
|
}
|
|
@@ -227,8 +286,68 @@ export class FarmingPlayer {
|
|
|
227
286
|
}
|
|
228
287
|
return val;
|
|
229
288
|
}
|
|
230
|
-
|
|
231
|
-
|
|
289
|
+
/**
|
|
290
|
+
* Build the canonical {@link EffectEnvironment} for this player + crop.
|
|
291
|
+
* Thin wrapper over {@link buildEffectEnvironment}; provided so callers
|
|
292
|
+
* never have to import the helper directly.
|
|
293
|
+
*/
|
|
294
|
+
buildEnvironment(crop) {
|
|
295
|
+
return buildEffectEnvironment(this, crop);
|
|
296
|
+
}
|
|
297
|
+
/**
|
|
298
|
+
* Aggregate the declarative {@link Effect}[] from every active source on
|
|
299
|
+
* the player: armor set (armor + equipment + set bonuses, including each
|
|
300
|
+
* piece's reforge & enchants), the selected tool, active accessories, the
|
|
301
|
+
* selected pet, every attribute shard, and every garden chip.
|
|
302
|
+
*
|
|
303
|
+
* Sources with a `getActive` guard that returns `active: false` are
|
|
304
|
+
* skipped. Sources whose `getEffects` returns `[]` contribute nothing.
|
|
305
|
+
*
|
|
306
|
+
* This method is the single seam consumed by the new effect-resolver
|
|
307
|
+
* pipeline (`getStat`, `getRates`). It does **not** apply scopes - that's
|
|
308
|
+
* the resolver's job - so the returned list includes every effect the
|
|
309
|
+
* player could plausibly emit, with their declarative scopes intact.
|
|
310
|
+
*/
|
|
311
|
+
collectEffects(env) {
|
|
312
|
+
const effects = [];
|
|
313
|
+
effects.push(...collectGeneralFortuneSourceEffects(this));
|
|
314
|
+
// Armor set: armor pieces, equipment pieces, and set bonuses.
|
|
315
|
+
// (Per-piece reforge/enchant effects are emitted by each piece.)
|
|
316
|
+
effects.push(...this.armorSet.getEffects(env));
|
|
317
|
+
// Tool: for crop-scoped calculations, use the selected/best tool for
|
|
318
|
+
// that crop. For crop-agnostic stat queries, use the selected tool.
|
|
319
|
+
const tool = env.crop ? this.getSelectedCropTool(env.crop) : this.selectedTool;
|
|
320
|
+
if (tool) {
|
|
321
|
+
effects.push(...tool.getEffects(env));
|
|
322
|
+
}
|
|
323
|
+
// Active accessories only - the same filtering `getStatBreakdown`
|
|
324
|
+
// applies, so we don't double-count Helianthus etc.
|
|
325
|
+
for (const accessory of this.activeAccessories) {
|
|
326
|
+
effects.push(...accessory.getEffects(env));
|
|
327
|
+
}
|
|
328
|
+
// Selected pet.
|
|
329
|
+
if (this.selectedPet) {
|
|
330
|
+
effects.push(...this.selectedPet.getEffects(env, this));
|
|
331
|
+
}
|
|
332
|
+
// Attribute shards.
|
|
333
|
+
for (const shard of Object.values(FARMING_ATTRIBUTE_SHARD_CLASSES)) {
|
|
334
|
+
const active = shard.getActive?.(this, env);
|
|
335
|
+
if (active && active.active === false)
|
|
336
|
+
continue;
|
|
337
|
+
effects.push(...shard.getEffects(this, env));
|
|
338
|
+
}
|
|
339
|
+
// Garden chips.
|
|
340
|
+
for (const chip of Object.values(GARDEN_CHIP_CLASSES)) {
|
|
341
|
+
const active = chip.getActive?.(this, env);
|
|
342
|
+
if (active && active.active === false)
|
|
343
|
+
continue;
|
|
344
|
+
effects.push(...chip.getEffects(this, env));
|
|
345
|
+
}
|
|
346
|
+
effects.push(...collectCropFortuneSourceEffects(this, env));
|
|
347
|
+
return effects;
|
|
348
|
+
}
|
|
349
|
+
getStat(stat, targetCrop) {
|
|
350
|
+
const breakdown = this.getStatBreakdown(stat, targetCrop);
|
|
232
351
|
return Object.values(breakdown).reduce((acc, val) => acc + val.value, 0);
|
|
233
352
|
}
|
|
234
353
|
getStatBreakdown(stat, targetCrop) {
|
|
@@ -241,110 +360,16 @@ export class FarmingPlayer {
|
|
|
241
360
|
breakdown[name].value += value;
|
|
242
361
|
}
|
|
243
362
|
};
|
|
244
|
-
// Identify all stats that contribute to the requested stat
|
|
245
363
|
const contributingStats = getContributoryStats(stat);
|
|
246
|
-
|
|
247
|
-
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
let val = 0;
|
|
256
|
-
if (source.currentStat) {
|
|
257
|
-
val = source.currentStat(this, targetStat) ?? 0;
|
|
258
|
-
}
|
|
259
|
-
else if (source.current && targetStat === Stat.FarmingFortune) {
|
|
260
|
-
val = source.current(this) ?? 0;
|
|
261
|
-
}
|
|
262
|
-
add(source.name, val, targetStat);
|
|
263
|
-
}
|
|
264
|
-
}
|
|
265
|
-
// Crop Sources
|
|
266
|
-
// Only run if we have a target crop
|
|
267
|
-
if (targetCrop) {
|
|
268
|
-
for (const source of CROP_FORTUNE_SOURCES) {
|
|
269
|
-
// Helianthus Relic Family is handled by activeAccessories
|
|
270
|
-
if (source.name === 'Helianthus Relic Family')
|
|
271
|
-
continue;
|
|
272
|
-
const ctx = { player: this, crop: targetCrop };
|
|
273
|
-
if (source.exists && !source.exists(ctx))
|
|
274
|
-
continue;
|
|
275
|
-
for (const targetStat of contributingStats) {
|
|
276
|
-
let val = 0;
|
|
277
|
-
// For Crop Sources, strictly match the crop's fortune type.
|
|
278
|
-
if (source.currentStat) {
|
|
279
|
-
val = source.currentStat(ctx, targetStat) ?? 0;
|
|
280
|
-
}
|
|
281
|
-
else if (source.current && targetStat === CROP_INFO[targetCrop].fortuneType) {
|
|
282
|
-
val = source.current(ctx) ?? 0;
|
|
283
|
-
}
|
|
284
|
-
add(source.name, val, targetStat);
|
|
285
|
-
}
|
|
286
|
-
}
|
|
287
|
-
}
|
|
288
|
-
// Pets
|
|
289
|
-
const pet = this.selectedPet;
|
|
290
|
-
if (pet) {
|
|
291
|
-
for (const targetStat of contributingStats) {
|
|
292
|
-
// Pass the player for abilities that depend on player context (e.g., Mosquito sugar cane fortune)
|
|
293
|
-
const val = pet.getFortune(targetStat, this);
|
|
294
|
-
add(pet.info.name ?? 'Selected Pet', val, targetStat);
|
|
295
|
-
}
|
|
296
|
-
}
|
|
297
|
-
// Tools
|
|
298
|
-
if (!targetCrop && this.selectedTool) {
|
|
299
|
-
for (const targetStat of contributingStats) {
|
|
300
|
-
const val = this.selectedTool.getStat(targetStat);
|
|
301
|
-
add(this.selectedTool.info.name, val, targetStat);
|
|
302
|
-
}
|
|
303
|
-
}
|
|
304
|
-
// Equipment
|
|
305
|
-
for (const piece of this.armorSet.equipment) {
|
|
306
|
-
if (!piece)
|
|
307
|
-
continue;
|
|
308
|
-
for (const targetStat of contributingStats) {
|
|
309
|
-
const val = piece.getStat(targetStat);
|
|
310
|
-
add(piece.info.name, val, targetStat);
|
|
311
|
-
}
|
|
312
|
-
}
|
|
313
|
-
// Armor
|
|
314
|
-
for (const piece of this.armorSet.armor) {
|
|
315
|
-
if (!piece)
|
|
316
|
-
continue;
|
|
317
|
-
for (const targetStat of contributingStats) {
|
|
318
|
-
const val = piece.getStat(targetStat);
|
|
319
|
-
add(piece.info.name, val, targetStat);
|
|
320
|
-
}
|
|
321
|
-
}
|
|
322
|
-
// Armor Set Bonuses
|
|
323
|
-
for (const { bonus, count } of this.armorSet.setBonuses) {
|
|
324
|
-
if (count < 2 || count > 4)
|
|
325
|
-
continue;
|
|
326
|
-
for (const targetStat of contributingStats) {
|
|
327
|
-
const val = bonus.stats?.[count]?.[targetStat] ?? 0;
|
|
328
|
-
add(bonus.name, val, targetStat);
|
|
329
|
-
}
|
|
330
|
-
}
|
|
331
|
-
// Equipment Set Bonuses
|
|
332
|
-
for (const { bonus, count } of this.armorSet.equipmentSetBonuses) {
|
|
333
|
-
if (count < 2 || count > 4)
|
|
334
|
-
continue;
|
|
335
|
-
for (const targetStat of contributingStats) {
|
|
336
|
-
const val = bonus.stats?.[count]?.[targetStat] ?? 0;
|
|
337
|
-
add(bonus.name, val, targetStat);
|
|
338
|
-
}
|
|
339
|
-
}
|
|
340
|
-
// Accessories
|
|
341
|
-
for (const acc of this.activeAccessories) {
|
|
342
|
-
// If the accessory is restricted to specific crops, check validity
|
|
343
|
-
if (acc.info.crops && (!targetCrop || !acc.info.crops.includes(targetCrop)))
|
|
344
|
-
continue;
|
|
345
|
-
for (const targetStat of contributingStats) {
|
|
346
|
-
const val = acc.getStat(targetStat);
|
|
347
|
-
add(acc.info.name, val, targetStat);
|
|
364
|
+
const env = this.buildEnvironment(targetCrop);
|
|
365
|
+
const effects = this.collectEffects(env);
|
|
366
|
+
const statContext = { env, crop: targetCrop };
|
|
367
|
+
for (const targetStat of contributingStats) {
|
|
368
|
+
const resolved = targetStat === Stat.Overbloom
|
|
369
|
+
? resolveOverbloomBreakdown(effects, statContext, Stat.Overbloom)
|
|
370
|
+
: resolveStatBreakdown(effects, targetStat, statContext);
|
|
371
|
+
for (const [name, value] of Object.entries(resolved)) {
|
|
372
|
+
add(name, value, targetStat);
|
|
348
373
|
}
|
|
349
374
|
}
|
|
350
375
|
// Temporary Fortune
|
|
@@ -373,9 +398,11 @@ export class FarmingPlayer {
|
|
|
373
398
|
const petName = this.selectedPet.info.name ?? 'Selected Pet';
|
|
374
399
|
// Get the stat type from the late breakdown entries (they specify their stat)
|
|
375
400
|
const lateBreakdownEntries = lateResult.breakdown ? Object.values(lateResult.breakdown) : [];
|
|
376
|
-
const
|
|
401
|
+
const contributingLateEntry = lateBreakdownEntries.find((entry) => contributingStats.includes(entry.stat));
|
|
402
|
+
const lateStat = contributingLateEntry?.stat ?? lateBreakdownEntries[0]?.stat ?? Stat.FarmingFortune;
|
|
403
|
+
const lateResultContributes = contributingStats.includes(lateStat);
|
|
377
404
|
// Add late additive effects to the pet's entry
|
|
378
|
-
if (lateResult.additive) {
|
|
405
|
+
if (lateResultContributes && lateResult.additive) {
|
|
379
406
|
if (breakdown[petName]) {
|
|
380
407
|
breakdown[petName].value += lateResult.additive;
|
|
381
408
|
}
|
|
@@ -384,7 +411,7 @@ export class FarmingPlayer {
|
|
|
384
411
|
}
|
|
385
412
|
}
|
|
386
413
|
// Apply multiplier to total fortune (add as reduction to pet's entry)
|
|
387
|
-
if (lateResult.multiplier !== undefined && lateResult.multiplier !== 1) {
|
|
414
|
+
if (lateResultContributes && lateResult.multiplier !== undefined && lateResult.multiplier !== 1) {
|
|
388
415
|
const reduction = baseFortune * (lateResult.multiplier - 1);
|
|
389
416
|
if (breakdown[petName]) {
|
|
390
417
|
breakdown[petName].value += reduction;
|
|
@@ -416,9 +443,12 @@ export class FarmingPlayer {
|
|
|
416
443
|
continue;
|
|
417
444
|
const fortune = source.fortune(this.options.temporaryFortune);
|
|
418
445
|
if (fortune) {
|
|
419
|
-
const
|
|
420
|
-
|
|
421
|
-
|
|
446
|
+
const stat = source.stat ?? Stat.FarmingFortune;
|
|
447
|
+
// Hypercharge chip only boosts farming fortune sources, not Overbloom or other stats.
|
|
448
|
+
const boosted = stat === Stat.FarmingFortune ? fortune * hyperchargeMultiplier : fortune;
|
|
449
|
+
breakdown[source.name] = { value: boosted, stat };
|
|
450
|
+
if (stat === Stat.FarmingFortune)
|
|
451
|
+
sum += boosted;
|
|
422
452
|
}
|
|
423
453
|
}
|
|
424
454
|
this.tempFortuneBreakdown = breakdown;
|
|
@@ -447,15 +477,34 @@ export class FarmingPlayer {
|
|
|
447
477
|
getRates(crop, blocksBroken) {
|
|
448
478
|
const tool = this.getBestTool(crop);
|
|
449
479
|
const cropFortune = this.getCropFortune(crop, tool);
|
|
450
|
-
const fortune =
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
480
|
+
const fortune = cropFortune.fortune;
|
|
481
|
+
const env = this.buildEnvironment(crop);
|
|
482
|
+
const effects = this.collectEffects(env);
|
|
483
|
+
return calculateDetailedDropsFromEffects({
|
|
484
|
+
crop,
|
|
485
|
+
blocksBroken,
|
|
454
486
|
farmingFortune: fortune,
|
|
487
|
+
armorPieces: this.armorSet.specialDropsCount(crop),
|
|
455
488
|
bountiful: tool?.bountiful ?? false,
|
|
456
489
|
mooshroom: this.selectedPet?.type === FarmingPets.MooshroomCow,
|
|
490
|
+
maxTool: tool?.getCurrentLevelProgress().maxed ?? false,
|
|
491
|
+
chips: this.options.chips,
|
|
492
|
+
pet: this.selectedPet,
|
|
493
|
+
effects,
|
|
494
|
+
env,
|
|
457
495
|
});
|
|
458
496
|
}
|
|
497
|
+
getUpgradeRateImpact(upgrade, options) {
|
|
498
|
+
const before = this.getRates(options.crop, options.blocksBroken);
|
|
499
|
+
const clonedPlayer = this.clone();
|
|
500
|
+
clonedPlayer.applyUpgrade(upgrade);
|
|
501
|
+
const after = clonedPlayer.getRates(options.crop, options.blocksBroken);
|
|
502
|
+
return {
|
|
503
|
+
before,
|
|
504
|
+
after,
|
|
505
|
+
delta: diffDetailedDrops(before, after),
|
|
506
|
+
};
|
|
507
|
+
}
|
|
459
508
|
getWeightCalc(info) {
|
|
460
509
|
return createFarmingWeightCalculator({
|
|
461
510
|
collection: this.options.collection,
|
|
@@ -480,6 +529,35 @@ export class FarmingPlayer {
|
|
|
480
529
|
if (!upgrade.meta)
|
|
481
530
|
return;
|
|
482
531
|
const { type, itemUuid, key, value, id } = upgrade.meta;
|
|
532
|
+
if (type === 'upgrade_group') {
|
|
533
|
+
for (const groupedUpgrade of upgrade.groupedUpgrades ?? []) {
|
|
534
|
+
this.applyUpgrade(groupedUpgrade);
|
|
535
|
+
}
|
|
536
|
+
this.permFortune = this.getGeneralFortune();
|
|
537
|
+
return;
|
|
538
|
+
}
|
|
539
|
+
if ((type === 'pet_level' || type === 'pet_item') && itemUuid) {
|
|
540
|
+
const index = this.pets.findIndex((pet) => pet.pet.uuid === itemUuid);
|
|
541
|
+
const target = this.pets[index];
|
|
542
|
+
if (target) {
|
|
543
|
+
const nextPetData = { ...target.pet };
|
|
544
|
+
if (type === 'pet_level' && value) {
|
|
545
|
+
nextPetData.exp = target.getXpForLevel(Number(value));
|
|
546
|
+
}
|
|
547
|
+
else if (type === 'pet_item' && id) {
|
|
548
|
+
nextPetData.heldItem = id;
|
|
549
|
+
}
|
|
550
|
+
const updatedPet = new FarmingPet(nextPetData, this.options);
|
|
551
|
+
this.pets[index] = updatedPet;
|
|
552
|
+
this.options.pets = this.pets;
|
|
553
|
+
if (this.selectedPet?.pet.uuid === itemUuid) {
|
|
554
|
+
this.selectedPet = updatedPet;
|
|
555
|
+
this.options.selectedPet = updatedPet;
|
|
556
|
+
}
|
|
557
|
+
this.permFortune = this.getGeneralFortune();
|
|
558
|
+
}
|
|
559
|
+
return;
|
|
560
|
+
}
|
|
483
561
|
if (itemUuid) {
|
|
484
562
|
const candidates = [...this.tools, ...this.armor, ...this.equipment, ...this.accessories];
|
|
485
563
|
const target = candidates.find((i) => i.item.uuid === itemUuid);
|
|
@@ -491,7 +569,11 @@ export class FarmingPlayer {
|
|
|
491
569
|
if (target instanceof FarmingTool) {
|
|
492
570
|
const idx = this.tools.indexOf(target);
|
|
493
571
|
if (idx >= 0) {
|
|
494
|
-
|
|
572
|
+
const updatedTool = new FarmingTool(target.item, this.options);
|
|
573
|
+
this.tools[idx] = updatedTool;
|
|
574
|
+
if (this.selectedTool === target) {
|
|
575
|
+
this.selectedTool = updatedTool;
|
|
576
|
+
}
|
|
495
577
|
}
|
|
496
578
|
}
|
|
497
579
|
else if (target instanceof FarmingArmor) {
|
|
@@ -524,7 +606,11 @@ export class FarmingPlayer {
|
|
|
524
606
|
if (target instanceof FarmingTool) {
|
|
525
607
|
const idx = this.tools.indexOf(target);
|
|
526
608
|
if (idx >= 0) {
|
|
527
|
-
|
|
609
|
+
const updatedTool = new FarmingTool(target.item, this.options);
|
|
610
|
+
this.tools[idx] = updatedTool;
|
|
611
|
+
if (this.selectedTool === target) {
|
|
612
|
+
this.selectedTool = updatedTool;
|
|
613
|
+
}
|
|
528
614
|
}
|
|
529
615
|
}
|
|
530
616
|
else if (target instanceof FarmingArmor) {
|
|
@@ -602,6 +688,7 @@ export class FarmingPlayer {
|
|
|
602
688
|
else if (type === 'item' && id === 'rarity_upgrades' && value) {
|
|
603
689
|
target.item.attributes ??= {};
|
|
604
690
|
target.item.attributes.rarity_upgrades = String(value);
|
|
691
|
+
setItemRarityAttribute(target.item, nextRarity(target.rarity));
|
|
605
692
|
// Recomb affects rarity, which affects stats. Need to reload tool.
|
|
606
693
|
if (target instanceof FarmingTool) {
|
|
607
694
|
const idx = this.tools.indexOf(target);
|
|
@@ -649,6 +736,7 @@ export class FarmingPlayer {
|
|
|
649
736
|
...newItem.item.gems,
|
|
650
737
|
...target.item.gems,
|
|
651
738
|
};
|
|
739
|
+
setItemRarityAttribute(newItem.item, getUpgradedItemRarity(target.rarity, target.info.maxRarity, newItem.info.maxRarity));
|
|
652
740
|
// Preserve the old item's UUID so the item remains trackable
|
|
653
741
|
newItem.item.uuid = target.item.uuid;
|
|
654
742
|
if (target instanceof FarmingTool && newItem instanceof FarmingTool) {
|
|
@@ -674,6 +762,7 @@ export class FarmingPlayer {
|
|
|
674
762
|
else if (target instanceof FarmingEquipment && newItem instanceof FarmingEquipment) {
|
|
675
763
|
const idx = this.equipment.indexOf(target);
|
|
676
764
|
if (idx >= 0) {
|
|
765
|
+
target.applyTierUpgradeStateTo(newItem);
|
|
677
766
|
const updatedPiece = new FarmingEquipment(newItem.item, this.options);
|
|
678
767
|
this.equipment[idx] = updatedPiece;
|
|
679
768
|
this.armorSet.updateEquipmentSlot(updatedPiece);
|
|
@@ -688,6 +777,10 @@ export class FarmingPlayer {
|
|
|
688
777
|
this.permFortune = this.getGeneralFortune();
|
|
689
778
|
}
|
|
690
779
|
}
|
|
780
|
+
if (target instanceof FarmingAccessory) {
|
|
781
|
+
this.syncActiveAccessories();
|
|
782
|
+
}
|
|
783
|
+
this.permFortune = this.getGeneralFortune();
|
|
691
784
|
}
|
|
692
785
|
}
|
|
693
786
|
else if (type === 'skill') {
|
|
@@ -737,12 +830,22 @@ export class FarmingPlayer {
|
|
|
737
830
|
if (key === 'cocoaFortuneUpgrade') {
|
|
738
831
|
this.options.cocoaFortuneUpgrade = Number(value);
|
|
739
832
|
}
|
|
833
|
+
else if (key === 'dnaMilestone') {
|
|
834
|
+
this.options.dnaMilestone = Number(value);
|
|
835
|
+
}
|
|
836
|
+
else if (key === 'refinedTruffles') {
|
|
837
|
+
this.options.refinedTruffles = Number(value);
|
|
838
|
+
}
|
|
740
839
|
this.permFortune = this.getGeneralFortune();
|
|
741
840
|
}
|
|
742
841
|
else if (type === 'unlock' && id) {
|
|
743
842
|
if (id === 'personal_best') {
|
|
744
843
|
this.options.personalBestsUnlocked = true;
|
|
745
844
|
}
|
|
845
|
+
else if (id === 'exportable_crop' && key) {
|
|
846
|
+
this.options.exportableCrops ??= {};
|
|
847
|
+
this.options.exportableCrops[key] = true;
|
|
848
|
+
}
|
|
746
849
|
this.permFortune = this.getGeneralFortune();
|
|
747
850
|
}
|
|
748
851
|
else if (type === 'buy_item' && id) {
|
|
@@ -785,7 +888,9 @@ export class FarmingPlayer {
|
|
|
785
888
|
this.armor[oldIdx] = new FarmingArmor(newItem.item, this.options);
|
|
786
889
|
}
|
|
787
890
|
else {
|
|
788
|
-
this.
|
|
891
|
+
const addedPiece = new FarmingArmor(newItem.item, this.options);
|
|
892
|
+
this.armor.push(addedPiece);
|
|
893
|
+
this.armorSet.updateArmorSlot(addedPiece);
|
|
789
894
|
}
|
|
790
895
|
}
|
|
791
896
|
else if (newItem instanceof FarmingEquipment) {
|
|
@@ -801,10 +906,13 @@ export class FarmingPlayer {
|
|
|
801
906
|
...oldItem.item.attributes,
|
|
802
907
|
};
|
|
803
908
|
newItem.item.gems = { ...newItem.item.gems, ...oldItem.item.gems };
|
|
909
|
+
oldItem.applyTierUpgradeStateTo(newItem);
|
|
804
910
|
this.equipment[oldIdx] = new FarmingEquipment(newItem.item, this.options);
|
|
805
911
|
}
|
|
806
912
|
else {
|
|
807
|
-
this.
|
|
913
|
+
const addedPiece = new FarmingEquipment(newItem.item, this.options);
|
|
914
|
+
this.equipment.push(addedPiece);
|
|
915
|
+
this.armorSet.updateEquipmentSlot(addedPiece);
|
|
808
916
|
}
|
|
809
917
|
}
|
|
810
918
|
else if (newItem instanceof FarmingAccessory) {
|
|
@@ -826,6 +934,9 @@ export class FarmingPlayer {
|
|
|
826
934
|
this.accessories.push(newItem);
|
|
827
935
|
}
|
|
828
936
|
}
|
|
937
|
+
if (newItem instanceof FarmingAccessory) {
|
|
938
|
+
this.syncActiveAccessories();
|
|
939
|
+
}
|
|
829
940
|
this.permFortune = this.getGeneralFortune();
|
|
830
941
|
}
|
|
831
942
|
}
|
|
@@ -843,6 +954,8 @@ export class FarmingPlayer {
|
|
|
843
954
|
lore: [...(item.item.lore ?? [])],
|
|
844
955
|
}));
|
|
845
956
|
};
|
|
957
|
+
const selectedToolUuid = this.selectedTool?.item.uuid;
|
|
958
|
+
const selectedPetUuid = this.selectedPet?.pet.uuid;
|
|
846
959
|
const clonedOptions = {
|
|
847
960
|
...this.options,
|
|
848
961
|
tools: cloneItems(this.tools),
|
|
@@ -858,8 +971,21 @@ export class FarmingPlayer {
|
|
|
858
971
|
bestiaryKills: { ...this.options.bestiaryKills },
|
|
859
972
|
attributes: { ...this.options.attributes },
|
|
860
973
|
plots: [...(this.options.plots ?? [])],
|
|
974
|
+
selectedTool: undefined,
|
|
975
|
+
selectedPet: undefined,
|
|
861
976
|
};
|
|
862
|
-
|
|
977
|
+
const clonedPlayer = new FarmingPlayer(clonedOptions);
|
|
978
|
+
if (selectedToolUuid) {
|
|
979
|
+
const selectedTool = clonedPlayer.tools.find((tool) => tool.item.uuid === selectedToolUuid);
|
|
980
|
+
if (selectedTool)
|
|
981
|
+
clonedPlayer.selectTool(selectedTool);
|
|
982
|
+
}
|
|
983
|
+
if (selectedPetUuid) {
|
|
984
|
+
const selectedPet = clonedPlayer.pets.find((pet) => pet.pet.uuid === selectedPetUuid);
|
|
985
|
+
if (selectedPet)
|
|
986
|
+
clonedPlayer.selectPet(selectedPet);
|
|
987
|
+
}
|
|
988
|
+
return clonedPlayer;
|
|
863
989
|
}
|
|
864
990
|
/**
|
|
865
991
|
* Expands an upgrade into a tree of follow-up upgrades.
|
|
@@ -908,6 +1034,25 @@ export class FarmingPlayer {
|
|
|
908
1034
|
totalCost: upgrade.cost,
|
|
909
1035
|
children: [],
|
|
910
1036
|
};
|
|
1037
|
+
if (upgrade.meta?.type === 'upgrade_group') {
|
|
1038
|
+
const sequentialPlayer = this.clone();
|
|
1039
|
+
for (const groupedUpgrade of upgrade.groupedUpgrades ?? []) {
|
|
1040
|
+
const childStatsBefore = sequentialPlayer.getAllStats(stats, crop);
|
|
1041
|
+
const childPlayer = sequentialPlayer.clone();
|
|
1042
|
+
childPlayer.applyUpgrade(groupedUpgrade);
|
|
1043
|
+
const childStatsAfter = childPlayer.getAllStats(stats, crop);
|
|
1044
|
+
node.children.push({
|
|
1045
|
+
upgrade: groupedUpgrade,
|
|
1046
|
+
statsBefore: childStatsBefore,
|
|
1047
|
+
statsAfter: childStatsAfter,
|
|
1048
|
+
statsGained: this.computeStatsDiff(childStatsBefore, childStatsAfter),
|
|
1049
|
+
totalCost: groupedUpgrade.cost,
|
|
1050
|
+
children: [],
|
|
1051
|
+
});
|
|
1052
|
+
sequentialPlayer.applyUpgrade(groupedUpgrade);
|
|
1053
|
+
}
|
|
1054
|
+
return node;
|
|
1055
|
+
}
|
|
911
1056
|
// Stop recursion at max depth
|
|
912
1057
|
if (depth >= maxDepth) {
|
|
913
1058
|
return node;
|
|
@@ -1004,9 +1149,12 @@ export class FarmingPlayer {
|
|
|
1004
1149
|
const target = player.tools.find((t) => t.item.uuid === itemUuid) ??
|
|
1005
1150
|
player.armor.find((a) => a.item.uuid === itemUuid) ??
|
|
1006
1151
|
player.equipment.find((e) => e.item.uuid === itemUuid) ??
|
|
1007
|
-
player.accessories.find((a) => a.item.uuid === itemUuid)
|
|
1152
|
+
player.accessories.find((a) => a.item.uuid === itemUuid) ??
|
|
1153
|
+
player.pets.find((p) => p.pet.uuid === itemUuid);
|
|
1008
1154
|
if (target && 'getUpgrades' in target && typeof target.getUpgrades === 'function') {
|
|
1009
|
-
const itemUpgrades = target
|
|
1155
|
+
const itemUpgrades = target instanceof FarmingPet
|
|
1156
|
+
? target.getUpgrades({ stat: primaryStat }, player)
|
|
1157
|
+
: target.getUpgrades({ stat: primaryStat });
|
|
1010
1158
|
// Filter to only include upgrades of the same type (enchant chains, tier upgrades, etc.)
|
|
1011
1159
|
// For gem upgrades, also match on slot to only show follow-ups for that specific slot
|
|
1012
1160
|
for (const u of itemUpgrades) {
|
|
@@ -1041,4 +1189,46 @@ export class FarmingPlayer {
|
|
|
1041
1189
|
return upgrades;
|
|
1042
1190
|
}
|
|
1043
1191
|
}
|
|
1192
|
+
function diffDetailedDrops(before, after) {
|
|
1193
|
+
const items = diffRecord(before.items, after.items);
|
|
1194
|
+
const rngItems = diffRecord(before.rngItems ?? {}, after.rngItems ?? {});
|
|
1195
|
+
const currencies = diffRecord(before.currencies, after.currencies);
|
|
1196
|
+
return {
|
|
1197
|
+
collection: after.collection - before.collection,
|
|
1198
|
+
npcCoins: after.npcCoins - before.npcCoins,
|
|
1199
|
+
coinSources: diffRecord(before.coinSources, after.coinSources),
|
|
1200
|
+
otherCollection: diffRecord(before.otherCollection, after.otherCollection),
|
|
1201
|
+
items,
|
|
1202
|
+
currencies,
|
|
1203
|
+
rngItems,
|
|
1204
|
+
totalItems: sumRecord(items) + sumRecord(rngItems),
|
|
1205
|
+
};
|
|
1206
|
+
}
|
|
1207
|
+
function diffRecord(before, after) {
|
|
1208
|
+
const result = {};
|
|
1209
|
+
const keys = new Set([...Object.keys(before), ...Object.keys(after)]);
|
|
1210
|
+
for (const key of keys) {
|
|
1211
|
+
const delta = (after[key] ?? 0) - (before[key] ?? 0);
|
|
1212
|
+
if (delta !== 0) {
|
|
1213
|
+
result[key] = delta;
|
|
1214
|
+
}
|
|
1215
|
+
}
|
|
1216
|
+
return result;
|
|
1217
|
+
}
|
|
1218
|
+
function sumRecord(record) {
|
|
1219
|
+
return Object.values(record).reduce((sum, value) => sum + value, 0);
|
|
1220
|
+
}
|
|
1221
|
+
function getUpgradedItemRarity(currentRarity, currentMaxRarity, nextMaxRarity) {
|
|
1222
|
+
const currentBaseRarity = previousRarity(currentMaxRarity);
|
|
1223
|
+
const nextBaseRarity = previousRarity(nextMaxRarity);
|
|
1224
|
+
const rarityIncrease = compareRarity(currentRarity, currentBaseRarity);
|
|
1225
|
+
if (rarityIncrease > 0) {
|
|
1226
|
+
return nextRarity(nextBaseRarity);
|
|
1227
|
+
}
|
|
1228
|
+
return nextBaseRarity;
|
|
1229
|
+
}
|
|
1230
|
+
function setItemRarityAttribute(item, rarity) {
|
|
1231
|
+
item.attributes ??= {};
|
|
1232
|
+
item.attributes.rarity = rarity;
|
|
1233
|
+
}
|
|
1044
1234
|
//# sourceMappingURL=player.js.map
|