From 467681e1e62e8183acc15fbf71a8af56cb58eb15 Mon Sep 17 00:00:00 2001 From: Patrick Hulin Date: Sat, 9 Nov 2024 14:27:36 -0500 Subject: [PATCH] Add delay tile. --- src/questInfo/delay.ts | 74 ++++++++++++++++++++++ src/questInfo/desert.ts | 62 ++++++++++++++++++ src/questInfo/hiddenCity.ts | 11 ++++ src/sections/QuestSection.tsx | 2 + src/sections/quests/Delay.tsx | 73 +++++++++++++++++++++ src/sections/quests/level11/Desert.tsx | 67 ++------------------ src/sections/quests/level11/HiddenCity.tsx | 11 +--- 7 files changed, 228 insertions(+), 72 deletions(-) create mode 100644 src/questInfo/delay.ts create mode 100644 src/questInfo/desert.ts create mode 100644 src/questInfo/hiddenCity.ts create mode 100644 src/sections/quests/Delay.tsx diff --git a/src/questInfo/delay.ts b/src/questInfo/delay.ts new file mode 100644 index 00000000..e1b16b86 --- /dev/null +++ b/src/questInfo/delay.ts @@ -0,0 +1,74 @@ +import { Location } from "kolmafia"; +import { $location } from "libram"; + +import { haveMachete, lianasCanBeFree } from "./hiddenCity"; + +interface ZoneDelay { + zone: Location; + length: number; + needed?: () => boolean; +} + +export const DELAY_ZONES: ZoneDelay[] = [ + { + zone: $location`The Outskirts of Cobb's Knob`, + length: 10, + }, + { + zone: $location`The Spooky Forest`, + length: 5, + }, + { + zone: $location`The Boss Bat's Lair`, + length: 5, + }, + { + zone: $location`The Haunted Gallery`, + length: 5, + }, + { + zone: $location`The Haunted Bathroom`, + length: 5, + }, + { + zone: $location`The Haunted Bedroom`, + length: 6, + }, + { + zone: $location`The Haunted Ballroom`, + length: 5, + }, + { + zone: $location`The Penultimate Fantasy Airship`, + length: 25, + }, + { + zone: $location`The Castle in the Clouds in the Sky (Ground Floor)`, + length: 10, + }, + { + zone: $location`The Hidden Park`, + length: 6, + needed: () => !haveMachete() && lianasCanBeFree(), + }, + { + zone: $location`The Copperhead Club`, + // Not including NCs themselves here. + length: 12, + }, + { + zone: $location`The Upper Chamber`, + length: 5, + }, + { + zone: $location`The Middle Chamber`, + length: 9, + }, +]; + +export function remainingDelay() { + return DELAY_ZONES.map(({ zone, length, needed }) => ({ + zone, + remaining: needed === undefined || needed() ? length - zone.turnsSpent : 0, + })).filter(({ remaining }) => remaining > 0); +} diff --git a/src/questInfo/desert.ts b/src/questInfo/desert.ts new file mode 100644 index 00000000..d78044da --- /dev/null +++ b/src/questInfo/desert.ts @@ -0,0 +1,62 @@ +import { canEquip, haveEquipped, myFamiliar, myPath } from "kolmafia"; +import { $effect, $familiar, $item, $path, get, have } from "libram"; + +import { haveUnrestricted } from "../util/available"; + +export function currentExplorationPerTurn(): number { + let exploration = 1; + if (haveEquipped($item`ornate dowsing rod`)) { + exploration += 2; + } + if (haveEquipped($item`UV-resistant compass`)) { + exploration += 1; + } + if (myPath() === $path`License to Adventure` && get("bondDesert")) { + exploration += 2; + } + if ( + myPath() === $path`Avatar of Sneaky Pete` && + get("peteMotorbikeHeadlight") === "Blacklight Bulb" + ) { + exploration += 2; + } + if (haveEquipped($item`survival knife`) && have($effect`Ultrahydrated`)) { + exploration += 2; + } + if (myFamiliar() === $familiar`Melodramedary`) { + exploration += 1; + } + return exploration; +} +export function possibleExplorationPerTurn(): number { + let exploration = 1; + if (have($item`ornate dowsing rod`)) { + exploration += 2; + } + if ( + have($item`UV-resistant compass`) && + (!have($item`ornate dowsing rod`) || + haveUnrestricted($familiar`Left-Hand Man`)) + ) { + exploration += 1; + } + if (myPath() === $path`License to Adventure` && get("bondDesert")) { + exploration += 2; + } + if ( + myPath() === $path`Avatar of Sneaky Pete` && + get("peteMotorbikeHeadlight") === "Blacklight Bulb" + ) { + exploration += 2; + } + if (have($item`survival knife`)) { + exploration += 2; + } + if ( + haveUnrestricted($familiar`Melodramedary`) && + canEquip($familiar`Melodramedary`) + ) { + exploration += 1; + } + return exploration; +} diff --git a/src/questInfo/hiddenCity.ts b/src/questInfo/hiddenCity.ts new file mode 100644 index 00000000..33f47a35 --- /dev/null +++ b/src/questInfo/hiddenCity.ts @@ -0,0 +1,11 @@ +import { myPath } from "kolmafia"; +import { $items, $path, have } from "libram"; + +export const MACHETES = $items`antique machete, muculent machete, machetito`; +export function haveMachete() { + return MACHETES.some((item) => have(item)); +} + +export function lianasCanBeFree() { + return myPath() !== $path`Avant Guard` && myPath() !== $path`BIG!`; +} diff --git a/src/sections/QuestSection.tsx b/src/sections/QuestSection.tsx index 7dbf9202..16ba97d7 100644 --- a/src/sections/QuestSection.tsx +++ b/src/sections/QuestSection.tsx @@ -3,6 +3,7 @@ import { $path, get } from "libram"; import TileSection from "../components/TileSection"; +import Delay from "./quests/Delay"; import DigitalKey from "./quests/DigitalKey"; import HeroKeys from "./quests/HeroKeys"; import HiddenTemple from "./quests/HiddenTemple"; @@ -35,6 +36,7 @@ const QuestSection = () => { Manor, ...(showStandardQuests ? [ + Delay, Level1, Level2, Level3, diff --git a/src/sections/quests/Delay.tsx b/src/sections/quests/Delay.tsx new file mode 100644 index 00000000..60541af1 --- /dev/null +++ b/src/sections/quests/Delay.tsx @@ -0,0 +1,73 @@ +import { ListItem, UnorderedList } from "@chakra-ui/react"; +import { canAdventure, Location } from "kolmafia"; +import { sum } from "libram"; +import { FC } from "react"; + +import AdviceTip from "../../components/AdviceTip"; +import Line from "../../components/Line"; +import MainLink from "../../components/MainLink"; +import Tile from "../../components/Tile"; +import { remainingDelay } from "../../questInfo/delay"; +import { parentPlaceLink } from "../../util/links"; +import { plural } from "../../util/text"; + +type Details = { zone: Location; remaining: number; available: boolean }; + +const ZoneList: FC<{ + zones: Details[]; +}> = ({ zones }) => ( + + {zones.map(({ zone, remaining, available }) => ( + + + {plural(remaining, "turn")} in {zone.identifierString}. + + + ))} + +); + +const Delay: FC = () => { + let allRemaining = remainingDelay() + .map(({ zone, remaining }) => ({ + zone, + remaining, + available: canAdventure(zone), + })) + .sort( + ({ available: availableA }, { available: availableB }) => + +availableB - +availableA, + ); + let truncated: Details[] = []; + if ( + allRemaining.length > 7 && + allRemaining.some(({ available }) => !available) + ) { + truncated = allRemaining.slice(1); + allRemaining = allRemaining.slice(0, 7); + } + + const total = sum(allRemaining, ({ remaining }) => remaining); + return ( + + Use free runs and free wanderers to avoid spending turns. + + {truncated.length > 0 && ( + + }> + Later zones. + + + )} + + ); +}; + +export default Delay; diff --git a/src/sections/quests/level11/Desert.tsx b/src/sections/quests/level11/Desert.tsx index e341dad6..657b7ed3 100644 --- a/src/sections/quests/level11/Desert.tsx +++ b/src/sections/quests/level11/Desert.tsx @@ -1,10 +1,8 @@ import { availableAmount, canAdventure, - canEquip, haveEquipped, myFamiliar, - myPath, npcPrice, } from "kolmafia"; import { @@ -13,7 +11,6 @@ import { $item, $items, $location, - $path, get, have, questStep, @@ -22,72 +19,16 @@ import { import AsyncLink from "../../../components/AsyncLink"; import Line from "../../../components/Line"; import QuestTile from "../../../components/QuestTile"; -import { haveUnrestricted } from "../../../util/available"; +import { + currentExplorationPerTurn, + possibleExplorationPerTurn, +} from "../../../questInfo/desert"; import { BLACK_MARKET_URL, inventoryLink } from "../../../util/links"; import { questFinished, Step } from "../../../util/quest"; import { commaAnd, commaOr, plural } from "../../../util/text"; const BEACH_URL = "/place.php?whichplace=desertbeach"; -function currentExplorationPerTurn(): number { - let exploration = 1; - if (haveEquipped($item`ornate dowsing rod`)) { - exploration += 2; - } - if (haveEquipped($item`UV-resistant compass`)) { - exploration += 1; - } - if (myPath() === $path`License to Adventure` && get("bondDesert")) { - exploration += 2; - } - if ( - myPath() === $path`Avatar of Sneaky Pete` && - get("peteMotorbikeHeadlight") === "Blacklight Bulb" - ) { - exploration += 2; - } - if (haveEquipped($item`survival knife`) && have($effect`Ultrahydrated`)) { - exploration += 2; - } - if (myFamiliar() === $familiar`Melodramedary`) { - exploration += 1; - } - return exploration; -} - -function possibleExplorationPerTurn(): number { - let exploration = 1; - if (have($item`ornate dowsing rod`)) { - exploration += 2; - } - if ( - have($item`UV-resistant compass`) && - (!have($item`ornate dowsing rod`) || - haveUnrestricted($familiar`Left-Hand Man`)) - ) { - exploration += 1; - } - if (myPath() === $path`License to Adventure` && get("bondDesert")) { - exploration += 2; - } - if ( - myPath() === $path`Avatar of Sneaky Pete` && - get("peteMotorbikeHeadlight") === "Blacklight Bulb" - ) { - exploration += 2; - } - if (have($item`survival knife`)) { - exploration += 2; - } - if ( - haveUnrestricted($familiar`Melodramedary`) && - canEquip($familiar`Melodramedary`) - ) { - exploration += 1; - } - return exploration; -} - const DesertQuest = () => { const step = questStep("questL11Desert"); diff --git a/src/sections/quests/level11/HiddenCity.tsx b/src/sections/quests/level11/HiddenCity.tsx index b8db9150..a9a9691e 100644 --- a/src/sections/quests/level11/HiddenCity.tsx +++ b/src/sections/quests/level11/HiddenCity.tsx @@ -13,7 +13,6 @@ import { import { $effect, $item, - $items, $location, $monster, $path, @@ -29,6 +28,7 @@ import MainLink from "../../../components/MainLink"; import QuestTile from "../../../components/QuestTile"; import { NagPriority } from "../../../contexts/NagContext"; import useNag from "../../../hooks/useNag"; +import { haveMachete, lianasCanBeFree } from "../../../questInfo/hiddenCity"; import { inventoryLink, parentPlaceLink } from "../../../util/links"; import { atStep, questFinished, Step } from "../../../util/quest"; import { commaAnd, plural, pluralItem } from "../../../util/text"; @@ -60,11 +60,6 @@ const Unlock: FC = ({ shrine, location }) => { ); }; -const machetes = $items`antique machete, muculent machete, machetito`; -function haveMachete() { - return machetes.some((item) => have(item)); -} - const Machete = () => { const hiddenPark = $location`The Hidden Park`; const delayRemaining = Math.max(0, 6 - hiddenPark.turnsSpent); @@ -439,8 +434,6 @@ const HiddenCity = () => { const ascensions = myAscensions(); const lastTempleAdventures = get("lastTempleAdventures"); const stoneFacedTurns = haveEffect($effect`Stone-Faced`); - const lianasCanBeFree = - myPath() !== $path`Avant Guard` && myPath() !== $path`BIG!`; useNag( () => ({ @@ -517,7 +510,7 @@ const HiddenCity = () => { Use your book of matches to unlock the Hidden Tavern. )} - {!haveMachete() && lianasCanBeFree ? ( + {!haveMachete() && lianasCanBeFree() ? ( ) : ( <>