diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 5333e3ff..b00d9457 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml @@ -15,7 +15,7 @@ on: env: # Default version of Node.js for jobs - node-version: "18" + node-version: "24" jobs: build-push: diff --git a/eslint.config.ts b/eslint.config.ts new file mode 100644 index 00000000..d82def48 --- /dev/null +++ b/eslint.config.ts @@ -0,0 +1,48 @@ +import * as eslint from "@eslint/js"; +import tseslint from "typescript-eslint"; +import prettier from "eslint-config-prettier"; +import libram, { verifyConstantsSinceRevision } from "eslint-plugin-libram"; + +const VERIFY_CONSTANTS_SINCE = 28904; + +await verifyConstantsSinceRevision(VERIFY_CONSTANTS_SINCE); + +export default [ + { + ignores: ["dist/**"], + files: ["**/*.ts", "**/*.tsx"], + languageOptions: { + parser: tseslint.parser, + parserOptions: { + tsconfigRootDir: import.meta.dirname, + projectService: { + allowDefaultProject: ["*.mjs", "*.js"], + }, + }, + }, + }, + + eslint.configs.recommended, + ...tseslint.configs.recommended, + libram.configs.recommended, + prettier, + + { + rules: { + "block-scoped-var": "error", + "eol-last": "error", + eqeqeq: "error", + "no-trailing-spaces": "error", + "no-var": "error", + "prefer-arrow-callback": "error", + "prefer-const": "error", + "prefer-template": "error", + "sort-imports": ["error", { ignoreCase: true, ignoreDeclarationSort: true }], + "no-unused-vars": "off", + "@typescript-eslint/no-unused-vars": "error", + "libram/verify-constants": "error", + }, + }, +]; + + diff --git a/package.json b/package.json index 3f482561..72e5c5dd 100644 --- a/package.json +++ b/package.json @@ -18,12 +18,12 @@ "@babel/plugin-proposal-object-rest-spread": "^7.14.7", "@babel/preset-env": "^7.15.0", "@babel/preset-typescript": "^7.15.0", - "@typescript-eslint/eslint-plugin": "^4.29.3", - "@typescript-eslint/parser": "^4.29.3", + "@typescript-eslint/eslint-plugin": "^8.33.1", + "@typescript-eslint/parser": "^8.33.1", "babel-loader": "^8.2.2", - "eslint": "^9.17.0", - "eslint-config-prettier": "^8.3.0", - "eslint-plugin-libram": "^0.4.16", + "eslint": "^9.39.2", + "eslint-config-prettier": "^10.1.8", + "eslint-plugin-libram": "^0.5.3", "prettier": "^2.3.2", "typescript": "^4.4.2", "webpack": "^5.61.0", @@ -31,11 +31,15 @@ }, "dependencies": { "core-js": "^3.16.4", + "data-of-loathing": "^2.2.0", "garbo-lib": "^0.0.1", - "grimoire-kolmafia": "^0.3.25", - "kolmafia": "^5.28266.0", - "libram": "^0.9.29", - "mafia-shared-relay": "0.0.7" + "grimoire-kolmafia": "^0.3.33", + "kol-rng": "^2.0.0", + "kolmafia": "^5.28904.0", + "libram": "^0.11.16", + "mafia-shared-relay": "0.0.7", + "node": "^25.6.0", + "typescript-eslint": "^8.54.0" }, "author": "Pantocyclus/Seraphiii", "license": "MIT", diff --git a/src/args.ts b/src/args.ts index 6795ea57..73605e3c 100644 --- a/src/args.ts +++ b/src/args.ts @@ -27,42 +27,10 @@ export const args = Args.create( help: `Name of the outfit that contains stick-knife, for stick-knife trick`, default: "", }), - fortifiedwine: Args.flag({ - help: `Do not grab the DFW lucky adventure (if you have numberology or are using skip-BT route)`, - default: true, - }), - perfectfreeze: Args.flag({ - help: `Do not craft and drink a perfect drink`, - default: true, - }), - beesknees: Args.flag({ - help: `Do not buy and drink Bee's Knees`, - default: true, - }), - sacramentowine: Args.flag({ - help: `Do not drink a Sacramento Wine for the item test`, - default: true, - }), synthxp: Args.flag({ help: `Do not use synth for the Xp% buff`, default: true, }), - deepdish: Args.flag({ - help: `Skip Deep Dish of Legend`, - default: false, - }), - latedeepdish: Args.flag({ - help: `Eat a deep dish, but only before the familiar test`, - default: false, - }), - calzone: Args.flag({ - help: `Skip Calzone of Legend`, - default: false, - }), - pizza: Args.flag({ - help: `Skip Pizza of Legend`, - default: false, - }), asdon: Args.flag({ help: `Should we use Asdon Martin? Incompatible with Skipping Borrowed Time`, default: false, @@ -79,26 +47,10 @@ export const args = Args.create( help: `Do not fight witchess monsters nor acquire Puzzle Champ`, default: false, }), - savebackups: Args.number({ - help: "How many backup camera backups should we save?", - default: 11, - }), - savehabitats: Args.number({ - help: "How many Book of Facts habitats should we save?", - default: 3, - }), redskeleton: Args.flag({ help: `Do not locket a red skeleton`, default: false, }), - witchessking: Args.flag({ - help: `Do not locket a witchess king`, - default: false, - }), - factoryworker: Args.flag({ - help: `Do not locket a factory worker (female)`, - default: false, - }), ninjamap: Args.flag({ help: `Do not attempt to grab a li'l ninja costume for your tot`, default: false, @@ -151,10 +103,6 @@ export const args = Args.create( help: `Do not acquire shoe gum with cop dollars`, default: false, }), - savekgb: Args.flag({ - help: `Do not use any KGB clicks`, - default: false, - }), savepantogramming: Args.flag({ help: `Do not use your pantogram`, default: false, @@ -175,10 +123,6 @@ export const args = Args.create( help: `Do not use harvested pumpkins`, default: false, }), - savesugar: Args.flag({ - help: `Do not spend tome uses on sugar shorts/chapeau/shank`, - default: false, - }), savegarden: Args.flag({ help: `Do not harvest your garden`, default: false, @@ -211,10 +155,6 @@ export const args = Args.create( help: `Do not use Giant Growth or any other deck cheats`, default: false, }), - savecyclops: Args.flag({ - help: `Do not get and use cyclops eyedrops`, - default: false, - }), saveembers: Args.flag({ help: `Do not get and use mouthwash/sept-ember`, default: false, @@ -231,14 +171,6 @@ export const args = Args.create( help: `Automatically optimize and use excess pulls for good stuff?`, default: false, }), - camelhat: Args.flag({ - help: `Use a box of familiar jacks to ensure camel is charged faster?`, - default: false, - }), - skipbt: Args.flag({ - help: `Route around using borrowed time? Note this requires using at least one legendary pizza.`, - default: false, - }), experimentalsynth: Args.flag({ help: `Try using Synth for item%? Requires Sugar Shummoning`, default: false, @@ -251,10 +183,6 @@ export const args = Args.create( help: `Effects that we should not acquire throughout the run.`, default: "", }), - wardrobe: Args.flag({ - help: `Should we skip using the Wardrobe-O-Matic at level 15 automatically?`, - default: false, - }), explicitlyexcludedfams: Args.string({ help: `Familiars that we should not use throughout the run.`, default: "", @@ -299,5 +227,9 @@ export const args = Args.create( help: `Set default weapon damage test limit`, default: 10, }), + test: Args.flag({ + help: `Test new features`, + default: false, + }), } ); diff --git a/src/beret.ts b/src/beret.ts new file mode 100644 index 00000000..3b57cb48 --- /dev/null +++ b/src/beret.ts @@ -0,0 +1,419 @@ +import { + beretBuskingEffects, + buy, + canEquip, + Effect, + equip, + equippedItem, + getPower, + Item, + myFamiliar, + myMeat, + npcPrice, + numericModifier, + toEffect, + toSlot, + useFamiliar, + useSkill, +} from "kolmafia"; +import { + $effect, + $familiar, + $item, + $skill, + $slot, + $slots, + get, + have as have_, + logger, + maxBy, + NumericModifier, + sum, + unequip, +} from "libram"; + +// eslint-disable-next-line libram/verify-constants +const beret = $item`prismatic beret`; + +export type EffectValuer = + | Partial> + | ((effect: Effect, duration: number) => number) + | Effect[]; +const valueEffect = (effect: Effect, duration: number, valuer: EffectValuer) => + typeof valuer === "function" + ? valuer(effect, duration) + : Array.isArray(valuer) + ? Number(valuer.includes(effect)) * duration + : sum( + Object.entries(valuer), + ([modifier, weight]) => weight * numericModifier(effect, modifier) + ); + +/** + * @returns Whether or not you have the prismatic beret + */ +export function have(): boolean { + return have_(beret); +} + +function getUseableClothes(buyItem = true): { + useableHats: Item[]; + useablePants: Item[]; + useableShirts: Item[]; +} { + const availableItems = Item.all().filter( + (i) => canEquip(i) && (have_(i) || (buyItem && npcPrice(i) > 0)) + ); + const useableHats = have_($familiar`Mad Hatrack`) + ? [...availableItems.filter((i) => toSlot(i) === $slot`hat`), $item.none] + : [beret]; + const useablePants = [...availableItems.filter((i) => toSlot(i) === $slot`pants`), $item.none]; + const useableShirts = [...availableItems.filter((i) => toSlot(i) === $slot`shirt`), $item.none]; + return { useableHats, useablePants, useableShirts }; +} + +function availablePowersums(buyItem: boolean, assumeHammertime: boolean): number[] { + const taoMultiplier = have_($skill`Tao of the Terrapin`) ? 2 : 1; + const hammerTimeMultiplier = assumeHammertime || have_($effect`Hammertime`) ? 4 : 0; + + const { useableHats, useablePants, useableShirts } = getUseableClothes(buyItem); + + const hatPowers = [...new Set(useableHats.map((i) => taoMultiplier * getPower(i)))]; + const pantPowers = [ + ...new Set(useablePants.map((i) => (taoMultiplier + hammerTimeMultiplier) * getPower(i))), + ]; + const shirtPowers = [...new Set(useableShirts.map((i) => getPower(i)))]; + + return [ + ...new Set( + hatPowers.flatMap((hat) => + pantPowers.flatMap((pant) => shirtPowers.flatMap((shirt) => hat + pant + shirt)) + ) + ), + ]; +} + +function scoreBusk( + effects: [Effect, number][], + effectValuer: EffectValuer, + uselessEffects: Set +): number { + const usefulEffects = effects.filter(([effect]) => !uselessEffects.has(effect)); + return sum(usefulEffects, ([effect, duration]) => valueEffect(effect, duration, effectValuer)); +} + +/** + * Calculate the optimal power-sum at which to busk, given a weighted set of modifiers. + * @param wantedEffects An array of Effects we care about; maximizes the number of those effects we end up with + * @param buskUses How many busks should we assume we've cast? Defaults to the current number. + * @param uselessEffects An array (defaults to empty) of effects not to consider for the purposes of busk valuation + * @param buyItem Whether or not we should consider purchasing items from NPC stores; defaults to true + * @returns The power-sum at which you'll find the optimal busk for this situation. + */ +export function findOptimalOutfitPower( + wantedEffects: Effect[], + buskUses?: number, + uselessEffects?: Effect[], + buyItem?: boolean, + assumeHammertime?: boolean +): number; +/** + * Calculate the optimal power-sum at which to busk, given a weighted set of modifiers. + * @param weightedModifiers An object keyed by Numeric Modifiers, with their values representing weights + * @param buskUses How many busks should we assume we've cast? Defaults to the current number. + * @param uselessEffects An array (defaults to empty) of effects not to consider for the purposes of busk valuation + * @param buyItem Whether or not we should consider purchasing items from NPC stores; defaults to true + * @returns The power-sum at which you'll find the optimal busk for this situation. + */ +export function findOptimalOutfitPower( + weightedModifiers: Partial>, + buskUses?: number, + uselessEffects?: Effect[], + buyItem?: boolean, + assumeHammertime?: boolean +): number; +/** + * Calculate the optimal power-sum at which to busk, given a weighted set of modifiers. + * @param valueFunction A function that maps effects to values + * @param buskUses How many busks should we assume we've cast? Defaults to the current number. + * @param uselessEffects An array (defaults to empty) of effects not to consider for the purposes of busk valuation + * @param buyItem Whether or not we should consider purchasing items from NPC stores; defaults to true + * @returns The power-sum at which you'll find the optimal busk for this situation. + */ +export function findOptimalOutfitPower( + valueFunction: (effect: Effect, duration: number) => number, + buskUses?: number, + uselessEffects?: Effect[], + buyItem?: boolean, + assumeHammertime?: boolean +): number; +/** + * Calculate the optimal power-sum at which to busk, given a weighted set of modifiers. + * @param effectValuer Either a function that maps effect-duration pairs to values, or an object keyed by numeric modifiers with weights as values, or an array of desired effects + * @param buskUses How many busks should we assume we've cast? Defaults to the current number. + * @param uselessEffects An array (defaults to empty) of effects not to consider for the purposes of busk valuation + * @param buyItem Whether or not we should consider purchasing items from NPC stores; defaults to true + * @returns The power-sum at which you'll find the optimal busk for this situation. + */ +export function findOptimalOutfitPower( + effectValuer: EffectValuer, + buskUses?: number, + uselessEffects?: Effect[], + buyItem?: boolean, + assumeHammertime?: boolean +): number; +/** + * Calculate the optimal power-sum at which to busk, given a weighted set of modifiers. + * @param effectValuer Either a function that maps effect-duration pairs to values, or an object keyed by numeric modifiers with weights as values, or an array of desired effects + * @param buskUses How many busks should we assume we've cast? Defaults to the current number. + * @param uselessEffects An array (defaults to empty) of effects not to consider for the purposes of busk valuation + * @param buyItem Whether or not we should consider purchasing items from NPC stores; defaults to true + * @returns The power-sum at which you'll find the optimal busk for this situation. + */ +export function findOptimalOutfitPower( + effectValuer: EffectValuer, + buskUses = get("_beretBuskingUses", 0), + uselessEffects: Effect[] = [], + buyItem = true, + assumeHammertime = false +): number { + const uselessEffectSet = new Set(uselessEffects); + const powersums = availablePowersums(buyItem, assumeHammertime); + if (!powersums.length) return 0; + return maxBy(powersums, (power) => + scoreBusk( + Object.entries(beretBuskingEffects(power, buskUses)) + .map(([effect, duration]): [Effect, number] => [toEffect(effect), duration]) + .filter(([e]) => e !== $effect.none), + effectValuer, + uselessEffectSet + ) + ); +} + +const populateMap = (arr: Item[], max: number, double: boolean) => { + const map = new Map(); + for (const it of arr) { + const power = getPower(it) * (double ? 2 : 1); + if (power > max) continue; + + const existing = map.get(power); + if (!existing || (!have_(existing) && (have_(it) || npcPrice(it) < npcPrice(existing)))) { + map.set(power, it); + } + } + return map; +}; +const relevantSlots = ["hat", "pants", "shirt"] as const; +const functionalPrice = (item: Item) => (have_(item) || item === Item.none ? 0 : npcPrice(item)); +const outfitPrice = (outfit: { hat: Item; pants: Item; shirt: Item }) => + sum(relevantSlots, (slot) => functionalPrice(outfit[slot])); +function findOutfit(power: number, buyItem: boolean) { + const { useableHats, useablePants, useableShirts } = getUseableClothes(buyItem); + const hatPowers = populateMap(useableHats, power, have_($skill`Tao of the Terrapin`)); + const pantsPowers = populateMap(useablePants, power, have_($skill`Tao of the Terrapin`)); + const shirtPowers = populateMap(useableShirts, power, false); + + const outfits = [...hatPowers].flatMap(([hatPower, hat]) => + [...pantsPowers].flatMap(([pantsPower, pants]) => + [...shirtPowers].flatMap(([shirtPower, shirt]) => + hatPower + pantsPower + shirtPower === power ? { hat, pants, shirt } : [] + ) + ) + ); + if (!outfits.length) return null; + const outfit = maxBy(outfits, outfitPrice, true); + logger.debug(`Chose outfit ${outfit.hat} ${outfit.shirt} ${outfit.pants}`); + if (outfitPrice(outfit) > myMeat()) return null; + + for (const slot of relevantSlots) { + const item = outfit[slot]; + if (have_(item) || item === Item.none) continue; + if (!buy(item)) { + logger.debug(`Failed to purchase ${item}`); + return null; + } + } + return outfit; +} + +/** + * Attempt to busk at a particular power + * @param power The power in question + * @param buyItem Whether to buy items from NPC shops to create an outfit + * @returns If we successfully busked at that power + */ +export function buskAt(power: number, buyItem = true): boolean { + if (!have()) return false; + const initialUses = get("_beretBuskingUses", 0); + if (initialUses >= 5) return false; + const outfit = findOutfit(power, buyItem); + if (!outfit) return false; + const initialEquips = $slots`hat, shirt, pants`.map((slot) => equippedItem(slot)); + const initialFamiliar = myFamiliar(); + const initialFamequip = equippedItem($slot`familiar`); + const { hat, pants, shirt } = outfit; + equip($slot`hat`, hat); + if (hat !== beret) { + useFamiliar($familiar`Mad Hatrack`); + equip($slot`familiar`, beret); + } + equip($slot`shirt`, shirt); + equip($slot`pants`, pants); + const taoMultiplier = have_($skill`Tao of the Terrapin`) ? 2 : 1; + try { + if ( + taoMultiplier * (getPower(equippedItem($slot`hat`)) + getPower(equippedItem($slot`pants`))) + + getPower(equippedItem($slot`shirt`)) !== + power + ) { + return false; + } + // eslint-disable-next-line libram/verify-constants + useSkill($skill`Beret Busking`); + return initialUses !== get("_beretBuskingUses", 0); + } finally { + $slots`hat, shirt, pants`.forEach((slot, index) => equip(slot, initialEquips[index])); + if (initialFamiliar !== $familiar`Mad Hatrack` && myFamiliar() === $familiar`Mad Hatrack`) { + unequip($slot`familiar`); + } + useFamiliar(initialFamiliar); + equip($slot`familiar`, initialFamequip); + } +} + +export function buskFor( + weightedModifiers: Partial>, + buyItem?: boolean, + uselessEffects?: Effect[] +): boolean; +export function buskFor(effects: Effect[], buyItem?: boolean, uselessEffects?: Effect[]): boolean; +export function buskFor( + valueFunction: (effect: Effect, duration: number) => number, + buyItem?: boolean, + uselessEffects?: Effect[] +): boolean; +/** + * Calculate the best outfit-power you can achieve for a given busk valuation, and then busks. + * @param effectValuer Either a function that maps effect-duration pairs to values, or an object keyed by numeric modifiers with weights as values, or an array of desired effects + * @param buyItem Whether or not we should consider purchasing items from NPC stores; defaults to true + * @param uselessEffects An array (defaults to empty) of effects not to consider for the purposes of busk valuation + * @returns Whether we were successful in our endeavor + */ +export function buskFor( + effectValuer: EffectValuer, + buyItem = true, + uselessEffects: Effect[] = [] +): boolean { + const outfitPower = findOptimalOutfitPower( + effectValuer, + get("_beretBuskingUses", 0), + uselessEffects, + buyItem + ); + return buskAt(outfitPower, buyItem); +} + +function multipliers(): [number, number] { + const taoHatMultiplier = have_($skill`Tao of the Terrapin`) ? 2 : 1; + const taoPantsMultiplier = have_($skill`Tao of the Terrapin`) ? 1 : 0; + const hammerTimeMultiplier = have_($effect`Hammertime`) ? 3 : 0; + const totalPantsMultiplier = 1 + hammerTimeMultiplier + taoPantsMultiplier; + + return [taoHatMultiplier, totalPantsMultiplier]; +} + +export function reconstructOutfit(daRaw: number): { hat?: Item; shirt?: Item; pants?: Item } { + const allItems = Item.all().filter((i) => have_(i) && canEquip(i)); + const shopItems = Item.all().filter((i) => npcPrice(i) > 0 && canEquip(i)); + allItems.push(...shopItems); + const allHats = () => + have_($familiar`Mad Hatrack`) ? allItems.filter((i) => toSlot(i) === $slot`hat`) : [beret]; + const allPants = allItems.filter((i) => toSlot(i) === $slot`pants`); + const allShirts = allItems.filter((i) => toSlot(i) === $slot`shirt`); + + for (const hat of allHats()) { + const hatPower = multipliers()[0] * getPower(hat); + for (const shirt of allShirts) { + const shirtPower = getPower(shirt); + for (const pants of allPants) { + const pantsPower = multipliers()[1] * getPower(pants); + if (shirtPower + hatPower + pantsPower === daRaw) { + return { hat, shirt, pants }; + } + } + } + } + + return {}; +} + +export function findTopBusksGreedy( + weightedModifiers: Partial>, + uselessEffects: Effect[] = [], + assumeHammertime = false +): { + powers: number[]; + effects: Effect[]; + outfit: ReturnType[]; + score: number; +} { + const buskCount = 5; + const allPowers = availablePowersums(true, assumeHammertime); + const uselessSet = new Set(uselessEffects); + + // Pre-score and pick top powers (same as before) + const scoredPowers = allPowers + .map((p) => { + const effects = Object.entries(beretBuskingEffects(p, 0)) + .map(([name, dur]): [Effect, number] => [toEffect(name), dur]) + .filter(([e]) => e !== $effect.none && !uselessSet.has(e)); + return { power: p, score: scoreBusk(effects, weightedModifiers, uselessSet) }; + }) + .filter((p) => p.score > 0) + .sort((a, b) => b.score - a.score) + .slice(0, 100); + + const chosenPowers: number[] = []; + const totalEffects = new Map(); + + for (let busk = 0; busk < buskCount; busk++) { + let bestChoice: number | null = null; + let bestScore = -Infinity; + let bestEffects: Map | null = null; + + for (const { power } of scoredPowers) { + if (chosenPowers.includes(power)) continue; + + const newEffects = Object.entries(beretBuskingEffects(power, busk)) + .map(([name, dur]) => [toEffect(name), dur] as [Effect, number]) + .filter(([e]) => e !== $effect.none && !uselessSet.has(e)); + + const effectMap = new Map(totalEffects); + for (const [e, dur] of newEffects) { + if (!effectMap.has(e)) effectMap.set(e, dur); + } + + const score = scoreBusk([...effectMap.entries()], weightedModifiers, uselessSet); + if (score > bestScore) { + bestChoice = power; + bestScore = score; + bestEffects = effectMap; + } + } + + if (bestChoice !== null && bestEffects !== null) { + chosenPowers.push(bestChoice); + for (const [e, dur] of bestEffects) totalEffects.set(e, dur); + } else { + break; // no good candidates + } + } + + return { + powers: chosenPowers, + effects: [...totalEffects.keys()], + outfit: chosenPowers.map((p) => reconstructOutfit(p)), + score: scoreBusk([...totalEffects.entries()], weightedModifiers, uselessSet), + }; +} diff --git a/src/combat.ts b/src/combat.ts index f4cfad73..4e496459 100644 --- a/src/combat.ts +++ b/src/combat.ts @@ -1,5 +1,5 @@ import { mpCost, myPrimestat, toInt } from "kolmafia"; -import { $item, $monster, $skill, $stat, get, have, StrictMacro } from "libram"; +import { $item, $monster, $skill, $stat, CommunityService, get, have, StrictMacro } from "libram"; //export const mainStat = myClass().primestat; export const mainStat = myPrimestat(); //Update to select mainstat based on class derived from Libram @@ -11,10 +11,13 @@ export default class Macro extends StrictMacro { const macroHead = this.trySkill($skill`Curse of Weaksauce`) .trySkill($skill`Micrometeorite`) .trySkill($skill`Sing Along`) + .ifHolidayWanderer(Macro.banish()) + .externalIf( + get("_cosmicBowlingSkillsUsed") < 1 && CommunityService.CoilWire.isDone(), + Macro.trySkill($skill`Bowl Sideways`) + ) .trySkill($skill`Gulp Latte`) - // eslint-disable-next-line libram/verify-constants .trySkill($skill`Surprisingly Sweet Stab`) - // eslint-disable-next-line libram/verify-constants .trySkill($skill`Surprisingly Sweet Slash`) .if_( `!mpbelow ${mpCost($skill`Stuffed Mortar Shell`)}`, @@ -48,24 +51,20 @@ export default class Macro extends StrictMacro { } itemDrop(): Macro { - return ( - Macro.if_( - $monster`sausage goblin`, - Macro.trySkill($skill`Bowl Straight Up`) - .trySkill($skill`Become a Bat`) - .default(false) - ), - Macro.if_( - $monster`fluffy bunny`, - Macro.trySkill($skill`Bowl Straight Up`) - .trySkill($skill`Become a Bat`) - .trySkill($skill`Feel Hatred`) - .trySkill($skill`Reflex Hammer`) - .trySkill($skill`Throw Latte on Opponent`) - .trySkill($skill`KGB tranquilizer dart`) - .trySkill($skill`Snokebomb`) - ) - ); + return Macro.if_( + $monster`sausage goblin`, + Macro.trySkill($skill`Bowl Straight Up`) + .trySkill($skill`Become a Bat`) + .default(false) + ) + .trySkill($skill`Bowl Straight Up`) + .trySkill($skill`Become a Bat`) + .trySkill($skill`Feel Hatred`) + .trySkill($skill`Reflex Hammer`) + .trySkill($skill`Throw Latte on Opponent`) + .trySkill($skill`KGB tranquilizer dart`) + .trySkill($skill`Snokebomb`) + .runaway(); } static itemDrop(): Macro { diff --git a/src/engine/outfit.ts b/src/engine/outfit.ts index 943eb1de..cfcc8a94 100644 --- a/src/engine/outfit.ts +++ b/src/engine/outfit.ts @@ -5,6 +5,7 @@ import { equippedItem, Familiar, Item, + Monster, myMaxmp, myMp, myPrimestat, @@ -18,20 +19,20 @@ import { $familiar, $familiars, $item, + $monster, $skill, $slot, - DaylightShavings, examine, get, + getScalingRate, have, maxBy, + ToyCupidBow, } from "libram"; import { camelFightsLeft, statToMaximizerString } from "../lib"; import { args } from "../args"; import { restoreMPEfficiently } from "../tasks/leveling"; -const primeStat = statToMaximizerString(myPrimestat()); - export function garbageShirt(): boolean { if ( have($item`January's Garbage Tote`) && @@ -87,6 +88,18 @@ function nanorhino(allowAttackingFamiliars = false): Familiar { : $familiar.none; } +// eslint-disable-next-line @typescript-eslint/no-unused-vars +function melodramedary(_allowAttackingFamiliars = false): Familiar { + return !have($effect`Spit Upon`) && + !( + have($item`legendary seal-clubbing club`) && + have($item`heartstone`) && + get("_clubEmTimeUsed") < 4 + ) + ? $familiar`Melodramedary` + : $familiar.none; +} + function shorterOrderCook(allowAttackingFamiliars = true): Familiar { return allowAttackingFamiliars && !have($item`short stack of pancakes`) ? $familiar`Shorter-Order Cook` @@ -100,8 +113,7 @@ function garbageFire(): Familiar { function sombrero(allowAttackingFamiliars = true): Familiar { const sombreros = [ ...(allowAttackingFamiliars - ? // eslint-disable-next-line libram/verify-constants - $familiars`Jill-of-All-Trades, Patriotic Eagle, Galloping Grill` + ? $familiars`Jill-of-All-Trades, Patriotic Eagle, Galloping Grill` : []), $familiar`Baby Sandworm`, $familiar`Hovering Sombrero`, @@ -117,22 +129,27 @@ function optimisticCandle(): Familiar { return !have($item`glob of melted wax`) ? $familiar`Optimistic Candle` : $familiar.none; } -function melodramedary(): Familiar { - if (have($effect`Spit Upon`)) return $familiar.none; - return (have($familiar`Melodramedary`) && - camelFightsLeft() >= Math.ceil((100 - get("camelSpit")) / 3.0) && - get("camelSpit") < 100) || - (have($familiar`Melodramedary`) && - camelFightsLeft() >= Math.ceil((100 - get("camelSpit")) / 4.0) && - get("camelSpit") < 100 && - have($item`dromedary drinking helmet`)) - ? $familiar`Melodramedary` - : $familiar.none; +function homemade(): Familiar { + if ( + have($familiar`Homemade Robot`) && + have($familiar`Comma Chameleon`) && + have($item`toy Cupid bow`) && + !have($item`homemade robot gear`) && + camelFightsLeft() >= 5 + ) + return $familiar`Homemade Robot`; + return $familiar.none; } export function chooseFamiliar(allowAttackingFamiliars = true): Familiar { const ignoredFamiliars = args.explicitlyexcludedfams.split(",").map((i) => toInt(i)); const defaultFam = have($familiar`Cookbookbat`) ? $familiar`Cookbookbat` : $familiar.none; + const tcbFamiliar = ToyCupidBow.currentFamiliar(); + if (tcbFamiliar !== null) { + if (ToyCupidBow.turnsLeft() < 5) { + return tcbFamiliar; + } + } const familiars = [ melodramedary, shorterOrderCook, @@ -140,10 +157,13 @@ export function chooseFamiliar(allowAttackingFamiliars = true): Familiar { nanorhino, optimisticCandle, rockinRobin, + homemade, sombrero, ] .map((fn) => fn(allowAttackingFamiliars)) .filter((fam) => have(fam) && !ignoredFamiliars.includes(toInt(fam))); + + print(`Familiar order: ${familiars}`); return familiars.length > 0 ? familiars[0] : defaultFam; } @@ -155,14 +175,6 @@ export function chooseHeaviestFamiliar(): Familiar { ); } -export function avoidDaylightShavingsHelm(): boolean { - return ( - DaylightShavings.nextBuff() === $effect`Musician's Musician's Moustache` || - DaylightShavings.hasBuff() || - !have($item`Daylight Shavings Helmet`) - ); -} - const candySword = $item`candy cane sword cane`; function useCandyCaneSword(): boolean { @@ -173,14 +185,27 @@ function useCandyCaneSword(): boolean { get("_surprisinglySweetSlashUsed", 0) < 11 && get("_surprisinglySweetStabUsed", 0) < 11 ) { - print(`Candy Cane at ${numericModifier(candySword, "Weapon Damage")} weapon damage`); return true; } return false; } -export function baseOutfit(allowAttackingFamiliars = true): OutfitSpec { +function baseOutfitFirstPass( + allowAttackingFamiliars = true, + avoidGarbageShirt = false, + medianMonster?: Monster +): OutfitSpec { parka(); + const mainstat = myPrimestat(); + const mainstatString = statToMaximizerString(mainstat); + + const monster = medianMonster ? medianMonster : $monster`flaming leaflet`; + const monsterScaling = getScalingRate(monster); + + const stringPrequel = + monsterScaling > 0 + ? `10 ${mainstatString}, 2 ML, 1 ${mainstatString} exp, 25 ${mainstatString} experience percent,` + : `2 ML, 3 ${mainstatString} exp, 25 ${mainstatString} experience percent,`; return { weapon: useCandyCaneSword() @@ -188,37 +213,61 @@ export function baseOutfit(allowAttackingFamiliars = true): OutfitSpec { : have($item`June cleaver`) ? $item`June cleaver` : undefined, - back: get("questPAGhost") === "unstarted" && get("nextParanormalActivity") <= totalTurnsPlayed() - ? $item`protonic accelerator pack` : undefined, - hat: avoidDaylightShavingsHelm() ? undefined : $item`Daylight Shavings Helmet`, - shirt: garbageShirt() ? $item`makeshift garbage shirt` : have($item`LOV Eardigan`) ? $item`LOV Eardigan` : undefined, + back: + get("questPAGhost") === "unstarted" && get("nextParanormalActivity") <= totalTurnsPlayed() + ? $item`protonic accelerator pack` + : undefined, + shirt: garbageShirt() && !avoidGarbageShirt ? $item`makeshift garbage shirt` : undefined, offhand: myMaxmp() > 200 && myMp() < 75 && restoreMPEfficiently() === "Gulp" ? $item`latte lovers member's mug` - : $item`unbreakable umbrella`, - acc1: have($item`codpiece`) ? $item`codpiece` : undefined, - acc2: + : undefined, + acc1: have($item`Cincho de Mayo`) && get("_cinchUsed", 0) < 95 && 100 - get("_cinchUsed", 0) > args.savecinch ? $item`Cincho de Mayo` : undefined, - familiar: - have($familiar`Melodramedary`) && get("camelSpit") < 100 && !have($effect`spit upon`) - ? $familiar`Melodramedary` - : chooseFamiliar(allowAttackingFamiliars), + familiar: chooseFamiliar(allowAttackingFamiliars), famequip: - have($item`dromedary drinking helmet`) && chooseFamiliar() === $familiar`Melodramedary` - ? $item`dromedary drinking helmet` - : have($item`tiny rake`) && - chooseFamiliar() === $familiar`Melodramedary` && - get("_leafMonstersFought", 0) < 5 - ? $item`tiny rake` - : undefined, - modifier: `1 ${primeStat}, 1 ML, 6 ${primeStat} exp, 30 ${primeStat} experience percent, -equip tinsel tights, -equip wad of used tape`, //Update to check prime stat - avoid: [ - ...sugarItemsAboutToBreak(), - ...(avoidDaylightShavingsHelm() ? [$item`Daylight Shavings Helmet`] : []), - ], + have($item`tiny rake`) && get("_leafMonstersFought", 0) < 5 ? $item`tiny rake` : undefined, + modifier: `${stringPrequel} 0.001 familiar experience, -equip tinsel tights, -equip wad of used tape`, + avoid: [...sugarItemsAboutToBreak()], }; } + +export function baseOutfit( + allowAttackingFamiliars = true, + avoidGarbageShirt = false, + medianMonster?: Monster +): OutfitSpec { + const outfit = baseOutfitFirstPass(allowAttackingFamiliars, avoidGarbageShirt, medianMonster); + + if (outfit.familiar === $familiar`Melodramedary`) { + if (have($item`dromedary drinking helmet`)) { + outfit.famequip = $item`dromedary drinking helmet`; + } else { + if (have($item`toy Cupid bow`)) { + outfit.famequip = $item`toy Cupid bow`; + } + } + } + + if (outfit.familiar === $familiar`Shorter-Order Cook`) { + if (have($item`blue plate`)) { + outfit.famequip = $item`blue plate`; + } else { + outfit.famequip = $item`toy Cupid bow`; + } + } + + if ( + outfit.familiar === $familiar`Homemade Robot` || + outfit.familiar === $familiar`Mu` || + outfit.familiar === $familiar`Cornbeefadon` + ) { + outfit.famequip = $item`toy Cupid bow`; + } + + return outfit; +} diff --git a/src/engine/resources.ts b/src/engine/resources.ts new file mode 100644 index 00000000..7d5dfbf4 --- /dev/null +++ b/src/engine/resources.ts @@ -0,0 +1,124 @@ +import { CombatResource as BaseCombatResource, OutfitSpec } from "grimoire-kolmafia"; +import { Effect, getFuel, Item, Skill } from "kolmafia"; +import { $effect, $item, $items, $monster, $skill, get, have } from "libram"; +import { fuelUp } from "../lib"; +import { baseOutfit } from "./outfit"; +import Macro from "../combat"; +import { useCinch } from "../tasks/leveling"; + +export interface Resource { + name: string; + available: () => boolean; + prepare?: () => void; + equip?: Item | OutfitSpec; + effect?: Effect; + chance?: () => number; +} + +export type CombatResource = Resource & BaseCombatResource; + +interface FreekillSource extends CombatResource { + do: Item | Skill; +} + +export const freekillSources: FreekillSource[] = [ + { + name: "Lil' Doctor™ bag", + available: () => have($item`Lil' Doctor™ bag`) && get("_chestXRayUsed") < 3, + do: $skill`Chest X-Ray`, + equip: $item`Lil' Doctor™ bag`, + }, + { + name: "Gingerbread Mob Hit", + available: () => have($skill`Gingerbread Mob Hit`) && !get("_gingerbreadMobHitUsed"), + do: $skill`Gingerbread Mob Hit`, + }, + { + name: "Shattering Punch", + available: () => have($skill`Shattering Punch`) && get("_shatteringPunchUsed") < 3, + do: $skill`Shattering Punch`, + }, + { + name: "Replica bat-oomerang", + available: () => have($item`replica bat-oomerang`) && get("_usedReplicaBatoomerang") < 3, + do: $item`replica bat-oomerang`, + }, + { + name: "The Jokester's gun", + available: () => have($item`The Jokester's gun`) && !get("_firedJokestersGun"), + do: $skill`Fire the Jokester's Gun`, + equip: $item`The Jokester's gun`, + }, + { + name: "Asdon Martin: Missile Launcher", + available: () => !get("_missileLauncherUsed"), + prepare: () => { + if (getFuel() < 100) fuelUp(); + }, + do: $skill`Asdon Martin: Missile Launcher`, + }, + { + name: "Seal Clubbing Club of Legend", + // eslint-disable-next-line libram/verify-constants + available: () => have($item`legendary seal-clubbing club`) && get("_clubEmTimeUsed", 0) < 5, + // eslint-disable-next-line libram/verify-constants + do: $skill`Club 'Em Back in Time`, + // eslint-disable-next-line libram/verify-constants + equip: $item`legendary seal-clubbing club`, + }, + { + name: "Jurassic Parka", + available: () => + have($skill`Torso Awareness`) && + have($item`Jurassic Parka`) && + !have($effect`Everything Looks Yellow`), + equip: { equip: $items`Jurassic Parka`, modes: { parka: "dilophosaur" } }, + do: $skill`Spit jurassic acid`, + }, +]; + +export function freekillsRemaining(): boolean { + return freekillSources.some((src) => src.available()); +} + +export function freekillOutfit(): OutfitSpec { + const base = baseOutfit(true, false, $monster`burnout`); + const outfit: OutfitSpec = { ...base, equip: [...(base.equip ?? [])] }; + + for (const src of freekillSources) { + if (!src.available() || !src.equip) continue; + + const eq = src.equip; + + if (eq instanceof Item) { + outfit.equip!.push(eq); + } else { + mergeOutfitSpec(outfit, eq); + } + } + + return outfit; +} + +function mergeOutfitSpec(base: OutfitSpec, add: OutfitSpec) { + if (add.equip) { + base.equip = [...(base.equip ?? []), ...add.equip]; + } + + if (add.modes) { + base.modes = { ...(base.modes ?? {}), ...add.modes }; + } +} + +export function freekillMacro(): Macro { + let m = Macro.if_($monster`sausage goblin`, Macro.default(useCinch())); + + for (const src of freekillSources) { + if (!src.available()) continue; + + if (src.do instanceof Skill) m = m.trySkill(src.do); + else m = m.tryItem(src.do); + } + + return m.abort(); +} diff --git a/src/lib.ts b/src/lib.ts index 92fe82d4..86c54e27 100644 --- a/src/lib.ts +++ b/src/lib.ts @@ -4,7 +4,9 @@ import { buy, buyUsingStorage, cliExecute, + cliExecuteOutput, create, + daycount, Effect, equip, equippedItem, @@ -60,7 +62,6 @@ import { $stat, AprilingBandHelmet, canRememberSong, - CombatLoversLocket, CommunityService, get, getKramcoWandererChance, @@ -166,6 +167,9 @@ export function sellMiscellaneousItems(): void { }); } +export const mainStatMaximizerStr = + mainStat === $stat`Muscle` ? "mus" : mainStat === $stat`Mysticality` ? "myst" : "mox"; + export function computeHotRes(sim: boolean): number { const cloake = have($item`vampyric cloake`) ? 2 : 0; const retro = RetroCape.have() ? 3 : 0; @@ -175,7 +179,6 @@ export function computeHotRes(sim: boolean): number { have($skill`Double-Fisted Skull Smashing`) ? 30 : 0; - const factory = !args.factoryworker ? 9 : 0; const horse = get("horseryAvailable") ? 1 : 0; const meteor = have($skill`Meteor Shower`) ? 5 : 0; const bird = get("yourFavoriteBirdMods").includes("Hot Resistance") ? 4 : 0; @@ -206,7 +209,6 @@ export function computeHotRes(sim: boolean): number { retro, shield, foam, - factory, horse, meteor, bird, @@ -250,11 +252,14 @@ export function computeWeaponDamage(sim: boolean): number { const cowrupt = 200; //Ungulith/seeing red. Can't be skipped. const imported = have($skill`Map the Monsters`) && get("ownsSpeakeasy") ? 50 : 0; const beach = have($item`Beach Comb`) ? 25 : 0; - const camel = (get("camelSpit") / 3.33) * camelFightsLeft() >= 100 ? 100 : 0; + const camel = + (get("camelSpit") / 3.33) * camelFightsLeft() >= 100 || have($effect`Spit Upon`) ? 100 : 0; const lov = get("loveTunnelAvailable") ? 50 : 0; const vote = myClass() === $class`Pastamancer` && get("voteAlways") ? 200 : 0; const carol = have($familiar`Ghost of Crimbo Carols`) ? 100 : 0; const elf = have($familiar`Machine Elf`) ? 100 : 0; + const billiards = have($item`Clan VIP Lounge key`) ? 50 : 0; + const north = have($skill`Song of the North`) ? 100 : 0; const effects = sumNumbers([ meteor, claws, @@ -279,20 +284,18 @@ export function computeWeaponDamage(sim: boolean): number { vote, carol, elf, + billiards, + north, ]); const hat = have($item`Crown of Thrones`) ? 10 : have($item`seal-skull helmet`) ? 1 : 0; const shirt = 0; - // eslint-disable-next-line libram/verify-constants const mainhand = have($item`candy cane sword cane`) - ? 165 + ? 180 : have($item`SpinMaster™ lathe`) ? 115 : 65; - // eslint-disable-next-line libram/verify-constants - const offhand = - // eslint-disable-next-line libram/verify-constants - have($item`SpinMaster™ lathe`) && have($item`candy cane sword cane`) ? 115 : 50; + const offhand = have($item`SpinMaster™ lathe`) && have($item`candy cane sword cane`) ? 115 : 50; const brogues = have($item`Bastille Battalion control rig`) ? 50 : 0; const glove = have($item`Powerful Glove`) ? 25 : 0; @@ -303,7 +306,6 @@ export function computeWeaponDamage(sim: boolean): number { const familiar = have($familiar`Disembodied Hand`) && - // eslint-disable-next-line libram/verify-constants have($item`candy cane sword cane`) && have($item`Stick-Knife of Loathing`) && have($item`SpinMaster™ lathe`) @@ -344,7 +346,6 @@ export function computeSpellDamage(sim: boolean): number { const moonSpoon = have($item`hewn moon-rune spoon`) ? 10 : 0; const saucier = have($skill`Master Saucier`) ? 10 : 0; const subtle = have($skill`Subtle and Quick to Anger`) ? 10 : 0; - const calzone = !args.calzone ? 50 : 0; const stick = !sim && have($item`Stick-Knife of Loathing`) ? 200 : 0; const staff = !sim && have($item`Staff of Simmering Hatred`) ? 200 : 0; const candle = !sim && have($item`Abracandalabra`) ? 100 : 0; @@ -373,7 +374,6 @@ export function computeSpellDamage(sim: boolean): number { moonSpoon, saucier, subtle, - calzone, candle, ]); @@ -382,7 +382,6 @@ export function computeSpellDamage(sim: boolean): number { export function computeFamiliarWeight(sim: boolean): number { const moonSpoon = have($item`hewn moon-rune spoon`) && !args.savemoontune ? 10 : 0; - const deepDish = args.latedeepdish || !args.deepdish ? 15 : 0; const newsPaper = have($familiar`Garbage Fire`) ? 10 : 0; const meteor = have($skill`Meteor Shower`) && have($item`Fourth of May Cosplay Saber`) ? 20 : 0; const belligerence = have($item`Clan VIP Lounge key`) ? 10 : 0; @@ -423,7 +422,6 @@ export function computeFamiliarWeight(sim: boolean): number { sumNumbers([ moonSpoon, sympathy, - deepDish, newsPaper, meteor, belligerence, @@ -453,7 +451,6 @@ export function computeFamiliarWeight(sim: boolean): number { export function computeBoozeDrop(): number { const loded = have($item`closed-circuit pay phone`) ? 100 : 0; - const eyedrops = !args.savecyclops ? 100 : 0; const bowling = have($item`cosmic bowling ball`) ? 25 : 0; const bat = have($item`vampyric cloake`) ? 50 : 0; const microphone = @@ -484,7 +481,6 @@ export function computeBoozeDrop(): number { const all = sumNumbers([ loded, - eyedrops, bowling, bat, microphone, @@ -518,24 +514,40 @@ export function computeBoozeDrop(): number { const famJacksValue = () => have($familiar`Comma Chameleon`) && !have($skill`Summon Clip Art`) ? 21 : 0; -const greatWolfs = () => Math.min(2, computeWeaponDamage(false) - 1) + 2; +const greatWolfsPartOne = () => + have($item`repaid diaper`) || storageAmount($item`repaid diaper`) > 0 ? 0 : 2; +const greatWolfs = () => Math.min(2, computeWeaponDamage(false) - 1) + greatWolfsPartOne(); const stickKnife = () => myPrimestat() === $stat`muscle` || (myClass() === $class`Pastamancer` && haveSkill($skill`Bind Undead Elbow Macaroni`)) ? Math.min(5, computeWeaponDamage(false) - 1) + 4 : 0; const staff = () => (have($skill`Spirit of Rigatoni`) ? 4 : 0); const tobikoSoda = () => (have($skill`Summon Alice's Army Cards`) ? 0 : 3); const meteorite = () => Math.min(8, computeWeaponDamage(false) - 1) + 4; -const slippers = () => computeCombatFrequency(false) <= -100 ? 1 : 4; -const chlamys = () => computeCombatFrequency(false) <= -100 ? 0 : 3; +const slippers = () => (computeCombatFrequency(false) <= -100 ? 1 : 4); +const chlamys = () => (computeCombatFrequency(false) <= -100 ? 0 : 3); +const fudge = () => { + const weapon = Math.min(2, computeWeaponDamage(false) - 1); + const spell = 2; + return weapon + spell; +}; type valuePull = { item: Item; value: number; }; +/*function bjornValue(): number { + const weaponValue = Math.min(2, computeWeaponDamage(false) - 1); + const spellValue = 0.4; + const itemValue = Math.min(1.6, computeBoozeDrop() - 1); + const nonCombatValue = computeCombatFrequency(false) <= -100 ? 0 : 3; + const famWeight = 1; + return weaponValue + spellValue + itemValue + nonCombatValue + famWeight; +}*/ + export const jacks = - mallPrice($item`box of Familiar Jacks`) < mallPrice($item`yule battery`) + mallPrice($item`box of Familiar Jacks`) < mallPrice($item`overloaded Yule battery`) ? $item`box of Familiar Jacks` - : $item`yule battery`; + : $item`overloaded Yule battery`; export const pullValue: valuePull[] = [ { @@ -552,7 +564,7 @@ export const pullValue: valuePull[] = [ }, { item: $item`Buddy Bjorn`, - value: 6.8, + value: 1.4, }, { item: $item`meteorite necklace`, @@ -578,6 +590,10 @@ export const pullValue: valuePull[] = [ item: $item`Fuzzy Slippers of Hatred`, value: slippers(), }, + { + item: $item`fudge-shaped hole in space-time`, + value: fudge(), + }, ]; export function acquirePulls(item: Item): boolean { @@ -706,7 +722,10 @@ export function logTestSetup(whichTest: CommunityService): void { }).`, "blue" ); - set(`_CSTest${whichTest.id}`, testTurns + (have($effect`Simmering`) ? 1 : 0)); + set( + `_CSTest${whichTest.id}`, + testTurns + (have($effect`Simmering`) && !have($item`April Shower Thoughts shield`) ? 1 : 0) + ); } export function tryAcquiringEffect(ef: Effect, tryRegardless = false): void { @@ -1044,17 +1063,6 @@ export function camelFightsLeft(): number { const XRay = have($item`Lil' Doctor™ bag`) ? 3 - get("_chestXRayUsed") : 0; const shatteringPunch = have($skill`Shattering Punch`) ? 3 - get("_shatteringPunchUsed") : 0; const mobHit = have($skill`Gingerbread Mob Hit`) && !get("_gingerbreadMobHitUsed") ? 1 : 0; - const locketedWitchess = - !Witchess.have() && - CombatLoversLocket.availableLocketMonsters().includes($monster`Witchess King`) && - !CombatLoversLocket.monstersReminisced().includes($monster`Witchess King`) && - !args.witchessking - ? 1 - : 0; - const backups = - Witchess.have() || have($item`Kramco Sausage-o-Matic™`) - ? Math.max(11 - args.savebackups - get("_backUpUses"), 0) - : 0; // No guarantee that we hit a tentacle, so we ignore that here // Currently does not consider gregs (require free banish + free fight source) // Include guaranteed non-free fights @@ -1080,8 +1088,6 @@ export function camelFightsLeft(): number { XRay, shatteringPunch, mobHit, - locketedWitchess, - backups, noveltySkeleton, leafyBoys, cyberRealm, @@ -1182,8 +1188,7 @@ export const generalStoreXpEffect: Effect = { }[mainStatStr]; export function checkLocketAvailable(): number { - const locketAvailable = - (args.redskeleton ? 1 : 0) + (args.witchessking ? 1 : 0) + (args.factoryworker ? 1 : 0); + const locketAvailable = (args.redskeleton ? 1 : 0) + 2; return locketAvailable; } @@ -1440,4 +1445,78 @@ export function checkPurqoise(meat: number): boolean { return true; } +type WardrobeLog = { + date: string; + entries: { + item: string; + modifier: string; + roll: string; + }[]; +}; + +export function parseWardrobeLog(raw: string): WardrobeLog[] { + const logs: WardrobeLog[] = []; + const chunks = raw.split(/(?=\d{4}-\d{2}-\d{2} \d{2}:\d{2})/); + + for (const chunk of chunks) { + const dateMatch = chunk.match(/^\d{4}-\d{2}-\d{2} \d{2}:\d{2}/); + if (!dateMatch) continue; + + const date = dateMatch[0]; + const entries: WardrobeLog["entries"] = []; + + // Match each table row: ... + const rows = [...chunk.matchAll(/(.*?)<\/tr>/gs)]; + + let currentItem = ""; + for (const [, rowHtml] of rows) { + const cols = [...rowHtml.matchAll(/(.*?)<\/td>/gs)].map(([, val]) => + val.replace(/ /g, " ").trim() + ); + + if (cols.length === 3) { + currentItem = cols[0]; + entries.push({ item: currentItem, modifier: cols[1], roll: cols[2] }); + } else if (cols.length === 2) { + entries.push({ item: currentItem, modifier: cols[0], roll: cols[1] }); + } + } + + logs.push({ date, entries }); + } + + return logs; +} + +function meetsCriteria(output: string): boolean { + const parsedData = parseWardrobeLog(output); + print("Parsed Data:", JSON.stringify(parsedData, null, 2)); + + for (const log of parsedData) { + for (const entry of log.entries) { + const { modifier, roll } = entry; + + // Parse roll — handle ranges like "11-26" and plain numbers like "45" + const rangeMatch = roll.match(/^(\d+)-(\d+)$/); + const numericValue = rangeMatch + ? parseInt(rangeMatch[2]) // upper end of range + : parseInt(roll); + + if (modifier.includes("Familiar Experience") && numericValue >= 4) return true; + if (modifier.includes("Meat Drop") && numericValue > 50) return true; + } + } + + return false; +} + +export function wardrobeGood(): boolean { + const baseSeed = daycount(); + const todayT5 = cliExecuteOutput(`wardrobe kolday=${baseSeed} tier 5`); + const tomorrowT5 = cliExecuteOutput(`wardrobe kolday=${baseSeed + 1} tier 5`); + + if (meetsCriteria(todayT5) || meetsCriteria(tomorrowT5)) return true; + return false; +} + export const peridotChoice = (monster: Monster) => ({ 1557: `1&bandersnatch=${monster.id}` }); diff --git a/src/main.ts b/src/main.ts index bab8d573..c86f36d0 100644 --- a/src/main.ts +++ b/src/main.ts @@ -1,5 +1,6 @@ import { cliExecute, + Effect, myAdventures, myAscensions, myPrimestat, @@ -22,7 +23,6 @@ import { Engine } from "./engine/engine"; import { Args, getTasks } from "grimoire-kolmafia"; import { Task } from "./engine/task"; import { HPQuest, MoxieQuest, MuscleQuest, MysticalityQuest } from "./tasks/stat"; -import { earlyLevelingQuest } from "./tasks/earlyleveling"; import { LevelingQuest } from "./tasks/leveling"; import { CoilWireQuest } from "./tasks/coilwire"; import { RunStartQuest } from "./tasks/runstart"; @@ -35,6 +35,7 @@ import { DonateQuest, logResourceUsage } from "./tasks/donate"; import { SpellDamageQuest } from "./tasks/spelldamage"; import { checkRequirements, checkTests, simPulls } from "./sim"; import { args } from "./args"; +import { findTopBusksGreedy } from "./beret"; const timeProperty = "fullday_elapsedTime"; @@ -52,6 +53,10 @@ export function main(command?: string): void { simPulls(); return; } + if (args.test) { + test(); + return; + } if (args.recap) { logResourceUsage(); @@ -86,7 +91,6 @@ export function main(command?: string): void { const tasks: Task[] = getTasks([ RunStartQuest, - earlyLevelingQuest, CoilWireQuest, LevelingQuest, swapMainStatTest ? MoxieQuest : MuscleQuest, @@ -94,10 +98,10 @@ export function main(command?: string): void { swapMainStatTest ? MuscleQuest : MysticalityQuest, swapMainStatTest ? HPQuest : MoxieQuest, HotResQuest, - WeaponDamageQuest, - SpellDamageQuest, swapNCandFamTest() || args.doncfirst ? NoncombatQuest : FamiliarWeightQuest, swapNCandFamTest() || args.doncfirst ? FamiliarWeightQuest : NoncombatQuest, + WeaponDamageQuest, + SpellDamageQuest, BoozeDropQuest, DonateQuest, ]); @@ -138,3 +142,28 @@ export function main(command?: string): void { function runComplete(): boolean { return get("kingLiberated") && get("lastEmptiedStorage") === myAscensions(); } + +function test(): void { + const uselesseffects = Effect.all().filter((e) => have(e)); + + const best = findTopBusksGreedy( + { + "Familiar Weight": 10, + "Spell Damage Percent": 1, + }, + uselesseffects + ); + + best.powers.forEach((power, index) => { + const outfit = best.outfit[index]; + print(`Busk ${index + 1}: Power = ${power}`); + print( + ` - Equipment: Hat = ${outfit.hat?.name ?? "?"}, Shirt = ${ + outfit.shirt?.name ?? "?" + }, Pants = ${outfit.pants?.name ?? "?"}` + ); + print(" "); + }); + + print(`Total score: ${best.score}`); +} diff --git a/src/tasks/boozedrop.ts b/src/tasks/boozedrop.ts index b490b1c8..bb913e65 100644 --- a/src/tasks/boozedrop.ts +++ b/src/tasks/boozedrop.ts @@ -1,17 +1,14 @@ import { Quest } from "../engine/task"; import { - adv1, autosell, buy, cliExecute, create, - drink, Effect, equip, - hermit, - inebrietyLimit, + handlingChoice, itemAmount, - myInebriety, + lastChoice, myMeat, print, retrieveItem, @@ -27,6 +24,7 @@ import { $effect, $familiar, $item, + $items, $location, $skill, $slot, @@ -35,7 +33,7 @@ import { get, getKramcoWandererChance, have, - uneffect, + MayamCalendar, unequip, withChoice, } from "libram"; @@ -43,29 +41,26 @@ import { checkTurnSave, checkValue, forbiddenEffects, - haveLoathingIdol, + fuelUp, logTestSetup, tryAcquiringEffect, useLoathingIdol, wishFor, } from "../lib"; import { CombatStrategy } from "grimoire-kolmafia"; -import Macro, { haveFreeBanish } from "../combat"; +import Macro from "../combat"; import { drive } from "libram/dist/resources/2017/AsdonMartin"; import { args } from "../args"; -import { chooseFamiliar } from "../engine/outfit"; function wishOrSpleen(): boolean { - if ( - (checkTurnSave("BoozeDrop", $effect`Infernal Thirst`) - - checkTurnSave("BoozeDrop", $effect`Synthesis: Collection`)) * - get("valueOfAdventure", 4000) - - 50000 + - get("valueOfAdventure", 4000) * 2 * get("garbo_embezzlerMultiplier", 2.5) > - 0 - ) - return true; - return false; + const actual = CommunityService.BoozeDrop.actualCost(); + const benefit = actual > 10 ? Math.min(actual - 10, 4) : 0; + const boombox = have($item`SongBoom™ BoomBox`) ? 25 : 0; + const spleen = Math.max(3 * (250 + boombox) * 30, get("valueOfAdventure") * 2.5); + const wish = get("prAlways") + ? (500 + boombox) * 2 * 30 + : 275 * 2 * 30 - benefit * get("valueOfAdventure"); + return wish > spleen; } export const BoozeDropQuest: Quest = { @@ -92,27 +87,6 @@ export const BoozeDropQuest: Quest = { do: () => AprilingBandHelmet.conduct($effect`Apriling Band Celebration Bop`), limit: { tries: 1 }, }, - { - name: "Acquire Clover", - completed: () => - have($item`11-leaf clover`) || get("_cloversPurchased") >= 2 || args.savecyclops, - do: (): void => { - buy(1, $item`chewing gum on a string`); - use(1, $item`chewing gum on a string`); - hermit($item`11-leaf clover`, 1); - }, - limit: { tries: 50 }, - }, - { - name: "Get Cyclops Eyedrops", - completed: () => - have($item`cyclops eyedrops`) || have($effect`One Very Clear Eye`) || args.savecyclops, - do: (): void => { - if (!have($effect`Lucky!`)) use($item`11-leaf clover`); - if (!have($item`cyclops eyedrops`)) adv1($location`The Limerick Dungeon`, -1); - }, - limit: { tries: 1 }, - }, { name: "Acquire Government", completed: () => @@ -132,11 +106,10 @@ export const BoozeDropQuest: Quest = { name: "Item Buff", completed: () => !have($item`cosmic bowling ball`) || - !haveFreeBanish() || have($effect`Cosmic Ball in the Air`) || have($effect`Bat-Adjacent Form`), - do: $location`The Dire Warren`, - combat: new CombatStrategy().macro(Macro.itemDrop().abort()), + do: $location`The Neverending Party`, + combat: new CombatStrategy().macro(Macro.itemDrop()), outfit: { back: $item`vampyric cloake`, offhand: @@ -145,24 +118,10 @@ export const BoozeDropQuest: Quest = { : $item`latte lovers member's mug`, acc1: $item`Kremlin's Greatest Briefcase`, acc2: $item`Lil' Doctor™ bag`, - familiar: chooseFamiliar(false), - }, - limit: { tries: 1 }, - }, - { - name: "Drink Sacramento Wine", - completed: () => - have($effect`Sacré Mental`) || - !have($item`Sacramento wine`) || - myInebriety() >= inebrietyLimit() || - args.sacramentowine, - do: (): void => { - if (myInebriety() < inebrietyLimit()) { - tryAcquiringEffect($effect`Ode to Booze`); - drink($item`Sacramento wine`, 1); - uneffect($effect`Ode to Booze`); - } + acc3: $item`spring shoes`, + familiar: $familiar`Pair of Stomping Boots`, }, + post: () => useFamiliar($familiar`Left-Hand Man`), limit: { tries: 1 }, }, { @@ -185,27 +144,14 @@ export const BoozeDropQuest: Quest = { completed: () => have($effect`Spitting Rhymes`) || !have($item`2002 Mr. Store Catalog`) || - forbiddenEffects.includes($effect`Spitting Rhymes`), + forbiddenEffects.includes($effect`Spitting Rhymes`) || + get("availableMrStore2002Credits") === 0, do: (): void => { - if (!haveLoathingIdol) { - buy($coinmaster`Mr. Store 2002`, 1, $item`Loathing Idol Microphone`); - } + buy($coinmaster`Mr. Store 2002`, 1, $item`Loathing Idol Microphone`); withChoice(1505, 3, () => useLoathingIdol()); }, limit: { tries: 1 }, }, - { - name: "Red-soled high heels", - ready: () => checkValue("2002", 3), - completed: () => have($item`red-soled high heels`) || !have($item`2002 Mr. Store Catalog`), - do: (): void => { - if (!have($item`Letter from Carrie Bradshaw`)) { - buy($coinmaster`Mr. Store 2002`, 1, $item`Letter from Carrie Bradshaw`); - } - withChoice(1506, 3, () => use($item`Letter from Carrie Bradshaw`)); - }, - limit: { tries: 1 }, - }, { name: "Favorite Bird (Item)", completed: () => @@ -222,13 +168,6 @@ export const BoozeDropQuest: Quest = { do: () => buy($item`oversized sparkler`, 1), limit: { tries: 1 }, }, - /* { - name: "Yams Item Drop", - ready: () => have($item`Mayam Calendar`), - completed: () => ["yam4", "explosion", "clock"].every((sym) => get("_mayamSymbolsUsed").includes(sym)) || get("_mayamSymbolsUsed").includes("eye"), - do: () => Mayam(stuff), - limit: { tries: 1 }, - }, */ { name: "Feeling Lost", completed: () => have($effect`Feeling Lost`) || !have($skill`Feel Lost`), @@ -237,7 +176,6 @@ export const BoozeDropQuest: Quest = { }, { name: "Contemplate Sauce", - ready: () => have($item`April Shower Thoughts shield`), prepare: () => equip($item`April Shower Thoughts shield`), completed: () => have($effect`Lubricating Sauce`), do: () => useSkill($skill`Sauce Contemplation`), @@ -249,10 +187,33 @@ export const BoozeDropQuest: Quest = { ready: () => args.asdon, completed: () => have($effect`Driving Observantly`), do: (): void => { + fuelUp(); drive($effect`Driving Observantly`); }, limit: { tries: 3 }, }, + { + name: "Mayam", + ready: () => MayamCalendar.have(), + completed: () => have($effect`Big Eyes`), + do: (): void => { + MayamCalendar.submit("eye meat eyepatch explosion"); + }, + limit: { tries: 1 }, + }, + { + name: "Radio", + ready: () => have($item`Allied Radio Backpack`) && get("_alliedRadioDropsUsed", 0) < 3, + // eslint-disable-next-line libram/verify-constants + completed: () => have($effect`Materiel intel`), + do: () => { + const visitRadio = () => visitUrl(`inventory.php?action=requestdrop&pwd`); + visitRadio(); + if (!handlingChoice() || lastChoice() !== 1563) visitRadio(); + runChoice(1, `request=materiel intel`); + }, + limit: { tries: 1 }, + }, { name: "Test", prepare: (): void => { @@ -281,21 +242,16 @@ export const BoozeDropQuest: Quest = { equip($slot`familiar`, $item`li'l ninja costume`); } - if ( - !wishOrSpleen() && - checkValue("Spleen", checkTurnSave("BoozeDrop", $effect`Synthesis: Collection`)) && - ((have($item`sugar shank`) && get("tomeSummons") <= 2) || get("tomeSummons") <= 1) && - have($skill`Summon Sugar Sheets`) - ) { - if (!have($item`sugar sheet`)) useSkill($skill`Summon Sugar Sheets`, 1); - if (!have($item`sugar shank`)) create($item`sugar shank`); - if (!have($item`sugar sheet`)) useSkill($skill`Summon Sugar Sheets`, 1); - sweetSynthesis($item`sugar shank`, $item`sugar sheet`); - } - - if (checkTurnSave("BoozeDrop", $effect`Incredibly Well Lit`) > 1) + if (CommunityService.BoozeDrop.actualCost() > 1) tryAcquiringEffect($effect`Incredibly Well Lit`); + if (CommunityService.BoozeDrop.actualCost() > 1) { + if (!have($item`Letter from Carrie Bradshaw`)) { + buy($coinmaster`Mr. Store 2002`, 1, $item`Letter from Carrie Bradshaw`); + } + withChoice(1506, 3, () => use($item`Letter from Carrie Bradshaw`)); + } + if ( checkValue($item`battery (lantern)`, checkTurnSave("BoozeDrop", $effect`Lantern-Charged`)) ) { @@ -310,8 +266,20 @@ export const BoozeDropQuest: Quest = { ) cliExecute("cheat fortune"); - if (checkValue($item`pocket wish`, checkTurnSave("BoozeDrop", $effect`Infernal Thirst`))) - wishFor($effect`Infernal Thirst`); + if (CommunityService.BoozeDrop.actualCost() > 1) { + if ( + wishOrSpleen() && + ((have($item`sugar shank`) && get("tomeSummons") <= 2) || get("tomeSummons") <= 1) && + have($skill`Summon Sugar Sheets`) + ) { + if (!have($item`sugar sheet`)) useSkill($skill`Summon Sugar Sheets`, 1); + if (!have($item`sugar shank`)) create($item`sugar shank`); + if (!have($item`sugar sheet`)) useSkill($skill`Summon Sugar Sheets`, 1); + sweetSynthesis($item`sugar shank`, $item`sugar sheet`); + } + } + + if (CommunityService.BoozeDrop.actualCost() > 4) wishFor($effect`Infernal Thirst`); }, completed: () => CommunityService.BoozeDrop.isDone(), do: (): void => { @@ -326,8 +294,9 @@ export const BoozeDropQuest: Quest = { CommunityService.BoozeDrop.run(() => logTestSetup(CommunityService.BoozeDrop), maxTurns); }, outfit: { + avoid: $items`surprisingly capacious handbag`, modifier: - "1 Item Drop, 2 Booze Drop, -equip broken champagne bottle, switch disembodied hand, -switch left-hand man", + "1 Item Drop, 2 Booze Drop, -equip broken champagne bottle, switch disembodied hand, switch left-hand man", }, limit: { tries: 1 }, }, diff --git a/src/tasks/earlyleveling.ts b/src/tasks/earlyleveling.ts deleted file mode 100644 index a48d9405..00000000 --- a/src/tasks/earlyleveling.ts +++ /dev/null @@ -1,496 +0,0 @@ -import { Quest } from "../engine/task"; -import { - abort, - autosell, - buy, - cliExecute, - eat, - equip, - getMonsters, - getWorkshed, - haveEquipped, - itemDrops, - Location, - mallPrice, - myAdventures, - myClass, - myLevel, - myMaxhp, - myMeat, - myPrimestat, - print, - restoreHp, - restoreMp, - storageAmount, - takeStorage, - toInt, - toItem, - use, - visitUrl, -} from "kolmafia"; -import { - $class, - $effect, - $familiar, - $item, - $location, - $monster, - $skill, - $slot, - AutumnAton, - clamp, - CombatLoversLocket, - CommunityService, - get, - getKramcoWandererChance, - have, - sum, - TrainSet, -} from "libram"; -import { CombatStrategy } from "grimoire-kolmafia"; -import { baseOutfit, docBag, unbreakableUmbrella } from "../engine/outfit"; -import { Cycle, setConfiguration, Station } from "libram/dist/resources/2022/TrainSet"; -import Macro from "../combat"; -import { mapMonster } from "libram/dist/resources/2020/Cartography"; -import { chooseRift } from "libram/dist/resources/2023/ClosedCircuitPayphone"; -import { boomBoxProfit, checkPurqoise, sellMiscellaneousItems } from "../lib"; -import { args } from "../args"; - -const useParkaSpit = have($item`Fourth of May Cosplay Saber`) && have($skill`Feel Envy`); - -let _bestShadowRift: Location | null = null; -export function bestShadowRift(): Location { - if (!_bestShadowRift) { - _bestShadowRift = - chooseRift({ - canAdventure: true, - sortBy: (l: Location) => { - const drops = getMonsters(l) - .map((m) => - [ - ...Object.keys(itemDrops(m)).map((s) => toItem(s)), - m === $monster`shadow guy` && - have($skill`Just the Facts`) && - myClass() === $class`Pastamancer` - ? $item`pocket wish` - : m === $monster`shadow spider` && - have($skill`Just the Facts`) && - myClass() === $class`Accordion Thief` - ? $item`pocket wish` - : $item.none, - ].filter((i) => i !== $item.none) - ) - .reduce((acc, val) => acc.concat(val), []); - return sum(drops, mallPrice); - }, - }) ?? $location.none; - if (_bestShadowRift === $location.none && have($item`closed-circuit pay phone`)) { - throw new Error("Failed to find a suitable Shadow Rift to adventure in"); - } - } - return _bestShadowRift; -} - -function sendAutumnaton(): void { - if (AutumnAton.availableLocations().includes(bestShadowRift()) && have($item`autumn-aton`)) - AutumnAton.sendTo(bestShadowRift()); -} - -export const earlyLevelingQuest: Quest = { - name: "Early Leveling", - completed: () => - get("pizzaOfLegendEaten") || - !args.skipbt || - args.asdon || - CommunityService.CoilWire.isDone() || - myAdventures() > 60, - tasks: [ - { - name: "Scavenge", - completed: () => get("_daycareGymScavenges") > 0 || !get("daycareOpen"), - prepare: (): void => { - cliExecute(`maximize ${myPrimestat()} experience percent`); - }, - do: (): void => { - cliExecute("daycare scavenge free"); - }, - limit: { tries: 1 }, - }, - { - name: "Install Trainset", - completed: () => !have($item`model train set`) || getWorkshed() === $item`model train set`, - do: (): void => { - use($item`model train set`); - visitUrl("campground.php?action=workshed"); - visitUrl("main.php"); - }, - limit: { tries: 1 }, - }, - { - name: "Configure Trainset Early", - completed: () => get("_folgerInitialConfig", false), - do: (): void => { - const offset = get("trainsetPosition") % 8; - const newStations: TrainSet.Station[] = []; - const statStation: Station = { - Muscle: Station.BRAWN_SILO, - Mysticality: Station.BRAIN_SILO, - Moxie: Station.GROIN_SILO, - }[myPrimestat().toString()]; - const stations = [ - Station.COAL_HOPPER, // double mainstat gain - statStation, // main stats - Station.VIEWING_PLATFORM, // all stats - Station.GAIN_MEAT, // meat - Station.TOWER_FIZZY, // mp regen - Station.TOWER_SEWAGE, // cold res - Station.WATER_BRIDGE, // +ML - Station.CANDY_FACTORY, // candies - ] as Cycle; - for (let i = 0; i < 8; i++) { - const newPos = (i + offset) % 8; - newStations[newPos] = stations[i]; - } - visitUrl("campground.php?action=workshed"); - visitUrl("main.php"); - setConfiguration(newStations as Cycle); - cliExecute("set _folgerInitialConfig = true"); - }, - limit: { tries: 2 }, - }, - { - name: "Ghost", - completed: () => get("questPAGhost") === "unstarted", - ready: () => - have($item`protonic accelerator pack`) && - get("questPAGhost") !== "unstarted" && - !!get("ghostLocation") && - !have($effect`Meteor Showered`), - do: () => get("ghostLocation") ?? abort("Failed to identify ghost location"), - combat: new CombatStrategy().macro( - Macro.trySkill($skill`micrometeorite`) - .trySkill($skill`Shoot Ghost`) - .trySkill($skill`Shoot Ghost`) - .trySkill($skill`Shoot Ghost`) - .trySkill($skill`Trap Ghost`) - ), - outfit: () => ({ - ...baseOutfit, - back: $item`protonic accelerator pack` - }), - }, - { - name: "Red Skeleton, Tropical Skeleton, Two For One", - after: ["Configure Trainset Early"], - ready: () => - !have($effect`Everything Looks Yellow`) || - (have($skill`Feel Envy`) && get("_feelEnvyUsed") < 3) || - (have($skill`Feel Nostalgic`) && get("_feelNostalgicUsed") < 3), - prepare: (): void => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - restoreMp(50); - if (checkPurqoise(250)) autosell($item`porquoise`, 1); - if (!have($item`red rocket`) && !have($effect`Everything Looks Red`)) { - if (myMeat() < 250) throw new Error("Insufficient Meat to purchase red rocket!"); - buy($item`red rocket`, 1); - } - unbreakableUmbrella(); - }, - completed: () => - CombatLoversLocket.monstersReminisced().includes($monster`red skeleton`) || - !CombatLoversLocket.availableLocketMonsters().includes($monster`red skeleton`) || - args.redskeleton, - do: () => CombatLoversLocket.reminisce($monster`red skeleton`), - combat: new CombatStrategy().macro( - Macro.trySkill($skill`Spring Away`) - .trySkill($skill`Snokebomb`) - .trySkill($skill`Reflex Hammer`) - .trySkill($skill`Chest X-Ray`) - .trySkill($skill`Gingerbread Mob Hit`) - .trySkill($skill`Shattering Punch`) - .default() - ), - outfit: () => ({ - ...baseOutfit(false), - shirt: have($item`Jurassic Parka`) ? $item`Jurassic Parka` : undefined, - familiar: have($familiar`Melodramedary`) ? $familiar`Melodramedary` : undefined, - acc3: have($item`Spring Shoes`) ? $item`Spring Shoes` : undefined, - modifier: `${baseOutfit().modifier}, -equip miniature crystal ball`, - }), - limit: { tries: 1 }, - }, - { - name: "Map Novelty Tropical Skeleton", - after: ["Red Skeleton, Tropical Skeleton, Two For One"], - prepare: (): void => { - if (useParkaSpit) { - cliExecute("parka dilophosaur"); - } else if (!have($item`red rocket`) && !have($effect`Everything Looks Yellow`)) { - if (myMeat() < 250) throw new Error("Insufficient Meat to purchase red rocket!"); - buy($item`red rocket`, 1); - } - unbreakableUmbrella(); - if (haveEquipped($item`miniature crystal ball`)) equip($slot`familiar`, $item.none); - }, - completed: () => - !have($skill`Map the Monsters`) || get("_monstersMapped") >= 3 || have($item`cherry`), - do: () => mapMonster($location`The Skeleton Store`, $monster`novelty tropical skeleton`), - combat: new CombatStrategy().macro( - Macro.trySkill($skill`Feel Nostalgic`) - .tryItem($item`red rocket`) - .trySkill($skill`Spit jurassic acid`) - .abort() - ), - outfit: () => ({ - ...baseOutfit(false), - shirt: have($item`Jurassic Parka`) ? $item`Jurassic Parka` : undefined, - familiar: have($familiar`Melodramedary`) ? $familiar`Melodramedary` : undefined, - acc2: have($item`Lil' Doctor™ bag`) ? $item`Lil' Doctor™ bag` : undefined, - modifier: `${baseOutfit().modifier}, -equip miniature crystal ball`, - }), - post: (): void => { - if (have($item`space blanket`)) autosell($item`space blanket`, 1); - use($item`red box`, 1); - sendAutumnaton(); - sellMiscellaneousItems(); - boomBoxProfit(); - }, - limit: { tries: 1 }, - }, - { - name: "ReConfigure Trainset", - after: ["Map Novelty Tropical Skeleton"], - completed: () => get("_folgerSecondConfig", false), - do: (): void => { - const offset = get("trainsetPosition") % 8; - const newStations: TrainSet.Station[] = []; - const statStation: Station = { - Muscle: Station.BRAWN_SILO, - Mysticality: Station.BRAIN_SILO, - Moxie: Station.GROIN_SILO, - }[myPrimestat().toString()]; - const stations = [ - Station.COAL_HOPPER, // double mainstat gain - statStation, // main stats - Station.VIEWING_PLATFORM, // all stats - Station.GAIN_MEAT, // meat - Station.TOWER_FIZZY, // mp regen - Station.TOWER_SEWAGE, // cold res - Station.WATER_BRIDGE, // +ML - Station.CANDY_FACTORY, // candies - ] as Cycle; - for (let i = 0; i < 8; i++) { - const newPos = (i + offset) % 8; - newStations[newPos] = stations[i]; - } - visitUrl("campground.php?action=workshed"); - visitUrl("main.php"); - setConfiguration(newStations as Cycle); - cliExecute("set _folgerSecondConfig = true"); - }, - limit: { tries: 2 }, - }, - { - name: "Kramco", - after: ["ReConfigure Trainset"], - prepare: (): void => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - restoreMp(50); - }, - ready: () => getKramcoWandererChance() >= 1.0, - completed: () => getKramcoWandererChance() < 1.0 || !have($item`Kramco Sausage-o-Matic™`), - do: $location`Noob Cave`, - outfit: () => ({ - ...baseOutfit(), - offhand: $item`Kramco Sausage-o-Matic™`, - }), - combat: new CombatStrategy().macro(Macro.default()), - }, - { - name: "Map Pocket Wishes", - after: ["Kramco"], - prepare: (): void => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - restoreMp(30); - unbreakableUmbrella(); - docBag(); - restoreMp(50); - if (!have($effect`Everything Looks Red`) && !have($item`red rocket`)) { - if (myMeat() >= 250) buy($item`red rocket`, 1); - } - }, - ready: () => myLevel() < 5, - completed: () => - !have($skill`Map the Monsters`) || - !have($skill`Just the Facts`) || - get("_monstersMapped") >= 3 || - have($item`pocket wish`, 1) || - myClass() !== $class`Seal Clubber` || - ((get("_shatteringPunchUsed") >= 3 || !have($skill`Shattering Punch`)) && - (get("_gingerbreadMobHitUsed") || !have($skill`Gingerbread Mob Hit`))), - do: () => mapMonster($location`The Haunted Kitchen`, $monster`paper towelgeist`), - combat: new CombatStrategy().macro( - Macro.if_( - $monster`paper towelgeist`, - Macro.tryItem($item`red rocket`) - .trySkill($skill`Chest X-Ray`) - .trySkill($skill`Gingerbread Mob Hit`) - .trySkill($skill`Shattering Punch`) - .default() - ).abort() - ), - outfit: () => ({ - ...baseOutfit, - offhand: $item`unbreakable umbrella`, - acc2: have($item`Lil' Doctor™ bag`) ? $item`Lil' Doctor™ bag` : undefined, - }), - post: (): void => { - sellMiscellaneousItems(); - boomBoxProfit(); - }, - limit: { tries: 1 }, - }, - { - name: "Bakery Pledge", - after: ["Map Pocket Wishes"], - prepare: (): void => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - restoreMp(50); - docBag(); - restoreMp(50); - }, - ready: () => !get("snojoAvailable", false), - completed: () => - have($effect`Citizen of a Zone`) || - !have($familiar`Patriotic Eagle`) || - get("_citizenZone").includes("Madness Bakery") || - get("_pledgeCheck", false), - do: $location`Madness Bakery`, - combat: new CombatStrategy().macro( - Macro.trySkill($skill`%fn, let's pledge allegiance to a Zone`) - .trySkill($skill`Snokebomb`) - .trySkill($skill`Reflex Hammer`) - .trySkill($skill`Chest X-Ray`) - .trySkill($skill`Gingerbread Mob Hit`) - .trySkill($skill`Shattering Punch`) - .default() - ), - outfit: () => ({ - ...baseOutfit, - familiar: $familiar`Patriotic Eagle`, - acc2: have($item`Lil' Doctor™ bag`) ? $item`Lil' Doctor™ bag` : undefined, - }), - post: (): void => { - sellMiscellaneousItems(); - cliExecute("set _pledgeCheck = true"); - boomBoxProfit(); - }, - limit: { tries: 2 }, - }, - { - name: "Bastille", - after: ["Bakery Pledge"], - ready: () => myLevel() < 5, - prepare: (): void => { - cliExecute(`maximize ${myPrimestat()} experience percent`); - }, - completed: () => get("_bastilleGames") > 0 || !have($item`Bastille Battalion control rig`), - do: (): void => { - if (have($item`familiar scrapbook`)) { - equip($item`familiar scrapbook`); - } - cliExecute("bastille.ash mainstat brutalist"); - }, - limit: { tries: 1 }, - }, - { - name: "Whetstone", - after: ["Bakery Pledge"], - completed: () => !have($item`whet stone`), - do: (): void => { - use($item`whet stone`); - }, - limit: { tries: 1 }, - }, - { - name: "Pull Pizza of Legend", - after: ["Bakery Pledge"], - completed: () => - have($item`Pizza of Legend`) || - have($effect`Endless Drool`) || - get("_roninStoragePulls") - .split(",") - .includes(toInt($item`Pizza of Legend`).toString()) || - args.pizza, - do: (): void => { - if (storageAmount($item`Pizza of Legend`) === 0) { - print("Uh oh! You do not seem to have a Pizza of Legend in Hagnk's", "red"); - print("Consider pulling something to make up for the turngen and 300%mox,", "red"); - print( - "then type 'set _instant_skipPizzaOfLegend=true' before re-running instantsccs", - "red" - ); - } - takeStorage($item`Pizza of Legend`, 1); - }, - limit: { tries: 1 }, - }, - { - name: "Eat Pizza", - ready: () => have($effect`Ready to Eat`), // only eat this after we red rocket - completed: () => - get("pizzaOfLegendEaten") || - !have($item`Pizza of Legend`) || - myAdventures() > 60 || - args.pizza, - prepare: (): void => { - cliExecute(`maximize ${myPrimestat()} experience percent`); - }, - do: (): void => { - if (have($item`familiar scrapbook`)) { - equip($item`familiar scrapbook`); - } - eat($item`Pizza of Legend`, 1); - }, - limit: { tries: 1 }, - }, - { - name: "Pull Calzone of Legend", - after: ["Eat Pizza"], - completed: () => - have($item`Calzone of Legend`) || - have($effect`In the 'zone zone!`) || - get("_roninStoragePulls") - .split(",") - .includes(toInt($item`Calzone of Legend`).toString()) || - args.calzone, - do: (): void => { - if (storageAmount($item`Calzone of Legend`) === 0) { - print("Uh oh! You do not seem to have a Calzone of Legend in Hagnk's", "red"); - print( - "Consider pulling something to make up for the turngen and 300%myst (e.g. a roasted vegetable focaccia),", - "red" - ); - } - takeStorage($item`Calzone of Legend`, 1); - }, - limit: { tries: 1 }, - }, - { - name: "Eat Calzone", - after: ["Eat Pizza"], - prepare: (): void => { - cliExecute(`maximize ${myPrimestat()} experience percent`); - }, - completed: () => - get("calzoneOfLegendEaten") || !have($item`Calzone of Legend`) || myAdventures() > 60, - do: (): void => { - if (have($item`familiar scrapbook`)) { - equip($item`familiar scrapbook`); - } - eat($item`Calzone of Legend`, 1); - }, - limit: { tries: 1 }, - }, - ], -}; diff --git a/src/tasks/familiarweight.ts b/src/tasks/familiarweight.ts index 1a8471ad..1c52e1a6 100644 --- a/src/tasks/familiarweight.ts +++ b/src/tasks/familiarweight.ts @@ -7,11 +7,14 @@ import { Effect, equip, haveEffect, + Item, itemAmount, myClass, mySign, print, toInt, + toItem, + toSlot, use, useFamiliar, useSkill, @@ -34,13 +37,9 @@ import { import { Quest } from "../engine/task"; import { checkValue, logTestSetup, shrugAT, tryAcquiringEffect } from "../lib"; import Macro from "../combat"; -import { - avoidDaylightShavingsHelm, - chooseFamiliar, - chooseHeaviestFamiliar, - sugarItemsAboutToBreak, -} from "../engine/outfit"; +import { chooseFamiliar, chooseHeaviestFamiliar, sugarItemsAboutToBreak } from "../engine/outfit"; import { args } from "../args"; +import { buskAt } from "../beret"; export const FamiliarWeightQuest: Quest = { name: "Familiar Weight", @@ -59,7 +58,6 @@ export const FamiliarWeightQuest: Quest = { }, { name: "Late Eat Deep Dish", - ready: () => args.latedeepdish, completed: () => get("deepDishOfLegendEaten") || !have($item`Deep Dish of Legend`), do: (): void => { if (have($item`familiar scrapbook`)) { @@ -92,7 +90,7 @@ export const FamiliarWeightQuest: Quest = { completed: () => have($effect`Party Soundtrack`) || !have($skill`Cincho: Party Soundtrack`) || - 100 - get("_cinchUsed") < 75, + get("_cinchUsed") > 75, do: (): void => { equip($slot`acc3`, $item`Cincho de Mayo`); useSkill($skill`Cincho: Party Soundtrack`); @@ -115,19 +113,14 @@ export const FamiliarWeightQuest: Quest = { outfit: () => ({ weapon: $item`Fourth of May Cosplay Saber`, familiar: chooseFamiliar(false), - avoid: [ - ...sugarItemsAboutToBreak(), - ...(avoidDaylightShavingsHelm() ? [$item`Daylight Shavings Helmet`] : []), - ], + avoid: [...sugarItemsAboutToBreak()], }), choices: { 1387: 3 }, limit: { tries: 1 }, }, { name: "Better Empathy", - ready: () => have($item`April Shower Thoughts shield`), - completed: () => - have($effect`Thoughtful Empathy`), + completed: () => have($effect`Thoughtful Empathy`), do: () => { unequip($item`April Shower Thoughts shield`); useSkill($skill`Empathy of the Newt`); @@ -137,6 +130,23 @@ export const FamiliarWeightQuest: Quest = { }, limit: { tries: 1 }, }, + { + name: "Beret? Beret.", + ready: () => have(toItem(11919)), + completed: () => get("_beretBuskingUses", 0) >= 5, + do: () => { + buskAt(825, true); // Alt: 1300 w/ Hammertime + + buskAt(800, true); // Alt: 1260 w/ Hammertime + + buskAt(885, true); // Alt: 1255 w/ Hammertime + + buskAt(765, true); + + buskAt(800, true); + }, + limit: { tries: 1 }, + }, { name: "Test", completed: () => CommunityService.FamiliarWeight.isDone(), @@ -167,9 +177,11 @@ export const FamiliarWeightQuest: Quest = { have($skill`Summon Clip Art`) && $familiars`Comma Chameleon, Homemade Robot`.every((fam) => have(fam)) ) { - if (!have($item`box of Familiar Jacks`)) create($item`box of Familiar Jacks`, 1); - useFamiliar($familiar`Homemade Robot`); - use($item`box of Familiar Jacks`, 1); + if (!have($item`homemade robot gear`)) { + if (!have($item`box of Familiar Jacks`)) create($item`box of Familiar Jacks`, 1); + useFamiliar($familiar`Homemade Robot`); + use($item`box of Familiar Jacks`, 1); + } useFamiliar($familiar`Comma Chameleon`); visitUrl( `inv_equip.php?which=2&action=equip&whichitem=${toInt($item`homemade robot gear`)}&pwd` @@ -194,8 +206,13 @@ export const FamiliarWeightQuest: Quest = { cliExecute("maximize familiar weight"); + const teaPartyHats = Item.all().filter( + (i) => have(i) && toSlot(i) === $slot`hat` && i.name.length === 25 + ); + if (!get("_madTeaParty")) { - if (!have($item`sombrero-mounted sparkler`)) buy($item`sombrero-mounted sparkler`); + if (!have($item`sombrero-mounted sparkler`) && teaPartyHats.length === 0) + buy($item`sombrero-mounted sparkler`); tryAcquiringEffect($effect`You Can Really Taste the Dormouse`); } }, diff --git a/src/tasks/hotres.ts b/src/tasks/hotres.ts index 7b651a1c..206d43a8 100644 --- a/src/tasks/hotres.ts +++ b/src/tasks/hotres.ts @@ -1,28 +1,18 @@ import { CombatStrategy } from "grimoire-kolmafia"; -import { buy, cliExecute, create, Effect, print, useSkill } from "kolmafia"; +import { cliExecute, create, Effect, print, useSkill } from "kolmafia"; import { $effect, $effects, $familiar, $item, $location, - $monster, $skill, - CombatLoversLocket, CommunityService, get, have, } from "libram"; import { Quest } from "../engine/task"; -import { - checkTurnSave, - checkValue, - computeHotRes, - logTestSetup, - tryAcquiringEffect, - wishFor, -} from "../lib"; -import { chooseFamiliar, sugarItemsAboutToBreak } from "../engine/outfit"; +import { checkTurnSave, checkValue, logTestSetup, tryAcquiringEffect, wishFor } from "../lib"; import Macro from "../combat"; import { args } from "../args"; @@ -30,41 +20,6 @@ export const HotResQuest: Quest = { name: "Hot Res", completed: () => CommunityService.HotRes.isDone(), tasks: [ - { - name: "Reminisce Factory Worker (female)", - after: ["Grab Foam Suit"], - prepare: (): void => { - if (!have($item`yellow rocket`) && !have($effect`Everything Looks Yellow`)) - buy($item`yellow rocket`, 1); - }, - completed: () => - CombatLoversLocket.monstersReminisced().includes($monster`factory worker (female)`) || - !CombatLoversLocket.availableLocketMonsters().includes($monster`factory worker (female)`) || - args.factoryworker || - checkValue("Locket", Math.min(14, CommunityService.HotRes.prediction - 1)) || - computeHotRes(false) <= 1, - do: () => CombatLoversLocket.reminisce($monster`factory worker (female)`), - outfit: () => ({ - back: $item`vampyric cloake`, - weapon: $item`Fourth of May Cosplay Saber`, - offhand: have($skill`Double-Fisted Skull Smashing`) - ? $item`industrial fire extinguisher` - : undefined, - familiar: chooseFamiliar(false), - modifier: "Item Drop", - avoid: sugarItemsAboutToBreak(), - }), - choices: { 1387: 3 }, - combat: new CombatStrategy().macro( - Macro.trySkill($skill`Become a Cloud of Mist`) - .trySkill($skill`Fire Extinguisher: Foam Yourself`) - .trySkill($skill`Use the Force`) - .trySkill($skill`Shocking Lick`) - .tryItem($item`yellow rocket`) - .default() - ), - limit: { tries: 1 }, - }, { name: "Grab Foam Suit", completed: () => @@ -110,12 +65,6 @@ export const HotResQuest: Quest = { prepare: (): void => { cliExecute("retrocape vampire hold"); if (get("parkaMode") !== "pterodactyl") cliExecute("parka pterodactyl"); - if ( - get("_kgbClicksUsed") < 22 && - have($item`Kremlin's Greatest Briefcase`) && - !args.savekgb - ) - cliExecute("briefcase e hot"); const usefulEffects: Effect[] = [ $effect`Amazing`, diff --git a/src/tasks/leveling.ts b/src/tasks/leveling.ts index 9c0b8610..33434f51 100644 --- a/src/tasks/leveling.ts +++ b/src/tasks/leveling.ts @@ -21,13 +21,10 @@ import { itemDrops, Location, mallPrice, - Monster, mpCost, myAdventures, myBasestat, myClass, - myHash, - myHp, myInebriety, myLevel, myMaxhp, @@ -49,6 +46,7 @@ import { toItem, toSkill, use, + useFamiliar, useSkill, visitUrl, } from "kolmafia"; @@ -62,19 +60,23 @@ import { $items, $location, $monster, - $monsters, $skill, $slot, $stat, + AprilingBandHelmet, AutumnAton, + CinchoDeMayo, clamp, CombatLoversLocket, ensureEffect, get, - getBanishedMonsters, getKramcoWandererChance, have, Leprecondo, + MayamCalendar, + PeridotOfPeril, + PrismaticBeret, + // set, SongBoom, SourceTerminal, sum, @@ -85,7 +87,7 @@ import { Witchess, withChoice, } from "libram"; -import { CombatStrategy, OutfitSpec } from "grimoire-kolmafia"; +import { CombatStrategy } from "grimoire-kolmafia"; import { acquirePulls, boomBoxProfit, @@ -95,18 +97,15 @@ import { checkPull, checkPurqoise, checkValue, - chooseLibram, + //chooseLibram, computeCombatFrequency, - computeHotRes, - computeWeaponDamage, findMaxPull, forbiddenEffects, - fuelUp, generalStoreXpEffect, getSynthExpBuff, getValidComplexCandyPairs, jacks, - overlevelled, + mainStatMaximizerStr, peridotChoice, reagentBalancerEffect, reagentBalancerIngredient, @@ -118,26 +117,17 @@ import { sellMiscellaneousItems, statToMaximizerString, synthExpBuff, - targetBaseMyst, - targetBaseMystGap, tryAcquiringEffect, useOffhandRemarkable, } from "../lib"; -import { - baseOutfit, - chooseFamiliar, - docBag, - garbageShirt, - unbreakableUmbrella, -} from "../engine/outfit"; -import Macro, { haveFreeBanish, haveFreeKill } from "../combat"; +import { baseOutfit, garbageShirt, unbreakableUmbrella } from "../engine/outfit"; +import Macro, { haveFreeKill } from "../combat"; import { mapMonster } from "libram/dist/resources/2020/Cartography"; import { chooseQuest, chooseRift, rufusTarget, } from "libram/dist/resources/2023/ClosedCircuitPayphone"; -import { drive } from "libram/dist/resources/2017/AsdonMartin"; import { cheatCard, getRemainingCheats } from "libram/dist/resources/2015/DeckOfEveryCard"; import { args } from "../args"; import { @@ -146,14 +136,10 @@ import { setConfiguration, Station, } from "libram/dist/resources/2022/TrainSet"; +import { freekillMacro, freekillOutfit, freekillsRemaining } from "../engine/resources"; -const primeStat = statToMaximizerString(myPrimestat()); - -const useCinch = () => args.savecinch < 100 - get("_cinchUsed"); -const baseBoozes = $items`bottle of rum, boxed wine, bottle of gin, bottle of vodka, bottle of tequila, bottle of whiskey`; -const freeFightMonsters: Monster[] = $monsters`Witchess Bishop, Witchess King, Witchess Witch, sausage goblin, Eldritch Tentacle`; +export const useCinch = () => get("_cinchUsed") <= 75; const godLobsterChoice = () => (have($item`God Lobster's Ring`) ? 2 : 3); -const godLobsterSave = () => computeCombatFrequency(false) === -95; export function restoreMPEfficiently(): string { if (have($item`bat wings`) && get("_batWingsRestUsed", 0) < 11) return "Bat Wings"; @@ -223,9 +209,11 @@ const usefulEffects: Effect[] = [ $effect`substats.enh`, $effect`Broad-Spectrum Vaccine`, $effect`Pyrite Pride`, + $effect`Having a Ball!`, // $effect`Think Win-Lose`, $effect`Confidence of the Votive`, $effect`Song of Bravado`, + $effect`Cold as Nice`, // ML $effect`Pride of the Puffin`, @@ -245,27 +233,6 @@ const usefulEffects: Effect[] = [ // Spell dmg ]; -const prismaticEffects: Effect[] = [ - $effect`Frostbeard`, - $effect`Intimidating Mien`, - $effect`Pyromania`, - $effect`Rotten Memories`, - $effect`Takin' It Greasy`, - $effect`Your Fifteen Minutes`, - $effect`Bendin' Hell`, -]; - -const wdmgEffects: Effect[] = [ - $effect`Carol of the Bulls`, - $effect`Disdain of the War Snapper`, - $effect`Frenzied, Bloody`, - $effect`Jackasses' Symphony of Destruction`, - $effect`Rage of the Reindeer`, - $effect`Scowl of the Auk`, - $effect`Song of the North`, - $effect`Tenacity of the Snapper`, -]; - export function powerlevelingLocation(): Location { if (get("neverendingPartyAlways")) return $location`The Neverending Party`; else if (get("stenchAirportAlways") || get("_stenchAirportToday")) @@ -316,21 +283,33 @@ function sendAutumnaton(): void { AutumnAton.sendTo(bestShadowRift()); } +function prepCommon(hp: boolean = true, mp: boolean = true, effects: boolean = true) { + if (hp) restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); + unbreakableUmbrella(); + garbageShirt(); + if (effects) [...usefulEffects, ...statEffects].forEach((ef) => tryAcquiringEffect(ef)); + if (mp) restoreMp(50); +} + export const LevelingQuest: Quest = { name: "Leveling", completed: () => get("csServicesPerformed").split(",").length > 1 || - (get("_feelPrideUsed", 3) >= 3 && - camelFightsLeft() === 0 && - !haveFreeKill()), + (have($effect`Spit Upon`) && have($item`short stack of pancakes`) && myLevel() >= 20) || + (get("_feelPrideUsed", 3) >= 3 && camelFightsLeft() === 0 && !haveFreeKill()), tasks: [ { name: "Eat Magical Sausages", ready: () => - restoreMPEfficiently() === "Sausage" || restoreMPEfficiently() === "Make Sausage" || myAdventures() < 1, + restoreMPEfficiently() === "Sausage" || + restoreMPEfficiently() === "Make Sausage" || + myAdventures() < 1, completed: () => get("_sausagesMade") >= 23 || - (myMp() >= 75 && restoreMPEfficiently() !== "Sausage" && restoreMPEfficiently() !== "Make Sausage" && myAdventures() > 1), + (myMp() >= 75 && + restoreMPEfficiently() !== "Sausage" && + restoreMPEfficiently() !== "Make Sausage" && + myAdventures() > 1), do: (): void => { if (restoreMPEfficiently() === "Sausage") eat($item`magical sausage`, 1); else { @@ -361,6 +340,49 @@ export const LevelingQuest: Quest = { do: () => cliExecute("crossstreams"), limit: { tries: 1 }, }, + { + name: "Party Soundtrack", + ready: () => have($item`Cincho de Mayo`) && CinchoDeMayo.currentCinch() >= 30, + completed: () => have($effect`Party Soundtrack`), + do: () => useSkill($skill`Cincho: Party Soundtrack`), + limit: { tries: 1 }, + }, + { + name: "Beret? Beret.", + ready: () => + have(toItem(11919)) && have($item`punk rock jacket`) && myBasestat($stat`muscle`) > 100, + completed: () => get("_beretBuskingUses", 0) >= 5, + do: () => { + PrismaticBeret.buskAt(825, true); + PrismaticBeret.buskAt(800, true); + PrismaticBeret.buskAt(885, true); + PrismaticBeret.buskAt(765, true); + PrismaticBeret.buskAt(800, true); + }, + limit: { tries: 1 }, + }, + { + name: "Do the sweats", + ready: () => have($item`blood cubic zirconia`) && myLevel() >= 15, + completed: () => have($effect`Up To 11`), + do: () => { + useSkill($skill`BCZ: Dial it up to 11`); + }, + limit: { tries: 1 }, + }, + { + name: "Leprecondo", + ready: () => Leprecondo.have(), + completed: () => Leprecondo.installedFurniture().includes("sous vide laboratory"), + do: () => + Leprecondo.setFurniture( + "sous vide laboratory", + "couch and flatscreen", + "whiskeybed", + "beer pong table" + ), + limit: { tries: 1 }, + }, { name: "Smile of Lyle", ready: () => have($item`candy cane sword cane`), @@ -449,11 +471,9 @@ export const LevelingQuest: Quest = { }, { name: "Wardrobe-o-matic", - // eslint-disable-next-line libram/verify-constants - ready: () => myLevel() >= 15 && have($item`wardrobe-o-matic`), + ready: () => myLevel() >= 20 && have($item`wardrobe-o-matic`), completed: () => get("_wardrobeUsed", false), do: (): void => { - // eslint-disable-next-line libram/verify-constants use($item`wardrobe-o-matic`); cliExecute("set _wardrobeUsed = true"); }, @@ -467,15 +487,17 @@ export const LevelingQuest: Quest = { }, { name: "Extra Buffs", - ready: () => have($item`April Shower Thoughts shield`), prepare: () => equip($item`April Shower Thoughts shield`), completed: () => have($effect`Thoughtful Empathy`), do: () => { visitUrl("inventory.php?action=shower&pwd"); + visitUrl("shop.php?whichshop=showerthoughts"); + visitUrl("shop.php?whichshop=showerthoughts&action=buyitem&quantity=1&whichrow=1581&pwd"); + use($item`wet paper weights`); useSkill($skill`Disco Aerobics`); useSkill($skill`Patience of the Tortoise`); useSkill($skill`Empathy of the Newt`); - unequip($item`April Shower Thoughts shield`) + unequip($item`April Shower Thoughts shield`); }, limit: { tries: 1 }, }, @@ -489,73 +511,14 @@ export const LevelingQuest: Quest = { do: (): void => getSynthExpBuff(), limit: { tries: 5 }, }, - { - name: "Pull Deep Dish of Legend", - ready: () => !args.deepdish, - completed: () => - checkPull($item`Deep Dish of Legend`) || have($effect`In the Depths`) || args.deepdish, - prepare: (): void => { - cliExecute(`maximize ${myPrimestat()} experience percent`); - }, - do: (): void => { - if (storageAmount($item`Deep Dish of Legend`) === 0) { - print("Uh oh! You do not seem to have a Deep Dish of Legend in Hagnk's", "red"); - print("Consider pulling something to make up for the turngen and 300%mus,", "red"); - print( - "then type 'set instant_skipDeepDishOfLegend=true' before re-running instantsccs", - "red" - ); - } - takeStorage($item`Deep Dish of Legend`, 1); - }, - limit: { tries: 1 }, - }, - { - name: "Pull Calzone of Legend", - completed: () => - checkPull($item`Calzone of Legend`) || have($effect`In the 'zone zone!`) || args.calzone, - prepare: (): void => { - cliExecute(`maximize ${myPrimestat()} experience percent`); - }, - do: (): void => { - if (storageAmount($item`Calzone of Legend`) === 0) { - print("Uh oh! You do not seem to have a Calzone of Legend in Hagnk's", "red"); - print( - "Consider pulling something to make up for the turngen and 300%myst (e.g. a roasted vegetable focaccia),", - "red" - ); - print( - "then type 'set instant_skipCalzoneOfLegend=true' before re-running instantsccs", - "red" - ); - } - takeStorage($item`Calzone of Legend`, 1); - }, - limit: { tries: 1 }, - }, - { - name: "Pull Pizza of Legend", - completed: () => - checkPull($item`Pizza of Legend`) || have($effect`Endless Drool`) || args.pizza, - do: (): void => { - if (storageAmount($item`Pizza of Legend`) === 0) { - print("Uh oh! You do not seem to have a Pizza of Legend in Hagnk's", "red"); - print("Consider pulling something to make up for the turngen and 300%mox,", "red"); - print( - "then type 'set instant_skipPizzaOfLegend=true' before re-running instantsccs", - "red" - ); - } - takeStorage($item`Pizza of Legend`, 1); - }, - limit: { tries: 1 }, - }, { name: "Pull Some Everything", ready: () => args.dopullstest, prepare: () => - $items`tobiko marble soda, ${jacks.name}`.forEach((item) => acquirePulls(item)), - completed: () => 5 - get("_roninStoragePulls").split(",").length <= args.savepulls || get("_roninStoragePulls").split(",").length >= 5, + $items`tobiko marble soda, fudge-shaped hole in space-time, ${jacks.name}`.forEach((item) => + acquirePulls(item) + ), + completed: () => 5 - get("_roninStoragePulls").split(",").length <= args.savepulls, do: (): void => { let i = 5 - args.savepulls - get("_roninStoragePulls").split(",").length; while (i < 5) { @@ -720,6 +683,20 @@ export const LevelingQuest: Quest = { do: () => cliExecute("bastille.ash mainstat brutalist"), limit: { tries: 1 }, }, + { + name: "Punk Rock Giant Spit", + completed: () => have($effect`Everything Looks Yellow`) || have($item`punk rock jacket`), + do: (): void => { + CombatLoversLocket.reminisce($monster`Punk Rock Giant`); + }, + outfit: () => ({ + ...baseOutfit(), + shirt: $item`Jurassic Parka`, + modes: { parka: "dilophosaur" }, + }), + combat: new CombatStrategy().macro(Macro.trySkill($skill`Spit jurassic acid`).abort()), + limit: { tries: 1 }, + }, { name: "Restore mp", completed: () => get("timesRested") >= args.saverests || myMp() >= Math.min(50, myMaxmp()), @@ -731,6 +708,7 @@ export const LevelingQuest: Quest = { if (myMeat() >= 2000) { restoreMp(50); } + useFamiliar($familiar`Skeleton of Crimbo Past`); if (get("chateauAvailable")) { visitUrl("place.php?whichplace=chateau&action=chateau_restbox"); } else if (get("getawayCampsiteUnlocked")) { @@ -767,8 +745,7 @@ export const LevelingQuest: Quest = { }, { name: "Eat Deep Dish", - completed: () => - get("deepDishOfLegendEaten") || !have($item`Deep Dish of Legend`) || args.latedeepdish, + completed: () => get("deepDishOfLegendEaten") || !have($item`Deep Dish of Legend`), prepare: (): void => { cliExecute(`maximize ${myPrimestat()} experience percent`); }, @@ -801,57 +778,6 @@ export const LevelingQuest: Quest = { do: () => useSkill($skill`Prevent Scurvy and Sobriety`), limit: { tries: 1 }, }, - { - name: "Cast Perfect Freeze", - completed: () => - !have($skill`Perfect Freeze`) || get("_perfectFreezeUsed") || args.perfectfreeze, - prepare: () => restoreMp(mpCost($skill`Perfect Freeze`)), - do: () => useSkill($skill`Perfect Freeze`), - limit: { tries: 1 }, - }, - { - name: "Drink Perfect Drink", - completed: () => - myInebriety() >= 3 || - !have($item`perfect ice cube`) || - !baseBoozes.some((it) => have(it)) || - args.perfectfreeze, - prepare: (): void => { - cliExecute(`maximize ${myPrimestat()} experience percent`); - }, - do: (): void => { - tryAcquiringEffect($effect`Ode to Booze`); - const baseBooze = baseBoozes.filter((it) => have(it))[0]; - let booze; - switch (baseBooze) { - case $item`bottle of vodka`: - booze = $item`perfect cosmopolitan`; - break; - case $item`bottle of whiskey`: - booze = $item`perfect old-fashioned`; - break; - case $item`boxed wine`: - booze = $item`perfect mimosa`; - break; - case $item`bottle of rum`: - booze = $item`perfect dark and stormy`; - break; - case $item`bottle of tequila`: - booze = $item`perfect paloma`; - break; - case $item`bottle of gin`: - booze = $item`perfect negroni`; - break; - default: - break; - } - if (booze) { - create(booze, 1); - drink(booze, 1); - } - }, - limit: { tries: 1 }, - }, { name: "Consult Fortune Teller", completed: () => get("_clanFortuneBuffUsed") || args.savefortune, @@ -895,14 +821,30 @@ export const LevelingQuest: Quest = { ready: () => myLevel() >= 11, completed: () => myInebriety() >= inebrietyLimit() || - (!have($item`astral six-pack`) && itemAmount($item`astral pilsner`) <= args.astralpils), + (!have($item`astral six-pack`) && itemAmount($item`astral pilsner`) <= 5), prepare: (): void => { cliExecute(`maximize ${myPrimestat()} experience percent`); tryAcquiringEffect($effect`Ode to Booze`); }, do: (): void => { if (have($item`astral six-pack`)) use($item`astral six-pack`, 1); - if (itemAmount($item`astral pilsner`) > args.astralpils) drink($item`astral pilsner`, 1); + if ( + have($familiar`Cooler Yeti`) && + MayamCalendar.have() && + !MayamCalendar.symbolsUsed().includes("fur") && + AprilingBandHelmet.have() + ) { + useFamiliar($familiar`Cooler Yeti`); + MayamCalendar.submit("fur yam2 wall yam4"); + AprilingBandHelmet.joinSection("Apriling band piccolo"); + AprilingBandHelmet.play("Apriling band piccolo"); + AprilingBandHelmet.play("Apriling band piccolo"); + } + if (have($familiar`Cooler Yeti`) && $familiar`Cooler Yeti`.experience > 225) { + visitUrl("main.php?talktoyeti=1", false); + runChoice(3); + } + if (itemAmount($item`astral pilsner`) > 5) drink($item`astral pilsner`, 1); }, post: (): void => { if (!have($item`astral six-pack`) && itemAmount($item`astral pilsner`) <= args.astralpils) @@ -929,27 +871,162 @@ export const LevelingQuest: Quest = { limit: { tries: 1 }, }, { - name: "Driving Recklessly", - after: ["Open Mayday"], - ready: () => args.asdon, - completed: () => have($effect`Driving Recklessly`), - do: (): void => { - fuelUp(); - drive($effect`Driving Recklessly`); + // Set up a pretty lit buff + name: "NEP Episode 2: The Prequel", + ready: () => get("noncombatForcerActive"), + completed: () => have($effect`Spiced Up`), + prepare: () => prepCommon, + do: $location`The Neverending Party`, + choices: { + 1324: 2, + 1326: 2, + 1562: 9, + }, + combat: new CombatStrategy().macro(Macro.trySkill($skill`%fn, spit on me!`).kill()), + outfit: () => ({ + ...baseOutfit(), + acc3: get("_mobiusStripEncounters", 0) === 0 ? $item`Möbius ring` : undefined, + }), + limit: { tries: 2 }, + post: (): void => { + sendAutumnaton(); + sellMiscellaneousItems(); + boomBoxProfit(); }, - limit: { tries: 3 }, }, { - // This won't actually run until it's ready, but we put it here, early, so that when it's ready it can run - name: "Early Camel Spit", + name: "Get an S", ready: () => - get("camelSpit") >= 100, - prepare: (): void => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - unbreakableUmbrella(); - [...usefulEffects, ...statEffects].forEach((ef) => tryAcquiringEffect(ef)); - restoreMp(50); + // eslint-disable-next-line libram/verify-constants + have($item`legendary seal-clubbing club`) && have($item`heartstone`), + prepare: () => prepCommon, + completed: () => + get("_clubEmTimeUsed") >= 1 || + PeridotOfPeril.zonesToday().includes($location`The Outskirts of Cobb's Knob`), + do: $location`The Outskirts of Cobb's Knob`, + choices: peridotChoice($monster`Knob Goblin Assistant Chef`), + // eslint-disable-next-line libram/verify-constants + combat: new CombatStrategy().macro( + Macro.trySkill($skill`steal monster's heart`) + .trySkill($skill`club 'em back in time`) + .abort() + ), + outfit: () => ({ + // eslint-disable-next-line libram/verify-constants + weapon: $item`legendary seal-clubbing club`, + // eslint-disable-next-line libram/verify-constants + acc2: $item`heartstone`, + acc3: $item`Peridot of Peril`, + }), + limit: { tries: 2 }, + post: (): void => { + sendAutumnaton(); + sellMiscellaneousItems(); + boomBoxProfit(); + refreshStatus(); + }, + }, + { + name: "Get a P", + ready: () => + // eslint-disable-next-line libram/verify-constants + have($item`legendary seal-clubbing club`) && have($item`heartstone`), + prepare: () => prepCommon, + completed: () => + get("_clubEmTimeUsed") >= 2 || + PeridotOfPeril.zonesToday().includes($location`The Sleazy Back Alley`), + do: $location`The Sleazy Back Alley`, + choices: peridotChoice($monster`big creepy spider`), + // eslint-disable-next-line libram/verify-constants + combat: new CombatStrategy().macro( + Macro.trySkill($skill`steal monster's heart`) + .trySkill($skill`club 'em back in time`) + .abort() + ), + outfit: () => ({ + // eslint-disable-next-line libram/verify-constants + weapon: $item`legendary seal-clubbing club`, + // eslint-disable-next-line libram/verify-constants + acc2: $item`heartstone`, + acc3: $item`Peridot of Peril`, + }), + limit: { tries: 2 }, + post: (): void => { + sendAutumnaton(); + sellMiscellaneousItems(); + boomBoxProfit(); + refreshStatus(); + }, + }, + { + name: "Get an I", + ready: () => + // eslint-disable-next-line libram/verify-constants + have($item`legendary seal-clubbing club`) && have($item`heartstone`), + prepare: () => prepCommon, + completed: () => + get("_clubEmTimeUsed") >= 3 || + PeridotOfPeril.zonesToday().includes($location`The Skeleton Store`), + do: $location`The Skeleton Store`, + choices: peridotChoice($monster`novelty tropical skeleton`), + // eslint-disable-next-line libram/verify-constants + combat: new CombatStrategy().macro( + Macro.trySkill($skill`steal monster's heart`) + .trySkill($skill`club 'em back in time`) + .abort() + ), + outfit: () => ({ + // eslint-disable-next-line libram/verify-constants + weapon: $item`legendary seal-clubbing club`, + // eslint-disable-next-line libram/verify-constants + acc2: $item`heartstone`, + acc3: $item`Peridot of Peril`, + }), + limit: { tries: 2 }, + post: (): void => { + sendAutumnaton(); + sellMiscellaneousItems(); + boomBoxProfit(); + refreshStatus(); + }, + }, + { + name: "Get a T", + ready: () => + // eslint-disable-next-line libram/verify-constants + have($item`legendary seal-clubbing club`) && have($item`heartstone`), + prepare: () => prepCommon, + completed: () => + get("_clubEmTimeUsed") >= 4 || + PeridotOfPeril.zonesToday().includes($location`The Haunted Conservatory`), + do: $location`The Haunted Conservatory`, + choices: peridotChoice($monster`skeletal cat`), + // eslint-disable-next-line libram/verify-constants + combat: new CombatStrategy().macro( + Macro.trySkill($skill`steal monster's heart`) + .trySkill($skill`club 'em back in time`) + .abort() + ), + outfit: () => ({ + // eslint-disable-next-line libram/verify-constants + weapon: $item`legendary seal-clubbing club`, + // eslint-disable-next-line libram/verify-constants + acc2: $item`heartstone`, + acc3: $item`Peridot of Peril`, + }), + limit: { tries: 2 }, + post: (): void => { + sendAutumnaton(); + sellMiscellaneousItems(); + boomBoxProfit(); + refreshStatus(); }, + }, + { + // This won't actually run until it's ready, but we put it here, early, so that when it's ready it can run + name: "Early Camel Spit", + ready: () => get("camelSpit") >= 100, + prepare: () => prepCommon, completed: () => have($effect`Spit Upon`), do: $location`Noob Cave`, choices: { @@ -959,7 +1036,11 @@ export const LevelingQuest: Quest = { 1324: 5, 1326: 2, }, - combat: new CombatStrategy().macro(Macro.trySkill($skill`%fn, spit on me!`).trySkill($skill`Spring Away`).abort()), + combat: new CombatStrategy().macro( + Macro.trySkill($skill`%fn, spit on me!`) + .trySkill($skill`Spring Away`) + .abort() + ), outfit: () => ({ acc3: $item`spring shoes`, shirt: $item`Jurassic Parka`, @@ -974,41 +1055,33 @@ export const LevelingQuest: Quest = { }, }, { - name: "Ghost", - completed: () => get("questPAGhost") === "unstarted", - ready: () => - have($item`protonic accelerator pack`) && - get("questPAGhost") !== "unstarted" && - !!get("ghostLocation") && - !have($effect`Meteor Showered`), - do: () => get("ghostLocation") ?? abort("Failed to identify ghost location"), - combat: new CombatStrategy().macro( - Macro.trySkill($skill`micrometeorite`) - .trySkill($skill`Shoot Ghost`) - .trySkill($skill`Shoot Ghost`) - .trySkill($skill`Shoot Ghost`) - .trySkill($skill`Trap Ghost`) - ), - outfit: () => ({ - ...baseOutfit, - back: $item`protonic accelerator pack` - }), - }, + name: "Ghost", + prepare: () => { + [...usefulEffects, ...statEffects].forEach((ef) => tryAcquiringEffect(ef)); + }, + completed: () => get("questPAGhost") === "unstarted", + ready: () => + have($item`protonic accelerator pack`) && + get("questPAGhost") !== "unstarted" && + !!get("ghostLocation") && + !have($effect`Meteor Showered`), + do: () => get("ghostLocation") ?? abort("Failed to identify ghost location"), + combat: new CombatStrategy().macro( + Macro.trySkill($skill`Micrometeorite`) + .trySkill($skill`Shoot Ghost`) + .trySkill($skill`Shoot Ghost`) + .trySkill($skill`Shoot Ghost`) + .trySkill($skill`Trap Ghost`) + ), + outfit: () => ({ + // eslint-disable-next-line libram/verify-constants + ...baseOutfit(true, false, $monster`ice woman`), + back: $item`protonic accelerator pack`, + }), + }, { name: "Map Amateur Ninja", - prepare: (): void => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - if (!have($effect`Everything Looks Blue`) && !have($item`blue rocket`)) { - if (myMeat() < 250) throw new Error("Insufficient Meat to purchase blue rocket!"); - buy($item`blue rocket`, 1); - } - unbreakableUmbrella(); - docBag(); - restoreMp(50); - if (!have($effect`Everything Looks Red`) && !have($item`red rocket`)) { - if (myMeat() >= 250) buy($item`red rocket`, 1); - } - }, + prepare: () => prepCommon, completed: () => !have($skill`Map the Monsters`) || get("_monstersMapped") >= 3 || @@ -1037,43 +1110,25 @@ export const LevelingQuest: Quest = { }, limit: { tries: 1 }, }, - { - name: "Sept-ember Mouthwash", - completed: () => - !have($item`Sept-Ember Censer`) || have($item`bembershoot`) || args.saveembers, - do: (): void => { - // Grab Embers - visitUrl("shop.php?whichshop=september"); - - // Grab Bembershoots - visitUrl(`shop.php?whichshop=september&action=buyitem&quantity=1&whichrow=1516&pwd`); - - // Grab Mouthwashes - visitUrl("shop.php?whichshop=september&action=buyitem&quantity=3&whichrow=1512&pwd"); - - // Re-maximize cold res after getting bembershoots - cliExecute("maximize cold res"); - - // eslint-disable-next-line libram/verify-constants - use($item`Mmm-brr! brand mouthwash`, 3); - }, - limit: { tries: 1 }, - outfit: { - modifier: `10 cold res, 1 ${primeStat} experience percent`, - familiar: $familiar`Exotic Parrot`, - }, - }, { name: "Free Fight Leafy Boys", + prepare: () => { + [...usefulEffects, ...statEffects].forEach((ef) => tryAcquiringEffect(ef)); + }, ready: () => !have($effect`Shadow Affinity`), completed: () => get("_leafMonstersFought", 0) >= 5 || !have($item`inflammable leaf`, 11), do: (): void => { visitUrl("campground.php?preaction=leaves"); visitUrl("choice.php?pwd&whichchoice=1510&option=1&leaves=11"); }, - combat: new CombatStrategy().macro(Macro.trySkill($skill`spring growth spurt`).default()), + combat: new CombatStrategy().macro( + Macro.trySkill($skill`Spring Growth Spurt`) + .trySkill($skill`Tear Away your Pants!`) + .default() + ), outfit: () => ({ - ...baseOutfit, + ...baseOutfit(true, true, $monster`flaming leaflet`), + pants: have($item`tearaway pants`) ? $item`tearaway pants` : undefined, acc3: have($item`spring shoes`) ? $item`spring shoes` : undefined, }), post: (): void => { @@ -1117,48 +1172,19 @@ export const LevelingQuest: Quest = { limit: { tries: 5 }, }, { - name: "Eat Magical Sausages", - ready: () => - restoreMPEfficiently() === "Sausage" || restoreMPEfficiently() === "Make Sausage", - completed: () => - get("_sausagesMade") >= 23 || - myMp() >= 75 || - (restoreMPEfficiently() !== "Sausage" && restoreMPEfficiently() !== "Make Sausage"), - do: (): void => { - if (restoreMPEfficiently() === "Sausage") eat($item`magical sausage`, 1); - else { - create($item`magical sausage`, 1); - eat($item`magical sausage`, 1); - } - }, - post: () => autosell($item`meat stack`, itemAmount($item`meat stack`)), - limit: { tries: 23 }, - }, - { - name: "Rest Upside Down", - ready: () => restoreMPEfficiently() === "Bat Wings", - completed: () => myMp() >= 75 || restoreMPEfficiently() !== "Bat Wings", + name: "Rest Upside Down", + ready: () => restoreMPEfficiently() === "Bat Wings", + completed: () => myMp() >= 75 || restoreMPEfficiently() !== "Bat Wings", do: (): void => { cliExecute("cast rest upside down"); }, + outfit: { back: $item`bat wings` }, limit: { tries: 11 }, }, { name: "Restore MP with Glowing Blue", ready: () => restoreMPEfficiently() === "Blue Rocket", - prepare: (): void => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - if (!have($effect`Everything Looks Blue`) && !have($item`blue rocket`)) { - if (myMeat() < 250) throw new Error("Insufficient Meat to purchase blue rocket!"); - buy($item`blue rocket`, 1); - } - unbreakableUmbrella(); - restoreMp(50); - if (!have($effect`Everything Looks Red`) && !have($item`red rocket`)) { - if (myMeat() >= 250) buy($item`red rocket`, 1); - } - sellMiscellaneousItems(); - }, + prepare: () => prepCommon, completed: () => have($effect`Everything Looks Blue`) || myMp() >= 75 || @@ -1177,19 +1203,15 @@ export const LevelingQuest: Quest = { 1094: 5, 1115: 6, 1322: 2, - 1324: 5, + 1324: 2, + 1326: 2, }, limit: { tries: 2 }, }, { name: "Restore MP with Glowing Blue (continued)", ready: () => restoreMPEfficiently() === "Blue Rocket", - prepare: (): void => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - unbreakableUmbrella(); - restoreMp(50); - sellMiscellaneousItems(); - }, + prepare: () => prepCommon, // We need to spend at least 1adv to get the mp regen from Glowing Blue // This is only an issue if our powerleveling zone is the NEP, since the previous fight would be free completed: () => @@ -1219,17 +1241,7 @@ export const LevelingQuest: Quest = { }, { name: "Shadow Rift", - prepare: (): void => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - unbreakableUmbrella(); - restoreMp(50); - sellMiscellaneousItems(); - garbageShirt(); - if (checkPurqoise(250)) autosell($item`porquoise`, 1); - if (!have($effect`Everything Looks Red`) && !have($item`red rocket`)) { - if (myMeat() >= 250) buy($item`red rocket`, 1); - } - }, + prepare: () => prepCommon, completed: () => have($item`Rufus's shadow lodestone`) || (!have($effect`Shadow Affinity`) && get("encountersUntilSRChoice") !== 0) || @@ -1242,7 +1254,7 @@ export const LevelingQuest: Quest = { .trySkill($skill`Recall Facts: %phylum Circadian Rhythms`) .default() ), - outfit: baseOutfit, + outfit: () => ({ ...baseOutfit(true, false, $monster`shadow slab`) }), post: (): void => { if (have(rufusTarget() as Item)) { withChoice(1498, 1, () => use($item`closed-circuit pay phone`)); @@ -1258,28 +1270,22 @@ export const LevelingQuest: Quest = { name: "Run CyberRealm", ready: () => have($item`server room key`) && have($skill`OVERCLOCK(10)`) && !args.savecyber, prepare: () => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - unbreakableUmbrella(); - restoreMp(50); - sellMiscellaneousItems(); - garbageShirt(); - if (checkPurqoise(250)) autosell($item`porquoise`, 1); + prepCommon(); $effects`Astral Shell, Elemental Saucesphere, Scarysauce`.forEach((ef) => { if (!have(ef)) useSkill(toSkill(ef)); }); }, - completed: () => $location`Cyberzone 1`.turnsSpent >= 10 || toInt(get("_cyberZone1Turns")) >= 10 || have($item`0`), + completed: () => + $location`Cyberzone 1`.turnsSpent >= 11 || toInt(get("_cyberZone1Turns")) >= 11, choices: { 1545: 1, 1546: 1 }, do: $location`Cyberzone 1`, + outfit: () => ({ ...baseOutfit(true, false, $monster`shadow slab`) }), combat: new CombatStrategy().macro(() => - Macro.if_( - "!monsterphylum construct", - Macro.default() - ) + Macro.if_("!monsterphylum construct", Macro.default()) .skill($skill`Throw Cyber Rock`) .repeat() ), - limit: { tries: 10 }, + limit: { tries: 11 }, }, { name: "Get Range", @@ -1328,17 +1334,9 @@ export const LevelingQuest: Quest = { limit: { tries: 1 }, }, { - name: "Snojo", - prepare: (): void => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - if (get("snojoSetting") === null) { - visitUrl("place.php?whichplace=snojo&action=snojo_controller"); - runChoice(1); - } - unbreakableUmbrella(); - garbageShirt(); - restoreMp(50); - }, + name: "Snojo Pledge", + prepare: () => prepCommon, + ready: () => have($familiar`Patriotic Eagle`) && get("snojoAvailable"), completed: () => get("_snojoFreeFights") >= 10 || !get("snojoAvailable"), do: $location`The X-32-F Combat Training Snowman`, combat: new CombatStrategy().macro( @@ -1351,8 +1349,24 @@ export const LevelingQuest: Quest = { .default() ), outfit: () => ({ - ...baseOutfit, - familiar: !have($effect`Citizen of a Zone`) ? $familiar`Patriotic Eagle` : chooseFamiliar(), + familiar: $familiar`Patriotic Eagle`, + }), + limit: { tries: 10 }, + post: (): void => { + if (get("_snojoFreeFights") >= 10) cliExecute("hottub"); + if (restoreMPEfficiently() === "Refill Latte" && myMp() < 75) refillLatte(); + sendAutumnaton(); + sellMiscellaneousItems(); + }, + }, + { + name: "Snojo", + prepare: () => prepCommon, + completed: () => get("_snojoFreeFights") >= 10 || !get("snojoAvailable"), + do: $location`The X-32-F Combat Training Snowman`, + combat: new CombatStrategy().macro(Macro.default()), + outfit: () => ({ + ...baseOutfit(true, false, $monster`X-32-F Combat Training Snowman`), shirt: garbageShirt() ? $item`makeshift garbage shirt` : undefined, }), limit: { tries: 10 }, @@ -1373,54 +1387,10 @@ export const LevelingQuest: Quest = { }, limit: { tries: 50 }, }, - { - name: "Red Skeleton", - ready: () => - !have($effect`Everything Looks Yellow`) || - (have($skill`Feel Envy`) && get("_feelEnvyUsed") < 3), - prepare: (): void => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - if (!have($item`yellow rocket`) && !have($effect`Everything Looks Yellow`)) { - if (myMeat() < 250) throw new Error("Insufficient Meat to purchase yellow rocket!"); - buy($item`yellow rocket`, 1); - } - unbreakableUmbrella(); - docBag(); - }, - completed: () => - CombatLoversLocket.monstersReminisced().includes($monster`red skeleton`) || - !CombatLoversLocket.availableLocketMonsters().includes($monster`red skeleton`) || - args.redskeleton || - checkValue("Locket", 4) || - have($item`red eye`), - do: () => CombatLoversLocket.reminisce($monster`red skeleton`), - combat: new CombatStrategy().macro( - Macro.if_("!haseffect Everything Looks Yellow", Macro.tryItem($item`yellow rocket`)) - .trySkill($skill`Feel Envy`) - .trySkill($skill`Chest X-Ray`) - .trySkill($skill`Shattering Punch`) - .trySkill($skill`Gingerbread Mob Hit`) - .default() - ), - outfit: baseOutfit, - post: (): void => { - if (restoreMPEfficiently() === "Refill Latte" && myMp() < 75) refillLatte(); - use($item`red box`, 1); - sendAutumnaton(); - sellMiscellaneousItems(); - boomBoxProfit(); - }, - limit: { tries: 1 }, - }, { name: "Bakery Pledge", - prepare: (): void => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - restoreMp(50); - docBag(); - restoreMp(50); - }, - ready: () => !get("snojoAvailable", false), + prepare: () => prepCommon, + ready: () => !get("snojoAvailable"), completed: () => have($effect`Citizen of a Zone`) || !have($familiar`Patriotic Eagle`) || @@ -1436,8 +1406,9 @@ export const LevelingQuest: Quest = { .default() ), outfit: () => ({ - ...baseOutfit, + shirt: $item`Jurassic Parka`, familiar: $familiar`Patriotic Eagle`, + modes: { parka: "spikolodon" }, }), post: (): void => { sellMiscellaneousItems(); @@ -1448,9 +1419,7 @@ export const LevelingQuest: Quest = { { name: "LOV Tunnel", prepare: (): void => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - unbreakableUmbrella(); - [...usefulEffects, ...statEffects].forEach((ef) => tryAcquiringEffect(ef)); + prepCommon(); tryAcquiringEffect($effect`Comic Violence`); tryAcquiringEffect($effect`Fat Leon's Phat Loot Lyric`); }, @@ -1478,8 +1447,8 @@ export const LevelingQuest: Quest = { .if_($monster`LOV Equivocator`, Macro.default()) ), outfit: () => ({ - ...baseOutfit(false), - weapon: $item`Fourth of May Cosplay Saber`, + ...baseOutfit(false, false, $monster`LOV Engineer`), + modifier: `0.25 ${mainStatMaximizerStr}, 0.001 item%, -equip tinsel tights, -equip wad of used tape, -equip Kramco Sausage-o-Matic™`, }), limit: { tries: 1 }, post: (): void => { @@ -1492,6 +1461,63 @@ export const LevelingQuest: Quest = { uneffect($effect`Fat Leon's Phat Loot Lyric`); }, }, + { + name: "Sept-ember Mouthwash", + prepare: () => { + const effects: Effect[] = [ + $effect`Elemental Saucesphere`, + $effect`Scarysauce`, + // eslint-disable-next-line libram/verify-constants + $effect`Feel Peaceful`, + $effect`Astral Shell`, + ]; + effects.forEach((ef) => tryAcquiringEffect(ef)); + }, + completed: () => + !have($item`Sept-Ember Censer`) || get("availableSeptEmbers") === 1 || args.saveembers, + do: (): void => { + // Saber a camel + if ( + have($familiar`Melodramedary`) && + have($item`Fourth of May Cosplay Saber`) && + !get("_entauntaunedToday") + ) { + const weapon = equippedItem($slot`weapon`); + useFamiliar($familiar`Melodramedary`); + equip($item`Fourth of May Cosplay Saber`); + visitUrl("/main.php?action=camel"); + runChoice(1); + useFamiliar($familiar`Cooler Yeti`); + equip(weapon); + } + + if (!have($effect`Cold as Nice`) && have($item`Beach Comb`)) + tryAcquiringEffect($effect`Cold as Nice`); + + // Grab Embers + visitUrl("shop.php?whichshop=september"); + + // Grab Mouthwashes + visitUrl("shop.php?whichshop=september&action=buyitem&quantity=3&whichrow=1512&pwd"); + + use($item`Mmm-brr! brand mouthwash`, 3); + }, + limit: { tries: 1 }, + outfit: () => ({ + hat: $item`prismatic beret`, + weapon: $item`McHugeLarge right pole`, + offhand: $item`McHugeLarge left pole`, + back: $item`McHugeLarge duffel bag`, + shirt: $item`LOV Eardigan`, + pants: $item`tearaway pants`, + // eslint-disable-next-line libram/verify-constants + acc1: $item`The Eternity Codpiece`, + acc2: $item`McHugeLarge left ski`, + acc3: $item`McHugeLarge right ski`, + familiar: $familiar`Cooler Yeti`, + famequip: $item`tiny stillsuit`, + }), + }, { name: "Restore cinch", completed: () => @@ -1500,6 +1526,7 @@ export const LevelingQuest: Quest = { if (have($item`Newbiesport™ tent`)) use($item`Newbiesport™ tent`); }, do: (): void => { + useFamiliar($familiar`Skeleton of Crimbo Past`); if (get("chateauAvailable")) { visitUrl("place.php?whichplace=chateau&action=chateau_restbox"); } else if (get("getawayCampsiteUnlocked")) { @@ -1510,99 +1537,18 @@ export const LevelingQuest: Quest = { }, outfit: { modifier: "myst, mp" }, }, - { - name: "Monster Habitats", - ready: () => - get("_monsterHabitatsFightsLeft") > 0 && - (haveFreeBanish() || - Array.from(getBanishedMonsters().values()).includes($monster`fluffy bunny`)), - prepare: (): void => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - unbreakableUmbrella(); - garbageShirt(); - [...usefulEffects, ...statEffects].forEach((ef) => tryAcquiringEffect(ef)); - restoreMp(50); - }, - completed: () => get("_monsterHabitatsFightsLeft") === 0, - do: $location`The Dire Warren`, - combat: new CombatStrategy().macro(() => - Macro.if_($monster`fluffy bunny`, Macro.banish()) - .externalIf( - get("_monsterHabitatsFightsLeft") <= 1 && - toInt(get("_monsterHabitatsRecalled")) < 3 - toInt(args.savehabitats) && - have($skill`Recall Facts: Monster Habitats`) && - (haveFreeBanish() || - Array.from(getBanishedMonsters().values()).includes($monster`fluffy bunny`)), - Macro.trySkill($skill`Recall Facts: Monster Habitats`) - ) - .default(useCinch()) - ), - outfit: baseOutfit, - post: (): void => { - sendAutumnaton(); - sellMiscellaneousItems(); - boomBoxProfit(); - }, - limit: { tries: 15 }, - }, - { - name: "Backups", - ready: () => freeFightMonsters.includes(get("lastCopyableMonster") ?? $monster.none), - prepare: (): void => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - unbreakableUmbrella(); - garbageShirt(); - [...usefulEffects, ...statEffects].forEach((ef) => tryAcquiringEffect(ef)); - restoreMp(50); - }, - completed: () => - !have($item`backup camera`) || - !freeFightMonsters.includes(get("lastCopyableMonster") ?? $monster.none) || - get("_backUpUses") >= 11 - clamp(args.savebackups, 0, 11) || - myBasestat(myPrimestat()) >= 190, // no longer need to back up Witchess Kings - do: $location`The Dire Warren`, - combat: new CombatStrategy().macro( - Macro.trySkill($skill`Back-Up to your Last Enemy`).default(useCinch()) - ), - outfit: () => ({ - ...baseOutfit(), - acc3: $item`backup camera`, - }), - post: (): void => { - if (!freeFightMonsters.includes(get("lastCopyableMonster") ?? $monster.none)) - throw new Error("Fought unexpected monster"); - sendAutumnaton(); - sellMiscellaneousItems(); - }, - limit: { tries: 11 }, - }, { name: "Kramco", - prepare: (): void => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - unbreakableUmbrella(); - garbageShirt(); - [...usefulEffects, ...statEffects].forEach((ef) => tryAcquiringEffect(ef)); - restoreMp(50); - }, + prepare: () => prepCommon, ready: () => getKramcoWandererChance() >= 1.0, completed: () => getKramcoWandererChance() < 1.0 || !have($item`Kramco Sausage-o-Matic™`), do: $location`Noob Cave`, outfit: () => ({ - ...baseOutfit(), + ...baseOutfit(true, false, $monster`sausage goblin`), offhand: $item`Kramco Sausage-o-Matic™`, shirt: garbageShirt() ? $item`makeshift garbage shirt` : undefined, }), - combat: new CombatStrategy().macro(() => - Macro.externalIf( - get("_monsterHabitatsFightsLeft") <= 1 && - toInt(get("_monsterHabitatsRecalled")) < 3 - args.savehabitats && - have($skill`Recall Facts: Monster Habitats`) && - (haveFreeBanish() || - Array.from(getBanishedMonsters().values()).includes($monster`fluffy bunny`)), - Macro.trySkill($skill`Recall Facts: Monster Habitats`) - ).default(useCinch()) - ), + combat: new CombatStrategy().macro(() => Macro.default(useCinch())), post: (): void => { sendAutumnaton(); sellMiscellaneousItems(); @@ -1611,17 +1557,12 @@ export const LevelingQuest: Quest = { }, { name: "Oliver's Place (Peridot)", - ready: () => have($item`peridot of peril`), prepare: (): void => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - unbreakableUmbrella(); - restoreMp(50); + prepCommon(); if (SourceTerminal.have()) cliExecute("terminal educate portscan"); }, completed: () => - get("_speakeasyFreeFights", 0) >= 1 || - !get("ownsSpeakeasy") || - have($item`imported taffy`), + get("_speakeasyFreeFights", 0) >= 1 || !get("ownsSpeakeasy") || have($item`imported taffy`), do: () => $location`An Unusually Quiet Barroom Brawl`, choices: peridotChoice($monster`goblin flapper`), combat: new CombatStrategy().macro( @@ -1629,7 +1570,10 @@ export const LevelingQuest: Quest = { .trySkill($skill`Portscan`) .default() ), - outfit: () => ({...baseOutfit(true), acc3: $item`Peridot of Peril`}), + outfit: () => ({ + ...baseOutfit(true, false, $monster`goblin flapper`), + acc3: $item`Peridot of Peril`, + }), limit: { tries: 2 }, post: (): void => { sendAutumnaton(); @@ -1637,68 +1581,13 @@ export const LevelingQuest: Quest = { boomBoxProfit(); }, }, - { - name: "Oliver's Place (Map)", - prepare: (): void => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - unbreakableUmbrella(); - restoreMp(50); - if (SourceTerminal.have()) cliExecute("terminal educate portscan"); - }, - completed: () => - get("_speakeasyFreeFights", 0) >= 1 || - !get("ownsSpeakeasy") || - !have($skill`Map the Monsters`) || - get("_monstersMapped") >= 3 || - have($item`imported taffy`), - do: () => mapMonster($location`An Unusually Quiet Barroom Brawl`, $monster`goblin flapper`), - combat: new CombatStrategy().macro( - Macro.trySkill($skill`Feel Envy`) - .trySkill($skill`Portscan`) - .default() - ), - outfit: baseOutfit, - limit: { tries: 1 }, - post: (): void => { - sendAutumnaton(); - sellMiscellaneousItems(); - boomBoxProfit(); - }, - }, - { - name: "Oliver's Place (Portscan)", - prepare: (): void => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - unbreakableUmbrella(); - restoreMp(50); - if (SourceTerminal.have()) cliExecute("terminal educate portscan"); - }, - completed: () => - get("_speakeasyFreeFights", 0) >= 2 || - !get("ownsSpeakeasy") || - !SourceTerminal.have() || - get("_sourceTerminalPortscanUses") > 0, - do: $location`An Unusually Quiet Barroom Brawl`, - combat: new CombatStrategy().macro(Macro.trySkill($skill`Portscan`).default()), - outfit: baseOutfit, - limit: { tries: 1 }, - post: (): void => { - sendAutumnaton(); - sellMiscellaneousItems(); - boomBoxProfit(); - }, - }, { name: "Oliver's Place", - prepare: (): void => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - unbreakableUmbrella(); - restoreMp(50); - }, + prepare: () => prepCommon, completed: () => get("_speakeasyFreeFights", 0) >= 3 || !get("ownsSpeakeasy"), do: $location`An Unusually Quiet Barroom Brawl`, combat: new CombatStrategy().macro(Macro.default()), - outfit: baseOutfit, + outfit: () => ({ ...baseOutfit(true, false, $monster`goblin flapper`) }), limit: { tries: 3 }, post: (): void => { sendAutumnaton(); @@ -1706,62 +1595,15 @@ export const LevelingQuest: Quest = { boomBoxProfit(); }, }, - { - name: "Map Pocket Wishes", - after: ["Oliver's Place (Map)"], - prepare: (): void => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - unbreakableUmbrella(); - docBag(); - restoreMp(50); - if (!have($effect`Everything Looks Red`) && !have($item`red rocket`)) { - if (myMeat() >= 250) buy($item`red rocket`, 1); - } - }, - completed: () => - !have($skill`Map the Monsters`) || - !have($skill`Just the Facts`) || - get("_monstersMapped") >= 3 || - have($item`pocket wish`, 1) || - myClass() !== $class`Seal Clubber` || - ((get("_shatteringPunchUsed") >= 3 || !have($skill`Shattering Punch`)) && - (get("_gingerbreadMobHitUsed") || !have($skill`Gingerbread Mob Hit`))), - do: () => mapMonster($location`The Haunted Kitchen`, $monster`paper towelgeist`), - combat: new CombatStrategy().macro( - Macro.if_( - $monster`paper towelgeist`, - Macro.tryItem($item`blue rocket`) - .tryItem($item`red rocket`) - .trySkill($skill`Chest X-Ray`) - .trySkill($skill`Gingerbread Mob Hit`) - .trySkill($skill`Shattering Punch`) - .default() - ).abort() - ), - post: (): void => { - sellMiscellaneousItems(); - boomBoxProfit(); - }, - limit: { tries: 1 }, - }, { name: "God Lobster", - prepare: (): void => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - unbreakableUmbrella(); - [...usefulEffects, ...statEffects].forEach((ef) => tryAcquiringEffect(ef)); - restoreMp(50); - garbageShirt(); - }, - completed: () => - get("_godLobsterFights") >= 3 || - !have($familiar`God Lobster`) || - (get("_godLobsterFights") >= 2 && godLobsterSave()), + prepare: () => prepCommon, + completed: () => get("_godLobsterFights") >= 3 || !have($familiar`God Lobster`), do: () => visitUrl("main.php?fightgodlobster=1"), combat: new CombatStrategy().macro(Macro.default(useCinch())), choices: { 1310: godLobsterChoice() }, // Get xp on last fight outfit: () => ({ - ...baseOutfit(), + ...baseOutfit(true, false, $monster`God Lobster`), famequip: $items`God Lobster's Ring, God Lobster's Scepter`, familiar: $familiar`God Lobster`, shirt: garbageShirt() ? $item`makeshift garbage shirt` : undefined, @@ -1775,12 +1617,7 @@ export const LevelingQuest: Quest = { }, { name: "Eldritch Tentacle", - prepare: (): void => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - unbreakableUmbrella(); - [...usefulEffects, ...statEffects].forEach((ef) => tryAcquiringEffect(ef)); - restoreMp(50); - }, + prepare: () => prepCommon, completed: () => get("_eldritchHorrorEvoked") || !have($skill`Evoke Eldritch Horror`), do: () => useSkill($skill`Evoke Eldritch Horror`), post: (): void => { @@ -1789,33 +1626,19 @@ export const LevelingQuest: Quest = { sellMiscellaneousItems(); }, combat: new CombatStrategy().macro(Macro.default(useCinch())), - outfit: baseOutfit, + outfit: () => ({ ...baseOutfit(true, false, $monster`Eldritch Tentacle`) }), limit: { tries: 1 }, }, { name: "Witchess Bishop", - prepare: (): void => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - unbreakableUmbrella(); - [...usefulEffects, ...statEffects].forEach((ef) => tryAcquiringEffect(ef)); - restoreMp(50); - }, + prepare: () => prepCommon, completed: () => get("_witchessFights") >= 4 - (args.skipbishop ? 2 : 0) || !Witchess.have() || args.witchess, do: () => Witchess.fightPiece($monster`Witchess Bishop`), - combat: new CombatStrategy().macro(() => - Macro.externalIf( - get("_monsterHabitatsFightsLeft") <= 1 && - toInt(get("_monsterHabitatsRecalled")) < 3 - args.savehabitats && - have($skill`Recall Facts: Monster Habitats`) && - (haveFreeBanish() || - Array.from(getBanishedMonsters().values()).includes($monster`fluffy bunny`)), - Macro.trySkill($skill`Recall Facts: Monster Habitats`) - ).default(useCinch()) - ), - outfit: baseOutfit, + combat: new CombatStrategy().macro(() => Macro.default(useCinch())), + outfit: () => ({ ...baseOutfit(true, false, $monster`Witchess Knight`) }), post: (): void => { sendAutumnaton(); sellMiscellaneousItems(); @@ -1825,18 +1648,12 @@ export const LevelingQuest: Quest = { }, { name: "DMT", - prepare: (): void => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - unbreakableUmbrella(); - [...usefulEffects, ...statEffects].forEach((ef) => tryAcquiringEffect(ef)); - restoreMp(50); - garbageShirt(); - }, + prepare: () => prepCommon, completed: () => get("_machineTunnelsAdv") >= 5 || !have($familiar`Machine Elf`), do: $location`The Deep Machine Tunnels`, combat: new CombatStrategy().macro(Macro.default(useCinch())), outfit: () => ({ - ...baseOutfit(), + ...baseOutfit(true, false, $monster`Perceiver of Sensations`), familiar: $familiar`Machine Elf`, }), limit: { tries: 5 }, @@ -1846,70 +1663,21 @@ export const LevelingQuest: Quest = { boomBoxProfit(); }, }, - { - name: "Early Camel Spit", - ready: () => - get("camelSpit") >= 100 && - have($familiar`Comma Chameleon`) && - get("_neverendingPartyFreeTurns") < 10 && - computeHotRes(false) + computeWeaponDamage(false) + 4 < 10, - prepare: (): void => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - unbreakableUmbrella(); - [...usefulEffects, ...statEffects].forEach((ef) => tryAcquiringEffect(ef)); - restoreMp(50); - garbageShirt(); - }, - completed: () => have($effect`Spit Upon`), - do: $location`The Neverending Party`, - choices: { - 1094: 5, - 1115: 6, - 1322: 2, - 1324: 5, - }, - combat: new CombatStrategy().macro(Macro.trySkill($skill`%fn, spit on me!`).kill()), - outfit: () => ({ - ...baseOutfit(), - familiar: $familiar`Melodramedary`, - }), - limit: { tries: 2 }, - post: (): void => { - sendAutumnaton(); - sellMiscellaneousItems(); - boomBoxProfit(); - }, - }, { name: "Powerlevel", completed: () => get("_neverendingPartyFreeTurns") >= 10, do: powerlevelingLocation(), - prepare: (): void => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - unbreakableUmbrella(); - garbageShirt(); - if (mainStatStr === `Muscle`) { - muscleList.forEach((ef) => tryAcquiringEffect(ef)); - } - if (mainStatStr === `Mysticality`) { - mysticalityList.forEach((ef) => tryAcquiringEffect(ef)); - } - if (mainStatStr === `Moxie`) { - moxieList.forEach((ef) => tryAcquiringEffect(ef)); - } - [...usefulEffects, ...statEffects].forEach((ef) => tryAcquiringEffect(ef)); - restoreMp(50); - if (!have($effect`Everything Looks Red`) && !have($item`red rocket`)) { - if (myMeat() >= 250) buy($item`red rocket`, 1); - } - }, - outfit: baseOutfit, + prepare: () => prepCommon, + outfit: () => ({ + ...baseOutfit(true, false, $monster`burnout`), + }), limit: { tries: 60 }, choices: { 1094: 5, 1115: 6, 1322: 2, 1324: 5, + 1326: 2, }, combat: new CombatStrategy().macro( Macro.tryItem($item`red rocket`) @@ -1927,70 +1695,6 @@ export const LevelingQuest: Quest = { boomBoxProfit(); }, }, - { - name: "Extra Camelspit Leveling", - ready: () => get("camelSpit") >= 94 && myBasestat(myPrimestat()) >= targetBaseMyst, - completed: () => !args.camelhat || get("camelSpit") >= 100 || have($effect`spit upon`), - do: powerlevelingLocation(), - prepare: (): void => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - unbreakableUmbrella(); - garbageShirt(); - if (mainStatStr === `Muscle`) { - muscleList.forEach((ef) => tryAcquiringEffect(ef)); - } - if (mainStatStr === `Mysticality`) { - mysticalityList.forEach((ef) => tryAcquiringEffect(ef)); - } - if (mainStatStr === `Moxie`) { - moxieList.forEach((ef) => tryAcquiringEffect(ef)); - } - [...usefulEffects, ...statEffects].forEach((ef) => tryAcquiringEffect(ef)); - restoreMp(50); - if (!have($effect`Everything Looks Red`) && !have($item`red rocket`)) { - if (myMeat() >= 250) buy($item`red rocket`, 1); - } - }, - outfit: () => ({ - ...baseOutfit(), - familiar: $familiar`Melodramedary`, - shirt: garbageShirt() ? $item`makeshift garbage shirt` : undefined, - }), - limit: { tries: 60 }, - choices: { - 1094: 5, - 1115: 6, - 1322: 2, - 1324: 5, - }, - combat: new CombatStrategy().macro( - Macro.trySkill($skill`Feel Pride`) - .trySkill($skill`Cincho: Confetti Extravaganza`) - .trySkill($skill`Gulp Latte`) - .trySkill($skill`Recall Facts: %phylum Circadian Rhythms`) - .trySkill($skill`Chest X-Ray`) - .trySkill($skill`Shattering Punch`) - .trySkill($skill`Gingerbread Mob Hit`) - .default(useCinch()) - ), - post: (): void => { - if (have($item`SMOOCH coffee cup`)) chew($item`SMOOCH coffee cup`, 1); - sendAutumnaton(); - sellMiscellaneousItems(); - boomBoxProfit(); - }, - }, - { - name: "Drink Bee's Knees", - after: ["Powerlevel"], - completed: () => have($effect`On the Trolley`) || args.beesknees, - do: (): void => { - if (myMeat() < 500) throw new Error("Insufficient Meat to purchase Bee's Knees!"); - tryAcquiringEffect($effect`Ode to Booze`); - visitUrl(`clan_viplounge.php?preaction=speakeasydrink&drink=5&pwd=${+myHash()}`); // Bee's Knees - }, - limit: { tries: 1 }, - }, { name: "Acquire Lyle's Buff", completed: () => get("_lyleFavored"), @@ -2002,17 +1706,7 @@ export const LevelingQuest: Quest = { }, { name: "Witchess King", - prepare: (): void => { - garbageShirt(); - [ - ...usefulEffects.filter((ef) => !$effects`Song of Sauce, Song of Bravado`.includes(ef)), - ...prismaticEffects, - ...wdmgEffects, - ...statEffects, - ].forEach((ef) => tryAcquiringEffect(ef)); - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - restoreMp(50); - }, + prepare: () => prepCommon, completed: () => have($item`dented scepter`) || get("_witchessFights") >= 5 || @@ -2021,7 +1715,7 @@ export const LevelingQuest: Quest = { args.skipking, do: () => Witchess.fightPiece($monster`Witchess King`), combat: new CombatStrategy().macro(Macro.default(useCinch())), - outfit: baseOutfit, + outfit: () => ({ ...baseOutfit(true, false, $monster`Witchess Knight`) }), post: (): void => { sendAutumnaton(); sellMiscellaneousItems(); @@ -2031,18 +1725,7 @@ export const LevelingQuest: Quest = { }, { name: "Witchess Witch", - prepare: (): void => { - garbageShirt(); - [ - ...usefulEffects.filter((ef) => !$effects`Song of Sauce, Song of Bravado`.includes(ef)), - ...prismaticEffects, - ...wdmgEffects, - ...statEffects, - ].forEach((ef) => tryAcquiringEffect(ef)); - if (get("_hotTubSoaks") < 5 && myHp() < myMaxhp()) cliExecute("hottub"); - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - restoreMp(50); - }, + prepare: () => prepCommon, completed: () => have($item`battle broom`) || get("_witchessFights") >= 5 || @@ -2056,7 +1739,7 @@ export const LevelingQuest: Quest = { .repeat() ), outfit: { - ...baseOutfit(), + ...baseOutfit(true, false, $monster`Witchess Knight`), weapon: have($effect`Comic Violence`) && have($item`Fourth of May Cosplay Saber`) ? $item`Fourth of May Cosplay Saber` @@ -2073,18 +1756,7 @@ export const LevelingQuest: Quest = { }, { name: "Witchess Queen", - prepare: (): void => { - garbageShirt(); - [ - ...usefulEffects.filter((ef) => !$effects`Song of Sauce, Song of Bravado`.includes(ef)), - ...prismaticEffects, - ...wdmgEffects, - ...statEffects, - ].forEach((ef) => tryAcquiringEffect(ef)); - if (get("_hotTubSoaks") < 5 && myHp() < myMaxhp()) cliExecute("hottub"); - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - restoreMp(50); - }, + prepare: () => prepCommon, completed: () => have($item`very pointy crown`) || get("_witchessFights") >= 5 || @@ -2094,7 +1766,7 @@ export const LevelingQuest: Quest = { do: () => Witchess.fightPiece($monster`Witchess Queen`), combat: new CombatStrategy().macro(Macro.attack().repeat()), outfit: { - ...baseOutfit(), + ...baseOutfit(true, false, $monster`Witchess Knight`), weapon: have($effect`Comic Violence`) && have($item`Fourth of May Cosplay Saber`) ? $item`Fourth of May Cosplay Saber` @@ -2109,74 +1781,45 @@ export const LevelingQuest: Quest = { limit: { tries: 1 }, }, { - name: "Witchess King (Locket)", - prepare: (): void => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - unbreakableUmbrella(); - garbageShirt(); - [...usefulEffects, ...statEffects].forEach((ef) => tryAcquiringEffect(ef)); - restoreMp(50); + name: "Authority", + prepare: () => prepCommon, + ready: () => + have($item`Sheriff moustache`) && have($item`Sheriff badge`) && have($item`Sheriff pistol`), + completed: () => get("_assertYourAuthorityCast") >= 3, + do: powerlevelingLocation(), + combat: new CombatStrategy().macro(Macro.trySkill($skill`Assert your Authority`).abort()), + choices: { + 1094: 5, + 1115: 6, + 1322: 2, + 1324: 5, + 1326: 2, }, - completed: () => - CombatLoversLocket.monstersReminisced().includes($monster`Witchess King`) || - !CombatLoversLocket.availableLocketMonsters().includes($monster`Witchess King`) || - args.witchessking || - have($item`dented scepter`), - do: () => CombatLoversLocket.reminisce($monster`Witchess King`), - combat: new CombatStrategy().macro(() => - Macro.externalIf( - get("_monsterHabitatsFightsLeft") <= 1 && - get("_monsterHabitatsRecalled") < 3 - args.savehabitats && - have($skill`Recall Facts: Monster Habitats`) && - (haveFreeBanish() || - Array.from(getBanishedMonsters().values()).includes($monster`fluffy bunny`)), - Macro.trySkill($skill`Recall Facts: Monster Habitats`) - ).default(useCinch()) - ), - outfit: baseOutfit, + outfit: () => ({ + ...baseOutfit(true, false, $monster`burnout`), + weapon: $item`Sheriff pistol`, + acc2: $item`Sheriff badge`, + acc3: $item`Sheriff moustache`, + }), post: (): void => { - sendAutumnaton(); sellMiscellaneousItems(); boomBoxProfit(); }, - limit: { tries: 1 }, + limit: { tries: 3 }, }, { name: "Free Kills and More Fights", - after: ["Drink Bee's Knees"], - prepare: (): void => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - if (equippedItem($slot`offhand`) !== $item`latte lovers member's mug`) { - unbreakableUmbrella(); - } - garbageShirt(); - docBag(); - [...usefulEffects, ...statEffects].forEach((ef) => tryAcquiringEffect(ef)); - restoreMp(50); - }, - outfit: baseOutfit, - completed: () => - (get("_shatteringPunchUsed") >= 3 || !have($skill`shattering punch`)) && - (get("_gingerbreadMobHitUsed") || !have($skill`gingerbread mob hit`)) && - (have($effect`Everything Looks Yellow`) || !have($item`jurassic parka`)) && - (get("_chestXRayUsed") >= 3 || !have($item`Lil' Doctor™ bag`)), + prepare: () => prepCommon, + outfit: freekillOutfit, + completed: () => !freekillsRemaining(), do: powerlevelingLocation(), - combat: new CombatStrategy().macro( - Macro.if_($monster`sausage goblin`, Macro.default(useCinch())) - .trySkill($skill`Feel Pride`) - .trySkill($skill`Gulp Latte`) - .trySkill($skill`Cincho: Confetti Extravaganza`) - .trySkill($skill`Spit jurassic acid`) - .trySkill($skill`Chest X-Ray`) - .trySkill($skill`Shattering Punch`) - .trySkill($skill`Gingerbread Mob Hit`) - .abort() - ), + combat: new CombatStrategy().macro(freekillMacro()), choices: { 1094: 5, 1115: 6, 1322: 2, 1324: 5, + 1326: 2, }, post: (): void => { if (have($item`SMOOCH coffee cup`)) chew($item`SMOOCH coffee cup`, 1); diff --git a/src/tasks/noncombat.ts b/src/tasks/noncombat.ts index 7dec949e..2d2c94ec 100644 --- a/src/tasks/noncombat.ts +++ b/src/tasks/noncombat.ts @@ -1,40 +1,31 @@ import { Quest } from "../engine/task"; -import { - buy, - cliExecute, - Effect, - equip, - myMaxhp, - print, - restoreHp, - restoreMp, - runChoice, - useSkill, - visitUrl, -} from "kolmafia"; +import { buy, cliExecute, Effect, equip, print, runChoice, useSkill, visitUrl } from "kolmafia"; import { $effect, $familiar, $item, $skill, $slot, - clamp, CommunityService, get, have, uneffect, } from "libram"; -import { checkTurnSave, checkValue, logTestSetup, tryAcquiringEffect, wishFor } from "../lib"; +import { + checkTurnSave, + checkValue, + fuelUp, + logTestSetup, + tryAcquiringEffect, + wishFor, +} from "../lib"; import { CombatStrategy } from "grimoire-kolmafia"; import Macro from "../combat"; import { drive } from "libram/dist/resources/2017/AsdonMartin"; import { args } from "../args"; -import { baseOutfit, unbreakableUmbrella } from "../engine/outfit"; -const familiar = have($familiar`peace turkey`) - ? $familiar`peace turkey` - : $familiar`disgeist`; -const cap = familiar === $familiar`peace turkey` ? 50 : 75; +const familiar = have($familiar`Peace Turkey`) ? $familiar`Peace Turkey` : $familiar`Disgeist`; +const cap = familiar === $familiar`Peace Turkey` ? 50 : 75; export const NoncombatQuest: Quest = { name: "Noncombat", @@ -68,6 +59,7 @@ export const NoncombatQuest: Quest = { ready: () => args.asdon, completed: () => have($effect`Driving Stealthily`), do: (): void => { + fuelUp(); drive($effect`Driving Stealthily`); }, limit: { tries: 3 }, @@ -82,58 +74,12 @@ export const NoncombatQuest: Quest = { }, limit: { tries: 1 }, }, - { - name: "Cincho: Party Soundtrack", - completed: () => - have($effect`Party Soundtrack`) || !have($item`Cincho de Mayo`) || get("_cinchUsed") >= 40, - do: (): void => { - equip($slot`acc3`, $item`Cincho de Mayo`); - useSkill($skill`Cincho: Party Soundtrack`); - }, - limit: { tries: 1 }, - }, - { - name: "God Lobster", - prepare: (): void => { - restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); - unbreakableUmbrella(); - restoreMp(50); - }, - completed: () => - get("_godLobsterFights") >= 3 || - !have($familiar`God Lobster`) || - !have($item`God Lobster's Ring`), - do: () => visitUrl("main.php?fightgodlobster=1"), - combat: new CombatStrategy().macro(Macro.default(false)), - choices: { 1310: 1 }, // Get xp on last fight - outfit: () => ({ - ...baseOutfit(), - famequip: $item`God Lobster's Ring`, - familiar: $familiar`God Lobster`, - }), - limit: { tries: 3 }, - }, - { - name: "Buy Porkpie-mounted Popper", - completed: () => - have($item`porkpie-mounted popper`) || - CommunityService.BoozeDrop.prediction <= 1 || - get("_fireworksShopHatBought", false), - do: () => buy($item`porkpie-mounted popper`, 1), - limit: { tries: 1 }, - }, { name: "Test", completed: () => CommunityService.Noncombat.isDone(), prepare: (): void => { if (have($item`Jurassic Parka`) && get("parkaMode") !== "pterodactyl") cliExecute("parka pterodactyl"); - if ( - get("_kgbClicksUsed") < 22 && - have($item`Kremlin's Greatest Briefcase`) && - !args.savekgb - ) - cliExecute("briefcase e -combat"); const usefulEffects: Effect[] = [ $effect`A Rose by Any Other Material`, $effect`Blessing of the Bird`, @@ -145,7 +91,7 @@ export const NoncombatQuest: Quest = { $effect`The Sonata of Sneakiness`, $effect`Feeling Sneaky`, $effect`Ultra-Soft Steps`, - $effect`Hiding from Seekers`, + $effect`Hiding From Seekers`, // Famwt for Disgeist $effect`Blood Bond`, @@ -154,8 +100,16 @@ export const NoncombatQuest: Quest = { $effect`Puzzle Champ`, ]; usefulEffects.forEach((ef) => tryAcquiringEffect(ef, true)); + + if ( + CommunityService.Noncombat.actualCost() > 1 && + !have($item`porkpie-mounted popper`) && + !get("_fireworksShopHatBought") + ) + buy($item`porkpie-mounted popper`, 1); + cliExecute( - `maximize -combat, 0.04 familiar weight ${cap} max, switch ${familiar}, switch left-hand man, switch disembodied hand, switch peace turkey -tie` + `maximize -raw combat rate, 0.04 familiar weight ${cap} max, switch ${familiar}, switch left-hand man, switch disembodied hand, switch peace turkey -tie` ); // To avoid maximizer bug, we invoke this once more if ( @@ -180,8 +134,7 @@ export const NoncombatQuest: Quest = { }, outfit: { familiar: familiar, - modifier: - `-combat, 0.04 familiar weight ${cap} max, switch ${familiar}, switch left-hand man, switch disembodied hand, -tie`, + modifier: `-raw combat rate, 0.04 familiar weight ${cap} max, switch ${familiar}, switch left-hand man, switch disembodied hand, -tie`, }, post: (): void => { uneffect($effect`The Sonata of Sneakiness`); diff --git a/src/tasks/runstart.ts b/src/tasks/runstart.ts index 3852a6c7..750b579b 100644 --- a/src/tasks/runstart.ts +++ b/src/tasks/runstart.ts @@ -1,24 +1,21 @@ -import { CombatStrategy, OutfitSpec } from "grimoire-kolmafia"; +import { CombatStrategy } from "grimoire-kolmafia"; import { - adv1, + abort, autosell, buy, + buyUsingStorage, changeMcd, cliExecute, create, currentMcd, - drink, eat, - equip, getCampground, + getClanName, getWorkshed, - haveEquipped, hermit, Item, itemAmount, myAdventures, - myInebriety, - myLevel, myMaxhp, myMaxmp, myMeat, @@ -48,34 +45,24 @@ import { $location, $monster, $skill, - $slot, $stat, AprilingBandHelmet, clamp, + Clan, CommunityService, get, - getBanishedMonsters, getKramcoWandererChance, have, haveInCampground, Pantogram, + set, SongBoom, TrainSet, } from "libram"; import { Quest } from "../engine/task"; -import { - bestSIT, - checkPull, - fuelUp, - getGarden, - goVote, - sellMiscellaneousItems, - statToMaximizerString, - tryAcquiringEffect, -} from "../lib"; +import { bestSIT, getGarden, goVote, sellMiscellaneousItems, statToMaximizerString } from "../lib"; import Macro from "../combat"; -import { mapMonster } from "libram/dist/resources/2020/Cartography"; -import { baseOutfit, chooseFamiliar, unbreakableUmbrella } from "../engine/outfit"; +import { baseOutfit } from "../engine/outfit"; import { args } from "../args"; import { Cycle, setConfiguration, Station } from "libram/dist/resources/2022/TrainSet"; @@ -88,9 +75,8 @@ const optimalCape = ? "heck thrill" : "robot thrill"; -let btorpizza = false; +const btorpizza = false; -const useParkaSpit = have($item`Fourth of May Cosplay Saber`) && have($skill`Feel Envy`); export const RunStartQuest: Quest = { name: "Run Start", completed: () => CommunityService.CoilWire.isDone(), @@ -164,15 +150,25 @@ export const RunStartQuest: Quest = { }, { name: "SIT Course", - // eslint-disable-next-line libram/verify-constants + ready: () => have($item`S.I.T. Course Completion Certificate`), completed: () => get("_sitCourseCompleted", false), choices: { 1494: bestSIT, }, - do: () => - // eslint-disable-next-line libram/verify-constants - use($item`S.I.T. Course Completion Certificate`), + do: () => use($item`S.I.T. Course Completion Certificate`), + }, + { + name: "Do Pullls", + completed: () => 5 - get("_roninStoragePulls").split(",").length <= args.savepulls, + do: () => { + buyUsingStorage($item`tobiko marble soda`, 1); + takeStorage($item`Great Wolf's beastly trousers`, 1); + takeStorage($item`meteorite necklace`, 1); + takeStorage($item`Stick-Knife of Loathing`, 1); + takeStorage($item`Staff of Simmering Hatred`, 1); + takeStorage($item`tobiko marble soda`, 1); + }, }, { name: "Tune Cape", @@ -199,13 +195,6 @@ export const RunStartQuest: Quest = { visitUrl(`inv_use.php?whichitem=${toInt($item`2002 Mr. Store Catalog`)}&which=f0&pwd`), limit: { tries: 1 }, }, - { - name: "KGB", - completed: () => - get("_kgbClicksUsed") > 0 || !have($item`Kremlin's Greatest Briefcase`) || args.savekgb, - do: () => cliExecute("briefcase e ml"), - limit: { tries: 1 }, - }, { name: "Restore mp", completed: () => get("timesRested") >= args.saverests || myMp() >= Math.min(50, myMaxmp()), @@ -217,6 +206,8 @@ export const RunStartQuest: Quest = { if (myMeat() >= 2000) { restoreMp(50); } + // eslint-disable-next-line libram/verify-constants + useFamiliar($familiar`Skeleton of Crimbo Past`); if (get("chateauAvailable")) { visitUrl("place.php?whichplace=chateau&action=chateau_restbox"); } else if (get("getawayCampsiteUnlocked")) { @@ -236,52 +227,6 @@ export const RunStartQuest: Quest = { do: () => cliExecute("numberology 69"), limit: { tries: 3 }, }, - { - name: "Get Camel Hat", - ready: () => args.camelhat, - completed: () => have($item`dromedary drinking helmet`) || !have($familiar`Melodramedary`), - do: (): void => { - if (!have($item`box of Familiar Jacks`)) create($item`box of Familiar Jacks`, 1); - - useFamiliar($familiar`Melodramedary`); - use($item`box of Familiar Jacks`, 1); - }, - limit: { tries: 1 }, - }, - { - name: "Ensure Comma Chameleon Jacks", - ready: () => have($skill`Summon Clip Art`), - completed: () => - have($item`box of Familiar Jacks`) || - !have($familiar`Comma Chameleon`) || - have($item`homemade robot gear`), - do: (): void => { - create($item`box of Familiar Jacks`, 1); - }, - limit: { tries: 1 }, - }, - { - name: "Summon Sugar Sheets", - completed: () => - !have($skill`Summon Sugar Sheets`) || args.savesugar || get("tomeSummons") >= 3, - do: (): void => { - const haveBT = have($item`borrowed time`) ? 1 : 0; - const sheetsToMake = 3 - get("tomeSummons") - haveBT; - restoreMp(2 * sheetsToMake); - useSkill($skill`Summon Sugar Sheets`, sheetsToMake); - }, - limit: { tries: 1 }, - }, - { - name: "Fold Sugar Sheets", - completed: () => !have($item`sugar sheet`) || args.experimentalsynth, - do: (): void => { - const nextMissingSugarItem = - $items`sugar shorts, sugar chapeau, sugar shank`.find((it) => !have(it)) || $item`none`; - create(nextMissingSugarItem); - }, - limit: { tries: 3 }, - }, { name: "Chateau Desk", completed: () => get("_chateauDeskHarvested") || !get("chateauAvailable"), @@ -343,12 +288,10 @@ export const RunStartQuest: Quest = { !have($item`mumming trunk`) || args.savemumming, do: (): void => { + useFamiliar($familiar`Jill-of-All-Trades`); const statString = statToMaximizerString(myPrimestat()); cliExecute(`mummery ${statString}`); }, - outfit: { - familiar: have($familiar`Melodramedary`) ? $familiar`Melodramedary` : chooseFamiliar(), - }, limit: { tries: 1 }, }, { @@ -470,10 +413,11 @@ export const RunStartQuest: Quest = { { name: "Set Workshed", completed: () => - getWorkshed() === $item`Asdon Martin keyfob` || getWorkshed() === $item`model train set`, + getWorkshed() === $item`Asdon Martin keyfob (on ring)` || + getWorkshed() === $item`model train set`, do: (): void => { if (args.asdon) { - use($item`Asdon Martin keyfob`); + use($item`Asdon Martin keyfob (on ring)`); } else use($item`model train set`); }, }, @@ -525,96 +469,6 @@ export const RunStartQuest: Quest = { }, limit: { tries: 2 }, }, - { - name: "Map Novelty Tropical Skeleton", - prepare: (): void => { - if (useParkaSpit) { - cliExecute("parka dilophosaur"); - } else if (!have($item`yellow rocket`) && !have($effect`Everything Looks Yellow`)) { - if (myMeat() < 250) throw new Error("Insufficient Meat to purchase yellow rocket!"); - buy($item`yellow rocket`, 1); - } - unbreakableUmbrella(); - if (haveEquipped($item`miniature crystal ball`)) equip($slot`familiar`, $item.none); - }, - completed: () => - !have($skill`Map the Monsters`) || - get("_monstersMapped") >= 3 || - have($item`cherry`) || - args.skipbt || - (() => { - // if we have another skeleton in the ice house, we don't need to map a novelty skeleton - const banishes = get("banishedMonsters").split(":"); - const iceHouseIndex = banishes.map((string) => string.toLowerCase()).indexOf("ice house"); - if (iceHouseIndex === -1) return false; - return ["remaindered skeleton", "factory-irregular skeleton", "swarm of skulls"].includes( - banishes[iceHouseIndex - 1] - ); - })(), - do: () => mapMonster($location`The Skeleton Store`, $monster`novelty tropical skeleton`), - combat: new CombatStrategy().macro( - Macro.if_( - $monster`novelty tropical skeleton`, - (useParkaSpit ? Macro.trySkill($skill`Spit jurassic acid`) : new Macro()).tryItem( - $item`yellow rocket` - ) - ).abort() - ), - outfit: () => ({ - ...baseOutfit(false), - shirt: have($item`Jurassic Parka`) ? $item`Jurassic Parka` : undefined, - modifier: `${baseOutfit().modifier}, -equip miniature crystal ball`, - }), - limit: { tries: 1 }, - }, - { - name: "Novelty Tropical Skeleton", - prepare: (): void => { - if (useParkaSpit) { - cliExecute("parka dilophosaur"); - } else if (!have($item`yellow rocket`) && !have($effect`Everything Looks Yellow`)) { - if (myMeat() < 250) throw new Error("Insufficient Meat to purchase yellow rocket!"); - buy($item`yellow rocket`, 1); - } - unbreakableUmbrella(); - if (get("_snokebombUsed") === 0) restoreMp(50); - if (haveEquipped($item`miniature crystal ball`)) equip($slot`familiar`, $item.none); - }, - completed: () => args.skipbt || have($item`cherry`), - do: $location`The Skeleton Store`, - combat: new CombatStrategy().macro(() => - Macro.if_( - $monster`novelty tropical skeleton`, - (useParkaSpit ? Macro.trySkill($skill`Spit jurassic acid`) : new Macro()).tryItem( - $item`yellow rocket` - ) - ) - .externalIf( - !Array.from(getBanishedMonsters().keys()).includes($skill`Bowl a Curveball`), - Macro.trySkill($skill`Bowl a Curveball`) - ) - .externalIf( - !Array.from(getBanishedMonsters().keys()).includes($skill`Snokebomb`), - Macro.trySkill($skill`Snokebomb`) - ) - .externalIf( - !Array.from(getBanishedMonsters().keys()).includes($skill`Monkey Slap`), - Macro.trySkill($skill`Monkey Slap`) - ) - .abort() - ), - - outfit: (): OutfitSpec => { - return { - shirt: useParkaSpit ? $item`Jurassic Parka` : undefined, - offhand: $item`unbreakable umbrella`, - acc3: $item`cursed monkey's paw`, - familiar: chooseFamiliar(false), - modifier: `${baseOutfit().modifier}, -equip miniature crystal ball`, - }; - }, - limit: { tries: 4 }, - }, { name: "Chewing Gum", completed: () => myMeat() <= 600 || get("_cloversPurchased") >= 1, @@ -635,78 +489,165 @@ export const RunStartQuest: Quest = { }, }, { - name: "Get Distilled Fortified Wine", - ready: () => have($item`11-leaf clover`) || have($effect`Lucky!`), + name: "Borrowed Time", + prepare: (): void => { + create($item`borrowed time`, 1); + }, + completed: () => get("_borrowedTimeUsed"), + do: (): void => { + if (storageAmount($item`borrowed time`) === 0 && !have($item`borrowed time`)) { + print("Uh oh! You do not seem to have a borrowed time in Hagnk's", "red"); + print( + "Try to purchase one from the mall with your meat from Hagnk's before re-running instantsccs", + "red" + ); + } + use($item`borrowed time`, 1); + }, + limit: { tries: 1 }, + }, + { + name: "Clan Photo Booth Free Kill", completed: () => - myInebriety() >= 1 || - args.fortifiedwine || - (get("_borrowedTimeUsed") && myAdventures() >= 60) || - args.skipbt, + (have($item`Sheriff moustache`) && + have($item`Sheriff badge`) && + have($item`Sheriff pistol`)) || + get("_photoBoothEquipment", 0) >= 3, do: (): void => { - if (!have($effect`Lucky!`)) use($item`11-leaf clover`); - if (!have($item`distilled fortified wine`)) adv1($location`The Sleazy Back Alley`, -1); - while (have($item`distilled fortified wine`) && myInebriety() < 1) { - tryAcquiringEffect($effect`Ode to Booze`); - drink($item`distilled fortified wine`, 1); + if (getClanName() !== "Bonus Adventures from Hell") { + const clanWL = Clan.getWhitelisted(); + const bafhWL = + clanWL.find((c) => c.name === getClanName()) !== undefined && + clanWL.find((c) => c.name === "Bonus Adventures from Hell") !== undefined; + if (!bafhWL) return; } + + Clan.with("Bonus Adventures from Hell", () => { + cliExecute("photobooth item moustache"); + cliExecute("photobooth item badge"); + cliExecute("photobooth item pistol"); + }); + }, + limit: { tries: 3 }, + }, + { + name: "Scavenge", + completed: () => get("_daycareGymScavenges") > 0 || !get("daycareOpen"), + prepare: (): void => { + cliExecute(`maximize ${myPrimestat()} experience percent`); + }, + do: (): void => { + cliExecute("daycare scavenge free"); + }, + limit: { tries: 1 }, + }, + { + name: "Install Trainset", + ready: () => !args.asdon, + completed: () => !have($item`model train set`) || getWorkshed() === $item`model train set`, + do: (): void => { + use($item`model train set`); + visitUrl("campground.php?action=workshed"); + visitUrl("main.php"); }, limit: { tries: 1 }, }, + { + name: "Configure Trainset Early", + ready: () => !args.asdon, + completed: () => get("_folgerInitialConfig", false), + do: (): void => { + const offset = get("trainsetPosition") % 8; + const newStations: TrainSet.Station[] = []; + const statStation: Station = { + Muscle: Station.BRAWN_SILO, + Mysticality: Station.BRAIN_SILO, + Moxie: Station.GROIN_SILO, + }[myPrimestat().toString()]; + const stations = [ + Station.COAL_HOPPER, // double mainstat gain + statStation, // main stats + Station.VIEWING_PLATFORM, // all stats + Station.GAIN_MEAT, // meat + Station.TOWER_FIZZY, // mp regen + Station.TOWER_SEWAGE, // cold res + Station.WATER_BRIDGE, // +ML + Station.CANDY_FACTORY, // candies + ] as Cycle; + for (let i = 0; i < 8; i++) { + const newPos = (i + offset) % 8; + newStations[newPos] = stations[i]; + } + visitUrl("campground.php?action=workshed"); + visitUrl("main.php"); + setConfiguration(newStations as Cycle); + cliExecute("set _folgerInitialConfig = true"); + }, + limit: { tries: 2 }, + }, + { + name: "Ghost", + completed: () => get("questPAGhost") === "unstarted", + ready: () => + have($item`protonic accelerator pack`) && + get("questPAGhost") !== "unstarted" && + !!get("ghostLocation") && + !have($effect`Meteor Showered`), + do: () => get("ghostLocation") ?? abort("Failed to identify ghost location"), + combat: new CombatStrategy().macro( + Macro.trySkill($skill`Micrometeorite`) + .trySkill($skill`Shoot Ghost`) + .trySkill($skill`Shoot Ghost`) + .trySkill($skill`Shoot Ghost`) + .trySkill($skill`Trap Ghost`) + ), + outfit: () => ({ + // eslint-disable-next-line libram/verify-constants + ...baseOutfit(true, true, $monster`ice woman`), + shirt: $item`Jurassic Parka`, + back: $item`protonic accelerator pack`, + avoid: $items`Daylight Shavings Helmet`, + }), + }, { name: "Kramco", prepare: (): void => { restoreHp(clamp(1000, myMaxhp() / 2, myMaxhp())); restoreMp(50); - if (!have($item`red rocket`) && !have($effect`Everything Looks Red`)) { - if (myMeat() < 250) throw new Error("Insufficient Meat to purchase red rocket!"); - buy($item`red rocket`, 1); - } }, ready: () => getKramcoWandererChance() >= 1.0, - completed: () => - getKramcoWandererChance() < 1.0 || !have($item`Kramco Sausage-o-Matic™`) || args.skipbt, + completed: () => getKramcoWandererChance() < 1.0 || !have($item`Kramco Sausage-o-Matic™`), do: $location`Noob Cave`, outfit: () => ({ - ...baseOutfit(), + ...baseOutfit(true, true, $monster`sausage goblin`), + shirt: $item`Jurassic Parka`, offhand: $item`Kramco Sausage-o-Matic™`, + // eslint-disable-next-line libram/verify-constants + acc3: $item`Möbius ring`, // Prime the ring + modes: { parka: "spikolodon" }, + avoid: $items`Daylight Shavings Helmet`, }), - combat: new CombatStrategy().macro(Macro.tryItem($item`red rocket`).default()), + combat: new CombatStrategy().macro( + Macro.trySkill($skill`Launch spikolodon spikes`).default() + ), + post: () => set("_mobiusSeeded", true), }, { - name: "Borrowed Time", - prepare: (): void => { - if (have($item`borrowed time`)) return; - if (myLevel() >= 5 && !args.calzone && !args.pizza) { - btorpizza = true; - return; - } - if (have($skill`Summon Clip Art`) && get("tomeSummons") < 3) - create($item`borrowed time`, 1); - else takeStorage($item`borrowed time`, 1); - }, - completed: () => get("_borrowedTimeUsed") || args.skipbt, - do: (): void => { - if (storageAmount($item`borrowed time`) === 0 && !have($item`borrowed time`)) { - print("Uh oh! You do not seem to have a borrowed time in Hagnk's", "red"); - print( - "Try to purchase one from the mall with your meat from Hagnk's before re-running instantsccs", - "red" - ); - } - use($item`borrowed time`, 1); - }, - limit: { tries: 1 }, + name: "NEP The Prequel", + completed: () => get("_questPartyFair") !== "unstarted", + do: $location`The Neverending Party`, + choices: { 1322: 2 }, + outfit: () => ({ + ...baseOutfit(true, true), + shirt: $item`Jurassic Parka`, + offhand: $item`Kramco Sausage-o-Matic™`, + }), + combat: new CombatStrategy().macro(Macro.default()), }, { name: "Pizza over Borrowed Time", ready: () => btorpizza, prepare: (): void => { - if (!args.calzone && checkPull($item`Calzone of Legend`)) - takeStorage($item`Calzone of Legend`, 1); - if (!args.pizza && checkPull($item`Pizza of Legend`)) - takeStorage($item`Pizza of Legend`, 1); - if (!args.deepdish && checkPull($item`Deep Dish of Legend`)) - takeStorage($item`Deep Dish of Legend`, 1); cliExecute(`maximize ${myPrimestat()} experience percent`); if (have($item`whet stone`)) use($item`whet stone`); }, @@ -714,8 +655,7 @@ export const RunStartQuest: Quest = { do: (): void => { if (have($item`Calzone of Legend`)) eat($item`Calzone of Legend`, 1); if (have($item`Pizza of Legend`)) eat($item`Pizza of Legend`, 1); - if (have($item`Deep Dish of Legend`) && !args.latedeepdish) - eat($item`Deep Dish of Legend`, 1); + if (have($item`Deep Dish of Legend`)) eat($item`Deep Dish of Legend`, 1); }, limit: { tries: 1 }, }, diff --git a/src/tasks/spelldamage.ts b/src/tasks/spelldamage.ts index 9bafaace..eed48518 100644 --- a/src/tasks/spelldamage.ts +++ b/src/tasks/spelldamage.ts @@ -7,6 +7,7 @@ import { equip, haveEquipped, inebrietyLimit, + Item, myAdventures, myClass, myHp, @@ -18,6 +19,7 @@ import { restoreHp, restoreMp, retrieveItem, + toSlot, use, useSkill, visitUrl, @@ -32,13 +34,14 @@ import { $items, $location, $skill, + $slot, $thrall, clamp, Clan, CommunityService, get, have, - Witchess, + unequip, } from "libram"; import { Quest } from "../engine/task"; import { @@ -62,9 +65,10 @@ export const SpellDamageQuest: Quest = { tasks: [ { name: "Simmer", - prepare: () => have($item`April Shower Thoughts shield`) ? equip($item`April Shower Thoughts shield`) : true, + prepare: () => equip($item`April Shower Thoughts shield`), completed: () => have($effect`Simmering`) || !have($skill`Simmer`), do: () => useSkill($skill`Simmer`), + post: () => unequip($item`April Shower Thoughts shield`), limit: { tries: 1 }, }, { @@ -206,6 +210,16 @@ export const SpellDamageQuest: Quest = { }, limit: { tries: 1 }, }, + { + name: "Dial up to 11", + ready: () => have($item`blood cubic zirconia`), + completed: () => have($effect`Up To 11`), + do: (): void => { + equip($item`blood cubic zirconia`, $slot`acc3`); + useSkill($skill`BCZ: Dial it up to 11`); + }, + limit: { tries: 1 }, + }, { name: "Test", prepare: (): void => { @@ -250,7 +264,11 @@ export const SpellDamageQuest: Quest = { if (checkValue($item`battery (AAA)`, checkTurnSave("SpellDamage", $effect`AAA-Charged`))) tryAcquiringEffect($effect`AAA-Charged`, true); - if (!get("_madTeaParty") && !Witchess.have()) { + const teaPartyHats = Item.all().filter( + (i) => have(i) && toSlot(i) === $slot`hat` && i.name.length === 12 + ); + + if (!get("_madTeaParty") && teaPartyHats.length === 0) { if (!have($item`mariachi hat`)) retrieveItem(1, $item`chewing gum on a string`); tryAcquiringEffect($effect`Full Bottle in front of Me`); } diff --git a/src/tasks/stat.ts b/src/tasks/stat.ts index 5eddf5c1..f25349ed 100644 --- a/src/tasks/stat.ts +++ b/src/tasks/stat.ts @@ -134,8 +134,7 @@ export const MuscleQuest: Quest = { if ( CommunityService.Muscle.turnsSavedBy($effect`Purity of Spirit`) >= 7 && have($skill`Summon Clip Art`) && - get("tomeSummons") === 0 && - args.skipbt + get("tomeSummons") === 0 ) { create($item`cold-filtered water`, 1); use($item`cold-filtered water`, 1); @@ -219,8 +218,7 @@ export const MysticalityQuest: Quest = { if ( CommunityService.Mysticality.actualCost() >= 7 && have($skill`Summon Clip Art`) && - get("tomeSummons") === 0 && - args.skipbt + get("tomeSummons") === 0 ) { create($item`cold-filtered water`, 1); use($item`cold-filtered water`, 1); @@ -261,35 +259,6 @@ export const MysticalityQuest: Quest = { export const MoxieQuest: Quest = { name: "Moxie", tasks: [ - { - // This is also useful for the BoozeDrop test, but we can grab the +10%mox here first - name: "High Heels", - completed: () => - have($item`red-soled high heels`) || - !have($item`2002 Mr. Store Catalog`) || - CommunityService.Moxie.isDone(), - do: (): void => { - if (!have($item`Letter from Carrie Bradshaw`)) { - buy($coinmaster`Mr. Store 2002`, 1, $item`Letter from Carrie Bradshaw`); - } - withChoice(1506, 3, () => use($item`Letter from Carrie Bradshaw`)); - }, - limit: { tries: 1 }, - }, - { - name: "Loathing Idol Microphone", - completed: () => - have($effect`Poppy Performance`) || - !have($item`2002 Mr. Store Catalog`) || - CommunityService.Moxie.isDone(), - do: (): void => { - if (!haveLoathingIdol()) { - buy($coinmaster`Mr. Store 2002`, 1, $item`Loathing Idol Microphone`); - } - withChoice(1505, 1, () => useLoathingIdol()); - }, - limit: { tries: 1 }, - }, { name: "Test", completed: () => CommunityService.Moxie.isDone(), @@ -324,19 +293,32 @@ export const MoxieQuest: Quest = { ]; usefulEffects.forEach((ef) => tryAcquiringEffect(ef, true)); + if (CommunityService.Moxie.actualCost() > 1) { + if (!haveLoathingIdol()) { + buy($coinmaster`Mr. Store 2002`, 1, $item`Loathing Idol Microphone`); + } + withChoice(1505, 1, () => useLoathingIdol()); + } + if ( - CommunityService.Moxie.actualCost() >= 1 && + CommunityService.Moxie.actualCost() > 1 && have($item`pocket maze`) && !have($effect`Amazing`) && computeHotRes(false) <= 1 ) use($item`pocket maze`); + if (CommunityService.Moxie.actualCost() > 1) { + if (!have($item`Letter from Carrie Bradshaw`)) { + buy($coinmaster`Mr. Store 2002`, 1, $item`Letter from Carrie Bradshaw`); + } + withChoice(1506, 3, () => use($item`Letter from Carrie Bradshaw`)); + } + if ( CommunityService.Moxie.actualCost() >= 7 && have($skill`Summon Clip Art`) && - get("tomeSummons") === 0 && - args.skipbt + get("tomeSummons") === 0 ) { create($item`cold-filtered water`, 1); use($item`cold-filtered water`, 1); diff --git a/src/tasks/weapondamage.ts b/src/tasks/weapondamage.ts index 07d1bb98..28fd10fc 100644 --- a/src/tasks/weapondamage.ts +++ b/src/tasks/weapondamage.ts @@ -7,6 +7,7 @@ import { faxbot, haveEquipped, myClass, + myLevel, myMaxhp, myPrimestat, myThrall, @@ -296,7 +297,13 @@ export const WeaponDamageQuest: Quest = { ); }, outfit: { - weapon: canesword ? $item`candy cane sword cane` : undefined, + // eslint-disable-next-line libram/verify-constants + weapon: + have($item`legendary seal-clubbing club`) && myLevel() >= 17 + ? $item`legendary seal-clubbing club` + : canesword + ? $item`candy cane sword cane` + : undefined, offhand: stickknife() ? $item`Stick-Knife of Loathing` : undefined, modifier: "weapon dmg, weapon dmg percent, switch disembodied hand, -switch left-hand man", }, diff --git a/webpack.config.js b/webpack.config.js index 302547e3..60ec4a8d 100644 --- a/webpack.config.js +++ b/webpack.config.js @@ -1,12 +1,7 @@ -/* eslint-env node */ - -/* eslint-disable @typescript-eslint/no-var-requires */ +/* eslint-disable @typescript-eslint/no-require-imports */ +/* eslint-disable no-undef */ const path = require("path"); -// eslint-disable-next-line @typescript-eslint/no-unused-vars -const webpack = require("webpack"); // does this have a purpose? or can it just get deleted? const packageData = require("./package.json"); -/* eslint-enable @typescript-eslint/no-var-requires */ -// eslint-disable-next-line @typescript-eslint/no-var-requires const { merge } = require("webpack-merge"); const shared = { @@ -22,15 +17,19 @@ const shared = { extensions: [".ts", ".tsx", ".js", ".json"], }, module: { - rules: [ - { - // Include ts, tsx, js, and jsx files. - test: /\.(ts|js)x?$/, - // exclude: /node_modules/, - loader: "babel-loader", + rules: [ + { + test: /\.m?js$/, + resolve: { + fullySpecified: false, }, - ], - }, + }, + { + test: /\.(ts|js)x?$/, + loader: "babel-loader", + }, + ], +}, optimization: { // Disable compression because it makes debugging more difficult for KolMafia minimize: false, diff --git a/yarn.lock b/yarn.lock index 879b14e2..f9580488 100644 --- a/yarn.lock +++ b/yarn.lock @@ -1026,38 +1026,57 @@ resolved "https://registry.yarnpkg.com/@discoveryjs/json-ext/-/json-ext-0.5.7.tgz#1d572bfbbe14b7704e0ba0f39b74815b84870d70" integrity sha512-dBVuXR082gk3jsFp7Rd/JI4kytwGHecnCoTtXFb7DB6CNHp4rg5k1bhg0nWdLGLnOV71lmDzGQaLMy8iPLY0pw== -"@eslint-community/eslint-utils@^4.2.0": - version "4.4.0" - resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.4.0.tgz#a23514e8fb9af1269d5f7788aa556798d61c6b59" - integrity sha512-1/sA4dwrzBAyeUoQ6oxahHKmrZvsnLCg4RfxW3ZFGGmQkSNQPFNLV9CUEFQP1x9EYXHTo5p6xdhZM1Ne9p/AfA== +"@eslint-community/eslint-utils@^4.7.0": + version "4.7.0" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.7.0.tgz#607084630c6c033992a082de6e6fbc1a8b52175a" + integrity sha512-dyybb3AcajC7uha6CvhdVRJqaKyn7w2YKqKyAN37NKYgZT36w+iRb0Dymmc5qEJ549c/S31cMMSFd75bteCpCw== dependencies: - eslint-visitor-keys "^3.3.0" + eslint-visitor-keys "^3.4.3" -"@eslint-community/regexpp@^4.12.1": +"@eslint-community/eslint-utils@^4.8.0", "@eslint-community/eslint-utils@^4.9.1": + version "4.9.1" + resolved "https://registry.yarnpkg.com/@eslint-community/eslint-utils/-/eslint-utils-4.9.1.tgz#4e90af67bc51ddee6cdef5284edf572ec376b595" + integrity sha512-phrYmNiYppR7znFEdqgfWHXR6NCkZEK7hwWDHZUjit/2/U0r6XvkDl0SYnoM51Hq7FhCGdLDT6zxCCOY1hexsQ== + dependencies: + eslint-visitor-keys "^3.4.3" + +"@eslint-community/regexpp@^4.10.0", "@eslint-community/regexpp@^4.12.1": version "4.12.1" resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.1.tgz#cfc6cffe39df390a3841cde2abccf92eaa7ae0e0" integrity sha512-CCZCDJuduB9OUkFkY2IgppNZMi2lBQgD2qzwXkEia16cge2pijY/aXi96CJMquDMn3nJdlPV1A5KrJEXwfLNzQ== -"@eslint/config-array@^0.19.0": - version "0.19.1" - resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.19.1.tgz#734aaea2c40be22bbb1f2a9dac687c57a6a4c984" - integrity sha512-fo6Mtm5mWyKjA/Chy1BYTdn5mGJoDNjC7C64ug20ADsRDGrA85bN3uK3MaKbeRkRuuIEAR5N33Jr1pbm411/PA== +"@eslint-community/regexpp@^4.12.2": + version "4.12.2" + resolved "https://registry.yarnpkg.com/@eslint-community/regexpp/-/regexpp-4.12.2.tgz#bccdf615bcf7b6e8db830ec0b8d21c9a25de597b" + integrity sha512-EriSTlt5OC9/7SXkRSCAhfSxxoSUgBm33OH+IkwbdpgoqsSsUg7y3uh+IICI/Qg4BBWr3U2i39RpmycbxMq4ew== + +"@eslint/config-array@^0.21.1": + version "0.21.1" + resolved "https://registry.yarnpkg.com/@eslint/config-array/-/config-array-0.21.1.tgz#7d1b0060fea407f8301e932492ba8c18aff29713" + integrity sha512-aw1gNayWpdI/jSYVgzN5pL0cfzU02GT3NBpeT/DXbx1/1x7ZKxFPd9bwrzygx/qiwIQiJ1sw/zD8qY/kRvlGHA== dependencies: - "@eslint/object-schema" "^2.1.5" + "@eslint/object-schema" "^2.1.7" debug "^4.3.1" minimatch "^3.1.2" -"@eslint/core@^0.9.0": - version "0.9.1" - resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.9.1.tgz#31763847308ef6b7084a4505573ac9402c51f9d1" - integrity sha512-GuUdqkyyzQI5RMIWkHhvTWLCyLo1jNK3vzkSyaExH5kHPDHcuL2VOpHjmMY+y3+NC69qAKToBqldTBgYeLSr9Q== +"@eslint/config-helpers@^0.4.2": + version "0.4.2" + resolved "https://registry.yarnpkg.com/@eslint/config-helpers/-/config-helpers-0.4.2.tgz#1bd006ceeb7e2e55b2b773ab318d300e1a66aeda" + integrity sha512-gBrxN88gOIf3R7ja5K9slwNayVcZgK6SOUORm2uBzTeIEfeVaIhOpCtTox3P6R7o2jLFwLFTLnC7kU/RGcYEgw== + dependencies: + "@eslint/core" "^0.17.0" + +"@eslint/core@^0.17.0": + version "0.17.0" + resolved "https://registry.yarnpkg.com/@eslint/core/-/core-0.17.0.tgz#77225820413d9617509da9342190a2019e78761c" + integrity sha512-yL/sLrpmtDaFEiUj1osRP4TI2MDz1AddJL+jZ7KSqvBuliN4xqYY54IfdN8qD8Toa6g1iloph1fxQNkjOxrrpQ== dependencies: "@types/json-schema" "^7.0.15" -"@eslint/eslintrc@^3.2.0": - version "3.2.0" - resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.2.0.tgz#57470ac4e2e283a6bf76044d63281196e370542c" - integrity sha512-grOjVNN8P3hjJn/eIETF1wwd12DdnwFDoyceUJLYYdkpbwq3nLi+4fqrTAONx7XDALqlL220wC/RHSC/QTI/0w== +"@eslint/eslintrc@^3.3.1": + version "3.3.1" + resolved "https://registry.yarnpkg.com/@eslint/eslintrc/-/eslintrc-3.3.1.tgz#e55f7f1dd400600dd066dbba349c4c0bac916964" + integrity sha512-gtF186CXhIl1p4pJNGZw8Yc6RlshoePRvE0X91oPGb3vZ8pM3qOS9W9NGPat9LziaBV7XrJWGylNQXkGcnM3IQ== dependencies: ajv "^6.12.4" debug "^4.3.2" @@ -1069,21 +1088,22 @@ minimatch "^3.1.2" strip-json-comments "^3.1.1" -"@eslint/js@9.17.0": - version "9.17.0" - resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.17.0.tgz#1523e586791f80376a6f8398a3964455ecc651ec" - integrity sha512-Sxc4hqcs1kTu0iID3kcZDW3JHq2a77HO9P8CP6YEA/FpH3Ll8UXE2r/86Rz9YJLKme39S9vU5OWNjC6Xl0Cr3w== +"@eslint/js@9.39.2": + version "9.39.2" + resolved "https://registry.yarnpkg.com/@eslint/js/-/js-9.39.2.tgz#2d4b8ec4c3ea13c1b3748e0c97ecd766bdd80599" + integrity sha512-q1mjIoW1VX4IvSocvM/vbTiveKC4k9eLrajNEuSsmjymSDEbpGddtpfOoN7YGAqBK3NG+uqo8ia4PDTt8buCYA== -"@eslint/object-schema@^2.1.5": - version "2.1.5" - resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.5.tgz#8670a8f6258a2be5b2c620ff314a1d984c23eb2e" - integrity sha512-o0bhxnL89h5Bae5T318nFoFzGy+YE5i/gGkoPAgkmTVdRKTiv3p8JHevPiPaMwoloKfEiiaHlawCqaZMqRm+XQ== +"@eslint/object-schema@^2.1.7": + version "2.1.7" + resolved "https://registry.yarnpkg.com/@eslint/object-schema/-/object-schema-2.1.7.tgz#6e2126a1347e86a4dedf8706ec67ff8e107ebbad" + integrity sha512-VtAOaymWVfZcmZbp6E2mympDIHvyjXs/12LqWYjVw6qjrfF+VK+fyG33kChz3nnK+SU5/NeHOqrTEHS8sXO3OA== -"@eslint/plugin-kit@^0.2.3": - version "0.2.4" - resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.2.4.tgz#2b78e7bb3755784bb13faa8932a1d994d6537792" - integrity sha512-zSkKow6H5Kdm0ZUQUB2kV5JIXqoG0+uH5YADhaEHswm664N9Db8dXSi0nMJpacpMf+MyyglF1vnZohpEg5yUtg== +"@eslint/plugin-kit@^0.4.1": + version "0.4.1" + resolved "https://registry.yarnpkg.com/@eslint/plugin-kit/-/plugin-kit-0.4.1.tgz#9779e3fd9b7ee33571a57435cf4335a1794a6cb2" + integrity sha512-43/qtrDUokr7LJqoF2c3+RInu/t4zfrpYdoSDfYyhg52rwLV6TnOvdG4fXm7IkSB3wErkcmJS9iEhjVtOSEjjA== dependencies: + "@eslint/core" "^0.17.0" levn "^0.4.1" "@humanfs/core@^0.19.1": @@ -1109,10 +1129,10 @@ resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.3.1.tgz#c72a5c76a9fbaf3488e231b13dc52c0da7bab42a" integrity sha512-JBxkERygn7Bv/GbN5Rv8Ul6LVknS+5Bp6RgDC/O8gEBU/yeH5Ui5C/OlWrTb6qct7LjjfT6Re2NxB0ln0yYybA== -"@humanwhocodes/retry@^0.4.1": - version "0.4.1" - resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.1.tgz#9a96ce501bc62df46c4031fbd970e3cc6b10f07b" - integrity sha512-c7hNEllBlenFTHBky65mhq8WD2kbN9Q6gk0bTk8lSBvc554jpXSkST1iePudpt7+A/AQvuHs9EMqjHDXMY1lrA== +"@humanwhocodes/retry@^0.4.2": + version "0.4.3" + resolved "https://registry.yarnpkg.com/@humanwhocodes/retry/-/retry-0.4.3.tgz#c2b9d2e374ee62c586d3adbea87199b1d7a7a6ba" + integrity sha512-bV0Tgo9K4hfPCek+aMAn81RppFKv2ySDQeMoSZuvTASywNTnVJCArCZE2FWqpvIatKu7VMRLWlR1EazvVhDyhQ== "@jridgewell/gen-mapping@^0.3.5": version "0.3.5" @@ -1206,7 +1226,7 @@ resolved "https://registry.yarnpkg.com/@types/estree/-/estree-1.0.6.tgz#628effeeae2064a1b4e79f78e81d87b7e5fc7b50" integrity sha512-AYnb1nQyY49te+VRAVgmzfcgjYS91mY5P0TKUDCLEM+gNnA+3T6rWITXRLYCpahpqSQbN5cE+gHpnPyXjHWxcw== -"@types/json-schema@*", "@types/json-schema@^7.0.15", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.7", "@types/json-schema@^7.0.8": +"@types/json-schema@*", "@types/json-schema@^7.0.15", "@types/json-schema@^7.0.5", "@types/json-schema@^7.0.8": version "7.0.15" resolved "https://registry.yarnpkg.com/@types/json-schema/-/json-schema-7.0.15.tgz#596a1747233694d50f6ad8a7869fcb6f56cf5841" integrity sha512-5+fP8P8MFNC+AyZCDxrB2pkZFPGzqQWUzpSeuuVLvm8VMcorNYavBqoFcxK8bQz4Qsbn4oUEEem4wDLfcysGHA== @@ -1218,75 +1238,198 @@ dependencies: undici-types "~5.26.4" -"@typescript-eslint/eslint-plugin@^4.29.3": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.33.0.tgz#c24dc7c8069c7706bc40d99f6fa87edcb2005276" - integrity sha512-aINiAxGVdOl1eJyVjaWn/YcVAq4Gi/Yo35qHGCnqbWVz61g39D0h23veY/MA0rFFGfxK7TySg2uwDeNv+JgVpg== - dependencies: - "@typescript-eslint/experimental-utils" "4.33.0" - "@typescript-eslint/scope-manager" "4.33.0" - debug "^4.3.1" - functional-red-black-tree "^1.0.1" - ignore "^5.1.8" - regexpp "^3.1.0" - semver "^7.3.5" - tsutils "^3.21.0" - -"@typescript-eslint/experimental-utils@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.33.0.tgz#6f2a786a4209fa2222989e9380b5331b2810f7fd" - integrity sha512-zeQjOoES5JFjTnAhI5QY7ZviczMzDptls15GFsI6jyUOq0kOf9+WonkhtlIhh0RgHRnqj5gdNxW5j1EvAyYg6Q== - dependencies: - "@types/json-schema" "^7.0.7" - "@typescript-eslint/scope-manager" "4.33.0" - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/typescript-estree" "4.33.0" - eslint-scope "^5.1.1" - eslint-utils "^3.0.0" - -"@typescript-eslint/parser@^4.29.3": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.33.0.tgz#dfe797570d9694e560528d18eecad86c8c744899" - integrity sha512-ZohdsbXadjGBSK0/r+d87X0SBmKzOq4/S5nzK6SBgJspFo9/CUDJ7hjayuze+JK7CZQLDMroqytp7pOcFKTxZA== - dependencies: - "@typescript-eslint/scope-manager" "4.33.0" - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/typescript-estree" "4.33.0" - debug "^4.3.1" - -"@typescript-eslint/scope-manager@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.33.0.tgz#d38e49280d983e8772e29121cf8c6e9221f280a3" - integrity sha512-5IfJHpgTsTZuONKbODctL4kKuQje/bzBRkwHE8UOZ4f89Zeddg+EGZs8PD8NcN4LdM3ygHWYB3ukPAYjvl/qbQ== - dependencies: - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/visitor-keys" "4.33.0" - -"@typescript-eslint/types@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.33.0.tgz#a1e59036a3b53ae8430ceebf2a919dc7f9af6d72" - integrity sha512-zKp7CjQzLQImXEpLt2BUw1tvOMPfNoTAfb8l51evhYbOEEzdWyQNmHWWGPR6hwKJDAi+1VXSBmnhL9kyVTTOuQ== - -"@typescript-eslint/typescript-estree@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.33.0.tgz#0dfb51c2908f68c5c08d82aefeaf166a17c24609" - integrity sha512-rkWRY1MPFzjwnEVHsxGemDzqqddw2QbTJlICPD9p9I9LfsO8fdmfQPOX3uKfUaGRDFJbfrtm/sXhVXN4E+bzCA== - dependencies: - "@typescript-eslint/types" "4.33.0" - "@typescript-eslint/visitor-keys" "4.33.0" - debug "^4.3.1" - globby "^11.0.3" - is-glob "^4.0.1" - semver "^7.3.5" - tsutils "^3.21.0" +"@typescript-eslint/eslint-plugin@8.54.0": + version "8.54.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.54.0.tgz#d8899e5c2eccf5c4a20d01c036a193753748454d" + integrity sha512-hAAP5io/7csFStuOmR782YmTthKBJ9ND3WVL60hcOjvtGFb+HJxH4O5huAcmcZ9v9G8P+JETiZ/G1B8MALnWZQ== + dependencies: + "@eslint-community/regexpp" "^4.12.2" + "@typescript-eslint/scope-manager" "8.54.0" + "@typescript-eslint/type-utils" "8.54.0" + "@typescript-eslint/utils" "8.54.0" + "@typescript-eslint/visitor-keys" "8.54.0" + ignore "^7.0.5" + natural-compare "^1.4.0" + ts-api-utils "^2.4.0" + +"@typescript-eslint/eslint-plugin@^8.33.1": + version "8.33.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-8.33.1.tgz#532641b416ed2afd5be893cddb2a58e9cd1f7a3e" + integrity sha512-TDCXj+YxLgtvxvFlAvpoRv9MAncDLBV2oT9Bd7YBGC/b/sEURoOYuIwLI99rjWOfY3QtDzO+mk0n4AmdFExW8A== + dependencies: + "@eslint-community/regexpp" "^4.10.0" + "@typescript-eslint/scope-manager" "8.33.1" + "@typescript-eslint/type-utils" "8.33.1" + "@typescript-eslint/utils" "8.33.1" + "@typescript-eslint/visitor-keys" "8.33.1" + graphemer "^1.4.0" + ignore "^7.0.0" + natural-compare "^1.4.0" + ts-api-utils "^2.1.0" + +"@typescript-eslint/parser@8.54.0": + version "8.54.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.54.0.tgz#3d01a6f54ed247deb9982621f70e7abf1810bd97" + integrity sha512-BtE0k6cjwjLZoZixN0t5AKP0kSzlGu7FctRXYuPAm//aaiZhmfq1JwdYpYr1brzEspYyFeF+8XF5j2VK6oalrA== + dependencies: + "@typescript-eslint/scope-manager" "8.54.0" + "@typescript-eslint/types" "8.54.0" + "@typescript-eslint/typescript-estree" "8.54.0" + "@typescript-eslint/visitor-keys" "8.54.0" + debug "^4.4.3" + +"@typescript-eslint/parser@^8.33.1": + version "8.33.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-8.33.1.tgz#ef9a5ee6aa37a6b4f46cc36d08a14f828238afe2" + integrity sha512-qwxv6dq682yVvgKKp2qWwLgRbscDAYktPptK4JPojCwwi3R9cwrvIxS4lvBpzmcqzR4bdn54Z0IG1uHFskW4dA== + dependencies: + "@typescript-eslint/scope-manager" "8.33.1" + "@typescript-eslint/types" "8.33.1" + "@typescript-eslint/typescript-estree" "8.33.1" + "@typescript-eslint/visitor-keys" "8.33.1" + debug "^4.3.4" + +"@typescript-eslint/project-service@8.33.1": + version "8.33.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.33.1.tgz#c85e7d9a44d6a11fe64e73ac1ed47de55dc2bf9f" + integrity sha512-DZR0efeNklDIHHGRpMpR5gJITQpu6tLr9lDJnKdONTC7vvzOlLAG/wcfxcdxEWrbiZApcoBCzXqU/Z458Za5Iw== + dependencies: + "@typescript-eslint/tsconfig-utils" "^8.33.1" + "@typescript-eslint/types" "^8.33.1" + debug "^4.3.4" + +"@typescript-eslint/project-service@8.54.0": + version "8.54.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/project-service/-/project-service-8.54.0.tgz#f582aceb3d752544c8e1b11fea8d95d00cf9adc6" + integrity sha512-YPf+rvJ1s7MyiWM4uTRhE4DvBXrEV+d8oC3P9Y2eT7S+HBS0clybdMIPnhiATi9vZOYDc7OQ1L/i6ga6NFYK/g== + dependencies: + "@typescript-eslint/tsconfig-utils" "^8.54.0" + "@typescript-eslint/types" "^8.54.0" + debug "^4.4.3" + +"@typescript-eslint/scope-manager@8.33.1": + version "8.33.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.33.1.tgz#d1e0efb296da5097d054bc9972e69878a2afea73" + integrity sha512-dM4UBtgmzHR9bS0Rv09JST0RcHYearoEoo3pG5B6GoTR9XcyeqX87FEhPo+5kTvVfKCvfHaHrcgeJQc6mrDKrA== + dependencies: + "@typescript-eslint/types" "8.33.1" + "@typescript-eslint/visitor-keys" "8.33.1" + +"@typescript-eslint/scope-manager@8.54.0": + version "8.54.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-8.54.0.tgz#307dc8cbd80157e2772c2d36216857415a71ab33" + integrity sha512-27rYVQku26j/PbHYcVfRPonmOlVI6gihHtXFbTdB5sb6qA0wdAQAbyXFVarQ5t4HRojIz64IV90YtsjQSSGlQg== + dependencies: + "@typescript-eslint/types" "8.54.0" + "@typescript-eslint/visitor-keys" "8.54.0" + +"@typescript-eslint/tsconfig-utils@8.33.1", "@typescript-eslint/tsconfig-utils@^8.33.1": + version "8.33.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.33.1.tgz#7836afcc097a4657a5ed56670851a450d8b70ab8" + integrity sha512-STAQsGYbHCF0/e+ShUQ4EatXQ7ceh3fBCXkNU7/MZVKulrlq1usH7t2FhxvCpuCi5O5oi1vmVaAjrGeL71OK1g== + +"@typescript-eslint/tsconfig-utils@8.54.0", "@typescript-eslint/tsconfig-utils@^8.54.0": + version "8.54.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/tsconfig-utils/-/tsconfig-utils-8.54.0.tgz#71dd7ba1674bd48b172fc4c85b2f734b0eae3dbc" + integrity sha512-dRgOyT2hPk/JwxNMZDsIXDgyl9axdJI3ogZ2XWhBPsnZUv+hPesa5iuhdYt2gzwA9t8RE5ytOJ6xB0moV0Ujvw== + +"@typescript-eslint/type-utils@8.33.1": + version "8.33.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.33.1.tgz#d73ee1a29d8a0abe60d4abbff4f1d040f0de15fa" + integrity sha512-1cG37d9xOkhlykom55WVwG2QRNC7YXlxMaMzqw2uPeJixBFfKWZgaP/hjAObqMN/u3fr5BrTwTnc31/L9jQ2ww== + dependencies: + "@typescript-eslint/typescript-estree" "8.33.1" + "@typescript-eslint/utils" "8.33.1" + debug "^4.3.4" + ts-api-utils "^2.1.0" + +"@typescript-eslint/type-utils@8.54.0": + version "8.54.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/type-utils/-/type-utils-8.54.0.tgz#64965317dd4118346c2fa5ee94492892200e9fb9" + integrity sha512-hiLguxJWHjjwL6xMBwD903ciAwd7DmK30Y9Axs/etOkftC3ZNN9K44IuRD/EB08amu+Zw6W37x9RecLkOo3pMA== + dependencies: + "@typescript-eslint/types" "8.54.0" + "@typescript-eslint/typescript-estree" "8.54.0" + "@typescript-eslint/utils" "8.54.0" + debug "^4.4.3" + ts-api-utils "^2.4.0" + +"@typescript-eslint/types@8.33.1", "@typescript-eslint/types@^8.33.1": + version "8.33.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.33.1.tgz#b693111bc2180f8098b68e9958cf63761657a55f" + integrity sha512-xid1WfizGhy/TKMTwhtVOgalHwPtV8T32MS9MaH50Cwvz6x6YqRIPdD2WvW0XaqOzTV9p5xdLY0h/ZusU5Lokg== + +"@typescript-eslint/types@8.54.0", "@typescript-eslint/types@^8.54.0": + version "8.54.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-8.54.0.tgz#c12d41f67a2e15a8a96fbc5f2d07b17331130889" + integrity sha512-PDUI9R1BVjqu7AUDsRBbKMtwmjWcn4J3le+5LpcFgWULN3LvHC5rkc9gCVxbrsrGmO1jfPybN5s6h4Jy+OnkAA== + +"@typescript-eslint/typescript-estree@8.33.1": + version "8.33.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.33.1.tgz#d271beed470bc915b8764e22365d4925c2ea265d" + integrity sha512-+s9LYcT8LWjdYWu7IWs7FvUxpQ/DGkdjZeE/GGulHvv8rvYwQvVaUZ6DE+j5x/prADUgSbbCWZ2nPI3usuVeOA== + dependencies: + "@typescript-eslint/project-service" "8.33.1" + "@typescript-eslint/tsconfig-utils" "8.33.1" + "@typescript-eslint/types" "8.33.1" + "@typescript-eslint/visitor-keys" "8.33.1" + debug "^4.3.4" + fast-glob "^3.3.2" + is-glob "^4.0.3" + minimatch "^9.0.4" + semver "^7.6.0" + ts-api-utils "^2.1.0" + +"@typescript-eslint/typescript-estree@8.54.0": + version "8.54.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-8.54.0.tgz#3c7716905b2b811fadbd2114804047d1bfc86527" + integrity sha512-BUwcskRaPvTk6fzVWgDPdUndLjB87KYDrN5EYGetnktoeAvPtO4ONHlAZDnj5VFnUANg0Sjm7j4usBlnoVMHwA== + dependencies: + "@typescript-eslint/project-service" "8.54.0" + "@typescript-eslint/tsconfig-utils" "8.54.0" + "@typescript-eslint/types" "8.54.0" + "@typescript-eslint/visitor-keys" "8.54.0" + debug "^4.4.3" + minimatch "^9.0.5" + semver "^7.7.3" + tinyglobby "^0.2.15" + ts-api-utils "^2.4.0" + +"@typescript-eslint/utils@8.33.1": + version "8.33.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.33.1.tgz#ea22f40d3553da090f928cf17907e963643d4b96" + integrity sha512-52HaBiEQUaRYqAXpfzWSR2U3gxk92Kw006+xZpElaPMg3C4PgM+A5LqwoQI1f9E5aZ/qlxAZxzm42WX+vn92SQ== + dependencies: + "@eslint-community/eslint-utils" "^4.7.0" + "@typescript-eslint/scope-manager" "8.33.1" + "@typescript-eslint/types" "8.33.1" + "@typescript-eslint/typescript-estree" "8.33.1" + +"@typescript-eslint/utils@8.54.0": + version "8.54.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/utils/-/utils-8.54.0.tgz#c79a4bcbeebb4f571278c0183ed1cb601d84c6c8" + integrity sha512-9Cnda8GS57AQakvRyG0PTejJNlA2xhvyNtEVIMlDWOOeEyBkYWhGPnfrIAnqxLMTSTo6q8g12XVjjev5l1NvMA== + dependencies: + "@eslint-community/eslint-utils" "^4.9.1" + "@typescript-eslint/scope-manager" "8.54.0" + "@typescript-eslint/types" "8.54.0" + "@typescript-eslint/typescript-estree" "8.54.0" + +"@typescript-eslint/visitor-keys@8.33.1": + version "8.33.1" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.33.1.tgz#6c6e002c24d13211df3df851767f24dfdb4f42bc" + integrity sha512-3i8NrFcZeeDHJ+7ZUuDkGT+UHq+XoFGsymNK2jZCOHcfEzRQ0BdpRtdpSx/Iyf3MHLWIcLS0COuOPibKQboIiQ== + dependencies: + "@typescript-eslint/types" "8.33.1" + eslint-visitor-keys "^4.2.0" -"@typescript-eslint/visitor-keys@4.33.0": - version "4.33.0" - resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.33.0.tgz#2a22f77a41604289b7a186586e9ec48ca92ef1dd" - integrity sha512-uqi/2aSz9g2ftcHWf8uLPJA70rUv6yuMW5Bohw+bwcuzaxQIHaKFZCKGoGXIrc9vkTJ3+0txM73K0Hq3d5wgIg== +"@typescript-eslint/visitor-keys@8.54.0": + version "8.54.0" + resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-8.54.0.tgz#0e4b50124b210b8600b245dd66cbad52deb15590" + integrity sha512-VFlhGSl4opC0bprJiItPQ1RfUhGDIBokcPwaFH4yiBCaNPeld/9VeXbiPO1cLyorQi1G1vL+ecBk1x8o1axORA== dependencies: - "@typescript-eslint/types" "4.33.0" - eslint-visitor-keys "^2.0.0" + "@typescript-eslint/types" "8.54.0" + eslint-visitor-keys "^4.2.1" "@webassemblyjs/ast@1.12.1", "@webassemblyjs/ast@^1.12.1": version "1.12.1" @@ -1451,6 +1594,11 @@ acorn@^8.14.0: resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.14.0.tgz#063e2c70cac5fb4f6467f0b11152e04c682795b0" integrity sha512-cl669nCJTZBsL97OF4kUQm5g5hC2uihk0NxY3WENAC0TYdILVkAyHymAntgxGkl7K+t0cXIrH5siy5S4XkFycA== +acorn@^8.15.0: + version "8.15.0" + resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.15.0.tgz#a360898bc415edaac46c8241f6383975b930b816" + integrity sha512-NZyJarBfL7nWwIq+FDL6Zp/yHEhePMNnnJ0y3qfieCrmNvYct8uvtiV41UvlSe6apAfk0fY1FbWx+NwfmpvtTg== + acorn@^8.7.1, acorn@^8.8.2: version "8.11.3" resolved "https://registry.yarnpkg.com/acorn/-/acorn-8.11.3.tgz#71e0b14e13a4ec160724b38fb7b0f233b1b81d7a" @@ -1498,11 +1646,6 @@ argparse@^2.0.1: resolved "https://registry.yarnpkg.com/argparse/-/argparse-2.0.1.tgz#246f50f3ca78a3240f6c997e8a9bd1eac49e4b38" integrity sha512-8+9WqebbFzpX9OR+Wa6O29asIogeRMzcGtAINdpMHHyAg10f05aSFVBbcEqGf/PXw1EjAZ+q2/bEBg3DvurK3Q== -array-union@^2.1.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/array-union/-/array-union-2.1.0.tgz#b798420adbeb1de828d84acd8a2e23d3efe85e8d" - integrity sha512-HGyxoOTYUyCM6stUe6EJgnd4EoewAI7zMdfqO+kGjnlZmBDz/cR5pf8r/cR4Wq60sL/p0IkcjUEEPwS3GFrIyw== - babel-loader@^8.2.2: version "8.3.0" resolved "https://registry.yarnpkg.com/babel-loader/-/babel-loader-8.3.0.tgz#124936e841ba4fe8176786d6ff28add1f134d6a8" @@ -1560,7 +1703,21 @@ brace-expansion@^1.1.7: balanced-match "^1.0.0" concat-map "0.0.1" -braces@^3.0.2, braces@~3.0.2: +brace-expansion@^2.0.1: + version "2.0.1" + resolved "https://registry.yarnpkg.com/brace-expansion/-/brace-expansion-2.0.1.tgz#1edc459e0f0c548486ecf9fc99f2221364b9a0ae" + integrity sha512-XnAIvQ8eM+kC6aULx6wuQiwVsnzsi9d3WxzV3FpWTGA19F621kwdbsAcFKXgKUHZWsy+mY6iL1sHTxWEFCytDA== + dependencies: + balanced-match "^1.0.0" + +braces@^3.0.3: + version "3.0.3" + resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.3.tgz#490332f40919452272d55a8480adc0c441358789" + integrity sha512-yQbXgO/OSZVD2IsiLlro+7Hf6Q18EJrKSEsdoMzKePKXct3gvD8oLcOQdIzGupr5Fj+EDe8gO/lxc1BzfMpxvA== + dependencies: + fill-range "^7.1.1" + +braces@~3.0.2: version "3.0.2" resolved "https://registry.yarnpkg.com/braces/-/braces-3.0.2.tgz#3454e1a462ee8d599e236df336cd9ea4f8afe107" integrity sha512-b8um+L1RzM3WDSzvhm6gIz1yfTbBt6YTlcEKAvsmqCZZFw46z626lVj9j1yEPW33H5H+lBQpZMP1k8l+78Ha0A== @@ -1709,6 +1866,11 @@ core-js@^3.16.4: resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.37.0.tgz#d8dde58e91d156b2547c19d8a4efd5c7f6c426bb" integrity sha512-fu5vHevQ8ZG4og+LXug8ulUtVxjOcEYvifJr7L5Bfq9GOztVqsKd9/59hUk2ZSbCrS3BqUr3EpaYGIYzq7g3Ug== +core-js@^3.47.0: + version "3.48.0" + resolved "https://registry.yarnpkg.com/core-js/-/core-js-3.48.0.tgz#1f813220a47bbf0e667e3885c36cd6f0593bf14d" + integrity sha512-zpEHTy1fjTMZCKLHUZoVeylt9XrzaIN2rbPXEt0k+q7JE5CkCZdo6bNq55bn24a69CH7ErAVLKijxJja4fw+UQ== + cross-spawn@^7.0.3: version "7.0.3" resolved "https://registry.yarnpkg.com/cross-spawn/-/cross-spawn-7.0.3.tgz#f73a85b9d5d41d045551c177e2882d4ac85728a6" @@ -1727,6 +1889,16 @@ cross-spawn@^7.0.6: shebang-command "^2.0.0" which "^2.0.1" +data-of-loathing@^2.2.0: + version "2.2.0" + resolved "https://registry.yarnpkg.com/data-of-loathing/-/data-of-loathing-2.2.0.tgz#2e5055ca66b1f685a3cc6c6b10178bc14744d636" + integrity sha512-RNVwnWeWjcNw706+bpmTG9BGXNEKYeXP+Nt+zjJfcZq8MX6dHJSJCnzmtClSrQvTvrlB0DKAkR+H0WIHuXnjpA== + +data-of-loathing@^2.6.2: + version "2.6.2" + resolved "https://registry.yarnpkg.com/data-of-loathing/-/data-of-loathing-2.6.2.tgz#b3f12d348dba44e4e3b4e892f36c2938d40bc1ee" + integrity sha512-/cldchEU08vJTx0HTP7Cxl1yMOuWfQa9yPFcOFfOzxdPyPsp8/L9ZtmTqWuJyL80rVz+gZa2GyLGQ24oLbxaaQ== + debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2: version "4.3.4" resolved "https://registry.yarnpkg.com/debug/-/debug-4.3.4.tgz#1319f6579357f2338d3337d2cdd4914bb5dcc865" @@ -1734,18 +1906,25 @@ debug@^4.1.0, debug@^4.1.1, debug@^4.3.1, debug@^4.3.2: dependencies: ms "2.1.2" +debug@^4.3.4: + version "4.4.1" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.1.tgz#e5a8bc6cbc4c6cd3e64308b0693a3d4fa550189b" + integrity sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ== + dependencies: + ms "^2.1.3" + +debug@^4.4.3: + version "4.4.3" + resolved "https://registry.yarnpkg.com/debug/-/debug-4.4.3.tgz#c6ae432d9bd9662582fce08709b038c58e9e3d6a" + integrity sha512-RGwwWnwQvkVfavKVt22FGLw+xYSdzARwm0ru6DhTVA3umU5hZc28V3kO4stgYryrTlLpuvgI9GiijltAjNbcqA== + dependencies: + ms "^2.1.3" + deep-is@^0.1.3: version "0.1.4" resolved "https://registry.yarnpkg.com/deep-is/-/deep-is-0.1.4.tgz#a6f2dce612fadd2ef1f519b73551f17e85199831" integrity sha512-oIPzksmTg4/MriiaYGO+okXDT7ztn/w3Eptv/+gSIdMdKsJo0u4CfYNFJPy+4SKMuCqGw2wxnA+URMg3t8a/bQ== -dir-glob@^3.0.1: - version "3.0.1" - resolved "https://registry.yarnpkg.com/dir-glob/-/dir-glob-3.0.1.tgz#56dbf73d992a4a93ba1584f4534063fd2e41717f" - integrity sha512-WkrWp9GR4KXfKGYzOLmTuGVi1UWFfws377n9cc55/tb6DuqyF6pcQ5AbiHEshaDpY9v6oaSr2XCDidGmMwdzIA== - dependencies: - path-type "^4.0.0" - electron-to-chromium@^1.4.668: version "1.4.756" resolved "https://registry.yarnpkg.com/electron-to-chromium/-/electron-to-chromium-1.4.756.tgz#7b872ed8c8c5bee571be771730225d6d2a37fe45" @@ -1764,6 +1943,11 @@ enhanced-resolve@^5.16.0: graceful-fs "^4.2.4" tapable "^2.2.0" +entities@^7.0.0: + version "7.0.0" + resolved "https://registry.yarnpkg.com/entities/-/entities-7.0.0.tgz#2ae4e443f3f17d152d3f5b0f79b932c1e59deb7a" + integrity sha512-FDWG5cmEYf2Z00IkYRhbFrwIwvdFKH07uV8dvNy0omp/Qb1xcyCWp2UDtcwJF4QZZvk0sLudP6/hAu42TaqVhQ== + envinfo@^7.7.3: version "7.13.0" resolved "https://registry.yarnpkg.com/envinfo/-/envinfo-7.13.0.tgz#81fbb81e5da35d74e814941aeab7c325a606fb31" @@ -1789,20 +1973,20 @@ escape-string-regexp@^4.0.0: resolved "https://registry.yarnpkg.com/escape-string-regexp/-/escape-string-regexp-4.0.0.tgz#14ba83a5d373e3d311e5afca29cf5bfad965bf34" integrity sha512-TtpcNJ3XAzx3Gq8sWRzJaVajRs0uVxA2YAkdb1jm2YkPz4G6egUFAyA3n5vtEIZefPk5Wa4UXbKuS5fKkJWdgA== -eslint-config-prettier@^8.3.0: - version "8.10.0" - resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-8.10.0.tgz#3a06a662130807e2502fc3ff8b4143d8a0658e11" - integrity sha512-SM8AMJdeQqRYT9O9zguiruQZaN7+z+E4eAP9oiLNGKMtomwaB1E9dcgUD6ZAn/eQAb52USbvezbiljfZUhbJcg== +eslint-config-prettier@^10.1.8: + version "10.1.8" + resolved "https://registry.yarnpkg.com/eslint-config-prettier/-/eslint-config-prettier-10.1.8.tgz#15734ce4af8c2778cc32f0b01b37b0b5cd1ecb97" + integrity sha512-82GZUjRS0p/jganf6q1rEO25VSoHH0hKPCTrgillPjdI/3bgBhAE1QzHrHTizjpRvy6pGAvKjDJtk2pF9NDq8w== -eslint-plugin-libram@^0.4.16: - version "0.4.21" - resolved "https://registry.yarnpkg.com/eslint-plugin-libram/-/eslint-plugin-libram-0.4.21.tgz#0db49bedd807f256bc01496622065d735c5ffc2e" - integrity sha512-wSS2Uqty4lE+08NT4614I8j19gHN7rEs4MOn6hXRTgfB7ES0mIsf2+bLuVNNpknkryF49yvT/znzmAN2JhoAnw== +eslint-plugin-libram@^0.5.3: + version "0.5.3" + resolved "https://registry.yarnpkg.com/eslint-plugin-libram/-/eslint-plugin-libram-0.5.3.tgz#287dae19267ccad78c44145229afaac9165fb616" + integrity sha512-F2mLTf5T1OxP9VX8tA8gRSJJqHVHihCoJKTJEDOwYgEDuexeoxaBnnroc2lCYdvsCn1H+DFKFsYsL7zJFsfsrg== dependencies: - html-entities "^2.5.2" - requireindex "~1.2.0" + data-of-loathing "^2.6.2" + entities "^7.0.0" -eslint-scope@5.1.1, eslint-scope@^5.1.1: +eslint-scope@5.1.1: version "5.1.1" resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-5.1.1.tgz#e786e59a66cb92b3f6c1fb0d508aab174848f48c" integrity sha512-2NxwbF/hZ0KpepYN0cNbo+FN6XoK7GaHlQhgx/hIZl6Va0bF45RQOOwhLIy8lQDbuCiadSLCBnH2CFYquit5bw== @@ -1810,27 +1994,15 @@ eslint-scope@5.1.1, eslint-scope@^5.1.1: esrecurse "^4.3.0" estraverse "^4.1.1" -eslint-scope@^8.2.0: - version "8.2.0" - resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.2.0.tgz#377aa6f1cb5dc7592cfd0b7f892fd0cf352ce442" - integrity sha512-PHlWUfG6lvPc3yvP5A4PNyBL1W8fkDUccmI21JUu/+GKZBoH/W5u6usENXUrWFRsyoW5ACUjFGgAFQp5gUlb/A== +eslint-scope@^8.4.0: + version "8.4.0" + resolved "https://registry.yarnpkg.com/eslint-scope/-/eslint-scope-8.4.0.tgz#88e646a207fad61436ffa39eb505147200655c82" + integrity sha512-sNXOfKCn74rt8RICKMvJS7XKV/Xk9kA7DyJr8mJik3S7Cwgy3qlkkmyS2uQB3jiJg6VNdZd/pDBJu0nvG2NlTg== dependencies: esrecurse "^4.3.0" estraverse "^5.2.0" -eslint-utils@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/eslint-utils/-/eslint-utils-3.0.0.tgz#8aebaface7345bb33559db0a1f13a1d2d48c3672" - integrity sha512-uuQC43IGctw68pJA1RgbQS8/NP7rch6Cwd4j3ZBtgo4/8Flj4eGE7ZYSZRN3iq5pVUv6GPdW5Z1RFleo84uLDA== - dependencies: - eslint-visitor-keys "^2.0.0" - -eslint-visitor-keys@^2.0.0: - version "2.1.0" - resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.1.0.tgz#f65328259305927392c938ed44eb0a5c9b2bd303" - integrity sha512-0rSmRBzXgDzIsD6mGdJgevzgezI534Cer5L/vyMX0kHzT/jiB43jRhd9YUlMGYLQy2zprNmoT8qasCGtY+QaKw== - -eslint-visitor-keys@^3.3.0: +eslint-visitor-keys@^3.4.3: version "3.4.3" resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-3.4.3.tgz#0cd72fe8550e3c2eae156a96a4dddcd1c8ac5800" integrity sha512-wpc+LXeiyiisxPlEkUzU6svyS1frIO3Mgxj1fdy7Pm8Ygzguax2N3Fa/D/ag1WqbOprdI+uY6wMUl8/a2G+iag== @@ -1840,31 +2012,36 @@ eslint-visitor-keys@^4.2.0: resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.0.tgz#687bacb2af884fcdda8a6e7d65c606f46a14cd45" integrity sha512-UyLnSehNt62FFhSwjZlHmeokpRK59rcz29j+F1/aDgbkbRTk7wIc9XzdoasMUbRNKDM0qQt/+BJ4BrpFeABemw== -eslint@^9.17.0: - version "9.17.0" - resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.17.0.tgz#faa1facb5dd042172fdc520106984b5c2421bb0c" - integrity sha512-evtlNcpJg+cZLcnVKwsai8fExnqjGPicK7gnUtlNuzu+Fv9bI0aLpND5T44VLQtoMEnI57LoXO9XAkIXwohKrA== +eslint-visitor-keys@^4.2.1: + version "4.2.1" + resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-4.2.1.tgz#4cfea60fe7dd0ad8e816e1ed026c1d5251b512c1" + integrity sha512-Uhdk5sfqcee/9H/rCOJikYz67o0a2Tw2hGRPOG2Y1R2dg7brRe1uG0yaNQDHu+TO/uQPF/5eCapvYSmHUjt7JQ== + +eslint@^9.39.2: + version "9.39.2" + resolved "https://registry.yarnpkg.com/eslint/-/eslint-9.39.2.tgz#cb60e6d16ab234c0f8369a3fe7cc87967faf4b6c" + integrity sha512-LEyamqS7W5HB3ujJyvi0HQK/dtVINZvd5mAAp9eT5S/ujByGjiZLCzPcHVzuXbpJDJF/cxwHlfceVUDZ2lnSTw== dependencies: - "@eslint-community/eslint-utils" "^4.2.0" + "@eslint-community/eslint-utils" "^4.8.0" "@eslint-community/regexpp" "^4.12.1" - "@eslint/config-array" "^0.19.0" - "@eslint/core" "^0.9.0" - "@eslint/eslintrc" "^3.2.0" - "@eslint/js" "9.17.0" - "@eslint/plugin-kit" "^0.2.3" + "@eslint/config-array" "^0.21.1" + "@eslint/config-helpers" "^0.4.2" + "@eslint/core" "^0.17.0" + "@eslint/eslintrc" "^3.3.1" + "@eslint/js" "9.39.2" + "@eslint/plugin-kit" "^0.4.1" "@humanfs/node" "^0.16.6" "@humanwhocodes/module-importer" "^1.0.1" - "@humanwhocodes/retry" "^0.4.1" + "@humanwhocodes/retry" "^0.4.2" "@types/estree" "^1.0.6" - "@types/json-schema" "^7.0.15" ajv "^6.12.4" chalk "^4.0.0" cross-spawn "^7.0.6" debug "^4.3.2" escape-string-regexp "^4.0.0" - eslint-scope "^8.2.0" - eslint-visitor-keys "^4.2.0" - espree "^10.3.0" + eslint-scope "^8.4.0" + eslint-visitor-keys "^4.2.1" + espree "^10.4.0" esquery "^1.5.0" esutils "^2.0.2" fast-deep-equal "^3.1.3" @@ -1880,7 +2057,7 @@ eslint@^9.17.0: natural-compare "^1.4.0" optionator "^0.9.3" -espree@^10.0.1, espree@^10.3.0: +espree@^10.0.1: version "10.3.0" resolved "https://registry.yarnpkg.com/espree/-/espree-10.3.0.tgz#29267cf5b0cb98735b65e64ba07e0ed49d1eed8a" integrity sha512-0QYC8b24HWY8zjRnDTL6RiHfDbAWn63qb4LMj1Z4b076A4une81+z03Kg7l7mn/48PUTqoLptSXez8oknU8Clg== @@ -1889,6 +2066,15 @@ espree@^10.0.1, espree@^10.3.0: acorn-jsx "^5.3.2" eslint-visitor-keys "^4.2.0" +espree@^10.4.0: + version "10.4.0" + resolved "https://registry.yarnpkg.com/espree/-/espree-10.4.0.tgz#d54f4949d4629005a1fa168d937c3ff1f7e2a837" + integrity sha512-j6PAQ2uUr79PZhBjP5C5fhl8e39FmRnOjsD5lGnWrFU8i2G776tBK7+nP8KuQUTTyAZUwfQqXAgrVH5MbH9CYQ== + dependencies: + acorn "^8.15.0" + acorn-jsx "^5.3.2" + eslint-visitor-keys "^4.2.1" + esquery@^1.5.0: version "1.6.0" resolved "https://registry.yarnpkg.com/esquery/-/esquery-1.6.0.tgz#91419234f804d852a82dceec3e16cdc22cf9dae7" @@ -1928,16 +2114,16 @@ fast-deep-equal@^3.1.1, fast-deep-equal@^3.1.3: resolved "https://registry.yarnpkg.com/fast-deep-equal/-/fast-deep-equal-3.1.3.tgz#3a7d56b559d6cbc3eb512325244e619a65c6c525" integrity sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q== -fast-glob@^3.2.9: - version "3.3.2" - resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.2.tgz#a904501e57cfdd2ffcded45e99a54fef55e46129" - integrity sha512-oX2ruAFQwf/Orj8m737Y5adxDQO0LAB7/S5MnxCdTNDd4p6BsyIVsv9JQsATbTSq8KHRpLwIHbVlUNatxd+1Ow== +fast-glob@^3.3.2: + version "3.3.3" + resolved "https://registry.yarnpkg.com/fast-glob/-/fast-glob-3.3.3.tgz#d06d585ce8dba90a16b0505c543c3ccfb3aeb818" + integrity sha512-7MptL8U0cqcFdzIzwOTHoilX9x5BrNqye7Z/LuC7kCMRio1EMSyqRK3BEAUD7sXRq4iT4AzTVuZdhgQ2TCvYLg== dependencies: "@nodelib/fs.stat" "^2.0.2" "@nodelib/fs.walk" "^1.2.3" glob-parent "^5.1.2" merge2 "^1.3.0" - micromatch "^4.0.4" + micromatch "^4.0.8" fast-json-stable-stringify@^2.0.0: version "2.1.0" @@ -1961,6 +2147,11 @@ fastq@^1.6.0: dependencies: reusify "^1.0.4" +fdir@^6.5.0: + version "6.5.0" + resolved "https://registry.yarnpkg.com/fdir/-/fdir-6.5.0.tgz#ed2ab967a331ade62f18d077dae192684d50d350" + integrity sha512-tIbYtZbucOs0BRGqPJkshJUYdL+SDH7dVM8gjy+ERp3WAUjLEFJE+02kanyHtwjWOnwrKYBiwAmM0p4kLJAnXg== + file-entry-cache@^8.0.0: version "8.0.0" resolved "https://registry.yarnpkg.com/file-entry-cache/-/file-entry-cache-8.0.0.tgz#7787bddcf1131bffb92636c69457bbc0edd6d81f" @@ -1975,6 +2166,13 @@ fill-range@^7.0.1: dependencies: to-regex-range "^5.0.1" +fill-range@^7.1.1: + version "7.1.1" + resolved "https://registry.yarnpkg.com/fill-range/-/fill-range-7.1.1.tgz#44265d3cac07e3ea7dc247516380643754a05292" + integrity sha512-YsGpe3WHLK8ZYi4tWDg2Jy3ebRz2rXowDxnld4bkQB00cc/1Zw9AWnC0i9ztDJitivtQvaI9KaLyKrc+hBW0yg== + dependencies: + to-regex-range "^5.0.1" + find-cache-dir@^3.3.1: version "3.3.2" resolved "https://registry.yarnpkg.com/find-cache-dir/-/find-cache-dir-3.3.2.tgz#b30c5b6eff0730731aea9bbd9dbecbd80256d64b" @@ -2038,11 +2236,6 @@ function-bind@^1.1.2: resolved "https://registry.yarnpkg.com/function-bind/-/function-bind-1.1.2.tgz#2c02d864d97f3ea6c8830c464cbd11ab6eab7a1c" integrity sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA== -functional-red-black-tree@^1.0.1: - version "1.0.1" - resolved "https://registry.yarnpkg.com/functional-red-black-tree/-/functional-red-black-tree-1.0.1.tgz#1b0ab3bd553b2a0d6399d29c0e3ea0b252078327" - integrity sha512-dsKNQNdj6xA3T+QlADDA7mOSlX0qiMINjn0cgr+eGHGsbSHzTabcIogz2+p/iqP1Xs6EP/sS2SbqH+brGTbq0g== - garbo-lib@^0.0.1: version "0.0.1" resolved "https://registry.yarnpkg.com/garbo-lib/-/garbo-lib-0.0.1.tgz#260324142563e7c1ba6663d63a63c2f557472955" @@ -2094,27 +2287,20 @@ globals@^14.0.0: resolved "https://registry.yarnpkg.com/globals/-/globals-14.0.0.tgz#898d7413c29babcf6bafe56fcadded858ada724e" integrity sha512-oahGvuMGQlPw/ivIYBjVSrWAfWLBeku5tpPE2fOPLi+WHffIWbuh2tCjhyQhTBPMf5E9jDEH4FOmTYgYwbKwtQ== -globby@^11.0.3: - version "11.1.0" - resolved "https://registry.yarnpkg.com/globby/-/globby-11.1.0.tgz#bd4be98bb042f83d796f7e3811991fbe82a0d34b" - integrity sha512-jhIXaOzy1sb8IyocaruWSn1TjmnBVs8Ayhcy83rmxNJ8q2uWKCAj3CnJY+KpGSXCueAPc0i05kVvVKtP1t9S3g== - dependencies: - array-union "^2.1.0" - dir-glob "^3.0.1" - fast-glob "^3.2.9" - ignore "^5.2.0" - merge2 "^1.4.1" - slash "^3.0.0" - graceful-fs@^4.1.2, graceful-fs@^4.2.11, graceful-fs@^4.2.4: version "4.2.11" resolved "https://registry.yarnpkg.com/graceful-fs/-/graceful-fs-4.2.11.tgz#4183e4e8bf08bb6e05bbb2f7d2e0c8f712ca40e3" integrity sha512-RbJ5/jmFcNNCcDV5o9eTnBLJ/HszWV0P73bc+Ff4nS/rJj+YaS6IGyiOL0VoBYX+l1Wrl3k63h/KrH+nhJ0XvQ== -grimoire-kolmafia@^0.3.25: - version "0.3.26" - resolved "https://registry.yarnpkg.com/grimoire-kolmafia/-/grimoire-kolmafia-0.3.26.tgz#651eeb440f1ae29be9c209abd4848638e2fae990" - integrity sha512-lePvPPpFsHBdjtA+nxwfPXu0eKyDt4kLEeTo3Alhe8NE1iFG6nMo9HypQPOKXstjUdSPVu0Uj2bR9cwdAQPZDw== +graphemer@^1.4.0: + version "1.4.0" + resolved "https://registry.yarnpkg.com/graphemer/-/graphemer-1.4.0.tgz#fb2f1d55e0e3a1849aeffc90c4fa0dd53a0e66c6" + integrity sha512-EtKwoO6kxCL9WO5xipiHTZlSzBm7WLT627TqC/uVRd0HKmq8NXyebnNYxDoBi7wt8eTWrUrKXCOVaFq9x1kgag== + +grimoire-kolmafia@^0.3.33: + version "0.3.33" + resolved "https://registry.yarnpkg.com/grimoire-kolmafia/-/grimoire-kolmafia-0.3.33.tgz#b56fa60cba48aea3fde88d68090ed2174a607b78" + integrity sha512-yidkJES1IKMAGuqAw8OLgX7p/XBcdDNXs2yt6zjP640ZgwFQKfLgxm42pdK/dt9WGzlSKMjIwrosndsENnOBNQ== dependencies: core-js "^3.16.4" @@ -2135,16 +2321,16 @@ hasown@^2.0.0: dependencies: function-bind "^1.1.2" -html-entities@^2.5.2: - version "2.5.2" - resolved "https://registry.yarnpkg.com/html-entities/-/html-entities-2.5.2.tgz#201a3cf95d3a15be7099521620d19dfb4f65359f" - integrity sha512-K//PSRMQk4FZ78Kyau+mZurHn3FH0Vwr+H36eE0rPbeYkRRi9YxceYPhuN60UwWorxyKHhqoAJl2OFKa4BVtaA== - -ignore@^5.1.8, ignore@^5.2.0: +ignore@^5.2.0: version "5.3.1" resolved "https://registry.yarnpkg.com/ignore/-/ignore-5.3.1.tgz#5073e554cd42c5b33b394375f538b8593e34d4ef" integrity sha512-5Fytz/IraMjqpwfd34ke28PTVMjZjJG2MPn5t7OE4eUCUNf8BAa7b5WUS9/Qvr6mwOQS7Mk6vdsMno5he+T8Xw== +ignore@^7.0.0, ignore@^7.0.5: + version "7.0.5" + resolved "https://registry.yarnpkg.com/ignore/-/ignore-7.0.5.tgz#4cb5f6cd7d4c7ab0365738c7aea888baa6d7efd9" + integrity sha512-Hs59xBNfUIunMFgWAbGX5cq6893IbWg4KnrjbYwX3tx0ztorVgTDA6B2sxf8ejHJ4wz8BqGUMYlnzNBer5NvGg== + import-fresh@^3.2.1: version "3.3.0" resolved "https://registry.yarnpkg.com/import-fresh/-/import-fresh-3.3.0.tgz#37162c25fcb9ebaa2e6e53d5b4d88ce17d9e0c2b" @@ -2300,10 +2486,17 @@ kind-of@^6.0.2: resolved "https://registry.yarnpkg.com/kind-of/-/kind-of-6.0.3.tgz#07c05034a6c349fa06e24fa35aa76db4580ce4dd" integrity sha512-dcS1ul+9tmeD95T+x28/ehLgd9mENa3LsvDTtzm3vyBEO7RPptvAD+t44WVXaUjTBRcrpFeFlC8WCruUR456hw== -kolmafia@^5.28266.0: - version "5.28266.0" - resolved "https://registry.yarnpkg.com/kolmafia/-/kolmafia-5.28266.0.tgz#c53baecd6335ad366e4d33fadb1d628f0748c2e5" - integrity sha512-hD8C0fkJZ9xwNEcUwELAblQR8QjkMEoGsj+ZHfmF4yhESktm9WKUsdzNwCdqHndoGw8KAB3xg5fTmhVkycwgIw== +kol-rng@^2.0.0: + version "2.0.0" + resolved "https://registry.yarnpkg.com/kol-rng/-/kol-rng-2.0.0.tgz#5334296d75f8e7c3390cbbd6838876ecc5d68534" + integrity sha512-IFG0g6wXYrGtnjUXXCZSsYTkTIY8DBYu6fSZQBT4EdehRr3OLz5nvQzQJ45Kub0+HWLnGbuH60YWkdzA+w1udw== + dependencies: + mersenne-twister "^1.1.0" + +kolmafia@^5.28904.0: + version "5.28904.0" + resolved "https://registry.yarnpkg.com/kolmafia/-/kolmafia-5.28904.0.tgz#761e828e48be4e1a7b12c730ff5202cf89bf3459" + integrity sha512-0CxgFOSfM1vkYiySZ4V7NNvDx76Epovx4v5pjhH9+QsdEV3VElxDm1FfTlz60pir9twHXOKDavvhkqoFVvpAeg== levn@^0.4.1: version "0.4.1" @@ -2313,12 +2506,13 @@ levn@^0.4.1: prelude-ls "^1.2.1" type-check "~0.4.0" -libram@^0.9.29: - version "0.9.29" - resolved "https://registry.yarnpkg.com/libram/-/libram-0.9.29.tgz#d81695cb7e9d9c463a0b5cfa7072ec2ff8375cb3" - integrity sha512-LVehF8VtyRhnnti2WW38FSbC6t26q4MXIw/tuth8tdcNXaRzC07Gif20cZMx+y0X76G4x2/LnIBhU0eKivnPSw== +libram@^0.11.16: + version "0.11.16" + resolved "https://registry.yarnpkg.com/libram/-/libram-0.11.16.tgz#a2a6d331f6f6bc17f24fcdac49c294574627717d" + integrity sha512-Ydym35o5hEuPUKI2Ove/lLqVaImfTuaAO47CSecXNcKjnLbnkj72+ongIdNjG0bzGh1xIw1aGFHT7x9+6QKPgA== dependencies: - html-entities "^2.5.2" + core-js "^3.47.0" + entities "^7.0.0" loader-runner@^4.2.0: version "4.3.0" @@ -2365,13 +2559,6 @@ lru-cache@^5.1.1: dependencies: yallist "^3.0.2" -lru-cache@^6.0.0: - version "6.0.0" - resolved "https://registry.yarnpkg.com/lru-cache/-/lru-cache-6.0.0.tgz#6d6fe6570ebd96aaf90fcad1dafa3b2566db3a94" - integrity sha512-Jo6dJ04CmSjuznwJSS3pUeWmd/H0ffTlkXXgwZi+eq1UCmqQwCh+eLsYOYCwY991i2Fah4h1BEMCx4qThGbsiA== - dependencies: - yallist "^4.0.0" - mafia-shared-relay@0.0.7: version "0.0.7" resolved "https://registry.yarnpkg.com/mafia-shared-relay/-/mafia-shared-relay-0.0.7.tgz#1a0d333ebeed8cdbb4506360376099108c72d95b" @@ -2397,17 +2584,22 @@ merge-stream@^2.0.0: resolved "https://registry.yarnpkg.com/merge-stream/-/merge-stream-2.0.0.tgz#52823629a14dd00c9770fb6ad47dc6310f2c1f60" integrity sha512-abv/qOcuPfk3URPfDzmZU1LKmuw8kT+0nIHvKrKgFrwifol/doWcdA4ZqsWQ8ENrFKkd67Mfpo/LovbIUsbt3w== -merge2@^1.3.0, merge2@^1.4.1: +merge2@^1.3.0: version "1.4.1" resolved "https://registry.yarnpkg.com/merge2/-/merge2-1.4.1.tgz#4368892f885e907455a6fd7dc55c0c9d404990ae" integrity sha512-8q7VEgMJW4J8tcfVPy8g09NcQwZdbwFEqhe/WZkoIzjn/3TGDwtOCYtXGxA3O8tPzpczCCDgv+P2P5y00ZJOOg== -micromatch@^4.0.4: - version "4.0.5" - resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.5.tgz#bc8999a7cbbf77cdc89f132f6e467051b49090c6" - integrity sha512-DMy+ERcEW2q8Z2Po+WNXuw3c5YaUSFjAO5GsJqfEl7UjvtIuFKO6ZrKvcItdy98dwFI2N1tg3zNIdKaQT+aNdA== +mersenne-twister@^1.1.0: + version "1.1.0" + resolved "https://registry.yarnpkg.com/mersenne-twister/-/mersenne-twister-1.1.0.tgz#f916618ee43d7179efcf641bec4531eb9670978a" + integrity sha512-mUYWsMKNrm4lfygPkL3OfGzOPTR2DBlTkBNHM//F6hGp8cLThY897crAlk3/Jo17LEOOjQUrNAx6DvgO77QJkA== + +micromatch@^4.0.8: + version "4.0.8" + resolved "https://registry.yarnpkg.com/micromatch/-/micromatch-4.0.8.tgz#d66fa18f3a47076789320b9b1af32bd86d9fa202" + integrity sha512-PXwfBhYu0hBCPw8Dn0E+WDYb7af3dSLVWKi3HGv84IdF4TyFoC0ysxFd0Goxw7nSv4T/PzEJQxsYsEiFCKo2BA== dependencies: - braces "^3.0.2" + braces "^3.0.3" picomatch "^2.3.1" mime-db@1.52.0: @@ -2429,11 +2621,23 @@ minimatch@^3.1.1, minimatch@^3.1.2: dependencies: brace-expansion "^1.1.7" +minimatch@^9.0.4, minimatch@^9.0.5: + version "9.0.5" + resolved "https://registry.yarnpkg.com/minimatch/-/minimatch-9.0.5.tgz#d74f9dd6b57d83d8e98cfb82133b03978bc929e5" + integrity sha512-G6T0ZX48xgozx7587koeX9Ys2NYy6Gmv//P89sEte9V9whIapMNF4idKxnW2QtCcLiTWlb/wfCabAtAFWhhBow== + dependencies: + brace-expansion "^2.0.1" + ms@2.1.2: version "2.1.2" resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.2.tgz#d09d1f357b443f493382a8eb3ccd183872ae6009" integrity sha512-sGkPx+VjMtmA6MX27oA4FBFELFCZZ4S4XqeGOXCv68tT+jb3vk/RyaKWP0PTKyWtmLSM0b+adUTEvbs1PEaH2w== +ms@^2.1.3: + version "2.1.3" + resolved "https://registry.yarnpkg.com/ms/-/ms-2.1.3.tgz#574c8138ce1d2b5861f0b44579dbadd60c6615b2" + integrity sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA== + natural-compare@^1.4.0: version "1.4.0" resolved "https://registry.yarnpkg.com/natural-compare/-/natural-compare-1.4.0.tgz#4abebfeed7541f2c27acfb29bdbbd15c8d5ba4f7" @@ -2444,11 +2648,23 @@ neo-async@^2.6.2: resolved "https://registry.yarnpkg.com/neo-async/-/neo-async-2.6.2.tgz#b4aafb93e3aeb2d8174ca53cf163ab7d7308305f" integrity sha512-Yd3UES5mWCSqR+qNT93S3UoYUkqAZ9lLg8a7g9rimsWmYGK8cVToA4/sF3RrshdyV3sAGMXVUmpMYOw+dLpOuw== +node-bin-setup@^1.0.0: + version "1.1.4" + resolved "https://registry.yarnpkg.com/node-bin-setup/-/node-bin-setup-1.1.4.tgz#e5a666044152b54d8d84b95297977ae07fd04047" + integrity sha512-vWNHOne0ZUavArqPP5LJta50+S8R261Fr5SvGul37HbEDcowvLjwdvd0ZeSr0r2lTSrPxl6okq9QUw8BFGiAxA== + node-releases@^2.0.14: version "2.0.14" resolved "https://registry.yarnpkg.com/node-releases/-/node-releases-2.0.14.tgz#2ffb053bceb8b2be8495ece1ab6ce600c4461b0b" integrity sha512-y10wOWt8yZpqXmOgRo77WaHEmhYQYGNA6y421PKsKYWEK8aW+cqAphborZDhqfyKrbZEN92CN1X2KbafY2s7Yw== +node@^25.6.0: + version "25.6.0" + resolved "https://registry.yarnpkg.com/node/-/node-25.6.0.tgz#1113dd51a513638db40f94541b2daae163e69469" + integrity sha512-7fNTDq9Yy2BEvvUi918Um+gA8aA5n1NFcfoPuNz01RevORSActe7aXNTuJtWYVVewdI0vZLho6Jlx9rO9b9btg== + dependencies: + node-bin-setup "^1.0.0" + normalize-path@^3.0.0, normalize-path@~3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/normalize-path/-/normalize-path-3.0.0.tgz#0dcd69ff23a1c9b11fd0978316644a0388216a65" @@ -2533,11 +2749,6 @@ path-parse@^1.0.7: resolved "https://registry.yarnpkg.com/path-parse/-/path-parse-1.0.7.tgz#fbc114b60ca42b30d9daf5858e4bd68bbedb6735" integrity sha512-LDJzPVEEEPR+y48z93A0Ed0yXb8pAByGWo/k5YYdYgpY2/2EsOsksJrq7lOHxryrVOn1ejG6oAp8ahvOIQD8sw== -path-type@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/path-type/-/path-type-4.0.0.tgz#84ed01c0a7ba380afe09d90a8c180dcd9d03043b" - integrity sha512-gDKb8aZMDeD/tZWs9P6+q0J9Mwkdl6xMV8TjnGP3qJVJ06bdMgkbBlLU8IdfOsIsFz2BW1rNVT3XuNEl8zPAvw== - picocolors@^1.0.0: version "1.0.0" resolved "https://registry.yarnpkg.com/picocolors/-/picocolors-1.0.0.tgz#cb5bdc74ff3f51892236eaf79d68bc44564ab81c" @@ -2548,6 +2759,11 @@ picomatch@^2.0.4, picomatch@^2.2.1, picomatch@^2.3.1: resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-2.3.1.tgz#3ba3833733646d9d3e4995946c1365a67fb07a42" integrity sha512-JU3teHTNjmE2VCGFzuY8EXzCDVwEqB2a8fsIvwaStHhAWJEeVd1o1QD80CU6+ZdEXXSLbSsuLwJjkCBWqRQUVA== +picomatch@^4.0.3: + version "4.0.3" + resolved "https://registry.yarnpkg.com/picomatch/-/picomatch-4.0.3.tgz#796c76136d1eead715db1e7bad785dedd695a042" + integrity sha512-5gTmgEY/sqK6gFXLIsQNH19lWb4ebPDLA4SdLP7dsWkIXHWlG66oPuVvXSGFPppYZz8ZDZq0dYYrbHfBCVUb1Q== + pify@^4.0.1: version "4.0.1" resolved "https://registry.yarnpkg.com/pify/-/pify-4.0.1.tgz#4b2cd25c50d598735c50292224fd8c6df41e3231" @@ -2625,11 +2841,6 @@ regenerator-transform@^0.15.2: dependencies: "@babel/runtime" "^7.8.4" -regexpp@^3.1.0: - version "3.2.0" - resolved "https://registry.yarnpkg.com/regexpp/-/regexpp-3.2.0.tgz#0425a2768d8f23bad70ca4b90461fa2f1213e1b2" - integrity sha512-pq2bWo9mVD43nbts2wGv17XLiNLya+GklZ8kaDLV2Z08gDCsGpnKn9BFMepvWuHCbyVvY7J5o5+BVvoQbmlJLg== - regexpu-core@^5.3.1: version "5.3.2" resolved "https://registry.yarnpkg.com/regexpu-core/-/regexpu-core-5.3.2.tgz#11a2b06884f3527aec3e93dbbf4a3b958a95546b" @@ -2649,11 +2860,6 @@ regjsparser@^0.9.1: dependencies: jsesc "~0.5.0" -requireindex@~1.2.0: - version "1.2.0" - resolved "https://registry.yarnpkg.com/requireindex/-/requireindex-1.2.0.tgz#3463cdb22ee151902635aa6c9535d4de9c2ef1ef" - integrity sha512-L9jEkOi3ASd9PYit2cwRfyppc9NoABujTP8/5gFcbERmo5jUoAKovIC3fsF17pkTnGsrByysqX+Kxd2OTNI1ww== - resolve-cwd@^3.0.0: version "3.0.0" resolved "https://registry.yarnpkg.com/resolve-cwd/-/resolve-cwd-3.0.0.tgz#0f0075f1bb2544766cf73ba6a6e2adfebcb13f2d" @@ -2725,12 +2931,15 @@ semver@^6.0.0, semver@^6.3.1: resolved "https://registry.yarnpkg.com/semver/-/semver-6.3.1.tgz#556d2ef8689146e46dcea4bfdd095f3434dffcb4" integrity sha512-BR7VvDCVHO+q2xBEWskxS6DJE1qRnb7DxzUrogb71CWoSficBxYsiAGd+Kl0mmq/MprG9yArRkyrQxTO6XjMzA== -semver@^7.3.5: - version "7.6.0" - resolved "https://registry.yarnpkg.com/semver/-/semver-7.6.0.tgz#1a46a4db4bffcccd97b743b5005c8325f23d4e2d" - integrity sha512-EnwXhrlwXMk9gKu5/flx5sv/an57AkRplG3hTK68W7FRDN+k+OWBj65M7719OkA82XLBxrcX0KSHj+X5COhOVg== - dependencies: - lru-cache "^6.0.0" +semver@^7.6.0: + version "7.7.2" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.2.tgz#67d99fdcd35cec21e6f8b87a7fd515a33f982b58" + integrity sha512-RF0Fw+rO5AMf9MAyaRXI4AV0Ulj5lMHqVxxdSgiVbixSCXoEmmX/jk0CuJw4+3SqroYO9VoUh+HcuJivvtJemA== + +semver@^7.7.3: + version "7.7.3" + resolved "https://registry.yarnpkg.com/semver/-/semver-7.7.3.tgz#4b5f4143d007633a8dc671cd0a6ef9147b8bb946" + integrity sha512-SdsKMrI9TdgjdweUSR9MweHA4EJ8YxHn8DFaDisvhVlUOe4BF1tLD7GAj0lIqWVl+dPb/rExr0Btby5loQm20Q== serialize-javascript@^6.0.1: version "6.0.2" @@ -2763,11 +2972,6 @@ slash@^2.0.0: resolved "https://registry.yarnpkg.com/slash/-/slash-2.0.0.tgz#de552851a1759df3a8f206535442f5ec4ddeab44" integrity sha512-ZYKh3Wh2z1PpEXWr0MpSBZ0V6mZHAQfYevttO11c51CaWjGTaadiKZ+wVt1PbMlDV5qhMFslpZCemhwOK7C89A== -slash@^3.0.0: - version "3.0.0" - resolved "https://registry.yarnpkg.com/slash/-/slash-3.0.0.tgz#6539be870c165adbd5240220dbe361f1bc4d4634" - integrity sha512-g9Q1haeby36OSStwb4ntCGGGaKsaVSjQ68fBxoQcutl5fS1vuY18H3wSt3jFyFtrkx+Kz0V1G85A4MyAdDMi2Q== - source-map-support@~0.5.20: version "0.5.21" resolved "https://registry.yarnpkg.com/source-map-support/-/source-map-support-0.5.21.tgz#04fe7c7f9e1ed2d662233c28cb2b35b9f63f6e4f" @@ -2838,6 +3042,14 @@ terser@^5.26.0: commander "^2.20.0" source-map-support "~0.5.20" +tinyglobby@^0.2.15: + version "0.2.15" + resolved "https://registry.yarnpkg.com/tinyglobby/-/tinyglobby-0.2.15.tgz#e228dd1e638cea993d2fdb4fcd2d4602a79951c2" + integrity sha512-j2Zq4NyQYG5XMST4cbs02Ak8iJUdxRM0XI5QyxXuZOzKOINmWurp3smXu3y5wDcJrptwpSjgXHzIQxR0omXljQ== + dependencies: + fdir "^6.5.0" + picomatch "^4.0.3" + to-fast-properties@^2.0.0: version "2.0.0" resolved "https://registry.yarnpkg.com/to-fast-properties/-/to-fast-properties-2.0.0.tgz#dc5e698cbd079265bc73e0377681a4e4e83f616e" @@ -2850,17 +3062,15 @@ to-regex-range@^5.0.1: dependencies: is-number "^7.0.0" -tslib@^1.8.1: - version "1.14.1" - resolved "https://registry.yarnpkg.com/tslib/-/tslib-1.14.1.tgz#cf2d38bdc34a134bcaf1091c41f6619e2f672d00" - integrity sha512-Xni35NKzjgMrwevysHTCArtLDpPvye8zV/0E4EyYn43P7/7qvQwPh9BGkHewbMulVntbigmcT7rdX3BNo9wRJg== +ts-api-utils@^2.1.0: + version "2.1.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.1.0.tgz#595f7094e46eed364c13fd23e75f9513d29baf91" + integrity sha512-CUgTZL1irw8u29bzrOD/nH85jqyc74D6SshFgujOIA7osm2Rz7dYH77agkx7H4FBNxDq7Cjf+IjaX/8zwFW+ZQ== -tsutils@^3.21.0: - version "3.21.0" - resolved "https://registry.yarnpkg.com/tsutils/-/tsutils-3.21.0.tgz#b48717d394cea6c1e096983eed58e9d61715b623" - integrity sha512-mHKK3iUXL+3UF6xL5k0PEhKRUBKPBCv/+RkEOpjRWxxx27KKRBmmA60A9pgOUvMi8GKhRMPEmjBRPzs2W7O1OA== - dependencies: - tslib "^1.8.1" +ts-api-utils@^2.4.0: + version "2.4.0" + resolved "https://registry.yarnpkg.com/ts-api-utils/-/ts-api-utils-2.4.0.tgz#2690579f96d2790253bdcf1ca35d569ad78f9ad8" + integrity sha512-3TaVTaAv2gTiMB35i3FiGJaRfwb3Pyn/j3m/bfAvGe8FB7CF6u+LMYqYlDh7reQf7UNvoTvdfAqHGmPGOSsPmA== type-check@^0.4.0, type-check@~0.4.0: version "0.4.0" @@ -2869,6 +3079,16 @@ type-check@^0.4.0, type-check@~0.4.0: dependencies: prelude-ls "^1.2.1" +typescript-eslint@^8.54.0: + version "8.54.0" + resolved "https://registry.yarnpkg.com/typescript-eslint/-/typescript-eslint-8.54.0.tgz#f4ef3b8882a5ddc2a41968e014194c178ab23f6a" + integrity sha512-CKsJ+g53QpsNPqbzUsfKVgd3Lny4yKZ1pP4qN3jdMOg/sisIDLGyDMezycquXLE5JsEU0wp3dGNdzig0/fmSVQ== + dependencies: + "@typescript-eslint/eslint-plugin" "8.54.0" + "@typescript-eslint/parser" "8.54.0" + "@typescript-eslint/typescript-estree" "8.54.0" + "@typescript-eslint/utils" "8.54.0" + typescript@^4.4.2: version "4.9.5" resolved "https://registry.yarnpkg.com/typescript/-/typescript-4.9.5.tgz#095979f9bcc0d09da324d58d03ce8f8374cbe65a" @@ -3014,11 +3234,6 @@ yallist@^3.0.2: resolved "https://registry.yarnpkg.com/yallist/-/yallist-3.1.1.tgz#dbb7daf9bfd8bac9ab45ebf602b8cbad0d5d08fd" integrity sha512-a4UGQaWPH59mOXUYnAG2ewncQS4i4F43Tv3JoAM+s2VDAmS9NsK8GpDMLrCHPksFT7h3K6TOoUNn2pb7RoXx4g== -yallist@^4.0.0: - version "4.0.0" - resolved "https://registry.yarnpkg.com/yallist/-/yallist-4.0.0.tgz#9bb92790d9c0effec63be73519e11a35019a3a72" - integrity sha512-3wdGidZyq5PB084XLES5TpOSRA3wjXAlIWMhum2kRcv/41Sn2emQ0dycQW4uZXLejwKvg6EsvbdlVL+FYEct7A== - yocto-queue@^0.1.0: version "0.1.0" resolved "https://registry.yarnpkg.com/yocto-queue/-/yocto-queue-0.1.0.tgz#0294eb3dee05028d31ee1a5fa2c556a6aaf10a1b"